]> err.no Git - linux-2.6/commitdiff
Merge branch 'for-2.6.25' of git://git.secretlab.ca/git/linux-2.6-mpc52xx into for...
authorPaul Mackerras <paulus@samba.org>
Thu, 7 Feb 2008 00:21:09 +0000 (11:21 +1100)
committerPaul Mackerras <paulus@samba.org>
Thu, 7 Feb 2008 00:21:09 +0000 (11:21 +1100)
2432 files changed:
CREDITS
Documentation/00-INDEX
Documentation/ABI/testing/sysfs-bus-usb
Documentation/BUG-HUNTING
Documentation/DocBook/rapidio.tmpl
Documentation/DocBook/s390-drivers.tmpl
Documentation/Smack.txt [new file with mode: 0644]
Documentation/SubmittingPatches
Documentation/arm/Sharp-LH/IOBarrier
Documentation/debugging-modules.txt
Documentation/driver-model/platform.txt
Documentation/feature-removal-schedule.txt
Documentation/filesystems/configfs/configfs.txt
Documentation/filesystems/porting
Documentation/filesystems/proc.txt
Documentation/filesystems/ramfs-rootfs-initramfs.txt
Documentation/filesystems/relay.txt
Documentation/frv/README.txt [moved from Documentation/fujitsu/frv/README.txt with 100% similarity]
Documentation/frv/atomic-ops.txt [moved from Documentation/fujitsu/frv/atomic-ops.txt with 100% similarity]
Documentation/frv/booting.txt [moved from Documentation/fujitsu/frv/booting.txt with 98% similarity]
Documentation/frv/clock.txt [moved from Documentation/fujitsu/frv/clock.txt with 100% similarity]
Documentation/frv/configuring.txt [moved from Documentation/fujitsu/frv/configuring.txt with 100% similarity]
Documentation/frv/features.txt [moved from Documentation/fujitsu/frv/features.txt with 100% similarity]
Documentation/frv/gdbinit [moved from Documentation/fujitsu/frv/gdbinit with 100% similarity]
Documentation/frv/gdbstub.txt [moved from Documentation/fujitsu/frv/gdbstub.txt with 100% similarity]
Documentation/frv/kernel-ABI.txt [moved from Documentation/fujitsu/frv/kernel-ABI.txt with 100% similarity]
Documentation/frv/mmu-layout.txt [moved from Documentation/fujitsu/frv/mmu-layout.txt with 100% similarity]
Documentation/gpio.txt
Documentation/i2c/chips/pca9539
Documentation/ia64/aliasing-test.c
Documentation/ide/ChangeLog.ide-cd.1994-2004 [new file with mode: 0644]
Documentation/ide/ChangeLog.ide-floppy.1996-2002 [new file with mode: 0644]
Documentation/ide/ChangeLog.ide-tape.1995-2002 [new file with mode: 0644]
Documentation/ide/ide-tape.txt [new file with mode: 0644]
Documentation/initrd.txt
Documentation/ja_JP/stable_kernel_rules.txt [new file with mode: 0644]
Documentation/kernel-parameters.txt
Documentation/lguest/lguest.c
Documentation/networking/decnet.txt
Documentation/networking/xfrm_proc.txt
Documentation/pci.txt
Documentation/pcmcia/driver-changes.txt
Documentation/pm_qos_interface.txt [new file with mode: 0644]
Documentation/power/basic-pm-debugging.txt
Documentation/power/devices.txt
Documentation/power/drivers-testing.txt
Documentation/power/notifiers.txt
Documentation/power/userland-swsusp.txt
Documentation/power_supply_class.txt
Documentation/smp.txt [deleted file]
Documentation/sound/alsa/ALSA-Configuration.txt
Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl
Documentation/sound/alsa/soc/DAI.txt
Documentation/sound/alsa/soc/clocking.txt
Documentation/sound/alsa/soc/codec.txt
Documentation/sound/alsa/soc/dapm.txt
Documentation/sound/alsa/soc/machine.txt
Documentation/sound/alsa/soc/overview.txt
Documentation/sound/alsa/soc/platform.txt
Documentation/sound/alsa/soc/pops_clicks.txt
Documentation/sysctl/vm.txt
Documentation/usb/gadget_printer.txt [new file with mode: 0644]
Documentation/usb/iuu_phoenix.txt [new file with mode: 0644]
Documentation/x86_64/00-INDEX [new file with mode: 0644]
MAINTAINERS
Makefile
arch/Kconfig [new file with mode: 0644]
arch/alpha/Kconfig
arch/alpha/kernel/pci-noop.c
arch/alpha/kernel/pci_iommu.c
arch/alpha/kernel/setup.c
arch/alpha/kernel/systbls.S
arch/arm/Kconfig
arch/arm/Kconfig.instrumentation [deleted file]
arch/arm/common/time-acorn.c
arch/arm/configs/ixp4xx_defconfig
arch/arm/kernel/Makefile
arch/arm/kernel/atags.c [new file with mode: 0644]
arch/arm/kernel/atags.h [new file with mode: 0644]
arch/arm/kernel/calls.S
arch/arm/kernel/machine_kexec.c
arch/arm/kernel/relocate_kernel.S
arch/arm/kernel/setup.c
arch/arm/kernel/smp.c
arch/arm/mach-at91/Kconfig
arch/arm/mach-at91/at91sam926x_time.c
arch/arm/mach-at91/generic.h
arch/arm/mach-at91/gpio.c
arch/arm/mach-at91/pm.c
arch/arm/mach-ixp4xx/Kconfig
arch/arm/mach-ixp4xx/Makefile
arch/arm/mach-ixp4xx/dsmg600-power.c [deleted file]
arch/arm/mach-ixp4xx/dsmg600-setup.c
arch/arm/mach-ixp4xx/ixdp425-setup.c
arch/arm/mach-ixp4xx/ixp4xx_npe.c [new file with mode: 0644]
arch/arm/mach-ixp4xx/ixp4xx_qmgr.c [new file with mode: 0644]
arch/arm/mach-ixp4xx/nas100d-power.c [deleted file]
arch/arm/mach-ixp4xx/nas100d-setup.c
arch/arm/mach-ixp4xx/nslu2-power.c [deleted file]
arch/arm/mach-ixp4xx/nslu2-setup.c
arch/arm/mach-pxa/Makefile
arch/arm/mach-pxa/cm-x270.c
arch/arm/mach-pxa/corgi_ssp.c
arch/arm/mach-pxa/devices.c
arch/arm/mach-pxa/generic.c
arch/arm/mach-pxa/generic.h
arch/arm/mach-pxa/gpio.c [new file with mode: 0644]
arch/arm/mach-pxa/irq.c
arch/arm/mach-pxa/mfp.c
arch/arm/mach-pxa/pcm027.c
arch/arm/mach-pxa/poodle.c
arch/arm/mach-pxa/pxa25x.c
arch/arm/mach-pxa/pxa27x.c
arch/arm/mach-pxa/pxa3xx.c
arch/arm/mach-pxa/sleep.S
arch/arm/mach-pxa/smemc.c [new file with mode: 0644]
arch/arm/mach-pxa/spitz.c
arch/arm/mach-pxa/tosa.c
arch/arm/mach-realview/Kconfig
arch/arm/mach-realview/Makefile
arch/arm/mach-realview/core.c
arch/arm/mach-realview/core.h
arch/arm/mach-realview/localtimer.c
arch/arm/mach-realview/platsmp.c
arch/arm/mach-realview/realview_eb.c
arch/arm/mach-sa1100/collie_pm.c
arch/arm/mach-sa1100/generic.c
arch/arm/mm/ioremap.c
arch/arm/mm/pgd.c
arch/arm/plat-iop/time.c
arch/arm/plat-s3c24xx/irq.c
arch/arm/plat-s3c24xx/time.c
arch/avr32/Kconfig
arch/avr32/kernel/syscall_table.S
arch/avr32/mach-at32ap/pio.c
arch/avr32/mach-at32ap/pio.h
arch/blackfin/Kconfig
arch/blackfin/mach-common/entry.S
arch/cris/Kconfig
arch/cris/arch-v10/Kconfig
arch/cris/arch-v10/drivers/Kconfig
arch/cris/arch-v10/kernel/entry.S
arch/cris/arch-v32/Kconfig
arch/cris/arch-v32/drivers/Kconfig
arch/cris/arch-v32/drivers/pci/dma.c
arch/frv/Kconfig
arch/frv/kernel/entry.S
arch/frv/kernel/vmlinux.lds.S
arch/frv/lib/atomic-ops.S
arch/frv/mm/mmu-context.c
arch/frv/mm/pgalloc.c
arch/h8300/Kconfig
arch/h8300/platform/h8s/ints.c
arch/ia64/Kconfig
arch/ia64/hp/common/sba_iommu.c
arch/ia64/ia32/ia32_support.c
arch/ia64/kernel/efi.c
arch/ia64/kernel/entry.S
arch/ia64/kernel/fsyscall_gtod_data.h
arch/ia64/kernel/ia64_ksyms.c
arch/ia64/kernel/kprobes.c
arch/ia64/kernel/mca.c
arch/ia64/kernel/mca_asm.S
arch/ia64/kernel/mca_drv.c
arch/ia64/kernel/mca_drv.h
arch/ia64/kernel/mca_drv_asm.S
arch/ia64/kernel/module.c
arch/ia64/kernel/perfmon.c
arch/ia64/kernel/sal.c
arch/ia64/kernel/setup.c
arch/ia64/kernel/smpboot.c
arch/ia64/kernel/traps.c
arch/ia64/kernel/unaligned.c
arch/ia64/mm/fault.c
arch/ia64/sn/kernel/sn2/sn2_smp.c
arch/ia64/sn/kernel/sn2/sn_hwperf.c
arch/m32r/Kconfig
arch/m32r/boot/compressed/m32r_sio.c
arch/m32r/kernel/ptrace.c
arch/m32r/kernel/syscall_table.S
arch/m68k/Kconfig
arch/m68k/Makefile
arch/m68k/amiga/Makefile
arch/m68k/amiga/amiga_ksyms.c [deleted file]
arch/m68k/amiga/amisound.c
arch/m68k/amiga/chipram.c
arch/m68k/amiga/config.c
arch/m68k/amiga/pcmcia.c
arch/m68k/atari/Makefile
arch/m68k/atari/ataints.c
arch/m68k/atari/atari_ksyms.c [deleted file]
arch/m68k/atari/atasound.c
arch/m68k/atari/config.c
arch/m68k/atari/debug.c
arch/m68k/atari/hades-pci.c
arch/m68k/atari/stdma.c
arch/m68k/atari/stram.c
arch/m68k/configs/mac_defconfig
arch/m68k/hp300/Makefile
arch/m68k/hp300/ksyms.c [deleted file]
arch/m68k/kernel/entry.S
arch/m68k/mac/Makefile
arch/m68k/mac/config.c
arch/m68k/mac/mac_ksyms.c [deleted file]
arch/m68k/mac/via.c
arch/m68k/mvme16x/Makefile
arch/m68k/mvme16x/config.c
arch/m68k/mvme16x/mvme16x_ksyms.c [deleted file]
arch/m68knommu/Kconfig
arch/m68knommu/Kconfig.debug
arch/m68knommu/Makefile
arch/m68knommu/defconfig
arch/m68knommu/kernel/m68k_ksyms.c
arch/m68knommu/kernel/setup.c
arch/m68knommu/kernel/syscalltable.S
arch/m68knommu/kernel/time.c
arch/m68knommu/platform/5206/config.c
arch/m68knommu/platform/5206e/config.c
arch/m68knommu/platform/520x/config.c
arch/m68knommu/platform/523x/config.c
arch/m68knommu/platform/5249/config.c
arch/m68knommu/platform/5272/config.c
arch/m68knommu/platform/527x/config.c
arch/m68knommu/platform/528x/config.c
arch/m68knommu/platform/5307/Makefile
arch/m68knommu/platform/5307/config.c
arch/m68knommu/platform/532x/config.c
arch/m68knommu/platform/5407/config.c
arch/m68knommu/platform/68328/timers.c
arch/m68knommu/platform/68360/config.c
arch/m68knommu/platform/coldfire/Makefile [new file with mode: 0644]
arch/m68knommu/platform/coldfire/dma.c [new file with mode: 0644]
arch/m68knommu/platform/coldfire/entry.S [moved from arch/m68knommu/platform/5307/entry.S with 100% similarity]
arch/m68knommu/platform/coldfire/head.S [moved from arch/m68knommu/platform/5307/head.S with 100% similarity]
arch/m68knommu/platform/coldfire/pit.c [moved from arch/m68knommu/platform/5307/pit.c with 53% similarity]
arch/m68knommu/platform/coldfire/timers.c [moved from arch/m68knommu/platform/5307/timers.c with 77% similarity]
arch/m68knommu/platform/coldfire/vectors.c [moved from arch/m68knommu/platform/5307/vectors.c with 100% similarity]
arch/mips/Kconfig
arch/mips/au1000/mtx-1/board_setup.c
arch/mips/kernel/binfmt_elfn32.c
arch/mips/kernel/binfmt_elfo32.c
arch/mips/kernel/head.S
arch/mips/kernel/kspd.c
arch/mips/kernel/scall32-o32.S
arch/mips/kernel/scall64-64.S
arch/mips/kernel/scall64-n32.S
arch/mips/kernel/scall64-o32.S
arch/mips/kernel/setup.c
arch/mips/kernel/smtc.c
arch/mips/mm/Makefile
arch/mips/mm/c-r4k.c
arch/mips/mm/tlbex.c
arch/mips/mm/uasm.c [new file with mode: 0644]
arch/mips/mm/uasm.h [new file with mode: 0644]
arch/mips/sgi-ip27/ip27-hubio.c
arch/parisc/Kconfig
arch/parisc/kernel/cache.c
arch/parisc/kernel/hardware.c
arch/parisc/kernel/signal.c
arch/powerpc/Kconfig
arch/powerpc/boot/dts/adder875-redboot.dts
arch/powerpc/boot/dts/adder875-uboot.dts
arch/powerpc/boot/dts/mpc8313erdb.dts
arch/powerpc/boot/dts/mpc8315erdb.dts
arch/powerpc/boot/dts/mpc834x_mds.dts
arch/powerpc/boot/dts/mpc8572ds.dts
arch/powerpc/boot/dts/mpc885ads.dts
arch/powerpc/boot/dts/storcenter.dts
arch/powerpc/configs/mpc83xx_defconfig
arch/powerpc/kernel/asm-offsets.c
arch/powerpc/kernel/cputable.c
arch/powerpc/kernel/dma_64.c
arch/powerpc/kernel/iommu.c
arch/powerpc/kernel/legacy_serial.c
arch/powerpc/kernel/pmc.c
arch/powerpc/kernel/vio.c
arch/powerpc/mm/mem.c
arch/powerpc/mm/pgtable_32.c
arch/powerpc/oprofile/Makefile
arch/powerpc/oprofile/common.c
arch/powerpc/oprofile/op_model_fsl_emb.c [moved from arch/powerpc/oprofile/op_model_fsl_booke.c with 90% similarity]
arch/powerpc/platforms/52xx/lite5200_pm.c
arch/powerpc/platforms/82xx/mpc8272_ads.c
arch/powerpc/platforms/82xx/pq2fads.c
arch/powerpc/platforms/83xx/mpc832x_rdb.c
arch/powerpc/platforms/83xx/mpc83xx.h
arch/powerpc/platforms/83xx/usb.c
arch/powerpc/platforms/8xx/adder875.c
arch/powerpc/platforms/8xx/ep88xc.c
arch/powerpc/platforms/Kconfig
arch/powerpc/platforms/Kconfig.cputype
arch/powerpc/platforms/cell/Kconfig
arch/powerpc/platforms/cell/axon_msi.c
arch/powerpc/platforms/cell/setup.c
arch/powerpc/platforms/cell/spufs/Makefile
arch/powerpc/platforms/cell/spufs/file.c
arch/powerpc/platforms/cell/spufs/inode.c
arch/powerpc/platforms/cell/spufs/run.c
arch/powerpc/platforms/cell/spufs/sched.c
arch/powerpc/platforms/cell/spufs/spufs.h
arch/powerpc/platforms/cell/spufs/sputrace.c [new file with mode: 0644]
arch/powerpc/platforms/embedded6xx/storcenter.c
arch/powerpc/platforms/iseries/iommu.c
arch/powerpc/platforms/pasemi/iommu.c
arch/powerpc/platforms/pseries/reconfig.c
arch/powerpc/sysdev/fsl_soc.c
arch/powerpc/sysdev/mpc8xx_pic.c
arch/powerpc/sysdev/qe_lib/qe.c
arch/ppc/Kconfig
arch/ppc/mm/pgtable.c
arch/s390/Kconfig
arch/s390/Kconfig.debug
arch/s390/kernel/compat_wrapper.S
arch/s390/kernel/entry.S
arch/s390/kernel/entry64.S
arch/s390/kernel/ipl.c
arch/s390/kernel/setup.c
arch/s390/kernel/smp.c
arch/s390/kernel/stacktrace.c
arch/s390/kernel/syscalls.S
arch/s390/kernel/traps.c
arch/s390/kernel/vmlinux.lds.S
arch/s390/mm/init.c
arch/s390/mm/vmem.c
arch/sh/Kconfig
arch/sh/drivers/pci/Kconfig
arch/sh/kernel/syscalls_32.S
arch/sh/kernel/syscalls_64.S
arch/sparc/Kconfig
arch/sparc/kernel/ioport.c
arch/sparc/kernel/systbls.S
arch/sparc/lib/rwsem.S
arch/sparc64/Kconfig
arch/sparc64/kernel/iommu.c
arch/sparc64/kernel/iommu_common.c
arch/sparc64/kernel/iommu_common.h
arch/sparc64/kernel/pci_sun4v.c
arch/sparc64/kernel/systbls.S
arch/sparc64/lib/GENbzero.S
arch/sparc64/lib/NGbzero.S
arch/sparc64/lib/rwsem.S
arch/sparc64/mm/init.c
arch/um/Kconfig
arch/um/Kconfig.char
arch/um/Kconfig.debug
arch/um/Kconfig.net
arch/um/Makefile
arch/um/Makefile-tt [deleted file]
arch/um/defconfig
arch/um/drivers/line.c
arch/um/drivers/mconsole_kern.c
arch/um/drivers/mconsole_user.c
arch/um/drivers/net_kern.c
arch/um/drivers/net_user.c
arch/um/drivers/port_kern.c
arch/um/drivers/random.c
arch/um/drivers/slip_user.c
arch/um/drivers/slirp_user.c
arch/um/drivers/ssl.c
arch/um/drivers/stdio_console.c
arch/um/drivers/ubd_kern.c
arch/um/drivers/ubd_user.c
arch/um/drivers/vde_user.c
arch/um/include/arch.h
arch/um/include/as-layout.h
arch/um/include/chan_user.h
arch/um/include/common-offsets.h
arch/um/include/init.h
arch/um/include/irq_user.h
arch/um/include/kern_util.h
arch/um/include/mem_user.h
arch/um/include/misc_constants.h [deleted file]
arch/um/include/os.h
arch/um/include/ptrace_user.h
arch/um/include/registers.h
arch/um/include/signal_kern.h [deleted file]
arch/um/include/skas/mode-skas.h [deleted file]
arch/um/include/sysdep-i386/syscalls.h
arch/um/include/sysdep-x86_64/kernel-offsets.h
arch/um/include/sysdep-x86_64/syscalls.h
arch/um/include/um_mmu.h
arch/um/include/um_uaccess.h
arch/um/kernel/exec.c
arch/um/kernel/exitcode.c
arch/um/kernel/gmon_syms.c
arch/um/kernel/gprof_syms.c
arch/um/kernel/initrd.c
arch/um/kernel/irq.c
arch/um/kernel/ksyms.c
arch/um/kernel/mem.c
arch/um/kernel/physmem.c
arch/um/kernel/process.c
arch/um/kernel/reboot.c
arch/um/kernel/sigio.c
arch/um/kernel/signal.c
arch/um/kernel/skas/clone.c
arch/um/kernel/skas/mmu.c
arch/um/kernel/skas/process.c
arch/um/kernel/skas/syscall.c
arch/um/kernel/skas/uaccess.c
arch/um/kernel/smp.c
arch/um/kernel/syscall.c
arch/um/kernel/sysrq.c
arch/um/kernel/time.c
arch/um/kernel/tlb.c
arch/um/kernel/trap.c
arch/um/kernel/uaccess.c
arch/um/kernel/um_arch.c
arch/um/kernel/umid.c
arch/um/os-Linux/Makefile
arch/um/os-Linux/aio.c
arch/um/os-Linux/drivers/ethertap_user.c
arch/um/os-Linux/drivers/tuntap_user.c
arch/um/os-Linux/file.c
arch/um/os-Linux/helper.c
arch/um/os-Linux/irq.c
arch/um/os-Linux/main.c
arch/um/os-Linux/mem.c
arch/um/os-Linux/process.c
arch/um/os-Linux/registers.c
arch/um/os-Linux/sigio.c
arch/um/os-Linux/signal.c
arch/um/os-Linux/skas/Makefile
arch/um/os-Linux/skas/process.c
arch/um/os-Linux/skas/trap.c [deleted file]
arch/um/os-Linux/start_up.c
arch/um/os-Linux/trap.c [deleted file]
arch/um/os-Linux/tty.c
arch/um/os-Linux/tty_log.c
arch/um/os-Linux/util.c
arch/um/sys-i386/bug.c
arch/um/sys-i386/bugs.c
arch/um/sys-i386/ldt.c
arch/um/sys-i386/ptrace.c
arch/um/sys-i386/ptrace_user.c
arch/um/sys-i386/signal.c
arch/um/sys-i386/stub.S
arch/um/sys-i386/stub_segv.c
arch/um/sys-i386/sys_call_table.S
arch/um/sys-i386/tls.c
arch/um/sys-ppc/Makefile
arch/um/sys-x86_64/bug.c
arch/um/sys-x86_64/bugs.c
arch/um/sys-x86_64/ptrace.c
arch/um/sys-x86_64/ptrace_user.c
arch/um/sys-x86_64/signal.c
arch/um/sys-x86_64/stub.S
arch/um/sys-x86_64/stub_segv.c
arch/um/sys-x86_64/syscall_table.c
arch/um/sys-x86_64/syscalls.c
arch/um/sys-x86_64/sysrq.c
arch/um/sys-x86_64/um_module.c
arch/v850/Kconfig
arch/x86/Kconfig
arch/x86/Makefile
arch/x86/boot/Makefile
arch/x86/boot/compressed/Makefile
arch/x86/boot/compressed/head_64.S
arch/x86/boot/compressed/vmlinux_64.lds
arch/x86/boot/cpu.c
arch/x86/boot/mkcpustr.c [new file with mode: 0644]
arch/x86/ia32/ia32entry.S
arch/x86/kernel/Makefile
arch/x86/kernel/acpi/boot.c
arch/x86/kernel/cpu/Makefile
arch/x86/kernel/cpu/amd.c
arch/x86/kernel/cpu/common.c
arch/x86/kernel/cpu/cpu.h
arch/x86/kernel/cpu/feature_names.c [new file with mode: 0644]
arch/x86/kernel/cpu/intel.c
arch/x86/kernel/cpu/intel_cacheinfo.c
arch/x86/kernel/cpu/mtrr/cyrix.c
arch/x86/kernel/cpu/mtrr/main.c
arch/x86/kernel/cpu/mtrr/mtrr.h
arch/x86/kernel/cpu/proc.c
arch/x86/kernel/cpuid.c
arch/x86/kernel/ds.c
arch/x86/kernel/e820_64.c
arch/x86/kernel/early_printk.c
arch/x86/kernel/efi.c
arch/x86/kernel/efi_64.c
arch/x86/kernel/head64.c
arch/x86/kernel/head_64.S
arch/x86/kernel/ldt.c
arch/x86/kernel/microcode.c
arch/x86/kernel/msr.c
arch/x86/kernel/pci-calgary_64.c
arch/x86/kernel/pci-gart_64.c
arch/x86/kernel/process_32.c
arch/x86/kernel/quirks.c
arch/x86/kernel/scx200_32.c
arch/x86/kernel/setup_64.c
arch/x86/kernel/smpboot_64.c
arch/x86/kernel/suspend_64.c
arch/x86/kernel/syscall_table_32.S
arch/x86/kernel/test_nx.c
arch/x86/kernel/topology.c
arch/x86/kernel/trampoline_32.S
arch/x86/kernel/trampoline_64.S
arch/x86/kernel/vmi_32.c
arch/x86/kvm/Kconfig
arch/x86/kvm/x86.c
arch/x86/lib/Makefile
arch/x86/lib/bitops_32.c
arch/x86/lib/bitops_64.c
arch/x86/lib/bitstr_64.c [deleted file]
arch/x86/lib/mmx_32.c
arch/x86/lib/usercopy_32.c
arch/x86/lib/usercopy_64.c
arch/x86/mm/fault.c
arch/x86/mm/init_32.c
arch/x86/mm/init_64.c
arch/x86/mm/ioremap.c
arch/x86/mm/numa_64.c
arch/x86/mm/pageattr-test.c
arch/x86/mm/pageattr.c
arch/x86/mm/pgtable_32.c
arch/x86/pci/fixup.c
arch/x86/pci/i386.c
arch/x86/pci/numa.c
arch/xtensa/Kconfig
block/as-iosched.c
block/blk-barrier.c
block/blk-core.c
block/blk-exec.c
block/blk-ioc.c
block/blk-map.c
block/blk-merge.c
block/blk-settings.c
block/blk-sysfs.c
block/blk-tag.c
block/cfq-iosched.c
block/elevator.c
drivers/Kconfig
drivers/Makefile
drivers/acpi/hardware/hwsleep.c
drivers/acpi/processor_idle.c
drivers/acpi/scan.c
drivers/acpi/sleep/main.c
drivers/acpi/sleep/sleep.h
drivers/acpi/utilities/utresrc.c
drivers/ata/Kconfig
drivers/ata/ahci.c
drivers/ata/ata_piix.c
drivers/ata/libata-core.c
drivers/ata/pata_at32.c
drivers/ata/pata_bf54x.c
drivers/ata/pata_cs5520.c
drivers/ata/pata_efar.c
drivers/ata/pata_it8213.c
drivers/ata/pata_sis.c
drivers/ata/pata_sl82c105.c
drivers/ata/sata_inic162x.c
drivers/ata/sata_mv.c
drivers/ata/sata_nv.c
drivers/base/Makefile
drivers/base/core.c
drivers/base/dmapool.c [deleted file]
drivers/base/driver.c
drivers/base/power/Makefile
drivers/base/power/main.c
drivers/base/power/power.h
drivers/block/Kconfig
drivers/block/cciss_scsi.c
drivers/block/sunvdc.c
drivers/block/ub.c
drivers/block/virtio_blk.c
drivers/bluetooth/bpa10x.c
drivers/bluetooth/bt3c_cs.c
drivers/bluetooth/btsdio.c
drivers/bluetooth/btuart_cs.c
drivers/bluetooth/hci_usb.c
drivers/cdrom/cdrom.c
drivers/cdrom/viocd.c
drivers/char/agp/agp.h
drivers/char/agp/alpha-agp.c
drivers/char/agp/amd-k7-agp.c
drivers/char/agp/backend.c
drivers/char/agp/compat_ioctl.c
drivers/char/agp/compat_ioctl.h
drivers/char/agp/frontend.c
drivers/char/agp/generic.c
drivers/char/agp/intel-agp.c
drivers/char/drm/drm_vm.c
drivers/char/drm/r300_reg.h
drivers/char/drm/via_dma.c
drivers/char/efirtc.c
drivers/char/epca.c
drivers/char/hangcheck-timer.c
drivers/char/hvcs.c
drivers/char/hw_random/core.c
drivers/char/ip2/i2lib.c
drivers/char/ip2/ip2main.c
drivers/char/misc.c
drivers/char/mspec.c
drivers/char/nozomi.c
drivers/char/pcmcia/cm4000_cs.c
drivers/char/random.c
drivers/char/synclink.c
drivers/char/toshiba.c
drivers/char/tty_audit.c
drivers/char/virtio_console.c
drivers/cpuidle/cpuidle.c
drivers/cpuidle/governors/ladder.c
drivers/cpuidle/governors/menu.c
drivers/dio/dio-driver.c
drivers/dio/dio.c
drivers/edac/edac_pci.c
drivers/edac/i5000_edac.c
drivers/firewire/fw-cdev.c
drivers/firewire/fw-device.c
drivers/firewire/fw-device.h
drivers/firewire/fw-ohci.c
drivers/firewire/fw-sbp2.c
drivers/firewire/fw-topology.c
drivers/firewire/fw-transaction.c
drivers/firmware/edd.c
drivers/gpio/Kconfig [new file with mode: 0644]
drivers/gpio/Makefile [new file with mode: 0644]
drivers/gpio/gpiolib.c [new file with mode: 0644]
drivers/gpio/mcp23s08.c [new file with mode: 0644]
drivers/gpio/pca9539.c [new file with mode: 0644]
drivers/gpio/pcf857x.c [new file with mode: 0644]
drivers/i2c/busses/scx200_acb.c
drivers/i2c/chips/Kconfig
drivers/ide/Kconfig
drivers/ide/Makefile
drivers/ide/arm/Makefile
drivers/ide/arm/bast-ide.c
drivers/ide/arm/icside.c
drivers/ide/arm/ide_arm.c
drivers/ide/arm/palm_bk3710.c [new file with mode: 0644]
drivers/ide/arm/rapide.c
drivers/ide/cris/ide-cris.c
drivers/ide/h8300/ide-h8300.c
drivers/ide/ide-acpi.c
drivers/ide/ide-cd.c
drivers/ide/ide-cd.h
drivers/ide/ide-cd_ioctl.c [new file with mode: 0644]
drivers/ide/ide-cd_verbose.c [new file with mode: 0644]
drivers/ide/ide-disk.c
drivers/ide/ide-dma.c
drivers/ide/ide-floppy.c
drivers/ide/ide-generic.c
drivers/ide/ide-io.c
drivers/ide/ide-iops.c
drivers/ide/ide-lib.c
drivers/ide/ide-pnp.c
drivers/ide/ide-probe.c
drivers/ide/ide-proc.c
drivers/ide/ide-scan-pci.c
drivers/ide/ide-tape.c
drivers/ide/ide-taskfile.c
drivers/ide/ide-timing.h
drivers/ide/ide.c
drivers/ide/legacy/ali14xx.c
drivers/ide/legacy/buddha.c
drivers/ide/legacy/dtc2278.c
drivers/ide/legacy/falconide.c
drivers/ide/legacy/gayle.c
drivers/ide/legacy/hd.c
drivers/ide/legacy/ht6560b.c
drivers/ide/legacy/ide-cs.c
drivers/ide/legacy/ide_platform.c
drivers/ide/legacy/macide.c
drivers/ide/legacy/q40ide.c
drivers/ide/legacy/qd65xx.c
drivers/ide/legacy/qd65xx.h
drivers/ide/legacy/umc8672.c
drivers/ide/mips/au1xxx-ide.c
drivers/ide/mips/swarm.c
drivers/ide/pci/Makefile
drivers/ide/pci/aec62xx.c
drivers/ide/pci/alim15x3.c
drivers/ide/pci/amd74xx.c
drivers/ide/pci/atiixp.c
drivers/ide/pci/cmd640.c
drivers/ide/pci/cmd64x.c
drivers/ide/pci/cs5520.c
drivers/ide/pci/cs5530.c
drivers/ide/pci/cs5535.c
drivers/ide/pci/cy82c693.c
drivers/ide/pci/delkin_cb.c
drivers/ide/pci/generic.c
drivers/ide/pci/hpt34x.c
drivers/ide/pci/hpt366.c
drivers/ide/pci/it8213.c
drivers/ide/pci/it821x.c
drivers/ide/pci/jmicron.c
drivers/ide/pci/ns87415.c
drivers/ide/pci/opti621.c
drivers/ide/pci/pdc202xx_new.c
drivers/ide/pci/pdc202xx_old.c
drivers/ide/pci/piix.c
drivers/ide/pci/rz1000.c
drivers/ide/pci/sc1200.c
drivers/ide/pci/scc_pata.c
drivers/ide/pci/serverworks.c
drivers/ide/pci/sgiioc4.c
drivers/ide/pci/siimage.c
drivers/ide/pci/sis5513.c
drivers/ide/pci/sl82c105.c
drivers/ide/pci/slc90e66.c
drivers/ide/pci/tc86c001.c
drivers/ide/pci/triflex.c
drivers/ide/pci/trm290.c
drivers/ide/pci/via82cxxx.c
drivers/ide/ppc/mpc8xx.c
drivers/ide/ppc/pmac.c
drivers/ide/setup-pci.c
drivers/ieee1394/dma.c
drivers/ieee1394/ieee1394_transactions.c
drivers/ieee1394/ohci1394.c
drivers/ieee1394/raw1394.c
drivers/ieee1394/sbp2.c
drivers/ieee1394/sbp2.h
drivers/infiniband/Kconfig
drivers/infiniband/Makefile
drivers/infiniband/core/cm.c
drivers/infiniband/core/fmr_pool.c
drivers/infiniband/hw/ehca/ehca_classes.h
drivers/infiniband/hw/ehca/ehca_irq.c
drivers/infiniband/hw/ehca/ehca_iverbs.h
drivers/infiniband/hw/ehca/ehca_main.c
drivers/infiniband/hw/ehca/ehca_reqs.c
drivers/infiniband/hw/ehca/ehca_sqp.c
drivers/infiniband/hw/mlx4/main.c
drivers/infiniband/hw/mthca/mthca_cmd.c
drivers/infiniband/hw/mthca/mthca_main.c
drivers/infiniband/hw/mthca/mthca_mr.c
drivers/infiniband/hw/mthca/mthca_provider.c
drivers/infiniband/hw/mthca/mthca_qp.c
drivers/infiniband/hw/mthca/mthca_srq.c
drivers/infiniband/hw/nes/Kconfig [new file with mode: 0644]
drivers/infiniband/hw/nes/Makefile [new file with mode: 0644]
drivers/infiniband/hw/nes/nes.c [new file with mode: 0644]
drivers/infiniband/hw/nes/nes.h [new file with mode: 0644]
drivers/infiniband/hw/nes/nes_cm.c [new file with mode: 0644]
drivers/infiniband/hw/nes/nes_cm.h [new file with mode: 0644]
drivers/infiniband/hw/nes/nes_context.h [new file with mode: 0644]
drivers/infiniband/hw/nes/nes_hw.c [new file with mode: 0644]
drivers/infiniband/hw/nes/nes_hw.h [new file with mode: 0644]
drivers/infiniband/hw/nes/nes_nic.c [new file with mode: 0644]
drivers/infiniband/hw/nes/nes_user.h [new file with mode: 0644]
drivers/infiniband/hw/nes/nes_utils.c [new file with mode: 0644]
drivers/infiniband/hw/nes/nes_verbs.c [new file with mode: 0644]
drivers/infiniband/hw/nes/nes_verbs.h [new file with mode: 0644]
drivers/infiniband/ulp/ipoib/ipoib_main.c
drivers/infiniband/ulp/srp/ib_srp.c
drivers/infiniband/ulp/srp/ib_srp.h
drivers/input/gameport/gameport.c
drivers/input/keyboard/bf54x-keys.c
drivers/input/keyboard/jornada720_kbd.c
drivers/input/serio/gscps2.c
drivers/input/touchscreen/ucb1400_ts.c
drivers/isdn/hardware/eicon/debuglib.c
drivers/isdn/hardware/eicon/debuglib.h
drivers/isdn/hardware/eicon/di.c
drivers/isdn/hardware/eicon/message.c
drivers/isdn/hysdn/hycapi.c
drivers/leds/led-class.c
drivers/lguest/lguest_device.c
drivers/lguest/x86/core.c
drivers/macintosh/adb.c
drivers/macintosh/mediabay.c
drivers/macintosh/smu.c
drivers/macintosh/via-macii.c
drivers/media/common/saa7146_core.c
drivers/media/dvb/dvb-core/dvb_net.c
drivers/media/video/bt8xx/bttv-cards.c
drivers/media/video/cx88/cx88-alsa.c
drivers/media/video/indycam.c
drivers/media/video/mt20xx.c
drivers/media/video/pvrusb2/pvrusb2.h
drivers/media/video/pwc/pwc-if.c
drivers/media/video/saa7134/saa7134-alsa.c
drivers/media/video/saa7134/saa7134.h
drivers/media/video/tea6420.c
drivers/media/video/usbvideo/quickcam_messenger.c
drivers/media/video/usbvision/usbvision-video.c
drivers/media/video/vpx3220.c
drivers/media/video/zoran_card.c
drivers/media/video/zr36050.c
drivers/media/video/zr36060.c
drivers/message/fusion/lsi/mpi_log_sas.h
drivers/message/fusion/mptctl.c
drivers/message/fusion/mptscsih.c
drivers/message/i2o/iop.c
drivers/mtd/devices/doc2000.c
drivers/mtd/nand/autcpu12.c
drivers/mtd/nand/bf5xx_nand.c
drivers/mtd/nand/cs553x_nand.c
drivers/mtd/nand/edb7312.c
drivers/mtd/nand/nand_base.c
drivers/mtd/nand/nandsim.c
drivers/mtd/nand/s3c2410.c
drivers/mtd/nand/sharpsl.c
drivers/mtd/nftlmount.c
drivers/net/Kconfig
drivers/net/arm/at91_ether.c
drivers/net/ax88796.c
drivers/net/bfin_mac.c
drivers/net/bfin_mac.h
drivers/net/bnx2.c
drivers/net/bnx2.h
drivers/net/bnx2_fw.h
drivers/net/bnx2_fw2.h
drivers/net/bonding/bond_main.c
drivers/net/bonding/bonding.h
drivers/net/cpmac.c
drivers/net/cxgb3/cxgb3_offload.c
drivers/net/cxgb3/mc5.c
drivers/net/cxgb3/sge.c
drivers/net/cxgb3/t3_hw.c
drivers/net/dl2k.h
drivers/net/e100.c
drivers/net/e1000/e1000_main.c
drivers/net/e1000e/defines.h
drivers/net/e1000e/ethtool.c
drivers/net/e1000e/netdev.c
drivers/net/eexpress.c
drivers/net/ehea/ehea.h
drivers/net/ehea/ehea_ethtool.c
drivers/net/ehea/ehea_hw.h
drivers/net/ehea/ehea_main.c
drivers/net/ehea/ehea_phyp.c
drivers/net/ehea/ehea_phyp.h
drivers/net/ehea/ehea_qmr.c
drivers/net/ehea/ehea_qmr.h
drivers/net/forcedeth.c
drivers/net/hamradio/dmascc.c
drivers/net/ibmlana.c
drivers/net/igb/igb_main.c
drivers/net/irda/ali-ircc.h
drivers/net/irda/nsc-ircc.h
drivers/net/irda/via-ircc.h
drivers/net/lib8390.c
drivers/net/macb.c
drivers/net/macvlan.c
drivers/net/mipsnet.c
drivers/net/mipsnet.h [deleted file]
drivers/net/mlx4/fw.c
drivers/net/mlx4/fw.h
drivers/net/mlx4/main.c
drivers/net/mlx4/mr.c
drivers/net/natsemi.c
drivers/net/pasemi_mac.c
drivers/net/pasemi_mac.h
drivers/net/pci-skeleton.c
drivers/net/pcmcia/3c574_cs.c
drivers/net/pcmcia/3c589_cs.c
drivers/net/pcmcia/axnet_cs.c
drivers/net/pcmcia/fmvj18x_cs.c
drivers/net/pcmcia/nmclan_cs.c
drivers/net/pcmcia/pcnet_cs.c
drivers/net/pcmcia/smc91c92_cs.c
drivers/net/pcmcia/xirc2ps_cs.c
drivers/net/phy/Kconfig
drivers/net/phy/Makefile
drivers/net/phy/broadcom.c
drivers/net/phy/mdio_bus.c
drivers/net/phy/phy.c
drivers/net/phy/phy_device.c
drivers/net/phy/realtek.c [new file with mode: 0644]
drivers/net/s2io.c
drivers/net/s2io.h
drivers/net/sis190.c
drivers/net/skfp/ess.c
drivers/net/skfp/fplustm.c
drivers/net/skfp/hwmtm.c
drivers/net/sky2.c
drivers/net/sunbmac.c
drivers/net/sunqe.c
drivers/net/sunvnet.c
drivers/net/tokenring/abyss.c
drivers/net/tokenring/abyss.h
drivers/net/tokenring/madgemc.c
drivers/net/tokenring/madgemc.h
drivers/net/tokenring/olympic.c
drivers/net/tokenring/proteon.c
drivers/net/tokenring/skisa.c
drivers/net/tokenring/tms380tr.c
drivers/net/tokenring/tms380tr.h
drivers/net/tokenring/tmspci.c
drivers/net/tun.c
drivers/net/ucc_geth.c
drivers/net/usb/asix.c
drivers/net/usb/cdc_ether.c
drivers/net/usb/cdc_subset.c
drivers/net/usb/dm9601.c
drivers/net/usb/gl620a.c
drivers/net/usb/mcs7830.c
drivers/net/usb/net1080.c
drivers/net/usb/plusb.c
drivers/net/usb/rndis_host.c
drivers/net/usb/rtl8150.c
drivers/net/usb/usbnet.c
drivers/net/usb/zaurus.c
drivers/net/via-rhine.c
drivers/net/via-velocity.c
drivers/net/via-velocity.h
drivers/net/virtio_net.c
drivers/net/wan/cycx_drv.c
drivers/net/wireless/Kconfig
drivers/net/wireless/Makefile
drivers/net/wireless/ath5k/base.c
drivers/net/wireless/ath5k/debug.c
drivers/net/wireless/ath5k/debug.h
drivers/net/wireless/b43/b43.h
drivers/net/wireless/b43/dma.c
drivers/net/wireless/b43/leds.c
drivers/net/wireless/b43/main.c
drivers/net/wireless/b43/xmit.c
drivers/net/wireless/b43/xmit.h
drivers/net/wireless/b43legacy/b43legacy.h
drivers/net/wireless/b43legacy/main.c
drivers/net/wireless/b43legacy/phy.c
drivers/net/wireless/b43legacy/pio.c
drivers/net/wireless/b43legacy/radio.c
drivers/net/wireless/hostap/hostap_80211.h
drivers/net/wireless/hostap/hostap_cs.c
drivers/net/wireless/ipw2100.c
drivers/net/wireless/iwlwifi/iwl-3945-hw.h
drivers/net/wireless/iwlwifi/iwl-3945.c
drivers/net/wireless/iwlwifi/iwl-3945.h
drivers/net/wireless/iwlwifi/iwl-4965-hw.h
drivers/net/wireless/iwlwifi/iwl-4965.c
drivers/net/wireless/iwlwifi/iwl-4965.h
drivers/net/wireless/iwlwifi/iwl-helpers.h
drivers/net/wireless/iwlwifi/iwl3945-base.c
drivers/net/wireless/iwlwifi/iwl4965-base.c
drivers/net/wireless/libertas/assoc.c
drivers/net/wireless/libertas/dev.h
drivers/net/wireless/libertas/if_cs.c
drivers/net/wireless/libertas/scan.c
drivers/net/wireless/netwave_cs.c
drivers/net/wireless/rndis_wlan.c [new file with mode: 0644]
drivers/net/wireless/rt2x00/rt61pci.c
drivers/net/wireless/rtl8180_dev.c
drivers/net/wireless/wavelan_cs.c
drivers/nubus/Makefile
drivers/nubus/nubus.c
drivers/nubus/nubus_syms.c [deleted file]
drivers/nubus/proc.c
drivers/of/base.c
drivers/of/platform.c
drivers/parisc/ccio-dma.c
drivers/parisc/hppb.c
drivers/parisc/iommu-helpers.h
drivers/parisc/sba_iommu.c
drivers/parport/probe.c
drivers/pci/Makefile
drivers/pci/bus.c
drivers/pci/dmar.c
drivers/pci/hotplug-pci.c [new file with mode: 0644]
drivers/pci/hotplug/Kconfig
drivers/pci/hotplug/Makefile
drivers/pci/hotplug/acpiphp.h
drivers/pci/hotplug/acpiphp_glue.c
drivers/pci/hotplug/fakephp.c
drivers/pci/hotplug/ibmphp_core.c
drivers/pci/hotplug/pci_hotplug_core.c
drivers/pci/hotplug/pciehp.h
drivers/pci/hotplug/pciehp_core.c
drivers/pci/hotplug/pciehp_ctrl.c
drivers/pci/hotplug/pciehp_hpc.c
drivers/pci/hotplug/pciehp_pci.c
drivers/pci/hotplug/rpaphp.h
drivers/pci/hotplug/rpaphp_pci.c
drivers/pci/hotplug/rpaphp_slot.c
drivers/pci/hotplug/shpchp_hpc.c
drivers/pci/intel-iommu.c
drivers/pci/msi.c
drivers/pci/pci-acpi.c
drivers/pci/pci-driver.c
drivers/pci/pci-sysfs.c
drivers/pci/pci.c
drivers/pci/pci.h
drivers/pci/pcie/aer/aerdrv_acpi.c
drivers/pci/pcie/portdrv_core.c
drivers/pci/probe.c
drivers/pci/proc.c
drivers/pci/quirks.c
drivers/pci/remove.c
drivers/pci/rom.c
drivers/pci/setup-bus.c
drivers/pci/setup-res.c
drivers/pci/syscall.c
drivers/pcmcia/at91_cf.c
drivers/pcmcia/cardbus.c
drivers/pcmcia/ds.c
drivers/pcmcia/i82092.c
drivers/pcmcia/i82365.c
drivers/pcmcia/m32r_cfc.c
drivers/pcmcia/m32r_pcc.c
drivers/pcmcia/m8xx_pcmcia.c
drivers/pcmcia/pcmcia_resource.c
drivers/pcmcia/rsrc_nonstatic.c
drivers/pcmcia/sa1100_jornada720.c
drivers/pcmcia/tcic.c
drivers/power/apm_power.c
drivers/power/olpc_battery.c
drivers/power/pda_power.c
drivers/power/power_supply_leds.c
drivers/power/power_supply_sysfs.c
drivers/s390/block/dasd.c
drivers/s390/block/dasd_3990_erp.c
drivers/s390/block/dcssblk.c
drivers/s390/char/sclp_tty.c
drivers/s390/char/sclp_vt220.c
drivers/s390/cio/ccwgroup.c
drivers/s390/cio/chsc.c
drivers/s390/cio/device_id.c
drivers/scsi/NCR53C9x.h
drivers/scsi/aacraid/linit.c
drivers/scsi/aha1542.c
drivers/scsi/aic7xxx/Makefile
drivers/scsi/aic7xxx/aic79xx_inline.h
drivers/scsi/aic7xxx/aic79xx_osm.c
drivers/scsi/aic7xxx/aic79xx_pci.c
drivers/scsi/aic7xxx/aic7xxx_inline.h
drivers/scsi/aic7xxx/aic7xxx_osm.c
drivers/scsi/ide-scsi.c
drivers/scsi/ipr.c
drivers/scsi/ips.c
drivers/scsi/lpfc/lpfc.h
drivers/scsi/lpfc/lpfc_init.c
drivers/scsi/lpfc/lpfc_mbox.c
drivers/scsi/megaraid/megaraid_mbox.c
drivers/scsi/pcmcia/fdomain_stub.c
drivers/scsi/qla2xxx/qla_def.h
drivers/scsi/qla2xxx/qla_gs.c
drivers/scsi/qla2xxx/qla_os.c
drivers/scsi/qla4xxx/ql4_def.h
drivers/scsi/qla4xxx/ql4_init.c
drivers/scsi/scsi_lib.c
drivers/scsi/scsi_tgt_lib.c
drivers/scsi/scsi_transport_sas.c
drivers/serial/21285.c
drivers/serial/68328serial.c
drivers/serial/8250.c
drivers/serial/8250_pci.c
drivers/serial/8250_pnp.c
drivers/serial/Kconfig
drivers/serial/Makefile
drivers/serial/atmel_serial.c
drivers/serial/icom.h
drivers/serial/mcf.c
drivers/serial/mpsc.c
drivers/serial/mux.c
drivers/serial/s3c2410.c
drivers/serial/serial_core.c
drivers/serial/serial_cs.c
drivers/spi/spi_imx.c
drivers/ssb/b43_pci_bridge.c
drivers/usb/Kconfig
drivers/usb/atm/Kconfig
drivers/usb/atm/ueagle-atm.c
drivers/usb/class/cdc-acm.c
drivers/usb/class/cdc-acm.h
drivers/usb/core/Kconfig
drivers/usb/core/buffer.c
drivers/usb/core/config.c
drivers/usb/core/devices.c
drivers/usb/core/devio.c
drivers/usb/core/driver.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/inode.c
drivers/usb/core/message.c
drivers/usb/core/notify.c
drivers/usb/core/otg_whitelist.h
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/amd5536udc.c
drivers/usb/gadget/at91_udc.c
drivers/usb/gadget/at91_udc.h
drivers/usb/gadget/atmel_usba_udc.c
drivers/usb/gadget/atmel_usba_udc.h
drivers/usb/gadget/dummy_hcd.c
drivers/usb/gadget/ether.c
drivers/usb/gadget/file_storage.c
drivers/usb/gadget/fsl_usb2_udc.c
drivers/usb/gadget/fsl_usb2_udc.h
drivers/usb/gadget/gmidi.c
drivers/usb/gadget/goku_udc.c
drivers/usb/gadget/inode.c
drivers/usb/gadget/lh7a40x_udc.c
drivers/usb/gadget/m66592-udc.c
drivers/usb/gadget/m66592-udc.h
drivers/usb/gadget/net2280.c
drivers/usb/gadget/omap_udc.c
drivers/usb/gadget/omap_udc.h
drivers/usb/gadget/printer.c [new file with mode: 0644]
drivers/usb/gadget/pxa2xx_udc.c
drivers/usb/gadget/pxa2xx_udc.h
drivers/usb/gadget/rndis.c
drivers/usb/gadget/s3c2410_udc.c
drivers/usb/gadget/serial.c
drivers/usb/gadget/zero.c
drivers/usb/host/Kconfig
drivers/usb/host/ehci-au1xxx.c
drivers/usb/host/ehci-dbg.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 [new file with mode: 0644]
drivers/usb/host/ehci-orion.c [new file with mode: 0644]
drivers/usb/host/ehci-pci.c
drivers/usb/host/ehci-ppc-of.c [new file with mode: 0644]
drivers/usb/host/ehci-ppc-soc.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/isp116x-hcd.c
drivers/usb/host/ohci-at91.c
drivers/usb/host/ohci-dbg.c
drivers/usb/host/ohci-hcd.c
drivers/usb/host/ohci-sh.c [new file with mode: 0644]
drivers/usb/host/ohci-sm501.c [new file with mode: 0644]
drivers/usb/host/ohci.h
drivers/usb/host/pci-quirks.c
drivers/usb/host/r8a66597.h
drivers/usb/image/mdc800.c
drivers/usb/misc/cypress_cy7c63.c
drivers/usb/misc/iowarrior.c
drivers/usb/misc/legousbtower.c
drivers/usb/misc/sisusbvga/sisusb.c
drivers/usb/misc/sisusbvga/sisusb.h
drivers/usb/misc/usbtest.c
drivers/usb/mon/mon_bin.c
drivers/usb/serial/Kconfig
drivers/usb/serial/Makefile
drivers/usb/serial/airprime.c
drivers/usb/serial/ark3116.c
drivers/usb/serial/belkin_sa.c
drivers/usb/serial/console.c
drivers/usb/serial/cp2101.c
drivers/usb/serial/cyberjack.c
drivers/usb/serial/cypress_m8.c
drivers/usb/serial/digi_acceleport.c
drivers/usb/serial/ezusb.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_ti.c
drivers/usb/serial/iuu_phoenix.c [new file with mode: 0644]
drivers/usb/serial/iuu_phoenix.h [new file with mode: 0644]
drivers/usb/serial/keyspan.c
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/mct_u232.h
drivers/usb/serial/mos7720.c
drivers/usb/serial/mos7840.c
drivers/usb/serial/option.c
drivers/usb/serial/oti6858.c
drivers/usb/serial/pl2303.c
drivers/usb/serial/pl2303.h
drivers/usb/serial/sierra.c
drivers/usb/serial/ti_usb_3410_5052.c
drivers/usb/serial/usb-serial.c
drivers/usb/serial/visor.c
drivers/usb/serial/whiteheat.c
drivers/usb/storage/initializers.c
drivers/usb/storage/isd200.c
drivers/usb/storage/unusual_devs.h
drivers/video/aty/radeon_pm.c
drivers/video/cyblafb.c
drivers/video/intelfb/intelfb.h
drivers/video/omap/lcdc.c
drivers/video/sis/sis.h
drivers/video/sis/sis_main.c
drivers/video/sm501fb.c
drivers/virtio/Kconfig
drivers/virtio/Makefile
drivers/virtio/virtio.c
drivers/virtio/virtio_balloon.c [new file with mode: 0644]
drivers/virtio/virtio_pci.c [new file with mode: 0644]
drivers/virtio/virtio_ring.c
drivers/watchdog/shwdt.c
fs/Kconfig
fs/befs/btree.c
fs/befs/datastream.c
fs/binfmt_elf.c
fs/buffer.c
fs/cifs/inode.c
fs/compat.c
fs/direct-io.c
fs/ecryptfs/mmap.c
fs/eventpoll.c
fs/exec.c
fs/ext3/inode.c
fs/ext4/inode.c
fs/freevxfs/vxfs_dir.h
fs/freevxfs/vxfs_immed.c
fs/fs-writeback.c
fs/gfs2/bmap.c
fs/gfs2/ops_address.c
fs/gfs2/recovery.c
fs/hostfs/hostfs_user.c
fs/hugetlbfs/inode.c
fs/jffs2/readinode.c
fs/jfs/jfs_xtree.c
fs/libfs.c
fs/lockd/host.c
fs/lockd/svc.c
fs/lockd/svc4proc.c
fs/lockd/svclock.c
fs/lockd/svcproc.c
fs/lockd/svcsubs.c
fs/locks.c
fs/mpage.c
fs/ncpfs/mmap.c
fs/nfs/callback.c
fs/nfs/client.c
fs/nfs/direct.c
fs/nfs/inode.c
fs/nfs/mount_clnt.c
fs/nfs/nfs3proc.c
fs/nfs/nfs4proc.c
fs/nfs/nfsroot.c
fs/nfs/pagelist.c
fs/nfs/read.c
fs/nfs/super.c
fs/nfs/write.c
fs/nfsd/auth.c
fs/nfsd/auth.h [moved from include/linux/nfsd/auth.h with 87% similarity]
fs/nfsd/export.c
fs/nfsd/nfs2acl.c
fs/nfsd/nfs3xdr.c
fs/nfsd/nfs4callback.c
fs/nfsd/nfs4idmap.c
fs/nfsd/nfs4proc.c
fs/nfsd/nfs4state.c
fs/nfsd/nfs4xdr.c
fs/nfsd/nfscache.c
fs/nfsd/nfsctl.c
fs/nfsd/nfsfh.c
fs/nfsd/nfssvc.c
fs/nfsd/nfsxdr.c
fs/nfsd/vfs.c
fs/ntfs/aops.c
fs/ntfs/compress.c
fs/ntfs/file.c
fs/ntfs/malloc.h
fs/ocfs2/alloc.c
fs/ocfs2/aops.c
fs/ocfs2/dir.c
fs/ocfs2/ocfs1_fs_compat.h
fs/ocfs2/suballoc.c
fs/proc/array.c
fs/proc/base.c
fs/proc/internal.h
fs/proc/kcore.c
fs/proc/proc_misc.c
fs/proc/task_mmu.c
fs/readdir.c
fs/reiserfs/bitmap.c
fs/reiserfs/inode.c
fs/signalfd.c
fs/smbfs/inode.c
fs/smbfs/request.c
fs/splice.c
fs/timerfd.c
fs/xattr.c
fs/xfs/linux-2.6/kmem.c
fs/xfs/linux-2.6/xfs_buf.c
fs/xfs/linux-2.6/xfs_lrw.c
include/acpi/acpixf.h
include/acpi/processor.h
include/asm-alpha/atomic.h
include/asm-alpha/pci.h
include/asm-alpha/pgalloc.h
include/asm-alpha/socket.h
include/asm-alpha/tlb.h
include/asm-alpha/tlbflush.h
include/asm-alpha/unistd.h
include/asm-arm/arch-at91/at91_mci.h
include/asm-arm/arch-at91/at91rm9200.h
include/asm-arm/arch-at91/at91sam9260.h
include/asm-arm/arch-at91/at91sam9261.h
include/asm-arm/arch-at91/at91sam9263.h
include/asm-arm/arch-at91/at91sam9rl.h
include/asm-arm/arch-at91/board.h
include/asm-arm/arch-at91/uncompress.h
include/asm-arm/arch-ixp4xx/cpu.h
include/asm-arm/arch-ixp4xx/dsmg600.h
include/asm-arm/arch-ixp4xx/hardware.h
include/asm-arm/arch-ixp4xx/io.h
include/asm-arm/arch-ixp4xx/ixp4xx-regs.h
include/asm-arm/arch-ixp4xx/nas100d.h
include/asm-arm/arch-ixp4xx/npe.h [new file with mode: 0644]
include/asm-arm/arch-ixp4xx/nslu2.h
include/asm-arm/arch-ixp4xx/platform.h
include/asm-arm/arch-ixp4xx/qmgr.h [new file with mode: 0644]
include/asm-arm/arch-ixp4xx/uncompress.h
include/asm-arm/arch-omap/eac.h
include/asm-arm/arch-omap/omap-alsa.h
include/asm-arm/arch-pxa/audio.h
include/asm-arm/arch-pxa/gpio.h
include/asm-arm/arch-pxa/pxa-regs.h
include/asm-arm/arch-pxa/pxa3xx-regs.h
include/asm-arm/arch-realview/board-eb.h [new file with mode: 0644]
include/asm-arm/arch-realview/entry-macro.S
include/asm-arm/arch-realview/hardware.h
include/asm-arm/arch-realview/irqs.h
include/asm-arm/arch-realview/platform.h
include/asm-arm/arch-realview/scu.h
include/asm-arm/arch-realview/uncompress.h
include/asm-arm/arch-versatile/irqs.h
include/asm-arm/hardware/arm_twd.h
include/asm-arm/hardware/it8152.h
include/asm-arm/kexec.h
include/asm-arm/mach/udc_pxa2xx.h
include/asm-arm/pgalloc.h
include/asm-arm/smp.h
include/asm-arm/socket.h
include/asm-arm/tlb.h
include/asm-avr32/arch-at32ap/at32ap700x.h
include/asm-avr32/arch-at32ap/gpio.h
include/asm-avr32/arch-at32ap/irq.h
include/asm-avr32/pgalloc.h
include/asm-avr32/socket.h
include/asm-avr32/unistd.h
include/asm-blackfin/socket.h
include/asm-cris/bitops.h
include/asm-cris/pgalloc.h
include/asm-cris/socket.h
include/asm-frv/atomic.h
include/asm-frv/bitops.h
include/asm-frv/cacheflush.h
include/asm-frv/dma-mapping.h
include/asm-frv/highmem.h
include/asm-frv/mem-layout.h
include/asm-frv/page.h
include/asm-frv/pgalloc.h
include/asm-frv/pgtable.h
include/asm-frv/scatterlist.h
include/asm-frv/socket.h
include/asm-frv/unistd.h
include/asm-generic/4level-fixup.h
include/asm-generic/gpio.h
include/asm-generic/pgtable-nopmd.h
include/asm-generic/pgtable-nopud.h
include/asm-generic/rtc.h
include/asm-generic/tlb.h
include/asm-h8300/socket.h
include/asm-ia64/bitops.h
include/asm-ia64/compat.h
include/asm-ia64/gcc_intrin.h
include/asm-ia64/mca.h
include/asm-ia64/mca_asm.h
include/asm-ia64/percpu.h
include/asm-ia64/pgalloc.h
include/asm-ia64/processor.h
include/asm-ia64/sal.h
include/asm-ia64/socket.h
include/asm-m32r/irq.h
include/asm-m32r/m32700ut/m32700ut_pld.h
include/asm-m32r/pgalloc.h
include/asm-m32r/socket.h
include/asm-m32r/unistd.h
include/asm-m68k/macintosh.h
include/asm-m68k/motorola_pgalloc.h
include/asm-m68k/socket.h
include/asm-m68k/sun3_pgalloc.h
include/asm-m68knommu/bitops.h
include/asm-m68knommu/cacheflush.h
include/asm-m68knommu/commproc.h
include/asm-m68knommu/delay.h
include/asm-m68knommu/m5249sim.h
include/asm-m68knommu/m5307sim.h
include/asm-m68knommu/m5407sim.h
include/asm-m68knommu/m68360_regs.h
include/asm-m68knommu/mcfcache.h
include/asm-m68knommu/mcfne.h
include/asm-m68knommu/mcfsim.h
include/asm-m68knommu/mcftimer.h
include/asm-m68knommu/mcfuart.h
include/asm-m68knommu/system.h
include/asm-mips/compat.h
include/asm-mips/mach-au1x00/au1xxx_ide.h
include/asm-mips/mach-excite/excite_fpga.h
include/asm-mips/mach-wrppmc/mach-gt64120.h
include/asm-mips/pgalloc.h
include/asm-mips/processor.h
include/asm-mips/sgi/ip22.h
include/asm-mips/sn/sn0/hubio.h
include/asm-mips/socket.h
include/asm-parisc/compat.h
include/asm-parisc/elf.h
include/asm-parisc/linkage.h
include/asm-parisc/pgalloc.h
include/asm-parisc/processor.h
include/asm-parisc/socket.h
include/asm-parisc/tlb.h
include/asm-parisc/vga.h
include/asm-powerpc/compat.h
include/asm-powerpc/cputable.h
include/asm-powerpc/iommu.h
include/asm-powerpc/mediabay.h
include/asm-powerpc/nvram.h
include/asm-powerpc/oprofile_impl.h
include/asm-powerpc/percpu.h
include/asm-powerpc/pgalloc-32.h
include/asm-powerpc/pgalloc-64.h
include/asm-powerpc/processor.h
include/asm-powerpc/reg.h
include/asm-powerpc/reg_booke.h
include/asm-powerpc/reg_fsl_emb.h [new file with mode: 0644]
include/asm-powerpc/socket.h
include/asm-powerpc/systbl.h
include/asm-powerpc/vio.h
include/asm-ppc/pgalloc.h
include/asm-s390/bitops.h
include/asm-s390/cacheflush.h
include/asm-s390/ccwgroup.h
include/asm-s390/compat.h
include/asm-s390/percpu.h
include/asm-s390/pgalloc.h
include/asm-s390/pgtable.h
include/asm-s390/processor.h
include/asm-s390/socket.h
include/asm-s390/tlb.h
include/asm-sh/pgalloc.h
include/asm-sh/socket.h
include/asm-sh/unistd_32.h
include/asm-sh/unistd_64.h
include/asm-sparc/pgalloc.h
include/asm-sparc/socket.h
include/asm-sparc64/compat.h
include/asm-sparc64/percpu.h
include/asm-sparc64/pgalloc.h
include/asm-sparc64/socket.h
include/asm-sparc64/tlb.h
include/asm-um/a.out.h
include/asm-um/current.h
include/asm-um/elf-i386.h
include/asm-um/elf-x86_64.h
include/asm-um/fixmap.h
include/asm-um/ldt.h
include/asm-um/linkage.h
include/asm-um/mmu_context.h
include/asm-um/page.h
include/asm-um/param.h
include/asm-um/pgalloc.h
include/asm-um/pgtable-2level.h
include/asm-um/pgtable-3level.h
include/asm-um/pgtable.h
include/asm-um/processor-generic.h
include/asm-um/processor-i386.h
include/asm-um/thread_info.h
include/asm-um/tlb.h
include/asm-um/uaccess.h
include/asm-v850/socket.h
include/asm-x86/asm.h
include/asm-x86/bitops_64.h
include/asm-x86/bugs.h
include/asm-x86/compat.h
include/asm-x86/cpu.h
include/asm-x86/cpufeature.h
include/asm-x86/e820_64.h
include/asm-x86/efi.h
include/asm-x86/futex.h
include/asm-x86/highmem.h
include/asm-x86/hw_irq_32.h
include/asm-x86/i387.h
include/asm-x86/io_32.h
include/asm-x86/mach-numaq/mach_apic.h
include/asm-x86/mach-voyager/do_timer.h
include/asm-x86/msr.h
include/asm-x86/page.h
include/asm-x86/page_64.h
include/asm-x86/pgalloc_32.h
include/asm-x86/pgalloc_64.h
include/asm-x86/pgtable-3level.h
include/asm-x86/pgtable.h
include/asm-x86/pgtable_32.h
include/asm-x86/pgtable_64.h
include/asm-x86/socket.h
include/asm-x86/string_32.h
include/asm-x86/system.h
include/asm-x86/thread_info_64.h
include/asm-x86/uaccess_32.h
include/asm-x86/uaccess_64.h
include/asm-x86/unistd_32.h
include/asm-x86/unistd_64.h
include/asm-x86/vm86.h
include/asm-xtensa/pgalloc.h
include/asm-xtensa/socket.h
include/asm-xtensa/tlb.h
include/linux/Kbuild
include/linux/agp_backend.h
include/linux/agpgart.h
include/linux/atmel_serial.h [moved from drivers/serial/atmel_serial.h with 99% similarity]
include/linux/audit.h
include/linux/blkdev.h
include/linux/capability.h
include/linux/cdrom.h
include/linux/chio.h
include/linux/compat.h
include/linux/completion.h
include/linux/cyclades.h
include/linux/cycx_x25.h
include/linux/dccp.h
include/linux/device.h
include/linux/dma-mapping.h
include/linux/dmaengine.h
include/linux/ethtool.h
include/linux/fs.h
include/linux/futex.h
include/linux/gfp.h
include/linux/hdreg.h
include/linux/hdsmart.h
include/linux/highmem.h
include/linux/hrtimer.h
include/linux/hw_random.h
include/linux/i2c/pca9539.h [new file with mode: 0644]
include/linux/i2c/pcf857x.h [new file with mode: 0644]
include/linux/ide.h
include/linux/ieee80211.h
include/linux/inetdevice.h
include/linux/init.h
include/linux/init_task.h
include/linux/input.h
include/linux/iommu-helper.h [new file with mode: 0644]
include/linux/ipv6.h
include/linux/latency.h [deleted file]
include/linux/leds.h
include/linux/lguest_launcher.h
include/linux/llc.h
include/linux/lockd/lockd.h
include/linux/lockd/xdr.h
include/linux/miscdevice.h
include/linux/mm.h
include/linux/mmzone.h
include/linux/mod_devicetable.h
include/linux/mutex.h
include/linux/netdevice.h
include/linux/netfilter/nf_conntrack_pptp.h
include/linux/netfilter/nf_conntrack_sip.h
include/linux/netfilter/x_tables.h
include/linux/netfilter/xt_conntrack.h
include/linux/netfilter/xt_hashlimit.h
include/linux/netfilter/xt_owner.h
include/linux/netfilter_arp/arp_tables.h
include/linux/netfilter_ipv4/ip_tables.h
include/linux/netfilter_ipv6/ip6_tables.h
include/linux/netlink.h
include/linux/nfs_fs.h
include/linux/nfs_mount.h
include/linux/nfsd/Kbuild
include/linux/nfsd/cache.h
include/linux/nfsd/export.h
include/linux/nfsd/nfsd.h
include/linux/nfsd/syscall.h
include/linux/nfsd/xdr.h
include/linux/nfsd/xdr3.h
include/linux/nfsd/xdr4.h
include/linux/nfsd_idmap.h
include/linux/notifier.h
include/linux/nubus.h
include/linux/of.h
include/linux/page-flags.h
include/linux/pagemap.h
include/linux/pci-acpi.h
include/linux/pci.h
include/linux/pci_ids.h
include/linux/pda_power.h
include/linux/percpu.h
include/linux/pfkeyv2.h
include/linux/phy.h
include/linux/pkt_cls.h
include/linux/pkt_sched.h
include/linux/pm.h
include/linux/pm_qos_params.h [new file with mode: 0644]
include/linux/pnp.h
include/linux/power_supply.h
include/linux/prctl.h
include/linux/proc_fs.h
include/linux/radix-tree.h
include/linux/reboot.h
include/linux/reiserfs_fs_sb.h
include/linux/rfkill.h
include/linux/rtnetlink.h
include/linux/sched.h
include/linux/security.h
include/linux/serial_8250.h
include/linux/signalfd.h
include/linux/skbuff.h
include/linux/slub_def.h
include/linux/sm501-regs.h
include/linux/snmp.h
include/linux/spi/mcp23s08.h [new file with mode: 0644]
include/linux/spinlock_api_up.h
include/linux/sunrpc/cache.h
include/linux/sunrpc/clnt.h
include/linux/sunrpc/debug.h
include/linux/sunrpc/sched.h
include/linux/sunrpc/svc.h
include/linux/sunrpc/svc_rdma.h [new file with mode: 0644]
include/linux/sunrpc/svc_xprt.h [new file with mode: 0644]
include/linux/sunrpc/svcsock.h
include/linux/sunrpc/xdr.h
include/linux/suspend.h
include/linux/suspend_ioctls.h [new file with mode: 0644]
include/linux/swap.h
include/linux/swapops.h
include/linux/syscalls.h
include/linux/sysctl.h
include/linux/tc_ematch/tc_em_meta.h
include/linux/thread_info.h
include/linux/tick.h
include/linux/time.h
include/linux/types.h
include/linux/usb.h
include/linux/usb/Kbuild
include/linux/usb/audio.h
include/linux/usb/cdc.h
include/linux/usb/g_printer.h [new file with mode: 0644]
include/linux/usb/gadget.h
include/linux/usb/gadgetfs.h
include/linux/usb/iowarrior.h
include/linux/usb/isp116x.h
include/linux/usb/midi.h
include/linux/usb/net2280.h
include/linux/usb/otg.h
include/linux/usb/rndis_host.h [new file with mode: 0644]
include/linux/usb/serial.h
include/linux/usb/sl811.h
include/linux/usb/usbnet.h [moved from drivers/net/usb/usbnet.h with 93% similarity]
include/linux/usb_usual.h
include/linux/usbdevice_fs.h
include/linux/virtio.h
include/linux/virtio_balloon.h [new file with mode: 0644]
include/linux/virtio_blk.h
include/linux/virtio_config.h
include/linux/virtio_net.h
include/linux/virtio_pci.h [new file with mode: 0644]
include/linux/virtio_ring.h
include/linux/vmalloc.h
include/linux/wait.h
include/linux/wireless.h
include/linux/writeback.h
include/linux/xattr.h
include/linux/xfrm.h
include/media/rds.h
include/net/arp.h
include/net/esp.h
include/net/if_inet6.h
include/net/inet6_hashtables.h
include/net/inet_connection_sock.h
include/net/inet_hashtables.h
include/net/inet_timewait_sock.h
include/net/ip_fib.h
include/net/ipv6.h
include/net/net_namespace.h
include/net/netfilter/nf_conntrack.h
include/net/netfilter/nf_conntrack_core.h
include/net/netfilter/nf_conntrack_expect.h
include/net/netfilter/nf_conntrack_helper.h
include/net/netfilter/nf_conntrack_l3proto.h
include/net/netfilter/nf_conntrack_l4proto.h
include/net/netfilter/nf_conntrack_tuple.h
include/net/netfilter/nf_log.h
include/net/netlabel.h
include/net/netns/ipv4.h
include/net/netns/ipv6.h
include/net/netns/x_tables.h [new file with mode: 0644]
include/net/pkt_cls.h
include/net/raw.h
include/net/route.h
include/net/sock.h
include/net/xfrm.h
include/pcmcia/cs.h
include/pcmcia/cs_types.h
include/pcmcia/ss.h
include/scsi/scsi_transport_fc.h
include/sound/ad1848.h
include/sound/ainstr_fm.h [deleted file]
include/sound/ainstr_gf1.h [deleted file]
include/sound/ainstr_iw.h [deleted file]
include/sound/ainstr_simple.h [deleted file]
include/sound/ak4xxx-adda.h
include/sound/asequencer.h
include/sound/asound.h
include/sound/asound_fm.h
include/sound/core.h
include/sound/cs4231-regs.h
include/sound/cs46xx.h
include/sound/driver.h
include/sound/emu10k1.h
include/sound/gus.h
include/sound/info.h
include/sound/opl3.h
include/sound/pcm.h
include/sound/seq_instr.h [deleted file]
include/sound/soc-dapm.h
include/sound/soc.h
include/sound/tea575x-tuner.h
include/sound/trident.h
include/sound/version.h
init/Kconfig
kernel/Kconfig.instrumentation [deleted file]
kernel/Makefile
kernel/audit.c
kernel/auditfilter.c
kernel/auditsc.c
kernel/capability.c
kernel/exit.c
kernel/fork.c
kernel/futex.c
kernel/futex_compat.c
kernel/hrtimer.c
kernel/latency.c [deleted file]
kernel/mutex.c
kernel/pm_qos_params.c [new file with mode: 0644]
kernel/posix-timers.c
kernel/power/Kconfig
kernel/power/disk.c
kernel/power/main.c
kernel/power/power.h
kernel/power/process.c
kernel/power/snapshot.c
kernel/power/swap.c
kernel/power/swsusp.c
kernel/power/user.c
kernel/printk.c
kernel/ptrace.c
kernel/relay.c
kernel/sched.c
kernel/sched_fair.c
kernel/signal.c
kernel/softlockup.c
kernel/sys.c
kernel/sys_ni.c
kernel/sysctl.c
kernel/sysctl_check.c
kernel/time.c
kernel/time/tick-sched.c
kernel/time/timekeeping.c
kernel/time/timer_list.c
kernel/timer.c
kernel/wait.c
lib/Kconfig.debug
lib/Makefile
lib/crc32.c
lib/iommu-helper.c [new file with mode: 0644]
lib/kobject.c
lib/radix-tree.c
lib/swiotlb.c
lib/zlib_deflate/defutil.h
mm/Makefile
mm/dmapool.c [new file with mode: 0644]
mm/fadvise.c
mm/filemap.c
mm/filemap_xip.c
mm/fremap.c
mm/highmem.c
mm/hugetlb.c
mm/internal.h
mm/memory.c
mm/memory_hotplug.c
mm/migrate.c
mm/mmap.c
mm/nommu.c
mm/oom_kill.c
mm/page-writeback.c
mm/page_alloc.c
mm/page_io.c
mm/pagewalk.c [new file with mode: 0644]
mm/rmap.c
mm/shmem.c
mm/slob.c
mm/slub.c
mm/sparse.c
mm/swap.c
mm/swap_state.c
mm/swapfile.c
mm/tiny-shmem.c
mm/truncate.c
mm/vmalloc.c
mm/vmstat.c
net/802/tr.c
net/8021q/vlan_dev.c
net/9p/conv.c
net/9p/trans_virtio.c
net/ax25/af_ax25.c
net/bluetooth/hci_sysfs.c
net/bluetooth/hidp/core.c
net/bluetooth/rfcomm/tty.c
net/bridge/br_netfilter.c
net/bridge/netfilter/ebt_802_3.c
net/bridge/netfilter/ebt_among.c
net/bridge/netfilter/ebt_arp.c
net/bridge/netfilter/ebt_arpreply.c
net/bridge/netfilter/ebt_dnat.c
net/bridge/netfilter/ebt_ip.c
net/bridge/netfilter/ebt_limit.c
net/bridge/netfilter/ebt_log.c
net/bridge/netfilter/ebt_mark.c
net/bridge/netfilter/ebt_mark_m.c
net/bridge/netfilter/ebt_pkttype.c
net/bridge/netfilter/ebt_redirect.c
net/bridge/netfilter/ebt_snat.c
net/bridge/netfilter/ebt_stp.c
net/bridge/netfilter/ebt_ulog.c
net/bridge/netfilter/ebt_vlan.c
net/core/dev.c
net/core/dev_mcast.c
net/core/net_namespace.c
net/core/pktgen.c
net/core/rtnetlink.c
net/core/skbuff.c
net/core/sock.c
net/dccp/dccp.h
net/dccp/ipv4.c
net/dccp/ipv6.c
net/dccp/proto.c
net/ipv4/Kconfig
net/ipv4/ah4.c
net/ipv4/arp.c
net/ipv4/cipso_ipv4.c
net/ipv4/devinet.c
net/ipv4/esp4.c
net/ipv4/fib_frontend.c
net/ipv4/fib_hash.c
net/ipv4/fib_semantics.c
net/ipv4/fib_trie.c
net/ipv4/icmp.c
net/ipv4/inet_connection_sock.c
net/ipv4/inet_diag.c
net/ipv4/inet_hashtables.c
net/ipv4/ip_output.c
net/ipv4/ipcomp.c
net/ipv4/netfilter/arp_tables.c
net/ipv4/netfilter/arptable_filter.c
net/ipv4/netfilter/ip_queue.c
net/ipv4/netfilter/ip_tables.c
net/ipv4/netfilter/ipt_CLUSTERIP.c
net/ipv4/netfilter/ipt_recent.c
net/ipv4/netfilter/iptable_filter.c
net/ipv4/netfilter/iptable_mangle.c
net/ipv4/netfilter/iptable_raw.c
net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c
net/ipv4/netfilter/nf_conntrack_proto_icmp.c
net/ipv4/netfilter/nf_nat_core.c
net/ipv4/netfilter/nf_nat_h323.c
net/ipv4/netfilter/nf_nat_helper.c
net/ipv4/netfilter/nf_nat_pptp.c
net/ipv4/netfilter/nf_nat_proto_gre.c
net/ipv4/netfilter/nf_nat_proto_icmp.c
net/ipv4/netfilter/nf_nat_proto_tcp.c
net/ipv4/netfilter/nf_nat_proto_udp.c
net/ipv4/netfilter/nf_nat_rule.c
net/ipv4/netfilter/nf_nat_sip.c
net/ipv4/netfilter/nf_nat_snmp_basic.c
net/ipv4/netfilter/nf_nat_tftp.c
net/ipv4/raw.c
net/ipv4/route.c
net/ipv4/sysctl_net_ipv4.c
net/ipv4/tcp.c
net/ipv4/tcp_input.c
net/ipv4/tcp_ipv4.c
net/ipv4/tcp_output.c
net/ipv4/udp.c
net/ipv4/xfrm4_mode_beet.c
net/ipv4/xfrm4_policy.c
net/ipv4/xfrm4_tunnel.c
net/ipv6/Kconfig
net/ipv6/ah6.c
net/ipv6/esp6.c
net/ipv6/icmp.c
net/ipv6/inet6_hashtables.c
net/ipv6/ip6_output.c
net/ipv6/ipcomp6.c
net/ipv6/mip6.c
net/ipv6/netfilter/ip6_queue.c
net/ipv6/netfilter/ip6_tables.c
net/ipv6/netfilter/ip6table_filter.c
net/ipv6/netfilter/ip6table_mangle.c
net/ipv6/netfilter/ip6table_raw.c
net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
net/ipv6/netfilter/nf_conntrack_reasm.c
net/ipv6/raw.c
net/ipv6/route.c
net/ipv6/tcp_ipv6.c
net/ipv6/udp.c
net/ipv6/xfrm6_policy.c
net/ipv6/xfrm6_tunnel.c
net/key/af_key.c
net/mac80211/Kconfig
net/mac80211/ieee80211.c
net/mac80211/rc80211_pid_algo.c
net/mac80211/rc80211_simple.c
net/mac80211/rx.c
net/netfilter/nf_conntrack_core.c
net/netfilter/nf_conntrack_expect.c
net/netfilter/nf_conntrack_h323_asn1.c
net/netfilter/nf_conntrack_h323_main.c
net/netfilter/nf_conntrack_h323_types.c
net/netfilter/nf_conntrack_helper.c
net/netfilter/nf_conntrack_irc.c
net/netfilter/nf_conntrack_netlink.c
net/netfilter/nf_conntrack_pptp.c
net/netfilter/nf_conntrack_proto_generic.c
net/netfilter/nf_conntrack_proto_gre.c
net/netfilter/nf_conntrack_proto_sctp.c
net/netfilter/nf_conntrack_proto_tcp.c
net/netfilter/nf_conntrack_proto_udp.c
net/netfilter/nf_conntrack_proto_udplite.c
net/netfilter/nf_conntrack_sane.c
net/netfilter/nf_conntrack_sip.c
net/netfilter/nf_conntrack_standalone.c
net/netfilter/nf_conntrack_tftp.c
net/netfilter/nf_log.c
net/netfilter/nfnetlink_log.c
net/netfilter/nfnetlink_queue.c
net/netfilter/x_tables.c
net/netfilter/xt_TCPMSS.c
net/netfilter/xt_connlimit.c
net/netfilter/xt_conntrack.c
net/netfilter/xt_hashlimit.c
net/netfilter/xt_iprange.c
net/netfilter/xt_owner.c
net/netlabel/netlabel_cipso_v4.c
net/netlabel/netlabel_cipso_v4.h
net/netlabel/netlabel_domainhash.h
net/netlabel/netlabel_kapi.c
net/netlink/af_netlink.c
net/rfkill/rfkill-input.c
net/rfkill/rfkill.c
net/rxrpc/ar-call.c
net/rxrpc/ar-internal.h
net/rxrpc/ar-proc.c
net/sched/Kconfig
net/sched/Makefile
net/sched/cls_api.c
net/sched/cls_basic.c
net/sched/cls_flow.c [new file with mode: 0644]
net/sched/cls_fw.c
net/sched/cls_route.c
net/sched/cls_tcindex.c
net/sched/cls_u32.c
net/sched/em_meta.c
net/sched/sch_ingress.c
net/sched/sch_sfq.c
net/sched/sch_teql.c
net/sctp/auth.c
net/sctp/sm_make_chunk.c
net/sctp/sm_statefuns.c
net/sunrpc/Makefile
net/sunrpc/auth.c
net/sunrpc/auth_gss/svcauth_gss.c
net/sunrpc/cache.c
net/sunrpc/clnt.c
net/sunrpc/rpcb_clnt.c
net/sunrpc/sched.c
net/sunrpc/stats.c
net/sunrpc/sunrpc_syms.c
net/sunrpc/svc.c
net/sunrpc/svc_xprt.c [new file with mode: 0644]
net/sunrpc/svcauth.c
net/sunrpc/svcauth_unix.c
net/sunrpc/svcsock.c
net/sunrpc/sysctl.c
net/sunrpc/xdr.c
net/sunrpc/xprtrdma/Makefile
net/sunrpc/xprtrdma/svc_rdma.c [new file with mode: 0644]
net/sunrpc/xprtrdma/svc_rdma_marshal.c [new file with mode: 0644]
net/sunrpc/xprtrdma/svc_rdma_recvfrom.c [new file with mode: 0644]
net/sunrpc/xprtrdma/svc_rdma_sendto.c [new file with mode: 0644]
net/sunrpc/xprtrdma/svc_rdma_transport.c [new file with mode: 0644]
net/x25/af_x25.c
net/xfrm/xfrm_algo.c
net/xfrm/xfrm_input.c
net/xfrm/xfrm_output.c
net/xfrm/xfrm_proc.c
net/xfrm/xfrm_state.c
net/xfrm/xfrm_user.c
scripts/kconfig/mconf.c
scripts/kconfig/menu.c
scripts/mod/file2alias.c
scripts/mod/modpost.c
scripts/setlocalversion [changed mode: 0644->0755]
security/Kconfig
security/Makefile
security/commoncap.c
security/dummy.c
security/security.c
security/selinux/hooks.c
security/selinux/selinuxfs.c
security/selinux/ss/services.c
security/smack/Kconfig [new file with mode: 0644]
security/smack/Makefile [new file with mode: 0644]
security/smack/smack.h [new file with mode: 0644]
security/smack/smack_access.c [new file with mode: 0644]
security/smack/smack_lsm.c [new file with mode: 0644]
security/smack/smackfs.c [new file with mode: 0644]
sound/aoa/aoa.h
sound/aoa/codecs/snd-aoa-codec-onyx.c
sound/aoa/codecs/snd-aoa-codec-tas.c
sound/aoa/fabrics/snd-aoa-fabric-layout.c
sound/aoa/soundbus/i2sbus/i2sbus-core.c
sound/aoa/soundbus/i2sbus/i2sbus-pcm.c
sound/arm/aaci.c
sound/arm/devdma.c
sound/arm/pxa2xx-ac97.c
sound/arm/pxa2xx-pcm.c
sound/arm/sa11xx-uda1341.c
sound/core/control.c
sound/core/control_compat.c
sound/core/device.c
sound/core/hwdep.c
sound/core/info.c
sound/core/info_oss.c
sound/core/init.c
sound/core/isadma.c
sound/core/memalloc.c
sound/core/memory.c
sound/core/misc.c
sound/core/oss/copy.c
sound/core/oss/io.c
sound/core/oss/linear.c
sound/core/oss/mixer_oss.c
sound/core/oss/mulaw.c
sound/core/oss/pcm_oss.c
sound/core/oss/pcm_plugin.c
sound/core/oss/rate.c
sound/core/oss/route.c
sound/core/pcm.c
sound/core/pcm_compat.c
sound/core/pcm_lib.c
sound/core/pcm_memory.c
sound/core/pcm_misc.c
sound/core/pcm_native.c
sound/core/pcm_timer.c
sound/core/rawmidi.c
sound/core/rtctimer.c
sound/core/seq/Makefile
sound/core/seq/instr/Makefile [deleted file]
sound/core/seq/instr/ainstr_fm.c [deleted file]
sound/core/seq/instr/ainstr_gf1.c [deleted file]
sound/core/seq/instr/ainstr_iw.c [deleted file]
sound/core/seq/instr/ainstr_simple.c [deleted file]
sound/core/seq/oss/seq_oss.c
sound/core/seq/oss/seq_oss_device.h
sound/core/seq/seq.c
sound/core/seq/seq_clientmgr.c
sound/core/seq/seq_clientmgr.h
sound/core/seq/seq_device.c
sound/core/seq/seq_dummy.c
sound/core/seq/seq_fifo.c
sound/core/seq/seq_info.c
sound/core/seq/seq_instr.c [deleted file]
sound/core/seq/seq_lock.c
sound/core/seq/seq_memory.c
sound/core/seq/seq_midi.c
sound/core/seq/seq_midi_emul.c
sound/core/seq/seq_midi_event.c
sound/core/seq/seq_ports.c
sound/core/seq/seq_prioq.c
sound/core/seq/seq_queue.c
sound/core/seq/seq_system.c
sound/core/seq/seq_timer.c
sound/core/seq/seq_timer.h
sound/core/seq/seq_virmidi.c
sound/core/sound.c
sound/core/sound_oss.c
sound/core/timer.c
sound/drivers/Kconfig
sound/drivers/Makefile
sound/drivers/dummy.c
sound/drivers/ml403-ac97cr.c [new file with mode: 0644]
sound/drivers/mpu401/mpu401.c
sound/drivers/mpu401/mpu401_uart.c
sound/drivers/mtpav.c
sound/drivers/mts64.c
sound/drivers/opl3/opl3_lib.c
sound/drivers/opl3/opl3_midi.c
sound/drivers/opl3/opl3_oss.c
sound/drivers/opl3/opl3_seq.c
sound/drivers/opl3/opl3_synth.c
sound/drivers/pcm-indirect2.c [new file with mode: 0644]
sound/drivers/pcm-indirect2.h [new file with mode: 0644]
sound/drivers/portman2x4.c
sound/drivers/serial-u16550.c
sound/drivers/virmidi.c
sound/drivers/vx/vx_cmd.c
sound/drivers/vx/vx_core.c
sound/drivers/vx/vx_hwdep.c
sound/drivers/vx/vx_mixer.c
sound/drivers/vx/vx_pcm.c
sound/drivers/vx/vx_uer.c
sound/i2c/cs8427.c
sound/i2c/i2c.c
sound/i2c/l3/uda1341.c
sound/i2c/other/ak4114.c
sound/i2c/other/ak4117.c
sound/i2c/other/ak4xxx-adda.c
sound/i2c/other/pt2258.c
sound/i2c/other/tea575x-tuner.c
sound/i2c/tea6330t.c
sound/isa/ad1816a/ad1816a.c
sound/isa/ad1816a/ad1816a_lib.c
sound/isa/ad1848/ad1848.c
sound/isa/ad1848/ad1848_lib.c
sound/isa/adlib.c
sound/isa/als100.c
sound/isa/azt2320.c
sound/isa/cmi8330.c
sound/isa/cs423x/cs4231.c
sound/isa/cs423x/cs4231_lib.c
sound/isa/cs423x/cs4236.c
sound/isa/cs423x/cs4236_lib.c
sound/isa/dt019x.c
sound/isa/es1688/es1688.c
sound/isa/es1688/es1688_lib.c
sound/isa/es18xx.c
sound/isa/gus/Makefile
sound/isa/gus/gus_dma.c
sound/isa/gus/gus_dram.c
sound/isa/gus/gus_instr.c
sound/isa/gus/gus_io.c
sound/isa/gus/gus_irq.c
sound/isa/gus/gus_main.c
sound/isa/gus/gus_mem.c
sound/isa/gus/gus_mem_proc.c
sound/isa/gus/gus_mixer.c
sound/isa/gus/gus_pcm.c
sound/isa/gus/gus_reset.c
sound/isa/gus/gus_sample.c [deleted file]
sound/isa/gus/gus_simple.c [deleted file]
sound/isa/gus/gus_synth.c [deleted file]
sound/isa/gus/gus_timer.c
sound/isa/gus/gus_uart.c
sound/isa/gus/gus_volume.c
sound/isa/gus/gusclassic.c
sound/isa/gus/gusextreme.c
sound/isa/gus/gusmax.c
sound/isa/gus/interwave.c
sound/isa/opl3sa2.c
sound/isa/opti9xx/miro.c
sound/isa/opti9xx/opti92x-ad1848.c
sound/isa/sb/emu8000.c
sound/isa/sb/emu8000_local.h
sound/isa/sb/es968.c
sound/isa/sb/sb16.c
sound/isa/sb/sb16_csp.c
sound/isa/sb/sb16_main.c
sound/isa/sb/sb8.c
sound/isa/sb/sb8_main.c
sound/isa/sb/sb8_midi.c
sound/isa/sb/sb_common.c
sound/isa/sb/sb_mixer.c
sound/isa/sc6000.c
sound/isa/sgalaxy.c
sound/isa/sscape.c
sound/isa/wavefront/wavefront.c
sound/isa/wavefront/wavefront_fx.c
sound/isa/wavefront/wavefront_midi.c
sound/isa/wavefront/wavefront_synth.c
sound/last.c
sound/mips/au1x00.c
sound/oss/via82cxxx_audio.c
sound/parisc/harmony.c
sound/pci/Kconfig
sound/pci/Makefile
sound/pci/ac97/ac97_codec.c
sound/pci/ac97/ac97_patch.c
sound/pci/ac97/ac97_patch.h
sound/pci/ac97/ac97_pcm.c
sound/pci/ac97/ac97_proc.c
sound/pci/ac97/ak4531_codec.c
sound/pci/ad1889.c
sound/pci/ali5451/ali5451.c
sound/pci/als300.c
sound/pci/als4000.c
sound/pci/atiixp.c
sound/pci/atiixp_modem.c
sound/pci/au88x0/au88x0.h
sound/pci/au88x0/au88x0_core.c
sound/pci/au88x0/au88x0_game.c
sound/pci/au88x0/au88x0_mixer.c
sound/pci/au88x0/au88x0_mpu401.c
sound/pci/au88x0/au88x0_pcm.c
sound/pci/azt3328.c
sound/pci/bt87x.c
sound/pci/ca0106/ca0106.h
sound/pci/ca0106/ca0106_main.c
sound/pci/ca0106/ca0106_mixer.c
sound/pci/ca0106/ca0106_proc.c
sound/pci/ca0106/ca_midi.c
sound/pci/cmipci.c
sound/pci/cs4281.c
sound/pci/cs46xx/cs46xx.c
sound/pci/cs46xx/cs46xx_lib.c
sound/pci/cs46xx/dsp_spos.c
sound/pci/cs46xx/dsp_spos_scb_lib.c
sound/pci/cs5530.c
sound/pci/cs5535audio/cs5535audio.c
sound/pci/cs5535audio/cs5535audio_pcm.c
sound/pci/cs5535audio/cs5535audio_pm.c
sound/pci/echoaudio/darla20.c
sound/pci/echoaudio/darla24.c
sound/pci/echoaudio/echo3g.c
sound/pci/echoaudio/echoaudio.c
sound/pci/echoaudio/echoaudio.h
sound/pci/echoaudio/gina20.c
sound/pci/echoaudio/gina24.c
sound/pci/echoaudio/indigo.c
sound/pci/echoaudio/indigodj.c
sound/pci/echoaudio/indigoio.c
sound/pci/echoaudio/layla20.c
sound/pci/echoaudio/layla24.c
sound/pci/echoaudio/mia.c
sound/pci/echoaudio/mona.c
sound/pci/emu10k1/emu10k1.c
sound/pci/emu10k1/emu10k1_callback.c
sound/pci/emu10k1/emu10k1_main.c
sound/pci/emu10k1/emu10k1_synth.c
sound/pci/emu10k1/emu10k1_synth_local.h
sound/pci/emu10k1/emu10k1x.c
sound/pci/emu10k1/emufx.c
sound/pci/emu10k1/emumixer.c
sound/pci/emu10k1/emumpu401.c
sound/pci/emu10k1/emupcm.c
sound/pci/emu10k1/emuproc.c
sound/pci/emu10k1/io.c
sound/pci/emu10k1/irq.c
sound/pci/emu10k1/memory.c
sound/pci/emu10k1/p16v.c
sound/pci/emu10k1/timer.c
sound/pci/emu10k1/voice.c
sound/pci/ens1370.c
sound/pci/es1938.c
sound/pci/es1968.c
sound/pci/fm801.c
sound/pci/hda/Makefile
sound/pci/hda/hda_codec.c
sound/pci/hda/hda_codec.h
sound/pci/hda/hda_generic.c
sound/pci/hda/hda_hwdep.c
sound/pci/hda/hda_intel.c
sound/pci/hda/hda_local.h
sound/pci/hda/hda_proc.c
sound/pci/hda/patch_analog.c
sound/pci/hda/patch_atihdmi.c
sound/pci/hda/patch_cmedia.c
sound/pci/hda/patch_conexant.c
sound/pci/hda/patch_realtek.c
sound/pci/hda/patch_si3054.c
sound/pci/hda/patch_sigmatel.c
sound/pci/hda/patch_via.c
sound/pci/hda/vmaster.c [new file with mode: 0644]
sound/pci/ice1712/Makefile
sound/pci/ice1712/ak4xxx.c
sound/pci/ice1712/amp.c
sound/pci/ice1712/aureon.c
sound/pci/ice1712/delta.c
sound/pci/ice1712/ews.c
sound/pci/ice1712/hoontech.c
sound/pci/ice1712/ice1712.c
sound/pci/ice1712/ice1712.h
sound/pci/ice1712/ice1724.c
sound/pci/ice1712/juli.c
sound/pci/ice1712/phase.c
sound/pci/ice1712/pontis.c
sound/pci/ice1712/prodigy192.c
sound/pci/ice1712/prodigy_hifi.c [new file with mode: 0644]
sound/pci/ice1712/prodigy_hifi.h [new file with mode: 0644]
sound/pci/ice1712/revo.c
sound/pci/ice1712/se.c [new file with mode: 0644]
sound/pci/ice1712/se.h [new file with mode: 0644]
sound/pci/ice1712/vt1720_mobo.c
sound/pci/ice1712/wtm.c
sound/pci/intel8x0.c
sound/pci/intel8x0m.c
sound/pci/korg1212/korg1212.c
sound/pci/maestro3.c
sound/pci/mixart/mixart.c
sound/pci/mixart/mixart_core.c
sound/pci/mixart/mixart_hwdep.c
sound/pci/mixart/mixart_mixer.c
sound/pci/nm256/nm256.c
sound/pci/oxygen/Makefile [new file with mode: 0644]
sound/pci/oxygen/ak4396.h [new file with mode: 0644]
sound/pci/oxygen/cm9780.h [new file with mode: 0644]
sound/pci/oxygen/hifier.c [new file with mode: 0644]
sound/pci/oxygen/oxygen.c [new file with mode: 0644]
sound/pci/oxygen/oxygen.h [new file with mode: 0644]
sound/pci/oxygen/oxygen_io.c [new file with mode: 0644]
sound/pci/oxygen/oxygen_lib.c [new file with mode: 0644]
sound/pci/oxygen/oxygen_mixer.c [new file with mode: 0644]
sound/pci/oxygen/oxygen_pcm.c [new file with mode: 0644]
sound/pci/oxygen/oxygen_regs.h [new file with mode: 0644]
sound/pci/oxygen/virtuoso.c [new file with mode: 0644]
sound/pci/pcxhr/pcxhr.c
sound/pci/pcxhr/pcxhr_core.c
sound/pci/pcxhr/pcxhr_hwdep.c
sound/pci/pcxhr/pcxhr_mixer.c
sound/pci/riptide/riptide.c
sound/pci/rme32.c
sound/pci/rme96.c
sound/pci/rme9652/hdsp.c
sound/pci/rme9652/hdspm.c
sound/pci/rme9652/rme9652.c
sound/pci/sis7019.c [new file with mode: 0644]
sound/pci/sis7019.h [new file with mode: 0644]
sound/pci/sonicvibes.c
sound/pci/trident/Makefile
sound/pci/trident/trident.c
sound/pci/trident/trident_main.c
sound/pci/trident/trident_memory.c
sound/pci/trident/trident_synth.c [deleted file]
sound/pci/via82xx.c
sound/pci/via82xx_modem.c
sound/pci/vx222/vx222.c
sound/pci/vx222/vx222_ops.c
sound/pci/ymfpci/ymfpci.c
sound/pci/ymfpci/ymfpci_main.c
sound/pcmcia/pdaudiocf/pdaudiocf.c
sound/pcmcia/pdaudiocf/pdaudiocf_core.c
sound/pcmcia/pdaudiocf/pdaudiocf_irq.c
sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c
sound/pcmcia/vx/vxp_mixer.c
sound/pcmcia/vx/vxp_ops.c
sound/pcmcia/vx/vxpocket.c
sound/ppc/awacs.c
sound/ppc/beep.c
sound/ppc/burgundy.c
sound/ppc/daca.c
sound/ppc/keywest.c
sound/ppc/pmac.c
sound/ppc/powermac.c
sound/ppc/snd_ps3.c
sound/ppc/tumbler.c
sound/sh/aica.c
sound/soc/Kconfig
sound/soc/Makefile
sound/soc/at91/at91-pcm.c
sound/soc/at91/at91-ssc.c
sound/soc/at91/eti_b1_wm8731.c
sound/soc/codecs/Kconfig
sound/soc/codecs/Makefile
sound/soc/codecs/ac97.c
sound/soc/codecs/cs4270.c
sound/soc/codecs/tlv320aic3x.c [new file with mode: 0644]
sound/soc/codecs/tlv320aic3x.h [new file with mode: 0644]
sound/soc/codecs/wm8731.c
sound/soc/codecs/wm8750.c
sound/soc/codecs/wm8753.c
sound/soc/codecs/wm9712.c
sound/soc/fsl/Kconfig [new file with mode: 0644]
sound/soc/fsl/Makefile [new file with mode: 0644]
sound/soc/fsl/fsl_dma.c [new file with mode: 0644]
sound/soc/fsl/fsl_dma.h [new file with mode: 0644]
sound/soc/fsl/fsl_ssi.c [new file with mode: 0644]
sound/soc/fsl/fsl_ssi.h [new file with mode: 0644]
sound/soc/fsl/mpc8610_hpcd.c [new file with mode: 0644]
sound/soc/pxa/Kconfig
sound/soc/pxa/Makefile
sound/soc/pxa/corgi.c
sound/soc/pxa/e800_wm9712.c [new file with mode: 0644]
sound/soc/pxa/poodle.c
sound/soc/pxa/pxa2xx-ac97.c
sound/soc/pxa/pxa2xx-i2s.c
sound/soc/pxa/pxa2xx-pcm.c
sound/soc/pxa/spitz.c
sound/soc/pxa/tosa.c
sound/soc/s3c24xx/Kconfig
sound/soc/s3c24xx/Makefile
sound/soc/s3c24xx/ln2440sbc_alc650.c [new file with mode: 0644]
sound/soc/s3c24xx/neo1973_wm8753.c
sound/soc/s3c24xx/s3c2412-i2s.c [new file with mode: 0644]
sound/soc/s3c24xx/s3c2412-i2s.h [new file with mode: 0644]
sound/soc/s3c24xx/s3c2443-ac97.c
sound/soc/s3c24xx/s3c24xx-ac97.h
sound/soc/s3c24xx/s3c24xx-i2s.c
sound/soc/s3c24xx/s3c24xx-pcm.c
sound/soc/s3c24xx/smdk2443_wm9710.c
sound/soc/sh/dma-sh7760.c
sound/soc/sh/hac.c
sound/soc/sh/sh7760-ac97.c
sound/soc/sh/ssi.c
sound/soc/soc-core.c
sound/soc/soc-dapm.c
sound/sparc/amd7930.c
sound/sparc/cs4231.c
sound/sparc/dbri.c
sound/spi/at73c213.c
sound/synth/emux/emux.c
sound/synth/emux/emux_hwdep.c
sound/synth/emux/emux_oss.c
sound/synth/emux/emux_proc.c
sound/synth/emux/emux_voice.h
sound/synth/emux/soundfont.c
sound/synth/util_mem.c
sound/usb/Kconfig
sound/usb/caiaq/Makefile
sound/usb/caiaq/caiaq-audio.c
sound/usb/caiaq/caiaq-control.c [new file with mode: 0644]
sound/usb/caiaq/caiaq-control.h [new file with mode: 0644]
sound/usb/caiaq/caiaq-device.c
sound/usb/caiaq/caiaq-device.h
sound/usb/caiaq/caiaq-input.c
sound/usb/caiaq/caiaq-midi.c
sound/usb/usbaudio.c
sound/usb/usbaudio.h
sound/usb/usbmidi.c
sound/usb/usbmixer.c
sound/usb/usbmixer_maps.c
sound/usb/usbquirks.h
sound/usb/usx2y/usX2Yhwdep.c
sound/usb/usx2y/usbusx2y.c
sound/usb/usx2y/usbusx2yaudio.c
sound/usb/usx2y/usx2yhwdeppcm.c

diff --git a/CREDITS b/CREDITS
index edff310dbe531a6f9c2da88578c605f099e79bfc..da0a56e23beeca7512d80c762425c4fedfaf45b8 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -508,12 +508,8 @@ D: REINER SCT cyberJack pinpad/e-com USB chipcard reader driver
 S: Germany
 
 N: Adrian Bunk
-E: bunk@stusta.de
 P: 1024D/4F12B400  B29C E71E FE19 6755 5C8A  84D4 99FC EA98 4F12 B400
 D: misc kernel hacking and testing
-S: Grasmeierstrasse 11
-S: 80805 Muenchen
-S: Germany
 
 N: Ray Burr
 E: ryb@nightmare.com
@@ -1124,6 +1120,9 @@ S: 1150 Ringwood Court
 S: San Jose, California 95131
 S: USA
 
+N: Adam Fritzler
+E: mid@zigamorph.net
+
 N: Fernando Fuganti
 E: fuganti@conectiva.com.br
 E: fuganti@netbank.com.br
index c3014df066c4e3ee61b12397cb6e964131630427..40ac7759c3bb5342edf9168153edbf1f1ff05e79 100644 (file)
@@ -154,7 +154,7 @@ firmware_class/
        - request_firmware() hotplug interface info.
 floppy.txt
        - notes and driver options for the floppy disk driver.
-fujitsu/
+frv/
        - Fujitsu FR-V Linux documentation.
 gpio.txt
        - overview of GPIO (General Purpose Input/Output) access conventions.
@@ -364,8 +364,6 @@ sharedsubtree.txt
        - a description of shared subtrees for namespaces.
 smart-config.txt
        - description of the Smart Config makefile feature.
-smp.txt
-       - a few notes on symmetric multi-processing.
 sony-laptop.txt
        - Sony Notebook Control Driver (SNC) Readme.
 sonypi.txt
index 9734577d171154630f49be83779863ef875d6b7e..11a3c1682cecb87e16514249d6877a18608ccf01 100644 (file)
@@ -52,3 +52,36 @@ Description:
                facility is inherently dangerous, it is disabled by default
                for all devices except hubs.  For more information, see
                Documentation/usb/persist.txt.
+
+What:          /sys/bus/usb/device/.../power/connected_duration
+Date:          January 2008
+KernelVersion: 2.6.25
+Contact:       Sarah Sharp <sarah.a.sharp@intel.com>
+Description:
+               If CONFIG_PM and CONFIG_USB_SUSPEND are enabled, then this file
+               is present.  When read, it returns the total time (in msec)
+               that the USB device has been connected to the machine.  This
+               file is read-only.
+Users:
+               PowerTOP <power@bughost.org>
+               http://www.lesswatts.org/projects/powertop/
+
+What:          /sys/bus/usb/device/.../power/active_duration
+Date:          January 2008
+KernelVersion: 2.6.25
+Contact:       Sarah Sharp <sarah.a.sharp@intel.com>
+Description:
+               If CONFIG_PM and CONFIG_USB_SUSPEND are enabled, then this file
+               is present.  When read, it returns the total time (in msec)
+               that the USB device has been active, i.e. not in a suspended
+               state.  This file is read-only.
+
+               Tools can use this file and the connected_duration file to
+               compute the percentage of time that a device has been active.
+               For example,
+               echo $((100 * `cat active_duration` / `cat connected_duration`))
+               will give an integer percentage.  Note that this does not
+               account for counter wrap.
+Users:
+               PowerTOP <power@bughost.org>
+               http://www.lesswatts.org/projects/powertop/
index 35f5bd243336aeb1927f42483e26fa7586bcb205..6c816751b8686394d8cbdbd1fc639154d7f5b7ac 100644 (file)
@@ -53,7 +53,7 @@ Finding it the old way
 
 [Sat Mar  2 10:32:33 PST 1996 KERNEL_BUG-HOWTO lm@sgi.com (Larry McVoy)]
 
-This is how to track down a bug if you know nothing about kernel hacking.  
+This is how to track down a bug if you know nothing about kernel hacking.
 It's a brute force approach but it works pretty well.
 
 You need:
@@ -66,12 +66,12 @@ You will then do:
 
         . Rebuild a revision that you believe works, install, and verify that.
         . Do a binary search over the kernels to figure out which one
-          introduced the bug.  I.e., suppose 1.3.28 didn't have the bug, but 
+          introduced the bug.  I.e., suppose 1.3.28 didn't have the bug, but
           you know that 1.3.69 does.  Pick a kernel in the middle and build
           that, like 1.3.50.  Build & test; if it works, pick the mid point
           between .50 and .69, else the mid point between .28 and .50.
         . You'll narrow it down to the kernel that introduced the bug.  You
-          can probably do better than this but it gets tricky.  
+          can probably do better than this but it gets tricky.
 
         . Narrow it down to a subdirectory
 
@@ -81,27 +81,27 @@ You will then do:
             directories:
 
                 Copy the non-working directory next to the working directory
-                as "dir.63".  
+                as "dir.63".
                 One directory at time, try moving the working directory to
-                "dir.62" and mv dir.63 dir"time, try 
+                "dir.62" and mv dir.63 dir"time, try
 
                         mv dir dir.62
                         mv dir.63 dir
                         find dir -name '*.[oa]' -print | xargs rm -f
 
                 And then rebuild and retest.  Assuming that all related
-                changes were contained in the sub directory, this should 
-                isolate the change to a directory.  
+                changes were contained in the sub directory, this should
+                isolate the change to a directory.
 
                 Problems: changes in header files may have occurred; I've
-                found in my case that they were self explanatory - you may 
+                found in my case that they were self explanatory - you may
                 or may not want to give up when that happens.
 
         . Narrow it down to a file
 
           - You can apply the same technique to each file in the directory,
-            hoping that the changes in that file are self contained.  
-            
+            hoping that the changes in that file are self contained.
+
         . Narrow it down to a routine
 
           - You can take the old file and the new file and manually create
@@ -130,7 +130,7 @@ You will then do:
             that makes the difference.
 
 Finally, you take all the info that you have, kernel revisions, bug
-description, the extent to which you have narrowed it down, and pass 
+description, the extent to which you have narrowed it down, and pass
 that off to whomever you believe is the maintainer of that section.
 A post to linux.dev.kernel isn't such a bad idea if you've done some
 work to narrow it down.
index 1becf27ba27ea60e9b1dc75dac3be7caccdc5e66..a8b88c47e80951e0a93b61d831bd9a198fe5f07f 100644 (file)
 !Idrivers/rapidio/rio-sysfs.c
      </sect1>
      <sect1><title>PPC32 support</title>
-!Iarch/ppc/kernel/rio.c
-!Earch/ppc/syslib/ppc85xx_rio.c
-!Iarch/ppc/syslib/ppc85xx_rio.c
+!Iarch/powerpc/kernel/rio.c
+!Earch/powerpc/sysdev/fsl_rio.c
+!Iarch/powerpc/sysdev/fsl_rio.c
      </sect1>
   </chapter>
 
index 3d2f31b99dd9f081b2a3032d5551c153eb60ab0f..4acc73240a6d536ef044bf1dfc5a2abd6ae4296f 100644 (file)
@@ -59,7 +59,7 @@
    <title>Introduction</title>
   <para>
     This document describes the interfaces available for device drivers that
-    drive s390 based channel attached devices. This includes interfaces for
+    drive s390 based channel attached I/O devices. This includes interfaces for
     interaction with the hardware and interfaces for interacting with the
     common driver core. Those interfaces are provided by the s390 common I/O
     layer.
        The ccw bus typically contains the majority of devices available to
        a s390 system. Named after the channel command word (ccw), the basic
        command structure used to address its devices, the ccw bus contains
-       so-called channel attached devices. They are addressed via subchannels,
-       visible on the css bus. A device driver, however, will never interact
-       with the subchannel directly, but only via the device on the ccw bus,
+       so-called channel attached devices. They are addressed via I/O
+       subchannels, visible on the css bus. A device driver for
+       channel-attached devices, however, will never interact  with the
+       subchannel directly, but only via the I/O device on the ccw bus,
        the ccw device.
   </para>
     <sect1 id="channelIO">
 !Iinclude/asm-s390/ccwdev.h
 !Edrivers/s390/cio/device.c
 !Edrivers/s390/cio/device_ops.c
-!Edrivers/s390/cio/airq.c
     </sect1>
     <sect1 id="cmf">
      <title>The channel-measurement facility</title>
    </sect1>
   </chapter>
 
+  <chapter id="genericinterfaces">
+   <title>Generic interfaces</title>
+  <para>
+       Some interfaces are available to other drivers that do not necessarily
+       have anything to do with the busses described above, but still are
+       indirectly using basic infrastructure in the common I/O layer.
+       One example is the support for adapter interrupts.
+  </para>
+!Edrivers/s390/cio/airq.c
+  </chapter>
+
 </book>
diff --git a/Documentation/Smack.txt b/Documentation/Smack.txt
new file mode 100644 (file)
index 0000000..989c2fc
--- /dev/null
@@ -0,0 +1,493 @@
+
+
+    "Good for you, you've decided to clean the elevator!"
+    - The Elevator, from Dark Star
+
+Smack is the the Simplified Mandatory Access Control Kernel.
+Smack is a kernel based implementation of mandatory access
+control that includes simplicity in its primary design goals.
+
+Smack is not the only Mandatory Access Control scheme
+available for Linux. Those new to Mandatory Access Control
+are encouraged to compare Smack with the other mechanisms
+available to determine which is best suited to the problem
+at hand.
+
+Smack consists of three major components:
+    - The kernel
+    - A start-up script and a few modified applications
+    - Configuration data
+
+The kernel component of Smack is implemented as a Linux
+Security Modules (LSM) module. It requires netlabel and
+works best with file systems that support extended attributes,
+although xattr support is not strictly required.
+It is safe to run a Smack kernel under a "vanilla" distribution.
+Smack kernels use the CIPSO IP option. Some network
+configurations are intolerant of IP options and can impede
+access to systems that use them as Smack does.
+
+The startup script etc-init.d-smack should be installed
+in /etc/init.d/smack and should be invoked early in the
+start-up process. On Fedora rc5.d/S02smack is recommended.
+This script ensures that certain devices have the correct
+Smack attributes and loads the Smack configuration if
+any is defined. This script invokes two programs that
+ensure configuration data is properly formatted. These
+programs are /usr/sbin/smackload and /usr/sin/smackcipso.
+The system will run just fine without these programs,
+but it will be difficult to set access rules properly.
+
+A version of "ls" that provides a "-M" option to display
+Smack labels on long listing is available.
+
+A hacked version of sshd that allows network logins by users
+with specific Smack labels is available. This version does
+not work for scp. You must set the /etc/ssh/sshd_config
+line:
+   UsePrivilegeSeparation no
+
+The format of /etc/smack/usr is:
+
+   username smack
+
+In keeping with the intent of Smack, configuration data is
+minimal and not strictly required. The most important
+configuration step is mounting the smackfs pseudo filesystem.
+
+Add this line to /etc/fstab:
+
+    smackfs /smack smackfs smackfsdef=* 0 0
+
+and create the /smack directory for mounting.
+
+Smack uses extended attributes (xattrs) to store file labels.
+The command to set a Smack label on a file is:
+
+    # attr -S -s SMACK64 -V "value" path
+
+NOTE: Smack labels are limited to 23 characters. The attr command
+      does not enforce this restriction and can be used to set
+      invalid Smack labels on files.
+
+If you don't do anything special all users will get the floor ("_")
+label when they log in. If you do want to log in via the hacked ssh
+at other labels use the attr command to set the smack value on the
+home directory and it's contents.
+
+You can add access rules in /etc/smack/accesses. They take the form:
+
+    subjectlabel objectlabel access
+
+access is a combination of the letters rwxa which specify the
+kind of access permitted a subject with subjectlabel on an
+object with objectlabel. If there is no rule no access is allowed.
+
+A process can see the smack label it is running with by
+reading /proc/self/attr/current. A privileged process can
+set the process smack by writing there.
+
+Look for additional programs on http://schaufler-ca.com
+
+From the Smack Whitepaper:
+
+The Simplified Mandatory Access Control Kernel
+
+Casey Schaufler
+casey@schaufler-ca.com
+
+Mandatory Access Control
+
+Computer systems employ a variety of schemes to constrain how information is
+shared among the people and services using the machine. Some of these schemes
+allow the program or user to decide what other programs or users are allowed
+access to pieces of data. These schemes are called discretionary access
+control mechanisms because the access control is specified at the discretion
+of the user. Other schemes do not leave the decision regarding what a user or
+program can access up to users or programs. These schemes are called mandatory
+access control mechanisms because you don't have a choice regarding the users
+or programs that have access to pieces of data.
+
+Bell & LaPadula
+
+From the middle of the 1980's until the turn of the century Mandatory Access
+Control (MAC) was very closely associated with the Bell & LaPadula security
+model, a mathematical description of the United States Department of Defense
+policy for marking paper documents. MAC in this form enjoyed a following
+within the Capital Beltway and Scandinavian supercomputer centers but was
+often sited as failing to address general needs.
+
+Domain Type Enforcement
+
+Around the turn of the century Domain Type Enforcement (DTE) became popular.
+This scheme organizes users, programs, and data into domains that are
+protected from each other. This scheme has been widely deployed as a component
+of popular Linux distributions. The administrative overhead required to
+maintain this scheme and the detailed understanding of the whole system
+necessary to provide a secure domain mapping leads to the scheme being
+disabled or used in limited ways in the majority of cases.
+
+Smack
+
+Smack is a Mandatory Access Control mechanism designed to provide useful MAC
+while avoiding the pitfalls of its predecessors. The limitations of Bell &
+LaPadula are addressed by providing a scheme whereby access can be controlled
+according to the requirements of the system and its purpose rather than those
+imposed by an arcane government policy. The complexity of Domain Type
+Enforcement and avoided by defining access controls in terms of the access
+modes already in use.
+
+Smack Terminology
+
+The jargon used to talk about Smack will be familiar to those who have dealt
+with other MAC systems and shouldn't be too difficult for the uninitiated to
+pick up. There are four terms that are used in a specific way and that are
+especially important:
+
+       Subject: A subject is an active entity on the computer system.
+       On Smack a subject is a task, which is in turn the basic unit
+       of execution.
+
+       Object: An object is a passive entity on the computer system.
+       On Smack files of all types, IPC, and tasks can be objects.
+
+       Access: Any attempt by a subject to put information into or get
+       information from an object is an access.
+
+       Label: Data that identifies the Mandatory Access Control
+       characteristics of a subject or an object.
+
+These definitions are consistent with the traditional use in the security
+community. There are also some terms from Linux that are likely to crop up:
+
+       Capability: A task that possesses a capability has permission to
+       violate an aspect of the system security policy, as identified by
+       the specific capability. A task that possesses one or more
+       capabilities is a privileged task, whereas a task with no
+       capabilities is an unprivileged task.
+
+       Privilege: A task that is allowed to violate the system security
+       policy is said to have privilege. As of this writing a task can
+       have privilege either by possessing capabilities or by having an
+       effective user of root.
+
+Smack Basics
+
+Smack is an extension to a Linux system. It enforces additional restrictions
+on what subjects can access which objects, based on the labels attached to
+each of the subject and the object.
+
+Labels
+
+Smack labels are ASCII character strings, one to twenty-three characters in
+length. Single character labels using special characters, that being anything
+other than a letter or digit, are reserved for use by the Smack development
+team. Smack labels are unstructured, case sensitive, and the only operation
+ever performed on them is comparison for equality. Smack labels cannot
+contain unprintable characters or the "/" (slash) character.
+
+There are some predefined labels:
+
+       _ Pronounced "floor", a single underscore character.
+       ^ Pronounced "hat", a single circumflex character.
+       * Pronounced "star", a single asterisk character.
+       ? Pronounced "huh", a single question mark character.
+
+Every task on a Smack system is assigned a label. System tasks, such as
+init(8) and systems daemons, are run with the floor ("_") label. User tasks
+are assigned labels according to the specification found in the
+/etc/smack/user configuration file.
+
+Access Rules
+
+Smack uses the traditional access modes of Linux. These modes are read,
+execute, write, and occasionally append. There are a few cases where the
+access mode may not be obvious. These include:
+
+       Signals: A signal is a write operation from the subject task to
+       the object task.
+       Internet Domain IPC: Transmission of a packet is considered a
+       write operation from the source task to the destination task.
+
+Smack restricts access based on the label attached to a subject and the label
+attached to the object it is trying to access. The rules enforced are, in
+order:
+
+       1. Any access requested by a task labeled "*" is denied.
+       2. A read or execute access requested by a task labeled "^"
+          is permitted.
+       3. A read or execute access requested on an object labeled "_"
+          is permitted.
+       4. Any access requested on an object labeled "*" is permitted.
+       5. Any access requested by a task on an object with the same
+          label is permitted.
+       6. Any access requested that is explicitly defined in the loaded
+          rule set is permitted.
+       7. Any other access is denied.
+
+Smack Access Rules
+
+With the isolation provided by Smack access separation is simple. There are
+many interesting cases where limited access by subjects to objects with
+different labels is desired. One example is the familiar spy model of
+sensitivity, where a scientist working on a highly classified project would be
+able to read documents of lower classifications and anything she writes will
+be "born" highly classified. To accommodate such schemes Smack includes a
+mechanism for specifying rules allowing access between labels.
+
+Access Rule Format
+
+The format of an access rule is:
+
+       subject-label object-label access
+
+Where subject-label is the Smack label of the task, object-label is the Smack
+label of the thing being accessed, and access is a string specifying the sort
+of access allowed. The Smack labels are limited to 23 characters. The access
+specification is searched for letters that describe access modes:
+
+       a: indicates that append access should be granted.
+       r: indicates that read access should be granted.
+       w: indicates that write access should be granted.
+       x: indicates that execute access should be granted.
+
+Uppercase values for the specification letters are allowed as well.
+Access mode specifications can be in any order. Examples of acceptable rules
+are:
+
+       TopSecret Secret  rx
+       Secret    Unclass R
+       Manager   Game    x
+       User      HR      w
+       New       Old     rRrRr
+       Closed    Off     -
+
+Examples of unacceptable rules are:
+
+       Top Secret Secret     rx
+       Ace        Ace        r
+       Odd        spells     waxbeans
+
+Spaces are not allowed in labels. Since a subject always has access to files
+with the same label specifying a rule for that case is pointless. Only
+valid letters (rwxaRWXA) and the dash ('-') character are allowed in
+access specifications. The dash is a placeholder, so "a-r" is the same
+as "ar". A lone dash is used to specify that no access should be allowed.
+
+Applying Access Rules
+
+The developers of Linux rarely define new sorts of things, usually importing
+schemes and concepts from other systems. Most often, the other systems are
+variants of Unix. Unix has many endearing properties, but consistency of
+access control models is not one of them. Smack strives to treat accesses as
+uniformly as is sensible while keeping with the spirit of the underlying
+mechanism.
+
+File system objects including files, directories, named pipes, symbolic links,
+and devices require access permissions that closely match those used by mode
+bit access. To open a file for reading read access is required on the file. To
+search a directory requires execute access. Creating a file with write access
+requires both read and write access on the containing directory. Deleting a
+file requires read and write access to the file and to the containing
+directory. It is possible that a user may be able to see that a file exists
+but not any of its attributes by the circumstance of having read access to the
+containing directory but not to the differently labeled file. This is an
+artifact of the file name being data in the directory, not a part of the file.
+
+IPC objects, message queues, semaphore sets, and memory segments exist in flat
+namespaces and access requests are only required to match the object in
+question.
+
+Process objects reflect tasks on the system and the Smack label used to access
+them is the same Smack label that the task would use for its own access
+attempts. Sending a signal via the kill() system call is a write operation
+from the signaler to the recipient. Debugging a process requires both reading
+and writing. Creating a new task is an internal operation that results in two
+tasks with identical Smack labels and requires no access checks.
+
+Sockets are data structures attached to processes and sending a packet from
+one process to another requires that the sender have write access to the
+receiver. The receiver is not required to have read access to the sender.
+
+Setting Access Rules
+
+The configuration file /etc/smack/accesses contains the rules to be set at
+system startup. The contents are written to the special file /smack/load.
+Rules can be written to /smack/load at any time and take effect immediately.
+For any pair of subject and object labels there can be only one rule, with the
+most recently specified overriding any earlier specification.
+
+The program smackload is provided to ensure data is formatted
+properly when written to /smack/load. This program reads lines
+of the form
+
+    subjectlabel objectlabel mode.
+
+Task Attribute
+
+The Smack label of a process can be read from /proc/<pid>/attr/current. A
+process can read its own Smack label from /proc/self/attr/current. A
+privileged process can change its own Smack label by writing to
+/proc/self/attr/current but not the label of another process.
+
+File Attribute
+
+The Smack label of a filesystem object is stored as an extended attribute
+named SMACK64 on the file. This attribute is in the security namespace. It can
+only be changed by a process with privilege.
+
+Privilege
+
+A process with CAP_MAC_OVERRIDE is privileged.
+
+Smack Networking
+
+As mentioned before, Smack enforces access control on network protocol
+transmissions. Every packet sent by a Smack process is tagged with its Smack
+label. This is done by adding a CIPSO tag to the header of the IP packet. Each
+packet received is expected to have a CIPSO tag that identifies the label and
+if it lacks such a tag the network ambient label is assumed. Before the packet
+is delivered a check is made to determine that a subject with the label on the
+packet has write access to the receiving process and if that is not the case
+the packet is dropped.
+
+CIPSO Configuration
+
+It is normally unnecessary to specify the CIPSO configuration. The default
+values used by the system handle all internal cases. Smack will compose CIPSO
+label values to match the Smack labels being used without administrative
+intervention. Unlabeled packets that come into the system will be given the
+ambient label.
+
+Smack requires configuration in the case where packets from a system that is
+not smack that speaks CIPSO may be encountered. Usually this will be a Trusted
+Solaris system, but there are other, less widely deployed systems out there.
+CIPSO provides 3 important values, a Domain Of Interpretation (DOI), a level,
+and a category set with each packet. The DOI is intended to identify a group
+of systems that use compatible labeling schemes, and the DOI specified on the
+smack system must match that of the remote system or packets will be
+discarded. The DOI is 3 by default. The value can be read from /smack/doi and
+can be changed by writing to /smack/doi.
+
+The label and category set are mapped to a Smack label as defined in
+/etc/smack/cipso.
+
+A Smack/CIPSO mapping has the form:
+
+       smack level [category [category]*]
+
+Smack does not expect the level or category sets to be related in any
+particular way and does not assume or assign accesses based on them. Some
+examples of mappings:
+
+       TopSecret 7
+       TS:A,B    7 1 2
+       SecBDE    5 2 4 6
+       RAFTERS   7 12 26
+
+The ":" and "," characters are permitted in a Smack label but have no special
+meaning.
+
+The mapping of Smack labels to CIPSO values is defined by writing to
+/smack/cipso. Again, the format of data written to this special file
+is highly restrictive, so the program smackcipso is provided to
+ensure the writes are done properly. This program takes mappings
+on the standard input and sends them to /smack/cipso properly.
+
+In addition to explicit mappings Smack supports direct CIPSO mappings. One
+CIPSO level is used to indicate that the category set passed in the packet is
+in fact an encoding of the Smack label. The level used is 250 by default. The
+value can be read from /smack/direct and changed by writing to /smack/direct.
+
+Socket Attributes
+
+There are two attributes that are associated with sockets. These attributes
+can only be set by privileged tasks, but any task can read them for their own
+sockets.
+
+       SMACK64IPIN: The Smack label of the task object. A privileged
+       program that will enforce policy may set this to the star label.
+
+       SMACK64IPOUT: The Smack label transmitted with outgoing packets.
+       A privileged program may set this to match the label of another
+       task with which it hopes to communicate.
+
+Writing Applications for Smack
+
+There are three sorts of applications that will run on a Smack system. How an
+application interacts with Smack will determine what it will have to do to
+work properly under Smack.
+
+Smack Ignorant Applications
+
+By far the majority of applications have no reason whatever to care about the
+unique properties of Smack. Since invoking a program has no impact on the
+Smack label associated with the process the only concern likely to arise is
+whether the process has execute access to the program.
+
+Smack Relevant Applications
+
+Some programs can be improved by teaching them about Smack, but do not make
+any security decisions themselves. The utility ls(1) is one example of such a
+program.
+
+Smack Enforcing Applications
+
+These are special programs that not only know about Smack, but participate in
+the enforcement of system policy. In most cases these are the programs that
+set up user sessions. There are also network services that provide information
+to processes running with various labels.
+
+File System Interfaces
+
+Smack maintains labels on file system objects using extended attributes. The
+Smack label of a file, directory, or other file system object can be obtained
+using getxattr(2).
+
+       len = getxattr("/", "security.SMACK64", value, sizeof (value));
+
+will put the Smack label of the root directory into value. A privileged
+process can set the Smack label of a file system object with setxattr(2).
+
+       len = strlen("Rubble");
+       rc = setxattr("/foo", "security.SMACK64", "Rubble", len, 0);
+
+will set the Smack label of /foo to "Rubble" if the program has appropriate
+privilege.
+
+Socket Interfaces
+
+The socket attributes can be read using fgetxattr(2).
+
+A privileged process can set the Smack label of outgoing packets with
+fsetxattr(2).
+
+       len = strlen("Rubble");
+       rc = fsetxattr(fd, "security.SMACK64IPOUT", "Rubble", len, 0);
+
+will set the Smack label "Rubble" on packets going out from the socket if the
+program has appropriate privilege.
+
+       rc = fsetxattr(fd, "security.SMACK64IPIN, "*", strlen("*"), 0);
+
+will set the Smack label "*" as the object label against which incoming
+packets will be checked if the program has appropriate privilege.
+
+Administration
+
+Smack supports some mount options:
+
+       smackfsdef=label: specifies the label to give files that lack
+       the Smack label extended attribute.
+
+       smackfsroot=label: specifies the label to assign the root of the
+       file system if it lacks the Smack extended attribute.
+
+       smackfshat=label: specifies a label that must have read access to
+       all labels set on the filesystem. Not yet enforced.
+
+       smackfsfloor=label: specifies a label to which all labels set on the
+       filesystem must have read access. Not yet enforced.
+
+These mount options apply to all file system types.
+
index 681e2b36195c98ea5271b76383b3a574b190b04f..08a1ed1cb5d84192d4b1e3e0eec3cf058dfded73 100644 (file)
@@ -220,20 +220,8 @@ decreasing the likelihood of your MIME-attached change being accepted.
 Exception:  If your mailer is mangling patches then someone may ask
 you to re-send them using MIME.
 
-
-WARNING: Some mailers like Mozilla send your messages with
----- message header ----
-Content-Type: text/plain; charset=us-ascii; format=flowed
----- message header ----
-The problem is that "format=flowed" makes some of the mailers
-on receiving side to replace TABs with spaces and do similar
-changes. Thus the patches from you can look corrupted.
-
-To fix this just make your mozilla defaults/pref/mailnews.js file to look like:
-pref("mailnews.send_plaintext_flowed", false); // RFC 2646=======
-pref("mailnews.display.disable_format_flowed_support", true);
-
-
+See Documentation/email-clients.txt for hints about configuring
+your e-mail client so that it sends your patches untouched.
 
 8) E-mail size.
 
index c0d8853672dc9e533e4be07c573c5e2918331038..2e953e228f4d7295d4f847cf531fb1719cc64a35 100644 (file)
@@ -32,7 +32,7 @@ BARRIER IO before the access to the SMC chip because the AEN latch
 only needs occurs after the SMC IO write cycle.  The routines that
 implement this work-around make an additional concession which is to
 disable interrupts during the IO sequence.  Other hardware devices
-(the LogicPD CPLD) have registers in the same the physical memory
+(the LogicPD CPLD) have registers in the same physical memory
 region as the SMC chip.  An interrupt might allow an access to one of
 those registers while SMC IO is being performed.
 
index 24029f65fc94a0096a2116b1c893c6258cb843a7..172ad4aec493cbe9a9db3b6193a43d8794b231e6 100644 (file)
@@ -16,3 +16,7 @@ echo 'echo "$@" >> /tmp/modprobe.log' >> /tmp/modprobe
 echo 'exec /sbin/modprobe "$@"' >> /tmp/modprobe
 chmod a+x /tmp/modprobe
 echo /tmp/modprobe > /proc/sys/kernel/modprobe
+
+Note that the above applies only when the *kernel* is requesting
+that the module be loaded -- it won't have any effect if that module
+is being loaded explicitly using "modprobe" from userspace.
index 2a97320ee17f1d1b1c5a9b1efc138bbea4631f0e..83009fdcbbc8ee2de932cb4713dbb44734eab4b0 100644 (file)
@@ -122,15 +122,15 @@ None the less, there are some APIs to support such legacy drivers.  Avoid
 using these calls except with such hotplug-deficient drivers.
 
        struct platform_device *platform_device_alloc(
-                       char *name, unsigned id);
+                       const char *name, int id);
 
 You can use platform_device_alloc() to dynamically allocate a device, which
 you will then initialize with resources and platform_device_register().
 A better solution is usually:
 
        struct platform_device *platform_device_register_simple(
-                       char *name, unsigned id,
-                       struct resource *res, unsigned nres);
+                       const char *name, int id,
+                       struct resource *res, unsigned int nres);
 
 You can use platform_device_register_simple() as a one-step call to allocate
 and register a device.
index 181bff00516784e3b4bc0c8a7f2b94ed47b76e70..a7d9d179131a76c1f3ef297792ddaae95786e283 100644 (file)
@@ -156,22 +156,6 @@ Who:       Arjan van de Ven <arjan@linux.intel.com>
 
 ---------------------------
 
-What:  USB driver API moves to EXPORT_SYMBOL_GPL
-When:  February 2008
-Files: include/linux/usb.h, drivers/usb/core/driver.c
-Why:   The USB subsystem has changed a lot over time, and it has been
-       possible to create userspace USB drivers using usbfs/libusb/gadgetfs
-       that operate as fast as the USB bus allows.  Because of this, the USB
-       subsystem will not be allowing closed source kernel drivers to
-       register with it, after this grace period is over.  If anyone needs
-       any help in converting their closed source drivers over to use the
-       userspace filesystems, please contact the
-       linux-usb-devel@lists.sourceforge.net mailing list, and the developers
-       there will be glad to help you out.
-Who:   Greg Kroah-Hartman <gregkh@suse.de>
-
----------------------------
-
 What:  vm_ops.nopage
 When:  Soon, provided in-kernel callers have been converted
 Why:   This interface is replaced by vm_ops.fault, but it has been around
index d1b98257d00063db10075d54180b7497bcc99d41..44c97e6accb2655faed63b52e4bc63848571a7ab 100644 (file)
@@ -377,7 +377,7 @@ more explicit to have a method whereby userspace sees this divergence.
 Rather than have a group where some items behave differently than
 others, configfs provides a method whereby one or many subgroups are
 automatically created inside the parent at its creation.  Thus,
-mkdir("parent) results in "parent", "parent/subgroup1", up through
+mkdir("parent") results in "parent", "parent/subgroup1", up through
 "parent/subgroupN".  Items of type 1 can now be created in
 "parent/subgroup1", and items of type N can be created in
 "parent/subgroupN".
index dac45c92d872b977312372210243ffa318ad08cb..0f33c77bc14b2695f6ebb1d70c464bee674c7c33 100644 (file)
@@ -1,6 +1,6 @@
 Changes since 2.5.0:
 
---- 
+---
 [recommended]
 
 New helpers: sb_bread(), sb_getblk(), sb_find_get_block(), set_bh(),
@@ -10,7 +10,7 @@ Use them.
 
 (sb_find_get_block() replaces 2.4's get_hash_table())
 
---- 
+---
 [recommended]
 
 New methods: ->alloc_inode() and ->destroy_inode().
@@ -28,7 +28,7 @@ Declare
 
 Use FOO_I(inode) instead of &inode->u.foo_inode_i;
 
-Add foo_alloc_inode() and foo_destory_inode() - the former should allocate
+Add foo_alloc_inode() and foo_destroy_inode() - the former should allocate
 foo_inode_info and return the address of ->vfs_inode, the latter should free
 FOO_I(inode) (see in-tree filesystems for examples).
 
index 4413a2d4646fc4fd5305cb60e06a57bd5243bd16..e2799b5fafea890153b2d94acb25a712fe6a2587 100644 (file)
@@ -216,6 +216,7 @@ Table 1-3: Contents of the stat files (as of 2.6.22-rc3)
   priority      priority level
   nice          nice level
   num_threads   number of threads
+  it_real_value        (obsolete, always 0)
   start_time    time the process started after system boot
   vsize         virtual memory size
   rss           resident set memory size
@@ -1134,13 +1135,6 @@ check the amount of free space (value is in seconds). Default settings are: 4,
 resume it  if we have a value of 3 or more percent; consider information about
 the amount of free space valid for 30 seconds
 
-audit_argv_kb
--------------
-
-The file contains a single value denoting the limit on the argv array size
-for execve (in KiB). This limit is only applied when system call auditing for
-execve is enabled, otherwise the value is ignored.
-
 ctrl-alt-del
 ------------
 
@@ -1321,13 +1315,28 @@ for writeout by the pdflush daemons.  It is expressed in 100'ths of a second.
 Data which has been dirty in-memory for longer than this interval will be
 written out next time a pdflush daemon wakes up.
 
+highmem_is_dirtyable
+--------------------
+
+Only present if CONFIG_HIGHMEM is set.
+
+This defaults to 0 (false), meaning that the ratios set above are calculated
+as a percentage of lowmem only.  This protects against excessive scanning
+in page reclaim, swapping and general VM distress.
+
+Setting this to 1 can be useful on 32 bit machines where you want to make
+random changes within an MMAPed file that is larger than your available
+lowmem without causing large quantities of random IO.  Is is safe if the
+behavior of all programs running on the machine is known and memory will
+not be otherwise stressed.
+
 legacy_va_layout
 ----------------
 
 If non-zero, this sysctl disables the new 32-bit mmap mmap layout - the kernel
 will use the legacy (2.4) layout for all processes.
 
-lower_zone_protection
+lowmem_reserve_ratio
 ---------------------
 
 For some specialised workloads on highmem machines it is dangerous for
@@ -1347,25 +1356,71 @@ captured into pinned user memory.
 mechanism will also defend that region from allocations which could use
 highmem or lowmem).
 
-The `lower_zone_protection' tunable determines how aggressive the kernel is
-in defending these lower zones.  The default value is zero - no
-protection at all.
+The `lowmem_reserve_ratio' tunable determines how aggressive the kernel is
+in defending these lower zones.
 
 If you have a machine which uses highmem or ISA DMA and your
 applications are using mlock(), or if you are running with no swap then
-you probably should increase the lower_zone_protection setting.
-
-The units of this tunable are fairly vague.  It is approximately equal
-to "megabytes," so setting lower_zone_protection=100 will protect around 100
-megabytes of the lowmem zone from user allocations.  It will also make
-those 100 megabytes unavailable for use by applications and by
-pagecache, so there is a cost.
-
-The effects of this tunable may be observed by monitoring
-/proc/meminfo:LowFree.  Write a single huge file and observe the point
-at which LowFree ceases to fall.
-
-A reasonable value for lower_zone_protection is 100.
+you probably should change the lowmem_reserve_ratio setting.
+
+The lowmem_reserve_ratio is an array. You can see them by reading this file.
+-
+% cat /proc/sys/vm/lowmem_reserve_ratio
+256     256     32
+-
+Note: # of this elements is one fewer than number of zones. Because the highest
+      zone's value is not necessary for following calculation.
+
+But, these values are not used directly. The kernel calculates # of protection
+pages for each zones from them. These are shown as array of protection pages
+in /proc/zoneinfo like followings. (This is an example of x86-64 box).
+Each zone has an array of protection pages like this.
+
+-
+Node 0, zone      DMA
+  pages free     1355
+        min      3
+        low      3
+        high     4
+       :
+       :
+    numa_other   0
+        protection: (0, 2004, 2004, 2004)
+       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+  pagesets
+    cpu: 0 pcp: 0
+        :
+-
+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]
+(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.
+
+zone[i]'s protection[j] is calculated by following exprssion.
+
+(i < j):
+  zone[i]->protection[j]
+  = (total sums of present_pages from zone[i+1] to zone[j] on the node)
+    / lowmem_reserve_ratio[i];
+(i = j):
+   (should not be protected. = 0;
+(i > j):
+   (not necessary, but looks 0)
+
+The default values of lowmem_reserve_ratio[i] are
+    256 (if zone[i] means DMA or DMA32 zone)
+    32  (others).
+As above expression, they are reciprocal number of ratio.
+256 means 1/256. # of protection pages becomes about "0.39%" of total present
+pages of higher zones on the node.
+
+If you would like to protect more pages, smaller values are effective.
+The minimum value is 1 (1/1 -> 100%).
 
 page-cluster
 ------------
@@ -1919,11 +1974,6 @@ max_size
 Maximum size  of  the routing cache. Old entries will be purged once the cache
 reached has this size.
 
-max_delay, min_delay
---------------------
-
-Delays for flushing the routing cache.
-
 redirect_load, redirect_number
 ------------------------------
 
index 339c6a4f220ec036a7bc681d512ef65982dcdcef..7be232b44ee4602f74dc0b75ed66d150c23a6aaf 100644 (file)
@@ -118,7 +118,7 @@ All this differs from the old initrd in several ways:
     with the new root (cd /newmount; mount --move . /; chroot .), attach
     stdin/stdout/stderr to the new /dev/console, and exec the new init.
 
-    Since this is a remarkably persnickity process (and involves deleting
+    Since this is a remarkably persnickety process (and involves deleting
     commands before you can run them), the klibc package introduced a helper
     program (utils/run_init.c) to do all this for you.  Most other packages
     (such as busybox) have named this command "switch_root".
index 18d23f9a18c74663e1a7cbcc07232e7879945c5e..094f2d2f38b1a5571283ee745aa494c12b12808c 100644 (file)
@@ -140,7 +140,7 @@ close()     decrements the channel buffer's refcount.  When the refcount
 In order for a user application to make use of relay files, the
 host filesystem must be mounted.  For example,
 
-       mount -t debugfs debugfs /debug
+       mount -t debugfs debugfs /sys/kernel/debug
 
 NOTE:   the host filesystem doesn't need to be mounted for kernel
        clients to create or use channels - it only needs to be
similarity index 98%
rename from Documentation/fujitsu/frv/booting.txt
rename to Documentation/frv/booting.txt
index 4e229056ef2261b79ac3ab40ef59820da16b0cf9..ace200b7c2140145c457ee86ce7f02b532c85e87 100644 (file)
@@ -177,5 +177,5 @@ separated by spaces:
   (*) vdc=...
 
       This option configures the MB93493 companion chip visual display
-      driver. Please see Documentation/fujitsu/mb93493/vdc.txt for more
+      driver. Please see Documentation/frv/mb93493/vdc.txt for more
       information.
index 6bc2ba215df9a3eb4b41ff6f987e5fa294e47250..8da724e2a0ff795d450e8b0b7b61118d7bf604a6 100644 (file)
@@ -32,7 +32,7 @@ The exact capabilities of GPIOs vary between systems.  Common options:
   - Input values are likewise readable (1, 0).  Some chips support readback
     of pins configured as "output", which is very useful in such "wire-OR"
     cases (to support bidirectional signaling).  GPIO controllers may have
-    input de-glitch logic, sometimes with software controls.
+    input de-glitch/debounce logic, sometimes with software controls.
 
   - Inputs can often be used as IRQ signals, often edge triggered but
     sometimes level triggered.  Such IRQs may be configurable as system
@@ -60,10 +60,13 @@ used on a board that's wired differently.  Only least-common-denominator
 functionality can be very portable.  Other features are platform-specific,
 and that can be critical for glue logic.
 
-Plus, this doesn't define an implementation framework, just an interface.
+Plus, this doesn't require any implementation framework, just an interface.
 One platform might implement it as simple inline functions accessing chip
 registers; another might implement it by delegating through abstractions
-used for several very different kinds of GPIO controller.
+used for several very different kinds of GPIO controller.  (There is some
+optional code supporting such an implementation strategy, described later
+in this document, but drivers acting as clients to the GPIO interface must
+not care how it's implemented.)
 
 That said, if the convention is supported on their platform, drivers should
 use it when possible.  Platforms should declare GENERIC_GPIO support in
@@ -121,6 +124,11 @@ before tasking is enabled, as part of early board setup.
 For output GPIOs, the value provided becomes the initial output value.
 This helps avoid signal glitching during system startup.
 
+For compatibility with legacy interfaces to GPIOs, setting the direction
+of a GPIO implicitly requests that GPIO (see below) if it has not been
+requested already.  That compatibility may be removed in the future;
+explicitly requesting GPIOs is strongly preferred.
+
 Setting the direction can fail if the GPIO number is invalid, or when
 that particular GPIO can't be used in that mode.  It's generally a bad
 idea to rely on boot firmware to have set the direction correctly, since
@@ -133,6 +141,7 @@ Spinlock-Safe GPIO access
 -------------------------
 Most GPIO controllers can be accessed with memory read/write instructions.
 That doesn't need to sleep, and can safely be done from inside IRQ handlers.
+(That includes hardirq contexts on RT kernels.)
 
 Use these calls to access such GPIOs:
 
@@ -145,7 +154,7 @@ Use these calls to access such GPIOs:
 The values are boolean, zero for low, nonzero for high.  When reading the
 value of an output pin, the value returned should be what's seen on the
 pin ... that won't always match the specified output value, because of
-issues including wire-OR and output latencies.
+issues including open-drain signaling and output latencies.
 
 The get/set calls have no error returns because "invalid GPIO" should have
 been reported earlier from gpio_direction_*().  However, note that not all
@@ -170,7 +179,8 @@ get to the head of a queue to transmit a command and get its response.
 This requires sleeping, which can't be done from inside IRQ handlers.
 
 Platforms that support this type of GPIO distinguish them from other GPIOs
-by returning nonzero from this call:
+by returning nonzero from this call (which requires a valid GPIO number,
+either explicitly or implicitly requested):
 
        int gpio_cansleep(unsigned gpio);
 
@@ -209,8 +219,11 @@ before tasking is enabled, as part of early board setup.
 These calls serve two basic purposes.  One is marking the signals which
 are actually in use as GPIOs, for better diagnostics; systems may have
 several hundred potential GPIOs, but often only a dozen are used on any
-given board.  Another is to catch conflicts between drivers, reporting
-errors when drivers wrongly think they have exclusive use of that signal.
+given board.  Another is to catch conflicts, identifying errors when
+(a) two or more drivers wrongly think they have exclusive use of that
+signal, or (b) something wrongly believes it's safe to remove drivers
+needed to manage a signal that's in active use.  That is, requesting a
+GPIO can serve as a kind of lock.
 
 These two calls are optional because not not all current Linux platforms
 offer such functionality in their GPIO support; a valid implementation
@@ -223,6 +236,9 @@ Note that requesting a GPIO does NOT cause it to be configured in any
 way; it just marks that GPIO as in use.  Separate code must handle any
 pin setup (e.g. controlling which pin the GPIO uses, pullup/pulldown).
 
+Also note that it's your responsibility to have stopped using a GPIO
+before you free it.
+
 
 GPIOs mapped to IRQs
 --------------------
@@ -238,7 +254,7 @@ map between them using calls like:
 
 Those return either the corresponding number in the other namespace, or
 else a negative errno code if the mapping can't be done.  (For example,
-some GPIOs can't used as IRQs.)  It is an unchecked error to use a GPIO
+some GPIOs can't be used as IRQs.)  It is an unchecked error to use a GPIO
 number that wasn't set up as an input using gpio_direction_input(), or
 to use an IRQ number that didn't originally come from gpio_to_irq().
 
@@ -299,17 +315,110 @@ Related to multiplexing is configuration and enabling of the pullups or
 pulldowns integrated on some platforms.  Not all platforms support them,
 or support them in the same way; and any given board might use external
 pullups (or pulldowns) so that the on-chip ones should not be used.
+(When a circuit needs 5 kOhm, on-chip 100 kOhm resistors won't do.)
 
 There are other system-specific mechanisms that are not specified here,
 like the aforementioned options for input de-glitching and wire-OR output.
 Hardware may support reading or writing GPIOs in gangs, but that's usually
 configuration dependent:  for GPIOs sharing the same bank.  (GPIOs are
 commonly grouped in banks of 16 or 32, with a given SOC having several such
-banks.)  Some systems can trigger IRQs from output GPIOs.  Code relying on
-such mechanisms will necessarily be nonportable.
+banks.)  Some systems can trigger IRQs from output GPIOs, or read values
+from pins not managed as GPIOs.  Code relying on such mechanisms will
+necessarily be nonportable.
 
-Dynamic definition of GPIOs is not currently supported; for example, as
+Dynamic definition of GPIOs is not currently standard; for example, as
 a side effect of configuring an add-on board with some GPIO expanders.
 
 These calls are purely for kernel space, but a userspace API could be built
-on top of it.
+on top of them.
+
+
+GPIO implementor's framework (OPTIONAL)
+=======================================
+As noted earlier, there is an optional implementation framework making it
+easier for platforms to support different kinds of GPIO controller using
+the same programming interface.
+
+As a debugging aid, if debugfs is available a /sys/kernel/debug/gpio file
+will be found there.  That will list all the controllers registered through
+this framework, and the state of the GPIOs currently in use.
+
+
+Controller Drivers: gpio_chip
+-----------------------------
+In this framework each GPIO controller is packaged as a "struct gpio_chip"
+with information common to each controller of that type:
+
+ - methods to establish GPIO direction
+ - methods used to access GPIO values
+ - flag saying whether calls to its methods may sleep
+ - optional debugfs dump method (showing extra state like pullup config)
+ - label for diagnostics
+
+There is also per-instance data, which may come from device.platform_data:
+the number of its first GPIO, and how many GPIOs it exposes.
+
+The code implementing a gpio_chip should support multiple instances of the
+controller, possibly using the driver model.  That code will configure each
+gpio_chip and issue gpiochip_add().  Removing a GPIO controller should be
+rare; use gpiochip_remove() when it is unavoidable.
+
+Most often a gpio_chip is part of an instance-specific structure with state
+not exposed by the GPIO interfaces, such as addressing, power management,
+and more.  Chips such as codecs will have complex non-GPIO state,
+
+Any debugfs dump method should normally ignore signals which haven't been
+requested as GPIOs.  They can use gpiochip_is_requested(), which returns
+either NULL or the label associated with that GPIO when it was requested.
+
+
+Platform Support
+----------------
+To support this framework, a platform's Kconfig will "select HAVE_GPIO_LIB"
+and arrange that its <asm/gpio.h> includes <asm-generic/gpio.h> and defines
+three functions: gpio_get_value(), gpio_set_value(), and gpio_cansleep().
+They may also want to provide a custom value for ARCH_NR_GPIOS.
+
+Trivial implementations of those functions can directly use framework
+code, which always dispatches through the gpio_chip:
+
+  #define gpio_get_value       __gpio_get_value
+  #define gpio_set_value       __gpio_set_value
+  #define gpio_cansleep                __gpio_cansleep
+
+Fancier implementations could instead define those as inline functions with
+logic optimizing access to specific SOC-based GPIOs.  For example, if the
+referenced GPIO is the constant "12", getting or setting its value could
+cost as little as two or three instructions, never sleeping.  When such an
+optimization is not possible those calls must delegate to the framework
+code, costing at least a few dozen instructions.  For bitbanged I/O, such
+instruction savings can be significant.
+
+For SOCs, platform-specific code defines and registers gpio_chip instances
+for each bank of on-chip GPIOs.  Those GPIOs should be numbered/labeled to
+match chip vendor documentation, and directly match board schematics.  They
+may well start at zero and go up to a platform-specific limit.  Such GPIOs
+are normally integrated into platform initialization to make them always be
+available, from arch_initcall() or earlier; they can often serve as IRQs.
+
+
+Board Support
+-------------
+For external GPIO controllers -- such as I2C or SPI expanders, ASICs, multi
+function devices, FPGAs or CPLDs -- most often board-specific code handles
+registering controller devices and ensures that their drivers know what GPIO
+numbers to use with gpiochip_add().  Their numbers often start right after
+platform-specific GPIOs.
+
+For example, board setup code could create structures identifying the range
+of GPIOs that chip will expose, and passes them to each GPIO expander chip
+using platform_data.  Then the chip driver's probe() routine could pass that
+data to gpiochip_add().
+
+Initialization order can be important.  For example, when a device relies on
+an I2C-based GPIO, its probe() routine should only be called after that GPIO
+becomes available.  That may mean the device should not be registered until
+calls for that GPIO can work.  One way to address such dependencies is for
+such gpio_chip controllers to provide setup() and teardown() callbacks to
+board specific code; those board specific callbacks would register devices
+once all the necessary resources are available.
index c4fce6a135374377bcd5d6aa2277c25f5811914f..1d81c530c4a584f15e25ad85e31e57693acfff6f 100644 (file)
@@ -1,6 +1,9 @@
 Kernel driver pca9539
 =====================
 
+NOTE: this driver is deprecated and will be dropped soon, use
+drivers/gpio/pca9539.c instead.
+
 Supported chips:
   * Philips PCA9539
     Prefix: 'pca9539'
index 773a814d409361767da369070d2d7e5267536c16..d23610fb2ff9e0560580bf4332bc81ea0a249326 100644 (file)
@@ -16,6 +16,7 @@
 #include <fcntl.h>
 #include <fnmatch.h>
 #include <string.h>
+#include <sys/ioctl.h>
 #include <sys/mman.h>
 #include <sys/stat.h>
 #include <unistd.h>
@@ -65,7 +66,7 @@ int scan_tree(char *path, char *file, off_t offset, size_t length, int touch)
 {
        struct dirent **namelist;
        char *name, *path2;
-       int i, n, r, rc, result = 0;
+       int i, n, r, rc = 0, result = 0;
        struct stat buf;
 
        n = scandir(path, &namelist, 0, alphasort);
@@ -113,7 +114,7 @@ skip:
                free(namelist[i]);
        }
        free(namelist);
-       return rc;
+       return result;
 }
 
 char buf[1024];
@@ -149,7 +150,7 @@ int scan_rom(char *path, char *file)
 {
        struct dirent **namelist;
        char *name, *path2;
-       int i, n, r, rc, result = 0;
+       int i, n, r, rc = 0, result = 0;
        struct stat buf;
 
        n = scandir(path, &namelist, 0, alphasort);
@@ -180,7 +181,7 @@ int scan_rom(char *path, char *file)
                         * important thing is that no MCA happened.
                         */
                        if (rc > 0)
-                               fprintf(stderr, "PASS: %s read %ld bytes\n", path2, rc);
+                               fprintf(stderr, "PASS: %s read %d bytes\n", path2, rc);
                        else {
                                fprintf(stderr, "PASS: %s not readable\n", path2);
                                return rc;
@@ -201,10 +202,10 @@ skip:
                free(namelist[i]);
        }
        free(namelist);
-       return rc;
+       return result;
 }
 
-int main()
+int main(void)
 {
        int rc;
 
@@ -256,4 +257,6 @@ int main()
        scan_tree("/proc/bus/pci", "??.?", 0xA0000, 0x20000, 0);
        scan_tree("/proc/bus/pci", "??.?", 0xC0000, 0x40000, 1);
        scan_tree("/proc/bus/pci", "??.?", 0, 1024*1024, 0);
+
+       return rc;
 }
diff --git a/Documentation/ide/ChangeLog.ide-cd.1994-2004 b/Documentation/ide/ChangeLog.ide-cd.1994-2004
new file mode 100644 (file)
index 0000000..190d17b
--- /dev/null
@@ -0,0 +1,268 @@
+/*
+ * 1.00  Oct 31, 1994 -- Initial version.
+ * 1.01  Nov  2, 1994 -- Fixed problem with starting request in
+ *                       cdrom_check_status.
+ * 1.03  Nov 25, 1994 -- leaving unmask_intr[] as a user-setting (as for disks)
+ * (from mlord)       -- minor changes to cdrom_setup()
+ *                    -- renamed ide_dev_s to ide_drive_t, enable irq on command
+ * 2.00  Nov 27, 1994 -- Generalize packet command interface;
+ *                       add audio ioctls.
+ * 2.01  Dec  3, 1994 -- Rework packet command interface to handle devices
+ *                       which send an interrupt when ready for a command.
+ * 2.02  Dec 11, 1994 -- Cache the TOC in the driver.
+ *                       Don't use SCMD_PLAYAUDIO_TI; it's not included
+ *                       in the current version of ATAPI.
+ *                       Try to use LBA instead of track or MSF addressing
+ *                       when possible.
+ *                       Don't wait for READY_STAT.
+ * 2.03  Jan 10, 1995 -- Rewrite block read routines to handle block sizes
+ *                       other than 2k and to move multiple sectors in a
+ *                       single transaction.
+ * 2.04  Apr 21, 1995 -- Add work-around for Creative Labs CD220E drives.
+ *                       Thanks to Nick Saw <cwsaw@pts7.pts.mot.com> for
+ *                       help in figuring this out.  Ditto for Acer and
+ *                       Aztech drives, which seem to have the same problem.
+ * 2.04b May 30, 1995 -- Fix to match changes in ide.c version 3.16 -ml
+ * 2.05  Jun  8, 1995 -- Don't attempt to retry after an illegal request
+ *                        or data protect error.
+ *                       Use HWIF and DEV_HWIF macros as in ide.c.
+ *                       Always try to do a request_sense after
+ *                        a failed command.
+ *                       Include an option to give textual descriptions
+ *                        of ATAPI errors.
+ *                       Fix a bug in handling the sector cache which
+ *                        showed up if the drive returned data in 512 byte
+ *                        blocks (like Pioneer drives).  Thanks to
+ *                        Richard Hirst <srh@gpt.co.uk> for diagnosing this.
+ *                       Properly supply the page number field in the
+ *                        MODE_SELECT command.
+ *                       PLAYAUDIO12 is broken on the Aztech; work around it.
+ * 2.05x Aug 11, 1995 -- lots of data structure renaming/restructuring in ide.c
+ *                       (my apologies to Scott, but now ide-cd.c is independent)
+ * 3.00  Aug 22, 1995 -- Implement CDROMMULTISESSION ioctl.
+ *                       Implement CDROMREADAUDIO ioctl (UNTESTED).
+ *                       Use input_ide_data() and output_ide_data().
+ *                       Add door locking.
+ *                       Fix usage count leak in cdrom_open, which happened
+ *                        when a read-write mount was attempted.
+ *                       Try to load the disk on open.
+ *                       Implement CDROMEJECT_SW ioctl (off by default).
+ *                       Read total cdrom capacity during open.
+ *                       Rearrange logic in cdrom_decode_status.  Issue
+ *                        request sense commands for failed packet commands
+ *                        from here instead of from cdrom_queue_packet_command.
+ *                        Fix a race condition in retrieving error information.
+ *                       Suppress printing normal unit attention errors and
+ *                        some drive not ready errors.
+ *                       Implement CDROMVOLREAD ioctl.
+ *                       Implement CDROMREADMODE1/2 ioctls.
+ *                       Fix race condition in setting up interrupt handlers
+ *                        when the `serialize' option is used.
+ * 3.01  Sep  2, 1995 -- Fix ordering of reenabling interrupts in
+ *                        cdrom_queue_request.
+ *                       Another try at using ide_[input,output]_data.
+ * 3.02  Sep 16, 1995 -- Stick total disk capacity in partition table as well.
+ *                       Make VERBOSE_IDE_CD_ERRORS dump failed command again.
+ *                       Dump out more information for ILLEGAL REQUEST errs.
+ *                       Fix handling of errors occurring before the
+ *                        packet command is transferred.
+ *                       Fix transfers with odd bytelengths.
+ * 3.03  Oct 27, 1995 -- Some Creative drives have an id of just `CD'.
+ *                       `DCI-2S10' drives are broken too.
+ * 3.04  Nov 20, 1995 -- So are Vertos drives.
+ * 3.05  Dec  1, 1995 -- Changes to go with overhaul of ide.c and ide-tape.c
+ * 3.06  Dec 16, 1995 -- Add support needed for partitions.
+ *                       More workarounds for Vertos bugs (based on patches
+ *                        from Holger Dietze <dietze@aix520.informatik.uni-leipzig.de>).
+ *                       Try to eliminate byteorder assumptions.
+ *                       Use atapi_cdrom_subchnl struct definition.
+ *                       Add STANDARD_ATAPI compilation option.
+ * 3.07  Jan 29, 1996 -- More twiddling for broken drives: Sony 55D,
+ *                        Vertos 300.
+ *                       Add NO_DOOR_LOCKING configuration option.
+ *                       Handle drive_cmd requests w/NULL args (for hdparm -t).
+ *                       Work around sporadic Sony55e audio play problem.
+ * 3.07a Feb 11, 1996 -- check drive->id for NULL before dereferencing, to fix
+ *                        problem with "hde=cdrom" with no drive present.  -ml
+ * 3.08  Mar  6, 1996 -- More Vertos workarounds.
+ * 3.09  Apr  5, 1996 -- Add CDROMCLOSETRAY ioctl.
+ *                       Switch to using MSF addressing for audio commands.
+ *                       Reformat to match kernel tabbing style.
+ *                       Add CDROM_GET_UPC ioctl.
+ * 3.10  Apr 10, 1996 -- Fix compilation error with STANDARD_ATAPI.
+ * 3.11  Apr 29, 1996 -- Patch from Heiko Eißfeldt <heiko@colossus.escape.de>
+ *                       to remove redundant verify_area calls.
+ * 3.12  May  7, 1996 -- Rudimentary changer support.  Based on patches
+ *                        from Gerhard Zuber <zuber@berlin.snafu.de>.
+ *                       Let open succeed even if there's no loaded disc.
+ * 3.13  May 19, 1996 -- Fixes for changer code.
+ * 3.14  May 29, 1996 -- Add work-around for Vertos 600.
+ *                        (From Hennus Bergman <hennus@sky.ow.nl>.)
+ * 3.15  July 2, 1996 -- Added support for Sanyo 3 CD changers
+ *                        from Ben Galliart <bgallia@luc.edu> with
+ *                        special help from Jeff Lightfoot
+ *                        <jeffml@pobox.com>
+ * 3.15a July 9, 1996 -- Improved Sanyo 3 CD changer identification
+ * 3.16  Jul 28, 1996 -- Fix from Gadi to reduce kernel stack usage for ioctl.
+ * 3.17  Sep 17, 1996 -- Tweak audio reads for some drives.
+ *                       Start changing CDROMLOADFROMSLOT to CDROM_SELECT_DISC.
+ * 3.18  Oct 31, 1996 -- Added module and DMA support.
+ *
+ * 4.00  Nov 5, 1996   -- New ide-cd maintainer,
+ *                                 Erik B. Andersen <andersee@debian.org>
+ *                     -- Newer Creative drives don't always set the error
+ *                          register correctly.  Make sure we see media changes
+ *                          regardless.
+ *                     -- Integrate with generic cdrom driver.
+ *                     -- CDROMGETSPINDOWN and CDROMSETSPINDOWN ioctls, based on
+ *                          a patch from Ciro Cattuto <>.
+ *                     -- Call set_device_ro.
+ *                     -- Implement CDROMMECHANISMSTATUS and CDROMSLOTTABLE
+ *                          ioctls, based on patch by Erik Andersen
+ *                     -- Add some probes of drive capability during setup.
+ *
+ * 4.01  Nov 11, 1996  -- Split into ide-cd.c and ide-cd.h
+ *                     -- Removed CDROMMECHANISMSTATUS and CDROMSLOTTABLE
+ *                          ioctls in favor of a generalized approach
+ *                          using the generic cdrom driver.
+ *                     -- Fully integrated with the 2.1.X kernel.
+ *                     -- Other stuff that I forgot (lots of changes)
+ *
+ * 4.02  Dec 01, 1996  -- Applied patch from Gadi Oxman <gadio@netvision.net.il>
+ *                          to fix the drive door locking problems.
+ *
+ * 4.03  Dec 04, 1996  -- Added DSC overlap support.
+ * 4.04  Dec 29, 1996  -- Added CDROMREADRAW ioclt based on patch
+ *                          by Ales Makarov (xmakarov@sun.felk.cvut.cz)
+ *
+ * 4.05  Nov 20, 1997  -- Modified to print more drive info on init
+ *                        Minor other changes
+ *                        Fix errors on CDROMSTOP (If you have a "Dolphin",
+ *                          you must define IHAVEADOLPHIN)
+ *                        Added identifier so new Sanyo CD-changer works
+ *                        Better detection if door locking isn't supported
+ *
+ * 4.06  Dec 17, 1997  -- fixed endless "tray open" messages  -ml
+ * 4.07  Dec 17, 1997  -- fallback to set pc->stat on "tray open"
+ * 4.08  Dec 18, 1997  -- spew less noise when tray is empty
+ *                     -- fix speed display for ACER 24X, 18X
+ * 4.09  Jan 04, 1998  -- fix handling of the last block so we return
+ *                         an end of file instead of an I/O error (Gadi)
+ * 4.10  Jan 24, 1998  -- fixed a bug so now changers can change to a new
+ *                         slot when there is no disc in the current slot.
+ *                     -- Fixed a memory leak where info->changer_info was
+ *                         malloc'ed but never free'd when closing the device.
+ *                     -- Cleaned up the global namespace a bit by making more
+ *                         functions static that should already have been.
+ * 4.11  Mar 12, 1998  -- Added support for the CDROM_SELECT_SPEED ioctl
+ *                         based on a patch for 2.0.33 by Jelle Foks
+ *                         <jelle@scintilla.utwente.nl>, a patch for 2.0.33
+ *                         by Toni Giorgino <toni@pcape2.pi.infn.it>, the SCSI
+ *                         version, and my own efforts.  -erik
+ *                     -- Fixed a stupid bug which egcs was kind enough to
+ *                         inform me of where "Illegal mode for this track"
+ *                         was never returned due to a comparison on data
+ *                         types of limited range.
+ * 4.12  Mar 29, 1998  -- Fixed bug in CDROM_SELECT_SPEED so write speed is
+ *                         now set ionly for CD-R and CD-RW drives.  I had
+ *                         removed this support because it produced errors.
+ *                         It produced errors _only_ for non-writers. duh.
+ * 4.13  May 05, 1998  -- Suppress useless "in progress of becoming ready"
+ *                         messages, since this is not an error.
+ *                     -- Change error messages to be const
+ *                     -- Remove a "\t" which looks ugly in the syslogs
+ * 4.14  July 17, 1998 -- Change to pointing to .ps version of ATAPI spec
+ *                         since the .pdf version doesn't seem to work...
+ *                     -- Updated the TODO list to something more current.
+ *
+ * 4.15  Aug 25, 1998  -- Updated ide-cd.h to respect mechine endianess,
+ *                         patch thanks to "Eddie C. Dost" <ecd@skynet.be>
+ *
+ * 4.50  Oct 19, 1998  -- New maintainers!
+ *                         Jens Axboe <axboe@image.dk>
+ *                         Chris Zwilling <chris@cloudnet.com>
+ *
+ * 4.51  Dec 23, 1998  -- Jens Axboe <axboe@image.dk>
+ *                      - ide_cdrom_reset enabled since the ide subsystem
+ *                         handles resets fine now. <axboe@image.dk>
+ *                      - Transfer size fix for Samsung CD-ROMs, thanks to
+ *                        "Ville Hallik" <ville.hallik@mail.ee>.
+ *                      - other minor stuff.
+ *
+ * 4.52  Jan 19, 1999  -- Jens Axboe <axboe@image.dk>
+ *                      - Detect DVD-ROM/RAM drives
+ *
+ * 4.53  Feb 22, 1999   - Include other model Samsung and one Goldstar
+ *                         drive in transfer size limit.
+ *                      - Fix the I/O error when doing eject without a medium
+ *                         loaded on some drives.
+ *                      - CDROMREADMODE2 is now implemented through
+ *                         CDROMREADRAW, since many drives don't support
+ *                         MODE2 (even though ATAPI 2.6 says they must).
+ *                      - Added ignore parameter to ide-cd (as a module), eg
+ *                             insmod ide-cd ignore='hda hdb'
+ *                         Useful when using ide-cd in conjunction with
+ *                         ide-scsi. TODO: non-modular way of doing the
+ *                         same.
+ *
+ * 4.54  Aug 5, 1999   - Support for MMC2 class commands through the generic
+ *                       packet interface to cdrom.c.
+ *                     - Unified audio ioctl support, most of it.
+ *                     - cleaned up various deprecated verify_area().
+ *                     - Added ide_cdrom_packet() as the interface for
+ *                       the Uniform generic_packet().
+ *                     - bunch of other stuff, will fill in logs later.
+ *                     - report 1 slot for non-changers, like the other
+ *                       cd-rom drivers. don't report select disc for
+ *                       non-changers as well.
+ *                     - mask out audio playing, if the device can't do it.
+ *
+ * 4.55  Sep 1, 1999   - Eliminated the rest of the audio ioctls, except
+ *                       for CDROMREADTOC[ENTRY|HEADER]. Some of the drivers
+ *                       use this independently of the actual audio handling.
+ *                       They will disappear later when I get the time to
+ *                       do it cleanly.
+ *                     - Minimize the TOC reading - only do it when we
+ *                       know a media change has occurred.
+ *                     - Moved all the CDROMREADx ioctls to the Uniform layer.
+ *                     - Heiko Eißfeldt <heiko@colossus.escape.de> supplied
+ *                       some fixes for CDI.
+ *                     - CD-ROM leaving door locked fix from Andries
+ *                       Brouwer <Andries.Brouwer@cwi.nl>
+ *                     - Erik Andersen <andersen@xmission.com> unified
+ *                       commands across the various drivers and how
+ *                       sense errors are handled.
+ *
+ * 4.56  Sep 12, 1999  - Removed changer support - it is now in the
+ *                       Uniform layer.
+ *                     - Added partition based multisession handling.
+ *                     - Mode sense and mode select moved to the
+ *                       Uniform layer.
+ *                     - Fixed a problem with WPI CDS-32X drive - it
+ *                       failed the capabilities
+ *
+ * 4.57  Apr 7, 2000   - Fixed sense reporting.
+ *                     - Fixed possible oops in ide_cdrom_get_last_session()
+ *                     - Fix locking mania and make ide_cdrom_reset relock
+ *                     - Stop spewing errors to log when magicdev polls with
+ *                       TEST_UNIT_READY on some drives.
+ *                     - Various fixes from Tobias Ringstrom:
+ *                       tray if it was locked prior to the reset.
+ *                       - cdrom_read_capacity returns one frame too little.
+ *                       - Fix real capacity reporting.
+ *
+ * 4.58  May 1, 2000   - Clean up ACER50 stuff.
+ *                     - Fix small problem with ide_cdrom_capacity
+ *
+ * 4.59  Aug 11, 2000  - Fix changer problem in cdrom_read_toc, we weren't
+ *                       correctly sensing a disc change.
+ *                     - Rearranged some code
+ *                     - Use extended sense on drives that support it for
+ *                       correctly reporting tray status -- from
+ *                       Michael D Johnson <johnsom@orst.edu>
+ * 4.60  Dec 17, 2003  - Add mt rainier support
+ *                     - Bump timeout for packet commands, matches sr
+ *                     - Odd stuff
+ * 4.61  Jan 22, 2004  - support hardware sector sizes other than 2kB,
+ *                       Pascal Schmidt <der.eremit@email.de>
+ */
diff --git a/Documentation/ide/ChangeLog.ide-floppy.1996-2002 b/Documentation/ide/ChangeLog.ide-floppy.1996-2002
new file mode 100644 (file)
index 0000000..46c19ef
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Many thanks to Lode Leroy <Lode.Leroy@www.ibase.be>, who tested so many
+ * ALPHA patches to this driver on an EASYSTOR LS-120 ATAPI floppy drive.
+ *
+ * Ver 0.1   Oct 17 96   Initial test version, mostly based on ide-tape.c.
+ * Ver 0.2   Oct 31 96   Minor changes.
+ * Ver 0.3   Dec  2 96   Fixed error recovery bug.
+ * Ver 0.4   Jan 26 97   Add support for the HDIO_GETGEO ioctl.
+ * Ver 0.5   Feb 21 97   Add partitions support.
+ *                       Use the minimum of the LBA and CHS capacities.
+ *                       Avoid hwgroup->rq == NULL on the last irq.
+ *                       Fix potential null dereferencing with DEBUG_LOG.
+ * Ver 0.8   Dec  7 97   Increase irq timeout from 10 to 50 seconds.
+ *                       Add media write-protect detection.
+ *                       Issue START command only if TEST UNIT READY fails.
+ *                       Add work-around for IOMEGA ZIP revision 21.D.
+ *                       Remove idefloppy_get_capabilities().
+ * Ver 0.9   Jul  4 99   Fix a bug which might have caused the number of
+ *                        bytes requested on each interrupt to be zero.
+ *                        Thanks to <shanos@es.co.nz> for pointing this out.
+ * Ver 0.9.sv Jan 6 01   Sam Varshavchik <mrsam@courier-mta.com>
+ *                       Implement low level formatting.  Reimplemented
+ *                       IDEFLOPPY_CAPABILITIES_PAGE, since we need the srfp
+ *                       bit.  My LS-120 drive barfs on
+ *                       IDEFLOPPY_CAPABILITIES_PAGE, but maybe it's just me.
+ *                       Compromise by not reporting a failure to get this
+ *                       mode page.  Implemented four IOCTLs in order to
+ *                       implement formatting.  IOCTls begin with 0x4600,
+ *                       0x46 is 'F' as in Format.
+ *            Jan 9 01   Userland option to select format verify.
+ *                       Added PC_SUPPRESS_ERROR flag - some idefloppy drives
+ *                       do not implement IDEFLOPPY_CAPABILITIES_PAGE, and
+ *                       return a sense error.  Suppress error reporting in
+ *                       this particular case in order to avoid spurious
+ *                       errors in syslog.  The culprit is
+ *                       idefloppy_get_capability_page(), so move it to
+ *                       idefloppy_begin_format() so that it's not used
+ *                       unless absolutely necessary.
+ *                       If drive does not support format progress indication
+ *                       monitor the dsc bit in the status register.
+ *                       Also, O_NDELAY on open will allow the device to be
+ *                       opened without a disk available.  This can be used to
+ *                       open an unformatted disk, or get the device capacity.
+ * Ver 0.91  Dec 11 99   Added IOMEGA Clik! drive support by
+ *                        <paul@paulbristow.net>
+ * Ver 0.92  Oct 22 00   Paul Bristow became official maintainer for this
+ *                        driver.  Included Powerbook internal zip kludge.
+ * Ver 0.93  Oct 24 00   Fixed bugs for Clik! drive
+ *                        no disk on insert and disk change now works
+ * Ver 0.94  Oct 27 00   Tidied up to remove strstr(Clik) everywhere
+ * Ver 0.95  Nov  7 00   Brought across to kernel 2.4
+ * Ver 0.96  Jan  7 01   Actually in line with release version of 2.4.0
+ *                       including set_bit patch from Rusty Russell
+ * Ver 0.97  Jul 22 01   Merge 0.91-0.96 onto 0.9.sv for ac series
+ * Ver 0.97.sv Aug 3 01  Backported from 2.4.7-ac3
+ * Ver 0.98  Oct 26 01   Split idefloppy_transfer_pc into two pieces to
+ *                        fix a lost interrupt problem. It appears the busy
+ *                        bit was being deasserted by my IOMEGA ATAPI ZIP 100
+ *                        drive before the drive was actually ready.
+ * Ver 0.98a Oct 29 01   Expose delay value so we can play.
+ * Ver 0.99  Feb 24 02   Remove duplicate code, modify clik! detection code
+ *                        to support new PocketZip drives
+ */
diff --git a/Documentation/ide/ChangeLog.ide-tape.1995-2002 b/Documentation/ide/ChangeLog.ide-tape.1995-2002
new file mode 100644 (file)
index 0000000..877fac8
--- /dev/null
@@ -0,0 +1,257 @@
+/*
+ * Ver 0.1   Nov  1 95   Pre-working code :-)
+ * Ver 0.2   Nov 23 95   A short backup (few megabytes) and restore procedure
+ *                        was successful ! (Using tar cvf ... on the block
+ *                        device interface).
+ *                       A longer backup resulted in major swapping, bad
+ *                        overall Linux performance and eventually failed as
+ *                        we received non serial read-ahead requests from the
+ *                        buffer cache.
+ * Ver 0.3   Nov 28 95   Long backups are now possible, thanks to the
+ *                        character device interface. Linux's responsiveness
+ *                        and performance doesn't seem to be much affected
+ *                        from the background backup procedure.
+ *                       Some general mtio.h magnetic tape operations are
+ *                        now supported by our character device. As a result,
+ *                        popular tape utilities are starting to work with
+ *                        ide tapes :-)
+ *                       The following configurations were tested:
+ *                       1. An IDE ATAPI TAPE shares the same interface
+ *                        and irq with an IDE ATAPI CDROM.
+ *                       2. An IDE ATAPI TAPE shares the same interface
+ *                        and irq with a normal IDE disk.
+ *                        Both configurations seemed to work just fine !
+ *                        However, to be on the safe side, it is meanwhile
+ *                        recommended to give the IDE TAPE its own interface
+ *                        and irq.
+ *                       The one thing which needs to be done here is to
+ *                        add a "request postpone" feature to ide.c,
+ *                        so that we won't have to wait for the tape to finish
+ *                        performing a long media access (DSC) request (such
+ *                        as a rewind) before we can access the other device
+ *                        on the same interface. This effect doesn't disturb
+ *                        normal operation most of the time because read/write
+ *                        requests are relatively fast, and once we are
+ *                        performing one tape r/w request, a lot of requests
+ *                        from the other device can be queued and ide.c will
+ *                       service all of them after this single tape request.
+ * Ver 1.0   Dec 11 95   Integrated into Linux 1.3.46 development tree.
+ *                       On each read / write request, we now ask the drive
+ *                        if we can transfer a constant number of bytes
+ *                        (a parameter of the drive) only to its buffers,
+ *                        without causing actual media access. If we can't,
+ *                        we just wait until we can by polling the DSC bit.
+ *                        This ensures that while we are not transferring
+ *                        more bytes than the constant referred to above, the
+ *                        interrupt latency will not become too high and
+ *                        we won't cause an interrupt timeout, as happened
+ *                        occasionally in the previous version.
+ *                       While polling for DSC, the current request is
+ *                        postponed and ide.c is free to handle requests from
+ *                        the other device. This is handled transparently to
+ *                        ide.c. The hwgroup locking method which was used
+ *                        in the previous version was removed.
+ *                       Use of new general features which are provided by
+ *                        ide.c for use with atapi devices.
+ *                        (Programming done by Mark Lord)
+ *                       Few potential bug fixes (Again, suggested by Mark)
+ *                       Single character device data transfers are now
+ *                        not limited in size, as they were before.
+ *                       We are asking the tape about its recommended
+ *                        transfer unit and send a larger data transfer
+ *                        as several transfers of the above size.
+ *                        For best results, use an integral number of this
+ *                        basic unit (which is shown during driver
+ *                        initialization). I will soon add an ioctl to get
+ *                        this important parameter.
+ *                       Our data transfer buffer is allocated on startup,
+ *                        rather than before each data transfer. This should
+ *                        ensure that we will indeed have a data buffer.
+ * Ver 1.1   Dec 14 95   Fixed random problems which occurred when the tape
+ *                        shared an interface with another device.
+ *                        (poll_for_dsc was a complete mess).
+ *                       Removed some old (non-active) code which had
+ *                        to do with supporting buffer cache originated
+ *                        requests.
+ *                       The block device interface can now be opened, so
+ *                        that general ide driver features like the unmask
+ *                        interrupts flag can be selected with an ioctl.
+ *                        This is the only use of the block device interface.
+ *                       New fast pipelined operation mode (currently only on
+ *                        writes). When using the pipelined mode, the
+ *                        throughput can potentially reach the maximum
+ *                        tape supported throughput, regardless of the
+ *                        user backup program. On my tape drive, it sometimes
+ *                        boosted performance by a factor of 2. Pipelined
+ *                        mode is enabled by default, but since it has a few
+ *                        downfalls as well, you may want to disable it.
+ *                        A short explanation of the pipelined operation mode
+ *                        is available below.
+ * Ver 1.2   Jan  1 96   Eliminated pipelined mode race condition.
+ *                       Added pipeline read mode. As a result, restores
+ *                        are now as fast as backups.
+ *                       Optimized shared interface behavior. The new behavior
+ *                        typically results in better IDE bus efficiency and
+ *                        higher tape throughput.
+ *                       Pre-calculation of the expected read/write request
+ *                        service time, based on the tape's parameters. In
+ *                        the pipelined operation mode, this allows us to
+ *                        adjust our polling frequency to a much lower value,
+ *                        and thus to dramatically reduce our load on Linux,
+ *                        without any decrease in performance.
+ *                       Implemented additional mtio.h operations.
+ *                       The recommended user block size is returned by
+ *                        the MTIOCGET ioctl.
+ *                       Additional minor changes.
+ * Ver 1.3   Feb  9 96   Fixed pipelined read mode bug which prevented the
+ *                        use of some block sizes during a restore procedure.
+ *                       The character device interface will now present a
+ *                        continuous view of the media - any mix of block sizes
+ *                        during a backup/restore procedure is supported. The
+ *                        driver will buffer the requests internally and
+ *                        convert them to the tape's recommended transfer
+ *                        unit, making performance almost independent of the
+ *                        chosen user block size.
+ *                       Some improvements in error recovery.
+ *                       By cooperating with ide-dma.c, bus mastering DMA can
+ *                        now sometimes be used with IDE tape drives as well.
+ *                        Bus mastering DMA has the potential to dramatically
+ *                        reduce the CPU's overhead when accessing the device,
+ *                        and can be enabled by using hdparm -d1 on the tape's
+ *                        block device interface. For more info, read the
+ *                        comments in ide-dma.c.
+ * Ver 1.4   Mar 13 96   Fixed serialize support.
+ * Ver 1.5   Apr 12 96   Fixed shared interface operation, broken in 1.3.85.
+ *                       Fixed pipelined read mode inefficiency.
+ *                       Fixed nasty null dereferencing bug.
+ * Ver 1.6   Aug 16 96   Fixed FPU usage in the driver.
+ *                       Fixed end of media bug.
+ * Ver 1.7   Sep 10 96   Minor changes for the CONNER CTT8000-A model.
+ * Ver 1.8   Sep 26 96   Attempt to find a better balance between good
+ *                        interactive response and high system throughput.
+ * Ver 1.9   Nov  5 96   Automatically cross encountered filemarks rather
+ *                        than requiring an explicit FSF command.
+ *                       Abort pending requests at end of media.
+ *                       MTTELL was sometimes returning incorrect results.
+ *                       Return the real block size in the MTIOCGET ioctl.
+ *                       Some error recovery bug fixes.
+ * Ver 1.10  Nov  5 96   Major reorganization.
+ *                       Reduced CPU overhead a bit by eliminating internal
+ *                        bounce buffers.
+ *                       Added module support.
+ *                       Added multiple tape drives support.
+ *                       Added partition support.
+ *                       Rewrote DSC handling.
+ *                       Some portability fixes.
+ *                       Removed ide-tape.h.
+ *                       Additional minor changes.
+ * Ver 1.11  Dec  2 96   Bug fix in previous DSC timeout handling.
+ *                       Use ide_stall_queue() for DSC overlap.
+ *                       Use the maximum speed rather than the current speed
+ *                        to compute the request service time.
+ * Ver 1.12  Dec  7 97   Fix random memory overwriting and/or last block data
+ *                        corruption, which could occur if the total number
+ *                        of bytes written to the tape was not an integral
+ *                        number of tape blocks.
+ *                       Add support for INTERRUPT DRQ devices.
+ * Ver 1.13  Jan  2 98   Add "speed == 0" work-around for HP COLORADO 5GB
+ * Ver 1.14  Dec 30 98   Partial fixes for the Sony/AIWA tape drives.
+ *                       Replace cli()/sti() with hwgroup spinlocks.
+ * Ver 1.15  Mar 25 99   Fix SMP race condition by replacing hwgroup
+ *                        spinlock with private per-tape spinlock.
+ * Ver 1.16  Sep  1 99   Add OnStream tape support.
+ *                       Abort read pipeline on EOD.
+ *                       Wait for the tape to become ready in case it returns
+ *                        "in the process of becoming ready" on open().
+ *                       Fix zero padding of the last written block in
+ *                        case the tape block size is larger than PAGE_SIZE.
+ *                       Decrease the default disconnection time to tn.
+ * Ver 1.16e Oct  3 99   Minor fixes.
+ * Ver 1.16e1 Oct 13 99  Patches by Arnold Niessen,
+ *                          niessen@iae.nl / arnold.niessen@philips.com
+ *                   GO-1)  Undefined code in idetape_read_position
+ *                             according to Gadi's email
+ *                   AJN-1) Minor fix asc == 11 should be asc == 0x11
+ *                               in idetape_issue_packet_command (did effect
+ *                               debugging output only)
+ *                   AJN-2) Added more debugging output, and
+ *                              added ide-tape: where missing. I would also
+ *                             like to add tape->name where possible
+ *                   AJN-3) Added different debug_level's
+ *                              via /proc/ide/hdc/settings
+ *                             "debug_level" determines amount of debugging output;
+ *                             can be changed using /proc/ide/hdx/settings
+ *                             0 : almost no debugging output
+ *                             1 : 0+output errors only
+ *                             2 : 1+output all sensekey/asc
+ *                             3 : 2+follow all chrdev related procedures
+ *                             4 : 3+follow all procedures
+ *                             5 : 4+include pc_stack rq_stack info
+ *                             6 : 5+USE_COUNT updates
+ *                   AJN-4) Fixed timeout for retension in idetape_queue_pc_tail
+ *                             from 5 to 10 minutes
+ *                   AJN-5) Changed maximum number of blocks to skip when
+ *                              reading tapes with multiple consecutive write
+ *                              errors from 100 to 1000 in idetape_get_logical_blk
+ *                   Proposed changes to code:
+ *                   1) output "logical_blk_num" via /proc
+ *                   2) output "current_operation" via /proc
+ *                   3) Either solve or document the fact that `mt rewind' is
+ *                      required after reading from /dev/nhtx to be
+ *                     able to rmmod the idetape module;
+ *                     Also, sometimes an application finishes but the
+ *                     device remains `busy' for some time. Same cause ?
+ *                   Proposed changes to release-notes:
+ *                  4) write a simple `quickstart' section in the
+ *                      release notes; I volunteer if you don't want to
+ *                  5) include a pointer to video4linux in the doc
+ *                      to stimulate video applications
+ *                   6) release notes lines 331 and 362: explain what happens
+ *                     if the application data rate is higher than 1100 KB/s;
+ *                     similar approach to lower-than-500 kB/s ?
+ *                  7) 6.6 Comparison; wouldn't it be better to allow different
+ *                     strategies for read and write ?
+ *                     Wouldn't it be better to control the tape buffer
+ *                     contents instead of the bandwidth ?
+ *                  8) line 536: replace will by would (if I understand
+ *                     this section correctly, a hypothetical and unwanted situation
+ *                      is being described)
+ * Ver 1.16f Dec 15 99   Change place of the secondary OnStream header frames.
+ * Ver 1.17  Nov 2000 / Jan 2001  Marcel Mol, marcel@mesa.nl
+ *                     - Add idetape_onstream_mode_sense_tape_parameter_page
+ *                       function to get tape capacity in frames: tape->capacity.
+ *                     - Add support for DI-50 drives( or any DI- drive).
+ *                     - 'workaround' for read error/blank block around block 3000.
+ *                     - Implement Early warning for end of media for Onstream.
+ *                     - Cosmetic code changes for readability.
+ *                     - Idetape_position_tape should not use SKIP bit during
+ *                       Onstream read recovery.
+ *                     - Add capacity, logical_blk_num and first/last_frame_position
+ *                       to /proc/ide/hd?/settings.
+ *                     - Module use count was gone in the Linux 2.4 driver.
+ * Ver 1.17a Apr 2001 Willem Riede osst@riede.org
+ *                     - Get drive's actual block size from mode sense block descriptor
+ *                     - Limit size of pipeline
+ * Ver 1.17b Oct 2002   Alan Stern <stern@rowland.harvard.edu>
+ *                     Changed IDETAPE_MIN_PIPELINE_STAGES to 1 and actually used
+ *                      it in the code!
+ *                     Actually removed aborted stages in idetape_abort_pipeline
+ *                      instead of just changing the command code.
+ *                     Made the transfer byte count for Request Sense equal to the
+ *                      actual length of the data transfer.
+ *                     Changed handling of partial data transfers: they do not
+ *                      cause DMA errors.
+ *                     Moved initiation of DMA transfers to the correct place.
+ *                     Removed reference to unallocated memory.
+ *                     Made __idetape_discard_read_pipeline return the number of
+ *                      sectors skipped, not the number of stages.
+ *                     Replaced errant kfree() calls with __idetape_kfree_stage().
+ *                     Fixed off-by-one error in testing the pipeline length.
+ *                     Fixed handling of filemarks in the read pipeline.
+ *                     Small code optimization for MTBSF and MTBSFM ioctls.
+ *                     Don't try to unlock the door during device close if is
+ *                      already unlocked!
+ *                     Cosmetic fixes to miscellaneous debugging output messages.
+ *                     Set the minimum /proc/ide/hd?/settings values for "pipeline",
+ *                      "pipeline_min", and "pipeline_max" to 1.
+ */
diff --git a/Documentation/ide/ide-tape.txt b/Documentation/ide/ide-tape.txt
new file mode 100644 (file)
index 0000000..658f271
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+ * IDE ATAPI streaming tape driver.
+ *
+ * This driver is a part of the Linux ide driver.
+ *
+ * The driver, in co-operation with ide.c, basically traverses the
+ * request-list for the block device interface. The character device
+ * interface, on the other hand, creates new requests, adds them
+ * to the request-list of the block device, and waits for their completion.
+ *
+ * Pipelined operation mode is now supported on both reads and writes.
+ *
+ * The block device major and minor numbers are determined from the
+ * tape's relative position in the ide interfaces, as explained in ide.c.
+ *
+ * The character device interface consists of the following devices:
+ *
+ * ht0         major 37, minor 0       first  IDE tape, rewind on close.
+ * ht1         major 37, minor 1       second IDE tape, rewind on close.
+ * ...
+ * nht0                major 37, minor 128     first  IDE tape, no rewind on close.
+ * nht1                major 37, minor 129     second IDE tape, no rewind on close.
+ * ...
+ *
+ * The general magnetic tape commands compatible interface, as defined by
+ * include/linux/mtio.h, is accessible through the character device.
+ *
+ * General ide driver configuration options, such as the interrupt-unmask
+ * flag, can be configured by issuing an ioctl to the block device interface,
+ * as any other ide device.
+ *
+ * Our own ide-tape ioctl's can be issued to either the block device or
+ * the character device interface.
+ *
+ * Maximal throughput with minimal bus load will usually be achieved in the
+ * following scenario:
+ *
+ *     1.      ide-tape is operating in the pipelined operation mode.
+ *     2.      No buffering is performed by the user backup program.
+ *
+ * Testing was done with a 2 GB CONNER CTMA 4000 IDE ATAPI Streaming Tape Drive.
+ *
+ * Here are some words from the first releases of hd.c, which are quoted
+ * in ide.c and apply here as well:
+ *
+ * | Special care is recommended.  Have Fun!
+ *
+ *
+ * An overview of the pipelined operation mode.
+ *
+ * In the pipelined write mode, we will usually just add requests to our
+ * pipeline and return immediately, before we even start to service them. The
+ * user program will then have enough time to prepare the next request while
+ * we are still busy servicing previous requests. In the pipelined read mode,
+ * the situation is similar - we add read-ahead requests into the pipeline,
+ * before the user even requested them.
+ *
+ * The pipeline can be viewed as a "safety net" which will be activated when
+ * the system load is high and prevents the user backup program from keeping up
+ * with the current tape speed. At this point, the pipeline will get
+ * shorter and shorter but the tape will still be streaming at the same speed.
+ * Assuming we have enough pipeline stages, the system load will hopefully
+ * decrease before the pipeline is completely empty, and the backup program
+ * will be able to "catch up" and refill the pipeline again.
+ *
+ * When using the pipelined mode, it would be best to disable any type of
+ * buffering done by the user program, as ide-tape already provides all the
+ * benefits in the kernel, where it can be done in a more efficient way.
+ * As we will usually not block the user program on a request, the most
+ * efficient user code will then be a simple read-write-read-... cycle.
+ * Any additional logic will usually just slow down the backup process.
+ *
+ * Using the pipelined mode, I get a constant over 400 KBps throughput,
+ * which seems to be the maximum throughput supported by my tape.
+ *
+ * However, there are some downfalls:
+ *
+ *     1.      We use memory (for data buffers) in proportional to the number
+ *             of pipeline stages (each stage is about 26 KB with my tape).
+ *     2.      In the pipelined write mode, we cheat and postpone error codes
+ *             to the user task. In read mode, the actual tape position
+ *             will be a bit further than the last requested block.
+ *
+ * Concerning (1):
+ *
+ *     1.      We allocate stages dynamically only when we need them. When
+ *             we don't need them, we don't consume additional memory. In
+ *             case we can't allocate stages, we just manage without them
+ *             (at the expense of decreased throughput) so when Linux is
+ *             tight in memory, we will not pose additional difficulties.
+ *
+ *     2.      The maximum number of stages (which is, in fact, the maximum
+ *             amount of memory) which we allocate is limited by the compile
+ *             time parameter IDETAPE_MAX_PIPELINE_STAGES.
+ *
+ *     3.      The maximum number of stages is a controlled parameter - We
+ *             don't start from the user defined maximum number of stages
+ *             but from the lower IDETAPE_MIN_PIPELINE_STAGES (again, we
+ *             will not even allocate this amount of stages if the user
+ *             program can't handle the speed). We then implement a feedback
+ *             loop which checks if the pipeline is empty, and if it is, we
+ *             increase the maximum number of stages as necessary until we
+ *             reach the optimum value which just manages to keep the tape
+ *             busy with minimum allocated memory or until we reach
+ *             IDETAPE_MAX_PIPELINE_STAGES.
+ *
+ * Concerning (2):
+ *
+ *     In pipelined write mode, ide-tape can not return accurate error codes
+ *     to the user program since we usually just add the request to the
+ *      pipeline without waiting for it to be serviced. In case an error
+ *      occurs, I will report it on the next user request.
+ *
+ *     In the pipelined read mode, subsequent read requests or forward
+ *     filemark spacing will perform correctly, as we preserve all blocks
+ *     and filemarks which we encountered during our excess read-ahead.
+ *
+ *     For accurate tape positioning and error reporting, disabling
+ *     pipelined mode might be the best option.
+ *
+ * You can enable/disable/tune the pipelined operation mode by adjusting
+ * the compile time parameters below.
+ *
+ *
+ *     Possible improvements.
+ *
+ *     1.      Support for the ATAPI overlap protocol.
+ *
+ *             In order to maximize bus throughput, we currently use the DSC
+ *             overlap method which enables ide.c to service requests from the
+ *             other device while the tape is busy executing a command. The
+ *             DSC overlap method involves polling the tape's status register
+ *             for the DSC bit, and servicing the other device while the tape
+ *             isn't ready.
+ *
+ *             In the current QIC development standard (December 1995),
+ *             it is recommended that new tape drives will *in addition*
+ *             implement the ATAPI overlap protocol, which is used for the
+ *             same purpose - efficient use of the IDE bus, but is interrupt
+ *             driven and thus has much less CPU overhead.
+ *
+ *             ATAPI overlap is likely to be supported in most new ATAPI
+ *             devices, including new ATAPI cdroms, and thus provides us
+ *             a method by which we can achieve higher throughput when
+ *             sharing a (fast) ATA-2 disk with any (slow) new ATAPI device.
+ */
index 74f68b35f7c161d0e6efe9a0822a8e45e6f49b49..1ba84f3584e3022e952647ce7420894f01d8349e 100644 (file)
@@ -85,7 +85,7 @@ involve special block devices or loopbacks; you merely create a directory on
 disk with the desired initrd content, cd to that directory, and run (as an
 example):
 
-find . | cpio --quiet -c -o | gzip -9 -n > /boot/imagefile.img
+find . | cpio --quiet -H newc -o | gzip -9 -n > /boot/imagefile.img
 
 Examining the contents of an existing image file is just as simple:
 
diff --git a/Documentation/ja_JP/stable_kernel_rules.txt b/Documentation/ja_JP/stable_kernel_rules.txt
new file mode 100644 (file)
index 0000000..17d8751
--- /dev/null
@@ -0,0 +1,79 @@
+NOTE:
+This is Japanese translated version of "Documentation/stable_kernel_rules.txt".
+This one is maintained by Tsugikazu Shibata <tshibata@ab.jp.nec.com>
+and JF Project team <www.linux.or.jp/JF>.
+If you find difference with original file or problem in translation,
+please contact maintainer of this file or JF project.
+
+Please also note that purpose of this file is easier to read for non
+English natives and do no intended to fork. So, if you have any
+comment or update of this file, please try to update Original(English)
+file at first.
+
+==================================
+ã\81\93ã\82\8cã\81¯ã\80\81
+linux-2.6.24/Documentation/stable_kernel_rules.txt
+ã\81®å\92\8c訳ã\81§ã\81\99ã\80\82
+
+翻訳å\9b£ä½\93ï¼\9a JF Ã£\83\97ã\83­ã\82¸ã\82§ã\82¯ã\83\88 < http://www.linux.or.jp/JF/ >
+翻訳æ\97¥ï¼\9a 2007/12/30
+翻訳è\80\85ï¼\9a Tsugikazu Shibata <tshibata at ab dot jp dot nec dot com>
+æ ¡æ­£è\80\85ï¼\9a Ã¦Â­Â¦Ã¤Âº\95伸å\85\89ã\81\95ã\82\93ã\80\81<takei at webmasters dot gr dot jp>
+         Ã£\81\8bã\81­ã\81\93ã\81\95ã\82\93 (Seiji Kaneko) <skaneko at a2 dot mbn dot or dot jp>
+         Ã¥Â°\8fæ\9e\97 Ã©\9b\85Ã¥\85¸ã\81\95ã\82\93 (Masanori Kobayasi) <zap03216 at nifty dot ne dot jp>
+         Ã©\87\8eÃ¥\8f£ã\81\95ã\82\93 (Kenji Noguchi) <tokyo246 at gmail dot com>
+         Ã§Â¥\9e宮信太é\83\8eã\81\95ã\82\93 <jin at libjingu dot jp>
+==================================
+
+ã\81\9aã\81£ã\81¨ç\9f¥ã\82\8aã\81\9fã\81\8bã\81£ã\81\9f Linux 2.6 -stable Ã£\83ªã\83ªã\83¼ã\82¹ã\81®å\85¨ã\81¦
+
+"-stable" Ã£\83\84ã\83ªã\83¼ã\81«ã\81©ã\81®ã\82\88ã\81\86ã\81ªç¨®é¡\9eã\81®ã\83\91ã\83\83ã\83\81ã\81\8cÃ¥\8f\97ã\81\91Ã¥\85¥ã\82\8cã\82\89ã\82\8cã\82\8bã\81\8bã\80\81ã\81©ã\81®ã\82\88ã\81\86ã\81ª
+ã\82\82ã\81®ã\81\8cå\8f\97ã\81\91å\85¥ã\82\8cã\82\89ã\82\8cã\81ªã\81\84ã\81\8bã\80\81ã\81«ã\81¤ã\81\84ã\81¦ã\81®è¦\8få\89\87-
+
+ - Ã¦\98\8eã\82\89ã\81\8bã\81«æ­£ã\81\97ã\81\8fã\80\81ã\83\86ã\82¹ã\83\88ã\81\95ã\82\8cã\81¦ã\81\84ã\82\8bã\82\82ã\81®ã\81§ã\81ªã\81\91ã\82\8cã\81°ã\81ªã\82\89ã\81ªã\81\84ã\80\82
+ - Ã¦\96\87è\84\88(å¤\89æ\9b´è¡\8cã\81®å\89\8då¾\8c)ã\82\92Ã¥\90«ã\82\81ã\81¦ 100 Ã¨Â¡\8cã\82\88ã\82\8a大ã\81\8dã\81\8fã\81¦ã\81¯ã\81\84ã\81\91ã\81ªã\81\84ã\80\82
+ - Ã£\81\9fã\81 ä¸\80Ã¥\80\8bã\81®ã\81\93ã\81¨ã\81 ã\81\91ã\82\92修正ã\81\97ã\81¦ã\81\84ã\82\8bã\81¹ã\81\8dã\80\82
+ - Ã§\9a\86ã\82\92æ\82©ã\81¾ã\81\9bã\81¦ã\81\84ã\82\8bæ\9c\89©ã\81®ã\83\90ã\82°ã\82\92修正ã\81\97ã\81ªã\81\91ã\82\8cã\81°ã\81ªã\82\89ã\81ªã\81\84ã\80\82("ã\81\93ã\82\8cã\81¯ã\83\90ã\82°ã\81§
+   Ã£\81\82ã\82\8bã\81\8bã\82\82ã\81\97ã\82\8cã\81ªã\81\84ã\81\8c..." Ã£\81®ã\82\88ã\81\86ã\81ªã\82\82ã\81®ã\81§ã\81¯ã\81ªã\81\84)
+ - Ã£\83\93ã\83«ã\83\89ã\82¨ã\83©ã\83¼(CONFIG_BROKENã\81«ã\81ªã\81£ã\81¦ã\81\84ã\82\8bã\82\82ã\81®ã\82\92é\99¤ã\81\8f), oops, Ã£\83\8fã\83³ã\82°ã\80\81ã\83\87ã\83¼
+   Ã£\82¿ç ´å£\8aã\80\81ç\8f¾å®\9fã\81®ã\82ȋ\82­ã\83¥ã\83ªã\83\86ã\82£å\95\8fé¡\8cã\80\81ã\81\9dã\81®ä»\96 "ã\81\82ã\81\82ã\80\81ã\81\93ã\82\8cã\81¯ã\83\80ã\83¡ã\81 ã\81­"ã\81¨ã\81\84ã\81\86
+   Ã£\82\88ã\81\86ã\81ªã\82\82ã\81®ã\82\92修正ã\81\97ã\81ªã\81\91ã\82\8cã\81°ã\81ªã\82\89ã\81ªã\81\84ã\80\82ç\9f­ã\81\8fè¨\80ã\81\88ã\81°ã\80\81é\87\8d大ã\81ªå\95\8fé¡\8cã\80\82
+ - Ã£\81©ã\81®ã\82\88ã\81\86ã\81«ç«¶å\90\88ç\8a¶æ\85\8bã\81\8cç\99ºç\94\9fã\81\99ã\82\8bã\81\8bã\81®èª¬æ\98\8eã\82\82ä¸\80ç·\92ã\81«æ\9b¸ã\81\8bã\82\8cã\81¦ã\81\84ã\81ªã\81\84é\99\90ã\82\8aã\80\81
+   "ç\90\86è«\96ç\9a\84ã\81«ã\81¯ç«¶å\90\88ç\8a¶æ\85\8bã\81«ã\81ªã\82\8b"ã\82\88ã\81\86ã\81ªã\82\82ã\81®ã\81¯ä¸\8dÃ¥\8f¯ã\80\82
+ - Ã£\81\84ã\81\8bã\81ªã\82\8bäº\9bç´°ã\81ªä¿®æ­£ã\82\82Ã¥\90«ã\82\81ã\82\8bã\81\93ã\81¨ã\81¯ã\81§ã\81\8dã\81ªã\81\84ã\80\82(ã\82¹ã\83\9aã\83«ã\81®ä¿®æ­£ã\80\81空ç\99½ã\81®ã\82¯ã\83ªã\83¼
+   Ã£\83³ã\82¢ã\83\83ã\83\97ã\81ªã\81©)
+ - Ã¥Â¯Â¾Ã¥Â¿\9cã\81\99ã\82\8bã\82µã\83\96ã\82·ã\82¹ã\83\86ã\83 ã\83¡ã\83³ã\83\86ã\83\8aã\81\8cÃ¥\8f\97ã\81\91Ã¥\85¥ã\82\8cã\81\9fã\82\82ã\81®ã\81§ã\81ªã\81\91ã\82\8cã\81°ã\81ªã\82\89ã\81ªã\81\84ã\80\82
+ - Documentation/SubmittingPatches Ã£\81®è¦\8fÃ¥\89\87ã\81«å¾\93ã\81£ã\81\9fã\82\82ã\81®ã\81§ã\81ªã\81\91ã\82\8cã\81°ã\81ªã\82\89ã\81ªã\81\84ã\80\82
+
+-stable Ã£\83\84ã\83ªã\83¼ã\81«ã\83\91ã\83\83ã\83\81ã\82\92é\80\81ä»\98ã\81\99ã\82\8bæ\89\8bç¶\9aã\81\8d-
+
+ - Ã¤Â¸\8aè¨\98ã\81®è¦\8fÃ¥\89\87ã\81«å¾\93ã\81£ã\81¦ã\81\84ã\82\8bã\81\8bã\82\92確èª\8dã\81\97ã\81\9få¾\8cã\81«ã\80\81stable@kernel.org Ã£\81«ã\83\91ã\83\83ã\83\81
+   Ã£\82\92é\80\81ã\82\8bã\80\82
+ - Ã©\80\81ä¿¡è\80\85ã\81¯ã\83\91ã\83\83ã\83\81ã\81\8cã\82­ã\83¥ã\83¼ã\81«å\8f\97ã\81\91ä»\98ã\81\91ã\82\89ã\82\8cã\81\9fé\9a\9bã\81«ã\81¯ ACK Ã£\82\92ã\80\81Ã¥\8d´ä¸\8bã\81\95ã\82\8cã\81\9få ´å\90\88
+   Ã£\81«ã\81¯ NAK Ã£\82\92Ã¥\8f\97ã\81\91Ã¥\8f\96ã\82\8bã\80\82ã\81\93ã\81®å\8f\8då¿\9cã\81¯é\96\8bç\99ºè\80\85ã\81\9fã\81¡ã\81®ã\82¹ã\82±ã\82¸ã\83¥ã\83¼ã\83«ã\81«ã\82\88ã\81£ã\81¦ã\80\81æ\95°
+   Ã¦\97¥ã\81\8bã\81\8bã\82\8bå ´å\90\88ã\81\8cã\81\82ã\82\8bã\80\82
+ - Ã£\82\82ã\81\97Ã¥\8f\97ã\81\91Ã¥\8f\96ã\82\89ã\82\8cã\81\9fã\82\89ã\80\81ã\83\91ã\83\83ã\83\81ã\81¯ä»\96ã\81®é\96\8bç\99ºè\80\85ã\81\9fã\81¡ã\81®ã\83‹\83\93ã\83¥ã\83¼ã\81®ã\81\9fã\82\81ã\81«
+   -stable Ã£\82­ã\83¥ã\83¼ã\81«è¿½å\8a ã\81\95ã\82\8cã\82\8bã\80\82
+ - Ã£\82ȋ\82­ã\83¥ã\83ªã\83\86ã\82£ã\83\91ã\83\83ã\83\81ã\81¯ã\81\93ã\81®ã\82¨ã\82¤ã\83ªã\82¢ã\82¹ (stable@kernel.org) Ã£\81«é\80\81ã\82\89ã\82\8cã\82\8bã\81¹
+   Ã£\81\8dã\81§ã\81¯ã\81ªã\81\8fã\80\81代ã\82\8fã\82\8aã\81« security@kernel.org Ã£\81®ã\82¢ã\83\89ã\83‹\82¹ã\81«é\80\81ã\82\89ã\82\8cã\82\8bã\80\82
+
+ã\83¬ã\83\93ã\83¥ã\83¼ã\82µã\82¤ã\82¯ã\83«-
+
+ - -stable Ã£\83¡ã\83³ã\83\86ã\83\8aã\81\8cã\83‹\83\93ã\83¥ã\83¼ã\82µã\82¤ã\82¯ã\83«ã\82\92決ã\82\81ã\82\8bã\81¨ã\81\8dã\80\81ã\83\91ã\83\83ã\83\81ã\81¯ã\83‹\83\93ã\83¥ã\83¼å§\94
+   Ã¥\93¡ä¼\9aã\81¨ã\83\91ã\83\83ã\83\81ã\81\8cå½±é\9f¿ã\81\99ã\82\8bé \98Ã¥\9f\9fã\81®ã\83¡ã\83³ã\83\86ã\83\8a(æ\8f\90ä¾\9bè\80\85ã\81\8cã\81\9dã\81®é \98Ã¥\9f\9fã\81®ã\83¡ã\83³ã\83\86ã\83\8aã\81§ç\84¡
+   Ã£\81\84é\99\90ã\82\8a)ã\81«é\80\81ã\82\89ã\82\8cã\80\81linux-kernel Ã£\83¡ã\83¼ã\83ªã\83³ã\82°ã\83ªã\82¹ã\83\88ã\81«CCã\81\95ã\82\8cã\82\8bã\80\82
+ - Ã£\83‹\83\93ã\83¥ã\83¼å§\94Ã¥\93¡ä¼\9aã\81¯ 48æ\99\82é\96\93ã\81®é\96\93ã\81« ACK Ã£\81\8b NAK Ã£\82\92Ã¥\87ºã\81\99ã\80\82
+ - Ã£\82\82ã\81\97ã\83\91ã\83\83ã\83\81ã\81\8cå§\94Ã¥\93¡ä¼\9aã\81®ã\83¡ã\83³ã\83\90ã\81\8bã\82\89Ã¥\8d´ä¸\8bã\82\8cã\82\8bã\81\8bã\80\81ã\83¡ã\83³ã\83\86ã\83\8aé\81\94ã\82\84ã\83¡ã\83³ã\83\90ã\81\8cæ°\97ä»\98
+   Ã£\81\8bã\81ªã\81\8bã\81£ã\81\9fÃ¥\95\8fé¡\8cã\81\8cæ\8c\81ã\81¡ã\81\82ã\81\8cã\82\8aã\80\81linux-kernel Ã£\83¡ã\83³ã\83\90ã\81\8cã\83\91ã\83\83ã\83\81ã\81«ç\95°è­°ã\82\92Ã¥\94±ã\81\88
+   Ã£\81\9få ´å\90\88ã\81«ã\81¯ã\80\81ã\83\91ã\83\83ã\83\81ã\81¯ã\82­ã\83¥ã\83¼ã\81\8bã\82\89Ã¥\89\8aé\99¤ã\81\95ã\82\8cã\82\8bã\80\82
+ - Ã£\83‹\83\93ã\83¥ã\83¼ã\82µã\82¤ã\82¯ã\83«ã\81®æ\9c\80å¾\8cã\81«ã\80\81ACK Ã£\82\92Ã¥\8f\97ã\81\91ã\81\9fã\83\91ã\83\83ã\83\81ã\81¯æ\9c\80æ\96°ã\81® -stable Ã£\83ªã\83ªã\83¼
+   Ã£\82¹ã\81«è¿½å\8a ã\81\95ã\82\8cã\80\81ã\81\9dã\81®å¾\8cã\81«æ\96°ã\81\97ã\81\84 -stable Ã£\83ªã\83ªã\83¼ã\82¹ã\81\8cè¡\8cã\82\8fã\82\8cã\82\8bã\80\82
+ - Ã£\82ȋ\82­ã\83¥ã\83ªã\83\86ã\82£ã\83\91ã\83\83ã\83\81ã\81¯ã\80\81é\80\9a常ã\81®ã\83‹\83\93ã\83¥ã\83¼ã\82µã\82¤ã\82¯ã\83«ã\82\92é\80\9aã\82\89ã\81\9aã\80\81ã\82ȋ\82­ã\83¥ã\83ªã\83\86ã\82£
+   Ã£\82«ã\83¼ã\83\8dã\83«ã\83\81ã\83¼ã\83 ã\81\8bã\82\89ç\9b´æ\8eÂ¥ -stable Ã£\83\84ã\83ªã\83¼ã\81«å\8f\97ã\81\91ä»\98ã\81\91ã\82\89ã\82\8cã\82\8bã\80\82
+   Ã£\81\93ã\81®æ\89\8bç¶\9aã\81\8dã\81®è©³ç´°ã\81«ã\81¤ã\81\84ã\81¦ã\81¯ kernel security Ã£\83\81ã\83¼ã\83 ã\81«å\95\8fã\81\84Ã¥\90\88ã\82\8fã\81\9bã\82\8bã\81\93ã\81¨ã\80\82
+
+ã\83¬ã\83\93ã\83¥ã\83¼å§\94å\93¡ä¼\9a-
+
+ - Ã£\81\93ã\81®å§\94Ã¥\93¡ä¼\9aã\81¯ã\80\81ã\81\93ã\81®ã\82¿ã\82¹ã\82¯ã\81«ã\81¤ã\81\84ã\81¦æ´»å\8b\95ã\81\99ã\82\8bå¤\9aã\81\8fã\81®ã\83\9cã\83©ã\83³ã\83\86ã\82£ã\82¢ã\81¨ã\80\81å°\91æ\95°ã\81®
+   Ã©\9d\9eã\83\9cã\83©ã\83³ã\83\86ã\82£ã\82¢ã\81®ã\82«ã\83¼ã\83\8dã\83«é\96\8bç\99ºè\80\85é\81\94ã\81§æ§\8bæ\88\90ã\81\95ã\82\8cã\81¦ã\81\84ã\82\8bã\80\82
+
index 92c40d174355505555642cbe3a0ea137881dcbd4..8fd5aa40585ff8419cc730104079ddd61b5ccb8e 100644 (file)
@@ -168,6 +168,11 @@ and is between 256 and 4096 characters. It is defined in the file
        acpi_irq_isa=   [HW,ACPI] If irq_balance, mark listed IRQs used by ISA
                        Format: <irq>,<irq>...
 
+       acpi_new_pts_ordering [HW,ACPI]
+                       Enforce the ACPI 2.0 ordering of the _PTS control
+                       method wrt putting devices into low power states
+                       default: pre ACPI 2.0 ordering of _PTS
+
        acpi_no_auto_ssdt       [HW,ACPI] Disable automatic loading of SSDT
 
        acpi_os_name=   [HW,ACPI] Tell ACPI BIOS the name of the OS
@@ -544,7 +549,7 @@ and is between 256 and 4096 characters. It is defined in the file
                        1 will print _a lot_ more information - normally
                        only useful to kernel developers.
 
-       decnet=         [HW,NET]
+       decnet.addr=    [HW,NET]
                        Format: <area>[,<node>]
                        See also Documentation/networking/decnet.txt.
 
@@ -775,6 +780,9 @@ and is between 256 and 4096 characters. It is defined in the file
                        loop use the MONITOR/MWAIT idle loop anyways. Performance should be the same
                        as idle=poll.
 
+       ide-pci-generic.all-generic-ide [HW] (E)IDE subsystem
+                       Claim all unknown PCI IDE storage controllers.
+
        ignore_loglevel [KNL]
                        Ignore loglevel setting - this will print /all/
                        kernel messages to the console. Useful for debugging.
@@ -1556,14 +1564,17 @@ and is between 256 and 4096 characters. It is defined in the file
        ramdisk_size=   [RAM] Sizes of RAM disks in kilobytes
                        See Documentation/ramdisk.txt.
 
-       rcu.blimit=     [KNL,BOOT] Set maximum number of finished
-                       RCU callbacks to process in one batch.
+       rcupdate.blimit=        [KNL,BOOT]
+                       Set maximum number of finished RCU callbacks to process
+                       in one batch.
 
-       rcu.qhimark=    [KNL,BOOT] Set threshold of queued
+       rcupdate.qhimark=       [KNL,BOOT]
+                       Set threshold of queued
                        RCU callbacks over which batch limiting is disabled.
 
-       rcu.qlowmark=   [KNL,BOOT] Set threshold of queued
-                       RCU callbacks below which batch limiting is re-enabled.
+       rcupdate.qlowmark=      [KNL,BOOT]
+                       Set threshold of queued RCU callbacks below which
+                       batch limiting is re-enabled.
 
        rdinit=         [KNL]
                        Format: <full_path>
@@ -1883,9 +1894,6 @@ and is between 256 and 4096 characters. It is defined in the file
        st=             [HW,SCSI] SCSI tape parameters (buffers, etc.)
                        See Documentation/scsi/st.txt.
 
-       st0x=           [HW,SCSI]
-                       See header of drivers/scsi/seagate.c.
-
        sti=            [PARISC,HW]
                        Format: <num>
                        Set the STI (builtin display/keyboard on the HP-PARISC
@@ -1970,9 +1978,6 @@ and is between 256 and 4096 characters. It is defined in the file
        tipar.delay=    [HW,PPT]
                        Set inter-bit delay in microseconds (default 10).
 
-       tmc8xx=         [HW,SCSI]
-                       See header of drivers/scsi/seagate.c.
-
        tmscsim=        [HW,SCSI]
                        See comment before function dc390_setup() in
                        drivers/scsi/tmscsim.c.
index 6c8a2386cd50d150fb58844324c40fbb8685bb8c..0f23d67f958ff5b6ee96a0248fdd2c9b9ab65586 100644 (file)
@@ -34,6 +34,8 @@
 #include <zlib.h>
 #include <assert.h>
 #include <sched.h>
+#include <limits.h>
+#include <stddef.h>
 #include "linux/lguest_launcher.h"
 #include "linux/virtio_config.h"
 #include "linux/virtio_net.h"
@@ -99,13 +101,11 @@ struct device_list
        /* The descriptor page for the devices. */
        u8 *descpage;
 
-       /* The tail of the last descriptor. */
-       unsigned int desc_used;
-
        /* A single linked list of devices. */
        struct device *dev;
-       /* ... And an end pointer so we can easily append new devices */
-       struct device **lastdev;
+       /* And a pointer to the last device for easy append and also for
+        * configuration appending. */
+       struct device *lastdev;
 };
 
 /* The list of Guest devices, based on command line arguments. */
@@ -191,7 +191,14 @@ static void *_convert(struct iovec *iov, size_t size, size_t align,
 #define cpu_to_le64(v64) (v64)
 #define le16_to_cpu(v16) (v16)
 #define le32_to_cpu(v32) (v32)
-#define le64_to_cpu(v32) (v64)
+#define le64_to_cpu(v64) (v64)
+
+/* The device virtqueue descriptors are followed by feature bitmasks. */
+static u8 *get_feature_bits(struct device *dev)
+{
+       return (u8 *)(dev->desc + 1)
+               + dev->desc->num_vq * sizeof(struct lguest_vqconfig);
+}
 
 /*L:100 The Launcher code itself takes us out into userspace, that scary place
  * where pointers run wild and free!  Unfortunately, like most userspace
@@ -914,21 +921,58 @@ static void enable_fd(int fd, struct virtqueue *vq)
        write(waker_fd, &vq->dev->fd, sizeof(vq->dev->fd));
 }
 
+/* Resetting a device is fairly easy. */
+static void reset_device(struct device *dev)
+{
+       struct virtqueue *vq;
+
+       verbose("Resetting device %s\n", dev->name);
+       /* Clear the status. */
+       dev->desc->status = 0;
+
+       /* Clear any features they've acked. */
+       memset(get_feature_bits(dev) + dev->desc->feature_len, 0,
+              dev->desc->feature_len);
+
+       /* Zero out the virtqueues. */
+       for (vq = dev->vq; vq; vq = vq->next) {
+               memset(vq->vring.desc, 0,
+                      vring_size(vq->config.num, getpagesize()));
+               vq->last_avail_idx = 0;
+       }
+}
+
 /* This is the generic routine we call when the Guest uses LHCALL_NOTIFY. */
 static void handle_output(int fd, unsigned long addr)
 {
        struct device *i;
        struct virtqueue *vq;
 
-       /* Check each virtqueue. */
+       /* Check each device and virtqueue. */
        for (i = devices.dev; i; i = i->next) {
+               /* Notifications to device descriptors reset the device. */
+               if (from_guest_phys(addr) == i->desc) {
+                       reset_device(i);
+                       return;
+               }
+
+               /* Notifications to virtqueues mean output has occurred. */
                for (vq = i->vq; vq; vq = vq->next) {
-                       if (vq->config.pfn == addr/getpagesize()
-                           && vq->handle_output) {
-                               verbose("Output to %s\n", vq->dev->name);
-                               vq->handle_output(fd, vq);
+                       if (vq->config.pfn != addr/getpagesize())
+                               continue;
+
+                       /* Guest should acknowledge (and set features!)  before
+                        * using the device. */
+                       if (i->desc->status == 0) {
+                               warnx("%s gave early output", i->name);
                                return;
                        }
+
+                       if (strcmp(vq->dev->name, "console") != 0)
+                               verbose("Output to %s\n", vq->dev->name);
+                       if (vq->handle_output)
+                               vq->handle_output(fd, vq);
+                       return;
                }
        }
 
@@ -986,54 +1030,44 @@ static void handle_input(int fd)
  *
  * All devices need a descriptor so the Guest knows it exists, and a "struct
  * device" so the Launcher can keep track of it.  We have common helper
- * routines to allocate them.
- *
- * This routine allocates a new "struct lguest_device_desc" from descriptor
- * table just above the Guest's normal memory.  It returns a pointer to that
- * descriptor. */
-static struct lguest_device_desc *new_dev_desc(u16 type)
-{
-       struct lguest_device_desc *d;
+ * routines to allocate and manage them. */
 
-       /* We only have one page for all the descriptors. */
-       if (devices.desc_used + sizeof(*d) > getpagesize())
-               errx(1, "Too many devices");
-
-       /* We don't need to set config_len or status: page is 0 already. */
-       d = (void *)devices.descpage + devices.desc_used;
-       d->type = type;
-       devices.desc_used += sizeof(*d);
-
-       return d;
+/* The layout of the device page is a "struct lguest_device_desc" followed by a
+ * number of virtqueue descriptors, then two sets of feature bits, then an
+ * array of configuration bytes.  This routine returns the configuration
+ * pointer. */
+static u8 *device_config(const struct device *dev)
+{
+       return (void *)(dev->desc + 1)
+               + dev->desc->num_vq * sizeof(struct lguest_vqconfig)
+               + dev->desc->feature_len * 2;
 }
 
-/* Each device descriptor is followed by some configuration information.
- * Each configuration field looks like: u8 type, u8 len, [... len bytes...].
- *
- * This routine adds a new field to an existing device's descriptor.  It only
- * works for the last device, but that's OK because that's how we use it. */
-static void add_desc_field(struct device *dev, u8 type, u8 len, const void *c)
+/* This routine allocates a new "struct lguest_device_desc" from descriptor
+ * table page just above the Guest's normal memory.  It returns a pointer to
+ * that descriptor. */
+static struct lguest_device_desc *new_dev_desc(u16 type)
 {
-       /* This is the last descriptor, right? */
-       assert(devices.descpage + devices.desc_used
-              == (u8 *)(dev->desc + 1) + dev->desc->config_len);
+       struct lguest_device_desc d = { .type = type };
+       void *p;
 
-       /* We only have one page of device descriptions. */
-       if (devices.desc_used + 2 + len > getpagesize())
-               errx(1, "Too many devices");
+       /* Figure out where the next device config is, based on the last one. */
+       if (devices.lastdev)
+               p = device_config(devices.lastdev)
+                       + devices.lastdev->desc->config_len;
+       else
+               p = devices.descpage;
 
-       /* Copy in the new config header: type then length. */
-       devices.descpage[devices.desc_used++] = type;
-       devices.descpage[devices.desc_used++] = len;
-       memcpy(devices.descpage + devices.desc_used, c, len);
-       devices.desc_used += len;
+       /* We only have one page for all the descriptors. */
+       if (p + sizeof(d) > (void *)devices.descpage + getpagesize())
+               errx(1, "Too many devices");
 
-       /* Update the device descriptor length: two byte head then data. */
-       dev->desc->config_len += 2 + len;
+       /* p might not be aligned, so we memcpy in. */
+       return memcpy(p, &d, sizeof(d));
 }
 
-/* This routine adds a virtqueue to a device.  We specify how many descriptors
- * the virtqueue is to have. */
+/* Each device descriptor is followed by the description of its virtqueues.  We
+ * specify how many descriptors the virtqueue is to have. */
 static void add_virtqueue(struct device *dev, unsigned int num_descs,
                          void (*handle_output)(int fd, struct virtqueue *me))
 {
@@ -1059,9 +1093,15 @@ static void add_virtqueue(struct device *dev, unsigned int num_descs,
        /* Initialize the vring. */
        vring_init(&vq->vring, num_descs, p, getpagesize());
 
-       /* Add the configuration information to this device's descriptor. */
-       add_desc_field(dev, VIRTIO_CONFIG_F_VIRTQUEUE,
-                      sizeof(vq->config), &vq->config);
+       /* Append virtqueue to this device's descriptor.  We use
+        * device_config() to get the end of the device's current virtqueues;
+        * we check that we haven't added any config or feature information
+        * yet, otherwise we'd be overwriting them. */
+       assert(dev->desc->config_len == 0 && dev->desc->feature_len == 0);
+       memcpy(device_config(dev), &vq->config, sizeof(vq->config));
+       dev->desc->num_vq++;
+
+       verbose("Virtqueue page %#lx\n", to_guest_phys(p));
 
        /* Add to tail of list, so dev->vq is first vq, dev->vq->next is
         * second.  */
@@ -1072,11 +1112,41 @@ static void add_virtqueue(struct device *dev, unsigned int num_descs,
         * virtqueue. */
        vq->handle_output = handle_output;
 
-       /* Set the "Don't Notify Me" flag if we don't have a handler */
+       /* As an optimization, set the advisory "Don't Notify Me" flag if we
+        * don't have a handler */
        if (!handle_output)
                vq->vring.used->flags = VRING_USED_F_NO_NOTIFY;
 }
 
+/* The first half of the feature bitmask is for us to advertise features.  The
+ * second half if for the Guest to accept features. */
+static void add_feature(struct device *dev, unsigned bit)
+{
+       u8 *features = get_feature_bits(dev);
+
+       /* We can't extend the feature bits once we've added config bytes */
+       if (dev->desc->feature_len <= bit / CHAR_BIT) {
+               assert(dev->desc->config_len == 0);
+               dev->desc->feature_len = (bit / CHAR_BIT) + 1;
+       }
+
+       features[bit / CHAR_BIT] |= (1 << (bit % CHAR_BIT));
+}
+
+/* This routine sets the configuration fields for an existing device's
+ * descriptor.  It only works for the last device, but that's OK because that's
+ * how we use it. */
+static void set_config(struct device *dev, unsigned len, const void *conf)
+{
+       /* Check we haven't overflowed our single page. */
+       if (device_config(dev) + len > devices.descpage + getpagesize())
+               errx(1, "Too many devices");
+
+       /* Copy in the config information, and store the length. */
+       memcpy(device_config(dev), conf, len);
+       dev->desc->config_len = len;
+}
+
 /* This routine does all the creation and setup of a new device, including
  * calling new_dev_desc() to allocate the descriptor and device memory. */
 static struct device *new_device(const char *name, u16 type, int fd,
@@ -1084,14 +1154,6 @@ static struct device *new_device(const char *name, u16 type, int fd,
 {
        struct device *dev = malloc(sizeof(*dev));
 
-       /* Append to device list.  Prepending to a single-linked list is
-        * easier, but the user expects the devices to be arranged on the bus
-        * in command-line order.  The first network device on the command line
-        * is eth0, the first block device /dev/vda, etc. */
-       *devices.lastdev = dev;
-       dev->next = NULL;
-       devices.lastdev = &dev->next;
-
        /* Now we populate the fields one at a time. */
        dev->fd = fd;
        /* If we have an input handler for this file descriptor, then we add it
@@ -1102,6 +1164,17 @@ static struct device *new_device(const char *name, u16 type, int fd,
        dev->handle_input = handle_input;
        dev->name = name;
        dev->vq = NULL;
+
+       /* Append to device list.  Prepending to a single-linked list is
+        * easier, but the user expects the devices to be arranged on the bus
+        * in command-line order.  The first network device on the command line
+        * is eth0, the first block device /dev/vda, etc. */
+       if (devices.lastdev)
+               devices.lastdev->next = dev;
+       else
+               devices.dev = dev;
+       devices.lastdev = dev;
+
        return dev;
 }
 
@@ -1226,7 +1299,7 @@ static void setup_tun_net(const char *arg)
        int netfd, ipfd;
        u32 ip;
        const char *br_name = NULL;
-       u8 hwaddr[6];
+       struct virtio_net_config conf;
 
        /* We open the /dev/net/tun device and tell it we want a tap device.  A
         * tap device is like a tun device, only somehow different.  To tell
@@ -1265,12 +1338,13 @@ static void setup_tun_net(const char *arg)
                ip = str2ip(arg);
 
        /* Set up the tun device, and get the mac address for the interface. */
-       configure_device(ipfd, ifr.ifr_name, ip, hwaddr);
+       configure_device(ipfd, ifr.ifr_name, ip, conf.mac);
 
        /* Tell Guest what MAC address to use. */
-       add_desc_field(dev, VIRTIO_CONFIG_NET_MAC_F, sizeof(hwaddr), hwaddr);
+       add_feature(dev, VIRTIO_NET_F_MAC);
+       set_config(dev, sizeof(conf), &conf);
 
-       /* We don't seed the socket any more; setup is done. */
+       /* We don't need the socket any more; setup is done. */
        close(ipfd);
 
        verbose("device %u: tun net %u.%u.%u.%u\n",
@@ -1458,8 +1532,7 @@ static void setup_block_file(const char *filename)
        struct device *dev;
        struct vblk_info *vblk;
        void *stack;
-       u64 cap;
-       unsigned int val;
+       struct virtio_blk_config conf;
 
        /* This is the pipe the I/O thread will use to tell us I/O is done. */
        pipe(p);
@@ -1477,14 +1550,18 @@ static void setup_block_file(const char *filename)
        vblk->fd = open_or_die(filename, O_RDWR|O_LARGEFILE);
        vblk->len = lseek64(vblk->fd, 0, SEEK_END);
 
+       /* We support barriers. */
+       add_feature(dev, VIRTIO_BLK_F_BARRIER);
+
        /* Tell Guest how many sectors this device has. */
-       cap = cpu_to_le64(vblk->len / 512);
-       add_desc_field(dev, VIRTIO_CONFIG_BLK_F_CAPACITY, sizeof(cap), &cap);
+       conf.capacity = cpu_to_le64(vblk->len / 512);
 
        /* Tell Guest not to put in too many descriptors at once: two are used
         * for the in and out elements. */
-       val = cpu_to_le32(VIRTQUEUE_NUM - 2);
-       add_desc_field(dev, VIRTIO_CONFIG_BLK_F_SEG_MAX, sizeof(val), &val);
+       add_feature(dev, VIRTIO_BLK_F_SEG_MAX);
+       conf.seg_max = cpu_to_le32(VIRTQUEUE_NUM - 2);
+
+       set_config(dev, sizeof(conf), &conf);
 
        /* The I/O thread writes to this end of the pipe when done. */
        vblk->done_fd = p[1];
@@ -1505,7 +1582,7 @@ static void setup_block_file(const char *filename)
        close(vblk->workpipe[0]);
 
        verbose("device %u: virtblock %llu sectors\n",
-               devices.device_num, cap);
+               devices.device_num, le64_to_cpu(conf.capacity));
 }
 /* That's the end of device setup. :*/
 
@@ -1610,12 +1687,12 @@ int main(int argc, char *argv[])
        /* First we initialize the device list.  Since console and network
         * device receive input from a file descriptor, we keep an fdset
         * (infds) and the maximum fd number (max_infd) with the head of the
-        * list.  We also keep a pointer to the last device, for easy appending
-        * to the list.  Finally, we keep the next interrupt number to hand out
-        * (1: remember that 0 is used by the timer). */
+        * list.  We also keep a pointer to the last device.  Finally, we keep
+        * the next interrupt number to hand out (1: remember that 0 is used by
+        * the timer). */
        FD_ZERO(&devices.infds);
        devices.max_infd = -1;
-       devices.lastdev = &devices.dev;
+       devices.lastdev = NULL;
        devices.next_irq = 1;
 
        cpu_id = 0;
index badb7480ea6282904d7ff648629262fa0f632a97..d8968958d839ddb7d94a317c8ac83918c66a2b63 100644 (file)
@@ -60,7 +60,7 @@ operation of the local communications in any other way though.
 
 The kernel command line takes options looking like the following:
 
-    decnet=1,2
+    decnet.addr=1,2
 
 the two numbers are the node address 1,2 = 1.2 For 2.2.xx kernels
 and early 2.3.xx kernels, you must use a comma when specifying the
index 53c1a58b02f1b3b5cf4010a693ba2cef496fc010..d0d8bafa9016b7f435ac5529ca6d6e1c736b42dc 100644 (file)
@@ -26,8 +26,9 @@ XfrmInStateProtoError:
        e.g. SA key is wrong
 XfrmInStateModeError:
        Transformation mode specific error
-XfrmInSeqOutOfWindow:
-       Sequence out of window
+XfrmInStateSeqError:
+       Sequence error
+       i.e. Sequence number is out of window
 XfrmInStateExpired:
        State is expired
 XfrmInStateMismatch:
@@ -60,6 +61,9 @@ XfrmOutStateProtoError:
        Transformation protocol specific error
 XfrmOutStateModeError:
        Transformation mode specific error
+XfrmOutStateSeqError:
+       Sequence error
+       i.e. Sequence number overflow
 XfrmOutStateExpired:
        State is expired
 XfrmOutPolBlock:
index 7754f5aea4e9b0bdd62280fb4f9fe88b23dce3fc..72b20c63959651ce7be7dad2f2e854c983f660e0 100644 (file)
@@ -274,8 +274,6 @@ the PCI device by calling pci_enable_device(). This will:
        o allocate an IRQ (if BIOS did not).
 
 NOTE: pci_enable_device() can fail! Check the return value.
-NOTE2: Also see pci_enable_device_bars() below. Drivers can
-    attempt to enable only a subset of BARs they need.
 
 [ OS BUG: we don't check resource allocations before enabling those
   resources. The sequence would make more sense if we called
@@ -605,40 +603,7 @@ device lists. This is still possible but discouraged.
 
 
 
-10. pci_enable_device_bars() and Legacy I/O Port space
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Large servers may not be able to provide I/O port resources to all PCI
-devices. I/O Port space is only 64KB on Intel Architecture[1] and is
-likely also fragmented since the I/O base register of PCI-to-PCI
-bridge will usually be aligned to a 4KB boundary[2]. On such systems,
-pci_enable_device() and pci_request_region() will fail when
-attempting to enable I/O Port regions that don't have I/O Port
-resources assigned.
-
-Fortunately, many PCI devices which request I/O Port resources also
-provide access to the same registers via MMIO BARs. These devices can
-be handled without using I/O port space and the drivers typically
-offer a CONFIG_ option to only use MMIO regions
-(e.g. CONFIG_TULIP_MMIO). PCI devices typically provide I/O port
-interface for legacy OSes and will work when I/O port resources are not
-assigned. The "PCI Local Bus Specification Revision 3.0" discusses
-this on p.44, "IMPLEMENTATION NOTE".
-
-If your PCI device driver doesn't need I/O port resources assigned to
-I/O Port BARs, you should use pci_enable_device_bars() instead of
-pci_enable_device() in order not to enable I/O port regions for the
-corresponding devices. In addition, you should use
-pci_request_selected_regions() and pci_release_selected_regions()
-instead of pci_request_regions()/pci_release_regions() in order not to
-request/release I/O port regions for the corresponding devices.
-
-[1] Some systems support 64KB I/O port space per PCI segment.
-[2] Some PCI-to-PCI bridges support optional 1KB aligned I/O base.
-
-
-
-11. MMIO Space and "Write Posting"
+10. MMIO Space and "Write Posting"
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 Converting a driver from using I/O Port space to using MMIO space
index 4739c5c3face33164587d55749eb3f2f98c3674d..96f155e687506096e0f694591aa3b9fd722e4a48 100644 (file)
@@ -33,8 +33,8 @@ This file details changes in 2.6 which affect PCMCIA card driver authors:
    and can be used (e.g. for SET_NETDEV_DEV) by using
    handle_to_dev(client_handle_t * handle).
 
-* Convert internal I/O port addresses to unsigned long (as of 2.6.11)
-   ioaddr_t should be replaced by kio_addr_t in PCMCIA card drivers.
+* Convert internal I/O port addresses to unsigned int (as of 2.6.11)
+   ioaddr_t should be replaced by unsigned int in PCMCIA card drivers.
 
 * irq_mask and irq_list parameters (as of 2.6.11)
    The irq_mask and irq_list parameters should no longer be used in
diff --git a/Documentation/pm_qos_interface.txt b/Documentation/pm_qos_interface.txt
new file mode 100644 (file)
index 0000000..49adb1a
--- /dev/null
@@ -0,0 +1,59 @@
+PM quality of Service interface.
+
+This interface provides a kernel and user mode interface for registering
+performance expectations by drivers, subsystems and user space applications on
+one of the parameters.
+
+Currently we have {cpu_dma_latency, network_latency, network_throughput} as the
+initial set of pm_qos parameters.
+
+The infrastructure exposes multiple misc device nodes one per implemented
+parameter.  The set of parameters implement is defined by pm_qos_power_init()
+and pm_qos_params.h.  This is done because having the available parameters
+being runtime configurable or changeable from a driver was seen as too easy to
+abuse.
+
+For each parameter a list of performance requirements is maintained along with
+an aggregated target value.  The aggregated target value is updated with
+changes to the requirement list or elements of the list.  Typically the
+aggregated target value is simply the max or min of the requirement values held
+in the parameter list elements.
+
+From kernel mode the use of this interface is simple:
+pm_qos_add_requirement(param_id, name, target_value):
+Will insert a named element in the list for that identified PM_QOS parameter
+with the target value.  Upon change to this list the new target is recomputed
+and any registered notifiers are called only if the target value is now
+different.
+
+pm_qos_update_requirement(param_id, name, new_target_value):
+Will search the list identified by the param_id for the named list element and
+then update its target value, calling the notification tree if the aggregated
+target is changed.  with that name is already registered.
+
+pm_qos_remove_requirement(param_id, name):
+Will search the identified list for the named element and remove it, after
+removal it will update the aggregate target and call the notification tree if
+the target was changed as a result of removing the named requirement.
+
+
+From user mode:
+Only processes can register a pm_qos requirement.  To provide for automatic
+cleanup for process the interface requires the process to register its
+parameter requirements in the following way:
+
+To register the default pm_qos target for the specific parameter, the process
+must open one of /dev/[cpu_dma_latency, network_latency, network_throughput]
+
+As long as the device node is held open that process has a registered
+requirement on the parameter.  The name of the requirement is "process_<PID>"
+derived from the current->pid from within the open system call.
+
+To change the requested target value the process needs to write a s32 value to
+the open device node.  This translates to a pm_qos_update_requirement call.
+
+To remove the user mode request for a target value simply close the device
+node.
+
+
+
index 57aef2f6e0de6ad30673d8ce34a5430dc59ec5ab..1555001bc73394dbed7fccbc9a10917671e403e1 100644 (file)
-Debugging suspend and resume
+Debugging hibernation and suspend
        (C) 2007 Rafael J. Wysocki <rjw@sisk.pl>, GPL
 
-1. Testing suspend to disk (STD)
+1. Testing hibernation (aka suspend to disk or STD)
 
-To verify that the STD works, you can try to suspend in the "reboot" mode:
+To check if hibernation works, you can try to hibernate in the "reboot" mode:
 
 # echo reboot > /sys/power/disk
 # echo disk > /sys/power/state
 
-and the system should suspend, reboot, resume and get back to the command prompt
-where you have started the transition.  If that happens, the STD is most likely
-to work correctly, but you need to repeat the test at least a couple of times in
-a row for confidence.  This is necessary, because some problems only show up on
-a second attempt at suspending and resuming the system.  You should also test
-the "platform" and "shutdown" modes of suspend:
+and the system should create a hibernation image, reboot, resume and get back to
+the command prompt where you have started the transition.  If that happens,
+hibernation is most likely to work correctly.  Still, you need to repeat the
+test at least a couple of times in a row for confidence.  [This is necessary,
+because some problems only show up on a second attempt at suspending and
+resuming the system.]  Moreover, hibernating in the "reboot" and "shutdown"
+modes causes the PM core to skip some platform-related callbacks which on ACPI
+systems might be necessary to make hibernation work.  Thus, if you machine fails
+to hibernate or resume in the "reboot" mode, you should try the "platform" mode:
 
 # echo platform > /sys/power/disk
 # echo disk > /sys/power/state
 
-or
+which is the default and recommended mode of hibernation.
+
+Unfortunately, the "platform" mode of hibernation does not work on some systems
+with broken BIOSes.  In such cases the "shutdown" mode of hibernation might
+work:
 
 # echo shutdown > /sys/power/disk
 # echo disk > /sys/power/state
 
-in which cases you will have to press the power button to make the system
-resume.  If that does not work, you will need to identify what goes wrong.
+(it is similar to the "reboot" mode, but it requires you to press the power
+button to make the system resume).
+
+If neither "platform" nor "shutdown" hibernation mode works, you will need to
+identify what goes wrong.
+
+a) Test modes of hibernation
+
+To find out why hibernation fails on your system, you can use a special testing
+facility available if the kernel is compiled with CONFIG_PM_DEBUG set.  Then,
+there is the file /sys/power/pm_test that can be used to make the hibernation
+core run in a test mode.  There are 5 test modes available:
+
+freezer
+- test the freezing of processes
+
+devices
+- test the freezing of processes and suspending of devices
 
-a) Test mode of STD
+platform
+- test the freezing of processes, suspending of devices and platform
+  global control methods(*)
 
-To verify if there are any drivers that cause problems you can run the STD
-in the test mode:
+processors
+- test the freezing of processes, suspending of devices, platform
+  global control methods(*) and the disabling of nonboot CPUs
 
-# echo test > /sys/power/disk
+core
+- test the freezing of processes, suspending of devices, platform global
+  control methods(*), the disabling of nonboot CPUs and suspending of
+  platform/system devices
+
+(*) the platform global control methods are only available on ACPI systems
+    and are only tested if the hibernation mode is set to "platform"
+
+To use one of them it is necessary to write the corresponding string to
+/sys/power/pm_test (eg. "devices" to test the freezing of processes and
+suspending devices) and issue the standard hibernation commands.  For example,
+to use the "devices" test mode along with the "platform" mode of hibernation,
+you should do the following:
+
+# echo devices > /sys/power/pm_test
+# echo platform > /sys/power/disk
 # echo disk > /sys/power/state
 
-in which case the system should freeze tasks, suspend devices, disable nonboot
-CPUs (if any), wait for 5 seconds, enable nonboot CPUs, resume devices, thaw
-tasks and return to your command prompt.  If that fails, most likely there is
-a driver that fails to either suspend or resume (in the latter case the system
-may hang or be unstable after the test, so please take that into consideration).
-To find this driver, you can carry out a binary search according to the rules:
+Then, the kernel will try to freeze processes, suspend devices, wait 5 seconds,
+resume devices and thaw processes.  If "platform" is written to
+/sys/power/pm_test , then after suspending devices the kernel will additionally
+invoke the global control methods (eg. ACPI global control methods) used to
+prepare the platform firmware for hibernation.  Next, it will wait 5 seconds and
+invoke the platform (eg. ACPI) global methods used to cancel hibernation etc.
+
+Writing "none" to /sys/power/pm_test causes the kernel to switch to the normal
+hibernation/suspend operations.  Also, when open for reading, /sys/power/pm_test
+contains a space-separated list of all available tests (including "none" that
+represents the normal functionality) in which the current test level is
+indicated by square brackets.
+
+Generally, as you can see, each test level is more "invasive" than the previous
+one and the "core" level tests the hardware and drivers as deeply as possible
+without creating a hibernation image.  Obviously, if the "devices" test fails,
+the "platform" test will fail as well and so on.  Thus, as a rule of thumb, you
+should try the test modes starting from "freezer", through "devices", "platform"
+and "processors" up to "core" (repeat the test on each level a couple of times
+to make sure that any random factors are avoided).
+
+If the "freezer" test fails, there is a task that cannot be frozen (in that case
+it usually is possible to identify the offending task by analysing the output of
+dmesg obtained after the failing test).  Failure at this level usually means
+that there is a problem with the tasks freezer subsystem that should be
+reported.
+
+If the "devices" test fails, most likely there is a driver that cannot suspend
+or resume its device (in the latter case the system may hang or become unstable
+after the test, so please take that into consideration).  To find this driver,
+you can carry out a binary search according to the rules:
 - if the test fails, unload a half of the drivers currently loaded and repeat
 (that would probably involve rebooting the system, so always note what drivers
 have been loaded before the test),
@@ -47,23 +113,46 @@ have been loaded before the test),
 recently and repeat.
 
 Once you have found the failing driver (there can be more than just one of
-them), you have to unload it every time before the STD transition.  In that case
-please make sure to report the problem with the driver.
-
-It is also possible that a cycle can still fail after you have unloaded
-all modules. In that case, you would want to look in your kernel configuration
-for the drivers that can be compiled as modules (testing again with them as
-modules), and possibly also try boot time options such as "noapic" or "noacpi".
+them), you have to unload it every time before hibernation.  In that case please
+make sure to report the problem with the driver.
+
+It is also possible that the "devices" test will still fail after you have
+unloaded all modules. In that case, you may want to look in your kernel
+configuration for the drivers that can be compiled as modules (and test again
+with these drivers compiled as modules).  You may also try to use some special
+kernel command line options such as "noapic", "noacpi" or even "acpi=off".
+
+If the "platform" test fails, there is a problem with the handling of the
+platform (eg. ACPI) firmware on your system.  In that case the "platform" mode
+of hibernation is not likely to work.  You can try the "shutdown" mode, but that
+is rather a poor man's workaround.
+
+If the "processors" test fails, the disabling/enabling of nonboot CPUs does not
+work (of course, this only may be an issue on SMP systems) and the problem
+should be reported.  In that case you can also try to switch the nonboot CPUs
+off and on using the /sys/devices/system/cpu/cpu*/online sysfs attributes and
+see if that works.
+
+If the "core" test fails, which means that suspending of the system/platform
+devices has failed (these devices are suspended on one CPU with interrupts off),
+the problem is most probably hardware-related and serious, so it should be
+reported.
+
+A failure of any of the "platform", "processors" or "core" tests may cause your
+system to hang or become unstable, so please beware.  Such a failure usually
+indicates a serious problem that very well may be related to the hardware, but
+please report it anyway.
 
 b) Testing minimal configuration
 
-If the test mode of STD works, you can boot the system with "init=/bin/bash"
-and attempt to suspend in the "reboot", "shutdown" and "platform" modes.  If
-that does not work, there probably is a problem with a driver statically
-compiled into the kernel and you can try to compile more drivers as modules,
-so that they can be tested individually.  Otherwise, there is a problem with a
-modular driver and you can find it by loading a half of the modules you normally
-use and binary searching in accordance with the algorithm:
+If all of the hibernation test modes work, you can boot the system with the
+"init=/bin/bash" command line parameter and attempt to hibernate in the
+"reboot", "shutdown" and "platform" modes.  If that does not work, there
+probably is a problem with a driver statically compiled into the kernel and you
+can try to compile more drivers as modules, so that they can be tested
+individually.  Otherwise, there is a problem with a modular driver and you can
+find it by loading a half of the modules you normally use and binary searching
+in accordance with the algorithm:
 - if there are n modules loaded and the attempt to suspend and resume fails,
 unload n/2 of the modules and try again (that would probably involve rebooting
 the system),
@@ -71,19 +160,19 @@ the system),
 load n/2 modules more and try again.
 
 Again, if you find the offending module(s), it(they) must be unloaded every time
-before the STD transition, and please report the problem with it(them).
+before hibernation, and please report the problem with it(them).
 
 c) Advanced debugging
 
-In case the STD does not work on your system even in the minimal configuration
-and compiling more drivers as modules is not practical or some modules cannot
-be unloaded, you can use one of the more advanced debugging techniques to find
-the problem.  First, if there is a serial port in your box, you can boot the
-kernel with the 'no_console_suspend' parameter and try to log kernel
-messages using the serial console.  This may provide you with some information
-about the reasons of the suspend (resume) failure.  Alternatively, it may be
-possible to use a FireWire port for debugging with firescope
-(ftp://ftp.firstfloor.org/pub/ak/firescope/).  On i386 it is also possible to
+In case that hibernation does not work on your system even in the minimal
+configuration and compiling more drivers as modules is not practical or some
+modules cannot be unloaded, you can use one of the more advanced debugging
+techniques to find the problem.  First, if there is a serial port in your box,
+you can boot the kernel with the 'no_console_suspend' parameter and try to log
+kernel messages using the serial console.  This may provide you with some
+information about the reasons of the suspend (resume) failure.  Alternatively,
+it may be possible to use a FireWire port for debugging with firescope
+(ftp://ftp.firstfloor.org/pub/ak/firescope/).  On x86 it is also possible to
 use the PM_TRACE mechanism documented in Documentation/s2ram.txt .
 
 2. Testing suspend to RAM (STR)
@@ -91,16 +180,25 @@ use the PM_TRACE mechanism documented in Documentation/s2ram.txt .
 To verify that the STR works, it is generally more convenient to use the s2ram
 tool available from http://suspend.sf.net and documented at
 http://en.opensuse.org/s2ram .  However, before doing that it is recommended to
-carry out the procedure described in section 1.
-
-Assume you have resolved the problems with the STD and you have found some
-failing drivers.  These drivers are also likely to fail during the STR or
-during the resume, so it is better to unload them every time before the STR
-transition.  Now, you can follow the instructions at
-http://en.opensuse.org/s2ram to test the system, but if it does not work
-"out of the box", you may need to boot it with "init=/bin/bash" and test
-s2ram in the minimal configuration.  In that case, you may be able to search
-for failing drivers by following the procedure analogous to the one described in
-1b).  If you find some failing drivers, you will have to unload them every time
-before the STR transition (ie. before you run s2ram), and please report the
-problems with them.
+carry out STR testing using the facility described in section 1.
+
+Namely, after writing "freezer", "devices", "platform", "processors", or "core"
+into /sys/power/pm_test (available if the kernel is compiled with
+CONFIG_PM_DEBUG set) the suspend code will work in the test mode corresponding
+to given string.  The STR test modes are defined in the same way as for
+hibernation, so please refer to Section 1 for more information about them.  In
+particular, the "core" test allows you to test everything except for the actual
+invocation of the platform firmware in order to put the system into the sleep
+state.
+
+Among other things, the testing with the help of /sys/power/pm_test may allow
+you to identify drivers that fail to suspend or resume their devices.  They
+should be unloaded every time before an STR transition.
+
+Next, you can follow the instructions at http://en.opensuse.org/s2ram to test
+the system, but if it does not work "out of the box", you may need to boot it
+with "init=/bin/bash" and test s2ram in the minimal configuration.  In that
+case, you may be able to search for failing drivers by following the procedure
+analogous to the one described in section 1.  If you find some failing drivers,
+you will have to unload them every time before an STR transition (ie. before
+you run s2ram), and please report the problems with them.
index d0e79d5820a5e7a7237f36a1cb5776ec589552d8..c53d263619194f7e04719e0a7250944b0134d598 100644 (file)
@@ -502,52 +502,3 @@ If the CPU can have a "cpufreq" driver, there also may be opportunities
 to shift to lower voltage settings and reduce the power cost of executing
 a given number of instructions.  (Without voltage adjustment, it's rare
 for cpufreq to save much power; the cost-per-instruction must go down.)
-
-
-/sys/devices/.../power/state files
-==================================
-For now you can also test some of this functionality using sysfs.
-
-       DEPRECATED:  USE "power/state" ONLY FOR DRIVER TESTING, AND
-       AVOID USING dev->power.power_state IN DRIVERS.
-
-       THESE WILL BE REMOVED.  IF THE "power/state" FILE GETS REPLACED,
-       IT WILL BECOME SOMETHING COUPLED TO THE BUS OR DRIVER.
-
-In each device's directory, there is a 'power' directory, which contains
-at least a 'state' file.  The value of this field is effectively boolean,
-PM_EVENT_ON or PM_EVENT_SUSPEND.
-
-   *   Reading from this file displays a value corresponding to
-       the power.power_state.event field.  All nonzero values are
-       displayed as "2", corresponding to a low power state; zero
-       is displayed as "0", corresponding to normal operation.
-
-   *   Writing to this file initiates a transition using the
-       specified event code number; only '0', '2', and '3' are
-       accepted (without a newline); '2' and '3' are both
-       mapped to PM_EVENT_SUSPEND.
-
-On writes, the PM core relies on that recorded event code and the device/bus
-capabilities to determine whether it uses a partial suspend() or resume()
-sequence to change things so that the recorded event corresponds to the
-numeric parameter.
-
-   -   If the bus requires the irqs-disabled suspend_late()/resume_early()
-       phases, writes fail because those operations are not supported here.
-
-   -   If the recorded value is the expected value, nothing is done.
-
-   -   If the recorded value is nonzero, the device is partially resumed,
-       using the bus.resume() and/or class.resume() methods.
-
-   -   If the target value is nonzero, the device is partially suspended,
-       using the class.suspend() and/or bus.suspend() methods and the
-       PM_EVENT_SUSPEND message.
-
-Drivers have no way to tell whether their suspend() and resume() calls
-have come through the sysfs power/state file or as part of entering a
-system sleep state, except that when accessed through sysfs the normal
-parent/child sequencing rules are ignored.  Drivers (such as bus, bridge,
-or hub drivers) which expose child devices may need to enforce those rules
-on their own.
index e4bdcaee24e46e6805caf0e0a9edfc9d57638402..7f7a737f7f9fd785deacaf4f3aaaf56d87a21c11 100644 (file)
@@ -6,9 +6,9 @@ Testing suspend and resume support in device drivers
 Unfortunately, to effectively test the support for the system-wide suspend and
 resume transitions in a driver, it is necessary to suspend and resume a fully
 functional system with this driver loaded.  Moreover, that should be done
-several times, preferably several times in a row, and separately for the suspend
-to disk (STD) and the suspend to RAM (STR) transitions, because each of these
-cases involves different ordering of operations and different interactions with
+several times, preferably several times in a row, and separately for hibernation
+(aka suspend to disk or STD) and suspend to RAM (STR), because each of these
+cases involves slightly different operations and different interactions with
 the machine's BIOS.
 
 Of course, for this purpose the test system has to be known to suspend and
@@ -22,20 +22,24 @@ for more information about the debugging of suspend/resume functionality.
 Once you have resolved the suspend/resume-related problems with your test system
 without the new driver, you are ready to test it:
 
-a) Build the driver as a module, load it and try the STD in the test mode (see:
-Documents/power/basic-pm-debugging.txt, 1a)).
+a) Build the driver as a module, load it and try the test modes of hibernation
+   (see: Documents/power/basic-pm-debugging.txt, 1).
 
-b) Load the driver and attempt to suspend to disk in the "reboot", "shutdown"
-and "platform" modes (see: Documents/power/basic-pm-debugging.txt, 1).
+b) Load the driver and attempt to hibernate in the "reboot", "shutdown" and
+   "platform" modes (see: Documents/power/basic-pm-debugging.txt, 1).
 
-c) Compile the driver directly into the kernel and try the STD in the test mode.
+c) Compile the driver directly into the kernel and try the test modes of
+   hibernation.
 
-d) Attempt to suspend to disk with the driver compiled directly into the kernel
-in the "reboot", "shutdown" and "platform" modes.
+d) Attempt to hibernate with the driver compiled directly into the kernel
+   in the "reboot", "shutdown" and "platform" modes.
 
-e) Attempt to suspend to RAM using the s2ram tool with the driver loaded (see:
-Documents/power/basic-pm-debugging.txt, 2).  As far as the STR tests are
-concerned, it should not matter whether or not the driver is built as a module.
+e) Try the test modes of suspend (see: Documents/power/basic-pm-debugging.txt,
+   2).  [As far as the STR tests are concerned, it should not matter whether or
+   not the driver is built as a module.]
+
+f) Attempt to suspend to RAM using the s2ram tool with the driver loaded
+   (see: Documents/power/basic-pm-debugging.txt, 2).
 
 Each of the above tests should be repeated several times and the STD tests
 should be mixed with the STR tests.  If any of them fails, the driver cannot be
index 9293e4bc857c6bb7a049b8951c97ee42ab306d9c..ae1b7ec07684bad822171767bba66fc9798cc204 100644 (file)
@@ -28,6 +28,14 @@ PM_POST_HIBERNATION  The system memory state has been restored from a
                        hibernation.  Device drivers' .resume() callbacks have
                        been executed and tasks have been thawed.
 
+PM_RESTORE_PREPARE     The system is going to restore a hibernation image.
+                       If all goes well the restored kernel will issue a
+                       PM_POST_HIBERNATION notification.
+
+PM_POST_RESTORE                An error occurred during the hibernation restore.
+                       Device drivers' .resume() callbacks have been executed
+                       and tasks have been thawed.
+
 PM_SUSPEND_PREPARE     The system is preparing for a suspend.
 
 PM_POST_SUSPEND                The system has just resumed or an error occured during
index e00c6cf09e85aad17e587f0ac9d19d0a543a4cad..7b99636564c8cbc608ff6fb1a24b883c254bf8e3 100644 (file)
@@ -14,7 +14,7 @@ are going to develop your own suspend/resume utilities.
 
 The interface consists of a character device providing the open(),
 release(), read(), and write() operations as well as several ioctl()
-commands defined in kernel/power/power.h.  The major and minor
+commands defined in include/linux/suspend_ioctls.h .  The major and minor
 numbers of the device are, respectively, 10 and 231, and they can
 be read from /sys/class/misc/snapshot/dev.
 
@@ -27,17 +27,17 @@ once at a time.
 The ioctl() commands recognized by the device are:
 
 SNAPSHOT_FREEZE - freeze user space processes (the current process is
-       not frozen); this is required for SNAPSHOT_ATOMIC_SNAPSHOT
+       not frozen); this is required for SNAPSHOT_CREATE_IMAGE
        and SNAPSHOT_ATOMIC_RESTORE to succeed
 
 SNAPSHOT_UNFREEZE - thaw user space processes frozen by SNAPSHOT_FREEZE
 
-SNAPSHOT_ATOMIC_SNAPSHOT - create a snapshot of the system memory; the
+SNAPSHOT_CREATE_IMAGE - create a snapshot of the system memory; the
        last argument of ioctl() should be a pointer to an int variable,
        the value of which will indicate whether the call returned after
        creating the snapshot (1) or after restoring the system memory state
        from it (0) (after resume the system finds itself finishing the
-       SNAPSHOT_ATOMIC_SNAPSHOT ioctl() again); after the snapshot
+       SNAPSHOT_CREATE_IMAGE ioctl() again); after the snapshot
        has been created the read() operation can be used to transfer
        it out of the kernel
 
@@ -49,39 +49,37 @@ SNAPSHOT_ATOMIC_RESTORE - restore the system memory state from the
 
 SNAPSHOT_FREE - free memory allocated for the snapshot image
 
-SNAPSHOT_SET_IMAGE_SIZE - set the preferred maximum size of the image
+SNAPSHOT_PREF_IMAGE_SIZE - set the preferred maximum size of the image
        (the kernel will do its best to ensure the image size will not exceed
        this number, but if it turns out to be impossible, the kernel will
        create the smallest image possible)
 
-SNAPSHOT_AVAIL_SWAP - return the amount of available swap in bytes (the last
-       argument should be a pointer to an unsigned int variable that will
+SNAPSHOT_GET_IMAGE_SIZE - return the actual size of the hibernation image
+
+SNAPSHOT_AVAIL_SWAP_SIZE - return the amount of available swap in bytes (the
+       last argument should be a pointer to an unsigned int variable that will
        contain the result if the call is successful).
 
-SNAPSHOT_GET_SWAP_PAGE - allocate a swap page from the resume partition
+SNAPSHOT_ALLOC_SWAP_PAGE - allocate a swap page from the resume partition
        (the last argument should be a pointer to a loff_t variable that
        will contain the swap page offset if the call is successful)
 
-SNAPSHOT_FREE_SWAP_PAGES - free all swap pages allocated with
-       SNAPSHOT_GET_SWAP_PAGE
-
-SNAPSHOT_SET_SWAP_FILE - set the resume partition (the last ioctl() argument
-       should specify the device's major and minor numbers in the old
-       two-byte format, as returned by the stat() function in the .st_rdev
-       member of the stat structure)
+SNAPSHOT_FREE_SWAP_PAGES - free all swap pages allocated by
+       SNAPSHOT_ALLOC_SWAP_PAGE
 
 SNAPSHOT_SET_SWAP_AREA - set the resume partition and the offset (in <PAGE_SIZE>
        units) from the beginning of the partition at which the swap header is
        located (the last ioctl() argument should point to a struct
-       resume_swap_area, as defined in kernel/power/power.h, containing the
-       resume device specification, as for the SNAPSHOT_SET_SWAP_FILE ioctl(),
-       and the offset); for swap partitions the offset is always 0, but it is
-       different to zero for swap files (please see
-       Documentation/swsusp-and-swap-files.txt for details).
-       The SNAPSHOT_SET_SWAP_AREA ioctl() is considered as a replacement for
-       SNAPSHOT_SET_SWAP_FILE which is regarded as obsolete.   It is
-       recommended to always use this call, because the code to set the resume
-       partition may be removed from future kernels
+       resume_swap_area, as defined in kernel/power/suspend_ioctls.h,
+       containing the resume device specification and the offset); for swap
+       partitions the offset is always 0, but it is different from zero for
+       swap files (see Documentation/swsusp-and-swap-files.txt for details).
+
+SNAPSHOT_PLATFORM_SUPPORT - enable/disable the hibernation platform support,
+       depending on the argument value (enable, if the argument is nonzero)
+
+SNAPSHOT_POWER_OFF - make the kernel transition the system to the hibernation
+       state (eg. ACPI S4) using the platform (eg. ACPI) driver
 
 SNAPSHOT_S2RAM - suspend to RAM; using this call causes the kernel to
        immediately enter the suspend-to-RAM state, so this call must always
@@ -93,24 +91,6 @@ SNAPSHOT_S2RAM - suspend to RAM; using this call causes the kernel to
        to resume the system from RAM if there's enough battery power or restore
        its state on the basis of the saved suspend image otherwise)
 
-SNAPSHOT_PMOPS - enable the usage of the hibernation_ops->prepare,
-       hibernate_ops->enter and hibernation_ops->finish methods (the in-kernel
-       swsusp knows these as the "platform method") which are needed on many
-       machines to (among others) speed up the resume by letting the BIOS skip
-       some steps or to let the system recognise the correct state of the
-       hardware after the resume (in particular on many machines this ensures
-       that unplugged AC adapters get correctly detected and that kacpid does
-       not run wild after the resume).  The last ioctl() argument can take one
-       of the three values, defined in kernel/power/power.h:
-       PMOPS_PREPARE - make the kernel carry out the
-               hibernation_ops->prepare() operation
-       PMOPS_ENTER - make the kernel power off the system by calling
-               hibernation_ops->enter()
-       PMOPS_FINISH - make the kernel carry out the
-               hibernation_ops->finish() operation
-       Note that the actual constants are misnamed because they surface
-       internal kernel implementation details that have changed.
-
 The device's read() operation can be used to transfer the snapshot image from
 the kernel.  It has the following limitations:
 - you cannot read() more than one virtual memory page at a time
@@ -122,7 +102,7 @@ The device's write() operation is used for uploading the system memory snapshot
 into the kernel.  It has the same limitations as the read() operation.
 
 The release() operation frees all memory allocated for the snapshot image
-and all swap pages allocated with SNAPSHOT_GET_SWAP_PAGE (if any).
+and all swap pages allocated with SNAPSHOT_ALLOC_SWAP_PAGE (if any).
 Thus it is not necessary to use either SNAPSHOT_FREE or
 SNAPSHOT_FREE_SWAP_PAGES before closing the device (in fact it will also
 unfreeze user space processes frozen by SNAPSHOT_UNFREEZE if they are
@@ -133,16 +113,12 @@ snapshot image from/to the kernel will use a swap parition, called the resume
 partition, or a swap file as storage space (if a swap file is used, the resume
 partition is the partition that holds this file).  However, this is not really
 required, as they can use, for example, a special (blank) suspend partition or
-a file on a partition that is unmounted before SNAPSHOT_ATOMIC_SNAPSHOT and
+a file on a partition that is unmounted before SNAPSHOT_CREATE_IMAGE and
 mounted afterwards.
 
-These utilities SHOULD NOT make any assumptions regarding the ordering of
-data within the snapshot image, except for the image header that MAY be
-assumed to start with an swsusp_info structure, as specified in
-kernel/power/power.h.  This structure MAY be used by the userland utilities
-to obtain some information about the snapshot image, such as the size
-of the snapshot image, including the metadata and the header itself,
-contained in the .size member of swsusp_info.
+These utilities MUST NOT make any assumptions regarding the ordering of
+data within the snapshot image.  The contents of the image are entirely owned
+by the kernel and its structure may be changed in future kernel releases.
 
 The snapshot image MUST be written to the kernel unaltered (ie. all of the image
 data, metadata and header MUST be written in _exactly_ the same amount, form
@@ -159,7 +135,7 @@ means, such as checksums, to ensure the integrity of the snapshot image.
 The suspending and resuming utilities MUST lock themselves in memory,
 preferrably using mlockall(), before calling SNAPSHOT_FREEZE.
 
-The suspending utility MUST check the value stored by SNAPSHOT_ATOMIC_SNAPSHOT
+The suspending utility MUST check the value stored by SNAPSHOT_CREATE_IMAGE
 in the memory location pointed to by the last argument of ioctl() and proceed
 in accordance with it:
 1.     If the value is 1 (ie. the system memory snapshot has just been
@@ -173,7 +149,7 @@ in accordance with it:
                image has been saved.
        (b)     The suspending utility SHOULD NOT attempt to perform any
                file system operations (including reads) on the file systems
-               that were mounted before SNAPSHOT_ATOMIC_SNAPSHOT has been
+               that were mounted before SNAPSHOT_CREATE_IMAGE has been
                called.  However, it MAY mount a file system that was not
                mounted at that time and perform some operations on it (eg.
                use it for saving the image).
index 9758cf433c0660f7f971f3958c5ffddbcb1a884a..a8686e5a68579fc207d4c12e59246d7aee58ffcd 100644 (file)
@@ -87,6 +87,10 @@ batteries use voltage for very approximated calculation of capacity.
 Battery driver also can use this attribute just to inform userspace
 about maximal and minimal voltage thresholds of a given battery.
 
+VOLTAGE_MAX, VOLTAGE_MIN - same as _DESIGN voltage values except that
+these ones should be used if hardware could only guess (measure and
+retain) the thresholds of a given power supply.
+
 CHARGE_FULL_DESIGN, CHARGE_EMPTY_DESIGN - design charge values, when
 battery considered full/empty.
 
@@ -100,8 +104,6 @@ age)". I.e. these attributes represents real thresholds, not design values.
 ENERGY_FULL, ENERGY_EMPTY - same as above but for energy.
 
 CAPACITY - capacity in percents.
-CAPACITY_LEVEL - capacity level. This corresponds to
-POWER_SUPPLY_CAPACITY_LEVEL_*.
 
 TEMP - temperature of the power supply.
 TEMP_AMBIENT - ambient temperature.
diff --git a/Documentation/smp.txt b/Documentation/smp.txt
deleted file mode 100644 (file)
index 82fc50b..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-To set up SMP
-
-Configure the kernel and answer Y to CONFIG_SMP.
-
-If you are using LILO, it is handy to have both SMP and non-SMP
-kernel images on hand. Edit /etc/lilo.conf to create an entry
-for another kernel image called "linux-smp" or something.
-
-The next time you compile the kernel, when running a SMP kernel,
-edit linux/Makefile and change "MAKE=make" to "MAKE=make -jN"
-(where N = number of CPU + 1, or if you have tons of memory/swap
- you can just use "-j" without a number). Feel free to experiment
-with this one.
-
-Of course you should time how long each build takes :-)
-Example:
-   make config
-   time -v sh -c 'make clean install modules modules_install'
-
-If you are using some Compaq MP compliant machines you will need to set
-the operating system in the BIOS settings to "Unixware" - don't ask me
-why Compaqs don't work otherwise.
index 4b48c2e82c3c1f340cf4cd7b4247d6d58941d162..e985cf5e04107798a4f079260486a1793c061623 100644 (file)
@@ -57,7 +57,9 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
                - Default: 1
                - For auto-loading more than one card, specify this
                  option together with snd-card-X aliases.
-
+    slots      - Reserve the slot index for the given driver.
+                 This option takes multiple strings.           
+                 See "Module Autoloading Support" section for details.
   
   Module snd-pcm-oss
   ------------------
@@ -148,13 +150,6 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
 
     Module for sound cards based on Analog Devices AD1816A/AD1815 ISA chips.
 
-    port       - port # for AD1816A chip (PnP setup)
-    mpu_port   - port # for MPU-401 UART (PnP setup)
-    fm_port    - port # for OPL3 (PnP setup)
-    irq                - IRQ # for AD1816A chip (PnP setup)
-    mpu_irq    - IRQ # for MPU-401 UART (PnP setup)
-    dma1       - first DMA # for AD1816A chip (PnP setup)
-    dma2       - second DMA # for AD1816A chip (PnP setup)
     clockfreq   - Clock frequency for AD1816A chip (default = 0, 33000Hz)
     
     This module supports multiple cards, autoprobe and PnP.
@@ -201,14 +196,6 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
 
     Module for sound cards based on Avance Logic ALS100/ALS120 ISA chips.
 
-    port       - port # for ALS100 (SB16) chip (PnP setup)
-    irq                - IRQ # for ALS100 (SB16) chip (PnP setup)
-    dma8       - 8-bit DMA # for ALS100 (SB16) chip (PnP setup)
-    dma16      - 16-bit DMA # for ALS100 (SB16) chip (PnP setup)
-    mpu_port   - port # for MPU-401 UART (PnP setup)
-    mpu_irq    - IRQ # for MPU-401 (PnP setup)
-    fm_port    - port # for OPL3 FM (PnP setup)
-    
     This module supports multiple cards, autoprobe and PnP.
 
     The power-management is supported.
@@ -302,15 +289,6 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
 
     Module for sound cards based on Aztech System AZT2320 ISA chip (PnP only).
 
-    port       - port # for AZT2320 chip (PnP setup)
-    wss_port   - port # for WSS (PnP setup)
-    mpu_port   - port # for MPU-401 UART (PnP setup)
-    fm_port    - FM port # for AZT2320 chip (PnP setup)
-    irq                - IRQ # for AZT2320 (WSS) chip (PnP setup)
-    mpu_irq    - IRQ # for MPU-401 UART (PnP setup)
-    dma1       - 1st DMA # for AZT2320 (WSS) chip (PnP setup)
-    dma2       - 2nd DMA # for AZT2320 (WSS) chip (PnP setup)
-    
     This module supports multiple cards, PnP and autoprobe.
     
     The power-management is supported.
@@ -350,6 +328,10 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
 
     Module for sound cards based on C-Media CMI8330 ISA chips.
 
+    isapnp     - ISA PnP detection - 0 = disable, 1 = enable (default)
+
+    with isapnp=0, the following options are available:
+
     wssport    - port # for CMI8330 chip (WSS)
     wssirq     - IRQ # for CMI8330 chip (WSS)
     wssdma     - first DMA # for CMI8330 chip (WSS)
@@ -404,6 +386,10 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
 
     Module for sound cards based on CS4232/CS4232A ISA chips.
 
+    isapnp     - ISA PnP detection - 0 = disable, 1 = enable (default)
+
+    with isapnp=0, the following options are available:
+
     port       - port # for CS4232 chip (PnP setup - 0x534)
     cport      - control port # for CS4232 chip (PnP setup - 0x120,0x210,0xf00)
     mpu_port   - port # for MPU-401 UART (PnP setup - 0x300), -1 = disable
@@ -412,10 +398,10 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
     mpu_irq    - IRQ # for MPU-401 UART (9,11,12,15)
     dma1       - first DMA # for CS4232 chip (0,1,3)
     dma2       - second DMA # for Yamaha CS4232 chip (0,1,3), -1 = disable
-    isapnp     - ISA PnP detection - 0 = disable, 1 = enable (default)
     
     This module supports multiple cards. This module does not support autoprobe
-    thus main port must be specified!!! Other ports are optional.
+    (if ISA PnP is not used) thus main port must be specified!!! Other ports are
+    optional.
 
     The power-management is supported.
     
@@ -425,6 +411,10 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
     Module for sound cards based on CS4235/CS4236/CS4236B/CS4237B/
                                    CS4238B/CS4239 ISA chips.
 
+    isapnp     - ISA PnP detection - 0 = disable, 1 = enable (default)
+
+    with isapnp=0, the following options are available:
+
     port       - port # for CS4236 chip (PnP setup - 0x534)
     cport      - control port # for CS4236 chip (PnP setup - 0x120,0x210,0xf00)
     mpu_port   - port # for MPU-401 UART (PnP setup - 0x300), -1 = disable
@@ -433,7 +423,6 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
     mpu_irq    - IRQ # for MPU-401 UART (9,11,12,15)
     dma1       - first DMA # for CS4236 chip (0,1,3)
     dma2       - second DMA # for CS4236 chip (0,1,3), -1 = disable
-    isapnp     - ISA PnP detection - 0 = disable, 1 = enable (default)
     
     This module supports multiple cards. This module does not support autoprobe
     (if ISA PnP is not used) thus main port and control port must be
@@ -503,13 +492,6 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
     Module for Diamond Technologies DT-019X / Avance Logic ALS-007 (PnP
     only)
 
-    port       - Port # (PnP setup)
-    mpu_port   - Port # for MPU-401 (PnP setup)
-    fm_port    - Port # for FM OPL-3 (PnP setup)
-    irq                - IRQ # (PnP setup)
-    mpu_irq    - IRQ # for MPU-401 (PnP setup)
-    dma8       - DMA # (PnP setup)
-
     This module supports multiple cards.  This module is enabled only with
     ISA PnP support.
 
@@ -607,10 +589,6 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
 
     Module for sound cards based on ESS ES968 chip (PnP only).
 
-    port       - port # for ES968 (SB8) chip (PnP setup)
-    irq                - IRQ # for ES968 (SB8) chip (PnP setup)
-    dma1       - DMA # for ES968 (SB8) chip (PnP setup)
-    
     This module supports multiple cards, PnP and autoprobe.
     
     The power-management is supported.
@@ -633,13 +611,16 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
 
     Module for ESS AudioDrive ES-18xx sound cards.
 
+    isapnp     - ISA PnP detection - 0 = disable, 1 = enable (default)
+
+    with isapnp=0, the following options are available:
+
     port       - port # for ES-18xx chip (0x220,0x240,0x260)
     mpu_port   - port # for MPU-401 port (0x300,0x310,0x320,0x330), -1 = disable (default)
     fm_port    - port # for FM (optional, not used)
     irq                - IRQ # for ES-18xx chip (5,7,9,10)
     dma1       - first DMA # for ES-18xx chip (0,1,3)
     dma2       - first DMA # for ES-18xx chip (0,1,3)
-    isapnp     - ISA PnP detection - 0 = disable, 1 = enable (default)
 
     This module supports multiple cards, ISA PnP and autoprobe (without MPU-401
     port if native ISA PnP routines are not used).
@@ -763,9 +744,12 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
                VIA VT8251/VT8237A,
                SIS966, ULI M5461
 
+    [Multiple options for each card instance]
     model      - force the model name
     position_fix - Fix DMA pointer (0 = auto, 1 = none, 2 = POSBUF, 3 = FIFO size)
     probe_mask  - Bitmask to probe codecs (default = -1, meaning all slots)
+    
+    [Single (global) options]
     single_cmd  - Use single immediate commands to communicate with
                codecs (for debugging only)
     enable_msi - Enable Message Signaled Interrupt (MSI) (default = off)
@@ -774,8 +758,8 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
     power_save_controller - Reset HD-audio controller in power-saving mode
                (default = on)
 
-    This module supports one card and autoprobe.
-
+    This module supports multiple cards and autoprobe.
+    
     Each codec may have a model table for different configurations.
     If your machine isn't listed there, the default (usually minimal)
     configuration is set up.  You can pass "model=<name>" option to
@@ -817,17 +801,23 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
          will          Will laptops (PB V7900)
          replacer      Replacer 672V
          basic         fixed pin assignment (old default model)
+         test          for testing/debugging purpose, almost all controls can
+                       adjusted.  Appearing only when compiled with
+                       $CONFIG_SND_DEBUG=y
          auto          auto-config reading BIOS (default)
 
        ALC262
          fujitsu       Fujitsu Laptop
          hp-bpc        HP xw4400/6400/8400/9400 laptops
          hp-bpc-d7000  HP BPC D7000
+         hp-tc-t5735   HP Thin Client T5735
+         hp-rp5700     HP RP5700
          benq          Benq ED8
          benq-t31      Benq T31
          hippo         Hippo (ATI) with jack detection, Sony UX-90s
          hippo_1       Hippo (Benq) with jack detection
          sony-assamd   Sony ASSAMD
+         ultra         Samsung Q1 Ultra Vista model
          basic         fixed pin assignment w/o SPDIF
          auto          auto-config reading BIOS (default)
 
@@ -835,6 +825,10 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
          3stack        3-stack model
          toshiba       Toshiba A205
          acer          Acer laptops
+         dell          Dell OEM laptops (Vostro 1200)
+         test          for testing/debugging purpose, almost all controls can
+                       adjusted.  Appearing only when compiled with
+                       $CONFIG_SND_DEBUG=y
          auto          auto-config reading BIOS (default)
 
        ALC662
@@ -843,6 +837,8 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
          3stack-6ch-dig 3-stack (6-channel) with SPDIF
          6stack-dig     6-stack with SPDIF
          lenovo-101e    Lenovo laptop
+         eeepc-p701    ASUS Eeepc P701
+         eeepc-ep20    ASUS Eeepc EP20
          auto          auto-config reading BIOS (default)
 
        ALC882/885
@@ -877,6 +873,8 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
          haier-w66     Haier W66
          6stack-hp     HP machines with 6stack (Nettle boards)
          3stack-hp     HP machines with 3stack (Lucknow, Samba boards)
+         6stack-dell   Dell machines with 6stack (Inspiron 530)
+         mitac         Mitac 8252D
          auto          auto-config reading BIOS (default)
 
        ALC861/660
@@ -928,6 +926,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
        AD1984
          basic         default configuration
          thinkpad      Lenovo Thinkpad T61/X61
+         dell          Dell T3400
 
        AD1986A
          6stack        6-jack, separate surrounds (default)
@@ -947,7 +946,10 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
          auto          auto-config reading BIOS (default)
        
        Conexant 5045
-         laptop        Laptop config 
+         laptop-hpsense    Laptop with HP sense (old model laptop)
+         laptop-micsense   Laptop with Mic sense (old model fujitsu)
+         laptop-hpmicsense Laptop with HP and Mic senses
+         benq          Benq R55E
          test          for testing/debugging purpose, almost all controls
                        can be adjusted.  Appearing only when compiled with
                        $CONFIG_SND_DEBUG=y
@@ -960,6 +962,10 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
                        can be adjusted.  Appearing only when compiled with
                        $CONFIG_SND_DEBUG=y
 
+       Conexant 5051
+         laptop        Basic Laptop config (default)
+         hp            HP Spartan laptop
+
        STAC9200
          ref           Reference board
          dell-d21      Dell (unknown)
@@ -1091,6 +1097,15 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
 
     See hdspm.txt for details.
 
+  Module snd-hifier
+  -----------------
+
+    Module for the MediaTek/TempoTec HiFier Fantasia sound card.
+
+    This module supports autoprobe and multiple cards.
+
+    Power management is _not_ supported.
+
   Module snd-ice1712
   ------------------
 
@@ -1156,11 +1171,14 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
                        * Chaintech 9CJS
                        * Chaintech AV-710
                        * Shuttle SN25P
+                       * Onkyo SE-90PCI
+                       * Onkyo SE-200PCI
 
     model       - Use the given board model, one of the following:
                  revo51, revo71, amp2000, prodigy71, prodigy71lt,
                  prodigy192, aureon51, aureon71, universe, ap192,
-                 k8x800, phase22, phase28, ms300, av710
+                 k8x800, phase22, phase28, ms300, av710, se200pci,
+                 se90pci
 
     This module supports multiple cards and autoprobe.
 
@@ -1257,15 +1275,19 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
     Module for Gravis UltraSound PnP, Dynasonic 3-D/Pro, STB Sound Rage 32
     and other sound cards based on AMD InterWave (tm) chip.
   
-    port       - port # for InterWave chip (0x210,0x220,0x230,0x240,0x250,0x260)
-    irq                - IRQ # for InterWave chip (3,5,9,11,12,15)
-    dma1       - DMA # for InterWave chip (0,1,3,5,6,7)
-    dma2       - DMA # for InterWave chip (0,1,3,5,6,7,-1=disable)
     joystick_dac - 0 to 31, (0.59V-4.52V or 0.389V-2.98V)
     midi       - 1 = MIDI UART enable, 0 = MIDI UART disable (default)
     pcm_voices - reserved PCM voices for the synthesizer (default 2)
     effect     - 1 = InterWave effects enable (default 0);
                   requires 8 voices
+    isapnp     - ISA PnP detection - 0 = disable, 1 = enable (default)
+
+    with isapnp=0, the following options are available:
+
+    port       - port # for InterWave chip (0x210,0x220,0x230,0x240,0x250,0x260)
+    irq                - IRQ # for InterWave chip (3,5,9,11,12,15)
+    dma1       - DMA # for InterWave chip (0,1,3,5,6,7)
+    dma2       - DMA # for InterWave chip (0,1,3,5,6,7,-1=disable)
 
     This module supports multiple cards, autoprobe and ISA PnP.
 
@@ -1276,16 +1298,20 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
     and other sound cards based on AMD InterWave (tm) chip with TEA6330T
     circuit for extended control of bass, treble and master volume.
   
-    port       - port # for InterWave chip (0x210,0x220,0x230,0x240,0x250,0x260)
-    port_tc    - tone control (i2c bus) port # for TEA6330T chip (0x350,0x360,0x370,0x380)
-    irq                - IRQ # for InterWave chip (3,5,9,11,12,15)
-    dma1       - DMA # for InterWave chip (0,1,3,5,6,7)
-    dma2       - DMA # for InterWave chip (0,1,3,5,6,7,-1=disable)
     joystick_dac - 0 to 31, (0.59V-4.52V or 0.389V-2.98V)
     midi       - 1 = MIDI UART enable, 0 = MIDI UART disable (default)
     pcm_voices - reserved PCM voices for the synthesizer (default 2)
     effect     - 1 = InterWave effects enable (default 0);
                   requires 8 voices
+    isapnp     - ISA PnP detection - 0 = disable, 1 = enable (default)
+
+    with isapnp=0, the following options are available:
+
+    port       - port # for InterWave chip (0x210,0x220,0x230,0x240,0x250,0x260)
+    port_tc    - tone control (i2c bus) port # for TEA6330T chip (0x350,0x360,0x370,0x380)
+    irq                - IRQ # for InterWave chip (3,5,9,11,12,15)
+    dma1       - DMA # for InterWave chip (0,1,3,5,6,7)
+    dma2       - DMA # for InterWave chip (0,1,3,5,6,7,-1=disable)
 
     This module supports multiple cards, autoprobe and ISA PnP.
 
@@ -1473,6 +1499,10 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
 
     Module for Yamaha OPL3-SA2/SA3 sound cards.
 
+    isapnp     - ISA PnP detection - 0 = disable, 1 = enable (default)
+
+    with isapnp=0, the following options are available:
+
     port       - control port # for OPL3-SA chip (0x370)
     sb_port    - SB port # for OPL3-SA chip (0x220,0x240)
     wss_port   - WSS port # for OPL3-SA chip (0x530,0xe80,0xf40,0x604)
@@ -1481,7 +1511,6 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
     irq                - IRQ # for OPL3-SA chip (5,7,9,10)
     dma1       - first DMA # for Yamaha OPL3-SA chip (0,1,3)
     dma2       - second DMA # for Yamaha OPL3-SA chip (0,1,3), -1 = disable
-    isapnp     - ISA PnP detection - 0 = disable, 1 = enable (default)
     
     This module supports multiple cards and ISA PnP.  It does not support
     autoprobe (if ISA PnP is not used) thus all ports must be specified!!!
@@ -1494,6 +1523,10 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
     Module for sound cards based on OPTi 82c92x and Analog Devices AD1848 chips.
     Module works with OAK Mozart cards as well.
     
+    isapnp    - ISA PnP detection - 0 = disable, 1 = enable (default)
+
+    with isapnp=0, the following options are available:
+
     port      - port # for WSS chip (0x530,0xe80,0xf40,0x604)
     mpu_port  - port # for MPU-401 UART (0x300,0x310,0x320,0x330)
     fm_port   - port # for OPL3 device (0x388)
@@ -1508,6 +1541,10 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
 
     Module for sound cards based on OPTi 82c92x and Crystal CS4231 chips.
     
+    isapnp    - ISA PnP detection - 0 = disable, 1 = enable (default)
+
+    with isapnp=0, the following options are available:
+
     port      - port # for WSS chip (0x530,0xe80,0xf40,0x604)
     mpu_port  - port # for MPU-401 UART (0x300,0x310,0x320,0x330)
     fm_port   - port # for OPL3 device (0x388)
@@ -1523,6 +1560,10 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
 
     Module for sound cards based on OPTi 82c93x chips.
     
+    isapnp    - ISA PnP detection - 0 = disable, 1 = enable (default)
+
+    with isapnp=0, the following options are available:
+
     port      - port # for WSS chip (0x530,0xe80,0xf40,0x604)
     mpu_port  - port # for MPU-401 UART (0x300,0x310,0x320,0x330)
     fm_port   - port # for OPL3 device (0x388)
@@ -1533,6 +1574,22 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
 
     This module supports only one card, autoprobe and PnP.
 
+  Module snd-oxygen
+  -----------------
+
+    Module for sound cards based on the C-Media CMI8788 chip:
+    * Asound A-8788
+    * AuzenTech X-Meridian
+    * Bgears b-Enspirer
+    * Club3D Theatron DTS
+    * HT-Omega Claro
+    * Razer Barracuda AC-1
+    * Sondigo Inferno
+
+    This module supports autoprobe and multiple cards.
+
+    Power management is _not_ supported.
+
   Module snd-pcxhr
   ----------------
 
@@ -1647,6 +1704,12 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
                                          SoundBlaster AWE 32 (PnP),
                                          SoundBlaster AWE 64 PnP
 
+    mic_agc    - Mic Auto-Gain-Control - 0 = disable, 1 = enable (default)
+    csp                - ASP/CSP chip support - 0 = disable (default), 1 = enable
+    isapnp     - ISA PnP detection - 0 = disable, 1 = enable (default)
+
+    with isapnp=0, the following options are available:
+
     port       - port # for SB DSP 4.x chip (0x220,0x240,0x260)
     mpu_port   - port # for MPU-401 UART (0x300,0x330), -1 = disable
     awe_port   - base port # for EMU8000 synthesizer (0x620,0x640,0x660)
@@ -1654,9 +1717,6 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
     irq                - IRQ # for SB DSP 4.x chip (5,7,9,10)
     dma8       - 8-bit DMA # for SB DSP 4.x chip (0,1,3)
     dma16      - 16-bit DMA # for SB DSP 4.x chip (5,6,7)
-    mic_agc    - Mic Auto-Gain-Control - 0 = disable, 1 = enable (default)
-    csp                - ASP/CSP chip support - 0 = disable (default), 1 = enable
-    isapnp     - ISA PnP detection - 0 = disable, 1 = enable (default)
     
     This module supports multiple cards, autoprobe and ISA PnP.
 
@@ -1739,18 +1799,21 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
 
     Module for Turtle Beach Maui, Tropez and Tropez+ sound cards.
 
+    use_cs4232_midi - Use CS4232 MPU-401 interface
+                      (inaccessibly located inside your computer)
+    isapnp          - ISA PnP detection - 0 = disable, 1 = enable (default)
+
+    with isapnp=0, the following options are available:
+
     cs4232_pcm_port - Port # for CS4232 PCM interface.
     cs4232_pcm_irq  - IRQ # for CS4232 PCM interface (5,7,9,11,12,15).
     cs4232_mpu_port - Port # for CS4232 MPU-401 interface.
     cs4232_mpu_irq  - IRQ # for CS4232 MPU-401 interface (9,11,12,15).
-    use_cs4232_midi - Use CS4232 MPU-401 interface
-                      (inaccessibly located inside your computer)
     ics2115_port    - Port # for ICS2115
     ics2115_irq     - IRQ # for ICS2115
     fm_port         - FM OPL-3 Port #
     dma1            - DMA1 # for CS4232 PCM interface.
     dma2            - DMA2 # for CS4232 PCM interface.
-    isapnp          - ISA PnP detection - 0 = disable, 1 = enable (default)
 
     The below are options for wavefront_synth features:
     wf_raw         - Assume that we need to boot the OS (default:no)
@@ -1965,6 +2028,16 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
     
     This module supports multiple cards.
 
+  Module snd-virtuoso
+  -------------------
+
+    Module for sound cards based on the Asus AV200 chip, i.e.,
+    Xonar D2 and Xonar D2X.
+
+    This module supports autoprobe and multiple cards.
+
+    Power management is _not_ supported.
+
   Module snd-vx222
   ----------------
 
@@ -2135,6 +2208,23 @@ alias sound-slot-1 snd-ens1371
 In this example, the interwave card is always loaded as the first card
 (index 0) and ens1371 as the second (index 1).
 
+Alternative (and new) way to fixate the slot assignment is to use
+"slots" option of snd module.  In the case above, specify like the
+following: 
+
+options snd slots=snd-interwave,snd-ens1371
+
+Then, the first slot (#0) is reserved for snd-interwave driver, and
+the second (#1) for snd-ens1371.  You can omit index option in each
+driver if slots option is used (although you can still have them at
+the same time as long as they don't conflict).
+
+The slots option is especially useful for avoiding the possible
+hot-plugging and the resultant slot conflict.  For example, in the
+case above again, the first two slots are already reserved.  If any
+other driver (e.g. snd-usb-audio) is loaded before snd-interwave or
+snd-ens1371, it will be assigned to the third or later slot.
+
 
 ALSA PCM devices to OSS devices mapping
 =======================================
index 2c3fc3cb3b6bdced5bf553b223719f8b370a6c26..b03df4d4795c6767b79bed4125b07bbdf64fc823 100644 (file)
@@ -18,7 +18,7 @@
       </affiliation>
      </author>
 
-     <date>September 10, 2007</date>
+     <date>Oct 15, 2007</date>
      <edition>0.3.7</edition>
 
     <abstract>
@@ -67,7 +67,7 @@
       This document describes how to write an
       <ulink url="http://www.alsa-project.org/"><citetitle>
       ALSA (Advanced Linux Sound Architecture)</citetitle></ulink>
-      driver. The document focuses mainly on the PCI soundcard.
+      driver. The document focuses mainly on PCI soundcards.
       In the case of other device types, the API might
       be different, too. However, at least the ALSA kernel API is
       consistent, and therefore it would be still a bit help for
     </para>
 
     <para>
-    The target of this document is ones who already have enough
-    skill of C language and have the basic knowledge of linux
-    kernel programming.  This document doesn't explain the general
-    topics of linux kernel codes and doesn't cover the detail of
-    implementation of each low-level driver.  It describes only how is
+    This document targets people who already have enough
+    C language skills and have basic linux kernel programming
+    knowledge.  This document doesn't explain the general
+    topic of linux kernel coding and doesn't cover low-level
+    driver implementation details. It only describes
     the standard way to write a PCI sound driver on ALSA.
     </para>
 
     <para>
-      If you are already familiar with the older ALSA ver.0.5.x, you
-    can check the drivers such as <filename>es1938.c</filename> or
-    <filename>maestro3.c</filename> which have also almost the same
+      If you are already familiar with the older ALSA ver.0.5.x API, you
+    can check the drivers such as <filename>sound/pci/es1938.c</filename> or
+    <filename>sound/pci/maestro3.c</filename> which have also almost the same
     code-base in the ALSA 0.5.x tree, so you can compare the differences.
     </para>
 
     <para>
-      This document is still a draft version. Any feedbacks and
+      This document is still a draft version. Any feedback and
     corrections, please!!
     </para>
   </preface>
     <section id="file-tree-general">
       <title>General</title>
       <para>
-        The ALSA drivers are provided in the two ways.
+        The ALSA drivers are provided in two ways.
       </para>
 
       <para>
       ALSA's ftp site, and another is the 2.6 (or later) Linux kernel
       tree. To synchronize both, the ALSA driver tree is split into
       two different trees: alsa-kernel and alsa-driver. The former
-      contains purely the source codes for the Linux 2.6 (or later)
+      contains purely the source code for the Linux 2.6 (or later)
       tree. This tree is designed only for compilation on 2.6 or
       later environment. The latter, alsa-driver, contains many subtle
-      files for compiling the ALSA driver on the outside of Linux
-      kernel like configure script, the wrapper functions for older,
-      2.2 and 2.4 kernels, to adapt the latest kernel API,
+      files for compiling ALSA drivers outside of the Linux kernel tree,
+      wrapper functions for older 2.2 and 2.4 kernels, to adapt the latest kernel API,
       and additional drivers which are still in development or in
       tests.  The drivers in alsa-driver tree will be moved to
-      alsa-kernel (eventually 2.6 kernel tree) once when they are
+      alsa-kernel (and eventually to the 2.6 kernel tree) when they are
       finished and confirmed to work fine.
       </para>
 
     <section id="file-tree-core-directory">
       <title>core directory</title>
       <para>
-        This directory contains the middle layer, that is, the heart
+        This directory contains the middle layer which is the heart
       of ALSA drivers. In this directory, the native ALSA modules are
       stored. The sub-directories contain different modules and are
       dependent upon the kernel config. 
           The codes for PCM and mixer OSS emulation modules are stored
         in this directory. The rawmidi OSS emulation is included in
         the ALSA rawmidi code since it's quite small. The sequencer
-        code is stored in core/seq/oss directory (see
+        code is stored in <filename>core/seq/oss</filename> directory (see
         <link linkend="file-tree-core-directory-seq-oss"><citetitle>
         below</citetitle></link>).
         </para>
       <section id="file-tree-core-directory-seq">
         <title>core/seq</title>
         <para>
-          This and its sub-directories are for the ALSA
+          This directory and its sub-directories are for the ALSA
         sequencer. This directory contains the sequencer core and
         primary sequencer modules such like snd-seq-midi,
         snd-seq-virmidi, etc. They are compiled only when
       <title>include directory</title>
       <para>
         This is the place for the public header files of ALSA drivers,
-      which are to be exported to the user-space, or included by
+      which are to be exported to user-space, or included by
       several files at different directories. Basically, the private
       header files should not be placed in this directory, but you may
-      still find files there, due to historical reason :) 
+      still find files there, due to historical reasons :) 
       </para>
     </section>
 
     <section id="file-tree-drivers-directory">
       <title>drivers directory</title>
       <para>
-        This directory contains the codes shared among different drivers
-      on the different architectures.  They are hence supposed not to be
+        This directory contains code shared among different drivers
+      on different architectures.  They are hence supposed not to be
       architecture-specific.
       For example, the dummy pcm driver and the serial MIDI
       driver are found in this directory. In the sub-directories,
-      there are the codes for components which are independent from
+      there is code for components which are independent from
       bus and cpu architectures. 
       </para>
 
 
       <para>
         Although there is a standard i2c layer on Linux, ALSA has its
-      own i2c codes for some cards, because the soundcard needs only a
+      own i2c code for some cards, because the soundcard needs only a
       simple operation and the standard i2c API is too complicated for
       such a purpose. 
       </para>
 
         <para>
           So far, there is only Emu8000/Emu10k1 synth driver under
-        synth/emux sub-directory. 
+        the <filename>synth/emux</filename> sub-directory. 
         </para>
     </section>
 
     <section id="file-tree-pci-directory">
       <title>pci directory</title>
       <para>
-        This and its sub-directories hold the top-level card modules
-      for PCI soundcards and the codes specific to the PCI BUS.
+        This directory and its sub-directories hold the top-level card modules
+      for PCI soundcards and the code specific to the PCI BUS.
       </para>
 
       <para>
-        The drivers compiled from a single file is stored directly on
-      pci directory, while the drivers with several source files are
-      stored on its own sub-directory (e.g. emu10k1, ice1712). 
+        The drivers compiled from a single file are stored directly
+      in the pci directory, while the drivers with several source files are
+      stored on their own sub-directory (e.g. emu10k1, ice1712). 
       </para>
     </section>
 
     <section id="file-tree-isa-directory">
       <title>isa directory</title>
       <para>
-        This and its sub-directories hold the top-level card modules
+        This directory and its sub-directories hold the top-level card modules
       for ISA soundcards. 
       </para>
     </section>
     <section id="file-tree-arm-ppc-sparc-directories">
       <title>arm, ppc, and sparc directories</title>
       <para>
-        These are for the top-level card modules which are
-      specific to each given architecture
+        They are used for top-level card modules which are
+      specific to one of these architectures
       </para>
     </section>
 
     <section id="file-tree-usb-directory">
       <title>usb directory</title>
       <para>
-        This contains the USB-audio driver. On the latest version, the
-      USB MIDI driver is integrated together with usb-audio driver. 
+        This directory contains the USB-audio driver. In the latest version, the
+      USB MIDI driver is integrated in the usb-audio driver. 
       </para>
     </section>
 
       <title>pcmcia directory</title>
       <para>
         The PCMCIA, especially PCCard drivers will go here. CardBus
-      drivers will be on pci directory, because its API is identical
-      with the standard PCI cards. 
+      drivers will be in the pci directory, because their API is identical
+      to that of standard PCI cards. 
       </para>
     </section>
 
     <section id="file-tree-oss-directory">
       <title>oss directory</title>
       <para>
-        The OSS/Lite source files are stored here on Linux 2.6 (or
-      later) tree. (In the ALSA driver tarball, it's empty, of course :) 
+        The OSS/Lite source files are stored here in Linux 2.6 (or
+      later) tree. In the ALSA driver tarball, this directory is empty,
+      of course :) 
       </para>
     </section>
   </chapter>
     <section id="basic-flow-outline">
       <title>Outline</title>
       <para>
-        The minimum flow of PCI soundcard is like the following:
+        The minimum flow for PCI soundcards is as follows:
 
         <itemizedlist>
           <listitem><para>define the PCI ID table (see the section
           </citetitle></link>).</para></listitem> 
           <listitem><para>create <function>probe()</function> callback.</para></listitem>
           <listitem><para>create <function>remove()</function> callback.</para></listitem>
-          <listitem><para>create pci_driver table which contains the three pointers above.</para></listitem>
-          <listitem><para>create <function>init()</function> function just calling <function>pci_register_driver()</function> to register the pci_driver table defined above.</para></listitem>
-          <listitem><para>create <function>exit()</function> function to call <function>pci_unregister_driver()</function> function.</para></listitem>
+          <listitem><para>create a <structname>pci_driver</structname> structure
+         containing the three pointers above.</para></listitem>
+          <listitem><para>create an <function>init()</function> function just calling
+         the <function>pci_register_driver()</function> to register the pci_driver table
+         defined above.</para></listitem>
+          <listitem><para>create an <function>exit()</function> function to call
+         the <function>pci_unregister_driver()</function> function.</para></listitem>
         </itemizedlist>
       </para>
     </section>
       <para>
         The code example is shown below. Some parts are kept
       unimplemented at this moment but will be filled in the
-      succeeding sections. The numbers in comment lines of
-      <function>snd_mychip_probe()</function> function are the
-      markers
+      next sections. The numbers in the comment lines of the
+      <function>snd_mychip_probe()</function> function
+      refer to details explained in the following section
 
         <example>
-          <title>Basic Flow for PCI Drivers Example</title>
+          <title>Basic Flow for PCI Drivers Example</title>
           <programlisting>
 <![CDATA[
-  #include <sound/driver.h>
   #include <linux/init.h>
   #include <linux/pci.h>
   #include <linux/slab.h>
   #include <sound/initval.h>
 
   /* module parameters (see "Module Parameters") */
+  /* SNDRV_CARDS: maximum number of cards supported by this module */
   static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
   static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
   static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
   /* definition of the chip-specific record */
   struct mychip {
           struct snd_card *card;
-          /* rest of implementation will be in the section
-           * "PCI Resource Managements"
+          /* the rest of the implementation will be in section
+           * "PCI Resource Management"
            */
   };
 
   /* chip-specific destructor
-   * (see "PCI Resource Managements")
+   * (see "PCI Resource Management")
    */
   static int snd_mychip_free(struct mychip *chip)
   {
           *rchip = NULL;
 
           /* check PCI availability here
-           * (see "PCI Resource Managements")
+           * (see "PCI Resource Management")
            */
           ....
 
           chip->card = card;
 
           /* rest of initialization here; will be implemented
-           * later, see "PCI Resource Managements"
+           * later, see "PCI Resource Management"
            */
           ....
 
           return 0;
   }
 
-  /* destructor -- see "Destructor" sub-section */
+  /* destructor -- see the "Destructor" sub-section */
   static void __devexit snd_mychip_remove(struct pci_dev *pci)
   {
           snd_card_free(pci_get_drvdata(pci));
     <section id="basic-flow-constructor">
       <title>Constructor</title>
       <para>
-        The real constructor of PCI drivers is probe callback. The
-      probe callback and other component-constructors which are called
-      from probe callback should be defined with
-      <parameter>__devinit</parameter> prefix. You 
-      cannot use <parameter>__init</parameter> prefix for them,
+        The real constructor of PCI drivers is the <function>probe</function> callback.
+      The <function>probe</function> callback and other component-constructors which are called
+      from the <function>probe</function> callback should be defined with
+      the <parameter>__devinit</parameter> prefix. You 
+      cannot use the <parameter>__init</parameter> prefix for them,
       because any PCI device could be a hotplug device. 
       </para>
 
       <para>
-        In the probe callback, the following scheme is often used.
+        In the <function>probe</function> callback, the following scheme is often used.
       </para>
 
       <section id="basic-flow-constructor-device-index">
         </para>
 
         <para>
-          At each time probe callback is called, check the
+          Each time the <function>probe</function> callback is called, check the
         availability of the device. If not available, simply increment
         the device index and returns. dev will be incremented also
         later (<link
         </para>
 
         <para>
-          The detail will be explained in the section
+          The details will be explained in the section
           <link linkend="card-management-card-instance"><citetitle>
           Management of Cards and Components</citetitle></link>.
         </para>
             </programlisting>
           </informalexample>
 
-          The detail will be explained in the section <link
+          The details will be explained in the section <link
         linkend="pci-resource"><citetitle>PCI Resource
-        Managements</citetitle></link>.
+        Management</citetitle></link>.
         </para>
       </section>
 
           </informalexample>
 
           The driver field holds the minimal ID string of the
-        chip. This is referred by alsa-lib's configurator, so keep it
+        chip. This is used by alsa-lib's configurator, so keep it
         simple but unique. 
           Even the same driver can have different driver IDs to
         distinguish the functionality of each chip type. 
 
         <para>
           The shortname field is a string shown as more verbose
-        name. The longname field contains the information which is
+        name. The longname field contains the information
         shown in <filename>/proc/asound/cards</filename>. 
         </para>
       </section>
           </informalexample>
 
           In the above, the card record is stored. This pointer is
-        referred in the remove callback and power-management
+        used in the remove callback and power-management
         callbacks, too. 
         </para>
       </section>
         <informalexample>
           <programlisting>
 <![CDATA[
-  #include <sound/driver.h>
   #include <linux/init.h>
   #include <linux/pci.h>
   #include <linux/slab.h>
         </informalexample>
 
        where the last one is necessary only when module options are
-      defined in the source file.  If the codes are split to several
-      files, the file without module options don't need them.
+      defined in the source file.  If the code is split into several
+      files, the files without module options don't need them.
       </para>
 
       <para>
-        In addition to them, you'll need
-      <filename>&lt;linux/interrupt.h&gt;</filename> for the interrupt
-      handling, and <filename>&lt;asm/io.h&gt;</filename> for the i/o
-      access. If you use <function>mdelay()</function> or
+        In addition to these headers, you'll need
+      <filename>&lt;linux/interrupt.h&gt;</filename> for interrupt
+      handling, and <filename>&lt;asm/io.h&gt;</filename> for I/O
+      access. If you use the <function>mdelay()</function> or
       <function>udelay()</function> functions, you'll need to include
-      <filename>&lt;linux/delay.h&gt;</filename>, too. 
+      <filename>&lt;linux/delay.h&gt;</filename> too. 
       </para>
 
       <para>
-      The ALSA interfaces like PCM or control API are defined in other
-      header files as <filename>&lt;sound/xxx.h&gt;</filename>.
+      The ALSA interfaces like the PCM and control APIs are defined in other
+      <filename>&lt;sound/xxx.h&gt;</filename> header files.
       They have to be included after
       <filename>&lt;sound/core.h&gt;</filename>.
       </para>
 
       <para>
       A card record is the headquarters of the soundcard.  It manages
-      the list of whole devices (components) on the soundcard, such as
+      the whole list of devices (components) on the soundcard, such as
       PCM, mixers, MIDI, synthesizer, and so on.  Also, the card
       record holds the ID and the name strings of the card, manages
       the root of proc files, and controls the power-management states
       and hotplug disconnections.  The component list on the card
-      record is used to manage the proper releases of resources at
+      record is used to manage the correct release of resources at
       destruction. 
       </para>
 
         <constant>THIS_MODULE</constant>),
         and the size of extra-data space.  The last argument is used to
         allocate card-&gt;private_data for the
-        chip-specific data.  Note that this data
-        <emphasis>is</emphasis> allocated by
-        <function>snd_card_new()</function>.
+        chip-specific data.  Note that these data
+        are allocated by <function>snd_card_new()</function>.
       </para>
     </section>
 
       <title>Components</title>
       <para>
         After the card is created, you can attach the components
-      (devices) to the card instance. On ALSA driver, a component is
+      (devices) to the card instance. In an ALSA driver, a component is
       represented as a struct <structname>snd_device</structname> object.
       A component can be a PCM instance, a control interface, a raw
-      MIDI interface, etc.  Each of such instances has one component
+      MIDI interface, etc.  Each such instance has one component
       entry.
       </para>
 
       (<constant>SNDRV_DEV_XXX</constant>), the data pointer, and the
       callback pointers (<parameter>&amp;ops</parameter>). The
       device-level defines the type of components and the order of
-      registration and de-registration.  For most of components, the
+      registration and de-registration.  For most components, the
       device-level is already defined.  For a user-defined component,
       you can use <constant>SNDRV_DEV_LOWLEVEL</constant>.
       </para>
       <para>
       This function itself doesn't allocate the data space. The data
       must be allocated manually beforehand, and its pointer is passed
-      as the argument. This pointer is used as the identifier
-      (<parameter>chip</parameter> in the above example) for the
-      instance. 
+      as the argument. This pointer is used as the
+      (<parameter>chip</parameter> identifier in the above example)
+      for the instance. 
       </para>
 
       <para>
-        Each ALSA pre-defined component such as ac97 or pcm calls
+        Each pre-defined ALSA component such as ac97 and pcm calls
       <function>snd_device_new()</function> inside its
       constructor. The destructor for each component is defined in the
       callback pointers.  Hence, you don't need to take care of
       </para>
 
       <para>
-        If you would like to create your own component, you need to
-      set the destructor function to dev_free callback in
-      <parameter>ops</parameter>, so that it can be released
-      automatically via <function>snd_card_free()</function>. The
-      example will be shown later as an implementation of a
-      chip-specific data. 
+        If you wish to create your own component, you need to
+      set the destructor function to the dev_free callback in
+      the <parameter>ops</parameter>, so that it can be released
+      automatically via <function>snd_card_free()</function>.
+      The next example will show an implementation of chip-specific
+      data.
       </para>
     </section>
 
     <section id="card-management-chip-specific">
       <title>Chip-Specific Data</title>
       <para>
-      The chip-specific information, e.g. the i/o port address, its
+      Chip-specific information, e.g. the I/O port address, its
       resource pointer, or the irq number, is stored in the
       chip-specific record.
 
       </para>
 
       <para>
-        In general, there are two ways to allocate the chip record.
+        In general, there are two ways of allocating the chip record.
       </para>
 
       <section id="card-management-chip-specific-snd-card-new">
         <title>1. Allocating via <function>snd_card_new()</function>.</title>
         <para>
-          As mentioned above, you can pass the extra-data-length to the 4th argument of <function>snd_card_new()</function>, i.e.
+          As mentioned above, you can pass the extra-data-length
+         to the 4th argument of <function>snd_card_new()</function>, i.e.
 
           <informalexample>
             <programlisting>
             </programlisting>
           </informalexample>
 
-          whether struct <structname>mychip</structname> is the type of the chip record.
+          struct <structname>mychip</structname> is the type of the chip record.
         </para>
 
         <para>
       <title>Registration and Release</title>
       <para>
         After all components are assigned, register the card instance
-      by calling <function>snd_card_register()</function>. The access
-      to the device files are enabled at this point. That is, before
+      by calling <function>snd_card_register()</function>. Access
+      to the device files is enabled at this point. That is, before
       <function>snd_card_register()</function> is called, the
       components are safely inaccessible from external side. If this
       call fails, exit the probe function after releasing the card via
 
       <para>
         For releasing the card instance, you can call simply
-      <function>snd_card_free()</function>. As already mentioned, all
+      <function>snd_card_free()</function>. As mentioned earlier, all
       components are released automatically by this call. 
       </para>
 
         As further notes, the destructors (both
       <function>snd_mychip_dev_free</function> and
       <function>snd_mychip_free</function>) cannot be defined with
-      <parameter>__devexit</parameter> prefix, because they may be
+      the <parameter>__devexit</parameter> prefix, because they may be
       called from the constructor, too, at the false path. 
       </para>
 
 
 
 <!-- ****************************************************** -->
-<!-- PCI Resource Managements  -->
+<!-- PCI Resource Management  -->
 <!-- ****************************************************** -->
   <chapter id="pci-resource">
-    <title>PCI Resource Managements</title>
+    <title>PCI Resource Management</title>
 
     <section id="pci-resource-example">
       <title>Full Code Example</title>
       <para>
-        In this section, we'll finish the chip-specific constructor,
-      destructor and PCI entries. The example code is shown first,
+        In this section, we'll complete the chip-specific constructor,
+      destructor and PCI entries. Example code is shown first,
       below. 
 
         <example>
-          <title>PCI Resource Managements Example</title>
+          <title>PCI Resource Management Example</title>
           <programlisting>
 <![CDATA[
   struct mychip {
           /* release the irq */
           if (chip->irq >= 0)
                   free_irq(chip->irq, chip);
-          /* release the i/o ports & memory */
+          /* release the I/O ports & memory */
           pci_release_regions(chip->pci);
           /* disable the PCI entry */
           pci_disable_device(chip->pci);
           .remove = __devexit_p(snd_mychip_remove),
   };
 
-  /* initialization of the module */
+  /* module initialization */
   static int __init alsa_card_mychip_init(void)
   {
           return pci_register_driver(&driver);
   }
 
-  /* clean up the module */
+  /* module clean up */
   static void __exit alsa_card_mychip_exit(void)
   {
           pci_unregister_driver(&driver);
       </para>
 
       <para>
-        In the case of PCI devices, you have to call at first
-      <function>pci_enable_device()</function> function before
+        In the case of PCI devices, you first have to call
+      the <function>pci_enable_device()</function> function before
       allocating resources. Also, you need to set the proper PCI DMA
-      mask to limit the accessed i/o range. In some cases, you might
+      mask to limit the accessed I/O range. In some cases, you might
       need to call <function>pci_set_master()</function> function,
       too.
       </para>
     <section id="pci-resource-resource-allocation">
       <title>Resource Allocation</title>
       <para>
-        The allocation of I/O ports and irqs are done via standard kernel
+        The allocation of I/O ports and irqs is done via standard kernel
       functions. Unlike ALSA ver.0.5.x., there are no helpers for
       that. And these resources must be released in the destructor
       function (see below). Also, on ALSA 0.9.x, you don't need to
-      allocate (pseudo-)DMA for PCI like ALSA 0.5.x.
+      allocate (pseudo-)DMA for PCI like in ALSA 0.5.x.
       </para>
 
       <para>
-        Now assume that this PCI device has an I/O port with 8 bytes
+        Now assume that the PCI device has an I/O port with 8 bytes
         and an interrupt. Then struct <structname>mychip</structname> will have the
         following fields:
 
       </para>
 
       <para>
-        For an i/o port (and also a memory region), you need to have
+        For an I/O port (and also a memory region), you need to have
       the resource pointer for the standard resource management. For
       an irq, you have to keep only the irq number (integer). But you
       need to initialize this number as -1 before actual allocation,
       </para>
 
       <para>
-        The allocation of an i/o port is done like this:
+        The allocation of an I/O port is done like this:
 
         <informalexample>
           <programlisting>
 
       <para>
         <!-- obsolete -->
-        It will reserve the i/o port region of 8 bytes of the given
+        It will reserve the I/O port region of 8 bytes of the given
       PCI device. The returned value, chip-&gt;res_port, is allocated
       via <function>kmalloc()</function> by
       <function>request_region()</function>. The pointer must be
-      released via <function>kfree()</function>, but there is some
-      problem regarding this. This issue will be explained more below.
+      released via <function>kfree()</function>, but there is a
+      problem with this. This issue will be explained later.
       </para>
 
       <para>
       </para>
 
       <para>
-      On the PCI bus, the interrupts can be shared. Thus,
-      <constant>IRQF_SHARED</constant> is given as the interrupt flag of
+      On the PCI bus, interrupts can be shared. Thus,
+      <constant>IRQF_SHARED</constant> is used as the interrupt flag of
       <function>request_irq()</function>. 
       </para>
 
       </para>
 
       <para>
-        I won't define the detail of the interrupt handler at this
+        I won't give details about the interrupt handler at this
         point, but at least its appearance can be explained now. The
         interrupt handler looks usually like the following: 
 
         Now let's write the corresponding destructor for the resources
       above. The role of destructor is simple: disable the hardware
       (if already activated) and release the resources. So far, we
-      have no hardware part, so the disabling is not written here. 
+      have no hardware part, so the disabling code is not written here. 
       </para>
 
       <para>
-        For releasing the resources, <quote>check-and-release</quote>
+        To release the resources, the <quote>check-and-release</quote>
         method is a safer way. For the interrupt, do like this: 
 
         <informalexample>
       <para>
         When you requested I/O ports or memory regions via
        <function>pci_request_region()</function> or
-       <function>pci_request_regions()</function> like this example,
+       <function>pci_request_regions()</function> like in this example,
        release the resource(s) using the corresponding function,
        <function>pci_release_region()</function> or
        <function>pci_release_regions()</function>.
        or <function>request_mem_region</function>, you can release it via
        <function>release_resource()</function>.  Suppose that you keep
        the resource pointer returned from <function>request_region()</function>
-       in chip-&gt;res_port, the release procedure looks like below:
+       in chip-&gt;res_port, the release procedure looks like:
 
         <informalexample>
           <programlisting>
 
       <para>
       Don't forget to call <function>pci_disable_device()</function>
-      before all finished.
+      before the end.
       </para>
 
       <para>
 
       <para>
       Again, remember that you cannot
-      set <parameter>__devexit</parameter> prefix for this destructor. 
+      use the <parameter>__devexit</parameter> prefix for this destructor. 
       </para>
 
       <para>
-      We didn't implement the hardware-disabling part in the above.
+      We didn't implement the hardware disabling part in the above.
       If you need to do this, please note that the destructor may be
       called even before the initialization of the chip is completed.
-      It would be better to have a flag to skip the hardware-disabling
+      It would be better to have a flag to skip hardware disabling
       if the hardware was not initialized yet.
       </para>
 
       <function>snd_device_new()</function> with
       <constant>SNDRV_DEV_LOWLELVEL</constant> , its destructor is 
       called at the last.  That is, it is assured that all other
-      components like PCMs and controls have been already released.
-      You don't have to call stopping PCMs, etc. explicitly, but just
-      stop the hardware in the low-level.
+      components like PCMs and controls have already been released.
+      You don't have to stop PCMs, etc. explicitly, but just
+      call low-level hardware stopping.
       </para>
 
       <para>
         The management of a memory-mapped region is almost as same as
-        the management of an i/o port. You'll need three fields like
+        the management of an I/O port. You'll need three fields like
         the following: 
 
         <informalexample>
     <section id="pci-resource-entries">
       <title>PCI Entries</title>
       <para>
-        So far, so good. Let's finish the rest of missing PCI
-      stuffs. At first, we need a
+        So far, so good. Let's finish the missing PCI
+      stuff. At first, we need a
       <structname>pci_device_id</structname> table for this
       chipset. It's a table of PCI vendor/device ID number, and some
       masks. 
 
       <para>
         The first and second fields of
-      <structname>pci_device_id</structname> struct are the vendor and
-      device IDs. If you have nothing special to filter the matching
-      devices, you can use the rest of fields like above. The last
-      field of <structname>pci_device_id</structname> struct is a
+      the <structname>pci_device_id</structname> structure are the vendor and
+      device IDs. If you have no reason to filter the matching
+      devices, you can leave the remaining fields as above. The last
+      field of the <structname>pci_device_id</structname> struct contains
       private data for this entry. You can specify any value here, for
-      example, to tell the type of different operations per each
-      device IDs. Such an example is found in intel8x0 driver. 
+      example, to define specific operations for supported device IDs.
+      Such an example is found in the intel8x0 driver. 
       </para>
 
       <para>
 
       <para>
         The <structfield>probe</structfield> and
-      <structfield>remove</structfield> functions are what we already
-      defined in 
-      the previous sections. The <structfield>remove</structfield> should
-      be defined with 
+      <structfield>remove</structfield> functions have already
+      been defined in the previous sections.
+      The <structfield>remove</structfield> function should
+      be defined with the 
       <function>__devexit_p()</function> macro, so that it's not
       defined for built-in (and non-hot-pluggable) case. The
       <structfield>name</structfield> 
 
       <para>
         Oh, one thing was forgotten. If you have no exported symbols,
-        you need to declare it on 2.2 or 2.4 kernels (on 2.6 kernels
-        it's not necessary, though).
+        you need to declare it in 2.2 or 2.4 kernels (it's not necessary in 2.6 kernels).
 
         <informalexample>
           <programlisting>
 
       <para>
         For accessing to the PCM layer, you need to include
-      <filename>&lt;sound/pcm.h&gt;</filename> above all. In addition,
+      <filename>&lt;sound/pcm.h&gt;</filename> first. In addition,
       <filename>&lt;sound/pcm_params.h&gt;</filename> might be needed
       if you access to some functions related with hw_param. 
       </para>
         Each card device can have up to four pcm instances. A pcm
       instance corresponds to a pcm device file. The limitation of
       number of instances comes only from the available bit size of
-      the linux's device number. Once when 64bit device number is
-      used, we'll have more available pcm instances
+      the Linux's device numbers. Once when 64bit device number is
+      used, we'll have more pcm instances available
       </para>
 
       <para>
         A pcm instance consists of pcm playback and capture streams,
       and each pcm stream consists of one or more pcm substreams. Some
-      soundcard supports the multiple-playback function. For example,
+      soundcards support multiple playback functions. For example,
       emu10k1 has a PCM playback of 32 stereo substreams. In this case, at
       each open, a free substream is (usually) automatically chosen
       and opened. Meanwhile, when only one substream exists and it was
-      already opened, the succeeding open will result in the blocking
-      or the error with <constant>EAGAIN</constant> according to the
-      file open mode. But you don't have to know the detail in your
-      driver. The PCM middle layer will take all such jobs. 
+      already opened, the successful open will either block
+      or error with <constant>EAGAIN</constant> according to the
+      file open mode. But you don't have to care about such details in your
+      driver. The PCM middle layer will take care of such work.
       </para>
     </section>
 
     <section id="pcm-interface-constructor">
       <title>Constructor</title>
       <para>
-        A pcm instance is allocated by <function>snd_pcm_new()</function>
+        A pcm instance is allocated by the <function>snd_pcm_new()</function>
       function. It would be better to create a constructor for pcm,
       namely, 
 
       </para>
 
       <para>
-        The <function>snd_pcm_new()</function> function takes the four
+        The <function>snd_pcm_new()</function> function takes four
       arguments. The first argument is the card pointer to which this
       pcm is assigned, and the second is the ID string. 
       </para>
 
       <para>
         The third argument (<parameter>index</parameter>, 0 in the
-      above) is the index of this new pcm. It begins from zero. When
-      you will create more than one pcm instances, specify the
+      above) is the index of this new pcm. It begins from zero. If
+      you create more than one pcm instances, specify the
       different numbers in this argument. For example,
       <parameter>index</parameter> = 1 for the second PCM device.  
       </para>
 
       <para>
         The fourth and fifth arguments are the number of substreams
-      for playback and capture, respectively. Here both 1 are given in
-      the above example.  When no playback or no capture is available,
+      for playback and capture, respectively. Here 1 is used for
+      both arguments. When no playback or capture substreams are available,
       pass 0 to the corresponding argument.
       </para>
 
           </programlisting>
         </informalexample>
 
-        Each of callbacks is explained in the subsection 
+        All the callbacks are described in the
         <link linkend="pcm-interface-operators"><citetitle>
-        Operators</citetitle></link>.
+        Operators</citetitle></link> subsection.
       </para>
 
       <para>
-        After setting the operators, most likely you'd like to
+        After setting the operators, you probably will want to
         pre-allocate the buffer. For the pre-allocation, simply call
         the following: 
 
           </programlisting>
         </informalexample>
 
-        It will allocate up to 64kB buffer as default. The details of
-      buffer management will be described in the later section <link
+        It will allocate a buffer up to 64kB as default.
+      Buffer management details will be described in the later section <link
       linkend="buffer-and-memory"><citetitle>Buffer and Memory
       Management</citetitle></link>. 
       </para>
       <para>
         The destructor for a pcm instance is not always
       necessary. Since the pcm device will be released by the middle
-      layer code automatically, you don't have to call destructor
+      layer code automatically, you don't have to call the destructor
       explicitly.
       </para>
 
       <para>
-        The destructor would be necessary when you created some
-        special records internally and need to release them. In such a
+        The destructor would be necessary if you created
+        special records internally and needed to release them. In such a
         case, set the destructor function to
         pcm-&gt;private_free: 
 
          When the PCM substream is opened, a PCM runtime instance is
        allocated and assigned to the substream. This pointer is
        accessible via <constant>substream-&gt;runtime</constant>.
-       This runtime pointer holds the various information; it holds
-       the copy of hw_params and sw_params configurations, the buffer
-       pointers, mmap records, spinlocks, etc.  Almost everything you
-       need for controlling the PCM can be found there.
+       This runtime pointer holds most information you need
+       to control the PCM: the copy of hw_params and sw_params configurations, the buffer
+       pointers, mmap records, spinlocks, etc.
        </para>
 
        <para>
        The definition of runtime instance is found in
-       <filename>&lt;sound/pcm.h&gt;</filename>.  Here is the
-       copy from the file.
+       <filename>&lt;sound/pcm.h&gt;</filename>.  Here are
+       the contents of this file:
           <informalexample>
             <programlisting>
 <![CDATA[
@@ -2185,7 +2186,6 @@ struct _snd_pcm_runtime {
        struct timespec tstamp_mode;    /* mmap timestamp is updated */
        unsigned int period_step;
        unsigned int sleep_min;         /* min ticks to sleep */
-       snd_pcm_uframes_t xfer_align;   /* xfer size need to be a multiple */
        snd_pcm_uframes_t start_threshold;
        snd_pcm_uframes_t stop_threshold;
        snd_pcm_uframes_t silence_threshold; /* Silence filling happens when
@@ -2244,7 +2244,7 @@ struct _snd_pcm_runtime {
        <para>
          For the operators (callbacks) of each sound driver, most of
        these records are supposed to be read-only.  Only the PCM
-       middle-layer changes / updates these info.  The exceptions are
+       middle-layer changes / updates them.  The exceptions are
        the hardware description (hw), interrupt callbacks
        (transfer_ack_xxx), DMA buffer information, and the private
        data.  Besides, if you use the standard buffer allocation
@@ -2285,7 +2285,7 @@ struct _snd_pcm_runtime {
        </para>
 
        <para>
-         Typically, you'll have a hardware descriptor like below:
+         Typically, you'll have a hardware descriptor as below:
           <informalexample>
             <programlisting>
 <![CDATA[
@@ -2320,10 +2320,10 @@ struct _snd_pcm_runtime {
         <constant>SNDRV_PCM_INFO_XXX</constant>. Here, at least, you
         have to specify whether the mmap is supported and which
         interleaved format is supported.
-        When the mmap is supported, add
+        When the is supported, add the
         <constant>SNDRV_PCM_INFO_MMAP</constant> flag here. When the
         hardware supports the interleaved or the non-interleaved
-        format, <constant>SNDRV_PCM_INFO_INTERLEAVED</constant> or
+        formats, <constant>SNDRV_PCM_INFO_INTERLEAVED</constant> or
         <constant>SNDRV_PCM_INFO_NONINTERLEAVED</constant> flag must
         be set, respectively. If both are supported, you can set both,
         too. 
@@ -2331,7 +2331,7 @@ struct _snd_pcm_runtime {
 
         <para>
           In the above example, <constant>MMAP_VALID</constant> and
-        <constant>BLOCK_TRANSFER</constant> are specified for OSS mmap
+        <constant>BLOCK_TRANSFER</constant> are specified for the OSS mmap
         mode. Usually both are set. Of course,
         <constant>MMAP_VALID</constant> is set only if the mmap is
         really supported. 
@@ -2345,11 +2345,11 @@ struct _snd_pcm_runtime {
         <quote>pause</quote> operation, while the
         <constant>RESUME</constant> bit means that the pcm supports
         the full <quote>suspend/resume</quote> operation.
-       If <constant>PAUSE</constant> flag is set,
+       If the <constant>PAUSE</constant> flag is set,
        the <structfield>trigger</structfield> callback below
         must handle the corresponding (pause push/release) commands.
        The suspend/resume trigger commands can be defined even without
-       <constant>RESUME</constant> flag.  See <link
+       the <constant>RESUME</constant> flag.  See <link
        linkend="power-management"><citetitle>
        Power Management</citetitle></link> section for details.
         </para>
@@ -2382,7 +2382,7 @@ struct _snd_pcm_runtime {
         <constant>CONTINUOUS</constant> bit additionally.
         The pre-defined rate bits are provided only for typical
        rates. If your chip supports unconventional rates, you need to add
-        <constant>KNOT</constant> bit and set up the hardware
+        the <constant>KNOT</constant> bit and set up the hardware
         constraint manually (explained later).
         </para>
        </listitem>
@@ -2390,8 +2390,8 @@ struct _snd_pcm_runtime {
        <listitem>
        <para>
        <structfield>rate_min</structfield> and
-       <structfield>rate_max</structfield> define the minimal and
-       maximal sample rate.  This should correspond somehow to
+       <structfield>rate_max</structfield> define the minimum and
+       maximum sample rate.  This should correspond somehow to
        <structfield>rates</structfield> bits.
        </para>
        </listitem>
@@ -2400,7 +2400,7 @@ struct _snd_pcm_runtime {
        <para>
        <structfield>channel_min</structfield> and
        <structfield>channel_max</structfield> 
-       define, as you might already expected, the minimal and maximal
+       define, as you might already expected, the minimum and maximum
        number of channels.
        </para>
        </listitem>
@@ -2408,21 +2408,21 @@ struct _snd_pcm_runtime {
        <listitem>
        <para>
        <structfield>buffer_bytes_max</structfield> defines the
-       maximal buffer size in bytes.  There is no
+       maximum buffer size in bytes.  There is no
        <structfield>buffer_bytes_min</structfield> field, since
-       it can be calculated from the minimal period size and the
-       minimal number of periods.
+       it can be calculated from the minimum period size and the
+       minimum number of periods.
        Meanwhile, <structfield>period_bytes_min</structfield> and
-       define the minimal and maximal size of the period in bytes.
+       define the minimum and maximum size of the period in bytes.
        <structfield>periods_max</structfield> and
-       <structfield>periods_min</structfield> define the maximal and
-       minimal number of periods in the buffer.
+       <structfield>periods_min</structfield> define the maximum and
+       minimum number of periods in the buffer.
         </para>
 
        <para>
-       The <quote>period</quote> is a term, that corresponds to
-       fragment in the OSS world.  The period defines the size at
-       which the PCM interrupt is generated. This size strongly
+       The <quote>period</quote> is a term that corresponds to
+       a fragment in the OSS world. The period defines the size at
+       which a PCM interrupt is generated. This size strongly
        depends on the hardware. 
        Generally, the smaller period size will give you more
        interrupts, that is, more controls. 
@@ -2435,8 +2435,8 @@ struct _snd_pcm_runtime {
        <listitem>
        <para>
        There is also a field <structfield>fifo_size</structfield>.
-       This specifies the size of the hardware FIFO, but it's not
-       used currently in the driver nor in the alsa-lib.  So, you
+       This specifies the size of the hardware FIFO, but currently it
+       is neither used in the driver nor in the alsa-lib.  So, you
        can ignore this field.
        </para>
        </listitem>
@@ -2450,7 +2450,7 @@ struct _snd_pcm_runtime {
        Ok, let's go back again to the PCM runtime records.
        The most frequently referred records in the runtime instance are
        the PCM configurations.
-       The PCM configurations are stored on runtime instance
+       The PCM configurations are stored in the runtime instance
        after the application sends <type>hw_params</type> data via
        alsa-lib.  There are many fields copied from hw_params and
        sw_params structs.  For example,
@@ -2461,11 +2461,11 @@ struct _snd_pcm_runtime {
 
        <para>
        One thing to be noted is that the configured buffer and period
-       sizes are stored in <quote>frames</quote> in the runtime
+       sizes are stored in <quote>frames</quote> in the runtime.
         In the ALSA world, 1 frame = channels * samples-size.
        For conversion between frames and bytes, you can use the
-       helper functions, <function>frames_to_bytes()</function> and
-          <function>bytes_to_frames()</function>. 
+       <function>frames_to_bytes()</function> and
+          <function>bytes_to_frames()</function> helper functions
           <informalexample>
             <programlisting>
 <![CDATA[
@@ -2515,7 +2515,7 @@ struct _snd_pcm_runtime {
        <structfield>dma_area</structfield> is necessary when the
        buffer is mmapped.  If your driver doesn't support mmap, this
        field is not necessary.  <structfield>dma_addr</structfield>
-       is also not mandatory.  You can use
+       is also optional.  You can use
        <structfield>dma_private</structfield> as you like, too.
        </para>
        </section>
@@ -2524,14 +2524,14 @@ struct _snd_pcm_runtime {
        <title>Running Status</title>
        <para>
        The running status can be referred via <constant>runtime-&gt;status</constant>.
-       This is the pointer to struct <structname>snd_pcm_mmap_status</structname>
+       This is the pointer to the struct <structname>snd_pcm_mmap_status</structname>
        record.  For example, you can get the current DMA hardware
        pointer via <constant>runtime-&gt;status-&gt;hw_ptr</constant>.
        </para>
 
        <para>
        The DMA application pointer can be referred via
-       <constant>runtime-&gt;control</constant>, which points
+       <constant>runtime-&gt;control</constant>, which points to the
        struct <structname>snd_pcm_mmap_control</structname> record.
        However, accessing directly to this value is not recommended.
        </para>
@@ -2542,14 +2542,14 @@ struct _snd_pcm_runtime {
        <para>
        You can allocate a record for the substream and store it in
        <constant>runtime-&gt;private_data</constant>.  Usually, this
-       done in
+       is done in
        <link linkend="pcm-interface-operators-open-callback"><citetitle>
        the open callback</citetitle></link>.
        Don't mix this with <constant>pcm-&gt;private_data</constant>.
-       The <constant>pcm-&gt;private_data</constant> usually points the
+       The <constant>pcm-&gt;private_data</constant> usually points to the
        chip instance assigned statically at the creation of PCM, while the 
-       <constant>runtime-&gt;private_data</constant> points a dynamic
-       data created at the PCM open callback.
+       <constant>runtime-&gt;private_data</constant> points to a dynamic
+       data structure created at the PCM open callback.
 
           <informalexample>
             <programlisting>
@@ -2579,7 +2579,7 @@ struct _snd_pcm_runtime {
        <para>
        The field <structfield>transfer_ack_begin</structfield> and
        <structfield>transfer_ack_end</structfield> are called at
-       the beginning and the end of
+       the beginning and at the end of
        <function>snd_pcm_period_elapsed()</function>, respectively. 
        </para>
        </section>
@@ -2589,17 +2589,18 @@ struct _snd_pcm_runtime {
     <section id="pcm-interface-operators">
       <title>Operators</title>
       <para>
-        OK, now let me explain the detail of each pcm callback
+        OK, now let me give details about each pcm callback
       (<parameter>ops</parameter>). In general, every callback must
-      return 0 if successful, or a negative number with the error
-      number such as <constant>-EINVAL</constant> at any
-      error. 
+      return 0 if successful, or a negative error number
+      such as <constant>-EINVAL</constant>. To choose an appropriate
+      error number, it is advised to check what value other parts of
+      the kernel return when the same kind of request fails.
       </para>
 
       <para>
         The callback function takes at least the argument with
-        <structname>snd_pcm_substream</structname> pointer. For retrieving the
-        chip record from the given substream instance, you can use the
+        <structname>snd_pcm_substream</structname> pointer. To retrieve
+        the chip record from the given substream instance, you can use the
         following macro. 
 
         <informalexample>
@@ -2616,7 +2617,7 @@ struct _snd_pcm_runtime {
        The macro reads <constant>substream-&gt;private_data</constant>,
        which is a copy of <constant>pcm-&gt;private_data</constant>.
        You can override the former if you need to assign different data
-       records per PCM substream.  For example, cmi8330 driver assigns
+       records per PCM substream.  For example, the cmi8330 driver assigns
        different private_data for playback and capture directions,
        because it uses two different codecs (SB- and AD-compatible) for
        different directions.
@@ -2709,7 +2710,7 @@ struct _snd_pcm_runtime {
       <section id="pcm-interface-operators-ioctl-callback">
         <title>ioctl callback</title>
         <para>
-          This is used for any special action to pcm ioctls. But
+          This is used for any special call to pcm ioctls. But
         usually you can pass a generic ioctl callback, 
         <function>snd_pcm_lib_ioctl</function>.
         </para>
@@ -2726,9 +2727,6 @@ struct _snd_pcm_runtime {
 ]]>
             </programlisting>
           </informalexample>
-
-          This and <structfield>hw_free</structfield> callbacks exist
-        only on ALSA 0.9.x. 
         </para>
 
         <para>
@@ -2740,13 +2738,13 @@ struct _snd_pcm_runtime {
         </para>
 
         <para>
-          Many hardware set-up should be done in this callback,
+          Many hardware setups should be done in this callback,
         including the allocation of buffers. 
         </para>
 
         <para>
           Parameters to be initialized are retrieved by
-          <function>params_xxx()</function> macros. For allocating a
+          <function>params_xxx()</function> macros. To allocate
           buffer, you can call a helper function, 
 
           <informalexample>
@@ -2772,8 +2770,8 @@ struct _snd_pcm_runtime {
         </para>
 
         <para>
-          Thus, you need to take care not to allocate the same buffers
-        many times, which will lead to memory leak!  Calling the
+          Thus, you need to be careful not to allocate the same buffers
+        many times, which will lead to memory leaks!  Calling the
         helper function above many times is OK. It will release the
         previous buffer automatically when it was already allocated. 
         </para>
@@ -2782,7 +2780,7 @@ struct _snd_pcm_runtime {
           Another note is that this callback is non-atomic
         (schedulable). This is important, because the
         <structfield>trigger</structfield> callback 
-        is atomic (non-schedulable). That is, mutex or any
+        is atomic (non-schedulable). That is, mutexes or any
         schedule-related functions are not available in
         <structfield>trigger</structfield> callback.
        Please see the subsection
@@ -2843,15 +2841,15 @@ struct _snd_pcm_runtime {
         <quote>prepared</quote>. You can set the format type, sample
         rate, etc. here. The difference from
         <structfield>hw_params</structfield> is that the 
-        <structfield>prepare</structfield> callback will be called at each
+        <structfield>prepare</structfield> callback will be called each
         time 
         <function>snd_pcm_prepare()</function> is called, i.e. when
-        recovered after underruns, etc. 
+        recovering after underruns, etc. 
         </para>
 
         <para>
-       Note that this callback became non-atomic since the recent version.
-       You can use schedule-related functions safely in this callback now.
+       Note that this callback is now non-atomic.
+       You can use schedule-related functions safely in this callback.
         </para>
 
         <para>
@@ -2871,7 +2869,7 @@ struct _snd_pcm_runtime {
 
         <para>
           Be careful that this callback will be called many times at
-        each set up, too. 
+        each setup, too. 
         </para>
       </section>
 
@@ -2893,7 +2891,7 @@ struct _snd_pcm_runtime {
           Which action is specified in the second argument,
           <constant>SNDRV_PCM_TRIGGER_XXX</constant> in
           <filename>&lt;sound/pcm.h&gt;</filename>. At least,
-          <constant>START</constant> and <constant>STOP</constant>
+          the <constant>START</constant> and <constant>STOP</constant>
           commands must be defined in this callback. 
 
           <informalexample>
@@ -2915,8 +2913,8 @@ struct _snd_pcm_runtime {
         </para>
 
         <para>
-          When the pcm supports the pause operation (given in info
-        field of the hardware table), <constant>PAUSE_PUSE</constant>
+          When the pcm supports the pause operation (given in the info
+        field of the hardware table), the <constant>PAUSE_PUSE</constant>
         and <constant>PAUSE_RELEASE</constant> commands must be
         handled here, too. The former is the command to pause the pcm,
         and the latter to restart the pcm again. 
@@ -2925,21 +2923,21 @@ struct _snd_pcm_runtime {
         <para>
           When the pcm supports the suspend/resume operation,
        regardless of full or partial suspend/resume support,
-        <constant>SUSPEND</constant> and <constant>RESUME</constant>
+        the <constant>SUSPEND</constant> and <constant>RESUME</constant>
         commands must be handled, too.
         These commands are issued when the power-management status is
         changed.  Obviously, the <constant>SUSPEND</constant> and
-        <constant>RESUME</constant>
-        do suspend and resume of the pcm substream, and usually, they
-        are identical with <constant>STOP</constant> and
+        <constant>RESUME</constant> commands
+        suspend and resume the pcm substream, and usually, they
+        are identical to the <constant>STOP</constant> and
         <constant>START</constant> commands, respectively.
-         See <link linkend="power-management"><citetitle>
+         See the <link linkend="power-management"><citetitle>
        Power Management</citetitle></link> section for details.
         </para>
 
         <para>
           As mentioned, this callback is atomic.  You cannot call
-         the function going to sleep.
+         functions which may sleep.
          The trigger callback should be as minimal as possible,
          just really triggering the DMA.  The other stuff should be
          initialized hw_params and prepare callbacks properly
@@ -2960,8 +2958,8 @@ struct _snd_pcm_runtime {
 
           This callback is called when the PCM middle layer inquires
         the current hardware position on the buffer. The position must
-        be returned in frames (which was in bytes on ALSA 0.5.x),
-        ranged from 0 to buffer_size - 1.
+        be returned in frames,
+        ranging from 0 to buffer_size - 1.
         </para>
 
         <para>
@@ -2983,7 +2981,7 @@ struct _snd_pcm_runtime {
         <para>
           These callbacks are not mandatory, and can be omitted in
         most cases. These callbacks are used when the hardware buffer
-        cannot be on the normal memory space. Some chips have their
+        cannot be in the normal memory space. Some chips have their
         own buffer on the hardware which is not mappable. In such a
         case, you have to transfer the data manually from the memory
         buffer to the hardware buffer. Or, if the buffer is
@@ -3018,8 +3016,8 @@ struct _snd_pcm_runtime {
         <title>page callback</title>
 
         <para>
-          This callback is also not mandatory. This callback is used
-        mainly for the non-contiguous buffer. The mmap calls this
+          This callback is optional too. This callback is used
+        mainly for non-contiguous buffers. The mmap calls this
         callback to get the page address. Some examples will be
         explained in the later section <link
         linkend="buffer-and-memory"><citetitle>Buffer and Memory
@@ -3035,7 +3033,7 @@ struct _snd_pcm_runtime {
       role of PCM interrupt handler in the sound driver is to update
       the buffer position and to tell the PCM middle layer when the
       buffer position goes across the prescribed period size. To
-      inform this, call <function>snd_pcm_period_elapsed()</function>
+      inform this, call the <function>snd_pcm_period_elapsed()</function>
       function. 
       </para>
 
@@ -3072,7 +3070,7 @@ struct _snd_pcm_runtime {
         </para>
 
         <para>
-          A typical coding would be like:
+          Typical code would be like:
 
           <example>
            <title>Interrupt Handler Case #1</title>
@@ -3101,21 +3099,21 @@ struct _snd_pcm_runtime {
       </section>
 
       <section id="pcm-interface-interrupt-handler-timer">
-        <title>High-frequent timer interrupts</title>
+        <title>High frequency timer interrupts</title>
         <para>
-       This is the case when the hardware doesn't generate interrupts
-        at the period boundary but do timer-interrupts at the fixed
+       This happense when the hardware doesn't generate interrupts
+        at the period boundary but issues timer interrupts at a fixed
         timer rate (e.g. es1968 or ymfpci drivers). 
         In this case, you need to check the current hardware
-        position and accumulates the processed sample length at each
-        interrupt.  When the accumulated size overcomes the period
+        position and accumulate the processed sample length at each
+        interrupt.  When the accumulated size exceeds the period
         size, call 
         <function>snd_pcm_period_elapsed()</function> and reset the
         accumulator. 
         </para>
 
         <para>
-          A typical coding would be like the following.
+          Typical code would be like the following.
 
           <example>
            <title>Interrupt Handler Case #2</title>
@@ -3178,32 +3176,33 @@ struct _snd_pcm_runtime {
     <section id="pcm-interface-atomicity">
       <title>Atomicity</title>
       <para>
-      One of the most important (and thus difficult to debug) problem
-      on the kernel programming is the race condition.
-      On linux kernel, usually it's solved via spin-locks or
-      semaphores.  In general, if the race condition may
-      happen in the interrupt handler, it's handled as atomic, and you
-      have to use spinlock for protecting the critical session.  If it
-      never happens in the interrupt and it may take relatively long
-      time, you should use semaphore.
+      One of the most important (and thus difficult to debug) problems
+      in kernel programming are race conditions.
+      In the Linux kernel, they are usually avoided via spin-locks, mutexes
+      or semaphores.  In general, if a race condition can happen
+      in an interrupt handler, it has to be managed atomically, and you
+      have to use a spinlock to protect the critical session. If the
+      critical section is not in interrupt handler code and
+      if taking a relatively long time to execute is acceptable, you
+      should use mutexes or semaphores instead.
       </para>
 
       <para>
       As already seen, some pcm callbacks are atomic and some are
-      not.  For example, <parameter>hw_params</parameter> callback is
+      not.  For example, the <parameter>hw_params</parameter> callback is
       non-atomic, while <parameter>trigger</parameter> callback is
       atomic.  This means, the latter is called already in a spinlock
       held by the PCM middle layer. Please take this atomicity into
-      account when you use a spinlock or a semaphore in the callbacks.
+      account when you choose a locking scheme in the callbacks.
       </para>
 
       <para>
       In the atomic callbacks, you cannot use functions which may call
       <function>schedule</function> or go to
-      <function>sleep</function>.  The semaphore and mutex do sleep,
+      <function>sleep</function>.  Semaphores and mutexes can sleep,
       and hence they cannot be used inside the atomic callbacks
       (e.g. <parameter>trigger</parameter> callback).
-      For taking a certain delay in such a callback, please use
+      To implement some delay in such a callback, please use
       <function>udelay()</function> or <function>mdelay()</function>.
       </para>
 
@@ -3257,7 +3256,7 @@ struct _snd_pcm_runtime {
 
       <para>
         There are many different constraints.
-        Look in <filename>sound/pcm.h</filename> for a complete list.
+        Look at <filename>sound/pcm.h</filename> for a complete list.
         You can even define your own constraint rules.
         For example, let's suppose my_chip can manage a substream of 1 channel
         if and only if the format is S16_LE, otherwise it supports any format
@@ -3346,7 +3345,7 @@ struct _snd_pcm_runtime {
       </para>
 
       <para>
-        I won't explain more details here, rather I
+        I won't give more details here, rather I
         would like to say, <quote>Luke, use the source.</quote>
       </para>
     </section>
@@ -3364,10 +3363,9 @@ struct _snd_pcm_runtime {
       <title>General</title>
       <para>
         The control interface is used widely for many switches,
-      sliders, etc. which are accessed from the user-space. Its most
-      important use is the mixer interface. In other words, on ALSA
-      0.9.x, all the mixer stuff is implemented on the control kernel
-      API (while there was an independent mixer kernel API on 0.5.x). 
+      sliders, etc. which are accessed from user-space. Its most
+      important use is the mixer interface. In other words, since ALSA
+      0.9.x, all the mixer stuff is implemented on the control kernel API.
       </para>
 
       <para>
@@ -3379,14 +3377,15 @@ struct _snd_pcm_runtime {
       <para>
         The control API is defined in
       <filename>&lt;sound/control.h&gt;</filename>.
-      Include this file if you add your own controls.
+      Include this file if you want to add your own controls.
       </para>
     </section>
 
     <section id="control-interface-definition">
       <title>Definition of Controls</title>
       <para>
-        For creating a new control, you need to define the three
+        To create a new control, you need to define the
+       following three
       callbacks: <structfield>info</structfield>,
       <structfield>get</structfield> and
       <structfield>put</structfield>. Then, define a
@@ -3414,13 +3413,13 @@ struct _snd_pcm_runtime {
       <para>
         Most likely the control is created via
       <function>snd_ctl_new1()</function>, and in such a case, you can
-      add <parameter>__devinitdata</parameter> prefix to the
-      definition like above. 
+      add the <parameter>__devinitdata</parameter> prefix to the
+      definition as above. 
       </para>
 
       <para>
-        The <structfield>iface</structfield> field specifies the type of
-      the control, <constant>SNDRV_CTL_ELEM_IFACE_XXX</constant>, which
+        The <structfield>iface</structfield> field specifies the control
+      type, <constant>SNDRV_CTL_ELEM_IFACE_XXX</constant>, which
       is usually <constant>MIXER</constant>.
       Use <constant>CARD</constant> for global controls that are not
       logically part of the mixer.
@@ -3435,12 +3434,11 @@ struct _snd_pcm_runtime {
 
       <para>
         The <structfield>name</structfield> is the name identifier
-      string. On ALSA 0.9.x, the control name is very important,
+      string. Since ALSA 0.9.x, the control name is very important,
       because its role is classified from its name. There are
       pre-defined standard control names. The details are described in
-      the subsection
-      <link linkend="control-interface-control-names"><citetitle>
-      Control Names</citetitle></link>.
+      the <link linkend="control-interface-control-names"><citetitle>
+      Control Names</citetitle></link> subsection.
       </para>
 
       <para>
@@ -3456,15 +3454,15 @@ struct _snd_pcm_runtime {
         The <structfield>access</structfield> field contains the access
       type of this control. Give the combination of bit masks,
       <constant>SNDRV_CTL_ELEM_ACCESS_XXX</constant>, there.
-      The detailed will be explained in the subsection
-      <link linkend="control-interface-access-flags"><citetitle>
-      Access Flags</citetitle></link>.
+      The details will be explained in
+      the <link linkend="control-interface-access-flags"><citetitle>
+      Access Flags</citetitle></link> subsection.
       </para>
 
       <para>
         The <structfield>private_value</structfield> field contains
       an arbitrary long integer value for this record. When using
-      generic <structfield>info</structfield>,
+      the generic <structfield>info</structfield>,
       <structfield>get</structfield> and
       <structfield>put</structfield> callbacks, you can pass a value 
       through this field. If several small numbers are necessary, you can
@@ -3489,7 +3487,7 @@ struct _snd_pcm_runtime {
     <section id="control-interface-control-names">
       <title>Control Names</title>
       <para>
-        There are some standards for defining the control names. A
+        There are some standards to define the control names. A
       control is usually defined from the three parts as
       <quote>SOURCE DIRECTION FUNCTION</quote>. 
       </para>
@@ -3497,7 +3495,7 @@ struct _snd_pcm_runtime {
       <para>
         The first, <constant>SOURCE</constant>, specifies the source
       of the control, and is a string such as <quote>Master</quote>,
-      <quote>PCM</quote>, <quote>CD</quote> or
+      <quote>PCM</quote>, <quote>CD</quote> and
       <quote>Line</quote>. There are many pre-defined sources. 
       </para>
 
@@ -3575,22 +3573,22 @@ struct _snd_pcm_runtime {
       <title>Access Flags</title>
 
       <para>
-      The access flag is the bit-flags which specifies the access type
+      The access flag is the bitmask which specifies the access type
       of the given control.  The default access type is
       <constant>SNDRV_CTL_ELEM_ACCESS_READWRITE</constant>, 
       which means both read and write are allowed to this control.
       When the access flag is omitted (i.e. = 0), it is
-      regarded as <constant>READWRITE</constant> access as default. 
+      considered as <constant>READWRITE</constant> access as default. 
       </para>
 
       <para>
       When the control is read-only, pass
       <constant>SNDRV_CTL_ELEM_ACCESS_READ</constant> instead.
       In this case, you don't have to define
-      <structfield>put</structfield> callback.
+      the <structfield>put</structfield> callback.
       Similarly, when the control is write-only (although it's a rare
-      case), you can use <constant>WRITE</constant> flag instead, and
-      you don't need <structfield>get</structfield> callback.
+      case), you can use the <constant>WRITE</constant> flag instead, and
+      you don't need the <structfield>get</structfield> callback.
       </para>
 
       <para>
@@ -3598,15 +3596,15 @@ struct _snd_pcm_runtime {
       <constant>VOLATILE</constant> flag should be given.  This means
       that the control may be changed without
       <link linkend="control-interface-change-notification"><citetitle>
-      notification</citetitle></link>.  Applications should poll such
+      notification</citetitle></link>. Applications should poll such
       a control constantly.
       </para>
 
       <para>
       When the control is inactive, set
-      <constant>INACTIVE</constant> flag, too.
+      the <constant>INACTIVE</constant> flag, too.
       There are <constant>LOCK</constant> and
-      <constant>OWNER</constant> flags for changing the write
+      <constant>OWNER</constant> flags to change the write
       permissions.
       </para>
 
@@ -3619,10 +3617,10 @@ struct _snd_pcm_runtime {
         <title>info callback</title>
         <para>
           The <structfield>info</structfield> callback is used to get
-        the detailed information of this control. This must store the
+        detailed information on this control. This must store the
         values of the given struct <structname>snd_ctl_elem_info</structname>
         object. For example, for a boolean control with a single
-        element will be
+        element: 
 
           <example>
            <title>Example of info callback</title>
@@ -3653,7 +3651,7 @@ struct _snd_pcm_runtime {
         volume would have count = 2. The
         <structfield>value</structfield> field is a union, and 
         the values stored are depending on the type. The boolean and
-        integer are identical. 
+        integer types are identical. 
         </para>
 
         <para>
@@ -3684,7 +3682,7 @@ struct _snd_pcm_runtime {
         </para>
 
         <para>
-         Some common info callbacks are prepared for easy use:
+         Some common info callbacks are available for your convenience:
        <function>snd_ctl_boolean_mono_info()</function> and
        <function>snd_ctl_boolean_stereo_info()</function>.
        Obviously, the former is an info callback for a mono channel
@@ -3699,7 +3697,7 @@ struct _snd_pcm_runtime {
 
         <para>
           This callback is used to read the current value of the
-        control and to return to the user-space. 
+        control and to return to user-space. 
         </para>
 
         <para>
@@ -3722,11 +3720,11 @@ struct _snd_pcm_runtime {
         </para>
 
         <para>
-       The <structfield>value</structfield> field is depending on
-        the type of control as well as on info callback.  For example,
+       The <structfield>value</structfield> field depends on 
+        the type of control as well as on the info callback.  For example,
        the sb driver uses this field to store the register offset,
         the bit-shift and the bit-mask.  The
-        <structfield>private_value</structfield> is set like
+        <structfield>private_value</structfield> field is set as follows:
           <informalexample>
             <programlisting>
 <![CDATA[
@@ -3752,7 +3750,8 @@ struct _snd_pcm_runtime {
        </para>
 
        <para>
-       In <structfield>get</structfield> callback, you have to fill all the elements if the
+       In the <structfield>get</structfield> callback,
+       you have to fill all the elements if the
         control has more than one elements,
         i.e. <structfield>count</structfield> &gt; 1.
        In the example above, we filled only one element
@@ -3765,7 +3764,7 @@ struct _snd_pcm_runtime {
         <title>put callback</title>
 
         <para>
-          This callback is used to write a value from the user-space.
+          This callback is used to write a value from user-space.
         </para>
 
         <para>
@@ -3799,7 +3798,7 @@ struct _snd_pcm_runtime {
         </para>
 
         <para>
-       Like <structfield>get</structfield> callback,
+       As in the <structfield>get</structfield> callback,
        when the control has more than one elements,
        all elements must be evaluated in this callback, too.
         </para>
@@ -3817,7 +3816,7 @@ struct _snd_pcm_runtime {
       <title>Constructor</title>
       <para>
         When everything is ready, finally we can create a new
-      control. For creating a control, there are two functions to be
+      control. To create a control, there are two functions to be
       called, <function>snd_ctl_new1()</function> and
       <function>snd_ctl_add()</function>. 
       </para>
@@ -3839,14 +3838,14 @@ struct _snd_pcm_runtime {
       struct <structname>snd_kcontrol_new</structname> object defined above, and chip
       is the object pointer to be passed to
       kcontrol-&gt;private_data 
-      which can be referred in callbacks. 
+      which can be referred to in callbacks. 
       </para>
 
       <para>
         <function>snd_ctl_new1()</function> allocates a new
       <structname>snd_kcontrol</structname> instance (that's why the definition
       of <parameter>my_control</parameter> can be with
-      <parameter>__devinitdata</parameter> 
+      the <parameter>__devinitdata</parameter> 
       prefix), and <function>snd_ctl_add</function> assigns the given
       control component to the card. 
       </para>
@@ -3941,7 +3940,7 @@ struct _snd_pcm_runtime {
       <title>General</title>
       <para>
         The ALSA AC97 codec layer is a well-defined one, and you don't
-      have to write many codes to control it. Only low-level control
+      have to write much code to control it. Only low-level control
       routines are necessary. The AC97 codec API is defined in
       <filename>&lt;sound/ac97_codec.h&gt;</filename>. 
       </para>
@@ -4004,7 +4003,7 @@ struct _snd_pcm_runtime {
     <section id="api-ac97-constructor">
       <title>Constructor</title>
       <para>
-        For creating an ac97 instance, first call <function>snd_ac97_bus</function>
+        To create an ac97 instance, first call <function>snd_ac97_bus</function>
       with an <type>ac97_bus_ops_t</type> record with callback functions.
 
         <informalexample>
@@ -4042,12 +4041,12 @@ struct _snd_pcm_runtime {
           </programlisting>
         </informalexample>
 
-        where chip-&gt;ac97 is the pointer of a newly created
+        where chip-&gt;ac97 is a pointer to a newly created
         <type>ac97_t</type> instance.
         In this case, the chip pointer is set as the private data, so that
         the read/write callback functions can refer to this chip instance.
         This instance is not necessarily stored in the chip
-       record.  When you need to change the register values from the
+       record.  If you need to change the register values from the
         driver, or need the suspend/resume of ac97 codecs, keep this
         pointer to pass to the corresponding functions.
       </para>
@@ -4098,7 +4097,7 @@ struct _snd_pcm_runtime {
       </para>
 
       <para>
-      These callbacks are non-atomic like the callbacks of control API.
+      These callbacks are non-atomic like the control API callbacks.
       </para>
 
       <para>
@@ -4110,14 +4109,14 @@ struct _snd_pcm_runtime {
 
       <para>
         The <structfield>reset</structfield> callback is used to reset
-      the codec. If the chip requires a special way of reset, you can
+      the codec. If the chip requires a special kind of reset, you can
       define this callback. 
       </para>
 
       <para>
-        The <structfield>wait</structfield> callback is used for a
-      certain wait at the standard initialization of the codec. If the
-      chip requires the extra wait-time, define this callback. 
+        The <structfield>wait</structfield> callback is used to
+      add some waiting time in the standard initialization of the codec. If the
+      chip requires the extra waiting time, define this callback. 
       </para>
 
       <para>
@@ -4172,7 +4171,7 @@ struct _snd_pcm_runtime {
 
       <para>
         <function>snd_ac97_update_bits()</function> is used to update
-        some bits of the given register.  
+        some bits in the given register.  
 
         <informalexample>
           <programlisting>
@@ -4185,7 +4184,7 @@ struct _snd_pcm_runtime {
 
       <para>
         Also, there is a function to change the sample rate (of a
-        certain register such as
+        given register such as
         <constant>AC97_PCM_FRONT_DAC_RATE</constant>) when VRA or
         DRA is supported by the codec:
         <function>snd_ac97_set_rate()</function>. 
@@ -4200,11 +4199,11 @@ struct _snd_pcm_runtime {
       </para>
 
       <para>
-        The following registers are available for setting the rate:
+        The following registers are available to set the rate:
       <constant>AC97_PCM_MIC_ADC_RATE</constant>,
       <constant>AC97_PCM_FRONT_DAC_RATE</constant>,
       <constant>AC97_PCM_LR_ADC_RATE</constant>,
-      <constant>AC97_SPDIF</constant>. When the
+      <constant>AC97_SPDIF</constant>. When
       <constant>AC97_SPDIF</constant> is specified, the register is
       not really changed but the corresponding IEC958 status bits will
       be updated. 
@@ -4214,12 +4213,11 @@ struct _snd_pcm_runtime {
     <section id="api-ac97-clock-adjustment">
       <title>Clock Adjustment</title>
       <para>
-        On some chip, the clock of the codec isn't 48000 but using a
+        In some chips, the clock of the codec isn't 48000 but using a
       PCI clock (to save a quartz!). In this case, change the field
       bus-&gt;clock to the corresponding
       value. For example, intel8x0 
-      and es1968 drivers have the auto-measurement function of the
-      clock. 
+      and es1968 drivers have their own function to read from the clock.
       </para>
     </section>
 
@@ -4239,15 +4237,13 @@ struct _snd_pcm_runtime {
         When there are several codecs on the same card, you need to
       call <function>snd_ac97_mixer()</function> multiple times with
       ac97.num=1 or greater. The <structfield>num</structfield> field
-      specifies the codec 
-      number. 
+      specifies the codec number. 
       </para>
 
       <para>
-        If you have set up multiple codecs, you need to either write
+        If you set up multiple codecs, you either need to write
       different callbacks for each codec or check
-      ac97-&gt;num in the 
-      callback routines. 
+      ac97-&gt;num in the callback routines. 
       </para>
     </section>
 
@@ -4271,7 +4267,7 @@ struct _snd_pcm_runtime {
       </para>
 
       <para>
-        Some soundchips have similar but a little bit different
+        Some soundchips have a similar but slightly different
       implementation of mpu401 stuff. For example, emu10k1 has its own
       mpu401 routines. 
       </para>
@@ -4280,7 +4276,7 @@ struct _snd_pcm_runtime {
     <section id="midi-interface-constructor">
       <title>Constructor</title>
       <para>
-        For creating a rawmidi object, call
+        To create a rawmidi object, call
       <function>snd_mpu401_uart_new()</function>. 
 
         <informalexample>
@@ -4307,25 +4303,24 @@ struct _snd_pcm_runtime {
       </para>
 
       <para>
-        The 4th argument is the i/o port address. Many
-      backward-compatible MPU401 has an i/o port such as 0x330. Or, it
-      might be a part of its own PCI i/o region. It depends on the
+        The 4th argument is the I/O port address. Many
+      backward-compatible MPU401 have an I/O port such as 0x330. Or, it
+      might be a part of its own PCI I/O region. It depends on the
       chip design. 
       </para>
 
       <para>
-       The 5th argument is bitflags for additional information.
-        When the i/o port address above is a part of the PCI i/o
-      region, the MPU401 i/o port might have been already allocated
+       The 5th argument is a bitflag for additional information.
+        When the I/O port address above is part of the PCI I/O
+      region, the MPU401 I/O port might have been already allocated
       (reserved) by the driver itself. In such a case, pass a bit flag
       <constant>MPU401_INFO_INTEGRATED</constant>,
-      and 
-      the mpu401-uart layer will allocate the i/o ports by itself. 
+      and the mpu401-uart layer will allocate the I/O ports by itself. 
       </para>
 
        <para>
        When the controller supports only the input or output MIDI stream,
-       pass <constant>MPU401_INFO_INPUT</constant> or
+       pass the <constant>MPU401_INFO_INPUT</constant> or
        <constant>MPU401_INFO_OUTPUT</constant> bitflag, respectively.
        Then the rawmidi instance is created as a single stream.
        </para>
@@ -4333,7 +4328,7 @@ struct _snd_pcm_runtime {
        <para>
        <constant>MPU401_INFO_MMIO</constant> bitflag is used to change
        the access method to MMIO (via readb and writeb) instead of
-       iob and outb.  In this case, you have to pass the iomapped address
+       iob and outb. In this case, you have to pass the iomapped address
        to <function>snd_mpu401_uart_new()</function>.
        </para>
 
@@ -4341,7 +4336,7 @@ struct _snd_pcm_runtime {
        When <constant>MPU401_INFO_TX_IRQ</constant> is set, the output
        stream isn't checked in the default interrupt handler.  The driver
        needs to call <function>snd_mpu401_uart_interrupt_tx()</function>
-       by itself to start processing the output stream in irq handler.
+       by itself to start processing the output stream in the irq handler.
        </para>
 
       <para>
@@ -4381,7 +4376,7 @@ struct _snd_pcm_runtime {
       (<parameter>irq_flags</parameter>). Otherwise, pass the flags
       for irq allocation 
       (<constant>SA_XXX</constant> bits) to it, and the irq will be
-      reserved by the mpu401-uart layer. If the card doesn't generates
+      reserved by the mpu401-uart layer. If the card doesn't generate
       UART interrupts, pass -1 as the irq number. Then a timer
       interrupt will be invoked for polling. 
       </para>
@@ -4392,8 +4387,8 @@ struct _snd_pcm_runtime {
       <para>
         When the interrupt is allocated in
       <function>snd_mpu401_uart_new()</function>, the private
-      interrupt handler is used, hence you don't have to do nothing
-      else than creating the mpu401 stuff. Otherwise, you have to call
+      interrupt handler is used, hence you don't have anything else to do
+      than creating the mpu401 stuff. Otherwise, you have to call
       <function>snd_mpu401_uart_interrupt()</function> explicitly when
       a UART interrupt is invoked and checked in your own interrupt
       handler.  
@@ -4480,8 +4475,8 @@ struct _snd_pcm_runtime {
 
       <para>
       The fourth and fifth arguments are the number of output and
-      input substreams, respectively, of this device.  (A substream is
-      the equivalent of a MIDI port.)
+      input substreams, respectively, of this device (a substream is
+      the equivalent of a MIDI port).
       </para>
 
       <para>
@@ -4498,7 +4493,7 @@ struct _snd_pcm_runtime {
       <para>
       After the rawmidi device is created, you need to set the
       operators (callbacks) for each substream.  There are helper
-      functions to set the operators for all substream of a device:
+      functions to set the operators for all the substreams of a device:
         <informalexample>
           <programlisting>
 <![CDATA[
@@ -4528,8 +4523,8 @@ struct _snd_pcm_runtime {
       </para>
 
       <para>
-      If there is more than one substream, you should give each one a
-      unique name:
+      If there are more than one substream, you should give a
+      unique name to each of them:
         <informalexample>
           <programlisting>
 <![CDATA[
@@ -4550,7 +4545,7 @@ struct _snd_pcm_runtime {
       <title>Callbacks</title>
 
       <para>
-      In all callbacks, the private data that you've set for the
+      In all the callbacks, the private data that you've set for the
       rawmidi device can be accessed as
       substream-&gt;rmidi-&gt;private_data.
       <!-- <code> isn't available before DocBook 4.3 -->
@@ -4583,8 +4578,8 @@ struct _snd_pcm_runtime {
 
         <para>
         This is called when a substream is opened.
-        You can initialize the hardware here, but you should not yet
-        start transmitting/receiving data.
+        You can initialize the hardware here, but you shouldn't
+        start transmitting/receiving data yet.
         </para>
       </section>
 
@@ -4632,9 +4627,9 @@ struct _snd_pcm_runtime {
         To read data from the buffer, call
         <function>snd_rawmidi_transmit_peek</function>.  It will
         return the number of bytes that have been read; this will be
-        less than the number of bytes requested when there is no more
+        less than the number of bytes requested when there are no more
         data in the buffer.
-        After the data has been transmitted successfully, call
+        After the data have been transmitted successfully, call
         <function>snd_rawmidi_transmit_ack</function> to remove the
         data from the substream buffer:
           <informalexample>
@@ -4655,7 +4650,7 @@ struct _snd_pcm_runtime {
         <para>
         If you know beforehand that the hardware will accept data, you
         can use the <function>snd_rawmidi_transmit</function> function
-        which reads some data and removes it from the buffer at once:
+        which reads some data and removes them from the buffer at once:
           <informalexample>
             <programlisting>
 <![CDATA[
@@ -4749,13 +4744,13 @@ struct _snd_pcm_runtime {
 
         <para>
         This is only used with output substreams.  This function should wait
-        until all data read from the substream buffer has been transmitted.
+        until all data read from the substream buffer have been transmitted.
         This ensures that the device can be closed and the driver unloaded
         without losing data.
         </para>
 
         <para>
-        This callback is optional.  If you do not set
+        This callback is optional. If you do not set
         <structfield>drain</structfield> in the struct snd_rawmidi_ops
         structure, ALSA will simply wait for 50&nbsp;milliseconds
         instead.
@@ -4775,24 +4770,24 @@ struct _snd_pcm_runtime {
     <section id="misc-devices-opl3">
       <title>FM OPL3</title>
       <para>
-        The FM OPL3 is still used on many chips (mainly for backward
+        The FM OPL3 is still used in many chips (mainly for backward
       compatibility). ALSA has a nice OPL3 FM control layer, too. The
       OPL3 API is defined in
       <filename>&lt;sound/opl3.h&gt;</filename>. 
       </para>
 
       <para>
-        FM registers can be directly accessed through direct-FM API,
+        FM registers can be directly accessed through the direct-FM API,
       defined in <filename>&lt;sound/asound_fm.h&gt;</filename>. In
       ALSA native mode, FM registers are accessed through
-      Hardware-Dependant Device direct-FM extension API, whereas in
-      OSS compatible mode, FM registers can be accessed with OSS
-      direct-FM compatible API on <filename>/dev/dmfmX</filename> device. 
+      the Hardware-Dependant Device direct-FM extension API, whereas in
+      OSS compatible mode, FM registers can be accessed with the OSS
+      direct-FM compatible API in <filename>/dev/dmfmX</filename> device. 
       </para>
 
       <para>
-        For creating the OPL3 component, you have two functions to
-        call. The first one is a constructor for <type>opl3_t</type>
+        To create the OPL3 component, you have two functions to
+        call. The first one is a constructor for the <type>opl3_t</type>
         instance. 
 
         <informalexample>
@@ -4819,12 +4814,12 @@ struct _snd_pcm_runtime {
       <para>
         When the left and right ports have been already allocated by
       the card driver, pass non-zero to the fifth argument
-      (<parameter>integrated</parameter>). Otherwise, opl3 module will
+      (<parameter>integrated</parameter>). Otherwise, the opl3 module will
       allocate the specified ports by itself. 
       </para>
 
       <para>
-        When the accessing to the hardware requires special method
+        When the accessing the hardware requires special method
         instead of the standard I/O access, you can create opl3 instance
         separately with <function>snd_opl3_new()</function>.
 
@@ -4845,13 +4840,13 @@ struct _snd_pcm_runtime {
        access function, the private data and the destructor.
        The l_port and r_port are not necessarily set.  Only the
        command must be set properly.  You can retrieve the data
-       from opl3-&gt;private_data field.
+       from the opl3-&gt;private_data field.
       </para>
 
       <para>
        After creating the opl3 instance via <function>snd_opl3_new()</function>,
        call <function>snd_opl3_init()</function> to initialize the chip to the
-       proper state.  Note that <function>snd_opl3_create()</function> always
+       proper state. Note that <function>snd_opl3_create()</function> always
        calls it internally.
       </para>
 
@@ -4884,7 +4879,7 @@ struct _snd_pcm_runtime {
     <section id="misc-devices-hardware-dependent">
       <title>Hardware-Dependent Devices</title>
       <para>
-        Some chips need the access from the user-space for special
+        Some chips need user-space access for special
       controls or for loading the micro code. In such a case, you can
       create a hwdep (hardware-dependent) device. The hwdep API is
       defined in <filename>&lt;sound/hwdep.h&gt;</filename>. You can
@@ -4893,7 +4888,7 @@ struct _snd_pcm_runtime {
       </para>
 
       <para>
-        Creation of the <type>hwdep</type> instance is done via
+        The creation of the <type>hwdep</type> instance is done via
         <function>snd_hwdep_new()</function>. 
 
         <informalexample>
@@ -4912,8 +4907,8 @@ struct _snd_pcm_runtime {
         You can then pass any pointer value to the
         <parameter>private_data</parameter>.
         If you assign a private data, you should define the
-        destructor, too. The destructor function is set to
-        <structfield>private_free</structfield> field.  
+        destructor, too. The destructor function is set in
+        the <structfield>private_free</structfield> field.  
 
         <informalexample>
           <programlisting>
@@ -4925,7 +4920,7 @@ struct _snd_pcm_runtime {
           </programlisting>
         </informalexample>
 
-        and the implementation of destructor would be:
+        and the implementation of the destructor would be:
 
         <informalexample>
           <programlisting>
@@ -4943,7 +4938,7 @@ struct _snd_pcm_runtime {
       <para>
         The arbitrary file operations can be defined for this
         instance. The file operators are defined in
-        <parameter>ops</parameter> table. For example, assume that
+        the <parameter>ops</parameter> table. For example, assume that
         this chip needs an ioctl. 
 
         <informalexample>
@@ -4964,7 +4959,7 @@ struct _snd_pcm_runtime {
       <title>IEC958 (S/PDIF)</title>
       <para>
         Usually the controls for IEC958 devices are implemented via
-      control interface. There is a macro to compose a name string for
+      the control interface. There is a macro to compose a name string for
       IEC958 controls, <function>SNDRV_CTL_NAME_IEC958()</function>
       defined in <filename>&lt;include/asound.h&gt;</filename>.  
       </para>
@@ -4973,7 +4968,7 @@ struct _snd_pcm_runtime {
         There are some standard controls for IEC958 status bits. These
       controls use the type <type>SNDRV_CTL_ELEM_TYPE_IEC958</type>,
       and the size of element is fixed as 4 bytes array
-      (value.iec958.status[x]). For <structfield>info</structfield>
+      (value.iec958.status[x]). For the <structfield>info</structfield>
       callback, you don't specify 
       the value field for this type (the count field must be set,
       though). 
@@ -5001,7 +4996,7 @@ struct _snd_pcm_runtime {
       enable/disable or to set the raw bit mode. The implementation
       will depend on the chip, but the control should be named as
       <quote>IEC958 xxx</quote>, preferably using
-      <function>SNDRV_CTL_NAME_IEC958()</function> macro. 
+      the <function>SNDRV_CTL_NAME_IEC958()</function> macro. 
       </para>
 
       <para>
@@ -5036,12 +5031,12 @@ struct _snd_pcm_runtime {
         The allocation of pages with fallback is
       <function>snd_malloc_xxx_pages_fallback()</function>. This
       function tries to allocate the specified pages but if the pages
-      are not available, it tries to reduce the page sizes until the
+      are not available, it tries to reduce the page sizes until
       enough space is found.
       </para>
 
       <para>
-      For releasing the space, call
+      The release the pages, call
       <function>snd_free_xxx_pages()</function> function. 
       </para>
 
@@ -5050,8 +5045,8 @@ struct _snd_pcm_runtime {
        a large contiguous physical space
        at the time the module is loaded for the later use.
        This is called <quote>pre-allocation</quote>.
-       As already written, you can call the following function at the
-       construction of pcm instance (in the case of PCI bus). 
+       As already written, you can call the following function at 
+       pcm instance construction time (in the case of PCI bus). 
 
         <informalexample>
           <programlisting>
@@ -5063,34 +5058,34 @@ struct _snd_pcm_runtime {
         </informalexample>
 
         where <parameter>size</parameter> is the byte size to be
-      pre-allocated and the <parameter>max</parameter> is the maximal
-      size to be changed via <filename>prealloc</filename> proc file.
-      The allocator will try to get as large area as possible
+      pre-allocated and the <parameter>max</parameter> is the maximum
+      size to be changed via the <filename>prealloc</filename> proc file.
+      The allocator will try to get an area as large as possible
       within the given size. 
       </para>
 
       <para>
       The second argument (type) and the third argument (device pointer)
       are dependent on the bus.
-      In the case of ISA bus, pass <function>snd_dma_isa_data()</function>
+      In the case of the ISA bus, pass <function>snd_dma_isa_data()</function>
       as the third argument with <constant>SNDRV_DMA_TYPE_DEV</constant> type.
       For the continuous buffer unrelated to the bus can be pre-allocated
       with <constant>SNDRV_DMA_TYPE_CONTINUOUS</constant> type and the
       <function>snd_dma_continuous_data(GFP_KERNEL)</function> device pointer,
-      whereh <constant>GFP_KERNEL</constant> is the kernel allocation flag to
+      where <constant>GFP_KERNEL</constant> is the kernel allocation flag to
       use.  For the SBUS, <constant>SNDRV_DMA_TYPE_SBUS</constant> and
       <function>snd_dma_sbus_data(sbus_dev)</function> are used instead.
       For the PCI scatter-gather buffers, use
       <constant>SNDRV_DMA_TYPE_DEV_SG</constant> with
       <function>snd_dma_pci_data(pci)</function>
-      (see the section
+      (see the 
           <link linkend="buffer-and-memory-non-contiguous"><citetitle>Non-Contiguous Buffers
-          </citetitle></link>).
+          </citetitle></link> section).
       </para>
 
       <para>
-        Once when the buffer is pre-allocated, you can use the
-        allocator in the <structfield>hw_params</structfield> callback 
+        Once the buffer is pre-allocated, you can use the
+        allocator in the <structfield>hw_params</structfield> callback: 
 
         <informalexample>
           <programlisting>
@@ -5116,8 +5111,8 @@ struct _snd_pcm_runtime {
       </para>
 
       <para>
-        The first case works fine if the external hardware buffer is enough
-      large.  This method doesn't need any extra buffers and thus is
+        The first case works fine if the external hardware buffer is large
+      enough.  This method doesn't need any extra buffers and thus is
       more effective. You need to define the
       <structfield>copy</structfield> and
       <structfield>silence</structfield> callbacks for 
@@ -5127,25 +5122,25 @@ struct _snd_pcm_runtime {
       </para>
 
       <para>
-        The second case allows the mmap of the buffer, although you have
-      to handle an interrupt or a tasklet for transferring the data
+        The second case allows for mmap on the buffer, although you have
+      to handle an interrupt or a tasklet to transfer the data
       from the intermediate buffer to the hardware buffer. You can find an
-      example in vxpocket driver. 
+      example in the vxpocket driver. 
       </para>
 
       <para>
-        Another case is that the chip uses a PCI memory-map
+        Another case is when the chip uses a PCI memory-map
       region for the buffer instead of the host memory. In this case,
-      mmap is available only on certain architectures like intel. In
-      non-mmap mode, the data cannot be transferred as the normal
-      way. Thus you need to define <structfield>copy</structfield> and
-      <structfield>silence</structfield> callbacks as well 
+      mmap is available only on certain architectures like the Intel one.
+      In non-mmap mode, the data cannot be transferred as in the normal
+      way. Thus you need to define the <structfield>copy</structfield> and
+      <structfield>silence</structfield> callbacks as well, 
       as in the cases above. The examples are found in
       <filename>rme32.c</filename> and <filename>rme96.c</filename>. 
       </para>
 
       <para>
-        The implementation of <structfield>copy</structfield> and
+        The implementation of the <structfield>copy</structfield> and
         <structfield>silence</structfield> callbacks depends upon 
         whether the hardware supports interleaved or non-interleaved
         samples. The <structfield>copy</structfield> callback is
@@ -5184,8 +5179,8 @@ struct _snd_pcm_runtime {
 
       <para>
         What you have to do in this callback is again different
-        between playback and capture directions. In the case of
-        playback, you do: copy the given amount of data
+        between playback and capture directions. In the
+        playback case, you copy the given amount of data
         (<parameter>count</parameter>) at the specified pointer
         (<parameter>src</parameter>) to the specified offset
         (<parameter>pos</parameter>) on the hardware buffer. When
@@ -5202,7 +5197,7 @@ struct _snd_pcm_runtime {
       </para>
 
       <para>
-        For the capture direction, you do: copy the given amount of
+        For the capture direction, you copy the given amount of
         data (<parameter>count</parameter>) at the specified offset
         (<parameter>pos</parameter>) on the hardware buffer to the
         specified pointer (<parameter>dst</parameter>). 
@@ -5216,7 +5211,7 @@ struct _snd_pcm_runtime {
           </programlisting>
         </informalexample>
 
-        Note that both of the position and the data amount are given
+        Note that both the position and the amount of data are given
       in frames. 
       </para>
 
@@ -5247,7 +5242,7 @@ struct _snd_pcm_runtime {
       </para>
 
       <para>
-        The meanings of arguments are identical with the
+        The meanings of arguments are the same as in the
       <structfield>copy</structfield> 
       callback, although there is no <parameter>src/dst</parameter>
       argument. In the case of interleaved samples, the channel
@@ -5284,8 +5279,8 @@ struct _snd_pcm_runtime {
     <section id="buffer-and-memory-non-contiguous">
       <title>Non-Contiguous Buffers</title>
       <para>
-        If your hardware supports the page table like emu10k1 or the
-      buffer descriptors like via82xx, you can use the scatter-gather
+        If your hardware supports the page table as in emu10k1 or the
+      buffer descriptors as in via82xx, you can use the scatter-gather
       (SG) DMA. ALSA provides an interface for handling SG-buffers.
       The API is provided in <filename>&lt;sound/pcm.h&gt;</filename>. 
       </para>
@@ -5296,7 +5291,7 @@ struct _snd_pcm_runtime {
         <function>snd_pcm_lib_preallocate_pages_for_all()</function>
         with <constant>SNDRV_DMA_TYPE_DEV_SG</constant>
        in the PCM constructor like other PCI pre-allocator.
-        You need to pass the <function>snd_dma_pci_data(pci)</function>,
+        You need to pass <function>snd_dma_pci_data(pci)</function>,
         where pci is the struct <structname>pci_dev</structname> pointer
         of the chip as well.
         The <type>struct snd_sg_buf</type> instance is created as
@@ -5314,7 +5309,7 @@ struct _snd_pcm_runtime {
 
       <para>
         Then call <function>snd_pcm_lib_malloc_pages()</function>
-      in <structfield>hw_params</structfield> callback
+      in the <structfield>hw_params</structfield> callback
       as well as in the case of normal PCI buffer.
       The SG-buffer handler will allocate the non-contiguous kernel
       pages of the given size and map them onto the virtually contiguous
@@ -5335,7 +5330,7 @@ struct _snd_pcm_runtime {
       </para>
 
       <para>
-        For releasing the data, call
+        To release the data, call
       <function>snd_pcm_lib_free_pages()</function> in the
       <structfield>hw_free</structfield> callback as usual.
       </para>
@@ -5390,7 +5385,7 @@ struct _snd_pcm_runtime {
     </para>
 
     <para>
-      For creating a proc file, call
+      To create a proc file, call
       <function>snd_card_proc_new()</function>. 
 
       <informalexample>
@@ -5402,7 +5397,7 @@ struct _snd_pcm_runtime {
         </programlisting>
       </informalexample>
 
-      where the second argument specifies the proc-file name to be
+      where the second argument specifies the name of the proc file to be
     created. The above example will create a file
     <filename>my-file</filename> under the card directory,
     e.g. <filename>/proc/asound/card0/my-file</filename>. 
@@ -5417,8 +5412,8 @@ struct _snd_pcm_runtime {
 
     <para>
       When the creation is successful, the function stores a new
-    instance at the pointer given in the third argument.
-    It is initialized as a text proc file for read only.  For using
+    instance in the pointer given in the third argument.
+    It is initialized as a text proc file for read only.  To use
     this proc file as a read-only text file as it is, set the read
     callback with a private data via 
      <function>snd_info_set_text_ops()</function>.
@@ -5470,9 +5465,9 @@ struct _snd_pcm_runtime {
     </para>
 
     <para>
-    The file permission can be changed afterwards.  As default, it's
-    set as read only for all users.  If you want to add the write
-    permission to the user (root as default), set like below:
+    The file permissions can be changed afterwards.  As default, it's
+    set as read only for all users.  If you want to add write
+    permission for the user (root as default), do as follows:
 
       <informalexample>
         <programlisting>
@@ -5503,7 +5498,7 @@ struct _snd_pcm_runtime {
     </para>
 
     <para>
-      For a raw-data proc-file, set the attributes like the following:
+      For a raw-data proc-file, set the attributes as follows:
 
       <informalexample>
         <programlisting>
@@ -5524,7 +5519,7 @@ struct _snd_pcm_runtime {
 
     <para>
       The callback is much more complicated than the text-file
-      version. You need to use a low-level i/o functions such as
+      version. You need to use a low-level I/O functions such as
       <function>copy_from/to_user()</function> to transfer the
       data.
 
@@ -5560,28 +5555,28 @@ struct _snd_pcm_runtime {
     <title>Power Management</title>
     <para>
       If the chip is supposed to work with suspend/resume
-      functions, you need to add the power-management codes to the
-      driver. The additional codes for the power-management should be
+      functions, you need to add power-management code to the
+      driver. The additional code for power-management should be
       <function>ifdef</function>'ed with
       <constant>CONFIG_PM</constant>. 
     </para>
 
        <para>
-       If the driver supports the suspend/resume
-       <emphasis>fully</emphasis>, that is, the device can be
-       properly resumed to the status at the suspend is called,
-       you can set <constant>SNDRV_PCM_INFO_RESUME</constant> flag
-       to pcm info field.  Usually, this is possible when the
-       registers of ths chip can be safely saved and restored to the
-       RAM.  If this is set, the trigger callback is called with
-       <constant>SNDRV_PCM_TRIGGER_RESUME</constant> after resume
-       callback is finished
+       If the driver <emphasis>fully</emphasis> supports suspend/resume
+       that is, the device can be
+       properly resumed to its state when suspend was called,
+       you can set the <constant>SNDRV_PCM_INFO_RESUME</constant> flag
+       in the pcm info field.  Usually, this is possible when the
+       registers of the chip can be safely saved and restored to
+       RAM. If this is set, the trigger callback is called with
+       <constant>SNDRV_PCM_TRIGGER_RESUME</constant> after the resume
+       callback completes
        </para>
 
        <para>
-       Even if the driver doesn't support PM fully but only the
-       partial suspend/resume is possible, it's still worthy to
-       implement suspend/resume callbacks.  In such a case, applications
+       Even if the driver doesn't support PM fully but 
+       partial suspend/resume is still possible, it's still worthy to
+       implement suspend/resume callbacks. In such a case, applications
        would reset the status by calling
        <function>snd_pcm_prepare()</function> and restart the stream
        appropriately.  Hence, you can define suspend/resume callbacks
@@ -5590,22 +5585,22 @@ struct _snd_pcm_runtime {
        </para>
        
        <para>
-       Note that the trigger with SUSPEND can be always called when
+       Note that the trigger with SUSPEND can always be called when
        <function>snd_pcm_suspend_all</function> is called,
-       regardless of <constant>SNDRV_PCM_INFO_RESUME</constant> flag.
+       regardless of the <constant>SNDRV_PCM_INFO_RESUME</constant> flag.
        The <constant>RESUME</constant> flag affects only the behavior
        of <function>snd_pcm_resume()</function>.
        (Thus, in theory,
        <constant>SNDRV_PCM_TRIGGER_RESUME</constant> isn't needed
        to be handled in the trigger callback when no
        <constant>SNDRV_PCM_INFO_RESUME</constant> flag is set.  But,
-       it's better to keep it for compatibility reason.)
+       it's better to keep it for compatibility reasons.)
        </para>
     <para>
       In the earlier version of ALSA drivers, a common
       power-management layer was provided, but it has been removed.
       The driver needs to define the suspend/resume hooks according to
-      the bus the device is assigned.  In the case of PCI driver, the
+      the bus the device is connected to.  In the case of PCI drivers, the
       callbacks look like below:
 
       <informalexample>
@@ -5629,7 +5624,7 @@ struct _snd_pcm_runtime {
     </para>
 
     <para>
-      The scheme of the real suspend job is as following.
+      The scheme of the real suspend job is as follows.
 
       <orderedlist>
         <listitem><para>Retrieve the card and the chip data.</para></listitem>
@@ -5679,11 +5674,11 @@ struct _snd_pcm_runtime {
     </para>
 
     <para>
-    The scheme of the real resume job is as following.
+    The scheme of the real resume job is as follows.
 
     <orderedlist>
     <listitem><para>Retrieve the card and the chip data.</para></listitem>
-    <listitem><para>Set up PCI.  First, call <function>pci_restore_state()</function>.
+    <listitem><para>Set up PCI. First, call <function>pci_restore_state()</function>.
        Then enable the pci device again by calling <function>pci_enable_device()</function>.
        Call <function>pci_set_master()</function> if necessary, too.</para></listitem>
     <listitem><para>Re-initialize the chip.</para></listitem>
@@ -5734,7 +5729,7 @@ struct _snd_pcm_runtime {
        <function>snd_pcm_suspend_all()</function> or
        <function>snd_pcm_suspend()</function>.  It means that the PCM
        streams are already stoppped when the register snapshot is
-       taken.  But, remind that you don't have to restart the PCM
+       taken.  But, remember that you don't have to restart the PCM
        stream in the resume callback. It'll be restarted via 
        trigger call with <constant>SNDRV_PCM_TRIGGER_RESUME</constant>
        when necessary.
@@ -5795,7 +5790,7 @@ struct _snd_pcm_runtime {
     </para>
 
     <para>
-      If you need a space for saving the registers, allocate the
+      If you need a space to save the registers, allocate the
        buffer for it here, too, since it would be fatal
     if you cannot allocate a memory in the suspend phase.
     The allocated buffer should be released in the corresponding
@@ -5833,7 +5828,7 @@ struct _snd_pcm_runtime {
     <title>Module Parameters</title>
     <para>
       There are standard module options for ALSA. At least, each
-      module should have <parameter>index</parameter>,
+      module should have the <parameter>index</parameter>,
       <parameter>id</parameter> and <parameter>enable</parameter>
       options. 
     </para>
@@ -5841,8 +5836,8 @@ struct _snd_pcm_runtime {
     <para>
       If the module supports multiple cards (usually up to
       8 = <constant>SNDRV_CARDS</constant> cards), they should be
-      arrays.  The default initial values are defined already as
-      constants for ease of programming:
+      arrays. The default initial values are defined already as
+      constants for easier programming:
 
       <informalexample>
         <programlisting>
@@ -5858,7 +5853,7 @@ struct _snd_pcm_runtime {
     <para>
       If the module supports only a single card, they could be single
     variables, instead.  <parameter>enable</parameter> option is not
-    always necessary in this case, but it wouldn't be so bad to have a
+    always necessary in this case, but it would be better to have a
     dummy option for compatibility.
     </para>
 
@@ -5923,22 +5918,22 @@ struct _snd_pcm_runtime {
        </para>
 
        <para>
-       Suppose that you'll create a new PCI driver for the card
+       Suppose that you create a new PCI driver for the card
        <quote>xyz</quote>.  The card module name would be
-       snd-xyz.  The new driver is usually put into alsa-driver
+       snd-xyz.  The new driver is usually put into the alsa-driver
        tree, <filename>alsa-driver/pci</filename> directory in
        the case of PCI cards.
        Then the driver is evaluated, audited and tested
        by developers and users.  After a certain time, the driver
-       will go to alsa-kernel tree (to the corresponding directory,
+       will go to the alsa-kernel tree (to the corresponding directory,
        such as <filename>alsa-kernel/pci</filename>) and eventually
-       integrated into Linux 2.6 tree (the directory would be
+       will be integrated into the Linux 2.6 tree (the directory would be
        <filename>linux/sound/pci</filename>).
        </para>
 
        <para>
        In the following sections, the driver code is supposed
-       to be put into alsa-driver tree.  The two cases are assumed:
+       to be put into alsa-driver tree. The two cases are covered:
        a driver consisting of a single source file and one consisting
        of several source files.
        </para>
@@ -6033,7 +6028,7 @@ struct _snd_pcm_runtime {
        <listitem>
        <para>
        Add a new directory (<filename>xyz</filename>) in
-       <filename>alsa-driver/pci/Makefile</filename> like below
+       <filename>alsa-driver/pci/Makefile</filename> as below
 
       <informalexample>
         <programlisting>
@@ -6102,7 +6097,7 @@ struct _snd_pcm_runtime {
     <section id="useful-functions-snd-printk">
       <title><function>snd_printk()</function> and friends</title>
       <para>
-        ALSA provides a verbose version of
+        ALSA provides a verbose version of the
       <function>printk()</function> function. If a kernel config
       <constant>CONFIG_SND_VERBOSE_PRINTK</constant> is set, this
       function prints the given message together with the file name
@@ -6170,7 +6165,7 @@ struct _snd_pcm_runtime {
     <section id="useful-functions-snd-bug">
       <title><function>snd_BUG()</function></title>
       <para>
-        It shows <computeroutput>BUG?</computeroutput> message and
+        It shows the <computeroutput>BUG?</computeroutput> message and
       stack trace as well as <function>snd_assert</function> at the point.
       It's useful to show that a fatal error happens there. 
       </para>
@@ -6199,6 +6194,4 @@ struct _snd_pcm_runtime {
     in the hardware constraints section.
     </para>
   </chapter>
-
-
 </book>
index 3feeb9ecdec49719443cba15fcac628a0c24b058..0ebd7ea9706cc1ced01508562d866d520eb1dec6 100644 (file)
@@ -1,5 +1,5 @@
 ASoC currently supports the three main Digital Audio Interfaces (DAI) found on
-SoC controllers and portable audio CODECS today, namely AC97, I2S and PCM.
+SoC controllers and portable audio CODECs today, namely AC97, I2S and PCM.
 
 
 AC97
@@ -25,7 +25,7 @@ left/right clock (LRC) synchronise the link. I2S is flexible in that either the
 controller or CODEC can drive (master) the BCLK and LRC clock lines. Bit clock
 usually varies depending on the sample rate and the master system clock
 (SYSCLK). LRCLK is the same as the sample rate. A few devices support separate
-ADC and DAC LRCLK's, this allows for simultaneous capture and playback at
+ADC and DAC LRCLKs, this allows for simultaneous capture and playback at
 different sample rates.
 
 I2S has several different operating modes:-
@@ -35,7 +35,7 @@ I2S has several different operating modes:-
 
  o Left Justified - MSB is transmitted on transition of LRC.
 
- o Right Justified - MSB is transmitted sample size BCLK's before LRC
+ o Right Justified - MSB is transmitted sample size BCLKs before LRC
                      transition.
 
 PCM
index 14930887c25f194c206a43dd6c56bd6188e07dd2..b1300162e01cef93ae7f97dc728ce02255487500 100644 (file)
@@ -13,7 +13,7 @@ or SYSCLK). This audio master clock can be derived from a number of sources
 (e.g. crystal, PLL, CPU clock) and is responsible for producing the correct
 audio playback and capture sample rates.
 
-Some master clocks (e.g. PLL's and CPU based clocks) are configurable in that
+Some master clocks (e.g. PLLs and CPU based clocks) are configurable in that
 their speed can be altered by software (depending on the system use and to save
 power). Other master clocks are fixed at a set frequency (i.e. crystals).
 
@@ -41,11 +41,11 @@ BCLK = LRC * x
 BCLK = LRC * Channels * Word Size
 
 This relationship depends on the codec or SoC CPU in particular. In general
-it's best to configure BCLK to the lowest possible speed (depending on your
-rate, number of channels and wordsize) to save on power.
+it is best to configure BCLK to the lowest possible speed (depending on your
+rate, number of channels and word size) to save on power.
 
-It's also desirable to use the codec (if possible) to drive (or master) the
-audio clocks as it's usually gives more accurate sample rates than the CPU.
+It is also desirable to use the codec (if possible) to drive (or master) the
+audio clocks as it usually gives more accurate sample rates than the CPU.
 
 
 
index 1e766ad0ebd1f4f28f4e20cb88899d4b8f5717da..1e95342ed72e4d7b91ef53743cc11c42fcf8dd12 100644 (file)
@@ -9,7 +9,7 @@ code should be added to the platform and machine drivers respectively.
 Each codec driver *must* provide the following features:-
 
  1) Codec DAI and PCM configuration
- 2) Codec control IO - using I2C, 3 Wire(SPI) or both API's
+ 2) Codec control IO - using I2C, 3 Wire(SPI) or both APIs
  3) Mixers and audio controls
  4) Codec audio operations
 
@@ -19,7 +19,7 @@ Optionally, codec drivers can also provide:-
  6) DAPM event handler.
  7) DAC Digital mute control.
 
-It's probably best to use this guide in conjunction with the existing codec
+Its probably best to use this guide in conjunction with the existing codec
 driver code in sound/soc/codecs/
 
 ASoC Codec driver breakdown
@@ -27,8 +27,8 @@ ASoC Codec driver breakdown
 
 1 - Codec DAI and PCM configuration
 -----------------------------------
-Each codec driver must have a struct snd_soc_codec_dai to define it's DAI and
-PCM's capabilities and operations. This struct is exported so that it can be
+Each codec driver must have a struct snd_soc_codec_dai to define its DAI and
+PCM capabilities and operations. This struct is exported so that it can be
 registered with the core by your machine driver.
 
 e.g.
@@ -67,18 +67,18 @@ EXPORT_SYMBOL_GPL(wm8731_dai);
 
 2 - Codec control IO
 --------------------
-The codec can usually be controlled via an I2C or SPI style interface (AC97
-combines control with data in the DAI). The codec drivers will have to provide
-functions to read and write the codec registers along with supplying a register
-cache:-
+The codec can usually be controlled via an I2C or SPI style interface
+(AC97 combines control with data in the DAI). The codec drivers provide
+functions to read and write the codec registers along with supplying a
+register cache:-
 
        /* IO control data and register cache */
-    void *control_data; /* codec control (i2c/3wire) data */
-    void *reg_cache;
+       void *control_data; /* codec control (i2c/3wire) data */
+       void *reg_cache;
 
-Codec read/write should do any data formatting and call the hardware read write
-below to perform the IO. These functions are called by the core and alsa when
-performing DAPM or changing the mixer:-
+Codec read/write should do any data formatting and call the hardware
+read write below to perform the IO. These functions are called by the
+core and ALSA when performing DAPM or changing the mixer:-
 
     unsigned int (*read)(struct snd_soc_codec *, unsigned int);
     int (*write)(struct snd_soc_codec *, unsigned int, unsigned int);
@@ -131,7 +131,7 @@ Defines a stereo enumerated control
 
 4 - Codec Audio Operations
 --------------------------
-The codec driver also supports the following alsa operations:-
+The codec driver also supports the following ALSA operations:-
 
 /* SoC audio ops */
 struct snd_soc_ops {
@@ -142,15 +142,15 @@ struct snd_soc_ops {
        int (*prepare)(struct snd_pcm_substream *);
 };
 
-Please refer to the alsa driver PCM documentation for details.
+Please refer to the ALSA driver PCM documentation for details.
 http://www.alsa-project.org/~iwai/writing-an-alsa-driver/c436.htm
 
 
 5 - DAPM description.
 ---------------------
-The Dynamic Audio Power Management description describes the codec's power
-components, their relationships and registers to the ASoC core. Please read
-dapm.txt for details of building the description.
+The Dynamic Audio Power Management description describes the codec power
+components and their relationships and registers to the ASoC core.
+Please read dapm.txt for details of building the description.
 
 Please also see the examples in other codec drivers.
 
@@ -158,8 +158,8 @@ Please also see the examples in other codec drivers.
 6 - DAPM event handler
 ----------------------
 This function is a callback that handles codec domain PM calls and system
-domain PM calls (e.g. suspend and resume). It's used to put the codec to sleep
-when not in use.
+domain PM calls (e.g. suspend and resume). It is used to put the codec
+to sleep when not in use.
 
 Power states:-
 
@@ -175,13 +175,14 @@ Power states:-
        SNDRV_CTL_POWER_D3cold: /* Everything Off, without power */
 
 
-7 - Codec DAC digital mute control.
-------------------------------------
-Most codecs have a digital mute before the DAC's that can be used to minimise
-any system noise.  The mute stops any digital data from entering the DAC.
+7 - Codec DAC digital mute control
+----------------------------------
+Most codecs have a digital mute before the DACs that can be used to
+minimise any system noise.  The mute stops any digital data from
+entering the DAC.
 
-A callback can be created that is called by the core for each codec DAI when the
-mute is applied or freed.
+A callback can be created that is called by the core for each codec DAI
+when the mute is applied or freed.
 
 i.e.
 
index ab0766fd78690859e1594602fcd62155f48b0529..c784a18b94dce93bdcb064b2ef6670d450846bd5 100644 (file)
@@ -4,20 +4,20 @@ Dynamic Audio Power Management for Portable Devices
 1. Description
 ==============
 
-Dynamic Audio Power Management (DAPM) is designed to allow portable Linux devices
-to use the minimum amount of power within the audio subsystem at all times. It
-is independent of other kernel PM and as such, can easily co-exist with the
-other PM systems.
+Dynamic Audio Power Management (DAPM) is designed to allow portable
+Linux devices to use the minimum amount of power within the audio
+subsystem at all times. It is independent of other kernel PM and as
+such, can easily co-exist with the other PM systems.
 
-DAPM is also completely transparent to all user space applications as all power
-switching is done within the ASoC core. No code changes or recompiling are
-required for user space applications. DAPM makes power switching decisions based
-upon any audio stream (capture/playback) activity and audio mixer settings
-within the device.
+DAPM is also completely transparent to all user space applications as
+all power switching is done within the ASoC core. No code changes or
+recompiling are required for user space applications. DAPM makes power
+switching decisions based upon any audio stream (capture/playback)
+activity and audio mixer settings within the device.
 
-DAPM spans the whole machine. It covers power control within the entire audio
-subsystem, this includes internal codec power blocks and machine level power
-systems.
+DAPM spans the whole machine. It covers power control within the entire
+audio subsystem, this includes internal codec power blocks and machine
+level power systems.
 
 There are 4 power domains within DAPM
 
@@ -34,7 +34,7 @@ There are 4 power domains within DAPM
       Automatically set when mixer and mux settings are changed by the user.
       e.g. alsamixer, amixer.
 
-   4. Stream domain - DAC's and ADC's.
+   4. Stream domain - DACs and ADCs.
       Enabled and disabled when stream playback/capture is started and
       stopped respectively. e.g. aplay, arecord.
 
@@ -51,7 +51,7 @@ widgets hereafter.
 Audio DAPM widgets fall into a number of types:-
 
  o Mixer      - Mixes several analog signals into a single analog signal.
- o Mux        - An analog switch that outputs only 1 of it's inputs.
+ o Mux        - An analog switch that outputs only one of many inputs.
  o PGA        - A programmable gain amplifier or attenuation widget.
  o ADC        - Analog to Digital Converter
  o DAC        - Digital to Analog Converter
@@ -78,14 +78,14 @@ parameters for stream name and kcontrols.
 2.1 Stream Domain Widgets
 -------------------------
 
-Stream Widgets relate to the stream power domain and only consist of ADC's
-(analog to digital converters) and DAC's (digital to analog converters).
+Stream Widgets relate to the stream power domain and only consist of ADCs
+(analog to digital converters) and DACs (digital to analog converters).
 
 Stream widgets have the following format:-
 
 SND_SOC_DAPM_DAC(name, stream name, reg, shift, invert),
 
-NOTE: the stream name must match the corresponding stream name in your codecs
+NOTE: the stream name must match the corresponding stream name in your codec
 snd_soc_codec_dai.
 
 e.g. stream widgets for HiFi playback and capture
@@ -97,7 +97,7 @@ SND_SOC_DAPM_ADC("HiFi ADC", "HiFi Capture", REG, 2, 1),
 2.2 Path Domain Widgets
 -----------------------
 
-Path domain widgets have a ability to control or effect the audio signal or
+Path domain widgets have a ability to control or affect the audio signal or
 audio paths within the audio subsystem. They have the following form:-
 
 SND_SOC_DAPM_PGA(name, reg, shift, invert, controls, num_controls)
@@ -149,7 +149,7 @@ SND_SOC_DAPM_MIC("Mic Jack", spitz_mic_bias),
 2.4 Codec Domain
 ----------------
 
-The Codec power domain has no widgets and is handled by the codecs DAPM event
+The codec power domain has no widgets and is handled by the codecs DAPM event
 handler. This handler is called when the codec powerstate is changed wrt to any
 stream event or by kernel PM events.
 
@@ -158,8 +158,8 @@ stream event or by kernel PM events.
 -------------------
 
 Sometimes widgets exist in the codec or machine audio map that don't have any
-corresponding register bit for power control. In this case it's necessary to
-create a virtual widget - a widget with no control bits e.g.
+corresponding soft power control. In this case it is necessary to create
+a virtual widget - a widget with no control bits e.g.
 
 SND_SOC_DAPM_MIXER("AC97 Mixer", SND_SOC_DAPM_NOPM, 0, 0, NULL, 0),
 
@@ -172,13 +172,14 @@ subsystem individually with a call to snd_soc_dapm_new_control().
 3. Codec Widget Interconnections
 ================================
 
-Widgets are connected to each other within the codec and machine by audio
-paths (called interconnections). Each interconnection must be defined in order
-to create a map of all audio paths between widgets.
+Widgets are connected to each other within the codec and machine by audio paths
+(called interconnections). Each interconnection must be defined in order to
+create a map of all audio paths between widgets.
+
 This is easiest with a diagram of the codec (and schematic of the machine audio
 system), as it requires joining widgets together via their audio signal paths.
 
-i.e. from the WM8731 codec's output mixer (wm8731.c)
+e.g., from the WM8731 output mixer (wm8731.c)
 
 The WM8731 output mixer has 3 inputs (sources)
 
index 72bd222f2a21796316a27cea63a539e620fdd99f..f370e7db86af6a970de14433523af4b1ca71d390 100644 (file)
@@ -16,7 +16,7 @@ struct snd_soc_machine {
        int (*remove)(struct platform_device *pdev);
 
        /* the pre and post PM functions are used to do any PM work before and
-        * after the codec and DAI's do any PM work. */
+        * after the codec and DAIs do any PM work. */
        int (*suspend_pre)(struct platform_device *pdev, pm_message_t state);
        int (*suspend_post)(struct platform_device *pdev, pm_message_t state);
        int (*resume_pre)(struct platform_device *pdev);
@@ -38,7 +38,7 @@ probe/remove are optional. Do any machine specific probe here.
 suspend()/resume()
 ------------------
 The machine driver has pre and post versions of suspend and resume to take care
-of any machine audio tasks that have to be done before or after the codec, DAI's
+of any machine audio tasks that have to be done before or after the codec, DAIs
 and DMA is suspended and resumed. Optional.
 
 
@@ -49,10 +49,10 @@ The machine specific audio operations can be set here. Again this is optional.
 
 Machine DAI Configuration
 -------------------------
-The machine DAI configuration glues all the codec and CPU DAI's together. It can
+The machine DAI configuration glues all the codec and CPU DAIs together. It can
 also be used to set up the DAI system clock and for any machine related DAI
 initialisation e.g. the machine audio map can be connected to the codec audio
-map, unconnnected codec pins can be set as such. Please see corgi.c, spitz.c
+map, unconnected codec pins can be set as such. Please see corgi.c, spitz.c
 for examples.
 
 struct snd_soc_dai_link is used to set up each DAI in your machine. e.g.
@@ -67,7 +67,7 @@ static struct snd_soc_dai_link corgi_dai = {
        .ops = &corgi_ops,
 };
 
-struct snd_soc_machine then sets up the machine with it's DAI's. e.g.
+struct snd_soc_machine then sets up the machine with it's DAIs. e.g.
 
 /* corgi audio machine driver */
 static struct snd_soc_machine snd_soc_machine_corgi = {
@@ -110,4 +110,4 @@ details.
 Machine Controls
 ----------------
 
-Machine specific audio mixer controls can be added in the dai init function.
\ No newline at end of file
+Machine specific audio mixer controls can be added in the DAI init function.
index c47ce9530677961142f371784bc7550cdc58c460..1e4c6d3655f2089c875ff381759ebd5528fe2ad3 100644 (file)
@@ -1,25 +1,26 @@
 ALSA SoC Layer
 ==============
 
-The overall project goal of the ALSA System on Chip (ASoC) layer is to provide
-better ALSA support for embedded system-on-chip processors (e.g. pxa2xx, au1x00,
-iMX, etc) and portable audio codecs. Currently there is some support in the
-kernel for SoC audio, however it has some limitations:-
+The overall project goal of the ALSA System on Chip (ASoC) layer is to
+provide better ALSA support for embedded system-on-chip processors (e.g.
+pxa2xx, au1x00, iMX, etc) and portable audio codecs.  Prior to the ASoC
+subsystem there was some support in the kernel for SoC audio, however it
+had some limitations:-
 
-  * Currently, codec drivers are often tightly coupled to the underlying SoC
-    CPU. This is not ideal and leads to code duplication i.e. Linux now has 4
-    different wm8731 drivers for 4 different SoC platforms.
+  * Codec drivers were often tightly coupled to the underlying SoC
+    CPU. This is not ideal and leads to code duplication - for example,
+    Linux had different wm8731 drivers for 4 different SoC platforms.
 
-  * There is no standard method to signal user initiated audio events (e.g.
+  * There was no standard method to signal user initiated audio events (e.g.
     Headphone/Mic insertion, Headphone/Mic detection after an insertion
     event). These are quite common events on portable devices and often require
     machine specific code to re-route audio, enable amps, etc., after such an
     event.
 
-  * Current drivers tend to power up the entire codec when playing
-    (or recording) audio. This is fine for a PC, but tends to waste a lot of
-    power on portable devices. There is also no support for saving power via
-    changing codec oversampling rates, bias currents, etc.
+  * Drivers tended to power up the entire codec when playing (or
+    recording) audio. This is fine for a PC, but tends to waste a lot of
+    power on portable devices. There was also no support for saving
+    power via changing codec oversampling rates, bias currents, etc.
 
 
 ASoC Design
@@ -31,12 +32,13 @@ features :-
   * Codec independence. Allows reuse of codec drivers on other platforms
     and machines.
 
-  * Easy I2S/PCM audio interface setup between codec and SoC. Each SoC interface
-    and codec registers it's audio interface capabilities with the core and are
-    subsequently matched and configured when the application hw params are known.
+  * Easy I2S/PCM audio interface setup between codec and SoC. Each SoC
+    interface and codec registers it's audio interface capabilities with the
+    core and are subsequently matched and configured when the application
+    hardware parameters are known.
 
   * Dynamic Audio Power Management (DAPM). DAPM automatically sets the codec to
-    it's minimum power state at all times. This includes powering up/down
+    its minimum power state at all times. This includes powering up/down
     internal power blocks depending on the internal codec audio routing and any
     active streams.
 
@@ -45,16 +47,16 @@ features :-
     signals the codec when to change power states.
 
   * Machine specific controls: Allow machines to add controls to the sound card
-    (e.g. volume control for speaker amp).
+    (e.g. volume control for speaker amplifier).
 
 To achieve all this, ASoC basically splits an embedded audio system into 3
 components :-
 
   * Codec driver: The codec driver is platform independent and contains audio
-    controls, audio interface capabilities, codec dapm definition and codec IO
+    controls, audio interface capabilities, codec DAPM definition and codec IO
     functions.
 
-  * Platform driver: The platform driver contains the audio dma engine and audio
+  * Platform driver: The platform driver contains the audio DMA engine and audio
     interface drivers (e.g. I2S, AC97, PCM) for that platform.
 
   * Machine driver: The machine driver handles any machine specific controls and
@@ -81,4 +83,4 @@ machine.txt: Machine driver internals.
 
 pop_clicks.txt: How to minimise audio artifacts.
 
-clocking.txt: ASoC clocking for best power performance.
\ No newline at end of file
+clocking.txt: ASoC clocking for best power performance.
index d4678b4dc6c6704869763c98b584bf015584fda2..b681d17fc3880b8872e7a770f77dd80d3f0b8137 100644 (file)
@@ -8,7 +8,7 @@ specific code.
 Audio DMA
 =========
 
-The platform DMA driver optionally supports the following alsa operations:-
+The platform DMA driver optionally supports the following ALSA operations:-
 
 /* SoC audio ops */
 struct snd_soc_ops {
@@ -38,7 +38,7 @@ struct snd_soc_platform {
        struct snd_pcm_ops *pcm_ops;
 };
 
-Please refer to the alsa driver documentation for details of audio DMA.
+Please refer to the ALSA driver documentation for details of audio DMA.
 http://www.alsa-project.org/~iwai/writing-an-alsa-driver/c436.htm
 
 An example DMA driver is soc/pxa/pxa2xx-pcm.c
@@ -52,7 +52,7 @@ Each SoC DAI driver must provide the following features:-
  1) Digital audio interface (DAI) description
  2) Digital audio interface configuration
  3) PCM's description
- 4) Sysclk configuration
+ 4) SYSCLK configuration
  5) Suspend and resume (optional)
 
 Please see codec.txt for a description of items 1 - 4.
index 3371bd9d7cfa52c46c7713b78b932326090f996c..e1e74daa4497219209446c9e152f6d4a40c7c837 100644 (file)
@@ -15,11 +15,11 @@ click every time a component power state is changed.
 Minimising Playback Pops and Clicks
 ===================================
 
-Playback pops in portable audio subsystems cannot be completely eliminated atm,
-however future audio codec hardware will have better pop and click suppression.
-Pops can be reduced within playback by powering the audio components in a
-specific order. This order is different for startup and shutdown and follows
-some basic rules:-
+Playback pops in portable audio subsystems cannot be completely eliminated
+currently, however future audio codec hardware will have better pop and click
+suppression.  Pops can be reduced within playback by powering the audio
+components in a specific order. This order is different for startup and
+shutdown and follows some basic rules:-
 
  Startup Order :- DAC --> Mixers --> Output PGA --> Digital Unmute
 
index 6f31f0a247d03137b85955bf59d06a666e34b1a0..24eac1bc735d733df28901555eefe36217d5dd2a 100644 (file)
@@ -22,6 +22,7 @@ Currently, these files are in /proc/sys/vm:
 - dirty_background_ratio
 - dirty_expire_centisecs
 - dirty_writeback_centisecs
+- highmem_is_dirtyable   (only if CONFIG_HIGHMEM set)
 - max_map_count
 - min_free_kbytes
 - laptop_mode
@@ -40,9 +41,9 @@ Currently, these files are in /proc/sys/vm:
 ==============================================================
 
 dirty_ratio, dirty_background_ratio, dirty_expire_centisecs,
-dirty_writeback_centisecs, vfs_cache_pressure, laptop_mode,
-block_dump, swap_token_timeout, drop-caches,
-hugepages_treat_as_movable:
+dirty_writeback_centisecs, highmem_is_dirtyable,
+vfs_cache_pressure, laptop_mode, block_dump, swap_token_timeout,
+drop-caches, hugepages_treat_as_movable:
 
 See Documentation/filesystems/proc.txt
 
diff --git a/Documentation/usb/gadget_printer.txt b/Documentation/usb/gadget_printer.txt
new file mode 100644 (file)
index 0000000..ad995bf
--- /dev/null
@@ -0,0 +1,510 @@
+
+                       Linux USB Printer Gadget Driver
+                                 06/04/2007
+
+              Copyright (C) 2007 Craig W. Nadler <craig@nadler.us>
+
+
+
+GENERAL
+=======
+
+This driver may be used if you are writing printer firmware using Linux as
+the embedded OS. This driver has nothing to do with using a printer with
+your Linux host system.
+
+You will need a USB device controller and a Linux driver for it that accepts
+a gadget / "device class" driver using the Linux USB Gadget API. After the
+USB device controller driver is loaded then load the printer gadget driver.
+This will present a printer interface to the USB Host that your USB Device
+port is connected to.
+
+This driver is structured for printer firmware that runs in user mode. The
+user mode printer firmware will read and write data from the kernel mode
+printer gadget driver using a device file. The printer returns a printer status
+byte when the USB HOST sends a device request to get the printer status.  The
+user space firmware can read or write this status byte using a device file
+/dev/g_printer . Both blocking and non-blocking read/write calls are supported.
+
+
+
+
+HOWTO USE THIS DRIVER
+=====================
+
+To load the USB device controller driver and the printer gadget driver. The
+following example uses the Netchip 2280 USB device controller driver:
+
+modprobe net2280
+modprobe g_printer
+
+
+The follow command line parameter can be used when loading the printer gadget
+(ex: modprobe g_printer idVendor=0x0525 idProduct=0xa4a8 ):
+
+idVendor - This is the Vendor ID used in the device descriptor. The default is
+       the Netchip vendor id 0x0525. YOU MUST CHANGE TO YOUR OWN VENDOR ID
+       BEFORE RELEASING A PRODUCT. If you plan to release a product and don't
+       already have a Vendor ID please see www.usb.org for details on how to
+       get one.
+
+idProduct - This is the Product ID used in the device descriptor. The default
+       is 0xa4a8, you should change this to an ID that's not used by any of
+       your other USB products if you have any. It would be a good idea to
+       start numbering your products starting with say 0x0001.
+
+bcdDevice - This is the version number of your product. It would be a good idea
+       to put your firmware version here.
+
+iManufacturer - A string containing the name of the Vendor.
+
+iProduct - A string containing the Product Name.
+
+iSerialNum - A string containing the Serial Number. This should be changed for
+       each unit of your product.
+
+iPNPstring -  The PNP ID string used for this printer. You will want to set
+       either on the command line or hard code the PNP ID string used for
+       your printer product.
+
+qlen - The number of 8k buffers to use per endpoint. The default is 10, you
+       should tune this for your product. You may also want to tune the
+       size of each buffer for your product.
+
+
+
+
+USING THE EXAMPLE CODE
+======================
+
+This example code talks to stdout, instead of a print engine.
+
+To compile the test code below:
+
+1) save it to a file called prn_example.c
+2) compile the code with the follow command:
+        gcc prn_example.c -o prn_example
+
+
+
+To read printer data from the host to stdout:
+
+       # prn_example -read_data
+
+
+To write printer data from a file (data_file) to the host:
+
+       # cat data_file | prn_example -write_data
+
+
+To get the current printer status for the gadget driver:
+
+       # prn_example -get_status
+
+       Printer status is:
+            Printer is NOT Selected
+            Paper is Out
+            Printer OK
+
+
+To set printer to Selected/On-line:
+
+       # prn_example -selected
+
+
+To set printer to Not Selected/Off-line:
+
+       # prn_example -not_selected
+
+
+To set paper status to paper out:
+
+       # prn_example -paper_out
+
+
+To set paper status to paper loaded:
+
+       # prn_example -paper_loaded
+
+
+To set error status to printer OK:
+
+       # prn_example -no_error
+
+
+To set error status to ERROR:
+
+       # prn_example -error
+
+
+
+
+EXAMPLE CODE
+============
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <linux/poll.h>
+#include <sys/ioctl.h>
+#include <linux/usb/g_printer.h>
+
+#define PRINTER_FILE                   "/dev/g_printer"
+#define BUF_SIZE                       512
+
+
+/*
+ * 'usage()' - Show program usage.
+ */
+
+static void
+usage(const char *option)              /* I - Option string or NULL */
+{
+       if (option) {
+               fprintf(stderr,"prn_example: Unknown option \"%s\"!\n",
+                               option);
+       }
+
+       fputs("\n", stderr);
+       fputs("Usage: prn_example -[options]\n", stderr);
+       fputs("Options:\n", stderr);
+       fputs("\n", stderr);
+       fputs("-get_status    Get the current printer status.\n", stderr);
+       fputs("-selected      Set the selected status to selected.\n", stderr);
+       fputs("-not_selected  Set the selected status to NOT selected.\n",
+                       stderr);
+       fputs("-error         Set the error status to error.\n", stderr);
+       fputs("-no_error      Set the error status to NO error.\n", stderr);
+       fputs("-paper_out     Set the paper status to paper out.\n", stderr);
+       fputs("-paper_loaded  Set the paper status to paper loaded.\n",
+                       stderr);
+       fputs("-read_data     Read printer data from driver.\n", stderr);
+       fputs("-write_data    Write printer sata to driver.\n", stderr);
+       fputs("-NB_read_data  (Non-Blocking) Read printer data from driver.\n",
+                       stderr);
+       fputs("\n\n", stderr);
+
+       exit(1);
+}
+
+
+static int
+read_printer_data()
+{
+       struct pollfd   fd[1];
+
+       /* Open device file for printer gadget. */
+       fd[0].fd = open(PRINTER_FILE, O_RDWR);
+       if (fd[0].fd < 0) {
+               printf("Error %d opening %s\n", fd[0].fd, PRINTER_FILE);
+               close(fd[0].fd);
+               return(-1);
+       }
+
+       fd[0].events = POLLIN | POLLRDNORM;
+
+       while (1) {
+               static char buf[BUF_SIZE];
+               int bytes_read;
+               int retval;
+
+               /* Wait for up to 1 second for data. */
+               retval = poll(fd, 1, 1000);
+
+               if (retval && (fd[0].revents & POLLRDNORM)) {
+
+                       /* Read data from printer gadget driver. */
+                       bytes_read = read(fd[0].fd, buf, BUF_SIZE);
+
+                       if (bytes_read < 0) {
+                               printf("Error %d reading from %s\n",
+                                               fd[0].fd, PRINTER_FILE);
+                               close(fd[0].fd);
+                               return(-1);
+                       } else if (bytes_read > 0) {
+                               /* Write data to standard OUTPUT (stdout). */
+                               fwrite(buf, 1, bytes_read, stdout);
+                               fflush(stdout);
+                       }
+
+               }
+
+       }
+
+       /* Close the device file. */
+       close(fd[0].fd);
+
+       return 0;
+}
+
+
+static int
+write_printer_data()
+{
+       struct pollfd   fd[1];
+
+       /* Open device file for printer gadget. */
+       fd[0].fd = open (PRINTER_FILE, O_RDWR);
+       if (fd[0].fd < 0) {
+               printf("Error %d opening %s\n", fd[0].fd, PRINTER_FILE);
+               close(fd[0].fd);
+               return(-1);
+       }
+
+       fd[0].events = POLLOUT | POLLWRNORM;
+
+       while (1) {
+               int retval;
+               static char buf[BUF_SIZE];
+               /* Read data from standard INPUT (stdin). */
+               int bytes_read = fread(buf, 1, BUF_SIZE, stdin);
+
+               if (!bytes_read) {
+                       break;
+               }
+
+               while (bytes_read) {
+
+                       /* Wait for up to 1 second to sent data. */
+                       retval = poll(fd, 1, 1000);
+
+                       /* Write data to printer gadget driver. */
+                       if (retval && (fd[0].revents & POLLWRNORM)) {
+                               retval = write(fd[0].fd, buf, bytes_read);
+                               if (retval < 0) {
+                                       printf("Error %d writing to %s\n",
+                                                       fd[0].fd,
+                                                       PRINTER_FILE);
+                                       close(fd[0].fd);
+                                       return(-1);
+                               } else {
+                                       bytes_read -= retval;
+                               }
+
+                       }
+
+               }
+
+       }
+
+       /* Wait until the data has been sent. */
+       fsync(fd[0].fd);
+
+       /* Close the device file. */
+       close(fd[0].fd);
+
+       return 0;
+}
+
+
+static int
+read_NB_printer_data()
+{
+       int             fd;
+       static char     buf[BUF_SIZE];
+       int             bytes_read;
+
+       /* Open device file for printer gadget. */
+       fd = open(PRINTER_FILE, O_RDWR|O_NONBLOCK);
+       if (fd < 0) {
+               printf("Error %d opening %s\n", fd, PRINTER_FILE);
+               close(fd);
+               return(-1);
+       }
+
+       while (1) {
+               /* Read data from printer gadget driver. */
+               bytes_read = read(fd, buf, BUF_SIZE);
+               if (bytes_read <= 0) {
+                       break;
+               }
+
+               /* Write data to standard OUTPUT (stdout). */
+               fwrite(buf, 1, bytes_read, stdout);
+               fflush(stdout);
+       }
+
+       /* Close the device file. */
+       close(fd);
+
+       return 0;
+}
+
+
+static int
+get_printer_status()
+{
+       int     retval;
+       int     fd;
+
+       /* Open device file for printer gadget. */
+       fd = open(PRINTER_FILE, O_RDWR);
+       if (fd < 0) {
+               printf("Error %d opening %s\n", fd, PRINTER_FILE);
+               close(fd);
+               return(-1);
+       }
+
+       /* Make the IOCTL call. */
+       retval = ioctl(fd, GADGET_GET_PRINTER_STATUS);
+       if (retval < 0) {
+               fprintf(stderr, "ERROR: Failed to set printer status\n");
+               return(-1);
+       }
+
+       /* Close the device file. */
+       close(fd);
+
+       return(retval);
+}
+
+
+static int
+set_printer_status(unsigned char buf, int clear_printer_status_bit)
+{
+       int     retval;
+       int     fd;
+
+       retval = get_printer_status();
+       if (retval < 0) {
+               fprintf(stderr, "ERROR: Failed to get printer status\n");
+               return(-1);
+       }
+
+       /* Open device file for printer gadget. */
+       fd = open(PRINTER_FILE, O_RDWR);
+
+       if (fd < 0) {
+               printf("Error %d opening %s\n", fd, PRINTER_FILE);
+               close(fd);
+               return(-1);
+       }
+
+       if (clear_printer_status_bit) {
+               retval &= ~buf;
+       } else {
+               retval |= buf;
+       }
+
+       /* Make the IOCTL call. */
+       if (ioctl(fd, GADGET_SET_PRINTER_STATUS, (unsigned char)retval)) {
+               fprintf(stderr, "ERROR: Failed to set printer status\n");
+               return(-1);
+       }
+
+       /* Close the device file. */
+       close(fd);
+
+       return 0;
+}
+
+
+static int
+display_printer_status()
+{
+       char    printer_status;
+
+       printer_status = get_printer_status();
+       if (printer_status < 0) {
+               fprintf(stderr, "ERROR: Failed to get printer status\n");
+               return(-1);
+       }
+
+       printf("Printer status is:\n");
+       if (printer_status & PRINTER_SELECTED) {
+               printf("     Printer is Selected\n");
+       } else {
+               printf("     Printer is NOT Selected\n");
+       }
+       if (printer_status & PRINTER_PAPER_EMPTY) {
+               printf("     Paper is Out\n");
+       } else {
+               printf("     Paper is Loaded\n");
+       }
+       if (printer_status & PRINTER_NOT_ERROR) {
+               printf("     Printer OK\n");
+       } else {
+               printf("     Printer ERROR\n");
+       }
+
+       return(0);
+}
+
+
+int
+main(int  argc, char *argv[])
+{
+       int     i;              /* Looping var */
+       int     retval = 0;
+
+       /* No Args */
+       if (argc == 1) {
+               usage(0);
+               exit(0);
+       }
+
+       for (i = 1; i < argc && !retval; i ++) {
+
+               if (argv[i][0] != '-') {
+                       continue;
+               }
+
+               if (!strcmp(argv[i], "-get_status")) {
+                       if (display_printer_status()) {
+                               retval = 1;
+                       }
+
+               } else if (!strcmp(argv[i], "-paper_loaded")) {
+                       if (set_printer_status(PRINTER_PAPER_EMPTY, 1)) {
+                               retval = 1;
+                       }
+
+               } else if (!strcmp(argv[i], "-paper_out")) {
+                       if (set_printer_status(PRINTER_PAPER_EMPTY, 0)) {
+                               retval = 1;
+                       }
+
+               } else if (!strcmp(argv[i], "-selected")) {
+                       if (set_printer_status(PRINTER_SELECTED, 0)) {
+                               retval = 1;
+                       }
+
+               } else if (!strcmp(argv[i], "-not_selected")) {
+                       if (set_printer_status(PRINTER_SELECTED, 1)) {
+                               retval = 1;
+                       }
+
+               } else if (!strcmp(argv[i], "-error")) {
+                       if (set_printer_status(PRINTER_NOT_ERROR, 1)) {
+                               retval = 1;
+                       }
+
+               } else if (!strcmp(argv[i], "-no_error")) {
+                       if (set_printer_status(PRINTER_NOT_ERROR, 0)) {
+                               retval = 1;
+                       }
+
+               } else if (!strcmp(argv[i], "-read_data")) {
+                       if (read_printer_data()) {
+                               retval = 1;
+                       }
+
+               } else if (!strcmp(argv[i], "-write_data")) {
+                       if (write_printer_data()) {
+                               retval = 1;
+                       }
+
+               } else if (!strcmp(argv[i], "-NB_read_data")) {
+                       if (read_NB_printer_data()) {
+                               retval = 1;
+                       }
+
+               } else {
+                       usage(argv[i]);
+                       retval = 1;
+               }
+       }
+
+       exit(retval);
+}
diff --git a/Documentation/usb/iuu_phoenix.txt b/Documentation/usb/iuu_phoenix.txt
new file mode 100644 (file)
index 0000000..e5f0480
--- /dev/null
@@ -0,0 +1,84 @@
+Infinity Usb Unlimited Readme
+-----------------------------
+
+Hi all,
+
+
+This module provide a serial interface to use your
+IUU unit in phoenix mode. Loading this module will
+bring a ttyUSB[0-x] interface. This driver must be
+used by your favorite application to pilot the IUU
+
+This driver is still in beta stage, so bugs can
+occur and your system may freeze. As far I now,
+I never had any problem with it, but I'm not a real
+guru, so don't blame me if your system is unstable
+
+You can plug more than one IUU. Every unit will
+have his own device file(/dev/ttyUSB0,/dev/ttyUSB1,...)
+
+
+
+How to tune the reader speed ?
+
+ A few parameters can be used at load time
+ To use parameters, just unload the module if it is
+ already loaded and use modprobe iuu_phoenix param=value.
+ In case of prebuilt module, use the command
+ insmod iuu_phoenix param=value.
+
+ Example:
+
+ modprobe iuu_phoenix clockmode=3
+
+ The parameters are:
+
+ parm:           clockmode:1=3Mhz579,2=3Mhz680,3=6Mhz (int)
+ parm:           boost:overclock boost percent 100 to 500 (int)
+ parm:           cdmode:Card detect mode 0=none, 1=CD, 2=!CD, 3=DSR, 4=!DSR, 5=CTS, 6=!CTS, 7=RING, 8=!RING (int)
+ parm:           xmas:xmas color enabled or not (bool)
+ parm:           debug:Debug enabled or not (bool)
+
+-  clockmode will provide 3 different base settings commonly adopted by
+   different software:
+       1. 3Mhz579
+       2. 3Mhz680
+       3. 6Mhz
+
+-  boost provide a way to overclock the reader ( my favorite :-)  )
+   For example to have best performance than a simple clockmode=3, try this:
+
+      modprobe boost=195
+
+   This will put the reader in a base of 3Mhz579 but boosted a 195 % !
+   the real clock will be now : 6979050 Hz ( 6Mhz979 ) and will increase
+   the speed to a score 10 to 20% better than the simple clockmode=3 !!!
+
+
+-  cdmode permit to setup the signal used to inform the userland ( ioctl answer )
+   if the card is present or not. Eight signals are possible.
+
+-  xmas is completely useless except for your eyes. This is one of my friend who was
+   so sad to have a nice device like the iuu without seeing all color range available.
+   So I have added this option to permit him to see a lot of color ( each activity change the color
+   and the frequency randomly )
+
+-  debug will produce a lot of debugging messages...
+
+
+ Last notes:
+
+ Don't worry about the serial settings, the serial emulation
+ is an abstraction, so use any speed or parity setting will
+ work. ( This will not change anything ).Later I will perhaps
+ use this settings to deduce de boost but is that feature
+ really necessary ?
+ The autodetect feature used is the serial CD. If that doesn't
+ work for your software, disable detection mechanism in it.
+
+
+ Have fun !
+
+ Alain Degreffe
+
+ eczema(at)ecze.com
diff --git a/Documentation/x86_64/00-INDEX b/Documentation/x86_64/00-INDEX
new file mode 100644 (file)
index 0000000..92fc20a
--- /dev/null
@@ -0,0 +1,16 @@
+00-INDEX
+       - This file
+boot-options.txt
+       - AMD64-specific boot options.
+cpu-hotplug-spec
+       - Firmware support for CPU hotplug under Linux/x86-64
+fake-numa-for-cpusets
+       - Using numa=fake and CPUSets for Resource Management
+kernel-stacks
+       - Context-specific per-processor interrupt stacks.
+machinecheck
+       - Configurable sysfs parameters for the x86-64 machine check code.
+mm.txt
+       - Memory layout of x86-64 (4 level page tables, 46 bits physical).
+uefi.txt
+       - Booting Linux via Unified Extensible Firmware Interface.
index ba05e8058689dc0471ddb9fe753290075404774d..4f3da8b56979c5365ab8403a90eaebd3ec3a378b 100644 (file)
@@ -84,13 +84,6 @@ S: Status, one of the following:
                        it has been replaced by a better system and you
                        should be using that.
 
-3C359 NETWORK DRIVER
-P:     Mike Phillips
-M:     mikep@linuxtr.net
-L:     netdev@vger.kernel.org
-W:     http://www.linuxtr.net
-S:     Maintained
-
 3C505 NETWORK DRIVER
 P:     Philip Blundell
 M:     philb@gnu.org
@@ -939,8 +932,6 @@ M:  maxk@qualcomm.com
 S:     Maintained
 
 BONDING DRIVER
-P:     Chad Tindel
-M:     ctindel@users.sourceforge.net
 P:     Jay Vosburgh
 M:     fubar@us.ibm.com
 L:     bonding-devel@lists.sourceforge.net
@@ -1595,7 +1586,7 @@ P:        Alexander Viro
 M:     viro@zeniv.linux.org.uk
 S:     Maintained
 
-FIREWIRE SUBSYSTEM
+FIREWIRE SUBSYSTEM (drivers/firewire, <linux/firewire*.h>)
 P:     Kristian Hoegsberg, Stefan Richter
 M:     krh@redhat.com, stefanr@s5r6.in-berlin.de
 L:     linux1394-devel@lists.sourceforge.net
@@ -1917,7 +1908,7 @@ L:        linux-ide@vger.kernel.org
 L:     linux-scsi@vger.kernel.org
 S:     Orphan
 
-IEEE 1394 SUBSYSTEM
+IEEE 1394 SUBSYSTEM (drivers/ieee1394)
 P:     Ben Collins
 M:     ben.collins@ubuntu.com
 P:     Stefan Richter
@@ -2247,7 +2238,7 @@ P:        J. Bruce Fields
 M:     bfields@fieldses.org
 P:     Neil Brown
 M:     neilb@suse.de
-L:     nfs@lists.sourceforge.net
+L:     linux-nfs@vger.kernel.org
 W:     http://nfs.sourceforge.net/
 S:     Supported
 
@@ -2258,6 +2249,15 @@ L:       kvm-devel@lists.sourceforge.net
 W:     kvm.sourceforge.net
 S:     Supported
 
+KERNEL VIRTUAL MACHINE For Itanium(KVM/IA64)
+P:     Anthony Xu
+M:     anthony.xu@intel.com
+P:     Xiantao Zhang
+M:     xiantao.zhang@intel.com
+L:     kvm-ia64-devel@lists.sourceforge.net
+W:     kvm.sourceforge.net
+S:     Supported
+
 KEXEC
 P:     Eric Biederman
 M:     ebiederm@xmission.com
@@ -2690,6 +2690,16 @@ M:       James.Bottomley@HansenPartnership.com
 L:     linux-scsi@vger.kernel.org
 S:     Maintained
 
+NETEFFECT IWARP RNIC DRIVER (IW_NES)
+P:     Faisal Latif
+M:     flatif@neteffect.com
+P:     Glenn Streiff
+M:     gstreiff@neteffect.com
+L:     general@lists.openfabrics.org
+W:     http://www.neteffect.com
+S:     Supported
+F:     drivers/infiniband/hw/nes/
+
 NETEM NETWORK EMULATOR
 P:     Stephen Hemminger
 M:     shemminger@linux-foundation.org
@@ -2864,15 +2874,6 @@ L:       ocfs2-devel@oss.oracle.com
 W:     http://oss.oracle.com/projects/ocfs2/
 S:     Supported
 
-OLYMPIC NETWORK DRIVER
-P:     Peter De Shrijver
-M:     p2@ace.ulyssis.student.kuleuven.ac.be
-P:     Mike Phillips
-M:     mikep@linuxtr.net
-L:     netdev@vger.kernel.org
-W:     http://www.linuxtr.net
-S:     Maintained
-
 OMNIKEY CARDMAN 4000 DRIVER
 P:     Harald Welte
 M:     laforge@gnumonks.org
@@ -3053,7 +3054,6 @@ M:        cbou@mail.ru
 P:     David Woodhouse
 M:     dwmw2@infradead.org
 L:     linux-kernel@vger.kernel.org
-L:     kernel-discuss@handhelds.org
 T:     git git.infradead.org/battery-2.6.git
 S:     Maintained
 
@@ -3196,7 +3196,7 @@ S:        Maintained
 
 RAYLINK/WEBGEAR 802.11 WIRELESS LAN DRIVER
 P:     Corey Thomas
-M:     corey@world.std.com
+M:     coreythomas@charter.net
 L:     linux-wireless@vger.kernel.org
 S:     Maintained
 
@@ -3571,6 +3571,9 @@ S:        Maintained
 SOUND - SOC LAYER / DYNAMIC AUDIO POWER MANAGEMENT
 P:     Liam Girdwood
 M:     liam.girdwood@wolfsonmicro.com
+P:     Mark Brown
+M:     broonie@opensource.wolfsonmicro.com
+T:     git opensource.wolfsonmicro.com/linux-2.6-asoc
 L:     alsa-devel@alsa-project.org (subscribers-only)
 S:     Supported
 
@@ -3786,13 +3789,6 @@ L:       tlan-devel@lists.sourceforge.net (subscribers-only)
 W:     http://sourceforge.net/projects/tlan/
 S:     Maintained
 
-TOKEN-RING NETWORK DRIVER
-P:     Mike Phillips
-M:     mikep@linuxtr.net
-L:     netdev@vger.kernel.org
-W:     http://www.linuxtr.net
-S:     Maintained
-
 TOSHIBA ACPI EXTRAS DRIVER
 P:     John Belmonte
 M:     toshiba_acpi@memebeam.org
@@ -3813,18 +3809,9 @@ L:       linux-kernel@vger.kernel.org
 S:     Maintained
 
 TRIVIAL PATCHES
-P:     Adrian Bunk
+P:     Jesper Juhl
 M:     trivial@kernel.org
 L:     linux-kernel@vger.kernel.org
-W:     http://www.kernel.org/pub/linux/kernel/people/bunk/trivial/
-T:     git kernel.org:/pub/scm/linux/kernel/git/bunk/trivial.git
-S:     Maintained
-
-TMS380 TOKEN-RING NETWORK DRIVER
-P:     Adam Fritzler
-M:     mid@auk.cx
-L:     linux-tr@linuxtr.net
-W:     http://www.auk.cx/tms380tr/
 S:     Maintained
 
 TULIP NETWORK DRIVER
@@ -4082,6 +4069,12 @@ L:       video4linux-list@redhat.com
 W:     http://www.linux-projects.org
 S:     Maintained
 
+USB WIRELESS RNDIS DRIVER (rndis_wlan)
+P:     Jussi Kivilinna
+M:     jussi.kivilinna@mbnet.fi
+L:     linux-wireless@vger.kernel.org
+S:     Maintained
+
 USB ZC0301 DRIVER
 P:     Luca Risolia
 M:     luca.risolia@studio.unibo.it
index 0f84c742ed0e1c8363d27121fb2ce563fb582bc7..89f2d8b5136d72efcc0bd761cd3ba37ab956718f 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1484,7 +1484,7 @@ kernelversion:
 # Single targets
 # ---------------------------------------------------------------------------
 # Single targets are compatible with:
-# - build whith mixed source and output
+# - build with mixed source and output
 # - build with separate output dir 'make O=...'
 # - external modules
 #
diff --git a/arch/Kconfig b/arch/Kconfig
new file mode 100644 (file)
index 0000000..3d72dc3
--- /dev/null
@@ -0,0 +1,31 @@
+#
+# General architecture dependent options
+#
+
+config OPROFILE
+       tristate "OProfile system profiling (EXPERIMENTAL)"
+       depends on PROFILING
+       depends on HAVE_OPROFILE
+       help
+         OProfile is a profiling system capable of profiling the
+         whole system, include the kernel, kernel modules, libraries,
+         and applications.
+
+         If unsure, say N.
+
+config HAVE_OPROFILE
+       def_bool n
+
+config KPROBES
+       bool "Kprobes"
+       depends on KALLSYMS && MODULES
+       depends on HAVE_KPROBES
+       help
+         Kprobes allows you to trap at almost any kernel address and
+         execute a callback function.  register_kprobe() establishes
+         a probepoint and specifies the callback.  Kprobes is useful
+         for kernel debugging, non-intrusive instrumentation and testing.
+         If in doubt, say "N".
+
+config HAVE_KPROBES
+       def_bool n
index 4c002ba37e5076fe726826e3a2a73deb29d25176..01b10ab588a630b36c0290448ffa53d29bf03dfc 100644 (file)
@@ -5,6 +5,7 @@
 config ALPHA
        bool
        default y
+       select HAVE_OPROFILE
        help
          The Alpha is a 64-bit general-purpose processor designed and
          marketed by the Digital Equipment Corporation of blessed memory,
@@ -318,11 +319,6 @@ config PCI
          your box. Other bus systems are ISA, EISA, MicroChannel (MCA) or
          VESA. If you have PCI, say Y, otherwise N.
 
-         The PCI-HOWTO, available from
-         <http://www.tldp.org/docs.html#howto>, contains valuable
-         information about which PCI hardware does work under Linux and which
-         doesn't.
-
 config PCI_DOMAINS
        bool
        default y
@@ -536,8 +532,8 @@ config SMP
          singleprocessor machines. On a singleprocessor machine, the kernel
          will run faster if you say N here.
 
-         See also the <file:Documentation/smp.txt>, and the SMP-HOWTO
-         available at <http://www.tldp.org/docs.html#howto>.
+         See also the SMP-HOWTO available at
+         <http://www.tldp.org/docs.html#howto>.
 
          If you don't know what to do here, say N.
 
@@ -654,8 +650,6 @@ source "drivers/Kconfig"
 
 source "fs/Kconfig"
 
-source "kernel/Kconfig.instrumentation"
-
 source "arch/alpha/Kconfig.debug"
 
 # DUMMY_CONSOLE may be defined in drivers/video/console/Kconfig
index 468b76ce66a1304e4eeddc48663effbe8545f83e..8ac08311f5a51bd765145b461b76864f550d38f1 100644 (file)
@@ -165,7 +165,7 @@ dma_alloc_coherent(struct device *dev, size_t size,
        ret = (void *)__get_free_pages(gfp, get_order(size));
        if (ret) {
                memset(ret, 0, size);
-               *dma_handle = virt_to_bus(ret);
+               *dma_handle = virt_to_phys(ret);
        }
        return ret;
 }
@@ -184,7 +184,7 @@ dma_map_sg(struct device *dev, struct scatterlist *sgl, int nents,
 
                BUG_ON(!sg_page(sg));
                va = sg_virt(sg);
-               sg_dma_address(sg) = (dma_addr_t)virt_to_bus(va);
+               sg_dma_address(sg) = (dma_addr_t)virt_to_phys(va);
                sg_dma_len(sg) = sg->length;
        }
 
index 2d00a08d3f0811d0f7b819475d6f858828d88496..26d3789dfdd0420bc4e7ce496995138b1decda14 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/bootmem.h>
 #include <linux/scatterlist.h>
 #include <linux/log2.h>
+#include <linux/dma-mapping.h>
 
 #include <asm/io.h>
 #include <asm/hwrpb.h>
@@ -470,22 +471,29 @@ EXPORT_SYMBOL(pci_free_consistent);
 #define SG_ENT_PHYS_ADDRESS(SG) __pa(SG_ENT_VIRT_ADDRESS(SG))
 
 static void
-sg_classify(struct scatterlist *sg, struct scatterlist *end, int virt_ok)
+sg_classify(struct device *dev, struct scatterlist *sg, struct scatterlist *end,
+           int virt_ok)
 {
        unsigned long next_paddr;
        struct scatterlist *leader;
        long leader_flag, leader_length;
+       unsigned int max_seg_size;
 
        leader = sg;
        leader_flag = 0;
        leader_length = leader->length;
        next_paddr = SG_ENT_PHYS_ADDRESS(leader) + leader_length;
 
+       /* we will not marge sg without device. */
+       max_seg_size = dev ? dma_get_max_seg_size(dev) : 0;
        for (++sg; sg < end; ++sg) {
                unsigned long addr, len;
                addr = SG_ENT_PHYS_ADDRESS(sg);
                len = sg->length;
 
+               if (leader_length + len > max_seg_size)
+                       goto new_segment;
+
                if (next_paddr == addr) {
                        sg->dma_address = -1;
                        leader_length += len;
@@ -494,6 +502,7 @@ sg_classify(struct scatterlist *sg, struct scatterlist *end, int virt_ok)
                        leader_flag = 1;
                        leader_length += len;
                } else {
+new_segment:
                        leader->dma_address = leader_flag;
                        leader->dma_length = leader_length;
                        leader = sg;
@@ -512,7 +521,7 @@ sg_classify(struct scatterlist *sg, struct scatterlist *end, int virt_ok)
    in the blanks.  */
 
 static int
-sg_fill(struct scatterlist *leader, struct scatterlist *end,
+sg_fill(struct device *dev, struct scatterlist *leader, struct scatterlist *end,
        struct scatterlist *out, struct pci_iommu_arena *arena,
        dma_addr_t max_dma, int dac_allowed)
 {
@@ -562,8 +571,8 @@ sg_fill(struct scatterlist *leader, struct scatterlist *end,
 
                /* Otherwise, break up the remaining virtually contiguous
                   hunks into individual direct maps and retry.  */
-               sg_classify(leader, end, 0);
-               return sg_fill(leader, end, out, arena, max_dma, dac_allowed);
+               sg_classify(dev, leader, end, 0);
+               return sg_fill(dev, leader, end, out, arena, max_dma, dac_allowed);
        }
 
        out->dma_address = arena->dma_base + dma_ofs*PAGE_SIZE + paddr;
@@ -619,12 +628,15 @@ pci_map_sg(struct pci_dev *pdev, struct scatterlist *sg, int nents,
        struct pci_iommu_arena *arena;
        dma_addr_t max_dma;
        int dac_allowed;
+       struct device *dev;
 
        if (direction == PCI_DMA_NONE)
                BUG();
 
        dac_allowed = pdev ? pci_dac_dma_supported(pdev, pdev->dma_mask) : 0;
 
+       dev = pdev ? &pdev->dev : NULL;
+
        /* Fast path single entry scatterlists.  */
        if (nents == 1) {
                sg->dma_length = sg->length;
@@ -638,7 +650,7 @@ pci_map_sg(struct pci_dev *pdev, struct scatterlist *sg, int nents,
        end = sg + nents;
 
        /* First, prepare information about the entries.  */
-       sg_classify(sg, end, alpha_mv.mv_pci_tbi != 0);
+       sg_classify(dev, sg, end, alpha_mv.mv_pci_tbi != 0);
 
        /* Second, figure out where we're going to map things.  */
        if (alpha_mv.mv_pci_tbi) {
@@ -658,7 +670,7 @@ pci_map_sg(struct pci_dev *pdev, struct scatterlist *sg, int nents,
        for (out = sg; sg < end; ++sg) {
                if ((int) sg->dma_address < 0)
                        continue;
-               if (sg_fill(sg, end, out, arena, max_dma, dac_allowed) < 0)
+               if (sg_fill(dev, sg, end, out, arena, max_dma, dac_allowed) < 0)
                        goto error;
                out++;
        }
index bd5e68cd61e84fb440bd0a618b6c90019d48fb75..beff6297f788a029aa7423bc2a615915a764126d 100644 (file)
@@ -58,7 +58,6 @@ static struct notifier_block alpha_panic_block = {
 #include <asm/system.h>
 #include <asm/hwrpb.h>
 #include <asm/dma.h>
-#include <asm/io.h>
 #include <asm/mmu_context.h>
 #include <asm/console.h>
 
index 79de99e32c35f91ad2fcebc0ab8513bc5fd612d7..ba914af18c4f30cc60d915277a04c9865d68308c 100644 (file)
@@ -495,7 +495,7 @@ sys_call_table:
        .quad sys_epoll_pwait
        .quad sys_utimensat                     /* 475 */
        .quad sys_signalfd
-       .quad sys_timerfd
+       .quad sys_ni_syscall
        .quad sys_eventfd
 
        .size sys_call_table, . - sys_call_table
index 77201d3f7479ccc65bf2e454fa310be75580a49b..e19e7744e366a3a8d14bbb7aa7fb5ab4d0d13986 100644 (file)
@@ -10,6 +10,8 @@ config ARM
        default y
        select RTC_LIB
        select SYS_SUPPORTS_APM_EMULATION
+       select HAVE_OPROFILE
+       select HAVE_KPROBES if (!XIP_KERNEL)
        help
          The ARM series is a line of low-power-consumption RISC chip designs
          licensed by ARM Ltd and targeted at embedded applications and
@@ -33,6 +35,11 @@ config GENERIC_CLOCKEVENTS
        bool
        default n
 
+config GENERIC_CLOCKEVENTS_BROADCAST
+       bool
+       depends on GENERIC_CLOCKEVENTS
+       default y if SMP && !LOCAL_TIMERS
+
 config MMU
        bool
        default y
@@ -135,6 +142,23 @@ config FIQ
 config ARCH_MTD_XIP
        bool
 
+if OPROFILE
+
+config OPROFILE_ARMV6
+       def_bool y
+       depends on CPU_V6 && !SMP
+       select OPROFILE_ARM11_CORE
+
+config OPROFILE_MPCORE
+       def_bool y
+       depends on CPU_V6 && SMP
+       select OPROFILE_ARM11_CORE
+
+config OPROFILE_ARM11_CORE
+       bool
+
+endif
+
 config VECTORS_BASE
        hex
        default 0xffff0000 if MMU || CPU_HIGH_VECTOR
@@ -168,6 +192,8 @@ config ARCH_REALVIEW
        bool "ARM Ltd. RealView family"
        select ARM_AMBA
        select ICST307
+       select GENERIC_TIME
+       select GENERIC_CLOCKEVENTS
        help
          This enables support for ARM Ltd RealView boards.
 
@@ -359,6 +385,7 @@ config ARCH_PXA
        depends on MMU
        select ARCH_MTD_XIP
        select GENERIC_GPIO
+       select HAVE_GPIO_LIB
        select GENERIC_TIME
        select GENERIC_CLOCKEVENTS
        select TICK_ONESHOT
@@ -577,11 +604,6 @@ config PCI
          your box. Other bus systems are ISA, EISA, MicroChannel (MCA) or
          VESA. If you have PCI, say Y, otherwise N.
 
-         The PCI-HOWTO, available from
-         <http://www.tldp.org/docs.html#howto>, contains valuable
-         information about which PCI hardware does work under Linux and which
-         doesn't.
-
 config PCI_SYSCALL
        def_bool PCI
 
@@ -609,7 +631,7 @@ source "kernel/time/Kconfig"
 
 config SMP
        bool "Symmetric Multi-Processing (EXPERIMENTAL)"
-       depends on EXPERIMENTAL && REALVIEW_MPCORE
+       depends on EXPERIMENTAL && REALVIEW_EB_ARM11MP
        help
          This enables support for systems with more than one CPU. If you have
          a system with only one CPU, like most personal computers, say N. If
@@ -621,8 +643,7 @@ config SMP
          processor machines. On a single processor machine, the kernel will
          run faster if you say N here.
 
-         See also the <file:Documentation/smp.txt>,
-         <file:Documentation/i386/IO-APIC.txt>,
+         See also <file:Documentation/i386/IO-APIC.txt>,
          <file:Documentation/nmi_watchdog.txt> and the SMP-HOWTO available at
          <http://www.linuxdoc.org/docs.html#howto>.
 
@@ -643,7 +664,7 @@ config HOTPLUG_CPU
 
 config LOCAL_TIMERS
        bool "Use local timer interrupts"
-       depends on SMP && REALVIEW_MPCORE
+       depends on SMP && REALVIEW_EB_ARM11MP
        default y
        help
          Enable support for local timers on SMP platforms, rather then the
@@ -899,6 +920,13 @@ config KEXEC
          initially work for you.  It may help to enable device hotplugging
          support.
 
+config ATAGS_PROC
+       bool "Export atags in procfs"
+       default n
+       help
+         Should the atags used to boot the kernel be exported in an "atags"
+         file in procfs. Useful with kexec.
+
 endmenu
 
 if (ARCH_SA1100 || ARCH_INTEGRATOR || ARCH_OMAP || ARCH_IMX || ARCH_PXA)
@@ -1035,6 +1063,9 @@ menu "Power management options"
 
 source "kernel/power/Kconfig"
 
+config ARCH_SUSPEND_POSSIBLE
+       def_bool y
+
 endmenu
 
 source "net/Kconfig"
@@ -1092,6 +1123,8 @@ source "drivers/i2c/Kconfig"
 
 source "drivers/spi/Kconfig"
 
+source "drivers/gpio/Kconfig"
+
 source "drivers/w1/Kconfig"
 
 source "drivers/power/Kconfig"
@@ -1130,8 +1163,6 @@ endmenu
 
 source "fs/Kconfig"
 
-source "arch/arm/Kconfig.instrumentation"
-
 source "arch/arm/Kconfig.debug"
 
 source "security/Kconfig"
diff --git a/arch/arm/Kconfig.instrumentation b/arch/arm/Kconfig.instrumentation
deleted file mode 100644 (file)
index 453ad8e..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-menuconfig INSTRUMENTATION
-       bool "Instrumentation Support"
-       default y
-       ---help---
-         Say Y here to get to see options related to performance measurement,
-         system-wide debugging, and testing. This option alone does not add any
-         kernel code.
-
-         If you say N, all options in this submenu will be skipped and
-         disabled. If you're trying to debug the kernel itself, go see the
-         Kernel Hacking menu.
-
-if INSTRUMENTATION
-
-config PROFILING
-       bool "Profiling support (EXPERIMENTAL)"
-       help
-         Say Y here to enable the extended profiling support mechanisms used
-         by profilers such as OProfile.
-
-config OPROFILE
-       tristate "OProfile system profiling (EXPERIMENTAL)"
-       depends on PROFILING && !UML
-       help
-         OProfile is a profiling system capable of profiling the
-         whole system, include the kernel, kernel modules, libraries,
-         and applications.
-
-         If unsure, say N.
-
-config OPROFILE_ARMV6
-       bool
-       depends on OPROFILE && CPU_V6 && !SMP
-       default y
-       select OPROFILE_ARM11_CORE
-
-config OPROFILE_MPCORE
-       bool
-       depends on OPROFILE && CPU_V6 && SMP
-       default y
-       select OPROFILE_ARM11_CORE
-
-config OPROFILE_ARM11_CORE
-       bool
-
-config KPROBES
-       bool "Kprobes"
-       depends on KALLSYMS && MODULES && !UML && !XIP_KERNEL
-       help
-         Kprobes allows you to trap at almost any kernel address and
-         execute a callback function.  register_kprobe() establishes
-         a probepoint and specifies the callback.  Kprobes is useful
-         for kernel debugging, non-intrusive instrumentation and testing.
-         If in doubt, say "N".
-
-config MARKERS
-       bool "Activate markers"
-       help
-         Place an empty function call at each marker site. Can be
-         dynamically changed for a probe function.
-
-endif # INSTRUMENTATION
index 34038eccbba9e478b3bfb75ec283e289fee63cb2..d544da4147310954c6013e37863e786ece6ff312 100644 (file)
@@ -69,9 +69,7 @@ void __init ioctime_init(void)
 static irqreturn_t
 ioc_timer_interrupt(int irq, void *dev_id)
 {
-       write_seqlock(&xtime_lock);
        timer_tick();
-       write_sequnlock(&xtime_lock);
        return IRQ_HANDLED;
 }
 
index db850a5689eb52c9438853877175aa26f38365e8..efa0485d2f7ec10eb01ed26b47b3180e3a66e47e 100644 (file)
@@ -1,69 +1,96 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15
-# Tue Jan  3 03:20:40 2006
+# Linux kernel version: 2.6.24
+# Sun Jan 27 07:33:38 2008
 #
 CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
 CONFIG_MMU=y
-CONFIG_UID16=y
+# CONFIG_NO_IOPORT is not set
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_GENERIC_HWEIGHT=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_ZONE_DMA=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
 
 #
-# Code maturity level options
+# General setup
 #
 CONFIG_EXPERIMENTAL=y
-CONFIG_CLEAN_COMPILE=y
 CONFIG_BROKEN_ON_SMP=y
 CONFIG_INIT_ENV_ARG_LIMIT=32
-
-#
-# General setup
-#
 CONFIG_LOCALVERSION=""
 CONFIG_LOCALVERSION_AUTO=y
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
 # CONFIG_POSIX_MQUEUE is not set
 CONFIG_BSD_PROCESS_ACCT=y
 # CONFIG_BSD_PROCESS_ACCT_V3 is not set
-CONFIG_SYSCTL=y
+# CONFIG_TASKSTATS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
 # CONFIG_AUDIT is not set
-# CONFIG_HOTPLUG is not set
-CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_CGROUPS is not set
+CONFIG_FAIR_GROUP_SCHED=y
+CONFIG_FAIR_USER_SCHED=y
+# CONFIG_FAIR_CGROUP_SCHED is not set
+CONFIG_SYSFS_DEPRECATED=y
+# CONFIG_RELAY is not set
+CONFIG_BLK_DEV_INITRD=y
 CONFIG_INITRAMFS_SOURCE=""
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
 CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_ALL is not set
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
 CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_EVENTFD=y
 CONFIG_SHMEM=y
-CONFIG_CC_ALIGN_FUNCTIONS=0
-CONFIG_CC_ALIGN_LABELS=0
-CONFIG_CC_ALIGN_LOOPS=0
-CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLUB_DEBUG=y
+# CONFIG_SLAB is not set
+CONFIG_SLUB=y
+# CONFIG_SLOB is not set
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
-
-#
-# Loadable module support
-#
 CONFIG_MODULES=y
 # CONFIG_MODULE_UNLOAD is not set
-CONFIG_OBSOLETE_MODPARM=y
 CONFIG_MODVERSIONS=y
 # CONFIG_MODULE_SRCVERSION_ALL is not set
 CONFIG_KMOD=y
-
-#
-# Block layer
-#
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
 
 #
 # IO Schedulers
@@ -81,28 +108,39 @@ CONFIG_DEFAULT_IOSCHED="anticipatory"
 #
 # System Type
 #
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91 is not set
 # CONFIG_ARCH_CLPS7500 is not set
 # CONFIG_ARCH_CLPS711X is not set
 # CONFIG_ARCH_CO285 is not set
 # CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
 # CONFIG_ARCH_FOOTBRIDGE is not set
-# CONFIG_ARCH_INTEGRATOR is not set
-# CONFIG_ARCH_IOP3XX is not set
-CONFIG_ARCH_IXP4XX=y
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP23XX is not set
 # CONFIG_ARCH_IXP2000 is not set
+CONFIG_ARCH_IXP4XX=y
 # CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_PNX4008 is not set
 # CONFIG_ARCH_PXA is not set
 # CONFIG_ARCH_RPC is not set
 # CONFIG_ARCH_SA1100 is not set
 # CONFIG_ARCH_S3C2410 is not set
 # CONFIG_ARCH_SHARK is not set
 # CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_DAVINCI is not set
 # CONFIG_ARCH_OMAP is not set
-# CONFIG_ARCH_VERSATILE is not set
-# CONFIG_ARCH_REALVIEW is not set
-# CONFIG_ARCH_IMX is not set
-# CONFIG_ARCH_H720X is not set
-# CONFIG_ARCH_AAEC2000 is not set
 CONFIG_ARCH_SUPPORTS_BIG_ENDIAN=y
 
 #
@@ -112,8 +150,12 @@ CONFIG_ARCH_SUPPORTS_BIG_ENDIAN=y
 #
 # IXP4xx Platforms
 #
-CONFIG_ARCH_AVILA=y
+CONFIG_MACH_NSLU2=y
+CONFIG_MACH_AVILA=y
+CONFIG_MACH_LOFT=y
 CONFIG_ARCH_ADI_COYOTE=y
+CONFIG_MACH_GATEWAY7001=y
+CONFIG_MACH_WG302V2=y
 CONFIG_ARCH_IXDP425=y
 CONFIG_MACH_IXDPG425=y
 CONFIG_MACH_IXDP465=y
@@ -121,15 +163,27 @@ CONFIG_MACH_KIXRP435=y
 CONFIG_ARCH_IXCDP1100=y
 CONFIG_ARCH_PRPMC1100=y
 CONFIG_MACH_NAS100D=y
+CONFIG_MACH_DSMG600=y
 CONFIG_ARCH_IXDP4XX=y
 CONFIG_CPU_IXP46X=y
 CONFIG_CPU_IXP43X=y
-# CONFIG_MACH_GTWX5715 is not set
+CONFIG_MACH_GTWX5715=y
 
 #
 # IXP4xx Options
 #
+CONFIG_DMABOUNCE=y
 # CONFIG_IXP4XX_INDIRECT_PCI is not set
+CONFIG_IXP4XX_QMGR=y
+CONFIG_IXP4XX_NPE=y
+
+#
+# Boot options
+#
+
+#
+# Power management
+#
 
 #
 # Processor Type
@@ -140,33 +194,40 @@ CONFIG_CPU_32v5=y
 CONFIG_CPU_ABRT_EV5T=y
 CONFIG_CPU_CACHE_VIVT=y
 CONFIG_CPU_TLB_V4WBI=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
 
 #
 # Processor Features
 #
 # CONFIG_ARM_THUMB is not set
 CONFIG_CPU_BIG_ENDIAN=y
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_OUTER_CACHE is not set
+# CONFIG_IWMMXT is not set
 CONFIG_XSCALE_PMU=y
-CONFIG_DMABOUNCE=y
 
 #
 # Bus support
 #
-CONFIG_ISA_DMA_API=y
 CONFIG_PCI=y
-CONFIG_PCI_LEGACY_PROC=y
+CONFIG_PCI_SYSCALL=y
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+CONFIG_PCI_LEGACY=y
 # CONFIG_PCI_DEBUG is not set
-
-#
-# PCCARD (PCMCIA/CardBus) support
-#
 # CONFIG_PCCARD is not set
 
 #
 # Kernel Features
 #
+# CONFIG_TICK_ONESHOT is not set
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
 # CONFIG_PREEMPT is not set
-# CONFIG_NO_IDLE_HZ is not set
+CONFIG_HZ=100
+CONFIG_AEABI=y
+CONFIG_OABI_COMPAT=y
 # CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
 CONFIG_SELECT_MEMORY_MODEL=y
 CONFIG_FLATMEM_MANUAL=y
@@ -175,7 +236,12 @@ CONFIG_FLATMEM_MANUAL=y
 CONFIG_FLATMEM=y
 CONFIG_FLAT_NODE_MEM_MAP=y
 # CONFIG_SPARSEMEM_STATIC is not set
+# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
 CONFIG_SPLIT_PTLOCK_CPUS=4096
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
 CONFIG_ALIGNMENT_TRAP=y
 
 #
@@ -185,6 +251,7 @@ CONFIG_ZBOOT_ROM_TEXT=0x0
 CONFIG_ZBOOT_ROM_BSS=0x0
 CONFIG_CMDLINE="console=ttyS0,115200 ip=bootp root=/dev/nfs"
 # CONFIG_XIP_KERNEL is not set
+# CONFIG_KEXEC is not set
 
 #
 # Floating point emulation
@@ -203,13 +270,12 @@ CONFIG_FPE_NWFPE=y
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_AOUT is not set
 # CONFIG_BINFMT_MISC is not set
-# CONFIG_ARTHUR is not set
 
 #
 # Power management options
 #
 # CONFIG_PM is not set
-# CONFIG_APM is not set
+CONFIG_SUSPEND_UP_POSSIBLE=y
 
 #
 # Networking
@@ -219,11 +285,13 @@ CONFIG_NET=y
 #
 # Networking options
 #
-CONFIG_PACKET=m
+CONFIG_PACKET=y
 CONFIG_PACKET_MMAP=y
 CONFIG_UNIX=y
 CONFIG_XFRM=y
 # CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
 # CONFIG_NET_KEY is not set
 CONFIG_INET=y
 CONFIG_IP_MULTICAST=y
@@ -232,9 +300,7 @@ CONFIG_ASK_IP_FIB_HASH=y
 # CONFIG_IP_FIB_TRIE is not set
 CONFIG_IP_FIB_HASH=y
 CONFIG_IP_MULTIPLE_TABLES=y
-CONFIG_IP_ROUTE_FWMARK=y
 CONFIG_IP_ROUTE_MULTIPATH=y
-# CONFIG_IP_ROUTE_MULTIPATH_CACHED is not set
 CONFIG_IP_ROUTE_VERBOSE=y
 CONFIG_IP_PNP=y
 CONFIG_IP_PNP_DHCP=y
@@ -251,15 +317,18 @@ CONFIG_SYN_COOKIES=y
 # CONFIG_INET_AH is not set
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
-CONFIG_INET_TUNNEL=m
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+# CONFIG_INET_LRO is not set
 CONFIG_INET_DIAG=y
 CONFIG_INET_TCP_DIAG=y
 # CONFIG_TCP_CONG_ADVANCED is not set
-CONFIG_TCP_CONG_BIC=y
-
-#
-# IP: Virtual Server Configuration
-#
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
 CONFIG_IP_VS=m
 CONFIG_IP_VS_DEBUG=y
 CONFIG_IP_VS_TAB_BITS=12
@@ -290,6 +359,9 @@ CONFIG_IP_VS_SH=m
 # IPVS application helper
 #
 # CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
 CONFIG_NETFILTER=y
 # CONFIG_NETFILTER_DEBUG is not set
 CONFIG_BRIDGE_NETFILTER=y
@@ -298,70 +370,57 @@ CONFIG_BRIDGE_NETFILTER=y
 # Core Netfilter Configuration
 #
 # CONFIG_NETFILTER_NETLINK is not set
+# CONFIG_NF_CONNTRACK_ENABLED is not set
+# CONFIG_NF_CONNTRACK is not set
+CONFIG_NETFILTER_XTABLES=m
+# CONFIG_NETFILTER_XT_TARGET_CLASSIFY is not set
+# CONFIG_NETFILTER_XT_TARGET_DSCP is not set
+# CONFIG_NETFILTER_XT_TARGET_MARK is not set
+# CONFIG_NETFILTER_XT_TARGET_NFQUEUE is not set
+# CONFIG_NETFILTER_XT_TARGET_NFLOG is not set
+# CONFIG_NETFILTER_XT_TARGET_TCPMSS is not set
+# CONFIG_NETFILTER_XT_MATCH_COMMENT is not set
+# CONFIG_NETFILTER_XT_MATCH_DCCP is not set
+# CONFIG_NETFILTER_XT_MATCH_DSCP is not set
+# CONFIG_NETFILTER_XT_MATCH_ESP is not set
+# CONFIG_NETFILTER_XT_MATCH_LENGTH is not set
+# CONFIG_NETFILTER_XT_MATCH_LIMIT is not set
+# CONFIG_NETFILTER_XT_MATCH_MAC is not set
+# CONFIG_NETFILTER_XT_MATCH_MARK is not set
+# CONFIG_NETFILTER_XT_MATCH_POLICY is not set
+# CONFIG_NETFILTER_XT_MATCH_MULTIPORT is not set
+# CONFIG_NETFILTER_XT_MATCH_PHYSDEV is not set
+# CONFIG_NETFILTER_XT_MATCH_PKTTYPE is not set
+# CONFIG_NETFILTER_XT_MATCH_QUOTA is not set
+# CONFIG_NETFILTER_XT_MATCH_REALM is not set
+# CONFIG_NETFILTER_XT_MATCH_SCTP is not set
+# CONFIG_NETFILTER_XT_MATCH_STATISTIC is not set
+# CONFIG_NETFILTER_XT_MATCH_STRING is not set
+# CONFIG_NETFILTER_XT_MATCH_TCPMSS is not set
+# CONFIG_NETFILTER_XT_MATCH_TIME is not set
+# CONFIG_NETFILTER_XT_MATCH_U32 is not set
+# CONFIG_NETFILTER_XT_MATCH_HASHLIMIT is not set
 
 #
 # IP: Netfilter Configuration
 #
-CONFIG_IP_NF_CONNTRACK=m
-# CONFIG_IP_NF_CT_ACCT is not set
-# CONFIG_IP_NF_CONNTRACK_MARK is not set
-# CONFIG_IP_NF_CONNTRACK_EVENTS is not set
-# CONFIG_IP_NF_CT_PROTO_SCTP is not set
-CONFIG_IP_NF_FTP=m
-CONFIG_IP_NF_IRC=m
-# CONFIG_IP_NF_NETBIOS_NS is not set
-# CONFIG_IP_NF_TFTP is not set
-# CONFIG_IP_NF_AMANDA is not set
-# CONFIG_IP_NF_PPTP is not set
 CONFIG_IP_NF_QUEUE=m
 CONFIG_IP_NF_IPTABLES=m
-CONFIG_IP_NF_MATCH_LIMIT=m
 # CONFIG_IP_NF_MATCH_IPRANGE is not set
-CONFIG_IP_NF_MATCH_MAC=m
-# CONFIG_IP_NF_MATCH_PKTTYPE is not set
-CONFIG_IP_NF_MATCH_MARK=m
-CONFIG_IP_NF_MATCH_MULTIPORT=m
 CONFIG_IP_NF_MATCH_TOS=m
 # CONFIG_IP_NF_MATCH_RECENT is not set
 # CONFIG_IP_NF_MATCH_ECN is not set
-# CONFIG_IP_NF_MATCH_DSCP is not set
-CONFIG_IP_NF_MATCH_AH_ESP=m
-CONFIG_IP_NF_MATCH_LENGTH=m
+# CONFIG_IP_NF_MATCH_AH is not set
 CONFIG_IP_NF_MATCH_TTL=m
-CONFIG_IP_NF_MATCH_TCPMSS=m
-# CONFIG_IP_NF_MATCH_HELPER is not set
-CONFIG_IP_NF_MATCH_STATE=m
-# CONFIG_IP_NF_MATCH_CONNTRACK is not set
 CONFIG_IP_NF_MATCH_OWNER=m
-# CONFIG_IP_NF_MATCH_PHYSDEV is not set
 # CONFIG_IP_NF_MATCH_ADDRTYPE is not set
-# CONFIG_IP_NF_MATCH_REALM is not set
-# CONFIG_IP_NF_MATCH_SCTP is not set
-# CONFIG_IP_NF_MATCH_DCCP is not set
-# CONFIG_IP_NF_MATCH_COMMENT is not set
-# CONFIG_IP_NF_MATCH_HASHLIMIT is not set
-# CONFIG_IP_NF_MATCH_STRING is not set
 CONFIG_IP_NF_FILTER=m
 CONFIG_IP_NF_TARGET_REJECT=m
 CONFIG_IP_NF_TARGET_LOG=m
 CONFIG_IP_NF_TARGET_ULOG=m
-CONFIG_IP_NF_TARGET_TCPMSS=m
-# CONFIG_IP_NF_TARGET_NFQUEUE is not set
-CONFIG_IP_NF_NAT=m
-CONFIG_IP_NF_NAT_NEEDED=y
-CONFIG_IP_NF_TARGET_MASQUERADE=m
-CONFIG_IP_NF_TARGET_REDIRECT=m
-# CONFIG_IP_NF_TARGET_NETMAP is not set
-# CONFIG_IP_NF_TARGET_SAME is not set
-CONFIG_IP_NF_NAT_SNMP_BASIC=m
-CONFIG_IP_NF_NAT_IRC=m
-CONFIG_IP_NF_NAT_FTP=m
 CONFIG_IP_NF_MANGLE=m
 CONFIG_IP_NF_TARGET_TOS=m
 # CONFIG_IP_NF_TARGET_ECN is not set
-# CONFIG_IP_NF_TARGET_DSCP is not set
-CONFIG_IP_NF_TARGET_MARK=m
-# CONFIG_IP_NF_TARGET_CLASSIFY is not set
 # CONFIG_IP_NF_TARGET_TTL is not set
 # CONFIG_IP_NF_RAW is not set
 CONFIG_IP_NF_ARPTABLES=m
@@ -372,16 +431,9 @@ CONFIG_IP_NF_ARPFILTER=m
 # Bridge: Netfilter Configuration
 #
 # CONFIG_BRIDGE_NF_EBTABLES is not set
-
-#
-# DCCP Configuration (EXPERIMENTAL)
-#
 # CONFIG_IP_DCCP is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
 # CONFIG_IP_SCTP is not set
+# CONFIG_TIPC is not set
 CONFIG_ATM=y
 CONFIG_ATM_CLIP=y
 # CONFIG_ATM_CLIP_NO_ICMP is not set
@@ -397,25 +449,17 @@ CONFIG_LLC=m
 CONFIG_IPX=m
 # CONFIG_IPX_INTERN is not set
 CONFIG_ATALK=m
-CONFIG_DEV_APPLETALK=y
+CONFIG_DEV_APPLETALK=m
 CONFIG_IPDDP=m
 CONFIG_IPDDP_ENCAP=y
 CONFIG_IPDDP_DECAP=y
 CONFIG_X25=m
 CONFIG_LAPB=m
-# CONFIG_NET_DIVERT is not set
 CONFIG_ECONET=m
 CONFIG_ECONET_AUNUDP=y
 CONFIG_ECONET_NATIVE=y
 CONFIG_WAN_ROUTER=m
-
-#
-# QoS and/or fair queueing
-#
 CONFIG_NET_SCHED=y
-CONFIG_NET_SCH_CLK_JIFFIES=y
-# CONFIG_NET_SCH_CLK_GETTIMEOFDAY is not set
-# CONFIG_NET_SCH_CLK_CPU is not set
 
 #
 # Queueing/Scheduling
@@ -425,6 +469,7 @@ CONFIG_NET_SCH_HTB=m
 # CONFIG_NET_SCH_HFSC is not set
 # CONFIG_NET_SCH_ATM is not set
 CONFIG_NET_SCH_PRIO=m
+# CONFIG_NET_SCH_RR is not set
 CONFIG_NET_SCH_RED=m
 CONFIG_NET_SCH_SFQ=m
 CONFIG_NET_SCH_TEQL=m
@@ -449,10 +494,17 @@ CONFIG_NET_CLS_U32=m
 CONFIG_NET_CLS_RSVP=m
 CONFIG_NET_CLS_RSVP6=m
 # CONFIG_NET_EMATCH is not set
-# CONFIG_NET_CLS_ACT is not set
+CONFIG_NET_CLS_ACT=y
+CONFIG_NET_ACT_POLICE=y
+# CONFIG_NET_ACT_GACT is not set
+# CONFIG_NET_ACT_MIRRED is not set
+# CONFIG_NET_ACT_IPT is not set
+# CONFIG_NET_ACT_NAT is not set
+# CONFIG_NET_ACT_PEDIT is not set
+# CONFIG_NET_ACT_SIMP is not set
 CONFIG_NET_CLS_POLICE=y
 # CONFIG_NET_CLS_IND is not set
-CONFIG_NET_ESTIMATOR=y
+CONFIG_NET_SCH_FIFO=y
 
 #
 # Network testing
@@ -461,7 +513,18 @@ CONFIG_NET_PKTGEN=m
 # CONFIG_HAMRADIO is not set
 # CONFIG_IRDA is not set
 # CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+CONFIG_FIB_RULES=y
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
 # CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
 
 #
 # Device Drivers
@@ -470,19 +533,14 @@ CONFIG_NET_PKTGEN=m
 #
 # Generic Driver Options
 #
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_STANDALONE=y
 CONFIG_PREVENT_FIRMWARE_BUILD=y
-# CONFIG_FW_LOADER is not set
+CONFIG_FW_LOADER=y
 # CONFIG_DEBUG_DRIVER is not set
-
-#
-# Connector - unified userspace <-> kernelspace linker
-#
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
 # CONFIG_CONNECTOR is not set
-
-#
-# Memory Technology Devices (MTD)
-#
 CONFIG_MTD=y
 # CONFIG_MTD_DEBUG is not set
 # CONFIG_MTD_CONCAT is not set
@@ -498,11 +556,14 @@ CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1
 # User Modules And Translation Layers
 #
 CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
 CONFIG_MTD_BLOCK=y
 # CONFIG_FTL is not set
 # CONFIG_NFTL is not set
 # CONFIG_INFTL is not set
 # CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
 
 #
 # RAM/ROM/Flash chip drivers
@@ -528,7 +589,6 @@ CONFIG_MTD_CFI_UTIL=y
 # CONFIG_MTD_RAM is not set
 # CONFIG_MTD_ROM is not set
 # CONFIG_MTD_ABSENT is not set
-# CONFIG_MTD_XIP is not set
 
 #
 # Mapping drivers for chip access
@@ -538,6 +598,7 @@ CONFIG_MTD_COMPLEX_MAPPINGS=y
 # CONFIG_MTD_ARM_INTEGRATOR is not set
 CONFIG_MTD_IXP4XX=y
 # CONFIG_MTD_PCI is not set
+# CONFIG_MTD_INTEL_VR_NOR is not set
 # CONFIG_MTD_PLATRAM is not set
 
 #
@@ -547,7 +608,6 @@ CONFIG_MTD_IXP4XX=y
 # CONFIG_MTD_SLRAM is not set
 # CONFIG_MTD_PHRAM is not set
 # CONFIG_MTD_MTDRAM is not set
-# CONFIG_MTD_BLKMTD is not set
 # CONFIG_MTD_BLOCK2MTD is not set
 
 #
@@ -556,33 +616,24 @@ CONFIG_MTD_IXP4XX=y
 # CONFIG_MTD_DOC2000 is not set
 # CONFIG_MTD_DOC2001 is not set
 # CONFIG_MTD_DOC2001PLUS is not set
-
-#
-# NAND Flash Device Drivers
-#
 CONFIG_MTD_NAND=m
 # CONFIG_MTD_NAND_VERIFY_WRITE is not set
+# CONFIG_MTD_NAND_ECC_SMC is not set
+# CONFIG_MTD_NAND_MUSEUM_IDS is not set
 CONFIG_MTD_NAND_IDS=m
 # CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_CAFE is not set
 # CONFIG_MTD_NAND_NANDSIM is not set
-
-#
-# OneNAND Flash Device Drivers
-#
+# CONFIG_MTD_NAND_PLATFORM is not set
+# CONFIG_MTD_ALAUDA is not set
 # CONFIG_MTD_ONENAND is not set
 
 #
-# Parallel port support
+# UBI - Unsorted block images
 #
+# CONFIG_MTD_UBI is not set
 # CONFIG_PARPORT is not set
-
-#
-# Plug and Play support
-#
-
-#
-# Block devices
-#
+CONFIG_BLK_DEV=y
 # CONFIG_BLK_CPQ_DA is not set
 # CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_BLK_DEV_DAC960 is not set
@@ -592,17 +643,20 @@ CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_CRYPTOLOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
 # CONFIG_BLK_DEV_SX8 is not set
+# CONFIG_BLK_DEV_UB is not set
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_COUNT=16
 CONFIG_BLK_DEV_RAM_SIZE=8192
-CONFIG_BLK_DEV_INITRD=y
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
 # CONFIG_CDROM_PKTCDVD is not set
 # CONFIG_ATA_OVER_ETH is not set
-
-#
-# ATA/ATAPI/MFM/RLL support
-#
+CONFIG_MISC_DEVICES=y
+# CONFIG_PHANTOM is not set
+# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_TIFM_CORE is not set
 CONFIG_IDE=y
+CONFIG_IDE_MAX_HWIFS=4
 CONFIG_BLK_DEV_IDE=y
 
 #
@@ -614,24 +668,28 @@ CONFIG_BLK_DEV_IDEDISK=y
 # CONFIG_BLK_DEV_IDECD is not set
 # CONFIG_BLK_DEV_IDETAPE is not set
 # CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_BLK_DEV_IDESCSI is not set
 # CONFIG_IDE_TASK_IOCTL is not set
+CONFIG_IDE_PROC_FS=y
 
 #
 # IDE chipset support/bugfixes
 #
 CONFIG_IDE_GENERIC=y
+# CONFIG_BLK_DEV_PLATFORM is not set
+
+#
+# PCI IDE chipsets support
+#
 CONFIG_BLK_DEV_IDEPCI=y
 # CONFIG_IDEPCI_SHARE_IRQ is not set
+CONFIG_IDEPCI_PCIBUS_ORDER=y
 # CONFIG_BLK_DEV_OFFBOARD is not set
 # CONFIG_BLK_DEV_GENERIC is not set
 # CONFIG_BLK_DEV_OPTI621 is not set
-# CONFIG_BLK_DEV_SL82C105 is not set
 CONFIG_BLK_DEV_IDEDMA_PCI=y
-# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
-# CONFIG_IDEDMA_PCI_AUTO is not set
 # CONFIG_BLK_DEV_AEC62XX is not set
 # CONFIG_BLK_DEV_ALI15X3 is not set
-# CONFIG_BLK_DEV_AMD74XX is not set
 CONFIG_BLK_DEV_CMD64X=y
 # CONFIG_BLK_DEV_TRIFLEX is not set
 # CONFIG_BLK_DEV_CY82C693 is not set
@@ -639,93 +697,163 @@ CONFIG_BLK_DEV_CMD64X=y
 # CONFIG_BLK_DEV_CS5530 is not set
 # CONFIG_BLK_DEV_HPT34X is not set
 CONFIG_BLK_DEV_HPT366=y
+# CONFIG_BLK_DEV_JMICRON is not set
 # CONFIG_BLK_DEV_SC1200 is not set
 # CONFIG_BLK_DEV_PIIX is not set
+# CONFIG_BLK_DEV_IT8213 is not set
 # CONFIG_BLK_DEV_IT821X is not set
 # CONFIG_BLK_DEV_NS87415 is not set
 # CONFIG_BLK_DEV_PDC202XX_OLD is not set
 CONFIG_BLK_DEV_PDC202XX_NEW=y
-# CONFIG_PDC202XX_FORCE is not set
 # CONFIG_BLK_DEV_SVWKS is not set
 # CONFIG_BLK_DEV_SIIMAGE is not set
+# CONFIG_BLK_DEV_SL82C105 is not set
 # CONFIG_BLK_DEV_SLC90E66 is not set
 # CONFIG_BLK_DEV_TRM290 is not set
 # CONFIG_BLK_DEV_VIA82CXXX is not set
+# CONFIG_BLK_DEV_TC86C001 is not set
 # CONFIG_IDE_ARM is not set
 CONFIG_BLK_DEV_IDEDMA=y
-# CONFIG_IDEDMA_IVB is not set
-# CONFIG_IDEDMA_AUTO is not set
+CONFIG_IDE_ARCH_OBSOLETE_INIT=y
 # CONFIG_BLK_DEV_HD is not set
 
 #
 # SCSI device support
 #
 # CONFIG_RAID_ATTRS is not set
-# CONFIG_SCSI is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_SCSI_PROC_FS is not set
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+# CONFIG_SCSI_LOWLEVEL is not set
+CONFIG_ATA=y
+# CONFIG_ATA_NONSTANDARD is not set
+# CONFIG_SATA_AHCI is not set
+# CONFIG_SATA_SVW is not set
+# CONFIG_ATA_PIIX is not set
+# CONFIG_SATA_MV is not set
+# CONFIG_SATA_NV is not set
+# CONFIG_PDC_ADMA is not set
+# CONFIG_SATA_QSTOR is not set
+# CONFIG_SATA_PROMISE is not set
+# CONFIG_SATA_SX4 is not set
+# CONFIG_SATA_SIL is not set
+# CONFIG_SATA_SIL24 is not set
+# CONFIG_SATA_SIS is not set
+# CONFIG_SATA_ULI is not set
+# CONFIG_SATA_VIA is not set
+# CONFIG_SATA_VITESSE is not set
+# CONFIG_SATA_INIC162X is not set
+# CONFIG_PATA_ALI is not set
+# CONFIG_PATA_AMD is not set
+CONFIG_PATA_ARTOP=y
+# CONFIG_PATA_ATIIXP is not set
+# CONFIG_PATA_CMD640_PCI is not set
+# CONFIG_PATA_CMD64X is not set
+# CONFIG_PATA_CS5520 is not set
+# CONFIG_PATA_CS5530 is not set
+# CONFIG_PATA_CYPRESS is not set
+# CONFIG_PATA_EFAR is not set
+# CONFIG_ATA_GENERIC is not set
+# CONFIG_PATA_HPT366 is not set
+# CONFIG_PATA_HPT37X is not set
+# CONFIG_PATA_HPT3X2N is not set
+# CONFIG_PATA_HPT3X3 is not set
+# CONFIG_PATA_IT821X is not set
+# CONFIG_PATA_IT8213 is not set
+# CONFIG_PATA_JMICRON is not set
+# CONFIG_PATA_TRIFLEX is not set
+# CONFIG_PATA_MARVELL is not set
+# CONFIG_PATA_MPIIX is not set
+# CONFIG_PATA_OLDPIIX is not set
+# CONFIG_PATA_NETCELL is not set
+# CONFIG_PATA_NS87410 is not set
+# CONFIG_PATA_NS87415 is not set
+# CONFIG_PATA_OPTI is not set
+# CONFIG_PATA_OPTIDMA is not set
+# CONFIG_PATA_PDC_OLD is not set
+# CONFIG_PATA_RADISYS is not set
+# CONFIG_PATA_RZ1000 is not set
+# CONFIG_PATA_SC1200 is not set
+# CONFIG_PATA_SERVERWORKS is not set
+# CONFIG_PATA_PDC2027X is not set
+# CONFIG_PATA_SIL680 is not set
+# CONFIG_PATA_SIS is not set
+# CONFIG_PATA_VIA is not set
+# CONFIG_PATA_WINBOND is not set
+# CONFIG_PATA_PLATFORM is not set
+CONFIG_PATA_IXP4XX_CF=y
 # CONFIG_MD is not set
-
-#
-# Fusion MPT device support
-#
 # CONFIG_FUSION is not set
 
 #
 # IEEE 1394 (FireWire) support
 #
+# CONFIG_FIREWIRE is not set
 # CONFIG_IEEE1394 is not set
-
-#
-# I2O device support
-#
 # CONFIG_I2O is not set
-
-#
-# Network device support
-#
 CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
+# CONFIG_IFB is not set
 CONFIG_DUMMY=y
 # CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
 # CONFIG_EQUALIZER is not set
 # CONFIG_TUN is not set
-
-#
-# ARCnet devices
-#
+# CONFIG_VETH is not set
 # CONFIG_ARCNET is not set
-
-#
-# PHY device support
-#
 # CONFIG_PHYLIB is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
 CONFIG_NET_ETHERNET=y
 CONFIG_MII=y
+CONFIG_IXP4XX_ETH=y
+# CONFIG_AX88796 is not set
 # CONFIG_HAPPYMEAL is not set
 # CONFIG_SUNGEM is not set
 # CONFIG_CASSINI is not set
 # CONFIG_NET_VENDOR_3COM is not set
 # CONFIG_SMC91X is not set
 # CONFIG_DM9000 is not set
-
-#
-# Tulip family network device support
-#
 # CONFIG_NET_TULIP is not set
 # CONFIG_HP100 is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
 CONFIG_NET_PCI=y
 # CONFIG_PCNET32 is not set
 # CONFIG_AMD8111_ETH is not set
 # CONFIG_ADAPTEC_STARFIRE is not set
 # CONFIG_B44 is not set
 # CONFIG_FORCEDETH is not set
-# CONFIG_DGRS is not set
 CONFIG_EEPRO100=y
 # CONFIG_E100 is not set
 # CONFIG_FEALNX is not set
@@ -738,93 +866,76 @@ CONFIG_EEPRO100=y
 # CONFIG_SUNDANCE is not set
 # CONFIG_TLAN is not set
 # CONFIG_VIA_RHINE is not set
-
-#
-# Ethernet (1000 Mbit)
-#
+# CONFIG_SC92031 is not set
+CONFIG_NETDEV_1000=y
 # CONFIG_ACENIC is not set
 # CONFIG_DL2K is not set
 # CONFIG_E1000 is not set
+# CONFIG_E1000E is not set
+# CONFIG_IP1000 is not set
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
 # CONFIG_R8169 is not set
 # CONFIG_SIS190 is not set
 # CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_VIA_VELOCITY is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_BNX2 is not set
-
-#
-# Ethernet (10000 Mbit)
-#
+# CONFIG_QLA3XXX is not set
+# CONFIG_ATL1 is not set
+CONFIG_NETDEV_10000=y
 # CONFIG_CHELSIO_T1 is not set
+# CONFIG_CHELSIO_T3 is not set
+# CONFIG_IXGBE is not set
 # CONFIG_IXGB is not set
 # CONFIG_S2IO is not set
-
-#
-# Token Ring devices
-#
+# CONFIG_MYRI10GE is not set
+# CONFIG_NETXEN_NIC is not set
+# CONFIG_NIU is not set
+# CONFIG_MLX4_CORE is not set
+# CONFIG_TEHUTI is not set
 # CONFIG_TR is not set
 
 #
-# Wireless LAN (non-hamradio)
-#
-CONFIG_NET_RADIO=y
-
-#
-# Obsolete Wireless cards support (pre-802.11)
-#
-# CONFIG_STRIP is not set
-
-#
-# Wireless 802.11b ISA/PCI cards support
-#
-# CONFIG_AIRO is not set
-CONFIG_HERMES=y
-# CONFIG_PLX_HERMES is not set
-# CONFIG_TMD_HERMES is not set
-# CONFIG_NORTEL_HERMES is not set
-CONFIG_PCI_HERMES=y
-# CONFIG_ATMEL is not set
-
-#
-# Prism GT/Duette 802.11(a/b/g) PCI/Cardbus support
+# Wireless LAN
 #
-# CONFIG_PRISM54 is not set
-# CONFIG_HOSTAP is not set
-CONFIG_NET_WIRELESS=y
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
 
 #
-# Wan interfaces
+# USB Network Adapters
 #
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET is not set
 CONFIG_WAN=y
-# CONFIG_DSCC4 is not set
 # CONFIG_LANMEDIA is not set
-# CONFIG_SYNCLINK_SYNCPPP is not set
 CONFIG_HDLC=m
-CONFIG_HDLC_RAW=y
+CONFIG_HDLC_RAW=m
 # CONFIG_HDLC_RAW_ETH is not set
-CONFIG_HDLC_CISCO=y
-CONFIG_HDLC_FR=y
-CONFIG_HDLC_PPP=y
-CONFIG_HDLC_X25=y
+CONFIG_HDLC_CISCO=m
+CONFIG_HDLC_FR=m
+CONFIG_HDLC_PPP=m
+CONFIG_HDLC_X25=m
 # CONFIG_PCI200SYN is not set
 # CONFIG_WANXL is not set
 # CONFIG_PC300 is not set
+# CONFIG_PC300TOO is not set
 # CONFIG_FARSYNC is not set
+# CONFIG_DSCC4 is not set
+# CONFIG_IXP4XX_HSS is not set
 CONFIG_DLCI=m
-CONFIG_DLCI_COUNT=24
 CONFIG_DLCI_MAX=8
-CONFIG_WAN_ROUTER_DRIVERS=y
+CONFIG_WAN_ROUTER_DRIVERS=m
 # CONFIG_CYCLADES_SYNC is not set
 # CONFIG_LAPBETHER is not set
 # CONFIG_X25_ASY is not set
-
-#
-# ATM drivers
-#
+CONFIG_ATM_DRIVERS=y
 # CONFIG_ATM_DUMMY is not set
 CONFIG_ATM_TCP=m
 # CONFIG_ATM_LANAI is not set
@@ -842,20 +953,19 @@ CONFIG_ATM_TCP=m
 # CONFIG_HIPPI is not set
 # CONFIG_PPP is not set
 # CONFIG_SLIP is not set
+# CONFIG_NET_FC is not set
 # CONFIG_SHAPER is not set
 # CONFIG_NETCONSOLE is not set
 # CONFIG_NETPOLL is not set
 # CONFIG_NET_POLL_CONTROLLER is not set
-
-#
-# ISDN subsystem
-#
 # CONFIG_ISDN is not set
 
 #
 # Input device support
 #
 CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
 
 #
 # Userland interfaces
@@ -865,7 +975,6 @@ CONFIG_INPUT_MOUSEDEV_PSAUX=y
 CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
 CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 # CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_TSDEV is not set
 # CONFIG_INPUT_EVDEV is not set
 # CONFIG_INPUT_EVBUG is not set
 
@@ -875,8 +984,16 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 # CONFIG_INPUT_KEYBOARD is not set
 # CONFIG_INPUT_MOUSE is not set
 # CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
 # CONFIG_INPUT_TOUCHSCREEN is not set
-# CONFIG_INPUT_MISC is not set
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_IXP4XX_BEEPER=y
+# CONFIG_INPUT_ATI_REMOTE is not set
+# CONFIG_INPUT_ATI_REMOTE2 is not set
+# CONFIG_INPUT_KEYSPAN_REMOTE is not set
+# CONFIG_INPUT_POWERMATE is not set
+# CONFIG_INPUT_YEALINK is not set
+# CONFIG_INPUT_UINPUT is not set
 
 #
 # Hardware I/O ports
@@ -895,7 +1012,9 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 #
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_PCI=y
 CONFIG_SERIAL_8250_NR_UARTS=2
+CONFIG_SERIAL_8250_RUNTIME_UARTS=2
 # CONFIG_SERIAL_8250_EXTENDED is not set
 
 #
@@ -907,51 +1026,17 @@ CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
-
-#
-# IPMI
-#
 # CONFIG_IPMI_HANDLER is not set
-
-#
-# Watchdog Cards
-#
-CONFIG_WATCHDOG=y
-# CONFIG_WATCHDOG_NOWAYOUT is not set
-
-#
-# Watchdog Device Drivers
-#
-# CONFIG_SOFT_WATCHDOG is not set
-CONFIG_IXP4XX_WATCHDOG=y
-
-#
-# PCI-based Watchdog Cards
-#
-# CONFIG_PCIPCWATCHDOG is not set
-# CONFIG_WDTPCI is not set
+CONFIG_HW_RANDOM=m
+CONFIG_HW_RANDOM_IXP4XX=m
 # CONFIG_NVRAM is not set
-# CONFIG_RTC is not set
-# CONFIG_DTLK is not set
 # CONFIG_R3964 is not set
 # CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_DRM is not set
 # CONFIG_RAW_DRIVER is not set
-
-#
-# TPM devices
-#
 # CONFIG_TCG_TPM is not set
-# CONFIG_TELCLOCK is not set
-
-#
-# I2C support
-#
+CONFIG_DEVPORT=y
 CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
 CONFIG_I2C_CHARDEV=y
 
 #
@@ -969,57 +1054,68 @@ CONFIG_I2C_ALGOBIT=y
 # CONFIG_I2C_ALI15X3 is not set
 # CONFIG_I2C_AMD756 is not set
 # CONFIG_I2C_AMD8111 is not set
+# CONFIG_I2C_GPIO is not set
 # CONFIG_I2C_I801 is not set
 # CONFIG_I2C_I810 is not set
 # CONFIG_I2C_PIIX4 is not set
 # CONFIG_I2C_IOP3XX is not set
 CONFIG_I2C_IXP4XX=y
 # CONFIG_I2C_NFORCE2 is not set
+# CONFIG_I2C_OCORES is not set
 # CONFIG_I2C_PARPORT_LIGHT is not set
 # CONFIG_I2C_PROSAVAGE is not set
 # CONFIG_I2C_SAVAGE4 is not set
-# CONFIG_SCx200_ACB is not set
+# CONFIG_I2C_SIMTEC is not set
 # CONFIG_I2C_SIS5595 is not set
 # CONFIG_I2C_SIS630 is not set
 # CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_TAOS_EVM is not set
 # CONFIG_I2C_STUB is not set
+# CONFIG_I2C_TINY_USB is not set
 # CONFIG_I2C_VIA is not set
 # CONFIG_I2C_VIAPRO is not set
 # CONFIG_I2C_VOODOO3 is not set
-# CONFIG_I2C_PCA_ISA is not set
 
 #
 # Miscellaneous I2C Chip support
 #
 # CONFIG_SENSORS_DS1337 is not set
 # CONFIG_SENSORS_DS1374 is not set
+# CONFIG_DS1682 is not set
 CONFIG_SENSORS_EEPROM=y
 # CONFIG_SENSORS_PCF8574 is not set
 # CONFIG_SENSORS_PCA9539 is not set
 # CONFIG_SENSORS_PCF8591 is not set
-# CONFIG_SENSORS_RTC8564 is not set
 # CONFIG_SENSORS_MAX6875 is not set
-# CONFIG_RTC_X1205_I2C is not set
+# CONFIG_SENSORS_TSL2550 is not set
 # CONFIG_I2C_DEBUG_CORE is not set
 # CONFIG_I2C_DEBUG_ALGO is not set
 # CONFIG_I2C_DEBUG_BUS is not set
 # CONFIG_I2C_DEBUG_CHIP is not set
 
 #
-# Hardware Monitoring support
+# SPI support
 #
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
 CONFIG_HWMON=y
 # CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_AD7418 is not set
 # CONFIG_SENSORS_ADM1021 is not set
 # CONFIG_SENSORS_ADM1025 is not set
 # CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1029 is not set
 # CONFIG_SENSORS_ADM1031 is not set
 # CONFIG_SENSORS_ADM9240 is not set
-# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_ADT7470 is not set
 # CONFIG_SENSORS_ATXP1 is not set
 # CONFIG_SENSORS_DS1621 is not set
-# CONFIG_SENSORS_FSCHER is not set
-# CONFIG_SENSORS_FSCPOS is not set
+# CONFIG_SENSORS_I5K_AMB is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_F71882FG is not set
+# CONFIG_SENSORS_F75375S is not set
 # CONFIG_SENSORS_GL518SM is not set
 # CONFIG_SENSORS_GL520SM is not set
 # CONFIG_SENSORS_IT87 is not set
@@ -1033,67 +1129,268 @@ CONFIG_HWMON=y
 # CONFIG_SENSORS_LM87 is not set
 # CONFIG_SENSORS_LM90 is not set
 # CONFIG_SENSORS_LM92 is not set
+# CONFIG_SENSORS_LM93 is not set
 # CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_MAX6650 is not set
 # CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 is not set
 # CONFIG_SENSORS_SIS5595 is not set
+# CONFIG_SENSORS_DME1737 is not set
 # CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47M192 is not set
 # CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_THMC50 is not set
 # CONFIG_SENSORS_VIA686A is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_VT8231 is not set
 # CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83791D is not set
 # CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83793 is not set
 # CONFIG_SENSORS_W83L785TS is not set
 # CONFIG_SENSORS_W83627HF is not set
 # CONFIG_SENSORS_W83627EHF is not set
 # CONFIG_HWMON_DEBUG_CHIP is not set
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
 
 #
-# Misc devices
+# Watchdog Device Drivers
 #
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_IXP4XX_WATCHDOG=y
 
 #
-# Multimedia Capabilities Port drivers
+# PCI-based Watchdog Cards
 #
+# CONFIG_PCIPCWATCHDOG is not set
+# CONFIG_WDTPCI is not set
 
 #
-# Multimedia devices
+# USB-based Watchdog Cards
 #
-# CONFIG_VIDEO_DEV is not set
+# CONFIG_USBPCWATCHDOG is not set
 
 #
-# Digital Video Broadcasting Devices
+# Sonics Silicon Backplane
 #
-# CONFIG_DVB is not set
+CONFIG_SSB_POSSIBLE=y
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+CONFIG_DAB=y
+# CONFIG_USB_DABUSB is not set
 
 #
 # Graphics support
 #
+# CONFIG_DRM is not set
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
 # CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
 
 #
 # Sound
 #
 # CONFIG_SOUND is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+# CONFIG_HIDRAW is not set
 
 #
-# USB support
+# USB Input Devices
 #
+CONFIG_USB_HID=y
+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
+# CONFIG_HID_FF is not set
+# CONFIG_USB_HIDDEV is not set
+CONFIG_USB_SUPPORT=y
 CONFIG_USB_ARCH_HAS_HCD=y
 CONFIG_USB_ARCH_HAS_OHCI=y
-# CONFIG_USB is not set
+CONFIG_USB_ARCH_HAS_EHCI=y
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_DEVICE_CLASS is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG is not set
+
+#
+# USB Host Controller Drivers
+#
+CONFIG_USB_EHCI_HCD=y
+# CONFIG_USB_EHCI_SPLIT_ISO is not set
+# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
+# CONFIG_USB_EHCI_TT_NEWSCHED is not set
+# CONFIG_USB_ISP116X_HCD is not set
+CONFIG_USB_OHCI_HCD=y
+# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+CONFIG_USB_UHCI_HCD=y
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
 
 #
 # NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
 #
 
+#
+# may also be needed; see USB_STORAGE Help for more information
+#
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+# CONFIG_USB_MON is not set
+
+#
+# USB port drivers
+#
+
+#
+# USB Serial Converter support
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGET is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_SISUSBVGA is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_TEST is not set
+
+#
+# USB DSL modem support
+#
+# CONFIG_USB_ATM is not set
+
 #
 # USB Gadget Support
 #
 # CONFIG_USB_GADGET is not set
+# CONFIG_MMC is not set
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
 
 #
-# MMC/SD Card support
+# LED drivers
+#
+# CONFIG_LEDS_IXP4XX is not set
+CONFIG_LEDS_GPIO=y
+
+#
+# LED Triggers
+#
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_TIMER=y
+CONFIG_LEDS_TRIGGER_IDE_DISK=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+# CONFIG_RTC_DRV_DS1307 is not set
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+CONFIG_RTC_DRV_X1205=y
+CONFIG_RTC_DRV_PCF8563=y
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
+
+#
+# SPI RTC drivers
+#
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_CMOS is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
 #
-# CONFIG_MMC is not set
 
 #
 # File systems
@@ -1107,16 +1404,19 @@ CONFIG_EXT3_FS=y
 CONFIG_EXT3_FS_XATTR=y
 CONFIG_EXT3_FS_POSIX_ACL=y
 # CONFIG_EXT3_FS_SECURITY is not set
+# CONFIG_EXT4DEV_FS is not set
 CONFIG_JBD=y
-# CONFIG_JBD_DEBUG is not set
 CONFIG_FS_MBCACHE=y
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 CONFIG_FS_POSIX_ACL=y
 # CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
 # CONFIG_QUOTA is not set
 CONFIG_DNOTIFY=y
 # CONFIG_AUTOFS_FS is not set
@@ -1140,11 +1440,12 @@ CONFIG_DNOTIFY=y
 # Pseudo filesystems
 #
 CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
 CONFIG_SYSFS=y
 CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
 # CONFIG_HUGETLB_PAGE is not set
-CONFIG_RAMFS=y
-# CONFIG_RELAYFS_FS is not set
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -1156,13 +1457,15 @@ CONFIG_RAMFS=y
 # CONFIG_BEFS_FS is not set
 # CONFIG_BFS_FS is not set
 # CONFIG_EFS_FS is not set
-# CONFIG_JFFS_FS is not set
 CONFIG_JFFS2_FS=y
 CONFIG_JFFS2_FS_DEBUG=0
 CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
 # CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_FS_XATTR is not set
 # CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
 CONFIG_JFFS2_ZLIB=y
+# CONFIG_JFFS2_LZO is not set
 CONFIG_JFFS2_RTIME=y
 # CONFIG_JFFS2_RUBIN is not set
 # CONFIG_CRAMFS is not set
@@ -1171,10 +1474,7 @@ CONFIG_JFFS2_RTIME=y
 # CONFIG_QNX4FS_FS is not set
 # CONFIG_SYSV_FS is not set
 # CONFIG_UFS_FS is not set
-
-#
-# Network File Systems
-#
+CONFIG_NETWORK_FILESYSTEMS=y
 CONFIG_NFS_FS=y
 CONFIG_NFS_V3=y
 # CONFIG_NFS_V3_ACL is not set
@@ -1186,6 +1486,7 @@ CONFIG_LOCKD=y
 CONFIG_LOCKD_V4=y
 CONFIG_NFS_COMMON=y
 CONFIG_SUNRPC=y
+# CONFIG_SUNRPC_BIND34 is not set
 # CONFIG_RPCSEC_GSS_KRB5 is not set
 # CONFIG_RPCSEC_GSS_SPKM3 is not set
 # CONFIG_SMB_FS is not set
@@ -1193,7 +1494,6 @@ CONFIG_SUNRPC=y
 # CONFIG_NCP_FS is not set
 # CONFIG_CODA_FS is not set
 # CONFIG_AFS_FS is not set
-# CONFIG_9P_FS is not set
 
 #
 # Partition Types
@@ -1213,37 +1513,53 @@ CONFIG_MSDOS_PARTITION=y
 # CONFIG_SGI_PARTITION is not set
 # CONFIG_ULTRIX_PARTITION is not set
 # CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
 # CONFIG_EFI_PARTITION is not set
-
-#
-# Native Language Support
-#
+# CONFIG_SYSV68_PARTITION is not set
 # CONFIG_NLS is not set
-
-#
-# Profiling support
-#
+# CONFIG_DLM is not set
+CONFIG_INSTRUMENTATION=y
 # CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
 
 #
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
-CONFIG_DEBUG_KERNEL=y
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
 CONFIG_MAGIC_SYSRQ=y
-CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
 CONFIG_DETECT_SOFTLOCKUP=y
+CONFIG_SCHED_DEBUG=y
 # CONFIG_SCHEDSTATS is not set
-# CONFIG_DEBUG_SLAB is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_SLUB_DEBUG_ON is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
 # CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
 # CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
 # CONFIG_DEBUG_KOBJECT is not set
 CONFIG_DEBUG_BUGVERBOSE=y
 # CONFIG_DEBUG_INFO is not set
-# CONFIG_DEBUG_FS is not set
 # CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
 CONFIG_FRAME_POINTER=y
+CONFIG_FORCED_INLINING=y
+# CONFIG_BOOT_PRINTK_DELAY is not set
 # CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_SAMPLES is not set
 # CONFIG_DEBUG_USER is not set
 CONFIG_DEBUG_ERRORS=y
 CONFIG_DEBUG_LL=y
@@ -1254,22 +1570,22 @@ CONFIG_DEBUG_LL=y
 #
 # CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
 # CONFIG_CRYPTO is not set
 
-#
-# Hardware crypto devices
-#
-
 #
 # Library routines
 #
+CONFIG_BITREVERSE=y
 # CONFIG_CRC_CCITT is not set
 # CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
 CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
 # CONFIG_LIBCRC32C is not set
 CONFIG_ZLIB_INFLATE=y
 CONFIG_ZLIB_DEFLATE=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
index faa7619211534c541f61e370985cf1480f247f52..00d44c6fbfe94be02a5c2aaa0aad6388aaa960a9 100644 (file)
@@ -20,6 +20,7 @@ obj-$(CONFIG_PCI)             += bios32.o isa.o
 obj-$(CONFIG_SMP)              += smp.o
 obj-$(CONFIG_KEXEC)            += machine_kexec.o relocate_kernel.o
 obj-$(CONFIG_KPROBES)          += kprobes.o kprobes-decode.o
+obj-$(CONFIG_ATAGS_PROC)       += atags.o
 obj-$(CONFIG_OABI_COMPAT)      += sys_oabi-compat.o
 
 obj-$(CONFIG_CRUNCH)           += crunch.o crunch-bits.o
diff --git a/arch/arm/kernel/atags.c b/arch/arm/kernel/atags.c
new file mode 100644 (file)
index 0000000..e2e934c
--- /dev/null
@@ -0,0 +1,86 @@
+#include <linux/slab.h>
+#include <linux/kexec.h>
+#include <linux/proc_fs.h>
+#include <asm/setup.h>
+#include <asm/types.h>
+#include <asm/page.h>
+
+struct buffer {
+       size_t size;
+       char *data;
+};
+static struct buffer tags_buffer;
+
+static int
+read_buffer(char* page, char** start, off_t off, int count,
+       int* eof, void* data)
+{
+       struct buffer *buffer = (struct buffer *)data;
+
+       if (off >= buffer->size) {
+               *eof = 1;
+               return 0;
+       }
+
+       count = min((int) (buffer->size - off), count);
+
+       memcpy(page, &buffer->data[off], count);
+
+       return count;
+}
+
+
+static int
+create_proc_entries(void)
+{
+       struct proc_dir_entry* tags_entry;
+
+       tags_entry = create_proc_read_entry("atags", 0400, &proc_root, read_buffer, &tags_buffer);
+       if (!tags_entry)
+               return -ENOMEM;
+
+       return 0;
+}
+
+
+static char __initdata atags_copy_buf[KEXEC_BOOT_PARAMS_SIZE];
+static char __initdata *atags_copy;
+
+void __init save_atags(const struct tag *tags)
+{
+       atags_copy = atags_copy_buf;
+       memcpy(atags_copy, tags, KEXEC_BOOT_PARAMS_SIZE);
+}
+
+
+static int __init init_atags_procfs(void)
+{
+       struct tag *tag;
+       int error;
+
+       if (!atags_copy) {
+               printk(KERN_WARNING "Exporting ATAGs: No saved tags found\n");
+               return -EIO;
+       }
+
+       for (tag = (struct tag *) atags_copy; tag->hdr.size; tag = tag_next(tag))
+               ;
+
+       tags_buffer.size = ((char *) tag - atags_copy) + sizeof(tag->hdr);
+       tags_buffer.data = kmalloc(tags_buffer.size, GFP_KERNEL);
+       if (tags_buffer.data == NULL)
+               return -ENOMEM;
+       memcpy(tags_buffer.data, atags_copy, tags_buffer.size);
+
+       error = create_proc_entries();
+       if (error) {
+               printk(KERN_ERR "Exporting ATAGs: not enough memory\n");
+               kfree(tags_buffer.data);
+               tags_buffer.size = 0;
+               tags_buffer.data = NULL;
+       }
+
+       return error;
+}
+
+arch_initcall(init_atags_procfs);
diff --git a/arch/arm/kernel/atags.h b/arch/arm/kernel/atags.h
new file mode 100644 (file)
index 0000000..e5f028d
--- /dev/null
@@ -0,0 +1,5 @@
+#ifdef CONFIG_ATAGS_PROC
+extern void save_atags(struct tag *tags);
+#else
+static inline void save_atags(struct tag *tags) { }
+#endif
index cecf658e362514e56fc0a56084ece50da5d8a0d2..283e14fff993dde1881b005aa6dbb1598e359780 100644 (file)
                CALL(sys_kexec_load)
                CALL(sys_utimensat)
                CALL(sys_signalfd)
-/* 350 */      CALL(sys_timerfd)
+/* 350 */      CALL(sys_ni_syscall)
                CALL(sys_eventfd)
                CALL(sys_fallocate)
 #ifndef syscalls_counted
index 863c66454f2b44ab82b0be5f55755df471153f5b..db8f54a3451f4f4fd0a8d8bf6dee963374d81db1 100644 (file)
@@ -21,6 +21,7 @@ extern void setup_mm_for_reboot(char mode);
 extern unsigned long kexec_start_address;
 extern unsigned long kexec_indirection_page;
 extern unsigned long kexec_mach_type;
+extern unsigned long kexec_boot_atags;
 
 /*
  * Provide a dummy crash_notes definition while crash dump arrives to arm.
@@ -62,6 +63,7 @@ void machine_kexec(struct kimage *image)
        kexec_start_address = image->start;
        kexec_indirection_page = page_list;
        kexec_mach_type = machine_arch_type;
+       kexec_boot_atags = image->start - KEXEC_ARM_ZIMAGE_OFFSET + KEXEC_ARM_ATAGS_OFFSET;
 
        /* copy our kernel relocation code to the control code page */
        memcpy(reboot_code_buffer,
index 062c111c572feb9bc223ea08399e931f67613c10..61930eb0902941030e3e180aca40f6f82697e39e 100644 (file)
@@ -7,23 +7,6 @@
        .globl relocate_new_kernel
 relocate_new_kernel:
 
-       /* Move boot params back to where the kernel expects them */
-
-       ldr     r0,kexec_boot_params_address
-       teq     r0,#0
-       beq     8f
-
-       ldr     r1,kexec_boot_params_copy
-       mov     r6,#KEXEC_BOOT_PARAMS_SIZE/4
-7:
-       ldr     r5,[r1],#4
-       str     r5,[r0],#4
-       subs    r6,r6,#1
-       bne     7b
-
-8:
-       /* Boot params moved, now go on with the kernel */
-
        ldr     r0,kexec_indirection_page
        ldr     r1,kexec_start_address
 
@@ -67,7 +50,7 @@ relocate_new_kernel:
        mov lr,r1
        mov r0,#0
        ldr r1,kexec_mach_type
-       ldr r2,kexec_boot_params_address
+       ldr r2,kexec_boot_atags
        mov pc,lr
 
        .globl kexec_start_address
@@ -82,14 +65,9 @@ kexec_indirection_page:
 kexec_mach_type:
        .long   0x0
 
-       /* phy addr where new kernel will expect to find boot params */
-       .globl kexec_boot_params_address
-kexec_boot_params_address:
-       .long   0x0
-
-       /* phy addr where old kernel put a copy of orig boot params */
-       .globl kexec_boot_params_copy
-kexec_boot_params_copy:
+       /* phy addr of the atags for the new kernel */
+       .globl kexec_boot_atags
+kexec_boot_atags:
        .long   0x0
 
 relocate_new_kernel_end:
index bf56eb337df16a9bc5d7c9033023202ba466cccc..d3941a7b0455cf632cc3ae066ade8fbad7124f2c 100644 (file)
@@ -24,7 +24,6 @@
 #include <linux/interrupt.h>
 #include <linux/smp.h>
 #include <linux/fs.h>
-#include <linux/kexec.h>
 
 #include <asm/cpu.h>
 #include <asm/elf.h>
@@ -39,6 +38,7 @@
 #include <asm/mach/time.h>
 
 #include "compat.h"
+#include "atags.h"
 
 #ifndef MEM_SIZE
 #define MEM_SIZE       (16*1024*1024)
@@ -62,6 +62,7 @@ extern int root_mountflags;
 extern void _stext, _text, _etext, __data_start, _edata, _end;
 
 unsigned int processor_id;
+EXPORT_SYMBOL(processor_id);
 unsigned int __machine_arch_type;
 EXPORT_SYMBOL(__machine_arch_type);
 
@@ -784,23 +785,6 @@ static int __init customize_machine(void)
 }
 arch_initcall(customize_machine);
 
-#ifdef CONFIG_KEXEC
-
-/* Physical addr of where the boot params should be for this machine */
-extern unsigned long kexec_boot_params_address;
-
-/* Physical addr of the buffer into which the boot params are copied */
-extern unsigned long kexec_boot_params_copy;
-
-/* Pointer to the boot params buffer, for manipulation and display */
-unsigned long kexec_boot_params;
-EXPORT_SYMBOL(kexec_boot_params);
-
-/* The buffer itself - make sure it is sized correctly */
-static unsigned long kexec_boot_params_buf[(KEXEC_BOOT_PARAMS_SIZE + 3) / 4];
-
-#endif
-
 void __init setup_arch(char **cmdline_p)
 {
        struct tag *tags = (struct tag *)&init_tags;
@@ -819,18 +803,6 @@ void __init setup_arch(char **cmdline_p)
        else if (mdesc->boot_params)
                tags = phys_to_virt(mdesc->boot_params);
 
-#ifdef CONFIG_KEXEC
-       kexec_boot_params_copy = virt_to_phys(kexec_boot_params_buf);
-       kexec_boot_params = (unsigned long)kexec_boot_params_buf;
-       if (__atags_pointer) {
-               kexec_boot_params_address = __atags_pointer;
-               memcpy((void *)kexec_boot_params, tags, KEXEC_BOOT_PARAMS_SIZE);
-       } else if (mdesc->boot_params) {
-               kexec_boot_params_address = mdesc->boot_params;
-               memcpy((void *)kexec_boot_params, tags, KEXEC_BOOT_PARAMS_SIZE);
-       }
-#endif
-
        /*
         * If we have the old style parameters, convert them to
         * a tag list.
@@ -846,6 +818,7 @@ void __init setup_arch(char **cmdline_p)
        if (tags->hdr.tag == ATAG_CORE) {
                if (meminfo.nr_banks != 0)
                        squash_mem_tags(tags);
+               save_atags(tags);
                parse_tags(tags);
        }
 
index eafbb2b05eb8a2cb7f78a522053f16e4cf70f574..eefae1de334cabbb94ec07e0c85d2ac01795282f 100644 (file)
@@ -150,7 +150,7 @@ int __cpuinit __cpu_up(unsigned int cpu)
        secondary_data.pgdir = 0;
 
        *pmd_offset(pgd, PHYS_OFFSET) = __pmd(0);
-       pgd_free(pgd);
+       pgd_free(&init_mm, pgd);
 
        if (ret) {
                printk(KERN_CRIT "CPU%u: processor failed to boot\n", cpu);
@@ -290,6 +290,11 @@ asmlinkage void __cpuinit secondary_start_kernel(void)
        local_irq_enable();
        local_fiq_enable();
 
+       /*
+        * Setup local timer for this CPU.
+        */
+       local_timer_setup(cpu);
+
        calibrate_delay();
 
        smp_store_cpu_info(cpu);
@@ -299,11 +304,6 @@ asmlinkage void __cpuinit secondary_start_kernel(void)
         */
        cpu_set(cpu, cpu_online_map);
 
-       /*
-        * Setup local timer for this CPU.
-        */
-       local_timer_setup(cpu);
-
        /*
         * OK, it's off to the idle thread for us
         */
@@ -454,6 +454,27 @@ int smp_call_function(void (*func)(void *info), void *info, int retry,
 }
 EXPORT_SYMBOL_GPL(smp_call_function);
 
+int smp_call_function_single(int cpu, void (*func)(void *info), void *info,
+                            int retry, int wait)
+{
+       /* prevent preemption and reschedule on another processor */
+       int current_cpu = get_cpu();
+       int ret = 0;
+
+       if (cpu == current_cpu) {
+               local_irq_disable();
+               func(info);
+               local_irq_enable();
+       } else
+               ret = smp_call_function_on_cpu(func, info, retry, wait,
+                                              cpumask_of_cpu(cpu));
+
+       put_cpu();
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(smp_call_function_single);
+
 void show_ipi_list(struct seq_file *p)
 {
        unsigned int cpu;
@@ -481,8 +502,7 @@ void show_local_irqs(struct seq_file *p)
 static void ipi_timer(void)
 {
        irq_enter();
-       profile_tick(CPU_PROFILING);
-       update_process_times(user_mode(get_irq_regs()));
+       local_timer_interrupt();
        irq_exit();
 }
 
@@ -621,6 +641,11 @@ void smp_send_timer(void)
        send_ipi_message(mask, IPI_TIMER);
 }
 
+void smp_timer_broadcast(cpumask_t mask)
+{
+       send_ipi_message(mask, IPI_TIMER);
+}
+
 void smp_send_stop(void)
 {
        cpumask_t mask = cpu_online_map;
index 5b0422cdde76e7504010d8b4a8971ef3d0ca7455..074dcd5d9a7ef185d4f81d80538f5744fa440e89 100644 (file)
@@ -253,6 +253,36 @@ config AT91_TIMER_HZ
          system clock (of at least several MHz), rounding is less of a
          problem so it can be safer to use a decimal values like 100.
 
+choice
+       prompt "Select a UART for early kernel messages"
+
+config AT91_EARLY_DBGU
+       bool "DBGU"
+
+config AT91_EARLY_USART0
+       bool "USART0"
+
+config AT91_EARLY_USART1
+       bool "USART1"
+
+config AT91_EARLY_USART2
+       bool "USART2"
+       depends on ! ARCH_AT91X40
+
+config AT91_EARLY_USART3
+       bool "USART3"
+       depends on (ARCH_AT91RM9200 || ARCH_AT91SAM9RL || ARCH_AT91SAM9260)
+
+config AT91_EARLY_USART4
+       bool "USART4"
+       depends on ARCH_AT91SAM9260
+
+config AT91_EARLY_USART5
+       bool "USART5"
+       depends on ARCH_AT91SAM9260
+
+endchoice
+
 endmenu
 
 endif
index 5c090c9442f5ee1ba43f6783a417a7ee0c194190..e38d237709928d2e17fc5f2fb693d96e05bdc050 100644 (file)
@@ -49,8 +49,6 @@ static irqreturn_t at91sam926x_timer_interrupt(int irq, void *dev_id)
        volatile long nr_ticks;
 
        if (at91_sys_read(AT91_PIT_SR) & AT91_PIT_PITS) {       /* This is a shared interrupt */
-               write_seqlock(&xtime_lock);
-
                /* Get number to ticks performed before interrupt and clear PIT interrupt */
                nr_ticks = PIT_PICNT(at91_sys_read(AT91_PIT_PIVR));
                do {
@@ -58,7 +56,6 @@ static irqreturn_t at91sam926x_timer_interrupt(int irq, void *dev_id)
                        nr_ticks--;
                } while (nr_ticks);
 
-               write_sequnlock(&xtime_lock);
                return IRQ_HANDLED;
        } else
                return IRQ_NONE;                /* not handled */
index b5daf7f5e011a797cc6b88f75ae9b9170a451174..7b9ce7a336b0ad897ec21fe0ff956598e8f5a867 100644 (file)
@@ -47,6 +47,9 @@ extern void at91_irq_resume(void);
 #define AT91RM9200_BGA         4       /* AT91RM9200 BGA package has 4 banks */
 
 struct at91_gpio_bank {
+       unsigned chipbase;              /* bank's first GPIO number */
+       void __iomem *regbase;          /* base of register bank */
+       struct at91_gpio_bank *next;    /* bank sharing same IRQ/clock/... */
        unsigned short id;              /* peripheral ID */
        unsigned long offset;           /* offset from system peripheral base */
        struct clk *clock;              /* associated clock */
index 6aeddd68d8af040e048489d4ebff70fa94a79663..f629c2b5f0c544bbec401964e6f7c13550e1e851 100644 (file)
@@ -33,12 +33,10 @@ static int gpio_banks;
 
 static inline void __iomem *pin_to_controller(unsigned pin)
 {
-       void __iomem *sys_base = (void __iomem *) AT91_VA_BASE_SYS;
-
        pin -= PIN_BASE;
        pin /= 32;
        if (likely(pin < gpio_banks))
-               return sys_base + gpio[pin].offset;
+               return gpio[pin].regbase;
 
        return NULL;
 }
@@ -294,11 +292,11 @@ void at91_gpio_suspend(void)
        int i;
 
        for (i = 0; i < gpio_banks; i++) {
-               u32 pio = gpio[i].offset;
+               void __iomem    *pio = gpio[i].regbase;
 
-               backups[i] = at91_sys_read(pio + PIO_IMR);
-               at91_sys_write(pio + PIO_IDR, backups[i]);
-               at91_sys_write(pio + PIO_IER, wakeups[i]);
+               backups[i] = __raw_readl(pio + PIO_IMR);
+               __raw_writel(backups[i], pio + PIO_IDR);
+               __raw_writel(wakeups[i], pio + PIO_IER);
 
                if (!wakeups[i])
                        clk_disable(gpio[i].clock);
@@ -315,13 +313,13 @@ void at91_gpio_resume(void)
        int i;
 
        for (i = 0; i < gpio_banks; i++) {
-               u32 pio = gpio[i].offset;
+               void __iomem    *pio = gpio[i].regbase;
 
                if (!wakeups[i])
                        clk_enable(gpio[i].clock);
 
-               at91_sys_write(pio + PIO_IDR, wakeups[i]);
-               at91_sys_write(pio + PIO_IER, backups[i]);
+               __raw_writel(wakeups[i], pio + PIO_IDR);
+               __raw_writel(backups[i], pio + PIO_IER);
        }
 }
 
@@ -361,7 +359,13 @@ static void gpio_irq_unmask(unsigned pin)
 
 static int gpio_irq_type(unsigned pin, unsigned type)
 {
-       return (type == IRQT_BOTHEDGE) ? 0 : -EINVAL;
+       switch (type) {
+       case IRQ_TYPE_NONE:
+       case IRQ_TYPE_EDGE_BOTH:
+               return 0;
+       default:
+               return -EINVAL;
+       }
 }
 
 static struct irq_chip gpio_irqchip = {
@@ -376,20 +380,30 @@ static void gpio_irq_handler(unsigned irq, struct irq_desc *desc)
 {
        unsigned        pin;
        struct irq_desc *gpio;
+       struct at91_gpio_bank *bank;
        void __iomem    *pio;
        u32             isr;
 
-       pio = get_irq_chip_data(irq);
+       bank = get_irq_chip_data(irq);
+       pio = bank->regbase;
 
        /* temporarily mask (level sensitive) parent IRQ */
        desc->chip->ack(irq);
        for (;;) {
-               /* reading ISR acks the pending (edge triggered) GPIO interrupt */
+               /* Reading ISR acks pending (edge triggered) GPIO interrupts.
+                * When there none are pending, we're finished unless we need
+                * to process multiple banks (like ID_PIOCDE on sam9263).
+                */
                isr = __raw_readl(pio + PIO_ISR) & __raw_readl(pio + PIO_IMR);
-               if (!isr)
-                       break;
+               if (!isr) {
+                       if (!bank->next)
+                               break;
+                       bank = bank->next;
+                       pio = bank->regbase;
+                       continue;
+               }
 
-               pin = (unsigned) get_irq_data(irq);
+               pin = bank->chipbase;
                gpio = &irq_desc[pin];
 
                while (isr) {
@@ -481,24 +495,21 @@ postcore_initcall(at91_gpio_debugfs_init);
  */
 void __init at91_gpio_irq_setup(void)
 {
-       unsigned        pioc, pin;
+       unsigned                pioc, pin;
+       struct at91_gpio_bank   *this, *prev;
 
-       for (pioc = 0, pin = PIN_BASE;
-                       pioc < gpio_banks;
-                       pioc++) {
-               void __iomem    *controller;
-               unsigned        id = gpio[pioc].id;
+       for (pioc = 0, pin = PIN_BASE, this = gpio, prev = NULL;
+                       pioc++ < gpio_banks;
+                       prev = this, this++) {
+               unsigned        id = this->id;
                unsigned        i;
 
-               clk_enable(gpio[pioc].clock);   /* enable PIO controller's clock */
-
-               controller = (void __iomem *) AT91_VA_BASE_SYS + gpio[pioc].offset;
-               __raw_writel(~0, controller + PIO_IDR);
+               /* enable PIO controller's clock */
+               clk_enable(this->clock);
 
-               set_irq_data(id, (void *) pin);
-               set_irq_chip_data(id, controller);
+               __raw_writel(~0, this->regbase + PIO_IDR);
 
-               for (i = 0; i < 32; i++, pin++) {
+               for (i = 0, pin = this->chipbase; i < 32; i++, pin++) {
                        /*
                         * Can use the "simple" and not "edge" handler since it's
                         * shorter, and the AIC handles interrupts sanely.
@@ -508,6 +519,14 @@ void __init at91_gpio_irq_setup(void)
                        set_irq_flags(pin, IRQF_VALID);
                }
 
+               /* The toplevel handler handles one bank of GPIOs, except
+                * AT91SAM9263_ID_PIOCDE handles three... PIOC is first in
+                * the list, so we only set up that handler.
+                */
+               if (prev && prev->next == this)
+                       continue;
+
+               set_irq_chip_data(id, this);
                set_irq_chained_handler(id, gpio_irq_handler);
        }
        pr_info("AT91: %d gpio irqs in %d banks\n", pin - PIN_BASE, gpio_banks);
@@ -518,8 +537,20 @@ void __init at91_gpio_irq_setup(void)
  */
 void __init at91_gpio_init(struct at91_gpio_bank *data, int nr_banks)
 {
+       unsigned                i;
+       struct at91_gpio_bank   *last;
+
        BUG_ON(nr_banks > MAX_GPIO_BANKS);
 
        gpio = data;
        gpio_banks = nr_banks;
+
+       for (i = 0, last = NULL; i < nr_banks; i++, last = data, data++) {
+               data->chipbase = PIN_BASE + i * 32;
+               data->regbase = data->offset + (void __iomem *)AT91_VA_BASE_SYS;
+
+               /* AT91SAM9263_ID_PIOCDE groups PIOC, PIOD, PIOE */
+               if (last && last->id == data->id)
+                       last->next = data;
+       }
 }
index 4b120cc361359760a542eaea0825365bba5e6b33..a67defd504387a2fc610be020695323947b60333 100644 (file)
@@ -52,7 +52,7 @@ static suspend_state_t target_state;
 /*
  * Called after processes are frozen, but before we shutdown devices.
  */
-static int at91_pm_set_target(suspend_state_t state)
+static int at91_pm_begin(suspend_state_t state)
 {
        target_state = state;
        return 0;
@@ -202,11 +202,20 @@ error:
        return 0;
 }
 
+/*
+ * Called right prior to thawing processes.
+ */
+static void at91_pm_end(void)
+{
+       target_state = PM_SUSPEND_ON;
+}
+
 
 static struct platform_suspend_ops at91_pm_ops ={
-       .valid          = at91_pm_valid_state,
-       .set_target     = at91_pm_set_target,
-       .enter          = at91_pm_enter,
+       .valid  = at91_pm_valid_state,
+       .begin  = at91_pm_begin,
+       .enter  = at91_pm_enter,
+       .end    = at91_pm_end,
 };
 
 static int __init at91_pm_init(void)
index 61b2dfcb89d623dd401cd8226ec2d66bbf939690..e774447c059285e27edb9c2612f7c116218ad486 100644 (file)
@@ -189,6 +189,20 @@ config IXP4XX_INDIRECT_PCI
          need to use the indirect method instead. If you don't know
          what you need, leave this option unselected.
 
+config IXP4XX_QMGR
+       tristate "IXP4xx Queue Manager support"
+       help
+         This driver supports IXP4xx built-in hardware queue manager
+         and is automatically selected by Ethernet and HSS drivers.
+
+config IXP4XX_NPE
+       tristate "IXP4xx Network Processor Engine support"
+       select HOTPLUG
+       select FW_LOADER
+       help
+         This driver supports IXP4xx built-in network coprocessors
+         and is automatically selected by Ethernet and HSS drivers.
+
 endmenu
 
 endif
index 77e00ade558589297aaa425558958a66a61fbffb..c1956882c48b0043a1944a2a5810bd0ed3cb5656 100644 (file)
@@ -23,10 +23,12 @@ obj-$(CONFIG_MACH_AVILA)    += avila-setup.o
 obj-$(CONFIG_MACH_IXDPG425)    += coyote-setup.o
 obj-$(CONFIG_ARCH_ADI_COYOTE)  += coyote-setup.o
 obj-$(CONFIG_MACH_GTWX5715)    += gtwx5715-setup.o
-obj-$(CONFIG_MACH_NSLU2)       += nslu2-setup.o nslu2-power.o
-obj-$(CONFIG_MACH_NAS100D)     += nas100d-setup.o nas100d-power.o
-obj-$(CONFIG_MACH_DSMG600)      += dsmg600-setup.o dsmg600-power.o
+obj-$(CONFIG_MACH_NSLU2)       += nslu2-setup.o
+obj-$(CONFIG_MACH_NAS100D)     += nas100d-setup.o
+obj-$(CONFIG_MACH_DSMG600)      += dsmg600-setup.o
 obj-$(CONFIG_MACH_GATEWAY7001) += gateway7001-setup.o
 obj-$(CONFIG_MACH_WG302V2)     += wg302v2-setup.o
 
 obj-$(CONFIG_PCI)              += $(obj-pci-$(CONFIG_PCI)) common-pci.o
+obj-$(CONFIG_IXP4XX_QMGR)      += ixp4xx_qmgr.o
+obj-$(CONFIG_IXP4XX_NPE)       += ixp4xx_npe.o
diff --git a/arch/arm/mach-ixp4xx/dsmg600-power.c b/arch/arm/mach-ixp4xx/dsmg600-power.c
deleted file mode 100644 (file)
index 3471787..0000000
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * arch/arm/mach-ixp4xx/dsmg600-power.c
- *
- * DSM-G600 Power/Reset driver
- * Author: Michael Westerhof <mwester@dls.net>
- *
- * Based on nslu2-power.c
- *  Copyright (C) 2005 Tower Technologies
- *  Author: Alessandro Zummo <a.zummo@towertech.it>
- *
- * which was based on nslu2-io.c
- *  Copyright (C) 2004 Karen Spearel
- *
- * Maintainers: http://www.nslu2-linux.org/
- *
- * 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/module.h>
-#include <linux/reboot.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/jiffies.h>
-#include <linux/timer.h>
-
-#include <asm/mach-types.h>
-
-extern void ctrl_alt_del(void);
-
-/* This is used to make sure the power-button pusher is serious.  The button
- * must be held until the value of this counter reaches zero.
- */
-static volatile int power_button_countdown;
-
-/* Must hold the button down for at least this many counts to be processed */
-#define PBUTTON_HOLDDOWN_COUNT 4 /* 2 secs */
-
-static void dsmg600_power_handler(unsigned long data);
-static DEFINE_TIMER(dsmg600_power_timer, dsmg600_power_handler, 0, 0);
-
-static void dsmg600_power_handler(unsigned long data)
-{
-       /* This routine is called twice per second to check the
-        * state of the power button.
-        */
-
-       if (*IXP4XX_GPIO_GPINR & DSMG600_PB_BM) {
-
-               /* IO Pin is 1 (button pushed) */
-               if (power_button_countdown == 0) {
-                       /* Signal init to do the ctrlaltdel action, this will bypass
-                        * init if it hasn't started and do a kernel_restart.
-                        */
-                       ctrl_alt_del();
-
-                       /* Change the state of the power LED to "blink" */
-                       gpio_line_set(DSMG600_LED_PWR_GPIO, IXP4XX_GPIO_LOW);
-               }
-               power_button_countdown--;
-
-       } else {
-               power_button_countdown = PBUTTON_HOLDDOWN_COUNT;
-       }
-
-       mod_timer(&dsmg600_power_timer, jiffies + msecs_to_jiffies(500));
-}
-
-static irqreturn_t dsmg600_reset_handler(int irq, void *dev_id)
-{
-       /* This is the paper-clip reset, it shuts the machine down directly. */
-       machine_power_off();
-
-       return IRQ_HANDLED;
-}
-
-static int __init dsmg600_power_init(void)
-{
-       if (!(machine_is_dsmg600()))
-               return 0;
-
-       if (request_irq(DSMG600_RB_IRQ, &dsmg600_reset_handler,
-               IRQF_DISABLED | IRQF_TRIGGER_LOW, "DSM-G600 reset button",
-               NULL) < 0) {
-
-               printk(KERN_DEBUG "Reset Button IRQ %d not available\n",
-                       DSMG600_RB_IRQ);
-
-               return -EIO;
-       }
-
-       /* The power button on the D-Link DSM-G600 is on GPIO 15, but
-        * it cannot handle interrupts on that GPIO line.  So we'll
-        * have to poll it with a kernel timer.
-        */
-
-       /* Make sure that the power button GPIO is set up as an input */
-       gpio_line_config(DSMG600_PB_GPIO, IXP4XX_GPIO_IN);
-
-       /* Set the initial value for the power button IRQ handler */
-       power_button_countdown = PBUTTON_HOLDDOWN_COUNT;
-
-       mod_timer(&dsmg600_power_timer, jiffies + msecs_to_jiffies(500));
-
-       return 0;
-}
-
-static void __exit dsmg600_power_exit(void)
-{
-       if (!(machine_is_dsmg600()))
-               return;
-
-       del_timer_sync(&dsmg600_power_timer);
-
-       free_irq(DSMG600_RB_IRQ, NULL);
-}
-
-module_init(dsmg600_power_init);
-module_exit(dsmg600_power_exit);
-
-MODULE_AUTHOR("Michael Westerhof <mwester@dls.net>");
-MODULE_DESCRIPTION("DSM-G600 Power/Reset driver");
-MODULE_LICENSE("GPL");
index c473d408aa7c10b64ab3cf4ee8156c45a2833946..688659668bdf12156627f7780057ae76c6e9b5fb 100644 (file)
@@ -1,25 +1,37 @@
 /*
  * DSM-G600 board-setup
  *
+ * Copyright (C) 2008 Rod Whitby <rod@whitby.id.au>
  * Copyright (C) 2006 Tower Technologies
- * Author: Alessandro Zummo <a.zummo@towertech.it>
  *
- * based ixdp425-setup.c:
+ * based on ixdp425-setup.c:
  *      Copyright (C) 2003-2004 MontaVista Software, Inc.
+ * based on nslu2-power.c:
+ *     Copyright (C) 2005 Tower Technologies
+ * based on nslu2-io.c:
+ *     Copyright (C) 2004 Karen Spearel
  *
  * Author: Alessandro Zummo <a.zummo@towertech.it>
+ * Author: Michael Westerhof <mwester@dls.net>
+ * Author: Rod Whitby <rod@whitby.id.au>
  * Maintainers: http://www.nslu2-linux.org/
  */
 
-#include <linux/kernel.h>
+#include <linux/irq.h>
+#include <linux/jiffies.h>
+#include <linux/timer.h>
 #include <linux/serial.h>
 #include <linux/serial_8250.h>
+#include <linux/leds.h>
+#include <linux/reboot.h>
+#include <linux/i2c.h>
 #include <linux/i2c-gpio.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/flash.h>
 #include <asm/mach/time.h>
+#include <asm/gpio.h>
 
 static struct flash_platform_data dsmg600_flash_data = {
        .map_name               = "cfi_probe",
@@ -51,29 +63,34 @@ static struct platform_device dsmg600_i2c_gpio = {
        },
 };
 
-#ifdef CONFIG_LEDS_CLASS
-static struct resource dsmg600_led_resources[] = {
+static struct i2c_board_info __initdata dsmg600_i2c_board_info [] = {
+       {
+               I2C_BOARD_INFO("rtc-pcf8563", 0x51),
+       },
+};
+
+static struct gpio_led dsmg600_led_pins[] = {
        {
-               .name           = "power",
-               .start          = DSMG600_LED_PWR_GPIO,
-               .end            = DSMG600_LED_PWR_GPIO,
-               .flags          = IXP4XX_GPIO_HIGH,
+               .name           = "power",
+               .gpio           = DSMG600_LED_PWR_GPIO,
        },
        {
-               .name           = "wlan",
-               .start          = DSMG600_LED_WLAN_GPIO,
-               .end            = DSMG600_LED_WLAN_GPIO,
-               .flags          = IXP4XX_GPIO_LOW,
+               .name           = "wlan",
+               .gpio           = DSMG600_LED_WLAN_GPIO,
+               .active_low     = true,
        },
 };
 
+static struct gpio_led_platform_data dsmg600_led_data = {
+       .num_leds               = ARRAY_SIZE(dsmg600_led_pins),
+       .leds                   = dsmg600_led_pins,
+};
+
 static struct platform_device dsmg600_leds = {
-        .name                   = "IXP4XX-GPIO-LED",
-        .id                     = -1,
-        .num_resources          = ARRAY_SIZE(dsmg600_led_resources),
-        .resource               = dsmg600_led_resources,
+       .name                   = "leds-gpio",
+       .id                     = -1,
+       .dev.platform_data      = &dsmg600_led_data,
 };
-#endif
 
 static struct resource dsmg600_uart_resources[] = {
        {
@@ -121,6 +138,7 @@ static struct platform_device dsmg600_uart = {
 static struct platform_device *dsmg600_devices[] __initdata = {
        &dsmg600_i2c_gpio,
        &dsmg600_flash,
+       &dsmg600_leds,
 };
 
 static void dsmg600_power_off(void)
@@ -132,6 +150,57 @@ static void dsmg600_power_off(void)
        gpio_line_set(DSMG600_PO_GPIO, IXP4XX_GPIO_HIGH);
 }
 
+/* This is used to make sure the power-button pusher is serious.  The button
+ * must be held until the value of this counter reaches zero.
+ */
+static int power_button_countdown;
+
+/* Must hold the button down for at least this many counts to be processed */
+#define PBUTTON_HOLDDOWN_COUNT 4 /* 2 secs */
+
+static void dsmg600_power_handler(unsigned long data);
+static DEFINE_TIMER(dsmg600_power_timer, dsmg600_power_handler, 0, 0);
+
+static void dsmg600_power_handler(unsigned long data)
+{
+       /* This routine is called twice per second to check the
+        * state of the power button.
+        */
+
+       if (gpio_get_value(DSMG600_PB_GPIO)) {
+
+               /* IO Pin is 1 (button pushed) */
+               if (power_button_countdown > 0)
+                       power_button_countdown--;
+
+       } else {
+
+               /* Done on button release, to allow for auto-power-on mods. */
+               if (power_button_countdown == 0) {
+                       /* Signal init to do the ctrlaltdel action,
+                        * this will bypass init if it hasn't started
+                        * and do a kernel_restart.
+                        */
+                       ctrl_alt_del();
+
+                       /* Change the state of the power LED to "blink" */
+                       gpio_line_set(DSMG600_LED_PWR_GPIO, IXP4XX_GPIO_LOW);
+               } else {
+                       power_button_countdown = PBUTTON_HOLDDOWN_COUNT;
+               }
+       }
+
+       mod_timer(&dsmg600_power_timer, jiffies + msecs_to_jiffies(500));
+}
+
+static irqreturn_t dsmg600_reset_handler(int irq, void *dev_id)
+{
+       /* This is the paper-clip reset, it shuts the machine down directly. */
+       machine_power_off();
+
+       return IRQ_HANDLED;
+}
+
 static void __init dsmg600_timer_init(void)
 {
     /* The xtal on this machine is non-standard. */
@@ -156,7 +225,8 @@ static void __init dsmg600_init(void)
        dsmg600_flash_resource.end =
                IXP4XX_EXP_BUS_BASE(0) + ixp4xx_exp_bus_size - 1;
 
-       pm_power_off = dsmg600_power_off;
+       i2c_register_board_info(0, dsmg600_i2c_board_info,
+                               ARRAY_SIZE(dsmg600_i2c_board_info));
 
        /* The UART is required on the DSM-G600 (Redboot cannot use the
         * NIC) -- do it here so that it does *not* get removed if
@@ -166,10 +236,28 @@ static void __init dsmg600_init(void)
 
        platform_add_devices(dsmg600_devices, ARRAY_SIZE(dsmg600_devices));
 
-#ifdef CONFIG_LEDS_CLASS
-        /* We don't care whether or not this works. */
-        (void)platform_device_register(&dsmg600_leds);
-#endif
+       pm_power_off = dsmg600_power_off;
+
+       if (request_irq(gpio_to_irq(DSMG600_RB_GPIO), &dsmg600_reset_handler,
+               IRQF_DISABLED | IRQF_TRIGGER_LOW,
+               "DSM-G600 reset button", NULL) < 0) {
+
+               printk(KERN_DEBUG "Reset Button IRQ %d not available\n",
+                       gpio_to_irq(DSMG600_RB_GPIO));
+       }
+
+       /* The power button on the D-Link DSM-G600 is on GPIO 15, but
+        * it cannot handle interrupts on that GPIO line.  So we'll
+        * have to poll it with a kernel timer.
+        */
+
+       /* Make sure that the power button GPIO is set up as an input */
+       gpio_line_config(DSMG600_PB_GPIO, IXP4XX_GPIO_IN);
+
+       /* Set the initial value for the power button IRQ handler */
+       power_button_countdown = PBUTTON_HOLDDOWN_COUNT;
+
+       mod_timer(&dsmg600_power_timer, jiffies + msecs_to_jiffies(500));
 }
 
 MACHINE_START(DSMG600, "D-Link DSM-G600 RevA")
index e89070da28bfb73afa135f6819a64ca0ec0d4549..44584afb34a3778ff70615f7954d9cf24cfd1a83 100644 (file)
@@ -177,6 +177,31 @@ static struct platform_device ixdp425_uart = {
        .resource               = ixdp425_uart_resources
 };
 
+/* Built-in 10/100 Ethernet MAC interfaces */
+static struct eth_plat_info ixdp425_plat_eth[] = {
+       {
+               .phy            = 0,
+               .rxq            = 3,
+               .txreadyq       = 20,
+       }, {
+               .phy            = 1,
+               .rxq            = 4,
+               .txreadyq       = 21,
+       }
+};
+
+static struct platform_device ixdp425_eth[] = {
+       {
+               .name                   = "ixp4xx_eth",
+               .id                     = IXP4XX_ETH_NPEB,
+               .dev.platform_data      = ixdp425_plat_eth,
+       }, {
+               .name                   = "ixp4xx_eth",
+               .id                     = IXP4XX_ETH_NPEC,
+               .dev.platform_data      = ixdp425_plat_eth + 1,
+       }
+};
+
 static struct platform_device *ixdp425_devices[] __initdata = {
        &ixdp425_i2c_gpio,
        &ixdp425_flash,
@@ -184,7 +209,9 @@ static struct platform_device *ixdp425_devices[] __initdata = {
     defined(CONFIG_MTD_NAND_PLATFORM_MODULE)
        &ixdp425_flash_nand,
 #endif
-       &ixdp425_uart
+       &ixdp425_uart,
+       &ixdp425_eth[0],
+       &ixdp425_eth[1],
 };
 
 static void __init ixdp425_init(void)
diff --git a/arch/arm/mach-ixp4xx/ixp4xx_npe.c b/arch/arm/mach-ixp4xx/ixp4xx_npe.c
new file mode 100644 (file)
index 0000000..83c137e
--- /dev/null
@@ -0,0 +1,741 @@
+/*
+ * Intel IXP4xx Network Processor Engine driver for Linux
+ *
+ * Copyright (C) 2007 Krzysztof Halasa <khc@pm.waw.pl>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ *
+ * The code is based on publicly available information:
+ * - Intel IXP4xx Developer's Manual and other e-papers
+ * - Intel IXP400 Access Library Software (BSD license)
+ * - previous works by Christian Hohnstaedt <chohnstaedt@innominate.com>
+ *   Thanks, Christian.
+ */
+
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/firmware.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <asm/arch/npe.h>
+
+#define DEBUG_MSG                      0
+#define DEBUG_FW                       0
+
+#define NPE_COUNT                      3
+#define MAX_RETRIES                    1000    /* microseconds */
+#define NPE_42X_DATA_SIZE              0x800   /* in dwords */
+#define NPE_46X_DATA_SIZE              0x1000
+#define NPE_A_42X_INSTR_SIZE           0x1000
+#define NPE_B_AND_C_42X_INSTR_SIZE     0x800
+#define NPE_46X_INSTR_SIZE             0x1000
+#define REGS_SIZE                      0x1000
+
+#define NPE_PHYS_REG                   32
+
+#define FW_MAGIC                       0xFEEDF00D
+#define FW_BLOCK_TYPE_INSTR            0x0
+#define FW_BLOCK_TYPE_DATA             0x1
+#define FW_BLOCK_TYPE_EOF              0xF
+
+/* NPE exec status (read) and command (write) */
+#define CMD_NPE_STEP                   0x01
+#define CMD_NPE_START                  0x02
+#define CMD_NPE_STOP                   0x03
+#define CMD_NPE_CLR_PIPE               0x04
+#define CMD_CLR_PROFILE_CNT            0x0C
+#define CMD_RD_INS_MEM                 0x10 /* instruction memory */
+#define CMD_WR_INS_MEM                 0x11
+#define CMD_RD_DATA_MEM                        0x12 /* data memory */
+#define CMD_WR_DATA_MEM                        0x13
+#define CMD_RD_ECS_REG                 0x14 /* exec access register */
+#define CMD_WR_ECS_REG                 0x15
+
+#define STAT_RUN                       0x80000000
+#define STAT_STOP                      0x40000000
+#define STAT_CLEAR                     0x20000000
+#define STAT_ECS_K                     0x00800000 /* pipeline clean */
+
+#define NPE_STEVT                      0x1B
+#define NPE_STARTPC                    0x1C
+#define NPE_REGMAP                     0x1E
+#define NPE_CINDEX                     0x1F
+
+#define INSTR_WR_REG_SHORT             0x0000C000
+#define INSTR_WR_REG_BYTE              0x00004000
+#define INSTR_RD_FIFO                  0x0F888220
+#define INSTR_RESET_MBOX               0x0FAC8210
+
+#define ECS_BG_CTXT_REG_0              0x00 /* Background Executing Context */
+#define ECS_BG_CTXT_REG_1              0x01 /*         Stack level */
+#define ECS_BG_CTXT_REG_2              0x02
+#define ECS_PRI_1_CTXT_REG_0           0x04 /* Priority 1 Executing Context */
+#define ECS_PRI_1_CTXT_REG_1           0x05 /*         Stack level */
+#define ECS_PRI_1_CTXT_REG_2           0x06
+#define ECS_PRI_2_CTXT_REG_0           0x08 /* Priority 2 Executing Context */
+#define ECS_PRI_2_CTXT_REG_1           0x09 /*         Stack level */
+#define ECS_PRI_2_CTXT_REG_2           0x0A
+#define ECS_DBG_CTXT_REG_0             0x0C /* Debug Executing Context */
+#define ECS_DBG_CTXT_REG_1             0x0D /*         Stack level */
+#define ECS_DBG_CTXT_REG_2             0x0E
+#define ECS_INSTRUCT_REG               0x11 /* NPE Instruction Register */
+
+#define ECS_REG_0_ACTIVE               0x80000000 /* all levels */
+#define ECS_REG_0_NEXTPC_MASK          0x1FFF0000 /* BG/PRI1/PRI2 levels */
+#define ECS_REG_0_LDUR_BITS            8
+#define ECS_REG_0_LDUR_MASK            0x00000700 /* all levels */
+#define ECS_REG_1_CCTXT_BITS           16
+#define ECS_REG_1_CCTXT_MASK           0x000F0000 /* all levels */
+#define ECS_REG_1_SELCTXT_BITS         0
+#define ECS_REG_1_SELCTXT_MASK         0x0000000F /* all levels */
+#define ECS_DBG_REG_2_IF               0x00100000 /* debug level */
+#define ECS_DBG_REG_2_IE               0x00080000 /* debug level */
+
+/* NPE watchpoint_fifo register bit */
+#define WFIFO_VALID                    0x80000000
+
+/* NPE messaging_status register bit definitions */
+#define MSGSTAT_OFNE   0x00010000 /* OutFifoNotEmpty */
+#define MSGSTAT_IFNF   0x00020000 /* InFifoNotFull */
+#define MSGSTAT_OFNF   0x00040000 /* OutFifoNotFull */
+#define MSGSTAT_IFNE   0x00080000 /* InFifoNotEmpty */
+#define MSGSTAT_MBINT  0x00100000 /* Mailbox interrupt */
+#define MSGSTAT_IFINT  0x00200000 /* InFifo interrupt */
+#define MSGSTAT_OFINT  0x00400000 /* OutFifo interrupt */
+#define MSGSTAT_WFINT  0x00800000 /* WatchFifo interrupt */
+
+/* NPE messaging_control register bit definitions */
+#define MSGCTL_OUT_FIFO                        0x00010000 /* enable output FIFO */
+#define MSGCTL_IN_FIFO                 0x00020000 /* enable input FIFO */
+#define MSGCTL_OUT_FIFO_WRITE          0x01000000 /* enable FIFO + WRITE */
+#define MSGCTL_IN_FIFO_WRITE           0x02000000
+
+/* NPE mailbox_status value for reset */
+#define RESET_MBOX_STAT                        0x0000F0F0
+
+const char *npe_names[] = { "NPE-A", "NPE-B", "NPE-C" };
+
+#define print_npe(pri, npe, fmt, ...)                                  \
+       printk(pri "%s: " fmt, npe_name(npe), ## __VA_ARGS__)
+
+#if DEBUG_MSG
+#define debug_msg(npe, fmt, ...)                                       \
+       print_npe(KERN_DEBUG, npe, fmt, ## __VA_ARGS__)
+#else
+#define debug_msg(npe, fmt, ...)
+#endif
+
+static struct {
+       u32 reg, val;
+} ecs_reset[] = {
+       { ECS_BG_CTXT_REG_0,    0xA0000000 },
+       { ECS_BG_CTXT_REG_1,    0x01000000 },
+       { ECS_BG_CTXT_REG_2,    0x00008000 },
+       { ECS_PRI_1_CTXT_REG_0, 0x20000080 },
+       { ECS_PRI_1_CTXT_REG_1, 0x01000000 },
+       { ECS_PRI_1_CTXT_REG_2, 0x00008000 },
+       { ECS_PRI_2_CTXT_REG_0, 0x20000080 },
+       { ECS_PRI_2_CTXT_REG_1, 0x01000000 },
+       { ECS_PRI_2_CTXT_REG_2, 0x00008000 },
+       { ECS_DBG_CTXT_REG_0,   0x20000000 },
+       { ECS_DBG_CTXT_REG_1,   0x00000000 },
+       { ECS_DBG_CTXT_REG_2,   0x001E0000 },
+       { ECS_INSTRUCT_REG,     0x1003C00F },
+};
+
+static struct npe npe_tab[NPE_COUNT] = {
+       {
+               .id     = 0,
+               .regs   = (struct npe_regs __iomem *)IXP4XX_NPEA_BASE_VIRT,
+               .regs_phys = IXP4XX_NPEA_BASE_PHYS,
+       }, {
+               .id     = 1,
+               .regs   = (struct npe_regs __iomem *)IXP4XX_NPEB_BASE_VIRT,
+               .regs_phys = IXP4XX_NPEB_BASE_PHYS,
+       }, {
+               .id     = 2,
+               .regs   = (struct npe_regs __iomem *)IXP4XX_NPEC_BASE_VIRT,
+               .regs_phys = IXP4XX_NPEC_BASE_PHYS,
+       }
+};
+
+int npe_running(struct npe *npe)
+{
+       return (__raw_readl(&npe->regs->exec_status_cmd) & STAT_RUN) != 0;
+}
+
+static void npe_cmd_write(struct npe *npe, u32 addr, int cmd, u32 data)
+{
+       __raw_writel(data, &npe->regs->exec_data);
+       __raw_writel(addr, &npe->regs->exec_addr);
+       __raw_writel(cmd, &npe->regs->exec_status_cmd);
+}
+
+static u32 npe_cmd_read(struct npe *npe, u32 addr, int cmd)
+{
+       __raw_writel(addr, &npe->regs->exec_addr);
+       __raw_writel(cmd, &npe->regs->exec_status_cmd);
+       /* Iintroduce extra read cycles after issuing read command to NPE
+          so that we read the register after the NPE has updated it.
+          This is to overcome race condition between XScale and NPE */
+       __raw_readl(&npe->regs->exec_data);
+       __raw_readl(&npe->regs->exec_data);
+       return __raw_readl(&npe->regs->exec_data);
+}
+
+static void npe_clear_active(struct npe *npe, u32 reg)
+{
+       u32 val = npe_cmd_read(npe, reg, CMD_RD_ECS_REG);
+       npe_cmd_write(npe, reg, CMD_WR_ECS_REG, val & ~ECS_REG_0_ACTIVE);
+}
+
+static void npe_start(struct npe *npe)
+{
+       /* ensure only Background Context Stack Level is active */
+       npe_clear_active(npe, ECS_PRI_1_CTXT_REG_0);
+       npe_clear_active(npe, ECS_PRI_2_CTXT_REG_0);
+       npe_clear_active(npe, ECS_DBG_CTXT_REG_0);
+
+       __raw_writel(CMD_NPE_CLR_PIPE, &npe->regs->exec_status_cmd);
+       __raw_writel(CMD_NPE_START, &npe->regs->exec_status_cmd);
+}
+
+static void npe_stop(struct npe *npe)
+{
+       __raw_writel(CMD_NPE_STOP, &npe->regs->exec_status_cmd);
+       __raw_writel(CMD_NPE_CLR_PIPE, &npe->regs->exec_status_cmd); /*FIXME?*/
+}
+
+static int __must_check npe_debug_instr(struct npe *npe, u32 instr, u32 ctx,
+                                       u32 ldur)
+{
+       u32 wc;
+       int i;
+
+       /* set the Active bit, and the LDUR, in the debug level */
+       npe_cmd_write(npe, ECS_DBG_CTXT_REG_0, CMD_WR_ECS_REG,
+                     ECS_REG_0_ACTIVE | (ldur << ECS_REG_0_LDUR_BITS));
+
+       /* set CCTXT at ECS DEBUG L3 to specify in which context to execute
+          the instruction, and set SELCTXT at ECS DEBUG Level to specify
+          which context store to access.
+          Debug ECS Level Reg 1 has form 0x000n000n, where n = context number
+       */
+       npe_cmd_write(npe, ECS_DBG_CTXT_REG_1, CMD_WR_ECS_REG,
+                     (ctx << ECS_REG_1_CCTXT_BITS) |
+                     (ctx << ECS_REG_1_SELCTXT_BITS));
+
+       /* clear the pipeline */
+       __raw_writel(CMD_NPE_CLR_PIPE, &npe->regs->exec_status_cmd);
+
+       /* load NPE instruction into the instruction register */
+       npe_cmd_write(npe, ECS_INSTRUCT_REG, CMD_WR_ECS_REG, instr);
+
+       /* we need this value later to wait for completion of NPE execution
+          step */
+       wc = __raw_readl(&npe->regs->watch_count);
+
+       /* issue a Step One command via the Execution Control register */
+       __raw_writel(CMD_NPE_STEP, &npe->regs->exec_status_cmd);
+
+       /* Watch Count register increments when NPE completes an instruction */
+       for (i = 0; i < MAX_RETRIES; i++) {
+               if (wc != __raw_readl(&npe->regs->watch_count))
+                       return 0;
+               udelay(1);
+       }
+
+       print_npe(KERN_ERR, npe, "reset: npe_debug_instr(): timeout\n");
+       return -ETIMEDOUT;
+}
+
+static int __must_check npe_logical_reg_write8(struct npe *npe, u32 addr,
+                                              u8 val, u32 ctx)
+{
+       /* here we build the NPE assembler instruction: mov8 d0, #0 */
+       u32 instr = INSTR_WR_REG_BYTE | /* OpCode */
+               addr << 9 |             /* base Operand */
+               (val & 0x1F) << 4 |     /* lower 5 bits to immediate data */
+               (val & ~0x1F) << (18 - 5);/* higher 3 bits to CoProc instr. */
+       return npe_debug_instr(npe, instr, ctx, 1); /* execute it */
+}
+
+static int __must_check npe_logical_reg_write16(struct npe *npe, u32 addr,
+                                               u16 val, u32 ctx)
+{
+       /* here we build the NPE assembler instruction: mov16 d0, #0 */
+       u32 instr = INSTR_WR_REG_SHORT | /* OpCode */
+               addr << 9 |             /* base Operand */
+               (val & 0x1F) << 4 |     /* lower 5 bits to immediate data */
+               (val & ~0x1F) << (18 - 5);/* higher 11 bits to CoProc instr. */
+       return npe_debug_instr(npe, instr, ctx, 1); /* execute it */
+}
+
+static int __must_check npe_logical_reg_write32(struct npe *npe, u32 addr,
+                                               u32 val, u32 ctx)
+{
+       /* write in 16 bit steps first the high and then the low value */
+       if (npe_logical_reg_write16(npe, addr, val >> 16, ctx))
+               return -ETIMEDOUT;
+       return npe_logical_reg_write16(npe, addr + 2, val & 0xFFFF, ctx);
+}
+
+static int npe_reset(struct npe *npe)
+{
+       u32 val, ctl, exec_count, ctx_reg2;
+       int i;
+
+       ctl = (__raw_readl(&npe->regs->messaging_control) | 0x3F000000) &
+               0x3F3FFFFF;
+
+       /* disable parity interrupt */
+       __raw_writel(ctl & 0x3F00FFFF, &npe->regs->messaging_control);
+
+       /* pre exec - debug instruction */
+       /* turn off the halt bit by clearing Execution Count register. */
+       exec_count = __raw_readl(&npe->regs->exec_count);
+       __raw_writel(0, &npe->regs->exec_count);
+       /* ensure that IF and IE are on (temporarily), so that we don't end up
+          stepping forever */
+       ctx_reg2 = npe_cmd_read(npe, ECS_DBG_CTXT_REG_2, CMD_RD_ECS_REG);
+       npe_cmd_write(npe, ECS_DBG_CTXT_REG_2, CMD_WR_ECS_REG, ctx_reg2 |
+                     ECS_DBG_REG_2_IF | ECS_DBG_REG_2_IE);
+
+       /* clear the FIFOs */
+       while (__raw_readl(&npe->regs->watchpoint_fifo) & WFIFO_VALID)
+               ;
+       while (__raw_readl(&npe->regs->messaging_status) & MSGSTAT_OFNE)
+               /* read from the outFIFO until empty */
+               print_npe(KERN_DEBUG, npe, "npe_reset: read FIFO = 0x%X\n",
+                         __raw_readl(&npe->regs->in_out_fifo));
+
+       while (__raw_readl(&npe->regs->messaging_status) & MSGSTAT_IFNE)
+               /* step execution of the NPE intruction to read inFIFO using
+                  the Debug Executing Context stack */
+               if (npe_debug_instr(npe, INSTR_RD_FIFO, 0, 0))
+                       return -ETIMEDOUT;
+
+       /* reset the mailbox reg from the XScale side */
+       __raw_writel(RESET_MBOX_STAT, &npe->regs->mailbox_status);
+       /* from NPE side */
+       if (npe_debug_instr(npe, INSTR_RESET_MBOX, 0, 0))
+               return -ETIMEDOUT;
+
+       /* Reset the physical registers in the NPE register file */
+       for (val = 0; val < NPE_PHYS_REG; val++) {
+               if (npe_logical_reg_write16(npe, NPE_REGMAP, val >> 1, 0))
+                       return -ETIMEDOUT;
+               /* address is either 0 or 4 */
+               if (npe_logical_reg_write32(npe, (val & 1) * 4, 0, 0))
+                       return -ETIMEDOUT;
+       }
+
+       /* Reset the context store = each context's Context Store registers */
+
+       /* Context 0 has no STARTPC. Instead, this value is used to set NextPC
+          for Background ECS, to set where NPE starts executing code */
+       val = npe_cmd_read(npe, ECS_BG_CTXT_REG_0, CMD_RD_ECS_REG);
+       val &= ~ECS_REG_0_NEXTPC_MASK;
+       val |= (0 /* NextPC */ << 16) & ECS_REG_0_NEXTPC_MASK;
+       npe_cmd_write(npe, ECS_BG_CTXT_REG_0, CMD_WR_ECS_REG, val);
+
+       for (i = 0; i < 16; i++) {
+               if (i) {        /* Context 0 has no STEVT nor STARTPC */
+                       /* STEVT = off, 0x80 */
+                       if (npe_logical_reg_write8(npe, NPE_STEVT, 0x80, i))
+                               return -ETIMEDOUT;
+                       if (npe_logical_reg_write16(npe, NPE_STARTPC, 0, i))
+                               return -ETIMEDOUT;
+               }
+               /* REGMAP = d0->p0, d8->p2, d16->p4 */
+               if (npe_logical_reg_write16(npe, NPE_REGMAP, 0x820, i))
+                       return -ETIMEDOUT;
+               if (npe_logical_reg_write8(npe, NPE_CINDEX, 0, i))
+                       return -ETIMEDOUT;
+       }
+
+       /* post exec */
+       /* clear active bit in debug level */
+       npe_cmd_write(npe, ECS_DBG_CTXT_REG_0, CMD_WR_ECS_REG, 0);
+       /* clear the pipeline */
+       __raw_writel(CMD_NPE_CLR_PIPE, &npe->regs->exec_status_cmd);
+       /* restore previous values */
+       __raw_writel(exec_count, &npe->regs->exec_count);
+       npe_cmd_write(npe, ECS_DBG_CTXT_REG_2, CMD_WR_ECS_REG, ctx_reg2);
+
+       /* write reset values to Execution Context Stack registers */
+       for (val = 0; val < ARRAY_SIZE(ecs_reset); val++)
+               npe_cmd_write(npe, ecs_reset[val].reg, CMD_WR_ECS_REG,
+                             ecs_reset[val].val);
+
+       /* clear the profile counter */
+       __raw_writel(CMD_CLR_PROFILE_CNT, &npe->regs->exec_status_cmd);
+
+       __raw_writel(0, &npe->regs->exec_count);
+       __raw_writel(0, &npe->regs->action_points[0]);
+       __raw_writel(0, &npe->regs->action_points[1]);
+       __raw_writel(0, &npe->regs->action_points[2]);
+       __raw_writel(0, &npe->regs->action_points[3]);
+       __raw_writel(0, &npe->regs->watch_count);
+
+       val = ixp4xx_read_feature_bits();
+       /* reset the NPE */
+       ixp4xx_write_feature_bits(val &
+                                 ~(IXP4XX_FEATURE_RESET_NPEA << npe->id));
+       for (i = 0; i < MAX_RETRIES; i++) {
+               if (!(ixp4xx_read_feature_bits() &
+                     (IXP4XX_FEATURE_RESET_NPEA << npe->id)))
+                       break;  /* reset completed */
+               udelay(1);
+       }
+       if (i == MAX_RETRIES)
+               return -ETIMEDOUT;
+
+       /* deassert reset */
+       ixp4xx_write_feature_bits(val |
+                                 (IXP4XX_FEATURE_RESET_NPEA << npe->id));
+       for (i = 0; i < MAX_RETRIES; i++) {
+               if (ixp4xx_read_feature_bits() &
+                   (IXP4XX_FEATURE_RESET_NPEA << npe->id))
+                       break;  /* NPE is back alive */
+               udelay(1);
+       }
+       if (i == MAX_RETRIES)
+               return -ETIMEDOUT;
+
+       npe_stop(npe);
+
+       /* restore NPE configuration bus Control Register - parity settings */
+       __raw_writel(ctl, &npe->regs->messaging_control);
+       return 0;
+}
+
+
+int npe_send_message(struct npe *npe, const void *msg, const char *what)
+{
+       const u32 *send = msg;
+       int cycles = 0;
+
+       debug_msg(npe, "Trying to send message %s [%08X:%08X]\n",
+                 what, send[0], send[1]);
+
+       if (__raw_readl(&npe->regs->messaging_status) & MSGSTAT_IFNE) {
+               debug_msg(npe, "NPE input FIFO not empty\n");
+               return -EIO;
+       }
+
+       __raw_writel(send[0], &npe->regs->in_out_fifo);
+
+       if (!(__raw_readl(&npe->regs->messaging_status) & MSGSTAT_IFNF)) {
+               debug_msg(npe, "NPE input FIFO full\n");
+               return -EIO;
+       }
+
+       __raw_writel(send[1], &npe->regs->in_out_fifo);
+
+       while ((cycles < MAX_RETRIES) &&
+              (__raw_readl(&npe->regs->messaging_status) & MSGSTAT_IFNE)) {
+               udelay(1);
+               cycles++;
+       }
+
+       if (cycles == MAX_RETRIES) {
+               debug_msg(npe, "Timeout sending message\n");
+               return -ETIMEDOUT;
+       }
+
+       debug_msg(npe, "Sending a message took %i cycles\n", cycles);
+       return 0;
+}
+
+int npe_recv_message(struct npe *npe, void *msg, const char *what)
+{
+       u32 *recv = msg;
+       int cycles = 0, cnt = 0;
+
+       debug_msg(npe, "Trying to receive message %s\n", what);
+
+       while (cycles < MAX_RETRIES) {
+               if (__raw_readl(&npe->regs->messaging_status) & MSGSTAT_OFNE) {
+                       recv[cnt++] = __raw_readl(&npe->regs->in_out_fifo);
+                       if (cnt == 2)
+                               break;
+               } else {
+                       udelay(1);
+                       cycles++;
+               }
+       }
+
+       switch(cnt) {
+       case 1:
+               debug_msg(npe, "Received [%08X]\n", recv[0]);
+               break;
+       case 2:
+               debug_msg(npe, "Received [%08X:%08X]\n", recv[0], recv[1]);
+               break;
+       }
+
+       if (cycles == MAX_RETRIES) {
+               debug_msg(npe, "Timeout waiting for message\n");
+               return -ETIMEDOUT;
+       }
+
+       debug_msg(npe, "Receiving a message took %i cycles\n", cycles);
+       return 0;
+}
+
+int npe_send_recv_message(struct npe *npe, void *msg, const char *what)
+{
+       int result;
+       u32 *send = msg, recv[2];
+
+       if ((result = npe_send_message(npe, msg, what)) != 0)
+               return result;
+       if ((result = npe_recv_message(npe, recv, what)) != 0)
+               return result;
+
+       if ((recv[0] != send[0]) || (recv[1] != send[1])) {
+               debug_msg(npe, "Message %s: unexpected message received\n",
+                         what);
+               return -EIO;
+       }
+       return 0;
+}
+
+
+int npe_load_firmware(struct npe *npe, const char *name, struct device *dev)
+{
+       const struct firmware *fw_entry;
+
+       struct dl_block {
+               u32 type;
+               u32 offset;
+       } *blk;
+
+       struct dl_image {
+               u32 magic;
+               u32 id;
+               u32 size;
+               union {
+                       u32 data[0];
+                       struct dl_block blocks[0];
+               };
+       } *image;
+
+       struct dl_codeblock {
+               u32 npe_addr;
+               u32 size;
+               u32 data[0];
+       } *cb;
+
+       int i, j, err, data_size, instr_size, blocks, table_end;
+       u32 cmd;
+
+       if ((err = request_firmware(&fw_entry, name, dev)) != 0)
+               return err;
+
+       err = -EINVAL;
+       if (fw_entry->size < sizeof(struct dl_image)) {
+               print_npe(KERN_ERR, npe, "incomplete firmware file\n");
+               goto err;
+       }
+       image = (struct dl_image*)fw_entry->data;
+
+#if DEBUG_FW
+       print_npe(KERN_DEBUG, npe, "firmware: %08X %08X %08X (0x%X bytes)\n",
+                 image->magic, image->id, image->size, image->size * 4);
+#endif
+
+       if (image->magic == swab32(FW_MAGIC)) { /* swapped file */
+               image->id = swab32(image->id);
+               image->size = swab32(image->size);
+       } else if (image->magic != FW_MAGIC) {
+               print_npe(KERN_ERR, npe, "bad firmware file magic: 0x%X\n",
+                         image->magic);
+               goto err;
+       }
+       if ((image->size * 4 + sizeof(struct dl_image)) != fw_entry->size) {
+               print_npe(KERN_ERR, npe,
+                         "inconsistent size of firmware file\n");
+               goto err;
+       }
+       if (((image->id >> 24) & 0xF /* NPE ID */) != npe->id) {
+               print_npe(KERN_ERR, npe, "firmware file NPE ID mismatch\n");
+               goto err;
+       }
+       if (image->magic == swab32(FW_MAGIC))
+               for (i = 0; i < image->size; i++)
+                       image->data[i] = swab32(image->data[i]);
+
+       if (!cpu_is_ixp46x() && ((image->id >> 28) & 0xF /* device ID */)) {
+               print_npe(KERN_INFO, npe, "IXP46x firmware ignored on "
+                         "IXP42x\n");
+               goto err;
+       }
+
+       if (npe_running(npe)) {
+               print_npe(KERN_INFO, npe, "unable to load firmware, NPE is "
+                         "already running\n");
+               err = -EBUSY;
+               goto err;
+       }
+#if 0
+       npe_stop(npe);
+       npe_reset(npe);
+#endif
+
+       print_npe(KERN_INFO, npe, "firmware functionality 0x%X, "
+                 "revision 0x%X:%X\n", (image->id >> 16) & 0xFF,
+                 (image->id >> 8) & 0xFF, image->id & 0xFF);
+
+       if (!cpu_is_ixp46x()) {
+               if (!npe->id)
+                       instr_size = NPE_A_42X_INSTR_SIZE;
+               else
+                       instr_size = NPE_B_AND_C_42X_INSTR_SIZE;
+               data_size = NPE_42X_DATA_SIZE;
+       } else {
+               instr_size = NPE_46X_INSTR_SIZE;
+               data_size = NPE_46X_DATA_SIZE;
+       }
+
+       for (blocks = 0; blocks * sizeof(struct dl_block) / 4 < image->size;
+            blocks++)
+               if (image->blocks[blocks].type == FW_BLOCK_TYPE_EOF)
+                       break;
+       if (blocks * sizeof(struct dl_block) / 4 >= image->size) {
+               print_npe(KERN_INFO, npe, "firmware EOF block marker not "
+                         "found\n");
+               goto err;
+       }
+
+#if DEBUG_FW
+       print_npe(KERN_DEBUG, npe, "%i firmware blocks found\n", blocks);
+#endif
+
+       table_end = blocks * sizeof(struct dl_block) / 4 + 1 /* EOF marker */;
+       for (i = 0, blk = image->blocks; i < blocks; i++, blk++) {
+               if (blk->offset > image->size - sizeof(struct dl_codeblock) / 4
+                   || blk->offset < table_end) {
+                       print_npe(KERN_INFO, npe, "invalid offset 0x%X of "
+                                 "firmware block #%i\n", blk->offset, i);
+                       goto err;
+               }
+
+               cb = (struct dl_codeblock*)&image->data[blk->offset];
+               if (blk->type == FW_BLOCK_TYPE_INSTR) {
+                       if (cb->npe_addr + cb->size > instr_size)
+                               goto too_big;
+                       cmd = CMD_WR_INS_MEM;
+               } else if (blk->type == FW_BLOCK_TYPE_DATA) {
+                       if (cb->npe_addr + cb->size > data_size)
+                               goto too_big;
+                       cmd = CMD_WR_DATA_MEM;
+               } else {
+                       print_npe(KERN_INFO, npe, "invalid firmware block #%i "
+                                 "type 0x%X\n", i, blk->type);
+                       goto err;
+               }
+               if (blk->offset + sizeof(*cb) / 4 + cb->size > image->size) {
+                       print_npe(KERN_INFO, npe, "firmware block #%i doesn't "
+                                 "fit in firmware image: type %c, start 0x%X,"
+                                 " length 0x%X\n", i,
+                                 blk->type == FW_BLOCK_TYPE_INSTR ? 'I' : 'D',
+                                 cb->npe_addr, cb->size);
+                       goto err;
+               }
+
+               for (j = 0; j < cb->size; j++)
+                       npe_cmd_write(npe, cb->npe_addr + j, cmd, cb->data[j]);
+       }
+
+       npe_start(npe);
+       if (!npe_running(npe))
+               print_npe(KERN_ERR, npe, "unable to start\n");
+       release_firmware(fw_entry);
+       return 0;
+
+too_big:
+       print_npe(KERN_INFO, npe, "firmware block #%i doesn't fit in NPE "
+                 "memory: type %c, start 0x%X, length 0x%X\n", i,
+                 blk->type == FW_BLOCK_TYPE_INSTR ? 'I' : 'D',
+                 cb->npe_addr, cb->size);
+err:
+       release_firmware(fw_entry);
+       return err;
+}
+
+
+struct npe *npe_request(int id)
+{
+       if (id < NPE_COUNT)
+               if (npe_tab[id].valid)
+                       if (try_module_get(THIS_MODULE))
+                               return &npe_tab[id];
+       return NULL;
+}
+
+void npe_release(struct npe *npe)
+{
+       module_put(THIS_MODULE);
+}
+
+
+static int __init npe_init_module(void)
+{
+
+       int i, found = 0;
+
+       for (i = 0; i < NPE_COUNT; i++) {
+               struct npe *npe = &npe_tab[i];
+               if (!(ixp4xx_read_feature_bits() &
+                     (IXP4XX_FEATURE_RESET_NPEA << i)))
+                       continue; /* NPE already disabled or not present */
+               if (!(npe->mem_res = request_mem_region(npe->regs_phys,
+                                                       REGS_SIZE,
+                                                       npe_name(npe)))) {
+                       print_npe(KERN_ERR, npe,
+                                 "failed to request memory region\n");
+                       continue;
+               }
+
+               if (npe_reset(npe))
+                       continue;
+               npe->valid = 1;
+               found++;
+       }
+
+       if (!found)
+               return -ENOSYS;
+       return 0;
+}
+
+static void __exit npe_cleanup_module(void)
+{
+       int i;
+
+       for (i = 0; i < NPE_COUNT; i++)
+               if (npe_tab[i].mem_res) {
+                       npe_reset(&npe_tab[i]);
+                       release_resource(npe_tab[i].mem_res);
+               }
+}
+
+module_init(npe_init_module);
+module_exit(npe_cleanup_module);
+
+MODULE_AUTHOR("Krzysztof Halasa");
+MODULE_LICENSE("GPL v2");
+
+EXPORT_SYMBOL(npe_names);
+EXPORT_SYMBOL(npe_running);
+EXPORT_SYMBOL(npe_request);
+EXPORT_SYMBOL(npe_release);
+EXPORT_SYMBOL(npe_load_firmware);
+EXPORT_SYMBOL(npe_send_message);
+EXPORT_SYMBOL(npe_recv_message);
+EXPORT_SYMBOL(npe_send_recv_message);
diff --git a/arch/arm/mach-ixp4xx/ixp4xx_qmgr.c b/arch/arm/mach-ixp4xx/ixp4xx_qmgr.c
new file mode 100644 (file)
index 0000000..e833013
--- /dev/null
@@ -0,0 +1,274 @@
+/*
+ * Intel IXP4xx Queue Manager driver for Linux
+ *
+ * Copyright (C) 2007 Krzysztof Halasa <khc@pm.waw.pl>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ */
+
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <asm/arch/qmgr.h>
+
+#define DEBUG          0
+
+struct qmgr_regs __iomem *qmgr_regs;
+static struct resource *mem_res;
+static spinlock_t qmgr_lock;
+static u32 used_sram_bitmap[4]; /* 128 16-dword pages */
+static void (*irq_handlers[HALF_QUEUES])(void *pdev);
+static void *irq_pdevs[HALF_QUEUES];
+
+void qmgr_set_irq(unsigned int queue, int src,
+                 void (*handler)(void *pdev), void *pdev)
+{
+       u32 __iomem *reg = &qmgr_regs->irqsrc[queue / 8]; /* 8 queues / u32 */
+       int bit = (queue % 8) * 4; /* 3 bits + 1 reserved bit per queue */
+       unsigned long flags;
+
+       src &= 7;
+       spin_lock_irqsave(&qmgr_lock, flags);
+       __raw_writel((__raw_readl(reg) & ~(7 << bit)) | (src << bit), reg);
+       irq_handlers[queue] = handler;
+       irq_pdevs[queue] = pdev;
+       spin_unlock_irqrestore(&qmgr_lock, flags);
+}
+
+
+static irqreturn_t qmgr_irq1(int irq, void *pdev)
+{
+       int i;
+       u32 val = __raw_readl(&qmgr_regs->irqstat[0]);
+       __raw_writel(val, &qmgr_regs->irqstat[0]); /* ACK */
+
+       for (i = 0; i < HALF_QUEUES; i++)
+               if (val & (1 << i))
+                       irq_handlers[i](irq_pdevs[i]);
+
+       return val ? IRQ_HANDLED : 0;
+}
+
+
+void qmgr_enable_irq(unsigned int queue)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&qmgr_lock, flags);
+       __raw_writel(__raw_readl(&qmgr_regs->irqen[0]) | (1 << queue),
+                    &qmgr_regs->irqen[0]);
+       spin_unlock_irqrestore(&qmgr_lock, flags);
+}
+
+void qmgr_disable_irq(unsigned int queue)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&qmgr_lock, flags);
+       __raw_writel(__raw_readl(&qmgr_regs->irqen[0]) & ~(1 << queue),
+                    &qmgr_regs->irqen[0]);
+       spin_unlock_irqrestore(&qmgr_lock, flags);
+}
+
+static inline void shift_mask(u32 *mask)
+{
+       mask[3] = mask[3] << 1 | mask[2] >> 31;
+       mask[2] = mask[2] << 1 | mask[1] >> 31;
+       mask[1] = mask[1] << 1 | mask[0] >> 31;
+       mask[0] <<= 1;
+}
+
+int qmgr_request_queue(unsigned int queue, unsigned int len /* dwords */,
+                      unsigned int nearly_empty_watermark,
+                      unsigned int nearly_full_watermark)
+{
+       u32 cfg, addr = 0, mask[4]; /* in 16-dwords */
+       int err;
+
+       if (queue >= HALF_QUEUES)
+               return -ERANGE;
+
+       if ((nearly_empty_watermark | nearly_full_watermark) & ~7)
+               return -EINVAL;
+
+       switch (len) {
+       case  16:
+               cfg = 0 << 24;
+               mask[0] = 0x1;
+               break;
+       case  32:
+               cfg = 1 << 24;
+               mask[0] = 0x3;
+               break;
+       case  64:
+               cfg = 2 << 24;
+               mask[0] = 0xF;
+               break;
+       case 128:
+               cfg = 3 << 24;
+               mask[0] = 0xFF;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       cfg |= nearly_empty_watermark << 26;
+       cfg |= nearly_full_watermark << 29;
+       len /= 16;              /* in 16-dwords: 1, 2, 4 or 8 */
+       mask[1] = mask[2] = mask[3] = 0;
+
+       if (!try_module_get(THIS_MODULE))
+               return -ENODEV;
+
+       spin_lock_irq(&qmgr_lock);
+       if (__raw_readl(&qmgr_regs->sram[queue])) {
+               err = -EBUSY;
+               goto err;
+       }
+
+       while (1) {
+               if (!(used_sram_bitmap[0] & mask[0]) &&
+                   !(used_sram_bitmap[1] & mask[1]) &&
+                   !(used_sram_bitmap[2] & mask[2]) &&
+                   !(used_sram_bitmap[3] & mask[3]))
+                       break; /* found free space */
+
+               addr++;
+               shift_mask(mask);
+               if (addr + len > ARRAY_SIZE(qmgr_regs->sram)) {
+                       printk(KERN_ERR "qmgr: no free SRAM space for"
+                              " queue %i\n", queue);
+                       err = -ENOMEM;
+                       goto err;
+               }
+       }
+
+       used_sram_bitmap[0] |= mask[0];
+       used_sram_bitmap[1] |= mask[1];
+       used_sram_bitmap[2] |= mask[2];
+       used_sram_bitmap[3] |= mask[3];
+       __raw_writel(cfg | (addr << 14), &qmgr_regs->sram[queue]);
+       spin_unlock_irq(&qmgr_lock);
+
+#if DEBUG
+       printk(KERN_DEBUG "qmgr: requested queue %i, addr = 0x%02X\n",
+              queue, addr);
+#endif
+       return 0;
+
+err:
+       spin_unlock_irq(&qmgr_lock);
+       module_put(THIS_MODULE);
+       return err;
+}
+
+void qmgr_release_queue(unsigned int queue)
+{
+       u32 cfg, addr, mask[4];
+
+       BUG_ON(queue >= HALF_QUEUES); /* not in valid range */
+
+       spin_lock_irq(&qmgr_lock);
+       cfg = __raw_readl(&qmgr_regs->sram[queue]);
+       addr = (cfg >> 14) & 0xFF;
+
+       BUG_ON(!addr);          /* not requested */
+
+       switch ((cfg >> 24) & 3) {
+       case 0: mask[0] = 0x1; break;
+       case 1: mask[0] = 0x3; break;
+       case 2: mask[0] = 0xF; break;
+       case 3: mask[0] = 0xFF; break;
+       }
+
+       while (addr--)
+               shift_mask(mask);
+
+       __raw_writel(0, &qmgr_regs->sram[queue]);
+
+       used_sram_bitmap[0] &= ~mask[0];
+       used_sram_bitmap[1] &= ~mask[1];
+       used_sram_bitmap[2] &= ~mask[2];
+       used_sram_bitmap[3] &= ~mask[3];
+       irq_handlers[queue] = NULL; /* catch IRQ bugs */
+       spin_unlock_irq(&qmgr_lock);
+
+       module_put(THIS_MODULE);
+#if DEBUG
+       printk(KERN_DEBUG "qmgr: released queue %i\n", queue);
+#endif
+}
+
+static int qmgr_init(void)
+{
+       int i, err;
+       mem_res = request_mem_region(IXP4XX_QMGR_BASE_PHYS,
+                                    IXP4XX_QMGR_REGION_SIZE,
+                                    "IXP4xx Queue Manager");
+       if (mem_res == NULL)
+               return -EBUSY;
+
+       qmgr_regs = ioremap(IXP4XX_QMGR_BASE_PHYS, IXP4XX_QMGR_REGION_SIZE);
+       if (qmgr_regs == NULL) {
+               err = -ENOMEM;
+               goto error_map;
+       }
+
+       /* reset qmgr registers */
+       for (i = 0; i < 4; i++) {
+               __raw_writel(0x33333333, &qmgr_regs->stat1[i]);
+               __raw_writel(0, &qmgr_regs->irqsrc[i]);
+       }
+       for (i = 0; i < 2; i++) {
+               __raw_writel(0, &qmgr_regs->stat2[i]);
+               __raw_writel(0xFFFFFFFF, &qmgr_regs->irqstat[i]); /* clear */
+               __raw_writel(0, &qmgr_regs->irqen[i]);
+       }
+
+       for (i = 0; i < QUEUES; i++)
+               __raw_writel(0, &qmgr_regs->sram[i]);
+
+       err = request_irq(IRQ_IXP4XX_QM1, qmgr_irq1, 0,
+                         "IXP4xx Queue Manager", NULL);
+       if (err) {
+               printk(KERN_ERR "qmgr: failed to request IRQ%i\n",
+                      IRQ_IXP4XX_QM1);
+               goto error_irq;
+       }
+
+       used_sram_bitmap[0] = 0xF; /* 4 first pages reserved for config */
+       spin_lock_init(&qmgr_lock);
+
+       printk(KERN_INFO "IXP4xx Queue Manager initialized.\n");
+       return 0;
+
+error_irq:
+       iounmap(qmgr_regs);
+error_map:
+       release_mem_region(IXP4XX_QMGR_BASE_PHYS, IXP4XX_QMGR_REGION_SIZE);
+       return err;
+}
+
+static void qmgr_remove(void)
+{
+       free_irq(IRQ_IXP4XX_QM1, NULL);
+       synchronize_irq(IRQ_IXP4XX_QM1);
+       iounmap(qmgr_regs);
+       release_mem_region(IXP4XX_QMGR_BASE_PHYS, IXP4XX_QMGR_REGION_SIZE);
+}
+
+module_init(qmgr_init);
+module_exit(qmgr_remove);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Krzysztof Halasa");
+
+EXPORT_SYMBOL(qmgr_regs);
+EXPORT_SYMBOL(qmgr_set_irq);
+EXPORT_SYMBOL(qmgr_enable_irq);
+EXPORT_SYMBOL(qmgr_disable_irq);
+EXPORT_SYMBOL(qmgr_request_queue);
+EXPORT_SYMBOL(qmgr_release_queue);
diff --git a/arch/arm/mach-ixp4xx/nas100d-power.c b/arch/arm/mach-ixp4xx/nas100d-power.c
deleted file mode 100644 (file)
index 29aa98d..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * arch/arm/mach-ixp4xx/nas100d-power.c
- *
- * NAS 100d Power/Reset driver
- *
- * Copyright (C) 2005 Tower Technologies
- *
- * based on nas100d-io.c
- *  Copyright (C) 2004 Karen Spearel
- *
- * Author: Alessandro Zummo <a.zummo@towertech.it>
- * Maintainers: http://www.nslu2-linux.org/
- *
- * 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/interrupt.h>
-#include <linux/irq.h>
-#include <linux/module.h>
-#include <linux/reboot.h>
-
-#include <asm/mach-types.h>
-
-static irqreturn_t nas100d_reset_handler(int irq, void *dev_id)
-{
-       /* Signal init to do the ctrlaltdel action, this will bypass init if
-        * it hasn't started and do a kernel_restart.
-        */
-       ctrl_alt_del();
-
-       return IRQ_HANDLED;
-}
-
-static int __init nas100d_power_init(void)
-{
-       if (!(machine_is_nas100d()))
-               return 0;
-
-       set_irq_type(NAS100D_RB_IRQ, IRQT_LOW);
-
-       if (request_irq(NAS100D_RB_IRQ, &nas100d_reset_handler,
-               IRQF_DISABLED, "NAS100D reset button", NULL) < 0) {
-
-               printk(KERN_DEBUG "Reset Button IRQ %d not available\n",
-                       NAS100D_RB_IRQ);
-
-               return -EIO;
-       }
-
-       return 0;
-}
-
-static void __exit nas100d_power_exit(void)
-{
-       if (!(machine_is_nas100d()))
-               return;
-
-       free_irq(NAS100D_RB_IRQ, NULL);
-}
-
-module_init(nas100d_power_init);
-module_exit(nas100d_power_exit);
-
-MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
-MODULE_DESCRIPTION("NAS100D Power/Reset driver");
-MODULE_LICENSE("GPL");
index 54d884fb2517a5207b2b5699d5b89e936917d6c1..4cecae84837b37309039280122ed726356d6ab5c 100644 (file)
@@ -3,8 +3,14 @@
  *
  * NAS 100d board-setup
  *
- * based ixdp425-setup.c:
+ * Copyright (C) 2008 Rod Whitby <rod@whitby.id.au>
+ *
+ * based on ixdp425-setup.c:
  *      Copyright (C) 2003-2004 MontaVista Software, Inc.
+ * based on nas100d-power.c:
+ *     Copyright (C) 2005 Tower Technologies
+ * based on nas100d-io.c
+ *     Copyright (C) 2004 Karen Spearel
  *
  * Author: Alessandro Zummo <a.zummo@towertech.it>
  * Author: Rod Whitby <rod@whitby.id.au>
  *
  */
 
-#include <linux/kernel.h>
+#include <linux/if_ether.h>
+#include <linux/irq.h>
+#include <linux/jiffies.h>
+#include <linux/timer.h>
 #include <linux/serial.h>
 #include <linux/serial_8250.h>
 #include <linux/leds.h>
+#include <linux/reboot.h>
+#include <linux/i2c.h>
 #include <linux/i2c-gpio.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/flash.h>
+#include <asm/io.h>
+#include <asm/gpio.h>
 
 static struct flash_platform_data nas100d_flash_data = {
        .map_name               = "cfi_probe",
@@ -39,35 +52,40 @@ static struct platform_device nas100d_flash = {
        .resource               = &nas100d_flash_resource,
 };
 
-#ifdef CONFIG_LEDS_IXP4XX
-static struct resource nas100d_led_resources[] = {
+static struct i2c_board_info __initdata nas100d_i2c_board_info [] = {
+       {
+               I2C_BOARD_INFO("rtc-pcf8563", 0x51),
+       },
+};
+
+static struct gpio_led nas100d_led_pins[] = {
        {
                .name           = "wlan",   /* green led */
-               .start          = 0,
-               .end            = 0,
-               .flags          = IXP4XX_GPIO_LOW,
+               .gpio           = NAS100D_LED_WLAN_GPIO,
+               .active_low     = true,
        },
        {
-               .name           = "ready",  /* blue power led (off is flashing!) */
-               .start          = 15,
-               .end            = 15,
-               .flags          = IXP4XX_GPIO_LOW,
+               .name           = "power",  /* blue power led (off=flashing) */
+               .gpio           = NAS100D_LED_PWR_GPIO,
+               .active_low     = true,
        },
        {
                .name           = "disk",   /* yellow led */
-               .start          = 3,
-               .end            = 3,
-               .flags          = IXP4XX_GPIO_LOW,
+               .gpio           = NAS100D_LED_DISK_GPIO,
+               .active_low     = true,
        },
 };
 
+static struct gpio_led_platform_data nas100d_led_data = {
+       .num_leds               = ARRAY_SIZE(nas100d_led_pins),
+       .leds                   = nas100d_led_pins,
+};
+
 static struct platform_device nas100d_leds = {
-       .name                   = "IXP4XX-GPIO-LED",
+       .name                   = "leds-gpio",
        .id                     = -1,
-       .num_resources          = ARRAY_SIZE(nas100d_led_resources),
-       .resource               = nas100d_led_resources,
+       .dev.platform_data      = &nas100d_led_data,
 };
-#endif
 
 static struct i2c_gpio_platform_data nas100d_i2c_gpio_data = {
        .sda_pin                = NAS100D_SDA_PIN,
@@ -125,12 +143,28 @@ static struct platform_device nas100d_uart = {
        .resource               = nas100d_uart_resources,
 };
 
+/* Built-in 10/100 Ethernet MAC interfaces */
+static struct eth_plat_info nas100d_plat_eth[] = {
+       {
+               .phy            = 0,
+               .rxq            = 3,
+               .txreadyq       = 20,
+       }
+};
+
+static struct platform_device nas100d_eth[] = {
+       {
+               .name                   = "ixp4xx_eth",
+               .id                     = IXP4XX_ETH_NPEB,
+               .dev.platform_data      = nas100d_plat_eth,
+       }
+};
+
 static struct platform_device *nas100d_devices[] __initdata = {
        &nas100d_i2c_gpio,
        &nas100d_flash,
-#ifdef CONFIG_LEDS_IXP4XX
        &nas100d_leds,
-#endif
+       &nas100d_eth[0],
 };
 
 static void nas100d_power_off(void)
@@ -144,8 +178,63 @@ static void nas100d_power_off(void)
        gpio_line_set(NAS100D_PO_GPIO, IXP4XX_GPIO_HIGH);
 }
 
+/* This is used to make sure the power-button pusher is serious.  The button
+ * must be held until the value of this counter reaches zero.
+ */
+static int power_button_countdown;
+
+/* Must hold the button down for at least this many counts to be processed */
+#define PBUTTON_HOLDDOWN_COUNT 4 /* 2 secs */
+
+static void nas100d_power_handler(unsigned long data);
+static DEFINE_TIMER(nas100d_power_timer, nas100d_power_handler, 0, 0);
+
+static void nas100d_power_handler(unsigned long data)
+{
+       /* This routine is called twice per second to check the
+        * state of the power button.
+        */
+
+       if (gpio_get_value(NAS100D_PB_GPIO)) {
+
+               /* IO Pin is 1 (button pushed) */
+               if (power_button_countdown > 0)
+                       power_button_countdown--;
+
+       } else {
+
+               /* Done on button release, to allow for auto-power-on mods. */
+               if (power_button_countdown == 0) {
+                       /* Signal init to do the ctrlaltdel action,
+                        * this will bypass init if it hasn't started
+                        * and do a kernel_restart.
+                        */
+                       ctrl_alt_del();
+
+                       /* Change the state of the power LED to "blink" */
+                       gpio_line_set(NAS100D_LED_PWR_GPIO, IXP4XX_GPIO_LOW);
+               } else {
+                       power_button_countdown = PBUTTON_HOLDDOWN_COUNT;
+               }
+       }
+
+       mod_timer(&nas100d_power_timer, jiffies + msecs_to_jiffies(500));
+}
+
+static irqreturn_t nas100d_reset_handler(int irq, void *dev_id)
+{
+       /* This is the paper-clip reset, it shuts the machine down directly. */
+       machine_power_off();
+
+       return IRQ_HANDLED;
+}
+
 static void __init nas100d_init(void)
 {
+       DECLARE_MAC_BUF(mac_buf);
+       uint8_t __iomem *f;
+       int i;
+
        ixp4xx_sys_init();
 
        /* gpio 14 and 15 are _not_ clocks */
@@ -155,7 +244,8 @@ static void __init nas100d_init(void)
        nas100d_flash_resource.end =
                IXP4XX_EXP_BUS_BASE(0) + ixp4xx_exp_bus_size - 1;
 
-       pm_power_off = nas100d_power_off;
+       i2c_register_board_info(0, nas100d_i2c_board_info,
+                               ARRAY_SIZE(nas100d_i2c_board_info));
 
        /*
         * This is only useful on a modified machine, but it is valuable
@@ -165,6 +255,48 @@ static void __init nas100d_init(void)
        (void)platform_device_register(&nas100d_uart);
 
        platform_add_devices(nas100d_devices, ARRAY_SIZE(nas100d_devices));
+
+       pm_power_off = nas100d_power_off;
+
+       if (request_irq(gpio_to_irq(NAS100D_RB_GPIO), &nas100d_reset_handler,
+               IRQF_DISABLED | IRQF_TRIGGER_LOW,
+               "NAS100D reset button", NULL) < 0) {
+
+               printk(KERN_DEBUG "Reset Button IRQ %d not available\n",
+                       gpio_to_irq(NAS100D_RB_GPIO));
+       }
+
+       /* The power button on the Iomega NAS100d is on GPIO 14, but
+        * it cannot handle interrupts on that GPIO line.  So we'll
+        * have to poll it with a kernel timer.
+        */
+
+       /* Make sure that the power button GPIO is set up as an input */
+       gpio_line_config(NAS100D_PB_GPIO, IXP4XX_GPIO_IN);
+
+       /* Set the initial value for the power button IRQ handler */
+       power_button_countdown = PBUTTON_HOLDDOWN_COUNT;
+
+       mod_timer(&nas100d_power_timer, jiffies + msecs_to_jiffies(500));
+
+       /*
+        * Map in a portion of the flash and read the MAC address.
+        * Since it is stored in BE in the flash itself, we need to
+        * byteswap it if we're in LE mode.
+        */
+       f = ioremap(IXP4XX_EXP_BUS_BASE(0), 0x1000000);
+       if (f) {
+               for (i = 0; i < 6; i++)
+#ifdef __ARMEB__
+                       nas100d_plat_eth[0].hwaddr[i] = readb(f + 0xFC0FD8 + i);
+#else
+                       nas100d_plat_eth[0].hwaddr[i] = readb(f + 0xFC0FD8 + (i^3));
+#endif
+               iounmap(f);
+       }
+       printk(KERN_INFO "NAS100D: Using MAC address %s for port 0\n",
+              print_mac(mac_buf, nas100d_plat_eth[0].hwaddr));
+
 }
 
 MACHINE_START(NAS100D, "Iomega NAS 100d")
diff --git a/arch/arm/mach-ixp4xx/nslu2-power.c b/arch/arm/mach-ixp4xx/nslu2-power.c
deleted file mode 100644 (file)
index 6f10dc2..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * arch/arm/mach-ixp4xx/nslu2-power.c
- *
- * NSLU2 Power/Reset driver
- *
- * Copyright (C) 2005 Tower Technologies
- *
- * based on nslu2-io.c
- *  Copyright (C) 2004 Karen Spearel
- *
- * Author: Alessandro Zummo <a.zummo@towertech.it>
- * Maintainers: http://www.nslu2-linux.org/
- *
- * 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/module.h>
-#include <linux/reboot.h>
-#include <linux/irq.h>
-#include <linux/interrupt.h>
-
-#include <asm/mach-types.h>
-
-static irqreturn_t nslu2_power_handler(int irq, void *dev_id)
-{
-       /* Signal init to do the ctrlaltdel action, this will bypass init if
-        * it hasn't started and do a kernel_restart.
-        */
-       ctrl_alt_del();
-
-       return IRQ_HANDLED;
-}
-
-static irqreturn_t nslu2_reset_handler(int irq, void *dev_id)
-{
-       /* This is the paper-clip reset, it shuts the machine down directly.
-        */
-       machine_power_off();
-
-       return IRQ_HANDLED;
-}
-
-static int __init nslu2_power_init(void)
-{
-       if (!(machine_is_nslu2()))
-               return 0;
-
-       *IXP4XX_GPIO_GPISR = 0x20400000;        /* read the 2 irqs to clr */
-
-       set_irq_type(NSLU2_RB_IRQ, IRQT_LOW);
-       set_irq_type(NSLU2_PB_IRQ, IRQT_HIGH);
-
-       if (request_irq(NSLU2_RB_IRQ, &nslu2_reset_handler,
-               IRQF_DISABLED, "NSLU2 reset button", NULL) < 0) {
-
-               printk(KERN_DEBUG "Reset Button IRQ %d not available\n",
-                       NSLU2_RB_IRQ);
-
-               return -EIO;
-       }
-
-       if (request_irq(NSLU2_PB_IRQ, &nslu2_power_handler,
-               IRQF_DISABLED, "NSLU2 power button", NULL) < 0) {
-
-               printk(KERN_DEBUG "Power Button IRQ %d not available\n",
-                       NSLU2_PB_IRQ);
-
-               return -EIO;
-       }
-
-       return 0;
-}
-
-static void __exit nslu2_power_exit(void)
-{
-       if (!(machine_is_nslu2()))
-               return;
-
-       free_irq(NSLU2_RB_IRQ, NULL);
-       free_irq(NSLU2_PB_IRQ, NULL);
-}
-
-module_init(nslu2_power_init);
-module_exit(nslu2_power_exit);
-
-MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
-MODULE_DESCRIPTION("NSLU2 Power/Reset driver");
-MODULE_LICENSE("GPL");
index 77277d27fcc51bef387520c3fea32d88cf7b3f22..acaebcbce53a07319cade57fb80f5bdbb8543ea1 100644 (file)
@@ -3,27 +3,35 @@
  *
  * NSLU2 board-setup
  *
- * based ixdp425-setup.c:
+ * Copyright (C) 2008 Rod Whitby <rod@whitby.id.au>
+ *
+ * based on ixdp425-setup.c:
  *      Copyright (C) 2003-2004 MontaVista Software, Inc.
+ * based on nslu2-power.c:
+ *     Copyright (C) 2005 Tower Technologies
  *
  * Author: Mark Rakes <mrakes at mac.com>
  * Author: Rod Whitby <rod@whitby.id.au>
+ * Author: Alessandro Zummo <a.zummo@towertech.it>
  * Maintainers: http://www.nslu2-linux.org/
  *
- * Fixed missing init_time in MACHINE_START kas11 10/22/04
- * Changed to conform to new style __init ixdp425 kas11 10/22/04
  */
 
-#include <linux/kernel.h>
+#include <linux/if_ether.h>
+#include <linux/irq.h>
 #include <linux/serial.h>
 #include <linux/serial_8250.h>
 #include <linux/leds.h>
+#include <linux/reboot.h>
+#include <linux/i2c.h>
 #include <linux/i2c-gpio.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/flash.h>
 #include <asm/mach/time.h>
+#include <asm/io.h>
+#include <asm/gpio.h>
 
 static struct flash_platform_data nslu2_flash_data = {
        .map_name               = "cfi_probe",
@@ -47,41 +55,43 @@ static struct i2c_gpio_platform_data nslu2_i2c_gpio_data = {
        .scl_pin                = NSLU2_SCL_PIN,
 };
 
-#ifdef CONFIG_LEDS_IXP4XX
-static struct resource nslu2_led_resources[] = {
+static struct i2c_board_info __initdata nslu2_i2c_board_info [] = {
+       {
+               I2C_BOARD_INFO("rtc-x1205", 0x6f),
+       },
+};
+
+static struct gpio_led nslu2_led_pins[] = {
        {
                .name           = "ready",  /* green led */
-               .start          = NSLU2_LED_GRN_GPIO,
-               .end            = NSLU2_LED_GRN_GPIO,
-               .flags          = IXP4XX_GPIO_HIGH,
+               .gpio           = NSLU2_LED_GRN_GPIO,
        },
        {
                .name           = "status", /* red led */
-               .start          = NSLU2_LED_RED_GPIO,
-               .end            = NSLU2_LED_RED_GPIO,
-               .flags          = IXP4XX_GPIO_HIGH,
+               .gpio           = NSLU2_LED_RED_GPIO,
        },
        {
                .name           = "disk-1",
-               .start          = NSLU2_LED_DISK1_GPIO,
-               .end            = NSLU2_LED_DISK1_GPIO,
-               .flags          = IXP4XX_GPIO_LOW,
+               .gpio           = NSLU2_LED_DISK1_GPIO,
+               .active_low     = true,
        },
        {
                .name           = "disk-2",
-               .start          = NSLU2_LED_DISK2_GPIO,
-               .end            = NSLU2_LED_DISK2_GPIO,
-               .flags          = IXP4XX_GPIO_LOW,
+               .gpio           = NSLU2_LED_DISK2_GPIO,
+               .active_low     = true,
        },
 };
 
+static struct gpio_led_platform_data nslu2_led_data = {
+       .num_leds               = ARRAY_SIZE(nslu2_led_pins),
+       .leds                   = nslu2_led_pins,
+};
+
 static struct platform_device nslu2_leds = {
-       .name                   = "IXP4XX-GPIO-LED",
+       .name                   = "leds-gpio",
        .id                     = -1,
-       .num_resources          = ARRAY_SIZE(nslu2_led_resources),
-       .resource               = nslu2_led_resources,
+       .dev.platform_data      = &nslu2_led_data,
 };
-#endif
 
 static struct platform_device nslu2_i2c_gpio = {
        .name                   = "i2c-gpio",
@@ -140,13 +150,29 @@ static struct platform_device nslu2_uart = {
        .resource               = nslu2_uart_resources,
 };
 
+/* Built-in 10/100 Ethernet MAC interfaces */
+static struct eth_plat_info nslu2_plat_eth[] = {
+       {
+               .phy            = 1,
+               .rxq            = 3,
+               .txreadyq       = 20,
+       }
+};
+
+static struct platform_device nslu2_eth[] = {
+       {
+               .name                   = "ixp4xx_eth",
+               .id                     = IXP4XX_ETH_NPEB,
+               .dev.platform_data      = nslu2_plat_eth,
+       }
+};
+
 static struct platform_device *nslu2_devices[] __initdata = {
        &nslu2_i2c_gpio,
        &nslu2_flash,
        &nslu2_beeper,
-#ifdef CONFIG_LEDS_IXP4XX
        &nslu2_leds,
-#endif
+       &nslu2_eth[0],
 };
 
 static void nslu2_power_off(void)
@@ -160,6 +186,25 @@ static void nslu2_power_off(void)
        gpio_line_set(NSLU2_PO_GPIO, IXP4XX_GPIO_HIGH);
 }
 
+static irqreturn_t nslu2_power_handler(int irq, void *dev_id)
+{
+       /* Signal init to do the ctrlaltdel action, this will bypass init if
+        * it hasn't started and do a kernel_restart.
+        */
+       ctrl_alt_del();
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t nslu2_reset_handler(int irq, void *dev_id)
+{
+       /* This is the paper-clip reset, it shuts the machine down directly.
+        */
+       machine_power_off();
+
+       return IRQ_HANDLED;
+}
+
 static void __init nslu2_timer_init(void)
 {
     /* The xtal on this machine is non-standard. */
@@ -175,13 +220,18 @@ static struct sys_timer nslu2_timer = {
 
 static void __init nslu2_init(void)
 {
+       DECLARE_MAC_BUF(mac_buf);
+       uint8_t __iomem *f;
+       int i;
+
        ixp4xx_sys_init();
 
        nslu2_flash_resource.start = IXP4XX_EXP_BUS_BASE(0);
        nslu2_flash_resource.end =
                IXP4XX_EXP_BUS_BASE(0) + ixp4xx_exp_bus_size - 1;
 
-       pm_power_off = nslu2_power_off;
+       i2c_register_board_info(0, nslu2_i2c_board_info,
+                               ARRAY_SIZE(nslu2_i2c_board_info));
 
        /*
         * This is only useful on a modified machine, but it is valuable
@@ -191,6 +241,43 @@ static void __init nslu2_init(void)
        (void)platform_device_register(&nslu2_uart);
 
        platform_add_devices(nslu2_devices, ARRAY_SIZE(nslu2_devices));
+
+       pm_power_off = nslu2_power_off;
+
+       if (request_irq(gpio_to_irq(NSLU2_RB_GPIO), &nslu2_reset_handler,
+               IRQF_DISABLED | IRQF_TRIGGER_LOW,
+               "NSLU2 reset button", NULL) < 0) {
+
+               printk(KERN_DEBUG "Reset Button IRQ %d not available\n",
+                       gpio_to_irq(NSLU2_RB_GPIO));
+       }
+
+       if (request_irq(gpio_to_irq(NSLU2_PB_GPIO), &nslu2_power_handler,
+               IRQF_DISABLED | IRQF_TRIGGER_HIGH,
+               "NSLU2 power button", NULL) < 0) {
+
+               printk(KERN_DEBUG "Power Button IRQ %d not available\n",
+                       gpio_to_irq(NSLU2_PB_GPIO));
+       }
+
+       /*
+        * Map in a portion of the flash and read the MAC address.
+        * Since it is stored in BE in the flash itself, we need to
+        * byteswap it if we're in LE mode.
+        */
+       f = ioremap(IXP4XX_EXP_BUS_BASE(0), 0x40000);
+       if (f) {
+               for (i = 0; i < 6; i++)
+#ifdef __ARMEB__
+                       nslu2_plat_eth[0].hwaddr[i] = readb(f + 0x3FFB0 + i);
+#else
+                       nslu2_plat_eth[0].hwaddr[i] = readb(f + 0x3FFB0 + (i^3));
+#endif
+               iounmap(f);
+       }
+       printk(KERN_INFO "NSLU2: Using MAC address %s for port 0\n",
+              print_mac(mac_buf, nslu2_plat_eth[0].hwaddr));
+
 }
 
 MACHINE_START(NSLU2, "Linksys NSLU2")
index b5c916c0747d68867b34325eebc576a86f5fad0b..6e0c4f5b5ae663526a9daf2750149f7f6fe2b89b 100644 (file)
@@ -3,10 +3,11 @@
 #
 
 # Common support (must be linked before board specific support)
-obj-y                          += clock.o devices.o generic.o irq.o dma.o time.o
+obj-y                          += clock.o devices.o generic.o irq.o dma.o \
+                                  time.o gpio.o
 obj-$(CONFIG_PXA25x)           += pxa25x.o
 obj-$(CONFIG_PXA27x)           += pxa27x.o
-obj-$(CONFIG_PXA3xx)           += pxa3xx.o mfp.o
+obj-$(CONFIG_PXA3xx)           += pxa3xx.o mfp.o smemc.o
 obj-$(CONFIG_CPU_PXA300)       += pxa300.o
 obj-$(CONFIG_CPU_PXA320)       += pxa320.o
 
index 28cfd71c032d2bf533621ef6f3503968e6668f7c..6012177a29a35b5afb0227c8f0d31bd95ed0f81c 100644 (file)
@@ -29,6 +29,7 @@
 #include <asm/mach/map.h>
 
 #include <asm/arch/pxa-regs.h>
+#include <asm/arch/pxa2xx-regs.h>
 #include <asm/arch/pxafb.h>
 #include <asm/arch/ohci.h>
 #include <asm/arch/mmc.h>
index efba65edcd51af287077294659b9564dae19417b..31706224a04c07a58e4c6e91a99a703ff5ff6f12 100644 (file)
@@ -32,7 +32,7 @@ static struct corgissp_machinfo *ssp_machinfo;
 /*
  * There are three devices connected to the SSP interface:
  *   1. A touchscreen controller (TI ADS7846 compatible)
- *   2. An LCD contoller (with some Backlight functionality)
+ *   2. An LCD controller (with some Backlight functionality)
  *   3. A battery monitoring IC (Maxim MAX1111)
  *
  * Each device uses a different speed/mode of communication.
index 50ff453ad3707453051ce1703bed2a519a7c4df4..bfccb80ac8eff129d62aaccd02469fbec7b504de 100644 (file)
@@ -10,6 +10,7 @@
 #include <asm/arch/mmc.h>
 #include <asm/arch/irda.h>
 #include <asm/arch/i2c.h>
+#include <asm/arch/ohci.h>
 
 #include "devices.h"
 
index 698aeec529617e4098db8e30ee1e4d9a4d56cf48..80721c610d41dee16f74ebdbeb72bb4c3be2b7cf 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/ioport.h>
 #include <linux/pm.h>
 #include <linux/string.h>
+#include <linux/sysdev.h>
 
 #include <asm/hardware.h>
 #include <asm/irq.h>
@@ -31,7 +32,6 @@
 #include <asm/mach/map.h>
 
 #include <asm/arch/pxa-regs.h>
-#include <asm/arch/gpio.h>
 
 #include "generic.h"
 
@@ -65,97 +65,6 @@ unsigned int get_memclk_frequency_10khz(void)
 }
 EXPORT_SYMBOL(get_memclk_frequency_10khz);
 
-/*
- * Handy function to set GPIO alternate functions
- */
-int pxa_last_gpio;
-
-int pxa_gpio_mode(int gpio_mode)
-{
-       unsigned long flags;
-       int gpio = gpio_mode & GPIO_MD_MASK_NR;
-       int fn = (gpio_mode & GPIO_MD_MASK_FN) >> 8;
-       int gafr;
-
-       if (gpio > pxa_last_gpio)
-               return -EINVAL;
-
-       local_irq_save(flags);
-       if (gpio_mode & GPIO_DFLT_LOW)
-               GPCR(gpio) = GPIO_bit(gpio);
-       else if (gpio_mode & GPIO_DFLT_HIGH)
-               GPSR(gpio) = GPIO_bit(gpio);
-       if (gpio_mode & GPIO_MD_MASK_DIR)
-               GPDR(gpio) |= GPIO_bit(gpio);
-       else
-               GPDR(gpio) &= ~GPIO_bit(gpio);
-       gafr = GAFR(gpio) & ~(0x3 << (((gpio) & 0xf)*2));
-       GAFR(gpio) = gafr |  (fn  << (((gpio) & 0xf)*2));
-       local_irq_restore(flags);
-
-       return 0;
-}
-
-EXPORT_SYMBOL(pxa_gpio_mode);
-
-int gpio_direction_input(unsigned gpio)
-{
-       unsigned long flags;
-       u32 mask;
-
-       if (gpio > pxa_last_gpio)
-               return -EINVAL;
-
-       mask = GPIO_bit(gpio);
-       local_irq_save(flags);
-       GPDR(gpio) &= ~mask;
-       local_irq_restore(flags);
-
-       return 0;
-}
-EXPORT_SYMBOL(gpio_direction_input);
-
-int gpio_direction_output(unsigned gpio, int value)
-{
-       unsigned long flags;
-       u32 mask;
-
-       if (gpio > pxa_last_gpio)
-               return -EINVAL;
-
-       mask = GPIO_bit(gpio);
-       local_irq_save(flags);
-       if (value)
-               GPSR(gpio) = mask;
-       else
-               GPCR(gpio) = mask;
-       GPDR(gpio) |= mask;
-       local_irq_restore(flags);
-
-       return 0;
-}
-EXPORT_SYMBOL(gpio_direction_output);
-
-/*
- * Return GPIO level
- */
-int pxa_gpio_get_value(unsigned gpio)
-{
-       return __gpio_get_value(gpio);
-}
-
-EXPORT_SYMBOL(pxa_gpio_get_value);
-
-/*
- * Set output GPIO level
- */
-void pxa_gpio_set_value(unsigned gpio, int value)
-{
-       __gpio_set_value(gpio, value);
-}
-
-EXPORT_SYMBOL(pxa_gpio_set_value);
-
 /*
  * Routine to safely enable or disable a clock in the CKEN
  */
@@ -171,7 +80,6 @@ void __pxa_set_cken(int clock, int enable)
 
        local_irq_restore(flags);
 }
-
 EXPORT_SYMBOL(__pxa_set_cken);
 
 /*
@@ -226,3 +134,59 @@ void __init pxa_map_io(void)
        iotable_init(standard_io_desc, ARRAY_SIZE(standard_io_desc));
        get_clk_frequency_khz(1);
 }
+
+#ifdef CONFIG_PM
+
+static unsigned long saved_gplr[4];
+static unsigned long saved_gpdr[4];
+static unsigned long saved_grer[4];
+static unsigned long saved_gfer[4];
+
+static int pxa_gpio_suspend(struct sys_device *dev, pm_message_t state)
+{
+       int i, gpio;
+
+       for (gpio = 0, i = 0; gpio < pxa_last_gpio; gpio += 32, i++) {
+               saved_gplr[i] = GPLR(gpio);
+               saved_gpdr[i] = GPDR(gpio);
+               saved_grer[i] = GRER(gpio);
+               saved_gfer[i] = GFER(gpio);
+
+               /* Clear GPIO transition detect bits */
+               GEDR(gpio) = GEDR(gpio);
+       }
+       return 0;
+}
+
+static int pxa_gpio_resume(struct sys_device *dev)
+{
+       int i, gpio;
+
+       for (gpio = 0, i = 0; gpio < pxa_last_gpio; gpio += 32, i++) {
+               /* restore level with set/clear */
+               GPSR(gpio) = saved_gplr[i];
+               GPCR(gpio) = ~saved_gplr[i];
+
+               GRER(gpio) = saved_grer[i];
+               GFER(gpio) = saved_gfer[i];
+               GPDR(gpio) = saved_gpdr[i];
+       }
+       return 0;
+}
+#else
+#define pxa_gpio_suspend       NULL
+#define pxa_gpio_resume                NULL
+#endif
+
+struct sysdev_class pxa_gpio_sysclass = {
+       .name           = "gpio",
+       .suspend        = pxa_gpio_suspend,
+       .resume         = pxa_gpio_resume,
+};
+
+static int __init pxa_gpio_init(void)
+{
+       return sysdev_class_register(&pxa_gpio_sysclass);
+}
+
+core_initcall(pxa_gpio_init);
index b30f240a16c798756e8e350142e9c92da65126c3..b3d10b0e52a01478055cf4e26b5f312d49d52b65 100644 (file)
@@ -16,6 +16,7 @@ extern void __init pxa_init_irq_low(void);
 extern void __init pxa_init_irq_high(void);
 extern void __init pxa_init_irq_gpio(int gpio_nr);
 extern void __init pxa_init_irq_set_wake(int (*set_wake)(unsigned int, unsigned int));
+extern void __init pxa_init_gpio(int gpio_nr);
 extern void __init pxa25x_init_irq(void);
 extern void __init pxa27x_init_irq(void);
 extern void __init pxa3xx_init_irq(void);
@@ -52,3 +53,6 @@ extern unsigned pxa3xx_get_memclk_frequency_10khz(void);
 #define pxa3xx_get_clk_frequency_khz(x)                (0)
 #define pxa3xx_get_memclk_frequency_10khz()    (0)
 #endif
+
+extern struct sysdev_class pxa_irq_sysclass;
+extern struct sysdev_class pxa_gpio_sysclass;
diff --git a/arch/arm/mach-pxa/gpio.c b/arch/arm/mach-pxa/gpio.c
new file mode 100644 (file)
index 0000000..8638dd7
--- /dev/null
@@ -0,0 +1,197 @@
+/*
+ *  linux/arch/arm/mach-pxa/gpio.c
+ *
+ *  Generic PXA GPIO handling
+ *
+ *  Author:    Nicolas Pitre
+ *  Created:   Jun 15, 2001
+ *  Copyright: MontaVista Software Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+
+#include <asm/gpio.h>
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/arch/pxa-regs.h>
+
+#include "generic.h"
+
+
+struct pxa_gpio_chip {
+       struct gpio_chip chip;
+       void __iomem     *regbase;
+};
+
+int pxa_last_gpio;
+
+/*
+ * Configure pins for GPIO or other functions
+ */
+int pxa_gpio_mode(int gpio_mode)
+{
+       unsigned long flags;
+       int gpio = gpio_mode & GPIO_MD_MASK_NR;
+       int fn = (gpio_mode & GPIO_MD_MASK_FN) >> 8;
+       int gafr;
+
+       if (gpio > pxa_last_gpio)
+               return -EINVAL;
+
+       local_irq_save(flags);
+       if (gpio_mode & GPIO_DFLT_LOW)
+               GPCR(gpio) = GPIO_bit(gpio);
+       else if (gpio_mode & GPIO_DFLT_HIGH)
+               GPSR(gpio) = GPIO_bit(gpio);
+       if (gpio_mode & GPIO_MD_MASK_DIR)
+               GPDR(gpio) |= GPIO_bit(gpio);
+       else
+               GPDR(gpio) &= ~GPIO_bit(gpio);
+       gafr = GAFR(gpio) & ~(0x3 << (((gpio) & 0xf)*2));
+       GAFR(gpio) = gafr |  (fn  << (((gpio) & 0xf)*2));
+       local_irq_restore(flags);
+
+       return 0;
+}
+EXPORT_SYMBOL(pxa_gpio_mode);
+
+static int pxa_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+       unsigned long        flags;
+       u32                  mask = 1 << offset;
+       u32                  value;
+       struct pxa_gpio_chip *pxa;
+       void __iomem         *gpdr;
+
+       pxa = container_of(chip, struct pxa_gpio_chip, chip);
+       gpdr = pxa->regbase + GPDR_OFFSET;
+       local_irq_save(flags);
+       value = __raw_readl(gpdr);
+       value &= ~mask;
+       __raw_writel(value, gpdr);
+       local_irq_restore(flags);
+
+       return 0;
+}
+
+static int pxa_gpio_direction_output(struct gpio_chip *chip,
+                                       unsigned offset, int value)
+{
+       unsigned long        flags;
+       u32                  mask = 1 << offset;
+       u32                  tmp;
+       struct pxa_gpio_chip *pxa;
+       void __iomem         *gpdr;
+
+       pxa = container_of(chip, struct pxa_gpio_chip, chip);
+       __raw_writel(mask,
+                       pxa->regbase + (value ? GPSR_OFFSET : GPCR_OFFSET));
+       gpdr = pxa->regbase + GPDR_OFFSET;
+       local_irq_save(flags);
+       tmp = __raw_readl(gpdr);
+       tmp |= mask;
+       __raw_writel(tmp, gpdr);
+       local_irq_restore(flags);
+
+       return 0;
+}
+
+/*
+ * Return GPIO level
+ */
+static int pxa_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+       u32                  mask = 1 << offset;
+       struct pxa_gpio_chip *pxa;
+
+       pxa = container_of(chip, struct pxa_gpio_chip, chip);
+       return __raw_readl(pxa->regbase + GPLR_OFFSET) & mask;
+}
+
+/*
+ * Set output GPIO level
+ */
+static void pxa_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+       u32                  mask = 1 << offset;
+       struct pxa_gpio_chip *pxa;
+
+       pxa = container_of(chip, struct pxa_gpio_chip, chip);
+
+       if (value)
+               __raw_writel(mask, pxa->regbase + GPSR_OFFSET);
+       else
+               __raw_writel(mask, pxa->regbase + GPCR_OFFSET);
+}
+
+static struct pxa_gpio_chip pxa_gpio_chip[] = {
+       [0] = {
+               .regbase = GPIO0_BASE,
+               .chip = {
+                       .label            = "gpio-0",
+                       .direction_input  = pxa_gpio_direction_input,
+                       .direction_output = pxa_gpio_direction_output,
+                       .get              = pxa_gpio_get,
+                       .set              = pxa_gpio_set,
+                       .base             = 0,
+                       .ngpio            = 32,
+               },
+       },
+       [1] = {
+               .regbase = GPIO1_BASE,
+               .chip = {
+                       .label            = "gpio-1",
+                       .direction_input  = pxa_gpio_direction_input,
+                       .direction_output = pxa_gpio_direction_output,
+                       .get              = pxa_gpio_get,
+                       .set              = pxa_gpio_set,
+                       .base             = 32,
+                       .ngpio            = 32,
+               },
+       },
+       [2] = {
+               .regbase = GPIO2_BASE,
+               .chip = {
+                       .label            = "gpio-2",
+                       .direction_input  = pxa_gpio_direction_input,
+                       .direction_output = pxa_gpio_direction_output,
+                       .get              = pxa_gpio_get,
+                       .set              = pxa_gpio_set,
+                       .base             = 64,
+                       .ngpio            = 32, /* 21 for PXA25x */
+               },
+       },
+#if defined(CONFIG_PXA27x) || defined(CONFIG_PXA3xx)
+       [3] = {
+               .regbase = GPIO3_BASE,
+               .chip = {
+                       .label            = "gpio-3",
+                       .direction_input  = pxa_gpio_direction_input,
+                       .direction_output = pxa_gpio_direction_output,
+                       .get              = pxa_gpio_get,
+                       .set              = pxa_gpio_set,
+                       .base             = 96,
+                       .ngpio            = 32,
+               },
+       },
+#endif
+};
+
+void __init pxa_init_gpio(int gpio_nr)
+{
+       int i;
+
+       /* add a GPIO chip for each register bank.
+        * the last PXA25x register only contains 21 GPIOs
+        */
+       for (i = 0; i < gpio_nr; i += 32) {
+               if (i+32 > gpio_nr)
+                       pxa_gpio_chip[i/32].chip.ngpio = gpio_nr - i;
+               gpiochip_add(&pxa_gpio_chip[i/32].chip);
+       }
+}
index 07acb45b16ea83ac26be925293943a1f14def698..36c6a68beca26e1fa895d6ebb2373bd4bdd0eed6 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/interrupt.h>
+#include <linux/sysdev.h>
 
 #include <asm/hardware.h>
 #include <asm/irq.h>
@@ -310,6 +311,8 @@ void __init pxa_init_irq_gpio(int gpio_nr)
        /* Install handler for GPIO>=2 edge detect interrupts */
        set_irq_chip(IRQ_GPIO_2_x, &pxa_internal_chip_low);
        set_irq_chained_handler(IRQ_GPIO_2_x, pxa_gpio_demux_handler);
+
+       pxa_init_gpio(gpio_nr);
 }
 
 void __init pxa_init_irq_set_wake(int (*set_wake)(unsigned int, unsigned int))
@@ -321,3 +324,64 @@ void __init pxa_init_irq_set_wake(int (*set_wake)(unsigned int, unsigned int))
        pxa_low_gpio_chip.set_wake = set_wake;
        pxa_muxed_gpio_chip.set_wake = set_wake;
 }
+
+#ifdef CONFIG_PM
+static unsigned long saved_icmr[2];
+
+static int pxa_irq_suspend(struct sys_device *dev, pm_message_t state)
+{
+       switch (dev->id) {
+       case 0:
+               saved_icmr[0] = ICMR;
+               ICMR = 0;
+               break;
+#if defined(CONFIG_PXA27x) || defined(CONFIG_PXA3xx)
+       case 1:
+               saved_icmr[1] = ICMR2;
+               ICMR2 = 0;
+               break;
+#endif
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int pxa_irq_resume(struct sys_device *dev)
+{
+       switch (dev->id) {
+       case 0:
+               ICMR = saved_icmr[0];
+               ICLR = 0;
+               ICCR = 1;
+               break;
+#if defined(CONFIG_PXA27x) || defined(CONFIG_PXA3xx)
+       case 1:
+               ICMR2 = saved_icmr[1];
+               ICLR2 = 0;
+               break;
+#endif
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+#else
+#define pxa_irq_suspend                NULL
+#define pxa_irq_resume         NULL
+#endif
+
+struct sysdev_class pxa_irq_sysclass = {
+       .name           = "irq",
+       .suspend        = pxa_irq_suspend,
+       .resume         = pxa_irq_resume,
+};
+
+static int __init pxa_irq_init(void)
+{
+       return sysdev_class_register(&pxa_irq_sysclass);
+}
+
+core_initcall(pxa_irq_init);
index ec1b2d8f61c475db0cbd7b7690b3a8522247e11b..f5809adce298219a46f077d7234dd0a99cf952e3 100644 (file)
@@ -22,6 +22,7 @@
 #include <asm/hardware.h>
 #include <asm/arch/mfp.h>
 #include <asm/arch/mfp-pxa3xx.h>
+#include <asm/arch/pxa3xx-regs.h>
 
 /* mfp_spin_lock is used to ensure that MFP register configuration
  * (most likely a read-modify-write operation) is atomic, and that
@@ -223,11 +224,19 @@ static int pxa3xx_mfp_resume(struct sys_device *d)
                struct pxa3xx_mfp_pin *p = &mfp_table[pin];
                __mfp_config_run(p);
        }
+
+       /* clear RDH bit when MFP settings are restored
+        *
+        * NOTE: the last 3 bits DxS are write-1-to-clear so carefully
+        * preserve them here in case they will be referenced later
+        */
+       ASCR &= ~(ASCR_RDH | ASCR_D1S | ASCR_D2S | ASCR_D3S);
+
        return 0;
 }
 
 static struct sysdev_class mfp_sysclass = {
-       set_kset_name("mfp"),
+       .name           = "mfp",
        .suspend        = pxa3xx_mfp_suspend,
        .resume         = pxa3xx_mfp_resume,
 };
index 540c3bba5f9a8663b508835b0894065015acfc43..c14696b9979dfbaba3e218ab082f3a1d0f77b0d5 100644 (file)
@@ -29,6 +29,7 @@
 #include <asm/mach/arch.h>
 #include <asm/arch/hardware.h>
 #include <asm/arch/pxa-regs.h>
+#include <asm/arch/pxa2xx-regs.h>
 #include <asm/arch/pxa2xx_spi.h>
 #include <asm/arch/pcm027.h>
 #include "generic.h"
index dd54496083cb2d7b89471d53a3e10ec6eb249cff..209eabf0ed3e60917ae29d72c5316efd54cfc8db 100644 (file)
@@ -164,7 +164,7 @@ static struct resource poodlets_resources[] = {
        },
 };
 
-static unsigned long poodle_get_hsync_len(void)
+static unsigned long poodle_get_hsync_invperiod(void)
 {
        return 0;
 }
@@ -174,9 +174,9 @@ static void poodle_null_hsync(void)
 }
 
 static struct corgits_machinfo  poodle_ts_machinfo = {
-       .get_hsync_len   = poodle_get_hsync_len,
-       .put_hsync       = poodle_null_hsync,
-       .wait_hsync      = poodle_null_hsync,
+       .get_hsync_invperiod    = poodle_get_hsync_invperiod,
+       .put_hsync              = poodle_null_hsync,
+       .wait_hsync             = poodle_null_hsync,
 };
 
 static struct platform_device poodle_ts_device = {
index ddd05bf78e022b0952ca06fafc30a2293d770fdf..599e53fcc2c5abb7b039269e506dd8d2d71aeaff 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/suspend.h>
+#include <linux/sysdev.h>
 
 #include <asm/hardware.h>
 #include <asm/arch/irqs.h>
@@ -141,11 +142,6 @@ static struct clk pxa25x_clks[] = {
 #define SAVE(x)                sleep_save[SLEEP_SAVE_##x] = x
 #define RESTORE(x)     x = sleep_save[SLEEP_SAVE_##x]
 
-#define RESTORE_GPLEVEL(n) do { \
-       GPSR##n = sleep_save[SLEEP_SAVE_GPLR##n]; \
-       GPCR##n = ~sleep_save[SLEEP_SAVE_GPLR##n]; \
-} while (0)
-
 /*
  * List of global PXA peripheral registers to preserve.
  * More ones like CP and general purpose register values are preserved
@@ -153,10 +149,6 @@ static struct clk pxa25x_clks[] = {
  */
 enum { SLEEP_SAVE_START = 0,
 
-       SLEEP_SAVE_GPLR0, SLEEP_SAVE_GPLR1, SLEEP_SAVE_GPLR2,
-       SLEEP_SAVE_GPDR0, SLEEP_SAVE_GPDR1, SLEEP_SAVE_GPDR2,
-       SLEEP_SAVE_GRER0, SLEEP_SAVE_GRER1, SLEEP_SAVE_GRER2,
-       SLEEP_SAVE_GFER0, SLEEP_SAVE_GFER1, SLEEP_SAVE_GFER2,
        SLEEP_SAVE_PGSR0, SLEEP_SAVE_PGSR1, SLEEP_SAVE_PGSR2,
 
        SLEEP_SAVE_GAFR0_L, SLEEP_SAVE_GAFR0_U,
@@ -165,7 +157,6 @@ enum {      SLEEP_SAVE_START = 0,
 
        SLEEP_SAVE_PSTR,
 
-       SLEEP_SAVE_ICMR,
        SLEEP_SAVE_CKEN,
 
        SLEEP_SAVE_SIZE
@@ -174,17 +165,12 @@ enum {    SLEEP_SAVE_START = 0,
 
 static void pxa25x_cpu_pm_save(unsigned long *sleep_save)
 {
-       SAVE(GPLR0); SAVE(GPLR1); SAVE(GPLR2);
-       SAVE(GPDR0); SAVE(GPDR1); SAVE(GPDR2);
-       SAVE(GRER0); SAVE(GRER1); SAVE(GRER2);
-       SAVE(GFER0); SAVE(GFER1); SAVE(GFER2);
        SAVE(PGSR0); SAVE(PGSR1); SAVE(PGSR2);
 
        SAVE(GAFR0_L); SAVE(GAFR0_U);
        SAVE(GAFR1_L); SAVE(GAFR1_U);
        SAVE(GAFR2_L); SAVE(GAFR2_U);
 
-       SAVE(ICMR); ICMR = 0;
        SAVE(CKEN);
        SAVE(PSTR);
 
@@ -198,22 +184,14 @@ static void pxa25x_cpu_pm_restore(unsigned long *sleep_save)
        PSPR = 0;
 
        /* restore registers */
-       RESTORE_GPLEVEL(0); RESTORE_GPLEVEL(1); RESTORE_GPLEVEL(2);
-       RESTORE(GPDR0); RESTORE(GPDR1); RESTORE(GPDR2);
        RESTORE(GAFR0_L); RESTORE(GAFR0_U);
        RESTORE(GAFR1_L); RESTORE(GAFR1_U);
        RESTORE(GAFR2_L); RESTORE(GAFR2_U);
-       RESTORE(GRER0); RESTORE(GRER1); RESTORE(GRER2);
-       RESTORE(GFER0); RESTORE(GFER1); RESTORE(GFER2);
        RESTORE(PGSR0); RESTORE(PGSR1); RESTORE(PGSR2);
 
        PSSR = PSSR_RDH | PSSR_PH;
 
        RESTORE(CKEN);
-
-       ICLR = 0;
-       ICCR = 1;
-       RESTORE(ICMR);
        RESTORE(PSTR);
 }
 
@@ -304,9 +282,17 @@ static struct platform_device *pxa25x_devices[] __initdata = {
        &pxa25x_device_assp,
 };
 
+static struct sys_device pxa25x_sysdev[] = {
+       {
+               .cls    = &pxa_irq_sysclass,
+       }, {
+               .cls    = &pxa_gpio_sysclass,
+       },
+};
+
 static int __init pxa25x_init(void)
 {
-       int ret = 0;
+       int i, ret = 0;
 
        /* Only add HWUART for PXA255/26x; PXA210/250/27x do not have it. */
        if (cpu_is_pxa25x())
@@ -320,9 +306,18 @@ static int __init pxa25x_init(void)
 
                pxa25x_init_pm();
 
+               for (i = 0; i < ARRAY_SIZE(pxa25x_sysdev); i++) {
+                       ret = sysdev_register(&pxa25x_sysdev[i]);
+                       if (ret)
+                               pr_err("failed to register sysdev[%d]\n", i);
+               }
+
                ret = platform_add_devices(pxa25x_devices,
                                           ARRAY_SIZE(pxa25x_devices));
+               if (ret)
+                       return ret;
        }
+
        /* Only add HWUART for PXA255/26x; PXA210/250/27x do not have it. */
        if (cpu_is_pxa25x())
                ret = platform_device_register(&pxa_device_hwuart);
index 96cf274ec7cbb7fa9a59c2f48263a06ae791f06f..46a951c3e5a0097e5c280bda04bbca0cf4936fb2 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/init.h>
 #include <linux/suspend.h>
 #include <linux/platform_device.h>
+#include <linux/sysdev.h>
 
 #include <asm/hardware.h>
 #include <asm/irq.h>
@@ -171,11 +172,6 @@ static struct clk pxa27x_clks[] = {
 #define SAVE(x)                sleep_save[SLEEP_SAVE_##x] = x
 #define RESTORE(x)     x = sleep_save[SLEEP_SAVE_##x]
 
-#define RESTORE_GPLEVEL(n) do { \
-       GPSR##n = sleep_save[SLEEP_SAVE_GPLR##n]; \
-       GPCR##n = ~sleep_save[SLEEP_SAVE_GPLR##n]; \
-} while (0)
-
 /*
  * List of global PXA peripheral registers to preserve.
  * More ones like CP and general purpose register values are preserved
@@ -183,10 +179,6 @@ static struct clk pxa27x_clks[] = {
  */
 enum { SLEEP_SAVE_START = 0,
 
-       SLEEP_SAVE_GPLR0, SLEEP_SAVE_GPLR1, SLEEP_SAVE_GPLR2, SLEEP_SAVE_GPLR3,
-       SLEEP_SAVE_GPDR0, SLEEP_SAVE_GPDR1, SLEEP_SAVE_GPDR2, SLEEP_SAVE_GPDR3,
-       SLEEP_SAVE_GRER0, SLEEP_SAVE_GRER1, SLEEP_SAVE_GRER2, SLEEP_SAVE_GRER3,
-       SLEEP_SAVE_GFER0, SLEEP_SAVE_GFER1, SLEEP_SAVE_GFER2, SLEEP_SAVE_GFER3,
        SLEEP_SAVE_PGSR0, SLEEP_SAVE_PGSR1, SLEEP_SAVE_PGSR2, SLEEP_SAVE_PGSR3,
 
        SLEEP_SAVE_GAFR0_L, SLEEP_SAVE_GAFR0_U,
@@ -196,7 +188,6 @@ enum {      SLEEP_SAVE_START = 0,
 
        SLEEP_SAVE_PSTR,
 
-       SLEEP_SAVE_ICMR,
        SLEEP_SAVE_CKEN,
 
        SLEEP_SAVE_MDREFR,
@@ -208,10 +199,6 @@ enum {     SLEEP_SAVE_START = 0,
 
 void pxa27x_cpu_pm_save(unsigned long *sleep_save)
 {
-       SAVE(GPLR0); SAVE(GPLR1); SAVE(GPLR2); SAVE(GPLR3);
-       SAVE(GPDR0); SAVE(GPDR1); SAVE(GPDR2); SAVE(GPDR3);
-       SAVE(GRER0); SAVE(GRER1); SAVE(GRER2); SAVE(GRER3);
-       SAVE(GFER0); SAVE(GFER1); SAVE(GFER2); SAVE(GFER3);
        SAVE(PGSR0); SAVE(PGSR1); SAVE(PGSR2); SAVE(PGSR3);
 
        SAVE(GAFR0_L); SAVE(GAFR0_U);
@@ -223,12 +210,8 @@ void pxa27x_cpu_pm_save(unsigned long *sleep_save)
        SAVE(PWER); SAVE(PCFR); SAVE(PRER);
        SAVE(PFER); SAVE(PKWR);
 
-       SAVE(ICMR); ICMR = 0;
        SAVE(CKEN);
        SAVE(PSTR);
-
-       /* Clear GPIO transition detect bits */
-       GEDR0 = GEDR0; GEDR1 = GEDR1; GEDR2 = GEDR2; GEDR3 = GEDR3;
 }
 
 void pxa27x_cpu_pm_restore(unsigned long *sleep_save)
@@ -237,15 +220,10 @@ void pxa27x_cpu_pm_restore(unsigned long *sleep_save)
        PSPR = 0;
 
        /* restore registers */
-       RESTORE_GPLEVEL(0); RESTORE_GPLEVEL(1);
-       RESTORE_GPLEVEL(2); RESTORE_GPLEVEL(3);
-       RESTORE(GPDR0); RESTORE(GPDR1); RESTORE(GPDR2); RESTORE(GPDR3);
        RESTORE(GAFR0_L); RESTORE(GAFR0_U);
        RESTORE(GAFR1_L); RESTORE(GAFR1_U);
        RESTORE(GAFR2_L); RESTORE(GAFR2_U);
        RESTORE(GAFR3_L); RESTORE(GAFR3_U);
-       RESTORE(GRER0); RESTORE(GRER1); RESTORE(GRER2); RESTORE(GRER3);
-       RESTORE(GFER0); RESTORE(GFER1); RESTORE(GFER2); RESTORE(GFER3);
        RESTORE(PGSR0); RESTORE(PGSR1); RESTORE(PGSR2); RESTORE(PGSR3);
 
        RESTORE(MDREFR);
@@ -256,9 +234,6 @@ void pxa27x_cpu_pm_restore(unsigned long *sleep_save)
 
        RESTORE(CKEN);
 
-       ICLR = 0;
-       ICCR = 1;
-       RESTORE(ICMR);
        RESTORE(PSTR);
 }
 
@@ -409,9 +384,22 @@ static struct platform_device *devices[] __initdata = {
        &pxa27x_device_ssp3,
 };
 
+static struct sys_device pxa27x_sysdev[] = {
+       {
+               .id     = 0,
+               .cls    = &pxa_irq_sysclass,
+       }, {
+               .id     = 1,
+               .cls    = &pxa_irq_sysclass,
+       }, {
+               .cls    = &pxa_gpio_sysclass,
+       },
+};
+
 static int __init pxa27x_init(void)
 {
-       int ret = 0;
+       int i, ret = 0;
+
        if (cpu_is_pxa27x()) {
                clks_register(pxa27x_clks, ARRAY_SIZE(pxa27x_clks));
 
@@ -420,8 +408,15 @@ static int __init pxa27x_init(void)
 
                pxa27x_init_pm();
 
+               for (i = 0; i < ARRAY_SIZE(pxa27x_sysdev); i++) {
+                       ret = sysdev_register(&pxa27x_sysdev[i]);
+                       if (ret)
+                               pr_err("failed to register sysdev[%d]\n", i);
+               }
+
                ret = platform_add_devices(devices, ARRAY_SIZE(devices));
        }
+
        return ret;
 }
 
index 5cbf057a1b32f4ce2c6f05d137efad8f086d0c74..e47e67c11afe65dfbc10f234c1dbfe8dc636cf32 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/platform_device.h>
 #include <linux/irq.h>
 #include <linux/io.h>
+#include <linux/sysdev.h>
 
 #include <asm/hardware.h>
 #include <asm/arch/pxa3xx-regs.h>
@@ -39,6 +40,7 @@
 #define RO_CLK         60000000
 
 #define ACCR_D0CS      (1 << 26)
+#define ACCR_PCCE      (1 << 11)
 
 /* crystal frequency to static memory controller multiplier (SMCFS) */
 static unsigned char smcfs_mult[8] = { 6, 0, 8, 0, 0, 16, };
@@ -203,7 +205,6 @@ static struct clk pxa3xx_clks[] = {
 };
 
 #ifdef CONFIG_PM
-#define SLEEP_SAVE_SIZE        4
 
 #define ISRAM_START    0x5c000000
 #define ISRAM_SIZE     SZ_256K
@@ -211,25 +212,29 @@ static struct clk pxa3xx_clks[] = {
 static void __iomem *sram;
 static unsigned long wakeup_src;
 
-static void pxa3xx_cpu_pm_save(unsigned long *sleep_save)
-{
-       pr_debug("PM: CKENA=%08x CKENB=%08x\n", CKENA, CKENB);
+#define SAVE(x)                sleep_save[SLEEP_SAVE_##x] = x
+#define RESTORE(x)     x = sleep_save[SLEEP_SAVE_##x]
 
-       if (CKENA & (1 << CKEN_USBH)) {
-               printk(KERN_ERR "PM: USB host clock not stopped?\n");
-               CKENA &= ~(1 << CKEN_USBH);
-       }
-//     CKENA |= 1 << (CKEN_ISC & 31);
+enum { SLEEP_SAVE_START = 0,
+       SLEEP_SAVE_CKENA,
+       SLEEP_SAVE_CKENB,
+       SLEEP_SAVE_ACCR,
 
-       /*
-        * Low power modes require the HSIO2 clock to be enabled.
-        */
-       CKENB |= 1 << (CKEN_HSIO2 & 31);
+       SLEEP_SAVE_SIZE,
+};
+
+static void pxa3xx_cpu_pm_save(unsigned long *sleep_save)
+{
+       SAVE(CKENA);
+       SAVE(CKENB);
+       SAVE(ACCR);
 }
 
 static void pxa3xx_cpu_pm_restore(unsigned long *sleep_save)
 {
-       CKENB &= ~(1 << (CKEN_HSIO2 & 31));
+       RESTORE(ACCR);
+       RESTORE(CKENA);
+       RESTORE(CKENB);
 }
 
 /*
@@ -265,6 +270,46 @@ static void pxa3xx_cpu_standby(unsigned int pwrmode)
        printk("PM: AD2D0SR=%08x ASCR=%08x\n", AD2D0SR, ASCR);
 }
 
+/*
+ * NOTE:  currently, the OBM (OEM Boot Module) binary comes along with
+ * PXA3xx development kits assumes that the resuming process continues
+ * with the address stored within the first 4 bytes of SDRAM. The PSPR
+ * register is used privately by BootROM and OBM, and _must_ be set to
+ * 0x5c014000 for the moment.
+ */
+static void pxa3xx_cpu_pm_suspend(void)
+{
+       volatile unsigned long *p = (volatile void *)0xc0000000;
+       unsigned long saved_data = *p;
+
+       extern void pxa3xx_cpu_suspend(void);
+       extern void pxa3xx_cpu_resume(void);
+
+       /* resuming from D2 requires the HSIO2/BOOT/TPM clocks enabled */
+       CKENA |= (1 << CKEN_BOOT) | (1 << CKEN_TPM);
+       CKENB |= 1 << (CKEN_HSIO2 & 0x1f);
+
+       /* clear and setup wakeup source */
+       AD3SR = ~0;
+       AD3ER = wakeup_src;
+       ASCR = ASCR;
+       ARSR = ARSR;
+
+       PCFR |= (1u << 13);                     /* L1_DIS */
+       PCFR &= ~((1u << 12) | (1u << 1));      /* L0_EN | SL_ROD */
+
+       PSPR = 0x5c014000;
+
+       /* overwrite with the resume address */
+       *p = virt_to_phys(pxa3xx_cpu_resume);
+
+       pxa3xx_cpu_suspend();
+
+       *p = saved_data;
+
+       AD3ER = 0;
+}
+
 static void pxa3xx_cpu_pm_enter(suspend_state_t state)
 {
        /*
@@ -279,6 +324,7 @@ static void pxa3xx_cpu_pm_enter(suspend_state_t state)
                break;
 
        case PM_SUSPEND_MEM:
+               pxa3xx_cpu_pm_suspend();
                break;
        }
 }
@@ -452,9 +498,21 @@ static struct platform_device *devices[] __initdata = {
        &pxa3xx_device_ssp4,
 };
 
+static struct sys_device pxa3xx_sysdev[] = {
+       {
+               .id     = 0,
+               .cls    = &pxa_irq_sysclass,
+       }, {
+               .id     = 1,
+               .cls    = &pxa_irq_sysclass,
+       }, {
+               .cls    = &pxa_gpio_sysclass,
+       },
+};
+
 static int __init pxa3xx_init(void)
 {
-       int ret = 0;
+       int i, ret = 0;
 
        if (cpu_is_pxa3xx()) {
                clks_register(pxa3xx_clks, ARRAY_SIZE(pxa3xx_clks));
@@ -464,9 +522,16 @@ static int __init pxa3xx_init(void)
 
                pxa3xx_init_pm();
 
-               return platform_add_devices(devices, ARRAY_SIZE(devices));
+               for (i = 0; i < ARRAY_SIZE(pxa3xx_sysdev); i++) {
+                       ret = sysdev_register(&pxa3xx_sysdev[i]);
+                       if (ret)
+                               pr_err("failed to register sysdev[%d]\n", i);
+               }
+
+               ret = platform_add_devices(devices, ARRAY_SIZE(devices));
        }
-       return 0;
+
+       return ret;
 }
 
 subsys_initcall(pxa3xx_init);
index 14bb4a93ea524e814c481e2b42123727471580b9..784716eb7fc5735a3e6b6209223508984013819f 100644 (file)
@@ -50,6 +50,108 @@ pxa_cpu_save_sp:
        str     r0, [r1]
        ldr     pc, [sp], #4
 
+#ifdef CONFIG_PXA3xx
+/*
+ * pxa3xx_cpu_suspend() - forces CPU into sleep state (S2D3C4)
+ *
+ * NOTE:  unfortunately, pxa_cpu_save_cp can not be reused here since
+ * the auxiliary control register address is different between pxa3xx
+ * and pxa{25x,27x}
+ */
+
+ENTRY(pxa3xx_cpu_suspend)
+
+#ifndef CONFIG_IWMMXT
+       mra     r2, r3, acc0
+#endif
+       stmfd   sp!, {r2 - r12, lr}     @ save registers on stack
+
+       mrc     p14, 0, r3, c6, c0, 0           @ clock configuration, for turbo mode
+       mrc     p15, 0, r4, c15, c1, 0          @ CP access reg
+       mrc     p15, 0, r5, c13, c0, 0          @ PID
+       mrc     p15, 0, r6, c3, c0, 0           @ domain ID
+       mrc     p15, 0, r7, c2, c0, 0           @ translation table base addr
+       mrc     p15, 0, r8, c1, c0, 1           @ auxiliary control reg
+       mrc     p15, 0, r9, c1, c0, 0           @ control reg
+
+       bic     r3, r3, #2                      @ clear frequency change bit
+
+       @ store them plus current virtual stack ptr on stack
+       mov     r10, sp
+       stmfd   sp!, {r3 - r10}
+
+       @ store physical address of stack pointer
+       mov     r0, sp
+       bl      sleep_phys_sp
+       ldr     r1, =sleep_save_sp
+       str     r0, [r1]
+
+       @ clean data cache
+       bl      xsc3_flush_kern_cache_all
+
+       mov     r0, #0x06               @ S2D3C4 mode
+       mcr     p14, 0, r0, c7, c0, 0   @ enter sleep
+
+20:    b       20b                     @ waiting for sleep
+
+       .data
+       .align 5
+/*
+ * pxa3xx_cpu_resume
+ */
+
+ENTRY(pxa3xx_cpu_resume)
+
+       mov     r0, #PSR_I_BIT | PSR_F_BIT | SVC_MODE   @ set SVC, irqs off
+       msr     cpsr_c, r0
+
+       ldr     r0, sleep_save_sp               @ stack phys addr
+       ldmfd   r0, {r3 - r9, sp}               @ CP regs + virt stack ptr
+
+       mov     r1, #0
+       mcr     p15, 0, r1, c7, c7, 0           @ invalidate I & D caches, BTB
+       mcr     p15, 0, r1, c7, c10, 4          @ drain write (&fill) buffer
+       mcr     p15, 0, r1, c7, c5, 4           @ flush prefetch buffer
+       mcr     p15, 0, r1, c8, c7, 0           @ invalidate I & D TLBs
+
+       mcr     p14, 0, r3, c6, c0, 0           @ clock configuration, turbo mode.
+       mcr     p15, 0, r4, c15, c1, 0          @ CP access reg
+       mcr     p15, 0, r5, c13, c0, 0          @ PID
+       mcr     p15, 0, r6, c3, c0, 0           @ domain ID
+       mcr     p15, 0, r7, c2, c0, 0           @ translation table base addr
+       mcr     p15, 0, r8, c1, c0, 1           @ auxiliary control reg
+
+       @ temporarily map resume_turn_on_mmu into the page table,
+       @ otherwise prefetch abort occurs after MMU is turned on
+       mov     r1, r7
+       bic     r1, r1, #0x00ff
+       bic     r1, r1, #0x3f00
+       ldr     r2, =0x542e
+
+       adr     r3, resume_turn_on_mmu
+       mov     r3, r3, lsr #20
+       orr     r4, r2, r3, lsl #20
+       ldr     r5, [r1, r3, lsl #2]
+       str     r4, [r1, r3, lsl #2]
+
+       @ Mapping page table address in the page table
+       mov     r6, r1, lsr #20
+       orr     r7, r2, r6, lsl #20
+       ldr     r8, [r1, r6, lsl #2]
+       str     r7, [r1, r6, lsl #2]
+
+       ldr     r2, =pxa3xx_resume_after_mmu    @ absolute virtual address
+       b       resume_turn_on_mmu              @ cache align execution
+
+       .text
+pxa3xx_resume_after_mmu:
+       /* restore the temporary mapping */
+       str     r5, [r1, r3, lsl #2]
+       str     r8, [r1, r6, lsl #2]
+       b       resume_after_mmu
+
+#endif /* CONFIG_PXA3xx */
+
 #ifdef CONFIG_PXA27x
 /*
  * pxa27x_cpu_suspend()
diff --git a/arch/arm/mach-pxa/smemc.c b/arch/arm/mach-pxa/smemc.c
new file mode 100644 (file)
index 0000000..ad346ad
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * Static Memory Controller
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/sysdev.h>
+
+#define SMEMC_PHYS_BASE        (0x4A000000)
+#define SMEMC_PHYS_SIZE        (0x90)
+
+#define MSC0           (0x08)  /* Static Memory Controller Register 0 */
+#define MSC1           (0x0C)  /* Static Memory Controller Register 1 */
+#define SXCNFG         (0x1C)  /* Synchronous Static Memory Control Register */
+#define MEMCLKCFG      (0x68)  /* Clock Configuration */
+#define CSADRCFG0      (0x80)  /* Address Configuration Register for CS0 */
+#define CSADRCFG1      (0x84)  /* Address Configuration Register for CS1 */
+#define CSADRCFG2      (0x88)  /* Address Configuration Register for CS2 */
+#define CSADRCFG3      (0x8C)  /* Address Configuration Register for CS3 */
+
+#ifdef CONFIG_PM
+static void __iomem *smemc_mmio_base;
+
+static unsigned long msc[2];
+static unsigned long sxcnfg, memclkcfg;
+static unsigned long csadrcfg[4];
+
+static int pxa3xx_smemc_suspend(struct sys_device *dev, pm_message_t state)
+{
+       msc[0] = __raw_readl(smemc_mmio_base + MSC0);
+       msc[1] = __raw_readl(smemc_mmio_base + MSC1);
+       sxcnfg = __raw_readl(smemc_mmio_base + SXCNFG);
+       memclkcfg = __raw_readl(smemc_mmio_base + MEMCLKCFG);
+       csadrcfg[0] = __raw_readl(smemc_mmio_base + CSADRCFG0);
+       csadrcfg[1] = __raw_readl(smemc_mmio_base + CSADRCFG1);
+       csadrcfg[2] = __raw_readl(smemc_mmio_base + CSADRCFG2);
+       csadrcfg[3] = __raw_readl(smemc_mmio_base + CSADRCFG3);
+
+       return 0;
+}
+
+static int pxa3xx_smemc_resume(struct sys_device *dev)
+{
+       __raw_writel(msc[0], smemc_mmio_base + MSC0);
+       __raw_writel(msc[1], smemc_mmio_base + MSC1);
+       __raw_writel(sxcnfg, smemc_mmio_base + SXCNFG);
+       __raw_writel(memclkcfg, smemc_mmio_base + MEMCLKCFG);
+       __raw_writel(csadrcfg[0], smemc_mmio_base + CSADRCFG0);
+       __raw_writel(csadrcfg[1], smemc_mmio_base + CSADRCFG1);
+       __raw_writel(csadrcfg[2], smemc_mmio_base + CSADRCFG2);
+       __raw_writel(csadrcfg[3], smemc_mmio_base + CSADRCFG3);
+
+       return 0;
+}
+
+static struct sysdev_class smemc_sysclass = {
+       .name           = "smemc",
+       .suspend        = pxa3xx_smemc_suspend,
+       .resume         = pxa3xx_smemc_resume,
+};
+
+static struct sys_device smemc_sysdev = {
+       .id             = 0,
+       .cls            = &smemc_sysclass,
+};
+
+static int __init smemc_init(void)
+{
+       int ret = 0;
+
+       if (cpu_is_pxa3xx()) {
+               smemc_mmio_base = ioremap(SMEMC_PHYS_BASE, SMEMC_PHYS_SIZE);
+               if (smemc_mmio_base == NULL)
+                       return -ENODEV;
+
+               ret = sysdev_class_register(&smemc_sysclass);
+               if (ret)
+                       return ret;
+
+               ret = sysdev_register(&smemc_sysdev);
+       }
+
+       return ret;
+}
+subsys_initcall(smemc_init);
+#endif
index 5078edeadf9637ef0be1ca626e0043a0a3dcebc8..9e7773fca01cf391abbe3ccf79e841c8f9f0ab47 100644 (file)
@@ -36,6 +36,7 @@
 #include <asm/mach/irq.h>
 
 #include <asm/arch/pxa-regs.h>
+#include <asm/arch/pxa2xx-regs.h>
 #include <asm/arch/irda.h>
 #include <asm/arch/mmc.h>
 #include <asm/arch/ohci.h>
index 1919756900f48daa9c12d64508a218a86f330f75..9b26fa5edad69200756d02384cdfcb941e8911d7 100644 (file)
@@ -29,6 +29,7 @@
 #include <asm/irq.h>
 #include <asm/system.h>
 #include <asm/arch/pxa-regs.h>
+#include <asm/arch/pxa2xx-regs.h>
 #include <asm/arch/irda.h>
 #include <asm/arch/mmc.h>
 #include <asm/arch/udc.h>
@@ -157,15 +158,10 @@ static void tosa_udc_command(int cmd)
        }
 }
 
-static int tosa_udc_is_connected(void)
-{
-       return ((GPLR(TOSA_GPIO_USB_IN) & GPIO_bit(TOSA_GPIO_USB_IN)) == 0);
-}
-
-
 static struct pxa2xx_udc_mach_info udc_info __initdata = {
        .udc_command            = tosa_udc_command,
-       .udc_is_connected       = tosa_udc_is_connected,
+       .gpio_vbus              = TOSA_GPIO_USB_IN,
+       .gpio_vbus_inverted     = 1,
 };
 
 /*
index 35156ca39df77e6a62414f30f879119e12b513df..39b3bb7f1020b35725ead58c7d5e051ce8ce0170 100644 (file)
@@ -7,24 +7,21 @@ config MACH_REALVIEW_EB
        help
          Include support for the ARM(R) RealView Emulation Baseboard platform.
 
-config REALVIEW_MPCORE
-       bool "Support MPcore tile"
+config REALVIEW_EB_ARM11MP
+       bool "Support ARM11MPCore tile"
        depends on MACH_REALVIEW_EB
        select CACHE_L2X0
        help
-         Enable support for the MPCore tile on the Realview platform.
-         Since there are device address and interrupt differences, a
-         kernel built with this option enabled is not compatible with
-         other tiles.
+         Enable support for the ARM11MPCore tile on the Realview platform.
 
-config REALVIEW_MPCORE_REVB
-       bool "Support MPcore RevB tile"
-       depends on REALVIEW_MPCORE
+config REALVIEW_EB_ARM11MP_REVB
+       bool "Support ARM11MPCore RevB tile"
+       depends on REALVIEW_EB_ARM11MP
        default n
        help
-         Enable support for the MPCore RevB tile on the Realview platform.
-         Since there are device address differences, a
+         Enable support for the ARM11MPCore RevB tile on the Realview
+         platform. Since there are device address differences, a
          kernel built with this option enabled is not compatible with
-         other tiles.
+         other revisions of the ARM11MPCore tile.
 
 endmenu
index 36e76ba937fc031286eeb4fa7acf46b13e37cd64..ca1e390c3c28795f3873bc8249e3eb3c74a8f078 100644 (file)
@@ -4,6 +4,5 @@
 
 obj-y                                  := core.o clock.o
 obj-$(CONFIG_MACH_REALVIEW_EB)         += realview_eb.o
-obj-$(CONFIG_SMP)                      += platsmp.o headsmp.o
+obj-$(CONFIG_SMP)                      += platsmp.o headsmp.o localtimer.o
 obj-$(CONFIG_HOTPLUG_CPU)              += hotplug.o
-obj-$(CONFIG_LOCAL_TIMERS)             += localtimer.o
index 61d70218f1e8adc60aee99d0e044700cb2fe6fd2..98aefc9f4df3bb3b81e6237b900a61d3930429fb 100644 (file)
@@ -25,6 +25,8 @@
 #include <linux/interrupt.h>
 #include <linux/amba/bus.h>
 #include <linux/amba/clcd.h>
+#include <linux/clocksource.h>
+#include <linux/clockchips.h>
 
 #include <asm/system.h>
 #include <asm/hardware.h>
@@ -37,7 +39,6 @@
 #include <asm/mach/arch.h>
 #include <asm/mach/flash.h>
 #include <asm/mach/irq.h>
-#include <asm/mach/time.h>
 #include <asm/mach/map.h>
 #include <asm/mach/mmc.h>
 
@@ -48,6 +49,9 @@
 
 #define REALVIEW_REFCOUNTER    (__io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_24MHz_OFFSET)
 
+/* used by entry-macro.S */
+void __iomem *gic_cpu_base_addr;
+
 /*
  * This is the RealView sched_clock implementation.  This has
  * a resolution of 41.7ns, and a maximum value of about 179s.
@@ -121,26 +125,6 @@ struct platform_device realview_flash_device = {
        .resource               = &realview_flash_resource,
 };
 
-static struct resource realview_smc91x_resources[] = {
-       [0] = {
-               .start          = REALVIEW_ETH_BASE,
-               .end            = REALVIEW_ETH_BASE + SZ_64K - 1,
-               .flags          = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start          = IRQ_ETH,
-               .end            = IRQ_ETH,
-               .flags          = IORESOURCE_IRQ,
-       },
-};
-
-struct platform_device realview_smc91x_device = {
-       .name           = "smc91x",
-       .id             = 0,
-       .num_resources  = ARRAY_SIZE(realview_smc91x_resources),
-       .resource       = realview_smc91x_resources,
-};
-
 static struct resource realview_i2c_resource = {
        .start          = REALVIEW_I2C_BASE,
        .end            = REALVIEW_I2C_BASE + SZ_4K - 1,
@@ -484,45 +468,64 @@ void realview_leds_event(led_event_t ledevt)
 #define TICKS2USECS(x) ((x) / TICKS_PER_uSEC)
 #endif
 
-/*
- * Returns number of ms since last clock interrupt.  Note that interrupts
- * will have been disabled by do_gettimeoffset()
- */
-static unsigned long realview_gettimeoffset(void)
+static void timer_set_mode(enum clock_event_mode mode,
+                          struct clock_event_device *clk)
 {
-       unsigned long ticks1, ticks2, status;
+       unsigned long ctrl;
 
-       /*
-        * Get the current number of ticks.  Note that there is a race
-        * condition between us reading the timer and checking for
-        * an interrupt.  We get around this by ensuring that the
-        * counter has not reloaded between our two reads.
-        */
-       ticks2 = readl(TIMER0_VA_BASE + TIMER_VALUE) & 0xffff;
-       do {
-               ticks1 = ticks2;
-               status = __raw_readl(__io_address(REALVIEW_GIC_DIST_BASE + GIC_DIST_PENDING_SET)
-                                    + ((IRQ_TIMERINT0_1 >> 5) << 2));
-               ticks2 = readl(TIMER0_VA_BASE + TIMER_VALUE) & 0xffff;
-       } while (ticks2 > ticks1);
+       switch(mode) {
+       case CLOCK_EVT_MODE_PERIODIC:
+               writel(TIMER_RELOAD, TIMER0_VA_BASE + TIMER_LOAD);
 
-       /*
-        * Number of ticks since last interrupt.
-        */
-       ticks1 = TIMER_RELOAD - ticks2;
+               ctrl = TIMER_CTRL_PERIODIC;
+               ctrl |= TIMER_CTRL_32BIT | TIMER_CTRL_IE | TIMER_CTRL_ENABLE;
+               break;
+       case CLOCK_EVT_MODE_ONESHOT:
+               /* period set, and timer enabled in 'next_event' hook */
+               ctrl = TIMER_CTRL_ONESHOT;
+               ctrl |= TIMER_CTRL_32BIT | TIMER_CTRL_IE;
+               break;
+       case CLOCK_EVT_MODE_UNUSED:
+       case CLOCK_EVT_MODE_SHUTDOWN:
+       default:
+               ctrl = 0;
+       }
 
-       /*
-        * Interrupt pending?  If so, we've reloaded once already.
-        *
-        * FIXME: Need to check this is effectively timer 0 that expires
-        */
-       if (status & IRQMASK_TIMERINT0_1)
-               ticks1 += TIMER_RELOAD;
+       writel(ctrl, TIMER0_VA_BASE + TIMER_CTRL);
+}
 
-       /*
-        * Convert the ticks to usecs
-        */
-       return TICKS2USECS(ticks1);
+static int timer_set_next_event(unsigned long evt,
+                               struct clock_event_device *unused)
+{
+       unsigned long ctrl = readl(TIMER0_VA_BASE + TIMER_CTRL);
+
+       writel(evt, TIMER0_VA_BASE + TIMER_LOAD);
+       writel(ctrl | TIMER_CTRL_ENABLE, TIMER0_VA_BASE + TIMER_CTRL);
+
+       return 0;
+}
+
+static struct clock_event_device timer0_clockevent =    {
+       .name           = "timer0",
+       .shift          = 32,
+       .features       = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
+       .set_mode       = timer_set_mode,
+       .set_next_event = timer_set_next_event,
+       .rating         = 300,
+       .cpumask        = CPU_MASK_ALL,
+};
+
+static void __init realview_clockevents_init(unsigned int timer_irq)
+{
+       timer0_clockevent.irq = timer_irq;
+       timer0_clockevent.mult =
+               div_sc(1000000, NSEC_PER_SEC, timer0_clockevent.shift);
+       timer0_clockevent.max_delta_ns =
+               clockevent_delta2ns(0xffffffff, &timer0_clockevent);
+       timer0_clockevent.min_delta_ns =
+               clockevent_delta2ns(0xf, &timer0_clockevent);
+
+       clockevents_register_device(&timer0_clockevent);
 }
 
 /*
@@ -530,15 +533,12 @@ static unsigned long realview_gettimeoffset(void)
  */
 static irqreturn_t realview_timer_interrupt(int irq, void *dev_id)
 {
-       // ...clear the interrupt
+       struct clock_event_device *evt = &timer0_clockevent;
+
+       /* clear the interrupt */
        writel(1, TIMER0_VA_BASE + TIMER_INTCLR);
 
-       timer_tick();
-
-#if defined(CONFIG_SMP) && !defined(CONFIG_LOCAL_TIMERS)
-       smp_send_timer();
-       update_process_times(user_mode(get_irq_regs()));
-#endif
+       evt->event_handler(evt);
 
        return IRQ_HANDLED;
 }
@@ -549,13 +549,49 @@ static struct irqaction realview_timer_irq = {
        .handler        = realview_timer_interrupt,
 };
 
+static cycle_t realview_get_cycles(void)
+{
+       return ~readl(TIMER3_VA_BASE + TIMER_VALUE);
+}
+
+static struct clocksource clocksource_realview = {
+       .name   = "timer3",
+       .rating = 200,
+       .read   = realview_get_cycles,
+       .mask   = CLOCKSOURCE_MASK(32),
+       .shift  = 20,
+       .flags  = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+static void __init realview_clocksource_init(void)
+{
+       /* setup timer 0 as free-running clocksource */
+       writel(0, TIMER3_VA_BASE + TIMER_CTRL);
+       writel(0xffffffff, TIMER3_VA_BASE + TIMER_LOAD);
+       writel(0xffffffff, TIMER3_VA_BASE + TIMER_VALUE);
+       writel(TIMER_CTRL_32BIT | TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC,
+               TIMER3_VA_BASE + TIMER_CTRL);
+
+       clocksource_realview.mult =
+               clocksource_khz2mult(1000, clocksource_realview.shift);
+       clocksource_register(&clocksource_realview);
+}
+
 /*
- * Set up timer interrupt, and return the current time in seconds.
+ * Set up the clock source and clock events devices
  */
-static void __init realview_timer_init(void)
+void __init realview_timer_init(unsigned int timer_irq)
 {
        u32 val;
 
+#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST
+       /*
+        * The dummy clock device has to be registered before the main device
+        * so that the latter will broadcast the clock events
+        */
+       local_timer_setup(smp_processor_id());
+#endif
+
        /* 
         * set clock frequency: 
         *      REALVIEW_REFCLK is 32KHz
@@ -576,18 +612,11 @@ static void __init realview_timer_init(void)
        writel(0, TIMER2_VA_BASE + TIMER_CTRL);
        writel(0, TIMER3_VA_BASE + TIMER_CTRL);
 
-       writel(TIMER_RELOAD, TIMER0_VA_BASE + TIMER_LOAD);
-       writel(TIMER_RELOAD, TIMER0_VA_BASE + TIMER_VALUE);
-       writel(TIMER_DIVISOR | TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC |
-              TIMER_CTRL_IE, TIMER0_VA_BASE + TIMER_CTRL);
-
        /* 
         * Make irqs happen for the system timer
         */
-       setup_irq(IRQ_TIMERINT0_1, &realview_timer_irq);
-}
+       setup_irq(timer_irq, &realview_timer_irq);
 
-struct sys_timer realview_timer = {
-       .init           = realview_timer_init,
-       .offset         = realview_gettimeoffset,
-};
+       realview_clocksource_init();
+       realview_clockevents_init(timer_irq);
+}
index 2b53420f9c1b41181c82e77120acd336bcdcd823..492a14c0d604baa39e8234f51e3b215aca41004e 100644 (file)
@@ -27,8 +27,6 @@
 #include <asm/leds.h>
 #include <asm/io.h>
 
-extern struct sys_timer realview_timer;
-
 #define AMBA_DEVICE(name,busid,base,plat)                      \
 static struct amba_device name##_device = {                    \
        .dev            = {                                     \
@@ -38,7 +36,7 @@ static struct amba_device name##_device = {                   \
        },                                                      \
        .res            = {                                     \
                .start  = REALVIEW_##base##_BASE,               \
-               .end    = (REALVIEW_##base##_BASE) + SZ_4K - 1,\
+               .end    = (REALVIEW_##base##_BASE) + SZ_4K - 1, \
                .flags  = IORESOURCE_MEM,                       \
        },                                                      \
        .dma_mask       = ~0,                                   \
@@ -46,74 +44,19 @@ static struct amba_device name##_device = {                 \
        /* .dma         = base##_DMA,*/                         \
 }
 
-/*
- * These devices are connected via the core APB bridge
- */
-#define GPIO2_IRQ      { IRQ_GPIOINT2, NO_IRQ }
-#define GPIO2_DMA      { 0, 0 }
-#define GPIO3_IRQ      { IRQ_GPIOINT3, NO_IRQ }
-#define GPIO3_DMA      { 0, 0 }
-
-#define AACI_IRQ       { IRQ_AACI, NO_IRQ }
-#define AACI_DMA       { 0x80, 0x81 }
-#define MMCI0_IRQ      { IRQ_MMCI0A,IRQ_MMCI0B }
-#define MMCI0_DMA      { 0x84, 0 }
-#define KMI0_IRQ       { IRQ_KMI0, NO_IRQ }
-#define KMI0_DMA       { 0, 0 }
-#define KMI1_IRQ       { IRQ_KMI1, NO_IRQ }
-#define KMI1_DMA       { 0, 0 }
-
-/*
- * These devices are connected directly to the multi-layer AHB switch
- */
-#define SMC_IRQ                { NO_IRQ, NO_IRQ }
-#define SMC_DMA                { 0, 0 }
-#define MPMC_IRQ       { NO_IRQ, NO_IRQ }
-#define MPMC_DMA       { 0, 0 }
-#define CLCD_IRQ       { IRQ_CLCDINT, NO_IRQ }
-#define CLCD_DMA       { 0, 0 }
-#define DMAC_IRQ       { IRQ_DMAINT, NO_IRQ }
-#define DMAC_DMA       { 0, 0 }
-
-/*
- * These devices are connected via the core APB bridge
- */
-#define SCTL_IRQ       { NO_IRQ, NO_IRQ }
-#define SCTL_DMA       { 0, 0 }
-#define WATCHDOG_IRQ   { IRQ_WDOGINT, NO_IRQ }
-#define WATCHDOG_DMA   { 0, 0 }
-#define GPIO0_IRQ      { IRQ_GPIOINT0, NO_IRQ }
-#define GPIO0_DMA      { 0, 0 }
-#define GPIO1_IRQ      { IRQ_GPIOINT1, NO_IRQ }
-#define GPIO1_DMA      { 0, 0 }
-#define RTC_IRQ                { IRQ_RTCINT, NO_IRQ }
-#define RTC_DMA                { 0, 0 }
-
-/*
- * These devices are connected via the DMA APB bridge
- */
-#define SCI_IRQ                { IRQ_SCIINT, NO_IRQ }
-#define SCI_DMA                { 7, 6 }
-#define UART0_IRQ      { IRQ_UARTINT0, NO_IRQ }
-#define UART0_DMA      { 15, 14 }
-#define UART1_IRQ      { IRQ_UARTINT1, NO_IRQ }
-#define UART1_DMA      { 13, 12 }
-#define UART2_IRQ      { IRQ_UARTINT2, NO_IRQ }
-#define UART2_DMA      { 11, 10 }
-#define UART3_IRQ      { IRQ_UART3, NO_IRQ }
-#define UART3_DMA      { 0x86, 0x87 }
-#define SSP_IRQ                { IRQ_SSPINT, NO_IRQ }
-#define SSP_DMA                { 9, 8 }
-
-
 extern struct platform_device realview_flash_device;
-extern struct platform_device realview_smc91x_device;
 extern struct platform_device realview_i2c_device;
 extern struct mmc_platform_data realview_mmc0_plat_data;
 extern struct mmc_platform_data realview_mmc1_plat_data;
 extern struct clk realview_clcd_clk;
 extern struct clcd_board clcd_plat_data;
+extern void __iomem *gic_cpu_base_addr;
+#ifdef CONFIG_LOCAL_TIMERS
+extern void __iomem *twd_base_addr;
+extern unsigned int twd_size;
+#endif
 
 extern void realview_leds_event(led_event_t ledevt);
+extern void realview_timer_init(unsigned int timer_irq);
 
 #endif
index c7bdf04ab094d1f82f2afbb52c204154cf0dfef4..50604360479fa9d3d8ecace270aba49f8f8454e2 100644 (file)
 #include <linux/device.h>
 #include <linux/smp.h>
 #include <linux/jiffies.h>
+#include <linux/percpu.h>
+#include <linux/clockchips.h>
+#include <linux/irq.h>
 
-#include <asm/mach/time.h>
 #include <asm/hardware/arm_twd.h>
 #include <asm/hardware/gic.h>
 #include <asm/hardware.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 
-#define TWD_BASE(cpu)  (__io_address(REALVIEW_TWD_BASE) + \
-                        ((cpu) * REALVIEW_TWD_SIZE))
+static DEFINE_PER_CPU(struct clock_event_device, local_clockevent);
+
+/*
+ * Used on SMP for either the local timer or IPI_TIMER
+ */
+void local_timer_interrupt(void)
+{
+       struct clock_event_device *clk = &__get_cpu_var(local_clockevent);
+
+       clk->event_handler(clk);
+}
+
+#ifdef CONFIG_LOCAL_TIMERS
+
+#define TWD_BASE(cpu)  (twd_base_addr + (cpu) * twd_size)
+
+/* set up by the platform code */
+void __iomem *twd_base_addr;
+unsigned int twd_size;
 
 static unsigned long mpcore_timer_rate;
 
+static void local_timer_set_mode(enum clock_event_mode mode,
+                                struct clock_event_device *clk)
+{
+       void __iomem *base = TWD_BASE(smp_processor_id());
+       unsigned long ctrl;
+
+       switch(mode) {
+       case CLOCK_EVT_MODE_PERIODIC:
+               /* timer load already set up */
+               ctrl = TWD_TIMER_CONTROL_ENABLE | TWD_TIMER_CONTROL_IT_ENABLE
+                       | TWD_TIMER_CONTROL_PERIODIC;
+               break;
+       case CLOCK_EVT_MODE_ONESHOT:
+               /* period set, and timer enabled in 'next_event' hook */
+               ctrl = TWD_TIMER_CONTROL_IT_ENABLE | TWD_TIMER_CONTROL_ONESHOT;
+               break;
+       case CLOCK_EVT_MODE_UNUSED:
+       case CLOCK_EVT_MODE_SHUTDOWN:
+       default:
+               ctrl = 0;
+       }
+
+       __raw_writel(ctrl, base + TWD_TIMER_CONTROL);
+}
+
+static int local_timer_set_next_event(unsigned long evt,
+                                     struct clock_event_device *unused)
+{
+       void __iomem *base = TWD_BASE(smp_processor_id());
+       unsigned long ctrl = __raw_readl(base + TWD_TIMER_CONTROL);
+
+       __raw_writel(evt, base + TWD_TIMER_COUNTER);
+       __raw_writel(ctrl | TWD_TIMER_CONTROL_ENABLE, base + TWD_TIMER_CONTROL);
+
+       return 0;
+}
+
 /*
  * local_timer_ack: checks for a local timer interrupt.
  *
@@ -45,12 +101,11 @@ int local_timer_ack(void)
        return 0;
 }
 
-void __cpuinit local_timer_setup(unsigned int cpu)
+static void __cpuinit twd_calibrate_rate(unsigned int cpu)
 {
        void __iomem *base = TWD_BASE(cpu);
-       unsigned int load, offset;
+       unsigned long load, count;
        u64 waitjiffies;
-       unsigned int count;
 
        /*
         * If this is the first time round, we need to work out how fast
@@ -88,36 +143,36 @@ void __cpuinit local_timer_setup(unsigned int cpu)
        load = mpcore_timer_rate / HZ;
 
        __raw_writel(load, base + TWD_TIMER_LOAD);
-       __raw_writel(0x7,  base + TWD_TIMER_CONTROL);
-
-       /*
-        * Now maneuver our local tick into the right part of the jiffy.
-        * Start by working out where within the tick our local timer
-        * interrupt should go.
-        */
-       offset = ((mpcore_timer_rate / HZ) / (NR_CPUS + 1)) * (cpu + 1);
-
-       /*
-        * gettimeoffset() will return a number of us since the last tick.
-        * Convert this number of us to a local timer tick count.
-        * Be careful of integer overflow whilst keeping maximum precision.
-        *
-        * with HZ=100 and 1MHz (fpga) ~ 1GHz processor:
-        * load = 1 ~ 10,000
-        * mpcore_timer_rate/10000 = 100 ~ 100,000
-        *
-        * so the multiply value will be less than 10^9 always.
-        */
-       load = (system_timer->offset() * (mpcore_timer_rate / 10000)) / 100;
-
-       /* Add on our offset to get the load value */
-       load = (load + offset) % (mpcore_timer_rate / HZ);
+}
 
-       __raw_writel(load, base + TWD_TIMER_COUNTER);
+/*
+ * Setup the local clock events for a CPU.
+ */
+void __cpuinit local_timer_setup(unsigned int cpu)
+{
+       struct clock_event_device *clk = &per_cpu(local_clockevent, cpu);
+       unsigned long flags;
+
+       twd_calibrate_rate(cpu);
+
+       clk->name               = "local_timer";
+       clk->features           = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
+       clk->rating             = 350;
+       clk->set_mode           = local_timer_set_mode;
+       clk->set_next_event     = local_timer_set_next_event;
+       clk->irq                = IRQ_LOCALTIMER;
+       clk->cpumask            = cpumask_of_cpu(cpu);
+       clk->shift              = 20;
+       clk->mult               = div_sc(mpcore_timer_rate, NSEC_PER_SEC, clk->shift);
+       clk->max_delta_ns       = clockevent_delta2ns(0xffffffff, clk);
+       clk->min_delta_ns       = clockevent_delta2ns(0xf, clk);
 
        /* Make sure our local interrupt controller has this enabled */
-       __raw_writel(1 << IRQ_LOCALTIMER,
-                    __io_address(REALVIEW_GIC_DIST_BASE) + GIC_DIST_ENABLE_SET);
+       local_irq_save(flags);
+       get_irq_chip(IRQ_LOCALTIMER)->unmask(IRQ_LOCALTIMER);
+       local_irq_restore(flags);
+
+       clockevents_register_device(clk);
 }
 
 /*
@@ -127,3 +182,26 @@ void __cpuexit local_timer_stop(unsigned int cpu)
 {
        __raw_writel(0, TWD_BASE(cpu) + TWD_TIMER_CONTROL);
 }
+
+#else  /* CONFIG_LOCAL_TIMERS */
+
+static void dummy_timer_set_mode(enum clock_event_mode mode,
+                                struct clock_event_device *clk)
+{
+}
+
+void __cpuinit local_timer_setup(unsigned int cpu)
+{
+       struct clock_event_device *clk = &per_cpu(local_clockevent, cpu);
+
+       clk->name               = "dummy_timer";
+       clk->features           = CLOCK_EVT_FEAT_DUMMY;
+       clk->rating             = 200;
+       clk->set_mode           = dummy_timer_set_mode;
+       clk->broadcast          = smp_timer_broadcast;
+       clk->cpumask            = cpumask_of_cpu(cpu);
+
+       clockevents_register_device(clk);
+}
+
+#endif /* !CONFIG_LOCAL_TIMERS */
index fce3596f9950a6aea5d8489d9d674a99759ad7b0..de2b7159557dd56c56eb5f673124cc263f0bfa6d 100644 (file)
@@ -18,6 +18,7 @@
 #include <asm/hardware/arm_scu.h>
 #include <asm/hardware.h>
 #include <asm/io.h>
+#include <asm/mach-types.h>
 
 extern void realview_secondary_startup(void);
 
@@ -31,9 +32,13 @@ static unsigned int __init get_core_count(void)
 {
        unsigned int ncores;
 
-       ncores = __raw_readl(__io_address(REALVIEW_MPCORE_SCU_BASE) + SCU_CONFIG);
+       if (machine_is_realview_eb() && core_tile_eb11mp()) {
+               ncores = __raw_readl(__io_address(REALVIEW_EB11MP_SCU_BASE) + SCU_CONFIG);
+               ncores = (ncores & 0x03) + 1;
+       } else
+               ncores = 1;
 
-       return (ncores & 0x03) + 1;
+       return ncores;
 }
 
 static DEFINE_SPINLOCK(boot_lock);
@@ -52,7 +57,7 @@ void __cpuinit platform_secondary_init(unsigned int cpu)
         * core (e.g. timer irq), then they will not have been enabled
         * for us: do so
         */
-       gic_cpu_init(0, __io_address(REALVIEW_GIC_CPU_BASE));
+       gic_cpu_init(0, __io_address(REALVIEW_EB11MP_GIC_CPU_BASE));
 
        /*
         * let the primary processor know we're out of the
@@ -187,10 +192,15 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
        if (max_cpus > ncores)
                max_cpus = ncores;
 
+#ifdef CONFIG_LOCAL_TIMERS
        /*
-        * Enable the local timer for primary CPU
+        * Enable the local timer for primary CPU. If the device is
+        * dummy (!CONFIG_LOCAL_TIMERS), it was already registers in
+        * realview_timer_init
         */
-       local_timer_setup(cpu);
+       if (machine_is_realview_eb() && core_tile_eb11mp())
+               local_timer_setup(cpu);
+#endif
 
        /*
         * Initialise the present map, which describes the set of CPUs
index ecec2f85c4cd12624f178e5ee46af887cc93d0c0..60d9eb810246f23957597695566de56af573750e 100644 (file)
@@ -36,7 +36,9 @@
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 #include <asm/mach/mmc.h>
+#include <asm/mach/time.h>
 
+#include <asm/arch/board-eb.h>
 #include <asm/arch/irqs.h>
 
 #include "core.h"
@@ -58,26 +60,7 @@ static struct map_desc realview_eb_io_desc[] __initdata = {
                .pfn            = __phys_to_pfn(REALVIEW_GIC_DIST_BASE),
                .length         = SZ_4K,
                .type           = MT_DEVICE,
-       },
-#ifdef CONFIG_REALVIEW_MPCORE
-       {
-               .virtual        = IO_ADDRESS(REALVIEW_GIC1_CPU_BASE),
-               .pfn            = __phys_to_pfn(REALVIEW_GIC1_CPU_BASE),
-               .length         = SZ_4K,
-               .type           = MT_DEVICE,
        }, {
-               .virtual        = IO_ADDRESS(REALVIEW_GIC1_DIST_BASE),
-               .pfn            = __phys_to_pfn(REALVIEW_GIC1_DIST_BASE),
-               .length         = SZ_4K,
-               .type           = MT_DEVICE,
-       }, {
-               .virtual        = IO_ADDRESS(REALVIEW_MPCORE_L220_BASE),
-               .pfn            = __phys_to_pfn(REALVIEW_MPCORE_L220_BASE),
-               .length         = SZ_8K,
-               .type           = MT_DEVICE,
-       },
-#endif
-       {
                .virtual        = IO_ADDRESS(REALVIEW_SCTL_BASE),
                .pfn            = __phys_to_pfn(REALVIEW_SCTL_BASE),
                .length         = SZ_4K,
@@ -103,11 +86,95 @@ static struct map_desc realview_eb_io_desc[] __initdata = {
 #endif
 };
 
+static struct map_desc realview_eb11mp_io_desc[] __initdata = {
+       {
+               .virtual        = IO_ADDRESS(REALVIEW_EB11MP_GIC_CPU_BASE),
+               .pfn            = __phys_to_pfn(REALVIEW_EB11MP_GIC_CPU_BASE),
+               .length         = SZ_4K,
+               .type           = MT_DEVICE,
+       }, {
+               .virtual        = IO_ADDRESS(REALVIEW_EB11MP_GIC_DIST_BASE),
+               .pfn            = __phys_to_pfn(REALVIEW_EB11MP_GIC_DIST_BASE),
+               .length         = SZ_4K,
+               .type           = MT_DEVICE,
+       }, {
+               .virtual        = IO_ADDRESS(REALVIEW_EB11MP_L220_BASE),
+               .pfn            = __phys_to_pfn(REALVIEW_EB11MP_L220_BASE),
+               .length         = SZ_8K,
+               .type           = MT_DEVICE,
+       }
+};
+
 static void __init realview_eb_map_io(void)
 {
        iotable_init(realview_eb_io_desc, ARRAY_SIZE(realview_eb_io_desc));
+       if (core_tile_eb11mp())
+               iotable_init(realview_eb11mp_io_desc, ARRAY_SIZE(realview_eb11mp_io_desc));
 }
 
+/*
+ * RealView EB AMBA devices
+ */
+
+/*
+ * These devices are connected via the core APB bridge
+ */
+#define GPIO2_IRQ      { IRQ_EB_GPIO2, NO_IRQ }
+#define GPIO2_DMA      { 0, 0 }
+#define GPIO3_IRQ      { IRQ_EB_GPIO3, NO_IRQ }
+#define GPIO3_DMA      { 0, 0 }
+
+#define AACI_IRQ       { IRQ_EB_AACI, NO_IRQ }
+#define AACI_DMA       { 0x80, 0x81 }
+#define MMCI0_IRQ      { IRQ_EB_MMCI0A, IRQ_EB_MMCI0B }
+#define MMCI0_DMA      { 0x84, 0 }
+#define KMI0_IRQ       { IRQ_EB_KMI0, NO_IRQ }
+#define KMI0_DMA       { 0, 0 }
+#define KMI1_IRQ       { IRQ_EB_KMI1, NO_IRQ }
+#define KMI1_DMA       { 0, 0 }
+
+/*
+ * These devices are connected directly to the multi-layer AHB switch
+ */
+#define SMC_IRQ                { NO_IRQ, NO_IRQ }
+#define SMC_DMA                { 0, 0 }
+#define MPMC_IRQ       { NO_IRQ, NO_IRQ }
+#define MPMC_DMA       { 0, 0 }
+#define CLCD_IRQ       { IRQ_EB_CLCD, NO_IRQ }
+#define CLCD_DMA       { 0, 0 }
+#define DMAC_IRQ       { IRQ_EB_DMA, NO_IRQ }
+#define DMAC_DMA       { 0, 0 }
+
+/*
+ * These devices are connected via the core APB bridge
+ */
+#define SCTL_IRQ       { NO_IRQ, NO_IRQ }
+#define SCTL_DMA       { 0, 0 }
+#define WATCHDOG_IRQ   { IRQ_EB_WDOG, NO_IRQ }
+#define WATCHDOG_DMA   { 0, 0 }
+#define GPIO0_IRQ      { IRQ_EB_GPIO0, NO_IRQ }
+#define GPIO0_DMA      { 0, 0 }
+#define GPIO1_IRQ      { IRQ_EB_GPIO1, NO_IRQ }
+#define GPIO1_DMA      { 0, 0 }
+#define RTC_IRQ                { IRQ_EB_RTC, NO_IRQ }
+#define RTC_DMA                { 0, 0 }
+
+/*
+ * These devices are connected via the DMA APB bridge
+ */
+#define SCI_IRQ                { IRQ_EB_SCI, NO_IRQ }
+#define SCI_DMA                { 7, 6 }
+#define UART0_IRQ      { IRQ_EB_UART0, NO_IRQ }
+#define UART0_DMA      { 15, 14 }
+#define UART1_IRQ      { IRQ_EB_UART1, NO_IRQ }
+#define UART1_DMA      { 13, 12 }
+#define UART2_IRQ      { IRQ_EB_UART2, NO_IRQ }
+#define UART2_DMA      { 11, 10 }
+#define UART3_IRQ      { IRQ_EB_UART3, NO_IRQ }
+#define UART3_DMA      { 0x86, 0x87 }
+#define SSP_IRQ                { IRQ_EB_SSP, NO_IRQ }
+#define SSP_DMA                { 9, 8 }
+
 /* FPGA Primecells */
 AMBA_DEVICE(aaci,  "fpga:04", AACI,     NULL);
 AMBA_DEVICE(mmc0,  "fpga:05", MMCI0,    &realview_mmc0_plat_data);
@@ -153,38 +220,127 @@ static struct amba_device *amba_devs[] __initdata = {
        &kmi1_device,
 };
 
+/*
+ * RealView EB platform devices
+ */
+
+static struct resource realview_eb_smc91x_resources[] = {
+       [0] = {
+               .start          = REALVIEW_ETH_BASE,
+               .end            = REALVIEW_ETH_BASE + SZ_64K - 1,
+               .flags          = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start          = IRQ_EB_ETH,
+               .end            = IRQ_EB_ETH,
+               .flags          = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device realview_eb_smc91x_device = {
+       .name           = "smc91x",
+       .id             = 0,
+       .num_resources  = ARRAY_SIZE(realview_eb_smc91x_resources),
+       .resource       = realview_eb_smc91x_resources,
+};
+
 static void __init gic_init_irq(void)
 {
-#ifdef CONFIG_REALVIEW_MPCORE
-       unsigned int pldctrl;
-       writel(0x0000a05f, __io_address(REALVIEW_SYS_LOCK));
-       pldctrl = readl(__io_address(REALVIEW_SYS_BASE) + REALVIEW_MPCORE_SYS_PLD_CTRL1);
-       pldctrl |= 0x00800000;  /* New irq mode */
-       writel(pldctrl, __io_address(REALVIEW_SYS_BASE) + REALVIEW_MPCORE_SYS_PLD_CTRL1);
-       writel(0x00000000, __io_address(REALVIEW_SYS_LOCK));
+       if (core_tile_eb11mp()) {
+               unsigned int pldctrl;
+
+               /* new irq mode */
+               writel(0x0000a05f, __io_address(REALVIEW_SYS_LOCK));
+               pldctrl = readl(__io_address(REALVIEW_SYS_BASE) + REALVIEW_EB11MP_SYS_PLD_CTRL1);
+               pldctrl |= 0x00800000;
+               writel(pldctrl, __io_address(REALVIEW_SYS_BASE) + REALVIEW_EB11MP_SYS_PLD_CTRL1);
+               writel(0x00000000, __io_address(REALVIEW_SYS_LOCK));
+
+               /* core tile GIC, primary */
+               gic_cpu_base_addr = __io_address(REALVIEW_EB11MP_GIC_CPU_BASE);
+               gic_dist_init(0, __io_address(REALVIEW_EB11MP_GIC_DIST_BASE), 29);
+               gic_cpu_init(0, gic_cpu_base_addr);
+
+#ifndef CONFIG_REALVIEW_EB_ARM11MP_REVB
+               /* board GIC, secondary */
+               gic_dist_init(1, __io_address(REALVIEW_GIC_DIST_BASE), 64);
+               gic_cpu_init(1, __io_address(REALVIEW_GIC_CPU_BASE));
+               gic_cascade_irq(1, IRQ_EB11MP_EB_IRQ1);
 #endif
-       gic_dist_init(0, __io_address(REALVIEW_GIC_DIST_BASE), 29);
-       gic_cpu_init(0, __io_address(REALVIEW_GIC_CPU_BASE));
-#if defined(CONFIG_REALVIEW_MPCORE) && !defined(CONFIG_REALVIEW_MPCORE_REVB)
-       gic_dist_init(1, __io_address(REALVIEW_GIC1_DIST_BASE), 64);
-       gic_cpu_init(1, __io_address(REALVIEW_GIC1_CPU_BASE));
-       gic_cascade_irq(1, IRQ_EB_IRQ1);
+       } else {
+               /* board GIC, primary */
+               gic_cpu_base_addr = __io_address(REALVIEW_GIC_CPU_BASE);
+               gic_dist_init(0, __io_address(REALVIEW_GIC_DIST_BASE), 29);
+               gic_cpu_init(0, gic_cpu_base_addr);
+       }
+}
+
+/*
+ * Fix up the IRQ numbers for the RealView EB/ARM11MPCore tile
+ */
+static void realview_eb11mp_fixup(void)
+{
+       /* AMBA devices */
+       dmac_device.irq[0]      = IRQ_EB11MP_DMA;
+       uart0_device.irq[0]     = IRQ_EB11MP_UART0;
+       uart1_device.irq[0]     = IRQ_EB11MP_UART1;
+       uart2_device.irq[0]     = IRQ_EB11MP_UART2;
+       uart3_device.irq[0]     = IRQ_EB11MP_UART3;
+       clcd_device.irq[0]      = IRQ_EB11MP_CLCD;
+       wdog_device.irq[0]      = IRQ_EB11MP_WDOG;
+       gpio0_device.irq[0]     = IRQ_EB11MP_GPIO0;
+       gpio1_device.irq[0]     = IRQ_EB11MP_GPIO1;
+       gpio2_device.irq[0]     = IRQ_EB11MP_GPIO2;
+       rtc_device.irq[0]       = IRQ_EB11MP_RTC;
+       sci0_device.irq[0]      = IRQ_EB11MP_SCI;
+       ssp0_device.irq[0]      = IRQ_EB11MP_SSP;
+       aaci_device.irq[0]      = IRQ_EB11MP_AACI;
+       mmc0_device.irq[0]      = IRQ_EB11MP_MMCI0A;
+       mmc0_device.irq[1]      = IRQ_EB11MP_MMCI0B;
+       kmi0_device.irq[0]      = IRQ_EB11MP_KMI0;
+       kmi1_device.irq[0]      = IRQ_EB11MP_KMI1;
+
+       /* platform devices */
+       realview_eb_smc91x_resources[1].start   = IRQ_EB11MP_ETH;
+       realview_eb_smc91x_resources[1].end     = IRQ_EB11MP_ETH;
+}
+
+static void __init realview_eb_timer_init(void)
+{
+       unsigned int timer_irq;
+
+       if (core_tile_eb11mp()) {
+#ifdef CONFIG_LOCAL_TIMERS
+               twd_base_addr = __io_address(REALVIEW_EB11MP_TWD_BASE);
+               twd_size = REALVIEW_EB11MP_TWD_SIZE;
 #endif
+               timer_irq = IRQ_EB11MP_TIMER0_1;
+       } else
+               timer_irq = IRQ_EB_TIMER0_1;
+
+       realview_timer_init(timer_irq);
 }
 
+static struct sys_timer realview_eb_timer = {
+       .init           = realview_eb_timer_init,
+};
+
 static void __init realview_eb_init(void)
 {
        int i;
 
-#ifdef CONFIG_REALVIEW_MPCORE
-       /* 1MB (128KB/way), 8-way associativity, evmon/parity/share enabled
-        * Bits:  .... ...0 0111 1001 0000 .... .... .... */
-       l2x0_init(__io_address(REALVIEW_MPCORE_L220_BASE), 0x00790000, 0xfe000fff);
-#endif
+       if (core_tile_eb11mp()) {
+               realview_eb11mp_fixup();
+
+               /* 1MB (128KB/way), 8-way associativity, evmon/parity/share enabled
+                * Bits:  .... ...0 0111 1001 0000 .... .... .... */
+               l2x0_init(__io_address(REALVIEW_EB11MP_L220_BASE), 0x00790000, 0xfe000fff);
+       }
+
        clk_register(&realview_clcd_clk);
 
        platform_device_register(&realview_flash_device);
-       platform_device_register(&realview_smc91x_device);
+       platform_device_register(&realview_eb_smc91x_device);
        platform_device_register(&realview_i2c_device);
 
        for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
@@ -204,6 +360,6 @@ MACHINE_START(REALVIEW_EB, "ARM-RealView EB")
        .boot_params    = 0x00000100,
        .map_io         = realview_eb_map_io,
        .init_irq       = gic_init_irq,
-       .timer          = &realview_timer,
+       .timer          = &realview_eb_timer,
        .init_machine   = realview_eb_init,
 MACHINE_END
index 1e25b1d19fce7e7f537269a5df27a27584be8b3d..94620be7bfac15ba366c90bca5bac761b98146ed 100644 (file)
@@ -165,7 +165,7 @@ int collie_read_temp(void)
 
        ucb1x00_adc_enable(ucb);
        ucb1x00_io_write(ucb, COLLIE_TC35143_GPIO_TMP_ON, 0);
-       /* >1010 = battery removed, 460 = 22C ?, higer = lower temp ? */
+       /* >1010 = battery removed, 460 = 22C ?, higher = lower temp ? */
        voltage = ucb1x00_adc_read(ucb, UCB_ADC_INP_AD0, UCB_SYNC);
        ucb1x00_io_write(ucb, 0, COLLIE_TC35143_GPIO_TMP_ON);
        ucb1x00_adc_disable(ucb);
index 9e13c8358ea7c0cc4a111f2a86977f9dd19109ea..5c84c604ed86d1fc5b68c89ab802d1713aa2311d 100644 (file)
@@ -470,7 +470,7 @@ void __init sa1110_mb_disable(void)
  * If the system is going to use the SA-1111 DMA engines, set up
  * the memory bus request/grant pins.
  */
-void __init sa1110_mb_enable(void)
+void __devinit sa1110_mb_enable(void)
 {
        unsigned long flags;
 
index 75952779ce1991f68114dcbeef6a188c4c47d027..303a7ff6bfd2eeb3120164d9cc185e0973d600de 100644 (file)
@@ -162,7 +162,7 @@ static void unmap_area_sections(unsigned long virt, unsigned long size)
                         * Free the page table, if there was one.
                         */
                        if ((pmd_val(pmd) & PMD_TYPE_MASK) == PMD_TYPE_TABLE)
-                               pte_free_kernel(pmd_page_vaddr(pmd));
+                               pte_free_kernel(&init_mm, pmd_page_vaddr(pmd));
                }
 
                addr += PGDIR_SIZE;
index 50b9aed6000d8ede02f5df0175df8c8aa7e85c65..500c9610ab3085094ec48d012610b4f557136ec1 100644 (file)
@@ -65,14 +65,14 @@ pgd_t *get_pgd_slow(struct mm_struct *mm)
        return new_pgd;
 
 no_pte:
-       pmd_free(new_pmd);
+       pmd_free(mm, new_pmd);
 no_pmd:
        free_pages((unsigned long)new_pgd, 2);
 no_pgd:
        return NULL;
 }
 
-void free_pgd_slow(pgd_t *pgd)
+void free_pgd_slow(struct mm_struct *mm, pgd_t *pgd)
 {
        pmd_t *pmd;
        struct page *pte;
@@ -94,8 +94,8 @@ void free_pgd_slow(pgd_t *pgd)
        pmd_clear(pmd);
        dec_zone_page_state(virt_to_page((unsigned long *)pgd), NR_PAGETABLE);
        pte_lock_deinit(pte);
-       pte_free(pte);
-       pmd_free(pmd);
+       pte_free(mm, pte);
+       pmd_free(mm, pmd);
 free:
        free_pages((unsigned long) pgd, 2);
 }
index ba3d21d8fba34c4c458a2d80b660e258ca06a2b3..6fe481ff4fdfe5230093846292a3725c98fb57e5 100644 (file)
@@ -57,8 +57,6 @@ unsigned long iop_gettimeoffset(void)
 static irqreturn_t
 iop_timer_interrupt(int irq, void *dev_id)
 {
-       write_seqlock(&xtime_lock);
-
        write_tisr(1);
 
        while ((signed long)(next_jiffy_time - read_tcr1())
@@ -67,8 +65,6 @@ iop_timer_interrupt(int irq, void *dev_id)
                next_jiffy_time -= ticks_per_jiffy;
        }
 
-       write_sequnlock(&xtime_lock);
-
        return IRQ_HANDLED;
 }
 
index d486f5112569bcd66721b892b128f49ddf016126..ae2c5d7efc9dc411cc1488840bee40d8b648a456 100644 (file)
@@ -47,7 +47,7 @@
  *               Mark IRQ_LCD valid
  *
  *   25-Jul-2005  Ben Dooks
- *               Split the S3C2440 IRQ code to seperate file
+ *               Split the S3C2440 IRQ code to separate file
 */
 
 #include <linux/init.h>
index 2ec1daaa0e537a6aed01f4aa62f5d7551ad3e8b8..766473b3f98b6bf2d8b4ae61af4254949d9431fb 100644 (file)
@@ -130,9 +130,7 @@ static unsigned long s3c2410_gettimeoffset (void)
 static irqreturn_t
 s3c2410_timer_interrupt(int irq, void *dev_id)
 {
-       write_seqlock(&xtime_lock);
        timer_tick();
-       write_sequnlock(&xtime_lock);
        return IRQ_HANDLED;
 }
 
index e34e2c9c94cb5b678eeae91929682ab081c7e661..28e0caf4156ca68bb066d8300fd1947264e28037 100644 (file)
@@ -10,6 +10,8 @@ config AVR32
        # With EMBEDDED=n, we get lots of stuff automatically selected
        # that we usually don't need on AVR32.
        select EMBEDDED
+       select HAVE_OPROFILE
+       select HAVE_KPROBES
        help
          AVR32 is a high-performance 32-bit RISC microprocessor core,
          designed for cost-sensitive embedded applications, with particular
@@ -54,9 +56,6 @@ config ARCH_HAS_ILOG2_U32
 config ARCH_HAS_ILOG2_U64
        def_bool n
 
-config ARCH_SUPPORTS_OPROFILE
-       def_bool y
-
 config GENERIC_HWEIGHT
        def_bool y
 
@@ -83,6 +82,7 @@ config PLATFORM_AT32AP
        select SUBARCH_AVR32B
        select MMU
        select PERFORMANCE_COUNTERS
+       select HAVE_GPIO_LIB
 
 #
 # CPU types
@@ -236,8 +236,6 @@ source "drivers/Kconfig"
 
 source "fs/Kconfig"
 
-source "kernel/Kconfig.instrumentation"
-
 source "arch/avr32/Kconfig.debug"
 
 source "security/Kconfig"
index 75c81f2dd0b3a623fb19722dc961bd99e788ccc3..478bda4c4a09a9ac57f119b4c8529d970cbc48e2 100644 (file)
@@ -293,6 +293,6 @@ sys_call_table:
        .long   sys_shmctl
        .long   sys_utimensat
        .long   sys_signalfd
-       .long   sys_timerfd             /* 280 */
+       .long   sys_ni_syscall          /* 280, was sys_timerfd */
        .long   sys_eventfd
        .long   sys_ni_syscall          /* r8 is saturated at nr_syscalls */
index d61a02da898cd68bd08316474ee2c2762dfd8036..38a8fa31c0b5c8de591ae8f39a08c2e90d2a862b 100644 (file)
 #define MAX_NR_PIO_DEVICES             8
 
 struct pio_device {
+       struct gpio_chip chip;
        void __iomem *regs;
        const struct platform_device *pdev;
        struct clk *clk;
        u32 pinmux_mask;
-       u32 gpio_mask;
        char name[8];
 };
 
@@ -64,7 +64,8 @@ void __init at32_select_periph(unsigned int pin, unsigned int periph,
                goto fail;
        }
 
-       if (unlikely(test_and_set_bit(pin_index, &pio->pinmux_mask))) {
+       if (unlikely(test_and_set_bit(pin_index, &pio->pinmux_mask)
+                        || gpiochip_is_requested(&pio->chip, pin_index))) {
                printk("%s: pin %u is busy\n", pio->name, pin_index);
                goto fail;
        }
@@ -79,9 +80,6 @@ void __init at32_select_periph(unsigned int pin, unsigned int periph,
        if (!(flags & AT32_GPIOF_PULLUP))
                pio_writel(pio, PUDR, mask);
 
-       /* gpio_request NOT allowed */
-       set_bit(pin_index, &pio->gpio_mask);
-
        return;
 
 fail:
@@ -130,9 +128,6 @@ void __init at32_select_gpio(unsigned int pin, unsigned long flags)
 
        pio_writel(pio, PER, mask);
 
-       /* gpio_request now allowed */
-       clear_bit(pin_index, &pio->gpio_mask);
-
        return;
 
 fail:
@@ -166,96 +161,50 @@ fail:
 
 /* GPIO API */
 
-int gpio_request(unsigned int gpio, const char *label)
+static int direction_input(struct gpio_chip *chip, unsigned offset)
 {
-       struct pio_device *pio;
-       unsigned int pin;
-
-       pio = gpio_to_pio(gpio);
-       if (!pio)
-               return -ENODEV;
+       struct pio_device *pio = container_of(chip, struct pio_device, chip);
+       u32 mask = 1 << offset;
 
-       pin = gpio & 0x1f;
-       if (test_and_set_bit(pin, &pio->gpio_mask))
-               return -EBUSY;
+       if (!(pio_readl(pio, PSR) & mask))
+               return -EINVAL;
 
+       pio_writel(pio, ODR, mask);
        return 0;
 }
-EXPORT_SYMBOL(gpio_request);
 
-void gpio_free(unsigned int gpio)
+static int gpio_get(struct gpio_chip *chip, unsigned offset)
 {
-       struct pio_device *pio;
-       unsigned int pin;
+       struct pio_device *pio = container_of(chip, struct pio_device, chip);
 
-       pio = gpio_to_pio(gpio);
-       if (!pio) {
-               printk(KERN_ERR
-                      "gpio: attempted to free invalid pin %u\n", gpio);
-               return;
-       }
-
-       pin = gpio & 0x1f;
-       if (!test_and_clear_bit(pin, &pio->gpio_mask))
-               printk(KERN_ERR "gpio: freeing free or non-gpio pin %s-%u\n",
-                      pio->name, pin);
+       return (pio_readl(pio, PDSR) >> offset) & 1;
 }
-EXPORT_SYMBOL(gpio_free);
 
-int gpio_direction_input(unsigned int gpio)
-{
-       struct pio_device *pio;
-       unsigned int pin;
-
-       pio = gpio_to_pio(gpio);
-       if (!pio)
-               return -ENODEV;
-
-       pin = gpio & 0x1f;
-       pio_writel(pio, ODR, 1 << pin);
-
-       return 0;
-}
-EXPORT_SYMBOL(gpio_direction_input);
+static void gpio_set(struct gpio_chip *chip, unsigned offset, int value);
 
-int gpio_direction_output(unsigned int gpio, int value)
+static int direction_output(struct gpio_chip *chip, unsigned offset, int value)
 {
-       struct pio_device *pio;
-       unsigned int pin;
-
-       pio = gpio_to_pio(gpio);
-       if (!pio)
-               return -ENODEV;
+       struct pio_device *pio = container_of(chip, struct pio_device, chip);
+       u32 mask = 1 << offset;
 
-       gpio_set_value(gpio, value);
-
-       pin = gpio & 0x1f;
-       pio_writel(pio, OER, 1 << pin);
+       if (!(pio_readl(pio, PSR) & mask))
+               return -EINVAL;
 
+       gpio_set(chip, offset, value);
+       pio_writel(pio, OER, mask);
        return 0;
 }
-EXPORT_SYMBOL(gpio_direction_output);
 
-int gpio_get_value(unsigned int gpio)
+static void gpio_set(struct gpio_chip *chip, unsigned offset, int value)
 {
-       struct pio_device *pio = &pio_dev[gpio >> 5];
+       struct pio_device *pio = container_of(chip, struct pio_device, chip);
+       u32 mask = 1 << offset;
 
-       return (pio_readl(pio, PDSR) >> (gpio & 0x1f)) & 1;
-}
-EXPORT_SYMBOL(gpio_get_value);
-
-void gpio_set_value(unsigned int gpio, int value)
-{
-       struct pio_device *pio = &pio_dev[gpio >> 5];
-       u32 mask;
-
-       mask = 1 << (gpio & 0x1f);
        if (value)
                pio_writel(pio, SODR, mask);
        else
                pio_writel(pio, CODR, mask);
 }
-EXPORT_SYMBOL(gpio_set_value);
 
 /*--------------------------------------------------------------------------*/
 
@@ -337,6 +286,63 @@ gpio_irq_setup(struct pio_device *pio, int irq, int gpio_irq)
        set_irq_chained_handler(irq, gpio_irq_handler);
 }
 
+/*--------------------------------------------------------------------------*/
+
+#ifdef CONFIG_DEBUG_FS
+
+#include <linux/seq_file.h>
+
+/*
+ * This shows more info than the generic gpio dump code:
+ * pullups, deglitching, open drain drive.
+ */
+static void pio_bank_show(struct seq_file *s, struct gpio_chip *chip)
+{
+       struct pio_device *pio = container_of(chip, struct pio_device, chip);
+       u32                     psr, osr, imr, pdsr, pusr, ifsr, mdsr;
+       unsigned                i;
+       u32                     mask;
+       char                    bank;
+
+       psr = pio_readl(pio, PSR);
+       osr = pio_readl(pio, OSR);
+       imr = pio_readl(pio, IMR);
+       pdsr = pio_readl(pio, PDSR);
+       pusr = pio_readl(pio, PUSR);
+       ifsr = pio_readl(pio, IFSR);
+       mdsr = pio_readl(pio, MDSR);
+
+       bank = 'A' + pio->pdev->id;
+
+       for (i = 0, mask = 1; i < 32; i++, mask <<= 1) {
+               const char *label;
+
+               label = gpiochip_is_requested(chip, i);
+               if (!label)
+                       continue;
+
+               seq_printf(s, " gpio-%-3d P%c%-2d (%-12s) %s %s %s",
+                       chip->base + i, bank, i,
+                       label,
+                       (osr & mask) ? "out" : "in ",
+                       (mask & pdsr) ? "hi" : "lo",
+                       (mask & pusr) ? "  " : "up");
+               if (ifsr & mask)
+                       seq_printf(s, " deglitch");
+               if ((osr & mdsr) & mask)
+                       seq_printf(s, " open-drain");
+               if (imr & mask)
+                       seq_printf(s, " irq-%d edge-both",
+                               gpio_to_irq(chip->base + i));
+               seq_printf(s, "\n");
+       }
+}
+
+#else
+#define pio_bank_show  NULL
+#endif
+
+
 /*--------------------------------------------------------------------------*/
 
 static int __init pio_probe(struct platform_device *pdev)
@@ -349,6 +355,18 @@ static int __init pio_probe(struct platform_device *pdev)
        pio = &pio_dev[pdev->id];
        BUG_ON(!pio->regs);
 
+       pio->chip.label = pio->name;
+       pio->chip.base = pdev->id * 32;
+       pio->chip.ngpio = 32;
+
+       pio->chip.direction_input = direction_input;
+       pio->chip.get = gpio_get;
+       pio->chip.direction_output = direction_output;
+       pio->chip.set = gpio_set;
+       pio->chip.dbg_show = pio_bank_show;
+
+       gpiochip_add(&pio->chip);
+
        gpio_irq_setup(pio, irq, gpio_irq_base);
 
        platform_set_drvdata(pdev, pio);
@@ -406,12 +424,6 @@ void __init at32_init_pio(struct platform_device *pdev)
        pio->pdev = pdev;
        pio->regs = ioremap(regs->start, regs->end - regs->start + 1);
 
-       /*
-        * request_gpio() is only valid for pins that have been
-        * explicitly configured as GPIO and not previously requested
-        */
-       pio->gpio_mask = ~0UL;
-
        /* start with irqs disabled and acked */
        pio_writel(pio, IDR, ~0UL);
        (void) pio_readl(pio, ISR);
index 50fa3aca32c58c23f471469e2def0c02767b2491..7795116a483af37707a66ae57c1f1da49e59a41a 100644 (file)
@@ -19,7 +19,7 @@
 #define PIO_OSR                                0x0018
 #define PIO_IFER                               0x0020
 #define PIO_IFDR                               0x0024
-#define PIO_ISFR                               0x0028
+#define PIO_IFSR                               0x0028
 #define PIO_SODR                               0x0030
 #define PIO_CODR                               0x0034
 #define PIO_ODSR                               0x0038
index fc7ca86ac8bf91627a627539da062d65da16a383..ba21e33b8b1ff2047a078dd3f418d8b4a794be8d 100644 (file)
@@ -24,6 +24,7 @@ config RWSEM_XCHGADD_ALGORITHM
 config BLACKFIN
        bool
        default y
+       select HAVE_OPROFILE
 
 config ZONE_DMA
        bool
@@ -898,6 +899,10 @@ endmenu
 menu "Power management options"
 source "kernel/power/Kconfig"
 
+config ARCH_SUSPEND_POSSIBLE
+       def_bool y
+       depends on !SMP
+
 choice
        prompt "Select PM Wakeup Event Source"
        default PM_WAKEUP_GPIO_BY_SIC_IWR
@@ -969,8 +974,6 @@ source "drivers/Kconfig"
 
 source "fs/Kconfig"
 
-source "kernel/Kconfig.instrumentation"
-
 source "arch/blackfin/Kconfig.debug"
 
 source "security/Kconfig"
index 56ff51bc8c21c8a761dc75f334b9a00f223754a4..fdd9bf43361edf9c31eae8fc19a5bdbdb2666b06 100644 (file)
@@ -1373,7 +1373,7 @@ ENTRY(_sys_call_table)
        .long _sys_epoll_pwait
        .long _sys_utimensat
        .long _sys_signalfd
-       .long _sys_timerfd
+       .long _sys_ni_syscall
        .long _sys_eventfd      /* 350 */
        .long _sys_pread64
        .long _sys_pwrite64
index 222da1501f47c0e81508996e8f74ec7c5ff21353..27b082ac7f11e25e8d6b292b54af2c932f259217 100644 (file)
@@ -150,6 +150,7 @@ config ETRAX_FLASH_BUSWIDTH
          Width in bytes of the Flash bus (1, 2 or 4). Is usually 2.
 
 source arch/cris/arch-v10/Kconfig
+source arch/cris/arch-v32/Kconfig
 
 endmenu
 
@@ -157,8 +158,8 @@ source "net/Kconfig"
 
 # bring in ETRAX built-in drivers
 menu "Drivers for built-in interfaces"
-# arch/cris/arch is a symlink to correct arch (arch-v10 or arch-v32)
-source arch/cris/arch/drivers/Kconfig
+source arch/cris/arch-v10/drivers/Kconfig
+source arch/cris/arch-v32/drivers/Kconfig
 
 endmenu
 
@@ -213,8 +214,6 @@ source "drivers/pci/Kconfig"
 
 source "drivers/usb/Kconfig"
 
-source "kernel/Kconfig.instrumentation"
-
 source "arch/cris/Kconfig.debug"
 
 source "security/Kconfig"
index f1ce6f64401dd45c4e375a466146790f53aeb8eb..1d61faec77cd0b01241462104bf1747e3b6a508d 100644 (file)
@@ -1,3 +1,5 @@
+if ETRAX_ARCH_V10
+
 # ETRAX 100LX v1 has a MMU "feature" requiring a low mapping
 config CRIS_LOW_MAP
        bool
@@ -451,3 +453,5 @@ config ETRAX_POWERBUTTON_BIT
        default "25"
        help
          Configure where power button is connected.
+
+endif
index e3c0f29281496781f948b6e14414e53aea75eaab..96740ef497d4237ebffc65ffb79afe8a1bdc5f4c 100644 (file)
@@ -1,3 +1,5 @@
+if ETRAX_ARCH_V10
+
 config ETRAX_ETHERNET
        bool "Ethernet support"
        depends on ETRAX_ARCH_V10
@@ -806,3 +808,5 @@ config ETRAX_DS1302_TRICKLE_CHARGE
          1 = 2kohm, 2 = 4kohm, 3 = 4kohm
          4 = 1 diode, 8 = 2 diodes
          Allowed values are (increasing current): 0, 11, 10, 9, 7, 6, 5
+
+endif
index ec62c951fa3cc37a1dd709609cd1a9bfa669ef1a..d1361dc119e24d76b3042bd7b70fcb91bdde205a 100644 (file)
@@ -1167,7 +1167,7 @@ sys_call_table:
        .long sys_epoll_pwait
        .long sys_utimensat             /* 320 */
        .long sys_signalfd
-       .long sys_timerfd
+       .long sys_ni_syscall
        .long sys_eventfd
        .long sys_fallocate
 
index 4f79d8ed3e1c451ec122f0b29f93549f9cb3e166..d8acaa920e1c0de92bfc5cfe34be843e11c56563 100644 (file)
@@ -1,3 +1,5 @@
+if ETRAX_ARCH_V32
+
 config ETRAX_DRAM_VIRTUAL_BASE
        hex
        depends on ETRAX_ARCH_V32
@@ -294,3 +296,5 @@ config ETRAX_DEF_GIO_PE_OUT
        help
          Configures the initial data for the general port E bits.  Most
          products should use 00000 here.
+
+endif
index 9bccb5e2a9607b399245f3a42f9c558d325e16bd..c329cce2a0c3c28a5bff0e18587d8dc8f1ce2e14 100644 (file)
@@ -1,3 +1,5 @@
+if ETRAX_ARCH_V32
+
 config ETRAX_ETHERNET
        bool "Ethernet support"
        depends on ETRAX_ARCH_V32
@@ -610,3 +612,5 @@ config ETRAX_STREAMCOPROC
        help
          This option enables a driver for the stream co-processor
          for cryptographic operations.
+
+endif
index 66f9500fbc027609b5d431b89c702015e9913b4c..e0364654fc447f2a4eae7756a28d84775b7654a0 100644 (file)
@@ -93,7 +93,7 @@ int dma_declare_coherent_memory(struct device *dev, dma_addr_t bus_addr,
 
        dev->dma_mem = kzalloc(sizeof(struct dma_coherent_mem), GFP_KERNEL);
        if (!dev->dma_mem)
-               goto out;
+               goto iounmap_out;
        dev->dma_mem->bitmap = kzalloc(bitmap_size, GFP_KERNEL);
        if (!dev->dma_mem->bitmap)
                goto free1_out;
@@ -110,6 +110,8 @@ int dma_declare_coherent_memory(struct device *dev, dma_addr_t bus_addr,
 
  free1_out:
        kfree(dev->dma_mem);
+ iounmap_out:
+       iounmap(mem_base);
  out:
        return 0;
 }
index 43153e767bb1ab548f1edc52bb755233b38830c3..96f7d70f4473681dc3f155b31c00215a55267257 100644 (file)
@@ -79,7 +79,7 @@ config FRV_OUTOFLINE_ATOMIC_OPS
          Setting this option causes the FR-V atomic operations to be mostly
          implemented out-of-line.
 
-         See Documentation/fujitsu/frv/atomic-ops.txt for more information.
+         See Documentation/frv/atomic-ops.txt for more information.
 
 config HIGHMEM
        bool "High memory support"
@@ -138,6 +138,15 @@ config UCPAGE_OFFSET_C0000000
 
 endchoice
 
+config PAGE_OFFSET
+       hex
+       default 0x20000000 if UCPAGE_OFFSET_20000000
+       default 0x40000000 if UCPAGE_OFFSET_40000000
+       default 0x60000000 if UCPAGE_OFFSET_60000000
+       default 0x80000000 if UCPAGE_OFFSET_80000000
+       default 0xA0000000 if UCPAGE_OFFSET_A0000000
+       default 0xC0000000
+
 config PROTECT_KERNEL
        bool "Protect core kernel against userspace"
        depends on !MMU
@@ -322,11 +331,6 @@ config PCI
          onboard. If you have one of these boards and you wish to use the PCI
          facilities, say Y here.
 
-         The PCI-HOWTO, available from
-         <http://www.tldp.org/docs.html#howto>, contains valuable
-         information about which PCI hardware does work under Linux and which
-         doesn't.
-
 config RESERVE_DMA_COHERENT
        bool "Reserve DMA coherent memory"
        depends on PCI && !MMU
@@ -357,6 +361,11 @@ source "drivers/pcmcia/Kconfig"
 #        should probably wait a while.
 
 menu "Power management options"
+
+config ARCH_SUSPEND_POSSIBLE
+       def_bool y
+       depends on !SMP
+
 source kernel/power/Kconfig
 endmenu
 
@@ -375,8 +384,6 @@ source "drivers/Kconfig"
 
 source "fs/Kconfig"
 
-source "kernel/Kconfig.instrumentation"
-
 source "arch/frv/Kconfig.debug"
 
 source "security/Kconfig"
index f926c70947764ef108d5d3da1bddd44a364e9e14..ca6a345b87e401f7309e89c0a41702a91f38a35d 100644 (file)
@@ -253,7 +253,7 @@ __entry_kernel_external_interrupt_reentry:
        andi.p          gr5,#~PSR_ET,gr5
 
        # set CCCR.CC3 to Undefined to abort atomic-modify completion inside the kernel
-       # - for an explanation of how it works, see: Documentation/fujitsu/frv/atomic-ops.txt
+       # - for an explanation of how it works, see: Documentation/frv/atomic-ops.txt
        andi            gr25,#~0xc0,gr25
 
        sti             gr20,@(gr28,#REG_TBR)
@@ -445,7 +445,7 @@ __entry_kernel_softprog_interrupt_reentry:
        sti             gr22,@(sp,#REG_SP)
 
        # set CCCR.CC3 to Undefined to abort atomic-modify completion inside the kernel
-       # - for an explanation of how it works, see: Documentation/fujitsu/frv/atomic-ops.txt
+       # - for an explanation of how it works, see: Documentation/frv/atomic-ops.txt
        movsg           cccr,gr20
        andi            gr20,#~0xc0,gr20
        movgs           gr20,cccr
@@ -1494,7 +1494,7 @@ sys_call_table:
        .long sys_epoll_pwait
        .long sys_utimensat             /* 320 */
        .long sys_signalfd
-       .long sys_timerfd
+       .long sys_ni_syscall
        .long sys_eventfd
        .long sys_fallocate
 
index f42b328b1dd0475e1af868308cdc000c89d40942..ef7527b8b0c77fabca307e5a0f614386d162c8ac 100644 (file)
@@ -13,7 +13,7 @@ ENTRY(_start)
 
 jiffies = jiffies_64 + 4;
 
-__page_offset = 0xc0000000;            /* start of area covered by struct pages */
+__page_offset = CONFIG_PAGE_OFFSET;    /* start of area covered by struct pages */
 __kernel_image_start = __page_offset;  /* address at which kernel image resides */
 
 SECTIONS
index 545cd325ac577d00c9ef96dc3f73fc97d24d44fe..ee0ac905fb08ac271139ecd12de58e9fc9b61366 100644 (file)
@@ -1,7 +1,7 @@
 /* atomic-ops.S: kernel atomic operations
  *
  * For an explanation of how atomic ops work in this arch, see:
- *   Documentation/fujitsu/frv/atomic-ops.txt
+ *   Documentation/frv/atomic-ops.txt
  *
  * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
  * Written by David Howells (dhowells@redhat.com)
index 1530a4111e6d743345ff379d191ba7d6df06e9a3..81757d55a5b592fed1e38281edc0cbb6a256dff7 100644 (file)
@@ -181,7 +181,7 @@ int cxn_pin_by_pid(pid_t pid)
 
        /* get a handle on the mm_struct */
        read_lock(&tasklist_lock);
-       tsk = find_task_by_pid(pid);
+       tsk = find_task_by_vpid(pid);
        if (tsk) {
                ret = -EINVAL;
 
index 7787c3cc52c6923d58e305b4ae10c4e3ab6b87e1..1a2e5c8d03a9c7e639ab354705a08cb0916bb443 100644 (file)
@@ -140,7 +140,7 @@ pgd_t *pgd_alloc(struct mm_struct *mm)
        return pgd;
 }
 
-void pgd_free(pgd_t *pgd)
+void pgd_free(struct mm_struct *mm, pgd_t *pgd)
 {
        /* in the non-PAE case, clear_page_tables() clears user pgd entries */
        quicklist_free(0, pgd_dtor, pgd);
index ff6a8712bd6d8c3f59f7724050d9793a22db3fcf..dc61222e11207b1d802481aa4dfdd4fd788e20b8 100644 (file)
@@ -223,8 +223,6 @@ endmenu
 
 source "fs/Kconfig"
 
-source "kernel/Kconfig.instrumentation"
-
 source "arch/h8300/Kconfig.debug"
 
 source "security/Kconfig"
index 551fd5f30d826ae0a25ab015100c18d9d0b3d4c4..ac10b9783850aa1473bd13c463af1e4eac021708 100644 (file)
@@ -121,7 +121,7 @@ void __init init_IRQ(void)
                printk("virtual vector at 0x%08lx\n",(unsigned long)ramvec);
 
 #if defined(CONFIG_GDB_DEBUG)
-       /* save orignal break vector */
+       /* save original break vector */
        break_vec = ramvec[TRAP3_VEC];
 #else
        break_vec = VECTOR(trace_break);
index 5a41e75ae1fefd1d9358917255a3d3b22041d073..b0de1132dfc02e0537c381b66be30d507daee2f5 100644 (file)
@@ -15,6 +15,8 @@ config IA64
        select ACPI if (!IA64_HP_SIM)
        select PM if (!IA64_HP_SIM)
        select ARCH_SUPPORTS_MSI
+       select HAVE_OPROFILE
+       select HAVE_KPROBES
        default y
        help
          The Itanium Processor Family is Intel's 64-bit successor to
@@ -80,7 +82,7 @@ config GENERIC_TIME_VSYSCALL
        bool
        default y
 
-config ARCH_SETS_UP_PER_CPU_AREA
+config HAVE_SETUP_PER_CPU_AREA
        def_bool y
 
 config DMI
@@ -283,8 +285,8 @@ config SMP
          single processor systems.  On a single processor system, the kernel
          will run faster if you say N here.
 
-         See also the <file:Documentation/smp.txt> and the SMP-HOWTO
-         available at <http://www.tldp.org/docs.html#howto>.
+         See also the SMP-HOWTO available at
+         <http://www.tldp.org/docs.html#howto>.
 
          If you don't know what to do here, say N.
 
@@ -600,8 +602,6 @@ config IRQ_PER_CPU
 
 source "arch/ia64/hp/sim/Kconfig"
 
-source "kernel/Kconfig.instrumentation"
-
 source "arch/ia64/Kconfig.debug"
 
 source "security/Kconfig"
index 45bf04eb7d705c2371d8907e8ec13cc7ab5d6be5..a94445422cc65d895eb76e4a417897bf067556d9 100644 (file)
@@ -1265,7 +1265,7 @@ sba_fill_pdir(
  * the sglist do both.
  */
 static SBA_INLINE int
-sba_coalesce_chunks( struct ioc *ioc,
+sba_coalesce_chunks(struct ioc *ioc, struct device *dev,
        struct scatterlist *startsg,
        int nents)
 {
@@ -1275,6 +1275,7 @@ sba_coalesce_chunks( struct ioc *ioc,
        struct scatterlist *dma_sg;        /* next DMA stream head */
        unsigned long dma_offset, dma_len; /* start/len of DMA stream */
        int n_mappings = 0;
+       unsigned int max_seg_size = dma_get_max_seg_size(dev);
 
        while (nents > 0) {
                unsigned long vaddr = (unsigned long) sba_sg_address(startsg);
@@ -1314,6 +1315,9 @@ sba_coalesce_chunks( struct ioc *ioc,
                            > DMA_CHUNK_SIZE)
                                break;
 
+                       if (dma_len + startsg->length > max_seg_size)
+                               break;
+
                        /*
                        ** Then look for virtually contiguous blocks.
                        **
@@ -1441,7 +1445,7 @@ int sba_map_sg(struct device *dev, struct scatterlist *sglist, int nents, int di
        ** w/o this association, we wouldn't have coherent DMA!
        ** Access to the virtual address is what forces a two pass algorithm.
        */
-       coalesced = sba_coalesce_chunks(ioc, sglist, nents);
+       coalesced = sba_coalesce_chunks(ioc, dev, sglist, nents);
 
        /*
        ** Program the I/O Pdir
@@ -1871,7 +1875,7 @@ ioc_show(struct seq_file *s, void *v)
        return 0;
 }
 
-static struct seq_operations ioc_seq_ops = {
+static const struct seq_operations ioc_seq_ops = {
        .start = ioc_start,
        .next  = ioc_next,
        .stop  = ioc_stop,
index d1d50cd1c38a700318a02ab3678a7bb16eca743d..896b1ebbfb268381bc87eb2e766e9c75e7d75f84 100644 (file)
@@ -27,7 +27,7 @@
 
 #include "ia32priv.h"
 
-extern void die_if_kernel (char *str, struct pt_regs *regs, long err);
+extern int die_if_kernel (char *str, struct pt_regs *regs, long err);
 
 struct exec_domain ia32_exec_domain;
 struct page *ia32_shared_page[NR_CPUS];
@@ -217,7 +217,8 @@ ia32_bad_interrupt (unsigned long int_num, struct pt_regs *regs)
 {
        siginfo_t siginfo;
 
-       die_if_kernel("Bad IA-32 interrupt", regs, int_num);
+       if (die_if_kernel("Bad IA-32 interrupt", regs, int_num))
+               return;
 
        siginfo.si_signo = SIGTRAP;
        siginfo.si_errno = int_num;     /* XXX is it OK to abuse si_errno like this? */
index 242d7934112009340e36724787477bffcda63175..919070a9aed7184c87ea43d83855963bb170d40e 100644 (file)
@@ -1,7 +1,8 @@
 /*
  * Extensible Firmware Interface
  *
- * Based on Extensible Firmware Interface Specification version 0.9 April 30, 1999
+ * Based on Extensible Firmware Interface Specification version 0.9
+ * April 30, 1999
  *
  * Copyright (C) 1999 VA Linux Systems
  * Copyright (C) 1999 Walt Drummond <drummond@valinux.com>
@@ -48,145 +49,157 @@ static unsigned long mem_limit = ~0UL, max_addr = ~0UL, min_addr = 0UL;
 
 #define efi_call_virt(f, args...)      (*(f))(args)
 
-#define STUB_GET_TIME(prefix, adjust_arg)                                                        \
-static efi_status_t                                                                              \
-prefix##_get_time (efi_time_t *tm, efi_time_cap_t *tc)                                           \
-{                                                                                                \
-       struct ia64_fpreg fr[6];                                                                  \
-       efi_time_cap_t *atc = NULL;                                                               \
-       efi_status_t ret;                                                                         \
-                                                                                                 \
-       if (tc)                                                                                   \
-               atc = adjust_arg(tc);                                                             \
-       ia64_save_scratch_fpregs(fr);                                                             \
-       ret = efi_call_##prefix((efi_get_time_t *) __va(runtime->get_time), adjust_arg(tm), atc); \
-       ia64_load_scratch_fpregs(fr);                                                             \
-       return ret;                                                                               \
+#define STUB_GET_TIME(prefix, adjust_arg)                                     \
+static efi_status_t                                                           \
+prefix##_get_time (efi_time_t *tm, efi_time_cap_t *tc)                        \
+{                                                                             \
+       struct ia64_fpreg fr[6];                                               \
+       efi_time_cap_t *atc = NULL;                                            \
+       efi_status_t ret;                                                      \
+                                                                              \
+       if (tc)                                                                \
+               atc = adjust_arg(tc);                                          \
+       ia64_save_scratch_fpregs(fr);                                          \
+       ret = efi_call_##prefix((efi_get_time_t *) __va(runtime->get_time),    \
+                               adjust_arg(tm), atc);                          \
+       ia64_load_scratch_fpregs(fr);                                          \
+       return ret;                                                            \
 }
 
-#define STUB_SET_TIME(prefix, adjust_arg)                                                      \
-static efi_status_t                                                                            \
-prefix##_set_time (efi_time_t *tm)                                                             \
-{                                                                                              \
-       struct ia64_fpreg fr[6];                                                                \
-       efi_status_t ret;                                                                       \
-                                                                                               \
-       ia64_save_scratch_fpregs(fr);                                                           \
-       ret = efi_call_##prefix((efi_set_time_t *) __va(runtime->set_time), adjust_arg(tm));    \
-       ia64_load_scratch_fpregs(fr);                                                           \
-       return ret;                                                                             \
+#define STUB_SET_TIME(prefix, adjust_arg)                                     \
+static efi_status_t                                                           \
+prefix##_set_time (efi_time_t *tm)                                            \
+{                                                                             \
+       struct ia64_fpreg fr[6];                                               \
+       efi_status_t ret;                                                      \
+                                                                              \
+       ia64_save_scratch_fpregs(fr);                                          \
+       ret = efi_call_##prefix((efi_set_time_t *) __va(runtime->set_time),    \
+                               adjust_arg(tm));                               \
+       ia64_load_scratch_fpregs(fr);                                          \
+       return ret;                                                            \
 }
 
-#define STUB_GET_WAKEUP_TIME(prefix, adjust_arg)                                               \
-static efi_status_t                                                                            \
-prefix##_get_wakeup_time (efi_bool_t *enabled, efi_bool_t *pending, efi_time_t *tm)            \
-{                                                                                              \
-       struct ia64_fpreg fr[6];                                                                \
-       efi_status_t ret;                                                                       \
-                                                                                               \
-       ia64_save_scratch_fpregs(fr);                                                           \
-       ret = efi_call_##prefix((efi_get_wakeup_time_t *) __va(runtime->get_wakeup_time),       \
-                               adjust_arg(enabled), adjust_arg(pending), adjust_arg(tm));      \
-       ia64_load_scratch_fpregs(fr);                                                           \
-       return ret;                                                                             \
+#define STUB_GET_WAKEUP_TIME(prefix, adjust_arg)                              \
+static efi_status_t                                                           \
+prefix##_get_wakeup_time (efi_bool_t *enabled, efi_bool_t *pending,           \
+                         efi_time_t *tm)                                      \
+{                                                                             \
+       struct ia64_fpreg fr[6];                                               \
+       efi_status_t ret;                                                      \
+                                                                              \
+       ia64_save_scratch_fpregs(fr);                                          \
+       ret = efi_call_##prefix(                                               \
+               (efi_get_wakeup_time_t *) __va(runtime->get_wakeup_time),      \
+               adjust_arg(enabled), adjust_arg(pending), adjust_arg(tm));     \
+       ia64_load_scratch_fpregs(fr);                                          \
+       return ret;                                                            \
 }
 
-#define STUB_SET_WAKEUP_TIME(prefix, adjust_arg)                                               \
-static efi_status_t                                                                            \
-prefix##_set_wakeup_time (efi_bool_t enabled, efi_time_t *tm)                                  \
-{                                                                                              \
-       struct ia64_fpreg fr[6];                                                                \
-       efi_time_t *atm = NULL;                                                                 \
-       efi_status_t ret;                                                                       \
-                                                                                               \
-       if (tm)                                                                                 \
-               atm = adjust_arg(tm);                                                           \
-       ia64_save_scratch_fpregs(fr);                                                           \
-       ret = efi_call_##prefix((efi_set_wakeup_time_t *) __va(runtime->set_wakeup_time),       \
-                               enabled, atm);                                                  \
-       ia64_load_scratch_fpregs(fr);                                                           \
-       return ret;                                                                             \
+#define STUB_SET_WAKEUP_TIME(prefix, adjust_arg)                              \
+static efi_status_t                                                           \
+prefix##_set_wakeup_time (efi_bool_t enabled, efi_time_t *tm)                 \
+{                                                                             \
+       struct ia64_fpreg fr[6];                                               \
+       efi_time_t *atm = NULL;                                                \
+       efi_status_t ret;                                                      \
+                                                                              \
+       if (tm)                                                                \
+               atm = adjust_arg(tm);                                          \
+       ia64_save_scratch_fpregs(fr);                                          \
+       ret = efi_call_##prefix(                                               \
+               (efi_set_wakeup_time_t *) __va(runtime->set_wakeup_time),      \
+               enabled, atm);                                                 \
+       ia64_load_scratch_fpregs(fr);                                          \
+       return ret;                                                            \
 }
 
-#define STUB_GET_VARIABLE(prefix, adjust_arg)                                          \
-static efi_status_t                                                                    \
-prefix##_get_variable (efi_char16_t *name, efi_guid_t *vendor, u32 *attr,              \
-                      unsigned long *data_size, void *data)                            \
-{                                                                                      \
-       struct ia64_fpreg fr[6];                                                        \
-       u32 *aattr = NULL;                                                                      \
-       efi_status_t ret;                                                               \
-                                                                                       \
-       if (attr)                                                                       \
-               aattr = adjust_arg(attr);                                               \
-       ia64_save_scratch_fpregs(fr);                                                   \
-       ret = efi_call_##prefix((efi_get_variable_t *) __va(runtime->get_variable),     \
-                               adjust_arg(name), adjust_arg(vendor), aattr,            \
-                               adjust_arg(data_size), adjust_arg(data));               \
-       ia64_load_scratch_fpregs(fr);                                                   \
-       return ret;                                                                     \
+#define STUB_GET_VARIABLE(prefix, adjust_arg)                                 \
+static efi_status_t                                                           \
+prefix##_get_variable (efi_char16_t *name, efi_guid_t *vendor, u32 *attr,      \
+                      unsigned long *data_size, void *data)                   \
+{                                                                             \
+       struct ia64_fpreg fr[6];                                               \
+       u32 *aattr = NULL;                                                     \
+       efi_status_t ret;                                                      \
+                                                                              \
+       if (attr)                                                              \
+               aattr = adjust_arg(attr);                                      \
+       ia64_save_scratch_fpregs(fr);                                          \
+       ret = efi_call_##prefix(                                               \
+               (efi_get_variable_t *) __va(runtime->get_variable),            \
+               adjust_arg(name), adjust_arg(vendor), aattr,                   \
+               adjust_arg(data_size), adjust_arg(data));                      \
+       ia64_load_scratch_fpregs(fr);                                          \
+       return ret;                                                            \
 }
 
-#define STUB_GET_NEXT_VARIABLE(prefix, adjust_arg)                                             \
-static efi_status_t                                                                            \
-prefix##_get_next_variable (unsigned long *name_size, efi_char16_t *name, efi_guid_t *vendor)  \
-{                                                                                              \
-       struct ia64_fpreg fr[6];                                                                \
-       efi_status_t ret;                                                                       \
-                                                                                               \
-       ia64_save_scratch_fpregs(fr);                                                           \
-       ret = efi_call_##prefix((efi_get_next_variable_t *) __va(runtime->get_next_variable),   \
-                               adjust_arg(name_size), adjust_arg(name), adjust_arg(vendor));   \
-       ia64_load_scratch_fpregs(fr);                                                           \
-       return ret;                                                                             \
+#define STUB_GET_NEXT_VARIABLE(prefix, adjust_arg)                            \
+static efi_status_t                                                           \
+prefix##_get_next_variable (unsigned long *name_size, efi_char16_t *name,      \
+                           efi_guid_t *vendor)                                \
+{                                                                             \
+       struct ia64_fpreg fr[6];                                               \
+       efi_status_t ret;                                                      \
+                                                                              \
+       ia64_save_scratch_fpregs(fr);                                          \
+       ret = efi_call_##prefix(                                               \
+               (efi_get_next_variable_t *) __va(runtime->get_next_variable),  \
+               adjust_arg(name_size), adjust_arg(name), adjust_arg(vendor));  \
+       ia64_load_scratch_fpregs(fr);                                          \
+       return ret;                                                            \
 }
 
-#define STUB_SET_VARIABLE(prefix, adjust_arg)                                          \
-static efi_status_t                                                                    \
-prefix##_set_variable (efi_char16_t *name, efi_guid_t *vendor, unsigned long attr,     \
-                      unsigned long data_size, void *data)                             \
-{                                                                                      \
-       struct ia64_fpreg fr[6];                                                        \
-       efi_status_t ret;                                                               \
-                                                                                       \
-       ia64_save_scratch_fpregs(fr);                                                   \
-       ret = efi_call_##prefix((efi_set_variable_t *) __va(runtime->set_variable),     \
-                               adjust_arg(name), adjust_arg(vendor), attr, data_size,  \
-                               adjust_arg(data));                                      \
-       ia64_load_scratch_fpregs(fr);                                                   \
-       return ret;                                                                     \
+#define STUB_SET_VARIABLE(prefix, adjust_arg)                                 \
+static efi_status_t                                                           \
+prefix##_set_variable (efi_char16_t *name, efi_guid_t *vendor,                \
+                      unsigned long attr, unsigned long data_size,            \
+                      void *data)                                             \
+{                                                                             \
+       struct ia64_fpreg fr[6];                                               \
+       efi_status_t ret;                                                      \
+                                                                              \
+       ia64_save_scratch_fpregs(fr);                                          \
+       ret = efi_call_##prefix(                                               \
+               (efi_set_variable_t *) __va(runtime->set_variable),            \
+               adjust_arg(name), adjust_arg(vendor), attr, data_size,         \
+               adjust_arg(data));                                             \
+       ia64_load_scratch_fpregs(fr);                                          \
+       return ret;                                                            \
 }
 
-#define STUB_GET_NEXT_HIGH_MONO_COUNT(prefix, adjust_arg)                                      \
-static efi_status_t                                                                            \
-prefix##_get_next_high_mono_count (u32 *count)                                                 \
-{                                                                                              \
-       struct ia64_fpreg fr[6];                                                                \
-       efi_status_t ret;                                                                       \
-                                                                                               \
-       ia64_save_scratch_fpregs(fr);                                                           \
-       ret = efi_call_##prefix((efi_get_next_high_mono_count_t *)                              \
-                               __va(runtime->get_next_high_mono_count), adjust_arg(count));    \
-       ia64_load_scratch_fpregs(fr);                                                           \
-       return ret;                                                                             \
+#define STUB_GET_NEXT_HIGH_MONO_COUNT(prefix, adjust_arg)                     \
+static efi_status_t                                                           \
+prefix##_get_next_high_mono_count (u32 *count)                                \
+{                                                                             \
+       struct ia64_fpreg fr[6];                                               \
+       efi_status_t ret;                                                      \
+                                                                              \
+       ia64_save_scratch_fpregs(fr);                                          \
+       ret = efi_call_##prefix((efi_get_next_high_mono_count_t *)             \
+                               __va(runtime->get_next_high_mono_count),       \
+                               adjust_arg(count));                            \
+       ia64_load_scratch_fpregs(fr);                                          \
+       return ret;                                                            \
 }
 
-#define STUB_RESET_SYSTEM(prefix, adjust_arg)                                  \
-static void                                                                    \
-prefix##_reset_system (int reset_type, efi_status_t status,                    \
-                      unsigned long data_size, efi_char16_t *data)             \
-{                                                                              \
-       struct ia64_fpreg fr[6];                                                \
-       efi_char16_t *adata = NULL;                                             \
-                                                                               \
-       if (data)                                                               \
-               adata = adjust_arg(data);                                       \
-                                                                               \
-       ia64_save_scratch_fpregs(fr);                                           \
-       efi_call_##prefix((efi_reset_system_t *) __va(runtime->reset_system),   \
-                         reset_type, status, data_size, adata);                \
-       /* should not return, but just in case... */                            \
-       ia64_load_scratch_fpregs(fr);                                           \
+#define STUB_RESET_SYSTEM(prefix, adjust_arg)                                 \
+static void                                                                   \
+prefix##_reset_system (int reset_type, efi_status_t status,                   \
+                      unsigned long data_size, efi_char16_t *data)            \
+{                                                                             \
+       struct ia64_fpreg fr[6];                                               \
+       efi_char16_t *adata = NULL;                                            \
+                                                                              \
+       if (data)                                                              \
+               adata = adjust_arg(data);                                      \
+                                                                              \
+       ia64_save_scratch_fpregs(fr);                                          \
+       efi_call_##prefix(                                                     \
+               (efi_reset_system_t *) __va(runtime->reset_system),            \
+               reset_type, status, data_size, adata);                         \
+       /* should not return, but just in case... */                           \
+       ia64_load_scratch_fpregs(fr);                                          \
 }
 
 #define phys_ptr(arg)  ((__typeof__(arg)) ia64_tpa(arg))
@@ -223,7 +236,8 @@ efi_gettimeofday (struct timespec *ts)
                return;
        }
 
-       ts->tv_sec = mktime(tm.year, tm.month, tm.day, tm.hour, tm.minute, tm.second);
+       ts->tv_sec = mktime(tm.year, tm.month, tm.day,
+                           tm.hour, tm.minute, tm.second);
        ts->tv_nsec = tm.nanosecond;
 }
 
@@ -297,8 +311,8 @@ walk (efi_freemem_callback_t callback, void *arg, u64 attr)
 }
 
 /*
- * Walks the EFI memory map and calls CALLBACK once for each EFI memory descriptor that
- * has memory that is available for OS use.
+ * Walk the EFI memory map and call CALLBACK once for each EFI memory
+ * descriptor that has memory that is available for OS use.
  */
 void
 efi_memmap_walk (efi_freemem_callback_t callback, void *arg)
@@ -307,8 +321,8 @@ efi_memmap_walk (efi_freemem_callback_t callback, void *arg)
 }
 
 /*
- * Walks the EFI memory map and calls CALLBACK once for each EFI memory descriptor that
- * has memory that is available for uncached allocator.
+ * Walk the EFI memory map and call CALLBACK once for each EFI memory
+ * descriptor that has memory that is available for uncached allocator.
  */
 void
 efi_memmap_walk_uc (efi_freemem_callback_t callback, void *arg)
@@ -317,11 +331,10 @@ efi_memmap_walk_uc (efi_freemem_callback_t callback, void *arg)
 }
 
 /*
- * Look for the PAL_CODE region reported by EFI and maps it using an
+ * Look for the PAL_CODE region reported by EFI and map it using an
  * ITR to enable safe PAL calls in virtual mode.  See IA-64 Processor
  * Abstraction Layer chapter 11 in ADAG
  */
-
 void *
 efi_get_pal_addr (void)
 {
@@ -341,45 +354,47 @@ efi_get_pal_addr (void)
                        continue;
 
                if (++pal_code_count > 1) {
-                       printk(KERN_ERR "Too many EFI Pal Code memory ranges, dropped @ %lx\n",
-                              md->phys_addr);
+                       printk(KERN_ERR "Too many EFI Pal Code memory ranges, "
+                              "dropped @ %lx\n", md->phys_addr);
                        continue;
                }
                /*
-                * The only ITLB entry in region 7 that is used is the one installed by
-                * __start().  That entry covers a 64MB range.
+                * The only ITLB entry in region 7 that is used is the one
+                * installed by __start().  That entry covers a 64MB range.
                 */
                mask  = ~((1 << KERNEL_TR_PAGE_SHIFT) - 1);
                vaddr = PAGE_OFFSET + md->phys_addr;
 
                /*
-                * We must check that the PAL mapping won't overlap with the kernel
-                * mapping.
+                * We must check that the PAL mapping won't overlap with the
+                * kernel mapping.
                 *
-                * PAL code is guaranteed to be aligned on a power of 2 between 4k and
-                * 256KB and that only one ITR is needed to map it. This implies that the
-                * PAL code is always aligned on its size, i.e., the closest matching page
-                * size supported by the TLB. Therefore PAL code is guaranteed never to
-                * cross a 64MB unless it is bigger than 64MB (very unlikely!).  So for
-                * now the following test is enough to determine whether or not we need a
-                * dedicated ITR for the PAL code.
+                * PAL code is guaranteed to be aligned on a power of 2 between
+                * 4k and 256KB and that only one ITR is needed to map it. This
+                * implies that the PAL code is always aligned on its size,
+                * i.e., the closest matching page size supported by the TLB.
+                * Therefore PAL code is guaranteed never to cross a 64MB unless
+                * it is bigger than 64MB (very unlikely!).  So for now the
+                * following test is enough to determine whether or not we need
+                * a dedicated ITR for the PAL code.
                 */
                if ((vaddr & mask) == (KERNEL_START & mask)) {
-                       printk(KERN_INFO "%s: no need to install ITR for PAL code\n",
-                              __FUNCTION__);
+                       printk(KERN_INFO "%s: no need to install ITR for "
+                              "PAL code\n", __FUNCTION__);
                        continue;
                }
 
                if (efi_md_size(md) > IA64_GRANULE_SIZE)
-                       panic("Woah!  PAL code size bigger than a granule!");
+                       panic("Whoa!  PAL code size bigger than a granule!");
 
 #if EFI_DEBUG
                mask  = ~((1 << IA64_GRANULE_SHIFT) - 1);
 
-               printk(KERN_INFO "CPU %d: mapping PAL code [0x%lx-0x%lx) into [0x%lx-0x%lx)\n",
-                       smp_processor_id(), md->phys_addr,
-                       md->phys_addr + efi_md_size(md),
-                       vaddr & mask, (vaddr & mask) + IA64_GRANULE_SIZE);
+               printk(KERN_INFO "CPU %d: mapping PAL code "
+                       "[0x%lx-0x%lx) into [0x%lx-0x%lx)\n",
+                       smp_processor_id(), md->phys_addr,
+                       md->phys_addr + efi_md_size(md),
+                       vaddr & mask, (vaddr & mask) + IA64_GRANULE_SIZE);
 #endif
                return __va(md->phys_addr);
        }
@@ -401,11 +416,11 @@ efi_map_pal_code (void)
         * Cannot write to CRx with PSR.ic=1
         */
        psr = ia64_clear_ic();
-       ia64_itr(0x1, IA64_TR_PALCODE, GRANULEROUNDDOWN((unsigned long) pal_vaddr),
+       ia64_itr(0x1, IA64_TR_PALCODE,
+                GRANULEROUNDDOWN((unsigned long) pal_vaddr),
                 pte_val(pfn_pte(__pa(pal_vaddr) >> PAGE_SHIFT, PAGE_KERNEL)),
                 IA64_GRANULE_SHIFT);
        ia64_set_psr(psr);              /* restore psr */
-       ia64_srlz_i();
 }
 
 void __init
@@ -418,7 +433,10 @@ efi_init (void)
        char *cp, vendor[100] = "unknown";
        int i;
 
-       /* it's too early to be able to use the standard kernel command line support... */
+       /*
+        * It's too early to be able to use the standard kernel command line
+        * support...
+        */
        for (cp = boot_command_line; *cp; ) {
                if (memcmp(cp, "mem=", 4) == 0) {
                        mem_limit = memparse(cp + 4, &cp);
@@ -434,9 +452,11 @@ efi_init (void)
                }
        }
        if (min_addr != 0UL)
-               printk(KERN_INFO "Ignoring memory below %luMB\n", min_addr >> 20);
+               printk(KERN_INFO "Ignoring memory below %luMB\n",
+                      min_addr >> 20);
        if (max_addr != ~0UL)
-               printk(KERN_INFO "Ignoring memory above %luMB\n", max_addr >> 20);
+               printk(KERN_INFO "Ignoring memory above %luMB\n",
+                      max_addr >> 20);
 
        efi.systab = __va(ia64_boot_param->efi_systab);
 
@@ -444,9 +464,9 @@ efi_init (void)
         * Verify the EFI Table
         */
        if (efi.systab == NULL)
-               panic("Woah! Can't find EFI system table.\n");
+               panic("Whoa! Can't find EFI system table.\n");
        if (efi.systab->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE)
-               panic("Woah! EFI system table signature incorrect\n");
+               panic("Whoa! EFI system table signature incorrect\n");
        if ((efi.systab->hdr.revision >> 16) == 0)
                printk(KERN_WARNING "Warning: EFI system table version "
                       "%d.%02d, expected 1.00 or greater\n",
@@ -464,7 +484,8 @@ efi_init (void)
        }
 
        printk(KERN_INFO "EFI v%u.%.02u by %s:",
-              efi.systab->hdr.revision >> 16, efi.systab->hdr.revision & 0xffff, vendor);
+              efi.systab->hdr.revision >> 16,
+              efi.systab->hdr.revision & 0xffff, vendor);
 
        efi.mps        = EFI_INVALID_TABLE_ADDR;
        efi.acpi       = EFI_INVALID_TABLE_ADDR;
@@ -519,9 +540,12 @@ efi_init (void)
                efi_memory_desc_t *md;
                void *p;
 
-               for (i = 0, p = efi_map_start; p < efi_map_end; ++i, p += efi_desc_size) {
+               for (i = 0, p = efi_map_start; p < efi_map_end;
+                    ++i, p += efi_desc_size)
+               {
                        md = p;
-                       printk("mem%02u: type=%u, attr=0x%lx, range=[0x%016lx-0x%016lx) (%luMB)\n",
+                       printk("mem%02u: type=%u, attr=0x%lx, "
+                              "range=[0x%016lx-0x%016lx) (%luMB)\n",
                               i, md->type, md->attribute, md->phys_addr,
                               md->phys_addr + efi_md_size(md),
                               md->num_pages >> (20 - EFI_PAGE_SHIFT));
@@ -549,8 +573,8 @@ efi_enter_virtual_mode (void)
                md = p;
                if (md->attribute & EFI_MEMORY_RUNTIME) {
                        /*
-                        * Some descriptors have multiple bits set, so the order of
-                        * the tests is relevant.
+                        * Some descriptors have multiple bits set, so the
+                        * order of the tests is relevant.
                         */
                        if (md->attribute & EFI_MEMORY_WB) {
                                md->virt_addr = (u64) __va(md->phys_addr);
@@ -558,21 +582,26 @@ efi_enter_virtual_mode (void)
                                md->virt_addr = (u64) ioremap(md->phys_addr, 0);
                        } else if (md->attribute & EFI_MEMORY_WC) {
 #if 0
-                               md->virt_addr = ia64_remap(md->phys_addr, (_PAGE_A | _PAGE_P
-                                                                          | _PAGE_D
-                                                                          | _PAGE_MA_WC
-                                                                          | _PAGE_PL_0
-                                                                          | _PAGE_AR_RW));
+                               md->virt_addr = ia64_remap(md->phys_addr,
+                                                          (_PAGE_A |
+                                                           _PAGE_P |
+                                                           _PAGE_D |
+                                                           _PAGE_MA_WC |
+                                                           _PAGE_PL_0 |
+                                                           _PAGE_AR_RW));
 #else
                                printk(KERN_INFO "EFI_MEMORY_WC mapping\n");
                                md->virt_addr = (u64) ioremap(md->phys_addr, 0);
 #endif
                        } else if (md->attribute & EFI_MEMORY_WT) {
 #if 0
-                               md->virt_addr = ia64_remap(md->phys_addr, (_PAGE_A | _PAGE_P
-                                                                          | _PAGE_D | _PAGE_MA_WT
-                                                                          | _PAGE_PL_0
-                                                                          | _PAGE_AR_RW));
+                               md->virt_addr = ia64_remap(md->phys_addr,
+                                                          (_PAGE_A |
+                                                           _PAGE_P |
+                                                           _PAGE_D |
+                                                           _PAGE_MA_WT |
+                                                           _PAGE_PL_0 |
+                                                           _PAGE_AR_RW));
 #else
                                printk(KERN_INFO "EFI_MEMORY_WT mapping\n");
                                md->virt_addr = (u64) ioremap(md->phys_addr, 0);
@@ -583,16 +612,18 @@ efi_enter_virtual_mode (void)
 
        status = efi_call_phys(__va(runtime->set_virtual_address_map),
                               ia64_boot_param->efi_memmap_size,
-                              efi_desc_size, ia64_boot_param->efi_memdesc_version,
+                              efi_desc_size,
+                              ia64_boot_param->efi_memdesc_version,
                               ia64_boot_param->efi_memmap);
        if (status != EFI_SUCCESS) {
-               printk(KERN_WARNING "warning: unable to switch EFI into virtual mode "
-                      "(status=%lu)\n", status);
+               printk(KERN_WARNING "warning: unable to switch EFI into "
+                      "virtual mode (status=%lu)\n", status);
                return;
        }
 
        /*
-        * Now that EFI is in virtual mode, we call the EFI functions more efficiently:
+        * Now that EFI is in virtual mode, we call the EFI functions more
+        * efficiently:
         */
        efi.get_time = virt_get_time;
        efi.set_time = virt_set_time;
@@ -606,8 +637,8 @@ efi_enter_virtual_mode (void)
 }
 
 /*
- * Walk the EFI memory map looking for the I/O port range.  There can only be one entry of
- * this type, other I/O port ranges should be described via ACPI.
+ * Walk the EFI memory map looking for the I/O port range.  There can only be
+ * one entry of this type, other I/O port ranges should be described via ACPI.
  */
 u64
 efi_get_iobase (void)
@@ -678,7 +709,6 @@ efi_memmap_intersects (unsigned long phys_addr, unsigned long size)
 
        for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) {
                md = p;
-
                if (md->phys_addr < end && efi_md_end(md) > phys_addr)
                        return 1;
        }
@@ -731,7 +761,7 @@ efi_mem_attribute (unsigned long phys_addr, unsigned long size)
                if (!md || (md->attribute & ~EFI_MEMORY_RUNTIME) != attr)
                        return 0;
        } while (md);
-       return 0;
+       return 0;       /* never reached */
 }
 
 u64
@@ -767,7 +797,7 @@ kern_mem_attribute (unsigned long phys_addr, unsigned long size)
                if (!md || md->attribute != attr)
                        return 0;
        } while (md);
-       return 0;
+       return 0;       /* never reached */
 }
 EXPORT_SYMBOL(kern_mem_attribute);
 
@@ -883,7 +913,7 @@ efi_uart_console_only(void)
                                return 1;
                        uart = 0;
                }
-               hdr = (struct efi_generic_dev_path *) ((u8 *) hdr + hdr->length);
+               hdr = (struct efi_generic_dev_path *)((u8 *) hdr + hdr->length);
        }
        printk(KERN_ERR "Malformed %s value\n", name);
        return 0;
@@ -921,10 +951,12 @@ find_memmap_space (void)
                if (!efi_wb(md)) {
                        continue;
                }
-               if (pmd == NULL || !efi_wb(pmd) || efi_md_end(pmd) != md->phys_addr) {
+               if (pmd == NULL || !efi_wb(pmd) ||
+                   efi_md_end(pmd) != md->phys_addr) {
                        contig_low = GRANULEROUNDUP(md->phys_addr);
                        contig_high = efi_md_end(md);
-                       for (q = p + efi_desc_size; q < efi_map_end; q += efi_desc_size) {
+                       for (q = p + efi_desc_size; q < efi_map_end;
+                            q += efi_desc_size) {
                                check_md = q;
                                if (!efi_wb(check_md))
                                        break;
@@ -988,8 +1020,9 @@ efi_memmap_init(unsigned long *s, unsigned long *e)
        for (p = efi_map_start; p < efi_map_end; pmd = md, p += efi_desc_size) {
                md = p;
                if (!efi_wb(md)) {
-                       if (efi_uc(md) && (md->type == EFI_CONVENTIONAL_MEMORY ||
-                                          md->type == EFI_BOOT_SERVICES_DATA)) {
+                       if (efi_uc(md) &&
+                           (md->type == EFI_CONVENTIONAL_MEMORY ||
+                            md->type == EFI_BOOT_SERVICES_DATA)) {
                                k->attribute = EFI_MEMORY_UC;
                                k->start = md->phys_addr;
                                k->num_pages = md->num_pages;
@@ -997,10 +1030,12 @@ efi_memmap_init(unsigned long *s, unsigned long *e)
                        }
                        continue;
                }
-               if (pmd == NULL || !efi_wb(pmd) || efi_md_end(pmd) != md->phys_addr) {
+               if (pmd == NULL || !efi_wb(pmd) ||
+                   efi_md_end(pmd) != md->phys_addr) {
                        contig_low = GRANULEROUNDUP(md->phys_addr);
                        contig_high = efi_md_end(md);
-                       for (q = p + efi_desc_size; q < efi_map_end; q += efi_desc_size) {
+                       for (q = p + efi_desc_size; q < efi_map_end;
+                            q += efi_desc_size) {
                                check_md = q;
                                if (!efi_wb(check_md))
                                        break;
@@ -1025,13 +1060,17 @@ efi_memmap_init(unsigned long *s, unsigned long *e)
                if (md->phys_addr < contig_low) {
                        lim = min(efi_md_end(md), contig_low);
                        if (efi_uc(md)) {
-                               if (k > kern_memmap && (k-1)->attribute == EFI_MEMORY_UC &&
+                               if (k > kern_memmap &&
+                                   (k-1)->attribute == EFI_MEMORY_UC &&
                                    kmd_end(k-1) == md->phys_addr) {
-                                       (k-1)->num_pages += (lim - md->phys_addr) >> EFI_PAGE_SHIFT;
+                                       (k-1)->num_pages +=
+                                               (lim - md->phys_addr)
+                                               >> EFI_PAGE_SHIFT;
                                } else {
                                        k->attribute = EFI_MEMORY_UC;
                                        k->start = md->phys_addr;
-                                       k->num_pages = (lim - md->phys_addr) >> EFI_PAGE_SHIFT;
+                                       k->num_pages = (lim - md->phys_addr)
+                                               >> EFI_PAGE_SHIFT;
                                        k++;
                                }
                        }
@@ -1049,7 +1088,8 @@ efi_memmap_init(unsigned long *s, unsigned long *e)
                                } else {
                                        k->attribute = EFI_MEMORY_UC;
                                        k->start = lim;
-                                       k->num_pages = (efi_md_end(md) - lim) >> EFI_PAGE_SHIFT;
+                                       k->num_pages = (efi_md_end(md) - lim)
+                                               >> EFI_PAGE_SHIFT;
                                        k++;
                                }
                        }
@@ -1151,8 +1191,10 @@ efi_initialize_iomem_resources(struct resource *code_resource,
                                break;
                }
 
-               if ((res = kzalloc(sizeof(struct resource), GFP_KERNEL)) == NULL) {
-                       printk(KERN_ERR "failed to alocate resource for iomem\n");
+               if ((res = kzalloc(sizeof(struct resource),
+                                  GFP_KERNEL)) == NULL) {
+                       printk(KERN_ERR
+                              "failed to allocate resource for iomem\n");
                        return;
                }
 
@@ -1187,44 +1229,44 @@ efi_initialize_iomem_resources(struct resource *code_resource,
    rsvd_regions are sorted
  */
 unsigned long __init
-kdump_find_rsvd_region (unsigned long size,
-               struct rsvd_region *r, int n)
+kdump_find_rsvd_region (unsigned long size, struct rsvd_region *r, int n)
 {
-  int i;
-  u64 start, end;
-  u64 alignment = 1UL << _PAGE_SIZE_64M;
-  void *efi_map_start, *efi_map_end, *p;
-  efi_memory_desc_t *md;
-  u64 efi_desc_size;
-
-  efi_map_start = __va(ia64_boot_param->efi_memmap);
-  efi_map_end   = efi_map_start + ia64_boot_param->efi_memmap_size;
-  efi_desc_size = ia64_boot_param->efi_memdesc_size;
-
-  for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) {
-         md = p;
-         if (!efi_wb(md))
-                 continue;
-         start = ALIGN(md->phys_addr, alignment);
-         end = efi_md_end(md);
-         for (i = 0; i < n; i++) {
-               if (__pa(r[i].start) >= start && __pa(r[i].end) < end) {
-                       if (__pa(r[i].start) > start + size)
-                               return start;
-                       start = ALIGN(__pa(r[i].end), alignment);
-                       if (i < n-1 && __pa(r[i+1].start) < start + size)
-                               continue;
-                       else
-                               break;
+       int i;
+       u64 start, end;
+       u64 alignment = 1UL << _PAGE_SIZE_64M;
+       void *efi_map_start, *efi_map_end, *p;
+       efi_memory_desc_t *md;
+       u64 efi_desc_size;
+
+       efi_map_start = __va(ia64_boot_param->efi_memmap);
+       efi_map_end   = efi_map_start + ia64_boot_param->efi_memmap_size;
+       efi_desc_size = ia64_boot_param->efi_memdesc_size;
+
+       for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) {
+               md = p;
+               if (!efi_wb(md))
+                       continue;
+               start = ALIGN(md->phys_addr, alignment);
+               end = efi_md_end(md);
+               for (i = 0; i < n; i++) {
+                       if (__pa(r[i].start) >= start && __pa(r[i].end) < end) {
+                               if (__pa(r[i].start) > start + size)
+                                       return start;
+                               start = ALIGN(__pa(r[i].end), alignment);
+                               if (i < n-1 &&
+                                   __pa(r[i+1].start) < start + size)
+                                       continue;
+                               else
+                                       break;
+                       }
                }
-         }
-         if (end > start + size)
-               return start;
-  }
-
-  printk(KERN_WARNING "Cannot reserve 0x%lx byte of memory for crashdump\n",
-       size);
-  return ~0UL;
+               if (end > start + size)
+                       return start;
+       }
+
+       printk(KERN_WARNING
+              "Cannot reserve 0x%lx byte of memory for crashdump\n", size);
+       return ~0UL;
 }
 #endif
 
index c36f43c9460094cfa72f9f5f73839965481c53fa..f5d3efbfbeda425c8fbe1810f3cadf4dcd72bb9d 100644 (file)
@@ -1586,7 +1586,7 @@ sys_call_table:
        data8 sys_epoll_pwait                   // 1305
        data8 sys_utimensat
        data8 sys_signalfd
-       data8 sys_timerfd
+       data8 sys_ni_syscall
        data8 sys_eventfd
 
        .org sys_call_table + 8*NR_syscalls     // guard against failures to increase NR_syscalls
index 490dab55fba34ea730f9d002858394ab24dd28a0..57d2ee6c83e1e637cd5c587f165834f980fb38a7 100644 (file)
@@ -14,10 +14,10 @@ struct fsyscall_gtod_data_t {
        u32             clk_shift;
        void            *clk_fsys_mmio;
        cycle_t         clk_cycle_last;
-} __attribute__ ((aligned (L1_CACHE_BYTES)));
+} ____cacheline_aligned;
 
 struct itc_jitter_data_t {
        int             itc_jitter;
        cycle_t         itc_lastcycle;
-} __attribute__ ((aligned (L1_CACHE_BYTES)));
+} ____cacheline_aligned;
 
index c3b4412ccc676a85ee76fb0c3a0a436c85b85f68..8e7193d55528754a4ab4553084501056c16790b1 100644 (file)
@@ -12,6 +12,9 @@ EXPORT_SYMBOL(memset);
 EXPORT_SYMBOL(memcpy);
 EXPORT_SYMBOL(strlen);
 
+#include<asm/pgtable.h>
+EXPORT_SYMBOL_GPL(empty_zero_page);
+
 #include <asm/checksum.h>
 EXPORT_SYMBOL(ip_fast_csum);           /* hand-coded assembly */
 EXPORT_SYMBOL(csum_ipv6_magic);
index fc4d2676264f363d766ce4d9b6c5f76176fd4cb4..b618487cdc858b836cee4adb044579bb5cb716f4 100644 (file)
@@ -381,9 +381,10 @@ static void __kprobes save_previous_kprobe(struct kprobe_ctlblk *kcb)
 static void __kprobes restore_previous_kprobe(struct kprobe_ctlblk *kcb)
 {
        unsigned int i;
-       i = atomic_sub_return(1, &kcb->prev_kprobe_index);
-       __get_cpu_var(current_kprobe) = kcb->prev_kprobe[i].kp;
-       kcb->kprobe_status = kcb->prev_kprobe[i].status;
+       i = atomic_read(&kcb->prev_kprobe_index);
+       __get_cpu_var(current_kprobe) = kcb->prev_kprobe[i-1].kp;
+       kcb->kprobe_status = kcb->prev_kprobe[i-1].status;
+       atomic_sub(1, &kcb->prev_kprobe_index);
 }
 
 static void __kprobes set_current_kprobe(struct kprobe *p,
index 6dbf5919d2d0e7600b9bf9d9fc7f7f7116bb04a8..846e7e036b13c6e717039ccbfd79964cc9063fb0 100644 (file)
@@ -2,61 +2,69 @@
  * File:       mca.c
  * Purpose:    Generic MCA handling layer
  *
- * Updated for latest kernel
  * Copyright (C) 2003 Hewlett-Packard Co
  *     David Mosberger-Tang <davidm@hpl.hp.com>
  *
  * Copyright (C) 2002 Dell Inc.
- * Copyright (C) Matt Domsch (Matt_Domsch@dell.com)
+ * Copyright (C) Matt Domsch <Matt_Domsch@dell.com>
  *
  * Copyright (C) 2002 Intel
- * Copyright (C) Jenna Hall (jenna.s.hall@intel.com)
+ * Copyright (C) Jenna Hall <jenna.s.hall@intel.com>
  *
  * Copyright (C) 2001 Intel
- * Copyright (C) Fred Lewis (frederick.v.lewis@intel.com)
+ * Copyright (C) Fred Lewis <frederick.v.lewis@intel.com>
  *
  * Copyright (C) 2000 Intel
- * Copyright (C) Chuck Fleckenstein (cfleck@co.intel.com)
+ * Copyright (C) Chuck Fleckenstein <cfleck@co.intel.com>
  *
  * Copyright (C) 1999, 2004 Silicon Graphics, Inc.
- * Copyright (C) Vijay Chander(vijay@engr.sgi.com)
+ * Copyright (C) Vijay Chander <vijay@engr.sgi.com>
  *
- * 03/04/15 D. Mosberger Added INIT backtrace support.
- * 02/03/25 M. Domsch  GUID cleanups
+ * Copyright (C) 2006 FUJITSU LIMITED
+ * Copyright (C) Hidetoshi Seto <seto.hidetoshi@jp.fujitsu.com>
  *
- * 02/01/04 J. Hall    Aligned MCA stack to 16 bytes, added platform vs. CPU
- *                     error flag, set SAL default return values, changed
- *                     error record structure to linked list, added init call
- *                     to sal_get_state_info_size().
+ * 2000-03-29 Chuck Fleckenstein <cfleck@co.intel.com>
+ *           Fixed PAL/SAL update issues, began MCA bug fixes, logging issues,
+ *           added min save state dump, added INIT handler.
  *
- * 01/01/03 F. Lewis    Added setup of CMCI and CPEI IRQs, logging of corrected
- *                      platform errors, completed code for logging of
- *                      corrected & uncorrected machine check errors, and
- *                      updated for conformance with Nov. 2000 revision of the
- *                      SAL 3.0 spec.
- * 00/03/29 C. Fleckenstein  Fixed PAL/SAL update issues, began MCA bug fixes, logging issues,
- *                           added min save state dump, added INIT handler.
+ * 2001-01-03 Fred Lewis <frederick.v.lewis@intel.com>
+ *           Added setup of CMCI and CPEI IRQs, logging of corrected platform
+ *           errors, completed code for logging of corrected & uncorrected
+ *           machine check errors, and updated for conformance with Nov. 2000
+ *           revision of the SAL 3.0 spec.
+ *
+ * 2002-01-04 Jenna Hall <jenna.s.hall@intel.com>
+ *           Aligned MCA stack to 16 bytes, added platform vs. CPU error flag,
+ *           set SAL default return values, changed error record structure to
+ *           linked list, added init call to sal_get_state_info_size().
+ *
+ * 2002-03-25 Matt Domsch <Matt_Domsch@dell.com>
+ *           GUID cleanups.
+ *
+ * 2003-04-15 David Mosberger-Tang <davidm@hpl.hp.com>
+ *           Added INIT backtrace support.
  *
  * 2003-12-08 Keith Owens <kaos@sgi.com>
- *            smp_call_function() must not be called from interrupt context (can
- *            deadlock on tasklist_lock).  Use keventd to call smp_call_function().
+ *           smp_call_function() must not be called from interrupt context
+ *           (can deadlock on tasklist_lock).
+ *           Use keventd to call smp_call_function().
  *
  * 2004-02-01 Keith Owens <kaos@sgi.com>
- *            Avoid deadlock when using printk() for MCA and INIT records.
- *            Delete all record printing code, moved to salinfo_decode in user space.
- *            Mark variables and functions static where possible.
- *            Delete dead variables and functions.
- *            Reorder to remove the need for forward declarations and to consolidate
- *            related code.
+ *           Avoid deadlock when using printk() for MCA and INIT records.
+ *           Delete all record printing code, moved to salinfo_decode in user
+ *           space.  Mark variables and functions static where possible.
+ *           Delete dead variables and functions.  Reorder to remove the need
+ *           for forward declarations and to consolidate related code.
  *
  * 2005-08-12 Keith Owens <kaos@sgi.com>
- *           Convert MCA/INIT handlers to use per event stacks and SAL/OS state.
+ *           Convert MCA/INIT handlers to use per event stacks and SAL/OS
+ *           state.
  *
  * 2005-10-07 Keith Owens <kaos@sgi.com>
  *           Add notify_die() hooks.
  *
  * 2006-09-15 Hidetoshi Seto <seto.hidetoshi@jp.fujitsu.com>
- *           Add printing support for MCA/INIT.
+ *           Add printing support for MCA/INIT.
  *
  * 2007-04-27 Russ Anderson <rja@sgi.com>
  *           Support multiple cpus going through OS_MCA in the same event.
index 0f5965fcdf85133fbf0c455f714dcbea091eea2d..8bc7d259e0c646313c56e8ac6ee22a8319b81370 100644 (file)
@@ -1,24 +1,28 @@
-//
-// assembly portion of the IA64 MCA handling
-//
-// Mods by cfleck to integrate into kernel build
-// 00/03/15 davidm Added various stop bits to get a clean compile
-//
-// 00/03/29 cfleck Added code to save INIT handoff state in pt_regs format, switch to temp
-//                kstack, switch modes, jump to C INIT handler
-//
-// 02/01/04 J.Hall <jenna.s.hall@intel.com>
-//                Before entering virtual mode code:
-//                1. Check for TLB CPU error
-//                2. Restore current thread pointer to kr6
-//                3. Move stack ptr 16 bytes to conform to C calling convention
-//
-// 04/11/12 Russ Anderson <rja@sgi.com>
-//                Added per cpu MCA/INIT stack save areas.
-//
-// 12/08/05 Keith Owens <kaos@sgi.com>
-//                Use per cpu MCA/INIT stacks for all data.
-//
+/*
+ * File:       mca_asm.S
+ * Purpose:    assembly portion of the IA64 MCA handling
+ *
+ * Mods by cfleck to integrate into kernel build
+ *
+ * 2000-03-15 David Mosberger-Tang <davidm@hpl.hp.com>
+ *             Added various stop bits to get a clean compile
+ *
+ * 2000-03-29 Chuck Fleckenstein <cfleck@co.intel.com>
+ *             Added code to save INIT handoff state in pt_regs format,
+ *             switch to temp kstack, switch modes, jump to C INIT handler
+ *
+ * 2002-01-04 J.Hall <jenna.s.hall@intel.com>
+ *             Before entering virtual mode code:
+ *              1. Check for TLB CPU error
+ *              2. Restore current thread pointer to kr6
+ *              3. Move stack ptr 16 bytes to conform to C calling convention
+ *
+ * 2004-11-12 Russ Anderson <rja@sgi.com>
+ *             Added per cpu MCA/INIT stack save areas.
+ *
+ * 2005-12-08 Keith Owens <kaos@sgi.com>
+ *             Use per cpu MCA/INIT stacks for all data.
+ */
 #include <linux/threads.h>
 
 #include <asm/asmmacro.h>
index aba813c2c150670e808078a4e5866096f523a3db..fab1d21a4f2c1cfe4443aa8812518d4a6bfeaeb6 100644 (file)
@@ -3,7 +3,7 @@
  * Purpose:    Generic MCA handling layer
  *
  * Copyright (C) 2004 FUJITSU LIMITED
- * Copyright (C) Hidetoshi Seto (seto.hidetoshi@jp.fujitsu.com)
+ * Copyright (C) 2004 Hidetoshi Seto <seto.hidetoshi@jp.fujitsu.com>
  * Copyright (C) 2005 Silicon Graphics, Inc
  * Copyright (C) 2005 Keith Owens <kaos@sgi.com>
  * Copyright (C) 2006 Russ Anderson <rja@sgi.com>
index 485e34d0b199333c3ff763f1c22c919628b09575..53b8ecb5b4b9de8b6c08e1a78acdd7ef2a47697c 100644 (file)
@@ -3,7 +3,7 @@
  * Purpose:    Define helpers for Generic MCA handling
  *
  * Copyright (C) 2004 FUJITSU LIMITED
- * Copyright (C) Hidetoshi Seto (seto.hidetoshi@jp.fujitsu.com)
+ * Copyright (C) 2004 Hidetoshi Seto <seto.hidetoshi@jp.fujitsu.com>
  */
 /*
  * Processor error section:
index 3bccb06c8d216cc1439c0f0081e6bacce2668035..767ac2c20d16a1eb28c9a7ec9a6ecea140740a15 100644 (file)
@@ -3,7 +3,7 @@
  * Purpose:     Assembly portion of Generic MCA handling
  *
  * Copyright (C) 2004 FUJITSU LIMITED
- * Copyright (C) Hidetoshi Seto (seto.hidetoshi@jp.fujitsu.com)
+ * Copyright (C) 2004 Hidetoshi Seto <seto.hidetoshi@jp.fujitsu.com>
  */
 #include <linux/threads.h>
 
index e699eb6c44be0f788397ba0300bac77800db1767..e58f4367cf11db4ad4cca80fed0785f7283d5b15 100644 (file)
@@ -940,14 +940,3 @@ module_arch_cleanup (struct module *mod)
        if (mod->arch.core_unw_table)
                unw_remove_unwind_table(mod->arch.core_unw_table);
 }
-
-#ifdef CONFIG_SMP
-void
-percpu_modcopy (void *pcpudst, const void *src, unsigned long size)
-{
-       unsigned int i;
-       for_each_possible_cpu(i) {
-               memcpy(pcpudst + per_cpu_offset(i), src, size);
-       }
-}
-#endif /* CONFIG_SMP */
index 73e7c2e40b54713e69566772b79d3b92fc44a7da..78acd9fe97e98263b0cfc431d9b37a71aa594a19 100644 (file)
@@ -2631,7 +2631,7 @@ pfm_task_incompatible(pfm_context_t *ctx, struct task_struct *task)
         */
        if (task == current) return 0;
 
-       if ((task->state != TASK_STOPPED) && (task->state != TASK_TRACED)) {
+       if (!task_is_stopped_or_traced(task)) {
                DPRINT(("cannot attach to non-stopped task [%d] state=%ld\n", task_pid_nr(task), task->state));
                return -EBUSY;
        }
@@ -2654,11 +2654,11 @@ pfm_get_task(pfm_context_t *ctx, pid_t pid, struct task_struct **task)
        /* XXX: need to add more checks here */
        if (pid < 2) return -EPERM;
 
-       if (pid != current->pid) {
+       if (pid != task_pid_vnr(current)) {
 
                read_lock(&tasklist_lock);
 
-               p = find_task_by_pid(pid);
+               p = find_task_by_vpid(pid);
 
                /* make sure task cannot go away while we operate on it */
                if (p) get_task_struct(p);
@@ -4792,7 +4792,7 @@ recheck:
         * the task must be stopped.
         */
        if (PFM_CMD_STOPPED(cmd)) {
-               if ((task->state != TASK_STOPPED) && (task->state != TASK_TRACED)) {
+               if (!task_is_stopped_or_traced(task)) {
                        DPRINT(("[%d] task not in stopped state\n", task_pid_nr(task)));
                        return -EBUSY;
                }
@@ -5795,7 +5795,7 @@ pfm_proc_show(struct seq_file *m, void *v)
        return 0;
 }
 
-struct seq_operations pfm_seq_ops = {
+const struct seq_operations pfm_seq_ops = {
        .start =        pfm_proc_start,
        .next =         pfm_proc_next,
        .stop =         pfm_proc_stop,
index 27c2ef445a565abb1cb62c8ae8ff983a4ca6f2fc..f44fe8412162c55b73b80663d8bb3e8d4d3d50a9 100644 (file)
@@ -284,6 +284,7 @@ ia64_sal_cache_flush (u64 cache_type)
        SAL_CALL(isrv, SAL_CACHE_FLUSH, cache_type, 0, 0, 0, 0, 0, 0);
        return isrv.status;
 }
+EXPORT_SYMBOL_GPL(ia64_sal_cache_flush);
 
 void __init
 ia64_sal_init (struct ia64_sal_systab *systab)
@@ -372,3 +373,16 @@ ia64_sal_oemcall_reentrant(struct ia64_sal_retval *isrvp, u64 oemfunc,
        return 0;
 }
 EXPORT_SYMBOL(ia64_sal_oemcall_reentrant);
+
+long
+ia64_sal_freq_base (unsigned long which, unsigned long *ticks_per_second,
+                   unsigned long *drift_info)
+{
+       struct ia64_sal_retval isrv;
+
+       SAL_CALL(isrv, SAL_FREQ_BASE, which, 0, 0, 0, 0, 0, 0);
+       *ticks_per_second = isrv.v0;
+       *drift_info = isrv.v1;
+       return isrv.status;
+}
+EXPORT_SYMBOL_GPL(ia64_sal_freq_base);
index 86028c69861e23373b1162fc20607a858da3b3e3..ebd1a09f32016b870ccb758dac93f1ade566f866 100644 (file)
@@ -654,7 +654,7 @@ c_stop (struct seq_file *m, void *v)
 {
 }
 
-struct seq_operations cpuinfo_op = {
+const struct seq_operations cpuinfo_op = {
        .start =        c_start,
        .next =         c_next,
        .stop =         c_stop,
index f0fc4d8465ad172cc9f4f0ce4215de85b3b3a09a..480b1a5085d542d22618b29a7e763e8f8f3904d6 100644 (file)
@@ -767,17 +767,6 @@ void __cpu_die(unsigned int cpu)
        }
        printk(KERN_ERR "CPU %u didn't die...\n", cpu);
 }
-#else /* !CONFIG_HOTPLUG_CPU */
-int __cpu_disable(void)
-{
-       return -ENOSYS;
-}
-
-void __cpu_die(unsigned int cpu)
-{
-       /* We said "no" in __cpu_disable */
-       BUG();
-}
 #endif /* CONFIG_HOTPLUG_CPU */
 
 void
index 78d65cb947d29c4fb763c346efed30a307130bfc..f0cda765e681d1252347675d45f582f8ab470b65 100644 (file)
@@ -35,7 +35,7 @@ trap_init (void)
                fpswa_interface = __va(ia64_boot_param->fpswa);
 }
 
-void
+int
 die (const char *str, struct pt_regs *regs, long err)
 {
        static struct {
@@ -62,8 +62,11 @@ die (const char *str, struct pt_regs *regs, long err)
        if (++die.lock_owner_depth < 3) {
                printk("%s[%d]: %s %ld [%d]\n",
                current->comm, task_pid_nr(current), str, err, ++die_counter);
-               (void) notify_die(DIE_OOPS, (char *)str, regs, err, 255, SIGSEGV);
-               show_regs(regs);
+               if (notify_die(DIE_OOPS, str, regs, err, 255, SIGSEGV)
+                   != NOTIFY_STOP)
+                       show_regs(regs);
+               else
+                       regs = NULL;
        } else
                printk(KERN_ERR "Recursive die() failure, output suppressed\n");
 
@@ -72,17 +75,22 @@ die (const char *str, struct pt_regs *regs, long err)
        add_taint(TAINT_DIE);
        spin_unlock_irq(&die.lock);
 
+       if (!regs)
+               return 1;
+
        if (panic_on_oops)
                panic("Fatal exception");
 
        do_exit(SIGSEGV);
+       return 0;
 }
 
-void
+int
 die_if_kernel (char *str, struct pt_regs *regs, long err)
 {
        if (!user_mode(regs))
-               die(str, regs, err);
+               return die(str, regs, err);
+       return 0;
 }
 
 void
@@ -102,7 +110,8 @@ __kprobes ia64_bad_break (unsigned long break_num, struct pt_regs *regs)
                if (notify_die(DIE_BREAK, "break 0", regs, break_num, TRAP_BRKPT, SIGTRAP)
                                == NOTIFY_STOP)
                        return;
-               die_if_kernel("bugcheck!", regs, break_num);
+               if (die_if_kernel("bugcheck!", regs, break_num))
+                       return;
                sig = SIGILL; code = ILL_ILLOPC;
                break;
 
@@ -155,8 +164,9 @@ __kprobes ia64_bad_break (unsigned long break_num, struct pt_regs *regs)
                break;
 
              default:
-               if (break_num < 0x40000 || break_num > 0x100000)
-                       die_if_kernel("Bad break", regs, break_num);
+               if ((break_num < 0x40000 || break_num > 0x100000)
+                   && die_if_kernel("Bad break", regs, break_num))
+                       return;
 
                if (break_num < 0x80000) {
                        sig = SIGILL; code = __ILL_BREAK;
@@ -402,14 +412,15 @@ ia64_illegal_op_fault (unsigned long ec, long arg1, long arg2, long arg3,
 #endif
 
        sprintf(buf, "IA-64 Illegal operation fault");
-       die_if_kernel(buf, &regs, 0);
+       rv.fkt = 0;
+       if (die_if_kernel(buf, &regs, 0))
+               return rv;
 
        memset(&si, 0, sizeof(si));
        si.si_signo = SIGILL;
        si.si_code = ILL_ILLOPC;
        si.si_addr = (void __user *) (regs.cr_iip + ia64_psr(&regs)->ri);
        force_sig_info(SIGILL, &si, current);
-       rv.fkt = 0;
        return rv;
 }
 
@@ -644,6 +655,6 @@ ia64_fault (unsigned long vector, unsigned long isr, unsigned long ifa,
                sprintf(buf, "Fault %lu", vector);
                break;
        }
-       die_if_kernel(buf, &regs, error);
-       force_sig(SIGILL, current);
+       if (!die_if_kernel(buf, &regs, error))
+               force_sig(SIGILL, current);
 }
index f6a1aeb742b3827acce249f7e5c84137678be1e6..52f70bbc192a6faa68ad87bd76bde20b37a6bb73 100644 (file)
@@ -23,7 +23,7 @@
 #include <asm/uaccess.h>
 #include <asm/unaligned.h>
 
-extern void die_if_kernel(char *str, struct pt_regs *regs, long err);
+extern int die_if_kernel(char *str, struct pt_regs *regs, long err);
 
 #undef DEBUG_UNALIGNED_TRAP
 
@@ -675,8 +675,9 @@ emulate_load_updates (update_t type, load_store_t ld, struct pt_regs *regs, unsi
         */
        if (ld.x6_op == 1 || ld.x6_op == 3) {
                printk(KERN_ERR "%s: register update on speculative load, error\n", __FUNCTION__);
-               die_if_kernel("unaligned reference on speculative load with register update\n",
-                             regs, 30);
+               if (die_if_kernel("unaligned reference on speculative load with register update\n",
+                                 regs, 30))
+                       return;
        }
 
 
@@ -1317,7 +1318,8 @@ ia64_handle_unaligned (unsigned long ifa, struct pt_regs *regs)
 
        if (ia64_psr(regs)->be) {
                /* we don't support big-endian accesses */
-               die_if_kernel("big-endian unaligned accesses are not supported", regs, 0);
+               if (die_if_kernel("big-endian unaligned accesses are not supported", regs, 0))
+                       return;
                goto force_sigbus;
        }
 
@@ -1534,7 +1536,8 @@ ia64_handle_unaligned (unsigned long ifa, struct pt_regs *regs)
                        ia64_handle_exception(regs, eh);
                        goto done;
                }
-               die_if_kernel("error during unaligned kernel access\n", regs, ret);
+               if (die_if_kernel("error during unaligned kernel access\n", regs, ret))
+                       return;
                /* NOT_REACHED */
        }
   force_sigbus:
index 7571076a16a1991742af9f502b2113f7d9bd35a4..3e69881648a35ea1b91536b52eeb9387de9fd8d6 100644 (file)
@@ -16,7 +16,7 @@
 #include <asm/system.h>
 #include <asm/uaccess.h>
 
-extern void die (char *, struct pt_regs *, long);
+extern int die(char *, struct pt_regs *, long);
 
 #ifdef CONFIG_KPROBES
 static inline int notify_page_fault(struct pt_regs *regs, int trap)
@@ -267,9 +267,11 @@ ia64_do_page_fault (unsigned long address, unsigned long isr, struct pt_regs *re
        else
                printk(KERN_ALERT "Unable to handle kernel paging request at "
                       "virtual address %016lx\n", address);
-       die("Oops", regs, isr);
+       if (die("Oops", regs, isr))
+               regs = NULL;
        bust_spinlocks(0);
-       do_exit(SIGKILL);
+       if (regs)
+               do_exit(SIGKILL);
        return;
 
   out_of_memory:
index f3c69329e14538934de9c983b422bb9dc52f763a..dfc6bf1c7b412084a6a3038a6b2bb35fb0c1da7d 100644 (file)
@@ -523,7 +523,7 @@ static ssize_t sn2_ptc_proc_write(struct file *file, const char __user *user, si
        return count;
 }
 
-static struct seq_operations sn2_ptc_seq_ops = {
+static const struct seq_operations sn2_ptc_seq_ops = {
        .start = sn2_ptc_seq_start,
        .next = sn2_ptc_seq_next,
        .stop = sn2_ptc_seq_stop,
index 1a8e49607f114e7febdcaa51913bf54527893617..4b0d1538e7e5586450fd2fe39c363af2768bdc35 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/smp_lock.h>
 #include <linux/nodemask.h>
 #include <linux/smp.h>
+#include <linux/mutex.h>
 
 #include <asm/processor.h>
 #include <asm/topology.h>
@@ -50,7 +51,7 @@ static void *sn_hwperf_salheap = NULL;
 static int sn_hwperf_obj_cnt = 0;
 static nasid_t sn_hwperf_master_nasid = INVALID_NASID;
 static int sn_hwperf_init(void);
-static DECLARE_MUTEX(sn_hwperf_init_mutex);
+static DEFINE_MUTEX(sn_hwperf_init_mutex);
 
 #define cnode_possible(n)      ((n) < num_cnodes)
 
@@ -577,7 +578,7 @@ static void sn_topology_stop(struct seq_file *m, void *v)
 /*
  * /proc/sgi_sn/sn_topology, read-only using seq_file
  */
-static struct seq_operations sn_topology_seq_ops = {
+static const struct seq_operations sn_topology_seq_ops = {
        .start = sn_topology_start,
        .next = sn_topology_next,
        .stop = sn_topology_stop,
@@ -884,10 +885,10 @@ static int sn_hwperf_init(void)
        int e = 0;
 
        /* single threaded, once-only initialization */
-       down(&sn_hwperf_init_mutex);
+       mutex_lock(&sn_hwperf_init_mutex);
 
        if (sn_hwperf_salheap) {
-               up(&sn_hwperf_init_mutex);
+               mutex_unlock(&sn_hwperf_init_mutex);
                return e;
        }
 
@@ -936,7 +937,7 @@ out:
                sn_hwperf_salheap = NULL;
                sn_hwperf_obj_cnt = 0;
        }
-       up(&sn_hwperf_init_mutex);
+       mutex_unlock(&sn_hwperf_init_mutex);
        return e;
 }
 
index f7237c5f531e511806133f0223ecd48edb0399ab..795180b8fd8e6199e56d118fec12f09a3079eb35 100644 (file)
@@ -8,6 +8,7 @@ mainmenu "Linux/M32R Kernel Configuration"
 config M32R
        bool
        default y
+       select HAVE_OPROFILE
 
 config SBUS
        bool
@@ -302,8 +303,7 @@ config SMP
          Y to "Enhanced Real Time Clock Support", below. The "Advanced Power
          Management" code will be disabled if you say Y here.
 
-         See also the <file:Documentation/smp.txt>,
-         and the SMP-HOWTO available at
+         See also the SMP-HOWTO available at
          <http://www.linuxdoc.org/docs.html#howto>.
 
          If you don't know what to do here, say N.
@@ -359,11 +359,6 @@ config PCI
          your box. Other bus systems are ISA, EISA, MicroChannel (MCA) or
          VESA. If you have PCI, say Y, otherwise N.
 
-         The PCI-HOWTO, available from
-         <http://www.linuxdoc.org/docs.html#howto>, contains valuable
-         information about which PCI hardware does work under Linux and which
-         doesn't.
-
 choice
        prompt "PCI access mode"
        depends on PCI
@@ -431,8 +426,6 @@ source "drivers/Kconfig"
 
 source "fs/Kconfig"
 
-source "kernel/Kconfig.instrumentation"
-
 source "arch/m32r/Kconfig.debug"
 
 source "security/Kconfig"
index ee3c8be12fa0efba5244d5c1f1b393760f131e89..01d877c6868f05e5a8fb72639a980cd4b7ef66dc 100644 (file)
@@ -17,7 +17,7 @@ static int puts(const char *s)
        return 0;
 }
 
-#if defined(CONFIG_PLAT_M32700UT_Alpha) || defined(CONFIG_PLAT_M32700UT) || defined(CONFIG_PLAT_OPSPUT)
+#if defined(CONFIG_PLAT_M32700UT) || defined(CONFIG_PLAT_OPSPUT)
 #include <asm/m32r.h>
 #include <asm/io.h>
 
@@ -52,7 +52,7 @@ static void putc(char c)
        }
        *BOOT_SIO0TXB = c;
 }
-#else /* !(CONFIG_PLAT_M32700UT_Alpha) && !(CONFIG_PLAT_M32700UT) */
+#else /* !(CONFIG_PLAT_M32700UT) */
 #if defined(CONFIG_PLAT_MAPPI2)
 #define SIO0STS        (volatile unsigned short *)(0xa0efd000 + 14)
 #define SIO0TXB        (volatile unsigned short *)(0xa0efd000 + 30)
index ed4d0756c5dbd0abd84a39bd4b0c43cf20118aea..9aa615d3a5b24372cdd1a193ee7869cd4c5ce78e 100644 (file)
@@ -476,7 +476,7 @@ unregister_debug_trap(struct task_struct *child, unsigned long addr,
                return 0;
        }
 
-       /* Recover orignal instruction code. */
+       /* Recover original instruction code. */
        *code = p->insn[i];
 
        /* Shift debug trap entries. */
index 95aa79874847135989d141c7aa6bf52f3a3ed2cf..aa3bf4cfab37cd8b0f999ba5211baeef6ebae3c3 100644 (file)
@@ -321,6 +321,6 @@ ENTRY(sys_call_table)
        .long sys_epoll_pwait
        .long sys_utimensat             /* 320 */
        .long sys_signalfd
-       .long sys_timerfd
+       .long sys_ni_syscall
        .long sys_eventfd
        .long sys_fallocate
index 01dee84f840ac72608dae4fe0ea4997b3e911f81..ffabd01c45eb1e4309680210cd30821cf4591864 100644 (file)
@@ -145,11 +145,6 @@ config PCI
          your box. Other bus systems are ISA, EISA, MicroChannel (MCA) or
          VESA. If you have PCI, say Y, otherwise N.
 
-         The PCI-HOWTO, available from
-         <http://www.tldp.org/docs.html#howto>, contains valuable
-         information about which PCI hardware does work under Linux and which
-         doesn't.
-
 config MAC
        bool "Macintosh support"
        depends on !MMU_SUN3
@@ -582,20 +577,6 @@ config MAC_HID
        depends on INPUT_ADBHID
        default y
 
-config MAC_ADBKEYCODES
-       bool "Support for ADB raw keycodes"
-       depends on INPUT_ADBHID
-       help
-         This provides support for sending raw ADB keycodes to console
-         devices.  This is the default up to 2.4.0, but in future this may be
-         phased out in favor of generic Linux keycodes.  If you say Y here,
-         you can dynamically switch via the
-         /proc/sys/dev/mac_hid/keyboard_sends_linux_keycodes
-         sysctl and with the "keyboard_sends_linux_keycodes=" kernel
-         argument.
-
-         If unsure, say Y here.
-
 config ADB_KEYBOARD
        bool "Support for ADB keyboard (old driver)"
        depends on MAC && !INPUT_ADBHID
@@ -683,8 +664,6 @@ endmenu
 
 source "fs/Kconfig"
 
-source "kernel/Kconfig.instrumentation"
-
 source "arch/m68k/Kconfig.debug"
 
 source "security/Kconfig"
index 4a1bd44ff162734a2864bf5c2ebc71a6b64c459f..2cba605cb59d16814bd5685ae4797a15459d1759 100644 (file)
 # Copyright (C) 1994 by Hamish Macdonald
 #
 
-# test for cross compiling
-COMPILE_ARCH = $(shell uname -m)
-
 # override top level makefile
 AS += -m68020
 LDFLAGS := -m m68kelf
 LDFLAGS_MODULE += -T $(srctree)/arch/m68k/kernel/module.lds
-ifneq ($(COMPILE_ARCH),$(ARCH))
-       # prefix for cross-compiling binaries
-       CROSS_COMPILE = m68k-linux-gnu-
+ifneq ($(SUBARCH),$(ARCH))
+       ifeq ($(CROSS_COMPILE),)
+               CROSS_COMPILE := $(call cc-cross-prefix, \
+                       m68k-linux-gnu- m68k-linux- m68k-unknown-linux-gnu-)
+       endif
 endif
 
 ifdef CONFIG_SUN3
index 8b415651edee270475bc4fea87cad9b0d099e0b1..6a0d7650f980fcdcbd5d5ab3b4547f4120bc65b8 100644 (file)
@@ -2,6 +2,6 @@
 # Makefile for Linux arch/m68k/amiga source directory
 #
 
-obj-y          := config.o amiints.o cia.o chipram.o amisound.o amiga_ksyms.o
+obj-y          := config.o amiints.o cia.o chipram.o amisound.o
 
 obj-$(CONFIG_AMIGA_PCMCIA)     += pcmcia.o
diff --git a/arch/m68k/amiga/amiga_ksyms.c b/arch/m68k/amiga/amiga_ksyms.c
deleted file mode 100644 (file)
index 7fdcf6b..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-#include <linux/module.h>
-#include <linux/types.h>
-#include <asm/ptrace.h>
-#include <asm/amigahw.h>
-#include <asm/amigaints.h>
-#include <asm/amipcmcia.h>
-
-extern volatile u_short amiga_audio_min_period;
-extern u_short amiga_audio_period;
-
-/*
- * Add things here when you find the need for it.
- */
-EXPORT_SYMBOL(amiga_model);
-EXPORT_SYMBOL(amiga_chipset);
-EXPORT_SYMBOL(amiga_hw_present);
-EXPORT_SYMBOL(amiga_eclock);
-EXPORT_SYMBOL(amiga_colorclock);
-EXPORT_SYMBOL(amiga_chip_alloc);
-EXPORT_SYMBOL(amiga_chip_free);
-EXPORT_SYMBOL(amiga_chip_avail);
-EXPORT_SYMBOL(amiga_chip_size);
-EXPORT_SYMBOL(amiga_audio_period);
-EXPORT_SYMBOL(amiga_audio_min_period);
-
-#ifdef CONFIG_AMIGA_PCMCIA
-  EXPORT_SYMBOL(pcmcia_reset);
-  EXPORT_SYMBOL(pcmcia_copy_tuple);
-  EXPORT_SYMBOL(pcmcia_program_voltage);
-  EXPORT_SYMBOL(pcmcia_access_speed);
-  EXPORT_SYMBOL(pcmcia_write_enable);
-  EXPORT_SYMBOL(pcmcia_write_disable);
-#endif
index 1f5bfb58429783be182e8aad94d2a5f94eb28d7d..61e5c54625aeee7dd2a3a206e38051c6430ea0bd 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/timer.h>
 #include <linux/init.h>
 #include <linux/string.h>
+#include <linux/module.h>
 
 #include <asm/system.h>
 #include <asm/amigahw.h>
@@ -21,7 +22,7 @@ static const signed char sine_data[] = {
        0,  39,  75,  103,  121,  127,  121,  103,  75,  39,
        0, -39, -75, -103, -121, -127, -121, -103, -75, -39
 };
-#define DATA_SIZE      (sizeof(sine_data)/sizeof(sine_data[0]))
+#define DATA_SIZE      ARRAY_SIZE(sine_data)
 
 #define custom amiga_custom
 
@@ -31,6 +32,7 @@ static const signed char sine_data[] = {
      */
 
 volatile unsigned short amiga_audio_min_period = 124; /* Default for pre-OCS */
+EXPORT_SYMBOL(amiga_audio_min_period);
 
 #define MAX_PERIOD     (65535)
 
@@ -40,6 +42,7 @@ volatile unsigned short amiga_audio_min_period = 124; /* Default for pre-OCS */
      */
 
 unsigned short amiga_audio_period = MAX_PERIOD;
+EXPORT_SYMBOL(amiga_audio_period);
 
 static unsigned long clock_constant;
 
index fa015d80161701ccf3e8a390f8e373e072ba08f8..d10726f9038b91606bf894c472703f383a81baf9 100644 (file)
 #include <linux/ioport.h>
 #include <linux/slab.h>
 #include <linux/string.h>
+#include <linux/module.h>
+
 #include <asm/page.h>
 #include <asm/amigahw.h>
 
 unsigned long amiga_chip_size;
+EXPORT_SYMBOL(amiga_chip_size);
 
 static struct resource chipram_res = {
     .name = "Chip RAM", .start = CHIP_PHYSADDR
@@ -67,6 +70,7 @@ void *amiga_chip_alloc(unsigned long size, const char *name)
 #endif
     return (void *)ZTWO_VADDR(res->start);
 }
+EXPORT_SYMBOL(amiga_chip_alloc);
 
 
     /*
@@ -120,6 +124,7 @@ void amiga_chip_free(void *ptr)
     }
     printk("amiga_chip_free: trying to free nonexistent region at %p\n", ptr);
 }
+EXPORT_SYMBOL(amiga_chip_free);
 
 
 unsigned long amiga_chip_avail(void)
@@ -129,3 +134,5 @@ unsigned long amiga_chip_avail(void)
 #endif
        return chipavail;
 }
+EXPORT_SYMBOL(amiga_chip_avail);
+
index 35748531327dac74710c653017395b73348014fc..50f5daab46b7b53ecb282fc50a6e8bad8f3df2df 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/zorro.h>
+#include <linux/module.h>
 
 #include <asm/bootinfo.h>
 #include <asm/setup.h>
 #include <asm/io.h>
 
 unsigned long amiga_model;
+EXPORT_SYMBOL(amiga_model);
+
 unsigned long amiga_eclock;
+EXPORT_SYMBOL(amiga_eclock);
+
 unsigned long amiga_masterclock;
+
 unsigned long amiga_colorclock;
+EXPORT_SYMBOL(amiga_colorclock);
+
 unsigned long amiga_chipset;
+EXPORT_SYMBOL(amiga_chipset);
+
 unsigned char amiga_vblank;
 unsigned char amiga_psfreq;
+
 struct amiga_hw_present amiga_hw_present;
+EXPORT_SYMBOL(amiga_hw_present);
 
 static char s_a500[] __initdata = "A500";
 static char s_a500p[] __initdata = "A500+";
index 186662ca1a89dd0603d8df5e9865b9d62dddbb32..7106f0c3639bc105ca18fc2cfb777717be7727e5 100644 (file)
@@ -15,6 +15,8 @@
 #include <linux/types.h>
 #include <linux/jiffies.h>
 #include <linux/timer.h>
+#include <linux/module.h>
+
 #include <asm/amigayle.h>
 #include <asm/amipcmcia.h>
 
@@ -30,6 +32,7 @@ void pcmcia_reset(void)
        while (time_before(jiffies, reset_start_time + 1*HZ/100));
        b = gayle_reset;
 }
+EXPORT_SYMBOL(pcmcia_reset);
 
 
 /* copy a tuple, including tuple header. return nb bytes copied */
@@ -61,6 +64,7 @@ int pcmcia_copy_tuple(unsigned char tuple_id, void *tuple, int max_len)
 
        return 0;
 }
+EXPORT_SYMBOL(pcmcia_copy_tuple);
 
 void pcmcia_program_voltage(int voltage)
 {
@@ -84,6 +88,7 @@ void pcmcia_program_voltage(int voltage)
        gayle.config = cfg_byte;
 
 }
+EXPORT_SYMBOL(pcmcia_program_voltage);
 
 void pcmcia_access_speed(int speed)
 {
@@ -101,13 +106,17 @@ void pcmcia_access_speed(int speed)
        cfg_byte = (cfg_byte & 0xf3) | s;
        gayle.config = cfg_byte;
 }
+EXPORT_SYMBOL(pcmcia_access_speed);
 
 void pcmcia_write_enable(void)
 {
        gayle.cardstatus = GAYLE_CS_WR|GAYLE_CS_DA;
 }
+EXPORT_SYMBOL(pcmcia_write_enable);
 
 void pcmcia_write_disable(void)
 {
        gayle.cardstatus = 0;
 }
+EXPORT_SYMBOL(pcmcia_write_disable);
+
index 2cb86191f0aab653f2449b7df16af28346d96d54..2cd905efe63abb15572d653fd6ee71b485c952b3 100644 (file)
@@ -3,7 +3,7 @@
 #
 
 obj-y          := config.o time.o debug.o ataints.o stdma.o \
-                       atasound.o stram.o atari_ksyms.o
+                       atasound.o stram.o
 
 ifeq ($(CONFIG_PCI),y)
 obj-$(CONFIG_HADES)    += hades-pci.o
index b85ca22024c1bbf2655ad75151e6ea795ec98b6f..b45593a60bddf67bfdb57e611ded063f3b386993 100644 (file)
@@ -40,6 +40,7 @@
 #include <linux/kernel_stat.h>
 #include <linux/init.h>
 #include <linux/seq_file.h>
+#include <linux/module.h>
 
 #include <asm/system.h>
 #include <asm/traps.h>
@@ -446,6 +447,7 @@ unsigned long atari_register_vme_int(void)
        free_vme_vec_bitmap |= 1 << i;
        return VME_SOURCE_BASE + i;
 }
+EXPORT_SYMBOL(atari_register_vme_int);
 
 
 void atari_unregister_vme_int(unsigned long irq)
@@ -455,5 +457,6 @@ void atari_unregister_vme_int(unsigned long irq)
                free_vme_vec_bitmap &= ~(1 << irq);
        }
 }
+EXPORT_SYMBOL(atari_unregister_vme_int);
 
 
diff --git a/arch/m68k/atari/atari_ksyms.c b/arch/m68k/atari/atari_ksyms.c
deleted file mode 100644 (file)
index a047571..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-#include <linux/module.h>
-
-#include <asm/ptrace.h>
-#include <asm/traps.h>
-#include <asm/atarihw.h>
-#include <asm/atariints.h>
-#include <asm/atarikb.h>
-#include <asm/atari_joystick.h>
-#include <asm/atari_stdma.h>
-#include <asm/atari_stram.h>
-
-extern void atari_microwire_cmd( int cmd );
-extern int atari_MFP_init_done;
-extern int atari_SCC_init_done;
-extern int atari_SCC_reset_done;
-
-EXPORT_SYMBOL(atari_mch_cookie);
-EXPORT_SYMBOL(atari_mch_type);
-EXPORT_SYMBOL(atari_hw_present);
-EXPORT_SYMBOL(atari_switches);
-EXPORT_SYMBOL(atari_dont_touch_floppy_select);
-EXPORT_SYMBOL(atari_register_vme_int);
-EXPORT_SYMBOL(atari_unregister_vme_int);
-EXPORT_SYMBOL(stdma_lock);
-EXPORT_SYMBOL(stdma_release);
-EXPORT_SYMBOL(stdma_others_waiting);
-EXPORT_SYMBOL(stdma_islocked);
-EXPORT_SYMBOL(atari_stram_alloc);
-EXPORT_SYMBOL(atari_stram_free);
-
-EXPORT_SYMBOL(atari_MFP_init_done);
-EXPORT_SYMBOL(atari_SCC_init_done);
-EXPORT_SYMBOL(atari_SCC_reset_done);
-
-EXPORT_SYMBOL(atari_microwire_cmd);
index ee04250eb56bdd38b05724a5e45bb5a518792a61..d266fe89c125e2297fa595140154ac9d2d7cf9a2 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/fcntl.h>
 #include <linux/errno.h>
 #include <linux/mm.h>
+#include <linux/module.h>
 
 #include <asm/atarihw.h>
 #include <asm/system.h>
@@ -43,6 +44,7 @@ void atari_microwire_cmd (int cmd)
        while( tt_microwire.mask != 0x7ff)
                ;
 }
+EXPORT_SYMBOL(atari_microwire_cmd);
 
 
 /* PSG base frequency */
index e40e5dcaa347ab3d0e87dab1a99e0d86d846e479..5945e15055582821ee0b1adcab4d640c8d3b1b56 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/delay.h>
 #include <linux/ioport.h>
 #include <linux/vt_kern.h>
+#include <linux/module.h>
 
 #include <asm/bootinfo.h>
 #include <asm/setup.h>
 #include <asm/io.h>
 
 u_long atari_mch_cookie;
+EXPORT_SYMBOL(atari_mch_cookie);
+
 u_long atari_mch_type;
+EXPORT_SYMBOL(atari_mch_type);
+
 struct atari_hw_present atari_hw_present;
+EXPORT_SYMBOL(atari_hw_present);
+
 u_long atari_switches;
+EXPORT_SYMBOL(atari_switches);
+
 int atari_dont_touch_floppy_select;
+EXPORT_SYMBOL(atari_dont_touch_floppy_select);
+
 int atari_rtc_year_offset;
 
 /* local function prototypes */
index fbeed8c8ecbcfb3df43932f06a442729ddd42fab..043ddbc61c7b1f2c63038a4de7bfd188f2b0ef9c 100644 (file)
 #include <linux/console.h>
 #include <linux/init.h>
 #include <linux/delay.h>
+#include <linux/module.h>
 
 #include <asm/atarihw.h>
 #include <asm/atariints.h>
 
 /* Flag that Modem1 port is already initialized and used */
 int atari_MFP_init_done;
+EXPORT_SYMBOL(atari_MFP_init_done);
+
 /* Flag that Modem1 port is already initialized and used */
 int atari_SCC_init_done;
+EXPORT_SYMBOL(atari_SCC_init_done);
+
 /* Can be set somewhere, if a SCC master reset has already be done and should
  * not be repeated; used by kgdb */
 int atari_SCC_reset_done;
+EXPORT_SYMBOL(atari_SCC_reset_done);
 
 static struct console atari_console_driver = {
        .name   = "debug",
index bee2b1443e368763d9473bc86894b3ed0b60a5b2..2bbabc00870875caf7de565327f26317fe050a66 100644 (file)
@@ -376,8 +376,8 @@ struct pci_bus_info * __init init_hades_pci(void)
         */
 
        bus = kzalloc(sizeof(struct pci_bus_info), GFP_KERNEL);
-       if (!bus)
-               return NULL;
+       if (unlikely(!bus))
+               goto iounmap_base_virt;
 
        /*
         * Claim resources. The m68k has no separate I/O space, both
@@ -385,43 +385,25 @@ struct pci_bus_info * __init init_hades_pci(void)
         * the I/O resources are requested in memory space as well.
         */
 
-       if (request_resource(&iomem_resource, &config_space) != 0)
-       {
-               kfree(bus);
-               return NULL;
-       }
+       if (unlikely(request_resource(&iomem_resource, &config_space) != 0))
+               goto free_bus;
 
-       if (request_resource(&iomem_resource, &io_space) != 0)
-       {
-               release_resource(&config_space);
-               kfree(bus);
-               return NULL;
-       }
+       if (unlikely(request_resource(&iomem_resource, &io_space) != 0))
+               goto release_config_space;
 
        bus->mem_space.start = HADES_MEM_BASE;
        bus->mem_space.end = HADES_MEM_BASE + HADES_MEM_SIZE - 1;
        bus->mem_space.name = pci_mem_name;
 #if 1
-       if (request_resource(&iomem_resource, &bus->mem_space) != 0)
-       {
-               release_resource(&io_space);
-               release_resource(&config_space);
-               kfree(bus);
-               return NULL;
-       }
+       if (unlikely(request_resource(&iomem_resource, &bus->mem_space) != 0))
+               goto release_io_space;
 #endif
        bus->io_space.start = pci_io_base_virt;
        bus->io_space.end = pci_io_base_virt + HADES_VIRT_IO_SIZE - 1;
        bus->io_space.name = pci_io_name;
 #if 1
-       if (request_resource(&ioport_resource, &bus->io_space) != 0)
-       {
-               release_resource(&bus->mem_space);
-               release_resource(&io_space);
-               release_resource(&config_space);
-               kfree(bus);
-               return NULL;
-       }
+       if (unlikely(request_resource(&ioport_resource, &bus->io_space) != 0))
+               goto release_bus_mem_space;
 #endif
        /*
         * Set hardware dependent functions.
@@ -438,5 +420,21 @@ struct pci_bus_info * __init init_hades_pci(void)
        tt_mfp.active_edge &= ~0x27;
 
        return bus;
+
+release_bus_mem_space:
+       release_resource(&bus->mem_space);
+release_io_space:
+       release_resource(&io_space);
+release_config_space:
+       release_resource(&config_space);
+free_bus:
+       kfree(bus);
+iounmap_base_virt:
+       iounmap((void *)pci_io_base_virt);
+
+       for (i = 0; i < N_SLOTS; i++)
+               iounmap((void *)pci_conf_base_virt[i]);
+
+       return NULL;
 }
 #endif
index ab3fd5202b2477c5624e4a23fbac11f78e7063bb..d1bd029a34ac612acfe5b04936a8dab1821ce2de 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/wait.h>
+#include <linux/module.h>
 
 #include <asm/atari_stdma.h>
 #include <asm/atariints.h>
@@ -91,6 +92,7 @@ void stdma_lock(irq_handler_t handler, void *data)
        stdma_isr_data = data;
        local_irq_restore(flags);
 }
+EXPORT_SYMBOL(stdma_lock);
 
 
 /*
@@ -117,6 +119,7 @@ void stdma_release(void)
 
        local_irq_restore(flags);
 }
+EXPORT_SYMBOL(stdma_release);
 
 
 /*
@@ -134,6 +137,7 @@ int stdma_others_waiting(void)
 {
        return waitqueue_active(&stdma_wait);
 }
+EXPORT_SYMBOL(stdma_others_waiting);
 
 
 /*
@@ -155,6 +159,7 @@ int stdma_islocked(void)
 {
        return stdma_locked;
 }
+EXPORT_SYMBOL(stdma_islocked);
 
 
 /*
index bf4588cbe3711bca7125a1d1167541ec76fe0531..8dda6515887affd45d33a55981329f5125eda9ba 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/bootmem.h>
 #include <linux/mount.h>
 #include <linux/blkdev.h>
+#include <linux/module.h>
 
 #include <asm/setup.h>
 #include <asm/machdep.h>
@@ -208,6 +209,7 @@ void *atari_stram_alloc(long size, const char *owner)
        }
        return( addr );
 }
+EXPORT_SYMBOL(atari_stram_alloc);
 
 void atari_stram_free( void *addr )
 
@@ -237,6 +239,7 @@ void atari_stram_free( void *addr )
        printk( KERN_ERR "atari_stram_free: cannot free block at %p "
                        "(called from %p)\n", addr, __builtin_return_address(0) );
 }
+EXPORT_SYMBOL(atari_stram_free);
 
 \f
 /* ------------------------------------------------------------------------ */
index 15b80abfe94a53e2462926f26d2417bed1113ceb..ff9dffa5b860c35f4458d6fc6cb8e82b922940fd 100644 (file)
@@ -678,7 +678,6 @@ CONFIG_LOGO_MAC_CLUT224=y
 #
 CONFIG_MAC_SCC=y
 CONFIG_MAC_HID=y
-CONFIG_MAC_ADBKEYCODES=y
 CONFIG_SERIAL_CONSOLE=y
 
 #
index 288b9c67c9bf4a19f024ff892ce3f7a24d91ac63..96d4244c82fd269c8b52506c4c097a7856631dcc 100644 (file)
@@ -2,4 +2,4 @@
 # Makefile for Linux arch/m68k/hp300 source directory
 #
 
-obj-y          := ksyms.o config.o time.o reboot.o
+obj-y          := config.o time.o reboot.o
diff --git a/arch/m68k/hp300/ksyms.c b/arch/m68k/hp300/ksyms.c
deleted file mode 100644 (file)
index 8202830..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-/*
- *  linux/arch/m68k/hp300/ksyms.c
- *
- *  Copyright (C) 1998 Philip Blundell <philb@gnu.org>
- *
- *  This file contains the HP300-specific kernel symbols.  None yet. :-)
- */
-
-#include <linux/module.h>
index 918f5dbeaef6c32dcea4aba039298a93ca99b2be..6dfa3b3c0e2a737d0b128e33cc1e6965e1aa8d00 100644 (file)
@@ -742,7 +742,7 @@ sys_call_table:
        .long sys_epoll_pwait           /* 315 */
        .long sys_utimensat
        .long sys_signalfd
-       .long sys_timerfd
+       .long sys_ni_syscall
        .long sys_eventfd
        .long sys_fallocate             /* 320 */
 
index 995a09d912f57abe14dd0367096913c2177c9a58..1d265ba365ad37fd58a6617cdd90986395606048 100644 (file)
@@ -3,4 +3,4 @@
 #
 
 obj-y          := config.o bootparse.o macints.o iop.o via.o oss.o psc.o \
-                       baboon.o macboing.o debug.o misc.o mac_ksyms.o
+                       baboon.o macboing.o debug.o misc.o
index 01b468b9392ec68cb1aade95d598adb06a51cdc5..735a49b4b9366b0345db8cc954a824e4b0ff5cb1 100644 (file)
@@ -58,8 +58,6 @@ extern struct mem_info m68k_memory[NUM_MEMINFO];
 
 extern struct mem_info m68k_ramdisk;
 
-extern char m68k_command_line[CL_SIZE];
-
 void *mac_env;                                 /* Loaded by the boot asm */
 
 /* The phys. video addr. - might be bogus on some machines */
diff --git a/arch/m68k/mac/mac_ksyms.c b/arch/m68k/mac/mac_ksyms.c
deleted file mode 100644 (file)
index 6e37ceb..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#include <linux/module.h>
-#include <asm/ptrace.h>
-#include <asm/traps.h>
-
-/* Says whether we're using A/UX interrupts or not */
-extern int via_alt_mapping;
-
-EXPORT_SYMBOL(via_alt_mapping);
index 8df270e950fabead2b0f0a2f2cf247d6fb02c41b..fa485df4160e7f7298359642de3cebde58196ab0 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/ide.h>
+#include <linux/module.h>
 
 #include <asm/bootinfo.h>
 #include <asm/macintosh.h>
@@ -41,7 +42,9 @@ volatile __u8 *via1, *via2;
 /* See note in mac_via.h about how this is possibly not useful */
 volatile long *via_memory_bogon=(long *)&via_memory_bogon;
 #endif
-int rbv_present, via_alt_mapping;
+int rbv_present;
+int via_alt_mapping;
+EXPORT_SYMBOL(via_alt_mapping);
 __u8 rbv_clear;
 
 /*
index 950e82f216408d889a493ccd275fb356624acbfe..edb3f6e6ee6acbfe6d3a4912595553a3c212d570 100644 (file)
@@ -2,4 +2,4 @@
 # Makefile for Linux arch/m68k/mvme16x source directory
 #
 
-obj-y          := config.o rtc.o mvme16x_ksyms.o
+obj-y          := config.o rtc.o
index daa7851614013c385b7c9f4660120f716849d39b..24cbc3030454aed4a76e847cfed91f415d8fc33b 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/genhd.h>
 #include <linux/rtc.h>
 #include <linux/interrupt.h>
+#include <linux/module.h>
 
 #include <asm/bootinfo.h>
 #include <asm/system.h>
@@ -58,6 +59,7 @@ static irq_handler_t tick_handler;
 
 
 unsigned short mvme16x_config;
+EXPORT_SYMBOL(mvme16x_config);
 
 
 int mvme16x_parse_bootinfo(const struct bi_record *bi)
diff --git a/arch/m68k/mvme16x/mvme16x_ksyms.c b/arch/m68k/mvme16x/mvme16x_ksyms.c
deleted file mode 100644 (file)
index 4a8a363..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#include <linux/module.h>
-#include <linux/types.h>
-#include <asm/ptrace.h>
-#include <asm/mvme16xhw.h>
-
-EXPORT_SYMBOL(mvme16x_config);
index f4b582cbb5678a541e9a972ef8f31d27399d69a9..6abbbb8aac5ebc733f7e4eb8cc8df3df6ef3959c 100644 (file)
@@ -53,6 +53,10 @@ config GENERIC_CALIBRATE_DELAY
        bool
        default y
 
+config GENERIC_TIME
+       bool
+       default y
+
 config TIME_LOW_RES
        bool
        default y
@@ -707,8 +711,6 @@ source "drivers/Kconfig"
 
 source "fs/Kconfig"
 
-source "kernel/Kconfig.instrumentation"
-
 source "arch/m68knommu/Kconfig.debug"
 
 source "security/Kconfig"
index 9ff47bd09aee0027362a2dbcd75194add548fab9..ed6d9a83bfdb79399547124794efd2bdef17138d 100644 (file)
@@ -21,13 +21,6 @@ config BOOTPARAM_STRING
        default 'console=ttyS0,19200'
        depends on BOOTPARAM
 
-config DUMPTOFLASH
-       bool "Panic/Dump to FLASH"
-       depends on COLDFIRE
-       help
-         Dump any panic of trap output into a flash memory segment
-         for later analysis.
-
 config NO_KERNEL_MSG
        bool "Suppress Kernel BUG Messages"
        help
index 30aa2553693d116702684f904a262016b1472ca4..e0b5f62e395caff7ee475a660482e2cdd8b24883 100644 (file)
@@ -61,17 +61,17 @@ MODEL := $(model-y)
 # for the selected cpu. ONLY need to define this for the non-base member
 # of the family.
 #
-cpuclass-$(CONFIG_M5206)       := 5307
-cpuclass-$(CONFIG_M5206e)      := 5307
-cpuclass-$(CONFIG_M520x)       := 5307
-cpuclass-$(CONFIG_M523x)       := 5307
-cpuclass-$(CONFIG_M5249)       := 5307
-cpuclass-$(CONFIG_M527x)       := 5307
-cpuclass-$(CONFIG_M5272)       := 5307
-cpuclass-$(CONFIG_M528x)       := 5307
-cpuclass-$(CONFIG_M5307)       := 5307
-cpuclass-$(CONFIG_M532x)       := 5307
-cpuclass-$(CONFIG_M5407)       := 5307
+cpuclass-$(CONFIG_M5206)       := coldfire
+cpuclass-$(CONFIG_M5206e)      := coldfire
+cpuclass-$(CONFIG_M520x)       := coldfire
+cpuclass-$(CONFIG_M523x)       := coldfire
+cpuclass-$(CONFIG_M5249)       := coldfire
+cpuclass-$(CONFIG_M527x)       := coldfire
+cpuclass-$(CONFIG_M5272)       := coldfire
+cpuclass-$(CONFIG_M528x)       := coldfire
+cpuclass-$(CONFIG_M5307)       := coldfire
+cpuclass-$(CONFIG_M532x)       := coldfire
+cpuclass-$(CONFIG_M5407)       := coldfire
 cpuclass-$(CONFIG_M68328)      := 68328
 cpuclass-$(CONFIG_M68EZ328)    := 68328
 cpuclass-$(CONFIG_M68VZ328)    := 68328
index 5a0ecaaee3b08132b89c5e9a67b43510e959dae9..648113075f9722cf0be3c657c7fc28554d533028 100644 (file)
@@ -597,7 +597,6 @@ CONFIG_MSDOS_PARTITION=y
 # CONFIG_FULLDEBUG is not set
 # CONFIG_HIGHPROFILE is not set
 # CONFIG_BOOTPARAM is not set
-# CONFIG_DUMPTOFLASH is not set
 # CONFIG_NO_KERNEL_MSG is not set
 # CONFIG_BDM_DISABLE is not set
 
index f795062aba1e31760b659ce0c3d065078eceeaf5..53fad149028277b8d68c554969c679faed524734 100644 (file)
@@ -24,14 +24,6 @@ extern int dump_fpu(struct pt_regs *, elf_fpregset_t *);
 EXPORT_SYMBOL(__ioremap);
 EXPORT_SYMBOL(iounmap);
 EXPORT_SYMBOL(dump_fpu);
-EXPORT_SYMBOL(strnlen);
-EXPORT_SYMBOL(strrchr);
-EXPORT_SYMBOL(strstr);
-EXPORT_SYMBOL(strchr);
-EXPORT_SYMBOL(strcat);
-EXPORT_SYMBOL(strlen);
-EXPORT_SYMBOL(strcmp);
-EXPORT_SYMBOL(strncmp);
 
 EXPORT_SYMBOL(ip_fast_csum);
 
@@ -46,9 +38,6 @@ EXPORT_SYMBOL(csum_partial_copy_nocheck);
    it's OK to leave it out of version control.  */
 EXPORT_SYMBOL(memcpy);
 EXPORT_SYMBOL(memset);
-EXPORT_SYMBOL(memcmp);
-EXPORT_SYMBOL(memscan);
-EXPORT_SYMBOL(memmove);
 
 EXPORT_SYMBOL(__down_failed);
 EXPORT_SYMBOL(__down_failed_interruptible);
index 332345d7675d878f85ab53714927e68140807368..81507c53d4a9b7cfce58de6bc0f4ee8f07bbccae 100644 (file)
@@ -64,9 +64,6 @@ void (*mach_power_off)(void);
 #ifdef CONFIG_M68VZ328
        #define CPU "MC68VZ328"
 #endif
-#ifdef CONFIG_M68332
-       #define CPU "MC68332"
-#endif
 #ifdef CONFIG_M68360
        #define CPU "MC68360"
 #endif
index 9620093514bcb51533ce958bebd9156e45fd7318..1b02b88200680c8ebbec377d4c67b56622bc1595 100644 (file)
@@ -336,7 +336,7 @@ ENTRY(sys_call_table)
        .long sys_epoll_pwait           /* 315 */
        .long sys_utimensat
        .long sys_signalfd
-       .long sys_timerfd
+       .long sys_ni_syscall
        .long sys_eventfd
        .long sys_fallocate             /* 320 */
 
index 77e5375a2dd505ecc90e0dee224ed953e043ab56..89cdbcaeb45f00e5a1b7e44a78d4e9389853b4dc 100644 (file)
@@ -22,7 +22,6 @@
 #include <linux/timex.h>
 
 #include <asm/machdep.h>
-#include <asm/io.h>
 #include <asm/irq_regs.h>
 
 #define        TICK_SIZE (tick_nsec / 1000)
@@ -66,29 +65,6 @@ irqreturn_t arch_timer_interrupt(int irq, void *dummy)
          else
            last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
        }
-#ifdef CONFIG_HEARTBEAT
-       /* use power LED as a heartbeat instead -- much more useful
-          for debugging -- based on the version for PReP by Cort */
-       /* acts like an actual heart beat -- ie thump-thump-pause... */
-       if (mach_heartbeat) {
-           static unsigned cnt = 0, period = 0, dist = 0;
-
-           if (cnt == 0 || cnt == dist)
-               mach_heartbeat( 1 );
-           else if (cnt == 7 || cnt == dist+7)
-               mach_heartbeat( 0 );
-
-           if (++cnt > period) {
-               cnt = 0;
-               /* The hyperbolic function below modifies the heartbeat period
-                * length in dependency of the current (5min) load. It goes
-                * through the points f(0)=126, f(1)=86, f(5)=51,
-                * f(inf)->30. */
-               period = ((672<<FSHIFT)/(5*avenrun[0]+(7<<FSHIFT))) + 30;
-               dist = period / 4;
-           }
-       }
-#endif /* CONFIG_HEARTBEAT */
 
        write_sequnlock(&xtime_lock);
        return(IRQ_HANDLED);
@@ -112,60 +88,3 @@ void time_init(void)
        hw_timer_init();
 }
 
-/*
- * This version of gettimeofday has near microsecond resolution.
- */
-void do_gettimeofday(struct timeval *tv)
-{
-       unsigned long flags;
-       unsigned long seq;
-       unsigned long usec, sec;
-
-       do {
-               seq = read_seqbegin_irqsave(&xtime_lock, flags);
-               usec = hw_timer_offset();
-               sec = xtime.tv_sec;
-               usec += (xtime.tv_nsec / 1000);
-       } while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
-
-       while (usec >= 1000000) {
-               usec -= 1000000;
-               sec++;
-       }
-
-       tv->tv_sec = sec;
-       tv->tv_usec = usec;
-}
-
-EXPORT_SYMBOL(do_gettimeofday);
-
-int do_settimeofday(struct timespec *tv)
-{
-       time_t wtm_sec, sec = tv->tv_sec;
-       long wtm_nsec, nsec = tv->tv_nsec;
-
-       if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC)
-               return -EINVAL;
-
-       write_seqlock_irq(&xtime_lock);
-       /*
-        * This is revolting. We need to set the xtime.tv_usec
-        * correctly. However, the value in this location is
-        * is value at the last tick.
-        * Discover what correction gettimeofday
-        * would have done, and then undo it!
-        */
-       nsec -= (hw_timer_offset() * 1000);
-
-       wtm_sec  = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec);
-       wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec);
-
-       set_normalized_timespec(&xtime, sec, nsec);
-       set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
-
-       ntp_clear();
-       write_sequnlock_irq(&xtime_lock);
-       clock_was_set();
-       return 0;
-}
-EXPORT_SYMBOL(do_settimeofday);
index b3c4dd4cc13546146be2726de69a53f747ba83f2..53a5920c2b71ad68185ae2fe5ef08c6647c5af86 100644 (file)
 #include <linux/param.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
-#include <asm/dma.h>
+#include <linux/io.h>
 #include <asm/machdep.h>
 #include <asm/coldfire.h>
-#include <asm/mcftimer.h>
 #include <asm/mcfsim.h>
-#include <asm/mcfdma.h>
+#include <asm/mcfuart.h>
 
 /***************************************************************************/
 
@@ -26,15 +25,51 @@ void coldfire_reset(void);
 
 /***************************************************************************/
 
-/*
- *     DMA channel base address table.
- */
-unsigned int   dma_base_addr[MAX_M68K_DMA_CHANNELS] = {
-        MCF_MBAR + MCFDMA_BASE0,
-        MCF_MBAR + MCFDMA_BASE1,
+static struct mcf_platform_uart m5206_uart_platform[] = {
+       {
+               .mapbase        = MCF_MBAR + MCFUART_BASE1,
+               .irq            = 73,
+       },
+       {
+               .mapbase        = MCF_MBAR + MCFUART_BASE2,
+               .irq            = 74,
+       },
+       { },
+};
+
+static struct platform_device m5206_uart = {
+       .name                   = "mcfuart",
+       .id                     = 0,
+       .dev.platform_data      = m5206_uart_platform,
+};
+
+static struct platform_device *m5206_devices[] __initdata = {
+       &m5206_uart,
 };
 
-unsigned int dma_device_address[MAX_M68K_DMA_CHANNELS];
+/***************************************************************************/
+
+static void __init m5206_uart_init_line(int line, int irq)
+{
+       if (line == 0) {
+               writel(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI1, MCF_MBAR + MCFSIM_UART1ICR);
+               writeb(irq, MCFUART_BASE1 + MCFUART_UIVR);
+               mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_UART1);
+       } else if (line == 1) {
+               writel(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI2, MCF_MBAR + MCFSIM_UART2ICR);
+               writeb(irq, MCFUART_BASE2 + MCFUART_UIVR);
+               mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_UART2);
+       }
+}
+
+static void __init m5206_uarts_init(void)
+{
+       const int nrlines = ARRAY_SIZE(m5206_uart_platform);
+       int line;
+
+       for (line = 0; (line < nrlines); line++)
+               m5206_uart_init_line(line, m5206_uart_platform[line].irq);
+}
 
 /***************************************************************************/
 
@@ -74,24 +109,21 @@ void mcf_settimericr(unsigned int timer, unsigned int level)
 
 /***************************************************************************/
 
-int mcf_timerirqpending(int timer)
+void __init config_BSP(char *commandp, int size)
 {
-       unsigned int imr = 0;
-
-       switch (timer) {
-       case 1:  imr = MCFSIM_IMR_TIMER1; break;
-       case 2:  imr = MCFSIM_IMR_TIMER2; break;
-       default: break;
-       }
-       return (mcf_getipr() & imr);
+       mcf_setimr(MCFSIM_IMR_MASKALL);
+       mach_reset = coldfire_reset;
 }
 
 /***************************************************************************/
 
-void config_BSP(char *commandp, int size)
+static int __init init_BSP(void)
 {
-       mcf_setimr(MCFSIM_IMR_MASKALL);
-       mach_reset = coldfire_reset;
+       m5206_uarts_init();
+       platform_add_devices(m5206_devices, ARRAY_SIZE(m5206_devices));
+       return 0;
 }
 
+arch_initcall(init_BSP);
+
 /***************************************************************************/
index f84a4aea8cb68669f62e1119ced59f7b6be27130..a6692e958f6b93265380bfe7631b57d2fae5fe01 100644 (file)
@@ -10,8 +10,9 @@
 
 #include <linux/kernel.h>
 #include <linux/param.h>
+#include <linux/init.h>
 #include <linux/interrupt.h>
-#include <asm/dma.h>
+#include <linux/io.h>
 #include <asm/machdep.h>
 #include <asm/coldfire.h>
 #include <asm/mcfsim.h>
@@ -23,15 +24,51 @@ void coldfire_reset(void);
 
 /***************************************************************************/
 
-/*
- *     DMA channel base address table.
- */
-unsigned int   dma_base_addr[MAX_M68K_DMA_CHANNELS] = {
-        MCF_MBAR + MCFDMA_BASE0,
-        MCF_MBAR + MCFDMA_BASE1,
+static struct mcf_platform_uart m5206e_uart_platform[] = {
+       {
+               .mapbase        = MCF_MBAR + MCFUART_BASE1,
+               .irq            = 73,
+       },
+       {
+               .mapbase        = MCF_MBAR + MCFUART_BASE2,
+               .irq            = 74,
+       },
+       { },
+};
+
+static struct platform_device m5206e_uart = {
+       .name                   = "mcfuart",
+       .id                     = 0,
+       .dev.platform_data      = m5206e_uart_platform,
 };
 
-unsigned int dma_device_address[MAX_M68K_DMA_CHANNELS];
+static struct platform_device *m5206e_devices[] __initdata = {
+       &m5206e_uart,
+};
+
+/***************************************************************************/
+
+static void __init m5206_uart_init_line(int line, int irq)
+{
+       if (line == 0) {
+               writel(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI1, MCF_MBAR + MCFSIM_UART1ICR);
+               writeb(irq, MCFUART_BASE1 + MCFUART_UIVR);
+               mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_UART1);
+       } else if (line == 1) {
+               writel(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI2, MCF_MBAR + MCFSIM_UART2ICR);
+               writeb(irq, MCFUART_BASE2 + MCFUART_UIVR);
+               mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_UART2);
+       }
+}
+
+static void __init m5206e_uarts_init(void)
+{
+       const int nrlines = ARRAY_SIZE(m5206e_uart_platform);
+       int line;
+
+       for (line = 0; (line < nrlines); line++)
+               m5206e_uart_init_line(line, m5206e_uart_platform[line].irq);
+}
 
 /***************************************************************************/
 
@@ -71,21 +108,7 @@ void mcf_settimericr(unsigned int timer, unsigned int level)
 
 /***************************************************************************/
 
-int mcf_timerirqpending(int timer)
-{
-       unsigned int imr = 0;
-
-       switch (timer) {
-       case 1:  imr = MCFSIM_IMR_TIMER1; break;
-       case 2:  imr = MCFSIM_IMR_TIMER2; break;
-       default: break;
-       }
-       return (mcf_getipr() & imr);
-}
-
-/***************************************************************************/
-
-void config_BSP(char *commandp, int size)
+void __init config_BSP(char *commandp, int size)
 {
        mcf_setimr(MCFSIM_IMR_MASKALL);
 
@@ -99,3 +122,14 @@ void config_BSP(char *commandp, int size)
 }
 
 /***************************************************************************/
+
+static int __init init_BSP(void)
+{
+       m5206e_uarts_init();
+       platform_add_devices(m5206e_devices, ARRAY_SIZE(m5206e_devices));
+       return 0;
+}
+
+arch_initcall(init_BSP);
+
+/***************************************************************************/
index 6edbd41261cc0253fd48f19646614f632543d335..06d887cdcbfbcc2c8aaf441a5f2e5a1e8c5bcd1f 100644 (file)
@@ -5,7 +5,7 @@
  *
  *  Copyright (C) 2005,      Freescale (www.freescale.com)
  *  Copyright (C) 2005,      Intec Automation (mike@steroidmicros.com)
- *  Copyright (C) 1999-2003, Greg Ungerer (gerg@snapgear.com)
+ *  Copyright (C) 1999-2007, Greg Ungerer (gerg@snapgear.com)
  *  Copyright (C) 2001-2003, SnapGear Inc. (www.snapgear.com)
  */
 
 
 #include <linux/kernel.h>
 #include <linux/param.h>
+#include <linux/init.h>
 #include <linux/interrupt.h>
+#include <linux/io.h>
 #include <asm/machdep.h>
-#include <asm/dma.h>
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+#include <asm/mcfuart.h>
 
 /***************************************************************************/
 
-/*
- *     DMA channel base address table.
- */
-unsigned int dma_base_addr[MAX_M68K_DMA_CHANNELS];
-unsigned int dma_device_address[MAX_M68K_DMA_CHANNELS];
+void coldfire_reset(void);
 
 /***************************************************************************/
 
-void coldfire_reset(void);
+static struct mcf_platform_uart m520x_uart_platform[] = {
+       {
+               .mapbase        = MCF_MBAR + MCFUART_BASE1,
+               .irq            = MCFINT_VECBASE + MCFINT_UART0,
+       },
+       {
+               .mapbase        = MCF_MBAR + MCFUART_BASE2,
+               .irq            = MCFINT_VECBASE + MCFINT_UART1,
+       },
+       {
+               .mapbase        = MCF_MBAR + MCFUART_BASE3,
+               .irq            = MCFINT_VECBASE + MCFINT_UART2,
+       },
+       { },
+};
+
+static struct platform_device m520x_uart = {
+       .name                   = "mcfuart",
+       .id                     = 0,
+       .dev.platform_data      = m520x_uart_platform,
+};
+
+static struct platform_device *m520x_devices[] __initdata = {
+       &m520x_uart,
+};
+
+/***************************************************************************/
+
+#define        INTC0   (MCF_MBAR + MCFICM_INTC0)
+
+static void __init m520x_uart_init_line(int line, int irq)
+{
+       u32 imr;
+       u16 par;
+       u8 par2;
+
+       writeb(0x03, INTC0 + MCFINTC_ICR0 + MCFINT_UART0 + line);
+
+       imr = readl(INTC0 + MCFINTC_IMRL);
+       imr &= ~((1 << (irq - MCFINT_VECBASE)) | 1);
+       writel(imr, INTC0 + MCFINTC_IMRL);
+
+       switch (line) {
+       case 0:
+               par = readw(MCF_IPSBAR + MCF_GPIO_PAR_UART);
+               par |= MCF_GPIO_PAR_UART_PAR_UTXD0 |
+                      MCF_GPIO_PAR_UART_PAR_URXD0;
+               writew(par, MCF_IPSBAR + MCF_GPIO_PAR_UART);
+               break;
+       case 1:
+               par = readw(MCF_IPSBAR + MCF_GPIO_PAR_UART);
+               par |= MCF_GPIO_PAR_UART_PAR_UTXD1 |
+                      MCF_GPIO_PAR_UART_PAR_URXD1;
+               writew(par, MCF_IPSBAR + MCF_GPIO_PAR_UART);
+               break;
+       case 2:
+               par2 = readb(MCF_IPSBAR + MCF_GPIO_PAR_FECI2C);
+               par2 &= ~0x0F;
+               par2 |= MCF_GPIO_PAR_FECI2C_PAR_SCL_UTXD2 |
+                       MCF_GPIO_PAR_FECI2C_PAR_SDA_URXD2;
+               writeb(par2, MCF_IPSBAR + MCF_GPIO_PAR_FECI2C);
+               break;
+       }
+}
+
+static void __init m520x_uarts_init(void)
+{
+       const int nrlines = ARRAY_SIZE(m520x_uart_platform);
+       int line;
+
+       for (line = 0; (line < nrlines); line++)
+               m520x_uart_init_line(line, m520x_uart_platform[line].irq);
+}
 
 /***************************************************************************/
 
@@ -42,9 +114,20 @@ void mcf_autovector(unsigned int vec)
 
 /***************************************************************************/
 
-void config_BSP(char *commandp, int size)
+void __init config_BSP(char *commandp, int size)
 {
        mach_reset = coldfire_reset;
+       m520x_uarts_init();
 }
 
 /***************************************************************************/
+
+static int __init init_BSP(void)
+{
+       platform_add_devices(m520x_devices, ARRAY_SIZE(m520x_devices));
+       return 0;
+}
+
+arch_initcall(init_BSP);
+
+/***************************************************************************/
index e7f80c8e8636f2234c8322555c6a7ce01e1e68a8..13f02611ea23a8c866755af5b0fe8585e2d60de2 100644 (file)
 #include <linux/param.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
-#include <asm/dma.h>
+#include <linux/io.h>
 #include <asm/machdep.h>
 #include <asm/coldfire.h>
 #include <asm/mcfsim.h>
-#include <asm/mcfdma.h>
+#include <asm/mcfuart.h>
 
 /***************************************************************************/
 
@@ -28,14 +28,58 @@ void coldfire_reset(void);
 
 /***************************************************************************/
 
-/*
- *     DMA channel base address table.
- */
-unsigned int   dma_base_addr[MAX_M68K_DMA_CHANNELS] = {
-        MCF_MBAR + MCFDMA_BASE0,
+static struct mcf_platform_uart m523x_uart_platform[] = {
+       {
+               .mapbase        = MCF_MBAR + MCFUART_BASE1,
+               .irq            = MCFINT_VECBASE + MCFINT_UART0,
+       },
+       {
+               .mapbase        = MCF_MBAR + MCFUART_BASE2,
+               .irq            = MCFINT_VECBASE + MCFINT_UART0 + 1,
+       },
+       {
+               .mapbase        = MCF_MBAR + MCFUART_BASE3,
+               .irq            = MCFINT_VECBASE + MCFINT_UART0 + 2,
+       },
+       { },
+};
+
+static struct platform_device m523x_uart = {
+       .name                   = "mcfuart",
+       .id                     = 0,
+       .dev.platform_data      = m523x_uart_platform,
+};
+
+static struct platform_device *m523x_devices[] __initdata = {
+       &m523x_uart,
 };
 
-unsigned int dma_device_address[MAX_M68K_DMA_CHANNELS];
+/***************************************************************************/
+
+#define        INTC0   (MCF_MBAR + MCFICM_INTC0)
+
+static void __init m523x_uart_init_line(int line, int irq)
+{
+       u32 imr;
+
+       if ((line < 0) || (line > 2))
+               return;
+
+       writeb(0x30+line, (INTC0 + MCFINTC_ICR0 + MCFINT_UART0 + line));
+
+       imr = readl(INTC0 + MCFINTC_IMRL);
+       imr &= ~((1 << (irq - MCFINT_VECBASE)) | 1);
+       writel(imr, INTC0 + MCFINTC_IMRL);
+}
+
+static void __init m523x_uarts_init(void)
+{
+       const int nrlines = ARRAY_SIZE(m523x_uart_platform);
+       int line;
+
+       for (line = 0; (line < nrlines); line++)
+               m523x_uart_init_line(line, m523x_uart_platform[line].irq);
+}
 
 /***************************************************************************/
 
@@ -49,15 +93,26 @@ void mcf_disableall(void)
 
 void mcf_autovector(unsigned int vec)
 {
-       /* Everything is auto-vectored on the 5272 */
+       /* Everything is auto-vectored on the 523x */
 }
 
 /***************************************************************************/
 
-void config_BSP(char *commandp, int size)
+void __init config_BSP(char *commandp, int size)
 {
        mcf_disableall();
        mach_reset = coldfire_reset;
+       m523x_uarts_init();
 }
 
 /***************************************************************************/
+
+static int __init init_BSP(void)
+{
+       platform_add_devices(m523x_devices, ARRAY_SIZE(m523x_devices));
+       return 0;
+}
+
+arch_initcall(init_BSP);
+
+/***************************************************************************/
index d4d39435cb15ce54bc33950027fd0f1072405aac..d299f7b8768a9981640733e60b51b5bb106a3bfb 100644 (file)
 #include <linux/param.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
-#include <asm/dma.h>
+#include <linux/io.h>
 #include <asm/machdep.h>
 #include <asm/coldfire.h>
 #include <asm/mcfsim.h>
-#include <asm/mcfdma.h>
+#include <asm/mcfuart.h>
 
 /***************************************************************************/
 
@@ -24,17 +24,51 @@ void coldfire_reset(void);
 
 /***************************************************************************/
 
-/*
- *     DMA channel base address table.
- */
-unsigned int   dma_base_addr[MAX_M68K_DMA_CHANNELS] = {
-        MCF_MBAR + MCFDMA_BASE0,
-        MCF_MBAR + MCFDMA_BASE1,
-        MCF_MBAR + MCFDMA_BASE2,
-        MCF_MBAR + MCFDMA_BASE3,
+static struct mcf_platform_uart m5249_uart_platform[] = {
+       {
+               .mapbase        = MCF_MBAR + MCFUART_BASE1,
+               .irq            = 73,
+       },
+       {
+               .mapbase        = MCF_MBAR + MCFUART_BASE2,
+               .irq            = 74,
+       }
+};
+
+static struct platform_device m5249_uart = {
+       .name                   = "mcfuart",
+       .id                     = 0,
+       .dev.platform_data      = m5249_uart_platform,
+};
+
+static struct platform_device *m5249_devices[] __initdata = {
+       &m5249_uart,
 };
 
-unsigned int dma_device_address[MAX_M68K_DMA_CHANNELS];
+/***************************************************************************/
+
+static void __init m5249_uart_init_line(int line, int irq)
+{
+       if (line == 0) {
+               writel(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI1, MCF_MBAR + MCFSIM_UART1ICR);
+               writeb(irq, MCFUART_BASE1 + MCFUART_UIVR);
+               mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_UART1);
+       } else if (line == 1) {
+               writel(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI2, MCF_MBAR + MCFSIM_UART2ICR);
+               writeb(irq, MCFUART_BASE2 + MCFUART_UIVR);
+               mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_UART2);
+       }
+}
+
+static void __init m5249_uarts_init(void)
+{
+       const int nrlines = ARRAY_SIZE(m5249_uart_platform);
+       int line;
+
+       for (line = 0; (line < nrlines); line++)
+               m5249_uart_init_line(line, m5249_uart_platform[line].irq);
+}
+
 
 /***************************************************************************/
 
@@ -71,24 +105,21 @@ void mcf_settimericr(unsigned int timer, unsigned int level)
 
 /***************************************************************************/
 
-int mcf_timerirqpending(int timer)
+void __init config_BSP(char *commandp, int size)
 {
-       unsigned int imr = 0;
-
-       switch (timer) {
-       case 1:  imr = MCFSIM_IMR_TIMER1; break;
-       case 2:  imr = MCFSIM_IMR_TIMER2; break;
-       default: break;
-       }
-       return (mcf_getipr() & imr);
+       mcf_setimr(MCFSIM_IMR_MASKALL);
+       mach_reset = coldfire_reset;
 }
 
 /***************************************************************************/
 
-void config_BSP(char *commandp, int size)
+static int __init init_BSP(void)
 {
-       mcf_setimr(MCFSIM_IMR_MASKALL);
-       mach_reset = coldfire_reset;
+       m5249_uarts_init();
+       platform_add_devices(m5249_devices, ARRAY_SIZE(m5249_devices));
+       return 0;
 }
 
+arch_initcall(init_BSP);
+
 /***************************************************************************/
index 634a6375e4a5f3a4f4f4f6e7428e16fe29ccf14d..2aca599a1ca714ae2b70ec3d6d89f2ce74dc631f 100644 (file)
 #include <linux/param.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
-#include <asm/dma.h>
+#include <linux/io.h>
 #include <asm/machdep.h>
 #include <asm/coldfire.h>
 #include <asm/mcfsim.h>
-#include <asm/mcfdma.h>
+#include <asm/mcfuart.h>
 
 /***************************************************************************/
 
@@ -37,14 +37,57 @@ unsigned char ledbank = 0xff;
 
 /***************************************************************************/
 
-/*
- *     DMA channel base address table.
- */
-unsigned int   dma_base_addr[MAX_M68K_DMA_CHANNELS] = {
-        MCF_MBAR + MCFDMA_BASE0,
+static struct mcf_platform_uart m5272_uart_platform[] = {
+       {
+               .mapbase        = MCF_MBAR + MCFUART_BASE1,
+               .irq            = 73,
+       },
+       {
+               .mapbase        = MCF_MBAR + MCFUART_BASE2,
+               .irq            = 74,
+       },
+       { },
 };
 
-unsigned int dma_device_address[MAX_M68K_DMA_CHANNELS];
+static struct platform_device m5272_uart = {
+       .name                   = "mcfuart",
+       .id                     = 0,
+       .dev.platform_data      = m5272_uart_platform,
+};
+
+static struct platform_device *m5272_devices[] __initdata = {
+       &m5272_uart,
+};
+
+/***************************************************************************/
+
+static void __init m5272_uart_init_line(int line, int irq)
+{
+       u32 v;
+
+       if ((line >= 0) && (line < 2)) {
+               v = (line) ? 0x0e000000 : 0xe0000000;
+               writel(v, MCF_MBAR + MCFSIM_ICR2);
+
+               /* Enable the output lines for the serial ports */
+               v = readl(MCF_MBAR + MCFSIM_PBCNT);
+               v = (v & ~0x000000ff) | 0x00000055;
+               writel(v, MCF_MBAR + MCFSIM_PBCNT);
+
+               v = readl(MCF_MBAR + MCFSIM_PDCNT);
+               v = (v & ~0x000003fc) | 0x000002a8;
+               writel(v, MCF_MBAR + MCFSIM_PDCNT);
+       }
+}
+
+static void __init m5272_uarts_init(void)
+{
+       const int nrlines = ARRAY_SIZE(m5272_uart_platform);
+       int line;
+
+       for (line = 0; (line < nrlines); line++)
+               m5272_uart_init_line(line, m5272_uart_platform[line].irq);
+}
 
 /***************************************************************************/
 
@@ -80,20 +123,7 @@ void mcf_settimericr(int timer, int level)
 
 /***************************************************************************/
 
-int mcf_timerirqpending(int timer)
-{
-       volatile unsigned long *icrp;
-
-       if ((timer >= 1 ) && (timer <= 4)) {
-               icrp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_ICR1);
-               return (*icrp & (0x8 << ((4 - timer) * 4)));
-       }
-       return 0;
-}
-
-/***************************************************************************/
-
-void config_BSP(char *commandp, int size)
+void __init config_BSP(char *commandp, int size)
 {
 #if defined (CONFIG_MOD5272)
        volatile unsigned char  *pivrp;
@@ -125,3 +155,14 @@ void config_BSP(char *commandp, int size)
 }
 
 /***************************************************************************/
+
+static int __init init_BSP(void)
+{
+       m5272_uarts_init();
+       platform_add_devices(m5272_devices, ARRAY_SIZE(m5272_devices));
+       return 0;
+}
+
+arch_initcall(init_BSP);
+
+/***************************************************************************/
index 9cbfbc68ae4f3a083417236191b67c9c983f59c8..73cd1aef4a9020c64133ea3c6b39a30669b2f57d 100644 (file)
 #include <linux/param.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
-#include <asm/dma.h>
+#include <linux/io.h>
 #include <asm/machdep.h>
 #include <asm/coldfire.h>
 #include <asm/mcfsim.h>
-#include <asm/mcfdma.h>
+#include <asm/mcfuart.h>
 
 /***************************************************************************/
 
@@ -28,14 +28,72 @@ void coldfire_reset(void);
 
 /***************************************************************************/
 
-/*
- *     DMA channel base address table.
- */
-unsigned int   dma_base_addr[MAX_M68K_DMA_CHANNELS] = {
-        MCF_MBAR + MCFDMA_BASE0,
+static struct mcf_platform_uart m527x_uart_platform[] = {
+       {
+               .mapbase        = MCF_MBAR + MCFUART_BASE1,
+               .irq            = MCFINT_VECBASE + MCFINT_UART0,
+       },
+       {
+               .mapbase        = MCF_MBAR + MCFUART_BASE2,
+               .irq            = MCFINT_VECBASE + MCFINT_UART1,
+       },
+       {
+               .mapbase        = MCF_MBAR + MCFUART_BASE3,
+               .irq            = MCFINT_VECBASE + MCFINT_UART2,
+       },
+       { },
 };
 
-unsigned int dma_device_address[MAX_M68K_DMA_CHANNELS];
+static struct platform_device m527x_uart = {
+       .name                   = "mcfuart",
+       .id                     = 0,
+       .dev.platform_data      = m527x_uart_platform,
+};
+
+static struct platform_device *m527x_devices[] __initdata = {
+       &m527x_uart,
+};
+
+/***************************************************************************/
+
+#define        INTC0   (MCF_MBAR + MCFICM_INTC0)
+
+static void __init m527x_uart_init_line(int line, int irq)
+{
+       u16 sepmask;
+       u32 imr;
+
+       if ((line < 0) || (line > 2))
+               return;
+
+       /* level 6, line based priority */
+       writeb(0x30+line, INTC0 + MCFINTC_ICR0 + MCFINT_UART0 + line);
+
+       imr = readl(INTC0 + MCFINTC_IMRL);
+       imr &= ~((1 << (irq - MCFINT_VECBASE)) | 1);
+       writel(imr, INTC0 + MCFINTC_IMRL);
+
+       /*
+        * External Pin Mask Setting & Enable External Pin for Interface
+        */
+       sepmask = readw(MCF_IPSBAR + MCF_GPIO_PAR_UART);
+       if (line == 0)
+               sepmask |= UART0_ENABLE_MASK;
+       else if (line == 1)
+               sepmask |= UART1_ENABLE_MASK;
+       else if (line == 2)
+               sepmask |= UART2_ENABLE_MASK;
+       writew(sepmask, MCF_IPSBAR + MCF_GPIO_PAR_UART);
+}
+
+static void __init m527x_uarts_init(void)
+{
+       const int nrlines = ARRAY_SIZE(m527x_uart_platform);
+       int line;
+
+       for (line = 0; (line < nrlines); line++)
+               m527x_uart_init_line(line, m527x_uart_platform[line].irq);
+}
 
 /***************************************************************************/
 
@@ -54,10 +112,21 @@ void mcf_autovector(unsigned int vec)
 
 /***************************************************************************/
 
-void config_BSP(char *commandp, int size)
+void __init config_BSP(char *commandp, int size)
 {
        mcf_disableall();
        mach_reset = coldfire_reset;
 }
 
 /***************************************************************************/
+
+static int __init init_BSP(void)
+{
+       m527x_uarts_init();
+       platform_add_devices(m527x_devices, ARRAY_SIZE(m527x_devices));
+       return 0;
+}
+
+arch_initcall(init_BSP);
+
+/***************************************************************************/
index acbd43486d97a457a3b0ce5c68123830274dc9d2..036e1b73d94400b8619db75d71e271a5ce2592e3 100644 (file)
 #include <linux/param.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
-#include <asm/dma.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/flash.h>
+#include <linux/io.h>
 #include <asm/machdep.h>
 #include <asm/coldfire.h>
 #include <asm/mcfsim.h>
-#include <asm/mcfdma.h>
+#include <asm/mcfuart.h>
+#include <asm/mcfqspi.h>
 
 /***************************************************************************/
 
@@ -28,14 +32,67 @@ void coldfire_reset(void);
 
 /***************************************************************************/
 
-/*
- *     DMA channel base address table.
- */
-unsigned int   dma_base_addr[MAX_M68K_DMA_CHANNELS] = {
-        MCF_MBAR + MCFDMA_BASE0,
+static struct mcf_platform_uart m528x_uart_platform[] = {
+       {
+               .mapbase        = MCF_MBAR + MCFUART_BASE1,
+               .irq            = MCFINT_VECBASE + MCFINT_UART0,
+       },
+       {
+               .mapbase        = MCF_MBAR + MCFUART_BASE2,
+               .irq            = MCFINT_VECBASE + MCFINT_UART0 + 1,
+       },
+       {
+               .mapbase        = MCF_MBAR + MCFUART_BASE3,
+               .irq            = MCFINT_VECBASE + MCFINT_UART0 + 2,
+       },
+       { },
 };
 
-unsigned int dma_device_address[MAX_M68K_DMA_CHANNELS];
+static struct platform_device m528x_uart = {
+       .name                   = "mcfuart",
+       .id                     = 0,
+       .dev.platform_data      = m528x_uart_platform,
+};
+
+static struct platform_device *m528x_devices[] __initdata = {
+       &m528x_uart,
+};
+
+/***************************************************************************/
+
+#define        INTC0   (MCF_MBAR + MCFICM_INTC0)
+
+static void __init m528x_uart_init_line(int line, int irq)
+{
+       u8 port;
+       u32 imr;
+
+       if ((line < 0) || (line > 2))
+               return;
+
+       /* level 6, line based priority */
+       writeb(0x30+line, INTC0 + MCFINTC_ICR0 + MCFINT_UART0 + line);
+
+       imr = readl(INTC0 + MCFINTC_IMRL);
+       imr &= ~((1 << (irq - MCFINT_VECBASE)) | 1);
+       writel(imr, INTC0 + MCFINTC_IMRL);
+
+       /* make sure PUAPAR is set for UART0 and UART1 */
+       if (line < 2) {
+               port = readb(MCF_MBAR + MCF5282_GPIO_PUAPAR);
+               port |= (0x03 << (line * 2));
+               writeb(port, MCF_MBAR + MCF5282_GPIO_PUAPAR);
+       }
+}
+
+static void __init m528x_uarts_init(void)
+{
+       const int nrlines = ARRAY_SIZE(m528x_uart_platform);
+       int line;
+
+       for (line = 0; (line < nrlines); line++)
+               m528x_uart_init_line(line, m528x_uart_platform[line].irq);
+}
 
 /***************************************************************************/
 
@@ -54,10 +111,21 @@ void mcf_autovector(unsigned int vec)
 
 /***************************************************************************/
 
-void config_BSP(char *commandp, int size)
+void __init config_BSP(char *commandp, int size)
 {
        mcf_disableall();
        mach_reset = coldfire_reset;
 }
 
 /***************************************************************************/
+
+static int __init init_BSP(void)
+{
+       m528x_uarts_init();
+       platform_add_devices(m528x_devices, ARRAY_SIZE(m528x_devices));
+       return 0;
+}
+
+arch_initcall(init_BSP);
+
+/***************************************************************************/
index 5b600530c8d2400a798c44bbf05ddd8135690bb0..580fd6658d7c204a1f86baff20ef0ba39b08b220 100644 (file)
@@ -16,17 +16,5 @@ ifdef CONFIG_FULLDEBUG
 EXTRA_AFLAGS += -DDEBUGGER_COMPATIBLE_CACHE=1
 endif
 
-obj-$(CONFIG_COLDFIRE) += entry.o vectors.o
-obj-$(CONFIG_M5206)    += timers.o
-obj-$(CONFIG_M5206e)   += timers.o
-obj-$(CONFIG_M520x)    += pit.o
-obj-$(CONFIG_M523x)    += pit.o
-obj-$(CONFIG_M5249)    += timers.o
-obj-$(CONFIG_M527x)     += pit.o
-obj-$(CONFIG_M5272)    += timers.o
-obj-$(CONFIG_M5307)    += config.o timers.o
-obj-$(CONFIG_M532x)    += timers.o
-obj-$(CONFIG_M528x)     += pit.o
-obj-$(CONFIG_M5407)    += timers.o
+obj-y  += config.o
 
-extra-y := head.o
index 6040821e637d40af16f2648438aac1ddd3ca632d..92dc862fa826edb5432875d585a99d266f2d80ca 100644 (file)
 #include <linux/param.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
-#include <asm/dma.h>
+#include <linux/io.h>
 #include <asm/machdep.h>
 #include <asm/coldfire.h>
 #include <asm/mcfsim.h>
-#include <asm/mcfdma.h>
+#include <asm/mcfuart.h>
 #include <asm/mcfwdebug.h>
 
 /***************************************************************************/
@@ -38,17 +38,51 @@ unsigned char ledbank = 0xff;
 
 /***************************************************************************/
 
-/*
- *     DMA channel base address table.
- */
-unsigned int   dma_base_addr[MAX_M68K_DMA_CHANNELS] = {
-        MCF_MBAR + MCFDMA_BASE0,
-        MCF_MBAR + MCFDMA_BASE1,
-        MCF_MBAR + MCFDMA_BASE2,
-        MCF_MBAR + MCFDMA_BASE3,
+static struct mcf_platform_uart m5307_uart_platform[] = {
+       {
+               .mapbase        = MCF_MBAR + MCFUART_BASE1,
+               .irq            = 73,
+       },
+       {
+               .mapbase        = MCF_MBAR + MCFUART_BASE2,
+               .irq            = 74,
+       },
+       { },
+};
+
+static struct platform_device m5307_uart = {
+       .name                   = "mcfuart",
+       .id                     = 0,
+       .dev.platform_data      = m5307_uart_platform,
 };
 
-unsigned int dma_device_address[MAX_M68K_DMA_CHANNELS];
+static struct platform_device *m5307_devices[] __initdata = {
+       &m5307_uart,
+};
+
+/***************************************************************************/
+
+static void __init m5307_uart_init_line(int line, int irq)
+{
+       if (line == 0) {
+               writel(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI1, MCF_MBAR + MCFSIM_UART1ICR);
+               writeb(irq, MCFUART_BASE1 + MCFUART_UIVR);
+               mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_UART1);
+       } else if (line == 1) {
+               writel(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI2, MCF_MBAR + MCFSIM_UART2ICR);
+               writeb(irq, MCFUART_BASE2 + MCFUART_UIVR);
+               mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_UART2);
+       }
+}
+
+static void __init m5307_uarts_init(void)
+{
+       const int nrlines = ARRAY_SIZE(m5307_uart_platform);
+       int line;
+
+       for (line = 0; (line < nrlines); line++)
+               m5307_uart_init_line(line, m5307_uart_platform[line].irq);
+}
 
 /***************************************************************************/
 
@@ -85,21 +119,7 @@ void mcf_settimericr(unsigned int timer, unsigned int level)
 
 /***************************************************************************/
 
-int mcf_timerirqpending(int timer)
-{
-       unsigned int imr = 0;
-
-       switch (timer) {
-       case 1:  imr = MCFSIM_IMR_TIMER1; break;
-       case 2:  imr = MCFSIM_IMR_TIMER2; break;
-       default: break;
-       }
-       return (mcf_getipr() & imr);
-}
-
-/***************************************************************************/
-
-void config_BSP(char *commandp, int size)
+void __init config_BSP(char *commandp, int size)
 {
        mcf_setimr(MCFSIM_IMR_MASKALL);
 
@@ -117,7 +137,7 @@ void config_BSP(char *commandp, int size)
 
        mach_reset = coldfire_reset;
 
-#ifdef MCF_BDM_DISABLE
+#ifdef CONFIG_BDM_DISABLE
        /*
         * Disable the BDM clocking.  This also turns off most of the rest of
         * the BDM device.  This is good for EMC reasons. This option is not
@@ -128,3 +148,14 @@ void config_BSP(char *commandp, int size)
 }
 
 /***************************************************************************/
+
+static int __init init_BSP(void)
+{
+       m5307_uarts_init();
+       platform_add_devices(m5307_devices, ARRAY_SIZE(m5307_devices));
+       return 0;
+}
+
+arch_initcall(init_BSP);
+
+/***************************************************************************/
index f77328b7b6db0439dcf63d2877bfef40e737ac76..4f44b632045b4b8230177bbffc6d864318ba01d0 100644 (file)
 #include <linux/param.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
-#include <asm/dma.h>
+#include <linux/io.h>
 #include <asm/machdep.h>
 #include <asm/coldfire.h>
 #include <asm/mcfsim.h>
+#include <asm/mcfuart.h>
 #include <asm/mcfdma.h>
 #include <asm/mcfwdebug.h>
 
@@ -38,11 +39,60 @@ extern unsigned int mcf_timerlevel;
 
 /***************************************************************************/
 
-/*
- *     DMA channel base address table.
- */
-unsigned int dma_base_addr[MAX_M68K_DMA_CHANNELS] = { };
-unsigned int dma_device_address[MAX_M68K_DMA_CHANNELS];
+static struct mcf_platform_uart m532x_uart_platform[] = {
+       {
+               .mapbase        = MCF_MBAR + MCFUART_BASE1,
+               .irq            = MCFINT_VECBASE + MCFINT_UART0,
+       },
+       {
+               .mapbase        = MCF_MBAR + MCFUART_BASE2,
+               .irq            = MCFINT_VECBASE + MCFINT_UART1,
+       },
+       {
+               .mapbase        = MCF_MBAR + MCFUART_BASE3,
+               .irq            = MCFINT_VECBASE + MCFINT_UART2,
+       },
+       { },
+};
+
+static struct platform_device m532x_uart = {
+       .name                   = "mcfuart",
+       .id                     = 0,
+       .dev.platform_data      = m532x_uart_platform,
+};
+
+static struct platform_device *m532x_devices[] __initdata = {
+       &m532x_uart,
+};
+
+/***************************************************************************/
+
+static void __init m532x_uart_init_line(int line, int irq)
+{
+       if (line == 0) {
+               MCF_INTC0_ICR26 = 0x3;
+               MCF_INTC0_CIMR = 26;
+               /* GPIO initialization */
+               MCF_GPIO_PAR_UART |= 0x000F;
+       } else if (line == 1) {
+               MCF_INTC0_ICR27 = 0x3;
+               MCF_INTC0_CIMR = 27;
+               /* GPIO initialization */
+               MCF_GPIO_PAR_UART |= 0x0FF0;
+       } else if (line == 2) {
+               MCF_INTC0_ICR28 = 0x3;
+               MCF_INTC0_CIMR = 28;
+       }
+}
+
+static void __init m532x_uarts_init(void)
+{
+       const int nrlines = ARRAY_SIZE(m532x_uart_platform);
+       int line;
+
+       for (line = 0; (line < nrlines); line++)
+               m532x_uart_init_line(line, m532x_uart_platform[line].irq);
+}
 
 /***************************************************************************/
 
@@ -66,21 +116,7 @@ void mcf_settimericr(unsigned int timer, unsigned int level)
 
 /***************************************************************************/
 
-int mcf_timerirqpending(int timer)
-{
-       unsigned int imr = 0;
-
-       switch (timer) {
-       case 1:  imr = 0x1; break;
-       case 2:  imr = 0x2; break;
-       default: break;
-       }
-       return (mcf_getiprh() & imr);
-}
-
-/***************************************************************************/
-
-void config_BSP(char *commandp, int size)
+void __init config_BSP(char *commandp, int size)
 {
        mcf_setimr(MCFSIM_IMR_MASKALL);
 
@@ -99,7 +135,7 @@ void config_BSP(char *commandp, int size)
        mcf_profilevector = 64+33;
        mach_reset = coldfire_reset;
 
-#ifdef MCF_BDM_DISABLE
+#ifdef CONFIG_BDM_DISABLE
        /*
         * Disable the BDM clocking.  This also turns off most of the rest of
         * the BDM device.  This is good for EMC reasons. This option is not
@@ -110,9 +146,19 @@ void config_BSP(char *commandp, int size)
 }
 
 /***************************************************************************/
-/* Board initialization */
 
-/********************************************************************/
+static int __init init_BSP(void)
+{
+       m532x_uarts_init();
+       platform_add_devices(m532x_devices, ARRAY_SIZE(m532x_devices));
+       return 0;
+}
+
+arch_initcall(init_BSP);
+
+/***************************************************************************/
+/* Board initialization */
+/***************************************************************************/
 /* 
  * PLL min/max specifications
  */
index 2d3b62eba7ca8c75040912d25ab33bec477f6bee..648b8b778211639fbf54ef9e7fae9d0e9e708e01 100644 (file)
 #include <linux/param.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
-#include <asm/dma.h>
+#include <linux/io.h>
 #include <asm/machdep.h>
 #include <asm/coldfire.h>
 #include <asm/mcfsim.h>
-#include <asm/mcfdma.h>
+#include <asm/mcfuart.h>
 
 /***************************************************************************/
 
@@ -29,17 +29,51 @@ extern unsigned int mcf_timerlevel;
 
 /***************************************************************************/
 
-/*
- *     DMA channel base address table.
- */
-unsigned int   dma_base_addr[MAX_M68K_DMA_CHANNELS] = {
-        MCF_MBAR + MCFDMA_BASE0,
-        MCF_MBAR + MCFDMA_BASE1,
-        MCF_MBAR + MCFDMA_BASE2,
-        MCF_MBAR + MCFDMA_BASE3,
+static struct mcf_platform_uart m5407_uart_platform[] = {
+       {
+               .mapbase        = MCF_MBAR + MCFUART_BASE1,
+               .irq            = 73,
+       },
+       {
+               .mapbase        = MCF_MBAR + MCFUART_BASE2,
+               .irq            = 74,
+       },
+       { },
+};
+
+static struct platform_device m5407_uart = {
+       .name                   = "mcfuart",
+       .id                     = 0,
+       .dev.platform_data      = m5407_uart_platform,
 };
 
-unsigned int dma_device_address[MAX_M68K_DMA_CHANNELS];
+static struct platform_device *m5407_devices[] __initdata = {
+       &m5407_uart,
+};
+
+/***************************************************************************/
+
+static void __init m5407_uart_init_line(int line, int irq)
+{
+       if (line == 0) {
+               writel(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI1, MCF_MBAR + MCFSIM_UART1ICR);
+               writeb(irq, MCFUART_BASE1 + MCFUART_UIVR);
+               mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_UART1);
+       } else if (line == 1) {
+               writel(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI2, MCF_MBAR + MCFSIM_UART2ICR);
+               writeb(irq, MCFUART_BASE2 + MCFUART_UIVR);
+               mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_UART2);
+       }
+}
+
+static void __init m5407_uarts_init(void)
+{
+       const int nrlines = ARRAY_SIZE(m5407_uart_platform);
+       int line;
+
+       for (line = 0; (line < nrlines); line++)
+               m5407_uart_init_line(line, m5407_uart_platform[line].irq);
+}
 
 /***************************************************************************/
 
@@ -76,21 +110,7 @@ void mcf_settimericr(unsigned int timer, unsigned int level)
 
 /***************************************************************************/
 
-int mcf_timerirqpending(int timer)
-{
-       unsigned int imr = 0;
-
-       switch (timer) {
-       case 1:  imr = MCFSIM_IMR_TIMER1; break;
-       case 2:  imr = MCFSIM_IMR_TIMER2; break;
-       default: break;
-       }
-       return (mcf_getipr() & imr);
-}
-
-/***************************************************************************/
-
-void config_BSP(char *commandp, int size)
+void __init config_BSP(char *commandp, int size)
 {
        mcf_setimr(MCFSIM_IMR_MASKALL);
 
@@ -105,3 +125,14 @@ void config_BSP(char *commandp, int size)
 }
 
 /***************************************************************************/
+
+static int __init init_BSP(void)
+{
+       m5407_uarts_init();
+       platform_add_devices(m5407_devices, ARRAY_SIZE(m5407_devices));
+       return 0;
+}
+
+arch_initcall(init_BSP);
+
+/***************************************************************************/
index 04cbc661d4bdc16faf3e09f932186114b2fe4295..9159fd05c9ac7638e64af74f8f9502936142d721 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/mm.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
+#include <linux/clocksource.h>
 #include <asm/setup.h>
 #include <asm/system.h>
 #include <asm/pgtable.h>
 #define TICKS_PER_JIFFY        10
 #endif
 
+static u32 m68328_tick_cnt;
+
+/***************************************************************************/
+
+static irqreturn_t hw_tick(int irq, void *dummy)
+{
+       /* Reset Timer1 */
+       TSTAT &= 0;
+
+       m68328_tick_cnt += TICKS_PER_JIFFY;
+       return arch_timer_interrupt(irq, dummy);
+}
+
 /***************************************************************************/
 
 static irqreturn_t hw_tick(int irq, void *dummy)
@@ -69,6 +83,33 @@ static struct irqaction m68328_timer_irq = {
        .handler = hw_tick,
 };
 
+/***************************************************************************/
+
+static cycle_t m68328_read_clk(void)
+{
+       unsigned long flags;
+       u32 cycles;
+
+       local_irq_save(flags);
+       cycles = m68328_tick_cnt + TCN;
+       local_irq_restore(flags);
+
+       return cycles;
+}
+
+/***************************************************************************/
+
+static struct clocksource m68328_clk = {
+       .name   = "timer",
+       .rating = 250,
+       .read   = m68328_read_clk,
+       .shift  = 20,
+       .mask   = CLOCKSOURCE_MASK(32),
+       .flags  = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+/***************************************************************************/
+
 void hw_timer_init(void)
 {
        /* disable timer 1 */
@@ -84,19 +125,8 @@ void hw_timer_init(void)
 
        /* Enable timer 1 */
        TCTL |= TCTL_TEN;
-}
-
-/***************************************************************************/
-
-unsigned long hw_timer_offset(void)
-{
-       unsigned long ticks = TCN, offset = 0;
-
-       /* check for pending interrupt */
-       if (ticks < (TICKS_PER_JIFFY >> 1) && (ISR & (1 << TMR_IRQ_NUM)))
-               offset = 1000000 / HZ;
-       ticks = (ticks * 1000000 / HZ) / TICKS_PER_JIFFY;
-       return ticks + offset;
+       m68328_clk.mult = clocksource_hz2mult(TICKS_PER_JIFFY*HZ, m68328_clk.shift);
+       clocksource_register(&m68328_clk);
 }
 
 /***************************************************************************/
index 2b3196af811f3b92ee9b20e532a7d46acbb91310..ac629fa300994c2ba8b1328ab5a7d29b84ded27e 100644 (file)
@@ -103,11 +103,6 @@ void hw_timer_init(void)
   pquicc->timer_tgcr  = tgcr_save;
 }
 
-unsigned long hw_timer_offset(void)
-{
-  return 0;
-}
-
 void BSP_gettod (int *yearp, int *monp, int *dayp,
                   int *hourp, int *minp, int *secp)
 {
diff --git a/arch/m68knommu/platform/coldfire/Makefile b/arch/m68knommu/platform/coldfire/Makefile
new file mode 100644 (file)
index 0000000..e5fff29
--- /dev/null
@@ -0,0 +1,32 @@
+#
+# Makefile for the m68knommu kernel.
+#
+
+#
+# If you want to play with the HW breakpoints then you will
+# need to add define this,  which will give you a stack backtrace
+# on the console port whenever a DBG interrupt occurs. You have to
+# set up you HW breakpoints to trigger a DBG interrupt:
+#
+# EXTRA_CFLAGS += -DTRAP_DBG_INTERRUPT
+# EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT
+#
+
+ifdef CONFIG_FULLDEBUG
+AFLAGS += -DDEBUGGER_COMPATIBLE_CACHE=1
+endif
+
+obj-$(CONFIG_COLDFIRE) += dma.o entry.o vectors.o
+obj-$(CONFIG_M5206)    += timers.o
+obj-$(CONFIG_M5206e)   += timers.o
+obj-$(CONFIG_M520x)    += pit.o
+obj-$(CONFIG_M523x)    += pit.o
+obj-$(CONFIG_M5249)    += timers.o
+obj-$(CONFIG_M527x)    += pit.o
+obj-$(CONFIG_M5272)    += timers.o
+obj-$(CONFIG_M528x)    += pit.o
+obj-$(CONFIG_M5307)    += timers.o
+obj-$(CONFIG_M532x)    += timers.o
+obj-$(CONFIG_M5407)    += timers.o
+
+extra-y := head.o
diff --git a/arch/m68knommu/platform/coldfire/dma.c b/arch/m68knommu/platform/coldfire/dma.c
new file mode 100644 (file)
index 0000000..2b30cf1
--- /dev/null
@@ -0,0 +1,39 @@
+/***************************************************************************/
+
+/*
+ *     dma.c -- Freescale ColdFire DMA support
+ *
+ *     Copyright (C) 2007, Greg Ungerer (gerg@snapgear.com)
+ */
+
+/***************************************************************************/
+
+#include <linux/kernel.h>
+#include <asm/dma.h>
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+#include <asm/mcfdma.h>
+
+/***************************************************************************/
+
+/*
+ *      DMA channel base address table.
+ */
+unsigned int dma_base_addr[MAX_M68K_DMA_CHANNELS] = {
+#ifdef MCFDMA_BASE0
+       MCF_MBAR + MCFDMA_BASE0,
+#endif
+#ifdef MCFDMA_BASE1
+       MCF_MBAR + MCFDMA_BASE1,
+#endif
+#ifdef MCFDMA_BASE2
+       MCF_MBAR + MCFDMA_BASE2,
+#endif
+#ifdef MCFDMA_BASE3
+       MCF_MBAR + MCFDMA_BASE3,
+#endif
+};
+
+unsigned int dma_device_address[MAX_M68K_DMA_CHANNELS];
+
+/***************************************************************************/
similarity index 53%
rename from arch/m68knommu/platform/5307/pit.c
rename to arch/m68knommu/platform/coldfire/pit.c
index 173b754d1cdadea1fdf810c4a6cca030fc1916d4..4290638012e0ee3dfee426848fb8624bb8cb77e5 100644 (file)
@@ -3,9 +3,10 @@
 /*
  *     pit.c -- Freescale ColdFire PIT timer. Currently this type of
  *              hardware timer only exists in the Freescale ColdFire
- *              5270/5271, 5282 and other CPUs.
+ *              5270/5271, 5282 and 5208 CPUs. No doubt newer ColdFire
+ *              family members will probably use it too.
  *
- *     Copyright (C) 1999-2007, Greg Ungerer (gerg@snapgear.com)
+ *     Copyright (C) 1999-2008, Greg Ungerer (gerg@snapgear.com)
  *     Copyright (C) 2001-2004, SnapGear Inc. (www.snapgear.com)
  */
 
@@ -17,6 +18,7 @@
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
+#include <linux/clocksource.h>
 #include <asm/machdep.h>
 #include <asm/io.h>
 #include <asm/coldfire.h>
 /*
  *     By default use timer1 as the system clock timer.
  */
+#define        FREQ    ((MCF_CLK / 2) / 64)
 #define        TA(a)   (MCF_IPSBAR + MCFPIT_BASE1 + (a))
+#define        INTC0   (MCF_IPSBAR + MCFICM_INTC0)
+
+static u32 pit_cycles_per_jiffy;
+static u32 pit_cnt;
 
 /***************************************************************************/
 
-static irqreturn_t hw_tick(int irq, void *dummy)
+static irqreturn_t pit_tick(int irq, void *dummy)
 {
-       unsigned short pcsr;
+       u16 pcsr;
 
        /* Reset the ColdFire timer */
        pcsr = __raw_readw(TA(MCFPIT_PCSR));
        __raw_writew(pcsr | MCFPIT_PCSR_PIF, TA(MCFPIT_PCSR));
 
+       pit_cnt += pit_cycles_per_jiffy;
        return arch_timer_interrupt(irq, dummy);
 }
 
 /***************************************************************************/
 
-static struct irqaction coldfire_pit_irq = {
+static struct irqaction pit_irq = {
        .name    = "timer",
        .flags   = IRQF_DISABLED | IRQF_TIMER,
-       .handler = hw_tick,
+       .handler = pit_tick,
 };
 
-void hw_timer_init(void)
+/***************************************************************************/
+
+static cycle_t pit_read_clk(void)
 {
-       volatile unsigned char *icrp;
-       volatile unsigned long *imrp;
+       unsigned long flags;
+       u32 cycles;
+       u16 pcntr;
 
-       setup_irq(MCFINT_VECBASE + MCFINT_PIT1, &coldfire_pit_irq);
+       local_irq_save(flags);
+       pcntr = __raw_readw(TA(MCFPIT_PCNTR));
+       cycles = pit_cnt;
+       local_irq_restore(flags);
 
-       icrp = (volatile unsigned char *) (MCF_IPSBAR + MCFICM_INTC0 +
-               MCFINTC_ICR0 + MCFINT_PIT1);
-       *icrp = ICR_INTRCONF;
+       return cycles + pit_cycles_per_jiffy - pcntr;
+}
 
-       imrp = (volatile unsigned long *) (MCF_IPSBAR + MCFICM_INTC0 + MCFPIT_IMR);
-       *imrp &= ~MCFPIT_IMR_IBIT;
+/***************************************************************************/
 
-       /* Set up PIT timer 1 as poll clock */
-       __raw_writew(MCFPIT_PCSR_DISABLE, TA(MCFPIT_PCSR));
-       __raw_writew(((MCF_CLK / 2) / 64) / HZ, TA(MCFPIT_PMR));
-       __raw_writew(MCFPIT_PCSR_EN | MCFPIT_PCSR_PIE | MCFPIT_PCSR_OVW |
-               MCFPIT_PCSR_RLD | MCFPIT_PCSR_CLK64, TA(MCFPIT_PCSR));
-}
+static struct clocksource pit_clk = {
+       .name   = "pit",
+       .rating = 250,
+       .read   = pit_read_clk,
+       .shift  = 20,
+       .mask   = CLOCKSOURCE_MASK(32),
+       .flags  = CLOCK_SOURCE_IS_CONTINUOUS,
+};
 
 /***************************************************************************/
 
-unsigned long hw_timer_offset(void)
+void hw_timer_init(void)
 {
-       volatile unsigned long *ipr;
-       unsigned long pmr, pcntr, offset;
+       u32 imr;
 
-       ipr = (volatile unsigned long *) (MCF_IPSBAR + MCFICM_INTC0 + MCFPIT_IMR);
+       setup_irq(MCFINT_VECBASE + MCFINT_PIT1, &pit_irq);
 
-       pmr = __raw_readw(TA(MCFPIT_PMR));
-       pcntr = __raw_readw(TA(MCFPIT_PCNTR));
+       __raw_writeb(ICR_INTRCONF, INTC0 + MCFINTC_ICR0 + MCFINT_PIT1);
+       imr = __raw_readl(INTC0 + MCFPIT_IMR);
+       imr &= ~MCFPIT_IMR_IBIT;
+       __raw_writel(imr, INTC0 + MCFPIT_IMR);
+
+       /* Set up PIT timer 1 as poll clock */
+       pit_cycles_per_jiffy = FREQ / HZ;
+       __raw_writew(MCFPIT_PCSR_DISABLE, TA(MCFPIT_PCSR));
+       __raw_writew(pit_cycles_per_jiffy, TA(MCFPIT_PMR));
+       __raw_writew(MCFPIT_PCSR_EN | MCFPIT_PCSR_PIE | MCFPIT_PCSR_OVW |
+               MCFPIT_PCSR_RLD | MCFPIT_PCSR_CLK64, TA(MCFPIT_PCSR));
 
-       /*
-        * If we are still in the first half of the upcount and a
-        * timer interrupt is pending, then add on a ticks worth of time.
-        */
-       offset = ((pmr - pcntr) * (1000000 / HZ)) / pmr;
-       if ((offset < (1000000 / HZ / 2)) && (*ipr & MCFPIT_IMR_IBIT))
-               offset += 1000000 / HZ;
-       return offset;  
+       pit_clk.mult = clocksource_hz2mult(FREQ, pit_clk.shift);
+       clocksource_register(&pit_clk);
 }
 
 /***************************************************************************/
similarity index 77%
rename from arch/m68knommu/platform/5307/timers.c
rename to arch/m68knommu/platform/coldfire/timers.c
index 489dec85c8594e8fa5d46eedf8478ec01cd249d3..a60213e877ef1b8695a2c836ca5038301106f20a 100644 (file)
@@ -3,7 +3,7 @@
 /*
  *     timers.c -- generic ColdFire hardware timer support.
  *
- *     Copyright (C) 1999-2007, Greg Ungerer (gerg@snapgear.com)
+ *     Copyright (C) 1999-2008, Greg Ungerer <gerg@snapgear.com>
  */
 
 /***************************************************************************/
@@ -13,6 +13,8 @@
 #include <linux/sched.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
+#include <linux/profile.h>
+#include <linux/clocksource.h>
 #include <asm/io.h>
 #include <asm/traps.h>
 #include <asm/machdep.h>
@@ -25,6 +27,7 @@
 /*
  *     By default use timer1 as the system clock timer.
  */
+#define        FREQ    (MCF_BUSCLK / 16)
 #define        TA(a)   (MCF_MBAR + MCFTIMER_BASE1 + (a))
 
 /*
@@ -41,7 +44,7 @@ unsigned int  mcf_timerlevel = 5;
  *     Unfortunately it is a little different on each ColdFire.
  */
 extern void mcf_settimericr(int timer, int level);
-extern int mcf_timerirqpending(int timer);
+void coldfire_profile_init(void);
 
 #if defined(CONFIG_M532x)
 #define        __raw_readtrr   __raw_readl
@@ -51,38 +54,70 @@ extern int mcf_timerirqpending(int timer);
 #define        __raw_writetrr  __raw_writew
 #endif
 
+static u32 mcftmr_cycles_per_jiffy;
+static u32 mcftmr_cnt;
+
 /***************************************************************************/
 
-static irqreturn_t hw_tick(int irq, void *dummy)
+static irqreturn_t mcftmr_tick(int irq, void *dummy)
 {
        /* Reset the ColdFire timer */
        __raw_writeb(MCFTIMER_TER_CAP | MCFTIMER_TER_REF, TA(MCFTIMER_TER));
 
+       mcftmr_cnt += mcftmr_cycles_per_jiffy;
        return arch_timer_interrupt(irq, dummy);
 }
 
 /***************************************************************************/
 
-static struct irqaction coldfire_timer_irq = {
+static struct irqaction mcftmr_timer_irq = {
        .name    = "timer",
        .flags   = IRQF_DISABLED | IRQF_TIMER,
-       .handler = hw_tick,
+       .handler = mcftmr_tick,
 };
 
 /***************************************************************************/
 
-static int ticks_per_intr;
+static cycle_t mcftmr_read_clk(void)
+{
+       unsigned long flags;
+       u32 cycles;
+       u16 tcn;
+
+       local_irq_save(flags);
+       tcn = __raw_readw(TA(MCFTIMER_TCN));
+       cycles = mcftmr_cnt;
+       local_irq_restore(flags);
+
+       return cycles + tcn;
+}
+
+/***************************************************************************/
+
+static struct clocksource mcftmr_clk = {
+       .name   = "tmr",
+       .rating = 250,
+       .read   = mcftmr_read_clk,
+       .shift  = 20,
+       .mask   = CLOCKSOURCE_MASK(32),
+       .flags  = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+/***************************************************************************/
 
 void hw_timer_init(void)
 {
-       setup_irq(mcf_timervector, &coldfire_timer_irq);
+       setup_irq(mcf_timervector, &mcftmr_timer_irq);
 
        __raw_writew(MCFTIMER_TMR_DISABLE, TA(MCFTIMER_TMR));
-       ticks_per_intr = (MCF_BUSCLK / 16) / HZ;
-       __raw_writetrr(ticks_per_intr - 1, TA(MCFTIMER_TRR));
+       mcftmr_cycles_per_jiffy = FREQ / HZ;
+       __raw_writetrr(mcftmr_cycles_per_jiffy, TA(MCFTIMER_TRR));
        __raw_writew(MCFTIMER_TMR_ENORI | MCFTIMER_TMR_CLK16 |
                MCFTIMER_TMR_RESTART | MCFTIMER_TMR_ENABLE, TA(MCFTIMER_TMR));
 
+       mcftmr_clk.mult = clocksource_hz2mult(FREQ, mcftmr_clk.shift);
+       clocksource_register(&mcftmr_clk);
+
        mcf_settimericr(1, mcf_timerlevel);
 
 #ifdef CONFIG_HIGHPROFILE
@@ -90,21 +125,6 @@ void hw_timer_init(void)
 #endif
 }
 
-/***************************************************************************/
-
-unsigned long hw_timer_offset(void)
-{
-       unsigned long tcn, offset;
-
-       tcn = __raw_readw(TA(MCFTIMER_TCN));
-       offset = ((tcn + 1) * (1000000 / HZ)) / ticks_per_intr;
-
-       /* Check if we just wrapped the counters and maybe missed a tick */
-       if ((offset < (1000000 / HZ / 2)) && mcf_timerirqpending(1))
-               offset += 1000000 / HZ;
-       return offset;
-}
-
 /***************************************************************************/
 #ifdef CONFIG_HIGHPROFILE
 /***************************************************************************/
index 4fad0a34b9974d31f16b5e1e6a8bb6e3c067e710..ec78a5762e9ec3be6a23630413c4f81a5f6b0fe9 100644 (file)
@@ -1,6 +1,7 @@
 config MIPS
        bool
        default y
+       select HAVE_OPROFILE
        # Horrible source of confusion.  Die, die, die ...
        select EMBEDDED
        select RTC_LIB
@@ -1754,8 +1755,8 @@ config SMP
          People using multiprocessor machines who say Y here should also say
          Y to "Enhanced Real Time Clock Support", below.
 
-         See also the <file:Documentation/smp.txt> and the SMP-HOWTO
-         available at <http://www.tldp.org/docs.html#howto>.
+         See also the SMP-HOWTO available at
+         <http://www.tldp.org/docs.html#howto>.
 
          If you don't know what to do here, say N.
 
@@ -1961,11 +1962,6 @@ config PCI
          your box. Other bus systems are ISA, EISA, or VESA. If you have PCI,
          say Y, otherwise N.
 
-         The PCI-HOWTO, available from
-         <http://www.tldp.org/docs.html#howto>, contains valuable
-         information about which PCI hardware does work under Linux and which
-         doesn't.
-
 config PCI_DOMAINS
        bool
 
@@ -2086,6 +2082,10 @@ endmenu
 
 menu "Power management options"
 
+config ARCH_SUSPEND_POSSIBLE
+       def_bool y
+       depends on !SMP
+
 source "kernel/power/Kconfig"
 
 endmenu
@@ -2096,8 +2096,6 @@ source "drivers/Kconfig"
 
 source "fs/Kconfig"
 
-source "kernel/Kconfig.instrumentation"
-
 source "arch/mips/Kconfig.debug"
 
 source "security/Kconfig"
index abfc4bcddf7a4569d7783f5de5603cb1f6e88a6a..310d5dff89fca6347f34ce38e112dbf2116a87f6 100644 (file)
@@ -99,7 +99,7 @@ mtx1_pci_idsel(unsigned int devsel, int assert)
 #endif
 
        if (assert && devsel != 0) {
-               // supress signal to cardbus
+               // suppress signal to cardbus
                au_writel( 0x00000002, SYS_OUTPUTCLR ); // set EXT_IO3 OFF
        }
        else {
index 9b34238d41c09d7a91887469fc3ff02eef223704..77db3473deabfc20c97acb99d89dbd77c96b9170 100644 (file)
@@ -98,7 +98,7 @@ static __inline__ void
 jiffies_to_compat_timeval(unsigned long jiffies, struct compat_timeval *value)
 {
        /*
-        * Convert jiffies to nanoseconds and seperate with
+        * Convert jiffies to nanoseconds and separate with
         * one divide.
         */
        u64 nsec = (u64)jiffies * TICK_NSEC;
index da41eac195ca0197b332824205cd47e31d4231b9..08f4cd781ee33cc5ac695fed9705a33e7e507e65 100644 (file)
@@ -100,7 +100,7 @@ static inline void
 jiffies_to_compat_timeval(unsigned long jiffies, struct compat_timeval *value)
 {
        /*
-        * Convert jiffies to nanoseconds and seperate with
+        * Convert jiffies to nanoseconds and separate with
         * one divide.
         */
        u64 nsec = (u64)jiffies * TICK_NSEC;
index 50be56c9e9ef590e9960337de7da248f5eaed575..a24fb790090113eef1fc650b677ce70c80d79c53 100644 (file)
@@ -140,7 +140,7 @@ FEXPORT(__kernel_entry)
        j       kernel_entry
 #endif
 
-       __INIT_REFOK
+       __REF
 
 NESTED(kernel_entry, 16, sp)                   # kernel entry point
 
index f6704ab16306a91b5b2b654d3dcc312b5a437648..998c4efcce88df4acb15485d529badd73a0782eb 100644 (file)
@@ -221,7 +221,7 @@ void sp_work_handle_request(void)
                }
        }
 
-       /* Run the syscall at the priviledge of the user who loaded the
+       /* Run the syscall at the privilege of the user who loaded the
           SP program */
 
        if (vpe_getuid(tclimit))
index 82480a1717d892eb6b07db692055c643851c0e44..f798139e888e144943870740b20b9cb812ef0543 100644 (file)
@@ -660,7 +660,7 @@ einval:     li      v0, -EINVAL
        sys     sys_ioprio_get          2       /* 4315 */
        sys     sys_utimensat           4
        sys     sys_signalfd            3
-       sys     sys_timerfd             4
+       sys     sys_ni_syscall          0
        sys     sys_eventfd             1
        sys     sys_fallocate           6       /* 4320 */
        .endm
index c2c10876da2e2a85d4ad9299111bddf004fb58f6..a626be6baea38e477ca76a444bb8326979cec1ae 100644 (file)
@@ -475,7 +475,7 @@ sys_call_table:
        PTR     sys_ioprio_get
        PTR     sys_utimensat                   /* 5275 */
        PTR     sys_signalfd
-       PTR     sys_timerfd
+       PTR     sys_ni_syscall
        PTR     sys_eventfd
        PTR     sys_fallocate
        .size   sys_call_table,.-sys_call_table
index 01993ec3368b5344caabcca54f8b1bc75e7641bc..9d5bcaf1b3890e35ba92a1ccbba03d2ec42f41ea 100644 (file)
@@ -401,7 +401,7 @@ EXPORT(sysn32_call_table)
        PTR     sys_ioprio_get
        PTR     compat_sys_utimensat
        PTR     compat_sys_signalfd             /* 5280 */
-       PTR     compat_sys_timerfd
+       PTR     sys_ni_syscall
        PTR     sys_eventfd
        PTR     sys_fallocate
        .size   sysn32_call_table,.-sysn32_call_table
index dd68afce7da5782dc0f59766b04eb3afcb7eb647..fd2019c1ec2d65e9a9532ece52a60828025090bf 100644 (file)
@@ -523,7 +523,7 @@ sys_call_table:
        PTR     sys_ioprio_get                  /* 4315 */
        PTR     compat_sys_utimensat
        PTR     compat_sys_signalfd
-       PTR     compat_sys_timerfd
+       PTR     sys_ni_syscall
        PTR     sys_eventfd
        PTR     sys32_fallocate                 /* 4320 */
        .size   sys_call_table,.-sys_call_table
index 269c252d956f42c1d74ec85162af510c3e986141..c032409cba9b50b7df4bfad7988dd26ad0d00213 100644 (file)
@@ -424,13 +424,13 @@ static void __init bootmem_init(void)
 #endif /* CONFIG_SGI_IP27 */
 
 /*
- * arch_mem_init - initialize memory managment subsystem
+ * arch_mem_init - initialize memory management subsystem
  *
  *  o plat_mem_setup() detects the memory configuration and will record detected
  *    memory areas using add_memory_region.
  *
  * At this stage the memory configuration of the system is known to the
- * kernel but generic memory managment system is still entirely uninitialized.
+ * kernel but generic memory management system is still entirely uninitialized.
  *
  *  o bootmem_init()
  *  o sparse_init()
index 85f700e581316df1a2e4d735e89a767d89fddd12..b42e71c711199a4f169f717e8467240b8ebbae57 100644 (file)
@@ -65,7 +65,7 @@ asiduse smtc_live_asid[MAX_SMTC_TLBS][MAX_SMTC_ASIDS];
 static atomic_t ipi_timer_latch[NR_CPUS];
 
 /*
- * Number of InterProcessor Interupt (IPI) message buffers to allocate
+ * Number of InterProcessor Interrupt (IPI) message buffers to allocate
  */
 
 #define IPIBUF_PER_CPU 4
@@ -780,7 +780,7 @@ void smtc_send_ipi(int cpu, int type, unsigned int action)
        if (cpu_data[cpu].vpe_id != cpu_data[smp_processor_id()].vpe_id) {
                if (type == SMTC_CLOCK_TICK)
                        atomic_inc(&ipi_timer_latch[cpu]);
-               /* If not on same VPE, enqueue and send cross-VPE interupt */
+               /* If not on same VPE, enqueue and send cross-VPE interrupt */
                smtc_ipi_nq(&IPIQ[cpu], pipi);
                LOCK_CORE_PRA();
                settc(cpu_data[cpu].tc_id);
@@ -1063,7 +1063,7 @@ static void setup_cross_vpe_interrupts(unsigned int nvpe)
                return;
 
        if (!cpu_has_vint)
-               panic("SMTC Kernel requires Vectored Interupt support");
+               panic("SMTC Kernel requires Vectored Interrupt support");
 
        set_vi_handler(MIPS_CPU_IPI_IRQ, ipi_irq_dispatch);
 
index 32fd5db95774c050cdce8f672456c3b495c1c52c..c6f832e0f41ca6f1cffac106e193cff2503ed912 100644 (file)
@@ -3,7 +3,8 @@
 #
 
 obj-y                          += cache.o dma-default.o extable.o fault.o \
-                                  init.o pgtable.o tlbex.o tlbex-fault.o
+                                  init.o pgtable.o tlbex.o tlbex-fault.o \
+                                  uasm.o
 
 obj-$(CONFIG_32BIT)            += ioremap.o pgtable-32.o
 obj-$(CONFIG_64BIT)            += pgtable-64.o
index 02bd180f0e02748354383af23352900da6d1b02b..53ec05267a98190739ac454d217f4e12a9f34e90 100644 (file)
@@ -1101,7 +1101,7 @@ static void __init setup_scache(void)
        /*
         * Do the probing thing on R4000SC and R4400SC processors.  Other
         * processors don't have a S-cache that would be relevant to the
-        * Linux memory managment.
+        * Linux memory management.
         */
        switch (c->cputype) {
        case CPU_R4000SC:
index d026302e0ecc6b8b49c4c95c847f4de79fddadec..218a6cc415e8865cbdb83b59889666fd4f2d8dc7 100644 (file)
@@ -5,7 +5,7 @@
  *
  * Synthesize TLB refill handlers at runtime.
  *
- * Copyright (C) 2004,2005,2006 by Thiemo Seufer
+ * Copyright (C) 2004, 2005, 2006, 2008  Thiemo Seufer
  * Copyright (C) 2005, 2007  Maciej W. Rozycki
  * Copyright (C) 2006  Ralf Baechle (ralf@linux-mips.org)
  *
 #include <linux/string.h>
 #include <linux/init.h>
 
-#include <asm/bugs.h>
 #include <asm/mmu_context.h>
-#include <asm/inst.h>
-#include <asm/elf.h>
 #include <asm/war.h>
 
+#include "uasm.h"
+
 static inline int r45k_bvahwbug(void)
 {
        /* XXX: We should probe for the presence of this bug, but we don't. */
@@ -67,371 +66,9 @@ static int __init m4kc_tlbp_war(void)
               (PRID_COMP_MIPS | PRID_IMP_4KC);
 }
 
-/*
- * A little micro-assembler, intended for TLB refill handler
- * synthesizing. It is intentionally kept simple, does only support
- * a subset of instructions, and does not try to hide pipeline effects
- * like branch delay slots.
- */
-
-enum fields
-{
-       RS = 0x001,
-       RT = 0x002,
-       RD = 0x004,
-       RE = 0x008,
-       SIMM = 0x010,
-       UIMM = 0x020,
-       BIMM = 0x040,
-       JIMM = 0x080,
-       FUNC = 0x100,
-       SET = 0x200
-};
-
-#define OP_MASK                0x3f
-#define OP_SH          26
-#define RS_MASK                0x1f
-#define RS_SH          21
-#define RT_MASK                0x1f
-#define RT_SH          16
-#define RD_MASK                0x1f
-#define RD_SH          11
-#define RE_MASK                0x1f
-#define RE_SH          6
-#define IMM_MASK       0xffff
-#define IMM_SH         0
-#define JIMM_MASK      0x3ffffff
-#define JIMM_SH                0
-#define FUNC_MASK      0x3f
-#define FUNC_SH                0
-#define SET_MASK       0x7
-#define SET_SH         0
-
-enum opcode {
-       insn_invalid,
-       insn_addu, insn_addiu, insn_and, insn_andi, insn_beq,
-       insn_beql, insn_bgez, insn_bgezl, insn_bltz, insn_bltzl,
-       insn_bne, insn_daddu, insn_daddiu, insn_dmfc0, insn_dmtc0,
-       insn_dsll, insn_dsll32, insn_dsra, insn_dsrl, insn_dsrl32,
-       insn_dsubu, insn_eret, insn_j, insn_jal, insn_jr, insn_ld,
-       insn_ll, insn_lld, insn_lui, insn_lw, insn_mfc0, insn_mtc0,
-       insn_ori, insn_rfe, insn_sc, insn_scd, insn_sd, insn_sll,
-       insn_sra, insn_srl, insn_subu, insn_sw, insn_tlbp, insn_tlbwi,
-       insn_tlbwr, insn_xor, insn_xori
-};
-
-struct insn {
-       enum opcode opcode;
-       u32 match;
-       enum fields fields;
-};
-
-/* This macro sets the non-variable bits of an instruction. */
-#define M(a, b, c, d, e, f)                                    \
-       ((a) << OP_SH                                           \
-        | (b) << RS_SH                                         \
-        | (c) << RT_SH                                         \
-        | (d) << RD_SH                                         \
-        | (e) << RE_SH                                         \
-        | (f) << FUNC_SH)
-
-static struct insn insn_table[] __initdata = {
-       { insn_addiu, M(addiu_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
-       { insn_addu, M(spec_op, 0, 0, 0, 0, addu_op), RS | RT | RD },
-       { insn_and, M(spec_op, 0, 0, 0, 0, and_op), RS | RT | RD },
-       { insn_andi, M(andi_op, 0, 0, 0, 0, 0), RS | RT | UIMM },
-       { insn_beq, M(beq_op, 0, 0, 0, 0, 0), RS | RT | BIMM },
-       { insn_beql, M(beql_op, 0, 0, 0, 0, 0), RS | RT | BIMM },
-       { insn_bgez, M(bcond_op, 0, bgez_op, 0, 0, 0), RS | BIMM },
-       { insn_bgezl, M(bcond_op, 0, bgezl_op, 0, 0, 0), RS | BIMM },
-       { insn_bltz, M(bcond_op, 0, bltz_op, 0, 0, 0), RS | BIMM },
-       { insn_bltzl, M(bcond_op, 0, bltzl_op, 0, 0, 0), RS | BIMM },
-       { insn_bne, M(bne_op, 0, 0, 0, 0, 0), RS | RT | BIMM },
-       { insn_daddiu, M(daddiu_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
-       { insn_daddu, M(spec_op, 0, 0, 0, 0, daddu_op), RS | RT | RD },
-       { insn_dmfc0, M(cop0_op, dmfc_op, 0, 0, 0, 0), RT | RD | SET},
-       { insn_dmtc0, M(cop0_op, dmtc_op, 0, 0, 0, 0), RT | RD | SET},
-       { insn_dsll, M(spec_op, 0, 0, 0, 0, dsll_op), RT | RD | RE },
-       { insn_dsll32, M(spec_op, 0, 0, 0, 0, dsll32_op), RT | RD | RE },
-       { insn_dsra, M(spec_op, 0, 0, 0, 0, dsra_op), RT | RD | RE },
-       { insn_dsrl, M(spec_op, 0, 0, 0, 0, dsrl_op), RT | RD | RE },
-       { insn_dsrl32, M(spec_op, 0, 0, 0, 0, dsrl32_op), RT | RD | RE },
-       { insn_dsubu, M(spec_op, 0, 0, 0, 0, dsubu_op), RS | RT | RD },
-       { insn_eret,  M(cop0_op, cop_op, 0, 0, 0, eret_op),  0 },
-       { insn_j,  M(j_op, 0, 0, 0, 0, 0),  JIMM },
-       { insn_jal,  M(jal_op, 0, 0, 0, 0, 0),  JIMM },
-       { insn_jr,  M(spec_op, 0, 0, 0, 0, jr_op),  RS },
-       { insn_ld,  M(ld_op, 0, 0, 0, 0, 0),  RS | RT | SIMM },
-       { insn_ll,  M(ll_op, 0, 0, 0, 0, 0),  RS | RT | SIMM },
-       { insn_lld,  M(lld_op, 0, 0, 0, 0, 0),  RS | RT | SIMM },
-       { insn_lui,  M(lui_op, 0, 0, 0, 0, 0),  RT | SIMM },
-       { insn_lw,  M(lw_op, 0, 0, 0, 0, 0),  RS | RT | SIMM },
-       { insn_mfc0,  M(cop0_op, mfc_op, 0, 0, 0, 0),  RT | RD | SET},
-       { insn_mtc0,  M(cop0_op, mtc_op, 0, 0, 0, 0),  RT | RD | SET},
-       { insn_ori,  M(ori_op, 0, 0, 0, 0, 0),  RS | RT | UIMM },
-       { insn_rfe,  M(cop0_op, cop_op, 0, 0, 0, rfe_op),  0 },
-       { insn_sc,  M(sc_op, 0, 0, 0, 0, 0),  RS | RT | SIMM },
-       { insn_scd,  M(scd_op, 0, 0, 0, 0, 0),  RS | RT | SIMM },
-       { insn_sd,  M(sd_op, 0, 0, 0, 0, 0),  RS | RT | SIMM },
-       { insn_sll,  M(spec_op, 0, 0, 0, 0, sll_op),  RT | RD | RE },
-       { insn_sra,  M(spec_op, 0, 0, 0, 0, sra_op),  RT | RD | RE },
-       { insn_srl,  M(spec_op, 0, 0, 0, 0, srl_op),  RT | RD | RE },
-       { insn_subu,  M(spec_op, 0, 0, 0, 0, subu_op),  RS | RT | RD },
-       { insn_sw,  M(sw_op, 0, 0, 0, 0, 0),  RS | RT | SIMM },
-       { insn_tlbp,  M(cop0_op, cop_op, 0, 0, 0, tlbp_op),  0 },
-       { insn_tlbwi,  M(cop0_op, cop_op, 0, 0, 0, tlbwi_op),  0 },
-       { insn_tlbwr,  M(cop0_op, cop_op, 0, 0, 0, tlbwr_op),  0 },
-       { insn_xor,  M(spec_op, 0, 0, 0, 0, xor_op),  RS | RT | RD },
-       { insn_xori,  M(xori_op, 0, 0, 0, 0, 0),  RS | RT | UIMM },
-       { insn_invalid, 0, 0 }
-};
-
-#undef M
-
-static u32 __init build_rs(u32 arg)
-{
-       if (arg & ~RS_MASK)
-               printk(KERN_WARNING "TLB synthesizer field overflow\n");
-
-       return (arg & RS_MASK) << RS_SH;
-}
-
-static u32 __init build_rt(u32 arg)
-{
-       if (arg & ~RT_MASK)
-               printk(KERN_WARNING "TLB synthesizer field overflow\n");
-
-       return (arg & RT_MASK) << RT_SH;
-}
-
-static u32 __init build_rd(u32 arg)
-{
-       if (arg & ~RD_MASK)
-               printk(KERN_WARNING "TLB synthesizer field overflow\n");
-
-       return (arg & RD_MASK) << RD_SH;
-}
-
-static u32 __init build_re(u32 arg)
-{
-       if (arg & ~RE_MASK)
-               printk(KERN_WARNING "TLB synthesizer field overflow\n");
-
-       return (arg & RE_MASK) << RE_SH;
-}
-
-static u32 __init build_simm(s32 arg)
-{
-       if (arg > 0x7fff || arg < -0x8000)
-               printk(KERN_WARNING "TLB synthesizer field overflow\n");
-
-       return arg & 0xffff;
-}
-
-static u32 __init build_uimm(u32 arg)
-{
-       if (arg & ~IMM_MASK)
-               printk(KERN_WARNING "TLB synthesizer field overflow\n");
-
-       return arg & IMM_MASK;
-}
-
-static u32 __init build_bimm(s32 arg)
-{
-       if (arg > 0x1ffff || arg < -0x20000)
-               printk(KERN_WARNING "TLB synthesizer field overflow\n");
-
-       if (arg & 0x3)
-               printk(KERN_WARNING "Invalid TLB synthesizer branch target\n");
-
-       return ((arg < 0) ? (1 << 15) : 0) | ((arg >> 2) & 0x7fff);
-}
-
-static u32 __init build_jimm(u32 arg)
-{
-       if (arg & ~((JIMM_MASK) << 2))
-               printk(KERN_WARNING "TLB synthesizer field overflow\n");
-
-       return (arg >> 2) & JIMM_MASK;
-}
-
-static u32 __init build_func(u32 arg)
-{
-       if (arg & ~FUNC_MASK)
-               printk(KERN_WARNING "TLB synthesizer field overflow\n");
-
-       return arg & FUNC_MASK;
-}
-
-static u32 __init build_set(u32 arg)
-{
-       if (arg & ~SET_MASK)
-               printk(KERN_WARNING "TLB synthesizer field overflow\n");
-
-       return arg & SET_MASK;
-}
-
-/*
- * The order of opcode arguments is implicitly left to right,
- * starting with RS and ending with FUNC or IMM.
- */
-static void __init build_insn(u32 **buf, enum opcode opc, ...)
-{
-       struct insn *ip = NULL;
-       unsigned int i;
-       va_list ap;
-       u32 op;
-
-       for (i = 0; insn_table[i].opcode != insn_invalid; i++)
-               if (insn_table[i].opcode == opc) {
-                       ip = &insn_table[i];
-                       break;
-               }
-
-       if (!ip || (opc == insn_daddiu && r4k_daddiu_bug()))
-               panic("Unsupported TLB synthesizer instruction %d", opc);
-
-       op = ip->match;
-       va_start(ap, opc);
-       if (ip->fields & RS) op |= build_rs(va_arg(ap, u32));
-       if (ip->fields & RT) op |= build_rt(va_arg(ap, u32));
-       if (ip->fields & RD) op |= build_rd(va_arg(ap, u32));
-       if (ip->fields & RE) op |= build_re(va_arg(ap, u32));
-       if (ip->fields & SIMM) op |= build_simm(va_arg(ap, s32));
-       if (ip->fields & UIMM) op |= build_uimm(va_arg(ap, u32));
-       if (ip->fields & BIMM) op |= build_bimm(va_arg(ap, s32));
-       if (ip->fields & JIMM) op |= build_jimm(va_arg(ap, u32));
-       if (ip->fields & FUNC) op |= build_func(va_arg(ap, u32));
-       if (ip->fields & SET) op |= build_set(va_arg(ap, u32));
-       va_end(ap);
-
-       **buf = op;
-       (*buf)++;
-}
-
-#define I_u1u2u3(op)                                           \
-       static void __init __maybe_unused i##op(u32 **buf, unsigned int a, \
-               unsigned int b, unsigned int c)                 \
-       {                                                       \
-               build_insn(buf, insn##op, a, b, c);             \
-       }
-
-#define I_u2u1u3(op)                                           \
-       static void __init __maybe_unused i##op(u32 **buf, unsigned int a, \
-               unsigned int b, unsigned int c)                 \
-       {                                                       \
-               build_insn(buf, insn##op, b, a, c);             \
-       }
-
-#define I_u3u1u2(op)                                           \
-       static void __init __maybe_unused i##op(u32 **buf, unsigned int a, \
-               unsigned int b, unsigned int c)                 \
-       {                                                       \
-               build_insn(buf, insn##op, b, c, a);             \
-       }
-
-#define I_u1u2s3(op)                                           \
-       static void __init __maybe_unused i##op(u32 **buf, unsigned int a, \
-               unsigned int b, signed int c)                   \
-       {                                                       \
-               build_insn(buf, insn##op, a, b, c);             \
-       }
-
-#define I_u2s3u1(op)                                           \
-       static void __init __maybe_unused i##op(u32 **buf, unsigned int a, \
-               signed int b, unsigned int c)                   \
-       {                                                       \
-               build_insn(buf, insn##op, c, a, b);             \
-       }
-
-#define I_u2u1s3(op)                                           \
-       static void __init __maybe_unused i##op(u32 **buf, unsigned int a, \
-               unsigned int b, signed int c)                   \
-       {                                                       \
-               build_insn(buf, insn##op, b, a, c);             \
-       }
-
-#define I_u1u2(op)                                             \
-       static void __init __maybe_unused i##op(u32 **buf, unsigned int a, \
-               unsigned int b)                                 \
-       {                                                       \
-               build_insn(buf, insn##op, a, b);                \
-       }
-
-#define I_u1s2(op)                                             \
-       static void __init __maybe_unused i##op(u32 **buf, unsigned int a, \
-               signed int b)                                   \
-       {                                                       \
-               build_insn(buf, insn##op, a, b);                \
-       }
-
-#define I_u1(op)                                               \
-       static void __init __maybe_unused i##op(u32 **buf, unsigned int a) \
-       {                                                       \
-               build_insn(buf, insn##op, a);                   \
-       }
-
-#define I_0(op)                                                        \
-       static void __init __maybe_unused i##op(u32 **buf)      \
-       {                                                       \
-               build_insn(buf, insn##op);                      \
-       }
-
-I_u2u1s3(_addiu);
-I_u3u1u2(_addu);
-I_u2u1u3(_andi);
-I_u3u1u2(_and);
-I_u1u2s3(_beq);
-I_u1u2s3(_beql);
-I_u1s2(_bgez);
-I_u1s2(_bgezl);
-I_u1s2(_bltz);
-I_u1s2(_bltzl);
-I_u1u2s3(_bne);
-I_u1u2u3(_dmfc0);
-I_u1u2u3(_dmtc0);
-I_u2u1s3(_daddiu);
-I_u3u1u2(_daddu);
-I_u2u1u3(_dsll);
-I_u2u1u3(_dsll32);
-I_u2u1u3(_dsra);
-I_u2u1u3(_dsrl);
-I_u2u1u3(_dsrl32);
-I_u3u1u2(_dsubu);
-I_0(_eret);
-I_u1(_j);
-I_u1(_jal);
-I_u1(_jr);
-I_u2s3u1(_ld);
-I_u2s3u1(_ll);
-I_u2s3u1(_lld);
-I_u1s2(_lui);
-I_u2s3u1(_lw);
-I_u1u2u3(_mfc0);
-I_u1u2u3(_mtc0);
-I_u2u1u3(_ori);
-I_0(_rfe);
-I_u2s3u1(_sc);
-I_u2s3u1(_scd);
-I_u2s3u1(_sd);
-I_u2u1u3(_sll);
-I_u2u1u3(_sra);
-I_u2u1u3(_srl);
-I_u3u1u2(_subu);
-I_u2s3u1(_sw);
-I_0(_tlbp);
-I_0(_tlbwi);
-I_0(_tlbwr);
-I_u3u1u2(_xor)
-I_u2u1u3(_xori);
-
-/*
- * handling labels
- */
-
+/* Handle labels (which must be positive integers). */
 enum label_id {
-       label_invalid,
-       label_second_part,
+       label_second_part = 1,
        label_leave,
 #ifdef MODULE_START
        label_module_alloc,
@@ -447,278 +84,20 @@ enum label_id {
        label_r3000_write_probe_fail,
 };
 
-struct label {
-       u32 *addr;
-       enum label_id lab;
-};
-
-static void __init build_label(struct label **lab, u32 *addr,
-                              enum label_id l)
-{
-       (*lab)->addr = addr;
-       (*lab)->lab = l;
-       (*lab)++;
-}
-
-#define L_LA(lb)                                               \
-       static inline void __init l##lb(struct label **lab, u32 *addr) \
-       {                                                       \
-               build_label(lab, addr, label##lb);              \
-       }
-
-L_LA(_second_part)
-L_LA(_leave)
+UASM_L_LA(_second_part)
+UASM_L_LA(_leave)
 #ifdef MODULE_START
-L_LA(_module_alloc)
-#endif
-L_LA(_vmalloc)
-L_LA(_vmalloc_done)
-L_LA(_tlbw_hazard)
-L_LA(_split)
-L_LA(_nopage_tlbl)
-L_LA(_nopage_tlbs)
-L_LA(_nopage_tlbm)
-L_LA(_smp_pgtable_change)
-L_LA(_r3000_write_probe_fail)
-
-/* convenience macros for instructions */
-#ifdef CONFIG_64BIT
-# define i_LW(buf, rs, rt, off) i_ld(buf, rs, rt, off)
-# define i_SW(buf, rs, rt, off) i_sd(buf, rs, rt, off)
-# define i_SLL(buf, rs, rt, sh) i_dsll(buf, rs, rt, sh)
-# define i_SRA(buf, rs, rt, sh) i_dsra(buf, rs, rt, sh)
-# define i_SRL(buf, rs, rt, sh) i_dsrl(buf, rs, rt, sh)
-# define i_MFC0(buf, rt, rd...) i_dmfc0(buf, rt, rd)
-# define i_MTC0(buf, rt, rd...) i_dmtc0(buf, rt, rd)
-# define i_ADDIU(buf, rs, rt, val) i_daddiu(buf, rs, rt, val)
-# define i_ADDU(buf, rs, rt, rd) i_daddu(buf, rs, rt, rd)
-# define i_SUBU(buf, rs, rt, rd) i_dsubu(buf, rs, rt, rd)
-# define i_LL(buf, rs, rt, off) i_lld(buf, rs, rt, off)
-# define i_SC(buf, rs, rt, off) i_scd(buf, rs, rt, off)
-#else
-# define i_LW(buf, rs, rt, off) i_lw(buf, rs, rt, off)
-# define i_SW(buf, rs, rt, off) i_sw(buf, rs, rt, off)
-# define i_SLL(buf, rs, rt, sh) i_sll(buf, rs, rt, sh)
-# define i_SRA(buf, rs, rt, sh) i_sra(buf, rs, rt, sh)
-# define i_SRL(buf, rs, rt, sh) i_srl(buf, rs, rt, sh)
-# define i_MFC0(buf, rt, rd...) i_mfc0(buf, rt, rd)
-# define i_MTC0(buf, rt, rd...) i_mtc0(buf, rt, rd)
-# define i_ADDIU(buf, rs, rt, val) i_addiu(buf, rs, rt, val)
-# define i_ADDU(buf, rs, rt, rd) i_addu(buf, rs, rt, rd)
-# define i_SUBU(buf, rs, rt, rd) i_subu(buf, rs, rt, rd)
-# define i_LL(buf, rs, rt, off) i_ll(buf, rs, rt, off)
-# define i_SC(buf, rs, rt, off) i_sc(buf, rs, rt, off)
-#endif
-
-#define i_b(buf, off) i_beq(buf, 0, 0, off)
-#define i_beqz(buf, rs, off) i_beq(buf, rs, 0, off)
-#define i_beqzl(buf, rs, off) i_beql(buf, rs, 0, off)
-#define i_bnez(buf, rs, off) i_bne(buf, rs, 0, off)
-#define i_bnezl(buf, rs, off) i_bnel(buf, rs, 0, off)
-#define i_move(buf, a, b) i_ADDU(buf, a, 0, b)
-#define i_nop(buf) i_sll(buf, 0, 0, 0)
-#define i_ssnop(buf) i_sll(buf, 0, 0, 1)
-#define i_ehb(buf) i_sll(buf, 0, 0, 3)
-
-static int __init __maybe_unused in_compat_space_p(long addr)
-{
-       /* Is this address in 32bit compat space? */
-#ifdef CONFIG_64BIT
-       return (((addr) & 0xffffffff00000000L) == 0xffffffff00000000L);
-#else
-       return 1;
+UASM_L_LA(_module_alloc)
 #endif
-}
-
-static int __init __maybe_unused rel_highest(long val)
-{
-#ifdef CONFIG_64BIT
-       return ((((val + 0x800080008000L) >> 48) & 0xffff) ^ 0x8000) - 0x8000;
-#else
-       return 0;
-#endif
-}
-
-static int __init __maybe_unused rel_higher(long val)
-{
-#ifdef CONFIG_64BIT
-       return ((((val + 0x80008000L) >> 32) & 0xffff) ^ 0x8000) - 0x8000;
-#else
-       return 0;
-#endif
-}
-
-static int __init rel_hi(long val)
-{
-       return ((((val + 0x8000L) >> 16) & 0xffff) ^ 0x8000) - 0x8000;
-}
-
-static int __init rel_lo(long val)
-{
-       return ((val & 0xffff) ^ 0x8000) - 0x8000;
-}
-
-static void __init i_LA_mostly(u32 **buf, unsigned int rs, long addr)
-{
-       if (!in_compat_space_p(addr)) {
-               i_lui(buf, rs, rel_highest(addr));
-               if (rel_higher(addr))
-                       i_daddiu(buf, rs, rs, rel_higher(addr));
-               if (rel_hi(addr)) {
-                       i_dsll(buf, rs, rs, 16);
-                       i_daddiu(buf, rs, rs, rel_hi(addr));
-                       i_dsll(buf, rs, rs, 16);
-               } else
-                       i_dsll32(buf, rs, rs, 0);
-       } else
-               i_lui(buf, rs, rel_hi(addr));
-}
-
-static void __init __maybe_unused i_LA(u32 **buf, unsigned int rs, long addr)
-{
-       i_LA_mostly(buf, rs, addr);
-       if (rel_lo(addr)) {
-               if (!in_compat_space_p(addr))
-                       i_daddiu(buf, rs, rs, rel_lo(addr));
-               else
-                       i_addiu(buf, rs, rs, rel_lo(addr));
-       }
-}
-
-/*
- * handle relocations
- */
-
-struct reloc {
-       u32 *addr;
-       unsigned int type;
-       enum label_id lab;
-};
-
-static void __init r_mips_pc16(struct reloc **rel, u32 *addr,
-                              enum label_id l)
-{
-       (*rel)->addr = addr;
-       (*rel)->type = R_MIPS_PC16;
-       (*rel)->lab = l;
-       (*rel)++;
-}
-
-static inline void __resolve_relocs(struct reloc *rel, struct label *lab)
-{
-       long laddr = (long)lab->addr;
-       long raddr = (long)rel->addr;
-
-       switch (rel->type) {
-       case R_MIPS_PC16:
-               *rel->addr |= build_bimm(laddr - (raddr + 4));
-               break;
-
-       default:
-               panic("Unsupported TLB synthesizer relocation %d",
-                     rel->type);
-       }
-}
-
-static void __init resolve_relocs(struct reloc *rel, struct label *lab)
-{
-       struct label *l;
-
-       for (; rel->lab != label_invalid; rel++)
-               for (l = lab; l->lab != label_invalid; l++)
-                       if (rel->lab == l->lab)
-                               __resolve_relocs(rel, l);
-}
-
-static void __init move_relocs(struct reloc *rel, u32 *first, u32 *end,
-                              long off)
-{
-       for (; rel->lab != label_invalid; rel++)
-               if (rel->addr >= first && rel->addr < end)
-                       rel->addr += off;
-}
-
-static void __init move_labels(struct label *lab, u32 *first, u32 *end,
-                              long off)
-{
-       for (; lab->lab != label_invalid; lab++)
-               if (lab->addr >= first && lab->addr < end)
-                       lab->addr += off;
-}
-
-static void __init copy_handler(struct reloc *rel, struct label *lab,
-                               u32 *first, u32 *end, u32 *target)
-{
-       long off = (long)(target - first);
-
-       memcpy(target, first, (end - first) * sizeof(u32));
-
-       move_relocs(rel, first, end, off);
-       move_labels(lab, first, end, off);
-}
-
-static int __init __maybe_unused insn_has_bdelay(struct reloc *rel,
-                                                      u32 *addr)
-{
-       for (; rel->lab != label_invalid; rel++) {
-               if (rel->addr == addr
-                   && (rel->type == R_MIPS_PC16
-                       || rel->type == R_MIPS_26))
-                       return 1;
-       }
-
-       return 0;
-}
-
-/* convenience functions for labeled branches */
-static void __init __maybe_unused
-       il_bltz(u32 **p, struct reloc **r, unsigned int reg, enum label_id l)
-{
-       r_mips_pc16(r, *p, l);
-       i_bltz(p, reg, 0);
-}
-
-static void __init __maybe_unused il_b(u32 **p, struct reloc **r,
-                                            enum label_id l)
-{
-       r_mips_pc16(r, *p, l);
-       i_b(p, 0);
-}
-
-static void __init il_beqz(u32 **p, struct reloc **r, unsigned int reg,
-                   enum label_id l)
-{
-       r_mips_pc16(r, *p, l);
-       i_beqz(p, reg, 0);
-}
-
-static void __init __maybe_unused
-il_beqzl(u32 **p, struct reloc **r, unsigned int reg, enum label_id l)
-{
-       r_mips_pc16(r, *p, l);
-       i_beqzl(p, reg, 0);
-}
-
-static void __init il_bnez(u32 **p, struct reloc **r, unsigned int reg,
-                   enum label_id l)
-{
-       r_mips_pc16(r, *p, l);
-       i_bnez(p, reg, 0);
-}
-
-static void __init il_bgezl(u32 **p, struct reloc **r, unsigned int reg,
-                    enum label_id l)
-{
-       r_mips_pc16(r, *p, l);
-       i_bgezl(p, reg, 0);
-}
-
-static void __init __maybe_unused
-il_bgez(u32 **p, struct reloc **r, unsigned int reg, enum label_id l)
-{
-       r_mips_pc16(r, *p, l);
-       i_bgez(p, reg, 0);
-}
+UASM_L_LA(_vmalloc)
+UASM_L_LA(_vmalloc_done)
+UASM_L_LA(_tlbw_hazard)
+UASM_L_LA(_split)
+UASM_L_LA(_nopage_tlbl)
+UASM_L_LA(_nopage_tlbs)
+UASM_L_LA(_nopage_tlbm)
+UASM_L_LA(_smp_pgtable_change)
+UASM_L_LA(_r3000_write_probe_fail)
 
 /*
  * For debug purposes.
@@ -752,9 +131,9 @@ static inline void dump_handler(const u32 *handler, int count)
 #define C0_XCONTEXT    20, 0
 
 #ifdef CONFIG_64BIT
-# define GET_CONTEXT(buf, reg) i_MFC0(buf, reg, C0_XCONTEXT)
+# define GET_CONTEXT(buf, reg) UASM_i_MFC0(buf, reg, C0_XCONTEXT)
 #else
-# define GET_CONTEXT(buf, reg) i_MFC0(buf, reg, C0_CONTEXT)
+# define GET_CONTEXT(buf, reg) UASM_i_MFC0(buf, reg, C0_CONTEXT)
 #endif
 
 /* The worst case length of the handler is around 18 instructions for
@@ -768,8 +147,8 @@ static inline void dump_handler(const u32 *handler, int count)
 static u32 tlb_handler[128] __initdata;
 
 /* simply assume worst case size for labels and relocs */
-static struct label labels[128] __initdata;
-static struct reloc relocs[128] __initdata;
+static struct uasm_label labels[128] __initdata;
+static struct uasm_reloc relocs[128] __initdata;
 
 /*
  * The R3000 TLB handler is simple.
@@ -782,29 +161,29 @@ static void __init build_r3000_tlb_refill_handler(void)
        memset(tlb_handler, 0, sizeof(tlb_handler));
        p = tlb_handler;
 
-       i_mfc0(&p, K0, C0_BADVADDR);
-       i_lui(&p, K1, rel_hi(pgdc)); /* cp0 delay */
-       i_lw(&p, K1, rel_lo(pgdc), K1);
-       i_srl(&p, K0, K0, 22); /* load delay */
-       i_sll(&p, K0, K0, 2);
-       i_addu(&p, K1, K1, K0);
-       i_mfc0(&p, K0, C0_CONTEXT);
-       i_lw(&p, K1, 0, K1); /* cp0 delay */
-       i_andi(&p, K0, K0, 0xffc); /* load delay */
-       i_addu(&p, K1, K1, K0);
-       i_lw(&p, K0, 0, K1);
-       i_nop(&p); /* load delay */
-       i_mtc0(&p, K0, C0_ENTRYLO0);
-       i_mfc0(&p, K1, C0_EPC); /* cp0 delay */
-       i_tlbwr(&p); /* cp0 delay */
-       i_jr(&p, K1);
-       i_rfe(&p); /* branch delay */
+       uasm_i_mfc0(&p, K0, C0_BADVADDR);
+       uasm_i_lui(&p, K1, uasm_rel_hi(pgdc)); /* cp0 delay */
+       uasm_i_lw(&p, K1, uasm_rel_lo(pgdc), K1);
+       uasm_i_srl(&p, K0, K0, 22); /* load delay */
+       uasm_i_sll(&p, K0, K0, 2);
+       uasm_i_addu(&p, K1, K1, K0);
+       uasm_i_mfc0(&p, K0, C0_CONTEXT);
+       uasm_i_lw(&p, K1, 0, K1); /* cp0 delay */
+       uasm_i_andi(&p, K0, K0, 0xffc); /* load delay */
+       uasm_i_addu(&p, K1, K1, K0);
+       uasm_i_lw(&p, K0, 0, K1);
+       uasm_i_nop(&p); /* load delay */
+       uasm_i_mtc0(&p, K0, C0_ENTRYLO0);
+       uasm_i_mfc0(&p, K1, C0_EPC); /* cp0 delay */
+       uasm_i_tlbwr(&p); /* cp0 delay */
+       uasm_i_jr(&p, K1);
+       uasm_i_rfe(&p); /* branch delay */
 
        if (p > tlb_handler + 32)
                panic("TLB refill handler space exceeded");
 
-       pr_info("Synthesized TLB refill handler (%u instructions).\n",
-               (unsigned int)(p - tlb_handler));
+       pr_debug("Wrote TLB refill handler (%u instructions).\n",
+                (unsigned int)(p - tlb_handler));
 
        memcpy((void *)ebase, tlb_handler, 0x80);
 
@@ -850,12 +229,12 @@ static void __init __maybe_unused build_tlb_probe_entry(u32 **p)
        case CPU_R5000:
        case CPU_R5000A:
        case CPU_NEVADA:
-               i_nop(p);
-               i_tlbp(p);
+               uasm_i_nop(p);
+               uasm_i_tlbp(p);
                break;
 
        default:
-               i_tlbp(p);
+               uasm_i_tlbp(p);
                break;
        }
 }
@@ -866,19 +245,19 @@ static void __init __maybe_unused build_tlb_probe_entry(u32 **p)
  */
 enum tlb_write_entry { tlb_random, tlb_indexed };
 
-static void __init build_tlb_write_entry(u32 **p, struct label **l,
-                                        struct reloc **r,
+static void __init build_tlb_write_entry(u32 **p, struct uasm_label **l,
+                                        struct uasm_reloc **r,
                                         enum tlb_write_entry wmode)
 {
        void(*tlbw)(u32 **) = NULL;
 
        switch (wmode) {
-       case tlb_random: tlbw = i_tlbwr; break;
-       case tlb_indexed: tlbw = i_tlbwi; break;
+       case tlb_random: tlbw = uasm_i_tlbwr; break;
+       case tlb_indexed: tlbw = uasm_i_tlbwi; break;
        }
 
        if (cpu_has_mips_r2) {
-               i_ehb(p);
+               uasm_i_ehb(p);
                tlbw(p);
                return;
        }
@@ -894,19 +273,19 @@ static void __init build_tlb_write_entry(u32 **p, struct label **l,
                 * This branch uses up a mtc0 hazard nop slot and saves
                 * two nops after the tlbw instruction.
                 */
-               il_bgezl(p, r, 0, label_tlbw_hazard);
+               uasm_il_bgezl(p, r, 0, label_tlbw_hazard);
                tlbw(p);
-               l_tlbw_hazard(l, *p);
-               i_nop(p);
+               uasm_l_tlbw_hazard(l, *p);
+               uasm_i_nop(p);
                break;
 
        case CPU_R4600:
        case CPU_R4700:
        case CPU_R5000:
        case CPU_R5000A:
-               i_nop(p);
+               uasm_i_nop(p);
                tlbw(p);
-               i_nop(p);
+               uasm_i_nop(p);
                break;
 
        case CPU_R4300:
@@ -920,7 +299,7 @@ static void __init build_tlb_write_entry(u32 **p, struct label **l,
        case CPU_AU1210:
        case CPU_AU1250:
        case CPU_PR4450:
-               i_nop(p);
+               uasm_i_nop(p);
                tlbw(p);
                break;
 
@@ -937,26 +316,26 @@ static void __init build_tlb_write_entry(u32 **p, struct label **l,
        case CPU_BCM4710:
        case CPU_LOONGSON2:
                if (m4kc_tlbp_war())
-                       i_nop(p);
+                       uasm_i_nop(p);
                tlbw(p);
                break;
 
        case CPU_NEVADA:
-               i_nop(p); /* QED specifies 2 nops hazard */
+               uasm_i_nop(p); /* QED specifies 2 nops hazard */
                /*
                 * This branch uses up a mtc0 hazard nop slot and saves
                 * a nop after the tlbw instruction.
                 */
-               il_bgezl(p, r, 0, label_tlbw_hazard);
+               uasm_il_bgezl(p, r, 0, label_tlbw_hazard);
                tlbw(p);
-               l_tlbw_hazard(l, *p);
+               uasm_l_tlbw_hazard(l, *p);
                break;
 
        case CPU_RM7000:
-               i_nop(p);
-               i_nop(p);
-               i_nop(p);
-               i_nop(p);
+               uasm_i_nop(p);
+               uasm_i_nop(p);
+               uasm_i_nop(p);
+               uasm_i_nop(p);
                tlbw(p);
                break;
 
@@ -967,15 +346,15 @@ static void __init build_tlb_write_entry(u32 **p, struct label **l,
                 * cpu cycles and use for data translations should not occur
                 * for 3 cpu cycles.
                 */
-               i_ssnop(p);
-               i_ssnop(p);
-               i_ssnop(p);
-               i_ssnop(p);
+               uasm_i_ssnop(p);
+               uasm_i_ssnop(p);
+               uasm_i_ssnop(p);
+               uasm_i_ssnop(p);
                tlbw(p);
-               i_ssnop(p);
-               i_ssnop(p);
-               i_ssnop(p);
-               i_ssnop(p);
+               uasm_i_ssnop(p);
+               uasm_i_ssnop(p);
+               uasm_i_ssnop(p);
+               uasm_i_ssnop(p);
                break;
 
        case CPU_VR4111:
@@ -983,18 +362,18 @@ static void __init build_tlb_write_entry(u32 **p, struct label **l,
        case CPU_VR4122:
        case CPU_VR4181:
        case CPU_VR4181A:
-               i_nop(p);
-               i_nop(p);
+               uasm_i_nop(p);
+               uasm_i_nop(p);
                tlbw(p);
-               i_nop(p);
-               i_nop(p);
+               uasm_i_nop(p);
+               uasm_i_nop(p);
                break;
 
        case CPU_VR4131:
        case CPU_VR4133:
        case CPU_R5432:
-               i_nop(p);
-               i_nop(p);
+               uasm_i_nop(p);
+               uasm_i_nop(p);
                tlbw(p);
                break;
 
@@ -1011,7 +390,7 @@ static void __init build_tlb_write_entry(u32 **p, struct label **l,
  * TMP will be clobbered, PTR will hold the pmd entry.
  */
 static void __init
-build_get_pmde64(u32 **p, struct label **l, struct reloc **r,
+build_get_pmde64(u32 **p, struct uasm_label **l, struct uasm_reloc **r,
                 unsigned int tmp, unsigned int ptr)
 {
        long pgdc = (long)pgd_current;
@@ -1019,52 +398,52 @@ build_get_pmde64(u32 **p, struct label **l, struct reloc **r,
        /*
         * The vmalloc handling is not in the hotpath.
         */
-       i_dmfc0(p, tmp, C0_BADVADDR);
+       uasm_i_dmfc0(p, tmp, C0_BADVADDR);
 #ifdef MODULE_START
-       il_bltz(p, r, tmp, label_module_alloc);
+       uasm_il_bltz(p, r, tmp, label_module_alloc);
 #else
-       il_bltz(p, r, tmp, label_vmalloc);
+       uasm_il_bltz(p, r, tmp, label_vmalloc);
 #endif
-       /* No i_nop needed here, since the next insn doesn't touch TMP. */
+       /* No uasm_i_nop needed here, since the next insn doesn't touch TMP. */
 
 #ifdef CONFIG_SMP
 # ifdef  CONFIG_MIPS_MT_SMTC
        /*
         * SMTC uses TCBind value as "CPU" index
         */
-       i_mfc0(p, ptr, C0_TCBIND);
-       i_dsrl(p, ptr, ptr, 19);
+       uasm_i_mfc0(p, ptr, C0_TCBIND);
+       uasm_i_dsrl(p, ptr, ptr, 19);
 # else
        /*
         * 64 bit SMP running in XKPHYS has smp_processor_id() << 3
         * stored in CONTEXT.
         */
-       i_dmfc0(p, ptr, C0_CONTEXT);
-       i_dsrl(p, ptr, ptr, 23);
+       uasm_i_dmfc0(p, ptr, C0_CONTEXT);
+       uasm_i_dsrl(p, ptr, ptr, 23);
 #endif
-       i_LA_mostly(p, tmp, pgdc);
-       i_daddu(p, ptr, ptr, tmp);
-       i_dmfc0(p, tmp, C0_BADVADDR);
-       i_ld(p, ptr, rel_lo(pgdc), ptr);
+       UASM_i_LA_mostly(p, tmp, pgdc);
+       uasm_i_daddu(p, ptr, ptr, tmp);
+       uasm_i_dmfc0(p, tmp, C0_BADVADDR);
+       uasm_i_ld(p, ptr, uasm_rel_lo(pgdc), ptr);
 #else
-       i_LA_mostly(p, ptr, pgdc);
-       i_ld(p, ptr, rel_lo(pgdc), ptr);
+       UASM_i_LA_mostly(p, ptr, pgdc);
+       uasm_i_ld(p, ptr, uasm_rel_lo(pgdc), ptr);
 #endif
 
-       l_vmalloc_done(l, *p);
+       uasm_l_vmalloc_done(l, *p);
 
        if (PGDIR_SHIFT - 3 < 32)               /* get pgd offset in bytes */
-               i_dsrl(p, tmp, tmp, PGDIR_SHIFT-3);
+               uasm_i_dsrl(p, tmp, tmp, PGDIR_SHIFT-3);
        else
-               i_dsrl32(p, tmp, tmp, PGDIR_SHIFT - 3 - 32);
-
-       i_andi(p, tmp, tmp, (PTRS_PER_PGD - 1)<<3);
-       i_daddu(p, ptr, ptr, tmp); /* add in pgd offset */
-       i_dmfc0(p, tmp, C0_BADVADDR); /* get faulting address */
-       i_ld(p, ptr, 0, ptr); /* get pmd pointer */
-       i_dsrl(p, tmp, tmp, PMD_SHIFT-3); /* get pmd offset in bytes */
-       i_andi(p, tmp, tmp, (PTRS_PER_PMD - 1)<<3);
-       i_daddu(p, ptr, ptr, tmp); /* add in pmd offset */
+               uasm_i_dsrl32(p, tmp, tmp, PGDIR_SHIFT - 3 - 32);
+
+       uasm_i_andi(p, tmp, tmp, (PTRS_PER_PGD - 1)<<3);
+       uasm_i_daddu(p, ptr, ptr, tmp); /* add in pgd offset */
+       uasm_i_dmfc0(p, tmp, C0_BADVADDR); /* get faulting address */
+       uasm_i_ld(p, ptr, 0, ptr); /* get pmd pointer */
+       uasm_i_dsrl(p, tmp, tmp, PMD_SHIFT-3); /* get pmd offset in bytes */
+       uasm_i_andi(p, tmp, tmp, (PTRS_PER_PMD - 1)<<3);
+       uasm_i_daddu(p, ptr, ptr, tmp); /* add in pmd offset */
 }
 
 /*
@@ -1072,7 +451,7 @@ build_get_pmde64(u32 **p, struct label **l, struct reloc **r,
  * PTR will hold the pgd for vmalloc.
  */
 static void __init
-build_get_pgd_vmalloc64(u32 **p, struct label **l, struct reloc **r,
+build_get_pgd_vmalloc64(u32 **p, struct uasm_label **l, struct uasm_reloc **r,
                        unsigned int bvaddr, unsigned int ptr)
 {
        long swpd = (long)swapper_pg_dir;
@@ -1080,58 +459,60 @@ build_get_pgd_vmalloc64(u32 **p, struct label **l, struct reloc **r,
 #ifdef MODULE_START
        long modd = (long)module_pg_dir;
 
-       l_module_alloc(l, *p);
+       uasm_l_module_alloc(l, *p);
        /*
         * Assumption:
         * VMALLOC_START >= 0xc000000000000000UL
         * MODULE_START >= 0xe000000000000000UL
         */
-       i_SLL(p, ptr, bvaddr, 2);
-       il_bgez(p, r, ptr, label_vmalloc);
+       UASM_i_SLL(p, ptr, bvaddr, 2);
+       uasm_il_bgez(p, r, ptr, label_vmalloc);
 
-       if (in_compat_space_p(MODULE_START) && !rel_lo(MODULE_START)) {
-               i_lui(p, ptr, rel_hi(MODULE_START)); /* delay slot */
+       if (uasm_in_compat_space_p(MODULE_START) &&
+           !uasm_rel_lo(MODULE_START)) {
+               uasm_i_lui(p, ptr, uasm_rel_hi(MODULE_START)); /* delay slot */
        } else {
                /* unlikely configuration */
-               i_nop(p); /* delay slot */
-               i_LA(p, ptr, MODULE_START);
+               uasm_i_nop(p); /* delay slot */
+               UASM_i_LA(p, ptr, MODULE_START);
        }
-       i_dsubu(p, bvaddr, bvaddr, ptr);
+       uasm_i_dsubu(p, bvaddr, bvaddr, ptr);
 
-       if (in_compat_space_p(modd) && !rel_lo(modd)) {
-               il_b(p, r, label_vmalloc_done);
-               i_lui(p, ptr, rel_hi(modd));
+       if (uasm_in_compat_space_p(modd) && !uasm_rel_lo(modd)) {
+               uasm_il_b(p, r, label_vmalloc_done);
+               uasm_i_lui(p, ptr, uasm_rel_hi(modd));
        } else {
-               i_LA_mostly(p, ptr, modd);
-               il_b(p, r, label_vmalloc_done);
-               if (in_compat_space_p(modd))
-                       i_addiu(p, ptr, ptr, rel_lo(modd));
+               UASM_i_LA_mostly(p, ptr, modd);
+               uasm_il_b(p, r, label_vmalloc_done);
+               if (uasm_in_compat_space_p(modd))
+                       uasm_i_addiu(p, ptr, ptr, uasm_rel_lo(modd));
                else
-                       i_daddiu(p, ptr, ptr, rel_lo(modd));
+                       uasm_i_daddiu(p, ptr, ptr, uasm_rel_lo(modd));
        }
 
-       l_vmalloc(l, *p);
-       if (in_compat_space_p(MODULE_START) && !rel_lo(MODULE_START) &&
+       uasm_l_vmalloc(l, *p);
+       if (uasm_in_compat_space_p(MODULE_START) &&
+           !uasm_rel_lo(MODULE_START) &&
            MODULE_START << 32 == VMALLOC_START)
-               i_dsll32(p, ptr, ptr, 0);       /* typical case */
+               uasm_i_dsll32(p, ptr, ptr, 0);  /* typical case */
        else
-               i_LA(p, ptr, VMALLOC_START);
+               UASM_i_LA(p, ptr, VMALLOC_START);
 #else
-       l_vmalloc(l, *p);
-       i_LA(p, ptr, VMALLOC_START);
+       uasm_l_vmalloc(l, *p);
+       UASM_i_LA(p, ptr, VMALLOC_START);
 #endif
-       i_dsubu(p, bvaddr, bvaddr, ptr);
+       uasm_i_dsubu(p, bvaddr, bvaddr, ptr);
 
-       if (in_compat_space_p(swpd) && !rel_lo(swpd)) {
-               il_b(p, r, label_vmalloc_done);
-               i_lui(p, ptr, rel_hi(swpd));
+       if (uasm_in_compat_space_p(swpd) && !uasm_rel_lo(swpd)) {
+               uasm_il_b(p, r, label_vmalloc_done);
+               uasm_i_lui(p, ptr, uasm_rel_hi(swpd));
        } else {
-               i_LA_mostly(p, ptr, swpd);
-               il_b(p, r, label_vmalloc_done);
-               if (in_compat_space_p(swpd))
-                       i_addiu(p, ptr, ptr, rel_lo(swpd));
+               UASM_i_LA_mostly(p, ptr, swpd);
+               uasm_il_b(p, r, label_vmalloc_done);
+               if (uasm_in_compat_space_p(swpd))
+                       uasm_i_addiu(p, ptr, ptr, uasm_rel_lo(swpd));
                else
-                       i_daddiu(p, ptr, ptr, rel_lo(swpd));
+                       uasm_i_daddiu(p, ptr, ptr, uasm_rel_lo(swpd));
        }
 }
 
@@ -1152,26 +533,26 @@ build_get_pgde32(u32 **p, unsigned int tmp, unsigned int ptr)
        /*
         * SMTC uses TCBind value as "CPU" index
         */
-       i_mfc0(p, ptr, C0_TCBIND);
-       i_LA_mostly(p, tmp, pgdc);
-       i_srl(p, ptr, ptr, 19);
+       uasm_i_mfc0(p, ptr, C0_TCBIND);
+       UASM_i_LA_mostly(p, tmp, pgdc);
+       uasm_i_srl(p, ptr, ptr, 19);
 #else
        /*
         * smp_processor_id() << 3 is stored in CONTEXT.
          */
-       i_mfc0(p, ptr, C0_CONTEXT);
-       i_LA_mostly(p, tmp, pgdc);
-       i_srl(p, ptr, ptr, 23);
+       uasm_i_mfc0(p, ptr, C0_CONTEXT);
+       UASM_i_LA_mostly(p, tmp, pgdc);
+       uasm_i_srl(p, ptr, ptr, 23);
 #endif
-       i_addu(p, ptr, tmp, ptr);
+       uasm_i_addu(p, ptr, tmp, ptr);
 #else
-       i_LA_mostly(p, ptr, pgdc);
+       UASM_i_LA_mostly(p, ptr, pgdc);
 #endif
-       i_mfc0(p, tmp, C0_BADVADDR); /* get faulting address */
-       i_lw(p, ptr, rel_lo(pgdc), ptr);
-       i_srl(p, tmp, tmp, PGDIR_SHIFT); /* get pgd only bits */
-       i_sll(p, tmp, tmp, PGD_T_LOG2);
-       i_addu(p, ptr, ptr, tmp); /* add in pgd offset */
+       uasm_i_mfc0(p, tmp, C0_BADVADDR); /* get faulting address */
+       uasm_i_lw(p, ptr, uasm_rel_lo(pgdc), ptr);
+       uasm_i_srl(p, tmp, tmp, PGDIR_SHIFT); /* get pgd only bits */
+       uasm_i_sll(p, tmp, tmp, PGD_T_LOG2);
+       uasm_i_addu(p, ptr, ptr, tmp); /* add in pgd offset */
 }
 
 #endif /* !CONFIG_64BIT */
@@ -1198,8 +579,8 @@ static void __init build_adjust_context(u32 **p, unsigned int ctx)
        }
 
        if (shift)
-               i_SRL(p, ctx, ctx, shift);
-       i_andi(p, ctx, ctx, mask);
+               UASM_i_SRL(p, ctx, ctx, shift);
+       uasm_i_andi(p, ctx, ctx, mask);
 }
 
 static void __init build_get_ptep(u32 **p, unsigned int tmp, unsigned int ptr)
@@ -1213,18 +594,18 @@ static void __init build_get_ptep(u32 **p, unsigned int tmp, unsigned int ptr)
         */
        switch (current_cpu_type()) {
        case CPU_NEVADA:
-               i_LW(p, ptr, 0, ptr);
+               UASM_i_LW(p, ptr, 0, ptr);
                GET_CONTEXT(p, tmp); /* get context reg */
                break;
 
        default:
                GET_CONTEXT(p, tmp); /* get context reg */
-               i_LW(p, ptr, 0, ptr);
+               UASM_i_LW(p, ptr, 0, ptr);
                break;
        }
 
        build_adjust_context(p, tmp);
-       i_ADDU(p, ptr, ptr, tmp); /* add in offset */
+       UASM_i_ADDU(p, ptr, ptr, tmp); /* add in offset */
 }
 
 static void __init build_update_entries(u32 **p, unsigned int tmp,
@@ -1236,45 +617,45 @@ static void __init build_update_entries(u32 **p, unsigned int tmp,
         */
 #ifdef CONFIG_64BIT_PHYS_ADDR
        if (cpu_has_64bits) {
-               i_ld(p, tmp, 0, ptep); /* get even pte */
-               i_ld(p, ptep, sizeof(pte_t), ptep); /* get odd pte */
-               i_dsrl(p, tmp, tmp, 6); /* convert to entrylo0 */
-               i_mtc0(p, tmp, C0_ENTRYLO0); /* load it */
-               i_dsrl(p, ptep, ptep, 6); /* convert to entrylo1 */
-               i_mtc0(p, ptep, C0_ENTRYLO1); /* load it */
+               uasm_i_ld(p, tmp, 0, ptep); /* get even pte */
+               uasm_i_ld(p, ptep, sizeof(pte_t), ptep); /* get odd pte */
+               uasm_i_dsrl(p, tmp, tmp, 6); /* convert to entrylo0 */
+               uasm_i_mtc0(p, tmp, C0_ENTRYLO0); /* load it */
+               uasm_i_dsrl(p, ptep, ptep, 6); /* convert to entrylo1 */
+               uasm_i_mtc0(p, ptep, C0_ENTRYLO1); /* load it */
        } else {
                int pte_off_even = sizeof(pte_t) / 2;
                int pte_off_odd = pte_off_even + sizeof(pte_t);
 
                /* The pte entries are pre-shifted */
-               i_lw(p, tmp, pte_off_even, ptep); /* get even pte */
-               i_mtc0(p, tmp, C0_ENTRYLO0); /* load it */
-               i_lw(p, ptep, pte_off_odd, ptep); /* get odd pte */
-               i_mtc0(p, ptep, C0_ENTRYLO1); /* load it */
+               uasm_i_lw(p, tmp, pte_off_even, ptep); /* get even pte */
+               uasm_i_mtc0(p, tmp, C0_ENTRYLO0); /* load it */
+               uasm_i_lw(p, ptep, pte_off_odd, ptep); /* get odd pte */
+               uasm_i_mtc0(p, ptep, C0_ENTRYLO1); /* load it */
        }
 #else
-       i_LW(p, tmp, 0, ptep); /* get even pte */
-       i_LW(p, ptep, sizeof(pte_t), ptep); /* get odd pte */
+       UASM_i_LW(p, tmp, 0, ptep); /* get even pte */
+       UASM_i_LW(p, ptep, sizeof(pte_t), ptep); /* get odd pte */
        if (r45k_bvahwbug())
                build_tlb_probe_entry(p);
-       i_SRL(p, tmp, tmp, 6); /* convert to entrylo0 */
+       UASM_i_SRL(p, tmp, tmp, 6); /* convert to entrylo0 */
        if (r4k_250MHZhwbug())
-               i_mtc0(p, 0, C0_ENTRYLO0);
-       i_mtc0(p, tmp, C0_ENTRYLO0); /* load it */
-       i_SRL(p, ptep, ptep, 6); /* convert to entrylo1 */
+               uasm_i_mtc0(p, 0, C0_ENTRYLO0);
+       uasm_i_mtc0(p, tmp, C0_ENTRYLO0); /* load it */
+       UASM_i_SRL(p, ptep, ptep, 6); /* convert to entrylo1 */
        if (r45k_bvahwbug())
-               i_mfc0(p, tmp, C0_INDEX);
+               uasm_i_mfc0(p, tmp, C0_INDEX);
        if (r4k_250MHZhwbug())
-               i_mtc0(p, 0, C0_ENTRYLO1);
-       i_mtc0(p, ptep, C0_ENTRYLO1); /* load it */
+               uasm_i_mtc0(p, 0, C0_ENTRYLO1);
+       uasm_i_mtc0(p, ptep, C0_ENTRYLO1); /* load it */
 #endif
 }
 
 static void __init build_r4000_tlb_refill_handler(void)
 {
        u32 *p = tlb_handler;
-       struct label *l = labels;
-       struct reloc *r = relocs;
+       struct uasm_label *l = labels;
+       struct uasm_reloc *r = relocs;
        u32 *f;
        unsigned int final_len;
 
@@ -1287,12 +668,12 @@ static void __init build_r4000_tlb_refill_handler(void)
         * create the plain linear handler
         */
        if (bcm1250_m3_war()) {
-               i_MFC0(&p, K0, C0_BADVADDR);
-               i_MFC0(&p, K1, C0_ENTRYHI);
-               i_xor(&p, K0, K0, K1);
-               i_SRL(&p, K0, K0, PAGE_SHIFT + 1);
-               il_bnez(&p, &r, K0, label_leave);
-               /* No need for i_nop */
+               UASM_i_MFC0(&p, K0, C0_BADVADDR);
+               UASM_i_MFC0(&p, K1, C0_ENTRYHI);
+               uasm_i_xor(&p, K0, K0, K1);
+               UASM_i_SRL(&p, K0, K0, PAGE_SHIFT + 1);
+               uasm_il_bnez(&p, &r, K0, label_leave);
+               /* No need for uasm_i_nop */
        }
 
 #ifdef CONFIG_64BIT
@@ -1304,8 +685,8 @@ static void __init build_r4000_tlb_refill_handler(void)
        build_get_ptep(&p, K0, K1);
        build_update_entries(&p, K0, K1);
        build_tlb_write_entry(&p, &l, &r, tlb_random);
-       l_leave(&l, p);
-       i_eret(&p); /* return from trap */
+       uasm_l_leave(&l, p);
+       uasm_i_eret(&p); /* return from trap */
 
 #ifdef CONFIG_64BIT
        build_get_pgd_vmalloc64(&p, &l, &r, K0, K1);
@@ -1325,7 +706,7 @@ static void __init build_r4000_tlb_refill_handler(void)
 #else
        if (((p - tlb_handler) > 63)
            || (((p - tlb_handler) > 61)
-               && insn_has_bdelay(relocs, tlb_handler + 29)))
+               && uasm_insn_has_bdelay(relocs, tlb_handler + 29)))
                panic("TLB refill handler space exceeded");
 #endif
 
@@ -1335,13 +716,13 @@ static void __init build_r4000_tlb_refill_handler(void)
 #if defined(CONFIG_32BIT) || defined(CONFIG_CPU_LOONGSON2)
        f = final_handler;
        /* Simplest case, just copy the handler. */
-       copy_handler(relocs, labels, tlb_handler, p, f);
+       uasm_copy_handler(relocs, labels, tlb_handler, p, f);
        final_len = p - tlb_handler;
 #else /* CONFIG_64BIT */
        f = final_handler + 32;
        if ((p - tlb_handler) <= 32) {
                /* Just copy the handler. */
-               copy_handler(relocs, labels, tlb_handler, p, f);
+               uasm_copy_handler(relocs, labels, tlb_handler, p, f);
                final_len = p - tlb_handler;
        } else {
                u32 *split = tlb_handler + 30;
@@ -1349,34 +730,34 @@ static void __init build_r4000_tlb_refill_handler(void)
                /*
                 * Find the split point.
                 */
-               if (insn_has_bdelay(relocs, split - 1))
+               if (uasm_insn_has_bdelay(relocs, split - 1))
                        split--;
 
                /* Copy first part of the handler. */
-               copy_handler(relocs, labels, tlb_handler, split, f);
+               uasm_copy_handler(relocs, labels, tlb_handler, split, f);
                f += split - tlb_handler;
 
                /* Insert branch. */
-               l_split(&l, final_handler);
-               il_b(&f, &r, label_split);
-               if (insn_has_bdelay(relocs, split))
-                       i_nop(&f);
+               uasm_l_split(&l, final_handler);
+               uasm_il_b(&f, &r, label_split);
+               if (uasm_insn_has_bdelay(relocs, split))
+                       uasm_i_nop(&f);
                else {
-                       copy_handler(relocs, labels, split, split + 1, f);
-                       move_labels(labels, f, f + 1, -1);
+                       uasm_copy_handler(relocs, labels, split, split + 1, f);
+                       uasm_move_labels(labels, f, f + 1, -1);
                        f++;
                        split++;
                }
 
                /* Copy the rest of the handler. */
-               copy_handler(relocs, labels, split, p, final_handler);
+               uasm_copy_handler(relocs, labels, split, p, final_handler);
                final_len = (f - (final_handler + 32)) + (p - split);
        }
 #endif /* CONFIG_64BIT */
 
-       resolve_relocs(relocs, labels);
-       pr_info("Synthesized TLB refill handler (%u instructions).\n",
-               final_len);
+       uasm_resolve_relocs(relocs, labels);
+       pr_debug("Wrote TLB refill handler (%u instructions).\n",
+                final_len);
 
        memcpy((void *)ebase, final_handler, 0x100);
 
@@ -1403,75 +784,75 @@ u32 handle_tlbs[FASTPATH_SIZE] __cacheline_aligned;
 u32 handle_tlbm[FASTPATH_SIZE] __cacheline_aligned;
 
 static void __init
-iPTE_LW(u32 **p, struct label **l, unsigned int pte, unsigned int ptr)
+iPTE_LW(u32 **p, struct uasm_label **l, unsigned int pte, unsigned int ptr)
 {
 #ifdef CONFIG_SMP
 # ifdef CONFIG_64BIT_PHYS_ADDR
        if (cpu_has_64bits)
-               i_lld(p, pte, 0, ptr);
+               uasm_i_lld(p, pte, 0, ptr);
        else
 # endif
-               i_LL(p, pte, 0, ptr);
+               UASM_i_LL(p, pte, 0, ptr);
 #else
 # ifdef CONFIG_64BIT_PHYS_ADDR
        if (cpu_has_64bits)
-               i_ld(p, pte, 0, ptr);
+               uasm_i_ld(p, pte, 0, ptr);
        else
 # endif
-               i_LW(p, pte, 0, ptr);
+               UASM_i_LW(p, pte, 0, ptr);
 #endif
 }
 
 static void __init
-iPTE_SW(u32 **p, struct reloc **r, unsigned int pte, unsigned int ptr,
+iPTE_SW(u32 **p, struct uasm_reloc **r, unsigned int pte, unsigned int ptr,
        unsigned int mode)
 {
 #ifdef CONFIG_64BIT_PHYS_ADDR
        unsigned int hwmode = mode & (_PAGE_VALID | _PAGE_DIRTY);
 #endif
 
-       i_ori(p, pte, pte, mode);
+       uasm_i_ori(p, pte, pte, mode);
 #ifdef CONFIG_SMP
 # ifdef CONFIG_64BIT_PHYS_ADDR
        if (cpu_has_64bits)
-               i_scd(p, pte, 0, ptr);
+               uasm_i_scd(p, pte, 0, ptr);
        else
 # endif
-               i_SC(p, pte, 0, ptr);
+               UASM_i_SC(p, pte, 0, ptr);
 
        if (r10000_llsc_war())
-               il_beqzl(p, r, pte, label_smp_pgtable_change);
+               uasm_il_beqzl(p, r, pte, label_smp_pgtable_change);
        else
-               il_beqz(p, r, pte, label_smp_pgtable_change);
+               uasm_il_beqz(p, r, pte, label_smp_pgtable_change);
 
 # ifdef CONFIG_64BIT_PHYS_ADDR
        if (!cpu_has_64bits) {
-               /* no i_nop needed */
-               i_ll(p, pte, sizeof(pte_t) / 2, ptr);
-               i_ori(p, pte, pte, hwmode);
-               i_sc(p, pte, sizeof(pte_t) / 2, ptr);
-               il_beqz(p, r, pte, label_smp_pgtable_change);
-               /* no i_nop needed */
-               i_lw(p, pte, 0, ptr);
+               /* no uasm_i_nop needed */
+               uasm_i_ll(p, pte, sizeof(pte_t) / 2, ptr);
+               uasm_i_ori(p, pte, pte, hwmode);
+               uasm_i_sc(p, pte, sizeof(pte_t) / 2, ptr);
+               uasm_il_beqz(p, r, pte, label_smp_pgtable_change);
+               /* no uasm_i_nop needed */
+               uasm_i_lw(p, pte, 0, ptr);
        } else
-               i_nop(p);
+               uasm_i_nop(p);
 # else
-       i_nop(p);
+       uasm_i_nop(p);
 # endif
 #else
 # ifdef CONFIG_64BIT_PHYS_ADDR
        if (cpu_has_64bits)
-               i_sd(p, pte, 0, ptr);
+               uasm_i_sd(p, pte, 0, ptr);
        else
 # endif
-               i_SW(p, pte, 0, ptr);
+               UASM_i_SW(p, pte, 0, ptr);
 
 # ifdef CONFIG_64BIT_PHYS_ADDR
        if (!cpu_has_64bits) {
-               i_lw(p, pte, sizeof(pte_t) / 2, ptr);
-               i_ori(p, pte, pte, hwmode);
-               i_sw(p, pte, sizeof(pte_t) / 2, ptr);
-               i_lw(p, pte, 0, ptr);
+               uasm_i_lw(p, pte, sizeof(pte_t) / 2, ptr);
+               uasm_i_ori(p, pte, pte, hwmode);
+               uasm_i_sw(p, pte, sizeof(pte_t) / 2, ptr);
+               uasm_i_lw(p, pte, 0, ptr);
        }
 # endif
 #endif
@@ -1483,18 +864,18 @@ iPTE_SW(u32 **p, struct reloc **r, unsigned int pte, unsigned int ptr,
  * with it's original value.
  */
 static void __init
-build_pte_present(u32 **p, struct label **l, struct reloc **r,
+build_pte_present(u32 **p, struct uasm_label **l, struct uasm_reloc **r,
                  unsigned int pte, unsigned int ptr, enum label_id lid)
 {
-       i_andi(p, pte, pte, _PAGE_PRESENT | _PAGE_READ);
-       i_xori(p, pte, pte, _PAGE_PRESENT | _PAGE_READ);
-       il_bnez(p, r, pte, lid);
+       uasm_i_andi(p, pte, pte, _PAGE_PRESENT | _PAGE_READ);
+       uasm_i_xori(p, pte, pte, _PAGE_PRESENT | _PAGE_READ);
+       uasm_il_bnez(p, r, pte, lid);
        iPTE_LW(p, l, pte, ptr);
 }
 
 /* Make PTE valid, store result in PTR. */
 static void __init
-build_make_valid(u32 **p, struct reloc **r, unsigned int pte,
+build_make_valid(u32 **p, struct uasm_reloc **r, unsigned int pte,
                 unsigned int ptr)
 {
        unsigned int mode = _PAGE_VALID | _PAGE_ACCESSED;
@@ -1507,12 +888,12 @@ build_make_valid(u32 **p, struct reloc **r, unsigned int pte,
  * restore PTE with value from PTR when done.
  */
 static void __init
-build_pte_writable(u32 **p, struct label **l, struct reloc **r,
+build_pte_writable(u32 **p, struct uasm_label **l, struct uasm_reloc **r,
                   unsigned int pte, unsigned int ptr, enum label_id lid)
 {
-       i_andi(p, pte, pte, _PAGE_PRESENT | _PAGE_WRITE);
-       i_xori(p, pte, pte, _PAGE_PRESENT | _PAGE_WRITE);
-       il_bnez(p, r, pte, lid);
+       uasm_i_andi(p, pte, pte, _PAGE_PRESENT | _PAGE_WRITE);
+       uasm_i_xori(p, pte, pte, _PAGE_PRESENT | _PAGE_WRITE);
+       uasm_il_bnez(p, r, pte, lid);
        iPTE_LW(p, l, pte, ptr);
 }
 
@@ -1520,7 +901,7 @@ build_pte_writable(u32 **p, struct label **l, struct reloc **r,
  * at PTR.
  */
 static void __init
-build_make_write(u32 **p, struct reloc **r, unsigned int pte,
+build_make_write(u32 **p, struct uasm_reloc **r, unsigned int pte,
                 unsigned int ptr)
 {
        unsigned int mode = (_PAGE_ACCESSED | _PAGE_MODIFIED | _PAGE_VALID
@@ -1534,11 +915,11 @@ build_make_write(u32 **p, struct reloc **r, unsigned int pte,
  * restore PTE with value from PTR when done.
  */
 static void __init
-build_pte_modifiable(u32 **p, struct label **l, struct reloc **r,
+build_pte_modifiable(u32 **p, struct uasm_label **l, struct uasm_reloc **r,
                     unsigned int pte, unsigned int ptr, enum label_id lid)
 {
-       i_andi(p, pte, pte, _PAGE_WRITE);
-       il_beqz(p, r, pte, lid);
+       uasm_i_andi(p, pte, pte, _PAGE_WRITE);
+       uasm_il_beqz(p, r, pte, lid);
        iPTE_LW(p, l, pte, ptr);
 }
 
@@ -1553,11 +934,11 @@ build_pte_modifiable(u32 **p, struct label **l, struct reloc **r,
 static void __init
 build_r3000_pte_reload_tlbwi(u32 **p, unsigned int pte, unsigned int tmp)
 {
-       i_mtc0(p, pte, C0_ENTRYLO0); /* cp0 delay */
-       i_mfc0(p, tmp, C0_EPC); /* cp0 delay */
-       i_tlbwi(p);
-       i_jr(p, tmp);
-       i_rfe(p); /* branch delay */
+       uasm_i_mtc0(p, pte, C0_ENTRYLO0); /* cp0 delay */
+       uasm_i_mfc0(p, tmp, C0_EPC); /* cp0 delay */
+       uasm_i_tlbwi(p);
+       uasm_i_jr(p, tmp);
+       uasm_i_rfe(p); /* branch delay */
 }
 
 /*
@@ -1567,20 +948,21 @@ build_r3000_pte_reload_tlbwi(u32 **p, unsigned int pte, unsigned int tmp)
  * kseg2 access, i.e. without refill.  Then it returns.
  */
 static void __init
-build_r3000_tlb_reload_write(u32 **p, struct label **l, struct reloc **r,
-                            unsigned int pte, unsigned int tmp)
-{
-       i_mfc0(p, tmp, C0_INDEX);
-       i_mtc0(p, pte, C0_ENTRYLO0); /* cp0 delay */
-       il_bltz(p, r, tmp, label_r3000_write_probe_fail); /* cp0 delay */
-       i_mfc0(p, tmp, C0_EPC); /* branch delay */
-       i_tlbwi(p); /* cp0 delay */
-       i_jr(p, tmp);
-       i_rfe(p); /* branch delay */
-       l_r3000_write_probe_fail(l, *p);
-       i_tlbwr(p); /* cp0 delay */
-       i_jr(p, tmp);
-       i_rfe(p); /* branch delay */
+build_r3000_tlb_reload_write(u32 **p, struct uasm_label **l,
+                            struct uasm_reloc **r, unsigned int pte,
+                            unsigned int tmp)
+{
+       uasm_i_mfc0(p, tmp, C0_INDEX);
+       uasm_i_mtc0(p, pte, C0_ENTRYLO0); /* cp0 delay */
+       uasm_il_bltz(p, r, tmp, label_r3000_write_probe_fail); /* cp0 delay */
+       uasm_i_mfc0(p, tmp, C0_EPC); /* branch delay */
+       uasm_i_tlbwi(p); /* cp0 delay */
+       uasm_i_jr(p, tmp);
+       uasm_i_rfe(p); /* branch delay */
+       uasm_l_r3000_write_probe_fail(l, *p);
+       uasm_i_tlbwr(p); /* cp0 delay */
+       uasm_i_jr(p, tmp);
+       uasm_i_rfe(p); /* branch delay */
 }
 
 static void __init
@@ -1589,25 +971,25 @@ build_r3000_tlbchange_handler_head(u32 **p, unsigned int pte,
 {
        long pgdc = (long)pgd_current;
 
-       i_mfc0(p, pte, C0_BADVADDR);
-       i_lui(p, ptr, rel_hi(pgdc)); /* cp0 delay */
-       i_lw(p, ptr, rel_lo(pgdc), ptr);
-       i_srl(p, pte, pte, 22); /* load delay */
-       i_sll(p, pte, pte, 2);
-       i_addu(p, ptr, ptr, pte);
-       i_mfc0(p, pte, C0_CONTEXT);
-       i_lw(p, ptr, 0, ptr); /* cp0 delay */
-       i_andi(p, pte, pte, 0xffc); /* load delay */
-       i_addu(p, ptr, ptr, pte);
-       i_lw(p, pte, 0, ptr);
-       i_tlbp(p); /* load delay */
+       uasm_i_mfc0(p, pte, C0_BADVADDR);
+       uasm_i_lui(p, ptr, uasm_rel_hi(pgdc)); /* cp0 delay */
+       uasm_i_lw(p, ptr, uasm_rel_lo(pgdc), ptr);
+       uasm_i_srl(p, pte, pte, 22); /* load delay */
+       uasm_i_sll(p, pte, pte, 2);
+       uasm_i_addu(p, ptr, ptr, pte);
+       uasm_i_mfc0(p, pte, C0_CONTEXT);
+       uasm_i_lw(p, ptr, 0, ptr); /* cp0 delay */
+       uasm_i_andi(p, pte, pte, 0xffc); /* load delay */
+       uasm_i_addu(p, ptr, ptr, pte);
+       uasm_i_lw(p, pte, 0, ptr);
+       uasm_i_tlbp(p); /* load delay */
 }
 
 static void __init build_r3000_tlb_load_handler(void)
 {
        u32 *p = handle_tlbl;
-       struct label *l = labels;
-       struct reloc *r = relocs;
+       struct uasm_label *l = labels;
+       struct uasm_reloc *r = relocs;
 
        memset(handle_tlbl, 0, sizeof(handle_tlbl));
        memset(labels, 0, sizeof(labels));
@@ -1615,20 +997,20 @@ static void __init build_r3000_tlb_load_handler(void)
 
        build_r3000_tlbchange_handler_head(&p, K0, K1);
        build_pte_present(&p, &l, &r, K0, K1, label_nopage_tlbl);
-       i_nop(&p); /* load delay */
+       uasm_i_nop(&p); /* load delay */
        build_make_valid(&p, &r, K0, K1);
        build_r3000_tlb_reload_write(&p, &l, &r, K0, K1);
 
-       l_nopage_tlbl(&l, p);
-       i_j(&p, (unsigned long)tlb_do_page_fault_0 & 0x0fffffff);
-       i_nop(&p);
+       uasm_l_nopage_tlbl(&l, p);
+       uasm_i_j(&p, (unsigned long)tlb_do_page_fault_0 & 0x0fffffff);
+       uasm_i_nop(&p);
 
        if ((p - handle_tlbl) > FASTPATH_SIZE)
                panic("TLB load handler fastpath space exceeded");
 
-       resolve_relocs(relocs, labels);
-       pr_info("Synthesized TLB load handler fastpath (%u instructions).\n",
-               (unsigned int)(p - handle_tlbl));
+       uasm_resolve_relocs(relocs, labels);
+       pr_debug("Wrote TLB load handler fastpath (%u instructions).\n",
+                (unsigned int)(p - handle_tlbl));
 
        dump_handler(handle_tlbl, ARRAY_SIZE(handle_tlbl));
 }
@@ -1636,8 +1018,8 @@ static void __init build_r3000_tlb_load_handler(void)
 static void __init build_r3000_tlb_store_handler(void)
 {
        u32 *p = handle_tlbs;
-       struct label *l = labels;
-       struct reloc *r = relocs;
+       struct uasm_label *l = labels;
+       struct uasm_reloc *r = relocs;
 
        memset(handle_tlbs, 0, sizeof(handle_tlbs));
        memset(labels, 0, sizeof(labels));
@@ -1645,20 +1027,20 @@ static void __init build_r3000_tlb_store_handler(void)
 
        build_r3000_tlbchange_handler_head(&p, K0, K1);
        build_pte_writable(&p, &l, &r, K0, K1, label_nopage_tlbs);
-       i_nop(&p); /* load delay */
+       uasm_i_nop(&p); /* load delay */
        build_make_write(&p, &r, K0, K1);
        build_r3000_tlb_reload_write(&p, &l, &r, K0, K1);
 
-       l_nopage_tlbs(&l, p);
-       i_j(&p, (unsigned long)tlb_do_page_fault_1 & 0x0fffffff);
-       i_nop(&p);
+       uasm_l_nopage_tlbs(&l, p);
+       uasm_i_j(&p, (unsigned long)tlb_do_page_fault_1 & 0x0fffffff);
+       uasm_i_nop(&p);
 
        if ((p - handle_tlbs) > FASTPATH_SIZE)
                panic("TLB store handler fastpath space exceeded");
 
-       resolve_relocs(relocs, labels);
-       pr_info("Synthesized TLB store handler fastpath (%u instructions).\n",
-               (unsigned int)(p - handle_tlbs));
+       uasm_resolve_relocs(relocs, labels);
+       pr_debug("Wrote TLB store handler fastpath (%u instructions).\n",
+                (unsigned int)(p - handle_tlbs));
 
        dump_handler(handle_tlbs, ARRAY_SIZE(handle_tlbs));
 }
@@ -1666,8 +1048,8 @@ static void __init build_r3000_tlb_store_handler(void)
 static void __init build_r3000_tlb_modify_handler(void)
 {
        u32 *p = handle_tlbm;
-       struct label *l = labels;
-       struct reloc *r = relocs;
+       struct uasm_label *l = labels;
+       struct uasm_reloc *r = relocs;
 
        memset(handle_tlbm, 0, sizeof(handle_tlbm));
        memset(labels, 0, sizeof(labels));
@@ -1675,20 +1057,20 @@ static void __init build_r3000_tlb_modify_handler(void)
 
        build_r3000_tlbchange_handler_head(&p, K0, K1);
        build_pte_modifiable(&p, &l, &r, K0, K1, label_nopage_tlbm);
-       i_nop(&p); /* load delay */
+       uasm_i_nop(&p); /* load delay */
        build_make_write(&p, &r, K0, K1);
        build_r3000_pte_reload_tlbwi(&p, K0, K1);
 
-       l_nopage_tlbm(&l, p);
-       i_j(&p, (unsigned long)tlb_do_page_fault_1 & 0x0fffffff);
-       i_nop(&p);
+       uasm_l_nopage_tlbm(&l, p);
+       uasm_i_j(&p, (unsigned long)tlb_do_page_fault_1 & 0x0fffffff);
+       uasm_i_nop(&p);
 
        if ((p - handle_tlbm) > FASTPATH_SIZE)
                panic("TLB modify handler fastpath space exceeded");
 
-       resolve_relocs(relocs, labels);
-       pr_info("Synthesized TLB modify handler fastpath (%u instructions).\n",
-               (unsigned int)(p - handle_tlbm));
+       uasm_resolve_relocs(relocs, labels);
+       pr_debug("Wrote TLB modify handler fastpath (%u instructions).\n",
+                (unsigned int)(p - handle_tlbm));
 
        dump_handler(handle_tlbm, ARRAY_SIZE(handle_tlbm));
 }
@@ -1697,8 +1079,8 @@ static void __init build_r3000_tlb_modify_handler(void)
  * R4000 style TLB load/store/modify handlers.
  */
 static void __init
-build_r4000_tlbchange_handler_head(u32 **p, struct label **l,
-                                  struct reloc **r, unsigned int pte,
+build_r4000_tlbchange_handler_head(u32 **p, struct uasm_label **l,
+                                  struct uasm_reloc **r, unsigned int pte,
                                   unsigned int ptr)
 {
 #ifdef CONFIG_64BIT
@@ -1707,31 +1089,31 @@ build_r4000_tlbchange_handler_head(u32 **p, struct label **l,
        build_get_pgde32(p, pte, ptr); /* get pgd in ptr */
 #endif
 
-       i_MFC0(p, pte, C0_BADVADDR);
-       i_LW(p, ptr, 0, ptr);
-       i_SRL(p, pte, pte, PAGE_SHIFT + PTE_ORDER - PTE_T_LOG2);
-       i_andi(p, pte, pte, (PTRS_PER_PTE - 1) << PTE_T_LOG2);
-       i_ADDU(p, ptr, ptr, pte);
+       UASM_i_MFC0(p, pte, C0_BADVADDR);
+       UASM_i_LW(p, ptr, 0, ptr);
+       UASM_i_SRL(p, pte, pte, PAGE_SHIFT + PTE_ORDER - PTE_T_LOG2);
+       uasm_i_andi(p, pte, pte, (PTRS_PER_PTE - 1) << PTE_T_LOG2);
+       UASM_i_ADDU(p, ptr, ptr, pte);
 
 #ifdef CONFIG_SMP
-       l_smp_pgtable_change(l, *p);
-# endif
+       uasm_l_smp_pgtable_change(l, *p);
+#endif
        iPTE_LW(p, l, pte, ptr); /* get even pte */
        if (!m4kc_tlbp_war())
                build_tlb_probe_entry(p);
 }
 
 static void __init
-build_r4000_tlbchange_handler_tail(u32 **p, struct label **l,
-                                  struct reloc **r, unsigned int tmp,
+build_r4000_tlbchange_handler_tail(u32 **p, struct uasm_label **l,
+                                  struct uasm_reloc **r, unsigned int tmp,
                                   unsigned int ptr)
 {
-       i_ori(p, ptr, ptr, sizeof(pte_t));
-       i_xori(p, ptr, ptr, sizeof(pte_t));
+       uasm_i_ori(p, ptr, ptr, sizeof(pte_t));
+       uasm_i_xori(p, ptr, ptr, sizeof(pte_t));
        build_update_entries(p, tmp, ptr);
        build_tlb_write_entry(p, l, r, tlb_indexed);
-       l_leave(l, *p);
-       i_eret(p); /* return from trap */
+       uasm_l_leave(l, *p);
+       uasm_i_eret(p); /* return from trap */
 
 #ifdef CONFIG_64BIT
        build_get_pgd_vmalloc64(p, l, r, tmp, ptr);
@@ -1741,20 +1123,20 @@ build_r4000_tlbchange_handler_tail(u32 **p, struct label **l,
 static void __init build_r4000_tlb_load_handler(void)
 {
        u32 *p = handle_tlbl;
-       struct label *l = labels;
-       struct reloc *r = relocs;
+       struct uasm_label *l = labels;
+       struct uasm_reloc *r = relocs;
 
        memset(handle_tlbl, 0, sizeof(handle_tlbl));
        memset(labels, 0, sizeof(labels));
        memset(relocs, 0, sizeof(relocs));
 
        if (bcm1250_m3_war()) {
-               i_MFC0(&p, K0, C0_BADVADDR);
-               i_MFC0(&p, K1, C0_ENTRYHI);
-               i_xor(&p, K0, K0, K1);
-               i_SRL(&p, K0, K0, PAGE_SHIFT + 1);
-               il_bnez(&p, &r, K0, label_leave);
-               /* No need for i_nop */
+               UASM_i_MFC0(&p, K0, C0_BADVADDR);
+               UASM_i_MFC0(&p, K1, C0_ENTRYHI);
+               uasm_i_xor(&p, K0, K0, K1);
+               UASM_i_SRL(&p, K0, K0, PAGE_SHIFT + 1);
+               uasm_il_bnez(&p, &r, K0, label_leave);
+               /* No need for uasm_i_nop */
        }
 
        build_r4000_tlbchange_handler_head(&p, &l, &r, K0, K1);
@@ -1764,16 +1146,16 @@ static void __init build_r4000_tlb_load_handler(void)
        build_make_valid(&p, &r, K0, K1);
        build_r4000_tlbchange_handler_tail(&p, &l, &r, K0, K1);
 
-       l_nopage_tlbl(&l, p);
-       i_j(&p, (unsigned long)tlb_do_page_fault_0 & 0x0fffffff);
-       i_nop(&p);
+       uasm_l_nopage_tlbl(&l, p);
+       uasm_i_j(&p, (unsigned long)tlb_do_page_fault_0 & 0x0fffffff);
+       uasm_i_nop(&p);
 
        if ((p - handle_tlbl) > FASTPATH_SIZE)
                panic("TLB load handler fastpath space exceeded");
 
-       resolve_relocs(relocs, labels);
-       pr_info("Synthesized TLB load handler fastpath (%u instructions).\n",
-               (unsigned int)(p - handle_tlbl));
+       uasm_resolve_relocs(relocs, labels);
+       pr_debug("Wrote TLB load handler fastpath (%u instructions).\n",
+                (unsigned int)(p - handle_tlbl));
 
        dump_handler(handle_tlbl, ARRAY_SIZE(handle_tlbl));
 }
@@ -1781,8 +1163,8 @@ static void __init build_r4000_tlb_load_handler(void)
 static void __init build_r4000_tlb_store_handler(void)
 {
        u32 *p = handle_tlbs;
-       struct label *l = labels;
-       struct reloc *r = relocs;
+       struct uasm_label *l = labels;
+       struct uasm_reloc *r = relocs;
 
        memset(handle_tlbs, 0, sizeof(handle_tlbs));
        memset(labels, 0, sizeof(labels));
@@ -1795,16 +1177,16 @@ static void __init build_r4000_tlb_store_handler(void)
        build_make_write(&p, &r, K0, K1);
        build_r4000_tlbchange_handler_tail(&p, &l, &r, K0, K1);
 
-       l_nopage_tlbs(&l, p);
-       i_j(&p, (unsigned long)tlb_do_page_fault_1 & 0x0fffffff);
-       i_nop(&p);
+       uasm_l_nopage_tlbs(&l, p);
+       uasm_i_j(&p, (unsigned long)tlb_do_page_fault_1 & 0x0fffffff);
+       uasm_i_nop(&p);
 
        if ((p - handle_tlbs) > FASTPATH_SIZE)
                panic("TLB store handler fastpath space exceeded");
 
-       resolve_relocs(relocs, labels);
-       pr_info("Synthesized TLB store handler fastpath (%u instructions).\n",
-               (unsigned int)(p - handle_tlbs));
+       uasm_resolve_relocs(relocs, labels);
+       pr_debug("Wrote TLB store handler fastpath (%u instructions).\n",
+                (unsigned int)(p - handle_tlbs));
 
        dump_handler(handle_tlbs, ARRAY_SIZE(handle_tlbs));
 }
@@ -1812,8 +1194,8 @@ static void __init build_r4000_tlb_store_handler(void)
 static void __init build_r4000_tlb_modify_handler(void)
 {
        u32 *p = handle_tlbm;
-       struct label *l = labels;
-       struct reloc *r = relocs;
+       struct uasm_label *l = labels;
+       struct uasm_reloc *r = relocs;
 
        memset(handle_tlbm, 0, sizeof(handle_tlbm));
        memset(labels, 0, sizeof(labels));
@@ -1827,16 +1209,16 @@ static void __init build_r4000_tlb_modify_handler(void)
        build_make_write(&p, &r, K0, K1);
        build_r4000_tlbchange_handler_tail(&p, &l, &r, K0, K1);
 
-       l_nopage_tlbm(&l, p);
-       i_j(&p, (unsigned long)tlb_do_page_fault_1 & 0x0fffffff);
-       i_nop(&p);
+       uasm_l_nopage_tlbm(&l, p);
+       uasm_i_j(&p, (unsigned long)tlb_do_page_fault_1 & 0x0fffffff);
+       uasm_i_nop(&p);
 
        if ((p - handle_tlbm) > FASTPATH_SIZE)
                panic("TLB modify handler fastpath space exceeded");
 
-       resolve_relocs(relocs, labels);
-       pr_info("Synthesized TLB modify handler fastpath (%u instructions).\n",
-               (unsigned int)(p - handle_tlbm));
+       uasm_resolve_relocs(relocs, labels);
+       pr_debug("Wrote TLB modify handler fastpath (%u instructions).\n",
+                (unsigned int)(p - handle_tlbm));
 
        dump_handler(handle_tlbm, ARRAY_SIZE(handle_tlbm));
 }
diff --git a/arch/mips/mm/uasm.c b/arch/mips/mm/uasm.c
new file mode 100644 (file)
index 0000000..e3f74ed
--- /dev/null
@@ -0,0 +1,576 @@
+/*
+ * 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.
+ *
+ * A small micro-assembler. It is intentionally kept simple, does only
+ * support a subset of instructions, and does not try to hide pipeline
+ * effects like branch delay slots.
+ *
+ * Copyright (C) 2004, 2005, 2006, 2008  Thiemo Seufer
+ * Copyright (C) 2005, 2007  Maciej W. Rozycki
+ * Copyright (C) 2006  Ralf Baechle (ralf@linux-mips.org)
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/init.h>
+
+#include <asm/inst.h>
+#include <asm/elf.h>
+#include <asm/bugs.h>
+
+#include "uasm.h"
+
+enum fields {
+       RS = 0x001,
+       RT = 0x002,
+       RD = 0x004,
+       RE = 0x008,
+       SIMM = 0x010,
+       UIMM = 0x020,
+       BIMM = 0x040,
+       JIMM = 0x080,
+       FUNC = 0x100,
+       SET = 0x200
+};
+
+#define OP_MASK                0x3f
+#define OP_SH          26
+#define RS_MASK                0x1f
+#define RS_SH          21
+#define RT_MASK                0x1f
+#define RT_SH          16
+#define RD_MASK                0x1f
+#define RD_SH          11
+#define RE_MASK                0x1f
+#define RE_SH          6
+#define IMM_MASK       0xffff
+#define IMM_SH         0
+#define JIMM_MASK      0x3ffffff
+#define JIMM_SH                0
+#define FUNC_MASK      0x3f
+#define FUNC_SH                0
+#define SET_MASK       0x7
+#define SET_SH         0
+
+enum opcode {
+       insn_invalid,
+       insn_addu, insn_addiu, insn_and, insn_andi, insn_beq,
+       insn_beql, insn_bgez, insn_bgezl, insn_bltz, insn_bltzl,
+       insn_bne, insn_daddu, insn_daddiu, insn_dmfc0, insn_dmtc0,
+       insn_dsll, insn_dsll32, insn_dsra, insn_dsrl, insn_dsrl32,
+       insn_dsubu, insn_eret, insn_j, insn_jal, insn_jr, insn_ld,
+       insn_ll, insn_lld, insn_lui, insn_lw, insn_mfc0, insn_mtc0,
+       insn_ori, insn_rfe, insn_sc, insn_scd, insn_sd, insn_sll,
+       insn_sra, insn_srl, insn_subu, insn_sw, insn_tlbp, insn_tlbwi,
+       insn_tlbwr, insn_xor, insn_xori
+};
+
+struct insn {
+       enum opcode opcode;
+       u32 match;
+       enum fields fields;
+};
+
+/* This macro sets the non-variable bits of an instruction. */
+#define M(a, b, c, d, e, f)                                    \
+       ((a) << OP_SH                                           \
+        | (b) << RS_SH                                         \
+        | (c) << RT_SH                                         \
+        | (d) << RD_SH                                         \
+        | (e) << RE_SH                                         \
+        | (f) << FUNC_SH)
+
+static struct insn insn_table[] __initdata = {
+       { insn_addiu, M(addiu_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
+       { insn_addu, M(spec_op, 0, 0, 0, 0, addu_op), RS | RT | RD },
+       { insn_and, M(spec_op, 0, 0, 0, 0, and_op), RS | RT | RD },
+       { insn_andi, M(andi_op, 0, 0, 0, 0, 0), RS | RT | UIMM },
+       { insn_beq, M(beq_op, 0, 0, 0, 0, 0), RS | RT | BIMM },
+       { insn_beql, M(beql_op, 0, 0, 0, 0, 0), RS | RT | BIMM },
+       { insn_bgez, M(bcond_op, 0, bgez_op, 0, 0, 0), RS | BIMM },
+       { insn_bgezl, M(bcond_op, 0, bgezl_op, 0, 0, 0), RS | BIMM },
+       { insn_bltz, M(bcond_op, 0, bltz_op, 0, 0, 0), RS | BIMM },
+       { insn_bltzl, M(bcond_op, 0, bltzl_op, 0, 0, 0), RS | BIMM },
+       { insn_bne, M(bne_op, 0, 0, 0, 0, 0), RS | RT | BIMM },
+       { insn_daddiu, M(daddiu_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
+       { insn_daddu, M(spec_op, 0, 0, 0, 0, daddu_op), RS | RT | RD },
+       { insn_dmfc0, M(cop0_op, dmfc_op, 0, 0, 0, 0), RT | RD | SET},
+       { insn_dmtc0, M(cop0_op, dmtc_op, 0, 0, 0, 0), RT | RD | SET},
+       { insn_dsll, M(spec_op, 0, 0, 0, 0, dsll_op), RT | RD | RE },
+       { insn_dsll32, M(spec_op, 0, 0, 0, 0, dsll32_op), RT | RD | RE },
+       { insn_dsra, M(spec_op, 0, 0, 0, 0, dsra_op), RT | RD | RE },
+       { insn_dsrl, M(spec_op, 0, 0, 0, 0, dsrl_op), RT | RD | RE },
+       { insn_dsrl32, M(spec_op, 0, 0, 0, 0, dsrl32_op), RT | RD | RE },
+       { insn_dsubu, M(spec_op, 0, 0, 0, 0, dsubu_op), RS | RT | RD },
+       { insn_eret,  M(cop0_op, cop_op, 0, 0, 0, eret_op),  0 },
+       { insn_j,  M(j_op, 0, 0, 0, 0, 0),  JIMM },
+       { insn_jal,  M(jal_op, 0, 0, 0, 0, 0),  JIMM },
+       { insn_jr,  M(spec_op, 0, 0, 0, 0, jr_op),  RS },
+       { insn_ld,  M(ld_op, 0, 0, 0, 0, 0),  RS | RT | SIMM },
+       { insn_ll,  M(ll_op, 0, 0, 0, 0, 0),  RS | RT | SIMM },
+       { insn_lld,  M(lld_op, 0, 0, 0, 0, 0),  RS | RT | SIMM },
+       { insn_lui,  M(lui_op, 0, 0, 0, 0, 0),  RT | SIMM },
+       { insn_lw,  M(lw_op, 0, 0, 0, 0, 0),  RS | RT | SIMM },
+       { insn_mfc0,  M(cop0_op, mfc_op, 0, 0, 0, 0),  RT | RD | SET},
+       { insn_mtc0,  M(cop0_op, mtc_op, 0, 0, 0, 0),  RT | RD | SET},
+       { insn_ori,  M(ori_op, 0, 0, 0, 0, 0),  RS | RT | UIMM },
+       { insn_rfe,  M(cop0_op, cop_op, 0, 0, 0, rfe_op),  0 },
+       { insn_sc,  M(sc_op, 0, 0, 0, 0, 0),  RS | RT | SIMM },
+       { insn_scd,  M(scd_op, 0, 0, 0, 0, 0),  RS | RT | SIMM },
+       { insn_sd,  M(sd_op, 0, 0, 0, 0, 0),  RS | RT | SIMM },
+       { insn_sll,  M(spec_op, 0, 0, 0, 0, sll_op),  RT | RD | RE },
+       { insn_sra,  M(spec_op, 0, 0, 0, 0, sra_op),  RT | RD | RE },
+       { insn_srl,  M(spec_op, 0, 0, 0, 0, srl_op),  RT | RD | RE },
+       { insn_subu,  M(spec_op, 0, 0, 0, 0, subu_op),  RS | RT | RD },
+       { insn_sw,  M(sw_op, 0, 0, 0, 0, 0),  RS | RT | SIMM },
+       { insn_tlbp,  M(cop0_op, cop_op, 0, 0, 0, tlbp_op),  0 },
+       { insn_tlbwi,  M(cop0_op, cop_op, 0, 0, 0, tlbwi_op),  0 },
+       { insn_tlbwr,  M(cop0_op, cop_op, 0, 0, 0, tlbwr_op),  0 },
+       { insn_xor,  M(spec_op, 0, 0, 0, 0, xor_op),  RS | RT | RD },
+       { insn_xori,  M(xori_op, 0, 0, 0, 0, 0),  RS | RT | UIMM },
+       { insn_invalid, 0, 0 }
+};
+
+#undef M
+
+static inline __init u32 build_rs(u32 arg)
+{
+       if (arg & ~RS_MASK)
+               printk(KERN_WARNING "Micro-assembler field overflow\n");
+
+       return (arg & RS_MASK) << RS_SH;
+}
+
+static inline __init u32 build_rt(u32 arg)
+{
+       if (arg & ~RT_MASK)
+               printk(KERN_WARNING "Micro-assembler field overflow\n");
+
+       return (arg & RT_MASK) << RT_SH;
+}
+
+static inline __init u32 build_rd(u32 arg)
+{
+       if (arg & ~RD_MASK)
+               printk(KERN_WARNING "Micro-assembler field overflow\n");
+
+       return (arg & RD_MASK) << RD_SH;
+}
+
+static inline __init u32 build_re(u32 arg)
+{
+       if (arg & ~RE_MASK)
+               printk(KERN_WARNING "Micro-assembler field overflow\n");
+
+       return (arg & RE_MASK) << RE_SH;
+}
+
+static inline __init u32 build_simm(s32 arg)
+{
+       if (arg > 0x7fff || arg < -0x8000)
+               printk(KERN_WARNING "Micro-assembler field overflow\n");
+
+       return arg & 0xffff;
+}
+
+static inline __init u32 build_uimm(u32 arg)
+{
+       if (arg & ~IMM_MASK)
+               printk(KERN_WARNING "Micro-assembler field overflow\n");
+
+       return arg & IMM_MASK;
+}
+
+static inline __init u32 build_bimm(s32 arg)
+{
+       if (arg > 0x1ffff || arg < -0x20000)
+               printk(KERN_WARNING "Micro-assembler field overflow\n");
+
+       if (arg & 0x3)
+               printk(KERN_WARNING "Invalid micro-assembler branch target\n");
+
+       return ((arg < 0) ? (1 << 15) : 0) | ((arg >> 2) & 0x7fff);
+}
+
+static inline __init u32 build_jimm(u32 arg)
+{
+       if (arg & ~((JIMM_MASK) << 2))
+               printk(KERN_WARNING "Micro-assembler field overflow\n");
+
+       return (arg >> 2) & JIMM_MASK;
+}
+
+static inline __init u32 build_func(u32 arg)
+{
+       if (arg & ~FUNC_MASK)
+               printk(KERN_WARNING "Micro-assembler field overflow\n");
+
+       return arg & FUNC_MASK;
+}
+
+static inline __init u32 build_set(u32 arg)
+{
+       if (arg & ~SET_MASK)
+               printk(KERN_WARNING "Micro-assembler field overflow\n");
+
+       return arg & SET_MASK;
+}
+
+/*
+ * The order of opcode arguments is implicitly left to right,
+ * starting with RS and ending with FUNC or IMM.
+ */
+static void __init build_insn(u32 **buf, enum opcode opc, ...)
+{
+       struct insn *ip = NULL;
+       unsigned int i;
+       va_list ap;
+       u32 op;
+
+       for (i = 0; insn_table[i].opcode != insn_invalid; i++)
+               if (insn_table[i].opcode == opc) {
+                       ip = &insn_table[i];
+                       break;
+               }
+
+       if (!ip || (opc == insn_daddiu && r4k_daddiu_bug()))
+               panic("Unsupported Micro-assembler instruction %d", opc);
+
+       op = ip->match;
+       va_start(ap, opc);
+       if (ip->fields & RS)
+               op |= build_rs(va_arg(ap, u32));
+       if (ip->fields & RT)
+               op |= build_rt(va_arg(ap, u32));
+       if (ip->fields & RD)
+               op |= build_rd(va_arg(ap, u32));
+       if (ip->fields & RE)
+               op |= build_re(va_arg(ap, u32));
+       if (ip->fields & SIMM)
+               op |= build_simm(va_arg(ap, s32));
+       if (ip->fields & UIMM)
+               op |= build_uimm(va_arg(ap, u32));
+       if (ip->fields & BIMM)
+               op |= build_bimm(va_arg(ap, s32));
+       if (ip->fields & JIMM)
+               op |= build_jimm(va_arg(ap, u32));
+       if (ip->fields & FUNC)
+               op |= build_func(va_arg(ap, u32));
+       if (ip->fields & SET)
+               op |= build_set(va_arg(ap, u32));
+       va_end(ap);
+
+       **buf = op;
+       (*buf)++;
+}
+
+#define I_u1u2u3(op)                                   \
+Ip_u1u2u3(op)                                          \
+{                                                      \
+       build_insn(buf, insn##op, a, b, c);             \
+}
+
+#define I_u2u1u3(op)                                   \
+Ip_u2u1u3(op)                                          \
+{                                                      \
+       build_insn(buf, insn##op, b, a, c);             \
+}
+
+#define I_u3u1u2(op)                                   \
+Ip_u3u1u2(op)                                          \
+{                                                      \
+       build_insn(buf, insn##op, b, c, a);             \
+}
+
+#define I_u1u2s3(op)                                   \
+Ip_u1u2s3(op)                                          \
+{                                                      \
+       build_insn(buf, insn##op, a, b, c);             \
+}
+
+#define I_u2s3u1(op)                                   \
+Ip_u2s3u1(op)                                          \
+{                                                      \
+       build_insn(buf, insn##op, c, a, b);             \
+}
+
+#define I_u2u1s3(op)                                   \
+Ip_u2u1s3(op)                                          \
+{                                                      \
+       build_insn(buf, insn##op, b, a, c);             \
+}
+
+#define I_u1u2(op)                                     \
+Ip_u1u2(op)                                            \
+{                                                      \
+       build_insn(buf, insn##op, a, b);                \
+}
+
+#define I_u1s2(op)                                     \
+Ip_u1s2(op)                                            \
+{                                                      \
+       build_insn(buf, insn##op, a, b);                \
+}
+
+#define I_u1(op)                                       \
+Ip_u1(op)                                              \
+{                                                      \
+       build_insn(buf, insn##op, a);                   \
+}
+
+#define I_0(op)                                                \
+Ip_0(op)                                               \
+{                                                      \
+       build_insn(buf, insn##op);                      \
+}
+
+I_u2u1s3(_addiu)
+I_u3u1u2(_addu)
+I_u2u1u3(_andi)
+I_u3u1u2(_and)
+I_u1u2s3(_beq)
+I_u1u2s3(_beql)
+I_u1s2(_bgez)
+I_u1s2(_bgezl)
+I_u1s2(_bltz)
+I_u1s2(_bltzl)
+I_u1u2s3(_bne)
+I_u1u2u3(_dmfc0)
+I_u1u2u3(_dmtc0)
+I_u2u1s3(_daddiu)
+I_u3u1u2(_daddu)
+I_u2u1u3(_dsll)
+I_u2u1u3(_dsll32)
+I_u2u1u3(_dsra)
+I_u2u1u3(_dsrl)
+I_u2u1u3(_dsrl32)
+I_u3u1u2(_dsubu)
+I_0(_eret)
+I_u1(_j)
+I_u1(_jal)
+I_u1(_jr)
+I_u2s3u1(_ld)
+I_u2s3u1(_ll)
+I_u2s3u1(_lld)
+I_u1s2(_lui)
+I_u2s3u1(_lw)
+I_u1u2u3(_mfc0)
+I_u1u2u3(_mtc0)
+I_u2u1u3(_ori)
+I_0(_rfe)
+I_u2s3u1(_sc)
+I_u2s3u1(_scd)
+I_u2s3u1(_sd)
+I_u2u1u3(_sll)
+I_u2u1u3(_sra)
+I_u2u1u3(_srl)
+I_u3u1u2(_subu)
+I_u2s3u1(_sw)
+I_0(_tlbp)
+I_0(_tlbwi)
+I_0(_tlbwr)
+I_u3u1u2(_xor)
+I_u2u1u3(_xori)
+
+/* Handle labels. */
+void __init uasm_build_label(struct uasm_label **lab, u32 *addr, int lid)
+{
+       (*lab)->addr = addr;
+       (*lab)->lab = lid;
+       (*lab)++;
+}
+
+int __init uasm_in_compat_space_p(long addr)
+{
+       /* Is this address in 32bit compat space? */
+#ifdef CONFIG_64BIT
+       return (((addr) & 0xffffffff00000000L) == 0xffffffff00000000L);
+#else
+       return 1;
+#endif
+}
+
+int __init uasm_rel_highest(long val)
+{
+#ifdef CONFIG_64BIT
+       return ((((val + 0x800080008000L) >> 48) & 0xffff) ^ 0x8000) - 0x8000;
+#else
+       return 0;
+#endif
+}
+
+int __init uasm_rel_higher(long val)
+{
+#ifdef CONFIG_64BIT
+       return ((((val + 0x80008000L) >> 32) & 0xffff) ^ 0x8000) - 0x8000;
+#else
+       return 0;
+#endif
+}
+
+int __init uasm_rel_hi(long val)
+{
+       return ((((val + 0x8000L) >> 16) & 0xffff) ^ 0x8000) - 0x8000;
+}
+
+int __init uasm_rel_lo(long val)
+{
+       return ((val & 0xffff) ^ 0x8000) - 0x8000;
+}
+
+void __init UASM_i_LA_mostly(u32 **buf, unsigned int rs, long addr)
+{
+       if (!uasm_in_compat_space_p(addr)) {
+               uasm_i_lui(buf, rs, uasm_rel_highest(addr));
+               if (uasm_rel_higher(addr))
+                       uasm_i_daddiu(buf, rs, rs, uasm_rel_higher(addr));
+               if (uasm_rel_hi(addr)) {
+                       uasm_i_dsll(buf, rs, rs, 16);
+                       uasm_i_daddiu(buf, rs, rs, uasm_rel_hi(addr));
+                       uasm_i_dsll(buf, rs, rs, 16);
+               } else
+                       uasm_i_dsll32(buf, rs, rs, 0);
+       } else
+               uasm_i_lui(buf, rs, uasm_rel_hi(addr));
+}
+
+void __init UASM_i_LA(u32 **buf, unsigned int rs, long addr)
+{
+       UASM_i_LA_mostly(buf, rs, addr);
+       if (uasm_rel_lo(addr)) {
+               if (!uasm_in_compat_space_p(addr))
+                       uasm_i_daddiu(buf, rs, rs, uasm_rel_lo(addr));
+               else
+                       uasm_i_addiu(buf, rs, rs, uasm_rel_lo(addr));
+       }
+}
+
+/* Handle relocations. */
+void __init
+uasm_r_mips_pc16(struct uasm_reloc **rel, u32 *addr, int lid)
+{
+       (*rel)->addr = addr;
+       (*rel)->type = R_MIPS_PC16;
+       (*rel)->lab = lid;
+       (*rel)++;
+}
+
+static inline void __init
+__resolve_relocs(struct uasm_reloc *rel, struct uasm_label *lab)
+{
+       long laddr = (long)lab->addr;
+       long raddr = (long)rel->addr;
+
+       switch (rel->type) {
+       case R_MIPS_PC16:
+               *rel->addr |= build_bimm(laddr - (raddr + 4));
+               break;
+
+       default:
+               panic("Unsupported Micro-assembler relocation %d",
+                     rel->type);
+       }
+}
+
+void __init
+uasm_resolve_relocs(struct uasm_reloc *rel, struct uasm_label *lab)
+{
+       struct uasm_label *l;
+
+       for (; rel->lab != UASM_LABEL_INVALID; rel++)
+               for (l = lab; l->lab != UASM_LABEL_INVALID; l++)
+                       if (rel->lab == l->lab)
+                               __resolve_relocs(rel, l);
+}
+
+void __init
+uasm_move_relocs(struct uasm_reloc *rel, u32 *first, u32 *end, long off)
+{
+       for (; rel->lab != UASM_LABEL_INVALID; rel++)
+               if (rel->addr >= first && rel->addr < end)
+                       rel->addr += off;
+}
+
+void __init
+uasm_move_labels(struct uasm_label *lab, u32 *first, u32 *end, long off)
+{
+       for (; lab->lab != UASM_LABEL_INVALID; lab++)
+               if (lab->addr >= first && lab->addr < end)
+                       lab->addr += off;
+}
+
+void __init
+uasm_copy_handler(struct uasm_reloc *rel, struct uasm_label *lab, u32 *first,
+                 u32 *end, u32 *target)
+{
+       long off = (long)(target - first);
+
+       memcpy(target, first, (end - first) * sizeof(u32));
+
+       uasm_move_relocs(rel, first, end, off);
+       uasm_move_labels(lab, first, end, off);
+}
+
+int __init uasm_insn_has_bdelay(struct uasm_reloc *rel, u32 *addr)
+{
+       for (; rel->lab != UASM_LABEL_INVALID; rel++) {
+               if (rel->addr == addr
+                   && (rel->type == R_MIPS_PC16
+                       || rel->type == R_MIPS_26))
+                       return 1;
+       }
+
+       return 0;
+}
+
+/* Convenience functions for labeled branches. */
+void __init
+uasm_il_bltz(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid)
+{
+       uasm_r_mips_pc16(r, *p, lid);
+       uasm_i_bltz(p, reg, 0);
+}
+
+void __init
+uasm_il_b(u32 **p, struct uasm_reloc **r, int lid)
+{
+       uasm_r_mips_pc16(r, *p, lid);
+       uasm_i_b(p, 0);
+}
+
+void __init
+uasm_il_beqz(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid)
+{
+       uasm_r_mips_pc16(r, *p, lid);
+       uasm_i_beqz(p, reg, 0);
+}
+
+void __init
+uasm_il_beqzl(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid)
+{
+       uasm_r_mips_pc16(r, *p, lid);
+       uasm_i_beqzl(p, reg, 0);
+}
+
+void __init
+uasm_il_bnez(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid)
+{
+       uasm_r_mips_pc16(r, *p, lid);
+       uasm_i_bnez(p, reg, 0);
+}
+
+void __init
+uasm_il_bgezl(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid)
+{
+       uasm_r_mips_pc16(r, *p, lid);
+       uasm_i_bgezl(p, reg, 0);
+}
+
+void __init
+uasm_il_bgez(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid)
+{
+       uasm_r_mips_pc16(r, *p, lid);
+       uasm_i_bgez(p, reg, 0);
+}
diff --git a/arch/mips/mm/uasm.h b/arch/mips/mm/uasm.h
new file mode 100644 (file)
index 0000000..a10fc11
--- /dev/null
@@ -0,0 +1,192 @@
+/*
+ * 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) 2004, 2005, 2006, 2008  Thiemo Seufer
+ * Copyright (C) 2005  Maciej W. Rozycki
+ * Copyright (C) 2006  Ralf Baechle (ralf@linux-mips.org)
+ */
+
+#include <linux/types.h>
+
+#define Ip_u1u2u3(op)                                                  \
+void __init                                                            \
+uasm_i##op(u32 **buf, unsigned int a, unsigned int b, unsigned int c)
+
+#define Ip_u2u1u3(op)                                                  \
+void __init                                                            \
+uasm_i##op(u32 **buf, unsigned int a, unsigned int b, unsigned int c)
+
+#define Ip_u3u1u2(op)                                                  \
+void __init                                                            \
+uasm_i##op(u32 **buf, unsigned int a, unsigned int b, unsigned int c)
+
+#define Ip_u1u2s3(op)                                                  \
+void __init                                                            \
+uasm_i##op(u32 **buf, unsigned int a, unsigned int b, signed int c)
+
+#define Ip_u2s3u1(op)                                                  \
+void __init                                                            \
+uasm_i##op(u32 **buf, unsigned int a, signed int b, unsigned int c)
+
+#define Ip_u2u1s3(op)                                                  \
+void __init                                                            \
+uasm_i##op(u32 **buf, unsigned int a, unsigned int b, signed int c)
+
+#define Ip_u1u2(op)                                                    \
+void __init uasm_i##op(u32 **buf, unsigned int a, unsigned int b)
+
+#define Ip_u1s2(op)                                                    \
+void __init uasm_i##op(u32 **buf, unsigned int a, signed int b)
+
+#define Ip_u1(op) void __init uasm_i##op(u32 **buf, unsigned int a)
+
+#define Ip_0(op) void __init uasm_i##op(u32 **buf)
+
+Ip_u2u1s3(_addiu);
+Ip_u3u1u2(_addu);
+Ip_u2u1u3(_andi);
+Ip_u3u1u2(_and);
+Ip_u1u2s3(_beq);
+Ip_u1u2s3(_beql);
+Ip_u1s2(_bgez);
+Ip_u1s2(_bgezl);
+Ip_u1s2(_bltz);
+Ip_u1s2(_bltzl);
+Ip_u1u2s3(_bne);
+Ip_u1u2u3(_dmfc0);
+Ip_u1u2u3(_dmtc0);
+Ip_u2u1s3(_daddiu);
+Ip_u3u1u2(_daddu);
+Ip_u2u1u3(_dsll);
+Ip_u2u1u3(_dsll32);
+Ip_u2u1u3(_dsra);
+Ip_u2u1u3(_dsrl);
+Ip_u2u1u3(_dsrl32);
+Ip_u3u1u2(_dsubu);
+Ip_0(_eret);
+Ip_u1(_j);
+Ip_u1(_jal);
+Ip_u1(_jr);
+Ip_u2s3u1(_ld);
+Ip_u2s3u1(_ll);
+Ip_u2s3u1(_lld);
+Ip_u1s2(_lui);
+Ip_u2s3u1(_lw);
+Ip_u1u2u3(_mfc0);
+Ip_u1u2u3(_mtc0);
+Ip_u2u1u3(_ori);
+Ip_0(_rfe);
+Ip_u2s3u1(_sc);
+Ip_u2s3u1(_scd);
+Ip_u2s3u1(_sd);
+Ip_u2u1u3(_sll);
+Ip_u2u1u3(_sra);
+Ip_u2u1u3(_srl);
+Ip_u3u1u2(_subu);
+Ip_u2s3u1(_sw);
+Ip_0(_tlbp);
+Ip_0(_tlbwi);
+Ip_0(_tlbwr);
+Ip_u3u1u2(_xor);
+Ip_u2u1u3(_xori);
+
+/* Handle labels. */
+struct uasm_label {
+       u32 *addr;
+       int lab;
+};
+
+void __init uasm_build_label(struct uasm_label **lab, u32 *addr, int lid);
+#ifdef CONFIG_64BIT
+int __init uasm_in_compat_space_p(long addr);
+int __init uasm_rel_highest(long val);
+int __init uasm_rel_higher(long val);
+#endif
+int __init uasm_rel_hi(long val);
+int __init uasm_rel_lo(long val);
+void __init UASM_i_LA_mostly(u32 **buf, unsigned int rs, long addr);
+void __init UASM_i_LA(u32 **buf, unsigned int rs, long addr);
+
+#define UASM_L_LA(lb)                                                  \
+static inline void __init uasm_l##lb(struct uasm_label **lab, u32 *addr) \
+{                                                                      \
+       uasm_build_label(lab, addr, label##lb);                         \
+}
+
+/* convenience macros for instructions */
+#ifdef CONFIG_64BIT
+# define UASM_i_LW(buf, rs, rt, off) uasm_i_ld(buf, rs, rt, off)
+# define UASM_i_SW(buf, rs, rt, off) uasm_i_sd(buf, rs, rt, off)
+# define UASM_i_SLL(buf, rs, rt, sh) uasm_i_dsll(buf, rs, rt, sh)
+# define UASM_i_SRA(buf, rs, rt, sh) uasm_i_dsra(buf, rs, rt, sh)
+# define UASM_i_SRL(buf, rs, rt, sh) uasm_i_dsrl(buf, rs, rt, sh)
+# define UASM_i_MFC0(buf, rt, rd...) uasm_i_dmfc0(buf, rt, rd)
+# define UASM_i_MTC0(buf, rt, rd...) uasm_i_dmtc0(buf, rt, rd)
+# define UASM_i_ADDIU(buf, rs, rt, val) uasm_i_daddiu(buf, rs, rt, val)
+# define UASM_i_ADDU(buf, rs, rt, rd) uasm_i_daddu(buf, rs, rt, rd)
+# define UASM_i_SUBU(buf, rs, rt, rd) uasm_i_dsubu(buf, rs, rt, rd)
+# define UASM_i_LL(buf, rs, rt, off) uasm_i_lld(buf, rs, rt, off)
+# define UASM_i_SC(buf, rs, rt, off) uasm_i_scd(buf, rs, rt, off)
+#else
+# define UASM_i_LW(buf, rs, rt, off) uasm_i_lw(buf, rs, rt, off)
+# define UASM_i_SW(buf, rs, rt, off) uasm_i_sw(buf, rs, rt, off)
+# define UASM_i_SLL(buf, rs, rt, sh) uasm_i_sll(buf, rs, rt, sh)
+# define UASM_i_SRA(buf, rs, rt, sh) uasm_i_sra(buf, rs, rt, sh)
+# define UASM_i_SRL(buf, rs, rt, sh) uasm_i_srl(buf, rs, rt, sh)
+# define UASM_i_MFC0(buf, rt, rd...) uasm_i_mfc0(buf, rt, rd)
+# define UASM_i_MTC0(buf, rt, rd...) uasm_i_mtc0(buf, rt, rd)
+# define UASM_i_ADDIU(buf, rs, rt, val) uasm_i_addiu(buf, rs, rt, val)
+# define UASM_i_ADDU(buf, rs, rt, rd) uasm_i_addu(buf, rs, rt, rd)
+# define UASM_i_SUBU(buf, rs, rt, rd) uasm_i_subu(buf, rs, rt, rd)
+# define UASM_i_LL(buf, rs, rt, off) uasm_i_ll(buf, rs, rt, off)
+# define UASM_i_SC(buf, rs, rt, off) uasm_i_sc(buf, rs, rt, off)
+#endif
+
+#define uasm_i_b(buf, off) uasm_i_beq(buf, 0, 0, off)
+#define uasm_i_beqz(buf, rs, off) uasm_i_beq(buf, rs, 0, off)
+#define uasm_i_beqzl(buf, rs, off) uasm_i_beql(buf, rs, 0, off)
+#define uasm_i_bnez(buf, rs, off) uasm_i_bne(buf, rs, 0, off)
+#define uasm_i_bnezl(buf, rs, off) uasm_i_bnel(buf, rs, 0, off)
+#define uasm_i_move(buf, a, b) UASM_i_ADDU(buf, a, 0, b)
+#define uasm_i_nop(buf) uasm_i_sll(buf, 0, 0, 0)
+#define uasm_i_ssnop(buf) uasm_i_sll(buf, 0, 0, 1)
+#define uasm_i_ehb(buf) uasm_i_sll(buf, 0, 0, 3)
+
+/* Handle relocations. */
+struct uasm_reloc {
+       u32 *addr;
+       unsigned int type;
+       int lab;
+};
+
+/* This is zero so we can use zeroed label arrays. */
+#define UASM_LABEL_INVALID 0
+
+void __init uasm_r_mips_pc16(struct uasm_reloc **rel, u32 *addr, int lid);
+void __init
+uasm_resolve_relocs(struct uasm_reloc *rel, struct uasm_label *lab);
+void __init
+uasm_move_relocs(struct uasm_reloc *rel, u32 *first, u32 *end, long off);
+void __init
+uasm_move_labels(struct uasm_label *lab, u32 *first, u32 *end, long off);
+void __init
+uasm_copy_handler(struct uasm_reloc *rel, struct uasm_label *lab, u32 *first,
+                 u32 *end, u32 *target);
+int __init uasm_insn_has_bdelay(struct uasm_reloc *rel, u32 *addr);
+
+/* Convenience functions for labeled branches. */
+void __init
+uasm_il_bltz(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid);
+void __init uasm_il_b(u32 **p, struct uasm_reloc **r, int lid);
+void __init
+uasm_il_beqz(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid);
+void __init
+uasm_il_beqzl(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid);
+void __init
+uasm_il_bnez(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid);
+void __init
+uasm_il_bgezl(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid);
+void __init
+uasm_il_bgez(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid);
index 524b371f9397ae2bff5eb527614666c866f31343..a1fa4abb3f6a719ad0122a0861f3b2d659d293a4 100644 (file)
@@ -168,7 +168,7 @@ static void hub_set_piomode(nasid_t nasid)
 }
 
 /*
- * hub_pio_init  -  PIO-related hub initalization
+ * hub_pio_init  -  PIO-related hub initialization
  *
  * @hub:       hubinfo structure for our hub
  */
index 2b649c46631c14fb07d408dd3bad2e0869a8dae6..028d8a0fdbfd2b3213c183a5f6a371211fe55833 100644 (file)
@@ -7,6 +7,7 @@ mainmenu "Linux/PA-RISC Kernel Configuration"
 
 config PARISC
        def_bool y
+       select HAVE_OPROFILE
        help
          The PA-RISC microprocessor is designed by Hewlett-Packard and used
          in many of their workstations & servers (HP9000 700 and 800 series,
@@ -205,9 +206,8 @@ config SMP
          singleprocessor machines. On a singleprocessor machine, the kernel
          will run faster if you say N here.
 
-         See also the <file:Documentation/smp.txt>,
-         <file:Documentation/nmi_watchdog.txt> and the SMP-HOWTO available
-         at <http://www.tldp.org/docs.html#howto>.
+         See also <file:Documentation/nmi_watchdog.txt> and the SMP-HOWTO
+         available at <http://www.tldp.org/docs.html#howto>.
 
          If you don't know what to do here, say N.
 
@@ -272,8 +272,6 @@ source "drivers/Kconfig"
 
 source "fs/Kconfig"
 
-source "kernel/Kconfig.instrumentation"
-
 source "arch/parisc/Kconfig.debug"
 
 source "security/Kconfig"
index 395bbce649937e627315a3d3796a17fb2fe256f8..e10d25d2d9c935b6049d16a81a5efc02903018b2 100644 (file)
@@ -305,7 +305,7 @@ flush_user_cache_page_non_current(struct vm_area_struct *vma,
        /* save the current process space and pgd */
        unsigned long space = mfsp(3), pgd = mfctl(25);
 
-       /* we don't mind taking interrups since they may not
+       /* we don't mind taking interrupts since they may not
         * do anything with user space, but we can't
         * be preempted here */
        preempt_disable();
index 04848b2b381c40c8cc10e387281baf66dfc9c3c6..84b9611a92285b8edcbab9fffc20fdbca6662d7c 100644 (file)
@@ -1187,7 +1187,7 @@ static struct hp_hardware hp_hardware_list[] __devinitdata = {
        {HPHW_FIO, 0x005, 0x000A9, 0x00, "AllegroLow Core PCI USB KB"}, 
        {HPHW_FIO, 0x006, 0x000A9, 0x00, "AllegroHigh Core PCI SuperIO RS-232"}, 
        {HPHW_FIO, 0x006, 0x000A9, 0x00, "AllegroHigh Core PCI USB KB"}, 
-       {HPHW_FIO, 0x007, 0x000A9, 0x0, "Miscelaneous PCI Plug-in"}, 
+       {HPHW_FIO, 0x007, 0x000A9, 0x0, "Miscellaneous PCI Plug-in"},
        {HPHW_FIO, 0x00A, 0x000A9, 0x0, "Lego 360 Core PCI SuperIO RS-232"}, 
        {HPHW_FIO, 0x00A, 0x000A9, 0x0, "Lego 360 Core PCI USB KB"}, 
        {HPHW_FIO, 0x004, 0x00320, 0x0, "Metheus Frame Buffer"}, 
index 2ce3806f02e1989d5157ac9c9a3a037f40a384fc..58fccc96d0035362aaada7b17521c1346bb15a61 100644 (file)
@@ -333,7 +333,7 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
        flush_user_icache_range((unsigned long) &frame->tramp[0],
                           (unsigned long) &frame->tramp[TRAMP_SIZE]);
 
-       /* TRAMP Words 0-4, Lenght 5 = SIGRESTARTBLOCK_TRAMP
+       /* TRAMP Words 0-4, Length 5 = SIGRESTARTBLOCK_TRAMP
         * TRAMP Words 5-9, Length 4 = SIGRETURN_TRAMP
         * So the SIGRETURN_TRAMP is at the end of SIGRESTARTBLOCK_TRAMP
         */
index 88ea64bd991af6b23f7fe6d56f953f9dffbe9b03..1348bbc9251031052cca137a805f6ee9c56c28c4 100644 (file)
@@ -42,7 +42,7 @@ config GENERIC_HARDIRQS
        bool
        default y
 
-config ARCH_SETS_UP_PER_CPU_AREA
+config HAVE_SETUP_PER_CPU_AREA
        def_bool PPC64
 
 config IRQ_PER_CPU
@@ -87,6 +87,8 @@ config ARCH_NO_VIRT_TO_BUS
 config PPC
        bool
        default y
+       select HAVE_OPROFILE
+       select HAVE_KPROBES
 
 config EARLY_PRINTK
        bool
@@ -151,11 +153,25 @@ config DEFAULT_UIMAGE
 config REDBOOT
        bool
 
-config PPC64_SWSUSP
+config HIBERNATE_32
        bool
-       depends on PPC64 && (BROKEN || (PPC_PMAC64 && EXPERIMENTAL))
+       depends on (PPC_PMAC && !SMP) || BROKEN
        default y
 
+config HIBERNATE_64
+       bool
+       depends on BROKEN || (PPC_PMAC64 && EXPERIMENTAL)
+       default y
+
+config ARCH_HIBERNATION_POSSIBLE
+       bool
+       depends on (PPC64 && HIBERNATE_64) || (PPC32 && HIBERNATE_32)
+       default y
+
+config ARCH_SUSPEND_POSSIBLE
+       def_bool y
+       depends on ADB_PMU || PPC_EFIKA || PPC_LITE5200
+
 config PPC_DCR_NATIVE
        bool
        default n
@@ -240,6 +256,9 @@ config IOMMU_VMERGE
 
          Most drivers don't have this problem; it is safe to say Y here.
 
+config IOMMU_HELPER
+       def_bool PPC64
+
 config HOTPLUG_CPU
        bool "Support for enabling/disabling CPUs"
        depends on SMP && HOTPLUG && EXPERIMENTAL && (PPC_PSERIES || PPC_PMAC)
@@ -391,6 +410,10 @@ config CMDLINE
          most cases you will need to specify the root device here.
 
 if !44x || BROKEN
+config ARCH_WANTS_FREEZER_CONTROL
+       def_bool y
+       depends on ADB_PMU
+
 source kernel/power/Kconfig
 endif
 
@@ -695,8 +718,6 @@ source "arch/powerpc/sysdev/qe_lib/Kconfig"
 
 source "lib/Kconfig"
 
-source "kernel/Kconfig.instrumentation"
-
 source "arch/powerpc/Kconfig.debug"
 
 source "security/Kconfig"
index 930bfb3894ebbf862966ea8629e583e89d0e15e3..28e9cd3d7a216c841ee8b8c6bd119b6194bed2cb 100644 (file)
                                compatible = "fsl,mpc875-brg",
                                             "fsl,cpm1-brg",
                                             "fsl,cpm-brg";
+                               clock-frequency = <50000000>;
                                reg = <0x9f0 0x10>;
                        };
 
index 0197242dacfb08945d2eb1ccb77520f819635434..54fb60ec03e540c06a37556f4535aa19c13ce959 100644 (file)
                                compatible = "fsl,mpc875-brg",
                                             "fsl,cpm1-brg",
                                             "fsl,cpm-brg";
+                               clock-frequency = <50000000>;
                                reg = <0x9f0 0x10>;
                        };
 
index 2d6653fe72ff578f91ead0ec74dbd46b7f8d1e05..e1f0dca8ac397324876f46aee281c08a2acc5e39 100644 (file)
                        interrupts = <14 0x8>;
                        interrupt-parent = <&ipic>;
                        dfsrr;
+                       rtc@68 {
+                               compatible = "dallas,ds1339";
+                               reg = <0x68>;
+                       };
                };
 
                i2c@3100 {
index b582032ba3d689fe3a7bba15c488b7d926de3ac9..d7a1ececa30f43fa7486e1669c869c8fdf224a70 100644 (file)
@@ -96,7 +96,7 @@
                #address-cells = <1>;
                #size-cells = <1>;
                device_type = "soc";
-               compatible = "simple-bus";
+               compatible = "fsl,mpc8315-immr", "simple-bus";
                ranges = <0 0xe0000000 0x00100000>;
                reg = <0xe0000000 0x00000200>;
                bus-frequency = <0>;
index 7480edae85edb46149110a9ab75afa57081efaa9..0199c5c548d80a5dfcfa843da5ad929b41a3ed1f 100644 (file)
                                 0xc000 0x0 0x0 0x3 &ipic 23 0x8
                                 0xc000 0x0 0x0 0x4 &ipic 20 0x8>;
                interrupt-parent = <&ipic>;
-               interrupts = <66 0x8>;
+               interrupts = <67 0x8>;
                bus-range = <0 0>;
                ranges = <0x02000000 0x0 0xb0000000 0xb0000000 0x0 0x10000000
                          0x42000000 0x0 0xa0000000 0xa0000000 0x0 0x10000000
index 813c259abbe5ca2f0b63477fd54e8787fc931f1b..db37214aee37a0851bbacffe70f64e565608c3f9 100644 (file)
                        bus-frequency = <0>;
                        clock-frequency = <0>;
                };
+
+               PowerPC,8572@1 {
+                       device_type = "cpu";
+                       reg = <1>;
+                       d-cache-line-size = <20>;       // 32 bytes
+                       i-cache-line-size = <20>;       // 32 bytes
+                       d-cache-size = <8000>;          // L1, 32K
+                       i-cache-size = <8000>;          // L1, 32K
+                       timebase-frequency = <0>;
+                       bus-frequency = <0>;
+                       clock-frequency = <0>;
+               };
        };
 
        memory {
index 8848e637293e64244cf629ce11220202569dd997..d84a012c2aaf10340daa1d6c9c24d67070b0a21c 100644 (file)
                                compatible = "fsl,mpc885-brg",
                                             "fsl,cpm1-brg",
                                             "fsl,cpm-brg";
+                               clock-frequency = <0>;
                                reg = <9f0 10>;
                        };
 
index 2204874ac5f3e5026d123d3a5bbd52530879dac2..5893816c0bcecc5b18ec1653c1cbb2e5c3cc8c1c 100644 (file)
@@ -15,7 +15,7 @@
 
 / {
        model = "StorCenter";
-       compatible = "storcenter";
+       compatible = "iomega,storcenter";
        #address-cells = <1>;
        #size-cells = <1>;
 
                        #size-cells = <0>;
                        compatible = "fsl-i2c";
                        reg = <0x3000 0x100>;
-                       interrupts = <5 2>;
+                       interrupts = <17 2>;
                        interrupt-parent = <&mpic>;
 
                        rtc@68 {
                                compatible = "dallas,ds1337";
-                               reg = <68>;
+                               reg = <0x68>;
                        };
                };
 
@@ -78,7 +78,7 @@
                        reg = <0x4500 0x20>;
                        clock-frequency = <97553800>; /* Hz */
                        current-speed = <115200>;
-                       interrupts = <9 2>;
+                       interrupts = <25 2>;
                        interrupt-parent = <&mpic>;
                };
 
@@ -89,7 +89,7 @@
                        reg = <0x4600 0x20>;
                        clock-frequency = <97553800>; /* Hz */
                        current-speed = <9600>;
-                       interrupts = <10 2>;
+                       interrupts = <26 2>;
                        interrupt-parent = <&mpic>;
                };
 
        };
 
        chosen {
-               linux,stdout-path = "/soc/serial@4500";
+               linux,stdout-path = &serial0;
        };
 };
index 31bdbf3f7566f8d09627953a96b49efa4d96fc48..a9807f083bc499e16e5bf1c8ab4b4a6f3050f0a4 100644 (file)
@@ -186,7 +186,7 @@ CONFIG_PREEMPT_NONE=y
 # CONFIG_PREEMPT is not set
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_MISC is not set
-# CONFIG_MATH_EMULATION is not set
+CONFIG_MATH_EMULATION=y
 CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
 CONFIG_ARCH_FLATMEM_ENABLE=y
 CONFIG_ARCH_POPULATES_NODE_MAP=y
@@ -416,14 +416,14 @@ CONFIG_PHYLIB=y
 # MII PHY device drivers
 #
 CONFIG_MARVELL_PHY=y
-# CONFIG_DAVICOM_PHY is not set
+CONFIG_DAVICOM_PHY=y
 # CONFIG_QSEMI_PHY is not set
 # CONFIG_LXT_PHY is not set
 # CONFIG_CICADA_PHY is not set
-# CONFIG_VITESSE_PHY is not set
+CONFIG_VITESSE_PHY=y
 # CONFIG_SMSC_PHY is not set
 # CONFIG_BROADCOM_PHY is not set
-# CONFIG_ICPLUS_PHY is not set
+CONFIG_ICPLUS_PHY=y
 # CONFIG_FIXED_PHY is not set
 # CONFIG_MDIO_BITBANG is not set
 CONFIG_NET_ETHERNET=y
@@ -436,7 +436,7 @@ CONFIG_MII=y
 CONFIG_NETDEV_1000=y
 CONFIG_GIANFAR=y
 # CONFIG_GFAR_NAPI is not set
-# CONFIG_UCC_GETH is not set
+CONFIG_UCC_GETH=y
 CONFIG_NETDEV_10000=y
 
 #
index ed083feaf6f9763df72e9458d40552c4927ba611..e6e49289f7882dd11494d9208168e253f806de21 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/mman.h>
 #include <linux/mm.h>
 #include <linux/suspend.h>
+#include <linux/hrtimer.h>
 #ifdef CONFIG_PPC64
 #include <linux/time.h>
 #include <linux/hardirq.h>
@@ -312,7 +313,7 @@ int main(void)
        DEFINE(CLOCK_REALTIME, CLOCK_REALTIME);
        DEFINE(CLOCK_MONOTONIC, CLOCK_MONOTONIC);
        DEFINE(NSEC_PER_SEC, NSEC_PER_SEC);
-       DEFINE(CLOCK_REALTIME_RES, TICK_NSEC);
+       DEFINE(CLOCK_REALTIME_RES, (KTIME_MONOTONIC_RES).tv64);
 
 #ifdef CONFIG_BUG
        DEFINE(BUG_ENTRY_SIZE, sizeof(struct bug_entry));
index a4c2771b5e6282b9264e4b038c9192a1ccfafc64..2a8f5cc5184f0c02641b7ba78aad7ba3c95367c4 100644 (file)
@@ -959,6 +959,9 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
                .cpu_setup              = __setup_cpu_603,
+               .num_pmcs               = 4,
+               .oprofile_cpu_type      = "ppc/e300",
+               .oprofile_type          = PPC_OPROFILE_FSL_EMB,
                .platform               = "ppc603",
        },
        {       /* e300c4 (e300c1, plus one IU) */
@@ -971,6 +974,9 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .dcache_bsize           = 32,
                .cpu_setup              = __setup_cpu_603,
                .machine_check          = machine_check_generic,
+               .num_pmcs               = 4,
+               .oprofile_cpu_type      = "ppc/e300",
+               .oprofile_type          = PPC_OPROFILE_FSL_EMB,
                .platform               = "ppc603",
        },
        {       /* default match, we assume split I/D cache & TB (non-601)... */
@@ -1435,7 +1441,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .dcache_bsize           = 32,
                .num_pmcs               = 4,
                .oprofile_cpu_type      = "ppc/e500",
-               .oprofile_type          = PPC_OPROFILE_BOOKE,
+               .oprofile_type          = PPC_OPROFILE_FSL_EMB,
                .machine_check          = machine_check_e500,
                .platform               = "ppc8540",
        },
@@ -1453,7 +1459,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .dcache_bsize           = 32,
                .num_pmcs               = 4,
                .oprofile_cpu_type      = "ppc/e500",
-               .oprofile_type          = PPC_OPROFILE_BOOKE,
+               .oprofile_type          = PPC_OPROFILE_FSL_EMB,
                .machine_check          = machine_check_e500,
                .platform               = "ppc8548",
        },
index 84239076a5b8e8092e7ad2d607ba16b0e0cff7a9..3a317cb0636a4f572790982648b65c077bb84b30 100644 (file)
@@ -31,8 +31,8 @@ static inline unsigned long device_to_mask(struct device *dev)
 static void *dma_iommu_alloc_coherent(struct device *dev, size_t size,
                                      dma_addr_t *dma_handle, gfp_t flag)
 {
-       return iommu_alloc_coherent(dev->archdata.dma_data, size, dma_handle,
-                                   device_to_mask(dev), flag,
+       return iommu_alloc_coherent(dev, dev->archdata.dma_data, size,
+                                   dma_handle, device_to_mask(dev), flag,
                                    dev->archdata.numa_node);
 }
 
@@ -52,7 +52,7 @@ static dma_addr_t dma_iommu_map_single(struct device *dev, void *vaddr,
                                       size_t size,
                                       enum dma_data_direction direction)
 {
-       return iommu_map_single(dev->archdata.dma_data, vaddr, size,
+       return iommu_map_single(dev, dev->archdata.dma_data, vaddr, size,
                                device_to_mask(dev), direction);
 }
 
@@ -68,7 +68,7 @@ static void dma_iommu_unmap_single(struct device *dev, dma_addr_t dma_handle,
 static int dma_iommu_map_sg(struct device *dev, struct scatterlist *sglist,
                            int nelems, enum dma_data_direction direction)
 {
-       return iommu_map_sg(dev->archdata.dma_data, sglist, nelems,
+       return iommu_map_sg(dev, sglist, nelems,
                            device_to_mask(dev), direction);
 }
 
index a3c406aca6643d04ed6a7351086bfa0d1a4b2738..8f1f4e539c4bdfe57d9c5a1c1fe2232f9370062f 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/string.h>
 #include <linux/dma-mapping.h>
 #include <linux/bitops.h>
+#include <linux/iommu-helper.h>
 #include <asm/io.h>
 #include <asm/prom.h>
 #include <asm/iommu.h>
@@ -81,17 +82,19 @@ static int __init setup_iommu(char *str)
 __setup("protect4gb=", setup_protect4gb);
 __setup("iommu=", setup_iommu);
 
-static unsigned long iommu_range_alloc(struct iommu_table *tbl,
+static unsigned long iommu_range_alloc(struct device *dev,
+                                      struct iommu_table *tbl,
                                        unsigned long npages,
                                        unsigned long *handle,
                                        unsigned long mask,
                                        unsigned int align_order)
 { 
-       unsigned long n, end, i, start;
+       unsigned long n, end, start;
        unsigned long limit;
        int largealloc = npages > 15;
        int pass = 0;
        unsigned long align_mask;
+       unsigned long boundary_size;
 
        align_mask = 0xffffffffffffffffl >> (64 - align_order);
 
@@ -136,14 +139,17 @@ static unsigned long iommu_range_alloc(struct iommu_table *tbl,
                        start &= mask;
        }
 
-       n = find_next_zero_bit(tbl->it_map, limit, start);
-
-       /* Align allocation */
-       n = (n + align_mask) & ~align_mask;
-
-       end = n + npages;
+       if (dev)
+               boundary_size = ALIGN(dma_get_seg_boundary(dev) + 1,
+                                     1 << IOMMU_PAGE_SHIFT);
+       else
+               boundary_size = ALIGN(1UL << 32, 1 << IOMMU_PAGE_SHIFT);
+       /* 4GB boundary for iseries_hv_alloc and iseries_hv_map */
 
-       if (unlikely(end >= limit)) {
+       n = iommu_area_alloc(tbl->it_map, limit, start, npages,
+                            tbl->it_offset, boundary_size >> IOMMU_PAGE_SHIFT,
+                            align_mask);
+       if (n == -1) {
                if (likely(pass < 2)) {
                        /* First failure, just rescan the half of the table.
                         * Second failure, rescan the other half of the table.
@@ -158,14 +164,7 @@ static unsigned long iommu_range_alloc(struct iommu_table *tbl,
                }
        }
 
-       for (i = n; i < end; i++)
-               if (test_bit(i, tbl->it_map)) {
-                       start = i+1;
-                       goto again;
-               }
-
-       for (i = n; i < end; i++)
-               __set_bit(i, tbl->it_map);
+       end = n + npages;
 
        /* Bump the hint to a new block for small allocs. */
        if (largealloc) {
@@ -184,16 +183,17 @@ static unsigned long iommu_range_alloc(struct iommu_table *tbl,
        return n;
 }
 
-static dma_addr_t iommu_alloc(struct iommu_table *tbl, void *page,
-                      unsigned int npages, enum dma_data_direction direction,
-                      unsigned long mask, unsigned int align_order)
+static dma_addr_t iommu_alloc(struct device *dev, struct iommu_table *tbl,
+                             void *page, unsigned int npages,
+                             enum dma_data_direction direction,
+                             unsigned long mask, unsigned int align_order)
 {
        unsigned long entry, flags;
        dma_addr_t ret = DMA_ERROR_CODE;
 
        spin_lock_irqsave(&(tbl->it_lock), flags);
 
-       entry = iommu_range_alloc(tbl, npages, NULL, mask, align_order);
+       entry = iommu_range_alloc(dev, tbl, npages, NULL, mask, align_order);
 
        if (unlikely(entry == DMA_ERROR_CODE)) {
                spin_unlock_irqrestore(&(tbl->it_lock), flags);
@@ -224,7 +224,6 @@ static void __iommu_free(struct iommu_table *tbl, dma_addr_t dma_addr,
                         unsigned int npages)
 {
        unsigned long entry, free_entry;
-       unsigned long i;
 
        entry = dma_addr >> IOMMU_PAGE_SHIFT;
        free_entry = entry - tbl->it_offset;
@@ -246,9 +245,7 @@ static void __iommu_free(struct iommu_table *tbl, dma_addr_t dma_addr,
        }
 
        ppc_md.tce_free(tbl, entry, npages);
-       
-       for (i = 0; i < npages; i++)
-               __clear_bit(free_entry+i, tbl->it_map);
+       iommu_area_free(tbl->it_map, free_entry, npages);
 }
 
 static void iommu_free(struct iommu_table *tbl, dma_addr_t dma_addr,
@@ -270,16 +267,18 @@ static void iommu_free(struct iommu_table *tbl, dma_addr_t dma_addr,
        spin_unlock_irqrestore(&(tbl->it_lock), flags);
 }
 
-int iommu_map_sg(struct iommu_table *tbl, struct scatterlist *sglist,
+int iommu_map_sg(struct device *dev, struct scatterlist *sglist,
                 int nelems, unsigned long mask,
                 enum dma_data_direction direction)
 {
+       struct iommu_table *tbl = dev->archdata.dma_data;
        dma_addr_t dma_next = 0, dma_addr;
        unsigned long flags;
        struct scatterlist *s, *outs, *segstart;
        int outcount, incount, i;
        unsigned int align;
        unsigned long handle;
+       unsigned int max_seg_size;
 
        BUG_ON(direction == DMA_NONE);
 
@@ -298,6 +297,7 @@ int iommu_map_sg(struct iommu_table *tbl, struct scatterlist *sglist,
 
        spin_lock_irqsave(&(tbl->it_lock), flags);
 
+       max_seg_size = dma_get_max_seg_size(dev);
        for_each_sg(sglist, s, nelems, i) {
                unsigned long vaddr, npages, entry, slen;
 
@@ -314,7 +314,7 @@ int iommu_map_sg(struct iommu_table *tbl, struct scatterlist *sglist,
                if (IOMMU_PAGE_SHIFT < PAGE_SHIFT && slen >= PAGE_SIZE &&
                    (vaddr & ~PAGE_MASK) == 0)
                        align = PAGE_SHIFT - IOMMU_PAGE_SHIFT;
-               entry = iommu_range_alloc(tbl, npages, &handle,
+               entry = iommu_range_alloc(dev, tbl, npages, &handle,
                                          mask >> IOMMU_PAGE_SHIFT, align);
 
                DBG("  - vaddr: %lx, size: %lx\n", vaddr, slen);
@@ -344,7 +344,8 @@ int iommu_map_sg(struct iommu_table *tbl, struct scatterlist *sglist,
                        /* We cannot merge if:
                         * - allocated dma_addr isn't contiguous to previous allocation
                         */
-                       if (novmerge || (dma_addr != dma_next)) {
+                       if (novmerge || (dma_addr != dma_next) ||
+                           (outs->dma_length + s->length > max_seg_size)) {
                                /* Can't merge: create a new segment */
                                segstart = s;
                                outcount++;
@@ -452,9 +453,6 @@ void iommu_unmap_sg(struct iommu_table *tbl, struct scatterlist *sglist,
 struct iommu_table *iommu_init_table(struct iommu_table *tbl, int nid)
 {
        unsigned long sz;
-       unsigned long start_index, end_index;
-       unsigned long entries_per_4g;
-       unsigned long index;
        static int welcomed = 0;
        struct page *page;
 
@@ -476,6 +474,7 @@ struct iommu_table *iommu_init_table(struct iommu_table *tbl, int nid)
 
 #ifdef CONFIG_CRASH_DUMP
        if (ppc_md.tce_get) {
+               unsigned long index;
                unsigned long tceval;
                unsigned long tcecount = 0;
 
@@ -506,23 +505,6 @@ struct iommu_table *iommu_init_table(struct iommu_table *tbl, int nid)
        ppc_md.tce_free(tbl, tbl->it_offset, tbl->it_size);
 #endif
 
-       /*
-        * DMA cannot cross 4 GB boundary.  Mark last entry of each 4
-        * GB chunk as reserved.
-        */
-       if (protect4gb) {
-               entries_per_4g = 0x100000000l >> IOMMU_PAGE_SHIFT;
-
-               /* Mark the last bit before a 4GB boundary as used */
-               start_index = tbl->it_offset | (entries_per_4g - 1);
-               start_index -= tbl->it_offset;
-
-               end_index = tbl->it_size;
-
-               for (index = start_index; index < end_index - 1; index += entries_per_4g)
-                       __set_bit(index, tbl->it_map);
-       }
-
        if (!welcomed) {
                printk(KERN_INFO "IOMMU table initialized, virtual merging %s\n",
                       novmerge ? "disabled" : "enabled");
@@ -570,9 +552,9 @@ void iommu_free_table(struct iommu_table *tbl, const char *node_name)
  * need not be page aligned, the dma_addr_t returned will point to the same
  * byte within the page as vaddr.
  */
-dma_addr_t iommu_map_single(struct iommu_table *tbl, void *vaddr,
-               size_t size, unsigned long mask,
-               enum dma_data_direction direction)
+dma_addr_t iommu_map_single(struct device *dev, struct iommu_table *tbl,
+                           void *vaddr, size_t size, unsigned long mask,
+                           enum dma_data_direction direction)
 {
        dma_addr_t dma_handle = DMA_ERROR_CODE;
        unsigned long uaddr;
@@ -589,7 +571,7 @@ dma_addr_t iommu_map_single(struct iommu_table *tbl, void *vaddr,
                    ((unsigned long)vaddr & ~PAGE_MASK) == 0)
                        align = PAGE_SHIFT - IOMMU_PAGE_SHIFT;
 
-               dma_handle = iommu_alloc(tbl, vaddr, npages, direction,
+               dma_handle = iommu_alloc(dev, tbl, vaddr, npages, direction,
                                         mask >> IOMMU_PAGE_SHIFT, align);
                if (dma_handle == DMA_ERROR_CODE) {
                        if (printk_ratelimit())  {
@@ -621,8 +603,9 @@ void iommu_unmap_single(struct iommu_table *tbl, dma_addr_t dma_handle,
  * Returns the virtual address of the buffer and sets dma_handle
  * to the dma address (mapping) of the first page.
  */
-void *iommu_alloc_coherent(struct iommu_table *tbl, size_t size,
-               dma_addr_t *dma_handle, unsigned long mask, gfp_t flag, int node)
+void *iommu_alloc_coherent(struct device *dev, struct iommu_table *tbl,
+                          size_t size, dma_addr_t *dma_handle,
+                          unsigned long mask, gfp_t flag, int node)
 {
        void *ret = NULL;
        dma_addr_t mapping;
@@ -656,7 +639,7 @@ void *iommu_alloc_coherent(struct iommu_table *tbl, size_t size,
        /* Set up tces to cover the allocated range */
        nio_pages = size >> IOMMU_PAGE_SHIFT;
        io_order = get_iommu_order(size);
-       mapping = iommu_alloc(tbl, ret, nio_pages, DMA_BIDIRECTIONAL,
+       mapping = iommu_alloc(dev, tbl, ret, nio_pages, DMA_BIDIRECTIONAL,
                              mask >> IOMMU_PAGE_SHIFT, io_order);
        if (mapping == DMA_ERROR_CODE) {
                free_pages((unsigned long)ret, order);
index 76b862bd1fe9aab628afabc4180b120040b3b7a8..61dd17449ddceb06267babf5373505984f7abd9c 100644 (file)
@@ -36,7 +36,8 @@ static struct legacy_serial_info {
 static struct __initdata of_device_id parents[] = {
        {.type = "soc",},
        {.type = "tsi-bridge",},
-       {.type = "opb", .compatible = "ibm,opb",},
+       {.type = "opb", },
+       {.compatible = "ibm,opb",},
        {.compatible = "simple-bus",},
        {.compatible = "wrs,epld-localbus",},
 };
index ea04e0ab3f2f192cf4355d27a31f46180aced233..0516e2d3e02ea5b1807d2b17e5ed148118d6535c 100644 (file)
@@ -26,7 +26,7 @@
 
 static void dummy_perf(struct pt_regs *regs)
 {
-#if defined(CONFIG_FSL_BOOKE) && !defined(CONFIG_E200)
+#if defined(CONFIG_FSL_EMB_PERFMON)
        mtpmr(PMRN_PMGC0, mfpmr(PMRN_PMGC0) & ~PMGC0_PMIE);
 #elif defined(CONFIG_PPC64) || defined(CONFIG_6xx)
        if (cur_cpu_spec->pmc_type == PPC_PMC_IBM)
index f0bad7070fb54087d241f6a81bf9ea875f71156b..f98867252ee269afac74dba19e04a5c0a629a07f 100644 (file)
@@ -176,7 +176,7 @@ static void __devinit vio_dev_release(struct device *dev)
  * Returns a pointer to the created vio_dev or NULL if node has
  * NULL device_type or compatible fields.
  */
-struct vio_dev * __devinit vio_register_device_node(struct device_node *of_node)
+struct vio_dev *vio_register_device_node(struct device_node *of_node)
 {
        struct vio_dev *viodev;
        const unsigned int *unit_address;
index e8122447f019ef81b5346ab911f82bd3c4439cd6..c7d7bd43a251a2feeedfa89a6f8a33e0687dacb4 100644 (file)
@@ -483,7 +483,12 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long address,
                 */
                _tlbie(address, 0 /* 8xx doesn't care about PID */);
 #endif
-               if (!PageReserved(page)
+               /* The _PAGE_USER test should really be _PAGE_EXEC, but
+                * older glibc versions execute some code from no-exec
+                * pages, which for now we are supporting.  If exec-only
+                * pages are ever implemented, this will have to change.
+                */
+               if (!PageReserved(page) && (pte_val(pte) & _PAGE_USER)
                    && !test_bit(PG_arch_1, &page->flags)) {
                        if (vma->vm_mm == current->active_mm) {
                                __flush_dcache_icache((void *) address);
index 64488723162a371b05f0148f8f54a413f428eed8..f80f90c4d58be2b277dd6bb6d602b43678b6dbad 100644 (file)
@@ -86,7 +86,7 @@ pgd_t *pgd_alloc(struct mm_struct *mm)
        return ret;
 }
 
-void pgd_free(pgd_t *pgd)
+void pgd_free(struct mm_struct *mm, pgd_t *pgd)
 {
        free_pages((unsigned long)pgd, PGDIR_ORDER);
 }
@@ -123,7 +123,7 @@ struct page *pte_alloc_one(struct mm_struct *mm, unsigned long address)
        return ptepage;
 }
 
-void pte_free_kernel(pte_t *pte)
+void pte_free_kernel(struct mm_struct *mm, pte_t *pte)
 {
 #ifdef CONFIG_SMP
        hash_page_sync();
@@ -131,7 +131,7 @@ void pte_free_kernel(pte_t *pte)
        free_page((unsigned long)pte);
 }
 
-void pte_free(struct page *ptepage)
+void pte_free(struct mm_struct *mm, struct page *ptepage)
 {
 #ifdef CONFIG_SMP
        hash_page_sync();
index c5f64c3bd668a21615dcc714c96a144a272bbcfe..2ef6b0dddd8c3fec59df6ea6db780facd6171d36 100644 (file)
@@ -15,5 +15,5 @@ oprofile-$(CONFIG_OPROFILE_CELL) += op_model_cell.o \
                cell/spu_profiler.o cell/vma_map.o \
                cell/spu_task_sync.o
 oprofile-$(CONFIG_PPC64) += op_model_rs64.o op_model_power4.o op_model_pa6t.o
-oprofile-$(CONFIG_FSL_BOOKE) += op_model_fsl_booke.o
+oprofile-$(CONFIG_FSL_EMB_PERFMON) += op_model_fsl_emb.o
 oprofile-$(CONFIG_6xx) += op_model_7450.o
index a28cce1d6c24628b82a5e01eb40677557b0bf23f..4908dc98f9caa2368129a7c7f16ed477ec1bebec 100644 (file)
@@ -202,9 +202,9 @@ int __init oprofile_arch_init(struct oprofile_operations *ops)
                        model = &op_model_7450;
                        break;
 #endif
-#ifdef CONFIG_FSL_BOOKE
-               case PPC_OPROFILE_BOOKE:
-                       model = &op_model_fsl_booke;
+#if defined(CONFIG_FSL_EMB_PERFMON)
+               case PPC_OPROFILE_FSL_EMB:
+                       model = &op_model_fsl_emb;
                        break;
 #endif
                default:
similarity index 90%
rename from arch/powerpc/oprofile/op_model_fsl_booke.c
rename to arch/powerpc/oprofile/op_model_fsl_emb.c
index 183a28bb1812e7b57f503acc1abbb0d18ec64d8d..91596f6ba1f497e4c277150922c105c662bc7a3c 100644 (file)
@@ -1,7 +1,5 @@
 /*
- * arch/powerpc/oprofile/op_model_fsl_booke.c
- *
- * Freescale Book-E oprofile support, based on ppc64 oprofile support
+ * Freescale Embedded oprofile support, based on ppc64 oprofile support
  * Copyright (C) 2004 Anton Blanchard <anton@au.ibm.com>, IBM
  *
  * Copyright (c) 2004 Freescale Semiconductor, Inc
@@ -22,7 +20,7 @@
 #include <asm/system.h>
 #include <asm/processor.h>
 #include <asm/cputable.h>
-#include <asm/reg_booke.h>
+#include <asm/reg_fsl_emb.h>
 #include <asm/page.h>
 #include <asm/pmc.h>
 #include <asm/oprofile_impl.h>
@@ -244,7 +242,7 @@ static void dump_pmcs(void)
                        mfpmr(PMRN_PMLCA3), mfpmr(PMRN_PMLCB3));
 }
 
-static int fsl_booke_cpu_setup(struct op_counter_config *ctr)
+static int fsl_emb_cpu_setup(struct op_counter_config *ctr)
 {
        int i;
 
@@ -262,7 +260,7 @@ static int fsl_booke_cpu_setup(struct op_counter_config *ctr)
        return 0;
 }
 
-static int fsl_booke_reg_setup(struct op_counter_config *ctr,
+static int fsl_emb_reg_setup(struct op_counter_config *ctr,
                             struct op_system_config *sys,
                             int num_ctrs)
 {
@@ -281,7 +279,7 @@ static int fsl_booke_reg_setup(struct op_counter_config *ctr,
        return 0;
 }
 
-static int fsl_booke_start(struct op_counter_config *ctr)
+static int fsl_emb_start(struct op_counter_config *ctr)
 {
        int i;
 
@@ -315,7 +313,7 @@ static int fsl_booke_start(struct op_counter_config *ctr)
        return 0;
 }
 
-static void fsl_booke_stop(void)
+static void fsl_emb_stop(void)
 {
        /* freeze counters */
        pmc_stop_ctrs();
@@ -329,7 +327,7 @@ static void fsl_booke_stop(void)
 }
 
 
-static void fsl_booke_handle_interrupt(struct pt_regs *regs,
+static void fsl_emb_handle_interrupt(struct pt_regs *regs,
                                    struct op_counter_config *ctr)
 {
        unsigned long pc;
@@ -362,10 +360,10 @@ static void fsl_booke_handle_interrupt(struct pt_regs *regs,
        pmc_start_ctrs(1);
 }
 
-struct op_powerpc_model op_model_fsl_booke = {
-       .reg_setup              = fsl_booke_reg_setup,
-       .cpu_setup              = fsl_booke_cpu_setup,
-       .start                  = fsl_booke_start,
-       .stop                   = fsl_booke_stop,
-       .handle_interrupt       = fsl_booke_handle_interrupt,
+struct op_powerpc_model op_model_fsl_emb = {
+       .reg_setup              = fsl_emb_reg_setup,
+       .cpu_setup              = fsl_emb_cpu_setup,
+       .start                  = fsl_emb_start,
+       .stop                   = fsl_emb_stop,
+       .handle_interrupt       = fsl_emb_handle_interrupt,
 };
index c0f13e8deb0b482936528761e040fd8fd026e048..41c7fd91e99e5836cbaef5c7d6803334bc37a206 100644 (file)
@@ -31,7 +31,7 @@ static int lite5200_pm_valid(suspend_state_t state)
        }
 }
 
-static int lite5200_pm_set_target(suspend_state_t state)
+static int lite5200_pm_begin(suspend_state_t state)
 {
        if (lite5200_pm_valid(state)) {
                lite5200_pm_target_state = state;
@@ -219,12 +219,18 @@ static void lite5200_pm_finish(void)
                mpc52xx_pm_finish();
 }
 
+static void lite5200_pm_end(void)
+{
+       lite5200_pm_target_state = PM_SUSPEND_ON;
+}
+
 static struct platform_suspend_ops lite5200_pm_ops = {
        .valid          = lite5200_pm_valid,
-       .set_target     = lite5200_pm_set_target,
+       .begin          = lite5200_pm_begin,
        .prepare        = lite5200_pm_prepare,
        .enter          = lite5200_pm_enter,
        .finish         = lite5200_pm_finish,
+       .end            = lite5200_pm_end,
 };
 
 int __init lite5200_pm_init(void)
index 3fce6b375dbc5f1d709701281987af8a2f483647..7d3018751988b4994d9024dca1dc38ce88b934f0 100644 (file)
@@ -134,13 +134,12 @@ static void __init mpc8272_ads_setup_arch(void)
        }
 
        bcsr = of_iomap(np, 0);
+       of_node_put(np);
        if (!bcsr) {
                printk(KERN_ERR "Cannot map BCSR registers\n");
                return;
        }
 
-       of_node_put(np);
-
        clrbits32(&bcsr[1], BCSR1_RS232_EN1 | BCSR1_RS232_EN2 | BCSR1_FETHIEN);
        setbits32(&bcsr[1], BCSR1_FETH_RST);
 
index 68196e349994afd50d5de9f07e826facc5494c90..e1dceeec49944aba3e07ecb967abe37e07c822bf 100644 (file)
@@ -130,13 +130,12 @@ static void __init pq2fads_setup_arch(void)
        }
 
        bcsr = of_iomap(np, 0);
+       of_node_put(np);
        if (!bcsr) {
                printk(KERN_ERR "Cannot map BCSR registers\n");
                return;
        }
 
-       of_node_put(np);
-
        /* Enable the serial and ethernet ports */
 
        clrbits32(&bcsr[1], BCSR1_RS232_EN1 | BCSR1_RS232_EN2 | BCSR1_FETHIEN);
index 9f0fd88b2b1f16e1a6126436fd9635ab2e5f19ae..e7f706b624feeb574a3e7f3a91d34c5b39192c0e 100644 (file)
@@ -101,7 +101,7 @@ static void __init mpc832x_rdb_setup_arch(void)
 #ifdef CONFIG_QUICC_ENGINE
        qe_reset();
 
-       if ((np = of_find_node_by_name(np, "par_io")) != NULL) {
+       if ((np = of_find_node_by_name(NULL, "par_io")) != NULL) {
                par_io_init(np);
                of_node_put(np);
 
index 88bb748aff0d7568a06aa7ffac4455afbd942c05..68065e62fc3d35faa42e69974ead970f13e154ed 100644 (file)
@@ -14,6 +14,8 @@
 #define MPC83XX_SCCR_USB_DRCM_11   0x00300000
 #define MPC83XX_SCCR_USB_DRCM_01   0x00100000
 #define MPC83XX_SCCR_USB_DRCM_10   0x00200000
+#define MPC8315_SCCR_USB_MASK      0x00c00000
+#define MPC8315_SCCR_USB_DRCM_11   0x00c00000
 #define MPC837X_SCCR_USB_DRCM_11   0x00c00000
 
 /* system i/o configuration register low */
index 681230a30acd7029cc10a0041b3c74567a781348..471fdd8f41084b629bc962534bc58dce2fadee93 100644 (file)
@@ -104,6 +104,7 @@ int mpc831x_usb_cfg(void)
        u32 temp;
        void __iomem *immap, *usb_regs;
        struct device_node *np = NULL;
+       struct device_node *immr_node = NULL;
        const void *prop;
        struct resource res;
        int ret = 0;
@@ -124,10 +125,15 @@ int mpc831x_usb_cfg(void)
        }
 
        /* Configure clock */
-       temp = in_be32(immap + MPC83XX_SCCR_OFFS);
-       temp &= ~MPC83XX_SCCR_USB_MASK;
-       temp |= MPC83XX_SCCR_USB_DRCM_11;  /* 1:3 */
-       out_be32(immap + MPC83XX_SCCR_OFFS, temp);
+       immr_node = of_get_parent(np);
+       if (immr_node && of_device_is_compatible(immr_node, "fsl,mpc8315-immr"))
+               clrsetbits_be32(immap + MPC83XX_SCCR_OFFS,
+                               MPC8315_SCCR_USB_MASK,
+                               MPC8315_SCCR_USB_DRCM_11);
+       else
+               clrsetbits_be32(immap + MPC83XX_SCCR_OFFS,
+                               MPC83XX_SCCR_USB_MASK,
+                               MPC83XX_SCCR_USB_DRCM_11);
 
        /* Configure pin mux for ULPI.  There is no pin mux for UTMI */
        if (prop && !strcmp(prop, "ulpi")) {
@@ -144,6 +150,9 @@ int mpc831x_usb_cfg(void)
 
        iounmap(immap);
 
+       if (immr_node)
+               of_node_put(immr_node);
+
        /* Map USB SOC space */
        ret = of_address_to_resource(np, 0, &res);
        if (ret) {
index c6bc0783c3b0819074d24b14f4f71b71beb25a9e..82363e98f50e4bc05240df0c147e65a3168b2c65 100644 (file)
 
 #include <asm/time.h>
 #include <asm/machdep.h>
-#include <asm/commproc.h>
+#include <asm/cpm1.h>
 #include <asm/fs_pd.h>
 #include <asm/udbg.h>
 #include <asm/prom.h>
 
-#include <sysdev/commproc.h>
+#include "mpc8xx.h"
 
 struct cpm_pin {
        int port, pin, flags;
@@ -108,7 +108,7 @@ define_machine(adder875) {
        .name = "Adder MPC875",
        .probe = adder875_probe,
        .setup_arch = adder875_setup,
-       .init_IRQ = m8xx_pic_init,
+       .init_IRQ = mpc8xx_pics_init,
        .get_irq = mpc8xx_get_irq,
        .restart = mpc8xx_restart,
        .calibrate_decr = generic_calibrate_decr,
index a8dffa005775f167b02949b04f58d9d38a296f0e..7d9ac6040d631f7f4bc19edb37056999249e3c40 100644 (file)
@@ -15,7 +15,6 @@
 #include <asm/machdep.h>
 #include <asm/io.h>
 #include <asm/udbg.h>
-#include <asm/commproc.h>
 #include <asm/cpm1.h>
 
 #include "mpc8xx.h"
index e2c952619805c7e8a05de3196b94e1ad7170d090..fcedbec07f94fe7478f50f19833afe3b9c87a20e 100644 (file)
@@ -24,6 +24,7 @@ config PPC_83xx
        select MPC83xx
        select IPIC
        select WANT_DEVICE_TREE
+       select FSL_EMB_PERFMON
 
 config PPC_86xx
        bool "Freescale 86xx"
index 51030ab2a023a5aeae4b567cf91f767e7955e5d8..69941ba709753fe0972f125aa2121c857161aa3d 100644 (file)
@@ -94,6 +94,7 @@ config 8xx
        bool
 
 config E500
+       select FSL_EMB_PERFMON
        bool
 
 config PPC_FPU
@@ -115,6 +116,9 @@ config FSL_BOOKE
        depends on E200 || E500
        default y
 
+config FSL_EMB_PERFMON
+       bool
+
 config PTE_64BIT
        bool
        depends on 44x || E500
index 3a963b4a9be0fcca0457e97a980f37bc6a63f4a9..2f169991896d9a2d8e33524df82675e2d5e2278b 100644 (file)
@@ -54,6 +54,13 @@ config SPU_FS_64K_LS
          uses 4K pages. This can improve performances of applications
          using multiple SPEs by lowering the TLB pressure on them.
 
+config SPU_TRACE
+       tristate "SPU event tracing support"
+       depends on SPU_FS && MARKERS
+       help
+         This option allows reading a trace of spu-related events through
+         the sputrace file in procfs.
+
 config SPU_BASE
        bool
        default n
index 095988f13bf4de8eca56f1c16457751dfb198a72..d95e71dee91f85f000a1662c200f2075b6bec95f 100644 (file)
@@ -13,7 +13,7 @@
 #include <linux/kernel.h>
 #include <linux/pci.h>
 #include <linux/msi.h>
-#include <linux/reboot.h>
+#include <linux/of_platform.h>
 
 #include <asm/dcr.h>
 #include <asm/machdep.h>
 
 struct axon_msic {
        struct irq_host *irq_host;
-       __le32 *fifo;
+       __le32 *fifo_virt;
+       dma_addr_t fifo_phys;
        dcr_host_t dcr_host;
-       struct list_head list;
        u32 read_offset;
 };
 
-static LIST_HEAD(axon_msic_list);
-
 static void msic_dcr_write(struct axon_msic *msic, unsigned int dcr_n, u32 val)
 {
        pr_debug("axon_msi: dcr_write(0x%x, 0x%x)\n", val, dcr_n);
@@ -94,7 +92,7 @@ static void axon_msi_cascade(unsigned int irq, struct irq_desc *desc)
 
        while (msic->read_offset != write_offset) {
                idx  = msic->read_offset / sizeof(__le32);
-               msi  = le32_to_cpu(msic->fifo[idx]);
+               msi  = le32_to_cpu(msic->fifo_virt[idx]);
                msi &= 0xFFFF;
 
                pr_debug("axon_msi: woff %x roff %x msi %x\n",
@@ -139,6 +137,7 @@ static struct axon_msic *find_msi_translator(struct pci_dev *dev)
 
        tmp = dn;
        dn = of_find_node_by_phandle(*ph);
+       of_node_put(tmp);
        if (!dn) {
                dev_dbg(&dev->dev,
                        "axon_msi: msi-translator doesn't point to a node\n");
@@ -156,7 +155,6 @@ static struct axon_msic *find_msi_translator(struct pci_dev *dev)
 
 out_error:
        of_node_put(dn);
-       of_node_put(tmp);
 
        return msic;
 }
@@ -292,30 +290,24 @@ static struct irq_host_ops msic_host_ops = {
        .map    = msic_host_map,
 };
 
-static int axon_msi_notify_reboot(struct notifier_block *nb,
-                                 unsigned long code, void *data)
+static int axon_msi_shutdown(struct of_device *device)
 {
-       struct axon_msic *msic;
+       struct axon_msic *msic = device->dev.platform_data;
        u32 tmp;
 
-       list_for_each_entry(msic, &axon_msic_list, list) {
-               pr_debug("axon_msi: disabling %s\n",
-                         msic->irq_host->of_node->full_name);
-               tmp  = dcr_read(msic->dcr_host, MSIC_CTRL_REG);
-               tmp &= ~MSIC_CTRL_ENABLE & ~MSIC_CTRL_IRQ_ENABLE;
-               msic_dcr_write(msic, MSIC_CTRL_REG, tmp);
-       }
+       pr_debug("axon_msi: disabling %s\n",
+                 msic->irq_host->of_node->full_name);
+       tmp  = dcr_read(msic->dcr_host, MSIC_CTRL_REG);
+       tmp &= ~MSIC_CTRL_ENABLE & ~MSIC_CTRL_IRQ_ENABLE;
+       msic_dcr_write(msic, MSIC_CTRL_REG, tmp);
 
        return 0;
 }
 
-static struct notifier_block axon_msi_reboot_notifier = {
-       .notifier_call = axon_msi_notify_reboot
-};
-
-static int axon_msi_setup_one(struct device_node *dn)
+static int axon_msi_probe(struct of_device *device,
+                         const struct of_device_id *device_id)
 {
-       struct page *page;
+       struct device_node *dn = device->node;
        struct axon_msic *msic;
        unsigned int virq;
        int dcr_base, dcr_len;
@@ -346,16 +338,14 @@ static int axon_msi_setup_one(struct device_node *dn)
                goto out_free_msic;
        }
 
-       page = alloc_pages_node(of_node_to_nid(dn), GFP_KERNEL,
-                               get_order(MSIC_FIFO_SIZE_BYTES));
-       if (!page) {
+       msic->fifo_virt = dma_alloc_coherent(&device->dev, MSIC_FIFO_SIZE_BYTES,
+                                            &msic->fifo_phys, GFP_KERNEL);
+       if (!msic->fifo_virt) {
                printk(KERN_ERR "axon_msi: couldn't allocate fifo for %s\n",
                       dn->full_name);
                goto out_free_msic;
        }
 
-       msic->fifo = page_address(page);
-
        msic->irq_host = irq_alloc_host(of_node_get(dn), IRQ_HOST_MAP_NOMAP,
                                        NR_IRQS, &msic_host_ops, 0);
        if (!msic->irq_host) {
@@ -378,14 +368,18 @@ static int axon_msi_setup_one(struct device_node *dn)
        pr_debug("axon_msi: irq 0x%x setup for axon_msi\n", virq);
 
        /* Enable the MSIC hardware */
-       msic_dcr_write(msic, MSIC_BASE_ADDR_HI_REG, (u64)msic->fifo >> 32);
+       msic_dcr_write(msic, MSIC_BASE_ADDR_HI_REG, msic->fifo_phys >> 32);
        msic_dcr_write(msic, MSIC_BASE_ADDR_LO_REG,
-                                 (u64)msic->fifo & 0xFFFFFFFF);
+                                 msic->fifo_phys & 0xFFFFFFFF);
        msic_dcr_write(msic, MSIC_CTRL_REG,
                        MSIC_CTRL_IRQ_ENABLE | MSIC_CTRL_ENABLE |
                        MSIC_CTRL_FIFO_SIZE);
 
-       list_add(&msic->list, &axon_msic_list);
+       device->dev.platform_data = msic;
+
+       ppc_md.setup_msi_irqs = axon_msi_setup_msi_irqs;
+       ppc_md.teardown_msi_irqs = axon_msi_teardown_msi_irqs;
+       ppc_md.msi_check_device = axon_msi_check_device;
 
        printk(KERN_DEBUG "axon_msi: setup MSIC on %s\n", dn->full_name);
 
@@ -394,7 +388,8 @@ static int axon_msi_setup_one(struct device_node *dn)
 out_free_host:
        kfree(msic->irq_host);
 out_free_fifo:
-       __free_pages(virt_to_page(msic->fifo), get_order(MSIC_FIFO_SIZE_BYTES));
+       dma_free_coherent(&device->dev, MSIC_FIFO_SIZE_BYTES, msic->fifo_virt,
+                         msic->fifo_phys);
 out_free_msic:
        kfree(msic);
 out:
@@ -402,28 +397,24 @@ out:
        return -1;
 }
 
-static int axon_msi_init(void)
-{
-       struct device_node *dn;
-       int found = 0;
-
-       pr_debug("axon_msi: initialising ...\n");
-
-       for_each_compatible_node(dn, NULL, "ibm,axon-msic") {
-               if (axon_msi_setup_one(dn) == 0)
-                       found++;
-       }
-
-       if (found) {
-               ppc_md.setup_msi_irqs = axon_msi_setup_msi_irqs;
-               ppc_md.teardown_msi_irqs = axon_msi_teardown_msi_irqs;
-               ppc_md.msi_check_device = axon_msi_check_device;
-
-               register_reboot_notifier(&axon_msi_reboot_notifier);
+static const struct of_device_id axon_msi_device_id[] = {
+       {
+               .compatible     = "ibm,axon-msic"
+       },
+       {}
+};
 
-               pr_debug("axon_msi: registered callbacks!\n");
-       }
+static struct of_platform_driver axon_msi_driver = {
+       .match_table    = axon_msi_device_id,
+       .probe          = axon_msi_probe,
+       .shutdown       = axon_msi_shutdown,
+       .driver         = {
+               .name   = "axon-msi"
+       },
+};
 
-       return 0;
+static int __init axon_msi_init(void)
+{
+       return of_register_platform_driver(&axon_msi_driver);
 }
-arch_initcall(axon_msi_init);
+subsys_initcall(axon_msi_init);
index e6534b519c9abb71267299eb313c1b9535571634..a7f609b3b876d61b1f128bf3902f8262761d0927 100644 (file)
@@ -98,7 +98,7 @@ static int __init cell_publish_devices(void)
        }
        return 0;
 }
-machine_device_initcall(cell, cell_publish_devices);
+machine_subsys_initcall(cell, cell_publish_devices);
 
 static void cell_mpic_cascade(unsigned int irq, struct irq_desc *desc)
 {
index d3a349fb42e58c9b2164a45a6bbb46d804aae72a..99610a6361f28133e1eff58c32d4e91455afa92f 100644 (file)
@@ -4,6 +4,8 @@ spufs-y += inode.o file.o context.o syscalls.o coredump.o
 spufs-y += sched.o backing_ops.o hw_ops.o run.o gang.o
 spufs-y += switch.o fault.o lscsa_alloc.o
 
+obj-$(CONFIG_SPU_TRACE)        += sputrace.o
+
 # Rules to build switch.o with the help of SPU tool chain
 SPU_CROSS      := spu-
 SPU_CC         := $(SPU_CROSS)gcc
index 3fcd06418b01d165ba1d01f7d9930608d6d15c6d..1018acd1746b76f7ac99ef91b62092d4d45529d6 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/poll.h>
 #include <linux/ptrace.h>
 #include <linux/seq_file.h>
+#include <linux/marker.h>
 
 #include <asm/io.h>
 #include <asm/semaphore.h>
@@ -358,6 +359,8 @@ static unsigned long spufs_ps_nopfn(struct vm_area_struct *vma,
        struct spu_context *ctx = vma->vm_file->private_data;
        unsigned long area, offset = address - vma->vm_start;
 
+       spu_context_nospu_trace(spufs_ps_nopfn__enter, ctx);
+
        offset += vma->vm_pgoff << PAGE_SHIFT;
        if (offset >= ps_size)
                return NOPFN_SIGBUS;
@@ -375,11 +378,14 @@ static unsigned long spufs_ps_nopfn(struct vm_area_struct *vma,
 
        if (ctx->state == SPU_STATE_SAVED) {
                up_read(&current->mm->mmap_sem);
+               spu_context_nospu_trace(spufs_ps_nopfn__sleep, ctx);
                spufs_wait(ctx->run_wq, ctx->state == SPU_STATE_RUNNABLE);
+               spu_context_trace(spufs_ps_nopfn__wake, ctx, ctx->spu);
                down_read(&current->mm->mmap_sem);
        } else {
                area = ctx->spu->problem_phys + ps_offs;
                vm_insert_pfn(vma, address, (area + offset) >> PAGE_SHIFT);
+               spu_context_trace(spufs_ps_nopfn__insert, ctx, ctx->spu);
        }
 
        spu_release(ctx);
index c0e968a4c21116d5ffd4a8bfb8ed7182cc79f15d..90784c029f25096ae46963e6fc035c9eaad6c1d5 100644 (file)
@@ -322,7 +322,7 @@ static struct spu_context *
 spufs_assert_affinity(unsigned int flags, struct spu_gang *gang,
                                                struct file *filp)
 {
-       struct spu_context *tmp, *neighbor;
+       struct spu_context *tmp, *neighbor, *err;
        int count, node;
        int aff_supp;
 
@@ -354,11 +354,15 @@ spufs_assert_affinity(unsigned int flags, struct spu_gang *gang,
                if (!list_empty(&neighbor->aff_list) && !(neighbor->aff_head) &&
                    !list_is_last(&neighbor->aff_list, &gang->aff_list_head) &&
                    !list_entry(neighbor->aff_list.next, struct spu_context,
-                   aff_list)->aff_head)
-                       return ERR_PTR(-EEXIST);
+                   aff_list)->aff_head) {
+                       err = ERR_PTR(-EEXIST);
+                       goto out_put_neighbor;
+               }
 
-               if (gang != neighbor->gang)
-                       return ERR_PTR(-EINVAL);
+               if (gang != neighbor->gang) {
+                       err = ERR_PTR(-EINVAL);
+                       goto out_put_neighbor;
+               }
 
                count = 1;
                list_for_each_entry(tmp, &gang->aff_list_head, aff_list)
@@ -372,11 +376,17 @@ spufs_assert_affinity(unsigned int flags, struct spu_gang *gang,
                                break;
                }
 
-               if (node == MAX_NUMNODES)
-                       return ERR_PTR(-EEXIST);
+               if (node == MAX_NUMNODES) {
+                       err = ERR_PTR(-EEXIST);
+                       goto out_put_neighbor;
+               }
        }
 
        return neighbor;
+
+out_put_neighbor:
+       put_spu_context(neighbor);
+       return err;
 }
 
 static void
@@ -454,9 +464,12 @@ spufs_create_context(struct inode *inode, struct dentry *dentry,
        if (ret)
                goto out_aff_unlock;
 
-       if (affinity)
+       if (affinity) {
                spufs_set_affinity(flags, SPUFS_I(dentry->d_inode)->i_ctx,
                                                                neighbor);
+               if (neighbor)
+                       put_spu_context(neighbor);
+       }
 
        /*
         * get references for dget and mntget, will be released
index c01a09da1e562b277ce8000396b7ae382c2758fc..b4814c740d8a7b065453e410a3057fd77a4d9b4f 100644 (file)
@@ -410,8 +410,11 @@ long spufs_run_spu(struct spu_context *ctx, u32 *npc, u32 *event)
         * since we have TIF_SINGLESTEP set, thus the kernel will do
         * it upon return from the syscall anyawy
         */
-       if ((status & SPU_STATUS_STOPPED_BY_STOP)
-           && (status >> SPU_STOP_STATUS_SHIFT) == 0x3fff) {
+       if (unlikely(status & SPU_STATUS_SINGLE_STEP))
+               ret = -ERESTARTSYS;
+
+       else if (unlikely((status & SPU_STATUS_STOPPED_BY_STOP)
+           && (status >> SPU_STOP_STATUS_SHIFT) == 0x3fff)) {
                force_sig(SIGTRAP, current);
                ret = -ERESTARTSYS;
        }
index 00d914232af1450318f1c08256c3a0da91d47294..5915343e2599b313320b2ca18edb42cdecec60e2 100644 (file)
@@ -39,6 +39,7 @@
 #include <linux/pid_namespace.h>
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
+#include <linux/marker.h>
 
 #include <asm/io.h>
 #include <asm/mmu_context.h>
@@ -216,8 +217,8 @@ void do_notify_spus_active(void)
  */
 static void spu_bind_context(struct spu *spu, struct spu_context *ctx)
 {
-       pr_debug("%s: pid=%d SPU=%d NODE=%d\n", __FUNCTION__, current->pid,
-                spu->number, spu->node);
+       spu_context_trace(spu_bind_context__enter, ctx, spu);
+
        spuctx_switch_state(ctx, SPU_UTIL_SYSTEM);
 
        if (ctx->flags & SPU_CREATE_NOSCHED)
@@ -399,8 +400,8 @@ static int has_affinity(struct spu_context *ctx)
  */
 static void spu_unbind_context(struct spu *spu, struct spu_context *ctx)
 {
-       pr_debug("%s: unbind pid=%d SPU=%d NODE=%d\n", __FUNCTION__,
-                spu->pid, spu->number, spu->node);
+       spu_context_trace(spu_unbind_context__enter, ctx, spu);
+
        spuctx_switch_state(ctx, SPU_UTIL_SYSTEM);
 
        if (spu->ctx->flags & SPU_CREATE_NOSCHED)
@@ -528,6 +529,8 @@ static struct spu *spu_get_idle(struct spu_context *ctx)
        struct spu *spu, *aff_ref_spu;
        int node, n;
 
+       spu_context_nospu_trace(spu_get_idle__enter, ctx);
+
        if (ctx->gang) {
                mutex_lock(&ctx->gang->aff_mutex);
                if (has_affinity(ctx)) {
@@ -546,8 +549,7 @@ static struct spu *spu_get_idle(struct spu_context *ctx)
                        if (atomic_dec_and_test(&ctx->gang->aff_sched_count))
                                ctx->gang->aff_ref_spu = NULL;
                        mutex_unlock(&ctx->gang->aff_mutex);
-
-                       return NULL;
+                       goto not_found;
                }
                mutex_unlock(&ctx->gang->aff_mutex);
        }
@@ -565,12 +567,14 @@ static struct spu *spu_get_idle(struct spu_context *ctx)
                mutex_unlock(&cbe_spu_info[node].list_mutex);
        }
 
+ not_found:
+       spu_context_nospu_trace(spu_get_idle__not_found, ctx);
        return NULL;
 
  found:
        spu->alloc_state = SPU_USED;
        mutex_unlock(&cbe_spu_info[node].list_mutex);
-       pr_debug("Got SPU %d %d\n", spu->number, spu->node);
+       spu_context_trace(spu_get_idle__found, ctx, spu);
        spu_init_channels(spu);
        return spu;
 }
@@ -587,6 +591,8 @@ static struct spu *find_victim(struct spu_context *ctx)
        struct spu *spu;
        int node, n;
 
+       spu_context_nospu_trace(spu_find_vitim__enter, ctx);
+
        /*
         * Look for a possible preemption candidate on the local node first.
         * If there is no candidate look at the other nodes.  This isn't
@@ -640,6 +646,8 @@ static struct spu *find_victim(struct spu_context *ctx)
                                goto restart;
                        }
 
+                       spu_context_trace(__spu_deactivate__unload, ctx, spu);
+
                        mutex_lock(&cbe_spu_info[node].list_mutex);
                        cbe_spu_info[node].nr_active--;
                        spu_unbind_context(spu, victim);
@@ -822,6 +830,7 @@ static int __spu_deactivate(struct spu_context *ctx, int force, int max_prio)
  */
 void spu_deactivate(struct spu_context *ctx)
 {
+       spu_context_nospu_trace(spu_deactivate__enter, ctx);
        __spu_deactivate(ctx, 1, MAX_PRIO);
 }
 
@@ -835,6 +844,7 @@ void spu_deactivate(struct spu_context *ctx)
  */
 void spu_yield(struct spu_context *ctx)
 {
+       spu_context_nospu_trace(spu_yield__enter, ctx);
        if (!(ctx->flags & SPU_CREATE_NOSCHED)) {
                mutex_lock(&ctx->state_mutex);
                __spu_deactivate(ctx, 0, MAX_PRIO);
@@ -864,11 +874,15 @@ static noinline void spusched_tick(struct spu_context *ctx)
                goto out;
 
        spu = ctx->spu;
+
+       spu_context_trace(spusched_tick__preempt, ctx, spu);
+
        new = grab_runnable_context(ctx->prio + 1, spu->node);
        if (new) {
                spu_unschedule(spu, ctx);
                spu_add_to_rq(ctx);
        } else {
+               spu_context_nospu_trace(spusched_tick__newslice, ctx);
                ctx->time_slice++;
        }
 out:
index 0e114038ea6fc136b5ec74e675987d848553629f..795a1b52538b7f093a9d2d8251a75dac2d300ba5 100644 (file)
@@ -325,4 +325,9 @@ extern void spu_free_lscsa(struct spu_state *csa);
 extern void spuctx_switch_state(struct spu_context *ctx,
                enum spu_utilization_state new_state);
 
+#define spu_context_trace(name, ctx, spu) \
+       trace_mark(name, "%p %p", ctx, spu);
+#define spu_context_nospu_trace(name, ctx) \
+       trace_mark(name, "%p", ctx);
+
 #endif
diff --git a/arch/powerpc/platforms/cell/spufs/sputrace.c b/arch/powerpc/platforms/cell/spufs/sputrace.c
new file mode 100644 (file)
index 0000000..2b1953f
--- /dev/null
@@ -0,0 +1,250 @@
+/*
+ * Copyright (C) 2007 IBM Deutschland Entwicklung GmbH
+ *     Released under GPL v2.
+ *
+ * Partially based on net/ipv4/tcp_probe.c.
+ *
+ * Simple tracing facility for spu contexts.
+ */
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/marker.h>
+#include <linux/proc_fs.h>
+#include <linux/wait.h>
+#include <asm/atomic.h>
+#include <asm/uaccess.h>
+#include "spufs.h"
+
+struct spu_probe {
+       const char *name;
+       const char *format;
+       marker_probe_func *probe_func;
+};
+
+struct sputrace {
+       ktime_t tstamp;
+       int owner_tid; /* owner */
+       int curr_tid;
+       const char *name;
+       int number;
+};
+
+static int bufsize __read_mostly = 16384;
+MODULE_PARM_DESC(bufsize, "Log buffer size (number of records)");
+module_param(bufsize, int, 0);
+
+
+static DEFINE_SPINLOCK(sputrace_lock);
+static DECLARE_WAIT_QUEUE_HEAD(sputrace_wait);
+static ktime_t sputrace_start;
+static unsigned long sputrace_head, sputrace_tail;
+static struct sputrace *sputrace_log;
+
+static int sputrace_used(void)
+{
+       return (sputrace_head - sputrace_tail) % bufsize;
+}
+
+static inline int sputrace_avail(void)
+{
+       return bufsize - sputrace_used();
+}
+
+static int sputrace_sprint(char *tbuf, int n)
+{
+       const struct sputrace *t = sputrace_log + sputrace_tail % bufsize;
+       struct timespec tv =
+               ktime_to_timespec(ktime_sub(t->tstamp, sputrace_start));
+
+       return snprintf(tbuf, n,
+               "[%lu.%09lu] %d: %s (thread = %d, spu = %d)\n",
+               (unsigned long) tv.tv_sec,
+               (unsigned long) tv.tv_nsec,
+               t->owner_tid,
+               t->name,
+               t->curr_tid,
+               t->number);
+}
+
+static ssize_t sputrace_read(struct file *file, char __user *buf,
+               size_t len, loff_t *ppos)
+{
+       int error = 0, cnt = 0;
+
+       if (!buf || len < 0)
+               return -EINVAL;
+
+       while (cnt < len) {
+               char tbuf[128];
+               int width;
+
+               error = wait_event_interruptible(sputrace_wait,
+                                                sputrace_used() > 0);
+               if (error)
+                       break;
+
+               spin_lock(&sputrace_lock);
+               if (sputrace_head == sputrace_tail) {
+                       spin_unlock(&sputrace_lock);
+                       continue;
+               }
+
+               width = sputrace_sprint(tbuf, sizeof(tbuf));
+               if (width < len)
+                       sputrace_tail = (sputrace_tail + 1) % bufsize;
+               spin_unlock(&sputrace_lock);
+
+               if (width >= len)
+                       break;
+
+               error = copy_to_user(buf + cnt, tbuf, width);
+               if (error)
+                       break;
+               cnt += width;
+       }
+
+       return cnt == 0 ? error : cnt;
+}
+
+static int sputrace_open(struct inode *inode, struct file *file)
+{
+       spin_lock(&sputrace_lock);
+       sputrace_head = sputrace_tail = 0;
+       sputrace_start = ktime_get();
+       spin_unlock(&sputrace_lock);
+
+       return 0;
+}
+
+static const struct file_operations sputrace_fops = {
+       .owner  = THIS_MODULE,
+       .open   = sputrace_open,
+       .read   = sputrace_read,
+};
+
+static void sputrace_log_item(const char *name, struct spu_context *ctx,
+               struct spu *spu)
+{
+       spin_lock(&sputrace_lock);
+       if (sputrace_avail() > 1) {
+               struct sputrace *t = sputrace_log + sputrace_head;
+
+               t->tstamp = ktime_get();
+               t->owner_tid = ctx->tid;
+               t->name = name;
+               t->curr_tid = current->pid;
+               t->number = spu ? spu->number : -1;
+
+               sputrace_head = (sputrace_head + 1) % bufsize;
+       } else {
+               printk(KERN_WARNING
+                      "sputrace: lost samples due to full buffer.\n");
+       }
+       spin_unlock(&sputrace_lock);
+
+       wake_up(&sputrace_wait);
+}
+
+static void spu_context_event(const struct marker *mdata,
+               void *private, const char *format, ...)
+{
+       struct spu_probe *p = mdata->private;
+       va_list ap;
+       struct spu_context *ctx;
+       struct spu *spu;
+
+       va_start(ap, format);
+       ctx = va_arg(ap, struct spu_context *);
+       spu = va_arg(ap, struct spu *);
+
+       sputrace_log_item(p->name, ctx, spu);
+       va_end(ap);
+}
+
+static void spu_context_nospu_event(const struct marker *mdata,
+               void *private, const char *format, ...)
+{
+       struct spu_probe *p = mdata->private;
+       va_list ap;
+       struct spu_context *ctx;
+
+       va_start(ap, format);
+       ctx = va_arg(ap, struct spu_context *);
+
+       sputrace_log_item(p->name, ctx, NULL);
+       va_end(ap);
+}
+
+struct spu_probe spu_probes[] = {
+       { "spu_bind_context__enter", "%p %p", spu_context_event },
+       { "spu_unbind_context__enter", "%p %p", spu_context_event },
+       { "spu_get_idle__enter", "%p", spu_context_nospu_event },
+       { "spu_get_idle__found", "%p %p", spu_context_event },
+       { "spu_get_idle__not_found", "%p", spu_context_nospu_event },
+       { "spu_find_victim__enter", "%p", spu_context_nospu_event },
+       { "spusched_tick__preempt", "%p %p", spu_context_event },
+       { "spusched_tick__newslice", "%p", spu_context_nospu_event },
+       { "spu_yield__enter", "%p", spu_context_nospu_event },
+       { "spu_deactivate__enter", "%p", spu_context_nospu_event },
+       { "__spu_deactivate__unload", "%p %p", spu_context_event },
+       { "spufs_ps_nopfn__enter", "%p", spu_context_nospu_event },
+       { "spufs_ps_nopfn__sleep", "%p", spu_context_nospu_event },
+       { "spufs_ps_nopfn__wake", "%p %p", spu_context_event },
+       { "spufs_ps_nopfn__insert", "%p %p", spu_context_event },
+       { "spu_acquire_saved__enter", "%p", spu_context_nospu_event },
+       { "destroy_spu_context__enter", "%p", spu_context_nospu_event },
+};
+
+static int __init sputrace_init(void)
+{
+       struct proc_dir_entry *entry;
+       int i, error = -ENOMEM;
+
+       sputrace_log = kcalloc(sizeof(struct sputrace),
+                               bufsize, GFP_KERNEL);
+       if (!sputrace_log)
+               goto out;
+
+       entry = create_proc_entry("sputrace", S_IRUSR, NULL);
+       if (!entry)
+               goto out_free_log;
+       entry->proc_fops = &sputrace_fops;
+
+       for (i = 0; i < ARRAY_SIZE(spu_probes); i++) {
+               struct spu_probe *p = &spu_probes[i];
+
+               error = marker_probe_register(p->name, p->format,
+                                             p->probe_func, p);
+               if (error)
+                       printk(KERN_INFO "Unable to register probe %s\n",
+                                       p->name);
+
+               error = marker_arm(p->name);
+               if (error)
+                       printk(KERN_INFO "Unable to arm probe %s\n", p->name);
+       }
+
+       return 0;
+
+out_free_log:
+       kfree(sputrace_log);
+out:
+       return -ENOMEM;
+}
+
+static void __exit sputrace_exit(void)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(spu_probes); i++)
+               marker_probe_unregister(spu_probes[i].name);
+
+       remove_proc_entry("sputrace", NULL);
+       kfree(sputrace_log);
+}
+
+module_init(sputrace_init);
+module_exit(sputrace_exit);
+
+MODULE_LICENSE("GPL");
index e12e9d2987162f7e306d285439192cc66c1a29bc..8864e488498012700e8a0608429cbd8a67195a61 100644 (file)
@@ -132,33 +132,18 @@ static void __init storcenter_init_IRQ(void)
 
        paddr = (phys_addr_t)of_translate_address(dnp, prop);
        mpic = mpic_alloc(dnp, paddr, MPIC_PRIMARY | MPIC_WANTS_RESET,
-                       4, 32, " EPIC     ");
+                       16, 32, " OpenPIC  ");
 
        of_node_put(dnp);
 
        BUG_ON(mpic == NULL);
 
-       /* PCI IRQs */
        /*
-        * 2.6.12 patch:
-        *         openpic_set_sources(0, 5, OpenPIC_Addr + 0x10200);
-        *         openpic_set_sources(5, 2, OpenPIC_Addr + 0x11120);
-        *         first_irq, num_irqs, __iomem first_ISR
-        *         o_ss: i, src: 0, fdf50200
-        *         o_ss: i, src: 1, fdf50220
-        *         o_ss: i, src: 2, fdf50240
-        *         o_ss: i, src: 3, fdf50260
-        *         o_ss: i, src: 4, fdf50280
-        *         o_ss: i, src: 5, fdf51120
-        *         o_ss: i, src: 6, fdf51140
+        * 16 Serial Interrupts followed by 16 Internal Interrupts.
+        * I2C is the second internal, so it is at 17, 0x11020.
         */
        mpic_assign_isu(mpic, 0, paddr + 0x10200);
-       mpic_assign_isu(mpic, 1, paddr + 0x10220);
-       mpic_assign_isu(mpic, 2, paddr + 0x10240);
-       mpic_assign_isu(mpic, 3, paddr + 0x10260);
-       mpic_assign_isu(mpic, 4, paddr + 0x10280);
-       mpic_assign_isu(mpic, 5, paddr + 0x11120);
-       mpic_assign_isu(mpic, 6, paddr + 0x11140);
+       mpic_assign_isu(mpic, 1, paddr + 0x11000);
 
        mpic_init(mpic);
 }
@@ -178,7 +163,7 @@ static int __init storcenter_probe(void)
 {
        unsigned long root = of_get_flat_dt_root();
 
-       return of_flat_dt_is_compatible(root, "storcenter");
+       return of_flat_dt_is_compatible(root, "iomega,storcenter");
 }
 
 define_machine(storcenter){
index 6a0c6f6675cdf0d3dce57eda11ae7009ebb77e58..11fa3c772ed567f8ba907b024dc3ef8010713777 100644 (file)
@@ -199,7 +199,7 @@ static struct iommu_table vio_iommu_table;
 
 void *iseries_hv_alloc(size_t size, dma_addr_t *dma_handle, gfp_t flag)
 {
-       return iommu_alloc_coherent(&vio_iommu_table, size, dma_handle,
+       return iommu_alloc_coherent(NULL, &vio_iommu_table, size, dma_handle,
                                DMA_32BIT_MASK, flag, -1);
 }
 EXPORT_SYMBOL_GPL(iseries_hv_alloc);
@@ -213,7 +213,7 @@ EXPORT_SYMBOL_GPL(iseries_hv_free);
 dma_addr_t iseries_hv_map(void *vaddr, size_t size,
                        enum dma_data_direction direction)
 {
-       return iommu_map_single(&vio_iommu_table, vaddr, size,
+       return iommu_map_single(NULL, &vio_iommu_table, vaddr, size,
                                DMA_32BIT_MASK, direction);
 }
 
index 9916a0f3e431955ba78117207e96038841b22ce6..5803f11c77fc07cc961f2610a9f0ec1b9f7aeef7 100644 (file)
@@ -182,8 +182,10 @@ static void pci_dma_dev_setup_pasemi(struct pci_dev *dev)
         * CONFIG_PPC_PASEMI_IOMMU_DMA_FORCE at build time.
         */
        if (dev->vendor == 0x1959 && dev->device == 0xa007 &&
-           !firmware_has_feature(FW_FEATURE_LPAR))
+           !firmware_has_feature(FW_FEATURE_LPAR)) {
                dev->dev.archdata.dma_ops = &dma_direct_ops;
+               return;
+       }
 #endif
 
        dev->dev.archdata.dma_data = &iommu_table_iobmap;
index c02f8742c54de5792650c2e641003637921cad03..2800fced8c7c2952425620f3e6d32373608b4757 100644 (file)
@@ -167,6 +167,7 @@ static int pSeries_reconfig_remove_node(struct device_node *np)
 
        if ((child = of_get_next_child(np, NULL))) {
                of_node_put(child);
+               of_node_put(parent);
                return -EBUSY;
        }
 
index e48b20e934ca233e744be83b36744a15cbd7d6ad..2c5388ce902abfaa3fd9f400c231a3dd64735cc5 100644 (file)
@@ -1342,7 +1342,7 @@ static int __init of_fsl_spi_probe(char *type, char *compatible, u32 sysclk,
                if (ret)
                        goto unreg;
 
-               ret = platform_device_register(pdev);
+               ret = platform_device_add(pdev);
                if (ret)
                        goto unreg;
 
index 0e74a4bd9827df1e4558810f3f77e177b3ec607c..5d2d5522ef416846a0ba9bf8073c05652227d4c7 100644 (file)
@@ -174,15 +174,19 @@ int mpc8xx_pic_init(void)
                goto out;
 
        siu_reg = ioremap(res.start, res.end - res.start + 1);
-       if (siu_reg == NULL)
-               return -EINVAL;
+       if (siu_reg == NULL) {
+               ret = -EINVAL;
+               goto out;
+       }
 
-       mpc8xx_pic_host = irq_alloc_host(of_node_get(np), IRQ_HOST_MAP_LINEAR,
+       mpc8xx_pic_host = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR,
                                         64, &mpc8xx_pic_host_ops, 64);
        if (mpc8xx_pic_host == NULL) {
                printk(KERN_ERR "MPC8xx PIC: failed to allocate irq host!\n");
                ret = -ENOMEM;
+               goto out;
        }
+       return 0;
 
 out:
        of_node_put(np);
index 5ef844da9355c15bcde600ab0121b4e45619f49e..6efbd5e5bb1b6f1b8119ed8ccf7e8ed35591a015 100644 (file)
@@ -66,7 +66,7 @@ phys_addr_t get_qe_base(void)
 {
        struct device_node *qe;
        unsigned int size;
-       const void *prop;
+       const u32 *prop;
 
        if (qebase != -1)
                return qebase;
@@ -79,7 +79,8 @@ phys_addr_t get_qe_base(void)
        }
 
        prop = of_get_property(qe, "reg", &size);
-       qebase = of_translate_address(qe, prop);
+       if (prop && size >= sizeof(*prop))
+               qebase = of_translate_address(qe, prop);
        of_node_put(qe);
 
        return qebase;
@@ -172,10 +173,9 @@ unsigned int get_brg_clk(void)
        }
 
        prop = of_get_property(qe, "brg-frequency", &size);
-       if (!prop || size != sizeof(*prop))
-               return brg_clk;
+       if (prop && size == sizeof(*prop))
+               brg_clk = *prop;
 
-       brg_clk = *prop;
        of_node_put(qe);
 
        return brg_clk;
index db5934cdafb3b9fd603317e53789a8e5230001db..531156f8919ca5e4877f1835a14a303a232496ae 100644 (file)
@@ -42,6 +42,8 @@ config GENERIC_CALIBRATE_DELAY
 config PPC
        bool
        default y
+       select HAVE_OPROFILE
+       select HAVE_KPROBES
 
 config PPC32
        bool
@@ -1256,8 +1258,6 @@ endmenu
 
 source "lib/Kconfig"
 
-source "kernel/Kconfig.instrumentation"
-
 source "arch/ppc/Kconfig.debug"
 
 source "security/Kconfig"
index fadacfd188068e70a787c623cfe81b9a5581f15a..409fcaa4994a598736ec082218dacde0709f2d9a 100644 (file)
@@ -74,7 +74,7 @@ pgd_t *pgd_alloc(struct mm_struct *mm)
        return ret;
 }
 
-void pgd_free(pgd_t *pgd)
+void pgd_free(struct mm_struct *mm, pgd_t *pgd)
 {
        free_pages((unsigned long)pgd, PGDIR_ORDER);
 }
@@ -111,7 +111,7 @@ struct page *pte_alloc_one(struct mm_struct *mm, unsigned long address)
        return ptepage;
 }
 
-void pte_free_kernel(pte_t *pte)
+void pte_free_kernel(struct mm_struct *mm, pte_t *pte)
 {
 #ifdef CONFIG_SMP
        hash_page_sync();
@@ -119,7 +119,7 @@ void pte_free_kernel(pte_t *pte)
        free_page((unsigned long)pte);
 }
 
-void pte_free(struct page *ptepage)
+void pte_free(struct mm_struct *mm, struct page *ptepage)
 {
 #ifdef CONFIG_SMP
        hash_page_sync();
index 6ef54d27fc001720f738aa3f066e15497503c064..92a4f7b4323a54e0f23453e714e0a7c714bab632 100644 (file)
@@ -16,6 +16,9 @@ config LOCKDEP_SUPPORT
 config STACKTRACE_SUPPORT
        def_bool y
 
+config HAVE_LATENCYTOP_SUPPORT
+       def_bool y
+
 config RWSEM_GENERIC_SPINLOCK
        bool
 
@@ -47,10 +50,17 @@ config NO_IOMEM
 config NO_DMA
        def_bool y
 
+config GENERIC_LOCKBREAK
+       bool
+       default y
+       depends on SMP && PREEMPT
+
 mainmenu "Linux Kernel Configuration"
 
 config S390
        def_bool y
+       select HAVE_OPROFILE
+       select HAVE_KPROBES
 
 source "init/Kconfig"
 
@@ -81,8 +91,8 @@ config SMP
          singleprocessor machines. On a singleprocessor machine, the kernel
          will run faster if you say N here.
 
-         See also the <file:Documentation/smp.txt> and the SMP-HOWTO
-         available at <http://www.tldp.org/docs.html#howto>.
+         See also the SMP-HOWTO available at
+         <http://www.tldp.org/docs.html#howto>.
 
          Even if you don't know what to do here, say Y.
 
@@ -526,8 +536,6 @@ source "drivers/Kconfig"
 
 source "fs/Kconfig"
 
-source "kernel/Kconfig.instrumentation"
-
 source "arch/s390/Kconfig.debug"
 
 source "security/Kconfig"
index 2283933a9a93eef48b2de37aefe944540af03ff4..4599fa06bd82a759d322dcd25a85bbfb6edfb369 100644 (file)
@@ -6,4 +6,12 @@ config TRACE_IRQFLAGS_SUPPORT
 
 source "lib/Kconfig.debug"
 
+config DEBUG_PAGEALLOC
+       bool "Debug page memory allocations"
+       depends on DEBUG_KERNEL
+       help
+         Unmap pages from the kernel linear mapping after free_pages().
+         This results in a slowdown, but helps to find certain types of
+         memory corruptions.
+
 endmenu
index 6ee1bedbd1bf85f020edfcf9b2c37457208ba1b7..062c3d4c0394b48f4e8bbea8306bc538a03c2758 100644 (file)
@@ -1698,14 +1698,6 @@ compat_sys_signalfd_wrapper:
        llgfr   %r4,%r4                 # compat_size_t
        jg      compat_sys_signalfd
 
-       .globl  compat_sys_timerfd_wrapper
-compat_sys_timerfd_wrapper:
-       lgfr    %r2,%r2                 # int
-       lgfr    %r3,%r3                 # int
-       lgfr    %r4,%r4                 # int
-       llgtr   %r5,%r5                 # struct compat_itimerspec *
-       jg      compat_sys_timerfd
-
        .globl  sys_eventfd_wrapper
 sys_eventfd_wrapper:
        llgfr   %r2,%r2                 # unsigned int
index 1a6dac8df6fb1942a96418ad4d76014be051bdda..6766e37fe8ea01955da640895bd2068358f660d6 100644 (file)
@@ -11,6 +11,7 @@
 
 #include <linux/sys.h>
 #include <linux/linkage.h>
+#include <linux/init.h>
 #include <asm/cache.h>
 #include <asm/lowcore.h>
 #include <asm/errno.h>
@@ -830,9 +831,7 @@ mcck_return:
  * Restart interruption handler, kick starter for additional CPUs
  */
 #ifdef CONFIG_SMP
-#ifndef CONFIG_HOTPLUG_CPU
-       .section .init.text,"ax"
-#endif
+       __CPUINIT
        .globl restart_int_handler
 restart_int_handler:
        l       %r15,__LC_SAVE_AREA+60  # load ksp
@@ -845,9 +844,7 @@ restart_int_handler:
        br      %r14                    # branch to start_secondary
 restart_addr:
        .long   start_secondary
-#ifndef CONFIG_HOTPLUG_CPU
        .previous
-#endif
 #else
 /*
  * If we do not run with SMP enabled, let the new CPU crash ...
index a3e47b893f079ca812c54b727f4b3dd4b2a6a6c2..efde6e178f6c22733322ac6c5048cdfed8c7e28b 100644 (file)
@@ -11,6 +11,7 @@
 
 #include <linux/sys.h>
 #include <linux/linkage.h>
+#include <linux/init.h>
 #include <asm/cache.h>
 #include <asm/lowcore.h>
 #include <asm/errno.h>
@@ -801,9 +802,7 @@ mcck_return:
  * Restart interruption handler, kick starter for additional CPUs
  */
 #ifdef CONFIG_SMP
-#ifndef CONFIG_HOTPLUG_CPU
-       .section .init.text,"ax"
-#endif
+       __CPUINIT
        .globl restart_int_handler
 restart_int_handler:
        lg      %r15,__LC_SAVE_AREA+120 # load ksp
@@ -814,9 +813,7 @@ restart_int_handler:
        lmg     %r6,%r15,__SF_GPRS(%r15) # load registers from clone
        stosm   __SF_EMPTY(%r15),0x04   # now we can turn dat on
        jg      start_secondary
-#ifndef CONFIG_HOTPLUG_CPU
        .previous
-#endif
 #else
 /*
  * If we do not run with SMP enabled, let the new CPU crash ...
index db28cca81fef75ec6c1ffcec76c14218dff80d34..60acdc266db177fab528d5cedea72829a1cbe939 100644 (file)
@@ -439,7 +439,7 @@ static void ipl_run(struct shutdown_trigger *trigger)
                reipl_ccw_dev(&ipl_info.data.ccw.dev_id);
 }
 
-static int ipl_init(void)
+static int __init ipl_init(void)
 {
        int rc;
 
@@ -471,8 +471,11 @@ out:
        return 0;
 }
 
-static struct shutdown_action ipl_action = {SHUTDOWN_ACTION_IPL_STR, ipl_run,
-                                           ipl_init};
+static struct shutdown_action __refdata ipl_action = {
+       .name   = SHUTDOWN_ACTION_IPL_STR,
+       .fn     = ipl_run,
+       .init   = ipl_init,
+};
 
 /*
  * reipl shutdown action: Reboot Linux on shutdown.
@@ -792,7 +795,7 @@ static int __init reipl_fcp_init(void)
        return 0;
 }
 
-static int reipl_init(void)
+static int __init reipl_init(void)
 {
        int rc;
 
@@ -819,8 +822,11 @@ static int reipl_init(void)
        return 0;
 }
 
-static struct shutdown_action reipl_action = {SHUTDOWN_ACTION_REIPL_STR,
-                                             reipl_run, reipl_init};
+static struct shutdown_action __refdata reipl_action = {
+       .name   = SHUTDOWN_ACTION_REIPL_STR,
+       .fn     = reipl_run,
+       .init   = reipl_init,
+};
 
 /*
  * dump shutdown action: Dump Linux on shutdown.
@@ -998,7 +1004,7 @@ static int __init dump_fcp_init(void)
        return 0;
 }
 
-static int dump_init(void)
+static int __init dump_init(void)
 {
        int rc;
 
@@ -1020,8 +1026,11 @@ static int dump_init(void)
        return 0;
 }
 
-static struct shutdown_action dump_action = {SHUTDOWN_ACTION_DUMP_STR,
-                                            dump_run, dump_init};
+static struct shutdown_action __refdata dump_action = {
+       .name   = SHUTDOWN_ACTION_DUMP_STR,
+       .fn     = dump_run,
+       .init   = dump_init,
+};
 
 /*
  * vmcmd shutdown action: Trigger vm command on shutdown.
index 766c783bd7a726e25c8a9f0ba243067a1a296344..29ae165d174931b0d7b1775e3690c1be23d5c8f9 100644 (file)
@@ -77,7 +77,7 @@ unsigned long machine_flags = 0;
 unsigned long elf_hwcap = 0;
 char elf_platform[ELF_PLATFORM_SIZE];
 
-struct mem_chunk __initdata memory_chunk[MEMORY_CHUNKS];
+struct mem_chunk __meminitdata memory_chunk[MEMORY_CHUNKS];
 volatile int __cpu_logical_map[NR_CPUS]; /* logical cpu to cpu address */
 static unsigned long __initdata memory_end;
 
@@ -145,7 +145,7 @@ __setup("condev=", condev_setup);
 
 static int __init conmode_setup(char *str)
 {
-#if defined(CONFIG_SCLP_CONSOLE)
+#if defined(CONFIG_SCLP_CONSOLE) || defined(CONFIG_SCLP_VT220_CONSOLE)
        if (strncmp(str, "hwc", 4) == 0 || strncmp(str, "sclp", 5) == 0)
                 SET_CONSOLE_SCLP;
 #endif
@@ -183,7 +183,7 @@ static void __init conmode_default(void)
                 */
                cpcmd("TERM CONMODE 3215", NULL, 0, NULL);
                if (ptr == NULL) {
-#if defined(CONFIG_SCLP_CONSOLE)
+#if defined(CONFIG_SCLP_CONSOLE) || defined(CONFIG_SCLP_VT220_CONSOLE)
                        SET_CONSOLE_SCLP;
 #endif
                        return;
@@ -193,7 +193,7 @@ static void __init conmode_default(void)
                        SET_CONSOLE_3270;
 #elif defined(CONFIG_TN3215_CONSOLE)
                        SET_CONSOLE_3215;
-#elif defined(CONFIG_SCLP_CONSOLE)
+#elif defined(CONFIG_SCLP_CONSOLE) || defined(CONFIG_SCLP_VT220_CONSOLE)
                        SET_CONSOLE_SCLP;
 #endif
                } else if (strncmp(ptr + 8, "3215", 4) == 0) {
@@ -201,7 +201,7 @@ static void __init conmode_default(void)
                        SET_CONSOLE_3215;
 #elif defined(CONFIG_TN3270_CONSOLE)
                        SET_CONSOLE_3270;
-#elif defined(CONFIG_SCLP_CONSOLE)
+#elif defined(CONFIG_SCLP_CONSOLE) || defined(CONFIG_SCLP_VT220_CONSOLE)
                        SET_CONSOLE_SCLP;
 #endif
                }
@@ -212,7 +212,7 @@ static void __init conmode_default(void)
                SET_CONSOLE_3270;
 #endif
        } else {
-#if defined(CONFIG_SCLP_CONSOLE)
+#if defined(CONFIG_SCLP_CONSOLE) || defined(CONFIG_SCLP_VT220_CONSOLE)
                SET_CONSOLE_SCLP;
 #endif
        }
@@ -528,7 +528,7 @@ static void __init setup_memory_end(void)
        memory_size = 0;
        memory_end &= PAGE_MASK;
 
-       max_mem = memory_end ? min(VMALLOC_START, memory_end) : VMALLOC_START;
+       max_mem = memory_end ? min(VMEM_MAX_PHYS, memory_end) : VMEM_MAX_PHYS;
        memory_end = min(max_mem, memory_end);
 
        /*
index aa37fa154512eb2323064bf2c9dc7ba44ec6be8e..85060659fb123d491227d849963dad292e13eeab 100644 (file)
@@ -225,12 +225,11 @@ EXPORT_SYMBOL(smp_call_function_single);
  * You must not call this function with disabled interrupts or from a
  * hardware interrupt handler or from a bottom half handler.
  */
-int
-smp_call_function_mask(cpumask_t mask,
-                       void (*func)(void *), void *info,
-                       int wait)
+int smp_call_function_mask(cpumask_t mask, void (*func)(void *), void *info,
+                          int wait)
 {
        preempt_disable();
+       cpu_clear(smp_processor_id(), mask);
        __smp_call_function_map(func, info, 0, wait, mask);
        preempt_enable();
        return 0;
@@ -1008,7 +1007,7 @@ static struct notifier_block __cpuinitdata smp_cpu_nb = {
        .notifier_call = smp_cpu_notify,
 };
 
-static int smp_add_present_cpu(int cpu)
+static int __devinit smp_add_present_cpu(int cpu)
 {
        struct cpu *c = &per_cpu(cpu_devices, cpu);
        struct sys_device *s = &c->sysdev;
@@ -1036,8 +1035,8 @@ out:
 }
 
 #ifdef CONFIG_HOTPLUG_CPU
-static ssize_t rescan_store(struct sys_device *dev, const char *buf,
-                           size_t count)
+static ssize_t __ref rescan_store(struct sys_device *dev,
+                                 const char *buf, size_t count)
 {
        cpumask_t newcpus;
        int cpu;
index da692472996449fa6daa83e79a56273f56ac4be8..85e46a5d0e0801d9880987cd2595a06391231401 100644 (file)
@@ -14,7 +14,8 @@
 static unsigned long save_context_stack(struct stack_trace *trace,
                                        unsigned long sp,
                                        unsigned long low,
-                                       unsigned long high)
+                                       unsigned long high,
+                                       int savesched)
 {
        struct stack_frame *sf;
        struct pt_regs *regs;
@@ -47,10 +48,12 @@ static unsigned long save_context_stack(struct stack_trace *trace,
                        return sp;
                regs = (struct pt_regs *)sp;
                addr = regs->psw.addr & PSW_ADDR_INSN;
-               if (!trace->skip)
-                       trace->entries[trace->nr_entries++] = addr;
-               else
-                       trace->skip--;
+               if (savesched || !in_sched_functions(addr)) {
+                       if (!trace->skip)
+                               trace->entries[trace->nr_entries++] = addr;
+                       else
+                               trace->skip--;
+               }
                if (trace->nr_entries >= trace->max_entries)
                        return sp;
                low = sp;
@@ -66,15 +69,27 @@ void save_stack_trace(struct stack_trace *trace)
        orig_sp = sp & PSW_ADDR_INSN;
        new_sp = save_context_stack(trace, orig_sp,
                                    S390_lowcore.panic_stack - PAGE_SIZE,
-                                   S390_lowcore.panic_stack);
+                                   S390_lowcore.panic_stack, 1);
        if (new_sp != orig_sp)
                return;
        new_sp = save_context_stack(trace, new_sp,
                                    S390_lowcore.async_stack - ASYNC_SIZE,
-                                   S390_lowcore.async_stack);
+                                   S390_lowcore.async_stack, 1);
        if (new_sp != orig_sp)
                return;
        save_context_stack(trace, new_sp,
                           S390_lowcore.thread_info,
-                          S390_lowcore.thread_info + THREAD_SIZE);
+                          S390_lowcore.thread_info + THREAD_SIZE, 1);
+}
+
+void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
+{
+       unsigned long sp, low, high;
+
+       sp = tsk->thread.ksp & PSW_ADDR_INSN;
+       low = (unsigned long) task_stack_page(tsk);
+       high = (unsigned long) task_pt_regs(tsk);
+       save_context_stack(trace, sp, low, high, 0);
+       if (trace->nr_entries < trace->max_entries)
+               trace->entries[trace->nr_entries++] = ULONG_MAX;
 }
index 9e26ed9fe4e73ee5301519ada6c2a602efdef2b6..25eac7802fc4dba21980e643fc6fc2f0b76081bf 100644 (file)
@@ -325,5 +325,5 @@ SYSCALL(sys_utimes,sys_utimes,compat_sys_utimes_wrapper)
 SYSCALL(s390_fallocate,sys_fallocate,sys_fallocate_wrapper)
 SYSCALL(sys_utimensat,sys_utimensat,compat_sys_utimensat_wrapper)      /* 315 */
 SYSCALL(sys_signalfd,sys_signalfd,compat_sys_signalfd_wrapper)
-SYSCALL(sys_timerfd,sys_timerfd,compat_sys_timerfd_wrapper)
+NI_SYSCALL                                             /* 317 old sys_timer_fd */
 SYSCALL(sys_eventfd,sys_eventfd,sys_eventfd_wrapper)
index 52b8342c6bf265e9facd1e18a4f3512d56c2357a..1a2fdb6991df0e6905c8640c71025d8ca54c1bf6 100644 (file)
@@ -271,7 +271,10 @@ void die(const char * str, struct pt_regs * regs, long err)
        printk("PREEMPT ");
 #endif
 #ifdef CONFIG_SMP
-       printk("SMP");
+       printk("SMP ");
+#endif
+#ifdef CONFIG_DEBUG_PAGEALLOC
+       printk("DEBUG_PAGEALLOC");
 #endif
        printk("\n");
        notify_die(DIE_OOPS, str, regs, err, current->thread.trap_no, SIGSEGV);
index 7d43c3cd3ef35880b5b0fd5a5fbb08b33a51e605..b4607155e8d0b930c98b8a913d050a08d47b9e4a 100644 (file)
@@ -35,7 +35,7 @@ SECTIONS
                KPROBES_TEXT
                *(.fixup)
                *(.gnu.warning)
-       } = 0x0700
+       } :text = 0x0700
 
        _etext = .;             /* End of text section */
 
index b234bb4a6da7545d5ab8b5ed7387fb7b3c25b994..983ec6ec0e7cc6c85800eea42068196a5fbdbc28 100644 (file)
@@ -167,6 +167,33 @@ void __init mem_init(void)
               PFN_ALIGN((unsigned long)&_eshared) - 1);
 }
 
+#ifdef CONFIG_DEBUG_PAGEALLOC
+void kernel_map_pages(struct page *page, int numpages, int enable)
+{
+       pgd_t *pgd;
+       pud_t *pud;
+       pmd_t *pmd;
+       pte_t *pte;
+       unsigned long address;
+       int i;
+
+       for (i = 0; i < numpages; i++) {
+               address = page_to_phys(page + i);
+               pgd = pgd_offset_k(address);
+               pud = pud_offset(pgd, address);
+               pmd = pmd_offset(pud, address);
+               pte = pte_offset_kernel(pmd, address);
+               if (!enable) {
+                       ptep_invalidate(address, pte);
+                       continue;
+               }
+               *pte = mk_pte_phys(address, __pgprot(_PAGE_TYPE_RW));
+               /* Flush cpu write queue. */
+               mb();
+       }
+}
+#endif
+
 void free_initmem(void)
 {
         unsigned long addr;
index 79d13a166a3dac765df9c7af68c18b0cf58bd253..7c1287ccf78864fee054865ef9afd97193497d93 100644 (file)
@@ -62,7 +62,7 @@ void __meminit memmap_init(unsigned long size, int nid, unsigned long zone,
        }
 }
 
-static void __init_refok *vmem_alloc_pages(unsigned int order)
+static void __ref *vmem_alloc_pages(unsigned int order)
 {
        if (slab_is_available())
                return (void *)__get_free_pages(GFP_KERNEL, order);
@@ -250,7 +250,7 @@ static int insert_memory_segment(struct memory_segment *seg)
 {
        struct memory_segment *tmp;
 
-       if (seg->start + seg->size >= VMALLOC_START ||
+       if (seg->start + seg->size >= VMEM_MAX_PHYS ||
            seg->start + seg->size < seg->start)
                return -ERANGE;
 
@@ -360,7 +360,6 @@ void __init vmem_map_init(void)
 {
        int i;
 
-       BUILD_BUG_ON((unsigned long)VMEM_MAP + VMEM_MAP_SIZE > VMEM_MAP_MAX);
        NODE_DATA(0)->node_mem_map = VMEM_MAP;
        for (i = 0; i < MEMORY_CHUNKS && memory_chunk[i].size > 0; i++)
                vmem_add_mem(memory_chunk[i].addr, memory_chunk[i].size);
index 1cd9c8fd927d8dd20fba363aeea28718d4562328..1c3a90835c7e00caf0cb6960c4da7a75f603ea51 100644 (file)
@@ -8,6 +8,7 @@ mainmenu "Linux/SuperH Kernel Configuration"
 config SUPERH
        def_bool y
        select EMBEDDED
+       select HAVE_OPROFILE
        help
          The SuperH is a RISC processor targeted for use in embedded systems
          and consumer electronics; it was also used in the Sega Dreamcast
@@ -672,9 +673,8 @@ config SMP
          People using multiprocessor machines who say Y here should also say
          Y to "Enhanced Real Time Clock Support", below.
 
-         See also the <file:Documentation/smp.txt>,
-         <file:Documentation/nmi_watchdog.txt> and the SMP-HOWTO available
-         at <http://www.tldp.org/docs.html#howto>.
+         See also <file:Documentation/nmi_watchdog.txt> and the SMP-HOWTO
+         available at <http://www.tldp.org/docs.html#howto>.
 
          If you don't know what to do here, say N.
 
@@ -882,6 +882,10 @@ endmenu
 menu "Power management options (EXPERIMENTAL)"
 depends on EXPERIMENTAL && SYS_SUPPORTS_PM
 
+config ARCH_SUSPEND_POSSIBLE
+       def_bool y
+       depends on !SMP
+
 source kernel/power/Kconfig
 
 endmenu
@@ -892,8 +896,6 @@ source "drivers/Kconfig"
 
 source "fs/Kconfig"
 
-source "kernel/Kconfig.instrumentation"
-
 source "arch/sh/Kconfig.debug"
 
 source "security/Kconfig"
index fbc6f2c8649fa72f17c3c1157871a043a1ee38de..7e816ededed762db82b04ce39b7bc2b449e9f769 100644 (file)
@@ -6,11 +6,6 @@ config PCI
          bus system, i.e. the way the CPU talks to the other stuff inside
          your box. If you have PCI, say Y, otherwise N.
 
-         The PCI-HOWTO, available from
-         <http://www.tldp.org/docs.html#howto>, contains valuable
-         information about which PCI hardware does work under Linux and which
-         doesn't.
-
 config SH_PCIDMA_NONCOHERENT
        bool "Cache and PCI noncoherent"
        depends on PCI
index 10bec45415ba0c09f856533418f1775e4e94eb96..719e127a7c05921be389465d2630c6821700603d 100644 (file)
@@ -338,6 +338,6 @@ ENTRY(sys_call_table)
        .long sys_epoll_pwait
        .long sys_utimensat             /* 320 */
        .long sys_signalfd
-       .long sys_timerfd
+       .long sys_ni_syscall
        .long sys_eventfd
        .long sys_fallocate
index 98a93efe36911a040084565d4ce09936b06b2ff7..12c7340356ae4bb78819e83cf8fa11fef0939217 100644 (file)
@@ -376,6 +376,6 @@ sys_call_table:
        .long sys_epoll_pwait
        .long sys_utimensat
        .long sys_signalfd
-       .long sys_timerfd               /* 350 */
+       .long sys_ni_syscall            /* 350 */
        .long sys_eventfd
        .long sys_fallocate
index 527adc808ad6c8609bc81581d49bcceec1ceb0aa..99f8971716d2226a53a27c3e5c19e99c32b6f135 100644 (file)
@@ -48,9 +48,8 @@ config SMP
          Y to "Enhanced Real Time Clock Support", below. The "Advanced Power
          Management" code will be disabled if you say Y here.
 
-         See also the <file:Documentation/smp.txt>,
-         <file:Documentation/nmi_watchdog.txt> and the SMP-HOWTO available at
-         <http://www.tldp.org/docs.html#howto>.
+         See also <file:Documentation/nmi_watchdog.txt> and the SMP-HOWTO
+         available at <http://www.tldp.org/docs.html#howto>.
 
          If you don't know what to do here, say N.
 
@@ -63,6 +62,7 @@ config NR_CPUS
 config SPARC
        bool
        default y
+       select HAVE_OPROFILE
 
 # Identify this as a Sparc32 build
 config SPARC32
@@ -320,8 +320,6 @@ endmenu
 
 source "fs/Kconfig"
 
-source "kernel/Kconfig.instrumentation"
-
 source "arch/sparc/Kconfig.debug"
 
 source "security/Kconfig"
index 97aa50d1e4ae053c2d61776d5880c820a2d38635..ad0ede24ca1d80e6e826d9e5eaee7f37bd391d36 100644 (file)
@@ -305,7 +305,7 @@ void *sbus_alloc_consistent(struct sbus_dev *sdev, long len, u32 *dma_addrp)
        struct resource *res;
        int order;
 
-       /* XXX why are some lenghts signed, others unsigned? */
+       /* XXX why are some lengths signed, others unsigned? */
        if (len <= 0) {
                return NULL;
        }
@@ -393,7 +393,7 @@ void sbus_free_consistent(struct sbus_dev *sdev, long n, void *p, u32 ba)
  */
 dma_addr_t sbus_map_single(struct sbus_dev *sdev, void *va, size_t len, int direction)
 {
-       /* XXX why are some lenghts signed, others unsigned? */
+       /* XXX why are some lengths signed, others unsigned? */
        if (len <= 0) {
                return 0;
        }
index 55722840859c89c15df7dc32409cdd902fb7c376..ee010f4532a0dd3979b764b99f0b775f795f61d3 100644 (file)
@@ -79,7 +79,7 @@ sys_call_table:
 /*295*/        .long sys_fchmodat, sys_faccessat, sys_pselect6, sys_ppoll, sys_unshare
 /*300*/        .long sys_set_robust_list, sys_get_robust_list, sys_migrate_pages, sys_mbind, sys_get_mempolicy
 /*305*/        .long sys_set_mempolicy, sys_kexec_load, sys_move_pages, sys_getcpu, sys_epoll_pwait
-/*310*/        .long sys_utimensat, sys_signalfd, sys_timerfd, sys_eventfd, sys_fallocate
+/*310*/        .long sys_utimensat, sys_signalfd, sys_ni_syscall, sys_eventfd, sys_fallocate
 
 #ifdef CONFIG_SUNOS_EMUL
        /* Now the SunOS syscall table. */
index 20657744c86444904958afde1576161636bfb067..f406b1f22791a8f65de6ba133c85cec37c6ad557 100644 (file)
@@ -7,7 +7,7 @@
 #include <asm/ptrace.h>
 #include <asm/psr.h>
 
-       .section .sched.text
+       .section .sched.text, "ax"
        .align  4
 
        .globl          ___down_read
index 26f5791baa33c7beb4a7264fd655310337bfd977..a8c6366f05a1b416ddbfd3a28c2e31b6d333a05d 100644 (file)
@@ -8,6 +8,8 @@ mainmenu "Linux/UltraSPARC Kernel Configuration"
 config SPARC
        bool
        default y
+       select HAVE_OPROFILE
+       select HAVE_KPROBES
 
 config SPARC64
        bool
@@ -66,7 +68,7 @@ config AUDIT_ARCH
        bool
        default y
 
-config ARCH_SETS_UP_PER_CPU_AREA
+config HAVE_SETUP_PER_CPU_AREA
        def_bool y
 
 config ARCH_NO_VIRT_TO_BUS
@@ -166,9 +168,8 @@ config SMP
          Y to "Enhanced Real Time Clock Support", below. The "Advanced Power
          Management" code will be disabled if you say Y here.
 
-         See also the <file:Documentation/smp.txt>,
-         <file:Documentation/nmi_watchdog.txt> and the SMP-HOWTO available at
-         <http://www.tldp.org/docs.html#howto>.
+         See also <file:Documentation/nmi_watchdog.txt> and the SMP-HOWTO
+         available at <http://www.tldp.org/docs.html#howto>.
 
          If you don't know what to do here, say N.
 
@@ -351,11 +352,6 @@ config PCI
          your box. Other bus systems are ISA, EISA, MicroChannel (MCA) or
          VESA. If you have PCI, say Y, otherwise N.
 
-         The PCI-HOWTO, available from
-         <http://www.tldp.org/docs.html#howto>, contains valuable
-         information about which PCI hardware does work under Linux and which
-         doesn't.
-
 config PCI_DOMAINS
        def_bool PCI
 
@@ -470,8 +466,6 @@ source "drivers/sbus/char/Kconfig"
 
 source "fs/Kconfig"
 
-source "kernel/Kconfig.instrumentation"
-
 source "arch/sparc64/Kconfig.debug"
 
 source "security/Kconfig"
index 070a4846c0cb7d7dcb06be192bcd8879733f5112..4b9115a4d92ecf909d17a0a5e5c1964b450dfe35 100644 (file)
@@ -580,7 +580,7 @@ static int dma_4u_map_sg(struct device *dev, struct scatterlist *sglist,
 
        /* Step 1: Prepare scatter list. */
 
-       npages = prepare_sg(sglist, nelems);
+       npages = prepare_sg(dev, sglist, nelems);
 
        /* Step 2: Allocate a cluster and context, if necessary. */
 
index efd5dff85f606ce55e26ff2acdc7ac9579da1ddb..72a4acfe8c7b9f9742e00cbd0866c4a686be178d 100644 (file)
@@ -4,6 +4,7 @@
  * Copyright (C) 1999 David S. Miller (davem@redhat.com)
  */
 
+#include <linux/dma-mapping.h>
 #include "iommu_common.h"
 
 /* You are _strongly_ advised to enable the following debugging code
@@ -201,21 +202,24 @@ void verify_sglist(struct scatterlist *sglist, int nents, iopte_t *iopte, int np
 }
 #endif
 
-unsigned long prepare_sg(struct scatterlist *sg, int nents)
+unsigned long prepare_sg(struct device *dev, struct scatterlist *sg, int nents)
 {
        struct scatterlist *dma_sg = sg;
        unsigned long prev;
        u32 dent_addr, dent_len;
+       unsigned int max_seg_size;
 
        prev  = (unsigned long) sg_virt(sg);
        prev += (unsigned long) (dent_len = sg->length);
        dent_addr = (u32) ((unsigned long)(sg_virt(sg)) & (IO_PAGE_SIZE - 1UL));
+       max_seg_size = dma_get_max_seg_size(dev);
        while (--nents) {
                unsigned long addr;
 
                sg = sg_next(sg);
                addr = (unsigned long) sg_virt(sg);
-               if (! VCONTIG(prev, addr)) {
+               if (! VCONTIG(prev, addr) ||
+                       dent_len + sg->length > max_seg_size) {
                        dma_sg->dma_address = dent_addr;
                        dma_sg->dma_length = dent_len;
                        dma_sg = sg_next(dma_sg);
index 75b5a58145227aa8aabea141d3e2190757bbda23..a90d046e8024fd1eb7667d478f2a9f6fd16e245e 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/scatterlist.h>
+#include <linux/device.h>
 
 #include <asm/iommu.h>
 #include <asm/scatterlist.h>
@@ -46,4 +47,4 @@ extern void verify_sglist(struct scatterlist *sg, int nents, iopte_t *iopte, int
 #define VCONTIG(__X, __Y)      (((__X) == (__Y)) || \
                                 (((__X) | (__Y)) << (64UL - PAGE_SHIFT)) == 0UL)
 
-extern unsigned long prepare_sg(struct scatterlist *sg, int nents);
+extern unsigned long prepare_sg(struct device *dev, struct scatterlist *sg, int nents);
index 1aa8e044b1057c5d8a2d34ae56447787faac4773..5ea2eab1ccdad4d63ea0125db2b65d8a3ad082e9 100644 (file)
@@ -490,7 +490,7 @@ static int dma_4v_map_sg(struct device *dev, struct scatterlist *sglist,
                goto bad;
 
        /* Step 1: Prepare scatter list. */
-       npages = prepare_sg(sglist, nelems);
+       npages = prepare_sg(dev, sglist, nelems);
 
        /* Step 2: Allocate a cluster and context, if necessary. */
        spin_lock_irqsave(&iommu->lock, flags);
@@ -625,8 +625,8 @@ static void __init pci_sun4v_scan_bus(struct pci_pbm_info *pbm)
        /* XXX register error interrupt handlers XXX */
 }
 
-static unsigned long probe_existing_entries(struct pci_pbm_info *pbm,
-                                           struct iommu *iommu)
+static unsigned long __init probe_existing_entries(struct pci_pbm_info *pbm,
+                                                  struct iommu *iommu)
 {
        struct iommu_arena *arena = &iommu->arena;
        unsigned long i, cnt = 0;
@@ -653,7 +653,7 @@ static unsigned long probe_existing_entries(struct pci_pbm_info *pbm,
        return cnt;
 }
 
-static void pci_sun4v_iommu_init(struct pci_pbm_info *pbm)
+static void __init pci_sun4v_iommu_init(struct pci_pbm_info *pbm)
 {
        struct iommu *iommu = pbm->iommu;
        struct property *prop;
index 06d10907d8cee77ed3111a2b87a2a5c6e0bd98cb..b8058906e7271dc3b593d42c299d638138ea987c 100644 (file)
@@ -80,7 +80,7 @@ sys_call_table32:
        .word sys_fchmodat, sys_faccessat, compat_sys_pselect6, compat_sys_ppoll, sys_unshare
 /*300*/        .word compat_sys_set_robust_list, compat_sys_get_robust_list, compat_sys_migrate_pages, compat_sys_mbind, compat_sys_get_mempolicy
        .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, compat_sys_timerfd, sys_eventfd, compat_sys_fallocate
+/*310*/        .word compat_sys_utimensat, compat_sys_signalfd, sys_ni_syscall, sys_eventfd, compat_sys_fallocate
 
 #endif /* CONFIG_COMPAT */
 
@@ -152,7 +152,7 @@ sys_call_table:
        .word sys_fchmodat, sys_faccessat, sys_pselect6, sys_ppoll, sys_unshare
 /*300*/        .word sys_set_robust_list, sys_get_robust_list, sys_migrate_pages, sys_mbind, sys_get_mempolicy
        .word sys_set_mempolicy, sys_kexec_load, sys_move_pages, sys_getcpu, sys_epoll_pwait
-/*310*/        .word sys_utimensat, sys_signalfd, sys_timerfd, sys_eventfd, sys_fallocate
+/*310*/        .word sys_utimensat, sys_signalfd, sys_ni_syscall, sys_eventfd, sys_fallocate
 
 #if defined(CONFIG_SUNOS_EMUL) || defined(CONFIG_SOLARIS_EMUL) || \
     defined(CONFIG_SOLARIS_EMUL_MODULE)
index f9c71d64eba1c2c42dbcefac3e7762d0ba471d2f..6a4f956a2f7a4a99d7388d0dafed55e65b506c30 100644 (file)
@@ -10,7 +10,7 @@
        .align 4;               \
 99:    retl;                   \
         mov    %o1, %o0;       \
-       .section __ex_table;    \
+       .section __ex_table,"a";\
        .align 4;               \
        .word 98b, 99b;         \
        .text;                  \
index f10e4529ee3743b770730de61d03c02ad08aa961..814d5f7a45e1c3e9fe132f094d48a5ce7f050e08 100644 (file)
@@ -10,7 +10,7 @@
        .align 4;               \
 99:    retl;                   \
         mov    %o1, %o0;       \
-       .section __ex_table;    \
+       .section __ex_table,"a";\
        .align 4;               \
        .word 98b, 99b;         \
        .text;                  \
index 75f0e6b951d61b9ff5ef5ecf4187bac65ea785bf..1a4cc5654de4668a5d751644115031e87555a53d 100644 (file)
@@ -6,7 +6,7 @@
 
 #include <asm/rwsem-const.h>
 
-       .section        .sched.text
+       .section        .sched.text, "ax"
 
        .globl          __down_read
 __down_read:
index fbeb55d71e769a116f01a326b708144c3b1e0c54..523e993ee90ca3b46652376a2b3e792b1b462f7d 100644 (file)
@@ -1328,6 +1328,11 @@ 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, pages_avail, shift, phys_base;
index dd1689b814cb5a842c456a0337f66ec9db2dbe2e..99e51d059a02286bb0a80fc25c05f48f64d10058 100644 (file)
@@ -68,6 +68,10 @@ config IRQ_RELEASE_METHOD
        bool
        default y
 
+config HZ
+       int
+       default 100
+
 menu "UML-specific options"
 
 config STATIC_LINK
@@ -95,23 +99,6 @@ config LD_SCRIPT_DYN
        default y
        depends on !LD_SCRIPT_STATIC
 
-config NET
-       bool "Networking support"
-       help
-         Unless you really know what you are doing, you should say Y here.
-         The reason is that some programs need kernel networking support even
-         when running on a stand-alone machine that isn't connected to any
-         other computer. If you are upgrading from an older kernel, you
-         should consider updating your networking tools too because changes
-         in the kernel and the tools often go hand in hand. The tools are
-         contained in the package net-tools, the location and version number
-         of which are given in <file:Documentation/Changes>.
-
-         For a general introduction to Linux networking, it is highly
-         recommended to read the NET-HOWTO, available from
-         <http://www.tldp.org/docs.html#howto>.
-
-
 source "fs/Kconfig.binfmt"
 
 config HOSTFS
@@ -145,7 +132,7 @@ config HPPFS
          by removing or changing anything in /proc which gives away the
          identity of a UML.
 
-         See <http://user-mode-linux.sf.net/hppfs.html> for more information.
+         See <http://user-mode-linux.sf.net/old/hppfs.html> for more information.
 
          You only need this if you are setting up a UML honeypot.  Otherwise,
          it is safe to say 'N' here.
@@ -189,8 +176,7 @@ config MAGIC_SYSRQ
 config SMP
        bool "Symmetric multi-processing support (EXPERIMENTAL)"
        default n
-       #SMP_BROKEN is for x86_64.
-       depends on EXPERIMENTAL && (!SMP_BROKEN || (BROKEN && SMP_BROKEN))
+       depends on BROKEN
        help
          This option enables UML SMP support.
          It is NOT related to having a real SMP box. Not directly, at least.
@@ -289,6 +275,4 @@ config INPUT
        bool
        default n
 
-source "kernel/Kconfig.instrumentation"
-
 source "arch/um/Kconfig.debug"
index 9a78d354f0b40e104a9d5542926e3a6b75cf25e8..3a4b396d7979916177b30d5689b759d277eafe35 100644 (file)
@@ -18,7 +18,7 @@ config SSL
           lines on the UML that are usually made to show up on the host as
           ttys or ptys.
 
-          See <http://user-mode-linux.sourceforge.net/input.html> for more
+          See <http://user-mode-linux.sourceforge.net/old/input.html> for more
           information and command line examples of how to use this facility.
 
           Unless you have a specific reason for disabling this, say Y.
index 1f6462ffd3e8eebce195201308c6806b97375d48..8fce5e536b0fa7a268fb59657c7ddc3f99e5d568 100644 (file)
@@ -4,12 +4,12 @@ source "lib/Kconfig.debug"
 
 config GPROF
        bool "Enable gprof support"
-       depends on DEBUG_INFO
+       depends on DEBUG_INFO && FRAME_POINTER
        help
          This allows profiling of a User-Mode Linux kernel with the gprof
          utility.
 
-         See <http://user-mode-linux.sourceforge.net/gprof.html> for more
+         See <http://user-mode-linux.sourceforge.net/old/gprof.html> for more
          details.
 
          If you're involved in UML kernel development and want to use gprof,
@@ -22,7 +22,7 @@ config GCOV
          This option allows developers to retrieve coverage data from a UML
          session.
 
-         See <http://user-mode-linux.sourceforge.net/gprof.html> for more
+         See <http://user-mode-linux.sourceforge.net/old/gprof.html> for more
          details.
 
          If you're involved in UML kernel development and want to use gcov,
index 66e50026ade9bf6374fb9ddceacbb45db44b8cfa..9e9a4aaa703d60d77dc04aa6e8433bd2592a1f95 100644 (file)
@@ -14,7 +14,7 @@ config UML_NET
 
         For more information, including explanations of the networking and
         sample configurations, see
-        <http://user-mode-linux.sourceforge.net/networking.html>.
+        <http://user-mode-linux.sourceforge.net/old/networking.html>.
 
         If you'd like to be able to enable networking in the User-Mode
         linux environment, say Y; otherwise say N.  Note that you must
@@ -38,7 +38,7 @@ config UML_NET_ETHERTAP
         CONFIG_NETLINK_DEV configured as Y or M.
 
         For more information, see
-        <http://user-mode-linux.sourceforge.net/networking.html>  That site
+        <http://user-mode-linux.sourceforge.net/old/networking.html>  That site
         has examples of the UML command line to use to enable Ethertap
         networking.
 
@@ -72,7 +72,7 @@ config UML_NET_SLIP
         To use this, your host must support slip devices.
 
         For more information, see
-        <http://user-mode-linux.sourceforge.net/networking.html>.  That site
+        <http://user-mode-linux.sourceforge.net/old/networking.html>.
         has examples of the UML command line to use to enable slip
         networking, and details of a few quirks with it.
 
@@ -96,7 +96,7 @@ config UML_NET_DAEMON
         networking daemon on the host.
 
         For more information, see
-        <http://user-mode-linux.sourceforge.net/networking.html>  That site
+        <http://user-mode-linux.sourceforge.net/old/networking.html>  That site
         has examples of the UML command line to use to enable Daemon
         networking.
 
@@ -144,7 +144,7 @@ config UML_NET_MCAST
         To use this, your host kernel(s) must support IP Multicasting.
 
         For more information, see
-        <http://user-mode-linux.sourceforge.net/networking.html>  That site
+        <http://user-mode-linux.sourceforge.net/old/networking.html>  That site
         has examples of the UML command line to use to enable Multicast
         networking, and notes about the security of this approach.
 
@@ -165,7 +165,7 @@ config UML_NET_PCAP
        installed in order to build the pcap transport into UML.
 
         For more information, see
-        <http://user-mode-linux.sourceforge.net/networking.html>  That site
+        <http://user-mode-linux.sourceforge.net/old/networking.html>  That site
         has examples of the UML command line to use to enable this option.
 
        If you intend to use UML as a network monitor for the host, say
index ba6813a4aa3768952e54e927ee4f898589b6004a..cb4af9bf20747bf06b572c669589e1dd0d543c87 100644 (file)
@@ -49,7 +49,7 @@ SYS_DIR               := $(ARCH_DIR)/include/sysdep-$(SUBARCH)
 #
 # These apply to USER_CFLAGS to.
 
-KBUILD_CFLAGS += $(CFLAGS-y) -D__arch_um__ -DSUBARCH=\"$(SUBARCH)\"    \
+KBUILD_CFLAGS += $(CFLAGS) $(CFLAGS-y) -D__arch_um__ -DSUBARCH=\"$(SUBARCH)\" \
        $(ARCH_INCLUDE) $(MODE_INCLUDE) -Dvmap=kernel_vmap      \
        -Din6addr_loopback=kernel_in6addr_loopback \
        -Din6addr_any=kernel_in6addr_any
@@ -58,7 +58,7 @@ KBUILD_AFLAGS += $(ARCH_INCLUDE)
 
 USER_CFLAGS = $(patsubst $(KERNEL_DEFINES),,$(patsubst -D__KERNEL__,,\
        $(patsubst -I%,,$(KBUILD_CFLAGS)))) $(ARCH_INCLUDE) $(MODE_INCLUDE) \
-       -D_FILE_OFFSET_BITS=64
+       $(filter -I%,$(CFLAGS)) -D_FILE_OFFSET_BITS=64
 
 include $(srctree)/$(ARCH_DIR)/Makefile-$(SUBARCH)
 
@@ -130,7 +130,9 @@ CPPFLAGS_vmlinux.lds = -U$(SUBARCH) -DSTART=$(START) -DELF_ARCH=$(ELF_ARCH) \
 # The wrappers will select whether using "malloc" or the kernel allocator.
 LINK_WRAPS = -Wl,--wrap,malloc -Wl,--wrap,free -Wl,--wrap,calloc
 
-CFLAGS_vmlinux := $(LINK-y) $(LINK_WRAPS)
+LD_FLAGS_CMDLINE = $(foreach opt,$(LDFLAGS),-Wl,$(opt))
+
+CFLAGS_vmlinux := $(LINK-y) $(LINK_WRAPS) $(LD_FLAGS_CMDLINE)
 define cmd_vmlinux__
        $(CC) $(CFLAGS_vmlinux) -o $@ \
        -Wl,-T,$(vmlinux-lds) $(vmlinux-init) \
@@ -158,7 +160,7 @@ ifneq ($(KBUILD_SRC),)
        $(Q)mkdir -p $(objtree)/include/asm-um
        $(Q)ln -fsn $(srctree)/include/asm-um/$(basename $(notdir $@))-$(SUBARCH)$(suffix $@) $@
 else
-       $(Q)cd $(TOPDIR)/$(dir $@) ; \
+       $(Q)cd $(srctree)/$(dir $@) ; \
        ln -sf $(basename $(notdir $@))-$(SUBARCH)$(suffix $@) $(notdir $@)
 endif
 
@@ -168,7 +170,7 @@ ifneq ($(KBUILD_SRC),)
        $(Q)mkdir -p $(objtree)/include/asm-um
        $(Q)ln -fsn $(srctree)/include/asm-$(HEADER_ARCH) include/asm-um/arch
 else
-       $(Q)cd $(TOPDIR)/include/asm-um && ln -fsn ../asm-$(HEADER_ARCH) arch
+       $(Q)cd $(srctree)/include/asm-um && ln -fsn ../asm-$(HEADER_ARCH) arch
 endif
 
 $(objtree)/$(ARCH_DIR)/include:
diff --git a/arch/um/Makefile-tt b/arch/um/Makefile-tt
deleted file mode 100644 (file)
index 03f7b10..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-# 
-# Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
-# Licensed under the GPL
-#
-
index f609edede0657fe5cebb1641a8458cb66e9cdd96..86db2862f2226eea9fc6a94f0220bb8db0a48dff 100644 (file)
@@ -77,7 +77,7 @@ CONFIG_LD_SCRIPT_DYN=y
 CONFIG_NET=y
 CONFIG_BINFMT_ELF=y
 CONFIG_BINFMT_MISC=m
-# CONFIG_HOSTFS is not set
+CONFIG_HOSTFS=y
 # CONFIG_HPPFS is not set
 CONFIG_MCONSOLE=y
 CONFIG_MAGIC_SYSRQ=y
@@ -188,7 +188,7 @@ CONFIG_CON_CHAN="xterm"
 CONFIG_SSL_CHAN="pts"
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
-CONFIG_LEGACY_PTY_COUNT=256
+CONFIG_LEGACY_PTY_COUNT=32
 # CONFIG_WATCHDOG is not set
 CONFIG_UML_SOUND=m
 CONFIG_SOUND=m
@@ -508,7 +508,7 @@ CONFIG_DEBUG_KERNEL=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_DETECT_SOFTLOCKUP=y
 # CONFIG_SCHEDSTATS is not set
-CONFIG_DEBUG_SLAB=y
+# CONFIG_DEBUG_SLAB is not set
 # CONFIG_DEBUG_SLAB_LEAK is not set
 # CONFIG_DEBUG_MUTEXES is not set
 # CONFIG_DEBUG_SPINLOCK is not set
index 83bf15a3dda88472dc5aea5ade3353e3f772e0e2..2c898c4d6b6ae6b7864199e73ae2ec32db84f243 100644 (file)
@@ -8,6 +8,7 @@
 #include "chan_kern.h"
 #include "irq_kern.h"
 #include "irq_user.h"
+#include "kern_util.h"
 #include "os.h"
 
 #define LINE_BUFSIZE 4096
@@ -48,7 +49,7 @@ static int write_room(struct line *line)
        n = line->head - line->tail;
 
        if (n <= 0)
-               n = LINE_BUFSIZE + n; /* The other case */
+               n += LINE_BUFSIZE; /* The other case */
        return n - 1;
 }
 
@@ -58,17 +59,10 @@ int line_write_room(struct tty_struct *tty)
        unsigned long flags;
        int room;
 
-       if (tty->stopped)
-               return 0;
-
        spin_lock_irqsave(&line->lock, flags);
        room = write_room(line);
        spin_unlock_irqrestore(&line->lock, flags);
 
-       /*XXX: Warning to remove */
-       if (0 == room)
-               printk(KERN_DEBUG "%s: %s: no room left in buffer\n",
-                      __FUNCTION__,tty->name);
        return room;
 }
 
@@ -79,8 +73,7 @@ int line_chars_in_buffer(struct tty_struct *tty)
        int ret;
 
        spin_lock_irqsave(&line->lock, flags);
-
-       /*write_room subtracts 1 for the needed NULL, so we readd it.*/
+       /* write_room subtracts 1 for the needed NULL, so we readd it.*/
        ret = LINE_BUFSIZE - (write_room(line) + 1);
        spin_unlock_irqrestore(&line->lock, flags);
 
@@ -184,10 +177,6 @@ void line_flush_buffer(struct tty_struct *tty)
        unsigned long flags;
        int err;
 
-       /*XXX: copied from line_write, verify if it is correct!*/
-       if (tty->stopped)
-               return;
-
        spin_lock_irqsave(&line->lock, flags);
        err = flush_buffer(line);
        spin_unlock_irqrestore(&line->lock, flags);
@@ -213,9 +202,6 @@ int line_write(struct tty_struct *tty, const unsigned char *buf, int len)
        unsigned long flags;
        int n, ret = 0;
 
-       if (tty->stopped)
-               return 0;
-
        spin_lock_irqsave(&line->lock, flags);
        if (line->head != line->tail)
                ret = buffer_data(line, buf, len);
@@ -788,9 +774,11 @@ static irqreturn_t winch_interrupt(int irq, void *data)
        tty = winch->tty;
        if (tty != NULL) {
                line = tty->driver_data;
-               chan_window_size(&line->chan_list, &tty->winsize.ws_row,
-                                &tty->winsize.ws_col);
-               kill_pgrp(tty->pgrp, SIGWINCH, 1);
+               if (line != NULL) {
+                       chan_window_size(&line->chan_list, &tty->winsize.ws_row,
+                                        &tty->winsize.ws_col);
+                       kill_pgrp(tty->pgrp, SIGWINCH, 1);
+               }
        }
  out:
        if (winch->fd != -1)
index 0f3c7d14a6e32977d1731a7c46daa51e08182534..ebb265c07e4de008a17ecb0898febf419cb69042 100644 (file)
@@ -1,23 +1,25 @@
 /*
  * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org)
- * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
+ * Copyright (C) 2001 - 2008 Jeff Dike (jdike@{addtoit,linux.intel}.com)
  * Licensed under the GPL
  */
 
-#include "linux/console.h"
-#include "linux/ctype.h"
-#include "linux/interrupt.h"
-#include "linux/list.h"
-#include "linux/mm.h"
-#include "linux/module.h"
-#include "linux/notifier.h"
-#include "linux/reboot.h"
-#include "linux/proc_fs.h"
-#include "linux/slab.h"
-#include "linux/syscalls.h"
-#include "linux/utsname.h"
-#include "linux/workqueue.h"
-#include "asm/uaccess.h"
+#include <linux/console.h>
+#include <linux/ctype.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/proc_fs.h>
+#include <linux/slab.h>
+#include <linux/syscalls.h>
+#include <linux/utsname.h>
+#include <linux/workqueue.h>
+#include <linux/mutex.h>
+#include <asm/uaccess.h>
+
 #include "init.h"
 #include "irq_kern.h"
 #include "irq_user.h"
@@ -305,7 +307,9 @@ void mconsole_stop(struct mc_request *req)
        deactivate_fd(req->originating_fd, MCONSOLE_IRQ);
        os_set_fd_block(req->originating_fd, 1);
        mconsole_reply(req, "stopped", 0, 0);
-       while (mconsole_get_request(req->originating_fd, req)) {
+       for (;;) {
+               if (!mconsole_get_request(req->originating_fd, req))
+                       continue;
                if (req->cmd->handler == mconsole_go)
                        break;
                if (req->cmd->handler == mconsole_stop) {
@@ -358,7 +362,7 @@ struct unplugged_pages {
        void *pages[UNPLUGGED_PER_PAGE];
 };
 
-static DECLARE_MUTEX(plug_mem_mutex);
+static DEFINE_MUTEX(plug_mem_mutex);
 static unsigned long long unplugged_pages_count = 0;
 static LIST_HEAD(unplugged_pages);
 static int unplug_index = UNPLUGGED_PER_PAGE;
@@ -394,7 +398,7 @@ static int mem_config(char *str, char **error_out)
 
        diff /= PAGE_SIZE;
 
-       down(&plug_mem_mutex);
+       mutex_lock(&plug_mem_mutex);
        for (i = 0; i < diff; i++) {
                struct unplugged_pages *unplugged;
                void *addr;
@@ -451,7 +455,7 @@ static int mem_config(char *str, char **error_out)
 
        err = 0;
 out_unlock:
-       up(&plug_mem_mutex);
+       mutex_unlock(&plug_mem_mutex);
 out:
        return err;
 }
@@ -741,7 +745,6 @@ void mconsole_stack(struct mc_request *req)
 {
        char *ptr = req->request.data;
        int pid_requested= -1;
-       struct task_struct *from = NULL;
        struct task_struct *to = NULL;
 
        /*
@@ -763,9 +766,7 @@ void mconsole_stack(struct mc_request *req)
                return;
        }
 
-       from = current;
-
-       to = find_task_by_pid(pid_requested);
+       to = find_task_by_pid_ns(pid_requested, &init_pid_ns);
        if ((to == NULL) || (pid_requested == 0)) {
                mconsole_reply(req, "Couldn't find that pid", 1, 0);
                return;
@@ -795,6 +796,8 @@ static int __init mconsole_init(void)
                printk(KERN_ERR "Failed to initialize management console\n");
                return 1;
        }
+       if (os_set_fd_block(sock, 0))
+               goto out;
 
        register_reboot_notifier(&reboot_notifier);
 
@@ -803,7 +806,7 @@ static int __init mconsole_init(void)
                             "mconsole", (void *)sock);
        if (err) {
                printk(KERN_ERR "Failed to get IRQ for management console\n");
-               return 1;
+               goto out;
        }
 
        if (notify_socket != NULL) {
@@ -819,6 +822,10 @@ static int __init mconsole_init(void)
        printk(KERN_INFO "mconsole (version %d) initialized on %s\n",
               MCONSOLE_VERSION, mconsole_socket_name);
        return 0;
+
+ out:
+       os_close_file(sock);
+       return 1;
 }
 
 __initcall(mconsole_init);
index 430c024a19b01d270e498df1867059c30661e315..13af2f03ed8479ac8f7f17ce4d7389120cdac297 100644 (file)
@@ -83,9 +83,8 @@ int mconsole_get_request(int fd, struct mc_request *req)
        int len;
 
        req->originlen = sizeof(req->origin);
-       req->len = recvfrom(fd, &req->request, sizeof(req->request),
-                           MSG_DONTWAIT, (struct sockaddr *) req->origin,
-                           &req->originlen);
+       req->len = recvfrom(fd, &req->request, sizeof(req->request), 0,
+                           (struct sockaddr *) req->origin, &req->originlen);
        if (req->len < 0)
                return 0;
 
index 3c6c44ca1ffa5785e1d6f34618628fc75cfea831..1e8f41a9951142e536e22312d25e106b1cf1297e 100644 (file)
@@ -318,7 +318,7 @@ static void setup_etheraddr(char *str, unsigned char *addr, char *name)
        if (str == NULL)
                goto random;
 
-       for (i = 0;i < 6; i++) {
+       for (i = 0; i < 6; i++) {
                addr[i] = simple_strtoul(str, &end, 16);
                if ((end == str) ||
                   ((*end != ':') && (*end != ',') && (*end != '\0'))) {
@@ -343,14 +343,13 @@ static void setup_etheraddr(char *str, unsigned char *addr, char *name)
        }
        if (!is_local_ether_addr(addr)) {
                printk(KERN_WARNING
-                      "Warning: attempt to assign a globally valid ethernet "
+                      "Warning: Assigning a globally valid ethernet "
                       "address to a device\n");
-               printk(KERN_WARNING "You should better enable the 2nd "
-                      "rightmost bit in the first byte of the MAC,\n");
+               printk(KERN_WARNING "You should set the 2nd rightmost bit in "
+                      "the first byte of the MAC,\n");
                printk(KERN_WARNING "i.e. %02x:%02x:%02x:%02x:%02x:%02x\n",
                       addr[0] | 0x02, addr[1], addr[2], addr[3], addr[4],
                       addr[5]);
-               goto random;
        }
        return;
 
@@ -368,7 +367,6 @@ static struct platform_driver uml_net_driver = {
                .name  = DRIVER_NAME,
        },
 };
-static int driver_registered;
 
 static void net_device_release(struct device *dev)
 {
@@ -383,6 +381,12 @@ static void net_device_release(struct device *dev)
        free_netdev(netdev);
 }
 
+/*
+ * Ensures that platform_driver_register is called only once by
+ * eth_configure.  Will be set in an initcall.
+ */
+static int driver_registered;
+
 static void eth_configure(int n, void *init, char *mac,
                          struct transport *transport)
 {
index 29185cad9fff97328b8b3be7a4cf6dfba6130f47..abf2653f5517cbf6f65b851dd10455e7bc8e27e2 100644 (file)
@@ -201,7 +201,7 @@ static int change_tramp(char **argv, char *output, int output_len)
        close(fds[1]);
 
        if (pid > 0)
-               helper_wait(pid, 0, "change_tramp");
+               helper_wait(pid);
        return pid;
 }
 
index 330543b3129b5a7ac613e3566456eaf3ef50040c..19930081d3d8e93c42c7c0cf3d8be783ede5c304 100644 (file)
@@ -6,6 +6,7 @@
 #include "linux/completion.h"
 #include "linux/interrupt.h"
 #include "linux/list.h"
+#include "linux/mutex.h"
 #include "asm/atomic.h"
 #include "init.h"
 #include "irq_kern.h"
@@ -120,7 +121,7 @@ static int port_accept(struct port_list *port)
        return 0;
 }
 
-static DECLARE_MUTEX(ports_sem);
+static DEFINE_MUTEX(ports_mutex);
 static LIST_HEAD(ports);
 
 static void port_work_proc(struct work_struct *unused)
@@ -161,7 +162,7 @@ void *port_data(int port_num)
        struct port_dev *dev = NULL;
        int fd;
 
-       down(&ports_sem);
+       mutex_lock(&ports_mutex);
        list_for_each(ele, &ports) {
                port = list_entry(ele, struct port_list, list);
                if (port->port == port_num)
@@ -216,7 +217,7 @@ void *port_data(int port_num)
  out_free:
        kfree(port);
  out:
-       up(&ports_sem);
+       mutex_unlock(&ports_mutex);
        return dev;
 }
 
index e942e836f9954335651fc3c2b6587c2bd7d7e888..71f0959c15357b4587cd10c816d3eca1db1fbe92 100644 (file)
@@ -5,6 +5,7 @@
  * This software may be used and distributed according to the terms
  * of the GNU General Public License, incorporated herein by reference.
  */
+#include <linux/sched.h>
 #include <linux/module.h>
 #include <linux/fs.h>
 #include <linux/miscdevice.h>
index b8711e50da801582081409b2c1d43ce398c83b67..8b80505a3fb0117ed35676de600cce0b11b2f721 100644 (file)
@@ -109,7 +109,7 @@ static int slip_tramp(char **argv, int fd)
        read_output(fds[0], output, output_len);
        printk("%s", output);
 
-       err = helper_wait(pid, 0, argv[0]);
+       err = helper_wait(pid);
        close(fds[0]);
 
 out_free:
index 89c1be225fda5f23525f0799673ba37fe11b6483..a0ada8fec72ab5cde45462e3a2ed0311a0561e50 100644 (file)
@@ -98,7 +98,7 @@ static void slirp_close(int fd, void *data)
                       "(%d)\n", pri->pid, errno);
        }
 #endif
-       err = helper_wait(pri->pid, 1, "slirp_close");
+       err = helper_wait(pri->pid);
        if (err < 0)
                return;
 
index 875d60d0c6a25da5ab3694378dfe22fec4bf1004..f1786e64607f11d785ab333bbe46e6ba3c8d7f0e 100644 (file)
@@ -15,7 +15,6 @@
 #include "line.h"
 #include "ssl.h"
 #include "chan_kern.h"
-#include "kern_util.h"
 #include "kern.h"
 #include "init.h"
 #include "irq_user.h"
index 656036e90b196958d13e593bcff3180ebb4a25cd..cec0c33cdd395d6461783c2793a74e18acfc07b6 100644 (file)
@@ -22,7 +22,6 @@
 #include "stdio_console.h"
 #include "line.h"
 #include "chan_kern.h"
-#include "kern_util.h"
 #include "irq_user.h"
 #include "mconsole_kern.h"
 #include "init.h"
index 99f9f9605e9c53761ad03774a2e72606254a7cc1..be3a2797dac4ee054c3c4f5e44734d2d76ce85f7 100644 (file)
@@ -49,6 +49,7 @@
 #include "irq_user.h"
 #include "irq_kern.h"
 #include "ubd_user.h"
+#include "kern_util.h"
 #include "os.h"
 #include "mem.h"
 #include "mem_kern.h"
@@ -229,7 +230,7 @@ static int proc_ide_read_media(char *page, char **start, off_t off, int count,
        return len;
 }
 
-static void make_ide_entries(char *dev_name)
+static void make_ide_entries(const char *dev_name)
 {
        struct proc_dir_entry *dir, *ent;
        char name[64];
@@ -244,7 +245,7 @@ static void make_ide_entries(char *dev_name)
        ent->data = NULL;
        ent->read_proc = proc_ide_read_media;
        ent->write_proc = NULL;
-       sprintf(name,"ide0/%s", dev_name);
+       snprintf(name, sizeof(name), "ide0/%s", dev_name);
        proc_symlink(dev_name, proc_ide_root, name);
 }
 
@@ -437,7 +438,10 @@ __uml_help(ubd_setup,
 "    machine by running 'dd' on the device. <n> must be in the range\n"
 "    0 to 7. Appending an 'r' to the number will cause that device\n"
 "    to be mounted read-only. For example ubd1r=./ext_fs. Appending\n"
-"    an 's' will cause data to be written to disk on the host immediately.\n\n"
+"    an 's' will cause data to be written to disk on the host immediately.\n"
+"    'c' will cause the device to be treated as being shared between multiple\n"
+"    UMLs and file locking will be turned off - this is appropriate for a\n"
+"    cluster filesystem and inappropriate at almost all other times.\n\n"
 );
 
 static int udb_setup(char *str)
@@ -456,20 +460,6 @@ __uml_help(udb_setup,
 "    in the boot output.\n\n"
 );
 
-static int fakehd_set = 0;
-static int fakehd(char *str)
-{
-       printk(KERN_INFO "fakehd : Changing ubd name to \"hd\".\n");
-       fakehd_set = 1;
-       return 1;
-}
-
-__setup("fakehd", fakehd);
-__uml_help(fakehd,
-"fakehd\n"
-"    Change the ubd device name to \"hd\".\n\n"
-);
-
 static void do_ubd_request(struct request_queue * q);
 
 /* Only changed by ubd_init, which is an initcall. */
@@ -718,8 +708,10 @@ static int ubd_add(int n, char **error_out)
                ubd_disk_register(fake_major, ubd_dev->size, n,
                                  &fake_gendisk[n]);
 
-       /* perhaps this should also be under the "if (fake_major)" above */
-       /* using the fake_disk->disk_name and also the fakehd_set name */
+       /*
+        * Perhaps this should also be under the "if (fake_major)" above
+        * using the fake_disk->disk_name
+        */
        if (fake_ide)
                make_ide_entries(ubd_gendisk[n]->disk_name);
 
index 48fc7452bc1d11e3f3aad9c40c6983dac8526fc9..b591bb9c41dd83f4b72152c42c8ae70c60218698 100644 (file)
@@ -16,7 +16,6 @@
 #include <sys/mman.h>
 #include <sys/param.h>
 #include "asm/types.h"
-#include "kern_util.h"
 #include "user.h"
 #include "ubd_user.h"
 #include "os.h"
index d9941fe5f9316fef619fdc11aee4fb6cbbfde911..56533db25343129bcd60c152744966a2b84241cc 100644 (file)
@@ -80,7 +80,7 @@ void vde_init_libstuff(struct vde_data *vpri, struct vde_init *init)
 
        vpri->args = kmalloc(sizeof(struct vde_open_args), UM_GFP_KERNEL);
        if (vpri->args == NULL) {
-               printk(UM_KERN_ERR "vde_init_libstuff - vde_open_args"
+               printk(UM_KERN_ERR "vde_init_libstuff - vde_open_args "
                       "allocation failed");
                return;
        }
index 49c601ff2bac31955326a907938ccf6f4ff86b35..2de92a08a76bb7eaeb81fe408ee5bd1ced7ce0a7 100644 (file)
@@ -10,6 +10,6 @@
 
 extern void arch_check_bugs(void);
 extern int arch_fixup(unsigned long address, struct uml_pt_regs *regs);
-extern int arch_handle_signal(int sig, struct uml_pt_regs *regs);
+extern void arch_examine_signal(int sig, struct uml_pt_regs *regs);
 
 #endif
index a5cdf953e04a964569e9ea6f2912e9a9b9d6369a..606bb5c7fdf6a2714d68111cf96c0c7a72eed012 100644 (file)
 #include "kern_constants.h"
 
 /*
- * Assembly doesn't want any casting, but C does, so define these
- * without casts here, and define new symbols with casts inside the C
- * section.
+ * Stolen from linux/const.h, which can't be directly included since
+ * this is used in userspace code, which has no access to the kernel
+ * headers.  Changed to be suitable for adding casts to the start,
+ * rather than "UL" to the end.
  */
-#define ASM_STUB_CODE (UML_CONFIG_TOP_ADDR - 2 * UM_KERN_PAGE_SIZE)
-#define ASM_STUB_DATA (UML_CONFIG_TOP_ADDR - UM_KERN_PAGE_SIZE)
-#define ASM_STUB_START ASM_STUB_CODE
 
-/*
- * This file is included by the assembly stubs, which just want the
- * definitions above.
+/* Some constant macros are used in both assembler and
+ * C code.  Therefore we cannot annotate them always with
+ * 'UL' and other type specifiers unilaterally.  We
+ * use the following macros to deal with this.
  */
-#ifndef __ASSEMBLY__
 
-#define STUB_CODE ((unsigned long) ASM_STUB_CODE)
-#define STUB_DATA ((unsigned long) ASM_STUB_DATA)
-#define STUB_START ((unsigned long) ASM_STUB_START)
+#ifdef __ASSEMBLY__
+#define _AC(X, Y)      (Y)
+#else
+#define __AC(X, Y)     (X (Y))
+#define _AC(X, Y)      __AC(X, Y)
+#endif
+
+#define STUB_START _AC(, 0x100000)
+#define STUB_CODE _AC((unsigned long), STUB_START)
+#define STUB_DATA _AC((unsigned long), STUB_CODE + UM_KERN_PAGE_SIZE)
+#define STUB_END _AC((unsigned long), STUB_DATA + UM_KERN_PAGE_SIZE)
+
+#ifndef __ASSEMBLY__
 
 #include "sysdep/ptrace.h"
 
index 5a2263e05bb20cb62bf5b8f7eecc02cde8d324b6..9b9ced85b70378457479215c85558ebb25e05388 100644 (file)
@@ -48,7 +48,7 @@ extern void register_winch_irq(int fd, int tty_fd, int pid,
 #define __channel_help(fn, prefix) \
 __uml_help(fn, prefix "[0-9]*=<channel description>\n" \
 "    Attach a console or serial line to a host channel.  See\n" \
-"    http://user-mode-linux.sourceforge.net/input.html for a complete\n" \
+"    http://user-mode-linux.sourceforge.net/old/input.html for a complete\n" \
 "    description of this switch.\n\n" \
 );
 
index 0edab695ed4e3e665588435d6bb07074a1b692ad..b54bd35585c2d7c306dd6e6def01c2d958dc9d2b 100644 (file)
@@ -18,6 +18,7 @@ DEFINE_STR(UM_KERN_WARNING, KERN_WARNING);
 DEFINE_STR(UM_KERN_NOTICE, KERN_NOTICE);
 DEFINE_STR(UM_KERN_INFO, KERN_INFO);
 DEFINE_STR(UM_KERN_DEBUG, KERN_DEBUG);
+DEFINE_STR(UM_KERN_CONT, KERN_CONT);
 
 DEFINE(UM_ELF_CLASS, ELF_CLASS);
 DEFINE(UM_ELFCLASS32, ELFCLASS32);
index cebc6cae91903442235e8f4b4e782b71a5feb5c9..b00a95741d4115339db192cddf54a7ba1b977ab7 100644 (file)
 typedef int (*initcall_t)(void);
 typedef void (*exitcall_t)(void);
 
+#ifndef __KERNEL__
+#ifndef __section
+# define __section(S) __attribute__ ((__section__(#S)))
+#endif
+
+#if __GNUC_MINOR__ >= 3
+# define __used                        __attribute__((__used__))
+#else
+# define __used                        __attribute__((__unused__))
+#endif
+
+#else
+#include <linux/compiler.h>
+#endif
 /* These are for everybody (although not all archs will actually
    discard it in modules) */
 #define __init         __section(.init.text)
@@ -127,14 +141,3 @@ extern struct uml_param __uml_setup_start, __uml_setup_end;
 #endif
 
 #endif /* _LINUX_UML_INIT_H */
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
index 884a9c17eea08b55c87086958b5991a1b8b2f2e6..e60b31873de135ebd949723ca2cdc283deab31d3 100644 (file)
@@ -14,7 +14,6 @@ struct irq_fd {
        int fd;
        int type;
        int irq;
-       int pid;
        int events;
        int current_events;
 };
index 74ce8e5370a6f50666d565a8fb99f3bb11ba2675..3c341222d2525e740a5beda96fa09c8819d97323 100644 (file)
 #include "sysdep/ptrace.h"
 #include "sysdep/faultinfo.h"
 
-typedef void (*kern_hndl)(int, struct uml_pt_regs *);
-
-struct kern_handlers {
-       kern_hndl relay_signal;
-       kern_hndl winch;
-       kern_hndl bus_handler;
-       kern_hndl page_fault;
-       kern_hndl sigio_handler;
-       kern_hndl timer_handler;
-};
-
-extern const struct kern_handlers handlinfo_kern;
+extern int uml_exitcode;
 
 extern int ncpus;
-extern char *gdb_init;
 extern int kmalloc_ok;
-extern int jail;
-extern int nsyscalls;
 
-#define UML_ROUND_DOWN(addr) ((void *)(((unsigned long) addr) & PAGE_MASK))
 #define UML_ROUND_UP(addr) \
-       UML_ROUND_DOWN(((unsigned long) addr) + PAGE_SIZE - 1)
+       ((((unsigned long) addr) + PAGE_SIZE - 1) & PAGE_MASK)
 
-extern int kernel_fork(unsigned long flags, int (*fn)(void *), void * arg);
-extern int kernel_thread_proc(void *data);
-extern void syscall_segv(int sig);
-extern int current_pid(void);
 extern unsigned long alloc_stack(int order, int atomic);
+extern void free_stack(unsigned long stack, int order);
+
 extern int do_signal(void);
-extern int is_stack_fault(unsigned long sp);
+extern void copy_sc(struct uml_pt_regs *regs, void *from);
+extern void interrupt_end(void);
+extern void relay_signal(int sig, struct uml_pt_regs *regs);
+
 extern unsigned long segv(struct faultinfo fi, unsigned long ip,
                          int is_user, struct uml_pt_regs *regs);
 extern int handle_page_fault(unsigned long address, unsigned long ip,
                             int is_write, int is_user, int *code_out);
-extern void syscall_ready(void);
-extern void set_tracing(void *t, int tracing);
-extern int is_tracing(void *task);
-extern int segv_syscall(void);
-extern void kern_finish_exec(void *task, int new_pid, unsigned long stack);
-extern unsigned long page_mask(void);
-extern int need_finish_fork(void);
-extern void free_stack(unsigned long stack, int order);
-extern void add_input_request(int op, void (*proc)(int), void *arg);
-extern char *current_cmd(void);
-extern void timer_handler(int sig, struct uml_pt_regs *regs);
-extern int set_signals(int enable);
-extern int pid_to_processor_id(int pid);
-extern void deliver_signals(void *t);
-extern int next_trap_index(int max);
-extern void default_idle(void);
-extern void finish_fork(void);
-extern void paging_init(void);
-extern void init_flush_vm(void);
-extern void *syscall_sp(void *t);
-extern void syscall_trace(struct uml_pt_regs *regs, int entryexit);
+
 extern unsigned int do_IRQ(int irq, struct uml_pt_regs *regs);
-extern void interrupt_end(void);
-extern void initial_thread_cb(void (*proc)(void *), void *arg);
-extern int debugger_signal(int status, int pid);
-extern void debugger_parent_signal(int status, int pid);
-extern void child_signal(int pid, int status);
-extern int init_ptrace_proxy(int idle_pid, int startup, int stop);
-extern int init_parent_proxy(int pid);
-extern int singlestepping(void *t);
-extern void check_stack_overflow(void *ptr);
-extern void relay_signal(int sig, struct uml_pt_regs *regs);
-extern int user_context(unsigned long sp);
-extern void timer_irq(struct uml_pt_regs *regs);
-extern void do_uml_exitcalls(void);
-extern int attach_debugger(int idle_pid, int pid, int stop);
-extern int config_gdb(char *str);
-extern int remove_gdb(void);
-extern char *uml_strdup(char *string);
-extern void unprotect_kernel_mem(void);
-extern void protect_kernel_mem(void);
-extern void uml_cleanup(void);
-extern void lock_signalled_task(void *t);
-extern void IPI_handler(int cpu);
-extern int jail_setup(char *line, int *add);
-extern void *get_init_task(void);
-extern int clear_user_proc(void *buf, int size);
-extern int copy_to_user_proc(void *to, void *from, int size);
-extern int copy_from_user_proc(void *to, void *from, int size);
-extern int strlen_user_proc(char *str);
-extern long execute_syscall(void *r);
 extern int smp_sigio_handler(void);
-extern void *get_current(void);
-extern struct task_struct *get_task(int pid, int require);
-extern void machine_halt(void);
+extern void initial_thread_cb(void (*proc)(void *), void *arg);
 extern int is_syscall(unsigned long addr);
+extern void timer_handler(int sig, struct uml_pt_regs *regs);
 
-extern void free_irq(unsigned int, void *);
-extern int cpu(void);
+extern void timer_handler(int sig, struct uml_pt_regs *regs);
 
-extern void time_init_kern(void);
+extern int start_uml(void);
+extern void paging_init(void);
 
-/* Are we disallowed to sleep? Used to choose between GFP_KERNEL and GFP_ATOMIC. */
+extern void uml_cleanup(void);
+extern void do_uml_exitcalls(void);
+
+/*
+ * Are we disallowed to sleep? Used to choose between GFP_KERNEL and
+ * GFP_ATOMIC.
+ */
 extern int __cant_sleep(void);
-extern void sigio_handler(int sig, struct uml_pt_regs *regs);
-extern void copy_sc(struct uml_pt_regs *regs, void *from);
+extern void *get_current(void);
+extern int copy_from_user_proc(void *to, void *from, int size);
+extern int cpu(void);
+extern char *uml_strdup(const char *string);
+
 extern unsigned long to_irq_stack(unsigned long *mask_out);
-unsigned long from_irq_stack(int nested);
-extern int start_uml(void);
+extern unsigned long from_irq_stack(int nested);
+
+extern void syscall_trace(struct uml_pt_regs *regs, int entryexit);
+extern int singlestepping(void *t);
+
+extern void segv_handler(int sig, struct uml_pt_regs *regs);
+extern void bus_handler(int sig, struct uml_pt_regs *regs);
+extern void winch(int sig, struct uml_pt_regs *regs);
+extern void fatal_sigsegv(void) __attribute__ ((noreturn));
+
+
 #endif
index a54514d2cc3ab81aa9e4244bb9f36f99f622a5b5..46384acd547b7590bd75e4f564cf203327e2e522 100644 (file)
@@ -46,9 +46,6 @@ extern int iomem_size;
 
 #define ROUND_4M(n) ((((unsigned long) (n)) + (1 << 22)) & ~((1 << 22) - 1))
 
-extern unsigned long host_task_size;
-extern unsigned long task_size;
-
 extern int init_mem_user(void);
 extern void setup_memory(void *entry);
 extern unsigned long find_iomem(char *driver, unsigned long *len_out);
@@ -59,9 +56,7 @@ extern void setup_physmem(unsigned long start, unsigned long usable,
                          unsigned long len, unsigned long long highmem);
 extern void add_iomem(char *name, int fd, unsigned long size);
 extern unsigned long phys_offset(unsigned long phys);
-extern void unmap_physmem(void);
 extern void map_memory(unsigned long virt, unsigned long phys,
                       unsigned long len, int r, int w, int x);
-extern unsigned long get_kmem_end(void);
 
 #endif
diff --git a/arch/um/include/misc_constants.h b/arch/um/include/misc_constants.h
deleted file mode 100644 (file)
index 989bc08..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __MISC_CONSTANT_H_
-#define __MISC_CONSTANT_H_
-
-#include <user_constants.h>
-
-#endif
index 6f0d1c741bcad5660be289861c4b71e48c088af2..0b6b6273330392122c82dc1e9b845f5d03bff3b2 100644 (file)
@@ -8,7 +8,6 @@
 
 #include <stdarg.h>
 #include "irq_user.h"
-#include "kern_util.h"
 #include "longjmp.h"
 #include "mm_id.h"
 #include "sysdep/tls.h"
@@ -128,33 +127,31 @@ static inline struct openflags of_cloexec(struct openflags flags)
 extern int os_stat_file(const char *file_name, struct uml_stat *buf);
 extern int os_stat_fd(const int fd, struct uml_stat *buf);
 extern int os_access(const char *file, int mode);
-extern int os_get_exec_close(int fd, int *close_on_exec);
 extern int os_set_exec_close(int fd);
 extern int os_ioctl_generic(int fd, unsigned int cmd, unsigned long arg);
 extern int os_get_ifname(int fd, char *namebuf);
 extern int os_set_slip(int fd);
-extern int os_set_owner(int fd, int pid);
 extern int os_mode_fd(int fd, int mode);
 
 extern int os_seek_file(int fd, unsigned long long offset);
-extern int os_open_file(char *file, struct openflags flags, int mode);
+extern int os_open_file(const char *file, struct openflags flags, int mode);
 extern int os_read_file(int fd, void *buf, int len);
 extern int os_write_file(int fd, const void *buf, int count);
-extern int os_file_size(char *file, unsigned long long *size_out);
-extern int os_file_modtime(char *file, unsigned long *modtime);
+extern int os_file_size(const char *file, unsigned long long *size_out);
+extern int os_file_modtime(const char *file, unsigned long *modtime);
 extern int os_pipe(int *fd, int stream, int close_on_exec);
-extern int os_set_fd_async(int fd, int owner);
+extern int os_set_fd_async(int fd);
 extern int os_clear_fd_async(int fd);
 extern int os_set_fd_block(int fd, int blocking);
 extern int os_accept_connection(int fd);
-extern int os_create_unix_socket(char *file, int len, int close_on_exec);
+extern int os_create_unix_socket(const char *file, int len, int close_on_exec);
 extern int os_shutdown_socket(int fd, int r, int w);
 extern void os_close_file(int fd);
 extern int os_rcv_fd(int fd, int *helper_pid_out);
 extern int create_unix_socket(char *file, int len, int close_on_exec);
-extern int os_connect_socket(char *name);
+extern int os_connect_socket(const char *name);
 extern int os_file_type(char *file);
-extern int os_file_mode(char *file, struct openflags *mode_out);
+extern int os_file_mode(const char *file, struct openflags *mode_out);
 extern int os_lock_file(int fd, int excl);
 extern void os_flush_stdout(void);
 extern int os_stat_filesystem(char *path, long *bsize_out,
@@ -168,14 +165,10 @@ extern int os_fchange_dir(int fd);
 
 /* start_up.c */
 extern void os_early_checks(void);
-extern int can_do_skas(void);
+extern void can_do_skas(void);
 extern void os_check_bugs(void);
 extern void check_host_supports_tls(int *supports_tls, int *tls_min);
 
-/* Make sure they are clear when running in TT mode. Required by
- * SEGV_MAYBE_FIXABLE */
-#define clear_can_do_skas() do { ptrace_faultinfo = proc_mm = 0; } while (0)
-
 /* mem.c */
 extern int create_mem_file(unsigned long long len);
 
@@ -214,7 +207,7 @@ extern int execvp_noalloc(char *buf, const char *file, char *const argv[]);
 extern int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv);
 extern int run_helper_thread(int (*proc)(void *), void *arg,
                             unsigned int flags, unsigned long *stack_out);
-extern int helper_wait(int pid, int nohang, char *pname);
+extern int helper_wait(int pid);
 
 
 /* tls.c */
@@ -237,16 +230,12 @@ extern void unblock_signals(void);
 extern int get_signals(void);
 extern int set_signals(int enable);
 
-/* trap.c */
-extern void os_fill_handlinfo(struct kern_handlers h);
-
 /* util.c */
 extern void stack_protections(unsigned long address);
 extern int raw(int fd);
 extern void setup_machinename(char *machine_out);
 extern void setup_hostinfo(char *buf, int len);
-extern int setjmp_wrapper(void (*proc)(void *, void *), ...);
-extern void os_dump_core(void);
+extern void os_dump_core(void) __attribute__ ((noreturn));
 
 /* time.c */
 extern void idle_sleep(unsigned long long nsecs);
@@ -275,11 +264,9 @@ extern int protect(struct mm_id * mm_idp, unsigned long addr,
 extern int is_skas_winch(int pid, int fd, void *data);
 extern int start_userspace(unsigned long stub_stack);
 extern int copy_context_skas0(unsigned long stack, int pid);
-extern void save_registers(int pid, struct uml_pt_regs *regs);
-extern void restore_registers(int pid, struct uml_pt_regs *regs);
 extern void userspace(struct uml_pt_regs *regs);
-extern void map_stub_pages(int fd, unsigned long code,
-                          unsigned long data, unsigned long stack);
+extern int map_stub_pages(int fd, unsigned long code, unsigned long data,
+                         unsigned long stack);
 extern void new_thread(void *stack, jmp_buf *buf, void (*handler)(void));
 extern void switch_threads(jmp_buf *me, jmp_buf *you);
 extern int start_idle_thread(void *stack, jmp_buf *switch_buf);
@@ -298,16 +285,12 @@ extern void os_free_irq_later(struct irq_fd *active_fds,
 extern int os_get_pollfd(int i);
 extern void os_set_pollfd(int i, int fd);
 extern void os_set_ioignore(void);
-extern void init_irq_signals(int on_sigstack);
 
 /* sigio.c */
 extern int add_sigio_fd(int fd);
 extern int ignore_sigio_fd(int fd);
 extern void maybe_sigio_broken(int fd, int read);
 
-/* skas/trap */
-extern void sig_handler_common_skas(int sig, void *sc_ptr);
-
 /* sys-x86_64/prctl.c */
 extern int os_arch_prctl(int pid, int code, unsigned long *addr);
 
index f3450e6bc18d3d9bf63269ebebee186d73b28828..4bce6e0128895ddad042c7959526a0e9f67eaf92 100644 (file)
@@ -1,5 +1,5 @@
 /* 
- * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
  * Licensed under the GPL
  */
 
 
 extern int ptrace_getregs(long pid, unsigned long *regs_out);
 extern int ptrace_setregs(long pid, unsigned long *regs_in);
-extern int ptrace_getfpregs(long pid, unsigned long *regs_out);
-extern int ptrace_setfpregs(long pid, unsigned long *regs);
-extern void arch_enter_kernel(void *task, int pid);
-extern void arch_leave_kernel(void *task, int pid);
-extern void ptrace_pokeuser(unsigned long addr, unsigned long data);
-
 
 /* syscall emulation path in ptrace */
 
@@ -54,7 +48,8 @@ extern int sysemu_supported;
        (((int[3][3] ) { \
                { PTRACE_SYSCALL, PTRACE_SYSCALL, PTRACE_SINGLESTEP }, \
                { PTRACE_SYSEMU, PTRACE_SYSEMU, PTRACE_SINGLESTEP }, \
-               { PTRACE_SYSEMU, PTRACE_SYSEMU_SINGLESTEP, PTRACE_SYSEMU_SINGLESTEP }}) \
+               { PTRACE_SYSEMU, PTRACE_SYSEMU_SINGLESTEP, \
+                 PTRACE_SYSEMU_SINGLESTEP } }) \
                [sysemu_mode][singlestep_mode])
 
 #endif
index 0e27406a43a4d24f311af678b10a71dbd51a6ffa..9ea1ae3c8f464d8c8b138eecf8d3694f238d32c5 100644 (file)
@@ -9,14 +9,13 @@
 #include "sysdep/ptrace.h"
 #include "sysdep/archsetjmp.h"
 
-extern void init_thread_registers(struct uml_pt_regs *to);
 extern int save_fp_registers(int pid, unsigned long *fp_regs);
 extern int restore_fp_registers(int pid, unsigned long *fp_regs);
 extern int save_fpx_registers(int pid, unsigned long *fp_regs);
 extern int restore_fpx_registers(int pid, unsigned long *fp_regs);
-extern void save_registers(int pid, struct uml_pt_regs *regs);
-extern void restore_registers(int pid, struct uml_pt_regs *regs);
-extern void init_registers(int pid);
+extern int save_registers(int pid, struct uml_pt_regs *regs);
+extern int restore_registers(int pid, struct uml_pt_regs *regs);
+extern int init_registers(int pid);
 extern void get_safe_registers(unsigned long *regs);
 extern unsigned long get_thread_reg(int reg, jmp_buf *buf);
 
diff --git a/arch/um/include/signal_kern.h b/arch/um/include/signal_kern.h
deleted file mode 100644 (file)
index aeb5d5a..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-/* 
- * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
- * Licensed under the GPL
- */
-
-#ifndef __SIGNAL_KERN_H__
-#define __SIGNAL_KERN_H__
-
-extern int have_signals(void *t);
-
-#endif
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/include/skas/mode-skas.h b/arch/um/include/skas/mode-skas.h
deleted file mode 100644 (file)
index e065feb..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-/*
- * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{linux.intel,addtoit}.com)
- * Licensed under the GPL
- */
-
-#ifndef __MODE_SKAS_H__
-#define __MODE_SKAS_H__
-
-extern void kill_off_processes_skas(void);
-
-#endif
index 57bd79efbee305887c0ac59cfa2504e3d6a1a2ba..905698197e35fc2f4fd612b0495bd846d3253a65 100644 (file)
@@ -1,5 +1,5 @@
 /* 
- * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Copyright (C) 2000 - 2008 Jeff Dike (jdike@{addtoit,linux.intel}.com)
  * Licensed under the GPL
  */
 
@@ -18,7 +18,8 @@ extern syscall_handler_t old_mmap_i386;
 extern syscall_handler_t *sys_call_table[];
 
 #define EXECUTE_SYSCALL(syscall, regs) \
-       ((long (*)(struct syscall_args)) (*sys_call_table[syscall]))(SYSCALL_ARGS(&regs->regs))
+       ((long (*)(struct syscall_args)) \
+        (*sys_call_table[syscall]))(SYSCALL_ARGS(&regs->regs))
 
 extern long sys_mmap2(unsigned long addr, unsigned long len,
                      unsigned long prot, unsigned long flags,
index c978b589df419abc42c818dba54012dcbc8fb3f6..a307237b7964394189e220673c160bddf08a6227 100644 (file)
 #define OFFSET(sym, str, mem) \
        DEFINE(sym, offsetof(struct str, mem));
 
-#define __NO_STUBS 1
-#undef __SYSCALL
-#undef _ASM_X86_64_UNISTD_H_
-#define __SYSCALL(nr, sym) [nr] = 1,
-static char syscalls[] = {
-#include <asm/arch/unistd.h>
-};
-
 void foo(void)
 {
 #include <common-offsets.h>
-DEFINE(UM_NR_syscall_max, sizeof(syscalls) - 1);
 }
index cf72256609e4ea29d42b331123b1db672c9c4899..7cfb0b085655b0554565a6178287d48951e76422 100644 (file)
@@ -30,6 +30,4 @@ extern long old_mmap(unsigned long addr, unsigned long len,
 extern syscall_handler_t sys_modify_ldt;
 extern syscall_handler_t sys_arch_prctl;
 
-#define NR_syscalls (UM_NR_syscall_max + 1)
-
 #endif
index 8855d8df512f6877a1e6d1534edbc29bd9275bbd..82865fcf6872eb0e7347d17ecd64cfc408240a02 100644 (file)
 
 typedef struct mm_context {
        struct mm_id id;
-       unsigned long last_page_table;
-#ifdef CONFIG_3_LEVEL_PGTABLES
-       unsigned long last_pmd;
-#endif
        struct uml_ldt ldt;
 } mm_context_t;
 
index fdfc06b85605a5bf709a3b7e3b369b49c766626c..2b6fc8e0f07137bdec6f6b5fcd166f9e79d4e0d6 100644 (file)
@@ -6,7 +6,9 @@
 #ifndef __ARCH_UM_UACCESS_H
 #define __ARCH_UM_UACCESS_H
 
-#include "asm/fixmap.h"
+#include <asm/elf.h>
+#include <asm/fixmap.h>
+#include "sysdep/archsetjmp.h"
 
 #define __under_task_size(addr, size) \
        (((unsigned long) (addr) < TASK_SIZE) && \
index 8196450451cd6332d6b76eb97bbb3b9ffc93a17f..76a62c0cb2bc89692e72df74a096df83f33487e5 100644 (file)
 void flush_thread(void)
 {
        void *data = NULL;
-       unsigned long end = proc_mm ? task_size : STUB_START;
        int ret;
 
        arch_flush_thread(&current->thread.arch);
 
-       ret = unmap(&current->mm->context.id, 0, end, 1, &data);
+       ret = unmap(&current->mm->context.id, 0, STUB_START, 0, &data);
+       ret = ret || unmap(&current->mm->context.id, STUB_END,
+                          TASK_SIZE - STUB_END, 1, &data);
        if (ret) {
                printk(KERN_ERR "flush_thread - clearing address space failed, "
                       "err = %d\n", ret);
index c716b5a6db13d9552a59e7f7ec5688229ca9bf0e..984f80e668ca5d7c85b3f8ae549dc13fa5aabe57 100644 (file)
@@ -1,15 +1,17 @@
 /*
- * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
  * Licensed under the GPL
  */
 
-#include "linux/kernel.h"
-#include "linux/init.h"
-#include "linux/ctype.h"
-#include "linux/proc_fs.h"
-#include "asm/uaccess.h"
+#include <linux/ctype.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/proc_fs.h>
+#include <linux/types.h>
+#include <asm/uaccess.h>
 
-/* If read and write race, the read will still atomically read a valid
+/*
+ * If read and write race, the read will still atomically read a valid
  * value.
  */
 int uml_exitcode = 0;
@@ -19,18 +21,19 @@ static int read_proc_exitcode(char *page, char **start, off_t off,
 {
        int len, val;
 
-       /* Save uml_exitcode in a local so that we don't need to guarantee
+       /*
+        * Save uml_exitcode in a local so that we don't need to guarantee
         * that sprintf accesses it atomically.
         */
        val = uml_exitcode;
        len = sprintf(page, "%d\n", val);
        len -= off;
-       if(len <= off+count)
+       if (len <= off+count)
                *eof = 1;
        *start = page + off;
-       if(len > count)
+       if (len > count)
                len = count;
-       if(len < 0)
+       if (len < 0)
                len = 0;
        return len;
 }
@@ -41,11 +44,11 @@ static int write_proc_exitcode(struct file *file, const char __user *buffer,
        char *end, buf[sizeof("nnnnn\0")];
        int tmp;
 
-       if(copy_from_user(buf, buffer, count))
+       if (copy_from_user(buf, buffer, count))
                return -EFAULT;
 
        tmp = simple_strtol(buf, &end, 0);
-       if((*end != '\0') && !isspace(*end))
+       if ((*end != '\0') && !isspace(*end))
                return -EINVAL;
 
        uml_exitcode = tmp;
@@ -57,7 +60,7 @@ static int make_proc_exitcode(void)
        struct proc_dir_entry *ent;
 
        ent = create_proc_entry("exitcode", 0600, &proc_root);
-       if(ent == NULL){
+       if (ent == NULL) {
                printk(KERN_WARNING "make_proc_exitcode : Failed to register "
                       "/proc/exitcode\n");
                return 0;
index 734f873cab12437885af0d61d7dfe3a902f1ae9b..72eccd2a41132daae3d3dd746901f8535913e290 100644 (file)
@@ -1,5 +1,5 @@
-/* 
- * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
+/*
+ * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
  * Licensed under the GPL
  */
 
@@ -8,12 +8,13 @@
 extern void __bb_init_func(void *)  __attribute__((weak));
 EXPORT_SYMBOL(__bb_init_func);
 
-/* This is defined (and referred to in profiling stub code) only by some GCC
+/*
+ * This is defined (and referred to in profiling stub code) only by some GCC
  * versions in libgcov.
  *
  * Since SuSE backported the fix, we cannot handle it depending on GCC version.
- * So, unconditionally export it. But also give it a weak declaration, which will
- * be overridden by any other one.
+ * So, unconditionally export it. But also give it a weak declaration, which
+ * will be overridden by any other one.
  */
 
 extern void __gcov_init(void *) __attribute__((weak));
index 9244f018d44cf981c478e32d65fbe18fd0492c4d..e2f043d0de6c80fd0050aedb0edf1748efbdb72b 100644 (file)
@@ -1,5 +1,5 @@
 /* 
- * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
  * Licensed under the GPL
  */
 
@@ -7,14 +7,3 @@
 
 extern void mcount(void);
 EXPORT_SYMBOL(mcount);
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
index 16dc43e9d940e305bfe2f42a9a5c35be05eb0a9c..fa015565001b6b46171149e073bfe2e828872566 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
  * Licensed under the GPL
  */
 
@@ -7,7 +7,6 @@
 #include "linux/bootmem.h"
 #include "linux/initrd.h"
 #include "asm/types.h"
-#include "kern_util.h"
 #include "initrd.h"
 #include "init.h"
 #include "os.h"
@@ -21,18 +20,27 @@ static int __init read_initrd(void)
        long long size;
        int err;
 
-       if(initrd == NULL)
+       if (initrd == NULL)
                return 0;
 
        err = os_file_size(initrd, &size);
-       if(err)
+       if (err)
                return 0;
 
+       /*
+        * This is necessary because alloc_bootmem craps out if you
+        * ask for no memory.
+        */
+       if (size == 0) {
+               printk(KERN_ERR "\"%\" is a zero-size initrd\n");
+               return 0;
+       }
+
        area = alloc_bootmem(size);
-       if(area == NULL)
+       if (area == NULL)
                return 0;
 
-       if(load_initrd(initrd, area, size) == -1)
+       if (load_initrd(initrd, area, size) == -1)
                return 0;
 
        initrd_start = (unsigned long) area;
@@ -59,13 +67,15 @@ int load_initrd(char *filename, void *buf, int size)
        int fd, n;
 
        fd = os_open_file(filename, of_read(OPENFLAGS()), 0);
-       if(fd < 0){
-               printk("Opening '%s' failed - err = %d\n", filename, -fd);
+       if (fd < 0) {
+               printk(KERN_ERR "Opening '%s' failed - err = %d\n", filename,
+                      -fd);
                return -1;
        }
        n = os_read_file(fd, buf, size);
-       if(n != size){
-               printk("Read of %d bytes from '%s' failed, err = %d\n", size,
+       if (n != size) {
+               printk(KERN_ERR "Read of %d bytes from '%s' failed, "
+                      "err = %d\n", size,
                       filename, -n);
                return -1;
        }
index ba11ccd6a8a3f72e4ab641a5f79f21a740a1ad0a..91587f8db34019a1045c81159f120eb1bd69c1ce 100644 (file)
@@ -107,10 +107,9 @@ int activate_fd(int irq, int fd, int type, void *dev_id)
        struct pollfd *tmp_pfd;
        struct irq_fd *new_fd, *irq_fd;
        unsigned long flags;
-       int pid, events, err, n;
+       int events, err, n;
 
-       pid = os_getpid();
-       err = os_set_fd_async(fd, pid);
+       err = os_set_fd_async(fd);
        if (err < 0)
                goto out;
 
@@ -127,7 +126,6 @@ int activate_fd(int irq, int fd, int type, void *dev_id)
                                     .fd                = fd,
                                     .type              = type,
                                     .irq               = irq,
-                                    .pid               = pid,
                                     .events            = events,
                                     .current_events    = 0 } );
 
index 7c7142ba3bd7d4c4980b07df559d3524d0fd78be..5311ee93ede3851c3ad311d134f911ec9c483188 100644 (file)
@@ -18,15 +18,11 @@ EXPORT_SYMBOL(set_signals);
 EXPORT_SYMBOL(get_signals);
 EXPORT_SYMBOL(kernel_thread);
 EXPORT_SYMBOL(sys_waitpid);
-EXPORT_SYMBOL(task_size);
 EXPORT_SYMBOL(flush_tlb_range);
-EXPORT_SYMBOL(host_task_size);
 EXPORT_SYMBOL(arch_validate);
-EXPORT_SYMBOL(get_kmem_end);
 
 EXPORT_SYMBOL(high_physmem);
 EXPORT_SYMBOL(empty_zero_page);
-EXPORT_SYMBOL(um_virt_to_phys);
 EXPORT_SYMBOL(handle_page_fault);
 EXPORT_SYMBOL(find_iomem);
 
@@ -40,7 +36,6 @@ EXPORT_SYMBOL(uml_strdup);
 EXPORT_SYMBOL(os_stat_fd);
 EXPORT_SYMBOL(os_stat_file);
 EXPORT_SYMBOL(os_access);
-EXPORT_SYMBOL(os_get_exec_close);
 EXPORT_SYMBOL(os_set_exec_close);
 EXPORT_SYMBOL(os_getpid);
 EXPORT_SYMBOL(os_open_file);
index 59822dee438adfe53f373569f9b74d675726b56d..d872fdce1d7ec76e9d4b37782b2a9ac9dd108395 100644 (file)
@@ -1,49 +1,41 @@
 /*
- * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
+ * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
  * Licensed under the GPL
  */
 
-#include "linux/stddef.h"
-#include "linux/kernel.h"
-#include "linux/mm.h"
-#include "linux/bootmem.h"
-#include "linux/swap.h"
-#include "linux/highmem.h"
-#include "linux/gfp.h"
-#include "asm/page.h"
-#include "asm/fixmap.h"
-#include "asm/pgalloc.h"
-#include "kern_util.h"
+#include <linux/stddef.h>
+#include <linux/bootmem.h>
+#include <linux/gfp.h>
+#include <linux/highmem.h>
+#include <linux/mm.h>
+#include <linux/swap.h>
+#include <asm/fixmap.h>
+#include <asm/page.h>
 #include "as-layout.h"
+#include "init.h"
 #include "kern.h"
+#include "kern_util.h"
 #include "mem_user.h"
-#include "um_uaccess.h"
 #include "os.h"
-#include "linux/types.h"
-#include "linux/string.h"
-#include "init.h"
-#include "kern_constants.h"
 
 /* allocated in paging_init, zeroed in mem_init, and unchanged thereafter */
 unsigned long *empty_zero_page = NULL;
 /* allocated in paging_init and unchanged thereafter */
 unsigned long *empty_bad_page = NULL;
+
+/*
+ * Initialized during boot, and readonly for initializing page tables
+ * afterwards
+ */
 pgd_t swapper_pg_dir[PTRS_PER_PGD];
+
+/* Initialized at boot time, and readonly after that */
 unsigned long long highmem;
 int kmalloc_ok = 0;
 
+/* Used during early boot */
 static unsigned long brk_end;
 
-void unmap_physmem(void)
-{
-       os_unmap_memory((void *) brk_end, uml_reserved - brk_end);
-}
-
-static void map_cb(void *unused)
-{
-       map_memory(brk_end, __pa(brk_end), uml_reserved - brk_end, 1, 1, 0);
-}
-
 #ifdef CONFIG_HIGHMEM
 static void setup_highmem(unsigned long highmem_start,
                          unsigned long highmem_len)
@@ -53,7 +45,7 @@ static void setup_highmem(unsigned long highmem_start,
        int i;
 
        highmem_pfn = __pa(highmem_start) >> PAGE_SHIFT;
-       for(i = 0; i < highmem_len >> PAGE_SHIFT; i++){
+       for (i = 0; i < highmem_len >> PAGE_SHIFT; i++) {
                page = &mem_map[highmem_pfn + i];
                ClearPageReserved(page);
                init_page_count(page);
@@ -65,14 +57,13 @@ static void setup_highmem(unsigned long highmem_start,
 void __init mem_init(void)
 {
        /* clear the zero-page */
-       memset((void *) empty_zero_page, 0, PAGE_SIZE);
+       memset(empty_zero_page, 0, PAGE_SIZE);
 
        /* Map in the area just after the brk now that kmalloc is about
         * to be turned on.
         */
        brk_end = (unsigned long) UML_ROUND_UP(sbrk(0));
-       map_cb(NULL);
-       initial_thread_cb(map_cb, NULL);
+       map_memory(brk_end, __pa(brk_end), uml_reserved - brk_end, 1, 1, 0);
        free_bootmem(__pa(brk_end), uml_reserved - brk_end);
        uml_reserved = brk_end;
 
@@ -85,7 +76,7 @@ void __init mem_init(void)
 #endif
        num_physpages = totalram_pages;
        max_pfn = totalram_pages;
-       printk(KERN_INFO "Memory: %luk available\n", 
+       printk(KERN_INFO "Memory: %luk available\n",
               (unsigned long) nr_free_pages() << (PAGE_SHIFT-10));
        kmalloc_ok = 1;
 
@@ -119,7 +110,7 @@ static void __init one_md_table_init(pud_t *pud)
 #endif
 }
 
-static void __init fixrange_init(unsigned long start, unsigned long end, 
+static void __init fixrange_init(unsigned long start, unsigned long end,
                                 pgd_t *pgd_base)
 {
        pgd_t *pgd;
@@ -138,7 +129,7 @@ static void __init fixrange_init(unsigned long start, unsigned long end,
                if (pud_none(*pud))
                        one_md_table_init(pud);
                pmd = pmd_offset(pud, vaddr);
-               for (; (j < PTRS_PER_PMD) && (vaddr != end); pmd++, j++) {
+               for (; (j < PTRS_PER_PMD) && (vaddr < end); pmd++, j++) {
                        one_page_table_init(pmd);
                        vaddr += PMD_SIZE;
                }
@@ -152,7 +143,7 @@ pgprot_t kmap_prot;
 
 #define kmap_get_fixmap_pte(vaddr)                                     \
        pte_offset_kernel(pmd_offset(pud_offset(pgd_offset_k(vaddr), (vaddr)),\
-                         (vaddr)), (vaddr))
+                                    (vaddr)), (vaddr))
 
 static void __init kmap_init(void)
 {
@@ -197,21 +188,23 @@ static void __init fixaddr_user_init( void)
        pud_t *pud;
        pmd_t *pmd;
        pte_t *pte;
-       unsigned long paddr, vaddr = FIXADDR_USER_START;
+       phys_t p;
+       unsigned long v, vaddr = FIXADDR_USER_START;
 
-       if (  ! size )
+       if (!size)
                return;
 
        fixrange_init( FIXADDR_USER_START, FIXADDR_USER_END, swapper_pg_dir);
-       paddr = (unsigned long)alloc_bootmem_low_pages( size);
-       memcpy( (void *)paddr, (void *)FIXADDR_USER_START, size);
-       paddr = __pa(paddr);
-       for ( ; size > 0; size-=PAGE_SIZE, vaddr+=PAGE_SIZE, paddr+=PAGE_SIZE){
+       v = (unsigned long) alloc_bootmem_low_pages(size);
+       memcpy((void *) v , (void *) FIXADDR_USER_START, size);
+       p = __pa(v);
+       for ( ; size > 0; size -= PAGE_SIZE, vaddr += PAGE_SIZE,
+                     p += PAGE_SIZE) {
                pgd = swapper_pg_dir + pgd_index(vaddr);
                pud = pud_offset(pgd, vaddr);
                pmd = pmd_offset(pud, vaddr);
                pte = pte_offset_kernel(pmd, vaddr);
-               pte_set_val( (*pte), paddr, PAGE_READONLY);
+               pte_set_val(*pte, p, PAGE_READONLY);
        }
 #endif
 }
@@ -223,7 +216,7 @@ void __init paging_init(void)
 
        empty_zero_page = (unsigned long *) alloc_bootmem_low_pages(PAGE_SIZE);
        empty_bad_page = (unsigned long *) alloc_bootmem_low_pages(PAGE_SIZE);
-       for(i = 0; i < ARRAY_SIZE(zones_size); i++)
+       for (i = 0; i < ARRAY_SIZE(zones_size); i++)
                zones_size[i] = 0;
 
        zones_size[ZONE_NORMAL] = (end_iomem >> PAGE_SHIFT) -
@@ -253,32 +246,33 @@ struct page *arch_validate(struct page *page, gfp_t mask, int order)
        int i;
 
  again:
-       if(page == NULL)
+       if (page == NULL)
                return page;
-       if(PageHighMem(page))
+       if (PageHighMem(page))
                return page;
 
        addr = (unsigned long) page_address(page);
-       for(i = 0; i < (1 << order); i++){
+       for (i = 0; i < (1 << order); i++) {
                current->thread.fault_addr = (void *) addr;
-               if(__do_copy_to_user((void __user *) addr, &zero,
+               if (__do_copy_to_user((void __user *) addr, &zero,
                                     sizeof(zero),
                                     &current->thread.fault_addr,
-                                    &current->thread.fault_catcher)){
-                       if(!(mask & __GFP_WAIT))
+                                    &current->thread.fault_catcher)) {
+                       if (!(mask & __GFP_WAIT))
                                return NULL;
                        else break;
                }
                addr += PAGE_SIZE;
        }
 
-       if(i == (1 << order))
+       if (i == (1 << order))
                return page;
        page = alloc_pages(mask, order);
        goto again;
 }
 
-/* This can't do anything because nothing in the kernel image can be freed
+/*
+ * This can't do anything because nothing in the kernel image can be freed
  * since it's not in kernel physical memory.
  */
 
@@ -290,8 +284,8 @@ void free_initmem(void)
 void free_initrd_mem(unsigned long start, unsigned long end)
 {
        if (start < end)
-               printk ("Freeing initrd memory: %ldk freed\n", 
-                       (end - start) >> 10);
+               printk(KERN_INFO "Freeing initrd memory: %ldk freed\n",
+                      (end - start) >> 10);
        for (; start < end; start += PAGE_SIZE) {
                ClearPageReserved(virt_to_page(start));
                init_page_count(virt_to_page(start));
@@ -308,32 +302,31 @@ void show_mem(void)
        int highmem = 0;
        struct page *page;
 
-       printk("Mem-info:\n");
+       printk(KERN_INFO "Mem-info:\n");
        show_free_areas();
-       printk("Free swap:       %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10));
+       printk(KERN_INFO "Free swap:       %6ldkB\n",
+              nr_swap_pages<<(PAGE_SHIFT-10));
        pfn = max_mapnr;
-       while(pfn-- > 0) {
+       while (pfn-- > 0) {
                page = pfn_to_page(pfn);
                total++;
-               if(PageHighMem(page))
+               if (PageHighMem(page))
                        highmem++;
-               if(PageReserved(page))
+               if (PageReserved(page))
                        reserved++;
-               else if(PageSwapCache(page))
+               else if (PageSwapCache(page))
                        cached++;
-               else if(page_count(page))
+               else if (page_count(page))
                        shared += page_count(page) - 1;
        }
-       printk("%d pages of RAM\n", total);
-       printk("%d pages of HIGHMEM\n", highmem);
-       printk("%d reserved pages\n", reserved);
-       printk("%d pages shared\n", shared);
-       printk("%d pages swap cached\n", cached);
+       printk(KERN_INFO "%d pages of RAM\n", total);
+       printk(KERN_INFO "%d pages of HIGHMEM\n", highmem);
+       printk(KERN_INFO "%d reserved pages\n", reserved);
+       printk(KERN_INFO "%d pages shared\n", shared);
+       printk(KERN_INFO "%d pages swap cached\n", cached);
 }
 
-/*
- * Allocate and free page tables.
- */
+/* Allocate and free page tables. */
 
 pgd_t *pgd_alloc(struct mm_struct *mm)
 {
@@ -341,14 +334,14 @@ pgd_t *pgd_alloc(struct mm_struct *mm)
 
        if (pgd) {
                memset(pgd, 0, USER_PTRS_PER_PGD * sizeof(pgd_t));
-               memcpy(pgd + USER_PTRS_PER_PGD, 
-                      swapper_pg_dir + USER_PTRS_PER_PGD, 
+               memcpy(pgd + USER_PTRS_PER_PGD,
+                      swapper_pg_dir + USER_PTRS_PER_PGD,
                       (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
        }
        return pgd;
 }
 
-void pgd_free(pgd_t *pgd)
+void pgd_free(struct mm_struct *mm, pgd_t *pgd)
 {
        free_page((unsigned long) pgd);
 }
@@ -368,3 +361,15 @@ struct page *pte_alloc_one(struct mm_struct *mm, unsigned long address)
        pte = alloc_page(GFP_KERNEL|__GFP_REPEAT|__GFP_ZERO);
        return pte;
 }
+
+#ifdef CONFIG_3_LEVEL_PGTABLES
+pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long address)
+{
+       pmd_t *pmd = (pmd_t *) __get_free_page(GFP_KERNEL);
+
+       if (pmd)
+               memset(pmd, 0, PAGE_SIZE);
+
+       return pmd;
+}
+#endif
index e66432f42485dad02584bb13a6bc28a626aa0814..9757085a022097fe1804373bfd8e498bd38b4991 100644 (file)
@@ -55,16 +55,6 @@ int __init init_maps(unsigned long physmem, unsigned long iomem,
        return 0;
 }
 
-/* Changed during early boot */
-static unsigned long kmem_top = 0;
-
-unsigned long get_kmem_end(void)
-{
-       if (kmem_top == 0)
-               kmem_top = host_task_size - 1024 * 1024;
-       return kmem_top;
-}
-
 void map_memory(unsigned long virt, unsigned long phys, unsigned long len,
                int r, int w, int x)
 {
@@ -174,10 +164,10 @@ __uml_setup("iomem=", parse_iomem,
  * setup_iomem, both of which run during early boot.  Afterwards, it's
  * unchanged.
  */
-struct iomem_region *iomem_regions = NULL;
+struct iomem_region *iomem_regions;
 
-/* Initialized in parse_iomem */
-int iomem_size = 0;
+/* Initialized in parse_iomem and unchanged thereafter */
+int iomem_size;
 
 unsigned long find_iomem(char *driver, unsigned long *len_out)
 {
index 0eae00b3e58895054d69afd0876bedae0bd12631..c07961bedb75ea7a379176275022c3cca26bae53 100644 (file)
@@ -4,19 +4,21 @@
  * Licensed under the GPL
  */
 
-#include "linux/stddef.h"
-#include "linux/err.h"
-#include "linux/hardirq.h"
-#include "linux/mm.h"
-#include "linux/personality.h"
-#include "linux/proc_fs.h"
-#include "linux/ptrace.h"
-#include "linux/random.h"
-#include "linux/sched.h"
-#include "linux/tick.h"
-#include "linux/threads.h"
-#include "asm/pgtable.h"
-#include "asm/uaccess.h"
+#include <linux/stddef.h>
+#include <linux/err.h>
+#include <linux/hardirq.h>
+#include <linux/gfp.h>
+#include <linux/mm.h>
+#include <linux/personality.h>
+#include <linux/proc_fs.h>
+#include <linux/ptrace.h>
+#include <linux/random.h>
+#include <linux/sched.h>
+#include <linux/tick.h>
+#include <linux/threads.h>
+#include <asm/current.h>
+#include <asm/pgtable.h>
+#include <asm/uaccess.h>
 #include "as-layout.h"
 #include "kern_util.h"
 #include "os.h"
@@ -30,7 +32,7 @@
  */
 struct cpu_task cpu_tasks[NR_CPUS] = { [0 ... NR_CPUS - 1] = { -1, NULL } };
 
-static inline int external_pid(struct task_struct *task)
+static inline int external_pid(void)
 {
        /* FIXME: Need to look up userspace_pid by cpu */
        return userspace_pid[0];
@@ -40,7 +42,7 @@ int pid_to_processor_id(int pid)
 {
        int i;
 
-       for(i = 0; i < ncpus; i++) {
+       for (i = 0; i < ncpus; i++) {
                if (cpu_tasks[i].pid == pid)
                        return i;
        }
@@ -60,8 +62,6 @@ unsigned long alloc_stack(int order, int atomic)
        if (atomic)
                flags = GFP_ATOMIC;
        page = __get_free_pages(flags, order);
-       if (page == 0)
-               return 0;
 
        return page;
 }
@@ -80,15 +80,15 @@ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
 static inline void set_current(struct task_struct *task)
 {
        cpu_tasks[task_thread_info(task)->cpu] = ((struct cpu_task)
-               { external_pid(task), task });
+               { external_pid(), task });
 }
 
-extern void arch_switch_to(struct task_struct *from, struct task_struct *to);
+extern void arch_switch_to(struct task_struct *to);
 
 void *_switch_to(void *prev, void *next, void *last)
 {
        struct task_struct *from = prev;
-       struct task_struct *to= next;
+       struct task_struct *to = next;
 
        to->thread.prev_sched = from;
        set_current(to);
@@ -99,13 +99,13 @@ void *_switch_to(void *prev, void *next, void *last)
                switch_threads(&from->thread.switch_buf,
                               &to->thread.switch_buf);
 
-               arch_switch_to(current->thread.prev_sched, current);
+               arch_switch_to(current);
 
                if (current->thread.saved_task)
                        show_regs(&(current->thread.regs));
-               next= current->thread.saved_task;
-               prev= current;
-       } while(current->thread.saved_task);
+               to = current->thread.saved_task;
+               from = current;
+       } while (current->thread.saved_task);
 
        return current->thread.prev_sched;
 
@@ -163,8 +163,6 @@ void new_thread_handler(void)
 void fork_handler(void)
 {
        force_flush_all();
-       if (current->thread.prev_sched == NULL)
-               panic("blech");
 
        schedule_tail(current->thread.prev_sched);
 
@@ -173,7 +171,7 @@ void fork_handler(void)
         * arch_switch_to isn't needed. We could want to apply this to
         * improve performance. -bb
         */
-       arch_switch_to(current->thread.prev_sched, current);
+       arch_switch_to(current);
 
        current->thread.prev_sched = NULL;
 
@@ -204,7 +202,7 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
                arch_copy_thread(&current->thread.arch, &p->thread.arch);
        }
        else {
-               init_thread_registers(&p->thread.regs.regs);
+               get_safe_registers(p->thread.regs.regs.gp);
                p->thread.request.u.thread = current->thread.request.u.thread;
                handler = new_thread_handler;
        }
@@ -237,7 +235,7 @@ void default_idle(void)
 {
        unsigned long long nsecs;
 
-       while(1) {
+       while (1) {
                /* endless idle loop with no priority at all */
 
                /*
@@ -256,53 +254,10 @@ void default_idle(void)
 
 void cpu_idle(void)
 {
-       cpu_tasks[current_thread->cpu].pid = os_getpid();
+       cpu_tasks[current_thread_info()->cpu].pid = os_getpid();
        default_idle();
 }
 
-void *um_virt_to_phys(struct task_struct *task, unsigned long addr,
-                     pte_t *pte_out)
-{
-       pgd_t *pgd;
-       pud_t *pud;
-       pmd_t *pmd;
-       pte_t *pte;
-       pte_t ptent;
-
-       if (task->mm == NULL)
-               return ERR_PTR(-EINVAL);
-       pgd = pgd_offset(task->mm, addr);
-       if (!pgd_present(*pgd))
-               return ERR_PTR(-EINVAL);
-
-       pud = pud_offset(pgd, addr);
-       if (!pud_present(*pud))
-               return ERR_PTR(-EINVAL);
-
-       pmd = pmd_offset(pud, addr);
-       if (!pmd_present(*pmd))
-               return ERR_PTR(-EINVAL);
-
-       pte = pte_offset_kernel(pmd, addr);
-       ptent = *pte;
-       if (!pte_present(ptent))
-               return ERR_PTR(-EINVAL);
-
-       if (pte_out != NULL)
-               *pte_out = ptent;
-       return (void *) (pte_val(ptent) & PAGE_MASK) + (addr & ~PAGE_MASK);
-}
-
-char *current_cmd(void)
-{
-#if defined(CONFIG_SMP) || defined(CONFIG_HIGHMEM)
-       return "(Unknown)";
-#else
-       void *addr = um_virt_to_phys(current, current->mm->arg_start, NULL);
-       return IS_ERR(addr) ? "(Unknown)": __va((unsigned long) addr);
-#endif
-}
-
 void dump_thread(struct pt_regs *regs, struct user *u)
 {
 }
@@ -317,7 +272,7 @@ int user_context(unsigned long sp)
        unsigned long stack;
 
        stack = sp & (PAGE_MASK << CONFIG_KERNEL_STACK_ORDER);
-       return stack != (unsigned long) current_thread;
+       return stack != (unsigned long) current_thread_info();
 }
 
 extern exitcall_t __uml_exitcall_begin, __uml_exitcall_end;
@@ -331,7 +286,7 @@ void do_uml_exitcalls(void)
                (*call)();
 }
 
-char *uml_strdup(char *string)
+char *uml_strdup(const char *string)
 {
        return kstrdup(string, GFP_KERNEL);
 }
@@ -359,7 +314,7 @@ int strlen_user_proc(char __user *str)
 int smp_sigio_handler(void)
 {
 #ifdef CONFIG_SMP
-       int cpu = current_thread->cpu;
+       int cpu = current_thread_info()->cpu;
        IPI_handler(cpu);
        if (cpu != 0)
                return 1;
@@ -369,7 +324,7 @@ int smp_sigio_handler(void)
 
 int cpu(void)
 {
-       return current_thread->cpu;
+       return current_thread_info()->cpu;
 }
 
 static atomic_t using_sysemu = ATOMIC_INIT(0);
@@ -435,7 +390,7 @@ int singlestepping(void * t)
 {
        struct task_struct *task = t ? t : current;
 
-       if ( ! (task->ptrace & PT_DTRACE) )
+       if (!(task->ptrace & PT_DTRACE))
                return 0;
 
        if (task->thread.singlestep_syscall)
@@ -459,3 +414,46 @@ unsigned long arch_align_stack(unsigned long sp)
        return sp & ~0xf;
 }
 #endif
+
+unsigned long get_wchan(struct task_struct *p)
+{
+       unsigned long stack_page, sp, ip;
+       bool seen_sched = 0;
+
+       if ((p == NULL) || (p == current) || (p->state == TASK_RUNNING))
+               return 0;
+
+       stack_page = (unsigned long) task_stack_page(p);
+       /* Bail if the process has no kernel stack for some reason */
+       if (stack_page == 0)
+               return 0;
+
+       sp = p->thread.switch_buf->JB_SP;
+       /*
+        * Bail if the stack pointer is below the bottom of the kernel
+        * stack for some reason
+        */
+       if (sp < stack_page)
+               return 0;
+
+       while (sp < stack_page + THREAD_SIZE) {
+               ip = *((unsigned long *) sp);
+               if (in_sched_functions(ip))
+                       /* Ignore everything until we're above the scheduler */
+                       seen_sched = 1;
+               else if (kernel_text_address(ip) && seen_sched)
+                       return ip;
+
+               sp += sizeof(unsigned long);
+       }
+
+       return 0;
+}
+
+int elf_core_copy_fpregs(struct task_struct *t, elf_fpregset_t *fpu)
+{
+       int cpu = current_thread_info()->cpu;
+
+       return save_fp_registers(userspace_pid[cpu], (unsigned long *) fpu);
+}
+
index 04cebcf0679ff90e590b9374ed5c8a8b041acc1e..00197d3d21ec96daba38fe57b74db08183fc1310 100644 (file)
@@ -4,6 +4,7 @@
  */
 
 #include "linux/sched.h"
+#include "kern_util.h"
 #include "os.h"
 #include "skas.h"
 
@@ -11,7 +12,7 @@ void (*pm_power_off)(void);
 
 static void kill_off_processes(void)
 {
-       if(proc_mm)
+       if (proc_mm)
                /*
                 * FIXME: need to loop over userspace_pids
                 */
@@ -21,8 +22,8 @@ static void kill_off_processes(void)
                int pid, me;
 
                me = os_getpid();
-               for_each_process(p){
-                       if(p->mm == NULL)
+               for_each_process(p) {
+                       if (p->mm == NULL)
                                continue;
 
                        pid = p->mm->context.id.u.pid;
index 89f9866a1354b8073cf5f015bd4b80e276b6e9a4..2b272b63b514c1508a83c3199d7a1b926d0c8c40 100644 (file)
@@ -1,18 +1,12 @@
 /*
- * Copyright (C) 2002 - 2003 Jeff Dike (jdike@addtoit.com)
+ * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{linux.intel,addtoit}.com)
  * Licensed under the GPL
  */
 
-#include "linux/kernel.h"
-#include "linux/list.h"
-#include "linux/slab.h"
-#include "linux/signal.h"
-#include "linux/interrupt.h"
-#include "init.h"
-#include "sigio.h"
-#include "irq_user.h"
+#include <linux/interrupt.h>
 #include "irq_kern.h"
 #include "os.h"
+#include "sigio.h"
 
 /* Protected by sigio_lock() called from write_sigio_workaround */
 static int sigio_irq_fd = -1;
@@ -33,9 +27,9 @@ int write_sigio_irq(int fd)
        err = um_request_irq(SIGIO_WRITE_IRQ, fd, IRQ_READ, sigio_interrupt,
                             IRQF_DISABLED|IRQF_SAMPLE_RANDOM, "write sigio",
                             NULL);
-       if(err){
-               printk("write_sigio_irq : um_request_irq failed, err = %d\n",
-                      err);
+       if (err) {
+               printk(KERN_ERR "write_sigio_irq : um_request_irq failed, "
+                      "err = %d\n", err);
                return -1;
        }
        sigio_irq_fd = fd;
index 19cb97733937973737c8119ecc59a9ee021ae47a..b0fce720c4d08378afba4f642ec97b712ca482c3 100644 (file)
@@ -3,12 +3,12 @@
  * Licensed under the GPL
  */
 
-#include "linux/module.h"
-#include "linux/ptrace.h"
-#include "linux/sched.h"
-#include "asm/siginfo.h"
-#include "asm/signal.h"
-#include "asm/unistd.h"
+#include <linux/module.h>
+#include <linux/ptrace.h>
+#include <linux/sched.h>
+#include <asm/siginfo.h>
+#include <asm/signal.h>
+#include <asm/unistd.h>
 #include "frame_kern.h"
 #include "kern_util.h"
 #include "sigcontext.h"
@@ -36,7 +36,7 @@ static int handle_signal(struct pt_regs *regs, unsigned long signr,
        /* Did we come from a system call? */
        if (PT_REGS_SYSCALL_NR(regs) >= 0) {
                /* If so, check system call restarting.. */
-               switch(PT_REGS_SYSCALL_RET(regs)) {
+               switch (PT_REGS_SYSCALL_RET(regs)) {
                case -ERESTART_RESTARTBLOCK:
                case -ERESTARTNOHAND:
                        PT_REGS_SYSCALL_RET(regs) = -EINTR;
@@ -116,7 +116,7 @@ static int kern_do_signal(struct pt_regs *regs)
        /* Did we come from a system call? */
        if (!handled_sig && (PT_REGS_SYSCALL_NR(regs) >= 0)) {
                /* Restart the system call - no handlers present */
-               switch(PT_REGS_SYSCALL_RET(regs)) {
+               switch (PT_REGS_SYSCALL_RET(regs)) {
                case -ERESTARTNOHAND:
                case -ERESTARTSYS:
                case -ERESTARTNOINTR:
index 8d07a7acb909c707bd5ec4d0bcf3ce6d53045db1..2c8583c1a344df2003ee0f2371ca6ead0a085982 100644 (file)
@@ -1,17 +1,20 @@
-#include <sched.h>
+/*
+ * Copyright (C) 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
+ * Licensed under the GPL
+ */
+
 #include <signal.h>
-#include <sys/mman.h>
-#include <sys/time.h>
+#include <sched.h>
 #include <asm/unistd.h>
+#include <sys/time.h>
 #include "as-layout.h"
+#include "kern_constants.h"
 #include "ptrace_user.h"
-#include "skas.h"
 #include "stub-data.h"
-#include "uml-config.h"
 #include "sysdep/stub.h"
-#include "kern_constants.h"
 
-/* This is in a separate file because it needs to be compiled with any
+/*
+ * This is in a separate file because it needs to be compiled with any
  * extraneous gcc flags (-pg, -fprofile-arcs, -ftest-coverage) disabled
  *
  * Use UM_KERN_PAGE_SIZE instead of PAGE_SIZE because that calls getpagesize
@@ -26,25 +29,26 @@ stub_clone_handler(void)
 
        err = stub_syscall2(__NR_clone, CLONE_PARENT | CLONE_FILES | SIGCHLD,
                            STUB_DATA + UM_KERN_PAGE_SIZE / 2 - sizeof(void *));
-       if(err != 0)
+       if (err != 0)
                goto out;
 
        err = stub_syscall4(__NR_ptrace, PTRACE_TRACEME, 0, 0, 0);
-       if(err)
+       if (err)
                goto out;
 
-       err = stub_syscall3(__NR_setitimer, ITIMER_VIRTUAL, 
+       err = stub_syscall3(__NR_setitimer, ITIMER_VIRTUAL,
                            (long) &data->timer, 0);
-       if(err)
+       if (err)
                goto out;
 
        remap_stack(data->fd, data->offset);
        goto done;
 
  out:
-       /* save current result. 
-        * Parent: pid; 
-        * child: retcode of mmap already saved and it jumps around this 
+       /*
+        * save current result.
+        * Parent: pid;
+        * child: retcode of mmap already saved and it jumps around this
         * assignment
         */
        data->err = err;
index f859ec306cd5ded54f4239bba0519d58eb52f2e3..78b3e9f69d57d6a81d9ac446e9f6edc16586e5fe 100644 (file)
@@ -34,33 +34,14 @@ static int init_stub_pte(struct mm_struct *mm, unsigned long proc,
        if (!pte)
                goto out_pte;
 
-       /*
-        * There's an interaction between the skas0 stub pages, stack
-        * randomization, and the BUG at the end of exit_mmap.  exit_mmap
-        * checks that the number of page tables freed is the same as had
-        * been allocated.  If the stack is on the last page table page,
-        * then the stack pte page will be freed, and if not, it won't.  To
-        * avoid having to know where the stack is, or if the process mapped
-        * something at the top of its address space for some other reason,
-        * we set TASK_SIZE to end at the start of the last page table.
-        * This keeps exit_mmap off the last page, but introduces a leak
-        * of that page.  So, we hang onto it here and free it in
-        * destroy_context_skas.
-        */
-
-       mm->context.last_page_table = pmd_page_vaddr(*pmd);
-#ifdef CONFIG_3_LEVEL_PGTABLES
-       mm->context.last_pmd = (unsigned long) __va(pud_val(*pud));
-#endif
-
        *pte = mk_pte(virt_to_page(kernel), __pgprot(_PAGE_PRESENT));
        *pte = pte_mkread(*pte);
        return 0;
 
  out_pmd:
-       pud_free(pud);
+       pud_free(mm, pud);
  out_pte:
-       pmd_free(pmd);
+       pmd_free(mm, pmd);
  out:
        return -ENOMEM;
 }
@@ -76,24 +57,6 @@ int init_new_context(struct task_struct *task, struct mm_struct *mm)
                stack = get_zeroed_page(GFP_KERNEL);
                if (stack == 0)
                        goto out;
-
-               /*
-                * This zeros the entry that pgd_alloc didn't, needed since
-                * we are about to reinitialize it, and want mm.nr_ptes to
-                * be accurate.
-                */
-               mm->pgd[USER_PTRS_PER_PGD] = __pgd(0);
-
-               ret = init_stub_pte(mm, STUB_CODE,
-                                   (unsigned long) &__syscall_stub_start);
-               if (ret)
-                       goto out_free;
-
-               ret = init_stub_pte(mm, STUB_DATA, stack);
-               if (ret)
-                       goto out_free;
-
-               mm->nr_ptes--;
        }
 
        to_mm->id.stack = stack;
@@ -114,6 +77,11 @@ int init_new_context(struct task_struct *task, struct mm_struct *mm)
                        to_mm->id.u.pid = copy_context_skas0(stack,
                                                             from_mm->id.u.pid);
                else to_mm->id.u.pid = start_userspace(stack);
+
+               if (to_mm->id.u.pid < 0) {
+                       ret = to_mm->id.u.pid;
+                       goto out_free;
+               }
        }
 
        ret = init_new_ldt(to_mm, from_mm);
@@ -132,24 +100,87 @@ int init_new_context(struct task_struct *task, struct mm_struct *mm)
        return ret;
 }
 
+void arch_dup_mmap(struct mm_struct *oldmm, struct mm_struct *mm)
+{
+       struct page **pages;
+       int err, ret;
+
+       if (!skas_needs_stub)
+               return;
+
+       ret = init_stub_pte(mm, STUB_CODE,
+                           (unsigned long) &__syscall_stub_start);
+       if (ret)
+               goto out;
+
+       ret = init_stub_pte(mm, STUB_DATA, mm->context.id.stack);
+       if (ret)
+               goto out;
+
+       pages = kmalloc(2 * sizeof(struct page *), GFP_KERNEL);
+       if (pages == NULL) {
+               printk(KERN_ERR "arch_dup_mmap failed to allocate 2 page "
+                      "pointers\n");
+               goto out;
+       }
+
+       pages[0] = virt_to_page(&__syscall_stub_start);
+       pages[1] = virt_to_page(mm->context.id.stack);
+
+       /* dup_mmap already holds mmap_sem */
+       err = install_special_mapping(mm, STUB_START, STUB_END - STUB_START,
+                                     VM_READ | VM_MAYREAD | VM_EXEC |
+                                     VM_MAYEXEC | VM_DONTCOPY, pages);
+       if (err) {
+               printk(KERN_ERR "install_special_mapping returned %d\n", err);
+               goto out_free;
+       }
+       return;
+
+out_free:
+       kfree(pages);
+out:
+       force_sigsegv(SIGSEGV, current);
+}
+
+void arch_exit_mmap(struct mm_struct *mm)
+{
+       pte_t *pte;
+
+       pte = virt_to_pte(mm, STUB_CODE);
+       if (pte != NULL)
+               pte_clear(mm, STUB_CODE, pte);
+
+       pte = virt_to_pte(mm, STUB_DATA);
+       if (pte == NULL)
+               return;
+
+       pte_clear(mm, STUB_DATA, pte);
+}
+
 void destroy_context(struct mm_struct *mm)
 {
        struct mm_context *mmu = &mm->context;
 
        if (proc_mm)
                os_close_file(mmu->id.u.mm_fd);
-       else
+       else {
+               /*
+                * If init_new_context wasn't called, this will be
+                * zero, resulting in a kill(0), which will result in the
+                * whole UML suddenly dying.  Also, cover negative and
+                * 1 cases, since they shouldn't happen either.
+                */
+               if (mmu->id.u.pid < 2) {
+                       printk(KERN_ERR "corrupt mm_context - pid = %d\n",
+                              mmu->id.u.pid);
+                       return;
+               }
                os_kill_ptraced_process(mmu->id.u.pid, 1);
+       }
 
-       if (!proc_mm || !ptrace_faultinfo) {
+       if (skas_needs_stub)
                free_page(mmu->id.stack);
-               pte_lock_deinit(virt_to_page(mmu->last_page_table));
-               pte_free_kernel((pte_t *) mmu->last_page_table);
-               dec_zone_page_state(virt_to_page(mmu->last_page_table), NR_PAGETABLE);
-#ifdef CONFIG_3_LEVEL_PGTABLES
-               pmd_free((pmd_t *) mmu->last_pmd);
-#endif
-       }
 
        free_ldt(mmu);
 }
index fce389c2342f3d942cdae4d047edbb1f3a2bab50..2e9852c0d487449911fc289e3520a90e6306f9b9 100644 (file)
@@ -6,19 +6,25 @@
 #include "linux/init.h"
 #include "linux/sched.h"
 #include "as-layout.h"
+#include "kern.h"
 #include "os.h"
 #include "skas.h"
 
 int new_mm(unsigned long stack)
 {
-       int fd;
+       int fd, err;
 
        fd = os_open_file("/proc/mm", of_cloexec(of_write(OPENFLAGS())), 0);
        if (fd < 0)
                return fd;
 
-       if (skas_needs_stub)
-               map_stub_pages(fd, STUB_CODE, STUB_DATA, stack);
+       if (skas_needs_stub) {
+               err = map_stub_pages(fd, STUB_CODE, STUB_DATA, stack);
+               if (err) {
+                       os_close_file(fd);
+                       return err;
+               }
+       }
 
        return fd;
 }
@@ -49,8 +55,14 @@ int __init start_uml(void)
 {
        stack_protections((unsigned long) &cpu0_irqstack);
        set_sigstack(cpu0_irqstack, THREAD_SIZE);
-       if (proc_mm)
+       if (proc_mm) {
                userspace_pid[0] = start_userspace(0);
+               if (userspace_pid[0] < 0) {
+                       printf("start_uml - start_userspace returned %d\n",
+                              userspace_pid[0]);
+                       exit(1);
+               }
+       }
 
        init_new_thread_signals();
 
index 50b476f2b38df9096fee81a705ae4ef5e04b93e5..4e3b820bd2beaa477d6bc57b20dcae501f357db6 100644 (file)
@@ -9,6 +9,9 @@
 #include "sysdep/ptrace.h"
 #include "sysdep/syscalls.h"
 
+extern int syscall_table_size;
+#define NR_syscalls (syscall_table_size / sizeof(void *))
+
 void handle_syscall(struct uml_pt_regs *r)
 {
        struct pt_regs *regs = container_of(r, struct pt_regs, regs);
@@ -17,9 +20,6 @@ void handle_syscall(struct uml_pt_regs *r)
 
        syscall_trace(r, 0);
 
-       current->thread.nsyscalls++;
-       nsyscalls++;
-
        /*
         * This should go in the declaration of syscall, but when I do that,
         * strace -f -c bash -c 'ls ; ls' breaks, sometimes not tracing
index 1d8b119f2d0e12f9930b5f3092df793f8d5c1803..e22c96993db3b07545e107adb57f2ef1d8ddb608 100644 (file)
  * Licensed under the GPL
  */
 
-#include "linux/err.h"
-#include "linux/highmem.h"
-#include "linux/mm.h"
-#include "asm/current.h"
-#include "asm/page.h"
-#include "asm/pgtable.h"
+#include <linux/err.h>
+#include <linux/highmem.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <asm/current.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
 #include "kern_util.h"
 #include "os.h"
 
-extern void *um_virt_to_phys(struct task_struct *task, unsigned long addr,
-                            pte_t *pte_out);
-
-static unsigned long maybe_map(unsigned long virt, int is_write)
+pte_t *virt_to_pte(struct mm_struct *mm, unsigned long addr)
 {
-       pte_t pte;
-       int err;
+       pgd_t *pgd;
+       pud_t *pud;
+       pmd_t *pmd;
+
+       if (mm == NULL)
+               return NULL;
+
+       pgd = pgd_offset(mm, addr);
+       if (!pgd_present(*pgd))
+               return NULL;
+
+       pud = pud_offset(pgd, addr);
+       if (!pud_present(*pud))
+               return NULL;
 
-       void *phys = um_virt_to_phys(current, virt, &pte);
-       int dummy_code;
+       pmd = pmd_offset(pud, addr);
+       if (!pmd_present(*pmd))
+               return NULL;
+
+       return pte_offset_kernel(pmd, addr);
+}
+
+static pte_t *maybe_map(unsigned long virt, int is_write)
+{
+       pte_t *pte = virt_to_pte(current->mm, virt);
+       int err, dummy_code;
 
-       if (IS_ERR(phys) || (is_write && !pte_write(pte))) {
+       if ((pte == NULL) || !pte_present(*pte) ||
+           (is_write && !pte_write(*pte))) {
                err = handle_page_fault(virt, 0, is_write, 1, &dummy_code);
                if (err)
-                       return -1UL;
-               phys = um_virt_to_phys(current, virt, NULL);
+                       return NULL;
+               pte = virt_to_pte(current->mm, virt);
        }
-       if (IS_ERR(phys))
-               phys = (void *) -1;
+       if (!pte_present(*pte))
+               pte = NULL;
 
-       return (unsigned long) phys;
+       return pte;
 }
 
 static int do_op_one_page(unsigned long addr, int len, int is_write,
                 int (*op)(unsigned long addr, int len, void *arg), void *arg)
 {
+       jmp_buf buf;
        struct page *page;
-       int n;
+       pte_t *pte;
+       int n, faulted;
 
-       addr = maybe_map(addr, is_write);
-       if (addr == -1UL)
+       pte = maybe_map(addr, is_write);
+       if (pte == NULL)
                return -1;
 
-       page = phys_to_page(addr);
+       page = pte_page(*pte);
        addr = (unsigned long) kmap_atomic(page, KM_UML_USERCOPY) +
                (addr & ~PAGE_MASK);
 
-       n = (*op)(addr, len, arg);
+       current->thread.fault_catcher = &buf;
+
+       faulted = UML_SETJMP(&buf);
+       if (faulted == 0)
+               n = (*op)(addr, len, arg);
+       else
+               n = -1;
+
+       current->thread.fault_catcher = NULL;
 
        kunmap_atomic(page, KM_UML_USERCOPY);
 
        return n;
 }
 
-static void do_buffer_op(void *jmpbuf, void *arg_ptr)
+static int buffer_op(unsigned long addr, int len, int is_write,
+                    int (*op)(unsigned long, int, void *), void *arg)
 {
-       va_list args;
-       unsigned long addr;
-       int len, is_write, size, remain, n;
-       int (*op)(unsigned long, int, void *);
-       void *arg;
-       int *res;
-
-       va_copy(args, *(va_list *)arg_ptr);
-       addr = va_arg(args, unsigned long);
-       len = va_arg(args, int);
-       is_write = va_arg(args, int);
-       op = va_arg(args, void *);
-       arg = va_arg(args, void *);
-       res = va_arg(args, int *);
-       va_end(args);
+       int size, remain, n;
+
        size = min(PAGE_ALIGN(addr) - addr, (unsigned long) len);
        remain = len;
 
-       current->thread.fault_catcher = jmpbuf;
        n = do_op_one_page(addr, size, is_write, op, arg);
        if (n != 0) {
-               *res = (n < 0 ? remain : 0);
+               remain = (n < 0 ? remain : 0);
                goto out;
        }
 
        addr += size;
        remain -= size;
-       if (remain == 0) {
-               *res = 0;
+       if (remain == 0)
                goto out;
-       }
 
-       while(addr < ((addr + remain) & PAGE_MASK)) {
+       while (addr < ((addr + remain) & PAGE_MASK)) {
                n = do_op_one_page(addr, PAGE_SIZE, is_write, op, arg);
                if (n != 0) {
-                       *res = (n < 0 ? remain : 0);
+                       remain = (n < 0 ? remain : 0);
                        goto out;
                }
 
                addr += PAGE_SIZE;
                remain -= PAGE_SIZE;
        }
-       if (remain == 0) {
-               *res = 0;
+       if (remain == 0)
                goto out;
-       }
 
        n = do_op_one_page(addr, remain, is_write, op, arg);
-       if (n != 0)
-               *res = (n < 0 ? remain : 0);
-       else *res = 0;
- out:
-       current->thread.fault_catcher = NULL;
-}
-
-static int buffer_op(unsigned long addr, int len, int is_write,
-                    int (*op)(unsigned long addr, int len, void *arg),
-                    void *arg)
-{
-       int faulted, res;
-
-       faulted = setjmp_wrapper(do_buffer_op, addr, len, is_write, op, arg,
-                                &res);
-       if (!faulted)
-               return res;
+       if (n != 0) {
+               remain = (n < 0 ? remain : 0);
+               goto out;
+       }
 
-       return addr + len - (unsigned long) current->thread.fault_addr;
+       return 0;
+ out:
+       return remain;
 }
 
 static int copy_chunk_from_user(unsigned long from, int len, void *arg)
index 36d89cf8d20b2b223bb04f08a5735cd2a76e08af..e1062ec36d4072cc1cc3cfa34232c67c81b59133 100644 (file)
@@ -21,7 +21,6 @@ DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
 #include "asm/smp.h"
 #include "asm/processor.h"
 #include "asm/spinlock.h"
-#include "kern_util.h"
 #include "kern.h"
 #include "irq_user.h"
 #include "os.h"
@@ -61,7 +60,7 @@ void smp_send_stop(void)
                        continue;
                os_write_file(cpu_data[i].ipi_pipe[1], "S", 1);
        }
-       printk(KERN_INFO "done\n");
+       printk(KERN_CONT "done\n");
 }
 
 static cpumask_t smp_commenced_mask = CPU_MASK_NONE;
@@ -75,8 +74,7 @@ static int idle_proc(void *cpup)
        if (err < 0)
                panic("CPU#%d failed to create IPI pipe, err = %d", cpu, -err);
 
-       os_set_fd_async(cpu_data[cpu].ipi_pipe[0],
-                    current->thread.mode.tt.extern_pid);
+       os_set_fd_async(cpu_data[cpu].ipi_pipe[0]);
 
        wmb();
        if (cpu_test_and_set(cpu, cpu_callin_map)) {
@@ -129,8 +127,7 @@ void smp_prepare_cpus(unsigned int maxcpus)
        if (err < 0)
                panic("CPU#0 failed to create IPI pipe, errno = %d", -err);
 
-       os_set_fd_async(cpu_data[me].ipi_pipe[0],
-                    current->thread.mode.tt.extern_pid);
+       os_set_fd_async(cpu_data[me].ipi_pipe[0]);
 
        for (cpu = 1; cpu < ncpus; cpu++) {
                printk(KERN_INFO "Booting processor %d...\n", cpu);
@@ -143,9 +140,8 @@ void smp_prepare_cpus(unsigned int maxcpus)
                while (waittime-- && !cpu_isset(cpu, cpu_callin_map))
                        cpu_relax();
 
-               if (cpu_isset(cpu, cpu_callin_map))
-                       printk(KERN_INFO "done\n");
-               else printk(KERN_INFO "failed\n");
+               printk(KERN_INFO "%s\n",
+                      cpu_isset(cpu, cpu_calling_map) ? "done" : "failed");
        }
 }
 
index b9d92b2089aed6cb0b3a5d67d0dafce8fd0051dc..9cffc628a37e0f9505f6da9a8283eaf0ee368e2f 100644 (file)
@@ -13,9 +13,6 @@
 #include "asm/uaccess.h"
 #include "asm/unistd.h"
 
-/*  Unlocked, I don't care if this is a bit off */
-int nsyscalls = 0;
-
 long sys_fork(void)
 {
        long ret;
index 93263571d813ecf7fc2b8e2212a91f13a621c3f5..56d43d0a39602b140d458f2f989779bc9512b66a 100644 (file)
@@ -1,38 +1,37 @@
-/* 
- * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
+/*
+ * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
  * Licensed under the GPL
  */
 
-#include "linux/sched.h"
-#include "linux/kernel.h"
-#include "linux/module.h"
-#include "linux/kallsyms.h"
-#include "asm/page.h"
-#include "asm/processor.h"
+#include <linux/kallsyms.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/sched.h>
 #include "sysrq.h"
 
 /* Catch non-i386 SUBARCH's. */
 #if !defined(CONFIG_UML_X86) || defined(CONFIG_64BIT)
 void show_trace(struct task_struct *task, unsigned long * stack)
 {
-        unsigned long addr;
+       unsigned long addr;
 
-        if (!stack) {
+       if (!stack) {
                stack = (unsigned long*) &stack;
                WARN_ON(1);
        }
 
-        printk("Call Trace: \n");
-        while (((long) stack & (THREAD_SIZE-1)) != 0) {
-                addr = *stack;
+       printk(KERN_INFO "Call Trace: \n");
+       while (((long) stack & (THREAD_SIZE-1)) != 0) {
+               addr = *stack;
                if (__kernel_text_address(addr)) {
-                       printk("%08lx:  [<%08lx>]", (unsigned long) stack, addr);
-                       print_symbol(" %s", addr);
-                       printk("\n");
-                }
-                stack++;
-        }
-        printk("\n");
+                       printk(KERN_INFO "%08lx:  [<%08lx>]",
+                              (unsigned long) stack, addr);
+                       print_symbol(KERN_CONT " %s", addr);
+                       printk(KERN_CONT "\n");
+               }
+               stack++;
+       }
+       printk(KERN_INFO "\n");
 }
 #endif
 
@@ -67,14 +66,13 @@ void show_stack(struct task_struct *task, unsigned long *esp)
        }
 
        stack = esp;
-       for(i = 0; i < kstack_depth_to_print; i++) {
+       for (i = 0; i < kstack_depth_to_print; i++) {
                if (kstack_end(stack))
                        break;
                if (i && ((i % 8) == 0))
-                       printk("\n       ");
+                       printk("\n" KERN_INFO "       ");
                printk("%08lx ", *stack++);
        }
 
-       printk("Call Trace: \n");
        show_trace(task, esp);
 }
index 1ac746a9eae1aae17e7b715a70084f793560cd4b..e066e84493b129a23f7018ce09d145dddf14f97b 100644 (file)
@@ -3,12 +3,12 @@
  * Licensed under the GPL
  */
 
-#include "linux/clockchips.h"
-#include "linux/interrupt.h"
-#include "linux/jiffies.h"
-#include "linux/threads.h"
-#include "asm/irq.h"
-#include "asm/param.h"
+#include <linux/clockchips.h>
+#include <linux/interrupt.h>
+#include <linux/jiffies.h>
+#include <linux/threads.h>
+#include <asm/irq.h>
+#include <asm/param.h>
 #include "kern_util.h"
 #include "os.h"
 
@@ -32,7 +32,7 @@ void timer_handler(int sig, struct uml_pt_regs *regs)
 static void itimer_set_mode(enum clock_event_mode mode,
                            struct clock_event_device *evt)
 {
-       switch(mode) {
+       switch (mode) {
        case CLOCK_EVT_MODE_PERIODIC:
                set_interval();
                break;
index f4a0e407eee4d66e9fb8b62db6a3e36110d2854a..d175d0566af02d35acde18d805040c61a4bd29f2 100644 (file)
@@ -3,9 +3,10 @@
  * Licensed under the GPL
  */
 
-#include "linux/mm.h"
-#include "asm/pgtable.h"
-#include "asm/tlbflush.h"
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <asm/pgtable.h>
+#include <asm/tlbflush.h>
 #include "as-layout.h"
 #include "mem_user.h"
 #include "os.h"
@@ -56,7 +57,7 @@ static int do_ops(struct host_vm_change *hvc, int end,
 
        for (i = 0; i < end && !ret; i++) {
                op = &hvc->ops[i];
-               switch(op->type) {
+               switch (op->type) {
                case MMAP:
                        ret = map(hvc->id, op->u.mmap.addr, op->u.mmap.len,
                                  op->u.mmap.prot, op->u.mmap.fd,
@@ -183,27 +184,30 @@ static inline int update_pte_range(pmd_t *pmd, unsigned long addr,
 
        pte = pte_offset_kernel(pmd, addr);
        do {
+               if ((addr >= STUB_START) && (addr < STUB_END))
+                       continue;
+
                r = pte_read(*pte);
                w = pte_write(*pte);
                x = pte_exec(*pte);
                if (!pte_young(*pte)) {
                        r = 0;
                        w = 0;
-               } else if (!pte_dirty(*pte)) {
+               } else if (!pte_dirty(*pte))
                        w = 0;
-               }
+
                prot = ((r ? UM_PROT_READ : 0) | (w ? UM_PROT_WRITE : 0) |
                        (x ? UM_PROT_EXEC : 0));
                if (hvc->force || pte_newpage(*pte)) {
                        if (pte_present(*pte))
                                ret = add_mmap(addr, pte_val(*pte) & PAGE_MASK,
                                               PAGE_SIZE, prot, hvc);
-                       else ret = add_munmap(addr, PAGE_SIZE, hvc);
-               }
-               else if (pte_newprot(*pte))
+                       else
+                               ret = add_munmap(addr, PAGE_SIZE, hvc);
+               else if (pte_newprot(*pte))
                        ret = add_mprotect(addr, PAGE_SIZE, prot, hvc);
                *pte = pte_mkuptodate(*pte);
-       } while (pte++, addr += PAGE_SIZE, ((addr != end) && !ret));
+       } while (pte++, addr += PAGE_SIZE, ((addr < end) && !ret));
        return ret;
 }
 
@@ -225,7 +229,7 @@ static inline int update_pmd_range(pud_t *pud, unsigned long addr,
                        }
                }
                else ret = update_pte_range(pmd, addr, next, hvc);
-       } while (pmd++, addr = next, ((addr != end) && !ret));
+       } while (pmd++, addr = next, ((addr < end) && !ret));
        return ret;
 }
 
@@ -247,7 +251,7 @@ static inline int update_pud_range(pgd_t *pgd, unsigned long addr,
                        }
                }
                else ret = update_pmd_range(pud, addr, next, hvc);
-       } while (pud++, addr = next, ((addr != end) && !ret));
+       } while (pud++, addr = next, ((addr < end) && !ret));
        return ret;
 }
 
@@ -270,7 +274,7 @@ void fix_range_common(struct mm_struct *mm, unsigned long start_addr,
                        }
                }
                else ret = update_pud_range(pgd, addr, next, &hvc);
-       } while (pgd++, addr = next, ((addr != end_addr) && !ret));
+       } while (pgd++, addr = next, ((addr < end_addr) && !ret));
 
        if (!ret)
                ret = do_ops(&hvc, hvc.index, 1);
@@ -485,9 +489,6 @@ void __flush_tlb_one(unsigned long addr)
 static void fix_range(struct mm_struct *mm, unsigned long start_addr,
                      unsigned long end_addr, int force)
 {
-       if (!proc_mm && (end_addr > STUB_START))
-               end_addr = STUB_START;
-
        fix_range_common(mm, start_addr, end_addr, force);
 }
 
@@ -499,10 +500,9 @@ void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
        else fix_range(vma->vm_mm, start, end, 0);
 }
 
-void flush_tlb_mm(struct mm_struct *mm)
+void flush_tlb_mm_range(struct mm_struct *mm, unsigned long start,
+                       unsigned long end)
 {
-       unsigned long end;
-
        /*
         * Don't bother flushing if this address space is about to be
         * destroyed.
@@ -510,8 +510,17 @@ void flush_tlb_mm(struct mm_struct *mm)
        if (atomic_read(&mm->mm_users) == 0)
                return;
 
-       end = proc_mm ? task_size : STUB_START;
-       fix_range(mm, 0, end, 0);
+       fix_range(mm, start, end, 0);
+}
+
+void flush_tlb_mm(struct mm_struct *mm)
+{
+       struct vm_area_struct *vma = mm->mmap;
+
+       while (vma != NULL) {
+               fix_range(mm, vma->vm_start, vma->vm_end, 0);
+               vma = vma->vm_next;
+       }
 }
 
 void force_flush_all(void)
index cb3321f8e0a91924167b0f83ea7f34c30df55080..44e4904194951f680f187fd4f6137ca289b9cab8 100644 (file)
@@ -13,6 +13,7 @@
 #include "as-layout.h"
 #include "kern_util.h"
 #include "os.h"
+#include "skas.h"
 #include "sysdep/sigcontext.h"
 
 /*
@@ -128,7 +129,19 @@ static void bad_segv(struct faultinfo fi, unsigned long ip)
        force_sig_info(SIGSEGV, &si, current);
 }
 
-static void segv_handler(int sig, struct uml_pt_regs *regs)
+void fatal_sigsegv(void)
+{
+       force_sigsegv(SIGSEGV, current);
+       do_signal();
+       /*
+        * This is to tell gcc that we're not returning - do_signal
+        * can, in general, return, but in this case, it's not, since
+        * we just got a fatal SIGSEGV queued.
+        */
+       os_dump_core();
+}
+
+void segv_handler(int sig, struct uml_pt_regs *regs)
 {
        struct faultinfo * fi = UPT_FAULTINFO(regs);
 
@@ -216,9 +229,6 @@ unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user,
 
 void relay_signal(int sig, struct uml_pt_regs *regs)
 {
-       if (arch_handle_signal(sig, regs))
-               return;
-
        if (!UPT_IS_USER(regs)) {
                if (sig == SIGBUS)
                        printk(KERN_ERR "Bus error - the host /dev/shm or /tmp "
@@ -226,31 +236,24 @@ void relay_signal(int sig, struct uml_pt_regs *regs)
                panic("Kernel mode signal %d", sig);
        }
 
+       arch_examine_signal(sig, regs);
+
        current->thread.arch.faultinfo = *UPT_FAULTINFO(regs);
        force_sig(sig, current);
 }
 
-static void bus_handler(int sig, struct uml_pt_regs *regs)
+void bus_handler(int sig, struct uml_pt_regs *regs)
 {
        if (current->thread.fault_catcher != NULL)
                UML_LONGJMP(current->thread.fault_catcher, 1);
        else relay_signal(sig, regs);
 }
 
-static void winch(int sig, struct uml_pt_regs *regs)
+void winch(int sig, struct uml_pt_regs *regs)
 {
        do_IRQ(WINCH_IRQ, regs);
 }
 
-const struct kern_handlers handlinfo_kern = {
-       .relay_signal = relay_signal,
-       .winch = winch,
-       .bus_handler = bus_handler,
-       .page_fault = segv_handler,
-       .sigio_handler = sigio_handler,
-       .timer_handler = timer_handler
-};
-
 void trap_init(void)
 {
 }
index d7436aacd26f0feeb88600770474912c9220522e..f0f4b040d7c51cb1b17e44402ce5be1b03ec8f40 100644 (file)
@@ -1,10 +1,11 @@
 /*
  * Copyright (C) 2001 Chris Emerson (cemerson@chiark.greenend.org.uk)
- * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
  * Licensed under the GPL
  */
 
-/* These are here rather than tt/uaccess.c because skas mode needs them in
+/*
+ * These are here rather than tt/uaccess.c because skas mode needs them in
  * order to do SIGBUS recovery when a tmpfs mount runs out of room.
  */
 
@@ -25,6 +26,8 @@ int __do_copy_to_user(void *to, const void *from, int n,
 
        fault = __do_user_copy(to, from, n, fault_addr, fault_catcher,
                               __do_copy, &faulted);
-       if(!faulted) return(0);
-       else return(n - (fault - (unsigned long) to));
+       if (!faulted)
+               return 0;
+       else
+               return n - (fault - (unsigned long) to);
 }
index f1c71393f57810feb8368b256f7dab7bf5111a43..468aba990dbd1652add865bb88f1006ece3a7d16 100644 (file)
@@ -3,22 +3,23 @@
  * Licensed under the GPL
  */
 
-#include "linux/delay.h"
-#include "linux/mm.h"
-#include "linux/module.h"
-#include "linux/seq_file.h"
-#include "linux/string.h"
-#include "linux/utsname.h"
-#include "asm/pgtable.h"
-#include "asm/processor.h"
-#include "asm/setup.h"
-#include "arch.h"
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/seq_file.h>
+#include <linux/string.h>
+#include <linux/utsname.h>
+#include <asm/pgtable.h>
+#include <asm/processor.h>
+#include <asm/setup.h>
 #include "as-layout.h"
+#include "arch.h"
 #include "init.h"
 #include "kern.h"
+#include "kern_util.h"
 #include "mem_user.h"
 #include "os.h"
-#include "skas.h"
 
 #define DEFAULT_COMMAND_LINE "root=98:0"
 
@@ -100,8 +101,6 @@ const struct seq_operations cpuinfo_op = {
 };
 
 /* Set in linux_main */
-unsigned long host_task_size;
-unsigned long task_size;
 unsigned long uml_physmem;
 unsigned long uml_reserved; /* Also modified in mem_init */
 unsigned long start_vm;
@@ -197,20 +196,19 @@ __uml_setup("--help", Usage,
 "    Prints this message.\n\n"
 );
 
-static int __init uml_checksetup(char *line, int *add)
+static void __init uml_checksetup(char *line, int *add)
 {
        struct uml_param *p;
 
        p = &__uml_setup_start;
-       while(p < &__uml_setup_end) {
+       while (p < &__uml_setup_end) {
                int n;
 
                n = strlen(p->str);
                if (!strncmp(line, p->str, n) && p->setup_func(line + n, add))
-                       return 1;
+                       return;
                p++;
        }
-       return 0;
 }
 
 static void __init uml_postsetup(void)
@@ -218,13 +216,30 @@ static void __init uml_postsetup(void)
        initcall_t *p;
 
        p = &__uml_postsetup_start;
-       while(p < &__uml_postsetup_end) {
+       while (p < &__uml_postsetup_end) {
                (*p)();
                p++;
        }
        return;
 }
 
+static int panic_exit(struct notifier_block *self, unsigned long unused1,
+                     void *unused2)
+{
+       bust_spinlocks(1);
+       show_regs(&(current->thread.regs));
+       bust_spinlocks(0);
+       uml_exitcode = 1;
+       os_dump_core();
+       return 0;
+}
+
+static struct notifier_block panic_exit_notifier = {
+       .notifier_call          = panic_exit,
+       .next                   = NULL,
+       .priority               = 0
+};
+
 /* Set during early boot */
 unsigned long brk_start;
 unsigned long end_iomem;
@@ -234,20 +249,6 @@ EXPORT_SYMBOL(end_iomem);
 
 extern char __binary_start;
 
-static unsigned long set_task_sizes_skas(unsigned long *task_size_out)
-{
-       /* Round up to the nearest 4M */
-       unsigned long host_task_size = ROUND_4M((unsigned long)
-                                               &host_task_size);
-
-       if (!skas_needs_stub)
-               *task_size_out = host_task_size;
-       else
-               *task_size_out = STUB_START & PGDIR_MASK;
-
-       return host_task_size;
-}
-
 int __init linux_main(int argc, char **argv)
 {
        unsigned long avail, diff;
@@ -278,13 +279,6 @@ int __init linux_main(int argc, char **argv)
 
        printf("UML running in %s mode\n", mode);
 
-       host_task_size = set_task_sizes_skas(&task_size);
-
-       /*
-        * Setting up handlers to 'sig_info' struct
-        */
-       os_fill_handlinfo(handlinfo_kern);
-
        brk_start = (unsigned long) sbrk(0);
 
        /*
@@ -309,7 +303,7 @@ int __init linux_main(int argc, char **argv)
 
        highmem = 0;
        iomem_size = (iomem_size + PAGE_SIZE - 1) & PAGE_MASK;
-       max_physmem = get_kmem_end() - uml_physmem - iomem_size - MIN_VMALLOC;
+       max_physmem = CONFIG_TOP_ADDR - uml_physmem - iomem_size - MIN_VMALLOC;
 
        /*
         * Zones have to begin on a 1 << MAX_ORDER page boundary,
@@ -341,7 +335,7 @@ int __init linux_main(int argc, char **argv)
        }
 
        virtmem_size = physmem_size;
-       avail = get_kmem_end() - start_vm;
+       avail = CONFIG_TOP_ADDR - start_vm;
        if (physmem_size > avail)
                virtmem_size = avail;
        end_vm = start_vm + virtmem_size;
@@ -350,6 +344,9 @@ int __init linux_main(int argc, char **argv)
                printf("Kernel virtual memory size shrunk to %lu bytes\n",
                       virtmem_size);
 
+       atomic_notifier_chain_register(&panic_notifier_list,
+                                      &panic_exit_notifier);
+
        uml_postsetup();
 
        stack_protections((unsigned long) &init_thread_info);
@@ -358,29 +355,8 @@ int __init linux_main(int argc, char **argv)
        return start_uml();
 }
 
-extern int uml_exitcode;
-
-static int panic_exit(struct notifier_block *self, unsigned long unused1,
-                     void *unused2)
-{
-       bust_spinlocks(1);
-       show_regs(&(current->thread.regs));
-       bust_spinlocks(0);
-       uml_exitcode = 1;
-       os_dump_core();
-       return 0;
-}
-
-static struct notifier_block panic_exit_notifier = {
-       .notifier_call          = panic_exit,
-       .next                   = NULL,
-       .priority               = 0
-};
-
 void __init setup_arch(char **cmdline_p)
 {
-       atomic_notifier_chain_register(&panic_notifier_list,
-                       &panic_exit_notifier);
        paging_init();
        strlcpy(boot_command_line, command_line, COMMAND_LINE_SIZE);
        *cmdline_p = command_line;
index 039e16efcd5571a7a520f051cf5efa1c61c61b54..81e07e2be3ae540abb2715ca56824f02b79c6cea 100644 (file)
@@ -1,13 +1,12 @@
-/* 
- * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
+/*
+ * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
  * Licensed under the GPL
  */
 
-#include "asm/errno.h"
+#include <asm/errno.h>
 #include "init.h"
-#include "os.h"
 #include "kern.h"
-#include "linux/kernel.h"
+#include "os.h"
 
 /* Changed by set_umid_arg */
 static int umid_inited = 0;
@@ -16,16 +15,16 @@ static int __init set_umid_arg(char *name, int *add)
 {
        int err;
 
-       if(umid_inited){
+       if (umid_inited) {
                printf("umid already set\n");
                return 0;
        }
 
        *add = 0;
        err = set_umid(name);
-       if(err == -EEXIST)
+       if (err == -EEXIST)
                printf("umid '%s' already in use\n", name);
-       else if(!err)
+       else if (!err)
                umid_inited = 1;
 
        return 0;
index 8e129af8170d2b7d7af03aee3e70957dc0f5835f..8a48d6a30064139fa28bcfc53a0897b046988a3b 100644 (file)
@@ -4,7 +4,7 @@
 #
 
 obj-y = aio.o elf_aux.o execvp.o file.o helper.o irq.o main.o mem.o process.o \
-       registers.o sigio.o signal.o start_up.o time.o trap.o tty.o uaccess.o \
+       registers.o sigio.o signal.o start_up.o time.o tty.o uaccess.o \
        umid.o tls.o user_syms.o util.o drivers/ sys-$(SUBARCH)/ skas/
 
 obj-$(CONFIG_TTY_LOG) += tty_log.o
@@ -12,7 +12,7 @@ user-objs-$(CONFIG_TTY_LOG) += tty_log.o
 
 USER_OBJS := $(user-objs-y) aio.o elf_aux.o execvp.o file.o helper.o irq.o \
        main.o mem.o process.o registers.o sigio.o signal.o start_up.o time.o \
-       trap.o tty.o tls.o uaccess.o umid.o util.o
+       tty.o tls.o uaccess.o umid.o util.o
 
 CFLAGS_user_syms.o += -DSUBARCH_$(SUBARCH)
 
index 93dc0c80ebaf7d128f08125185a8ba65c5f6f770..b8d8c9ca8d4afa48d3374520615fc5fdf8c2d8df 100644 (file)
@@ -12,6 +12,7 @@
 #include "aio.h"
 #include "init.h"
 #include "kern_constants.h"
+#include "kern_util.h"
 #include "os.h"
 #include "user.h"
 
index 07ca0cb472acf40b1ed8976070e5f4e2ac2cba25..6fb0b174f538df06711bf0f5b779f62ea4eb1f63 100644 (file)
@@ -131,7 +131,7 @@ static int etap_tramp(char *dev, char *gate, int control_me,
        }
        if (c != 1) {
                printk(UM_KERN_ERR "etap_tramp : uml_net failed\n");
-               err = helper_wait(pid, 0, "uml_net");
+               err = helper_wait(pid);
        }
        return err;
 }
index 1037a3b6386ee95f4ff746f764fd1200dc5411f3..2448be03fd7a5018691d3656d963d934b604c810 100644 (file)
@@ -14,6 +14,7 @@
 #include <sys/wait.h>
 #include <sys/uio.h>
 #include "kern_constants.h"
+#include "kern_util.h"
 #include "os.h"
 #include "tuntap.h"
 #include "user.h"
@@ -107,7 +108,7 @@ static int tuntap_open_tramp(char *gate, int *fd_out, int me, int remote,
                       "errno = %d\n", errno);
                return err;
        }
-       helper_wait(pid, 0, "tuntap_open_tramp");
+       helper_wait(pid);
 
        cmsg = CMSG_FIRSTHDR(&msg);
        if (cmsg == NULL) {
@@ -148,7 +149,7 @@ static int tuntap_open(void *data)
                memset(&ifr, 0, sizeof(ifr));
                ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
                strlcpy(ifr.ifr_name, pri->dev_name, sizeof(ifr.ifr_name));
-               if (ioctl(pri->fd, TUNSETIFF, (void *) &ifr) < 0) {
+               if (ioctl(pri->fd, TUNSETIFF, &ifr) < 0) {
                        err = -errno;
                        printk(UM_KERN_ERR "TUNSETIFF failed, errno = %d\n",
                               errno);
index f834627586272b80c4702b499553ac24c296c9dd..b5afcfd0f8611dedd72bd3c58defddcd1e647035 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
  * Licensed under the GPL
  */
 
@@ -8,18 +8,16 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <signal.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/socket.h>
-#include <sys/un.h>
 #include <sys/ioctl.h>
 #include <sys/mount.h>
-#include <sys/uio.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/un.h>
+#include "kern_constants.h"
 #include "os.h"
 #include "user.h"
-#include "kern_util.h"
 
-static void copy_stat(struct uml_stat *dst, struct stat64 *src)
+static void copy_stat(struct uml_stat *dst, const struct stat64 *src)
 {
        *dst = ((struct uml_stat) {
                .ust_dev     = src->st_dev,     /* device */
@@ -43,10 +41,10 @@ int os_stat_fd(const int fd, struct uml_stat *ubuf)
        int err;
 
        CATCH_EINTR(err = fstat64(fd, &sbuf));
-       if(err < 0)
+       if (err < 0)
                return -errno;
 
-       if(ubuf != NULL)
+       if (ubuf != NULL)
                copy_stat(ubuf, &sbuf);
        return err;
 }
@@ -56,27 +54,26 @@ int os_stat_file(const char *file_name, struct uml_stat *ubuf)
        struct stat64 sbuf;
        int err;
 
-       do {
-               err = stat64(file_name, &sbuf);
-       } while((err < 0) && (errno == EINTR)) ;
-
-       if(err < 0)
+       CATCH_EINTR(err = stat64(file_name, &sbuf));
+       if (err < 0)
                return -errno;
 
-       if(ubuf != NULL)
+       if (ubuf != NULL)
                copy_stat(ubuf, &sbuf);
        return err;
 }
 
-int os_access(const charfile, int mode)
+int os_access(const char *file, int mode)
 {
        int amode, err;
 
-       amode=(mode&OS_ACC_R_OK ? R_OK : 0) | (mode&OS_ACC_W_OK ? W_OK : 0) |
-             (mode&OS_ACC_X_OK ? X_OK : 0) | (mode&OS_ACC_F_OK ? F_OK : 0) ;
+       amode = (mode & OS_ACC_R_OK ? R_OK : 0) |
+               (mode & OS_ACC_W_OK ? W_OK : 0) |
+               (mode & OS_ACC_X_OK ? X_OK : 0) |
+               (mode & OS_ACC_F_OK ? F_OK : 0);
 
        err = access(file, amode);
-       if(err < 0)
+       if (err < 0)
                return -errno;
 
        return 0;
@@ -88,7 +85,7 @@ int os_ioctl_generic(int fd, unsigned int cmd, unsigned long arg)
        int err;
 
        err = ioctl(fd, cmd, arg);
-       if(err < 0)
+       if (err < 0)
                return -errno;
 
        return err;
@@ -97,7 +94,7 @@ int os_ioctl_generic(int fd, unsigned int cmd, unsigned long arg)
 /* FIXME: ensure namebuf in os_get_if_name is big enough */
 int os_get_ifname(int fd, char* namebuf)
 {
-       if(ioctl(fd, SIOCGIFNAME, namebuf) < 0)
+       if (ioctl(fd, SIOCGIFNAME, namebuf) < 0)
                return -errno;
 
        return 0;
@@ -108,37 +105,22 @@ int os_set_slip(int fd)
        int disc, sencap;
 
        disc = N_SLIP;
-       if(ioctl(fd, TIOCSETD, &disc) < 0)
+       if (ioctl(fd, TIOCSETD, &disc) < 0)
                return -errno;
 
        sencap = 0;
-       if(ioctl(fd, SIOCSIFENCAP, &sencap) < 0)
+       if (ioctl(fd, SIOCSIFENCAP, &sencap) < 0)
                return -errno;
 
        return 0;
 }
 
-int os_set_owner(int fd, int pid)
-{
-       if(fcntl(fd, F_SETOWN, pid) < 0){
-               int save_errno = errno;
-
-               if(fcntl(fd, F_GETOWN, 0) != pid)
-                       return -save_errno;
-       }
-
-       return 0;
-}
-
 int os_mode_fd(int fd, int mode)
 {
        int err;
 
-       do {
-               err = fchmod(fd, mode);
-       } while((err < 0) && (errno==EINTR)) ;
-
-       if(err < 0)
+       CATCH_EINTR(err = fchmod(fd, mode));
+       if (err < 0)
                return -errno;
 
        return 0;
@@ -150,64 +132,73 @@ int os_file_type(char *file)
        int err;
 
        err = os_stat_file(file, &buf);
-       if(err < 0)
+       if (err < 0)
                return err;
 
-       if(S_ISDIR(buf.ust_mode))
+       if (S_ISDIR(buf.ust_mode))
                return OS_TYPE_DIR;
-       else if(S_ISLNK(buf.ust_mode))
+       else if (S_ISLNK(buf.ust_mode))
                return OS_TYPE_SYMLINK;
-       else if(S_ISCHR(buf.ust_mode))
+       else if (S_ISCHR(buf.ust_mode))
                return OS_TYPE_CHARDEV;
-       else if(S_ISBLK(buf.ust_mode))
+       else if (S_ISBLK(buf.ust_mode))
                return OS_TYPE_BLOCKDEV;
-       else if(S_ISFIFO(buf.ust_mode))
+       else if (S_ISFIFO(buf.ust_mode))
                return OS_TYPE_FIFO;
-       else if(S_ISSOCK(buf.ust_mode))
+       else if (S_ISSOCK(buf.ust_mode))
                return OS_TYPE_SOCK;
        else return OS_TYPE_FILE;
 }
 
-int os_file_mode(char *file, struct openflags *mode_out)
+int os_file_mode(const char *file, struct openflags *mode_out)
 {
        int err;
 
        *mode_out = OPENFLAGS();
 
        err = access(file, W_OK);
-       if(err && (errno != EACCES))
+       if (err && (errno != EACCES))
                return -errno;
-       else if(!err)
+       else if (!err)
                *mode_out = of_write(*mode_out);
 
        err = access(file, R_OK);
-       if(err && (errno != EACCES))
+       if (err && (errno != EACCES))
                return -errno;
-       else if(!err)
+       else if (!err)
                *mode_out = of_read(*mode_out);
 
        return err;
 }
 
-int os_open_file(char *file, struct openflags flags, int mode)
+int os_open_file(const char *file, struct openflags flags, int mode)
 {
        int fd, err, f = 0;
 
-       if(flags.r && flags.w) f = O_RDWR;
-       else if(flags.r) f = O_RDONLY;
-       else if(flags.w) f = O_WRONLY;
+       if (flags.r && flags.w)
+               f = O_RDWR;
+       else if (flags.r)
+               f = O_RDONLY;
+       else if (flags.w)
+               f = O_WRONLY;
        else f = 0;
 
-       if(flags.s) f |= O_SYNC;
-       if(flags.c) f |= O_CREAT;
-       if(flags.t) f |= O_TRUNC;
-       if(flags.e) f |= O_EXCL;
+       if (flags.s)
+               f |= O_SYNC;
+       if (flags.c)
+               f |= O_CREAT;
+       if (flags.t)
+               f |= O_TRUNC;
+       if (flags.e)
+               f |= O_EXCL;
+       if (flags.a)
+               f |= O_APPEND;
 
        fd = open64(file, f, mode);
-       if(fd < 0)
+       if (fd < 0)
                return -errno;
 
-       if(flags.cl && fcntl(fd, F_SETFD, 1)){
+       if (flags.cl && fcntl(fd, F_SETFD, 1)) {
                err = -errno;
                close(fd);
                return err;
@@ -216,7 +207,7 @@ int os_open_file(char *file, struct openflags flags, int mode)
        return fd;
 }
 
-int os_connect_socket(char *name)
+int os_connect_socket(const char *name)
 {
        struct sockaddr_un sock;
        int fd, err;
@@ -225,13 +216,13 @@ int os_connect_socket(char *name)
        snprintf(sock.sun_path, sizeof(sock.sun_path), "%s", name);
 
        fd = socket(AF_UNIX, SOCK_STREAM, 0);
-       if(fd < 0) {
+       if (fd < 0) {
                err = -errno;
                goto out;
        }
 
        err = connect(fd, (struct sockaddr *) &sock, sizeof(sock));
-       if(err) {
+       if (err) {
                err = -errno;
                goto out_close;
        }
@@ -254,7 +245,7 @@ int os_seek_file(int fd, unsigned long long offset)
        unsigned long long actual;
 
        actual = lseek64(fd, offset, SEEK_SET);
-       if(actual != offset)
+       if (actual != offset)
                return -errno;
        return 0;
 }
@@ -263,7 +254,7 @@ int os_read_file(int fd, void *buf, int len)
 {
        int n = read(fd, buf, len);
 
-       if(n < 0)
+       if (n < 0)
                return -errno;
        return n;
 }
@@ -272,37 +263,38 @@ int os_write_file(int fd, const void *buf, int len)
 {
        int n = write(fd, (void *) buf, len);
 
-       if(n < 0)
+       if (n < 0)
                return -errno;
        return n;
 }
 
-int os_file_size(char *file, unsigned long long *size_out)
+int os_file_size(const char *file, unsigned long long *size_out)
 {
        struct uml_stat buf;
        int err;
 
        err = os_stat_file(file, &buf);
-       if(err < 0){
-               printk("Couldn't stat \"%s\" : err = %d\n", file, -err);
+       if (err < 0) {
+               printk(UM_KERN_ERR "Couldn't stat \"%s\" : err = %d\n", file,
+                      -err);
                return err;
        }
 
-       if(S_ISBLK(buf.ust_mode)){
+       if (S_ISBLK(buf.ust_mode)) {
                int fd;
                long blocks;
 
                fd = open(file, O_RDONLY, 0);
-               if(fd < 0) {
+               if (fd < 0) {
                        err = -errno;
-                       printk("Couldn't open \"%s\", errno = %d\n", file,
-                              errno);
+                       printk(UM_KERN_ERR "Couldn't open \"%s\", "
+                              "errno = %d\n", file, errno);
                        return err;
                }
-               if(ioctl(fd, BLKGETSIZE, &blocks) < 0){
+               if (ioctl(fd, BLKGETSIZE, &blocks) < 0) {
                        err = -errno;
-                       printk("Couldn't get the block size of \"%s\", "
-                              "errno = %d\n", file, errno);
+                       printk(UM_KERN_ERR "Couldn't get the block size of "
+                              "\"%s\", errno = %d\n", file, errno);
                        close(fd);
                        return err;
                }
@@ -314,14 +306,15 @@ int os_file_size(char *file, unsigned long long *size_out)
        return 0;
 }
 
-int os_file_modtime(char *file, unsigned long *modtime)
+int os_file_modtime(const char *file, unsigned long *modtime)
 {
        struct uml_stat buf;
        int err;
 
        err = os_stat_file(file, &buf);
-       if(err < 0){
-               printk("Couldn't stat \"%s\" : err = %d\n", file, -err);
+       if (err < 0) {
+               printk(UM_KERN_ERR "Couldn't stat \"%s\" : err = %d\n", file,
+                      -err);
                return err;
        }
 
@@ -329,26 +322,13 @@ int os_file_modtime(char *file, unsigned long *modtime)
        return 0;
 }
 
-int os_get_exec_close(int fd, int *close_on_exec)
-{
-       int ret;
-
-       CATCH_EINTR(ret = fcntl(fd, F_GETFD));
-
-       if(ret < 0)
-               return -errno;
-
-       *close_on_exec = (ret & FD_CLOEXEC) ? 1 : 0;
-       return ret;
-}
-
 int os_set_exec_close(int fd)
 {
        int err;
 
        CATCH_EINTR(err = fcntl(fd, F_SETFD, FD_CLOEXEC));
 
-       if(err < 0)
+       if (err < 0)
                return -errno;
        return err;
 }
@@ -358,53 +338,51 @@ int os_pipe(int *fds, int stream, int close_on_exec)
        int err, type = stream ? SOCK_STREAM : SOCK_DGRAM;
 
        err = socketpair(AF_UNIX, type, 0, fds);
-       if(err < 0)
+       if (err < 0)
                return -errno;
 
-       if(!close_on_exec)
+       if (!close_on_exec)
                return 0;
 
        err = os_set_exec_close(fds[0]);
-       if(err < 0)
+       if (err < 0)
                goto error;
 
        err = os_set_exec_close(fds[1]);
-       if(err < 0)
+       if (err < 0)
                goto error;
 
        return 0;
 
  error:
-       printk("os_pipe : Setting FD_CLOEXEC failed, err = %d\n", -err);
+       printk(UM_KERN_ERR "os_pipe : Setting FD_CLOEXEC failed, err = %d\n",
+              -err);
        close(fds[1]);
        close(fds[0]);
        return err;
 }
 
-int os_set_fd_async(int fd, int owner)
+int os_set_fd_async(int fd)
 {
-       int err;
+       int err, flags;
+
+       flags = fcntl(fd, F_GETFL);
+       if (flags < 0)
+               return -errno;
 
-       /* XXX This should do F_GETFL first */
-       if(fcntl(fd, F_SETFL, O_ASYNC | O_NONBLOCK) < 0){
+       flags |= O_ASYNC | O_NONBLOCK;
+       if (fcntl(fd, F_SETFL, flags) < 0) {
                err = -errno;
-               printk("os_set_fd_async : failed to set O_ASYNC and "
-                      "O_NONBLOCK on fd # %d, errno = %d\n", fd, errno);
+               printk(UM_KERN_ERR "os_set_fd_async : failed to set O_ASYNC "
+                      "and O_NONBLOCK on fd # %d, errno = %d\n", fd, errno);
                return err;
        }
-#ifdef notdef
-       if(fcntl(fd, F_SETFD, 1) < 0){
-               printk("os_set_fd_async : Setting FD_CLOEXEC failed, "
-                      "errno = %d\n", errno);
-       }
-#endif
 
-       if((fcntl(fd, F_SETSIG, SIGIO) < 0) ||
-          (fcntl(fd, F_SETOWN, owner) < 0)){
+       if ((fcntl(fd, F_SETSIG, SIGIO) < 0) ||
+           (fcntl(fd, F_SETOWN, os_getpid()) < 0)) {
                err = -errno;
-               printk("os_set_fd_async : Failed to fcntl F_SETOWN "
-                      "(or F_SETSIG) fd %d to pid %d, errno = %d\n", fd,
-                      owner, errno);
+               printk(UM_KERN_ERR "os_set_fd_async : Failed to fcntl F_SETOWN "
+                      "(or F_SETSIG) fd %d, errno = %d\n", fd, errno);
                return err;
        }
 
@@ -413,10 +391,14 @@ int os_set_fd_async(int fd, int owner)
 
 int os_clear_fd_async(int fd)
 {
-       int flags = fcntl(fd, F_GETFL);
+       int flags;
+
+       flags = fcntl(fd, F_GETFL);
+       if (flags < 0)
+               return -errno;
 
        flags &= ~(O_ASYNC | O_NONBLOCK);
-       if(fcntl(fd, F_SETFL, flags) < 0)
+       if (fcntl(fd, F_SETFL, flags) < 0)
                return -errno;
        return 0;
 }
@@ -426,11 +408,15 @@ int os_set_fd_block(int fd, int blocking)
        int flags;
 
        flags = fcntl(fd, F_GETFL);
+       if (flags < 0)
+               return -errno;
 
-       if(blocking) flags &= ~O_NONBLOCK;
-       else flags |= O_NONBLOCK;
+       if (blocking)
+               flags &= ~O_NONBLOCK;
+       else
+               flags |= O_NONBLOCK;
 
-       if(fcntl(fd, F_SETFL, flags) < 0)
+       if (fcntl(fd, F_SETFL, flags) < 0)
                return -errno;
 
        return 0;
@@ -441,7 +427,7 @@ int os_accept_connection(int fd)
        int new;
 
        new = accept(fd, NULL, 0);
-       if(new < 0)
+       if (new < 0)
                return -errno;
        return new;
 }
@@ -462,15 +448,17 @@ int os_shutdown_socket(int fd, int r, int w)
 {
        int what, err;
 
-       if(r && w) what = SHUT_RDWR;
-       else if(r) what = SHUT_RD;
-       else if(w) what = SHUT_WR;
-       else {
-               printk("os_shutdown_socket : neither r or w was set\n");
+       if (r && w)
+               what = SHUT_RDWR;
+       else if (r)
+               what = SHUT_RD;
+       else if (w)
+               what = SHUT_WR;
+       else
                return -EINVAL;
-       }
+
        err = shutdown(fd, what);
-       if(err < 0)
+       if (err < 0)
                return -errno;
        return 0;
 }
@@ -494,19 +482,20 @@ int os_rcv_fd(int fd, int *helper_pid_out)
        msg.msg_flags = 0;
 
        n = recvmsg(fd, &msg, 0);
-       if(n < 0)
+       if (n < 0)
                return -errno;
-       else if(n != iov.iov_len)
+       else if (n != iov.iov_len)
                *helper_pid_out = -1;
 
        cmsg = CMSG_FIRSTHDR(&msg);
-       if(cmsg == NULL){
-               printk("rcv_fd didn't receive anything, error = %d\n", errno);
+       if (cmsg == NULL) {
+               printk(UM_KERN_ERR "rcv_fd didn't receive anything, "
+                      "error = %d\n", errno);
                return -1;
        }
-       if((cmsg->cmsg_level != SOL_SOCKET) ||
-          (cmsg->cmsg_type != SCM_RIGHTS)){
-               printk("rcv_fd didn't receive a descriptor\n");
+       if ((cmsg->cmsg_level != SOL_SOCKET) ||
+           (cmsg->cmsg_type != SCM_RIGHTS)) {
+               printk(UM_KERN_ERR "rcv_fd didn't receive a descriptor\n");
                return -1;
        }
 
@@ -514,29 +503,28 @@ int os_rcv_fd(int fd, int *helper_pid_out)
        return new;
 }
 
-int os_create_unix_socket(char *file, int len, int close_on_exec)
+int os_create_unix_socket(const char *file, int len, int close_on_exec)
 {
        struct sockaddr_un addr;
        int sock, err;
 
        sock = socket(PF_UNIX, SOCK_DGRAM, 0);
-       if(sock < 0)
+       if (sock < 0)
                return -errno;
 
-       if(close_on_exec) {
+       if (close_on_exec) {
                err = os_set_exec_close(sock);
-               if(err < 0)
-                       printk("create_unix_socket : close_on_exec failed, "
-                      "err = %d", -err);
+               if (err < 0)
+                       printk(UM_KERN_ERR "create_unix_socket : "
+                              "close_on_exec failed, err = %d", -err);
        }
 
        addr.sun_family = AF_UNIX;
 
-       /* XXX Be more careful about overflow */
        snprintf(addr.sun_path, len, "%s", file);
 
        err = bind(sock, (struct sockaddr *) &addr, sizeof(addr));
-       if(err < 0)
+       if (err < 0)
                return -errno;
 
        return sock;
@@ -557,17 +545,18 @@ int os_lock_file(int fd, int excl)
        int err, save;
 
        err = fcntl(fd, F_SETLK, &lock);
-       if(!err)
+       if (!err)
                goto out;
 
        save = -errno;
        err = fcntl(fd, F_GETLK, &lock);
-       if(err){
+       if (err) {
                err = -errno;
                goto out;
        }
 
-       printk("F_SETLK failed, file already locked by pid %d\n", lock.l_pid);
+       printk(UM_KERN_ERR "F_SETLK failed, file already locked by pid %d\n",
+              lock.l_pid);
        err = save;
  out:
        return err;
index fba3f0fefeef7ca78d3edd685f24e8d5d4c254bc..f4bd349d441222fb7c400ac63d8e7b8c390784a2 100644 (file)
@@ -1,22 +1,19 @@
 /*
- * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
  * Licensed under the GPL
  */
 
-#include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <errno.h>
 #include <sched.h>
-#include <limits.h>
-#include <sys/signal.h>
-#include <sys/wait.h>
 #include <sys/socket.h>
-#include "user.h"
+#include <sys/wait.h>
+#include "kern_constants.h"
 #include "kern_util.h"
 #include "os.h"
 #include "um_malloc.h"
-#include "kern_constants.h"
+#include "user.h"
 
 struct helper_data {
        void (*pre_exec)(void*);
@@ -30,21 +27,19 @@ static int helper_child(void *arg)
 {
        struct helper_data *data = arg;
        char **argv = data->argv;
-       int errval;
+       int err;
 
        if (data->pre_exec != NULL)
                (*data->pre_exec)(data->pre_data);
-       errval = execvp_noalloc(data->buf, argv[0], argv);
-       printk("helper_child - execvp of '%s' failed - errno = %d\n", argv[0],
-              -errval);
-       write(data->fd, &errval, sizeof(errval));
-       kill(os_getpid(), SIGKILL);
+       err = execvp_noalloc(data->buf, argv[0], argv);
+
+       /* If the exec succeeds, we don't get here */
+       write(data->fd, &err, sizeof(err));
+
        return 0;
 }
 
-/* Returns either the pid of the child process we run or -E* on failure.
- * XXX The alloc_stack here breaks if this is called in the tracing thread, so
- * we need to receive a preallocated stack (a local buffer is ok). */
+/* Returns either the pid of the child process we run or -E* on failure. */
 int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv)
 {
        struct helper_data data;
@@ -58,14 +53,15 @@ int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv)
        ret = socketpair(AF_UNIX, SOCK_STREAM, 0, fds);
        if (ret < 0) {
                ret = -errno;
-               printk("run_helper : pipe failed, errno = %d\n", errno);
+               printk(UM_KERN_ERR "run_helper : pipe failed, errno = %d\n",
+                      errno);
                goto out_free;
        }
 
        ret = os_set_exec_close(fds[1]);
        if (ret < 0) {
-               printk("run_helper : setting FD_CLOEXEC failed, ret = %d\n",
-                      -ret);
+               printk(UM_KERN_ERR "run_helper : setting FD_CLOEXEC failed, "
+                      "ret = %d\n", -ret);
                goto out_close;
        }
 
@@ -79,7 +75,8 @@ int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv)
        pid = clone(helper_child, (void *) sp, CLONE_VM, &data);
        if (pid < 0) {
                ret = -errno;
-               printk("run_helper : clone failed, errno = %d\n", errno);
+               printk(UM_KERN_ERR "run_helper : clone failed, errno = %d\n",
+                      errno);
                goto out_free2;
        }
 
@@ -96,10 +93,9 @@ int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv)
        } else {
                if (n < 0) {
                        n = -errno;
-                       printk("run_helper : read on pipe failed, ret = %d\n",
-                              -n);
+                       printk(UM_KERN_ERR "run_helper : read on pipe failed, "
+                              "ret = %d\n", -n);
                        ret = n;
-                       kill(pid, SIGKILL);
                }
                CATCH_EINTR(waitpid(pid, NULL, __WCLONE));
        }
@@ -129,50 +125,40 @@ int run_helper_thread(int (*proc)(void *), void *arg, unsigned int flags,
        pid = clone(proc, (void *) sp, flags, arg);
        if (pid < 0) {
                err = -errno;
-               printk("run_helper_thread : clone failed, errno = %d\n",
-                      errno);
+               printk(UM_KERN_ERR "run_helper_thread : clone failed, "
+                      "errno = %d\n", errno);
                return err;
        }
        if (stack_out == NULL) {
                CATCH_EINTR(pid = waitpid(pid, &status, __WCLONE));
                if (pid < 0) {
                        err = -errno;
-                       printk("run_helper_thread - wait failed, errno = %d\n",
-                              errno);
+                       printk(UM_KERN_ERR "run_helper_thread - wait failed, "
+                              "errno = %d\n", errno);
                        pid = err;
                }
                if (!WIFEXITED(status) || (WEXITSTATUS(status) != 0))
-                       printk("run_helper_thread - thread returned status "
-                              "0x%x\n", status);
+                       printk(UM_KERN_ERR "run_helper_thread - thread "
+                              "returned status 0x%x\n", status);
                free_stack(stack, 0);
        } else
                *stack_out = stack;
        return pid;
 }
 
-int helper_wait(int pid, int nohang, char *pname)
+int helper_wait(int pid)
 {
        int ret, status;
        int wflags = __WCLONE;
 
-       if (nohang)
-               wflags |= WNOHANG;
-
-       if (!pname)
-               pname = "helper_wait";
-
        CATCH_EINTR(ret = waitpid(pid, &status, wflags));
        if (ret < 0) {
-               printk(UM_KERN_ERR "%s : waitpid process %d failed, "
-                      "errno = %d\n", pname, pid, errno);
+               printk(UM_KERN_ERR "helper_wait : waitpid process %d failed, "
+                      "errno = %d\n", pid, errno);
                return -errno;
-       } else if (nohang && ret == 0) {
-               printk(UM_KERN_ERR "%s : process %d has not exited\n",
-                      pname, pid);
-               return -ECHILD;
        } else if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
-               printk(UM_KERN_ERR "%s : process %d didn't exit with "
-                      "status 0\n", pname, pid);
+               printk(UM_KERN_ERR "helper_wait : process %d exited with "
+                      "status 0x%x\n", pid, status);
                return -ECHILD;
        } else
                return 0;
index 6aa6f95d652491ab4e1161247febeaa1c91856c1..0348b975e81cb3a5a4d067a8f3b39c5d2db1fff5 100644 (file)
@@ -1,23 +1,19 @@
 /*
- * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
  * Licensed under the GPL
  */
 
 #include <stdlib.h>
-#include <unistd.h>
 #include <errno.h>
+#include <poll.h>
 #include <signal.h>
 #include <string.h>
-#include <sys/poll.h>
-#include <sys/types.h>
-#include <sys/time.h>
-#include "kern_util.h"
-#include "user.h"
-#include "process.h"
-#include "sigio.h"
 #include "irq_user.h"
+#include "kern_constants.h"
 #include "os.h"
+#include "process.h"
 #include "um_malloc.h"
+#include "user.h"
 
 /*
  * Locked by irq_lock in arch/um/kernel/irq.c.  Changed by os_create_pollfd
@@ -36,7 +32,7 @@ int os_waiting_for_events(struct irq_fd *active_fds)
        if (n < 0) {
                err = -errno;
                if (errno != EINTR)
-                       printk("sigio_handler: os_waiting_for_events:"
+                       printk(UM_KERN_ERR "os_waiting_for_events:"
                               " poll returned %d, errno = %d\n", n, errno);
                return err;
        }
@@ -95,24 +91,26 @@ void os_free_irq_by_cb(int (*test)(struct irq_fd *, void *), void *arg,
                        struct irq_fd *old_fd = *prev;
                        if ((pollfds[i].fd != -1) &&
                            (pollfds[i].fd != (*prev)->fd)) {
-                               printk("os_free_irq_by_cb - mismatch between "
-                                      "active_fds and pollfds, fd %d vs %d\n",
+                               printk(UM_KERN_ERR "os_free_irq_by_cb - "
+                                      "mismatch between active_fds and "
+                                      "pollfds, fd %d vs %d\n",
                                       (*prev)->fd, pollfds[i].fd);
                                goto out;
                        }
 
                        pollfds_num--;
 
-                       /* This moves the *whole* array after pollfds[i]
+                       /*
+                        * This moves the *whole* array after pollfds[i]
                         * (though it doesn't spot as such)!
                         */
                        memmove(&pollfds[i], &pollfds[i + 1],
                               (pollfds_num - i) * sizeof(pollfds[0]));
-                       if(*last_irq_ptr2 == &old_fd->next)
+                       if (*last_irq_ptr2 == &old_fd->next)
                                *last_irq_ptr2 = prev;
 
                        *prev = (*prev)->next;
-                       if(old_fd->type == IRQ_WRITE)
+                       if (old_fd->type == IRQ_WRITE)
                                ignore_sigio_fd(old_fd->fd);
                        kfree(old_fd);
                        continue;
@@ -138,14 +136,3 @@ void os_set_ioignore(void)
 {
        signal(SIGIO, SIG_IGN);
 }
-
-void init_irq_signals(int on_sigstack)
-{
-       int flags;
-
-       flags = on_sigstack ? SA_ONSTACK : 0;
-
-       set_handler(SIGIO, (__sighandler_t) sig_handler, flags | SA_RESTART,
-                   SIGUSR1, SIGIO, SIGWINCH, SIGVTALRM, -1);
-       signal(SIGWINCH, SIG_IGN);
-}
index 82c3778627b8e91e448e969022c7b06e1a2241ab..abb9b0ffd9600402e770d93fce945c9b0295b98b 100644 (file)
@@ -73,7 +73,7 @@ static void install_fatal_handler(int sig)
        action.sa_handler = last_ditch_exit;
        if (sigaction(sig, &action, NULL) < 0) {
                printf("failed to install handler for signal %d - errno = %d\n",
-                      errno);
+                      sig, errno);
                exit(1);
        }
 }
@@ -92,7 +92,8 @@ static void setup_env_path(void)
         * just use the default + /usr/lib/uml
         */
        if (!old_path || (path_len = strlen(old_path)) == 0) {
-               putenv("PATH=:/bin:/usr/bin/" UML_LIB_PATH);
+               if (putenv("PATH=:/bin:/usr/bin/" UML_LIB_PATH))
+                       perror("couldn't putenv");
                return;
        }
 
@@ -100,15 +101,16 @@ static void setup_env_path(void)
        path_len += strlen("PATH=" UML_LIB_PATH) + 1;
        new_path = malloc(path_len);
        if (!new_path) {
-               perror("coudn't malloc to set a new PATH");
+               perror("couldn't malloc to set a new PATH");
                return;
        }
        snprintf(new_path, path_len, "PATH=%s" UML_LIB_PATH, old_path);
-       putenv(new_path);
+       if (putenv(new_path)) {
+               perror("couldn't putenv to set a new PATH");
+               free(new_path);
+       }
 }
 
-extern int uml_exitcode;
-
 extern void scan_elf_aux( char **envp);
 
 int __init main(int argc, char **argv, char **envp)
index 436f8d20b20f64de342c3b4a4c2fdef2d92dab2f..eedc2d88ef8a5a3d6b00e87e88a8a05e7c77ab89 100644 (file)
@@ -9,7 +9,6 @@
 #include <sys/types.h>
 #include <sys/mman.h>
 #include <sys/statfs.h>
-#include "kern_util.h"
 #include "user.h"
 #include "mem_user.h"
 #include "init.h"
@@ -30,7 +29,7 @@ static char *tempdir = NULL;
 
 static void __init find_tempdir(void)
 {
-       char *dirs[] = { "TMP", "TEMP", "TMPDIR", NULL };
+       const char *dirs[] = { "TMP", "TEMP", "TMPDIR", NULL };
        int i;
        char *dir = NULL;
 
@@ -59,9 +58,10 @@ static void __init find_tempdir(void)
  * read the file as needed.  If there's an error, -errno is returned;
  * if the end of the file is reached, 0 is returned.
  */
-static int next(int fd, char *buf, int size, char c)
+static int next(int fd, char *buf, size_t size, char c)
 {
-       int n, len;
+       ssize_t n;
+       size_t len;
        char *ptr;
 
        while((ptr = strchr(buf, c)) == NULL){
@@ -172,13 +172,15 @@ int __init make_tempfile(const char *template, char **out_tempname,
 
        which_tmpdir();
        tempname = malloc(MAXPATHLEN);
+       if (!tempname)
+               goto out;
 
        find_tempdir();
        if (template[0] != '/')
                strcpy(tempname, tempdir);
        else
                tempname[0] = '\0';
-       strcat(tempname, template);
+       strncat(tempname, template, MAXPATHLEN-1-strlen(tempname));
        fd = mkstemp(tempname);
        if(fd < 0){
                fprintf(stderr, "open - cannot create %s: %s\n", tempname,
@@ -268,6 +270,7 @@ void __init check_tmpexec(void)
        if(addr == MAP_FAILED){
                err = errno;
                perror("failed");
+               close(fd);
                if(err == EPERM)
                        printf("%s must be not mounted noexec\n",tempdir);
                exit(1);
index bda5c3150d6c798254dd974e7780286971c8f6d7..abf6beae3df1bec14f60943754e54ba9e4d32f16 100644 (file)
@@ -249,7 +249,10 @@ void init_new_thread_signals(void)
                    SIGUSR1, SIGIO, SIGWINCH, SIGVTALRM, -1);
        signal(SIGHUP, SIG_IGN);
 
-       init_irq_signals(1);
+       set_handler(SIGIO, (__sighandler_t) sig_handler,
+                   SA_ONSTACK | SA_RESTART, SIGUSR1, SIGIO, SIGWINCH, SIGALRM,
+                   SIGVTALRM, -1);
+       signal(SIGWINCH, SIG_IGN);
 }
 
 int run_kernel_thread(int (*fn)(void *), void *arg, jmp_buf **jmp_ptr)
index a32ba6ab12112e3c6379d55588e538560512fb28..830fe6a1518ae71dfa4deef46727b6fd367fbb18 100644 (file)
@@ -8,47 +8,41 @@
 #include <string.h>
 #include <sys/ptrace.h>
 #include "sysdep/ptrace.h"
-#include "user.h"
 
-/* This is set once at boot time and not changed thereafter */
-
-static unsigned long exec_regs[MAX_REG_NR];
-
-void init_thread_registers(struct uml_pt_regs *to)
-{
-       memcpy(to->gp, exec_regs, sizeof(to->gp));
-}
-
-void save_registers(int pid, struct uml_pt_regs *regs)
+int save_registers(int pid, struct uml_pt_regs *regs)
 {
        int err;
 
        err = ptrace(PTRACE_GETREGS, pid, 0, regs->gp);
        if (err < 0)
-               panic("save_registers - saving registers failed, errno = %d\n",
-                     errno);
+               return -errno;
+       return 0;
 }
 
-void restore_registers(int pid, struct uml_pt_regs *regs)
+int restore_registers(int pid, struct uml_pt_regs *regs)
 {
        int err;
 
        err = ptrace(PTRACE_SETREGS, pid, 0, regs->gp);
        if (err < 0)
-               panic("restore_registers - saving registers failed, "
-                     "errno = %d\n", errno);
+               return -errno;
+       return 0;
 }
 
-void init_registers(int pid)
+/* This is set once at boot time and not changed thereafter */
+
+static unsigned long exec_regs[MAX_REG_NR];
+
+int init_registers(int pid)
 {
        int err;
 
        err = ptrace(PTRACE_GETREGS, pid, 0, exec_regs);
-       if (err)
-               panic("check_ptrace : PTRACE_GETREGS failed, errno = %d",
-                     errno);
+       if (err < 0)
+               return -errno;
 
        arch_init_registers(pid);
+       return 0;
 }
 
 void get_safe_registers(unsigned long *regs)
index dc03e9cccb630146c0d62504d5ff4ea5e2c14b50..abf47a7c4abd795c039f4c98136163819adb92a4 100644 (file)
@@ -1,34 +1,33 @@
 /*
- * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
  * Licensed under the GPL
  */
 
 #include <unistd.h>
-#include <stdlib.h>
-#include <termios.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <poll.h>
 #include <pty.h>
+#include <sched.h>
 #include <signal.h>
-#include <fcntl.h>
-#include <errno.h>
 #include <string.h>
-#include <sched.h>
-#include <sys/socket.h>
-#include <sys/poll.h>
-#include "init.h"
-#include "user.h"
+#include "kern_constants.h"
 #include "kern_util.h"
-#include "sigio.h"
+#include "init.h"
 #include "os.h"
+#include "sigio.h"
 #include "um_malloc.h"
-#include "init.h"
+#include "user.h"
 
-/* Protected by sigio_lock(), also used by sigio_cleanup, which is an
+/*
+ * Protected by sigio_lock(), also used by sigio_cleanup, which is an
  * exitcall.
  */
 static int write_sigio_pid = -1;
 static unsigned long write_sigio_stack;
 
-/* These arrays are initialized before the sigio thread is started, and
+/*
+ * These arrays are initialized before the sigio thread is started, and
  * the descriptors closed after it is killed.  So, it can't see them change.
  * On the UML side, they are changed under the sigio_lock.
  */
@@ -43,7 +42,8 @@ struct pollfds {
        int used;
 };
 
-/* Protected by sigio_lock().  Used by the sigio thread, but the UML thread
+/*
+ * Protected by sigio_lock().  Used by the sigio thread, but the UML thread
  * synchronizes with it.
  */
 static struct pollfds current_poll;
@@ -57,23 +57,26 @@ static int write_sigio_thread(void *unused)
        int i, n, respond_fd;
        char c;
 
-        signal(SIGWINCH, SIG_IGN);
+       signal(SIGWINCH, SIG_IGN);
        fds = &current_poll;
-       while(1){
+       while (1) {
                n = poll(fds->poll, fds->used, -1);
-               if(n < 0){
-                       if(errno == EINTR) continue;
-                       printk("write_sigio_thread : poll returned %d, "
-                              "errno = %d\n", n, errno);
+               if (n < 0) {
+                       if (errno == EINTR)
+                               continue;
+                       printk(UM_KERN_ERR "write_sigio_thread : poll returned "
+                              "%d, errno = %d\n", n, errno);
                }
-               for(i = 0; i < fds->used; i++){
+               for (i = 0; i < fds->used; i++) {
                        p = &fds->poll[i];
-                       if(p->revents == 0) continue;
-                       if(p->fd == sigio_private[1]){
+                       if (p->revents == 0)
+                               continue;
+                       if (p->fd == sigio_private[1]) {
                                CATCH_EINTR(n = read(sigio_private[1], &c,
                                                     sizeof(c)));
-                               if(n != sizeof(c))
-                                       printk("write_sigio_thread : "
+                               if (n != sizeof(c))
+                                       printk(UM_KERN_ERR
+                                              "write_sigio_thread : "
                                               "read on socket failed, "
                                               "err = %d\n", errno);
                                tmp = current_poll;
@@ -89,9 +92,10 @@ static int write_sigio_thread(void *unused)
                        }
 
                        CATCH_EINTR(n = write(respond_fd, &c, sizeof(c)));
-                       if(n != sizeof(c))
-                               printk("write_sigio_thread : write on socket "
-                                      "failed, err = %d\n", errno);
+                       if (n != sizeof(c))
+                               printk(UM_KERN_ERR "write_sigio_thread : "
+                                      "write on socket failed, err = %d\n",
+                                      errno);
                }
        }
 
@@ -102,12 +106,13 @@ static int need_poll(struct pollfds *polls, int n)
 {
        struct pollfd *new;
 
-       if(n <= polls->size)
+       if (n <= polls->size)
                return 0;
 
        new = kmalloc(n * sizeof(struct pollfd), UM_GFP_ATOMIC);
-       if(new == NULL){
-               printk("need_poll : failed to allocate new pollfds\n");
+       if (new == NULL) {
+               printk(UM_KERN_ERR "need_poll : failed to allocate new "
+                      "pollfds\n");
                return -ENOMEM;
        }
 
@@ -119,7 +124,8 @@ static int need_poll(struct pollfds *polls, int n)
        return 0;
 }
 
-/* Must be called with sigio_lock held, because it's needed by the marked
+/*
+ * Must be called with sigio_lock held, because it's needed by the marked
  * critical section.
  */
 static void update_thread(void)
@@ -129,15 +135,17 @@ static void update_thread(void)
        char c;
 
        flags = set_signals(0);
-       n = write(sigio_private[0], &c, sizeof(c));
-       if(n != sizeof(c)){
-               printk("update_thread : write failed, err = %d\n", errno);
+       CATCH_EINTR(n = write(sigio_private[0], &c, sizeof(c)));
+       if (n != sizeof(c)) {
+               printk(UM_KERN_ERR "update_thread : write failed, err = %d\n",
+                      errno);
                goto fail;
        }
 
        CATCH_EINTR(n = read(sigio_private[0], &c, sizeof(c)));
-       if(n != sizeof(c)){
-               printk("update_thread : read failed, err = %d\n", errno);
+       if (n != sizeof(c)) {
+               printk(UM_KERN_ERR "update_thread : read failed, err = %d\n",
+                      errno);
                goto fail;
        }
 
@@ -164,23 +172,23 @@ int add_sigio_fd(int fd)
        int err = 0, i, n;
 
        sigio_lock();
-       for(i = 0; i < all_sigio_fds.used; i++){
-               if(all_sigio_fds.poll[i].fd == fd)
+       for (i = 0; i < all_sigio_fds.used; i++) {
+               if (all_sigio_fds.poll[i].fd == fd)
                        break;
        }
-       if(i == all_sigio_fds.used)
+       if (i == all_sigio_fds.used)
                goto out;
 
        p = &all_sigio_fds.poll[i];
 
-       for(i = 0; i < current_poll.used; i++){
-               if(current_poll.poll[i].fd == fd)
+       for (i = 0; i < current_poll.used; i++) {
+               if (current_poll.poll[i].fd == fd)
                        goto out;
        }
 
        n = current_poll.used;
        err = need_poll(&next_poll, n + 1);
-       if(err)
+       if (err)
                goto out;
 
        memcpy(next_poll.poll, current_poll.poll,
@@ -198,27 +206,29 @@ int ignore_sigio_fd(int fd)
        struct pollfd *p;
        int err = 0, i, n = 0;
 
-       /* This is called from exitcalls elsewhere in UML - if
+       /*
+        * This is called from exitcalls elsewhere in UML - if
         * sigio_cleanup has already run, then update_thread will hang
         * or fail because the thread is no longer running.
         */
-       if(write_sigio_pid == -1)
+       if (write_sigio_pid == -1)
                return -EIO;
 
        sigio_lock();
-       for(i = 0; i < current_poll.used; i++){
-               if(current_poll.poll[i].fd == fd) break;
+       for (i = 0; i < current_poll.used; i++) {
+               if (current_poll.poll[i].fd == fd)
+                       break;
        }
-       if(i == current_poll.used)
+       if (i == current_poll.used)
                goto out;
 
        err = need_poll(&next_poll, current_poll.used - 1);
-       if(err)
+       if (err)
                goto out;
 
-       for(i = 0; i < current_poll.used; i++){
+       for (i = 0; i < current_poll.used; i++) {
                p = &current_poll.poll[i];
-               if(p->fd != fd)
+               if (p->fd != fd)
                        next_poll.poll[n++] = *p;
        }
        next_poll.used = current_poll.used - 1;
@@ -235,7 +245,8 @@ static struct pollfd *setup_initial_poll(int fd)
 
        p = kmalloc(sizeof(struct pollfd), UM_GFP_KERNEL);
        if (p == NULL) {
-               printk("setup_initial_poll : failed to allocate poll\n");
+               printk(UM_KERN_ERR "setup_initial_poll : failed to allocate "
+                      "poll\n");
                return NULL;
        }
        *p = ((struct pollfd) { .fd             = fd,
@@ -261,27 +272,29 @@ static void write_sigio_workaround(void)
                return;
 
        err = os_pipe(l_write_sigio_fds, 1, 1);
-       if(err < 0){
-               printk("write_sigio_workaround - os_pipe 1 failed, "
+       if (err < 0) {
+               printk(UM_KERN_ERR "write_sigio_workaround - os_pipe 1 failed, "
                       "err = %d\n", -err);
                return;
        }
        err = os_pipe(l_sigio_private, 1, 1);
-       if(err < 0){
-               printk("write_sigio_workaround - os_pipe 2 failed, "
+       if (err < 0) {
+               printk(UM_KERN_ERR "write_sigio_workaround - os_pipe 2 failed, "
                       "err = %d\n", -err);
                goto out_close1;
        }
 
        p = setup_initial_poll(l_sigio_private[1]);
-       if(!p)
+       if (!p)
                goto out_close2;
 
        sigio_lock();
 
-       /* Did we race? Don't try to optimize this, please, it's not so likely
-        * to happen, and no more than once at the boot. */
-       if(write_sigio_pid != -1)
+       /*
+        * Did we race? Don't try to optimize this, please, it's not so likely
+        * to happen, and no more than once at the boot.
+        */
+       if (write_sigio_pid != -1)
                goto out_free;
 
        current_poll = ((struct pollfds) { .poll        = p,
@@ -333,19 +346,19 @@ void maybe_sigio_broken(int fd, int read)
 {
        int err;
 
-       if(!isatty(fd))
+       if (!isatty(fd))
                return;
 
-       if((read || pty_output_sigio) && (!read || pty_close_sigio))
+       if ((read || pty_output_sigio) && (!read || pty_close_sigio))
                return;
 
        write_sigio_workaround();
 
        sigio_lock();
        err = need_poll(&all_sigio_fds, all_sigio_fds.used + 1);
-       if(err){
-               printk("maybe_sigio_broken - failed to add pollfd for "
-                      "descriptor %d\n", fd);
+       if (err) {
+               printk(UM_KERN_ERR "maybe_sigio_broken - failed to add pollfd "
+                      "for descriptor %d\n", fd);
                goto out;
        }
 
@@ -388,7 +401,7 @@ static void openpty_cb(void *arg)
        struct openpty_arg *info = arg;
 
        info->err = 0;
-       if(openpty(&info->master, &info->slave, NULL, NULL, NULL))
+       if (openpty(&info->master, &info->slave, NULL, NULL, NULL))
                info->err = -errno;
 }
 
@@ -397,17 +410,17 @@ static int async_pty(int master, int slave)
        int flags;
 
        flags = fcntl(master, F_GETFL);
-       if(flags < 0)
+       if (flags < 0)
                return -errno;
 
-       if((fcntl(master, F_SETFL, flags | O_NONBLOCK | O_ASYNC) < 0) ||
-          (fcntl(master, F_SETOWN, os_getpid()) < 0))
+       if ((fcntl(master, F_SETFL, flags | O_NONBLOCK | O_ASYNC) < 0) ||
+           (fcntl(master, F_SETOWN, os_getpid()) < 0))
                return -errno;
 
-       if((fcntl(slave, F_SETFL, flags | O_NONBLOCK) < 0))
+       if ((fcntl(slave, F_SETFL, flags | O_NONBLOCK) < 0))
                return -errno;
 
-       return(0);
+       return 0;
 }
 
 static void __init check_one_sigio(void (*proc)(int, int))
@@ -417,34 +430,49 @@ static void __init check_one_sigio(void (*proc)(int, int))
        int master, slave, err;
 
        initial_thread_cb(openpty_cb, &pty);
-       if(pty.err){
-               printk("openpty failed, errno = %d\n", -pty.err);
+       if (pty.err) {
+               printk(UM_KERN_ERR "check_one_sigio failed, errno = %d\n",
+                      -pty.err);
                return;
        }
 
        master = pty.master;
        slave = pty.slave;
 
-       if((master == -1) || (slave == -1)){
-               printk("openpty failed to allocate a pty\n");
+       if ((master == -1) || (slave == -1)) {
+               printk(UM_KERN_ERR "check_one_sigio failed to allocate a "
+                      "pty\n");
                return;
        }
 
        /* Not now, but complain so we now where we failed. */
        err = raw(master);
-       if (err < 0)
-               panic("check_sigio : __raw failed, errno = %d\n", -err);
+       if (err < 0) {
+               printk(UM_KERN_ERR "check_one_sigio : raw failed, errno = %d\n",
+                     -err);
+               return;
+       }
 
        err = async_pty(master, slave);
-       if(err < 0)
-               panic("tty_fds : sigio_async failed, err = %d\n", -err);
+       if (err < 0) {
+               printk(UM_KERN_ERR "check_one_sigio : sigio_async failed, "
+                      "err = %d\n", -err);
+               return;
+       }
+
+       if (sigaction(SIGIO, NULL, &old) < 0) {
+               printk(UM_KERN_ERR "check_one_sigio : sigaction 1 failed, "
+                      "errno = %d\n", errno);
+               return;
+       }
 
-       if(sigaction(SIGIO, NULL, &old) < 0)
-               panic("check_sigio : sigaction 1 failed, errno = %d\n", errno);
        new = old;
        new.sa_handler = handler;
-       if(sigaction(SIGIO, &new, NULL) < 0)
-               panic("check_sigio : sigaction 2 failed, errno = %d\n", errno);
+       if (sigaction(SIGIO, &new, NULL) < 0) {
+               printk(UM_KERN_ERR "check_one_sigio : sigaction 2 failed, "
+                      "errno = %d\n", errno);
+               return;
+       }
 
        got_sigio = 0;
        (*proc)(master, slave);
@@ -452,8 +480,9 @@ static void __init check_one_sigio(void (*proc)(int, int))
        close(master);
        close(slave);
 
-       if(sigaction(SIGIO, &old, NULL) < 0)
-               panic("check_sigio : sigaction 3 failed, errno = %d\n", errno);
+       if (sigaction(SIGIO, &old, NULL) < 0)
+               printk(UM_KERN_ERR "check_one_sigio : sigaction 3 failed, "
+                      "errno = %d\n", errno);
 }
 
 static void tty_output(int master, int slave)
@@ -461,42 +490,45 @@ static void tty_output(int master, int slave)
        int n;
        char buf[512];
 
-       printk("Checking that host ptys support output SIGIO...");
+       printk(UM_KERN_INFO "Checking that host ptys support output SIGIO...");
 
        memset(buf, 0, sizeof(buf));
 
-       while(write(master, buf, sizeof(buf)) > 0) ;
-       if(errno != EAGAIN)
-               panic("tty_output : write failed, errno = %d\n", errno);
-       while(((n = read(slave, buf, sizeof(buf))) > 0) && !got_sigio) ;
+       while (write(master, buf, sizeof(buf)) > 0) ;
+       if (errno != EAGAIN)
+               printk(UM_KERN_ERR "tty_output : write failed, errno = %d\n",
+                      errno);
+       while (((n = read(slave, buf, sizeof(buf))) > 0) && !got_sigio)
+               ;
 
-       if(got_sigio){
-               printk("Yes\n");
+       if (got_sigio) {
+               printk(UM_KERN_CONT "Yes\n");
                pty_output_sigio = 1;
-       }
-       else if(n == -EAGAIN)
-               printk("No, enabling workaround\n");
-       else panic("tty_output : read failed, err = %d\n", n);
+       } else if (n == -EAGAIN)
+               printk(UM_KERN_CONT "No, enabling workaround\n");
+       else
+               printk(UM_KERN_CONT "tty_output : read failed, err = %d\n", n);
 }
 
 static void tty_close(int master, int slave)
 {
-       printk("Checking that host ptys support SIGIO on close...");
+       printk(UM_KERN_INFO "Checking that host ptys support SIGIO on "
+              "close...");
 
        close(slave);
-       if(got_sigio){
-               printk("Yes\n");
+       if (got_sigio) {
+               printk(UM_KERN_CONT "Yes\n");
                pty_close_sigio = 1;
-       }
-       else printk("No, enabling workaround\n");
+       } else
+               printk(UM_KERN_CONT "No, enabling workaround\n");
 }
 
 void __init check_sigio(void)
 {
-       if((os_access("/dev/ptmx", OS_ACC_R_OK) < 0) &&
-          (os_access("/dev/ptyp0", OS_ACC_R_OK) < 0)){
-               printk("No pseudo-terminals available - skipping pty SIGIO "
-                      "check\n");
+       if ((access("/dev/ptmx", R_OK) < 0) &&
+           (access("/dev/ptyp0", R_OK) < 0)) {
+               printk(UM_KERN_WARNING "No pseudo-terminals available - "
+                      "skipping pty SIGIO check\n");
                return;
        }
        check_one_sigio(tty_output);
index e9800b0b5689b6abc750606ab886826709964e56..0fb0cc8d47577c34d842a25a75f2e477dfc6d2c3 100644 (file)
@@ -9,11 +9,47 @@
 #include <errno.h>
 #include <signal.h>
 #include <strings.h>
+#include "as-layout.h"
+#include "kern_util.h"
 #include "os.h"
 #include "sysdep/barrier.h"
 #include "sysdep/sigcontext.h"
 #include "user.h"
 
+/* Copied from linux/compiler-gcc.h since we can't include it directly */
+#define barrier() __asm__ __volatile__("": : :"memory")
+
+void (*sig_info[NSIG])(int, struct uml_pt_regs *) = {
+       [SIGTRAP]       = relay_signal,
+       [SIGFPE]        = relay_signal,
+       [SIGILL]        = relay_signal,
+       [SIGWINCH]      = winch,
+       [SIGBUS]        = bus_handler,
+       [SIGSEGV]       = segv_handler,
+       [SIGIO]         = sigio_handler,
+       [SIGVTALRM]     = timer_handler };
+
+static void sig_handler_common(int sig, struct sigcontext *sc)
+{
+       struct uml_pt_regs r;
+       int save_errno = errno;
+
+       r.is_user = 0;
+       if (sig == SIGSEGV) {
+               /* For segfaults, we want the data from the sigcontext. */
+               copy_sc(&r, sc);
+               GET_FAULTINFO_FROM_SC(r.faultinfo, sc);
+       }
+
+       /* enable signals if sig isn't IRQ signal */
+       if ((sig != SIGIO) && (sig != SIGWINCH) && (sig != SIGVTALRM))
+               unblock_signals();
+
+       (*sig_info[sig])(sig, &r);
+
+       errno = save_errno;
+}
+
 /*
  * These are the asynchronous signals.  SIGPROF is excluded because we want to
  * be able to profile all of UML, not just the non-critical sections.  If
 #define SIGVTALRM_BIT 1
 #define SIGVTALRM_MASK (1 << SIGVTALRM_BIT)
 
-/*
- * These are used by both the signal handlers and
- * block/unblock_signals.  I don't want modifications cached in a
- * register - they must go straight to memory.
- */
-static volatile int signals_enabled = 1;
-static volatile int pending = 0;
+static int signals_enabled;
+static unsigned int signals_pending;
 
 void sig_handler(int sig, struct sigcontext *sc)
 {
@@ -40,13 +71,13 @@ void sig_handler(int sig, struct sigcontext *sc)
 
        enabled = signals_enabled;
        if (!enabled && (sig == SIGIO)) {
-               pending |= SIGIO_MASK;
+               signals_pending |= SIGIO_MASK;
                return;
        }
 
        block_signals();
 
-       sig_handler_common_skas(sig, sc);
+       sig_handler_common(sig, sc);
 
        set_signals(enabled);
 }
@@ -68,7 +99,7 @@ void alarm_handler(int sig, struct sigcontext *sc)
 
        enabled = signals_enabled;
        if (!signals_enabled) {
-               pending |= SIGVTALRM_MASK;
+               signals_pending |= SIGVTALRM_MASK;
                return;
        }
 
@@ -94,16 +125,6 @@ void set_sigstack(void *sig_stack, int size)
                panic("enabling signal stack failed, errno = %d\n", errno);
 }
 
-void remove_sigstack(void)
-{
-       stack_t stack = ((stack_t) { .ss_flags  = SS_DISABLE,
-                                    .ss_sp     = NULL,
-                                    .ss_size   = 0 });
-
-       if (sigaltstack(&stack, NULL) != 0)
-               panic("disabling signal stack failed, errno = %d\n", errno);
-}
-
 void (*handlers[_NSIG])(int sig, struct sigcontext *sc);
 
 void handle_signal(int sig, struct sigcontext *sc)
@@ -166,6 +187,9 @@ void set_handler(int sig, void (*handler)(int), int flags, ...)
                sigaddset(&action.sa_mask, mask);
        va_end(ap);
 
+       if (sig == SIGSEGV)
+               flags |= SA_NODEFER;
+
        action.sa_flags = flags;
        action.sa_restorer = NULL;
        if (sigaction(sig, &action, NULL) < 0)
@@ -179,12 +203,14 @@ void set_handler(int sig, void (*handler)(int), int flags, ...)
 
 int change_sig(int signal, int on)
 {
-       sigset_t sigset, old;
+       sigset_t sigset;
 
        sigemptyset(&sigset);
        sigaddset(&sigset, signal);
-       sigprocmask(on ? SIG_UNBLOCK : SIG_BLOCK, &sigset, &old);
-       return !sigismember(&old, signal);
+       if (sigprocmask(on ? SIG_UNBLOCK : SIG_BLOCK, &sigset, NULL) < 0)
+               return -errno;
+
+       return 0;
 }
 
 void block_signals(void)
@@ -196,7 +222,7 @@ void block_signals(void)
         * This might matter if gcc figures out how to inline this and
         * decides to shuffle this code into the caller.
         */
-       mb();
+       barrier();
 }
 
 void unblock_signals(void)
@@ -209,36 +235,26 @@ void unblock_signals(void)
        /*
         * We loop because the IRQ handler returns with interrupts off.  So,
         * interrupts may have arrived and we need to re-enable them and
-        * recheck pending.
+        * recheck signals_pending.
         */
        while(1) {
                /*
                 * Save and reset save_pending after enabling signals.  This
-                * way, pending won't be changed while we're reading it.
+                * way, signals_pending won't be changed while we're reading it.
                 */
                signals_enabled = 1;
 
                /*
-                * Setting signals_enabled and reading pending must
+                * Setting signals_enabled and reading signals_pending must
                 * happen in this order.
                 */
-               mb();
-
-               save_pending = pending;
-               if (save_pending == 0) {
-                       /*
-                        * This must return with signals enabled, so
-                        * this barrier ensures that writes are
-                        * flushed out before the return.  This might
-                        * matter if gcc figures out how to inline
-                        * this (unlikely, given its size) and decides
-                        * to shuffle this code into the caller.
-                        */
-                       mb();
+               barrier();
+
+               save_pending = signals_pending;
+               if (save_pending == 0)
                        return;
-               }
 
-               pending = 0;
+               signals_pending = 0;
 
                /*
                 * We have pending interrupts, so disable signals, as the
@@ -254,7 +270,7 @@ void unblock_signals(void)
                 * back here.
                 */
                if (save_pending & SIGIO_MASK)
-                       sig_handler_common_skas(SIGIO, NULL);
+                       sig_handler_common(SIGIO, NULL);
 
                if (save_pending & SIGVTALRM_MASK)
                        real_alarm_handler(NULL);
index 5fd8d4dad66a123501d9aff333d9bef809bba881..d2ea3409e072e9818c3f643aa4b312caf351861d 100644 (file)
@@ -1,10 +1,10 @@
 #
-# Copyright (C) 2002 - 2004 Jeff Dike (jdike@addtoit.com)
+# Copyright (C) 2002 - 2007 Jeff Dike (jdike@{linux.intel,addtoit}.com)
 # Licensed under the GPL
 #
 
-obj-y := mem.o process.o trap.o
+obj-y := mem.o process.o
 
-USER_OBJS := mem.o process.o trap.o
+USER_OBJS := $(obj-y)
 
 include arch/um/scripts/Makefile.rules
index e8b7a97e83d3eb8d75785b6a44e29492ae81efcf..d36c89c24a45c5df05a652f88dc26901577bb19b 100644 (file)
@@ -15,6 +15,7 @@
 #include "as-layout.h"
 #include "chan_user.h"
 #include "kern_constants.h"
+#include "kern_util.h"
 #include "mem.h"
 #include "os.h"
 #include "process.h"
@@ -37,27 +38,27 @@ int is_skas_winch(int pid, int fd, void *data)
 
 static int ptrace_dump_regs(int pid)
 {
-        unsigned long regs[MAX_REG_NR];
-        int i;
+       unsigned long regs[MAX_REG_NR];
+       int i;
 
-        if (ptrace(PTRACE_GETREGS, pid, 0, regs) < 0)
-                return -errno;
+       if (ptrace(PTRACE_GETREGS, pid, 0, regs) < 0)
+               return -errno;
 
        printk(UM_KERN_ERR "Stub registers -\n");
        for (i = 0; i < ARRAY_SIZE(regs); i++)
                printk(UM_KERN_ERR "\t%d - %lx\n", i, regs[i]);
 
-        return 0;
+       return 0;
 }
 
 /*
  * Signals that are OK to receive in the stub - we'll just continue it.
  * SIGWINCH will happen when UML is inside a detached screen.
  */
-#define STUB_SIG_MASK ((1 << SIGVTALRM) | (1 << SIGWINCH))
+#define STUB_SIG_MASK (1 << SIGVTALRM)
 
 /* Signals that the stub will finish with - anything else is an error */
-#define STUB_DONE_MASK ((1 << SIGUSR1) | (1 << SIGTRAP))
+#define STUB_DONE_MASK (1 << SIGTRAP)
 
 void wait_stub_done(int pid)
 {
@@ -72,9 +73,11 @@ void wait_stub_done(int pid)
                        break;
 
                err = ptrace(PTRACE_CONT, pid, 0, 0);
-               if (err)
-                       panic("wait_stub_done : continue failed, errno = %d\n",
-                             errno);
+               if (err) {
+                       printk(UM_KERN_ERR "wait_stub_done : continue failed, "
+                              "errno = %d\n", errno);
+                       fatal_sigsegv();
+               }
        }
 
        if (((1 << WSTOPSIG(status)) & STUB_DONE_MASK) != 0)
@@ -85,8 +88,10 @@ bad_wait:
        if (err)
                printk(UM_KERN_ERR "Failed to get registers from stub, "
                       "errno = %d\n", -err);
-       panic("wait_stub_done : failed to wait for SIGUSR1/SIGTRAP, pid = %d, "
-             "n = %d, errno = %d, status = 0x%x\n", pid, n, errno, status);
+       printk(UM_KERN_ERR "wait_stub_done : failed to wait for SIGTRAP, "
+              "pid = %d, n = %d, errno = %d, status = 0x%x\n", pid, n, errno,
+              status);
+       fatal_sigsegv();
 }
 
 extern unsigned long current_stub_stack(void);
@@ -97,9 +102,11 @@ void get_skas_faultinfo(int pid, struct faultinfo * fi)
 
        if (ptrace_faultinfo) {
                err = ptrace(PTRACE_FAULTINFO, pid, 0, fi);
-               if (err)
-                       panic("get_skas_faultinfo - PTRACE_FAULTINFO failed, "
-                             "errno = %d\n", errno);
+               if (err) {
+                       printk(UM_KERN_ERR "get_skas_faultinfo - "
+                              "PTRACE_FAULTINFO failed, errno = %d\n", errno);
+                       fatal_sigsegv();
+               }
 
                /* Special handling for i386, which has different structs */
                if (sizeof(struct ptrace_faultinfo) < sizeof(struct faultinfo))
@@ -109,9 +116,11 @@ void get_skas_faultinfo(int pid, struct faultinfo * fi)
        }
        else {
                err = ptrace(PTRACE_CONT, pid, 0, SIGSEGV);
-               if (err)
-                       panic("Failed to continue stub, pid = %d, errno = %d\n",
-                             pid, errno);
+               if (err) {
+                       printk(UM_KERN_ERR "Failed to continue stub, pid = %d, "
+                              "errno = %d\n", pid, errno);
+                       fatal_sigsegv();
+               }
                wait_stub_done(pid);
 
                /*
@@ -137,6 +146,9 @@ static void handle_trap(int pid, struct uml_pt_regs *regs,
 {
        int err, status;
 
+       if ((UPT_IP(regs) >= STUB_START) && (UPT_IP(regs) < STUB_END))
+               fatal_sigsegv();
+
        /* Mark this as a syscall */
        UPT_SYSCALL_NR(regs) = PT_SYSCALL_NR(regs->gp);
 
@@ -144,25 +156,31 @@ static void handle_trap(int pid, struct uml_pt_regs *regs,
        {
                err = ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_NR_OFFSET,
                             __NR_getpid);
-               if (err < 0)
-                       panic("handle_trap - nullifying syscall failed, "
-                             "errno = %d\n", errno);
+               if (err < 0) {
+                       printk(UM_KERN_ERR "handle_trap - nullifying syscall "
+                              "failed, errno = %d\n", errno);
+                       fatal_sigsegv();
+               }
 
                err = ptrace(PTRACE_SYSCALL, pid, 0, 0);
-               if (err < 0)
-                       panic("handle_trap - continuing to end of syscall "
-                             "failed, errno = %d\n", errno);
+               if (err < 0) {
+                       printk(UM_KERN_ERR "handle_trap - continuing to end of "
+                              "syscall failed, errno = %d\n", errno);
+                       fatal_sigsegv();
+               }
 
                CATCH_EINTR(err = waitpid(pid, &status, WUNTRACED | __WALL));
                if ((err < 0) || !WIFSTOPPED(status) ||
-                  (WSTOPSIG(status) != SIGTRAP + 0x80)) {
-                        err = ptrace_dump_regs(pid);
-                        if (err)
-                                printk(UM_KERN_ERR "Failed to get registers "
+                   (WSTOPSIG(status) != SIGTRAP + 0x80)) {
+                       err = ptrace_dump_regs(pid);
+                       if (err)
+                               printk(UM_KERN_ERR "Failed to get registers "
                                       "from process, errno = %d\n", -err);
-                       panic("handle_trap - failed to wait at end of syscall, "
-                             "errno = %d, status = %d\n", errno, status);
-                }
+                       printk(UM_KERN_ERR "handle_trap - failed to wait at "
+                              "end of syscall, errno = %d, status = %d\n",
+                              errno, status);
+                       fatal_sigsegv();
+               }
        }
 
        handle_syscall(regs);
@@ -178,10 +196,13 @@ static int userspace_tramp(void *stack)
        ptrace(PTRACE_TRACEME, 0, 0, 0);
 
        signal(SIGTERM, SIG_DFL);
+       signal(SIGWINCH, SIG_IGN);
        err = set_interval();
-       if (err)
-               panic("userspace_tramp - setting timer failed, errno = %d\n",
-                     err);
+       if (err) {
+               printk(UM_KERN_ERR "userspace_tramp - setting timer failed, "
+                      "errno = %d\n", err);
+               exit(1);
+       }
 
        if (!proc_mm) {
                /*
@@ -221,16 +242,14 @@ static int userspace_tramp(void *stack)
 
                set_sigstack((void *) STUB_DATA, UM_KERN_PAGE_SIZE);
                sigemptyset(&sa.sa_mask);
-               sigaddset(&sa.sa_mask, SIGIO);
-               sigaddset(&sa.sa_mask, SIGWINCH);
-               sigaddset(&sa.sa_mask, SIGVTALRM);
-               sigaddset(&sa.sa_mask, SIGUSR1);
-               sa.sa_flags = SA_ONSTACK;
+               sa.sa_flags = SA_ONSTACK | SA_NODEFER;
                sa.sa_handler = (void *) v;
                sa.sa_restorer = NULL;
-               if (sigaction(SIGSEGV, &sa, NULL) < 0)
-                       panic("userspace_tramp - setting SIGSEGV handler "
-                             "failed - errno = %d\n", errno);
+               if (sigaction(SIGSEGV, &sa, NULL) < 0) {
+                       printk(UM_KERN_ERR "userspace_tramp - setting SIGSEGV "
+                              "handler failed - errno = %d\n", errno);
+                       exit(1);
+               }
        }
 
        kill(os_getpid(), SIGSTOP);
@@ -246,13 +265,18 @@ int start_userspace(unsigned long stub_stack)
 {
        void *stack;
        unsigned long sp;
-       int pid, status, n, flags;
+       int pid, status, n, flags, err;
 
        stack = mmap(NULL, UM_KERN_PAGE_SIZE,
                     PROT_READ | PROT_WRITE | PROT_EXEC,
                     MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
-       if (stack == MAP_FAILED)
-               panic("start_userspace : mmap failed, errno = %d", errno);
+       if (stack == MAP_FAILED) {
+               err = -errno;
+               printk(UM_KERN_ERR "start_userspace : mmap failed, "
+                      "errno = %d\n", errno);
+               return err;
+       }
+
        sp = (unsigned long) stack + UM_KERN_PAGE_SIZE - sizeof(void *);
 
        flags = CLONE_FILES;
@@ -262,29 +286,50 @@ int start_userspace(unsigned long stub_stack)
                flags |= SIGCHLD;
 
        pid = clone(userspace_tramp, (void *) sp, flags, (void *) stub_stack);
-       if (pid < 0)
-               panic("start_userspace : clone failed, errno = %d", errno);
+       if (pid < 0) {
+               err = -errno;
+               printk(UM_KERN_ERR "start_userspace : clone failed, "
+                      "errno = %d\n", errno);
+               return err;
+       }
 
        do {
                CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED | __WALL));
-               if (n < 0)
-                       panic("start_userspace : wait failed, errno = %d",
-                             errno);
+               if (n < 0) {
+                       err = -errno;
+                       printk(UM_KERN_ERR "start_userspace : wait failed, "
+                              "errno = %d\n", errno);
+                       goto out_kill;
+               }
        } while (WIFSTOPPED(status) && (WSTOPSIG(status) == SIGVTALRM));
 
-       if (!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP))
-               panic("start_userspace : expected SIGSTOP, got status = %d",
-                     status);
+       if (!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP)) {
+               err = -EINVAL;
+               printk(UM_KERN_ERR "start_userspace : expected SIGSTOP, got "
+                      "status = %d\n", status);
+               goto out_kill;
+       }
 
        if (ptrace(PTRACE_OLDSETOPTIONS, pid, NULL,
-                  (void *) PTRACE_O_TRACESYSGOOD) < 0)
-               panic("start_userspace : PTRACE_OLDSETOPTIONS failed, "
-                     "errno = %d\n", errno);
+                  (void *) PTRACE_O_TRACESYSGOOD) < 0) {
+               err = -errno;
+               printk(UM_KERN_ERR "start_userspace : PTRACE_OLDSETOPTIONS "
+                      "failed, errno = %d\n", errno);
+               goto out_kill;
+       }
 
-       if (munmap(stack, UM_KERN_PAGE_SIZE) < 0)
-               panic("start_userspace : munmap failed, errno = %d\n", errno);
+       if (munmap(stack, UM_KERN_PAGE_SIZE) < 0) {
+               err = -errno;
+               printk(UM_KERN_ERR "start_userspace : munmap failed, "
+                      "errno = %d\n", errno);
+               goto out_kill;
+       }
 
        return pid;
+
+ out_kill:
+       os_kill_ptraced_process(pid, 1);
+       return err;
 }
 
 void userspace(struct uml_pt_regs *regs)
@@ -302,7 +347,16 @@ void userspace(struct uml_pt_regs *regs)
        nsecs += os_nsecs();
 
        while (1) {
-               restore_registers(pid, regs);
+               /*
+                * This can legitimately fail if the process loads a
+                * bogus value into a segment register.  It will
+                * segfault and PTRACE_GETREGS will read that value
+                * out of the process.  However, PTRACE_SETREGS will
+                * fail.  In this case, there is nothing to do but
+                * just kill the process.
+                */
+               if (ptrace(PTRACE_SETREGS, pid, 0, regs->gp))
+                       fatal_sigsegv();
 
                /* Now we set local_using_sysemu to be used for one loop */
                local_using_sysemu = get_using_sysemu();
@@ -310,19 +364,26 @@ void userspace(struct uml_pt_regs *regs)
                op = SELECT_PTRACE_OPERATION(local_using_sysemu,
                                             singlestepping(NULL));
 
-               err = ptrace(op, pid, 0, 0);
-               if (err)
-                       panic("userspace - could not resume userspace process, "
-                             "pid=%d, ptrace operation = %d, errno = %d\n",
-                             pid, op, errno);
+               if (ptrace(op, pid, 0, 0)) {
+                       printk(UM_KERN_ERR "userspace - ptrace continue "
+                              "failed, op = %d, errno = %d\n", op, errno);
+                       fatal_sigsegv();
+               }
 
                CATCH_EINTR(err = waitpid(pid, &status, WUNTRACED | __WALL));
-               if (err < 0)
-                       panic("userspace - waitpid failed, errno = %d\n",
-                             errno);
+               if (err < 0) {
+                       printk(UM_KERN_ERR "userspace - wait failed, "
+                              "errno = %d\n", errno);
+                       fatal_sigsegv();
+               }
 
                regs->is_user = 1;
-               save_registers(pid, regs);
+               if (ptrace(PTRACE_GETREGS, pid, 0, regs->gp)) {
+                       printk(UM_KERN_ERR "userspace - PTRACE_GETREGS failed, "
+                              "errno = %d\n", errno);
+                       fatal_sigsegv();
+               }
+
                UPT_SYSCALL_NR(regs) = -1; /* Assume: It's not a syscall */
 
                if (WIFSTOPPED(status)) {
@@ -345,7 +406,7 @@ void userspace(struct uml_pt_regs *regs)
                                break;
                        case SIGVTALRM:
                                now = os_nsecs();
-                               if(now < nsecs)
+                               if (now < nsecs)
                                        break;
                                block_signals();
                                (*sig_info[sig])(sig, regs);
@@ -368,6 +429,7 @@ void userspace(struct uml_pt_regs *regs)
                        default:
                                printk(UM_KERN_ERR "userspace - child stopped "
                                       "with signal %d\n", sig);
+                               fatal_sigsegv();
                        }
                        pid = userspace_pid[0];
                        interrupt_end();
@@ -419,9 +481,12 @@ int copy_context_skas0(unsigned long new_stack, int pid)
                                                     .it_interval = tv }) });
 
        err = ptrace_setregs(pid, thread_regs);
-       if (err < 0)
-               panic("copy_context_skas0 : PTRACE_SETREGS failed, "
-                     "pid = %d, errno = %d\n", pid, -err);
+       if (err < 0) {
+               err = -errno;
+               printk(UM_KERN_ERR "copy_context_skas0 : PTRACE_SETREGS "
+                      "failed, pid = %d, errno = %d\n", pid, -err);
+               return err;
+       }
 
        /* set a well known return code for detection of child write failure */
        child_data->err = 12345678;
@@ -431,31 +496,47 @@ int copy_context_skas0(unsigned long new_stack, int pid)
         * parent's stack, and check, if bad result.
         */
        err = ptrace(PTRACE_CONT, pid, 0, 0);
-       if (err)
-               panic("Failed to continue new process, pid = %d, "
-                     "errno = %d\n", pid, errno);
+       if (err) {
+               err = -errno;
+               printk(UM_KERN_ERR "Failed to continue new process, pid = %d, "
+                      "errno = %d\n", pid, errno);
+               return err;
+       }
+
        wait_stub_done(pid);
 
        pid = data->err;
-       if (pid < 0)
-               panic("copy_context_skas0 - stub-parent reports error %d\n",
-                     -pid);
+       if (pid < 0) {
+               printk(UM_KERN_ERR "copy_context_skas0 - stub-parent reports "
+                      "error %d\n", -pid);
+               return pid;
+       }
 
        /*
         * Wait, until child has finished too: read child's result from
         * child's stack and check it.
         */
        wait_stub_done(pid);
-       if (child_data->err != STUB_DATA)
-               panic("copy_context_skas0 - stub-child reports error %ld\n",
-                     child_data->err);
+       if (child_data->err != STUB_DATA) {
+               printk(UM_KERN_ERR "copy_context_skas0 - stub-child reports "
+                      "error %ld\n", child_data->err);
+               err = child_data->err;
+               goto out_kill;
+       }
 
        if (ptrace(PTRACE_OLDSETOPTIONS, pid, NULL,
-                  (void *)PTRACE_O_TRACESYSGOOD) < 0)
-               panic("copy_context_skas0 : PTRACE_OLDSETOPTIONS failed, "
-                     "errno = %d\n", errno);
+                  (void *)PTRACE_O_TRACESYSGOOD) < 0) {
+               err = -errno;
+               printk(UM_KERN_ERR "copy_context_skas0 : PTRACE_OLDSETOPTIONS "
+                      "failed, errno = %d\n", errno);
+               goto out_kill;
+       }
 
        return pid;
+
+ out_kill:
+       os_kill_ptraced_process(pid, 1);
+       return err;
 }
 
 /*
@@ -463,8 +544,8 @@ int copy_context_skas0(unsigned long new_stack, int pid)
  * available. Opening /proc/mm creates a new mm_context, which lacks
  * the stub-pages. Thus, we map them using /proc/mm-fd
  */
-void map_stub_pages(int fd, unsigned long code,
-                   unsigned long data, unsigned long stack)
+int map_stub_pages(int fd, unsigned long code, unsigned long data,
+                  unsigned long stack)
 {
        struct proc_mm_op mmop;
        int n;
@@ -488,8 +569,9 @@ void map_stub_pages(int fd, unsigned long code,
                printk(UM_KERN_ERR "mmap args - addr = 0x%lx, fd = %d, "
                       "offset = %llx\n", code, code_fd,
                       (unsigned long long) code_offset);
-               panic("map_stub_pages : /proc/mm map for code failed, "
-                     "err = %d\n", n);
+               printk(UM_KERN_ERR "map_stub_pages : /proc/mm map for code "
+                      "failed, err = %d\n", n);
+               return -n;
        }
 
        if (stack) {
@@ -507,10 +589,15 @@ void map_stub_pages(int fd, unsigned long code,
                                      .offset  = map_offset
                } } });
                CATCH_EINTR(n = write(fd, &mmop, sizeof(mmop)));
-               if (n != sizeof(mmop))
-                       panic("map_stub_pages : /proc/mm map for data failed, "
-                             "err = %d\n", errno);
+               if (n != sizeof(mmop)) {
+                       n = errno;
+                       printk(UM_KERN_ERR "map_stub_pages : /proc/mm map for "
+                              "data failed, err = %d\n", n);
+                       return -n;
+               }
        }
+
+       return 0;
 }
 
 void new_thread(void *stack, jmp_buf *buf, void (*handler)(void))
@@ -571,7 +658,9 @@ int start_idle_thread(void *stack, jmp_buf *switch_buf)
                kmalloc_ok = 0;
                return 1;
        default:
-               panic("Bad sigsetjmp return in start_idle_thread - %d\n", n);
+               printk(UM_KERN_ERR "Bad sigsetjmp return in "
+                      "start_idle_thread - %d\n", n);
+               fatal_sigsegv();
        }
        longjmp(*switch_buf, 1);
 }
@@ -614,9 +703,11 @@ void __switch_mm(struct mm_id *mm_idp)
        if (proc_mm) {
                err = ptrace(PTRACE_SWITCH_MM, userspace_pid[0], 0,
                             mm_idp->u.mm_fd);
-               if (err)
-                       panic("__switch_mm - PTRACE_SWITCH_MM failed, "
-                             "errno = %d\n", errno);
+               if (err) {
+                       printk(UM_KERN_ERR "__switch_mm - PTRACE_SWITCH_MM "
+                              "failed, errno = %d\n", errno);
+                       fatal_sigsegv();
+               }
        }
        else userspace_pid[0] = mm_idp->u.pid;
 }
diff --git a/arch/um/os-Linux/skas/trap.c b/arch/um/os-Linux/skas/trap.c
deleted file mode 100644 (file)
index 3b1b924..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
- * Licensed under the GPL
- */
-
-#if 0
-#include "kern_util.h"
-#include "skas.h"
-#include "ptrace_user.h"
-#include "sysdep/ptrace_user.h"
-#endif
-
-#include <errno.h>
-#include <signal.h>
-#include "sysdep/ptrace.h"
-#include "kern_constants.h"
-#include "as-layout.h"
-#include "os.h"
-#include "sigcontext.h"
-#include "task.h"
-
-static struct uml_pt_regs ksig_regs[UM_NR_CPUS];
-
-void sig_handler_common_skas(int sig, void *sc_ptr)
-{
-       struct sigcontext *sc = sc_ptr;
-       struct uml_pt_regs *r;
-       void (*handler)(int, struct uml_pt_regs *);
-       int save_user, save_errno = errno;
-
-       /*
-        * This is done because to allow SIGSEGV to be delivered inside a SEGV
-        * handler.  This can happen in copy_user, and if SEGV is disabled,
-        * the process will die.
-        * XXX Figure out why this is better than SA_NODEFER
-        */
-       if (sig == SIGSEGV) {
-               change_sig(SIGSEGV, 1);
-               /*
-                * For segfaults, we want the data from the
-                * sigcontext.  In this case, we don't want to mangle
-                * the process registers, so use a static set of
-                * registers.  For other signals, the process
-                * registers are OK.
-                */
-               r = &ksig_regs[cpu()];
-               copy_sc(r, sc_ptr);
-       }
-       else r = TASK_REGS(get_current());
-
-       save_user = r->is_user;
-       r->is_user = 0;
-       if ((sig == SIGFPE) || (sig == SIGSEGV) || (sig == SIGBUS) ||
-           (sig == SIGILL) || (sig == SIGTRAP))
-               GET_FAULTINFO_FROM_SC(r->faultinfo, sc);
-
-       change_sig(SIGUSR1, 1);
-
-       handler = sig_info[sig];
-
-       /* unblock SIGVTALRM, SIGIO if sig isn't IRQ signal */
-       if ((sig != SIGIO) && (sig != SIGWINCH) && (sig != SIGVTALRM))
-               unblock_signals();
-
-       handler(sig, r);
-
-       errno = save_errno;
-       r->is_user = save_user;
-}
index 7b81f6c08a5eddda2aaab95ac4df4f5fd729f88a..b616e15638fbc8c1aa5a8bdf710862715124de42 100644 (file)
@@ -60,10 +60,11 @@ static int ptrace_child(void)
                 * the UML code itself.
                 */
                ret = 2;
-       _exit(ret);
+
+       exit(ret);
 }
 
-static void fatal_perror(char *str)
+static void fatal_perror(const char *str)
 {
        perror(str);
        exit(1);
@@ -341,6 +342,8 @@ static void __init check_coredump_limit(void)
 
 void __init os_early_checks(void)
 {
+       int pid;
+
        /* Print out the core dump limits early */
        check_coredump_limit();
 
@@ -350,6 +353,11 @@ void __init os_early_checks(void)
         * kernel is running.
         */
        check_tmpexec();
+
+       pid = start_ptraced_child();
+       if (init_registers(pid))
+               fatal("Failed to initialize default registers");
+       stop_ptraced_child(pid, 1, 1);
 }
 
 static int __init noprocmm_cmd_param(char *str, int* add)
@@ -411,7 +419,6 @@ static inline void check_skas3_ptrace_faultinfo(void)
                        non_fatal("found\n");
        }
 
-       init_registers(pid);
        stop_ptraced_child(pid, 1, 1);
 }
 
@@ -466,7 +473,7 @@ static inline void check_skas3_proc_mm(void)
        else non_fatal("found\n");
 }
 
-int can_do_skas(void)
+void can_do_skas(void)
 {
        non_fatal("Checking for the skas3 patch in the host:\n");
 
@@ -476,8 +483,6 @@ int can_do_skas(void)
 
        if (!proc_mm || !ptrace_faultinfo || !ptrace_ldt)
                skas_needs_stub = 1;
-
-       return 1;
 }
 
 int __init parse_iomem(char *str, int *add)
diff --git a/arch/um/os-Linux/trap.c b/arch/um/os-Linux/trap.c
deleted file mode 100644 (file)
index 2a1c984..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
- * Licensed under the GPL
- */
-
-#include <signal.h>
-#include "os.h"
-#include "sysdep/ptrace.h"
-
-/* Initialized from linux_main() */
-void (*sig_info[NSIG])(int, struct uml_pt_regs *);
-
-void os_fill_handlinfo(struct kern_handlers h)
-{
-       sig_info[SIGTRAP] = h.relay_signal;
-       sig_info[SIGFPE] = h.relay_signal;
-       sig_info[SIGILL] = h.relay_signal;
-       sig_info[SIGWINCH] = h.winch;
-       sig_info[SIGBUS] = h.bus_handler;
-       sig_info[SIGSEGV] = h.page_fault;
-       sig_info[SIGIO] = h.sigio_handler;
-       sig_info[SIGVTALRM] = h.timer_handler;
-}
index 4cfdd18ea1efdd383e44405a4ddcf98642f0c43d..b09ff66a77eeaf7578d84df8839e2a2961813cd3 100644 (file)
@@ -1,13 +1,16 @@
-/* 
- * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+/*
+ * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
  * Licensed under the GPL
  */
 
 #include <stdlib.h>
+#include <unistd.h>
 #include <errno.h>
+#include <fcntl.h>
+#include "kern_constants.h"
+#include "kern_util.h"
 #include "os.h"
 #include "user.h"
-#include "kern_util.h"
 
 struct grantpt_info {
        int fd;
@@ -26,36 +29,34 @@ static void grantpt_cb(void *arg)
 int get_pty(void)
 {
        struct grantpt_info info;
-       int fd;
-
-       fd = os_open_file("/dev/ptmx", of_rdwr(OPENFLAGS()), 0);
-       if(fd < 0){
-               printk("get_pty : Couldn't open /dev/ptmx - err = %d\n", -fd);
-               return(fd);
+       int fd, err;
+
+       fd = open("/dev/ptmx", O_RDWR);
+       if (fd < 0) {
+               err = -errno;
+               printk(UM_KERN_ERR "get_pty : Couldn't open /dev/ptmx - "
+                      "err = %d\n", errno);
+               return err;
        }
 
        info.fd = fd;
        initial_thread_cb(grantpt_cb, &info);
 
-       if(info.res < 0){
-               printk("get_pty : Couldn't grant pty - errno = %d\n", 
-                      -info.err);
-               return(-1);
+       if (info.res < 0) {
+               err = -info.err;
+               printk(UM_KERN_ERR "get_pty : Couldn't grant pty - "
+                      "errno = %d\n", -info.err);
+               goto out;
        }
-       if(unlockpt(fd) < 0){
-               printk("get_pty : Couldn't unlock pty - errno = %d\n", errno);
-               return(-1);
+
+       if (unlockpt(fd) < 0) {
+               err = -errno;
+               printk(UM_KERN_ERR "get_pty : Couldn't unlock pty - "
+                      "errno = %d\n", errno);
+               goto out;
        }
-       return(fd);
+       return fd;
+out:
+       close(fd);
+       return err;
 }
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
index d11a55baa6bd59800860bd0acc822adf89b7ef6b..cc648e6fd3a2c1ecaa92196eeee145b65cc8c47f 100644 (file)
@@ -12,7 +12,6 @@
 #include <sys/time.h>
 #include "init.h"
 #include "user.h"
-#include "kern_util.h"
 #include "os.h"
 
 #define TTY_LOG_DIR "./"
index 3e058ce9ffb6cd044a8fbf5ff33883b46b649348..a6f31d476993cd0314c8c6adbf9dad0c7c796f15 100644 (file)
@@ -88,21 +88,6 @@ void setup_hostinfo(char *buf, int len)
                 host.release, host.version, host.machine);
 }
 
-int setjmp_wrapper(void (*proc)(void *, void *), ...)
-{
-       va_list args;
-       jmp_buf buf;
-       int n;
-
-       n = UML_SETJMP(&buf);
-       if(n == 0){
-               va_start(args, proc);
-               (*proc)(&buf, &args);
-       }
-       va_end(args);
-       return n;
-}
-
 void os_dump_core(void)
 {
        int pid;
index a4360b5207db9e6c2e49676522c168942ff5b7f2..8d4f273f1219b0aaab6d3fc24769d7dddb5ec4c4 100644 (file)
@@ -4,6 +4,7 @@
  */
 
 #include <linux/uaccess.h>
+#include <asm/errno.h>
 
 /* Mostly copied from i386/x86_86 - eliminated the eip < PAGE_OFFSET because
  * that's not relevant in skas mode.
index 806895d73bcc1d9eec6495457c03ba2715f81871..a74442d1376213bc5ad41bf3eb11772a743cdeaa 100644 (file)
  * Licensed under the GPL
  */
 
-#include <errno.h>
 #include <signal.h>
-#include <string.h>
 #include "kern_constants.h"
-#include "os.h"
+#include "kern_util.h"
+#include "longjmp.h"
 #include "task.h"
 #include "user.h"
-
-#define MAXTOKEN 64
+#include "sysdep/ptrace.h"
 
 /* Set during early boot */
 int host_has_cmov = 1;
-int host_has_xmm = 0;
+static jmp_buf cmov_test_return;
 
-static char token(int fd, char *buf, int len, char stop)
+static void cmov_sigill_test_handler(int sig)
 {
-       int n;
-       char *ptr, *end, c;
-
-       ptr = buf;
-       end = &buf[len];
-       do {
-               n = os_read_file(fd, ptr, sizeof(*ptr));
-               c = *ptr++;
-               if (n != sizeof(*ptr)) {
-                       if (n == 0)
-                               return 0;
-                       printk(UM_KERN_ERR "Reading /proc/cpuinfo failed, "
-                              "err = %d\n", -n);
-                       if (n < 0)
-                               return n;
-                       else return -EIO;
-               }
-       } while ((c != '\n') && (c != stop) && (ptr < end));
-
-       if (ptr == end) {
-               printk(UM_KERN_ERR "Failed to find '%c' in /proc/cpuinfo\n",
-                      stop);
-               return -1;
-       }
-       *(ptr - 1) = '\0';
-       return c;
-}
-
-static int find_cpuinfo_line(int fd, char *key, char *scratch, int len)
-{
-       int n;
-       char c;
-
-       scratch[len - 1] = '\0';
-       while (1) {
-               c = token(fd, scratch, len - 1, ':');
-               if (c <= 0)
-                       return 0;
-               else if (c != ':') {
-                       printk(UM_KERN_ERR "Failed to find ':' in "
-                              "/proc/cpuinfo\n");
-                       return 0;
-               }
-
-               if (!strncmp(scratch, key, strlen(key)))
-                       return 1;
-
-               do {
-                       n = os_read_file(fd, &c, sizeof(c));
-                       if (n != sizeof(c)) {
-                               printk(UM_KERN_ERR "Failed to find newline in "
-                                      "/proc/cpuinfo, err = %d\n", -n);
-                               return 0;
-                       }
-               } while (c != '\n');
-       }
-       return 0;
+       host_has_cmov = 0;
+       longjmp(cmov_test_return, 1);
 }
 
-static int check_cpu_flag(char *feature, int *have_it)
-{
-       char buf[MAXTOKEN], c;
-       int fd, len = ARRAY_SIZE(buf);
-
-       printk(UM_KERN_INFO "Checking for host processor %s support...",
-              feature);
-       fd = os_open_file("/proc/cpuinfo", of_read(OPENFLAGS()), 0);
-       if (fd < 0) {
-               printk(UM_KERN_ERR "Couldn't open /proc/cpuinfo, err = %d\n",
-                      -fd);
-               return 0;
-       }
-
-       *have_it = 0;
-       if (!find_cpuinfo_line(fd, "flags", buf, ARRAY_SIZE(buf)))
-               goto out;
-
-       c = token(fd, buf, len - 1, ' ');
-       if (c < 0)
-               goto out;
-       else if (c != ' ') {
-               printk(UM_KERN_ERR "Failed to find ' ' in /proc/cpuinfo\n");
-               goto out;
-       }
-
-       while (1) {
-               c = token(fd, buf, len - 1, ' ');
-               if (c < 0)
-                       goto out;
-               else if (c == '\n')
-                       break;
-
-               if (!strcmp(buf, feature)) {
-                       *have_it = 1;
-                       goto out;
-               }
-       }
- out:
-       if (*have_it == 0)
-               printk("No\n");
-       else if (*have_it == 1)
-               printk("Yes\n");
-       os_close_file(fd);
-       return 1;
-}
-
-#if 0 /*
-       * This doesn't work in tt mode, plus it's causing compilation problems
-       * for some people.
-       */
-static void disable_lcall(void)
+void arch_check_bugs(void)
 {
-       struct modify_ldt_ldt_s ldt;
-       int err;
+       struct sigaction old, new;
 
-       bzero(&ldt, sizeof(ldt));
-       ldt.entry_number = 7;
-       ldt.base_addr = 0;
-       ldt.limit = 0;
-       err = modify_ldt(1, &ldt, sizeof(ldt));
-       if (err)
-               printk(UM_KERN_ERR "Failed to disable lcall7 - errno = %d\n",
-                      errno);
-}
-#endif
+       printk(UM_KERN_INFO "Checking for host processor cmov support...");
+       new.sa_handler = cmov_sigill_test_handler;
 
-void arch_init_thread(void)
-{
-#if 0
-       disable_lcall();
-#endif
-}
+       /* Make sure that SIGILL is enabled after the handler longjmps back */
+       new.sa_flags = SA_NODEFER;
+       sigemptyset(&new.sa_mask);
+       sigaction(SIGILL, &new, &old);
 
-void arch_check_bugs(void)
-{
-       int have_it;
+       if (setjmp(cmov_test_return) == 0) {
+               unsigned long foo = 0;
+               __asm__ __volatile__("cmovz %0, %1" : "=r" (foo) : "0" (foo));
+               printk(UM_KERN_CONT "Yes\n");
+       } else
+               printk(UM_KERN_CONT "No\n");
 
-       if (os_access("/proc/cpuinfo", OS_ACC_R_OK) < 0) {
-               printk(UM_KERN_ERR "/proc/cpuinfo not available - skipping CPU "
-                      "capability checks\n");
-               return;
-       }
-       if (check_cpu_flag("cmov", &have_it))
-               host_has_cmov = have_it;
-       if (check_cpu_flag("xmm", &have_it))
-               host_has_xmm = have_it;
+       sigaction(SIGILL, &old, &new);
 }
 
-int arch_handle_signal(int sig, struct uml_pt_regs *regs)
+void arch_examine_signal(int sig, struct uml_pt_regs *regs)
 {
        unsigned char tmp[2];
 
@@ -176,24 +52,25 @@ int arch_handle_signal(int sig, struct uml_pt_regs *regs)
         * SIGILL in init.
         */
        if ((sig != SIGILL) || (TASK_PID(get_current()) != 1))
-               return 0;
+               return;
+
+       if (copy_from_user_proc(tmp, (void *) UPT_IP(regs), 2)) {
+               printk(UM_KERN_ERR "SIGILL in init, could not read "
+                      "instructions!\n");
+               return;
+       }
 
-       if (copy_from_user_proc(tmp, (void *) UPT_IP(regs), 2))
-               panic("SIGILL in init, could not read instructions!\n");
        if ((tmp[0] != 0x0f) || ((tmp[1] & 0xf0) != 0x40))
-               return 0;
+               return;
 
        if (host_has_cmov == 0)
-               panic("SIGILL caused by cmov, which this processor doesn't "
-                     "implement, boot a filesystem compiled for older "
-                     "processors");
+               printk(UM_KERN_ERR "SIGILL caused by cmov, which this "
+                      "processor doesn't implement.  Boot a filesystem "
+                      "compiled for older processors");
        else if (host_has_cmov == 1)
-               panic("SIGILL caused by cmov, which this processor claims to "
-                     "implement");
-       else if (host_has_cmov == -1)
-               panic("SIGILL caused by cmov, couldn't tell if this processor "
-                     "implements it, boot a filesystem compiled for older "
-                     "processors");
-       else panic("Bad value for host_has_cmov (%d)", host_has_cmov);
-       return 0;
+               printk(UM_KERN_ERR "SIGILL caused by cmov, which this "
+                      "processor claims to implement");
+       else
+               printk(UM_KERN_ERR "Bad value for host_has_cmov (%d)",
+                       host_has_cmov);
 }
index 67c0958eb984266e7e59eaf682754b3c25746642..a34263e6b08d3cc2cedf5e87ed0083ef05288e0b 100644 (file)
@@ -3,8 +3,9 @@
  * Licensed under the GPL
  */
 
-#include "linux/mm.h"
-#include "asm/unistd.h"
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <asm/unistd.h>
 #include "os.h"
 #include "proc_mm.h"
 #include "skas.h"
@@ -146,7 +147,7 @@ static int read_ldt(void __user * ptr, unsigned long bytecount)
        if (ptrace_ldt)
                return read_ldt_from_host(ptr, bytecount);
 
-       down(&ldt->semaphore);
+       mutex_lock(&ldt->lock);
        if (ldt->entry_count <= LDT_DIRECT_ENTRIES) {
                size = LDT_ENTRY_SIZE*LDT_DIRECT_ENTRIES;
                if (size > bytecount)
@@ -170,7 +171,7 @@ static int read_ldt(void __user * ptr, unsigned long bytecount)
                        ptr += size;
                }
        }
-       up(&ldt->semaphore);
+       mutex_unlock(&ldt->lock);
 
        if (bytecount == 0 || err == -EFAULT)
                goto out;
@@ -228,7 +229,7 @@ static int write_ldt(void __user * ptr, unsigned long bytecount, int func)
        }
 
        if (!ptrace_ldt)
-               down(&ldt->semaphore);
+               mutex_lock(&ldt->lock);
 
        err = write_ldt_entry(mm_idp, func, &ldt_info, &addr, 1);
        if (err)
@@ -288,7 +289,7 @@ static int write_ldt(void __user * ptr, unsigned long bytecount, int func)
        err = 0;
 
 out_unlock:
-       up(&ldt->semaphore);
+       mutex_unlock(&ldt->lock);
 out:
        return err;
 }
@@ -395,7 +396,7 @@ long init_new_ldt(struct mm_context *new_mm, struct mm_context *from_mm)
 
 
        if (!ptrace_ldt)
-               init_MUTEX(&new_mm->ldt.semaphore);
+               mutex_init(&new_mm->ldt.lock);
 
        if (!from_mm) {
                memset(&desc, 0, sizeof(desc));
@@ -455,7 +456,7 @@ long init_new_ldt(struct mm_context *new_mm, struct mm_context *from_mm)
                 * i.e., we have to use the stub for modify_ldt, which
                 * can't handle the big read buffer of up to 64kB.
                 */
-               down(&from_mm->ldt.semaphore);
+               mutex_lock(&from_mm->ldt.lock);
                if (from_mm->ldt.entry_count <= LDT_DIRECT_ENTRIES)
                        memcpy(new_mm->ldt.u.entries, from_mm->ldt.u.entries,
                               sizeof(new_mm->ldt.u.entries));
@@ -474,7 +475,7 @@ long init_new_ldt(struct mm_context *new_mm, struct mm_context *from_mm)
                        }
                }
                new_mm->ldt.entry_count = from_mm->ldt.entry_count;
-               up(&from_mm->ldt.semaphore);
+               mutex_unlock(&from_mm->ldt.lock);
        }
 
     out:
index bd3da8a61f645810bc7af9ec42a6db240379b778..6b4499906a6c96be3139a594681b7c632b8139c1 100644 (file)
@@ -8,11 +8,11 @@
 #include "asm/uaccess.h"
 #include "skas.h"
 
-extern int arch_switch_tls(struct task_struct *from, struct task_struct *to);
+extern int arch_switch_tls(struct task_struct *to);
 
-void arch_switch_to(struct task_struct *from, struct task_struct *to)
+void arch_switch_to(struct task_struct *to)
 {
-       int err = arch_switch_tls(from, to);
+       int err = arch_switch_tls(to);
        if (!err)
                return;
 
index 5cf97bc229b98a7b3e49c2f0ec576c460341d4ba..0b10c3e7402885ae69d471773d554c49b09dc51d 100644 (file)
@@ -19,17 +19,3 @@ int ptrace_setregs(long pid, unsigned long *regs)
                return -errno;
        return 0;
 }
-
-int ptrace_getfpregs(long pid, unsigned long *regs)
-{
-       if (ptrace(PTRACE_GETFPREGS, pid, 0, regs) < 0)
-               return -errno;
-       return 0;
-}
-
-int ptrace_setfpregs(long pid, unsigned long *regs)
-{
-       if (ptrace(PTRACE_SETFPREGS, pid, 0, regs) < 0)
-               return -errno;
-       return 0;
-}
index 19053d46cb60190421d818435af10bac6ce2bbfb..fd0c25ad6af3ecdbd03be96d1a9ee142ec8560e2 100644 (file)
@@ -168,12 +168,13 @@ static int copy_sc_from_user(struct pt_regs *regs,
                             struct sigcontext __user *from)
 {
        struct sigcontext sc;
-       int err;
+       int err, pid;
 
        err = copy_from_user(&sc, from, sizeof(sc));
        if (err)
                return err;
 
+       pid = userspace_pid[current_thread_info()->cpu];
        copy_sc(&regs->regs, &sc);
        if (have_fpx_regs) {
                struct user_fxsr_struct fpx;
@@ -187,8 +188,7 @@ static int copy_sc_from_user(struct pt_regs *regs,
                if (err)
                        return 1;
 
-               err = restore_fpx_registers(userspace_pid[current_thread->cpu],
-                                           (unsigned long *) &fpx);
+               err = restore_fpx_registers(pid, (unsigned long *) &fpx);
                if (err < 0) {
                        printk(KERN_ERR "copy_sc_from_user - "
                               "restore_fpx_registers failed, errno = %d\n",
@@ -204,8 +204,7 @@ static int copy_sc_from_user(struct pt_regs *regs,
                if (err)
                        return 1;
 
-               err = restore_fp_registers(userspace_pid[current_thread->cpu],
-                                          (unsigned long *) &fp);
+               err = restore_fp_registers(pid, (unsigned long *) &fp);
                if (err < 0) {
                        printk(KERN_ERR "copy_sc_from_user - "
                               "restore_fp_registers failed, errno = %d\n",
@@ -223,7 +222,7 @@ static int copy_sc_to_user(struct sigcontext __user *to,
 {
        struct sigcontext sc;
        struct faultinfo * fi = &current->thread.arch.faultinfo;
-       int err;
+       int err, pid;
 
        sc.gs = REGS_GS(regs->regs.gp);
        sc.fs = REGS_FS(regs->regs.gp);
@@ -249,11 +248,11 @@ static int copy_sc_to_user(struct sigcontext __user *to,
        to_fp = (to_fp ? to_fp : (struct _fpstate __user *) (to + 1));
        sc.fpstate = to_fp;
 
+       pid = userspace_pid[current_thread_info()->cpu];
        if (have_fpx_regs) {
                struct user_fxsr_struct fpx;
 
-               err = save_fpx_registers(userspace_pid[current_thread->cpu],
-                                        (unsigned long *) &fpx);
+               err = save_fpx_registers(pid, (unsigned long *) &fpx);
                if (err < 0){
                        printk(KERN_ERR "copy_sc_to_user - save_fpx_registers "
                               "failed, errno = %d\n", err);
@@ -276,8 +275,7 @@ static int copy_sc_to_user(struct sigcontext __user *to,
        else {
                struct user_i387_struct fp;
 
-               err = save_fp_registers(userspace_pid[current_thread->cpu],
-                                       (unsigned long *) &fp);
+               err = save_fp_registers(pid, (unsigned long *) &fp);
                if (copy_to_user(to_fp, &fp, sizeof(struct user_i387_struct)))
                        return 1;
        }
index e730772c401b53206810ceb387aa56b9f4f06cf9..7699e89f660fd42701736ce1bfe79e4d6b2d0ddc 100644 (file)
@@ -7,7 +7,7 @@
        .globl batch_syscall_stub
 batch_syscall_stub:
        /* load pointer to first operation */
-       mov     $(ASM_STUB_DATA+8), %esp
+       mov     $(STUB_DATA+8), %esp
 
 again:
        /* load length of additional data */
@@ -15,12 +15,12 @@ again:
 
        /* if(length == 0) : end of list */
        /* write possible 0 to header */
-       mov     %eax, ASM_STUB_DATA+4
+       mov     %eax, STUB_DATA+4
        cmpl    $0, %eax
        jz      done
 
        /* save current pointer */
-       mov     %esp, ASM_STUB_DATA+4
+       mov     %esp, STUB_DATA+4
 
        /* skip additional data */
        add     %eax, %esp
@@ -46,7 +46,7 @@ again:
 
 done:
        /* save return value */
-       mov     %eax, ASM_STUB_DATA
+       mov     %eax, STUB_DATA
 
        /* stop */
        int3
index b3999cb76bfd2eb004ba5f8be32fec82e38beeeb..28ccf737a79fa9c7364e89fb6c36d3d0608a2f62 100644 (file)
@@ -1,32 +1,17 @@
 /*
- * Copyright (C) 2004 Jeff Dike (jdike@addtoit.com)
+ * Copyright (C) 2004 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
  * Licensed under the GPL
  */
 
-#include <signal.h>
-#include <sys/select.h> /* The only way I can see to get sigset_t */
-#include <asm/unistd.h>
-#include "as-layout.h"
-#include "uml-config.h"
 #include "sysdep/stub.h"
 #include "sysdep/sigcontext.h"
-#include "sysdep/faultinfo.h"
 
 void __attribute__ ((__section__ (".__syscall_stub")))
 stub_segv_handler(int sig)
 {
        struct sigcontext *sc = (struct sigcontext *) (&sig + 1);
-       int pid;
 
        GET_FAULTINFO_FROM_SC(*((struct faultinfo *) STUB_DATA), sc);
 
-       pid = stub_syscall0(__NR_getpid);
-       stub_syscall2(__NR_kill, pid, SIGUSR1);
-
-       /* Load pointer to sigcontext into esp, since we need to leave
-        * the stack in its original form when we do the sigreturn here, by
-        * hand.
-        */
-       __asm__ __volatile__("mov %0,%%esp ; movl %1, %%eax ; "
-                            "int $0x80" : : "a" (sc), "g" (__NR_sigreturn));
+       trap_myself();
 }
index 12d4148dba39aa186aeddcff09be9a8c046a164e..00e5f5203eea337abd3a3e0ee115d6795ab0e4d3 100644 (file)
@@ -9,4 +9,9 @@
 
 #define old_mmap old_mmap_i386
 
+.section .rodata,"a"
+
 #include "../../x86/kernel/syscall_table_32.S"
+
+ENTRY(syscall_table_size)
+.long .-sys_call_table
index fcaff86b000c7397656320d67952821e44c73be2..c6c7131e563bcab77bf69cdfc1ef9160c8c6f9d4 100644 (file)
@@ -26,6 +26,11 @@ int do_set_thread_area(struct user_desc *info)
        cpu = get_cpu();
        ret = os_set_thread_area(info, userspace_pid[cpu]);
        put_cpu();
+
+       if (ret)
+               printk(KERN_ERR "PTRACE_SET_THREAD_AREA failed, err = %d, "
+                      "index = %d\n", ret, info->entry_number);
+
        return ret;
 }
 
@@ -37,6 +42,11 @@ int do_get_thread_area(struct user_desc *info)
        cpu = get_cpu();
        ret = os_get_thread_area(info, userspace_pid[cpu]);
        put_cpu();
+
+       if (ret)
+               printk(KERN_ERR "PTRACE_GET_THREAD_AREA failed, err = %d, "
+                      "index = %d\n", ret, info->entry_number);
+
        return ret;
 }
 
@@ -172,7 +182,7 @@ void clear_flushed_tls(struct task_struct *task)
  * SKAS patch.
  */
 
-int arch_switch_tls(struct task_struct *from, struct task_struct *to)
+int arch_switch_tls(struct task_struct *to)
 {
        if (!host_supports_tls)
                return 0;
@@ -225,7 +235,8 @@ out:
 }
 
 /* XXX: use do_get_thread_area to read the host value? I'm not at all sure! */
-static int get_tls_entry(struct task_struct* task, struct user_desc *info, int idx)
+static int get_tls_entry(struct task_struct *task, struct user_desc *info,
+                        int idx)
 {
        struct thread_struct *t = &task->thread;
 
@@ -263,7 +274,7 @@ clear:
        goto out;
 }
 
-asmlinkage int sys_set_thread_area(struct user_desc __user *user_desc)
+int sys_set_thread_area(struct user_desc __user *user_desc)
 {
        struct user_desc info;
        int idx, ret;
@@ -298,7 +309,7 @@ asmlinkage int sys_set_thread_area(struct user_desc __user *user_desc)
  * i386. However the only possible error are caused by bugs.
  */
 int ptrace_set_thread_area(struct task_struct *child, int idx,
-               struct user_desc __user *user_desc)
+                          struct user_desc __user *user_desc)
 {
        struct user_desc info;
 
@@ -311,7 +322,7 @@ int ptrace_set_thread_area(struct task_struct *child, int idx,
        return set_tls_entry(child, &info, idx, 0);
 }
 
-asmlinkage int sys_get_thread_area(struct user_desc __user *user_desc)
+int sys_get_thread_area(struct user_desc __user *user_desc)
 {
        struct user_desc info;
        int idx, ret;
@@ -355,10 +366,9 @@ out:
        return ret;
 }
 
-
 /*
- * XXX: This part is probably common to i386 and x86-64. Don't create a common
- * file for now, do that when implementing x86-64 support.
+ * This code is really i386-only, but it detects and logs x86_64 GDT indexes
+ * if a 32-bit UML is running on a 64-bit host.
  */
 static int __init __setup_host_supports_tls(void)
 {
@@ -367,13 +377,16 @@ static int __init __setup_host_supports_tls(void)
                printk(KERN_INFO "Host TLS support detected\n");
                printk(KERN_INFO "Detected host type: ");
                switch (host_gdt_entry_tls_min) {
-                       case GDT_ENTRY_TLS_MIN_I386:
-                               printk("i386\n");
-                               break;
-                       case GDT_ENTRY_TLS_MIN_X86_64:
-                               printk("x86_64\n");
-                               break;
+               case GDT_ENTRY_TLS_MIN_I386:
+                       printk(KERN_CONT "i386");
+                       break;
+               case GDT_ENTRY_TLS_MIN_X86_64:
+                       printk(KERN_CONT "x86_64");
+                       break;
                }
+               printk(KERN_CONT " (GDT indexes %d to %d)\n",
+                      host_gdt_entry_tls_min,
+                      host_gdt_entry_tls_min + GDT_ENTRY_TLS_ENTRIES);
        } else
                printk(KERN_ERR "  Host TLS support NOT detected! "
                                "TLS support inside UML will not work\n");
index a9814a7ae60efb1a6690a00b97f0ad01e7850697..08901526e893bda363b59246f8b22b3c3745b697 100644 (file)
@@ -6,7 +6,7 @@ OBJ = built-in.o
 OBJS = ptrace.o sigcontext.o semaphore.o checksum.o miscthings.o misc.o \
        ptrace_user.o sysrq.o
 
-EXTRA_AFLAGS := -DCONFIG_PPC32 -I. -I$(TOPDIR)/arch/ppc/kernel
+EXTRA_AFLAGS := -DCONFIG_PPC32 -I. -I$(srctree)/arch/ppc/kernel
 
 all: $(OBJ)
 
@@ -22,25 +22,25 @@ sigcontext.o: sigcontext.c
 
 semaphore.c:
        rm -f $@
-       ln -s $(TOPDIR)/arch/ppc/kernel/$@ $@
+       ln -s $(srctree)/arch/ppc/kernel/$@ $@
 
 checksum.S:
        rm -f $@
-       ln -s $(TOPDIR)/arch/ppc/lib/$@ $@
+       ln -s $(srctree)/arch/ppc/lib/$@ $@
 
 mk_defs.c:
        rm -f $@
-       ln -s $(TOPDIR)/arch/ppc/kernel/$@ $@
+       ln -s $(srctree)/arch/ppc/kernel/$@ $@
 
 ppc_defs.head:
        rm -f $@
-       ln -s $(TOPDIR)/arch/ppc/kernel/$@ $@
+       ln -s $(srctree)/arch/ppc/kernel/$@ $@
 
 ppc_defs.h: mk_defs.c ppc_defs.head \
-               $(TOPDIR)/include/asm-ppc/mmu.h \
-               $(TOPDIR)/include/asm-ppc/processor.h \
-               $(TOPDIR)/include/asm-ppc/pgtable.h \
-               $(TOPDIR)/include/asm-ppc/ptrace.h
+               $(srctree)/include/asm-ppc/mmu.h \
+               $(srctree)/include/asm-ppc/processor.h \
+               $(srctree)/include/asm-ppc/pgtable.h \
+               $(srctree)/include/asm-ppc/ptrace.h
 #      $(CC) $(CFLAGS) -S mk_defs.c
        cp ppc_defs.head ppc_defs.h
 # for bk, this way we can write to the file even if it's not checked out
@@ -56,13 +56,13 @@ ppc_defs.h: mk_defs.c ppc_defs.head \
 
 checksum.o: checksum.S
        rm -f asm
-       ln -s $(TOPDIR)/include/asm-ppc asm
+       ln -s $(srctree)/include/asm-ppc asm
        $(CC) $(EXTRA_AFLAGS) $(KBUILD_AFLAGS) -D__ASSEMBLY__ -D__UM_PPC__ -c $< -o $*.o
        rm -f asm
 
 misc.o: misc.S ppc_defs.h
        rm -f asm
-       ln -s $(TOPDIR)/include/asm-ppc asm
+       ln -s $(srctree)/include/asm-ppc asm
        $(CC) $(EXTRA_AFLAGS) $(KBUILD_AFLAGS) -D__ASSEMBLY__ -D__UM_PPC__ -c $< -o $*.o
        rm -f asm
 
index a4360b5207db9e6c2e49676522c168942ff5b7f2..e8034e363d83f9be90460494af01787e73c13c77 100644 (file)
@@ -5,7 +5,8 @@
 
 #include <linux/uaccess.h>
 
-/* Mostly copied from i386/x86_86 - eliminated the eip < PAGE_OFFSET because
+/*
+ * Mostly copied from i386/x86_86 - eliminated the eip < PAGE_OFFSET because
  * that's not relevant in skas mode.
  */
 
index 506b6765bbcb917a5b77dcd5ab66e97c46da471f..44e02ba2a2656c54595d50ac315b7a64b5f24a7a 100644 (file)
@@ -6,15 +6,10 @@
 
 #include "sysdep/ptrace.h"
 
-void arch_init_thread(void)
-{
-}
-
 void arch_check_bugs(void)
 {
 }
 
-int arch_handle_signal(int sig, struct uml_pt_regs *regs)
+void arch_examine_signal(int sig, struct uml_pt_regs *regs)
 {
-       return 0;
 }
index b7631b0e9ddc212a12966652925646e996768188..f3458d7d1c5ac4a39d5d8aab4fe94c80bfa593e3 100644 (file)
@@ -5,13 +5,12 @@
  * Licensed under the GPL
  */
 
-#define __FRAME_OFFSETS
-#include <asm/ptrace.h>
+#include <linux/mm.h>
 #include <linux/sched.h>
 #include <linux/errno.h>
-#include <linux/mm.h>
+#define __FRAME_OFFSETS
+#include <asm/ptrace.h>
 #include <asm/uaccess.h>
-#include <asm/elf.h>
 
 /*
  * determines which flags the user has access to.
@@ -24,12 +23,14 @@ int putreg(struct task_struct *child, int regno, unsigned long value)
        unsigned long tmp;
 
 #ifdef TIF_IA32
-       /* Some code in the 64bit emulation may not be 64bit clean.
-          Don't take any chances. */
+       /*
+        * Some code in the 64bit emulation may not be 64bit clean.
+        * Don't take any chances.
+        */
        if (test_tsk_thread_flag(child, TIF_IA32))
                value &= 0xffffffff;
 #endif
-       switch (regno){
+       switch (regno) {
        case FS:
        case GS:
        case DS:
@@ -66,7 +67,7 @@ int poke_user(struct task_struct *child, long addr, long data)
        if (addr < MAX_REG_OFFSET)
                return putreg(child, addr, data);
        else if ((addr >= offsetof(struct user, u_debugreg[0])) &&
-               (addr <= offsetof(struct user, u_debugreg[7]))){
+               (addr <= offsetof(struct user, u_debugreg[7]))) {
                addr -= offsetof(struct user, u_debugreg[0]);
                addr = addr >> 2;
                if ((addr == 4) || (addr == 5))
@@ -108,11 +109,10 @@ int peek_user(struct task_struct *child, long addr, long data)
                return -EIO;
 
        tmp = 0;  /* Default return condition */
-       if (addr < MAX_REG_OFFSET){
+       if (addr < MAX_REG_OFFSET)
                tmp = getreg(child, addr);
-       }
        else if ((addr >= offsetof(struct user, u_debugreg[0])) &&
-               (addr <= offsetof(struct user, u_debugreg[7]))){
+               (addr <= offsetof(struct user, u_debugreg[7]))) {
                addr -= offsetof(struct user, u_debugreg[0]);
                addr = addr >> 2;
                tmp = child->thread.arch.debugregs[addr];
@@ -127,8 +127,9 @@ int is_syscall(unsigned long addr)
        int n;
 
        n = copy_from_user(&instr, (void __user *) addr, sizeof(instr));
-       if (n){
-               /* access_process_vm() grants access to vsyscall and stub,
+       if (n) {
+               /*
+                * access_process_vm() grants access to vsyscall and stub,
                 * while copy_from_user doesn't. Maybe access_process_vm is
                 * slow, but that doesn't matter, since it will be called only
                 * in case of singlestepping, if copy_from_user failed.
@@ -155,7 +156,7 @@ int get_fpregs(struct user_i387_struct __user *buf, struct task_struct *child)
                return err;
 
        n = copy_to_user(buf, fpregs, sizeof(fpregs));
-       if(n > 0)
+       if (n > 0)
                return -EFAULT;
 
        return n;
index b5f9c33e311e1b17bfdaf798365d299d0e9585a1..c57a496d3f5b13d668946067e62b7f0ae0a7663a 100644 (file)
@@ -4,55 +4,19 @@
  * Licensed under the GPL
  */
 
-#include <stddef.h>
 #include <errno.h>
 #include "ptrace_user.h"
-#include "user.h"
-#include "kern_constants.h"
 
 int ptrace_getregs(long pid, unsigned long *regs_out)
 {
-       if(ptrace(PTRACE_GETREGS, pid, 0, regs_out) < 0)
-               return(-errno);
-       return(0);
-}
-
-int ptrace_setregs(long pid, unsigned long *regs)
-{
-       if(ptrace(PTRACE_SETREGS, pid, 0, regs) < 0)
-               return(-errno);
+       if (ptrace(PTRACE_GETREGS, pid, 0, regs_out) < 0)
+               return -errno;
        return(0);
 }
 
-int ptrace_setfpregs(long pid, unsigned long *regs)
+int ptrace_setregs(long pid, unsigned long *regs_out)
 {
-       if (ptrace(PTRACE_SETFPREGS, pid, 0, regs) < 0)
+       if (ptrace(PTRACE_SETREGS, pid, 0, regs_out) < 0)
                return -errno;
-       return 0;
-}
-
-void ptrace_pokeuser(unsigned long addr, unsigned long data)
-{
-       panic("ptrace_pokeuser");
-}
-
-#define DS 184
-#define ES 192
-#define __USER_DS     0x2b
-
-void arch_enter_kernel(void *task, int pid)
-{
-}
-
-void arch_leave_kernel(void *task, int pid)
-{
-#ifdef UM_USER_CS
-        if(ptrace(PTRACE_POKEUSR, pid, CS, UM_USER_CS) < 0)
-                printk("POKEUSR CS failed");
-#endif
-
-        if(ptrace(PTRACE_POKEUSR, pid, DS, __USER_DS) < 0)
-                printk("POKEUSR DS failed");
-        if(ptrace(PTRACE_POKEUSR, pid, ES, __USER_DS) < 0)
-                printk("POKEUSR ES failed");
+       return(0);
 }
index 7457436b433a915c6b41d783417d2a0b40cbd171..1a899a7ed7a643261e8c6bc25d6bccbf201221a8 100644 (file)
@@ -81,7 +81,7 @@ static int copy_sc_from_user(struct pt_regs *regs,
        if (err)
                return 1;
 
-       err = restore_fp_registers(userspace_pid[current_thread->cpu],
+       err = restore_fp_registers(userspace_pid[current_thread_info()->cpu],
                                   (unsigned long *) &fp);
        if (err < 0) {
                printk(KERN_ERR "copy_sc_from_user - "
@@ -112,7 +112,7 @@ static int copy_sc_to_user(struct sigcontext __user *to,
        err |= PUTREG(regs, RSI, to, si);
        err |= PUTREG(regs, RBP, to, bp);
        /*
-        * Must use orignal RSP, which is passed in, rather than what's in
+        * Must use original RSP, which is passed in, rather than what's in
         * the pt_regs, because that's already been updated to point at the
         * signal frame.
         */
@@ -143,7 +143,7 @@ static int copy_sc_to_user(struct sigcontext __user *to,
        if (err)
                return 1;
 
-       err = save_fp_registers(userspace_pid[current_thread->cpu],
+       err = save_fp_registers(userspace_pid[current_thread_info()->cpu],
                                (unsigned long *) &fp);
        if (err < 0) {
                printk(KERN_ERR "copy_sc_from_user - restore_fp_registers "
index 4afe204a6af7acea809aa768facf1c6c11c3eb51..5687687631554dabc7e61719a4a900d8d5f691c1 100644 (file)
@@ -8,18 +8,18 @@ syscall_stub:
        /* We don't have 64-bit constants, so this constructs the address
         * we need.
         */
-       movq    $(ASM_STUB_DATA >> 32), %rbx
+       movq    $(STUB_DATA >> 32), %rbx
        salq    $32, %rbx
-       movq    $(ASM_STUB_DATA & 0xffffffff), %rcx
+       movq    $(STUB_DATA & 0xffffffff), %rcx
        or      %rcx, %rbx
        movq    %rax, (%rbx)
        int3
 
        .globl batch_syscall_stub
 batch_syscall_stub:
-       mov     $(ASM_STUB_DATA >> 32), %rbx
+       mov     $(STUB_DATA >> 32), %rbx
        sal     $32, %rbx
-       mov     $(ASM_STUB_DATA & 0xffffffff), %rax
+       mov     $(STUB_DATA & 0xffffffff), %rax
        or      %rax, %rbx
        /* load pointer to first operation */
        mov     %rbx, %rsp
index 3afb590f007212e2da4e90bad9c8447017b46dd4..ced051afc705c47ad29bcbacc78a0443a064267a 100644 (file)
@@ -1,51 +1,22 @@
 /*
- * Copyright (C) 2004 Jeff Dike (jdike@addtoit.com)
+ * Copyright (C) 2004 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
  * Licensed under the GPL
  */
 
-#include <stddef.h>
 #include <signal.h>
-#include <asm/unistd.h>
 #include "as-layout.h"
-#include "uml-config.h"
-#include "sysdep/sigcontext.h"
-#include "sysdep/faultinfo.h"
 #include "sysdep/stub.h"
-
-/* Copied from sys-x86_64/signal.c - Can't find an equivalent definition
- * in the libc headers anywhere.
- */
-struct rt_sigframe
-{
-       char *pretcode;
-       struct ucontext uc;
-       struct siginfo info;
-};
-
-/* Copied here from <linux/kernel.h> - we're userspace. */
-#define container_of(ptr, type, member) ({                   \
-       const typeof( ((type *)0)->member ) *__mptr = (ptr); \
-       (type *)( (char *)__mptr - offsetof(type,member) );})
+#include "sysdep/faultinfo.h"
+#include "sysdep/sigcontext.h"
 
 void __attribute__ ((__section__ (".__syscall_stub")))
 stub_segv_handler(int sig)
 {
        struct ucontext *uc;
-        int pid;
 
        __asm__ __volatile__("movq %%rdx, %0" : "=g" (uc) :);
        GET_FAULTINFO_FROM_SC(*((struct faultinfo *) STUB_DATA),
                              &uc->uc_mcontext);
-
-       pid = stub_syscall0(__NR_getpid);
-       stub_syscall2(__NR_kill, pid, SIGUSR1);
-
-       /* sys_sigreturn expects that the stack pointer will be 8 bytes into
-        * the signal frame.  So, we use the ucontext pointer, which we know
-        * already, to get the signal frame pointer, and add 8 to that.
-        */
-       __asm__ __volatile__("movq %0, %%rsp; movq %1, %%rax ; syscall": :
-                             "g" ((unsigned long)
-                                  container_of(uc, struct rt_sigframe, uc) + 8),
-                             "g" (__NR_rt_sigreturn));
+       trap_myself();
 }
+
index 71b2ae4ad5de17985ee73b97bc43088f67ef2167..c128eb89700804c62f275077147d8d879146ffa7 100644 (file)
@@ -1,5 +1,7 @@
-/* System call table for UML/x86-64, copied from arch/x86_64/kernel/syscall.c
- * with some changes for UML. */
+/*
+ * System call table for UML/x86-64, copied from arch/x86_64/kernel/syscall.c
+ * with some changes for UML.
+ */
 
 #include <linux/linkage.h>
 #include <linux/sys.h>
 
 #define __NO_STUBS
 
-/* Below you can see, in terms of #define's, the differences between the x86-64
- * and the UML syscall table. */
+/*
+ * Below you can see, in terms of #define's, the differences between the x86-64
+ * and the UML syscall table.
+ */
 
 /* Not going to be implemented by UML, since we have no hardware. */
 #define stub_iopl sys_ni_syscall
 #define sys_ioperm sys_ni_syscall
 
-/* The UML TLS problem. Note that x86_64 does not implement this, so the below
- * is needed only for the ia32 compatibility. */
-/*#define sys_set_thread_area sys_ni_syscall
-#define sys_get_thread_area sys_ni_syscall*/
+/*
+ * The UML TLS problem. Note that x86_64 does not implement this, so the below
+ * is needed only for the ia32 compatibility.
+ */
 
 /* On UML we call it this way ("old" means it's not mmap2) */
 #define sys_mmap old_mmap
-/* On x86-64 sys_uname is actually sys_newuname plus a compatibility trick.
- * See arch/x86_64/kernel/sys_x86_64.c */
+/*
+ * On x86-64 sys_uname is actually sys_newuname plus a compatibility trick.
+ * See arch/x86_64/kernel/sys_x86_64.c
+ */
 #define sys_uname sys_uname64
 
 #define stub_clone sys_clone
@@ -46,8 +52,19 @@ typedef void (*sys_call_ptr_t)(void);
 
 extern void sys_ni_syscall(void);
 
-sys_call_ptr_t sys_call_table[UM_NR_syscall_max+1] __cacheline_aligned = {
-       /* Smells like a like a compiler bug -- it doesn't work when the & below is removed. */
-       [0 ... UM_NR_syscall_max] = &sys_ni_syscall,
+/*
+ * We used to have a trick here which made sure that holes in the
+ * x86_64 table were filled in with sys_ni_syscall, but a comment in
+ * unistd_64.h says that holes aren't allowed, so the trick was
+ * removed.
+ * The trick looked like this
+ *     [0 ... UM_NR_syscall_max] = &sys_ni_syscall
+ * before including unistd_64.h - the later initializations overwrote
+ * the sys_ni_syscall filler.
+ */
+
+sys_call_ptr_t sys_call_table[] __cacheline_aligned = {
 #include <asm-x86/unistd_64.h>
 };
+
+int syscall_table_size = sizeof(sys_call_table);
index 86f6b18410ee9e470159c3b63ab8b0e814cff600..f1199fd34d383db5018f349ab811aaea5eb71197 100644 (file)
@@ -48,7 +48,9 @@ long arch_prctl(struct task_struct *task, int code, unsigned long __user *addr)
        switch (code) {
        case ARCH_SET_FS:
        case ARCH_SET_GS:
-               restore_registers(pid, &current->thread.regs.regs);
+               ret = restore_registers(pid, &current->thread.regs.regs);
+               if (ret)
+                       return ret;
                break;
        case ARCH_GET_FS:
        case ARCH_GET_GS:
@@ -70,10 +72,10 @@ long arch_prctl(struct task_struct *task, int code, unsigned long __user *addr)
        switch (code) {
        case ARCH_SET_FS:
                current->thread.arch.fs = (unsigned long) ptr;
-               save_registers(pid, &current->thread.regs.regs);
+               ret = save_registers(pid, &current->thread.regs.regs);
                break;
        case ARCH_SET_GS:
-               save_registers(pid, &current->thread.regs.regs);
+               ret = save_registers(pid, &current->thread.regs.regs);
                break;
        case ARCH_GET_FS:
                ret = put_user(tmp, addr);
@@ -105,7 +107,7 @@ long sys_clone(unsigned long clone_flags, unsigned long newsp,
        return ret;
 }
 
-void arch_switch_to(struct task_struct *from, struct task_struct *to)
+void arch_switch_to(struct task_struct *to)
 {
        if ((to->thread.arch.fs == 0) || (to->mm == NULL))
                return;
index 765444031819c55ce6c51f92f09e665c57448ccd..f4f82beb350889b3c69531797d8b9db11127eb6f 100644 (file)
@@ -4,32 +4,33 @@
  * Licensed under the GPL
  */
 
-#include "linux/kernel.h"
-#include "linux/utsname.h"
-#include "linux/module.h"
-#include "asm/current.h"
-#include "asm/ptrace.h"
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/utsname.h>
+#include <asm/current.h>
+#include <asm/ptrace.h>
 #include "sysrq.h"
 
-void __show_regs(struct pt_regs * regs)
+void __show_regs(struct pt_regs *regs)
 {
        printk("\n");
        print_modules();
-       printk("Pid: %d, comm: %.20s %s %s\n", task_pid_nr(current),
+       printk(KERN_INFO "Pid: %d, comm: %.20s %s %s\n", task_pid_nr(current),
                current->comm, print_tainted(), init_utsname()->release);
-       printk("RIP: %04lx:[<%016lx>] ", PT_REGS_CS(regs) & 0xffff,
+       printk(KERN_INFO "RIP: %04lx:[<%016lx>]\n", PT_REGS_CS(regs) & 0xffff,
               PT_REGS_RIP(regs));
-       printk("\nRSP: %016lx  EFLAGS: %08lx\n", PT_REGS_RSP(regs),
+       printk(KERN_INFO "RSP: %016lx  EFLAGS: %08lx\n", PT_REGS_RSP(regs),
               PT_REGS_EFLAGS(regs));
-       printk("RAX: %016lx RBX: %016lx RCX: %016lx\n",
+       printk(KERN_INFO "RAX: %016lx RBX: %016lx RCX: %016lx\n",
               PT_REGS_RAX(regs), PT_REGS_RBX(regs), PT_REGS_RCX(regs));
-       printk("RDX: %016lx RSI: %016lx RDI: %016lx\n",
+       printk(KERN_INFO "RDX: %016lx RSI: %016lx RDI: %016lx\n",
               PT_REGS_RDX(regs), PT_REGS_RSI(regs), PT_REGS_RDI(regs));
-       printk("RBP: %016lx R08: %016lx R09: %016lx\n",
+       printk(KERN_INFO "RBP: %016lx R08: %016lx R09: %016lx\n",
               PT_REGS_RBP(regs), PT_REGS_R8(regs), PT_REGS_R9(regs));
-       printk("R10: %016lx R11: %016lx R12: %016lx\n",
+       printk(KERN_INFO "R10: %016lx R11: %016lx R12: %016lx\n",
               PT_REGS_R10(regs), PT_REGS_R11(regs), PT_REGS_R12(regs));
-       printk("R13: %016lx R14: %016lx R15: %016lx\n",
+       printk(KERN_INFO "R13: %016lx R14: %016lx R15: %016lx\n",
               PT_REGS_R13(regs), PT_REGS_R14(regs), PT_REGS_R15(regs));
 }
 
index 8b8eff1bd9775de5c636b67f680ca4b49b95437e..3dead392a415d3abb5421582ac251298fcd99cf3 100644 (file)
@@ -1,7 +1,7 @@
 #include <linux/vmalloc.h>
 #include <linux/moduleloader.h>
 
-/*Copied from i386 arch/i386/kernel/module.c */
+/* Copied from i386 arch/i386/kernel/module.c */
 void *module_alloc(unsigned long size)
 {
        if (size == 0)
@@ -13,7 +13,9 @@ void *module_alloc(unsigned long size)
 void module_free(struct module *mod, void *module_region)
 {
        vfree(module_region);
-       /* FIXME: If module_region == mod->init_region, trim exception
-           table entries. */
+       /*
+        * FIXME: If module_region == mod->init_region, trim exception
+        * table entries.
+        */
 }
 
index b6a50b8b38de2c4edc2fdbc8b30012d772c3b672..ace479ab273ff329cc387ce536e8598f171054b4 100644 (file)
@@ -331,8 +331,6 @@ source "sound/Kconfig"
 
 source "drivers/usb/Kconfig"
 
-source "kernel/Kconfig.instrumentation"
-
 source "arch/v850/Kconfig.debug"
 
 source "security/Kconfig"
index 65b449134cf7b15cbc2bdf66993b813fa6f409f0..434821187cfccf9c34b32f91f3784113b6b741f6 100644 (file)
@@ -18,6 +18,8 @@ config X86_64
 ### Arch settings
 config X86
        def_bool y
+       select HAVE_OPROFILE
+       select HAVE_KPROBES
 
 config GENERIC_LOCKBREAK
        def_bool n
@@ -44,6 +46,9 @@ config LOCKDEP_SUPPORT
 config STACKTRACE_SUPPORT
        def_bool y
 
+config HAVE_LATENCYTOP_SUPPORT
+       def_bool y
+
 config SEMAPHORE_SLEEPERS
        def_bool y
 
@@ -103,12 +108,16 @@ config GENERIC_TIME_VSYSCALL
 config HAVE_SETUP_PER_CPU_AREA
        def_bool X86_64
 
-config ARCH_SUPPORTS_OPROFILE
-       bool
-       default y
-
 select HAVE_KVM
 
+config ARCH_HIBERNATION_POSSIBLE
+       def_bool y
+       depends on !SMP || !X86_VOYAGER
+
+config ARCH_SUSPEND_POSSIBLE
+       def_bool y
+       depends on !X86_VOYAGER
+
 config ZONE_DMA32
        bool
        default X86_64
@@ -193,8 +202,7 @@ config SMP
          Y to "Enhanced Real Time Clock Support", below. The "Advanced Power
          Management" code will be disabled if you say Y here.
 
-         See also the <file:Documentation/smp.txt>,
-         <file:Documentation/i386/IO-APIC.txt>,
+         See also <file:Documentation/i386/IO-APIC.txt>,
          <file:Documentation/nmi_watchdog.txt> and the SMP-HOWTO available at
          <http://www.tldp.org/docs.html#howto>.
 
@@ -298,6 +306,7 @@ config X86_RDC321X
        select M486
        select X86_REBOOTFIXUPS
        select GENERIC_GPIO
+       select LEDS_CLASS
        select LEDS_GPIO
        help
          This option is needed for RDC R-321x system-on-chip, also known
@@ -456,6 +465,9 @@ config CALGARY_IOMMU_ENABLED_BY_DEFAULT
          Calgary anyway, pass 'iommu=calgary' on the kernel command line.
          If unsure, say Y.
 
+config IOMMU_HELPER
+       def_bool (CALGARY_IOMMU || GART_IOMMU)
+
 # need this always selected by IOMMU for the VIA workaround
 config SWIOTLB
        bool
@@ -1366,11 +1378,6 @@ config PCI
          your box. Other bus systems are ISA, EISA, MicroChannel (MCA) or
          VESA. If you have PCI, say Y, otherwise N.
 
-         The PCI-HOWTO, available from
-         <http://www.tldp.org/docs.html#howto>, contains valuable
-         information about which PCI hardware does work under Linux and which
-         doesn't.
-
 choice
        prompt "PCI access mode"
        depends on X86_32 && PCI && !X86_VISWS
@@ -1591,8 +1598,6 @@ source "drivers/firmware/Kconfig"
 
 source "fs/Kconfig"
 
-source "kernel/Kconfig.instrumentation"
-
 source "arch/x86/Kconfig.debug"
 
 source "security/Kconfig"
index da8f4129780bd8d25801eeee7742986ec92dddbc..364865b1b08de8b54625efbf3acb4bb9dbe8089d 100644 (file)
@@ -92,7 +92,6 @@ KBUILD_AFLAGS += $(cfi) $(cfi-sigframe)
 KBUILD_CFLAGS += $(cfi) $(cfi-sigframe)
 
 LDFLAGS := -m elf_$(UTS_MACHINE)
-OBJCOPYFLAGS := -O binary -R .note -R .comment -S
 
 # Speed up the build
 KBUILD_CFLAGS += -pipe
@@ -143,7 +142,7 @@ mcore-$(CONFIG_X86_ES7000)  := arch/x86/mach-default/
 
 # RDC R-321x subarch support
 mflags-$(CONFIG_X86_RDC321X)   := -Iinclude/asm-x86/mach-rdc321x
-mcore-$(CONFIG_X86_RDC321X)    := arch/x86/mach-default
+mcore-$(CONFIG_X86_RDC321X)    := arch/x86/mach-default/
 core-$(CONFIG_X86_RDC321X)     += arch/x86/mach-rdc321x/
 
 # default subarch .h files
index 349b81a39c40b586275a5c8695f058ac80bc162f..f88458e83ef0dabc17229685c3b6089d24b5a660 100644 (file)
@@ -26,7 +26,7 @@ SVGA_MODE := -DSVGA_MODE=NORMAL_VGA
 #RAMDISK := -DRAMDISK=512
 
 targets                := vmlinux.bin setup.bin setup.elf zImage bzImage
-subdir-        := compressed
+subdir-                := compressed
 
 setup-y                += a20.o cmdline.o copy.o cpu.o cpucheck.o edd.o
 setup-y                += header.o main.o mca.o memory.o pm.o pmjump.o
@@ -43,9 +43,17 @@ setup-y              += video-vesa.o
 setup-y                += video-bios.o
 
 targets                += $(setup-y)
-hostprogs-y    := tools/build
+hostprogs-y    := mkcpustr tools/build
 
-HOSTCFLAGS_build.o := $(LINUXINCLUDE)
+HOST_EXTRACFLAGS += $(LINUXINCLUDE)
+
+$(obj)/cpu.o: $(obj)/cpustr.h
+
+quiet_cmd_cpustr = CPUSTR  $@
+      cmd_cpustr = $(obj)/mkcpustr > $@
+targets                += cpustr.h
+$(obj)/cpustr.h: $(obj)/mkcpustr FORCE
+       $(call if_changed,cpustr)
 
 # ---------------------------------------------------------------------------
 
@@ -80,6 +88,7 @@ $(obj)/zImage $(obj)/bzImage: $(obj)/setup.bin \
        $(call if_changed,image)
        @echo 'Kernel: $@ is ready' ' (#'`cat .version`')'
 
+OBJCOPYFLAGS_vmlinux.bin := -O binary -R .note -R .comment -S
 $(obj)/vmlinux.bin: $(obj)/compressed/vmlinux FORCE
        $(call if_changed,objcopy)
 
@@ -90,7 +99,6 @@ $(obj)/setup.elf: $(src)/setup.ld $(SETUP_OBJS) FORCE
        $(call if_changed,ld)
 
 OBJCOPYFLAGS_setup.bin := -O binary
-
 $(obj)/setup.bin: $(obj)/setup.elf FORCE
        $(call if_changed,objcopy)
 
@@ -98,7 +106,7 @@ $(obj)/compressed/vmlinux: FORCE
        $(Q)$(MAKE) $(build)=$(obj)/compressed IMAGE_OFFSET=$(IMAGE_OFFSET) $@
 
 # Set this if you want to pass append arguments to the zdisk/fdimage/isoimage kernel
-FDARGS = 
+FDARGS =
 # Set this if you want an initrd included with the zdisk/fdimage/isoimage kernel
 FDINITRD =
 
index fe24ceabd9095b9d1c0c4c0aac50672e2cc38023..d2b9f3bb87c0575abc28020564b002f8c1965f25 100644 (file)
@@ -22,6 +22,7 @@ $(obj)/vmlinux: $(src)/vmlinux_$(BITS).lds $(obj)/head_$(BITS).o $(obj)/misc.o $
        $(call if_changed,ld)
        @:
 
+OBJCOPYFLAGS_vmlinux.bin := -O binary -R .note -R .comment -S
 $(obj)/vmlinux.bin: vmlinux FORCE
        $(call if_changed,objcopy)
 
index 1ccb38a7f0d2c72610c906bf89d5c142a97e9229..e8657b98c902a0773a1e9861fc4db6349f0bb909 100644 (file)
@@ -80,8 +80,8 @@ startup_32:
 
 #ifdef CONFIG_RELOCATABLE
        movl    %ebp, %ebx
-       addl    $(LARGE_PAGE_SIZE -1), %ebx
-       andl    $LARGE_PAGE_MASK, %ebx
+       addl    $(PMD_PAGE_SIZE -1), %ebx
+       andl    $PMD_PAGE_MASK, %ebx
 #else
        movl    $CONFIG_PHYSICAL_START, %ebx
 #endif
@@ -220,8 +220,8 @@ ENTRY(startup_64)
        /* Start with the delta to where the kernel will run at. */
 #ifdef CONFIG_RELOCATABLE
        leaq    startup_32(%rip) /* - $startup_32 */, %rbp
-       addq    $(LARGE_PAGE_SIZE - 1), %rbp
-       andq    $LARGE_PAGE_MASK, %rbp
+       addq    $(PMD_PAGE_SIZE - 1), %rbp
+       andq    $PMD_PAGE_MASK, %rbp
        movq    %rbp, %rbx
 #else
        movq    $CONFIG_PHYSICAL_START, %rbp
index f6e5b445f45734126152819bf0dcb8e9de7acbfb..7e5c7209f6cc2f0b932c6deb3208b8c4d5583374 100644 (file)
@@ -3,7 +3,7 @@ OUTPUT_ARCH(i386:x86-64)
 ENTRY(startup_64)
 SECTIONS
 {
-       /* Be careful parts of head_64.S assume startup_64 is at
+       /* Be careful parts of head_64.S assume startup_32 is at
         * address 0.
         */
        . = 0;
index 2a5c32da5852a307424a1b5105e60cff63e2d7ce..00e19edd852c60d8cc32a2b009a604938747dd77 100644 (file)
@@ -1,7 +1,7 @@
 /* -*- linux-c -*- ------------------------------------------------------- *
  *
  *   Copyright (C) 1991, 1992 Linus Torvalds
- *   Copyright 2007 rPath, Inc. - All Rights Reserved
+ *   Copyright 2007-2008 rPath, Inc. - All Rights Reserved
  *
  *   This file is part of the Linux kernel, and is made available under
  *   the terms of the GNU General Public License version 2.
@@ -9,7 +9,7 @@
  * ----------------------------------------------------------------------- */
 
 /*
- * arch/i386/boot/cpu.c
+ * arch/x86/boot/cpu.c
  *
  * Check for obligatory CPU features and abort if the features are not
  * present.
@@ -19,6 +19,8 @@
 #include "bitops.h"
 #include <asm/cpufeature.h>
 
+#include "cpustr.h"
+
 static char *cpu_name(int level)
 {
        static char buf[6];
@@ -35,6 +37,7 @@ int validate_cpu(void)
 {
        u32 *err_flags;
        int cpu_level, req_level;
+       const unsigned char *msg_strs;
 
        check_cpu(&cpu_level, &req_level, &err_flags);
 
@@ -51,13 +54,26 @@ int validate_cpu(void)
                puts("This kernel requires the following features "
                     "not present on the CPU:\n");
 
+               msg_strs = (const unsigned char *)x86_cap_strs;
+
                for (i = 0; i < NCAPINTS; i++) {
                        u32 e = err_flags[i];
 
                        for (j = 0; j < 32; j++) {
-                               if (e & 1)
-                                       printf("%d:%d ", i, j);
-
+                               int n = (i << 5)+j;
+                               if (*msg_strs < n) {
+                                       /* Skip to the next string */
+                                       do {
+                                               msg_strs++;
+                                       } while (*msg_strs);
+                                       msg_strs++;
+                               }
+                               if (e & 1) {
+                                       if (*msg_strs == n && msg_strs[1])
+                                               printf("%s ", msg_strs+1);
+                                       else
+                                               printf("%d:%d ", i, j);
+                               }
                                e >>= 1;
                        }
                }
diff --git a/arch/x86/boot/mkcpustr.c b/arch/x86/boot/mkcpustr.c
new file mode 100644 (file)
index 0000000..bbe7695
--- /dev/null
@@ -0,0 +1,49 @@
+/* ----------------------------------------------------------------------- *
+ *
+ *   Copyright 2008 rPath, Inc. - All Rights Reserved
+ *
+ *   This file is part of the Linux kernel, and is made available under
+ *   the terms of the GNU General Public License version 2 or (at your
+ *   option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * This is a host program to preprocess the CPU strings into a
+ * compact format suitable for the setup code.
+ */
+
+#include <stdio.h>
+
+#include "../kernel/cpu/feature_names.c"
+
+#if NCAPFLAGS > 8
+# error "Need to adjust the boot code handling of CPUID strings"
+#endif
+
+int main(void)
+{
+       int i;
+       const char *str;
+
+       printf("static const char x86_cap_strs[] = \n");
+
+       for (i = 0; i < NCAPINTS*32; i++) {
+               str = x86_cap_flags[i];
+
+               if (i == NCAPINTS*32-1) {
+                       /* The last entry must be unconditional; this
+                          also consumes the compiler-added null character */
+                       if (!str)
+                               str = "";
+                       printf("\t\"\\x%02x\"\"%s\"\n", i, str);
+               } else if (str) {
+                       printf("#if REQUIRED_MASK%d & (1 << %d)\n"
+                              "\t\"\\x%02x\"\"%s\\0\"\n"
+                              "#endif\n",
+                              i >> 5, i & 31, i, str);
+               }
+       }
+       printf("\t;\n");
+       return 0;
+}
index 0db0a6291bbd06d059c654ce58f8e5d387d685c0..8022d3c695c0dcf0d4a609387d337bf8eeaac888 100644 (file)
@@ -722,7 +722,9 @@ ia32_sys_call_table:
        .quad sys_epoll_pwait
        .quad compat_sys_utimensat      /* 320 */
        .quad compat_sys_signalfd
-       .quad compat_sys_timerfd
+       .quad sys_timerfd_create
        .quad sys_eventfd
        .quad sys32_fallocate
+       .quad compat_sys_timerfd_settime        /* 325 */
+       .quad compat_sys_timerfd_gettime
 ia32_syscall_end:
index 6f813009d44b348de25cbb355a197f9c8f1241fe..21dc1a061bf1b13c653b6ba7c8f54e31941f80ff 100644 (file)
@@ -37,7 +37,8 @@ obj-$(CONFIG_X86_MSR)         += msr.o
 obj-$(CONFIG_X86_CPUID)                += cpuid.o
 obj-$(CONFIG_MICROCODE)                += microcode.o
 obj-$(CONFIG_PCI)              += early-quirks.o
-obj-$(CONFIG_APM)              += apm_32.o
+apm-y                          := apm_32.o
+obj-$(CONFIG_APM)              += apm.o
 obj-$(CONFIG_X86_SMP)          += smp_$(BITS).o smpboot_$(BITS).o tsc_sync.o
 obj-$(CONFIG_X86_32_SMP)       += smpcommon_32.o
 obj-$(CONFIG_X86_64_SMP)       += smp_64.o smpboot_64.o tsc_sync.o
@@ -74,7 +75,8 @@ ifdef CONFIG_INPUT_PCSPKR
 obj-y                          += pcspeaker.o
 endif
 
-obj-$(CONFIG_SCx200)           += scx200_32.o
+obj-$(CONFIG_SCx200)           += scx200.o
+scx200-y                       += scx200_32.o
 
 ###
 # 64 bit specific files
index 0ca27c7b0e8db00335d47dc158557bf4915aede6..d2a58431a074b3f6282b58489635076878bdf2d3 100644 (file)
@@ -496,7 +496,8 @@ EXPORT_SYMBOL(acpi_register_gsi);
  *  ACPI based hotplug support for CPU
  */
 #ifdef CONFIG_ACPI_HOTPLUG_CPU
-int acpi_map_lsapic(acpi_handle handle, int *pcpu)
+
+static int __cpuinit _acpi_map_lsapic(acpi_handle handle, int *pcpu)
 {
        struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
        union acpi_object *obj;
@@ -551,6 +552,11 @@ int acpi_map_lsapic(acpi_handle handle, int *pcpu)
        return 0;
 }
 
+/* wrapper to silence section mismatch warning */
+int __ref acpi_map_lsapic(acpi_handle handle, int *pcpu)
+{
+       return _acpi_map_lsapic(handle, pcpu);
+}
 EXPORT_SYMBOL(acpi_map_lsapic);
 
 int acpi_unmap_lsapic(int cpu)
index cfdb2f3bd7636bff75d5ac2fd322800c5afa8639..a0c4d7c5dbd7bcf944fbc4e23ea74215c80c6d42 100644 (file)
@@ -3,6 +3,7 @@
 #
 
 obj-y                  := intel_cacheinfo.o addon_cpuid_features.o
+obj-y                  += feature_names.o
 
 obj-$(CONFIG_X86_32)   += common.o proc.o bugs.o
 obj-$(CONFIG_X86_32)   += amd.o
index 06fa159232fd74b9520cb41a706f1d239e653572..693e353999cdfbda06f6dedf3ece288990ebffa9 100644 (file)
@@ -304,7 +304,7 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c)
        if (c->x86 < 6)
                clear_bit(X86_FEATURE_MCE, c->x86_capability);
 
-       if (cpu_has_xmm)
+       if (cpu_has_xmm2)
                set_bit(X86_FEATURE_MFENCE_RDTSC, c->x86_capability);
 }
 
index db28aa9e2f694b7f14669d3c66df8cc712cfab48..d9313d9adcedd04479a041a11709627032ca3a52 100644 (file)
@@ -258,10 +258,10 @@ static int __cpuinit have_cpuid_p(void)
 void __init cpu_detect(struct cpuinfo_x86 *c)
 {
        /* Get vendor name */
-       cpuid(0x00000000, &c->cpuid_level,
-             (int *)&c->x86_vendor_id[0],
-             (int *)&c->x86_vendor_id[8],
-             (int *)&c->x86_vendor_id[4]);
+       cpuid(0x00000000, (unsigned int *)&c->cpuid_level,
+             (unsigned int *)&c->x86_vendor_id[0],
+             (unsigned int *)&c->x86_vendor_id[8],
+             (unsigned int *)&c->x86_vendor_id[4]);
 
        c->x86 = 4;
        if (c->cpuid_level >= 0x00000001) {
@@ -274,14 +274,16 @@ void __init cpu_detect(struct cpuinfo_x86 *c)
                if (c->x86 >= 0x6)
                        c->x86_model += ((tfms >> 16) & 0xF) << 4;
                c->x86_mask = tfms & 15;
-               if (cap0 & (1<<19))
+               if (cap0 & (1<<19)) {
                        c->x86_cache_alignment = ((misc >> 8) & 0xff) * 8;
+                       c->x86_clflush_size = ((misc >> 8) & 0xff) * 8;
+               }
        }
 }
 static void __cpuinit early_get_cap(struct cpuinfo_x86 *c)
 {
        u32 tfms, xlvl;
-       int ebx;
+       unsigned int ebx;
 
        memset(&c->x86_capability, 0, sizeof c->x86_capability);
        if (have_cpuid_p()) {
@@ -317,6 +319,7 @@ static void __init early_cpu_detect(void)
        struct cpuinfo_x86 *c = &boot_cpu_data;
 
        c->x86_cache_alignment = 32;
+       c->x86_clflush_size = 32;
 
        if (!have_cpuid_p())
                return;
@@ -340,14 +343,14 @@ static void __init early_cpu_detect(void)
 static void __cpuinit generic_identify(struct cpuinfo_x86 * c)
 {
        u32 tfms, xlvl;
-       int ebx;
+       unsigned int ebx;
 
        if (have_cpuid_p()) {
                /* Get vendor name */
-               cpuid(0x00000000, &c->cpuid_level,
-                     (int *)&c->x86_vendor_id[0],
-                     (int *)&c->x86_vendor_id[8],
-                     (int *)&c->x86_vendor_id[4]);
+               cpuid(0x00000000, (unsigned int *)&c->cpuid_level,
+                     (unsigned int *)&c->x86_vendor_id[0],
+                     (unsigned int *)&c->x86_vendor_id[8],
+                     (unsigned int *)&c->x86_vendor_id[4]);
                
                get_cpu_vendor(c, 0);
                /* Initialize the standard set of capabilities */
@@ -620,16 +623,6 @@ cpumask_t cpu_initialized __cpuinitdata = CPU_MASK_NONE;
  * They will insert themselves into the cpu_devs structure.
  * Then, when cpu_init() is called, we can just iterate over that array.
  */
-
-extern int intel_cpu_init(void);
-extern int cyrix_init_cpu(void);
-extern int nsc_init_cpu(void);
-extern int amd_init_cpu(void);
-extern int centaur_init_cpu(void);
-extern int transmeta_init_cpu(void);
-extern int nexgen_init_cpu(void);
-extern int umc_init_cpu(void);
-
 void __init early_cpu_init(void)
 {
        intel_cpu_init();
index ad6527a5beb12ba086ab643553722aa31fdbc08a..e0b38c33d84276c971110146960ecdcc1b11fdb3 100644 (file)
@@ -27,3 +27,12 @@ extern void display_cacheinfo(struct cpuinfo_x86 *c);
 extern void early_init_intel(struct cpuinfo_x86 *c);
 extern void early_init_amd(struct cpuinfo_x86 *c);
 
+/* Specific CPU type init functions */
+int intel_cpu_init(void);
+int amd_init_cpu(void);
+int cyrix_init_cpu(void);
+int nsc_init_cpu(void);
+int centaur_init_cpu(void);
+int transmeta_init_cpu(void);
+int nexgen_init_cpu(void);
+int umc_init_cpu(void);
diff --git a/arch/x86/kernel/cpu/feature_names.c b/arch/x86/kernel/cpu/feature_names.c
new file mode 100644 (file)
index 0000000..ee975ac
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Strings for the various x86 capability flags.
+ *
+ * This file must not contain any executable code.
+ */
+
+#include "asm/cpufeature.h"
+
+/*
+ * These flag bits must match the definitions in <asm/cpufeature.h>.
+ * NULL means this bit is undefined or reserved; either way it doesn't
+ * have meaning as far as Linux is concerned.  Note that it's important
+ * to realize there is a difference between this table and CPUID -- if
+ * applications want to get the raw CPUID data, they should access
+ * /dev/cpu/<cpu_nr>/cpuid instead.
+ */
+const char * const x86_cap_flags[NCAPINTS*32] = {
+       /* Intel-defined */
+       "fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce",
+       "cx8", "apic", NULL, "sep", "mtrr", "pge", "mca", "cmov",
+       "pat", "pse36", "pn", "clflush", NULL, "dts", "acpi", "mmx",
+       "fxsr", "sse", "sse2", "ss", "ht", "tm", "ia64", "pbe",
+
+       /* AMD-defined */
+       NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+       NULL, NULL, NULL, "syscall", NULL, NULL, NULL, NULL,
+       NULL, NULL, NULL, "mp", "nx", NULL, "mmxext", NULL,
+       NULL, "fxsr_opt", "pdpe1gb", "rdtscp", NULL, "lm",
+       "3dnowext", "3dnow",
+
+       /* Transmeta-defined */
+       "recovery", "longrun", NULL, "lrti", NULL, NULL, NULL, NULL,
+       NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+       NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+       NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+
+       /* Other (Linux-defined) */
+       "cxmmx", "k6_mtrr", "cyrix_arr", "centaur_mcr",
+       NULL, NULL, NULL, NULL,
+       "constant_tsc", "up", NULL, "arch_perfmon",
+       "pebs", "bts", NULL, NULL,
+       "rep_good", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+       NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+
+       /* Intel-defined (#2) */
+       "pni", NULL, NULL, "monitor", "ds_cpl", "vmx", "smx", "est",
+       "tm2", "ssse3", "cid", NULL, NULL, "cx16", "xtpr", NULL,
+       NULL, NULL, "dca", "sse4_1", "sse4_2", NULL, NULL, "popcnt",
+       NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+
+       /* VIA/Cyrix/Centaur-defined */
+       NULL, NULL, "rng", "rng_en", NULL, NULL, "ace", "ace_en",
+       "ace2", "ace2_en", "phe", "phe_en", "pmm", "pmm_en", NULL, NULL,
+       NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+       NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+
+       /* AMD-defined (#2) */
+       "lahf_lm", "cmp_legacy", "svm", "extapic",
+       "cr8_legacy", "abm", "sse4a", "misalignsse",
+       "3dnowprefetch", "osvw", "ibs", "sse5",
+       "skinit", "wdt", NULL, NULL,
+       NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+       NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+
+       /* Auxiliary (Linux-defined) */
+       "ida", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+       NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+       NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+       NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+};
+
+const char *const x86_power_flags[32] = {
+       "ts",   /* temperature sensor */
+       "fid",  /* frequency id control */
+       "vid",  /* voltage id control */
+       "ttp",  /* thermal trip */
+       "tm",
+       "stc",
+       "100mhzsteps",
+       "hwpstate",
+       "",     /* tsc invariant mapped to constant_tsc */
+               /* nothing */
+};
index d1c372b018dbe299fde8ae3c5bcfc21961929e84..fae31ce747bdc042d0d94723a4e8da4fe5b61721 100644 (file)
@@ -13,6 +13,7 @@
 #include <asm/uaccess.h>
 #include <asm/ptrace.h>
 #include <asm/ds.h>
+#include <asm/bugs.h>
 
 #include "cpu.h"
 
index 8b4507b8469b18ed09f906e35b94ba6649e75b8a..1b889860eb730fc3081b31d02fd304c923667711 100644 (file)
@@ -352,8 +352,8 @@ unsigned int __cpuinit init_intel_cacheinfo(struct cpuinfo_x86 *c)
         */
        if ((num_cache_leaves == 0 || c->x86 == 15) && c->cpuid_level > 1) {
                /* supports eax=2  call */
-               int i, j, n;
-               int regs[4];
+               int j, n;
+               unsigned int regs[4];
                unsigned char *dp = (unsigned char *)regs;
                int only_trace = 0;
 
@@ -368,7 +368,7 @@ unsigned int __cpuinit init_intel_cacheinfo(struct cpuinfo_x86 *c)
 
                        /* If bit 31 is set, this is an unknown format */
                        for ( j = 0 ; j < 3 ; j++ ) {
-                               if ( regs[j] < 0 ) regs[j] = 0;
+                               if (regs[j] & (1 << 31)) regs[j] = 0;
                        }
 
                        /* Byte 0 is level count, not a descriptor */
index 8e139c70f888262a62535bc7c2007acd2ad5b7f6..ff14c320040ccf9ab496b4b170cd03f97626dc36 100644 (file)
@@ -7,8 +7,6 @@
 #include <asm/processor-flags.h>
 #include "mtrr.h"
 
-int arr3_protected;
-
 static void
 cyrix_get_arr(unsigned int reg, unsigned long *base,
              unsigned long *size, mtrr_type * type)
@@ -99,8 +97,6 @@ cyrix_get_free_region(unsigned long base, unsigned long size, int replace_reg)
        case 4:
                return replace_reg;
        case 3:
-               if (arr3_protected)
-                       break;
        case 2:
        case 1:
        case 0:
@@ -115,8 +111,6 @@ cyrix_get_free_region(unsigned long base, unsigned long size, int replace_reg)
        } else {
                for (i = 0; i < 7; i++) {
                        cyrix_get_arr(i, &lbase, &lsize, &ltype);
-                       if ((i == 3) && arr3_protected)
-                               continue;
                        if (lsize == 0)
                                return i;
                }
@@ -260,107 +254,6 @@ static void cyrix_set_all(void)
        post_set();
 }
 
-#if 0
-/*
- * On Cyrix 6x86(MX) and M II the ARR3 is special: it has connection
- * with the SMM (System Management Mode) mode. So we need the following:
- * Check whether SMI_LOCK (CCR3 bit 0) is set
- *   if it is set, write a warning message: ARR3 cannot be changed!
- *     (it cannot be changed until the next processor reset)
- *   if it is reset, then we can change it, set all the needed bits:
- *   - disable access to SMM memory through ARR3 range (CCR1 bit 7 reset)
- *   - disable access to SMM memory (CCR1 bit 2 reset)
- *   - disable SMM mode (CCR1 bit 1 reset)
- *   - disable write protection of ARR3 (CCR6 bit 1 reset)
- *   - (maybe) disable ARR3
- * Just to be sure, we enable ARR usage by the processor (CCR5 bit 5 set)
- */
-static void __init
-cyrix_arr_init(void)
-{
-       struct set_mtrr_context ctxt;
-       unsigned char ccr[7];
-       int ccrc[7] = { 0, 0, 0, 0, 0, 0, 0 };
-#ifdef CONFIG_SMP
-       int i;
-#endif
-
-       /* flush cache and enable MAPEN */
-       set_mtrr_prepare_save(&ctxt);
-       set_mtrr_cache_disable(&ctxt);
-
-       /* Save all CCRs locally */
-       ccr[0] = getCx86(CX86_CCR0);
-       ccr[1] = getCx86(CX86_CCR1);
-       ccr[2] = getCx86(CX86_CCR2);
-       ccr[3] = ctxt.ccr3;
-       ccr[4] = getCx86(CX86_CCR4);
-       ccr[5] = getCx86(CX86_CCR5);
-       ccr[6] = getCx86(CX86_CCR6);
-
-       if (ccr[3] & 1) {
-               ccrc[3] = 1;
-               arr3_protected = 1;
-       } else {
-               /* Disable SMM mode (bit 1), access to SMM memory (bit 2) and
-                * access to SMM memory through ARR3 (bit 7).
-                */
-               if (ccr[1] & 0x80) {
-                       ccr[1] &= 0x7f;
-                       ccrc[1] |= 0x80;
-               }
-               if (ccr[1] & 0x04) {
-                       ccr[1] &= 0xfb;
-                       ccrc[1] |= 0x04;
-               }
-               if (ccr[1] & 0x02) {
-                       ccr[1] &= 0xfd;
-                       ccrc[1] |= 0x02;
-               }
-               arr3_protected = 0;
-               if (ccr[6] & 0x02) {
-                       ccr[6] &= 0xfd;
-                       ccrc[6] = 1;    /* Disable write protection of ARR3 */
-                       setCx86(CX86_CCR6, ccr[6]);
-               }
-               /* Disable ARR3. This is safe now that we disabled SMM. */
-               /* cyrix_set_arr_up (3, 0, 0, 0, FALSE); */
-       }
-       /* If we changed CCR1 in memory, change it in the processor, too. */
-       if (ccrc[1])
-               setCx86(CX86_CCR1, ccr[1]);
-
-       /* Enable ARR usage by the processor */
-       if (!(ccr[5] & 0x20)) {
-               ccr[5] |= 0x20;
-               ccrc[5] = 1;
-               setCx86(CX86_CCR5, ccr[5]);
-       }
-#ifdef CONFIG_SMP
-       for (i = 0; i < 7; i++)
-               ccr_state[i] = ccr[i];
-       for (i = 0; i < 8; i++)
-               cyrix_get_arr(i,
-                             &arr_state[i].base, &arr_state[i].size,
-                             &arr_state[i].type);
-#endif
-
-       set_mtrr_done(&ctxt);   /* flush cache and disable MAPEN */
-
-       if (ccrc[5])
-               printk(KERN_INFO "mtrr: ARR usage was not enabled, enabled manually\n");
-       if (ccrc[3])
-               printk(KERN_INFO "mtrr: ARR3 cannot be changed\n");
-/*
-    if ( ccrc[1] & 0x80) printk ("mtrr: SMM memory access through ARR3 disabled\n");
-    if ( ccrc[1] & 0x04) printk ("mtrr: SMM memory access disabled\n");
-    if ( ccrc[1] & 0x02) printk ("mtrr: SMM mode disabled\n");
-*/
-       if (ccrc[6])
-               printk(KERN_INFO "mtrr: ARR3 was write protected, unprotected\n");
-}
-#endif
-
 static struct mtrr_ops cyrix_mtrr_ops = {
        .vendor            = X86_VENDOR_CYRIX,
 //     .init              = cyrix_arr_init,
index 715919582657564a32f2941947687d87c448f722..1e27b69a7a0eca1750e4c16dd2470e49ab706112 100644 (file)
@@ -59,12 +59,6 @@ struct mtrr_ops * mtrr_if = NULL;
 static void set_mtrr(unsigned int reg, unsigned long base,
                     unsigned long size, mtrr_type type);
 
-#ifndef CONFIG_X86_64
-extern int arr3_protected;
-#else
-#define arr3_protected 0
-#endif
-
 void set_mtrr_ops(struct mtrr_ops * ops)
 {
        if (ops->vendor && ops->vendor < X86_VENDOR_NUM)
@@ -513,12 +507,6 @@ int mtrr_del_page(int reg, unsigned long base, unsigned long size)
                printk(KERN_WARNING "mtrr: register: %d too big\n", reg);
                goto out;
        }
-       if (is_cpu(CYRIX) && !use_intel()) {
-               if ((reg == 3) && arr3_protected) {
-                       printk(KERN_WARNING "mtrr: ARR3 cannot be changed\n");
-                       goto out;
-               }
-       }
        mtrr_if->get(reg, &lbase, &lsize, &ltype);
        if (lsize < 1) {
                printk(KERN_WARNING "mtrr: MTRR %d not used\n", reg);
@@ -566,10 +554,6 @@ EXPORT_SYMBOL(mtrr_del);
  * These should be called implicitly, but we can't yet until all the initcall
  * stuff is done...
  */
-extern void amd_init_mtrr(void);
-extern void cyrix_init_mtrr(void);
-extern void centaur_init_mtrr(void);
-
 static void __init init_ifs(void)
 {
 #ifndef CONFIG_X86_64
index fb74a2c2081487bfd7207f6d4b620064cd67c4c8..2cc77eb6fea36967f7defdbae74359ebaac14ebb 100644 (file)
@@ -97,3 +97,7 @@ void mtrr_state_warn(void);
 const char *mtrr_attrib_to_str(int x);
 void mtrr_wrmsr(unsigned, unsigned, unsigned);
 
+/* CPU specific mtrr init functions */
+int amd_init_mtrr(void);
+int cyrix_init_mtrr(void);
+int centaur_init_mtrr(void);
index 028213260148d62b75f6d1804aa0977cfec6395f..af11d31dce0ae0df0b8a15772b2da15059a1871a 100644 (file)
  */
 static int show_cpuinfo(struct seq_file *m, void *v)
 {
-       /* 
-        * These flag bits must match the definitions in <asm/cpufeature.h>.
-        * NULL means this bit is undefined or reserved; either way it doesn't
-        * have meaning as far as Linux is concerned.  Note that it's important
-        * to realize there is a difference between this table and CPUID -- if
-        * applications want to get the raw CPUID data, they should access
-        * /dev/cpu/<cpu_nr>/cpuid instead.
-        */
-       static const char * const x86_cap_flags[] = {
-               /* Intel-defined */
-               "fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce",
-               "cx8", "apic", NULL, "sep", "mtrr", "pge", "mca", "cmov",
-               "pat", "pse36", "pn", "clflush", NULL, "dts", "acpi", "mmx",
-               "fxsr", "sse", "sse2", "ss", "ht", "tm", "ia64", "pbe",
-
-               /* AMD-defined */
-               NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-               NULL, NULL, NULL, "syscall", NULL, NULL, NULL, NULL,
-               NULL, NULL, NULL, "mp", "nx", NULL, "mmxext", NULL,
-               NULL, "fxsr_opt", "pdpe1gb", "rdtscp", NULL, "lm",
-               "3dnowext", "3dnow",
-
-               /* Transmeta-defined */
-               "recovery", "longrun", NULL, "lrti", NULL, NULL, NULL, NULL,
-               NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-               NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-               NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-
-               /* Other (Linux-defined) */
-               "cxmmx", "k6_mtrr", "cyrix_arr", "centaur_mcr",
-               NULL, NULL, NULL, NULL,
-               "constant_tsc", "up", NULL, "arch_perfmon",
-               "pebs", "bts", NULL, "sync_rdtsc",
-               "rep_good", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-               NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-
-               /* Intel-defined (#2) */
-               "pni", NULL, NULL, "monitor", "ds_cpl", "vmx", "smx", "est",
-               "tm2", "ssse3", "cid", NULL, NULL, "cx16", "xtpr", NULL,
-               NULL, NULL, "dca", "sse4_1", "sse4_2", NULL, NULL, "popcnt",
-               NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-
-               /* VIA/Cyrix/Centaur-defined */
-               NULL, NULL, "rng", "rng_en", NULL, NULL, "ace", "ace_en",
-               "ace2", "ace2_en", "phe", "phe_en", "pmm", "pmm_en", NULL, NULL,
-               NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-               NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-
-               /* AMD-defined (#2) */
-               "lahf_lm", "cmp_legacy", "svm", "extapic",
-               "cr8_legacy", "abm", "sse4a", "misalignsse",
-               "3dnowprefetch", "osvw", "ibs", "sse5",
-               "skinit", "wdt", NULL, NULL,
-               NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-               NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-
-               /* Auxiliary (Linux-defined) */
-               "ida", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-               NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-               NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-               NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-       };
-       static const char * const x86_power_flags[] = {
-               "ts",   /* temperature sensor */
-               "fid",  /* frequency id control */
-               "vid",  /* voltage id control */
-               "ttp",  /* thermal trip */
-               "tm",
-               "stc",
-               "100mhzsteps",
-               "hwpstate",
-               "",     /* constant_tsc - moved to flags */
-               /* nothing */
-       };
        struct cpuinfo_x86 *c = v;
        int i, n = 0;
        int fpu_exception;
index dec66e4528100c72ee384f7c5aa9400339eb26ab..288e7a6598ac6450c1b13a88e51337ccc0c0b9d2 100644 (file)
@@ -1,6 +1,6 @@
 /* ----------------------------------------------------------------------- *
- *   
- *   Copyright 2000 H. Peter Anvin - All Rights Reserved
+ *
+ *   Copyright 2000-2008 H. Peter Anvin - All Rights Reserved
  *
  *   This program is free software; you can redistribute it and/or modify
  *   it under the terms of the GNU General Public License as published by
  * and then read in chunks of 16 bytes.  A larger size means multiple
  * reads of consecutive levels.
  *
+ * The lower 32 bits of the file position is used as the incoming %eax,
+ * and the upper 32 bits of the file position as the incoming %ecx,
+ * the latter intended for "counting" eax levels like eax=4.
+ *
  * This driver uses /dev/cpu/%d/cpuid where %d is the minor number, and on
  * an SMP box will direct the access to CPU %d.
  */
 
 static struct class *cpuid_class;
 
-struct cpuid_command {
-       u32 reg;
-       u32 *data;
+struct cpuid_regs {
+       u32 eax, ebx, ecx, edx;
 };
 
 static void cpuid_smp_cpuid(void *cmd_block)
 {
-       struct cpuid_command *cmd = cmd_block;
-
-       cpuid(cmd->reg, &cmd->data[0], &cmd->data[1], &cmd->data[2],
-                     &cmd->data[3]);
-}
-
-static inline void do_cpuid(int cpu, u32 reg, u32 * data)
-{
-       struct cpuid_command cmd;
-
-       cmd.reg = reg;
-       cmd.data = data;
+       struct cpuid_regs *cmd = (struct cpuid_regs *)cmd_block;
 
-       smp_call_function_single(cpu, cpuid_smp_cpuid, &cmd, 1, 1);
+       cpuid_count(cmd->eax, cmd->ecx,
+                   &cmd->eax, &cmd->ebx, &cmd->ecx, &cmd->edx);
 }
 
 static loff_t cpuid_seek(struct file *file, loff_t offset, int orig)
 {
        loff_t ret;
+       struct inode *inode = file->f_mapping->host;
 
-       lock_kernel();
-
+       mutex_lock(&inode->i_mutex);
        switch (orig) {
        case 0:
                file->f_pos = offset;
@@ -84,8 +77,7 @@ static loff_t cpuid_seek(struct file *file, loff_t offset, int orig)
        default:
                ret = -EINVAL;
        }
-
-       unlock_kernel();
+       mutex_unlock(&inode->i_mutex);
        return ret;
 }
 
@@ -93,19 +85,21 @@ static ssize_t cpuid_read(struct file *file, char __user *buf,
                          size_t count, loff_t * ppos)
 {
        char __user *tmp = buf;
-       u32 data[4];
-       u32 reg = *ppos;
+       struct cpuid_regs cmd;
        int cpu = iminor(file->f_path.dentry->d_inode);
+       u64 pos = *ppos;
 
        if (count % 16)
                return -EINVAL; /* Invalid chunk size */
 
        for (; count; count -= 16) {
-               do_cpuid(cpu, reg, data);
-               if (copy_to_user(tmp, &data, 16))
+               cmd.eax = pos;
+               cmd.ecx = pos >> 32;
+               smp_call_function_single(cpu, cpuid_smp_cpuid, &cmd, 1, 1);
+               if (copy_to_user(tmp, &cmd, 16))
                        return -EFAULT;
                tmp += 16;
-               *ppos = reg++;
+               *ppos = ++pos;
        }
 
        return tmp - buf;
@@ -170,7 +164,7 @@ static int __cpuinit cpuid_class_cpu_callback(struct notifier_block *nfb,
        return err ? NOTIFY_BAD : NOTIFY_OK;
 }
 
-static struct notifier_block __cpuinitdata cpuid_class_cpu_notifier =
+static struct notifier_block __refdata cpuid_class_cpu_notifier =
 {
        .notifier_call = cpuid_class_cpu_callback,
 };
@@ -193,7 +187,7 @@ static int __init cpuid_init(void)
        }
        for_each_online_cpu(i) {
                err = cpuid_device_create(i);
-               if (err != 0) 
+               if (err != 0)
                        goto out_class;
        }
        register_hotcpu_notifier(&cpuid_class_cpu_notifier);
@@ -208,7 +202,7 @@ out_class:
        }
        class_destroy(cpuid_class);
 out_chrdev:
-       unregister_chrdev(CPUID_MAJOR, "cpu/cpuid");    
+       unregister_chrdev(CPUID_MAJOR, "cpu/cpuid");
 out:
        return err;
 }
index 1c5ca4d187877544dc4838f39ee31ae8d0493448..dcd918c1580dfda5dc66c50d3d9d3492dde6fcee 100644 (file)
@@ -223,7 +223,7 @@ int ds_free(void **dsp)
        if (*dsp)
                kfree((void *)get_bts_buffer_base(*dsp));
        kfree(*dsp);
-       *dsp = 0;
+       *dsp = NULL;
 
        return 0;
 }
index c617174e896382fe91b77a4c70b8ef2996511b92..9f65b4cc323c49cf39d61242f62394865c94decb 100644 (file)
@@ -54,30 +54,33 @@ static unsigned long __initdata end_user_pfn = MAXMEM>>PAGE_SHIFT;
 
 struct early_res {
        unsigned long start, end;
+       char name[16];
 };
 static struct early_res early_res[MAX_EARLY_RES] __initdata = {
-       { 0, PAGE_SIZE },                       /* BIOS data page */
+       { 0, PAGE_SIZE, "BIOS data page" },                     /* BIOS data page */
 #ifdef CONFIG_SMP
-       { SMP_TRAMPOLINE_BASE, SMP_TRAMPOLINE_BASE + 2*PAGE_SIZE },
+       { SMP_TRAMPOLINE_BASE, SMP_TRAMPOLINE_BASE + 2*PAGE_SIZE, "SMP_TRAMPOLINE" },
 #endif
        {}
 };
 
-void __init reserve_early(unsigned long start, unsigned long end)
+void __init reserve_early(unsigned long start, unsigned long end, char *name)
 {
        int i;
        struct early_res *r;
        for (i = 0; i < MAX_EARLY_RES && early_res[i].end; i++) {
                r = &early_res[i];
                if (end > r->start && start < r->end)
-                       panic("Overlapping early reservations %lx-%lx to %lx-%lx\n",
-                             start, end, r->start, r->end);
+                       panic("Overlapping early reservations %lx-%lx %s to %lx-%lx %s\n",
+                             start, end - 1, name?name:"", r->start, r->end - 1, r->name);
        }
        if (i >= MAX_EARLY_RES)
                panic("Too many early reservations");
        r = &early_res[i];
        r->start = start;
        r->end = end;
+       if (name)
+               strncpy(r->name, name, sizeof(r->name) - 1);
 }
 
 void __init early_res_to_bootmem(void)
@@ -85,6 +88,8 @@ void __init early_res_to_bootmem(void)
        int i;
        for (i = 0; i < MAX_EARLY_RES && early_res[i].end; i++) {
                struct early_res *r = &early_res[i];
+               printk(KERN_INFO "early res: %d [%lx-%lx] %s\n", i,
+                       r->start, r->end - 1, r->name);
                reserve_bootmem_generic(r->start, r->end - r->start);
        }
 }
@@ -166,12 +171,13 @@ int __init e820_all_mapped(unsigned long start, unsigned long end,
 }
 
 /*
- * Find a free area in a specific range.
+ * Find a free area with specified alignment in a specific range.
  */
 unsigned long __init find_e820_area(unsigned long start, unsigned long end,
-                                   unsigned size)
+                                   unsigned size, unsigned long align)
 {
        int i;
+       unsigned long mask = ~(align - 1);
 
        for (i = 0; i < e820.nr_map; i++) {
                struct e820entry *ei = &e820.map[i];
@@ -185,7 +191,8 @@ unsigned long __init find_e820_area(unsigned long start, unsigned long end,
                        continue;
                while (bad_addr(&addr, size) && addr+size <= ei->addr+ei->size)
                        ;
-               last = PAGE_ALIGN(addr) + size;
+               addr = (addr + align - 1) & mask;
+               last = addr + size;
                if (last > ei->addr + ei->size)
                        continue;
                if (last > end)
index b7d6c23f28716f1108795d98b69d5572dd53dff0..cff84cd9987f37270689154df1e07db469a4f9df 100644 (file)
@@ -193,7 +193,7 @@ static struct console simnow_console = {
 };
 
 /* Direct interface for emergencies */
-struct console *early_console = &early_vga_console;
+static struct console *early_console = &early_vga_console;
 static int early_console_initialized = 0;
 
 void early_printk(const char *fmt, ...)
index 1411324a625ca5ae0060d49afbdbc897b9e70c68..32dd62b36ff7e200807d1e8ea20651651bd41a9b 100644 (file)
@@ -379,11 +379,9 @@ void __init efi_init(void)
 #endif
 }
 
-#if defined(CONFIG_X86_64) || defined(CONFIG_X86_PAE)
 static void __init runtime_code_page_mkexec(void)
 {
        efi_memory_desc_t *md;
-       unsigned long end;
        void *p;
 
        if (!(__supported_pte_mask & _PAGE_NX))
@@ -392,18 +390,13 @@ static void __init runtime_code_page_mkexec(void)
        /* Make EFI runtime service code area executable */
        for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
                md = p;
-               end = md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT);
-               if (md->type == EFI_RUNTIME_SERVICES_CODE &&
-                   (end >> PAGE_SHIFT) <= max_pfn_mapped) {
-                       set_memory_x(md->virt_addr, md->num_pages);
-                       set_memory_uc(md->virt_addr, md->num_pages);
-               }
+
+               if (md->type != EFI_RUNTIME_SERVICES_CODE)
+                       continue;
+
+               set_memory_x(md->virt_addr, md->num_pages << EFI_PAGE_SHIFT);
        }
-       __flush_tlb_all();
 }
-#else
-static inline void __init runtime_code_page_mkexec(void) { }
-#endif
 
 /*
  * This function will switch the EFI runtime services to virtual mode.
@@ -417,30 +410,40 @@ void __init efi_enter_virtual_mode(void)
 {
        efi_memory_desc_t *md;
        efi_status_t status;
-       unsigned long end;
-       void *p;
+       unsigned long size;
+       u64 end, systab;
+       void *p, *va;
 
        efi.systab = NULL;
        for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
                md = p;
                if (!(md->attribute & EFI_MEMORY_RUNTIME))
                        continue;
-               end = md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT);
-               if ((md->attribute & EFI_MEMORY_WB) &&
-                   ((end >> PAGE_SHIFT) <= max_pfn_mapped))
-                       md->virt_addr = (unsigned long)__va(md->phys_addr);
+
+               size = md->num_pages << EFI_PAGE_SHIFT;
+               end = md->phys_addr + size;
+
+               if ((end >> PAGE_SHIFT) <= max_pfn_mapped)
+                       va = __va(md->phys_addr);
                else
-                       md->virt_addr = (unsigned long)
-                               efi_ioremap(md->phys_addr,
-                                           md->num_pages << EFI_PAGE_SHIFT);
-               if (!md->virt_addr)
+                       va = efi_ioremap(md->phys_addr, size);
+
+               if (md->attribute & EFI_MEMORY_WB)
+                       set_memory_uc(md->virt_addr, size);
+
+               md->virt_addr = (u64) (unsigned long) va;
+
+               if (!va) {
                        printk(KERN_ERR PFX "ioremap of 0x%llX failed!\n",
                               (unsigned long long)md->phys_addr);
-               if ((md->phys_addr <= (unsigned long)efi_phys.systab) &&
-                   ((unsigned long)efi_phys.systab < end))
-                       efi.systab = (efi_system_table_t *)(unsigned long)
-                               (md->virt_addr - md->phys_addr +
-                                (unsigned long)efi_phys.systab);
+                       continue;
+               }
+
+               systab = (u64) (unsigned long) efi_phys.systab;
+               if (md->phys_addr <= systab && systab < end) {
+                       systab += md->virt_addr - md->phys_addr;
+                       efi.systab = (efi_system_table_t *) (unsigned long) systab;
+               }
        }
 
        BUG_ON(!efi.systab);
index 4b73992c1e111945012993742b436fda177f51b8..09d5c23309342779ca955e641a408657a7395ec8 100644 (file)
@@ -44,7 +44,7 @@ static void __init early_mapping_set_exec(unsigned long start,
                                          int executable)
 {
        pte_t *kpte;
-       int level;
+       unsigned int level;
 
        while (start < end) {
                kpte = lookup_address((unsigned long)__va(start), &level);
@@ -54,10 +54,10 @@ static void __init early_mapping_set_exec(unsigned long start,
                else
                        set_pte(kpte, __pte((pte_val(*kpte) | _PAGE_NX) & \
                                            __supported_pte_mask));
-               if (level == 4)
-                       start = (start + PMD_SIZE) & PMD_MASK;
-               else
+               if (level == PG_LEVEL_4K)
                        start = (start + PAGE_SIZE) & PAGE_MASK;
+               else
+                       start = (start + PMD_SIZE) & PMD_MASK;
        }
 }
 
@@ -109,23 +109,23 @@ void __init efi_reserve_bootmem(void)
                                memmap.nr_map * memmap.desc_size);
 }
 
-void __iomem * __init efi_ioremap(unsigned long offset,
-                                 unsigned long size)
+void __iomem * __init efi_ioremap(unsigned long phys_addr, unsigned long size)
 {
        static unsigned pages_mapped;
-       unsigned long last_addr;
        unsigned i, pages;
 
-       last_addr = offset + size - 1;
-       offset &= PAGE_MASK;
-       pages = (PAGE_ALIGN(last_addr) - offset) >> PAGE_SHIFT;
+       /* phys_addr and size must be page aligned */
+       if ((phys_addr & ~PAGE_MASK) || (size & ~PAGE_MASK))
+               return NULL;
+
+       pages = size >> PAGE_SHIFT;
        if (pages_mapped + pages > MAX_EFI_IO_PAGES)
                return NULL;
 
        for (i = 0; i < pages; i++) {
                __set_fixmap(FIX_EFI_IO_MAP_FIRST_PAGE - pages_mapped,
-                            offset, PAGE_KERNEL_EXEC_NOCACHE);
-               offset += PAGE_SIZE;
+                            phys_addr, PAGE_KERNEL);
+               phys_addr += PAGE_SIZE;
                pages_mapped++;
        }
 
index a317336cdeaaff2c52aff6f008e6b62447e6db19..24dbf56928d73877969fae6ebff7deb40d3624fe 100644 (file)
@@ -75,7 +75,7 @@ static __init void reserve_ebda(void)
        if (ebda_size > 64*1024)
                ebda_size = 64*1024;
 
-       reserve_early(ebda_addr, ebda_addr + ebda_size);
+       reserve_early(ebda_addr, ebda_addr + ebda_size, "EBDA");
 }
 
 void __init x86_64_start_kernel(char * real_mode_data)
@@ -105,14 +105,14 @@ void __init x86_64_start_kernel(char * real_mode_data)
        pda_init(0);
        copy_bootdata(__va(real_mode_data));
 
-       reserve_early(__pa_symbol(&_text), __pa_symbol(&_end));
+       reserve_early(__pa_symbol(&_text), __pa_symbol(&_end), "TEXT DATA BSS");
 
        /* Reserve INITRD */
        if (boot_params.hdr.type_of_loader && boot_params.hdr.ramdisk_image) {
                unsigned long ramdisk_image = boot_params.hdr.ramdisk_image;
                unsigned long ramdisk_size  = boot_params.hdr.ramdisk_size;
                unsigned long ramdisk_end   = ramdisk_image + ramdisk_size;
-               reserve_early(ramdisk_image, ramdisk_end);
+               reserve_early(ramdisk_image, ramdisk_end, "RAMDISK");
        }
 
        reserve_ebda();
index 1d5a7a361200b69e28e61294ce7e45b75e6ba659..4f283ad215ecac483909e1510ddb98e6f37607d0 100644 (file)
@@ -63,7 +63,7 @@ startup_64:
 
        /* Is the address not 2M aligned? */
        movq    %rbp, %rax
-       andl    $~LARGE_PAGE_MASK, %eax
+       andl    $~PMD_PAGE_MASK, %eax
        testl   %eax, %eax
        jnz     bad_address
 
@@ -88,7 +88,7 @@ startup_64:
 
        /* Add an Identity mapping if I am above 1G */
        leaq    _text(%rip), %rdi
-       andq    $LARGE_PAGE_MASK, %rdi
+       andq    $PMD_PAGE_MASK, %rdi
 
        movq    %rdi, %rax
        shrq    $PUD_SHIFT, %rax
index 8a7660c8394a5a2ae2362e6d3d4ec032d5def37e..0224c3637c73e68b4566124dd5d825034bc8c07a 100644 (file)
@@ -35,7 +35,8 @@ static int alloc_ldt(mm_context_t *pc, int mincount, int reload)
        if (mincount <= pc->size)
                return 0;
        oldsize = pc->size;
-       mincount = (mincount + 511) & (~511);
+       mincount = (mincount + (PAGE_SIZE / LDT_ENTRY_SIZE - 1)) &
+                       (~(PAGE_SIZE / LDT_ENTRY_SIZE - 1));
        if (mincount * LDT_ENTRY_SIZE > PAGE_SIZE)
                newldt = vmalloc(mincount * LDT_ENTRY_SIZE);
        else
index 6ff447f9fda702398aaaaef9aa8f93143c56a12d..f2702d01b8a8773a8d7658d47fd7e6c1997fdc7c 100644 (file)
@@ -797,7 +797,7 @@ mc_cpu_callback(struct notifier_block *nb, unsigned long action, void *hcpu)
        return NOTIFY_OK;
 }
 
-static struct notifier_block __cpuinitdata mc_cpu_notifier = {
+static struct notifier_block __refdata mc_cpu_notifier = {
        .notifier_call = mc_cpu_callback,
 };
 
index 21f6e3c0be185c657d307042168fef4509073798..af51ea8400b2de88509efab5ad3df145f2ccab08 100644 (file)
@@ -1,6 +1,6 @@
 /* ----------------------------------------------------------------------- *
- *   
- *   Copyright 2000 H. Peter Anvin - All Rights Reserved
+ *
+ *   Copyright 2000-2008 H. Peter Anvin - All Rights Reserved
  *
  *   This program is free software; you can redistribute it and/or modify
  *   it under the terms of the GNU General Public License as published by
@@ -45,9 +45,10 @@ static struct class *msr_class;
 
 static loff_t msr_seek(struct file *file, loff_t offset, int orig)
 {
-       loff_t ret = -EINVAL;
+       loff_t ret;
+       struct inode *inode = file->f_mapping->host;
 
-       lock_kernel();
+       mutex_lock(&inode->i_mutex);
        switch (orig) {
        case 0:
                file->f_pos = offset;
@@ -56,8 +57,11 @@ static loff_t msr_seek(struct file *file, loff_t offset, int orig)
        case 1:
                file->f_pos += offset;
                ret = file->f_pos;
+               break;
+       default:
+               ret = -EINVAL;
        }
-       unlock_kernel();
+       mutex_unlock(&inode->i_mutex);
        return ret;
 }
 
@@ -168,7 +172,7 @@ static int __cpuinit msr_class_cpu_callback(struct notifier_block *nfb,
        return err ? NOTIFY_BAD : NOTIFY_OK;
 }
 
-static struct notifier_block __cpuinitdata msr_class_cpu_notifier = {
+static struct notifier_block __refdata msr_class_cpu_notifier = {
        .notifier_call = msr_class_cpu_callback,
 };
 
index 21f34db2c03c1efe90fd7ef4dcedc2407dc17e6f..1b5464c2434f2fbe115816a6603fc3434dd55b96 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/scatterlist.h>
+#include <linux/iommu-helper.h>
 #include <asm/gart.h>
 #include <asm/calgary.h>
 #include <asm/tce.h>
@@ -260,22 +261,28 @@ static void iommu_range_reserve(struct iommu_table *tbl,
        spin_unlock_irqrestore(&tbl->it_lock, flags);
 }
 
-static unsigned long iommu_range_alloc(struct iommu_table *tbl,
-       unsigned int npages)
+static unsigned long iommu_range_alloc(struct device *dev,
+                                      struct iommu_table *tbl,
+                                      unsigned int npages)
 {
        unsigned long flags;
        unsigned long offset;
+       unsigned long boundary_size;
+
+       boundary_size = ALIGN(dma_get_seg_boundary(dev) + 1,
+                             PAGE_SIZE) >> PAGE_SHIFT;
 
        BUG_ON(npages == 0);
 
        spin_lock_irqsave(&tbl->it_lock, flags);
 
-       offset = find_next_zero_string(tbl->it_map, tbl->it_hint,
-                                      tbl->it_size, npages);
+       offset = iommu_area_alloc(tbl->it_map, tbl->it_size, tbl->it_hint,
+                                 npages, 0, boundary_size, 0);
        if (offset == ~0UL) {
                tbl->chip_ops->tce_cache_blast(tbl);
-               offset = find_next_zero_string(tbl->it_map, 0,
-                                              tbl->it_size, npages);
+
+               offset = iommu_area_alloc(tbl->it_map, tbl->it_size, 0,
+                                         npages, 0, boundary_size, 0);
                if (offset == ~0UL) {
                        printk(KERN_WARNING "Calgary: IOMMU full.\n");
                        spin_unlock_irqrestore(&tbl->it_lock, flags);
@@ -286,7 +293,6 @@ static unsigned long iommu_range_alloc(struct iommu_table *tbl,
                }
        }
 
-       set_bit_string(tbl->it_map, offset, npages);
        tbl->it_hint = offset + npages;
        BUG_ON(tbl->it_hint > tbl->it_size);
 
@@ -295,13 +301,13 @@ static unsigned long iommu_range_alloc(struct iommu_table *tbl,
        return offset;
 }
 
-static dma_addr_t iommu_alloc(struct iommu_table *tbl, void *vaddr,
-       unsigned int npages, int direction)
+static dma_addr_t iommu_alloc(struct device *dev, struct iommu_table *tbl,
+                             void *vaddr, unsigned int npages, int direction)
 {
        unsigned long entry;
        dma_addr_t ret = bad_dma_address;
 
-       entry = iommu_range_alloc(tbl, npages);
+       entry = iommu_range_alloc(dev, tbl, npages);
 
        if (unlikely(entry == bad_dma_address))
                goto error;
@@ -354,7 +360,7 @@ static void iommu_free(struct iommu_table *tbl, dma_addr_t dma_addr,
                               badbit, tbl, dma_addr, entry, npages);
        }
 
-       __clear_bit_string(tbl->it_map, entry, npages);
+       iommu_area_free(tbl->it_map, entry, npages);
 
        spin_unlock_irqrestore(&tbl->it_lock, flags);
 }
@@ -438,7 +444,7 @@ static int calgary_map_sg(struct device *dev, struct scatterlist *sg,
                vaddr = (unsigned long) sg_virt(s);
                npages = num_dma_pages(vaddr, s->length);
 
-               entry = iommu_range_alloc(tbl, npages);
+               entry = iommu_range_alloc(dev, tbl, npages);
                if (entry == bad_dma_address) {
                        /* makes sure unmap knows to stop */
                        s->dma_length = 0;
@@ -476,7 +482,7 @@ static dma_addr_t calgary_map_single(struct device *dev, void *vaddr,
        npages = num_dma_pages(uaddr, size);
 
        if (translation_enabled(tbl))
-               dma_handle = iommu_alloc(tbl, vaddr, npages, direction);
+               dma_handle = iommu_alloc(dev, tbl, vaddr, npages, direction);
        else
                dma_handle = virt_to_bus(vaddr);
 
@@ -516,7 +522,7 @@ static void* calgary_alloc_coherent(struct device *dev, size_t size,
 
        if (translation_enabled(tbl)) {
                /* set up tces to cover the allocated range */
-               mapping = iommu_alloc(tbl, ret, npages, DMA_BIDIRECTIONAL);
+               mapping = iommu_alloc(dev, tbl, ret, npages, DMA_BIDIRECTIONAL);
                if (mapping == bad_dma_address)
                        goto free;
 
@@ -1006,7 +1012,7 @@ static void __init calgary_set_split_completion_timeout(void __iomem *bbar,
        readq(target); /* flush */
 }
 
-static void calioc2_handle_quirks(struct iommu_table *tbl, struct pci_dev *dev)
+static void __init calioc2_handle_quirks(struct iommu_table *tbl, struct pci_dev *dev)
 {
        unsigned char busnum = dev->bus->number;
        void __iomem *bbar = tbl->bbar;
@@ -1022,7 +1028,7 @@ static void calioc2_handle_quirks(struct iommu_table *tbl, struct pci_dev *dev)
        writel(cpu_to_be32(val), target);
 }
 
-static void calgary_handle_quirks(struct iommu_table *tbl, struct pci_dev *dev)
+static void __init calgary_handle_quirks(struct iommu_table *tbl, struct pci_dev *dev)
 {
        unsigned char busnum = dev->bus->number;
 
index 4d5cc718198229eda0913fa5a19c6d417fa6589e..65f6acb025c8833dc8183991bb313e52e3cff9ec 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/bitops.h>
 #include <linux/kdebug.h>
 #include <linux/scatterlist.h>
+#include <linux/iommu-helper.h>
 #include <asm/atomic.h>
 #include <asm/io.h>
 #include <asm/mtrr.h>
@@ -82,17 +83,24 @@ AGPEXTERN __u32 *agp_gatt_table;
 static unsigned long next_bit;  /* protected by iommu_bitmap_lock */
 static int need_flush;         /* global flush state. set for each gart wrap */
 
-static unsigned long alloc_iommu(int size)
+static unsigned long alloc_iommu(struct device *dev, int size)
 {
        unsigned long offset, flags;
+       unsigned long boundary_size;
+       unsigned long base_index;
+
+       base_index = ALIGN(iommu_bus_base & dma_get_seg_boundary(dev),
+                          PAGE_SIZE) >> PAGE_SHIFT;
+       boundary_size = ALIGN(dma_get_seg_boundary(dev) + 1,
+                             PAGE_SIZE) >> PAGE_SHIFT;
 
        spin_lock_irqsave(&iommu_bitmap_lock, flags);
-       offset = find_next_zero_string(iommu_gart_bitmap, next_bit,
-                                       iommu_pages, size);
+       offset = iommu_area_alloc(iommu_gart_bitmap, iommu_pages, next_bit,
+                                 size, base_index, boundary_size, 0);
        if (offset == -1) {
                need_flush = 1;
-               offset = find_next_zero_string(iommu_gart_bitmap, 0,
-                                               iommu_pages, size);
+               offset = iommu_area_alloc(iommu_gart_bitmap, iommu_pages, 0,
+                                         size, base_index, boundary_size, 0);
        }
        if (offset != -1) {
                set_bit_string(iommu_gart_bitmap, offset, size);
@@ -114,7 +122,7 @@ static void free_iommu(unsigned long offset, int size)
        unsigned long flags;
 
        spin_lock_irqsave(&iommu_bitmap_lock, flags);
-       __clear_bit_string(iommu_gart_bitmap, offset, size);
+       iommu_area_free(iommu_gart_bitmap, offset, size);
        spin_unlock_irqrestore(&iommu_bitmap_lock, flags);
 }
 
@@ -235,7 +243,7 @@ static dma_addr_t dma_map_area(struct device *dev, dma_addr_t phys_mem,
                                size_t size, int dir)
 {
        unsigned long npages = to_pages(phys_mem, size);
-       unsigned long iommu_page = alloc_iommu(npages);
+       unsigned long iommu_page = alloc_iommu(dev, npages);
        int i;
 
        if (iommu_page == -1) {
@@ -355,10 +363,11 @@ static int dma_map_sg_nonforce(struct device *dev, struct scatterlist *sg,
 }
 
 /* Map multiple scatterlist entries continuous into the first. */
-static int __dma_map_cont(struct scatterlist *start, int nelems,
-                         struct scatterlist *sout, unsigned long pages)
+static int __dma_map_cont(struct device *dev, struct scatterlist *start,
+                         int nelems, struct scatterlist *sout,
+                         unsigned long pages)
 {
-       unsigned long iommu_start = alloc_iommu(pages);
+       unsigned long iommu_start = alloc_iommu(dev, pages);
        unsigned long iommu_page = iommu_start;
        struct scatterlist *s;
        int i;
@@ -394,8 +403,8 @@ static int __dma_map_cont(struct scatterlist *start, int nelems,
 }
 
 static inline int
-dma_map_cont(struct scatterlist *start, int nelems, struct scatterlist *sout,
-            unsigned long pages, int need)
+dma_map_cont(struct device *dev, struct scatterlist *start, int nelems,
+            struct scatterlist *sout, unsigned long pages, int need)
 {
        if (!need) {
                BUG_ON(nelems != 1);
@@ -403,7 +412,7 @@ dma_map_cont(struct scatterlist *start, int nelems, struct scatterlist *sout,
                sout->dma_length = start->length;
                return 0;
        }
-       return __dma_map_cont(start, nelems, sout, pages);
+       return __dma_map_cont(dev, start, nelems, sout, pages);
 }
 
 /*
@@ -416,6 +425,8 @@ gart_map_sg(struct device *dev, struct scatterlist *sg, int nents, int dir)
        struct scatterlist *s, *ps, *start_sg, *sgmap;
        int need = 0, nextneed, i, out, start;
        unsigned long pages = 0;
+       unsigned int seg_size;
+       unsigned int max_seg_size;
 
        if (nents == 0)
                return 0;
@@ -426,6 +437,8 @@ gart_map_sg(struct device *dev, struct scatterlist *sg, int nents, int dir)
        out = 0;
        start = 0;
        start_sg = sgmap = sg;
+       seg_size = 0;
+       max_seg_size = dma_get_max_seg_size(dev);
        ps = NULL; /* shut up gcc */
        for_each_sg(sg, s, nents, i) {
                dma_addr_t addr = sg_phys(s);
@@ -443,11 +456,13 @@ gart_map_sg(struct device *dev, struct scatterlist *sg, int nents, int dir)
                         * offset.
                         */
                        if (!iommu_merge || !nextneed || !need || s->offset ||
+                           (s->length + seg_size > max_seg_size) ||
                            (ps->offset + ps->length) % PAGE_SIZE) {
-                               if (dma_map_cont(start_sg, i - start, sgmap,
-                                                 pages, need) < 0)
+                               if (dma_map_cont(dev, start_sg, i - start,
+                                                sgmap, pages, need) < 0)
                                        goto error;
                                out++;
+                               seg_size = 0;
                                sgmap = sg_next(sgmap);
                                pages = 0;
                                start = i;
@@ -455,11 +470,12 @@ gart_map_sg(struct device *dev, struct scatterlist *sg, int nents, int dir)
                        }
                }
 
+               seg_size += s->length;
                need = nextneed;
                pages += to_pages(s->offset, s->length);
                ps = s;
        }
-       if (dma_map_cont(start_sg, i - start, sgmap, pages, need) < 0)
+       if (dma_map_cont(dev, start_sg, i - start, sgmap, pages, need) < 0)
                goto error;
        out++;
        flush_gart();
@@ -501,7 +517,7 @@ static __init unsigned long check_iommu_size(unsigned long aper, u64 aper_size)
        }
 
        a = aper + iommu_size;
-       iommu_size -= round_up(a, LARGE_PAGE_SIZE) - a;
+       iommu_size -= round_up(a, PMD_PAGE_SIZE) - a;
 
        if (iommu_size < 64*1024*1024) {
                printk(KERN_WARNING
@@ -731,7 +747,8 @@ void __init gart_iommu_init(void)
         * the backing memory. The GART address is only used by PCI
         * devices.
         */
-       clear_kernel_mapping((unsigned long)__va(iommu_bus_base), iommu_size);
+       set_memory_np((unsigned long)__va(iommu_bus_base),
+                               iommu_size >> PAGE_SHIFT);
 
        /*
         * Try to workaround a bug (thanks to BenH)
index 968371ab223a250b59117d4fad4df43c247c104a..dabdbeff1f778685af46cb66b465ec0e36c71a02 100644 (file)
@@ -251,7 +251,7 @@ void cpu_idle_wait(void)
                 * because it has nothing to do.
                 * Give all the remaining CPUS a kick.
                 */
-               smp_call_function_mask(map, do_nothing, 0, 0);
+               smp_call_function_mask(map, do_nothing, NULL, 0);
        } while (!cpus_empty(map));
 
        set_cpus_allowed(current, tmp);
index 150ba29a0d331a486e2cea33c3ce3d4aec1464d7..3cd7a2dcd4fe729986267ed1c3d2e20d35ab0a0e 100644 (file)
@@ -30,8 +30,8 @@ static void __devinit quirk_intel_irqbalance(struct pci_dev *dev)
        raw_pci_ops->read(0, 0, 0x40, 0x4c, 2, &word);
 
        if (!(word & (1 << 13))) {
-               printk(KERN_INFO "Intel E7520/7320/7525 detected. "
-                       "Disabling irq balancing and affinity\n");
+               dev_info(&dev->dev, "Intel E7520/7320/7525 detected; "
+                       "disabling irq balancing and affinity\n");
 #ifdef CONFIG_IRQBALANCE
                irqbalance_disable("");
 #endif
@@ -104,14 +104,16 @@ static void ich_force_enable_hpet(struct pci_dev *dev)
        pci_read_config_dword(dev, 0xF0, &rcba);
        rcba &= 0xFFFFC000;
        if (rcba == 0) {
-               printk(KERN_DEBUG "RCBA disabled. Cannot force enable HPET\n");
+               dev_printk(KERN_DEBUG, &dev->dev, "RCBA disabled; "
+                       "cannot force enable HPET\n");
                return;
        }
 
        /* use bits 31:14, 16 kB aligned */
        rcba_base = ioremap_nocache(rcba, 0x4000);
        if (rcba_base == NULL) {
-               printk(KERN_DEBUG "ioremap failed. Cannot force enable HPET\n");
+               dev_printk(KERN_DEBUG, &dev->dev, "ioremap failed; "
+                       "cannot force enable HPET\n");
                return;
        }
 
@@ -122,8 +124,8 @@ static void ich_force_enable_hpet(struct pci_dev *dev)
                /* HPET is enabled in HPTC. Just not reported by BIOS */
                val = val & 0x3;
                force_hpet_address = 0xFED00000 | (val << 12);
-               printk(KERN_DEBUG "Force enabled HPET at base address 0x%lx\n",
-                              force_hpet_address);
+               dev_printk(KERN_DEBUG, &dev->dev, "Force enabled HPET at "
+                       "0x%lx\n", force_hpet_address);
                iounmap(rcba_base);
                return;
        }
@@ -142,11 +144,12 @@ static void ich_force_enable_hpet(struct pci_dev *dev)
        if (err) {
                force_hpet_address = 0;
                iounmap(rcba_base);
-               printk(KERN_DEBUG "Failed to force enable HPET\n");
+               dev_printk(KERN_DEBUG, &dev->dev,
+                       "Failed to force enable HPET\n");
        } else {
                force_hpet_resume_type = ICH_FORCE_HPET_RESUME;
-               printk(KERN_DEBUG "Force enabled HPET at base address 0x%lx\n",
-                              force_hpet_address);
+               dev_printk(KERN_DEBUG, &dev->dev, "Force enabled HPET at "
+                       "0x%lx\n", force_hpet_address);
        }
 }
 
@@ -208,8 +211,8 @@ static void old_ich_force_enable_hpet(struct pci_dev *dev)
        if (val & 0x4) {
                val &= 0x3;
                force_hpet_address = 0xFED00000 | (val << 12);
-               printk(KERN_DEBUG "HPET at base address 0x%lx\n",
-                              force_hpet_address);
+               dev_printk(KERN_DEBUG, &dev->dev, "HPET at 0x%lx\n",
+                       force_hpet_address);
                return;
        }
 
@@ -229,14 +232,14 @@ static void old_ich_force_enable_hpet(struct pci_dev *dev)
                /* HPET is enabled in HPTC. Just not reported by BIOS */
                val &= 0x3;
                force_hpet_address = 0xFED00000 | (val << 12);
-               printk(KERN_DEBUG "Force enabled HPET at base address 0x%lx\n",
-                              force_hpet_address);
+               dev_printk(KERN_DEBUG, &dev->dev, "Force enabled HPET at "
+                       "0x%lx\n", force_hpet_address);
                cached_dev = dev;
                force_hpet_resume_type = OLD_ICH_FORCE_HPET_RESUME;
                return;
        }
 
-       printk(KERN_DEBUG "Failed to force enable HPET\n");
+       dev_printk(KERN_DEBUG, &dev->dev, "Failed to force enable HPET\n");
 }
 
 /*
@@ -294,8 +297,8 @@ static void vt8237_force_enable_hpet(struct pci_dev *dev)
         */
        if (val & 0x80) {
                force_hpet_address = (val & ~0x3ff);
-               printk(KERN_DEBUG "HPET at base address 0x%lx\n",
-                              force_hpet_address);
+               dev_printk(KERN_DEBUG, &dev->dev, "HPET at 0x%lx\n",
+                       force_hpet_address);
                return;
        }
 
@@ -309,14 +312,14 @@ static void vt8237_force_enable_hpet(struct pci_dev *dev)
        pci_read_config_dword(dev, 0x68, &val);
        if (val & 0x80) {
                force_hpet_address = (val & ~0x3ff);
-               printk(KERN_DEBUG "Force enabled HPET at base address 0x%lx\n",
-                              force_hpet_address);
+               dev_printk(KERN_DEBUG, &dev->dev, "Force enabled HPET at "
+                       "0x%lx\n", force_hpet_address);
                cached_dev = dev;
                force_hpet_resume_type = VT8237_FORCE_HPET_RESUME;
                return;
        }
 
-       printk(KERN_DEBUG "Failed to force enable HPET\n");
+       dev_printk(KERN_DEBUG, &dev->dev, "Failed to force enable HPET\n");
 }
 
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8235,
@@ -344,7 +347,7 @@ static void nvidia_force_enable_hpet(struct pci_dev *dev)
        pci_read_config_dword(dev, 0x44, &val);
        force_hpet_address = val & 0xfffffffe;
        force_hpet_resume_type = NVIDIA_FORCE_HPET_RESUME;
-       printk(KERN_DEBUG "Force enabled HPET at base address 0x%lx\n",
+       dev_printk(KERN_DEBUG, &dev->dev, "Force enabled HPET at 0x%lx\n",
                force_hpet_address);
        cached_dev = dev;
        return;
index 87bc159d29dfeaa8fdf0563a0e63128608c6fa1f..7e004acbe52648918fd691765f6cafc86297b42b 100644 (file)
@@ -65,7 +65,7 @@ static int __devinit scx200_probe(struct pci_dev *pdev, const struct pci_device_
                base = pci_resource_start(pdev, 0);
                printk(KERN_INFO NAME ": GPIO base 0x%x\n", base);
 
-               if (request_region(base, SCx200_GPIO_SIZE, "NatSemi SCx200 GPIO") == 0) {
+               if (!request_region(base, SCx200_GPIO_SIZE, "NatSemi SCx200 GPIO")) {
                        printk(KERN_ERR NAME ": can't allocate I/O for GPIOs\n");
                        return -EBUSY;
                }
index 77fb87bf6e5a6fc12971be48212fd545422a68cf..c8939dfddfba3c0f7bdd63e3d21d6d38e67712fc 100644 (file)
@@ -182,7 +182,8 @@ contig_initmem_init(unsigned long start_pfn, unsigned long end_pfn)
        unsigned long bootmap_size, bootmap;
 
        bootmap_size = bootmem_bootmap_pages(end_pfn)<<PAGE_SHIFT;
-       bootmap = find_e820_area(0, end_pfn<<PAGE_SHIFT, bootmap_size);
+       bootmap = find_e820_area(0, end_pfn<<PAGE_SHIFT, bootmap_size,
+                                PAGE_SIZE);
        if (bootmap == -1L)
                panic("Cannot find bootmem map of size %ld\n", bootmap_size);
        bootmap_size = init_bootmem(bootmap >> PAGE_SHIFT, end_pfn);
@@ -1067,82 +1068,6 @@ static int show_cpuinfo(struct seq_file *m, void *v)
        struct cpuinfo_x86 *c = v;
        int cpu = 0, i;
 
-       /*
-        * These flag bits must match the definitions in <asm/cpufeature.h>.
-        * NULL means this bit is undefined or reserved; either way it doesn't
-        * have meaning as far as Linux is concerned.  Note that it's important
-        * to realize there is a difference between this table and CPUID -- if
-        * applications want to get the raw CPUID data, they should access
-        * /dev/cpu/<cpu_nr>/cpuid instead.
-        */
-       static const char *const x86_cap_flags[] = {
-               /* Intel-defined */
-               "fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce",
-               "cx8", "apic", NULL, "sep", "mtrr", "pge", "mca", "cmov",
-               "pat", "pse36", "pn", "clflush", NULL, "dts", "acpi", "mmx",
-               "fxsr", "sse", "sse2", "ss", "ht", "tm", "ia64", "pbe",
-
-               /* AMD-defined */
-               NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-               NULL, NULL, NULL, "syscall", NULL, NULL, NULL, NULL,
-               NULL, NULL, NULL, NULL, "nx", NULL, "mmxext", NULL,
-               NULL, "fxsr_opt", "pdpe1gb", "rdtscp", NULL, "lm",
-               "3dnowext", "3dnow",
-
-               /* Transmeta-defined */
-               "recovery", "longrun", NULL, "lrti", NULL, NULL, NULL, NULL,
-               NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-               NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-               NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-
-               /* Other (Linux-defined) */
-               "cxmmx", "k6_mtrr", "cyrix_arr", "centaur_mcr",
-               NULL, NULL, NULL, NULL,
-               "constant_tsc", "up", NULL, "arch_perfmon",
-               "pebs", "bts", NULL, "sync_rdtsc",
-               "rep_good", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-               NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-
-               /* Intel-defined (#2) */
-               "pni", NULL, NULL, "monitor", "ds_cpl", "vmx", "smx", "est",
-               "tm2", "ssse3", "cid", NULL, NULL, "cx16", "xtpr", NULL,
-               NULL, NULL, "dca", "sse4_1", "sse4_2", NULL, NULL, "popcnt",
-               NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-
-               /* VIA/Cyrix/Centaur-defined */
-               NULL, NULL, "rng", "rng_en", NULL, NULL, "ace", "ace_en",
-               "ace2", "ace2_en", "phe", "phe_en", "pmm", "pmm_en", NULL, NULL,
-               NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-               NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-
-               /* AMD-defined (#2) */
-               "lahf_lm", "cmp_legacy", "svm", "extapic",
-               "cr8_legacy", "abm", "sse4a", "misalignsse",
-               "3dnowprefetch", "osvw", "ibs", "sse5",
-               "skinit", "wdt", NULL, NULL,
-               NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-               NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-
-               /* Auxiliary (Linux-defined) */
-               "ida", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-               NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-               NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-               NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-       };
-       static const char *const x86_power_flags[] = {
-               "ts",   /* temperature sensor */
-               "fid",  /* frequency id control */
-               "vid",  /* voltage id control */
-               "ttp",  /* thermal trip */
-               "tm",
-               "stc",
-               "100mhzsteps",
-               "hwpstate",
-               "",     /* tsc invariant mapped to constant_tsc */
-               /* nothing */
-       };
-
-
 #ifdef CONFIG_SMP
        cpu = c->cpu_index;
 #endif
index cc64b8085c2aec9f0196dd83320b1f11db0d2afa..d53bd6fcb42877106dea1c2e8500c31f2614f15a 100644 (file)
@@ -1019,7 +1019,7 @@ static void remove_siblinginfo(int cpu)
        cpu_clear(cpu, cpu_sibling_setup_map);
 }
 
-void remove_cpu_from_maps(void)
+static void __ref remove_cpu_from_maps(void)
 {
        int cpu = smp_processor_id();
 
index 09199511c25623057b8f3c60c96069c646ee27b8..7ac7130022f1a73926a392ee2a83d1c366d29164 100644 (file)
@@ -140,7 +140,12 @@ static void fix_processor_context(void)
        int cpu = smp_processor_id();
        struct tss_struct *t = &per_cpu(init_tss, cpu);
 
-       set_tss_desc(cpu,t);    /* This just modifies memory; should not be necessary. But... This is necessary, because 386 hardware has concept of busy TSS or some similar stupidity. */
+       /*
+        * This just modifies memory; should not be necessary. But... This
+        * is necessary, because 386 hardware has concept of busy TSS or some
+        * similar stupidity.
+        */
+       set_tss_desc(cpu, t);
 
        get_cpu_gdt_table(cpu)[GDT_ENTRY_TSS].type = 9;
 
@@ -160,7 +165,6 @@ static void fix_processor_context(void)
                 loaddebug(&current->thread, 6);
                 loaddebug(&current->thread, 7);
        }
-
 }
 
 #ifdef CONFIG_HIBERNATION
index 8344c70adf615264bc509a9d6e6f959a72b771d4..adff5562f5fd4bbc40965ba8eb5f33d433f9f776 100644 (file)
@@ -321,6 +321,8 @@ ENTRY(sys_call_table)
        .long sys_epoll_pwait
        .long sys_utimensat             /* 320 */
        .long sys_signalfd
-       .long sys_timerfd
+       .long sys_timerfd_create
        .long sys_eventfd
        .long sys_fallocate
+       .long sys_timerfd_settime       /* 325 */
+       .long sys_timerfd_gettime
index 6d7ef11e79757610caac0814e1a683c9558f4bd6..36c100c323aa5d1a01d0fdf2316deeba5c3c37ec 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/module.h>
 #include <linux/sort.h>
 #include <asm/uaccess.h>
+#include <asm/asm.h>
 
 extern int rodata_test_data;
 
@@ -89,11 +90,7 @@ static noinline int test_address(void *address)
                "2:     mov %[zero], %[rslt]\n"
                "       ret\n"
                ".previous\n"
-               ".section __ex_table,\"a\"\n"
-               "       .align 8\n"
-               "       .quad 0b\n"
-               "       .quad 2b\n"
-               ".previous\n"
+               _ASM_EXTABLE(0b,2b)
                : [rslt] "=r" (result)
                : [fake_code] "r" (address), [zero] "r" (0UL), "0" (result)
        );
index 78cbb655aa79d1201954a18c542ec9ce85596c5d..e6757aaa202bda9c7dfc1992d3e148fa55541f45 100644 (file)
@@ -57,11 +57,10 @@ void arch_unregister_cpu(int num)
 }
 EXPORT_SYMBOL(arch_unregister_cpu);
 #else
-int arch_register_cpu(int num)
+static int __init arch_register_cpu(int num)
 {
        return register_cpu(&per_cpu(cpu_devices, num).cpu, num);
 }
-EXPORT_SYMBOL(arch_register_cpu);
 #endif /*CONFIG_HOTPLUG_CPU*/
 
 static int __init topology_init(void)
index 9bcc1c6aca3d6b08ac916bd93e9482b128a1074b..64580679861e60371112b9d032d51f6d87c04a96 100644 (file)
  *     trampoline page to make our stack and everything else
  *     is a mystery.
  *
- *     In fact we don't actually need a stack so we don't
- *     set one up.
- *
- *     We jump into the boot/compressed/head.S code. So you'd
- *     better be running a compressed kernel image or you
- *     won't get very far.
+ *     We jump into arch/x86/kernel/head_32.S.
  *
  *     On entry to trampoline_data, the processor is in real mode
  *     with 16-bit addressing and 16-bit data.  CS has some value
index e30b67c6a9f5ddabb5893bef7dd62b07df0239a9..4aedd0bcee4cf58162a7c1296aee4b9bd9691687 100644 (file)
@@ -10,9 +10,6 @@
  *     trampoline page to make our stack and everything else
  *     is a mystery.
  *
- *     In fact we don't actually need a stack so we don't
- *     set one up.
- *
  *     On entry to trampoline_data, the processor is in real mode
  *     with 16-bit addressing and 16-bit data.  CS has some value
  *     and IP is zero.  Thus, data addresses need to be absolute
index 4525bc2c2e19bd88fe00f1b399f2a05efa29454f..12affe1f9bce8d7da1a872880bf41e581e3281c7 100644 (file)
@@ -220,21 +220,21 @@ static void vmi_set_tr(void)
 static void vmi_write_idt_entry(gate_desc *dt, int entry, const gate_desc *g)
 {
        u32 *idt_entry = (u32 *)g;
-       vmi_ops.write_idt_entry(dt, entry, idt_entry[0], idt_entry[2]);
+       vmi_ops.write_idt_entry(dt, entry, idt_entry[0], idt_entry[1]);
 }
 
 static void vmi_write_gdt_entry(struct desc_struct *dt, int entry,
                                const void *desc, int type)
 {
        u32 *gdt_entry = (u32 *)desc;
-       vmi_ops.write_gdt_entry(dt, entry, gdt_entry[0], gdt_entry[2]);
+       vmi_ops.write_gdt_entry(dt, entry, gdt_entry[0], gdt_entry[1]);
 }
 
 static void vmi_write_ldt_entry(struct desc_struct *dt, int entry,
                                const void *desc)
 {
        u32 *ldt_entry = (u32 *)desc;
-       vmi_ops.write_idt_entry(dt, entry, ldt_entry[0], ldt_entry[2]);
+       vmi_ops.write_idt_entry(dt, entry, ldt_entry[0], ldt_entry[1]);
 }
 
 static void vmi_load_sp0(struct tss_struct *tss,
index c83e1c9b5129b3cc96ecfcb8992e378cd7d4119e..41962e793c0fe9f122d22517956535875ea1170f 100644 (file)
@@ -53,5 +53,6 @@ config KVM_AMD
 # OK, it's a little counter-intuitive to do this, but it puts it neatly under
 # the virtualization menu.
 source drivers/lguest/Kconfig
+source drivers/virtio/Kconfig
 
 endif # VIRTUALIZATION
index 8f94a0b89dffd51e5c5387be1b0bb6b1653762bc..cf530814868957a9de8058849538405ca493dcc5 100644 (file)
@@ -1739,7 +1739,7 @@ static int emulator_cmpxchg_emulated(unsigned long addr,
        if (bytes == 8) {
                gpa_t gpa;
                struct page *page;
-               char *addr;
+               char *kaddr;
                u64 val;
 
                down_read(&current->mm->mmap_sem);
@@ -1754,9 +1754,9 @@ static int emulator_cmpxchg_emulated(unsigned long addr,
 
                val = *(u64 *)new;
                page = gfn_to_page(vcpu->kvm, gpa >> PAGE_SHIFT);
-               addr = kmap_atomic(page, KM_USER0);
-               set_64bit((u64 *)(addr + offset_in_page(gpa)), val);
-               kunmap_atomic(addr, KM_USER0);
+               kaddr = kmap_atomic(page, KM_USER0);
+               set_64bit((u64 *)(kaddr + offset_in_page(gpa)), val);
+               kunmap_atomic(kaddr, KM_USER0);
                kvm_release_page_dirty(page);
        emul_write:
                up_read(&current->mm->mmap_sem);
index 4876182daf8a5d1af3bf11516fa6ab2ec0d15283..25df1c1989fe5e5574ba4e833978d99317b168c2 100644 (file)
@@ -21,7 +21,7 @@ else
 
         lib-y += csum-partial_64.o csum-copy_64.o csum-wrappers_64.o
         lib-y += thunk_64.o clear_page_64.o copy_page_64.o
-        lib-y += bitstr_64.o bitops_64.o
+        lib-y += bitops_64.o
         lib-y += memmove_64.o memset_64.o
         lib-y += copy_user_64.o rwlock_64.o copy_user_nocache_64.o
 endif
index afd0045595d470938ef69f6547db0f859b08fbf5..b65440459859e4843ee23a672c05519d2669876b 100644 (file)
@@ -2,7 +2,7 @@
 #include <linux/module.h>
 
 /**
- * find_next_bit - find the first set bit in a memory region
+ * find_next_bit - find the next set bit in a memory region
  * @addr: The address to base the search on
  * @offset: The bitnumber to start searching at
  * @size: The maximum size to search
index 95b6d9639fba60fa9c03c027199bd173f631102b..0e8f491e6ccc84b13ec7c0e82683002f829a862e 100644 (file)
@@ -58,7 +58,7 @@ long find_first_zero_bit(const unsigned long * addr, unsigned long size)
 }
 
 /**
- * find_next_zero_bit - find the first zero bit in a memory region
+ * find_next_zero_bit - find the next zero bit in a memory region
  * @addr: The address to base the search on
  * @offset: The bitnumber to start searching at
  * @size: The maximum size to search
diff --git a/arch/x86/lib/bitstr_64.c b/arch/x86/lib/bitstr_64.c
deleted file mode 100644 (file)
index 7445caf..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-#include <linux/module.h>
-#include <linux/bitops.h>
-
-/* Find string of zero bits in a bitmap */ 
-unsigned long 
-find_next_zero_string(unsigned long *bitmap, long start, long nbits, int len)
-{ 
-       unsigned long n, end, i;        
-
- again:
-       n = find_next_zero_bit(bitmap, nbits, start);
-       if (n == -1) 
-               return -1;
-       
-       /* could test bitsliced, but it's hardly worth it */
-       end = n+len;
-       if (end > nbits)
-               return -1; 
-       for (i = n+1; i < end; i++) { 
-               if (test_bit(i, bitmap)) {  
-                       start = i+1; 
-                       goto again; 
-               } 
-       }
-       return n;
-}
-
-EXPORT_SYMBOL(find_next_zero_string);
index 28084d2e8dd4d96f8371a629f206406b05031203..cc9b4a4450f3fe3fc344f34114fc3d9ec4cd4fe4 100644 (file)
@@ -4,6 +4,7 @@
 #include <linux/hardirq.h>
 #include <linux/module.h>
 
+#include <asm/asm.h>
 #include <asm/i387.h>
 
 
@@ -50,10 +51,7 @@ void *_mmx_memcpy(void *to, const void *from, size_t len)
                "3: movw $0x1AEB, 1b\n" /* jmp on 26 bytes */
                "   jmp 2b\n"
                ".previous\n"
-               ".section __ex_table,\"a\"\n"
-               "       .align 4\n"
-               "       .long 1b, 3b\n"
-               ".previous"
+               _ASM_EXTABLE(1b,3b)
                : : "r" (from) );
                
        
@@ -81,10 +79,7 @@ void *_mmx_memcpy(void *to, const void *from, size_t len)
                "3: movw $0x05EB, 1b\n" /* jmp on 5 bytes */
                "   jmp 2b\n"
                ".previous\n"
-               ".section __ex_table,\"a\"\n"
-               "       .align 4\n"
-               "       .long 1b, 3b\n"
-               ".previous"
+               _ASM_EXTABLE(1b,3b)
                : : "r" (from), "r" (to) : "memory");
                from+=64;
                to+=64;
@@ -181,10 +176,7 @@ static void fast_copy_page(void *to, void *from)
                "3: movw $0x1AEB, 1b\n" /* jmp on 26 bytes */
                "   jmp 2b\n"
                ".previous\n"
-               ".section __ex_table,\"a\"\n"
-               "       .align 4\n"
-               "       .long 1b, 3b\n"
-               ".previous"
+               _ASM_EXTABLE(1b,3b)
                : : "r" (from) );
 
        for(i=0; i<(4096-320)/64; i++)
@@ -211,10 +203,7 @@ static void fast_copy_page(void *to, void *from)
                "3: movw $0x05EB, 1b\n" /* jmp on 5 bytes */
                "   jmp 2b\n"
                ".previous\n"
-               ".section __ex_table,\"a\"\n"
-               "       .align 4\n"
-               "       .long 1b, 3b\n"
-               ".previous"
+               _ASM_EXTABLE(1b,3b)
                : : "r" (from), "r" (to) : "memory");
                from+=64;
                to+=64;
@@ -311,10 +300,7 @@ static void fast_copy_page(void *to, void *from)
                "3: movw $0x1AEB, 1b\n" /* jmp on 26 bytes */
                "   jmp 2b\n"
                ".previous\n"
-               ".section __ex_table,\"a\"\n"
-               "       .align 4\n"
-               "       .long 1b, 3b\n"
-               ".previous"
+               _ASM_EXTABLE(1b,3b)
                : : "r" (from) );
 
        for(i=0; i<4096/64; i++)
@@ -341,10 +327,7 @@ static void fast_copy_page(void *to, void *from)
                "3: movw $0x05EB, 1b\n" /* jmp on 5 bytes */
                "   jmp 2b\n"
                ".previous\n"
-               ".section __ex_table,\"a\"\n"
-               "       .align 4\n"
-               "       .long 1b, 3b\n"
-               ".previous"
+               _ASM_EXTABLE(1b,3b)
                : : "r" (from), "r" (to) : "memory");
                from+=64;
                to+=64;
index 8bab2b2efaff86c2707ccc929b996f5a245cecd5..e849b9998b0e1577519a96f9f110893bfab804ca 100644 (file)
@@ -48,10 +48,7 @@ do {                                                                    \
                "3:     movl %5,%0\n"                                      \
                "       jmp 2b\n"                                          \
                ".previous\n"                                              \
-               ".section __ex_table,\"a\"\n"                              \
-               "       .align 4\n"                                        \
-               "       .long 0b,3b\n"                                     \
-               ".previous"                                                \
+               _ASM_EXTABLE(0b,3b)                                        \
                : "=d"(res), "=c"(count), "=&a" (__d0), "=&S" (__d1),      \
                  "=&D" (__d2)                                             \
                : "i"(-EFAULT), "0"(count), "1"(count), "3"(src), "4"(dst) \
@@ -132,11 +129,8 @@ do {                                                                       \
                "3:     lea 0(%2,%0,4),%0\n"                            \
                "       jmp 2b\n"                                       \
                ".previous\n"                                           \
-               ".section __ex_table,\"a\"\n"                           \
-               "       .align 4\n"                                     \
-               "       .long 0b,3b\n"                                  \
-               "       .long 1b,2b\n"                                  \
-               ".previous"                                             \
+               _ASM_EXTABLE(0b,3b)                                     \
+               _ASM_EXTABLE(1b,2b)                                     \
                : "=&c"(size), "=&D" (__d0)                             \
                : "r"(size & 3), "0"(size / 4), "1"(addr), "a"(0));     \
 } while (0)
@@ -817,6 +811,7 @@ unsigned long __copy_from_user_ll_nocache(void *to, const void __user *from,
 #endif
        return n;
 }
+EXPORT_SYMBOL(__copy_from_user_ll_nocache);
 
 unsigned long __copy_from_user_ll_nocache_nozero(void *to, const void __user *from,
                                        unsigned long n)
@@ -831,6 +826,7 @@ unsigned long __copy_from_user_ll_nocache_nozero(void *to, const void __user *fr
 #endif
        return n;
 }
+EXPORT_SYMBOL(__copy_from_user_ll_nocache_nozero);
 
 /**
  * copy_to_user: - Copy a block of data into user space.
index 893d43f838ccd0186a6ef6869594358de12fd303..0c89d1bb02871e0324b57418d5390535c1780c2b 100644 (file)
@@ -31,10 +31,7 @@ do {                                                                    \
                "3:     movq %5,%0\n"                                      \
                "       jmp 2b\n"                                          \
                ".previous\n"                                              \
-               ".section __ex_table,\"a\"\n"                              \
-               "       .align 8\n"                                        \
-               "       .quad 0b,3b\n"                                     \
-               ".previous"                                                \
+               _ASM_EXTABLE(0b,3b)                                        \
                : "=r"(res), "=c"(count), "=&a" (__d0), "=&S" (__d1),      \
                  "=&D" (__d2)                                             \
                : "i"(-EFAULT), "0"(count), "1"(count), "3"(src), "4"(dst) \
@@ -87,11 +84,8 @@ unsigned long __clear_user(void __user *addr, unsigned long size)
                "3:     lea 0(%[size1],%[size8],8),%[size8]\n"
                "       jmp 2b\n"
                ".previous\n"
-               ".section __ex_table,\"a\"\n"
-               "       .align 8\n"
-               "       .quad 0b,3b\n"
-               "       .quad 1b,2b\n"
-               ".previous"
+               _ASM_EXTABLE(0b,3b)
+               _ASM_EXTABLE(1b,2b)
                : [size8] "=c"(size), [dst] "=&D" (__d0)
                : [size1] "r"(size & 7), "[size8]" (size / 8), "[dst]"(addr),
                  [zero] "r" (0UL), [eight] "r" (8UL));
index e28cc5277b167c3907075b0f610342cd7a2ceec8..ad8b9733d6b3fee4d2f90e2981e54dc2b71299e4 100644 (file)
@@ -240,7 +240,8 @@ void dump_pagetable(unsigned long address)
        pud = pud_offset(pgd, address);
        if (bad_address(pud)) goto bad;
        printk("PUD %lx ", pud_val(*pud));
-       if (!pud_present(*pud)) goto ret;
+       if (!pud_present(*pud) || pud_large(*pud))
+               goto ret;
 
        pmd = pmd_offset(pud, address);
        if (bad_address(pmd)) goto bad;
@@ -382,7 +383,7 @@ static void show_fault_oops(struct pt_regs *regs, unsigned long error_code,
 
 #ifdef CONFIG_X86_PAE
        if (error_code & PF_INSTR) {
-               int level;
+               unsigned int level;
                pte_t *pte = lookup_address(address, &level);
 
                if (pte && pte_present(*pte) && !pte_exec(*pte))
@@ -508,6 +509,10 @@ static int vmalloc_fault(unsigned long address)
        pmd_t *pmd, *pmd_ref;
        pte_t *pte, *pte_ref;
 
+       /* Make sure we are in vmalloc area */
+       if (!(address >= VMALLOC_START && address < VMALLOC_END))
+               return -1;
+
        /* Copy kernel mappings over when needed. This can also
           happen within a race in page table update. In the later
           case just flush. */
@@ -603,6 +608,9 @@ void __kprobes do_page_fault(struct pt_regs *regs, unsigned long error_code)
         */
 #ifdef CONFIG_X86_32
        if (unlikely(address >= TASK_SIZE)) {
+#else
+       if (unlikely(address >= TASK_SIZE64)) {
+#endif
                if (!(error_code & (PF_RSVD|PF_USER|PF_PROT)) &&
                    vmalloc_fault(address) >= 0)
                        return;
@@ -618,6 +626,8 @@ void __kprobes do_page_fault(struct pt_regs *regs, unsigned long error_code)
                goto bad_area_nosemaphore;
        }
 
+
+#ifdef CONFIG_X86_32
        /* It's safe to allow irq's after cr2 has been saved and the vmalloc
           fault has been handled. */
        if (regs->flags & (X86_EFLAGS_IF|VM_MASK))
@@ -630,28 +640,6 @@ void __kprobes do_page_fault(struct pt_regs *regs, unsigned long error_code)
        if (in_atomic() || !mm)
                goto bad_area_nosemaphore;
 #else /* CONFIG_X86_64 */
-       if (unlikely(address >= TASK_SIZE64)) {
-               /*
-                * Don't check for the module range here: its PML4
-                * is always initialized because it's shared with the main
-                * kernel text. Only vmalloc may need PML4 syncups.
-                */
-               if (!(error_code & (PF_RSVD|PF_USER|PF_PROT)) &&
-                     ((address >= VMALLOC_START && address < VMALLOC_END))) {
-                       if (vmalloc_fault(address) >= 0)
-                               return;
-               }
-
-               /* Can handle a stale RO->RW TLB */
-               if (spurious_fault(address, error_code))
-                       return;
-
-               /*
-                * Don't take the mm semaphore here. If we fixup a prefetch
-                * fault we could otherwise deadlock.
-                */
-               goto bad_area_nosemaphore;
-       }
        if (likely(regs->flags & X86_EFLAGS_IF))
                local_irq_enable();
 
index da524fb22422eafc8b4d6514609aec749ffc2dc0..d1bc04006d16e12fc706fe10b942e01cde3bb2d5 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/initrd.h>
 #include <linux/cpumask.h>
 
+#include <asm/asm.h>
 #include <asm/processor.h>
 #include <asm/system.h>
 #include <asm/uaccess.h>
@@ -423,23 +424,23 @@ static void __init pagetable_init(void)
        paravirt_pagetable_setup_done(pgd_base);
 }
 
-#if defined(CONFIG_HIBERNATION) || defined(CONFIG_ACPI)
+#ifdef CONFIG_ACPI_SLEEP
 /*
- * Swap suspend & friends need this for resume because things like the intel-agp
+ * ACPI suspend needs this for resume, because things like the intel-agp
  * driver might have split up a kernel 4MB mapping.
  */
-char __nosavedata swsusp_pg_dir[PAGE_SIZE]
+char swsusp_pg_dir[PAGE_SIZE]
        __attribute__ ((aligned(PAGE_SIZE)));
 
 static inline void save_pg_dir(void)
 {
        memcpy(swsusp_pg_dir, swapper_pg_dir, PAGE_SIZE);
 }
-#else
+#else /* !CONFIG_ACPI_SLEEP */
 static inline void save_pg_dir(void)
 {
 }
-#endif
+#endif /* !CONFIG_ACPI_SLEEP */
 
 void zap_low_mappings(void)
 {
@@ -718,10 +719,7 @@ static noinline int do_test_wp_bit(void)
                "1:     movb %1, %0     \n"
                "       xorl %2, %2     \n"
                "2:                     \n"
-               ".section __ex_table, \"a\"\n"
-               "       .align 4        \n"
-               "       .long 1b, 2b    \n"
-               ".previous              \n"
+               _ASM_EXTABLE(1b,2b)
                :"=m" (*(char *)fix_to_virt(FIX_WP_TEST)),
                 "=q" (tmp_reg),
                 "=r" (flag)
index cc50a13ce8d9d855f9f29e884843ed8717c1e0b2..3a98d6f724ab69b9ed4d075a0a14895efe482dbc 100644 (file)
@@ -273,7 +273,6 @@ phys_pmd_init(pmd_t *pmd_page, unsigned long address, unsigned long end)
        int i = pmd_index(address);
 
        for (; i < PTRS_PER_PMD; i++, address += PMD_SIZE) {
-               unsigned long entry;
                pmd_t *pmd = pmd_page + pmd_index(address);
 
                if (address >= end) {
@@ -287,9 +286,8 @@ phys_pmd_init(pmd_t *pmd_page, unsigned long address, unsigned long end)
                if (pmd_val(*pmd))
                        continue;
 
-               entry = __PAGE_KERNEL_LARGE|_PAGE_GLOBAL|address;
-               entry &= __supported_pte_mask;
-               set_pmd(pmd, __pmd(entry));
+               set_pte((pte_t *)pmd,
+                       pfn_pte(address >> PAGE_SHIFT, PAGE_KERNEL_LARGE));
        }
 }
 
@@ -354,17 +352,10 @@ static void __init find_early_table_space(unsigned long end)
         * need roughly 0.5KB per GB.
         */
        start = 0x8000;
-       table_start = find_e820_area(start, end, tables);
+       table_start = find_e820_area(start, end, tables, PAGE_SIZE);
        if (table_start == -1UL)
                panic("Cannot find space for the kernel page tables");
 
-       /*
-        * When you have a lot of RAM like 256GB, early_table will not fit
-        * into 0x8000 range, find_e820_area() will find area after kernel
-        * bss but the table_start is not page aligned, so need to round it
-        * up to avoid overlap with bss:
-        */
-       table_start = round_up(table_start, PAGE_SIZE);
        table_start >>= PAGE_SHIFT;
        table_end = table_start;
 
@@ -420,7 +411,9 @@ void __init_refok init_memory_mapping(unsigned long start, unsigned long end)
                mmu_cr4_features = read_cr4();
        __flush_tlb_all();
 
-       reserve_early(table_start << PAGE_SHIFT, table_end << PAGE_SHIFT);
+       if (!after_bootmem)
+               reserve_early(table_start << PAGE_SHIFT,
+                                table_end << PAGE_SHIFT, "PGTABLE");
 }
 
 #ifndef CONFIG_NUMA
@@ -439,49 +432,6 @@ void __init paging_init(void)
 }
 #endif
 
-/*
- * Unmap a kernel mapping if it exists. This is useful to avoid
- * prefetches from the CPU leading to inconsistent cache lines.
- * address and size must be aligned to 2MB boundaries.
- * Does nothing when the mapping doesn't exist.
- */
-void __init clear_kernel_mapping(unsigned long address, unsigned long size)
-{
-       unsigned long end = address + size;
-
-       BUG_ON(address & ~LARGE_PAGE_MASK);
-       BUG_ON(size & ~LARGE_PAGE_MASK);
-
-       for (; address < end; address += LARGE_PAGE_SIZE) {
-               pgd_t *pgd = pgd_offset_k(address);
-               pud_t *pud;
-               pmd_t *pmd;
-
-               if (pgd_none(*pgd))
-                       continue;
-
-               pud = pud_offset(pgd, address);
-               if (pud_none(*pud))
-                       continue;
-
-               pmd = pmd_offset(pud, address);
-               if (!pmd || pmd_none(*pmd))
-                       continue;
-
-               if (!(pmd_val(*pmd) & _PAGE_PSE)) {
-                       /*
-                        * Could handle this, but it should not happen
-                        * currently:
-                        */
-                       printk(KERN_ERR "clear_kernel_mapping: "
-                               "mapping has been split. will leak memory\n");
-                       pmd_ERROR(*pmd);
-               }
-               set_pmd(pmd, __pmd(0));
-       }
-       __flush_tlb_all();
-}
-
 /*
  * Memory hotplug specific functions
  */
index ed795721ca8ea2e9d81c4b2dbca082efb2262126..ee6648fe6b15de75a4e0fe53a90f6311fa8b917a 100644 (file)
@@ -70,23 +70,11 @@ int page_is_ram(unsigned long pagenr)
  * Fix up the linear direct mapping of the kernel to avoid cache attribute
  * conflicts.
  */
-static int ioremap_change_attr(unsigned long paddr, unsigned long size,
+static int ioremap_change_attr(unsigned long vaddr, unsigned long size,
                               enum ioremap_mode mode)
 {
-       unsigned long vaddr = (unsigned long)__va(paddr);
        unsigned long nrpages = size >> PAGE_SHIFT;
-       int err, level;
-
-       /* No change for pages after the last mapping */
-       if ((paddr + size - 1) >= (max_pfn_mapped << PAGE_SHIFT))
-               return 0;
-
-       /*
-        * If there is no identity map for this address,
-        * change_page_attr_addr is unnecessary
-        */
-       if (!lookup_address(vaddr, &level))
-               return 0;
+       int err;
 
        switch (mode) {
        case IOR_MODE_UNCACHED:
@@ -113,9 +101,8 @@ static int ioremap_change_attr(unsigned long paddr, unsigned long size,
 static void __iomem *__ioremap(unsigned long phys_addr, unsigned long size,
                               enum ioremap_mode mode)
 {
-       void __iomem *addr;
+       unsigned long pfn, offset, last_addr, vaddr;
        struct vm_struct *area;
-       unsigned long offset, last_addr;
        pgprot_t prot;
 
        /* Don't allow wraparound or zero size */
@@ -132,9 +119,10 @@ static void __iomem *__ioremap(unsigned long phys_addr, unsigned long size,
        /*
         * Don't allow anybody to remap normal RAM that we're using..
         */
-       for (offset = phys_addr >> PAGE_SHIFT; offset < max_pfn_mapped &&
-            (offset << PAGE_SHIFT) < last_addr; offset++) {
-               if (page_is_ram(offset))
+       for (pfn = phys_addr >> PAGE_SHIFT; pfn < max_pfn_mapped &&
+            (pfn << PAGE_SHIFT) < last_addr; pfn++) {
+               if (page_is_ram(pfn) && pfn_valid(pfn) &&
+                   !PageReserved(pfn_to_page(pfn)))
                        return NULL;
        }
 
@@ -162,19 +150,18 @@ static void __iomem *__ioremap(unsigned long phys_addr, unsigned long size,
        if (!area)
                return NULL;
        area->phys_addr = phys_addr;
-       addr = (void __iomem *) area->addr;
-       if (ioremap_page_range((unsigned long)addr, (unsigned long)addr + size,
-                              phys_addr, prot)) {
-               remove_vm_area((void *)(PAGE_MASK & (unsigned long) addr));
+       vaddr = (unsigned long) area->addr;
+       if (ioremap_page_range(vaddr, vaddr + size, phys_addr, prot)) {
+               remove_vm_area((void *)(vaddr & PAGE_MASK));
                return NULL;
        }
 
-       if (ioremap_change_attr(phys_addr, size, mode) < 0) {
-               vunmap(addr);
+       if (ioremap_change_attr(vaddr, size, mode) < 0) {
+               vunmap(area->addr);
                return NULL;
        }
 
-       return (void __iomem *) (offset + (char __iomem *)addr);
+       return (void __iomem *) (vaddr + offset);
 }
 
 /**
@@ -253,9 +240,6 @@ void iounmap(volatile void __iomem *addr)
                return;
        }
 
-       /* Reset the direct mapping. Can block */
-       ioremap_change_attr(p->phys_addr, p->size, IOR_MODE_CACHED);
-
        /* Finally remove it */
        o = remove_vm_area((void *)addr);
        BUG_ON(p != o || o == NULL);
@@ -340,7 +324,7 @@ void __init early_ioremap_reset(void)
        for (idx = FIX_BTMAP_BEGIN; idx >= FIX_BTMAP_END; idx--) {
                addr = fix_to_virt(idx);
                pte = early_ioremap_pte(addr);
-               if (!*pte & _PAGE_PRESENT) {
+               if (*pte & _PAGE_PRESENT) {
                        phys = *pte & PAGE_MASK;
                        set_fixmap(idx, phys);
                }
index dc3b1f7e1451ba46221524860aa0cf54c7e564bb..5a02bf4c91ec7eac8b9c25da1cf1f666bc2b961f 100644 (file)
@@ -84,26 +84,24 @@ static int __init populate_memnodemap(const struct bootnode *nodes,
 
 static int __init allocate_cachealigned_memnodemap(void)
 {
-       unsigned long pad, pad_addr;
+       unsigned long addr;
 
        memnodemap = memnode.embedded_map;
        if (memnodemapsize <= ARRAY_SIZE(memnode.embedded_map))
                return 0;
 
-       pad = L1_CACHE_BYTES - 1;
-       pad_addr = 0x8000;
-       nodemap_size = pad + sizeof(s16) * memnodemapsize;
-       nodemap_addr = find_e820_area(pad_addr, end_pfn<<PAGE_SHIFT,
-                                     nodemap_size);
+       addr = 0x8000;
+       nodemap_size = round_up(sizeof(s16) * memnodemapsize, L1_CACHE_BYTES);
+       nodemap_addr = find_e820_area(addr, end_pfn<<PAGE_SHIFT,
+                                     nodemap_size, L1_CACHE_BYTES);
        if (nodemap_addr == -1UL) {
                printk(KERN_ERR
                       "NUMA: Unable to allocate Memory to Node hash map\n");
                nodemap_addr = nodemap_size = 0;
                return -1;
        }
-       pad_addr = (nodemap_addr + pad) & ~pad;
-       memnodemap = phys_to_virt(pad_addr);
-       reserve_early(nodemap_addr, nodemap_addr + nodemap_size);
+       memnodemap = phys_to_virt(nodemap_addr);
+       reserve_early(nodemap_addr, nodemap_addr + nodemap_size, "MEMNODEMAP");
 
        printk(KERN_DEBUG "NUMA: Allocated memnodemap from %lx - %lx\n",
               nodemap_addr, nodemap_addr + nodemap_size);
@@ -164,15 +162,16 @@ int early_pfn_to_nid(unsigned long pfn)
 }
 
 static void * __init early_node_mem(int nodeid, unsigned long start,
-                                   unsigned long end, unsigned long size)
+                                   unsigned long end, unsigned long size,
+                                   unsigned long align)
 {
-       unsigned long mem = find_e820_area(start, end, size);
+       unsigned long mem = find_e820_area(start, end, size, align);
        void *ptr;
 
        if (mem != -1L)
                return __va(mem);
-       ptr = __alloc_bootmem_nopanic(size,
-                               SMP_CACHE_BYTES, __pa(MAX_DMA_ADDRESS));
+
+       ptr = __alloc_bootmem_nopanic(size, align, __pa(MAX_DMA_ADDRESS));
        if (ptr == NULL) {
                printk(KERN_ERR "Cannot find %lu bytes in node %d\n",
                       size, nodeid);
@@ -198,10 +197,13 @@ void __init setup_node_bootmem(int nodeid, unsigned long start,
        start_pfn = start >> PAGE_SHIFT;
        end_pfn = end >> PAGE_SHIFT;
 
-       node_data[nodeid] = early_node_mem(nodeid, start, end, pgdat_size);
+       node_data[nodeid] = early_node_mem(nodeid, start, end, pgdat_size,
+                                          SMP_CACHE_BYTES);
        if (node_data[nodeid] == NULL)
                return;
        nodedata_phys = __pa(node_data[nodeid]);
+       printk(KERN_INFO "  NODE_DATA [%016lx - %016lx]\n", nodedata_phys,
+               nodedata_phys + pgdat_size - 1);
 
        memset(NODE_DATA(nodeid), 0, sizeof(pg_data_t));
        NODE_DATA(nodeid)->bdata = &plat_node_bdata[nodeid];
@@ -211,8 +213,12 @@ void __init setup_node_bootmem(int nodeid, unsigned long start,
        /* Find a place for the bootmem map */
        bootmap_pages = bootmem_bootmap_pages(end_pfn - start_pfn);
        bootmap_start = round_up(nodedata_phys + pgdat_size, PAGE_SIZE);
+       /*
+        * SMP_CAHCE_BYTES could be enough, but init_bootmem_node like
+        * to use that to align to PAGE_SIZE
+        */
        bootmap = early_node_mem(nodeid, bootmap_start, end,
-                                       bootmap_pages<<PAGE_SHIFT);
+                                bootmap_pages<<PAGE_SHIFT, PAGE_SIZE);
        if (bootmap == NULL)  {
                if (nodedata_phys < start || nodedata_phys >= end)
                        free_bootmem((unsigned long)node_data[nodeid],
@@ -221,12 +227,15 @@ void __init setup_node_bootmem(int nodeid, unsigned long start,
                return;
        }
        bootmap_start = __pa(bootmap);
-       Dprintk("bootmap start %lu pages %lu\n", bootmap_start, bootmap_pages);
 
        bootmap_size = init_bootmem_node(NODE_DATA(nodeid),
                                         bootmap_start >> PAGE_SHIFT,
                                         start_pfn, end_pfn);
 
+       printk(KERN_INFO "  bootmap [%016lx -  %016lx] pages %lx\n",
+                bootmap_start, bootmap_start + bootmap_size - 1,
+                bootmap_pages);
+
        free_bootmem_with_active_regions(nodeid, end);
 
        reserve_bootmem_node(NODE_DATA(nodeid), nodedata_phys, pgdat_size);
index 06353d43f72e073cc01034502d426a37f90d015e..398f3a578dde446e292109a6463409f1b70d3415 100644 (file)
@@ -42,7 +42,7 @@ static __init int print_split(struct split_state *s)
        s->max_exec = 0;
        for (i = 0; i < max_pfn_mapped; ) {
                unsigned long addr = (unsigned long)__va(i << PAGE_SHIFT);
-               int level;
+               unsigned int level;
                pte_t *pte;
 
                pte = lookup_address(addr, &level);
@@ -106,7 +106,7 @@ static __init int exercise_pageattr(void)
        unsigned long *bm;
        pte_t *pte, pte0;
        int failed = 0;
-       int level;
+       unsigned int level;
        int i, k;
        int err;
 
@@ -137,7 +137,8 @@ static __init int exercise_pageattr(void)
 
                for (k = 0; k < len[i]; k++) {
                        pte = lookup_address(addr[i] + k*PAGE_SIZE, &level);
-                       if (!pte || pgprot_val(pte_pgprot(*pte)) == 0) {
+                       if (!pte || pgprot_val(pte_pgprot(*pte)) == 0 ||
+                           !(pte_val(*pte) & _PAGE_PRESENT)) {
                                addr[i] = 0;
                                break;
                        }
index 1cc6607eacb072c64c789ccdaeffa4f97330a804..16ce841f08d6600170a8cf223a80f04cec1376d9 100644 (file)
 #include <asm/uaccess.h>
 #include <asm/pgalloc.h>
 
+/*
+ * The current flushing context - we pass it instead of 5 arguments:
+ */
+struct cpa_data {
+       unsigned long   vaddr;
+       pgprot_t        mask_set;
+       pgprot_t        mask_clr;
+       int             numpages;
+       int             flushtlb;
+};
+
 static inline int
 within(unsigned long addr, unsigned long start, unsigned long end)
 {
@@ -52,21 +63,23 @@ void clflush_cache_range(void *vaddr, unsigned int size)
 
 static void __cpa_flush_all(void *arg)
 {
+       unsigned long cache = (unsigned long)arg;
+
        /*
         * Flush all to work around Errata in early athlons regarding
         * large page flushing.
         */
        __flush_tlb_all();
 
-       if (boot_cpu_data.x86_model >= 4)
+       if (cache && boot_cpu_data.x86_model >= 4)
                wbinvd();
 }
 
-static void cpa_flush_all(void)
+static void cpa_flush_all(unsigned long cache)
 {
        BUG_ON(irqs_disabled());
 
-       on_each_cpu(__cpa_flush_all, NULL, 1, 1);
+       on_each_cpu(__cpa_flush_all, (void *) cache, 1, 1);
 }
 
 static void __cpa_flush_range(void *arg)
@@ -79,7 +92,7 @@ static void __cpa_flush_range(void *arg)
        __flush_tlb_all();
 }
 
-static void cpa_flush_range(unsigned long start, int numpages)
+static void cpa_flush_range(unsigned long start, int numpages, int cache)
 {
        unsigned int i, level;
        unsigned long addr;
@@ -89,6 +102,9 @@ static void cpa_flush_range(unsigned long start, int numpages)
 
        on_each_cpu(__cpa_flush_range, NULL, 1, 1);
 
+       if (!cache)
+               return;
+
        /*
         * We only need to flush on one CPU,
         * clflush is a MESI-coherent instruction that
@@ -101,11 +117,27 @@ static void cpa_flush_range(unsigned long start, int numpages)
                /*
                 * Only flush present addresses:
                 */
-               if (pte && pte_present(*pte))
+               if (pte && (pte_val(*pte) & _PAGE_PRESENT))
                        clflush_cache_range((void *) addr, PAGE_SIZE);
        }
 }
 
+#define HIGH_MAP_START __START_KERNEL_map
+#define HIGH_MAP_END   (__START_KERNEL_map + KERNEL_TEXT_SIZE)
+
+
+/*
+ * Converts a virtual address to a X86-64 highmap address
+ */
+static unsigned long virt_to_highmap(void *address)
+{
+#ifdef CONFIG_X86_64
+       return __pa((unsigned long)address) + HIGH_MAP_START - phys_base;
+#else
+       return (unsigned long)address;
+#endif
+}
+
 /*
  * Certain areas of memory on x86 require very specific protection flags,
  * for example the BIOS area or kernel text. Callers don't always get this
@@ -129,12 +161,24 @@ static inline pgprot_t static_protections(pgprot_t prot, unsigned long address)
         */
        if (within(address, (unsigned long)_text, (unsigned long)_etext))
                pgprot_val(forbidden) |= _PAGE_NX;
+       /*
+        * Do the same for the x86-64 high kernel mapping
+        */
+       if (within(address, virt_to_highmap(_text), virt_to_highmap(_etext)))
+               pgprot_val(forbidden) |= _PAGE_NX;
+
 
 #ifdef CONFIG_DEBUG_RODATA
        /* The .rodata section needs to be read-only */
        if (within(address, (unsigned long)__start_rodata,
                                (unsigned long)__end_rodata))
                pgprot_val(forbidden) |= _PAGE_RW;
+       /*
+        * Do the same for the x86-64 high kernel mapping
+        */
+       if (within(address, virt_to_highmap(__start_rodata),
+                               virt_to_highmap(__end_rodata)))
+               pgprot_val(forbidden) |= _PAGE_RW;
 #endif
 
        prot = __pgprot(pgprot_val(prot) & ~pgprot_val(forbidden));
@@ -142,6 +186,14 @@ static inline pgprot_t static_protections(pgprot_t prot, unsigned long address)
        return prot;
 }
 
+/*
+ * Lookup the page table entry for a virtual address. Return a pointer
+ * to the entry and the level of the mapping.
+ *
+ * Note: We return pud and pmd either when the entry is marked large
+ * or when the present bit is not set. Otherwise we would return a
+ * pointer to a nonexisting mapping.
+ */
 pte_t *lookup_address(unsigned long address, int *level)
 {
        pgd_t *pgd = pgd_offset_k(address);
@@ -152,21 +204,31 @@ pte_t *lookup_address(unsigned long address, int *level)
 
        if (pgd_none(*pgd))
                return NULL;
+
        pud = pud_offset(pgd, address);
        if (pud_none(*pud))
                return NULL;
+
+       *level = PG_LEVEL_1G;
+       if (pud_large(*pud) || !pud_present(*pud))
+               return (pte_t *)pud;
+
        pmd = pmd_offset(pud, address);
        if (pmd_none(*pmd))
                return NULL;
 
        *level = PG_LEVEL_2M;
-       if (pmd_large(*pmd))
+       if (pmd_large(*pmd) || !pmd_present(*pmd))
                return (pte_t *)pmd;
 
        *level = PG_LEVEL_4K;
+
        return pte_offset_kernel(pmd, address);
 }
 
+/*
+ * Set the new pmd in all the pgds we know about:
+ */
 static void __set_pmd_pte(pte_t *kpte, unsigned long address, pte_t pte)
 {
        /* change init_mm */
@@ -189,18 +251,114 @@ static void __set_pmd_pte(pte_t *kpte, unsigned long address, pte_t pte)
 #endif
 }
 
+static int
+try_preserve_large_page(pte_t *kpte, unsigned long address,
+                       struct cpa_data *cpa)
+{
+       unsigned long nextpage_addr, numpages, pmask, psize, flags;
+       pte_t new_pte, old_pte, *tmp;
+       pgprot_t old_prot, new_prot;
+       int level, do_split = 1;
+
+       /*
+        * An Athlon 64 X2 showed hard hangs if we tried to preserve
+        * largepages and changed the PSE entry from RW to RO.
+        *
+        * As AMD CPUs have a long series of erratas in this area,
+        * (and none of the known ones seem to explain this hang),
+        * disable this code until the hang can be debugged:
+        */
+       if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD)
+               return 1;
+
+       spin_lock_irqsave(&pgd_lock, flags);
+       /*
+        * Check for races, another CPU might have split this page
+        * up already:
+        */
+       tmp = lookup_address(address, &level);
+       if (tmp != kpte)
+               goto out_unlock;
+
+       switch (level) {
+       case PG_LEVEL_2M:
+               psize = PMD_PAGE_SIZE;
+               pmask = PMD_PAGE_MASK;
+               break;
+#ifdef CONFIG_X86_64
+       case PG_LEVEL_1G:
+               psize = PMD_PAGE_SIZE;
+               pmask = PMD_PAGE_MASK;
+               break;
+#endif
+       default:
+               do_split = -EINVAL;
+               goto out_unlock;
+       }
+
+       /*
+        * Calculate the number of pages, which fit into this large
+        * page starting at address:
+        */
+       nextpage_addr = (address + psize) & pmask;
+       numpages = (nextpage_addr - address) >> PAGE_SHIFT;
+       if (numpages < cpa->numpages)
+               cpa->numpages = numpages;
+
+       /*
+        * We are safe now. Check whether the new pgprot is the same:
+        */
+       old_pte = *kpte;
+       old_prot = new_prot = pte_pgprot(old_pte);
+
+       pgprot_val(new_prot) &= ~pgprot_val(cpa->mask_clr);
+       pgprot_val(new_prot) |= pgprot_val(cpa->mask_set);
+       new_prot = static_protections(new_prot, address);
+
+       /*
+        * If there are no changes, return. maxpages has been updated
+        * above:
+        */
+       if (pgprot_val(new_prot) == pgprot_val(old_prot)) {
+               do_split = 0;
+               goto out_unlock;
+       }
+
+       /*
+        * We need to change the attributes. Check, whether we can
+        * change the large page in one go. We request a split, when
+        * the address is not aligned and the number of pages is
+        * smaller than the number of pages in the large page. Note
+        * that we limited the number of possible pages already to
+        * the number of pages in the large page.
+        */
+       if (address == (nextpage_addr - psize) && cpa->numpages == numpages) {
+               /*
+                * The address is aligned and the number of pages
+                * covers the full page.
+                */
+               new_pte = pfn_pte(pte_pfn(old_pte), canon_pgprot(new_prot));
+               __set_pmd_pte(kpte, address, new_pte);
+               cpa->flushtlb = 1;
+               do_split = 0;
+       }
+
+out_unlock:
+       spin_unlock_irqrestore(&pgd_lock, flags);
+
+       return do_split;
+}
+
 static int split_large_page(pte_t *kpte, unsigned long address)
 {
-       pgprot_t ref_prot = pte_pgprot(pte_clrhuge(*kpte));
+       unsigned long flags, pfn, pfninc = 1;
        gfp_t gfp_flags = GFP_KERNEL;
-       unsigned long flags;
-       unsigned long addr;
+       unsigned int i, level;
        pte_t *pbase, *tmp;
+       pgprot_t ref_prot;
        struct page *base;
-       unsigned int i, level;
 
 #ifdef CONFIG_DEBUG_PAGEALLOC
-       gfp_flags = __GFP_HIGH | __GFP_NOFAIL | __GFP_NOWARN;
        gfp_flags = GFP_ATOMIC | __GFP_NOWARN;
 #endif
        base = alloc_pages(gfp_flags, 0);
@@ -213,30 +371,41 @@ static int split_large_page(pte_t *kpte, unsigned long address)
         * up for us already:
         */
        tmp = lookup_address(address, &level);
-       if (tmp != kpte) {
-               WARN_ON_ONCE(1);
+       if (tmp != kpte)
                goto out_unlock;
-       }
 
-       address = __pa(address);
-       addr = address & LARGE_PAGE_MASK;
        pbase = (pte_t *)page_address(base);
 #ifdef CONFIG_X86_32
        paravirt_alloc_pt(&init_mm, page_to_pfn(base));
 #endif
+       ref_prot = pte_pgprot(pte_clrhuge(*kpte));
 
-       pgprot_val(ref_prot) &= ~_PAGE_NX;
-       for (i = 0; i < PTRS_PER_PTE; i++, addr += PAGE_SIZE)
-               set_pte(&pbase[i], pfn_pte(addr >> PAGE_SHIFT, ref_prot));
+#ifdef CONFIG_X86_64
+       if (level == PG_LEVEL_1G) {
+               pfninc = PMD_PAGE_SIZE >> PAGE_SHIFT;
+               pgprot_val(ref_prot) |= _PAGE_PSE;
+       }
+#endif
 
        /*
-        * Install the new, split up pagetable. Important detail here:
+        * Get the target pfn from the original entry:
+        */
+       pfn = pte_pfn(*kpte);
+       for (i = 0; i < PTRS_PER_PTE; i++, pfn += pfninc)
+               set_pte(&pbase[i], pfn_pte(pfn, ref_prot));
+
+       /*
+        * Install the new, split up pagetable. Important details here:
         *
         * On Intel the NX bit of all levels must be cleared to make a
         * page executable. See section 4.13.2 of Intel 64 and IA-32
         * Architectures Software Developer's Manual).
+        *
+        * Mark the entry present. The current mapping might be
+        * set to not present, which we preserved above.
         */
        ref_prot = pte_pgprot(pte_mkexec(pte_clrhuge(*kpte)));
+       pgprot_val(ref_prot) |= _PAGE_PRESENT;
        __set_pmd_pte(kpte, address, mk_pte(base, ref_prot));
        base = NULL;
 
@@ -249,18 +418,12 @@ out_unlock:
        return 0;
 }
 
-static int
-__change_page_attr(unsigned long address, unsigned long pfn,
-                  pgprot_t mask_set, pgprot_t mask_clr)
+static int __change_page_attr(unsigned long address, struct cpa_data *cpa)
 {
+       int level, do_split, err;
        struct page *kpte_page;
-       int level, err = 0;
        pte_t *kpte;
 
-#ifdef CONFIG_X86_32
-       BUG_ON(pfn > max_low_pfn);
-#endif
-
 repeat:
        kpte = lookup_address(address, &level);
        if (!kpte)
@@ -271,23 +434,62 @@ repeat:
        BUG_ON(PageCompound(kpte_page));
 
        if (level == PG_LEVEL_4K) {
-               pgprot_t new_prot = pte_pgprot(*kpte);
                pte_t new_pte, old_pte = *kpte;
+               pgprot_t new_prot = pte_pgprot(old_pte);
+
+               if(!pte_val(old_pte)) {
+                       printk(KERN_WARNING "CPA: called for zero pte. "
+                              "vaddr = %lx cpa->vaddr = %lx\n", address,
+                               cpa->vaddr);
+                       WARN_ON(1);
+                       return -EINVAL;
+               }
 
-               pgprot_val(new_prot) &= ~pgprot_val(mask_clr);
-               pgprot_val(new_prot) |= pgprot_val(mask_set);
+               pgprot_val(new_prot) &= ~pgprot_val(cpa->mask_clr);
+               pgprot_val(new_prot) |= pgprot_val(cpa->mask_set);
 
                new_prot = static_protections(new_prot, address);
 
-               new_pte = pfn_pte(pfn, canon_pgprot(new_prot));
-               BUG_ON(pte_pfn(new_pte) != pte_pfn(old_pte));
+               /*
+                * We need to keep the pfn from the existing PTE,
+                * after all we're only going to change it's attributes
+                * not the memory it points to
+                */
+               new_pte = pfn_pte(pte_pfn(old_pte), canon_pgprot(new_prot));
+
+               /*
+                * Do we really change anything ?
+                */
+               if (pte_val(old_pte) != pte_val(new_pte)) {
+                       set_pte_atomic(kpte, new_pte);
+                       cpa->flushtlb = 1;
+               }
+               cpa->numpages = 1;
+               return 0;
+       }
+
+       /*
+        * Check, whether we can keep the large page intact
+        * and just change the pte:
+        */
+       do_split = try_preserve_large_page(kpte, address, cpa);
+       /*
+        * When the range fits into the existing large page,
+        * return. cp->numpages and cpa->tlbflush have been updated in
+        * try_large_page:
+        */
+       if (do_split <= 0)
+               return do_split;
 
-               set_pte_atomic(kpte, new_pte);
-       } else {
-               err = split_large_page(kpte, address);
-               if (!err)
-                       goto repeat;
+       /*
+        * We have to split the large page:
+        */
+       err = split_large_page(kpte, address);
+       if (!err) {
+               cpa->flushtlb = 1;
+               goto repeat;
        }
+
        return err;
 }
 
@@ -304,19 +506,14 @@ repeat:
  *
  * Modules and drivers should use the set_memory_* APIs instead.
  */
-
-#define HIGH_MAP_START __START_KERNEL_map
-#define HIGH_MAP_END   (__START_KERNEL_map + KERNEL_TEXT_SIZE)
-
-static int
-change_page_attr_addr(unsigned long address, pgprot_t mask_set,
-                     pgprot_t mask_clr)
+static int change_page_attr_addr(struct cpa_data *cpa)
 {
-       unsigned long phys_addr = __pa(address);
-       unsigned long pfn = phys_addr >> PAGE_SHIFT;
        int err;
+       unsigned long address = cpa->vaddr;
 
 #ifdef CONFIG_X86_64
+       unsigned long phys_addr = __pa(address);
+
        /*
         * If we are inside the high mapped kernel range, then we
         * fixup the low mapping first. __va() returns the virtual
@@ -326,7 +523,7 @@ change_page_attr_addr(unsigned long address, pgprot_t mask_set,
                address = (unsigned long) __va(phys_addr);
 #endif
 
-       err = __change_page_attr(address, pfn, mask_set, mask_clr);
+       err = __change_page_attr(address, cpa);
        if (err)
                return err;
 
@@ -339,42 +536,89 @@ change_page_attr_addr(unsigned long address, pgprot_t mask_set,
                /*
                 * Calc the high mapping address. See __phys_addr()
                 * for the non obvious details.
+                *
+                * Note that NX and other required permissions are
+                * checked in static_protections().
                 */
                address = phys_addr + HIGH_MAP_START - phys_base;
-               /* Make sure the kernel mappings stay executable */
-               pgprot_val(mask_clr) |= _PAGE_NX;
 
                /*
                 * Our high aliases are imprecise, because we check
                 * everything between 0 and KERNEL_TEXT_SIZE, so do
                 * not propagate lookup failures back to users:
                 */
-               __change_page_attr(address, pfn, mask_set, mask_clr);
+               __change_page_attr(address, cpa);
        }
 #endif
        return err;
 }
 
-static int __change_page_attr_set_clr(unsigned long addr, int numpages,
-                                     pgprot_t mask_set, pgprot_t mask_clr)
+static int __change_page_attr_set_clr(struct cpa_data *cpa)
 {
-       unsigned int i;
-       int ret;
+       int ret, numpages = cpa->numpages;
 
-       for (i = 0; i < numpages ; i++, addr += PAGE_SIZE) {
-               ret = change_page_attr_addr(addr, mask_set, mask_clr);
+       while (numpages) {
+               /*
+                * Store the remaining nr of pages for the large page
+                * preservation check.
+                */
+               cpa->numpages = numpages;
+               ret = change_page_attr_addr(cpa);
                if (ret)
                        return ret;
-       }
 
+               /*
+                * Adjust the number of pages with the result of the
+                * CPA operation. Either a large page has been
+                * preserved or a single page update happened.
+                */
+               BUG_ON(cpa->numpages > numpages);
+               numpages -= cpa->numpages;
+               cpa->vaddr += cpa->numpages * PAGE_SIZE;
+       }
        return 0;
 }
 
+static inline int cache_attr(pgprot_t attr)
+{
+       return pgprot_val(attr) &
+               (_PAGE_PAT | _PAGE_PAT_LARGE | _PAGE_PWT | _PAGE_PCD);
+}
+
 static int change_page_attr_set_clr(unsigned long addr, int numpages,
                                    pgprot_t mask_set, pgprot_t mask_clr)
 {
-       int ret = __change_page_attr_set_clr(addr, numpages, mask_set,
-                                            mask_clr);
+       struct cpa_data cpa;
+       int ret, cache;
+
+       /*
+        * Check, if we are requested to change a not supported
+        * feature:
+        */
+       mask_set = canon_pgprot(mask_set);
+       mask_clr = canon_pgprot(mask_clr);
+       if (!pgprot_val(mask_set) && !pgprot_val(mask_clr))
+               return 0;
+
+       cpa.vaddr = addr;
+       cpa.numpages = numpages;
+       cpa.mask_set = mask_set;
+       cpa.mask_clr = mask_clr;
+       cpa.flushtlb = 0;
+
+       ret = __change_page_attr_set_clr(&cpa);
+
+       /*
+        * Check whether we really changed something:
+        */
+       if (!cpa.flushtlb)
+               return ret;
+
+       /*
+        * No need to flush, when we did not set any of the caching
+        * attributes:
+        */
+       cache = cache_attr(mask_set);
 
        /*
         * On success we use clflush, when the CPU supports it to
@@ -383,9 +627,9 @@ static int change_page_attr_set_clr(unsigned long addr, int numpages,
         * wbindv):
         */
        if (!ret && cpu_has_clflush)
-               cpa_flush_range(addr, numpages);
+               cpa_flush_range(addr, numpages, cache);
        else
-               cpa_flush_all();
+               cpa_flush_all(cache);
 
        return ret;
 }
@@ -399,8 +643,7 @@ static inline int change_page_attr_set(unsigned long addr, int numpages,
 static inline int change_page_attr_clear(unsigned long addr, int numpages,
                                         pgprot_t mask)
 {
-       return __change_page_attr_set_clr(addr, numpages, __pgprot(0), mask);
-
+       return change_page_attr_set_clr(addr, numpages, __pgprot(0), mask);
 }
 
 int set_memory_uc(unsigned long addr, int numpages)
@@ -490,37 +733,26 @@ int set_pages_rw(struct page *page, int numpages)
        return set_memory_rw(addr, numpages);
 }
 
-
-#if defined(CONFIG_DEBUG_PAGEALLOC) || defined(CONFIG_CPA_DEBUG)
-static inline int __change_page_attr_set(unsigned long addr, int numpages,
-                                        pgprot_t mask)
-{
-       return __change_page_attr_set_clr(addr, numpages, mask, __pgprot(0));
-}
-
-static inline int __change_page_attr_clear(unsigned long addr, int numpages,
-                                          pgprot_t mask)
-{
-       return __change_page_attr_set_clr(addr, numpages, __pgprot(0), mask);
-}
-#endif
-
 #ifdef CONFIG_DEBUG_PAGEALLOC
 
 static int __set_pages_p(struct page *page, int numpages)
 {
-       unsigned long addr = (unsigned long)page_address(page);
+       struct cpa_data cpa = { .vaddr = (unsigned long) page_address(page),
+                               .numpages = numpages,
+                               .mask_set = __pgprot(_PAGE_PRESENT | _PAGE_RW),
+                               .mask_clr = __pgprot(0)};
 
-       return __change_page_attr_set(addr, numpages,
-                                     __pgprot(_PAGE_PRESENT | _PAGE_RW));
+       return __change_page_attr_set_clr(&cpa);
 }
 
 static int __set_pages_np(struct page *page, int numpages)
 {
-       unsigned long addr = (unsigned long)page_address(page);
+       struct cpa_data cpa = { .vaddr = (unsigned long) page_address(page),
+                               .numpages = numpages,
+                               .mask_set = __pgprot(0),
+                               .mask_clr = __pgprot(_PAGE_PRESENT | _PAGE_RW)};
 
-       return __change_page_attr_clear(addr, numpages,
-                                       __pgprot(_PAGE_PRESENT));
+       return __change_page_attr_set_clr(&cpa);
 }
 
 void kernel_map_pages(struct page *page, int numpages, int enable)
index 2ae5999a795adfb5cd56f160d0018aee4f0578ee..6c1914622a88344456f571d2cbf06e58921f451b 100644 (file)
@@ -219,50 +219,39 @@ static inline void pgd_list_del(pgd_t *pgd)
        list_del(&page->lru);
 }
 
+#define UNSHARED_PTRS_PER_PGD                          \
+       (SHARED_KERNEL_PMD ? USER_PTRS_PER_PGD : PTRS_PER_PGD)
 
-
-#if (PTRS_PER_PMD == 1)
-/* Non-PAE pgd constructor */
-static void pgd_ctor(void *pgd)
+static void pgd_ctor(void *p)
 {
+       pgd_t *pgd = p;
        unsigned long flags;
 
-       /* !PAE, no pagetable sharing */
+       /* Clear usermode parts of PGD */
        memset(pgd, 0, USER_PTRS_PER_PGD*sizeof(pgd_t));
 
        spin_lock_irqsave(&pgd_lock, flags);
 
-       /* must happen under lock */
-       clone_pgd_range((pgd_t *)pgd + USER_PTRS_PER_PGD,
-                       swapper_pg_dir + USER_PTRS_PER_PGD,
-                       KERNEL_PGD_PTRS);
-       paravirt_alloc_pd_clone(__pa(pgd) >> PAGE_SHIFT,
-                               __pa(swapper_pg_dir) >> PAGE_SHIFT,
-                               USER_PTRS_PER_PGD,
-                               KERNEL_PGD_PTRS);
-       pgd_list_add(pgd);
-       spin_unlock_irqrestore(&pgd_lock, flags);
-}
-#else  /* PTRS_PER_PMD > 1 */
-/* PAE pgd constructor */
-static void pgd_ctor(void *pgd)
-{
-       /* PAE, kernel PMD may be shared */
-
-       if (SHARED_KERNEL_PMD) {
-               clone_pgd_range((pgd_t *)pgd + USER_PTRS_PER_PGD,
+       /* If the pgd points to a shared pagetable level (either the
+          ptes in non-PAE, or shared PMD in PAE), then just copy the
+          references from swapper_pg_dir. */
+       if (PAGETABLE_LEVELS == 2 ||
+           (PAGETABLE_LEVELS == 3 && SHARED_KERNEL_PMD)) {
+               clone_pgd_range(pgd + USER_PTRS_PER_PGD,
                                swapper_pg_dir + USER_PTRS_PER_PGD,
                                KERNEL_PGD_PTRS);
-       } else {
-               unsigned long flags;
+               paravirt_alloc_pd_clone(__pa(pgd) >> PAGE_SHIFT,
+                                       __pa(swapper_pg_dir) >> PAGE_SHIFT,
+                                       USER_PTRS_PER_PGD,
+                                       KERNEL_PGD_PTRS);
+       }
 
-               memset(pgd, 0, USER_PTRS_PER_PGD*sizeof(pgd_t));
-               spin_lock_irqsave(&pgd_lock, flags);
+       /* list required to sync kernel mapping updates */
+       if (!SHARED_KERNEL_PMD)
                pgd_list_add(pgd);
-               spin_unlock_irqrestore(&pgd_lock, flags);
-       }
+
+       spin_unlock_irqrestore(&pgd_lock, flags);
 }
-#endif /* PTRS_PER_PMD */
 
 static void pgd_dtor(void *pgd)
 {
@@ -276,9 +265,6 @@ static void pgd_dtor(void *pgd)
        spin_unlock_irqrestore(&pgd_lock, flags);
 }
 
-#define UNSHARED_PTRS_PER_PGD                          \
-       (SHARED_KERNEL_PMD ? USER_PTRS_PER_PGD : PTRS_PER_PGD)
-
 #ifdef CONFIG_X86_PAE
 /*
  * Mop up any pmd pages which may still be attached to the pgd.
@@ -286,7 +272,7 @@ static void pgd_dtor(void *pgd)
  * preallocate which never got a corresponding vma will need to be
  * freed manually.
  */
-static void pgd_mop_up_pmds(pgd_t *pgdp)
+static void pgd_mop_up_pmds(struct mm_struct *mm, pgd_t *pgdp)
 {
        int i;
 
@@ -299,7 +285,7 @@ static void pgd_mop_up_pmds(pgd_t *pgdp)
                        pgdp[i] = native_make_pgd(0);
 
                        paravirt_release_pd(pgd_val(pgd) >> PAGE_SHIFT);
-                       pmd_free(pmd);
+                       pmd_free(mm, pmd);
                }
        }
 }
@@ -327,7 +313,7 @@ static int pgd_prepopulate_pmd(struct mm_struct *mm, pgd_t *pgd)
                pmd_t *pmd = pmd_alloc_one(mm, addr);
 
                if (!pmd) {
-                       pgd_mop_up_pmds(pgd);
+                       pgd_mop_up_pmds(mm, pgd);
                        return 0;
                }
 
@@ -347,7 +333,7 @@ static int pgd_prepopulate_pmd(struct mm_struct *mm, pgd_t *pgd)
        return 1;
 }
 
-static void pgd_mop_up_pmds(pgd_t *pgd)
+static void pgd_mop_up_pmds(struct mm_struct *mm, pgd_t *pgdp)
 {
 }
 #endif /* CONFIG_X86_PAE */
@@ -366,9 +352,9 @@ pgd_t *pgd_alloc(struct mm_struct *mm)
        return pgd;
 }
 
-void pgd_free(pgd_t *pgd)
+void pgd_free(struct mm_struct *mm, pgd_t *pgd)
 {
-       pgd_mop_up_pmds(pgd);
+       pgd_mop_up_pmds(mm, pgd);
        quicklist_free(0, pgd_dtor, pgd);
 }
 
@@ -376,3 +362,19 @@ void check_pgt_cache(void)
 {
        quicklist_trim(0, pgd_dtor, 25, 16);
 }
+
+void __pte_free_tlb(struct mmu_gather *tlb, struct page *pte)
+{
+       paravirt_release_pt(page_to_pfn(pte));
+       tlb_remove_page(tlb, pte);
+}
+
+#ifdef CONFIG_X86_PAE
+
+void __pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmd)
+{
+       paravirt_release_pd(__pa(pmd) >> PAGE_SHIFT);
+       tlb_remove_page(tlb, virt_to_page(pmd));
+}
+
+#endif
index cb63007e20b2af4142a6cf1703987a48ee86c944..74d30ff33c495319e6f45da8097f7fefc5f4f606 100644 (file)
@@ -17,7 +17,7 @@ static void __devinit pci_fixup_i450nx(struct pci_dev *d)
        int pxb, reg;
        u8 busno, suba, subb;
 
-       printk(KERN_WARNING "PCI: Searching for i450NX host bridges on %s\n", pci_name(d));
+       dev_warn(&d->dev, "Searching for i450NX host bridges\n");
        reg = 0xd0;
        for(pxb = 0; pxb < 2; pxb++) {
                pci_read_config_byte(d, reg++, &busno);
@@ -41,7 +41,7 @@ static void __devinit pci_fixup_i450gx(struct pci_dev *d)
         */
        u8 busno;
        pci_read_config_byte(d, 0x4a, &busno);
-       printk(KERN_INFO "PCI: i440KX/GX host bridge %s: secondary bus %02x\n", pci_name(d), busno);
+       dev_info(&d->dev, "i440KX/GX host bridge; secondary bus %02x\n", busno);
        pci_scan_bus_with_sysdata(busno);
        pcibios_last_bus = -1;
 }
@@ -55,7 +55,7 @@ static void __devinit  pci_fixup_umc_ide(struct pci_dev *d)
         */
        int i;
 
-       printk(KERN_WARNING "PCI: Fixing base address flags for device %s\n", pci_name(d));
+       dev_warn(&d->dev, "Fixing base address flags\n");
        for(i = 0; i < 4; i++)
                d->resource[i].flags |= PCI_BASE_ADDRESS_SPACE_IO;
 }
@@ -68,7 +68,7 @@ static void __devinit  pci_fixup_ncr53c810(struct pci_dev *d)
         * Fix class to be PCI_CLASS_STORAGE_SCSI
         */
        if (!d->class) {
-               printk(KERN_WARNING "PCI: fixing NCR 53C810 class code for %s\n", pci_name(d));
+               dev_warn(&d->dev, "Fixing NCR 53C810 class code\n");
                d->class = PCI_CLASS_STORAGE_SCSI << 8;
        }
 }
@@ -80,7 +80,7 @@ static void __devinit  pci_fixup_latency(struct pci_dev *d)
         *  SiS 5597 and 5598 chipsets require latency timer set to
         *  at most 32 to avoid lockups.
         */
-       DBG("PCI: Setting max latency to 32\n");
+       dev_dbg(&d->dev, "Setting max latency to 32\n");
        pcibios_max_latency = 32;
 }
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5597, pci_fixup_latency);
@@ -138,7 +138,7 @@ static void pci_fixup_via_northbridge_bug(struct pci_dev *d)
 
        pci_read_config_byte(d, where, &v);
        if (v & ~mask) {
-               printk(KERN_WARNING "Disabling VIA memory write queue (PCI ID %04x, rev %02x): [%02x] %02x & %02x -> %02x\n", \
+               dev_warn(&d->dev, "Disabling VIA memory write queue (PCI ID %04x, rev %02x): [%02x] %02x & %02x -> %02x\n", \
                        d->device, d->revision, where, v, mask, v & mask);
                v &= mask;
                pci_write_config_byte(d, where, v);
@@ -200,7 +200,7 @@ static void pci_fixup_nforce2(struct pci_dev *dev)
         * Apply fixup if needed, but don't touch disconnect state
         */
        if ((val & 0x00FF0000) != 0x00010000) {
-               printk(KERN_WARNING "PCI: nForce2 C1 Halt Disconnect fixup\n");
+               dev_warn(&dev->dev, "nForce2 C1 Halt Disconnect fixup\n");
                pci_write_config_dword(dev, 0x6c, (val & 0xFF00FFFF) | 0x00010000);
        }
 }
@@ -348,7 +348,7 @@ static void __devinit pci_fixup_video(struct pci_dev *pdev)
        pci_read_config_word(pdev, PCI_COMMAND, &config);
        if (config & (PCI_COMMAND_IO | PCI_COMMAND_MEMORY)) {
                pdev->resource[PCI_ROM_RESOURCE].flags |= IORESOURCE_ROM_SHADOW;
-               printk(KERN_DEBUG "Boot video device is %s\n", pci_name(pdev));
+               dev_printk(KERN_DEBUG, &pdev->dev, "Boot video device\n");
        }
 }
 DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, pci_fixup_video);
@@ -388,11 +388,11 @@ static void __devinit pci_fixup_msi_k8t_onboard_sound(struct pci_dev *dev)
                /* verify the change for status output */
                pci_read_config_byte(dev, 0x50, &val);
                if (val & 0x40)
-                       printk(KERN_INFO "PCI: Detected MSI K8T Neo2-FIR, "
+                       dev_info(&dev->dev, "Detected MSI K8T Neo2-FIR; "
                                        "can't enable onboard soundcard!\n");
                else
-                       printk(KERN_INFO "PCI: Detected MSI K8T Neo2-FIR, "
-                                       "enabled onboard soundcard.\n");
+                       dev_info(&dev->dev, "Detected MSI K8T Neo2-FIR; "
+                                       "enabled onboard soundcard\n");
        }
 }
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237,
index 42ba0e2da1a05235f4cade3b9c12315f4eca5134..103b9dff12136b7f87a3498dcf6149d23637175c 100644 (file)
@@ -72,7 +72,7 @@ pcibios_align_resource(void *data, struct resource *res,
                }
        }
 }
-
+EXPORT_SYMBOL(pcibios_align_resource);
 
 /*
  *  Handle resources of PCI devices.  If the world were perfect, we could
index f5f165f69e0c602b9a7619c5d4e316e5ff1839ca..55270c26237ce7ff1f95d65eb17d8c3b81e350d8 100644 (file)
@@ -5,36 +5,62 @@
 #include <linux/pci.h>
 #include <linux/init.h>
 #include <linux/nodemask.h>
+#include <mach_apic.h>
 #include "pci.h"
 
+#define XQUAD_PORTIO_BASE 0xfe400000
+#define XQUAD_PORTIO_QUAD 0x40000  /* 256k per quad. */
+
 #define BUS2QUAD(global) (mp_bus_id_to_node[global])
 #define BUS2LOCAL(global) (mp_bus_id_to_local[global])
 #define QUADLOCAL2BUS(quad,local) (quad_local_to_mp_bus_id[quad][local])
 
+extern void *xquad_portio;    /* Where the IO area was mapped */
+#define XQUAD_PORT_ADDR(port, quad) (xquad_portio + (XQUAD_PORTIO_QUAD*quad) + port)
+
 #define PCI_CONF1_MQ_ADDRESS(bus, devfn, reg) \
        (0x80000000 | (BUS2LOCAL(bus) << 16) | (devfn << 8) | (reg & ~3))
 
+static void write_cf8(unsigned bus, unsigned devfn, unsigned reg)
+{
+       unsigned val = PCI_CONF1_MQ_ADDRESS(bus, devfn, reg);
+       if (xquad_portio)
+               writel(val, XQUAD_PORT_ADDR(0xcf8, BUS2QUAD(bus)));
+       else
+               outl(val, 0xCF8);
+}
+
 static int pci_conf1_mq_read(unsigned int seg, unsigned int bus,
                             unsigned int devfn, int reg, int len, u32 *value)
 {
        unsigned long flags;
+       void *adr __iomem = XQUAD_PORT_ADDR(0xcfc, BUS2QUAD(bus));
 
        if (!value || (bus >= MAX_MP_BUSSES) || (devfn > 255) || (reg > 255))
                return -EINVAL;
 
        spin_lock_irqsave(&pci_config_lock, flags);
 
-       outl_quad(PCI_CONF1_MQ_ADDRESS(bus, devfn, reg), 0xCF8, BUS2QUAD(bus));
+       write_cf8(bus, devfn, reg);
 
        switch (len) {
        case 1:
-               *value = inb_quad(0xCFC + (reg & 3), BUS2QUAD(bus));
+               if (xquad_portio)
+                       *value = readb(adr + (reg & 3));
+               else
+                       *value = inb(0xCFC + (reg & 3));
                break;
        case 2:
-               *value = inw_quad(0xCFC + (reg & 2), BUS2QUAD(bus));
+               if (xquad_portio)
+                       *value = readw(adr + (reg & 2));
+               else
+                       *value = inw(0xCFC + (reg & 2));
                break;
        case 4:
-               *value = inl_quad(0xCFC, BUS2QUAD(bus));
+               if (xquad_portio)
+                       *value = readl(adr);
+               else
+                       *value = inl(0xCFC);
                break;
        }
 
@@ -47,23 +73,33 @@ static int pci_conf1_mq_write(unsigned int seg, unsigned int bus,
                              unsigned int devfn, int reg, int len, u32 value)
 {
        unsigned long flags;
+       void *adr __iomem = XQUAD_PORT_ADDR(0xcfc, BUS2QUAD(bus));
 
        if ((bus >= MAX_MP_BUSSES) || (devfn > 255) || (reg > 255)) 
                return -EINVAL;
 
        spin_lock_irqsave(&pci_config_lock, flags);
 
-       outl_quad(PCI_CONF1_MQ_ADDRESS(bus, devfn, reg), 0xCF8, BUS2QUAD(bus));
+       write_cf8(bus, devfn, reg);
 
        switch (len) {
        case 1:
-               outb_quad((u8)value, 0xCFC + (reg & 3), BUS2QUAD(bus));
+               if (xquad_portio)
+                       writeb(value, adr + (reg & 3));
+               else
+                       outb((u8)value, 0xCFC + (reg & 3));
                break;
        case 2:
-               outw_quad((u16)value, 0xCFC + (reg & 2), BUS2QUAD(bus));
+               if (xquad_portio)
+                       writew(value, adr + (reg & 2));
+               else
+                       outw((u16)value, 0xCFC + (reg & 2));
                break;
        case 4:
-               outl_quad((u32)value, 0xCFC, BUS2QUAD(bus));
+               if (xquad_portio)
+                       writel(value, adr + reg);
+               else
+                       outl((u32)value, 0xCFC);
                break;
        }
 
index d3cb3d6af4c8da3249b4e4cda5602724831dd549..5d5546ce88fe90b02ff376a633a4933b22639685 100644 (file)
@@ -174,11 +174,6 @@ config PCI
          your box. Other bus systems are ISA, EISA, MicroChannel (MCA) or
          VESA. If you have PCI, say Y, otherwise N.
 
-         The PCI-HOWTO, available from
-         <http://www.linuxdoc.org/docs.html#howto>, contains valuable
-         information about which PCI hardware does work under Linux and which
-         doesn't
-
 source "drivers/pci/Kconfig"
 
 config HOTPLUG
@@ -251,8 +246,6 @@ config EMBEDDED_RAMDISK_IMAGE
          provide one yourself.
 endmenu
 
-source "kernel/Kconfig.instrumentation"
-
 source "arch/xtensa/Kconfig.debug"
 
 source "security/Kconfig"
index 96036846a0017505691060d62734afc0dcad9529..8c3946787dbbbaedd3381a195ab7851e84ec8272 100644 (file)
@@ -170,11 +170,11 @@ static void free_as_io_context(struct as_io_context *aic)
 
 static void as_trim(struct io_context *ioc)
 {
-       spin_lock(&ioc->lock);
+       spin_lock_irq(&ioc->lock);
        if (ioc->aic)
                free_as_io_context(ioc->aic);
        ioc->aic = NULL;
-       spin_unlock(&ioc->lock);
+       spin_unlock_irq(&ioc->lock);
 }
 
 /* Called when the task exits */
@@ -235,10 +235,12 @@ static void as_put_io_context(struct request *rq)
        aic = RQ_IOC(rq)->aic;
 
        if (rq_is_sync(rq) && aic) {
-               spin_lock(&aic->lock);
+               unsigned long flags;
+
+               spin_lock_irqsave(&aic->lock, flags);
                set_bit(AS_TASK_IORUNNING, &aic->state);
                aic->last_end_request = jiffies;
-               spin_unlock(&aic->lock);
+               spin_unlock_irqrestore(&aic->lock, flags);
        }
 
        put_io_context(RQ_IOC(rq));
@@ -1266,22 +1268,8 @@ static void as_merged_requests(struct request_queue *q, struct request *req,
         */
        if (!list_empty(&req->queuelist) && !list_empty(&next->queuelist)) {
                if (time_before(rq_fifo_time(next), rq_fifo_time(req))) {
-                       struct io_context *rioc = RQ_IOC(req);
-                       struct io_context *nioc = RQ_IOC(next);
-
                        list_move(&req->queuelist, &next->queuelist);
                        rq_set_fifo_time(req, rq_fifo_time(next));
-                       /*
-                        * Don't copy here but swap, because when anext is
-                        * removed below, it must contain the unused context
-                        */
-                       if (rioc != nioc) {
-                               double_spin_lock(&rioc->lock, &nioc->lock,
-                                                               rioc < nioc);
-                               swap_io_context(&rioc, &nioc);
-                               double_spin_unlock(&rioc->lock, &nioc->lock,
-                                                               rioc < nioc);
-                       }
                }
        }
 
index 5f74fec327d53e35651d4616098a99e6e146630b..6901eedeffce83bd3db09b3d0b802da6486994b4 100644 (file)
@@ -26,7 +26,8 @@ int blk_queue_ordered(struct request_queue *q, unsigned ordered,
 {
        if (ordered & (QUEUE_ORDERED_PREFLUSH | QUEUE_ORDERED_POSTFLUSH) &&
            prepare_flush_fn == NULL) {
-               printk(KERN_ERR "blk_queue_ordered: prepare_flush_fn required\n");
+               printk(KERN_ERR "%s: prepare_flush_fn required\n",
+                                                               __FUNCTION__);
                return -EINVAL;
        }
 
@@ -47,7 +48,6 @@ int blk_queue_ordered(struct request_queue *q, unsigned ordered,
 
        return 0;
 }
-
 EXPORT_SYMBOL(blk_queue_ordered);
 
 /*
@@ -315,5 +315,4 @@ int blkdev_issue_flush(struct block_device *bdev, sector_t *error_sector)
        bio_put(bio);
        return ret;
 }
-
 EXPORT_SYMBOL(blkdev_issue_flush);
index 8ff99440ee449cc34a84b4ec00d8044e15812cf7..4afb39c823396ccec50c3ded2673d22ed0b07cf3 100644 (file)
@@ -3,7 +3,8 @@
  * Copyright (C) 1994,      Karl Keyte: Added support for disk statistics
  * Elevator latency, (C) 2000  Andrea Arcangeli <andrea@suse.de> SuSE
  * Queue request tables / lock, selectable elevator, Jens Axboe <axboe@suse.de>
- * kernel-doc documentation started by NeilBrown <neilb@cse.unsw.edu.au> -  July2000
+ * kernel-doc documentation started by NeilBrown <neilb@cse.unsw.edu.au>
+ *     -  July2000
  * bio rewrite, highmem i/o, etc, Jens Axboe <axboe@suse.de> - may 2001
  */
 
@@ -42,7 +43,7 @@ struct kmem_cache *request_cachep;
 /*
  * For queue allocation
  */
-struct kmem_cache *blk_requestq_cachep = NULL;
+struct kmem_cache *blk_requestq_cachep;
 
 /*
  * Controlling structure to kblockd
@@ -137,7 +138,7 @@ static void req_bio_endio(struct request *rq, struct bio *bio,
                        error = -EIO;
 
                if (unlikely(nbytes > bio->bi_size)) {
-                       printk("%s: want %u bytes done, only %u left\n",
+                       printk(KERN_ERR "%s: want %u bytes done, %u left\n",
                               __FUNCTION__, nbytes, bio->bi_size);
                        nbytes = bio->bi_size;
                }
@@ -161,23 +162,26 @@ void blk_dump_rq_flags(struct request *rq, char *msg)
 {
        int bit;
 
-       printk("%s: dev %s: type=%x, flags=%x\n", msg,
+       printk(KERN_INFO "%s: dev %s: type=%x, flags=%x\n", msg,
                rq->rq_disk ? rq->rq_disk->disk_name : "?", rq->cmd_type,
                rq->cmd_flags);
 
-       printk("\nsector %llu, nr/cnr %lu/%u\n", (unsigned long long)rq->sector,
-                                                      rq->nr_sectors,
-                                                      rq->current_nr_sectors);
-       printk("bio %p, biotail %p, buffer %p, data %p, len %u\n", rq->bio, rq->biotail, rq->buffer, rq->data, rq->data_len);
+       printk(KERN_INFO "  sector %llu, nr/cnr %lu/%u\n",
+                                               (unsigned long long)rq->sector,
+                                               rq->nr_sectors,
+                                               rq->current_nr_sectors);
+       printk(KERN_INFO "  bio %p, biotail %p, buffer %p, data %p, len %u\n",
+                                               rq->bio, rq->biotail,
+                                               rq->buffer, rq->data,
+                                               rq->data_len);
 
        if (blk_pc_request(rq)) {
-               printk("cdb: ");
+               printk(KERN_INFO "  cdb: ");
                for (bit = 0; bit < sizeof(rq->cmd); bit++)
                        printk("%02x ", rq->cmd[bit]);
                printk("\n");
        }
 }
-
 EXPORT_SYMBOL(blk_dump_rq_flags);
 
 /*
@@ -204,7 +208,6 @@ void blk_plug_device(struct request_queue *q)
                blk_add_trace_generic(q, NULL, 0, BLK_TA_PLUG);
        }
 }
-
 EXPORT_SYMBOL(blk_plug_device);
 
 /*
@@ -221,7 +224,6 @@ int blk_remove_plug(struct request_queue *q)
        del_timer(&q->unplug_timer);
        return 1;
 }
-
 EXPORT_SYMBOL(blk_remove_plug);
 
 /*
@@ -328,7 +330,6 @@ void blk_start_queue(struct request_queue *q)
                kblockd_schedule_work(&q->unplug_work);
        }
 }
-
 EXPORT_SYMBOL(blk_start_queue);
 
 /**
@@ -408,7 +409,7 @@ void blk_put_queue(struct request_queue *q)
 }
 EXPORT_SYMBOL(blk_put_queue);
 
-void blk_cleanup_queue(struct request_queue * q)
+void blk_cleanup_queue(struct request_queue *q)
 {
        mutex_lock(&q->sysfs_lock);
        set_bit(QUEUE_FLAG_DEAD, &q->queue_flags);
@@ -419,7 +420,6 @@ void blk_cleanup_queue(struct request_queue * q)
 
        blk_put_queue(q);
 }
-
 EXPORT_SYMBOL(blk_cleanup_queue);
 
 static int blk_init_free_list(struct request_queue *q)
@@ -575,7 +575,6 @@ int blk_get_queue(struct request_queue *q)
 
        return 1;
 }
-
 EXPORT_SYMBOL(blk_get_queue);
 
 static inline void blk_free_request(struct request_queue *q, struct request *rq)
@@ -774,7 +773,7 @@ rq_starved:
         */
        if (ioc_batching(q, ioc))
                ioc->nr_batch_requests--;
-       
+
        rq_init(q, rq);
 
        blk_add_trace_generic(q, bio, rw, BLK_TA_GETRQ);
@@ -888,7 +887,6 @@ void blk_requeue_request(struct request_queue *q, struct request *rq)
 
        elv_requeue_request(q, rq);
 }
-
 EXPORT_SYMBOL(blk_requeue_request);
 
 /**
@@ -939,7 +937,6 @@ void blk_insert_request(struct request_queue *q, struct request *rq,
        blk_start_queueing(q);
        spin_unlock_irqrestore(q->queue_lock, flags);
 }
-
 EXPORT_SYMBOL(blk_insert_request);
 
 /*
@@ -947,7 +944,7 @@ EXPORT_SYMBOL(blk_insert_request);
  * queue lock is held and interrupts disabled, as we muck with the
  * request queue list.
  */
-static inline void add_request(struct request_queue * q, struct request * req)
+static inline void add_request(struct request_queue *q, struct request *req)
 {
        drive_stat_acct(req, 1);
 
@@ -957,7 +954,7 @@ static inline void add_request(struct request_queue * q, struct request * req)
         */
        __elv_add_request(q, req, ELEVATOR_INSERT_SORT, 0);
 }
+
 /*
  * disk_round_stats()  - Round off the performance stats on a struct
  * disk_stats.
@@ -987,7 +984,6 @@ void disk_round_stats(struct gendisk *disk)
        }
        disk->stamp = now;
 }
-
 EXPORT_SYMBOL_GPL(disk_round_stats);
 
 /*
@@ -1017,7 +1013,6 @@ void __blk_put_request(struct request_queue *q, struct request *req)
                freed_request(q, rw, priv);
        }
 }
-
 EXPORT_SYMBOL_GPL(__blk_put_request);
 
 void blk_put_request(struct request *req)
@@ -1035,7 +1030,6 @@ void blk_put_request(struct request *req)
                spin_unlock_irqrestore(q->queue_lock, flags);
        }
 }
-
 EXPORT_SYMBOL(blk_put_request);
 
 void init_request_from_bio(struct request *req, struct bio *bio)
@@ -1096,53 +1090,53 @@ static int __make_request(struct request_queue *q, struct bio *bio)
 
        el_ret = elv_merge(q, &req, bio);
        switch (el_ret) {
-               case ELEVATOR_BACK_MERGE:
-                       BUG_ON(!rq_mergeable(req));
+       case ELEVATOR_BACK_MERGE:
+               BUG_ON(!rq_mergeable(req));
 
-                       if (!ll_back_merge_fn(q, req, bio))
-                               break;
+               if (!ll_back_merge_fn(q, req, bio))
+                       break;
 
-                       blk_add_trace_bio(q, bio, BLK_TA_BACKMERGE);
+               blk_add_trace_bio(q, bio, BLK_TA_BACKMERGE);
 
-                       req->biotail->bi_next = bio;
-                       req->biotail = bio;
-                       req->nr_sectors = req->hard_nr_sectors += nr_sectors;
-                       req->ioprio = ioprio_best(req->ioprio, prio);
-                       drive_stat_acct(req, 0);
-                       if (!attempt_back_merge(q, req))
-                               elv_merged_request(q, req, el_ret);
-                       goto out;
+               req->biotail->bi_next = bio;
+               req->biotail = bio;
+               req->nr_sectors = req->hard_nr_sectors += nr_sectors;
+               req->ioprio = ioprio_best(req->ioprio, prio);
+               drive_stat_acct(req, 0);
+               if (!attempt_back_merge(q, req))
+                       elv_merged_request(q, req, el_ret);
+               goto out;
 
-               case ELEVATOR_FRONT_MERGE:
-                       BUG_ON(!rq_mergeable(req));
+       case ELEVATOR_FRONT_MERGE:
+               BUG_ON(!rq_mergeable(req));
 
-                       if (!ll_front_merge_fn(q, req, bio))
-                               break;
+               if (!ll_front_merge_fn(q, req, bio))
+                       break;
 
-                       blk_add_trace_bio(q, bio, BLK_TA_FRONTMERGE);
+               blk_add_trace_bio(q, bio, BLK_TA_FRONTMERGE);
 
-                       bio->bi_next = req->bio;
-                       req->bio = bio;
+               bio->bi_next = req->bio;
+               req->bio = bio;
 
-                       /*
-                        * may not be valid. if the low level driver said
-                        * it didn't need a bounce buffer then it better
-                        * not touch req->buffer either...
-                        */
-                       req->buffer = bio_data(bio);
-                       req->current_nr_sectors = bio_cur_sectors(bio);
-                       req->hard_cur_sectors = req->current_nr_sectors;
-                       req->sector = req->hard_sector = bio->bi_sector;
-                       req->nr_sectors = req->hard_nr_sectors += nr_sectors;
-                       req->ioprio = ioprio_best(req->ioprio, prio);
-                       drive_stat_acct(req, 0);
-                       if (!attempt_front_merge(q, req))
-                               elv_merged_request(q, req, el_ret);
-                       goto out;
-
-               /* ELV_NO_MERGE: elevator says don't/can't merge. */
-               default:
-                       ;
+               /*
+                * may not be valid. if the low level driver said
+                * it didn't need a bounce buffer then it better
+                * not touch req->buffer either...
+                */
+               req->buffer = bio_data(bio);
+               req->current_nr_sectors = bio_cur_sectors(bio);
+               req->hard_cur_sectors = req->current_nr_sectors;
+               req->sector = req->hard_sector = bio->bi_sector;
+               req->nr_sectors = req->hard_nr_sectors += nr_sectors;
+               req->ioprio = ioprio_best(req->ioprio, prio);
+               drive_stat_acct(req, 0);
+               if (!attempt_front_merge(q, req))
+                       elv_merged_request(q, req, el_ret);
+               goto out;
+
+       /* ELV_NO_MERGE: elevator says don't/can't merge. */
+       default:
+               ;
        }
 
 get_rq:
@@ -1350,7 +1344,7 @@ end_io:
                }
 
                if (unlikely(nr_sectors > q->max_hw_sectors)) {
-                       printk("bio too big device %s (%u > %u)\n", 
+                       printk(KERN_ERR "bio too big device %s (%u > %u)\n",
                                bdevname(bio->bi_bdev, b),
                                bio_sectors(bio),
                                q->max_hw_sectors);
@@ -1439,7 +1433,6 @@ void generic_make_request(struct bio *bio)
        } while (bio);
        current->bio_tail = NULL; /* deactivate */
 }
-
 EXPORT_SYMBOL(generic_make_request);
 
 /**
@@ -1480,13 +1473,12 @@ void submit_bio(int rw, struct bio *bio)
                        current->comm, task_pid_nr(current),
                                (rw & WRITE) ? "WRITE" : "READ",
                                (unsigned long long)bio->bi_sector,
-                               bdevname(bio->bi_bdev,b));
+                               bdevname(bio->bi_bdev, b));
                }
        }
 
        generic_make_request(bio);
 }
-
 EXPORT_SYMBOL(submit_bio);
 
 /**
@@ -1518,9 +1510,8 @@ static int __end_that_request_first(struct request *req, int error,
        if (!blk_pc_request(req))
                req->errors = 0;
 
-       if (error) {
-               if (blk_fs_request(req) && !(req->cmd_flags & REQ_QUIET))
-                       printk("end_request: I/O error, dev %s, sector %llu\n",
+       if (error && (blk_fs_request(req) && !(req->cmd_flags & REQ_QUIET))) {
+               printk(KERN_ERR "end_request: I/O error, dev %s, sector %llu\n",
                                req->rq_disk ? req->rq_disk->disk_name : "?",
                                (unsigned long long)req->sector);
        }
@@ -1554,9 +1545,9 @@ static int __end_that_request_first(struct request *req, int error,
 
                        if (unlikely(bio->bi_idx >= bio->bi_vcnt)) {
                                blk_dump_rq_flags(req, "__end_that");
-                               printk("%s: bio idx %d >= vcnt %d\n",
-                                               __FUNCTION__,
-                                               bio->bi_idx, bio->bi_vcnt);
+                               printk(KERN_ERR "%s: bio idx %d >= vcnt %d\n",
+                                               __FUNCTION__, bio->bi_idx,
+                                               bio->bi_vcnt);
                                break;
                        }
 
@@ -1582,7 +1573,8 @@ static int __end_that_request_first(struct request *req, int error,
                total_bytes += nbytes;
                nr_bytes -= nbytes;
 
-               if ((bio = req->bio)) {
+               bio = req->bio;
+               if (bio) {
                        /*
                         * end more in this run, or just return 'not-done'
                         */
@@ -1626,15 +1618,16 @@ static void blk_done_softirq(struct softirq_action *h)
        local_irq_enable();
 
        while (!list_empty(&local_list)) {
-               struct request *rq = list_entry(local_list.next, struct request, donelist);
+               struct request *rq;
 
+               rq = list_entry(local_list.next, struct request, donelist);
                list_del_init(&rq->donelist);
                rq->q->softirq_done_fn(rq);
        }
 }
 
-static int __cpuinit blk_cpu_notify(struct notifier_block *self, unsigned long action,
-                         void *hcpu)
+static int __cpuinit blk_cpu_notify(struct notifier_block *self,
+                                   unsigned long action, void *hcpu)
 {
        /*
         * If a CPU goes away, splice its entries to the current CPU
@@ -1676,7 +1669,7 @@ void blk_complete_request(struct request *req)
        unsigned long flags;
 
        BUG_ON(!req->q->softirq_done_fn);
-               
+
        local_irq_save(flags);
 
        cpu_list = &__get_cpu_var(blk_cpu_done);
@@ -1685,9 +1678,8 @@ void blk_complete_request(struct request *req)
 
        local_irq_restore(flags);
 }
-
 EXPORT_SYMBOL(blk_complete_request);
-       
+
 /*
  * queue lock must be held
  */
@@ -1846,8 +1838,9 @@ EXPORT_SYMBOL(end_request);
  *     0 - we are done with this request
  *     1 - this request is not freed yet, it still has pending buffers.
  **/
-static int blk_end_io(struct request *rq, int error, int nr_bytes,
-                     int bidi_bytes, int (drv_callback)(struct request *))
+static int blk_end_io(struct request *rq, int error, unsigned int nr_bytes,
+                     unsigned int bidi_bytes,
+                     int (drv_callback)(struct request *))
 {
        struct request_queue *q = rq->q;
        unsigned long flags = 0UL;
@@ -1889,7 +1882,7 @@ static int blk_end_io(struct request *rq, int error, int nr_bytes,
  *     0 - we are done with this request
  *     1 - still buffers pending for this request
  **/
-int blk_end_request(struct request *rq, int error, int nr_bytes)
+int blk_end_request(struct request *rq, int error, unsigned int nr_bytes)
 {
        return blk_end_io(rq, error, nr_bytes, 0, NULL);
 }
@@ -1908,7 +1901,7 @@ EXPORT_SYMBOL_GPL(blk_end_request);
  *     0 - we are done with this request
  *     1 - still buffers pending for this request
  **/
-int __blk_end_request(struct request *rq, int error, int nr_bytes)
+int __blk_end_request(struct request *rq, int error, unsigned int nr_bytes)
 {
        if (blk_fs_request(rq) || blk_pc_request(rq)) {
                if (__end_that_request_first(rq, error, nr_bytes))
@@ -1937,8 +1930,8 @@ EXPORT_SYMBOL_GPL(__blk_end_request);
  *     0 - we are done with this request
  *     1 - still buffers pending for this request
  **/
-int blk_end_bidi_request(struct request *rq, int error, int nr_bytes,
-                        int bidi_bytes)
+int blk_end_bidi_request(struct request *rq, int error, unsigned int nr_bytes,
+                        unsigned int bidi_bytes)
 {
        return blk_end_io(rq, error, nr_bytes, bidi_bytes, NULL);
 }
@@ -1969,7 +1962,8 @@ EXPORT_SYMBOL_GPL(blk_end_bidi_request);
  *         this request still has pending buffers or
  *         the driver doesn't want to finish this request yet.
  **/
-int blk_end_request_callback(struct request *rq, int error, int nr_bytes,
+int blk_end_request_callback(struct request *rq, int error,
+                            unsigned int nr_bytes,
                             int (drv_callback)(struct request *))
 {
        return blk_end_io(rq, error, nr_bytes, 0, drv_callback);
@@ -2000,7 +1994,6 @@ int kblockd_schedule_work(struct work_struct *work)
 {
        return queue_work(kblockd_workqueue, work);
 }
-
 EXPORT_SYMBOL(kblockd_schedule_work);
 
 void kblockd_flush_work(struct work_struct *work)
index ebfb44e959a950e73d427bcae7d17f79f882de96..391dd6224890a660f688df22b1985810930b88f3 100644 (file)
@@ -101,5 +101,4 @@ int blk_execute_rq(struct request_queue *q, struct gendisk *bd_disk,
 
        return err;
 }
-
 EXPORT_SYMBOL(blk_execute_rq);
index 6d1675508eb5d20c8367992fa125dc3cad3a06d8..80245dc30c75798d33089b99e14e80a746b8d50f 100644 (file)
@@ -176,15 +176,6 @@ void copy_io_context(struct io_context **pdst, struct io_context **psrc)
 }
 EXPORT_SYMBOL(copy_io_context);
 
-void swap_io_context(struct io_context **ioc1, struct io_context **ioc2)
-{
-       struct io_context *temp;
-       temp = *ioc1;
-       *ioc1 = *ioc2;
-       *ioc2 = temp;
-}
-EXPORT_SYMBOL(swap_io_context);
-
 int __init blk_ioc_init(void)
 {
        iocontext_cachep = kmem_cache_create("blkdev_ioc",
index 916cfc96ffa0de2ee8b92c63273b71daaef7db1b..955d75c1a58fd634e3f168ec8d091c4c9e93a965 100644 (file)
@@ -53,7 +53,8 @@ static int __blk_rq_map_user(struct request_queue *q, struct request *rq,
         * direct dma. else, set up kernel bounce buffers
         */
        uaddr = (unsigned long) ubuf;
-       if (!(uaddr & queue_dma_alignment(q)) && !(len & queue_dma_alignment(q)))
+       if (!(uaddr & queue_dma_alignment(q)) &&
+           !(len & queue_dma_alignment(q)))
                bio = bio_map_user(q, NULL, uaddr, len, reading);
        else
                bio = bio_copy_user(q, uaddr, len, reading);
@@ -144,7 +145,6 @@ unmap_rq:
        blk_rq_unmap_user(bio);
        return ret;
 }
-
 EXPORT_SYMBOL(blk_rq_map_user);
 
 /**
@@ -179,7 +179,8 @@ int blk_rq_map_user_iov(struct request_queue *q, struct request *rq,
        /* we don't allow misaligned data like bio_map_user() does.  If the
         * user is using sg, they're expected to know the alignment constraints
         * and respect them accordingly */
-       bio = bio_map_user_iov(q, NULL, iov, iov_count, rq_data_dir(rq)== READ);
+       bio = bio_map_user_iov(q, NULL, iov, iov_count,
+                               rq_data_dir(rq) == READ);
        if (IS_ERR(bio))
                return PTR_ERR(bio);
 
@@ -194,7 +195,6 @@ int blk_rq_map_user_iov(struct request_queue *q, struct request *rq,
        rq->buffer = rq->data = NULL;
        return 0;
 }
-
 EXPORT_SYMBOL(blk_rq_map_user_iov);
 
 /**
@@ -227,7 +227,6 @@ int blk_rq_unmap_user(struct bio *bio)
 
        return ret;
 }
-
 EXPORT_SYMBOL(blk_rq_unmap_user);
 
 /**
@@ -260,5 +259,4 @@ int blk_rq_map_kern(struct request_queue *q, struct request *rq, void *kbuf,
        rq->buffer = rq->data = NULL;
        return 0;
 }
-
 EXPORT_SYMBOL(blk_rq_map_kern);
index 5023f0b08073f7a0e52563987911f88916d80052..845ef81311081e719ed3ca9409fad05a0c890bf7 100644 (file)
@@ -32,7 +32,7 @@ void blk_recalc_rq_sectors(struct request *rq, int nsect)
                 * size, something has gone terribly wrong
                 */
                if (rq->nr_sectors < rq->current_nr_sectors) {
-                       printk("blk: request botched\n");
+                       printk(KERN_ERR "blk: request botched\n");
                        rq->nr_sectors = rq->current_nr_sectors;
                }
        }
@@ -235,7 +235,6 @@ new_segment:
 
        return nsegs;
 }
-
 EXPORT_SYMBOL(blk_rq_map_sg);
 
 static inline int ll_new_mergeable(struct request_queue *q,
@@ -305,8 +304,8 @@ int ll_back_merge_fn(struct request_queue *q, struct request *req,
        if (unlikely(!bio_flagged(bio, BIO_SEG_VALID)))
                blk_recount_segments(q, bio);
        len = req->biotail->bi_hw_back_size + bio->bi_hw_front_size;
-       if (BIOVEC_VIRT_MERGEABLE(__BVEC_END(req->biotail), __BVEC_START(bio)) &&
-           !BIOVEC_VIRT_OVERSIZE(len)) {
+       if (BIOVEC_VIRT_MERGEABLE(__BVEC_END(req->biotail), __BVEC_START(bio))
+           && !BIOVEC_VIRT_OVERSIZE(len)) {
                int mergeable =  ll_new_mergeable(q, req, bio);
 
                if (mergeable) {
@@ -321,7 +320,7 @@ int ll_back_merge_fn(struct request_queue *q, struct request *req,
        return ll_new_hw_segment(q, req, bio);
 }
 
-int ll_front_merge_fn(struct request_queue *q, struct request *req, 
+int ll_front_merge_fn(struct request_queue *q, struct request *req,
                      struct bio *bio)
 {
        unsigned short max_sectors;
@@ -388,7 +387,8 @@ static int ll_merge_requests_fn(struct request_queue *q, struct request *req,
 
        total_hw_segments = req->nr_hw_segments + next->nr_hw_segments;
        if (blk_hw_contig_segment(q, req->biotail, next->bio)) {
-               int len = req->biotail->bi_hw_back_size + next->bio->bi_hw_front_size;
+               int len = req->biotail->bi_hw_back_size +
+                               next->bio->bi_hw_front_size;
                /*
                 * propagate the combined length to the end of the requests
                 */
index 4df09a1b8f437a637339cff15352572411cf0eb8..c8d0c572409826a109410d0d197c91fa305aeb13 100644 (file)
 
 #include "blk.h"
 
-unsigned long blk_max_low_pfn, blk_max_pfn;
+unsigned long blk_max_low_pfn;
 EXPORT_SYMBOL(blk_max_low_pfn);
+
+unsigned long blk_max_pfn;
 EXPORT_SYMBOL(blk_max_pfn);
 
 /**
@@ -29,7 +31,6 @@ void blk_queue_prep_rq(struct request_queue *q, prep_rq_fn *pfn)
 {
        q->prep_rq_fn = pfn;
 }
-
 EXPORT_SYMBOL(blk_queue_prep_rq);
 
 /**
@@ -52,14 +53,12 @@ void blk_queue_merge_bvec(struct request_queue *q, merge_bvec_fn *mbfn)
 {
        q->merge_bvec_fn = mbfn;
 }
-
 EXPORT_SYMBOL(blk_queue_merge_bvec);
 
 void blk_queue_softirq_done(struct request_queue *q, softirq_done_fn *fn)
 {
        q->softirq_done_fn = fn;
 }
-
 EXPORT_SYMBOL(blk_queue_softirq_done);
 
 /**
@@ -84,7 +83,7 @@ EXPORT_SYMBOL(blk_queue_softirq_done);
  *    __bio_kmap_atomic() to get a temporary kernel mapping, or by calling
  *    blk_queue_bounce() to create a buffer in normal memory.
  **/
-void blk_queue_make_request(struct request_queue * q, make_request_fn * mfn)
+void blk_queue_make_request(struct request_queue *q, make_request_fn *mfn)
 {
        /*
         * set defaults
@@ -93,7 +92,8 @@ void blk_queue_make_request(struct request_queue * q, make_request_fn * mfn)
        blk_queue_max_phys_segments(q, MAX_PHYS_SEGMENTS);
        blk_queue_max_hw_segments(q, MAX_HW_SEGMENTS);
        q->make_request_fn = mfn;
-       q->backing_dev_info.ra_pages = (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE;
+       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);
@@ -117,7 +117,6 @@ void blk_queue_make_request(struct request_queue * q, make_request_fn * mfn)
         */
        blk_queue_bounce_limit(q, BLK_BOUNCE_HIGH);
 }
-
 EXPORT_SYMBOL(blk_queue_make_request);
 
 /**
@@ -133,7 +132,7 @@ EXPORT_SYMBOL(blk_queue_make_request);
  **/
 void blk_queue_bounce_limit(struct request_queue *q, u64 dma_addr)
 {
-       unsigned long bounce_pfn = dma_addr >> PAGE_SHIFT;
+       unsigned long b_pfn = dma_addr >> PAGE_SHIFT;
        int dma = 0;
 
        q->bounce_gfp = GFP_NOIO;
@@ -141,21 +140,20 @@ void blk_queue_bounce_limit(struct request_queue *q, u64 dma_addr)
        /* Assume anything <= 4GB can be handled by IOMMU.
           Actually some IOMMUs can handle everything, but I don't
           know of a way to test this here. */
-       if (bounce_pfn < (min_t(u64,0xffffffff,BLK_BOUNCE_HIGH) >> PAGE_SHIFT))
+       if (b_pfn < (min_t(u64, 0xffffffff, BLK_BOUNCE_HIGH) >> PAGE_SHIFT))
                dma = 1;
        q->bounce_pfn = max_low_pfn;
 #else
-       if (bounce_pfn < blk_max_low_pfn)
+       if (b_pfn < blk_max_low_pfn)
                dma = 1;
-       q->bounce_pfn = bounce_pfn;
+       q->bounce_pfn = b_pfn;
 #endif
        if (dma) {
                init_emergency_isa_pool();
                q->bounce_gfp = GFP_NOIO | GFP_DMA;
-               q->bounce_pfn = bounce_pfn;
+               q->bounce_pfn = b_pfn;
        }
 }
-
 EXPORT_SYMBOL(blk_queue_bounce_limit);
 
 /**
@@ -171,7 +169,8 @@ void blk_queue_max_sectors(struct request_queue *q, unsigned int max_sectors)
 {
        if ((max_sectors << 9) < PAGE_CACHE_SIZE) {
                max_sectors = 1 << (PAGE_CACHE_SHIFT - 9);
-               printk("%s: set to minimum %d\n", __FUNCTION__, max_sectors);
+               printk(KERN_INFO "%s: set to minimum %d\n", __FUNCTION__,
+                                                       max_sectors);
        }
 
        if (BLK_DEF_MAX_SECTORS > max_sectors)
@@ -181,7 +180,6 @@ void blk_queue_max_sectors(struct request_queue *q, unsigned int max_sectors)
                q->max_hw_sectors = max_sectors;
        }
 }
-
 EXPORT_SYMBOL(blk_queue_max_sectors);
 
 /**
@@ -199,12 +197,12 @@ void blk_queue_max_phys_segments(struct request_queue *q,
 {
        if (!max_segments) {
                max_segments = 1;
-               printk("%s: set to minimum %d\n", __FUNCTION__, max_segments);
+               printk(KERN_INFO "%s: set to minimum %d\n", __FUNCTION__,
+                                                       max_segments);
        }
 
        q->max_phys_segments = max_segments;
 }
-
 EXPORT_SYMBOL(blk_queue_max_phys_segments);
 
 /**
@@ -223,12 +221,12 @@ void blk_queue_max_hw_segments(struct request_queue *q,
 {
        if (!max_segments) {
                max_segments = 1;
-               printk("%s: set to minimum %d\n", __FUNCTION__, max_segments);
+               printk(KERN_INFO "%s: set to minimum %d\n", __FUNCTION__,
+                                                       max_segments);
        }
 
        q->max_hw_segments = max_segments;
 }
-
 EXPORT_SYMBOL(blk_queue_max_hw_segments);
 
 /**
@@ -244,12 +242,12 @@ void blk_queue_max_segment_size(struct request_queue *q, unsigned int max_size)
 {
        if (max_size < PAGE_CACHE_SIZE) {
                max_size = PAGE_CACHE_SIZE;
-               printk("%s: set to minimum %d\n", __FUNCTION__, max_size);
+               printk(KERN_INFO "%s: set to minimum %d\n", __FUNCTION__,
+                                                       max_size);
        }
 
        q->max_segment_size = max_size;
 }
-
 EXPORT_SYMBOL(blk_queue_max_segment_size);
 
 /**
@@ -267,7 +265,6 @@ void blk_queue_hardsect_size(struct request_queue *q, unsigned short size)
 {
        q->hardsect_size = size;
 }
-
 EXPORT_SYMBOL(blk_queue_hardsect_size);
 
 /*
@@ -283,17 +280,16 @@ EXPORT_SYMBOL(blk_queue_hardsect_size);
 void blk_queue_stack_limits(struct request_queue *t, struct request_queue *b)
 {
        /* zero is "infinity" */
-       t->max_sectors = min_not_zero(t->max_sectors,b->max_sectors);
-       t->max_hw_sectors = min_not_zero(t->max_hw_sectors,b->max_hw_sectors);
+       t->max_sectors = min_not_zero(t->max_sectors, b->max_sectors);
+       t->max_hw_sectors = min_not_zero(t->max_hw_sectors, b->max_hw_sectors);
 
-       t->max_phys_segments = min(t->max_phys_segments,b->max_phys_segments);
-       t->max_hw_segments = min(t->max_hw_segments,b->max_hw_segments);
-       t->max_segment_size = min(t->max_segment_size,b->max_segment_size);
-       t->hardsect_size = max(t->hardsect_size,b->hardsect_size);
+       t->max_phys_segments = min(t->max_phys_segments, b->max_phys_segments);
+       t->max_hw_segments = min(t->max_hw_segments, b->max_hw_segments);
+       t->max_segment_size = min(t->max_segment_size, b->max_segment_size);
+       t->hardsect_size = max(t->hardsect_size, b->hardsect_size);
        if (!test_bit(QUEUE_FLAG_CLUSTER, &b->queue_flags))
                clear_bit(QUEUE_FLAG_CLUSTER, &t->queue_flags);
 }
-
 EXPORT_SYMBOL(blk_queue_stack_limits);
 
 /**
@@ -332,7 +328,6 @@ int blk_queue_dma_drain(struct request_queue *q, void *buf,
 
        return 0;
 }
-
 EXPORT_SYMBOL_GPL(blk_queue_dma_drain);
 
 /**
@@ -344,12 +339,12 @@ void blk_queue_segment_boundary(struct request_queue *q, unsigned long mask)
 {
        if (mask < PAGE_CACHE_SIZE - 1) {
                mask = PAGE_CACHE_SIZE - 1;
-               printk("%s: set to minimum %lx\n", __FUNCTION__, mask);
+               printk(KERN_INFO "%s: set to minimum %lx\n", __FUNCTION__,
+                                                       mask);
        }
 
        q->seg_boundary_mask = mask;
 }
-
 EXPORT_SYMBOL(blk_queue_segment_boundary);
 
 /**
@@ -366,7 +361,6 @@ void blk_queue_dma_alignment(struct request_queue *q, int mask)
 {
        q->dma_alignment = mask;
 }
-
 EXPORT_SYMBOL(blk_queue_dma_alignment);
 
 /**
@@ -390,7 +384,6 @@ void blk_queue_update_dma_alignment(struct request_queue *q, int mask)
        if (mask > q->dma_alignment)
                q->dma_alignment = mask;
 }
-
 EXPORT_SYMBOL(blk_queue_update_dma_alignment);
 
 int __init blk_settings_init(void)
index bc28776ba76ab710efe936e93893272f9cb89d8b..54d0db116153c943674217aac801144a8c55553b 100644 (file)
@@ -207,12 +207,13 @@ queue_attr_store(struct kobject *kobj, struct attribute *attr,
                    const char *page, size_t length)
 {
        struct queue_sysfs_entry *entry = to_queue(attr);
-       struct request_queue *q = container_of(kobj, struct request_queue, kobj);
-
+       struct request_queue *q;
        ssize_t res;
 
        if (!entry->store)
                return -EIO;
+
+       q = container_of(kobj, struct request_queue, kobj);
        mutex_lock(&q->sysfs_lock);
        if (test_bit(QUEUE_FLAG_DEAD, &q->queue_flags)) {
                mutex_unlock(&q->sysfs_lock);
index d1fd300e8aeaa73f57945fb75fa7de819a7aeeaa..a8c37d4bbb32064f8a7f4dcd39734ccb403c2fae 100644 (file)
@@ -21,7 +21,6 @@ struct request *blk_queue_find_tag(struct request_queue *q, int tag)
 {
        return blk_map_queue_find_tag(q->queue_tags, tag);
 }
-
 EXPORT_SYMBOL(blk_queue_find_tag);
 
 /**
@@ -99,7 +98,6 @@ void blk_queue_free_tags(struct request_queue *q)
 {
        clear_bit(QUEUE_FLAG_QUEUED, &q->queue_flags);
 }
-
 EXPORT_SYMBOL(blk_queue_free_tags);
 
 static int
@@ -185,7 +183,8 @@ int blk_queue_init_tags(struct request_queue *q, int depth,
                if (!tags)
                        goto fail;
        } else if (q->queue_tags) {
-               if ((rc = blk_queue_resize_tags(q, depth)))
+               rc = blk_queue_resize_tags(q, depth);
+               if (rc)
                        return rc;
                set_bit(QUEUE_FLAG_QUEUED, &q->queue_flags);
                return 0;
@@ -203,7 +202,6 @@ fail:
        kfree(tags);
        return -ENOMEM;
 }
-
 EXPORT_SYMBOL(blk_queue_init_tags);
 
 /**
@@ -260,7 +258,6 @@ int blk_queue_resize_tags(struct request_queue *q, int new_depth)
        kfree(tag_map);
        return 0;
 }
-
 EXPORT_SYMBOL(blk_queue_resize_tags);
 
 /**
@@ -313,7 +310,6 @@ void blk_queue_end_tag(struct request_queue *q, struct request *rq)
        clear_bit_unlock(tag, bqt->tag_map);
        bqt->busy--;
 }
-
 EXPORT_SYMBOL(blk_queue_end_tag);
 
 /**
@@ -340,7 +336,7 @@ int blk_queue_start_tag(struct request_queue *q, struct request *rq)
        int tag;
 
        if (unlikely((rq->cmd_flags & REQ_QUEUED))) {
-               printk(KERN_ERR 
+               printk(KERN_ERR
                       "%s: request %p for device [%s] already tagged %d",
                       __FUNCTION__, rq,
                       rq->rq_disk ? rq->rq_disk->disk_name : "?", rq->tag);
@@ -370,7 +366,6 @@ int blk_queue_start_tag(struct request_queue *q, struct request *rq)
        bqt->busy++;
        return 0;
 }
-
 EXPORT_SYMBOL(blk_queue_start_tag);
 
 /**
@@ -392,5 +387,4 @@ void blk_queue_invalidate_tags(struct request_queue *q)
        list_for_each_safe(tmp, n, &q->tag_busy_list)
                blk_requeue_request(q, list_entry_rq(tmp));
 }
-
 EXPORT_SYMBOL(blk_queue_invalidate_tags);
index f28d1fb30608cd5667b6b6f9c67e545bdb4802de..ca198e61fa65c555bf936d2d628876313b62dbb1 100644 (file)
 /*
  * tunables
  */
-static const int cfq_quantum = 4;              /* max queue in one round of service */
+/* max queue in one round of service */
+static const int cfq_quantum = 4;
 static const int cfq_fifo_expire[2] = { HZ / 4, HZ / 8 };
-static const int cfq_back_max = 16 * 1024;     /* maximum backwards seek, in KiB */
-static const int cfq_back_penalty = 2;         /* penalty of a backwards seek */
-
+/* maximum backwards seek, in KiB */
+static const int cfq_back_max = 16 * 1024;
+/* penalty of a backwards seek */
+static const int cfq_back_penalty = 2;
 static const int cfq_slice_sync = HZ / 10;
 static int cfq_slice_async = HZ / 25;
 static const int cfq_slice_async_rq = 2;
@@ -37,7 +39,8 @@ static int cfq_slice_idle = HZ / 125;
 
 #define CFQ_SLICE_SCALE                (5)
 
-#define RQ_CIC(rq)             ((struct cfq_io_context*)(rq)->elevator_private)
+#define RQ_CIC(rq)             \
+       ((struct cfq_io_context *) (rq)->elevator_private)
 #define RQ_CFQQ(rq)            ((rq)->elevator_private2)
 
 static struct kmem_cache *cfq_pool;
@@ -171,15 +174,15 @@ enum cfqq_state_flags {
 #define CFQ_CFQQ_FNS(name)                                             \
 static inline void cfq_mark_cfqq_##name(struct cfq_queue *cfqq)                \
 {                                                                      \
-       cfqq->flags |= (1 << CFQ_CFQQ_FLAG_##name);                     \
+       (cfqq)->flags |= (1 << CFQ_CFQQ_FLAG_##name);                   \
 }                                                                      \
 static inline void cfq_clear_cfqq_##name(struct cfq_queue *cfqq)       \
 {                                                                      \
-       cfqq->flags &= ~(1 << CFQ_CFQQ_FLAG_##name);                    \
+       (cfqq)->flags &= ~(1 << CFQ_CFQQ_FLAG_##name);                  \
 }                                                                      \
 static inline int cfq_cfqq_##name(const struct cfq_queue *cfqq)                \
 {                                                                      \
-       return (cfqq->flags & (1 << CFQ_CFQQ_FLAG_##name)) != 0;        \
+       return ((cfqq)->flags & (1 << CFQ_CFQQ_FLAG_##name)) != 0;      \
 }
 
 CFQ_CFQQ_FNS(on_rr);
@@ -1005,7 +1008,8 @@ __cfq_dispatch_requests(struct cfq_data *cfqd, struct cfq_queue *cfqq,
                /*
                 * follow expired path, else get first next available
                 */
-               if ((rq = cfq_check_fifo(cfqq)) == NULL)
+               rq = cfq_check_fifo(cfqq);
+               if (rq == NULL)
                        rq = cfqq->next_rq;
 
                /*
@@ -1294,28 +1298,28 @@ static void cfq_init_prio_data(struct cfq_queue *cfqq, struct io_context *ioc)
 
        ioprio_class = IOPRIO_PRIO_CLASS(ioc->ioprio);
        switch (ioprio_class) {
-               default:
-                       printk(KERN_ERR "cfq: bad prio %x\n", ioprio_class);
-               case IOPRIO_CLASS_NONE:
-                       /*
-                        * no prio set, place us in the middle of the BE classes
-                        */
-                       cfqq->ioprio = task_nice_ioprio(tsk);
-                       cfqq->ioprio_class = IOPRIO_CLASS_BE;
-                       break;
-               case IOPRIO_CLASS_RT:
-                       cfqq->ioprio = task_ioprio(ioc);
-                       cfqq->ioprio_class = IOPRIO_CLASS_RT;
-                       break;
-               case IOPRIO_CLASS_BE:
-                       cfqq->ioprio = task_ioprio(ioc);
-                       cfqq->ioprio_class = IOPRIO_CLASS_BE;
-                       break;
-               case IOPRIO_CLASS_IDLE:
-                       cfqq->ioprio_class = IOPRIO_CLASS_IDLE;
-                       cfqq->ioprio = 7;
-                       cfq_clear_cfqq_idle_window(cfqq);
-                       break;
+       default:
+               printk(KERN_ERR "cfq: bad prio %x\n", ioprio_class);
+       case IOPRIO_CLASS_NONE:
+               /*
+                * no prio set, place us in the middle of the BE classes
+                */
+               cfqq->ioprio = task_nice_ioprio(tsk);
+               cfqq->ioprio_class = IOPRIO_CLASS_BE;
+               break;
+       case IOPRIO_CLASS_RT:
+               cfqq->ioprio = task_ioprio(ioc);
+               cfqq->ioprio_class = IOPRIO_CLASS_RT;
+               break;
+       case IOPRIO_CLASS_BE:
+               cfqq->ioprio = task_ioprio(ioc);
+               cfqq->ioprio_class = IOPRIO_CLASS_BE;
+               break;
+       case IOPRIO_CLASS_IDLE:
+               cfqq->ioprio_class = IOPRIO_CLASS_IDLE;
+               cfqq->ioprio = 7;
+               cfq_clear_cfqq_idle_window(cfqq);
+               break;
        }
 
        /*
@@ -1427,7 +1431,7 @@ out:
 static struct cfq_queue **
 cfq_async_queue_prio(struct cfq_data *cfqd, int ioprio_class, int ioprio)
 {
-       switch(ioprio_class) {
+       switch (ioprio_class) {
        case IOPRIO_CLASS_RT:
                return &cfqd->async_cfqq[0][ioprio];
        case IOPRIO_CLASS_BE:
@@ -2018,7 +2022,8 @@ static void cfq_idle_slice_timer(unsigned long data)
 
        spin_lock_irqsave(cfqd->queue->queue_lock, flags);
 
-       if ((cfqq = cfqd->active_queue) != NULL) {
+       cfqq = cfqd->active_queue;
+       if (cfqq) {
                timed_out = 0;
 
                /*
@@ -2212,14 +2217,18 @@ static ssize_t __FUNC(elevator_t *e, const char *page, size_t count)    \
        return ret;                                                     \
 }
 STORE_FUNCTION(cfq_quantum_store, &cfqd->cfq_quantum, 1, UINT_MAX, 0);
-STORE_FUNCTION(cfq_fifo_expire_sync_store, &cfqd->cfq_fifo_expire[1], 1, UINT_MAX, 1);
-STORE_FUNCTION(cfq_fifo_expire_async_store, &cfqd->cfq_fifo_expire[0], 1, UINT_MAX, 1);
+STORE_FUNCTION(cfq_fifo_expire_sync_store, &cfqd->cfq_fifo_expire[1], 1,
+               UINT_MAX, 1);
+STORE_FUNCTION(cfq_fifo_expire_async_store, &cfqd->cfq_fifo_expire[0], 1,
+               UINT_MAX, 1);
 STORE_FUNCTION(cfq_back_seek_max_store, &cfqd->cfq_back_max, 0, UINT_MAX, 0);
-STORE_FUNCTION(cfq_back_seek_penalty_store, &cfqd->cfq_back_penalty, 1, UINT_MAX, 0);
+STORE_FUNCTION(cfq_back_seek_penalty_store, &cfqd->cfq_back_penalty, 1,
+               UINT_MAX, 0);
 STORE_FUNCTION(cfq_slice_idle_store, &cfqd->cfq_slice_idle, 0, UINT_MAX, 1);
 STORE_FUNCTION(cfq_slice_sync_store, &cfqd->cfq_slice[1], 1, UINT_MAX, 1);
 STORE_FUNCTION(cfq_slice_async_store, &cfqd->cfq_slice[0], 1, UINT_MAX, 1);
-STORE_FUNCTION(cfq_slice_async_rq_store, &cfqd->cfq_slice_async_rq, 1, UINT_MAX, 0);
+STORE_FUNCTION(cfq_slice_async_rq_store, &cfqd->cfq_slice_async_rq, 1,
+               UINT_MAX, 0);
 #undef STORE_FUNCTION
 
 #define CFQ_ATTR(name) \
index 8cd5775acd7a2d4c1111acb0f823a57a46819dc0..bafbae0344d319e909e3e7add07467b1c0463a73 100644 (file)
@@ -45,7 +45,8 @@ static LIST_HEAD(elv_list);
  */
 static const int elv_hash_shift = 6;
 #define ELV_HASH_BLOCK(sec)    ((sec) >> 3)
-#define ELV_HASH_FN(sec)       (hash_long(ELV_HASH_BLOCK((sec)), elv_hash_shift))
+#define ELV_HASH_FN(sec)       \
+               (hash_long(ELV_HASH_BLOCK((sec)), elv_hash_shift))
 #define ELV_HASH_ENTRIES       (1 << elv_hash_shift)
 #define rq_hash_key(rq)                ((rq)->sector + (rq)->nr_sectors)
 #define ELV_ON_HASH(rq)                (!hlist_unhashed(&(rq)->hash))
@@ -224,15 +225,27 @@ int elevator_init(struct request_queue *q, char *name)
        q->end_sector = 0;
        q->boundary_rq = NULL;
 
-       if (name && !(e = elevator_get(name)))
-               return -EINVAL;
+       if (name) {
+               e = elevator_get(name);
+               if (!e)
+                       return -EINVAL;
+       }
 
-       if (!e && *chosen_elevator && !(e = elevator_get(chosen_elevator)))
-               printk("I/O scheduler %s not found\n", chosen_elevator);
+       if (!e && *chosen_elevator) {
+               e = elevator_get(chosen_elevator);
+               if (!e)
+                       printk(KERN_ERR "I/O scheduler %s not found\n",
+                                                       chosen_elevator);
+       }
 
-       if (!e && !(e = elevator_get(CONFIG_DEFAULT_IOSCHED))) {
-               printk("Default I/O scheduler not found, using no-op\n");
-               e = elevator_get("noop");
+       if (!e) {
+               e = elevator_get(CONFIG_DEFAULT_IOSCHED);
+               if (!e) {
+                       printk(KERN_ERR
+                               "Default I/O scheduler not found. " \
+                               "Using noop.\n");
+                       e = elevator_get("noop");
+               }
        }
 
        eq = elevator_alloc(q, e);
@@ -248,7 +261,6 @@ int elevator_init(struct request_queue *q, char *name)
        elevator_attach(q, eq, data);
        return ret;
 }
-
 EXPORT_SYMBOL(elevator_init);
 
 void elevator_exit(elevator_t *e)
@@ -261,7 +273,6 @@ void elevator_exit(elevator_t *e)
 
        kobject_put(&e->kobj);
 }
-
 EXPORT_SYMBOL(elevator_exit);
 
 static void elv_activate_rq(struct request_queue *q, struct request *rq)
@@ -353,7 +364,6 @@ struct request *elv_rb_add(struct rb_root *root, struct request *rq)
        rb_insert_color(&rq->rb_node, root);
        return NULL;
 }
-
 EXPORT_SYMBOL(elv_rb_add);
 
 void elv_rb_del(struct rb_root *root, struct request *rq)
@@ -362,7 +372,6 @@ void elv_rb_del(struct rb_root *root, struct request *rq)
        rb_erase(&rq->rb_node, root);
        RB_CLEAR_NODE(&rq->rb_node);
 }
-
 EXPORT_SYMBOL(elv_rb_del);
 
 struct request *elv_rb_find(struct rb_root *root, sector_t sector)
@@ -383,7 +392,6 @@ struct request *elv_rb_find(struct rb_root *root, sector_t sector)
 
        return NULL;
 }
-
 EXPORT_SYMBOL(elv_rb_find);
 
 /*
@@ -395,6 +403,7 @@ void elv_dispatch_sort(struct request_queue *q, struct request *rq)
 {
        sector_t boundary;
        struct list_head *entry;
+       int stop_flags;
 
        if (q->last_merge == rq)
                q->last_merge = NULL;
@@ -404,13 +413,13 @@ void elv_dispatch_sort(struct request_queue *q, struct request *rq)
        q->nr_sorted--;
 
        boundary = q->end_sector;
-
+       stop_flags = REQ_SOFTBARRIER | REQ_HARDBARRIER | REQ_STARTED;
        list_for_each_prev(entry, &q->queue_head) {
                struct request *pos = list_entry_rq(entry);
 
                if (rq_data_dir(rq) != rq_data_dir(pos))
                        break;
-               if (pos->cmd_flags & (REQ_SOFTBARRIER|REQ_HARDBARRIER|REQ_STARTED))
+               if (pos->cmd_flags & stop_flags)
                        break;
                if (rq->sector >= boundary) {
                        if (pos->sector < boundary)
@@ -425,7 +434,6 @@ void elv_dispatch_sort(struct request_queue *q, struct request *rq)
 
        list_add(&rq->queuelist, entry);
 }
-
 EXPORT_SYMBOL(elv_dispatch_sort);
 
 /*
@@ -446,7 +454,6 @@ void elv_dispatch_add_tail(struct request_queue *q, struct request *rq)
        q->boundary_rq = rq;
        list_add_tail(&rq->queuelist, &q->queue_head);
 }
-
 EXPORT_SYMBOL(elv_dispatch_add_tail);
 
 int elv_merge(struct request_queue *q, struct request **req, struct bio *bio)
@@ -665,7 +672,8 @@ void __elv_add_request(struct request_queue *q, struct request *rq, int where,
                        q->end_sector = rq_end_sector(rq);
                        q->boundary_rq = rq;
                }
-       } else if (!(rq->cmd_flags & REQ_ELVPRIV) && where == ELEVATOR_INSERT_SORT)
+       } else if (!(rq->cmd_flags & REQ_ELVPRIV) &&
+                   where == ELEVATOR_INSERT_SORT)
                where = ELEVATOR_INSERT_BACK;
 
        if (plug)
@@ -673,7 +681,6 @@ void __elv_add_request(struct request_queue *q, struct request *rq, int where,
 
        elv_insert(q, rq, where);
 }
-
 EXPORT_SYMBOL(__elv_add_request);
 
 void elv_add_request(struct request_queue *q, struct request *rq, int where,
@@ -685,7 +692,6 @@ void elv_add_request(struct request_queue *q, struct request *rq, int where,
        __elv_add_request(q, rq, where, plug);
        spin_unlock_irqrestore(q->queue_lock, flags);
 }
-
 EXPORT_SYMBOL(elv_add_request);
 
 static inline struct request *__elv_next_request(struct request_queue *q)
@@ -792,7 +798,6 @@ struct request *elv_next_request(struct request_queue *q)
 
        return rq;
 }
-
 EXPORT_SYMBOL(elv_next_request);
 
 void elv_dequeue_request(struct request_queue *q, struct request *rq)
@@ -810,7 +815,6 @@ void elv_dequeue_request(struct request_queue *q, struct request *rq)
        if (blk_account_rq(rq))
                q->in_flight++;
 }
-
 EXPORT_SYMBOL(elv_dequeue_request);
 
 int elv_queue_empty(struct request_queue *q)
@@ -825,7 +829,6 @@ int elv_queue_empty(struct request_queue *q)
 
        return 1;
 }
-
 EXPORT_SYMBOL(elv_queue_empty);
 
 struct request *elv_latter_request(struct request_queue *q, struct request *rq)
@@ -994,7 +997,8 @@ void elv_register(struct elevator_type *e)
                         !strcmp(e->elevator_name, CONFIG_DEFAULT_IOSCHED)))
                                def = " (default)";
 
-       printk(KERN_INFO "io scheduler %s registered%s\n", e->elevator_name, def);
+       printk(KERN_INFO "io scheduler %s registered%s\n", e->elevator_name,
+                                                               def);
 }
 EXPORT_SYMBOL_GPL(elv_register);
 
@@ -1126,7 +1130,8 @@ ssize_t elv_iosched_store(struct request_queue *q, const char *name,
        }
 
        if (!elevator_switch(q, e))
-               printk(KERN_ERR "elevator: switch to %s failed\n",elevator_name);
+               printk(KERN_ERR "elevator: switch to %s failed\n",
+                                                       elevator_name);
        return count;
 }
 
@@ -1160,7 +1165,6 @@ struct request *elv_rb_former_request(struct request_queue *q,
 
        return NULL;
 }
-
 EXPORT_SYMBOL(elv_rb_former_request);
 
 struct request *elv_rb_latter_request(struct request_queue *q,
@@ -1173,5 +1177,4 @@ struct request *elv_rb_latter_request(struct request_queue *q,
 
        return NULL;
 }
-
 EXPORT_SYMBOL(elv_rb_latter_request);
index 08d4ae201597cde366f07efc2a4a8f4f8e08d83e..d74d9fbb9fd21177eca9f2096d8df82fc4f2b469 100644 (file)
@@ -52,6 +52,8 @@ source "drivers/i2c/Kconfig"
 
 source "drivers/spi/Kconfig"
 
+source "drivers/gpio/Kconfig"
+
 source "drivers/w1/Kconfig"
 
 source "drivers/power/Kconfig"
@@ -91,6 +93,4 @@ source "drivers/dca/Kconfig"
 source "drivers/auxdisplay/Kconfig"
 
 source "drivers/uio/Kconfig"
-
-source "drivers/virtio/Kconfig"
 endmenu
index 0ee9a8a4095e6a5106789717dc57516a73d81fa8..f1c11db52a57e09b30b13380b1b000923dafcf3b 100644 (file)
@@ -5,6 +5,7 @@
 # Rewritten to use lists instead of if-statements.
 #
 
+obj-$(CONFIG_HAVE_GPIO_LIB)    += gpio/
 obj-$(CONFIG_PCI)              += pci/
 obj-$(CONFIG_PARISC)           += parisc/
 obj-$(CONFIG_RAPIDIO)          += rapidio/
index 81b2484297037e4b4c4e86e9b82d431e50021f00..fd1c4ba63367469f9826460c6b545407491f9f86 100644 (file)
@@ -192,18 +192,13 @@ acpi_status acpi_enter_sleep_state_prep(u8 sleep_state)
        arg.type = ACPI_TYPE_INTEGER;
        arg.integer.value = sleep_state;
 
-       /* Run the _PTS and _GTS methods */
+       /* Run the _PTS method */
 
        status = acpi_evaluate_object(NULL, METHOD_NAME__PTS, &arg_list, NULL);
        if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
                return_ACPI_STATUS(status);
        }
 
-       status = acpi_evaluate_object(NULL, METHOD_NAME__GTS, &arg_list, NULL);
-       if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
-               return_ACPI_STATUS(status);
-       }
-
        /* Setup the argument to _SST */
 
        switch (sleep_state) {
@@ -234,10 +229,6 @@ acpi_status acpi_enter_sleep_state_prep(u8 sleep_state)
                                "While executing method _SST"));
        }
 
-       /* Disable/Clear all GPEs */
-
-       status = acpi_hw_disable_all_gpes();
-
        return_ACPI_STATUS(status);
 }
 
@@ -262,6 +253,8 @@ acpi_status asmlinkage acpi_enter_sleep_state(u8 sleep_state)
        struct acpi_bit_register_info *sleep_type_reg_info;
        struct acpi_bit_register_info *sleep_enable_reg_info;
        u32 in_value;
+       struct acpi_object_list arg_list;
+       union acpi_object arg;
        acpi_status status;
 
        ACPI_FUNCTION_TRACE(acpi_enter_sleep_state);
@@ -307,6 +300,18 @@ acpi_status asmlinkage acpi_enter_sleep_state(u8 sleep_state)
                return_ACPI_STATUS(status);
        }
 
+       /* Execute the _GTS method */
+
+       arg_list.count = 1;
+       arg_list.pointer = &arg;
+       arg.type = ACPI_TYPE_INTEGER;
+       arg.integer.value = sleep_state;
+
+       status = acpi_evaluate_object(NULL, METHOD_NAME__GTS, &arg_list, NULL);
+       if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
+               return_ACPI_STATUS(status);
+       }
+
        /* Get current value of PM1A control */
 
        status = acpi_hw_register_read(ACPI_REGISTER_PM1_CONTROL, &PM1Acontrol);
@@ -473,17 +478,18 @@ ACPI_EXPORT_SYMBOL(acpi_enter_sleep_state_s4bios)
 
 /*******************************************************************************
  *
- * FUNCTION:    acpi_leave_sleep_state
+ * FUNCTION:    acpi_leave_sleep_state_prep
  *
- * PARAMETERS:  sleep_state         - Which sleep state we just exited
+ * PARAMETERS:  sleep_state         - Which sleep state we are exiting
  *
  * RETURN:      Status
  *
- * DESCRIPTION: Perform OS-independent ACPI cleanup after a sleep
- *              Called with interrupts ENABLED.
+ * DESCRIPTION: Perform the first state of OS-independent ACPI cleanup after a
+ *              sleep.
+ *              Called with interrupts DISABLED.
  *
  ******************************************************************************/
-acpi_status acpi_leave_sleep_state(u8 sleep_state)
+acpi_status acpi_leave_sleep_state_prep(u8 sleep_state)
 {
        struct acpi_object_list arg_list;
        union acpi_object arg;
@@ -493,7 +499,7 @@ acpi_status acpi_leave_sleep_state(u8 sleep_state)
        u32 PM1Acontrol;
        u32 PM1Bcontrol;
 
-       ACPI_FUNCTION_TRACE(acpi_leave_sleep_state);
+       ACPI_FUNCTION_TRACE(acpi_leave_sleep_state_prep);
 
        /*
         * Set SLP_TYPE and SLP_EN to state S0.
@@ -540,6 +546,41 @@ acpi_status acpi_leave_sleep_state(u8 sleep_state)
                }
        }
 
+       /* Execute the _BFS method */
+
+       arg_list.count = 1;
+       arg_list.pointer = &arg;
+       arg.type = ACPI_TYPE_INTEGER;
+       arg.integer.value = sleep_state;
+
+       status = acpi_evaluate_object(NULL, METHOD_NAME__BFS, &arg_list, NULL);
+       if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
+               ACPI_EXCEPTION((AE_INFO, status, "During Method _BFS"));
+       }
+
+       return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_leave_sleep_state
+ *
+ * PARAMETERS:  sleep_state         - Which sleep state we just exited
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Perform OS-independent ACPI cleanup after a sleep
+ *              Called with interrupts ENABLED.
+ *
+ ******************************************************************************/
+acpi_status acpi_leave_sleep_state(u8 sleep_state)
+{
+       struct acpi_object_list arg_list;
+       union acpi_object arg;
+       acpi_status status;
+
+       ACPI_FUNCTION_TRACE(acpi_leave_sleep_state);
+
        /* Ensure enter_sleep_state_prep -> enter_sleep_state ordering */
 
        acpi_gbl_sleep_type_a = ACPI_SLEEP_TYPE_INVALID;
@@ -558,12 +599,6 @@ acpi_status acpi_leave_sleep_state(u8 sleep_state)
                ACPI_EXCEPTION((AE_INFO, status, "During Method _SST"));
        }
 
-       arg.integer.value = sleep_state;
-       status = acpi_evaluate_object(NULL, METHOD_NAME__BFS, &arg_list, NULL);
-       if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
-               ACPI_EXCEPTION((AE_INFO, status, "During Method _BFS"));
-       }
-
        /*
         * GPEs must be enabled before _WAK is called as GPEs
         * might get fired there
index eb1f82f79153c0d3c6f9136b8a88faf829c886d1..199ea21461534cf835cefdafd641b5194bc8a1d1 100644 (file)
@@ -38,7 +38,7 @@
 #include <linux/dmi.h>
 #include <linux/moduleparam.h>
 #include <linux/sched.h>       /* need_resched() */
-#include <linux/latency.h>
+#include <linux/pm_qos_params.h>
 #include <linux/clockchips.h>
 #include <linux/cpuidle.h>
 
@@ -648,7 +648,8 @@ static void acpi_processor_idle(void)
        if (cx->promotion.state &&
            ((cx->promotion.state - pr->power.states) <= max_cstate)) {
                if (sleep_ticks > cx->promotion.threshold.ticks &&
-                 cx->promotion.state->latency <= system_latency_constraint()) {
+                 cx->promotion.state->latency <=
+                               pm_qos_requirement(PM_QOS_CPU_DMA_LATENCY)) {
                        cx->promotion.count++;
                        cx->demotion.count = 0;
                        if (cx->promotion.count >=
@@ -692,7 +693,8 @@ static void acpi_processor_idle(void)
         * or if the latency of the current state is unacceptable
         */
        if ((pr->power.state - pr->power.states) > max_cstate ||
-               pr->power.state->latency > system_latency_constraint()) {
+               pr->power.state->latency >
+                               pm_qos_requirement(PM_QOS_CPU_DMA_LATENCY)) {
                if (cx->demotion.state)
                        next_state = cx->demotion.state;
        }
@@ -1200,7 +1202,7 @@ static int acpi_processor_power_seq_show(struct seq_file *seq, void *offset)
                   "maximum allowed latency: %d usec\n",
                   pr->power.state ? pr->power.state - pr->power.states : 0,
                   max_cstate, (unsigned)pr->power.bm_activity,
-                  system_latency_constraint());
+                  pm_qos_requirement(PM_QOS_CPU_DMA_LATENCY));
 
        seq_puts(seq, "states:\n");
 
@@ -1718,8 +1720,9 @@ int __cpuinit acpi_processor_power_init(struct acpi_processor *pr,
                               "ACPI: processor limited to max C-state %d\n",
                               max_cstate);
                first_run++;
-#if !defined (CONFIG_CPU_IDLE) && defined (CONFIG_SMP)
-               register_latency_notifier(&acpi_processor_latency_notifier);
+#if !defined(CONFIG_CPU_IDLE) && defined(CONFIG_SMP)
+               pm_qos_add_notifier(PM_QOS_CPU_DMA_LATENCY,
+                               &acpi_processor_latency_notifier);
 #endif
        }
 
@@ -1806,7 +1809,8 @@ int acpi_processor_power_exit(struct acpi_processor *pr,
                 */
                cpu_idle_wait();
 #ifdef CONFIG_SMP
-               unregister_latency_notifier(&acpi_processor_latency_notifier);
+               pm_qos_remove_notifier(PM_QOS_CPU_DMA_LATENCY,
+                               &acpi_processor_latency_notifier);
 #endif
        }
 #endif
index cbfe9ae7a9e55226d82c86e6e6947121ee6e7adc..d9d531cce27f26e401ff920b8325968b5fd4fb37 100644 (file)
@@ -830,7 +830,7 @@ static int acpi_bus_get_flags(struct acpi_device *device)
        if (ACPI_SUCCESS(status))
                device->flags.wake_capable = 1;
 
-       /* TBD: Peformance management */
+       /* TBD: Performance management */
 
        return 0;
 }
index 2c0b6630f8ba54603530fce4574f8697faaabe9e..485de1347075c812c4c7dbd4347c67cca7bd67b3 100644 (file)
@@ -26,9 +26,24 @@ u8 sleep_states[ACPI_S_STATE_COUNT];
 
 #ifdef CONFIG_PM_SLEEP
 static u32 acpi_target_sleep_state = ACPI_STATE_S0;
+static bool acpi_sleep_finish_wake_up;
+
+/*
+ * ACPI 2.0 and later want us to execute _PTS after suspending devices, so we
+ * allow the user to request that behavior by using the 'acpi_new_pts_ordering'
+ * kernel command line option that causes the following variable to be set.
+ */
+static bool new_pts_ordering;
+
+static int __init acpi_new_pts_ordering(char *str)
+{
+       new_pts_ordering = true;
+       return 1;
+}
+__setup("acpi_new_pts_ordering", acpi_new_pts_ordering);
 #endif
 
-int acpi_sleep_prepare(u32 acpi_state)
+static int acpi_sleep_prepare(u32 acpi_state)
 {
 #ifdef CONFIG_ACPI_SLEEP
        /* do we have a wakeup address for S2 and S3? */
@@ -44,6 +59,8 @@ int acpi_sleep_prepare(u32 acpi_state)
        ACPI_FLUSH_CPU_CACHE();
        acpi_enable_wakeup_device_prep(acpi_state);
 #endif
+       printk(KERN_INFO PREFIX "Preparing to enter system sleep state S%d\n",
+               acpi_state);
        acpi_enter_sleep_state_prep(acpi_state);
        return 0;
 }
@@ -63,17 +80,25 @@ static u32 acpi_suspend_states[] = {
 static int init_8259A_after_S1;
 
 /**
- *     acpi_pm_set_target - Set the target system sleep state to the state
+ *     acpi_pm_begin - Set the target system sleep state to the state
  *             associated with given @pm_state, if supported.
  */
 
-static int acpi_pm_set_target(suspend_state_t pm_state)
+static int acpi_pm_begin(suspend_state_t pm_state)
 {
        u32 acpi_state = acpi_suspend_states[pm_state];
        int error = 0;
 
        if (sleep_states[acpi_state]) {
                acpi_target_sleep_state = acpi_state;
+               if (new_pts_ordering)
+                       return 0;
+
+               error = acpi_sleep_prepare(acpi_state);
+               if (error)
+                       acpi_target_sleep_state = ACPI_STATE_S0;
+               else
+                       acpi_sleep_finish_wake_up = true;
        } else {
                printk(KERN_ERR "ACPI does not support this state: %d\n",
                        pm_state);
@@ -91,12 +116,17 @@ static int acpi_pm_set_target(suspend_state_t pm_state)
 
 static int acpi_pm_prepare(void)
 {
-       int error = acpi_sleep_prepare(acpi_target_sleep_state);
+       if (new_pts_ordering) {
+               int error = acpi_sleep_prepare(acpi_target_sleep_state);
 
-       if (error)
-               acpi_target_sleep_state = ACPI_STATE_S0;
+               if (error) {
+                       acpi_target_sleep_state = ACPI_STATE_S0;
+                       return error;
+               }
+               acpi_sleep_finish_wake_up = true;
+       }
 
-       return error;
+       return ACPI_SUCCESS(acpi_hw_disable_all_gpes()) ? 0 : -EFAULT;
 }
 
 /**
@@ -120,10 +150,8 @@ static int acpi_pm_enter(suspend_state_t pm_state)
        if (acpi_state == ACPI_STATE_S3) {
                int error = acpi_save_state_mem();
 
-               if (error) {
-                       acpi_target_sleep_state = ACPI_STATE_S0;
+               if (error)
                        return error;
-               }
        }
 
        local_irq_save(flags);
@@ -139,6 +167,9 @@ static int acpi_pm_enter(suspend_state_t pm_state)
                break;
        }
 
+       /* Reprogram control registers and execute _BFS */
+       acpi_leave_sleep_state_prep(acpi_state);
+
        /* ACPI 3.0 specs (P62) says that it's the responsabilty
         * of the OSPM to clear the status bit [ implying that the
         * POWER_BUTTON event should not reach userspace ]
@@ -146,6 +177,13 @@ static int acpi_pm_enter(suspend_state_t pm_state)
        if (ACPI_SUCCESS(status) && (acpi_state == ACPI_STATE_S3))
                acpi_clear_event(ACPI_EVENT_POWER_BUTTON);
 
+       /*
+        * Disable and clear GPE status before interrupt is enabled. Some GPEs
+        * (like wakeup GPE) haven't handler, this can avoid such GPE misfire.
+        * acpi_leave_sleep_state will reenable specific GPEs later
+        */
+       acpi_hw_disable_all_gpes();
+
        local_irq_restore(flags);
        printk(KERN_DEBUG "Back to C!\n");
 
@@ -157,7 +195,7 @@ static int acpi_pm_enter(suspend_state_t pm_state)
 }
 
 /**
- *     acpi_pm_finish - Finish up suspend sequence.
+ *     acpi_pm_finish - Instruct the platform to leave a sleep state.
  *
  *     This is called after we wake back up (or if entering the sleep state
  *     failed). 
@@ -174,6 +212,7 @@ static void acpi_pm_finish(void)
        acpi_set_firmware_waking_vector((acpi_physical_address) 0);
 
        acpi_target_sleep_state = ACPI_STATE_S0;
+       acpi_sleep_finish_wake_up = false;
 
 #ifdef CONFIG_X86
        if (init_8259A_after_S1) {
@@ -183,6 +222,20 @@ static void acpi_pm_finish(void)
 #endif
 }
 
+/**
+ *     acpi_pm_end - Finish up suspend sequence.
+ */
+
+static void acpi_pm_end(void)
+{
+       /*
+        * This is necessary in case acpi_pm_finish() is not called directly
+        * during a failing transition to a sleep state.
+        */
+       if (acpi_sleep_finish_wake_up)
+               acpi_pm_finish();
+}
+
 static int acpi_pm_state_valid(suspend_state_t pm_state)
 {
        u32 acpi_state;
@@ -201,10 +254,11 @@ static int acpi_pm_state_valid(suspend_state_t pm_state)
 
 static struct platform_suspend_ops acpi_pm_ops = {
        .valid = acpi_pm_state_valid,
-       .set_target = acpi_pm_set_target,
+       .begin = acpi_pm_begin,
        .prepare = acpi_pm_prepare,
        .enter = acpi_pm_enter,
        .finish = acpi_pm_finish,
+       .end = acpi_pm_end,
 };
 
 /*
@@ -229,15 +283,36 @@ static struct dmi_system_id __initdata acpisleep_dmi_table[] = {
 #endif /* CONFIG_SUSPEND */
 
 #ifdef CONFIG_HIBERNATION
-static int acpi_hibernation_start(void)
+static int acpi_hibernation_begin(void)
 {
+       int error;
+
        acpi_target_sleep_state = ACPI_STATE_S4;
-       return 0;
+       if (new_pts_ordering)
+               return 0;
+
+       error = acpi_sleep_prepare(ACPI_STATE_S4);
+       if (error)
+               acpi_target_sleep_state = ACPI_STATE_S0;
+       else
+               acpi_sleep_finish_wake_up = true;
+
+       return error;
 }
 
 static int acpi_hibernation_prepare(void)
 {
-       return acpi_sleep_prepare(ACPI_STATE_S4);
+       if (new_pts_ordering) {
+               int error = acpi_sleep_prepare(ACPI_STATE_S4);
+
+               if (error) {
+                       acpi_target_sleep_state = ACPI_STATE_S0;
+                       return error;
+               }
+               acpi_sleep_finish_wake_up = true;
+       }
+
+       return ACPI_SUCCESS(acpi_hw_disable_all_gpes()) ? 0 : -EFAULT;
 }
 
 static int acpi_hibernation_enter(void)
@@ -251,6 +326,8 @@ static int acpi_hibernation_enter(void)
        acpi_enable_wakeup_device(ACPI_STATE_S4);
        /* This shouldn't return.  If it returns, we have a problem */
        status = acpi_enter_sleep_state(ACPI_STATE_S4);
+       /* Reprogram control registers and execute _BFS */
+       acpi_leave_sleep_state_prep(ACPI_STATE_S4);
        local_irq_restore(flags);
 
        return ACPI_SUCCESS(status) ? 0 : -EFAULT;
@@ -263,15 +340,12 @@ static void acpi_hibernation_leave(void)
         * enable it here.
         */
        acpi_enable();
+       /* Reprogram control registers and execute _BFS */
+       acpi_leave_sleep_state_prep(ACPI_STATE_S4);
 }
 
 static void acpi_hibernation_finish(void)
 {
-       /*
-        * If ACPI is not enabled by the BIOS and the boot kernel, we need to
-        * enable it here.
-        */
-       acpi_enable();
        acpi_disable_wakeup_device(ACPI_STATE_S4);
        acpi_leave_sleep_state(ACPI_STATE_S4);
 
@@ -279,6 +353,17 @@ static void acpi_hibernation_finish(void)
        acpi_set_firmware_waking_vector((acpi_physical_address) 0);
 
        acpi_target_sleep_state = ACPI_STATE_S0;
+       acpi_sleep_finish_wake_up = false;
+}
+
+static void acpi_hibernation_end(void)
+{
+       /*
+        * This is necessary in case acpi_hibernation_finish() is not called
+        * directly during a failing transition to the sleep state.
+        */
+       if (acpi_sleep_finish_wake_up)
+               acpi_hibernation_finish();
 }
 
 static int acpi_hibernation_pre_restore(void)
@@ -296,7 +381,8 @@ static void acpi_hibernation_restore_cleanup(void)
 }
 
 static struct platform_hibernation_ops acpi_hibernation_ops = {
-       .start = acpi_hibernation_start,
+       .begin = acpi_hibernation_begin,
+       .end = acpi_hibernation_end,
        .pre_snapshot = acpi_hibernation_prepare,
        .finish = acpi_hibernation_finish,
        .prepare = acpi_hibernation_prepare,
@@ -403,6 +489,7 @@ static void acpi_power_off_prepare(void)
 {
        /* Prepare to power off the system */
        acpi_sleep_prepare(ACPI_STATE_S5);
+       acpi_hw_disable_all_gpes();
 }
 
 static void acpi_power_off(void)
index a2ea125ae2d0e961c52aa909bdbb9083e2e5ea97..cfaf8f5b0a149b3b7bdcf056ebfcd2bfc7fb9870 100644 (file)
@@ -5,5 +5,3 @@ extern int acpi_suspend (u32 state);
 extern void acpi_enable_wakeup_device_prep(u8 sleep_state);
 extern void acpi_enable_wakeup_device(u8 sleep_state);
 extern void acpi_disable_wakeup_device(u8 sleep_state);
-
-extern int acpi_sleep_prepare(u32 acpi_state);
index cbbd3315a1e22bbc9eacc32942ccaded198c14a7..b630ee137ee197b4a2c8c9555ce1879886a26a3b 100644 (file)
@@ -1,6 +1,6 @@
 /*******************************************************************************
  *
- * Module Name: utresrc - Resource managment utilities
+ * Module Name: utresrc - Resource management utilities
  *
  ******************************************************************************/
 
index ae19c9b30d150b23f7b1bdec79e78ecb30fec289..ba8f7f4dfa1182cb1619007ea628c4ba08ade5e1 100644 (file)
@@ -69,7 +69,7 @@ config ATA_PIIX
 
 config SATA_MV
        tristate "Marvell SATA support (HIGHLY EXPERIMENTAL)"
-       depends on PCI && EXPERIMENTAL
+       depends on EXPERIMENTAL
        help
          This option enables support for the Marvell Serial ATA family.
          Currently supports 88SX[56]0[48][01] chips.
index 6f089b899a1a7e9587bbba731f9b9047e7c15eae..27c8d56111c2959b8d7f6cb64b9dccd85cee8a39 100644 (file)
@@ -475,6 +475,8 @@ static const struct pci_device_id ahci_pci_tbl[] = {
        { PCI_VDEVICE(INTEL, 0x294e), board_ahci }, /* ICH9M */
        { PCI_VDEVICE(INTEL, 0x502a), board_ahci }, /* Tolapai */
        { PCI_VDEVICE(INTEL, 0x502b), board_ahci }, /* Tolapai */
+       { PCI_VDEVICE(INTEL, 0x3a05), board_ahci }, /* ICH10 */
+       { PCI_VDEVICE(INTEL, 0x3a25), board_ahci }, /* ICH10 */
 
        /* JMicron 360/1/3/5/6, match class to avoid IDE function */
        { PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
index a65c8ae5c461136bae02ccf766030d1c3ecb20e4..4b99ed0c59bb2cbada622776825725791e05d997 100644 (file)
@@ -267,6 +267,14 @@ static const struct pci_device_id piix_pci_tbl[] = {
        { 0x8086, 0x292e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci },
        /* SATA Controller IDE (Tolapai) */
        { 0x8086, 0x5028, PCI_ANY_ID, PCI_ANY_ID, 0, 0, tolapai_sata_ahci },
+       /* SATA Controller IDE (ICH10) */
+       { 0x8086, 0x3a00, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci },
+       /* SATA Controller IDE (ICH10) */
+       { 0x8086, 0x3a06, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
+       /* SATA Controller IDE (ICH10) */
+       { 0x8086, 0x3a20, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci },
+       /* SATA Controller IDE (ICH10) */
+       { 0x8086, 0x3a26, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
 
        { }     /* terminate list */
 };
@@ -829,7 +837,7 @@ static void piix_set_piomode(struct ata_port *ap, struct ata_device *adev)
        if (is_slave) {
                /* clear TIME1|IE1|PPE1|DTE1 */
                master_data &= 0xff0f;
-               /* Enable SITRE (seperate slave timing register) */
+               /* Enable SITRE (separate slave timing register) */
                master_data |= 0x4000;
                /* enable PPE1, IE1 and TIME1 as needed */
                master_data |= (control << 4);
@@ -1068,7 +1076,7 @@ static void piix_sidpr_write(struct ata_device *dev, unsigned int reg, u32 val)
        iowrite32(val, hpriv->sidpr + PIIX_SIDPR_DATA);
 }
 
-u32 piix_merge_scr(u32 val0, u32 val1, const int * const *merge_tbl)
+static u32 piix_merge_scr(u32 val0, u32 val1, const int * const *merge_tbl)
 {
        u32 val = 0;
        int i, mi;
index bdbd55af70228ad38e646a4aa9e8bfcc1f0d0f37..361cf50cbdeab53565f57e3dcc6c84ec64cfd439 100644 (file)
@@ -3097,7 +3097,7 @@ static int ata_dev_set_mode(struct ata_device *dev)
 /**
  *     ata_do_set_mode - Program timings and issue SET FEATURES - XFER
  *     @link: link on which timings will be programmed
- *     @r_failed_dev: out paramter for failed device
+ *     @r_failed_dev: out parameter for failed device
  *
  *     Standard implementation of the function used to tune and set
  *     ATA device disk transfer mode (PIO3, UDMA6, etc.).  If
index 67e574de31e855c5ae6b1a046d1bc3f5b5f29c1c..db057b183d601b95c9ff950bfaef5acba39de562 100644 (file)
@@ -324,7 +324,7 @@ static int __init pata_at32_probe(struct platform_device *pdev)
        if (irq < 0)
                return irq;
 
-       /* Setup struct containing private infomation */
+       /* Setup struct containing private information */
        info = kzalloc(sizeof(struct at32_ide_info), GFP_KERNEL);
        if (!info)
                return -ENOMEM;
index a32e3c44a606f2f78d5169f6d11103b47749d1f6..7f87f105c2f6af44e61d119ba7e3f3dfc1930426 100644 (file)
@@ -299,7 +299,7 @@ static void bfin_set_piomode(struct ata_port *ap, struct ata_device *adev)
        */
        n6 = num_clocks_min(t6min, fsclk);
        if (mode >= 0 && mode <= 4 && n6 >= 1) {
-               pr_debug("set piomode: mode=%d, fsclk=%ud\n", mode, fsclk);
+               dev_dbg(adev->link->ap->dev, "set piomode: mode=%d, fsclk=%ud\n", mode, fsclk);
                /* calculate the timing values for register transfers. */
                while (mode > 0 && pio_fsclk[mode] > fsclk)
                        mode--;
@@ -376,7 +376,7 @@ static void bfin_set_dmamode(struct ata_port *ap, struct ata_device *adev)
 
        mode = adev->dma_mode - XFER_UDMA_0;
        if (mode >= 0 && mode <= 5) {
-               pr_debug("set udmamode: mode=%d\n", mode);
+               dev_dbg(adev->link->ap->dev, "set udmamode: mode=%d\n", mode);
                /* the most restrictive timing value is t6 and tc,
                 * the DIOW - data hold. If one SCLK pulse is longer
                 * than this minimum value then register
@@ -433,7 +433,7 @@ static void bfin_set_dmamode(struct ata_port *ap, struct ata_device *adev)
 
        mode = adev->dma_mode - XFER_MW_DMA_0;
        if (mode >= 0 && mode <= 2) {
-               pr_debug("set mdmamode: mode=%d\n", mode);
+               dev_dbg(adev->link->ap->dev, "set mdmamode: mode=%d\n", mode);
                /* the most restrictive timing value is tf, the DMACK to
                 * read data released. If one SCLK pulse is longer than
                 * this maximum value then the MDMA mode
@@ -697,7 +697,7 @@ static void bfin_tf_load(struct ata_port *ap, const struct ata_taskfile *tf)
                        write_atapi_register(base, ATA_REG_LBAL, tf->hob_lbal);
                        write_atapi_register(base, ATA_REG_LBAM, tf->hob_lbam);
                        write_atapi_register(base, ATA_REG_LBAH, tf->hob_lbah);
-                       pr_debug("hob: feat 0x%X nsect 0x%X, lba 0x%X "
+                       dev_dbg(ap->dev, "hob: feat 0x%X nsect 0x%X, lba 0x%X "
                                 "0x%X 0x%X\n",
                                tf->hob_feature,
                                tf->hob_nsect,
@@ -711,7 +711,7 @@ static void bfin_tf_load(struct ata_port *ap, const struct ata_taskfile *tf)
                write_atapi_register(base, ATA_REG_LBAL, tf->lbal);
                write_atapi_register(base, ATA_REG_LBAM, tf->lbam);
                write_atapi_register(base, ATA_REG_LBAH, tf->lbah);
-               pr_debug("feat 0x%X nsect 0x%X lba 0x%X 0x%X 0x%X\n",
+               dev_dbg(ap->dev, "feat 0x%X nsect 0x%X lba 0x%X 0x%X 0x%X\n",
                        tf->feature,
                        tf->nsect,
                        tf->lbal,
@@ -721,7 +721,7 @@ static void bfin_tf_load(struct ata_port *ap, const struct ata_taskfile *tf)
 
        if (tf->flags & ATA_TFLAG_DEVICE) {
                write_atapi_register(base, ATA_REG_DEVICE, tf->device);
-               pr_debug("device 0x%X\n", tf->device);
+               dev_dbg(ap->dev, "device 0x%X\n", tf->device);
        }
 
        ata_wait_idle(ap);
@@ -782,7 +782,7 @@ static void bfin_exec_command(struct ata_port *ap,
                              const struct ata_taskfile *tf)
 {
        void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
-       pr_debug("ata%u: cmd 0x%X\n", ap->print_id, tf->command);
+       dev_dbg(ap->dev, "ata%u: cmd 0x%X\n", ap->print_id, tf->command);
 
        write_atapi_register(base, ATA_REG_CMD, tf->command);
        ata_pause(ap);
@@ -834,7 +834,7 @@ static void bfin_bmdma_setup(struct ata_queued_cmd *qc)
        struct scatterlist *sg;
        unsigned int si;
 
-       pr_debug("in atapi dma setup\n");
+       dev_dbg(qc->ap->dev, "in atapi dma setup\n");
        /* Program the ATA_CTRL register with dir */
        if (qc->tf.flags & ATA_TFLAG_WRITE) {
                /* fill the ATAPI DMA controller */
@@ -870,7 +870,7 @@ static void bfin_bmdma_start(struct ata_queued_cmd *qc)
        struct scatterlist *sg;
        unsigned int si;
 
-       pr_debug("in atapi dma start\n");
+       dev_dbg(qc->ap->dev, "in atapi dma start\n");
        if (!(ap->udma_mask || ap->mwdma_mask))
                return;
 
@@ -888,7 +888,7 @@ static void bfin_bmdma_start(struct ata_queued_cmd *qc)
                                sg_dma_address(sg) + sg_dma_len(sg));
                }
                enable_dma(CH_ATAPI_TX);
-               pr_debug("enable udma write\n");
+               dev_dbg(qc->ap->dev, "enable udma write\n");
 
                /* Send ATA DMA write command */
                bfin_exec_command(ap, &qc->tf);
@@ -898,7 +898,7 @@ static void bfin_bmdma_start(struct ata_queued_cmd *qc)
                        | XFER_DIR));
        } else {
                enable_dma(CH_ATAPI_RX);
-               pr_debug("enable udma read\n");
+               dev_dbg(qc->ap->dev, "enable udma read\n");
 
                /* Send ATA DMA read command */
                bfin_exec_command(ap, &qc->tf);
@@ -936,7 +936,7 @@ static void bfin_bmdma_stop(struct ata_queued_cmd *qc)
        struct scatterlist *sg;
        unsigned int si;
 
-       pr_debug("in atapi dma stop\n");
+       dev_dbg(qc->ap->dev, "in atapi dma stop\n");
        if (!(ap->udma_mask || ap->mwdma_mask))
                return;
 
@@ -1147,15 +1147,15 @@ static unsigned char bfin_bmdma_status(struct ata_port *ap)
        void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
        unsigned short int_status = ATAPI_GET_INT_STATUS(base);
 
-       if (ATAPI_GET_STATUS(base) & (MULTI_XFER_ON|ULTRA_XFER_ON)) {
+       if (ATAPI_GET_STATUS(base) & (MULTI_XFER_ON|ULTRA_XFER_ON))
                host_stat |= ATA_DMA_ACTIVE;
-       }
-       if (int_status & (MULTI_DONE_INT|UDMAIN_DONE_INT|UDMAOUT_DONE_INT)) {
+       if (int_status & (MULTI_DONE_INT|UDMAIN_DONE_INT|UDMAOUT_DONE_INT|
+               ATAPI_DEV_INT))
                host_stat |= ATA_DMA_INTR;
-       }
-       if (int_status & (MULTI_TERM_INT|UDMAIN_TERM_INT|UDMAOUT_TERM_INT)) {
-               host_stat |= ATA_DMA_ERR;
-       }
+       if (int_status & (MULTI_TERM_INT|UDMAIN_TERM_INT|UDMAOUT_TERM_INT))
+               host_stat |= ATA_DMA_ERR|ATA_DMA_INTR;
+
+       dev_dbg(ap->dev, "ATAPI: host_stat=0x%x\n", host_stat);
 
        return host_stat;
 }
@@ -1213,8 +1213,7 @@ static void bfin_irq_clear(struct ata_port *ap)
 {
        void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
 
-       pr_debug("in atapi irq clear\n");
-
+       dev_dbg(ap->dev, "in atapi irq clear\n");
        ATAPI_SET_INT_STATUS(base, ATAPI_GET_INT_STATUS(base)|ATAPI_DEV_INT
                | MULTI_DONE_INT | UDMAIN_DONE_INT | UDMAOUT_DONE_INT
                | MULTI_TERM_INT | UDMAIN_TERM_INT | UDMAOUT_TERM_INT);
@@ -1232,7 +1231,7 @@ static unsigned char bfin_irq_on(struct ata_port *ap)
        void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
        u8 tmp;
 
-       pr_debug("in atapi irq on\n");
+       dev_dbg(ap->dev, "in atapi irq on\n");
        ap->ctl &= ~ATA_NIEN;
        ap->last_ctl = ap->ctl;
 
@@ -1255,7 +1254,7 @@ static void bfin_bmdma_freeze(struct ata_port *ap)
 {
        void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
 
-       pr_debug("in atapi dma freeze\n");
+       dev_dbg(ap->dev, "in atapi dma freeze\n");
        ap->ctl |= ATA_NIEN;
        ap->last_ctl = ap->ctl;
 
@@ -1328,7 +1327,7 @@ static void bfin_error_handler(struct ata_port *ap)
 
 static void bfin_port_stop(struct ata_port *ap)
 {
-       pr_debug("in atapi port stop\n");
+       dev_dbg(ap->dev, "in atapi port stop\n");
        if (ap->udma_mask != 0 || ap->mwdma_mask != 0) {
                free_dma(CH_ATAPI_RX);
                free_dma(CH_ATAPI_TX);
@@ -1337,7 +1336,7 @@ static void bfin_port_stop(struct ata_port *ap)
 
 static int bfin_port_start(struct ata_port *ap)
 {
-       pr_debug("in atapi port start\n");
+       dev_dbg(ap->dev, "in atapi port start\n");
        if (!(ap->udma_mask || ap->mwdma_mask))
                return 0;
 
@@ -1373,10 +1372,6 @@ static struct scsi_host_template bfin_sht = {
        .slave_configure        = ata_scsi_slave_config,
        .slave_destroy          = ata_scsi_slave_destroy,
        .bios_param             = ata_std_bios_param,
-#ifdef CONFIG_PM
-       .resume                 = ata_scsi_device_resume,
-       .suspend                = ata_scsi_device_suspend,
-#endif
 };
 
 static const struct ata_port_operations bfin_pata_ops = {
index d4590f546c497c7aa2ae2a365bc1d2a0232b4bff..7ed279b0a12edb90af54c013261cfadf88a8d5c1 100644 (file)
@@ -229,7 +229,7 @@ static int __devinit cs5520_init_one(struct pci_dev *pdev, const struct pci_devi
                return -ENOMEM;
 
        /* Perform set up for DMA */
-       if (pci_enable_device_bars(pdev, 1<<2)) {
+       if (pci_enable_device_io(pdev)) {
                printk(KERN_ERR DRV_NAME ": unable to configure BAR2.\n");
                return -ENODEV;
        }
index 043dcd35106c0877aed1ce07e91a8f6a9d4b8892..dc33220fe5b20ca9588af25522d40288627bf2cf 100644 (file)
@@ -135,7 +135,7 @@ static void efar_set_piomode (struct ata_port *ap, struct ata_device *adev)
                idetm_data &= 0xCC0F;
                idetm_data |= (control << 4);
 
-               /* Slave timing in seperate register */
+               /* Slave timing in separate register */
                pci_read_config_byte(dev, 0x44, &slave_data);
                slave_data &= 0x0F << shift;
                slave_data |= ((timings[pio][0] << 2) | timings[pio][1]) << shift;
index 1eda821e5e395b32dd78a86bc8c7ab2bd58fd537..e0c2cc29d0ca93d60b970441ef0d4d54599aced9 100644 (file)
@@ -128,7 +128,7 @@ static void it8213_set_piomode (struct ata_port *ap, struct ata_device *adev)
                idetm_data &= 0xCC0F;
                idetm_data |= (control << 4);
 
-               /* Slave timing in seperate register */
+               /* Slave timing in separate register */
                pci_read_config_byte(dev, 0x44, &slave_data);
                slave_data &= 0xF0;
                slave_data |= ((timings[pio][0] << 2) | timings[pio][1]) << 4;
index 87546d9f1ca0839cf5067d94116af34ae297c7e7..dc7e91562e436fafadab3d2796e328ac4cf5b351 100644 (file)
@@ -345,7 +345,7 @@ static void sis_old_set_dmamode (struct ata_port *ap, struct ata_device *adev)
 
        if (adev->dma_mode < XFER_UDMA_0) {
                /* bits 3-0 hold recovery timing bits 8-10 active timing and
-                  the higer bits are dependant on the device */
+                  the higher bits are dependant on the device */
                timing &= ~0x870F;
                timing |= mwdma_bits[speed];
        } else {
@@ -385,7 +385,7 @@ static void sis_66_set_dmamode (struct ata_port *ap, struct ata_device *adev)
 
        if (adev->dma_mode < XFER_UDMA_0) {
                /* bits 3-0 hold recovery timing bits 8-10 active timing and
-                  the higer bits are dependant on the device, bit 15 udma */
+                  the higher bits are dependant on the device, bit 15 udma */
                timing &= ~0x870F;
                timing |= mwdma_bits[speed];
        } else {
index 1388cef52c073d4dc3045e16103ca904acdce942..81ef207f82652ad7b3002ac77b10d42daf2473cf 100644 (file)
@@ -26,7 +26,7 @@
 #include <linux/libata.h>
 
 #define DRV_NAME "pata_sl82c105"
-#define DRV_VERSION "0.3.2"
+#define DRV_VERSION "0.3.3"
 
 enum {
        /*
@@ -206,6 +206,34 @@ static void sl82c105_bmdma_stop(struct ata_queued_cmd *qc)
        sl82c105_set_piomode(ap, qc->dev);
 }
 
+/**
+ *     sl82c105_qc_defer       -       implement serialization
+ *     @qc: command
+ *
+ *     We must issue one command per host not per channel because
+ *     of the reset bug.
+ *
+ *     Q: is the scsi host lock sufficient ?
+ */
+
+static int sl82c105_qc_defer(struct ata_queued_cmd *qc)
+{
+       struct ata_host *host = qc->ap->host;
+       struct ata_port *alt = host->ports[1 ^ qc->ap->port_no];
+       int rc;
+
+       /* First apply the usual rules */       
+       rc = ata_std_qc_defer(qc);
+       if (rc != 0)
+               return rc;
+
+       /* Now apply serialization rules. Only allow a command if the
+          other channel state machine is idle */
+       if (alt && alt->qc_active)
+               return  ATA_DEFER_PORT;
+       return 0;
+}
+
 static struct scsi_host_template sl82c105_sht = {
        .module                 = THIS_MODULE,
        .name                   = DRV_NAME,
@@ -245,6 +273,7 @@ static struct ata_port_operations sl82c105_port_ops = {
        .bmdma_stop     = sl82c105_bmdma_stop,
        .bmdma_status   = ata_bmdma_status,
 
+       .qc_defer       = sl82c105_qc_defer,
        .qc_prep        = ata_qc_prep,
        .qc_issue       = ata_qc_issue_prot,
 
@@ -312,7 +341,7 @@ static int sl82c105_init_one(struct pci_dev *dev, const struct pci_device_id *id
        };
        /* for now use only the first port */
        const struct ata_port_info *ppi[] = { &info_early,
-                                              &ata_dummy_port_info };
+                                              NULL };
        u32 val;
        int rev;
 
index 96e614a1c1692c896c52d6a6fb71c13bb03470d9..59e65edc5820123169441619fbb515011e837410 100644 (file)
@@ -108,17 +108,6 @@ struct inic_port_priv {
        u8      cached_pirq_mask;
 };
 
-static int inic_slave_config(struct scsi_device *sdev)
-{
-       /* This controller is braindamaged.  dma_boundary is 0xffff
-        * like others but it will lock up the whole machine HARD if
-        * 65536 byte PRD entry is fed.  Reduce maximum segment size.
-        */
-       blk_queue_max_segment_size(sdev->request_queue, 65536 - 512);
-
-       return ata_scsi_slave_config(sdev);
-}
-
 static struct scsi_host_template inic_sht = {
        .module                 = THIS_MODULE,
        .name                   = DRV_NAME,
@@ -132,7 +121,7 @@ static struct scsi_host_template inic_sht = {
        .use_clustering         = ATA_SHT_USE_CLUSTERING,
        .proc_name              = DRV_NAME,
        .dma_boundary           = ATA_DMA_BOUNDARY,
-       .slave_configure        = inic_slave_config,
+       .slave_configure        = ata_scsi_slave_config,
        .slave_destroy          = ata_scsi_slave_destroy,
        .bios_param             = ata_std_bios_param,
 };
@@ -730,6 +719,18 @@ static int inic_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
                return rc;
        }
 
+       /*
+        * This controller is braindamaged.  dma_boundary is 0xffff
+        * like others but it will lock up the whole machine HARD if
+        * 65536 byte PRD entry is fed. Reduce maximum segment size.
+        */
+       rc = pci_set_dma_max_seg_size(pdev, 65536 - 512);
+       if (rc) {
+               dev_printk(KERN_ERR, &pdev->dev,
+                          "failed to set the maximum segment size.\n");
+               return rc;
+       }
+
        rc = init_controller(iomap[MMIO_BAR], hpriv->cached_hctl);
        if (rc) {
                dev_printk(KERN_ERR, &pdev->dev,
index 7e72463a90eb8b84a9ea76ad13e91aea2b5249d8..3c1b5c9027db5a4446a041b3316440c77c1b1468 100644 (file)
   I distinctly remember a couple workarounds (one related to PCI-X)
   are still needed.
 
-  4) Add NCQ support (easy to intermediate, once new-EH support appears)
+  2) Improve/fix IRQ and error handling sequences.
+
+  3) ATAPI support (Marvell claims the 60xx/70xx chips can do it).
+
+  4) Think about TCQ support here, and for libata in general
+  with controllers that suppport it via host-queuing hardware
+  (a software-only implementation could be a nightmare).
 
   5) Investigate problems with PCI Message Signalled Interrupts (MSI).
 
@@ -53,8 +59,6 @@
   Target mode, for those without docs, is the ability to directly
   connect two SATA controllers.
 
-  13) Verify that 7042 is fully supported.  I only have a 6042.
-
 */
 
 
@@ -73,7 +77,7 @@
 #include <linux/libata.h>
 
 #define DRV_NAME       "sata_mv"
-#define DRV_VERSION    "1.01"
+#define DRV_VERSION    "1.20"
 
 enum {
        /* BAR's are enumerated in terms of pci_resource_start() terms */
@@ -107,14 +111,12 @@ enum {
 
        /* CRQB needs alignment on a 1KB boundary. Size == 1KB
         * CRPB needs alignment on a 256B boundary. Size == 256B
-        * SG count of 176 leads to MV_PORT_PRIV_DMA_SZ == 4KB
         * ePRD (SG) entries need alignment on a 16B boundary. Size == 16B
         */
        MV_CRQB_Q_SZ            = (32 * MV_MAX_Q_DEPTH),
        MV_CRPB_Q_SZ            = (8 * MV_MAX_Q_DEPTH),
-       MV_MAX_SG_CT            = 176,
+       MV_MAX_SG_CT            = 256,
        MV_SG_TBL_SZ            = (16 * MV_MAX_SG_CT),
-       MV_PORT_PRIV_DMA_SZ     = (MV_CRQB_Q_SZ + MV_CRPB_Q_SZ + MV_SG_TBL_SZ),
 
        MV_PORTS_PER_HC         = 4,
        /* == (port / MV_PORTS_PER_HC) to determine HC from 0-7 port */
@@ -125,6 +127,9 @@ enum {
        /* Host Flags */
        MV_FLAG_DUAL_HC         = (1 << 30),  /* two SATA Host Controllers */
        MV_FLAG_IRQ_COALESCE    = (1 << 29),  /* IRQ coalescing capability */
+       /* SoC integrated controllers, no PCI interface */
+       MV_FLAG_SOC = (1 << 28),
+
        MV_COMMON_FLAGS         = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
                                  ATA_FLAG_MMIO | ATA_FLAG_NO_ATAPI |
                                  ATA_FLAG_PIO_POLLING,
@@ -170,7 +175,7 @@ enum {
 
        PCIE_IRQ_CAUSE_OFS      = 0x1900,
        PCIE_IRQ_MASK_OFS       = 0x1910,
-       PCIE_UNMASK_ALL_IRQS    = 0x70a,        /* assorted bits */
+       PCIE_UNMASK_ALL_IRQS    = 0x40a,        /* assorted bits */
 
        HC_MAIN_IRQ_CAUSE_OFS   = 0x1d60,
        HC_MAIN_IRQ_MASK_OFS    = 0x1d64,
@@ -210,6 +215,7 @@ enum {
        /* SATA registers */
        SATA_STATUS_OFS         = 0x300,  /* ctrl, err regs follow status */
        SATA_ACTIVE_OFS         = 0x350,
+       SATA_FIS_IRQ_CAUSE_OFS  = 0x364,
        PHY_MODE3               = 0x310,
        PHY_MODE4               = 0x314,
        PHY_MODE2               = 0x330,
@@ -222,11 +228,11 @@ enum {
 
        /* Port registers */
        EDMA_CFG_OFS            = 0,
-       EDMA_CFG_Q_DEPTH        = 0,                    /* queueing disabled */
-       EDMA_CFG_NCQ            = (1 << 5),
-       EDMA_CFG_NCQ_GO_ON_ERR  = (1 << 14),            /* continue on error */
-       EDMA_CFG_RD_BRST_EXT    = (1 << 11),            /* read burst 512B */
-       EDMA_CFG_WR_BUFF_LEN    = (1 << 13),            /* write buffer 512B */
+       EDMA_CFG_Q_DEPTH        = 0x1f,         /* max device queue depth */
+       EDMA_CFG_NCQ            = (1 << 5),     /* for R/W FPDMA queued */
+       EDMA_CFG_NCQ_GO_ON_ERR  = (1 << 14),    /* continue on error */
+       EDMA_CFG_RD_BRST_EXT    = (1 << 11),    /* read burst 512B */
+       EDMA_CFG_WR_BUFF_LEN    = (1 << 13),    /* write buffer 512B */
 
        EDMA_ERR_IRQ_CAUSE_OFS  = 0x8,
        EDMA_ERR_IRQ_MASK_OFS   = 0xc,
@@ -244,14 +250,33 @@ enum {
        EDMA_ERR_CRPB_PAR       = (1 << 10),    /* CRPB parity error */
        EDMA_ERR_INTRL_PAR      = (1 << 11),    /* internal parity error */
        EDMA_ERR_IORDY          = (1 << 12),    /* IORdy timeout */
+
        EDMA_ERR_LNK_CTRL_RX    = (0xf << 13),  /* link ctrl rx error */
-       EDMA_ERR_LNK_CTRL_RX_2  = (1 << 15),
+       EDMA_ERR_LNK_CTRL_RX_0  = (1 << 13),    /* transient: CRC err */
+       EDMA_ERR_LNK_CTRL_RX_1  = (1 << 14),    /* transient: FIFO err */
+       EDMA_ERR_LNK_CTRL_RX_2  = (1 << 15),    /* fatal: caught SYNC */
+       EDMA_ERR_LNK_CTRL_RX_3  = (1 << 16),    /* transient: FIS rx err */
+
        EDMA_ERR_LNK_DATA_RX    = (0xf << 17),  /* link data rx error */
+
        EDMA_ERR_LNK_CTRL_TX    = (0x1f << 21), /* link ctrl tx error */
+       EDMA_ERR_LNK_CTRL_TX_0  = (1 << 21),    /* transient: CRC err */
+       EDMA_ERR_LNK_CTRL_TX_1  = (1 << 22),    /* transient: FIFO err */
+       EDMA_ERR_LNK_CTRL_TX_2  = (1 << 23),    /* transient: caught SYNC */
+       EDMA_ERR_LNK_CTRL_TX_3  = (1 << 24),    /* transient: caught DMAT */
+       EDMA_ERR_LNK_CTRL_TX_4  = (1 << 25),    /* transient: FIS collision */
+
        EDMA_ERR_LNK_DATA_TX    = (0x1f << 26), /* link data tx error */
+
        EDMA_ERR_TRANS_PROTO    = (1 << 31),    /* transport protocol error */
        EDMA_ERR_OVERRUN_5      = (1 << 5),
        EDMA_ERR_UNDERRUN_5     = (1 << 6),
+
+       EDMA_ERR_IRQ_TRANSIENT  = EDMA_ERR_LNK_CTRL_RX_0 |
+                                 EDMA_ERR_LNK_CTRL_RX_1 |
+                                 EDMA_ERR_LNK_CTRL_RX_3 |
+                                 EDMA_ERR_LNK_CTRL_TX,
+
        EDMA_EH_FREEZE          = EDMA_ERR_D_PAR |
                                  EDMA_ERR_PRD_PAR |
                                  EDMA_ERR_DEV_DCON |
@@ -311,12 +336,14 @@ enum {
 
        /* Port private flags (pp_flags) */
        MV_PP_FLAG_EDMA_EN      = (1 << 0),     /* is EDMA engine enabled? */
+       MV_PP_FLAG_NCQ_EN       = (1 << 1),     /* is EDMA set up for NCQ? */
        MV_PP_FLAG_HAD_A_RESET  = (1 << 2),     /* 1st hard reset complete? */
 };
 
 #define IS_GEN_I(hpriv) ((hpriv)->hp_flags & MV_HP_GEN_I)
 #define IS_GEN_II(hpriv) ((hpriv)->hp_flags & MV_HP_GEN_II)
 #define IS_GEN_IIE(hpriv) ((hpriv)->hp_flags & MV_HP_GEN_IIE)
+#define HAS_PCI(host) (!((host)->ports[0]->flags & MV_FLAG_SOC))
 
 enum {
        /* DMA boundary 0xffff is required by the s/g splitting
@@ -379,8 +406,8 @@ struct mv_port_priv {
        dma_addr_t              crqb_dma;
        struct mv_crpb          *crpb;
        dma_addr_t              crpb_dma;
-       struct mv_sg            *sg_tbl;
-       dma_addr_t              sg_tbl_dma;
+       struct mv_sg            *sg_tbl[MV_MAX_Q_DEPTH];
+       dma_addr_t              sg_tbl_dma[MV_MAX_Q_DEPTH];
 
        unsigned int            req_idx;
        unsigned int            resp_idx;
@@ -400,6 +427,14 @@ struct mv_host_priv {
        u32                     irq_cause_ofs;
        u32                     irq_mask_ofs;
        u32                     unmask_all_irqs;
+       /*
+        * These consistent DMA memory pools give us guaranteed
+        * alignment for hardware-accessed data structures,
+        * and less memory waste in accomplishing the alignment.
+        */
+       struct dma_pool         *crqb_pool;
+       struct dma_pool         *crpb_pool;
+       struct dma_pool         *sg_tbl_pool;
 };
 
 struct mv_hw_ops {
@@ -411,7 +446,7 @@ struct mv_hw_ops {
        int (*reset_hc)(struct mv_host_priv *hpriv, void __iomem *mmio,
                        unsigned int n_hc);
        void (*reset_flash)(struct mv_host_priv *hpriv, void __iomem *mmio);
-       void (*reset_bus)(struct pci_dev *pdev, void __iomem *mmio);
+       void (*reset_bus)(struct ata_host *host, void __iomem *mmio);
 };
 
 static void mv_irq_clear(struct ata_port *ap);
@@ -425,10 +460,9 @@ static void mv_qc_prep(struct ata_queued_cmd *qc);
 static void mv_qc_prep_iie(struct ata_queued_cmd *qc);
 static unsigned int mv_qc_issue(struct ata_queued_cmd *qc);
 static void mv_error_handler(struct ata_port *ap);
-static void mv_post_int_cmd(struct ata_queued_cmd *qc);
 static void mv_eh_freeze(struct ata_port *ap);
 static void mv_eh_thaw(struct ata_port *ap);
-static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
+static void mv6_dev_config(struct ata_device *dev);
 
 static void mv5_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio,
                           unsigned int port);
@@ -438,7 +472,7 @@ static void mv5_read_preamp(struct mv_host_priv *hpriv, int idx,
 static int mv5_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio,
                        unsigned int n_hc);
 static void mv5_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio);
-static void mv5_reset_bus(struct pci_dev *pdev, void __iomem *mmio);
+static void mv5_reset_bus(struct ata_host *host, void __iomem *mmio);
 
 static void mv6_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio,
                           unsigned int port);
@@ -448,10 +482,17 @@ static void mv6_read_preamp(struct mv_host_priv *hpriv, int idx,
 static int mv6_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio,
                        unsigned int n_hc);
 static void mv6_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio);
-static void mv_reset_pci_bus(struct pci_dev *pdev, void __iomem *mmio);
+static void mv_reset_pci_bus(struct ata_host *host, void __iomem *mmio);
 static void mv_channel_reset(struct mv_host_priv *hpriv, void __iomem *mmio,
                             unsigned int port_no);
+static void mv_edma_cfg(struct mv_port_priv *pp, struct mv_host_priv *hpriv,
+                       void __iomem *port_mmio, int want_ncq);
+static int __mv_stop_dma(struct ata_port *ap);
 
+/* .sg_tablesize is (MV_MAX_SG_CT / 2) in the structures below
+ * because we have to allow room for worst case splitting of
+ * PRDs for 64K boundaries in mv_fill_sg().
+ */
 static struct scsi_host_template mv5_sht = {
        .module                 = THIS_MODULE,
        .name                   = DRV_NAME,
@@ -475,7 +516,8 @@ static struct scsi_host_template mv6_sht = {
        .name                   = DRV_NAME,
        .ioctl                  = ata_scsi_ioctl,
        .queuecommand           = ata_scsi_queuecmd,
-       .can_queue              = ATA_DEF_QUEUE,
+       .change_queue_depth     = ata_scsi_change_queue_depth,
+       .can_queue              = MV_MAX_Q_DEPTH - 1,
        .this_id                = ATA_SHT_THIS_ID,
        .sg_tablesize           = MV_MAX_SG_CT / 2,
        .cmd_per_lun            = ATA_SHT_CMD_PER_LUN,
@@ -505,7 +547,6 @@ static const struct ata_port_operations mv5_ops = {
        .irq_on                 = ata_irq_on,
 
        .error_handler          = mv_error_handler,
-       .post_internal_cmd      = mv_post_int_cmd,
        .freeze                 = mv_eh_freeze,
        .thaw                   = mv_eh_thaw,
 
@@ -517,6 +558,7 @@ static const struct ata_port_operations mv5_ops = {
 };
 
 static const struct ata_port_operations mv6_ops = {
+       .dev_config             = mv6_dev_config,
        .tf_load                = ata_tf_load,
        .tf_read                = ata_tf_read,
        .check_status           = ata_check_status,
@@ -533,9 +575,9 @@ static const struct ata_port_operations mv6_ops = {
        .irq_on                 = ata_irq_on,
 
        .error_handler          = mv_error_handler,
-       .post_internal_cmd      = mv_post_int_cmd,
        .freeze                 = mv_eh_freeze,
        .thaw                   = mv_eh_thaw,
+       .qc_defer               = ata_std_qc_defer,
 
        .scr_read               = mv_scr_read,
        .scr_write              = mv_scr_write,
@@ -561,9 +603,9 @@ static const struct ata_port_operations mv_iie_ops = {
        .irq_on                 = ata_irq_on,
 
        .error_handler          = mv_error_handler,
-       .post_internal_cmd      = mv_post_int_cmd,
        .freeze                 = mv_eh_freeze,
        .thaw                   = mv_eh_thaw,
+       .qc_defer               = ata_std_qc_defer,
 
        .scr_read               = mv_scr_read,
        .scr_write              = mv_scr_write,
@@ -592,26 +634,29 @@ static const struct ata_port_info mv_port_info[] = {
                .port_ops       = &mv5_ops,
        },
        {  /* chip_604x */
-               .flags          = MV_COMMON_FLAGS | MV_6XXX_FLAGS,
+               .flags          = MV_COMMON_FLAGS | MV_6XXX_FLAGS |
+                                 ATA_FLAG_NCQ,
                .pio_mask       = 0x1f, /* pio0-4 */
                .udma_mask      = ATA_UDMA6,
                .port_ops       = &mv6_ops,
        },
        {  /* chip_608x */
                .flags          = MV_COMMON_FLAGS | MV_6XXX_FLAGS |
-                                 MV_FLAG_DUAL_HC,
+                                 ATA_FLAG_NCQ | MV_FLAG_DUAL_HC,
                .pio_mask       = 0x1f, /* pio0-4 */
                .udma_mask      = ATA_UDMA6,
                .port_ops       = &mv6_ops,
        },
        {  /* chip_6042 */
-               .flags          = MV_COMMON_FLAGS | MV_6XXX_FLAGS,
+               .flags          = MV_COMMON_FLAGS | MV_6XXX_FLAGS |
+                                 ATA_FLAG_NCQ,
                .pio_mask       = 0x1f, /* pio0-4 */
                .udma_mask      = ATA_UDMA6,
                .port_ops       = &mv_iie_ops,
        },
        {  /* chip_7042 */
-               .flags          = MV_COMMON_FLAGS | MV_6XXX_FLAGS,
+               .flags          = MV_COMMON_FLAGS | MV_6XXX_FLAGS |
+                                 ATA_FLAG_NCQ,
                .pio_mask       = 0x1f, /* pio0-4 */
                .udma_mask      = ATA_UDMA6,
                .port_ops       = &mv_iie_ops,
@@ -648,13 +693,6 @@ static const struct pci_device_id mv_pci_tbl[] = {
        { }                     /* terminate list */
 };
 
-static struct pci_driver mv_pci_driver = {
-       .name                   = DRV_NAME,
-       .id_table               = mv_pci_tbl,
-       .probe                  = mv_init_one,
-       .remove                 = ata_pci_remove_one,
-};
-
 static const struct mv_hw_ops mv5xxx_ops = {
        .phy_errata             = mv5_phy_errata,
        .enable_leds            = mv5_enable_leds,
@@ -673,45 +711,6 @@ static const struct mv_hw_ops mv6xxx_ops = {
        .reset_bus              = mv_reset_pci_bus,
 };
 
-/*
- * module options
- */
-static int msi;              /* Use PCI msi; either zero (off, default) or non-zero */
-
-
-/* move to PCI layer or libata core? */
-static int pci_go_64(struct pci_dev *pdev)
-{
-       int rc;
-
-       if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
-               rc = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
-               if (rc) {
-                       rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
-                       if (rc) {
-                               dev_printk(KERN_ERR, &pdev->dev,
-                                          "64-bit DMA enable failed\n");
-                               return rc;
-                       }
-               }
-       } else {
-               rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
-               if (rc) {
-                       dev_printk(KERN_ERR, &pdev->dev,
-                                  "32-bit DMA enable failed\n");
-                       return rc;
-               }
-               rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
-               if (rc) {
-                       dev_printk(KERN_ERR, &pdev->dev,
-                                  "32-bit consistent DMA enable failed\n");
-                       return rc;
-               }
-       }
-
-       return rc;
-}
-
 /*
  * Functions
  */
@@ -815,19 +814,46 @@ static void mv_set_edma_ptrs(void __iomem *port_mmio,
  *      LOCKING:
  *      Inherited from caller.
  */
-static void mv_start_dma(void __iomem *base, struct mv_host_priv *hpriv,
-                        struct mv_port_priv *pp)
+static void mv_start_dma(struct ata_port *ap, void __iomem *port_mmio,
+                        struct mv_port_priv *pp, u8 protocol)
 {
+       int want_ncq = (protocol == ATA_PROT_NCQ);
+
+       if (pp->pp_flags & MV_PP_FLAG_EDMA_EN) {
+               int using_ncq = ((pp->pp_flags & MV_PP_FLAG_NCQ_EN) != 0);
+               if (want_ncq != using_ncq)
+                       __mv_stop_dma(ap);
+       }
        if (!(pp->pp_flags & MV_PP_FLAG_EDMA_EN)) {
+               struct mv_host_priv *hpriv = ap->host->private_data;
+               int hard_port = mv_hardport_from_port(ap->port_no);
+               void __iomem *hc_mmio = mv_hc_base_from_port(
+                               ap->host->iomap[MV_PRIMARY_BAR], hard_port);
+               u32 hc_irq_cause, ipending;
+
                /* clear EDMA event indicators, if any */
-               writelfl(0, base + EDMA_ERR_IRQ_CAUSE_OFS);
+               writelfl(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
+
+               /* clear EDMA interrupt indicator, if any */
+               hc_irq_cause = readl(hc_mmio + HC_IRQ_CAUSE_OFS);
+               ipending = (DEV_IRQ << hard_port) |
+                               (CRPB_DMA_DONE << hard_port);
+               if (hc_irq_cause & ipending) {
+                       writelfl(hc_irq_cause & ~ipending,
+                                hc_mmio + HC_IRQ_CAUSE_OFS);
+               }
+
+               mv_edma_cfg(pp, hpriv, port_mmio, want_ncq);
+
+               /* clear FIS IRQ Cause */
+               writelfl(0, port_mmio + SATA_FIS_IRQ_CAUSE_OFS);
 
-               mv_set_edma_ptrs(base, hpriv, pp);
+               mv_set_edma_ptrs(port_mmio, hpriv, pp);
 
-               writelfl(EDMA_EN, base + EDMA_CMD_OFS);
+               writelfl(EDMA_EN, port_mmio + EDMA_CMD_OFS);
                pp->pp_flags |= MV_PP_FLAG_EDMA_EN;
        }
-       WARN_ON(!(EDMA_EN & readl(base + EDMA_CMD_OFS)));
+       WARN_ON(!(EDMA_EN & readl(port_mmio + EDMA_CMD_OFS)));
 }
 
 /**
@@ -1003,38 +1029,76 @@ static int mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val)
                return -EINVAL;
 }
 
-static void mv_edma_cfg(struct ata_port *ap, struct mv_host_priv *hpriv,
-                       void __iomem *port_mmio)
+static void mv6_dev_config(struct ata_device *adev)
 {
-       u32 cfg = readl(port_mmio + EDMA_CFG_OFS);
+       /*
+        * We don't have hob_nsect when doing NCQ commands on Gen-II.
+        * See mv_qc_prep() for more info.
+        */
+       if (adev->flags & ATA_DFLAG_NCQ)
+               if (adev->max_sectors > ATA_MAX_SECTORS)
+                       adev->max_sectors = ATA_MAX_SECTORS;
+}
+
+static void mv_edma_cfg(struct mv_port_priv *pp, struct mv_host_priv *hpriv,
+                       void __iomem *port_mmio, int want_ncq)
+{
+       u32 cfg;
 
        /* set up non-NCQ EDMA configuration */
-       cfg &= ~(1 << 9);       /* disable eQue */
+       cfg = EDMA_CFG_Q_DEPTH;         /* always 0x1f for *all* chips */
 
-       if (IS_GEN_I(hpriv)) {
-               cfg &= ~0x1f;           /* clear queue depth */
+       if (IS_GEN_I(hpriv))
                cfg |= (1 << 8);        /* enab config burst size mask */
-       }
 
-       else if (IS_GEN_II(hpriv)) {
-               cfg &= ~0x1f;           /* clear queue depth */
+       else if (IS_GEN_II(hpriv))
                cfg |= EDMA_CFG_RD_BRST_EXT | EDMA_CFG_WR_BUFF_LEN;
-               cfg &= ~(EDMA_CFG_NCQ | EDMA_CFG_NCQ_GO_ON_ERR); /* clear NCQ */
-       }
 
        else if (IS_GEN_IIE(hpriv)) {
                cfg |= (1 << 23);       /* do not mask PM field in rx'd FIS */
                cfg |= (1 << 22);       /* enab 4-entry host queue cache */
-               cfg &= ~(1 << 19);      /* dis 128-entry queue (for now?) */
                cfg |= (1 << 18);       /* enab early completion */
                cfg |= (1 << 17);       /* enab cut-through (dis stor&forwrd) */
-               cfg &= ~(1 << 16);      /* dis FIS-based switching (for now) */
-               cfg &= ~(EDMA_CFG_NCQ); /* clear NCQ */
        }
 
+       if (want_ncq) {
+               cfg |= EDMA_CFG_NCQ;
+               pp->pp_flags |=  MV_PP_FLAG_NCQ_EN;
+       } else
+               pp->pp_flags &= ~MV_PP_FLAG_NCQ_EN;
+
        writelfl(cfg, port_mmio + EDMA_CFG_OFS);
 }
 
+static void mv_port_free_dma_mem(struct ata_port *ap)
+{
+       struct mv_host_priv *hpriv = ap->host->private_data;
+       struct mv_port_priv *pp = ap->private_data;
+       int tag;
+
+       if (pp->crqb) {
+               dma_pool_free(hpriv->crqb_pool, pp->crqb, pp->crqb_dma);
+               pp->crqb = NULL;
+       }
+       if (pp->crpb) {
+               dma_pool_free(hpriv->crpb_pool, pp->crpb, pp->crpb_dma);
+               pp->crpb = NULL;
+       }
+       /*
+        * For GEN_I, there's no NCQ, so we have only a single sg_tbl.
+        * For later hardware, we have one unique sg_tbl per NCQ tag.
+        */
+       for (tag = 0; tag < MV_MAX_Q_DEPTH; ++tag) {
+               if (pp->sg_tbl[tag]) {
+                       if (tag == 0 || !IS_GEN_I(hpriv))
+                               dma_pool_free(hpriv->sg_tbl_pool,
+                                             pp->sg_tbl[tag],
+                                             pp->sg_tbl_dma[tag]);
+                       pp->sg_tbl[tag] = NULL;
+               }
+       }
+}
+
 /**
  *      mv_port_start - Port specific init/start routine.
  *      @ap: ATA channel to manipulate
@@ -1051,51 +1115,47 @@ static int mv_port_start(struct ata_port *ap)
        struct mv_host_priv *hpriv = ap->host->private_data;
        struct mv_port_priv *pp;
        void __iomem *port_mmio = mv_ap_base(ap);
-       void *mem;
-       dma_addr_t mem_dma;
        unsigned long flags;
-       int rc;
+       int tag, rc;
 
        pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL);
        if (!pp)
                return -ENOMEM;
-
-       mem = dmam_alloc_coherent(dev, MV_PORT_PRIV_DMA_SZ, &mem_dma,
-                                 GFP_KERNEL);
-       if (!mem)
-               return -ENOMEM;
-       memset(mem, 0, MV_PORT_PRIV_DMA_SZ);
+       ap->private_data = pp;
 
        rc = ata_pad_alloc(ap, dev);
        if (rc)
                return rc;
 
-       /* First item in chunk of DMA memory:
-        * 32-slot command request table (CRQB), 32 bytes each in size
-        */
-       pp->crqb = mem;
-       pp->crqb_dma = mem_dma;
-       mem += MV_CRQB_Q_SZ;
-       mem_dma += MV_CRQB_Q_SZ;
+       pp->crqb = dma_pool_alloc(hpriv->crqb_pool, GFP_KERNEL, &pp->crqb_dma);
+       if (!pp->crqb)
+               return -ENOMEM;
+       memset(pp->crqb, 0, MV_CRQB_Q_SZ);
 
-       /* Second item:
-        * 32-slot command response table (CRPB), 8 bytes each in size
-        */
-       pp->crpb = mem;
-       pp->crpb_dma = mem_dma;
-       mem += MV_CRPB_Q_SZ;
-       mem_dma += MV_CRPB_Q_SZ;
+       pp->crpb = dma_pool_alloc(hpriv->crpb_pool, GFP_KERNEL, &pp->crpb_dma);
+       if (!pp->crpb)
+               goto out_port_free_dma_mem;
+       memset(pp->crpb, 0, MV_CRPB_Q_SZ);
 
-       /* Third item:
-        * Table of scatter-gather descriptors (ePRD), 16 bytes each
+       /*
+        * For GEN_I, there's no NCQ, so we only allocate a single sg_tbl.
+        * For later hardware, we need one unique sg_tbl per NCQ tag.
         */
-       pp->sg_tbl = mem;
-       pp->sg_tbl_dma = mem_dma;
+       for (tag = 0; tag < MV_MAX_Q_DEPTH; ++tag) {
+               if (tag == 0 || !IS_GEN_I(hpriv)) {
+                       pp->sg_tbl[tag] = dma_pool_alloc(hpriv->sg_tbl_pool,
+                                             GFP_KERNEL, &pp->sg_tbl_dma[tag]);
+                       if (!pp->sg_tbl[tag])
+                               goto out_port_free_dma_mem;
+               } else {
+                       pp->sg_tbl[tag]     = pp->sg_tbl[0];
+                       pp->sg_tbl_dma[tag] = pp->sg_tbl_dma[0];
+               }
+       }
 
        spin_lock_irqsave(&ap->host->lock, flags);
 
-       mv_edma_cfg(ap, hpriv, port_mmio);
-
+       mv_edma_cfg(pp, hpriv, port_mmio, 0);
        mv_set_edma_ptrs(port_mmio, hpriv, pp);
 
        spin_unlock_irqrestore(&ap->host->lock, flags);
@@ -1104,8 +1164,11 @@ static int mv_port_start(struct ata_port *ap)
         * we'll be unable to send non-data, PIO, etc due to restricted access
         * to shadow regs.
         */
-       ap->private_data = pp;
        return 0;
+
+out_port_free_dma_mem:
+       mv_port_free_dma_mem(ap);
+       return -ENOMEM;
 }
 
 /**
@@ -1120,6 +1183,7 @@ static int mv_port_start(struct ata_port *ap)
 static void mv_port_stop(struct ata_port *ap)
 {
        mv_stop_dma(ap);
+       mv_port_free_dma_mem(ap);
 }
 
 /**
@@ -1138,7 +1202,7 @@ static void mv_fill_sg(struct ata_queued_cmd *qc)
        struct mv_sg *mv_sg, *last_sg = NULL;
        unsigned int si;
 
-       mv_sg = pp->sg_tbl;
+       mv_sg = pp->sg_tbl[qc->tag];
        for_each_sg(qc->sg, sg, qc->n_elem, si) {
                dma_addr_t addr = sg_dma_address(sg);
                u32 sg_len = sg_dma_len(sg);
@@ -1194,7 +1258,8 @@ static void mv_qc_prep(struct ata_queued_cmd *qc)
        u16 flags = 0;
        unsigned in_index;
 
-       if (qc->tf.protocol != ATA_PROT_DMA)
+       if ((qc->tf.protocol != ATA_PROT_DMA) &&
+           (qc->tf.protocol != ATA_PROT_NCQ))
                return;
 
        /* Fill in command request block
@@ -1203,15 +1268,14 @@ static void mv_qc_prep(struct ata_queued_cmd *qc)
                flags |= CRQB_FLAG_READ;
        WARN_ON(MV_MAX_Q_DEPTH <= qc->tag);
        flags |= qc->tag << CRQB_TAG_SHIFT;
-       flags |= qc->tag << CRQB_IOID_SHIFT;    /* 50xx appears to ignore this*/
 
        /* get current queue index from software */
        in_index = pp->req_idx & MV_MAX_Q_DEPTH_MASK;
 
        pp->crqb[in_index].sg_addr =
-               cpu_to_le32(pp->sg_tbl_dma & 0xffffffff);
+               cpu_to_le32(pp->sg_tbl_dma[qc->tag] & 0xffffffff);
        pp->crqb[in_index].sg_addr_hi =
-               cpu_to_le32((pp->sg_tbl_dma >> 16) >> 16);
+               cpu_to_le32((pp->sg_tbl_dma[qc->tag] >> 16) >> 16);
        pp->crqb[in_index].ctrl_flags = cpu_to_le16(flags);
 
        cw = &pp->crqb[in_index].ata_cmd[0];
@@ -1231,13 +1295,11 @@ static void mv_qc_prep(struct ata_queued_cmd *qc)
        case ATA_CMD_WRITE_FUA_EXT:
                mv_crqb_pack_cmd(cw++, tf->hob_nsect, ATA_REG_NSECT, 0);
                break;
-#ifdef LIBATA_NCQ              /* FIXME: remove this line when NCQ added */
        case ATA_CMD_FPDMA_READ:
        case ATA_CMD_FPDMA_WRITE:
                mv_crqb_pack_cmd(cw++, tf->hob_feature, ATA_REG_FEATURE, 0);
                mv_crqb_pack_cmd(cw++, tf->feature, ATA_REG_FEATURE, 0);
                break;
-#endif                         /* FIXME: remove this line when NCQ added */
        default:
                /* The only other commands EDMA supports in non-queued and
                 * non-NCQ mode are: [RW] STREAM DMA and W DMA FUA EXT, none
@@ -1286,7 +1348,8 @@ static void mv_qc_prep_iie(struct ata_queued_cmd *qc)
        unsigned in_index;
        u32 flags = 0;
 
-       if (qc->tf.protocol != ATA_PROT_DMA)
+       if ((qc->tf.protocol != ATA_PROT_DMA) &&
+           (qc->tf.protocol != ATA_PROT_NCQ))
                return;
 
        /* Fill in Gen IIE command request block
@@ -1296,15 +1359,14 @@ static void mv_qc_prep_iie(struct ata_queued_cmd *qc)
 
        WARN_ON(MV_MAX_Q_DEPTH <= qc->tag);
        flags |= qc->tag << CRQB_TAG_SHIFT;
-       flags |= qc->tag << CRQB_IOID_SHIFT;    /* "I/O Id" is -really-
-                                                  what we use as our tag */
+       flags |= qc->tag << CRQB_HOSTQ_SHIFT;
 
        /* get current queue index from software */
        in_index = pp->req_idx & MV_MAX_Q_DEPTH_MASK;
 
        crqb = (struct mv_crqb_iie *) &pp->crqb[in_index];
-       crqb->addr = cpu_to_le32(pp->sg_tbl_dma & 0xffffffff);
-       crqb->addr_hi = cpu_to_le32((pp->sg_tbl_dma >> 16) >> 16);
+       crqb->addr = cpu_to_le32(pp->sg_tbl_dma[qc->tag] & 0xffffffff);
+       crqb->addr_hi = cpu_to_le32((pp->sg_tbl_dma[qc->tag] >> 16) >> 16);
        crqb->flags = cpu_to_le32(flags);
 
        tf = &qc->tf;
@@ -1351,10 +1413,10 @@ static unsigned int mv_qc_issue(struct ata_queued_cmd *qc)
        struct ata_port *ap = qc->ap;
        void __iomem *port_mmio = mv_ap_base(ap);
        struct mv_port_priv *pp = ap->private_data;
-       struct mv_host_priv *hpriv = ap->host->private_data;
        u32 in_index;
 
-       if (qc->tf.protocol != ATA_PROT_DMA) {
+       if ((qc->tf.protocol != ATA_PROT_DMA) &&
+           (qc->tf.protocol != ATA_PROT_NCQ)) {
                /* We're about to send a non-EDMA capable command to the
                 * port.  Turn off EDMA so there won't be problems accessing
                 * shadow block, etc registers.
@@ -1363,13 +1425,7 @@ static unsigned int mv_qc_issue(struct ata_queued_cmd *qc)
                return ata_qc_issue_prot(qc);
        }
 
-       mv_start_dma(port_mmio, hpriv, pp);
-
-       in_index = pp->req_idx & MV_MAX_Q_DEPTH_MASK;
-
-       /* until we do queuing, the queue should be empty at this point */
-       WARN_ON(in_index != ((readl(port_mmio + EDMA_REQ_Q_OUT_PTR_OFS)
-               >> EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK));
+       mv_start_dma(ap, port_mmio, pp, qc->tf.protocol);
 
        pp->req_idx++;
 
@@ -1437,6 +1493,7 @@ static void mv_err_intr(struct ata_port *ap, struct ata_queued_cmd *qc)
                ata_ehi_hotplugged(ehi);
                ata_ehi_push_desc(ehi, edma_err_cause & EDMA_ERR_DEV_DCON ?
                        "dev disconnect" : "dev connect");
+               action |= ATA_EH_HARDRESET;
        }
 
        if (IS_GEN_I(hpriv)) {
@@ -1465,7 +1522,7 @@ static void mv_err_intr(struct ata_port *ap, struct ata_queued_cmd *qc)
        }
 
        /* Clear EDMA now that SERR cleanup done */
-       writelfl(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
+       writelfl(~edma_err_cause, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
 
        if (!err_mask) {
                err_mask = AC_ERR_OTHER;
@@ -1538,23 +1595,17 @@ static void mv_intr_edma(struct ata_port *ap)
                 * support for queueing.  this works transparently for
                 * queued and non-queued modes.
                 */
-               else if (IS_GEN_II(hpriv))
-                       tag = (le16_to_cpu(pp->crpb[out_index].id)
-                               >> CRPB_IOID_SHIFT_6) & 0x3f;
-
-               else /* IS_GEN_IIE */
-                       tag = (le16_to_cpu(pp->crpb[out_index].id)
-                               >> CRPB_IOID_SHIFT_7) & 0x3f;
+               else
+                       tag = le16_to_cpu(pp->crpb[out_index].id) & 0x1f;
 
                qc = ata_qc_from_tag(ap, tag);
 
-               /* lower 8 bits of status are EDMA_ERR_IRQ_CAUSE_OFS
-                * bits (WARNING: might not necessarily be associated
-                * with this command), which -should- be clear
-                * if all is well
+               /* For non-NCQ mode, the lower 8 bits of status
+                * are from EDMA_ERR_IRQ_CAUSE_OFS,
+                * which should be zero if all went well.
                 */
                status = le16_to_cpu(pp->crpb[out_index].flags);
-               if (unlikely(status & 0xff)) {
+               if ((status & 0xff) && !(pp->pp_flags & MV_PP_FLAG_NCQ_EN)) {
                        mv_err_intr(ap, qc);
                        return;
                }
@@ -1715,20 +1766,21 @@ static irqreturn_t mv_interrupt(int irq, void *dev_instance)
        struct ata_host *host = dev_instance;
        unsigned int hc, handled = 0, n_hcs;
        void __iomem *mmio = host->iomap[MV_PRIMARY_BAR];
-       u32 irq_stat;
+       u32 irq_stat, irq_mask;
 
+       spin_lock(&host->lock);
        irq_stat = readl(mmio + HC_MAIN_IRQ_CAUSE_OFS);
+       irq_mask = readl(mmio + HC_MAIN_IRQ_MASK_OFS);
 
        /* check the cases where we either have nothing pending or have read
         * a bogus register value which can indicate HW removal or PCI fault
         */
-       if (!irq_stat || (0xffffffffU == irq_stat))
-               return IRQ_NONE;
+       if (!(irq_stat & irq_mask) || (0xffffffffU == irq_stat))
+               goto out_unlock;
 
        n_hcs = mv_get_hc_count(host->ports[0]->flags);
-       spin_lock(&host->lock);
 
-       if (unlikely(irq_stat & PCI_ERR)) {
+       if (unlikely((irq_stat & PCI_ERR) && HAS_PCI(host))) {
                mv_pci_error(host, mmio);
                handled = 1;
                goto out_unlock;        /* skip all other HC irq handling */
@@ -1799,8 +1851,9 @@ static int mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val)
                return -EINVAL;
 }
 
-static void mv5_reset_bus(struct pci_dev *pdev, void __iomem *mmio)
+static void mv5_reset_bus(struct ata_host *host, void __iomem *mmio)
 {
+       struct pci_dev *pdev = to_pci_dev(host->dev);
        int early_5080;
 
        early_5080 = (pdev->device == 0x5080) && (pdev->revision == 0);
@@ -1811,7 +1864,7 @@ static void mv5_reset_bus(struct pci_dev *pdev, void __iomem *mmio)
                writel(tmp, mmio + MV_PCI_EXP_ROM_BAR_CTL);
        }
 
-       mv_reset_pci_bus(pdev, mmio);
+       mv_reset_pci_bus(host, mmio);
 }
 
 static void mv5_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio)
@@ -1935,9 +1988,8 @@ static int mv5_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio,
 
 #undef ZERO
 #define ZERO(reg) writel(0, mmio + (reg))
-static void mv_reset_pci_bus(struct pci_dev *pdev, void __iomem *mmio)
+static void mv_reset_pci_bus(struct ata_host *host, void __iomem *mmio)
 {
-       struct ata_host     *host = dev_get_drvdata(&pdev->dev);
        struct mv_host_priv *hpriv = host->private_data;
        u32 tmp;
 
@@ -2329,11 +2381,6 @@ static void mv_error_handler(struct ata_port *ap)
                  mv_hardreset, mv_postreset);
 }
 
-static void mv_post_int_cmd(struct ata_queued_cmd *qc)
-{
-       mv_stop_dma(qc->ap);
-}
-
 static void mv_eh_freeze(struct ata_port *ap)
 {
        void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR];
@@ -2427,8 +2474,8 @@ static void mv_port_init(struct ata_ioports *port,  void __iomem *port_mmio)
        writelfl(readl(port_mmio + serr_ofs), port_mmio + serr_ofs);
        writelfl(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
 
-       /* unmask all EDMA error interrupts */
-       writelfl(~0, port_mmio + EDMA_ERR_IRQ_MASK_OFS);
+       /* unmask all non-transient EDMA error interrupts */
+       writelfl(~EDMA_ERR_IRQ_TRANSIENT, port_mmio + EDMA_ERR_IRQ_MASK_OFS);
 
        VPRINTK("EDMA cfg=0x%08x EDMA IRQ err cause/mask=0x%08x/0x%08x\n",
                readl(port_mmio + EDMA_CFG_OFS),
@@ -2586,7 +2633,6 @@ static int mv_chip_id(struct ata_host *host, unsigned int board_idx)
 static int mv_init_host(struct ata_host *host, unsigned int board_idx)
 {
        int rc = 0, n_hc, port, hc;
-       struct pci_dev *pdev = to_pci_dev(host->dev);
        void __iomem *mmio = host->iomap[MV_PRIMARY_BAR];
        struct mv_host_priv *hpriv = host->private_data;
 
@@ -2607,7 +2653,7 @@ static int mv_init_host(struct ata_host *host, unsigned int board_idx)
                goto done;
 
        hpriv->ops->reset_flash(hpriv, mmio);
-       hpriv->ops->reset_bus(pdev, mmio);
+       hpriv->ops->reset_bus(host, mmio);
        hpriv->ops->enable_leds(hpriv, mmio);
 
        for (port = 0; port < host->n_ports; port++) {
@@ -2630,8 +2676,10 @@ static int mv_init_host(struct ata_host *host, unsigned int board_idx)
 
                mv_port_init(&ap->ioaddr, port_mmio);
 
+#ifdef CONFIG_PCI
                ata_port_pbar_desc(ap, MV_PRIMARY_BAR, -1, "mmio");
                ata_port_pbar_desc(ap, MV_PRIMARY_BAR, offset, "port");
+#endif
        }
 
        for (hc = 0; hc < n_hc; hc++) {
@@ -2668,6 +2716,55 @@ done:
        return rc;
 }
 
+#ifdef CONFIG_PCI
+static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
+
+static struct pci_driver mv_pci_driver = {
+       .name                   = DRV_NAME,
+       .id_table               = mv_pci_tbl,
+       .probe                  = mv_init_one,
+       .remove                 = ata_pci_remove_one,
+};
+
+/*
+ * module options
+ */
+static int msi;              /* Use PCI msi; either zero (off, default) or non-zero */
+
+
+/* move to PCI layer or libata core? */
+static int pci_go_64(struct pci_dev *pdev)
+{
+       int rc;
+
+       if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
+               rc = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
+               if (rc) {
+                       rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+                       if (rc) {
+                               dev_printk(KERN_ERR, &pdev->dev,
+                                          "64-bit DMA enable failed\n");
+                               return rc;
+                       }
+               }
+       } else {
+               rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+               if (rc) {
+                       dev_printk(KERN_ERR, &pdev->dev,
+                                  "32-bit DMA enable failed\n");
+                       return rc;
+               }
+               rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+               if (rc) {
+                       dev_printk(KERN_ERR, &pdev->dev,
+                                  "32-bit consistent DMA enable failed\n");
+                       return rc;
+               }
+       }
+
+       return rc;
+}
+
 /**
  *      mv_print_info - Dump key info to kernel log for perusal.
  *      @host: ATA host to print info about
@@ -2710,6 +2807,26 @@ static void mv_print_info(struct ata_host *host)
               scc_s, (MV_HP_FLAG_MSI & hpriv->hp_flags) ? "MSI" : "INTx");
 }
 
+static int mv_create_dma_pools(struct mv_host_priv *hpriv, struct device *dev)
+{
+       hpriv->crqb_pool   = dmam_pool_create("crqb_q", dev, MV_CRQB_Q_SZ,
+                                                            MV_CRQB_Q_SZ, 0);
+       if (!hpriv->crqb_pool)
+               return -ENOMEM;
+
+       hpriv->crpb_pool   = dmam_pool_create("crpb_q", dev, MV_CRPB_Q_SZ,
+                                                            MV_CRPB_Q_SZ, 0);
+       if (!hpriv->crpb_pool)
+               return -ENOMEM;
+
+       hpriv->sg_tbl_pool = dmam_pool_create("sg_tbl", dev, MV_SG_TBL_SZ,
+                                                            MV_SG_TBL_SZ, 0);
+       if (!hpriv->sg_tbl_pool)
+               return -ENOMEM;
+
+       return 0;
+}
+
 /**
  *      mv_init_one - handle a positive probe of a Marvell host
  *      @pdev: PCI device found
@@ -2755,6 +2872,10 @@ static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        if (rc)
                return rc;
 
+       rc = mv_create_dma_pools(hpriv, &pdev->dev);
+       if (rc)
+               return rc;
+
        /* initialize adapter */
        rc = mv_init_host(host, board_idx);
        if (rc)
@@ -2772,15 +2893,22 @@ static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        return ata_host_activate(host, pdev->irq, mv_interrupt, IRQF_SHARED,
                                 IS_GEN_I(hpriv) ? &mv5_sht : &mv6_sht);
 }
+#endif
 
 static int __init mv_init(void)
 {
-       return pci_register_driver(&mv_pci_driver);
+       int rc = -ENODEV;
+#ifdef CONFIG_PCI
+       rc = pci_register_driver(&mv_pci_driver);
+#endif
+       return rc;
 }
 
 static void __exit mv_exit(void)
 {
+#ifdef CONFIG_PCI
        pci_unregister_driver(&mv_pci_driver);
+#endif
 }
 
 MODULE_AUTHOR("Brett Russ");
@@ -2789,8 +2917,10 @@ MODULE_LICENSE("GPL");
 MODULE_DEVICE_TABLE(pci, mv_pci_tbl);
 MODULE_VERSION(DRV_VERSION);
 
+#ifdef CONFIG_PCI
 module_param(msi, int, 0444);
 MODULE_PARM_DESC(msi, "Enable use of PCI MSI (0=off, 1=on)");
+#endif
 
 module_init(mv_init);
 module_exit(mv_exit);
index a0f98fdab7a0c04da379acd19f72add501e69aa0..bfe92a43cf895d4169619298d6f18a037b828a5c 100644 (file)
@@ -1011,14 +1011,20 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance)
                        }
 
                        if (status & (NV_ADMA_STAT_DONE |
-                                     NV_ADMA_STAT_CPBERR)) {
-                               u32 check_commands;
+                                     NV_ADMA_STAT_CPBERR |
+                                     NV_ADMA_STAT_CMD_COMPLETE)) {
+                               u32 check_commands = notifier_clears[i];
                                int pos, error = 0;
 
-                               if (ata_tag_valid(ap->link.active_tag))
-                                       check_commands = 1 << ap->link.active_tag;
-                               else
-                                       check_commands = ap->link.sactive;
+                               if (status & NV_ADMA_STAT_CPBERR) {
+                                       /* Check all active commands */
+                                       if (ata_tag_valid(ap->link.active_tag))
+                                               check_commands = 1 <<
+                                                       ap->link.active_tag;
+                                       else
+                                               check_commands = ap->
+                                                       link.sactive;
+                               }
 
                                /** Check CPBs for completed commands */
                                while ((pos = ffs(check_commands)) && !error) {
index 63e09c015ca02305e6bb475d3ba8ca78c5677e63..c66637392bbc71756731941a50253240d0da3b9a 100644 (file)
@@ -5,7 +5,7 @@ obj-y                   := core.o sys.o bus.o dd.o \
                           cpu.o firmware.o init.o map.o devres.o \
                           attribute_container.o transport_class.o
 obj-y                  += power/
-obj-$(CONFIG_HAS_DMA)  += dma-mapping.o dmapool.o
+obj-$(CONFIG_HAS_DMA)  += dma-mapping.o
 obj-$(CONFIG_ISA)      += isa.o
 obj-$(CONFIG_FW_LOADER)        += firmware_class.o
 obj-$(CONFIG_NUMA)     += node.o
index b1727876182cdff178550856fc0696a770db9bdc..9c0070b5bd3e75d828a44d405dca4695b70e6ef6 100644 (file)
@@ -423,10 +423,8 @@ struct kset *devices_kset;
 int device_create_file(struct device *dev, struct device_attribute *attr)
 {
        int error = 0;
-       if (get_device(dev)) {
+       if (dev)
                error = sysfs_create_file(&dev->kobj, &attr->attr);
-               put_device(dev);
-       }
        return error;
 }
 
@@ -437,10 +435,8 @@ int device_create_file(struct device *dev, struct device_attribute *attr)
  */
 void device_remove_file(struct device *dev, struct device_attribute *attr)
 {
-       if (get_device(dev)) {
+       if (dev)
                sysfs_remove_file(&dev->kobj, &attr->attr);
-               put_device(dev);
-       }
 }
 
 /**
@@ -1144,25 +1140,11 @@ error:
 }
 EXPORT_SYMBOL_GPL(device_create);
 
-/**
- * find_device - finds a device that was created with device_create()
- * @class: pointer to the struct class that this device was registered with
- * @devt: the dev_t of the device that was previously registered
- */
-static struct device *find_device(struct class *class, dev_t devt)
+static int __match_devt(struct device *dev, void *data)
 {
-       struct device *dev = NULL;
-       struct device *dev_tmp;
+       dev_t *devt = data;
 
-       down(&class->sem);
-       list_for_each_entry(dev_tmp, &class->devices, node) {
-               if (dev_tmp->devt == devt) {
-                       dev = dev_tmp;
-                       break;
-               }
-       }
-       up(&class->sem);
-       return dev;
+       return dev->devt == *devt;
 }
 
 /**
@@ -1177,9 +1159,11 @@ void device_destroy(struct class *class, dev_t devt)
 {
        struct device *dev;
 
-       dev = find_device(class, devt);
-       if (dev)
+       dev = class_find_device(class, &devt, __match_devt);
+       if (dev) {
+               put_device(dev);
                device_unregister(dev);
+       }
 }
 EXPORT_SYMBOL_GPL(device_destroy);
 
@@ -1203,9 +1187,11 @@ void destroy_suspended_device(struct class *class, dev_t devt)
 {
        struct device *dev;
 
-       dev = find_device(class, devt);
-       if (dev)
+       dev = class_find_device(class, &devt, __match_devt);
+       if (dev) {
                device_pm_schedule_removal(dev);
+               put_device(dev);
+       }
 }
 EXPORT_SYMBOL_GPL(destroy_suspended_device);
 #endif /* CONFIG_PM_SLEEP */
diff --git a/drivers/base/dmapool.c b/drivers/base/dmapool.c
deleted file mode 100644 (file)
index b5034dc..0000000
+++ /dev/null
@@ -1,481 +0,0 @@
-
-#include <linux/device.h>
-#include <linux/mm.h>
-#include <asm/io.h>            /* Needed for i386 to build */
-#include <linux/dma-mapping.h>
-#include <linux/dmapool.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/poison.h>
-#include <linux/sched.h>
-
-/*
- * Pool allocator ... wraps the dma_alloc_coherent page allocator, so
- * small blocks are easily used by drivers for bus mastering controllers.
- * This should probably be sharing the guts of the slab allocator.
- */
-
-struct dma_pool {      /* the pool */
-       struct list_head        page_list;
-       spinlock_t              lock;
-       size_t                  blocks_per_page;
-       size_t                  size;
-       struct device           *dev;
-       size_t                  allocation;
-       char                    name [32];
-       wait_queue_head_t       waitq;
-       struct list_head        pools;
-};
-
-struct dma_page {      /* cacheable header for 'allocation' bytes */
-       struct list_head        page_list;
-       void                    *vaddr;
-       dma_addr_t              dma;
-       unsigned                in_use;
-       unsigned long           bitmap [0];
-};
-
-#define        POOL_TIMEOUT_JIFFIES    ((100 /* msec */ * HZ) / 1000)
-
-static DEFINE_MUTEX (pools_lock);
-
-static ssize_t
-show_pools (struct device *dev, struct device_attribute *attr, char *buf)
-{
-       unsigned temp;
-       unsigned size;
-       char *next;
-       struct dma_page *page;
-       struct dma_pool *pool;
-
-       next = buf;
-       size = PAGE_SIZE;
-
-       temp = scnprintf(next, size, "poolinfo - 0.1\n");
-       size -= temp;
-       next += temp;
-
-       mutex_lock(&pools_lock);
-       list_for_each_entry(pool, &dev->dma_pools, pools) {
-               unsigned pages = 0;
-               unsigned blocks = 0;
-
-               list_for_each_entry(page, &pool->page_list, page_list) {
-                       pages++;
-                       blocks += page->in_use;
-               }
-
-               /* per-pool info, no real statistics yet */
-               temp = scnprintf(next, size, "%-16s %4u %4Zu %4Zu %2u\n",
-                               pool->name,
-                               blocks, pages * pool->blocks_per_page,
-                               pool->size, pages);
-               size -= temp;
-               next += temp;
-       }
-       mutex_unlock(&pools_lock);
-
-       return PAGE_SIZE - size;
-}
-static DEVICE_ATTR (pools, S_IRUGO, show_pools, NULL);
-
-/**
- * dma_pool_create - Creates a pool of consistent memory blocks, for dma.
- * @name: name of pool, for diagnostics
- * @dev: device that will be doing the DMA
- * @size: size of the blocks in this pool.
- * @align: alignment requirement for blocks; must be a power of two
- * @allocation: returned blocks won't cross this boundary (or zero)
- * Context: !in_interrupt()
- *
- * Returns a dma allocation pool with the requested characteristics, or
- * null if one can't be created.  Given one of these pools, dma_pool_alloc()
- * may be used to allocate memory.  Such memory will all have "consistent"
- * DMA mappings, accessible by the device and its driver without using
- * cache flushing primitives.  The actual size of blocks allocated may be
- * larger than requested because of alignment.
- *
- * If allocation is nonzero, objects returned from dma_pool_alloc() won't
- * cross that size boundary.  This is useful for devices which have
- * addressing restrictions on individual DMA transfers, such as not crossing
- * boundaries of 4KBytes.
- */
-struct dma_pool *
-dma_pool_create (const char *name, struct device *dev,
-       size_t size, size_t align, size_t allocation)
-{
-       struct dma_pool         *retval;
-
-       if (align == 0)
-               align = 1;
-       if (size == 0)
-               return NULL;
-       else if (size < align)
-               size = align;
-       else if ((size % align) != 0) {
-               size += align + 1;
-               size &= ~(align - 1);
-       }
-
-       if (allocation == 0) {
-               if (PAGE_SIZE < size)
-                       allocation = size;
-               else
-                       allocation = PAGE_SIZE;
-               // FIXME: round up for less fragmentation
-       } else if (allocation < size)
-               return NULL;
-
-       if (!(retval = kmalloc_node (sizeof *retval, GFP_KERNEL, dev_to_node(dev))))
-               return retval;
-
-       strlcpy (retval->name, name, sizeof retval->name);
-
-       retval->dev = dev;
-
-       INIT_LIST_HEAD (&retval->page_list);
-       spin_lock_init (&retval->lock);
-       retval->size = size;
-       retval->allocation = allocation;
-       retval->blocks_per_page = allocation / size;
-       init_waitqueue_head (&retval->waitq);
-
-       if (dev) {
-               int ret;
-
-               mutex_lock(&pools_lock);
-               if (list_empty (&dev->dma_pools))
-                       ret = device_create_file (dev, &dev_attr_pools);
-               else
-                       ret = 0;
-               /* note:  not currently insisting "name" be unique */
-               if (!ret)
-                       list_add (&retval->pools, &dev->dma_pools);
-               else {
-                       kfree(retval);
-                       retval = NULL;
-               }
-               mutex_unlock(&pools_lock);
-       } else
-               INIT_LIST_HEAD (&retval->pools);
-
-       return retval;
-}
-
-
-static struct dma_page *
-pool_alloc_page (struct dma_pool *pool, gfp_t mem_flags)
-{
-       struct dma_page *page;
-       int             mapsize;
-
-       mapsize = pool->blocks_per_page;
-       mapsize = (mapsize + BITS_PER_LONG - 1) / BITS_PER_LONG;
-       mapsize *= sizeof (long);
-
-       page = kmalloc(mapsize + sizeof *page, mem_flags);
-       if (!page)
-               return NULL;
-       page->vaddr = dma_alloc_coherent (pool->dev,
-                                           pool->allocation,
-                                           &page->dma,
-                                           mem_flags);
-       if (page->vaddr) {
-               memset (page->bitmap, 0xff, mapsize);   // bit set == free
-#ifdef CONFIG_DEBUG_SLAB
-               memset (page->vaddr, POOL_POISON_FREED, pool->allocation);
-#endif
-               list_add (&page->page_list, &pool->page_list);
-               page->in_use = 0;
-       } else {
-               kfree (page);
-               page = NULL;
-       }
-       return page;
-}
-
-
-static inline int
-is_page_busy (int blocks, unsigned long *bitmap)
-{
-       while (blocks > 0) {
-               if (*bitmap++ != ~0UL)
-                       return 1;
-               blocks -= BITS_PER_LONG;
-       }
-       return 0;
-}
-
-static void
-pool_free_page (struct dma_pool *pool, struct dma_page *page)
-{
-       dma_addr_t      dma = page->dma;
-
-#ifdef CONFIG_DEBUG_SLAB
-       memset (page->vaddr, POOL_POISON_FREED, pool->allocation);
-#endif
-       dma_free_coherent (pool->dev, pool->allocation, page->vaddr, dma);
-       list_del (&page->page_list);
-       kfree (page);
-}
-
-
-/**
- * dma_pool_destroy - destroys a pool of dma memory blocks.
- * @pool: dma pool that will be destroyed
- * Context: !in_interrupt()
- *
- * Caller guarantees that no more memory from the pool is in use,
- * and that nothing will try to use the pool after this call.
- */
-void
-dma_pool_destroy (struct dma_pool *pool)
-{
-       mutex_lock(&pools_lock);
-       list_del (&pool->pools);
-       if (pool->dev && list_empty (&pool->dev->dma_pools))
-               device_remove_file (pool->dev, &dev_attr_pools);
-       mutex_unlock(&pools_lock);
-
-       while (!list_empty (&pool->page_list)) {
-               struct dma_page         *page;
-               page = list_entry (pool->page_list.next,
-                               struct dma_page, page_list);
-               if (is_page_busy (pool->blocks_per_page, page->bitmap)) {
-                       if (pool->dev)
-                               dev_err(pool->dev, "dma_pool_destroy %s, %p busy\n",
-                                       pool->name, page->vaddr);
-                       else
-                               printk (KERN_ERR "dma_pool_destroy %s, %p busy\n",
-                                       pool->name, page->vaddr);
-                       /* leak the still-in-use consistent memory */
-                       list_del (&page->page_list);
-                       kfree (page);
-               } else
-                       pool_free_page (pool, page);
-       }
-
-       kfree (pool);
-}
-
-
-/**
- * dma_pool_alloc - get a block of consistent memory
- * @pool: dma pool that will produce the block
- * @mem_flags: GFP_* bitmask
- * @handle: pointer to dma address of block
- *
- * This returns the kernel virtual address of a currently unused block,
- * and reports its dma address through the handle.
- * If such a memory block can't be allocated, null is returned.
- */
-void *
-dma_pool_alloc (struct dma_pool *pool, gfp_t mem_flags, dma_addr_t *handle)
-{
-       unsigned long           flags;
-       struct dma_page         *page;
-       int                     map, block;
-       size_t                  offset;
-       void                    *retval;
-
-restart:
-       spin_lock_irqsave (&pool->lock, flags);
-       list_for_each_entry(page, &pool->page_list, page_list) {
-               int             i;
-               /* only cachable accesses here ... */
-               for (map = 0, i = 0;
-                               i < pool->blocks_per_page;
-                               i += BITS_PER_LONG, map++) {
-                       if (page->bitmap [map] == 0)
-                               continue;
-                       block = ffz (~ page->bitmap [map]);
-                       if ((i + block) < pool->blocks_per_page) {
-                               clear_bit (block, &page->bitmap [map]);
-                               offset = (BITS_PER_LONG * map) + block;
-                               offset *= pool->size;
-                               goto ready;
-                       }
-               }
-       }
-       if (!(page = pool_alloc_page (pool, GFP_ATOMIC))) {
-               if (mem_flags & __GFP_WAIT) {
-                       DECLARE_WAITQUEUE (wait, current);
-
-                       __set_current_state(TASK_INTERRUPTIBLE);
-                       add_wait_queue (&pool->waitq, &wait);
-                       spin_unlock_irqrestore (&pool->lock, flags);
-
-                       schedule_timeout (POOL_TIMEOUT_JIFFIES);
-
-                       remove_wait_queue (&pool->waitq, &wait);
-                       goto restart;
-               }
-               retval = NULL;
-               goto done;
-       }
-
-       clear_bit (0, &page->bitmap [0]);
-       offset = 0;
-ready:
-       page->in_use++;
-       retval = offset + page->vaddr;
-       *handle = offset + page->dma;
-#ifdef CONFIG_DEBUG_SLAB
-       memset (retval, POOL_POISON_ALLOCATED, pool->size);
-#endif
-done:
-       spin_unlock_irqrestore (&pool->lock, flags);
-       return retval;
-}
-
-
-static struct dma_page *
-pool_find_page (struct dma_pool *pool, dma_addr_t dma)
-{
-       unsigned long           flags;
-       struct dma_page         *page;
-
-       spin_lock_irqsave (&pool->lock, flags);
-       list_for_each_entry(page, &pool->page_list, page_list) {
-               if (dma < page->dma)
-                       continue;
-               if (dma < (page->dma + pool->allocation))
-                       goto done;
-       }
-       page = NULL;
-done:
-       spin_unlock_irqrestore (&pool->lock, flags);
-       return page;
-}
-
-
-/**
- * dma_pool_free - put block back into dma pool
- * @pool: the dma pool holding the block
- * @vaddr: virtual address of block
- * @dma: dma address of block
- *
- * Caller promises neither device nor driver will again touch this block
- * unless it is first re-allocated.
- */
-void
-dma_pool_free (struct dma_pool *pool, void *vaddr, dma_addr_t dma)
-{
-       struct dma_page         *page;
-       unsigned long           flags;
-       int                     map, block;
-
-       if ((page = pool_find_page(pool, dma)) == NULL) {
-               if (pool->dev)
-                       dev_err(pool->dev, "dma_pool_free %s, %p/%lx (bad dma)\n",
-                               pool->name, vaddr, (unsigned long) dma);
-               else
-                       printk (KERN_ERR "dma_pool_free %s, %p/%lx (bad dma)\n",
-                               pool->name, vaddr, (unsigned long) dma);
-               return;
-       }
-
-       block = dma - page->dma;
-       block /= pool->size;
-       map = block / BITS_PER_LONG;
-       block %= BITS_PER_LONG;
-
-#ifdef CONFIG_DEBUG_SLAB
-       if (((dma - page->dma) + (void *)page->vaddr) != vaddr) {
-               if (pool->dev)
-                       dev_err(pool->dev, "dma_pool_free %s, %p (bad vaddr)/%Lx\n",
-                               pool->name, vaddr, (unsigned long long) dma);
-               else
-                       printk (KERN_ERR "dma_pool_free %s, %p (bad vaddr)/%Lx\n",
-                               pool->name, vaddr, (unsigned long long) dma);
-               return;
-       }
-       if (page->bitmap [map] & (1UL << block)) {
-               if (pool->dev)
-                       dev_err(pool->dev, "dma_pool_free %s, dma %Lx already free\n",
-                               pool->name, (unsigned long long)dma);
-               else
-                       printk (KERN_ERR "dma_pool_free %s, dma %Lx already free\n",
-                               pool->name, (unsigned long long)dma);
-               return;
-       }
-       memset (vaddr, POOL_POISON_FREED, pool->size);
-#endif
-
-       spin_lock_irqsave (&pool->lock, flags);
-       page->in_use--;
-       set_bit (block, &page->bitmap [map]);
-       if (waitqueue_active (&pool->waitq))
-               wake_up (&pool->waitq);
-       /*
-        * Resist a temptation to do
-        *    if (!is_page_busy(bpp, page->bitmap)) pool_free_page(pool, page);
-        * Better have a few empty pages hang around.
-        */
-       spin_unlock_irqrestore (&pool->lock, flags);
-}
-
-/*
- * Managed DMA pool
- */
-static void dmam_pool_release(struct device *dev, void *res)
-{
-       struct dma_pool *pool = *(struct dma_pool **)res;
-
-       dma_pool_destroy(pool);
-}
-
-static int dmam_pool_match(struct device *dev, void *res, void *match_data)
-{
-       return *(struct dma_pool **)res == match_data;
-}
-
-/**
- * dmam_pool_create - Managed dma_pool_create()
- * @name: name of pool, for diagnostics
- * @dev: device that will be doing the DMA
- * @size: size of the blocks in this pool.
- * @align: alignment requirement for blocks; must be a power of two
- * @allocation: returned blocks won't cross this boundary (or zero)
- *
- * Managed dma_pool_create().  DMA pool created with this function is
- * automatically destroyed on driver detach.
- */
-struct dma_pool *dmam_pool_create(const char *name, struct device *dev,
-                                 size_t size, size_t align, size_t allocation)
-{
-       struct dma_pool **ptr, *pool;
-
-       ptr = devres_alloc(dmam_pool_release, sizeof(*ptr), GFP_KERNEL);
-       if (!ptr)
-               return NULL;
-
-       pool = *ptr = dma_pool_create(name, dev, size, align, allocation);
-       if (pool)
-               devres_add(dev, ptr);
-       else
-               devres_free(ptr);
-
-       return pool;
-}
-
-/**
- * dmam_pool_destroy - Managed dma_pool_destroy()
- * @pool: dma pool that will be destroyed
- *
- * Managed dma_pool_destroy().
- */
-void dmam_pool_destroy(struct dma_pool *pool)
-{
-       struct device *dev = pool->dev;
-
-       dma_pool_destroy(pool);
-       WARN_ON(devres_destroy(dev, dmam_pool_release, dmam_pool_match, pool));
-}
-
-EXPORT_SYMBOL (dma_pool_create);
-EXPORT_SYMBOL (dma_pool_destroy);
-EXPORT_SYMBOL (dma_pool_alloc);
-EXPORT_SYMBOL (dma_pool_free);
-EXPORT_SYMBOL (dmam_pool_create);
-EXPORT_SYMBOL (dmam_pool_destroy);
index a35f04121a00f938503f3b585c4e792e8a578d8f..ba75184c653c32794e3ac60283369a1bd39ea461 100644 (file)
@@ -97,10 +97,9 @@ int driver_create_file(struct device_driver *drv,
                       struct driver_attribute *attr)
 {
        int error;
-       if (get_driver(drv)) {
+       if (drv)
                error = sysfs_create_file(&drv->p->kobj, &attr->attr);
-               put_driver(drv);
-       } else
+       else
                error = -EINVAL;
        return error;
 }
@@ -114,10 +113,8 @@ EXPORT_SYMBOL_GPL(driver_create_file);
 void driver_remove_file(struct device_driver *drv,
                        struct driver_attribute *attr)
 {
-       if (get_driver(drv)) {
+       if (drv)
                sysfs_remove_file(&drv->p->kobj, &attr->attr);
-               put_driver(drv);
-       }
 }
 EXPORT_SYMBOL_GPL(driver_remove_file);
 
index de28dfd3b96c6ff4db97ed85320f017a8542e799..911208b892593965857211727a51b028cbd4b10f 100644 (file)
@@ -1,6 +1,6 @@
 obj-$(CONFIG_PM)       += sysfs.o
 obj-$(CONFIG_PM_SLEEP) += main.o
-obj-$(CONFIG_PM_TRACE) += trace.o
+obj-$(CONFIG_PM_TRACE_RTC)     += trace.o
 
 ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG
 ccflags-$(CONFIG_PM_VERBOSE)   += -DDEBUG
index 200ed5fafd505ad0e18fff1131500e2a2fd4ba9c..bdc03f7e8424ceda39d454413a76d637a9215418 100644 (file)
@@ -129,6 +129,7 @@ void device_pm_schedule_removal(struct device *dev)
        list_move_tail(&dev->power.entry, &dpm_destroy);
        mutex_unlock(&dpm_list_mtx);
 }
+EXPORT_SYMBOL_GPL(device_pm_schedule_removal);
 
 /**
  *     pm_sleep_lock - mutual exclusion for registration and suspend
index 6f0dfca8ebdd2437da619ab7a0c89abd7a60dcca..e32d3bdb92c1dbf45d02c161130fcafbdd0044d9 100644 (file)
@@ -13,7 +13,6 @@ static inline struct device *to_device(struct list_head *entry)
 
 extern void device_pm_add(struct device *);
 extern void device_pm_remove(struct device *);
-extern void device_pm_schedule_removal(struct device *);
 extern int pm_sleep_lock(void);
 extern void pm_sleep_unlock(void);
 
index f2122855d4ec5d714ae0260708aa66562af17db1..64e5148d82bc8cce2018012f6bf5587570ba2267 100644 (file)
@@ -440,6 +440,7 @@ config VIRTIO_BLK
        tristate "Virtio block driver (EXPERIMENTAL)"
        depends on EXPERIMENTAL && VIRTIO
        ---help---
-         This is the virtual block driver for lguest.  Say Y or M.
+         This is the virtual block driver for virtio.  It can be used with
+          lguest or QEMU based VMMs (like KVM or Xen).  Say Y or M.
 
 endif # BLK_DEV
index 63ee6c076cb3ec61771c05b2743998a9a4da1b49..55178e9973a094fe08fd23bf040c237e58695a02 100644 (file)
@@ -1453,7 +1453,7 @@ static int cciss_eh_device_reset_handler(struct scsi_cmnd *scsicmd)
        rc = sendcmd(CCISS_RESET_MSG, ctlr, NULL, 0, 2, 0, 0, 
                (unsigned char *) &cmd_in_trouble->Header.LUN.LunAddrBytes[0], 
                TYPE_MSG);
-       /* sendcmd turned off interrputs on the board, turn 'em back on. */
+       /* sendcmd turned off interrupts on the board, turn 'em back on. */
        (*c)->access.set_intr_mask(*c, CCISS_INTR_ON);
        if (rc == 0)
                return SUCCESS;
@@ -1483,7 +1483,7 @@ static int  cciss_eh_abort_handler(struct scsi_cmnd *scsicmd)
                0, 2, 0, 0, 
                (unsigned char *) &cmd_to_abort->Header.LUN.LunAddrBytes[0], 
                TYPE_MSG);
-       /* sendcmd turned off interrputs on the board, turn 'em back on. */
+       /* sendcmd turned off interrupts on the board, turn 'em back on. */
        (*c)->access.set_intr_mask(*c, CCISS_INTR_ON);
        if (rc == 0)
                return SUCCESS;
index 66e30155b0abe03d504fd6753579409324f326ae..a8de037ecd4ac7b5ab3e56f48f6f15400b196463 100644 (file)
@@ -732,7 +732,7 @@ static struct vio_driver_ops vdc_vio_ops = {
        .handshake_complete     = vdc_handshake_complete,
 };
 
-static void print_version(void)
+static void __devinit print_version(void)
 {
        static int version_printed;
 
index c6179d6ac6e430764b5c22e67f2b4130191ef599..a70c1c29a7aa2c28e99c9fa352fa6f42b2048d17 100644 (file)
@@ -922,11 +922,6 @@ static int ub_scsi_cmd_start(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
        usb_fill_bulk_urb(&sc->work_urb, sc->dev, sc->send_bulk_pipe,
            bcb, US_BULK_CB_WRAP_LEN, ub_urb_complete, sc);
 
-       /* Fill what we shouldn't be filling, because usb-storage did so. */
-       sc->work_urb.actual_length = 0;
-       sc->work_urb.error_count = 0;
-       sc->work_urb.status = 0;
-
        if ((rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC)) != 0) {
                /* XXX Clear stalls */
                ub_complete(&sc->work_done);
@@ -1313,9 +1308,6 @@ static void ub_data_start(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
        sc->last_pipe = pipe;
        usb_fill_bulk_urb(&sc->work_urb, sc->dev, pipe, sg_virt(sg),
            sg->length, ub_urb_complete, sc);
-       sc->work_urb.actual_length = 0;
-       sc->work_urb.error_count = 0;
-       sc->work_urb.status = 0;
 
        if ((rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC)) != 0) {
                /* XXX Clear stalls */
@@ -1356,9 +1348,6 @@ static int __ub_state_stat(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
        sc->last_pipe = sc->recv_bulk_pipe;
        usb_fill_bulk_urb(&sc->work_urb, sc->dev, sc->recv_bulk_pipe,
            &sc->work_bcs, US_BULK_CS_WRAP_LEN, ub_urb_complete, sc);
-       sc->work_urb.actual_length = 0;
-       sc->work_urb.error_count = 0;
-       sc->work_urb.status = 0;
 
        if ((rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC)) != 0) {
                /* XXX Clear stalls */
@@ -1473,9 +1462,6 @@ static int ub_submit_clear_stall(struct ub_dev *sc, struct ub_scsi_cmd *cmd,
 
        usb_fill_control_urb(&sc->work_urb, sc->dev, sc->send_ctrl_pipe,
            (unsigned char*) cr, NULL, 0, ub_urb_complete, sc);
-       sc->work_urb.actual_length = 0;
-       sc->work_urb.error_count = 0;
-       sc->work_urb.status = 0;
 
        if ((rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC)) != 0) {
                ub_complete(&sc->work_done);
@@ -1953,9 +1939,6 @@ static int ub_sync_reset(struct ub_dev *sc)
 
        usb_fill_control_urb(&sc->work_urb, sc->dev, sc->send_ctrl_pipe,
            (unsigned char*) cr, NULL, 0, ub_probe_urb_complete, &compl);
-       sc->work_urb.actual_length = 0;
-       sc->work_urb.error_count = 0;
-       sc->work_urb.status = 0;
 
        if ((rc = usb_submit_urb(&sc->work_urb, GFP_KERNEL)) != 0) {
                printk(KERN_WARNING
@@ -2007,9 +1990,6 @@ static int ub_sync_getmaxlun(struct ub_dev *sc)
 
        usb_fill_control_urb(&sc->work_urb, sc->dev, sc->recv_ctrl_pipe,
            (unsigned char*) cr, p, 1, ub_probe_urb_complete, &compl);
-       sc->work_urb.actual_length = 0;
-       sc->work_urb.error_count = 0;
-       sc->work_urb.status = 0;
 
        if ((rc = usb_submit_urb(&sc->work_urb, GFP_KERNEL)) != 0)
                goto err_submit;
@@ -2077,9 +2057,6 @@ static int ub_probe_clear_stall(struct ub_dev *sc, int stalled_pipe)
 
        usb_fill_control_urb(&sc->work_urb, sc->dev, sc->send_ctrl_pipe,
            (unsigned char*) cr, NULL, 0, ub_probe_urb_complete, &compl);
-       sc->work_urb.actual_length = 0;
-       sc->work_urb.error_count = 0;
-       sc->work_urb.status = 0;
 
        if ((rc = usb_submit_urb(&sc->work_urb, GFP_KERNEL)) != 0) {
                printk(KERN_WARNING
index 924ddd8bccd2b8fdd32e06a7db1c3e05918ebc12..3b1a68d6eddb3c0860794c778a643340b59ec920 100644 (file)
@@ -7,8 +7,10 @@
 #include <linux/scatterlist.h>
 
 #define VIRTIO_MAX_SG  (3+MAX_PHYS_SEGMENTS)
+#define PART_BITS 4
+
+static int major, index;
 
-static unsigned char virtblk_index = 'a';
 struct virtio_blk
 {
        spinlock_t lock;
@@ -36,7 +38,7 @@ struct virtblk_req
        struct virtio_blk_inhdr in_hdr;
 };
 
-static bool blk_done(struct virtqueue *vq)
+static void blk_done(struct virtqueue *vq)
 {
        struct virtio_blk *vblk = vq->vdev->priv;
        struct virtblk_req *vbr;
@@ -65,7 +67,6 @@ static bool blk_done(struct virtqueue *vq)
        /* In case queue is stopped waiting for more buffers. */
        blk_start_queue(vblk->disk->queue);
        spin_unlock_irqrestore(&vblk->lock, flags);
-       return true;
 }
 
 static bool do_req(struct request_queue *q, struct virtio_blk *vblk,
@@ -153,20 +154,37 @@ static int virtblk_ioctl(struct inode *inode, struct file *filp,
                              (void __user *)data);
 }
 
+/* We provide getgeo only to please some old bootloader/partitioning tools */
+static int virtblk_getgeo(struct block_device *bd, struct hd_geometry *geo)
+{
+       /* some standard values, similar to sd */
+       geo->heads = 1 << 6;
+       geo->sectors = 1 << 5;
+       geo->cylinders = get_capacity(bd->bd_disk) >> 11;
+       return 0;
+}
+
 static struct block_device_operations virtblk_fops = {
-       .ioctl = virtblk_ioctl,
-       .owner = THIS_MODULE,
+       .ioctl  = virtblk_ioctl,
+       .owner  = THIS_MODULE,
+       .getgeo = virtblk_getgeo,
 };
 
+static int index_to_minor(int index)
+{
+       return index << PART_BITS;
+}
+
 static int virtblk_probe(struct virtio_device *vdev)
 {
        struct virtio_blk *vblk;
-       int err, major;
-       void *token;
-       unsigned int len;
+       int err;
        u64 cap;
        u32 v;
 
+       if (index_to_minor(index) >= 1 << MINORBITS)
+               return -ENOSPC;
+
        vdev->priv = vblk = kmalloc(sizeof(*vblk), GFP_KERNEL);
        if (!vblk) {
                err = -ENOMEM;
@@ -178,7 +196,7 @@ static int virtblk_probe(struct virtio_device *vdev)
        vblk->vdev = vdev;
 
        /* We expect one virtqueue, for output. */
-       vblk->vq = vdev->config->find_vq(vdev, blk_done);
+       vblk->vq = vdev->config->find_vq(vdev, 0, blk_done);
        if (IS_ERR(vblk->vq)) {
                err = PTR_ERR(vblk->vq);
                goto out_free_vblk;
@@ -190,17 +208,11 @@ static int virtblk_probe(struct virtio_device *vdev)
                goto out_free_vq;
        }
 
-       major = register_blkdev(0, "virtblk");
-       if (major < 0) {
-               err = major;
-               goto out_mempool;
-       }
-
        /* FIXME: How many partitions?  How long is a piece of string? */
-       vblk->disk = alloc_disk(1 << 4);
+       vblk->disk = alloc_disk(1 << PART_BITS);
        if (!vblk->disk) {
                err = -ENOMEM;
-               goto out_unregister_blkdev;
+               goto out_mempool;
        }
 
        vblk->disk->queue = blk_init_queue(do_virtblk_request, &vblk->lock);
@@ -209,22 +221,32 @@ static int virtblk_probe(struct virtio_device *vdev)
                goto out_put_disk;
        }
 
-       sprintf(vblk->disk->disk_name, "vd%c", virtblk_index++);
+       if (index < 26) {
+               sprintf(vblk->disk->disk_name, "vd%c", 'a' + index % 26);
+       } else if (index < (26 + 1) * 26) {
+               sprintf(vblk->disk->disk_name, "vd%c%c",
+                       'a' + index / 26 - 1, 'a' + index % 26);
+       } else {
+               const unsigned int m1 = (index / 26 - 1) / 26 - 1;
+               const unsigned int m2 = (index / 26 - 1) % 26;
+               const unsigned int m3 =  index % 26;
+               sprintf(vblk->disk->disk_name, "vd%c%c%c",
+                       'a' + m1, 'a' + m2, 'a' + m3);
+       }
+
        vblk->disk->major = major;
-       vblk->disk->first_minor = 0;
+       vblk->disk->first_minor = index_to_minor(index);
        vblk->disk->private_data = vblk;
        vblk->disk->fops = &virtblk_fops;
+       index++;
 
        /* If barriers are supported, tell block layer that queue is ordered */
-       token = vdev->config->find(vdev, VIRTIO_CONFIG_BLK_F, &len);
-       if (virtio_use_bit(vdev, token, len, VIRTIO_BLK_F_BARRIER))
+       if (vdev->config->feature(vdev, VIRTIO_BLK_F_BARRIER))
                blk_queue_ordered(vblk->disk->queue, QUEUE_ORDERED_TAG, NULL);
 
-       err = virtio_config_val(vdev, VIRTIO_CONFIG_BLK_F_CAPACITY, &cap);
-       if (err) {
-               dev_err(&vdev->dev, "Bad/missing capacity in config\n");
-               goto out_cleanup_queue;
-       }
+       /* Host must always specify the capacity. */
+       __virtio_config_val(vdev, offsetof(struct virtio_blk_config, capacity),
+                           &cap);
 
        /* If capacity is too big, truncate with warning. */
        if ((sector_t)cap != cap) {
@@ -234,31 +256,25 @@ static int virtblk_probe(struct virtio_device *vdev)
        }
        set_capacity(vblk->disk, cap);
 
-       err = virtio_config_val(vdev, VIRTIO_CONFIG_BLK_F_SIZE_MAX, &v);
+       /* Host can optionally specify maximum segment size and number of
+        * segments. */
+       err = virtio_config_val(vdev, VIRTIO_BLK_F_SIZE_MAX,
+                               offsetof(struct virtio_blk_config, size_max),
+                               &v);
        if (!err)
                blk_queue_max_segment_size(vblk->disk->queue, v);
-       else if (err != -ENOENT) {
-               dev_err(&vdev->dev, "Bad SIZE_MAX in config\n");
-               goto out_cleanup_queue;
-       }
 
-       err = virtio_config_val(vdev, VIRTIO_CONFIG_BLK_F_SEG_MAX, &v);
+       err = virtio_config_val(vdev, VIRTIO_BLK_F_SEG_MAX,
+                               offsetof(struct virtio_blk_config, seg_max),
+                               &v);
        if (!err)
                blk_queue_max_hw_segments(vblk->disk->queue, v);
-       else if (err != -ENOENT) {
-               dev_err(&vdev->dev, "Bad SEG_MAX in config\n");
-               goto out_cleanup_queue;
-       }
 
        add_disk(vblk->disk);
        return 0;
 
-out_cleanup_queue:
-       blk_cleanup_queue(vblk->disk->queue);
 out_put_disk:
        put_disk(vblk->disk);
-out_unregister_blkdev:
-       unregister_blkdev(major, "virtblk");
 out_mempool:
        mempool_destroy(vblk->pool);
 out_free_vq:
@@ -274,12 +290,16 @@ static void virtblk_remove(struct virtio_device *vdev)
        struct virtio_blk *vblk = vdev->priv;
        int major = vblk->disk->major;
 
+       /* Nothing should be pending. */
        BUG_ON(!list_empty(&vblk->reqs));
+
+       /* Stop all the virtqueues. */
+       vdev->config->reset(vdev);
+
        blk_cleanup_queue(vblk->disk->queue);
        put_disk(vblk->disk);
        unregister_blkdev(major, "virtblk");
        mempool_destroy(vblk->pool);
-       /* There should be nothing in the queue now, so no need to shutdown */
        vdev->config->del_vq(vblk->vq);
        kfree(vblk);
 }
@@ -299,11 +319,15 @@ static struct virtio_driver virtio_blk = {
 
 static int __init init(void)
 {
+       major = register_blkdev(0, "virtblk");
+       if (major < 0)
+               return major;
        return register_virtio_driver(&virtio_blk);
 }
 
 static void __exit fini(void)
 {
+       unregister_blkdev(major, "virtblk");
        unregister_virtio_driver(&virtio_blk);
 }
 module_init(init);
index 1375b5345a0a1466045204b80a2804672b6c4756..3b28658f5a1ff1b748bb450d3272388c71783fca 100644 (file)
@@ -423,6 +423,7 @@ static int bpa10x_send_frame(struct sk_buff *skb)
                break;
 
        default:
+               usb_free_urb(urb);
                return -EILSEQ;
        }
 
index a18f9b8c9e128c33e8c3942ce55d3b7197d22ecb..7703d6e06fd988926dd2e697e32c4a57eee37158 100644 (file)
@@ -704,7 +704,7 @@ static int next_tuple(struct pcmcia_device *handle, tuple_t *tuple, cisparse_t *
 
 static int bt3c_config(struct pcmcia_device *link)
 {
-       static kio_addr_t base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 };
+       static unsigned int base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 };
        bt3c_info_t *info = link->priv;
        tuple_t tuple;
        u_short buf[256];
index b786f618790210857f429bea9d21eb83266c1499..58630cc1eff2f1047ed0049edcbb9c4e578d511f 100644 (file)
@@ -162,10 +162,8 @@ static int btsdio_rx_packet(struct btsdio_data *data)
        bt_cb(skb)->pkt_type = hdr[3];
 
        err = hci_recv_frame(skb);
-       if (err < 0) {
-               kfree(skb);
+       if (err < 0)
                return err;
-       }
 
        sdio_writeb(data->func, 0x00, REG_PC_RRT, NULL);
 
index 08f48d577ababf1b38bb0cf4693a311922392a8e..68d1d258e6a4f5f4e8064a061d374ef1b632dca3 100644 (file)
@@ -383,7 +383,7 @@ static void btuart_change_speed(btuart_info_t *info, unsigned int speed)
        outb(lcr, iobase + UART_LCR);   /* Set 8N1  */
        outb(fcr, iobase + UART_FCR);   /* Enable FIFO's */
 
-       /* Turn on interrups */
+       /* Turn on interrupts */
        outb(UART_IER_RLSI | UART_IER_RDI | UART_IER_THRI, iobase + UART_IER);
 
        spin_unlock_irqrestore(&(info->lock), flags);
@@ -634,7 +634,7 @@ static int next_tuple(struct pcmcia_device *handle, tuple_t *tuple, cisparse_t *
 
 static int btuart_config(struct pcmcia_device *link)
 {
-       static kio_addr_t base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 };
+       static unsigned int base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 };
        btuart_info_t *info = link->priv;
        tuple_t tuple;
        u_short buf[256];
index 98a9cdeaffb67a8c9a435ec57ae78fa880200176..372c7ef633dab53471c5d3e0dda7ac4dc49fdeff 100644 (file)
@@ -111,6 +111,7 @@ static struct usb_device_id blacklist_ids[] = {
        { USB_DEVICE(0x0a5c, 0x2033), .driver_info = HCI_IGNORE },
 
        /* Broadcom BCM2035 */
+       { USB_DEVICE(0x0a5c, 0x2035), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU },
        { USB_DEVICE(0x0a5c, 0x200a), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU },
        { USB_DEVICE(0x0a5c, 0x2009), .driver_info = HCI_BCM92035 },
 
index af0561053167cd177d89c499c3d9f2b108843d46..47e5b40510cb4655cb031ce7470a81c5b7ebf85e 100644 (file)
@@ -2787,12 +2787,6 @@ int cdrom_ioctl(struct file * file, struct cdrom_device_info *cdi,
        return -ENOSYS;
 }
 
-static inline
-int msf_to_lba(char m, char s, char f)
-{
-       return (((m * CD_SECS) + s) * CD_FRAMES + f) - CD_MSF_OFFSET;
-}
-
 /*
  * Required when we need to use READ_10 to issue other than 2048 block
  * reads
index 8473b9f1da96168df571768b41889bf982c7e6a0..cac06bc1754b327f7e88605c4f1ed838d8187966 100644 (file)
@@ -558,7 +558,7 @@ static struct cdrom_device_ops viocd_dops = {
        .capability = CDC_CLOSE_TRAY | CDC_OPEN_TRAY | CDC_LOCK | CDC_SELECT_SPEED | CDC_SELECT_DISC | CDC_MULTI_SESSION | CDC_MCN | CDC_MEDIA_CHANGED | CDC_PLAY_AUDIO | CDC_RESET | CDC_DRIVE_STATUS | CDC_GENERIC_PACKET | CDC_CD_R | CDC_CD_RW | CDC_DVD | CDC_DVD_R | CDC_DVD_RAM | CDC_RAM
 };
 
-static int __init find_capability(const char *type)
+static int find_capability(const char *type)
 {
        struct capability_entry *entry;
 
index b83824c41329f3d4f4459de76b981c67ec946ba5..c69f79598e47cb4c9e375bc648daaa0e28e26646 100644 (file)
@@ -117,7 +117,8 @@ struct agp_bridge_driver {
        void (*free_by_type)(struct agp_memory *);
        void *(*agp_alloc_page)(struct agp_bridge_data *);
        void (*agp_destroy_page)(void *, int flags);
-        int (*agp_type_to_mask_type) (struct agp_bridge_data *, int);
+       int (*agp_type_to_mask_type) (struct agp_bridge_data *, int);
+       void (*chipset_flush)(struct agp_bridge_data *);
 };
 
 struct agp_bridge_data {
@@ -235,6 +236,9 @@ struct agp_bridge_data {
 #define I965_PGETBL_SIZE_512KB (0 << 1)
 #define I965_PGETBL_SIZE_256KB (1 << 1)
 #define I965_PGETBL_SIZE_128KB (2 << 1)
+#define I965_PGETBL_SIZE_1MB   (3 << 1)
+#define I965_PGETBL_SIZE_2MB   (4 << 1)
+#define I965_PGETBL_SIZE_1_5MB (5 << 1)
 #define G33_PGETBL_SIZE_MASK    (3 << 8)
 #define G33_PGETBL_SIZE_1M      (1 << 8)
 #define G33_PGETBL_SIZE_2M      (2 << 8)
index aa8f3a39a7044d74fe1652d62ef077fc470b024b..e77c17838c8af6ac0bf0559a20e4055875f7d9a1 100644 (file)
 
 #include "agp.h"
 
-static struct page *alpha_core_agp_vm_nopage(struct vm_area_struct *vma,
-                                            unsigned long address,
-                                            int *type)
+static int alpha_core_agp_vm_fault(struct vm_area_struct *vma,
+                                       struct vm_fault *vmf)
 {
        alpha_agp_info *agp = agp_bridge->dev_private_data;
        dma_addr_t dma_addr;
        unsigned long pa;
        struct page *page;
 
-       dma_addr = address - vma->vm_start + agp->aperture.bus_base;
+       dma_addr = (unsigned long)vmf->virtual_address - vma->vm_start
+                                               + agp->aperture.bus_base;
        pa = agp->ops->translate(agp, dma_addr);
 
        if (pa == (unsigned long)-EINVAL)
-               return NULL;    /* no translation */
+               return VM_FAULT_SIGBUS; /* no translation */
 
        /*
         * Get the page, inc the use count, and return it
         */
        page = virt_to_page(__va(pa));
        get_page(page);
-       if (type)
-               *type = VM_FAULT_MINOR;
-       return page;
+       vmf->page = page;
+       return 0;
 }
 
 static struct aper_size_info_fixed alpha_core_agp_sizes[] =
@@ -42,7 +41,7 @@ static struct aper_size_info_fixed alpha_core_agp_sizes[] =
 };
 
 struct vm_operations_struct alpha_core_agp_vm_ops = {
-       .nopage = alpha_core_agp_vm_nopage,
+       .fault = alpha_core_agp_vm_fault,
 };
 
 
index 1405a42585e13eb29dcb9ae3bce3d99836b9d5fb..87be46406dafdc201e5da80cd5faabd7dd1060da 100644 (file)
@@ -436,10 +436,6 @@ static int __devinit agp_amdk7_probe(struct pci_dev *pdev,
                                return -ENODEV;
                        }
                        cap_ptr = pci_find_capability(gfxcard, PCI_CAP_ID_AGP);
-                       if (!cap_ptr) {
-                               pci_dev_put(gfxcard);
-                               continue;
-                       }
                }
 
                /* With so many variants of NVidia cards, it's simpler just
index 2720882e66fec157dd987f0c665ae732171aa8df..b1bdd015165c092a5f850f606b1d9a8ed948d409 100644 (file)
@@ -43,7 +43,7 @@
  * fix some real stupidity. It's only by chance we can bump
  * past 0.99 at all due to some boolean logic error. */
 #define AGPGART_VERSION_MAJOR 0
-#define AGPGART_VERSION_MINOR 102
+#define AGPGART_VERSION_MINOR 103
 static const struct agp_version agp_current_version =
 {
        .major = AGPGART_VERSION_MAJOR,
index ecd4248861b9dfda6475e29d0acfcc9c6c547f96..39275794fe63a433edd5760b740af63ee12bf062 100644 (file)
@@ -273,6 +273,10 @@ long compat_agp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
        case AGPIOC_UNBIND32:
                ret_val = compat_agpioc_unbind_wrap(curr_priv, (void __user *) arg);
                break;
+
+       case AGPIOC_CHIPSET_FLUSH32:
+               ret_val = agpioc_chipset_flush_wrap(curr_priv);
+               break;
        }
 
 ioctl_out:
index 71939d637236c9e260e80a41ee74d1d8a69f8a05..0c9678ac03716809fa22ef01deaee895ffc40002 100644 (file)
@@ -39,6 +39,7 @@
 #define AGPIOC_DEALLOCATE32 _IOW (AGPIOC_BASE, 7, compat_int_t)
 #define AGPIOC_BIND32       _IOW (AGPIOC_BASE, 8, compat_uptr_t)
 #define AGPIOC_UNBIND32     _IOW (AGPIOC_BASE, 9, compat_uptr_t)
+#define AGPIOC_CHIPSET_FLUSH32 _IO (AGPIOC_BASE, 10)
 
 struct agp_info32 {
        struct agp_version version;     /* version of the driver        */
@@ -101,5 +102,6 @@ void agp_free_memory_wrap(struct agp_memory *memory);
 struct agp_memory *agp_allocate_memory_wrap(size_t pg_count, u32 type);
 struct agp_memory *agp_find_mem_by_key(int key);
 struct agp_client *agp_find_client_by_pid(pid_t id);
+int agpioc_chipset_flush_wrap(struct agp_file_private *priv);
 
 #endif /* _AGP_COMPAT_H */
index 7791e98de51c81a34ed3b4aed1b007cb4b728e46..55d7a82bd071a725a8813d888dabb77215de79be 100644 (file)
@@ -689,7 +689,7 @@ static int agp_open(struct inode *inode, struct file *file)
        set_bit(AGP_FF_ALLOW_CLIENT, &priv->access_flags);
        priv->my_pid = current->pid;
 
-       if ((current->uid == 0) || (current->suid == 0)) {
+       if (capable(CAP_SYS_RAWIO)) {
                /* Root priv, can be controller */
                set_bit(AGP_FF_ALLOW_CONTROLLER, &priv->access_flags);
        }
@@ -960,6 +960,13 @@ static int agpioc_unbind_wrap(struct agp_file_private *priv, void __user *arg)
        return agp_unbind_memory(memory);
 }
 
+int agpioc_chipset_flush_wrap(struct agp_file_private *priv)
+{
+       DBG("");
+       agp_flush_chipset(agp_bridge);
+       return 0;
+}
+
 static int agp_ioctl(struct inode *inode, struct file *file,
                     unsigned int cmd, unsigned long arg)
 {
@@ -1033,6 +1040,10 @@ static int agp_ioctl(struct inode *inode, struct file *file,
        case AGPIOC_UNBIND:
                ret_val = agpioc_unbind_wrap(curr_priv, (void __user *) arg);
                break;
+              
+       case AGPIOC_CHIPSET_FLUSH:
+               ret_val = agpioc_chipset_flush_wrap(curr_priv);
+               break;
        }
 
 ioctl_out:
index 1a4674ce0c718f4c1c3a9bceb8342551fc5e73b8..7484bc759c4ccb8e2fb2fa407e68ae38e5936dae 100644 (file)
@@ -80,6 +80,13 @@ static int agp_get_key(void)
        return -1;
 }
 
+void agp_flush_chipset(struct agp_bridge_data *bridge)
+{
+       if (bridge->driver->chipset_flush)
+               bridge->driver->chipset_flush(bridge);
+}
+EXPORT_SYMBOL(agp_flush_chipset);
+
 /*
  * Use kmalloc if possible for the page list. Otherwise fall back to
  * vmalloc. This speeds things up and also saves memory for small AGP
index 189efb6ef970e81b07aa69e90847ddabd14b161e..eeea50a1d22ace69991af91a7bcee524a4319e3e 100644 (file)
@@ -14,8 +14,8 @@
 #define PCI_DEVICE_ID_INTEL_E7221_IG   0x258a
 #define PCI_DEVICE_ID_INTEL_82946GZ_HB      0x2970
 #define PCI_DEVICE_ID_INTEL_82946GZ_IG      0x2972
-#define PCI_DEVICE_ID_INTEL_82965G_1_HB     0x2980
-#define PCI_DEVICE_ID_INTEL_82965G_1_IG     0x2982
+#define PCI_DEVICE_ID_INTEL_82G35_HB     0x2980
+#define PCI_DEVICE_ID_INTEL_82G35_IG     0x2982
 #define PCI_DEVICE_ID_INTEL_82965Q_HB       0x2990
 #define PCI_DEVICE_ID_INTEL_82965Q_IG       0x2992
 #define PCI_DEVICE_ID_INTEL_82965G_HB       0x29A0
 #define PCI_DEVICE_ID_INTEL_Q35_IG          0x29B2
 #define PCI_DEVICE_ID_INTEL_Q33_HB          0x29D0
 #define PCI_DEVICE_ID_INTEL_Q33_IG          0x29D2
+#define PCI_DEVICE_ID_INTEL_IGD_HB          0x2A40
+#define PCI_DEVICE_ID_INTEL_IGD_IG          0x2A42
+
+/* cover 915 and 945 variants */
+#define IS_I915 (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_E7221_HB || \
+                agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915G_HB || \
+                agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB || \
+                agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945G_HB || \
+                agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945GM_HB || \
+                agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945GME_HB)
 
 #define IS_I965 (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82946GZ_HB || \
-                 agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965G_1_HB || \
-                 agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965Q_HB || \
-                 agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965G_HB || \
-                 agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965GM_HB || \
-                 agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965GME_HB)
+                agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82G35_HB || \
+                agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965Q_HB || \
+                agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965G_HB || \
+                agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965GM_HB || \
+                agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965GME_HB || \
+                agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IGD_HB)
 
 #define IS_G33 (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_G33_HB || \
                agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_Q35_HB || \
@@ -71,9 +82,11 @@ extern int agp_memory_reserved;
 #define I915_GMCH_GMS_STOLEN_64M       (0x7 << 4)
 #define G33_GMCH_GMS_STOLEN_128M       (0x8 << 4)
 #define G33_GMCH_GMS_STOLEN_256M       (0x9 << 4)
+#define I915_IFPADDR    0x60
 
 /* Intel 965G registers */
 #define I965_MSAC 0x62
+#define I965_IFPADDR    0x70
 
 /* Intel 7505 registers */
 #define INTEL_I7505_APSIZE     0x74
@@ -115,6 +128,13 @@ static struct _intel_private {
         * popup and for the GTT.
         */
        int gtt_entries;                        /* i830+ */
+       union {
+               void __iomem *i9xx_flush_page;
+               void *i8xx_flush_page;
+       };
+       struct page *i8xx_page;
+       struct resource ifp_resource;
+       int resource_valid;
 } intel_private;
 
 static int intel_i810_fetch_size(void)
@@ -204,7 +224,7 @@ static void intel_i810_agp_enable(struct agp_bridge_data *bridge, u32 mode)
 /* Exists to support ARGB cursors */
 static void *i8xx_alloc_pages(void)
 {
-       struct page * page;
+       struct page *page;
 
        page = alloc_pages(GFP_KERNEL | GFP_DMA32, 2);
        if (page == NULL)
@@ -433,7 +453,7 @@ static void intel_i830_init_gtt_entries(void)
        static const int ddt[4] = { 0, 16, 32, 64 };
        int size; /* reserved space (in kb) at the top of stolen memory */
 
-       pci_read_config_word(agp_bridge->dev,I830_GMCH_CTRL,&gmch_ctrl);
+       pci_read_config_word(agp_bridge->dev, I830_GMCH_CTRL, &gmch_ctrl);
 
        if (IS_I965) {
                u32 pgetbl_ctl;
@@ -453,6 +473,15 @@ static void intel_i830_init_gtt_entries(void)
                case I965_PGETBL_SIZE_512KB:
                        size = 512;
                        break;
+               case I965_PGETBL_SIZE_1MB:
+                       size = 1024;
+                       break;
+               case I965_PGETBL_SIZE_2MB:
+                       size = 2048;
+                       break;
+               case I965_PGETBL_SIZE_1_5MB:
+                       size = 1024 + 512;
+                       break;
                default:
                        printk(KERN_INFO PFX "Unknown page table size, "
                               "assuming 512KB\n");
@@ -523,26 +552,14 @@ static void intel_i830_init_gtt_entries(void)
                        break;
                case I915_GMCH_GMS_STOLEN_48M:
                        /* Check it's really I915G */
-                       if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_E7221_HB ||
-                           agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915G_HB ||
-                           agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB ||
-                           agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945G_HB ||
-                           agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945GM_HB ||
-                           agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945GME_HB ||
-                           IS_I965 || IS_G33)
+                       if (IS_I915 || IS_I965 || IS_G33)
                                gtt_entries = MB(48) - KB(size);
                        else
                                gtt_entries = 0;
                        break;
                case I915_GMCH_GMS_STOLEN_64M:
                        /* Check it's really I915G */
-                       if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_E7221_HB ||
-                           agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915G_HB ||
-                           agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB ||
-                           agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945G_HB ||
-                           agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945GM_HB ||
-                           agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945GME_HB ||
-                           IS_I965 || IS_G33)
+                       if (IS_I915 || IS_I965 || IS_G33)
                                gtt_entries = MB(64) - KB(size);
                        else
                                gtt_entries = 0;
@@ -575,6 +592,45 @@ static void intel_i830_init_gtt_entries(void)
        intel_private.gtt_entries = gtt_entries;
 }
 
+static void intel_i830_fini_flush(void)
+{
+       kunmap(intel_private.i8xx_page);
+       intel_private.i8xx_flush_page = NULL;
+       unmap_page_from_agp(intel_private.i8xx_page);
+
+       __free_page(intel_private.i8xx_page);
+       intel_private.i8xx_page = NULL;
+}
+
+static void intel_i830_setup_flush(void)
+{
+       /* return if we've already set the flush mechanism up */
+       if (intel_private.i8xx_page)
+               return;
+
+       intel_private.i8xx_page = alloc_page(GFP_KERNEL | __GFP_ZERO | GFP_DMA32);
+       if (!intel_private.i8xx_page)
+               return;
+
+       /* make page uncached */
+       map_page_into_agp(intel_private.i8xx_page);
+
+       intel_private.i8xx_flush_page = kmap(intel_private.i8xx_page);
+       if (!intel_private.i8xx_flush_page)
+               intel_i830_fini_flush();
+}
+
+static void intel_i830_chipset_flush(struct agp_bridge_data *bridge)
+{
+       unsigned int *pg = intel_private.i8xx_flush_page;
+       int i;
+
+       for (i = 0; i < 256; i += 2)
+               *(pg + i) = i;
+
+       wmb();
+}
+
 /* The intel i830 automatically initializes the agp aperture during POST.
  * Use the memory already set aside for in the GTT.
  */
@@ -590,10 +646,10 @@ static int intel_i830_create_gatt_table(struct agp_bridge_data *bridge)
        num_entries = size->num_entries;
        agp_bridge->gatt_table_real = NULL;
 
-       pci_read_config_dword(intel_private.pcidev,I810_MMADDR,&temp);
+       pci_read_config_dword(intel_private.pcidev, I810_MMADDR, &temp);
        temp &= 0xfff80000;
 
-       intel_private.registers = ioremap(temp,128 * 4096);
+       intel_private.registers = ioremap(temp, 128 * 4096);
        if (!intel_private.registers)
                return -ENOMEM;
 
@@ -633,7 +689,7 @@ static int intel_i830_fetch_size(void)
                return values[0].size;
        }
 
-       pci_read_config_word(agp_bridge->dev,I830_GMCH_CTRL,&gmch_ctrl);
+       pci_read_config_word(agp_bridge->dev, I830_GMCH_CTRL, &gmch_ctrl);
 
        if ((gmch_ctrl & I830_GMCH_MEM_MASK) == I830_GMCH_MEM_128M) {
                agp_bridge->previous_size = agp_bridge->current_size = (void *) values;
@@ -657,12 +713,12 @@ static int intel_i830_configure(void)
 
        current_size = A_SIZE_FIX(agp_bridge->current_size);
 
-       pci_read_config_dword(intel_private.pcidev,I810_GMADDR,&temp);
+       pci_read_config_dword(intel_private.pcidev, I810_GMADDR, &temp);
        agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
 
-       pci_read_config_word(agp_bridge->dev,I830_GMCH_CTRL,&gmch_ctrl);
+       pci_read_config_word(agp_bridge->dev, I830_GMCH_CTRL, &gmch_ctrl);
        gmch_ctrl |= I830_GMCH_ENABLED;
-       pci_write_config_word(agp_bridge->dev,I830_GMCH_CTRL,gmch_ctrl);
+       pci_write_config_word(agp_bridge->dev, I830_GMCH_CTRL, gmch_ctrl);
 
        writel(agp_bridge->gatt_bus_addr|I810_PGETBL_ENABLED, intel_private.registers+I810_PGETBL_CTL);
        readl(intel_private.registers+I810_PGETBL_CTL); /* PCI Posting. */
@@ -675,6 +731,8 @@ static int intel_i830_configure(void)
        }
 
        global_cache_flush();
+
+       intel_i830_setup_flush();
        return 0;
 }
 
@@ -683,9 +741,10 @@ static void intel_i830_cleanup(void)
        iounmap(intel_private.registers);
 }
 
-static int intel_i830_insert_entries(struct agp_memory *mem,off_t pg_start, int type)
+static int intel_i830_insert_entries(struct agp_memory *mem, off_t pg_start,
+                                    int type)
 {
-       int i,j,num_entries;
+       int i, j, num_entries;
        void *temp;
        int ret = -EINVAL;
        int mask_type;
@@ -697,10 +756,10 @@ static int intel_i830_insert_entries(struct agp_memory *mem,off_t pg_start, int
        num_entries = A_SIZE_FIX(temp)->num_entries;
 
        if (pg_start < intel_private.gtt_entries) {
-               printk (KERN_DEBUG PFX "pg_start == 0x%.8lx,intel_private.gtt_entries == 0x%.8x\n",
-                               pg_start,intel_private.gtt_entries);
+               printk(KERN_DEBUG PFX "pg_start == 0x%.8lx,intel_private.gtt_entries == 0x%.8x\n",
+                               pg_start, intel_private.gtt_entries);
 
-               printk (KERN_INFO PFX "Trying to insert into local/stolen memory\n");
+               printk(KERN_INFO PFX "Trying to insert into local/stolen memory\n");
                goto out_err;
        }
 
@@ -738,8 +797,8 @@ out_err:
        return ret;
 }
 
-static int intel_i830_remove_entries(struct agp_memory *mem,off_t pg_start,
-                               int type)
+static int intel_i830_remove_entries(struct agp_memory *mem, off_t pg_start,
+                                    int type)
 {
        int i;
 
@@ -747,7 +806,7 @@ static int intel_i830_remove_entries(struct agp_memory *mem,off_t pg_start,
                return 0;
 
        if (pg_start < intel_private.gtt_entries) {
-               printk (KERN_INFO PFX "Trying to disable local/stolen memory\n");
+               printk(KERN_INFO PFX "Trying to disable local/stolen memory\n");
                return -EINVAL;
        }
 
@@ -760,7 +819,7 @@ static int intel_i830_remove_entries(struct agp_memory *mem,off_t pg_start,
        return 0;
 }
 
-static struct agp_memory *intel_i830_alloc_by_type(size_t pg_count,int type)
+static struct agp_memory *intel_i830_alloc_by_type(size_t pg_count, int type)
 {
        if (type == AGP_PHYS_MEMORY)
                return alloc_agpphysmem_i8xx(pg_count, type);
@@ -768,6 +827,95 @@ static struct agp_memory *intel_i830_alloc_by_type(size_t pg_count,int type)
        return NULL;
 }
 
+static int intel_alloc_chipset_flush_resource(void)
+{
+       int ret;
+       ret = pci_bus_alloc_resource(agp_bridge->dev->bus, &intel_private.ifp_resource, PAGE_SIZE,
+                                    PAGE_SIZE, PCIBIOS_MIN_MEM, 0,
+                                    pcibios_align_resource, agp_bridge->dev);
+
+       return ret;
+}
+
+static void intel_i915_setup_chipset_flush(void)
+{
+       int ret;
+       u32 temp;
+
+       pci_read_config_dword(agp_bridge->dev, I915_IFPADDR, &temp);
+       if (!(temp & 0x1)) {
+               intel_alloc_chipset_flush_resource();
+               intel_private.resource_valid = 1;
+               pci_write_config_dword(agp_bridge->dev, I915_IFPADDR, (intel_private.ifp_resource.start & 0xffffffff) | 0x1);
+       } else {
+               temp &= ~1;
+
+               intel_private.resource_valid = 1;
+               intel_private.ifp_resource.start = temp;
+               intel_private.ifp_resource.end = temp + PAGE_SIZE;
+               ret = request_resource(&iomem_resource, &intel_private.ifp_resource);
+               /* some BIOSes reserve this area in a pnp some don't */
+               if (ret)
+                       intel_private.resource_valid = 0;
+       }
+}
+
+static void intel_i965_g33_setup_chipset_flush(void)
+{
+       u32 temp_hi, temp_lo;
+       int ret;
+
+       pci_read_config_dword(agp_bridge->dev, I965_IFPADDR + 4, &temp_hi);
+       pci_read_config_dword(agp_bridge->dev, I965_IFPADDR, &temp_lo);
+
+       if (!(temp_lo & 0x1)) {
+
+               intel_alloc_chipset_flush_resource();
+
+               intel_private.resource_valid = 1;
+               pci_write_config_dword(agp_bridge->dev, I965_IFPADDR + 4,
+                       upper_32_bits(intel_private.ifp_resource.start));
+               pci_write_config_dword(agp_bridge->dev, I965_IFPADDR, (intel_private.ifp_resource.start & 0xffffffff) | 0x1);
+       } else {
+               u64 l64;
+
+               temp_lo &= ~0x1;
+               l64 = ((u64)temp_hi << 32) | temp_lo;
+
+               intel_private.resource_valid = 1;
+               intel_private.ifp_resource.start = l64;
+               intel_private.ifp_resource.end = l64 + PAGE_SIZE;
+               ret = request_resource(&iomem_resource, &intel_private.ifp_resource);
+               /* some BIOSes reserve this area in a pnp some don't */
+               if (ret)
+                       intel_private.resource_valid = 0;
+       }
+}
+
+static void intel_i9xx_setup_flush(void)
+{
+       /* return if already configured */
+       if (intel_private.ifp_resource.start)
+               return;
+
+       /* setup a resource for this object */
+       intel_private.ifp_resource.name = "Intel Flush Page";
+       intel_private.ifp_resource.flags = IORESOURCE_MEM;
+
+       /* Setup chipset flush for 915 */
+       if (IS_I965 || IS_G33) {
+               intel_i965_g33_setup_chipset_flush();
+       } else {
+               intel_i915_setup_chipset_flush();
+       }
+
+       if (intel_private.ifp_resource.start) {
+               intel_private.i9xx_flush_page = ioremap_nocache(intel_private.ifp_resource.start, PAGE_SIZE);
+               if (!intel_private.i9xx_flush_page)
+                       printk(KERN_INFO "unable to ioremap flush  page - no chipset flushing");
+       }
+}
+
 static int intel_i915_configure(void)
 {
        struct aper_size_info_fixed *current_size;
@@ -781,9 +929,9 @@ static int intel_i915_configure(void)
 
        agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
 
-       pci_read_config_word(agp_bridge->dev,I830_GMCH_CTRL,&gmch_ctrl);
+       pci_read_config_word(agp_bridge->dev, I830_GMCH_CTRL, &gmch_ctrl);
        gmch_ctrl |= I830_GMCH_ENABLED;
-       pci_write_config_word(agp_bridge->dev,I830_GMCH_CTRL,gmch_ctrl);
+       pci_write_config_word(agp_bridge->dev, I830_GMCH_CTRL, gmch_ctrl);
 
        writel(agp_bridge->gatt_bus_addr|I810_PGETBL_ENABLED, intel_private.registers+I810_PGETBL_CTL);
        readl(intel_private.registers+I810_PGETBL_CTL); /* PCI Posting. */
@@ -796,19 +944,34 @@ static int intel_i915_configure(void)
        }
 
        global_cache_flush();
+
+       intel_i9xx_setup_flush();
+
        return 0;
 }
 
 static void intel_i915_cleanup(void)
 {
+       if (intel_private.i9xx_flush_page)
+               iounmap(intel_private.i9xx_flush_page);
+       if (intel_private.resource_valid)
+               release_resource(&intel_private.ifp_resource);
+       intel_private.ifp_resource.start = 0;
+       intel_private.resource_valid = 0;
        iounmap(intel_private.gtt);
        iounmap(intel_private.registers);
 }
 
-static int intel_i915_insert_entries(struct agp_memory *mem,off_t pg_start,
-                               int type)
+static void intel_i915_chipset_flush(struct agp_bridge_data *bridge)
 {
-       int i,j,num_entries;
+       if (intel_private.i9xx_flush_page)
+               writel(1, intel_private.i9xx_flush_page);
+}
+
+static int intel_i915_insert_entries(struct agp_memory *mem, off_t pg_start,
+                                    int type)
+{
+       int i, j, num_entries;
        void *temp;
        int ret = -EINVAL;
        int mask_type;
@@ -820,10 +983,10 @@ static int intel_i915_insert_entries(struct agp_memory *mem,off_t pg_start,
        num_entries = A_SIZE_FIX(temp)->num_entries;
 
        if (pg_start < intel_private.gtt_entries) {
-               printk (KERN_DEBUG PFX "pg_start == 0x%.8lx,intel_private.gtt_entries == 0x%.8x\n",
-                               pg_start,intel_private.gtt_entries);
+               printk(KERN_DEBUG PFX "pg_start == 0x%.8lx,intel_private.gtt_entries == 0x%.8x\n",
+                               pg_start, intel_private.gtt_entries);
 
-               printk (KERN_INFO PFX "Trying to insert into local/stolen memory\n");
+               printk(KERN_INFO PFX "Trying to insert into local/stolen memory\n");
                goto out_err;
        }
 
@@ -861,8 +1024,8 @@ static int intel_i915_insert_entries(struct agp_memory *mem,off_t pg_start,
        return ret;
 }
 
-static int intel_i915_remove_entries(struct agp_memory *mem,off_t pg_start,
-                               int type)
+static int intel_i915_remove_entries(struct agp_memory *mem, off_t pg_start,
+                                    int type)
 {
        int i;
 
@@ -870,13 +1033,13 @@ static int intel_i915_remove_entries(struct agp_memory *mem,off_t pg_start,
                return 0;
 
        if (pg_start < intel_private.gtt_entries) {
-               printk (KERN_INFO PFX "Trying to disable local/stolen memory\n");
+               printk(KERN_INFO PFX "Trying to disable local/stolen memory\n");
                return -EINVAL;
        }
 
-       for (i = pg_start; i < (mem->page_count + pg_start); i++) {
+       for (i = pg_start; i < (mem->page_count + pg_start); i++)
                writel(agp_bridge->scratch_page, intel_private.gtt+i);
-       }
+
        readl(intel_private.gtt+i-1);
 
        agp_bridge->driver->tlb_flush(mem);
@@ -923,7 +1086,7 @@ static int intel_i915_create_gatt_table(struct agp_bridge_data *bridge)
        agp_bridge->gatt_table_real = NULL;
 
        pci_read_config_dword(intel_private.pcidev, I915_MMADDR, &temp);
-       pci_read_config_dword(intel_private.pcidev, I915_PTEADDR,&temp2);
+       pci_read_config_dword(intel_private.pcidev, I915_PTEADDR, &temp2);
 
        if (IS_G33)
            gtt_map_size = 1024 * 1024; /* 1M on G33 */
@@ -933,7 +1096,7 @@ static int intel_i915_create_gatt_table(struct agp_bridge_data *bridge)
 
        temp &= 0xfff80000;
 
-       intel_private.registers = ioremap(temp,128 * 4096);
+       intel_private.registers = ioremap(temp, 128 * 4096);
        if (!intel_private.registers) {
                iounmap(intel_private.gtt);
                return -ENOMEM;
@@ -980,6 +1143,7 @@ static int intel_i965_create_gatt_table(struct agp_bridge_data *bridge)
        struct aper_size_info_fixed *size;
        int num_entries;
        u32 temp;
+       int gtt_offset, gtt_size;
 
        size = agp_bridge->current_size;
        page_order = size->page_order;
@@ -989,13 +1153,18 @@ static int intel_i965_create_gatt_table(struct agp_bridge_data *bridge)
        pci_read_config_dword(intel_private.pcidev, I915_MMADDR, &temp);
 
        temp &= 0xfff00000;
-       intel_private.gtt = ioremap((temp + (512 * 1024)) , 512 * 1024);
 
-       if (!intel_private.gtt)
-               return -ENOMEM;
+       if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IGD_HB)
+              gtt_offset = gtt_size = MB(2);
+       else
+              gtt_offset = gtt_size = KB(512);
+
+       intel_private.gtt = ioremap((temp + gtt_offset) , gtt_size);
 
+       if (!intel_private.gtt)
+              return -ENOMEM;
 
-       intel_private.registers = ioremap(temp,128 * 4096);
+       intel_private.registers = ioremap(temp, 128 * 4096);
        if (!intel_private.registers) {
                iounmap(intel_private.gtt);
                return -ENOMEM;
@@ -1154,7 +1323,7 @@ static int intel_815_configure(void)
        /* the Intel 815 chipset spec. says that bits 29-31 in the
        * ATTBASE register are reserved -> try not to write them */
        if (agp_bridge->gatt_bus_addr & INTEL_815_ATTBASE_MASK) {
-               printk (KERN_EMERG PFX "gatt bus addr too high");
+               printk(KERN_EMERG PFX "gatt bus addr too high");
                return -EINVAL;
        }
 
@@ -1296,6 +1465,8 @@ static int intel_845_configure(void)
        pci_write_config_byte(agp_bridge->dev, INTEL_I845_AGPM, temp2 | (1 << 1));
        /* clear any possible error conditions */
        pci_write_config_word(agp_bridge->dev, INTEL_I845_ERRSTS, 0x001c);
+
+       intel_i830_setup_flush();
        return 0;
 }
 
@@ -1552,6 +1723,7 @@ static const struct agp_bridge_driver intel_830_driver = {
        .agp_alloc_page         = agp_generic_alloc_page,
        .agp_destroy_page       = agp_generic_destroy_page,
        .agp_type_to_mask_type  = intel_i830_type_to_mask_type,
+       .chipset_flush          = intel_i830_chipset_flush,
 };
 
 static const struct agp_bridge_driver intel_820_driver = {
@@ -1648,6 +1820,7 @@ static const struct agp_bridge_driver intel_845_driver = {
        .agp_alloc_page         = agp_generic_alloc_page,
        .agp_destroy_page       = agp_generic_destroy_page,
        .agp_type_to_mask_type  = agp_generic_type_to_mask_type,
+       .chipset_flush          = intel_i830_chipset_flush,
 };
 
 static const struct agp_bridge_driver intel_850_driver = {
@@ -1721,6 +1894,7 @@ static const struct agp_bridge_driver intel_915_driver = {
        .agp_alloc_page         = agp_generic_alloc_page,
        .agp_destroy_page       = agp_generic_destroy_page,
        .agp_type_to_mask_type  = intel_i830_type_to_mask_type,
+       .chipset_flush          = intel_i915_chipset_flush,
 };
 
 static const struct agp_bridge_driver intel_i965_driver = {
@@ -1746,6 +1920,7 @@ static const struct agp_bridge_driver intel_i965_driver = {
        .agp_alloc_page         = agp_generic_alloc_page,
        .agp_destroy_page       = agp_generic_destroy_page,
        .agp_type_to_mask_type  = intel_i830_type_to_mask_type,
+       .chipset_flush          = intel_i915_chipset_flush,
 };
 
 static const struct agp_bridge_driver intel_7505_driver = {
@@ -1795,6 +1970,7 @@ static const struct agp_bridge_driver intel_g33_driver = {
        .agp_alloc_page         = agp_generic_alloc_page,
        .agp_destroy_page       = agp_generic_destroy_page,
        .agp_type_to_mask_type  = intel_i830_type_to_mask_type,
+       .chipset_flush          = intel_i915_chipset_flush,
 };
 
 static int find_gmch(u16 device)
@@ -1804,7 +1980,7 @@ static int find_gmch(u16 device)
        gmch_device = pci_get_device(PCI_VENDOR_ID_INTEL, device, NULL);
        if (gmch_device && PCI_FUNC(gmch_device->devfn) != 0) {
                gmch_device = pci_get_device(PCI_VENDOR_ID_INTEL,
-                                device, gmch_device);
+                                            device, gmch_device);
        }
 
        if (!gmch_device)
@@ -1867,7 +2043,7 @@ static const struct intel_driver_description {
                NULL, &intel_915_driver },
        { PCI_DEVICE_ID_INTEL_82946GZ_HB, PCI_DEVICE_ID_INTEL_82946GZ_IG, 0, "946GZ",
                NULL, &intel_i965_driver },
-       { PCI_DEVICE_ID_INTEL_82965G_1_HB, PCI_DEVICE_ID_INTEL_82965G_1_IG, 0, "965G",
+       { PCI_DEVICE_ID_INTEL_82G35_HB, PCI_DEVICE_ID_INTEL_82G35_IG, 0, "G35",
                NULL, &intel_i965_driver },
        { PCI_DEVICE_ID_INTEL_82965Q_HB, PCI_DEVICE_ID_INTEL_82965Q_IG, 0, "965Q",
                NULL, &intel_i965_driver },
@@ -1885,6 +2061,8 @@ static const struct intel_driver_description {
                NULL, &intel_g33_driver },
        { PCI_DEVICE_ID_INTEL_Q33_HB, PCI_DEVICE_ID_INTEL_Q33_IG, 0, "Q33",
                NULL, &intel_g33_driver },
+       { PCI_DEVICE_ID_INTEL_IGD_HB, PCI_DEVICE_ID_INTEL_IGD_IG, 0,
+           "Intel Integrated Graphics Device", NULL, &intel_i965_driver },
        { 0, 0, 0, NULL, NULL, NULL }
 };
 
@@ -1924,7 +2102,7 @@ static int __devinit agp_intel_probe(struct pci_dev *pdev,
        if (intel_agp_chipsets[i].name == NULL) {
                if (cap_ptr)
                        printk(KERN_WARNING PFX "Unsupported Intel chipset"
-                               "(device id: %04x)\n", pdev->device);
+                              "(device id: %04x)\n", pdev->device);
                agp_put_bridge(bridge);
                return -ENODEV;
        }
@@ -1937,7 +2115,7 @@ static int __devinit agp_intel_probe(struct pci_dev *pdev,
                                intel_agp_chipsets[i].gmch_chip_id);
                agp_put_bridge(bridge);
                return -ENODEV;
-        }
+       }
 
        bridge->dev = pdev;
        bridge->capndx = cap_ptr;
@@ -2067,7 +2245,7 @@ static struct pci_device_id agp_intel_pci_table[] = {
        ID(PCI_DEVICE_ID_INTEL_82945GM_HB),
        ID(PCI_DEVICE_ID_INTEL_82945GME_HB),
        ID(PCI_DEVICE_ID_INTEL_82946GZ_HB),
-       ID(PCI_DEVICE_ID_INTEL_82965G_1_HB),
+       ID(PCI_DEVICE_ID_INTEL_82G35_HB),
        ID(PCI_DEVICE_ID_INTEL_82965Q_HB),
        ID(PCI_DEVICE_ID_INTEL_82965G_HB),
        ID(PCI_DEVICE_ID_INTEL_82965GM_HB),
@@ -2075,6 +2253,7 @@ static struct pci_device_id agp_intel_pci_table[] = {
        ID(PCI_DEVICE_ID_INTEL_G33_HB),
        ID(PCI_DEVICE_ID_INTEL_Q35_HB),
        ID(PCI_DEVICE_ID_INTEL_Q33_HB),
+       ID(PCI_DEVICE_ID_INTEL_IGD_HB),
        { }
 };
 
index e8d50af58201825effe532d775362187a90b46fc..ef5e6b130c4845aa8b3ad68b36538b34d90e6311 100644 (file)
@@ -506,6 +506,7 @@ static int drm_mmap_dma(struct file *filp, struct vm_area_struct *vma)
        vma->vm_ops = &drm_vm_dma_ops;
 
        vma->vm_flags |= VM_RESERVED;   /* Don't swap */
+       vma->vm_flags |= VM_DONTEXPAND;
 
        vma->vm_file = filp;    /* Needed for drm_vm_open() */
        drm_vm_open_locked(vma);
@@ -655,6 +656,7 @@ static int drm_mmap_locked(struct file *filp, struct vm_area_struct *vma)
                return -EINVAL; /* This should never happen. */
        }
        vma->vm_flags |= VM_RESERVED;   /* Don't swap */
+       vma->vm_flags |= VM_DONTEXPAND;
 
        vma->vm_file = filp;    /* Needed for drm_vm_open() */
        drm_vm_open_locked(vma);
index 3ae57ecc7afd84b30b6557a4e01d0be30c45fc5c..fa194a46c1e4f3166ef0d2164e215b8221b9be07 100644 (file)
@@ -584,7 +584,7 @@ USE OR OTHER DEALINGS IN THE SOFTWARE.
 #define R300_RE_FOG_START                     0x4298
 
 /* Not sure why there are duplicate of factor and constant values.
- * My best guess so far is that there are seperate zbiases for test and write.
+ * My best guess so far is that there are separate zbiases for test and write.
  * Ordering might be wrong.
  * Some of the tests indicate that fgl has a fallback implementation of zbias
  * via pixel shaders.
index 75d6b748c2c0dec1e2634082820681e5f5b3e288..7009dbddac436fc86fbd1fe20757382d6228541f 100644 (file)
@@ -400,7 +400,7 @@ static inline uint32_t *via_align_buffer(drm_via_private_t * dev_priv,
 }
 
 /*
- * This function is used internally by ring buffer mangement code.
+ * This function is used internally by ring buffer management code.
  *
  * Returns virtual pointer to ring buffer.
  */
index 004141d535a27852eda7d3a9ea287893ea3db2e7..49233f5898742040339b5a1d31c4ce7fd74d9960 100644 (file)
@@ -18,7 +18,7 @@
  *
  * NOTES:
  *     - Locking is required for safe execution of EFI calls with regards
- *       to interrrupts and SMP.
+ *       to interrupts and SMP.
  *
  * TODO (December 1999):
  *     - provide the API to set/get the WakeUp Alarm (different from the
index ffcecde9e2a5b317319e605480c5520264c77ee3..ffd747c5dff00dc7e69a1835d078003dd7ffc3d7 100644 (file)
@@ -1797,7 +1797,7 @@ static unsigned termios2digi_c(struct channel *ch, unsigned cflag)
        res |= cflag & ((CBAUD ^ CBAUDEX) | PARODD | PARENB | CSTOPB | CSIZE);
        /*
         * This gets a little confusing. The Digi cards have their own
-        * representation of c_cflags controling baud rate. For the most part
+        * representation of c_cflags controlling baud rate. For the most part
         * this is identical to the Linux implementation. However; Digi
         * supports one rate (76800) that Linux doesn't. This means that the
         * c_cflag entry that would normally mean 76800 for Digi actually means
@@ -2068,7 +2068,7 @@ static int info_ioctl(struct tty_struct *tty, struct file *file,
                {
                        /*
                         * This call is made by the apps to complete the
-                        * initilization of the board(s). This routine is
+                        * initialization of the board(s). This routine is
                         * responsible for setting the card to its initial
                         * state and setting the drivers control fields to the
                         * sutianle settings for the card in question.
index 0e8ceea5ea780a10c0e5f9bbb506da486cd658c6..712d9f271aa6b8ed7026bca1594cc3b38052287f 100644 (file)
@@ -26,7 +26,7 @@
  * The hangcheck-timer driver uses the TSC to catch delays that
  * jiffies does not notice.  A timer is set.  When the timer fires, it
  * checks whether it was delayed and if that delay exceeds a given
- * margin of error.  The hangcheck_tick module paramter takes the timer
+ * margin of error.  The hangcheck_tick module parameter takes the timer
  * duration in seconds.  The hangcheck_margin parameter defines the
  * margin of error, in seconds.  The defaults are 60 seconds for the
  * timer and 180 seconds for the margin of error.  IOW, a timer is set
index fd7559084b8204479c76dc0cbd72da06fe431126..3402def22007145a5ffba726bcc3e3b55554b51d 100644 (file)
@@ -838,7 +838,7 @@ static int __devexit hvcs_remove(struct vio_dev *dev)
        if (!hvcsd)
                return -ENODEV;
 
-       /* By this time the vty-server won't be getting any more interrups */
+       /* By this time the vty-server won't be getting any more interrupts */
 
        spin_lock_irqsave(&hvcsd->lock, flags);
 
index 0118b9817a95efa7a414033d52418f2d6885f6f1..84cdf9025737722fe4341974cf3bce90d268bc3f 100644 (file)
@@ -234,11 +234,11 @@ static DEVICE_ATTR(rng_available, S_IRUGO,
                   NULL);
 
 
-static void unregister_miscdev(void)
+static void unregister_miscdev(bool suspended)
 {
        device_remove_file(rng_miscdev.this_device, &dev_attr_rng_available);
        device_remove_file(rng_miscdev.this_device, &dev_attr_rng_current);
-       misc_deregister(&rng_miscdev);
+       __misc_deregister(&rng_miscdev, suspended);
 }
 
 static int register_miscdev(void)
@@ -313,7 +313,7 @@ out:
 }
 EXPORT_SYMBOL_GPL(hwrng_register);
 
-void hwrng_unregister(struct hwrng *rng)
+void __hwrng_unregister(struct hwrng *rng, bool suspended)
 {
        int err;
 
@@ -332,11 +332,11 @@ void hwrng_unregister(struct hwrng *rng)
                }
        }
        if (list_empty(&rng_list))
-               unregister_miscdev();
+               unregister_miscdev(suspended);
 
        mutex_unlock(&rng_mutex);
 }
-EXPORT_SYMBOL_GPL(hwrng_unregister);
+EXPORT_SYMBOL_GPL(__hwrng_unregister);
 
 
 MODULE_DESCRIPTION("H/W Random Number Generator (RNG) driver");
index e46120d05b689af32f855e68a1656fd1d9794fd0..d6567b32fb5c18c960651fb49fdfee5277225895 100644 (file)
@@ -661,7 +661,7 @@ i2QueueCommands(int type, i2ChanStrPtr pCh, int timeout, int nCommands,
                if (!in_interrupt()) {
                        schedule_timeout_interruptible(1);      // short nap
                } else {
-                       // we cannot sched/sleep in interrrupt silly
+                       // we cannot sched/sleep in interrupt silly
                        return 0;   
                }
                if (signal_pending(current)) {
index e04e66cf2c68c53c6bc829d2923fbc8c5910a909..0f49ccf02a7fea974440587b337e60f015740e6f 100644 (file)
@@ -1251,7 +1251,7 @@ ip2_poll(unsigned long arg)
 
        // Just polled boards, IRQ = 0 will hit all non-interrupt boards.
        // It will NOT poll boards handled by hard interrupts.
-       // The issue of queued BH interrups is handled in ip2_interrupt().
+       // The issue of queued BH interrupts is handled in ip2_interrupt().
        ip2_polled_interrupt();
 
        PollTimer.expires = POLL_TIMEOUT;
index 71c8cd7fa15f8d5c32574ce95016f980e6830c41..a39101feb2ed8f70ff57f5d74e1a05855bec959d 100644 (file)
@@ -232,8 +232,9 @@ int misc_register(struct miscdevice * misc)
 }
 
 /**
- *     misc_deregister - unregister a miscellaneous device
+ *     __misc_deregister - unregister a miscellaneous device
  *     @misc: device to unregister
+ *     @suspended: to be set if the function is used during suspend/resume
  *
  *     Unregister a miscellaneous device that was previously
  *     successfully registered with misc_register(). Success
@@ -241,7 +242,7 @@ int misc_register(struct miscdevice * misc)
  *     indicates an error.
  */
 
-int misc_deregister(struct miscdevice * misc)
+int __misc_deregister(struct miscdevice *misc, bool suspended)
 {
        int i = misc->minor;
 
@@ -250,7 +251,11 @@ int misc_deregister(struct miscdevice * misc)
 
        mutex_lock(&misc_mtx);
        list_del(&misc->list);
-       device_destroy(misc_class, MKDEV(MISC_MAJOR, misc->minor));
+       if (suspended)
+               destroy_suspended_device(misc_class,
+                                       MKDEV(MISC_MAJOR, misc->minor));
+       else
+               device_destroy(misc_class, MKDEV(MISC_MAJOR, misc->minor));
        if (i < DYNAMIC_MINORS && i>0) {
                misc_minors[i>>3] &= ~(1 << (misc->minor & 7));
        }
@@ -259,7 +264,7 @@ int misc_deregister(struct miscdevice * misc)
 }
 
 EXPORT_SYMBOL(misc_register);
-EXPORT_SYMBOL(misc_deregister);
+EXPORT_SYMBOL(__misc_deregister);
 
 static int __init misc_init(void)
 {
index 82f2e27dca7d17ac42072adbd56cb52a175d551a..ff146c2b08fd65cb6e26498923d4df8b03ab95df 100644 (file)
@@ -283,7 +283,7 @@ mspec_mmap(struct file *file, struct vm_area_struct *vma,
        vdata->refcnt = ATOMIC_INIT(1);
        vma->vm_private_data = vdata;
 
-       vma->vm_flags |= (VM_IO | VM_RESERVED | VM_PFNMAP);
+       vma->vm_flags |= (VM_IO | VM_RESERVED | VM_PFNMAP | VM_DONTEXPAND);
        if (vdata->type == MSPEC_FETCHOP || vdata->type == MSPEC_UNCACHED)
                vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
        vma->vm_ops = &mspec_vm_ops;
index 6076e662886a43fc3b863ab3bd6022e0e8041f0e..dfaab2322de32c09a0adeab709cf5613ca9a0d5f 100644 (file)
@@ -2,7 +2,7 @@
  * nozomi.c  -- HSDPA driver Broadband Wireless Data Card - Globe Trotter
  *
  * Written by: Ulf Jakobsson,
- *             Jan ï¿½erfeldt,
+ *             Jan Ã…kerfeldt,
  *             Stefan Thomasson,
  *
  * Maintained by: Paul Hardwick (p.hardwick@option.com)
  * --------------------------------------------------------------------------
  */
 
-/*
- * CHANGELOG
- * Version 2.1d
- * 11-November-2007 Jiri Slaby, Frank Seidel
- * - Big rework of multicard support by Jiri
- * - Major cleanups (semaphore to mutex, endianess, no major reservation)
- * - Optimizations
- *
- * Version 2.1c
- * 30-October-2007 Frank Seidel
- * - Completed multicard support
- * - Minor cleanups
- *
- * Version 2.1b
- * 07-August-2007 Frank Seidel
- * - Minor cleanups
- * - theoretical multicard support
- *
- * Version 2.1
- * 03-July-2006 Paul Hardwick
- *
- * - Stability Improvements. Incorporated spinlock wraps patch.
- * - Updated for newer 2.6.14+ kernels (tty_buffer_request_room)
- * - using __devexit macro for tty
- *
- *
- * Version 2.0
- * 08-feb-2006 15:34:10:Ulf
- *
- * -Fixed issue when not waking up line disipine layer, could probably result
- *  in better uplink performance for 2.4.
- *
- * -Fixed issue with big endian during initalization, now proper toggle flags
- *  are handled between preloader and maincode.
- *
- * -Fixed flow control issue.
- *
- * -Added support for setting DTR.
- *
- * -For 2.4 kernels, removing temporary buffer that's not needed.
- *
- * -Reading CTS only for modem port (only port that supports it).
- *
- * -Return 0 in write_room instead of netative value, it's not handled in
- *  upper layer.
- *
- * --------------------------------------------------------------------------
- * Version 1.0
- *
- * First version of driver, only tested with card of type F32_2.
- * Works fine with 2.4 and 2.6 kernels.
- * Driver also support big endian architecture.
- */
-
 /* Enable this to have a lot of debug printouts */
 #define DEBUG
 
@@ -143,8 +89,9 @@ do {                                                         \
 /* Do we need this settable at runtime? */
 static int debug = NOZOMI_DEBUG_LEVEL;
 
-#define D(lvl, args...)  do {if (lvl & debug) NFO(KERN_DEBUG, ##args); } \
-                               while (0)
+#define D(lvl, args...)  do \
+                       {if (lvl & debug) NFO(KERN_DEBUG, ##args); } \
+                       while (0)
 #define D_(lvl, args...) D(lvl, ##args)
 
 /* These printouts are always printed */
@@ -273,13 +220,13 @@ enum port_type {
 /* Big endian */
 
 struct toggles {
-       unsigned enabled:5;     /*
+       unsigned int enabled:5; /*
                                 * Toggle fields are valid if enabled is 0,
                                 * else A-channels must always be used.
                                 */
-       unsigned diag_dl:1;
-       unsigned mdm_dl:1;
-       unsigned mdm_ul:1;
+       unsigned int diag_dl:1;
+       unsigned int mdm_dl:1;
+       unsigned int mdm_ul:1;
 } __attribute__ ((packed));
 
 /* Configuration table to read at startup of card */
@@ -320,19 +267,19 @@ struct config_table {
 /* This stores all control downlink flags */
 struct ctrl_dl {
        u8 port;
-       unsigned reserved:4;
-       unsigned CTS:1;
-       unsigned RI:1;
-       unsigned DCD:1;
-       unsigned DSR:1;
+       unsigned int reserved:4;
+       unsigned int CTS:1;
+       unsigned int RI:1;
+       unsigned int DCD:1;
+       unsigned int DSR:1;
 } __attribute__ ((packed));
 
 /* This stores all control uplink flags */
 struct ctrl_ul {
        u8 port;
-       unsigned reserved:6;
-       unsigned RTS:1;
-       unsigned DTR:1;
+       unsigned int reserved:6;
+       unsigned int RTS:1;
+       unsigned int DTR:1;
 } __attribute__ ((packed));
 
 #else
@@ -340,10 +287,10 @@ struct ctrl_ul {
 
 /* This represents the toggle information */
 struct toggles {
-       unsigned mdm_ul:1;
-       unsigned mdm_dl:1;
-       unsigned diag_dl:1;
-       unsigned enabled:5;     /*
+       unsigned int mdm_ul:1;
+       unsigned int mdm_dl:1;
+       unsigned int diag_dl:1;
+       unsigned int enabled:5; /*
                                 * Toggle fields are valid if enabled is 0,
                                 * else A-channels must always be used.
                                 */
@@ -379,19 +326,19 @@ struct config_table {
 
 /* This stores all control downlink flags */
 struct ctrl_dl {
-       unsigned DSR:1;
-       unsigned DCD:1;
-       unsigned RI:1;
-       unsigned CTS:1;
-       unsigned reserverd:4;
+       unsigned int DSR:1;
+       unsigned int DCD:1;
+       unsigned int RI:1;
+       unsigned int CTS:1;
+       unsigned int reserverd:4;
        u8 port;
 } __attribute__ ((packed));
 
 /* This stores all control uplink flags */
 struct ctrl_ul {
-       unsigned DTR:1;
-       unsigned RTS:1;
-       unsigned reserved:6;
+       unsigned int DTR:1;
+       unsigned int RTS:1;
+       unsigned int reserved:6;
        u8 port;
 } __attribute__ ((packed));
 #endif
@@ -448,7 +395,7 @@ struct buffer {
 } __attribute__ ((packed));
 
 /*    Global variables */
-static struct pci_device_id nozomi_pci_tbl[] = {
+static const struct pci_device_id nozomi_pci_tbl[] __devinitconst = {
        {PCI_DEVICE(VENDOR1, DEVICE1)},
        {},
 };
@@ -524,12 +471,12 @@ out:
  * -Optimize
  * -Rewrite cleaner
  */
-static u32 write_mem32(void __iomem *mem_addr_start, u32 *buf,
+static u32 write_mem32(void __iomem *mem_addr_start, const u32 *buf,
                        u32 size_bytes)
 {
        u32 i = 0;
        u32 *ptr = (__force u32 *) mem_addr_start;
-       u16 *buf16;
+       const u16 *buf16;
 
        if (unlikely(!ptr || !buf))
                return 0;
@@ -537,7 +484,7 @@ static u32 write_mem32(void __iomem *mem_addr_start, u32 *buf,
        /* shortcut for extremely often used cases */
        switch (size_bytes) {
        case 2: /* 2 bytes */
-               buf16 = (u16 *) buf;
+               buf16 = (const u16 *)buf;
                writew(__cpu_to_le16(*buf16), (void __iomem *)ptr);
                return 2;
                break;
@@ -554,7 +501,7 @@ static u32 write_mem32(void __iomem *mem_addr_start, u32 *buf,
        while (i < size_bytes) {
                if (size_bytes - i == 2) {
                        /* 2 bytes */
-                       buf16 = (u16 *) buf;
+                       buf16 = (const u16 *)buf;
                        writew(__cpu_to_le16(*buf16), (void __iomem *)ptr);
                        i += 2;
                } else {
@@ -694,7 +641,7 @@ static void dump_table(const struct nozomi *dc)
           dc->config_table.ul_ctrl_len);
 }
 #else
-static __inline__ void dump_table(const struct nozomi *dc) { }
+static inline void dump_table(const struct nozomi *dc) { }
 #endif
 
 /*
@@ -776,8 +723,7 @@ static int nozomi_read_config_table(struct nozomi *dc)
 /* Enable uplink interrupts  */
 static void enable_transmit_ul(enum port_type port, struct nozomi *dc)
 {
-       u16 mask[NOZOMI_MAX_PORTS] = \
-                       {MDM_UL, DIAG_UL, APP1_UL, APP2_UL, CTRL_UL};
+       static const u16 mask[] = {MDM_UL, DIAG_UL, APP1_UL, APP2_UL, CTRL_UL};
 
        if (port < NOZOMI_MAX_PORTS) {
                dc->last_ier |= mask[port];
@@ -790,8 +736,8 @@ static void enable_transmit_ul(enum port_type port, struct nozomi *dc)
 /* Disable uplink interrupts  */
 static void disable_transmit_ul(enum port_type port, struct nozomi *dc)
 {
-       u16 mask[NOZOMI_MAX_PORTS] = \
-                       {~MDM_UL, ~DIAG_UL, ~APP1_UL, ~APP2_UL, ~CTRL_UL};
+       static const u16 mask[] =
+               {~MDM_UL, ~DIAG_UL, ~APP1_UL, ~APP2_UL, ~CTRL_UL};
 
        if (port < NOZOMI_MAX_PORTS) {
                dc->last_ier &= mask[port];
@@ -804,8 +750,7 @@ static void disable_transmit_ul(enum port_type port, struct nozomi *dc)
 /* Enable downlink interrupts */
 static void enable_transmit_dl(enum port_type port, struct nozomi *dc)
 {
-       u16 mask[NOZOMI_MAX_PORTS] = \
-                       {MDM_DL, DIAG_DL, APP1_DL, APP2_DL, CTRL_DL};
+       static const u16 mask[] = {MDM_DL, DIAG_DL, APP1_DL, APP2_DL, CTRL_DL};
 
        if (port < NOZOMI_MAX_PORTS) {
                dc->last_ier |= mask[port];
@@ -818,8 +763,8 @@ static void enable_transmit_dl(enum port_type port, struct nozomi *dc)
 /* Disable downlink interrupts */
 static void disable_transmit_dl(enum port_type port, struct nozomi *dc)
 {
-       u16 mask[NOZOMI_MAX_PORTS] = \
-                       {~MDM_DL, ~DIAG_DL, ~APP1_DL, ~APP2_DL, ~CTRL_DL};
+       static const u16 mask[] =
+               {~MDM_DL, ~DIAG_DL, ~APP1_DL, ~APP2_DL, ~CTRL_DL};
 
        if (port < NOZOMI_MAX_PORTS) {
                dc->last_ier &= mask[port];
@@ -833,13 +778,13 @@ static void disable_transmit_dl(enum port_type port, struct nozomi *dc)
  * Return 1 - send buffer to card and ack.
  * Return 0 - don't ack, don't send buffer to card.
  */
-static int send_data(enum port_type index, struct nozomi *dc)
+static int send_data(enum port_type index, const struct nozomi *dc)
 {
        u32 size = 0;
-       struct port *port = &dc->port[index];
-       u8 toggle = port->toggle_ul;
+       const struct port *port = &dc->port[index];
+       const u8 toggle = port->toggle_ul;
        void __iomem *addr = port->ul_addr[toggle];
-       u32 ul_size = port->ul_size[toggle];
+       const u32 ul_size = port->ul_size[toggle];
        struct tty_struct *tty = port->tty;
 
        /* Get data from tty and place in buf for now */
@@ -1102,7 +1047,7 @@ static int send_flow_control(struct nozomi *dc)
 }
 
 /*
- * Handle donlink data, ports that are handled are modem and diagnostics
+ * Handle downlink data, ports that are handled are modem and diagnostics
  * Return 1 - ok
  * Return 0 - toggle fields are out of sync
  */
@@ -1359,20 +1304,20 @@ static void nozomi_setup_private_data(struct nozomi *dc)
 static ssize_t card_type_show(struct device *dev, struct device_attribute *attr,
                          char *buf)
 {
-       struct nozomi *dc = pci_get_drvdata(to_pci_dev(dev));
+       const struct nozomi *dc = pci_get_drvdata(to_pci_dev(dev));
 
        return sprintf(buf, "%d\n", dc->card_type);
 }
-static DEVICE_ATTR(card_type, 0444, card_type_show, NULL);
+static DEVICE_ATTR(card_type, S_IRUGO, card_type_show, NULL);
 
 static ssize_t open_ttys_show(struct device *dev, struct device_attribute *attr,
                          char *buf)
 {
-       struct nozomi *dc = pci_get_drvdata(to_pci_dev(dev));
+       const struct nozomi *dc = pci_get_drvdata(to_pci_dev(dev));
 
        return sprintf(buf, "%u\n", dc->open_ttys);
 }
-static DEVICE_ATTR(open_ttys, 0444, open_ttys_show, NULL);
+static DEVICE_ATTR(open_ttys, S_IRUGO, open_ttys_show, NULL);
 
 static void make_sysfs_files(struct nozomi *dc)
 {
@@ -1735,7 +1680,7 @@ static int ntty_write_room(struct tty_struct *tty)
 {
        struct port *port = tty->driver_data;
        int room = 0;
-       struct nozomi *dc = get_dc_by_tty(tty);
+       const struct nozomi *dc = get_dc_by_tty(tty);
 
        if (!dc || !port)
                return 0;
@@ -1755,9 +1700,9 @@ exit:
 /* Gets io control parameters */
 static int ntty_tiocmget(struct tty_struct *tty, struct file *file)
 {
-       struct port *port = tty->driver_data;
-       struct ctrl_dl *ctrl_dl = &port->ctrl_dl;
-       struct ctrl_ul *ctrl_ul = &port->ctrl_ul;
+       const struct port *port = tty->driver_data;
+       const struct ctrl_dl *ctrl_dl = &port->ctrl_dl;
+       const struct ctrl_ul *ctrl_ul = &port->ctrl_ul;
 
        return  (ctrl_ul->RTS ? TIOCM_RTS : 0) |
                (ctrl_ul->DTR ? TIOCM_DTR : 0) |
@@ -1787,7 +1732,7 @@ static int ntty_tiocmset(struct tty_struct *tty, struct file *file,
 static int ntty_cflags_changed(struct port *port, unsigned long flags,
                struct async_icount *cprev)
 {
-       struct async_icount cnow = port->tty_icount;
+       const struct async_icount cnow = port->tty_icount;
        int ret;
 
        ret =   ((flags & TIOCM_RNG) && (cnow.rng != cprev->rng)) ||
@@ -1802,7 +1747,7 @@ static int ntty_cflags_changed(struct port *port, unsigned long flags,
 
 static int ntty_ioctl_tiocgicount(struct port *port, void __user *argp)
 {
-       struct async_icount cnow = port->tty_icount;
+       const struct async_icount cnow = port->tty_icount;
        struct serial_icounter_struct icount;
 
        icount.cts = cnow.cts;
@@ -1882,7 +1827,10 @@ static void ntty_throttle(struct tty_struct *tty)
 /* just to discard single character writes */
 static void ntty_put_char(struct tty_struct *tty, unsigned char c)
 {
-       /* FIXME !!! */
+       /*
+        * card does not react correct when we write single chars
+        * to the card, so we discard them
+        */
        DBG2("PUT CHAR Function: %c", c);
 }
 
@@ -1910,7 +1858,7 @@ exit_in_buffer:
        return rval;
 }
 
-static struct tty_operations tty_ops = {
+static const struct tty_operations tty_ops = {
        .ioctl = ntty_ioctl,
        .open = ntty_open,
        .close = ntty_close,
index 02518da6a386a934ef7c3af885c4630e3c46741f..454d7324ba40b19ef3ce1396b3f09dfb0aeaff9e 100644 (file)
@@ -308,7 +308,8 @@ static unsigned int calc_baudv(unsigned char fidi)
        return (wcrcf / wbrcf);
 }
 
-static unsigned short io_read_num_rec_bytes(ioaddr_t iobase, unsigned short *s)
+static unsigned short io_read_num_rec_bytes(unsigned int iobase,
+                                           unsigned short *s)
 {
        unsigned short tmp;
 
@@ -426,7 +427,7 @@ static struct card_fixup card_fixups[] = {
 static void set_cardparameter(struct cm4000_dev *dev)
 {
        int i;
-       ioaddr_t iobase = dev->p_dev->io.BasePort1;
+       unsigned int iobase = dev->p_dev->io.BasePort1;
        u_int8_t stopbits = 0x02; /* ISO default */
 
        DEBUGP(3, dev, "-> set_cardparameter\n");
@@ -459,7 +460,7 @@ static int set_protocol(struct cm4000_dev *dev, struct ptsreq *ptsreq)
        unsigned short num_bytes_read;
        unsigned char pts_reply[4];
        ssize_t rc;
-       ioaddr_t iobase = dev->p_dev->io.BasePort1;
+       unsigned int iobase = dev->p_dev->io.BasePort1;
 
        rc = 0;
 
@@ -610,7 +611,7 @@ exit_setprotocol:
        return rc;
 }
 
-static int io_detect_cm4000(ioaddr_t iobase, struct cm4000_dev *dev)
+static int io_detect_cm4000(unsigned int iobase, struct cm4000_dev *dev)
 {
 
        /* note: statemachine is assumed to be reset */
@@ -671,7 +672,7 @@ static void terminate_monitor(struct cm4000_dev *dev)
 static void monitor_card(unsigned long p)
 {
        struct cm4000_dev *dev = (struct cm4000_dev *) p;
-       ioaddr_t iobase = dev->p_dev->io.BasePort1;
+       unsigned int iobase = dev->p_dev->io.BasePort1;
        unsigned short s;
        struct ptsreq ptsreq;
        int i, atrc;
@@ -933,7 +934,7 @@ static ssize_t cmm_read(struct file *filp, __user char *buf, size_t count,
                        loff_t *ppos)
 {
        struct cm4000_dev *dev = filp->private_data;
-       ioaddr_t iobase = dev->p_dev->io.BasePort1;
+       unsigned int iobase = dev->p_dev->io.BasePort1;
        ssize_t rc;
        int i, j, k;
 
@@ -1054,7 +1055,7 @@ static ssize_t cmm_write(struct file *filp, const char __user *buf,
                         size_t count, loff_t *ppos)
 {
        struct cm4000_dev *dev = (struct cm4000_dev *) filp->private_data;
-       ioaddr_t iobase = dev->p_dev->io.BasePort1;
+       unsigned int iobase = dev->p_dev->io.BasePort1;
        unsigned short s;
        unsigned char tmp;
        unsigned char infolen;
@@ -1408,7 +1409,7 @@ static int cmm_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
                     unsigned long arg)
 {
        struct cm4000_dev *dev = filp->private_data;
-       ioaddr_t iobase = dev->p_dev->io.BasePort1;
+       unsigned int iobase = dev->p_dev->io.BasePort1;
        struct pcmcia_device *link;
        int size;
        int rc;
index 5fee05661823766a0ed5651724d81fad0ee951b8..c511a831f0c053e60220d39c1f45b94ee3a93cb7 100644 (file)
@@ -667,8 +667,6 @@ void add_disk_randomness(struct gendisk *disk)
        add_timer_randomness(disk->random,
                             0x100 + MKDEV(disk->major, disk->first_minor));
 }
-
-EXPORT_SYMBOL(add_disk_randomness);
 #endif
 
 #define EXTRACT_SIZE 10
index 905d1f51a7bfd7db75f90b9de128f13fd5142ac8..d010ed95ed3b1681bed5cea128625bbaea61a71b 100644 (file)
@@ -1544,7 +1544,7 @@ static void mgsl_isr_receive_data( struct mgsl_struct *info )
 
 /* mgsl_isr_misc()
  * 
- *     Service a miscellaneos interrupt source.
+ *     Service a miscellaneous interrupt source.
  *     
  * Arguments:          info            pointer to device extension (instance data)
  * Return Value:       None
index 5422f999636fffff6e499a9b7242d52f9e733fa9..ce5ebe3b168ffe0cb59f83484370a2bf6d957602 100644 (file)
@@ -505,7 +505,7 @@ static int __init toshiba_init(void)
        if (tosh_probe())
                return -ENODEV;
 
-       printk(KERN_INFO "Toshiba System Managment Mode driver v" TOSH_VERSION "\n");
+       printk(KERN_INFO "Toshiba System Management Mode driver v" TOSH_VERSION "\n");
 
        /* set the port to use for Fn status if not specified as a parameter */
        if (tosh_fn==0x00)
index d222012c1b0ca039a4c41c6f7a450a4fbe2ba8a0..bacded0eefabcb76aab68de33bea773bd4e8e21f 100644 (file)
@@ -73,6 +73,7 @@ static void tty_audit_buf_put(struct tty_audit_buf *buf)
  *     @tsk with @loginuid.  @buf->mutex must be locked.
  */
 static void tty_audit_buf_push(struct task_struct *tsk, uid_t loginuid,
+                              unsigned int sessionid,
                               struct tty_audit_buf *buf)
 {
        struct audit_buffer *ab;
@@ -85,9 +86,9 @@ static void tty_audit_buf_push(struct task_struct *tsk, uid_t loginuid,
        if (ab) {
                char name[sizeof(tsk->comm)];
 
-               audit_log_format(ab, "tty pid=%u uid=%u auid=%u major=%d "
-                                "minor=%d comm=", tsk->pid, tsk->uid,
-                                loginuid, buf->major, buf->minor);
+               audit_log_format(ab, "tty pid=%u uid=%u auid=%u ses=%u "
+                                "major=%d minor=%d comm=", tsk->pid, tsk->uid,
+                                loginuid, sessionid, buf->major, buf->minor);
                get_task_comm(name, tsk);
                audit_log_untrustedstring(ab, name);
                audit_log_format(ab, " data=");
@@ -105,8 +106,9 @@ static void tty_audit_buf_push(struct task_struct *tsk, uid_t loginuid,
  */
 static void tty_audit_buf_push_current(struct tty_audit_buf *buf)
 {
-       tty_audit_buf_push(current, audit_get_loginuid(current->audit_context),
-                          buf);
+       uid_t auid = audit_get_loginuid(current);
+       unsigned int sessionid = audit_get_sessionid(current);
+       tty_audit_buf_push(current, auid, sessionid, buf);
 }
 
 /**
@@ -152,6 +154,11 @@ void tty_audit_fork(struct signal_struct *sig)
 void tty_audit_push_task(struct task_struct *tsk, uid_t loginuid)
 {
        struct tty_audit_buf *buf;
+       /* FIXME I think this is correct.  Check against netlink once that is
+        * I really need to read this code more closely.  But that's for
+        * another patch.
+        */
+       unsigned int sessionid = audit_get_sessionid(tsk);
 
        spin_lock_irq(&tsk->sighand->siglock);
        buf = tsk->signal->tty_audit_buf;
@@ -162,7 +169,7 @@ void tty_audit_push_task(struct task_struct *tsk, uid_t loginuid)
                return;
 
        mutex_lock(&buf->mutex);
-       tty_audit_buf_push(tsk, loginuid, buf);
+       tty_audit_buf_push(tsk, loginuid, sessionid, buf);
        mutex_unlock(&buf->mutex);
 
        tty_audit_buf_put(buf);
index e34da5c971966fc87d68b40588ea4f22e3f94189..dc17fe3a88bc48f2813ad5c3e5dd27efd00ff7d3 100644 (file)
@@ -158,13 +158,13 @@ static int __devinit virtcons_probe(struct virtio_device *dev)
        /* Find the input queue. */
        /* FIXME: This is why we want to wean off hvc: we do nothing
         * when input comes in. */
-       in_vq = vdev->config->find_vq(vdev, NULL);
+       in_vq = vdev->config->find_vq(vdev, 0, NULL);
        if (IS_ERR(in_vq)) {
                err = PTR_ERR(in_vq);
                goto free;
        }
 
-       out_vq = vdev->config->find_vq(vdev, NULL);
+       out_vq = vdev->config->find_vq(vdev, 1, NULL);
        if (IS_ERR(out_vq)) {
                err = PTR_ERR(out_vq);
                goto free_in_vq;
index d2fabe7863a96345e096f5a644c111436a492819..2a98d99cbd46075707c15572dff6ace4e6c602c3 100644 (file)
@@ -12,7 +12,7 @@
 #include <linux/mutex.h>
 #include <linux/sched.h>
 #include <linux/notifier.h>
-#include <linux/latency.h>
+#include <linux/pm_qos_params.h>
 #include <linux/cpu.h>
 #include <linux/cpuidle.h>
 
@@ -265,7 +265,10 @@ static struct notifier_block cpuidle_latency_notifier = {
        .notifier_call = cpuidle_latency_notify,
 };
 
-#define latency_notifier_init(x) do { register_latency_notifier(x); } while (0)
+static inline void latency_notifier_init(struct notifier_block *n)
+{
+       pm_qos_add_notifier(PM_QOS_CPU_DMA_LATENCY, n);
+}
 
 #else /* CONFIG_SMP */
 
index eb666ecae7c913a769529a9b0debef857947103d..ba7b9a6b17a13678896bd1390b1d4823504b641a 100644 (file)
@@ -14,7 +14,7 @@
 
 #include <linux/kernel.h>
 #include <linux/cpuidle.h>
-#include <linux/latency.h>
+#include <linux/pm_qos_params.h>
 #include <linux/moduleparam.h>
 #include <linux/jiffies.h>
 
@@ -81,7 +81,8 @@ static int ladder_select_state(struct cpuidle_device *dev)
        /* consider promotion */
        if (last_idx < dev->state_count - 1 &&
            last_residency > last_state->threshold.promotion_time &&
-           dev->states[last_idx + 1].exit_latency <= system_latency_constraint()) {
+           dev->states[last_idx + 1].exit_latency <=
+                       pm_qos_requirement(PM_QOS_CPU_DMA_LATENCY)) {
                last_state->stats.promotion_count++;
                last_state->stats.demotion_count = 0;
                if (last_state->stats.promotion_count >= last_state->threshold.promotion_count) {
index 299d45c3bdd28c6f6111dde39080c76c51dfb172..78d77c5dc35c3ec00b261fa39a7e3aa89271a957 100644 (file)
@@ -8,7 +8,7 @@
 
 #include <linux/kernel.h>
 #include <linux/cpuidle.h>
-#include <linux/latency.h>
+#include <linux/pm_qos_params.h>
 #include <linux/time.h>
 #include <linux/ktime.h>
 #include <linux/hrtimer.h>
@@ -48,7 +48,7 @@ static int menu_select(struct cpuidle_device *dev)
                        break;
                if (s->target_residency > data->predicted_us)
                        break;
-               if (s->exit_latency > system_latency_constraint())
+               if (s->exit_latency > pm_qos_requirement(PM_QOS_CPU_DMA_LATENCY))
                        break;
        }
 
index e4c48e329367d93617635e65a671ffb2816a47f7..8cd8507b1a8ae4e76662101b4a55c513ec91e14e 100644 (file)
 #include <linux/dio.h>
 
 
-       /**
-        *  dio_match_device - Tell if a DIO device structure has a matching
-        *                     DIO device id structure
-        *  @ids: array of DIO device id structures to search in
-        *  @dev: the DIO device structure to match against
-        *
-        *  Used by a driver to check whether a DIO device present in the
-        *  system is in its list of supported devices. Returns the matching
-        *  dio_device_id structure or %NULL if there is no match.
-        */
+/**
+ *  dio_match_device - Tell if a DIO device structure has a matching DIO device id structure
+ *  @ids: array of DIO device id structures to search in
+ *  @d: the DIO device structure to match against
+ *
+ *  Used by a driver to check whether a DIO device present in the
+ *  system is in its list of supported devices. Returns the matching
+ *  dio_device_id structure or %NULL if there is no match.
+ */
 
 const struct dio_device_id *
 dio_match_device(const struct dio_device_id *ids,
@@ -66,13 +65,13 @@ static int dio_device_probe(struct device *dev)
 }
 
 
-       /**
       *  dio_register_driver - register a new DIO driver
       *  @drv: the driver structure to register
       *
       *  Adds the driver structure to the list of registered drivers
       *  Returns zero or a negative error value.
       */
+/**
+ *  dio_register_driver - register a new DIO driver
+ *  @drv: the driver structure to register
+ *
+ *  Adds the driver structure to the list of registered drivers
+ *  Returns zero or a negative error value.
+ */
 
 int dio_register_driver(struct dio_driver *drv)
 {
@@ -85,15 +84,15 @@ int dio_register_driver(struct dio_driver *drv)
 }
 
 
-       /**
       *  dio_unregister_driver - unregister a DIO driver
       *  @drv: the driver structure to unregister
       *
       *  Deletes the driver structure from the list of registered DIO drivers,
       *  gives it a chance to clean up by calling its remove() function for
       *  each device it was responsible for, and marks those devices as
       *  driverless.
       */
+/**
+ *  dio_unregister_driver - unregister a DIO driver
+ *  @drv: the driver structure to unregister
+ *
+ *  Deletes the driver structure from the list of registered DIO drivers,
+ *  gives it a chance to clean up by calling its remove() function for
+ *  each device it was responsible for, and marks those devices as
+ *  driverless.
+ */
 
 void dio_unregister_driver(struct dio_driver *drv)
 {
@@ -101,16 +100,15 @@ void dio_unregister_driver(struct dio_driver *drv)
 }
 
 
-       /**
-        *  dio_bus_match - Tell if a DIO device structure has a matching DIO
-        *                  device id structure
-        *  @ids: array of DIO device id structures to search in
-        *  @dev: the DIO device structure to match against
-        *
-        *  Used by a driver to check whether a DIO device present in the
-        *  system is in its list of supported devices. Returns the matching
-        *  dio_device_id structure or %NULL if there is no match.
-        */
+/**
+ *  dio_bus_match - Tell if a DIO device structure has a matching DIO device id structure
+ *  @dev: the DIO device structure to match against
+ *  @drv: the &device_driver that points to the array of DIO device id structures to search
+ *
+ *  Used by a driver to check whether a DIO device present in the
+ *  system is in its list of supported devices. Returns the matching
+ *  dio_device_id structure or %NULL if there is no match.
+ */
 
 static int dio_bus_match(struct device *dev, struct device_driver *drv)
 {
index 17502d6efae788c2bb614f3833a550de9059a59c..07f274f853d95f5dc0cf8b671e989fca3a65742f 100644 (file)
@@ -88,8 +88,6 @@ static struct dioname names[] =
 #undef DIONAME
 #undef DIOFBNAME
 
-#define NUMNAMES (sizeof(names) / sizeof(struct dioname))
-
 static const char *unknowndioname 
         = "unknown DIO board -- please email <linux-m68k@lists.linux-m68k.org>!";
 
@@ -97,7 +95,7 @@ static const char *dio_getname(int id)
 {
         /* return pointer to a constant string describing the board with given ID */
        unsigned int i;
-        for (i = 0; i < NUMNAMES; i++)
+       for (i = 0; i < ARRAY_SIZE(names); i++)
                 if (names[i].id == id) 
                         return names[i].name;
 
index 5dee9f50414bee396fde63895efa6ddcf7f0841c..e0b47b74ec4581aa60dda973c612bddc6c5738ca 100644 (file)
@@ -73,7 +73,7 @@ EXPORT_SYMBOL_GPL(edac_pci_alloc_ctl_info);
  *
  *     Last action on the pci control structure.
  *
- *     call the remove sysfs informaton, which will unregister
+ *     call the remove sysfs information, which will unregister
  *     this control struct's kobj. When that kobj's ref count
  *     goes to zero, its release function will be call and then
  *     kfree() the memory.
index a1f24c42d5ff45176984727961c245df1d0908fc..5a852017c17a70dc87d1bd16c7e83587b8b7a1c7 100644 (file)
@@ -351,7 +351,7 @@ struct i5000_pvt {
        u16 b1_ambpresent0;     /* Branch 1, Channel 8 */
        u16 b1_ambpresent1;     /* Branch 1, Channel 1 */
 
-       /* DIMM infomation matrix, allocating architecture maximums */
+       /* DIMM information matrix, allocating architecture maximums */
        struct i5000_dimm_info dimm_info[MAX_CSROWS][MAX_CHANNELS];
 
        /* Actual values for this controller */
index 60f1a8924a953ac14c37068d286ebe2cf45959a5..7e73cbaa4121047ffe6eb7c5f137357e0739c58e 100644 (file)
@@ -206,12 +206,13 @@ fill_bus_reset_event(struct fw_cdev_event_bus_reset *event,
 
        event->closure       = client->bus_reset_closure;
        event->type          = FW_CDEV_EVENT_BUS_RESET;
+       event->generation    = client->device->generation;
+       smp_rmb();           /* node_id must not be older than generation */
        event->node_id       = client->device->node_id;
        event->local_node_id = card->local_node->node_id;
        event->bm_node_id    = 0; /* FIXME: We don't track the BM. */
        event->irm_node_id   = card->irm_node->node_id;
        event->root_node_id  = card->root_node->node_id;
-       event->generation    = card->generation;
 }
 
 static void
index 56681b3b297baa43ed5b756151933b9a57f05f2c..de9066e69adfbeea440d31cec1c0945f337db728 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/idr.h>
 #include <linux/rwsem.h>
 #include <asm/semaphore.h>
+#include <asm/system.h>
 #include <linux/ctype.h>
 #include "fw-transaction.h"
 #include "fw-topology.h"
@@ -182,9 +183,14 @@ static void fw_device_release(struct device *dev)
 
 int fw_device_enable_phys_dma(struct fw_device *device)
 {
+       int generation = device->generation;
+
+       /* device->node_id, accessed below, must not be older than generation */
+       smp_rmb();
+
        return device->card->driver->enable_phys_dma(device->card,
                                                     device->node_id,
-                                                    device->generation);
+                                                    generation);
 }
 EXPORT_SYMBOL(fw_device_enable_phys_dma);
 
@@ -384,17 +390,21 @@ complete_transaction(struct fw_card *card, int rcode,
        complete(&callback_data->done);
 }
 
-static int read_rom(struct fw_device *device, int index, u32 * data)
+static int
+read_rom(struct fw_device *device, int generation, int index, u32 *data)
 {
        struct read_quadlet_callback_data callback_data;
        struct fw_transaction t;
        u64 offset;
 
+       /* device->node_id, accessed below, must not be older than generation */
+       smp_rmb();
+
        init_completion(&callback_data.done);
 
        offset = 0xfffff0000400ULL + index * 4;
        fw_send_request(device->card, &t, TCODE_READ_QUADLET_REQUEST,
-                       device->node_id, device->generation, device->max_speed,
+                       device->node_id, generation, device->max_speed,
                        offset, NULL, 4, complete_transaction, &callback_data);
 
        wait_for_completion(&callback_data.done);
@@ -404,7 +414,14 @@ static int read_rom(struct fw_device *device, int index, u32 * data)
        return callback_data.rcode;
 }
 
-static int read_bus_info_block(struct fw_device *device)
+/*
+ * Read the bus info block, perform a speed probe, and read all of the rest of
+ * the config ROM.  We do all this with a cached bus generation.  If the bus
+ * generation changes under us, read_bus_info_block will fail and get retried.
+ * It's better to start all over in this case because the node from which we
+ * are reading the ROM may have changed the ROM during the reset.
+ */
+static int read_bus_info_block(struct fw_device *device, int generation)
 {
        static u32 rom[256];
        u32 stack[16], sp, key;
@@ -414,7 +431,7 @@ static int read_bus_info_block(struct fw_device *device)
 
        /* First read the bus info block. */
        for (i = 0; i < 5; i++) {
-               if (read_rom(device, i, &rom[i]) != RCODE_COMPLETE)
+               if (read_rom(device, generation, i, &rom[i]) != RCODE_COMPLETE)
                        return -1;
                /*
                 * As per IEEE1212 7.2, during power-up, devices can
@@ -449,7 +466,8 @@ static int read_bus_info_block(struct fw_device *device)
                        device->max_speed = device->card->link_speed;
 
                while (device->max_speed > SCODE_100) {
-                       if (read_rom(device, 0, &dummy) == RCODE_COMPLETE)
+                       if (read_rom(device, generation, 0, &dummy) ==
+                           RCODE_COMPLETE)
                                break;
                        device->max_speed--;
                }
@@ -482,7 +500,7 @@ static int read_bus_info_block(struct fw_device *device)
                        return -1;
 
                /* Read header quadlet for the block to get the length. */
-               if (read_rom(device, i, &rom[i]) != RCODE_COMPLETE)
+               if (read_rom(device, generation, i, &rom[i]) != RCODE_COMPLETE)
                        return -1;
                end = i + (rom[i] >> 16) + 1;
                i++;
@@ -501,7 +519,8 @@ static int read_bus_info_block(struct fw_device *device)
                 * it references another block, and push it in that case.
                 */
                while (i < end) {
-                       if (read_rom(device, i, &rom[i]) != RCODE_COMPLETE)
+                       if (read_rom(device, generation, i, &rom[i]) !=
+                           RCODE_COMPLETE)
                                return -1;
                        if ((key >> 30) == 3 && (rom[i] >> 30) > 1 &&
                            sp < ARRAY_SIZE(stack))
@@ -648,7 +667,7 @@ static void fw_device_init(struct work_struct *work)
         * device.
         */
 
-       if (read_bus_info_block(device) < 0) {
+       if (read_bus_info_block(device, device->generation) < 0) {
                if (device->config_rom_retries < MAX_RETRIES) {
                        device->config_rom_retries++;
                        schedule_delayed_work(&device->work, RETRY_DELAY);
@@ -801,6 +820,7 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event)
 
                device = node->data;
                device->node_id = node->node_id;
+               smp_wmb();  /* update node_id before generation */
                device->generation = card->generation;
                if (atomic_read(&device->state) == FW_DEVICE_RUNNING) {
                        PREPARE_DELAYED_WORK(&device->work, fw_device_update);
index 894d4a92a18ec9186787e391594f5c2e5c0c2c40..0854fe2bc11085943d0b7edcdef5884d8996c60c 100644 (file)
@@ -35,6 +35,18 @@ struct fw_attribute_group {
        struct attribute *attrs[11];
 };
 
+/*
+ * 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.
+ */
 struct fw_device {
        atomic_t state;
        struct fw_node *node;
index 436a855a4c60700e2cc64f22446a57daf78ec504..7ebad3c14cb80bbd62b930551494400c901f81f0 100644 (file)
@@ -98,17 +98,48 @@ struct context;
 typedef int (*descriptor_callback_t)(struct context *ctx,
                                     struct descriptor *d,
                                     struct descriptor *last);
+
+/*
+ * A buffer that contains a block of DMA-able coherent memory used for
+ * storing a portion of a DMA descriptor program.
+ */
+struct descriptor_buffer {
+       struct list_head list;
+       dma_addr_t buffer_bus;
+       size_t buffer_size;
+       size_t used;
+       struct descriptor buffer[0];
+};
+
 struct context {
        struct fw_ohci *ohci;
        u32 regs;
+       int total_allocation;
 
-       struct descriptor *buffer;
-       dma_addr_t buffer_bus;
-       size_t buffer_size;
-       struct descriptor *head_descriptor;
-       struct descriptor *tail_descriptor;
-       struct descriptor *tail_descriptor_last;
-       struct descriptor *prev_descriptor;
+       /*
+        * List of page-sized buffers for storing DMA descriptors.
+        * Head of list contains buffers in use and tail of list contains
+        * free buffers.
+        */
+       struct list_head buffer_list;
+
+       /*
+        * Pointer to a buffer inside buffer_list that contains the tail
+        * end of the current DMA program.
+        */
+       struct descriptor_buffer *buffer_tail;
+
+       /*
+        * The descriptor containing the branch address of the first
+        * descriptor that has not yet been filled by the device.
+        */
+       struct descriptor *last;
+
+       /*
+        * The last descriptor in the DMA program.  It contains the branch
+        * address that must be updated upon appending a new descriptor.
+        */
+       struct descriptor *prev;
 
        descriptor_callback_t callback;
 
@@ -125,6 +156,7 @@ struct context {
 struct iso_context {
        struct fw_iso_context base;
        struct context context;
+       int excess_bytes;
        void *header;
        size_t header_length;
 };
@@ -197,8 +229,6 @@ static inline struct fw_ohci *fw_ohci(struct fw_card *card)
 #define SELF_ID_BUF_SIZE               0x800
 #define OHCI_TCODE_PHY_PACKET          0x0e
 #define OHCI_VERSION_1_1               0x010010
-#define ISO_BUFFER_SIZE                        (64 * 1024)
-#define AT_BUFFER_SIZE                 4096
 
 static char ohci_driver_name[] = KBUILD_MODNAME;
 
@@ -455,71 +485,108 @@ find_branch_descriptor(struct descriptor *d, int z)
 static void context_tasklet(unsigned long data)
 {
        struct context *ctx = (struct context *) data;
-       struct fw_ohci *ohci = ctx->ohci;
        struct descriptor *d, *last;
        u32 address;
        int z;
+       struct descriptor_buffer *desc;
 
-       dma_sync_single_for_cpu(ohci->card.device, ctx->buffer_bus,
-                               ctx->buffer_size, DMA_TO_DEVICE);
-
-       d    = ctx->tail_descriptor;
-       last = ctx->tail_descriptor_last;
-
+       desc = list_entry(ctx->buffer_list.next,
+                       struct descriptor_buffer, list);
+       last = ctx->last;
        while (last->branch_address != 0) {
+               struct descriptor_buffer *old_desc = desc;
                address = le32_to_cpu(last->branch_address);
                z = address & 0xf;
-               d = ctx->buffer + (address - ctx->buffer_bus) / sizeof(*d);
+               address &= ~0xf;
+
+               /* If the branch address points to a buffer outside of the
+                * current buffer, advance to the next buffer. */
+               if (address < desc->buffer_bus ||
+                               address >= desc->buffer_bus + desc->used)
+                       desc = list_entry(desc->list.next,
+                                       struct descriptor_buffer, list);
+               d = desc->buffer + (address - desc->buffer_bus) / sizeof(*d);
                last = find_branch_descriptor(d, z);
 
                if (!ctx->callback(ctx, d, last))
                        break;
 
-               ctx->tail_descriptor      = d;
-               ctx->tail_descriptor_last = last;
+               if (old_desc != desc) {
+                       /* If we've advanced to the next buffer, move the
+                        * previous buffer to the free list. */
+                       unsigned long flags;
+                       old_desc->used = 0;
+                       spin_lock_irqsave(&ctx->ohci->lock, flags);
+                       list_move_tail(&old_desc->list, &ctx->buffer_list);
+                       spin_unlock_irqrestore(&ctx->ohci->lock, flags);
+               }
+               ctx->last = last;
        }
 }
 
+/*
+ * Allocate a new buffer and add it to the list of free buffers for this
+ * context.  Must be called with ohci->lock held.
+ */
+static int
+context_add_buffer(struct context *ctx)
+{
+       struct descriptor_buffer *desc;
+       dma_addr_t bus_addr;
+       int offset;
+
+       /*
+        * 16MB of descriptors should be far more than enough for any DMA
+        * program.  This will catch run-away userspace or DoS attacks.
+        */
+       if (ctx->total_allocation >= 16*1024*1024)
+               return -ENOMEM;
+
+       desc = dma_alloc_coherent(ctx->ohci->card.device, PAGE_SIZE,
+                       &bus_addr, GFP_ATOMIC);
+       if (!desc)
+               return -ENOMEM;
+
+       offset = (void *)&desc->buffer - (void *)desc;
+       desc->buffer_size = PAGE_SIZE - offset;
+       desc->buffer_bus = bus_addr + offset;
+       desc->used = 0;
+
+       list_add_tail(&desc->list, &ctx->buffer_list);
+       ctx->total_allocation += PAGE_SIZE;
+
+       return 0;
+}
+
 static int
 context_init(struct context *ctx, struct fw_ohci *ohci,
-            size_t buffer_size, u32 regs,
-            descriptor_callback_t callback)
+            u32 regs, descriptor_callback_t callback)
 {
        ctx->ohci = ohci;
        ctx->regs = regs;
-       ctx->buffer_size = buffer_size;
-       ctx->buffer = kmalloc(buffer_size, GFP_KERNEL);
-       if (ctx->buffer == NULL)
+       ctx->total_allocation = 0;
+
+       INIT_LIST_HEAD(&ctx->buffer_list);
+       if (context_add_buffer(ctx) < 0)
                return -ENOMEM;
 
+       ctx->buffer_tail = list_entry(ctx->buffer_list.next,
+                       struct descriptor_buffer, list);
+
        tasklet_init(&ctx->tasklet, context_tasklet, (unsigned long)ctx);
        ctx->callback = callback;
 
-       ctx->buffer_bus =
-               dma_map_single(ohci->card.device, ctx->buffer,
-                              buffer_size, DMA_TO_DEVICE);
-       if (dma_mapping_error(ctx->buffer_bus)) {
-               kfree(ctx->buffer);
-               return -ENOMEM;
-       }
-
-       ctx->head_descriptor      = ctx->buffer;
-       ctx->prev_descriptor      = ctx->buffer;
-       ctx->tail_descriptor      = ctx->buffer;
-       ctx->tail_descriptor_last = ctx->buffer;
-
        /*
         * We put a dummy descriptor in the buffer that has a NULL
         * branch address and looks like it's been sent.  That way we
-        * have a descriptor to append DMA programs to.  Also, the
-        * ring buffer invariant is that it always has at least one
-        * element so that head == tail means buffer full.
+        * have a descriptor to append DMA programs to.
         */
-
-       memset(ctx->head_descriptor, 0, sizeof(*ctx->head_descriptor));
-       ctx->head_descriptor->control = cpu_to_le16(DESCRIPTOR_OUTPUT_LAST);
-       ctx->head_descriptor->transfer_status = cpu_to_le16(0x8011);
-       ctx->head_descriptor++;
+       memset(ctx->buffer_tail->buffer, 0, sizeof(*ctx->buffer_tail->buffer));
+       ctx->buffer_tail->buffer->control = cpu_to_le16(DESCRIPTOR_OUTPUT_LAST);
+       ctx->buffer_tail->buffer->transfer_status = cpu_to_le16(0x8011);
+       ctx->buffer_tail->used += sizeof(*ctx->buffer_tail->buffer);
+       ctx->last = ctx->buffer_tail->buffer;
+       ctx->prev = ctx->buffer_tail->buffer;
 
        return 0;
 }
@@ -528,35 +595,42 @@ static void
 context_release(struct context *ctx)
 {
        struct fw_card *card = &ctx->ohci->card;
+       struct descriptor_buffer *desc, *tmp;
 
-       dma_unmap_single(card->device, ctx->buffer_bus,
-                        ctx->buffer_size, DMA_TO_DEVICE);
-       kfree(ctx->buffer);
+       list_for_each_entry_safe(desc, tmp, &ctx->buffer_list, list)
+               dma_free_coherent(card->device, PAGE_SIZE, desc,
+                       desc->buffer_bus -
+                       ((void *)&desc->buffer - (void *)desc));
 }
 
+/* Must be called with ohci->lock held */
 static struct descriptor *
 context_get_descriptors(struct context *ctx, int z, dma_addr_t *d_bus)
 {
-       struct descriptor *d, *tail, *end;
-
-       d = ctx->head_descriptor;
-       tail = ctx->tail_descriptor;
-       end = ctx->buffer + ctx->buffer_size / sizeof(*d);
-
-       if (d + z <= tail) {
-               goto has_space;
-       } else if (d > tail && d + z <= end) {
-               goto has_space;
-       } else if (d > tail && ctx->buffer + z <= tail) {
-               d = ctx->buffer;
-               goto has_space;
-       }
+       struct descriptor *d = NULL;
+       struct descriptor_buffer *desc = ctx->buffer_tail;
+
+       if (z * sizeof(*d) > desc->buffer_size)
+               return NULL;
 
-       return NULL;
+       if (z * sizeof(*d) > desc->buffer_size - desc->used) {
+               /* No room for the descriptor in this buffer, so advance to the
+                * next one. */
+
+               if (desc->list.next == &ctx->buffer_list) {
+                       /* If there is no free buffer next in the list,
+                        * allocate one. */
+                       if (context_add_buffer(ctx) < 0)
+                               return NULL;
+               }
+               desc = list_entry(desc->list.next,
+                               struct descriptor_buffer, list);
+               ctx->buffer_tail = desc;
+       }
 
- has_space:
+       d = desc->buffer + desc->used / sizeof(*d);
        memset(d, 0, z * sizeof(*d));
-       *d_bus = ctx->buffer_bus + (d - ctx->buffer) * sizeof(*d);
+       *d_bus = desc->buffer_bus + desc->used;
 
        return d;
 }
@@ -566,7 +640,7 @@ static void context_run(struct context *ctx, u32 extra)
        struct fw_ohci *ohci = ctx->ohci;
 
        reg_write(ohci, COMMAND_PTR(ctx->regs),
-                 le32_to_cpu(ctx->tail_descriptor_last->branch_address));
+                 le32_to_cpu(ctx->last->branch_address));
        reg_write(ohci, CONTROL_CLEAR(ctx->regs), ~0);
        reg_write(ohci, CONTROL_SET(ctx->regs), CONTEXT_RUN | extra);
        flush_writes(ohci);
@@ -576,15 +650,13 @@ static void context_append(struct context *ctx,
                           struct descriptor *d, int z, int extra)
 {
        dma_addr_t d_bus;
+       struct descriptor_buffer *desc = ctx->buffer_tail;
 
-       d_bus = ctx->buffer_bus + (d - ctx->buffer) * sizeof(*d);
+       d_bus = desc->buffer_bus + (d - desc->buffer) * sizeof(*d);
 
-       ctx->head_descriptor = d + z + extra;
-       ctx->prev_descriptor->branch_address = cpu_to_le32(d_bus | z);
-       ctx->prev_descriptor = find_branch_descriptor(d, z);
-
-       dma_sync_single_for_device(ctx->ohci->card.device, ctx->buffer_bus,
-                                  ctx->buffer_size, DMA_TO_DEVICE);
+       desc->used += (z + extra) * sizeof(*d);
+       ctx->prev->branch_address = cpu_to_le32(d_bus | z);
+       ctx->prev = find_branch_descriptor(d, z);
 
        reg_write(ctx->ohci, CONTROL_SET(ctx->regs), CONTEXT_WAKE);
        flush_writes(ctx->ohci);
@@ -1078,6 +1150,13 @@ static irqreturn_t irq_handler(int irq, void *data)
        if (unlikely(event & OHCI1394_postedWriteErr))
                fw_error("PCI posted write error\n");
 
+       if (unlikely(event & OHCI1394_cycleTooLong)) {
+               if (printk_ratelimit())
+                       fw_notify("isochronous cycle too long\n");
+               reg_write(ohci, OHCI1394_LinkControlSet,
+                         OHCI1394_LinkControl_cycleMaster);
+       }
+
        if (event & OHCI1394_cycle64Seconds) {
                cycle_time = reg_read(ohci, OHCI1394_IsochronousCycleTimer);
                if ((cycle_time & 0x80000000) == 0)
@@ -1151,8 +1230,8 @@ static int ohci_enable(struct fw_card *card, u32 *config_rom, size_t length)
                  OHCI1394_RQPkt | OHCI1394_RSPkt |
                  OHCI1394_reqTxComplete | OHCI1394_respTxComplete |
                  OHCI1394_isochRx | OHCI1394_isochTx |
-                 OHCI1394_postedWriteErr | OHCI1394_cycle64Seconds |
-                 OHCI1394_masterIntEnable);
+                 OHCI1394_postedWriteErr | OHCI1394_cycleTooLong |
+                 OHCI1394_cycle64Seconds | OHCI1394_masterIntEnable);
 
        /* Activate link_on bit and contender bit in our self ID packets.*/
        if (ohci_update_phy_reg(card, 4, 0,
@@ -1408,9 +1487,13 @@ static int handle_ir_dualbuffer_packet(struct context *context,
        void *p, *end;
        int i;
 
-       if (db->first_res_count > 0 && db->second_res_count > 0)
-               /* This descriptor isn't done yet, stop iteration. */
-               return 0;
+       if (db->first_res_count > 0 && db->second_res_count > 0) {
+               if (ctx->excess_bytes <= le16_to_cpu(db->second_req_count)) {
+                       /* This descriptor isn't done yet, stop iteration. */
+                       return 0;
+               }
+               ctx->excess_bytes -= le16_to_cpu(db->second_req_count);
+       }
 
        header_length = le16_to_cpu(db->first_req_count) -
                le16_to_cpu(db->first_res_count);
@@ -1429,11 +1512,15 @@ static int handle_ir_dualbuffer_packet(struct context *context,
                *(u32 *) (ctx->header + i) = __swab32(*(u32 *) (p + 4));
                memcpy(ctx->header + i + 4, p + 8, ctx->base.header_size - 4);
                i += ctx->base.header_size;
+               ctx->excess_bytes +=
+                       (le32_to_cpu(*(u32 *)(p + 4)) >> 16) & 0xffff;
                p += ctx->base.header_size + 4;
        }
-
        ctx->header_length = i;
 
+       ctx->excess_bytes -= le16_to_cpu(db->second_req_count) -
+               le16_to_cpu(db->second_res_count);
+
        if (le16_to_cpu(db->control) & DESCRIPTOR_IRQ_ALWAYS) {
                ir_header = (__le32 *) (db + 1);
                ctx->base.callback(&ctx->base,
@@ -1452,24 +1539,24 @@ static int handle_ir_packet_per_buffer(struct context *context,
 {
        struct iso_context *ctx =
                container_of(context, struct iso_context, context);
-       struct descriptor *pd = d + 1;
+       struct descriptor *pd;
        __le32 *ir_header;
-       size_t header_length;
-       void *p, *end;
-       int i, z;
+       void *p;
+       int i;
 
-       if (pd->res_count == pd->req_count)
+       for (pd = d; pd <= last; pd++) {
+               if (pd->transfer_status)
+                       break;
+       }
+       if (pd > last)
                /* Descriptor(s) not done yet, stop iteration */
                return 0;
 
-       header_length = le16_to_cpu(d->req_count);
-
        i   = ctx->header_length;
-       z   = le32_to_cpu(pd->branch_address) & 0xf;
-       p   = d + z;
-       end = p + header_length;
+       p   = last + 1;
 
-       while (p < end && i + ctx->base.header_size <= PAGE_SIZE) {
+       if (ctx->base.header_size > 0 &&
+                       i + ctx->base.header_size <= PAGE_SIZE) {
                /*
                 * The iso header is byteswapped to little endian by
                 * the controller, but the remaining header quadlets
@@ -1478,14 +1565,11 @@ static int handle_ir_packet_per_buffer(struct context *context,
                 */
                *(u32 *) (ctx->header + i) = __swab32(*(u32 *) (p + 4));
                memcpy(ctx->header + i + 4, p + 8, ctx->base.header_size - 4);
-               i += ctx->base.header_size;
-               p += ctx->base.header_size + 4;
+               ctx->header_length += ctx->base.header_size;
        }
 
-       ctx->header_length = i;
-
-       if (le16_to_cpu(pd->control) & DESCRIPTOR_IRQ_ALWAYS) {
-               ir_header = (__le32 *) (d + z);
+       if (le16_to_cpu(last->control) & DESCRIPTOR_IRQ_ALWAYS) {
+               ir_header = (__le32 *) p;
                ctx->base.callback(&ctx->base,
                                   le32_to_cpu(ir_header[0]) & 0xffff,
                                   ctx->header_length, ctx->header,
@@ -1493,7 +1577,6 @@ static int handle_ir_packet_per_buffer(struct context *context,
                ctx->header_length = 0;
        }
 
-
        return 1;
 }
 
@@ -1559,8 +1642,7 @@ ohci_allocate_iso_context(struct fw_card *card, int type, size_t header_size)
        if (ctx->header == NULL)
                goto out;
 
-       retval = context_init(&ctx->context, ohci, ISO_BUFFER_SIZE,
-                             regs, callback);
+       retval = context_init(&ctx->context, ohci, regs, callback);
        if (retval < 0)
                goto out_with_header;
 
@@ -1775,19 +1857,6 @@ ohci_queue_iso_receive_dualbuffer(struct fw_iso_context *base,
         * packet, retransmit or terminate..
         */
 
-       if (packet->skip) {
-               d = context_get_descriptors(&ctx->context, 2, &d_bus);
-               if (d == NULL)
-                       return -ENOMEM;
-
-               db = (struct db_descriptor *) d;
-               db->control = cpu_to_le16(DESCRIPTOR_STATUS |
-                                         DESCRIPTOR_BRANCH_ALWAYS |
-                                         DESCRIPTOR_WAIT);
-               db->first_size = cpu_to_le16(ctx->base.header_size + 4);
-               context_append(&ctx->context, d, 2, 0);
-       }
-
        p = packet;
        z = 2;
 
@@ -1815,11 +1884,18 @@ ohci_queue_iso_receive_dualbuffer(struct fw_iso_context *base,
                db->control = cpu_to_le16(DESCRIPTOR_STATUS |
                                          DESCRIPTOR_BRANCH_ALWAYS);
                db->first_size = cpu_to_le16(ctx->base.header_size + 4);
-               db->first_req_count = cpu_to_le16(header_size);
+               if (p->skip && rest == p->payload_length) {
+                       db->control |= cpu_to_le16(DESCRIPTOR_WAIT);
+                       db->first_req_count = db->first_size;
+               } else {
+                       db->first_req_count = cpu_to_le16(header_size);
+               }
                db->first_res_count = db->first_req_count;
                db->first_buffer = cpu_to_le32(d_bus + sizeof(*db));
 
-               if (offset + rest < PAGE_SIZE)
+               if (p->skip && rest == p->payload_length)
+                       length = 4;
+               else if (offset + rest < PAGE_SIZE)
                        length = rest;
                else
                        length = PAGE_SIZE - offset;
@@ -1835,7 +1911,8 @@ ohci_queue_iso_receive_dualbuffer(struct fw_iso_context *base,
                context_append(&ctx->context, d, z, header_z);
                offset = (offset + length) & ~PAGE_MASK;
                rest -= length;
-               page++;
+               if (offset == 0)
+                       page++;
        }
 
        return 0;
@@ -1849,67 +1926,70 @@ ohci_queue_iso_receive_packet_per_buffer(struct fw_iso_context *base,
 {
        struct iso_context *ctx = container_of(base, struct iso_context, base);
        struct descriptor *d = NULL, *pd = NULL;
-       struct fw_iso_packet *p;
+       struct fw_iso_packet *p = packet;
        dma_addr_t d_bus, page_bus;
        u32 z, header_z, rest;
-       int i, page, offset, packet_count, header_size;
-
-       if (packet->skip) {
-               d = context_get_descriptors(&ctx->context, 1, &d_bus);
-               if (d == NULL)
-                       return -ENOMEM;
-
-               d->control = cpu_to_le16(DESCRIPTOR_STATUS |
-                                        DESCRIPTOR_INPUT_LAST |
-                                        DESCRIPTOR_BRANCH_ALWAYS |
-                                        DESCRIPTOR_WAIT);
-               context_append(&ctx->context, d, 1, 0);
-       }
-
-       /* one descriptor for header, one for payload */
-       /* FIXME: handle cases where we need multiple desc. for payload */
-       z = 2;
-       p = packet;
+       int i, j, length;
+       int page, offset, packet_count, header_size, payload_per_buffer;
 
        /*
         * The OHCI controller puts the status word in the
         * buffer too, so we need 4 extra bytes per packet.
         */
        packet_count = p->header_length / ctx->base.header_size;
-       header_size  = packet_count * (ctx->base.header_size + 4);
+       header_size  = ctx->base.header_size + 4;
 
        /* Get header size in number of descriptors. */
        header_z = DIV_ROUND_UP(header_size, sizeof(*d));
        page     = payload >> PAGE_SHIFT;
        offset   = payload & ~PAGE_MASK;
-       rest     = p->payload_length;
+       payload_per_buffer = p->payload_length / packet_count;
 
        for (i = 0; i < packet_count; i++) {
                /* d points to the header descriptor */
+               z = DIV_ROUND_UP(payload_per_buffer + offset, PAGE_SIZE) + 1;
                d = context_get_descriptors(&ctx->context,
-                                           z + header_z, &d_bus);
+                               z + header_z, &d_bus);
                if (d == NULL)
                        return -ENOMEM;
 
-               d->control      = cpu_to_le16(DESCRIPTOR_INPUT_MORE);
+               d->control      = cpu_to_le16(DESCRIPTOR_STATUS |
+                                             DESCRIPTOR_INPUT_MORE);
+               if (p->skip && i == 0)
+                       d->control |= cpu_to_le16(DESCRIPTOR_WAIT);
                d->req_count    = cpu_to_le16(header_size);
                d->res_count    = d->req_count;
+               d->transfer_status = 0;
                d->data_address = cpu_to_le32(d_bus + (z * sizeof(*d)));
 
-               /* pd points to the payload descriptor */
-               pd = d + 1;
+               rest = payload_per_buffer;
+               for (j = 1; j < z; j++) {
+                       pd = d + j;
+                       pd->control = cpu_to_le16(DESCRIPTOR_STATUS |
+                                                 DESCRIPTOR_INPUT_MORE);
+
+                       if (offset + rest < PAGE_SIZE)
+                               length = rest;
+                       else
+                               length = PAGE_SIZE - offset;
+                       pd->req_count = cpu_to_le16(length);
+                       pd->res_count = pd->req_count;
+                       pd->transfer_status = 0;
+
+                       page_bus = page_private(buffer->pages[page]);
+                       pd->data_address = cpu_to_le32(page_bus + offset);
+
+                       offset = (offset + length) & ~PAGE_MASK;
+                       rest -= length;
+                       if (offset == 0)
+                               page++;
+               }
                pd->control = cpu_to_le16(DESCRIPTOR_STATUS |
                                          DESCRIPTOR_INPUT_LAST |
                                          DESCRIPTOR_BRANCH_ALWAYS);
-               if (p->interrupt)
+               if (p->interrupt && i == packet_count - 1)
                        pd->control |= cpu_to_le16(DESCRIPTOR_IRQ_ALWAYS);
 
-               pd->req_count = cpu_to_le16(rest);
-               pd->res_count = pd->req_count;
-
-               page_bus = page_private(buffer->pages[page]);
-               pd->data_address = cpu_to_le32(page_bus + offset);
-
                context_append(&ctx->context, d, z, header_z);
        }
 
@@ -1923,16 +2003,22 @@ ohci_queue_iso(struct fw_iso_context *base,
               unsigned long payload)
 {
        struct iso_context *ctx = container_of(base, struct iso_context, base);
+       unsigned long flags;
+       int retval;
 
+       spin_lock_irqsave(&ctx->context.ohci->lock, flags);
        if (base->type == FW_ISO_CONTEXT_TRANSMIT)
-               return ohci_queue_iso_transmit(base, packet, buffer, payload);
+               retval = ohci_queue_iso_transmit(base, packet, buffer, payload);
        else if (ctx->context.ohci->version >= OHCI_VERSION_1_1)
-               return ohci_queue_iso_receive_dualbuffer(base, packet,
+               retval = ohci_queue_iso_receive_dualbuffer(base, packet,
                                                         buffer, payload);
        else
-               return ohci_queue_iso_receive_packet_per_buffer(base, packet,
+               retval = ohci_queue_iso_receive_packet_per_buffer(base, packet,
                                                                buffer,
                                                                payload);
+       spin_unlock_irqrestore(&ctx->context.ohci->lock, flags);
+
+       return retval;
 }
 
 static const struct fw_card_driver ohci_driver = {
@@ -2004,10 +2090,10 @@ pci_probe(struct pci_dev *dev, const struct pci_device_id *ent)
        ar_context_init(&ohci->ar_response_ctx, ohci,
                        OHCI1394_AsRspRcvContextControlSet);
 
-       context_init(&ohci->at_request_ctx, ohci, AT_BUFFER_SIZE,
+       context_init(&ohci->at_request_ctx, ohci,
                     OHCI1394_AsReqTrContextControlSet, handle_at_packet);
 
-       context_init(&ohci->at_response_ctx, ohci, AT_BUFFER_SIZE,
+       context_init(&ohci->at_response_ctx, ohci,
                     OHCI1394_AsRspTrContextControlSet, handle_at_packet);
 
        reg_write(ohci, OHCI1394_IsoRecvIntMaskSet, ~0);
index c2169d215bf7473d3fa2a983bd3852b8ab329a24..19ece9b6d7425906d6cff48cee2ebfba172f5141 100644 (file)
@@ -40,6 +40,7 @@
 #include <linux/stringify.h>
 #include <linux/timer.h>
 #include <linux/workqueue.h>
+#include <asm/system.h>
 
 #include <scsi/scsi.h>
 #include <scsi/scsi_cmnd.h>
@@ -148,18 +149,26 @@ struct sbp2_target {
 
        unsigned workarounds;
        struct list_head lu_list;
+
+       unsigned int mgt_orb_timeout;
 };
 
-#define SBP2_MAX_SG_ELEMENT_LENGTH     0xf000
-#define SBP2_MAX_SECTORS               255     /* Max sectors supported */
+/*
+ * Per section 7.4.8 of the SBP-2 spec, a mgt_ORB_timeout value can be
+ * provided in the config rom. Most devices do provide a value, which
+ * we'll use for login management orbs, but with some sane limits.
+ */
+#define SBP2_MIN_LOGIN_ORB_TIMEOUT     5000U   /* Timeout in ms */
+#define SBP2_MAX_LOGIN_ORB_TIMEOUT     40000U  /* Timeout in ms */
 #define SBP2_ORB_TIMEOUT               2000    /* Timeout in ms */
-
 #define SBP2_ORB_NULL                  0x80000000
+#define SBP2_MAX_SG_ELEMENT_LENGTH     0xf000
 
 #define SBP2_DIRECTION_TO_MEDIA                0x0
 #define SBP2_DIRECTION_FROM_MEDIA      0x1
 
 /* Unit directory keys */
+#define SBP2_CSR_UNIT_CHARACTERISTICS  0x3a
 #define SBP2_CSR_FIRMWARE_REVISION     0x3c
 #define SBP2_CSR_LOGICAL_UNIT_NUMBER   0x14
 #define SBP2_CSR_LOGICAL_UNIT_DIRECTORY        0xd4
@@ -489,6 +498,7 @@ sbp2_send_management_orb(struct sbp2_logical_unit *lu, int node_id,
 {
        struct fw_device *device = fw_device(lu->tgt->unit->device.parent);
        struct sbp2_management_orb *orb;
+       unsigned int timeout;
        int retval = -ENOMEM;
 
        orb = kzalloc(sizeof(*orb), GFP_ATOMIC);
@@ -516,9 +526,13 @@ sbp2_send_management_orb(struct sbp2_logical_unit *lu, int node_id,
        orb->request.status_fifo.low  = lu->address_handler.offset;
 
        if (function == SBP2_LOGIN_REQUEST) {
+               /* Ask for 2^2 == 4 seconds reconnect grace period */
                orb->request.misc |=
-                       MANAGEMENT_ORB_EXCLUSIVE(sbp2_param_exclusive_login) |
-                       MANAGEMENT_ORB_RECONNECT(0);
+                       MANAGEMENT_ORB_RECONNECT(2) |
+                       MANAGEMENT_ORB_EXCLUSIVE(sbp2_param_exclusive_login);
+               timeout = lu->tgt->mgt_orb_timeout;
+       } else {
+               timeout = SBP2_ORB_TIMEOUT;
        }
 
        fw_memcpy_to_be32(&orb->request, &orb->request, sizeof(orb->request));
@@ -535,8 +549,7 @@ sbp2_send_management_orb(struct sbp2_logical_unit *lu, int node_id,
        sbp2_send_orb(&orb->base, lu, node_id, generation,
                      lu->tgt->management_agent_address);
 
-       wait_for_completion_timeout(&orb->done,
-                                   msecs_to_jiffies(SBP2_ORB_TIMEOUT));
+       wait_for_completion_timeout(&orb->done, msecs_to_jiffies(timeout));
 
        retval = -EIO;
        if (sbp2_cancel_orbs(lu) == 0) {
@@ -608,13 +621,17 @@ static void sbp2_release_target(struct kref *kref)
        struct sbp2_logical_unit *lu, *next;
        struct Scsi_Host *shost =
                container_of((void *)tgt, struct Scsi_Host, hostdata[0]);
+       struct fw_device *device = fw_device(tgt->unit->device.parent);
 
        list_for_each_entry_safe(lu, next, &tgt->lu_list, link) {
                if (lu->sdev)
                        scsi_remove_device(lu->sdev);
 
-               sbp2_send_management_orb(lu, tgt->node_id, lu->generation,
-                               SBP2_LOGOUT_REQUEST, lu->login_id, NULL);
+               if (!fw_device_is_shutdown(device))
+                       sbp2_send_management_orb(lu, tgt->node_id,
+                                       lu->generation, SBP2_LOGOUT_REQUEST,
+                                       lu->login_id, NULL);
+
                fw_core_remove_address_handler(&lu->address_handler);
                list_del(&lu->link);
                kfree(lu);
@@ -628,6 +645,21 @@ static void sbp2_release_target(struct kref *kref)
 
 static struct workqueue_struct *sbp2_wq;
 
+/*
+ * Always get the target's kref when scheduling work on one its units.
+ * Each workqueue job is responsible to call sbp2_target_put() upon return.
+ */
+static void sbp2_queue_work(struct sbp2_logical_unit *lu, unsigned long delay)
+{
+       if (queue_delayed_work(sbp2_wq, &lu->work, delay))
+               kref_get(&lu->tgt->kref);
+}
+
+static void sbp2_target_put(struct sbp2_target *tgt)
+{
+       kref_put(&tgt->kref, sbp2_release_target);
+}
+
 static void sbp2_reconnect(struct work_struct *work);
 
 static void sbp2_login(struct work_struct *work)
@@ -643,22 +675,19 @@ static void sbp2_login(struct work_struct *work)
        struct sbp2_login_response response;
        int generation, node_id, local_node_id;
 
-       generation    = device->card->generation;
-       node_id       = device->node->node_id;
-       local_node_id = device->card->local_node->node_id;
+       generation    = device->generation;
+       smp_rmb();    /* node_id must not be older than generation */
+       node_id       = device->node_id;
+       local_node_id = device->card->node_id;
 
        if (sbp2_send_management_orb(lu, node_id, generation,
                                SBP2_LOGIN_REQUEST, lu->lun, &response) < 0) {
-               if (lu->retries++ < 5) {
-                       if (queue_delayed_work(sbp2_wq, &lu->work,
-                                              DIV_ROUND_UP(HZ, 5)))
-                               kref_get(&lu->tgt->kref);
-               } else {
+               if (lu->retries++ < 5)
+                       sbp2_queue_work(lu, DIV_ROUND_UP(HZ, 5));
+               else
                        fw_error("failed to login to %s LUN %04x\n",
                                 unit->device.bus_id, lu->lun);
-               }
-               kref_put(&lu->tgt->kref, sbp2_release_target);
-               return;
+               goto out;
        }
 
        lu->generation        = generation;
@@ -700,7 +729,8 @@ static void sbp2_login(struct work_struct *work)
                lu->sdev = sdev;
                scsi_device_put(sdev);
        }
-       kref_put(&lu->tgt->kref, sbp2_release_target);
+ out:
+       sbp2_target_put(lu->tgt);
 }
 
 static int sbp2_add_logical_unit(struct sbp2_target *tgt, int lun_entry)
@@ -750,6 +780,7 @@ static int sbp2_scan_unit_dir(struct sbp2_target *tgt, u32 *directory,
 {
        struct fw_csr_iterator ci;
        int key, value;
+       unsigned int timeout;
 
        fw_csr_iterator_init(&ci, directory);
        while (fw_csr_iterator_next(&ci, &key, &value)) {
@@ -772,6 +803,21 @@ static int sbp2_scan_unit_dir(struct sbp2_target *tgt, u32 *directory,
                        *firmware_revision = value;
                        break;
 
+               case SBP2_CSR_UNIT_CHARACTERISTICS:
+                       /* the timeout value is stored in 500ms units */
+                       timeout = ((unsigned int) value >> 8 & 0xff) * 500;
+                       timeout = max(timeout, SBP2_MIN_LOGIN_ORB_TIMEOUT);
+                       tgt->mgt_orb_timeout =
+                                 min(timeout, SBP2_MAX_LOGIN_ORB_TIMEOUT);
+
+                       if (timeout > tgt->mgt_orb_timeout)
+                               fw_notify("%s: config rom contains %ds "
+                                         "management ORB timeout, limiting "
+                                         "to %ds\n", tgt->unit->device.bus_id,
+                                         timeout / 1000,
+                                         tgt->mgt_orb_timeout / 1000);
+                       break;
+
                case SBP2_CSR_LOGICAL_UNIT_NUMBER:
                        if (sbp2_add_logical_unit(tgt, value) < 0)
                                return -ENOMEM;
@@ -865,18 +911,13 @@ static int sbp2_probe(struct device *dev)
 
        get_device(&unit->device);
 
-       /*
-        * We schedule work to do the login so we can easily
-        * reschedule retries. Always get the ref before scheduling
-        * work.
-        */
+       /* Do the login in a workqueue so we can easily reschedule retries. */
        list_for_each_entry(lu, &tgt->lu_list, link)
-               if (queue_delayed_work(sbp2_wq, &lu->work, 0))
-                       kref_get(&tgt->kref);
+               sbp2_queue_work(lu, 0);
        return 0;
 
  fail_tgt_put:
-       kref_put(&tgt->kref, sbp2_release_target);
+       sbp2_target_put(tgt);
        return -ENOMEM;
 
  fail_shost_put:
@@ -889,7 +930,7 @@ static int sbp2_remove(struct device *dev)
        struct fw_unit *unit = fw_unit(dev);
        struct sbp2_target *tgt = unit->device.driver_data;
 
-       kref_put(&tgt->kref, sbp2_release_target);
+       sbp2_target_put(tgt);
        return 0;
 }
 
@@ -901,9 +942,10 @@ static void sbp2_reconnect(struct work_struct *work)
        struct fw_device *device = fw_device(unit->device.parent);
        int generation, node_id, local_node_id;
 
-       generation    = device->card->generation;
-       node_id       = device->node->node_id;
-       local_node_id = device->card->local_node->node_id;
+       generation    = device->generation;
+       smp_rmb();    /* node_id must not be older than generation */
+       node_id       = device->node_id;
+       local_node_id = device->card->node_id;
 
        if (sbp2_send_management_orb(lu, node_id, generation,
                                     SBP2_RECONNECT_REQUEST,
@@ -915,10 +957,8 @@ static void sbp2_reconnect(struct work_struct *work)
                        lu->retries = 0;
                        PREPARE_DELAYED_WORK(&lu->work, sbp2_login);
                }
-               if (queue_delayed_work(sbp2_wq, &lu->work, DIV_ROUND_UP(HZ, 5)))
-                       kref_get(&lu->tgt->kref);
-               kref_put(&lu->tgt->kref, sbp2_release_target);
-               return;
+               sbp2_queue_work(lu, DIV_ROUND_UP(HZ, 5));
+               goto out;
        }
 
        lu->generation        = generation;
@@ -930,8 +970,8 @@ static void sbp2_reconnect(struct work_struct *work)
 
        sbp2_agent_reset(lu);
        sbp2_cancel_orbs(lu);
-
-       kref_put(&lu->tgt->kref, sbp2_release_target);
+ out:
+       sbp2_target_put(lu->tgt);
 }
 
 static void sbp2_update(struct fw_unit *unit)
@@ -947,8 +987,7 @@ static void sbp2_update(struct fw_unit *unit)
         */
        list_for_each_entry(lu, &tgt->lu_list, link) {
                lu->retries = 0;
-               if (queue_delayed_work(sbp2_wq, &lu->work, 0))
-                       kref_get(&tgt->kref);
+               sbp2_queue_work(lu, 0);
        }
 }
 
@@ -1103,9 +1142,9 @@ sbp2_map_scatterlist(struct sbp2_command_orb *orb, struct fw_device *device,
         * elements larger than 65535 bytes, some IOMMUs may merge sg elements
         * during DMA mapping, and Linux currently doesn't prevent this.
         */
-       for (i = 0, j = 0; i < count; i++) {
-               sg_len = sg_dma_len(sg + i);
-               sg_addr = sg_dma_address(sg + i);
+       for (i = 0, j = 0; i < count; i++, sg = sg_next(sg)) {
+               sg_len = sg_dma_len(sg);
+               sg_addr = sg_dma_address(sg);
                while (sg_len) {
                        /* FIXME: This won't get us out of the pinch. */
                        if (unlikely(j >= ARRAY_SIZE(orb->page_table))) {
index 0fc9b000e99dcdc714a42d58aa8865395cce0759..172c1867e9aa358c19cbb47afa85478a448ef510 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/module.h>
 #include <linux/wait.h>
 #include <linux/errno.h>
+#include <asm/system.h>
 #include "fw-transaction.h"
 #include "fw-topology.h"
 
@@ -518,6 +519,11 @@ fw_core_handle_bus_reset(struct fw_card *card,
                card->bm_retries = 0;
 
        card->node_id = node_id;
+       /*
+        * Update node_id before generation to prevent anybody from using
+        * a stale node_id together with a current generation.
+        */
+       smp_wmb();
        card->generation = generation;
        card->reset_jiffies = jiffies;
        schedule_delayed_work(&card->work, 0);
index c00d4a9b39e5861980d884823e9d46d41c18a61f..7fcc59dedf08cfa038d652336d1f85383614ccd3 100644 (file)
@@ -153,7 +153,7 @@ fw_fill_request(struct fw_packet *packet, int tcode, int tlabel,
        int ext_tcode;
 
        if (tcode > 0x10) {
-               ext_tcode = tcode 0x10;
+               ext_tcode = tcode & ~0x10;
                tcode = TCODE_LOCK_REQUEST;
        } else
                ext_tcode = 0;
@@ -650,7 +650,7 @@ fw_core_handle_request(struct fw_card *card, struct fw_packet *p)
                 HEADER_GET_OFFSET_HIGH(p->header[1]) << 32) | p->header[2];
        tcode       = HEADER_GET_TCODE(p->header[0]);
        destination = HEADER_GET_DESTINATION(p->header[0]);
-       source      = HEADER_GET_SOURCE(p->header[0]);
+       source      = HEADER_GET_SOURCE(p->header[1]);
 
        spin_lock_irqsave(&address_handler_lock, flags);
        handler = lookup_enclosing_address_handler(&address_handler_list,
index d168223db1594b7d351956f14903448548c08e1e..744011989044e029ca95cd00b9e3eb9ffed7cfb8 100644 (file)
@@ -11,7 +11,7 @@
  *
  * This code takes information provided by BIOS EDD calls
  * fn41 - Check Extensions Present and
- * fn48 - Get Device Parametes with EDD extensions
+ * fn48 - Get Device Parameters with EDD extensions
  * made in setup.S, copied to safe structures in setup.c,
  * and presents it in sysfs.
  *
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
new file mode 100644 (file)
index 0000000..74fac0f
--- /dev/null
@@ -0,0 +1,72 @@
+#
+# GPIO infrastructure and expanders
+#
+
+config HAVE_GPIO_LIB
+       bool
+       help
+         Platforms select gpiolib if they use this infrastructure
+         for all their GPIOs, usually starting with ones integrated
+         into SOC processors.
+
+menu "GPIO Support"
+       depends on HAVE_GPIO_LIB
+
+config DEBUG_GPIO
+       bool "Debug GPIO calls"
+       depends on DEBUG_KERNEL
+       help
+         Say Y here to add some extra checks and diagnostics to GPIO calls.
+         The checks help ensure that GPIOs have been properly initialized
+         before they are used and that sleeping calls aren not made from
+         nonsleeping contexts.  They can make bitbanged serial protocols
+         slower.  The diagnostics help catch the type of setup errors
+         that are most common when setting up new platforms or boards.
+
+# put expanders in the right section, in alphabetical order
+
+comment "I2C GPIO expanders:"
+
+config GPIO_PCA9539
+       tristate "PCA9539 16-bit I/O port"
+       depends on I2C
+       help
+         Say yes here to support the PCA9539 16-bit I/O port. These
+         parts are made by NXP and TI.
+
+         This driver can also be built as a module.  If so, the module
+         will be called pca9539.
+
+config GPIO_PCF857X
+       tristate "PCF857x, PCA857x, and PCA967x I2C GPIO expanders"
+       depends on I2C
+       help
+         Say yes here to provide access to most "quasi-bidirectional" I2C
+         GPIO expanders used for additional digital outputs or inputs.
+         Most of these parts are from NXP, though TI is a second source for
+         some of them.  Compatible models include:
+
+         8 bits:   pcf8574, pcf8574a, pca8574, pca8574a,
+                   pca9670, pca9672, pca9674, pca9674a
+
+         16 bits:  pcf8575, pcf8575c, pca8575,
+                   pca9671, pca9673, pca9675
+
+         Your board setup code will need to declare the expanders in
+         use, and assign numbers to the GPIOs they expose.  Those GPIOs
+         can then be used from drivers and other kernel code, just like
+         other GPIOs, but only accessible from task contexts.
+
+         This driver provides an in-kernel interface to those GPIOs using
+         platform-neutral GPIO calls.
+
+comment "SPI GPIO expanders:"
+
+config GPIO_MCP23S08
+       tristate "Microchip MCP23S08 I/O expander"
+       depends on SPI_MASTER
+       help
+         SPI driver for Microchip MCP23S08 I/O expander.  This provides
+         a GPIO interface supporting inputs and outputs.
+
+endmenu
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
new file mode 100644 (file)
index 0000000..470ecd6
--- /dev/null
@@ -0,0 +1,9 @@
+# gpio support: dedicated expander chips, etc
+
+ccflags-$(CONFIG_DEBUG_GPIO)   += -DDEBUG
+
+obj-$(CONFIG_HAVE_GPIO_LIB)    += gpiolib.o
+
+obj-$(CONFIG_GPIO_MCP23S08)    += mcp23s08.o
+obj-$(CONFIG_GPIO_PCA9539)     += pca9539.o
+obj-$(CONFIG_GPIO_PCF857X)     += pcf857x.o
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
new file mode 100644 (file)
index 0000000..d8db2f8
--- /dev/null
@@ -0,0 +1,567 @@
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/irq.h>
+#include <linux/spinlock.h>
+
+#include <asm/gpio.h>
+
+
+/* Optional implementation infrastructure for GPIO interfaces.
+ *
+ * Platforms may want to use this if they tend to use very many GPIOs
+ * that aren't part of a System-On-Chip core; or across I2C/SPI/etc.
+ *
+ * When kernel footprint or instruction count is an issue, simpler
+ * implementations may be preferred.  The GPIO programming interface
+ * allows for inlining speed-critical get/set operations for common
+ * cases, so that access to SOC-integrated GPIOs can sometimes cost
+ * only an instruction or two per bit.
+ */
+
+
+/* When debugging, extend minimal trust to callers and platform code.
+ * Also emit diagnostic messages that may help initial bringup, when
+ * board setup or driver bugs are most common.
+ *
+ * Otherwise, minimize overhead in what may be bitbanging codepaths.
+ */
+#ifdef DEBUG
+#define        extra_checks    1
+#else
+#define        extra_checks    0
+#endif
+
+/* gpio_lock prevents conflicts during gpio_desc[] table updates.
+ * While any GPIO is requested, its gpio_chip is not removable;
+ * each GPIO's "requested" flag serves as a lock and refcount.
+ */
+static DEFINE_SPINLOCK(gpio_lock);
+
+struct gpio_desc {
+       struct gpio_chip        *chip;
+       unsigned long           flags;
+/* flag symbols are bit numbers */
+#define FLAG_REQUESTED 0
+#define FLAG_IS_OUT    1
+
+#ifdef CONFIG_DEBUG_FS
+       const char              *label;
+#endif
+};
+static struct gpio_desc gpio_desc[ARCH_NR_GPIOS];
+
+static inline void desc_set_label(struct gpio_desc *d, const char *label)
+{
+#ifdef CONFIG_DEBUG_FS
+       d->label = label;
+#endif
+}
+
+/* Warn when drivers omit gpio_request() calls -- legal but ill-advised
+ * when setting direction, and otherwise illegal.  Until board setup code
+ * and drivers use explicit requests everywhere (which won't happen when
+ * those calls have no teeth) we can't avoid autorequesting.  This nag
+ * message should motivate switching to explicit requests...
+ */
+static void gpio_ensure_requested(struct gpio_desc *desc)
+{
+       if (test_and_set_bit(FLAG_REQUESTED, &desc->flags) == 0) {
+               pr_warning("GPIO-%d autorequested\n", (int)(desc - gpio_desc));
+               desc_set_label(desc, "[auto]");
+       }
+}
+
+/* caller holds gpio_lock *OR* gpio is marked as requested */
+static inline struct gpio_chip *gpio_to_chip(unsigned gpio)
+{
+       return gpio_desc[gpio].chip;
+}
+
+/**
+ * gpiochip_add() - register a gpio_chip
+ * @chip: the chip to register, with chip->base initialized
+ * Context: potentially before irqs or kmalloc will work
+ *
+ * Returns a negative errno if the chip can't be registered, such as
+ * because the chip->base is invalid or already associated with a
+ * different chip.  Otherwise it returns zero as a success code.
+ */
+int gpiochip_add(struct gpio_chip *chip)
+{
+       unsigned long   flags;
+       int             status = 0;
+       unsigned        id;
+
+       /* NOTE chip->base negative is reserved to mean a request for
+        * dynamic allocation.  We don't currently support that.
+        */
+
+       if (chip->base < 0 || (chip->base  + chip->ngpio) >= ARCH_NR_GPIOS) {
+               status = -EINVAL;
+               goto fail;
+       }
+
+       spin_lock_irqsave(&gpio_lock, flags);
+
+       /* these GPIO numbers must not be managed by another gpio_chip */
+       for (id = chip->base; id < chip->base + chip->ngpio; id++) {
+               if (gpio_desc[id].chip != NULL) {
+                       status = -EBUSY;
+                       break;
+               }
+       }
+       if (status == 0) {
+               for (id = chip->base; id < chip->base + chip->ngpio; id++) {
+                       gpio_desc[id].chip = chip;
+                       gpio_desc[id].flags = 0;
+               }
+       }
+
+       spin_unlock_irqrestore(&gpio_lock, flags);
+fail:
+       /* failures here can mean systems won't boot... */
+       if (status)
+               pr_err("gpiochip_add: gpios %d..%d (%s) not registered\n",
+                       chip->base, chip->base + chip->ngpio,
+                       chip->label ? : "generic");
+       return status;
+}
+EXPORT_SYMBOL_GPL(gpiochip_add);
+
+/**
+ * gpiochip_remove() - unregister a gpio_chip
+ * @chip: the chip to unregister
+ *
+ * A gpio_chip with any GPIOs still requested may not be removed.
+ */
+int gpiochip_remove(struct gpio_chip *chip)
+{
+       unsigned long   flags;
+       int             status = 0;
+       unsigned        id;
+
+       spin_lock_irqsave(&gpio_lock, flags);
+
+       for (id = chip->base; id < chip->base + chip->ngpio; id++) {
+               if (test_bit(FLAG_REQUESTED, &gpio_desc[id].flags)) {
+                       status = -EBUSY;
+                       break;
+               }
+       }
+       if (status == 0) {
+               for (id = chip->base; id < chip->base + chip->ngpio; id++)
+                       gpio_desc[id].chip = NULL;
+       }
+
+       spin_unlock_irqrestore(&gpio_lock, flags);
+       return status;
+}
+EXPORT_SYMBOL_GPL(gpiochip_remove);
+
+
+/* These "optional" allocation calls help prevent drivers from stomping
+ * on each other, and help provide better diagnostics in debugfs.
+ * They're called even less than the "set direction" calls.
+ */
+int gpio_request(unsigned gpio, const char *label)
+{
+       struct gpio_desc        *desc;
+       int                     status = -EINVAL;
+       unsigned long           flags;
+
+       spin_lock_irqsave(&gpio_lock, flags);
+
+       if (gpio >= ARCH_NR_GPIOS)
+               goto done;
+       desc = &gpio_desc[gpio];
+       if (desc->chip == NULL)
+               goto done;
+
+       /* NOTE:  gpio_request() can be called in early boot,
+        * before IRQs are enabled.
+        */
+
+       if (test_and_set_bit(FLAG_REQUESTED, &desc->flags) == 0) {
+               desc_set_label(desc, label ? : "?");
+               status = 0;
+       } else
+               status = -EBUSY;
+
+done:
+       if (status)
+               pr_debug("gpio_request: gpio-%d (%s) status %d\n",
+                       gpio, label ? : "?", status);
+       spin_unlock_irqrestore(&gpio_lock, flags);
+       return status;
+}
+EXPORT_SYMBOL_GPL(gpio_request);
+
+void gpio_free(unsigned gpio)
+{
+       unsigned long           flags;
+       struct gpio_desc        *desc;
+
+       if (gpio >= ARCH_NR_GPIOS) {
+               WARN_ON(extra_checks);
+               return;
+       }
+
+       spin_lock_irqsave(&gpio_lock, flags);
+
+       desc = &gpio_desc[gpio];
+       if (desc->chip && test_and_clear_bit(FLAG_REQUESTED, &desc->flags))
+               desc_set_label(desc, NULL);
+       else
+               WARN_ON(extra_checks);
+
+       spin_unlock_irqrestore(&gpio_lock, flags);
+}
+EXPORT_SYMBOL_GPL(gpio_free);
+
+
+/**
+ * gpiochip_is_requested - return string iff signal was requested
+ * @chip: controller managing the signal
+ * @offset: of signal within controller's 0..(ngpio - 1) range
+ *
+ * Returns NULL if the GPIO is not currently requested, else a string.
+ * If debugfs support is enabled, the string returned is the label passed
+ * to gpio_request(); otherwise it is a meaningless constant.
+ *
+ * This function is for use by GPIO controller drivers.  The label can
+ * help with diagnostics, and knowing that the signal is used as a GPIO
+ * can help avoid accidentally multiplexing it to another controller.
+ */
+const char *gpiochip_is_requested(struct gpio_chip *chip, unsigned offset)
+{
+       unsigned gpio = chip->base + offset;
+
+       if (gpio >= ARCH_NR_GPIOS || gpio_desc[gpio].chip != chip)
+               return NULL;
+       if (test_bit(FLAG_REQUESTED, &gpio_desc[gpio].flags) == 0)
+               return NULL;
+#ifdef CONFIG_DEBUG_FS
+       return gpio_desc[gpio].label;
+#else
+       return "?";
+#endif
+}
+EXPORT_SYMBOL_GPL(gpiochip_is_requested);
+
+
+/* Drivers MUST set GPIO direction before making get/set calls.  In
+ * some cases this is done in early boot, before IRQs are enabled.
+ *
+ * As a rule these aren't called more than once (except for drivers
+ * using the open-drain emulation idiom) so these are natural places
+ * to accumulate extra debugging checks.  Note that we can't (yet)
+ * rely on gpio_request() having been called beforehand.
+ */
+
+int gpio_direction_input(unsigned gpio)
+{
+       unsigned long           flags;
+       struct gpio_chip        *chip;
+       struct gpio_desc        *desc = &gpio_desc[gpio];
+       int                     status = -EINVAL;
+
+       spin_lock_irqsave(&gpio_lock, flags);
+
+       if (gpio >= ARCH_NR_GPIOS)
+               goto fail;
+       chip = desc->chip;
+       if (!chip || !chip->get || !chip->direction_input)
+               goto fail;
+       gpio -= chip->base;
+       if (gpio >= chip->ngpio)
+               goto fail;
+       gpio_ensure_requested(desc);
+
+       /* now we know the gpio is valid and chip won't vanish */
+
+       spin_unlock_irqrestore(&gpio_lock, flags);
+
+       might_sleep_if(extra_checks && chip->can_sleep);
+
+       status = chip->direction_input(chip, gpio);
+       if (status == 0)
+               clear_bit(FLAG_IS_OUT, &desc->flags);
+       return status;
+fail:
+       spin_unlock_irqrestore(&gpio_lock, flags);
+       if (status)
+               pr_debug("%s: gpio-%d status %d\n",
+                       __FUNCTION__, gpio, status);
+       return status;
+}
+EXPORT_SYMBOL_GPL(gpio_direction_input);
+
+int gpio_direction_output(unsigned gpio, int value)
+{
+       unsigned long           flags;
+       struct gpio_chip        *chip;
+       struct gpio_desc        *desc = &gpio_desc[gpio];
+       int                     status = -EINVAL;
+
+       spin_lock_irqsave(&gpio_lock, flags);
+
+       if (gpio >= ARCH_NR_GPIOS)
+               goto fail;
+       chip = desc->chip;
+       if (!chip || !chip->set || !chip->direction_output)
+               goto fail;
+       gpio -= chip->base;
+       if (gpio >= chip->ngpio)
+               goto fail;
+       gpio_ensure_requested(desc);
+
+       /* now we know the gpio is valid and chip won't vanish */
+
+       spin_unlock_irqrestore(&gpio_lock, flags);
+
+       might_sleep_if(extra_checks && chip->can_sleep);
+
+       status = chip->direction_output(chip, gpio, value);
+       if (status == 0)
+               set_bit(FLAG_IS_OUT, &desc->flags);
+       return status;
+fail:
+       spin_unlock_irqrestore(&gpio_lock, flags);
+       if (status)
+               pr_debug("%s: gpio-%d status %d\n",
+                       __FUNCTION__, gpio, status);
+       return status;
+}
+EXPORT_SYMBOL_GPL(gpio_direction_output);
+
+
+/* I/O calls are only valid after configuration completed; the relevant
+ * "is this a valid GPIO" error checks should already have been done.
+ *
+ * "Get" operations are often inlinable as reading a pin value register,
+ * and masking the relevant bit in that register.
+ *
+ * When "set" operations are inlinable, they involve writing that mask to
+ * one register to set a low value, or a different register to set it high.
+ * Otherwise locking is needed, so there may be little value to inlining.
+ *
+ *------------------------------------------------------------------------
+ *
+ * IMPORTANT!!!  The hot paths -- get/set value -- assume that callers
+ * have requested the GPIO.  That can include implicit requesting by
+ * a direction setting call.  Marking a gpio as requested locks its chip
+ * in memory, guaranteeing that these table lookups need no more locking
+ * and that gpiochip_remove() will fail.
+ *
+ * REVISIT when debugging, consider adding some instrumentation to ensure
+ * that the GPIO was actually requested.
+ */
+
+/**
+ * __gpio_get_value() - return a gpio's value
+ * @gpio: gpio whose value will be returned
+ * Context: any
+ *
+ * This is used directly or indirectly to implement gpio_get_value().
+ * It returns the zero or nonzero value provided by the associated
+ * gpio_chip.get() method; or zero if no such method is provided.
+ */
+int __gpio_get_value(unsigned gpio)
+{
+       struct gpio_chip        *chip;
+
+       chip = gpio_to_chip(gpio);
+       WARN_ON(extra_checks && chip->can_sleep);
+       return chip->get ? chip->get(chip, gpio - chip->base) : 0;
+}
+EXPORT_SYMBOL_GPL(__gpio_get_value);
+
+/**
+ * __gpio_set_value() - assign a gpio's value
+ * @gpio: gpio whose value will be assigned
+ * @value: value to assign
+ * Context: any
+ *
+ * This is used directly or indirectly to implement gpio_set_value().
+ * It invokes the associated gpio_chip.set() method.
+ */
+void __gpio_set_value(unsigned gpio, int value)
+{
+       struct gpio_chip        *chip;
+
+       chip = gpio_to_chip(gpio);
+       WARN_ON(extra_checks && chip->can_sleep);
+       chip->set(chip, gpio - chip->base, value);
+}
+EXPORT_SYMBOL_GPL(__gpio_set_value);
+
+/**
+ * __gpio_cansleep() - report whether gpio value access will sleep
+ * @gpio: gpio in question
+ * Context: any
+ *
+ * This is used directly or indirectly to implement gpio_cansleep().  It
+ * returns nonzero if access reading or writing the GPIO value can sleep.
+ */
+int __gpio_cansleep(unsigned gpio)
+{
+       struct gpio_chip        *chip;
+
+       /* only call this on GPIOs that are valid! */
+       chip = gpio_to_chip(gpio);
+
+       return chip->can_sleep;
+}
+EXPORT_SYMBOL_GPL(__gpio_cansleep);
+
+
+
+/* There's no value in making it easy to inline GPIO calls that may sleep.
+ * Common examples include ones connected to I2C or SPI chips.
+ */
+
+int gpio_get_value_cansleep(unsigned gpio)
+{
+       struct gpio_chip        *chip;
+
+       might_sleep_if(extra_checks);
+       chip = gpio_to_chip(gpio);
+       return chip->get(chip, gpio - chip->base);
+}
+EXPORT_SYMBOL_GPL(gpio_get_value_cansleep);
+
+void gpio_set_value_cansleep(unsigned gpio, int value)
+{
+       struct gpio_chip        *chip;
+
+       might_sleep_if(extra_checks);
+       chip = gpio_to_chip(gpio);
+       chip->set(chip, gpio - chip->base, value);
+}
+EXPORT_SYMBOL_GPL(gpio_set_value_cansleep);
+
+
+#ifdef CONFIG_DEBUG_FS
+
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+
+
+static void gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip)
+{
+       unsigned                i;
+       unsigned                gpio = chip->base;
+       struct gpio_desc        *gdesc = &gpio_desc[gpio];
+       int                     is_out;
+
+       for (i = 0; i < chip->ngpio; i++, gpio++, gdesc++) {
+               if (!test_bit(FLAG_REQUESTED, &gdesc->flags))
+                       continue;
+
+               is_out = test_bit(FLAG_IS_OUT, &gdesc->flags);
+               seq_printf(s, " gpio-%-3d (%-12s) %s %s",
+                       gpio, gdesc->label,
+                       is_out ? "out" : "in ",
+                       chip->get
+                               ? (chip->get(chip, i) ? "hi" : "lo")
+                               : "?  ");
+
+               if (!is_out) {
+                       int             irq = gpio_to_irq(gpio);
+                       struct irq_desc *desc = irq_desc + irq;
+
+                       /* This races with request_irq(), set_irq_type(),
+                        * and set_irq_wake() ... but those are "rare".
+                        *
+                        * More significantly, trigger type flags aren't
+                        * currently maintained by genirq.
+                        */
+                       if (irq >= 0 && desc->action) {
+                               char *trigger;
+
+                               switch (desc->status & IRQ_TYPE_SENSE_MASK) {
+                               case IRQ_TYPE_NONE:
+                                       trigger = "(default)";
+                                       break;
+                               case IRQ_TYPE_EDGE_FALLING:
+                                       trigger = "edge-falling";
+                                       break;
+                               case IRQ_TYPE_EDGE_RISING:
+                                       trigger = "edge-rising";
+                                       break;
+                               case IRQ_TYPE_EDGE_BOTH:
+                                       trigger = "edge-both";
+                                       break;
+                               case IRQ_TYPE_LEVEL_HIGH:
+                                       trigger = "level-high";
+                                       break;
+                               case IRQ_TYPE_LEVEL_LOW:
+                                       trigger = "level-low";
+                                       break;
+                               default:
+                                       trigger = "?trigger?";
+                                       break;
+                               }
+
+                               seq_printf(s, " irq-%d %s%s",
+                                       irq, trigger,
+                                       (desc->status & IRQ_WAKEUP)
+                                               ? " wakeup" : "");
+                       }
+               }
+
+               seq_printf(s, "\n");
+       }
+}
+
+static int gpiolib_show(struct seq_file *s, void *unused)
+{
+       struct gpio_chip        *chip = NULL;
+       unsigned                gpio;
+       int                     started = 0;
+
+       /* REVISIT this isn't locked against gpio_chip removal ... */
+
+       for (gpio = 0; gpio < ARCH_NR_GPIOS; gpio++) {
+               if (chip == gpio_desc[gpio].chip)
+                       continue;
+               chip = gpio_desc[gpio].chip;
+               if (!chip)
+                       continue;
+
+               seq_printf(s, "%sGPIOs %d-%d, %s%s:\n",
+                               started ? "\n" : "",
+                               chip->base, chip->base + chip->ngpio - 1,
+                               chip->label ? : "generic",
+                               chip->can_sleep ? ", can sleep" : "");
+               started = 1;
+               if (chip->dbg_show)
+                       chip->dbg_show(s, chip);
+               else
+                       gpiolib_dbg_show(s, chip);
+       }
+       return 0;
+}
+
+static int gpiolib_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, gpiolib_show, NULL);
+}
+
+static struct file_operations gpiolib_operations = {
+       .open           = gpiolib_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+static int __init gpiolib_debugfs_init(void)
+{
+       /* /sys/kernel/debug/gpio */
+       (void) debugfs_create_file("gpio", S_IFREG | S_IRUGO,
+                               NULL, NULL, &gpiolib_operations);
+       return 0;
+}
+subsys_initcall(gpiolib_debugfs_init);
+
+#endif /* DEBUG_FS */
diff --git a/drivers/gpio/mcp23s08.c b/drivers/gpio/mcp23s08.c
new file mode 100644 (file)
index 0000000..bb60e8c
--- /dev/null
@@ -0,0 +1,357 @@
+/*
+ * mcp23s08.c - SPI gpio expander driver
+ */
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/workqueue.h>
+#include <linux/mutex.h>
+
+#include <linux/spi/spi.h>
+#include <linux/spi/mcp23s08.h>
+
+#include <asm/gpio.h>
+
+
+/* Registers are all 8 bits wide.
+ *
+ * The mcp23s17 has twice as many bits, and can be configured to work
+ * with either 16 bit registers or with two adjacent 8 bit banks.
+ *
+ * Also, there are I2C versions of both chips.
+ */
+#define MCP_IODIR      0x00            /* init/reset:  all ones */
+#define MCP_IPOL       0x01
+#define MCP_GPINTEN    0x02
+#define MCP_DEFVAL     0x03
+#define MCP_INTCON     0x04
+#define MCP_IOCON      0x05
+#      define IOCON_SEQOP      (1 << 5)
+#      define IOCON_HAEN       (1 << 3)
+#      define IOCON_ODR        (1 << 2)
+#      define IOCON_INTPOL     (1 << 1)
+#define MCP_GPPU       0x06
+#define MCP_INTF       0x07
+#define MCP_INTCAP     0x08
+#define MCP_GPIO       0x09
+#define MCP_OLAT       0x0a
+
+struct mcp23s08 {
+       struct spi_device       *spi;
+       u8                      addr;
+
+       /* lock protects the cached values */
+       struct mutex            lock;
+       u8                      cache[11];
+
+       struct gpio_chip        chip;
+
+       struct work_struct      work;
+};
+
+static int mcp23s08_read(struct mcp23s08 *mcp, unsigned reg)
+{
+       u8      tx[2], rx[1];
+       int     status;
+
+       tx[0] = mcp->addr | 0x01;
+       tx[1] = reg;
+       status = spi_write_then_read(mcp->spi, tx, sizeof tx, rx, sizeof rx);
+       return (status < 0) ? status : rx[0];
+}
+
+static int mcp23s08_write(struct mcp23s08 *mcp, unsigned reg, u8 val)
+{
+       u8      tx[3];
+
+       tx[0] = mcp->addr;
+       tx[1] = reg;
+       tx[2] = val;
+       return spi_write_then_read(mcp->spi, tx, sizeof tx, NULL, 0);
+}
+
+static int
+mcp23s08_read_regs(struct mcp23s08 *mcp, unsigned reg, u8 *vals, unsigned n)
+{
+       u8      tx[2];
+
+       if ((n + reg) > sizeof mcp->cache)
+               return -EINVAL;
+       tx[0] = mcp->addr | 0x01;
+       tx[1] = reg;
+       return spi_write_then_read(mcp->spi, tx, sizeof tx, vals, n);
+}
+
+/*----------------------------------------------------------------------*/
+
+static int mcp23s08_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+       struct mcp23s08 *mcp = container_of(chip, struct mcp23s08, chip);
+       int status;
+
+       mutex_lock(&mcp->lock);
+       mcp->cache[MCP_IODIR] |= (1 << offset);
+       status = mcp23s08_write(mcp, MCP_IODIR, mcp->cache[MCP_IODIR]);
+       mutex_unlock(&mcp->lock);
+       return status;
+}
+
+static int mcp23s08_get(struct gpio_chip *chip, unsigned offset)
+{
+       struct mcp23s08 *mcp = container_of(chip, struct mcp23s08, chip);
+       int status;
+
+       mutex_lock(&mcp->lock);
+
+       /* REVISIT reading this clears any IRQ ... */
+       status = mcp23s08_read(mcp, MCP_GPIO);
+       if (status < 0)
+               status = 0;
+       else {
+               mcp->cache[MCP_GPIO] = status;
+               status = !!(status & (1 << offset));
+       }
+       mutex_unlock(&mcp->lock);
+       return status;
+}
+
+static int __mcp23s08_set(struct mcp23s08 *mcp, unsigned mask, int value)
+{
+       u8 olat = mcp->cache[MCP_OLAT];
+
+       if (value)
+               olat |= mask;
+       else
+               olat &= ~mask;
+       mcp->cache[MCP_OLAT] = olat;
+       return mcp23s08_write(mcp, MCP_OLAT, olat);
+}
+
+static void mcp23s08_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+       struct mcp23s08 *mcp = container_of(chip, struct mcp23s08, chip);
+       u8 mask = 1 << offset;
+
+       mutex_lock(&mcp->lock);
+       __mcp23s08_set(mcp, mask, value);
+       mutex_unlock(&mcp->lock);
+}
+
+static int
+mcp23s08_direction_output(struct gpio_chip *chip, unsigned offset, int value)
+{
+       struct mcp23s08 *mcp = container_of(chip, struct mcp23s08, chip);
+       u8 mask = 1 << offset;
+       int status;
+
+       mutex_lock(&mcp->lock);
+       status = __mcp23s08_set(mcp, mask, value);
+       if (status == 0) {
+               mcp->cache[MCP_IODIR] &= ~mask;
+               status = mcp23s08_write(mcp, MCP_IODIR, mcp->cache[MCP_IODIR]);
+       }
+       mutex_unlock(&mcp->lock);
+       return status;
+}
+
+/*----------------------------------------------------------------------*/
+
+#ifdef CONFIG_DEBUG_FS
+
+#include <linux/seq_file.h>
+
+/*
+ * This shows more info than the generic gpio dump code:
+ * pullups, deglitching, open drain drive.
+ */
+static void mcp23s08_dbg_show(struct seq_file *s, struct gpio_chip *chip)
+{
+       struct mcp23s08 *mcp;
+       char            bank;
+       unsigned        t;
+       unsigned        mask;
+
+       mcp = container_of(chip, struct mcp23s08, chip);
+
+       /* NOTE: we only handle one bank for now ... */
+       bank = '0' + ((mcp->addr >> 1) & 0x3);
+
+       mutex_lock(&mcp->lock);
+       t = mcp23s08_read_regs(mcp, 0, mcp->cache, sizeof mcp->cache);
+       if (t < 0) {
+               seq_printf(s, " I/O ERROR %d\n", t);
+               goto done;
+       }
+
+       for (t = 0, mask = 1; t < 8; t++, mask <<= 1) {
+               const char      *label;
+
+               label = gpiochip_is_requested(chip, t);
+               if (!label)
+                       continue;
+
+               seq_printf(s, " gpio-%-3d P%c.%d (%-12s) %s %s %s",
+                       chip->base + t, bank, t, label,
+                       (mcp->cache[MCP_IODIR] & mask) ? "in " : "out",
+                       (mcp->cache[MCP_GPIO] & mask) ? "hi" : "lo",
+                       (mcp->cache[MCP_GPPU] & mask) ? "  " : "up");
+               /* NOTE:  ignoring the irq-related registers */
+               seq_printf(s, "\n");
+       }
+done:
+       mutex_unlock(&mcp->lock);
+}
+
+#else
+#define mcp23s08_dbg_show      NULL
+#endif
+
+/*----------------------------------------------------------------------*/
+
+static int mcp23s08_probe(struct spi_device *spi)
+{
+       struct mcp23s08                 *mcp;
+       struct mcp23s08_platform_data   *pdata;
+       int                             status;
+       int                             do_update = 0;
+
+       pdata = spi->dev.platform_data;
+       if (!pdata || pdata->slave > 3 || !pdata->base)
+               return -ENODEV;
+
+       mcp = kzalloc(sizeof *mcp, GFP_KERNEL);
+       if (!mcp)
+               return -ENOMEM;
+
+       mutex_init(&mcp->lock);
+
+       mcp->spi = spi;
+       mcp->addr = 0x40 | (pdata->slave << 1);
+
+       mcp->chip.label = "mcp23s08",
+
+       mcp->chip.direction_input = mcp23s08_direction_input;
+       mcp->chip.get = mcp23s08_get;
+       mcp->chip.direction_output = mcp23s08_direction_output;
+       mcp->chip.set = mcp23s08_set;
+       mcp->chip.dbg_show = mcp23s08_dbg_show;
+
+       mcp->chip.base = pdata->base;
+       mcp->chip.ngpio = 8;
+       mcp->chip.can_sleep = 1;
+
+       spi_set_drvdata(spi, mcp);
+
+       /* verify MCP_IOCON.SEQOP = 0, so sequential reads work */
+       status = mcp23s08_read(mcp, MCP_IOCON);
+       if (status < 0)
+               goto fail;
+       if (status & IOCON_SEQOP) {
+               status &= ~IOCON_SEQOP;
+               status = mcp23s08_write(mcp, MCP_IOCON, (u8) status);
+               if (status < 0)
+                       goto fail;
+       }
+
+       /* configure ~100K pullups */
+       status = mcp23s08_write(mcp, MCP_GPPU, pdata->pullups);
+       if (status < 0)
+               goto fail;
+
+       status = mcp23s08_read_regs(mcp, 0, mcp->cache, sizeof mcp->cache);
+       if (status < 0)
+               goto fail;
+
+       /* disable inverter on input */
+       if (mcp->cache[MCP_IPOL] != 0) {
+               mcp->cache[MCP_IPOL] = 0;
+               do_update = 1;
+       }
+
+       /* disable irqs */
+       if (mcp->cache[MCP_GPINTEN] != 0) {
+               mcp->cache[MCP_GPINTEN] = 0;
+               do_update = 1;
+       }
+
+       if (do_update) {
+               u8 tx[4];
+
+               tx[0] = mcp->addr;
+               tx[1] = MCP_IPOL;
+               memcpy(&tx[2], &mcp->cache[MCP_IPOL], sizeof(tx) - 2);
+               status = spi_write_then_read(mcp->spi, tx, sizeof tx, NULL, 0);
+
+               /* FIXME check status... */
+       }
+
+       status = gpiochip_add(&mcp->chip);
+
+       /* NOTE:  these chips have a relatively sane IRQ framework, with
+        * per-signal masking and level/edge triggering.  It's not yet
+        * handled here...
+        */
+
+       if (pdata->setup) {
+               status = pdata->setup(spi, mcp->chip.base,
+                               mcp->chip.ngpio, pdata->context);
+               if (status < 0)
+                       dev_dbg(&spi->dev, "setup --> %d\n", status);
+       }
+
+       return 0;
+
+fail:
+       kfree(mcp);
+       return status;
+}
+
+static int mcp23s08_remove(struct spi_device *spi)
+{
+       struct mcp23s08                 *mcp = spi_get_drvdata(spi);
+       struct mcp23s08_platform_data   *pdata = spi->dev.platform_data;
+       int                             status = 0;
+
+       if (pdata->teardown) {
+               status = pdata->teardown(spi,
+                               mcp->chip.base, mcp->chip.ngpio,
+                               pdata->context);
+               if (status < 0) {
+                       dev_err(&spi->dev, "%s --> %d\n", "teardown", status);
+                       return status;
+               }
+       }
+
+       status = gpiochip_remove(&mcp->chip);
+       if (status == 0)
+               kfree(mcp);
+       else
+               dev_err(&spi->dev, "%s --> %d\n", "remove", status);
+       return status;
+}
+
+static struct spi_driver mcp23s08_driver = {
+       .probe          = mcp23s08_probe,
+       .remove         = mcp23s08_remove,
+       .driver = {
+               .name   = "mcp23s08",
+               .owner  = THIS_MODULE,
+       },
+};
+
+/*----------------------------------------------------------------------*/
+
+static int __init mcp23s08_init(void)
+{
+       return spi_register_driver(&mcp23s08_driver);
+}
+module_init(mcp23s08_init);
+
+static void __exit mcp23s08_exit(void)
+{
+       spi_unregister_driver(&mcp23s08_driver);
+}
+module_exit(mcp23s08_exit);
+
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/gpio/pca9539.c b/drivers/gpio/pca9539.c
new file mode 100644 (file)
index 0000000..3e85c92
--- /dev/null
@@ -0,0 +1,271 @@
+/*
+ *  pca9539.c - 16-bit I/O port with interrupt and reset
+ *
+ *  Copyright (C) 2005 Ben Gardner <bgardner@wabtec.com>
+ *  Copyright (C) 2007 Marvell International Ltd.
+ *
+ *  Derived from drivers/i2c/chips/pca9539.c
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/i2c/pca9539.h>
+
+#include <asm/gpio.h>
+
+
+#define NR_PCA9539_GPIOS       16
+
+#define PCA9539_INPUT          0
+#define PCA9539_OUTPUT         2
+#define PCA9539_INVERT         4
+#define PCA9539_DIRECTION      6
+
+struct pca9539_chip {
+       unsigned gpio_start;
+       uint16_t reg_output;
+       uint16_t reg_direction;
+
+       struct i2c_client *client;
+       struct gpio_chip gpio_chip;
+};
+
+/* NOTE:  we can't currently rely on fault codes to come from SMBus
+ * calls, so we map all errors to EIO here and return zero otherwise.
+ */
+static int pca9539_write_reg(struct pca9539_chip *chip, int reg, uint16_t val)
+{
+       if (i2c_smbus_write_word_data(chip->client, reg, val) < 0)
+               return -EIO;
+       else
+               return 0;
+}
+
+static int pca9539_read_reg(struct pca9539_chip *chip, int reg, uint16_t *val)
+{
+       int ret;
+
+       ret = i2c_smbus_read_word_data(chip->client, reg);
+       if (ret < 0) {
+               dev_err(&chip->client->dev, "failed reading register\n");
+               return -EIO;
+       }
+
+       *val = (uint16_t)ret;
+       return 0;
+}
+
+static int pca9539_gpio_direction_input(struct gpio_chip *gc, unsigned off)
+{
+       struct pca9539_chip *chip;
+       uint16_t reg_val;
+       int ret;
+
+       chip = container_of(gc, struct pca9539_chip, gpio_chip);
+
+       reg_val = chip->reg_direction | (1u << off);
+       ret = pca9539_write_reg(chip, PCA9539_DIRECTION, reg_val);
+       if (ret)
+               return ret;
+
+       chip->reg_direction = reg_val;
+       return 0;
+}
+
+static int pca9539_gpio_direction_output(struct gpio_chip *gc,
+               unsigned off, int val)
+{
+       struct pca9539_chip *chip;
+       uint16_t reg_val;
+       int ret;
+
+       chip = container_of(gc, struct pca9539_chip, gpio_chip);
+
+       /* set output level */
+       if (val)
+               reg_val = chip->reg_output | (1u << off);
+       else
+               reg_val = chip->reg_output & ~(1u << off);
+
+       ret = pca9539_write_reg(chip, PCA9539_OUTPUT, reg_val);
+       if (ret)
+               return ret;
+
+       chip->reg_output = reg_val;
+
+       /* then direction */
+       reg_val = chip->reg_direction & ~(1u << off);
+       ret = pca9539_write_reg(chip, PCA9539_DIRECTION, reg_val);
+       if (ret)
+               return ret;
+
+       chip->reg_direction = reg_val;
+       return 0;
+}
+
+static int pca9539_gpio_get_value(struct gpio_chip *gc, unsigned off)
+{
+       struct pca9539_chip *chip;
+       uint16_t reg_val;
+       int ret;
+
+       chip = container_of(gc, struct pca9539_chip, gpio_chip);
+
+       ret = pca9539_read_reg(chip, PCA9539_INPUT, &reg_val);
+       if (ret < 0) {
+               /* NOTE:  diagnostic already emitted; that's all we should
+                * do unless gpio_*_value_cansleep() calls become different
+                * from their nonsleeping siblings (and report faults).
+                */
+               return 0;
+       }
+
+       return (reg_val & (1u << off)) ? 1 : 0;
+}
+
+static void pca9539_gpio_set_value(struct gpio_chip *gc, unsigned off, int val)
+{
+       struct pca9539_chip *chip;
+       uint16_t reg_val;
+       int ret;
+
+       chip = container_of(gc, struct pca9539_chip, gpio_chip);
+
+       if (val)
+               reg_val = chip->reg_output | (1u << off);
+       else
+               reg_val = chip->reg_output & ~(1u << off);
+
+       ret = pca9539_write_reg(chip, PCA9539_OUTPUT, reg_val);
+       if (ret)
+               return;
+
+       chip->reg_output = reg_val;
+}
+
+static int pca9539_init_gpio(struct pca9539_chip *chip)
+{
+       struct gpio_chip *gc;
+
+       gc = &chip->gpio_chip;
+
+       gc->direction_input  = pca9539_gpio_direction_input;
+       gc->direction_output = pca9539_gpio_direction_output;
+       gc->get = pca9539_gpio_get_value;
+       gc->set = pca9539_gpio_set_value;
+
+       gc->base = chip->gpio_start;
+       gc->ngpio = NR_PCA9539_GPIOS;
+       gc->label = "pca9539";
+
+       return gpiochip_add(gc);
+}
+
+static int __devinit pca9539_probe(struct i2c_client *client)
+{
+       struct pca9539_platform_data *pdata;
+       struct pca9539_chip *chip;
+       int ret;
+
+       pdata = client->dev.platform_data;
+       if (pdata == NULL)
+               return -ENODEV;
+
+       chip = kzalloc(sizeof(struct pca9539_chip), GFP_KERNEL);
+       if (chip == NULL)
+               return -ENOMEM;
+
+       chip->client = client;
+
+       chip->gpio_start = pdata->gpio_base;
+
+       /* initialize cached registers from their original values.
+        * we can't share this chip with another i2c master.
+        */
+       ret = pca9539_read_reg(chip, PCA9539_OUTPUT, &chip->reg_output);
+       if (ret)
+               goto out_failed;
+
+       ret = pca9539_read_reg(chip, PCA9539_DIRECTION, &chip->reg_direction);
+       if (ret)
+               goto out_failed;
+
+       /* set platform specific polarity inversion */
+       ret = pca9539_write_reg(chip, PCA9539_INVERT, pdata->invert);
+       if (ret)
+               goto out_failed;
+
+       ret = pca9539_init_gpio(chip);
+       if (ret)
+               goto out_failed;
+
+       if (pdata->setup) {
+               ret = pdata->setup(client, chip->gpio_chip.base,
+                               chip->gpio_chip.ngpio, pdata->context);
+               if (ret < 0)
+                       dev_warn(&client->dev, "setup failed, %d\n", ret);
+       }
+
+       i2c_set_clientdata(client, chip);
+       return 0;
+
+out_failed:
+       kfree(chip);
+       return ret;
+}
+
+static int pca9539_remove(struct i2c_client *client)
+{
+       struct pca9539_platform_data *pdata = client->dev.platform_data;
+       struct pca9539_chip *chip = i2c_get_clientdata(client);
+       int ret = 0;
+
+       if (pdata->teardown) {
+               ret = pdata->teardown(client, chip->gpio_chip.base,
+                               chip->gpio_chip.ngpio, pdata->context);
+               if (ret < 0) {
+                       dev_err(&client->dev, "%s failed, %d\n",
+                                       "teardown", ret);
+                       return ret;
+               }
+       }
+
+       ret = gpiochip_remove(&chip->gpio_chip);
+       if (ret) {
+               dev_err(&client->dev, "%s failed, %d\n",
+                               "gpiochip_remove()", ret);
+               return ret;
+       }
+
+       kfree(chip);
+       return 0;
+}
+
+static struct i2c_driver pca9539_driver = {
+       .driver = {
+               .name   = "pca9539",
+       },
+       .probe          = pca9539_probe,
+       .remove         = pca9539_remove,
+};
+
+static int __init pca9539_init(void)
+{
+       return i2c_add_driver(&pca9539_driver);
+}
+module_init(pca9539_init);
+
+static void __exit pca9539_exit(void)
+{
+       i2c_del_driver(&pca9539_driver);
+}
+module_exit(pca9539_exit);
+
+MODULE_AUTHOR("eric miao <eric.miao@marvell.com>");
+MODULE_DESCRIPTION("GPIO expander driver for PCA9539");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpio/pcf857x.c b/drivers/gpio/pcf857x.c
new file mode 100644 (file)
index 0000000..c6b3b53
--- /dev/null
@@ -0,0 +1,330 @@
+/*
+ * pcf857x - driver for pcf857x, pca857x, and pca967x I2C GPIO expanders
+ *
+ * Copyright (C) 2007 David Brownell
+ *
+ * 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/slab.h>
+#include <linux/i2c.h>
+#include <linux/i2c/pcf857x.h>
+
+#include <asm/gpio.h>
+
+
+/*
+ * The pcf857x, pca857x, and pca967x chips only expose one read and one
+ * write register.  Writing a "one" bit (to match the reset state) lets
+ * that pin be used as an input; it's not an open-drain model, but acts
+ * a bit like one.  This is described as "quasi-bidirectional"; read the
+ * chip documentation for details.
+ *
+ * Many other I2C GPIO expander chips (like the pca953x models) have
+ * more complex register models and more conventional circuitry using
+ * push/pull drivers.  They often use the same 0x20..0x27 addresses as
+ * pcf857x parts, making the "legacy" I2C driver model problematic.
+ */
+struct pcf857x {
+       struct gpio_chip        chip;
+       struct i2c_client       *client;
+       unsigned                out;            /* software latch */
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* Talk to 8-bit I/O expander */
+
+static int pcf857x_input8(struct gpio_chip *chip, unsigned offset)
+{
+       struct pcf857x  *gpio = container_of(chip, struct pcf857x, chip);
+
+       gpio->out |= (1 << offset);
+       return i2c_smbus_write_byte(gpio->client, gpio->out);
+}
+
+static int pcf857x_get8(struct gpio_chip *chip, unsigned offset)
+{
+       struct pcf857x  *gpio = container_of(chip, struct pcf857x, chip);
+       s32             value;
+
+       value = i2c_smbus_read_byte(gpio->client);
+       return (value < 0) ? 0 : (value & (1 << offset));
+}
+
+static int pcf857x_output8(struct gpio_chip *chip, unsigned offset, int value)
+{
+       struct pcf857x  *gpio = container_of(chip, struct pcf857x, chip);
+       unsigned        bit = 1 << offset;
+
+       if (value)
+               gpio->out |= bit;
+       else
+               gpio->out &= ~bit;
+       return i2c_smbus_write_byte(gpio->client, gpio->out);
+}
+
+static void pcf857x_set8(struct gpio_chip *chip, unsigned offset, int value)
+{
+       pcf857x_output8(chip, offset, value);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* Talk to 16-bit I/O expander */
+
+static int i2c_write_le16(struct i2c_client *client, u16 word)
+{
+       u8 buf[2] = { word & 0xff, word >> 8, };
+       int status;
+
+       status = i2c_master_send(client, buf, 2);
+       return (status < 0) ? status : 0;
+}
+
+static int i2c_read_le16(struct i2c_client *client)
+{
+       u8 buf[2];
+       int status;
+
+       status = i2c_master_recv(client, buf, 2);
+       if (status < 0)
+               return status;
+       return (buf[1] << 8) | buf[0];
+}
+
+static int pcf857x_input16(struct gpio_chip *chip, unsigned offset)
+{
+       struct pcf857x  *gpio = container_of(chip, struct pcf857x, chip);
+
+       gpio->out |= (1 << offset);
+       return i2c_write_le16(gpio->client, gpio->out);
+}
+
+static int pcf857x_get16(struct gpio_chip *chip, unsigned offset)
+{
+       struct pcf857x  *gpio = container_of(chip, struct pcf857x, chip);
+       int             value;
+
+       value = i2c_read_le16(gpio->client);
+       return (value < 0) ? 0 : (value & (1 << offset));
+}
+
+static int pcf857x_output16(struct gpio_chip *chip, unsigned offset, int value)
+{
+       struct pcf857x  *gpio = container_of(chip, struct pcf857x, chip);
+       unsigned        bit = 1 << offset;
+
+       if (value)
+               gpio->out |= bit;
+       else
+               gpio->out &= ~bit;
+       return i2c_write_le16(gpio->client, gpio->out);
+}
+
+static void pcf857x_set16(struct gpio_chip *chip, unsigned offset, int value)
+{
+       pcf857x_output16(chip, offset, value);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int pcf857x_probe(struct i2c_client *client)
+{
+       struct pcf857x_platform_data    *pdata;
+       struct pcf857x                  *gpio;
+       int                             status;
+
+       pdata = client->dev.platform_data;
+       if (!pdata)
+               return -ENODEV;
+
+       /* Allocate, initialize, and register this gpio_chip. */
+       gpio = kzalloc(sizeof *gpio, GFP_KERNEL);
+       if (!gpio)
+               return -ENOMEM;
+
+       gpio->chip.base = pdata->gpio_base;
+       gpio->chip.can_sleep = 1;
+
+       /* NOTE:  the OnSemi jlc1562b is also largely compatible with
+        * these parts, notably for output.  It has a low-resolution
+        * DAC instead of pin change IRQs; and its inputs can be the
+        * result of comparators.
+        */
+
+       /* 8574 addresses are 0x20..0x27; 8574a uses 0x38..0x3f;
+        * 9670, 9672, 9764, and 9764a use quite a variety.
+        *
+        * NOTE: we don't distinguish here between *4 and *4a parts.
+        */
+       if (strcmp(client->name, "pcf8574") == 0
+                       || strcmp(client->name, "pca8574") == 0
+                       || strcmp(client->name, "pca9670") == 0
+                       || strcmp(client->name, "pca9672") == 0
+                       || strcmp(client->name, "pca9674") == 0
+                       ) {
+               gpio->chip.ngpio = 8;
+               gpio->chip.direction_input = pcf857x_input8;
+               gpio->chip.get = pcf857x_get8;
+               gpio->chip.direction_output = pcf857x_output8;
+               gpio->chip.set = pcf857x_set8;
+
+               if (!i2c_check_functionality(client->adapter,
+                               I2C_FUNC_SMBUS_BYTE))
+                       status = -EIO;
+
+               /* fail if there's no chip present */
+               else
+                       status = i2c_smbus_read_byte(client);
+
+       /* '75/'75c addresses are 0x20..0x27, just like the '74;
+        * the '75c doesn't have a current source pulling high.
+        * 9671, 9673, and 9765 use quite a variety of addresses.
+        *
+        * NOTE: we don't distinguish here between '75 and '75c parts.
+        */
+       } else if (strcmp(client->name, "pcf8575") == 0
+                       || strcmp(client->name, "pca8575") == 0
+                       || strcmp(client->name, "pca9671") == 0
+                       || strcmp(client->name, "pca9673") == 0
+                       || strcmp(client->name, "pca9675") == 0
+                       ) {
+               gpio->chip.ngpio = 16;
+               gpio->chip.direction_input = pcf857x_input16;
+               gpio->chip.get = pcf857x_get16;
+               gpio->chip.direction_output = pcf857x_output16;
+               gpio->chip.set = pcf857x_set16;
+
+               if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
+                       status = -EIO;
+
+               /* fail if there's no chip present */
+               else
+                       status = i2c_read_le16(client);
+
+       } else
+               status = -ENODEV;
+
+       if (status < 0)
+               goto fail;
+
+       gpio->chip.label = client->name;
+
+       gpio->client = client;
+       i2c_set_clientdata(client, gpio);
+
+       /* NOTE:  these chips have strange "quasi-bidirectional" I/O pins.
+        * We can't actually know whether a pin is configured (a) as output
+        * and driving the signal low, or (b) as input and reporting a low
+        * value ... without knowing the last value written since the chip
+        * came out of reset (if any).  We can't read the latched output.
+        *
+        * In short, the only reliable solution for setting up pin direction
+        * is to do it explicitly.  The setup() method can do that, but it
+        * may cause transient glitching since it can't know the last value
+        * written (some pins may need to be driven low).
+        *
+        * Using pdata->n_latch avoids that trouble.  When left initialized
+        * to zero, our software copy of the "latch" then matches the chip's
+        * all-ones reset state.  Otherwise it flags pins to be driven low.
+        */
+       gpio->out = ~pdata->n_latch;
+
+       status = gpiochip_add(&gpio->chip);
+       if (status < 0)
+               goto fail;
+
+       /* NOTE: these chips can issue "some pin-changed" IRQs, which we
+        * don't yet even try to use.  Among other issues, the relevant
+        * genirq state isn't available to modular drivers; and most irq
+        * methods can't be called from sleeping contexts.
+        */
+
+       dev_info(&client->dev, "gpios %d..%d on a %s%s\n",
+                       gpio->chip.base,
+                       gpio->chip.base + gpio->chip.ngpio - 1,
+                       client->name,
+                       client->irq ? " (irq ignored)" : "");
+
+       /* Let platform code set up the GPIOs and their users.
+        * Now is the first time anyone could use them.
+        */
+       if (pdata->setup) {
+               status = pdata->setup(client,
+                               gpio->chip.base, gpio->chip.ngpio,
+                               pdata->context);
+               if (status < 0)
+                       dev_warn(&client->dev, "setup --> %d\n", status);
+       }
+
+       return 0;
+
+fail:
+       dev_dbg(&client->dev, "probe error %d for '%s'\n",
+                       status, client->name);
+       kfree(gpio);
+       return status;
+}
+
+static int pcf857x_remove(struct i2c_client *client)
+{
+       struct pcf857x_platform_data    *pdata = client->dev.platform_data;
+       struct pcf857x                  *gpio = i2c_get_clientdata(client);
+       int                             status = 0;
+
+       if (pdata->teardown) {
+               status = pdata->teardown(client,
+                               gpio->chip.base, gpio->chip.ngpio,
+                               pdata->context);
+               if (status < 0) {
+                       dev_err(&client->dev, "%s --> %d\n",
+                                       "teardown", status);
+                       return status;
+               }
+       }
+
+       status = gpiochip_remove(&gpio->chip);
+       if (status == 0)
+               kfree(gpio);
+       else
+               dev_err(&client->dev, "%s --> %d\n", "remove", status);
+       return status;
+}
+
+static struct i2c_driver pcf857x_driver = {
+       .driver = {
+               .name   = "pcf857x",
+               .owner  = THIS_MODULE,
+       },
+       .probe  = pcf857x_probe,
+       .remove = pcf857x_remove,
+};
+
+static int __init pcf857x_init(void)
+{
+       return i2c_add_driver(&pcf857x_driver);
+}
+module_init(pcf857x_init);
+
+static void __exit pcf857x_exit(void)
+{
+       i2c_del_driver(&pcf857x_driver);
+}
+module_exit(pcf857x_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("David Brownell");
index e6c4a2b762ec955497864f860815fb027d9aa275..f5e7a70da831b1c54b51e081bdf0c1a0bc6ef1f8 100644 (file)
@@ -492,7 +492,7 @@ static __init int scx200_create_pci(const char *text, struct pci_dev *pdev,
        iface->pdev = pdev;
        iface->bar = bar;
 
-       rc = pci_enable_device_bars(iface->pdev, 1 << iface->bar);
+       rc = pci_enable_device_io(iface->pdev);
        if (rc)
                goto errout_free;
 
index bd7082c2443dbd5336553ccbb18bca9c62ec7fea..b21593f93586adc191cf43178c06d1166bf0ed6b 100644 (file)
@@ -54,8 +54,8 @@ config PCF8575
          hardware.  If unsure, say N.
 
 config SENSORS_PCA9539
-       tristate "Philips PCA9539 16-bit I/O port"
-       depends on EXPERIMENTAL
+       tristate "Philips PCA9539 16-bit I/O port (DEPRECATED)"
+       depends on EXPERIMENTAL && GPIO_PCA9539 = "n"
        help
          If you say yes here you get support for the Philips PCA9539
          16-bit I/O port.
@@ -63,6 +63,9 @@ config SENSORS_PCA9539
          This driver can also be built as a module.  If so, the module
          will be called pca9539.
 
+         This driver is deprecated and will be dropped soon. Use
+         drivers/gpio/pca9539.c instead.
+
 config SENSORS_PCF8591
        tristate "Philips PCF8591"
        depends on EXPERIMENTAL
index 64df55e20ab53fb90673fa507b42289ccabbb3d4..ab8fb257528ed51cb4e9bac0abb0710ce7543fbb 100644 (file)
@@ -206,9 +206,17 @@ config BLK_DEV_IDECD
          To compile this driver as a module, choose M here: the
          module will be called ide-cd.
 
+config BLK_DEV_IDECD_VERBOSE_ERRORS
+       bool "Verbose error logging for IDE/ATAPI CDROM driver" if EMBEDDED
+       depends on BLK_DEV_IDECD
+       default y
+       help
+         Turn this on to have the driver print out the meanings of the
+         ATAPI error codes.  This will use up additional 8kB of kernel-space
+         memory, though.
+
 config BLK_DEV_IDETAPE
-       tristate "Include IDE/ATAPI TAPE support (EXPERIMENTAL)"
-       depends on EXPERIMENTAL
+       tristate "Include IDE/ATAPI TAPE support"
        help
          If you have an IDE tape drive using the ATAPI protocol, say Y.
          ATAPI is a newer protocol used by IDE tape and CD-ROM drives,
@@ -617,8 +625,8 @@ config BLK_DEV_SC1200
        tristate "National SCx200 chipset support"
        select BLK_DEV_IDEDMA_PCI
        help
-         This driver adds support for the built in IDE on the National
-         SCx200 series of embedded x86 "Geode" systems
+         This driver adds support for the on-board IDE controller on the
+         National SCx200 series of embedded x86 "Geode" systems.
 
 config BLK_DEV_PIIX
        tristate "Intel PIIXn chipsets support"
@@ -793,22 +801,22 @@ config BLK_DEV_CELLEB
        depends on PPC_CELLEB
        select BLK_DEV_IDEDMA_PCI
        help
-         This driver provides support for the built-in IDE controller on
+         This driver provides support for the on-board IDE controller on
          Toshiba Cell Reference Board.
          If unsure, say Y.
 
 endif
 
 config BLK_DEV_IDE_PMAC
-       tristate "Builtin PowerMac IDE support"
+       tristate "PowerMac on-board IDE support"
        depends on PPC_PMAC && IDE=y && BLK_DEV_IDE=y
        help
-         This driver provides support for the built-in IDE controller on
+         This driver provides support for the on-board IDE controller on
          most of the recent Apple Power Macintoshes and PowerBooks.
          If unsure, say Y.
 
 config BLK_DEV_IDE_PMAC_ATA100FIRST
-       bool "Probe internal ATA/100 (Kauai) first"
+       bool "Probe on-board ATA/100 (Kauai) first"
        depends on BLK_DEV_IDE_PMAC
        help
          This option will cause the ATA/100 controller found in UniNorth2
@@ -823,7 +831,7 @@ config BLK_DEV_IDEDMA_PMAC
        depends on BLK_DEV_IDE_PMAC
        select BLK_DEV_IDEDMA_PCI
        help
-         This option allows the driver for the built-in IDE controller on
+         This option allows the driver for the on-board IDE controller on
          Power Macintoshes and PowerBooks to use DMA (direct memory access)
          to transfer data to and from memory.  Saying Y is safe and improves
          performance.
@@ -934,7 +942,7 @@ config BLK_DEV_GAYLE
        help
          This is the IDE driver for the Amiga Gayle IDE interface. It supports
          both the `A1200 style' and `A4000 style' of the Gayle IDE interface,
-         This includes builtin IDE interfaces on some Amiga models (A600,
+         This includes on-board IDE interfaces on some Amiga models (A600,
          A1200, A4000, and A4000T), and IDE interfaces on the Zorro expansion
          bus (M-Tech E-Matrix 530 expansion card).
          Say Y if you have an Amiga with a Gayle IDE interface and want to use
@@ -948,10 +956,10 @@ config BLK_DEV_IDEDOUBLER
        depends on BLK_DEV_GAYLE && EXPERIMENTAL
        ---help---
          This driver provides support for the so-called `IDE doublers' (made
-         by various manufacturers, e.g. Eyetech) that can be connected to the
-         builtin IDE interface of some Amiga models. Using such an IDE
-         doubler, you can connect up to four instead of two IDE devices on
-         the Amiga's builtin IDE interface.
+         by various manufacturers, e.g. Eyetech) that can be connected to
+         the on-board IDE interface of some Amiga models. Using such an IDE
+         doubler, you can connect up to four instead of two IDE devices to
+         the Amiga's on-board IDE interface.
 
          Note that the normal Amiga Gayle IDE driver may not work correctly
          if you have an IDE doubler and don't enable this driver!
@@ -963,9 +971,9 @@ config BLK_DEV_BUDDHA
        tristate "Buddha/Catweasel/X-Surf IDE interface support (EXPERIMENTAL)"
        depends on ZORRO && EXPERIMENTAL
        help
-         This is the IDE driver for the IDE interfaces on the Buddha, 
-         Catweasel and X-Surf expansion boards.  It supports up to two interfaces 
-         on the Buddha, three on the Catweasel and two on the X-Surf.
+         This is the IDE driver for the IDE interfaces on the Buddha, Catweasel
+         and X-Surf expansion boards.  It supports up to two interfaces on the
+         Buddha, three on the Catweasel and two on the X-Surf.
 
          Say Y if you have a Buddha or Catweasel expansion board and want to
          use IDE devices (hard disks, CD-ROM drives, etc.) that are connected
@@ -975,23 +983,23 @@ config BLK_DEV_FALCON_IDE
        tristate "Falcon IDE interface support"
        depends on ATARI
        help
-         This is the IDE driver for the builtin IDE interface on the Atari
+         This is the IDE driver for the on-board IDE interface on the Atari
          Falcon. Say Y if you have a Falcon and want to use IDE devices (hard
-         disks, CD-ROM drives, etc.) that are connected to the builtin IDE
+         disks, CD-ROM drives, etc.) that are connected to the on-board IDE
          interface.
 
 config BLK_DEV_MAC_IDE
        tristate "Macintosh Quadra/Powerbook IDE interface support"
        depends on MAC
        help
-         This is the IDE driver for the builtin IDE interface on some m68k
+         This is the IDE driver for the on-board IDE interface on some m68k
          Macintosh models. It supports both the `Quadra style' (used in
          Quadra/ Centris 630 and Performa 588 models) and `Powerbook style'
          (used in the Powerbook 150 and 190 models) IDE interface.
 
          Say Y if you have such an Macintosh model and want to use IDE
          devices (hard disks, CD-ROM drives, etc.) that are connected to the
-         builtin IDE interface.
+         on-board IDE interface.
 
 config BLK_DEV_Q40IDE
        tristate "Q40/Q60 IDE interface support"
@@ -1001,6 +1009,15 @@ config BLK_DEV_Q40IDE
          normally be on; disable it only if you are running a custom hard
          drive subsystem through an expansion card.
 
+config BLK_DEV_PALMCHIP_BK3710
+       tristate "Palmchip bk3710 IDE controller support"
+       depends on ARCH_DAVINCI
+       select BLK_DEV_IDEDMA_PCI
+       help
+         Say Y here if you want to support the onchip IDE controller on the
+         TI DaVinci SoC
+
+
 config BLK_DEV_MPC8xx_IDE
        tristate "MPC8xx IDE support"
        depends on 8xx && (LWMON || IVMS8 || IVML24 || TQM8xxL) && IDE=y && BLK_DEV_IDE=y && !PPC_MERGE
@@ -1062,8 +1079,8 @@ config BLK_DEV_ALI14XX
          boot parameter.  It enables support for the secondary IDE interface
          of the ALI M1439/1443/1445/1487/1489 chipsets, and permits faster
          I/O speeds to be set as well.  See the files
-         <file:Documentation/ide.txt> and <file:drivers/ide/legacy/ali14xx.c> for
-         more info.
+         <file:Documentation/ide.txt> and <file:drivers/ide/legacy/ali14xx.c>
+         for more info.
 
 config BLK_DEV_DTC2278
        tristate "DTC-2278 support"
@@ -1088,8 +1105,8 @@ config BLK_DEV_QD65XX
        help
          This driver is enabled at runtime using the "qd65xx.probe" kernel
          boot parameter.  It permits faster I/O speeds to be set.  See the
-         <file:Documentation/ide.txt> and <file:drivers/ide/legacy/qd65xx.c> for
-         more info.
+         <file:Documentation/ide.txt> and <file:drivers/ide/legacy/qd65xx.c>
+         for more info.
 
 config BLK_DEV_UMC8672
        tristate "UMC-8672 support"
index 0d2da89d15cff8f989f4436f5b9f1e8618e9b05a..a4a4323be911b3761b1c6642c893576e3824c4d0 100644 (file)
@@ -40,8 +40,10 @@ obj-$(CONFIG_BLK_DEV_IDEPNP)         += ide-pnp.o
 obj-$(CONFIG_IDE_H8300)                        += h8300/
 obj-$(CONFIG_IDE_GENERIC)              += ide-generic.o
 
+ide-cd_mod-y += ide-cd.o ide-cd_ioctl.o ide-cd_verbose.o
+
 obj-$(CONFIG_BLK_DEV_IDEDISK)          += ide-disk.o
-obj-$(CONFIG_BLK_DEV_IDECD)            += ide-cd.o
+obj-$(CONFIG_BLK_DEV_IDECD)            += ide-cd_mod.o
 obj-$(CONFIG_BLK_DEV_IDETAPE)          += ide-tape.o
 obj-$(CONFIG_BLK_DEV_IDEFLOPPY)                += ide-floppy.o
 
index 5f63ad216862e50fd1d583384cc61a83d2dd182f..936e7b0237f5499fe0305845679c12a96d025d16 100644 (file)
@@ -2,6 +2,7 @@
 obj-$(CONFIG_BLK_DEV_IDE_ICSIDE)       += icside.o
 obj-$(CONFIG_BLK_DEV_IDE_RAPIDE)       += rapide.o
 obj-$(CONFIG_BLK_DEV_IDE_BAST)         += bast-ide.o
+obj-$(CONFIG_BLK_DEV_PALMCHIP_BK3710)  += palm_bk3710.o
 
 ifeq ($(CONFIG_IDE_ARM), m)
        obj-m += ide_arm.o
index 45bf9c825f2b11c7afd2fd4d65d45c49a0dfaa45..0e7574c0ee60bcbfa48c75ef8f3843b71c44bac5 100644 (file)
@@ -1,5 +1,4 @@
-/* linux/drivers/ide/arm/bast-ide.c
- *
+/*
  * Copyright (c) 2003-2004 Simtec Electronics
  *  Ben Dooks <ben@simtec.co.uk>
  *
@@ -29,8 +28,10 @@ static int __init
 bastide_register(unsigned int base, unsigned int aux, int irq,
                 ide_hwif_t **hwif)
 {
+       ide_hwif_t *hwif;
        hw_regs_t hw;
        int i;
+       u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
 
        memset(&hw, 0, sizeof(hw));
 
@@ -45,8 +46,24 @@ bastide_register(unsigned int base, unsigned int aux, int irq,
        hw.io_ports[IDE_CONTROL_OFFSET] = aux + (6 * 0x20);
        hw.irq = irq;
 
-       ide_register_hw(&hw, NULL, hwif);
+       hwif = ide_deprecated_find_port(hw.io_ports[IDE_DATA_OFFSET]);
+       if (hwif == NULL)
+               goto out;
+
+       i = hwif->index;
+
+       if (hwif->present)
+               ide_unregister(i, 0, 0);
+       else if (!hwif->hold)
+               ide_init_port_data(hwif, i);
+
+       ide_init_port_hw(hwif, &hw);
+       hwif->quirkproc = NULL;
+
+       idx[0] = i;
 
+       ide_device_add(idx, NULL);
+out:
        return 0;
 }
 
index 8a5c7205b77c7a4176406449c90272fc4fd9f256..e816b0ffcfe647a1899161225708014271316517 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * linux/drivers/ide/arm/icside.c
- *
  * Copyright (c) 1996-2004 Russell King.
  *
  * Please note that this platform does not support 32-bit IDE IO.
@@ -71,8 +69,6 @@ struct icside_state {
        void __iomem *irq_port;
        void __iomem *ioc_base;
        unsigned int type;
-       /* parent device... until the IDE core gets one of its own */
-       struct device *dev;
        ide_hwif_t *hwif[2];
 };
 
@@ -206,23 +202,6 @@ static void icside_maskproc(ide_drive_t *drive, int mask)
  * interfaces use the same IRQ, which should guarantee this.
  */
 
-static void icside_build_sglist(ide_drive_t *drive, struct request *rq)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       struct icside_state *state = hwif->hwif_data;
-       struct scatterlist *sg = hwif->sg_table;
-
-       ide_map_sg(drive, rq);
-
-       if (rq_data_dir(rq) == READ)
-               hwif->sg_dma_direction = DMA_FROM_DEVICE;
-       else
-               hwif->sg_dma_direction = DMA_TO_DEVICE;
-
-       hwif->sg_nents = dma_map_sg(state->dev, sg, hwif->sg_nents,
-                                   hwif->sg_dma_direction);
-}
-
 /*
  * Configure the IOMD to give the appropriate timings for the transfer
  * mode being requested.  We take the advice of the ATA standards, and
@@ -294,33 +273,32 @@ static void icside_dma_host_set(ide_drive_t *drive, int on)
 static int icside_dma_end(ide_drive_t *drive)
 {
        ide_hwif_t *hwif = HWIF(drive);
-       struct icside_state *state = hwif->hwif_data;
+       struct expansion_card *ec = ECARD_DEV(hwif->dev);
 
        drive->waiting_for_dma = 0;
 
-       disable_dma(ECARD_DEV(state->dev)->dma);
+       disable_dma(ec->dma);
 
        /* Teardown mappings after DMA has completed. */
-       dma_unmap_sg(state->dev, hwif->sg_table, hwif->sg_nents,
-                    hwif->sg_dma_direction);
+       ide_destroy_dmatable(drive);
 
-       return get_dma_residue(ECARD_DEV(state->dev)->dma) != 0;
+       return get_dma_residue(ec->dma) != 0;
 }
 
 static void icside_dma_start(ide_drive_t *drive)
 {
        ide_hwif_t *hwif = HWIF(drive);
-       struct icside_state *state = hwif->hwif_data;
+       struct expansion_card *ec = ECARD_DEV(hwif->dev);
 
        /* We can not enable DMA on both channels simultaneously. */
-       BUG_ON(dma_channel_active(ECARD_DEV(state->dev)->dma));
-       enable_dma(ECARD_DEV(state->dev)->dma);
+       BUG_ON(dma_channel_active(ec->dma));
+       enable_dma(ec->dma);
 }
 
 static int icside_dma_setup(ide_drive_t *drive)
 {
        ide_hwif_t *hwif = HWIF(drive);
-       struct icside_state *state = hwif->hwif_data;
+       struct expansion_card *ec = ECARD_DEV(hwif->dev);
        struct request *rq = hwif->hwgroup->rq;
        unsigned int dma_mode;
 
@@ -332,9 +310,9 @@ static int icside_dma_setup(ide_drive_t *drive)
        /*
         * We can not enable DMA on both channels.
         */
-       BUG_ON(dma_channel_active(ECARD_DEV(state->dev)->dma));
+       BUG_ON(dma_channel_active(ec->dma));
 
-       icside_build_sglist(drive, rq);
+       hwif->sg_nents = ide_build_sglist(drive, rq);
 
        /*
         * Ensure that we have the right interrupt routed.
@@ -349,14 +327,14 @@ static int icside_dma_setup(ide_drive_t *drive)
        /*
         * Select the correct timing for this drive.
         */
-       set_dma_speed(ECARD_DEV(state->dev)->dma, drive->drive_data);
+       set_dma_speed(ec->dma, drive->drive_data);
 
        /*
         * Tell the DMA engine about the SG table and
         * data direction.
         */
-       set_dma_sg(ECARD_DEV(state->dev)->dma, hwif->sg_table, hwif->sg_nents);
-       set_dma_mode(ECARD_DEV(state->dev)->dma, dma_mode);
+       set_dma_sg(ec->dma, hwif->sg_table, hwif->sg_nents);
+       set_dma_mode(ec->dma, dma_mode);
 
        drive->waiting_for_dma = 1;
 
@@ -387,7 +365,7 @@ static void icside_dma_timeout(ide_drive_t *drive)
        if (icside_dma_test_irq(drive))
                return;
 
-       ide_dump_status(drive, "DMA timeout", HWIF(drive)->INB(IDE_STATUS_REG));
+       ide_dump_status(drive, "DMA timeout", ide_read_status(drive));
 
        icside_dma_end(drive);
 }
@@ -399,9 +377,6 @@ static void icside_dma_lost_irq(ide_drive_t *drive)
 
 static void icside_dma_init(ide_hwif_t *hwif)
 {
-       hwif->mwdma_mask        = 7; /* MW0..2 */
-       hwif->swdma_mask        = 7; /* SW0..2 */
-
        hwif->dmatable_cpu      = NULL;
        hwif->dmatable_dma      = 0;
        hwif->set_dma_mode      = icside_set_dma_mode;
@@ -444,6 +419,7 @@ icside_setup(void __iomem *base, struct cardinfo *info, struct expansion_card *e
                hwif->noprobe = 0;
                hwif->chipset = ide_acorn;
                hwif->gendev.parent = &ec->dev;
+               hwif->dev = &ec->dev;
        }
 
        return hwif;
@@ -480,11 +456,19 @@ icside_register_v5(struct icside_state *state, struct expansion_card *ec)
 
        idx[0] = hwif->index;
 
-       ide_device_add(idx);
+       ide_device_add(idx, NULL);
 
        return 0;
 }
 
+static const struct ide_port_info icside_v6_port_info __initdata = {
+       .host_flags             = IDE_HFLAG_SERIALIZE |
+                                 IDE_HFLAG_NO_DMA | /* no SFF-style DMA */
+                                 IDE_HFLAG_NO_AUTOTUNE,
+       .mwdma_mask             = ATA_MWDMA2,
+       .swdma_mask             = ATA_SWDMA2,
+};
+
 static int __init
 icside_register_v6(struct icside_state *state, struct expansion_card *ec)
 {
@@ -493,6 +477,7 @@ icside_register_v6(struct icside_state *state, struct expansion_card *ec)
        unsigned int sel = 0;
        int ret;
        u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
+       struct ide_port_info d = icside_v6_port_info;
 
        ioc_base = ecardm_iomap(ec, ECARD_RES_IOCFAST, 0, 0);
        if (!ioc_base) {
@@ -542,30 +527,25 @@ icside_register_v6(struct icside_state *state, struct expansion_card *ec)
        state->hwif[1]    = mate;
 
        hwif->maskproc    = icside_maskproc;
-       hwif->channel     = 0;
        hwif->hwif_data   = state;
-       hwif->mate        = mate;
-       hwif->serialized  = 1;
        hwif->config_data = (unsigned long)ioc_base;
        hwif->select_data = sel;
 
        mate->maskproc    = icside_maskproc;
-       mate->channel     = 1;
        mate->hwif_data   = state;
-       mate->mate        = hwif;
-       mate->serialized  = 1;
        mate->config_data = (unsigned long)ioc_base;
        mate->select_data = sel | 1;
 
        if (ec->dma != NO_DMA && !request_dma(ec->dma, hwif->name)) {
                icside_dma_init(hwif);
                icside_dma_init(mate);
-       }
+       } else
+               d.mwdma_mask = d.swdma_mask = 0;
 
        idx[0] = hwif->index;
        idx[1] = mate->index;
 
-       ide_device_add(idx);
+       ide_device_add(idx, &d);
 
        return 0;
 
@@ -591,7 +571,6 @@ icside_probe(struct expansion_card *ec, const struct ecard_id *id)
        }
 
        state->type     = ICS_TYPE_NOTYPE;
-       state->dev      = &ec->dev;
 
        idmem = ecardm_iomap(ec, ECARD_RES_IOCFAST, 0, 0);
        if (idmem) {
index 60f2497542c05048d9a3f9b5e1a780d8717426f3..43a70e91363e0b2eed2cdde591a4ffb345c388f3 100644 (file)
@@ -39,7 +39,7 @@ static int __init ide_arm_init(void)
                ide_init_port_hw(hwif, &hw);
                idx[0] = hwif->index;
 
-               ide_device_add(idx);
+               ide_device_add(idx, NULL);
        }
 
        return 0;
diff --git a/drivers/ide/arm/palm_bk3710.c b/drivers/ide/arm/palm_bk3710.c
new file mode 100644 (file)
index 0000000..c306997
--- /dev/null
@@ -0,0 +1,395 @@
+/*
+ * Palmchip bk3710 IDE controller
+ *
+ * Copyright (C) 2006 Texas Instruments.
+ * Copyright (C) 2007 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 as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * ----------------------------------------------------------------------------
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+
+/* Offset of the primary interface registers */
+#define IDE_PALM_ATA_PRI_REG_OFFSET 0x1F0
+
+/* Primary Control Offset */
+#define IDE_PALM_ATA_PRI_CTL_OFFSET 0x3F6
+
+/*
+ * PalmChip 3710 IDE Controller UDMA timing structure Definition
+ */
+struct palm_bk3710_udmatiming {
+       unsigned int rptime;    /* Ready to pause time  */
+       unsigned int cycletime; /* Cycle Time           */
+};
+
+#define BK3710_BMICP           0x00
+#define BK3710_BMISP           0x02
+#define BK3710_BMIDTP          0x04
+#define BK3710_BMICS           0x08
+#define BK3710_BMISS           0x0A
+#define BK3710_BMIDTS          0x0C
+#define BK3710_IDETIMP         0x40
+#define BK3710_IDETIMS         0x42
+#define BK3710_SIDETIM         0x44
+#define BK3710_SLEWCTL         0x45
+#define BK3710_IDESTATUS       0x47
+#define BK3710_UDMACTL         0x48
+#define BK3710_UDMATIM         0x4A
+#define BK3710_MISCCTL         0x50
+#define BK3710_REGSTB          0x54
+#define BK3710_REGRCVR         0x58
+#define BK3710_DATSTB          0x5C
+#define BK3710_DATRCVR         0x60
+#define BK3710_DMASTB          0x64
+#define BK3710_DMARCVR         0x68
+#define BK3710_UDMASTB         0x6C
+#define BK3710_UDMATRP         0x70
+#define BK3710_UDMAENV         0x74
+#define BK3710_IORDYTMP                0x78
+#define BK3710_IORDYTMS                0x7C
+
+#include "../ide-timing.h"
+
+static long ide_palm_clk;
+
+static const struct palm_bk3710_udmatiming palm_bk3710_udmatimings[6] = {
+       {160, 240},             /* UDMA Mode 0 */
+       {125, 160},             /* UDMA Mode 1 */
+       {100, 120},             /* UDMA Mode 2 */
+       {100, 90},              /* UDMA Mode 3 */
+       {85,  60},              /* UDMA Mode 4 */
+};
+
+static struct clk *ideclkp;
+
+static void palm_bk3710_setudmamode(void __iomem *base, unsigned int dev,
+                                   unsigned int mode)
+{
+       u8 tenv, trp, t0;
+       u32 val32;
+       u16 val16;
+
+       /* DMA Data Setup */
+       t0 = (palm_bk3710_udmatimings[mode].cycletime + ide_palm_clk - 1)
+                       / ide_palm_clk - 1;
+       tenv = (20 + ide_palm_clk - 1) / ide_palm_clk - 1;
+       trp = (palm_bk3710_udmatimings[mode].rptime + ide_palm_clk - 1)
+                       / ide_palm_clk - 1;
+
+       /* udmatim Register */
+       val16 = readw(base + BK3710_UDMATIM) & (dev ? 0xFF0F : 0xFFF0);
+       val16 |= (mode << (dev ? 4 : 0));
+       writew(val16, base + BK3710_UDMATIM);
+
+       /* udmastb Ultra DMA Access Strobe Width */
+       val32 = readl(base + BK3710_UDMASTB) & (0xFF << (dev ? 0 : 8));
+       val32 |= (t0 << (dev ? 8 : 0));
+       writel(val32, base + BK3710_UDMASTB);
+
+       /* udmatrp Ultra DMA Ready to Pause Time */
+       val32 = readl(base + BK3710_UDMATRP) & (0xFF << (dev ? 0 : 8));
+       val32 |= (trp << (dev ? 8 : 0));
+       writel(val32, base + BK3710_UDMATRP);
+
+       /* udmaenv Ultra DMA envelop Time */
+       val32 = readl(base + BK3710_UDMAENV) & (0xFF << (dev ? 0 : 8));
+       val32 |= (tenv << (dev ? 8 : 0));
+       writel(val32, base + BK3710_UDMAENV);
+
+       /* Enable UDMA for Device */
+       val16 = readw(base + BK3710_UDMACTL) | (1 << dev);
+       writew(val16, base + BK3710_UDMACTL);
+}
+
+static void palm_bk3710_setdmamode(void __iomem *base, unsigned int dev,
+                                  unsigned short min_cycle,
+                                  unsigned int mode)
+{
+       u8 td, tkw, t0;
+       u32 val32;
+       u16 val16;
+       struct ide_timing *t;
+       int cycletime;
+
+       t = ide_timing_find_mode(mode);
+       cycletime = max_t(int, t->cycle, min_cycle);
+
+       /* DMA Data Setup */
+       t0 = (cycletime + ide_palm_clk - 1) / ide_palm_clk;
+       td = (t->active + ide_palm_clk - 1) / ide_palm_clk;
+       tkw = t0 - td - 1;
+       td -= 1;
+
+       val32 = readl(base + BK3710_DMASTB) & (0xFF << (dev ? 0 : 8));
+       val32 |= (td << (dev ? 8 : 0));
+       writel(val32, base + BK3710_DMASTB);
+
+       val32 = readl(base + BK3710_DMARCVR) & (0xFF << (dev ? 0 : 8));
+       val32 |= (tkw << (dev ? 8 : 0));
+       writel(val32, base + BK3710_DMARCVR);
+
+       /* Disable UDMA for Device */
+       val16 = readw(base + BK3710_UDMACTL) & ~(1 << dev);
+       writew(val16, base + BK3710_UDMACTL);
+}
+
+static void palm_bk3710_setpiomode(void __iomem *base, ide_drive_t *mate,
+                                  unsigned int dev, unsigned int cycletime,
+                                  unsigned int mode)
+{
+       u8 t2, t2i, t0;
+       u32 val32;
+       struct ide_timing *t;
+
+       /* PIO Data Setup */
+       t0 = (cycletime + ide_palm_clk - 1) / ide_palm_clk;
+       t2 = (ide_timing_find_mode(XFER_PIO_0 + mode)->active +
+             ide_palm_clk - 1) / ide_palm_clk;
+
+       t2i = t0 - t2 - 1;
+       t2 -= 1;
+
+       val32 = readl(base + BK3710_DATSTB) & (0xFF << (dev ? 0 : 8));
+       val32 |= (t2 << (dev ? 8 : 0));
+       writel(val32, base + BK3710_DATSTB);
+
+       val32 = readl(base + BK3710_DATRCVR) & (0xFF << (dev ? 0 : 8));
+       val32 |= (t2i << (dev ? 8 : 0));
+       writel(val32, base + BK3710_DATRCVR);
+
+       if (mate && mate->present) {
+               u8 mode2 = ide_get_best_pio_mode(mate, 255, 4);
+
+               if (mode2 < mode)
+                       mode = mode2;
+       }
+
+       /* TASKFILE Setup */
+       t = ide_timing_find_mode(XFER_PIO_0 + mode);
+       t0 = (t->cyc8b + ide_palm_clk - 1) / ide_palm_clk;
+       t2 = (t->act8b + ide_palm_clk - 1) / ide_palm_clk;
+
+       t2i = t0 - t2 - 1;
+       t2 -= 1;
+
+       val32 = readl(base + BK3710_REGSTB) & (0xFF << (dev ? 0 : 8));
+       val32 |= (t2 << (dev ? 8 : 0));
+       writel(val32, base + BK3710_REGSTB);
+
+       val32 = readl(base + BK3710_REGRCVR) & (0xFF << (dev ? 0 : 8));
+       val32 |= (t2i << (dev ? 8 : 0));
+       writel(val32, base + BK3710_REGRCVR);
+}
+
+static void palm_bk3710_set_dma_mode(ide_drive_t *drive, u8 xferspeed)
+{
+       int is_slave = drive->dn & 1;
+       void __iomem *base = (void *)drive->hwif->dma_base;
+
+       if (xferspeed >= XFER_UDMA_0) {
+               palm_bk3710_setudmamode(base, is_slave,
+                                       xferspeed - XFER_UDMA_0);
+       } else {
+               palm_bk3710_setdmamode(base, is_slave, drive->id->eide_dma_min,
+                                      xferspeed);
+       }
+}
+
+static void palm_bk3710_set_pio_mode(ide_drive_t *drive, u8 pio)
+{
+       unsigned int cycle_time;
+       int is_slave = drive->dn & 1;
+       ide_drive_t *mate;
+       void __iomem *base = (void *)drive->hwif->dma_base;
+
+       /*
+        * Obtain the drive PIO data for tuning the Palm Chip registers
+        */
+       cycle_time = ide_pio_cycle_time(drive, pio);
+       mate = ide_get_paired_drive(drive);
+       palm_bk3710_setpiomode(base, mate, is_slave, cycle_time, pio);
+}
+
+static void __devinit palm_bk3710_chipinit(void __iomem *base)
+{
+       /*
+        * enable the reset_en of ATA controller so that when ata signals
+        * are brought out, by writing into device config. at that
+        * time por_n signal should not be 'Z' and have a stable value.
+        */
+       writel(0x0300, base + BK3710_MISCCTL);
+
+       /* wait for some time and deassert the reset of ATA Device. */
+       mdelay(100);
+
+       /* Deassert the Reset */
+       writel(0x0200, base + BK3710_MISCCTL);
+
+       /*
+        * Program the IDETIMP Register Value based on the following assumptions
+        *
+        * (ATA_IDETIMP_IDEEN           , ENABLE ) |
+        * (ATA_IDETIMP_SLVTIMEN        , DISABLE) |
+        * (ATA_IDETIMP_RDYSMPL         , 70NS)    |
+        * (ATA_IDETIMP_RDYRCVRY        , 50NS)    |
+        * (ATA_IDETIMP_DMAFTIM1        , PIOCOMP) |
+        * (ATA_IDETIMP_PREPOST1        , DISABLE) |
+        * (ATA_IDETIMP_RDYSEN1         , DISABLE) |
+        * (ATA_IDETIMP_PIOFTIM1        , DISABLE) |
+        * (ATA_IDETIMP_DMAFTIM0        , PIOCOMP) |
+        * (ATA_IDETIMP_PREPOST0        , DISABLE) |
+        * (ATA_IDETIMP_RDYSEN0         , DISABLE) |
+        * (ATA_IDETIMP_PIOFTIM0        , DISABLE)
+        */
+       writew(0xB388, base + BK3710_IDETIMP);
+
+       /*
+        * Configure  SIDETIM  Register
+        * (ATA_SIDETIM_RDYSMPS1        ,120NS ) |
+        * (ATA_SIDETIM_RDYRCYS1        ,120NS )
+        */
+       writeb(0, base + BK3710_SIDETIM);
+
+       /*
+        * UDMACTL Ultra-ATA DMA Control
+        * (ATA_UDMACTL_UDMAP1  , 0 ) |
+        * (ATA_UDMACTL_UDMAP0  , 0 )
+        *
+        */
+       writew(0, base + BK3710_UDMACTL);
+
+       /*
+        * MISCCTL Miscellaneous Conrol Register
+        * (ATA_MISCCTL_RSTMODEP        , 1) |
+        * (ATA_MISCCTL_RESETP          , 0) |
+        * (ATA_MISCCTL_TIMORIDE        , 1)
+        */
+       writel(0x201, base + BK3710_MISCCTL);
+
+       /*
+        * IORDYTMP IORDY Timer for Primary Register
+        * (ATA_IORDYTMP_IORDYTMP     , 0xffff  )
+        */
+       writel(0xFFFF, base + BK3710_IORDYTMP);
+
+       /*
+        * Configure BMISP Register
+        * (ATA_BMISP_DMAEN1    , DISABLE )     |
+        * (ATA_BMISP_DMAEN0    , DISABLE )     |
+        * (ATA_BMISP_IORDYINT  , CLEAR)        |
+        * (ATA_BMISP_INTRSTAT  , CLEAR)        |
+        * (ATA_BMISP_DMAERROR  , CLEAR)
+        */
+       writew(0, base + BK3710_BMISP);
+
+       palm_bk3710_setpiomode(base, NULL, 0, 600, 0);
+       palm_bk3710_setpiomode(base, NULL, 1, 600, 0);
+}
+static int __devinit palm_bk3710_probe(struct platform_device *pdev)
+{
+       hw_regs_t ide_ctlr_info;
+       int index = 0;
+       int pribase;
+       struct clk *clkp;
+       struct resource *mem, *irq;
+       ide_hwif_t *hwif;
+       void __iomem *base;
+
+       clkp = clk_get(NULL, "IDECLK");
+       if (IS_ERR(clkp))
+               return -ENODEV;
+
+       ideclkp = clkp;
+       clk_enable(ideclkp);
+       ide_palm_clk = clk_get_rate(ideclkp)/100000;
+       ide_palm_clk = (10000/ide_palm_clk) + 1;
+       /* Register the IDE interface with Linux ATA Interface */
+       memset(&ide_ctlr_info, 0, sizeof(ide_ctlr_info));
+
+       mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (mem == NULL) {
+               printk(KERN_ERR "failed to get memory region resource\n");
+               return -ENODEV;
+       }
+       irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (irq == NULL) {
+               printk(KERN_ERR "failed to get IRQ resource\n");
+               return -ENODEV;
+       }
+
+       base = (void *)mem->start;
+
+       /* Configure the Palm Chip controller */
+       palm_bk3710_chipinit(base);
+
+       pribase = mem->start + IDE_PALM_ATA_PRI_REG_OFFSET;
+       for (index = 0; index < IDE_NR_PORTS - 2; index++)
+               ide_ctlr_info.io_ports[index] = pribase + index;
+       ide_ctlr_info.io_ports[IDE_CONTROL_OFFSET] = mem->start +
+                       IDE_PALM_ATA_PRI_CTL_OFFSET;
+       ide_ctlr_info.irq = irq->start;
+       ide_ctlr_info.chipset = ide_palm3710;
+
+       if (ide_register_hw(&ide_ctlr_info, NULL, &hwif) < 0) {
+               printk(KERN_WARNING "Palm Chip BK3710 IDE Register Fail\n");
+               return -ENODEV;
+       }
+
+       hwif->set_pio_mode = &palm_bk3710_set_pio_mode;
+       hwif->set_dma_mode = &palm_bk3710_set_dma_mode;
+       hwif->mmio = 1;
+       default_hwif_mmiops(hwif);
+       hwif->cbl = ATA_CBL_PATA80;
+       hwif->ultra_mask = 0x1f;        /* Ultra DMA Mode 4 Max
+                                               (input clk 99MHz) */
+       hwif->mwdma_mask = 0x7;
+       hwif->drives[0].autotune = 1;
+       hwif->drives[1].autotune = 1;
+
+       ide_setup_dma(hwif, mem->start);
+
+       return 0;
+}
+
+static struct platform_driver platform_bk_driver = {
+       .driver = {
+               .name = "palm_bk3710",
+       },
+       .probe = palm_bk3710_probe,
+       .remove = NULL,
+};
+
+static int __init palm_bk3710_init(void)
+{
+       return platform_driver_register(&platform_bk_driver);
+}
+
+module_init(palm_bk3710_init);
+MODULE_LICENSE("GPL");
+
index e6b56d1d48f4902ce9f1b0f518c1a5fa4103b563..efba00d2fc37bf4de6c20b35a46b5ee02b7c4663 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * linux/drivers/ide/arm/rapide.c
- *
  * Copyright (c) 1996-2002 Russell King.
  */
 
@@ -60,7 +58,7 @@ rapide_probe(struct expansion_card *ec, const struct ecard_id *id)
 
                idx[0] = hwif->index;
 
-               ide_device_add(idx);
+               ide_device_add(idx, NULL);
 
                ecard_set_drvdata(ec, hwif);
                goto out;
@@ -78,8 +76,8 @@ static void __devexit rapide_remove(struct expansion_card *ec)
 
        ecard_set_drvdata(ec, NULL);
 
-       /* there must be a better way */
-       ide_unregister(hwif - ide_hwifs);
+       ide_unregister(hwif->index, 0, 0);
+
        ecard_release_resources(ec);
 }
 
index 8c3294c4d23e2fd390dd6653aff30a6cb5d618ca..e79bf8f9b7dbc29ca3c66f2f338a013ef12062fb 100644 (file)
@@ -1,5 +1,4 @@
-/* $Id: cris-ide-driver.patch,v 1.1 2005/06/29 21:39:07 akpm Exp $
- *
+/*
  * Etrax specific IDE functions, like init and PIO-mode setting etc.
  * Almost the entire ide.c is used for the rest of the Etrax ATA driver.
  * Copyright (c) 2000-2005 Axis Communications AB
@@ -754,34 +753,53 @@ static void cris_set_dma_mode(ide_drive_t *drive, const u8 speed)
                cris_ide_set_speed(TYPE_DMA, 0, strobe, hold);
 }
 
+static void __init cris_setup_ports(hw_regs_t *hw, unsigned long base)
+{
+       int i;
+
+       memset(hw, 0, sizeof(*hw));
+
+       for (i = 0; i <= 7; i++)
+               hw->io_ports[i] = base + cris_ide_reg_addr(i, 0, 1);
+
+       /*
+        * the IDE control register is at ATA address 6,
+        * with CS1 active instead of CS0
+        */
+       hw->io_ports[IDE_CONTROL_OFFSET] = base + cris_ide_reg_addr(6, 1, 0);
+
+       hw->irq = ide_default_irq(0);
+       hw->ack_intr = cris_ide_ack_intr;
+}
+
+static const struct ide_port_info cris_port_info __initdata = {
+       .chipset                = ide_etrax100,
+       .host_flags             = IDE_HFLAG_NO_ATAPI_DMA |
+                                 IDE_HFLAG_NO_DMA, /* no SFF-style DMA */
+       .pio_mask               = ATA_PIO4,
+       .udma_mask              = cris_ultra_mask,
+       .mwdma_mask             = ATA_MWDMA2,
+};
+
 static int __init init_e100_ide(void)
 {
        hw_regs_t hw;
-       int ide_offsets[IDE_NR_PORTS], h, i;
+       int h;
        u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
 
        printk("ide: ETRAX FS built-in ATA DMA controller\n");
 
-       for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++)
-               ide_offsets[i] = cris_ide_reg_addr(i, 0, 1);
-
-       /* the IDE control register is at ATA address 6, with CS1 active instead of CS0 */
-       ide_offsets[IDE_CONTROL_OFFSET] = cris_ide_reg_addr(6, 1, 0);
-
        for (h = 0; h < 4; h++) {
                ide_hwif_t *hwif = NULL;
 
-               ide_setup_ports(&hw, cris_ide_base_address(h),
-                               ide_offsets,
-                               0, 0, cris_ide_ack_intr,
-                               ide_default_irq(0));
+               cris_setup_ports(&hw, cris_ide_base_address(h));
+
                hwif = ide_find_port(hw.io_ports[IDE_DATA_OFFSET]);
                if (hwif == NULL)
                        continue;
                ide_init_port_data(hwif, hwif->index);
                ide_init_port_hw(hwif, &hw);
                hwif->mmio = 1;
-               hwif->chipset = ide_etrax100;
                hwif->set_pio_mode = &cris_set_pio_mode;
                hwif->set_dma_mode = &cris_set_dma_mode;
                hwif->ata_input_data = &cris_ide_input_data;
@@ -800,12 +818,6 @@ static int __init init_e100_ide(void)
                hwif->INB = &cris_ide_inb;
                hwif->INW = &cris_ide_inw;
                hwif->cbl = ATA_CBL_PATA40;
-               hwif->host_flags |= IDE_HFLAG_NO_ATAPI_DMA;
-               hwif->pio_mask = ATA_PIO4,
-               hwif->drives[0].autotune = 1;
-               hwif->drives[1].autotune = 1;
-               hwif->ultra_mask = cris_ultra_mask;
-               hwif->mwdma_mask = 0x07; /* Multiword DMA 0-2 */
 
                idx[h] = hwif->index;
        }
@@ -821,7 +833,7 @@ static int __init init_e100_ide(void)
        cris_ide_set_speed(TYPE_DMA, 0, ATA_DMA2_STROBE, ATA_DMA2_HOLD);
        cris_ide_set_speed(TYPE_UDMA, ATA_UDMA2_CYC, ATA_UDMA2_DVS, 0);
 
-       ide_device_add(idx);
+       ide_device_add(idx, &cris_port_info);
 
        return 0;
 }
@@ -1033,11 +1045,7 @@ static int cris_dma_setup(ide_drive_t *drive)
 
 static void cris_dma_exec_cmd(ide_drive_t *drive, u8 command)
 {
-       /* set the irq handler which will finish the request when DMA is done */
-       ide_set_handler(drive, &cris_dma_intr, WAIT_CMD, NULL);
-
-       /* issue cmd to drive */
-       cris_ide_outb(command, IDE_COMMAND_REG);
+       ide_execute_command(drive, command, &cris_dma_intr, WAIT_CMD, NULL);
 }
 
 static void cris_dma_start(ide_drive_t *drive)
index 4f6d0191cf6c31c74c9bec652c11e08861a23918..520aec075700d691a75b3ac03e66ea315e4bc1fd 100644 (file)
@@ -1,5 +1,4 @@
 /*
- * drivers/ide/h8300/ide-h8300.c
  * H8/300 generic IDE interface
  */
 
@@ -115,7 +114,7 @@ static int __init h8300_ide_init(void)
 
        idx[0] = index;
 
-       ide_device_add(idx);
+       ide_device_add(idx, NULL);
 
        return 0;
 
index e888fc35b27ce55401827d7255d064a7670ff02f..e07b189f3ec8504d7f2b19628253855f884ba2c6 100644 (file)
@@ -1,5 +1,4 @@
 /*
- * ide-acpi.c
  * Provides ACPI support for IDE drives.
  *
  * Copyright (C) 2005 Intel Corp.
@@ -40,7 +39,6 @@ struct GTM_buffer {
 };
 
 struct ide_acpi_drive_link {
-       ide_drive_t     *drive;
        acpi_handle      obj_handle;
        u8               idbuff[512];
 };
@@ -173,7 +171,7 @@ err:
 static acpi_handle ide_acpi_hwif_get_handle(ide_hwif_t *hwif)
 {
        struct device           *dev = hwif->gendev.parent;
-       acpi_handle             dev_handle;
+       acpi_handle             uninitialized_var(dev_handle);
        acpi_integer            pcidevfn;
        acpi_handle             chan_handle;
        int                     err;
@@ -281,16 +279,6 @@ static int do_drive_get_GTF(ide_drive_t *drive,
 
        port = hwif->channel ? drive->dn - 2: drive->dn;
 
-       if (!drive->acpidata) {
-               if (port == 0) {
-                       drive->acpidata = &hwif->acpidata->master;
-                       hwif->acpidata->master.drive = drive;
-               } else {
-                       drive->acpidata = &hwif->acpidata->slave;
-                       hwif->acpidata->slave.drive = drive;
-               }
-       }
-
        DEBPRINT("ENTER: %s at %s, port#: %d, hard_port#: %d\n",
                 hwif->name, dev->bus_id, port, hwif->channel);
 
@@ -495,7 +483,6 @@ int ide_acpi_exec_tfs(ide_drive_t *drive)
 
        return ret;
 }
-EXPORT_SYMBOL_GPL(ide_acpi_exec_tfs);
 
 /**
  * ide_acpi_get_timing - get the channel (controller) timings
@@ -581,7 +568,6 @@ void ide_acpi_get_timing(ide_hwif_t *hwif)
 
        kfree(output.pointer);
 }
-EXPORT_SYMBOL_GPL(ide_acpi_get_timing);
 
 /**
  * ide_acpi_push_timing - set the channel (controller) timings
@@ -635,7 +621,6 @@ void ide_acpi_push_timing(ide_hwif_t *hwif)
        }
        DEBPRINT("_STM status: %d\n", status);
 }
-EXPORT_SYMBOL_GPL(ide_acpi_push_timing);
 
 /**
  * ide_acpi_set_state - set the channel power state
@@ -689,11 +674,6 @@ void ide_acpi_set_state(ide_hwif_t *hwif, int on)
  */
 void ide_acpi_init(ide_hwif_t *hwif)
 {
-       int unit;
-       int                     err;
-       struct ide_acpi_drive_link      *master;
-       struct ide_acpi_drive_link      *slave;
-
        ide_acpi_blacklist();
 
        hwif->acpidata = kzalloc(sizeof(struct ide_acpi_hwif_link), GFP_KERNEL);
@@ -705,40 +685,38 @@ void ide_acpi_init(ide_hwif_t *hwif)
                DEBPRINT("no ACPI object for %s found\n", hwif->name);
                kfree(hwif->acpidata);
                hwif->acpidata = NULL;
-               return;
        }
+}
+
+void ide_acpi_port_init_devices(ide_hwif_t *hwif)
+{
+       ide_drive_t *drive;
+       int i, err;
+
+       if (hwif->acpidata == NULL)
+               return;
 
        /*
         * The ACPI spec mandates that we send information
         * for both drives, regardless whether they are connected
         * or not.
         */
-       hwif->acpidata->master.drive = &hwif->drives[0];
        hwif->drives[0].acpidata = &hwif->acpidata->master;
-       master = &hwif->acpidata->master;
-
-       hwif->acpidata->slave.drive = &hwif->drives[1];
        hwif->drives[1].acpidata = &hwif->acpidata->slave;
-       slave = &hwif->acpidata->slave;
-
 
        /*
         * Send IDENTIFY for each drive
         */
-       if (master->drive->present) {
-               err = taskfile_lib_get_identify(master->drive, master->idbuff);
-               if (err) {
-                       DEBPRINT("identify device %s failed (%d)\n",
-                                master->drive->name, err);
-               }
-       }
+       for (i = 0; i < MAX_DRIVES; i++) {
+               drive = &hwif->drives[i];
+
+               if (!drive->present)
+                       continue;
 
-       if (slave->drive->present) {
-               err = taskfile_lib_get_identify(slave->drive, slave->idbuff);
-               if (err) {
+               err = taskfile_lib_get_identify(drive, drive->acpidata->idbuff);
+               if (err)
                        DEBPRINT("identify device %s failed (%d)\n",
-                                slave->drive->name, err);
-               }
+                                drive->name, err);
        }
 
        if (ide_noacpionboot) {
@@ -754,13 +732,11 @@ void ide_acpi_init(ide_hwif_t *hwif)
        ide_acpi_get_timing(hwif);
        ide_acpi_push_timing(hwif);
 
-       for (unit = 0; unit < MAX_DRIVES; ++unit) {
-               ide_drive_t *drive = &hwif->drives[unit];
+       for (i = 0; i < MAX_DRIVES; i++) {
+               drive = &hwif->drives[i];
 
-               if (drive->present) {
+               if (drive->present)
                        /* Execute ACPI startup code */
                        ide_acpi_exec_tfs(drive);
-               }
        }
 }
-EXPORT_SYMBOL_GPL(ide_acpi_init);
index 74c6087ada38a99714011f84f18a0c05f9b69666..5e42c19a03e3b7f9e2eec932a929660cb513730d 100644 (file)
@@ -1,14 +1,14 @@
 /*
- * linux/drivers/ide/ide-cd.c
+ * ATAPI CD-ROM driver.
  *
- * Copyright (C) 1994, 1995, 1996  scott snyder  <snyder@fnald0.fnal.gov>
- * Copyright (C) 1996-1998  Erik Andersen <andersee@debian.org>
- * Copyright (C) 1998-2000  Jens Axboe <axboe@suse.de>
+ * Copyright (C) 1994-1996   Scott Snyder <snyder@fnald0.fnal.gov>
+ * Copyright (C) 1996-1998   Erik Andersen <andersee@debian.org>
+ * Copyright (C) 1998-2000   Jens Axboe <axboe@suse.de>
+ * Copyright (C) 2005, 2007  Bartlomiej Zolnierkiewicz
  *
  * May be copied or modified under the terms of the GNU General Public
  * License.  See linux/COPYING for more information.
  *
- * ATAPI CD-ROM driver.  To be used with ide.c.
  * See Documentation/cdrom/ide-cd for usage information.
  *
  * Suggestions are welcome. Patches that work are more welcome though. ;-)
  * ftp://fission.dt.wdc.com/pub/standards/SFF_atapi/spec/SFF8020-r2.6/PS/8020r26.ps
  * ftp://ftp.avc-pioneer.com/Mtfuji4/Spec/Fuji4r10.pdf
  *
- * Drives that deviate from these standards will be accommodated as much
- * as possible via compile time or command-line options.  Since I only have
- * a few drives, you generally need to send me patches...
- *
- * ----------------------------------
- * TO DO LIST:
- * -Make it so that Pioneer CD DR-A24X and friends don't get screwed up on
- *   boot
- *
- * ----------------------------------
- * 1.00  Oct 31, 1994 -- Initial version.
- * 1.01  Nov  2, 1994 -- Fixed problem with starting request in
- *                       cdrom_check_status.
- * 1.03  Nov 25, 1994 -- leaving unmask_intr[] as a user-setting (as for disks)
- * (from mlord)       -- minor changes to cdrom_setup()
- *                    -- renamed ide_dev_s to ide_drive_t, enable irq on command
- * 2.00  Nov 27, 1994 -- Generalize packet command interface;
- *                       add audio ioctls.
- * 2.01  Dec  3, 1994 -- Rework packet command interface to handle devices
- *                       which send an interrupt when ready for a command.
- * 2.02  Dec 11, 1994 -- Cache the TOC in the driver.
- *                       Don't use SCMD_PLAYAUDIO_TI; it's not included
- *                       in the current version of ATAPI.
- *                       Try to use LBA instead of track or MSF addressing
- *                       when possible.
- *                       Don't wait for READY_STAT.
- * 2.03  Jan 10, 1995 -- Rewrite block read routines to handle block sizes
- *                       other than 2k and to move multiple sectors in a
- *                       single transaction.
- * 2.04  Apr 21, 1995 -- Add work-around for Creative Labs CD220E drives.
- *                       Thanks to Nick Saw <cwsaw@pts7.pts.mot.com> for
- *                       help in figuring this out.  Ditto for Acer and
- *                       Aztech drives, which seem to have the same problem.
- * 2.04b May 30, 1995 -- Fix to match changes in ide.c version 3.16 -ml
- * 2.05  Jun  8, 1995 -- Don't attempt to retry after an illegal request
- *                        or data protect error.
- *                       Use HWIF and DEV_HWIF macros as in ide.c.
- *                       Always try to do a request_sense after
- *                        a failed command.
- *                       Include an option to give textual descriptions
- *                        of ATAPI errors.
- *                       Fix a bug in handling the sector cache which
- *                        showed up if the drive returned data in 512 byte
- *                        blocks (like Pioneer drives).  Thanks to
- *                        Richard Hirst <srh@gpt.co.uk> for diagnosing this.
- *                       Properly supply the page number field in the
- *                        MODE_SELECT command.
- *                       PLAYAUDIO12 is broken on the Aztech; work around it.
- * 2.05x Aug 11, 1995 -- lots of data structure renaming/restructuring in ide.c
- *                       (my apologies to Scott, but now ide-cd.c is independent)
- * 3.00  Aug 22, 1995 -- Implement CDROMMULTISESSION ioctl.
- *                       Implement CDROMREADAUDIO ioctl (UNTESTED).
- *                       Use input_ide_data() and output_ide_data().
- *                       Add door locking.
- *                       Fix usage count leak in cdrom_open, which happened
- *                        when a read-write mount was attempted.
- *                       Try to load the disk on open.
- *                       Implement CDROMEJECT_SW ioctl (off by default).
- *                       Read total cdrom capacity during open.
- *                       Rearrange logic in cdrom_decode_status.  Issue
- *                        request sense commands for failed packet commands
- *                        from here instead of from cdrom_queue_packet_command.
- *                        Fix a race condition in retrieving error information.
- *                       Suppress printing normal unit attention errors and
- *                        some drive not ready errors.
- *                       Implement CDROMVOLREAD ioctl.
- *                       Implement CDROMREADMODE1/2 ioctls.
- *                       Fix race condition in setting up interrupt handlers
- *                        when the `serialize' option is used.
- * 3.01  Sep  2, 1995 -- Fix ordering of reenabling interrupts in
- *                        cdrom_queue_request.
- *                       Another try at using ide_[input,output]_data.
- * 3.02  Sep 16, 1995 -- Stick total disk capacity in partition table as well.
- *                       Make VERBOSE_IDE_CD_ERRORS dump failed command again.
- *                       Dump out more information for ILLEGAL REQUEST errs.
- *                       Fix handling of errors occurring before the
- *                        packet command is transferred.
- *                       Fix transfers with odd bytelengths.
- * 3.03  Oct 27, 1995 -- Some Creative drives have an id of just `CD'.
- *                       `DCI-2S10' drives are broken too.
- * 3.04  Nov 20, 1995 -- So are Vertos drives.
- * 3.05  Dec  1, 1995 -- Changes to go with overhaul of ide.c and ide-tape.c
- * 3.06  Dec 16, 1995 -- Add support needed for partitions.
- *                       More workarounds for Vertos bugs (based on patches
- *                        from Holger Dietze <dietze@aix520.informatik.uni-leipzig.de>).
- *                       Try to eliminate byteorder assumptions.
- *                       Use atapi_cdrom_subchnl struct definition.
- *                       Add STANDARD_ATAPI compilation option.
- * 3.07  Jan 29, 1996 -- More twiddling for broken drives: Sony 55D,
- *                        Vertos 300.
- *                       Add NO_DOOR_LOCKING configuration option.
- *                       Handle drive_cmd requests w/NULL args (for hdparm -t).
- *                       Work around sporadic Sony55e audio play problem.
- * 3.07a Feb 11, 1996 -- check drive->id for NULL before dereferencing, to fix
- *                        problem with "hde=cdrom" with no drive present.  -ml
- * 3.08  Mar  6, 1996 -- More Vertos workarounds.
- * 3.09  Apr  5, 1996 -- Add CDROMCLOSETRAY ioctl.
- *                       Switch to using MSF addressing for audio commands.
- *                       Reformat to match kernel tabbing style.
- *                       Add CDROM_GET_UPC ioctl.
- * 3.10  Apr 10, 1996 -- Fix compilation error with STANDARD_ATAPI.
- * 3.11  Apr 29, 1996 -- Patch from Heiko Eißfeldt <heiko@colossus.escape.de>
- *                       to remove redundant verify_area calls.
- * 3.12  May  7, 1996 -- Rudimentary changer support.  Based on patches
- *                        from Gerhard Zuber <zuber@berlin.snafu.de>.
- *                       Let open succeed even if there's no loaded disc.
- * 3.13  May 19, 1996 -- Fixes for changer code.
- * 3.14  May 29, 1996 -- Add work-around for Vertos 600.
- *                        (From Hennus Bergman <hennus@sky.ow.nl>.)
- * 3.15  July 2, 1996 -- Added support for Sanyo 3 CD changers
- *                        from Ben Galliart <bgallia@luc.edu> with 
- *                        special help from Jeff Lightfoot 
- *                        <jeffml@pobox.com>
- * 3.15a July 9, 1996 -- Improved Sanyo 3 CD changer identification
- * 3.16  Jul 28, 1996 -- Fix from Gadi to reduce kernel stack usage for ioctl.
- * 3.17  Sep 17, 1996 -- Tweak audio reads for some drives.
- *                       Start changing CDROMLOADFROMSLOT to CDROM_SELECT_DISC.
- * 3.18  Oct 31, 1996 -- Added module and DMA support.
- *                       
- *                       
- * 4.00  Nov 5, 1996   -- New ide-cd maintainer,
- *                                 Erik B. Andersen <andersee@debian.org>
- *                     -- Newer Creative drives don't always set the error
- *                          register correctly.  Make sure we see media changes
- *                          regardless.
- *                     -- Integrate with generic cdrom driver.
- *                     -- CDROMGETSPINDOWN and CDROMSETSPINDOWN ioctls, based on
- *                          a patch from Ciro Cattuto <>.
- *                     -- Call set_device_ro.
- *                     -- Implement CDROMMECHANISMSTATUS and CDROMSLOTTABLE
- *                          ioctls, based on patch by Erik Andersen
- *                     -- Add some probes of drive capability during setup.
- *
- * 4.01  Nov 11, 1996  -- Split into ide-cd.c and ide-cd.h
- *                     -- Removed CDROMMECHANISMSTATUS and CDROMSLOTTABLE 
- *                          ioctls in favor of a generalized approach 
- *                          using the generic cdrom driver.
- *                     -- Fully integrated with the 2.1.X kernel.
- *                     -- Other stuff that I forgot (lots of changes)
- *
- * 4.02  Dec 01, 1996  -- Applied patch from Gadi Oxman <gadio@netvision.net.il>
- *                          to fix the drive door locking problems.
- *
- * 4.03  Dec 04, 1996  -- Added DSC overlap support.
- * 4.04  Dec 29, 1996  -- Added CDROMREADRAW ioclt based on patch 
- *                          by Ales Makarov (xmakarov@sun.felk.cvut.cz)
- *
- * 4.05  Nov 20, 1997  -- Modified to print more drive info on init
- *                        Minor other changes
- *                        Fix errors on CDROMSTOP (If you have a "Dolphin",
- *                          you must define IHAVEADOLPHIN)
- *                        Added identifier so new Sanyo CD-changer works
- *                        Better detection if door locking isn't supported
- *
- * 4.06  Dec 17, 1997  -- fixed endless "tray open" messages  -ml
- * 4.07  Dec 17, 1997  -- fallback to set pc->stat on "tray open"
- * 4.08  Dec 18, 1997  -- spew less noise when tray is empty
- *                     -- fix speed display for ACER 24X, 18X
- * 4.09  Jan 04, 1998  -- fix handling of the last block so we return
- *                         an end of file instead of an I/O error (Gadi)
- * 4.10  Jan 24, 1998  -- fixed a bug so now changers can change to a new
- *                         slot when there is no disc in the current slot.
- *                     -- Fixed a memory leak where info->changer_info was
- *                         malloc'ed but never free'd when closing the device.
- *                     -- Cleaned up the global namespace a bit by making more
- *                         functions static that should already have been.
- * 4.11  Mar 12, 1998  -- Added support for the CDROM_SELECT_SPEED ioctl
- *                         based on a patch for 2.0.33 by Jelle Foks 
- *                         <jelle@scintilla.utwente.nl>, a patch for 2.0.33
- *                         by Toni Giorgino <toni@pcape2.pi.infn.it>, the SCSI
- *                         version, and my own efforts.  -erik
- *                     -- Fixed a stupid bug which egcs was kind enough to
- *                         inform me of where "Illegal mode for this track"
- *                         was never returned due to a comparison on data
- *                         types of limited range.
- * 4.12  Mar 29, 1998  -- Fixed bug in CDROM_SELECT_SPEED so write speed is 
- *                         now set ionly for CD-R and CD-RW drives.  I had 
- *                         removed this support because it produced errors.
- *                         It produced errors _only_ for non-writers. duh.
- * 4.13  May 05, 1998  -- Suppress useless "in progress of becoming ready"
- *                         messages, since this is not an error.
- *                     -- Change error messages to be const
- *                     -- Remove a "\t" which looks ugly in the syslogs
- * 4.14  July 17, 1998 -- Change to pointing to .ps version of ATAPI spec
- *                         since the .pdf version doesn't seem to work...
- *                     -- Updated the TODO list to something more current.
- *
- * 4.15  Aug 25, 1998  -- Updated ide-cd.h to respect mechine endianess, 
- *                         patch thanks to "Eddie C. Dost" <ecd@skynet.be>
- *
- * 4.50  Oct 19, 1998  -- New maintainers!
- *                         Jens Axboe <axboe@image.dk>
- *                         Chris Zwilling <chris@cloudnet.com>
- *
- * 4.51  Dec 23, 1998  -- Jens Axboe <axboe@image.dk>
- *                      - ide_cdrom_reset enabled since the ide subsystem
- *                         handles resets fine now. <axboe@image.dk>
- *                      - Transfer size fix for Samsung CD-ROMs, thanks to
- *                        "Ville Hallik" <ville.hallik@mail.ee>.
- *                      - other minor stuff.
- *
- * 4.52  Jan 19, 1999  -- Jens Axboe <axboe@image.dk>
- *                      - Detect DVD-ROM/RAM drives
- *
- * 4.53  Feb 22, 1999   - Include other model Samsung and one Goldstar
- *                         drive in transfer size limit.
- *                      - Fix the I/O error when doing eject without a medium
- *                         loaded on some drives.
- *                      - CDROMREADMODE2 is now implemented through
- *                         CDROMREADRAW, since many drives don't support
- *                         MODE2 (even though ATAPI 2.6 says they must).
- *                      - Added ignore parameter to ide-cd (as a module), eg
- *                             insmod ide-cd ignore='hda hdb'
- *                         Useful when using ide-cd in conjunction with
- *                         ide-scsi. TODO: non-modular way of doing the
- *                         same.
- *
- * 4.54  Aug 5, 1999   - Support for MMC2 class commands through the generic
- *                       packet interface to cdrom.c.
- *                     - Unified audio ioctl support, most of it.
- *                     - cleaned up various deprecated verify_area().
- *                     - Added ide_cdrom_packet() as the interface for
- *                       the Uniform generic_packet().
- *                     - bunch of other stuff, will fill in logs later.
- *                     - report 1 slot for non-changers, like the other
- *                       cd-rom drivers. don't report select disc for
- *                       non-changers as well.
- *                     - mask out audio playing, if the device can't do it.
- *
- * 4.55  Sep 1, 1999   - Eliminated the rest of the audio ioctls, except
- *                       for CDROMREADTOC[ENTRY|HEADER]. Some of the drivers
- *                       use this independently of the actual audio handling.
- *                       They will disappear later when I get the time to
- *                       do it cleanly.
- *                     - Minimize the TOC reading - only do it when we
- *                       know a media change has occurred.
- *                     - Moved all the CDROMREADx ioctls to the Uniform layer.
- *                     - Heiko Eißfeldt <heiko@colossus.escape.de> supplied
- *                       some fixes for CDI.
- *                     - CD-ROM leaving door locked fix from Andries
- *                       Brouwer <Andries.Brouwer@cwi.nl>
- *                     - Erik Andersen <andersen@xmission.com> unified
- *                       commands across the various drivers and how
- *                       sense errors are handled.
- *
- * 4.56  Sep 12, 1999  - Removed changer support - it is now in the
- *                       Uniform layer.
- *                     - Added partition based multisession handling.
- *                     - Mode sense and mode select moved to the
- *                       Uniform layer.
- *                     - Fixed a problem with WPI CDS-32X drive - it
- *                       failed the capabilities 
- *
- * 4.57  Apr 7, 2000   - Fixed sense reporting.
- *                     - Fixed possible oops in ide_cdrom_get_last_session()
- *                     - Fix locking mania and make ide_cdrom_reset relock
- *                     - Stop spewing errors to log when magicdev polls with
- *                       TEST_UNIT_READY on some drives.
- *                     - Various fixes from Tobias Ringstrom:
- *                       tray if it was locked prior to the reset.
- *                       - cdrom_read_capacity returns one frame too little.
- *                       - Fix real capacity reporting.
- *
- * 4.58  May 1, 2000   - Clean up ACER50 stuff.
- *                     - Fix small problem with ide_cdrom_capacity
- *
- * 4.59  Aug 11, 2000  - Fix changer problem in cdrom_read_toc, we weren't
- *                       correctly sensing a disc change.
- *                     - Rearranged some code
- *                     - Use extended sense on drives that support it for
- *                       correctly reporting tray status -- from
- *                       Michael D Johnson <johnsom@orst.edu>
- * 4.60  Dec 17, 2003  - Add mt rainier support
- *                     - Bump timeout for packet commands, matches sr
- *                     - Odd stuff
- * 4.61  Jan 22, 2004  - support hardware sector sizes other than 2kB,
- *                       Pascal Schmidt <der.eremit@email.de>
- *
- *************************************************************************/
-#define IDECD_VERSION "4.61"
+ * For historical changelog please see:
+ *     Documentation/ide/ChangeLog.ide-cd.1994-2004
+ */
+
+#define IDECD_VERSION "5.00"
 
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/ide.h>
 #include <linux/completion.h>
 #include <linux/mutex.h>
+#include <linux/bcd.h>
 
 #include <scsi/scsi.h> /* For SCSI -> ATAPI command conversion */
 
@@ -360,11 +85,11 @@ static void ide_cd_put(struct cdrom_info *cd)
    buffers. */
 static void cdrom_saw_media_change (ide_drive_t *drive)
 {
-       struct cdrom_info *info = drive->driver_data;
-       
-       CDROM_STATE_FLAGS (drive)->media_changed = 1;
-       CDROM_STATE_FLAGS (drive)->toc_valid = 0;
-       info->nsectors_buffered = 0;
+       struct cdrom_info *cd = drive->driver_data;
+
+       cd->cd_flags |= IDE_CD_FLAG_MEDIA_CHANGED;
+       cd->cd_flags &= ~IDE_CD_FLAG_TOC_VALID;
+       cd->nsectors_buffered = 0;
 }
 
 static int cdrom_log_sense(ide_drive_t *drive, struct request *rq,
@@ -465,134 +190,14 @@ void cdrom_analyze_sense_data(ide_drive_t *drive,
                        }
                }
        }
-#if VERBOSE_IDE_CD_ERRORS
-       {
-               int i;
-               const char *s = "bad sense key!";
-               char buf[80];
-
-               printk ("ATAPI device %s:\n", drive->name);
-               if (sense->error_code==0x70)
-                       printk("  Error: ");
-               else if (sense->error_code==0x71)
-                       printk("  Deferred Error: ");
-               else if (sense->error_code == 0x7f)
-                       printk("  Vendor-specific Error: ");
-               else
-                       printk("  Unknown Error Type: ");
-
-               if (sense->sense_key < ARRAY_SIZE(sense_key_texts))
-                       s = sense_key_texts[sense->sense_key];
-
-               printk("%s -- (Sense key=0x%02x)\n", s, sense->sense_key);
-
-               if (sense->asc == 0x40) {
-                       sprintf(buf, "Diagnostic failure on component 0x%02x",
-                                sense->ascq);
-                       s = buf;
-               } else {
-                       int lo = 0, mid, hi = ARRAY_SIZE(sense_data_texts);
-                       unsigned long key = (sense->sense_key << 16);
-                       key |= (sense->asc << 8);
-                       if (!(sense->ascq >= 0x80 && sense->ascq <= 0xdd))
-                               key |= sense->ascq;
-                       s = NULL;
-
-                       while (hi > lo) {
-                               mid = (lo + hi) / 2;
-                               if (sense_data_texts[mid].asc_ascq == key ||
-                                   sense_data_texts[mid].asc_ascq == (0xff0000|key)) {
-                                       s = sense_data_texts[mid].text;
-                                       break;
-                               }
-                               else if (sense_data_texts[mid].asc_ascq > key)
-                                       hi = mid;
-                               else
-                                       lo = mid+1;
-                       }
-               }
-
-               if (s == NULL) {
-                       if (sense->asc > 0x80)
-                               s = "(vendor-specific error)";
-                       else
-                               s = "(reserved error code)";
-               }
 
-               printk(KERN_ERR "  %s -- (asc=0x%02x, ascq=0x%02x)\n",
-                       s, sense->asc, sense->ascq);
-
-               if (failed_command != NULL) {
-
-                       int lo=0, mid, hi= ARRAY_SIZE(packet_command_texts);
-                       s = NULL;
-
-                       while (hi > lo) {
-                               mid = (lo + hi) / 2;
-                               if (packet_command_texts[mid].packet_command ==
-                                   failed_command->cmd[0]) {
-                                       s = packet_command_texts[mid].text;
-                                       break;
-                               }
-                               if (packet_command_texts[mid].packet_command >
-                                   failed_command->cmd[0])
-                                       hi = mid;
-                               else
-                                       lo = mid+1;
-                       }
-
-                       printk (KERN_ERR "  The failed \"%s\" packet command was: \n  \"", s);
-                       for (i=0; i<sizeof (failed_command->cmd); i++)
-                               printk ("%02x ", failed_command->cmd[i]);
-                       printk ("\"\n");
-               }
-
-               /* The SKSV bit specifies validity of the sense_key_specific
-                * in the next two commands. It is bit 7 of the first byte.
-                * In the case of NOT_READY, if SKSV is set the drive can
-                * give us nice ETA readings.
-                */
-               if (sense->sense_key == NOT_READY && (sense->sks[0] & 0x80)) {
-                       int progress = (sense->sks[1] << 8 | sense->sks[2]) * 100;
-                       printk(KERN_ERR "  Command is %02d%% complete\n", progress / 0xffff);
-
-               }
-
-               if (sense->sense_key == ILLEGAL_REQUEST &&
-                   (sense->sks[0] & 0x80) != 0) {
-                       printk(KERN_ERR "  Error in %s byte %d",
-                               (sense->sks[0] & 0x40) != 0 ?
-                               "command packet" : "command data",
-                               (sense->sks[1] << 8) + sense->sks[2]);
-
-                       if ((sense->sks[0] & 0x40) != 0)
-                               printk (" bit %d", sense->sks[0] & 0x07);
-
-                       printk ("\n");
-               }
-       }
-
-#else /* not VERBOSE_IDE_CD_ERRORS */
-
-       /* Suppress printing unit attention and `in progress of becoming ready'
-          errors when we're not being verbose. */
-
-       if (sense->sense_key == UNIT_ATTENTION ||
-           (sense->sense_key == NOT_READY && (sense->asc == 4 ||
-                                               sense->asc == 0x3a)))
-               return;
-
-       printk(KERN_ERR "%s: error code: 0x%02x  sense_key: 0x%02x  asc: 0x%02x  ascq: 0x%02x\n",
-               drive->name,
-               sense->error_code, sense->sense_key,
-               sense->asc, sense->ascq);
-#endif /* not VERBOSE_IDE_CD_ERRORS */
+       ide_cd_log_error(drive->name, failed_command, sense);
 }
 
 /*
  * Initialize a ide-cd packet command request
  */
-static void cdrom_prepare_request(ide_drive_t *drive, struct request *rq)
+void ide_cd_init_rq(ide_drive_t *drive, struct request *rq)
 {
        struct cdrom_info *cd = drive->driver_data;
 
@@ -611,7 +216,7 @@ static void cdrom_queue_request_sense(ide_drive_t *drive, void *sense,
                sense = &info->sense_data;
 
        /* stuff the sense request in front of our current request */
-       cdrom_prepare_request(drive, rq);
+       ide_cd_init_rq(drive, rq);
 
        rq->data = sense;
        rq->cmd[0] = GPCMD_REQUEST_SENSE;
@@ -690,7 +295,8 @@ static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret)
        int stat, err, sense_key;
        
        /* Check for errors. */
-       stat = HWIF(drive)->INB(IDE_STATUS_REG);
+       stat = ide_read_status(drive);
+
        if (stat_ret)
                *stat_ret = stat;
 
@@ -698,7 +304,7 @@ static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret)
                return 0;
 
        /* Get the IDE error register. */
-       err = HWIF(drive)->INB(IDE_ERROR_REG);
+       err = ide_read_error(drive);
        sense_key = err >> 4;
 
        if (rq == NULL) {
@@ -718,7 +324,6 @@ static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret)
 
        } else if (blk_pc_request(rq) || rq->cmd_type == REQ_TYPE_ATA_PC) {
                /* All other functions, except for READ. */
-               unsigned long flags;
 
                /*
                 * if we have an error, pass back CHECK_CONDITION as the
@@ -756,15 +361,7 @@ static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret)
                 * remove failed request completely and end it when the
                 * request sense has completed
                 */
-               if (stat & ERR_STAT) {
-                       spin_lock_irqsave(&ide_lock, flags);
-                       blkdev_dequeue_request(rq);
-                       HWGROUP(drive)->rq = NULL;
-                       spin_unlock_irqrestore(&ide_lock, flags);
-
-                       cdrom_queue_request_sense(drive, rq->sense, rq);
-               } else
-                       cdrom_end_request(drive, 0);
+               goto end_request;
 
        } else if (blk_fs_request(rq)) {
                int do_end_request = 0;
@@ -844,23 +441,15 @@ static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret)
                   sense data. We need this in order to perform end of media
                   processing */
 
-               if (do_end_request) {
-                       if (stat & ERR_STAT) {
-                               unsigned long flags;
-                               spin_lock_irqsave(&ide_lock, flags);
-                               blkdev_dequeue_request(rq);
-                               HWGROUP(drive)->rq = NULL;
-                               spin_unlock_irqrestore(&ide_lock, flags);
+               if (do_end_request)
+                       goto end_request;
 
-                               cdrom_queue_request_sense(drive, rq->sense, rq);
-                       } else
-                               cdrom_end_request(drive, 0);
-               } else {
-                       /* If we got a CHECK_CONDITION status,
-                          queue a request sense command. */
-                       if (stat & ERR_STAT)
-                               cdrom_queue_request_sense(drive, NULL, NULL);
-               }
+               /*
+                * If we got a CHECK_CONDITION status,
+                * queue a request sense command.
+                */
+               if (stat & ERR_STAT)
+                       cdrom_queue_request_sense(drive, NULL, NULL);
        } else {
                blk_dump_rq_flags(rq, "ide-cd: bad rq");
                cdrom_end_request(drive, 0);
@@ -868,6 +457,21 @@ static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret)
 
        /* Retry, or handle the next request. */
        return 1;
+
+end_request:
+       if (stat & ERR_STAT) {
+               unsigned long flags;
+
+               spin_lock_irqsave(&ide_lock, flags);
+               blkdev_dequeue_request(rq);
+               HWGROUP(drive)->rq = NULL;
+               spin_unlock_irqrestore(&ide_lock, flags);
+
+               cdrom_queue_request_sense(drive, rq->sense, rq);
+       } else
+               cdrom_end_request(drive, 0);
+
+       return 1;
 }
 
 static int cdrom_timer_expiry(ide_drive_t *drive)
@@ -924,8 +528,8 @@ static ide_startstop_t cdrom_start_packet_command(ide_drive_t *drive,
        /* Set up the controller registers. */
        ide_pktcmd_tf_load(drive, IDE_TFLAG_OUT_NSECT | IDE_TFLAG_OUT_LBAL |
                           IDE_TFLAG_NO_SELECT_MASK, xferlen, info->dma);
-       if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) {
+
+       if (info->cd_flags & IDE_CD_FLAG_DRQ_INTERRUPT) {
                /* waiting for CDB interrupt, not DMA yet. */
                if (info->dma)
                        drive->waiting_for_dma = 0;
@@ -951,10 +555,6 @@ static ide_startstop_t cdrom_start_packet_command(ide_drive_t *drive,
    by cdrom_start_packet_command.
    HANDLER is the interrupt handler to call when the command completes
    or there's data ready. */
-/*
- * changed 5 parameters to 3 for dvd-ram
- * struct packet_command *pc; now packet_command_t *pc;
- */
 #define ATAPI_MIN_CDB_BYTES 12
 static ide_startstop_t cdrom_transfer_packet_command (ide_drive_t *drive,
                                          struct request *rq,
@@ -965,7 +565,7 @@ static ide_startstop_t cdrom_transfer_packet_command (ide_drive_t *drive,
        struct cdrom_info *info = drive->driver_data;
        ide_startstop_t startstop;
 
-       if (CDROM_CONFIG_FLAGS(drive)->drq_interrupt) {
+       if (info->cd_flags & IDE_CD_FLAG_DRQ_INTERRUPT) {
                /* Here we should have been called after receiving an interrupt
                   from the device.  DRQ should how be set. */
 
@@ -1005,6 +605,25 @@ static ide_startstop_t cdrom_transfer_packet_command (ide_drive_t *drive,
  * Block read functions.
  */
 
+static void ide_cd_pad_transfer(ide_drive_t *drive, xfer_func_t *xf, int len)
+{
+       while (len > 0) {
+               int dum = 0;
+               xf(drive, &dum, sizeof(dum));
+               len -= sizeof(dum);
+       }
+}
+
+static void ide_cd_drain_data(ide_drive_t *drive, int nsects)
+{
+       while (nsects > 0) {
+               static char dum[SECTOR_SIZE];
+
+               drive->hwif->atapi_input_bytes(drive, dum, sizeof(dum));
+               nsects--;
+       }
+}
+
 /*
  * Buffer up to SECTORS_TO_TRANSFER sectors from the drive in our sector
  * buffer.  Once the first sector is added, any subsequent sectors are
@@ -1043,11 +662,7 @@ static void cdrom_buffer_sectors (ide_drive_t *drive, unsigned long sector,
        }
 
        /* Throw away any remaining data. */
-       while (sectors_to_transfer > 0) {
-               static char dum[SECTOR_SIZE];
-               HWIF(drive)->atapi_input_bytes(drive, dum, sizeof (dum));
-               --sectors_to_transfer;
-       }
+       ide_cd_drain_data(drive, sectors_to_transfer);
 }
 
 /*
@@ -1056,27 +671,29 @@ static void cdrom_buffer_sectors (ide_drive_t *drive, unsigned long sector,
  * ok; nonzero if the request has been terminated.
  */
 static
-int cdrom_read_check_ireason (ide_drive_t *drive, int len, int ireason)
+int ide_cd_check_ireason(ide_drive_t *drive, int len, int ireason, int rw)
 {
-       if (ireason == 2)
+       /*
+        * ireason == 0: the drive wants to receive data from us
+        * ireason == 2: the drive is expecting to transfer data to us
+        */
+       if (ireason == (!rw << 1))
                return 0;
-       else if (ireason == 0) {
-               /* Whoops... The drive is expecting to receive data from us! */
+       else if (ireason == (rw << 1)) {
+               ide_hwif_t *hwif = drive->hwif;
+               xfer_func_t *xf;
+
+               /* Whoops... */
                printk(KERN_ERR "%s: %s: wrong transfer direction!\n",
                                drive->name, __FUNCTION__);
 
-               /* Throw some data at the drive so it doesn't hang
-                  and quit this request. */
-               while (len > 0) {
-                       int dum = 0;
-                       HWIF(drive)->atapi_output_bytes(drive, &dum, sizeof (dum));
-                       len -= sizeof (dum);
-               }
-       } else  if (ireason == 1) {
+               xf = rw ? hwif->atapi_output_bytes : hwif->atapi_input_bytes;
+               ide_cd_pad_transfer(drive, xf, len);
+       } else  if (rw == 0 && ireason == 1) {
                /* Some drives (ASUS) seem to tell us that status
                 * info is available. just get it and ignore.
                 */
-               (void) HWIF(drive)->INB(IDE_STATUS_REG);
+               (void)ide_read_status(drive);
                return 0;
        } else {
                /* Drive wants a command packet, or invalid ireason... */
@@ -1089,137 +706,28 @@ int cdrom_read_check_ireason (ide_drive_t *drive, int len, int ireason)
 }
 
 /*
- * Interrupt routine.  Called when a read request has completed.
+ * Assume that the drive will always provide data in multiples of at least
+ * SECTOR_SIZE, as it gets hairy to keep track of the transfers otherwise.
  */
-static ide_startstop_t cdrom_read_intr (ide_drive_t *drive)
+static int ide_cd_check_transfer_size(ide_drive_t *drive, int len)
 {
-       int stat;
-       int ireason, len, sectors_to_transfer, nskip;
-       struct cdrom_info *info = drive->driver_data;
-       u8 lowcyl = 0, highcyl = 0;
-       int dma = info->dma, dma_error = 0;
-
-       struct request *rq = HWGROUP(drive)->rq;
-
-       /*
-        * handle dma case
-        */
-       if (dma) {
-               info->dma = 0;
-               dma_error = HWIF(drive)->ide_dma_end(drive);
-               if (dma_error) {
-                       printk(KERN_ERR "%s: DMA read error\n", drive->name);
-                       ide_dma_off(drive);
-               }
-       }
-
-       if (cdrom_decode_status(drive, 0, &stat))
-               return ide_stopped;
-
-       if (dma) {
-               if (!dma_error) {
-                       ide_end_request(drive, 1, rq->nr_sectors);
-                       return ide_stopped;
-               } else
-                       return ide_error(drive, "dma error", stat);
-       }
-
-       /* Read the interrupt reason and the transfer length. */
-       ireason = HWIF(drive)->INB(IDE_IREASON_REG) & 0x3;
-       lowcyl  = HWIF(drive)->INB(IDE_BCOUNTL_REG);
-       highcyl = HWIF(drive)->INB(IDE_BCOUNTH_REG);
-
-       len = lowcyl + (256 * highcyl);
-
-       /* If DRQ is clear, the command has completed. */
-       if ((stat & DRQ_STAT) == 0) {
-               /* If we're not done filling the current buffer, complain.
-                  Otherwise, complete the command normally. */
-               if (rq->current_nr_sectors > 0) {
-                       printk (KERN_ERR "%s: cdrom_read_intr: data underrun (%d blocks)\n",
-                               drive->name, rq->current_nr_sectors);
-                       rq->cmd_flags |= REQ_FAILED;
-                       cdrom_end_request(drive, 0);
-               } else
-                       cdrom_end_request(drive, 1);
-               return ide_stopped;
-       }
-
-       /* Check that the drive is expecting to do the same thing we are. */
-       if (cdrom_read_check_ireason (drive, len, ireason))
-               return ide_stopped;
-
-       /* Assume that the drive will always provide data in multiples
-          of at least SECTOR_SIZE, as it gets hairy to keep track
-          of the transfers otherwise. */
-       if ((len % SECTOR_SIZE) != 0) {
-               printk (KERN_ERR "%s: cdrom_read_intr: Bad transfer size %d\n",
-                       drive->name, len);
-               if (CDROM_CONFIG_FLAGS(drive)->limit_nframes)
-                       printk (KERN_ERR "  This drive is not supported by this version of the driver\n");
-               else {
-                       printk (KERN_ERR "  Trying to limit transfer sizes\n");
-                       CDROM_CONFIG_FLAGS(drive)->limit_nframes = 1;
-               }
-               cdrom_end_request(drive, 0);
-               return ide_stopped;
-       }
-
-       /* The number of sectors we need to read from the drive. */
-       sectors_to_transfer = len / SECTOR_SIZE;
-
-       /* First, figure out if we need to bit-bucket
-          any of the leading sectors. */
-       nskip = min_t(int, rq->current_nr_sectors - bio_cur_sectors(rq->bio), sectors_to_transfer);
-
-       while (nskip > 0) {
-               /* We need to throw away a sector. */
-               static char dum[SECTOR_SIZE];
-               HWIF(drive)->atapi_input_bytes(drive, dum, sizeof (dum));
-
-               --rq->current_nr_sectors;
-               --nskip;
-               --sectors_to_transfer;
-       }
+       struct cdrom_info *cd = drive->driver_data;
 
-       /* Now loop while we still have data to read from the drive. */
-       while (sectors_to_transfer > 0) {
-               int this_transfer;
+       if ((len % SECTOR_SIZE) == 0)
+               return 0;
 
-               /* If we've filled the present buffer but there's another
-                  chained buffer after it, move on. */
-               if (rq->current_nr_sectors == 0 && rq->nr_sectors)
-                       cdrom_end_request(drive, 1);
+       printk(KERN_ERR "%s: %s: Bad transfer size %d\n",
+                       drive->name, __FUNCTION__, len);
 
-               /* If the buffers are full, cache the rest of the data in our
-                  internal buffer. */
-               if (rq->current_nr_sectors == 0) {
-                       cdrom_buffer_sectors(drive, rq->sector, sectors_to_transfer);
-                       sectors_to_transfer = 0;
-               } else {
-                       /* Transfer data to the buffers.
-                          Figure out how many sectors we can transfer
-                          to the current buffer. */
-                       this_transfer = min_t(int, sectors_to_transfer,
-                                            rq->current_nr_sectors);
-
-                       /* Read this_transfer sectors
-                          into the current buffer. */
-                       while (this_transfer > 0) {
-                               HWIF(drive)->atapi_input_bytes(drive, rq->buffer, SECTOR_SIZE);
-                               rq->buffer += SECTOR_SIZE;
-                               --rq->nr_sectors;
-                               --rq->current_nr_sectors;
-                               ++rq->sector;
-                               --this_transfer;
-                               --sectors_to_transfer;
-                       }
-               }
+       if (cd->cd_flags & IDE_CD_FLAG_LIMIT_NFRAMES)
+               printk(KERN_ERR "  This drive is not supported by "
+                               "this version of the driver\n");
+       else {
+               printk(KERN_ERR "  Trying to limit transfer sizes\n");
+               cd->cd_flags |= IDE_CD_FLAG_LIMIT_NFRAMES;
        }
 
-       /* Done moving data!  Wait for another interrupt. */
-       ide_set_handler(drive, &cdrom_read_intr, ATAPI_WAIT_PC, NULL);
-       return ide_started;
+       return 1;
 }
 
 /*
@@ -1281,48 +789,58 @@ static int cdrom_read_from_buffer (ide_drive_t *drive)
        return 0;
 }
 
+static ide_startstop_t cdrom_newpc_intr(ide_drive_t *);
+
 /*
- * Routine to send a read packet command to the drive.
- * This is usually called directly from cdrom_start_read.
+ * Routine to send a read/write packet command to the drive.
+ * This is usually called directly from cdrom_start_{read,write}().
  * However, for drq_interrupt devices, it is called from an interrupt
  * when the drive is ready to accept the command.
  */
-static ide_startstop_t cdrom_start_read_continuation (ide_drive_t *drive)
+static ide_startstop_t cdrom_start_rw_cont(ide_drive_t *drive)
 {
        struct request *rq = HWGROUP(drive)->rq;
-       unsigned short sectors_per_frame;
-       int nskip;
 
-       sectors_per_frame = queue_hardsect_size(drive->queue) >> SECTOR_BITS;
+       if (rq_data_dir(rq) == READ) {
+               unsigned short sectors_per_frame =
+                       queue_hardsect_size(drive->queue) >> SECTOR_BITS;
+               int nskip = rq->sector & (sectors_per_frame - 1);
 
-       /* If the requested sector doesn't start on a cdrom block boundary,
-          we must adjust the start of the transfer so that it does,
-          and remember to skip the first few sectors.
-          If the CURRENT_NR_SECTORS field is larger than the size
-          of the buffer, it will mean that we're to skip a number
-          of sectors equal to the amount by which CURRENT_NR_SECTORS
-          is larger than the buffer size. */
-       nskip = rq->sector & (sectors_per_frame - 1);
-       if (nskip > 0) {
-               /* Sanity check... */
-               if (rq->current_nr_sectors != bio_cur_sectors(rq->bio) &&
-                       (rq->sector & (sectors_per_frame - 1))) {
-                       printk(KERN_ERR "%s: cdrom_start_read_continuation: buffer botch (%u)\n",
-                               drive->name, rq->current_nr_sectors);
-                       cdrom_end_request(drive, 0);
-                       return ide_stopped;
+               /*
+                * If the requested sector doesn't start on a frame boundary,
+                * we must adjust the start of the transfer so that it does,
+                * and remember to skip the first few sectors.
+                *
+                * If the rq->current_nr_sectors field is larger than the size
+                * of the buffer, it will mean that we're to skip a number of
+                * sectors equal to the amount by which rq->current_nr_sectors
+                * is larger than the buffer size.
+                */
+               if (nskip > 0) {
+                       /* Sanity check... */
+                       if (rq->current_nr_sectors !=
+                           bio_cur_sectors(rq->bio)) {
+                               printk(KERN_ERR "%s: %s: buffer botch (%u)\n",
+                                               drive->name, __FUNCTION__,
+                                               rq->current_nr_sectors);
+                               cdrom_end_request(drive, 0);
+                               return ide_stopped;
+                       }
+                       rq->current_nr_sectors += nskip;
                }
-               rq->current_nr_sectors += nskip;
        }
-
+#if 0
+       else
+               /* the immediate bit */
+               rq->cmd[1] = 1 << 3;
+#endif
        /* Set up the command */
        rq->timeout = ATAPI_WAIT_PC;
 
        /* Send the command to the drive and return. */
-       return cdrom_transfer_packet_command(drive, rq, &cdrom_read_intr);
+       return cdrom_transfer_packet_command(drive, rq, cdrom_newpc_intr);
 }
 
-
 #define IDECD_SEEK_THRESHOLD   (1000)                  /* 1000 blocks */
 #define IDECD_SEEK_TIMER       (5 * WAIT_MIN_SLEEP)    /* 100 ms */
 #define IDECD_SEEK_TIMEOUT     (2 * WAIT_CMD)          /* 20 sec */
@@ -1335,7 +853,8 @@ static ide_startstop_t cdrom_seek_intr (ide_drive_t *drive)
 
        if (cdrom_decode_status(drive, 0, &stat))
                return ide_stopped;
-       CDROM_CONFIG_FLAGS(drive)->seeking = 1;
+
+       info->cd_flags |= IDE_CD_FLAG_SEEKING;
 
        if (retry && time_after(jiffies, info->start_seek + IDECD_SEEK_TIMER)) {
                if (--retry == 0) {
@@ -1391,184 +910,25 @@ static void restore_request (struct request *rq)
        rq->q->prep_rq_fn(rq->q, rq);
 }
 
-/*
- * Start a read request from the CD-ROM.
- */
-static ide_startstop_t cdrom_start_read (ide_drive_t *drive, unsigned int block)
-{
-       struct cdrom_info *info = drive->driver_data;
-       struct request *rq = HWGROUP(drive)->rq;
-       unsigned short sectors_per_frame;
-
-       sectors_per_frame = queue_hardsect_size(drive->queue) >> SECTOR_BITS;
-
-       /* We may be retrying this request after an error.  Fix up
-          any weirdness which might be present in the request packet. */
-       restore_request(rq);
-
-       /* Satisfy whatever we can of this request from our cached sector. */
-       if (cdrom_read_from_buffer(drive))
-               return ide_stopped;
-
-       /* Clear the local sector buffer. */
-       info->nsectors_buffered = 0;
-
-       /* use dma, if possible. */
-       info->dma = drive->using_dma;
-       if ((rq->sector & (sectors_per_frame - 1)) ||
-           (rq->nr_sectors & (sectors_per_frame - 1)))
-               info->dma = 0;
-
-       /* Start sending the read request to the drive. */
-       return cdrom_start_packet_command(drive, 32768, cdrom_start_read_continuation);
-}
-
 /****************************************************************************
  * Execute all other packet commands.
  */
 
-/* Interrupt routine for packet command completion. */
-static ide_startstop_t cdrom_pc_intr (ide_drive_t *drive)
+static void ide_cd_request_sense_fixup(struct request *rq)
 {
-       int ireason, len, thislen;
-       struct request *rq = HWGROUP(drive)->rq;
-       u8 lowcyl = 0, highcyl = 0;
-       int stat;
-
-       /* Check for errors. */
-       if (cdrom_decode_status(drive, 0, &stat))
-               return ide_stopped;
-
-       /* Read the interrupt reason and the transfer length. */
-       ireason = HWIF(drive)->INB(IDE_IREASON_REG) & 0x3;
-       lowcyl  = HWIF(drive)->INB(IDE_BCOUNTL_REG);
-       highcyl = HWIF(drive)->INB(IDE_BCOUNTH_REG);
-
-       len = lowcyl + (256 * highcyl);
-
-       /* If DRQ is clear, the command has completed.
-          Complain if we still have data left to transfer. */
-       if ((stat & DRQ_STAT) == 0) {
-               /* Some of the trailing request sense fields are optional, and
-                  some drives don't send them.  Sigh. */
-               if (rq->cmd[0] == GPCMD_REQUEST_SENSE &&
-                   rq->data_len > 0 &&
-                   rq->data_len <= 5) {
-                       while (rq->data_len > 0) {
-                               *(unsigned char *)rq->data++ = 0;
-                               --rq->data_len;
-                       }
-               }
-
-               if (rq->data_len == 0)
-                       cdrom_end_request(drive, 1);
-               else {
-                       /* Comment this out, because this always happens 
-                          right after a reset occurs, and it is annoying to 
-                          always print expected stuff.  */
-                       /*
-                       printk ("%s: cdrom_pc_intr: data underrun %d\n",
-                               drive->name, pc->buflen);
-                       */
-                       rq->cmd_flags |= REQ_FAILED;
-                       cdrom_end_request(drive, 0);
-               }
-               return ide_stopped;
-       }
-
-       /* Figure out how much data to transfer. */
-       thislen = rq->data_len;
-       if (thislen > len) thislen = len;
-
-       /* The drive wants to be written to. */
-       if (ireason == 0) {
-               if (!rq->data) {
-                       blk_dump_rq_flags(rq, "cdrom_pc_intr, write");
-                       goto confused;
-               }
-               /* Transfer the data. */
-               HWIF(drive)->atapi_output_bytes(drive, rq->data, thislen);
-
-               /* If we haven't moved enough data to satisfy the drive,
-                  add some padding. */
-               while (len > thislen) {
-                       int dum = 0;
-                       HWIF(drive)->atapi_output_bytes(drive, &dum, sizeof(dum));
-                       len -= sizeof(dum);
-               }
-
-               /* Keep count of how much data we've moved. */
-               rq->data += thislen;
-               rq->data_len -= thislen;
-       }
-
-       /* Same drill for reading. */
-       else if (ireason == 2) {
-               if (!rq->data) {
-                       blk_dump_rq_flags(rq, "cdrom_pc_intr, read");
-                       goto confused;
-               }
-               /* Transfer the data. */
-               HWIF(drive)->atapi_input_bytes(drive, rq->data, thislen);
-
-               /* If we haven't moved enough data to satisfy the drive,
-                  add some padding. */
-               while (len > thislen) {
-                       int dum = 0;
-                       HWIF(drive)->atapi_input_bytes(drive, &dum, sizeof(dum));
-                       len -= sizeof(dum);
+       /*
+        * Some of the trailing request sense fields are optional,
+        * and some drives don't send them.  Sigh.
+        */
+       if (rq->cmd[0] == GPCMD_REQUEST_SENSE &&
+           rq->data_len > 0 && rq->data_len <= 5)
+               while (rq->data_len > 0) {
+                       *(u8 *)rq->data++ = 0;
+                       --rq->data_len;
                }
-
-               /* Keep count of how much data we've moved. */
-               rq->data += thislen;
-               rq->data_len -= thislen;
-
-               if (blk_sense_request(rq))
-                       rq->sense_len += thislen;
-       } else {
-confused:
-               printk (KERN_ERR "%s: cdrom_pc_intr: The drive "
-                       "appears confused (ireason = 0x%02x). "
-                       "Trying to recover by ending request.\n",
-                       drive->name, ireason);
-               rq->cmd_flags |= REQ_FAILED;
-               cdrom_end_request(drive, 0);
-               return ide_stopped;
-       }
-
-       /* Now we wait for another interrupt. */
-       ide_set_handler(drive, &cdrom_pc_intr, ATAPI_WAIT_PC, cdrom_timer_expiry);
-       return ide_started;
-}
-
-static ide_startstop_t cdrom_do_pc_continuation (ide_drive_t *drive)
-{
-       struct request *rq = HWGROUP(drive)->rq;
-
-       if (!rq->timeout)
-               rq->timeout = ATAPI_WAIT_PC;
-
-       /* Send the command to the drive and return. */
-       return cdrom_transfer_packet_command(drive, rq, &cdrom_pc_intr);
-}
-
-
-static ide_startstop_t cdrom_do_packet_command (ide_drive_t *drive)
-{
-       int len;
-       struct request *rq = HWGROUP(drive)->rq;
-       struct cdrom_info *info = drive->driver_data;
-
-       info->dma = 0;
-       rq->cmd_flags &= ~REQ_FAILED;
-       len = rq->data_len;
-
-       /* Start sending the command to the drive. */
-       return cdrom_start_packet_command(drive, len, cdrom_do_pc_continuation);
 }
 
-
-static int cdrom_queue_packet_command(ide_drive_t *drive, struct request *rq)
+int ide_cd_queue_pc(ide_drive_t *drive, struct request *rq)
 {
        struct request_sense sense;
        int retries = 10;
@@ -1616,37 +976,6 @@ static int cdrom_queue_packet_command(ide_drive_t *drive, struct request *rq)
        return (rq->cmd_flags & REQ_FAILED) ? -EIO : 0;
 }
 
-/*
- * Write handling
- */
-static int cdrom_write_check_ireason(ide_drive_t *drive, int len, int ireason)
-{
-       /* Two notes about IDE interrupt reason here - 0 means that
-        * the drive wants to receive data from us, 2 means that
-        * the drive is expecting to transfer data to us.
-        */
-       if (ireason == 0)
-               return 0;
-       else if (ireason == 2) {
-               /* Whoops... The drive wants to send data. */
-               printk(KERN_ERR "%s: %s: wrong transfer direction!\n",
-                               drive->name, __FUNCTION__);
-
-               while (len > 0) {
-                       int dum = 0;
-                       HWIF(drive)->atapi_input_bytes(drive, &dum, sizeof(dum));
-                       len -= sizeof(dum);
-               }
-       } else {
-               /* Drive wants a command packet, or invalid ireason... */
-               printk(KERN_ERR "%s: %s: bad interrupt reason 0x%02x\n",
-                               drive->name, __FUNCTION__, ireason);
-       }
-
-       cdrom_end_request(drive, 0);
-       return 1;
-}
-
 /*
  * Called from blk_end_request_callback() after the data of the request
  * is completed and before the request is completed.
@@ -1658,29 +987,27 @@ static int cdrom_newpc_intr_dummy_cb(struct request *rq)
        return 1;
 }
 
-typedef void (xfer_func_t)(ide_drive_t *, void *, u32);
-
-/*
- * best way to deal with dma that is not sector aligned right now... note
- * that in this path we are not using ->data or ->buffer at all. this irs
- * can replace cdrom_pc_intr, cdrom_read_intr, and cdrom_write_intr in the
- * future.
- */
 static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
 {
        struct cdrom_info *info = drive->driver_data;
        struct request *rq = HWGROUP(drive)->rq;
-       int dma_error, dma, stat, ireason, len, thislen;
-       u8 lowcyl, highcyl;
        xfer_func_t *xferfunc;
-       unsigned long flags;
+       ide_expiry_t *expiry = NULL;
+       int dma_error = 0, dma, stat, ireason, len, thislen, uptodate = 0;
+       int write = (rq_data_dir(rq) == WRITE) ? 1 : 0;
+       unsigned int timeout;
+       u8 lowcyl, highcyl;
 
        /* Check for errors. */
-       dma_error = 0;
        dma = info->dma;
        if (dma) {
                info->dma = 0;
                dma_error = HWIF(drive)->ide_dma_end(drive);
+               if (dma_error) {
+                       printk(KERN_ERR "%s: DMA %s error\n", drive->name,
+                                       write ? "write" : "read");
+                       ide_dma_off(drive);
+               }
        }
 
        if (cdrom_decode_status(drive, 0, &stat))
@@ -1690,19 +1017,13 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
         * using dma, transfer is complete now
         */
        if (dma) {
-               if (dma_error) {
-                       printk(KERN_ERR "ide-cd: dma error\n");
-                       ide_dma_off(drive);
+               if (dma_error)
                        return ide_error(drive, "dma error", stat);
+               if (blk_fs_request(rq)) {
+                       ide_end_request(drive, 1, rq->nr_sectors);
+                       return ide_stopped;
                }
-
-               spin_lock_irqsave(&ide_lock, flags);
-               if (__blk_end_request(rq, 0, rq->data_len))
-                       BUG();
-               HWGROUP(drive)->rq = NULL;
-               spin_unlock_irqrestore(&ide_lock, flags);
-
-               return ide_stopped;
+               goto end_request;
        }
 
        /*
@@ -1713,7 +1034,8 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
        highcyl = HWIF(drive)->INB(IDE_BCOUNTH_REG);
 
        len = lowcyl + (256 * highcyl);
-       thislen = rq->data_len;
+
+       thislen = blk_fs_request(rq) ? len : rq->data_len;
        if (thislen > len)
                thislen = len;
 
@@ -1721,53 +1043,111 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
         * If DRQ is clear, the command has completed.
         */
        if ((stat & DRQ_STAT) == 0) {
-               spin_lock_irqsave(&ide_lock, flags);
-               if (__blk_end_request(rq, 0, 0))
-                       BUG();
-               HWGROUP(drive)->rq = NULL;
-               spin_unlock_irqrestore(&ide_lock, flags);
-
-               return ide_stopped;
+               if (blk_fs_request(rq)) {
+                       /*
+                        * If we're not done reading/writing, complain.
+                        * Otherwise, complete the command normally.
+                        */
+                       uptodate = 1;
+                       if (rq->current_nr_sectors > 0) {
+                               printk(KERN_ERR "%s: %s: data underrun "
+                                               "(%d blocks)\n",
+                                               drive->name, __FUNCTION__,
+                                               rq->current_nr_sectors);
+                               if (!write)
+                                       rq->cmd_flags |= REQ_FAILED;
+                               uptodate = 0;
+                       }
+                       cdrom_end_request(drive, uptodate);
+                       return ide_stopped;
+               } else if (!blk_pc_request(rq)) {
+                       ide_cd_request_sense_fixup(rq);
+                       /* Complain if we still have data left to transfer. */
+                       uptodate = rq->data_len ? 0 : 1;
+               }
+               goto end_request;
        }
 
        /*
         * check which way to transfer data
         */
-       if (rq_data_dir(rq) == WRITE) {
-               /*
-                * write to drive
-                */
-               if (cdrom_write_check_ireason(drive, len, ireason))
+       if (blk_fs_request(rq) || blk_pc_request(rq)) {
+               if (ide_cd_check_ireason(drive, len, ireason, write))
                        return ide_stopped;
 
-               xferfunc = HWIF(drive)->atapi_output_bytes;
-       } else  {
-               /*
-                * read from drive
-                */
-               if (cdrom_read_check_ireason(drive, len, ireason))
-                       return ide_stopped;
+               if (blk_fs_request(rq) && write == 0) {
+                       int nskip;
+
+                       if (ide_cd_check_transfer_size(drive, len)) {
+                               cdrom_end_request(drive, 0);
+                               return ide_stopped;
+                       }
+
+                       /*
+                        * First, figure out if we need to bit-bucket
+                        * any of the leading sectors.
+                        */
+                       nskip = min_t(int, rq->current_nr_sectors
+                                          - bio_cur_sectors(rq->bio),
+                                          thislen >> 9);
+                       if (nskip > 0) {
+                               ide_cd_drain_data(drive, nskip);
+                               rq->current_nr_sectors -= nskip;
+                               thislen -= (nskip << 9);
+                       }
+               }
+       }
 
+       if (ireason == 0) {
+               write = 1;
+               xferfunc = HWIF(drive)->atapi_output_bytes;
+       } else if (ireason == 2 || (ireason == 1 &&
+                  (blk_fs_request(rq) || blk_pc_request(rq)))) {
+               write = 0;
                xferfunc = HWIF(drive)->atapi_input_bytes;
+       } else {
+               printk(KERN_ERR "%s: %s: The drive "
+                               "appears confused (ireason = 0x%02x). "
+                               "Trying to recover by ending request.\n",
+                               drive->name, __FUNCTION__, ireason);
+               goto end_request;
        }
 
        /*
         * transfer data
         */
        while (thislen > 0) {
-               int blen = blen = rq->data_len;
-               char *ptr = rq->data;
+               u8 *ptr = blk_fs_request(rq) ? NULL : rq->data;
+               int blen = rq->data_len;
 
                /*
                 * bio backed?
                 */
                if (rq->bio) {
-                       ptr = bio_data(rq->bio);
-                       blen = bio_iovec(rq->bio)->bv_len;
+                       if (blk_fs_request(rq)) {
+                               ptr = rq->buffer;
+                               blen = rq->current_nr_sectors << 9;
+                       } else {
+                               ptr = bio_data(rq->bio);
+                               blen = bio_iovec(rq->bio)->bv_len;
+                       }
                }
 
                if (!ptr) {
-                       printk(KERN_ERR "%s: confused, missing data\n", drive->name);
+                       if (blk_fs_request(rq) && !write)
+                               /*
+                                * If the buffers are full, cache the rest
+                                * of the data in our internal buffer.
+                                */
+                               cdrom_buffer_sectors(drive, rq->sector,
+                                                    thislen >> 9);
+                       else {
+                               printk(KERN_ERR "%s: confused, missing data\n",
+                                               drive->name);
+                               blk_dump_rq_flags(rq, rq_data_dir(rq)
+                                                 ? "cdrom_newpc_intr, write"
+                                                 : "cdrom_newpc_intr, read");
+                       }
                        break;
                }
 
@@ -1778,185 +1158,117 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
 
                thislen -= blen;
                len -= blen;
-               rq->data_len -= blen;
 
-               if (rq->bio)
+               if (blk_fs_request(rq)) {
+                       rq->buffer += blen;
+                       rq->nr_sectors -= (blen >> 9);
+                       rq->current_nr_sectors -= (blen >> 9);
+                       rq->sector += (blen >> 9);
+
+                       if (rq->current_nr_sectors == 0 && rq->nr_sectors)
+                               cdrom_end_request(drive, 1);
+               } else {
+                       rq->data_len -= blen;
+
                        /*
                         * The request can't be completed until DRQ is cleared.
                         * So complete the data, but don't complete the request
                         * using the dummy function for the callback feature
                         * of blk_end_request_callback().
                         */
-                       blk_end_request_callback(rq, 0, blen,
+                       if (rq->bio)
+                               blk_end_request_callback(rq, 0, blen,
                                                 cdrom_newpc_intr_dummy_cb);
-               else
-                       rq->data += blen;
-       }
-
-       /*
-        * pad, if necessary
-        */
-       if (len > 0) {
-               while (len > 0) {
-                       int pad = 0;
-
-                       xferfunc(drive, &pad, sizeof(pad));
-                       len -= sizeof(pad);
-               }
-       }
-
-       BUG_ON(HWGROUP(drive)->handler != NULL);
-
-       ide_set_handler(drive, cdrom_newpc_intr, rq->timeout, NULL);
-       return ide_started;
-}
-
-static ide_startstop_t cdrom_write_intr(ide_drive_t *drive)
-{
-       int stat, ireason, len, sectors_to_transfer, uptodate;
-       struct cdrom_info *info = drive->driver_data;
-       int dma_error = 0, dma = info->dma;
-       u8 lowcyl = 0, highcyl = 0;
-
-       struct request *rq = HWGROUP(drive)->rq;
-
-       /* Check for errors. */
-       if (dma) {
-               info->dma = 0;
-               dma_error = HWIF(drive)->ide_dma_end(drive);
-               if (dma_error) {
-                       printk(KERN_ERR "%s: DMA write error\n", drive->name);
-                       ide_dma_off(drive);
+                       else
+                               rq->data += blen;
                }
        }
 
-       if (cdrom_decode_status(drive, 0, &stat))
-               return ide_stopped;
+       if (write && blk_sense_request(rq))
+               rq->sense_len += thislen;
 
        /*
-        * using dma, transfer is complete now
+        * pad, if necessary
         */
-       if (dma) {
-               if (dma_error)
-                       return ide_error(drive, "dma error", stat);
+       if (!blk_fs_request(rq) && len > 0)
+               ide_cd_pad_transfer(drive, xferfunc, len);
 
-               ide_end_request(drive, 1, rq->nr_sectors);
-               return ide_stopped;
+       if (blk_pc_request(rq)) {
+               timeout = rq->timeout;
+       } else {
+               timeout = ATAPI_WAIT_PC;
+               if (!blk_fs_request(rq))
+                       expiry = cdrom_timer_expiry;
        }
 
-       /* Read the interrupt reason and the transfer length. */
-       ireason = HWIF(drive)->INB(IDE_IREASON_REG) & 0x3;
-       lowcyl  = HWIF(drive)->INB(IDE_BCOUNTL_REG);
-       highcyl = HWIF(drive)->INB(IDE_BCOUNTH_REG);
+       ide_set_handler(drive, cdrom_newpc_intr, timeout, expiry);
+       return ide_started;
 
-       len = lowcyl + (256 * highcyl);
+end_request:
+       if (blk_pc_request(rq)) {
+               unsigned long flags;
 
-       /* If DRQ is clear, the command has completed. */
-       if ((stat & DRQ_STAT) == 0) {
-               /* If we're not done writing, complain.
-                * Otherwise, complete the command normally.
-                */
-               uptodate = 1;
-               if (rq->current_nr_sectors > 0) {
-                       printk(KERN_ERR "%s: %s: data underrun (%d blocks)\n",
-                                       drive->name, __FUNCTION__,
-                                       rq->current_nr_sectors);
-                       uptodate = 0;
-               }
+               spin_lock_irqsave(&ide_lock, flags);
+               if (__blk_end_request(rq, 0, rq->data_len))
+                       BUG();
+               HWGROUP(drive)->rq = NULL;
+               spin_unlock_irqrestore(&ide_lock, flags);
+       } else {
+               if (!uptodate)
+                       rq->cmd_flags |= REQ_FAILED;
                cdrom_end_request(drive, uptodate);
-               return ide_stopped;
        }
+       return ide_stopped;
+}
 
-       /* Check that the drive is expecting to do the same thing we are. */
-       if (cdrom_write_check_ireason(drive, len, ireason))
-               return ide_stopped;
-
-       sectors_to_transfer = len / SECTOR_SIZE;
-
-       /*
-        * now loop and write out the data
-        */
-       while (sectors_to_transfer > 0) {
-               int this_transfer;
-
-               if (!rq->current_nr_sectors) {
-                       printk(KERN_ERR "%s: %s: confused, missing data\n",
-                                       drive->name, __FUNCTION__);
-                       break;
-               }
+static ide_startstop_t cdrom_start_rw(ide_drive_t *drive, struct request *rq)
+{
+       struct cdrom_info *cd = drive->driver_data;
+       int write = rq_data_dir(rq) == WRITE;
+       unsigned short sectors_per_frame =
+               queue_hardsect_size(drive->queue) >> SECTOR_BITS;
 
+       if (write) {
                /*
-                * Figure out how many sectors we can transfer
+                * disk has become write protected
                 */
-               this_transfer = min_t(int, sectors_to_transfer, rq->current_nr_sectors);
-
-               while (this_transfer > 0) {
-                       HWIF(drive)->atapi_output_bytes(drive, rq->buffer, SECTOR_SIZE);
-                       rq->buffer += SECTOR_SIZE;
-                       --rq->nr_sectors;
-                       --rq->current_nr_sectors;
-                       ++rq->sector;
-                       --this_transfer;
-                       --sectors_to_transfer;
+               if (cd->disk->policy) {
+                       cdrom_end_request(drive, 0);
+                       return ide_stopped;
                }
-
+       } else {
                /*
-                * current buffer complete, move on
+                * We may be retrying this request after an error.  Fix up any
+                * weirdness which might be present in the request packet.
                 */
-               if (rq->current_nr_sectors == 0 && rq->nr_sectors)
-                       cdrom_end_request(drive, 1);
-       }
+               restore_request(rq);
 
-       /* re-arm handler */
-       ide_set_handler(drive, &cdrom_write_intr, ATAPI_WAIT_PC, NULL);
-       return ide_started;
-}
-
-static ide_startstop_t cdrom_start_write_cont(ide_drive_t *drive)
-{
-       struct request *rq = HWGROUP(drive)->rq;
-
-#if 0  /* the immediate bit */
-       rq->cmd[1] = 1 << 3;
-#endif
-       rq->timeout = ATAPI_WAIT_PC;
-
-       return cdrom_transfer_packet_command(drive, rq, cdrom_write_intr);
-}
-
-static ide_startstop_t cdrom_start_write(ide_drive_t *drive, struct request *rq)
-{
-       struct cdrom_info *info = drive->driver_data;
-       struct gendisk *g = info->disk;
-       unsigned short sectors_per_frame = queue_hardsect_size(drive->queue) >> SECTOR_BITS;
+               /* Satisfy whatever we can of this request from our cache. */
+               if (cdrom_read_from_buffer(drive))
+                       return ide_stopped;
+       }
 
        /*
-        * writes *must* be hardware frame aligned
+        * use DMA, if possible / writes *must* be hardware frame aligned
         */
        if ((rq->nr_sectors & (sectors_per_frame - 1)) ||
            (rq->sector & (sectors_per_frame - 1))) {
-               cdrom_end_request(drive, 0);
-               return ide_stopped;
-       }
-
-       /*
-        * disk has become write protected
-        */
-       if (g->policy) {
-               cdrom_end_request(drive, 0);
-               return ide_stopped;
-       }
-
-       info->nsectors_buffered = 0;
+               if (write) {
+                       cdrom_end_request(drive, 0);
+                       return ide_stopped;
+               }
+               cd->dma = 0;
+       } else
+               cd->dma = drive->using_dma;
 
-       /* use dma, if possible. we don't need to check more, since we
-        * know that the transfer is always (at least!) frame aligned */
-       info->dma = drive->using_dma ? 1 : 0;
+       /* Clear the local sector buffer. */
+       cd->nsectors_buffered = 0;
 
-       info->devinfo.media_written = 1;
+       if (write)
+               cd->devinfo.media_written = 1;
 
-       /* Start sending the write request to the drive. */
-       return cdrom_start_packet_command(drive, 32768, cdrom_start_write_cont);
+       /* Start sending the read/write request to the drive. */
+       return cdrom_start_packet_command(drive, 32768, cdrom_start_rw_cont);
 }
 
 static ide_startstop_t cdrom_do_newpc_cont(ide_drive_t *drive)
@@ -1973,7 +1285,10 @@ static ide_startstop_t cdrom_do_block_pc(ide_drive_t *drive, struct request *rq)
 {
        struct cdrom_info *info = drive->driver_data;
 
-       rq->cmd_flags |= REQ_QUIET;
+       if (blk_pc_request(rq))
+               rq->cmd_flags |= REQ_QUIET;
+       else
+               rq->cmd_flags &= ~REQ_FAILED;
 
        info->dma = 0;
 
@@ -2010,9 +1325,9 @@ ide_do_rw_cdrom (ide_drive_t *drive, struct request *rq, sector_t block)
        struct cdrom_info *info = drive->driver_data;
 
        if (blk_fs_request(rq)) {
-               if (CDROM_CONFIG_FLAGS(drive)->seeking) {
+               if (info->cd_flags & IDE_CD_FLAG_SEEKING) {
                        unsigned long elapsed = jiffies - info->start_seek;
-                       int stat = HWIF(drive)->INB(IDE_STATUS_REG);
+                       int stat = ide_read_status(drive);
 
                        if ((stat & SEEK_STAT) != SEEK_STAT) {
                                if (elapsed < IDECD_SEEK_TIMEOUT) {
@@ -2021,22 +1336,16 @@ ide_do_rw_cdrom (ide_drive_t *drive, struct request *rq, sector_t block)
                                }
                                printk (KERN_ERR "%s: DSC timeout\n", drive->name);
                        }
-                       CDROM_CONFIG_FLAGS(drive)->seeking = 0;
+                       info->cd_flags &= ~IDE_CD_FLAG_SEEKING;
                }
                if ((rq_data_dir(rq) == READ) && IDE_LARGE_SEEK(info->last_block, block, IDECD_SEEK_THRESHOLD) && drive->dsc_overlap) {
                        action = cdrom_start_seek(drive, block);
-               } else {
-                       if (rq_data_dir(rq) == READ)
-                               action = cdrom_start_read(drive, block);
-                       else
-                               action = cdrom_start_write(drive, rq);
-               }
+               } else
+                       action = cdrom_start_rw(drive, rq);
                info->last_block = block;
                return action;
-       } else if (rq->cmd_type == REQ_TYPE_SENSE ||
+       } else if (blk_sense_request(rq) || blk_pc_request(rq) ||
                   rq->cmd_type == REQ_TYPE_ATA_PC) {
-               return cdrom_do_packet_command(drive);
-       } else if (blk_pc_request(rq)) {
                return cdrom_do_block_pc(drive, rq);
        } else if (blk_special_request(rq)) {
                /*
@@ -2063,141 +1372,33 @@ ide_do_rw_cdrom (ide_drive_t *drive, struct request *rq, sector_t block)
  * can also be NULL, in which case no sense information is returned.
  */
 
-#if ! STANDARD_ATAPI
-static inline
-int bin2bcd (int x)
-{
-       return (x%10) | ((x/10) << 4);
-}
-
-
-static inline
-int bcd2bin (int x)
-{
-       return (x >> 4) * 10 + (x & 0x0f);
-}
-
 static
 void msf_from_bcd (struct atapi_msf *msf)
 {
-       msf->minute = bcd2bin (msf->minute);
-       msf->second = bcd2bin (msf->second);
-       msf->frame  = bcd2bin (msf->frame);
+       msf->minute = BCD2BIN(msf->minute);
+       msf->second = BCD2BIN(msf->second);
+       msf->frame  = BCD2BIN(msf->frame);
 }
 
-#endif /* not STANDARD_ATAPI */
-
-
-static inline
-void lba_to_msf (int lba, byte *m, byte *s, byte *f)
-{
-       lba += CD_MSF_OFFSET;
-       lba &= 0xffffff;  /* negative lbas use only 24 bits */
-       *m = lba / (CD_SECS * CD_FRAMES);
-       lba %= (CD_SECS * CD_FRAMES);
-       *s = lba / CD_FRAMES;
-       *f = lba % CD_FRAMES;
-}
-
-
-static inline
-int msf_to_lba (byte m, byte s, byte f)
-{
-       return (((m * CD_SECS) + s) * CD_FRAMES + f) - CD_MSF_OFFSET;
-}
-
-static int cdrom_check_status(ide_drive_t *drive, struct request_sense *sense)
+int cdrom_check_status(ide_drive_t *drive, struct request_sense *sense)
 {
        struct request req;
        struct cdrom_info *info = drive->driver_data;
        struct cdrom_device_info *cdi = &info->devinfo;
 
-       cdrom_prepare_request(drive, &req);
+       ide_cd_init_rq(drive, &req);
 
        req.sense = sense;
        req.cmd[0] = GPCMD_TEST_UNIT_READY;
        req.cmd_flags |= REQ_QUIET;
 
-#if ! STANDARD_ATAPI
-        /* the Sanyo 3 CD changer uses byte 7 of TEST_UNIT_READY to 
-           switch CDs instead of supporting the LOAD_UNLOAD opcode   */
-
+       /*
+        * Sanyo 3 CD changer uses byte 7 of TEST_UNIT_READY to
+        * switch CDs instead of supporting the LOAD_UNLOAD opcode.
+        */
        req.cmd[7] = cdi->sanyo_slot % 3;
-#endif /* not STANDARD_ATAPI */
-
-       return cdrom_queue_packet_command(drive, &req);
-}
-
-
-/* Lock the door if LOCKFLAG is nonzero; unlock it otherwise. */
-static int
-cdrom_lockdoor(ide_drive_t *drive, int lockflag, struct request_sense *sense)
-{
-       struct request_sense my_sense;
-       struct request req;
-       int stat;
-
-       if (sense == NULL)
-               sense = &my_sense;
 
-       /* If the drive cannot lock the door, just pretend. */
-       if (CDROM_CONFIG_FLAGS(drive)->no_doorlock) {
-               stat = 0;
-       } else {
-               cdrom_prepare_request(drive, &req);
-               req.sense = sense;
-               req.cmd[0] = GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL;
-               req.cmd[4] = lockflag ? 1 : 0;
-               stat = cdrom_queue_packet_command(drive, &req);
-       }
-
-       /* If we got an illegal field error, the drive
-          probably cannot lock the door. */
-       if (stat != 0 &&
-           sense->sense_key == ILLEGAL_REQUEST &&
-           (sense->asc == 0x24 || sense->asc == 0x20)) {
-               printk (KERN_ERR "%s: door locking not supported\n",
-                       drive->name);
-               CDROM_CONFIG_FLAGS(drive)->no_doorlock = 1;
-               stat = 0;
-       }
-       
-       /* no medium, that's alright. */
-       if (stat != 0 && sense->sense_key == NOT_READY && sense->asc == 0x3a)
-               stat = 0;
-
-       if (stat == 0)
-               CDROM_STATE_FLAGS(drive)->door_locked = lockflag;
-
-       return stat;
-}
-
-
-/* Eject the disk if EJECTFLAG is 0.
-   If EJECTFLAG is 1, try to reload the disk. */
-static int cdrom_eject(ide_drive_t *drive, int ejectflag,
-                      struct request_sense *sense)
-{
-       struct request req;
-       char loej = 0x02;
-
-       if (CDROM_CONFIG_FLAGS(drive)->no_eject && !ejectflag)
-               return -EDRIVE_CANT_DO_THIS;
-       
-       /* reload fails on some drives, if the tray is locked */
-       if (CDROM_STATE_FLAGS(drive)->door_locked && ejectflag)
-               return 0;
-
-       cdrom_prepare_request(drive, &req);
-
-       /* only tell drive to close tray if open, if it can do that */
-       if (ejectflag && !CDROM_CONFIG_FLAGS(drive)->close_tray)
-               loej = 0;
-
-       req.sense = sense;
-       req.cmd[0] = GPCMD_START_STOP_UNIT;
-       req.cmd[4] = loej | (ejectflag != 0);
-       return cdrom_queue_packet_command(drive, &req);
+       return ide_cd_queue_pc(drive, &req);
 }
 
 static int cdrom_read_capacity(ide_drive_t *drive, unsigned long *capacity,
@@ -2212,7 +1413,7 @@ static int cdrom_read_capacity(ide_drive_t *drive, unsigned long *capacity,
        int stat;
        struct request req;
 
-       cdrom_prepare_request(drive, &req);
+       ide_cd_init_rq(drive, &req);
 
        req.sense = sense;
        req.cmd[0] = GPCMD_READ_CDVD_CAPACITY;
@@ -2220,7 +1421,7 @@ static int cdrom_read_capacity(ide_drive_t *drive, unsigned long *capacity,
        req.data_len = sizeof(capbuf);
        req.cmd_flags |= REQ_QUIET;
 
-       stat = cdrom_queue_packet_command(drive, &req);
+       stat = ide_cd_queue_pc(drive, &req);
        if (stat == 0) {
                *capacity = 1 + be32_to_cpu(capbuf.lba);
                *sectors_per_frame =
@@ -2236,7 +1437,7 @@ static int cdrom_read_tocentry(ide_drive_t *drive, int trackno, int msf_flag,
 {
        struct request req;
 
-       cdrom_prepare_request(drive, &req);
+       ide_cd_init_rq(drive, &req);
 
        req.sense = sense;
        req.data =  buf;
@@ -2251,12 +1452,11 @@ static int cdrom_read_tocentry(ide_drive_t *drive, int trackno, int msf_flag,
        if (msf_flag)
                req.cmd[1] = 2;
 
-       return cdrom_queue_packet_command(drive, &req);
+       return ide_cd_queue_pc(drive, &req);
 }
 
-
 /* Try to read the entire TOC for the disk into our internal buffer. */
-static int cdrom_read_toc(ide_drive_t *drive, struct request_sense *sense)
+int ide_cd_read_toc(ide_drive_t *drive, struct request_sense *sense)
 {
        int stat, ntracks, i;
        struct cdrom_info *info = drive->driver_data;
@@ -2283,7 +1483,7 @@ static int cdrom_read_toc(ide_drive_t *drive, struct request_sense *sense)
           If it is, just return. */
        (void) cdrom_check_status(drive, sense);
 
-       if (CDROM_STATE_FLAGS(drive)->toc_valid)
+       if (info->cd_flags & IDE_CD_FLAG_TOC_VALID)
                return 0;
 
        /* Try to get the total cdrom capacity and sector size. */
@@ -2305,12 +1505,10 @@ static int cdrom_read_toc(ide_drive_t *drive, struct request_sense *sense)
        if (stat)
                return stat;
 
-#if ! STANDARD_ATAPI
-       if (CDROM_CONFIG_FLAGS(drive)->toctracks_as_bcd) {
-               toc->hdr.first_track = bcd2bin(toc->hdr.first_track);
-               toc->hdr.last_track  = bcd2bin(toc->hdr.last_track);
+       if (info->cd_flags & IDE_CD_FLAG_TOCTRACKS_AS_BCD) {
+               toc->hdr.first_track = BCD2BIN(toc->hdr.first_track);
+               toc->hdr.last_track  = BCD2BIN(toc->hdr.last_track);
        }
-#endif  /* not STANDARD_ATAPI */
 
        ntracks = toc->hdr.last_track - toc->hdr.first_track + 1;
        if (ntracks <= 0)
@@ -2342,16 +1540,13 @@ static int cdrom_read_toc(ide_drive_t *drive, struct request_sense *sense)
                                           (ntracks + 1) *
                                           sizeof(struct atapi_toc_entry),
                                           sense);
-               if (stat) {
+               if (stat)
                        return stat;
-               }
-#if ! STANDARD_ATAPI
-               if (CDROM_CONFIG_FLAGS(drive)->toctracks_as_bcd) {
-                       toc->hdr.first_track = bin2bcd(CDROM_LEADOUT);
-                       toc->hdr.last_track = bin2bcd(CDROM_LEADOUT);
-               } else
-#endif  /* not STANDARD_ATAPI */
-               {
+
+               if (info->cd_flags & IDE_CD_FLAG_TOCTRACKS_AS_BCD) {
+                       toc->hdr.first_track = (u8)BIN2BCD(CDROM_LEADOUT);
+                       toc->hdr.last_track = (u8)BIN2BCD(CDROM_LEADOUT);
+               } else {
                        toc->hdr.first_track = CDROM_LEADOUT;
                        toc->hdr.last_track = CDROM_LEADOUT;
                }
@@ -2362,21 +1557,17 @@ static int cdrom_read_toc(ide_drive_t *drive, struct request_sense *sense)
 
        toc->hdr.toc_length = ntohs (toc->hdr.toc_length);
 
-#if ! STANDARD_ATAPI
-       if (CDROM_CONFIG_FLAGS(drive)->toctracks_as_bcd) {
-               toc->hdr.first_track = bcd2bin(toc->hdr.first_track);
-               toc->hdr.last_track  = bcd2bin(toc->hdr.last_track);
+       if (info->cd_flags & IDE_CD_FLAG_TOCTRACKS_AS_BCD) {
+               toc->hdr.first_track = BCD2BIN(toc->hdr.first_track);
+               toc->hdr.last_track  = BCD2BIN(toc->hdr.last_track);
        }
-#endif  /* not STANDARD_ATAPI */
 
-       for (i=0; i<=ntracks; i++) {
-#if ! STANDARD_ATAPI
-               if (CDROM_CONFIG_FLAGS(drive)->tocaddr_as_bcd) {
-                       if (CDROM_CONFIG_FLAGS(drive)->toctracks_as_bcd)
-                               toc->ent[i].track = bcd2bin(toc->ent[i].track);
+       for (i = 0; i <= ntracks; i++) {
+               if (info->cd_flags & IDE_CD_FLAG_TOCADDR_AS_BCD) {
+                       if (info->cd_flags & IDE_CD_FLAG_TOCTRACKS_AS_BCD)
+                               toc->ent[i].track = BCD2BIN(toc->ent[i].track);
                        msf_from_bcd(&toc->ent[i].addr.msf);
                }
-#endif  /* not STANDARD_ATAPI */
                toc->ent[i].addr.lba = msf_to_lba (toc->ent[i].addr.msf.minute,
                                                   toc->ent[i].addr.msf.second,
                                                   toc->ent[i].addr.msf.frame);
@@ -2396,8 +1587,7 @@ static int cdrom_read_toc(ide_drive_t *drive, struct request_sense *sense)
                toc->last_session_lba = msf_to_lba(0, 2, 0); /* 0m 2s 0f */
        }
 
-#if ! STANDARD_ATAPI
-       if (CDROM_CONFIG_FLAGS(drive)->tocaddr_as_bcd) {
+       if (info->cd_flags & IDE_CD_FLAG_TOCADDR_AS_BCD) {
                /* Re-read multisession information using MSF format */
                stat = cdrom_read_tocentry(drive, 0, 1, 1, (char *)&ms_tmp,
                                           sizeof(ms_tmp), sense);
@@ -2409,7 +1599,6 @@ static int cdrom_read_toc(ide_drive_t *drive, struct request_sense *sense)
                                                   ms_tmp.ent.addr.msf.second,
                                                   ms_tmp.ent.addr.msf.frame);
        }
-#endif  /* not STANDARD_ATAPI */
 
        toc->xa_flag = (ms_tmp.hdr.first_track != ms_tmp.hdr.last_track);
 
@@ -2422,278 +1611,22 @@ static int cdrom_read_toc(ide_drive_t *drive, struct request_sense *sense)
        }
 
        /* Remember that we've read this stuff. */
-       CDROM_STATE_FLAGS(drive)->toc_valid = 1;
+       info->cd_flags |= IDE_CD_FLAG_TOC_VALID;
 
        return 0;
 }
 
-
-static int cdrom_read_subchannel(ide_drive_t *drive, int format, char *buf,
-                                int buflen, struct request_sense *sense)
-{
-       struct request req;
-
-       cdrom_prepare_request(drive, &req);
-
-       req.sense = sense;
-       req.data = buf;
-       req.data_len = buflen;
-       req.cmd[0] = GPCMD_READ_SUBCHANNEL;
-       req.cmd[1] = 2;     /* MSF addressing */
-       req.cmd[2] = 0x40;  /* request subQ data */
-       req.cmd[3] = format;
-       req.cmd[7] = (buflen >> 8);
-       req.cmd[8] = (buflen & 0xff);
-       return cdrom_queue_packet_command(drive, &req);
-}
-
-/* ATAPI cdrom drives are free to select the speed you request or any slower
-   rate :-( Requesting too fast a speed will _not_ produce an error. */
-static int cdrom_select_speed(ide_drive_t *drive, int speed,
-                             struct request_sense *sense)
-{
-       struct request req;
-       cdrom_prepare_request(drive, &req);
-
-       req.sense = sense;
-       if (speed == 0)
-               speed = 0xffff; /* set to max */
-       else
-               speed *= 177;   /* Nx to kbytes/s */
-
-       req.cmd[0] = GPCMD_SET_SPEED;
-       /* Read Drive speed in kbytes/second MSB */
-       req.cmd[2] = (speed >> 8) & 0xff;       
-       /* Read Drive speed in kbytes/second LSB */
-       req.cmd[3] = speed & 0xff;
-       if (CDROM_CONFIG_FLAGS(drive)->cd_r ||
-           CDROM_CONFIG_FLAGS(drive)->cd_rw ||
-           CDROM_CONFIG_FLAGS(drive)->dvd_r) {
-               /* Write Drive speed in kbytes/second MSB */
-               req.cmd[4] = (speed >> 8) & 0xff;
-               /* Write Drive speed in kbytes/second LSB */
-               req.cmd[5] = speed & 0xff;
-       }
-
-       return cdrom_queue_packet_command(drive, &req);
-}
-
-static int cdrom_play_audio(ide_drive_t *drive, int lba_start, int lba_end)
-{
-       struct request_sense sense;
-       struct request req;
-
-       cdrom_prepare_request(drive, &req);
-
-       req.sense = &sense;
-       req.cmd[0] = GPCMD_PLAY_AUDIO_MSF;
-       lba_to_msf(lba_start, &req.cmd[3], &req.cmd[4], &req.cmd[5]);
-       lba_to_msf(lba_end-1, &req.cmd[6], &req.cmd[7], &req.cmd[8]);
-
-       return cdrom_queue_packet_command(drive, &req);
-}
-
-static int cdrom_get_toc_entry(ide_drive_t *drive, int track,
-                               struct atapi_toc_entry **ent)
-{
-       struct cdrom_info *info = drive->driver_data;
-       struct atapi_toc *toc = info->toc;
-       int ntracks;
-
-       /*
-        * don't serve cached data, if the toc isn't valid
-        */
-       if (!CDROM_STATE_FLAGS(drive)->toc_valid)
-               return -EINVAL;
-
-       /* Check validity of requested track number. */
-       ntracks = toc->hdr.last_track - toc->hdr.first_track + 1;
-       if (toc->hdr.first_track == CDROM_LEADOUT) ntracks = 0;
-       if (track == CDROM_LEADOUT)
-               *ent = &toc->ent[ntracks];
-       else if (track < toc->hdr.first_track ||
-                track > toc->hdr.last_track)
-               return -EINVAL;
-       else
-               *ent = &toc->ent[track - toc->hdr.first_track];
-
-       return 0;
-}
-
-/* the generic packet interface to cdrom.c */
-static int ide_cdrom_packet(struct cdrom_device_info *cdi,
-                           struct packet_command *cgc)
-{
-       struct request req;
-       ide_drive_t *drive = cdi->handle;
-
-       if (cgc->timeout <= 0)
-               cgc->timeout = ATAPI_WAIT_PC;
-
-       /* here we queue the commands from the uniform CD-ROM
-          layer. the packet must be complete, as we do not
-          touch it at all. */
-       cdrom_prepare_request(drive, &req);
-       memcpy(req.cmd, cgc->cmd, CDROM_PACKET_SIZE);
-       if (cgc->sense)
-               memset(cgc->sense, 0, sizeof(struct request_sense));
-       req.data = cgc->buffer;
-       req.data_len = cgc->buflen;
-       req.timeout = cgc->timeout;
-
-       if (cgc->quiet)
-               req.cmd_flags |= REQ_QUIET;
-
-       req.sense = cgc->sense;
-       cgc->stat = cdrom_queue_packet_command(drive, &req);
-       if (!cgc->stat)
-               cgc->buflen -= req.data_len;
-       return cgc->stat;
-}
-
-static
-int ide_cdrom_audio_ioctl (struct cdrom_device_info *cdi,
-                          unsigned int cmd, void *arg)
-                          
-{
-       ide_drive_t *drive = cdi->handle;
-       struct cdrom_info *info = drive->driver_data;
-       int stat;
-
-       switch (cmd) {
-       /*
-        * emulate PLAY_AUDIO_TI command with PLAY_AUDIO_10, since
-        * atapi doesn't support it
-        */
-       case CDROMPLAYTRKIND: {
-               unsigned long lba_start, lba_end;
-               struct cdrom_ti *ti = arg;
-               struct atapi_toc_entry *first_toc, *last_toc;
-
-               stat = cdrom_get_toc_entry(drive, ti->cdti_trk0, &first_toc);
-               if (stat)
-                       return stat;
-
-               stat = cdrom_get_toc_entry(drive, ti->cdti_trk1, &last_toc);
-               if (stat)
-                       return stat;
-
-               if (ti->cdti_trk1 != CDROM_LEADOUT)
-                       ++last_toc;
-               lba_start = first_toc->addr.lba;
-               lba_end   = last_toc->addr.lba;
-
-               if (lba_end <= lba_start)
-                       return -EINVAL;
-
-               return cdrom_play_audio(drive, lba_start, lba_end);
-       }
-
-       case CDROMREADTOCHDR: {
-               struct cdrom_tochdr *tochdr = arg;
-               struct atapi_toc *toc;
-
-               /* Make sure our saved TOC is valid. */
-               stat = cdrom_read_toc(drive, NULL);
-               if (stat)
-                       return stat;
-
-               toc = info->toc;
-               tochdr->cdth_trk0 = toc->hdr.first_track;
-               tochdr->cdth_trk1 = toc->hdr.last_track;
-
-               return 0;
-       }
-
-       case CDROMREADTOCENTRY: {
-               struct cdrom_tocentry *tocentry = arg;
-               struct atapi_toc_entry *toce;
-
-               stat = cdrom_get_toc_entry(drive, tocentry->cdte_track, &toce);
-               if (stat)
-                       return stat;
-
-               tocentry->cdte_ctrl = toce->control;
-               tocentry->cdte_adr  = toce->adr;
-               if (tocentry->cdte_format == CDROM_MSF) {
-                       lba_to_msf (toce->addr.lba,
-                                  &tocentry->cdte_addr.msf.minute,
-                                  &tocentry->cdte_addr.msf.second,
-                                  &tocentry->cdte_addr.msf.frame);
-               } else
-                       tocentry->cdte_addr.lba = toce->addr.lba;
-
-               return 0;
-       }
-
-       default:
-               return -EINVAL;
-       }
-}
-
-static
-int ide_cdrom_reset (struct cdrom_device_info *cdi)
-{
-       ide_drive_t *drive = cdi->handle;
-       struct request_sense sense;
-       struct request req;
-       int ret;
-
-       cdrom_prepare_request(drive, &req);
-       req.cmd_type = REQ_TYPE_SPECIAL;
-       req.cmd_flags = REQ_QUIET;
-       ret = ide_do_drive_cmd(drive, &req, ide_wait);
-
-       /*
-        * A reset will unlock the door. If it was previously locked,
-        * lock it again.
-        */
-       if (CDROM_STATE_FLAGS(drive)->door_locked)
-               (void) cdrom_lockdoor(drive, 1, &sense);
-
-       return ret;
-}
-
-
-static
-int ide_cdrom_tray_move (struct cdrom_device_info *cdi, int position)
-{
-       ide_drive_t *drive = cdi->handle;
-       struct request_sense sense;
-
-       if (position) {
-               int stat = cdrom_lockdoor(drive, 0, &sense);
-               if (stat)
-                       return stat;
-       }
-
-       return cdrom_eject(drive, !position, &sense);
-}
-
-static
-int ide_cdrom_lock_door (struct cdrom_device_info *cdi, int lock)
-{
-       ide_drive_t *drive = cdi->handle;
-       return cdrom_lockdoor(drive, lock, NULL);
-}
-
-static
-int ide_cdrom_get_capabilities(ide_drive_t *drive, struct atapi_capabilities_page *cap)
+int ide_cdrom_get_capabilities(ide_drive_t *drive, u8 *buf)
 {
        struct cdrom_info *info = drive->driver_data;
        struct cdrom_device_info *cdi = &info->devinfo;
        struct packet_command cgc;
-       int stat, attempts = 3, size = sizeof(*cap);
+       int stat, attempts = 3, size = ATAPI_CAPABILITIES_PAGE_SIZE;
 
-       /*
-        * ACER50 (and others?) require the full spec length mode sense
-        * page capabilities size, but older drives break.
-        */
-       if (!(!strcmp(drive->id->model, "ATAPI CD ROM DRIVE 50X MAX") ||
-           !strcmp(drive->id->model, "WPI CDS-32X")))
-               size -= sizeof(cap->pad);
+       if ((info->cd_flags & IDE_CD_FLAG_FULL_CAPS_PAGE) == 0)
+               size -= ATAPI_CAPABILITIES_PAGE_PAD_SIZE;
 
-       init_cdrom_command(&cgc, cap, size, CGC_DATA_UNKNOWN);
+       init_cdrom_command(&cgc, buf, size, CGC_DATA_UNKNOWN);
        do { /* we seem to get stat=0x01,err=0x00 the first time (??) */
                stat = cdrom_mode_sense(cdi, &cgc, GPMODE_CAPABILITIES_PAGE, 0);
                if (!stat)
@@ -2702,177 +1635,33 @@ int ide_cdrom_get_capabilities(ide_drive_t *drive, struct atapi_capabilities_pag
        return stat;
 }
 
-static
-void ide_cdrom_update_speed (ide_drive_t *drive, struct atapi_capabilities_page *cap)
+void ide_cdrom_update_speed(ide_drive_t *drive, u8 *buf)
 {
-       /* The ACER/AOpen 24X cdrom has the speed fields byte-swapped */
-       if (!drive->id->model[0] &&
-           !strncmp(drive->id->fw_rev, "241N", 4)) {
-               CDROM_STATE_FLAGS(drive)->current_speed  =
-                       (le16_to_cpu(cap->curspeed) + (176/2)) / 176;
-               CDROM_CONFIG_FLAGS(drive)->max_speed =
-                       (le16_to_cpu(cap->maxspeed) + (176/2)) / 176;
-       } else {
-               CDROM_STATE_FLAGS(drive)->current_speed  =
-                       (be16_to_cpu(cap->curspeed) + (176/2)) / 176;
-               CDROM_CONFIG_FLAGS(drive)->max_speed =
-                       (be16_to_cpu(cap->maxspeed) + (176/2)) / 176;
-       }
-}
-
-static
-int ide_cdrom_select_speed (struct cdrom_device_info *cdi, int speed)
-{
-       ide_drive_t *drive = cdi->handle;
-       struct request_sense sense;
-       struct atapi_capabilities_page cap;
-       int stat;
-
-       if ((stat = cdrom_select_speed(drive, speed, &sense)) < 0)
-               return stat;
-
-       if (!ide_cdrom_get_capabilities(drive, &cap)) {
-               ide_cdrom_update_speed(drive, &cap);
-               cdi->speed = CDROM_STATE_FLAGS(drive)->current_speed;
-       }
-        return 0;
-}
-
-/*
- * add logic to try GET_EVENT command first to check for media and tray
- * status. this should be supported by newer cd-r/w and all DVD etc
- * drives
- */
-static
-int ide_cdrom_drive_status (struct cdrom_device_info *cdi, int slot_nr)
-{
-       ide_drive_t *drive = cdi->handle;
-       struct media_event_desc med;
-       struct request_sense sense;
-       int stat;
-
-       if (slot_nr != CDSL_CURRENT)
-               return -EINVAL;
-
-       stat = cdrom_check_status(drive, &sense);
-       if (!stat || sense.sense_key == UNIT_ATTENTION)
-               return CDS_DISC_OK;
-
-       if (!cdrom_get_media_event(cdi, &med)) {
-               if (med.media_present)
-                       return CDS_DISC_OK;
-               else if (med.door_open)
-                       return CDS_TRAY_OPEN;
-               else
-                       return CDS_NO_DISC;
-       }
-
-       if (sense.sense_key == NOT_READY && sense.asc == 0x04 && sense.ascq == 0x04)
-               return CDS_DISC_OK;
-
-       /*
-        * If not using Mt Fuji extended media tray reports,
-        * just return TRAY_OPEN since ATAPI doesn't provide
-        * any other way to detect this...
-        */
-       if (sense.sense_key == NOT_READY) {
-               if (sense.asc == 0x3a && sense.ascq == 1)
-                       return CDS_NO_DISC;
-               else
-                       return CDS_TRAY_OPEN;
-       }
-       return CDS_DRIVE_NOT_READY;
-}
-
-static
-int ide_cdrom_get_last_session (struct cdrom_device_info *cdi,
-                               struct cdrom_multisession *ms_info)
-{
-       struct atapi_toc *toc;
-       ide_drive_t *drive = cdi->handle;
-       struct cdrom_info *info = drive->driver_data;
-       struct request_sense sense;
-       int ret;
-
-       if (!CDROM_STATE_FLAGS(drive)->toc_valid || info->toc == NULL)
-               if ((ret = cdrom_read_toc(drive, &sense)))
-                       return ret;
-
-       toc = info->toc;
-       ms_info->addr.lba = toc->last_session_lba;
-       ms_info->xa_flag = toc->xa_flag;
-
-       return 0;
-}
-
-static
-int ide_cdrom_get_mcn (struct cdrom_device_info *cdi,
-                      struct cdrom_mcn *mcn_info)
-{
-       int stat;
-       char mcnbuf[24];
-       ide_drive_t *drive = cdi->handle;
-
-/* get MCN */
-       if ((stat = cdrom_read_subchannel(drive, 2, mcnbuf, sizeof (mcnbuf), NULL)))
-               return stat;
-
-       memcpy (mcn_info->medium_catalog_number, mcnbuf+9,
-               sizeof (mcn_info->medium_catalog_number)-1);
-       mcn_info->medium_catalog_number[sizeof (mcn_info->medium_catalog_number)-1]
-               = '\0';
-
-       return 0;
-}
-
-
+       struct cdrom_info *cd = drive->driver_data;
+       u16 curspeed, maxspeed;
 
-/****************************************************************************
- * Other driver requests (open, close, check media change).
- */
+       curspeed = *(u16 *)&buf[8 + 14];
+       maxspeed = *(u16 *)&buf[8 +  8];
 
-static
-int ide_cdrom_check_media_change_real (struct cdrom_device_info *cdi,
-                                      int slot_nr)
-{
-       ide_drive_t *drive = cdi->handle;
-       int retval;
-       
-       if (slot_nr == CDSL_CURRENT) {
-               (void) cdrom_check_status(drive, NULL);
-               retval = CDROM_STATE_FLAGS(drive)->media_changed;
-               CDROM_STATE_FLAGS(drive)->media_changed = 0;
-               return retval;
+       if (cd->cd_flags & IDE_CD_FLAG_LE_SPEED_FIELDS) {
+               curspeed = le16_to_cpu(curspeed);
+               maxspeed = le16_to_cpu(maxspeed);
        } else {
-               return -EINVAL;
+               curspeed = be16_to_cpu(curspeed);
+               maxspeed = be16_to_cpu(maxspeed);
        }
-}
 
-
-static
-int ide_cdrom_open_real (struct cdrom_device_info *cdi, int purpose)
-{
-       return 0;
+       cd->current_speed = (curspeed + (176/2)) / 176;
+       cd->max_speed = (maxspeed + (176/2)) / 176;
 }
 
-/*
- * Close down the device.  Invalidate all cached blocks.
- */
-
-static
-void ide_cdrom_release_real (struct cdrom_device_info *cdi)
-{
-       ide_drive_t *drive = cdi->handle;
-
-       if (!cdi->use_count)
-               CDROM_STATE_FLAGS(drive)->toc_valid = 0;
-}
+#define IDE_CD_CAPABILITIES \
+       (CDC_CLOSE_TRAY | CDC_OPEN_TRAY | CDC_LOCK | CDC_SELECT_SPEED | \
+        CDC_SELECT_DISC | CDC_MULTI_SESSION | CDC_MCN | CDC_MEDIA_CHANGED | \
+        CDC_PLAY_AUDIO | CDC_RESET | CDC_DRIVE_STATUS | CDC_CD_R | \
+        CDC_CD_RW | CDC_DVD | CDC_DVD_R | CDC_DVD_RAM | CDC_GENERIC_PACKET | \
+        CDC_MO_DRIVE | CDC_MRW | CDC_MRW_W | CDC_RAM)
 
-
-
-/****************************************************************************
- * Device initialization.
- */
 static struct cdrom_device_ops ide_cdrom_dops = {
        .open                   = ide_cdrom_open_real,
        .release                = ide_cdrom_release_real,
@@ -2885,14 +1674,7 @@ static struct cdrom_device_ops ide_cdrom_dops = {
        .get_mcn                = ide_cdrom_get_mcn,
        .reset                  = ide_cdrom_reset,
        .audio_ioctl            = ide_cdrom_audio_ioctl,
-       .capability             = CDC_CLOSE_TRAY | CDC_OPEN_TRAY | CDC_LOCK |
-                               CDC_SELECT_SPEED | CDC_SELECT_DISC |
-                               CDC_MULTI_SESSION | CDC_MCN |
-                               CDC_MEDIA_CHANGED | CDC_PLAY_AUDIO | CDC_RESET |
-                               CDC_DRIVE_STATUS | CDC_CD_R |
-                               CDC_CD_RW | CDC_DVD | CDC_DVD_R| CDC_DVD_RAM |
-                               CDC_GENERIC_PACKET | CDC_MO_DRIVE | CDC_MRW |
-                               CDC_MRW_W | CDC_RAM,
+       .capability             = IDE_CD_CAPABILITIES,
        .generic_packet         = ide_cdrom_packet,
 };
 
@@ -2902,35 +1684,12 @@ static int ide_cdrom_register (ide_drive_t *drive, int nslots)
        struct cdrom_device_info *devinfo = &info->devinfo;
 
        devinfo->ops = &ide_cdrom_dops;
-       devinfo->mask = 0;
-       devinfo->speed = CDROM_STATE_FLAGS(drive)->current_speed;
+       devinfo->speed = info->current_speed;
        devinfo->capacity = nslots;
        devinfo->handle = drive;
        strcpy(devinfo->name, drive->name);
-       
-       /* set capability mask to match the probe. */
-       if (!CDROM_CONFIG_FLAGS(drive)->cd_r)
-               devinfo->mask |= CDC_CD_R;
-       if (!CDROM_CONFIG_FLAGS(drive)->cd_rw)
-               devinfo->mask |= CDC_CD_RW;
-       if (!CDROM_CONFIG_FLAGS(drive)->dvd)
-               devinfo->mask |= CDC_DVD;
-       if (!CDROM_CONFIG_FLAGS(drive)->dvd_r)
-               devinfo->mask |= CDC_DVD_R;
-       if (!CDROM_CONFIG_FLAGS(drive)->dvd_ram)
-               devinfo->mask |= CDC_DVD_RAM;
-       if (!CDROM_CONFIG_FLAGS(drive)->is_changer)
-               devinfo->mask |= CDC_SELECT_DISC;
-       if (!CDROM_CONFIG_FLAGS(drive)->audio_play)
-               devinfo->mask |= CDC_PLAY_AUDIO;
-       if (!CDROM_CONFIG_FLAGS(drive)->close_tray)
-               devinfo->mask |= CDC_CLOSE_TRAY;
-       if (!CDROM_CONFIG_FLAGS(drive)->mo_drive)
-               devinfo->mask |= CDC_MO_DRIVE;
-       if (!CDROM_CONFIG_FLAGS(drive)->ram)
-               devinfo->mask |= CDC_RAM;
-
-       if (CDROM_CONFIG_FLAGS(drive)->no_speed_select)
+
+       if (info->cd_flags & IDE_CD_FLAG_NO_SPEED_SELECT)
                devinfo->mask |= CDC_SELECT_SPEED;
 
        devinfo->disk = info->disk;
@@ -2940,22 +1699,25 @@ static int ide_cdrom_register (ide_drive_t *drive, int nslots)
 static
 int ide_cdrom_probe_capabilities (ide_drive_t *drive)
 {
-       struct cdrom_info *info = drive->driver_data;
-       struct cdrom_device_info *cdi = &info->devinfo;
-       struct atapi_capabilities_page cap;
+       struct cdrom_info *cd = drive->driver_data;
+       struct cdrom_device_info *cdi = &cd->devinfo;
+       u8 buf[ATAPI_CAPABILITIES_PAGE_SIZE];
+       mechtype_t mechtype;
        int nslots = 1;
 
+       cdi->mask = (CDC_CD_R | CDC_CD_RW | CDC_DVD | CDC_DVD_R |
+                    CDC_DVD_RAM | CDC_SELECT_DISC | CDC_PLAY_AUDIO |
+                    CDC_MO_DRIVE | CDC_RAM);
+
        if (drive->media == ide_optical) {
-               CDROM_CONFIG_FLAGS(drive)->mo_drive = 1;
-               CDROM_CONFIG_FLAGS(drive)->ram = 1;
+               cdi->mask &= ~(CDC_MO_DRIVE | CDC_RAM);
                printk(KERN_ERR "%s: ATAPI magneto-optical drive\n", drive->name);
                return nslots;
        }
 
-       if (CDROM_CONFIG_FLAGS(drive)->nec260 ||
-           !strcmp(drive->id->model,"STINGRAY 8422 IDE 8X CD-ROM 7-27-95")) {
-               CDROM_CONFIG_FLAGS(drive)->no_eject = 0;
-               CDROM_CONFIG_FLAGS(drive)->audio_play = 1;
+       if (cd->cd_flags & IDE_CD_FLAG_PRE_ATAPI12) {
+               cd->cd_flags &= ~IDE_CD_FLAG_NO_EJECT;
+               cdi->mask &= ~CDC_PLAY_AUDIO;
                return nslots;
        }
 
@@ -2969,83 +1731,66 @@ int ide_cdrom_probe_capabilities (ide_drive_t *drive)
        cdi->handle = drive;
        cdi->ops = &ide_cdrom_dops;
 
-       if (ide_cdrom_get_capabilities(drive, &cap))
+       if (ide_cdrom_get_capabilities(drive, buf))
                return 0;
 
-       if (cap.lock == 0)
-               CDROM_CONFIG_FLAGS(drive)->no_doorlock = 1;
-       if (cap.eject)
-               CDROM_CONFIG_FLAGS(drive)->no_eject = 0;
-       if (cap.cd_r_write)
-               CDROM_CONFIG_FLAGS(drive)->cd_r = 1;
-       if (cap.cd_rw_write) {
-               CDROM_CONFIG_FLAGS(drive)->cd_rw = 1;
-               CDROM_CONFIG_FLAGS(drive)->ram = 1;
-       }
-       if (cap.test_write)
-               CDROM_CONFIG_FLAGS(drive)->test_write = 1;
-       if (cap.dvd_ram_read || cap.dvd_r_read || cap.dvd_rom)
-               CDROM_CONFIG_FLAGS(drive)->dvd = 1;
-       if (cap.dvd_ram_write) {
-               CDROM_CONFIG_FLAGS(drive)->dvd_ram = 1;
-               CDROM_CONFIG_FLAGS(drive)->ram = 1;
-       }
-       if (cap.dvd_r_write)
-               CDROM_CONFIG_FLAGS(drive)->dvd_r = 1;
-       if (cap.audio_play)
-               CDROM_CONFIG_FLAGS(drive)->audio_play = 1;
-       if (cap.mechtype == mechtype_caddy || cap.mechtype == mechtype_popup)
-               CDROM_CONFIG_FLAGS(drive)->close_tray = 0;
-
-       /* Some drives used by Apple don't advertise audio play
-        * but they do support reading TOC & audio datas
-        */
-       if (strcmp(drive->id->model, "MATSHITADVD-ROM SR-8187") == 0 ||
-           strcmp(drive->id->model, "MATSHITADVD-ROM SR-8186") == 0 ||
-           strcmp(drive->id->model, "MATSHITADVD-ROM SR-8176") == 0 ||
-           strcmp(drive->id->model, "MATSHITADVD-ROM SR-8174") == 0)
-               CDROM_CONFIG_FLAGS(drive)->audio_play = 1;
+       if ((buf[8 + 6] & 0x01) == 0)
+               cd->cd_flags |= IDE_CD_FLAG_NO_DOORLOCK;
+       if (buf[8 + 6] & 0x08)
+               cd->cd_flags &= ~IDE_CD_FLAG_NO_EJECT;
+       if (buf[8 + 3] & 0x01)
+               cdi->mask &= ~CDC_CD_R;
+       if (buf[8 + 3] & 0x02)
+               cdi->mask &= ~(CDC_CD_RW | CDC_RAM);
+       if (buf[8 + 2] & 0x38)
+               cdi->mask &= ~CDC_DVD;
+       if (buf[8 + 3] & 0x20)
+               cdi->mask &= ~(CDC_DVD_RAM | CDC_RAM);
+       if (buf[8 + 3] & 0x10)
+               cdi->mask &= ~CDC_DVD_R;
+       if ((buf[8 + 4] & 0x01) || (cd->cd_flags & IDE_CD_FLAG_PLAY_AUDIO_OK))
+               cdi->mask &= ~CDC_PLAY_AUDIO;
+
+       mechtype = buf[8 + 6] >> 5;
+       if (mechtype == mechtype_caddy || mechtype == mechtype_popup)
+               cdi->mask |= CDC_CLOSE_TRAY;
 
-#if ! STANDARD_ATAPI
        if (cdi->sanyo_slot > 0) {
-               CDROM_CONFIG_FLAGS(drive)->is_changer = 1;
+               cdi->mask &= ~CDC_SELECT_DISC;
                nslots = 3;
+       } else if (mechtype == mechtype_individual_changer ||
+                  mechtype == mechtype_cartridge_changer) {
+               nslots = cdrom_number_of_slots(cdi);
+               if (nslots > 1)
+                       cdi->mask &= ~CDC_SELECT_DISC;
        }
 
-       else
-#endif /* not STANDARD_ATAPI */
-       if (cap.mechtype == mechtype_individual_changer ||
-           cap.mechtype == mechtype_cartridge_changer) {
-               if ((nslots = cdrom_number_of_slots(cdi)) > 1) {
-                       CDROM_CONFIG_FLAGS(drive)->is_changer = 1;
-                       CDROM_CONFIG_FLAGS(drive)->supp_disc_present = 1;
-               }
-       }
+       ide_cdrom_update_speed(drive, buf);
 
-       ide_cdrom_update_speed(drive, &cap);
-       /* don't print speed if the drive reported 0.
-        */
        printk(KERN_INFO "%s: ATAPI", drive->name);
-       if (CDROM_CONFIG_FLAGS(drive)->max_speed)
-               printk(" %dX", CDROM_CONFIG_FLAGS(drive)->max_speed);
-       printk(" %s", CDROM_CONFIG_FLAGS(drive)->dvd ? "DVD-ROM" : "CD-ROM");
 
-       if (CDROM_CONFIG_FLAGS(drive)->dvd_r|CDROM_CONFIG_FLAGS(drive)->dvd_ram)
-               printk(" DVD%s%s", 
-               (CDROM_CONFIG_FLAGS(drive)->dvd_r)? "-R" : "", 
-               (CDROM_CONFIG_FLAGS(drive)->dvd_ram)? "-RAM" : "");
+       /* don't print speed if the drive reported 0 */
+       if (cd->max_speed)
+               printk(KERN_CONT " %dX", cd->max_speed);
 
-        if (CDROM_CONFIG_FLAGS(drive)->cd_r|CDROM_CONFIG_FLAGS(drive)->cd_rw) 
-               printk(" CD%s%s", 
-               (CDROM_CONFIG_FLAGS(drive)->cd_r)? "-R" : "", 
-               (CDROM_CONFIG_FLAGS(drive)->cd_rw)? "/RW" : "");
+       printk(KERN_CONT " %s", (cdi->mask & CDC_DVD) ? "CD-ROM" : "DVD-ROM");
 
-        if (CDROM_CONFIG_FLAGS(drive)->is_changer) 
-               printk(" changer w/%d slots", nslots);
-        else   
-               printk(" drive");
+       if ((cdi->mask & CDC_DVD_R) == 0 || (cdi->mask & CDC_DVD_RAM) == 0)
+               printk(KERN_CONT " DVD%s%s",
+                                (cdi->mask & CDC_DVD_R) ? "" : "-R",
+                                (cdi->mask & CDC_DVD_RAM) ? "" : "-RAM");
 
-       printk(KERN_CONT ", %dkB Cache\n", be16_to_cpu(cap.buffer_size));
+       if ((cdi->mask & CDC_CD_R) == 0 || (cdi->mask & CDC_CD_RW) == 0)
+               printk(KERN_CONT " CD%s%s",
+                                (cdi->mask & CDC_CD_R) ? "" : "-R",
+                                (cdi->mask & CDC_CD_RW) ? "" : "/RW");
+
+       if ((cdi->mask & CDC_SELECT_DISC) == 0)
+               printk(KERN_CONT " changer w/%d slots", nslots);
+       else
+               printk(KERN_CONT " drive");
+
+       printk(KERN_CONT ", %dkB Cache\n", be16_to_cpu(*(u16 *)&buf[8 + 12]));
 
        return nslots;
 }
@@ -3138,11 +1883,74 @@ static int ide_cdrom_prep_fn(struct request_queue *q, struct request *rq)
        return 0;
 }
 
+struct cd_list_entry {
+       const char      *id_model;
+       const char      *id_firmware;
+       unsigned int    cd_flags;
+};
+
+static const struct cd_list_entry ide_cd_quirks_list[] = {
+       /* Limit transfer size per interrupt. */
+       { "SAMSUNG CD-ROM SCR-2430", NULL,   IDE_CD_FLAG_LIMIT_NFRAMES      },
+       { "SAMSUNG CD-ROM SCR-2432", NULL,   IDE_CD_FLAG_LIMIT_NFRAMES      },
+       /* SCR-3231 doesn't support the SET_CD_SPEED command. */
+       { "SAMSUNG CD-ROM SCR-3231", NULL,   IDE_CD_FLAG_NO_SPEED_SELECT    },
+       /* Old NEC260 (not R) was released before ATAPI 1.2 spec. */
+       { "NEC CD-ROM DRIVE:260",    "1.01", IDE_CD_FLAG_TOCADDR_AS_BCD |
+                                            IDE_CD_FLAG_PRE_ATAPI12,       },
+       /* Vertos 300, some versions of this drive like to talk BCD. */
+       { "V003S0DS",                NULL,   IDE_CD_FLAG_VERTOS_300_SSD,    },
+       /* Vertos 600 ESD. */
+       { "V006E0DS",                NULL,   IDE_CD_FLAG_VERTOS_600_ESD,    },
+       /*
+        * Sanyo 3 CD changer uses a non-standard command for CD changing
+        * (by default standard ATAPI support for CD changers is used).
+        */
+       { "CD-ROM CDR-C3 G",         NULL,   IDE_CD_FLAG_SANYO_3CD          },
+       { "CD-ROM CDR-C3G",          NULL,   IDE_CD_FLAG_SANYO_3CD          },
+       { "CD-ROM CDR_C36",          NULL,   IDE_CD_FLAG_SANYO_3CD          },
+       /* Stingray 8X CD-ROM. */
+       { "STINGRAY 8422 IDE 8X CD-ROM 7-27-95", NULL, IDE_CD_FLAG_PRE_ATAPI12},
+       /*
+        * ACER 50X CD-ROM and WPI 32X CD-ROM require the full spec length
+        * mode sense page capabilities size, but older drives break.
+        */
+       { "ATAPI CD ROM DRIVE 50X MAX", NULL,   IDE_CD_FLAG_FULL_CAPS_PAGE  },
+       { "WPI CDS-32X",                NULL,   IDE_CD_FLAG_FULL_CAPS_PAGE  },
+       /* ACER/AOpen 24X CD-ROM has the speed fields byte-swapped. */
+       { "",                        "241N", IDE_CD_FLAG_LE_SPEED_FIELDS    },
+       /*
+        * Some drives used by Apple don't advertise audio play
+        * but they do support reading TOC & audio datas.
+        */
+       { "MATSHITADVD-ROM SR-8187", NULL,   IDE_CD_FLAG_PLAY_AUDIO_OK      },
+       { "MATSHITADVD-ROM SR-8186", NULL,   IDE_CD_FLAG_PLAY_AUDIO_OK      },
+       { "MATSHITADVD-ROM SR-8176", NULL,   IDE_CD_FLAG_PLAY_AUDIO_OK      },
+       { "MATSHITADVD-ROM SR-8174", NULL,   IDE_CD_FLAG_PLAY_AUDIO_OK      },
+       { NULL, NULL, 0 }
+};
+
+static unsigned int ide_cd_flags(struct hd_driveid *id)
+{
+       const struct cd_list_entry *cle = ide_cd_quirks_list;
+
+       while (cle->id_model) {
+               if (strcmp(cle->id_model, id->model) == 0 &&
+                   (cle->id_firmware == NULL ||
+                    strstr(id->fw_rev, cle->id_firmware)))
+                       return cle->cd_flags;
+               cle++;
+       }
+
+       return 0;
+}
+
 static
 int ide_cdrom_setup (ide_drive_t *drive)
 {
-       struct cdrom_info *info = drive->driver_data;
-       struct cdrom_device_info *cdi = &info->devinfo;
+       struct cdrom_info *cd = drive->driver_data;
+       struct cdrom_device_info *cdi = &cd->devinfo;
+       struct hd_driveid *id = drive->id;
        int nslots;
 
        blk_queue_prep_rq(drive->queue, ide_cdrom_prep_fn);
@@ -3153,101 +1961,21 @@ int ide_cdrom_setup (ide_drive_t *drive)
 
        drive->special.all      = 0;
 
-       CDROM_STATE_FLAGS(drive)->media_changed = 1;
-       CDROM_STATE_FLAGS(drive)->toc_valid     = 0;
-       CDROM_STATE_FLAGS(drive)->door_locked   = 0;
-
-#if NO_DOOR_LOCKING
-       CDROM_CONFIG_FLAGS(drive)->no_doorlock = 1;
-#else
-       CDROM_CONFIG_FLAGS(drive)->no_doorlock = 0;
-#endif
+       cd->cd_flags = IDE_CD_FLAG_MEDIA_CHANGED | IDE_CD_FLAG_NO_EJECT |
+                      ide_cd_flags(id);
 
-       CDROM_CONFIG_FLAGS(drive)->drq_interrupt = ((drive->id->config & 0x0060) == 0x20);
-       CDROM_CONFIG_FLAGS(drive)->is_changer = 0;
-       CDROM_CONFIG_FLAGS(drive)->cd_r = 0;
-       CDROM_CONFIG_FLAGS(drive)->cd_rw = 0;
-       CDROM_CONFIG_FLAGS(drive)->test_write = 0;
-       CDROM_CONFIG_FLAGS(drive)->dvd = 0;
-       CDROM_CONFIG_FLAGS(drive)->dvd_r = 0;
-       CDROM_CONFIG_FLAGS(drive)->dvd_ram = 0;
-       CDROM_CONFIG_FLAGS(drive)->no_eject = 1;
-       CDROM_CONFIG_FLAGS(drive)->supp_disc_present = 0;
-       CDROM_CONFIG_FLAGS(drive)->audio_play = 0;
-       CDROM_CONFIG_FLAGS(drive)->close_tray = 1;
-       
-       /* limit transfer size per interrupt. */
-       CDROM_CONFIG_FLAGS(drive)->limit_nframes = 0;
-       /* a testament to the nice quality of Samsung drives... */
-       if (!strcmp(drive->id->model, "SAMSUNG CD-ROM SCR-2430"))
-               CDROM_CONFIG_FLAGS(drive)->limit_nframes = 1;
-       else if (!strcmp(drive->id->model, "SAMSUNG CD-ROM SCR-2432"))
-               CDROM_CONFIG_FLAGS(drive)->limit_nframes = 1;
-       /* the 3231 model does not support the SET_CD_SPEED command */
-       else if (!strcmp(drive->id->model, "SAMSUNG CD-ROM SCR-3231"))
-               CDROM_CONFIG_FLAGS(drive)->no_speed_select = 1;
-
-#if ! STANDARD_ATAPI
-       /* by default Sanyo 3 CD changer support is turned off and
-           ATAPI Rev 2.2+ standard support for CD changers is used */
-       cdi->sanyo_slot = 0;
-
-       CDROM_CONFIG_FLAGS(drive)->nec260 = 0;
-       CDROM_CONFIG_FLAGS(drive)->toctracks_as_bcd = 0;
-       CDROM_CONFIG_FLAGS(drive)->tocaddr_as_bcd = 0;
-       CDROM_CONFIG_FLAGS(drive)->playmsf_as_bcd = 0;
-       CDROM_CONFIG_FLAGS(drive)->subchan_as_bcd = 0;
-
-       if (strcmp (drive->id->model, "V003S0DS") == 0 &&
-           drive->id->fw_rev[4] == '1' &&
-           drive->id->fw_rev[6] <= '2') {
-               /* Vertos 300.
-                  Some versions of this drive like to talk BCD. */
-               CDROM_CONFIG_FLAGS(drive)->toctracks_as_bcd = 1;
-               CDROM_CONFIG_FLAGS(drive)->tocaddr_as_bcd = 1;
-               CDROM_CONFIG_FLAGS(drive)->playmsf_as_bcd = 1;
-               CDROM_CONFIG_FLAGS(drive)->subchan_as_bcd = 1;
-       }
+       if ((id->config & 0x0060) == 0x20)
+               cd->cd_flags |= IDE_CD_FLAG_DRQ_INTERRUPT;
 
-       else if (strcmp (drive->id->model, "V006E0DS") == 0 &&
-           drive->id->fw_rev[4] == '1' &&
-           drive->id->fw_rev[6] <= '2') {
-               /* Vertos 600 ESD. */
-               CDROM_CONFIG_FLAGS(drive)->toctracks_as_bcd = 1;
-       }
-       else if (strcmp(drive->id->model, "NEC CD-ROM DRIVE:260") == 0 &&
-                strncmp(drive->id->fw_rev, "1.01", 4) == 0) { /* FIXME */
-               /* Old NEC260 (not R).
-                  This drive was released before the 1.2 version
-                  of the spec. */
-               CDROM_CONFIG_FLAGS(drive)->tocaddr_as_bcd = 1;
-               CDROM_CONFIG_FLAGS(drive)->playmsf_as_bcd = 1;
-               CDROM_CONFIG_FLAGS(drive)->subchan_as_bcd = 1;
-               CDROM_CONFIG_FLAGS(drive)->nec260         = 1;
-       }
-       else if (strcmp(drive->id->model, "WEARNES CDD-120") == 0 &&
-                strncmp(drive->id->fw_rev, "A1.1", 4) == 0) { /* FIXME */
-               /* Wearnes */
-               CDROM_CONFIG_FLAGS(drive)->playmsf_as_bcd = 1;
-               CDROM_CONFIG_FLAGS(drive)->subchan_as_bcd = 1;
-       }
-        /* Sanyo 3 CD changer uses a non-standard command
-           for CD changing */
-        else if ((strcmp(drive->id->model, "CD-ROM CDR-C3 G") == 0) ||
-                 (strcmp(drive->id->model, "CD-ROM CDR-C3G") == 0) ||
-                 (strcmp(drive->id->model, "CD-ROM CDR_C36") == 0)) {
-                 /* uses CD in slot 0 when value is set to 3 */
-                 cdi->sanyo_slot = 3;
-        }
-#endif /* not STANDARD_ATAPI */
-
-       info->toc               = NULL;
-       info->buffer            = NULL;
-       info->sector_buffered   = 0;
-       info->nsectors_buffered = 0;
-       info->changer_info      = NULL;
-       info->last_block        = 0;
-       info->start_seek        = 0;
+       if ((cd->cd_flags & IDE_CD_FLAG_VERTOS_300_SSD) &&
+           id->fw_rev[4] == '1' && id->fw_rev[6] <= '2')
+               cd->cd_flags |= (IDE_CD_FLAG_TOCTRACKS_AS_BCD |
+                                IDE_CD_FLAG_TOCADDR_AS_BCD);
+       else if ((cd->cd_flags & IDE_CD_FLAG_VERTOS_600_ESD) &&
+                id->fw_rev[4] == '1' && id->fw_rev[6] <= '2')
+               cd->cd_flags |= IDE_CD_FLAG_TOCTRACKS_AS_BCD;
+       else if (cd->cd_flags & IDE_CD_FLAG_SANYO_3CD)
+               cdi->sanyo_slot = 3;    /* 3 => use CD in slot 0 */
 
        nslots = ide_cdrom_probe_capabilities (drive);
 
@@ -3262,7 +1990,7 @@ int ide_cdrom_setup (ide_drive_t *drive)
 
        if (ide_cdrom_register(drive, nslots)) {
                printk (KERN_ERR "%s: ide_cdrom_setup failed to register device with the cdrom driver.\n", drive->name);
-               info->devinfo.handle = NULL;
+               cd->devinfo.handle = NULL;
                return 1;
        }
        ide_cdrom_add_settings(drive);
@@ -3302,7 +2030,6 @@ static void ide_cd_release(struct kref *kref)
 
        kfree(info->buffer);
        kfree(info->toc);
-       kfree(info->changer_info);
        if (devinfo->handle == drive && unregister_cdrom(devinfo))
                printk(KERN_ERR "%s: %s failed to unregister device from the cdrom "
                                "driver.\n", __FUNCTION__, drive->name);
@@ -3458,7 +2185,9 @@ static int idecd_revalidate_disk(struct gendisk *disk)
 {
        struct cdrom_info *info = ide_cd_g(disk);
        struct request_sense sense;
-       cdrom_read_toc(info->drive, &sense);
+
+       ide_cd_read_toc(info->drive, &sense);
+
        return  0;
 }
 
@@ -3533,7 +2262,7 @@ static int ide_cd_probe(ide_drive_t *drive)
                goto failed;
        }
 
-       cdrom_read_toc(drive, &sense);
+       ide_cd_read_toc(drive, &sense);
        g->fops = &idecd_ops;
        g->flags |= GENHD_FL_REMOVABLE;
        add_disk(g);
@@ -3556,6 +2285,7 @@ static int __init ide_cdrom_init(void)
 }
 
 MODULE_ALIAS("ide:*m-cdrom*");
+MODULE_ALIAS("ide-cd");
 module_init(ide_cdrom_init);
 module_exit(ide_cdrom_exit);
 MODULE_LICENSE("GPL");
index 1b302fe2724d3d451f24278c61ecbab901792a9c..22e3751a681e0ce627aa1fb21cb95a88de298f8a 100644 (file)
@@ -1,6 +1,4 @@
 /*
- *  linux/drivers/ide/ide_cd.h
- *
  *  Copyright (C) 1996-98  Erik Andersen
  *  Copyright (C) 1998-2000 Jens Axboe
  */
@@ -10,31 +8,6 @@
 #include <linux/cdrom.h>
 #include <asm/byteorder.h>
 
-/* Turn this on to have the driver print out the meanings of the
-   ATAPI error codes.  This will use up additional kernel-space
-   memory, though. */
-
-#ifndef VERBOSE_IDE_CD_ERRORS
-#define VERBOSE_IDE_CD_ERRORS 1
-#endif
-
-
-/* Turning this on will remove code to work around various nonstandard
-   ATAPI implementations.  If you know your drive follows the standard,
-   this will give you a slightly smaller kernel. */
-
-#ifndef STANDARD_ATAPI
-#define STANDARD_ATAPI 0
-#endif
-
-
-/* Turning this on will disable the door-locking functionality.
-   This is apparently needed for supermount. */
-
-#ifndef NO_DOOR_LOCKING
-#define NO_DOOR_LOCKING 0
-#endif
-
 /*
  * typical timeout for packet command
  */
 #endif
 #define SECTORS_PER_FRAME      (CD_FRAMESIZE >> SECTOR_BITS)
 #define SECTOR_BUFFER_SIZE     (CD_FRAMESIZE * 32)
-#define SECTORS_BUFFER         (SECTOR_BUFFER_SIZE >> SECTOR_BITS)
-#define SECTORS_MAX            (131072 >> SECTOR_BITS)
-
-#define BLOCKS_PER_FRAME       (CD_FRAMESIZE / BLOCK_SIZE)
-
-/* special command codes for strategy routine. */
-#define PACKET_COMMAND        4315
-#define REQUEST_SENSE_COMMAND 4316
-#define RESET_DRIVE_COMMAND   4317
-
-
-/* Configuration flags.  These describe the capabilities of the drive.
-   They generally do not change after initialization, unless we learn
-   more about the drive from stuff failing. */
-struct ide_cd_config_flags {
-       __u8 drq_interrupt      : 1; /* Device sends an interrupt when ready
-                                       for a packet command. */
-       __u8 no_doorlock        : 1; /* Drive cannot lock the door. */
-       __u8 no_eject           : 1; /* Drive cannot eject the disc. */
-       __u8 nec260             : 1; /* Drive is a pre-1.2 NEC 260 drive. */
-       __u8 playmsf_as_bcd     : 1; /* PLAYMSF command takes BCD args. */
-       __u8 tocaddr_as_bcd     : 1; /* TOC addresses are in BCD. */
-       __u8 toctracks_as_bcd   : 1; /* TOC track numbers are in BCD. */
-       __u8 subchan_as_bcd     : 1; /* Subchannel info is in BCD. */
-       __u8 is_changer         : 1; /* Drive is a changer. */
-       __u8 cd_r               : 1; /* Drive can write to CD-R media . */
-       __u8 cd_rw              : 1; /* Drive can write to CD-R/W media . */
-       __u8 dvd                : 1; /* Drive is a DVD-ROM */
-       __u8 dvd_r              : 1; /* Drive can write DVD-R */
-       __u8 dvd_ram            : 1; /* Drive can write DVD-RAM */
-       __u8 ram                : 1; /* generic WRITE (dvd-ram/mrw) */
-       __u8 test_write         : 1; /* Drive can fake writes */
-       __u8 supp_disc_present  : 1; /* Changer can report exact contents
-                                       of slots. */
-       __u8 limit_nframes      : 1; /* Drive does not provide data in
-                                       multiples of SECTOR_SIZE when more
-                                       than one interrupt is needed. */
-       __u8 seeking            : 1; /* Seeking in progress */
-       __u8 audio_play         : 1; /* can do audio related commands */
-       __u8 close_tray         : 1; /* can close the tray */
-       __u8 writing            : 1; /* pseudo write in progress */
-       __u8 mo_drive           : 1; /* drive is an MO device */
-       __u8 no_speed_select    : 1; /* SET_CD_SPEED command is unsupported. */
-       __u8 reserved           : 1;
-       byte max_speed;              /* Max speed of the drive */
-};
-#define CDROM_CONFIG_FLAGS(drive) (&(((struct cdrom_info *)(drive->driver_data))->config_flags))
 
-/* State flags.  These give information about the current state of the
-   drive, and will change during normal operation. */
-struct ide_cd_state_flags {
-       __u8 media_changed : 1; /* Driver has noticed a media change. */
-       __u8 toc_valid     : 1; /* Saved TOC information is current. */
-       __u8 door_locked   : 1; /* We think that the drive door is locked. */
-       __u8 writing       : 1; /* the drive is currently writing */
-       __u8 reserved      : 4;
-       byte current_speed;     /* Current speed of the drive */
+/* Capabilities Page size including 8 bytes of Mode Page Header */
+#define ATAPI_CAPABILITIES_PAGE_SIZE           (8 + 20)
+#define ATAPI_CAPABILITIES_PAGE_PAD_SIZE       4
+
+enum {
+       /* Device sends an interrupt when ready for a packet command. */
+       IDE_CD_FLAG_DRQ_INTERRUPT       = (1 << 0),
+       /* Drive cannot lock the door. */
+       IDE_CD_FLAG_NO_DOORLOCK         = (1 << 1),
+       /* Drive cannot eject the disc. */
+       IDE_CD_FLAG_NO_EJECT            = (1 << 2),
+       /* Drive is a pre ATAPI 1.2 drive. */
+       IDE_CD_FLAG_PRE_ATAPI12         = (1 << 3),
+       /* TOC addresses are in BCD. */
+       IDE_CD_FLAG_TOCADDR_AS_BCD      = (1 << 4),
+       /* TOC track numbers are in BCD. */
+       IDE_CD_FLAG_TOCTRACKS_AS_BCD    = (1 << 5),
+       /*
+        * Drive does not provide data in multiples of SECTOR_SIZE
+        * when more than one interrupt is needed.
+        */
+       IDE_CD_FLAG_LIMIT_NFRAMES       = (1 << 6),
+       /* Seeking in progress. */
+       IDE_CD_FLAG_SEEKING             = (1 << 7),
+       /* Driver has noticed a media change. */
+       IDE_CD_FLAG_MEDIA_CHANGED       = (1 << 8),
+       /* Saved TOC information is current. */
+       IDE_CD_FLAG_TOC_VALID           = (1 << 9),
+       /* We think that the drive door is locked. */
+       IDE_CD_FLAG_DOOR_LOCKED         = (1 << 10),
+       /* SET_CD_SPEED command is unsupported. */
+       IDE_CD_FLAG_NO_SPEED_SELECT     = (1 << 11),
+       IDE_CD_FLAG_VERTOS_300_SSD      = (1 << 12),
+       IDE_CD_FLAG_VERTOS_600_ESD      = (1 << 13),
+       IDE_CD_FLAG_SANYO_3CD           = (1 << 14),
+       IDE_CD_FLAG_FULL_CAPS_PAGE      = (1 << 15),
+       IDE_CD_FLAG_PLAY_AUDIO_OK       = (1 << 16),
+       IDE_CD_FLAG_LE_SPEED_FIELDS     = (1 << 17),
 };
 
-#define CDROM_STATE_FLAGS(drive) (&(((struct cdrom_info *)(drive->driver_data))->state_flags))
-
 /* Structure of a MSF cdrom address. */
 struct atapi_msf {
        byte reserved;
@@ -155,310 +107,6 @@ struct atapi_toc {
          /* One extra for the leadout. */
 };
 
-
-/* This structure is annoyingly close to, but not identical with,
-   the cdrom_subchnl structure from cdrom.h. */
-struct atapi_cdrom_subchnl {
-       u_char  acdsc_reserved;
-       u_char  acdsc_audiostatus;
-       u_short acdsc_length;
-       u_char  acdsc_format;
-
-#if defined(__BIG_ENDIAN_BITFIELD)
-       u_char  acdsc_ctrl:     4;
-       u_char  acdsc_adr:      4;
-#elif defined(__LITTLE_ENDIAN_BITFIELD)
-       u_char  acdsc_adr:      4;
-       u_char  acdsc_ctrl:     4;
-#else
-#error "Please fix <asm/byteorder.h>"
-#endif
-       u_char  acdsc_trk;
-       u_char  acdsc_ind;
-       union {
-               struct atapi_msf msf;
-               int     lba;
-       } acdsc_absaddr;
-       union {
-               struct atapi_msf msf;
-               int     lba;
-       } acdsc_reladdr;
-};
-
-
-
-/* This should probably go into cdrom.h along with the other
- * generic stuff now in the Mt. Fuji spec.
- */
-struct atapi_capabilities_page {
-       struct mode_page_header header;
-#if defined(__BIG_ENDIAN_BITFIELD)
-       __u8 parameters_saveable : 1;
-       __u8 reserved1           : 1;
-       __u8 page_code           : 6;
-#elif defined(__LITTLE_ENDIAN_BITFIELD)
-       __u8 page_code           : 6;
-       __u8 reserved1           : 1;
-       __u8 parameters_saveable : 1;
-#else
-#error "Please fix <asm/byteorder.h>"
-#endif
-
-       byte     page_length;
-
-#if defined(__BIG_ENDIAN_BITFIELD)
-       __u8 reserved2           : 2;
-       /* Drive supports reading of DVD-RAM discs */
-       __u8 dvd_ram_read        : 1;
-       /* Drive supports reading of DVD-R discs */
-       __u8 dvd_r_read          : 1;
-       /* Drive supports reading of DVD-ROM discs */
-       __u8 dvd_rom             : 1;
-       /* Drive supports reading CD-R discs with addressing method 2 */
-       __u8 method2             : 1; /* reserved in 1.2 */
-       /* Drive can read from CD-R/W (CD-E) discs (orange book, part III) */
-       __u8 cd_rw_read          : 1; /* reserved in 1.2 */
-       /* Drive supports read from CD-R discs (orange book, part II) */
-       __u8 cd_r_read           : 1; /* reserved in 1.2 */
-#elif defined(__LITTLE_ENDIAN_BITFIELD)
-       /* Drive supports read from CD-R discs (orange book, part II) */
-       __u8 cd_r_read           : 1; /* reserved in 1.2 */
-       /* Drive can read from CD-R/W (CD-E) discs (orange book, part III) */
-       __u8 cd_rw_read          : 1; /* reserved in 1.2 */
-       /* Drive supports reading CD-R discs with addressing method 2 */
-       __u8 method2             : 1;
-       /* Drive supports reading of DVD-ROM discs */
-       __u8 dvd_rom             : 1;
-       /* Drive supports reading of DVD-R discs */
-       __u8 dvd_r_read          : 1;
-       /* Drive supports reading of DVD-RAM discs */
-       __u8 dvd_ram_read        : 1;
-       __u8 reserved2           : 2;
-#else
-#error "Please fix <asm/byteorder.h>"
-#endif
-
-#if defined(__BIG_ENDIAN_BITFIELD)
-       __u8 reserved3           : 2;
-       /* Drive can write DVD-RAM discs */
-       __u8 dvd_ram_write       : 1;
-       /* Drive can write DVD-R discs */
-       __u8 dvd_r_write         : 1;
-       __u8 reserved3a          : 1;
-       /* Drive can fake writes */
-       __u8 test_write          : 1;
-       /* Drive can write to CD-R/W (CD-E) discs (orange book, part III) */
-       __u8 cd_rw_write         : 1; /* reserved in 1.2 */
-       /* Drive supports write to CD-R discs (orange book, part II) */
-       __u8 cd_r_write          : 1; /* reserved in 1.2 */
-#elif defined(__LITTLE_ENDIAN_BITFIELD)
-       /* Drive can write to CD-R discs (orange book, part II) */
-       __u8 cd_r_write          : 1; /* reserved in 1.2 */
-       /* Drive can write to CD-R/W (CD-E) discs (orange book, part III) */
-       __u8 cd_rw_write         : 1; /* reserved in 1.2 */
-       /* Drive can fake writes */
-       __u8 test_write          : 1;
-       __u8 reserved3a          : 1;
-       /* Drive can write DVD-R discs */
-       __u8 dvd_r_write         : 1;
-       /* Drive can write DVD-RAM discs */
-       __u8 dvd_ram_write       : 1;
-       __u8 reserved3           : 2;
-#else
-#error "Please fix <asm/byteorder.h>"
-#endif
-
-#if defined(__BIG_ENDIAN_BITFIELD)
-       __u8 reserved4           : 1;
-       /* Drive can read multisession discs. */
-       __u8 multisession        : 1;
-       /* Drive can read mode 2, form 2 data. */
-       __u8 mode2_form2         : 1;
-       /* Drive can read mode 2, form 1 (XA) data. */
-       __u8 mode2_form1         : 1;
-       /* Drive supports digital output on port 2. */
-       __u8 digport2            : 1;
-       /* Drive supports digital output on port 1. */
-       __u8 digport1            : 1;
-       /* Drive can deliver a composite audio/video data stream. */
-       __u8 composite           : 1;
-       /* Drive supports audio play operations. */
-       __u8 audio_play          : 1;
-#elif defined(__LITTLE_ENDIAN_BITFIELD)
-       /* Drive supports audio play operations. */
-       __u8 audio_play          : 1;
-       /* Drive can deliver a composite audio/video data stream. */
-       __u8 composite           : 1;
-       /* Drive supports digital output on port 1. */
-       __u8 digport1            : 1;
-       /* Drive supports digital output on port 2. */
-       __u8 digport2            : 1;
-       /* Drive can read mode 2, form 1 (XA) data. */
-       __u8 mode2_form1         : 1;
-       /* Drive can read mode 2, form 2 data. */
-       __u8 mode2_form2         : 1;
-       /* Drive can read multisession discs. */
-       __u8 multisession        : 1;
-       __u8 reserved4           : 1;
-#else
-#error "Please fix <asm/byteorder.h>"
-#endif
-
-#if defined(__BIG_ENDIAN_BITFIELD)
-       __u8 reserved5           : 1;
-       /* Drive can return Media Catalog Number (UPC) info. */
-       __u8 upc                 : 1;
-       /* Drive can return International Standard Recording Code info. */
-       __u8 isrc                : 1;
-       /* Drive supports C2 error pointers. */
-       __u8 c2_pointers         : 1;
-       /* R-W data will be returned deinterleaved and error corrected. */
-       __u8 rw_corr             : 1;
-       /* Subchannel reads can return combined R-W information. */
-       __u8 rw_supported        : 1;
-       /* Drive can continue a read cdda operation from a loss of streaming.*/
-       __u8 cdda_accurate       : 1;
-       /* Drive can read Red Book audio data. */
-       __u8 cdda                : 1;
-#elif defined(__LITTLE_ENDIAN_BITFIELD)
-       /* Drive can read Red Book audio data. */
-       __u8 cdda                : 1;
-       /* Drive can continue a read cdda operation from a loss of streaming.*/
-       __u8 cdda_accurate       : 1;
-       /* Subchannel reads can return combined R-W information. */
-       __u8 rw_supported        : 1;
-       /* R-W data will be returned deinterleaved and error corrected. */
-       __u8 rw_corr             : 1;
-       /* Drive supports C2 error pointers. */
-       __u8 c2_pointers         : 1;
-       /* Drive can return International Standard Recording Code info. */
-       __u8 isrc                : 1;
-       /* Drive can return Media Catalog Number (UPC) info. */
-       __u8 upc                 : 1;
-       __u8 reserved5           : 1;
-#else
-#error "Please fix <asm/byteorder.h>"
-#endif
-
-#if defined(__BIG_ENDIAN_BITFIELD)
-       /* Drive mechanism types. */
-       mechtype_t mechtype      : 3;
-       __u8 reserved6           : 1;
-       /* Drive can eject a disc or changer cartridge. */
-       __u8 eject               : 1;
-       /* State of prevent/allow jumper. */
-       __u8 prevent_jumper      : 1;
-       /* Present state of door lock. */
-       __u8 lock_state          : 1;
-       /* Drive can lock the door. */
-       __u8 lock                : 1;
-#elif defined(__LITTLE_ENDIAN_BITFIELD)
-
-       /* Drive can lock the door. */
-       __u8 lock                : 1;
-       /* Present state of door lock. */
-       __u8 lock_state          : 1;
-       /* State of prevent/allow jumper. */
-       __u8 prevent_jumper      : 1;
-       /* Drive can eject a disc or changer cartridge. */
-       __u8 eject               : 1;
-       __u8 reserved6           : 1;
-       /* Drive mechanism types. */
-       mechtype_t mechtype      : 3;
-#else
-#error "Please fix <asm/byteorder.h>"
-#endif
-
-#if defined(__BIG_ENDIAN_BITFIELD)
-       __u8 reserved7           : 4;
-       /* Drive supports software slot selection. */
-       __u8 sss                 : 1;  /* reserved in 1.2 */
-       /* Changer can report exact contents of slots. */
-       __u8 disc_present        : 1;  /* reserved in 1.2 */
-       /* Audio for each channel can be muted independently. */
-       __u8 separate_mute       : 1;
-       /* Audio level for each channel can be controlled independently. */
-       __u8 separate_volume     : 1;
-#elif defined(__LITTLE_ENDIAN_BITFIELD)
-
-       /* Audio level for each channel can be controlled independently. */
-       __u8 separate_volume     : 1;
-       /* Audio for each channel can be muted independently. */
-       __u8 separate_mute       : 1;
-       /* Changer can report exact contents of slots. */
-       __u8 disc_present        : 1;  /* reserved in 1.2 */
-       /* Drive supports software slot selection. */
-       __u8 sss                 : 1;  /* reserved in 1.2 */
-       __u8 reserved7           : 4;
-#else
-#error "Please fix <asm/byteorder.h>"
-#endif
-
-       /* Note: the following four fields are returned in big-endian form. */
-       /* Maximum speed (in kB/s). */
-       unsigned short maxspeed;
-       /* Number of discrete volume levels. */
-       unsigned short n_vol_levels;
-       /* Size of cache in drive, in kB. */
-       unsigned short buffer_size;
-       /* Current speed (in kB/s). */
-       unsigned short curspeed;
-       char pad[4];
-};
-
-
-struct atapi_mechstat_header {
-#if defined(__BIG_ENDIAN_BITFIELD)
-       __u8 fault         : 1;
-       __u8 changer_state : 2;
-       __u8 curslot       : 5;
-#elif defined(__LITTLE_ENDIAN_BITFIELD)
-       __u8 curslot       : 5;
-       __u8 changer_state : 2;
-       __u8 fault         : 1;
-#else
-#error "Please fix <asm/byteorder.h>"
-#endif
-
-#if defined(__BIG_ENDIAN_BITFIELD)
-       __u8 mech_state    : 3;
-       __u8 door_open     : 1;
-       __u8 reserved1     : 4;
-#elif defined(__LITTLE_ENDIAN_BITFIELD)
-       __u8 reserved1     : 4;
-       __u8 door_open     : 1;
-       __u8 mech_state    : 3;
-#else
-#error "Please fix <asm/byteorder.h>"
-#endif
-
-       byte     curlba[3];
-       byte     nslots;
-       __u16    slot_tablelen;
-};
-
-
-struct atapi_slot {
-#if defined(__BIG_ENDIAN_BITFIELD)
-       __u8 disc_present : 1;
-       __u8 reserved1    : 6;
-       __u8 change       : 1;
-#elif defined(__LITTLE_ENDIAN_BITFIELD)
-       __u8 change       : 1;
-       __u8 reserved1    : 6;
-       __u8 disc_present : 1;
-#else
-#error "Please fix <asm/byteorder.h>"
-#endif
-
-       byte reserved2[3];
-};
-
-struct atapi_changer_info {
-       struct atapi_mechstat_header hdr;
-       struct atapi_slot slots[0];
-};
-
 /* Extra per-device info for cdrom drives. */
 struct cdrom_info {
        ide_drive_t     *drive;
@@ -483,11 +131,11 @@ struct cdrom_info {
        int dma;
        unsigned long last_block;
        unsigned long start_seek;
-       /* Buffer to hold mechanism status and changer slot table. */
-       struct atapi_changer_info *changer_info;
 
-       struct ide_cd_config_flags      config_flags;
-       struct ide_cd_state_flags       state_flags;
+       unsigned int cd_flags;
+
+       u8 max_speed;           /* Max speed of the drive. */
+       u8 current_speed;       /* Current speed of the drive. */
 
         /* Per-device info needed by cdrom.c generic driver. */
         struct cdrom_device_info devinfo;
@@ -495,250 +143,30 @@ struct cdrom_info {
        unsigned long write_timeout;
 };
 
-/****************************************************************************
- * Descriptions of ATAPI error codes.
- */
-
-/* This stuff should be in cdrom.h, since it is now generic... */
-
-/* ATAPI sense keys (from table 140 of ATAPI 2.6) */
-#define NO_SENSE                0x00
-#define RECOVERED_ERROR         0x01
-#define NOT_READY               0x02
-#define MEDIUM_ERROR            0x03
-#define HARDWARE_ERROR          0x04
-#define ILLEGAL_REQUEST         0x05
-#define UNIT_ATTENTION          0x06
-#define DATA_PROTECT            0x07
-#define BLANK_CHECK             0x08
-#define ABORTED_COMMAND         0x0b
-#define MISCOMPARE              0x0e
-
-
-/* This stuff should be in cdrom.h, since it is now generic... */
-#if VERBOSE_IDE_CD_ERRORS
-
- /* The generic packet command opcodes for CD/DVD Logical Units,
- * From Table 57 of the SFF8090 Ver. 3 (Mt. Fuji) draft standard. */ 
-static const struct {
-       unsigned short packet_command;
-       const char * const text;
-} packet_command_texts[] = {
-       { GPCMD_TEST_UNIT_READY, "Test Unit Ready" },
-       { GPCMD_REQUEST_SENSE, "Request Sense" },
-       { GPCMD_FORMAT_UNIT, "Format Unit" },
-       { GPCMD_INQUIRY, "Inquiry" },
-       { GPCMD_START_STOP_UNIT, "Start/Stop Unit" },
-       { GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL, "Prevent/Allow Medium Removal" },
-       { GPCMD_READ_FORMAT_CAPACITIES, "Read Format Capacities" },
-       { GPCMD_READ_CDVD_CAPACITY, "Read Cd/Dvd Capacity" },
-       { GPCMD_READ_10, "Read 10" },
-       { GPCMD_WRITE_10, "Write 10" },
-       { GPCMD_SEEK, "Seek" },
-       { GPCMD_WRITE_AND_VERIFY_10, "Write and Verify 10" },
-       { GPCMD_VERIFY_10, "Verify 10" },
-       { GPCMD_FLUSH_CACHE, "Flush Cache" },
-       { GPCMD_READ_SUBCHANNEL, "Read Subchannel" },
-       { GPCMD_READ_TOC_PMA_ATIP, "Read Table of Contents" },
-       { GPCMD_READ_HEADER, "Read Header" },
-       { GPCMD_PLAY_AUDIO_10, "Play Audio 10" },
-       { GPCMD_GET_CONFIGURATION, "Get Configuration" },
-       { GPCMD_PLAY_AUDIO_MSF, "Play Audio MSF" },
-       { GPCMD_PLAYAUDIO_TI, "Play Audio TrackIndex" },
-       { GPCMD_GET_EVENT_STATUS_NOTIFICATION, "Get Event Status Notification" },
-       { GPCMD_PAUSE_RESUME, "Pause/Resume" },
-       { GPCMD_STOP_PLAY_SCAN, "Stop Play/Scan" },
-       { GPCMD_READ_DISC_INFO, "Read Disc Info" },
-       { GPCMD_READ_TRACK_RZONE_INFO, "Read Track Rzone Info" },
-       { GPCMD_RESERVE_RZONE_TRACK, "Reserve Rzone Track" },
-       { GPCMD_SEND_OPC, "Send OPC" },
-       { GPCMD_MODE_SELECT_10, "Mode Select 10" },
-       { GPCMD_REPAIR_RZONE_TRACK, "Repair Rzone Track" },
-       { GPCMD_MODE_SENSE_10, "Mode Sense 10" },
-       { GPCMD_CLOSE_TRACK, "Close Track" },
-       { GPCMD_BLANK, "Blank" },
-       { GPCMD_SEND_EVENT, "Send Event" },
-       { GPCMD_SEND_KEY, "Send Key" },
-       { GPCMD_REPORT_KEY, "Report Key" },
-       { GPCMD_LOAD_UNLOAD, "Load/Unload" },
-       { GPCMD_SET_READ_AHEAD, "Set Read-ahead" },
-       { GPCMD_READ_12, "Read 12" },
-       { GPCMD_GET_PERFORMANCE, "Get Performance" },
-       { GPCMD_SEND_DVD_STRUCTURE, "Send DVD Structure" },
-       { GPCMD_READ_DVD_STRUCTURE, "Read DVD Structure" },
-       { GPCMD_SET_STREAMING, "Set Streaming" },
-       { GPCMD_READ_CD_MSF, "Read CD MSF" },
-       { GPCMD_SCAN, "Scan" },
-       { GPCMD_SET_SPEED, "Set Speed" },
-       { GPCMD_PLAY_CD, "Play CD" },
-       { GPCMD_MECHANISM_STATUS, "Mechanism Status" },
-       { GPCMD_READ_CD, "Read CD" },
-};
-
-
-
-/* From Table 303 of the SFF8090 Ver. 3 (Mt. Fuji) draft standard. */
-static const char * const sense_key_texts[16] = {
-       "No sense data",
-       "Recovered error",
-       "Not ready",
-       "Medium error",
-       "Hardware error",
-       "Illegal request",
-       "Unit attention",
-       "Data protect",
-       "Blank check",
-       "(reserved)",
-       "(reserved)",
-       "Aborted command",
-       "(reserved)",
-       "(reserved)",
-       "Miscompare",
-       "(reserved)",
-};
-
-/* From Table 304 of the SFF8090 Ver. 3 (Mt. Fuji) draft standard. */
-static const struct {
-       unsigned long asc_ascq;
-       const char * const text;
-} sense_data_texts[] = {
-       { 0x000000, "No additional sense information" },
-       { 0x000011, "Play operation in progress" },
-       { 0x000012, "Play operation paused" },
-       { 0x000013, "Play operation successfully completed" },
-       { 0x000014, "Play operation stopped due to error" },
-       { 0x000015, "No current audio status to return" },
-       { 0x010c0a, "Write error - padding blocks added" },
-       { 0x011700, "Recovered data with no error correction applied" },
-       { 0x011701, "Recovered data with retries" },
-       { 0x011702, "Recovered data with positive head offset" },
-       { 0x011703, "Recovered data with negative head offset" },
-       { 0x011704, "Recovered data with retries and/or CIRC applied" },
-       { 0x011705, "Recovered data using previous sector ID" },
-       { 0x011800, "Recovered data with error correction applied" },
-       { 0x011801, "Recovered data with error correction and retries applied"},
-       { 0x011802, "Recovered data - the data was auto-reallocated" },
-       { 0x011803, "Recovered data with CIRC" },
-       { 0x011804, "Recovered data with L-EC" },
-       { 0x015d00, 
-           "Failure prediction threshold exceeded - Predicted logical unit failure" },
-       { 0x015d01, 
-           "Failure prediction threshold exceeded - Predicted media failure" },
-       { 0x015dff, "Failure prediction threshold exceeded - False" },
-       { 0x017301, "Power calibration area almost full" },
-       { 0x020400, "Logical unit not ready - cause not reportable" },
-       /* Following is misspelled in ATAPI 2.6, _and_ in Mt. Fuji */
-       { 0x020401,
-         "Logical unit not ready - in progress [sic] of becoming ready" },
-       { 0x020402, "Logical unit not ready - initializing command required" },
-       { 0x020403, "Logical unit not ready - manual intervention required" },
-       { 0x020404, "Logical unit not ready - format in progress" },
-       { 0x020407, "Logical unit not ready - operation in progress" },
-       { 0x020408, "Logical unit not ready - long write in progress" },
-       { 0x020600, "No reference position found (media may be upside down)" },
-       { 0x023000, "Incompatible medium installed" },
-       { 0x023a00, "Medium not present" },
-       { 0x025300, "Media load or eject failed" },
-       { 0x025700, "Unable to recover table of contents" },
-       { 0x030300, "Peripheral device write fault" },
-       { 0x030301, "No write current" },
-       { 0x030302, "Excessive write errors" },
-       { 0x030c00, "Write error" },
-       { 0x030c01, "Write error - Recovered with auto reallocation" },
-       { 0x030c02, "Write error - auto reallocation failed" },
-       { 0x030c03, "Write error - recommend reassignment" },
-       { 0x030c04, "Compression check miscompare error" },
-       { 0x030c05, "Data expansion occurred during compress" },
-       { 0x030c06, "Block not compressible" },
-       { 0x030c07, "Write error - recovery needed" },
-       { 0x030c08, "Write error - recovery failed" },
-       { 0x030c09, "Write error - loss of streaming" },
-       { 0x031100, "Unrecovered read error" },
-       { 0x031106, "CIRC unrecovered error" },
-       { 0x033101, "Format command failed" },
-       { 0x033200, "No defect spare location available" },
-       { 0x033201, "Defect list update failure" },
-       { 0x035100, "Erase failure" },
-       { 0x037200, "Session fixation error" },
-       { 0x037201, "Session fixation error writin lead-in" },
-       { 0x037202, "Session fixation error writin lead-out" },
-       { 0x037300, "CD control error" },
-       { 0x037302, "Power calibration area is full" },
-       { 0x037303, "Power calibration area error" },
-       { 0x037304, "Program memory area / RMA update failure" },
-       { 0x037305, "Program memory area / RMA is full" },
-       { 0x037306, "Program memory area / RMA is (almost) full" },
-
-       { 0x040200, "No seek complete" },
-       { 0x040300, "Write fault" },
-       { 0x040900, "Track following error" },
-       { 0x040901, "Tracking servo failure" },
-       { 0x040902, "Focus servo failure" },
-       { 0x040903, "Spindle servo failure" },
-       { 0x041500, "Random positioning error" },
-       { 0x041501, "Mechanical positioning or changer error" },
-       { 0x041502, "Positioning error detected by read of medium" },
-       { 0x043c00, "Mechanical positioning or changer error" },
-       { 0x044000, "Diagnostic failure on component (ASCQ)" },
-       { 0x044400, "Internal CD/DVD logical unit failure" },
-       { 0x04b600, "Media load mechanism failed" },
-       { 0x051a00, "Parameter list length error" },
-       { 0x052000, "Invalid command operation code" },
-       { 0x052100, "Logical block address out of range" },
-       { 0x052102, "Invalid address for write" },
-       { 0x052400, "Invalid field in command packet" },
-       { 0x052600, "Invalid field in parameter list" },
-       { 0x052601, "Parameter not supported" },
-       { 0x052602, "Parameter value invalid" },
-       { 0x052700, "Write protected media" },
-       { 0x052c00, "Command sequence error" },
-       { 0x052c03, "Current program area is not empty" },
-       { 0x052c04, "Current program area is empty" },
-       { 0x053001, "Cannot read medium - unknown format" },
-       { 0x053002, "Cannot read medium - incompatible format" },
-       { 0x053900, "Saving parameters not supported" },
-       { 0x054e00, "Overlapped commands attempted" },
-       { 0x055302, "Medium removal prevented" },
-       { 0x055500, "System resource failure" },
-       { 0x056300, "End of user area encountered on this track" },
-       { 0x056400, "Illegal mode for this track or incompatible medium" },
-       { 0x056f00, "Copy protection key exchange failure - Authentication failure" },
-       { 0x056f01, "Copy protection key exchange failure - Key not present" },
-       { 0x056f02, "Copy protection key exchange failure - Key not established" },
-       { 0x056f03, "Read of scrambled sector without authentication" },
-       { 0x056f04, "Media region code is mismatched to logical unit" },
-       { 0x056f05,  "Drive region must be permanent / region reset count error" },
-       { 0x057203, "Session fixation error - incomplete track in session" },
-       { 0x057204, "Empty or partially written reserved track" },
-       { 0x057205, "No more RZONE reservations are allowed" },
-       { 0x05bf00, "Loss of streaming" },
-       { 0x062800, "Not ready to ready transition, medium may have changed" },
-       { 0x062900, "Power on, reset or hardware reset occurred" },
-       { 0x062a00, "Parameters changed" },
-       { 0x062a01, "Mode parameters changed" },
-       { 0x062e00, "Insufficient time for operation" },
-       { 0x063f00, "Logical unit operating conditions have changed" },
-       { 0x063f01, "Microcode has been changed" },
-       { 0x065a00, "Operator request or state change input (unspecified)" },
-       { 0x065a01, "Operator medium removal request" },
-       { 0x0bb900, "Play operation aborted" },
-
-       /* Here we use 0xff for the key (not a valid key) to signify
-        * that these can have _any_ key value associated with them... */
-       { 0xff0401, "Logical unit is in process of becoming ready" },
-       { 0xff0400, "Logical unit not ready, cause not reportable" },
-       { 0xff0402, "Logical unit not ready, initializing command required" },
-       { 0xff0403, "Logical unit not ready, manual intervention required" },
-       { 0xff0500, "Logical unit does not respond to selection" },
-       { 0xff0800, "Logical unit communication failure" },
-       { 0xff0802, "Logical unit communication parity error" },
-       { 0xff0801, "Logical unit communication time-out" },
-       { 0xff2500, "Logical unit not supported" },
-       { 0xff4c00, "Logical unit failed self-configuration" },
-       { 0xff3e00, "Logical unit has not self-configured yet" },
-};
-#endif
-
+/* ide-cd_verbose.c */
+void ide_cd_log_error(const char *, struct request *, struct request_sense *);
+
+/* ide-cd.c functions used by ide-cd_ioctl.c */
+void ide_cd_init_rq(ide_drive_t *, struct request *);
+int ide_cd_queue_pc(ide_drive_t *, struct request *);
+int ide_cd_read_toc(ide_drive_t *, struct request_sense *);
+int ide_cdrom_get_capabilities(ide_drive_t *, u8 *);
+void ide_cdrom_update_speed(ide_drive_t *, u8 *);
+int cdrom_check_status(ide_drive_t *, struct request_sense *);
+
+/* ide-cd_ioctl.c */
+int ide_cdrom_open_real(struct cdrom_device_info *, int);
+void ide_cdrom_release_real(struct cdrom_device_info *);
+int ide_cdrom_drive_status(struct cdrom_device_info *, int);
+int ide_cdrom_check_media_change_real(struct cdrom_device_info *, int);
+int ide_cdrom_tray_move(struct cdrom_device_info *, int);
+int ide_cdrom_lock_door(struct cdrom_device_info *, int);
+int ide_cdrom_select_speed(struct cdrom_device_info *, int);
+int ide_cdrom_get_last_session(struct cdrom_device_info *,
+                              struct cdrom_multisession *);
+int ide_cdrom_get_mcn(struct cdrom_device_info *, struct cdrom_mcn *);
+int ide_cdrom_reset(struct cdrom_device_info *cdi);
+int ide_cdrom_audio_ioctl(struct cdrom_device_info *, unsigned int, void *);
+int ide_cdrom_packet(struct cdrom_device_info *, struct packet_command *);
 
 #endif /* _IDE_CD_H */
diff --git a/drivers/ide/ide-cd_ioctl.c b/drivers/ide/ide-cd_ioctl.c
new file mode 100644 (file)
index 0000000..b68284d
--- /dev/null
@@ -0,0 +1,475 @@
+/*
+ * cdrom.c IOCTLs handling for ide-cd driver.
+ *
+ * Copyright (C) 1994-1996  Scott Snyder <snyder@fnald0.fnal.gov>
+ * Copyright (C) 1996-1998  Erik Andersen <andersee@debian.org>
+ * Copyright (C) 1998-2000  Jens Axboe <axboe@suse.de>
+ */
+
+#include <linux/kernel.h>
+#include <linux/cdrom.h>
+#include <linux/ide.h>
+#include <scsi/scsi.h>
+
+#include "ide-cd.h"
+
+/****************************************************************************
+ * Other driver requests (open, close, check media change).
+ */
+int ide_cdrom_open_real(struct cdrom_device_info *cdi, int purpose)
+{
+       return 0;
+}
+
+/*
+ * Close down the device.  Invalidate all cached blocks.
+ */
+void ide_cdrom_release_real(struct cdrom_device_info *cdi)
+{
+       ide_drive_t *drive = cdi->handle;
+       struct cdrom_info *cd = drive->driver_data;
+
+       if (!cdi->use_count)
+               cd->cd_flags &= ~IDE_CD_FLAG_TOC_VALID;
+}
+
+/*
+ * add logic to try GET_EVENT command first to check for media and tray
+ * status. this should be supported by newer cd-r/w and all DVD etc
+ * drives
+ */
+int ide_cdrom_drive_status(struct cdrom_device_info *cdi, int slot_nr)
+{
+       ide_drive_t *drive = cdi->handle;
+       struct media_event_desc med;
+       struct request_sense sense;
+       int stat;
+
+       if (slot_nr != CDSL_CURRENT)
+               return -EINVAL;
+
+       stat = cdrom_check_status(drive, &sense);
+       if (!stat || sense.sense_key == UNIT_ATTENTION)
+               return CDS_DISC_OK;
+
+       if (!cdrom_get_media_event(cdi, &med)) {
+               if (med.media_present)
+                       return CDS_DISC_OK;
+               else if (med.door_open)
+                       return CDS_TRAY_OPEN;
+               else
+                       return CDS_NO_DISC;
+       }
+
+       if (sense.sense_key == NOT_READY && sense.asc == 0x04
+                       && sense.ascq == 0x04)
+               return CDS_DISC_OK;
+
+       /*
+        * If not using Mt Fuji extended media tray reports,
+        * just return TRAY_OPEN since ATAPI doesn't provide
+        * any other way to detect this...
+        */
+       if (sense.sense_key == NOT_READY) {
+               if (sense.asc == 0x3a && sense.ascq == 1)
+                       return CDS_NO_DISC;
+               else
+                       return CDS_TRAY_OPEN;
+       }
+       return CDS_DRIVE_NOT_READY;
+}
+
+int ide_cdrom_check_media_change_real(struct cdrom_device_info *cdi,
+                                      int slot_nr)
+{
+       ide_drive_t *drive = cdi->handle;
+       struct cdrom_info *cd = drive->driver_data;
+       int retval;
+
+       if (slot_nr == CDSL_CURRENT) {
+               (void) cdrom_check_status(drive, NULL);
+               retval = (cd->cd_flags & IDE_CD_FLAG_MEDIA_CHANGED) ? 1 : 0;
+               cd->cd_flags &= ~IDE_CD_FLAG_MEDIA_CHANGED;
+               return retval;
+       } else {
+               return -EINVAL;
+       }
+}
+
+/* Eject the disk if EJECTFLAG is 0.
+   If EJECTFLAG is 1, try to reload the disk. */
+static
+int cdrom_eject(ide_drive_t *drive, int ejectflag,
+               struct request_sense *sense)
+{
+       struct cdrom_info *cd = drive->driver_data;
+       struct cdrom_device_info *cdi = &cd->devinfo;
+       struct request req;
+       char loej = 0x02;
+
+       if ((cd->cd_flags & IDE_CD_FLAG_NO_EJECT) && !ejectflag)
+               return -EDRIVE_CANT_DO_THIS;
+
+       /* reload fails on some drives, if the tray is locked */
+       if ((cd->cd_flags & IDE_CD_FLAG_DOOR_LOCKED) && ejectflag)
+               return 0;
+
+       ide_cd_init_rq(drive, &req);
+
+       /* only tell drive to close tray if open, if it can do that */
+       if (ejectflag && (cdi->mask & CDC_CLOSE_TRAY))
+               loej = 0;
+
+       req.sense = sense;
+       req.cmd[0] = GPCMD_START_STOP_UNIT;
+       req.cmd[4] = loej | (ejectflag != 0);
+
+       return ide_cd_queue_pc(drive, &req);
+}
+
+/* Lock the door if LOCKFLAG is nonzero; unlock it otherwise. */
+static
+int ide_cd_lockdoor(ide_drive_t *drive, int lockflag,
+                   struct request_sense *sense)
+{
+       struct cdrom_info *cd = drive->driver_data;
+       struct request_sense my_sense;
+       struct request req;
+       int stat;
+
+       if (sense == NULL)
+               sense = &my_sense;
+
+       /* If the drive cannot lock the door, just pretend. */
+       if (cd->cd_flags & IDE_CD_FLAG_NO_DOORLOCK) {
+               stat = 0;
+       } else {
+               ide_cd_init_rq(drive, &req);
+               req.sense = sense;
+               req.cmd[0] = GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL;
+               req.cmd[4] = lockflag ? 1 : 0;
+               stat = ide_cd_queue_pc(drive, &req);
+       }
+
+       /* If we got an illegal field error, the drive
+          probably cannot lock the door. */
+       if (stat != 0 &&
+           sense->sense_key == ILLEGAL_REQUEST &&
+           (sense->asc == 0x24 || sense->asc == 0x20)) {
+               printk(KERN_ERR "%s: door locking not supported\n",
+                       drive->name);
+               cd->cd_flags |= IDE_CD_FLAG_NO_DOORLOCK;
+               stat = 0;
+       }
+
+       /* no medium, that's alright. */
+       if (stat != 0 && sense->sense_key == NOT_READY && sense->asc == 0x3a)
+               stat = 0;
+
+       if (stat == 0) {
+               if (lockflag)
+                       cd->cd_flags |= IDE_CD_FLAG_DOOR_LOCKED;
+               else
+                       cd->cd_flags &= ~IDE_CD_FLAG_DOOR_LOCKED;
+       }
+
+       return stat;
+}
+
+int ide_cdrom_tray_move(struct cdrom_device_info *cdi, int position)
+{
+       ide_drive_t *drive = cdi->handle;
+       struct request_sense sense;
+
+       if (position) {
+               int stat = ide_cd_lockdoor(drive, 0, &sense);
+
+               if (stat)
+                       return stat;
+       }
+
+       return cdrom_eject(drive, !position, &sense);
+}
+
+int ide_cdrom_lock_door(struct cdrom_device_info *cdi, int lock)
+{
+       ide_drive_t *drive = cdi->handle;
+
+       return ide_cd_lockdoor(drive, lock, NULL);
+}
+
+/*
+ * ATAPI devices are free to select the speed you request or any slower
+ * rate. :-(  Requesting too fast a speed will _not_ produce an error.
+ */
+int ide_cdrom_select_speed(struct cdrom_device_info *cdi, int speed)
+{
+       ide_drive_t *drive = cdi->handle;
+       struct cdrom_info *cd = drive->driver_data;
+       struct request rq;
+       struct request_sense sense;
+       u8 buf[ATAPI_CAPABILITIES_PAGE_SIZE];
+       int stat;
+
+       ide_cd_init_rq(drive, &rq);
+
+       rq.sense = &sense;
+
+       if (speed == 0)
+               speed = 0xffff; /* set to max */
+       else
+               speed *= 177;   /* Nx to kbytes/s */
+
+       rq.cmd[0] = GPCMD_SET_SPEED;
+       /* Read Drive speed in kbytes/second MSB/LSB */
+       rq.cmd[2] = (speed >> 8) & 0xff;
+       rq.cmd[3] = speed & 0xff;
+       if ((cdi->mask & (CDC_CD_R | CDC_CD_RW | CDC_DVD_R)) !=
+           (CDC_CD_R | CDC_CD_RW | CDC_DVD_R)) {
+               /* Write Drive speed in kbytes/second MSB/LSB */
+               rq.cmd[4] = (speed >> 8) & 0xff;
+               rq.cmd[5] = speed & 0xff;
+       }
+
+       stat = ide_cd_queue_pc(drive, &rq);
+
+       if (!ide_cdrom_get_capabilities(drive, buf)) {
+               ide_cdrom_update_speed(drive, buf);
+               cdi->speed = cd->current_speed;
+       }
+
+       return 0;
+}
+
+int ide_cdrom_get_last_session(struct cdrom_device_info *cdi,
+                              struct cdrom_multisession *ms_info)
+{
+       struct atapi_toc *toc;
+       ide_drive_t *drive = cdi->handle;
+       struct cdrom_info *info = drive->driver_data;
+       struct request_sense sense;
+       int ret;
+
+       if ((info->cd_flags & IDE_CD_FLAG_TOC_VALID) == 0 || !info->toc) {
+               ret = ide_cd_read_toc(drive, &sense);
+               if (ret)
+                       return ret;
+       }
+
+       toc = info->toc;
+       ms_info->addr.lba = toc->last_session_lba;
+       ms_info->xa_flag = toc->xa_flag;
+
+       return 0;
+}
+
+int ide_cdrom_get_mcn(struct cdrom_device_info *cdi,
+                     struct cdrom_mcn *mcn_info)
+{
+       ide_drive_t *drive = cdi->handle;
+       int stat, mcnlen;
+       struct request rq;
+       char buf[24];
+
+       ide_cd_init_rq(drive, &rq);
+
+       rq.data = buf;
+       rq.data_len = sizeof(buf);
+
+       rq.cmd[0] = GPCMD_READ_SUBCHANNEL;
+       rq.cmd[1] = 2;          /* MSF addressing */
+       rq.cmd[2] = 0x40;       /* request subQ data */
+       rq.cmd[3] = 2;          /* format */
+       rq.cmd[8] = sizeof(buf);
+
+       stat = ide_cd_queue_pc(drive, &rq);
+       if (stat)
+               return stat;
+
+       mcnlen = sizeof(mcn_info->medium_catalog_number) - 1;
+       memcpy(mcn_info->medium_catalog_number, buf + 9, mcnlen);
+       mcn_info->medium_catalog_number[mcnlen] = '\0';
+
+       return 0;
+}
+
+int ide_cdrom_reset(struct cdrom_device_info *cdi)
+{
+       ide_drive_t *drive = cdi->handle;
+       struct cdrom_info *cd = drive->driver_data;
+       struct request_sense sense;
+       struct request req;
+       int ret;
+
+       ide_cd_init_rq(drive, &req);
+       req.cmd_type = REQ_TYPE_SPECIAL;
+       req.cmd_flags = REQ_QUIET;
+       ret = ide_do_drive_cmd(drive, &req, ide_wait);
+
+       /*
+        * A reset will unlock the door. If it was previously locked,
+        * lock it again.
+        */
+       if (cd->cd_flags & IDE_CD_FLAG_DOOR_LOCKED)
+               (void)ide_cd_lockdoor(drive, 1, &sense);
+
+       return ret;
+}
+
+static int ide_cd_get_toc_entry(ide_drive_t *drive, int track,
+                               struct atapi_toc_entry **ent)
+{
+       struct cdrom_info *info = drive->driver_data;
+       struct atapi_toc *toc = info->toc;
+       int ntracks;
+
+       /*
+        * don't serve cached data, if the toc isn't valid
+        */
+       if ((info->cd_flags & IDE_CD_FLAG_TOC_VALID) == 0)
+               return -EINVAL;
+
+       /* Check validity of requested track number. */
+       ntracks = toc->hdr.last_track - toc->hdr.first_track + 1;
+
+       if (toc->hdr.first_track == CDROM_LEADOUT)
+               ntracks = 0;
+
+       if (track == CDROM_LEADOUT)
+               *ent = &toc->ent[ntracks];
+       else if (track < toc->hdr.first_track || track > toc->hdr.last_track)
+               return -EINVAL;
+       else
+               *ent = &toc->ent[track - toc->hdr.first_track];
+
+       return 0;
+}
+
+static int ide_cd_fake_play_trkind(ide_drive_t *drive, void *arg)
+{
+       struct cdrom_ti *ti = arg;
+       struct atapi_toc_entry *first_toc, *last_toc;
+       unsigned long lba_start, lba_end;
+       int stat;
+       struct request rq;
+       struct request_sense sense;
+
+       stat = ide_cd_get_toc_entry(drive, ti->cdti_trk0, &first_toc);
+       if (stat)
+               return stat;
+
+       stat = ide_cd_get_toc_entry(drive, ti->cdti_trk1, &last_toc);
+       if (stat)
+               return stat;
+
+       if (ti->cdti_trk1 != CDROM_LEADOUT)
+               ++last_toc;
+       lba_start = first_toc->addr.lba;
+       lba_end   = last_toc->addr.lba;
+
+       if (lba_end <= lba_start)
+               return -EINVAL;
+
+       ide_cd_init_rq(drive, &rq);
+
+       rq.sense = &sense;
+       rq.cmd[0] = GPCMD_PLAY_AUDIO_MSF;
+       lba_to_msf(lba_start,   &rq.cmd[3], &rq.cmd[4], &rq.cmd[5]);
+       lba_to_msf(lba_end - 1, &rq.cmd[6], &rq.cmd[7], &rq.cmd[8]);
+
+       return ide_cd_queue_pc(drive, &rq);
+}
+
+static int ide_cd_read_tochdr(ide_drive_t *drive, void *arg)
+{
+       struct cdrom_info *cd = drive->driver_data;
+       struct cdrom_tochdr *tochdr = arg;
+       struct atapi_toc *toc;
+       int stat;
+
+       /* Make sure our saved TOC is valid. */
+       stat = ide_cd_read_toc(drive, NULL);
+       if (stat)
+               return stat;
+
+       toc = cd->toc;
+       tochdr->cdth_trk0 = toc->hdr.first_track;
+       tochdr->cdth_trk1 = toc->hdr.last_track;
+
+       return 0;
+}
+
+static int ide_cd_read_tocentry(ide_drive_t *drive, void *arg)
+{
+       struct cdrom_tocentry *tocentry = arg;
+       struct atapi_toc_entry *toce;
+       int stat;
+
+       stat = ide_cd_get_toc_entry(drive, tocentry->cdte_track, &toce);
+       if (stat)
+               return stat;
+
+       tocentry->cdte_ctrl = toce->control;
+       tocentry->cdte_adr  = toce->adr;
+       if (tocentry->cdte_format == CDROM_MSF) {
+               lba_to_msf(toce->addr.lba,
+                          &tocentry->cdte_addr.msf.minute,
+                          &tocentry->cdte_addr.msf.second,
+                          &tocentry->cdte_addr.msf.frame);
+       } else
+               tocentry->cdte_addr.lba = toce->addr.lba;
+
+       return 0;
+}
+
+int ide_cdrom_audio_ioctl(struct cdrom_device_info *cdi,
+                         unsigned int cmd, void *arg)
+{
+       ide_drive_t *drive = cdi->handle;
+
+       switch (cmd) {
+       /*
+        * emulate PLAY_AUDIO_TI command with PLAY_AUDIO_10, since
+        * atapi doesn't support it
+        */
+       case CDROMPLAYTRKIND:
+               return ide_cd_fake_play_trkind(drive, arg);
+       case CDROMREADTOCHDR:
+               return ide_cd_read_tochdr(drive, arg);
+       case CDROMREADTOCENTRY:
+               return ide_cd_read_tocentry(drive, arg);
+       default:
+               return -EINVAL;
+       }
+}
+
+/* the generic packet interface to cdrom.c */
+int ide_cdrom_packet(struct cdrom_device_info *cdi,
+                           struct packet_command *cgc)
+{
+       struct request req;
+       ide_drive_t *drive = cdi->handle;
+
+       if (cgc->timeout <= 0)
+               cgc->timeout = ATAPI_WAIT_PC;
+
+       /* here we queue the commands from the uniform CD-ROM
+          layer. the packet must be complete, as we do not
+          touch it at all. */
+       ide_cd_init_rq(drive, &req);
+       memcpy(req.cmd, cgc->cmd, CDROM_PACKET_SIZE);
+       if (cgc->sense)
+               memset(cgc->sense, 0, sizeof(struct request_sense));
+       req.data = cgc->buffer;
+       req.data_len = cgc->buflen;
+       req.timeout = cgc->timeout;
+
+       if (cgc->quiet)
+               req.cmd_flags |= REQ_QUIET;
+
+       req.sense = cgc->sense;
+       cgc->stat = ide_cd_queue_pc(drive, &req);
+       if (!cgc->stat)
+               cgc->buflen -= req.data_len;
+       return cgc->stat;
+}
diff --git a/drivers/ide/ide-cd_verbose.c b/drivers/ide/ide-cd_verbose.c
new file mode 100644 (file)
index 0000000..6ed7ca0
--- /dev/null
@@ -0,0 +1,359 @@
+/*
+ * Verbose error logging for ATAPI CD/DVD devices.
+ *
+ * Copyright (C) 1994-1996  Scott Snyder <snyder@fnald0.fnal.gov>
+ * Copyright (C) 1996-1998  Erik Andersen <andersee@debian.org>
+ * Copyright (C) 1998-2000  Jens Axboe <axboe@suse.de>
+ */
+
+#include <linux/kernel.h>
+#include <linux/blkdev.h>
+#include <linux/cdrom.h>
+#include <scsi/scsi.h>
+
+#ifndef CONFIG_BLK_DEV_IDECD_VERBOSE_ERRORS
+void ide_cd_log_error(const char *name, struct request *failed_command,
+                     struct request_sense *sense)
+{
+       /* Suppress printing unit attention and `in progress of becoming ready'
+          errors when we're not being verbose. */
+       if (sense->sense_key == UNIT_ATTENTION ||
+           (sense->sense_key == NOT_READY && (sense->asc == 4 ||
+                                               sense->asc == 0x3a)))
+               return;
+
+       printk(KERN_ERR "%s: error code: 0x%02x  sense_key: 0x%02x  "
+                       "asc: 0x%02x  ascq: 0x%02x\n",
+                       name, sense->error_code, sense->sense_key,
+                       sense->asc, sense->ascq);
+}
+#else
+/* The generic packet command opcodes for CD/DVD Logical Units,
+ * From Table 57 of the SFF8090 Ver. 3 (Mt. Fuji) draft standard. */
+static const struct {
+       unsigned short packet_command;
+       const char * const text;
+} packet_command_texts[] = {
+       { GPCMD_TEST_UNIT_READY, "Test Unit Ready" },
+       { GPCMD_REQUEST_SENSE, "Request Sense" },
+       { GPCMD_FORMAT_UNIT, "Format Unit" },
+       { GPCMD_INQUIRY, "Inquiry" },
+       { GPCMD_START_STOP_UNIT, "Start/Stop Unit" },
+       { GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL, "Prevent/Allow Medium Removal" },
+       { GPCMD_READ_FORMAT_CAPACITIES, "Read Format Capacities" },
+       { GPCMD_READ_CDVD_CAPACITY, "Read Cd/Dvd Capacity" },
+       { GPCMD_READ_10, "Read 10" },
+       { GPCMD_WRITE_10, "Write 10" },
+       { GPCMD_SEEK, "Seek" },
+       { GPCMD_WRITE_AND_VERIFY_10, "Write and Verify 10" },
+       { GPCMD_VERIFY_10, "Verify 10" },
+       { GPCMD_FLUSH_CACHE, "Flush Cache" },
+       { GPCMD_READ_SUBCHANNEL, "Read Subchannel" },
+       { GPCMD_READ_TOC_PMA_ATIP, "Read Table of Contents" },
+       { GPCMD_READ_HEADER, "Read Header" },
+       { GPCMD_PLAY_AUDIO_10, "Play Audio 10" },
+       { GPCMD_GET_CONFIGURATION, "Get Configuration" },
+       { GPCMD_PLAY_AUDIO_MSF, "Play Audio MSF" },
+       { GPCMD_PLAYAUDIO_TI, "Play Audio TrackIndex" },
+       { GPCMD_GET_EVENT_STATUS_NOTIFICATION,
+               "Get Event Status Notification" },
+       { GPCMD_PAUSE_RESUME, "Pause/Resume" },
+       { GPCMD_STOP_PLAY_SCAN, "Stop Play/Scan" },
+       { GPCMD_READ_DISC_INFO, "Read Disc Info" },
+       { GPCMD_READ_TRACK_RZONE_INFO, "Read Track Rzone Info" },
+       { GPCMD_RESERVE_RZONE_TRACK, "Reserve Rzone Track" },
+       { GPCMD_SEND_OPC, "Send OPC" },
+       { GPCMD_MODE_SELECT_10, "Mode Select 10" },
+       { GPCMD_REPAIR_RZONE_TRACK, "Repair Rzone Track" },
+       { GPCMD_MODE_SENSE_10, "Mode Sense 10" },
+       { GPCMD_CLOSE_TRACK, "Close Track" },
+       { GPCMD_BLANK, "Blank" },
+       { GPCMD_SEND_EVENT, "Send Event" },
+       { GPCMD_SEND_KEY, "Send Key" },
+       { GPCMD_REPORT_KEY, "Report Key" },
+       { GPCMD_LOAD_UNLOAD, "Load/Unload" },
+       { GPCMD_SET_READ_AHEAD, "Set Read-ahead" },
+       { GPCMD_READ_12, "Read 12" },
+       { GPCMD_GET_PERFORMANCE, "Get Performance" },
+       { GPCMD_SEND_DVD_STRUCTURE, "Send DVD Structure" },
+       { GPCMD_READ_DVD_STRUCTURE, "Read DVD Structure" },
+       { GPCMD_SET_STREAMING, "Set Streaming" },
+       { GPCMD_READ_CD_MSF, "Read CD MSF" },
+       { GPCMD_SCAN, "Scan" },
+       { GPCMD_SET_SPEED, "Set Speed" },
+       { GPCMD_PLAY_CD, "Play CD" },
+       { GPCMD_MECHANISM_STATUS, "Mechanism Status" },
+       { GPCMD_READ_CD, "Read CD" },
+};
+
+/* From Table 303 of the SFF8090 Ver. 3 (Mt. Fuji) draft standard. */
+static const char * const sense_key_texts[16] = {
+       "No sense data",
+       "Recovered error",
+       "Not ready",
+       "Medium error",
+       "Hardware error",
+       "Illegal request",
+       "Unit attention",
+       "Data protect",
+       "Blank check",
+       "(reserved)",
+       "(reserved)",
+       "Aborted command",
+       "(reserved)",
+       "(reserved)",
+       "Miscompare",
+       "(reserved)",
+};
+
+/* From Table 304 of the SFF8090 Ver. 3 (Mt. Fuji) draft standard. */
+static const struct {
+       unsigned long asc_ascq;
+       const char * const text;
+} sense_data_texts[] = {
+       { 0x000000, "No additional sense information" },
+       { 0x000011, "Play operation in progress" },
+       { 0x000012, "Play operation paused" },
+       { 0x000013, "Play operation successfully completed" },
+       { 0x000014, "Play operation stopped due to error" },
+       { 0x000015, "No current audio status to return" },
+       { 0x010c0a, "Write error - padding blocks added" },
+       { 0x011700, "Recovered data with no error correction applied" },
+       { 0x011701, "Recovered data with retries" },
+       { 0x011702, "Recovered data with positive head offset" },
+       { 0x011703, "Recovered data with negative head offset" },
+       { 0x011704, "Recovered data with retries and/or CIRC applied" },
+       { 0x011705, "Recovered data using previous sector ID" },
+       { 0x011800, "Recovered data with error correction applied" },
+       { 0x011801, "Recovered data with error correction and retries applied"},
+       { 0x011802, "Recovered data - the data was auto-reallocated" },
+       { 0x011803, "Recovered data with CIRC" },
+       { 0x011804, "Recovered data with L-EC" },
+       { 0x015d00, "Failure prediction threshold exceeded"
+                   " - Predicted logical unit failure" },
+       { 0x015d01, "Failure prediction threshold exceeded"
+                   " - Predicted media failure" },
+       { 0x015dff, "Failure prediction threshold exceeded - False" },
+       { 0x017301, "Power calibration area almost full" },
+       { 0x020400, "Logical unit not ready - cause not reportable" },
+       /* Following is misspelled in ATAPI 2.6, _and_ in Mt. Fuji */
+       { 0x020401, "Logical unit not ready"
+                   " - in progress [sic] of becoming ready" },
+       { 0x020402, "Logical unit not ready - initializing command required" },
+       { 0x020403, "Logical unit not ready - manual intervention required" },
+       { 0x020404, "Logical unit not ready - format in progress" },
+       { 0x020407, "Logical unit not ready - operation in progress" },
+       { 0x020408, "Logical unit not ready - long write in progress" },
+       { 0x020600, "No reference position found (media may be upside down)" },
+       { 0x023000, "Incompatible medium installed" },
+       { 0x023a00, "Medium not present" },
+       { 0x025300, "Media load or eject failed" },
+       { 0x025700, "Unable to recover table of contents" },
+       { 0x030300, "Peripheral device write fault" },
+       { 0x030301, "No write current" },
+       { 0x030302, "Excessive write errors" },
+       { 0x030c00, "Write error" },
+       { 0x030c01, "Write error - Recovered with auto reallocation" },
+       { 0x030c02, "Write error - auto reallocation failed" },
+       { 0x030c03, "Write error - recommend reassignment" },
+       { 0x030c04, "Compression check miscompare error" },
+       { 0x030c05, "Data expansion occurred during compress" },
+       { 0x030c06, "Block not compressible" },
+       { 0x030c07, "Write error - recovery needed" },
+       { 0x030c08, "Write error - recovery failed" },
+       { 0x030c09, "Write error - loss of streaming" },
+       { 0x031100, "Unrecovered read error" },
+       { 0x031106, "CIRC unrecovered error" },
+       { 0x033101, "Format command failed" },
+       { 0x033200, "No defect spare location available" },
+       { 0x033201, "Defect list update failure" },
+       { 0x035100, "Erase failure" },
+       { 0x037200, "Session fixation error" },
+       { 0x037201, "Session fixation error writin lead-in" },
+       { 0x037202, "Session fixation error writin lead-out" },
+       { 0x037300, "CD control error" },
+       { 0x037302, "Power calibration area is full" },
+       { 0x037303, "Power calibration area error" },
+       { 0x037304, "Program memory area / RMA update failure" },
+       { 0x037305, "Program memory area / RMA is full" },
+       { 0x037306, "Program memory area / RMA is (almost) full" },
+       { 0x040200, "No seek complete" },
+       { 0x040300, "Write fault" },
+       { 0x040900, "Track following error" },
+       { 0x040901, "Tracking servo failure" },
+       { 0x040902, "Focus servo failure" },
+       { 0x040903, "Spindle servo failure" },
+       { 0x041500, "Random positioning error" },
+       { 0x041501, "Mechanical positioning or changer error" },
+       { 0x041502, "Positioning error detected by read of medium" },
+       { 0x043c00, "Mechanical positioning or changer error" },
+       { 0x044000, "Diagnostic failure on component (ASCQ)" },
+       { 0x044400, "Internal CD/DVD logical unit failure" },
+       { 0x04b600, "Media load mechanism failed" },
+       { 0x051a00, "Parameter list length error" },
+       { 0x052000, "Invalid command operation code" },
+       { 0x052100, "Logical block address out of range" },
+       { 0x052102, "Invalid address for write" },
+       { 0x052400, "Invalid field in command packet" },
+       { 0x052600, "Invalid field in parameter list" },
+       { 0x052601, "Parameter not supported" },
+       { 0x052602, "Parameter value invalid" },
+       { 0x052700, "Write protected media" },
+       { 0x052c00, "Command sequence error" },
+       { 0x052c03, "Current program area is not empty" },
+       { 0x052c04, "Current program area is empty" },
+       { 0x053001, "Cannot read medium - unknown format" },
+       { 0x053002, "Cannot read medium - incompatible format" },
+       { 0x053900, "Saving parameters not supported" },
+       { 0x054e00, "Overlapped commands attempted" },
+       { 0x055302, "Medium removal prevented" },
+       { 0x055500, "System resource failure" },
+       { 0x056300, "End of user area encountered on this track" },
+       { 0x056400, "Illegal mode for this track or incompatible medium" },
+       { 0x056f00, "Copy protection key exchange failure"
+                   " - Authentication failure" },
+       { 0x056f01, "Copy protection key exchange failure - Key not present" },
+       { 0x056f02, "Copy protection key exchange failure"
+                    " - Key not established" },
+       { 0x056f03, "Read of scrambled sector without authentication" },
+       { 0x056f04, "Media region code is mismatched to logical unit" },
+       { 0x056f05, "Drive region must be permanent"
+                   " / region reset count error" },
+       { 0x057203, "Session fixation error - incomplete track in session" },
+       { 0x057204, "Empty or partially written reserved track" },
+       { 0x057205, "No more RZONE reservations are allowed" },
+       { 0x05bf00, "Loss of streaming" },
+       { 0x062800, "Not ready to ready transition, medium may have changed" },
+       { 0x062900, "Power on, reset or hardware reset occurred" },
+       { 0x062a00, "Parameters changed" },
+       { 0x062a01, "Mode parameters changed" },
+       { 0x062e00, "Insufficient time for operation" },
+       { 0x063f00, "Logical unit operating conditions have changed" },
+       { 0x063f01, "Microcode has been changed" },
+       { 0x065a00, "Operator request or state change input (unspecified)" },
+       { 0x065a01, "Operator medium removal request" },
+       { 0x0bb900, "Play operation aborted" },
+       /* Here we use 0xff for the key (not a valid key) to signify
+        * that these can have _any_ key value associated with them... */
+       { 0xff0401, "Logical unit is in process of becoming ready" },
+       { 0xff0400, "Logical unit not ready, cause not reportable" },
+       { 0xff0402, "Logical unit not ready, initializing command required" },
+       { 0xff0403, "Logical unit not ready, manual intervention required" },
+       { 0xff0500, "Logical unit does not respond to selection" },
+       { 0xff0800, "Logical unit communication failure" },
+       { 0xff0802, "Logical unit communication parity error" },
+       { 0xff0801, "Logical unit communication time-out" },
+       { 0xff2500, "Logical unit not supported" },
+       { 0xff4c00, "Logical unit failed self-configuration" },
+       { 0xff3e00, "Logical unit has not self-configured yet" },
+};
+
+void ide_cd_log_error(const char *name, struct request *failed_command,
+                     struct request_sense *sense)
+{
+       int i;
+       const char *s = "bad sense key!";
+       char buf[80];
+
+       printk(KERN_ERR "ATAPI device %s:\n", name);
+       if (sense->error_code == 0x70)
+               printk(KERN_CONT "  Error: ");
+       else if (sense->error_code == 0x71)
+               printk("  Deferred Error: ");
+       else if (sense->error_code == 0x7f)
+               printk(KERN_CONT "  Vendor-specific Error: ");
+       else
+               printk(KERN_CONT "  Unknown Error Type: ");
+
+       if (sense->sense_key < ARRAY_SIZE(sense_key_texts))
+               s = sense_key_texts[sense->sense_key];
+
+       printk(KERN_CONT "%s -- (Sense key=0x%02x)\n", s, sense->sense_key);
+
+       if (sense->asc == 0x40) {
+               sprintf(buf, "Diagnostic failure on component 0x%02x",
+                       sense->ascq);
+               s = buf;
+       } else {
+               int lo = 0, mid, hi = ARRAY_SIZE(sense_data_texts);
+               unsigned long key = (sense->sense_key << 16);
+
+               key |= (sense->asc << 8);
+               if (!(sense->ascq >= 0x80 && sense->ascq <= 0xdd))
+                       key |= sense->ascq;
+               s = NULL;
+
+               while (hi > lo) {
+                       mid = (lo + hi) / 2;
+                       if (sense_data_texts[mid].asc_ascq == key ||
+                           sense_data_texts[mid].asc_ascq == (0xff0000|key)) {
+                               s = sense_data_texts[mid].text;
+                               break;
+                       } else if (sense_data_texts[mid].asc_ascq > key)
+                               hi = mid;
+                       else
+                               lo = mid + 1;
+               }
+       }
+
+       if (s == NULL) {
+               if (sense->asc > 0x80)
+                       s = "(vendor-specific error)";
+               else
+                       s = "(reserved error code)";
+       }
+
+       printk(KERN_ERR "  %s -- (asc=0x%02x, ascq=0x%02x)\n",
+                       s, sense->asc, sense->ascq);
+
+       if (failed_command != NULL) {
+               int lo = 0, mid, hi = ARRAY_SIZE(packet_command_texts);
+               s = NULL;
+
+               while (hi > lo) {
+                       mid = (lo + hi) / 2;
+                       if (packet_command_texts[mid].packet_command ==
+                           failed_command->cmd[0]) {
+                               s = packet_command_texts[mid].text;
+                               break;
+                       }
+                       if (packet_command_texts[mid].packet_command >
+                           failed_command->cmd[0])
+                               hi = mid;
+                       else
+                               lo = mid + 1;
+               }
+
+               printk(KERN_ERR "  The failed \"%s\" packet command "
+                               "was: \n  \"", s);
+               for (i = 0; i < sizeof(failed_command->cmd); i++)
+                       printk(KERN_CONT "%02x ", failed_command->cmd[i]);
+               printk(KERN_CONT "\"\n");
+       }
+
+       /* The SKSV bit specifies validity of the sense_key_specific
+        * in the next two commands. It is bit 7 of the first byte.
+        * In the case of NOT_READY, if SKSV is set the drive can
+        * give us nice ETA readings.
+        */
+       if (sense->sense_key == NOT_READY && (sense->sks[0] & 0x80)) {
+               int progress = (sense->sks[1] << 8 | sense->sks[2]) * 100;
+
+               printk(KERN_ERR "  Command is %02d%% complete\n",
+                               progress / 0xffff);
+       }
+
+       if (sense->sense_key == ILLEGAL_REQUEST &&
+           (sense->sks[0] & 0x80) != 0) {
+               printk(KERN_ERR "  Error in %s byte %d",
+                               (sense->sks[0] & 0x40) != 0 ?
+                               "command packet" : "command data",
+                               (sense->sks[1] << 8) + sense->sks[2]);
+
+               if ((sense->sks[0] & 0x40) != 0)
+                       printk(KERN_CONT " bit %d", sense->sks[0] & 0x07);
+
+               printk(KERN_CONT "\n");
+       }
+}
+#endif
index 717e114ced524d96bbd89a91ac8b3042ab9a4e8f..3c69822507e2a59216e8d2690362c961a940579b 100644 (file)
@@ -1,10 +1,9 @@
 /*
- *  linux/drivers/ide/ide-disk.c       Version 1.18    Mar 05, 2003
- *
- *  Copyright (C) 1994-1998  Linus Torvalds & authors (see below)
- *  Copyright (C) 1998-2002  Linux ATA Development
- *                             Andre Hedrick <andre@linux-ide.org>
- *  Copyright (C) 2003      Red Hat <alan@redhat.com>
+ *  Copyright (C) 1994-1998       Linus Torvalds & authors (see below)
+ *  Copyright (C) 1998-2002       Linux ATA Development
+ *                                   Andre Hedrick <andre@linux-ide.org>
+ *  Copyright (C) 2003            Red Hat <alan@redhat.com>
+ *  Copyright (C) 2003-2005, 2007  Bartlomiej Zolnierkiewicz
  */
 
 /*
index 5bf32038dc435ed029644d425045efbdde610397..a4bb32883c6bfb23d04c19f60e2b714da9a92744 100644 (file)
@@ -1,15 +1,13 @@
 /*
- *  linux/drivers/ide/ide-dma.c                Version 4.10    June 9, 2000
+ *  Copyright (C) 1995-1998   Mark Lord
+ *  Copyright (C) 1999-2000   Andre Hedrick <andre@linux-ide.org>
+ *  Copyright (C) 2004, 2007  Bartlomiej Zolnierkiewicz
  *
- *  Copyright (c) 1999-2000    Andre Hedrick <andre@linux-ide.org>
  *  May be copied or modified under the terms of the GNU General Public License
  */
 
 /*
  *  Special Thanks to Mark for his Six years of work.
- *
- *  Copyright (c) 1995-1998  Mark Lord
- *  May be copied or modified under the terms of the GNU General Public License
  */
 
 /*
@@ -85,6 +83,7 @@
 #include <linux/ide.h>
 #include <linux/delay.h>
 #include <linux/scatterlist.h>
+#include <linux/dma-mapping.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
@@ -148,7 +147,8 @@ ide_startstop_t ide_dma_intr (ide_drive_t *drive)
        u8 stat = 0, dma_stat = 0;
 
        dma_stat = HWIF(drive)->ide_dma_end(drive);
-       stat = HWIF(drive)->INB(IDE_STATUS_REG);        /* get drive status */
+       stat = ide_read_status(drive);
+
        if (OK_STAT(stat,DRIVE_READY,drive->bad_wstat|DRQ_STAT)) {
                if (!dma_stat) {
                        struct request *rq = HWGROUP(drive)->rq;
@@ -169,16 +169,15 @@ static int ide_dma_good_drive(ide_drive_t *drive)
        return ide_in_drive_list(drive->id, drive_whitelist);
 }
 
-#ifdef CONFIG_BLK_DEV_IDEDMA_PCI
 /**
  *     ide_build_sglist        -       map IDE scatter gather for DMA I/O
  *     @drive: the drive to build the DMA table for
  *     @rq: the request holding the sg list
  *
- *     Perform the PCI mapping magic necessary to access the source or
- *     target buffers of a request via PCI DMA. The lower layers of the
+ *     Perform the DMA mapping magic necessary to access the source or
+ *     target buffers of a request via DMA.  The lower layers of the
  *     kernel provide the necessary cache management so that we can
- *     operate in a portable fashion
+ *     operate in a portable fashion.
  */
 
 int ide_build_sglist(ide_drive_t *drive, struct request *rq)
@@ -186,20 +185,20 @@ int ide_build_sglist(ide_drive_t *drive, struct request *rq)
        ide_hwif_t *hwif = HWIF(drive);
        struct scatterlist *sg = hwif->sg_table;
 
-       BUG_ON((rq->cmd_type == REQ_TYPE_ATA_TASKFILE) && rq->nr_sectors > 256);
-
        ide_map_sg(drive, rq);
 
        if (rq_data_dir(rq) == READ)
-               hwif->sg_dma_direction = PCI_DMA_FROMDEVICE;
+               hwif->sg_dma_direction = DMA_FROM_DEVICE;
        else
-               hwif->sg_dma_direction = PCI_DMA_TODEVICE;
+               hwif->sg_dma_direction = DMA_TO_DEVICE;
 
-       return pci_map_sg(hwif->pci_dev, sg, hwif->sg_nents, hwif->sg_dma_direction);
+       return dma_map_sg(hwif->dev, sg, hwif->sg_nents,
+                         hwif->sg_dma_direction);
 }
 
 EXPORT_SYMBOL_GPL(ide_build_sglist);
 
+#ifdef CONFIG_BLK_DEV_IDEDMA_PCI
 /**
  *     ide_build_dmatable      -       build IDE DMA table
  *
@@ -284,16 +283,17 @@ int ide_build_dmatable (ide_drive_t *drive, struct request *rq)
                        *--table |= cpu_to_le32(0x80000000);
                return count;
        }
+
        printk(KERN_ERR "%s: empty DMA table?\n", drive->name);
+
 use_pio_instead:
-       pci_unmap_sg(hwif->pci_dev,
-                    hwif->sg_table,
-                    hwif->sg_nents,
-                    hwif->sg_dma_direction);
+       ide_destroy_dmatable(drive);
+
        return 0; /* revert to PIO for this request */
 }
 
 EXPORT_SYMBOL_GPL(ide_build_dmatable);
+#endif
 
 /**
  *     ide_destroy_dmatable    -       clean up DMA mapping
@@ -308,15 +308,15 @@ EXPORT_SYMBOL_GPL(ide_build_dmatable);
  
 void ide_destroy_dmatable (ide_drive_t *drive)
 {
-       struct pci_dev *dev = HWIF(drive)->pci_dev;
-       struct scatterlist *sg = HWIF(drive)->sg_table;
-       int nents = HWIF(drive)->sg_nents;
+       ide_hwif_t *hwif = drive->hwif;
 
-       pci_unmap_sg(dev, sg, nents, HWIF(drive)->sg_dma_direction);
+       dma_unmap_sg(hwif->dev, hwif->sg_table, hwif->sg_nents,
+                    hwif->sg_dma_direction);
 }
 
 EXPORT_SYMBOL_GPL(ide_destroy_dmatable);
 
+#ifdef CONFIG_BLK_DEV_IDEDMA_PCI
 /**
  *     config_drive_for_dma    -       attempt to activate IDE DMA
  *     @drive: the drive to place in DMA mode
@@ -474,8 +474,6 @@ void ide_dma_on(ide_drive_t *drive)
        drive->hwif->dma_host_set(drive, 1);
 }
 
-EXPORT_SYMBOL(ide_dma_on);
-
 #ifdef CONFIG_BLK_DEV_IDEDMA_PCI
 /**
  *     ide_dma_setup   -       begin a DMA phase
@@ -822,6 +820,26 @@ int ide_set_dma(ide_drive_t *drive)
        return 0;
 }
 
+void ide_check_dma_crc(ide_drive_t *drive)
+{
+       u8 mode;
+
+       ide_dma_off_quietly(drive);
+       drive->crc_count = 0;
+       mode = drive->current_speed;
+       /*
+        * Don't try non Ultra-DMA modes without iCRC's.  Force the
+        * device to PIO and make the user enable SWDMA/MWDMA modes.
+        */
+       if (mode > XFER_UDMA_0 && mode <= XFER_UDMA_7)
+               mode--;
+       else
+               mode = XFER_PIO_4;
+       ide_set_xfer_rate(drive, mode);
+       if (drive->current_speed >= XFER_SW_DMA_0)
+               ide_dma_on(drive);
+}
+
 #ifdef CONFIG_BLK_DEV_IDEDMA_PCI
 void ide_dma_lost_irq (ide_drive_t *drive)
 {
@@ -847,10 +865,10 @@ EXPORT_SYMBOL(ide_dma_timeout);
 static void ide_release_dma_engine(ide_hwif_t *hwif)
 {
        if (hwif->dmatable_cpu) {
-               pci_free_consistent(hwif->pci_dev,
-                                   PRD_ENTRIES * PRD_BYTES,
-                                   hwif->dmatable_cpu,
-                                   hwif->dmatable_dma);
+               struct pci_dev *pdev = to_pci_dev(hwif->dev);
+
+               pci_free_consistent(pdev, PRD_ENTRIES * PRD_BYTES,
+                                   hwif->dmatable_cpu, hwif->dmatable_dma);
                hwif->dmatable_cpu = NULL;
        }
 }
@@ -878,7 +896,9 @@ int ide_release_dma(ide_hwif_t *hwif)
 
 static int ide_allocate_dma_engine(ide_hwif_t *hwif)
 {
-       hwif->dmatable_cpu = pci_alloc_consistent(hwif->pci_dev,
+       struct pci_dev *pdev = to_pci_dev(hwif->dev);
+
+       hwif->dmatable_cpu = pci_alloc_consistent(pdev,
                                                  PRD_ENTRIES * PRD_BYTES,
                                                  &hwif->dmatable_dma);
 
@@ -891,19 +911,19 @@ static int ide_allocate_dma_engine(ide_hwif_t *hwif)
        return 1;
 }
 
-static int ide_mapped_mmio_dma(ide_hwif_t *hwif, unsigned long base, unsigned int ports)
+static int ide_mapped_mmio_dma(ide_hwif_t *hwif, unsigned long base)
 {
        printk(KERN_INFO "    %s: MMIO-DMA ", hwif->name);
 
        return 0;
 }
 
-static int ide_iomio_dma(ide_hwif_t *hwif, unsigned long base, unsigned int ports)
+static int ide_iomio_dma(ide_hwif_t *hwif, unsigned long base)
 {
        printk(KERN_INFO "    %s: BM-DMA at 0x%04lx-0x%04lx",
-              hwif->name, base, base + ports - 1);
+              hwif->name, base, base + 7);
 
-       if (!request_region(base, ports, hwif->name)) {
+       if (!request_region(base, 8, hwif->name)) {
                printk(" -- Error, ports in use.\n");
                return 1;
        }
@@ -915,7 +935,7 @@ static int ide_iomio_dma(ide_hwif_t *hwif, unsigned long base, unsigned int port
                        if (!request_region(hwif->extra_base,
                                            hwif->cds->extra, hwif->cds->name)) {
                                printk(" -- Error, extra ports in use.\n");
-                               release_region(base, ports);
+                               release_region(base, 8);
                                return 1;
                        }
                        hwif->extra_ports = hwif->cds->extra;
@@ -925,17 +945,19 @@ static int ide_iomio_dma(ide_hwif_t *hwif, unsigned long base, unsigned int port
        return 0;
 }
 
-static int ide_dma_iobase(ide_hwif_t *hwif, unsigned long base, unsigned int ports)
+static int ide_dma_iobase(ide_hwif_t *hwif, unsigned long base)
 {
        if (hwif->mmio)
-               return ide_mapped_mmio_dma(hwif, base,ports);
+               return ide_mapped_mmio_dma(hwif, base);
 
-       return ide_iomio_dma(hwif, base, ports);
+       return ide_iomio_dma(hwif, base);
 }
 
-void ide_setup_dma(ide_hwif_t *hwif, unsigned long base, unsigned num_ports)
+void ide_setup_dma(ide_hwif_t *hwif, unsigned long base)
 {
-       if (ide_dma_iobase(hwif, base, num_ports))
+       u8 dma_stat;
+
+       if (ide_dma_iobase(hwif, base))
                return;
 
        if (ide_allocate_dma_engine(hwif)) {
@@ -945,16 +967,16 @@ void ide_setup_dma(ide_hwif_t *hwif, unsigned long base, unsigned num_ports)
 
        hwif->dma_base = base;
 
-       if (!(hwif->dma_command))
-               hwif->dma_command       = hwif->dma_base;
-       if (!(hwif->dma_vendor1))
-               hwif->dma_vendor1       = (hwif->dma_base + 1);
-       if (!(hwif->dma_status))
-               hwif->dma_status        = (hwif->dma_base + 2);
-       if (!(hwif->dma_vendor3))
-               hwif->dma_vendor3       = (hwif->dma_base + 3);
-       if (!(hwif->dma_prdtable))
-               hwif->dma_prdtable      = (hwif->dma_base + 4);
+       if (!hwif->dma_command)
+               hwif->dma_command       = hwif->dma_base + 0;
+       if (!hwif->dma_vendor1)
+               hwif->dma_vendor1       = hwif->dma_base + 1;
+       if (!hwif->dma_status)
+               hwif->dma_status        = hwif->dma_base + 2;
+       if (!hwif->dma_vendor3)
+               hwif->dma_vendor3       = hwif->dma_base + 3;
+       if (!hwif->dma_prdtable)
+               hwif->dma_prdtable      = hwif->dma_base + 4;
 
        if (!hwif->dma_host_set)
                hwif->dma_host_set = &ide_dma_host_set;
@@ -973,13 +995,10 @@ void ide_setup_dma(ide_hwif_t *hwif, unsigned long base, unsigned num_ports)
        if (!hwif->dma_lost_irq)
                hwif->dma_lost_irq = &ide_dma_lost_irq;
 
-       if (hwif->chipset != ide_trm290) {
-               u8 dma_stat = hwif->INB(hwif->dma_status);
-               printk(", BIOS settings: %s:%s, %s:%s",
-                      hwif->drives[0].name, (dma_stat & 0x20) ? "DMA" : "pio",
-                      hwif->drives[1].name, (dma_stat & 0x40) ? "DMA" : "pio");
-       }
-       printk("\n");
+       dma_stat = hwif->INB(hwif->dma_status);
+       printk(KERN_CONT ", BIOS settings: %s:%s, %s:%s\n",
+              hwif->drives[0].name, (dma_stat & 0x20) ? "DMA" : "PIO",
+              hwif->drives[1].name, (dma_stat & 0x40) ? "DMA" : "PIO");
 }
 
 EXPORT_SYMBOL_GPL(ide_setup_dma);
index ff8232ef96598ae784001a0a61dd2da69a91c69a..faf22d716f805995e6e59351c77e740b514f4fce 100644 (file)
@@ -1,15 +1,9 @@
-/*
- * linux/drivers/ide/ide-floppy.c      Version 0.99    Feb 24 2002
- *
- * Copyright (C) 1996 - 1999 Gadi Oxman <gadio@netvision.net.il>
- * Copyright (C) 2000 - 2002 Paul Bristow <paul@paulbristow.net>
- */
-
 /*
  * IDE ATAPI floppy driver.
  *
- * The driver currently doesn't have any fancy features, just the bare
- * minimum read/write support.
+ * Copyright (C) 1996-1999  Gadi Oxman <gadio@netvision.net.il>
+ * Copyright (C) 2000-2002  Paul Bristow <paul@paulbristow.net>
+ * Copyright (C) 2005       Bartlomiej Zolnierkiewicz
  *
  * This driver supports the following IDE floppy drives:
  *
  * Iomega Zip 100/250
  * Iomega PC Card Clik!/PocketZip
  *
- * Many thanks to Lode Leroy <Lode.Leroy@www.ibase.be>, who tested so many
- * ALPHA patches to this driver on an EASYSTOR LS-120 ATAPI floppy drive.
- *
- * Ver 0.1   Oct 17 96   Initial test version, mostly based on ide-tape.c.
- * Ver 0.2   Oct 31 96   Minor changes.
- * Ver 0.3   Dec  2 96   Fixed error recovery bug.
- * Ver 0.4   Jan 26 97   Add support for the HDIO_GETGEO ioctl.
- * Ver 0.5   Feb 21 97   Add partitions support.
- *                       Use the minimum of the LBA and CHS capacities.
- *                       Avoid hwgroup->rq == NULL on the last irq.
- *                       Fix potential null dereferencing with DEBUG_LOG.
- * Ver 0.8   Dec  7 97   Increase irq timeout from 10 to 50 seconds.
- *                       Add media write-protect detection.
- *                       Issue START command only if TEST UNIT READY fails.
- *                       Add work-around for IOMEGA ZIP revision 21.D.
- *                       Remove idefloppy_get_capabilities().
- * Ver 0.9   Jul  4 99   Fix a bug which might have caused the number of
- *                        bytes requested on each interrupt to be zero.
- *                        Thanks to <shanos@es.co.nz> for pointing this out.
- * Ver 0.9.sv Jan 6 01   Sam Varshavchik <mrsam@courier-mta.com>
- *                       Implement low level formatting.  Reimplemented
- *                       IDEFLOPPY_CAPABILITIES_PAGE, since we need the srfp
- *                       bit.  My LS-120 drive barfs on
- *                       IDEFLOPPY_CAPABILITIES_PAGE, but maybe it's just me.
- *                       Compromise by not reporting a failure to get this
- *                       mode page.  Implemented four IOCTLs in order to
- *                       implement formatting.  IOCTls begin with 0x4600,
- *                       0x46 is 'F' as in Format.
- *            Jan 9 01   Userland option to select format verify.
- *                       Added PC_SUPPRESS_ERROR flag - some idefloppy drives
- *                       do not implement IDEFLOPPY_CAPABILITIES_PAGE, and
- *                       return a sense error.  Suppress error reporting in
- *                       this particular case in order to avoid spurious
- *                       errors in syslog.  The culprit is
- *                       idefloppy_get_capability_page(), so move it to
- *                       idefloppy_begin_format() so that it's not used
- *                       unless absolutely necessary.
- *                       If drive does not support format progress indication
- *                       monitor the dsc bit in the status register.
- *                       Also, O_NDELAY on open will allow the device to be
- *                       opened without a disk available.  This can be used to
- *                       open an unformatted disk, or get the device capacity.
- * Ver 0.91  Dec 11 99   Added IOMEGA Clik! drive support by 
- *                        <paul@paulbristow.net>
- * Ver 0.92  Oct 22 00   Paul Bristow became official maintainer for this 
- *                        driver.  Included Powerbook internal zip kludge.
- * Ver 0.93  Oct 24 00   Fixed bugs for Clik! drive
- *                        no disk on insert and disk change now works
- * Ver 0.94  Oct 27 00   Tidied up to remove strstr(Clik) everywhere
- * Ver 0.95  Nov  7 00   Brought across to kernel 2.4
- * Ver 0.96  Jan  7 01   Actually in line with release version of 2.4.0
- *                       including set_bit patch from Rusty Russell
- * Ver 0.97  Jul 22 01   Merge 0.91-0.96 onto 0.9.sv for ac series
- * Ver 0.97.sv Aug 3 01  Backported from 2.4.7-ac3
- * Ver 0.98  Oct 26 01   Split idefloppy_transfer_pc into two pieces to
- *                        fix a lost interrupt problem. It appears the busy
- *                        bit was being deasserted by my IOMEGA ATAPI ZIP 100
- *                        drive before the drive was actually ready.
- * Ver 0.98a Oct 29 01   Expose delay value so we can play.
- * Ver 0.99  Feb 24 02   Remove duplicate code, modify clik! detection code 
- *                        to support new PocketZip drives 
+ * For a historical changelog see
+ * Documentation/ide/ChangeLog.ide-floppy.1996-2002
  */
 
-#define IDEFLOPPY_VERSION "0.99.newide"
+#define IDEFLOPPY_VERSION "1.00"
 
 #include <linux/module.h>
 #include <linux/types.h>
 #include <scsi/scsi_ioctl.h>
 
 #include <asm/byteorder.h>
-#include <asm/irq.h>
-#include <asm/uaccess.h>
-#include <asm/io.h>
+#include <linux/irq.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
 #include <asm/unaligned.h>
 
-/*
- *     The following are used to debug the driver.
- */
+/* define to see debug info */
 #define IDEFLOPPY_DEBUG_LOG            0
-#define IDEFLOPPY_DEBUG_INFO           0
-#define IDEFLOPPY_DEBUG_BUGS           1
 
 /* #define IDEFLOPPY_DEBUG(fmt, args...) printk(KERN_INFO fmt, ## args) */
-#define IDEFLOPPY_DEBUG( fmt, args... )
+#define IDEFLOPPY_DEBUG(fmt, args...)
 
 #if IDEFLOPPY_DEBUG_LOG
-#define debug_log printk
+#define debug_log(fmt, args...) \
+       printk(KERN_INFO "ide-floppy: " fmt, ## args)
 #else
-#define debug_log(fmt, args... ) do {} while(0)
+#define debug_log(fmt, args...) do {} while (0)
 #endif
 
 
-/*
- *     Some drives require a longer irq timeout.
- */
+/* Some drives require a longer irq timeout. */
 #define IDEFLOPPY_WAIT_CMD             (5 * WAIT_CMD)
 
 /*
- *     After each failed packet command we issue a request sense command
- *     and retry the packet command IDEFLOPPY_MAX_PC_RETRIES times.
+ * After each failed packet command we issue a request sense command and retry
+ * the packet command IDEFLOPPY_MAX_PC_RETRIES times.
  */
 #define IDEFLOPPY_MAX_PC_RETRIES       3
 
 /*
- *     With each packet command, we allocate a buffer of
- *     IDEFLOPPY_PC_BUFFER_SIZE bytes.
+ * With each packet command, we allocate a buffer of IDEFLOPPY_PC_BUFFER_SIZE
+ * bytes.
  */
 #define IDEFLOPPY_PC_BUFFER_SIZE       256
 
 /*
- *     In various places in the driver, we need to allocate storage
- *     for packet commands and requests, which will remain valid while
- *     we leave the driver to wait for an interrupt or a timeout event.
+ * In various places in the driver, we need to allocate storage for packet
+ * commands and requests, which will remain valid while        we leave the driver to
+ * wait for an interrupt or a timeout event.
  */
 #define IDEFLOPPY_PC_STACK             (10 + IDEFLOPPY_MAX_PC_RETRIES)
 
-/*
- *     Our view of a packet command.
- */
 typedef struct idefloppy_packet_command_s {
        u8 c[12];                               /* Actual packet bytes */
-       int retries;                            /* On each retry, we increment retries */
+       int retries;                            /* On each retry, we increment
+                                                  retries */
        int error;                              /* Error code */
        int request_transfer;                   /* Bytes to transfer */
        int actually_transferred;               /* Bytes actually transferred */
        int buffer_size;                        /* Size of our data buffer */
-       int b_count;                            /* Missing/Available data on the current buffer */
+       int b_count;                            /* Missing/Available data on
+                                                  the current buffer */
        struct request *rq;                     /* The corresponding request */
        u8 *buffer;                             /* Data buffer */
-       u8 *current_position;                   /* Pointer into the above buffer */
-       void (*callback) (ide_drive_t *);       /* Called when this packet command is completed */
+       u8 *current_position;                   /* Pointer into above buffer */
+       void (*callback) (ide_drive_t *);       /* Called when this packet
+                                                  command is completed */
        u8 pc_buffer[IDEFLOPPY_PC_BUFFER_SIZE]; /* Temporary buffer */
-       unsigned long flags;                    /* Status/Action bit flags: long for set_bit */
+       unsigned long flags;                    /* Status/Action bit flags: long
+                                                  for set_bit */
 } idefloppy_pc_t;
 
-/*
- *     Packet command flag bits.
- */
-#define        PC_ABORT                        0       /* Set when an error is considered normal - We won't retry */
-#define PC_DMA_RECOMMENDED             2       /* 1 when we prefer to use DMA if possible */
-#define        PC_DMA_IN_PROGRESS              3       /* 1 while DMA in progress */
-#define        PC_DMA_ERROR                    4       /* 1 when encountered problem during DMA */
-#define        PC_WRITING                      5       /* Data direction */
-
-#define        PC_SUPPRESS_ERROR               6       /* Suppress error reporting */
-
-/*
- *     Removable Block Access Capabilities Page
- */
-typedef struct {
-#if defined(__LITTLE_ENDIAN_BITFIELD)
-       unsigned        page_code       :6;     /* Page code - Should be 0x1b */
-       unsigned        reserved1_6     :1;     /* Reserved */
-       unsigned        ps              :1;     /* Should be 0 */
-#elif defined(__BIG_ENDIAN_BITFIELD)
-       unsigned        ps              :1;     /* Should be 0 */
-       unsigned        reserved1_6     :1;     /* Reserved */
-       unsigned        page_code       :6;     /* Page code - Should be 0x1b */
-#else
-#error "Bitfield endianness not defined! Check your byteorder.h"
-#endif
-       u8              page_length;            /* Page Length - Should be 0xa */
-#if defined(__LITTLE_ENDIAN_BITFIELD)
-       unsigned        reserved2       :6;
-       unsigned        srfp            :1;     /* Supports reporting progress of format */
-       unsigned        sflp            :1;     /* System floppy type device */
-       unsigned        tlun            :3;     /* Total logical units supported by the device */
-       unsigned        reserved3       :3;
-       unsigned        sml             :1;     /* Single / Multiple lun supported */
-       unsigned        ncd             :1;     /* Non cd optical device */
-#elif defined(__BIG_ENDIAN_BITFIELD)
-       unsigned        sflp            :1;     /* System floppy type device */
-       unsigned        srfp            :1;     /* Supports reporting progress of format */
-       unsigned        reserved2       :6;
-       unsigned        ncd             :1;     /* Non cd optical device */
-       unsigned        sml             :1;     /* Single / Multiple lun supported */
-       unsigned        reserved3       :3;
-       unsigned        tlun            :3;     /* Total logical units supported by the device */
-#else
-#error "Bitfield endianness not defined! Check your byteorder.h"
-#endif
-       u8              reserved[8];
-} idefloppy_capabilities_page_t;
-
-/*
- *     Flexible disk page.
- */
-typedef struct {
-#if defined(__LITTLE_ENDIAN_BITFIELD)
-       unsigned        page_code       :6;     /* Page code - Should be 0x5 */
-       unsigned        reserved1_6     :1;     /* Reserved */
-       unsigned        ps              :1;     /* The device is capable of saving the page */
-#elif defined(__BIG_ENDIAN_BITFIELD)
-       unsigned        ps              :1;     /* The device is capable of saving the page */
-       unsigned        reserved1_6     :1;     /* Reserved */
-       unsigned        page_code       :6;     /* Page code - Should be 0x5 */
-#else
-#error "Bitfield endianness not defined! Check your byteorder.h"
-#endif
-       u8              page_length;            /* Page Length - Should be 0x1e */
-       u16             transfer_rate;          /* In kilobits per second */
-       u8              heads, sectors;         /* Number of heads, Number of sectors per track */
-       u16             sector_size;            /* Byes per sector */
-       u16             cyls;                   /* Number of cylinders */
-       u8              reserved10[10];
-       u8              motor_delay;            /* Motor off delay */
-       u8              reserved21[7];
-       u16             rpm;                    /* Rotations per minute */
-       u8              reserved30[2];
-} idefloppy_flexible_disk_page_t;
-/*
- *     Format capacity
- */
-typedef struct {
-       u8              reserved[3];
-       u8              length;                 /* Length of the following descriptors in bytes */
-} idefloppy_capacity_header_t;
-
-typedef struct {
-       u32             blocks;                 /* Number of blocks */
-#if defined(__LITTLE_ENDIAN_BITFIELD)
-       unsigned        dc              :2;     /* Descriptor Code */
-       unsigned        reserved        :6;
-#elif defined(__BIG_ENDIAN_BITFIELD)
-       unsigned        reserved        :6;
-       unsigned        dc              :2;     /* Descriptor Code */
-#else
-#error "Bitfield endianness not defined! Check your byteorder.h"
-#endif
-       u8              length_msb;             /* Block Length (MSB)*/
-       u16             length;                 /* Block Length */
-} idefloppy_capacity_descriptor_t;
+/* Packet command flag bits. */
+enum {
+       /* 1 when we prefer to use DMA if possible */
+       PC_FLAG_DMA_RECOMMENDED = (1 << 0),
+       /* 1 while DMA in progress */
+       PC_FLAG_DMA_IN_PROGRESS = (1 << 1),
+       /* 1 when encountered problem during DMA */
+       PC_FLAG_DMA_ERROR       = (1 << 2),
+       /* Data direction */
+       PC_FLAG_WRITING         = (1 << 3),
+       /* Suppress error reporting */
+       PC_FLAG_SUPPRESS_ERROR  = (1 << 4),
+};
 
+/* format capacities descriptor codes */
 #define CAPACITY_INVALID       0x00
 #define CAPACITY_UNFORMATTED   0x01
 #define CAPACITY_CURRENT       0x02
 #define CAPACITY_NO_CARTRIDGE  0x03
 
 /*
- *     Most of our global data which we need to save even as we leave the
- *     driver due to an interrupt or a timer event is stored in a variable
- *     of type idefloppy_floppy_t, defined below.
+ * Most of our global data which we need to save even as we leave the driver
+ * due to an interrupt or a timer event is stored in a variable of type
+ * idefloppy_floppy_t, defined below.
  */
 typedef struct ide_floppy_obj {
        ide_drive_t     *drive;
@@ -295,23 +142,19 @@ typedef struct ide_floppy_obj {
        /* We implement a circular array */
        int rq_stack_index;
 
-       /*
-        *      Last error information
-        */
+       /* Last error information */
        u8 sense_key, asc, ascq;
        /* delay this long before sending packet command */
        u8 ticks;
        int progress_indication;
 
-       /*
-        *      Device information
-        */
+       /* Device information */
        /* Current format */
        int blocks, block_size, bs_factor;
-       /* Last format capacity */
-       idefloppy_capacity_descriptor_t capacity;
+       /* Last format capacity descriptor */
+       u8 cap_desc[8];
        /* Copy of the flexible disk page */
-       idefloppy_flexible_disk_page_t flexible_disk_page;
+       u8 flexible_disk_page[32];
        /* Write protect */
        int wp;
        /* Supports format progress report */
@@ -322,64 +165,40 @@ typedef struct ide_floppy_obj {
 
 #define IDEFLOPPY_TICKS_DELAY  HZ/20   /* default delay for ZIP 100 (50ms) */
 
-/*
- *     Floppy flag bits values.
- */
-#define IDEFLOPPY_DRQ_INTERRUPT                0       /* DRQ interrupt device */
-#define IDEFLOPPY_MEDIA_CHANGED                1       /* Media may have changed */
-#define IDEFLOPPY_USE_READ12           2       /* Use READ12/WRITE12 or READ10/WRITE10 */
-#define        IDEFLOPPY_FORMAT_IN_PROGRESS    3       /* Format in progress */
-#define IDEFLOPPY_CLIK_DRIVE           4       /* Avoid commands not supported in Clik drive */
-#define IDEFLOPPY_ZIP_DRIVE            5       /* Requires BH algorithm for packets */
-
-/*
- *     ATAPI floppy drive packet commands
- */
-#define IDEFLOPPY_FORMAT_UNIT_CMD      0x04
-#define IDEFLOPPY_INQUIRY_CMD          0x12
-#define IDEFLOPPY_MODE_SELECT_CMD      0x55
-#define IDEFLOPPY_MODE_SENSE_CMD       0x5a
-#define IDEFLOPPY_READ10_CMD           0x28
-#define IDEFLOPPY_READ12_CMD           0xa8
-#define IDEFLOPPY_READ_CAPACITY_CMD    0x23
-#define IDEFLOPPY_REQUEST_SENSE_CMD    0x03
-#define IDEFLOPPY_PREVENT_REMOVAL_CMD  0x1e
-#define IDEFLOPPY_SEEK_CMD             0x2b
-#define IDEFLOPPY_START_STOP_CMD       0x1b
-#define IDEFLOPPY_TEST_UNIT_READY_CMD  0x00
-#define IDEFLOPPY_VERIFY_CMD           0x2f
-#define IDEFLOPPY_WRITE10_CMD          0x2a
-#define IDEFLOPPY_WRITE12_CMD          0xaa
-#define IDEFLOPPY_WRITE_VERIFY_CMD     0x2e
+/* Floppy flag bits values. */
+enum {
+       /* DRQ interrupt device */
+       IDEFLOPPY_FLAG_DRQ_INTERRUPT            = (1 << 0),
+       /* Media may have changed */
+       IDEFLOPPY_FLAG_MEDIA_CHANGED            = (1 << 1),
+       /* Format in progress */
+       IDEFLOPPY_FLAG_FORMAT_IN_PROGRESS       = (1 << 2),
+       /* Avoid commands not supported in Clik drive */
+       IDEFLOPPY_FLAG_CLIK_DRIVE               = (1 << 3),
+       /* Requires BH algorithm for packets */
+       IDEFLOPPY_FLAG_ZIP_DRIVE                = (1 << 4),
+};
 
-/*
- *     Defines for the mode sense command
- */
+/* Defines for the MODE SENSE command */
 #define MODE_SENSE_CURRENT             0x00
 #define MODE_SENSE_CHANGEABLE          0x01
-#define MODE_SENSE_DEFAULT             0x02 
+#define MODE_SENSE_DEFAULT             0x02
 #define MODE_SENSE_SAVED               0x03
 
-/*
- *     IOCTLs used in low-level formatting.
- */
-
+/* IOCTLs used in low-level formatting. */
 #define        IDEFLOPPY_IOCTL_FORMAT_SUPPORTED        0x4600
 #define        IDEFLOPPY_IOCTL_FORMAT_GET_CAPACITY     0x4601
 #define        IDEFLOPPY_IOCTL_FORMAT_START            0x4602
 #define IDEFLOPPY_IOCTL_FORMAT_GET_PROGRESS    0x4603
 
-/*
- *     Error codes which are returned in rq->errors to the higher part
- *     of the driver.
- */
+/* Error code returned in rq->errors to the higher part of the driver. */
 #define        IDEFLOPPY_ERROR_GENERAL         101
 
 /*
- *     The following is used to format the general configuration word of
- *     the ATAPI IDENTIFY DEVICE command.
+ * The following is used to format the general configuration word of the
+ * ATAPI IDENTIFY DEVICE command.
  */
-struct idefloppy_id_gcw {      
+struct idefloppy_id_gcw {
 #if defined(__LITTLE_ENDIAN_BITFIELD)
        unsigned packet_size            :2;     /* Packet Size */
        unsigned reserved234            :3;     /* Reserved */
@@ -402,103 +221,12 @@ struct idefloppy_id_gcw {
 };
 
 /*
- *     INQUIRY packet command - Data Format
- */
-typedef struct {
-#if defined(__LITTLE_ENDIAN_BITFIELD)
-       unsigned        device_type     :5;     /* Peripheral Device Type */
-       unsigned        reserved0_765   :3;     /* Peripheral Qualifier - Reserved */
-       unsigned        reserved1_6t0   :7;     /* Reserved */
-       unsigned        rmb             :1;     /* Removable Medium Bit */
-       unsigned        ansi_version    :3;     /* ANSI Version */
-       unsigned        ecma_version    :3;     /* ECMA Version */
-       unsigned        iso_version     :2;     /* ISO Version */
-       unsigned        response_format :4;     /* Response Data Format */
-       unsigned        reserved3_45    :2;     /* Reserved */
-       unsigned        reserved3_6     :1;     /* TrmIOP - Reserved */
-       unsigned        reserved3_7     :1;     /* AENC - Reserved */
-#elif defined(__BIG_ENDIAN_BITFIELD)
-       unsigned        reserved0_765   :3;     /* Peripheral Qualifier - Reserved */
-       unsigned        device_type     :5;     /* Peripheral Device Type */
-       unsigned        rmb             :1;     /* Removable Medium Bit */
-       unsigned        reserved1_6t0   :7;     /* Reserved */
-       unsigned        iso_version     :2;     /* ISO Version */
-       unsigned        ecma_version    :3;     /* ECMA Version */
-       unsigned        ansi_version    :3;     /* ANSI Version */
-       unsigned        reserved3_7     :1;     /* AENC - Reserved */
-       unsigned        reserved3_6     :1;     /* TrmIOP - Reserved */
-       unsigned        reserved3_45    :2;     /* Reserved */
-       unsigned        response_format :4;     /* Response Data Format */
-#else
-#error "Bitfield endianness not defined! Check your byteorder.h"
-#endif
-       u8              additional_length;      /* Additional Length (total_length-4) */
-       u8              rsv5, rsv6, rsv7;       /* Reserved */
-       u8              vendor_id[8];           /* Vendor Identification */
-       u8              product_id[16];         /* Product Identification */
-       u8              revision_level[4];      /* Revision Level */
-       u8              vendor_specific[20];    /* Vendor Specific - Optional */
-       u8              reserved56t95[40];      /* Reserved - Optional */
-                                               /* Additional information may be returned */
-} idefloppy_inquiry_result_t;
-
-/*
- *     REQUEST SENSE packet command result - Data Format.
- */
-typedef struct {
-#if defined(__LITTLE_ENDIAN_BITFIELD)
-       unsigned        error_code      :7;     /* Current error (0x70) */
-       unsigned        valid           :1;     /* The information field conforms to SFF-8070i */
-       u8              reserved1       :8;     /* Reserved */
-       unsigned        sense_key       :4;     /* Sense Key */
-       unsigned        reserved2_4     :1;     /* Reserved */
-       unsigned        ili             :1;     /* Incorrect Length Indicator */
-       unsigned        reserved2_67    :2;
-#elif defined(__BIG_ENDIAN_BITFIELD)
-       unsigned        valid           :1;     /* The information field conforms to SFF-8070i */
-       unsigned        error_code      :7;     /* Current error (0x70) */
-       u8              reserved1       :8;     /* Reserved */
-       unsigned        reserved2_67    :2;
-       unsigned        ili             :1;     /* Incorrect Length Indicator */
-       unsigned        reserved2_4     :1;     /* Reserved */
-       unsigned        sense_key       :4;     /* Sense Key */
-#else
-#error "Bitfield endianness not defined! Check your byteorder.h"
-#endif
-       u32             information __attribute__ ((packed));
-       u8              asl;                    /* Additional sense length (n-7) */
-       u32             command_specific;       /* Additional command specific information */
-       u8              asc;                    /* Additional Sense Code */
-       u8              ascq;                   /* Additional Sense Code Qualifier */
-       u8              replaceable_unit_code;  /* Field Replaceable Unit Code */
-       u8              sksv[3];
-       u8              pad[2];                 /* Padding to 20 bytes */
-} idefloppy_request_sense_result_t;
-
-/*
- *     Pages of the SELECT SENSE / MODE SENSE packet commands.
+ * Pages of the SELECT SENSE / MODE SENSE packet commands.
+ * See SFF-8070i spec.
  */
 #define        IDEFLOPPY_CAPABILITIES_PAGE     0x1b
 #define IDEFLOPPY_FLEXIBLE_DISK_PAGE   0x05
 
-/*
- *     Mode Parameter Header for the MODE SENSE packet command
- */
-typedef struct {
-       u16             mode_data_length;       /* Length of the following data transfer */
-       u8              medium_type;            /* Medium Type */
-#if defined(__LITTLE_ENDIAN_BITFIELD)
-       unsigned        reserved3       :7;
-       unsigned        wp              :1;     /* Write protect */
-#elif defined(__BIG_ENDIAN_BITFIELD)
-       unsigned        wp              :1;     /* Write protect */
-       unsigned        reserved3       :7;
-#else
-#error "Bitfield endianness not defined! Check your byteorder.h"
-#endif
-       u8              reserved[4];
-} idefloppy_mode_parameter_header_t;
-
 static DEFINE_MUTEX(idefloppy_ref_mutex);
 
 #define to_ide_floppy(obj) container_of(obj, struct ide_floppy_obj, kref)
@@ -518,39 +246,35 @@ static struct ide_floppy_obj *ide_floppy_get(struct gendisk *disk)
        return floppy;
 }
 
-static void ide_floppy_release(struct kref *);
+static void idefloppy_cleanup_obj(struct kref *);
 
 static void ide_floppy_put(struct ide_floppy_obj *floppy)
 {
        mutex_lock(&idefloppy_ref_mutex);
-       kref_put(&floppy->kref, ide_floppy_release);
+       kref_put(&floppy->kref, idefloppy_cleanup_obj);
        mutex_unlock(&idefloppy_ref_mutex);
 }
 
 /*
- *     Too bad. The drive wants to send us data which we are not ready to accept.
- *     Just throw it away.
+ * Too bad. The drive wants to send us data which we are not ready to accept.
+ * Just throw it away.
  */
-static void idefloppy_discard_data (ide_drive_t *drive, unsigned int bcount)
+static void idefloppy_discard_data(ide_drive_t *drive, unsigned int bcount)
 {
        while (bcount--)
                (void) HWIF(drive)->INB(IDE_DATA_REG);
 }
 
-#if IDEFLOPPY_DEBUG_BUGS
-static void idefloppy_write_zeros (ide_drive_t *drive, unsigned int bcount)
+static void idefloppy_write_zeros(ide_drive_t *drive, unsigned int bcount)
 {
        while (bcount--)
                HWIF(drive)->OUTB(0, IDE_DATA_REG);
 }
-#endif /* IDEFLOPPY_DEBUG_BUGS */
 
 
 /*
- *     idefloppy_do_end_request is used to finish servicing a request.
- *
- *     For read/write requests, we will call ide_end_request to pass to the
- *     next buffer.
+ * Used to finish servicing a request. For read/write requests, we will call
+ * ide_end_request to pass to the next buffer.
  */
 static int idefloppy_do_end_request(ide_drive_t *drive, int uptodate, int nsecs)
 {
@@ -558,12 +282,12 @@ static int idefloppy_do_end_request(ide_drive_t *drive, int uptodate, int nsecs)
        struct request *rq = HWGROUP(drive)->rq;
        int error;
 
-       debug_log(KERN_INFO "Reached idefloppy_end_request\n");
+       debug_log("Reached %s\n", __func__);
 
        switch (uptodate) {
-               case 0: error = IDEFLOPPY_ERROR_GENERAL; break;
-               case 1: error = 0; break;
-               default: error = uptodate;
+       case 0: error = IDEFLOPPY_ERROR_GENERAL; break;
+       case 1: error = 0; break;
+       default: error = uptodate;
        }
        if (error)
                floppy->failed_pc = NULL;
@@ -581,39 +305,8 @@ static int idefloppy_do_end_request(ide_drive_t *drive, int uptodate, int nsecs)
        return 0;
 }
 
-static void idefloppy_input_buffers (ide_drive_t *drive, idefloppy_pc_t *pc, unsigned int bcount)
-{
-       struct request *rq = pc->rq;
-       struct bio_vec *bvec;
-       struct req_iterator iter;
-       unsigned long flags;
-       char *data;
-       int count, done = 0;
-
-       rq_for_each_segment(bvec, rq, iter) {
-               if (!bcount)
-                       break;
-
-               count = min(bvec->bv_len, bcount);
-
-               data = bvec_kmap_irq(bvec, &flags);
-               drive->hwif->atapi_input_bytes(drive, data, count);
-               bvec_kunmap_irq(data, &flags);
-
-               bcount -= count;
-               pc->b_count += count;
-               done += count;
-       }
-
-       idefloppy_do_end_request(drive, 1, done >> 9);
-
-       if (bcount) {
-               printk(KERN_ERR "%s: leftover data in idefloppy_input_buffers, bcount == %d\n", drive->name, bcount);
-               idefloppy_discard_data(drive, bcount);
-       }
-}
-
-static void idefloppy_output_buffers (ide_drive_t *drive, idefloppy_pc_t *pc, unsigned int bcount)
+static void ide_floppy_io_buffers(ide_drive_t *drive, idefloppy_pc_t *pc,
+                                 unsigned int bcount, int direction)
 {
        struct request *rq = pc->rq;
        struct req_iterator iter;
@@ -629,7 +322,10 @@ static void idefloppy_output_buffers (ide_drive_t *drive, idefloppy_pc_t *pc, un
                count = min(bvec->bv_len, bcount);
 
                data = bvec_kmap_irq(bvec, &flags);
-               drive->hwif->atapi_output_bytes(drive, data, count);
+               if (direction)
+                       drive->hwif->atapi_output_bytes(drive, data, count);
+               else
+                       drive->hwif->atapi_input_bytes(drive, data, count);
                bvec_kunmap_irq(data, &flags);
 
                bcount -= count;
@@ -639,15 +335,18 @@ static void idefloppy_output_buffers (ide_drive_t *drive, idefloppy_pc_t *pc, un
 
        idefloppy_do_end_request(drive, 1, done >> 9);
 
-#if IDEFLOPPY_DEBUG_BUGS
        if (bcount) {
-               printk(KERN_ERR "%s: leftover data in idefloppy_output_buffers, bcount == %d\n", drive->name, bcount);
-               idefloppy_write_zeros(drive, bcount);
+               printk(KERN_ERR "%s: leftover data in %s, bcount == %d\n",
+                               drive->name, __func__, bcount);
+               if (direction)
+                       idefloppy_write_zeros(drive, bcount);
+               else
+                       idefloppy_discard_data(drive, bcount);
+
        }
-#endif
 }
 
-static void idefloppy_update_buffers (ide_drive_t *drive, idefloppy_pc_t *pc)
+static void idefloppy_update_buffers(ide_drive_t *drive, idefloppy_pc_t *pc)
 {
        struct request *rq = pc->rq;
        struct bio *bio = rq->bio;
@@ -657,11 +356,12 @@ static void idefloppy_update_buffers (ide_drive_t *drive, idefloppy_pc_t *pc)
 }
 
 /*
- *     idefloppy_queue_pc_head generates a new packet command request in front
- *     of the request queue, before the current request, so that it will be
- *     processed immediately, on the next pass through the driver.
+ * Generate a new packet command request in front of the request queue, before
+ * the current request so that it will be processed immediately, on the next
+ * pass through the driver.
  */
-static void idefloppy_queue_pc_head (ide_drive_t *drive,idefloppy_pc_t *pc,struct request *rq)
+static void idefloppy_queue_pc_head(ide_drive_t *drive, idefloppy_pc_t *pc,
+               struct request *rq)
 {
        struct ide_floppy_obj *floppy = drive->driver_data;
 
@@ -672,16 +372,16 @@ static void idefloppy_queue_pc_head (ide_drive_t *drive,idefloppy_pc_t *pc,struc
        (void) ide_do_drive_cmd(drive, rq, ide_preempt);
 }
 
-static idefloppy_pc_t *idefloppy_next_pc_storage (ide_drive_t *drive)
+static idefloppy_pc_t *idefloppy_next_pc_storage(ide_drive_t *drive)
 {
        idefloppy_floppy_t *floppy = drive->driver_data;
 
        if (floppy->pc_stack_index == IDEFLOPPY_PC_STACK)
-               floppy->pc_stack_index=0;
+               floppy->pc_stack_index = 0;
        return (&floppy->pc_stack[floppy->pc_stack_index++]);
 }
 
-static struct request *idefloppy_next_rq_storage (ide_drive_t *drive)
+static struct request *idefloppy_next_rq_storage(ide_drive_t *drive)
 {
        idefloppy_floppy_t *floppy = drive->driver_data;
 
@@ -690,60 +390,53 @@ static struct request *idefloppy_next_rq_storage (ide_drive_t *drive)
        return (&floppy->rq_stack[floppy->rq_stack_index++]);
 }
 
-/*
- *     idefloppy_analyze_error is called on each failed packet command retry
- *     to analyze the request sense.
- */
-static void idefloppy_analyze_error (ide_drive_t *drive,idefloppy_request_sense_result_t *result)
+static void idefloppy_request_sense_callback(ide_drive_t *drive)
 {
        idefloppy_floppy_t *floppy = drive->driver_data;
+       u8 *buf = floppy->pc->buffer;
 
-       floppy->sense_key = result->sense_key;
-       floppy->asc = result->asc;
-       floppy->ascq = result->ascq;
-       floppy->progress_indication = result->sksv[0] & 0x80 ?
-               (u16)get_unaligned((u16 *)(result->sksv+1)):0x10000;
-       if (floppy->failed_pc)
-               debug_log(KERN_INFO "ide-floppy: pc = %x, sense key = %x, "
-                       "asc = %x, ascq = %x\n", floppy->failed_pc->c[0],
-                       result->sense_key, result->asc, result->ascq);
-       else
-               debug_log(KERN_INFO "ide-floppy: sense key = %x, asc = %x, "
-                       "ascq = %x\n", result->sense_key,
-                       result->asc, result->ascq);
-}
+       debug_log("Reached %s\n", __func__);
 
-static void idefloppy_request_sense_callback (ide_drive_t *drive)
-{
-       idefloppy_floppy_t *floppy = drive->driver_data;
-
-       debug_log(KERN_INFO "ide-floppy: Reached %s\n", __FUNCTION__);
-       
        if (!floppy->pc->error) {
-               idefloppy_analyze_error(drive,(idefloppy_request_sense_result_t *) floppy->pc->buffer);
+               floppy->sense_key = buf[2] & 0x0F;
+               floppy->asc = buf[12];
+               floppy->ascq = buf[13];
+               floppy->progress_indication = buf[15] & 0x80 ?
+                       (u16)get_unaligned((u16 *)&buf[16]) : 0x10000;
+
+               if (floppy->failed_pc)
+                       debug_log("pc = %x, sense key = %x, asc = %x,"
+                                       " ascq = %x\n",
+                                       floppy->failed_pc->c[0],
+                                       floppy->sense_key,
+                                       floppy->asc,
+                                       floppy->ascq);
+               else
+                       debug_log("sense key = %x, asc = %x, ascq = %x\n",
+                                       floppy->sense_key,
+                                       floppy->asc,
+                                       floppy->ascq);
+
+
                idefloppy_do_end_request(drive, 1, 0);
        } else {
-               printk(KERN_ERR "Error in REQUEST SENSE itself - Aborting request!\n");
+               printk(KERN_ERR "Error in REQUEST SENSE itself - Aborting"
+                               " request!\n");
                idefloppy_do_end_request(drive, 0, 0);
        }
 }
 
-/*
- *     General packet command callback function.
- */
-static void idefloppy_pc_callback (ide_drive_t *drive)
+/* General packet command callback function. */
+static void idefloppy_pc_callback(ide_drive_t *drive)
 {
        idefloppy_floppy_t *floppy = drive->driver_data;
-       
-       debug_log(KERN_INFO "ide-floppy: Reached %s\n", __FUNCTION__);
+
+       debug_log("Reached %s\n", __func__);
 
        idefloppy_do_end_request(drive, floppy->pc->error ? 0 : 1, 0);
 }
 
-/*
- *     idefloppy_init_pc initializes a packet command.
- */
-static void idefloppy_init_pc (idefloppy_pc_t *pc)
+static void idefloppy_init_pc(idefloppy_pc_t *pc)
 {
        memset(pc->c, 0, 12);
        pc->retries = 0;
@@ -754,75 +447,75 @@ static void idefloppy_init_pc (idefloppy_pc_t *pc)
        pc->callback = &idefloppy_pc_callback;
 }
 
-static void idefloppy_create_request_sense_cmd (idefloppy_pc_t *pc)
+static void idefloppy_create_request_sense_cmd(idefloppy_pc_t *pc)
 {
-       idefloppy_init_pc(pc);  
-       pc->c[0] = IDEFLOPPY_REQUEST_SENSE_CMD;
+       idefloppy_init_pc(pc);
+       pc->c[0] = GPCMD_REQUEST_SENSE;
        pc->c[4] = 255;
        pc->request_transfer = 18;
        pc->callback = &idefloppy_request_sense_callback;
 }
 
 /*
- *     idefloppy_retry_pc is called when an error was detected during the
- *     last packet command. We queue a request sense packet command in
- *     the head of the request list.
+ * Called when an error was detected during the last packet command. We queue a
+ * request sense packet command in the head of the request list.
  */
-static void idefloppy_retry_pc (ide_drive_t *drive)
+static void idefloppy_retry_pc(ide_drive_t *drive)
 {
        idefloppy_pc_t *pc;
        struct request *rq;
 
-       (void)drive->hwif->INB(IDE_ERROR_REG);
+       (void)ide_read_error(drive);
        pc = idefloppy_next_pc_storage(drive);
        rq = idefloppy_next_rq_storage(drive);
        idefloppy_create_request_sense_cmd(pc);
        idefloppy_queue_pc_head(drive, pc, rq);
 }
 
-/*
- *     idefloppy_pc_intr is the usual interrupt handler which will be called
- *     during a packet command.
- */
+/* The usual interrupt handler called during a packet command. */
 static ide_startstop_t idefloppy_pc_intr (ide_drive_t *drive)
 {
        idefloppy_floppy_t *floppy = drive->driver_data;
        ide_hwif_t *hwif = drive->hwif;
        idefloppy_pc_t *pc = floppy->pc;
        struct request *rq = pc->rq;
+       xfer_func_t *xferfunc;
        unsigned int temp;
+       int dma_error = 0;
        u16 bcount;
        u8 stat, ireason;
 
-       debug_log(KERN_INFO "ide-floppy: Reached %s interrupt handler\n",
-               __FUNCTION__);
+       debug_log("Reached %s interrupt handler\n", __func__);
 
-       if (test_bit(PC_DMA_IN_PROGRESS, &pc->flags)) {
-               if (HWIF(drive)->ide_dma_end(drive)) {
-                       set_bit(PC_DMA_ERROR, &pc->flags);
+       if (pc->flags & PC_FLAG_DMA_IN_PROGRESS) {
+               dma_error = hwif->ide_dma_end(drive);
+               if (dma_error) {
+                       printk(KERN_ERR "%s: DMA %s error\n", drive->name,
+                                       rq_data_dir(rq) ? "write" : "read");
+                       pc->flags |= PC_FLAG_DMA_ERROR;
                } else {
                        pc->actually_transferred = pc->request_transfer;
                        idefloppy_update_buffers(drive, pc);
                }
-               debug_log(KERN_INFO "ide-floppy: DMA finished\n");
+               debug_log("DMA finished\n");
        }
 
        /* Clear the interrupt */
-       stat = drive->hwif->INB(IDE_STATUS_REG);
+       stat = ide_read_status(drive);
 
-       if ((stat & DRQ_STAT) == 0) {           /* No more interrupts */
-               debug_log(KERN_INFO "Packet command completed, %d bytes "
-                       "transferred\n", pc->actually_transferred);
-               clear_bit(PC_DMA_IN_PROGRESS, &pc->flags);
+       /* No more interrupts */
+       if ((stat & DRQ_STAT) == 0) {
+               debug_log("Packet command completed, %d bytes transferred\n",
+                               pc->actually_transferred);
+               pc->flags &= ~PC_FLAG_DMA_IN_PROGRESS;
 
                local_irq_enable_in_hardirq();
 
-               if ((stat & ERR_STAT) || test_bit(PC_DMA_ERROR, &pc->flags)) {
+               if ((stat & ERR_STAT) || (pc->flags & PC_FLAG_DMA_ERROR)) {
                        /* Error detected */
-                       debug_log(KERN_INFO "ide-floppy: %s: I/O error\n",
-                               drive->name);
+                       debug_log("%s: I/O error\n", drive->name);
                        rq->errors++;
-                       if (pc->c[0] == IDEFLOPPY_REQUEST_SENSE_CMD) {
+                       if (pc->c[0] == GPCMD_REQUEST_SENSE) {
                                printk(KERN_ERR "ide-floppy: I/O error in "
                                        "request sense command\n");
                                return ide_do_reset(drive);
@@ -840,7 +533,8 @@ static ide_startstop_t idefloppy_pc_intr (ide_drive_t *drive)
                return ide_stopped;
        }
 
-       if (test_and_clear_bit(PC_DMA_IN_PROGRESS, &pc->flags)) {
+       if (pc->flags & PC_FLAG_DMA_IN_PROGRESS) {
+               pc->flags &= ~PC_FLAG_DMA_IN_PROGRESS;
                printk(KERN_ERR "ide-floppy: The floppy wants to issue "
                        "more interrupts in DMA mode\n");
                ide_dma_off(drive);
@@ -854,10 +548,10 @@ static ide_startstop_t idefloppy_pc_intr (ide_drive_t *drive)
        ireason = hwif->INB(IDE_IREASON_REG);
 
        if (ireason & CD) {
-               printk(KERN_ERR "ide-floppy: CoD != 0 in idefloppy_pc_intr\n");
+               printk(KERN_ERR "ide-floppy: CoD != 0 in %s\n", __func__);
                return ide_do_reset(drive);
        }
-       if (((ireason & IO) == IO) == test_bit(PC_WRITING, &pc->flags)) {
+       if (((ireason & IO) == IO) == !!(pc->flags & PC_FLAG_WRITING)) {
                /* Hopefully, we will never get here */
                printk(KERN_ERR "ide-floppy: We wanted to %s, ",
                                (ireason & IO) ? "Write" : "Read");
@@ -865,7 +559,7 @@ static ide_startstop_t idefloppy_pc_intr (ide_drive_t *drive)
                                (ireason & IO) ? "Read" : "Write");
                return ide_do_reset(drive);
        }
-       if (!test_bit(PC_WRITING, &pc->flags)) {
+       if (!(pc->flags & PC_FLAG_WRITING)) {
                /* Reading - Check that we have enough space */
                temp = pc->actually_transferred + bcount;
                if (temp > pc->request_transfer) {
@@ -874,39 +568,34 @@ static ide_startstop_t idefloppy_pc_intr (ide_drive_t *drive)
                                        "to send us more data than expected "
                                        "- discarding data\n");
                                idefloppy_discard_data(drive, bcount);
-                               BUG_ON(HWGROUP(drive)->handler != NULL);
+
                                ide_set_handler(drive,
                                                &idefloppy_pc_intr,
                                                IDEFLOPPY_WAIT_CMD,
                                                NULL);
                                return ide_started;
                        }
-                       debug_log(KERN_NOTICE "ide-floppy: The floppy wants to "
-                               "send us more data than expected - "
-                               "allowing transfer\n");
+                       debug_log("The floppy wants to send us more data than"
+                                       " expected - allowing transfer\n");
                }
        }
-       if (test_bit(PC_WRITING, &pc->flags)) {
-               if (pc->buffer != NULL)
-                       /* Write the current buffer */
-                       hwif->atapi_output_bytes(drive, pc->current_position,
-                                                bcount);
-               else
-                       idefloppy_output_buffers(drive, pc, bcount);
-       } else {
-               if (pc->buffer != NULL)
-                       /* Read the current buffer */
-                       hwif->atapi_input_bytes(drive, pc->current_position,
-                                               bcount);
-               else
-                       idefloppy_input_buffers(drive, pc, bcount);
-       }
+       if (pc->flags & PC_FLAG_WRITING)
+               xferfunc = hwif->atapi_output_bytes;
+       else
+               xferfunc = hwif->atapi_input_bytes;
+
+       if (pc->buffer)
+               xferfunc(drive, pc->current_position, bcount);
+       else
+               ide_floppy_io_buffers(drive, pc, bcount,
+                                     !!(pc->flags & PC_FLAG_WRITING));
+
        /* Update the current position */
        pc->actually_transferred += bcount;
        pc->current_position += bcount;
 
-       BUG_ON(HWGROUP(drive)->handler != NULL);
-       ide_set_handler(drive, &idefloppy_pc_intr, IDEFLOPPY_WAIT_CMD, NULL);           /* And set the interrupt handler again */
+       /* And set the interrupt handler again */
+       ide_set_handler(drive, &idefloppy_pc_intr, IDEFLOPPY_WAIT_CMD, NULL);
        return ide_started;
 }
 
@@ -915,7 +604,7 @@ static ide_startstop_t idefloppy_pc_intr (ide_drive_t *drive)
  * It fails at high speeds on the Iomega ZIP drive, so there's a slower version
  * for that drive below. The algorithm is chosen based on drive type
  */
-static ide_startstop_t idefloppy_transfer_pc (ide_drive_t *drive)
+static ide_startstop_t idefloppy_transfer_pc(ide_drive_t *drive)
 {
        ide_startstop_t startstop;
        idefloppy_floppy_t *floppy = drive->driver_data;
@@ -932,7 +621,7 @@ static ide_startstop_t idefloppy_transfer_pc (ide_drive_t *drive)
                                "issuing a packet command\n");
                return ide_do_reset(drive);
        }
-       BUG_ON(HWGROUP(drive)->handler != NULL);
+
        /* Set the interrupt routine */
        ide_set_handler(drive, &idefloppy_pc_intr, IDEFLOPPY_WAIT_CMD, NULL);
        /* Send the actual packet */
@@ -942,18 +631,16 @@ static ide_startstop_t idefloppy_transfer_pc (ide_drive_t *drive)
 
 
 /*
- * What we have here is a classic case of a top half / bottom half
- * interrupt service routine. In interrupt mode, the device sends
- * an interrupt to signal it's ready to receive a packet. However,
- * we need to delay about 2-3 ticks before issuing the packet or we
- * gets in trouble.
+ * What we have here is a classic case of a top half / bottom half interrupt
+ * service routine. In interrupt mode, the device sends an interrupt to signal
+ * that it is ready to receive a packet. However, we need to delay about 2-3
+ * ticks before issuing the packet or we gets in trouble.
  *
- * So, follow carefully. transfer_pc1 is called as an interrupt (or
- * directly). In either case, when the device says it's ready for a 
- * packet, we schedule the packet transfer to occur about 2-3 ticks
- * later in transfer_pc2.
+ * So, follow carefully. transfer_pc1 is called as an interrupt (or directly).
+ * In either case, when the device says it's ready for a packet, we schedule
+ * the packet transfer to occur about 2-3 ticks later in transfer_pc2.
  */
-static int idefloppy_transfer_pc2 (ide_drive_t *drive)
+static int idefloppy_transfer_pc2(ide_drive_t *drive)
 {
        idefloppy_floppy_t *floppy = drive->driver_data;
 
@@ -963,7 +650,7 @@ static int idefloppy_transfer_pc2 (ide_drive_t *drive)
        return IDEFLOPPY_WAIT_CMD;
 }
 
-static ide_startstop_t idefloppy_transfer_pc1 (ide_drive_t *drive)
+static ide_startstop_t idefloppy_transfer_pc1(ide_drive_t *drive)
 {
        idefloppy_floppy_t *floppy = drive->driver_data;
        ide_startstop_t startstop;
@@ -980,7 +667,7 @@ static ide_startstop_t idefloppy_transfer_pc1 (ide_drive_t *drive)
                                "while issuing a packet command\n");
                return ide_do_reset(drive);
        }
-       /* 
+       /*
         * The following delay solves a problem with ATAPI Zip 100 drives
         * where the Busy flag was apparently being deasserted before the
         * unit was ready to receive data. This was happening on a
@@ -988,32 +675,30 @@ static ide_startstop_t idefloppy_transfer_pc1 (ide_drive_t *drive)
         * 40 and 50msec work well. idefloppy_pc_intr will not be actually
         * used until after the packet is moved in about 50 msec.
         */
-       BUG_ON(HWGROUP(drive)->handler != NULL);
-       ide_set_handler(drive, 
-         &idefloppy_pc_intr,           /* service routine for packet command */
-         floppy->ticks,                /* wait this long before "failing" */
-         &idefloppy_transfer_pc2);     /* fail == transfer_pc2 */
+
+       ide_set_handler(drive, &idefloppy_pc_intr, floppy->ticks,
+                       &idefloppy_transfer_pc2);
        return ide_started;
 }
 
-/**
- * idefloppy_should_report_error()
- *
- * Supresses error messages resulting from Medium not present
- */
-static inline int idefloppy_should_report_error(idefloppy_floppy_t *floppy)
+static void ide_floppy_report_error(idefloppy_floppy_t *floppy,
+                                   idefloppy_pc_t *pc)
 {
+       /* supress error messages resulting from Medium not present */
        if (floppy->sense_key == 0x02 &&
            floppy->asc       == 0x3a &&
            floppy->ascq      == 0x00)
-               return 0;
-       return 1;
+               return;
+
+       printk(KERN_ERR "ide-floppy: %s: I/O error, pc = %2x, key = %2x, "
+                       "asc = %2x, ascq = %2x\n",
+                       floppy->drive->name, pc->c[0], floppy->sense_key,
+                       floppy->asc, floppy->ascq);
+
 }
 
-/*
- *     Issue a packet command
- */
-static ide_startstop_t idefloppy_issue_pc (ide_drive_t *drive, idefloppy_pc_t *pc)
+static ide_startstop_t idefloppy_issue_pc(ide_drive_t *drive,
+               idefloppy_pc_t *pc)
 {
        idefloppy_floppy_t *floppy = drive->driver_data;
        ide_hwif_t *hwif = drive->hwif;
@@ -1022,36 +707,23 @@ static ide_startstop_t idefloppy_issue_pc (ide_drive_t *drive, idefloppy_pc_t *p
        u8 dma;
 
        if (floppy->failed_pc == NULL &&
-           pc->c[0] != IDEFLOPPY_REQUEST_SENSE_CMD)
+           pc->c[0] != GPCMD_REQUEST_SENSE)
                floppy->failed_pc = pc;
        /* Set the current packet command */
        floppy->pc = pc;
 
-       if (pc->retries > IDEFLOPPY_MAX_PC_RETRIES ||
-           test_bit(PC_ABORT, &pc->flags)) {
-               /*
-                *      We will "abort" retrying a packet command in case
-                *      a legitimate error code was received.
-                */
-               if (!test_bit(PC_ABORT, &pc->flags)) {
-                       if (!test_bit(PC_SUPPRESS_ERROR, &pc->flags)) {
-                               if (idefloppy_should_report_error(floppy))
-                                       printk(KERN_ERR "ide-floppy: %s: I/O error, "
-                                              "pc = %2x, key = %2x, "
-                                              "asc = %2x, ascq = %2x\n",
-                                              drive->name, pc->c[0],
-                                              floppy->sense_key,
-                                              floppy->asc, floppy->ascq);
-                       }
-                       /* Giving up */
-                       pc->error = IDEFLOPPY_ERROR_GENERAL;
-               }
+       if (pc->retries > IDEFLOPPY_MAX_PC_RETRIES) {
+               if (!(pc->flags & PC_FLAG_SUPPRESS_ERROR))
+                       ide_floppy_report_error(floppy, pc);
+               /* Giving up */
+               pc->error = IDEFLOPPY_ERROR_GENERAL;
+
                floppy->failed_pc = NULL;
                pc->callback(drive);
                return ide_stopped;
        }
 
-       debug_log(KERN_INFO "Retry number - %d\n",pc->retries);
+       debug_log("Retry number - %d\n", pc->retries);
 
        pc->retries++;
        /* We haven't transferred any data yet */
@@ -1059,24 +731,26 @@ static ide_startstop_t idefloppy_issue_pc (ide_drive_t *drive, idefloppy_pc_t *p
        pc->current_position = pc->buffer;
        bcount = min(pc->request_transfer, 63 * 1024);
 
-       if (test_and_clear_bit(PC_DMA_ERROR, &pc->flags))
+       if (pc->flags & PC_FLAG_DMA_ERROR) {
+               pc->flags &= ~PC_FLAG_DMA_ERROR;
                ide_dma_off(drive);
-
+       }
        dma = 0;
 
-       if (test_bit(PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma)
+       if ((pc->flags & PC_FLAG_DMA_RECOMMENDED) && drive->using_dma)
                dma = !hwif->dma_setup(drive);
 
        ide_pktcmd_tf_load(drive, IDE_TFLAG_NO_SELECT_MASK |
                           IDE_TFLAG_OUT_DEVICE, bcount, dma);
 
-       if (dma) {      /* Begin DMA, if necessary */
-               set_bit(PC_DMA_IN_PROGRESS, &pc->flags);
+       if (dma) {
+               /* Begin DMA, if necessary */
+               pc->flags |= PC_FLAG_DMA_IN_PROGRESS;
                hwif->dma_start(drive);
        }
 
        /* Can we transfer the packet when we get the interrupt or wait? */
-       if (test_bit(IDEFLOPPY_ZIP_DRIVE, &floppy->flags)) {
+       if (floppy->flags & IDEFLOPPY_FLAG_ZIP_DRIVE) {
                /* wait */
                pkt_xfer_routine = &idefloppy_transfer_pc1;
        } else {
@@ -1084,7 +758,7 @@ static ide_startstop_t idefloppy_issue_pc (ide_drive_t *drive, idefloppy_pc_t *p
                pkt_xfer_routine = &idefloppy_transfer_pc;
        }
        
-       if (test_bit (IDEFLOPPY_DRQ_INTERRUPT, &floppy->flags)) {
+       if (floppy->flags & IDEFLOPPY_FLAG_DRQ_INTERRUPT) {
                /* Issue the packet command */
                ide_execute_command(drive, WIN_PACKETCMD,
                                pkt_xfer_routine,
@@ -1098,38 +772,37 @@ static ide_startstop_t idefloppy_issue_pc (ide_drive_t *drive, idefloppy_pc_t *p
        }
 }
 
-static void idefloppy_rw_callback (ide_drive_t *drive)
+static void idefloppy_rw_callback(ide_drive_t *drive)
 {
-       debug_log(KERN_INFO "ide-floppy: Reached idefloppy_rw_callback\n");
+       debug_log("Reached %s\n", __func__);
 
        idefloppy_do_end_request(drive, 1, 0);
        return;
 }
 
-static void idefloppy_create_prevent_cmd (idefloppy_pc_t *pc, int prevent)
+static void idefloppy_create_prevent_cmd(idefloppy_pc_t *pc, int prevent)
 {
-       debug_log(KERN_INFO "ide-floppy: creating prevent removal command, "
-               "prevent = %d\n", prevent);
+       debug_log("creating prevent removal command, prevent = %d\n", prevent);
 
        idefloppy_init_pc(pc);
-       pc->c[0] = IDEFLOPPY_PREVENT_REMOVAL_CMD;
+       pc->c[0] = GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL;
        pc->c[4] = prevent;
 }
 
-static void idefloppy_create_read_capacity_cmd (idefloppy_pc_t *pc)
+static void idefloppy_create_read_capacity_cmd(idefloppy_pc_t *pc)
 {
        idefloppy_init_pc(pc);
-       pc->c[0] = IDEFLOPPY_READ_CAPACITY_CMD;
+       pc->c[0] = GPCMD_READ_FORMAT_CAPACITIES;
        pc->c[7] = 255;
        pc->c[8] = 255;
        pc->request_transfer = 255;
 }
 
-static void idefloppy_create_format_unit_cmd (idefloppy_pc_t *pc, int b, int l,
+static void idefloppy_create_format_unit_cmd(idefloppy_pc_t *pc, int b, int l,
                                              int flags)
 {
        idefloppy_init_pc(pc);
-       pc->c[0] = IDEFLOPPY_FORMAT_UNIT_CMD;
+       pc->c[0] = GPCMD_FORMAT_UNIT;
        pc->c[1] = 0x17;
 
        memset(pc->buffer, 0, 12);
@@ -1140,83 +813,79 @@ static void idefloppy_create_format_unit_cmd (idefloppy_pc_t *pc, int b, int l,
                pc->buffer[1] ^= 0x20;          /* ... turn off DCRT bit */
        pc->buffer[3] = 8;
 
-       put_unaligned(htonl(b), (unsigned int *)(&pc->buffer[4]));
-       put_unaligned(htonl(l), (unsigned int *)(&pc->buffer[8]));
-       pc->buffer_size=12;
-       set_bit(PC_WRITING, &pc->flags);
+       put_unaligned(cpu_to_be32(b), (unsigned int *)(&pc->buffer[4]));
+       put_unaligned(cpu_to_be32(l), (unsigned int *)(&pc->buffer[8]));
+       pc->buffer_size = 12;
+       pc->flags |= PC_FLAG_WRITING;
 }
 
-/*
- *     A mode sense command is used to "sense" floppy parameters.
- */
-static void idefloppy_create_mode_sense_cmd (idefloppy_pc_t *pc, u8 page_code, u8 type)
+/* A mode sense command is used to "sense" floppy parameters. */
+static void idefloppy_create_mode_sense_cmd(idefloppy_pc_t *pc, u8 page_code,
+               u8 type)
 {
-       u16 length = sizeof(idefloppy_mode_parameter_header_t);
-       
+       u16 length = 8; /* sizeof(Mode Parameter Header) = 8 Bytes */
+
        idefloppy_init_pc(pc);
-       pc->c[0] = IDEFLOPPY_MODE_SENSE_CMD;
+       pc->c[0] = GPCMD_MODE_SENSE_10;
        pc->c[1] = 0;
        pc->c[2] = page_code + (type << 6);
 
        switch (page_code) {
-               case IDEFLOPPY_CAPABILITIES_PAGE:
-                       length += 12;
-                       break;
-               case IDEFLOPPY_FLEXIBLE_DISK_PAGE:
-                       length += 32;
-                       break;
-               default:
-                       printk(KERN_ERR "ide-floppy: unsupported page code "
+       case IDEFLOPPY_CAPABILITIES_PAGE:
+               length += 12;
+               break;
+       case IDEFLOPPY_FLEXIBLE_DISK_PAGE:
+               length += 32;
+               break;
+       default:
+               printk(KERN_ERR "ide-floppy: unsupported page code "
                                "in create_mode_sense_cmd\n");
        }
-       put_unaligned(htons(length), (u16 *) &pc->c[7]);
+       put_unaligned(cpu_to_be16(length), (u16 *) &pc->c[7]);
        pc->request_transfer = length;
 }
 
-static void idefloppy_create_start_stop_cmd (idefloppy_pc_t *pc, int start)
+static void idefloppy_create_start_stop_cmd(idefloppy_pc_t *pc, int start)
 {
        idefloppy_init_pc(pc);
-       pc->c[0] = IDEFLOPPY_START_STOP_CMD;
+       pc->c[0] = GPCMD_START_STOP_UNIT;
        pc->c[4] = start;
 }
 
 static void idefloppy_create_test_unit_ready_cmd(idefloppy_pc_t *pc)
 {
        idefloppy_init_pc(pc);
-       pc->c[0] = IDEFLOPPY_TEST_UNIT_READY_CMD;
+       pc->c[0] = GPCMD_TEST_UNIT_READY;
 }
 
-static void idefloppy_create_rw_cmd (idefloppy_floppy_t *floppy, idefloppy_pc_t *pc, struct request *rq, unsigned long sector)
+static void idefloppy_create_rw_cmd(idefloppy_floppy_t *floppy,
+                                   idefloppy_pc_t *pc, struct request *rq,
+                                   unsigned long sector)
 {
        int block = sector / floppy->bs_factor;
        int blocks = rq->nr_sectors / floppy->bs_factor;
        int cmd = rq_data_dir(rq);
 
-       debug_log("create_rw1%d_cmd: block == %d, blocks == %d\n",
-               2 * test_bit (IDEFLOPPY_USE_READ12, &floppy->flags),
+       debug_log("create_rw10_cmd: block == %d, blocks == %d\n",
                block, blocks);
 
        idefloppy_init_pc(pc);
-       if (test_bit(IDEFLOPPY_USE_READ12, &floppy->flags)) {
-               pc->c[0] = cmd == READ ? IDEFLOPPY_READ12_CMD : IDEFLOPPY_WRITE12_CMD;
-               put_unaligned(htonl(blocks), (unsigned int *) &pc->c[6]);
-       } else {
-               pc->c[0] = cmd == READ ? IDEFLOPPY_READ10_CMD : IDEFLOPPY_WRITE10_CMD;
-               put_unaligned(htons(blocks), (unsigned short *) &pc->c[7]);
-       }
-       put_unaligned(htonl(block), (unsigned int *) &pc->c[2]);
+       pc->c[0] = cmd == READ ? GPCMD_READ_10 : GPCMD_WRITE_10;
+       put_unaligned(cpu_to_be16(blocks), (unsigned short *)&pc->c[7]);
+       put_unaligned(cpu_to_be32(block), (unsigned int *) &pc->c[2]);
+
        pc->callback = &idefloppy_rw_callback;
        pc->rq = rq;
        pc->b_count = cmd == READ ? 0 : rq->bio->bi_size;
        if (rq->cmd_flags & REQ_RW)
-               set_bit(PC_WRITING, &pc->flags);
+               pc->flags |= PC_FLAG_WRITING;
        pc->buffer = NULL;
        pc->request_transfer = pc->buffer_size = blocks * floppy->block_size;
-       set_bit(PC_DMA_RECOMMENDED, &pc->flags);
+       pc->flags |= PC_FLAG_DMA_RECOMMENDED;
 }
 
-static void
-idefloppy_blockpc_cmd(idefloppy_floppy_t *floppy, idefloppy_pc_t *pc, struct request *rq)
+static void idefloppy_blockpc_cmd(idefloppy_floppy_t *floppy,
+               idefloppy_pc_t *pc, struct request *rq)
 {
        idefloppy_init_pc(pc);
        pc->callback = &idefloppy_rw_callback;
@@ -1224,11 +893,10 @@ idefloppy_blockpc_cmd(idefloppy_floppy_t *floppy, idefloppy_pc_t *pc, struct req
        pc->rq = rq;
        pc->b_count = rq->data_len;
        if (rq->data_len && rq_data_dir(rq) == WRITE)
-               set_bit(PC_WRITING, &pc->flags);
+               pc->flags |= PC_FLAG_WRITING;
        pc->buffer = rq->data;
        if (rq->bio)
-               set_bit(PC_DMA_RECOMMENDED, &pc->flags);
-               
+               pc->flags |= PC_FLAG_DMA_RECOMMENDED;
        /*
         * possibly problematic, doesn't look like ide-floppy correctly
         * handled scattered requests if dma fails...
@@ -1236,30 +904,23 @@ idefloppy_blockpc_cmd(idefloppy_floppy_t *floppy, idefloppy_pc_t *pc, struct req
        pc->request_transfer = pc->buffer_size = rq->data_len;
 }
 
-/*
- *     idefloppy_do_request is our request handling function.  
- */
-static ide_startstop_t idefloppy_do_request (ide_drive_t *drive, struct request *rq, sector_t block_s)
+static ide_startstop_t idefloppy_do_request(ide_drive_t *drive,
+               struct request *rq, sector_t block_s)
 {
        idefloppy_floppy_t *floppy = drive->driver_data;
        idefloppy_pc_t *pc;
        unsigned long block = (unsigned long)block_s;
 
-       debug_log(KERN_INFO "dev: %s, flags: %lx, errors: %d\n",
+       debug_log("dev: %s, cmd_type: %x, errors: %d\n",
                        rq->rq_disk ? rq->rq_disk->disk_name : "?",
-                       rq->flags, rq->errors);
-       debug_log(KERN_INFO "sector: %ld, nr_sectors: %ld, "
+                       rq->cmd_type, rq->errors);
+       debug_log("sector: %ld, nr_sectors: %ld, "
                        "current_nr_sectors: %d\n", (long)rq->sector,
                        rq->nr_sectors, rq->current_nr_sectors);
 
        if (rq->errors >= ERROR_MAX) {
-               if (floppy->failed_pc != NULL) {
-                       if (idefloppy_should_report_error(floppy))
-                               printk(KERN_ERR "ide-floppy: %s: I/O error, pc = %2x,"
-                                      " key = %2x, asc = %2x, ascq = %2x\n",
-                                      drive->name, floppy->failed_pc->c[0],
-                                      floppy->sense_key, floppy->asc, floppy->ascq);
-               }
+               if (floppy->failed_pc)
+                       ide_floppy_report_error(floppy, floppy->failed_pc);
                else
                        printk(KERN_ERR "ide-floppy: %s: I/O error\n",
                                drive->name);
@@ -1269,8 +930,8 @@ static ide_startstop_t idefloppy_do_request (ide_drive_t *drive, struct request
        if (blk_fs_request(rq)) {
                if (((long)rq->sector % floppy->bs_factor) ||
                    (rq->nr_sectors % floppy->bs_factor)) {
-                       printk("%s: unsupported r/w request size\n",
-                               drive->name);
+                       printk(KERN_ERR "%s: unsupported r/w request size\n",
+                                       drive->name);
                        idefloppy_do_end_request(drive, 0, 0);
                        return ide_stopped;
                }
@@ -1293,15 +954,15 @@ static ide_startstop_t idefloppy_do_request (ide_drive_t *drive, struct request
 }
 
 /*
- *     idefloppy_queue_pc_tail adds a special packet command request to the
- *     tail of the request queue, and waits for it to be serviced.
+ * Add a special packet command request to the tail of the request queue,
+ * and wait for it to be serviced.
  */
-static int idefloppy_queue_pc_tail (ide_drive_t *drive,idefloppy_pc_t *pc)
+static int idefloppy_queue_pc_tail(ide_drive_t *drive, idefloppy_pc_t *pc)
 {
        struct ide_floppy_obj *floppy = drive->driver_data;
        struct request rq;
 
-       ide_init_drive_cmd (&rq);
+       ide_init_drive_cmd(&rq);
        rq.buffer = (char *) pc;
        rq.cmd_type = REQ_TYPE_SPECIAL;
        rq.rq_disk = floppy->disk;
@@ -1310,88 +971,90 @@ static int idefloppy_queue_pc_tail (ide_drive_t *drive,idefloppy_pc_t *pc)
 }
 
 /*
- *     Look at the flexible disk page parameters. We will ignore the CHS
- *     capacity parameters and use the LBA parameters instead.
+ * Look at the flexible disk page parameters. We ignore the CHS capacity
+ * parameters and use the LBA parameters instead.
  */
-static int idefloppy_get_flexible_disk_page (ide_drive_t *drive)
+static int ide_floppy_get_flexible_disk_page(ide_drive_t *drive)
 {
        idefloppy_floppy_t *floppy = drive->driver_data;
        idefloppy_pc_t pc;
-       idefloppy_mode_parameter_header_t *header;
-       idefloppy_flexible_disk_page_t *page;
+       u8 *page;
        int capacity, lba_capacity;
+       u16 transfer_rate, sector_size, cyls, rpm;
+       u8 heads, sectors;
 
-       idefloppy_create_mode_sense_cmd(&pc, IDEFLOPPY_FLEXIBLE_DISK_PAGE, MODE_SENSE_CURRENT);
-       if (idefloppy_queue_pc_tail(drive,&pc)) {
-               printk(KERN_ERR "ide-floppy: Can't get flexible disk "
-                       "page parameters\n");
+       idefloppy_create_mode_sense_cmd(&pc, IDEFLOPPY_FLEXIBLE_DISK_PAGE,
+                                       MODE_SENSE_CURRENT);
+
+       if (idefloppy_queue_pc_tail(drive, &pc)) {
+               printk(KERN_ERR "ide-floppy: Can't get flexible disk page"
+                               " parameters\n");
                return 1;
        }
-       header = (idefloppy_mode_parameter_header_t *) pc.buffer;
-       floppy->wp = header->wp;
+       floppy->wp = !!(pc.buffer[3] & 0x80);
        set_disk_ro(floppy->disk, floppy->wp);
-       page = (idefloppy_flexible_disk_page_t *) (header + 1);
-
-       page->transfer_rate = ntohs(page->transfer_rate);
-       page->sector_size = ntohs(page->sector_size);
-       page->cyls = ntohs(page->cyls);
-       page->rpm = ntohs(page->rpm);
-       capacity = page->cyls * page->heads * page->sectors * page->sector_size;
-       if (memcmp (page, &floppy->flexible_disk_page, sizeof (idefloppy_flexible_disk_page_t)))
+       page = &pc.buffer[8];
+
+       transfer_rate = be16_to_cpu(*(u16 *)&pc.buffer[8 + 2]);
+       sector_size   = be16_to_cpu(*(u16 *)&pc.buffer[8 + 6]);
+       cyls          = be16_to_cpu(*(u16 *)&pc.buffer[8 + 8]);
+       rpm           = be16_to_cpu(*(u16 *)&pc.buffer[8 + 28]);
+       heads         = pc.buffer[8 + 4];
+       sectors       = pc.buffer[8 + 5];
+
+       capacity = cyls * heads * sectors * sector_size;
+
+       if (memcmp(page, &floppy->flexible_disk_page, 32))
                printk(KERN_INFO "%s: %dkB, %d/%d/%d CHS, %d kBps, "
                                "%d sector size, %d rpm\n",
-                       drive->name, capacity / 1024, page->cyls,
-                       page->heads, page->sectors,
-                       page->transfer_rate / 8, page->sector_size, page->rpm);
-
-       floppy->flexible_disk_page = *page;
-       drive->bios_cyl = page->cyls;
-       drive->bios_head = page->heads;
-       drive->bios_sect = page->sectors;
+                               drive->name, capacity / 1024, cyls, heads,
+                               sectors, transfer_rate / 8, sector_size, rpm);
+
+       memcpy(&floppy->flexible_disk_page, page, 32);
+       drive->bios_cyl = cyls;
+       drive->bios_head = heads;
+       drive->bios_sect = sectors;
        lba_capacity = floppy->blocks * floppy->block_size;
+
        if (capacity < lba_capacity) {
                printk(KERN_NOTICE "%s: The disk reports a capacity of %d "
                        "bytes, but the drive only handles %d\n",
                        drive->name, lba_capacity, capacity);
-               floppy->blocks = floppy->block_size ? capacity / floppy->block_size : 0;
+               floppy->blocks = floppy->block_size ?
+                       capacity / floppy->block_size : 0;
        }
        return 0;
 }
 
-static int idefloppy_get_capability_page(ide_drive_t *drive)
+static int idefloppy_get_sfrp_bit(ide_drive_t *drive)
 {
        idefloppy_floppy_t *floppy = drive->driver_data;
        idefloppy_pc_t pc;
-       idefloppy_mode_parameter_header_t *header;
-       idefloppy_capabilities_page_t *page;
 
        floppy->srfp = 0;
        idefloppy_create_mode_sense_cmd(&pc, IDEFLOPPY_CAPABILITIES_PAGE,
                                                 MODE_SENSE_CURRENT);
 
-       set_bit(PC_SUPPRESS_ERROR, &pc.flags);
-       if (idefloppy_queue_pc_tail(drive,&pc)) {
+       pc.flags |= PC_FLAG_SUPPRESS_ERROR;
+       if (idefloppy_queue_pc_tail(drive, &pc))
                return 1;
-       }
 
-       header = (idefloppy_mode_parameter_header_t *) pc.buffer;
-       page= (idefloppy_capabilities_page_t *)(header+1);
-       floppy->srfp = page->srfp;
+       floppy->srfp = pc.buffer[8 + 2] & 0x40;
        return (0);
 }
 
 /*
- *     Determine if a media is present in the floppy drive, and if so,
- *     its LBA capacity.
+ * Determine if a media is present in the floppy drive, and if so, its LBA
+ * capacity.
  */
-static int idefloppy_get_capacity (ide_drive_t *drive)
+static int ide_floppy_get_capacity(ide_drive_t *drive)
 {
        idefloppy_floppy_t *floppy = drive->driver_data;
        idefloppy_pc_t pc;
-       idefloppy_capacity_header_t *header;
-       idefloppy_capacity_descriptor_t *descriptor;
-       int i, descriptors, rc = 1, blocks, length;
-       
+       u8 *cap_desc;
+       u8 header_len, desc_cnt;
+       int i, rc = 1, blocks, length;
+
        drive->bios_cyl = 0;
        drive->bios_head = drive->bios_sect = 0;
        floppy->blocks = 0;
@@ -1403,44 +1066,55 @@ static int idefloppy_get_capacity (ide_drive_t *drive)
                printk(KERN_ERR "ide-floppy: Can't get floppy parameters\n");
                return 1;
        }
-       header = (idefloppy_capacity_header_t *) pc.buffer;
-       descriptors = header->length / sizeof(idefloppy_capacity_descriptor_t);
-       descriptor = (idefloppy_capacity_descriptor_t *) (header + 1);
+       header_len = pc.buffer[3];
+       cap_desc = &pc.buffer[4];
+       desc_cnt = header_len / 8; /* capacity descriptor of 8 bytes */
+
+       for (i = 0; i < desc_cnt; i++) {
+               unsigned int desc_start = 4 + i*8;
 
-       for (i = 0; i < descriptors; i++, descriptor++) {
-               blocks = descriptor->blocks = ntohl(descriptor->blocks);
-               length = descriptor->length = ntohs(descriptor->length);
+               blocks = be32_to_cpu(*(u32 *)&pc.buffer[desc_start]);
+               length = be16_to_cpu(*(u16 *)&pc.buffer[desc_start + 6]);
 
-               if (!i) 
-               {
-               switch (descriptor->dc) {
+               debug_log("Descriptor %d: %dkB, %d blocks, %d sector size\n",
+                               i, blocks * length / 1024, blocks, length);
+
+               if (i)
+                       continue;
+               /*
+                * the code below is valid only for the 1st descriptor, ie i=0
+                */
+
+               switch (pc.buffer[desc_start + 4] & 0x03) {
                /* Clik! drive returns this instead of CAPACITY_CURRENT */
                case CAPACITY_UNFORMATTED:
-                       if (!test_bit(IDEFLOPPY_CLIK_DRIVE, &floppy->flags))
-                                /*
+                       if (!(floppy->flags & IDEFLOPPY_FLAG_CLIK_DRIVE))
+                               /*
                                 * If it is not a clik drive, break out
                                 * (maintains previous driver behaviour)
                                 */
                                break;
                case CAPACITY_CURRENT:
                        /* Normal Zip/LS-120 disks */
-                       if (memcmp(descriptor, &floppy->capacity, sizeof (idefloppy_capacity_descriptor_t)))
+                       if (memcmp(cap_desc, &floppy->cap_desc, 8))
                                printk(KERN_INFO "%s: %dkB, %d blocks, %d "
                                        "sector size\n", drive->name,
                                        blocks * length / 1024, blocks, length);
-                       floppy->capacity = *descriptor;
+                       memcpy(&floppy->cap_desc, cap_desc, 8);
+
                        if (!length || length % 512) {
                                printk(KERN_NOTICE "%s: %d bytes block size "
                                        "not supported\n", drive->name, length);
                        } else {
-                                floppy->blocks = blocks;
-                                floppy->block_size = length;
-                                if ((floppy->bs_factor = length / 512) != 1)
-                                        printk(KERN_NOTICE "%s: warning: non "
+                               floppy->blocks = blocks;
+                               floppy->block_size = length;
+                               floppy->bs_factor = length / 512;
+                               if (floppy->bs_factor != 1)
+                                       printk(KERN_NOTICE "%s: warning: non "
                                                "512 bytes block size not "
                                                "fully supported\n",
                                                drive->name);
-                                rc = 0;
+                               rc = 0;
                        }
                        break;
                case CAPACITY_NO_CARTRIDGE:
@@ -1455,54 +1129,42 @@ static int idefloppy_get_capacity (ide_drive_t *drive)
                                "in drive\n", drive->name);
                        break;
                }
-               }
-               if (!i) {
-                       debug_log( "Descriptor 0 Code: %d\n",
-                               descriptor->dc);
-               }
-               debug_log( "Descriptor %d: %dkB, %d blocks, %d "
-                       "sector size\n", i, blocks * length / 1024, blocks,
-                       length);
+               debug_log("Descriptor 0 Code: %d\n",
+                         pc.buffer[desc_start + 4] & 0x03);
        }
 
        /* Clik! disk does not support get_flexible_disk_page */
-        if (!test_bit(IDEFLOPPY_CLIK_DRIVE, &floppy->flags)) {
-               (void) idefloppy_get_flexible_disk_page(drive);
-       }
+       if (!(floppy->flags & IDEFLOPPY_FLAG_CLIK_DRIVE))
+               (void) ide_floppy_get_flexible_disk_page(drive);
 
        set_capacity(floppy->disk, floppy->blocks * floppy->bs_factor);
        return rc;
 }
 
 /*
-** Obtain the list of formattable capacities.
-** Very similar to idefloppy_get_capacity, except that we push the capacity
-** descriptors to userland, instead of our own structures.
-**
-** Userland gives us the following structure:
-**
-** struct idefloppy_format_capacities {
-**        int nformats;
-**        struct {
-**                int nblocks;
-**                int blocksize;
-**                } formats[];
-**        } ;
-**
-** userland initializes nformats to the number of allocated formats[]
-** records.  On exit we set nformats to the number of records we've
-** actually initialized.
-**
-*/
-
-static int idefloppy_get_format_capacities(ide_drive_t *drive, int __user *arg)
+ * Obtain the list of formattable capacities.
+ * Very similar to ide_floppy_get_capacity, except that we push the capacity
+ * descriptors to userland, instead of our own structures.
+ *
+ * Userland gives us the following structure:
+ *
+ * struct idefloppy_format_capacities {
+ *     int nformats;
+ *     struct {
+ *             int nblocks;
+ *             int blocksize;
+ *     } formats[];
+ * };
+ *
+ * userland initializes nformats to the number of allocated formats[] records.
+ * On exit we set nformats to the number of records we've actually initialized.
+ */
+
+static int ide_floppy_get_format_capacities(ide_drive_t *drive, int __user *arg)
 {
-        idefloppy_pc_t pc;
-       idefloppy_capacity_header_t *header;
-        idefloppy_capacity_descriptor_t *descriptor;
-       int i, descriptors, blocks, length;
-       int u_array_size;
-       int u_index;
+       idefloppy_pc_t pc;
+       u8 header_len, desc_cnt;
+       int i, blocks, length, u_array_size, u_index;
        int __user *argp;
 
        if (get_user(u_array_size, arg))
@@ -1514,30 +1176,27 @@ static int idefloppy_get_format_capacities(ide_drive_t *drive, int __user *arg)
        idefloppy_create_read_capacity_cmd(&pc);
        if (idefloppy_queue_pc_tail(drive, &pc)) {
                printk(KERN_ERR "ide-floppy: Can't get floppy parameters\n");
-                return (-EIO);
-        }
-        header = (idefloppy_capacity_header_t *) pc.buffer;
-        descriptors = header->length /
-               sizeof(idefloppy_capacity_descriptor_t);
-       descriptor = (idefloppy_capacity_descriptor_t *) (header + 1);
+               return (-EIO);
+       }
+       header_len = pc.buffer[3];
+       desc_cnt = header_len / 8; /* capacity descriptor of 8 bytes */
 
        u_index = 0;
        argp = arg + 1;
 
        /*
-       ** We always skip the first capacity descriptor.  That's the
-       ** current capacity.  We are interested in the remaining descriptors,
-       ** the formattable capacities.
-       */
+        * We always skip the first capacity descriptor.  That's the current
+        * capacity.  We are interested in the remaining descriptors, the
+        * formattable capacities.
+        */
+       for (i = 1; i < desc_cnt; i++) {
+               unsigned int desc_start = 4 + i*8;
 
-       for (i=0; i<descriptors; i++, descriptor++) {
                if (u_index >= u_array_size)
                        break;  /* User-supplied buffer too small */
-               if (i == 0)
-                       continue;       /* Skip the first descriptor */
 
-               blocks = ntohl(descriptor->blocks);
-               length = ntohs(descriptor->length);
+               blocks = be32_to_cpu(*(u32 *)&pc.buffer[desc_start]);
+               length = be16_to_cpu(*(u16 *)&pc.buffer[desc_start + 6]);
 
                if (put_user(blocks, argp))
                        return(-EFAULT);
@@ -1556,53 +1215,14 @@ static int idefloppy_get_format_capacities(ide_drive_t *drive, int __user *arg)
 }
 
 /*
-** Send ATAPI_FORMAT_UNIT to the drive.
-**
-** Userland gives us the following structure:
-**
-** struct idefloppy_format_command {
-**        int nblocks;
-**        int blocksize;
-**        int flags;
-**        } ;
-**
-** flags is a bitmask, currently, the only defined flag is:
-**
-**        0x01 - verify media after format.
-*/
-
-static int idefloppy_begin_format(ide_drive_t *drive, int __user *arg)
-{
-       int blocks;
-       int length;
-       int flags;
-       idefloppy_pc_t pc;
-
-       if (get_user(blocks, arg) ||
-           get_user(length, arg+1) ||
-           get_user(flags, arg+2)) {
-               return (-EFAULT);
-       }
-
-       /* Get the SFRP bit */
-       (void) idefloppy_get_capability_page(drive);
-       idefloppy_create_format_unit_cmd(&pc, blocks, length, flags);
-       if (idefloppy_queue_pc_tail(drive, &pc)) {
-                return (-EIO);
-       }
-
-       return (0);
-}
-
-/*
-** Get ATAPI_FORMAT_UNIT progress indication.
-**
-** Userland gives a pointer to an int.  The int is set to a progress
-** indicator 0-65536, with 65536=100%.
-**
-** If the drive does not support format progress indication, we just check
-** the dsc bit, and return either 0 or 65536.
-*/
+ * Get ATAPI_FORMAT_UNIT progress indication.
+ *
+ * Userland gives a pointer to an int.  The int is set to a progress
+ * indicator 0-65536, with 65536=100%.
+ *
+ * If the drive does not support format progress indication, we just check
+ * the dsc bit, and return either 0 or 65536.
+ */
 
 static int idefloppy_get_format_progress(ide_drive_t *drive, int __user *arg)
 {
@@ -1612,23 +1232,21 @@ static int idefloppy_get_format_progress(ide_drive_t *drive, int __user *arg)
 
        if (floppy->srfp) {
                idefloppy_create_request_sense_cmd(&pc);
-               if (idefloppy_queue_pc_tail(drive, &pc)) {
+               if (idefloppy_queue_pc_tail(drive, &pc))
                        return (-EIO);
-               }
 
                if (floppy->sense_key == 2 &&
                    floppy->asc == 4 &&
-                   floppy->ascq == 4) {
+                   floppy->ascq == 4)
                        progress_indication = floppy->progress_indication;
-               }
-               /* Else assume format_unit has finished, and we're
-               ** at 0x10000 */
+
+               /* Else assume format_unit has finished, and we're at 0x10000 */
        } else {
                unsigned long flags;
                u8 stat;
 
                local_irq_save(flags);
-               stat = drive->hwif->INB(IDE_STATUS_REG);
+               stat = ide_read_status(drive);
                local_irq_restore(flags);
 
                progress_indication = ((stat & SEEK_STAT) == 0) ? 0 : 0x10000;
@@ -1639,10 +1257,7 @@ static int idefloppy_get_format_progress(ide_drive_t *drive, int __user *arg)
        return (0);
 }
 
-/*
- *     Return the current floppy capacity.
- */
-static sector_t idefloppy_capacity (ide_drive_t *drive)
+static sector_t idefloppy_capacity(ide_drive_t *drive)
 {
        idefloppy_floppy_t *floppy = drive->driver_data;
        unsigned long capacity = floppy->blocks * floppy->bs_factor;
@@ -1651,16 +1266,12 @@ static sector_t idefloppy_capacity (ide_drive_t *drive)
 }
 
 /*
- *     idefloppy_identify_device checks if we can support a drive,
- *     based on the ATAPI IDENTIFY command results.
+ * Check whether we can support a drive, based on the ATAPI IDENTIFY command
+ * results.
  */
-static int idefloppy_identify_device (ide_drive_t *drive,struct hd_driveid *id)
+static int idefloppy_identify_device(ide_drive_t *drive, struct hd_driveid *id)
 {
        struct idefloppy_id_gcw gcw;
-#if IDEFLOPPY_DEBUG_INFO
-       u16 mask,i;
-       char buffer[80];
-#endif /* IDEFLOPPY_DEBUG_INFO */
 
        *((u16 *) &gcw) = id->config;
 
@@ -1669,103 +1280,23 @@ static int idefloppy_identify_device (ide_drive_t *drive,struct hd_driveid *id)
        if ((gcw.device_type == 5) &&
            !strstr(id->model, "CD-ROM") &&
            strstr(id->model, "ZIP"))
-               gcw.device_type = 0;                    
+               gcw.device_type = 0;
 #endif
 
-#if IDEFLOPPY_DEBUG_INFO
-       printk(KERN_INFO "Dumping ATAPI Identify Device floppy parameters\n");
-       switch (gcw.protocol) {
-               case 0: case 1: sprintf(buffer, "ATA");break;
-               case 2: sprintf(buffer, "ATAPI");break;
-               case 3: sprintf(buffer, "Reserved (Unknown to ide-floppy)");break;
-       }
-       printk(KERN_INFO "Protocol Type: %s\n", buffer);
-       switch (gcw.device_type) {
-               case 0: sprintf(buffer, "Direct-access Device");break;
-               case 1: sprintf(buffer, "Streaming Tape Device");break;
-               case 2: case 3: case 4: sprintf (buffer, "Reserved");break;
-               case 5: sprintf(buffer, "CD-ROM Device");break;
-               case 6: sprintf(buffer, "Reserved");
-               case 7: sprintf(buffer, "Optical memory Device");break;
-               case 0x1f: sprintf(buffer, "Unknown or no Device type");break;
-               default: sprintf(buffer, "Reserved");
-       }
-       printk(KERN_INFO "Device Type: %x - %s\n", gcw.device_type, buffer);
-       printk(KERN_INFO "Removable: %s\n",gcw.removable ? "Yes":"No"); 
-       switch (gcw.drq_type) {
-               case 0: sprintf(buffer, "Microprocessor DRQ");break;
-               case 1: sprintf(buffer, "Interrupt DRQ");break;
-               case 2: sprintf(buffer, "Accelerated DRQ");break;
-               case 3: sprintf(buffer, "Reserved");break;
-       }
-       printk(KERN_INFO "Command Packet DRQ Type: %s\n", buffer);
-       switch (gcw.packet_size) {
-               case 0: sprintf(buffer, "12 bytes");break;
-               case 1: sprintf(buffer, "16 bytes");break;
-               default: sprintf(buffer, "Reserved");break;
-       }
-       printk(KERN_INFO "Command Packet Size: %s\n", buffer);
-       printk(KERN_INFO "Model: %.40s\n",id->model);
-       printk(KERN_INFO "Firmware Revision: %.8s\n",id->fw_rev);
-       printk(KERN_INFO "Serial Number: %.20s\n",id->serial_no);
-       printk(KERN_INFO "Write buffer size(?): %d bytes\n",id->buf_size*512);
-       printk(KERN_INFO "DMA: %s",id->capability & 0x01 ? "Yes\n":"No\n");
-       printk(KERN_INFO "LBA: %s",id->capability & 0x02 ? "Yes\n":"No\n");
-       printk(KERN_INFO "IORDY can be disabled: %s",id->capability & 0x04 ? "Yes\n":"No\n");
-       printk(KERN_INFO "IORDY supported: %s",id->capability & 0x08 ? "Yes\n":"Unknown\n");
-       printk(KERN_INFO "ATAPI overlap supported: %s",id->capability & 0x20 ? "Yes\n":"No\n");
-       printk(KERN_INFO "PIO Cycle Timing Category: %d\n",id->tPIO);
-       printk(KERN_INFO "DMA Cycle Timing Category: %d\n",id->tDMA);
-       printk(KERN_INFO "Single Word DMA supported modes:\n");
-       for (i=0,mask=1;i<8;i++,mask=mask << 1) {
-               if (id->dma_1word & mask)
-                       printk(KERN_INFO "   Mode %d%s\n", i,
-                       (id->dma_1word & (mask << 8)) ? " (active)" : "");
-       }
-       printk(KERN_INFO "Multi Word DMA supported modes:\n");
-       for (i=0,mask=1;i<8;i++,mask=mask << 1) {
-               if (id->dma_mword & mask)
-                       printk(KERN_INFO "   Mode %d%s\n", i,
-                       (id->dma_mword & (mask << 8)) ? " (active)" : "");
-       }
-       if (id->field_valid & 0x0002) {
-               printk(KERN_INFO "Enhanced PIO Modes: %s\n",
-                       id->eide_pio_modes & 1 ? "Mode 3":"None");
-               if (id->eide_dma_min == 0)
-                       sprintf(buffer, "Not supported");
-               else
-                       sprintf(buffer, "%d ns",id->eide_dma_min);
-               printk(KERN_INFO "Minimum Multi-word DMA cycle per word: %s\n", buffer);
-               if (id->eide_dma_time == 0)
-                       sprintf(buffer, "Not supported");
-               else
-                       sprintf(buffer, "%d ns",id->eide_dma_time);
-               printk(KERN_INFO "Manufacturer\'s Recommended Multi-word cycle: %s\n", buffer);
-               if (id->eide_pio == 0)
-                       sprintf(buffer, "Not supported");
-               else
-                       sprintf(buffer, "%d ns",id->eide_pio);
-               printk(KERN_INFO "Minimum PIO cycle without IORDY: %s\n",
-                       buffer);
-               if (id->eide_pio_iordy == 0)
-                       sprintf(buffer, "Not supported");
-               else
-                       sprintf(buffer, "%d ns",id->eide_pio_iordy);
-               printk(KERN_INFO "Minimum PIO cycle with IORDY: %s\n", buffer);
-       } else
-               printk(KERN_INFO "According to the device, fields 64-70 are not valid.\n");
-#endif /* IDEFLOPPY_DEBUG_INFO */
-
        if (gcw.protocol != 2)
-               printk(KERN_ERR "ide-floppy: Protocol is not ATAPI\n");
+               printk(KERN_ERR "ide-floppy: Protocol (0x%02x) is not ATAPI\n",
+                               gcw.protocol);
        else if (gcw.device_type != 0)
-               printk(KERN_ERR "ide-floppy: Device type is not set to floppy\n");
+               printk(KERN_ERR "ide-floppy: Device type (0x%02x) is not set "
+                               "to floppy\n", gcw.device_type);
        else if (!gcw.removable)
                printk(KERN_ERR "ide-floppy: The removable flag is not set\n");
        else if (gcw.drq_type == 3) {
-               printk(KERN_ERR "ide-floppy: Sorry, DRQ type %d not supported\n", gcw.drq_type);
+               printk(KERN_ERR "ide-floppy: Sorry, DRQ type (0x%02x) not "
+                               "supported\n", gcw.drq_type);
        } else if (gcw.packet_size != 0) {
-               printk(KERN_ERR "ide-floppy: Packet size is not 12 bytes long\n");
+               printk(KERN_ERR "ide-floppy: Packet size (0x%02x) is not 12 "
+                               "bytes long\n", gcw.packet_size);
        } else
                return 1;
        return 0;
@@ -1776,59 +1307,53 @@ static void idefloppy_add_settings(ide_drive_t *drive)
 {
        idefloppy_floppy_t *floppy = drive->driver_data;
 
-/*
- *                     drive   setting name    read/write      data type       min     max     mul_factor      div_factor      data pointer            set function
- */
-       ide_add_setting(drive,  "bios_cyl",     SETTING_RW,     TYPE_INT,       0,      1023,           1,              1,      &drive->bios_cyl,       NULL);
-       ide_add_setting(drive,  "bios_head",    SETTING_RW,     TYPE_BYTE,      0,      255,            1,              1,      &drive->bios_head,      NULL);
-       ide_add_setting(drive,  "bios_sect",    SETTING_RW,     TYPE_BYTE,      0,      63,             1,              1,      &drive->bios_sect,      NULL);
-       ide_add_setting(drive,  "ticks",        SETTING_RW,     TYPE_BYTE,      0,      255,            1,              1,      &floppy->ticks,         NULL);
+       ide_add_setting(drive, "bios_cyl", SETTING_RW, TYPE_INT, 0, 1023, 1, 1,
+                       &drive->bios_cyl, NULL);
+       ide_add_setting(drive, "bios_head", SETTING_RW, TYPE_BYTE, 0, 255, 1, 1,
+                       &drive->bios_head, NULL);
+       ide_add_setting(drive, "bios_sect", SETTING_RW, TYPE_BYTE, 0,  63, 1, 1,
+                       &drive->bios_sect, NULL);
+       ide_add_setting(drive, "ticks",    SETTING_RW, TYPE_BYTE, 0, 255, 1, 1,
+                       &floppy->ticks,  NULL);
 }
 #else
 static inline void idefloppy_add_settings(ide_drive_t *drive) { ; }
 #endif
 
-/*
- *     Driver initialization.
- */
-static void idefloppy_setup (ide_drive_t *drive, idefloppy_floppy_t *floppy)
+static void idefloppy_setup(ide_drive_t *drive, idefloppy_floppy_t *floppy)
 {
        struct idefloppy_id_gcw gcw;
 
        *((u16 *) &gcw) = drive->id->config;
        floppy->pc = floppy->pc_stack;
        if (gcw.drq_type == 1)
-               set_bit(IDEFLOPPY_DRQ_INTERRUPT, &floppy->flags);
+               floppy->flags |= IDEFLOPPY_FLAG_DRQ_INTERRUPT;
        /*
-        *      We used to check revisions here. At this point however
-        *      I'm giving up. Just assume they are all broken, its easier.
+        * We used to check revisions here. At this point however I'm giving up.
+        * Just assume they are all broken, its easier.
         *
-        *      The actual reason for the workarounds was likely
-        *      a driver bug after all rather than a firmware bug,
-        *      and the workaround below used to hide it. It should
-        *      be fixed as of version 1.9, but to be on the safe side
-        *      we'll leave the limitation below for the 2.2.x tree.
+        * The actual reason for the workarounds was likely a driver bug after
+        * all rather than a firmware bug, and the workaround below used to hide
+        * it. It should be fixed as of version 1.9, but to be on the safe side
+        * we'll leave the limitation below for the 2.2.x tree.
         */
-
        if (!strncmp(drive->id->model, "IOMEGA ZIP 100 ATAPI", 20)) {
-               set_bit(IDEFLOPPY_ZIP_DRIVE, &floppy->flags);
+               floppy->flags |= IDEFLOPPY_FLAG_ZIP_DRIVE;
                /* This value will be visible in the /proc/ide/hdx/settings */
                floppy->ticks = IDEFLOPPY_TICKS_DELAY;
                blk_queue_max_sectors(drive->queue, 64);
        }
 
        /*
-       *      Guess what?  The IOMEGA Clik! drive also needs the
-       *      above fix.  It makes nasty clicking noises without
-       *      it, so please don't remove this.
-       */
+        * Guess what? The IOMEGA Clik! drive also needs the above fix. It makes
+        * nasty clicking noises without it, so please don't remove this.
+        */
        if (strncmp(drive->id->model, "IOMEGA Clik!", 11) == 0) {
                blk_queue_max_sectors(drive->queue, 64);
-               set_bit(IDEFLOPPY_CLIK_DRIVE, &floppy->flags);
+               floppy->flags |= IDEFLOPPY_FLAG_CLIK_DRIVE;
        }
 
-
-       (void) idefloppy_get_capacity(drive);
+       (void) ide_floppy_get_capacity(drive);
        idefloppy_add_settings(drive);
 }
 
@@ -1844,7 +1369,7 @@ static void ide_floppy_remove(ide_drive_t *drive)
        ide_floppy_put(floppy);
 }
 
-static void ide_floppy_release(struct kref *kref)
+static void idefloppy_cleanup_obj(struct kref *kref)
 {
        struct ide_floppy_obj *floppy = to_ide_floppy(kref);
        ide_drive_t *drive = floppy->drive;
@@ -1857,19 +1382,19 @@ static void ide_floppy_release(struct kref *kref)
 }
 
 #ifdef CONFIG_IDE_PROC_FS
-static int proc_idefloppy_read_capacity
-       (char *page, char **start, off_t off, int count, int *eof, void *data)
+static int proc_idefloppy_read_capacity(char *page, char **start, off_t off,
+               int count, int *eof, void *data)
 {
        ide_drive_t*drive = (ide_drive_t *)data;
        int len;
 
-       len = sprintf(page,"%llu\n", (long long)idefloppy_capacity(drive));
-       PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+       len = sprintf(page, "%llu\n", (long long)idefloppy_capacity(drive));
+       PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
 }
 
 static ide_proc_entry_t idefloppy_proc[] = {
-       { "capacity",   S_IFREG|S_IRUGO,        proc_idefloppy_read_capacity, NULL },
-       { "geometry",   S_IFREG|S_IRUGO,        proc_ide_read_geometry, NULL },
+       { "capacity",   S_IFREG|S_IRUGO, proc_idefloppy_read_capacity,  NULL },
+       { "geometry",   S_IFREG|S_IRUGO, proc_ide_read_geometry,        NULL },
        { NULL, 0, NULL, NULL }
 };
 #endif /* CONFIG_IDE_PROC_FS */
@@ -1904,9 +1429,10 @@ static int idefloppy_open(struct inode *inode, struct file *filp)
        idefloppy_pc_t pc;
        int ret = 0;
 
-       debug_log(KERN_INFO "Reached idefloppy_open\n");
+       debug_log("Reached %s\n", __func__);
 
-       if (!(floppy = ide_floppy_get(disk)))
+       floppy = ide_floppy_get(disk);
+       if (!floppy)
                return -ENXIO;
 
        drive = floppy->drive;
@@ -1914,7 +1440,7 @@ static int idefloppy_open(struct inode *inode, struct file *filp)
        floppy->openers++;
 
        if (floppy->openers == 1) {
-               clear_bit(IDEFLOPPY_FORMAT_IN_PROGRESS, &floppy->flags);
+               floppy->flags &= ~IDEFLOPPY_FLAG_FORMAT_IN_PROGRESS;
                /* Just in case */
 
                idefloppy_create_test_unit_ready_cmd(&pc);
@@ -1923,13 +1449,13 @@ static int idefloppy_open(struct inode *inode, struct file *filp)
                        (void) idefloppy_queue_pc_tail(drive, &pc);
                }
 
-               if (idefloppy_get_capacity (drive)
+               if (ide_floppy_get_capacity(drive)
                   && (filp->f_flags & O_NDELAY) == 0
                    /*
-                   ** Allow O_NDELAY to open a drive without a disk, or with
-                   ** an unreadable disk, so that we can get the format
-                   ** capacity of the drive or begin the format - Sam
-                   */
+                    * Allow O_NDELAY to open a drive without a disk, or with an
+                    * unreadable disk, so that we can get the format capacity
+                    * of the drive or begin the format - Sam
+                    */
                    ) {
                        ret = -EIO;
                        goto out_put_floppy;
@@ -1939,14 +1465,14 @@ static int idefloppy_open(struct inode *inode, struct file *filp)
                        ret = -EROFS;
                        goto out_put_floppy;
                }
-               set_bit(IDEFLOPPY_MEDIA_CHANGED, &floppy->flags);
+               floppy->flags |= IDEFLOPPY_FLAG_MEDIA_CHANGED;
                /* IOMEGA Clik! drives do not support lock/unlock commands */
-                if (!test_bit(IDEFLOPPY_CLIK_DRIVE, &floppy->flags)) {
+               if (!(floppy->flags & IDEFLOPPY_FLAG_CLIK_DRIVE)) {
                        idefloppy_create_prevent_cmd(&pc, 1);
                        (void) idefloppy_queue_pc_tail(drive, &pc);
                }
                check_disk_change(inode->i_bdev);
-       } else if (test_bit(IDEFLOPPY_FORMAT_IN_PROGRESS, &floppy->flags)) {
+       } else if (floppy->flags & IDEFLOPPY_FLAG_FORMAT_IN_PROGRESS) {
                ret = -EBUSY;
                goto out_put_floppy;
        }
@@ -1964,17 +1490,17 @@ static int idefloppy_release(struct inode *inode, struct file *filp)
        struct ide_floppy_obj *floppy = ide_floppy_g(disk);
        ide_drive_t *drive = floppy->drive;
        idefloppy_pc_t pc;
-       
-       debug_log(KERN_INFO "Reached idefloppy_release\n");
+
+       debug_log("Reached %s\n", __func__);
 
        if (floppy->openers == 1) {
                /* IOMEGA Clik! drives do not support lock/unlock commands */
-                if (!test_bit(IDEFLOPPY_CLIK_DRIVE, &floppy->flags)) {
+               if (!(floppy->flags & IDEFLOPPY_FLAG_CLIK_DRIVE)) {
                        idefloppy_create_prevent_cmd(&pc, 0);
                        (void) idefloppy_queue_pc_tail(drive, &pc);
                }
 
-               clear_bit(IDEFLOPPY_FORMAT_IN_PROGRESS, &floppy->flags);
+               floppy->flags &= ~IDEFLOPPY_FLAG_FORMAT_IN_PROGRESS;
        }
 
        floppy->openers--;
@@ -1995,64 +1521,105 @@ static int idefloppy_getgeo(struct block_device *bdev, struct hd_geometry *geo)
        return 0;
 }
 
+static int ide_floppy_lockdoor(idefloppy_floppy_t *floppy, idefloppy_pc_t *pc,
+                              unsigned long arg, unsigned int cmd)
+{
+       if (floppy->openers > 1)
+               return -EBUSY;
+
+       /* The IOMEGA Clik! Drive doesn't support this command -
+        * no room for an eject mechanism */
+       if (!(floppy->flags & IDEFLOPPY_FLAG_CLIK_DRIVE)) {
+               int prevent = arg ? 1 : 0;
+
+               if (cmd == CDROMEJECT)
+                       prevent = 0;
+
+               idefloppy_create_prevent_cmd(pc, prevent);
+               (void) idefloppy_queue_pc_tail(floppy->drive, pc);
+       }
+
+       if (cmd == CDROMEJECT) {
+               idefloppy_create_start_stop_cmd(pc, 2);
+               (void) idefloppy_queue_pc_tail(floppy->drive, pc);
+       }
+
+       return 0;
+}
+
+static int ide_floppy_format_unit(idefloppy_floppy_t *floppy,
+                                 int __user *arg)
+{
+       int blocks, length, flags, err = 0;
+       idefloppy_pc_t pc;
+
+       if (floppy->openers > 1) {
+               /* Don't format if someone is using the disk */
+               floppy->flags &= ~IDEFLOPPY_FLAG_FORMAT_IN_PROGRESS;
+               return -EBUSY;
+       }
+
+       floppy->flags |= IDEFLOPPY_FLAG_FORMAT_IN_PROGRESS;
+
+       /*
+        * Send ATAPI_FORMAT_UNIT to the drive.
+        *
+        * Userland gives us the following structure:
+        *
+        * struct idefloppy_format_command {
+        *        int nblocks;
+        *        int blocksize;
+        *        int flags;
+        *        } ;
+        *
+        * flags is a bitmask, currently, the only defined flag is:
+        *
+        *        0x01 - verify media after format.
+        */
+       if (get_user(blocks, arg) ||
+                       get_user(length, arg+1) ||
+                       get_user(flags, arg+2)) {
+               err = -EFAULT;
+               goto out;
+       }
+
+       (void) idefloppy_get_sfrp_bit(floppy->drive);
+       idefloppy_create_format_unit_cmd(&pc, blocks, length, flags);
+
+       if (idefloppy_queue_pc_tail(floppy->drive, &pc))
+               err = -EIO;
+
+out:
+       if (err)
+               floppy->flags &= ~IDEFLOPPY_FLAG_FORMAT_IN_PROGRESS;
+       return err;
+}
+
+
 static int idefloppy_ioctl(struct inode *inode, struct file *file,
                        unsigned int cmd, unsigned long arg)
 {
        struct block_device *bdev = inode->i_bdev;
        struct ide_floppy_obj *floppy = ide_floppy_g(bdev->bd_disk);
        ide_drive_t *drive = floppy->drive;
+       idefloppy_pc_t pc;
        void __user *argp = (void __user *)arg;
        int err;
-       int prevent = (arg) ? 1 : 0;
-       idefloppy_pc_t pc;
 
        switch (cmd) {
        case CDROMEJECT:
-               prevent = 0;
                /* fall through */
        case CDROM_LOCKDOOR:
-               if (floppy->openers > 1)
-                       return -EBUSY;
-
-               /* The IOMEGA Clik! Drive doesn't support this command - no room for an eject mechanism */
-                if (!test_bit(IDEFLOPPY_CLIK_DRIVE, &floppy->flags)) {
-                       idefloppy_create_prevent_cmd(&pc, prevent);
-                       (void) idefloppy_queue_pc_tail(drive, &pc);
-               }
-               if (cmd == CDROMEJECT) {
-                       idefloppy_create_start_stop_cmd(&pc, 2);
-                       (void) idefloppy_queue_pc_tail(drive, &pc);
-               }
-               return 0;
+               return ide_floppy_lockdoor(floppy, &pc, arg, cmd);
        case IDEFLOPPY_IOCTL_FORMAT_SUPPORTED:
                return 0;
        case IDEFLOPPY_IOCTL_FORMAT_GET_CAPACITY:
-               return idefloppy_get_format_capacities(drive, argp);
+               return ide_floppy_get_format_capacities(drive, argp);
        case IDEFLOPPY_IOCTL_FORMAT_START:
-
                if (!(file->f_mode & 2))
                        return -EPERM;
 
-               if (floppy->openers > 1) {
-                       /* Don't format if someone is using the disk */
-
-                       clear_bit(IDEFLOPPY_FORMAT_IN_PROGRESS,
-                                 &floppy->flags);
-                       return -EBUSY;
-               }
-
-               set_bit(IDEFLOPPY_FORMAT_IN_PROGRESS, &floppy->flags);
-
-               err = idefloppy_begin_format(drive, argp);
-               if (err)
-                       clear_bit(IDEFLOPPY_FORMAT_IN_PROGRESS, &floppy->flags);
-               return err;
-               /*
-               ** Note, the bit will be cleared when the device is
-               ** closed.  This is the cleanest way to handle the
-               ** situation where the drive does not support
-               ** format progress reporting.
-               */
+               return ide_floppy_format_unit(floppy, (int __user *)arg);
        case IDEFLOPPY_IOCTL_FORMAT_GET_PROGRESS:
                return idefloppy_get_format_progress(drive, argp);
        }
@@ -2077,13 +1644,16 @@ static int idefloppy_media_changed(struct gendisk *disk)
 {
        struct ide_floppy_obj *floppy = ide_floppy_g(disk);
        ide_drive_t *drive = floppy->drive;
+       int ret;
 
        /* do not scan partitions twice if this is a removable device */
        if (drive->attach) {
                drive->attach = 0;
                return 0;
        }
-       return test_and_clear_bit(IDEFLOPPY_MEDIA_CHANGED, &floppy->flags);
+       ret = !!(floppy->flags & IDEFLOPPY_FLAG_MEDIA_CHANGED);
+       floppy->flags &= ~IDEFLOPPY_FLAG_MEDIA_CHANGED;
+       return ret;
 }
 
 static int idefloppy_revalidate_disk(struct gendisk *disk)
@@ -2114,16 +1684,20 @@ static int ide_floppy_probe(ide_drive_t *drive)
                goto failed;
        if (drive->media != ide_floppy)
                goto failed;
-       if (!idefloppy_identify_device (drive, drive->id)) {
-               printk (KERN_ERR "ide-floppy: %s: not supported by this version of ide-floppy\n", drive->name);
+       if (!idefloppy_identify_device(drive, drive->id)) {
+               printk(KERN_ERR "ide-floppy: %s: not supported by this version"
+                               " of ide-floppy\n", drive->name);
                goto failed;
        }
        if (drive->scsi) {
-               printk("ide-floppy: passing drive %s to ide-scsi emulation.\n", drive->name);
+               printk(KERN_INFO "ide-floppy: passing drive %s to ide-scsi"
+                               " emulation.\n", drive->name);
                goto failed;
        }
-       if ((floppy = kzalloc(sizeof (idefloppy_floppy_t), GFP_KERNEL)) == NULL) {
-               printk (KERN_ERR "ide-floppy: %s: Can't allocate a floppy structure\n", drive->name);
+       floppy = kzalloc(sizeof(idefloppy_floppy_t), GFP_KERNEL);
+       if (!floppy) {
+               printk(KERN_ERR "ide-floppy: %s: Can't allocate a floppy"
+                               " structure\n", drive->name);
                goto failed;
        }
 
@@ -2145,7 +1719,7 @@ static int ide_floppy_probe(ide_drive_t *drive)
 
        drive->driver_data = floppy;
 
-       idefloppy_setup (drive, floppy);
+       idefloppy_setup(drive, floppy);
 
        g->minors = 1 << PARTN_BITS;
        g->driverfs_dev = &drive->gendev;
@@ -2161,9 +1735,7 @@ failed:
        return -ENODEV;
 }
 
-MODULE_DESCRIPTION("ATAPI FLOPPY Driver");
-
-static void __exit idefloppy_exit (void)
+static void __exit idefloppy_exit(void)
 {
        driver_unregister(&idefloppy_driver.gen_driver);
 }
@@ -2178,3 +1750,5 @@ MODULE_ALIAS("ide:*m-floppy*");
 module_init(idefloppy_init);
 module_exit(idefloppy_exit);
 MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("ATAPI FLOPPY Driver");
+
index bb30c29f6ec04599d7d55d86ffc5cdc351c3b9c4..709b9e4d2871239f75c8f6b8f59834f8375f003f 100644 (file)
@@ -20,10 +20,16 @@ static int __init ide_generic_init(void)
        if (ide_hwifs[0].io_ports[IDE_DATA_OFFSET])
                ide_get_lock(NULL, NULL); /* for atari only */
 
-       for (i = 0; i < MAX_HWIFS; i++)
-               idx[i] = ide_hwifs[i].present ? 0xff : i;
+       for (i = 0; i < MAX_HWIFS; i++) {
+               ide_hwif_t *hwif = &ide_hwifs[i];
 
-       ide_device_add_all(idx);
+               if (hwif->io_ports[IDE_DATA_OFFSET] && !hwif->present)
+                       idx[i] = i;
+               else
+                       idx[i] = 0xff;
+       }
+
+       ide_device_add_all(idx, NULL);
 
        if (ide_hwifs[0].io_ports[IDE_DATA_OFFSET])
                ide_release_lock();     /* for atari only */
index e6bb9cf24e3d8f3fcbd599319fb693fdfe497019..3addbe478d26743701ba669c4ae6acf5b2050725 100644 (file)
@@ -466,7 +466,7 @@ static ide_startstop_t ide_ata_error(ide_drive_t *drive, struct request *rq, u8
                return ide_stopped;
        }
 
-       if (hwif->INB(IDE_STATUS_REG) & (BUSY_STAT|DRQ_STAT))
+       if (ide_read_status(drive) & (BUSY_STAT | DRQ_STAT))
                rq->errors |= ERROR_RESET;
 
        if ((rq->errors & ERROR_RESET) == ERROR_RESET) {
@@ -493,7 +493,7 @@ static ide_startstop_t ide_atapi_error(ide_drive_t *drive, struct request *rq, u
                /* add decoding error stuff */
        }
 
-       if (hwif->INB(IDE_STATUS_REG) & (BUSY_STAT|DRQ_STAT))
+       if (ide_read_status(drive) & (BUSY_STAT | DRQ_STAT))
                /* force an abort */
                hwif->OUTB(WIN_IDLEIMMEDIATE, IDE_COMMAND_REG);
 
@@ -821,9 +821,8 @@ static ide_startstop_t execute_drive_cmd (ide_drive_t *drive,
 #ifdef DEBUG
        printk("%s: DRIVE_CMD (null)\n", drive->name);
 #endif
-       ide_end_drive_cmd(drive,
-                       hwif->INB(IDE_STATUS_REG),
-                       hwif->INB(IDE_ERROR_REG));
+       ide_end_drive_cmd(drive, ide_read_status(drive), ide_read_error(drive));
+
        return ide_stopped;
 }
 
@@ -1231,7 +1230,7 @@ static ide_startstop_t ide_dma_timeout_retry(ide_drive_t *drive, int error)
                printk(KERN_WARNING "%s: DMA timeout error\n", drive->name);
                (void)HWIF(drive)->ide_dma_end(drive);
                ret = ide_error(drive, "dma timeout error",
-                                               hwif->INB(IDE_STATUS_REG));
+                               ide_read_status(drive));
        } else {
                printk(KERN_WARNING "%s: DMA timeout retry\n", drive->name);
                hwif->dma_timeout(drive);
@@ -1355,7 +1354,8 @@ void ide_timer_expiry (unsigned long data)
                                        startstop = ide_dma_timeout_retry(drive, wait);
                                } else
                                        startstop =
-                                       ide_error(drive, "irq timeout", hwif->INB(IDE_STATUS_REG));
+                                       ide_error(drive, "irq timeout",
+                                                 ide_read_status(drive));
                        }
                        drive->service_time = jiffies - drive->service_start;
                        spin_lock_irq(&ide_lock);
@@ -1487,7 +1487,7 @@ irqreturn_t ide_intr (int irq, void *dev_id)
                 * remove all the ifdef PCI crap
                 */
 #ifdef CONFIG_BLK_DEV_IDEPCI
-               if (hwif->pci_dev && !hwif->pci_dev->vendor)
+               if (hwif->chipset != ide_pci)
 #endif /* CONFIG_BLK_DEV_IDEPCI */
                {
                        /*
index e2a7e95e1636ccfc326748f5fa32a27132f2341d..c32e759df2089a5229f211154f0642da5e6e3fed 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * linux/drivers/ide/ide-iops.c        Version 0.37    Mar 05, 2003
- *
  *  Copyright (C) 2000-2002    Andre Hedrick <andre@linux-ide.org>
  *  Copyright (C) 2003         Red Hat <alan@redhat.com>
  *
@@ -165,8 +163,6 @@ void SELECT_DRIVE (ide_drive_t *drive)
        HWIF(drive)->OUTB(drive->select.all, IDE_SELECT_REG);
 }
 
-EXPORT_SYMBOL(SELECT_DRIVE);
-
 void SELECT_MASK (ide_drive_t *drive, int mask)
 {
        if (HWIF(drive)->maskproc)
@@ -434,10 +430,10 @@ int drive_is_ready (ide_drive_t *drive)
         * about possible isa-pnp and pci-pnp issues yet.
         */
        if (IDE_CONTROL_REG)
-               stat = hwif->INB(IDE_ALTSTATUS_REG);
+               stat = ide_read_altstatus(drive);
        else
                /* Note: this may clear a pending IRQ!! */
-               stat = hwif->INB(IDE_STATUS_REG);
+               stat = ide_read_status(drive);
 
        if (stat & BUSY_STAT)
                /* drive busy:  definitely not interrupting */
@@ -462,23 +458,24 @@ EXPORT_SYMBOL(drive_is_ready);
  */
 static int __ide_wait_stat(ide_drive_t *drive, u8 good, u8 bad, unsigned long timeout, u8 *rstat)
 {
-       ide_hwif_t *hwif = drive->hwif;
        unsigned long flags;
        int i;
        u8 stat;
 
        udelay(1);      /* spec allows drive 400ns to assert "BUSY" */
-       if ((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) {
+       stat = ide_read_status(drive);
+
+       if (stat & BUSY_STAT) {
                local_irq_set(flags);
                timeout += jiffies;
-               while ((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) {
+               while ((stat = ide_read_status(drive)) & BUSY_STAT) {
                        if (time_after(jiffies, timeout)) {
                                /*
                                 * One last read after the timeout in case
                                 * heavy interrupt load made us not make any
                                 * progress during the timeout..
                                 */
-                               stat = hwif->INB(IDE_STATUS_REG);
+                               stat = ide_read_status(drive);
                                if (!(stat & BUSY_STAT))
                                        break;
 
@@ -498,7 +495,9 @@ static int __ide_wait_stat(ide_drive_t *drive, u8 good, u8 bad, unsigned long ti
         */
        for (i = 0; i < 10; i++) {
                udelay(1);
-               if (OK_STAT((stat = hwif->INB(IDE_STATUS_REG)), good, bad)) {
+               stat = ide_read_status(drive);
+
+               if (OK_STAT(stat, good, bad)) {
                        *rstat = stat;
                        return 0;
                }
@@ -616,71 +615,12 @@ no_80w:
        return 0;
 }
 
-int ide_ata66_check (ide_drive_t *drive, ide_task_t *args)
-{
-       if (args->tf.command == WIN_SETFEATURES &&
-           args->tf.nsect > XFER_UDMA_2 &&
-           args->tf.feature == SETFEATURES_XFER) {
-               if (eighty_ninty_three(drive) == 0) {
-                       printk(KERN_WARNING "%s: UDMA speeds >UDMA33 cannot "
-                                           "be set\n", drive->name);
-                       return 1;
-               }
-       }
-
-       return 0;
-}
-
-/*
- * Backside of HDIO_DRIVE_CMD call of SETFEATURES_XFER.
- * 1 : Safe to update drive->id DMA registers.
- * 0 : OOPs not allowed.
- */
-int set_transfer (ide_drive_t *drive, ide_task_t *args)
-{
-       if (args->tf.command == WIN_SETFEATURES &&
-           args->tf.nsect >= XFER_SW_DMA_0 &&
-           args->tf.feature == SETFEATURES_XFER &&
-           (drive->id->dma_ultra ||
-            drive->id->dma_mword ||
-            drive->id->dma_1word))
-               return 1;
-
-       return 0;
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-static u8 ide_auto_reduce_xfer (ide_drive_t *drive)
-{
-       if (!drive->crc_count)
-               return drive->current_speed;
-       drive->crc_count = 0;
-
-       switch(drive->current_speed) {
-               case XFER_UDMA_7:       return XFER_UDMA_6;
-               case XFER_UDMA_6:       return XFER_UDMA_5;
-               case XFER_UDMA_5:       return XFER_UDMA_4;
-               case XFER_UDMA_4:       return XFER_UDMA_3;
-               case XFER_UDMA_3:       return XFER_UDMA_2;
-               case XFER_UDMA_2:       return XFER_UDMA_1;
-               case XFER_UDMA_1:       return XFER_UDMA_0;
-                       /*
-                        * OOPS we do not goto non Ultra DMA modes
-                        * without iCRC's available we force
-                        * the system to PIO and make the user
-                        * invoke the ATA-1 ATA-2 DMA modes.
-                        */
-               case XFER_UDMA_0:
-               default:                return XFER_PIO_4;
-       }
-}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
 int ide_driveid_update(ide_drive_t *drive)
 {
        ide_hwif_t *hwif = drive->hwif;
        struct hd_driveid *id;
        unsigned long timeout, flags;
+       u8 stat;
 
        /*
         * Re-read drive->id for possible DMA mode
@@ -697,10 +637,15 @@ int ide_driveid_update(ide_drive_t *drive)
                        SELECT_MASK(drive, 0);
                        return 0;       /* drive timed-out */
                }
+
                msleep(50);     /* give drive a breather */
-       } while (hwif->INB(IDE_ALTSTATUS_REG) & BUSY_STAT);
+               stat = ide_read_altstatus(drive);
+       } while (stat & BUSY_STAT);
+
        msleep(50);     /* wait for IRQ and DRQ_STAT */
-       if (!OK_STAT(hwif->INB(IDE_STATUS_REG),DRQ_STAT,BAD_R_STAT)) {
+       stat = ide_read_status(drive);
+
+       if (!OK_STAT(stat, DRQ_STAT, BAD_R_STAT)) {
                SELECT_MASK(drive, 0);
                printk("%s: CHECK for good STATUS\n", drive->name);
                return 0;
@@ -713,7 +658,7 @@ int ide_driveid_update(ide_drive_t *drive)
                return 0;
        }
        ata_input_data(drive, id, SECTOR_WORDS);
-       (void) hwif->INB(IDE_STATUS_REG);       /* clear drive IRQ */
+       (void)ide_read_status(drive);   /* clear drive IRQ */
        local_irq_enable();
        local_irq_restore(flags);
        ide_fix_driveid(id);
@@ -884,22 +829,17 @@ void ide_execute_command(ide_drive_t *drive, u8 cmd, ide_handler_t *handler,
        unsigned long flags;
        ide_hwgroup_t *hwgroup = HWGROUP(drive);
        ide_hwif_t *hwif = HWIF(drive);
-       
+
        spin_lock_irqsave(&ide_lock, flags);
-       
        BUG_ON(hwgroup->handler);
-       hwgroup->handler        = handler;
-       hwgroup->expiry         = expiry;
-       hwgroup->timer.expires  = jiffies + timeout;
-       hwgroup->req_gen_timer = hwgroup->req_gen;
-       add_timer(&hwgroup->timer);
+       __ide_set_handler(drive, handler, timeout, expiry);
        hwif->OUTBSYNC(drive, cmd, IDE_COMMAND_REG);
-       /* Drive takes 400nS to respond, we must avoid the IRQ being
-          serviced before that. 
-          
-          FIXME: we could skip this delay with care on non shared
-          devices 
-       */
+       /*
+        * Drive takes 400nS to respond, we must avoid the IRQ being
+        * serviced before that.
+        *
+        * FIXME: we could skip this delay with care on non shared devices
+        */
        ndelay(400);
        spin_unlock_irqrestore(&ide_lock, flags);
 }
@@ -919,17 +859,16 @@ static ide_startstop_t do_reset1 (ide_drive_t *, int);
 static ide_startstop_t atapi_reset_pollfunc (ide_drive_t *drive)
 {
        ide_hwgroup_t *hwgroup  = HWGROUP(drive);
-       ide_hwif_t *hwif        = HWIF(drive);
        u8 stat;
 
        SELECT_DRIVE(drive);
        udelay (10);
+       stat = ide_read_status(drive);
 
-       if (OK_STAT(stat = hwif->INB(IDE_STATUS_REG), 0, BUSY_STAT)) {
+       if (OK_STAT(stat, 0, BUSY_STAT))
                printk("%s: ATAPI reset complete\n", drive->name);
-       else {
+       else {
                if (time_before(jiffies, hwgroup->poll_timeout)) {
-                       BUG_ON(HWGROUP(drive)->handler != NULL);
                        ide_set_handler(drive, &atapi_reset_pollfunc, HZ/20, NULL);
                        /* continue polling */
                        return ide_started;
@@ -967,9 +906,10 @@ static ide_startstop_t reset_pollfunc (ide_drive_t *drive)
                }
        }
 
-       if (!OK_STAT(tmp = hwif->INB(IDE_STATUS_REG), 0, BUSY_STAT)) {
+       tmp = ide_read_status(drive);
+
+       if (!OK_STAT(tmp, 0, BUSY_STAT)) {
                if (time_before(jiffies, hwgroup->poll_timeout)) {
-                       BUG_ON(HWGROUP(drive)->handler != NULL);
                        ide_set_handler(drive, &reset_pollfunc, HZ/20, NULL);
                        /* continue polling */
                        return ide_started;
@@ -978,7 +918,9 @@ static ide_startstop_t reset_pollfunc (ide_drive_t *drive)
                drive->failures++;
        } else  {
                printk("%s: reset: ", hwif->name);
-               if ((tmp = hwif->INB(IDE_ERROR_REG)) == 1) {
+               tmp = ide_read_error(drive);
+
+               if (tmp == 1) {
                        printk("success\n");
                        drive->failures = 0;
                } else {
@@ -1007,19 +949,6 @@ static ide_startstop_t reset_pollfunc (ide_drive_t *drive)
        return ide_stopped;
 }
 
-static void check_dma_crc(ide_drive_t *drive)
-{
-#ifdef CONFIG_BLK_DEV_IDEDMA
-       if (drive->crc_count) {
-               ide_dma_off_quietly(drive);
-               ide_set_xfer_rate(drive, ide_auto_reduce_xfer(drive));
-               if (drive->current_speed >= XFER_SW_DMA_0)
-                       ide_dma_on(drive);
-       } else
-               ide_dma_off(drive);
-#endif
-}
-
 static void ide_disk_pre_reset(ide_drive_t *drive)
 {
        int legacy = (drive->id->cfs_enable_2 & 0x0400) ? 0 : 1;
@@ -1041,17 +970,20 @@ static void pre_reset(ide_drive_t *drive)
        else
                drive->post_reset = 1;
 
+       if (drive->using_dma) {
+               if (drive->crc_count)
+                       ide_check_dma_crc(drive);
+               else
+                       ide_dma_off(drive);
+       }
+
        if (!drive->keep_settings) {
-               if (drive->using_dma) {
-                       check_dma_crc(drive);
-               } else {
+               if (!drive->using_dma) {
                        drive->unmask = 0;
                        drive->io_32bit = 0;
                }
                return;
        }
-       if (drive->using_dma)
-               check_dma_crc(drive);
 
        if (HWIF(drive)->pre_reset != NULL)
                HWIF(drive)->pre_reset(drive);
@@ -1168,7 +1100,7 @@ EXPORT_SYMBOL(ide_do_reset);
 
 /*
  * ide_wait_not_busy() waits for the currently selected device on the hwif
- * to report a non-busy status, see comments in probe_hwif().
+ * to report a non-busy status, see comments in ide_probe_port().
  */
 int ide_wait_not_busy(ide_hwif_t *hwif, unsigned long timeout)
 {
index 9b44fbdfe41fc503d085b6a0f08c1d3a9775d8fe..1ff676cc6473f56dd9a5cc00b7f31d57c4899e4d 100644 (file)
@@ -358,8 +358,10 @@ void ide_toggle_bounce(ide_drive_t *drive, int on)
        if (!PCI_DMA_BUS_IS_PHYS) {
                addr = BLK_BOUNCE_ANY;
        } else if (on && drive->media == ide_disk) {
-               if (HWIF(drive)->pci_dev)
-                       addr = HWIF(drive)->pci_dev->dma_mask;
+               struct device *dev = drive->hwif->dev;
+
+               if (dev && dev->dma_mask)
+                       addr = *dev->dma_mask;
        }
 
        if (drive->queue)
@@ -576,7 +578,7 @@ u8 ide_dump_status(ide_drive_t *drive, const char *msg, u8 stat)
        }
        printk("}\n");
        if ((stat & (BUSY_STAT|ERR_STAT)) == ERR_STAT) {
-               err = drive->hwif->INB(IDE_ERROR_REG);
+               err = ide_read_error(drive);
                printk("%s: %s: error=0x%02x ", drive->name, msg, err);
                if (drive->media == ide_disk)
                        ide_dump_ata_error(drive, err);
index cbbb0f75be92ea218d2ccf9ae4e452bfeb3adb1d..b163b2e522128d16bd513b1eac2346042878a377 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * linux/drivers/ide/ide-pnp.c
- *
  * This file provides autodetection for ISA PnP IDE interfaces.
  * It was tested with "ESS ES1868 Plug and Play AudioDrive" IDE interface.
  *
@@ -51,7 +49,7 @@ static int idepnp_probe(struct pnp_dev * dev, const struct pnp_device_id *dev_id
                printk(KERN_INFO "ide%d: generic PnP IDE interface\n", index);
                pnp_set_drvdata(dev,hwif);
 
-               ide_device_add(idx);
+               ide_device_add(idx, NULL);
 
                return 0;
        }
@@ -62,9 +60,10 @@ static int idepnp_probe(struct pnp_dev * dev, const struct pnp_device_id *dev_id
 static void idepnp_remove(struct pnp_dev * dev)
 {
        ide_hwif_t *hwif = pnp_get_drvdata(dev);
-       if (hwif) {
-               ide_unregister(hwif->index);
-       } else
+
+       if (hwif)
+               ide_unregister(hwif->index, 0, 0);
+       else
                printk(KERN_ERR "idepnp: Unable to remove device, please report.\n");
 }
 
index edf650b20c67b87782b12a09488e612de03250f9..fd0ef8268950138a304c54c640ca51807ad67bbc 100644 (file)
@@ -1,7 +1,6 @@
 /*
- *  linux/drivers/ide/ide-probe.c      Version 1.11    Mar 05, 2003
- *
- *  Copyright (C) 1994-1998  Linus Torvalds & authors (see below)
+ *  Copyright (C) 1994-1998   Linus Torvalds & authors (see below)
+ *  Copyright (C) 2005, 2007  Bartlomiej Zolnierkiewicz
  */
 
 /*
@@ -129,6 +128,10 @@ static inline void do_identify (ide_drive_t *drive, u8 cmd)
 
        drive->id_read = 1;
        local_irq_enable();
+#ifdef DEBUG
+       printk(KERN_INFO "%s: dumping identify data\n", drive->name);
+       ide_dump_identify((u8 *)id);
+#endif
        ide_fix_driveid(id);
 
 #if defined (CONFIG_SCSI_EATA_PIO) || defined (CONFIG_SCSI_EATA)
@@ -261,8 +264,7 @@ err_misc:
 static int actual_try_to_identify (ide_drive_t *drive, u8 cmd)
 {
        ide_hwif_t *hwif = HWIF(drive);
-       int rc;
-       unsigned long hd_status;
+       int use_altstatus = 0, rc;
        unsigned long timeout;
        u8 s = 0, a = 0;
 
@@ -270,19 +272,17 @@ static int actual_try_to_identify (ide_drive_t *drive, u8 cmd)
        msleep(50);
 
        if (IDE_CONTROL_REG) {
-               a = hwif->INB(IDE_ALTSTATUS_REG);
-               s = hwif->INB(IDE_STATUS_REG);
-               if ((a ^ s) & ~INDEX_STAT) {
-                       printk(KERN_INFO "%s: probing with STATUS(0x%02x) instead of "
-                               "ALTSTATUS(0x%02x)\n", drive->name, s, a);
+               a = ide_read_altstatus(drive);
+               s = ide_read_status(drive);
+               if ((a ^ s) & ~INDEX_STAT)
                        /* ancient Seagate drives, broken interfaces */
-                       hd_status = IDE_STATUS_REG;
-               } else {
+                       printk(KERN_INFO "%s: probing with STATUS(0x%02x) "
+                                        "instead of ALTSTATUS(0x%02x)\n",
+                                        drive->name, s, a);
+               else
                        /* use non-intrusive polling */
-                       hd_status = IDE_ALTSTATUS_REG;
-               }
-       } else
-               hd_status = IDE_STATUS_REG;
+                       use_altstatus = 1;
+       }
 
        /* set features register for atapi
         * identify command to be sure of reply
@@ -303,11 +303,15 @@ static int actual_try_to_identify (ide_drive_t *drive, u8 cmd)
                }
                /* give drive a breather */
                msleep(50);
-       } while ((hwif->INB(hd_status)) & BUSY_STAT);
+               s = use_altstatus ? ide_read_altstatus(drive)
+                                 : ide_read_status(drive);
+       } while (s & BUSY_STAT);
 
        /* wait for IRQ and DRQ_STAT */
        msleep(50);
-       if (OK_STAT((hwif->INB(IDE_STATUS_REG)), DRQ_STAT, BAD_R_STAT)) {
+       s = ide_read_status(drive);
+
+       if (OK_STAT(s, DRQ_STAT, BAD_R_STAT)) {
                unsigned long flags;
 
                /* local CPU only; some systems need this */
@@ -317,7 +321,7 @@ static int actual_try_to_identify (ide_drive_t *drive, u8 cmd)
                /* drive responded with ID */
                rc = 0;
                /* clear drive IRQ */
-               (void) hwif->INB(IDE_STATUS_REG);
+               (void)ide_read_status(drive);
                local_irq_restore(flags);
        } else {
                /* drive refused ID */
@@ -364,7 +368,7 @@ static int try_to_identify (ide_drive_t *drive, u8 cmd)
 
                ide_set_irq(drive, 0);
                /* clear drive IRQ */
-               (void) hwif->INB(IDE_STATUS_REG);
+               (void)ide_read_status(drive);
                udelay(5);
                irq = probe_irq_off(cookie);
                if (!hwif->irq) {
@@ -420,8 +424,9 @@ static int ide_busy_sleep(ide_hwif_t *hwif)
 
 static int do_probe (ide_drive_t *drive, u8 cmd)
 {
-       int rc;
        ide_hwif_t *hwif = HWIF(drive);
+       int rc;
+       u8 stat;
 
        if (drive->present) {
                /* avoid waiting for inappropriate probes */
@@ -451,22 +456,26 @@ static int do_probe (ide_drive_t *drive, u8 cmd)
                return 3;
        }
 
-       if (OK_STAT((hwif->INB(IDE_STATUS_REG)), READY_STAT, BUSY_STAT) ||
+       stat = ide_read_status(drive);
+
+       if (OK_STAT(stat, READY_STAT, BUSY_STAT) ||
            drive->present || cmd == WIN_PIDENTIFY) {
                /* send cmd and wait */
                if ((rc = try_to_identify(drive, cmd))) {
                        /* failed: try again */
                        rc = try_to_identify(drive,cmd);
                }
-               if (hwif->INB(IDE_STATUS_REG) == (BUSY_STAT|READY_STAT))
+
+               stat = ide_read_status(drive);
+
+               if (stat == (BUSY_STAT | READY_STAT))
                        return 4;
 
                if ((rc == 1 && cmd == WIN_PIDENTIFY) &&
                        ((drive->autotune == IDE_TUNE_DEFAULT) ||
                        (drive->autotune == IDE_TUNE_AUTO))) {
-                       printk("%s: no response (status = 0x%02x), "
-                               "resetting drive\n", drive->name,
-                               hwif->INB(IDE_STATUS_REG));
+                       printk(KERN_ERR "%s: no response (status = 0x%02x), "
+                                       "resetting drive\n", drive->name, stat);
                        msleep(50);
                        hwif->OUTB(drive->select.all, IDE_SELECT_REG);
                        msleep(50);
@@ -474,11 +483,13 @@ static int do_probe (ide_drive_t *drive, u8 cmd)
                        (void)ide_busy_sleep(hwif);
                        rc = try_to_identify(drive, cmd);
                }
+
+               /* ensure drive IRQ is clear */
+               stat = ide_read_status(drive);
+
                if (rc == 1)
-                       printk("%s: no response (status = 0x%02x)\n",
-                               drive->name, hwif->INB(IDE_STATUS_REG));
-               /* ensure drive irq is clear */
-               (void) hwif->INB(IDE_STATUS_REG);
+                       printk(KERN_ERR "%s: no response (status = 0x%02x)\n",
+                                       drive->name, stat);
        } else {
                /* not present or maybe ATAPI */
                rc = 3;
@@ -488,7 +499,7 @@ static int do_probe (ide_drive_t *drive, u8 cmd)
                SELECT_DRIVE(&hwif->drives[0]);
                msleep(50);
                /* ensure drive irq is clear */
-               (void) hwif->INB(IDE_STATUS_REG);
+               (void)ide_read_status(drive);
        }
        return rc;
 }
@@ -499,6 +510,7 @@ static int do_probe (ide_drive_t *drive, u8 cmd)
 static void enable_nest (ide_drive_t *drive)
 {
        ide_hwif_t *hwif = HWIF(drive);
+       u8 stat;
 
        printk("%s: enabling %s -- ", hwif->name, drive->id->model);
        SELECT_DRIVE(drive);
@@ -512,11 +524,12 @@ static void enable_nest (ide_drive_t *drive)
 
        msleep(50);
 
-       if (!OK_STAT((hwif->INB(IDE_STATUS_REG)), 0, BAD_STAT)) {
-               printk("failed (status = 0x%02x)\n", hwif->INB(IDE_STATUS_REG));
-       } else {
-               printk("success\n");
-       }
+       stat = ide_read_status(drive);
+
+       if (!OK_STAT(stat, 0, BAD_STAT))
+               printk(KERN_CONT "failed (status = 0x%02x)\n", stat);
+       else
+               printk(KERN_CONT "success\n");
 
        /* if !(success||timed-out) */
        if (do_probe(drive, WIN_IDENTIFY) >= 2) {
@@ -610,7 +623,7 @@ static void hwif_release_dev (struct device *dev)
        complete(&hwif->gendev_rel_comp);
 }
 
-static void hwif_register (ide_hwif_t *hwif)
+static void ide_register_port(ide_hwif_t *hwif)
 {
        int ret;
 
@@ -618,8 +631,8 @@ static void hwif_register (ide_hwif_t *hwif)
        strlcpy(hwif->gendev.bus_id,hwif->name,BUS_ID_SIZE);
        hwif->gendev.driver_data = hwif;
        if (hwif->gendev.parent == NULL) {
-               if (hwif->pci_dev)
-                       hwif->gendev.parent = &hwif->pci_dev->dev;
+               if (hwif->dev)
+                       hwif->gendev.parent = hwif->dev;
                else
                        /* Would like to do = &device_legacy */
                        hwif->gendev.parent = NULL;
@@ -631,7 +644,33 @@ static void hwif_register (ide_hwif_t *hwif)
                        __FUNCTION__, ret);
 }
 
-static int wait_hwif_ready(ide_hwif_t *hwif)
+/**
+ *     ide_port_wait_ready     -       wait for port to become ready
+ *     @hwif: IDE port
+ *
+ *     This is needed on some PPCs and a bunch of BIOS-less embedded
+ *     platforms.  Typical cases are:
+ *
+ *     - The firmware hard reset the disk before booting the kernel,
+ *       the drive is still doing it's poweron-reset sequence, that
+ *       can take up to 30 seconds.
+ *
+ *     - The firmware does nothing (or no firmware), the device is
+ *       still in POST state (same as above actually).
+ *
+ *     - Some CD/DVD/Writer combo drives tend to drive the bus during
+ *       their reset sequence even when they are non-selected slave
+ *       devices, thus preventing discovery of the main HD.
+ *
+ *     Doing this wait-for-non-busy should not harm any existing
+ *     configuration and fix some issues like the above.
+ *
+ *     BenH.
+ *
+ *     Returns 0 on success, error code (< 0) otherwise.
+ */
+
+static int ide_port_wait_ready(ide_hwif_t *hwif)
 {
        int unit, rc;
 
@@ -709,36 +748,16 @@ void ide_undecoded_slave(ide_drive_t *drive1)
 
 EXPORT_SYMBOL_GPL(ide_undecoded_slave);
 
-/*
- * This routine only knows how to look for drive units 0 and 1
- * on an interface, so any setting of MAX_DRIVES > 2 won't work here.
- */
-static void probe_hwif(ide_hwif_t *hwif)
+static int ide_probe_port(ide_hwif_t *hwif)
 {
        unsigned long flags;
        unsigned int irqd;
-       int unit;
+       int unit, rc = -ENODEV;
 
-       if (hwif->noprobe)
-               return;
+       BUG_ON(hwif->present);
 
-       if ((hwif->chipset != ide_4drives || !hwif->mate || !hwif->mate->present) &&
-           (ide_hwif_request_regions(hwif))) {
-               u16 msgout = 0;
-               for (unit = 0; unit < MAX_DRIVES; ++unit) {
-                       ide_drive_t *drive = &hwif->drives[unit];
-                       if (drive->present) {
-                               drive->present = 0;
-                               printk(KERN_ERR "%s: ERROR, PORTS ALREADY IN USE\n",
-                                       drive->name);
-                               msgout = 1;
-                       }
-               }
-               if (!msgout)
-                       printk(KERN_ERR "%s: ports already in use, skipping probe\n",
-                               hwif->name);
-               return; 
-       }
+       if (hwif->noprobe)
+               return -EACCES;
 
        /*
         * We must always disable IRQ, as probe_for_drive will assert IRQ, but
@@ -750,26 +769,7 @@ static void probe_hwif(ide_hwif_t *hwif)
 
        local_irq_set(flags);
 
-       /* This is needed on some PPCs and a bunch of BIOS-less embedded
-        * platforms. Typical cases are:
-        * 
-        *  - The firmware hard reset the disk before booting the kernel,
-        *    the drive is still doing it's poweron-reset sequence, that
-        *    can take up to 30 seconds
-        *  - The firmware does nothing (or no firmware), the device is
-        *    still in POST state (same as above actually).
-        *  - Some CD/DVD/Writer combo drives tend to drive the bus during
-        *    their reset sequence even when they are non-selected slave
-        *    devices, thus preventing discovery of the main HD
-        *    
-        *  Doing this wait-for-busy should not harm any existing configuration
-        *  (at least things won't be worse than what current code does, that
-        *  is blindly go & talk to the drive) and fix some issues like the
-        *  above.
-        *  
-        *  BenH.
-        */
-       if (wait_hwif_ready(hwif) == -EBUSY)
+       if (ide_port_wait_ready(hwif) == -EBUSY)
                printk(KERN_DEBUG "%s: Wait for ready failed before probe !\n", hwif->name);
 
        /*
@@ -779,14 +779,8 @@ static void probe_hwif(ide_hwif_t *hwif)
                ide_drive_t *drive = &hwif->drives[unit];
                drive->dn = (hwif->channel ? 2 : 0) + unit;
                (void) probe_for_drive(drive);
-               if (drive->present && !hwif->present) {
-                       hwif->present = 1;
-                       if (hwif->chipset != ide_4drives ||
-                           !hwif->mate || 
-                           !hwif->mate->present) {
-                               hwif_register(hwif);
-                       }
-               }
+               if (drive->present)
+                       rc = 0;
        }
        if (hwif->io_ports[IDE_CONTROL_OFFSET] && hwif->reset) {
                printk(KERN_WARNING "%s: reset\n", hwif->name);
@@ -803,10 +797,12 @@ static void probe_hwif(ide_hwif_t *hwif)
        if (irqd)
                enable_irq(irqd);
 
-       if (!hwif->present) {
-               ide_hwif_release_regions(hwif);
-               return;
-       }
+       return rc;
+}
+
+static void ide_port_tune_devices(ide_hwif_t *hwif)
+{
+       int unit;
 
        for (unit = 0; unit < MAX_DRIVES; unit++) {
                ide_drive_t *drive = &hwif->drives[unit];
@@ -836,7 +832,7 @@ static void probe_hwif(ide_hwif_t *hwif)
        for (unit = 0; unit < MAX_DRIVES; ++unit) {
                ide_drive_t *drive = &hwif->drives[unit];
 
-               if (hwif->no_io_32bit)
+               if (hwif->host_flags & IDE_HFLAG_NO_IO_32BIT)
                        drive->no_io_32bit = 1;
                else
                        drive->no_io_32bit = drive->id->dword_io ? 1 : 0;
@@ -895,13 +891,6 @@ static int ide_init_queue(ide_drive_t *drive)
        q->queuedata = drive;
        blk_queue_segment_boundary(q, 0xffff);
 
-       if (!hwif->rqsize) {
-               if ((hwif->host_flags & IDE_HFLAG_NO_LBA48) ||
-                   (hwif->host_flags & IDE_HFLAG_NO_LBA48_DMA))
-                       hwif->rqsize = 256;
-               else
-                       hwif->rqsize = 65536;
-       }
        if (hwif->rqsize < max_sectors)
                max_sectors = hwif->rqsize;
        blk_queue_max_sectors(q, max_sectors);
@@ -932,6 +921,48 @@ static int ide_init_queue(ide_drive_t *drive)
        return 0;
 }
 
+static void ide_add_drive_to_hwgroup(ide_drive_t *drive)
+{
+       ide_hwgroup_t *hwgroup = drive->hwif->hwgroup;
+
+       spin_lock_irq(&ide_lock);
+       if (!hwgroup->drive) {
+               /* first drive for hwgroup. */
+               drive->next = drive;
+               hwgroup->drive = drive;
+               hwgroup->hwif = HWIF(hwgroup->drive);
+       } else {
+               drive->next = hwgroup->drive->next;
+               hwgroup->drive->next = drive;
+       }
+       spin_unlock_irq(&ide_lock);
+}
+
+/*
+ * For any present drive:
+ * - allocate the block device queue
+ * - link drive into the hwgroup
+ */
+static void ide_port_setup_devices(ide_hwif_t *hwif)
+{
+       int i;
+
+       for (i = 0; i < MAX_DRIVES; i++) {
+               ide_drive_t *drive = &hwif->drives[i];
+
+               if (!drive->present)
+                       continue;
+
+               if (ide_init_queue(drive)) {
+                       printk(KERN_ERR "ide: failed to init %s\n",
+                                       drive->name);
+                       continue;
+               }
+
+               ide_add_drive_to_hwgroup(drive);
+       }
+}
+
 /*
  * This routine sets up the irq for an ide interface, and creates a new
  * hwgroup for the irq/hwif if none was previously assigned.
@@ -997,21 +1028,17 @@ static int init_irq (ide_hwif_t *hwif)
                spin_lock_irq(&ide_lock);
                hwif->next = hwgroup->hwif->next;
                hwgroup->hwif->next = hwif;
+               BUG_ON(hwif->next == hwif);
                spin_unlock_irq(&ide_lock);
        } else {
-               hwgroup = kmalloc_node(sizeof(ide_hwgroup_t),
-                                       GFP_KERNEL | __GFP_ZERO,
-                                       hwif_to_node(hwif->drives[0].hwif));
-               if (!hwgroup)
-                       goto out_up;
+               hwgroup = kmalloc_node(sizeof(*hwgroup), GFP_KERNEL|__GFP_ZERO,
+                                      hwif_to_node(hwif));
+               if (hwgroup == NULL)
+                       goto out_up;
 
                hwif->hwgroup = hwgroup;
+               hwgroup->hwif = hwif->next = hwif;
 
-               hwgroup->hwif     = hwif->next = hwif;
-               hwgroup->rq       = NULL;
-               hwgroup->handler  = NULL;
-               hwgroup->drive    = NULL;
-               hwgroup->busy     = 0;
                init_timer(&hwgroup->timer);
                hwgroup->timer.function = &ide_timer_expiry;
                hwgroup->timer.data = (unsigned long) hwgroup;
@@ -1037,30 +1064,12 @@ static int init_irq (ide_hwif_t *hwif)
                        goto out_unlink;
        }
 
-       /*
-        * For any present drive:
-        * - allocate the block device queue
-        * - link drive into the hwgroup
-        */
-       for (index = 0; index < MAX_DRIVES; ++index) {
-               ide_drive_t *drive = &hwif->drives[index];
-               if (!drive->present)
-                       continue;
-               if (ide_init_queue(drive)) {
-                       printk(KERN_ERR "ide: failed to init %s\n",drive->name);
-                       continue;
-               }
-               spin_lock_irq(&ide_lock);
-               if (!hwgroup->drive) {
-                       /* first drive for hwgroup. */
-                       drive->next = drive;
-                       hwgroup->drive = drive;
-                       hwgroup->hwif = HWIF(hwgroup->drive);
-               } else {
-                       drive->next = hwgroup->drive->next;
-                       hwgroup->drive->next = drive;
-               }
-               spin_unlock_irq(&ide_lock);
+       if (!hwif->rqsize) {
+               if ((hwif->host_flags & IDE_HFLAG_NO_LBA48) ||
+                   (hwif->host_flags & IDE_HFLAG_NO_LBA48_DMA))
+                       hwif->rqsize = 256;
+               else
+                       hwif->rqsize = 65536;
        }
 
 #if !defined(__mc68000__) && !defined(CONFIG_APUS)
@@ -1076,28 +1085,13 @@ static int init_irq (ide_hwif_t *hwif)
                printk(" (%sed with %s)",
                        hwif->sharing_irq ? "shar" : "serializ", match->name);
        printk("\n");
+
+       ide_port_setup_devices(hwif);
+
        mutex_unlock(&ide_cfg_mtx);
        return 0;
 out_unlink:
-       spin_lock_irq(&ide_lock);
-       if (hwif->next == hwif) {
-               BUG_ON(match);
-               BUG_ON(hwgroup->hwif != hwif);
-               kfree(hwgroup);
-       } else {
-               ide_hwif_t *g;
-               g = hwgroup->hwif;
-               while (g->next != hwif)
-                       g = g->next;
-               g->next = hwif->next;
-               if (hwgroup->hwif == hwif) {
-                       /* Impossible. */
-                       printk(KERN_ERR "Duh. Uninitialized hwif listed as active hwif.\n");
-                       hwgroup->hwif = g;
-               }
-               BUG_ON(hwgroup->hwif == hwif);
-       }
-       spin_unlock_irq(&ide_lock);
+       ide_remove_port_from_hwgroup(hwif);
 out_up:
        mutex_unlock(&ide_cfg_mtx);
        return 1;
@@ -1218,56 +1212,25 @@ static void drive_release_dev (struct device *dev)
        complete(&drive->gendev_rel_comp);
 }
 
-/*
- * init_gendisk() (as opposed to ide_geninit) is called for each major device,
- * after probing for drives, to allocate partition tables and other data
- * structures needed for the routines in genhd.c.  ide_geninit() gets called
- * somewhat later, during the partition check.
- */
-static void init_gendisk (ide_hwif_t *hwif)
-{
-       unsigned int unit;
-
-       for (unit = 0; unit < MAX_DRIVES; ++unit) {
-               ide_drive_t * drive = &hwif->drives[unit];
-               ide_add_generic_settings(drive);
-               snprintf(drive->gendev.bus_id,BUS_ID_SIZE,"%u.%u",
-                        hwif->index,unit);
-               drive->gendev.parent = &hwif->gendev;
-               drive->gendev.bus = &ide_bus_type;
-               drive->gendev.driver_data = drive;
-               drive->gendev.release = drive_release_dev;
-       }
-       blk_register_region(MKDEV(hwif->major, 0), MAX_DRIVES << PARTN_BITS,
-                       THIS_MODULE, ata_probe, ata_lock, hwif);
-}
-
 static int hwif_init(ide_hwif_t *hwif)
 {
        int old_irq;
 
-       /* Return success if no device is connected */
-       if (!hwif->present)
-               return 1;
-
        if (!hwif->irq) {
                if (!(hwif->irq = ide_default_irq(hwif->io_ports[IDE_DATA_OFFSET])))
                {
                        printk("%s: DISABLED, NO IRQ\n", hwif->name);
-                       return (hwif->present = 0);
+                       return 0;
                }
        }
 #ifdef CONFIG_BLK_DEV_HD
        if (hwif->irq == HD_IRQ && hwif->io_ports[IDE_DATA_OFFSET] != HD_DATA) {
                printk("%s: CANNOT SHARE IRQ WITH OLD "
                        "HARDDISK DRIVER (hd.c)\n", hwif->name);
-               return (hwif->present = 0);
+               return 0;
        }
 #endif /* CONFIG_BLK_DEV_HD */
 
-       /* we set it back to 1 if all is ok below */    
-       hwif->present = 0;
-
        if (register_blkdev(hwif->major, hwif->name))
                return 0;
 
@@ -1305,11 +1268,8 @@ static int hwif_init(ide_hwif_t *hwif)
                hwif->name, hwif->irq);
 
 done:
-       init_gendisk(hwif);
-
-       ide_acpi_init(hwif);
-
-       hwif->present = 1;      /* success */
+       blk_register_region(MKDEV(hwif->major, 0), MAX_DRIVES << PARTN_BITS,
+                           THIS_MODULE, ata_probe, ata_lock, hwif);
        return 1;
 
 out:
@@ -1323,28 +1283,143 @@ static void hwif_register_devices(ide_hwif_t *hwif)
 
        for (i = 0; i < MAX_DRIVES; i++) {
                ide_drive_t *drive = &hwif->drives[i];
+               struct device *dev = &drive->gendev;
+               int ret;
 
-               if (drive->present) {
-                       int ret = device_register(&drive->gendev);
+               if (!drive->present)
+                       continue;
 
-                       if (ret < 0)
-                               printk(KERN_WARNING "IDE: %s: "
-                                       "device_register error: %d\n",
-                                       __FUNCTION__, ret);
-               }
+               ide_add_generic_settings(drive);
+
+               snprintf(dev->bus_id, BUS_ID_SIZE, "%u.%u", hwif->index, i);
+               dev->parent = &hwif->gendev;
+               dev->bus = &ide_bus_type;
+               dev->driver_data = drive;
+               dev->release = drive_release_dev;
+
+               ret = device_register(dev);
+               if (ret < 0)
+                       printk(KERN_WARNING "IDE: %s: device_register error: "
+                                           "%d\n", __func__, ret);
        }
 }
 
-int ide_device_add_all(u8 *idx)
+static void ide_port_init_devices(ide_hwif_t *hwif)
 {
-       ide_hwif_t *hwif;
+       int i;
+
+       for (i = 0; i < MAX_DRIVES; i++) {
+               ide_drive_t *drive = &hwif->drives[i];
+
+               if (hwif->host_flags & IDE_HFLAG_IO_32BIT)
+                       drive->io_32bit = 1;
+               if (hwif->host_flags & IDE_HFLAG_UNMASK_IRQS)
+                       drive->unmask = 1;
+               if (hwif->host_flags & IDE_HFLAG_NO_UNMASK_IRQS)
+                       drive->no_unmask = 1;
+               if ((hwif->host_flags & IDE_HFLAG_NO_AUTOTUNE) == 0)
+                       drive->autotune = 1;
+       }
+
+       if (hwif->port_init_devs)
+               hwif->port_init_devs(hwif);
+}
+
+static void ide_init_port(ide_hwif_t *hwif, unsigned int port,
+                         const struct ide_port_info *d)
+{
+       if (d->chipset != ide_etrax100)
+               hwif->channel = port;
+
+       if (d->chipset)
+               hwif->chipset = d->chipset;
+
+       if (d->init_iops)
+               d->init_iops(hwif);
+
+       if ((d->host_flags & IDE_HFLAG_NO_DMA) == 0)
+               ide_hwif_setup_dma(hwif, d);
+
+       if ((!hwif->irq && (d->host_flags & IDE_HFLAG_LEGACY_IRQS)) ||
+           (d->host_flags & IDE_HFLAG_FORCE_LEGACY_IRQS))
+               hwif->irq = port ? 15 : 14;
+
+       hwif->host_flags = d->host_flags;
+       hwif->pio_mask = d->pio_mask;
+
+       if ((d->host_flags & IDE_HFLAG_SERIALIZE) && hwif->mate)
+               hwif->mate->serialized = hwif->serialized = 1;
+
+       hwif->swdma_mask = d->swdma_mask;
+       hwif->mwdma_mask = d->mwdma_mask;
+       hwif->ultra_mask = d->udma_mask;
+
+       /* reset DMA masks only for SFF-style DMA controllers */
+       if ((d->host_flags && IDE_HFLAG_NO_DMA) == 0 && hwif->dma_base == 0)
+               hwif->swdma_mask = hwif->mwdma_mask = hwif->ultra_mask = 0;
+
+       if (d->host_flags & IDE_HFLAG_RQSIZE_256)
+               hwif->rqsize = 256;
+
+       /* call chipset specific routine for each enabled port */
+       if (d->init_hwif)
+               d->init_hwif(hwif);
+
+       if (hwif->cable_detect && (hwif->ultra_mask & 0x78)) {
+               if (hwif->cbl != ATA_CBL_PATA40_SHORT)
+                       hwif->cbl = hwif->cable_detect(hwif);
+       }
+}
+
+int ide_device_add_all(u8 *idx, const struct ide_port_info *d)
+{
+       ide_hwif_t *hwif, *mate = NULL;
        int i, rc = 0;
 
+       for (i = 0; i < MAX_HWIFS; i++) {
+               if (d == NULL || idx[i] == 0xff) {
+                       mate = NULL;
+                       continue;
+               }
+
+               hwif = &ide_hwifs[idx[i]];
+
+               if (d->chipset != ide_etrax100 && (i & 1) && mate) {
+                       hwif->mate = mate;
+                       mate->mate = hwif;
+               }
+
+               mate = (i & 1) ? NULL : hwif;
+
+               ide_init_port(hwif, i & 1, d);
+               ide_port_init_devices(hwif);
+       }
+
        for (i = 0; i < MAX_HWIFS; i++) {
                if (idx[i] == 0xff)
                        continue;
 
-               probe_hwif(&ide_hwifs[idx[i]]);
+               hwif = &ide_hwifs[idx[i]];
+
+               if ((hwif->chipset != ide_4drives || !hwif->mate ||
+                    !hwif->mate->present) && ide_hwif_request_regions(hwif)) {
+                       printk(KERN_ERR "%s: ports already in use, "
+                                       "skipping probe\n", hwif->name);
+                       continue;
+               }
+
+               if (ide_probe_port(hwif) < 0) {
+                       ide_hwif_release_regions(hwif);
+                       continue;
+               }
+
+               hwif->present = 1;
+
+               if (hwif->chipset != ide_4drives || !hwif->mate ||
+                   !hwif->mate->present)
+                       ide_register_port(hwif);
+
+               ide_port_tune_devices(hwif);
        }
 
        for (i = 0; i < MAX_HWIFS; i++) {
@@ -1353,12 +1428,19 @@ int ide_device_add_all(u8 *idx)
 
                hwif = &ide_hwifs[idx[i]];
 
+               if (!hwif->present)
+                       continue;
+
                if (hwif_init(hwif) == 0) {
                        printk(KERN_INFO "%s: failed to initialize IDE "
                                         "interface\n", hwif->name);
+                       hwif->present = 0;
                        rc = -1;
                        continue;
                }
+
+               ide_acpi_init(hwif);
+               ide_acpi_port_init_devices(hwif);
        }
 
        for (i = 0; i < MAX_HWIFS; i++) {
@@ -1376,15 +1458,22 @@ int ide_device_add_all(u8 *idx)
        }
 
        for (i = 0; i < MAX_HWIFS; i++) {
-               if (idx[i] != 0xff)
-                       ide_proc_register_port(&ide_hwifs[idx[i]]);
+               if (idx[i] == 0xff)
+                       continue;
+
+               hwif = &ide_hwifs[idx[i]];
+
+               if (hwif->present) {
+                       ide_proc_register_port(hwif);
+                       ide_proc_port_register_devices(hwif);
+               }
        }
 
        return rc;
 }
 EXPORT_SYMBOL_GPL(ide_device_add_all);
 
-int ide_device_add(u8 idx[4])
+int ide_device_add(u8 idx[4], const struct ide_port_info *d)
 {
        u8 idx_all[MAX_HWIFS];
        int i;
@@ -1392,6 +1481,6 @@ int ide_device_add(u8 idx[4])
        for (i = 0; i < MAX_HWIFS; i++)
                idx_all[i] = (i < 4) ? idx[i] : 0xff;
 
-       return ide_device_add_all(idx_all);
+       return ide_device_add_all(idx_all, d);
 }
 EXPORT_SYMBOL_GPL(ide_device_add);
index aa663e7f46f2f4b29ebc3fad6fe612a6166ffc3e..bab88ca7f7ecb953495cd09c17d979a395ae5fd9 100644 (file)
@@ -1,6 +1,4 @@
 /*
- *  linux/drivers/ide/ide-proc.c       Version 1.05    Mar 05, 2003
- *
  *  Copyright (C) 1997-1998    Mark Lord
  *  Copyright (C) 2003         Red Hat <alan@redhat.com>
  *
@@ -67,6 +65,7 @@ static int proc_ide_read_imodel
                case ide_4drives:       name = "4drives";       break;
                case ide_pmac:          name = "mac-io";        break;
                case ide_au1xxx:        name = "au1xxx";        break;
+               case ide_palm3710:      name = "palm3710";      break;
                case ide_etrax100:      name = "etrax100";      break;
                case ide_acorn:         name = "acorn";         break;
                default:                name = "(unknown)";     break;
@@ -741,7 +740,7 @@ void ide_proc_unregister_driver(ide_drive_t *drive, ide_driver_t *driver)
 
 EXPORT_SYMBOL(ide_proc_unregister_driver);
 
-static void create_proc_ide_drives(ide_hwif_t *hwif)
+void ide_proc_port_register_devices(ide_hwif_t *hwif)
 {
        int     d;
        struct proc_dir_entry *ent;
@@ -795,9 +794,6 @@ static ide_proc_entry_t hwif_entries[] = {
 
 void ide_proc_register_port(ide_hwif_t *hwif)
 {
-       if (!hwif->present)
-               return;
-
        if (!hwif->proc) {
                hwif->proc = proc_mkdir(hwif->name, proc_ide_root);
 
@@ -806,8 +802,6 @@ void ide_proc_register_port(ide_hwif_t *hwif)
 
                ide_add_proc_entries(hwif->proc, hwif_entries, hwif);
        }
-
-       create_proc_ide_drives(hwif);
 }
 
 #ifdef CONFIG_BLK_DEV_IDEPCI
index 7ffa332d77cedf5c17512cc78ae88d2c9a745a7b..93d2e41be85386ae00626073d052502be4be90ab 100644 (file)
@@ -81,7 +81,7 @@ static int __init ide_scan_pcidev(struct pci_dev *dev)
  *     module ordering not traditionally ordered.
  */
 
-int __init ide_scan_pcibus(void)
+static int __init ide_scan_pcibus(void)
 {
        struct pci_dev *dev = NULL;
        struct pci_driver *d;
@@ -113,9 +113,4 @@ int __init ide_scan_pcibus(void)
        return 0;
 }
 
-static int __init ide_scan_pci(void)
-{
-       return ide_scan_pcibus();
-}
-
-module_init(ide_scan_pci);
+module_init(ide_scan_pcibus);
index d71a584f076547661674cc6876fe7e37cc9391ca..49dd2e7bae7a788f95f8157089f9d20c8d7e695b 100644 (file)
@@ -1,9 +1,8 @@
 /*
- * linux/drivers/ide/ide-tape.c                Version 1.19    Nov, 2003
- *
- * Copyright (C) 1995 - 1999 Gadi Oxman <gadio@netvision.net.il>
+ * IDE ATAPI streaming tape driver.
  *
- * $Header$
+ * Copyright (C) 1995-1999  Gadi Oxman <gadio@netvision.net.il>
+ * Copyright (C) 2003-2005  Bartlomiej Zolnierkiewicz
  *
  * This driver was constructed as a student project in the software laboratory
  * of the faculty of electrical engineering in the Technion - Israel's
  *
  * It is hereby placed under the terms of the GNU general public license.
  * (See linux/COPYING).
- */
-/*
- * IDE ATAPI streaming tape driver.
- *
- * This driver is a part of the Linux ide driver and works in co-operation
- * with linux/drivers/block/ide.c.
- *
- * The driver, in co-operation with ide.c, basically traverses the 
- * request-list for the block device interface. The character device
- * interface, on the other hand, creates new requests, adds them
- * to the request-list of the block device, and waits for their completion.
- *
- * Pipelined operation mode is now supported on both reads and writes.
- *
- * The block device major and minor numbers are determined from the
- * tape's relative position in the ide interfaces, as explained in ide.c.
- *
- * The character device interface consists of the following devices:
- *
- * ht0         major 37, minor 0       first  IDE tape, rewind on close.
- * ht1         major 37, minor 1       second IDE tape, rewind on close.
- * ...
- * nht0                major 37, minor 128     first  IDE tape, no rewind on close.
- * nht1                major 37, minor 129     second IDE tape, no rewind on close.
- * ...
- *
- * Run linux/scripts/MAKEDEV.ide to create the above entries.
- *
- * The general magnetic tape commands compatible interface, as defined by
- * include/linux/mtio.h, is accessible through the character device.
- *
- * General ide driver configuration options, such as the interrupt-unmask
- * flag, can be configured by issuing an ioctl to the block device interface,
- * as any other ide device.
- *
- * Our own ide-tape ioctl's can be issued to either the block device or
- * the character device interface.
- *
- * Maximal throughput with minimal bus load will usually be achieved in the
- * following scenario:
- *
- *     1.      ide-tape is operating in the pipelined operation mode.
- *     2.      No buffering is performed by the user backup program.
- *
- * Testing was done with a 2 GB CONNER CTMA 4000 IDE ATAPI Streaming Tape Drive.
- * 
- * Ver 0.1   Nov  1 95   Pre-working code :-)
- * Ver 0.2   Nov 23 95   A short backup (few megabytes) and restore procedure
- *                        was successful ! (Using tar cvf ... on the block
- *                        device interface).
- *                       A longer backup resulted in major swapping, bad
- *                        overall Linux performance and eventually failed as
- *                        we received non serial read-ahead requests from the
- *                        buffer cache.
- * Ver 0.3   Nov 28 95   Long backups are now possible, thanks to the
- *                        character device interface. Linux's responsiveness
- *                        and performance doesn't seem to be much affected
- *                        from the background backup procedure.
- *                       Some general mtio.h magnetic tape operations are
- *                        now supported by our character device. As a result,
- *                        popular tape utilities are starting to work with
- *                        ide tapes :-)
- *                       The following configurations were tested:
- *                             1. An IDE ATAPI TAPE shares the same interface
- *                                and irq with an IDE ATAPI CDROM.
- *                             2. An IDE ATAPI TAPE shares the same interface
- *                                and irq with a normal IDE disk.
- *                        Both configurations seemed to work just fine !
- *                        However, to be on the safe side, it is meanwhile
- *                        recommended to give the IDE TAPE its own interface
- *                        and irq.
- *                       The one thing which needs to be done here is to
- *                        add a "request postpone" feature to ide.c,
- *                        so that we won't have to wait for the tape to finish
- *                        performing a long media access (DSC) request (such
- *                        as a rewind) before we can access the other device
- *                        on the same interface. This effect doesn't disturb
- *                        normal operation most of the time because read/write
- *                        requests are relatively fast, and once we are
- *                        performing one tape r/w request, a lot of requests
- *                        from the other device can be queued and ide.c will
- *                       service all of them after this single tape request.
- * Ver 1.0   Dec 11 95   Integrated into Linux 1.3.46 development tree.
- *                       On each read / write request, we now ask the drive
- *                        if we can transfer a constant number of bytes
- *                        (a parameter of the drive) only to its buffers,
- *                        without causing actual media access. If we can't,
- *                        we just wait until we can by polling the DSC bit.
- *                        This ensures that while we are not transferring
- *                        more bytes than the constant referred to above, the
- *                        interrupt latency will not become too high and
- *                        we won't cause an interrupt timeout, as happened
- *                        occasionally in the previous version.
- *                       While polling for DSC, the current request is
- *                        postponed and ide.c is free to handle requests from
- *                        the other device. This is handled transparently to
- *                        ide.c. The hwgroup locking method which was used
- *                        in the previous version was removed.
- *                       Use of new general features which are provided by
- *                        ide.c for use with atapi devices.
- *                        (Programming done by Mark Lord)
- *                       Few potential bug fixes (Again, suggested by Mark)
- *                       Single character device data transfers are now
- *                        not limited in size, as they were before.
- *                       We are asking the tape about its recommended
- *                        transfer unit and send a larger data transfer
- *                        as several transfers of the above size.
- *                        For best results, use an integral number of this
- *                        basic unit (which is shown during driver
- *                        initialization). I will soon add an ioctl to get
- *                        this important parameter.
- *                       Our data transfer buffer is allocated on startup,
- *                        rather than before each data transfer. This should
- *                        ensure that we will indeed have a data buffer.
- * Ver 1.1   Dec 14 95   Fixed random problems which occurred when the tape
- *                        shared an interface with another device.
- *                        (poll_for_dsc was a complete mess).
- *                       Removed some old (non-active) code which had
- *                        to do with supporting buffer cache originated
- *                        requests.
- *                       The block device interface can now be opened, so
- *                        that general ide driver features like the unmask
- *                        interrupts flag can be selected with an ioctl.
- *                        This is the only use of the block device interface.
- *                       New fast pipelined operation mode (currently only on
- *                        writes). When using the pipelined mode, the
- *                        throughput can potentially reach the maximum
- *                        tape supported throughput, regardless of the
- *                        user backup program. On my tape drive, it sometimes
- *                        boosted performance by a factor of 2. Pipelined
- *                        mode is enabled by default, but since it has a few
- *                        downfalls as well, you may want to disable it.
- *                        A short explanation of the pipelined operation mode
- *                        is available below.
- * Ver 1.2   Jan  1 96   Eliminated pipelined mode race condition.
- *                       Added pipeline read mode. As a result, restores
- *                        are now as fast as backups.
- *                       Optimized shared interface behavior. The new behavior
- *                        typically results in better IDE bus efficiency and
- *                        higher tape throughput.
- *                       Pre-calculation of the expected read/write request
- *                        service time, based on the tape's parameters. In
- *                        the pipelined operation mode, this allows us to
- *                        adjust our polling frequency to a much lower value,
- *                        and thus to dramatically reduce our load on Linux,
- *                        without any decrease in performance.
- *                       Implemented additional mtio.h operations.
- *                       The recommended user block size is returned by
- *                        the MTIOCGET ioctl.
- *                       Additional minor changes.
- * Ver 1.3   Feb  9 96   Fixed pipelined read mode bug which prevented the
- *                        use of some block sizes during a restore procedure.
- *                       The character device interface will now present a
- *                        continuous view of the media - any mix of block sizes
- *                        during a backup/restore procedure is supported. The
- *                        driver will buffer the requests internally and
- *                        convert them to the tape's recommended transfer
- *                        unit, making performance almost independent of the
- *                        chosen user block size.
- *                       Some improvements in error recovery.
- *                       By cooperating with ide-dma.c, bus mastering DMA can
- *                        now sometimes be used with IDE tape drives as well.
- *                        Bus mastering DMA has the potential to dramatically
- *                        reduce the CPU's overhead when accessing the device,
- *                        and can be enabled by using hdparm -d1 on the tape's
- *                        block device interface. For more info, read the
- *                        comments in ide-dma.c.
- * Ver 1.4   Mar 13 96   Fixed serialize support.
- * Ver 1.5   Apr 12 96   Fixed shared interface operation, broken in 1.3.85.
- *                       Fixed pipelined read mode inefficiency.
- *                       Fixed nasty null dereferencing bug.
- * Ver 1.6   Aug 16 96   Fixed FPU usage in the driver.
- *                       Fixed end of media bug.
- * Ver 1.7   Sep 10 96   Minor changes for the CONNER CTT8000-A model.
- * Ver 1.8   Sep 26 96   Attempt to find a better balance between good
- *                        interactive response and high system throughput.
- * Ver 1.9   Nov  5 96   Automatically cross encountered filemarks rather
- *                        than requiring an explicit FSF command.
- *                       Abort pending requests at end of media.
- *                       MTTELL was sometimes returning incorrect results.
- *                       Return the real block size in the MTIOCGET ioctl.
- *                       Some error recovery bug fixes.
- * Ver 1.10  Nov  5 96   Major reorganization.
- *                       Reduced CPU overhead a bit by eliminating internal
- *                        bounce buffers.
- *                       Added module support.
- *                       Added multiple tape drives support.
- *                       Added partition support.
- *                       Rewrote DSC handling.
- *                       Some portability fixes.
- *                       Removed ide-tape.h.
- *                       Additional minor changes.
- * Ver 1.11  Dec  2 96   Bug fix in previous DSC timeout handling.
- *                       Use ide_stall_queue() for DSC overlap.
- *                       Use the maximum speed rather than the current speed
- *                        to compute the request service time.
- * Ver 1.12  Dec  7 97   Fix random memory overwriting and/or last block data
- *                        corruption, which could occur if the total number
- *                        of bytes written to the tape was not an integral
- *                        number of tape blocks.
- *                       Add support for INTERRUPT DRQ devices.
- * Ver 1.13  Jan  2 98   Add "speed == 0" work-around for HP COLORADO 5GB
- * Ver 1.14  Dec 30 98   Partial fixes for the Sony/AIWA tape drives.
- *                       Replace cli()/sti() with hwgroup spinlocks.
- * Ver 1.15  Mar 25 99   Fix SMP race condition by replacing hwgroup
- *                        spinlock with private per-tape spinlock.
- * Ver 1.16  Sep  1 99   Add OnStream tape support.
- *                       Abort read pipeline on EOD.
- *                       Wait for the tape to become ready in case it returns
- *                        "in the process of becoming ready" on open().
- *                       Fix zero padding of the last written block in
- *                        case the tape block size is larger than PAGE_SIZE.
- *                       Decrease the default disconnection time to tn.
- * Ver 1.16e Oct  3 99   Minor fixes.
- * Ver 1.16e1 Oct 13 99  Patches by Arnold Niessen,
- *                          niessen@iae.nl / arnold.niessen@philips.com
- *                   GO-1)  Undefined code in idetape_read_position
- *                             according to Gadi's email
- *                   AJN-1) Minor fix asc == 11 should be asc == 0x11
- *                               in idetape_issue_packet_command (did effect
- *                               debugging output only)
- *                   AJN-2) Added more debugging output, and
- *                              added ide-tape: where missing. I would also
- *                             like to add tape->name where possible
- *                   AJN-3) Added different debug_level's 
- *                              via /proc/ide/hdc/settings
- *                             "debug_level" determines amount of debugging output;
- *                             can be changed using /proc/ide/hdx/settings
- *                             0 : almost no debugging output
- *                             1 : 0+output errors only
- *                             2 : 1+output all sensekey/asc
- *                             3 : 2+follow all chrdev related procedures
- *                             4 : 3+follow all procedures
- *                             5 : 4+include pc_stack rq_stack info
- *                             6 : 5+USE_COUNT updates
- *                   AJN-4) Fixed timeout for retension in idetape_queue_pc_tail
- *                             from 5 to 10 minutes
- *                   AJN-5) Changed maximum number of blocks to skip when
- *                              reading tapes with multiple consecutive write
- *                              errors from 100 to 1000 in idetape_get_logical_blk
- *                   Proposed changes to code:
- *                   1) output "logical_blk_num" via /proc
- *                   2) output "current_operation" via /proc
- *                   3) Either solve or document the fact that `mt rewind' is
- *                      required after reading from /dev/nhtx to be
- *                     able to rmmod the idetape module;
- *                     Also, sometimes an application finishes but the
- *                     device remains `busy' for some time. Same cause ?
- *                   Proposed changes to release-notes:
- *                  4) write a simple `quickstart' section in the
- *                      release notes; I volunteer if you don't want to
- *                  5) include a pointer to video4linux in the doc
- *                      to stimulate video applications
- *                   6) release notes lines 331 and 362: explain what happens
- *                     if the application data rate is higher than 1100 KB/s; 
- *                     similar approach to lower-than-500 kB/s ?
- *                  7) 6.6 Comparison; wouldn't it be better to allow different 
- *                     strategies for read and write ?
- *                     Wouldn't it be better to control the tape buffer
- *                     contents instead of the bandwidth ?
- *                  8) line 536: replace will by would (if I understand
- *                     this section correctly, a hypothetical and unwanted situation
- *                      is being described)
- * Ver 1.16f Dec 15 99   Change place of the secondary OnStream header frames.
- * Ver 1.17  Nov 2000 / Jan 2001  Marcel Mol, marcel@mesa.nl
- *                     - Add idetape_onstream_mode_sense_tape_parameter_page
- *                       function to get tape capacity in frames: tape->capacity.
- *                     - Add support for DI-50 drives( or any DI- drive).
- *                     - 'workaround' for read error/blank block around block 3000.
- *                     - Implement Early warning for end of media for Onstream.
- *                     - Cosmetic code changes for readability.
- *                     - Idetape_position_tape should not use SKIP bit during
- *                       Onstream read recovery.
- *                     - Add capacity, logical_blk_num and first/last_frame_position
- *                       to /proc/ide/hd?/settings.
- *                     - Module use count was gone in the Linux 2.4 driver.
- * Ver 1.17a Apr 2001 Willem Riede osst@riede.org
- *                     - Get drive's actual block size from mode sense block descriptor
- *                     - Limit size of pipeline
- * Ver 1.17b Oct 2002   Alan Stern <stern@rowland.harvard.edu>
- *                     Changed IDETAPE_MIN_PIPELINE_STAGES to 1 and actually used
- *                      it in the code!
- *                     Actually removed aborted stages in idetape_abort_pipeline
- *                      instead of just changing the command code.
- *                     Made the transfer byte count for Request Sense equal to the
- *                      actual length of the data transfer.
- *                     Changed handling of partial data transfers: they do not
- *                      cause DMA errors.
- *                     Moved initiation of DMA transfers to the correct place.
- *                     Removed reference to unallocated memory.
- *                     Made __idetape_discard_read_pipeline return the number of
- *                      sectors skipped, not the number of stages.
- *                     Replaced errant kfree() calls with __idetape_kfree_stage().
- *                     Fixed off-by-one error in testing the pipeline length.
- *                     Fixed handling of filemarks in the read pipeline.
- *                     Small code optimization for MTBSF and MTBSFM ioctls.
- *                     Don't try to unlock the door during device close if is
- *                      already unlocked!
- *                     Cosmetic fixes to miscellaneous debugging output messages.
- *                     Set the minimum /proc/ide/hd?/settings values for "pipeline",
- *                      "pipeline_min", and "pipeline_max" to 1.
- *
- * Here are some words from the first releases of hd.c, which are quoted
- * in ide.c and apply here as well:
- *
- * | Special care is recommended.  Have Fun!
  *
+ * For a historical changelog see
+ * Documentation/ide/ChangeLog.ide-tape.1995-2002
  */
 
-/*
- * An overview of the pipelined operation mode.
- *
- * In the pipelined write mode, we will usually just add requests to our
- * pipeline and return immediately, before we even start to service them. The
- * user program will then have enough time to prepare the next request while
- * we are still busy servicing previous requests. In the pipelined read mode,
- * the situation is similar - we add read-ahead requests into the pipeline,
- * before the user even requested them.
- *
- * The pipeline can be viewed as a "safety net" which will be activated when
- * the system load is high and prevents the user backup program from keeping up
- * with the current tape speed. At this point, the pipeline will get
- * shorter and shorter but the tape will still be streaming at the same speed.
- * Assuming we have enough pipeline stages, the system load will hopefully
- * decrease before the pipeline is completely empty, and the backup program
- * will be able to "catch up" and refill the pipeline again.
- * 
- * When using the pipelined mode, it would be best to disable any type of
- * buffering done by the user program, as ide-tape already provides all the
- * benefits in the kernel, where it can be done in a more efficient way.
- * As we will usually not block the user program on a request, the most
- * efficient user code will then be a simple read-write-read-... cycle.
- * Any additional logic will usually just slow down the backup process.
- *
- * Using the pipelined mode, I get a constant over 400 KBps throughput,
- * which seems to be the maximum throughput supported by my tape.
- *
- * However, there are some downfalls:
- *
- *     1.      We use memory (for data buffers) in proportional to the number
- *             of pipeline stages (each stage is about 26 KB with my tape).
- *     2.      In the pipelined write mode, we cheat and postpone error codes
- *             to the user task. In read mode, the actual tape position
- *             will be a bit further than the last requested block.
- *
- * Concerning (1):
- *
- *     1.      We allocate stages dynamically only when we need them. When
- *             we don't need them, we don't consume additional memory. In
- *             case we can't allocate stages, we just manage without them
- *             (at the expense of decreased throughput) so when Linux is
- *             tight in memory, we will not pose additional difficulties.
- *
- *     2.      The maximum number of stages (which is, in fact, the maximum
- *             amount of memory) which we allocate is limited by the compile
- *             time parameter IDETAPE_MAX_PIPELINE_STAGES.
- *
- *     3.      The maximum number of stages is a controlled parameter - We
- *             don't start from the user defined maximum number of stages
- *             but from the lower IDETAPE_MIN_PIPELINE_STAGES (again, we
- *             will not even allocate this amount of stages if the user
- *             program can't handle the speed). We then implement a feedback
- *             loop which checks if the pipeline is empty, and if it is, we
- *             increase the maximum number of stages as necessary until we
- *             reach the optimum value which just manages to keep the tape
- *             busy with minimum allocated memory or until we reach
- *             IDETAPE_MAX_PIPELINE_STAGES.
- *
- * Concerning (2):
- *
- *     In pipelined write mode, ide-tape can not return accurate error codes
- *     to the user program since we usually just add the request to the
- *      pipeline without waiting for it to be serviced. In case an error
- *      occurs, I will report it on the next user request.
- *
- *     In the pipelined read mode, subsequent read requests or forward
- *     filemark spacing will perform correctly, as we preserve all blocks
- *     and filemarks which we encountered during our excess read-ahead.
- * 
- *     For accurate tape positioning and error reporting, disabling
- *     pipelined mode might be the best option.
- *
- * You can enable/disable/tune the pipelined operation mode by adjusting
- * the compile time parameters below.
- */
-
-/*
- *     Possible improvements.
- *
- *     1.      Support for the ATAPI overlap protocol.
- *
- *             In order to maximize bus throughput, we currently use the DSC
- *             overlap method which enables ide.c to service requests from the
- *             other device while the tape is busy executing a command. The
- *             DSC overlap method involves polling the tape's status register
- *             for the DSC bit, and servicing the other device while the tape
- *             isn't ready.
- *
- *             In the current QIC development standard (December 1995),
- *             it is recommended that new tape drives will *in addition* 
- *             implement the ATAPI overlap protocol, which is used for the
- *             same purpose - efficient use of the IDE bus, but is interrupt
- *             driven and thus has much less CPU overhead.
- *
- *             ATAPI overlap is likely to be supported in most new ATAPI
- *             devices, including new ATAPI cdroms, and thus provides us
- *             a method by which we can achieve higher throughput when
- *             sharing a (fast) ATA-2 disk with any (slow) new ATAPI device.
- */
-
-#define IDETAPE_VERSION "1.19"
+#define IDETAPE_VERSION "1.20"
 
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/completion.h>
 #include <linux/bitops.h>
 #include <linux/mutex.h>
+#include <scsi/scsi.h>
 
 #include <asm/byteorder.h>
-#include <asm/irq.h>
-#include <asm/uaccess.h>
-#include <asm/io.h>
+#include <linux/irq.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
 #include <asm/unaligned.h>
+#include <linux/mtio.h>
 
-/*
- * partition
- */
-typedef struct os_partition_s {
-       __u8    partition_num;
-       __u8    par_desc_ver;
-       __u16   wrt_pass_cntr;
-       __u32   first_frame_addr;
-       __u32   last_frame_addr;
-       __u32   eod_frame_addr;
-} os_partition_t;
-
-/*
- * DAT entry
- */
-typedef struct os_dat_entry_s {
-       __u32   blk_sz;
-       __u16   blk_cnt;
-       __u8    flags;
-       __u8    reserved;
-} os_dat_entry_t;
-
-/*
- * DAT
- */
-#define OS_DAT_FLAGS_DATA      (0xc)
-#define OS_DAT_FLAGS_MARK      (0x1)
+enum {
+       /* output errors only */
+       DBG_ERR =               (1 << 0),
+       /* output all sense key/asc */
+       DBG_SENSE =             (1 << 1),
+       /* info regarding all chrdev-related procedures */
+       DBG_CHRDEV =            (1 << 2),
+       /* all remaining procedures */
+       DBG_PROCS =             (1 << 3),
+       /* buffer alloc info (pc_stack & rq_stack) */
+       DBG_PCRQ_STACK =        (1 << 4),
+};
 
-typedef struct os_dat_s {
-       __u8            dat_sz;
-       __u8            reserved1;
-       __u8            entry_cnt;
-       __u8            reserved3;
-       os_dat_entry_t  dat_list[16];
-} os_dat_t;
+/* define to see debug info */
+#define IDETAPE_DEBUG_LOG              0
 
-#include <linux/mtio.h>
+#if IDETAPE_DEBUG_LOG
+#define debug_log(lvl, fmt, args...)                   \
+{                                                      \
+       if (tape->debug_mask & lvl)                     \
+       printk(KERN_INFO "ide-tape: " fmt, ## args);    \
+}
+#else
+#define debug_log(lvl, fmt, args...) do {} while (0)
+#endif
 
 /**************************** Tunable parameters *****************************/
 
 
 /*
- *     Pipelined mode parameters.
+ * Pipelined mode parameters.
  *
- *     We try to use the minimum number of stages which is enough to
- *     keep the tape constantly streaming. To accomplish that, we implement
- *     a feedback loop around the maximum number of stages:
+ * We try to use the minimum number of stages which is enough to keep the tape
+ * constantly streaming. To accomplish that, we implement a feedback loop around
+ * the maximum number of stages:
  *
- *     We start from MIN maximum stages (we will not even use MIN stages
- *      if we don't need them), increment it by RATE*(MAX-MIN)
- *     whenever we sense that the pipeline is empty, until we reach
- *     the optimum value or until we reach MAX.
+ * We start from MIN maximum stages (we will not even use MIN stages if we don't
+ * need them), increment it by RATE*(MAX-MIN) whenever we sense that the
+ * pipeline is empty, until we reach the optimum value or until we reach MAX.
  *
- *     Setting the following parameter to 0 is illegal: the pipelined mode
- *     cannot be disabled (calculate_speeds() divides by tape->max_stages.)
+ * Setting the following parameter to 0 is illegal: the pipelined mode cannot be
+ * disabled (idetape_calculate_speeds() divides by tape->max_stages.)
  */
 #define IDETAPE_MIN_PIPELINE_STAGES      1
 #define IDETAPE_MAX_PIPELINE_STAGES    400
 #define IDETAPE_INCREASE_STAGES_RATE    20
 
 /*
- *     The following are used to debug the driver:
- *
- *     Setting IDETAPE_DEBUG_INFO to 1 will report device capabilities.
- *     Setting IDETAPE_DEBUG_LOG to 1 will log driver flow control.
- *     Setting IDETAPE_DEBUG_BUGS to 1 will enable self-sanity checks in
- *     some places.
- *
- *     Setting them to 0 will restore normal operation mode:
- *
- *             1.      Disable logging normal successful operations.
- *             2.      Disable self-sanity checks.
- *             3.      Errors will still be logged, of course.
- *
- *     All the #if DEBUG code will be removed some day, when the driver
- *     is verified to be stable enough. This will make it much more
- *     esthetic.
- */
-#define IDETAPE_DEBUG_INFO             0
-#define IDETAPE_DEBUG_LOG              0
-#define IDETAPE_DEBUG_BUGS             1
-
-/*
- *     After each failed packet command we issue a request sense command
- *     and retry the packet command IDETAPE_MAX_PC_RETRIES times.
+ * After each failed packet command we issue a request sense command and retry
+ * the packet command IDETAPE_MAX_PC_RETRIES times.
  *
- *     Setting IDETAPE_MAX_PC_RETRIES to 0 will disable retries.
+ * Setting IDETAPE_MAX_PC_RETRIES to 0 will disable retries.
  */
 #define IDETAPE_MAX_PC_RETRIES         3
 
 /*
- *     With each packet command, we allocate a buffer of
- *     IDETAPE_PC_BUFFER_SIZE bytes. This is used for several packet
- *     commands (Not for READ/WRITE commands).
+ * With each packet command, we allocate a buffer of IDETAPE_PC_BUFFER_SIZE
+ * bytes. This is used for several packet commands (Not for READ/WRITE commands)
  */
 #define IDETAPE_PC_BUFFER_SIZE         256
 
@@ -562,48 +121,39 @@ typedef struct os_dat_s {
 #define IDETAPE_WAIT_CMD               (900*HZ)
 
 /*
- *     The following parameter is used to select the point in the internal
- *     tape fifo in which we will start to refill the buffer. Decreasing
- *     the following parameter will improve the system's latency and
- *     interactive response, while using a high value might improve system
- *     throughput.
+ * The following parameter is used to select the point in the internal tape fifo
+ * in which we will start to refill the buffer. Decreasing the following
+ * parameter will improve the system's latency and interactive response, while
+ * using a high value might improve system throughput.
  */
-#define IDETAPE_FIFO_THRESHOLD                 2
+#define IDETAPE_FIFO_THRESHOLD         2
 
 /*
- *     DSC polling parameters.
- *
- *     Polling for DSC (a single bit in the status register) is a very
- *     important function in ide-tape. There are two cases in which we
- *     poll for DSC:
+ * DSC polling parameters.
  *
- *     1.      Before a read/write packet command, to ensure that we
- *             can transfer data from/to the tape's data buffers, without
- *             causing an actual media access. In case the tape is not
- *             ready yet, we take out our request from the device
- *             request queue, so that ide.c will service requests from
- *             the other device on the same interface meanwhile.
+ * Polling for DSC (a single bit in the status register) is a very important
+ * function in ide-tape. There are two cases in which we poll for DSC:
  *
- *     2.      After the successful initialization of a "media access
- *             packet command", which is a command which can take a long
- *             time to complete (it can be several seconds or even an hour).
+ * 1. Before a read/write packet command, to ensure that we can transfer data
+ * from/to the tape's data buffers, without causing an actual media access.
+ * In case the tape is not ready yet, we take out our request from the device
+ * request queue, so that ide.c could service requests from the other device
+ * on the same interface in the meantime.
  *
- *             Again, we postpone our request in the middle to free the bus
- *             for the other device. The polling frequency here should be
- *             lower than the read/write frequency since those media access
- *             commands are slow. We start from a "fast" frequency -
- *             IDETAPE_DSC_MA_FAST (one second), and if we don't receive DSC
- *             after IDETAPE_DSC_MA_THRESHOLD (5 minutes), we switch it to a
- *             lower frequency - IDETAPE_DSC_MA_SLOW (1 minute).
+ * 2. After the successful initialization of a "media access packet command",
+ * which is a command that can take a long time to complete (the interval can
+ * range from several seconds to even an hour). Again, we postpone our request
+ * in the middle to free the bus for the other device. The polling frequency
+ * here should be lower than the read/write frequency since those media access
+ * commands are slow. We start from a "fast" frequency - IDETAPE_DSC_MA_FAST
+ * (1 second), and if we don't receive DSC after IDETAPE_DSC_MA_THRESHOLD
+ * (5 min), we switch it to a lower frequency - IDETAPE_DSC_MA_SLOW (1 min).
  *
- *     We also set a timeout for the timer, in case something goes wrong.
- *     The timeout should be longer then the maximum execution time of a
- *     tape operation.
- */
-/*
- *     DSC timings.
+ * We also set a timeout for the timer, in case something goes wrong. The
+ * timeout should be longer then the maximum execution time of a tape operation.
  */
+
+/* DSC timings. */
 #define IDETAPE_DSC_RW_MIN             5*HZ/100        /* 50 msec */
 #define IDETAPE_DSC_RW_MAX             40*HZ/100       /* 400 msec */
 #define IDETAPE_DSC_RW_TIMEOUT         2*60*HZ         /* 2 minutes */
@@ -614,19 +164,15 @@ typedef struct os_dat_s {
 
 /*************************** End of tunable parameters ***********************/
 
-/*
- *     Read/Write error simulation
- */
+/* Read/Write error simulation */
 #define SIMULATE_ERRORS                        0
 
-/*
- *     For general magnetic tape device compatibility.
- */
-typedef enum {
-       idetape_direction_none,
-       idetape_direction_read,
-       idetape_direction_write
-} idetape_chrdev_direction_t;
+/* tape directions */
+enum {
+       IDETAPE_DIR_NONE  = (1 << 0),
+       IDETAPE_DIR_READ  = (1 << 1),
+       IDETAPE_DIR_WRITE = (1 << 2),
+};
 
 struct idetape_bh {
        u32 b_size;
@@ -635,24 +181,32 @@ struct idetape_bh {
        char *b_data;
 };
 
-/*
- *     Our view of a packet command.
- */
 typedef struct idetape_packet_command_s {
-       u8 c[12];                               /* Actual packet bytes */
-       int retries;                            /* On each retry, we increment retries */
-       int error;                              /* Error code */
-       int request_transfer;                   /* Bytes to transfer */
-       int actually_transferred;               /* Bytes actually transferred */
-       int buffer_size;                        /* Size of our data buffer */
+       /* Actual packet bytes */
+       u8 c[12];
+       /* On each retry, we increment retries */
+       int retries;
+       /* Error code */
+       int error;
+       /* Bytes to transfer */
+       int request_transfer;
+       /* Bytes actually transferred */
+       int actually_transferred;
+       /* Size of our data buffer */
+       int buffer_size;
        struct idetape_bh *bh;
        char *b_data;
        int b_count;
-       u8 *buffer;                             /* Data buffer */
-       u8 *current_position;                   /* Pointer into the above buffer */
-       ide_startstop_t (*callback) (ide_drive_t *);    /* Called when this packet command is completed */
-       u8 pc_buffer[IDETAPE_PC_BUFFER_SIZE];   /* Temporary buffer */
-       unsigned long flags;                    /* Status/Action bit flags: long for set_bit */
+       /* Data buffer */
+       u8 *buffer;
+       /* Pointer into the above buffer */
+       u8 *current_position;
+       /* Called when this packet command is completed */
+       ide_startstop_t (*callback) (ide_drive_t *);
+       /* Temporary buffer */
+       u8 pc_buffer[IDETAPE_PC_BUFFER_SIZE];
+       /* Status/Action bit flags: long for set_bit */
+       unsigned long flags;
 } idetape_pc_t;
 
 /*
@@ -671,68 +225,7 @@ typedef struct idetape_packet_command_s {
 /* Data direction */
 #define        PC_WRITING                      5
 
-/*
- *     Capabilities and Mechanical Status Page
- */
-typedef struct {
-       unsigned        page_code       :6;     /* Page code - Should be 0x2a */
-       __u8            reserved0_6     :1;
-       __u8            ps              :1;     /* parameters saveable */
-       __u8            page_length;            /* Page Length - Should be 0x12 */
-       __u8            reserved2, reserved3;
-       unsigned        ro              :1;     /* Read Only Mode */
-       unsigned        reserved4_1234  :4;
-       unsigned        sprev           :1;     /* Supports SPACE in the reverse direction */
-       unsigned        reserved4_67    :2;
-       unsigned        reserved5_012   :3;
-       unsigned        efmt            :1;     /* Supports ERASE command initiated formatting */
-       unsigned        reserved5_4     :1;
-       unsigned        qfa             :1;     /* Supports the QFA two partition formats */
-       unsigned        reserved5_67    :2;
-       unsigned        lock            :1;     /* Supports locking the volume */
-       unsigned        locked          :1;     /* The volume is locked */
-       unsigned        prevent         :1;     /* The device defaults in the prevent state after power up */   
-       unsigned        eject           :1;     /* The device can eject the volume */
-       __u8            disconnect      :1;     /* The device can break request > ctl */        
-       __u8            reserved6_5     :1;
-       unsigned        ecc             :1;     /* Supports error correction */
-       unsigned        cmprs           :1;     /* Supports data compression */
-       unsigned        reserved7_0     :1;
-       unsigned        blk512          :1;     /* Supports 512 bytes block size */
-       unsigned        blk1024         :1;     /* Supports 1024 bytes block size */
-       unsigned        reserved7_3_6   :4;
-       unsigned        blk32768        :1;     /* slowb - the device restricts the byte count for PIO */
-                                               /* transfers for slow buffer memory ??? */
-                                               /* Also 32768 block size in some cases */
-       __u16           max_speed;              /* Maximum speed supported in KBps */
-       __u8            reserved10, reserved11;
-       __u16           ctl;                    /* Continuous Transfer Limit in blocks */
-       __u16           speed;                  /* Current Speed, in KBps */
-       __u16           buffer_size;            /* Buffer Size, in 512 bytes */
-       __u8            reserved18, reserved19;
-} idetape_capabilities_page_t;
-
-/*
- *     Block Size Page
- */
-typedef struct {
-       unsigned        page_code       :6;     /* Page code - Should be 0x30 */
-       unsigned        reserved1_6     :1;
-       unsigned        ps              :1;
-       __u8            page_length;            /* Page Length - Should be 2 */
-       __u8            reserved2;
-       unsigned        play32          :1;
-       unsigned        play32_5        :1;
-       unsigned        reserved2_23    :2;
-       unsigned        record32        :1;
-       unsigned        record32_5      :1;
-       unsigned        reserved2_6     :1;
-       unsigned        one             :1;
-} idetape_block_size_page_t;
-
-/*
- *     A pipeline stage.
- */
+/* A pipeline stage. */
 typedef struct idetape_stage_s {
        struct request rq;                      /* The corresponding request */
        struct idetape_bh *bh;                  /* The data buffers */
@@ -740,35 +233,8 @@ typedef struct idetape_stage_s {
 } idetape_stage_t;
 
 /*
- *     REQUEST SENSE packet command result - Data Format.
- */
-typedef struct {
-       unsigned        error_code      :7;     /* Current of deferred errors */
-       unsigned        valid           :1;     /* The information field conforms to QIC-157C */
-       __u8            reserved1       :8;     /* Segment Number - Reserved */
-       unsigned        sense_key       :4;     /* Sense Key */
-       unsigned        reserved2_4     :1;     /* Reserved */
-       unsigned        ili             :1;     /* Incorrect Length Indicator */
-       unsigned        eom             :1;     /* End Of Medium */
-       unsigned        filemark        :1;     /* Filemark */
-       __u32           information __attribute__ ((packed));
-       __u8            asl;                    /* Additional sense length (n-7) */
-       __u32           command_specific;       /* Additional command specific information */
-       __u8            asc;                    /* Additional Sense Code */
-       __u8            ascq;                   /* Additional Sense Code Qualifier */
-       __u8            replaceable_unit_code;  /* Field Replaceable Unit Code */
-       unsigned        sk_specific1    :7;     /* Sense Key Specific */
-       unsigned        sksv            :1;     /* Sense Key Specific information is valid */
-       __u8            sk_specific2;           /* Sense Key Specific */
-       __u8            sk_specific3;           /* Sense Key Specific */
-       __u8            pad[2];                 /* Padding to 20 bytes */
-} idetape_request_sense_result_t;
-
-
-/*
- *     Most of our global data which we need to save even as we leave the
- *     driver due to an interrupt or a timer event is stored in a variable
- *     of type idetape_tape_t, defined below.
+ * Most of our global data which we need to save even as we leave the driver due
+ * to an interrupt or a timer event is stored in the struct defined below.
  */
 typedef struct ide_tape_obj {
        ide_drive_t     *drive;
@@ -804,15 +270,14 @@ typedef struct ide_tape_obj {
        int rq_stack_index;
 
        /*
-        *      DSC polling variables.
+        * DSC polling variables.
         *
-        *      While polling for DSC we use postponed_rq to postpone the
-        *      current request so that ide.c will be able to service
-        *      pending requests on the other device. Note that at most
-        *      we will have only one DSC (usually data transfer) request
-        *      in the device request queue. Additional requests can be
-        *      queued in our internal pipeline, but they will be visible
-        *      to ide.c only one at a time.
+        * While polling for DSC we use postponed_rq to postpone the current
+        * request so that ide.c will be able to service pending requests on the
+        * other device. Note that at most we will have only one DSC (usually
+        * data transfer) request in the device request queue. Additional
+        * requests can be queued in our internal pipeline, but they will be
+        * visible to ide.c only one at a time.
         */
        struct request *postponed_rq;
        /* The time in which we started polling for DSC */
@@ -820,72 +285,57 @@ typedef struct ide_tape_obj {
        /* Timer used to poll for dsc */
        struct timer_list dsc_timer;
        /* Read/Write dsc polling frequency */
-       unsigned long best_dsc_rw_frequency;
-       /* The current polling frequency */
-       unsigned long dsc_polling_frequency;
-       /* Maximum waiting time */
+       unsigned long best_dsc_rw_freq;
+       unsigned long dsc_poll_freq;
        unsigned long dsc_timeout;
 
-       /*
-        *      Read position information
-        */
+       /* Read position information */
        u8 partition;
        /* Current block */
-       unsigned int first_frame_position;
-       unsigned int last_frame_position;
-       unsigned int blocks_in_buffer;
+       unsigned int first_frame;
 
-       /*
-        *      Last error information
-        */
+       /* Last error information */
        u8 sense_key, asc, ascq;
 
-       /*
-        *      Character device operation
-        */
+       /* Character device operation */
        unsigned int minor;
        /* device name */
        char name[4];
        /* Current character device data transfer direction */
-       idetape_chrdev_direction_t chrdev_direction;
+       u8 chrdev_dir;
 
-       /*
-        *      Device information
-        */
-       /* Usually 512 or 1024 bytes */
-       unsigned short tape_block_size;
+       /* tape block size, usually 512 or 1024 bytes */
+       unsigned short blk_size;
        int user_bs_factor;
+
        /* Copy of the tape's Capabilities and Mechanical Page */
-       idetape_capabilities_page_t capabilities;
+       u8 caps[20];
 
        /*
-        *      Active data transfer request parameters.
+        * Active data transfer request parameters.
         *
-        *      At most, there is only one ide-tape originated data transfer
-        *      request in the device request queue. This allows ide.c to
-        *      easily service requests from the other device when we
-        *      postpone our active request. In the pipelined operation
-        *      mode, we use our internal pipeline structure to hold
-        *      more data requests.
-        *
-        *      The data buffer size is chosen based on the tape's
-        *      recommendation.
+        * At most, there is only one ide-tape originated data transfer request
+        * in the device request queue. This allows ide.c to easily service
+        * requests from the other device when we postpone our active request.
+        * In the pipelined operation mode, we use our internal pipeline
+        * structure to hold more data requests. The data buffer size is chosen
+        * based on the tape's recommendation.
         */
-       /* Pointer to the request which is waiting in the device request queue */
-       struct request *active_data_request;
-       /* Data buffer size (chosen based on the tape's recommendation */
+       /* ptr to the request which is waiting in the device request queue */
+       struct request *active_data_rq;
+       /* Data buffer size chosen based on the tape's recommendation */
        int stage_size;
        idetape_stage_t *merge_stage;
        int merge_stage_size;
        struct idetape_bh *bh;
        char *b_data;
        int b_count;
-       
+
        /*
-        *      Pipeline parameters.
+        * Pipeline parameters.
         *
-        *      To accomplish non-pipelined mode, we simply set the following
-        *      variables to zero (or NULL, where appropriate).
+        * To accomplish non-pipelined mode, we simply set the following
+        * variables to zero (or NULL, where appropriate).
         */
        /* Number of currently used stages */
        int nr_stages;
@@ -910,23 +360,13 @@ typedef struct ide_tape_obj {
        /* Status/Action flags: long for set_bit */
        unsigned long flags;
        /* protects the ide-tape queue */
-       spinlock_t spinlock;
+       spinlock_t lock;
 
-       /*
-        * Measures average tape speed
-        */
+       /* Measures average tape speed */
        unsigned long avg_time;
        int avg_size;
        int avg_speed;
 
-       /* last sense information */
-       idetape_request_sense_result_t sense;
-
-       char vendor_id[10];
-       char product_id[18];
-       char firmware_revision[6];
-       int firmware_revision_num;
-
        /* the door is currently locked */
        int door_locked;
        /* the tape hardware is write protected */
@@ -935,11 +375,9 @@ typedef struct ide_tape_obj {
        char write_prot;
 
        /*
-        * Limit the number of times a request can
-        * be postponed, to avoid an infinite postpone
-        * deadlock.
+        * Limit the number of times a request can be postponed, to avoid an
+        * infinite postpone deadlock.
         */
-       /* request postpone count limit */
        int postpone_cnt;
 
        /*
@@ -954,30 +392,19 @@ typedef struct ide_tape_obj {
        int tape_head;
        int last_tape_head;
 
-       /*
-        * Speed control at the tape buffers input/output
-        */
+       /* Speed control at the tape buffers input/output */
        unsigned long insert_time;
        int insert_size;
        int insert_speed;
        int max_insert_speed;
        int measure_insert_time;
 
-       /*
-        * Measure tape still time, in milliseconds
-        */
-       unsigned long tape_still_time_begin;
-       int tape_still_time;
-
-       /*
-        * Speed regulation negative feedback loop
-        */
+       /* Speed regulation negative feedback loop */
        int speed_control;
        int pipeline_head_speed;
        int controlled_pipeline_head_speed;
        int uncontrolled_pipeline_head_speed;
        int controlled_last_pipeline_head;
-       int uncontrolled_last_pipeline_head;
        unsigned long uncontrolled_pipeline_head_time;
        unsigned long controlled_pipeline_head_time;
        int controlled_previous_pipeline_head;
@@ -986,18 +413,7 @@ typedef struct ide_tape_obj {
        unsigned long uncontrolled_previous_head_time;
        int restart_speed_control_req;
 
-        /*
-         * Debug_level determines amount of debugging output;
-         * can be changed using /proc/ide/hdx/settings
-         * 0 : almost no debugging output
-         * 1 : 0+output errors only
-         * 2 : 1+output all sensekey/asc
-         * 3 : 2+follow all chrdev related procedures
-         * 4 : 3+follow all procedures
-         * 5 : 4+include pc_stack rq_stack info
-         * 6 : 5+USE_COUNT updates
-         */
-         int debug_level; 
+       u32 debug_mask;
 } idetape_tape_t;
 
 static DEFINE_MUTEX(idetape_ref_mutex);
@@ -1030,9 +446,7 @@ static void ide_tape_put(struct ide_tape_obj *tape)
        mutex_unlock(&idetape_ref_mutex);
 }
 
-/*
- *     Tape door status
- */
+/* Tape door status */
 #define DOOR_UNLOCKED                  0
 #define DOOR_LOCKED                    1
 #define DOOR_EXPLICITLY_LOCKED         2
@@ -1052,51 +466,23 @@ static void ide_tape_put(struct ide_tape_obj *tape)
 /* 0 = no tape is loaded, so we don't rewind after ejecting */
 #define IDETAPE_MEDIUM_PRESENT         9
 
-/*
- *     Supported ATAPI tape drives packet commands
- */
-#define IDETAPE_TEST_UNIT_READY_CMD    0x00
-#define IDETAPE_REWIND_CMD             0x01
-#define IDETAPE_REQUEST_SENSE_CMD      0x03
-#define IDETAPE_READ_CMD               0x08
-#define IDETAPE_WRITE_CMD              0x0a
-#define IDETAPE_WRITE_FILEMARK_CMD     0x10
-#define IDETAPE_SPACE_CMD              0x11
-#define IDETAPE_INQUIRY_CMD            0x12
-#define IDETAPE_ERASE_CMD              0x19
-#define IDETAPE_MODE_SENSE_CMD         0x1a
-#define IDETAPE_MODE_SELECT_CMD                0x15
-#define IDETAPE_LOAD_UNLOAD_CMD                0x1b
-#define IDETAPE_PREVENT_CMD            0x1e
-#define IDETAPE_LOCATE_CMD             0x2b
-#define IDETAPE_READ_POSITION_CMD      0x34
-#define IDETAPE_READ_BUFFER_CMD                0x3c
-#define IDETAPE_SET_SPEED_CMD          0xbb
-
-/*
- *     Some defines for the READ BUFFER command
- */
+/* A define for the READ BUFFER command */
 #define IDETAPE_RETRIEVE_FAULTY_BLOCK  6
 
-/*
- *     Some defines for the SPACE command
- */
+/* Some defines for the SPACE command */
 #define IDETAPE_SPACE_OVER_FILEMARK    1
 #define IDETAPE_SPACE_TO_EOD           3
 
-/*
- *     Some defines for the LOAD UNLOAD command
- */
+/* Some defines for the LOAD UNLOAD command */
 #define IDETAPE_LU_LOAD_MASK           1
 #define IDETAPE_LU_RETENSION_MASK      2
 #define IDETAPE_LU_EOT_MASK            4
 
 /*
- *     Special requests for our block device strategy routine.
+ * Special requests for our block device strategy routine.
  *
- *     In order to service a character device command, we add special
- *     requests to the tail of our block device request queue and wait
- *     for their completion.
+ * In order to service a character device command, we add special requests to
+ * the tail of our block device request queue and wait for their completion.
  */
 
 enum {
@@ -1107,171 +493,20 @@ enum {
        REQ_IDETAPE_READ_BUFFER = (1 << 4),
 };
 
-/*
- *     Error codes which are returned in rq->errors to the higher part
- *     of the driver.
- */
+/* Error codes returned in rq->errors to the higher part of the driver. */
 #define        IDETAPE_ERROR_GENERAL           101
 #define        IDETAPE_ERROR_FILEMARK          102
 #define        IDETAPE_ERROR_EOD               103
 
-/*
- *     The following is used to format the general configuration word of
- *     the ATAPI IDENTIFY DEVICE command.
- */
-struct idetape_id_gcw {        
-       unsigned packet_size            :2;     /* Packet Size */
-       unsigned reserved234            :3;     /* Reserved */
-       unsigned drq_type               :2;     /* Command packet DRQ type */
-       unsigned removable              :1;     /* Removable media */
-       unsigned device_type            :5;     /* Device type */
-       unsigned reserved13             :1;     /* Reserved */
-       unsigned protocol               :2;     /* Protocol type */
-};
-
-/*
- *     INQUIRY packet command - Data Format (From Table 6-8 of QIC-157C)
- */
-typedef struct {
-       unsigned        device_type     :5;     /* Peripheral Device Type */
-       unsigned        reserved0_765   :3;     /* Peripheral Qualifier - Reserved */
-       unsigned        reserved1_6t0   :7;     /* Reserved */
-       unsigned        rmb             :1;     /* Removable Medium Bit */
-       unsigned        ansi_version    :3;     /* ANSI Version */
-       unsigned        ecma_version    :3;     /* ECMA Version */
-       unsigned        iso_version     :2;     /* ISO Version */
-       unsigned        response_format :4;     /* Response Data Format */
-       unsigned        reserved3_45    :2;     /* Reserved */
-       unsigned        reserved3_6     :1;     /* TrmIOP - Reserved */
-       unsigned        reserved3_7     :1;     /* AENC - Reserved */
-       __u8            additional_length;      /* Additional Length (total_length-4) */
-       __u8            rsv5, rsv6, rsv7;       /* Reserved */
-       __u8            vendor_id[8];           /* Vendor Identification */
-       __u8            product_id[16];         /* Product Identification */
-       __u8            revision_level[4];      /* Revision Level */
-       __u8            vendor_specific[20];    /* Vendor Specific - Optional */
-       __u8            reserved56t95[40];      /* Reserved - Optional */
-                                               /* Additional information may be returned */
-} idetape_inquiry_result_t;
-
-/*
- *     READ POSITION packet command - Data Format (From Table 6-57)
- */
-typedef struct {
-       unsigned        reserved0_10    :2;     /* Reserved */
-       unsigned        bpu             :1;     /* Block Position Unknown */    
-       unsigned        reserved0_543   :3;     /* Reserved */
-       unsigned        eop             :1;     /* End Of Partition */
-       unsigned        bop             :1;     /* Beginning Of Partition */
-       u8              partition;              /* Partition Number */
-       u8              reserved2, reserved3;   /* Reserved */
-       u32             first_block;            /* First Block Location */
-       u32             last_block;             /* Last Block Location (Optional) */
-       u8              reserved12;             /* Reserved */
-       u8              blocks_in_buffer[3];    /* Blocks In Buffer - (Optional) */
-       u32             bytes_in_buffer;        /* Bytes In Buffer (Optional) */
-} idetape_read_position_result_t;
-
-/*
- *     Follows structures which are related to the SELECT SENSE / MODE SENSE
- *     packet commands. Those packet commands are still not supported
- *     by ide-tape.
- */
+/* Structures related to the SELECT SENSE / MODE SENSE packet commands. */
 #define IDETAPE_BLOCK_DESCRIPTOR       0
 #define        IDETAPE_CAPABILITIES_PAGE       0x2a
-#define IDETAPE_PARAMTR_PAGE           0x2b   /* Onstream DI-x0 only */
-#define IDETAPE_BLOCK_SIZE_PAGE                0x30
-#define IDETAPE_BUFFER_FILLING_PAGE    0x33
-
-/*
- *     Mode Parameter Header for the MODE SENSE packet command
- */
-typedef struct {
-       __u8    mode_data_length;       /* Length of the following data transfer */
-       __u8    medium_type;            /* Medium Type */
-       __u8    dsp;                    /* Device Specific Parameter */
-       __u8    bdl;                    /* Block Descriptor Length */
-#if 0
-       /* data transfer page */
-       __u8    page_code       :6;
-       __u8    reserved0_6     :1;
-       __u8    ps              :1;     /* parameters saveable */
-       __u8    page_length;            /* page Length == 0x02 */
-       __u8    reserved2;
-       __u8    read32k         :1;     /* 32k blk size (data only) */
-       __u8    read32k5        :1;     /* 32.5k blk size (data&AUX) */
-       __u8    reserved3_23    :2;
-       __u8    write32k        :1;     /* 32k blk size (data only) */
-       __u8    write32k5       :1;     /* 32.5k blk size (data&AUX) */
-       __u8    reserved3_6     :1;
-       __u8    streaming       :1;     /* streaming mode enable */
-#endif
-} idetape_mode_parameter_header_t;
-
-/*
- *     Mode Parameter Block Descriptor the MODE SENSE packet command
- *
- *     Support for block descriptors is optional.
- */
-typedef struct {
-       __u8            density_code;           /* Medium density code */
-       __u8            blocks[3];              /* Number of blocks */
-       __u8            reserved4;              /* Reserved */
-       __u8            length[3];              /* Block Length */
-} idetape_parameter_block_descriptor_t;
-
-/*
- *     The Data Compression Page, as returned by the MODE SENSE packet command.
- */
-typedef struct {
-       unsigned        page_code       :6;     /* Page Code - Should be 0xf */
-       unsigned        reserved0       :1;     /* Reserved */
-       unsigned        ps              :1;
-       __u8            page_length;            /* Page Length - Should be 14 */
-       unsigned        reserved2       :6;     /* Reserved */
-       unsigned        dcc             :1;     /* Data Compression Capable */
-       unsigned        dce             :1;     /* Data Compression Enable */
-       unsigned        reserved3       :5;     /* Reserved */
-       unsigned        red             :2;     /* Report Exception on Decompression */
-       unsigned        dde             :1;     /* Data Decompression Enable */
-       __u32           ca;                     /* Compression Algorithm */
-       __u32           da;                     /* Decompression Algorithm */
-       __u8            reserved[4];            /* Reserved */
-} idetape_data_compression_page_t;
-
-/*
- *     The Medium Partition Page, as returned by the MODE SENSE packet command.
- */
-typedef struct {
-       unsigned        page_code       :6;     /* Page Code - Should be 0x11 */
-       unsigned        reserved1_6     :1;     /* Reserved */
-       unsigned        ps              :1;
-       __u8            page_length;            /* Page Length - Should be 6 */
-       __u8            map;                    /* Maximum Additional Partitions - Should be 0 */
-       __u8            apd;                    /* Additional Partitions Defined - Should be 0 */
-       unsigned        reserved4_012   :3;     /* Reserved */
-       unsigned        psum            :2;     /* Should be 0 */
-       unsigned        idp             :1;     /* Should be 0 */
-       unsigned        sdp             :1;     /* Should be 0 */
-       unsigned        fdp             :1;     /* Fixed Data Partitions */
-       __u8            mfr;                    /* Medium Format Recognition */
-       __u8            reserved[2];            /* Reserved */
-} idetape_medium_partition_page_t;
-
-/*
- *     Run time configurable parameters.
- */
-typedef struct {
-       int     dsc_rw_frequency;
-       int     dsc_media_access_frequency;
-       int     nr_stages;
-} idetape_config_t;
 
 /*
- *     The variables below are used for the character device interface.
- *     Additional state variables are defined in our ide_drive_t structure.
+ * The variables below are used for the character device interface. Additional
+ * state variables are defined in our ide_drive_t structure.
  */
-static struct ide_tape_obj * idetape_devs[MAX_HWIFS * MAX_DRIVES];
+static struct ide_tape_obj *idetape_devs[MAX_HWIFS * MAX_DRIVES];
 
 #define ide_tape_f(file) ((file)->private_data)
 
@@ -1287,39 +522,34 @@ static struct ide_tape_obj *ide_tape_chrdev_get(unsigned int i)
        return tape;
 }
 
-/*
- *      Function declarations
- *
- */
-static int idetape_chrdev_release (struct inode *inode, struct file *filp);
-static void idetape_write_release (ide_drive_t *drive, unsigned int minor);
-
 /*
  * Too bad. The drive wants to send us data which we are not ready to accept.
  * Just throw it away.
  */
-static void idetape_discard_data (ide_drive_t *drive, unsigned int bcount)
+static void idetape_discard_data(ide_drive_t *drive, unsigned int bcount)
 {
        while (bcount--)
                (void) HWIF(drive)->INB(IDE_DATA_REG);
 }
 
-static void idetape_input_buffers (ide_drive_t *drive, idetape_pc_t *pc, unsigned int bcount)
+static void idetape_input_buffers(ide_drive_t *drive, idetape_pc_t *pc,
+                                 unsigned int bcount)
 {
        struct idetape_bh *bh = pc->bh;
        int count;
 
        while (bcount) {
-#if IDETAPE_DEBUG_BUGS
                if (bh == NULL) {
                        printk(KERN_ERR "ide-tape: bh == NULL in "
                                "idetape_input_buffers\n");
                        idetape_discard_data(drive, bcount);
                        return;
                }
-#endif /* IDETAPE_DEBUG_BUGS */
-               count = min((unsigned int)(bh->b_size - atomic_read(&bh->b_count)), bcount);
-               HWIF(drive)->atapi_input_bytes(drive, bh->b_data + atomic_read(&bh->b_count), count);
+               count = min(
+                       (unsigned int)(bh->b_size - atomic_read(&bh->b_count)),
+                       bcount);
+               HWIF(drive)->atapi_input_bytes(drive, bh->b_data +
+                                       atomic_read(&bh->b_count), count);
                bcount -= count;
                atomic_add(count, &bh->b_count);
                if (atomic_read(&bh->b_count) == bh->b_size) {
@@ -1331,26 +561,26 @@ static void idetape_input_buffers (ide_drive_t *drive, idetape_pc_t *pc, unsigne
        pc->bh = bh;
 }
 
-static void idetape_output_buffers (ide_drive_t *drive, idetape_pc_t *pc, unsigned int bcount)
+static void idetape_output_buffers(ide_drive_t *drive, idetape_pc_t *pc,
+                                  unsigned int bcount)
 {
        struct idetape_bh *bh = pc->bh;
        int count;
 
        while (bcount) {
-#if IDETAPE_DEBUG_BUGS
                if (bh == NULL) {
-                       printk(KERN_ERR "ide-tape: bh == NULL in "
-                               "idetape_output_buffers\n");
+                       printk(KERN_ERR "ide-tape: bh == NULL in %s\n",
+                                       __func__);
                        return;
                }
-#endif /* IDETAPE_DEBUG_BUGS */
                count = min((unsigned int)pc->b_count, (unsigned int)bcount);
                HWIF(drive)->atapi_output_bytes(drive, pc->b_data, count);
                bcount -= count;
                pc->b_data += count;
                pc->b_count -= count;
                if (!pc->b_count) {
-                       pc->bh = bh = bh->b_reqnext;
+                       bh = bh->b_reqnext;
+                       pc->bh = bh;
                        if (bh) {
                                pc->b_data = bh->b_data;
                                pc->b_count = atomic_read(&bh->b_count);
@@ -1359,7 +589,7 @@ static void idetape_output_buffers (ide_drive_t *drive, idetape_pc_t *pc, unsign
        }
 }
 
-static void idetape_update_buffers (idetape_pc_t *pc)
+static void idetape_update_buffers(idetape_pc_t *pc)
 {
        struct idetape_bh *bh = pc->bh;
        int count;
@@ -1368,13 +598,11 @@ static void idetape_update_buffers (idetape_pc_t *pc)
        if (test_bit(PC_WRITING, &pc->flags))
                return;
        while (bcount) {
-#if IDETAPE_DEBUG_BUGS
                if (bh == NULL) {
-                       printk(KERN_ERR "ide-tape: bh == NULL in "
-                               "idetape_update_buffers\n");
+                       printk(KERN_ERR "ide-tape: bh == NULL in %s\n",
+                                       __func__);
                        return;
                }
-#endif /* IDETAPE_DEBUG_BUGS */
                count = min((unsigned int)bh->b_size, (unsigned int)bcount);
                atomic_set(&bh->b_count, count);
                if (atomic_read(&bh->b_count) == bh->b_size)
@@ -1390,17 +618,14 @@ static void idetape_update_buffers (idetape_pc_t *pc)
  *     driver. A storage space for a maximum of IDETAPE_PC_STACK packet
  *     commands is allocated at initialization time.
  */
-static idetape_pc_t *idetape_next_pc_storage (ide_drive_t *drive)
+static idetape_pc_t *idetape_next_pc_storage(ide_drive_t *drive)
 {
        idetape_tape_t *tape = drive->driver_data;
 
-#if IDETAPE_DEBUG_LOG
-       if (tape->debug_level >= 5)
-               printk(KERN_INFO "ide-tape: pc_stack_index=%d\n",
-                       tape->pc_stack_index);
-#endif /* IDETAPE_DEBUG_LOG */
+       debug_log(DBG_PCRQ_STACK, "pc_stack_index=%d\n", tape->pc_stack_index);
+
        if (tape->pc_stack_index == IDETAPE_PC_STACK)
-               tape->pc_stack_index=0;
+               tape->pc_stack_index = 0;
        return (&tape->pc_stack[tape->pc_stack_index++]);
 }
 
@@ -1409,32 +634,26 @@ static idetape_pc_t *idetape_next_pc_storage (ide_drive_t *drive)
  *     Since we queue packet commands in the request queue, we need to
  *     allocate a request, along with the allocation of a packet command.
  */
+
 /**************************************************************
  *                                                            *
  *  This should get fixed to use kmalloc(.., GFP_ATOMIC)      *
  *  followed later on by kfree().   -ml                       *
  *                                                            *
  **************************************************************/
-static struct request *idetape_next_rq_storage (ide_drive_t *drive)
+
+static struct request *idetape_next_rq_storage(ide_drive_t *drive)
 {
        idetape_tape_t *tape = drive->driver_data;
 
-#if IDETAPE_DEBUG_LOG
-       if (tape->debug_level >= 5)
-               printk(KERN_INFO "ide-tape: rq_stack_index=%d\n",
-                       tape->rq_stack_index);
-#endif /* IDETAPE_DEBUG_LOG */
+       debug_log(DBG_PCRQ_STACK, "rq_stack_index=%d\n", tape->rq_stack_index);
+
        if (tape->rq_stack_index == IDETAPE_PC_STACK)
-               tape->rq_stack_index=0;
+               tape->rq_stack_index = 0;
        return (&tape->rq_stack[tape->rq_stack_index++]);
 }
 
-/*
- *     idetape_init_pc initializes a packet command.
- */
-static void idetape_init_pc (idetape_pc_t *pc)
+static void idetape_init_pc(idetape_pc_t *pc)
 {
        memset(pc->c, 0, 12);
        pc->retries = 0;
@@ -1447,36 +666,26 @@ static void idetape_init_pc (idetape_pc_t *pc)
 }
 
 /*
- *     idetape_analyze_error is called on each failed packet command retry
- *     to analyze the request sense. We currently do not utilize this
- *     information.
+ * called on each failed packet command retry to analyze the request sense. We
+ * currently do not utilize this information.
  */
-static void idetape_analyze_error (ide_drive_t *drive, idetape_request_sense_result_t *result)
+static void idetape_analyze_error(ide_drive_t *drive, u8 *sense)
 {
        idetape_tape_t *tape = drive->driver_data;
        idetape_pc_t *pc = tape->failed_pc;
 
-       tape->sense     = *result;
-       tape->sense_key = result->sense_key;
-       tape->asc       = result->asc;
-       tape->ascq      = result->ascq;
-#if IDETAPE_DEBUG_LOG
-       /*
-        *      Without debugging, we only log an error if we decided to
-        *      give up retrying.
-        */
-       if (tape->debug_level >= 1)
-               printk(KERN_INFO "ide-tape: pc = %x, sense key = %x, "
-                       "asc = %x, ascq = %x\n",
-                       pc->c[0], result->sense_key,
-                       result->asc, result->ascq);
-#endif /* IDETAPE_DEBUG_LOG */
+       tape->sense_key = sense[2] & 0xF;
+       tape->asc       = sense[12];
+       tape->ascq      = sense[13];
 
-       /*
-        *      Correct pc->actually_transferred by asking the tape.
-        */
+       debug_log(DBG_ERR, "pc = %x, sense key = %x, asc = %x, ascq = %x\n",
+                pc->c[0], tape->sense_key, tape->asc, tape->ascq);
+
+       /* Correct pc->actually_transferred by asking the tape.  */
        if (test_bit(PC_DMA_ERROR, &pc->flags)) {
-               pc->actually_transferred = pc->request_transfer - tape->tape_block_size * ntohl(get_unaligned(&result->information));
+               pc->actually_transferred = pc->request_transfer -
+                       tape->blk_size *
+                       be32_to_cpu(get_unaligned((u32 *)&sense[3]));
                idetape_update_buffers(pc);
        }
 
@@ -1485,29 +694,29 @@ static void idetape_analyze_error (ide_drive_t *drive, idetape_request_sense_res
         * with sense key=5, asc=0x22, ascq=0, let it slide.  Some drives
         * (i.e. Seagate STT3401A Travan) don't support 0-length read/writes.
         */
-       if ((pc->c[0] == IDETAPE_READ_CMD || pc->c[0] == IDETAPE_WRITE_CMD)
-           && pc->c[4] == 0 && pc->c[3] == 0 && pc->c[2] == 0) { /* length==0 */
-               if (result->sense_key == 5) {
+       if ((pc->c[0] == READ_6 || pc->c[0] == WRITE_6)
+           /* length == 0 */
+           && pc->c[4] == 0 && pc->c[3] == 0 && pc->c[2] == 0) {
+               if (tape->sense_key == 5) {
                        /* don't report an error, everything's ok */
                        pc->error = 0;
                        /* don't retry read/write */
                        set_bit(PC_ABORT, &pc->flags);
                }
        }
-       if (pc->c[0] == IDETAPE_READ_CMD && result->filemark) {
+       if (pc->c[0] == READ_6 && (sense[2] & 0x80)) {
                pc->error = IDETAPE_ERROR_FILEMARK;
                set_bit(PC_ABORT, &pc->flags);
        }
-       if (pc->c[0] == IDETAPE_WRITE_CMD) {
-               if (result->eom ||
-                   (result->sense_key == 0xd && result->asc == 0x0 &&
-                    result->ascq == 0x2)) {
+       if (pc->c[0] == WRITE_6) {
+               if ((sense[2] & 0x40) || (tape->sense_key == 0xd
+                    && tape->asc == 0x0 && tape->ascq == 0x2)) {
                        pc->error = IDETAPE_ERROR_EOD;
                        set_bit(PC_ABORT, &pc->flags);
                }
        }
-       if (pc->c[0] == IDETAPE_READ_CMD || pc->c[0] == IDETAPE_WRITE_CMD) {
-               if (result->sense_key == 8) {
+       if (pc->c[0] == READ_6 || pc->c[0] == WRITE_6) {
+               if (tape->sense_key == 8) {
                        pc->error = IDETAPE_ERROR_EOD;
                        set_bit(PC_ABORT, &pc->flags);
                }
@@ -1517,61 +726,30 @@ static void idetape_analyze_error (ide_drive_t *drive, idetape_request_sense_res
        }
 }
 
-/*
- * idetape_active_next_stage will declare the next stage as "active".
- */
-static void idetape_active_next_stage (ide_drive_t *drive)
+static void idetape_activate_next_stage(ide_drive_t *drive)
 {
        idetape_tape_t *tape = drive->driver_data;
        idetape_stage_t *stage = tape->next_stage;
        struct request *rq = &stage->rq;
 
-#if IDETAPE_DEBUG_LOG
-       if (tape->debug_level >= 4)
-               printk(KERN_INFO "ide-tape: Reached idetape_active_next_stage\n");
-#endif /* IDETAPE_DEBUG_LOG */
-#if IDETAPE_DEBUG_BUGS
+       debug_log(DBG_PROCS, "Enter %s\n", __func__);
+
        if (stage == NULL) {
-               printk(KERN_ERR "ide-tape: bug: Trying to activate a non existing stage\n");
+               printk(KERN_ERR "ide-tape: bug: Trying to activate a non"
+                               " existing stage\n");
                return;
        }
-#endif /* IDETAPE_DEBUG_BUGS */        
 
        rq->rq_disk = tape->disk;
        rq->buffer = NULL;
        rq->special = (void *)stage->bh;
-       tape->active_data_request = rq;
+       tape->active_data_rq = rq;
        tape->active_stage = stage;
        tape->next_stage = stage->next;
 }
 
-/*
- *     idetape_increase_max_pipeline_stages is a part of the feedback
- *     loop which tries to find the optimum number of stages. In the
- *     feedback loop, we are starting from a minimum maximum number of
- *     stages, and if we sense that the pipeline is empty, we try to
- *     increase it, until we reach the user compile time memory limit.
- */
-static void idetape_increase_max_pipeline_stages (ide_drive_t *drive)
-{
-       idetape_tape_t *tape = drive->driver_data;
-       int increase = (tape->max_pipeline - tape->min_pipeline) / 10;
-       
-#if IDETAPE_DEBUG_LOG
-       if (tape->debug_level >= 4)
-               printk (KERN_INFO "ide-tape: Reached idetape_increase_max_pipeline_stages\n");
-#endif /* IDETAPE_DEBUG_LOG */
-
-       tape->max_stages += max(increase, 1);
-       tape->max_stages = max(tape->max_stages, tape->min_pipeline);
-       tape->max_stages = min(tape->max_stages, tape->max_pipeline);
-}
-
-/*
- *     idetape_kfree_stage calls kfree to completely free a stage, along with
- *     its related buffers.
- */
-static void __idetape_kfree_stage (idetape_stage_t *stage)
+/* Free a stage along with its related buffers completely. */
+static void __idetape_kfree_stage(idetape_stage_t *stage)
 {
        struct idetape_bh *prev_bh, *bh = stage->bh;
        int size;
@@ -1592,46 +770,43 @@ static void __idetape_kfree_stage (idetape_stage_t *stage)
        kfree(stage);
 }
 
-static void idetape_kfree_stage (idetape_tape_t *tape, idetape_stage_t *stage)
+static void idetape_kfree_stage(idetape_tape_t *tape, idetape_stage_t *stage)
 {
        __idetape_kfree_stage(stage);
 }
 
 /*
- *     idetape_remove_stage_head removes tape->first_stage from the pipeline.
- *     The caller should avoid race conditions.
+ * Remove tape->first_stage from the pipeline. The caller should avoid race
+ * conditions.
  */
-static void idetape_remove_stage_head (ide_drive_t *drive)
+static void idetape_remove_stage_head(ide_drive_t *drive)
 {
        idetape_tape_t *tape = drive->driver_data;
        idetape_stage_t *stage;
-       
-#if IDETAPE_DEBUG_LOG
-       if (tape->debug_level >= 4)
-               printk(KERN_INFO "ide-tape: Reached idetape_remove_stage_head\n");
-#endif /* IDETAPE_DEBUG_LOG */
-#if IDETAPE_DEBUG_BUGS
+
+       debug_log(DBG_PROCS, "Enter %s\n", __func__);
+
        if (tape->first_stage == NULL) {
                printk(KERN_ERR "ide-tape: bug: tape->first_stage is NULL\n");
-               return;         
+               return;
        }
        if (tape->active_stage == tape->first_stage) {
-               printk(KERN_ERR "ide-tape: bug: Trying to free our active pipeline stage\n");
+               printk(KERN_ERR "ide-tape: bug: Trying to free our active "
+                               "pipeline stage\n");
                return;
        }
-#endif /* IDETAPE_DEBUG_BUGS */
        stage = tape->first_stage;
        tape->first_stage = stage->next;
        idetape_kfree_stage(tape, stage);
        tape->nr_stages--;
        if (tape->first_stage == NULL) {
                tape->last_stage = NULL;
-#if IDETAPE_DEBUG_BUGS
                if (tape->next_stage != NULL)
-                       printk(KERN_ERR "ide-tape: bug: tape->next_stage != NULL\n");
+                       printk(KERN_ERR "ide-tape: bug: tape->next_stage !="
+                                       " NULL\n");
                if (tape->nr_stages)
-                       printk(KERN_ERR "ide-tape: bug: nr_stages should be 0 now\n");
-#endif /* IDETAPE_DEBUG_BUGS */
+                       printk(KERN_ERR "ide-tape: bug: nr_stages should be 0 "
+                                       "now\n");
        }
 }
 
@@ -1646,10 +821,8 @@ static void idetape_abort_pipeline(ide_drive_t *drive,
        idetape_stage_t *stage = new_last_stage->next;
        idetape_stage_t *nstage;
 
-#if IDETAPE_DEBUG_LOG
-       if (tape->debug_level >= 4)
-               printk(KERN_INFO "ide-tape: %s: idetape_abort_pipeline called\n", tape->name);
-#endif
+       debug_log(DBG_PROCS, "%s: Enter %s\n", tape->name, __func__);
+
        while (stage) {
                nstage = stage->next;
                idetape_kfree_stage(tape, stage);
@@ -1664,8 +837,8 @@ static void idetape_abort_pipeline(ide_drive_t *drive,
 }
 
 /*
- *     idetape_end_request is used to finish servicing a request, and to
- *     insert a pending pipeline request into the main device queue.
+ * Finish servicing a request and insert a pending pipeline request into the
+ * main device queue.
  */
 static int idetape_end_request(ide_drive_t *drive, int uptodate, int nr_sects)
 {
@@ -1676,15 +849,12 @@ static int idetape_end_request(ide_drive_t *drive, int uptodate, int nr_sects)
        int remove_stage = 0;
        idetape_stage_t *active_stage;
 
-#if IDETAPE_DEBUG_LOG
-        if (tape->debug_level >= 4)
-       printk(KERN_INFO "ide-tape: Reached idetape_end_request\n");
-#endif /* IDETAPE_DEBUG_LOG */
+       debug_log(DBG_PROCS, "Enter %s\n", __func__);
 
        switch (uptodate) {
-               case 0: error = IDETAPE_ERROR_GENERAL; break;
-               case 1: error = 0; break;
-               default: error = uptodate;
+       case 0: error = IDETAPE_ERROR_GENERAL; break;
+       case 1: error = 0; break;
+       default: error = uptodate;
        }
        rq->errors = error;
        if (error)
@@ -1695,20 +865,21 @@ static int idetape_end_request(ide_drive_t *drive, int uptodate, int nr_sects)
                return 0;
        }
 
-       spin_lock_irqsave(&tape->spinlock, flags);
+       spin_lock_irqsave(&tape->lock, flags);
 
        /* The request was a pipelined data transfer request */
-       if (tape->active_data_request == rq) {
+       if (tape->active_data_rq == rq) {
                active_stage = tape->active_stage;
                tape->active_stage = NULL;
-               tape->active_data_request = NULL;
+               tape->active_data_rq = NULL;
                tape->nr_pending_stages--;
                if (rq->cmd[0] & REQ_IDETAPE_WRITE) {
                        remove_stage = 1;
                        if (error) {
                                set_bit(IDETAPE_PIPELINE_ERROR, &tape->flags);
                                if (error == IDETAPE_ERROR_EOD)
-                                       idetape_abort_pipeline(drive, active_stage);
+                                       idetape_abort_pipeline(drive,
+                                                               active_stage);
                        }
                } else if (rq->cmd[0] & REQ_IDETAPE_READ) {
                        if (error == IDETAPE_ERROR_EOD) {
@@ -1717,51 +888,60 @@ static int idetape_end_request(ide_drive_t *drive, int uptodate, int nr_sects)
                        }
                }
                if (tape->next_stage != NULL) {
-                       idetape_active_next_stage(drive);
+                       idetape_activate_next_stage(drive);
 
+                       /* Insert the next request into the request queue. */
+                       (void)ide_do_drive_cmd(drive, tape->active_data_rq,
+                                               ide_end);
+               } else if (!error) {
                        /*
-                        * Insert the next request into the request queue.
+                        * This is a part of the feedback loop which tries to
+                        * find the optimum number of stages. We are starting
+                        * from a minimum maximum number of stages, and if we
+                        * sense that the pipeline is empty, we try to increase
+                        * it, until we reach the user compile time memory
+                        * limit.
                         */
-                       (void) ide_do_drive_cmd(drive, tape->active_data_request, ide_end);
-               } else if (!error) {
-                               idetape_increase_max_pipeline_stages(drive);
+                       int i = (tape->max_pipeline - tape->min_pipeline) / 10;
+
+                       tape->max_stages += max(i, 1);
+                       tape->max_stages = max(tape->max_stages,
+                                               tape->min_pipeline);
+                       tape->max_stages = min(tape->max_stages,
+                                               tape->max_pipeline);
                }
        }
        ide_end_drive_cmd(drive, 0, 0);
-//     blkdev_dequeue_request(rq);
-//     drive->rq = NULL;
-//     end_that_request_last(rq);
 
        if (remove_stage)
                idetape_remove_stage_head(drive);
-       if (tape->active_data_request == NULL)
+       if (tape->active_data_rq == NULL)
                clear_bit(IDETAPE_PIPELINE_ACTIVE, &tape->flags);
-       spin_unlock_irqrestore(&tape->spinlock, flags);
+       spin_unlock_irqrestore(&tape->lock, flags);
        return 0;
 }
 
-static ide_startstop_t idetape_request_sense_callback (ide_drive_t *drive)
+static ide_startstop_t idetape_request_sense_callback(ide_drive_t *drive)
 {
        idetape_tape_t *tape = drive->driver_data;
 
-#if IDETAPE_DEBUG_LOG
-       if (tape->debug_level >= 4)
-               printk(KERN_INFO "ide-tape: Reached idetape_request_sense_callback\n");
-#endif /* IDETAPE_DEBUG_LOG */
+       debug_log(DBG_PROCS, "Enter %s\n", __func__);
+
        if (!tape->pc->error) {
-               idetape_analyze_error(drive, (idetape_request_sense_result_t *) tape->pc->buffer);
+               idetape_analyze_error(drive, tape->pc->buffer);
                idetape_end_request(drive, 1, 0);
        } else {
-               printk(KERN_ERR "ide-tape: Error in REQUEST SENSE itself - Aborting request!\n");
+               printk(KERN_ERR "ide-tape: Error in REQUEST SENSE itself - "
+                               "Aborting request!\n");
                idetape_end_request(drive, 0, 0);
        }
        return ide_stopped;
 }
 
-static void idetape_create_request_sense_cmd (idetape_pc_t *pc)
+static void idetape_create_request_sense_cmd(idetape_pc_t *pc)
 {
-       idetape_init_pc(pc);    
-       pc->c[0] = IDETAPE_REQUEST_SENSE_CMD;
+       idetape_init_pc(pc);
+       pc->c[0] = REQUEST_SENSE;
        pc->c[4] = 20;
        pc->request_transfer = 20;
        pc->callback = &idetape_request_sense_callback;
@@ -1775,25 +955,22 @@ static void idetape_init_rq(struct request *rq, u8 cmd)
 }
 
 /*
- *     idetape_queue_pc_head generates a new packet command request in front
- *     of the request queue, before the current request, so that it will be
- *     processed immediately, on the next pass through the driver.
+ * Generate a new packet command request in front of the request queue, before
+ * the current request, so that it will be processed immediately, on the next
+ * pass through the driver. The function below is called from the request
+ * handling part of the driver (the "bottom" part). Safe storage for the request
+ * should be allocated with ide_tape_next_{pc,rq}_storage() prior to that.
  *
- *     idetape_queue_pc_head is called from the request handling part of
- *     the driver (the "bottom" part). Safe storage for the request should
- *     be allocated with idetape_next_pc_storage and idetape_next_rq_storage
- *     before calling idetape_queue_pc_head.
+ * Memory for those requests is pre-allocated at initialization time, and is
+ * limited to IDETAPE_PC_STACK requests. We assume that we have enough space for
+ * the maximum possible number of inter-dependent packet commands.
  *
- *     Memory for those requests is pre-allocated at initialization time, and
- *     is limited to IDETAPE_PC_STACK requests. We assume that we have enough
- *     space for the maximum possible number of inter-dependent packet commands.
- *
- *     The higher level of the driver - The ioctl handler and the character
- *     device handling functions should queue request to the lower level part
- *     and wait for their completion using idetape_queue_pc_tail or
- *     idetape_queue_rw_tail.
+ * The higher level of the driver - The ioctl handler and the character device
+ * handling functions should queue request to the lower level part and wait for
+ * their completion using idetape_queue_pc_tail or idetape_queue_rw_tail.
  */
-static void idetape_queue_pc_head (ide_drive_t *drive, idetape_pc_t *pc,struct request *rq)
+static void idetape_queue_pc_head(ide_drive_t *drive, idetape_pc_t *pc,
+                                 struct request *rq)
 {
        struct ide_tape_obj *tape = drive->driver_data;
 
@@ -1814,7 +991,7 @@ static ide_startstop_t idetape_retry_pc (ide_drive_t *drive)
        idetape_pc_t *pc;
        struct request *rq;
 
-       (void)drive->hwif->INB(IDE_ERROR_REG);
+       (void)ide_read_error(drive);
        pc = idetape_next_pc_storage(drive);
        rq = idetape_next_rq_storage(drive);
        idetape_create_request_sense_cmd(pc);
@@ -1824,50 +1001,46 @@ static ide_startstop_t idetape_retry_pc (ide_drive_t *drive)
 }
 
 /*
- *     idetape_postpone_request postpones the current request so that
- *     ide.c will be able to service requests from another device on
- *     the same hwgroup while we are polling for DSC.
+ * Postpone the current request so that ide.c will be able to service requests
+ * from another device on the same hwgroup while we are polling for DSC.
  */
-static void idetape_postpone_request (ide_drive_t *drive)
+static void idetape_postpone_request(ide_drive_t *drive)
 {
        idetape_tape_t *tape = drive->driver_data;
 
-#if IDETAPE_DEBUG_LOG
-       if (tape->debug_level >= 4)
-               printk(KERN_INFO "ide-tape: idetape_postpone_request\n");
-#endif
+       debug_log(DBG_PROCS, "Enter %s\n", __func__);
+
        tape->postponed_rq = HWGROUP(drive)->rq;
-       ide_stall_queue(drive, tape->dsc_polling_frequency);
+       ide_stall_queue(drive, tape->dsc_poll_freq);
 }
 
+typedef void idetape_io_buf(ide_drive_t *, idetape_pc_t *, unsigned int);
+
 /*
- *     idetape_pc_intr is the usual interrupt handler which will be called
- *     during a packet command. We will transfer some of the data (as
- *     requested by the drive) and will re-point interrupt handler to us.
- *     When data transfer is finished, we will act according to the
- *     algorithm described before idetape_issue_packet_command.
- *
+ * This is the usual interrupt handler which will be called during a packet
+ * command. We will transfer some of the data (as requested by the drive) and
+ * will re-point interrupt handler to us. When data transfer is finished, we
+ * will act according to the algorithm described before
+ * idetape_issue_pc.
  */
-static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
+static ide_startstop_t idetape_pc_intr(ide_drive_t *drive)
 {
        ide_hwif_t *hwif = drive->hwif;
        idetape_tape_t *tape = drive->driver_data;
        idetape_pc_t *pc = tape->pc;
+       xfer_func_t *xferfunc;
+       idetape_io_buf *iobuf;
        unsigned int temp;
 #if SIMULATE_ERRORS
-       static int error_sim_count = 0;
+       static int error_sim_count;
 #endif
        u16 bcount;
        u8 stat, ireason;
 
-#if IDETAPE_DEBUG_LOG
-       if (tape->debug_level >= 4)
-               printk(KERN_INFO "ide-tape: Reached idetape_pc_intr "
-                               "interrupt handler\n");
-#endif /* IDETAPE_DEBUG_LOG */ 
+       debug_log(DBG_PROCS, "Enter %s - interrupt handler\n", __func__);
 
        /* Clear the interrupt */
-       stat = hwif->INB(IDE_STATUS_REG);
+       stat = ide_read_status(drive);
 
        if (test_bit(PC_DMA_IN_PROGRESS, &pc->flags)) {
                if (hwif->ide_dma_end(drive) || (stat & ERR_STAT)) {
@@ -1897,48 +1070,40 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
                        pc->actually_transferred = pc->request_transfer;
                        idetape_update_buffers(pc);
                }
-#if IDETAPE_DEBUG_LOG
-               if (tape->debug_level >= 4)
-                       printk(KERN_INFO "ide-tape: DMA finished\n");
-#endif /* IDETAPE_DEBUG_LOG */
+               debug_log(DBG_PROCS, "DMA finished\n");
+
        }
 
        /* No more interrupts */
        if ((stat & DRQ_STAT) == 0) {
-#if IDETAPE_DEBUG_LOG
-               if (tape->debug_level >= 2)
-                       printk(KERN_INFO "ide-tape: Packet command completed, %d bytes transferred\n", pc->actually_transferred);
-#endif /* IDETAPE_DEBUG_LOG */
-               clear_bit(PC_DMA_IN_PROGRESS, &pc->flags);
+               debug_log(DBG_SENSE, "Packet command completed, %d bytes"
+                               " transferred\n", pc->actually_transferred);
 
+               clear_bit(PC_DMA_IN_PROGRESS, &pc->flags);
                local_irq_enable();
 
 #if SIMULATE_ERRORS
-               if ((pc->c[0] == IDETAPE_WRITE_CMD ||
-                    pc->c[0] == IDETAPE_READ_CMD) &&
+               if ((pc->c[0] == WRITE_6 || pc->c[0] == READ_6) &&
                    (++error_sim_count % 100) == 0) {
                        printk(KERN_INFO "ide-tape: %s: simulating error\n",
                                tape->name);
                        stat |= ERR_STAT;
                }
 #endif
-               if ((stat & ERR_STAT) && pc->c[0] == IDETAPE_REQUEST_SENSE_CMD)
+               if ((stat & ERR_STAT) && pc->c[0] == REQUEST_SENSE)
                        stat &= ~ERR_STAT;
                if ((stat & ERR_STAT) || test_bit(PC_DMA_ERROR, &pc->flags)) {
                        /* Error detected */
-#if IDETAPE_DEBUG_LOG
-                       if (tape->debug_level >= 1)
-                               printk(KERN_INFO "ide-tape: %s: I/O error\n",
-                                       tape->name);
-#endif /* IDETAPE_DEBUG_LOG */
-                       if (pc->c[0] == IDETAPE_REQUEST_SENSE_CMD) {
-                               printk(KERN_ERR "ide-tape: I/O error in request sense command\n");
+                       debug_log(DBG_ERR, "%s: I/O error\n", tape->name);
+
+                       if (pc->c[0] == REQUEST_SENSE) {
+                               printk(KERN_ERR "ide-tape: I/O error in request"
+                                               " sense command\n");
                                return ide_do_reset(drive);
                        }
-#if IDETAPE_DEBUG_LOG
-                       if (tape->debug_level >= 1)
-                               printk(KERN_INFO "ide-tape: [cmd %x]: check condition\n", pc->c[0]);
-#endif
+                       debug_log(DBG_ERR, "[cmd %x]: check condition\n",
+                                       pc->c[0]);
+
                        /* Retry operation */
                        return idetape_retry_pc(drive);
                }
@@ -1947,7 +1112,7 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
                    (stat & SEEK_STAT) == 0) {
                        /* Media access command */
                        tape->dsc_polling_start = jiffies;
-                       tape->dsc_polling_frequency = IDETAPE_DSC_MA_FAST;
+                       tape->dsc_poll_freq = IDETAPE_DSC_MA_FAST;
                        tape->dsc_timeout = jiffies + IDETAPE_DSC_MA_TIMEOUT;
                        /* Allow ide.c to handle other requests */
                        idetape_postpone_request(drive);
@@ -1972,7 +1137,7 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
        ireason = hwif->INB(IDE_IREASON_REG);
 
        if (ireason & CD) {
-               printk(KERN_ERR "ide-tape: CoD != 0 in idetape_pc_intr\n");
+               printk(KERN_ERR "ide-tape: CoD != 0 in %s\n", __func__);
                return ide_do_reset(drive);
        }
        if (((ireason & IO) == IO) == test_bit(PC_WRITING, &pc->flags)) {
@@ -1988,86 +1153,76 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
                temp = pc->actually_transferred + bcount;
                if (temp > pc->request_transfer) {
                        if (temp > pc->buffer_size) {
-                               printk(KERN_ERR "ide-tape: The tape wants to send us more data than expected - discarding data\n");
+                               printk(KERN_ERR "ide-tape: The tape wants to "
+                                       "send us more data than expected "
+                                       "- discarding data\n");
                                idetape_discard_data(drive, bcount);
-                               ide_set_handler(drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL);
+                               ide_set_handler(drive, &idetape_pc_intr,
+                                               IDETAPE_WAIT_CMD, NULL);
                                return ide_started;
                        }
-#if IDETAPE_DEBUG_LOG
-                       if (tape->debug_level >= 2)
-                               printk(KERN_NOTICE "ide-tape: The tape wants to send us more data than expected - allowing transfer\n");
-#endif /* IDETAPE_DEBUG_LOG */
+                       debug_log(DBG_SENSE, "The tape wants to send us more "
+                               "data than expected - allowing transfer\n");
                }
-       }
-       if (test_bit(PC_WRITING, &pc->flags)) {
-               if (pc->bh != NULL)
-                       idetape_output_buffers(drive, pc, bcount);
-               else
-                       /* Write the current buffer */
-                       hwif->atapi_output_bytes(drive, pc->current_position,
-                                                bcount);
+               iobuf = &idetape_input_buffers;
+               xferfunc = hwif->atapi_input_bytes;
        } else {
-               if (pc->bh != NULL)
-                       idetape_input_buffers(drive, pc, bcount);
-               else
-                       /* Read the current buffer */
-                       hwif->atapi_input_bytes(drive, pc->current_position,
-                                               bcount);
+               iobuf = &idetape_output_buffers;
+               xferfunc = hwif->atapi_output_bytes;
        }
+
+       if (pc->bh)
+               iobuf(drive, pc, bcount);
+       else
+               xferfunc(drive, pc->current_position, bcount);
+
        /* Update the current position */
        pc->actually_transferred += bcount;
        pc->current_position += bcount;
-#if IDETAPE_DEBUG_LOG
-       if (tape->debug_level >= 2)
-               printk(KERN_INFO "ide-tape: [cmd %x] transferred %d bytes "
-                                "on that interrupt\n", pc->c[0], bcount);
-#endif
+
+       debug_log(DBG_SENSE, "[cmd %x] transferred %d bytes on that intr.\n",
+                       pc->c[0], bcount);
+
        /* And set the interrupt handler again */
        ide_set_handler(drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL);
        return ide_started;
 }
 
 /*
- *     Packet Command Interface
+ * Packet Command Interface
  *
- *     The current Packet Command is available in tape->pc, and will not
- *     change until we finish handling it. Each packet command is associated
- *     with a callback function that will be called when the command is
- *     finished.
+ * The current Packet Command is available in tape->pc, and will not change
+ * until we finish handling it. Each packet command is associated with a
+ * callback function that will be called when the command is finished.
  *
- *     The handling will be done in three stages:
+ * The handling will be done in three stages:
  *
- *     1.      idetape_issue_packet_command will send the packet command to the
- *             drive, and will set the interrupt handler to idetape_pc_intr.
+ * 1. idetape_issue_pc will send the packet command to the drive, and will set
+ * the interrupt handler to idetape_pc_intr.
  *
- *     2.      On each interrupt, idetape_pc_intr will be called. This step
- *             will be repeated until the device signals us that no more
- *             interrupts will be issued.
+ * 2. On each interrupt, idetape_pc_intr will be called. This step will be
+ * repeated until the device signals us that no more interrupts will be issued.
  *
- *     3.      ATAPI Tape media access commands have immediate status with a
- *             delayed process. In case of a successful initiation of a
- *             media access packet command, the DSC bit will be set when the
- *             actual execution of the command is finished. 
- *             Since the tape drive will not issue an interrupt, we have to
- *             poll for this event. In this case, we define the request as
- *             "low priority request" by setting rq_status to
- *             IDETAPE_RQ_POSTPONED,   set a timer to poll for DSC and exit
- *             the driver.
+ * 3. ATAPI Tape media access commands have immediate status with a delayed
+ * process. In case of a successful initiation of a media access packet command,
+ * the DSC bit will be set when the actual execution of the command is finished.
+ * Since the tape drive will not issue an interrupt, we have to poll for this
+ * event. In this case, we define the request as "low priority request" by
+ * setting rq_status to IDETAPE_RQ_POSTPONED, set a timer to poll for DSC and
+ * exit the driver.
  *
- *             ide.c will then give higher priority to requests which
- *             originate from the other device, until will change rq_status
- *             to RQ_ACTIVE.
+ * ide.c will then give higher priority to requests which originate from the
+ * other device, until will change rq_status to RQ_ACTIVE.
  *
- *     4.      When the packet command is finished, it will be checked for errors.
+ * 4. When the packet command is finished, it will be checked for errors.
  *
- *     5.      In case an error was found, we queue a request sense packet
- *             command in front of the request queue and retry the operation
- *             up to IDETAPE_MAX_PC_RETRIES times.
- *
- *     6.      In case no error was found, or we decided to give up and not
- *             to retry again, the callback function will be called and then
- *             we will handle the next request.
+ * 5. In case an error was found, we queue a request sense packet command in
+ * front of the request queue and retry the operation up to
+ * IDETAPE_MAX_PC_RETRIES times.
  *
+ * 6. In case no error was found, or we decided to give up and not to retry
+ * again, the callback function will be called and then we will handle the next
+ * request.
  */
 static ide_startstop_t idetape_transfer_pc(ide_drive_t *drive)
 {
@@ -2078,8 +1233,9 @@ static ide_startstop_t idetape_transfer_pc(ide_drive_t *drive)
        ide_startstop_t startstop;
        u8 ireason;
 
-       if (ide_wait_stat(&startstop,drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) {
-               printk(KERN_ERR "ide-tape: Strange, packet command initiated yet DRQ isn't asserted\n");
+       if (ide_wait_stat(&startstop, drive, DRQ_STAT, BUSY_STAT, WAIT_READY)) {
+               printk(KERN_ERR "ide-tape: Strange, packet command initiated "
+                               "yet DRQ isn't asserted\n");
                return startstop;
        }
        ireason = hwif->INB(IDE_IREASON_REG);
@@ -2112,22 +1268,20 @@ static ide_startstop_t idetape_transfer_pc(ide_drive_t *drive)
        return ide_started;
 }
 
-static ide_startstop_t idetape_issue_packet_command (ide_drive_t *drive, idetape_pc_t *pc)
+static ide_startstop_t idetape_issue_pc(ide_drive_t *drive, idetape_pc_t *pc)
 {
        ide_hwif_t *hwif = drive->hwif;
        idetape_tape_t *tape = drive->driver_data;
        int dma_ok = 0;
        u16 bcount;
 
-#if IDETAPE_DEBUG_BUGS
-       if (tape->pc->c[0] == IDETAPE_REQUEST_SENSE_CMD &&
-           pc->c[0] == IDETAPE_REQUEST_SENSE_CMD) {
+       if (tape->pc->c[0] == REQUEST_SENSE &&
+           pc->c[0] == REQUEST_SENSE) {
                printk(KERN_ERR "ide-tape: possible ide-tape.c bug - "
                        "Two request sense in serial were issued\n");
        }
-#endif /* IDETAPE_DEBUG_BUGS */
 
-       if (tape->failed_pc == NULL && pc->c[0] != IDETAPE_REQUEST_SENSE_CMD)
+       if (tape->failed_pc == NULL && pc->c[0] != REQUEST_SENSE)
                tape->failed_pc = pc;
        /* Set the current packet command */
        tape->pc = pc;
@@ -2135,12 +1289,12 @@ static ide_startstop_t idetape_issue_packet_command (ide_drive_t *drive, idetape
        if (pc->retries > IDETAPE_MAX_PC_RETRIES ||
            test_bit(PC_ABORT, &pc->flags)) {
                /*
-                *      We will "abort" retrying a packet command in case
-                *      a legitimate error code was received (crossing a
-                *      filemark, or end of the media, for example).
+                * We will "abort" retrying a packet command in case legitimate
+                * error code was received (crossing a filemark, or end of the
+                * media, for example).
                 */
                if (!test_bit(PC_ABORT, &pc->flags)) {
-                       if (!(pc->c[0] == IDETAPE_TEST_UNIT_READY_CMD &&
+                       if (!(pc->c[0] == TEST_UNIT_READY &&
                              tape->sense_key == 2 && tape->asc == 4 &&
                             (tape->ascq == 1 || tape->ascq == 8))) {
                                printk(KERN_ERR "ide-tape: %s: I/O error, "
@@ -2156,10 +1310,7 @@ static ide_startstop_t idetape_issue_packet_command (ide_drive_t *drive, idetape
                tape->failed_pc = NULL;
                return pc->callback(drive);
        }
-#if IDETAPE_DEBUG_LOG
-       if (tape->debug_level >= 2)
-               printk(KERN_INFO "ide-tape: Retry number - %d, cmd = %02X\n", pc->retries, pc->c[0]);
-#endif /* IDETAPE_DEBUG_LOG */
+       debug_log(DBG_SENSE, "Retry #%d, cmd = %02X\n", pc->retries, pc->c[0]);
 
        pc->retries++;
        /* We haven't transferred any data yet */
@@ -2182,8 +1333,8 @@ static ide_startstop_t idetape_issue_packet_command (ide_drive_t *drive, idetape
        if (dma_ok)                     /* Will begin DMA later */
                set_bit(PC_DMA_IN_PROGRESS, &pc->flags);
        if (test_bit(IDETAPE_DRQ_INTERRUPT, &tape->flags)) {
-               ide_set_handler(drive, &idetape_transfer_pc, IDETAPE_WAIT_CMD, NULL);
-               hwif->OUTB(WIN_PACKETCMD, IDE_COMMAND_REG);
+               ide_execute_command(drive, WIN_PACKETCMD, &idetape_transfer_pc,
+                                   IDETAPE_WAIT_CMD, NULL);
                return ide_started;
        } else {
                hwif->OUTB(WIN_PACKETCMD, IDE_COMMAND_REG);
@@ -2191,31 +1342,24 @@ static ide_startstop_t idetape_issue_packet_command (ide_drive_t *drive, idetape
        }
 }
 
-/*
- *     General packet command callback function.
- */
-static ide_startstop_t idetape_pc_callback (ide_drive_t *drive)
+static ide_startstop_t idetape_pc_callback(ide_drive_t *drive)
 {
        idetape_tape_t *tape = drive->driver_data;
-       
-#if IDETAPE_DEBUG_LOG
-       if (tape->debug_level >= 4)
-               printk(KERN_INFO "ide-tape: Reached idetape_pc_callback\n");
-#endif /* IDETAPE_DEBUG_LOG */
+
+       debug_log(DBG_PROCS, "Enter %s\n", __func__);
 
        idetape_end_request(drive, tape->pc->error ? 0 : 1, 0);
        return ide_stopped;
 }
 
-/*
- *     A mode sense command is used to "sense" tape parameters.
- */
-static void idetape_create_mode_sense_cmd (idetape_pc_t *pc, u8 page_code)
+/* A mode sense command is used to "sense" tape parameters. */
+static void idetape_create_mode_sense_cmd(idetape_pc_t *pc, u8 page_code)
 {
        idetape_init_pc(pc);
-       pc->c[0] = IDETAPE_MODE_SENSE_CMD;
+       pc->c[0] = MODE_SENSE;
        if (page_code != IDETAPE_BLOCK_DESCRIPTOR)
-               pc->c[1] = 8;   /* DBD = 1 - Don't return block descriptors */
+               /* DBD = 1 - Don't return block descriptors */
+               pc->c[1] = 8;
        pc->c[2] = page_code;
        /*
         * Changed pc->c[3] to 0 (255 will at best return unused info).
@@ -2225,7 +1369,8 @@ static void idetape_create_mode_sense_cmd (idetape_pc_t *pc, u8 page_code)
         * and return an error when 255 is used.
         */
        pc->c[3] = 0;
-       pc->c[4] = 255;         /* (We will just discard data in that case) */
+       /* We will just discard data in that case */
+       pc->c[4] = 255;
        if (page_code == IDETAPE_BLOCK_DESCRIPTOR)
                pc->request_transfer = 12;
        else if (page_code == IDETAPE_CAPABILITIES_PAGE)
@@ -2235,66 +1380,81 @@ static void idetape_create_mode_sense_cmd (idetape_pc_t *pc, u8 page_code)
        pc->callback = &idetape_pc_callback;
 }
 
-static void calculate_speeds(ide_drive_t *drive)
+static void idetape_calculate_speeds(ide_drive_t *drive)
 {
        idetape_tape_t *tape = drive->driver_data;
-       int full = 125, empty = 75;
 
-       if (time_after(jiffies, tape->controlled_pipeline_head_time + 120 * HZ)) {
-               tape->controlled_previous_pipeline_head = tape->controlled_last_pipeline_head;
-               tape->controlled_previous_head_time = tape->controlled_pipeline_head_time;
+       if (time_after(jiffies,
+                       tape->controlled_pipeline_head_time + 120 * HZ)) {
+               tape->controlled_previous_pipeline_head =
+                       tape->controlled_last_pipeline_head;
+               tape->controlled_previous_head_time =
+                       tape->controlled_pipeline_head_time;
                tape->controlled_last_pipeline_head = tape->pipeline_head;
                tape->controlled_pipeline_head_time = jiffies;
        }
        if (time_after(jiffies, tape->controlled_pipeline_head_time + 60 * HZ))
-               tape->controlled_pipeline_head_speed = (tape->pipeline_head - tape->controlled_last_pipeline_head) * 32 * HZ / (jiffies - tape->controlled_pipeline_head_time);
+               tape->controlled_pipeline_head_speed = (tape->pipeline_head -
+                               tape->controlled_last_pipeline_head) * 32 * HZ /
+                               (jiffies - tape->controlled_pipeline_head_time);
        else if (time_after(jiffies, tape->controlled_previous_head_time))
-               tape->controlled_pipeline_head_speed = (tape->pipeline_head - tape->controlled_previous_pipeline_head) * 32 * HZ / (jiffies - tape->controlled_previous_head_time);
+               tape->controlled_pipeline_head_speed = (tape->pipeline_head -
+                               tape->controlled_previous_pipeline_head) * 32 *
+                       HZ / (jiffies - tape->controlled_previous_head_time);
 
-       if (tape->nr_pending_stages < tape->max_stages /*- 1 */) {
+       if (tape->nr_pending_stages < tape->max_stages/*- 1 */) {
                /* -1 for read mode error recovery */
-               if (time_after(jiffies, tape->uncontrolled_previous_head_time + 10 * HZ)) {
+               if (time_after(jiffies, tape->uncontrolled_previous_head_time +
+                                       10 * HZ)) {
                        tape->uncontrolled_pipeline_head_time = jiffies;
-                       tape->uncontrolled_pipeline_head_speed = (tape->pipeline_head - tape->uncontrolled_previous_pipeline_head) * 32 * HZ / (jiffies - tape->uncontrolled_previous_head_time);
+                       tape->uncontrolled_pipeline_head_speed =
+                               (tape->pipeline_head -
+                                tape->uncontrolled_previous_pipeline_head) *
+                               32 * HZ / (jiffies -
+                                       tape->uncontrolled_previous_head_time);
                }
        } else {
                tape->uncontrolled_previous_head_time = jiffies;
                tape->uncontrolled_previous_pipeline_head = tape->pipeline_head;
-               if (time_after(jiffies, tape->uncontrolled_pipeline_head_time + 30 * HZ)) {
+               if (time_after(jiffies, tape->uncontrolled_pipeline_head_time +
+                                       30 * HZ))
                        tape->uncontrolled_pipeline_head_time = jiffies;
-               }
+
        }
-       tape->pipeline_head_speed = max(tape->uncontrolled_pipeline_head_speed, tape->controlled_pipeline_head_speed);
-       if (tape->speed_control == 0) {
-               tape->max_insert_speed = 5000;
-       } else if (tape->speed_control == 1) {
+       tape->pipeline_head_speed = max(tape->uncontrolled_pipeline_head_speed,
+                                       tape->controlled_pipeline_head_speed);
+
+       if (tape->speed_control == 1) {
                if (tape->nr_pending_stages >= tape->max_stages / 2)
                        tape->max_insert_speed = tape->pipeline_head_speed +
-                               (1100 - tape->pipeline_head_speed) * 2 * (tape->nr_pending_stages - tape->max_stages / 2) / tape->max_stages;
+                               (1100 - tape->pipeline_head_speed) * 2 *
+                               (tape->nr_pending_stages - tape->max_stages / 2)
+                               / tape->max_stages;
                else
                        tape->max_insert_speed = 500 +
-                               (tape->pipeline_head_speed - 500) * 2 * tape->nr_pending_stages / tape->max_stages;
+                               (tape->pipeline_head_speed - 500) * 2 *
+                               tape->nr_pending_stages / tape->max_stages;
+
                if (tape->nr_pending_stages >= tape->max_stages * 99 / 100)
                        tape->max_insert_speed = 5000;
-       } else if (tape->speed_control == 2) {
-               tape->max_insert_speed = tape->pipeline_head_speed * empty / 100 +
-                       (tape->pipeline_head_speed * full / 100 - tape->pipeline_head_speed * empty / 100) * tape->nr_pending_stages / tape->max_stages;
        } else
                tape->max_insert_speed = tape->speed_control;
+
        tape->max_insert_speed = max(tape->max_insert_speed, 500);
 }
 
-static ide_startstop_t idetape_media_access_finished (ide_drive_t *drive)
+static ide_startstop_t idetape_media_access_finished(ide_drive_t *drive)
 {
        idetape_tape_t *tape = drive->driver_data;
        idetape_pc_t *pc = tape->pc;
        u8 stat;
 
-       stat = drive->hwif->INB(IDE_STATUS_REG);
+       stat = ide_read_status(drive);
+
        if (stat & SEEK_STAT) {
                if (stat & ERR_STAT) {
                        /* Error detected */
-                       if (pc->c[0] != IDETAPE_TEST_UNIT_READY_CMD)
+                       if (pc->c[0] != TEST_UNIT_READY)
                                printk(KERN_ERR "ide-tape: %s: I/O error, ",
                                                tape->name);
                        /* Retry operation */
@@ -2310,14 +1470,14 @@ static ide_startstop_t idetape_media_access_finished (ide_drive_t *drive)
        return pc->callback(drive);
 }
 
-static ide_startstop_t idetape_rw_callback (ide_drive_t *drive)
+static ide_startstop_t idetape_rw_callback(ide_drive_t *drive)
 {
        idetape_tape_t *tape = drive->driver_data;
        struct request *rq = HWGROUP(drive)->rq;
-       int blocks = tape->pc->actually_transferred / tape->tape_block_size;
+       int blocks = tape->pc->actually_transferred / tape->blk_size;
 
-       tape->avg_size += blocks * tape->tape_block_size;
-       tape->insert_size += blocks * tape->tape_block_size;
+       tape->avg_size += blocks * tape->blk_size;
+       tape->insert_size += blocks * tape->blk_size;
        if (tape->insert_size > 1024 * 1024)
                tape->measure_insert_time = 1;
        if (tape->measure_insert_time) {
@@ -2326,19 +1486,17 @@ static ide_startstop_t idetape_rw_callback (ide_drive_t *drive)
                tape->insert_size = 0;
        }
        if (time_after(jiffies, tape->insert_time))
-               tape->insert_speed = tape->insert_size / 1024 * HZ / (jiffies - tape->insert_time);
+               tape->insert_speed = tape->insert_size / 1024 * HZ /
+                                       (jiffies - tape->insert_time);
        if (time_after_eq(jiffies, tape->avg_time + HZ)) {
-               tape->avg_speed = tape->avg_size * HZ / (jiffies - tape->avg_time) / 1024;
+               tape->avg_speed = tape->avg_size * HZ /
+                               (jiffies - tape->avg_time) / 1024;
                tape->avg_size = 0;
                tape->avg_time = jiffies;
        }
+       debug_log(DBG_PROCS, "Enter %s\n", __func__);
 
-#if IDETAPE_DEBUG_LOG  
-       if (tape->debug_level >= 4)
-               printk(KERN_INFO "ide-tape: Reached idetape_rw_callback\n");
-#endif /* IDETAPE_DEBUG_LOG */
-
-       tape->first_frame_position += blocks;
+       tape->first_frame += blocks;
        rq->current_nr_sectors -= blocks;
 
        if (!tape->pc->error)
@@ -2348,28 +1506,31 @@ static ide_startstop_t idetape_rw_callback (ide_drive_t *drive)
        return ide_stopped;
 }
 
-static void idetape_create_read_cmd(idetape_tape_t *tape, idetape_pc_t *pc, unsigned int length, struct idetape_bh *bh)
+static void idetape_create_read_cmd(idetape_tape_t *tape, idetape_pc_t *pc,
+               unsigned int length, struct idetape_bh *bh)
 {
        idetape_init_pc(pc);
-       pc->c[0] = IDETAPE_READ_CMD;
-       put_unaligned(htonl(length), (unsigned int *) &pc->c[1]);
+       pc->c[0] = READ_6;
+       put_unaligned(cpu_to_be32(length), (unsigned int *) &pc->c[1]);
        pc->c[1] = 1;
        pc->callback = &idetape_rw_callback;
        pc->bh = bh;
        atomic_set(&bh->b_count, 0);
        pc->buffer = NULL;
-       pc->request_transfer = pc->buffer_size = length * tape->tape_block_size;
+       pc->buffer_size = length * tape->blk_size;
+       pc->request_transfer = pc->buffer_size;
        if (pc->request_transfer == tape->stage_size)
                set_bit(PC_DMA_RECOMMENDED, &pc->flags);
 }
 
-static void idetape_create_read_buffer_cmd(idetape_tape_t *tape, idetape_pc_t *pc, unsigned int length, struct idetape_bh *bh)
+static void idetape_create_read_buffer_cmd(idetape_tape_t *tape,
+               idetape_pc_t *pc, struct idetape_bh *bh)
 {
        int size = 32768;
        struct idetape_bh *p = bh;
 
        idetape_init_pc(pc);
-       pc->c[0] = IDETAPE_READ_BUFFER_CMD;
+       pc->c[0] = READ_BUFFER;
        pc->c[1] = IDETAPE_RETRIEVE_FAULTY_BLOCK;
        pc->c[7] = size >> 8;
        pc->c[8] = size & 0xff;
@@ -2381,14 +1542,16 @@ static void idetape_create_read_buffer_cmd(idetape_tape_t *tape, idetape_pc_t *p
                atomic_set(&p->b_count, 0);
                p = p->b_reqnext;
        }
-       pc->request_transfer = pc->buffer_size = size;
+       pc->request_transfer = size;
+       pc->buffer_size = size;
 }
 
-static void idetape_create_write_cmd(idetape_tape_t *tape, idetape_pc_t *pc, unsigned int length, struct idetape_bh *bh)
+static void idetape_create_write_cmd(idetape_tape_t *tape, idetape_pc_t *pc,
+               unsigned int length, struct idetape_bh *bh)
 {
        idetape_init_pc(pc);
-       pc->c[0] = IDETAPE_WRITE_CMD;
-       put_unaligned(htonl(length), (unsigned int *) &pc->c[1]);
+       pc->c[0] = WRITE_6;
+       put_unaligned(cpu_to_be32(length), (unsigned int *) &pc->c[1]);
        pc->c[1] = 1;
        pc->callback = &idetape_rw_callback;
        set_bit(PC_WRITING, &pc->flags);
@@ -2396,14 +1559,12 @@ static void idetape_create_write_cmd(idetape_tape_t *tape, idetape_pc_t *pc, uns
        pc->b_data = bh->b_data;
        pc->b_count = atomic_read(&bh->b_count);
        pc->buffer = NULL;
-       pc->request_transfer = pc->buffer_size = length * tape->tape_block_size;
+       pc->buffer_size = length * tape->blk_size;
+       pc->request_transfer = pc->buffer_size;
        if (pc->request_transfer == tape->stage_size)
                set_bit(PC_DMA_RECOMMENDED, &pc->flags);
 }
 
-/*
- * idetape_do_request is our request handling function.        
- */
 static ide_startstop_t idetape_do_request(ide_drive_t *drive,
                                          struct request *rq, sector_t block)
 {
@@ -2412,37 +1573,22 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive,
        struct request *postponed_rq = tape->postponed_rq;
        u8 stat;
 
-#if IDETAPE_DEBUG_LOG
-#if 0
-       if (tape->debug_level >= 5)
-               printk(KERN_INFO "ide-tape:  %d, "
-                       "dev: %s, cmd: %ld, errors: %d\n",
-                        rq->rq_disk->disk_name, rq->cmd[0], rq->errors);
-#endif
-       if (tape->debug_level >= 2)
-               printk(KERN_INFO "ide-tape: sector: %ld, "
-                       "nr_sectors: %ld, current_nr_sectors: %d\n",
+       debug_log(DBG_SENSE, "sector: %ld, nr_sectors: %ld,"
+                       " current_nr_sectors: %d\n",
                        rq->sector, rq->nr_sectors, rq->current_nr_sectors);
-#endif /* IDETAPE_DEBUG_LOG */
 
        if (!blk_special_request(rq)) {
-               /*
-                * We do not support buffer cache originated requests.
-                */
+               /* We do not support buffer cache originated requests. */
                printk(KERN_NOTICE "ide-tape: %s: Unsupported request in "
                        "request queue (%d)\n", drive->name, rq->cmd_type);
                ide_end_request(drive, 0, 0);
                return ide_stopped;
        }
 
-       /*
-        *      Retry a failed packet command
-        */
-       if (tape->failed_pc != NULL &&
-           tape->pc->c[0] == IDETAPE_REQUEST_SENSE_CMD) {
-               return idetape_issue_packet_command(drive, tape->failed_pc);
-       }
-#if IDETAPE_DEBUG_BUGS
+       /* Retry a failed packet command */
+       if (tape->failed_pc && tape->pc->c[0] == REQUEST_SENSE)
+               return idetape_issue_pc(drive, tape->failed_pc);
+
        if (postponed_rq != NULL)
                if (rq != postponed_rq) {
                        printk(KERN_ERR "ide-tape: ide-tape.c bug - "
@@ -2450,7 +1596,6 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive,
                        idetape_end_request(drive, 0, 0);
                        return ide_stopped;
                }
-#endif /* IDETAPE_DEBUG_BUGS */
 
        tape->postponed_rq = NULL;
 
@@ -2458,7 +1603,7 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive,
         * If the tape is still busy, postpone our request and service
         * the other device meanwhile.
         */
-       stat = drive->hwif->INB(IDE_STATUS_REG);
+       stat = ide_read_status(drive);
 
        if (!drive->dsc_overlap && !(rq->cmd[0] & REQ_IDETAPE_PC2))
                set_bit(IDETAPE_IGNORE_DSC, &tape->flags);
@@ -2468,16 +1613,15 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive,
                drive->post_reset = 0;
        }
 
-       if (tape->tape_still_time > 100 && tape->tape_still_time < 200)
-               tape->measure_insert_time = 1;
        if (time_after(jiffies, tape->insert_time))
-               tape->insert_speed = tape->insert_size / 1024 * HZ / (jiffies - tape->insert_time);
-       calculate_speeds(drive);
+               tape->insert_speed = tape->insert_size / 1024 * HZ /
+                                       (jiffies - tape->insert_time);
+       idetape_calculate_speeds(drive);
        if (!test_and_clear_bit(IDETAPE_IGNORE_DSC, &tape->flags) &&
            (stat & SEEK_STAT) == 0) {
                if (postponed_rq == NULL) {
                        tape->dsc_polling_start = jiffies;
-                       tape->dsc_polling_frequency = tape->best_dsc_rw_frequency;
+                       tape->dsc_poll_freq = tape->best_dsc_rw_freq;
                        tape->dsc_timeout = jiffies + IDETAPE_DSC_RW_TIMEOUT;
                } else if (time_after(jiffies, tape->dsc_timeout)) {
                        printk(KERN_ERR "ide-tape: %s: DSC timeout\n",
@@ -2488,8 +1632,10 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive,
                        } else {
                                return ide_do_reset(drive);
                        }
-               } else if (time_after(jiffies, tape->dsc_polling_start + IDETAPE_DSC_MA_THRESHOLD))
-                       tape->dsc_polling_frequency = IDETAPE_DSC_MA_SLOW;
+               } else if (time_after(jiffies,
+                                       tape->dsc_polling_start +
+                                       IDETAPE_DSC_MA_THRESHOLD))
+                       tape->dsc_poll_freq = IDETAPE_DSC_MA_SLOW;
                idetape_postpone_request(drive);
                return ide_stopped;
        }
@@ -2497,20 +1643,23 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive,
                tape->buffer_head++;
                tape->postpone_cnt = 0;
                pc = idetape_next_pc_storage(drive);
-               idetape_create_read_cmd(tape, pc, rq->current_nr_sectors, (struct idetape_bh *)rq->special);
+               idetape_create_read_cmd(tape, pc, rq->current_nr_sectors,
+                                       (struct idetape_bh *)rq->special);
                goto out;
        }
        if (rq->cmd[0] & REQ_IDETAPE_WRITE) {
                tape->buffer_head++;
                tape->postpone_cnt = 0;
                pc = idetape_next_pc_storage(drive);
-               idetape_create_write_cmd(tape, pc, rq->current_nr_sectors, (struct idetape_bh *)rq->special);
+               idetape_create_write_cmd(tape, pc, rq->current_nr_sectors,
+                                        (struct idetape_bh *)rq->special);
                goto out;
        }
        if (rq->cmd[0] & REQ_IDETAPE_READ_BUFFER) {
                tape->postpone_cnt = 0;
                pc = idetape_next_pc_storage(drive);
-               idetape_create_read_buffer_cmd(tape, pc, rq->current_nr_sectors, (struct idetape_bh *)rq->special);
+               idetape_create_read_buffer_cmd(tape, pc,
+                               (struct idetape_bh *)rq->special);
                goto out;
        }
        if (rq->cmd[0] & REQ_IDETAPE_PC1) {
@@ -2525,49 +1674,51 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive,
        }
        BUG();
 out:
-       return idetape_issue_packet_command(drive, pc);
+       return idetape_issue_pc(drive, pc);
 }
 
-/*
- *     Pipeline related functions
- */
-static inline int idetape_pipeline_active (idetape_tape_t *tape)
+/* Pipeline related functions */
+static inline int idetape_pipeline_active(idetape_tape_t *tape)
 {
        int rc1, rc2;
 
        rc1 = test_bit(IDETAPE_PIPELINE_ACTIVE, &tape->flags);
-       rc2 = (tape->active_data_request != NULL);
+       rc2 = (tape->active_data_rq != NULL);
        return rc1;
 }
 
 /*
- *     idetape_kmalloc_stage uses __get_free_page to allocate a pipeline
- *     stage, along with all the necessary small buffers which together make
- *     a buffer of size tape->stage_size (or a bit more). We attempt to
- *     combine sequential pages as much as possible.
+ * The function below uses __get_free_page to allocate a pipeline stage, along
+ * with all the necessary small buffers which together make a buffer of size
+ * tape->stage_size (or a bit more). We attempt to combine sequential pages as
+ * much as possible.
  *
- *     Returns a pointer to the new allocated stage, or NULL if we
- *     can't (or don't want to) allocate a stage.
+ * It returns a pointer to the new allocated stage, or NULL if we can't (or
+ * don't want to) allocate a stage.
  *
- *     Pipeline stages are optional and are used to increase performance.
- *     If we can't allocate them, we'll manage without them.
+ * Pipeline stages are optional and are used to increase performance. If we
+ * can't allocate them, we'll manage without them.
  */
-static idetape_stage_t *__idetape_kmalloc_stage (idetape_tape_t *tape, int full, int clear)
+static idetape_stage_t *__idetape_kmalloc_stage(idetape_tape_t *tape, int full,
+                                               int clear)
 {
        idetape_stage_t *stage;
        struct idetape_bh *prev_bh, *bh;
        int pages = tape->pages_per_stage;
        char *b_data = NULL;
 
-       if ((stage = kmalloc(sizeof (idetape_stage_t),GFP_KERNEL)) == NULL)
+       stage = kmalloc(sizeof(idetape_stage_t), GFP_KERNEL);
+       if (!stage)
                return NULL;
        stage->next = NULL;
 
-       bh = stage->bh = kmalloc(sizeof(struct idetape_bh), GFP_KERNEL);
+       stage->bh = kmalloc(sizeof(struct idetape_bh), GFP_KERNEL);
+       bh = stage->bh;
        if (bh == NULL)
                goto abort;
        bh->b_reqnext = NULL;
-       if ((bh->b_data = (char *) __get_free_page (GFP_KERNEL)) == NULL)
+       bh->b_data = (char *) __get_free_page(GFP_KERNEL);
+       if (!bh->b_data)
                goto abort;
        if (clear)
                memset(bh->b_data, 0, PAGE_SIZE);
@@ -2575,7 +1726,8 @@ static idetape_stage_t *__idetape_kmalloc_stage (idetape_tape_t *tape, int full,
        atomic_set(&bh->b_count, full ? bh->b_size : 0);
 
        while (--pages) {
-               if ((b_data = (char *) __get_free_page (GFP_KERNEL)) == NULL)
+               b_data = (char *) __get_free_page(GFP_KERNEL);
+               if (!b_data)
                        goto abort;
                if (clear)
                        memset(b_data, 0, PAGE_SIZE);
@@ -2593,7 +1745,8 @@ static idetape_stage_t *__idetape_kmalloc_stage (idetape_tape_t *tape, int full,
                        continue;
                }
                prev_bh = bh;
-               if ((bh = kmalloc(sizeof(struct idetape_bh), GFP_KERNEL)) == NULL) {
+               bh = kmalloc(sizeof(struct idetape_bh), GFP_KERNEL);
+               if (!bh) {
                        free_page((unsigned long) b_data);
                        goto abort;
                }
@@ -2612,14 +1765,11 @@ abort:
        return NULL;
 }
 
-static idetape_stage_t *idetape_kmalloc_stage (idetape_tape_t *tape)
+static idetape_stage_t *idetape_kmalloc_stage(idetape_tape_t *tape)
 {
        idetape_stage_t *cache_stage = tape->cache_stage;
 
-#if IDETAPE_DEBUG_LOG
-       if (tape->debug_level >= 4)
-               printk(KERN_INFO "ide-tape: Reached idetape_kmalloc_stage\n");
-#endif /* IDETAPE_DEBUG_LOG */
+       debug_log(DBG_PROCS, "Enter %s\n", __func__);
 
        if (tape->nr_stages >= tape->max_stages)
                return NULL;
@@ -2630,22 +1780,24 @@ static idetape_stage_t *idetape_kmalloc_stage (idetape_tape_t *tape)
        return __idetape_kmalloc_stage(tape, 0, 0);
 }
 
-static int idetape_copy_stage_from_user (idetape_tape_t *tape, idetape_stage_t *stage, const char __user *buf, int n)
+static int idetape_copy_stage_from_user(idetape_tape_t *tape,
+               idetape_stage_t *stage, const char __user *buf, int n)
 {
        struct idetape_bh *bh = tape->bh;
        int count;
        int ret = 0;
 
        while (n) {
-#if IDETAPE_DEBUG_BUGS
                if (bh == NULL) {
-                       printk(KERN_ERR "ide-tape: bh == NULL in "
-                               "idetape_copy_stage_from_user\n");
+                       printk(KERN_ERR "ide-tape: bh == NULL in %s\n",
+                                       __func__);
                        return 1;
                }
-#endif /* IDETAPE_DEBUG_BUGS */
-               count = min((unsigned int)(bh->b_size - atomic_read(&bh->b_count)), (unsigned int)n);
-               if (copy_from_user(bh->b_data + atomic_read(&bh->b_count), buf, count))
+               count = min((unsigned int)
+                               (bh->b_size - atomic_read(&bh->b_count)),
+                               (unsigned int)n);
+               if (copy_from_user(bh->b_data + atomic_read(&bh->b_count), buf,
+                               count))
                        ret = 1;
                n -= count;
                atomic_add(count, &bh->b_count);
@@ -2660,20 +1812,19 @@ static int idetape_copy_stage_from_user (idetape_tape_t *tape, idetape_stage_t *
        return ret;
 }
 
-static int idetape_copy_stage_to_user (idetape_tape_t *tape, char __user *buf, idetape_stage_t *stage, int n)
+static int idetape_copy_stage_to_user(idetape_tape_t *tape, char __user *buf,
+               idetape_stage_t *stage, int n)
 {
        struct idetape_bh *bh = tape->bh;
        int count;
        int ret = 0;
 
        while (n) {
-#if IDETAPE_DEBUG_BUGS
                if (bh == NULL) {
-                       printk(KERN_ERR "ide-tape: bh == NULL in "
-                               "idetape_copy_stage_to_user\n");
+                       printk(KERN_ERR "ide-tape: bh == NULL in %s\n",
+                                       __func__);
                        return 1;
                }
-#endif /* IDETAPE_DEBUG_BUGS */
                count = min(tape->b_count, n);
                if  (copy_to_user(buf, tape->b_data, count))
                        ret = 1;
@@ -2682,7 +1833,8 @@ static int idetape_copy_stage_to_user (idetape_tape_t *tape, char __user *buf, i
                tape->b_count -= count;
                buf += count;
                if (!tape->b_count) {
-                       tape->bh = bh = bh->b_reqnext;
+                       bh = bh->b_reqnext;
+                       tape->bh = bh;
                        if (bh) {
                                tape->b_data = bh->b_data;
                                tape->b_count = atomic_read(&bh->b_count);
@@ -2692,12 +1844,12 @@ static int idetape_copy_stage_to_user (idetape_tape_t *tape, char __user *buf, i
        return ret;
 }
 
-static void idetape_init_merge_stage (idetape_tape_t *tape)
+static void idetape_init_merge_stage(idetape_tape_t *tape)
 {
        struct idetape_bh *bh = tape->merge_stage->bh;
-       
+
        tape->bh = bh;
-       if (tape->chrdev_direction == idetape_direction_write)
+       if (tape->chrdev_dir == IDETAPE_DIR_WRITE)
                atomic_set(&bh->b_count, 0);
        else {
                tape->b_data = bh->b_data;
@@ -2705,7 +1857,7 @@ static void idetape_init_merge_stage (idetape_tape_t *tape)
        }
 }
 
-static void idetape_switch_buffers (idetape_tape_t *tape, idetape_stage_t *stage)
+static void idetape_switch_buffers(idetape_tape_t *tape, idetape_stage_t *stage)
 {
        struct idetape_bh *tmp;
 
@@ -2715,89 +1867,76 @@ static void idetape_switch_buffers (idetape_tape_t *tape, idetape_stage_t *stage
        idetape_init_merge_stage(tape);
 }
 
-/*
- *     idetape_add_stage_tail adds a new stage at the end of the pipeline.
- */
-static void idetape_add_stage_tail (ide_drive_t *drive,idetape_stage_t *stage)
+/* Add a new stage at the end of the pipeline. */
+static void idetape_add_stage_tail(ide_drive_t *drive, idetape_stage_t *stage)
 {
        idetape_tape_t *tape = drive->driver_data;
        unsigned long flags;
-       
-#if IDETAPE_DEBUG_LOG
-       if (tape->debug_level >= 4)
-               printk (KERN_INFO "ide-tape: Reached idetape_add_stage_tail\n");
-#endif /* IDETAPE_DEBUG_LOG */
-       spin_lock_irqsave(&tape->spinlock, flags);
+
+       debug_log(DBG_PROCS, "Enter %s\n", __func__);
+
+       spin_lock_irqsave(&tape->lock, flags);
        stage->next = NULL;
        if (tape->last_stage != NULL)
-               tape->last_stage->next=stage;
+               tape->last_stage->next = stage;
        else
-               tape->first_stage = tape->next_stage=stage;
+               tape->first_stage = stage;
+               tape->next_stage  = stage;
        tape->last_stage = stage;
        if (tape->next_stage == NULL)
                tape->next_stage = tape->last_stage;
        tape->nr_stages++;
        tape->nr_pending_stages++;
-       spin_unlock_irqrestore(&tape->spinlock, flags);
+       spin_unlock_irqrestore(&tape->lock, flags);
 }
 
-/*
- *     idetape_wait_for_request installs a completion in a pending request
- *     and sleeps until it is serviced.
- *
- *     The caller should ensure that the request will not be serviced
- *     before we install the completion (usually by disabling interrupts).
+/* Install a completion in a pending request and sleep until it is serviced. The
+ * caller should ensure that the request will not be serviced before we install
+ * the completion (usually by disabling interrupts).
  */
-static void idetape_wait_for_request (ide_drive_t *drive, struct request *rq)
+static void idetape_wait_for_request(ide_drive_t *drive, struct request *rq)
 {
        DECLARE_COMPLETION_ONSTACK(wait);
        idetape_tape_t *tape = drive->driver_data;
 
-#if IDETAPE_DEBUG_BUGS
        if (rq == NULL || !blk_special_request(rq)) {
-               printk (KERN_ERR "ide-tape: bug: Trying to sleep on non-valid request\n");
+               printk(KERN_ERR "ide-tape: bug: Trying to sleep on non-valid"
+                                " request\n");
                return;
        }
-#endif /* IDETAPE_DEBUG_BUGS */
        rq->end_io_data = &wait;
        rq->end_io = blk_end_sync_rq;
-       spin_unlock_irq(&tape->spinlock);
+       spin_unlock_irq(&tape->lock);
        wait_for_completion(&wait);
        /* The stage and its struct request have been deallocated */
-       spin_lock_irq(&tape->spinlock);
+       spin_lock_irq(&tape->lock);
 }
 
-static ide_startstop_t idetape_read_position_callback (ide_drive_t *drive)
+static ide_startstop_t idetape_read_position_callback(ide_drive_t *drive)
 {
        idetape_tape_t *tape = drive->driver_data;
-       idetape_read_position_result_t *result;
-       
-#if IDETAPE_DEBUG_LOG
-       if (tape->debug_level >= 4)
-               printk(KERN_INFO "ide-tape: Reached idetape_read_position_callback\n");
-#endif /* IDETAPE_DEBUG_LOG */
+       u8 *readpos = tape->pc->buffer;
+
+       debug_log(DBG_PROCS, "Enter %s\n", __func__);
 
        if (!tape->pc->error) {
-               result = (idetape_read_position_result_t *) tape->pc->buffer;
-#if IDETAPE_DEBUG_LOG
-               if (tape->debug_level >= 2)
-                       printk(KERN_INFO "ide-tape: BOP - %s\n",result->bop ? "Yes":"No");
-               if (tape->debug_level >= 2)
-                       printk(KERN_INFO "ide-tape: EOP - %s\n",result->eop ? "Yes":"No");
-#endif /* IDETAPE_DEBUG_LOG */
-               if (result->bpu) {
-                       printk(KERN_INFO "ide-tape: Block location is unknown to the tape\n");
+               debug_log(DBG_SENSE, "BOP - %s\n",
+                               (readpos[0] & 0x80) ? "Yes" : "No");
+               debug_log(DBG_SENSE, "EOP - %s\n",
+                               (readpos[0] & 0x40) ? "Yes" : "No");
+
+               if (readpos[0] & 0x4) {
+                       printk(KERN_INFO "ide-tape: Block location is unknown"
+                                        "to the tape\n");
                        clear_bit(IDETAPE_ADDRESS_VALID, &tape->flags);
                        idetape_end_request(drive, 0, 0);
                } else {
-#if IDETAPE_DEBUG_LOG
-                       if (tape->debug_level >= 2)
-                               printk(KERN_INFO "ide-tape: Block Location - %u\n", ntohl(result->first_block));
-#endif /* IDETAPE_DEBUG_LOG */
-                       tape->partition = result->partition;
-                       tape->first_frame_position = ntohl(result->first_block);
-                       tape->last_frame_position = ntohl(result->last_block);
-                       tape->blocks_in_buffer = result->blocks_in_buffer[2];
+                       debug_log(DBG_SENSE, "Block Location - %u\n",
+                                       be32_to_cpu(*(u32 *)&readpos[4]));
+
+                       tape->partition = readpos[1];
+                       tape->first_frame =
+                               be32_to_cpu(*(u32 *)&readpos[4]);
                        set_bit(IDETAPE_ADDRESS_VALID, &tape->flags);
                        idetape_end_request(drive, 1, 0);
                }
@@ -2808,17 +1947,14 @@ static ide_startstop_t idetape_read_position_callback (ide_drive_t *drive)
 }
 
 /*
- *     idetape_create_write_filemark_cmd will:
- *
- *             1.      Write a filemark if write_filemark=1.
- *             2.      Flush the device buffers without writing a filemark
- *                     if write_filemark=0.
- *
+ * Write a filemark if write_filemark=1. Flush the device buffers without
+ * writing a filemark otherwise.
  */
-static void idetape_create_write_filemark_cmd (ide_drive_t *drive, idetape_pc_t *pc,int write_filemark)
+static void idetape_create_write_filemark_cmd(ide_drive_t *drive,
+               idetape_pc_t *pc, int write_filemark)
 {
        idetape_init_pc(pc);
-       pc->c[0] = IDETAPE_WRITE_FILEMARK_CMD;
+       pc->c[0] = WRITE_FILEMARKS;
        pc->c[4] = write_filemark;
        set_bit(PC_WAIT_FOR_DSC, &pc->flags);
        pc->callback = &idetape_pc_callback;
@@ -2827,31 +1963,24 @@ static void idetape_create_write_filemark_cmd (ide_drive_t *drive, idetape_pc_t
 static void idetape_create_test_unit_ready_cmd(idetape_pc_t *pc)
 {
        idetape_init_pc(pc);
-       pc->c[0] = IDETAPE_TEST_UNIT_READY_CMD;
+       pc->c[0] = TEST_UNIT_READY;
        pc->callback = &idetape_pc_callback;
 }
 
 /*
- *     idetape_queue_pc_tail is based on the following functions:
- *
- *     ide_do_drive_cmd from ide.c
- *     cdrom_queue_request and cdrom_queue_packet_command from ide-cd.c
+ * We add a special packet command request to the tail of the request queue, and
+ * wait for it to be serviced. This is not to be called from within the request
+ * handling part of the driver! We allocate here data on the stack and it is
+ * valid until the request is finished. This is not the case for the bottom part
+ * of the driver, where we are always leaving the functions to wait for an
+ * interrupt or a timer event.
  *
- *     We add a special packet command request to the tail of the request
- *     queue, and wait for it to be serviced.
- *
- *     This is not to be called from within the request handling part
- *     of the driver ! We allocate here data in the stack, and it is valid
- *     until the request is finished. This is not the case for the bottom
- *     part of the driver, where we are always leaving the functions to wait
- *     for an interrupt or a timer event.
- *
- *     From the bottom part of the driver, we should allocate safe memory
- *     using idetape_next_pc_storage and idetape_next_rq_storage, and add
- *     the request to the request list without waiting for it to be serviced !
- *     In that case, we usually use idetape_queue_pc_head.
+ * From the bottom part of the driver, we should allocate safe memory using
+ * idetape_next_pc_storage() and ide_tape_next_rq_storage(), and add the request
+ * to the request list without waiting for it to be serviced! In that case, we
+ * usually use idetape_queue_pc_head().
  */
-static int __idetape_queue_pc_tail (ide_drive_t *drive, idetape_pc_t *pc)
+static int __idetape_queue_pc_tail(ide_drive_t *drive, idetape_pc_t *pc)
 {
        struct ide_tape_obj *tape = drive->driver_data;
        struct request rq;
@@ -2862,10 +1991,11 @@ static int __idetape_queue_pc_tail (ide_drive_t *drive, idetape_pc_t *pc)
        return ide_do_drive_cmd(drive, &rq, ide_wait);
 }
 
-static void idetape_create_load_unload_cmd (ide_drive_t *drive, idetape_pc_t *pc,int cmd)
+static void idetape_create_load_unload_cmd(ide_drive_t *drive, idetape_pc_t *pc,
+               int cmd)
 {
        idetape_init_pc(pc);
-       pc->c[0] = IDETAPE_LOAD_UNLOAD_CMD;
+       pc->c[0] = START_STOP;
        pc->c[4] = cmd;
        set_bit(PC_WAIT_FOR_DSC, &pc->flags);
        pc->callback = &idetape_pc_callback;
@@ -2877,9 +2007,7 @@ static int idetape_wait_ready(ide_drive_t *drive, unsigned long timeout)
        idetape_pc_t pc;
        int load_attempted = 0;
 
-       /*
-        * Wait for the tape to become ready
-        */
+       /* Wait for the tape to become ready */
        set_bit(IDETAPE_MEDIUM_PRESENT, &tape->flags);
        timeout += jiffies;
        while (time_before(jiffies, timeout)) {
@@ -2887,10 +2015,12 @@ static int idetape_wait_ready(ide_drive_t *drive, unsigned long timeout)
                if (!__idetape_queue_pc_tail(drive, &pc))
                        return 0;
                if ((tape->sense_key == 2 && tape->asc == 4 && tape->ascq == 2)
-                   || (tape->asc == 0x3A)) {   /* no media */
+                   || (tape->asc == 0x3A)) {
+                       /* no media */
                        if (load_attempted)
                                return -ENOMEDIUM;
-                       idetape_create_load_unload_cmd(drive, &pc, IDETAPE_LU_LOAD_MASK);
+                       idetape_create_load_unload_cmd(drive, &pc,
+                                                       IDETAPE_LU_LOAD_MASK);
                        __idetape_queue_pc_tail(drive, &pc);
                        load_attempted = 1;
                /* not about to be ready */
@@ -2902,85 +2032,86 @@ static int idetape_wait_ready(ide_drive_t *drive, unsigned long timeout)
        return -EIO;
 }
 
-static int idetape_queue_pc_tail (ide_drive_t *drive,idetape_pc_t *pc)
+static int idetape_queue_pc_tail(ide_drive_t *drive, idetape_pc_t *pc)
 {
        return __idetape_queue_pc_tail(drive, pc);
 }
 
-static int idetape_flush_tape_buffers (ide_drive_t *drive)
+static int idetape_flush_tape_buffers(ide_drive_t *drive)
 {
        idetape_pc_t pc;
        int rc;
 
        idetape_create_write_filemark_cmd(drive, &pc, 0);
-       if ((rc = idetape_queue_pc_tail(drive, &pc)))
+       rc = idetape_queue_pc_tail(drive, &pc);
+       if (rc)
                return rc;
        idetape_wait_ready(drive, 60 * 5 * HZ);
        return 0;
 }
 
-static void idetape_create_read_position_cmd (idetape_pc_t *pc)
+static void idetape_create_read_position_cmd(idetape_pc_t *pc)
 {
        idetape_init_pc(pc);
-       pc->c[0] = IDETAPE_READ_POSITION_CMD;
+       pc->c[0] = READ_POSITION;
        pc->request_transfer = 20;
        pc->callback = &idetape_read_position_callback;
 }
 
-static int idetape_read_position (ide_drive_t *drive)
+static int idetape_read_position(ide_drive_t *drive)
 {
        idetape_tape_t *tape = drive->driver_data;
        idetape_pc_t pc;
        int position;
 
-#if IDETAPE_DEBUG_LOG
-        if (tape->debug_level >= 4)
-               printk(KERN_INFO "ide-tape: Reached idetape_read_position\n");
-#endif /* IDETAPE_DEBUG_LOG */
+       debug_log(DBG_PROCS, "Enter %s\n", __func__);
 
        idetape_create_read_position_cmd(&pc);
        if (idetape_queue_pc_tail(drive, &pc))
                return -1;
-       position = tape->first_frame_position;
+       position = tape->first_frame;
        return position;
 }
 
-static void idetape_create_locate_cmd (ide_drive_t *drive, idetape_pc_t *pc, unsigned int block, u8 partition, int skip)
+static void idetape_create_locate_cmd(ide_drive_t *drive, idetape_pc_t *pc,
+               unsigned int block, u8 partition, int skip)
 {
        idetape_init_pc(pc);
-       pc->c[0] = IDETAPE_LOCATE_CMD;
+       pc->c[0] = POSITION_TO_ELEMENT;
        pc->c[1] = 2;
-       put_unaligned(htonl(block), (unsigned int *) &pc->c[3]);
+       put_unaligned(cpu_to_be32(block), (unsigned int *) &pc->c[3]);
        pc->c[8] = partition;
        set_bit(PC_WAIT_FOR_DSC, &pc->flags);
        pc->callback = &idetape_pc_callback;
 }
 
-static int idetape_create_prevent_cmd (ide_drive_t *drive, idetape_pc_t *pc, int prevent)
+static int idetape_create_prevent_cmd(ide_drive_t *drive, idetape_pc_t *pc,
+                                     int prevent)
 {
        idetape_tape_t *tape = drive->driver_data;
 
-       if (!tape->capabilities.lock)
+       /* device supports locking according to capabilities page */
+       if (!(tape->caps[6] & 0x01))
                return 0;
 
        idetape_init_pc(pc);
-       pc->c[0] = IDETAPE_PREVENT_CMD;
+       pc->c[0] = ALLOW_MEDIUM_REMOVAL;
        pc->c[4] = prevent;
        pc->callback = &idetape_pc_callback;
        return 1;
 }
 
-static int __idetape_discard_read_pipeline (ide_drive_t *drive)
+static int __idetape_discard_read_pipeline(ide_drive_t *drive)
 {
        idetape_tape_t *tape = drive->driver_data;
        unsigned long flags;
        int cnt;
 
-       if (tape->chrdev_direction != idetape_direction_read)
+       if (tape->chrdev_dir != IDETAPE_DIR_READ)
                return 0;
 
        /* Remove merge stage. */
-       cnt = tape->merge_stage_size / tape->tape_block_size;
+       cnt = tape->merge_stage_size / tape->blk_size;
        if (test_and_clear_bit(IDETAPE_FILEMARK, &tape->flags))
                ++cnt;          /* Filemarks count as 1 sector */
        tape->merge_stage_size = 0;
@@ -2991,22 +2122,22 @@ static int __idetape_discard_read_pipeline (ide_drive_t *drive)
 
        /* Clear pipeline flags. */
        clear_bit(IDETAPE_PIPELINE_ERROR, &tape->flags);
-       tape->chrdev_direction = idetape_direction_none;
+       tape->chrdev_dir = IDETAPE_DIR_NONE;
 
        /* Remove pipeline stages. */
        if (tape->first_stage == NULL)
                return 0;
 
-       spin_lock_irqsave(&tape->spinlock, flags);
+       spin_lock_irqsave(&tape->lock, flags);
        tape->next_stage = NULL;
        if (idetape_pipeline_active(tape))
-               idetape_wait_for_request(drive, tape->active_data_request);
-       spin_unlock_irqrestore(&tape->spinlock, flags);
+               idetape_wait_for_request(drive, tape->active_data_rq);
+       spin_unlock_irqrestore(&tape->lock, flags);
 
        while (tape->first_stage != NULL) {
                struct request *rq_ptr = &tape->first_stage->rq;
 
-               cnt += rq_ptr->nr_sectors - rq_ptr->current_nr_sectors; 
+               cnt += rq_ptr->nr_sectors - rq_ptr->current_nr_sectors;
                if (rq_ptr->errors == IDETAPE_ERROR_FILEMARK)
                        ++cnt;
                idetape_remove_stage_head(drive);
@@ -3017,21 +2148,19 @@ static int __idetape_discard_read_pipeline (ide_drive_t *drive)
 }
 
 /*
- *     idetape_position_tape positions the tape to the requested block
- *     using the LOCATE packet command. A READ POSITION command is then
- *     issued to check where we are positioned.
- *
- *     Like all higher level operations, we queue the commands at the tail
- *     of the request queue and wait for their completion.
- *     
+ * Position the tape to the requested block using the LOCATE packet command.
+ * A READ POSITION command is then issued to check where we are positioned. Like
+ * all higher level operations, we queue the commands at the tail of the request
+ * queue and wait for their completion.
  */
-static int idetape_position_tape (ide_drive_t *drive, unsigned int block, u8 partition, int skip)
+static int idetape_position_tape(ide_drive_t *drive, unsigned int block,
+               u8 partition, int skip)
 {
        idetape_tape_t *tape = drive->driver_data;
        int retval;
        idetape_pc_t pc;
 
-       if (tape->chrdev_direction == idetape_direction_read)
+       if (tape->chrdev_dir == IDETAPE_DIR_READ)
                __idetape_discard_read_pipeline(drive);
        idetape_wait_ready(drive, 60 * 5 * HZ);
        idetape_create_locate_cmd(drive, &pc, block, partition, skip);
@@ -3043,7 +2172,8 @@ static int idetape_position_tape (ide_drive_t *drive, unsigned int block, u8 par
        return (idetape_queue_pc_tail(drive, &pc));
 }
 
-static void idetape_discard_read_pipeline (ide_drive_t *drive, int restore_position)
+static void idetape_discard_read_pipeline(ide_drive_t *drive,
+                                         int restore_position)
 {
        idetape_tape_t *tape = drive->driver_data;
        int cnt;
@@ -3054,37 +2184,37 @@ static void idetape_discard_read_pipeline (ide_drive_t *drive, int restore_posit
                position = idetape_read_position(drive);
                seek = position > cnt ? position - cnt : 0;
                if (idetape_position_tape(drive, seek, 0, 0)) {
-                       printk(KERN_INFO "ide-tape: %s: position_tape failed in discard_pipeline()\n", tape->name);
+                       printk(KERN_INFO "ide-tape: %s: position_tape failed in"
+                                        " discard_pipeline()\n", tape->name);
                        return;
                }
        }
 }
 
 /*
- * idetape_queue_rw_tail generates a read/write request for the block
- * device interface and wait for it to be serviced.
+ * Generate a read/write request for the block device interface and wait for it
+ * to be serviced.
  */
-static int idetape_queue_rw_tail(ide_drive_t *drive, int cmd, int blocks, struct idetape_bh *bh)
+static int idetape_queue_rw_tail(ide_drive_t *drive, int cmd, int blocks,
+                                struct idetape_bh *bh)
 {
        idetape_tape_t *tape = drive->driver_data;
        struct request rq;
 
-#if IDETAPE_DEBUG_LOG
-       if (tape->debug_level >= 2)
-               printk(KERN_INFO "ide-tape: idetape_queue_rw_tail: cmd=%d\n",cmd);
-#endif /* IDETAPE_DEBUG_LOG */
-#if IDETAPE_DEBUG_BUGS
+       debug_log(DBG_SENSE, "%s: cmd=%d\n", __func__, cmd);
+
        if (idetape_pipeline_active(tape)) {
-               printk(KERN_ERR "ide-tape: bug: the pipeline is active in idetape_queue_rw_tail\n");
+               printk(KERN_ERR "ide-tape: bug: the pipeline is active in %s\n",
+                               __func__);
                return (0);
        }
-#endif /* IDETAPE_DEBUG_BUGS */        
 
        idetape_init_rq(&rq, cmd);
        rq.rq_disk = tape->disk;
        rq.special = (void *)bh;
-       rq.sector = tape->first_frame_position;
-       rq.nr_sectors = rq.current_nr_sectors = blocks;
+       rq.sector = tape->first_frame;
+       rq.nr_sectors           = blocks;
+       rq.current_nr_sectors   = blocks;
        (void) ide_do_drive_cmd(drive, &rq, ide_wait);
 
        if ((cmd & (REQ_IDETAPE_READ | REQ_IDETAPE_WRITE)) == 0)
@@ -3094,14 +2224,11 @@ static int idetape_queue_rw_tail(ide_drive_t *drive, int cmd, int blocks, struct
                idetape_init_merge_stage(tape);
        if (rq.errors == IDETAPE_ERROR_GENERAL)
                return -EIO;
-       return (tape->tape_block_size * (blocks-rq.current_nr_sectors));
+       return (tape->blk_size * (blocks-rq.current_nr_sectors));
 }
 
-/*
- *     idetape_insert_pipeline_into_queue is used to start servicing the
- *     pipeline stages, starting from tape->next_stage.
- */
-static void idetape_insert_pipeline_into_queue (ide_drive_t *drive)
+/* start servicing the pipeline stages, starting from tape->next_stage. */
+static void idetape_plug_pipeline(ide_drive_t *drive)
 {
        idetape_tape_t *tape = drive->driver_data;
 
@@ -3109,142 +2236,128 @@ static void idetape_insert_pipeline_into_queue (ide_drive_t *drive)
                return;
        if (!idetape_pipeline_active(tape)) {
                set_bit(IDETAPE_PIPELINE_ACTIVE, &tape->flags);
-               idetape_active_next_stage(drive);
-               (void) ide_do_drive_cmd(drive, tape->active_data_request, ide_end);
+               idetape_activate_next_stage(drive);
+               (void) ide_do_drive_cmd(drive, tape->active_data_rq, ide_end);
        }
 }
 
-static void idetape_create_inquiry_cmd (idetape_pc_t *pc)
+static void idetape_create_inquiry_cmd(idetape_pc_t *pc)
 {
        idetape_init_pc(pc);
-       pc->c[0] = IDETAPE_INQUIRY_CMD;
-       pc->c[4] = pc->request_transfer = 254;
+       pc->c[0] = INQUIRY;
+       pc->c[4] = 254;
+       pc->request_transfer = 254;
        pc->callback = &idetape_pc_callback;
 }
 
-static void idetape_create_rewind_cmd (ide_drive_t *drive, idetape_pc_t *pc)
+static void idetape_create_rewind_cmd(ide_drive_t *drive, idetape_pc_t *pc)
 {
        idetape_init_pc(pc);
-       pc->c[0] = IDETAPE_REWIND_CMD;
+       pc->c[0] = REZERO_UNIT;
        set_bit(PC_WAIT_FOR_DSC, &pc->flags);
        pc->callback = &idetape_pc_callback;
 }
 
-#if 0
-static void idetape_create_mode_select_cmd (idetape_pc_t *pc, int length)
+static void idetape_create_erase_cmd(idetape_pc_t *pc)
 {
        idetape_init_pc(pc);
-       set_bit(PC_WRITING, &pc->flags);
-       pc->c[0] = IDETAPE_MODE_SELECT_CMD;
-       pc->c[1] = 0x10;
-       put_unaligned(htons(length), (unsigned short *) &pc->c[3]);
-       pc->request_transfer = 255;
-       pc->callback = &idetape_pc_callback;
-}
-#endif
-
-static void idetape_create_erase_cmd (idetape_pc_t *pc)
-{
-       idetape_init_pc(pc);
-       pc->c[0] = IDETAPE_ERASE_CMD;
+       pc->c[0] = ERASE;
        pc->c[1] = 1;
        set_bit(PC_WAIT_FOR_DSC, &pc->flags);
        pc->callback = &idetape_pc_callback;
 }
 
-static void idetape_create_space_cmd (idetape_pc_t *pc,int count, u8 cmd)
+static void idetape_create_space_cmd(idetape_pc_t *pc, int count, u8 cmd)
 {
        idetape_init_pc(pc);
-       pc->c[0] = IDETAPE_SPACE_CMD;
-       put_unaligned(htonl(count), (unsigned int *) &pc->c[1]);
+       pc->c[0] = SPACE;
+       put_unaligned(cpu_to_be32(count), (unsigned int *) &pc->c[1]);
        pc->c[1] = cmd;
        set_bit(PC_WAIT_FOR_DSC, &pc->flags);
        pc->callback = &idetape_pc_callback;
 }
 
-static void idetape_wait_first_stage (ide_drive_t *drive)
+static void idetape_wait_first_stage(ide_drive_t *drive)
 {
        idetape_tape_t *tape = drive->driver_data;
        unsigned long flags;
 
        if (tape->first_stage == NULL)
                return;
-       spin_lock_irqsave(&tape->spinlock, flags);
+       spin_lock_irqsave(&tape->lock, flags);
        if (tape->active_stage == tape->first_stage)
-               idetape_wait_for_request(drive, tape->active_data_request);
-       spin_unlock_irqrestore(&tape->spinlock, flags);
+               idetape_wait_for_request(drive, tape->active_data_rq);
+       spin_unlock_irqrestore(&tape->lock, flags);
 }
 
 /*
- *     idetape_add_chrdev_write_request tries to add a character device
- *     originated write request to our pipeline. In case we don't succeed,
- *     we revert to non-pipelined operation mode for this request.
+ * Try to add a character device originated write request to our pipeline. In
+ * case we don't succeed, we revert to non-pipelined operation mode for this
+ * request. In order to accomplish that, we
  *
- *     1.      Try to allocate a new pipeline stage.
- *     2.      If we can't, wait for more and more requests to be serviced
- *             and try again each time.
- *     3.      If we still can't allocate a stage, fallback to
- *             non-pipelined operation mode for this request.
+ * 1. Try to allocate a new pipeline stage.
+ * 2. If we can't, wait for more and more requests to be serviced and try again
+ * each time.
+ * 3. If we still can't allocate a stage, fallback to non-pipelined operation
+ * mode for this request.
  */
-static int idetape_add_chrdev_write_request (ide_drive_t *drive, int blocks)
+static int idetape_add_chrdev_write_request(ide_drive_t *drive, int blocks)
 {
        idetape_tape_t *tape = drive->driver_data;
        idetape_stage_t *new_stage;
        unsigned long flags;
        struct request *rq;
 
-#if IDETAPE_DEBUG_LOG
-       if (tape->debug_level >= 3)
-               printk(KERN_INFO "ide-tape: Reached idetape_add_chrdev_write_request\n");
-#endif /* IDETAPE_DEBUG_LOG */
+       debug_log(DBG_CHRDEV, "Enter %s\n", __func__);
 
-       /*
-        *      Attempt to allocate a new stage.
-        *      Pay special attention to possible race conditions.
-        */
+       /* Attempt to allocate a new stage. Beware possible race conditions. */
        while ((new_stage = idetape_kmalloc_stage(tape)) == NULL) {
-               spin_lock_irqsave(&tape->spinlock, flags);
+               spin_lock_irqsave(&tape->lock, flags);
                if (idetape_pipeline_active(tape)) {
-                       idetape_wait_for_request(drive, tape->active_data_request);
-                       spin_unlock_irqrestore(&tape->spinlock, flags);
+                       idetape_wait_for_request(drive, tape->active_data_rq);
+                       spin_unlock_irqrestore(&tape->lock, flags);
                } else {
-                       spin_unlock_irqrestore(&tape->spinlock, flags);
-                       idetape_insert_pipeline_into_queue(drive);
+                       spin_unlock_irqrestore(&tape->lock, flags);
+                       idetape_plug_pipeline(drive);
                        if (idetape_pipeline_active(tape))
                                continue;
                        /*
-                        *      Linux is short on memory. Fallback to
-                        *      non-pipelined operation mode for this request.
+                        * The machine is short on memory. Fallback to non-
+                        * pipelined operation mode for this request.
                         */
-                       return idetape_queue_rw_tail(drive, REQ_IDETAPE_WRITE, blocks, tape->merge_stage->bh);
+                       return idetape_queue_rw_tail(drive, REQ_IDETAPE_WRITE,
+                                               blocks, tape->merge_stage->bh);
                }
        }
        rq = &new_stage->rq;
        idetape_init_rq(rq, REQ_IDETAPE_WRITE);
        /* Doesn't actually matter - We always assume sequential access */
-       rq->sector = tape->first_frame_position;
-       rq->nr_sectors = rq->current_nr_sectors = blocks;
+       rq->sector = tape->first_frame;
+       rq->current_nr_sectors = blocks;
+       rq->nr_sectors = blocks;
 
        idetape_switch_buffers(tape, new_stage);
        idetape_add_stage_tail(drive, new_stage);
        tape->pipeline_head++;
-       calculate_speeds(drive);
+       idetape_calculate_speeds(drive);
 
        /*
-        *      Estimate whether the tape has stopped writing by checking
-        *      if our write pipeline is currently empty. If we are not
-        *      writing anymore, wait for the pipeline to be full enough
-        *      (90%) before starting to service requests, so that we will
-        *      be able to keep up with the higher speeds of the tape.
+        * Estimate whether the tape has stopped writing by checking if our
+        * write pipeline is currently empty. If we are not writing anymore,
+        * wait for the pipeline to be almost completely full (90%) before
+        * starting to service requests, so that we will be able to keep up with
+        * the higher speeds of the tape.
         */
        if (!idetape_pipeline_active(tape)) {
                if (tape->nr_stages >= tape->max_stages * 9 / 10 ||
-                   tape->nr_stages >= tape->max_stages - tape->uncontrolled_pipeline_head_speed * 3 * 1024 / tape->tape_block_size) {
+                       tape->nr_stages >= tape->max_stages -
+                       tape->uncontrolled_pipeline_head_speed * 3 * 1024 /
+                       tape->blk_size) {
                        tape->measure_insert_time = 1;
                        tape->insert_time = jiffies;
                        tape->insert_size = 0;
                        tape->insert_speed = 0;
-                       idetape_insert_pipeline_into_queue(drive);
+                       idetape_plug_pipeline(drive);
                }
        }
        if (test_and_clear_bit(IDETAPE_PIPELINE_ERROR, &tape->flags))
@@ -3254,46 +2367,46 @@ static int idetape_add_chrdev_write_request (ide_drive_t *drive, int blocks)
 }
 
 /*
- *     idetape_wait_for_pipeline will wait until all pending pipeline
- *     requests are serviced. Typically called on device close.
+ * Wait until all pending pipeline requests are serviced. Typically called on
+ * device close.
  */
-static void idetape_wait_for_pipeline (ide_drive_t *drive)
+static void idetape_wait_for_pipeline(ide_drive_t *drive)
 {
        idetape_tape_t *tape = drive->driver_data;
        unsigned long flags;
 
        while (tape->next_stage || idetape_pipeline_active(tape)) {
-               idetape_insert_pipeline_into_queue(drive);
-               spin_lock_irqsave(&tape->spinlock, flags);
+               idetape_plug_pipeline(drive);
+               spin_lock_irqsave(&tape->lock, flags);
                if (idetape_pipeline_active(tape))
-                       idetape_wait_for_request(drive, tape->active_data_request);
-               spin_unlock_irqrestore(&tape->spinlock, flags);
+                       idetape_wait_for_request(drive, tape->active_data_rq);
+               spin_unlock_irqrestore(&tape->lock, flags);
        }
 }
 
-static void idetape_empty_write_pipeline (ide_drive_t *drive)
+static void idetape_empty_write_pipeline(ide_drive_t *drive)
 {
        idetape_tape_t *tape = drive->driver_data;
        int blocks, min;
        struct idetape_bh *bh;
-       
-#if IDETAPE_DEBUG_BUGS
-       if (tape->chrdev_direction != idetape_direction_write) {
-               printk(KERN_ERR "ide-tape: bug: Trying to empty write pipeline, but we are not writing.\n");
+
+       if (tape->chrdev_dir != IDETAPE_DIR_WRITE) {
+               printk(KERN_ERR "ide-tape: bug: Trying to empty write pipeline,"
+                               " but we are not writing.\n");
                return;
        }
        if (tape->merge_stage_size > tape->stage_size) {
                printk(KERN_ERR "ide-tape: bug: merge_buffer too big\n");
                tape->merge_stage_size = tape->stage_size;
        }
-#endif /* IDETAPE_DEBUG_BUGS */
        if (tape->merge_stage_size) {
-               blocks = tape->merge_stage_size / tape->tape_block_size;
-               if (tape->merge_stage_size % tape->tape_block_size) {
+               blocks = tape->merge_stage_size / tape->blk_size;
+               if (tape->merge_stage_size % tape->blk_size) {
                        unsigned int i;
 
                        blocks++;
-                       i = tape->tape_block_size - tape->merge_stage_size % tape->tape_block_size;
+                       i = tape->blk_size - tape->merge_stage_size %
+                               tape->blk_size;
                        bh = tape->bh->b_reqnext;
                        while (bh) {
                                atomic_set(&bh->b_count, 0);
@@ -3302,12 +2415,14 @@ static void idetape_empty_write_pipeline (ide_drive_t *drive)
                        bh = tape->bh;
                        while (i) {
                                if (bh == NULL) {
-
-                                       printk(KERN_INFO "ide-tape: bug, bh NULL\n");
+                                       printk(KERN_INFO "ide-tape: bug,"
+                                                        " bh NULL\n");
                                        break;
                                }
-                               min = min(i, (unsigned int)(bh->b_size - atomic_read(&bh->b_count)));
-                               memset(bh->b_data + atomic_read(&bh->b_count), 0, min);
+                               min = min(i, (unsigned int)(bh->b_size -
+                                               atomic_read(&bh->b_count)));
+                               memset(bh->b_data + atomic_read(&bh->b_count),
+                                               0, min);
                                atomic_add(min, &bh->b_count);
                                i -= min;
                                bh = bh->b_reqnext;
@@ -3322,16 +2437,15 @@ static void idetape_empty_write_pipeline (ide_drive_t *drive)
                tape->merge_stage = NULL;
        }
        clear_bit(IDETAPE_PIPELINE_ERROR, &tape->flags);
-       tape->chrdev_direction = idetape_direction_none;
+       tape->chrdev_dir = IDETAPE_DIR_NONE;
 
        /*
-        *      On the next backup, perform the feedback loop again.
-        *      (I don't want to keep sense information between backups,
-        *       as some systems are constantly on, and the system load
-        *       can be totally different on the next backup).
+        * On the next backup, perform the feedback loop again. (I don't want to
+        * keep sense information between backups, as some systems are
+        * constantly on, and the system load can be totally different on the
+        * next backup).
         */
        tape->max_stages = tape->min_pipeline;
-#if IDETAPE_DEBUG_BUGS
        if (tape->first_stage != NULL ||
            tape->next_stage != NULL ||
            tape->last_stage != NULL ||
@@ -3342,60 +2456,64 @@ static void idetape_empty_write_pipeline (ide_drive_t *drive)
                        tape->first_stage, tape->next_stage,
                        tape->last_stage, tape->nr_stages);
        }
-#endif /* IDETAPE_DEBUG_BUGS */
 }
 
-static void idetape_restart_speed_control (ide_drive_t *drive)
+static void idetape_restart_speed_control(ide_drive_t *drive)
 {
        idetape_tape_t *tape = drive->driver_data;
 
        tape->restart_speed_control_req = 0;
        tape->pipeline_head = 0;
-       tape->controlled_last_pipeline_head = tape->uncontrolled_last_pipeline_head = 0;
-       tape->controlled_previous_pipeline_head = tape->uncontrolled_previous_pipeline_head = 0;
-       tape->pipeline_head_speed = tape->controlled_pipeline_head_speed = 5000;
+       tape->controlled_last_pipeline_head = 0;
+       tape->controlled_previous_pipeline_head = 0;
+       tape->uncontrolled_previous_pipeline_head = 0;
+       tape->controlled_pipeline_head_speed = 5000;
+       tape->pipeline_head_speed = 5000;
        tape->uncontrolled_pipeline_head_speed = 0;
-       tape->controlled_pipeline_head_time = tape->uncontrolled_pipeline_head_time = jiffies;
-       tape->controlled_previous_head_time = tape->uncontrolled_previous_head_time = jiffies;
+       tape->controlled_pipeline_head_time =
+               tape->uncontrolled_pipeline_head_time = jiffies;
+       tape->controlled_previous_head_time =
+               tape->uncontrolled_previous_head_time = jiffies;
 }
 
-static int idetape_initiate_read (ide_drive_t *drive, int max_stages)
+static int idetape_init_read(ide_drive_t *drive, int max_stages)
 {
        idetape_tape_t *tape = drive->driver_data;
        idetape_stage_t *new_stage;
        struct request rq;
        int bytes_read;
-       int blocks = tape->capabilities.ctl;
+       u16 blocks = *(u16 *)&tape->caps[12];
 
        /* Initialize read operation */
-       if (tape->chrdev_direction != idetape_direction_read) {
-               if (tape->chrdev_direction == idetape_direction_write) {
+       if (tape->chrdev_dir != IDETAPE_DIR_READ) {
+               if (tape->chrdev_dir == IDETAPE_DIR_WRITE) {
                        idetape_empty_write_pipeline(drive);
                        idetape_flush_tape_buffers(drive);
                }
-#if IDETAPE_DEBUG_BUGS
                if (tape->merge_stage || tape->merge_stage_size) {
-                       printk (KERN_ERR "ide-tape: merge_stage_size should be 0 now\n");
+                       printk(KERN_ERR "ide-tape: merge_stage_size should be"
+                                        " 0 now\n");
                        tape->merge_stage_size = 0;
                }
-#endif /* IDETAPE_DEBUG_BUGS */
-               if ((tape->merge_stage = __idetape_kmalloc_stage(tape, 0, 0)) == NULL)
+               tape->merge_stage = __idetape_kmalloc_stage(tape, 0, 0);
+               if (!tape->merge_stage)
                        return -ENOMEM;
-               tape->chrdev_direction = idetape_direction_read;
+               tape->chrdev_dir = IDETAPE_DIR_READ;
 
                /*
-                *      Issue a read 0 command to ensure that DSC handshake
-                *      is switched from completion mode to buffer available
-                *      mode.
-                *      No point in issuing this if DSC overlap isn't supported,
-                *      some drives (Seagate STT3401A) will return an error.
+                * Issue a read 0 command to ensure that DSC handshake is
+                * switched from completion mode to buffer available mode.
+                * No point in issuing this if DSC overlap isn't supported, some
+                * drives (Seagate STT3401A) will return an error.
                 */
                if (drive->dsc_overlap) {
-                       bytes_read = idetape_queue_rw_tail(drive, REQ_IDETAPE_READ, 0, tape->merge_stage->bh);
+                       bytes_read = idetape_queue_rw_tail(drive,
+                                                       REQ_IDETAPE_READ, 0,
+                                                       tape->merge_stage->bh);
                        if (bytes_read < 0) {
                                __idetape_kfree_stage(tape->merge_stage);
                                tape->merge_stage = NULL;
-                               tape->chrdev_direction = idetape_direction_none;
+                               tape->chrdev_dir = IDETAPE_DIR_NONE;
                                return bytes_read;
                        }
                }
@@ -3403,8 +2521,9 @@ static int idetape_initiate_read (ide_drive_t *drive, int max_stages)
        if (tape->restart_speed_control_req)
                idetape_restart_speed_control(drive);
        idetape_init_rq(&rq, REQ_IDETAPE_READ);
-       rq.sector = tape->first_frame_position;
-       rq.nr_sectors = rq.current_nr_sectors = blocks;
+       rq.sector = tape->first_frame;
+       rq.nr_sectors = blocks;
+       rq.current_nr_sectors = blocks;
        if (!test_bit(IDETAPE_PIPELINE_ERROR, &tape->flags) &&
            tape->nr_stages < max_stages) {
                new_stage = idetape_kmalloc_stage(tape);
@@ -3422,50 +2541,43 @@ static int idetape_initiate_read (ide_drive_t *drive, int max_stages)
                        tape->insert_time = jiffies;
                        tape->insert_size = 0;
                        tape->insert_speed = 0;
-                       idetape_insert_pipeline_into_queue(drive);
+                       idetape_plug_pipeline(drive);
                }
        }
        return 0;
 }
 
 /*
- *     idetape_add_chrdev_read_request is called from idetape_chrdev_read
- *     to service a character device read request and add read-ahead
- *     requests to our pipeline.
+ * Called from idetape_chrdev_read() to service a character device read request
+ * and add read-ahead requests to our pipeline.
  */
-static int idetape_add_chrdev_read_request (ide_drive_t *drive,int blocks)
+static int idetape_add_chrdev_read_request(ide_drive_t *drive, int blocks)
 {
        idetape_tape_t *tape = drive->driver_data;
        unsigned long flags;
        struct request *rq_ptr;
        int bytes_read;
 
-#if IDETAPE_DEBUG_LOG
-       if (tape->debug_level >= 4)
-               printk(KERN_INFO "ide-tape: Reached idetape_add_chrdev_read_request, %d blocks\n", blocks);
-#endif /* IDETAPE_DEBUG_LOG */
+       debug_log(DBG_PROCS, "Enter %s, %d blocks\n", __func__, blocks);
 
-       /*
-        * If we are at a filemark, return a read length of 0
-        */
+       /* If we are at a filemark, return a read length of 0 */
        if (test_bit(IDETAPE_FILEMARK, &tape->flags))
                return 0;
 
-       /*
-        * Wait for the next block to be available at the head
-        * of the pipeline
-        */
-       idetape_initiate_read(drive, tape->max_stages);
+       /* Wait for the next block to reach the head of the pipeline. */
+       idetape_init_read(drive, tape->max_stages);
        if (tape->first_stage == NULL) {
                if (test_bit(IDETAPE_PIPELINE_ERROR, &tape->flags))
                        return 0;
-               return idetape_queue_rw_tail(drive, REQ_IDETAPE_READ, blocks, tape->merge_stage->bh);
+               return idetape_queue_rw_tail(drive, REQ_IDETAPE_READ, blocks,
+                                       tape->merge_stage->bh);
        }
        idetape_wait_first_stage(drive);
        rq_ptr = &tape->first_stage->rq;
-       bytes_read = tape->tape_block_size * (rq_ptr->nr_sectors - rq_ptr->current_nr_sectors);
-       rq_ptr->nr_sectors = rq_ptr->current_nr_sectors = 0;
-
+       bytes_read = tape->blk_size * (rq_ptr->nr_sectors -
+                                       rq_ptr->current_nr_sectors);
+       rq_ptr->nr_sectors = 0;
+       rq_ptr->current_nr_sectors = 0;
 
        if (rq_ptr->errors == IDETAPE_ERROR_EOD)
                return 0;
@@ -3473,45 +2585,46 @@ static int idetape_add_chrdev_read_request (ide_drive_t *drive,int blocks)
                idetape_switch_buffers(tape, tape->first_stage);
                if (rq_ptr->errors == IDETAPE_ERROR_FILEMARK)
                        set_bit(IDETAPE_FILEMARK, &tape->flags);
-               spin_lock_irqsave(&tape->spinlock, flags);
+               spin_lock_irqsave(&tape->lock, flags);
                idetape_remove_stage_head(drive);
-               spin_unlock_irqrestore(&tape->spinlock, flags);
+               spin_unlock_irqrestore(&tape->lock, flags);
                tape->pipeline_head++;
-               calculate_speeds(drive);
+               idetape_calculate_speeds(drive);
        }
-#if IDETAPE_DEBUG_BUGS
-       if (bytes_read > blocks * tape->tape_block_size) {
-               printk(KERN_ERR "ide-tape: bug: trying to return more bytes than requested\n");
-               bytes_read = blocks * tape->tape_block_size;
+       if (bytes_read > blocks * tape->blk_size) {
+               printk(KERN_ERR "ide-tape: bug: trying to return more bytes"
+                               " than requested\n");
+               bytes_read = blocks * tape->blk_size;
        }
-#endif /* IDETAPE_DEBUG_BUGS */
        return (bytes_read);
 }
 
-static void idetape_pad_zeros (ide_drive_t *drive, int bcount)
+static void idetape_pad_zeros(ide_drive_t *drive, int bcount)
 {
        idetape_tape_t *tape = drive->driver_data;
        struct idetape_bh *bh;
        int blocks;
-       
+
        while (bcount) {
                unsigned int count;
 
                bh = tape->merge_stage->bh;
                count = min(tape->stage_size, bcount);
                bcount -= count;
-               blocks = count / tape->tape_block_size;
+               blocks = count / tape->blk_size;
                while (count) {
-                       atomic_set(&bh->b_count, min(count, (unsigned int)bh->b_size));
+                       atomic_set(&bh->b_count,
+                                  min(count, (unsigned int)bh->b_size));
                        memset(bh->b_data, 0, atomic_read(&bh->b_count));
                        count -= atomic_read(&bh->b_count);
                        bh = bh->b_reqnext;
                }
-               idetape_queue_rw_tail(drive, REQ_IDETAPE_WRITE, blocks, tape->merge_stage->bh);
+               idetape_queue_rw_tail(drive, REQ_IDETAPE_WRITE, blocks,
+                                     tape->merge_stage->bh);
        }
 }
 
-static int idetape_pipeline_size (ide_drive_t *drive)
+static int idetape_pipeline_size(ide_drive_t *drive)
 {
        idetape_tape_t *tape = drive->driver_data;
        idetape_stage_t *stage;
@@ -3522,9 +2635,10 @@ static int idetape_pipeline_size (ide_drive_t *drive)
        stage = tape->first_stage;
        while (stage != NULL) {
                rq = &stage->rq;
-               size += tape->tape_block_size * (rq->nr_sectors-rq->current_nr_sectors);
+               size += tape->blk_size * (rq->nr_sectors -
+                               rq->current_nr_sectors);
                if (rq->errors == IDETAPE_ERROR_FILEMARK)
-                       size += tape->tape_block_size;
+                       size += tape->blk_size;
                stage = stage->next;
        }
        size += tape->merge_stage_size;
@@ -3532,20 +2646,18 @@ static int idetape_pipeline_size (ide_drive_t *drive)
 }
 
 /*
- *     Rewinds the tape to the Beginning Of the current Partition (BOP).
- *
- *     We currently support only one partition.
- */ 
-static int idetape_rewind_tape (ide_drive_t *drive)
+ * Rewinds the tape to the Beginning Of the current Partition (BOP). We
+ * currently support only one partition.
+ */
+static int idetape_rewind_tape(ide_drive_t *drive)
 {
        int retval;
        idetape_pc_t pc;
-#if IDETAPE_DEBUG_LOG
-       idetape_tape_t *tape = drive->driver_data;
-       if (tape->debug_level >= 2)
-               printk(KERN_INFO "ide-tape: Reached idetape_rewind_tape\n");
-#endif /* IDETAPE_DEBUG_LOG */ 
-       
+       idetape_tape_t *tape;
+       tape = drive->driver_data;
+
+       debug_log(DBG_SENSE, "Enter %s\n", __func__);
+
        idetape_create_rewind_cmd(drive, &pc);
        retval = idetape_queue_pc_tail(drive, &pc);
        if (retval)
@@ -3558,71 +2670,66 @@ static int idetape_rewind_tape (ide_drive_t *drive)
        return 0;
 }
 
-/*
- *     Our special ide-tape ioctl's.
- *
- *     Currently there aren't any ioctl's.
- *     mtio.h compatible commands should be issued to the character device
- *     interface.
- */
-static int idetape_blkdev_ioctl(ide_drive_t *drive, unsigned int cmd, unsigned long arg)
+/* mtio.h compatible commands should be issued to the chrdev interface. */
+static int idetape_blkdev_ioctl(ide_drive_t *drive, unsigned int cmd,
+                               unsigned long arg)
 {
        idetape_tape_t *tape = drive->driver_data;
-       idetape_config_t config;
        void __user *argp = (void __user *)arg;
 
-#if IDETAPE_DEBUG_LOG  
-       if (tape->debug_level >= 4)
-               printk(KERN_INFO "ide-tape: Reached idetape_blkdev_ioctl\n");
-#endif /* IDETAPE_DEBUG_LOG */
+       struct idetape_config {
+               int dsc_rw_frequency;
+               int dsc_media_access_frequency;
+               int nr_stages;
+       } config;
+
+       debug_log(DBG_PROCS, "Enter %s\n", __func__);
+
        switch (cmd) {
-               case 0x0340:
-                       if (copy_from_user(&config, argp, sizeof (idetape_config_t)))
-                               return -EFAULT;
-                       tape->best_dsc_rw_frequency = config.dsc_rw_frequency;
-                       tape->max_stages = config.nr_stages;
-                       break;
-               case 0x0350:
-                       config.dsc_rw_frequency = (int) tape->best_dsc_rw_frequency;
-                       config.nr_stages = tape->max_stages; 
-                       if (copy_to_user(argp, &config, sizeof (idetape_config_t)))
-                               return -EFAULT;
-                       break;
-               default:
-                       return -EIO;
+       case 0x0340:
+               if (copy_from_user(&config, argp, sizeof(config)))
+                       return -EFAULT;
+               tape->best_dsc_rw_freq = config.dsc_rw_frequency;
+               tape->max_stages = config.nr_stages;
+               break;
+       case 0x0350:
+               config.dsc_rw_frequency = (int) tape->best_dsc_rw_freq;
+               config.nr_stages = tape->max_stages;
+               if (copy_to_user(argp, &config, sizeof(config)))
+                       return -EFAULT;
+               break;
+       default:
+               return -EIO;
        }
        return 0;
 }
 
 /*
- *     idetape_space_over_filemarks is now a bit more complicated than just
- *     passing the command to the tape since we may have crossed some
- *     filemarks during our pipelined read-ahead mode.
- *
- *     As a minor side effect, the pipeline enables us to support MTFSFM when
- *     the filemark is in our internal pipeline even if the tape doesn't
- *     support spacing over filemarks in the reverse direction.
+ * The function below is now a bit more complicated than just passing the
+ * command to the tape since we may have crossed some filemarks during our
+ * pipelined read-ahead mode. As a minor side effect, the pipeline enables us to
+ * support MTFSFM when the filemark is in our internal pipeline even if the tape
+ * doesn't support spacing over filemarks in the reverse direction.
  */
-static int idetape_space_over_filemarks (ide_drive_t *drive,short mt_op,int mt_count)
+static int idetape_space_over_filemarks(ide_drive_t *drive, short mt_op,
+                                       int mt_count)
 {
        idetape_tape_t *tape = drive->driver_data;
        idetape_pc_t pc;
        unsigned long flags;
-       int retval,count=0;
+       int retval, count = 0;
+       int sprev = !!(tape->caps[4] & 0x20);
 
        if (mt_count == 0)
                return 0;
        if (MTBSF == mt_op || MTBSFM == mt_op) {
-               if (!tape->capabilities.sprev)
+               if (!sprev)
                        return -EIO;
-               mt_count = - mt_count;
+               mt_count = -mt_count;
        }
 
-       if (tape->chrdev_direction == idetape_direction_read) {
-               /*
-                *      We have a read-ahead buffer. Scan it for crossed
-                *      filemarks.
-                */
+       if (tape->chrdev_dir == IDETAPE_DIR_READ) {
+               /* its a read-ahead buffer, scan it for crossed filemarks. */
                tape->merge_stage_size = 0;
                if (test_and_clear_bit(IDETAPE_FILEMARK, &tape->flags))
                        ++count;
@@ -3632,24 +2739,27 @@ static int idetape_space_over_filemarks (ide_drive_t *drive,short mt_op,int mt_c
                                        set_bit(IDETAPE_FILEMARK, &tape->flags);
                                return 0;
                        }
-                       spin_lock_irqsave(&tape->spinlock, flags);
+                       spin_lock_irqsave(&tape->lock, flags);
                        if (tape->first_stage == tape->active_stage) {
                                /*
-                                *      We have reached the active stage in the read pipeline.
-                                *      There is no point in allowing the drive to continue
-                                *      reading any farther, so we stop the pipeline.
+                                * We have reached the active stage in the read
+                                * pipeline. There is no point in allowing the
+                                * drive to continue reading any farther, so we
+                                * stop the pipeline.
                                 *
-                                *      This section should be moved to a separate subroutine,
-                                *      because a similar function is performed in
-                                *      __idetape_discard_read_pipeline(), for example.
+                                * This section should be moved to a separate
+                                * subroutine because similar operations are
+                                * done in __idetape_discard_read_pipeline(),
+                                * for example.
                                 */
                                tape->next_stage = NULL;
-                               spin_unlock_irqrestore(&tape->spinlock, flags);
+                               spin_unlock_irqrestore(&tape->lock, flags);
                                idetape_wait_first_stage(drive);
                                tape->next_stage = tape->first_stage->next;
                        } else
-                               spin_unlock_irqrestore(&tape->spinlock, flags);
-                       if (tape->first_stage->rq.errors == IDETAPE_ERROR_FILEMARK)
+                               spin_unlock_irqrestore(&tape->lock, flags);
+                       if (tape->first_stage->rq.errors ==
+                                       IDETAPE_ERROR_FILEMARK)
                                ++count;
                        idetape_remove_stage_head(drive);
                }
@@ -3657,157 +2767,156 @@ static int idetape_space_over_filemarks (ide_drive_t *drive,short mt_op,int mt_c
        }
 
        /*
-        *      The filemark was not found in our internal pipeline.
-        *      Now we can issue the space command.
+        * The filemark was not found in our internal pipeline; now we can issue
+        * the space command.
         */
        switch (mt_op) {
-               case MTFSF:
-               case MTBSF:
-                       idetape_create_space_cmd(&pc,mt_count-count,IDETAPE_SPACE_OVER_FILEMARK);
-                       return (idetape_queue_pc_tail(drive, &pc));
-               case MTFSFM:
-               case MTBSFM:
-                       if (!tape->capabilities.sprev)
-                               return (-EIO);
-                       retval = idetape_space_over_filemarks(drive, MTFSF, mt_count-count);
-                       if (retval) return (retval);
-                       count = (MTBSFM == mt_op ? 1 : -1);
-                       return (idetape_space_over_filemarks(drive, MTFSF, count));
-               default:
-                       printk(KERN_ERR "ide-tape: MTIO operation %d not supported\n",mt_op);
-                       return (-EIO);
+       case MTFSF:
+       case MTBSF:
+               idetape_create_space_cmd(&pc, mt_count - count,
+                                        IDETAPE_SPACE_OVER_FILEMARK);
+               return idetape_queue_pc_tail(drive, &pc);
+       case MTFSFM:
+       case MTBSFM:
+               if (!sprev)
+                       return -EIO;
+               retval = idetape_space_over_filemarks(drive, MTFSF,
+                                                     mt_count - count);
+               if (retval)
+                       return retval;
+               count = (MTBSFM == mt_op ? 1 : -1);
+               return idetape_space_over_filemarks(drive, MTFSF, count);
+       default:
+               printk(KERN_ERR "ide-tape: MTIO operation %d not supported\n",
+                               mt_op);
+               return -EIO;
        }
 }
 
-
 /*
- *     Our character device read / write functions.
+ * Our character device read / write functions.
  *
- *     The tape is optimized to maximize throughput when it is transferring
- *     an integral number of the "continuous transfer limit", which is
- *     a parameter of the specific tape (26 KB on my particular tape).
- *      (32 kB for Onstream)
+ * The tape is optimized to maximize throughput when it is transferring an
+ * integral number of the "continuous transfer limit", which is a parameter of
+ * the specific tape (26kB on my particular tape, 32kB for Onstream).
  *
- *     As of version 1.3 of the driver, the character device provides an
- *     abstract continuous view of the media - any mix of block sizes (even 1
- *     byte) on the same backup/restore procedure is supported. The driver
- *     will internally convert the requests to the recommended transfer unit,
- *     so that an unmatch between the user's block size to the recommended
- *     size will only result in a (slightly) increased driver overhead, but
- *     will no longer hit performance.
- *      This is not applicable to Onstream.
+ * As of version 1.3 of the driver, the character device provides an abstract
+ * continuous view of the media - any mix of block sizes (even 1 byte) on the
+ * same backup/restore procedure is supported. The driver will internally
+ * convert the requests to the recommended transfer unit, so that an unmatch
+ * between the user's block size to the recommended size will only result in a
+ * (slightly) increased driver overhead, but will no longer hit performance.
+ * This is not applicable to Onstream.
  */
-static ssize_t idetape_chrdev_read (struct file *file, char __user *buf,
-                                   size_t count, loff_t *ppos)
+static ssize_t idetape_chrdev_read(struct file *file, char __user *buf,
+                                  size_t count, loff_t *ppos)
 {
        struct ide_tape_obj *tape = ide_tape_f(file);
        ide_drive_t *drive = tape->drive;
-       ssize_t bytes_read,temp, actually_read = 0, rc;
+       ssize_t bytes_read, temp, actually_read = 0, rc;
        ssize_t ret = 0;
+       u16 ctl = *(u16 *)&tape->caps[12];
 
-#if IDETAPE_DEBUG_LOG
-       if (tape->debug_level >= 3)
-               printk(KERN_INFO "ide-tape: Reached idetape_chrdev_read, count %Zd\n", count);
-#endif /* IDETAPE_DEBUG_LOG */
+       debug_log(DBG_CHRDEV, "Enter %s, count %Zd\n", __func__, count);
 
-       if (tape->chrdev_direction != idetape_direction_read) {
+       if (tape->chrdev_dir != IDETAPE_DIR_READ) {
                if (test_bit(IDETAPE_DETECT_BS, &tape->flags))
-                       if (count > tape->tape_block_size &&
-                           (count % tape->tape_block_size) == 0)
-                               tape->user_bs_factor = count / tape->tape_block_size;
+                       if (count > tape->blk_size &&
+                           (count % tape->blk_size) == 0)
+                               tape->user_bs_factor = count / tape->blk_size;
        }
-       if ((rc = idetape_initiate_read(drive, tape->max_stages)) < 0)
+       rc = idetape_init_read(drive, tape->max_stages);
+       if (rc < 0)
                return rc;
        if (count == 0)
                return (0);
        if (tape->merge_stage_size) {
-               actually_read = min((unsigned int)(tape->merge_stage_size), (unsigned int)count);
-               if (idetape_copy_stage_to_user(tape, buf, tape->merge_stage, actually_read))
+               actually_read = min((unsigned int)(tape->merge_stage_size),
+                                   (unsigned int)count);
+               if (idetape_copy_stage_to_user(tape, buf, tape->merge_stage,
+                                              actually_read))
                        ret = -EFAULT;
                buf += actually_read;
                tape->merge_stage_size -= actually_read;
                count -= actually_read;
        }
        while (count >= tape->stage_size) {
-               bytes_read = idetape_add_chrdev_read_request(drive, tape->capabilities.ctl);
+               bytes_read = idetape_add_chrdev_read_request(drive, ctl);
                if (bytes_read <= 0)
                        goto finish;
-               if (idetape_copy_stage_to_user(tape, buf, tape->merge_stage, bytes_read))
+               if (idetape_copy_stage_to_user(tape, buf, tape->merge_stage,
+                                              bytes_read))
                        ret = -EFAULT;
                buf += bytes_read;
                count -= bytes_read;
                actually_read += bytes_read;
        }
        if (count) {
-               bytes_read = idetape_add_chrdev_read_request(drive, tape->capabilities.ctl);
+               bytes_read = idetape_add_chrdev_read_request(drive, ctl);
                if (bytes_read <= 0)
                        goto finish;
                temp = min((unsigned long)count, (unsigned long)bytes_read);
-               if (idetape_copy_stage_to_user(tape, buf, tape->merge_stage, temp))
+               if (idetape_copy_stage_to_user(tape, buf, tape->merge_stage,
+                                              temp))
                        ret = -EFAULT;
                actually_read += temp;
                tape->merge_stage_size = bytes_read-temp;
        }
 finish:
        if (!actually_read && test_bit(IDETAPE_FILEMARK, &tape->flags)) {
-#if IDETAPE_DEBUG_LOG
-               if (tape->debug_level >= 2)
-                       printk(KERN_INFO "ide-tape: %s: spacing over filemark\n", tape->name);
-#endif
+               debug_log(DBG_SENSE, "%s: spacing over filemark\n", tape->name);
+
                idetape_space_over_filemarks(drive, MTFSF, 1);
                return 0;
        }
 
-       return (ret) ? ret : actually_read;
+       return ret ? ret : actually_read;
 }
 
-static ssize_t idetape_chrdev_write (struct file *file, const char __user *buf,
+static ssize_t idetape_chrdev_write(struct file *file, const char __user *buf,
                                     size_t count, loff_t *ppos)
 {
        struct ide_tape_obj *tape = ide_tape_f(file);
        ide_drive_t *drive = tape->drive;
        ssize_t actually_written = 0;
        ssize_t ret = 0;
+       u16 ctl = *(u16 *)&tape->caps[12];
 
        /* The drive is write protected. */
        if (tape->write_prot)
                return -EACCES;
 
-#if IDETAPE_DEBUG_LOG
-       if (tape->debug_level >= 3)
-               printk(KERN_INFO "ide-tape: Reached idetape_chrdev_write, "
-                       "count %Zd\n", count);
-#endif /* IDETAPE_DEBUG_LOG */
+       debug_log(DBG_CHRDEV, "Enter %s, count %Zd\n", __func__, count);
 
        /* Initialize write operation */
-       if (tape->chrdev_direction != idetape_direction_write) {
-               if (tape->chrdev_direction == idetape_direction_read)
+       if (tape->chrdev_dir != IDETAPE_DIR_WRITE) {
+               if (tape->chrdev_dir == IDETAPE_DIR_READ)
                        idetape_discard_read_pipeline(drive, 1);
-#if IDETAPE_DEBUG_BUGS
                if (tape->merge_stage || tape->merge_stage_size) {
                        printk(KERN_ERR "ide-tape: merge_stage_size "
                                "should be 0 now\n");
                        tape->merge_stage_size = 0;
                }
-#endif /* IDETAPE_DEBUG_BUGS */
-               if ((tape->merge_stage = __idetape_kmalloc_stage(tape, 0, 0)) == NULL)
+               tape->merge_stage = __idetape_kmalloc_stage(tape, 0, 0);
+               if (!tape->merge_stage)
                        return -ENOMEM;
-               tape->chrdev_direction = idetape_direction_write;
+               tape->chrdev_dir = IDETAPE_DIR_WRITE;
                idetape_init_merge_stage(tape);
 
                /*
-                *      Issue a write 0 command to ensure that DSC handshake
-                *      is switched from completion mode to buffer available
-                *      mode.
-                *      No point in issuing this if DSC overlap isn't supported,
-                *      some drives (Seagate STT3401A) will return an error.
+                * Issue a write 0 command to ensure that DSC handshake is
+                * switched from completion mode to buffer available mode. No
+                * point in issuing this if DSC overlap isn't supported, some
+                * drives (Seagate STT3401A) will return an error.
                 */
                if (drive->dsc_overlap) {
-                       ssize_t retval = idetape_queue_rw_tail(drive, REQ_IDETAPE_WRITE, 0, tape->merge_stage->bh);
+                       ssize_t retval = idetape_queue_rw_tail(drive,
+                                                       REQ_IDETAPE_WRITE, 0,
+                                                       tape->merge_stage->bh);
                        if (retval < 0) {
                                __idetape_kfree_stage(tape->merge_stage);
                                tape->merge_stage = NULL;
-                               tape->chrdev_direction = idetape_direction_none;
+                               tape->chrdev_dir = IDETAPE_DIR_NONE;
                                return retval;
                        }
                }
@@ -3817,14 +2926,15 @@ static ssize_t idetape_chrdev_write (struct file *file, const char __user *buf,
        if (tape->restart_speed_control_req)
                idetape_restart_speed_control(drive);
        if (tape->merge_stage_size) {
-#if IDETAPE_DEBUG_BUGS
                if (tape->merge_stage_size >= tape->stage_size) {
-                       printk(KERN_ERR "ide-tape: bug: merge buffer too big\n");
+                       printk(KERN_ERR "ide-tape: bug: merge buf too big\n");
                        tape->merge_stage_size = 0;
                }
-#endif /* IDETAPE_DEBUG_BUGS */
-               actually_written = min((unsigned int)(tape->stage_size - tape->merge_stage_size), (unsigned int)count);
-               if (idetape_copy_stage_from_user(tape, tape->merge_stage, buf, actually_written))
+               actually_written = min((unsigned int)
+                               (tape->stage_size - tape->merge_stage_size),
+                               (unsigned int)count);
+               if (idetape_copy_stage_from_user(tape, tape->merge_stage, buf,
+                                                actually_written))
                                ret = -EFAULT;
                buf += actually_written;
                tape->merge_stage_size += actually_written;
@@ -3833,32 +2943,34 @@ static ssize_t idetape_chrdev_write (struct file *file, const char __user *buf,
                if (tape->merge_stage_size == tape->stage_size) {
                        ssize_t retval;
                        tape->merge_stage_size = 0;
-                       retval = idetape_add_chrdev_write_request(drive, tape->capabilities.ctl);
+                       retval = idetape_add_chrdev_write_request(drive, ctl);
                        if (retval <= 0)
                                return (retval);
                }
        }
        while (count >= tape->stage_size) {
                ssize_t retval;
-               if (idetape_copy_stage_from_user(tape, tape->merge_stage, buf, tape->stage_size))
+               if (idetape_copy_stage_from_user(tape, tape->merge_stage, buf,
+                                                tape->stage_size))
                        ret = -EFAULT;
                buf += tape->stage_size;
                count -= tape->stage_size;
-               retval = idetape_add_chrdev_write_request(drive, tape->capabilities.ctl);
+               retval = idetape_add_chrdev_write_request(drive, ctl);
                actually_written += tape->stage_size;
                if (retval <= 0)
                        return (retval);
        }
        if (count) {
                actually_written += count;
-               if (idetape_copy_stage_from_user(tape, tape->merge_stage, buf, count))
+               if (idetape_copy_stage_from_user(tape, tape->merge_stage, buf,
+                                                count))
                        ret = -EFAULT;
                tape->merge_stage_size += count;
        }
-       return (ret) ? ret : actually_written;
+       return ret ? ret : actually_written;
 }
 
-static int idetape_write_filemark (ide_drive_t *drive)
+static int idetape_write_filemark(ide_drive_t *drive)
 {
        idetape_pc_t pc;
 
@@ -3872,265 +2984,224 @@ static int idetape_write_filemark (ide_drive_t *drive)
 }
 
 /*
- *     idetape_mtioctop is called from idetape_chrdev_ioctl when
- *     the general mtio MTIOCTOP ioctl is requested.
- *
- *     We currently support the following mtio.h operations:
- *
- *     MTFSF   -       Space over mt_count filemarks in the positive direction.
- *                     The tape is positioned after the last spaced filemark.
- *
- *     MTFSFM  -       Same as MTFSF, but the tape is positioned before the
- *                     last filemark.
- *
- *     MTBSF   -       Steps background over mt_count filemarks, tape is
- *                     positioned before the last filemark.
- *
- *     MTBSFM  -       Like MTBSF, only tape is positioned after the last filemark.
- *
- *     Note:
- *
- *             MTBSF and MTBSFM are not supported when the tape doesn't
- *             support spacing over filemarks in the reverse direction.
- *             In this case, MTFSFM is also usually not supported (it is
- *             supported in the rare case in which we crossed the filemark
- *             during our read-ahead pipelined operation mode).
- *             
- *     MTWEOF  -       Writes mt_count filemarks. Tape is positioned after
- *                     the last written filemark.
+ * Called from idetape_chrdev_ioctl when the general mtio MTIOCTOP ioctl is
+ * requested.
  *
- *     MTREW   -       Rewinds tape.
+ * Note: MTBSF and MTBSFM are not supported when the tape doesn't support
+ * spacing over filemarks in the reverse direction. In this case, MTFSFM is also
+ * usually not supported (it is supported in the rare case in which we crossed
+ * the filemark during our read-ahead pipelined operation mode).
  *
- *     MTLOAD  -       Loads the tape.
+ * The following commands are currently not supported:
  *
- *     MTOFFL  -       Puts the tape drive "Offline": Rewinds the tape and
- *     MTUNLOAD        prevents further access until the media is replaced.
- *
- *     MTNOP   -       Flushes tape buffers.
- *
- *     MTRETEN -       Retension media. This typically consists of one end
- *                     to end pass on the media.
- *
- *     MTEOM   -       Moves to the end of recorded data.
- *
- *     MTERASE -       Erases tape.
- *
- *     MTSETBLK -      Sets the user block size to mt_count bytes. If
- *                     mt_count is 0, we will attempt to autodetect
- *                     the block size.
- *
- *     MTSEEK  -       Positions the tape in a specific block number, where
- *                     each block is assumed to contain which user_block_size
- *                     bytes.
- *
- *     MTSETPART -     Switches to another tape partition.
- *
- *     MTLOCK -        Locks the tape door.
- *
- *     MTUNLOCK -      Unlocks the tape door.
- *
- *     The following commands are currently not supported:
- *
- *     MTFSS, MTBSS, MTWSM, MTSETDENSITY,
- *     MTSETDRVBUFFER, MT_ST_BOOLEANS, MT_ST_WRITE_THRESHOLD.
+ * MTFSS, MTBSS, MTWSM, MTSETDENSITY, MTSETDRVBUFFER, MT_ST_BOOLEANS,
+ * MT_ST_WRITE_THRESHOLD.
  */
-static int idetape_mtioctop (ide_drive_t *drive,short mt_op,int mt_count)
+static int idetape_mtioctop(ide_drive_t *drive, short mt_op, int mt_count)
 {
        idetape_tape_t *tape = drive->driver_data;
        idetape_pc_t pc;
-       int i,retval;
+       int i, retval;
 
-#if IDETAPE_DEBUG_LOG
-       if (tape->debug_level >= 1)
-               printk(KERN_INFO "ide-tape: Handling MTIOCTOP ioctl: "
-                       "mt_op=%d, mt_count=%d\n", mt_op, mt_count);
-#endif /* IDETAPE_DEBUG_LOG */
-       /*
-        *      Commands which need our pipelined read-ahead stages.
-        */
+       debug_log(DBG_ERR, "Handling MTIOCTOP ioctl: mt_op=%d, mt_count=%d\n",
+                       mt_op, mt_count);
+
+       /* Commands which need our pipelined read-ahead stages. */
        switch (mt_op) {
-               case MTFSF:
-               case MTFSFM:
-               case MTBSF:
-               case MTBSFM:
-                       if (!mt_count)
-                               return (0);
-                       return (idetape_space_over_filemarks(drive,mt_op,mt_count));
-               default:
-                       break;
+       case MTFSF:
+       case MTFSFM:
+       case MTBSF:
+       case MTBSFM:
+               if (!mt_count)
+                       return 0;
+               return idetape_space_over_filemarks(drive, mt_op, mt_count);
+       default:
+               break;
        }
+
        switch (mt_op) {
-               case MTWEOF:
-                       if (tape->write_prot)
-                               return -EACCES;
-                       idetape_discard_read_pipeline(drive, 1);
-                       for (i = 0; i < mt_count; i++) {
-                               retval = idetape_write_filemark(drive);
-                               if (retval)
-                                       return retval;
-                       }
-                       return (0);
-               case MTREW:
-                       idetape_discard_read_pipeline(drive, 0);
-                       if (idetape_rewind_tape(drive))
+       case MTWEOF:
+               if (tape->write_prot)
+                       return -EACCES;
+               idetape_discard_read_pipeline(drive, 1);
+               for (i = 0; i < mt_count; i++) {
+                       retval = idetape_write_filemark(drive);
+                       if (retval)
+                               return retval;
+               }
+               return 0;
+       case MTREW:
+               idetape_discard_read_pipeline(drive, 0);
+               if (idetape_rewind_tape(drive))
+                       return -EIO;
+               return 0;
+       case MTLOAD:
+               idetape_discard_read_pipeline(drive, 0);
+               idetape_create_load_unload_cmd(drive, &pc,
+                                              IDETAPE_LU_LOAD_MASK);
+               return idetape_queue_pc_tail(drive, &pc);
+       case MTUNLOAD:
+       case MTOFFL:
+               /*
+                * If door is locked, attempt to unlock before
+                * attempting to eject.
+                */
+               if (tape->door_locked) {
+                       if (idetape_create_prevent_cmd(drive, &pc, 0))
+                               if (!idetape_queue_pc_tail(drive, &pc))
+                                       tape->door_locked = DOOR_UNLOCKED;
+               }
+               idetape_discard_read_pipeline(drive, 0);
+               idetape_create_load_unload_cmd(drive, &pc,
+                                             !IDETAPE_LU_LOAD_MASK);
+               retval = idetape_queue_pc_tail(drive, &pc);
+               if (!retval)
+                       clear_bit(IDETAPE_MEDIUM_PRESENT, &tape->flags);
+               return retval;
+       case MTNOP:
+               idetape_discard_read_pipeline(drive, 0);
+               return idetape_flush_tape_buffers(drive);
+       case MTRETEN:
+               idetape_discard_read_pipeline(drive, 0);
+               idetape_create_load_unload_cmd(drive, &pc,
+                       IDETAPE_LU_RETENSION_MASK | IDETAPE_LU_LOAD_MASK);
+               return idetape_queue_pc_tail(drive, &pc);
+       case MTEOM:
+               idetape_create_space_cmd(&pc, 0, IDETAPE_SPACE_TO_EOD);
+               return idetape_queue_pc_tail(drive, &pc);
+       case MTERASE:
+               (void)idetape_rewind_tape(drive);
+               idetape_create_erase_cmd(&pc);
+               return idetape_queue_pc_tail(drive, &pc);
+       case MTSETBLK:
+               if (mt_count) {
+                       if (mt_count < tape->blk_size ||
+                           mt_count % tape->blk_size)
                                return -EIO;
+                       tape->user_bs_factor = mt_count / tape->blk_size;
+                       clear_bit(IDETAPE_DETECT_BS, &tape->flags);
+               } else
+                       set_bit(IDETAPE_DETECT_BS, &tape->flags);
+               return 0;
+       case MTSEEK:
+               idetape_discard_read_pipeline(drive, 0);
+               return idetape_position_tape(drive,
+                       mt_count * tape->user_bs_factor, tape->partition, 0);
+       case MTSETPART:
+               idetape_discard_read_pipeline(drive, 0);
+               return idetape_position_tape(drive, 0, mt_count, 0);
+       case MTFSR:
+       case MTBSR:
+       case MTLOCK:
+               if (!idetape_create_prevent_cmd(drive, &pc, 1))
                        return 0;
-               case MTLOAD:
-                       idetape_discard_read_pipeline(drive, 0);
-                       idetape_create_load_unload_cmd(drive, &pc, IDETAPE_LU_LOAD_MASK);
-                       return (idetape_queue_pc_tail(drive, &pc));
-               case MTUNLOAD:
-               case MTOFFL:
-                       /*
-                        * If door is locked, attempt to unlock before
-                        * attempting to eject.
-                        */
-                       if (tape->door_locked) {
-                               if (idetape_create_prevent_cmd(drive, &pc, 0))
-                                       if (!idetape_queue_pc_tail(drive, &pc))
-                                               tape->door_locked = DOOR_UNLOCKED;
-                       }
-                       idetape_discard_read_pipeline(drive, 0);
-                       idetape_create_load_unload_cmd(drive, &pc,!IDETAPE_LU_LOAD_MASK);
-                       retval = idetape_queue_pc_tail(drive, &pc);
-                       if (!retval)
-                               clear_bit(IDETAPE_MEDIUM_PRESENT, &tape->flags);
+               retval = idetape_queue_pc_tail(drive, &pc);
+               if (retval)
                        return retval;
-               case MTNOP:
-                       idetape_discard_read_pipeline(drive, 0);
-                       return (idetape_flush_tape_buffers(drive));
-               case MTRETEN:
-                       idetape_discard_read_pipeline(drive, 0);
-                       idetape_create_load_unload_cmd(drive, &pc,IDETAPE_LU_RETENSION_MASK | IDETAPE_LU_LOAD_MASK);
-                       return (idetape_queue_pc_tail(drive, &pc));
-               case MTEOM:
-                       idetape_create_space_cmd(&pc, 0, IDETAPE_SPACE_TO_EOD);
-                       return (idetape_queue_pc_tail(drive, &pc));
-               case MTERASE:
-                       (void) idetape_rewind_tape(drive);
-                       idetape_create_erase_cmd(&pc);
-                       return (idetape_queue_pc_tail(drive, &pc));
-               case MTSETBLK:
-                       if (mt_count) {
-                               if (mt_count < tape->tape_block_size || mt_count % tape->tape_block_size)
-                                       return -EIO;
-                               tape->user_bs_factor = mt_count / tape->tape_block_size;
-                               clear_bit(IDETAPE_DETECT_BS, &tape->flags);
-                       } else
-                               set_bit(IDETAPE_DETECT_BS, &tape->flags);
-                       return 0;
-               case MTSEEK:
-                       idetape_discard_read_pipeline(drive, 0);
-                       return idetape_position_tape(drive, mt_count * tape->user_bs_factor, tape->partition, 0);
-               case MTSETPART:
-                       idetape_discard_read_pipeline(drive, 0);
-                       return (idetape_position_tape(drive, 0, mt_count, 0));
-               case MTFSR:
-               case MTBSR:
-               case MTLOCK:
-                       if (!idetape_create_prevent_cmd(drive, &pc, 1))
-                               return 0;
-                       retval = idetape_queue_pc_tail(drive, &pc);
-                       if (retval) return retval;
-                       tape->door_locked = DOOR_EXPLICITLY_LOCKED;
-                       return 0;
-               case MTUNLOCK:
-                       if (!idetape_create_prevent_cmd(drive, &pc, 0))
-                               return 0;
-                       retval = idetape_queue_pc_tail(drive, &pc);
-                       if (retval) return retval;
-                       tape->door_locked = DOOR_UNLOCKED;
+               tape->door_locked = DOOR_EXPLICITLY_LOCKED;
+               return 0;
+       case MTUNLOCK:
+               if (!idetape_create_prevent_cmd(drive, &pc, 0))
                        return 0;
-               default:
-                       printk(KERN_ERR "ide-tape: MTIO operation %d not "
-                               "supported\n", mt_op);
-                       return (-EIO);
+               retval = idetape_queue_pc_tail(drive, &pc);
+               if (retval)
+                       return retval;
+               tape->door_locked = DOOR_UNLOCKED;
+               return 0;
+       default:
+               printk(KERN_ERR "ide-tape: MTIO operation %d not supported\n",
+                               mt_op);
+               return -EIO;
        }
 }
 
 /*
- *     Our character device ioctls.
- *
- *     General mtio.h magnetic io commands are supported here, and not in
- *     the corresponding block interface.
- *
- *     The following ioctls are supported:
- *
- *     MTIOCTOP -      Refer to idetape_mtioctop for detailed description.
- *
- *     MTIOCGET -      The mt_dsreg field in the returned mtget structure
- *                     will be set to (user block size in bytes <<
- *                     MT_ST_BLKSIZE_SHIFT) & MT_ST_BLKSIZE_MASK.
- *
- *                     The mt_blkno is set to the current user block number.
- *                     The other mtget fields are not supported.
- *
- *     MTIOCPOS -      The current tape "block position" is returned. We
- *                     assume that each block contains user_block_size
- *                     bytes.
- *
- *     Our own ide-tape ioctls are supported on both interfaces.
+ * Our character device ioctls. General mtio.h magnetic io commands are
+ * supported here, and not in the corresponding block interface. Our own
+ * ide-tape ioctls are supported on both interfaces.
  */
-static int idetape_chrdev_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+static int idetape_chrdev_ioctl(struct inode *inode, struct file *file,
+                               unsigned int cmd, unsigned long arg)
 {
        struct ide_tape_obj *tape = ide_tape_f(file);
        ide_drive_t *drive = tape->drive;
        struct mtop mtop;
        struct mtget mtget;
        struct mtpos mtpos;
-       int block_offset = 0, position = tape->first_frame_position;
+       int block_offset = 0, position = tape->first_frame;
        void __user *argp = (void __user *)arg;
 
-#if IDETAPE_DEBUG_LOG
-       if (tape->debug_level >= 3)
-               printk(KERN_INFO "ide-tape: Reached idetape_chrdev_ioctl, "
-                       "cmd=%u\n", cmd);
-#endif /* IDETAPE_DEBUG_LOG */
+       debug_log(DBG_CHRDEV, "Enter %s, cmd=%u\n", __func__, cmd);
 
        tape->restart_speed_control_req = 1;
-       if (tape->chrdev_direction == idetape_direction_write) {
+       if (tape->chrdev_dir == IDETAPE_DIR_WRITE) {
                idetape_empty_write_pipeline(drive);
                idetape_flush_tape_buffers(drive);
        }
        if (cmd == MTIOCGET || cmd == MTIOCPOS) {
-               block_offset = idetape_pipeline_size(drive) / (tape->tape_block_size * tape->user_bs_factor);
-               if ((position = idetape_read_position(drive)) < 0)
+               block_offset = idetape_pipeline_size(drive) /
+                       (tape->blk_size * tape->user_bs_factor);
+               position = idetape_read_position(drive);
+               if (position < 0)
                        return -EIO;
        }
        switch (cmd) {
-               case MTIOCTOP:
-                       if (copy_from_user(&mtop, argp, sizeof (struct mtop)))
-                               return -EFAULT;
-                       return (idetape_mtioctop(drive,mtop.mt_op,mtop.mt_count));
-               case MTIOCGET:
-                       memset(&mtget, 0, sizeof (struct mtget));
-                       mtget.mt_type = MT_ISSCSI2;
-                       mtget.mt_blkno = position / tape->user_bs_factor - block_offset;
-                       mtget.mt_dsreg = ((tape->tape_block_size * tape->user_bs_factor) << MT_ST_BLKSIZE_SHIFT) & MT_ST_BLKSIZE_MASK;
-                       if (tape->drv_write_prot) {
-                               mtget.mt_gstat |= GMT_WR_PROT(0xffffffff);
-                       }
-                       if (copy_to_user(argp, &mtget, sizeof(struct mtget)))
-                               return -EFAULT;
-                       return 0;
-               case MTIOCPOS:
-                       mtpos.mt_blkno = position / tape->user_bs_factor - block_offset;
-                       if (copy_to_user(argp, &mtpos, sizeof(struct mtpos)))
-                               return -EFAULT;
-                       return 0;
-               default:
-                       if (tape->chrdev_direction == idetape_direction_read)
-                               idetape_discard_read_pipeline(drive, 1);
-                       return idetape_blkdev_ioctl(drive, cmd, arg);
+       case MTIOCTOP:
+               if (copy_from_user(&mtop, argp, sizeof(struct mtop)))
+                       return -EFAULT;
+               return idetape_mtioctop(drive, mtop.mt_op, mtop.mt_count);
+       case MTIOCGET:
+               memset(&mtget, 0, sizeof(struct mtget));
+               mtget.mt_type = MT_ISSCSI2;
+               mtget.mt_blkno = position / tape->user_bs_factor - block_offset;
+               mtget.mt_dsreg =
+                       ((tape->blk_size * tape->user_bs_factor)
+                        << MT_ST_BLKSIZE_SHIFT) & MT_ST_BLKSIZE_MASK;
+
+               if (tape->drv_write_prot)
+                       mtget.mt_gstat |= GMT_WR_PROT(0xffffffff);
+
+               if (copy_to_user(argp, &mtget, sizeof(struct mtget)))
+                       return -EFAULT;
+               return 0;
+       case MTIOCPOS:
+               mtpos.mt_blkno = position / tape->user_bs_factor - block_offset;
+               if (copy_to_user(argp, &mtpos, sizeof(struct mtpos)))
+                       return -EFAULT;
+               return 0;
+       default:
+               if (tape->chrdev_dir == IDETAPE_DIR_READ)
+                       idetape_discard_read_pipeline(drive, 1);
+               return idetape_blkdev_ioctl(drive, cmd, arg);
        }
 }
 
-static void idetape_get_blocksize_from_block_descriptor(ide_drive_t *drive);
-
 /*
- *     Our character device open function.
+ * Do a mode sense page 0 with block descriptor and if it succeeds set the tape
+ * block size with the reported value.
  */
-static int idetape_chrdev_open (struct inode *inode, struct file *filp)
+static void ide_tape_get_bsize_from_bdesc(ide_drive_t *drive)
+{
+       idetape_tape_t *tape = drive->driver_data;
+       idetape_pc_t pc;
+
+       idetape_create_mode_sense_cmd(&pc, IDETAPE_BLOCK_DESCRIPTOR);
+       if (idetape_queue_pc_tail(drive, &pc)) {
+               printk(KERN_ERR "ide-tape: Can't get block descriptor\n");
+               if (tape->blk_size == 0) {
+                       printk(KERN_WARNING "ide-tape: Cannot deal with zero "
+                                           "block size, assuming 32k\n");
+                       tape->blk_size = 32768;
+               }
+               return;
+       }
+       tape->blk_size = (pc.buffer[4 + 5] << 16) +
+                               (pc.buffer[4 + 6] << 8)  +
+                                pc.buffer[4 + 7];
+       tape->drv_write_prot = (pc.buffer[2] & 0x80) >> 7;
+}
+
+static int idetape_chrdev_open(struct inode *inode, struct file *filp)
 {
        unsigned int minor = iminor(inode), i = minor & ~0xc0;
        ide_drive_t *drive;
@@ -4138,6 +3209,15 @@ static int idetape_chrdev_open (struct inode *inode, struct file *filp)
        idetape_pc_t pc;
        int retval;
 
+       if (i >= MAX_HWIFS * MAX_DRIVES)
+               return -ENXIO;
+
+       tape = ide_tape_chrdev_get(i);
+       if (!tape)
+               return -ENXIO;
+
+       debug_log(DBG_CHRDEV, "Enter %s\n", __func__);
+
        /*
         * We really want to do nonseekable_open(inode, filp); here, but some
         * versions of tar incorrectly call lseek on tapes and bail out if that
@@ -4145,16 +3225,6 @@ static int idetape_chrdev_open (struct inode *inode, struct file *filp)
         */
        filp->f_mode &= ~(FMODE_PREAD | FMODE_PWRITE);
 
-#if IDETAPE_DEBUG_LOG
-       printk(KERN_INFO "ide-tape: Reached idetape_chrdev_open\n");
-#endif /* IDETAPE_DEBUG_LOG */
-       
-       if (i >= MAX_HWIFS * MAX_DRIVES)
-               return -ENXIO;
-
-       if (!(tape = ide_tape_chrdev_get(i)))
-               return -ENXIO;
-
        drive = tape->drive;
 
        filp->private_data = tape;
@@ -4175,11 +3245,11 @@ static int idetape_chrdev_open (struct inode *inode, struct file *filp)
        if (!test_bit(IDETAPE_ADDRESS_VALID, &tape->flags))
                (void)idetape_rewind_tape(drive);
 
-       if (tape->chrdev_direction != idetape_direction_read)
+       if (tape->chrdev_dir != IDETAPE_DIR_READ)
                clear_bit(IDETAPE_PIPELINE_ERROR, &tape->flags);
 
        /* Read block size and write protect status from drive. */
-       idetape_get_blocksize_from_block_descriptor(drive);
+       ide_tape_get_bsize_from_bdesc(drive);
 
        /* Set write protect flag if device is opened as read-only. */
        if ((filp->f_flags & O_ACCMODE) == O_RDONLY)
@@ -4197,10 +3267,8 @@ static int idetape_chrdev_open (struct inode *inode, struct file *filp)
                }
        }
 
-       /*
-        * Lock the tape drive door so user can't eject.
-        */
-       if (tape->chrdev_direction == idetape_direction_none) {
+       /* Lock the tape drive door so user can't eject. */
+       if (tape->chrdev_dir == IDETAPE_DIR_NONE) {
                if (idetape_create_prevent_cmd(drive, &pc, 1)) {
                        if (!idetape_queue_pc_tail(drive, &pc)) {
                                if (tape->door_locked != DOOR_EXPLICITLY_LOCKED)
@@ -4217,14 +3285,15 @@ out_put_tape:
        return retval;
 }
 
-static void idetape_write_release (ide_drive_t *drive, unsigned int minor)
+static void idetape_write_release(ide_drive_t *drive, unsigned int minor)
 {
        idetape_tape_t *tape = drive->driver_data;
 
        idetape_empty_write_pipeline(drive);
        tape->merge_stage = __idetape_kmalloc_stage(tape, 1, 0);
        if (tape->merge_stage != NULL) {
-               idetape_pad_zeros(drive, tape->tape_block_size * (tape->user_bs_factor - 1));
+               idetape_pad_zeros(drive, tape->blk_size *
+                               (tape->user_bs_factor - 1));
                __idetape_kfree_stage(tape->merge_stage);
                tape->merge_stage = NULL;
        }
@@ -4233,10 +3302,7 @@ static void idetape_write_release (ide_drive_t *drive, unsigned int minor)
        idetape_flush_tape_buffers(drive);
 }
 
-/*
- *     Our character device release function.
- */
-static int idetape_chrdev_release (struct inode *inode, struct file *filp)
+static int idetape_chrdev_release(struct inode *inode, struct file *filp)
 {
        struct ide_tape_obj *tape = ide_tape_f(filp);
        ide_drive_t *drive = tape->drive;
@@ -4245,14 +3311,12 @@ static int idetape_chrdev_release (struct inode *inode, struct file *filp)
 
        lock_kernel();
        tape = drive->driver_data;
-#if IDETAPE_DEBUG_LOG
-       if (tape->debug_level >= 3)
-               printk(KERN_INFO "ide-tape: Reached idetape_chrdev_release\n");
-#endif /* IDETAPE_DEBUG_LOG */
 
-       if (tape->chrdev_direction == idetape_direction_write)
+       debug_log(DBG_CHRDEV, "Enter %s\n", __func__);
+
+       if (tape->chrdev_dir == IDETAPE_DIR_WRITE)
                idetape_write_release(drive, minor);
-       if (tape->chrdev_direction == idetape_direction_read) {
+       if (tape->chrdev_dir == IDETAPE_DIR_READ) {
                if (minor < 128)
                        idetape_discard_read_pipeline(drive, 1);
                else
@@ -4264,7 +3328,7 @@ static int idetape_chrdev_release (struct inode *inode, struct file *filp)
        }
        if (minor < 128 && test_bit(IDETAPE_MEDIUM_PRESENT, &tape->flags))
                (void) idetape_rewind_tape(drive);
-       if (tape->chrdev_direction == idetape_direction_none) {
+       if (tape->chrdev_dir == IDETAPE_DIR_NONE) {
                if (tape->door_locked == DOOR_LOCKED) {
                        if (idetape_create_prevent_cmd(drive, &pc, 0)) {
                                if (!idetape_queue_pc_tail(drive, &pc))
@@ -4279,331 +3343,188 @@ static int idetape_chrdev_release (struct inode *inode, struct file *filp)
 }
 
 /*
- *     idetape_identify_device is called to check the contents of the
- *     ATAPI IDENTIFY command results. We return:
+ * check the contents of the ATAPI IDENTIFY command results. We return:
  *
- *     1       If the tape can be supported by us, based on the information
- *             we have so far.
+ * 1 - If the tape can be supported by us, based on the information we have so
+ * far.
  *
- *     0       If this tape driver is not currently supported by us.
+ * 0 - If this tape driver is not currently supported by us.
  */
-static int idetape_identify_device (ide_drive_t *drive)
+static int idetape_identify_device(ide_drive_t *drive)
 {
-       struct idetape_id_gcw gcw;
-       struct hd_driveid *id = drive->id;
-#if IDETAPE_DEBUG_INFO
-       unsigned short mask,i;
-#endif /* IDETAPE_DEBUG_INFO */
+       u8 gcw[2], protocol, device_type, removable, packet_size;
 
        if (drive->id_read == 0)
                return 1;
 
-       *((unsigned short *) &gcw) = id->config;
-
-#if IDETAPE_DEBUG_INFO
-       printk(KERN_INFO "ide-tape: Dumping ATAPI Identify Device tape parameters\n");
-       printk(KERN_INFO "ide-tape: Protocol Type: ");
-       switch (gcw.protocol) {
-               case 0: case 1: printk("ATA\n");break;
-               case 2: printk("ATAPI\n");break;
-               case 3: printk("Reserved (Unknown to ide-tape)\n");break;
-       }
-       printk(KERN_INFO "ide-tape: Device Type: %x - ",gcw.device_type);       
-       switch (gcw.device_type) {
-               case 0: printk("Direct-access Device\n");break;
-               case 1: printk("Streaming Tape Device\n");break;
-               case 2: case 3: case 4: printk("Reserved\n");break;
-               case 5: printk("CD-ROM Device\n");break;
-               case 6: printk("Reserved\n");
-               case 7: printk("Optical memory Device\n");break;
-               case 0x1f: printk("Unknown or no Device type\n");break;
-               default: printk("Reserved\n");
-       }
-       printk(KERN_INFO "ide-tape: Removable: %s",gcw.removable ? "Yes\n":"No\n");     
-       printk(KERN_INFO "ide-tape: Command Packet DRQ Type: ");
-       switch (gcw.drq_type) {
-               case 0: printk("Microprocessor DRQ\n");break;
-               case 1: printk("Interrupt DRQ\n");break;
-               case 2: printk("Accelerated DRQ\n");break;
-               case 3: printk("Reserved\n");break;
-       }
-       printk(KERN_INFO "ide-tape: Command Packet Size: ");
-       switch (gcw.packet_size) {
-               case 0: printk("12 bytes\n");break;
-               case 1: printk("16 bytes\n");break;
-               default: printk("Reserved\n");break;
-       }
-       printk(KERN_INFO "ide-tape: Model: %.40s\n",id->model);
-       printk(KERN_INFO "ide-tape: Firmware Revision: %.8s\n",id->fw_rev);
-       printk(KERN_INFO "ide-tape: Serial Number: %.20s\n",id->serial_no);
-       printk(KERN_INFO "ide-tape: Write buffer size: %d bytes\n",id->buf_size*512);
-       printk(KERN_INFO "ide-tape: DMA: %s",id->capability & 0x01 ? "Yes\n":"No\n");
-       printk(KERN_INFO "ide-tape: LBA: %s",id->capability & 0x02 ? "Yes\n":"No\n");
-       printk(KERN_INFO "ide-tape: IORDY can be disabled: %s",id->capability & 0x04 ? "Yes\n":"No\n");
-       printk(KERN_INFO "ide-tape: IORDY supported: %s",id->capability & 0x08 ? "Yes\n":"Unknown\n");
-       printk(KERN_INFO "ide-tape: ATAPI overlap supported: %s",id->capability & 0x20 ? "Yes\n":"No\n");
-       printk(KERN_INFO "ide-tape: PIO Cycle Timing Category: %d\n",id->tPIO);
-       printk(KERN_INFO "ide-tape: DMA Cycle Timing Category: %d\n",id->tDMA);
-       printk(KERN_INFO "ide-tape: Single Word DMA supported modes: ");
-       for (i=0,mask=1;i<8;i++,mask=mask << 1) {
-               if (id->dma_1word & mask)
-                       printk("%d ",i);
-               if (id->dma_1word & (mask << 8))
-                       printk("(active) ");
-       }
-       printk("\n");
-       printk(KERN_INFO "ide-tape: Multi Word DMA supported modes: ");
-       for (i=0,mask=1;i<8;i++,mask=mask << 1) {
-               if (id->dma_mword & mask)
-                       printk("%d ",i);
-               if (id->dma_mword & (mask << 8))
-                       printk("(active) ");
-       }
-       printk("\n");
-       if (id->field_valid & 0x0002) {
-               printk(KERN_INFO "ide-tape: Enhanced PIO Modes: %s\n",
-                       id->eide_pio_modes & 1 ? "Mode 3":"None");
-               printk(KERN_INFO "ide-tape: Minimum Multi-word DMA cycle per word: ");
-               if (id->eide_dma_min == 0)
-                       printk("Not supported\n");
-               else
-                       printk("%d ns\n",id->eide_dma_min);
-
-               printk(KERN_INFO "ide-tape: Manufacturer\'s Recommended Multi-word cycle: ");
-               if (id->eide_dma_time == 0)
-                       printk("Not supported\n");
-               else
-                       printk("%d ns\n",id->eide_dma_time);
-
-               printk(KERN_INFO "ide-tape: Minimum PIO cycle without IORDY: ");
-               if (id->eide_pio == 0)
-                       printk("Not supported\n");
-               else
-                       printk("%d ns\n",id->eide_pio);
+       *((unsigned short *) &gcw) = drive->id->config;
 
-               printk(KERN_INFO "ide-tape: Minimum PIO cycle with IORDY: ");
-               if (id->eide_pio_iordy == 0)
-                       printk("Not supported\n");
-               else
-                       printk("%d ns\n",id->eide_pio_iordy);
-               
-       } else
-               printk(KERN_INFO "ide-tape: According to the device, fields 64-70 are not valid.\n");
-#endif /* IDETAPE_DEBUG_INFO */
+       protocol        =   (gcw[1] & 0xC0) >> 6;
+       device_type     =    gcw[1] & 0x1F;
+       removable       = !!(gcw[0] & 0x80);
+       packet_size     =    gcw[0] & 0x3;
 
        /* Check that we can support this device */
-
-       if (gcw.protocol !=2 )
-               printk(KERN_ERR "ide-tape: Protocol is not ATAPI\n");
-       else if (gcw.device_type != 1)
-               printk(KERN_ERR "ide-tape: Device type is not set to tape\n");
-       else if (!gcw.removable)
+       if (protocol != 2)
+               printk(KERN_ERR "ide-tape: Protocol (0x%02x) is not ATAPI\n",
+                               protocol);
+       else if (device_type != 1)
+               printk(KERN_ERR "ide-tape: Device type (0x%02x) is not set "
+                               "to tape\n", device_type);
+       else if (!removable)
                printk(KERN_ERR "ide-tape: The removable flag is not set\n");
-       else if (gcw.packet_size != 0) {
-               printk(KERN_ERR "ide-tape: Packet size is not 12 bytes long\n");
-               if (gcw.packet_size == 1)
-                       printk(KERN_ERR "ide-tape: Sorry, padding to 16 bytes is still not supported\n");
+       else if (packet_size != 0) {
+               printk(KERN_ERR "ide-tape: Packet size (0x%02x) is not 12"
+                               " bytes\n", packet_size);
        } else
                return 1;
        return 0;
 }
 
-/*
- * Use INQUIRY to get the firmware revision
- */
-static void idetape_get_inquiry_results (ide_drive_t *drive)
+static void idetape_get_inquiry_results(ide_drive_t *drive)
 {
-       char *r;
        idetape_tape_t *tape = drive->driver_data;
        idetape_pc_t pc;
-       idetape_inquiry_result_t *inquiry;
-       
+       char fw_rev[6], vendor_id[10], product_id[18];
+
        idetape_create_inquiry_cmd(&pc);
        if (idetape_queue_pc_tail(drive, &pc)) {
-               printk(KERN_ERR "ide-tape: %s: can't get INQUIRY results\n", tape->name);
+               printk(KERN_ERR "ide-tape: %s: can't get INQUIRY results\n",
+                               tape->name);
                return;
        }
-       inquiry = (idetape_inquiry_result_t *) pc.buffer;
-       memcpy(tape->vendor_id, inquiry->vendor_id, 8);
-       memcpy(tape->product_id, inquiry->product_id, 16);
-       memcpy(tape->firmware_revision, inquiry->revision_level, 4);
-       ide_fixstring(tape->vendor_id, 10, 0);
-       ide_fixstring(tape->product_id, 18, 0);
-       ide_fixstring(tape->firmware_revision, 6, 0);
-       r = tape->firmware_revision;
-       if (*(r + 1) == '.')
-               tape->firmware_revision_num = (*r - '0') * 100 + (*(r + 2) - '0') * 10 + *(r + 3) - '0';
-       printk(KERN_INFO "ide-tape: %s <-> %s: %s %s rev %s\n", drive->name, tape->name, tape->vendor_id, tape->product_id, tape->firmware_revision);
+       memcpy(vendor_id, &pc.buffer[8], 8);
+       memcpy(product_id, &pc.buffer[16], 16);
+       memcpy(fw_rev, &pc.buffer[32], 4);
+
+       ide_fixstring(vendor_id, 10, 0);
+       ide_fixstring(product_id, 18, 0);
+       ide_fixstring(fw_rev, 6, 0);
+
+       printk(KERN_INFO "ide-tape: %s <-> %s: %s %s rev %s\n",
+                       drive->name, tape->name, vendor_id, product_id, fw_rev);
 }
 
 /*
- *     idetape_get_mode_sense_results asks the tape about its various
- *     parameters. In particular, we will adjust our data transfer buffer
- *     size to the recommended value as returned by the tape.
+ * Ask the tape about its various parameters. In particular, we will adjust our
+ * data transfer buffer        size to the recommended value as returned by the tape.
  */
-static void idetape_get_mode_sense_results (ide_drive_t *drive)
+static void idetape_get_mode_sense_results(ide_drive_t *drive)
 {
        idetape_tape_t *tape = drive->driver_data;
        idetape_pc_t pc;
-       idetape_mode_parameter_header_t *header;
-       idetape_capabilities_page_t *capabilities;
-       
+       u8 *caps;
+       u8 speed, max_speed;
+
        idetape_create_mode_sense_cmd(&pc, IDETAPE_CAPABILITIES_PAGE);
        if (idetape_queue_pc_tail(drive, &pc)) {
-               printk(KERN_ERR "ide-tape: Can't get tape parameters - assuming some default values\n");
-               tape->tape_block_size = 512;
-               tape->capabilities.ctl = 52;
-               tape->capabilities.speed = 450;
-               tape->capabilities.buffer_size = 6 * 52;
+               printk(KERN_ERR "ide-tape: Can't get tape parameters - assuming"
+                               " some default values\n");
+               tape->blk_size = 512;
+               put_unaligned(52,   (u16 *)&tape->caps[12]);
+               put_unaligned(540,  (u16 *)&tape->caps[14]);
+               put_unaligned(6*52, (u16 *)&tape->caps[16]);
                return;
        }
-       header = (idetape_mode_parameter_header_t *) pc.buffer;
-       capabilities = (idetape_capabilities_page_t *) (pc.buffer + sizeof(idetape_mode_parameter_header_t) + header->bdl);
+       caps = pc.buffer + 4 + pc.buffer[3];
 
-       capabilities->max_speed = ntohs(capabilities->max_speed);
-       capabilities->ctl = ntohs(capabilities->ctl);
-       capabilities->speed = ntohs(capabilities->speed);
-       capabilities->buffer_size = ntohs(capabilities->buffer_size);
+       /* convert to host order and save for later use */
+       speed = be16_to_cpu(*(u16 *)&caps[14]);
+       max_speed = be16_to_cpu(*(u16 *)&caps[8]);
 
-       if (!capabilities->speed) {
-               printk(KERN_INFO "ide-tape: %s: overriding capabilities->speed (assuming 650KB/sec)\n", drive->name);
-               capabilities->speed = 650;
+       put_unaligned(max_speed, (u16 *)&caps[8]);
+       put_unaligned(be16_to_cpu(*(u16 *)&caps[12]), (u16 *)&caps[12]);
+       put_unaligned(speed, (u16 *)&caps[14]);
+       put_unaligned(be16_to_cpu(*(u16 *)&caps[16]), (u16 *)&caps[16]);
+
+       if (!speed) {
+               printk(KERN_INFO "ide-tape: %s: invalid tape speed "
+                               "(assuming 650KB/sec)\n", drive->name);
+               put_unaligned(650, (u16 *)&caps[14]);
        }
-       if (!capabilities->max_speed) {
-               printk(KERN_INFO "ide-tape: %s: overriding capabilities->max_speed (assuming 650KB/sec)\n", drive->name);
-               capabilities->max_speed = 650;
+       if (!max_speed) {
+               printk(KERN_INFO "ide-tape: %s: invalid max_speed "
+                               "(assuming 650KB/sec)\n", drive->name);
+               put_unaligned(650, (u16 *)&caps[8]);
        }
 
-       tape->capabilities = *capabilities;             /* Save us a copy */
-       if (capabilities->blk512)
-               tape->tape_block_size = 512;
-       else if (capabilities->blk1024)
-               tape->tape_block_size = 1024;
-
-#if IDETAPE_DEBUG_INFO
-       printk(KERN_INFO "ide-tape: Dumping the results of the MODE SENSE packet command\n");
-       printk(KERN_INFO "ide-tape: Mode Parameter Header:\n");
-       printk(KERN_INFO "ide-tape: Mode Data Length - %d\n",header->mode_data_length);
-       printk(KERN_INFO "ide-tape: Medium Type - %d\n",header->medium_type);
-       printk(KERN_INFO "ide-tape: Device Specific Parameter - %d\n",header->dsp);
-       printk(KERN_INFO "ide-tape: Block Descriptor Length - %d\n",header->bdl);
-       
-       printk(KERN_INFO "ide-tape: Capabilities and Mechanical Status Page:\n");
-       printk(KERN_INFO "ide-tape: Page code - %d\n",capabilities->page_code);
-       printk(KERN_INFO "ide-tape: Page length - %d\n",capabilities->page_length);
-       printk(KERN_INFO "ide-tape: Read only - %s\n",capabilities->ro ? "Yes":"No");
-       printk(KERN_INFO "ide-tape: Supports reverse space - %s\n",capabilities->sprev ? "Yes":"No");
-       printk(KERN_INFO "ide-tape: Supports erase initiated formatting - %s\n",capabilities->efmt ? "Yes":"No");
-       printk(KERN_INFO "ide-tape: Supports QFA two Partition format - %s\n",capabilities->qfa ? "Yes":"No");
-       printk(KERN_INFO "ide-tape: Supports locking the medium - %s\n",capabilities->lock ? "Yes":"No");
-       printk(KERN_INFO "ide-tape: The volume is currently locked - %s\n",capabilities->locked ? "Yes":"No");
-       printk(KERN_INFO "ide-tape: The device defaults in the prevent state - %s\n",capabilities->prevent ? "Yes":"No");
-       printk(KERN_INFO "ide-tape: Supports ejecting the medium - %s\n",capabilities->eject ? "Yes":"No");
-       printk(KERN_INFO "ide-tape: Supports error correction - %s\n",capabilities->ecc ? "Yes":"No");
-       printk(KERN_INFO "ide-tape: Supports data compression - %s\n",capabilities->cmprs ? "Yes":"No");
-       printk(KERN_INFO "ide-tape: Supports 512 bytes block size - %s\n",capabilities->blk512 ? "Yes":"No");
-       printk(KERN_INFO "ide-tape: Supports 1024 bytes block size - %s\n",capabilities->blk1024 ? "Yes":"No");
-       printk(KERN_INFO "ide-tape: Supports 32768 bytes block size / Restricted byte count for PIO transfers - %s\n",capabilities->blk32768 ? "Yes":"No");
-       printk(KERN_INFO "ide-tape: Maximum supported speed in KBps - %d\n",capabilities->max_speed);
-       printk(KERN_INFO "ide-tape: Continuous transfer limits in blocks - %d\n",capabilities->ctl);
-       printk(KERN_INFO "ide-tape: Current speed in KBps - %d\n",capabilities->speed); 
-       printk(KERN_INFO "ide-tape: Buffer size - %d\n",capabilities->buffer_size*512);
-#endif /* IDETAPE_DEBUG_INFO */
-}
-
-/*
- *     ide_get_blocksize_from_block_descriptor does a mode sense page 0 with block descriptor
- *     and if it succeeds sets the tape block size with the reported value
- */
-static void idetape_get_blocksize_from_block_descriptor(ide_drive_t *drive)
-{
-
-       idetape_tape_t *tape = drive->driver_data;
-       idetape_pc_t pc;
-       idetape_mode_parameter_header_t *header;
-       idetape_parameter_block_descriptor_t *block_descrp;
-       
-       idetape_create_mode_sense_cmd(&pc, IDETAPE_BLOCK_DESCRIPTOR);
-       if (idetape_queue_pc_tail(drive, &pc)) {
-               printk(KERN_ERR "ide-tape: Can't get block descriptor\n");
-               if (tape->tape_block_size == 0) {
-                       printk(KERN_WARNING "ide-tape: Cannot deal with zero block size, assume 32k\n");
-                       tape->tape_block_size =  32768;
-               }
-               return;
-       }
-       header = (idetape_mode_parameter_header_t *) pc.buffer;
-       block_descrp = (idetape_parameter_block_descriptor_t *) (pc.buffer + sizeof(idetape_mode_parameter_header_t));
-       tape->tape_block_size =( block_descrp->length[0]<<16) + (block_descrp->length[1]<<8) + block_descrp->length[2];
-       tape->drv_write_prot = (header->dsp & 0x80) >> 7;
-
-#if IDETAPE_DEBUG_INFO
-       printk(KERN_INFO "ide-tape: Adjusted block size - %d\n", tape->tape_block_size);
-#endif /* IDETAPE_DEBUG_INFO */
+       memcpy(&tape->caps, caps, 20);
+       if (caps[7] & 0x02)
+               tape->blk_size = 512;
+       else if (caps[7] & 0x04)
+               tape->blk_size = 1024;
 }
 
 #ifdef CONFIG_IDE_PROC_FS
-static void idetape_add_settings (ide_drive_t *drive)
+static void idetape_add_settings(ide_drive_t *drive)
 {
        idetape_tape_t *tape = drive->driver_data;
 
-/*
- *                     drive   setting name            read/write      data type       min                     max                     mul_factor                      div_factor      data pointer                            set function
- */
-       ide_add_setting(drive,  "buffer",               SETTING_READ,   TYPE_SHORT,     0,                      0xffff,                 1,                              2,              &tape->capabilities.buffer_size,        NULL);
-       ide_add_setting(drive,  "pipeline_min",         SETTING_RW,     TYPE_INT,       1,                      0xffff,                 tape->stage_size / 1024,        1,              &tape->min_pipeline,                    NULL);
-       ide_add_setting(drive,  "pipeline",             SETTING_RW,     TYPE_INT,       1,                      0xffff,                 tape->stage_size / 1024,        1,              &tape->max_stages,                      NULL);
-       ide_add_setting(drive,  "pipeline_max",         SETTING_RW,     TYPE_INT,       1,                      0xffff,                 tape->stage_size / 1024,        1,              &tape->max_pipeline,                    NULL);
-       ide_add_setting(drive,  "pipeline_used",        SETTING_READ,   TYPE_INT,       0,                      0xffff,                 tape->stage_size / 1024,        1,              &tape->nr_stages,                       NULL);
-       ide_add_setting(drive,  "pipeline_pending",     SETTING_READ,   TYPE_INT,       0,                      0xffff,                 tape->stage_size / 1024,        1,              &tape->nr_pending_stages,               NULL);
-       ide_add_setting(drive,  "speed",                SETTING_READ,   TYPE_SHORT,     0,                      0xffff,                 1,                              1,              &tape->capabilities.speed,              NULL);
-       ide_add_setting(drive,  "stage",                SETTING_READ,   TYPE_INT,       0,                      0xffff,                 1,                              1024,           &tape->stage_size,                      NULL);
-       ide_add_setting(drive,  "tdsc",                 SETTING_RW,     TYPE_INT,       IDETAPE_DSC_RW_MIN,     IDETAPE_DSC_RW_MAX,     1000,                           HZ,             &tape->best_dsc_rw_frequency,           NULL);
-       ide_add_setting(drive,  "dsc_overlap",          SETTING_RW,     TYPE_BYTE,      0,                      1,                      1,                              1,              &drive->dsc_overlap,                    NULL);
-       ide_add_setting(drive,  "pipeline_head_speed_c",SETTING_READ,   TYPE_INT,       0,                      0xffff,                 1,                              1,              &tape->controlled_pipeline_head_speed,  NULL);
-       ide_add_setting(drive,  "pipeline_head_speed_u",SETTING_READ,   TYPE_INT,       0,                      0xffff,                 1,                              1,              &tape->uncontrolled_pipeline_head_speed,NULL);
-       ide_add_setting(drive,  "avg_speed",            SETTING_READ,   TYPE_INT,       0,                      0xffff,                 1,                              1,              &tape->avg_speed,                       NULL);
-       ide_add_setting(drive,  "debug_level",          SETTING_RW,     TYPE_INT,       0,                      0xffff,                 1,                              1,              &tape->debug_level,                     NULL);
+       ide_add_setting(drive, "buffer", SETTING_READ, TYPE_SHORT, 0, 0xffff,
+                       1, 2, (u16 *)&tape->caps[16], NULL);
+       ide_add_setting(drive, "pipeline_min", SETTING_RW, TYPE_INT, 1, 0xffff,
+                       tape->stage_size / 1024, 1, &tape->min_pipeline, NULL);
+       ide_add_setting(drive, "pipeline", SETTING_RW, TYPE_INT, 1, 0xffff,
+                       tape->stage_size / 1024, 1, &tape->max_stages, NULL);
+       ide_add_setting(drive, "pipeline_max", SETTING_RW, TYPE_INT, 1, 0xffff,
+                       tape->stage_size / 1024, 1, &tape->max_pipeline, NULL);
+       ide_add_setting(drive, "pipeline_used", SETTING_READ, TYPE_INT, 0,
+                       0xffff, tape->stage_size / 1024, 1, &tape->nr_stages,
+                       NULL);
+       ide_add_setting(drive, "pipeline_pending", SETTING_READ, TYPE_INT, 0,
+                       0xffff, tape->stage_size / 1024, 1,
+                       &tape->nr_pending_stages, NULL);
+       ide_add_setting(drive, "speed", SETTING_READ, TYPE_SHORT, 0, 0xffff,
+                       1, 1, (u16 *)&tape->caps[14], NULL);
+       ide_add_setting(drive, "stage", SETTING_READ, TYPE_INT, 0, 0xffff, 1,
+                       1024, &tape->stage_size, NULL);
+       ide_add_setting(drive, "tdsc", SETTING_RW, TYPE_INT, IDETAPE_DSC_RW_MIN,
+                       IDETAPE_DSC_RW_MAX, 1000, HZ, &tape->best_dsc_rw_freq,
+                       NULL);
+       ide_add_setting(drive, "dsc_overlap", SETTING_RW, TYPE_BYTE, 0, 1, 1,
+                       1, &drive->dsc_overlap, NULL);
+       ide_add_setting(drive, "pipeline_head_speed_c", SETTING_READ, TYPE_INT,
+                       0, 0xffff, 1, 1, &tape->controlled_pipeline_head_speed,
+                       NULL);
+       ide_add_setting(drive, "pipeline_head_speed_u", SETTING_READ, TYPE_INT,
+                       0, 0xffff, 1, 1,
+                       &tape->uncontrolled_pipeline_head_speed, NULL);
+       ide_add_setting(drive, "avg_speed", SETTING_READ, TYPE_INT, 0, 0xffff,
+                       1, 1, &tape->avg_speed, NULL);
+       ide_add_setting(drive, "debug_mask", SETTING_RW, TYPE_INT, 0, 0xffff, 1,
+                       1, &tape->debug_mask, NULL);
 }
 #else
 static inline void idetape_add_settings(ide_drive_t *drive) { ; }
 #endif
 
 /*
- *     ide_setup is called to:
+ * The function below is called to:
  *
- *             1.      Initialize our various state variables.
- *             2.      Ask the tape for its capabilities.
- *             3.      Allocate a buffer which will be used for data
- *                     transfer. The buffer size is chosen based on
- *                     the recommendation which we received in step (2).
+ * 1. Initialize our various state variables.
+ * 2. Ask the tape for its capabilities.
+ * 3. Allocate a buffer which will be used for data transfer. The buffer size
+ * is chosen based on the recommendation which we received in step 2.
  *
- *     Note that at this point ide.c already assigned us an irq, so that
- *     we can queue requests here and wait for their completion.
+ * Note that at this point ide.c already assigned us an irq, so that we can
+ * queue requests here and wait for their completion.
  */
-static void idetape_setup (ide_drive_t *drive, idetape_tape_t *tape, int minor)
+static void idetape_setup(ide_drive_t *drive, idetape_tape_t *tape, int minor)
 {
        unsigned long t1, tmid, tn, t;
        int speed;
-       struct idetape_id_gcw gcw;
        int stage_size;
+       u8 gcw[2];
        struct sysinfo si;
+       u16 *ctl = (u16 *)&tape->caps[12];
 
-       spin_lock_init(&tape->spinlock);
+       spin_lock_init(&tape->lock);
        drive->dsc_overlap = 1;
-#ifdef CONFIG_BLK_DEV_IDEPCI
-       if (HWIF(drive)->pci_dev != NULL) {
-               /*
-                * These two ide-pci host adapters appear to need DSC overlap disabled.
-                * This probably needs further analysis.
-                */
-               if ((HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF) ||
-                   (HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_TTI_HPT343)) {
-                       printk(KERN_INFO "ide-tape: %s: disabling DSC overlap\n", tape->name);
-                       drive->dsc_overlap = 0;
-               }
+       if (drive->hwif->host_flags & IDE_HFLAG_NO_DSC) {
+               printk(KERN_INFO "ide-tape: %s: disabling DSC overlap\n",
+                                tape->name);
+               drive->dsc_overlap = 0;
        }
-#endif /* CONFIG_BLK_DEV_IDEPCI */
        /* Seagate Travan drives do not support DSC overlap. */
        if (strstr(drive->id->model, "Seagate STT3401"))
                drive->dsc_overlap = 0;
@@ -4611,25 +3532,29 @@ static void idetape_setup (ide_drive_t *drive, idetape_tape_t *tape, int minor)
        tape->name[0] = 'h';
        tape->name[1] = 't';
        tape->name[2] = '0' + minor;
-       tape->chrdev_direction = idetape_direction_none;
+       tape->chrdev_dir = IDETAPE_DIR_NONE;
        tape->pc = tape->pc_stack;
        tape->max_insert_speed = 10000;
        tape->speed_control = 1;
        *((unsigned short *) &gcw) = drive->id->config;
-       if (gcw.drq_type == 1)
+
+       /* Command packet DRQ type */
+       if (((gcw[0] & 0x60) >> 5) == 1)
                set_bit(IDETAPE_DRQ_INTERRUPT, &tape->flags);
 
-       tape->min_pipeline = tape->max_pipeline = tape->max_stages = 10;
-       
+       tape->min_pipeline = 10;
+       tape->max_pipeline = 10;
+       tape->max_stages   = 10;
+
        idetape_get_inquiry_results(drive);
        idetape_get_mode_sense_results(drive);
-       idetape_get_blocksize_from_block_descriptor(drive);
+       ide_tape_get_bsize_from_bdesc(drive);
        tape->user_bs_factor = 1;
-       tape->stage_size = tape->capabilities.ctl * tape->tape_block_size;
+       tape->stage_size = *ctl * tape->blk_size;
        while (tape->stage_size > 0xffff) {
                printk(KERN_NOTICE "ide-tape: decreasing stage size\n");
-               tape->capabilities.ctl /= 2;
-               tape->stage_size = tape->capabilities.ctl * tape->tape_block_size;
+               *ctl /= 2;
+               tape->stage_size = *ctl * tape->blk_size;
        }
        stage_size = tape->stage_size;
        tape->pages_per_stage = stage_size / PAGE_SIZE;
@@ -4638,28 +3563,30 @@ static void idetape_setup (ide_drive_t *drive, idetape_tape_t *tape, int minor)
                tape->excess_bh_size = PAGE_SIZE - stage_size % PAGE_SIZE;
        }
 
-       /*
-        *      Select the "best" DSC read/write polling frequency
-        *      and pipeline size.
-        */
-       speed = max(tape->capabilities.speed, tape->capabilities.max_speed);
+       /* Select the "best" DSC read/write polling freq and pipeline size. */
+       speed = max(*(u16 *)&tape->caps[14], *(u16 *)&tape->caps[8]);
 
        tape->max_stages = speed * 1000 * 10 / tape->stage_size;
 
-       /*
-        *      Limit memory use for pipeline to 10% of physical memory
-        */
+       /* Limit memory use for pipeline to 10% of physical memory */
        si_meminfo(&si);
-       if (tape->max_stages * tape->stage_size > si.totalram * si.mem_unit / 10)
-               tape->max_stages = si.totalram * si.mem_unit / (10 * tape->stage_size);
+       if (tape->max_stages * tape->stage_size >
+                       si.totalram * si.mem_unit / 10)
+               tape->max_stages =
+                       si.totalram * si.mem_unit / (10 * tape->stage_size);
+
        tape->max_stages   = min(tape->max_stages, IDETAPE_MAX_PIPELINE_STAGES);
        tape->min_pipeline = min(tape->max_stages, IDETAPE_MIN_PIPELINE_STAGES);
-       tape->max_pipeline = min(tape->max_stages * 2, IDETAPE_MAX_PIPELINE_STAGES);
-       if (tape->max_stages == 0)
-               tape->max_stages = tape->min_pipeline = tape->max_pipeline = 1;
+       tape->max_pipeline =
+               min(tape->max_stages * 2, IDETAPE_MAX_PIPELINE_STAGES);
+       if (tape->max_stages == 0) {
+               tape->max_stages   = 1;
+               tape->min_pipeline = 1;
+               tape->max_pipeline = 1;
+       }
 
        t1 = (tape->stage_size * HZ) / (speed * 1000);
-       tmid = (tape->capabilities.buffer_size * 32 * HZ) / (speed * 125);
+       tmid = (*(u16 *)&tape->caps[16] * 32 * HZ) / (speed * 125);
        tn = (IDETAPE_FIFO_THRESHOLD * tape->stage_size * HZ) / (speed * 1000);
 
        if (tape->max_stages)
@@ -4668,17 +3595,19 @@ static void idetape_setup (ide_drive_t *drive, idetape_tape_t *tape, int minor)
                t = t1;
 
        /*
-        *      Ensure that the number we got makes sense; limit
-        *      it within IDETAPE_DSC_RW_MIN and IDETAPE_DSC_RW_MAX.
+        * Ensure that the number we got makes sense; limit it within
+        * IDETAPE_DSC_RW_MIN and IDETAPE_DSC_RW_MAX.
         */
-       tape->best_dsc_rw_frequency = max_t(unsigned long, min_t(unsigned long, t, IDETAPE_DSC_RW_MAX), IDETAPE_DSC_RW_MIN);
+       tape->best_dsc_rw_freq = max_t(unsigned long,
+                               min_t(unsigned long, t, IDETAPE_DSC_RW_MAX),
+                               IDETAPE_DSC_RW_MIN);
        printk(KERN_INFO "ide-tape: %s <-> %s: %dKBps, %d*%dkB buffer, "
                "%dkB pipeline, %lums tDSC%s\n",
-               drive->name, tape->name, tape->capabilities.speed,
-               (tape->capabilities.buffer_size * 512) / tape->stage_size,
+               drive->name, tape->name, *(u16 *)&tape->caps[14],
+               (*(u16 *)&tape->caps[16] * 512) / tape->stage_size,
                tape->stage_size / 1024,
                tape->max_stages * tape->stage_size / 1024,
-               tape->best_dsc_rw_frequency * 1000 / HZ,
+               tape->best_dsc_rw_freq * 1000 / HZ,
                drive->using_dma ? ", DMA":"");
 
        idetape_add_settings(drive);
@@ -4706,7 +3635,8 @@ static void ide_tape_release(struct kref *kref)
        drive->dsc_overlap = 0;
        drive->driver_data = NULL;
        device_destroy(idetape_sysfs_class, MKDEV(IDETAPE_MAJOR, tape->minor));
-       device_destroy(idetape_sysfs_class, MKDEV(IDETAPE_MAJOR, tape->minor + 128));
+       device_destroy(idetape_sysfs_class,
+                       MKDEV(IDETAPE_MAJOR, tape->minor + 128));
        idetape_devs[tape->minor] = NULL;
        g->private_data = NULL;
        put_disk(g);
@@ -4755,9 +3685,7 @@ static ide_driver_t idetape_driver = {
 #endif
 };
 
-/*
- *     Our character device supporting functions, passed to register_chrdev.
- */
+/* Our character device supporting functions, passed to register_chrdev. */
 static const struct file_operations idetape_fops = {
        .owner          = THIS_MODULE,
        .read           = idetape_chrdev_read,
@@ -4772,7 +3700,8 @@ static int idetape_open(struct inode *inode, struct file *filp)
        struct gendisk *disk = inode->i_bdev->bd_disk;
        struct ide_tape_obj *tape;
 
-       if (!(tape = ide_tape_get(disk)))
+       tape = ide_tape_get(disk);
+       if (!tape)
                return -ENXIO;
 
        return 0;
@@ -4819,21 +3748,20 @@ static int ide_tape_probe(ide_drive_t *drive)
                goto failed;
        if (drive->media != ide_tape)
                goto failed;
-       if (!idetape_identify_device (drive)) {
-               printk(KERN_ERR "ide-tape: %s: not supported by this version of ide-tape\n", drive->name);
+       if (!idetape_identify_device(drive)) {
+               printk(KERN_ERR "ide-tape: %s: not supported by this version of"
+                               " the driver\n", drive->name);
                goto failed;
        }
        if (drive->scsi) {
-               printk("ide-tape: passing drive %s to ide-scsi emulation.\n", drive->name);
+               printk(KERN_INFO "ide-tape: passing drive %s to ide-scsi"
+                                " emulation.\n", drive->name);
                goto failed;
        }
-       if (strstr(drive->id->model, "OnStream DI-")) {
-               printk(KERN_WARNING "ide-tape: Use drive %s with ide-scsi emulation and osst.\n", drive->name);
-               printk(KERN_WARNING "ide-tape: OnStream support will be removed soon from ide-tape!\n");
-       }
-       tape = kzalloc(sizeof (idetape_tape_t), GFP_KERNEL);
+       tape = kzalloc(sizeof(idetape_tape_t), GFP_KERNEL);
        if (tape == NULL) {
-               printk(KERN_ERR "ide-tape: %s: Can't allocate a tape structure\n", drive->name);
+               printk(KERN_ERR "ide-tape: %s: Can't allocate a tape struct\n",
+                               drive->name);
                goto failed;
        }
 
@@ -4879,10 +3807,7 @@ failed:
        return -ENODEV;
 }
 
-MODULE_DESCRIPTION("ATAPI Streaming TAPE Driver");
-MODULE_LICENSE("GPL");
-
-static void __exit idetape_exit (void)
+static void __exit idetape_exit(void)
 {
        driver_unregister(&idetape_driver.gen_driver);
        class_destroy(idetape_sysfs_class);
@@ -4901,7 +3826,8 @@ static int __init idetape_init(void)
        }
 
        if (register_chrdev(IDETAPE_MAJOR, "ht", &idetape_fops)) {
-               printk(KERN_ERR "ide-tape: Failed to register character device interface\n");
+               printk(KERN_ERR "ide-tape: Failed to register chrdev"
+                               " interface\n");
                error = -EBUSY;
                goto out_free_class;
        }
@@ -4924,3 +3850,5 @@ MODULE_ALIAS("ide:*m-tape*");
 module_init(idetape_init);
 module_exit(idetape_exit);
 MODULE_ALIAS_CHARDEV_MAJOR(IDETAPE_MAJOR);
+MODULE_DESCRIPTION("ATAPI Streaming TAPE Driver");
+MODULE_LICENSE("GPL");
index 5eb6fa15dc4df6d65c5408869b6e22027d049085..0518a2e948cf46f9317f8ef27e4a4121c6df08ae 100644 (file)
@@ -1,11 +1,9 @@
 /*
- * linux/drivers/ide/ide-taskfile.c    Version 0.38    March 05, 2003
- *
- *  Copyright (C) 2000-2002    Michael Cornwell <cornwell@acm.org>
- *  Copyright (C) 2000-2002    Andre Hedrick <andre@linux-ide.org>
- *  Copyright (C) 2001-2002    Klaus Smolin
+ *  Copyright (C) 2000-2002       Michael Cornwell <cornwell@acm.org>
+ *  Copyright (C) 2000-2002       Andre Hedrick <andre@linux-ide.org>
+ *  Copyright (C) 2001-2002       Klaus Smolin
  *                                     IBM Storage Technology Division
- *  Copyright (C) 2003-2004    Bartlomiej Zolnierkiewicz
+ *  Copyright (C) 2003-2004, 2007  Bartlomiej Zolnierkiewicz
  *
  *  The big the bad and the ugly.
  */
@@ -191,12 +189,11 @@ EXPORT_SYMBOL_GPL(do_rw_taskfile);
  */
 static ide_startstop_t set_multmode_intr(ide_drive_t *drive)
 {
-       ide_hwif_t *hwif = HWIF(drive);
-       u8 stat;
+       u8 stat = ide_read_status(drive);
 
-       if (OK_STAT(stat = hwif->INB(IDE_STATUS_REG),READY_STAT,BAD_STAT)) {
+       if (OK_STAT(stat, READY_STAT, BAD_STAT))
                drive->mult_count = drive->mult_req;
-       else {
+       else {
                drive->mult_req = drive->mult_count = 0;
                drive->special.b.recalibrate = 1;
                (void) ide_dump_status(drive, "set_multmode", stat);
@@ -209,11 +206,10 @@ static ide_startstop_t set_multmode_intr(ide_drive_t *drive)
  */
 static ide_startstop_t set_geometry_intr(ide_drive_t *drive)
 {
-       ide_hwif_t *hwif = HWIF(drive);
        int retries = 5;
        u8 stat;
 
-       while (((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) && retries--)
+       while (((stat = ide_read_status(drive)) & BUSY_STAT) && retries--)
                udelay(10);
 
        if (OK_STAT(stat, READY_STAT, BAD_STAT))
@@ -232,10 +228,9 @@ static ide_startstop_t set_geometry_intr(ide_drive_t *drive)
  */
 static ide_startstop_t recal_intr(ide_drive_t *drive)
 {
-       ide_hwif_t *hwif = HWIF(drive);
-       u8 stat;
+       u8 stat = ide_read_status(drive);
 
-       if (!OK_STAT(stat = hwif->INB(IDE_STATUS_REG), READY_STAT, BAD_STAT))
+       if (!OK_STAT(stat, READY_STAT, BAD_STAT))
                return ide_error(drive, "recal_intr", stat);
        return ide_stopped;
 }
@@ -246,23 +241,23 @@ static ide_startstop_t recal_intr(ide_drive_t *drive)
 static ide_startstop_t task_no_data_intr(ide_drive_t *drive)
 {
        ide_task_t *args        = HWGROUP(drive)->rq->special;
-       ide_hwif_t *hwif        = HWIF(drive);
        u8 stat;
 
        local_irq_enable_in_hardirq();
-       if (!OK_STAT(stat = hwif->INB(IDE_STATUS_REG),READY_STAT,BAD_STAT)) {
+       stat = ide_read_status(drive);
+
+       if (!OK_STAT(stat, READY_STAT, BAD_STAT))
                return ide_error(drive, "task_no_data_intr", stat);
                /* calls ide_end_drive_cmd */
-       }
+
        if (args)
-               ide_end_drive_cmd(drive, stat, hwif->INB(IDE_ERROR_REG));
+               ide_end_drive_cmd(drive, stat, ide_read_error(drive));
 
        return ide_stopped;
 }
 
-u8 wait_drive_not_busy(ide_drive_t *drive)
+static u8 wait_drive_not_busy(ide_drive_t *drive)
 {
-       ide_hwif_t *hwif = HWIF(drive);
        int retries;
        u8 stat;
 
@@ -271,7 +266,9 @@ u8 wait_drive_not_busy(ide_drive_t *drive)
         * This can take up to 10 usec, but we will wait max 1 ms.
         */
        for (retries = 0; retries < 100; retries++) {
-               if ((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT)
+               stat = ide_read_status(drive);
+
+               if (stat & BUSY_STAT)
                        udelay(10);
                else
                        break;
@@ -410,7 +407,7 @@ static ide_startstop_t task_error(ide_drive_t *drive, struct request *rq,
 void task_end_request(ide_drive_t *drive, struct request *rq, u8 stat)
 {
        if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) {
-               u8 err = drive->hwif->INB(IDE_ERROR_REG);
+               u8 err = ide_read_error(drive);
 
                ide_end_drive_cmd(drive, stat, err);
                return;
@@ -432,7 +429,7 @@ static ide_startstop_t task_in_intr(ide_drive_t *drive)
 {
        ide_hwif_t *hwif = drive->hwif;
        struct request *rq = HWGROUP(drive)->rq;
-       u8 stat = hwif->INB(IDE_STATUS_REG);
+       u8 stat = ide_read_status(drive);
 
        /* new way for dealing with premature shared PCI interrupts */
        if (!OK_STAT(stat, DRQ_STAT, BAD_R_STAT)) {
@@ -467,7 +464,7 @@ static ide_startstop_t task_out_intr (ide_drive_t *drive)
 {
        ide_hwif_t *hwif = drive->hwif;
        struct request *rq = HWGROUP(drive)->rq;
-       u8 stat = hwif->INB(IDE_STATUS_REG);
+       u8 stat = ide_read_status(drive);
 
        if (!OK_STAT(stat, DRIVE_READY, drive->bad_wstat))
                return task_error(drive, rq, __FUNCTION__, stat);
@@ -757,6 +754,7 @@ int ide_cmd_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
        u8 args[4], xfer_rate = 0;
        ide_task_t tfargs;
        struct ide_taskfile *tf = &tfargs.tf;
+       struct hd_driveid *id = drive->id;
 
        if (NULL == (void *) arg) {
                struct request rq;
@@ -794,10 +792,16 @@ int ide_cmd_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
                        return -ENOMEM;
        }
 
-       if (set_transfer(drive, &tfargs)) {
+       if (tf->command == WIN_SETFEATURES &&
+           tf->feature == SETFEATURES_XFER &&
+           tf->nsect >= XFER_SW_DMA_0 &&
+           (id->dma_ultra || id->dma_mword || id->dma_1word)) {
                xfer_rate = args[1];
-               if (ide_ata66_check(drive, &tfargs))
+               if (tf->nsect > XFER_UDMA_2 && !eighty_ninty_three(drive)) {
+                       printk(KERN_WARNING "%s: UDMA speeds >UDMA33 cannot "
+                                           "be set\n", drive->name);
                        goto abort;
+               }
        }
 
        err = ide_raw_taskfile(drive, &tfargs, buf, args[3]);
index daffbb9797e18d756299786d2326e0f892fe67f6..3b12ffe770712dd1f1a708c7852ff5745a9b6e2a 100644 (file)
@@ -2,8 +2,6 @@
 #define _IDE_TIMING_H
 
 /*
- * $Id: ide-timing.h,v 1.6 2001/12/23 22:47:56 vojtech Exp $
- *
  *  Copyright (c) 1999-2001 Vojtech Pavlik
  */
 
@@ -201,7 +199,7 @@ static int ide_timing_compute(ide_drive_t *drive, short speed, struct ide_timing
        }
 
 /*
- * Lenghten active & recovery time so that cycle time is correct.
+ * Lengthen active & recovery time so that cycle time is correct.
  */
 
        if (t->act8b + t->rec8b < t->cyc8b) {
index 97894abd9ebca93da51af65b7268a953e7969a47..ad0e9955f73c9ce38de7485b487bb778b9542e87 100644 (file)
@@ -1,7 +1,6 @@
 /*
- *  linux/drivers/ide/ide.c            Version 7.00beta2       Mar 05 2003
- *
- *  Copyright (C) 1994-1998  Linus Torvalds & authors (see below)
+ *  Copyright (C) 1994-1998        Linus Torvalds & authors (see below)
+ *  Copyrifht (C) 2003-2005, 2007   Bartlomiej Zolnierkiewicz
  */
 
 /*
@@ -46,7 +45,6 @@
  */
 
 #define        REVISION        "Revision: 7.00alpha2"
-#define        VERSION         "Id: ide.c 7.00a2 20020906"
 
 #define _IDE_C                 /* Tell ide.h it's really us */
 
@@ -242,22 +240,12 @@ static int ide_system_bus_speed(void)
 #define pci_default 0
 #endif /* CONFIG_PCI */
 
-       if (!system_bus_speed) {
-               if (idebus_parameter) {
-                       /* user supplied value */
-                       system_bus_speed = idebus_parameter;
-               } else if (pci_dev_present(pci_default)) {
-                       /* safe default value for PCI */
-                       system_bus_speed = 33;
-               } else {
-                       /* safe default value for VESA and PCI */
-                       system_bus_speed = 50;
-               }
-               printk(KERN_INFO "ide: Assuming %dMHz system bus speed "
-                       "for PIO modes%s\n", system_bus_speed,
-                       idebus_parameter ? "" : "; override with idebus=xx");
-       }
-       return system_bus_speed;
+       /* user supplied value */
+       if (idebus_parameter)
+               return idebus_parameter;
+
+       /* safe default value for PCI or VESA and PCI*/
+       return pci_dev_present(pci_default) ? 33 : 50;
 }
 
 ide_hwif_t * ide_find_port(unsigned long base)
@@ -405,8 +393,9 @@ static void ide_hwif_restore(ide_hwif_t *hwif, ide_hwif_t *tmp_hwif)
        hwif->chipset                   = tmp_hwif->chipset;
        hwif->hold                      = tmp_hwif->hold;
 
+       hwif->dev                       = tmp_hwif->dev;
+
 #ifdef CONFIG_BLK_DEV_IDEPCI
-       hwif->pci_dev                   = tmp_hwif->pci_dev;
        hwif->cds                       = tmp_hwif->cds;
 #endif
 
@@ -472,9 +461,46 @@ static void ide_hwif_restore(ide_hwif_t *hwif, ide_hwif_t *tmp_hwif)
        hwif->hwif_data                 = tmp_hwif->hwif_data;
 }
 
+void ide_remove_port_from_hwgroup(ide_hwif_t *hwif)
+{
+       ide_hwgroup_t *hwgroup = hwif->hwgroup;
+
+       spin_lock_irq(&ide_lock);
+       /*
+        * Remove us from the hwgroup, and free
+        * the hwgroup if we were the only member
+        */
+       if (hwif->next == hwif) {
+               BUG_ON(hwgroup->hwif != hwif);
+               kfree(hwgroup);
+       } else {
+               /* There is another interface in hwgroup.
+                * Unlink us, and set hwgroup->drive and ->hwif to
+                * something sane.
+                */
+               ide_hwif_t *g = hwgroup->hwif;
+
+               while (g->next != hwif)
+                       g = g->next;
+               g->next = hwif->next;
+               if (hwgroup->hwif == hwif) {
+                       /* Chose a random hwif for hwgroup->hwif.
+                        * It's guaranteed that there are no drives
+                        * left in the hwgroup.
+                        */
+                       BUG_ON(hwgroup->drive != NULL);
+                       hwgroup->hwif = g;
+               }
+               BUG_ON(hwgroup->hwif == hwif);
+       }
+       spin_unlock_irq(&ide_lock);
+}
+
 /**
  *     ide_unregister          -       free an IDE interface
  *     @index: index of interface (will change soon to a pointer)
+ *     @init_default: init default hwif flag
+ *     @restore: restore hwif flag
  *
  *     Perform the final unregister of an IDE interface. At the moment
  *     we don't refcount interfaces so this will also get split up.
@@ -494,7 +520,7 @@ static void ide_hwif_restore(ide_hwif_t *hwif, ide_hwif_t *tmp_hwif)
  *     This is raving bonkers.
  */
 
-void ide_unregister(unsigned int index)
+void ide_unregister(unsigned int index, int init_default, int restore)
 {
        ide_drive_t *drive;
        ide_hwif_t *hwif, *g;
@@ -539,43 +565,8 @@ void ide_unregister(unsigned int index)
        if (irq_count == 1)
                free_irq(hwif->irq, hwgroup);
 
-       spin_lock_irq(&ide_lock);
-       /*
-        * Note that we only release the standard ports,
-        * and do not even try to handle any extra ports
-        * allocated for weird IDE interface chipsets.
-        */
-       ide_hwif_release_regions(hwif);
-
-       /*
-        * Remove us from the hwgroup, and free
-        * the hwgroup if we were the only member
-        */
-       if (hwif->next == hwif) {
-               BUG_ON(hwgroup->hwif != hwif);
-               kfree(hwgroup);
-       } else {
-               /* There is another interface in hwgroup.
-                * Unlink us, and set hwgroup->drive and ->hwif to
-                * something sane.
-                */
-               g = hwgroup->hwif;
-               while (g->next != hwif)
-                       g = g->next;
-               g->next = hwif->next;
-               if (hwgroup->hwif == hwif) {
-                       /* Chose a random hwif for hwgroup->hwif.
-                        * It's guaranteed that there are no drives
-                        * left in the hwgroup.
-                        */
-                       BUG_ON(hwgroup->drive != NULL);
-                       hwgroup->hwif = g;
-               }
-               BUG_ON(hwgroup->hwif == hwif);
-       }
+       ide_remove_port_from_hwgroup(hwif);
 
-       /* More messed up locking ... */
-       spin_unlock_irq(&ide_lock);
        device_unregister(&hwif->gendev);
        wait_for_completion(&hwif->gendev_rel_comp);
 
@@ -601,14 +592,24 @@ void ide_unregister(unsigned int index)
                hwif->extra_ports = 0;
        }
 
+       /*
+        * Note that we only release the standard ports,
+        * and do not even try to handle any extra ports
+        * allocated for weird IDE interface chipsets.
+        */
+       ide_hwif_release_regions(hwif);
+
        /* copy original settings */
        tmp_hwif = *hwif;
 
        /* restore hwif data to pristine status */
        ide_init_port_data(hwif, index);
-       init_hwif_default(hwif, index);
 
-       ide_hwif_restore(hwif, &tmp_hwif);
+       if (init_default)
+               init_hwif_default(hwif, index);
+
+       if (restore)
+               ide_hwif_restore(hwif, &tmp_hwif);
 
 abort:
        spin_unlock_irq(&ide_lock);
@@ -617,60 +618,6 @@ abort:
 
 EXPORT_SYMBOL(ide_unregister);
 
-
-/**
- *     ide_setup_ports         -       set up IDE interface ports
- *     @hw: register descriptions
- *     @base: base register
- *     @offsets: table of register offsets
- *     @ctrl: control register
- *     @ack_irq: IRQ ack
- *     @irq: interrupt lie
- *
- *     Setup hw_regs_t structure described by parameters.  You
- *     may set up the hw structure yourself OR use this routine to
- *     do it for you. This is basically a helper
- *
- */
-void ide_setup_ports ( hw_regs_t *hw,
-                       unsigned long base, int *offsets,
-                       unsigned long ctrl, unsigned long intr,
-                       ide_ack_intr_t *ack_intr,
-/*
- *                     ide_io_ops_t *iops,
- */
-                       int irq)
-{
-       int i;
-
-       memset(hw, 0, sizeof(hw_regs_t));
-       for (i = 0; i < IDE_NR_PORTS; i++) {
-               if (offsets[i] == -1) {
-                       switch(i) {
-                               case IDE_CONTROL_OFFSET:
-                                       hw->io_ports[i] = ctrl;
-                                       break;
-#if defined(CONFIG_AMIGA) || defined(CONFIG_MAC)
-                               case IDE_IRQ_OFFSET:
-                                       hw->io_ports[i] = intr;
-                                       break;
-#endif /* (CONFIG_AMIGA) || (CONFIG_MAC) */
-                               default:
-                                       hw->io_ports[i] = 0;
-                                       break;
-                       }
-               } else {
-                       hw->io_ports[i] = base + offsets[i];
-               }
-       }
-       hw->irq = irq;
-       hw->ack_intr = ack_intr;
-/*
- *     hw->iops = iops;
- */
-}
-
 void ide_init_port_hw(ide_hwif_t *hwif, hw_regs_t *hw)
 {
        memcpy(hwif->io_ports, hw->io_ports, sizeof(hwif->io_ports));
@@ -682,6 +629,31 @@ void ide_init_port_hw(ide_hwif_t *hwif, hw_regs_t *hw)
 }
 EXPORT_SYMBOL_GPL(ide_init_port_hw);
 
+ide_hwif_t *ide_deprecated_find_port(unsigned long base)
+{
+       ide_hwif_t *hwif;
+       int i;
+
+       for (i = 0; i < MAX_HWIFS; i++) {
+               hwif = &ide_hwifs[i];
+               if (hwif->io_ports[IDE_DATA_OFFSET] == base)
+                       goto found;
+       }
+
+       for (i = 0; i < MAX_HWIFS; i++) {
+               hwif = &ide_hwifs[i];
+               if (hwif->hold)
+                       continue;
+               if (!hwif->present && hwif->mate == NULL)
+                       goto found;
+       }
+
+       hwif = NULL;
+found:
+       return hwif;
+}
+EXPORT_SYMBOL_GPL(ide_deprecated_find_port);
+
 /**
  *     ide_register_hw         -       register IDE interface
  *     @hw: hardware registers
@@ -701,38 +673,26 @@ int ide_register_hw(hw_regs_t *hw, void (*quirkproc)(ide_drive_t *),
        u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
 
        do {
-               for (index = 0; index < MAX_HWIFS; ++index) {
-                       hwif = &ide_hwifs[index];
-                       if (hwif->io_ports[IDE_DATA_OFFSET] == hw->io_ports[IDE_DATA_OFFSET])
-                               goto found;
-               }
-               for (index = 0; index < MAX_HWIFS; ++index) {
-                       hwif = &ide_hwifs[index];
-                       if (hwif->hold)
-                               continue;
-                       if (!hwif->present && hwif->mate == NULL)
-                               goto found;
-               }
+               hwif = ide_deprecated_find_port(hw->io_ports[IDE_DATA_OFFSET]);
+               index = hwif->index;
+               if (hwif)
+                       goto found;
                for (index = 0; index < MAX_HWIFS; index++)
-                       ide_unregister(index);
+                       ide_unregister(index, 1, 1);
        } while (retry--);
        return -1;
 found:
        if (hwif->present)
-               ide_unregister(index);
-       else if (!hwif->hold) {
+               ide_unregister(index, 0, 1);
+       else if (!hwif->hold)
                ide_init_port_data(hwif, index);
-               init_hwif_default(hwif, index);
-       }
-       if (hwif->present)
-               return -1;
 
        ide_init_port_hw(hwif, hw);
        hwif->quirkproc = quirkproc;
 
        idx[0] = index;
 
-       ide_device_add(idx);
+       ide_device_add(idx, NULL);
 
        if (hwifp)
                *hwifp = hwif;
@@ -795,10 +755,6 @@ int set_io_32bit(ide_drive_t *drive, int arg)
                return -EBUSY;
 
        drive->io_32bit = arg;
-#ifdef CONFIG_BLK_DEV_DTC2278
-       if (HWIF(drive)->chipset == ide_dtc2278)
-               HWIF(drive)->drives[!drive->select.b.unit].io_32bit = arg;
-#endif /* CONFIG_BLK_DEV_DTC2278 */
 
        spin_unlock_irq(&ide_lock);
 
@@ -913,7 +869,7 @@ static int set_unmaskirq(ide_drive_t *drive, int arg)
 
 int system_bus_clock (void)
 {
-       return((int) ((!system_bus_speed) ? ide_system_bus_speed() : system_bus_speed ));
+       return system_bus_speed;
 }
 
 EXPORT_SYMBOL(system_bus_clock);
@@ -1025,11 +981,8 @@ int generic_ide_ioctl(ide_drive_t *drive, struct file *file, struct block_device
                case HDIO_GET_NICE:
                        return put_user(drive->dsc_overlap      <<      IDE_NICE_DSC_OVERLAP    |
                                        drive->atapi_overlap    <<      IDE_NICE_ATAPI_OVERLAP  |
-                                       drive->nice0            <<      IDE_NICE_0              |
-                                       drive->nice1            <<      IDE_NICE_1              |
-                                       drive->nice2            <<      IDE_NICE_2,
+                                       drive->nice1 << IDE_NICE_1,
                                        (long __user *) arg);
-
 #ifdef CONFIG_IDE_TASK_IOCTL
                case HDIO_DRIVE_TASKFILE:
                        if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
@@ -1070,7 +1023,7 @@ int generic_ide_ioctl(ide_drive_t *drive, struct file *file, struct block_device
                case HDIO_UNREGISTER_HWIF:
                        if (!capable(CAP_SYS_RAWIO)) return -EACCES;
                        /* (arg > MAX_HWIFS) checked in function */
-                       ide_unregister(arg);
+                       ide_unregister(arg, 1, 1);
                        return 0;
                case HDIO_SET_NICE:
                        if (!capable(CAP_SYS_ADMIN)) return -EACCES;
@@ -1668,6 +1621,10 @@ static int __init ide_init(void)
        printk(KERN_INFO "Uniform Multi-Platform E-IDE driver " REVISION "\n");
        system_bus_speed = ide_system_bus_speed();
 
+       printk(KERN_INFO "ide: Assuming %dMHz system bus speed "
+                        "for PIO modes%s\n", system_bus_speed,
+                       idebus_parameter ? "" : "; override with idebus=xx");
+
        ret = bus_register(&ide_bus_type);
        if (ret < 0) {
                printk(KERN_WARNING "IDE: bus_register error: %d\n", ret);
@@ -1711,7 +1668,7 @@ void __exit cleanup_module (void)
        int index;
 
        for (index = 0; index < MAX_HWIFS; ++index)
-               ide_unregister(index);
+               ide_unregister(index, 0, 0);
 
        proc_ide_destroy();
 
index 5ec0be4cbad71d1d5f5fc626792db680c8cb09f9..d4d1a6bea599e3bf93dbae01d4e05dc5ffd2d9f7 100644 (file)
@@ -1,6 +1,4 @@
 /*
- *  linux/drivers/ide/legacy/ali14xx.c         Version 0.03    Feb 09, 1996
- *
  *  Copyright (C) 1996  Linus Torvalds & author (see below)
  */
 
@@ -193,9 +191,14 @@ static int __init initRegisters (void) {
        return t;
 }
 
+static const struct ide_port_info ali14xx_port_info = {
+       .chipset                = ide_ali14xx,
+       .host_flags             = IDE_HFLAG_NO_DMA | IDE_HFLAG_NO_AUTOTUNE,
+       .pio_mask               = ATA_PIO4,
+};
+
 static int __init ali14xx_probe(void)
 {
-       ide_hwif_t *hwif, *mate;
        static u8 idx[4] = { 0, 1, 0xff, 0xff };
 
        printk(KERN_DEBUG "ali14xx: base=0x%03x, regOn=0x%02x.\n",
@@ -207,21 +210,10 @@ static int __init ali14xx_probe(void)
                return 1;
        }
 
-       hwif = &ide_hwifs[0];
-       mate = &ide_hwifs[1];
-
-       hwif->chipset = ide_ali14xx;
-       hwif->pio_mask = ATA_PIO4;
-       hwif->set_pio_mode = &ali14xx_set_pio_mode;
-       hwif->mate = mate;
-
-       mate->chipset = ide_ali14xx;
-       mate->pio_mask = ATA_PIO4;
-       mate->set_pio_mode = &ali14xx_set_pio_mode;
-       mate->mate = hwif;
-       mate->channel = 1;
+       ide_hwifs[0].set_pio_mode = &ali14xx_set_pio_mode;
+       ide_hwifs[1].set_pio_mode = &ali14xx_set_pio_mode;
 
-       ide_device_add(idx);
+       ide_device_add(idx, &ali14xx_port_info);
 
        return 0;
 }
index 74d28e058f55a9038d609683f2bc0078ac6a2e2a..50ffa871d5e937b190490f4be21f68f98f6667b5 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/ide/legacy/buddha.c -- Amiga Buddha, Catweasel and X-Surf IDE Driver
+ *  Amiga Buddha, Catweasel and X-Surf IDE Driver
  *
  *     Copyright (C) 1997, 2001 by Geert Uytterhoeven and others
  *
@@ -56,31 +56,11 @@ static u_int xsurf_bases[XSURF_NUM_HWIFS] __initdata = {
      XSURF_BASE1, XSURF_BASE2
 };
 
-
     /*
      *  Offsets from one of the above bases
      */
 
-#define BUDDHA_DATA    0x00
-#define BUDDHA_ERROR   0x06            /* see err-bits */
-#define BUDDHA_NSECTOR 0x0a            /* nr of sectors to read/write */
-#define BUDDHA_SECTOR  0x0e            /* starting sector */
-#define BUDDHA_LCYL    0x12            /* starting cylinder */
-#define BUDDHA_HCYL    0x16            /* high byte of starting cyl */
-#define BUDDHA_SELECT  0x1a            /* 101dhhhh , d=drive, hhhh=head */
-#define BUDDHA_STATUS  0x1e            /* see status-bits */
 #define BUDDHA_CONTROL 0x11a
-#define XSURF_CONTROL   -1              /* X-Surf has no CS1* (Control/AltStat) */
-
-static int buddha_offsets[IDE_NR_PORTS] __initdata = {
-    BUDDHA_DATA, BUDDHA_ERROR, BUDDHA_NSECTOR, BUDDHA_SECTOR, BUDDHA_LCYL,
-    BUDDHA_HCYL, BUDDHA_SELECT, BUDDHA_STATUS, BUDDHA_CONTROL, -1
-};
-
-static int xsurf_offsets[IDE_NR_PORTS] __initdata = {
-    BUDDHA_DATA, BUDDHA_ERROR, BUDDHA_NSECTOR, BUDDHA_SECTOR, BUDDHA_LCYL,
-    BUDDHA_HCYL, BUDDHA_SELECT, BUDDHA_STATUS, XSURF_CONTROL, -1
-};
 
     /*
      *  Other registers
@@ -140,6 +120,26 @@ static int xsurf_ack_intr(ide_hwif_t *hwif)
     return 1;
 }
 
+static void __init buddha_setup_ports(hw_regs_t *hw, unsigned long base,
+                                     unsigned long ctl, unsigned long irq_port,
+                                     ide_ack_intr_t *ack_intr)
+{
+       int i;
+
+       memset(hw, 0, sizeof(*hw));
+
+       hw->io_ports[IDE_DATA_OFFSET] = base;
+
+       for (i = 1; i < 8; i++)
+               hw->io_ports[i] = base + 2 + i * 4;
+
+       hw->io_ports[IDE_CONTROL_OFFSET] = ctl;
+       hw->io_ports[IDE_IRQ_OFFSET] = irq_port;
+
+       hw->irq = IRQ_AMIGA_PORTS;
+       hw->ack_intr = ack_intr;
+}
+
     /*
      *  Probe for a Buddha or Catweasel IDE interface
      */
@@ -202,22 +202,24 @@ fail_base2:
                printk(KERN_INFO "ide: %s IDE controller\n",
                                 buddha_board_name[type]);
 
-               for(i=0;i<buddha_num_hwifs;i++) {
-                       if(type != BOARD_XSURF) {
-                               ide_setup_ports(&hw, (buddha_board+buddha_bases[i]),
-                                               buddha_offsets, 0,
-                                               (buddha_board+buddha_irqports[i]),
-                                               buddha_ack_intr,
-//                                             budda_iops,
-                                               IRQ_AMIGA_PORTS);
+               for (i = 0; i < buddha_num_hwifs; i++) {
+                       unsigned long base, ctl, irq_port;
+                       ide_ack_intr_t *ack_intr;
+
+                       if (type != BOARD_XSURF) {
+                               base = buddha_board + buddha_bases[i];
+                               ctl = base + BUDDHA_CONTROL;
+                               irq_port = buddha_board + buddha_irqports[i];
+                               ack_intr = buddha_ack_intr;
                        } else {
-                               ide_setup_ports(&hw, (buddha_board+xsurf_bases[i]),
-                                               xsurf_offsets, 0,
-                                               (buddha_board+xsurf_irqports[i]),
-                                               xsurf_ack_intr,
-//                                             xsurf_iops,
-                                               IRQ_AMIGA_PORTS);
-                       }       
+                               base = buddha_board + xsurf_bases[i];
+                               /* X-Surf has no CS1* (Control/AltStat) */
+                               ctl = 0;
+                               irq_port = buddha_board + xsurf_irqports[i];
+                               ack_intr = xsurf_ack_intr;
+                       }
+
+                       buddha_setup_ports(&hw, base, ctl, irq_port, ack_intr);
 
                        hwif = ide_find_port(hw.io_ports[IDE_DATA_OFFSET]);
                        if (hwif) {
@@ -232,7 +234,7 @@ fail_base2:
                        }
                }
 
-               ide_device_add(idx);
+               ide_device_add(idx, NULL);
        }
 
        return 0;
index 13eee6da280656073f657db9ed2a44488eb5d3af..73396f70f2b74c6aed1b5a7c41da3dde495d4fe2 100644 (file)
@@ -1,6 +1,4 @@
 /*
- *  linux/drivers/ide/legacy/dtc2278.c         Version 0.02    Feb 10, 1996
- *
  *  Copyright (C) 1996  Linus Torvalds & author (see below)
  */
 
@@ -86,14 +84,20 @@ static void dtc2278_set_pio_mode(ide_drive_t *drive, const u8 pio)
                /* Actually we do - there is a data sheet available for the
                   Winbond but does anyone actually care */
        }
-
-       /*
-        * 32bit I/O has to be enabled for *both* drives at the same time.
-        */
-       drive->io_32bit = 1;
-       HWIF(drive)->drives[!drive->select.b.unit].io_32bit = 1;
 }
 
+static const struct ide_port_info dtc2278_port_info __initdata = {
+       .chipset                = ide_dtc2278,
+       .host_flags             = IDE_HFLAG_SERIALIZE |
+                                 IDE_HFLAG_NO_UNMASK_IRQS |
+                                 IDE_HFLAG_IO_32BIT |
+                                 /* disallow ->io_32bit changes */
+                                 IDE_HFLAG_NO_IO_32BIT |
+                                 IDE_HFLAG_NO_DMA |
+                                 IDE_HFLAG_NO_AUTOTUNE,
+       .pio_mask               = ATA_PIO4,
+};
+
 static int __init dtc2278_probe(void)
 {
        unsigned long flags;
@@ -124,23 +128,9 @@ static int __init dtc2278_probe(void)
 #endif
        local_irq_restore(flags);
 
-       hwif->serialized = 1;
-       hwif->chipset = ide_dtc2278;
-       hwif->pio_mask = ATA_PIO4;
        hwif->set_pio_mode = &dtc2278_set_pio_mode;
-       hwif->drives[0].no_unmask = 1;
-       hwif->drives[1].no_unmask = 1;
-       hwif->mate = mate;
-
-       mate->serialized = 1;
-       mate->chipset = ide_dtc2278;
-       mate->pio_mask = ATA_PIO4;
-       mate->drives[0].no_unmask = 1;
-       mate->drives[1].no_unmask = 1;
-       mate->mate = hwif;
-       mate->channel = 1;
-
-       ide_device_add(idx);
+
+       ide_device_add(idx, &dtc2278_port_info);
 
        return 0;
 }
index 2860956bdcb079196c199e91af40163615670043..f044048903b3ebc8af7b3f67aa4cb8a073c89bc7 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/ide/legacy/falconide.c -- Atari Falcon IDE Driver
+ *  Atari Falcon IDE Driver
  *
  *     Created 12 Jul 1997 by Geert Uytterhoeven
  *
      *  Offsets from the above base
      */
 
-#define ATA_HD_DATA    0x00
-#define ATA_HD_ERROR   0x05            /* see err-bits */
-#define ATA_HD_NSECTOR 0x09            /* nr of sectors to read/write */
-#define ATA_HD_SECTOR  0x0d            /* starting sector */
-#define ATA_HD_LCYL    0x11            /* starting cylinder */
-#define ATA_HD_HCYL    0x15            /* high byte of starting cyl */
-#define ATA_HD_SELECT  0x19            /* 101dhhhh , d=drive, hhhh=head */
-#define ATA_HD_STATUS  0x1d            /* see status-bits */
 #define ATA_HD_CONTROL 0x39
 
-static int falconide_offsets[IDE_NR_PORTS] __initdata = {
-    ATA_HD_DATA, ATA_HD_ERROR, ATA_HD_NSECTOR, ATA_HD_SECTOR, ATA_HD_LCYL,
-    ATA_HD_HCYL, ATA_HD_SELECT, ATA_HD_STATUS, ATA_HD_CONTROL, -1
-};
-
-
     /*
      *  falconide_intr_lock is used to obtain access to the IDE interrupt,
      *  which is shared between several drivers.
@@ -57,6 +43,22 @@ static int falconide_offsets[IDE_NR_PORTS] __initdata = {
 int falconide_intr_lock;
 EXPORT_SYMBOL(falconide_intr_lock);
 
+static void __init falconide_setup_ports(hw_regs_t *hw)
+{
+       int i;
+
+       memset(hw, 0, sizeof(*hw));
+
+       hw->io_ports[IDE_DATA_OFFSET] = ATA_HD_BASE;
+
+       for (i = 1; i < 8; i++)
+               hw->io_ports[i] = ATA_HD_BASE + 1 + i * 4;
+
+       hw->io_ports[IDE_CONTROL_OFFSET] = ATA_HD_CONTROL;
+
+       hw->irq = IRQ_MFP_IDE;
+       hw->ack_intr = NULL;
+}
 
     /*
      *  Probe for a Falcon IDE interface
@@ -64,15 +66,15 @@ EXPORT_SYMBOL(falconide_intr_lock);
 
 static int __init falconide_init(void)
 {
-    if (MACH_IS_ATARI && ATARIHW_PRESENT(IDE)) {
        hw_regs_t hw;
+       ide_hwif_t *hwif;
+
+       if (!MACH_IS_ATARI || !ATARIHW_PRESENT(IDE))
+               return 0;
 
        printk(KERN_INFO "ide: Falcon IDE controller\n");
 
-       ide_setup_ports(&hw, ATA_HD_BASE, falconide_offsets,
-                       0, 0, NULL,
-//                     falconide_iops,
-                       IRQ_MFP_IDE);
+       falconide_setup_ports(&hw);
 
        hwif = ide_find_port(hw.io_ports[IDE_DATA_OFFSET]);
        if (hwif) {
@@ -82,11 +84,10 @@ static int __init falconide_init(void)
                ide_init_port_data(hwif, index);
                ide_init_port_hw(hwif, &hw);
 
-               ide_device_add(idx);
+               ide_device_add(idx, NULL);
        }
-    }
 
-    return 0;
+       return 0;
 }
 
 module_init(falconide_init);
index 492fa047efc00bb8da4b114f18f7e6b7b1405d88..9d3851d27677785ff331fc8908cd93e9e5da81ed 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/ide/legacy/gayle.c -- Amiga Gayle IDE Driver
+ *  Amiga Gayle IDE Driver
  *
  *     Created 9 Jul 1997 by Geert Uytterhoeven
  *
      *  Offsets from one of the above bases
      */
 
-#define GAYLE_DATA     0x00
-#define GAYLE_ERROR    0x06            /* see err-bits */
-#define GAYLE_NSECTOR  0x0a            /* nr of sectors to read/write */
-#define GAYLE_SECTOR   0x0e            /* starting sector */
-#define GAYLE_LCYL     0x12            /* starting cylinder */
-#define GAYLE_HCYL     0x16            /* high byte of starting cyl */
-#define GAYLE_SELECT   0x1a            /* 101dhhhh , d=drive, hhhh=head */
-#define GAYLE_STATUS   0x1e            /* see status-bits */
 #define GAYLE_CONTROL  0x101a
 
-static int gayle_offsets[IDE_NR_PORTS] __initdata = {
-    GAYLE_DATA, GAYLE_ERROR, GAYLE_NSECTOR, GAYLE_SECTOR, GAYLE_LCYL,
-    GAYLE_HCYL, GAYLE_SELECT, GAYLE_STATUS, -1, -1
-};
-
-
     /*
      *  These are at different offsets from the base
      */
@@ -106,6 +92,26 @@ static int gayle_ack_intr_a1200(ide_hwif_t *hwif)
     return 1;
 }
 
+static void __init gayle_setup_ports(hw_regs_t *hw, unsigned long base,
+                                    unsigned long ctl, unsigned long irq_port,
+                                    ide_ack_intr_t *ack_intr);
+{
+       int i;
+
+       memset(hw, 0, sizeof(*hw));
+
+       hw->io_ports[IDE_DATA_OFFSET] = base;
+
+       for (i = 1; i < 8; i++)
+               hw->io_ports[i] = base + 2 + i * 4;
+
+       hw->io_ports[IDE_CONTROL_OFFSET] = ctl;
+       hw->io_ports[IDE_IRQ_OFFSET] = irq_port;
+
+       hw->irq = IRQ_AMIGA_PORTS;
+       hw->ack_intr = ack_intr;
+}
+
     /*
      *  Probe for a Gayle IDE interface (and optionally for an IDE doubler)
      */
@@ -167,10 +173,7 @@ found:
        base = (unsigned long)ZTWO_VADDR(phys_base);
        ctrlport = GAYLE_HAS_CONTROL_REG ? (base + GAYLE_CONTROL) : 0;
 
-       ide_setup_ports(&hw, base, gayle_offsets,
-                       ctrlport, irqport, ack_intr,
-//                     &gayle_iops,
-                       IRQ_AMIGA_PORTS);
+       gayle_setup_ports(&hw, base, ctrlport, irqport, ack_intr);
 
        hwif = ide_find_port(base);
        if (hwif) {
@@ -186,7 +189,7 @@ found:
            release_mem_region(res_start, res_n);
     }
 
-    ide_device_add(idx);
+    ide_device_add(idx, NULL);
 
     return 0;
 }
index 8e05d88e81babd0e74560821e80065dfa18e79d7..0b0d867319278af5e652d1310f887f0dafc915fa 100644 (file)
@@ -421,11 +421,14 @@ static void bad_rw_intr(void)
 
 static inline int wait_DRQ(void)
 {
-       int retries = 100000, stat;
+       int retries;
+       int stat;
 
-       while (--retries > 0)
-               if ((stat = inb_p(HD_STATUS)) & DRQ_STAT)
+       for (retries = 0; retries < 100000; retries++) {
+               stat = inb_p(HD_STATUS);
+               if (stat & DRQ_STAT)
                        return 0;
+       }
        dump_status("wait_DRQ", stat);
        return -1;
 }
index 8da5031a6d05d7a7848033152bcbd57d34fe4f61..02d12c74764a6a6fcd38935f8cbba4286398b4f7 100644 (file)
@@ -1,6 +1,4 @@
 /*
- *  linux/drivers/ide/legacy/ht6560b.c         Version 0.07    Feb  1, 2000
- *
  *  Copyright (C) 1995-2000  Linus Torvalds & author (see below)
  */
 
@@ -302,16 +300,36 @@ static void ht6560b_set_pio_mode(ide_drive_t *drive, const u8 pio)
 #endif
 }
 
+static void __init ht6560b_port_init_devs(ide_hwif_t *hwif)
+{
+       /* Setting default configurations for drives. */
+       int t = (HT_CONFIG_DEFAULT << 8) | HT_TIMING_DEFAULT;
+
+       if (hwif->channel)
+               t |= (HT_SECONDARY_IF << 8);
+
+       hwif->drives[0].drive_data = t;
+       hwif->drives[1].drive_data = t;
+}
+
 int probe_ht6560b = 0;
 
 module_param_named(probe, probe_ht6560b, bool, 0);
 MODULE_PARM_DESC(probe, "probe for HT6560B chipset");
 
+static const struct ide_port_info ht6560b_port_info __initdata = {
+       .chipset                = ide_ht6560b,
+       .host_flags             = IDE_HFLAG_SERIALIZE | /* is this needed? */
+                                 IDE_HFLAG_NO_DMA |
+                                 IDE_HFLAG_NO_AUTOTUNE |
+                                 IDE_HFLAG_ABUSE_PREFETCH,
+       .pio_mask               = ATA_PIO5,
+};
+
 static int __init ht6560b_init(void)
 {
        ide_hwif_t *hwif, *mate;
        static u8 idx[4] = { 0, 1, 0xff, 0xff };
-       int t;
 
        if (probe_ht6560b == 0)
                return -ENODEV;
@@ -330,36 +348,16 @@ static int __init ht6560b_init(void)
                goto release_region;
        }
 
-       hwif->chipset = ide_ht6560b;
        hwif->selectproc = &ht6560b_selectproc;
-       hwif->host_flags = IDE_HFLAG_ABUSE_PREFETCH;
-       hwif->pio_mask = ATA_PIO5;
        hwif->set_pio_mode = &ht6560b_set_pio_mode;
-       hwif->serialized = 1;   /* is this needed? */
-       hwif->mate = mate;
 
-       mate->chipset = ide_ht6560b;
        mate->selectproc = &ht6560b_selectproc;
-       mate->host_flags = IDE_HFLAG_ABUSE_PREFETCH;
-       mate->pio_mask = ATA_PIO5;
        mate->set_pio_mode = &ht6560b_set_pio_mode;
-       mate->serialized = 1;   /* is this needed? */
-       mate->mate = hwif;
-       mate->channel = 1;
-
-       /*
-        * Setting default configurations for drives
-        */
-       t = (HT_CONFIG_DEFAULT << 8);
-       t |= HT_TIMING_DEFAULT;
-       hwif->drives[0].drive_data = t;
-       hwif->drives[1].drive_data = t;
 
-       t |= (HT_SECONDARY_IF << 8);
-       mate->drives[0].drive_data = t;
-       mate->drives[1].drive_data = t;
+       hwif->port_init_devs = ht6560b_port_init_devs;
+       mate->port_init_devs = ht6560b_port_init_devs;
 
-       ide_device_add(idx);
+       ide_device_add(idx, &ht6560b_port_info);
 
        return 0;
 
index f4ea15b32969322d6e29dbd27a87f33dedff35c1..15ccf6944ae21565a3829e2ecdfcaea3d7c6080e 100644 (file)
@@ -2,8 +2,6 @@
 
     A driver for PCMCIA IDE/ATA disk cards
 
-    ide-cs.c 1.3 2002/10/26 05:45:31
-
     The contents of this file are subject to the Mozilla Public
     License Version 1.1 (the "License"); you may not use this file
     except in compliance with the License. You may obtain a copy of
@@ -147,13 +145,36 @@ static void ide_detach(struct pcmcia_device *link)
 
 static int idecs_register(unsigned long io, unsigned long ctl, unsigned long irq, struct pcmcia_device *handle)
 {
+    ide_hwif_t *hwif;
     hw_regs_t hw;
+    int i;
+    u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
+
     memset(&hw, 0, sizeof(hw));
-    ide_init_hwif_ports(&hw, io, ctl, NULL);
+    ide_std_init_ports(&hw, io, ctl);
     hw.irq = irq;
     hw.chipset = ide_pci;
     hw.dev = &handle->dev;
-    return ide_register_hw(&hw, &ide_undecoded_slave, NULL);
+
+    hwif = ide_deprecated_find_port(hw.io_ports[IDE_DATA_OFFSET]);
+    if (hwif == NULL)
+       return -1;
+
+    i = hwif->index;
+
+    if (hwif->present)
+       ide_unregister(i, 0, 0);
+    else if (!hwif->hold)
+       ide_init_port_data(hwif, i);
+
+    ide_init_port_hw(hwif, &hw);
+    hwif->quirkproc = &ide_undecoded_slave;
+
+    idx[0] = i;
+
+    ide_device_add(idx, NULL);
+
+    return hwif->present ? i : -1;
 }
 
 /*======================================================================
@@ -339,7 +360,7 @@ void ide_release(struct pcmcia_device *link)
     if (info->ndev) {
        /* FIXME: if this fails we need to queue the cleanup somehow
           -- need to investigate the required PCMCIA magic */
-       ide_unregister(info->hd);
+       ide_unregister(info->hd, 0, 0);
     }
     info->ndev = 0;
 
index 69a0fb0e564f9ee5c22af0c6c30cbcaf4f634a28..26c82ce602dedb7f3da016152b078428f64e899e 100644 (file)
 #include <linux/platform_device.h>
 #include <linux/io.h>
 
-static struct {
-       void __iomem *plat_ide_mapbase;
-       void __iomem *plat_ide_alt_mapbase;
-       ide_hwif_t *hwif;
-       int index;
-} hwif_prop;
-
 static void __devinit plat_ide_setup_ports(hw_regs_t *hw,
                                           void __iomem *base,
                                           void __iomem *ctrl,
@@ -54,6 +47,7 @@ static void __devinit plat_ide_setup_ports(hw_regs_t *hw,
 static int __devinit plat_ide_probe(struct platform_device *pdev)
 {
        struct resource *res_base, *res_alt, *res_irq;
+       void __iomem *base, *alt_base;
        ide_hwif_t *hwif;
        struct pata_platform_info *pdata;
        u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
@@ -84,27 +78,25 @@ static int __devinit plat_ide_probe(struct platform_device *pdev)
        }
 
        if (mmio) {
-               hwif_prop.plat_ide_mapbase = devm_ioremap(&pdev->dev,
+               base = devm_ioremap(&pdev->dev,
                        res_base->start, res_base->end - res_base->start + 1);
-               hwif_prop.plat_ide_alt_mapbase = devm_ioremap(&pdev->dev,
+               alt_base = devm_ioremap(&pdev->dev,
                        res_alt->start, res_alt->end - res_alt->start + 1);
        } else {
-               hwif_prop.plat_ide_mapbase = devm_ioport_map(&pdev->dev,
+               base = devm_ioport_map(&pdev->dev,
                        res_base->start, res_base->end - res_base->start + 1);
-               hwif_prop.plat_ide_alt_mapbase = devm_ioport_map(&pdev->dev,
+               alt_base = devm_ioport_map(&pdev->dev,
                        res_alt->start, res_alt->end - res_alt->start + 1);
        }
 
-       hwif = ide_find_port((unsigned long)hwif_prop.plat_ide_mapbase);
+       hwif = ide_find_port((unsigned long)base);
        if (!hwif) {
                ret = -ENODEV;
                goto out;
        }
 
        memset(&hw, 0, sizeof(hw));
-       plat_ide_setup_ports(&hw, hwif_prop.plat_ide_mapbase,
-                            hwif_prop.plat_ide_alt_mapbase,
-                            pdata, res_irq->start);
+       plat_ide_setup_ports(&hw, base, alt_base, pdata, res_irq->start);
        hw.dev = &pdev->dev;
 
        ide_init_port_hw(hwif, &hw);
@@ -114,12 +106,9 @@ static int __devinit plat_ide_probe(struct platform_device *pdev)
                default_hwif_mmiops(hwif);
        }
 
-       hwif_prop.hwif = hwif;
-       hwif_prop.index = hwif->index;
-
        idx[0] = hwif->index;
 
-       ide_device_add(idx);
+       ide_device_add(idx, NULL);
 
        platform_set_drvdata(pdev, hwif);
 
@@ -133,14 +122,7 @@ static int __devexit plat_ide_remove(struct platform_device *pdev)
 {
        ide_hwif_t *hwif = pdev->dev.driver_data;
 
-       if (hwif != hwif_prop.hwif) {
-               dev_printk(KERN_DEBUG, &pdev->dev, "%s: hwif value error",
-                          pdev->name);
-       } else {
-               ide_unregister(hwif_prop.index);
-               hwif_prop.index = 0;
-               hwif_prop.hwif = NULL;
-       }
+       ide_unregister(hwif->index, 0, 0);
 
        return 0;
 }
index 782d4c76c0e578f607fdf20635838d8191db7b1d..a61e60737dc70d658c74eb060a6cc678a9a41a8f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/ide/legacy/macide.c -- Macintosh IDE Driver
+ *  Macintosh IDE Driver
  *
  *     Copyright (C) 1998 by Michael Schmitz
  *
  * These match MkLinux so they should be correct.
  */
 
-#define IDE_DATA       0x00
-#define IDE_ERROR      0x04    /* see err-bits */
-#define IDE_NSECTOR    0x08    /* nr of sectors to read/write */
-#define IDE_SECTOR     0x0c    /* starting sector */
-#define IDE_LCYL       0x10    /* starting cylinder */
-#define IDE_HCYL       0x14    /* high byte of starting cyl */
-#define IDE_SELECT     0x18    /* 101dhhhh , d=drive, hhhh=head */
-#define IDE_STATUS     0x1c    /* see status-bits */
 #define IDE_CONTROL    0x38    /* control/altstatus */
 
 /*
 
 volatile unsigned char *ide_ifr = (unsigned char *) (IDE_BASE + IDE_IFR);
 
-static int macide_offsets[IDE_NR_PORTS] = {
-    IDE_DATA, IDE_ERROR,  IDE_NSECTOR, IDE_SECTOR, IDE_LCYL,
-    IDE_HCYL, IDE_SELECT, IDE_STATUS,  IDE_CONTROL
-};
-
 int macide_ack_intr(ide_hwif_t* hwif)
 {
        if (*ide_ifr & 0x20) {
@@ -77,6 +64,22 @@ int macide_ack_intr(ide_hwif_t* hwif)
        return 0;
 }
 
+static void __init macide_setup_ports(hw_regs_t *hw, unsigned long base,
+                                     int irq, ide_ack_intr_t *ack_intr)
+{
+       int i;
+
+       memset(hw, 0, sizeof(*hw));
+
+       for (i = 0; i < 8; i++)
+               hw->io_ports[i] = base + i * 4;
+
+       hw->io_ports[IDE_CONTROL_OFFSET] = IDE_CONTROL;
+
+       hw->irq = irq;
+       hw->ack_intr = ack_intr;
+}
+
 static const char *mac_ide_name[] =
        { "Quadra", "Powerbook", "Powerbook Baboon" };
 
@@ -86,27 +89,27 @@ static const char *mac_ide_name[] =
 
 static int __init macide_init(void)
 {
-       hw_regs_t hw;
        ide_hwif_t *hwif;
+       ide_ack_intr_t *ack_intr;
+       unsigned long base;
+       int irq;
+       hw_regs_t hw;
 
        switch (macintosh_config->ide_type) {
        case MAC_IDE_QUADRA:
-               ide_setup_ports(&hw, IDE_BASE, macide_offsets,
-                               0, 0, macide_ack_intr,
-//                             quadra_ide_iops,
-                               IRQ_NUBUS_F);
+               base = IDE_BASE;
+               ack_intr = macide_ack_intr;
+               irq = IRQ_NUBUS_F;
                break;
        case MAC_IDE_PB:
-               ide_setup_ports(&hw, IDE_BASE, macide_offsets,
-                               0, 0, macide_ack_intr,
-//                             macide_pb_iops,
-                               IRQ_NUBUS_C);
+               base = IDE_BASE;
+               ack_intr = macide_ack_intr;
+               irq = IRQ_NUBUS_C;
                break;
        case MAC_IDE_BABOON:
-               ide_setup_ports(&hw, BABOON_BASE, macide_offsets,
-                               0, 0, NULL,
-//                             macide_baboon_iops,
-                               IRQ_BABOON_1);
+               base = BABOON_BASE;
+               ack_intr = NULL;
+               irq = IRQ_BABOON_1;
                break;
        default:
                return -ENODEV;
@@ -115,6 +118,8 @@ static int __init macide_init(void)
        printk(KERN_INFO "ide: Macintosh %s IDE controller\n",
                         mac_ide_name[macintosh_config->ide_type - 1]);
 
+       macide_setup_ports(&hw, base, irq, ack_intr);
+
        hwif = ide_find_port(hw.io_ports[IDE_DATA_OFFSET]);
        if (hwif) {
                u8 index = hwif->index;
@@ -123,19 +128,9 @@ static int __init macide_init(void)
                ide_init_port_data(hwif, index);
                ide_init_port_hw(hwif, &hw);
 
-               if (macintosh_config->ide_type == MAC_IDE_BABOON &&
-                   macintosh_config->ident == MAC_MODEL_PB190) {
-                       /* Fix breakage in ide-disk.c: drive capacity   */
-                       /* is not initialized for drives without a      */
-                       /* hardware ID, and we can't get that without   */
-                       /* probing the drive which freezes a 190.       */
-                       ide_drive_t *drive = &hwif->drives[0];
-                       drive->capacity64 = drive->cyl*drive->head*drive->sect;
-               }
-
                hwif->mmio = 1;
 
-               ide_device_add(idx);
+               ide_device_add(idx, NULL);
        }
 
        return 0;
index f5329730df99d17bbd3abe5b2f05485c8e4d3db6..1381b91bc316e3982671bf281b2455ac7ff8c02b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/ide/legacy/q40ide.c -- Q40 I/O port IDE Driver
+ *  Q40 I/O port IDE Driver
  *
  *     (c) Richard Zidlicky
  *
@@ -66,16 +66,12 @@ static int q40ide_default_irq(unsigned long base)
 
 
 /*
- * This is very similar to ide_setup_ports except that addresses
- * are pretranslated for q40 ISA access
+ * Addresses are pretranslated for Q40 ISA access.
  */
 void q40_ide_setup_ports ( hw_regs_t *hw,
                        unsigned long base, int *offsets,
                        unsigned long ctrl, unsigned long intr,
                        ide_ack_intr_t *ack_intr,
-/*
- *                     ide_io_ops_t *iops,
- */
                        int irq)
 {
        int i;
@@ -92,9 +88,6 @@ void q40_ide_setup_ports ( hw_regs_t *hw,
 
        hw->irq = irq;
        hw->ack_intr = ack_intr;
-/*
- *     hw->iops = iops;
- */
 }
 
 
@@ -154,7 +147,7 @@ static int __init q40ide_init(void)
        }
     }
 
-    ide_device_add(idx);
+    ide_device_add(idx, NULL);
 
     return 0;
 }
index 2bac4c1a65324685a9cdd2b85ca318ef40b7b6fe..bba29df5f21d6094660c777724c38ef9d2de454b 100644 (file)
@@ -1,6 +1,4 @@
 /*
- *  linux/drivers/ide/legacy/qd65xx.c          Version 0.07    Sep 30, 2001
- *
  *  Copyright (C) 1996-2001  Linus Torvalds & author (see below)
  */
 
@@ -307,18 +305,33 @@ static int __init qd_testreg(int port)
  * called to setup an ata channel : adjusts attributes & links for tuning
  */
 
-static void __init qd_setup(ide_hwif_t *hwif, int base, int config,
-                           unsigned int data0, unsigned int data1)
+static void __init qd_setup(ide_hwif_t *hwif, int base, int config)
 {
-       hwif->chipset = ide_qd65xx;
-       hwif->channel = hwif->index;
        hwif->select_data = base;
        hwif->config_data = config;
-       hwif->drives[0].drive_data = data0;
-       hwif->drives[1].drive_data = data1;
-       hwif->drives[0].io_32bit =
-       hwif->drives[1].io_32bit = 1;
-       hwif->pio_mask = ATA_PIO4;
+}
+
+static void __init qd6500_port_init_devs(ide_hwif_t *hwif)
+{
+       u8 base = hwif->select_data, config = QD_CONFIG(hwif);
+
+       hwif->drives[0].drive_data = QD6500_DEF_DATA;
+       hwif->drives[1].drive_data = QD6500_DEF_DATA;
+}
+
+static void __init qd6580_port_init_devs(ide_hwif_t *hwif)
+{
+       u16 t1, t2;
+       u8 base = hwif->select_data, config = QD_CONFIG(hwif);
+
+       if (QD_CONTROL(hwif) & QD_CONTR_SEC_DISABLED) {
+               t1 = QD6580_DEF_DATA;
+               t2 = QD6580_DEF_DATA2;
+       } else
+               t2 = t1 = hwif->channel ? QD6580_DEF_DATA2 : QD6580_DEF_DATA;
+
+       hwif->drives[0].drive_data = t1;
+       hwif->drives[1].drive_data = t2;
 }
 
 /*
@@ -358,6 +371,14 @@ static void __exit qd_unsetup(ide_hwif_t *hwif)
 }
 */
 
+static const struct ide_port_info qd65xx_port_info __initdata = {
+       .chipset                = ide_qd65xx,
+       .host_flags             = IDE_HFLAG_IO_32BIT |
+                                 IDE_HFLAG_NO_DMA |
+                                 IDE_HFLAG_NO_AUTOTUNE,
+       .pio_mask               = ATA_PIO4,
+};
+
 /*
  * qd_probe:
  *
@@ -395,13 +416,14 @@ static int __init qd_probe(int base)
                        return 1;
                }
 
-               qd_setup(hwif, base, config, QD6500_DEF_DATA, QD6500_DEF_DATA);
+               qd_setup(hwif, base, config);
 
+               hwif->port_init_devs = qd6500_port_init_devs;
                hwif->set_pio_mode = &qd6500_set_pio_mode;
 
-               idx[0] = unit;
+               idx[unit] = unit;
 
-               ide_device_add(idx);
+               ide_device_add(idx, &qd65xx_port_info);
 
                return 1;
        }
@@ -428,14 +450,15 @@ static int __init qd_probe(int base)
                        hwif = &ide_hwifs[unit];
                        printk(KERN_INFO "%s: qd6580: single IDE board\n",
                                         hwif->name);
-                       qd_setup(hwif, base, config | (control << 8),
-                                QD6580_DEF_DATA, QD6580_DEF_DATA2);
 
+                       qd_setup(hwif, base, config | (control << 8));
+
+                       hwif->port_init_devs = qd6580_port_init_devs;
                        hwif->set_pio_mode = &qd6580_set_pio_mode;
 
-                       idx[0] = unit;
+                       idx[unit] = unit;
 
-                       ide_device_add(idx);
+                       ide_device_add(idx, &qd65xx_port_info);
 
                        outb(QD_DEF_CONTR, QD_CONTROL_PORT);
 
@@ -449,20 +472,20 @@ static int __init qd_probe(int base)
                        printk(KERN_INFO "%s&%s: qd6580: dual IDE board\n",
                                        hwif->name, mate->name);
 
-                       qd_setup(hwif, base, config | (control << 8),
-                                QD6580_DEF_DATA, QD6580_DEF_DATA);
+                       qd_setup(hwif, base, config | (control << 8));
 
+                       hwif->port_init_devs = qd6580_port_init_devs;
                        hwif->set_pio_mode = &qd6580_set_pio_mode;
 
-                       qd_setup(mate, base, config | (control << 8),
-                                QD6580_DEF_DATA2, QD6580_DEF_DATA2);
+                       qd_setup(mate, base, config | (control << 8));
 
+                       mate->port_init_devs = qd6580_port_init_devs;
                        mate->set_pio_mode = &qd6580_set_pio_mode;
 
                        idx[0] = 0;
                        idx[1] = 1;
 
-                       ide_device_add(idx);
+                       ide_device_add(idx, &qd65xx_port_info);
 
                        outb(QD_DEF_CONTR, QD_CONTROL_PORT);
 
index 633a42456ef6c03f12af41463ee5326a4e2ed7fe..28dd50a15d55af3ad1ccb566f04a76f28d8c9740 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * linux/drivers/ide/legacy/qd65xx.h
- *
  * Copyright (c) 2000  Linus Torvalds & authors
  */
 
index a1ae1ae6699d0ecc5e04878a0210304291afdb9d..5696ba026005359b0126acab59b48f27725f3ab9 100644 (file)
@@ -1,6 +1,4 @@
 /*
- *  linux/drivers/ide/legacy/umc8672.c         Version 0.05    Jul 31, 1996
- *
  *  Copyright (C) 1995-1996  Linus Torvalds & author (see below)
  */
 
@@ -122,9 +120,14 @@ static void umc_set_pio_mode(ide_drive_t *drive, const u8 pio)
        spin_unlock_irqrestore(&ide_lock, flags);
 }
 
+static const struct ide_port_info umc8672_port_info __initdata = {
+       .chipset                = ide_umc8672,
+       .host_flags             = IDE_HFLAG_NO_DMA | IDE_HFLAG_NO_AUTOTUNE,
+       .pio_mask               = ATA_PIO4,
+};
+
 static int __init umc8672_probe(void)
 {
-       ide_hwif_t *hwif, *mate;
        unsigned long flags;
        static u8 idx[4] = { 0, 1, 0xff, 0xff };
 
@@ -145,21 +148,10 @@ static int __init umc8672_probe(void)
        umc_set_speeds (current_speeds);
        local_irq_restore(flags);
 
-       hwif = &ide_hwifs[0];
-       mate = &ide_hwifs[1];
-
-       hwif->chipset = ide_umc8672;
-       hwif->pio_mask = ATA_PIO4;
-       hwif->set_pio_mode = &umc_set_pio_mode;
-       hwif->mate = mate;
-
-       mate->chipset = ide_umc8672;
-       mate->pio_mask = ATA_PIO4;
-       mate->set_pio_mode = &umc_set_pio_mode;
-       mate->mate = hwif;
-       mate->channel = 1;
+       ide_hwifs[0].set_pio_mode = &umc_set_pio_mode;
+       ide_hwifs[1].set_pio_mode = &umc_set_pio_mode;
 
-       ide_device_add(idx);
+       ide_device_add(idx, &umc8672_port_info);
 
        return 0;
 }
index 2d3e5115b83404db30e4d1a2fcd684fceaadd198..0f4bf5d7283598b20b7df331fc62a20085a1c03f 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * linux/drivers/ide/mips/au1xxx-ide.c  version 01.30.00        Aug. 02 2005
- *
  * BRIEF MODULE DESCRIPTION
  * AMD Alchemy Au1xxx IDE interface routines over the Static Bus
  *
@@ -50,7 +48,6 @@
 #include <asm/mach-au1x00/au1xxx_ide.h>
 
 #define DRV_NAME       "au1200-ide"
-#define DRV_VERSION    "1.0"
 #define DRV_AUTHOR     "Enrico Walther <enrico.walther@amd.com> / Pete Popov <ppopov@embeddedalley.com>"
 
 /* enable the burstmode in the dbdma */
@@ -209,24 +206,6 @@ static void auide_set_dma_mode(ide_drive_t *drive, const u8 speed)
  */
 
 #ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA
-
-static int auide_build_sglist(ide_drive_t *drive,  struct request *rq)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       _auide_hwif *ahwif = (_auide_hwif*)hwif->hwif_data;
-       struct scatterlist *sg = hwif->sg_table;
-
-       ide_map_sg(drive, rq);
-
-       if (rq_data_dir(rq) == READ)
-               hwif->sg_dma_direction = DMA_FROM_DEVICE;
-       else
-               hwif->sg_dma_direction = DMA_TO_DEVICE;
-
-       return dma_map_sg(ahwif->dev, sg, hwif->sg_nents,
-                         hwif->sg_dma_direction);
-}
-
 static int auide_build_dmatable(ide_drive_t *drive)
 {
        int i, iswrite, count = 0;
@@ -241,8 +220,7 @@ static int auide_build_dmatable(ide_drive_t *drive)
        /* Save for interrupt context */
        ahwif->drive = drive;
 
-       /* Build sglist */
-       hwif->sg_nents = i = auide_build_sglist(drive, rq);
+       hwif->sg_nents = i = ide_build_sglist(drive, rq);
 
        if (!i)
                return 0;
@@ -300,10 +278,7 @@ static int auide_build_dmatable(ide_drive_t *drive)
                return 1;
 
  use_pio_instead:
-       dma_unmap_sg(ahwif->dev,
-                    hwif->sg_table,
-                    hwif->sg_nents,
-                    hwif->sg_dma_direction);
+       ide_destroy_dmatable(drive);
 
        return 0; /* revert to PIO for this request */
 }
@@ -311,11 +286,9 @@ static int auide_build_dmatable(ide_drive_t *drive)
 static int auide_dma_end(ide_drive_t *drive)
 {
        ide_hwif_t *hwif = HWIF(drive);
-       _auide_hwif *ahwif = (_auide_hwif*)hwif->hwif_data;
 
        if (hwif->sg_nents) {
-               dma_unmap_sg(ahwif->dev, hwif->sg_table, hwif->sg_nents,
-                            hwif->sg_dma_direction);
+               ide_destroy_dmatable(drive);
                hwif->sg_nents = 0;
        }
 
@@ -504,7 +477,7 @@ static int auide_ddma_init(_auide_hwif *auide) {
        auide->rx_desc_head = (void*)au1xxx_dbdma_ring_alloc(auide->rx_chan,
                                                             NUM_DESCRIPTORS);
  
-       hwif->dmatable_cpu = dma_alloc_coherent(auide->dev,
+       hwif->dmatable_cpu = dma_alloc_coherent(hwif->dev,
                                                PRD_ENTRIES * PRD_BYTES,        /* 1 Page */
                                                &hwif->dmatable_dma, GFP_KERNEL);
        
@@ -575,6 +548,17 @@ static void auide_setup_ports(hw_regs_t *hw, _auide_hwif *ahwif)
        *ata_regs = ahwif->regbase + (14 << AU1XXX_ATA_REG_OFFSET);
 }
 
+static const struct ide_port_info au1xxx_port_info = {
+       .host_flags             = IDE_HFLAG_POST_SET_MODE |
+                                 IDE_HFLAG_NO_DMA | /* no SFF-style DMA */
+                                 IDE_HFLAG_NO_IO_32BIT |
+                                 IDE_HFLAG_UNMASK_IRQS,
+       .pio_mask               = ATA_PIO4,
+#ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA
+       .mwdma_mask             = ATA_MWDMA2,
+#endif
+};
+
 static int au_ide_probe(struct device *dev)
 {
        struct platform_device *pdev = to_platform_device(dev);
@@ -592,9 +576,6 @@ static int au_ide_probe(struct device *dev)
 #endif
 
        memset(&auide_hwif, 0, sizeof(_auide_hwif));
-       auide_hwif.dev                  = 0;
-
-       ahwif->dev = dev;
        ahwif->irq = platform_get_irq(pdev, 0);
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -629,24 +610,12 @@ static int au_ide_probe(struct device *dev)
        memset(&hw, 0, sizeof(hw));
        auide_setup_ports(&hw, ahwif);
        hw.irq = ahwif->irq;
+       hw.dev = dev;
        hw.chipset = ide_au1xxx;
 
        ide_init_port_hw(hwif, &hw);
 
-       hwif->ultra_mask                = 0x0;  /* Disable Ultra DMA */
-#ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA
-       hwif->mwdma_mask                = 0x07; /* Multimode-2 DMA  */
-       hwif->swdma_mask                = 0x00;
-#else
-       hwif->mwdma_mask                = 0x0;
-       hwif->swdma_mask                = 0x0;
-#endif
-
-       hwif->pio_mask = ATA_PIO4;
-       hwif->host_flags = IDE_HFLAG_POST_SET_MODE;
-
-       hwif->drives[0].unmask          = 1;
-       hwif->drives[1].unmask          = 1;
+       hwif->dev = dev;
 
        /* hold should be on in all cases */
        hwif->hold                      = 1;
@@ -678,16 +647,9 @@ static int au_ide_probe(struct device *dev)
        hwif->ide_dma_test_irq          = &auide_dma_test_irq;
        hwif->dma_lost_irq              = &auide_dma_lost_irq;
 #endif
-       hwif->channel                   = 0;
        hwif->select_data               = 0;    /* no chipset-specific code */
        hwif->config_data               = 0;    /* no chipset-specific code */
 
-       hwif->drives[0].autotune        = 1;    /* 1=autotune, 2=noautotune, 0=default */
-       hwif->drives[1].autotune        = 1;
-
-       hwif->drives[0].no_io_32bit     = 1;
-       hwif->drives[1].no_io_32bit     = 1;
-
        auide_hwif.hwif                 = hwif;
        hwif->hwif_data                 = &auide_hwif;
 
@@ -698,7 +660,7 @@ static int au_ide_probe(struct device *dev)
 
        idx[0] = hwif->index;
 
-       ide_device_add(idx);
+       ide_device_add(idx, &au1xxx_port_info);
 
        dev_set_drvdata(dev, hwif);
 
@@ -715,7 +677,7 @@ static int au_ide_remove(struct device *dev)
        ide_hwif_t *hwif = dev_get_drvdata(dev);
        _auide_hwif *ahwif = &auide_hwif;
 
-       ide_unregister(hwif - ide_hwifs);
+       ide_unregister(hwif->index, 0, 0);
 
        iounmap((void *)ahwif->regbase);
 
index 8b3959dfa2b7b692c806fd979890900065dbd20a..956259fc09ba079ced2db086cdf6fbf6a63fcab5 100644 (file)
@@ -129,7 +129,7 @@ static int __devinit swarm_ide_probe(struct device *dev)
 
        idx[0] = hwif->index;
 
-       ide_device_add(idx);
+       ide_device_add(idx, NULL);
 
        dev_set_drvdata(dev, hwif);
 
index 94803253e8af0268d1878833e7600d37035ace3a..02e6ee7d751defaad1fe96d081a881495ecceca5 100644 (file)
@@ -34,7 +34,8 @@ obj-$(CONFIG_BLK_DEV_TRM290)          += trm290.o
 obj-$(CONFIG_BLK_DEV_VIA82CXXX)                += via82cxxx.o
 
 # Must appear at the end of the block
-obj-$(CONFIG_BLK_DEV_GENERIC)          += generic.o
+obj-$(CONFIG_BLK_DEV_GENERIC)          += ide-pci-generic.o
+ide-pci-generic-y                      += generic.o
 
 ifeq ($(CONFIG_BLK_DEV_CMD640), m)
        obj-m += cmd640.o
index 7f4d1857d5559f73f5e3ceb6c7e975c79e4b28b6..cfb3265bc1a8764befa33b60ca8b5ed23057260b 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * linux/drivers/ide/pci/aec62xx.c             Version 0.27    Sep 16, 2007
- *
  * Copyright (C) 1999-2002     Andre Hedrick <andre@linux-ide.org>
  * Copyright (C) 2007          MontaVista Software, Inc. <source@mvista.com>
  *
@@ -9,7 +7,6 @@
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/pci.h>
-#include <linux/delay.h>
 #include <linux/hdreg.h>
 #include <linux/ide.h>
 #include <linux/init.h>
@@ -90,7 +87,7 @@ static u8 pci_bus_clock_list_ultra (u8 speed, struct chipset_bus_clock_list_entr
 static void aec6210_set_mode(ide_drive_t *drive, const u8 speed)
 {
        ide_hwif_t *hwif        = HWIF(drive);
-       struct pci_dev *dev     = hwif->pci_dev;
+       struct pci_dev *dev     = to_pci_dev(hwif->dev);
        u16 d_conf              = 0;
        u8 ultra = 0, ultra_conf = 0;
        u8 tmp0 = 0, tmp1 = 0, tmp2 = 0;
@@ -116,7 +113,7 @@ static void aec6210_set_mode(ide_drive_t *drive, const u8 speed)
 static void aec6260_set_mode(ide_drive_t *drive, const u8 speed)
 {
        ide_hwif_t *hwif        = HWIF(drive);
-       struct pci_dev *dev     = hwif->pci_dev;
+       struct pci_dev *dev     = to_pci_dev(hwif->dev);
        u8 unit         = (drive->select.b.unit & 0x01);
        u8 tmp1 = 0, tmp2 = 0;
        u8 ultra = 0, drive_conf = 0, ultra_conf = 0;
@@ -168,29 +165,28 @@ static unsigned int __devinit init_chipset_aec62xx(struct pci_dev *dev, const ch
        return dev->irq;
 }
 
+static u8 __devinit atp86x_cable_detect(ide_hwif_t *hwif)
+{
+       struct pci_dev *dev = to_pci_dev(hwif->dev);
+       u8 ata66 = 0, mask = hwif->channel ? 0x02 : 0x01;
+
+       pci_read_config_byte(dev, 0x49, &ata66);
+
+       return (ata66 & mask) ? ATA_CBL_PATA40 : ATA_CBL_PATA80;
+}
+
 static void __devinit init_hwif_aec62xx(ide_hwif_t *hwif)
 {
-       struct pci_dev *dev     = hwif->pci_dev;
+       struct pci_dev *dev = to_pci_dev(hwif->dev);
 
        hwif->set_pio_mode = &aec_set_pio_mode;
 
        if (dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF)
                hwif->set_dma_mode = &aec6210_set_mode;
-       else
+       else {
                hwif->set_dma_mode = &aec6260_set_mode;
 
-       if (hwif->dma_base == 0)
-               return;
-
-       if (dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF)
-               return;
-
-       if (hwif->cbl != ATA_CBL_PATA40_SHORT) {
-               u8 ata66 = 0, mask = hwif->channel ? 0x02 : 0x01;
-
-               pci_read_config_byte(hwif->pci_dev, 0x49, &ata66);
-
-               hwif->cbl = (ata66 & mask) ? ATA_CBL_PATA40 : ATA_CBL_PATA80;
+               hwif->cable_detect = atp86x_cable_detect;
        }
 }
 
@@ -202,6 +198,7 @@ static const struct ide_port_info aec62xx_chipsets[] __devinitdata = {
                .enablebits     = {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
                .host_flags     = IDE_HFLAG_SERIALIZE |
                                  IDE_HFLAG_NO_ATAPI_DMA |
+                                 IDE_HFLAG_NO_DSC |
                                  IDE_HFLAG_ABUSE_SET_DMA_MODE |
                                  IDE_HFLAG_OFF_BOARD,
                .pio_mask       = ATA_PIO4,
index 49aa82e412b6ed1da3fb40b3d2291501a92b232a..b3b6f514ce2d8ac4d5775ebddb353f4907ca4460 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * linux/drivers/ide/pci/alim15x3.c            Version 0.29    Sep 16 2007
- *
  *  Copyright (C) 1998-2000 Michel Aubry, Maintainer
  *  Copyright (C) 1998-2000 Andrzej Krzysztofowicz, Maintainer
  *  Copyright (C) 1999-2000 CJ, cjtsai@ali.com.tw, Maintainer
@@ -33,7 +31,6 @@
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/pci.h>
-#include <linux/delay.h>
 #include <linux/hdreg.h>
 #include <linux/ide.h>
 #include <linux/init.h>
@@ -293,7 +290,7 @@ static int ali_get_info (char *buffer, char **addr, off_t offset, int count)
 static void ali_set_pio_mode(ide_drive_t *drive, const u8 pio)
 {
        ide_hwif_t *hwif = HWIF(drive);
-       struct pci_dev *dev = hwif->pci_dev;
+       struct pci_dev *dev = to_pci_dev(hwif->dev);
        int s_time, a_time, c_time;
        u8 s_clc, a_clc, r_clc;
        unsigned long flags;
@@ -396,7 +393,7 @@ static u8 ali_udma_filter(ide_drive_t *drive)
 static void ali_set_dma_mode(ide_drive_t *drive, const u8 speed)
 {
        ide_hwif_t *hwif        = HWIF(drive);
-       struct pci_dev *dev     = hwif->pci_dev;
+       struct pci_dev *dev     = to_pci_dev(hwif->dev);
        u8 speed1               = speed;
        u8 unit                 = (drive->select.b.unit & 0x01);
        u8 tmpbyte              = 0x00;
@@ -625,7 +622,7 @@ static int ali_cable_override(struct pci_dev *pdev)
 
 static u8 __devinit ata66_ali15x3(ide_hwif_t *hwif)
 {
-       struct pci_dev *dev     = hwif->pci_dev;
+       struct pci_dev *dev = to_pci_dev(hwif->dev);
        unsigned long flags;
        u8 cbl = ATA_CBL_PATA40, tmpbyte;
 
@@ -668,13 +665,12 @@ static void __devinit init_hwif_common_ali15x3 (ide_hwif_t *hwif)
        hwif->set_dma_mode = &ali_set_dma_mode;
        hwif->udma_filter = &ali_udma_filter;
 
+       hwif->cable_detect = ata66_ali15x3;
+
        if (hwif->dma_base == 0)
                return;
 
        hwif->dma_setup = &ali15x3_dma_setup;
-
-       if (hwif->cbl != ATA_CBL_PATA40_SHORT)
-               hwif->cbl = ata66_ali15x3(hwif);
 }
 
 /**
@@ -688,12 +684,13 @@ static void __devinit init_hwif_common_ali15x3 (ide_hwif_t *hwif)
 
 static void __devinit init_hwif_ali15x3 (ide_hwif_t *hwif)
 {
+       struct pci_dev *dev = to_pci_dev(hwif->dev);
        u8 ideic, inmir;
        s8 irq_routing_table[] = { -1,  9, 3, 10, 4,  5, 7,  6,
                                      1, 11, 0, 12, 0, 14, 0, 15 };
        int irq = -1;
 
-       if (hwif->pci_dev->device == PCI_DEVICE_ID_AL_M5229)
+       if (dev->device == PCI_DEVICE_ID_AL_M5229)
                hwif->irq = hwif->channel ? 15 : 14;
 
        if (isa_dev) {
@@ -745,7 +742,7 @@ static void __devinit init_dma_ali15x3 (ide_hwif_t *hwif, unsigned long dmabase)
                return;
        if (!hwif->channel)
                outb(inb(dmabase + 2) & 0x60, dmabase + 2);
-       ide_setup_dma(hwif, dmabase, 8);
+       ide_setup_dma(hwif, dmabase);
 }
 
 static const struct ide_port_info ali15x3_chipset __devinitdata = {
@@ -775,7 +772,7 @@ static int __devinit alim15x3_init_one(struct pci_dev *dev, const struct pci_dev
        };
 
        struct ide_port_info d = ali15x3_chipset;
-       u8 rev = dev->revision;
+       u8 rev = dev->revision, idx = id->driver_data;
 
        if (pci_dev_present(ati_rs100))
                printk(KERN_WARNING "alim15x3: ATI Radeon IGP Northbridge is not yet fully tested.\n");
@@ -798,6 +795,9 @@ static int __devinit alim15x3_init_one(struct pci_dev *dev, const struct pci_dev
                        d.udma_mask = ATA_UDMA6;
        }
 
+       if (idx == 0)
+               d.host_flags |= IDE_HFLAG_CLEAR_SIMPLEX;
+
 #if defined(CONFIG_SPARC64)
        d.init_hwif = init_hwif_common_ali15x3;
 #endif /* CONFIG_SPARC64 */
@@ -807,7 +807,7 @@ static int __devinit alim15x3_init_one(struct pci_dev *dev, const struct pci_dev
 
 static const struct pci_device_id alim15x3_pci_tbl[] = {
        { PCI_VDEVICE(AL, PCI_DEVICE_ID_AL_M5229), 0 },
-       { PCI_VDEVICE(AL, PCI_DEVICE_ID_AL_M5228), 0 },
+       { PCI_VDEVICE(AL, PCI_DEVICE_ID_AL_M5228), 1 },
        { 0, },
 };
 MODULE_DEVICE_TABLE(pci, alim15x3_pci_tbl);
index cee51fdafcf6f5353369b9601b99b7c812fff31d..2ef890ce80976fa83e6667f80ade5689df0899dc 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * Version 2.24
- *
  * AMD 755/756/766/8111 and nVidia nForce/2/2s/3/3s/CK804/MCP04
  * IDE driver for Linux.
  *
 
 #include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
 #include <linux/pci.h>
 #include <linux/init.h>
 #include <linux/ide.h>
-#include <asm/io.h>
 
 #include "ide-timing.h"
 
-#define AMD_IDE_CONFIG         (0x01 + amd_config->base)
-#define AMD_CABLE_DETECT       (0x02 + amd_config->base)
-#define AMD_DRIVE_TIMING       (0x08 + amd_config->base)
-#define AMD_8BIT_TIMING                (0x0e + amd_config->base)
-#define AMD_ADDRESS_SETUP      (0x0c + amd_config->base)
-#define AMD_UDMA_TIMING                (0x10 + amd_config->base)
-
-#define AMD_CHECK_SWDMA                0x08
-#define AMD_BAD_SWDMA          0x10
-#define AMD_BAD_FIFO           0x20
-#define AMD_CHECK_SERENADE     0x40
-
-/*
- * AMD SouthBridge chips.
- */
-
-static struct amd_ide_chip {
-       unsigned short id;
-       u8 base;
-       u8 udma_mask;
-       u8 flags;
-} amd_ide_chips[] = {
-       { PCI_DEVICE_ID_AMD_COBRA_7401,          0x40, ATA_UDMA2, AMD_BAD_SWDMA },
-       { PCI_DEVICE_ID_AMD_VIPER_7409,          0x40, ATA_UDMA4, AMD_CHECK_SWDMA },
-       { PCI_DEVICE_ID_AMD_VIPER_7411,          0x40, ATA_UDMA5, AMD_BAD_FIFO },
-       { PCI_DEVICE_ID_AMD_OPUS_7441,           0x40, ATA_UDMA5, },
-       { PCI_DEVICE_ID_AMD_8111_IDE,            0x40, ATA_UDMA6, AMD_CHECK_SERENADE },
-       { PCI_DEVICE_ID_NVIDIA_NFORCE_IDE,       0x50, ATA_UDMA5, },
-       { PCI_DEVICE_ID_NVIDIA_NFORCE2_IDE,      0x50, ATA_UDMA6, },
-       { PCI_DEVICE_ID_NVIDIA_NFORCE2S_IDE,     0x50, ATA_UDMA6, },
-       { PCI_DEVICE_ID_NVIDIA_NFORCE2S_SATA,    0x50, ATA_UDMA6, },
-       { PCI_DEVICE_ID_NVIDIA_NFORCE3_IDE,      0x50, ATA_UDMA6, },
-       { PCI_DEVICE_ID_NVIDIA_NFORCE3S_IDE,     0x50, ATA_UDMA6, },
-       { PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA,    0x50, ATA_UDMA6, },
-       { PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA2,   0x50, ATA_UDMA6, },
-       { PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_IDE, 0x50, ATA_UDMA6, },
-       { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_IDE, 0x50, ATA_UDMA6, },
-       { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_IDE, 0x50, ATA_UDMA6, },
-       { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_IDE, 0x50, ATA_UDMA6, },
-       { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_IDE, 0x50, ATA_UDMA6, },
-       { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP65_IDE, 0x50, ATA_UDMA6, },
-       { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP67_IDE, 0x50, ATA_UDMA6, },
-       { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP73_IDE, 0x50, ATA_UDMA6, },
-       { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP77_IDE, 0x50, ATA_UDMA6, },
-       { PCI_DEVICE_ID_AMD_CS5536_IDE,          0x40, ATA_UDMA5, },
-       { 0 }
+enum {
+       AMD_IDE_CONFIG          = 0x41,
+       AMD_CABLE_DETECT        = 0x42,
+       AMD_DRIVE_TIMING        = 0x48,
+       AMD_8BIT_TIMING         = 0x4e,
+       AMD_ADDRESS_SETUP       = 0x4c,
+       AMD_UDMA_TIMING         = 0x50,
 };
 
-static struct amd_ide_chip *amd_config;
-static const struct ide_port_info *amd_chipset;
 static unsigned int amd_80w;
 static unsigned int amd_clock;
 
 static char *amd_dma[] = { "16", "25", "33", "44", "66", "100", "133" };
 static unsigned char amd_cyc2udma[] = { 6, 6, 5, 4, 0, 1, 1, 2, 2, 3, 3, 3, 3, 3, 3, 7 };
 
+static inline u8 amd_offset(struct pci_dev *dev)
+{
+       return (dev->vendor == PCI_VENDOR_ID_NVIDIA) ? 0x10 : 0;
+}
+
 /*
  * amd_set_speed() writes timing values to the chipset registers
  */
 
-static void amd_set_speed(struct pci_dev *dev, unsigned char dn, struct ide_timing *timing)
+static void amd_set_speed(struct pci_dev *dev, u8 dn, u8 udma_mask,
+                         struct ide_timing *timing)
 {
-       unsigned char t;
+       u8 t = 0, offset = amd_offset(dev);
 
-       pci_read_config_byte(dev, AMD_ADDRESS_SETUP, &t);
+       pci_read_config_byte(dev, AMD_ADDRESS_SETUP + offset, &t);
        t = (t & ~(3 << ((3 - dn) << 1))) | ((FIT(timing->setup, 1, 4) - 1) << ((3 - dn) << 1));
-       pci_write_config_byte(dev, AMD_ADDRESS_SETUP, t);
+       pci_write_config_byte(dev, AMD_ADDRESS_SETUP + offset, t);
 
-       pci_write_config_byte(dev, AMD_8BIT_TIMING + (1 - (dn >> 1)),
+       pci_write_config_byte(dev, AMD_8BIT_TIMING + offset + (1 - (dn >> 1)),
                ((FIT(timing->act8b, 1, 16) - 1) << 4) | (FIT(timing->rec8b, 1, 16) - 1));
 
-       pci_write_config_byte(dev, AMD_DRIVE_TIMING + (3 - dn),
+       pci_write_config_byte(dev, AMD_DRIVE_TIMING + offset + (3 - dn),
                ((FIT(timing->active, 1, 16) - 1) << 4) | (FIT(timing->recover, 1, 16) - 1));
 
-       switch (amd_config->udma_mask) {
+       switch (udma_mask) {
        case ATA_UDMA2: t = timing->udma ? (0xc0 | (FIT(timing->udma, 2, 5) - 2)) : 0x03; break;
        case ATA_UDMA4: t = timing->udma ? (0xc0 | amd_cyc2udma[FIT(timing->udma, 2, 10)]) : 0x03; break;
        case ATA_UDMA5: t = timing->udma ? (0xc0 | amd_cyc2udma[FIT(timing->udma, 1, 10)]) : 0x03; break;
@@ -110,7 +70,7 @@ static void amd_set_speed(struct pci_dev *dev, unsigned char dn, struct ide_timi
        default: return;
        }
 
-       pci_write_config_byte(dev, AMD_UDMA_TIMING + (3 - dn), t);
+       pci_write_config_byte(dev, AMD_UDMA_TIMING + offset + (3 - dn), t);
 }
 
 /*
@@ -120,12 +80,15 @@ static void amd_set_speed(struct pci_dev *dev, unsigned char dn, struct ide_timi
 
 static void amd_set_drive(ide_drive_t *drive, const u8 speed)
 {
-       ide_drive_t *peer = HWIF(drive)->drives + (~drive->dn & 1);
+       ide_hwif_t *hwif = drive->hwif;
+       struct pci_dev *dev = to_pci_dev(hwif->dev);
+       ide_drive_t *peer = hwif->drives + (~drive->dn & 1);
        struct ide_timing t, p;
        int T, UT;
+       u8 udma_mask = hwif->ultra_mask;
 
        T = 1000000000 / amd_clock;
-       UT = (amd_config->udma_mask == ATA_UDMA2) ? T : (T / 2);
+       UT = (udma_mask == ATA_UDMA2) ? T : (T / 2);
 
        ide_timing_compute(drive, speed, &t, T, UT);
 
@@ -137,7 +100,7 @@ static void amd_set_drive(ide_drive_t *drive, const u8 speed)
        if (speed == XFER_UDMA_5 && amd_clock <= 33333) t.udma = 1;
        if (speed == XFER_UDMA_6 && amd_clock <= 33333) t.udma = 15;
 
-       amd_set_speed(HWIF(drive)->pci_dev, drive->dn, &t);
+       amd_set_speed(dev, drive->dn, udma_mask, &t);
 }
 
 /*
@@ -149,67 +112,68 @@ static void amd_set_pio_mode(ide_drive_t *drive, const u8 pio)
        amd_set_drive(drive, XFER_PIO_0 + pio);
 }
 
-/*
- * The initialization callback. Here we determine the IDE chip type
- * and initialize its drive independent registers.
- */
+static void __devinit amd7409_cable_detect(struct pci_dev *dev,
+                                          const char *name)
+{
+       /* no host side cable detection */
+       amd_80w = 0x03;
+}
 
-static unsigned int __devinit init_chipset_amd74xx(struct pci_dev *dev, const char *name)
+static void __devinit amd7411_cable_detect(struct pci_dev *dev,
+                                          const char *name)
 {
-       unsigned char t;
-       unsigned int u;
        int i;
+       u32 u = 0;
+       u8 t = 0, offset = amd_offset(dev);
+
+       pci_read_config_byte(dev, AMD_CABLE_DETECT + offset, &t);
+       pci_read_config_dword(dev, AMD_UDMA_TIMING + offset, &u);
+       amd_80w = ((t & 0x3) ? 1 : 0) | ((t & 0xc) ? 2 : 0);
+       for (i = 24; i >= 0; i -= 8)
+               if (((u >> i) & 4) && !(amd_80w & (1 << (1 - (i >> 4))))) {
+                       printk(KERN_WARNING "%s: BIOS didn't set cable bits "
+                                           "correctly. Enabling workaround.\n",
+                                           name);
+                       amd_80w |= (1 << (1 - (i >> 4)));
+               }
+}
 
 /*
- * Check for bad SWDMA.
+ * The initialization callback.  Initialize drive independent registers.
  */
 
-       if (amd_config->flags & AMD_CHECK_SWDMA) {
-               if (dev->revision <= 7)
-                       amd_config->flags |= AMD_BAD_SWDMA;
-       }
+static unsigned int __devinit init_chipset_amd74xx(struct pci_dev *dev,
+                                                  const char *name)
+{
+       u8 t = 0, offset = amd_offset(dev);
 
 /*
  * Check 80-wire cable presence.
  */
 
-       switch (amd_config->udma_mask) {
-
-               case ATA_UDMA6:
-               case ATA_UDMA5:
-                       pci_read_config_byte(dev, AMD_CABLE_DETECT, &t);
-                       pci_read_config_dword(dev, AMD_UDMA_TIMING, &u);
-                       amd_80w = ((t & 0x3) ? 1 : 0) | ((t & 0xc) ? 2 : 0);
-                       for (i = 24; i >= 0; i -= 8)
-                               if (((u >> i) & 4) && !(amd_80w & (1 << (1 - (i >> 4))))) {
-                                       printk(KERN_WARNING "%s: BIOS didn't set cable bits correctly. Enabling workaround.\n",
-                                               amd_chipset->name);
-                                       amd_80w |= (1 << (1 - (i >> 4)));
-                               }
-                       break;
-
-               case ATA_UDMA4:
-                       /* no host side cable detection */
-                       amd_80w = 0x03;
-                       break;
-       }
+       if (dev->vendor == PCI_VENDOR_ID_AMD &&
+           dev->device == PCI_DEVICE_ID_AMD_COBRA_7401)
+               ; /* no UDMA > 2 */
+       else if (dev->vendor == PCI_VENDOR_ID_AMD &&
+                dev->device == PCI_DEVICE_ID_AMD_VIPER_7409)
+               amd7409_cable_detect(dev, name);
+       else
+               amd7411_cable_detect(dev, name);
 
 /*
  * Take care of prefetch & postwrite.
  */
 
-       pci_read_config_byte(dev, AMD_IDE_CONFIG, &t);
-       pci_write_config_byte(dev, AMD_IDE_CONFIG,
-               (amd_config->flags & AMD_BAD_FIFO) ? (t & 0x0f) : (t | 0xf0));
-
-/*
- * Take care of incorrectly wired Serenade mainboards.
- */
-
-       if ((amd_config->flags & AMD_CHECK_SERENADE) &&
-               dev->subsystem_vendor == PCI_VENDOR_ID_AMD &&
-               dev->subsystem_device == PCI_DEVICE_ID_AMD_SERENADE)
-                       amd_config->udma_mask = ATA_UDMA5;
+       pci_read_config_byte(dev, AMD_IDE_CONFIG + offset, &t);
+       /*
+        * Check for broken FIFO support.
+        */
+       if (dev->vendor == PCI_VENDOR_ID_AMD &&
+           dev->vendor == PCI_DEVICE_ID_AMD_VIPER_7411)
+               t &= 0x0f;
+       else
+               t |= 0xf0;
+       pci_write_config_byte(dev, AMD_IDE_CONFIG + offset, t);
 
 /*
  * Determine the system bus clock.
@@ -225,42 +189,32 @@ static unsigned int __devinit init_chipset_amd74xx(struct pci_dev *dev, const ch
 
        if (amd_clock < 20000 || amd_clock > 50000) {
                printk(KERN_WARNING "%s: User given PCI clock speed impossible (%d), using 33 MHz instead.\n",
-                       amd_chipset->name, amd_clock);
+                                   name, amd_clock);
                amd_clock = 33333;
        }
 
-/*
- * Print the boot message.
- */
-
-       printk(KERN_INFO "%s: %s (rev %02x) UDMA%s controller\n",
-               amd_chipset->name, pci_name(dev), dev->revision,
-               amd_dma[fls(amd_config->udma_mask) - 1]);
-
        return dev->irq;
 }
 
+static u8 __devinit amd_cable_detect(ide_hwif_t *hwif)
+{
+       if ((amd_80w >> hwif->channel) & 1)
+               return ATA_CBL_PATA80;
+       else
+               return ATA_CBL_PATA40;
+}
+
 static void __devinit init_hwif_amd74xx(ide_hwif_t *hwif)
 {
+       struct pci_dev *dev = to_pci_dev(hwif->dev);
+
        if (hwif->irq == 0) /* 0 is bogus but will do for now */
-               hwif->irq = pci_get_legacy_ide_irq(hwif->pci_dev, hwif->channel);
+               hwif->irq = pci_get_legacy_ide_irq(dev, hwif->channel);
 
        hwif->set_pio_mode = &amd_set_pio_mode;
        hwif->set_dma_mode = &amd_set_drive;
 
-       if (!hwif->dma_base)
-               return;
-
-       hwif->ultra_mask = amd_config->udma_mask;
-       if (amd_config->flags & AMD_BAD_SWDMA)
-               hwif->swdma_mask = 0x00;
-
-       if (hwif->cbl != ATA_CBL_PATA40_SHORT) {
-               if ((amd_80w >> hwif->channel) & 1)
-                       hwif->cbl = ATA_CBL_PATA80;
-               else
-                       hwif->cbl = ATA_CBL_PATA40;
-       }
+       hwif->cable_detect = amd_cable_detect;
 }
 
 #define IDE_HFLAGS_AMD \
@@ -272,7 +226,7 @@ static void __devinit init_hwif_amd74xx(ide_hwif_t *hwif)
         IDE_HFLAG_UNMASK_IRQS | \
         IDE_HFLAG_BOOTABLE)
 
-#define DECLARE_AMD_DEV(name_str)                                      \
+#define DECLARE_AMD_DEV(name_str, swdma, udma)                         \
        {                                                               \
                .name           = name_str,                             \
                .init_chipset   = init_chipset_amd74xx,                 \
@@ -280,11 +234,12 @@ static void __devinit init_hwif_amd74xx(ide_hwif_t *hwif)
                .enablebits     = {{0x40,0x02,0x02}, {0x40,0x01,0x01}}, \
                .host_flags     = IDE_HFLAGS_AMD,                       \
                .pio_mask       = ATA_PIO5,                             \
-               .swdma_mask     = ATA_SWDMA2,                           \
+               .swdma_mask     = swdma,                                \
                .mwdma_mask     = ATA_MWDMA2,                           \
+               .udma_mask      = udma,                                 \
        }
 
-#define DECLARE_NV_DEV(name_str)                                       \
+#define DECLARE_NV_DEV(name_str, udma)                                 \
        {                                                               \
                .name           = name_str,                             \
                .init_chipset   = init_chipset_amd74xx,                 \
@@ -294,45 +249,62 @@ static void __devinit init_hwif_amd74xx(ide_hwif_t *hwif)
                .pio_mask       = ATA_PIO5,                             \
                .swdma_mask     = ATA_SWDMA2,                           \
                .mwdma_mask     = ATA_MWDMA2,                           \
+               .udma_mask      = udma,                                 \
        }
 
 static const struct ide_port_info amd74xx_chipsets[] __devinitdata = {
-       /*  0 */ DECLARE_AMD_DEV("AMD7401"),
-       /*  1 */ DECLARE_AMD_DEV("AMD7409"),
-       /*  2 */ DECLARE_AMD_DEV("AMD7411"),
-       /*  3 */ DECLARE_AMD_DEV("AMD7441"),
-       /*  4 */ DECLARE_AMD_DEV("AMD8111"),
-
-       /*  5 */ DECLARE_NV_DEV("NFORCE"),
-       /*  6 */ DECLARE_NV_DEV("NFORCE2"),
-       /*  7 */ DECLARE_NV_DEV("NFORCE2-U400R"),
-       /*  8 */ DECLARE_NV_DEV("NFORCE2-U400R-SATA"),
-       /*  9 */ DECLARE_NV_DEV("NFORCE3-150"),
-       /* 10 */ DECLARE_NV_DEV("NFORCE3-250"),
-       /* 11 */ DECLARE_NV_DEV("NFORCE3-250-SATA"),
-       /* 12 */ DECLARE_NV_DEV("NFORCE3-250-SATA2"),
-       /* 13 */ DECLARE_NV_DEV("NFORCE-CK804"),
-       /* 14 */ DECLARE_NV_DEV("NFORCE-MCP04"),
-       /* 15 */ DECLARE_NV_DEV("NFORCE-MCP51"),
-       /* 16 */ DECLARE_NV_DEV("NFORCE-MCP55"),
-       /* 17 */ DECLARE_NV_DEV("NFORCE-MCP61"),
-       /* 18 */ DECLARE_NV_DEV("NFORCE-MCP65"),
-       /* 19 */ DECLARE_NV_DEV("NFORCE-MCP67"),
-       /* 20 */ DECLARE_NV_DEV("NFORCE-MCP73"),
-       /* 21 */ DECLARE_NV_DEV("NFORCE-MCP77"),
-       /* 22 */ DECLARE_AMD_DEV("AMD5536"),
+       /*  0 */ DECLARE_AMD_DEV("AMD7401",       0x00, ATA_UDMA2),
+       /*  1 */ DECLARE_AMD_DEV("AMD7409", ATA_SWDMA2, ATA_UDMA4),
+       /*  2 */ DECLARE_AMD_DEV("AMD7411", ATA_SWDMA2, ATA_UDMA5),
+       /*  3 */ DECLARE_AMD_DEV("AMD7441", ATA_SWDMA2, ATA_UDMA5),
+       /*  4 */ DECLARE_AMD_DEV("AMD8111", ATA_SWDMA2, ATA_UDMA6),
+
+       /*  5 */ DECLARE_NV_DEV("NFORCE",               ATA_UDMA5),
+       /*  6 */ DECLARE_NV_DEV("NFORCE2",              ATA_UDMA6),
+       /*  7 */ DECLARE_NV_DEV("NFORCE2-U400R",        ATA_UDMA6),
+       /*  8 */ DECLARE_NV_DEV("NFORCE2-U400R-SATA",   ATA_UDMA6),
+       /*  9 */ DECLARE_NV_DEV("NFORCE3-150",          ATA_UDMA6),
+       /* 10 */ DECLARE_NV_DEV("NFORCE3-250",          ATA_UDMA6),
+       /* 11 */ DECLARE_NV_DEV("NFORCE3-250-SATA",     ATA_UDMA6),
+       /* 12 */ DECLARE_NV_DEV("NFORCE3-250-SATA2",    ATA_UDMA6),
+       /* 13 */ DECLARE_NV_DEV("NFORCE-CK804",         ATA_UDMA6),
+       /* 14 */ DECLARE_NV_DEV("NFORCE-MCP04",         ATA_UDMA6),
+       /* 15 */ DECLARE_NV_DEV("NFORCE-MCP51",         ATA_UDMA6),
+       /* 16 */ DECLARE_NV_DEV("NFORCE-MCP55",         ATA_UDMA6),
+       /* 17 */ DECLARE_NV_DEV("NFORCE-MCP61",         ATA_UDMA6),
+       /* 18 */ DECLARE_NV_DEV("NFORCE-MCP65",         ATA_UDMA6),
+       /* 19 */ DECLARE_NV_DEV("NFORCE-MCP67",         ATA_UDMA6),
+       /* 20 */ DECLARE_NV_DEV("NFORCE-MCP73",         ATA_UDMA6),
+       /* 21 */ DECLARE_NV_DEV("NFORCE-MCP77",         ATA_UDMA6),
+
+       /* 22 */ DECLARE_AMD_DEV("AMD5536", ATA_SWDMA2, ATA_UDMA5),
 };
 
 static int __devinit amd74xx_probe(struct pci_dev *dev, const struct pci_device_id *id)
 {
-       amd_chipset = amd74xx_chipsets + id->driver_data;
-       amd_config = amd_ide_chips + id->driver_data;
-       if (dev->device != amd_config->id) {
-               printk(KERN_ERR "%s: assertion 0x%02x == 0x%02x failed !\n",
-                      pci_name(dev), dev->device, amd_config->id);
-               return -ENODEV;
+       struct ide_port_info d;
+       u8 idx = id->driver_data;
+
+       d = amd74xx_chipsets[idx];
+
+       /*
+        * Check for bad SWDMA and incorrectly wired Serenade mainboards.
+        */
+       if (idx == 1) {
+               if (dev->revision <= 7)
+                       d.swdma_mask = 0;
+               d.host_flags |= IDE_HFLAG_CLEAR_SIMPLEX;
+       } else if (idx == 4) {
+               if (dev->subsystem_vendor == PCI_VENDOR_ID_AMD &&
+                   dev->subsystem_device == PCI_DEVICE_ID_AMD_SERENADE)
+                       d.udma_mask = ATA_UDMA5;
        }
-       return ide_setup_pci_device(dev, amd_chipset);
+
+       printk(KERN_INFO "%s: %s (rev %02x) UDMA%s controller\n",
+                        d.name, pci_name(dev), dev->revision,
+                        amd_dma[fls(d.udma_mask) - 1]);
+
+       return ide_setup_pci_device(dev, &d);
 }
 
 static const struct pci_device_id amd74xx_pci_tbl[] = {
index 491871984aaa71213e2820706c8201fea9c2faf2..7e037c880cb0a62279f22dfc4654ef05ab446982 100644 (file)
@@ -1,6 +1,4 @@
 /*
- *  linux/drivers/ide/pci/atiixp.c     Version 0.05    Nov 9 2007
- *
  *  Copyright (C) 2003 ATI Inc. <hyu@ati.com>
  *  Copyright (C) 2004,2007 Bartlomiej Zolnierkiewicz
  */
@@ -8,15 +6,11 @@
 #include <linux/types.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/ioport.h>
 #include <linux/pci.h>
 #include <linux/hdreg.h>
 #include <linux/ide.h>
-#include <linux/delay.h>
 #include <linux/init.h>
 
-#include <asm/io.h>
-
 #define ATIIXP_IDE_PIO_TIMING          0x40
 #define ATIIXP_IDE_MDMA_TIMING         0x44
 #define ATIIXP_IDE_PIO_CONTROL         0x48
@@ -55,7 +49,7 @@ static DEFINE_SPINLOCK(atiixp_lock);
 
 static void atiixp_set_pio_mode(ide_drive_t *drive, const u8 pio)
 {
-       struct pci_dev *dev = drive->hwif->pci_dev;
+       struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
        unsigned long flags;
        int timing_shift = (drive->dn & 2) ? 16 : 0 + (drive->dn & 1) ? 0 : 8;
        u32 pio_timing_data;
@@ -88,7 +82,7 @@ static void atiixp_set_pio_mode(ide_drive_t *drive, const u8 pio)
 
 static void atiixp_set_dma_mode(ide_drive_t *drive, const u8 speed)
 {
-       struct pci_dev *dev = drive->hwif->pci_dev;
+       struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
        unsigned long flags;
        int timing_shift = (drive->dn & 2) ? 16 : 0 + (drive->dn & 1) ? 0 : 8;
        u32 tmp32;
@@ -123,6 +117,19 @@ static void atiixp_set_dma_mode(ide_drive_t *drive, const u8 speed)
        spin_unlock_irqrestore(&atiixp_lock, flags);
 }
 
+static u8 __devinit atiixp_cable_detect(ide_hwif_t *hwif)
+{
+       struct pci_dev *pdev = to_pci_dev(hwif->dev);
+       u8 udma_mode = 0, ch = hwif->channel;
+
+       pci_read_config_byte(pdev, ATIIXP_IDE_UDMA_MODE + ch, &udma_mode);
+
+       if ((udma_mode & 0x07) >= 0x04 || (udma_mode & 0x70) >= 0x40)
+               return ATA_CBL_PATA80;
+       else
+               return ATA_CBL_PATA40;
+}
+
 /**
  *     init_hwif_atiixp                -       fill in the hwif for the ATIIXP
  *     @hwif: IDE interface
@@ -133,22 +140,10 @@ static void atiixp_set_dma_mode(ide_drive_t *drive, const u8 speed)
 
 static void __devinit init_hwif_atiixp(ide_hwif_t *hwif)
 {
-       u8 udma_mode = 0;
-       u8 ch = hwif->channel;
-       struct pci_dev *pdev = hwif->pci_dev;
-
        hwif->set_pio_mode = &atiixp_set_pio_mode;
        hwif->set_dma_mode = &atiixp_set_dma_mode;
 
-       if (!hwif->dma_base)
-               return;
-
-       pci_read_config_byte(pdev, ATIIXP_IDE_UDMA_MODE + ch, &udma_mode);
-
-       if ((udma_mode & 0x07) >= 0x04 || (udma_mode & 0x70) >= 0x40)
-               hwif->cbl = ATA_CBL_PATA80;
-       else
-               hwif->cbl = ATA_CBL_PATA40;
+       hwif->cable_detect = atiixp_cable_detect;
 }
 
 static const struct ide_port_info atiixp_pci_info[] __devinitdata = {
index da3565e0071f417628d96fa806daa29c9876cd4a..bd24dad3cfc6b2a82c990120ff7e10ac567599ab 100644 (file)
@@ -1,6 +1,4 @@
 /*
- *  linux/drivers/ide/pci/cmd640.c             Version 1.02  Sep 01, 1996
- *
  *  Copyright (C) 1995-1996  Linus Torvalds & authors (see below)
  */
 
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
 #include <linux/hdreg.h>
 #include <linux/ide.h>
 #include <linux/init.h>
@@ -705,6 +699,18 @@ static int pci_conf2(void)
        return 0;
 }
 
+static const struct ide_port_info cmd640_port_info __initdata = {
+       .chipset                = ide_cmd640,
+       .host_flags             = IDE_HFLAG_SERIALIZE |
+                                 IDE_HFLAG_NO_DMA |
+                                 IDE_HFLAG_NO_AUTOTUNE |
+                                 IDE_HFLAG_ABUSE_PREFETCH |
+                                 IDE_HFLAG_ABUSE_FAST_DEVSEL,
+#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
+       .pio_mask               = ATA_PIO5,
+#endif
+};
+
 /*
  * Probe for a cmd640 chipset, and initialize it if found.
  */
@@ -762,11 +768,7 @@ static int __init cmd640x_init(void)
        setup_device_ptrs ();
        printk("%s: buggy cmd640%c interface on %s, config=0x%02x\n",
               cmd_hwif0->name, 'a' + cmd640_chip_version - 1, bus_type, cfr);
-       cmd_hwif0->chipset = ide_cmd640;
 #ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
-       cmd_hwif0->host_flags = IDE_HFLAG_ABUSE_PREFETCH |
-                               IDE_HFLAG_ABUSE_FAST_DEVSEL;
-       cmd_hwif0->pio_mask = ATA_PIO5;
        cmd_hwif0->set_pio_mode = &cmd640_set_pio_mode;
 #endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
 
@@ -817,23 +819,14 @@ static int __init cmd640x_init(void)
         * Initialize data for secondary cmd640 port, if enabled
         */
        if (second_port_cmd640) {
-               cmd_hwif0->serialized = 1;
-               cmd_hwif1->serialized = 1;
-               cmd_hwif1->chipset = ide_cmd640;
-               cmd_hwif0->mate = cmd_hwif1;
-               cmd_hwif1->mate = cmd_hwif0;
-               cmd_hwif1->channel = 1;
 #ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
-               cmd_hwif1->host_flags = IDE_HFLAG_ABUSE_PREFETCH |
-                                       IDE_HFLAG_ABUSE_FAST_DEVSEL;
-               cmd_hwif1->pio_mask = ATA_PIO5;
                cmd_hwif1->set_pio_mode = &cmd640_set_pio_mode;
 #endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
 
                idx[1] = cmd_hwif1->index;
        }
        printk(KERN_INFO "%s: %sserialized, secondary interface %s\n", cmd_hwif1->name,
-               cmd_hwif0->serialized ? "" : "not ", port2);
+                        second_port_cmd640 ? "" : "not ", port2);
 
        /*
         * Establish initial timings/prefetch for all drives.
@@ -878,7 +871,7 @@ static int __init cmd640x_init(void)
        cmd640_dump_regs();
 #endif
 
-       ide_device_add(idx);
+       ide_device_add(idx, &cmd640_port_info);
 
        return 1;
 }
index cd4eb9def1515719d2d3c998a67438a8aefa9bbf..edabe6299efdf58ca2b6806600c7191b45fed0fa 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * linux/drivers/ide/pci/cmd64x.c              Version 1.53    Dec 24, 2007
- *
  * cmd64x.c: Enable interrupts at initialization time on Ultra/PCI machines.
  *           Due to massive hardware bugs, UltraDMA is only supported
  *           on the 646U2 and not on the 646U.
@@ -15,7 +13,6 @@
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/pci.h>
-#include <linux/delay.h>
 #include <linux/hdreg.h>
 #include <linux/ide.h>
 #include <linux/init.h>
@@ -71,7 +68,7 @@ static u8 quantize_timing(int timing, int quant)
  */
 static void program_cycle_times (ide_drive_t *drive, int cycle_time, int active_time)
 {
-       struct pci_dev *dev     = HWIF(drive)->pci_dev;
+       struct pci_dev *dev     = to_pci_dev(drive->hwif->dev);
        int clock_time          = 1000 / system_bus_clock();
        u8  cycle_count, active_count, recovery_count, drwtim;
        static const u8 recovery_values[] =
@@ -118,7 +115,7 @@ static void program_cycle_times (ide_drive_t *drive, int cycle_time, int active_
 static void cmd64x_tune_pio(ide_drive_t *drive, const u8 pio)
 {
        ide_hwif_t *hwif        = HWIF(drive);
-       struct pci_dev *dev     = hwif->pci_dev;
+       struct pci_dev *dev     = to_pci_dev(hwif->dev);
        unsigned int cycle_time;
        u8 setup_count, arttim = 0;
 
@@ -183,7 +180,7 @@ static void cmd64x_set_pio_mode(ide_drive_t *drive, const u8 pio)
 static void cmd64x_set_dma_mode(ide_drive_t *drive, const u8 speed)
 {
        ide_hwif_t *hwif        = HWIF(drive);
-       struct pci_dev *dev     = hwif->pci_dev;
+       struct pci_dev *dev     = to_pci_dev(hwif->dev);
        u8 unit                 = drive->dn & 0x01;
        u8 regU = 0, pciU       = hwif->channel ? UDIDETCR1 : UDIDETCR0;
 
@@ -245,7 +242,7 @@ static int cmd648_ide_dma_end (ide_drive_t *drive)
 static int cmd64x_ide_dma_end (ide_drive_t *drive)
 {
        ide_hwif_t *hwif        = HWIF(drive);
-       struct pci_dev *dev     = hwif->pci_dev;
+       struct pci_dev *dev     = to_pci_dev(hwif->dev);
        int irq_reg             = hwif->channel ? ARTTIM23 : CFR;
        u8  irq_mask            = hwif->channel ? ARTTIM23_INTR_CH1 :
                                                  CFR_INTR_CH0;
@@ -285,7 +282,7 @@ static int cmd648_ide_dma_test_irq (ide_drive_t *drive)
 static int cmd64x_ide_dma_test_irq (ide_drive_t *drive)
 {
        ide_hwif_t *hwif        = HWIF(drive);
-       struct pci_dev *dev     = hwif->pci_dev;
+       struct pci_dev *dev     = to_pci_dev(hwif->dev);
        int irq_reg             = hwif->channel ? ARTTIM23 : CFR;
        u8  irq_mask            = hwif->channel ? ARTTIM23_INTR_CH1 :
                                                  CFR_INTR_CH0;
@@ -375,7 +372,7 @@ static unsigned int __devinit init_chipset_cmd64x(struct pci_dev *dev, const cha
 
 static u8 __devinit ata66_cmd64x(ide_hwif_t *hwif)
 {
-       struct pci_dev  *dev    = hwif->pci_dev;
+       struct pci_dev  *dev    = to_pci_dev(hwif->dev);
        u8 bmidecsr = 0, mask   = hwif->channel ? 0x02 : 0x01;
 
        switch (dev->device) {
@@ -390,11 +387,13 @@ static u8 __devinit ata66_cmd64x(ide_hwif_t *hwif)
 
 static void __devinit init_hwif_cmd64x(ide_hwif_t *hwif)
 {
-       struct pci_dev *dev     = hwif->pci_dev;
+       struct pci_dev *dev = to_pci_dev(hwif->dev);
 
        hwif->set_pio_mode = &cmd64x_set_pio_mode;
        hwif->set_dma_mode = &cmd64x_set_dma_mode;
 
+       hwif->cable_detect = ata66_cmd64x;
+
        if (!hwif->dma_base)
                return;
 
@@ -413,9 +412,6 @@ static void __devinit init_hwif_cmd64x(ide_hwif_t *hwif)
        if (dev->device == PCI_DEVICE_ID_CMD_646 && dev->revision < 5)
                hwif->ultra_mask = 0x00;
 
-       if (hwif->cbl != ATA_CBL_PATA40_SHORT)
-               hwif->cbl = ata66_cmd64x(hwif);
-
        switch (dev->device) {
        case PCI_DEVICE_ID_CMD_648:
        case PCI_DEVICE_ID_CMD_649:
@@ -443,7 +439,9 @@ static const struct ide_port_info cmd64x_chipsets[] __devinitdata = {
                .init_chipset   = init_chipset_cmd64x,
                .init_hwif      = init_hwif_cmd64x,
                .enablebits     = {{0x00,0x00,0x00}, {0x51,0x08,0x08}},
-               .host_flags     = IDE_HFLAG_ABUSE_PREFETCH | IDE_HFLAG_BOOTABLE,
+               .host_flags     = IDE_HFLAG_CLEAR_SIMPLEX |
+                                 IDE_HFLAG_ABUSE_PREFETCH |
+                                 IDE_HFLAG_BOOTABLE,
                .pio_mask       = ATA_PIO5,
                .mwdma_mask     = ATA_MWDMA2,
                .udma_mask      = 0x00, /* no udma */
index 6ec00b8d7ec1b1e10f51a7e023b4a9ed6ffed1b4..0be1a824102b90494f33410e3a199e8f5a432187 100644 (file)
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
 #include <linux/hdreg.h>
-
-#include <linux/interrupt.h>
 #include <linux/init.h>
 #include <linux/pci.h>
 #include <linux/ide.h>
 #include <linux/dma-mapping.h>
 
-#include <asm/io.h>
-#include <asm/irq.h>
-
 struct pio_clocks
 {
        int address;
@@ -69,7 +59,7 @@ static struct pio_clocks cs5520_pio_clocks[]={
 static void cs5520_set_pio_mode(ide_drive_t *drive, const u8 pio)
 {
        ide_hwif_t *hwif = HWIF(drive);
-       struct pci_dev *pdev = hwif->pci_dev;
+       struct pci_dev *pdev = to_pci_dev(hwif->dev);
        int controller = drive->dn > 1 ? 1 : 0;
 
        /* FIXME: if DMA = 1 do we need to set the DMA bit here ? */
@@ -156,8 +146,14 @@ static int __devinit cs5520_init_one(struct pci_dev *dev, const struct pci_devic
        ide_setup_pci_noise(dev, d);
 
        /* We must not grab the entire device, it has 'ISA' space in its
-          BARS too and we will freak out other bits of the kernel */
-       if (pci_enable_device_bars(dev, 1<<2)) {
+        * BARS too and we will freak out other bits of the kernel
+        *
+        * pci_enable_device_bars() is going away. I replaced it with
+        * IO only enable for now but I'll need confirmation this is
+        * allright for that device. If not, it will need some kind of
+        * quirk. --BenH.
+        */
+       if (pci_enable_device_io(dev)) {
                printk(KERN_WARNING "%s: Unable to enable 55x0.\n", d->name);
                return -ENODEV;
        }
@@ -174,7 +170,7 @@ static int __devinit cs5520_init_one(struct pci_dev *dev, const struct pci_devic
 
        ide_pci_setup_ports(dev, d, 14, &idx[0]);
 
-       ide_device_add(idx);
+       ide_device_add(idx, d);
 
        return 0;
 }
index df5966b334600f66bdfd528d246831dec68bebe6..941a1344820b95ae8d2f238714124f9d3e4c6470 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * linux/drivers/ide/pci/cs5530.c              Version 0.77    Sep 24 2007
- *
  * Copyright (C) 2000                  Andre Hedrick <andre@linux-ide.org>
  * Copyright (C) 2000                  Mark Lord <mlord@pobox.com>
  * Copyright (C) 2007                  Bartlomiej Zolnierkiewicz
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
 #include <linux/hdreg.h>
-#include <linux/interrupt.h>
 #include <linux/pci.h>
 #include <linux/init.h>
 #include <linux/ide.h>
+
 #include <asm/io.h>
-#include <asm/irq.h>
 
 /*
  * Here are the standard PIO mode 0-4 timings for each "format".
index 50b3d7791f55110c00d132202b335bb80d1cb6e8..d7b5ea992e94a25ee10b46eac7bb4237a9848764 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * linux/drivers/ide/pci/cs5535.c
- *
  * Copyright (C) 2004-2005 Advanced Micro Devices, Inc.
  * Copyright (C)      2007 Bartlomiej Zolnierkiewicz
  *
@@ -157,8 +155,9 @@ static void cs5535_set_pio_mode(ide_drive_t *drive, const u8 pio)
        cs5535_set_speed(drive, XFER_PIO_0 + pio);
 }
 
-static u8 __devinit cs5535_cable_detect(struct pci_dev *dev)
+static u8 __devinit cs5535_cable_detect(ide_hwif_t *hwif)
 {
+       struct pci_dev *dev = to_pci_dev(hwif->dev);
        u8 bit;
 
        /* if a 80 wire cable was detected */
@@ -180,10 +179,7 @@ static void __devinit init_hwif_cs5535(ide_hwif_t *hwif)
        hwif->set_pio_mode = &cs5535_set_pio_mode;
        hwif->set_dma_mode = &cs5535_set_dma_mode;
 
-       if (hwif->dma_base == 0)
-               return;
-
-       hwif->cbl = cs5535_cable_detect(hwif->pci_dev);
+       hwif->cable_detect = cs5535_cable_detect;
 }
 
 static const struct ide_port_info cs5535_chipset __devinitdata = {
index 3ec4c659a37d2593a1aa7e528217dab371f423e6..724cbacf4e5b04d9a82e19e5ea05a0d6e0cf5292 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * linux/drivers/ide/pci/cy82c693.c            Version 0.44    Nov 8, 2007
- *
  *  Copyright (C) 1998-2000 Andreas S. Krebs (akrebs@altavista.net), Maintainer
  *  Copyright (C) 1998-2002 Andre Hedrick <andre@linux-ide.org>, Integrator
  *
@@ -47,7 +45,6 @@
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/pci.h>
-#include <linux/delay.h>
 #include <linux/ide.h>
 #include <linux/init.h>
 
@@ -228,7 +225,7 @@ static void cy82c693_set_dma_mode(ide_drive_t *drive, const u8 mode)
 static void cy82c693_set_pio_mode(ide_drive_t *drive, const u8 pio)
 {
        ide_hwif_t *hwif = HWIF(drive);
-       struct pci_dev *dev = hwif->pci_dev;
+       struct pci_dev *dev = to_pci_dev(hwif->dev);
        pio_clocks_t pclk;
        unsigned int addrCtrl;
 
@@ -397,8 +394,9 @@ static void __devinit init_hwif_cy82c693(ide_hwif_t *hwif)
 static void __devinit init_iops_cy82c693(ide_hwif_t *hwif)
 {
        static ide_hwif_t *primary;
+       struct pci_dev *dev = to_pci_dev(hwif->dev);
 
-       if (PCI_FUNC(hwif->pci_dev->devfn) == 1)
+       if (PCI_FUNC(dev->devfn) == 1)
                primary = hwif;
        else {
                hwif->mate = primary;
index 26aa492071bb5fddb63ca8b3c3822637480060ef..3f9cd64c26a6aa0f2214918c485fcce7c9b6d120 100644 (file)
@@ -1,6 +1,4 @@
 /*
- *  linux/drivers/ide/pci/delkin_cb.c
- *
  *  Created 20 Oct 2004 by Mark Lord
  *
  *  Basic support for Delkin/ASKA/Workbit Cardbus CompactFlash adapter
  *  License.  See the file COPYING in the main directory of this archive for
  *  more details.
  */
-#include <linux/autoconf.h>
+
 #include <linux/types.h>
 #include <linux/module.h>
-#include <linux/mm.h>
-#include <linux/blkdev.h>
 #include <linux/hdreg.h>
 #include <linux/ide.h>
 #include <linux/init.h>
 #include <linux/pci.h>
+
 #include <asm/io.h>
 
 /*
@@ -54,6 +51,7 @@ delkin_cb_probe (struct pci_dev *dev, const struct pci_device_id *id)
        ide_hwif_t *hwif = NULL;
        ide_drive_t *drive;
        int i, rc;
+       u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
 
        rc = pci_enable_device(dev);
        if (rc) {
@@ -80,20 +78,40 @@ delkin_cb_probe (struct pci_dev *dev, const struct pci_device_id *id)
        hw.irq = dev->irq;
        hw.chipset = ide_pci;           /* this enables IRQ sharing */
 
-       rc = ide_register_hw(&hw, &ide_undecoded_slave, &hwif);
-       if (rc < 0) {
-               printk(KERN_ERR "delkin_cb: ide_register_hw failed (%d)\n", rc);
-               pci_disable_device(dev);
-               return -ENODEV;
-       }
+       hwif = ide_deprecated_find_port(hw.io_ports[IDE_DATA_OFFSET]);
+       if (hwif == NULL)
+               goto out_disable;
+
+       i = hwif->index;
+
+       if (hwif->present)
+               ide_unregister(i, 0, 0);
+       else if (!hwif->hold)
+               ide_init_port_data(hwif, i);
+
+       ide_init_port_hw(hwif, &hw);
+       hwif->quirkproc = &ide_undecoded_slave;
+
+       idx[0] = i;
+
+       ide_device_add(idx, NULL);
+
+       if (!hwif->present)
+               goto out_disable;
+
        pci_set_drvdata(dev, hwif);
-       hwif->pci_dev = dev;
+       hwif->dev = &dev->dev;
        drive = &hwif->drives[0];
        if (drive->present) {
                drive->io_32bit = 1;
                drive->unmask   = 1;
        }
        return 0;
+
+out_disable:
+       printk(KERN_ERR "delkin_cb: no IDE devices found\n");
+       pci_disable_device(dev);
+       return -ENODEV;
 }
 
 static void
@@ -102,7 +120,8 @@ delkin_cb_remove (struct pci_dev *dev)
        ide_hwif_t *hwif = pci_get_drvdata(dev);
 
        if (hwif)
-               ide_unregister(hwif->index);
+               ide_unregister(hwif->index, 0, 0);
+
        pci_disable_device(dev);
 }
 
index 06885697ed7b95c444fcd961b9f067ad7d02b1ee..7fd83a9d4dee16fb8612850bce50732e0e60930a 100644 (file)
@@ -1,6 +1,4 @@
 /*
- *  linux/drivers/ide/pci/generic.c    Version 0.11    December 30, 2002
- *
  *  Copyright (C) 2001-2002    Andre Hedrick <andre@linux-ide.org>
  *  Portions (C) Copyright 2002  Red Hat Inc <alan@redhat.com>
  *
 #include <linux/types.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
 #include <linux/hdreg.h>
 #include <linux/pci.h>
 #include <linux/ide.h>
 #include <linux/init.h>
 
-#include <asm/io.h>
-
 static int ide_generic_all;            /* Set to claim all devices */
 
-/*
- * the module_param_named() was added for the modular case
- * the __setup() is left as compatibility for existing setups
- */
-#ifndef MODULE
-static int __init ide_generic_all_on(char *unused)
-{
-       ide_generic_all = 1;
-       printk(KERN_INFO "IDE generic will claim all unknown PCI IDE storage controllers.\n");
-       return 1;
-}
-const __setup("all-generic-ide", ide_generic_all_on);
-#endif
 module_param_named(all_generic_ide, ide_generic_all, bool, 0444);
 MODULE_PARM_DESC(all_generic_ide, "IDE generic will claim all unknown PCI IDE storage controllers.");
 
@@ -104,7 +82,8 @@ static const struct ide_port_info generic_chipsets[] __devinitdata = {
 
        {       /* 14 */
                .name           = "Revolution",
-               .host_flags     = IDE_HFLAG_TRUST_BIOS_FOR_DMA |
+               .host_flags     = IDE_HFLAG_CLEAR_SIMPLEX |
+                                 IDE_HFLAG_TRUST_BIOS_FOR_DMA |
                                  IDE_HFLAG_OFF_BOARD,
                .swdma_mask     = ATA_SWDMA2,
                .mwdma_mask     = ATA_MWDMA2,
index dfba0d13fcd39f4f4ebc96df5a874d798fc5b65d..9f01da46b01648d6ead8c8b516fbe7a7a9d4cc1e 100644 (file)
@@ -1,7 +1,6 @@
 /*
- * linux/drivers/ide/pci/hpt34x.c              Version 0.40    Sept 10, 2002
- *
  * Copyright (C) 1998-2000     Andre Hedrick <andre@linux-ide.org>
+ *
  * May be copied or modified under the terms of the GNU General Public License
  *
  *
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
 #include <linux/ioport.h>
-#include <linux/blkdev.h>
 #include <linux/hdreg.h>
 #include <linux/interrupt.h>
 #include <linux/pci.h>
 #include <linux/init.h>
 #include <linux/ide.h>
 
-#include <asm/io.h>
-#include <asm/irq.h>
-
 #define HPT343_DEBUG_DRIVE_INFO                0
 
 static void hpt34x_set_mode(ide_drive_t *drive, const u8 speed)
 {
-       struct pci_dev *dev     = HWIF(drive)->pci_dev;
+       struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
        u32 reg1= 0, tmp1 = 0, reg2 = 0, tmp2 = 0;
        u8                      hi_speed, lo_speed;
 
@@ -131,6 +123,7 @@ static void __devinit init_hwif_hpt34x(ide_hwif_t *hwif)
 
 #define IDE_HFLAGS_HPT34X \
        (IDE_HFLAG_NO_ATAPI_DMA | \
+        IDE_HFLAG_NO_DSC | \
         IDE_HFLAG_ABUSE_SET_DMA_MODE | \
         IDE_HFLAG_NO_AUTODMA)
 
index 12685939a813f61f0e30521d2b871f2dd9fb9b1d..d0f7bb8b8adf1d881fe4d2f7c5f86106dc4b63d1 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * linux/drivers/ide/pci/hpt366.c              Version 1.30    Dec 12, 2007
- *
  * Copyright (C) 1999-2003             Andre Hedrick <andre@linux-ide.org>
  * Portions Copyright (C) 2001         Sun Microsystems, Inc.
  * Portions Copyright (C) 2003         Red Hat Inc
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
 #include <linux/blkdev.h>
 #include <linux/hdreg.h>
-
 #include <linux/interrupt.h>
 #include <linux/pci.h>
 #include <linux/init.h>
 
 #include <asm/uaccess.h>
 #include <asm/io.h>
-#include <asm/irq.h>
 
 /* various tuning parameters */
 #define HPT_RESET_STATE_ENGINE
@@ -626,7 +619,8 @@ static int check_in_drive_list(ide_drive_t *drive, const char **list)
 static u8 hpt3xx_udma_filter(ide_drive_t *drive)
 {
        ide_hwif_t *hwif        = HWIF(drive);
-       struct hpt_info *info   = pci_get_drvdata(hwif->pci_dev);
+       struct pci_dev *dev     = to_pci_dev(hwif->dev);
+       struct hpt_info *info   = pci_get_drvdata(dev);
        u8 mask                 = hwif->ultra_mask;
 
        switch (info->chip_type) {
@@ -665,7 +659,8 @@ static u8 hpt3xx_udma_filter(ide_drive_t *drive)
 static u8 hpt3xx_mdma_filter(ide_drive_t *drive)
 {
        ide_hwif_t *hwif        = HWIF(drive);
-       struct hpt_info *info   = pci_get_drvdata(hwif->pci_dev);
+       struct pci_dev *dev     = to_pci_dev(hwif->dev);
+       struct hpt_info *info   = pci_get_drvdata(dev);
 
        switch (info->chip_type) {
        case HPT372 :
@@ -699,7 +694,7 @@ static u32 get_speed_setting(u8 speed, struct hpt_info *info)
 
 static void hpt3xx_set_mode(ide_drive_t *drive, const u8 speed)
 {
-       struct pci_dev  *dev    = HWIF(drive)->pci_dev;
+       struct pci_dev  *dev    = to_pci_dev(drive->hwif->dev);
        struct hpt_info *info   = pci_get_drvdata(dev);
        struct hpt_timings *t   = info->timings;
        u8  itr_addr            = 0x40 + (drive->dn * 4);
@@ -742,7 +737,7 @@ static void hpt3xx_quirkproc(ide_drive_t *drive)
 static void hpt3xx_maskproc(ide_drive_t *drive, int mask)
 {
        ide_hwif_t *hwif        = HWIF(drive);
-       struct pci_dev  *dev    = hwif->pci_dev;
+       struct pci_dev  *dev    = to_pci_dev(hwif->dev);
        struct hpt_info *info   = pci_get_drvdata(dev);
 
        if (drive->quirk_list) {
@@ -774,7 +769,7 @@ static void hpt3xx_maskproc(ide_drive_t *drive, int mask)
  */
 static void hpt366_dma_lost_irq(ide_drive_t *drive)
 {
-       struct pci_dev *dev = HWIF(drive)->pci_dev;
+       struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
        u8 mcr1 = 0, mcr3 = 0, scr1 = 0;
 
        pci_read_config_byte(dev, 0x50, &mcr1);
@@ -790,18 +785,20 @@ static void hpt366_dma_lost_irq(ide_drive_t *drive)
 static void hpt370_clear_engine(ide_drive_t *drive)
 {
        ide_hwif_t *hwif = HWIF(drive);
+       struct pci_dev *dev = to_pci_dev(hwif->dev);
 
-       pci_write_config_byte(hwif->pci_dev, hwif->select_data, 0x37);
+       pci_write_config_byte(dev, hwif->select_data, 0x37);
        udelay(10);
 }
 
 static void hpt370_irq_timeout(ide_drive_t *drive)
 {
        ide_hwif_t *hwif        = HWIF(drive);
+       struct pci_dev *dev     = to_pci_dev(hwif->dev);
        u16 bfifo               = 0;
        u8  dma_cmd;
 
-       pci_read_config_word(hwif->pci_dev, hwif->select_data + 2, &bfifo);
+       pci_read_config_word(dev, hwif->select_data + 2, &bfifo);
        printk(KERN_DEBUG "%s: %d bytes in FIFO\n", drive->name, bfifo & 0x1ff);
 
        /* get DMA command mode */
@@ -844,10 +841,11 @@ static void hpt370_dma_timeout(ide_drive_t *drive)
 static int hpt374_ide_dma_test_irq(ide_drive_t *drive)
 {
        ide_hwif_t *hwif        = HWIF(drive);
+       struct pci_dev *dev     = to_pci_dev(hwif->dev);
        u16 bfifo               = 0;
        u8  dma_stat;
 
-       pci_read_config_word(hwif->pci_dev, hwif->select_data + 2, &bfifo);
+       pci_read_config_word(dev, hwif->select_data + 2, &bfifo);
        if (bfifo & 0x1FF) {
 //             printk("%s: %d bytes in FIFO\n", drive->name, bfifo);
                return 0;
@@ -867,7 +865,7 @@ static int hpt374_ide_dma_test_irq(ide_drive_t *drive)
 static int hpt374_ide_dma_end(ide_drive_t *drive)
 {
        ide_hwif_t *hwif        = HWIF(drive);
-       struct pci_dev  *dev    = hwif->pci_dev;
+       struct pci_dev *dev     = to_pci_dev(hwif->dev);
        u8 mcr  = 0, mcr_addr   = hwif->select_data;
        u8 bwsr = 0, mask       = hwif->channel ? 0x02 : 0x01;
 
@@ -942,7 +940,7 @@ static void hpt3xxn_rw_disk(ide_drive_t *drive, struct request *rq)
 static int hpt3xx_busproc(ide_drive_t *drive, int state)
 {
        ide_hwif_t *hwif        = HWIF(drive);
-       struct pci_dev *dev     = hwif->pci_dev;
+       struct pci_dev *dev     = to_pci_dev(hwif->dev);
        u8  mcr_addr            = hwif->select_data + 2;
        u8  resetmask           = hwif->channel ? 0x80 : 0x40;
        u8  bsr2                = 0;
@@ -1276,12 +1274,55 @@ static unsigned int __devinit init_chipset_hpt366(struct pci_dev *dev, const cha
        return dev->irq;
 }
 
+static u8 __devinit hpt3xx_cable_detect(ide_hwif_t *hwif)
+{
+       struct pci_dev  *dev    = to_pci_dev(hwif->dev);
+       struct hpt_info *info   = pci_get_drvdata(dev);
+       u8 chip_type            = info->chip_type;
+       u8 scr1 = 0, ata66      = hwif->channel ? 0x01 : 0x02;
+
+       /*
+        * The HPT37x uses the CBLID pins as outputs for MA15/MA16
+        * address lines to access an external EEPROM.  To read valid
+        * cable detect state the pins must be enabled as inputs.
+        */
+       if (chip_type == HPT374 && (PCI_FUNC(dev->devfn) & 1)) {
+               /*
+                * HPT374 PCI function 1
+                * - set bit 15 of reg 0x52 to enable TCBLID as input
+                * - set bit 15 of reg 0x56 to enable FCBLID as input
+                */
+               u8  mcr_addr = hwif->select_data + 2;
+               u16 mcr;
+
+               pci_read_config_word(dev, mcr_addr, &mcr);
+               pci_write_config_word(dev, mcr_addr, (mcr | 0x8000));
+               /* now read cable id register */
+               pci_read_config_byte(dev, 0x5a, &scr1);
+               pci_write_config_word(dev, mcr_addr, mcr);
+       } else if (chip_type >= HPT370) {
+               /*
+                * HPT370/372 and 374 pcifn 0
+                * - clear bit 0 of reg 0x5b to enable P/SCBLID as inputs
+                */
+               u8 scr2 = 0;
+
+               pci_read_config_byte(dev, 0x5b, &scr2);
+               pci_write_config_byte(dev, 0x5b, (scr2 & ~1));
+               /* now read cable id register */
+               pci_read_config_byte(dev, 0x5a, &scr1);
+               pci_write_config_byte(dev, 0x5b,  scr2);
+       } else
+               pci_read_config_byte(dev, 0x5a, &scr1);
+
+       return (scr1 & ata66) ? ATA_CBL_PATA40 : ATA_CBL_PATA80;
+}
+
 static void __devinit init_hwif_hpt366(ide_hwif_t *hwif)
 {
-       struct pci_dev  *dev    = hwif->pci_dev;
+       struct pci_dev *dev     = to_pci_dev(hwif->dev);
        struct hpt_info *info   = pci_get_drvdata(dev);
        int serialize           = HPT_SERIALIZE_IO;
-       u8  scr1 = 0, ata66     = hwif->channel ? 0x01 : 0x02;
        u8  chip_type           = info->chip_type;
        u8  new_mcr, old_mcr    = 0;
 
@@ -1298,6 +1339,8 @@ static void __devinit init_hwif_hpt366(ide_hwif_t *hwif)
        hwif->udma_filter       = &hpt3xx_udma_filter;
        hwif->mdma_filter       = &hpt3xx_mdma_filter;
 
+       hwif->cable_detect      = hpt3xx_cable_detect;
+
        /*
         * HPT3xxN chips have some complications:
         *
@@ -1343,43 +1386,6 @@ static void __devinit init_hwif_hpt366(ide_hwif_t *hwif)
        if (hwif->dma_base == 0)
                return;
 
-       /*
-        * The HPT37x uses the CBLID pins as outputs for MA15/MA16
-        * address lines to access an external EEPROM.  To read valid
-        * cable detect state the pins must be enabled as inputs.
-        */
-       if (chip_type == HPT374 && (PCI_FUNC(dev->devfn) & 1)) {
-               /*
-                * HPT374 PCI function 1
-                * - set bit 15 of reg 0x52 to enable TCBLID as input
-                * - set bit 15 of reg 0x56 to enable FCBLID as input
-                */
-               u8  mcr_addr = hwif->select_data + 2;
-               u16 mcr;
-
-               pci_read_config_word (dev, mcr_addr, &mcr);
-               pci_write_config_word(dev, mcr_addr, (mcr | 0x8000));
-               /* now read cable id register */
-               pci_read_config_byte (dev, 0x5a, &scr1);
-               pci_write_config_word(dev, mcr_addr, mcr);
-       } else if (chip_type >= HPT370) {
-               /*
-                * HPT370/372 and 374 pcifn 0
-                * - clear bit 0 of reg 0x5b to enable P/SCBLID as inputs
-                */
-               u8 scr2 = 0;
-
-               pci_read_config_byte (dev, 0x5b, &scr2);
-               pci_write_config_byte(dev, 0x5b, (scr2 & ~1));
-               /* now read cable id register */
-               pci_read_config_byte (dev, 0x5a, &scr1);
-               pci_write_config_byte(dev, 0x5b,  scr2);
-       } else
-               pci_read_config_byte (dev, 0x5a, &scr1);
-
-       if (hwif->cbl != ATA_CBL_PATA40_SHORT)
-               hwif->cbl = (scr1 & ata66) ? ATA_CBL_PATA40 : ATA_CBL_PATA80;
-
        if (chip_type >= HPT374) {
                hwif->ide_dma_test_irq  = &hpt374_ide_dma_test_irq;
                hwif->ide_dma_end       = &hpt374_ide_dma_end;
@@ -1393,7 +1399,7 @@ static void __devinit init_hwif_hpt366(ide_hwif_t *hwif)
 
 static void __devinit init_dma_hpt366(ide_hwif_t *hwif, unsigned long dmabase)
 {
-       struct pci_dev  *dev            = hwif->pci_dev;
+       struct pci_dev *dev = to_pci_dev(hwif->dev);
        u8 masterdma    = 0, slavedma   = 0;
        u8 dma_new      = 0, dma_old    = 0;
        unsigned long flags;
@@ -1413,7 +1419,7 @@ static void __devinit init_dma_hpt366(ide_hwif_t *hwif, unsigned long dmabase)
 
        local_irq_restore(flags);
 
-       ide_setup_dma(hwif, dmabase, 8);
+       ide_setup_dma(hwif, dmabase);
 }
 
 static void __devinit hpt374_init(struct pci_dev *dev, struct pci_dev *dev2)
index 2a0f45c4f4c4167290db93a4814a2c40facc18c4..e3427eaab430b9de5ef463c4e8c558e6bace1fec 100644 (file)
 #include <linux/types.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/delay.h>
 #include <linux/hdreg.h>
 #include <linux/ide.h>
 #include <linux/init.h>
 
-#include <asm/io.h>
-
 /**
  *     it8213_set_pio_mode     -       set host controller for PIO mode
  *     @drive: drive
@@ -28,7 +25,7 @@
 static void it8213_set_pio_mode(ide_drive_t *drive, const u8 pio)
 {
        ide_hwif_t *hwif        = HWIF(drive);
-       struct pci_dev *dev     = hwif->pci_dev;
+       struct pci_dev *dev     = to_pci_dev(hwif->dev);
        int is_slave            = drive->dn & 1;
        int master_port         = 0x40;
        int slave_port          = 0x44;
@@ -85,7 +82,7 @@ static void it8213_set_pio_mode(ide_drive_t *drive, const u8 pio)
 static void it8213_set_dma_mode(ide_drive_t *drive, const u8 speed)
 {
        ide_hwif_t *hwif        = HWIF(drive);
-       struct pci_dev *dev     = hwif->pci_dev;
+       struct pci_dev *dev     = to_pci_dev(hwif->dev);
        u8 maslave              = 0x40;
        int a_speed             = 3 << (drive->dn * 4);
        int u_flag              = 1 << drive->dn;
@@ -143,6 +140,16 @@ static void it8213_set_dma_mode(ide_drive_t *drive, const u8 speed)
        }
 }
 
+static u8 __devinit it8213_cable_detect(ide_hwif_t *hwif)
+{
+       struct pci_dev *dev = to_pci_dev(hwif->dev);
+       u8 reg42h = 0;
+
+       pci_read_config_byte(dev, 0x42, &reg42h);
+
+       return (reg42h & 0x02) ? ATA_CBL_PATA40 : ATA_CBL_PATA80;
+}
+
 /**
  *     init_hwif_it8213        -       set up hwif structs
  *     @hwif: interface to set up
@@ -152,18 +159,10 @@ static void it8213_set_dma_mode(ide_drive_t *drive, const u8 speed)
 
 static void __devinit init_hwif_it8213(ide_hwif_t *hwif)
 {
-       u8 reg42h = 0;
-
        hwif->set_dma_mode = &it8213_set_dma_mode;
        hwif->set_pio_mode = &it8213_set_pio_mode;
 
-       if (!hwif->dma_base)
-               return;
-
-       pci_read_config_byte(hwif->pci_dev, 0x42, &reg42h);
-
-       if (hwif->cbl != ATA_CBL_PATA40_SHORT)
-               hwif->cbl = (reg42h & 0x02) ? ATA_CBL_PATA40 : ATA_CBL_PATA80;
+       hwif->cable_detect = it8213_cable_detect;
 }
 
 
index e610a5340fdcb8758a90e4cf1a75c3147ee4487d..1597f0cc1bf1ced36b76caa3b7e264f563f5a3f0 100644 (file)
@@ -1,7 +1,4 @@
-
 /*
- * linux/drivers/ide/pci/it821x.c              Version 0.16    Jul 3 2007
- *
  * Copyright (C) 2004          Red Hat <alan@redhat.com>
  * Copyright (C) 2007          Bartlomiej Zolnierkiewicz
  *
 #include <linux/types.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/delay.h>
 #include <linux/hdreg.h>
 #include <linux/ide.h>
 #include <linux/init.h>
 
-#include <asm/io.h>
-
 struct it821x_dev
 {
        unsigned int smart:1,           /* Are we in smart raid mode */
@@ -113,7 +107,8 @@ static int it8212_noraid;
 
 static void it821x_program(ide_drive_t *drive, u16 timing)
 {
-       ide_hwif_t *hwif        = drive->hwif;
+       ide_hwif_t *hwif = drive->hwif;
+       struct pci_dev *dev = to_pci_dev(hwif->dev);
        struct it821x_dev *itdev = ide_get_hwifdata(hwif);
        int channel = hwif->channel;
        u8 conf;
@@ -123,7 +118,8 @@ static void it821x_program(ide_drive_t *drive, u16 timing)
                conf = timing >> 8;
        else
                conf = timing & 0xFF;
-       pci_write_config_byte(hwif->pci_dev, 0x54 + 4 * channel, conf);
+
+       pci_write_config_byte(dev, 0x54 + 4 * channel, conf);
 }
 
 /**
@@ -137,7 +133,8 @@ static void it821x_program(ide_drive_t *drive, u16 timing)
 
 static void it821x_program_udma(ide_drive_t *drive, u16 timing)
 {
-       ide_hwif_t *hwif        = drive->hwif;
+       ide_hwif_t *hwif = drive->hwif;
+       struct pci_dev *dev = to_pci_dev(hwif->dev);
        struct it821x_dev *itdev = ide_get_hwifdata(hwif);
        int channel = hwif->channel;
        int unit = drive->select.b.unit;
@@ -148,11 +145,12 @@ static void it821x_program_udma(ide_drive_t *drive, u16 timing)
                conf = timing >> 8;
        else
                conf = timing & 0xFF;
-       if(itdev->timing10 == 0)
-               pci_write_config_byte(hwif->pci_dev, 0x56 + 4 * channel + unit, conf);
+
+       if (itdev->timing10 == 0)
+               pci_write_config_byte(dev, 0x56 + 4 * channel + unit, conf);
        else {
-               pci_write_config_byte(hwif->pci_dev, 0x56 + 4 * channel, conf);
-               pci_write_config_byte(hwif->pci_dev, 0x56 + 4 * channel + 1, conf);
+               pci_write_config_byte(dev, 0x56 + 4 * channel, conf);
+               pci_write_config_byte(dev, 0x56 + 4 * channel + 1, conf);
        }
 }
 
@@ -167,6 +165,7 @@ static void it821x_program_udma(ide_drive_t *drive, u16 timing)
 static void it821x_clock_strategy(ide_drive_t *drive)
 {
        ide_hwif_t *hwif = drive->hwif;
+       struct pci_dev *dev = to_pci_dev(hwif->dev);
        struct it821x_dev *itdev = ide_get_hwifdata(hwif);
 
        u8 unit = drive->select.b.unit;
@@ -205,10 +204,11 @@ static void it821x_clock_strategy(ide_drive_t *drive)
                itdev->clock_mode = ATA_50;
                sel = 1;
        }
-       pci_read_config_byte(hwif->pci_dev, 0x50, &v);
+
+       pci_read_config_byte(dev, 0x50, &v);
        v &= ~(1 << (1 + hwif->channel));
        v |= sel << (1 + hwif->channel);
-       pci_write_config_byte(hwif->pci_dev, 0x50, v);
+       pci_write_config_byte(dev, 0x50, v);
 
        /*
         *      Reprogram the UDMA/PIO of the pair drive for the switch
@@ -282,7 +282,8 @@ static void it821x_set_pio_mode(ide_drive_t *drive, const u8 pio)
 
 static void it821x_tune_mwdma (ide_drive_t *drive, byte mode_wanted)
 {
-       ide_hwif_t *hwif        = drive->hwif;
+       ide_hwif_t *hwif = drive->hwif;
+       struct pci_dev *dev = to_pci_dev(hwif->dev);
        struct it821x_dev *itdev = (void *)ide_get_hwifdata(hwif);
        int unit = drive->select.b.unit;
        int channel = hwif->channel;
@@ -297,12 +298,12 @@ static void it821x_tune_mwdma (ide_drive_t *drive, byte mode_wanted)
        itdev->udma[unit] = UDMA_OFF;
 
        /* UDMA bits off - Revision 0x10 do them in pairs */
-       pci_read_config_byte(hwif->pci_dev, 0x50, &conf);
-       if(itdev->timing10)
+       pci_read_config_byte(dev, 0x50, &conf);
+       if (itdev->timing10)
                conf |= channel ? 0x60: 0x18;
        else
                conf |= 1 << (3 + 2 * channel + unit);
-       pci_write_config_byte(hwif->pci_dev, 0x50, conf);
+       pci_write_config_byte(dev, 0x50, conf);
 
        it821x_clock_strategy(drive);
        /* FIXME: do we need to program this ? */
@@ -320,7 +321,8 @@ static void it821x_tune_mwdma (ide_drive_t *drive, byte mode_wanted)
 
 static void it821x_tune_udma (ide_drive_t *drive, byte mode_wanted)
 {
-       ide_hwif_t *hwif        = drive->hwif;
+       ide_hwif_t *hwif = drive->hwif;
+       struct pci_dev *dev = to_pci_dev(hwif->dev);
        struct it821x_dev *itdev = ide_get_hwifdata(hwif);
        int unit = drive->select.b.unit;
        int channel = hwif->channel;
@@ -337,12 +339,12 @@ static void it821x_tune_udma (ide_drive_t *drive, byte mode_wanted)
                itdev->udma[unit] |= 0x8080;    /* UDMA 5/6 select on */
 
        /* UDMA on. Again revision 0x10 must do the pair */
-       pci_read_config_byte(hwif->pci_dev, 0x50, &conf);
-       if(itdev->timing10)
+       pci_read_config_byte(dev, 0x50, &conf);
+       if (itdev->timing10)
                conf &= channel ? 0x9F: 0xE7;
        else
                conf &= ~ (1 << (3 + 2 * channel + unit));
-       pci_write_config_byte(hwif->pci_dev, 0x50, conf);
+       pci_write_config_byte(dev, 0x50, conf);
 
        it821x_clock_strategy(drive);
        it821x_program_udma(drive, itdev->udma[unit]);
@@ -520,6 +522,7 @@ static void __devinit it821x_quirkproc(ide_drive_t *drive)
 
 static void __devinit init_hwif_it821x(ide_hwif_t *hwif)
 {
+       struct pci_dev *dev = to_pci_dev(hwif->dev);
        struct it821x_dev *idev = kzalloc(sizeof(struct it821x_dev), GFP_KERNEL);
        u8 conf;
 
@@ -532,7 +535,7 @@ static void __devinit init_hwif_it821x(ide_hwif_t *hwif)
 
        ide_set_hwifdata(hwif, idev);
 
-       pci_read_config_byte(hwif->pci_dev, 0x50, &conf);
+       pci_read_config_byte(dev, 0x50, &conf);
        if (conf & 1) {
                idev->smart = 1;
                hwif->host_flags |= IDE_HFLAG_NO_ATAPI_DMA;
@@ -555,7 +558,7 @@ static void __devinit init_hwif_it821x(ide_hwif_t *hwif)
         *      this is necessary.
         */
 
-       pci_read_config_byte(hwif->pci_dev, 0x08, &conf);
+       pci_read_config_byte(dev, 0x08, &conf);
        if (conf == 0x10) {
                idev->timing10 = 1;
                hwif->host_flags |= IDE_HFLAG_NO_ATAPI_DMA;
@@ -573,14 +576,13 @@ static void __devinit init_hwif_it821x(ide_hwif_t *hwif)
        } else
                hwif->host_flags |= IDE_HFLAG_NO_SET_MODE;
 
+       hwif->cable_detect = ata66_it821x;
+
        if (hwif->dma_base == 0)
                return;
 
        hwif->ultra_mask = ATA_UDMA6;
        hwif->mwdma_mask = ATA_MWDMA2;
-
-       if (hwif->cbl != ATA_CBL_PATA40_SHORT)
-               hwif->cbl = ata66_it821x(hwif);
 }
 
 static void __devinit it8212_disable_raid(struct pci_dev *dev)
index 0083eaf89c773ca61760b4a180d870e77f9fa8e4..a56bcb4f22f4f9d402616d5314c50a4ed8794ec5 100644 (file)
@@ -8,13 +8,10 @@
 #include <linux/types.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/delay.h>
 #include <linux/hdreg.h>
 #include <linux/ide.h>
 #include <linux/init.h>
 
-#include <asm/io.h>
-
 typedef enum {
        PORT_PATA0 = 0,
        PORT_PATA1 = 1,
@@ -30,7 +27,7 @@ typedef enum {
 
 static u8 __devinit ata66_jmicron(ide_hwif_t *hwif)
 {
-       struct pci_dev *pdev = hwif->pci_dev;
+       struct pci_dev *pdev = to_pci_dev(hwif->dev);
 
        u32 control;
        u32 control5;
@@ -111,11 +108,7 @@ static void __devinit init_hwif_jmicron(ide_hwif_t *hwif)
        hwif->set_pio_mode = &jmicron_set_pio_mode;
        hwif->set_dma_mode = &jmicron_set_dma_mode;
 
-       if (hwif->dma_base == 0)
-               return;
-
-       if (hwif->cbl != ATA_CBL_PATA40_SHORT)
-               hwif->cbl = ata66_jmicron(hwif);
+       hwif->cable_detect = ata66_jmicron;
 }
 
 static const struct ide_port_info jmicron_chipset __devinitdata = {
index d4df4642dbb5ff83e136b26126816fcc3ca09fff..bf0d3b2931f1c3202259fa40c444642cb93f07c6 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * linux/drivers/ide/pci/ns87415.c             Version 2.00  Sep. 10, 2002
- *
  * Copyright (C) 1997-1998     Mark Lord <mlord@pobox.com>
  * Copyright (C) 1998          Eddie C. Dost <ecd@skynet.be>
  * Copyright (C) 1999-2000     Andre Hedrick <andre@linux-ide.org>
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
 #include <linux/interrupt.h>
-#include <linux/blkdev.h>
 #include <linux/hdreg.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
@@ -71,10 +65,9 @@ static u8 superio_ide_inb (unsigned long port)
 
 static void __devinit superio_ide_init_iops (struct hwif_s *hwif)
 {
+       struct pci_dev *pdev = to_pci_dev(hwif->dev);
        u32 base, dmabase;
-       u8 tmp;
-       struct pci_dev *pdev = hwif->pci_dev;
-       u8 port = hwif->channel;
+       u8 port = hwif->channel, tmp;
 
        base = pci_resource_start(pdev, port * 2) & ~3;
        dmabase = pci_resource_start(pdev, 4) & ~3;
@@ -93,10 +86,11 @@ static void __devinit superio_ide_init_iops (struct hwif_s *hwif)
 
 static void __devinit init_iops_ns87415(ide_hwif_t *hwif)
 {
-       if (PCI_SLOT(hwif->pci_dev->devfn) == 0xE) {
+       struct pci_dev *dev = to_pci_dev(hwif->dev);
+
+       if (PCI_SLOT(dev->devfn) == 0xE)
                /* Built-in - assume it's under superio. */
                superio_ide_init_iops(hwif);
-       }
 }
 #endif
 
@@ -110,8 +104,8 @@ static unsigned int ns87415_count = 0, ns87415_control[MAX_HWIFS] = { 0 };
 static void ns87415_prepare_drive (ide_drive_t *drive, unsigned int use_dma)
 {
        ide_hwif_t *hwif = HWIF(drive);
+       struct pci_dev *dev = to_pci_dev(hwif->dev);
        unsigned int bit, other, new, *old = (unsigned int *) hwif->select_data;
-       struct pci_dev *dev = hwif->pci_dev;
        unsigned long flags;
 
        local_irq_save(flags);
@@ -189,7 +183,7 @@ static int ns87415_ide_dma_setup(ide_drive_t *drive)
 
 static void __devinit init_hwif_ns87415 (ide_hwif_t *hwif)
 {
-       struct pci_dev *dev = hwif->pci_dev;
+       struct pci_dev *dev = to_pci_dev(hwif->dev);
        unsigned int ctrl, using_inta;
        u8 progif;
 #ifdef __sparc_v9__
@@ -231,8 +225,8 @@ static void __devinit init_hwif_ns87415 (ide_hwif_t *hwif)
 
 #ifdef __sparc_v9__
                /*
-                * XXX: Reset the device, if we don't it will not respond
-                *      to SELECT_DRIVE() properly during first probe_hwif().
+                * XXX: Reset the device, if we don't it will not respond to
+                *      SELECT_DRIVE() properly during first ide_probe_port().
                 */
                timeout = 10000;
                outb(12, hwif->io_ports[IDE_CONTROL_OFFSET]);
index 8953d9c3926fe3ea909563562374f3599d9568e6..46e8748f507e57cdb985007b32f18e80619f93a6 100644 (file)
@@ -1,6 +1,4 @@
 /*
- *  linux/drivers/ide/pci/opti621.c            Version 0.9     Sep 24, 2007
- *
  *  Copyright (C) 1996-1998  Linus Torvalds & authors (see below)
  */
 
 #include <linux/types.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
 #include <linux/pci.h>
 #include <linux/hdreg.h>
 #include <linux/ide.h>
@@ -322,14 +315,18 @@ static void opti621_set_pio_mode(ide_drive_t *drive, const u8 pio)
        spin_unlock_irqrestore(&opti621_lock, flags);
 }
 
+static void __devinit opti621_port_init_devs(ide_hwif_t *hwif)
+{
+       hwif->drives[0].drive_data = PIO_DONT_KNOW;
+       hwif->drives[1].drive_data = PIO_DONT_KNOW;
+}
+
 /*
  * init_hwif_opti621() is called once for each hwif found at boot.
  */
 static void __devinit init_hwif_opti621 (ide_hwif_t *hwif)
 {
-       hwif->drives[0].drive_data = PIO_DONT_KNOW;
-       hwif->drives[1].drive_data = PIO_DONT_KNOW;
-
+       hwif->port_init_devs = opti621_port_init_devs;
        hwif->set_pio_mode = &opti621_set_pio_mode;
 }
 
index 89d2363a1ebdafef4c3a868000e9199588bfe28f..1c8cb7797a4aea2a6800c22da7ab251fe9cb8163 100644 (file)
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
 #include <linux/hdreg.h>
-#include <linux/interrupt.h>
 #include <linux/pci.h>
 #include <linux/init.h>
 #include <linux/ide.h>
 
 #include <asm/io.h>
-#include <asm/irq.h>
 
 #ifdef CONFIG_PPC_PMAC
 #include <asm/prom.h>
@@ -149,6 +143,7 @@ static struct udma_timing {
 static void pdcnew_set_dma_mode(ide_drive_t *drive, const u8 speed)
 {
        ide_hwif_t *hwif        = HWIF(drive);
+       struct pci_dev *dev     = to_pci_dev(hwif->dev);
        u8 adj                  = (drive->dn & 1) ? 0x08 : 0x00;
 
        /*
@@ -159,7 +154,7 @@ static void pdcnew_set_dma_mode(ide_drive_t *drive, const u8 speed)
         * As we set up the PLL to output 133 MHz for UltraDMA/133 capable
         * chips, we must override the default register settings...
         */
-       if (max_dma_rate(hwif->pci_dev) == 4) {
+       if (max_dma_rate(dev) == 4) {
                u8 mode = speed & 0x07;
 
                if (speed >= XFER_UDMA_0) {
@@ -186,16 +181,17 @@ static void pdcnew_set_dma_mode(ide_drive_t *drive, const u8 speed)
 static void pdcnew_set_pio_mode(ide_drive_t *drive, const u8 pio)
 {
        ide_hwif_t *hwif = drive->hwif;
+       struct pci_dev *dev = to_pci_dev(hwif->dev);
        u8 adj = (drive->dn & 1) ? 0x08 : 0x00;
 
-       if (max_dma_rate(hwif->pci_dev) == 4) {
+       if (max_dma_rate(dev) == 4) {
                set_indexed_reg(hwif, 0x0c + adj, pio_timings[pio].reg0c);
                set_indexed_reg(hwif, 0x0d + adj, pio_timings[pio].reg0d);
                set_indexed_reg(hwif, 0x13 + adj, pio_timings[pio].reg13);
        }
 }
 
-static u8 pdcnew_cable_detect(ide_hwif_t *hwif)
+static u8 __devinit pdcnew_cable_detect(ide_hwif_t *hwif)
 {
        if (get_indexed_reg(hwif, 0x0b) & 0x04)
                return ATA_CBL_PATA40;
@@ -454,11 +450,7 @@ static void __devinit init_hwif_pdc202new(ide_hwif_t *hwif)
        hwif->quirkproc = &pdcnew_quirkproc;
        hwif->resetproc = &pdcnew_reset;
 
-       if (hwif->dma_base == 0)
-               return;
-
-       if (hwif->cbl != ATA_CBL_PATA40_SHORT)
-               hwif->cbl = pdcnew_cable_detect(hwif);
+       hwif->cable_detect = pdcnew_cable_detect;
 }
 
 static struct pci_dev * __devinit pdc20270_get_dev2(struct pci_dev *dev)
index 3a1e081fe3901c06e70dbaf7054238f28e90e10f..da4329790387c6019ceaf7b24d7394840b25fb1d 100644 (file)
@@ -1,6 +1,4 @@
 /*
- *  linux/drivers/ide/pci/pdc202xx_old.c       Version 0.52    Aug 27, 2007
- *
  *  Copyright (C) 1998-2002            Andre Hedrick <andre@linux-ide.org>
  *  Copyright (C) 2006-2007            MontaVista Software, Inc.
  *  Copyright (C) 2007                 Bartlomiej Zolnierkiewicz
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
 #include <linux/blkdev.h>
 #include <linux/hdreg.h>
-#include <linux/interrupt.h>
 #include <linux/pci.h>
 #include <linux/init.h>
 #include <linux/ide.h>
 
 #include <asm/io.h>
-#include <asm/irq.h>
 
 #define PDC202XX_DEBUG_DRIVE_INFO      0
 
@@ -66,7 +59,7 @@ static void pdc_old_disable_66MHz_clock(ide_hwif_t *);
 static void pdc202xx_set_mode(ide_drive_t *drive, const u8 speed)
 {
        ide_hwif_t *hwif        = HWIF(drive);
-       struct pci_dev *dev     = hwif->pci_dev;
+       struct pci_dev *dev     = to_pci_dev(hwif->dev);
        u8 drive_pci            = 0x60 + (drive->dn << 2);
 
        u8                      AP = 0, BP = 0, CP = 0;
@@ -142,11 +135,12 @@ static void pdc202xx_set_pio_mode(ide_drive_t *drive, const u8 pio)
        pdc202xx_set_mode(drive, XFER_PIO_0 + pio);
 }
 
-static u8 pdc202xx_old_cable_detect (ide_hwif_t *hwif)
+static u8 __devinit pdc2026x_old_cable_detect(ide_hwif_t *hwif)
 {
-       u16 CIS = 0, mask = (hwif->channel) ? (1<<11) : (1<<10);
+       struct pci_dev *dev = to_pci_dev(hwif->dev);
+       u16 CIS, mask = hwif->channel ? (1 << 11) : (1 << 10);
 
-       pci_read_config_word(hwif->pci_dev, 0x50, &CIS);
+       pci_read_config_word(dev, 0x50, &CIS);
 
        return (CIS & mask) ? ATA_CBL_PATA40 : ATA_CBL_PATA80;
 }
@@ -305,24 +299,26 @@ static unsigned int __devinit init_chipset_pdc202xx(struct pci_dev *dev,
 
 static void __devinit init_hwif_pdc202xx(ide_hwif_t *hwif)
 {
+       struct pci_dev *dev = to_pci_dev(hwif->dev);
+
        hwif->set_pio_mode = &pdc202xx_set_pio_mode;
        hwif->set_dma_mode = &pdc202xx_set_mode;
 
        hwif->quirkproc = &pdc202xx_quirkproc;
 
-       if (hwif->pci_dev->device != PCI_DEVICE_ID_PROMISE_20246)
+       if (dev->device != PCI_DEVICE_ID_PROMISE_20246) {
                hwif->resetproc = &pdc202xx_reset;
 
+               hwif->cable_detect = pdc2026x_old_cable_detect;
+       }
+
        if (hwif->dma_base == 0)
                return;
 
        hwif->dma_lost_irq = &pdc202xx_dma_lost_irq;
        hwif->dma_timeout = &pdc202xx_dma_timeout;
 
-       if (hwif->pci_dev->device != PCI_DEVICE_ID_PROMISE_20246) {
-               if (hwif->cbl != ATA_CBL_PATA40_SHORT)
-                       hwif->cbl = pdc202xx_old_cable_detect(hwif);
-
+       if (dev->device != PCI_DEVICE_ID_PROMISE_20246) {
                hwif->dma_start = &pdc202xx_old_ide_dma_start;
                hwif->ide_dma_end = &pdc202xx_old_ide_dma_end;
        } 
@@ -334,7 +330,7 @@ static void __devinit init_dma_pdc202xx(ide_hwif_t *hwif, unsigned long dmabase)
        u8 udma_speed_flag = 0, primary_mode = 0, secondary_mode = 0;
 
        if (hwif->channel) {
-               ide_setup_dma(hwif, dmabase, 8);
+               ide_setup_dma(hwif, dmabase);
                return;
        }
 
@@ -358,7 +354,7 @@ static void __devinit init_dma_pdc202xx(ide_hwif_t *hwif, unsigned long dmabase)
        }
 #endif /* CONFIG_PDC202XX_BURST */
 
-       ide_setup_dma(hwif, dmabase, 8);
+       ide_setup_dma(hwif, dmabase);
 }
 
 static void __devinit pdc202ata4_fixup_irq(struct pci_dev *dev,
index bd6d3f77d30c1c028f44263d4c437f8ac3f27491..decef0f476748ab0858360f3bc9fbfa647f96f06 100644 (file)
@@ -1,6 +1,4 @@
 /*
- *  linux/drivers/ide/pci/piix.c       Version 0.54    Sep 5, 2007
- *
  *  Copyright (C) 1998-1999 Andrzej Krzysztofowicz, Author and Maintainer
  *  Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org>
  *  Copyright (C) 2003 Red Hat Inc <alan@redhat.com>
@@ -8,53 +6,8 @@
  *
  *  May be copied or modified under the terms of the GNU General Public License
  *
- *  PIO mode setting function for Intel chipsets.
- *  For use instead of BIOS settings.
- *
- * 40-41
- * 42-43
- * 
- *                 41
- *                 43
- *
- * | PIO 0       | c0 | 80 | 0 |
- * | PIO 2 | SW2 | d0 | 90 | 4 |
- * | PIO 3 | MW1 | e1 | a1 | 9 |
- * | PIO 4 | MW2 | e3 | a3 | b |
- *
- * sitre = word40 & 0x4000; primary
- * sitre = word42 & 0x4000; secondary
- *
- * 44 8421|8421    hdd|hdb
- *
- * 48 8421         hdd|hdc|hdb|hda udma enabled
- *
- *    0001         hda
- *    0010         hdb
- *    0100         hdc
- *    1000         hdd
+ * Documentation:
  *
- * 4a 84|21        hdb|hda
- * 4b 84|21        hdd|hdc
- *
- *    ata-33/82371AB
- *    ata-33/82371EB
- *    ata-33/82801AB            ata-66/82801AA
- *    00|00 udma 0              00|00 reserved
- *    01|01 udma 1              01|01 udma 3
- *    10|10 udma 2              10|10 udma 4
- *    11|11 reserved            11|11 reserved
- *
- * 54 8421|8421    ata66 drive|ata66 enable
- *
- * pci_read_config_word(HWIF(drive)->pci_dev, 0x40, &reg40);
- * pci_read_config_word(HWIF(drive)->pci_dev, 0x42, &reg42);
- * pci_read_config_word(HWIF(drive)->pci_dev, 0x44, &reg44);
- * pci_read_config_byte(HWIF(drive)->pci_dev, 0x48, &reg48);
- * pci_read_config_word(HWIF(drive)->pci_dev, 0x4a, &reg4a);
- * pci_read_config_byte(HWIF(drive)->pci_dev, 0x54, &reg54);
- *
- * Documentation
  *     Publically available from Intel web site. Errata documentation
  * is also publically available. As an aide to anyone hacking on this
  * driver the list of errata that are relevant is below.going back to
 #include <linux/types.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/ioport.h>
 #include <linux/pci.h>
 #include <linux/hdreg.h>
 #include <linux/ide.h>
-#include <linux/delay.h>
 #include <linux/init.h>
 
 #include <asm/io.h>
@@ -116,7 +67,7 @@ static int no_piix_dma;
 static void piix_set_pio_mode(ide_drive_t *drive, const u8 pio)
 {
        ide_hwif_t *hwif        = HWIF(drive);
-       struct pci_dev *dev     = hwif->pci_dev;
+       struct pci_dev *dev     = to_pci_dev(hwif->dev);
        int is_slave            = drive->dn & 1;
        int master_port         = hwif->channel ? 0x42 : 0x40;
        int slave_port          = 0x44;
@@ -185,7 +136,7 @@ static void piix_set_pio_mode(ide_drive_t *drive, const u8 pio)
 static void piix_set_dma_mode(ide_drive_t *drive, const u8 speed)
 {
        ide_hwif_t *hwif        = HWIF(drive);
-       struct pci_dev *dev     = hwif->pci_dev;
+       struct pci_dev *dev     = to_pci_dev(hwif->dev);
        u8 maslave              = hwif->channel ? 0x42 : 0x40;
        int a_speed             = 3 << (drive->dn * 4);
        int u_flag              = 1 << drive->dn;
@@ -305,7 +256,7 @@ static const struct ich_laptop ich_laptop[] = {
 
 static u8 __devinit piix_cable_detect(ide_hwif_t *hwif)
 {
-       struct pci_dev *pdev = hwif->pci_dev;
+       struct pci_dev *pdev = to_pci_dev(hwif->dev);
        const struct ich_laptop *lap = &ich_laptop[0];
        u8 reg54h = 0, mask = hwif->channel ? 0xc0 : 0x30;
 
@@ -337,14 +288,11 @@ static void __devinit init_hwif_piix(ide_hwif_t *hwif)
        hwif->set_pio_mode = &piix_set_pio_mode;
        hwif->set_dma_mode = &piix_set_dma_mode;
 
+       hwif->cable_detect = piix_cable_detect;
+
        if (!hwif->dma_base)
                return;
 
-       if (hwif->ultra_mask & 0x78) {
-               if (hwif->cbl != ATA_CBL_PATA40_SHORT)
-                       hwif->cbl = piix_cable_detect(hwif);
-       }
-
        if (no_piix_dma)
                hwif->ultra_mask = hwif->mwdma_mask = hwif->swdma_mask = 0;
 }
index 6b10ae260fa29e148ae6f9f874400ce1d0997381..51676612f78f0d603e49e8456a8012ca54f58f06 100644 (file)
@@ -1,6 +1,4 @@
 /*
- *  linux/drivers/ide/pci/rz1000.c     Version 0.06    January 12, 2003
- *
  *  Copyright (C) 1995-1998  Linus Torvalds & author (see below)
  */
 
 #include <linux/types.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
 #include <linux/hdreg.h>
 #include <linux/pci.h>
 #include <linux/ide.h>
 #include <linux/init.h>
 
-#include <asm/io.h>
-
 static void __devinit init_hwif_rz1000 (ide_hwif_t *hwif)
 {
+       struct pci_dev *dev = to_pci_dev(hwif->dev);
        u16 reg;
-       struct pci_dev *dev = hwif->pci_dev;
 
        if (!pci_read_config_word (dev, 0x40, &reg) &&
            !pci_write_config_word(dev, 0x40, reg & 0xdfff)) {
@@ -42,8 +33,7 @@ static void __devinit init_hwif_rz1000 (ide_hwif_t *hwif)
        } else {
                if (hwif->mate)
                        hwif->mate->serialized = hwif->serialized = 1;
-               hwif->drives[0].no_unmask = 1;
-               hwif->drives[1].no_unmask = 1;
+               hwif->host_flags |= IDE_HFLAG_NO_UNMASK_IRQS;
                printk(KERN_INFO "%s: serialized, disabled unmasking "
                        "(buggy RZ1000/RZ1001)\n", hwif->name);
        }
index 32fdf53379f5a5bf6cd817628c6543a4dba71182..561aa47c7720fafa38c615a4fa36d0dd62dba76d 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * linux/drivers/ide/pci/sc1200.c              Version 0.97    Aug 3 2007
- *
  * Copyright (C) 2000-2002             Mark Lord <mlord@pobox.com>
  * Copyright (C)      2007             Bartlomiej Zolnierkiewicz
  *
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
 #include <linux/hdreg.h>
-#include <linux/interrupt.h>
 #include <linux/pci.h>
 #include <linux/init.h>
 #include <linux/ide.h>
 #include <linux/pm.h>
+
 #include <asm/io.h>
-#include <asm/irq.h>
 
 #define SC1200_REV_A   0x00
 #define SC1200_REV_B1  0x01
@@ -87,7 +79,7 @@ static const unsigned int sc1200_pio_timings[4][5] =
 static void sc1200_tunepio(ide_drive_t *drive, u8 pio)
 {
        ide_hwif_t *hwif = drive->hwif;
-       struct pci_dev *pdev = hwif->pci_dev;
+       struct pci_dev *pdev = to_pci_dev(hwif->dev);
        unsigned int basereg = hwif->channel ? 0x50 : 0x40, format = 0;
 
        pci_read_config_dword(pdev, basereg + 4, &format);
@@ -130,6 +122,7 @@ out:
 static void sc1200_set_dma_mode(ide_drive_t *drive, const u8 mode)
 {
        ide_hwif_t              *hwif = HWIF(drive);
+       struct pci_dev          *dev = to_pci_dev(hwif->dev);
        int                     unit = drive->select.b.unit;
        unsigned int            reg, timings;
        unsigned short          pci_clock;
@@ -160,12 +153,11 @@ static void sc1200_set_dma_mode(ide_drive_t *drive, const u8 mode)
                timings = mwdma_timing[pci_clock][mode - XFER_MW_DMA_0];
 
        if (unit == 0) {                        /* are we configuring drive0? */
-               pci_read_config_dword(hwif->pci_dev, basereg+4, &reg);
+               pci_read_config_dword(dev, basereg + 4, &reg);
                timings |= reg & 0x80000000;    /* preserve PIO format bit */
-               pci_write_config_dword(hwif->pci_dev, basereg+4, timings);
-       } else {
-               pci_write_config_dword(hwif->pci_dev, basereg+12, timings);
-       }
+               pci_write_config_dword(dev, basereg + 4, timings);
+       } else
+               pci_write_config_dword(dev, basereg + 12, timings);
 }
 
 /*  Replacement for the standard ide_dma_end action in
index 24a85bbcd2a6c3e1db2df10355274fef707fe465..238e3e181e873f0f98566e72f50e67e6771d54c1 100644 (file)
@@ -594,7 +594,7 @@ static int __devinit init_setup_scc(struct pci_dev *dev,
 
 static void __devinit init_mmio_iops_scc(ide_hwif_t *hwif)
 {
-       struct pci_dev *dev = hwif->pci_dev;
+       struct pci_dev *dev = to_pci_dev(hwif->dev);
        struct scc_ports *ports = pci_get_drvdata(dev);
        unsigned long dma_base = ports->dma;
 
@@ -620,7 +620,7 @@ static void __devinit init_mmio_iops_scc(ide_hwif_t *hwif)
        hwif->io_ports[IDE_STATUS_OFFSET] = dma_base + 0x3c;
        hwif->io_ports[IDE_CONTROL_OFFSET] = dma_base + 0x40;
 
-       hwif->irq = hwif->pci_dev->irq;
+       hwif->irq = dev->irq;
        hwif->dma_base = dma_base;
        hwif->config_data = ports->ctl;
        hwif->mmio = 1;
@@ -636,13 +636,19 @@ static void __devinit init_mmio_iops_scc(ide_hwif_t *hwif)
 
 static void __devinit init_iops_scc(ide_hwif_t *hwif)
 {
-       struct pci_dev *dev =  hwif->pci_dev;
+       struct pci_dev *dev = to_pci_dev(hwif->dev);
+
        hwif->hwif_data = NULL;
        if (pci_get_drvdata(dev) == NULL)
                return;
        init_mmio_iops_scc(hwif);
 }
 
+static u8 __devinit scc_cable_detect(ide_hwif_t *hwif)
+{
+       return ATA_CBL_PATA80;
+}
+
 /**
  *     init_hwif_scc   -       set up hwif
  *     @hwif: interface to set up
@@ -677,8 +683,7 @@ static void __devinit init_hwif_scc(ide_hwif_t *hwif)
        else
                hwif->ultra_mask = ATA_UDMA5; /* 100MHz */
 
-       /* we support 80c cable only. */
-       hwif->cbl = ATA_CBL_PATA80;
+       hwif->cable_detect = scc_cable_detect;
 }
 
 #define DECLARE_SCC_DEV(name_str)                      \
@@ -726,14 +731,12 @@ static void __devexit scc_remove(struct pci_dev *dev)
        unsigned long dma_size = pci_resource_len(dev, 1);
 
        if (hwif->dmatable_cpu) {
-               pci_free_consistent(hwif->pci_dev,
-                                   PRD_ENTRIES * PRD_BYTES,
-                                   hwif->dmatable_cpu,
-                                   hwif->dmatable_dma);
+               pci_free_consistent(dev, PRD_ENTRIES * PRD_BYTES,
+                                   hwif->dmatable_cpu, hwif->dmatable_dma);
                hwif->dmatable_cpu = NULL;
        }
 
-       ide_unregister(hwif->index);
+       ide_unregister(hwif->index, 0, 0);
 
        hwif->chipset = ide_unknown;
        iounmap((void*)ports->dma);
index 877c09bf482957c3ee067724a35ee535fde7bc31..c11880b0709f711c4ee49ef2edc376f8e57e1df6 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * linux/drivers/ide/pci/serverworks.c         Version 0.22    Jun 27 2007
- *
  * Copyright (C) 1998-2000 Michel Aubry
  * Copyright (C) 1998-2000 Andrzej Krzysztofowicz
  * Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org>
 #include <linux/types.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/ioport.h>
 #include <linux/pci.h>
 #include <linux/hdreg.h>
 #include <linux/ide.h>
 #include <linux/init.h>
-#include <linux/delay.h>
 
 #include <asm/io.h>
 
@@ -67,7 +63,7 @@ static int check_in_drive_lists (ide_drive_t *drive, const char **list)
 
 static u8 svwks_udma_filter(ide_drive_t *drive)
 {
-       struct pci_dev *dev     = HWIF(drive)->pci_dev;
+       struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
        u8 mask = 0;
 
        if (dev->device == PCI_DEVICE_ID_SERVERWORKS_HT1000IDE)
@@ -130,7 +126,7 @@ static void svwks_set_pio_mode(ide_drive_t *drive, const u8 pio)
        static const u8 pio_modes[] = { 0x5d, 0x47, 0x34, 0x22, 0x20 };
        static const u8 drive_pci[] = { 0x41, 0x40, 0x43, 0x42 };
 
-       struct pci_dev *dev = drive->hwif->pci_dev;
+       struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
 
        pci_write_config_byte(dev, drive_pci[drive->dn], pio_modes[pio]);
 
@@ -153,7 +149,7 @@ static void svwks_set_dma_mode(ide_drive_t *drive, const u8 speed)
        static const u8 drive_pci2[]            = { 0x45, 0x44, 0x47, 0x46 };
 
        ide_hwif_t *hwif        = HWIF(drive);
-       struct pci_dev *dev     = hwif->pci_dev;
+       struct pci_dev *dev     = to_pci_dev(hwif->dev);
        u8 unit                 = (drive->select.b.unit & 0x01);
 
        u8 ultra_enable  = 0, ultra_timing = 0, dma_timing = 0;
@@ -287,7 +283,8 @@ static u8 __devinit ata66_svwks_svwks(ide_hwif_t *hwif)
  */
 static u8 __devinit ata66_svwks_dell(ide_hwif_t *hwif)
 {
-       struct pci_dev *dev = hwif->pci_dev;
+       struct pci_dev *dev = to_pci_dev(hwif->dev);
+
        if (dev->subsystem_vendor == PCI_VENDOR_ID_DELL &&
            dev->vendor == PCI_VENDOR_ID_SERVERWORKS &&
            (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE ||
@@ -305,7 +302,8 @@ static u8 __devinit ata66_svwks_dell(ide_hwif_t *hwif)
  */
 static u8 __devinit ata66_svwks_cobalt(ide_hwif_t *hwif)
 {
-       struct pci_dev *dev = hwif->pci_dev;
+       struct pci_dev *dev = to_pci_dev(hwif->dev);
+
        if (dev->subsystem_vendor == PCI_VENDOR_ID_SUN &&
            dev->vendor == PCI_VENDOR_ID_SERVERWORKS &&
            dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE)
@@ -316,7 +314,7 @@ static u8 __devinit ata66_svwks_cobalt(ide_hwif_t *hwif)
 
 static u8 __devinit ata66_svwks(ide_hwif_t *hwif)
 {
-       struct pci_dev *dev = hwif->pci_dev;
+       struct pci_dev *dev = to_pci_dev(hwif->dev);
 
        /* Server Works */
        if (dev->subsystem_vendor == PCI_VENDOR_ID_SERVERWORKS)
@@ -340,17 +338,14 @@ static u8 __devinit ata66_svwks(ide_hwif_t *hwif)
 
 static void __devinit init_hwif_svwks (ide_hwif_t *hwif)
 {
+       struct pci_dev *dev = to_pci_dev(hwif->dev);
+
        hwif->set_pio_mode = &svwks_set_pio_mode;
        hwif->set_dma_mode = &svwks_set_dma_mode;
        hwif->udma_filter = &svwks_udma_filter;
 
-       if (!hwif->dma_base)
-               return;
-
-       if (hwif->pci_dev->device != PCI_DEVICE_ID_SERVERWORKS_OSB4IDE) {
-               if (hwif->cbl != ATA_CBL_PATA40_SHORT)
-                       hwif->cbl = ata66_svwks(hwif);
-       }
+       if (dev->device != PCI_DEVICE_ID_SERVERWORKS_OSB4IDE)
+               hwif->cable_detect = ata66_svwks;
 }
 
 #define IDE_HFLAGS_SVWKS \
@@ -418,7 +413,9 @@ static int __devinit svwks_init_one(struct pci_dev *dev, const struct pci_device
 
        d = serverworks_chipsets[idx];
 
-       if (idx == 2 || idx == 3) {
+       if (idx == 1)
+               d.host_flags |= IDE_HFLAG_CLEAR_SIMPLEX;
+       else if (idx == 2 || idx == 3) {
                if ((PCI_FUNC(dev->devfn) & 1) == 0) {
                        if (pci_resource_start(dev, 0) != 0x01f1)
                                d.host_flags &= ~IDE_HFLAG_BOOTABLE;
index 9e0be7d549800e2a4304a99fb54d75b74d0fdcf2..054626497be49405cd5e9ae95952196040564689 100644 (file)
@@ -25,8 +25,6 @@
 #include <linux/hdreg.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
 #include <linux/ioport.h>
 #include <linux/blkdev.h>
 #include <linux/scatterlist.h>
@@ -159,6 +157,7 @@ sgiioc4_clearirq(ide_drive_t * drive)
                }
 
                if (intr_reg & 0x02) {
+                       struct pci_dev *dev = to_pci_dev(hwif->dev);
                        /* Error when transferring DMA data on PCI bus */
                        u32 pci_err_addr_low, pci_err_addr_high,
                            pci_stat_cmd_reg;
@@ -167,7 +166,7 @@ sgiioc4_clearirq(ide_drive_t * drive)
                                readl((void __iomem *)hwif->io_ports[IDE_IRQ_OFFSET]);
                        pci_err_addr_high =
                                readl((void __iomem *)(hwif->io_ports[IDE_IRQ_OFFSET] + 4));
-                       pci_read_config_dword(hwif->pci_dev, PCI_COMMAND,
+                       pci_read_config_dword(dev, PCI_COMMAND,
                                              &pci_stat_cmd_reg);
                        printk(KERN_ERR
                               "%s(%s) : PCI Bus Error when doing DMA:"
@@ -178,8 +177,7 @@ sgiioc4_clearirq(ide_drive_t * drive)
                               __FUNCTION__, drive->name,
                               pci_err_addr_high, pci_err_addr_low);
                        /* Clear the PCI Error indicator */
-                       pci_write_config_dword(hwif->pci_dev, PCI_COMMAND,
-                                              0x00000146);
+                       pci_write_config_dword(dev, PCI_COMMAND, 0x00000146);
                }
 
                /* Clear the Interrupt, Error bits on the IOC4 */
@@ -334,6 +332,7 @@ sgiioc4_INB(unsigned long port)
 static int __devinit
 ide_dma_sgiioc4(ide_hwif_t * hwif, unsigned long dma_base)
 {
+       struct pci_dev *dev = to_pci_dev(hwif->dev);
        void __iomem *virt_dma_base;
        int num_ports = sizeof (ioc4_dma_regs_t);
        void *pad;
@@ -359,7 +358,7 @@ ide_dma_sgiioc4(ide_hwif_t * hwif, unsigned long dma_base)
        }
        hwif->dma_base = (unsigned long) virt_dma_base;
 
-       hwif->dmatable_cpu = pci_alloc_consistent(hwif->pci_dev,
+       hwif->dmatable_cpu = pci_alloc_consistent(dev,
                                          IOC4_PRD_ENTRIES * IOC4_PRD_BYTES,
                                          &hwif->dmatable_dma);
 
@@ -368,7 +367,7 @@ ide_dma_sgiioc4(ide_hwif_t * hwif, unsigned long dma_base)
 
        hwif->sg_max_nents = IOC4_PRD_ENTRIES;
 
-       pad = pci_alloc_consistent(hwif->pci_dev, IOC4_IDE_CACHELINE_SIZE,
+       pad = pci_alloc_consistent(dev, IOC4_IDE_CACHELINE_SIZE,
                                   (dma_addr_t *) &(hwif->dma_status));
 
        if (pad) {
@@ -376,8 +375,7 @@ ide_dma_sgiioc4(ide_hwif_t * hwif, unsigned long dma_base)
                return 0;
        }
 
-       pci_free_consistent(hwif->pci_dev,
-                           IOC4_PRD_ENTRIES * IOC4_PRD_BYTES,
+       pci_free_consistent(dev, IOC4_PRD_ENTRIES * IOC4_PRD_BYTES,
                            hwif->dmatable_cpu, hwif->dmatable_dma);
        printk(KERN_INFO
               "%s() -- Error! Unable to allocate DMA Maps for drive %s\n",
@@ -517,8 +515,7 @@ sgiioc4_build_dma_table(ide_drive_t * drive, struct request *rq, int ddir)
        }
 
 use_pio_instead:
-       pci_unmap_sg(hwif->pci_dev, hwif->sg_table, hwif->sg_nents,
-                    hwif->sg_dma_direction);
+       ide_destroy_dmatable(drive);
 
        return 0;               /* revert to PIO for this request */
 }
@@ -556,7 +553,6 @@ static void __devinit
 ide_init_sgiioc4(ide_hwif_t * hwif)
 {
        hwif->mmio = 1;
-       hwif->pio_mask = 0x00;
        hwif->set_pio_mode = NULL; /* Sets timing for PIO mode */
        hwif->set_dma_mode = &sgiioc4_set_dma_mode;
        hwif->selectproc = NULL;/* Use the default routine to select drive */
@@ -573,8 +569,6 @@ ide_init_sgiioc4(ide_hwif_t * hwif)
        if (hwif->dma_base == 0)
                return;
 
-       hwif->mwdma_mask = ATA_MWDMA2_ONLY;
-
        hwif->dma_host_set = &sgiioc4_dma_host_set;
        hwif->dma_setup = &sgiioc4_ide_dma_setup;
        hwif->dma_start = &sgiioc4_ide_dma_start;
@@ -584,6 +578,13 @@ ide_init_sgiioc4(ide_hwif_t * hwif)
        hwif->dma_timeout = &ide_dma_timeout;
 }
 
+static const struct ide_port_info sgiioc4_port_info __devinitdata = {
+       .chipset                = ide_pci,
+       .host_flags             = IDE_HFLAG_NO_DMA | /* no SFF-style DMA */
+                                 IDE_HFLAG_NO_AUTOTUNE,
+       .mwdma_mask             = ATA_MWDMA2_ONLY,
+};
+
 static int __devinit
 sgiioc4_ide_setup_pci_device(struct pci_dev *dev)
 {
@@ -594,6 +595,7 @@ sgiioc4_ide_setup_pci_device(struct pci_dev *dev)
        int h;
        u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
        hw_regs_t hw;
+       struct ide_port_info d = sgiioc4_port_info;
 
        /*
         * Find an empty HWIF; if none available, return -ENOMEM.
@@ -641,8 +643,7 @@ sgiioc4_ide_setup_pci_device(struct pci_dev *dev)
        hw.dev = &dev->dev;
        ide_init_port_hw(hwif, &hw);
 
-       hwif->pci_dev = dev;
-       hwif->channel = 0;      /* Single Channel chip */
+       hwif->dev = &dev->dev;
 
        /* The IOC4 uses MMIO rather than Port IO. */
        default_hwif_mmiops(hwif);
@@ -650,15 +651,17 @@ sgiioc4_ide_setup_pci_device(struct pci_dev *dev)
        /* Initializing chipset IRQ Registers */
        writel(0x03, (void __iomem *)(irqport + IOC4_INTR_SET * 4));
 
-       if (dma_base == 0 || ide_dma_sgiioc4(hwif, dma_base))
+       if (dma_base == 0 || ide_dma_sgiioc4(hwif, dma_base)) {
                printk(KERN_INFO "%s: %s Bus-Master DMA disabled\n",
                                 hwif->name, DRV_NAME);
+               d.mwdma_mask = 0;
+       }
 
        ide_init_sgiioc4(hwif);
 
        idx[0] = hwif->index;
 
-       if (ide_device_add(idx))
+       if (ide_device_add(idx, &d))
                return -EIO;
 
        return 0;
index 908f37b4e0ee140f7dca78f6c6e5c6de2efc3484..cc4be9621bc0ec04048f9811183283ece1d55e10 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * linux/drivers/ide/pci/siimage.c             Version 1.19    Nov 16 2007
- *
  * Copyright (C) 2001-2002     Andre Hedrick <andre@linux-ide.org>
  * Copyright (C) 2003          Red Hat <alan@redhat.com>
  * Copyright (C) 2007          MontaVista Software, Inc.
@@ -41,7 +39,6 @@
 #include <linux/types.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/delay.h>
 #include <linux/hdreg.h>
 #include <linux/ide.h>
 #include <linux/init.h>
@@ -79,7 +76,7 @@ static int pdev_is_sata(struct pci_dev *pdev)
  
 static inline int is_sata(ide_hwif_t *hwif)
 {
-       return pdev_is_sata(hwif->pci_dev);
+       return pdev_is_sata(to_pci_dev(hwif->dev));
 }
 
 /**
@@ -140,13 +137,14 @@ static inline unsigned long siimage_seldev(ide_drive_t *drive, int r)
 static u8 sil_pata_udma_filter(ide_drive_t *drive)
 {
        ide_hwif_t *hwif = drive->hwif;
+       struct pci_dev *dev = to_pci_dev(hwif->dev);
        unsigned long base = (unsigned long) hwif->hwif_data;
        u8 mask = 0, scsc = 0;
 
        if (hwif->mmio)
                scsc = hwif->INB(base + 0x4A);
        else
-               pci_read_config_byte(hwif->pci_dev, 0x8A, &scsc);
+               pci_read_config_byte(dev, 0x8A, &scsc);
 
        if ((scsc & 0x30) == 0x10)      /* 133 */
                mask = ATA_UDMA6;
@@ -219,19 +217,21 @@ static void sil_set_pio_mode(ide_drive_t *drive, u8 pio)
                mode |= (unit ? 0x10 : 0x01);
                hwif->OUTB(mode, base + addr_mask);
        } else {
-               pci_write_config_word(hwif->pci_dev, addr, speedp);
-               pci_write_config_word(hwif->pci_dev, tfaddr, speedt);
-               pci_read_config_word(hwif->pci_dev, tfaddr-2, &speedp);
+               struct pci_dev *dev = to_pci_dev(hwif->dev);
+
+               pci_write_config_word(dev, addr, speedp);
+               pci_write_config_word(dev, tfaddr, speedt);
+               pci_read_config_word(dev, tfaddr - 2, &speedp);
                speedp &= ~0x200;
                /* Set IORDY for mode 3 or 4 */
                if (pio > 2)
                        speedp |= 0x200;
-               pci_write_config_word(hwif->pci_dev, tfaddr-2, speedp);
+               pci_write_config_word(dev, tfaddr - 2, speedp);
 
-               pci_read_config_byte(hwif->pci_dev, addr_mask, &mode);
+               pci_read_config_byte(dev, addr_mask, &mode);
                mode &= ~(unit ? 0x30 : 0x03);
                mode |= (unit ? 0x10 : 0x01);
-               pci_write_config_byte(hwif->pci_dev, addr_mask, mode);
+               pci_write_config_byte(dev, addr_mask, mode);
        }
 }
 
@@ -250,6 +250,7 @@ static void sil_set_dma_mode(ide_drive_t *drive, const u8 speed)
        u16 dma[]               = { 0x2208, 0x10C2, 0x10C1 };
 
        ide_hwif_t *hwif        = HWIF(drive);
+       struct pci_dev *dev     = to_pci_dev(hwif->dev);
        u16 ultra = 0, multi    = 0;
        u8 mode = 0, unit       = drive->select.b.unit;
        unsigned long base      = (unsigned long)hwif->hwif_data;
@@ -266,10 +267,10 @@ static void sil_set_dma_mode(ide_drive_t *drive, const u8 speed)
                multi = hwif->INW(ma);
                ultra = hwif->INW(ua);
        } else {
-               pci_read_config_byte(hwif->pci_dev, 0x8A, &scsc);
-               pci_read_config_byte(hwif->pci_dev, addr_mask, &mode);
-               pci_read_config_word(hwif->pci_dev, ma, &multi);
-               pci_read_config_word(hwif->pci_dev, ua, &ultra);
+               pci_read_config_byte(dev, 0x8A, &scsc);
+               pci_read_config_byte(dev, addr_mask, &mode);
+               pci_read_config_word(dev, ma, &multi);
+               pci_read_config_word(dev, ua, &ultra);
        }
 
        mode &= ~((unit) ? 0x30 : 0x03);
@@ -293,9 +294,9 @@ static void sil_set_dma_mode(ide_drive_t *drive, const u8 speed)
                hwif->OUTW(multi, ma);
                hwif->OUTW(ultra, ua);
        } else {
-               pci_write_config_byte(hwif->pci_dev, addr_mask, mode);
-               pci_write_config_word(hwif->pci_dev, ma, multi);
-               pci_write_config_word(hwif->pci_dev, ua, ultra);
+               pci_write_config_byte(dev, addr_mask, mode);
+               pci_write_config_word(dev, ma, multi);
+               pci_write_config_word(dev, ua, ultra);
        }
 }
 
@@ -303,6 +304,7 @@ static void sil_set_dma_mode(ide_drive_t *drive, const u8 speed)
 static int siimage_io_ide_dma_test_irq (ide_drive_t *drive)
 {
        ide_hwif_t *hwif        = HWIF(drive);
+       struct pci_dev *dev     = to_pci_dev(hwif->dev);
        u8 dma_altstat          = 0;
        unsigned long addr      = siimage_selreg(hwif, 1);
 
@@ -311,7 +313,7 @@ static int siimage_io_ide_dma_test_irq (ide_drive_t *drive)
                return 1;
 
        /* return 1 if Device INTR asserted */
-       pci_read_config_byte(hwif->pci_dev, addr, &dma_altstat);
+       pci_read_config_byte(dev, addr, &dma_altstat);
        if (dma_altstat & 8)
                return 0;       //return 1;
        return 0;
@@ -329,15 +331,18 @@ static int siimage_mmio_ide_dma_test_irq (ide_drive_t *drive)
 {
        ide_hwif_t *hwif        = HWIF(drive);
        unsigned long addr      = siimage_selreg(hwif, 0x1);
+       void __iomem *sata_error_addr
+               = (void __iomem *)hwif->sata_scr[SATA_ERROR_OFFSET];
 
-       if (SATA_ERROR_REG) {
+       if (sata_error_addr) {
                unsigned long base = (unsigned long)hwif->hwif_data;
-
                u32 ext_stat = readl((void __iomem *)(base + 0x10));
                u8 watchdog = 0;
+
                if (ext_stat & ((hwif->channel) ? 0x40 : 0x10)) {
-                       u32 sata_error = readl((void __iomem *)SATA_ERROR_REG);
-                       writel(sata_error, (void __iomem *)SATA_ERROR_REG);
+                       u32 sata_error = readl(sata_error_addr);
+
+                       writel(sata_error, sata_error_addr);
                        watchdog = (sata_error & 0x00680000) ? 1 : 0;
                        printk(KERN_WARNING "%s: sata_error = 0x%08x, "
                                "watchdog = %d, %s\n",
@@ -377,13 +382,14 @@ static int siimage_mmio_ide_dma_test_irq (ide_drive_t *drive)
 static int sil_sata_busproc(ide_drive_t * drive, int state)
 {
        ide_hwif_t *hwif        = HWIF(drive);
+       struct pci_dev *dev     = to_pci_dev(hwif->dev);
        u32 stat_config         = 0;
        unsigned long addr      = siimage_selreg(hwif, 0);
 
        if (hwif->mmio)
                stat_config = readl((void __iomem *)addr);
        else
-               pci_read_config_dword(hwif->pci_dev, addr, &stat_config);
+               pci_read_config_dword(dev, addr, &stat_config);
 
        switch (state) {
                case BUSSTATE_ON:
@@ -415,13 +421,17 @@ static int sil_sata_busproc(ide_drive_t * drive, int state)
 
 static int sil_sata_reset_poll(ide_drive_t *drive)
 {
-       if (SATA_STATUS_REG) {
-               ide_hwif_t *hwif        = HWIF(drive);
+       ide_hwif_t *hwif = drive->hwif;
+       void __iomem *sata_status_addr
+               = (void __iomem *)hwif->sata_scr[SATA_STATUS_OFFSET];
+
+       if (sata_status_addr) {
+               /* SATA Status is available only when in MMIO mode */
+               u32 sata_stat = readl(sata_status_addr);
 
-               /* SATA_STATUS_REG is valid only when in MMIO mode */
-               if ((readl((void __iomem *)SATA_STATUS_REG) & 0x03) != 0x03) {
+               if ((sata_stat & 0x03) != 0x03) {
                        printk(KERN_WARNING "%s: reset phy dead, status=0x%08x\n",
-                               hwif->name, readl((void __iomem *)SATA_STATUS_REG));
+                                           hwif->name, sata_stat);
                        HWGROUP(drive)->polling = 0;
                        return ide_started;
                }
@@ -643,7 +653,7 @@ static unsigned int __devinit init_chipset_siimage(struct pci_dev *dev, const ch
 
 static void __devinit init_mmio_iops_siimage(ide_hwif_t *hwif)
 {
-       struct pci_dev *dev     = hwif->pci_dev;
+       struct pci_dev *dev     = to_pci_dev(hwif->dev);
        void *addr              = pci_get_drvdata(dev);
        u8 ch                   = hwif->channel;
        hw_regs_t               hw;
@@ -694,9 +704,6 @@ static void __devinit init_mmio_iops_siimage(ide_hwif_t *hwif)
                hwif->sata_scr[SATA_STATUS_OFFSET]      = base + 0x104;
                hwif->sata_scr[SATA_ERROR_OFFSET]       = base + 0x108;
                hwif->sata_scr[SATA_CONTROL_OFFSET]     = base + 0x100;
-               hwif->sata_misc[SATA_MISC_OFFSET]       = base + 0x140;
-               hwif->sata_misc[SATA_PHY_OFFSET]        = base + 0x144;
-               hwif->sata_misc[SATA_IEN_OFFSET]        = base + 0x148;
        }
 
        memcpy(hwif->io_ports, hw.io_ports, sizeof(hwif->io_ports));
@@ -756,12 +763,14 @@ static void __devinit sil_quirkproc(ide_drive_t *drive)
 
 static void __devinit init_iops_siimage(ide_hwif_t *hwif)
 {
+       struct pci_dev *dev = to_pci_dev(hwif->dev);
+
        hwif->hwif_data = NULL;
 
        /* Pessimal until we finish probing */
        hwif->rqsize = 15;
 
-       if (pci_get_drvdata(hwif->pci_dev) == NULL)
+       if (pci_get_drvdata(dev) == NULL)
                return;
 
        init_mmio_iops_siimage(hwif);
@@ -777,11 +786,12 @@ static void __devinit init_iops_siimage(ide_hwif_t *hwif)
 
 static u8 __devinit ata66_siimage(ide_hwif_t *hwif)
 {
+       struct pci_dev *dev = to_pci_dev(hwif->dev);
        unsigned long addr = siimage_selreg(hwif, 0);
        u8 ata66 = 0;
 
-       if (pci_get_drvdata(hwif->pci_dev) == NULL)
-               pci_read_config_byte(hwif->pci_dev, addr, &ata66);
+       if (pci_get_drvdata(dev) == NULL)
+               pci_read_config_byte(dev, addr, &ata66);
        else
                ata66 = hwif->INB(addr);
 
@@ -820,15 +830,14 @@ static void __devinit init_hwif_siimage(ide_hwif_t *hwif)
        } else
                hwif->udma_filter = &sil_pata_udma_filter;
 
+       hwif->cable_detect = ata66_siimage;
+
        if (hwif->dma_base == 0)
                return;
 
        if (sata)
                hwif->host_flags |= IDE_HFLAG_NO_ATAPI_DMA;
 
-       if (hwif->cbl != ATA_CBL_PATA40_SHORT)
-               hwif->cbl = ata66_siimage(hwif);
-
        if (hwif->mmio) {
                hwif->ide_dma_test_irq = &siimage_mmio_ide_dma_test_irq;
        } else {
index 85d36996e6af768ed2f23be7ab2bd23968eb6ac4..512bb4c1fd5cdab9a2005fff535ea0838d3d2a90 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * linux/drivers/ide/pci/sis5513.c     Version 0.31    Aug 9, 2007
- *
  * Copyright (C) 1999-2000     Andre Hedrick <andre@linux-ide.org>
  * Copyright (C) 2002          Lionel Bouton <Lionel.Bouton@inet6.fr>, Maintainer
  * Copyright (C) 2003          Vojtech Pavlik <vojtech@suse.cz>
 #include <linux/types.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
 #include <linux/hdreg.h>
-
-#include <linux/interrupt.h>
 #include <linux/pci.h>
 #include <linux/init.h>
 #include <linux/ide.h>
 
-#include <asm/irq.h>
-
 #include "ide-timing.h"
 
 /* registers layout and init values are chipset family dependant */
@@ -197,7 +186,7 @@ static char* chipset_capability[] = {
 
 static u8 sis_ata133_get_base(ide_drive_t *drive)
 {
-       struct pci_dev *dev = drive->hwif->pci_dev;
+       struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
        u32 reg54 = 0;
 
        pci_read_config_dword(dev, 0x54, &reg54);
@@ -207,7 +196,7 @@ static u8 sis_ata133_get_base(ide_drive_t *drive)
 
 static void sis_ata16_program_timings(ide_drive_t *drive, const u8 mode)
 {
-       struct pci_dev *dev = drive->hwif->pci_dev;
+       struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
        u16 t1 = 0;
        u8 drive_pci = 0x40 + drive->dn * 2;
 
@@ -230,7 +219,7 @@ static void sis_ata16_program_timings(ide_drive_t *drive, const u8 mode)
 
 static void sis_ata100_program_timings(ide_drive_t *drive, const u8 mode)
 {
-       struct pci_dev *dev = drive->hwif->pci_dev;
+       struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
        u8 t1, drive_pci = 0x40 + drive->dn * 2;
 
        /* timing bits: 7:4 active 3:0 recovery */
@@ -253,7 +242,7 @@ static void sis_ata100_program_timings(ide_drive_t *drive, const u8 mode)
 
 static void sis_ata133_program_timings(ide_drive_t *drive, const u8 mode)
 {
-       struct pci_dev *dev = drive->hwif->pci_dev;
+       struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
        u32 t1 = 0;
        u8 drive_pci = sis_ata133_get_base(drive), clk, idx;
 
@@ -286,7 +275,7 @@ static void sis_program_timings(ide_drive_t *drive, const u8 mode)
 static void config_drive_art_rwp (ide_drive_t *drive)
 {
        ide_hwif_t *hwif        = HWIF(drive);
-       struct pci_dev *dev     = hwif->pci_dev;
+       struct pci_dev *dev     = to_pci_dev(hwif->dev);
        u8 reg4bh               = 0;
        u8 rw_prefetch          = 0;
 
@@ -307,7 +296,7 @@ static void sis_set_pio_mode(ide_drive_t *drive, const u8 pio)
 
 static void sis_ata133_program_udma_timings(ide_drive_t *drive, const u8 mode)
 {
-       struct pci_dev *dev = drive->hwif->pci_dev;
+       struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
        u32 regdw = 0;
        u8 drive_pci = sis_ata133_get_base(drive), clk, idx;
 
@@ -326,7 +315,7 @@ static void sis_ata133_program_udma_timings(ide_drive_t *drive, const u8 mode)
 
 static void sis_ata33_program_udma_timings(ide_drive_t *drive, const u8 mode)
 {
-       struct pci_dev *dev = drive->hwif->pci_dev;
+       struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
        u8 drive_pci = 0x40 + drive->dn * 2, reg = 0, i = chipset_family;
 
        pci_read_config_byte(dev, drive_pci + 1, &reg);
@@ -359,7 +348,7 @@ static void sis_set_dma_mode(ide_drive_t *drive, const u8 speed)
 
 static u8 sis5513_ata133_udma_filter(ide_drive_t *drive)
 {
-       struct pci_dev *dev = drive->hwif->pci_dev;
+       struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
        u32 regdw = 0;
        u8 drive_pci = sis_ata133_get_base(drive);
 
@@ -530,7 +519,7 @@ static const struct sis_laptop sis_laptop[] = {
 
 static u8 __devinit ata66_sis5513(ide_hwif_t *hwif)
 {
-       struct pci_dev *pdev = hwif->pci_dev;
+       struct pci_dev *pdev = to_pci_dev(hwif->dev);
        const struct sis_laptop *lap = &sis_laptop[0];
        u8 ata66 = 0;
 
@@ -545,12 +534,12 @@ static u8 __devinit ata66_sis5513(ide_hwif_t *hwif)
        if (chipset_family >= ATA_133) {
                u16 regw = 0;
                u16 reg_addr = hwif->channel ? 0x52: 0x50;
-               pci_read_config_word(hwif->pci_dev, reg_addr, &regw);
+               pci_read_config_word(pdev, reg_addr, &regw);
                ata66 = (regw & 0x8000) ? 0 : 1;
        } else if (chipset_family >= ATA_66) {
                u8 reg48h = 0;
                u8 mask = hwif->channel ? 0x20 : 0x10;
-               pci_read_config_byte(hwif->pci_dev, 0x48, &reg48h);
+               pci_read_config_byte(pdev, 0x48, &reg48h);
                ata66 = (reg48h & mask) ? 0 : 1;
        }
 
@@ -567,13 +556,12 @@ static void __devinit init_hwif_sis5513 (ide_hwif_t *hwif)
        if (chipset_family >= ATA_133)
                hwif->udma_filter = sis5513_ata133_udma_filter;
 
+       hwif->cable_detect = ata66_sis5513;
+
        if (hwif->dma_base == 0)
                return;
 
        hwif->ultra_mask = udma_rates[chipset_family];
-
-       if (hwif->cbl != ATA_CBL_PATA40_SHORT)
-               hwif->cbl = ata66_sis5513(hwif);
 }
 
 static const struct ide_port_info sis5513_chipset __devinitdata = {
index c7a125b66c297504bea97c933b0f1b50044a9a46..ee261ae15b6f01afecea50e926a968bbec553249 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * linux/drivers/ide/pci/sl82c105.c
- *
  * SL82C105/Winbond 553 IDE driver
  *
  * Maintainer unknown.
 #include <linux/types.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/interrupt.h>
-#include <linux/blkdev.h>
 #include <linux/hdreg.h>
 #include <linux/pci.h>
 #include <linux/ide.h>
 
 #include <asm/io.h>
-#include <asm/dma.h>
 
 #undef DEBUG
 
@@ -78,7 +70,7 @@ static unsigned int get_pio_timings(ide_drive_t *drive, u8 pio)
  */
 static void sl82c105_set_pio_mode(ide_drive_t *drive, const u8 pio)
 {
-       struct pci_dev *dev     = HWIF(drive)->pci_dev;
+       struct pci_dev *dev     = to_pci_dev(drive->hwif->dev);
        int reg                 = 0x44 + drive->dn * 4;
        u16 drv_ctrl;
 
@@ -147,7 +139,7 @@ static inline void sl82c105_reset_host(struct pci_dev *dev)
 static void sl82c105_dma_lost_irq(ide_drive_t *drive)
 {
        ide_hwif_t *hwif        = HWIF(drive);
-       struct pci_dev *dev     = hwif->pci_dev;
+       struct pci_dev *dev     = to_pci_dev(hwif->dev);
        u32 val, mask           = hwif->channel ? CTRL_IDE_IRQB : CTRL_IDE_IRQA;
        u8 dma_cmd;
 
@@ -184,7 +176,7 @@ static void sl82c105_dma_lost_irq(ide_drive_t *drive)
 static void sl82c105_dma_start(ide_drive_t *drive)
 {
        ide_hwif_t *hwif        = HWIF(drive);
-       struct pci_dev *dev     = hwif->pci_dev;
+       struct pci_dev *dev     = to_pci_dev(hwif->dev);
        int reg                 = 0x44 + drive->dn * 4;
 
        DBG(("%s(drive:%s)\n", __FUNCTION__, drive->name));
@@ -197,15 +189,17 @@ static void sl82c105_dma_start(ide_drive_t *drive)
 
 static void sl82c105_dma_timeout(ide_drive_t *drive)
 {
+       struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
+
        DBG(("sl82c105_dma_timeout(drive:%s)\n", drive->name));
 
-       sl82c105_reset_host(HWIF(drive)->pci_dev);
+       sl82c105_reset_host(dev);
        ide_dma_timeout(drive);
 }
 
 static int sl82c105_dma_end(ide_drive_t *drive)
 {
-       struct pci_dev *dev     = HWIF(drive)->pci_dev;
+       struct pci_dev *dev     = to_pci_dev(drive->hwif->dev);
        int reg                 = 0x44 + drive->dn * 4;
        int ret;
 
@@ -224,7 +218,7 @@ static int sl82c105_dma_end(ide_drive_t *drive)
  */
 static void sl82c105_resetproc(ide_drive_t *drive)
 {
-       struct pci_dev *dev = HWIF(drive)->pci_dev;
+       struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
        u32 val;
 
        DBG(("sl82c105_resetproc(drive:%s)\n", drive->name));
@@ -293,6 +287,7 @@ static unsigned int __devinit init_chipset_sl82c105(struct pci_dev *dev, const c
  */
 static void __devinit init_hwif_sl82c105(ide_hwif_t *hwif)
 {
+       struct pci_dev *dev = to_pci_dev(hwif->dev);
        unsigned int rev;
 
        DBG(("init_hwif_sl82c105(hwif: ide%d)\n", hwif->index));
@@ -304,7 +299,7 @@ static void __devinit init_hwif_sl82c105(ide_hwif_t *hwif)
        if (!hwif->dma_base)
                return;
 
-       rev = sl82c105_bridge_revision(hwif->pci_dev);
+       rev = sl82c105_bridge_revision(dev);
        if (rev <= 5) {
                /*
                 * Never ever EVER under any circumstances enable
index dbbb46819a2dbdae2ba1a9d52830639985e7456f..65f4c2ffaa5964604c713a1ca78719ee6112ae48 100644 (file)
@@ -1,6 +1,4 @@
 /*
- *  linux/drivers/ide/pci/slc90e66.c   Version 0.19    Sep 24, 2007
- *
  *  Copyright (C) 2000-2002 Andre Hedrick <andre@linux-ide.org>
  *  Copyright (C) 2006-2007 MontaVista Software, Inc. <source@mvista.com>
  *
 #include <linux/types.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/ioport.h>
 #include <linux/pci.h>
 #include <linux/hdreg.h>
 #include <linux/ide.h>
-#include <linux/delay.h>
 #include <linux/init.h>
 
-#include <asm/io.h>
-
 static DEFINE_SPINLOCK(slc90e66_lock);
 
 static void slc90e66_set_pio_mode(ide_drive_t *drive, const u8 pio)
 {
        ide_hwif_t *hwif        = HWIF(drive);
-       struct pci_dev *dev     = hwif->pci_dev;
+       struct pci_dev *dev     = to_pci_dev(hwif->dev);
        int is_slave            = drive->dn & 1;
        int master_port         = hwif->channel ? 0x42 : 0x40;
        int slave_port          = 0x44;
@@ -79,7 +73,7 @@ static void slc90e66_set_pio_mode(ide_drive_t *drive, const u8 pio)
 static void slc90e66_set_dma_mode(ide_drive_t *drive, const u8 speed)
 {
        ide_hwif_t *hwif        = HWIF(drive);
-       struct pci_dev *dev     = hwif->pci_dev;
+       struct pci_dev *dev     = to_pci_dev(hwif->dev);
        u8 maslave              = hwif->channel ? 0x42 : 0x40;
        int sitre = 0, a_speed  = 7 << (drive->dn * 4);
        int u_speed = 0, u_flag = 1 << drive->dn;
@@ -120,22 +114,23 @@ static void slc90e66_set_dma_mode(ide_drive_t *drive, const u8 speed)
        }
 }
 
-static void __devinit init_hwif_slc90e66 (ide_hwif_t *hwif)
+static u8 __devinit slc90e66_cable_detect(ide_hwif_t *hwif)
 {
-       u8 reg47 = 0;
-       u8 mask = hwif->channel ? 0x01 : 0x02;  /* bit0:Primary */
+       struct pci_dev *dev = to_pci_dev(hwif->dev);
+       u8 reg47 = 0, mask = hwif->channel ? 0x01 : 0x02;
 
-       hwif->set_pio_mode = &slc90e66_set_pio_mode;
-       hwif->set_dma_mode = &slc90e66_set_dma_mode;
+       pci_read_config_byte(dev, 0x47, &reg47);
 
-       pci_read_config_byte(hwif->pci_dev, 0x47, &reg47);
+       /* bit[0(1)]: 0:80, 1:40 */
+       return (reg47 & mask) ? ATA_CBL_PATA40 : ATA_CBL_PATA80;
+}
 
-       if (hwif->dma_base == 0)
-               return;
+static void __devinit init_hwif_slc90e66(ide_hwif_t *hwif)
+{
+       hwif->set_pio_mode = &slc90e66_set_pio_mode;
+       hwif->set_dma_mode = &slc90e66_set_dma_mode;
 
-       if (hwif->cbl != ATA_CBL_PATA40_SHORT)
-               /* bit[0(1)]: 0:80, 1:40 */
-               hwif->cbl = (reg47 & mask) ? ATA_CBL_PATA40 : ATA_CBL_PATA80;
+       hwif->cable_detect = slc90e66_cable_detect;
 }
 
 static const struct ide_port_info slc90e66_chipset __devinitdata = {
index e1faf6c2fe1678ba442fbfae9516144e4cbfeb1e..2ef2ed2f2b32a9e0ba45d263963edf97efeccda5 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * drivers/ide/pci/tc86c001.c  Version 1.01    Sep 5, 2007
- *
  * Copyright (C) 2002 Toshiba Corporation
  * Copyright (C) 2005-2006 MontaVista Software, Inc. <source@mvista.com>
  *
@@ -162,9 +160,23 @@ static int tc86c001_busproc(ide_drive_t *drive, int state)
        return 0;
 }
 
+static u8 __devinit tc86c001_cable_detect(ide_hwif_t *hwif)
+{
+       struct pci_dev *dev = to_pci_dev(hwif->dev);
+       unsigned long sc_base = pci_resource_start(dev, 5);
+       u16 scr1 = inw(sc_base + 0x00);
+
+       /*
+        * System Control  1 Register bit 13 (PDIAGN):
+        * 0=80-pin cable, 1=40-pin cable
+        */
+       return (scr1 & 0x2000) ? ATA_CBL_PATA40 : ATA_CBL_PATA80;
+}
+
 static void __devinit init_hwif_tc86c001(ide_hwif_t *hwif)
 {
-       unsigned long sc_base   = pci_resource_start(hwif->pci_dev, 5);
+       struct pci_dev *dev     = to_pci_dev(hwif->dev);
+       unsigned long sc_base   = pci_resource_start(dev, 5);
        u16 scr1                = inw(sc_base + 0x00);
 
        /* System Control 1 Register bit 15 (Soft Reset) set */
@@ -184,6 +196,8 @@ static void __devinit init_hwif_tc86c001(ide_hwif_t *hwif)
 
        hwif->busproc   = &tc86c001_busproc;
 
+       hwif->cable_detect = tc86c001_cable_detect;
+
        if (!hwif->dma_base)
                return;
 
@@ -197,15 +211,6 @@ static void __devinit init_hwif_tc86c001(ide_hwif_t *hwif)
        hwif->rqsize     = 0xffff;
 
        hwif->dma_start         = &tc86c001_dma_start;
-
-       if (hwif->cbl != ATA_CBL_PATA40_SHORT) {
-               /*
-                * System Control  1 Register bit 13 (PDIAGN):
-                * 0=80-pin cable, 1=40-pin cable
-                */
-               scr1 = inw(sc_base + 0x00);
-               hwif->cbl = (scr1 & 0x2000) ? ATA_CBL_PATA40 : ATA_CBL_PATA80;
-       }
 }
 
 static unsigned int __devinit init_chipset_tc86c001(struct pci_dev *dev,
index ae52a96a1cf9d5770660637ea19d44f9b71bff4b..a67d02a3f96e108484f42b71cbbbeec9dc97a6aa 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * triflex.c
- * 
  * IDE Chipset driver for the Compaq TriFlex IDE controller.
  * 
  * Known to work with the Compaq Workstation 5x00 series.
 #include <linux/types.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
 #include <linux/hdreg.h>
 #include <linux/pci.h>
 #include <linux/ide.h>
@@ -43,7 +36,7 @@
 static void triflex_set_mode(ide_drive_t *drive, const u8 speed)
 {
        ide_hwif_t *hwif = HWIF(drive);
-       struct pci_dev *dev = hwif->pci_dev;
+       struct pci_dev *dev = to_pci_dev(hwif->dev);
        u8 channel_offset = hwif->channel ? 0x74 : 0x70;
        u16 timing = 0;
        u32 triflex_timings = 0;
index 04cd893e1ab053e8621aa486fdfe2087725ace49..de750f7a43e97f12725a7673c3557b6ab1ed38b8 100644 (file)
@@ -1,8 +1,7 @@
 /*
- *  linux/drivers/ide/pci/trm290.c             Version 1.05    Dec. 26, 2007
- *
  *  Copyright (c) 1997-1998  Mark Lord
  *  Copyright (c) 2007       MontaVista Software, Inc. <source@mvista.com>
+ *
  *  May be copied or modified under the terms of the GNU General Public License
  *
  *  June 22, 2004 - get rid of check_region
 #include <linux/types.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/mm.h>
 #include <linux/ioport.h>
 #include <linux/interrupt.h>
 #include <linux/blkdev.h>
 #include <linux/init.h>
 #include <linux/hdreg.h>
 #include <linux/pci.h>
-#include <linux/delay.h>
 #include <linux/ide.h>
 
 #include <asm/io.h>
@@ -180,10 +177,7 @@ static void trm290_selectproc (ide_drive_t *drive)
 
 static void trm290_dma_exec_cmd(ide_drive_t *drive, u8 command)
 {
-       BUG_ON(HWGROUP(drive)->handler != NULL);        /* paranoia check */
-       ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL);
-       /* issue cmd to drive */
-       outb(command, IDE_COMMAND_REG);
+       ide_execute_command(drive, command, &ide_dma_intr, WAIT_CMD, NULL);
 }
 
 static int trm290_dma_setup(ide_drive_t *drive)
@@ -209,10 +203,10 @@ static int trm290_dma_setup(ide_drive_t *drive)
        }
        /* select DMA xfer */
        trm290_prepare_drive(drive, 1);
-       outl(hwif->dmatable_dma | rw, hwif->dma_command);
+       outl(hwif->dmatable_dma | rw, hwif->dma_base);
        drive->waiting_for_dma = 1;
        /* start DMA */
-       outw((count * 2) - 1, hwif->dma_status);
+       outw(count * 2 - 1, hwif->dma_base + 2);
        return 0;
 }
 
@@ -222,23 +216,21 @@ static void trm290_dma_start(ide_drive_t *drive)
 
 static int trm290_ide_dma_end (ide_drive_t *drive)
 {
-       ide_hwif_t *hwif = HWIF(drive);
-       u16 status = 0;
+       u16 status;
 
        drive->waiting_for_dma = 0;
        /* purge DMA mappings */
        ide_destroy_dmatable(drive);
-       status = inw(hwif->dma_status);
-       return (status != 0x00ff);
+       status = inw(HWIF(drive)->dma_base + 2);
+       return status != 0x00ff;
 }
 
 static int trm290_ide_dma_test_irq (ide_drive_t *drive)
 {
-       ide_hwif_t *hwif = HWIF(drive);
-       u16 status = 0;
+       u16 status;
 
-       status = inw(hwif->dma_status);
-       return (status == 0x00ff);
+       status = inw(HWIF(drive)->dma_base + 2);
+       return status == 0x00ff;
 }
 
 static void trm290_dma_host_set(ide_drive_t *drive, int on)
@@ -247,21 +239,37 @@ static void trm290_dma_host_set(ide_drive_t *drive, int on)
 
 static void __devinit init_hwif_trm290(ide_hwif_t *hwif)
 {
-       unsigned int cfgbase = 0;
+       struct pci_dev *dev     = to_pci_dev(hwif->dev);
+       unsigned int  cfg_base  = pci_resource_start(dev, 4);
        unsigned long flags;
        u8 reg = 0;
-       struct pci_dev *dev = hwif->pci_dev;
-
-       cfgbase = pci_resource_start(dev, 4);
-       if ((dev->class & 5) && cfgbase) {
-               hwif->config_data = cfgbase;
-               printk(KERN_INFO "TRM290: chip config base at 0x%04lx\n",
-                       hwif->config_data);
-       } else {
-               hwif->config_data = 0x3df0;
-               printk(KERN_INFO "TRM290: using default config base at 0x%04lx\n",
-                       hwif->config_data);
+
+       if ((dev->class & 5) && cfg_base)
+               printk(KERN_INFO "TRM290: chip");
+       else {
+               cfg_base = 0x3df0;
+               printk(KERN_INFO "TRM290: using default");
        }
+       printk(KERN_CONT " config base at 0x%04x\n", cfg_base);
+       hwif->config_data = cfg_base;
+       hwif->dma_base = (cfg_base + 4) ^ (hwif->channel ? 0x80 : 0);
+
+       printk(KERN_INFO "    %s: BM-DMA at 0x%04lx-0x%04lx",
+              hwif->name, hwif->dma_base, hwif->dma_base + 3);
+
+       if (!request_region(hwif->dma_base, 4, hwif->name)) {
+               printk(KERN_CONT " -- Error, ports in use.\n");
+               return;
+       }
+
+       hwif->dmatable_cpu = pci_alloc_consistent(dev, PRD_ENTRIES * PRD_BYTES,
+                                                 &hwif->dmatable_dma);
+       if (!hwif->dmatable_cpu) {
+               printk(KERN_CONT " -- Error, unable to allocate DMA table.\n");
+               release_region(hwif->dma_base, 4);
+               return;
+       }
+       printk(KERN_CONT "\n");
 
        local_irq_save(flags);
        /* put config reg into first byte of hwif->select_data */
@@ -276,15 +284,13 @@ static void __devinit init_hwif_trm290(ide_hwif_t *hwif)
        outb(reg, hwif->config_data + 3);
        local_irq_restore(flags);
 
-       if ((reg & 0x10))
+       if (reg & 0x10)
                /* legacy mode */
                hwif->irq = hwif->channel ? 15 : 14;
        else if (!hwif->irq && hwif->mate && hwif->mate->irq)
                /* sharing IRQ with mate */
                hwif->irq = hwif->mate->irq;
 
-       ide_setup_dma(hwif, (hwif->config_data + 4) ^ (hwif->channel ? 0x0080 : 0x0000), 3);
-
        hwif->dma_host_set      = &trm290_dma_host_set;
        hwif->dma_setup         = &trm290_dma_setup;
        hwif->dma_exec_cmd      = &trm290_dma_exec_cmd;
index 4b32c90f489695b212883a868e55b7c3f6b9f948..f3f79f8058131836164dea76d90f777949c7d82d 100644 (file)
@@ -1,7 +1,4 @@
 /*
- *
- * Version 3.50
- *
  * VIA IDE driver for Linux. Supported southbridges:
  *
  *   vt82c576, vt82c586, vt82c586a, vt82c586b, vt82c596a, vt82c596b,
 
 #include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
 #include <linux/pci.h>
 #include <linux/init.h>
 #include <linux/ide.h>
 #include <linux/dmi.h>
 
-#include <asm/io.h>
-
 #ifdef CONFIG_PPC_CHRP
 #include <asm/processor.h>
 #endif
@@ -121,8 +114,8 @@ struct via82cxxx_dev
 
 static void via_set_speed(ide_hwif_t *hwif, u8 dn, struct ide_timing *timing)
 {
-       struct pci_dev *dev = hwif->pci_dev;
-       struct via82cxxx_dev *vdev = pci_get_drvdata(hwif->pci_dev);
+       struct pci_dev *dev = to_pci_dev(hwif->dev);
+       struct via82cxxx_dev *vdev = pci_get_drvdata(dev);
        u8 t;
 
        if (~vdev->via_config->flags & VIA_BAD_AST) {
@@ -159,8 +152,10 @@ static void via_set_speed(ide_hwif_t *hwif, u8 dn, struct ide_timing *timing)
 
 static void via_set_drive(ide_drive_t *drive, const u8 speed)
 {
-       ide_drive_t *peer = HWIF(drive)->drives + (~drive->dn & 1);
-       struct via82cxxx_dev *vdev = pci_get_drvdata(drive->hwif->pci_dev);
+       ide_hwif_t *hwif = drive->hwif;
+       ide_drive_t *peer = hwif->drives + (~drive->dn & 1);
+       struct pci_dev *dev = to_pci_dev(hwif->dev);
+       struct via82cxxx_dev *vdev = pci_get_drvdata(dev);
        struct ide_timing t, p;
        unsigned int T, UT;
 
@@ -408,7 +403,7 @@ static int via_cable_override(struct pci_dev *pdev)
 
 static u8 __devinit via82cxxx_cable_detect(ide_hwif_t *hwif)
 {
-       struct pci_dev *pdev = hwif->pci_dev;
+       struct pci_dev *pdev = to_pci_dev(hwif->dev);
        struct via82cxxx_dev *vdev = pci_get_drvdata(pdev);
 
        if (via_cable_override(pdev))
@@ -425,11 +420,7 @@ static void __devinit init_hwif_via82cxxx(ide_hwif_t *hwif)
        hwif->set_pio_mode = &via_set_pio_mode;
        hwif->set_dma_mode = &via_set_drive;
 
-       if (!hwif->dma_base)
-               return;
-
-       if (hwif->cbl != ATA_CBL_PATA40_SHORT)
-               hwif->cbl = via82cxxx_cable_detect(hwif);
+       hwif->cable_detect = via82cxxx_cable_detect;
 }
 
 static const struct ide_port_info via82cxxx_chipset __devinitdata = {
index 3fd5d45b5e0e2584cbdcfbfa2de47b62a47e8f08..06190b1c4ec5ef5e310223c2dbbee6414a5726b7 100644 (file)
@@ -1,6 +1,4 @@
 /*
- *  linux/drivers/ide/ppc/ide-m8xx.c
- *
  *  Copyright (C) 2000, 2001 Wolfgang Denk, wd@denx.de
  *  Modified for direct IDE interface
  *     by Thomas Lange, thomas@corelatus.com
@@ -850,7 +848,7 @@ static int __init mpc8xx_ide_probe(void)
 #endif
 #endif
 
-       ide_device_add(idx);
+       ide_device_add(idx, NULL);
 
        return 0;
 }
index 736d12c8e68afb5170653119d90472d4e63013bf..12ac3bfb4f9ac1d098cae0738521b44442e992b3 100644 (file)
@@ -1,7 +1,6 @@
 /*
- * linux/drivers/ide/ppc/pmac.c
- *
  * Support for IDE interfaces on PowerMacs.
+ *
  * These IDE interfaces are memory-mapped and have a DBDMA channel
  * for doing DMA.
  *
@@ -413,7 +412,7 @@ kauai_lookup_timing(struct kauai_timing* table, int cycle_time)
  */
 #define IDE_WAKEUP_DELAY       (1*HZ)
 
-static void pmac_ide_setup_dma(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif);
+static int pmac_ide_setup_dma(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif);
 static int pmac_ide_build_dmatable(ide_drive_t *drive, struct request *rq);
 static void pmac_ide_selectproc(ide_drive_t *drive);
 static void pmac_ide_kauai_selectproc(ide_drive_t *drive);
@@ -1004,6 +1003,17 @@ pmac_ide_do_resume(ide_hwif_t *hwif)
        return 0;
 }
 
+static const struct ide_port_info pmac_port_info = {
+       .chipset                = ide_pmac,
+       .host_flags             = IDE_HFLAG_SET_PIO_MODE_KEEP_DMA |
+                                 IDE_HFLAG_PIO_NO_DOWNGRADE |
+                                 IDE_HFLAG_POST_SET_MODE |
+                                 IDE_HFLAG_NO_DMA | /* no SFF-style DMA */
+                                 IDE_HFLAG_UNMASK_IRQS,
+       .pio_mask               = ATA_PIO4,
+       .mwdma_mask             = ATA_MWDMA2,
+};
+
 /*
  * Setup, register & probe an IDE channel driven by this driver, this is
  * called by one of the 2 probe functions (macio or PCI). Note that a channel
@@ -1011,29 +1021,34 @@ pmac_ide_do_resume(ide_hwif_t *hwif)
  * (it is kept in 2.4). This introduce an interface numbering change on some
  * rare machines unfortunately, but it's better this way.
  */
-static int
+static int __devinit
 pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif, hw_regs_t *hw)
 {
        struct device_node *np = pmif->node;
        const int *bidp;
        u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
+       struct ide_port_info d = pmac_port_info;
 
        pmif->cable_80 = 0;
        pmif->broken_dma = pmif->broken_dma_warn = 0;
-       if (of_device_is_compatible(np, "shasta-ata"))
+       if (of_device_is_compatible(np, "shasta-ata")) {
                pmif->kind = controller_sh_ata6;
-       else if (of_device_is_compatible(np, "kauai-ata"))
+               d.udma_mask = ATA_UDMA6;
+       } else if (of_device_is_compatible(np, "kauai-ata")) {
                pmif->kind = controller_un_ata6;
-       else if (of_device_is_compatible(np, "K2-UATA"))
+               d.udma_mask = ATA_UDMA5;
+       } else if (of_device_is_compatible(np, "K2-UATA")) {
                pmif->kind = controller_k2_ata6;
-       else if (of_device_is_compatible(np, "keylargo-ata")) {
-               if (strcmp(np->name, "ata-4") == 0)
+               d.udma_mask = ATA_UDMA5;
+       } else if (of_device_is_compatible(np, "keylargo-ata")) {
+               if (strcmp(np->name, "ata-4") == 0) {
                        pmif->kind = controller_kl_ata4;
-               else
+                       d.udma_mask = ATA_UDMA4;
+               } else
                        pmif->kind = controller_kl_ata3;
-       } else if (of_device_is_compatible(np, "heathrow-ata"))
+       } else if (of_device_is_compatible(np, "heathrow-ata")) {
                pmif->kind = controller_heathrow;
-       else {
+       else {
                pmif->kind = controller_ohare;
                pmif->broken_dma = 1;
        }
@@ -1102,19 +1117,10 @@ pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif, hw_regs_t *hw)
        /* Tell common code _not_ to mess with resources */
        hwif->mmio = 1;
        hwif->hwif_data = pmif;
-       hw->chipset = ide_pmac;
        ide_init_port_hw(hwif, hw);
        hwif->noprobe = pmif->mediabay;
        hwif->hold = pmif->mediabay;
        hwif->cbl = pmif->cable_80 ? ATA_CBL_PATA80 : ATA_CBL_PATA40;
-       hwif->drives[0].unmask = 1;
-       hwif->drives[1].unmask = 1;
-       hwif->drives[0].autotune = IDE_TUNE_AUTO;
-       hwif->drives[1].autotune = IDE_TUNE_AUTO;
-       hwif->host_flags = IDE_HFLAG_SET_PIO_MODE_KEEP_DMA |
-                          IDE_HFLAG_PIO_NO_DOWNGRADE |
-                          IDE_HFLAG_POST_SET_MODE;
-       hwif->pio_mask = ATA_PIO4;
        hwif->set_pio_mode = pmac_ide_set_pio_mode;
        if (pmif->kind == controller_un_ata6
            || pmif->kind == controller_k2_ata6
@@ -1134,14 +1140,16 @@ pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif, hw_regs_t *hw)
 #endif /* CONFIG_PMAC_MEDIABAY */
 
 #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
+       if (pmif->cable_80 == 0)
+               d.udma_mask &= ATA_UDMA2;
        /* has a DBDMA controller channel */
-       if (pmif->dma_regs)
-               pmac_ide_setup_dma(pmif, hwif);
-#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
+       if (pmif->dma_regs == 0 || pmac_ide_setup_dma(pmif, hwif) < 0)
+#endif
+               d.udma_mask = d.mwdma_mask = 0;
 
        idx[0] = hwif->index;
 
-       ide_device_add(idx);
+       ide_device_add(idx, &d);
 
        return 0;
 }
@@ -1200,7 +1208,7 @@ pmac_ide_macio_attach(struct macio_dev *mdev, const struct of_device_id *match)
        base = ioremap(macio_resource_start(mdev, 0), 0x400);
        regbase = (unsigned long) base;
 
-       hwif->pci_dev = mdev->bus->pdev;
+       hwif->dev = &mdev->bus->pdev->dev;
 
        pmif->mdev = mdev;
        pmif->node = mdev->ofdev.node;
@@ -1228,12 +1236,12 @@ pmac_ide_macio_attach(struct macio_dev *mdev, const struct of_device_id *match)
                /* The inteface is released to the common IDE layer */
                dev_set_drvdata(&mdev->ofdev.dev, NULL);
                iounmap(base);
-               if (pmif->dma_regs)
+               if (pmif->dma_regs) {
                        iounmap(pmif->dma_regs);
+                       macio_release_resource(mdev, 1);
+               }
                memset(pmif, 0, sizeof(*pmif));
                macio_release_resource(mdev, 0);
-               if (pmif->dma_regs)
-                       macio_release_resource(mdev, 1);
        }
 
        return rc;
@@ -1315,7 +1323,7 @@ pmac_ide_pci_attach(struct pci_dev *pdev, const struct pci_device_id *id)
                return -ENXIO;
        }
 
-       hwif->pci_dev = pdev;
+       hwif->dev = &pdev->dev;
        pmif->mdev = NULL;
        pmif->node = np;
 
@@ -1535,11 +1543,10 @@ pmac_ide_build_dmatable(ide_drive_t *drive, struct request *rq)
        }
 
        printk(KERN_DEBUG "%s: empty DMA table?\n", drive->name);
- use_pio_instead:
-       pci_unmap_sg(hwif->pci_dev,
-                    hwif->sg_table,
-                    hwif->sg_nents,
-                    hwif->sg_dma_direction);
+
+use_pio_instead:
+       ide_destroy_dmatable(drive);
+
        return 0; /* revert to PIO for this request */
 }
 
@@ -1548,12 +1555,9 @@ static void
 pmac_ide_destroy_dmatable (ide_drive_t *drive)
 {
        ide_hwif_t *hwif = drive->hwif;
-       struct pci_dev *dev = HWIF(drive)->pci_dev;
-       struct scatterlist *sg = hwif->sg_table;
-       int nents = hwif->sg_nents;
 
-       if (nents) {
-               pci_unmap_sg(dev, sg, nents, hwif->sg_dma_direction);
+       if (hwif->sg_nents) {
+               ide_destroy_dmatable(drive);
                hwif->sg_nents = 0;
        }
 }
@@ -1726,27 +1730,28 @@ pmac_ide_dma_lost_irq (ide_drive_t *drive)
  * Allocate the data structures needed for using DMA with an interface
  * and fill the proper list of functions pointers
  */
-static void __init 
-pmac_ide_setup_dma(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif)
+static int __devinit pmac_ide_setup_dma(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif)
 {
+       struct pci_dev *dev = to_pci_dev(hwif->dev);
+
        /* We won't need pci_dev if we switch to generic consistent
         * DMA routines ...
         */
-       if (hwif->pci_dev == NULL)
-               return;
+       if (dev == NULL)
+               return -ENODEV;
        /*
         * Allocate space for the DBDMA commands.
         * The +2 is +1 for the stop command and +1 to allow for
         * aligning the start address to a multiple of 16 bytes.
         */
        pmif->dma_table_cpu = (struct dbdma_cmd*)pci_alloc_consistent(
-               hwif->pci_dev,
+               dev,
                (MAX_DCMDS + 2) * sizeof(struct dbdma_cmd),
                &hwif->dmatable_dma);
        if (pmif->dma_table_cpu == NULL) {
                printk(KERN_ERR "%s: unable to allocate DMA command list\n",
                       hwif->name);
-               return;
+               return -ENOMEM;
        }
 
        hwif->sg_max_nents = MAX_DCMDS;
@@ -1760,29 +1765,7 @@ pmac_ide_setup_dma(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif)
        hwif->dma_timeout = &ide_dma_timeout;
        hwif->dma_lost_irq = &pmac_ide_dma_lost_irq;
 
-       switch(pmif->kind) {
-               case controller_sh_ata6:
-                       hwif->ultra_mask = pmif->cable_80 ? 0x7f : 0x07;
-                       hwif->mwdma_mask = 0x07;
-                       hwif->swdma_mask = 0x00;
-                       break;
-               case controller_un_ata6:
-               case controller_k2_ata6:
-                       hwif->ultra_mask = pmif->cable_80 ? 0x3f : 0x07;
-                       hwif->mwdma_mask = 0x07;
-                       hwif->swdma_mask = 0x00;
-                       break;
-               case controller_kl_ata4:
-                       hwif->ultra_mask = pmif->cable_80 ? 0x1f : 0x07;
-                       hwif->mwdma_mask = 0x07;
-                       hwif->swdma_mask = 0x00;
-                       break;
-               default:
-                       hwif->ultra_mask = 0x00;
-                       hwif->mwdma_mask = 0x07;
-                       hwif->swdma_mask = 0x00;
-                       break;
-       }
+       return 0;
 }
 
 #endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
index 676c66e728818aac177442847d50b1d73413ef6e..634e3f6a96087907b8053fc8bcdb29d3b20281d0 100644 (file)
@@ -1,9 +1,8 @@
 /*
- *  linux/drivers/ide/setup-pci.c              Version 1.10    2002/08/19
+ *  Copyright (C) 1998-2000  Andre Hedrick <andre@linux-ide.org>
+ *  Copyright (C) 1995-1998  Mark Lord
+ *  Copyright (C)      2007  Bartlomiej Zolnierkiewicz
  *
- *  Copyright (c) 1998-2000  Andre Hedrick <andre@linux-ide.org>
- *
- *  Copyright (c) 1995-1998  Mark Lord
  *  May be copied or modified under the terms of the GNU General Public License
  */
 
@@ -140,6 +139,16 @@ static int ide_setup_pci_baseregs (struct pci_dev *dev, const char *name)
 }
 
 #ifdef CONFIG_BLK_DEV_IDEDMA_PCI
+static void ide_pci_clear_simplex(unsigned long dma_base, const char *name)
+{
+       u8 dma_stat = inb(dma_base + 2);
+
+       outb(dma_stat & 0x60, dma_base + 2);
+       dma_stat = inb(dma_base + 2);
+       if (dma_stat & 0x80)
+               printk(KERN_INFO "%s: simplex device: DMA forced\n", name);
+}
+
 /**
  *     ide_get_or_set_dma_base         -       setup BMIBA
  *     @d: IDE port info
@@ -152,8 +161,9 @@ static int ide_setup_pci_baseregs (struct pci_dev *dev, const char *name)
 
 static unsigned long ide_get_or_set_dma_base(const struct ide_port_info *d, ide_hwif_t *hwif)
 {
-       unsigned long   dma_base = 0;
-       struct pci_dev  *dev = hwif->pci_dev;
+       struct pci_dev *dev = to_pci_dev(hwif->dev);
+       unsigned long dma_base = 0;
+       u8 dma_stat = 0;
 
        if (hwif->mmio)
                return hwif->dma_base;
@@ -174,52 +184,30 @@ static unsigned long ide_get_or_set_dma_base(const struct ide_port_info *d, ide_
        if (hwif->channel)
                dma_base += 8;
 
-       if ((d->host_flags & IDE_HFLAG_CS5520) == 0) {
-               u8 simplex_stat = 0;
-
-               switch(dev->device) {
-                       case PCI_DEVICE_ID_AL_M5219:
-                       case PCI_DEVICE_ID_AL_M5229:
-                       case PCI_DEVICE_ID_AMD_VIPER_7409:
-                       case PCI_DEVICE_ID_CMD_643:
-                       case PCI_DEVICE_ID_SERVERWORKS_CSB5IDE:
-                       case PCI_DEVICE_ID_REVOLUTION:
-                               simplex_stat = inb(dma_base + 2);
-                               outb(simplex_stat & 0x60, dma_base + 2);
-                               simplex_stat = inb(dma_base + 2);
-                               if (simplex_stat & 0x80) {
-                                       printk(KERN_INFO "%s: simplex device: "
-                                                        "DMA forced\n",
-                                                        d->name);
-                               }
-                               break;
-                       default:
-                               /*
-                                * If the device claims "simplex" DMA,
-                                * this means only one of the two interfaces
-                                * can be trusted with DMA at any point in time.
-                                * So we should enable DMA only on one of the
-                                * two interfaces.
-                                */
-                               simplex_stat = hwif->INB(dma_base + 2);
-                               if (simplex_stat & 0x80) {
-                                       /* simplex device? */
-/*
- *     At this point we haven't probed the drives so we can't make the
- *     appropriate decision. Really we should defer this problem
- *     until we tune the drive then try to grab DMA ownership if we want
- *     to be the DMA end. This has to be become dynamic to handle hot
- *     plug.
- */
-                                       if (hwif->mate && hwif->mate->dma_base) {
-                                               printk(KERN_INFO "%s: simplex device: "
-                                                                "DMA disabled\n",
-                                                                d->name);
-                                               dma_base = 0;
-                                       }
-                               }
-               }
+       if (d->host_flags & IDE_HFLAG_CS5520)
+               goto out;
+
+       if (d->host_flags & IDE_HFLAG_CLEAR_SIMPLEX) {
+               ide_pci_clear_simplex(dma_base, d->name);
+               goto out;
+       }
+
+       /*
+        * If the device claims "simplex" DMA, this means that only one of
+        * the two interfaces can be trusted with DMA at any point in time
+        * (so we should enable DMA only on one of the two interfaces).
+        *
+        * FIXME: At this point we haven't probed the drives so we can't make
+        * the appropriate decision.  Really we should defer this problem until
+        * we tune the drive then try to grab DMA ownership if we want to be
+        * the DMA end.  This has to be become dynamic to handle hot-plug.
+        */
+       dma_stat = hwif->INB(dma_base + 2);
+       if ((dma_stat & 0x80) && hwif->mate && hwif->mate->dma_base) {
+               printk(KERN_INFO "%s: simplex device: DMA disabled\n", d->name);
+               dma_base = 0;
        }
+out:
        return dma_base;
 }
 #endif /* CONFIG_BLK_DEV_IDEDMA_PCI */
@@ -240,7 +228,9 @@ EXPORT_SYMBOL_GPL(ide_setup_pci_noise);
  *     @d: IDE port info
  *
  *     Enable the IDE PCI device. We attempt to enable the device in full
- *     but if that fails then we only need BAR4 so we will enable that.
+ *     but if that fails then we only need IO space. The PCI code should
+ *     have setup the proper resources for us already for controllers in
+ *     legacy mode.
  *     
  *     Returns zero on success or an error code
  */
@@ -250,7 +240,7 @@ static int ide_pci_enable(struct pci_dev *dev, const struct ide_port_info *d)
        int ret;
 
        if (pci_enable_device(dev)) {
-               ret = pci_enable_device_bars(dev, 1 << 4);
+               ret = pci_enable_device_io(dev);
                if (ret < 0) {
                        printk(KERN_WARNING "%s: (ide_setup_pci_device:) "
                                "Could not enable device.\n", d->name);
@@ -349,7 +339,8 @@ static int ide_pci_check_iomem(struct pci_dev *dev, const struct ide_port_info *
  *     ide_hwif_configure      -       configure an IDE interface
  *     @dev: PCI device holding interface
  *     @d: IDE port info
- *     @mate: Paired interface if any
+ *     @port: port number
+ *     @irq: PCI IRQ
  *
  *     Perform the initial set up for the hardware interface structure. This
  *     is done per interface port rather than per PCI device. There may be
@@ -358,7 +349,9 @@ static int ide_pci_check_iomem(struct pci_dev *dev, const struct ide_port_info *
  *     Returns the new hardware interface structure, or NULL on a failure
  */
 
-static ide_hwif_t *ide_hwif_configure(struct pci_dev *dev, const struct ide_port_info *d, ide_hwif_t *mate, int port, int irq)
+static ide_hwif_t *ide_hwif_configure(struct pci_dev *dev,
+                                     const struct ide_port_info *d,
+                                     unsigned int port, int irq)
 {
        unsigned long ctl = 0, base = 0;
        ide_hwif_t *hwif;
@@ -402,31 +395,26 @@ static ide_hwif_t *ide_hwif_configure(struct pci_dev *dev, const struct ide_port
 
        hwif->noprobe = oldnoprobe;
 
-       hwif->pci_dev = dev;
+       hwif->dev = &dev->dev;
        hwif->cds = d;
-       hwif->channel = port;
 
-       if (mate) {
-               hwif->mate = mate;
-               mate->mate = hwif;
-       }
        return hwif;
 }
 
+#ifdef CONFIG_BLK_DEV_IDEDMA_PCI
 /**
  *     ide_hwif_setup_dma      -       configure DMA interface
- *     @dev: PCI device
- *     @d: IDE port info
  *     @hwif: IDE interface
+ *     @d: IDE port info
  *
  *     Set up the DMA base for the interface. Enable the master bits as
  *     necessary and attempt to bring the device DMA into a ready to use
  *     state
  */
 
-static void ide_hwif_setup_dma(struct pci_dev *dev, const struct ide_port_info *d, ide_hwif_t *hwif)
+void ide_hwif_setup_dma(ide_hwif_t *hwif, const struct ide_port_info *d)
 {
-#ifdef CONFIG_BLK_DEV_IDEDMA_PCI
+       struct pci_dev *dev = to_pci_dev(hwif->dev);
        u16 pcicmd;
 
        pci_read_config_word(dev, PCI_COMMAND, &pcicmd);
@@ -451,15 +439,15 @@ static void ide_hwif_setup_dma(struct pci_dev *dev, const struct ide_port_info *
                        if (d->init_dma) {
                                d->init_dma(hwif, dma_base);
                        } else {
-                               ide_setup_dma(hwif, dma_base, 8);
+                               ide_setup_dma(hwif, dma_base);
                        }
                } else {
                        printk(KERN_INFO "%s: %s Bus-Master DMA disabled "
                                "(BIOS)\n", hwif->name, d->name);
                }
        }
-#endif /* CONFIG_BLK_DEV_IDEDMA_PCI*/
 }
+#endif /* CONFIG_BLK_DEV_IDEDMA_PCI */
 
 /**
  *     ide_setup_pci_controller        -       set up IDE PCI
@@ -521,7 +509,7 @@ out:
 void ide_pci_setup_ports(struct pci_dev *dev, const struct ide_port_info *d, int pciirq, u8 *idx)
 {
        int channels = (d->host_flags & IDE_HFLAG_SINGLE) ? 1 : 2, port;
-       ide_hwif_t *hwif, *mate = NULL;
+       ide_hwif_t *hwif;
        u8 tmp;
 
        /*
@@ -537,56 +525,11 @@ void ide_pci_setup_ports(struct pci_dev *dev, const struct ide_port_info *d, int
                        continue;       /* port not enabled */
                }
 
-               if ((hwif = ide_hwif_configure(dev, d, mate, port, pciirq)) == NULL)
+               hwif = ide_hwif_configure(dev, d, port, pciirq);
+               if (hwif == NULL)
                        continue;
 
                *(idx + port) = hwif->index;
-
-               if (d->init_iops)
-                       d->init_iops(hwif);
-
-               if ((d->host_flags & IDE_HFLAG_NO_DMA) == 0)
-                       ide_hwif_setup_dma(dev, d, hwif);
-
-               if ((!hwif->irq && (d->host_flags & IDE_HFLAG_LEGACY_IRQS)) ||
-                   (d->host_flags & IDE_HFLAG_FORCE_LEGACY_IRQS))
-                       hwif->irq = port ? 15 : 14;
-
-               hwif->host_flags = d->host_flags;
-               hwif->pio_mask = d->pio_mask;
-
-               if ((d->host_flags & IDE_HFLAG_SERIALIZE) && hwif->mate)
-                       hwif->mate->serialized = hwif->serialized = 1;
-
-               if (d->host_flags & IDE_HFLAG_IO_32BIT) {
-                       hwif->drives[0].io_32bit = 1;
-                       hwif->drives[1].io_32bit = 1;
-               }
-
-               if (d->host_flags & IDE_HFLAG_UNMASK_IRQS) {
-                       hwif->drives[0].unmask = 1;
-                       hwif->drives[1].unmask = 1;
-               }
-
-               if (hwif->dma_base) {
-                       hwif->swdma_mask = d->swdma_mask;
-                       hwif->mwdma_mask = d->mwdma_mask;
-                       hwif->ultra_mask = d->udma_mask;
-               }
-
-               hwif->drives[0].autotune = 1;
-               hwif->drives[1].autotune = 1;
-
-               if (d->host_flags & IDE_HFLAG_RQSIZE_256)
-                       hwif->rqsize = 256;
-
-               if (d->init_hwif)
-                       /* Call chipset-specific routine
-                        * for each enabled hwif
-                        */
-                       d->init_hwif(hwif);
-
-               mate = hwif;
        }
 }
 
@@ -668,7 +611,7 @@ int ide_setup_pci_device(struct pci_dev *dev, const struct ide_port_info *d)
        ret = do_ide_setup_pci_device(dev, d, &idx[0], 1);
 
        if (ret >= 0)
-               ide_device_add(idx);
+               ide_device_add(idx, d);
 
        return ret;
 }
@@ -692,7 +635,7 @@ int ide_setup_pci_devices(struct pci_dev *dev1, struct pci_dev *dev2,
                        goto out;
        }
 
-       ide_device_add(idx);
+       ide_device_add(idx, d);
 out:
        return ret;
 }
index 7c4eb39b70241ef55f2bcc6ff4e7330acdc03938..73685e7dc7e4c9e6acea24c454e737686768b7e3 100644 (file)
@@ -231,37 +231,24 @@ void dma_region_sync_for_device(struct dma_region *dma, unsigned long offset,
 
 #ifdef CONFIG_MMU
 
-/* nopage() handler for mmap access */
-
-static struct page *dma_region_pagefault(struct vm_area_struct *area,
-                                        unsigned long address, int *type)
+static int dma_region_pagefault(struct vm_area_struct *vma,
+                               struct vm_fault *vmf)
 {
-       unsigned long offset;
-       unsigned long kernel_virt_addr;
-       struct page *ret = NOPAGE_SIGBUS;
-
-       struct dma_region *dma = (struct dma_region *)area->vm_private_data;
+       struct dma_region *dma = (struct dma_region *)vma->vm_private_data;
 
        if (!dma->kvirt)
-               goto out;
-
-       if ((address < (unsigned long)area->vm_start) ||
-           (address >
-            (unsigned long)area->vm_start + (dma->n_pages << PAGE_SHIFT)))
-               goto out;
-
-       if (type)
-               *type = VM_FAULT_MINOR;
-       offset = address - area->vm_start;
-       kernel_virt_addr = (unsigned long)dma->kvirt + offset;
-       ret = vmalloc_to_page((void *)kernel_virt_addr);
-       get_page(ret);
-      out:
-       return ret;
+               return VM_FAULT_SIGBUS;
+
+       if (vmf->pgoff >= dma->n_pages)
+               return VM_FAULT_SIGBUS;
+
+       vmf->page = vmalloc_to_page(dma->kvirt + (vmf->pgoff << PAGE_SHIFT));
+       get_page(vmf->page);
+       return 0;
 }
 
 static struct vm_operations_struct dma_region_vm_ops = {
-       .nopage = dma_region_pagefault,
+       .fault = dma_region_pagefault,
 };
 
 /**
@@ -275,7 +262,7 @@ int dma_region_mmap(struct dma_region *dma, struct file *file,
        if (!dma->kvirt)
                return -EINVAL;
 
-       /* must be page-aligned */
+       /* must be page-aligned (XXX: comment is wrong, we could allow pgoff) */
        if (vma->vm_pgoff != 0)
                return -EINVAL;
 
index 677989320951fc394229b74a69b65ef2317eb7c4..10c3d9f8c038ea944750bff2e913ef8b3c12d8b0 100644 (file)
@@ -570,71 +570,3 @@ int hpsb_write(struct hpsb_host *host, nodeid_t node, unsigned int generation,
 
        return retval;
 }
-
-#if 0
-
-int hpsb_lock(struct hpsb_host *host, nodeid_t node, unsigned int generation,
-             u64 addr, int extcode, quadlet_t * data, quadlet_t arg)
-{
-       struct hpsb_packet *packet;
-       int retval = 0;
-
-       BUG_ON(in_interrupt()); // We can't be called in an interrupt, yet
-
-       packet = hpsb_make_lockpacket(host, node, addr, extcode, data, arg);
-       if (!packet)
-               return -ENOMEM;
-
-       packet->generation = generation;
-       retval = hpsb_send_packet_and_wait(packet);
-       if (retval < 0)
-               goto hpsb_lock_fail;
-
-       retval = hpsb_packet_success(packet);
-
-       if (retval == 0) {
-               *data = packet->data[0];
-       }
-
-      hpsb_lock_fail:
-       hpsb_free_tlabel(packet);
-       hpsb_free_packet(packet);
-
-       return retval;
-}
-
-int hpsb_send_gasp(struct hpsb_host *host, int channel, unsigned int generation,
-                  quadlet_t * buffer, size_t length, u32 specifier_id,
-                  unsigned int version)
-{
-       struct hpsb_packet *packet;
-       int retval = 0;
-       u16 specifier_id_hi = (specifier_id & 0x00ffff00) >> 8;
-       u8 specifier_id_lo = specifier_id & 0xff;
-
-       HPSB_VERBOSE("Send GASP: channel = %d, length = %Zd", channel, length);
-
-       length += 8;
-
-       packet = hpsb_make_streampacket(host, NULL, length, channel, 3, 0);
-       if (!packet)
-               return -ENOMEM;
-
-       packet->data[0] = cpu_to_be32((host->node_id << 16) | specifier_id_hi);
-       packet->data[1] =
-           cpu_to_be32((specifier_id_lo << 24) | (version & 0x00ffffff));
-
-       memcpy(&(packet->data[2]), buffer, length - 8);
-
-       packet->generation = generation;
-
-       packet->no_waiter = 1;
-
-       retval = hpsb_send_packet(packet);
-       if (retval < 0)
-               hpsb_free_packet(packet);
-
-       return retval;
-}
-
-#endif                         /*  0  */
index 372c5c16eb3180df3940d13d8f602acf4c1d97aa..969de2a2d633450bc8aad554c53f7bd740672ccc 100644 (file)
@@ -2126,10 +2126,14 @@ static void ohci_schedule_iso_tasklets(struct ti_ohci *ohci,
        list_for_each_entry(t, &ohci->iso_tasklet_list, link) {
                mask = 1 << t->context;
 
-               if (t->type == OHCI_ISO_TRANSMIT && tx_event & mask)
-                       tasklet_schedule(&t->tasklet);
-               else if (rx_event & mask)
-                       tasklet_schedule(&t->tasklet);
+               if (t->type == OHCI_ISO_TRANSMIT) {
+                       if (tx_event & mask)
+                               tasklet_schedule(&t->tasklet);
+               } else {
+                       /* OHCI_ISO_RECEIVE or OHCI_ISO_MULTICHANNEL_RECEIVE */
+                       if (rx_event & mask)
+                               tasklet_schedule(&t->tasklet);
+               }
        }
 
        spin_unlock_irqrestore(&ohci->iso_tasklet_list_lock, flags);
index cadf0479cce54d7b0150aaa833114d2b9b8f2b7e..37e7e109af38258c5a2bb44c6a4469481917f34a 100644 (file)
@@ -858,7 +858,7 @@ static int arm_read(struct hpsb_host *host, int nodeid, quadlet_t * buffer,
        int found = 0, size = 0, rcode = -1;
        struct arm_request_response *arm_req_resp = NULL;
 
-       DBGMSG("arm_read  called by node: %X"
+       DBGMSG("arm_read  called by node: %X "
               "addr: %4.4x %8.8x length: %Zu", nodeid,
               (u16) ((addr >> 32) & 0xFFFF), (u32) (addr & 0xFFFFFFFF),
               length);
@@ -1012,7 +1012,7 @@ static int arm_write(struct hpsb_host *host, int nodeid, int destid,
        int found = 0, size = 0, rcode = -1, length_conflict = 0;
        struct arm_request_response *arm_req_resp = NULL;
 
-       DBGMSG("arm_write called by node: %X"
+       DBGMSG("arm_write called by node: %X "
               "addr: %4.4x %8.8x length: %Zu", nodeid,
               (u16) ((addr >> 32) & 0xFFFF), (u32) (addr & 0xFFFFFFFF),
               length);
index 1eda11abeb1e0b3cb912cb7e0c9bcac196b79810..28e155a9e2a5a6bc8e424e2e1dc235f94fac2c26 100644 (file)
@@ -51,6 +51,7 @@
  * Grep for inline FIXME comments below.
  */
 
+#include <linux/blkdev.h>
 #include <linux/compiler.h>
 #include <linux/delay.h>
 #include <linux/device.h>
@@ -127,17 +128,21 @@ MODULE_PARM_DESC(serialize_io, "Serialize requests coming from SCSI drivers "
                 "(default = Y, faster but buggy = N)");
 
 /*
- * Bump up max_sectors if you'd like to support very large sized
- * transfers. Please note that some older sbp2 bridge chips are broken for
- * transfers greater or equal to 128KB.  Default is a value of 255
- * sectors, or just under 128KB (at 512 byte sector size). I can note that
- * the Oxsemi sbp2 chipsets have no problems supporting very large
- * transfer sizes.
+ * Adjust max_sectors if you'd like to influence how many sectors each SCSI
+ * command can transfer at most. Please note that some older SBP-2 bridge
+ * chips are broken for transfers greater or equal to 128KB, therefore
+ * max_sectors used to be a safe 255 sectors for many years. We now have a
+ * default of 0 here which means that we let the SCSI stack choose a limit.
+ *
+ * The SBP2_WORKAROUND_128K_MAX_TRANS flag, if set either in the workarounds
+ * module parameter or in the sbp2_workarounds_table[], will override the
+ * value of max_sectors. We should use sbp2_workarounds_table[] to cover any
+ * bridge chip which becomes known to need the 255 sectors limit.
  */
-static int sbp2_max_sectors = SBP2_MAX_SECTORS;
+static int sbp2_max_sectors;
 module_param_named(max_sectors, sbp2_max_sectors, int, 0444);
 MODULE_PARM_DESC(max_sectors, "Change max sectors per I/O supported "
-                "(default = " __stringify(SBP2_MAX_SECTORS) ")");
+                "(default = 0 = use SCSI stack's default)");
 
 /*
  * Exclusive login to sbp2 device? In most cases, the sbp2 driver should
@@ -1451,7 +1456,7 @@ static void sbp2_prep_command_orb_sg(struct sbp2_command_orb *orb,
                                     struct sbp2_fwhost_info *hi,
                                     struct sbp2_command_info *cmd,
                                     unsigned int scsi_use_sg,
-                                    struct scatterlist *sgpnt,
+                                    struct scatterlist *sg,
                                     u32 orb_direction,
                                     enum dma_data_direction dma_dir)
 {
@@ -1460,13 +1465,12 @@ static void sbp2_prep_command_orb_sg(struct sbp2_command_orb *orb,
        orb->misc |= ORB_SET_DIRECTION(orb_direction);
 
        /* special case if only one element (and less than 64KB in size) */
-       if ((scsi_use_sg == 1) &&
-           (sgpnt[0].length <= SBP2_MAX_SG_ELEMENT_LENGTH)) {
+       if (scsi_use_sg == 1 && sg->length <= SBP2_MAX_SG_ELEMENT_LENGTH) {
 
-               cmd->dma_size = sgpnt[0].length;
+               cmd->dma_size = sg->length;
                cmd->dma_type = CMD_DMA_PAGE;
                cmd->cmd_dma = dma_map_page(hi->host->device.parent,
-                                           sg_page(&sgpnt[0]), sgpnt[0].offset,
+                                           sg_page(sg), sg->offset,
                                            cmd->dma_size, cmd->dma_dir);
 
                orb->data_descriptor_lo = cmd->cmd_dma;
@@ -1477,11 +1481,11 @@ static void sbp2_prep_command_orb_sg(struct sbp2_command_orb *orb,
                                                &cmd->scatter_gather_element[0];
                u32 sg_count, sg_len;
                dma_addr_t sg_addr;
-               int i, count = dma_map_sg(hi->host->device.parent, sgpnt,
+               int i, count = dma_map_sg(hi->host->device.parent, sg,
                                          scsi_use_sg, dma_dir);
 
                cmd->dma_size = scsi_use_sg;
-               cmd->sge_buffer = sgpnt;
+               cmd->sge_buffer = sg;
 
                /* use page tables (s/g) */
                orb->misc |= ORB_SET_PAGE_TABLE_PRESENT(0x1);
@@ -1489,9 +1493,9 @@ static void sbp2_prep_command_orb_sg(struct sbp2_command_orb *orb,
 
                /* loop through and fill out our SBP-2 page tables
                 * (and split up anything too large) */
-               for (i = 0, sg_count = 0 ; i < count; i++, sgpnt++) {
-                       sg_len = sg_dma_len(sgpnt);
-                       sg_addr = sg_dma_address(sgpnt);
+               for (i = 0, sg_count = 0; i < count; i++, sg = sg_next(sg)) {
+                       sg_len = sg_dma_len(sg);
+                       sg_addr = sg_dma_address(sg);
                        while (sg_len) {
                                sg_element[sg_count].segment_base_lo = sg_addr;
                                if (sg_len > SBP2_MAX_SG_ELEMENT_LENGTH) {
@@ -1521,11 +1525,10 @@ static void sbp2_create_command_orb(struct sbp2_lu *lu,
                                    unchar *scsi_cmd,
                                    unsigned int scsi_use_sg,
                                    unsigned int scsi_request_bufflen,
-                                   void *scsi_request_buffer,
+                                   struct scatterlist *sg,
                                    enum dma_data_direction dma_dir)
 {
        struct sbp2_fwhost_info *hi = lu->hi;
-       struct scatterlist *sgpnt = (struct scatterlist *)scsi_request_buffer;
        struct sbp2_command_orb *orb = &cmd->command_orb;
        u32 orb_direction;
 
@@ -1560,7 +1563,7 @@ static void sbp2_create_command_orb(struct sbp2_lu *lu,
                orb->data_descriptor_lo = 0x0;
                orb->misc |= ORB_SET_DIRECTION(1);
        } else
-               sbp2_prep_command_orb_sg(orb, hi, cmd, scsi_use_sg, sgpnt,
+               sbp2_prep_command_orb_sg(orb, hi, cmd, scsi_use_sg, sg,
                                         orb_direction, dma_dir);
 
        sbp2util_cpu_to_be32_buffer(orb, sizeof(*orb));
@@ -1650,7 +1653,6 @@ static int sbp2_send_command(struct sbp2_lu *lu, struct scsi_cmnd *SCpnt,
                             void (*done)(struct scsi_cmnd *))
 {
        unchar *scsi_cmd = (unchar *)SCpnt->cmnd;
-       unsigned int request_bufflen = scsi_bufflen(SCpnt);
        struct sbp2_command_info *cmd;
 
        cmd = sbp2util_allocate_command_orb(lu, SCpnt, done);
@@ -1658,7 +1660,7 @@ static int sbp2_send_command(struct sbp2_lu *lu, struct scsi_cmnd *SCpnt,
                return -EIO;
 
        sbp2_create_command_orb(lu, cmd, scsi_cmd, scsi_sg_count(SCpnt),
-                               request_bufflen, scsi_sglist(SCpnt),
+                               scsi_bufflen(SCpnt), scsi_sglist(SCpnt),
                                SCpnt->sc_data_direction);
        sbp2_link_orb_command(lu, cmd);
 
@@ -1987,6 +1989,8 @@ static int sbp2scsi_slave_configure(struct scsi_device *sdev)
                sdev->skip_ms_page_8 = 1;
        if (lu->workarounds & SBP2_WORKAROUND_FIX_CAPACITY)
                sdev->fix_capacity = 1;
+       if (lu->workarounds & SBP2_WORKAROUND_128K_MAX_TRANS)
+               blk_queue_max_sectors(sdev->request_queue, 128 * 1024 / 512);
        return 0;
 }
 
@@ -2093,9 +2097,6 @@ static int sbp2_module_init(void)
                sbp2_shost_template.cmd_per_lun = 1;
        }
 
-       if (sbp2_default_workarounds & SBP2_WORKAROUND_128K_MAX_TRANS &&
-           (sbp2_max_sectors * 512) > (128 * 1024))
-               sbp2_max_sectors = 128 * 1024 / 512;
        sbp2_shost_template.max_sectors = sbp2_max_sectors;
 
        hpsb_register_highlevel(&sbp2_highlevel);
index 333a4bb767434997bc0fa06e6fd922a063d46c86..d2ecb0d8a1bba4e577eef7c03dbcbb8df5ee0eee 100644 (file)
@@ -222,7 +222,6 @@ struct sbp2_status_block {
  */
 
 #define SBP2_MAX_SG_ELEMENT_LENGTH             0xf000
-#define SBP2_MAX_SECTORS                       255
 /* There is no real limitation of the queue depth (i.e. length of the linked
  * list of command ORBs) at the target. The chosen depth is merely an
  * implementation detail of the sbp2 driver. */
index a193dfbf99d2f38dd6c9066efb63daeaa14d3b1b..a5dc78ae62d43c5cef9722250f2a7e4db58cddcc 100644 (file)
@@ -44,8 +44,8 @@ source "drivers/infiniband/hw/ipath/Kconfig"
 source "drivers/infiniband/hw/ehca/Kconfig"
 source "drivers/infiniband/hw/amso1100/Kconfig"
 source "drivers/infiniband/hw/cxgb3/Kconfig"
-
 source "drivers/infiniband/hw/mlx4/Kconfig"
+source "drivers/infiniband/hw/nes/Kconfig"
 
 source "drivers/infiniband/ulp/ipoib/Kconfig"
 
index 75f325e40b54516e44e65934885053fae2782993..ed35e44962410ffaa7a715d30f2eba75bc3c6598 100644 (file)
@@ -5,6 +5,7 @@ obj-$(CONFIG_INFINIBAND_EHCA)           += hw/ehca/
 obj-$(CONFIG_INFINIBAND_AMSO1100)      += hw/amso1100/
 obj-$(CONFIG_INFINIBAND_CXGB3)         += hw/cxgb3/
 obj-$(CONFIG_MLX4_INFINIBAND)          += hw/mlx4/
+obj-$(CONFIG_INFINIBAND_NES)           += hw/nes/
 obj-$(CONFIG_INFINIBAND_IPOIB)         += ulp/ipoib/
 obj-$(CONFIG_INFINIBAND_SRP)           += ulp/srp/
 obj-$(CONFIG_INFINIBAND_ISER)          += ulp/iser/
index c0150147d3478d5c539d2e3e320e1722c4b408ba..638b727d42e0796ff57de4de2fd3b4881c1839c4 100644 (file)
@@ -974,6 +974,9 @@ static void cm_format_req(struct cm_req_msg *req_msg,
                          struct cm_id_private *cm_id_priv,
                          struct ib_cm_req_param *param)
 {
+       struct ib_sa_path_rec *pri_path = param->primary_path;
+       struct ib_sa_path_rec *alt_path = param->alternate_path;
+
        cm_format_mad_hdr(&req_msg->hdr, CM_REQ_ATTR_ID,
                          cm_form_tid(cm_id_priv, CM_MSG_SEQUENCE_REQ));
 
@@ -997,35 +1000,46 @@ static void cm_format_req(struct cm_req_msg *req_msg,
        cm_req_set_max_cm_retries(req_msg, param->max_cm_retries);
        cm_req_set_srq(req_msg, param->srq);
 
-       req_msg->primary_local_lid = param->primary_path->slid;
-       req_msg->primary_remote_lid = param->primary_path->dlid;
-       req_msg->primary_local_gid = param->primary_path->sgid;
-       req_msg->primary_remote_gid = param->primary_path->dgid;
-       cm_req_set_primary_flow_label(req_msg, param->primary_path->flow_label);
-       cm_req_set_primary_packet_rate(req_msg, param->primary_path->rate);
-       req_msg->primary_traffic_class = param->primary_path->traffic_class;
-       req_msg->primary_hop_limit = param->primary_path->hop_limit;
-       cm_req_set_primary_sl(req_msg, param->primary_path->sl);
-       cm_req_set_primary_subnet_local(req_msg, 1); /* local only... */
+       if (pri_path->hop_limit <= 1) {
+               req_msg->primary_local_lid = pri_path->slid;
+               req_msg->primary_remote_lid = pri_path->dlid;
+       } else {
+               /* Work-around until there's a way to obtain remote LID info */
+               req_msg->primary_local_lid = IB_LID_PERMISSIVE;
+               req_msg->primary_remote_lid = IB_LID_PERMISSIVE;
+       }
+       req_msg->primary_local_gid = pri_path->sgid;
+       req_msg->primary_remote_gid = pri_path->dgid;
+       cm_req_set_primary_flow_label(req_msg, pri_path->flow_label);
+       cm_req_set_primary_packet_rate(req_msg, pri_path->rate);
+       req_msg->primary_traffic_class = pri_path->traffic_class;
+       req_msg->primary_hop_limit = pri_path->hop_limit;
+       cm_req_set_primary_sl(req_msg, pri_path->sl);
+       cm_req_set_primary_subnet_local(req_msg, (pri_path->hop_limit <= 1));
        cm_req_set_primary_local_ack_timeout(req_msg,
                cm_ack_timeout(cm_id_priv->av.port->cm_dev->ack_delay,
-                              param->primary_path->packet_life_time));
+                              pri_path->packet_life_time));
 
-       if (param->alternate_path) {
-               req_msg->alt_local_lid = param->alternate_path->slid;
-               req_msg->alt_remote_lid = param->alternate_path->dlid;
-               req_msg->alt_local_gid = param->alternate_path->sgid;
-               req_msg->alt_remote_gid = param->alternate_path->dgid;
+       if (alt_path) {
+               if (alt_path->hop_limit <= 1) {
+                       req_msg->alt_local_lid = alt_path->slid;
+                       req_msg->alt_remote_lid = alt_path->dlid;
+               } else {
+                       req_msg->alt_local_lid = IB_LID_PERMISSIVE;
+                       req_msg->alt_remote_lid = IB_LID_PERMISSIVE;
+               }
+               req_msg->alt_local_gid = alt_path->sgid;
+               req_msg->alt_remote_gid = alt_path->dgid;
                cm_req_set_alt_flow_label(req_msg,
-                                         param->alternate_path->flow_label);
-               cm_req_set_alt_packet_rate(req_msg, param->alternate_path->rate);
-               req_msg->alt_traffic_class = param->alternate_path->traffic_class;
-               req_msg->alt_hop_limit = param->alternate_path->hop_limit;
-               cm_req_set_alt_sl(req_msg, param->alternate_path->sl);
-               cm_req_set_alt_subnet_local(req_msg, 1); /* local only... */
+                                         alt_path->flow_label);
+               cm_req_set_alt_packet_rate(req_msg, alt_path->rate);
+               req_msg->alt_traffic_class = alt_path->traffic_class;
+               req_msg->alt_hop_limit = alt_path->hop_limit;
+               cm_req_set_alt_sl(req_msg, alt_path->sl);
+               cm_req_set_alt_subnet_local(req_msg, (alt_path->hop_limit <= 1));
                cm_req_set_alt_local_ack_timeout(req_msg,
                        cm_ack_timeout(cm_id_priv->av.port->cm_dev->ack_delay,
-                                      param->alternate_path->packet_life_time));
+                                      alt_path->packet_life_time));
        }
 
        if (param->private_data && param->private_data_len)
@@ -1441,6 +1455,34 @@ out:
        return listen_cm_id_priv;
 }
 
+/*
+ * Work-around for inter-subnet connections.  If the LIDs are permissive,
+ * we need to override the LID/SL data in the REQ with the LID information
+ * in the work completion.
+ */
+static void cm_process_routed_req(struct cm_req_msg *req_msg, struct ib_wc *wc)
+{
+       if (!cm_req_get_primary_subnet_local(req_msg)) {
+               if (req_msg->primary_local_lid == IB_LID_PERMISSIVE) {
+                       req_msg->primary_local_lid = cpu_to_be16(wc->slid);
+                       cm_req_set_primary_sl(req_msg, wc->sl);
+               }
+
+               if (req_msg->primary_remote_lid == IB_LID_PERMISSIVE)
+                       req_msg->primary_remote_lid = cpu_to_be16(wc->dlid_path_bits);
+       }
+
+       if (!cm_req_get_alt_subnet_local(req_msg)) {
+               if (req_msg->alt_local_lid == IB_LID_PERMISSIVE) {
+                       req_msg->alt_local_lid = cpu_to_be16(wc->slid);
+                       cm_req_set_alt_sl(req_msg, wc->sl);
+               }
+
+               if (req_msg->alt_remote_lid == IB_LID_PERMISSIVE)
+                       req_msg->alt_remote_lid = cpu_to_be16(wc->dlid_path_bits);
+       }
+}
+
 static int cm_req_handler(struct cm_work *work)
 {
        struct ib_cm_id *cm_id;
@@ -1481,6 +1523,7 @@ static int cm_req_handler(struct cm_work *work)
        cm_id_priv->id.service_id = req_msg->service_id;
        cm_id_priv->id.service_mask = __constant_cpu_to_be64(~0ULL);
 
+       cm_process_routed_req(req_msg, work->mad_recv_wc->wc);
        cm_format_paths_from_req(req_msg, &work->path[0], &work->path[1]);
        ret = cm_init_av_by_path(&work->path[0], &cm_id_priv->av);
        if (ret) {
index 6c7aa59794d4ebb248f8e16fe789e7bdace6f81d..7f00347364f7a4b07f4b0237cb77ab45983c2732 100644 (file)
@@ -320,10 +320,13 @@ struct ib_fmr_pool *ib_create_fmr_pool(struct ib_pd             *pd,
                        .max_maps   = pool->max_remaps,
                        .page_shift = params->page_shift
                };
+               int bytes_per_fmr = sizeof *fmr;
+
+               if (pool->cache_bucket)
+                       bytes_per_fmr += params->max_pages_per_fmr * sizeof (u64);
 
                for (i = 0; i < params->pool_size; ++i) {
-                       fmr = kmalloc(sizeof *fmr + params->max_pages_per_fmr * sizeof (u64),
-                                     GFP_KERNEL);
+                       fmr = kmalloc(bytes_per_fmr, GFP_KERNEL);
                        if (!fmr) {
                                printk(KERN_WARNING PFX "failed to allocate fmr "
                                       "struct for FMR %d\n", i);
index f281d16040f5ac794e14e28820b37e537a7db51f..92cce8aacbb7279d3f45af63ac8e812001111ef6 100644 (file)
@@ -101,6 +101,7 @@ struct ehca_sport {
        spinlock_t mod_sqp_lock;
        enum ib_port_state port_state;
        struct ehca_sma_attr saved_attr;
+       u32 pma_qp_nr;
 };
 
 #define HCA_CAP_MR_PGSIZE_4K  0x80000000
index 863b34fa9ff9391c85fa1411d13ee4ce759436db..b5ca94c6b8d91a603aebff7f907c42f3234bb31e 100644 (file)
@@ -403,6 +403,8 @@ static void parse_ec(struct ehca_shca *shca, u64 eqe)
                        sport->port_state = IB_PORT_ACTIVE;
                        dispatch_port_event(shca, port, IB_EVENT_PORT_ACTIVE,
                                            "is active");
+                       ehca_query_sma_attr(shca, port,
+                                           &sport->saved_attr);
                } else
                        notify_port_conf_change(shca, port);
                break;
index c469bfde270875521f91411df5ea51b4f4bed13e..a8a2ea585d2f93c038300652e4a329f55ede6f27 100644 (file)
@@ -187,6 +187,11 @@ int ehca_dealloc_ucontext(struct ib_ucontext *context);
 
 int ehca_mmap(struct ib_ucontext *context, struct vm_area_struct *vma);
 
+int ehca_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num,
+                    struct ib_wc *in_wc, struct ib_grh *in_grh,
+                    struct ib_mad *in_mad,
+                    struct ib_mad *out_mad);
+
 void ehca_poll_eqs(unsigned long data);
 
 int ehca_calc_ipd(struct ehca_shca *shca, int port,
index 84c9b7b8669b0edc1833ff3c18c388d6feeb5999..a86ebcc79a95a7db5343cdcd4f37fb6a9a1e8d07 100644 (file)
@@ -472,7 +472,7 @@ int ehca_init_device(struct ehca_shca *shca)
        shca->ib_device.dealloc_fmr         = ehca_dealloc_fmr;
        shca->ib_device.attach_mcast        = ehca_attach_mcast;
        shca->ib_device.detach_mcast        = ehca_detach_mcast;
-       /* shca->ib_device.process_mad      = ehca_process_mad;     */
+       shca->ib_device.process_mad         = ehca_process_mad;
        shca->ib_device.mmap                = ehca_mmap;
 
        if (EHCA_BMASK_GET(HCA_CAP_SRQ, shca->hca_cap)) {
index 3aacc8cf1e448391feb37accef997118c5ca6f08..2ce8cffb8664537035586cf30a5004adcdb83a25 100644 (file)
@@ -209,6 +209,10 @@ static inline int ehca_write_swqe(struct ehca_qp *qp,
                        ehca_gen_err("wr.ud.ah is NULL. qp=%p", qp);
                        return -EINVAL;
                }
+               if (unlikely(send_wr->wr.ud.remote_qpn == 0)) {
+                       ehca_gen_err("dest QP# is 0. qp=%x", qp->real_qp_num);
+                       return -EINVAL;
+               }
                my_av = container_of(send_wr->wr.ud.ah, struct ehca_av, ib_ah);
                wqe_p->u.ud_av.ud_av = my_av->av;
 
index 79e72b25b252f33fd6d1d6d5c1ac18b1e12969bd..706d97ad5555cd5243cf8a2081d46c5f743b5b03 100644 (file)
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
+#include <rdma/ib_mad.h>
 
 #include "ehca_classes.h"
 #include "ehca_tools.h"
 #include "ehca_iverbs.h"
 #include "hcp_if.h"
 
+#define IB_MAD_STATUS_REDIRECT         __constant_htons(0x0002)
+#define IB_MAD_STATUS_UNSUP_VERSION    __constant_htons(0x0004)
+#define IB_MAD_STATUS_UNSUP_METHOD     __constant_htons(0x0008)
+
+#define IB_PMA_CLASS_PORT_INFO         __constant_htons(0x0001)
 
 /**
  * ehca_define_sqp - Defines special queue pair 1 (GSI QP). When special queue
@@ -83,6 +89,9 @@ u64 ehca_define_sqp(struct ehca_shca *shca,
                                 port, ret);
                        return ret;
                }
+               shca->sport[port - 1].pma_qp_nr = pma_qp_nr;
+               ehca_dbg(&shca->ib_device, "port=%x pma_qp_nr=%x",
+                        port, pma_qp_nr);
                break;
        default:
                ehca_err(&shca->ib_device, "invalid qp_type=%x",
@@ -109,3 +118,85 @@ u64 ehca_define_sqp(struct ehca_shca *shca,
 
        return H_SUCCESS;
 }
+
+struct ib_perf {
+       struct ib_mad_hdr mad_hdr;
+       u8 reserved[40];
+       u8 data[192];
+} __attribute__ ((packed));
+
+
+static int ehca_process_perf(struct ib_device *ibdev, u8 port_num,
+                            struct ib_mad *in_mad, struct ib_mad *out_mad)
+{
+       struct ib_perf *in_perf = (struct ib_perf *)in_mad;
+       struct ib_perf *out_perf = (struct ib_perf *)out_mad;
+       struct ib_class_port_info *poi =
+               (struct ib_class_port_info *)out_perf->data;
+       struct ehca_shca *shca =
+               container_of(ibdev, struct ehca_shca, ib_device);
+       struct ehca_sport *sport = &shca->sport[port_num - 1];
+
+       ehca_dbg(ibdev, "method=%x", in_perf->mad_hdr.method);
+
+       *out_mad = *in_mad;
+
+       if (in_perf->mad_hdr.class_version != 1) {
+               ehca_warn(ibdev, "Unsupported class_version=%x",
+                         in_perf->mad_hdr.class_version);
+               out_perf->mad_hdr.status = IB_MAD_STATUS_UNSUP_VERSION;
+               goto perf_reply;
+       }
+
+       switch (in_perf->mad_hdr.method) {
+       case IB_MGMT_METHOD_GET:
+       case IB_MGMT_METHOD_SET:
+               /* set class port info for redirection */
+               out_perf->mad_hdr.attr_id = IB_PMA_CLASS_PORT_INFO;
+               out_perf->mad_hdr.status = IB_MAD_STATUS_REDIRECT;
+               memset(poi, 0, sizeof(*poi));
+               poi->base_version = 1;
+               poi->class_version = 1;
+               poi->resp_time_value = 18;
+               poi->redirect_lid = sport->saved_attr.lid;
+               poi->redirect_qp = sport->pma_qp_nr;
+               poi->redirect_qkey = IB_QP1_QKEY;
+               poi->redirect_pkey = IB_DEFAULT_PKEY_FULL;
+
+               ehca_dbg(ibdev, "ehca_pma_lid=%x ehca_pma_qp=%x",
+                        sport->saved_attr.lid, sport->pma_qp_nr);
+               break;
+
+       case IB_MGMT_METHOD_GET_RESP:
+               return IB_MAD_RESULT_FAILURE;
+
+       default:
+               out_perf->mad_hdr.status = IB_MAD_STATUS_UNSUP_METHOD;
+               break;
+       }
+
+perf_reply:
+       out_perf->mad_hdr.method = IB_MGMT_METHOD_GET_RESP;
+
+       return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_REPLY;
+}
+
+int ehca_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num,
+                    struct ib_wc *in_wc, struct ib_grh *in_grh,
+                    struct ib_mad *in_mad,
+                    struct ib_mad *out_mad)
+{
+       int ret;
+
+       if (!port_num || port_num > ibdev->phys_port_cnt)
+               return IB_MAD_RESULT_FAILURE;
+
+       /* accept only pma request */
+       if (in_mad->mad_hdr.mgmt_class != IB_MGMT_CLASS_PERF_MGMT)
+               return IB_MAD_RESULT_SUCCESS;
+
+       ehca_dbg(ibdev, "port_num=%x src_qp=%x", port_num, in_wc->src_qp);
+       ret = ehca_process_perf(ibdev, port_num, in_mad, out_mad);
+
+       return ret;
+}
index d8287d9db41e5a8eb0bb3167db75635c266b4960..96a39b5c9254491a6e0b0aae227f7fb327ad0df9 100644 (file)
@@ -52,7 +52,7 @@ MODULE_DESCRIPTION("Mellanox ConnectX HCA InfiniBand driver");
 MODULE_LICENSE("Dual BSD/GPL");
 MODULE_VERSION(DRV_VERSION);
 
-static const char mlx4_ib_version[] __devinitdata =
+static const char mlx4_ib_version[] =
        DRV_NAME ": Mellanox ConnectX InfiniBand driver v"
        DRV_VERSION " (" DRV_RELDATE ")\n";
 
@@ -468,6 +468,7 @@ static int init_node_data(struct mlx4_ib_dev *dev)
        if (err)
                goto out;
 
+       dev->dev->rev_id = be32_to_cpup((__be32 *) (out_mad->data + 32));
        memcpy(&dev->ib_dev.node_guid, out_mad->data + 12, 8);
 
 out:
@@ -516,9 +517,16 @@ static struct class_device_attribute *mlx4_class_attributes[] = {
 
 static void *mlx4_ib_add(struct mlx4_dev *dev)
 {
+       static int mlx4_ib_version_printed;
        struct mlx4_ib_dev *ibdev;
        int i;
 
+
+       if (!mlx4_ib_version_printed) {
+               printk(KERN_INFO "%s", mlx4_ib_version);
+               ++mlx4_ib_version_printed;
+       }
+
        ibdev = (struct mlx4_ib_dev *) ib_alloc_device(sizeof *ibdev);
        if (!ibdev) {
                dev_err(&dev->pdev->dev, "Device struct alloc failed\n");
index 6966f943f44036b2fee4c07ccb4f0eda25a0956f..09a30dd12b147433020a796ef94b21cd33725bf3 100644 (file)
@@ -1255,9 +1255,14 @@ int mthca_QUERY_ADAPTER(struct mthca_dev *dev,
        if (err)
                goto out;
 
-       MTHCA_GET(adapter->vendor_id, outbox,   QUERY_ADAPTER_VENDOR_ID_OFFSET);
-       MTHCA_GET(adapter->device_id, outbox,   QUERY_ADAPTER_DEVICE_ID_OFFSET);
-       MTHCA_GET(adapter->revision_id, outbox, QUERY_ADAPTER_REVISION_ID_OFFSET);
+       if (!mthca_is_memfree(dev)) {
+               MTHCA_GET(adapter->vendor_id, outbox,
+                         QUERY_ADAPTER_VENDOR_ID_OFFSET);
+               MTHCA_GET(adapter->device_id, outbox,
+                         QUERY_ADAPTER_DEVICE_ID_OFFSET);
+               MTHCA_GET(adapter->revision_id, outbox,
+                         QUERY_ADAPTER_REVISION_ID_OFFSET);
+       }
        MTHCA_GET(adapter->inta_pin, outbox,    QUERY_ADAPTER_INTA_PIN_OFFSET);
 
        get_board_id(outbox + QUERY_ADAPTER_VSD_OFFSET / 4,
index 5cf8250d4e164003312fed79579b578267c94eed..cd3d8adbef9ffe6a5f6d8d152ad9b5b8aa20c155 100644 (file)
@@ -126,7 +126,7 @@ module_param_named(fmr_reserved_mtts, hca_profile.fmr_reserved_mtts, int, 0444);
 MODULE_PARM_DESC(fmr_reserved_mtts,
                 "number of memory translation table segments reserved for FMR");
 
-static const char mthca_version[] __devinitdata =
+static char mthca_version[] __devinitdata =
        DRV_NAME ": Mellanox InfiniBand HCA driver v"
        DRV_VERSION " (" DRV_RELDATE ")\n";
 
@@ -735,7 +735,8 @@ static int mthca_init_hca(struct mthca_dev *mdev)
        }
 
        mdev->eq_table.inta_pin = adapter.inta_pin;
-       mdev->rev_id            = adapter.revision_id;
+       if (!mthca_is_memfree(mdev))
+               mdev->rev_id = adapter.revision_id;
        memcpy(mdev->board_id, adapter.board_id, sizeof mdev->board_id);
 
        return 0;
index aa6c70a6a36f24c35fbfc3d7bff3b741a18f6cae..3b6985557cb21cb77cc05df345a9dfb8dd573d3d 100644 (file)
@@ -613,8 +613,10 @@ int mthca_fmr_alloc(struct mthca_dev *dev, u32 pd,
                        sizeof *(mr->mem.tavor.mpt) * idx;
 
        mr->mtt = __mthca_alloc_mtt(dev, list_len, dev->mr_table.fmr_mtt_buddy);
-       if (IS_ERR(mr->mtt))
+       if (IS_ERR(mr->mtt)) {
+               err = PTR_ERR(mr->mtt);
                goto err_out_table;
+       }
 
        mtt_seg = mr->mtt->first_seg * MTHCA_MTT_SEG_SIZE;
 
@@ -627,8 +629,10 @@ int mthca_fmr_alloc(struct mthca_dev *dev, u32 pd,
                mr->mem.tavor.mtts = dev->mr_table.tavor_fmr.mtt_base + mtt_seg;
 
        mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
-       if (IS_ERR(mailbox))
+       if (IS_ERR(mailbox)) {
+               err = PTR_ERR(mailbox);
                goto err_out_free_mtt;
+       }
 
        mpt_entry = mailbox->buf;
 
index 6bcde1cb9688f9860b8116fb22526553a23d5746..9e491df6419cd12b2266fb2846f381479d6e07b4 100644 (file)
@@ -923,17 +923,13 @@ static struct ib_mr *mthca_reg_phys_mr(struct ib_pd       *pd,
        struct mthca_mr *mr;
        u64 *page_list;
        u64 total_size;
-       u64 mask;
+       unsigned long mask;
        int shift;
        int npages;
        int err;
        int i, j, n;
 
-       /* First check that we have enough alignment */
-       if ((*iova_start & ~PAGE_MASK) != (buffer_list[0].addr & ~PAGE_MASK))
-               return ERR_PTR(-EINVAL);
-
-       mask = 0;
+       mask = buffer_list[0].addr ^ *iova_start;
        total_size = 0;
        for (i = 0; i < num_phys_buf; ++i) {
                if (i != 0)
@@ -947,17 +943,7 @@ static struct ib_mr *mthca_reg_phys_mr(struct ib_pd       *pd,
        if (mask & ~PAGE_MASK)
                return ERR_PTR(-EINVAL);
 
-       /* Find largest page shift we can use to cover buffers */
-       for (shift = PAGE_SHIFT; shift < 31; ++shift)
-               if (num_phys_buf > 1) {
-                       if ((1ULL << shift) & mask)
-                               break;
-               } else {
-                       if (1ULL << shift >=
-                           buffer_list[0].size +
-                           (buffer_list[0].addr & ((1ULL << shift) - 1)))
-                               break;
-               }
+       shift = __ffs(mask | 1 << 31);
 
        buffer_list[0].size += buffer_list[0].addr & ((1ULL << shift) - 1);
        buffer_list[0].addr &= ~0ull << shift;
@@ -1270,6 +1256,8 @@ static int mthca_init_node_data(struct mthca_dev *dev)
                goto out;
        }
 
+       if (mthca_is_memfree(dev))
+               dev->rev_id = be32_to_cpup((__be32 *) (out_mad->data + 32));
        memcpy(&dev->ib_dev.node_guid, out_mad->data + 12, 8);
 
 out:
index 0e5461c65731db15ec38a16bc670ca331f69b4b7..db5595bbf7f08fb30e5993a301e063b2df21ee05 100644 (file)
@@ -1175,6 +1175,7 @@ static int mthca_alloc_qp_common(struct mthca_dev *dev,
 {
        int ret;
        int i;
+       struct mthca_next_seg *next;
 
        qp->refcount = 1;
        init_waitqueue_head(&qp->wait);
@@ -1217,7 +1218,6 @@ static int mthca_alloc_qp_common(struct mthca_dev *dev,
        }
 
        if (mthca_is_memfree(dev)) {
-               struct mthca_next_seg *next;
                struct mthca_data_seg *scatter;
                int size = (sizeof (struct mthca_next_seg) +
                            qp->rq.max_gs * sizeof (struct mthca_data_seg)) / 16;
@@ -1240,6 +1240,13 @@ static int mthca_alloc_qp_common(struct mthca_dev *dev,
                                                    qp->sq.wqe_shift) +
                                                   qp->send_wqe_offset);
                }
+       } else {
+               for (i = 0; i < qp->rq.max; ++i) {
+                       next = get_recv_wqe(qp, i);
+                       next->nda_op = htonl((((i + 1) % qp->rq.max) <<
+                                             qp->rq.wqe_shift) | 1);
+               }
+
        }
 
        qp->sq.last = get_send_wqe(qp, qp->sq.max - 1);
@@ -1863,7 +1870,6 @@ int mthca_tavor_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr,
                prev_wqe = qp->rq.last;
                qp->rq.last = wqe;
 
-               ((struct mthca_next_seg *) wqe)->nda_op = 0;
                ((struct mthca_next_seg *) wqe)->ee_nds =
                        cpu_to_be32(MTHCA_NEXT_DBD);
                ((struct mthca_next_seg *) wqe)->flags = 0;
@@ -1885,9 +1891,6 @@ int mthca_tavor_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr,
 
                qp->wrid[ind] = wr->wr_id;
 
-               ((struct mthca_next_seg *) prev_wqe)->nda_op =
-                       cpu_to_be32((ind << qp->rq.wqe_shift) | 1);
-               wmb();
                ((struct mthca_next_seg *) prev_wqe)->ee_nds =
                        cpu_to_be32(MTHCA_NEXT_DBD | size);
 
index 553d681f6813a709a2d8e2a5601c8e1dc98bc902..a5ffff6e10263c06c296c0c6d7c0dd3f35b8bd2f 100644 (file)
@@ -175,9 +175,17 @@ static int mthca_alloc_srq_buf(struct mthca_dev *dev, struct mthca_pd *pd,
         * scatter list L_Keys to the sentry value of 0x100.
         */
        for (i = 0; i < srq->max; ++i) {
-               wqe = get_wqe(srq, i);
+               struct mthca_next_seg *next;
 
-               *wqe_to_link(wqe) = i < srq->max - 1 ? i + 1 : -1;
+               next = wqe = get_wqe(srq, i);
+
+               if (i < srq->max - 1) {
+                       *wqe_to_link(wqe) = i + 1;
+                       next->nda_op = htonl(((i + 1) << srq->wqe_shift) | 1);
+               } else {
+                       *wqe_to_link(wqe) = -1;
+                       next->nda_op = 0;
+               }
 
                for (scatter = wqe + sizeof (struct mthca_next_seg);
                     (void *) scatter < wqe + (1 << srq->wqe_shift);
@@ -470,16 +478,15 @@ out:
 void mthca_free_srq_wqe(struct mthca_srq *srq, u32 wqe_addr)
 {
        int ind;
+       struct mthca_next_seg *last_free;
 
        ind = wqe_addr >> srq->wqe_shift;
 
        spin_lock(&srq->lock);
 
-       if (likely(srq->first_free >= 0))
-               *wqe_to_link(get_wqe(srq, srq->last_free)) = ind;
-       else
-               srq->first_free = ind;
-
+       last_free = get_wqe(srq, srq->last_free);
+       *wqe_to_link(last_free) = ind;
+       last_free->nda_op = htonl((ind << srq->wqe_shift) | 1);
        *wqe_to_link(get_wqe(srq, ind)) = -1;
        srq->last_free = ind;
 
@@ -506,15 +513,7 @@ int mthca_tavor_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr,
        first_ind = srq->first_free;
 
        for (nreq = 0; wr; wr = wr->next) {
-               ind = srq->first_free;
-
-               if (unlikely(ind < 0)) {
-                       mthca_err(dev, "SRQ %06x full\n", srq->srqn);
-                       err = -ENOMEM;
-                       *bad_wr = wr;
-                       break;
-               }
-
+               ind       = srq->first_free;
                wqe       = get_wqe(srq, ind);
                next_ind  = *wqe_to_link(wqe);
 
@@ -528,7 +527,6 @@ int mthca_tavor_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr,
                prev_wqe  = srq->last;
                srq->last = wqe;
 
-               ((struct mthca_next_seg *) wqe)->nda_op = 0;
                ((struct mthca_next_seg *) wqe)->ee_nds = 0;
                /* flags field will always remain 0 */
 
@@ -549,9 +547,6 @@ int mthca_tavor_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr,
                if (i < srq->max_gs)
                        mthca_set_data_seg_inval(wqe);
 
-               ((struct mthca_next_seg *) prev_wqe)->nda_op =
-                       cpu_to_be32((ind << srq->wqe_shift) | 1);
-               wmb();
                ((struct mthca_next_seg *) prev_wqe)->ee_nds =
                        cpu_to_be32(MTHCA_NEXT_DBD);
 
@@ -614,15 +609,7 @@ int mthca_arbel_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr,
        spin_lock_irqsave(&srq->lock, flags);
 
        for (nreq = 0; wr; ++nreq, wr = wr->next) {
-               ind = srq->first_free;
-
-               if (unlikely(ind < 0)) {
-                       mthca_err(dev, "SRQ %06x full\n", srq->srqn);
-                       err = -ENOMEM;
-                       *bad_wr = wr;
-                       break;
-               }
-
+               ind       = srq->first_free;
                wqe       = get_wqe(srq, ind);
                next_ind  = *wqe_to_link(wqe);
 
@@ -633,8 +620,6 @@ int mthca_arbel_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr,
                        break;
                }
 
-               ((struct mthca_next_seg *) wqe)->nda_op =
-                       cpu_to_be32((next_ind << srq->wqe_shift) | 1);
                ((struct mthca_next_seg *) wqe)->ee_nds = 0;
                /* flags field will always remain 0 */
 
diff --git a/drivers/infiniband/hw/nes/Kconfig b/drivers/infiniband/hw/nes/Kconfig
new file mode 100644 (file)
index 0000000..2aeb7ac
--- /dev/null
@@ -0,0 +1,16 @@
+config INFINIBAND_NES
+       tristate "NetEffect RNIC Driver"
+       depends on PCI && INET && INFINIBAND
+       select LIBCRC32C
+       ---help---
+         This is a low-level driver for NetEffect RDMA enabled
+         Network Interface Cards (RNIC).
+
+config INFINIBAND_NES_DEBUG
+       bool "Verbose debugging output"
+       depends on INFINIBAND_NES
+       default n
+       ---help---
+         This option causes the NetEffect RNIC driver to produce debug
+         messages.  Select this if you are developing the driver
+         or trying to diagnose a problem.
diff --git a/drivers/infiniband/hw/nes/Makefile b/drivers/infiniband/hw/nes/Makefile
new file mode 100644 (file)
index 0000000..3514851
--- /dev/null
@@ -0,0 +1,3 @@
+obj-$(CONFIG_INFINIBAND_NES) += iw_nes.o
+
+iw_nes-objs := nes.o nes_hw.o nes_nic.o nes_utils.o nes_verbs.o nes_cm.o
diff --git a/drivers/infiniband/hw/nes/nes.c b/drivers/infiniband/hw/nes/nes.c
new file mode 100644 (file)
index 0000000..7f8853b
--- /dev/null
@@ -0,0 +1,1152 @@
+/*
+ * Copyright (c) 2006 - 2008 NetEffect, Inc. All rights reserved.
+ * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include <linux/if_vlan.h>
+#include <linux/crc32.h>
+#include <linux/in.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/if_arp.h>
+#include <linux/highmem.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/byteorder.h>
+#include <rdma/ib_smi.h>
+#include <rdma/ib_verbs.h>
+#include <rdma/ib_pack.h>
+#include <rdma/iw_cm.h>
+
+#include "nes.h"
+
+#include <net/netevent.h>
+#include <net/neighbour.h>
+#include <linux/route.h>
+#include <net/ip_fib.h>
+
+MODULE_AUTHOR("NetEffect");
+MODULE_DESCRIPTION("NetEffect RNIC Low-level iWARP Driver");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_VERSION(DRV_VERSION);
+
+int max_mtu = 9000;
+int nics_per_function = 1;
+int interrupt_mod_interval = 0;
+
+
+/* Interoperability */
+int mpa_version = 1;
+module_param(mpa_version, int, 0);
+MODULE_PARM_DESC(mpa_version, "MPA version to be used int MPA Req/Resp (0 or 1)");
+
+/* Interoperability */
+int disable_mpa_crc = 0;
+module_param(disable_mpa_crc, int, 0);
+MODULE_PARM_DESC(disable_mpa_crc, "Disable checking of MPA CRC");
+
+unsigned int send_first = 0;
+module_param(send_first, int, 0);
+MODULE_PARM_DESC(send_first, "Send RDMA Message First on Active Connection");
+
+
+unsigned int nes_drv_opt = 0;
+module_param(nes_drv_opt, int, 0);
+MODULE_PARM_DESC(nes_drv_opt, "Driver option parameters");
+
+unsigned int nes_debug_level = 0;
+module_param_named(debug_level, nes_debug_level, uint, 0644);
+MODULE_PARM_DESC(debug_level, "Enable debug output level");
+
+LIST_HEAD(nes_adapter_list);
+LIST_HEAD(nes_dev_list);
+
+atomic_t qps_destroyed;
+atomic_t cqp_reqs_allocated;
+atomic_t cqp_reqs_freed;
+atomic_t cqp_reqs_dynallocated;
+atomic_t cqp_reqs_dynfreed;
+atomic_t cqp_reqs_queued;
+atomic_t cqp_reqs_redriven;
+
+static void nes_print_macaddr(struct net_device *netdev);
+static irqreturn_t nes_interrupt(int, void *);
+static int __devinit nes_probe(struct pci_dev *, const struct pci_device_id *);
+static void __devexit nes_remove(struct pci_dev *);
+static int __init nes_init_module(void);
+static void __exit nes_exit_module(void);
+static unsigned int ee_flsh_adapter;
+static unsigned int sysfs_nonidx_addr;
+static unsigned int sysfs_idx_addr;
+
+static struct pci_device_id nes_pci_table[] = {
+       {PCI_VENDOR_ID_NETEFFECT, PCI_DEVICE_ID_NETEFFECT_NE020, PCI_ANY_ID, PCI_ANY_ID},
+       {0}
+};
+
+MODULE_DEVICE_TABLE(pci, nes_pci_table);
+
+static int nes_inetaddr_event(struct notifier_block *, unsigned long, void *);
+static int nes_net_event(struct notifier_block *, unsigned long, void *);
+static int nes_notifiers_registered;
+
+
+static struct notifier_block nes_inetaddr_notifier = {
+       .notifier_call = nes_inetaddr_event
+};
+
+static struct notifier_block nes_net_notifier = {
+       .notifier_call = nes_net_event
+};
+
+
+
+
+/**
+ * nes_inetaddr_event
+ */
+static int nes_inetaddr_event(struct notifier_block *notifier,
+               unsigned long event, void *ptr)
+{
+       struct in_ifaddr *ifa = ptr;
+       struct net_device *event_netdev = ifa->ifa_dev->dev;
+       struct nes_device *nesdev;
+       struct net_device *netdev;
+       struct nes_vnic *nesvnic;
+       unsigned int addr;
+       unsigned int mask;
+
+       addr = ntohl(ifa->ifa_address);
+       mask = ntohl(ifa->ifa_mask);
+       nes_debug(NES_DBG_NETDEV, "nes_inetaddr_event: ip address %08X, netmask %08X.\n",
+                       addr, mask);
+       list_for_each_entry(nesdev, &nes_dev_list, list) {
+               nes_debug(NES_DBG_NETDEV, "Nesdev list entry = 0x%p. (%s)\n",
+                               nesdev, nesdev->netdev[0]->name);
+               netdev = nesdev->netdev[0];
+               nesvnic = netdev_priv(netdev);
+               if (netdev == event_netdev) {
+                       if (nesvnic->rdma_enabled == 0) {
+                               nes_debug(NES_DBG_NETDEV, "Returning without processing event for %s since"
+                                               " RDMA is not enabled.\n",
+                                               netdev->name);
+                               return NOTIFY_OK;
+                       }
+                       /* we have ifa->ifa_address/mask here if we need it */
+                       switch (event) {
+                               case NETDEV_DOWN:
+                                       nes_debug(NES_DBG_NETDEV, "event:DOWN\n");
+                                       nes_write_indexed(nesdev,
+                                                       NES_IDX_DST_IP_ADDR+(0x10*PCI_FUNC(nesdev->pcidev->devfn)), 0);
+
+                                       nes_manage_arp_cache(netdev, netdev->dev_addr,
+                                                       ntohl(nesvnic->local_ipaddr), NES_ARP_DELETE);
+                                       nesvnic->local_ipaddr = 0;
+                                       return NOTIFY_OK;
+                                       break;
+                               case NETDEV_UP:
+                                       nes_debug(NES_DBG_NETDEV, "event:UP\n");
+
+                                       if (nesvnic->local_ipaddr != 0) {
+                                               nes_debug(NES_DBG_NETDEV, "Interface already has local_ipaddr\n");
+                                               return NOTIFY_OK;
+                                       }
+                                       /* Add the address to the IP table */
+                                       nesvnic->local_ipaddr = ifa->ifa_address;
+
+                                       nes_write_indexed(nesdev,
+                                                       NES_IDX_DST_IP_ADDR+(0x10*PCI_FUNC(nesdev->pcidev->devfn)),
+                                                       ntohl(ifa->ifa_address));
+                                       nes_manage_arp_cache(netdev, netdev->dev_addr,
+                                                       ntohl(nesvnic->local_ipaddr), NES_ARP_ADD);
+                                       return NOTIFY_OK;
+                                       break;
+                               default:
+                                       break;
+                       }
+               }
+       }
+
+       return NOTIFY_DONE;
+}
+
+
+/**
+ * nes_net_event
+ */
+static int nes_net_event(struct notifier_block *notifier,
+               unsigned long event, void *ptr)
+{
+       struct neighbour *neigh = ptr;
+       struct nes_device *nesdev;
+       struct net_device *netdev;
+       struct nes_vnic *nesvnic;
+
+       switch (event) {
+               case NETEVENT_NEIGH_UPDATE:
+                       list_for_each_entry(nesdev, &nes_dev_list, list) {
+                               /* nes_debug(NES_DBG_NETDEV, "Nesdev list entry = 0x%p.\n", nesdev); */
+                               netdev = nesdev->netdev[0];
+                               nesvnic = netdev_priv(netdev);
+                               if (netdev == neigh->dev) {
+                                       if (nesvnic->rdma_enabled == 0) {
+                                               nes_debug(NES_DBG_NETDEV, "Skipping device %s since no RDMA\n",
+                                                               netdev->name);
+                                       } else {
+                                               if (neigh->nud_state & NUD_VALID) {
+                                                       nes_manage_arp_cache(neigh->dev, neigh->ha,
+                                                                       ntohl(*(__be32 *)neigh->primary_key), NES_ARP_ADD);
+                                               } else {
+                                                       nes_manage_arp_cache(neigh->dev, neigh->ha,
+                                                                       ntohl(*(__be32 *)neigh->primary_key), NES_ARP_DELETE);
+                                               }
+                                       }
+                                       return NOTIFY_OK;
+                               }
+                       }
+                       break;
+               default:
+                       nes_debug(NES_DBG_NETDEV, "NETEVENT_ %lu undefined\n", event);
+                       break;
+       }
+
+       return NOTIFY_DONE;
+}
+
+
+/**
+ * nes_add_ref
+ */
+void nes_add_ref(struct ib_qp *ibqp)
+{
+       struct nes_qp *nesqp;
+
+       nesqp = to_nesqp(ibqp);
+       nes_debug(NES_DBG_QP, "Bumping refcount for QP%u.  Pre-inc value = %u\n",
+                       ibqp->qp_num, atomic_read(&nesqp->refcount));
+       atomic_inc(&nesqp->refcount);
+}
+
+static void nes_cqp_rem_ref_callback(struct nes_device *nesdev, struct nes_cqp_request *cqp_request)
+{
+       unsigned long flags;
+       struct nes_qp *nesqp = cqp_request->cqp_callback_pointer;
+       struct nes_adapter *nesadapter = nesdev->nesadapter;
+       u32 qp_id;
+
+       atomic_inc(&qps_destroyed);
+
+       /* Free the control structures */
+
+       qp_id = nesqp->hwqp.qp_id;
+       if (nesqp->pbl_vbase) {
+               pci_free_consistent(nesdev->pcidev, nesqp->qp_mem_size,
+                               nesqp->hwqp.q2_vbase, nesqp->hwqp.q2_pbase);
+               spin_lock_irqsave(&nesadapter->pbl_lock, flags);
+               nesadapter->free_256pbl++;
+               spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
+               pci_free_consistent(nesdev->pcidev, 256, nesqp->pbl_vbase, nesqp->pbl_pbase);
+               nesqp->pbl_vbase = NULL;
+
+       } else {
+               pci_free_consistent(nesdev->pcidev, nesqp->qp_mem_size,
+                               nesqp->hwqp.sq_vbase, nesqp->hwqp.sq_pbase);
+       }
+       nes_free_resource(nesadapter, nesadapter->allocated_qps, nesqp->hwqp.qp_id);
+
+       kfree(nesqp->allocated_buffer);
+
+}
+
+/**
+ * nes_rem_ref
+ */
+void nes_rem_ref(struct ib_qp *ibqp)
+{
+       u64 u64temp;
+       struct nes_qp *nesqp;
+       struct nes_vnic *nesvnic = to_nesvnic(ibqp->device);
+       struct nes_device *nesdev = nesvnic->nesdev;
+       struct nes_adapter *nesadapter = nesdev->nesadapter;
+       struct nes_hw_cqp_wqe *cqp_wqe;
+       struct nes_cqp_request *cqp_request;
+       u32 opcode;
+
+       nesqp = to_nesqp(ibqp);
+
+       if (atomic_read(&nesqp->refcount) == 0) {
+               printk(KERN_INFO PFX "%s: Reference count already 0 for QP%d, last aeq = 0x%04X.\n",
+                               __FUNCTION__, ibqp->qp_num, nesqp->last_aeq);
+               BUG();
+       }
+
+       if (atomic_dec_and_test(&nesqp->refcount)) {
+               nesadapter->qp_table[nesqp->hwqp.qp_id-NES_FIRST_QPN] = NULL;
+
+               /* Destroy the QP */
+               cqp_request = nes_get_cqp_request(nesdev);
+               if (cqp_request == NULL) {
+                       nes_debug(NES_DBG_QP, "Failed to get a cqp_request.\n");
+                       return;
+               }
+               cqp_request->waiting = 0;
+               cqp_request->callback = 1;
+               cqp_request->cqp_callback = nes_cqp_rem_ref_callback;
+               cqp_request->cqp_callback_pointer = nesqp;
+               cqp_wqe = &cqp_request->cqp_wqe;
+
+               nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
+               opcode = NES_CQP_DESTROY_QP | NES_CQP_QP_TYPE_IWARP;
+
+               if (nesqp->hte_added) {
+                       opcode  |= NES_CQP_QP_DEL_HTE;
+                       nesqp->hte_added = 0;
+               }
+               set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_OPCODE_IDX, opcode);
+               set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_ID_IDX, nesqp->hwqp.qp_id);
+               u64temp = (u64)nesqp->nesqp_context_pbase;
+               set_wqe_64bit_value(cqp_wqe->wqe_words, NES_CQP_QP_WQE_CONTEXT_LOW_IDX, u64temp);
+               nes_post_cqp_request(nesdev, cqp_request, NES_CQP_REQUEST_RING_DOORBELL);
+       }
+}
+
+
+/**
+ * nes_get_qp
+ */
+struct ib_qp *nes_get_qp(struct ib_device *device, int qpn)
+{
+       struct nes_vnic *nesvnic = to_nesvnic(device);
+       struct nes_device *nesdev = nesvnic->nesdev;
+       struct nes_adapter *nesadapter = nesdev->nesadapter;
+
+       if ((qpn < NES_FIRST_QPN) || (qpn >= (NES_FIRST_QPN + nesadapter->max_qp)))
+               return NULL;
+
+       return &nesadapter->qp_table[qpn - NES_FIRST_QPN]->ibqp;
+}
+
+
+/**
+ * nes_print_macaddr
+ */
+static void nes_print_macaddr(struct net_device *netdev)
+{
+       nes_debug(NES_DBG_INIT, "%s: MAC %02X:%02X:%02X:%02X:%02X:%02X, IRQ %u\n",
+                       netdev->name,
+                       netdev->dev_addr[0], netdev->dev_addr[1], netdev->dev_addr[2],
+                       netdev->dev_addr[3], netdev->dev_addr[4], netdev->dev_addr[5],
+                       netdev->irq);
+}
+
+
+/**
+ * nes_interrupt - handle interrupts
+ */
+static irqreturn_t nes_interrupt(int irq, void *dev_id)
+{
+       struct nes_device *nesdev = (struct nes_device *)dev_id;
+       int handled = 0;
+       u32 int_mask;
+       u32 int_req;
+       u32 int_stat;
+       u32 intf_int_stat;
+       u32 timer_stat;
+
+       if (nesdev->msi_enabled) {
+               /* No need to read the interrupt pending register if msi is enabled */
+               handled = 1;
+       } else {
+               if (unlikely(nesdev->nesadapter->hw_rev == NE020_REV)) {
+                       /* Master interrupt enable provides synchronization for kicking off bottom half
+                         when interrupt sharing is going on */
+                       int_mask = nes_read32(nesdev->regs + NES_INT_MASK);
+                       if (int_mask & 0x80000000) {
+                               /* Check interrupt status to see if this might be ours */
+                               int_stat = nes_read32(nesdev->regs + NES_INT_STAT);
+                               int_req = nesdev->int_req;
+                               if (int_stat&int_req) {
+                                       /* if interesting CEQ or AEQ is pending, claim the interrupt */
+                                       if ((int_stat&int_req) & (~(NES_INT_TIMER|NES_INT_INTF))) {
+                                               handled = 1;
+                                       } else {
+                                               if (((int_stat & int_req) & NES_INT_TIMER) == NES_INT_TIMER) {
+                                                       /* Timer might be running but might be for another function */
+                                                       timer_stat = nes_read32(nesdev->regs + NES_TIMER_STAT);
+                                                       if ((timer_stat & nesdev->timer_int_req) != 0) {
+                                                               handled = 1;
+                                                       }
+                                               }
+                                               if ((((int_stat & int_req) & NES_INT_INTF) == NES_INT_INTF) &&
+                                                               (handled == 0)) {
+                                                       intf_int_stat = nes_read32(nesdev->regs+NES_INTF_INT_STAT);
+                                                       if ((intf_int_stat & nesdev->intf_int_req) != 0) {
+                                                               handled = 1;
+                                                       }
+                                               }
+                                       }
+                                       if (handled) {
+                                               nes_write32(nesdev->regs+NES_INT_MASK, int_mask & (~0x80000000));
+                                               int_mask = nes_read32(nesdev->regs+NES_INT_MASK);
+                                               /* Save off the status to save an additional read */
+                                               nesdev->int_stat = int_stat;
+                                               nesdev->napi_isr_ran = 1;
+                                       }
+                               }
+                       }
+               } else {
+                       handled = nes_read32(nesdev->regs+NES_INT_PENDING);
+               }
+       }
+
+       if (handled) {
+
+               if (nes_napi_isr(nesdev) == 0) {
+                       tasklet_schedule(&nesdev->dpc_tasklet);
+
+               }
+               return IRQ_HANDLED;
+       } else {
+               return IRQ_NONE;
+       }
+}
+
+
+/**
+ * nes_probe - Device initialization
+ */
+static int __devinit nes_probe(struct pci_dev *pcidev, const struct pci_device_id *ent)
+{
+       struct net_device *netdev = NULL;
+       struct nes_device *nesdev = NULL;
+       int ret = 0;
+       struct nes_vnic *nesvnic = NULL;
+       void __iomem *mmio_regs = NULL;
+       u8 hw_rev;
+
+       assert(pcidev != NULL);
+       assert(ent != NULL);
+
+       printk(KERN_INFO PFX "NetEffect RNIC driver v%s loading. (%s)\n",
+                       DRV_VERSION, pci_name(pcidev));
+
+       ret = pci_enable_device(pcidev);
+       if (ret) {
+               printk(KERN_ERR PFX "Unable to enable PCI device. (%s)\n", pci_name(pcidev));
+               goto bail0;
+       }
+
+       nes_debug(NES_DBG_INIT, "BAR0 (@0x%08lX) size = 0x%lX bytes\n",
+                       (long unsigned int)pci_resource_start(pcidev, BAR_0),
+                       (long unsigned int)pci_resource_len(pcidev, BAR_0));
+       nes_debug(NES_DBG_INIT, "BAR1 (@0x%08lX) size = 0x%lX bytes\n",
+                       (long unsigned int)pci_resource_start(pcidev, BAR_1),
+                       (long unsigned int)pci_resource_len(pcidev, BAR_1));
+
+       /* Make sure PCI base addr are MMIO */
+       if (!(pci_resource_flags(pcidev, BAR_0) & IORESOURCE_MEM) ||
+                       !(pci_resource_flags(pcidev, BAR_1) & IORESOURCE_MEM)) {
+               printk(KERN_ERR PFX "PCI regions not an MMIO resource\n");
+               ret = -ENODEV;
+               goto bail1;
+       }
+
+       /* Reserve PCI I/O and memory resources */
+       ret = pci_request_regions(pcidev, DRV_NAME);
+       if (ret) {
+               printk(KERN_ERR PFX "Unable to request regions. (%s)\n", pci_name(pcidev));
+               goto bail1;
+       }
+
+       if ((sizeof(dma_addr_t) > 4)) {
+               ret = pci_set_dma_mask(pcidev, DMA_64BIT_MASK);
+               if (ret < 0) {
+                       printk(KERN_ERR PFX "64b DMA mask configuration failed\n");
+                       goto bail2;
+               }
+               ret = pci_set_consistent_dma_mask(pcidev, DMA_64BIT_MASK);
+               if (ret) {
+                       printk(KERN_ERR PFX "64b DMA consistent mask configuration failed\n");
+                       goto bail2;
+               }
+       } else {
+               ret = pci_set_dma_mask(pcidev, DMA_32BIT_MASK);
+               if (ret < 0) {
+                       printk(KERN_ERR PFX "32b DMA mask configuration failed\n");
+                       goto bail2;
+               }
+               ret = pci_set_consistent_dma_mask(pcidev, DMA_32BIT_MASK);
+               if (ret) {
+                       printk(KERN_ERR PFX "32b DMA consistent mask configuration failed\n");
+                       goto bail2;
+               }
+       }
+
+       pci_set_master(pcidev);
+
+       /* Allocate hardware structure */
+       nesdev = kzalloc(sizeof(struct nes_device), GFP_KERNEL);
+       if (!nesdev) {
+               printk(KERN_ERR PFX "%s: Unable to alloc hardware struct\n", pci_name(pcidev));
+               ret = -ENOMEM;
+               goto bail2;
+       }
+
+       nes_debug(NES_DBG_INIT, "Allocated nes device at %p\n", nesdev);
+       nesdev->pcidev = pcidev;
+       pci_set_drvdata(pcidev, nesdev);
+
+       pci_read_config_byte(pcidev, 0x0008, &hw_rev);
+       nes_debug(NES_DBG_INIT, "hw_rev=%u\n", hw_rev);
+
+       spin_lock_init(&nesdev->indexed_regs_lock);
+
+       /* Remap the PCI registers in adapter BAR0 to kernel VA space */
+       mmio_regs = ioremap_nocache(pci_resource_start(pcidev, BAR_0), sizeof(mmio_regs));
+       if (mmio_regs == NULL) {
+               printk(KERN_ERR PFX "Unable to remap BAR0\n");
+               ret = -EIO;
+               goto bail3;
+       }
+       nesdev->regs = mmio_regs;
+       nesdev->index_reg = 0x50 + (PCI_FUNC(pcidev->devfn)*8) + mmio_regs;
+
+       /* Ensure interrupts are disabled */
+       nes_write32(nesdev->regs+NES_INT_MASK, 0x7fffffff);
+
+       if (nes_drv_opt & NES_DRV_OPT_ENABLE_MSI) {
+               if (!pci_enable_msi(nesdev->pcidev)) {
+                       nesdev->msi_enabled = 1;
+                       nes_debug(NES_DBG_INIT, "MSI is enabled for device %s\n",
+                                       pci_name(pcidev));
+               } else {
+                       nes_debug(NES_DBG_INIT, "MSI is disabled by linux for device %s\n",
+                                       pci_name(pcidev));
+               }
+       } else {
+               nes_debug(NES_DBG_INIT, "MSI not requested due to driver options for device %s\n",
+                               pci_name(pcidev));
+       }
+
+       nesdev->csr_start = pci_resource_start(nesdev->pcidev, BAR_0);
+       nesdev->doorbell_region = pci_resource_start(nesdev->pcidev, BAR_1);
+
+       /* Init the adapter */
+       nesdev->nesadapter = nes_init_adapter(nesdev, hw_rev);
+       nesdev->nesadapter->et_rx_coalesce_usecs_irq = interrupt_mod_interval;
+       if (!nesdev->nesadapter) {
+               printk(KERN_ERR PFX "Unable to initialize adapter.\n");
+               ret = -ENOMEM;
+               goto bail5;
+       }
+
+       /* nesdev->base_doorbell_index =
+                       nesdev->nesadapter->pd_config_base[PCI_FUNC(nesdev->pcidev->devfn)]; */
+       nesdev->base_doorbell_index = 1;
+       nesdev->doorbell_start = nesdev->nesadapter->doorbell_start;
+       nesdev->mac_index = PCI_FUNC(nesdev->pcidev->devfn) % nesdev->nesadapter->port_count;
+
+       tasklet_init(&nesdev->dpc_tasklet, nes_dpc, (unsigned long)nesdev);
+
+       /* bring up the Control QP */
+       if (nes_init_cqp(nesdev)) {
+               ret = -ENODEV;
+               goto bail6;
+       }
+
+       /* Arm the CCQ */
+       nes_write32(nesdev->regs+NES_CQE_ALLOC, NES_CQE_ALLOC_NOTIFY_NEXT |
+                       PCI_FUNC(nesdev->pcidev->devfn));
+       nes_read32(nesdev->regs+NES_CQE_ALLOC);
+
+       /* Enable the interrupts */
+       nesdev->int_req = (0x101 << PCI_FUNC(nesdev->pcidev->devfn)) |
+                       (1 << (PCI_FUNC(nesdev->pcidev->devfn)+16));
+       if (PCI_FUNC(nesdev->pcidev->devfn) < 4) {
+               nesdev->int_req |= (1 << (PCI_FUNC(nesdev->pcidev->devfn)+24));
+       }
+
+       /* TODO: This really should be the first driver to load, not function 0 */
+       if (PCI_FUNC(nesdev->pcidev->devfn) == 0) {
+               /* pick up PCI and critical errors if the first driver to load */
+               nesdev->intf_int_req = NES_INTF_INT_PCIERR | NES_INTF_INT_CRITERR;
+               nesdev->int_req |= NES_INT_INTF;
+       } else {
+               nesdev->intf_int_req = 0;
+       }
+       nesdev->intf_int_req |= (1 << (PCI_FUNC(nesdev->pcidev->devfn)+16));
+       nes_write_indexed(nesdev, NES_IDX_DEBUG_ERROR_MASKS0, 0);
+       nes_write_indexed(nesdev, NES_IDX_DEBUG_ERROR_MASKS1, 0);
+       nes_write_indexed(nesdev, NES_IDX_DEBUG_ERROR_MASKS2, 0x00001265);
+       nes_write_indexed(nesdev, NES_IDX_DEBUG_ERROR_MASKS4, 0x18021804);
+
+       nes_write_indexed(nesdev, NES_IDX_DEBUG_ERROR_MASKS3, 0x17801790);
+
+       /* deal with both periodic and one_shot */
+       nesdev->timer_int_req = 0x101 << PCI_FUNC(nesdev->pcidev->devfn);
+       nesdev->nesadapter->timer_int_req |= nesdev->timer_int_req;
+       nes_debug(NES_DBG_INIT, "setting int_req for function %u, nesdev = 0x%04X, adapter = 0x%04X\n",
+                       PCI_FUNC(nesdev->pcidev->devfn),
+                       nesdev->timer_int_req, nesdev->nesadapter->timer_int_req);
+
+       nes_write32(nesdev->regs+NES_INTF_INT_MASK, ~(nesdev->intf_int_req));
+
+       list_add_tail(&nesdev->list, &nes_dev_list);
+
+       /* Request an interrupt line for the driver */
+       ret = request_irq(pcidev->irq, nes_interrupt, IRQF_SHARED, DRV_NAME, nesdev);
+       if (ret) {
+               printk(KERN_ERR PFX "%s: requested IRQ %u is busy\n",
+                               pci_name(pcidev), pcidev->irq);
+               goto bail65;
+       }
+
+       nes_write32(nesdev->regs+NES_INT_MASK, ~nesdev->int_req);
+
+       if (nes_notifiers_registered == 0) {
+               register_inetaddr_notifier(&nes_inetaddr_notifier);
+               register_netevent_notifier(&nes_net_notifier);
+       }
+       nes_notifiers_registered++;
+
+       /* Initialize network devices */
+               if ((netdev = nes_netdev_init(nesdev, mmio_regs)) == NULL) {
+                       goto bail7;
+               }
+
+               /* Register network device */
+               ret = register_netdev(netdev);
+               if (ret) {
+                       printk(KERN_ERR PFX "Unable to register netdev, ret = %d\n", ret);
+                       nes_netdev_destroy(netdev);
+                       goto bail7;
+               }
+
+               nes_print_macaddr(netdev);
+               /* create a CM core for this netdev */
+               nesvnic = netdev_priv(netdev);
+
+               nesdev->netdev_count++;
+               nesdev->nesadapter->netdev_count++;
+
+
+       printk(KERN_ERR PFX "%s: NetEffect RNIC driver successfully loaded.\n",
+                       pci_name(pcidev));
+       return 0;
+
+       bail7:
+       printk(KERN_ERR PFX "bail7\n");
+       while (nesdev->netdev_count > 0) {
+               nesdev->netdev_count--;
+               nesdev->nesadapter->netdev_count--;
+
+               unregister_netdev(nesdev->netdev[nesdev->netdev_count]);
+               nes_netdev_destroy(nesdev->netdev[nesdev->netdev_count]);
+       }
+
+       nes_debug(NES_DBG_INIT, "netdev_count=%d, nesadapter->netdev_count=%d\n",
+                       nesdev->netdev_count, nesdev->nesadapter->netdev_count);
+
+       nes_notifiers_registered--;
+       if (nes_notifiers_registered == 0) {
+               unregister_netevent_notifier(&nes_net_notifier);
+               unregister_inetaddr_notifier(&nes_inetaddr_notifier);
+       }
+
+       list_del(&nesdev->list);
+       nes_destroy_cqp(nesdev);
+
+       bail65:
+       printk(KERN_ERR PFX "bail65\n");
+       free_irq(pcidev->irq, nesdev);
+       if (nesdev->msi_enabled) {
+               pci_disable_msi(pcidev);
+       }
+       bail6:
+       printk(KERN_ERR PFX "bail6\n");
+       tasklet_kill(&nesdev->dpc_tasklet);
+       /* Deallocate the Adapter Structure */
+       nes_destroy_adapter(nesdev->nesadapter);
+
+       bail5:
+       printk(KERN_ERR PFX "bail5\n");
+       iounmap(nesdev->regs);
+
+       bail3:
+       printk(KERN_ERR PFX "bail3\n");
+       kfree(nesdev);
+
+       bail2:
+       pci_release_regions(pcidev);
+
+       bail1:
+       pci_disable_device(pcidev);
+
+       bail0:
+       return ret;
+}
+
+
+/**
+ * nes_remove - unload from kernel
+ */
+static void __devexit nes_remove(struct pci_dev *pcidev)
+{
+       struct nes_device *nesdev = pci_get_drvdata(pcidev);
+       struct net_device *netdev;
+       int netdev_index = 0;
+
+               if (nesdev->netdev_count) {
+                       netdev = nesdev->netdev[netdev_index];
+                       if (netdev) {
+                               netif_stop_queue(netdev);
+                               unregister_netdev(netdev);
+                               nes_netdev_destroy(netdev);
+
+                               nesdev->netdev[netdev_index] = NULL;
+                               nesdev->netdev_count--;
+                               nesdev->nesadapter->netdev_count--;
+                       }
+               }
+
+       nes_notifiers_registered--;
+       if (nes_notifiers_registered == 0) {
+               unregister_netevent_notifier(&nes_net_notifier);
+               unregister_inetaddr_notifier(&nes_inetaddr_notifier);
+       }
+
+       list_del(&nesdev->list);
+       nes_destroy_cqp(nesdev);
+       tasklet_kill(&nesdev->dpc_tasklet);
+
+       /* Deallocate the Adapter Structure */
+       nes_destroy_adapter(nesdev->nesadapter);
+
+       free_irq(pcidev->irq, nesdev);
+
+       if (nesdev->msi_enabled) {
+               pci_disable_msi(pcidev);
+       }
+
+       iounmap(nesdev->regs);
+       kfree(nesdev);
+
+       /* nes_debug(NES_DBG_SHUTDOWN, "calling pci_release_regions.\n"); */
+       pci_release_regions(pcidev);
+       pci_disable_device(pcidev);
+       pci_set_drvdata(pcidev, NULL);
+}
+
+
+static struct pci_driver nes_pci_driver = {
+       .name = DRV_NAME,
+       .id_table = nes_pci_table,
+       .probe = nes_probe,
+       .remove = __devexit_p(nes_remove),
+};
+
+static ssize_t nes_show_adapter(struct device_driver *ddp, char *buf)
+{
+       unsigned int  devfn = 0xffffffff;
+       unsigned char bus_number = 0xff;
+       unsigned int  i = 0;
+       struct nes_device *nesdev;
+
+       list_for_each_entry(nesdev, &nes_dev_list, list) {
+               if (i == ee_flsh_adapter) {
+                       devfn      = nesdev->nesadapter->devfn;
+                       bus_number = nesdev->nesadapter->bus_number;
+                       break;
+               }
+               i++;
+       }
+
+       return snprintf(buf, PAGE_SIZE, "%x:%x", bus_number, devfn);
+}
+
+static ssize_t nes_store_adapter(struct device_driver *ddp,
+       const char *buf, size_t count)
+{
+       char *p = (char *)buf;
+
+       ee_flsh_adapter = simple_strtoul(p, &p, 10);
+       return strnlen(buf, count);
+}
+
+static ssize_t nes_show_ee_cmd(struct device_driver *ddp, char *buf)
+{
+       u32 eeprom_cmd = 0xdead;
+       u32 i = 0;
+       struct nes_device *nesdev;
+
+       list_for_each_entry(nesdev, &nes_dev_list, list) {
+               if (i == ee_flsh_adapter) {
+                       eeprom_cmd = nes_read32(nesdev->regs + NES_EEPROM_COMMAND);
+                       break;
+               }
+               i++;
+       }
+       return snprintf(buf, PAGE_SIZE, "0x%x\n", eeprom_cmd);
+}
+
+static ssize_t nes_store_ee_cmd(struct device_driver *ddp,
+       const char *buf, size_t count)
+{
+       char *p = (char *)buf;
+       u32 val;
+       u32 i = 0;
+       struct nes_device *nesdev;
+
+       if (p[1] == 'x' || p[1] == 'X' || p[0] == 'x' || p[0] == 'X') {
+               val = simple_strtoul(p, &p, 16);
+               list_for_each_entry(nesdev, &nes_dev_list, list) {
+                       if (i == ee_flsh_adapter) {
+                               nes_write32(nesdev->regs + NES_EEPROM_COMMAND, val);
+                               break;
+                       }
+                       i++;
+               }
+       }
+       return strnlen(buf, count);
+}
+
+static ssize_t nes_show_ee_data(struct device_driver *ddp, char *buf)
+{
+       u32 eeprom_data = 0xdead;
+       u32 i = 0;
+       struct nes_device *nesdev;
+
+       list_for_each_entry(nesdev, &nes_dev_list, list) {
+               if (i == ee_flsh_adapter) {
+                       eeprom_data = nes_read32(nesdev->regs + NES_EEPROM_DATA);
+                       break;
+               }
+               i++;
+       }
+
+       return  snprintf(buf, PAGE_SIZE, "0x%x\n", eeprom_data);
+}
+
+static ssize_t nes_store_ee_data(struct device_driver *ddp,
+       const char *buf, size_t count)
+{
+       char *p = (char *)buf;
+       u32 val;
+       u32 i = 0;
+       struct nes_device *nesdev;
+
+       if (p[1] == 'x' || p[1] == 'X' || p[0] == 'x' || p[0] == 'X') {
+               val = simple_strtoul(p, &p, 16);
+               list_for_each_entry(nesdev, &nes_dev_list, list) {
+                       if (i == ee_flsh_adapter) {
+                               nes_write32(nesdev->regs + NES_EEPROM_DATA, val);
+                               break;
+                       }
+                       i++;
+               }
+       }
+       return strnlen(buf, count);
+}
+
+static ssize_t nes_show_flash_cmd(struct device_driver *ddp, char *buf)
+{
+       u32 flash_cmd = 0xdead;
+       u32 i = 0;
+       struct nes_device *nesdev;
+
+       list_for_each_entry(nesdev, &nes_dev_list, list) {
+               if (i == ee_flsh_adapter) {
+                       flash_cmd = nes_read32(nesdev->regs + NES_FLASH_COMMAND);
+                       break;
+               }
+               i++;
+       }
+
+       return  snprintf(buf, PAGE_SIZE, "0x%x\n", flash_cmd);
+}
+
+static ssize_t nes_store_flash_cmd(struct device_driver *ddp,
+       const char *buf, size_t count)
+{
+       char *p = (char *)buf;
+       u32 val;
+       u32 i = 0;
+       struct nes_device *nesdev;
+
+       if (p[1] == 'x' || p[1] == 'X' || p[0] == 'x' || p[0] == 'X') {
+               val = simple_strtoul(p, &p, 16);
+               list_for_each_entry(nesdev, &nes_dev_list, list) {
+                       if (i == ee_flsh_adapter) {
+                               nes_write32(nesdev->regs + NES_FLASH_COMMAND, val);
+                               break;
+                       }
+                       i++;
+               }
+       }
+       return strnlen(buf, count);
+}
+
+static ssize_t nes_show_flash_data(struct device_driver *ddp, char *buf)
+{
+       u32 flash_data = 0xdead;
+       u32 i = 0;
+       struct nes_device *nesdev;
+
+       list_for_each_entry(nesdev, &nes_dev_list, list) {
+               if (i == ee_flsh_adapter) {
+                       flash_data = nes_read32(nesdev->regs + NES_FLASH_DATA);
+                       break;
+               }
+               i++;
+       }
+
+       return  snprintf(buf, PAGE_SIZE, "0x%x\n", flash_data);
+}
+
+static ssize_t nes_store_flash_data(struct device_driver *ddp,
+       const char *buf, size_t count)
+{
+       char *p = (char *)buf;
+       u32 val;
+       u32 i = 0;
+       struct nes_device *nesdev;
+
+       if (p[1] == 'x' || p[1] == 'X' || p[0] == 'x' || p[0] == 'X') {
+               val = simple_strtoul(p, &p, 16);
+               list_for_each_entry(nesdev, &nes_dev_list, list) {
+                       if (i == ee_flsh_adapter) {
+                               nes_write32(nesdev->regs + NES_FLASH_DATA, val);
+                               break;
+                       }
+                       i++;
+               }
+       }
+       return strnlen(buf, count);
+}
+
+static ssize_t nes_show_nonidx_addr(struct device_driver *ddp, char *buf)
+{
+       return  snprintf(buf, PAGE_SIZE, "0x%x\n", sysfs_nonidx_addr);
+}
+
+static ssize_t nes_store_nonidx_addr(struct device_driver *ddp,
+       const char *buf, size_t count)
+{
+       char *p = (char *)buf;
+
+       if (p[1] == 'x' || p[1] == 'X' || p[0] == 'x' || p[0] == 'X')
+               sysfs_nonidx_addr = simple_strtoul(p, &p, 16);
+
+       return strnlen(buf, count);
+}
+
+static ssize_t nes_show_nonidx_data(struct device_driver *ddp, char *buf)
+{
+       u32 nonidx_data = 0xdead;
+       u32 i = 0;
+       struct nes_device *nesdev;
+
+       list_for_each_entry(nesdev, &nes_dev_list, list) {
+               if (i == ee_flsh_adapter) {
+                       nonidx_data = nes_read32(nesdev->regs + sysfs_nonidx_addr);
+                       break;
+               }
+               i++;
+       }
+
+       return  snprintf(buf, PAGE_SIZE, "0x%x\n", nonidx_data);
+}
+
+static ssize_t nes_store_nonidx_data(struct device_driver *ddp,
+       const char *buf, size_t count)
+{
+       char *p = (char *)buf;
+       u32 val;
+       u32 i = 0;
+       struct nes_device *nesdev;
+
+       if (p[1] == 'x' || p[1] == 'X' || p[0] == 'x' || p[0] == 'X') {
+               val = simple_strtoul(p, &p, 16);
+               list_for_each_entry(nesdev, &nes_dev_list, list) {
+                       if (i == ee_flsh_adapter) {
+                               nes_write32(nesdev->regs + sysfs_nonidx_addr, val);
+                               break;
+                       }
+                       i++;
+               }
+       }
+       return strnlen(buf, count);
+}
+
+static ssize_t nes_show_idx_addr(struct device_driver *ddp, char *buf)
+{
+       return  snprintf(buf, PAGE_SIZE, "0x%x\n", sysfs_idx_addr);
+}
+
+static ssize_t nes_store_idx_addr(struct device_driver *ddp,
+       const char *buf, size_t count)
+{
+       char *p = (char *)buf;
+
+       if (p[1] == 'x' || p[1] == 'X' || p[0] == 'x' || p[0] == 'X')
+               sysfs_idx_addr = simple_strtoul(p, &p, 16);
+
+       return strnlen(buf, count);
+}
+
+static ssize_t nes_show_idx_data(struct device_driver *ddp, char *buf)
+{
+       u32 idx_data = 0xdead;
+       u32 i = 0;
+       struct nes_device *nesdev;
+
+       list_for_each_entry(nesdev, &nes_dev_list, list) {
+               if (i == ee_flsh_adapter) {
+                       idx_data = nes_read_indexed(nesdev, sysfs_idx_addr);
+                       break;
+               }
+               i++;
+       }
+
+       return  snprintf(buf, PAGE_SIZE, "0x%x\n", idx_data);
+}
+
+static ssize_t nes_store_idx_data(struct device_driver *ddp,
+       const char *buf, size_t count)
+{
+       char *p = (char *)buf;
+       u32 val;
+       u32 i = 0;
+       struct nes_device *nesdev;
+
+       if (p[1] == 'x' || p[1] == 'X' || p[0] == 'x' || p[0] == 'X') {
+               val = simple_strtoul(p, &p, 16);
+               list_for_each_entry(nesdev, &nes_dev_list, list) {
+                       if (i == ee_flsh_adapter) {
+                               nes_write_indexed(nesdev, sysfs_idx_addr, val);
+                               break;
+                       }
+                       i++;
+               }
+       }
+       return strnlen(buf, count);
+}
+
+static DRIVER_ATTR(adapter, S_IRUSR | S_IWUSR,
+                  nes_show_adapter, nes_store_adapter);
+static DRIVER_ATTR(eeprom_cmd, S_IRUSR | S_IWUSR,
+                  nes_show_ee_cmd, nes_store_ee_cmd);
+static DRIVER_ATTR(eeprom_data, S_IRUSR | S_IWUSR,
+                  nes_show_ee_data, nes_store_ee_data);
+static DRIVER_ATTR(flash_cmd, S_IRUSR | S_IWUSR,
+                  nes_show_flash_cmd, nes_store_flash_cmd);
+static DRIVER_ATTR(flash_data, S_IRUSR | S_IWUSR,
+                  nes_show_flash_data, nes_store_flash_data);
+static DRIVER_ATTR(nonidx_addr, S_IRUSR | S_IWUSR,
+                  nes_show_nonidx_addr, nes_store_nonidx_addr);
+static DRIVER_ATTR(nonidx_data, S_IRUSR | S_IWUSR,
+                  nes_show_nonidx_data, nes_store_nonidx_data);
+static DRIVER_ATTR(idx_addr, S_IRUSR | S_IWUSR,
+                  nes_show_idx_addr, nes_store_idx_addr);
+static DRIVER_ATTR(idx_data, S_IRUSR | S_IWUSR,
+                  nes_show_idx_data, nes_store_idx_data);
+
+static int nes_create_driver_sysfs(struct pci_driver *drv)
+{
+       int error;
+       error  = driver_create_file(&drv->driver, &driver_attr_adapter);
+       error |= driver_create_file(&drv->driver, &driver_attr_eeprom_cmd);
+       error |= driver_create_file(&drv->driver, &driver_attr_eeprom_data);
+       error |= driver_create_file(&drv->driver, &driver_attr_flash_cmd);
+       error |= driver_create_file(&drv->driver, &driver_attr_flash_data);
+       error |= driver_create_file(&drv->driver, &driver_attr_nonidx_addr);
+       error |= driver_create_file(&drv->driver, &driver_attr_nonidx_data);
+       error |= driver_create_file(&drv->driver, &driver_attr_idx_addr);
+       error |= driver_create_file(&drv->driver, &driver_attr_idx_data);
+       return error;
+}
+
+static void nes_remove_driver_sysfs(struct pci_driver *drv)
+{
+       driver_remove_file(&drv->driver, &driver_attr_adapter);
+       driver_remove_file(&drv->driver, &driver_attr_eeprom_cmd);
+       driver_remove_file(&drv->driver, &driver_attr_eeprom_data);
+       driver_remove_file(&drv->driver, &driver_attr_flash_cmd);
+       driver_remove_file(&drv->driver, &driver_attr_flash_data);
+       driver_remove_file(&drv->driver, &driver_attr_nonidx_addr);
+       driver_remove_file(&drv->driver, &driver_attr_nonidx_data);
+       driver_remove_file(&drv->driver, &driver_attr_idx_addr);
+       driver_remove_file(&drv->driver, &driver_attr_idx_data);
+}
+
+/**
+ * nes_init_module - module initialization entry point
+ */
+static int __init nes_init_module(void)
+{
+       int retval;
+       int retval1;
+
+       retval = nes_cm_start();
+       if (retval) {
+               printk(KERN_ERR PFX "Unable to start NetEffect iWARP CM.\n");
+               return retval;
+       }
+       retval = pci_register_driver(&nes_pci_driver);
+       if (retval >= 0) {
+               retval1 = nes_create_driver_sysfs(&nes_pci_driver);
+               if (retval1 < 0)
+                       printk(KERN_ERR PFX "Unable to create NetEffect sys files.\n");
+       }
+       return retval;
+}
+
+
+/**
+ * nes_exit_module - module unload entry point
+ */
+static void __exit nes_exit_module(void)
+{
+       nes_cm_stop();
+       nes_remove_driver_sysfs(&nes_pci_driver);
+
+       pci_unregister_driver(&nes_pci_driver);
+}
+
+
+module_init(nes_init_module);
+module_exit(nes_exit_module);
diff --git a/drivers/infiniband/hw/nes/nes.h b/drivers/infiniband/hw/nes/nes.h
new file mode 100644 (file)
index 0000000..fd57e8a
--- /dev/null
@@ -0,0 +1,560 @@
+/*
+ * Copyright (c) 2006 - 2008 NetEffect, Inc. All rights reserved.
+ * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * 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.
+ */
+
+#ifndef __NES_H
+#define __NES_H
+
+#include <linux/netdevice.h>
+#include <linux/inetdevice.h>
+#include <linux/spinlock.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <linux/workqueue.h>
+#include <linux/slab.h>
+#include <asm/semaphore.h>
+#include <linux/version.h>
+#include <asm/io.h>
+#include <linux/crc32c.h>
+
+#include <rdma/ib_smi.h>
+#include <rdma/ib_verbs.h>
+#include <rdma/ib_pack.h>
+#include <rdma/rdma_cm.h>
+#include <rdma/iw_cm.h>
+
+#define NES_SEND_FIRST_WRITE
+
+#define QUEUE_DISCONNECTS
+
+#define DRV_BUILD   "1"
+
+#define DRV_NAME    "iw_nes"
+#define DRV_VERSION "1.0 KO Build " DRV_BUILD
+#define PFX         DRV_NAME ": "
+
+/*
+ * NetEffect PCI vendor id and NE010 PCI device id.
+ */
+#ifndef PCI_VENDOR_ID_NETEFFECT        /* not in pci.ids yet */
+#define PCI_VENDOR_ID_NETEFFECT       0x1678
+#define PCI_DEVICE_ID_NETEFFECT_NE020 0x0100
+#endif
+
+#define NE020_REV   4
+#define NE020_REV1  5
+
+#define BAR_0       0
+#define BAR_1       2
+
+#define RX_BUF_SIZE             (1536 + 8)
+#define NES_REG0_SIZE           (4 * 1024)
+#define NES_TX_TIMEOUT          (6*HZ)
+#define NES_FIRST_QPN           64
+#define NES_SW_CONTEXT_ALIGN    1024
+
+#define NES_NIC_MAX_NICS        16
+#define NES_MAX_ARP_TABLE_SIZE  4096
+
+#define NES_NIC_CEQ_SIZE        8
+/* NICs will be on a separate CQ */
+#define NES_CCEQ_SIZE ((nesadapter->max_cq / nesadapter->port_count) - 32)
+
+#define NES_MAX_PORT_COUNT 4
+
+#define MAX_DPC_ITERATIONS               128
+
+#define NES_CQP_REQUEST_NO_DOORBELL_RING 0
+#define NES_CQP_REQUEST_RING_DOORBELL    1
+
+#define NES_DRV_OPT_ENABLE_MPA_VER_0     0x00000001
+#define NES_DRV_OPT_DISABLE_MPA_CRC      0x00000002
+#define NES_DRV_OPT_DISABLE_FIRST_WRITE  0x00000004
+#define NES_DRV_OPT_DISABLE_INTF         0x00000008
+#define NES_DRV_OPT_ENABLE_MSI           0x00000010
+#define NES_DRV_OPT_DUAL_LOGICAL_PORT    0x00000020
+#define NES_DRV_OPT_SUPRESS_OPTION_BC    0x00000040
+#define NES_DRV_OPT_NO_INLINE_DATA       0x00000080
+#define NES_DRV_OPT_DISABLE_INT_MOD      0x00000100
+#define NES_DRV_OPT_DISABLE_VIRT_WQ      0x00000200
+
+#define NES_AEQ_EVENT_TIMEOUT         2500
+#define NES_DISCONNECT_EVENT_TIMEOUT  2000
+
+/* debug levels */
+/* must match userspace */
+#define NES_DBG_HW          0x00000001
+#define NES_DBG_INIT        0x00000002
+#define NES_DBG_ISR         0x00000004
+#define NES_DBG_PHY         0x00000008
+#define NES_DBG_NETDEV      0x00000010
+#define NES_DBG_CM          0x00000020
+#define NES_DBG_CM1         0x00000040
+#define NES_DBG_NIC_RX      0x00000080
+#define NES_DBG_NIC_TX      0x00000100
+#define NES_DBG_CQP         0x00000200
+#define NES_DBG_MMAP        0x00000400
+#define NES_DBG_MR          0x00000800
+#define NES_DBG_PD          0x00001000
+#define NES_DBG_CQ          0x00002000
+#define NES_DBG_QP          0x00004000
+#define NES_DBG_MOD_QP      0x00008000
+#define NES_DBG_AEQ         0x00010000
+#define NES_DBG_IW_RX       0x00020000
+#define NES_DBG_IW_TX       0x00040000
+#define NES_DBG_SHUTDOWN    0x00080000
+#define NES_DBG_RSVD1       0x10000000
+#define NES_DBG_RSVD2       0x20000000
+#define NES_DBG_RSVD3       0x40000000
+#define NES_DBG_RSVD4       0x80000000
+#define NES_DBG_ALL         0xffffffff
+
+#ifdef CONFIG_INFINIBAND_NES_DEBUG
+#define nes_debug(level, fmt, args...) \
+       if (level & nes_debug_level) \
+               printk(KERN_ERR PFX "%s[%u]: " fmt, __FUNCTION__, __LINE__, ##args)
+
+#define assert(expr)                                                \
+if (!(expr)) {                                                       \
+       printk(KERN_ERR PFX "Assertion failed! %s, %s, %s, line %d\n",  \
+                  #expr, __FILE__, __FUNCTION__, __LINE__);                \
+}
+
+#define NES_EVENT_TIMEOUT   1200000
+#else
+#define nes_debug(level, fmt, args...)
+#define assert(expr)          do {} while (0)
+
+#define NES_EVENT_TIMEOUT   100000
+#endif
+
+#include "nes_hw.h"
+#include "nes_verbs.h"
+#include "nes_context.h"
+#include "nes_user.h"
+#include "nes_cm.h"
+
+extern int max_mtu;
+extern int nics_per_function;
+#define max_frame_len (max_mtu+ETH_HLEN)
+extern int interrupt_mod_interval;
+extern int nes_if_count;
+extern int mpa_version;
+extern int disable_mpa_crc;
+extern unsigned int send_first;
+extern unsigned int nes_drv_opt;
+extern unsigned int nes_debug_level;
+
+extern struct list_head nes_adapter_list;
+extern struct list_head nes_dev_list;
+
+extern struct nes_cm_core *g_cm_core;
+
+extern atomic_t cm_connects;
+extern atomic_t cm_accepts;
+extern atomic_t cm_disconnects;
+extern atomic_t cm_closes;
+extern atomic_t cm_connecteds;
+extern atomic_t cm_connect_reqs;
+extern atomic_t cm_rejects;
+extern atomic_t mod_qp_timouts;
+extern atomic_t qps_created;
+extern atomic_t qps_destroyed;
+extern atomic_t sw_qps_destroyed;
+extern u32 mh_detected;
+extern u32 mh_pauses_sent;
+extern u32 cm_packets_sent;
+extern u32 cm_packets_bounced;
+extern u32 cm_packets_created;
+extern u32 cm_packets_received;
+extern u32 cm_packets_dropped;
+extern u32 cm_packets_retrans;
+extern u32 cm_listens_created;
+extern u32 cm_listens_destroyed;
+extern u32 cm_backlog_drops;
+extern atomic_t cm_loopbacks;
+extern atomic_t cm_nodes_created;
+extern atomic_t cm_nodes_destroyed;
+extern atomic_t cm_accel_dropped_pkts;
+extern atomic_t cm_resets_recvd;
+
+extern u32 crit_err_count;
+extern u32 int_mod_timer_init;
+extern u32 int_mod_cq_depth_256;
+extern u32 int_mod_cq_depth_128;
+extern u32 int_mod_cq_depth_32;
+extern u32 int_mod_cq_depth_24;
+extern u32 int_mod_cq_depth_16;
+extern u32 int_mod_cq_depth_4;
+extern u32 int_mod_cq_depth_1;
+
+extern atomic_t cqp_reqs_allocated;
+extern atomic_t cqp_reqs_freed;
+extern atomic_t cqp_reqs_dynallocated;
+extern atomic_t cqp_reqs_dynfreed;
+extern atomic_t cqp_reqs_queued;
+extern atomic_t cqp_reqs_redriven;
+
+
+struct nes_device {
+       struct nes_adapter         *nesadapter;
+       void __iomem           *regs;
+       void __iomem           *index_reg;
+       struct pci_dev         *pcidev;
+       struct net_device      *netdev[NES_NIC_MAX_NICS];
+       u64                    link_status_interrupts;
+       struct tasklet_struct  dpc_tasklet;
+       spinlock_t             indexed_regs_lock;
+       unsigned long          csr_start;
+       unsigned long          doorbell_region;
+       unsigned long          doorbell_start;
+       unsigned long          mac_tx_errors;
+       unsigned long          mac_pause_frames_sent;
+       unsigned long          mac_pause_frames_received;
+       unsigned long          mac_rx_errors;
+       unsigned long          mac_rx_crc_errors;
+       unsigned long          mac_rx_symbol_err_frames;
+       unsigned long          mac_rx_jabber_frames;
+       unsigned long          mac_rx_oversized_frames;
+       unsigned long          mac_rx_short_frames;
+       unsigned long          port_rx_discards;
+       unsigned long          port_tx_discards;
+       unsigned int           mac_index;
+       unsigned int           nes_stack_start;
+
+       /* Control Structures */
+       void                   *cqp_vbase;
+       dma_addr_t             cqp_pbase;
+       u32                    cqp_mem_size;
+       u8                     ceq_index;
+       u8                     nic_ceq_index;
+       struct nes_hw_cqp      cqp;
+       struct nes_hw_cq       ccq;
+       struct list_head       cqp_avail_reqs;
+       struct list_head       cqp_pending_reqs;
+       struct nes_cqp_request *nes_cqp_requests;
+
+       u32                    int_req;
+       u32                    int_stat;
+       u32                    timer_int_req;
+       u32                    timer_only_int_count;
+       u32                    intf_int_req;
+       u32                    last_mac_tx_pauses;
+       u32                    last_used_chunks_tx;
+       struct list_head       list;
+
+       u16                    base_doorbell_index;
+       u16                    currcq_count;
+       u16                    deepcq_count;
+       u8                     msi_enabled;
+       u8                     netdev_count;
+       u8                     napi_isr_ran;
+       u8                     disable_rx_flow_control;
+       u8                     disable_tx_flow_control;
+};
+
+
+static inline void
+set_wqe_64bit_value(__le32 *wqe_words, u32 index, u64 value)
+{
+       wqe_words[index]     = cpu_to_le32((u32) ((unsigned long)value));
+       wqe_words[index + 1] = cpu_to_le32((u32)(upper_32_bits((unsigned long)value)));
+}
+
+static inline void
+set_wqe_32bit_value(__le32 *wqe_words, u32 index, u32 value)
+{
+       wqe_words[index] = cpu_to_le32(value);
+}
+
+static inline void
+nes_fill_init_cqp_wqe(struct nes_hw_cqp_wqe *cqp_wqe, struct nes_device *nesdev)
+{
+       set_wqe_64bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_COMP_CTX_LOW_IDX,
+                       (u64)((unsigned long) &nesdev->cqp));
+       cqp_wqe->wqe_words[NES_CQP_WQE_COMP_SCRATCH_LOW_IDX]   = 0;
+       cqp_wqe->wqe_words[NES_CQP_WQE_COMP_SCRATCH_HIGH_IDX]  = 0;
+       cqp_wqe->wqe_words[NES_CQP_STAG_WQE_PBL_BLK_COUNT_IDX] = 0;
+       cqp_wqe->wqe_words[NES_CQP_STAG_WQE_PBL_LEN_IDX]       = 0;
+       cqp_wqe->wqe_words[NES_CQP_STAG_WQE_LEN_LOW_IDX]       = 0;
+       cqp_wqe->wqe_words[NES_CQP_STAG_WQE_PA_LOW_IDX]        = 0;
+       cqp_wqe->wqe_words[NES_CQP_STAG_WQE_PA_HIGH_IDX]       = 0;
+}
+
+static inline void
+nes_fill_init_qp_wqe(struct nes_hw_qp_wqe *wqe, struct nes_qp *nesqp, u32 head)
+{
+       u32 value;
+       value = ((u32)((unsigned long) nesqp)) | head;
+       set_wqe_32bit_value(wqe->wqe_words, NES_IWARP_SQ_WQE_COMP_CTX_HIGH_IDX,
+                       (u32)(upper_32_bits((unsigned long)(nesqp))));
+       set_wqe_32bit_value(wqe->wqe_words, NES_IWARP_SQ_WQE_COMP_CTX_LOW_IDX, value);
+}
+
+/* Read from memory-mapped device */
+static inline u32 nes_read_indexed(struct nes_device *nesdev, u32 reg_index)
+{
+       unsigned long flags;
+       void __iomem *addr = nesdev->index_reg;
+       u32 value;
+
+       spin_lock_irqsave(&nesdev->indexed_regs_lock, flags);
+
+       writel(reg_index, addr);
+       value = readl((void __iomem *)addr + 4);
+
+       spin_unlock_irqrestore(&nesdev->indexed_regs_lock, flags);
+       return value;
+}
+
+static inline u32 nes_read32(const void __iomem *addr)
+{
+       return readl(addr);
+}
+
+static inline u16 nes_read16(const void __iomem *addr)
+{
+       return readw(addr);
+}
+
+static inline u8 nes_read8(const void __iomem *addr)
+{
+       return readb(addr);
+}
+
+/* Write to memory-mapped device */
+static inline void nes_write_indexed(struct nes_device *nesdev, u32 reg_index, u32 val)
+{
+       unsigned long flags;
+       void __iomem *addr = nesdev->index_reg;
+
+       spin_lock_irqsave(&nesdev->indexed_regs_lock, flags);
+
+       writel(reg_index, addr);
+       writel(val, (void __iomem *)addr + 4);
+
+       spin_unlock_irqrestore(&nesdev->indexed_regs_lock, flags);
+}
+
+static inline void nes_write32(void __iomem *addr, u32 val)
+{
+       writel(val, addr);
+}
+
+static inline void nes_write16(void __iomem *addr, u16 val)
+{
+       writew(val, addr);
+}
+
+static inline void nes_write8(void __iomem *addr, u8 val)
+{
+       writeb(val, addr);
+}
+
+
+
+static inline int nes_alloc_resource(struct nes_adapter *nesadapter,
+               unsigned long *resource_array, u32 max_resources,
+               u32 *req_resource_num, u32 *next)
+{
+       unsigned long flags;
+       u32 resource_num;
+
+       spin_lock_irqsave(&nesadapter->resource_lock, flags);
+
+       resource_num = find_next_zero_bit(resource_array, max_resources, *next);
+       if (resource_num >= max_resources) {
+               resource_num = find_first_zero_bit(resource_array, max_resources);
+               if (resource_num >= max_resources) {
+                       printk(KERN_ERR PFX "%s: No available resourcess.\n", __FUNCTION__);
+                       spin_unlock_irqrestore(&nesadapter->resource_lock, flags);
+                       return -EMFILE;
+               }
+       }
+       set_bit(resource_num, resource_array);
+       *next = resource_num+1;
+       if (*next == max_resources) {
+               *next = 0;
+       }
+       spin_unlock_irqrestore(&nesadapter->resource_lock, flags);
+       *req_resource_num = resource_num;
+
+       return 0;
+}
+
+static inline int nes_is_resource_allocated(struct nes_adapter *nesadapter,
+               unsigned long *resource_array, u32 resource_num)
+{
+       unsigned long flags;
+       int bit_is_set;
+
+       spin_lock_irqsave(&nesadapter->resource_lock, flags);
+
+       bit_is_set = test_bit(resource_num, resource_array);
+       nes_debug(NES_DBG_HW, "resource_num %u is%s allocated.\n",
+                       resource_num, (bit_is_set ? "": " not"));
+       spin_unlock_irqrestore(&nesadapter->resource_lock, flags);
+
+       return bit_is_set;
+}
+
+static inline void nes_free_resource(struct nes_adapter *nesadapter,
+               unsigned long *resource_array, u32 resource_num)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&nesadapter->resource_lock, flags);
+       clear_bit(resource_num, resource_array);
+       spin_unlock_irqrestore(&nesadapter->resource_lock, flags);
+}
+
+static inline struct nes_vnic *to_nesvnic(struct ib_device *ibdev)
+{
+       return container_of(ibdev, struct nes_ib_device, ibdev)->nesvnic;
+}
+
+static inline struct nes_pd *to_nespd(struct ib_pd *ibpd)
+{
+       return container_of(ibpd, struct nes_pd, ibpd);
+}
+
+static inline struct nes_ucontext *to_nesucontext(struct ib_ucontext *ibucontext)
+{
+       return container_of(ibucontext, struct nes_ucontext, ibucontext);
+}
+
+static inline struct nes_mr *to_nesmr(struct ib_mr *ibmr)
+{
+       return container_of(ibmr, struct nes_mr, ibmr);
+}
+
+static inline struct nes_mr *to_nesmr_from_ibfmr(struct ib_fmr *ibfmr)
+{
+       return container_of(ibfmr, struct nes_mr, ibfmr);
+}
+
+static inline struct nes_mr *to_nesmw(struct ib_mw *ibmw)
+{
+       return container_of(ibmw, struct nes_mr, ibmw);
+}
+
+static inline struct nes_fmr *to_nesfmr(struct nes_mr *nesmr)
+{
+       return container_of(nesmr, struct nes_fmr, nesmr);
+}
+
+static inline struct nes_cq *to_nescq(struct ib_cq *ibcq)
+{
+       return container_of(ibcq, struct nes_cq, ibcq);
+}
+
+static inline struct nes_qp *to_nesqp(struct ib_qp *ibqp)
+{
+       return container_of(ibqp, struct nes_qp, ibqp);
+}
+
+
+
+/* nes.c */
+void nes_add_ref(struct ib_qp *);
+void nes_rem_ref(struct ib_qp *);
+struct ib_qp *nes_get_qp(struct ib_device *, int);
+
+
+/* nes_hw.c */
+struct nes_adapter *nes_init_adapter(struct nes_device *, u8);
+void  nes_nic_init_timer_defaults(struct nes_device *, u8);
+unsigned int nes_reset_adapter_ne020(struct nes_device *, u8 *);
+int nes_init_serdes(struct nes_device *, u8, u8, u8);
+void nes_init_csr_ne020(struct nes_device *, u8, u8);
+void nes_destroy_adapter(struct nes_adapter *);
+int nes_init_cqp(struct nes_device *);
+int nes_init_phy(struct nes_device *);
+int nes_init_nic_qp(struct nes_device *, struct net_device *);
+void nes_destroy_nic_qp(struct nes_vnic *);
+int nes_napi_isr(struct nes_device *);
+void nes_dpc(unsigned long);
+void nes_process_ceq(struct nes_device *, struct nes_hw_ceq *);
+void nes_process_aeq(struct nes_device *, struct nes_hw_aeq *);
+void nes_process_mac_intr(struct nes_device *, u32);
+void nes_nic_napi_ce_handler(struct nes_device *, struct nes_hw_nic_cq *);
+void nes_nic_ce_handler(struct nes_device *, struct nes_hw_nic_cq *);
+void nes_cqp_ce_handler(struct nes_device *, struct nes_hw_cq *);
+void nes_process_iwarp_aeqe(struct nes_device *, struct nes_hw_aeqe *);
+void nes_iwarp_ce_handler(struct nes_device *, struct nes_hw_cq *);
+int nes_destroy_cqp(struct nes_device *);
+int nes_nic_cm_xmit(struct sk_buff *, struct net_device *);
+
+/* nes_nic.c */
+void nes_netdev_set_multicast_list(struct net_device *);
+void nes_netdev_exit(struct nes_vnic *);
+struct net_device *nes_netdev_init(struct nes_device *, void __iomem *);
+void nes_netdev_destroy(struct net_device *);
+int nes_nic_cm_xmit(struct sk_buff *, struct net_device *);
+
+/* nes_cm.c */
+void *nes_cm_create(struct net_device *);
+int nes_cm_recv(struct sk_buff *, struct net_device *);
+void nes_update_arp(unsigned char *, u32, u32, u16, u16);
+void nes_manage_arp_cache(struct net_device *, unsigned char *, u32, u32);
+void nes_sock_release(struct nes_qp *, unsigned long *);
+struct nes_cm_core *nes_cm_alloc_core(void);
+void flush_wqes(struct nes_device *nesdev, struct nes_qp *, u32, u32);
+int nes_manage_apbvt(struct nes_vnic *, u32, u32, u32);
+int nes_cm_disconn(struct nes_qp *);
+void nes_cm_disconn_worker(void *);
+
+/* nes_verbs.c */
+int nes_hw_modify_qp(struct nes_device *, struct nes_qp *, u32, u32);
+int nes_modify_qp(struct ib_qp *, struct ib_qp_attr *, int, struct ib_udata *);
+struct nes_ib_device *nes_init_ofa_device(struct net_device *);
+void nes_destroy_ofa_device(struct nes_ib_device *);
+int nes_register_ofa_device(struct nes_ib_device *);
+void nes_unregister_ofa_device(struct nes_ib_device *);
+
+/* nes_util.c */
+int nes_read_eeprom_values(struct nes_device *, struct nes_adapter *);
+void nes_write_1G_phy_reg(struct nes_device *, u8, u8, u16);
+void nes_read_1G_phy_reg(struct nes_device *, u8, u8, u16 *);
+void nes_write_10G_phy_reg(struct nes_device *, u16, u8, u16);
+void nes_read_10G_phy_reg(struct nes_device *, u16, u8);
+struct nes_cqp_request *nes_get_cqp_request(struct nes_device *);
+void nes_post_cqp_request(struct nes_device *, struct nes_cqp_request *, int);
+int nes_arp_table(struct nes_device *, u32, u8 *, u32);
+void nes_mh_fix(unsigned long);
+void nes_clc(unsigned long);
+void nes_dump_mem(unsigned int, void *, int);
+u32 nes_crc32(u32, u32, u32, u32, u8 *, u32, u32, u32);
+
+#endif /* __NES_H */
diff --git a/drivers/infiniband/hw/nes/nes_cm.c b/drivers/infiniband/hw/nes/nes_cm.c
new file mode 100644 (file)
index 0000000..bd5cfea
--- /dev/null
@@ -0,0 +1,3088 @@
+/*
+ * Copyright (c) 2006 - 2008 NetEffect, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * 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.
+ *
+ */
+
+
+#define TCPOPT_TIMESTAMP 8
+
+#include <asm/atomic.h>
+#include <linux/skbuff.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/init.h>
+#include <linux/if_arp.h>
+#include <linux/notifier.h>
+#include <linux/net.h>
+#include <linux/types.h>
+#include <linux/timer.h>
+#include <linux/time.h>
+#include <linux/delay.h>
+#include <linux/etherdevice.h>
+#include <linux/netdevice.h>
+#include <linux/random.h>
+#include <linux/list.h>
+#include <linux/threads.h>
+
+#include <net/neighbour.h>
+#include <net/route.h>
+#include <net/ip_fib.h>
+
+#include "nes.h"
+
+u32 cm_packets_sent;
+u32 cm_packets_bounced;
+u32 cm_packets_dropped;
+u32 cm_packets_retrans;
+u32 cm_packets_created;
+u32 cm_packets_received;
+u32 cm_listens_created;
+u32 cm_listens_destroyed;
+u32 cm_backlog_drops;
+atomic_t cm_loopbacks;
+atomic_t cm_nodes_created;
+atomic_t cm_nodes_destroyed;
+atomic_t cm_accel_dropped_pkts;
+atomic_t cm_resets_recvd;
+
+static inline int mini_cm_accelerated(struct nes_cm_core *, struct nes_cm_node *);
+static struct nes_cm_listener *mini_cm_listen(struct nes_cm_core *,
+               struct nes_vnic *, struct nes_cm_info *);
+static int add_ref_cm_node(struct nes_cm_node *);
+static int rem_ref_cm_node(struct nes_cm_core *, struct nes_cm_node *);
+static int mini_cm_del_listen(struct nes_cm_core *, struct nes_cm_listener *);
+
+
+/* External CM API Interface */
+/* instance of function pointers for client API */
+/* set address of this instance to cm_core->cm_ops at cm_core alloc */
+static struct nes_cm_ops nes_cm_api = {
+       mini_cm_accelerated,
+       mini_cm_listen,
+       mini_cm_del_listen,
+       mini_cm_connect,
+       mini_cm_close,
+       mini_cm_accept,
+       mini_cm_reject,
+       mini_cm_recv_pkt,
+       mini_cm_dealloc_core,
+       mini_cm_get,
+       mini_cm_set
+};
+
+struct nes_cm_core *g_cm_core;
+
+atomic_t cm_connects;
+atomic_t cm_accepts;
+atomic_t cm_disconnects;
+atomic_t cm_closes;
+atomic_t cm_connecteds;
+atomic_t cm_connect_reqs;
+atomic_t cm_rejects;
+
+
+/**
+ * create_event
+ */
+static struct nes_cm_event *create_event(struct nes_cm_node *cm_node,
+               enum nes_cm_event_type type)
+{
+       struct nes_cm_event *event;
+
+       if (!cm_node->cm_id)
+               return NULL;
+
+       /* allocate an empty event */
+       event = kzalloc(sizeof(*event), GFP_ATOMIC);
+
+       if (!event)
+               return NULL;
+
+       event->type = type;
+       event->cm_node = cm_node;
+       event->cm_info.rem_addr = cm_node->rem_addr;
+       event->cm_info.loc_addr = cm_node->loc_addr;
+       event->cm_info.rem_port = cm_node->rem_port;
+       event->cm_info.loc_port = cm_node->loc_port;
+       event->cm_info.cm_id = cm_node->cm_id;
+
+       nes_debug(NES_DBG_CM, "Created event=%p, type=%u, dst_addr=%08x[%x],"
+                       " src_addr=%08x[%x]\n",
+                       event, type,
+                       event->cm_info.loc_addr, event->cm_info.loc_port,
+                       event->cm_info.rem_addr, event->cm_info.rem_port);
+
+       nes_cm_post_event(event);
+       return event;
+}
+
+
+/**
+ * send_mpa_request
+ */
+int send_mpa_request(struct nes_cm_node *cm_node)
+{
+       struct sk_buff *skb;
+       int ret;
+
+       skb = get_free_pkt(cm_node);
+       if (!skb) {
+               nes_debug(NES_DBG_CM, "Failed to get a Free pkt\n");
+               return -1;
+       }
+
+       /* send an MPA Request frame */
+       form_cm_frame(skb, cm_node, NULL, 0, &cm_node->mpa_frame,
+                       cm_node->mpa_frame_size, SET_ACK);
+
+       ret = schedule_nes_timer(cm_node, skb, NES_TIMER_TYPE_SEND, 1, 0);
+       if (ret < 0) {
+               return ret;
+       }
+
+       return 0;
+}
+
+
+/**
+ * recv_mpa - process a received TCP pkt, we are expecting an
+ * IETF MPA frame
+ */
+static int parse_mpa(struct nes_cm_node *cm_node, u8 *buffer, u32 len)
+{
+       struct ietf_mpa_frame *mpa_frame;
+
+       /* assume req frame is in tcp data payload */
+       if (len < sizeof(struct ietf_mpa_frame)) {
+               nes_debug(NES_DBG_CM, "The received ietf buffer was too small (%x)\n", len);
+               return -1;
+       }
+
+       mpa_frame = (struct ietf_mpa_frame *)buffer;
+       cm_node->mpa_frame_size = ntohs(mpa_frame->priv_data_len);
+
+       if (cm_node->mpa_frame_size + sizeof(struct ietf_mpa_frame) != len) {
+               nes_debug(NES_DBG_CM, "The received ietf buffer was not right"
+                               " complete (%x + %x != %x)\n",
+                               cm_node->mpa_frame_size, (u32)sizeof(struct ietf_mpa_frame), len);
+               return -1;
+       }
+
+       /* copy entire MPA frame to our cm_node's frame */
+       memcpy(cm_node->mpa_frame_buf, buffer + sizeof(struct ietf_mpa_frame),
+                       cm_node->mpa_frame_size);
+
+       return 0;
+}
+
+
+/**
+ * handle_exception_pkt - process an exception packet.
+ * We have been in a TSA state, and we have now received SW
+ * TCP/IP traffic should be a FIN request or IP pkt with options
+ */
+static int handle_exception_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb)
+{
+       int ret = 0;
+       struct tcphdr *tcph = tcp_hdr(skb);
+
+       /* first check to see if this a FIN pkt */
+       if (tcph->fin) {
+               /* we need to ACK the FIN request */
+               send_ack(cm_node);
+
+               /* check which side we are (client/server) and set next state accordingly */
+               if (cm_node->tcp_cntxt.client)
+                       cm_node->state = NES_CM_STATE_CLOSING;
+               else {
+                       /* we are the server side */
+                       cm_node->state = NES_CM_STATE_CLOSE_WAIT;
+                       /* since this is a self contained CM we don't wait for */
+                       /* an APP to close us, just send final FIN immediately */
+                       ret = send_fin(cm_node, NULL);
+                       cm_node->state = NES_CM_STATE_LAST_ACK;
+               }
+       } else {
+               ret = -EINVAL;
+       }
+
+       return ret;
+}
+
+
+/**
+ * form_cm_frame - get a free packet and build empty frame Use
+ * node info to build.
+ */
+struct sk_buff *form_cm_frame(struct sk_buff *skb, struct nes_cm_node *cm_node,
+               void *options, u32 optionsize, void *data, u32 datasize, u8 flags)
+{
+       struct tcphdr *tcph;
+       struct iphdr *iph;
+       struct ethhdr *ethh;
+       u8 *buf;
+       u16 packetsize = sizeof(*iph);
+
+       packetsize += sizeof(*tcph);
+       packetsize +=  optionsize + datasize;
+
+       memset(skb->data, 0x00, ETH_HLEN + sizeof(*iph) + sizeof(*tcph));
+
+       skb->len = 0;
+       buf = skb_put(skb, packetsize + ETH_HLEN);
+
+       ethh = (struct ethhdr *) buf;
+       buf += ETH_HLEN;
+
+       iph = (struct iphdr *)buf;
+       buf += sizeof(*iph);
+       tcph = (struct tcphdr *)buf;
+       skb_reset_mac_header(skb);
+       skb_set_network_header(skb, ETH_HLEN);
+       skb_set_transport_header(skb, ETH_HLEN+sizeof(*iph));
+       buf += sizeof(*tcph);
+
+       skb->ip_summed = CHECKSUM_PARTIAL;
+       skb->protocol = htons(0x800);
+       skb->data_len = 0;
+       skb->mac_len = ETH_HLEN;
+
+       memcpy(ethh->h_dest, cm_node->rem_mac, ETH_ALEN);
+       memcpy(ethh->h_source, cm_node->loc_mac, ETH_ALEN);
+       ethh->h_proto = htons(0x0800);
+
+       iph->version = IPVERSION;
+       iph->ihl = 5;           /* 5 * 4Byte words, IP headr len */
+       iph->tos = 0;
+       iph->tot_len = htons(packetsize);
+       iph->id = htons(++cm_node->tcp_cntxt.loc_id);
+
+       iph->frag_off = htons(0x4000);
+       iph->ttl = 0x40;
+       iph->protocol = 0x06;   /* IPPROTO_TCP */
+
+       iph->saddr = htonl(cm_node->loc_addr);
+       iph->daddr = htonl(cm_node->rem_addr);
+
+       tcph->source = htons(cm_node->loc_port);
+       tcph->dest = htons(cm_node->rem_port);
+       tcph->seq = htonl(cm_node->tcp_cntxt.loc_seq_num);
+
+       if (flags & SET_ACK) {
+               cm_node->tcp_cntxt.loc_ack_num = cm_node->tcp_cntxt.rcv_nxt;
+               tcph->ack_seq = htonl(cm_node->tcp_cntxt.loc_ack_num);
+               tcph->ack = 1;
+       } else
+               tcph->ack_seq = 0;
+
+       if (flags & SET_SYN) {
+               cm_node->tcp_cntxt.loc_seq_num++;
+               tcph->syn = 1;
+       } else
+               cm_node->tcp_cntxt.loc_seq_num += datasize;     /* data (no headers) */
+
+       if (flags & SET_FIN)
+               tcph->fin = 1;
+
+       if (flags & SET_RST)
+               tcph->rst = 1;
+
+       tcph->doff = (u16)((sizeof(*tcph) + optionsize + 3) >> 2);
+       tcph->window = htons(cm_node->tcp_cntxt.rcv_wnd);
+       tcph->urg_ptr = 0;
+       if (optionsize)
+               memcpy(buf, options, optionsize);
+       buf += optionsize;
+       if (datasize)
+               memcpy(buf, data, datasize);
+
+       skb_shinfo(skb)->nr_frags = 0;
+       cm_packets_created++;
+
+       return skb;
+}
+
+
+/**
+ * print_core - dump a cm core
+ */
+static void print_core(struct nes_cm_core *core)
+{
+       nes_debug(NES_DBG_CM, "---------------------------------------------\n");
+       nes_debug(NES_DBG_CM, "CM Core  -- (core = %p )\n", core);
+       if (!core)
+               return;
+       nes_debug(NES_DBG_CM, "---------------------------------------------\n");
+       nes_debug(NES_DBG_CM, "Session ID    : %u \n", atomic_read(&core->session_id));
+
+       nes_debug(NES_DBG_CM, "State         : %u \n",  core->state);
+
+       nes_debug(NES_DBG_CM, "Tx Free cnt   : %u \n", skb_queue_len(&core->tx_free_list));
+       nes_debug(NES_DBG_CM, "Listen Nodes  : %u \n", atomic_read(&core->listen_node_cnt));
+       nes_debug(NES_DBG_CM, "Active Nodes  : %u \n", atomic_read(&core->node_cnt));
+
+       nes_debug(NES_DBG_CM, "core          : %p \n", core);
+
+       nes_debug(NES_DBG_CM, "-------------- end core ---------------\n");
+}
+
+
+/**
+ * schedule_nes_timer
+ * note - cm_node needs to be protected before calling this. Encase in:
+ *                     rem_ref_cm_node(cm_core, cm_node);add_ref_cm_node(cm_node);
+ */
+int schedule_nes_timer(struct nes_cm_node *cm_node, struct sk_buff *skb,
+               enum nes_timer_type type, int send_retrans,
+               int close_when_complete)
+{
+       unsigned long  flags;
+       struct nes_cm_core *cm_core;
+       struct nes_timer_entry *new_send;
+       int ret = 0;
+       u32 was_timer_set;
+
+       new_send = kzalloc(sizeof(*new_send), GFP_ATOMIC);
+       if (!new_send)
+               return -1;
+       if (!cm_node)
+               return -EINVAL;
+
+       /* new_send->timetosend = currenttime */
+       new_send->retrycount = NES_DEFAULT_RETRYS;
+       new_send->retranscount = NES_DEFAULT_RETRANS;
+       new_send->skb = skb;
+       new_send->timetosend = jiffies;
+       new_send->type = type;
+       new_send->netdev = cm_node->netdev;
+       new_send->send_retrans = send_retrans;
+       new_send->close_when_complete = close_when_complete;
+
+       if (type == NES_TIMER_TYPE_CLOSE) {
+               new_send->timetosend += (HZ/2); /* TODO: decide on the correct value here */
+               spin_lock_irqsave(&cm_node->recv_list_lock, flags);
+               list_add_tail(&new_send->list, &cm_node->recv_list);
+               spin_unlock_irqrestore(&cm_node->recv_list_lock, flags);
+       }
+
+       if (type == NES_TIMER_TYPE_SEND) {
+               new_send->seq_num = htonl(tcp_hdr(skb)->seq);
+               atomic_inc(&new_send->skb->users);
+
+               ret = nes_nic_cm_xmit(new_send->skb, cm_node->netdev);
+               if (ret != NETDEV_TX_OK) {
+                       nes_debug(NES_DBG_CM, "Error sending packet %p (jiffies = %lu)\n",
+                                       new_send, jiffies);
+                       atomic_dec(&new_send->skb->users);
+                       new_send->timetosend = jiffies;
+               } else {
+                       cm_packets_sent++;
+                       if (!send_retrans) {
+                               if (close_when_complete)
+                                       rem_ref_cm_node(cm_node->cm_core, cm_node);
+                               dev_kfree_skb_any(new_send->skb);
+                               kfree(new_send);
+                               return ret;
+                       }
+                       new_send->timetosend = jiffies + NES_RETRY_TIMEOUT;
+               }
+               spin_lock_irqsave(&cm_node->retrans_list_lock, flags);
+               list_add_tail(&new_send->list, &cm_node->retrans_list);
+               spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags);
+       }
+       if (type == NES_TIMER_TYPE_RECV) {
+               new_send->seq_num = htonl(tcp_hdr(skb)->seq);
+               new_send->timetosend = jiffies;
+               spin_lock_irqsave(&cm_node->recv_list_lock, flags);
+               list_add_tail(&new_send->list, &cm_node->recv_list);
+               spin_unlock_irqrestore(&cm_node->recv_list_lock, flags);
+       }
+       cm_core = cm_node->cm_core;
+
+       was_timer_set = timer_pending(&cm_core->tcp_timer);
+
+       if (!was_timer_set) {
+               cm_core->tcp_timer.expires = new_send->timetosend;
+               add_timer(&cm_core->tcp_timer);
+       }
+
+       return ret;
+}
+
+
+/**
+ * nes_cm_timer_tick
+ */
+void nes_cm_timer_tick(unsigned long pass)
+{
+       unsigned long flags, qplockflags;
+       unsigned long nexttimeout = jiffies + NES_LONG_TIME;
+       struct iw_cm_id *cm_id;
+       struct nes_cm_node *cm_node;
+       struct nes_timer_entry *send_entry, *recv_entry;
+       struct list_head *list_core, *list_core_temp;
+       struct list_head *list_node, *list_node_temp;
+       struct nes_cm_core *cm_core = g_cm_core;
+       struct nes_qp *nesqp;
+       struct sk_buff *skb;
+       u32 settimer = 0;
+       int ret = NETDEV_TX_OK;
+       int    node_done;
+
+       spin_lock_irqsave(&cm_core->ht_lock, flags);
+
+       list_for_each_safe(list_node, list_core_temp, &cm_core->connected_nodes) {
+               cm_node = container_of(list_node, struct nes_cm_node, list);
+               add_ref_cm_node(cm_node);
+               spin_unlock_irqrestore(&cm_core->ht_lock, flags);
+               spin_lock_irqsave(&cm_node->recv_list_lock, flags);
+               list_for_each_safe(list_core, list_node_temp, &cm_node->recv_list) {
+                       recv_entry = container_of(list_core, struct nes_timer_entry, list);
+                       if ((time_after(recv_entry->timetosend, jiffies)) &&
+                                       (recv_entry->type == NES_TIMER_TYPE_CLOSE)) {
+                               if (nexttimeout > recv_entry->timetosend || !settimer) {
+                                       nexttimeout = recv_entry->timetosend;
+                                       settimer = 1;
+                               }
+                               continue;
+                       }
+                       list_del(&recv_entry->list);
+                       cm_id = cm_node->cm_id;
+                       spin_unlock_irqrestore(&cm_node->recv_list_lock, flags);
+                       if (recv_entry->type == NES_TIMER_TYPE_CLOSE) {
+                               nesqp = (struct nes_qp *)recv_entry->skb;
+                               spin_lock_irqsave(&nesqp->lock, qplockflags);
+                               if (nesqp->cm_id) {
+                                       nes_debug(NES_DBG_CM, "QP%u: cm_id = %p, refcount = %d: "
+                                                       "****** HIT A NES_TIMER_TYPE_CLOSE"
+                                                       " with something to do!!! ******\n",
+                                                       nesqp->hwqp.qp_id, cm_id,
+                                                       atomic_read(&nesqp->refcount));
+                                       nesqp->hw_tcp_state = NES_AEQE_TCP_STATE_CLOSED;
+                                       nesqp->last_aeq = NES_AEQE_AEID_RESET_SENT;
+                                       nesqp->ibqp_state = IB_QPS_ERR;
+                                       spin_unlock_irqrestore(&nesqp->lock, qplockflags);
+                                       nes_cm_disconn(nesqp);
+                               } else {
+                                       spin_unlock_irqrestore(&nesqp->lock, qplockflags);
+                                       nes_debug(NES_DBG_CM, "QP%u: cm_id = %p, refcount = %d:"
+                                                       " ****** HIT A NES_TIMER_TYPE_CLOSE"
+                                                       " with nothing to do!!! ******\n",
+                                                       nesqp->hwqp.qp_id, cm_id,
+                                                       atomic_read(&nesqp->refcount));
+                                       nes_rem_ref(&nesqp->ibqp);
+                               }
+                               if (cm_id)
+                                       cm_id->rem_ref(cm_id);
+                       }
+                       kfree(recv_entry);
+                       spin_lock_irqsave(&cm_node->recv_list_lock, flags);
+               }
+               spin_unlock_irqrestore(&cm_node->recv_list_lock, flags);
+
+               spin_lock_irqsave(&cm_node->retrans_list_lock, flags);
+               node_done = 0;
+               list_for_each_safe(list_core, list_node_temp, &cm_node->retrans_list) {
+                       if (node_done) {
+                               break;
+                       }
+                       send_entry = container_of(list_core, struct nes_timer_entry, list);
+                       if (time_after(send_entry->timetosend, jiffies)) {
+                               if (cm_node->state != NES_CM_STATE_TSA) {
+                                       if ((nexttimeout > send_entry->timetosend) || !settimer) {
+                                               nexttimeout = send_entry->timetosend;
+                                               settimer = 1;
+                                       }
+                                       node_done = 1;
+                                       continue;
+                               } else {
+                                       list_del(&send_entry->list);
+                                       skb = send_entry->skb;
+                                       spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags);
+                                       dev_kfree_skb_any(skb);
+                                       kfree(send_entry);
+                                       spin_lock_irqsave(&cm_node->retrans_list_lock, flags);
+                                       continue;
+                               }
+                       }
+                       if (send_entry->type == NES_TIMER_NODE_CLEANUP) {
+                               list_del(&send_entry->list);
+                               spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags);
+                               kfree(send_entry);
+                               spin_lock_irqsave(&cm_node->retrans_list_lock, flags);
+                               continue;
+                       }
+                       if ((send_entry->seq_num < cm_node->tcp_cntxt.rem_ack_num) ||
+                                       (cm_node->state == NES_CM_STATE_TSA) ||
+                                       (cm_node->state == NES_CM_STATE_CLOSED)) {
+                               skb = send_entry->skb;
+                               list_del(&send_entry->list);
+                               spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags);
+                               kfree(send_entry);
+                               dev_kfree_skb_any(skb);
+                               spin_lock_irqsave(&cm_node->retrans_list_lock, flags);
+                               continue;
+                       }
+
+                       if (!send_entry->retranscount || !send_entry->retrycount) {
+                               cm_packets_dropped++;
+                               skb = send_entry->skb;
+                               list_del(&send_entry->list);
+                               spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags);
+                               dev_kfree_skb_any(skb);
+                               kfree(send_entry);
+                               if (cm_node->state == NES_CM_STATE_SYN_RCVD) {
+                                       /* this node never even generated an indication up to the cm */
+                                       rem_ref_cm_node(cm_core, cm_node);
+                               } else {
+                                       cm_node->state = NES_CM_STATE_CLOSED;
+                                       create_event(cm_node, NES_CM_EVENT_ABORTED);
+                               }
+                               spin_lock_irqsave(&cm_node->retrans_list_lock, flags);
+                               continue;
+                       }
+                       /* this seems like the correct place, but leave send entry unprotected */
+                       // spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags);
+                       atomic_inc(&send_entry->skb->users);
+                       cm_packets_retrans++;
+                       nes_debug(NES_DBG_CM, "Retransmitting send_entry %p for node %p,"
+                                       " jiffies = %lu, time to send =  %lu, retranscount = %u, "
+                                       "send_entry->seq_num = 0x%08X, cm_node->tcp_cntxt.rem_ack_num = 0x%08X\n",
+                                       send_entry, cm_node, jiffies, send_entry->timetosend, send_entry->retranscount,
+                                       send_entry->seq_num, cm_node->tcp_cntxt.rem_ack_num);
+
+                       spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags);
+                       ret = nes_nic_cm_xmit(send_entry->skb, cm_node->netdev);
+                       if (ret != NETDEV_TX_OK) {
+                               cm_packets_bounced++;
+                               atomic_dec(&send_entry->skb->users);
+                               send_entry->retrycount--;
+                               nexttimeout = jiffies + NES_SHORT_TIME;
+                               settimer = 1;
+                               node_done = 1;
+                               spin_lock_irqsave(&cm_node->retrans_list_lock, flags);
+                               continue;
+                       } else {
+                               cm_packets_sent++;
+                       }
+                       spin_lock_irqsave(&cm_node->retrans_list_lock, flags);
+                       list_del(&send_entry->list);
+                       nes_debug(NES_DBG_CM, "Packet Sent: retrans count = %u, retry count = %u.\n",
+                                       send_entry->retranscount, send_entry->retrycount);
+                       if (send_entry->send_retrans) {
+                               send_entry->retranscount--;
+                               send_entry->timetosend = jiffies + NES_RETRY_TIMEOUT;
+                               if (nexttimeout > send_entry->timetosend || !settimer) {
+                                       nexttimeout = send_entry->timetosend;
+                                       settimer = 1;
+                               }
+                               list_add(&send_entry->list, &cm_node->retrans_list);
+                               continue;
+                       } else {
+                               int close_when_complete;
+                               skb = send_entry->skb;
+                               close_when_complete = send_entry->close_when_complete;
+                               spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags);
+                               if (close_when_complete) {
+                                       BUG_ON(atomic_read(&cm_node->ref_count) == 1);
+                                       rem_ref_cm_node(cm_core, cm_node);
+                               }
+                               dev_kfree_skb_any(skb);
+                               kfree(send_entry);
+                               spin_lock_irqsave(&cm_node->retrans_list_lock, flags);
+                               continue;
+                       }
+               }
+               spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags);
+
+               rem_ref_cm_node(cm_core, cm_node);
+
+               spin_lock_irqsave(&cm_core->ht_lock, flags);
+               if (ret != NETDEV_TX_OK)
+                       break;
+       }
+       spin_unlock_irqrestore(&cm_core->ht_lock, flags);
+
+       if (settimer) {
+               if (!timer_pending(&cm_core->tcp_timer)) {
+                       cm_core->tcp_timer.expires  = nexttimeout;
+                       add_timer(&cm_core->tcp_timer);
+               }
+       }
+}
+
+
+/**
+ * send_syn
+ */
+int send_syn(struct nes_cm_node *cm_node, u32 sendack)
+{
+       int ret;
+       int flags = SET_SYN;
+       struct sk_buff *skb;
+       char optionsbuffer[sizeof(struct option_mss) +
+                       sizeof(struct option_windowscale) +
+                       sizeof(struct option_base) + 1];
+
+       int optionssize = 0;
+       /* Sending MSS option */
+       union all_known_options *options;
+
+       if (!cm_node)
+               return -EINVAL;
+
+       options = (union all_known_options *)&optionsbuffer[optionssize];
+       options->as_mss.optionnum = OPTION_NUMBER_MSS;
+       options->as_mss.length = sizeof(struct option_mss);
+       options->as_mss.mss = htons(cm_node->tcp_cntxt.mss);
+       optionssize += sizeof(struct option_mss);
+
+       options = (union all_known_options *)&optionsbuffer[optionssize];
+       options->as_windowscale.optionnum = OPTION_NUMBER_WINDOW_SCALE;
+       options->as_windowscale.length = sizeof(struct option_windowscale);
+       options->as_windowscale.shiftcount = cm_node->tcp_cntxt.rcv_wscale;
+       optionssize += sizeof(struct option_windowscale);
+
+       if (sendack && !(NES_DRV_OPT_SUPRESS_OPTION_BC & nes_drv_opt)
+                       ) {
+               options = (union all_known_options *)&optionsbuffer[optionssize];
+               options->as_base.optionnum = OPTION_NUMBER_WRITE0;
+               options->as_base.length = sizeof(struct option_base);
+               optionssize += sizeof(struct option_base);
+               /* we need the size to be a multiple of 4 */
+               options = (union all_known_options *)&optionsbuffer[optionssize];
+               options->as_end = 1;
+               optionssize += 1;
+               options = (union all_known_options *)&optionsbuffer[optionssize];
+               options->as_end = 1;
+               optionssize += 1;
+       }
+
+       options = (union all_known_options *)&optionsbuffer[optionssize];
+       options->as_end = OPTION_NUMBER_END;
+       optionssize += 1;
+
+       skb = get_free_pkt(cm_node);
+       if (!skb) {
+               nes_debug(NES_DBG_CM, "Failed to get a Free pkt\n");
+               return -1;
+       }
+
+       if (sendack)
+               flags |= SET_ACK;
+
+       form_cm_frame(skb, cm_node, optionsbuffer, optionssize, NULL, 0, flags);
+       ret = schedule_nes_timer(cm_node, skb, NES_TIMER_TYPE_SEND, 1, 0);
+
+       return ret;
+}
+
+
+/**
+ * send_reset
+ */
+int send_reset(struct nes_cm_node *cm_node)
+{
+       int ret;
+       struct sk_buff *skb = get_free_pkt(cm_node);
+       int flags = SET_RST | SET_ACK;
+
+       if (!skb) {
+               nes_debug(NES_DBG_CM, "Failed to get a Free pkt\n");
+               return -1;
+       }
+
+       add_ref_cm_node(cm_node);
+       form_cm_frame(skb, cm_node, NULL, 0, NULL, 0, flags);
+       ret = schedule_nes_timer(cm_node, skb, NES_TIMER_TYPE_SEND, 0, 1);
+
+       return ret;
+}
+
+
+/**
+ * send_ack
+ */
+int send_ack(struct nes_cm_node *cm_node)
+{
+       int ret;
+       struct sk_buff *skb = get_free_pkt(cm_node);
+
+       if (!skb) {
+               nes_debug(NES_DBG_CM, "Failed to get a Free pkt\n");
+               return -1;
+       }
+
+       form_cm_frame(skb, cm_node, NULL, 0, NULL, 0, SET_ACK);
+       ret = schedule_nes_timer(cm_node, skb, NES_TIMER_TYPE_SEND, 0, 0);
+
+       return ret;
+}
+
+
+/**
+ * send_fin
+ */
+int send_fin(struct nes_cm_node *cm_node, struct sk_buff *skb)
+{
+       int ret;
+
+       /* if we didn't get a frame get one */
+       if (!skb)
+               skb = get_free_pkt(cm_node);
+
+       if (!skb) {
+               nes_debug(NES_DBG_CM, "Failed to get a Free pkt\n");
+               return -1;
+       }
+
+       form_cm_frame(skb, cm_node, NULL, 0, NULL, 0, SET_ACK | SET_FIN);
+       ret = schedule_nes_timer(cm_node, skb, NES_TIMER_TYPE_SEND, 1, 0);
+
+       return ret;
+}
+
+
+/**
+ * get_free_pkt
+ */
+struct sk_buff *get_free_pkt(struct nes_cm_node *cm_node)
+{
+       struct sk_buff *skb, *new_skb;
+
+       /* check to see if we need to repopulate the free tx pkt queue */
+       if (skb_queue_len(&cm_node->cm_core->tx_free_list) < NES_CM_FREE_PKT_LO_WATERMARK) {
+               while (skb_queue_len(&cm_node->cm_core->tx_free_list) <
+                               cm_node->cm_core->free_tx_pkt_max) {
+                       /* replace the frame we took, we won't get it back */
+                       new_skb = dev_alloc_skb(cm_node->cm_core->mtu);
+                       BUG_ON(!new_skb);
+                       /* add a replacement frame to the free tx list head */
+                       skb_queue_head(&cm_node->cm_core->tx_free_list, new_skb);
+               }
+       }
+
+       skb = skb_dequeue(&cm_node->cm_core->tx_free_list);
+
+       return skb;
+}
+
+
+/**
+ * make_hashkey - generate hash key from node tuple
+ */
+static inline int make_hashkey(u16 loc_port, nes_addr_t loc_addr, u16 rem_port,
+               nes_addr_t rem_addr)
+{
+       u32 hashkey = 0;
+
+       hashkey = loc_addr + rem_addr + loc_port + rem_port;
+       hashkey = (hashkey % NES_CM_HASHTABLE_SIZE);
+
+       return hashkey;
+}
+
+
+/**
+ * find_node - find a cm node that matches the reference cm node
+ */
+static struct nes_cm_node *find_node(struct nes_cm_core *cm_core,
+               u16 rem_port, nes_addr_t rem_addr, u16 loc_port, nes_addr_t loc_addr)
+{
+       unsigned long flags;
+       u32 hashkey;
+       struct list_head *list_pos;
+       struct list_head *hte;
+       struct nes_cm_node *cm_node;
+
+       /* make a hash index key for this packet */
+       hashkey = make_hashkey(loc_port, loc_addr, rem_port, rem_addr);
+
+       /* get a handle on the hte */
+       hte = &cm_core->connected_nodes;
+
+       nes_debug(NES_DBG_CM, "Searching for an owner node:%x:%x from core %p->%p\n",
+                       loc_addr, loc_port, cm_core, hte);
+
+       /* walk list and find cm_node associated with this session ID */
+       spin_lock_irqsave(&cm_core->ht_lock, flags);
+       list_for_each(list_pos, hte) {
+               cm_node = container_of(list_pos, struct nes_cm_node, list);
+               /* compare quad, return node handle if a match */
+               nes_debug(NES_DBG_CM, "finding node %x:%x =? %x:%x ^ %x:%x =? %x:%x\n",
+                               cm_node->loc_addr, cm_node->loc_port,
+                               loc_addr, loc_port,
+                               cm_node->rem_addr, cm_node->rem_port,
+                               rem_addr, rem_port);
+               if ((cm_node->loc_addr == loc_addr) && (cm_node->loc_port == loc_port) &&
+                               (cm_node->rem_addr == rem_addr) && (cm_node->rem_port == rem_port)) {
+                       add_ref_cm_node(cm_node);
+                       spin_unlock_irqrestore(&cm_core->ht_lock, flags);
+                       return cm_node;
+               }
+       }
+       spin_unlock_irqrestore(&cm_core->ht_lock, flags);
+
+       /* no owner node */
+       return NULL;
+}
+
+
+/**
+ * find_listener - find a cm node listening on this addr-port pair
+ */
+static struct nes_cm_listener *find_listener(struct nes_cm_core *cm_core,
+               nes_addr_t dst_addr, u16 dst_port, enum nes_cm_listener_state listener_state)
+{
+       unsigned long flags;
+       struct list_head *listen_list;
+       struct nes_cm_listener *listen_node;
+
+       /* walk list and find cm_node associated with this session ID */
+       spin_lock_irqsave(&cm_core->listen_list_lock, flags);
+       list_for_each(listen_list, &cm_core->listen_list.list) {
+               listen_node = container_of(listen_list, struct nes_cm_listener, list);
+               /* compare node pair, return node handle if a match */
+               if (((listen_node->loc_addr == dst_addr) ||
+                               listen_node->loc_addr == 0x00000000) &&
+                               (listen_node->loc_port == dst_port) &&
+                               (listener_state & listen_node->listener_state)) {
+                       atomic_inc(&listen_node->ref_count);
+                       spin_unlock_irqrestore(&cm_core->listen_list_lock, flags);
+                       return listen_node;
+               }
+       }
+       spin_unlock_irqrestore(&cm_core->listen_list_lock, flags);
+
+       nes_debug(NES_DBG_CM, "Unable to find listener- %x:%x\n",
+                       dst_addr, dst_port);
+
+       /* no listener */
+       return NULL;
+}
+
+
+/**
+ * add_hte_node - add a cm node to the hash table
+ */
+static int add_hte_node(struct nes_cm_core *cm_core, struct nes_cm_node *cm_node)
+{
+       unsigned long flags;
+       u32 hashkey;
+       struct list_head *hte;
+
+       if (!cm_node || !cm_core)
+               return -EINVAL;
+
+       nes_debug(NES_DBG_CM, "Adding Node to Active Connection HT\n");
+
+       /* first, make an index into our hash table */
+       hashkey = make_hashkey(cm_node->loc_port, cm_node->loc_addr,
+                       cm_node->rem_port, cm_node->rem_addr);
+       cm_node->hashkey = hashkey;
+
+       spin_lock_irqsave(&cm_core->ht_lock, flags);
+
+       /* get a handle on the hash table element (list head for this slot) */
+       hte = &cm_core->connected_nodes;
+       list_add_tail(&cm_node->list, hte);
+       atomic_inc(&cm_core->ht_node_cnt);
+
+       spin_unlock_irqrestore(&cm_core->ht_lock, flags);
+
+       return 0;
+}
+
+
+/**
+ * mini_cm_dec_refcnt_listen
+ */
+static int mini_cm_dec_refcnt_listen(struct nes_cm_core *cm_core,
+               struct nes_cm_listener *listener, int free_hanging_nodes)
+{
+       int ret = 1;
+       unsigned long flags;
+       spin_lock_irqsave(&cm_core->listen_list_lock, flags);
+       if (!atomic_dec_return(&listener->ref_count)) {
+               list_del(&listener->list);
+
+               /* decrement our listen node count */
+               atomic_dec(&cm_core->listen_node_cnt);
+
+               spin_unlock_irqrestore(&cm_core->listen_list_lock, flags);
+
+               if (listener->nesvnic) {
+                       nes_manage_apbvt(listener->nesvnic, listener->loc_port,
+                                       PCI_FUNC(listener->nesvnic->nesdev->pcidev->devfn), NES_MANAGE_APBVT_DEL);
+               }
+
+               nes_debug(NES_DBG_CM, "destroying listener (%p)\n", listener);
+
+               kfree(listener);
+               ret = 0;
+               cm_listens_destroyed++;
+       } else {
+               spin_unlock_irqrestore(&cm_core->listen_list_lock, flags);
+       }
+       if (listener) {
+               if (atomic_read(&listener->pend_accepts_cnt) > 0)
+                       nes_debug(NES_DBG_CM, "destroying listener (%p)"
+                                       " with non-zero pending accepts=%u\n",
+                                       listener, atomic_read(&listener->pend_accepts_cnt));
+       }
+
+       return ret;
+}
+
+
+/**
+ * mini_cm_del_listen
+ */
+static int mini_cm_del_listen(struct nes_cm_core *cm_core,
+               struct nes_cm_listener *listener)
+{
+       listener->listener_state = NES_CM_LISTENER_PASSIVE_STATE;
+       listener->cm_id = NULL; /* going to be destroyed pretty soon */
+       return mini_cm_dec_refcnt_listen(cm_core, listener, 1);
+}
+
+
+/**
+ * mini_cm_accelerated
+ */
+static inline int mini_cm_accelerated(struct nes_cm_core *cm_core,
+               struct nes_cm_node *cm_node)
+{
+       u32 was_timer_set;
+       cm_node->accelerated = 1;
+
+       if (cm_node->accept_pend) {
+               BUG_ON(!cm_node->listener);
+               atomic_dec(&cm_node->listener->pend_accepts_cnt);
+               BUG_ON(atomic_read(&cm_node->listener->pend_accepts_cnt) < 0);
+       }
+
+       was_timer_set = timer_pending(&cm_core->tcp_timer);
+       if (!was_timer_set) {
+               cm_core->tcp_timer.expires = jiffies + NES_SHORT_TIME;
+               add_timer(&cm_core->tcp_timer);
+       }
+
+       return 0;
+}
+
+
+/**
+ * nes_addr_send_arp
+ */
+static void nes_addr_send_arp(u32 dst_ip)
+{
+       struct rtable *rt;
+       struct flowi fl;
+
+       memset(&fl, 0, sizeof fl);
+       fl.nl_u.ip4_u.daddr = htonl(dst_ip);
+       if (ip_route_output_key(&init_net, &rt, &fl)) {
+               printk("%s: ip_route_output_key failed for 0x%08X\n",
+                               __FUNCTION__, dst_ip);
+               return;
+       }
+
+       neigh_event_send(rt->u.dst.neighbour, NULL);
+       ip_rt_put(rt);
+}
+
+
+/**
+ * make_cm_node - create a new instance of a cm node
+ */
+static struct nes_cm_node *make_cm_node(struct nes_cm_core *cm_core,
+               struct nes_vnic *nesvnic, struct nes_cm_info *cm_info,
+               struct nes_cm_listener *listener)
+{
+       struct nes_cm_node *cm_node;
+       struct timespec ts;
+       int arpindex = 0;
+       struct nes_device *nesdev;
+       struct nes_adapter *nesadapter;
+
+       /* create an hte and cm_node for this instance */
+       cm_node = kzalloc(sizeof(*cm_node), GFP_ATOMIC);
+       if (!cm_node)
+               return NULL;
+
+       /* set our node specific transport info */
+       cm_node->loc_addr = cm_info->loc_addr;
+       cm_node->rem_addr = cm_info->rem_addr;
+       cm_node->loc_port = cm_info->loc_port;
+       cm_node->rem_port = cm_info->rem_port;
+       cm_node->send_write0 = send_first;
+       nes_debug(NES_DBG_CM, "Make node addresses : loc = %x:%x, rem = %x:%x\n",
+                       cm_node->loc_addr, cm_node->loc_port, cm_node->rem_addr, cm_node->rem_port);
+       cm_node->listener = listener;
+       cm_node->netdev = nesvnic->netdev;
+       cm_node->cm_id = cm_info->cm_id;
+       memcpy(cm_node->loc_mac, nesvnic->netdev->dev_addr, ETH_ALEN);
+
+       nes_debug(NES_DBG_CM, "listener=%p, cm_id=%p\n",
+                       cm_node->listener, cm_node->cm_id);
+
+       INIT_LIST_HEAD(&cm_node->retrans_list);
+       spin_lock_init(&cm_node->retrans_list_lock);
+       INIT_LIST_HEAD(&cm_node->recv_list);
+       spin_lock_init(&cm_node->recv_list_lock);
+
+       cm_node->loopbackpartner = NULL;
+       atomic_set(&cm_node->ref_count, 1);
+       /* associate our parent CM core */
+       cm_node->cm_core = cm_core;
+       cm_node->tcp_cntxt.loc_id = NES_CM_DEF_LOCAL_ID;
+       cm_node->tcp_cntxt.rcv_wscale = NES_CM_DEFAULT_RCV_WND_SCALE;
+       cm_node->tcp_cntxt.rcv_wnd = NES_CM_DEFAULT_RCV_WND_SCALED >>
+                       NES_CM_DEFAULT_RCV_WND_SCALE;
+       ts = current_kernel_time();
+       cm_node->tcp_cntxt.loc_seq_num = htonl(ts.tv_nsec);
+       cm_node->tcp_cntxt.mss = nesvnic->max_frame_size - sizeof(struct iphdr) -
+                       sizeof(struct tcphdr) - ETH_HLEN;
+       cm_node->tcp_cntxt.rcv_nxt = 0;
+       /* get a unique session ID , add thread_id to an upcounter to handle race */
+       atomic_inc(&cm_core->node_cnt);
+       atomic_inc(&cm_core->session_id);
+       cm_node->session_id = (u32)(atomic_read(&cm_core->session_id) + current->tgid);
+       cm_node->conn_type = cm_info->conn_type;
+       cm_node->apbvt_set = 0;
+       cm_node->accept_pend = 0;
+
+       cm_node->nesvnic = nesvnic;
+       /* get some device handles, for arp lookup */
+       nesdev = nesvnic->nesdev;
+       nesadapter = nesdev->nesadapter;
+
+       cm_node->loopbackpartner = NULL;
+       /* get the mac addr for the remote node */
+       arpindex = nes_arp_table(nesdev, cm_node->rem_addr, NULL, NES_ARP_RESOLVE);
+       if (arpindex < 0) {
+               kfree(cm_node);
+               nes_addr_send_arp(cm_info->rem_addr);
+               return NULL;
+       }
+
+       /* copy the mac addr to node context */
+       memcpy(cm_node->rem_mac, nesadapter->arp_table[arpindex].mac_addr, ETH_ALEN);
+       nes_debug(NES_DBG_CM, "Remote mac addr from arp table:%02x,"
+                       " %02x, %02x, %02x, %02x, %02x\n",
+                       cm_node->rem_mac[0], cm_node->rem_mac[1],
+                       cm_node->rem_mac[2], cm_node->rem_mac[3],
+                       cm_node->rem_mac[4], cm_node->rem_mac[5]);
+
+       add_hte_node(cm_core, cm_node);
+       atomic_inc(&cm_nodes_created);
+
+       return cm_node;
+}
+
+
+/**
+ * add_ref_cm_node - destroy an instance of a cm node
+ */
+static int add_ref_cm_node(struct nes_cm_node *cm_node)
+{
+       atomic_inc(&cm_node->ref_count);
+       return 0;
+}
+
+
+/**
+ * rem_ref_cm_node - destroy an instance of a cm node
+ */
+static int rem_ref_cm_node(struct nes_cm_core *cm_core,
+               struct nes_cm_node *cm_node)
+{
+       unsigned long flags, qplockflags;
+       struct nes_timer_entry *send_entry;
+       struct nes_timer_entry *recv_entry;
+       struct iw_cm_id *cm_id;
+       struct list_head *list_core, *list_node_temp;
+       struct nes_qp *nesqp;
+
+       if (!cm_node)
+               return -EINVAL;
+
+       spin_lock_irqsave(&cm_node->cm_core->ht_lock, flags);
+       if (atomic_dec_return(&cm_node->ref_count)) {
+               spin_unlock_irqrestore(&cm_node->cm_core->ht_lock, flags);
+               return 0;
+       }
+       list_del(&cm_node->list);
+       atomic_dec(&cm_core->ht_node_cnt);
+       spin_unlock_irqrestore(&cm_node->cm_core->ht_lock, flags);
+
+       /* if the node is destroyed before connection was accelerated */
+       if (!cm_node->accelerated && cm_node->accept_pend) {
+               BUG_ON(!cm_node->listener);
+               atomic_dec(&cm_node->listener->pend_accepts_cnt);
+               BUG_ON(atomic_read(&cm_node->listener->pend_accepts_cnt) < 0);
+       }
+
+       spin_lock_irqsave(&cm_node->retrans_list_lock, flags);
+       list_for_each_safe(list_core, list_node_temp, &cm_node->retrans_list) {
+               send_entry = container_of(list_core, struct nes_timer_entry, list);
+               list_del(&send_entry->list);
+               spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags);
+               dev_kfree_skb_any(send_entry->skb);
+               kfree(send_entry);
+               spin_lock_irqsave(&cm_node->retrans_list_lock, flags);
+               continue;
+       }
+       spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags);
+
+       spin_lock_irqsave(&cm_node->recv_list_lock, flags);
+       list_for_each_safe(list_core, list_node_temp, &cm_node->recv_list) {
+               recv_entry = container_of(list_core, struct nes_timer_entry, list);
+               list_del(&recv_entry->list);
+               cm_id = cm_node->cm_id;
+               spin_unlock_irqrestore(&cm_node->recv_list_lock, flags);
+               if (recv_entry->type == NES_TIMER_TYPE_CLOSE) {
+                       nesqp = (struct nes_qp *)recv_entry->skb;
+                       spin_lock_irqsave(&nesqp->lock, qplockflags);
+                       if (nesqp->cm_id) {
+                               nes_debug(NES_DBG_CM, "QP%u: cm_id = %p: ****** HIT A NES_TIMER_TYPE_CLOSE"
+                                               " with something to do!!! ******\n",
+                                               nesqp->hwqp.qp_id, cm_id);
+                               nesqp->hw_tcp_state = NES_AEQE_TCP_STATE_CLOSED;
+                               nesqp->last_aeq = NES_AEQE_AEID_RESET_SENT;
+                               nesqp->ibqp_state = IB_QPS_ERR;
+                               spin_unlock_irqrestore(&nesqp->lock, qplockflags);
+                               nes_cm_disconn(nesqp);
+                       } else {
+                               spin_unlock_irqrestore(&nesqp->lock, qplockflags);
+                               nes_debug(NES_DBG_CM, "QP%u: cm_id = %p: ****** HIT A NES_TIMER_TYPE_CLOSE"
+                                               " with nothing to do!!! ******\n",
+                                               nesqp->hwqp.qp_id, cm_id);
+                               nes_rem_ref(&nesqp->ibqp);
+                       }
+                       cm_id->rem_ref(cm_id);
+               } else if (recv_entry->type == NES_TIMER_TYPE_RECV) {
+                       dev_kfree_skb_any(recv_entry->skb);
+               }
+               kfree(recv_entry);
+               spin_lock_irqsave(&cm_node->recv_list_lock, flags);
+       }
+       spin_unlock_irqrestore(&cm_node->recv_list_lock, flags);
+
+       if (cm_node->listener) {
+               mini_cm_dec_refcnt_listen(cm_core, cm_node->listener, 0);
+       } else {
+               if (cm_node->apbvt_set && cm_node->nesvnic) {
+                       nes_manage_apbvt(cm_node->nesvnic, cm_node->loc_port,
+                                       PCI_FUNC(cm_node->nesvnic->nesdev->pcidev->devfn),
+                                       NES_MANAGE_APBVT_DEL);
+               }
+       }
+
+       kfree(cm_node);
+       atomic_dec(&cm_core->node_cnt);
+       atomic_inc(&cm_nodes_destroyed);
+
+       return 0;
+}
+
+
+/**
+ * process_options
+ */
+static int process_options(struct nes_cm_node *cm_node, u8 *optionsloc, u32 optionsize, u32 syn_packet)
+{
+       u32 tmp;
+       u32 offset = 0;
+       union all_known_options *all_options;
+       char got_mss_option = 0;
+
+       while (offset < optionsize) {
+               all_options = (union all_known_options *)(optionsloc + offset);
+               switch (all_options->as_base.optionnum) {
+                       case OPTION_NUMBER_END:
+                               offset = optionsize;
+                               break;
+                       case OPTION_NUMBER_NONE:
+                               offset += 1;
+                               continue;
+                       case OPTION_NUMBER_MSS:
+                               nes_debug(NES_DBG_CM, "%s: MSS Length: %d Offset: %d Size: %d\n",
+                                               __FUNCTION__,
+                                               all_options->as_mss.length, offset, optionsize);
+                               got_mss_option = 1;
+                               if (all_options->as_mss.length != 4) {
+                                       return 1;
+                               } else {
+                                       tmp = ntohs(all_options->as_mss.mss);
+                                       if (tmp > 0 && tmp < cm_node->tcp_cntxt.mss)
+                                               cm_node->tcp_cntxt.mss = tmp;
+                               }
+                               break;
+                       case OPTION_NUMBER_WINDOW_SCALE:
+                               cm_node->tcp_cntxt.snd_wscale = all_options->as_windowscale.shiftcount;
+                               break;
+                       case OPTION_NUMBER_WRITE0:
+                               cm_node->send_write0 = 1;
+                               break;
+                       default:
+                               nes_debug(NES_DBG_CM, "TCP Option not understood: %x\n",
+                                               all_options->as_base.optionnum);
+                               break;
+               }
+               offset += all_options->as_base.length;
+       }
+       if ((!got_mss_option) && (syn_packet))
+               cm_node->tcp_cntxt.mss = NES_CM_DEFAULT_MSS;
+       return 0;
+}
+
+
+/**
+ * process_packet
+ */
+int process_packet(struct nes_cm_node *cm_node, struct sk_buff *skb,
+               struct nes_cm_core *cm_core)
+{
+       int optionsize;
+       int datasize;
+       int ret = 0;
+       struct tcphdr *tcph = tcp_hdr(skb);
+       u32 inc_sequence;
+       if (cm_node->state == NES_CM_STATE_SYN_SENT && tcph->syn) {
+               inc_sequence = ntohl(tcph->seq);
+               cm_node->tcp_cntxt.rcv_nxt = inc_sequence;
+       }
+
+       if ((!tcph) || (cm_node->state == NES_CM_STATE_TSA)) {
+               BUG_ON(!tcph);
+               atomic_inc(&cm_accel_dropped_pkts);
+               return -1;
+       }
+
+       if (tcph->rst) {
+               atomic_inc(&cm_resets_recvd);
+               nes_debug(NES_DBG_CM, "Received Reset, cm_node = %p, state = %u. refcnt=%d\n",
+                               cm_node, cm_node->state, atomic_read(&cm_node->ref_count));
+               switch (cm_node->state) {
+                       case NES_CM_STATE_LISTENING:
+                               rem_ref_cm_node(cm_core, cm_node);
+                               break;
+                       case NES_CM_STATE_TSA:
+                       case NES_CM_STATE_CLOSED:
+                               break;
+                       case NES_CM_STATE_SYN_RCVD:
+                                       nes_debug(NES_DBG_CM, "Received a reset for local 0x%08X:%04X,"
+                                                       " remote 0x%08X:%04X, node state = %u\n",
+                                                       cm_node->loc_addr, cm_node->loc_port,
+                                                       cm_node->rem_addr, cm_node->rem_port,
+                                                       cm_node->state);
+                               rem_ref_cm_node(cm_core, cm_node);
+                               break;
+                       case NES_CM_STATE_ONE_SIDE_ESTABLISHED:
+                       case NES_CM_STATE_ESTABLISHED:
+                       case NES_CM_STATE_MPAREQ_SENT:
+                       default:
+                                       nes_debug(NES_DBG_CM, "Received a reset for local 0x%08X:%04X,"
+                                                       " remote 0x%08X:%04X, node state = %u refcnt=%d\n",
+                                                       cm_node->loc_addr, cm_node->loc_port,
+                                                       cm_node->rem_addr, cm_node->rem_port,
+                                                       cm_node->state, atomic_read(&cm_node->ref_count));
+                               // create event
+                               cm_node->state = NES_CM_STATE_CLOSED;
+
+                               create_event(cm_node, NES_CM_EVENT_ABORTED);
+                               break;
+
+               }
+               return -1;
+       }
+
+       optionsize = (tcph->doff << 2) - sizeof(struct tcphdr);
+
+       skb_pull(skb, ip_hdr(skb)->ihl << 2);
+       skb_pull(skb, tcph->doff << 2);
+
+       datasize = skb->len;
+       inc_sequence = ntohl(tcph->seq);
+       nes_debug(NES_DBG_CM, "datasize = %u, sequence = 0x%08X, ack_seq = 0x%08X,"
+                       " rcv_nxt = 0x%08X Flags: %s %s.\n",
+                       datasize, inc_sequence, ntohl(tcph->ack_seq),
+                       cm_node->tcp_cntxt.rcv_nxt, (tcph->syn ? "SYN":""),
+                       (tcph->ack ? "ACK":""));
+
+       if (!tcph->syn && (inc_sequence != cm_node->tcp_cntxt.rcv_nxt)
+               ) {
+               nes_debug(NES_DBG_CM, "dropping packet, datasize = %u, sequence = 0x%08X,"
+                               " ack_seq = 0x%08X, rcv_nxt = 0x%08X Flags: %s.\n",
+                               datasize, inc_sequence, ntohl(tcph->ack_seq),
+                               cm_node->tcp_cntxt.rcv_nxt, (tcph->ack ? "ACK":""));
+               if (cm_node->state == NES_CM_STATE_LISTENING) {
+                       rem_ref_cm_node(cm_core, cm_node);
+               }
+               return -1;
+       }
+
+               cm_node->tcp_cntxt.rcv_nxt = inc_sequence + datasize;
+
+
+       if (optionsize) {
+               u8 *optionsloc = (u8 *)&tcph[1];
+               if (process_options(cm_node, optionsloc, optionsize, (u32)tcph->syn)) {
+                       nes_debug(NES_DBG_CM, "%s: Node %p, Sending RESET\n", __FUNCTION__, cm_node);
+                       send_reset(cm_node);
+                       if (cm_node->state != NES_CM_STATE_SYN_SENT)
+                       rem_ref_cm_node(cm_core, cm_node);
+                       return 0;
+               }
+       } else if (tcph->syn)
+               cm_node->tcp_cntxt.mss = NES_CM_DEFAULT_MSS;
+
+       cm_node->tcp_cntxt.snd_wnd = ntohs(tcph->window) <<
+                       cm_node->tcp_cntxt.snd_wscale;
+
+       if (cm_node->tcp_cntxt.snd_wnd > cm_node->tcp_cntxt.max_snd_wnd) {
+               cm_node->tcp_cntxt.max_snd_wnd = cm_node->tcp_cntxt.snd_wnd;
+       }
+
+       if (tcph->ack) {
+               cm_node->tcp_cntxt.rem_ack_num = ntohl(tcph->ack_seq);
+               switch (cm_node->state) {
+                       case NES_CM_STATE_SYN_RCVD:
+                       case NES_CM_STATE_SYN_SENT:
+                               /* read and stash current sequence number */
+                               if (cm_node->tcp_cntxt.rem_ack_num != cm_node->tcp_cntxt.loc_seq_num) {
+                                       nes_debug(NES_DBG_CM, "ERROR - cm_node->tcp_cntxt.rem_ack_num !="
+                                                       " cm_node->tcp_cntxt.loc_seq_num\n");
+                                       send_reset(cm_node);
+                                       return 0;
+                               }
+                               if (cm_node->state == NES_CM_STATE_SYN_SENT)
+                                       cm_node->state = NES_CM_STATE_ONE_SIDE_ESTABLISHED;
+                               else {
+                                               cm_node->state = NES_CM_STATE_ESTABLISHED;
+                               }
+                               break;
+                       case NES_CM_STATE_LAST_ACK:
+                               cm_node->state = NES_CM_STATE_CLOSED;
+                               break;
+                       case NES_CM_STATE_FIN_WAIT1:
+                               cm_node->state = NES_CM_STATE_FIN_WAIT2;
+                               break;
+                       case NES_CM_STATE_CLOSING:
+                               cm_node->state = NES_CM_STATE_TIME_WAIT;
+                               /* need to schedule this to happen in 2MSL timeouts */
+                               cm_node->state = NES_CM_STATE_CLOSED;
+                               break;
+                       case NES_CM_STATE_ONE_SIDE_ESTABLISHED:
+                       case NES_CM_STATE_ESTABLISHED:
+                       case NES_CM_STATE_MPAREQ_SENT:
+                       case NES_CM_STATE_CLOSE_WAIT:
+                       case NES_CM_STATE_TIME_WAIT:
+                       case NES_CM_STATE_CLOSED:
+                               break;
+                       case NES_CM_STATE_LISTENING:
+                               nes_debug(NES_DBG_CM, "Received an ACK on a listening port (SYN %d)\n", tcph->syn);
+                               cm_node->tcp_cntxt.loc_seq_num = ntohl(tcph->ack_seq);
+                               send_reset(cm_node);
+                               /* send_reset bumps refcount, this should have been a new node */
+                               rem_ref_cm_node(cm_core, cm_node);
+                               return -1;
+                               break;
+                       case NES_CM_STATE_TSA:
+                               nes_debug(NES_DBG_CM, "Received a packet with the ack bit set while in TSA state\n");
+                               break;
+                       case NES_CM_STATE_UNKNOWN:
+                       case NES_CM_STATE_INITED:
+                       case NES_CM_STATE_ACCEPTING:
+                       case NES_CM_STATE_FIN_WAIT2:
+                       default:
+                               nes_debug(NES_DBG_CM, "Received ack from unknown state: %x\n",
+                                               cm_node->state);
+                               send_reset(cm_node);
+                               break;
+               }
+       }
+
+       if (tcph->syn) {
+               if (cm_node->state == NES_CM_STATE_LISTENING) {
+                       /* do not exceed backlog */
+                       atomic_inc(&cm_node->listener->pend_accepts_cnt);
+                       if (atomic_read(&cm_node->listener->pend_accepts_cnt) >
+                                       cm_node->listener->backlog) {
+                               nes_debug(NES_DBG_CM, "drop syn due to backlog pressure \n");
+                               cm_backlog_drops++;
+                               atomic_dec(&cm_node->listener->pend_accepts_cnt);
+                               rem_ref_cm_node(cm_core, cm_node);
+                               return 0;
+                       }
+                       cm_node->accept_pend = 1;
+
+               }
+               if (datasize == 0)
+                       cm_node->tcp_cntxt.rcv_nxt ++;
+
+               if (cm_node->state == NES_CM_STATE_LISTENING) {
+                       cm_node->state = NES_CM_STATE_SYN_RCVD;
+                       send_syn(cm_node, 1);
+               }
+               if (cm_node->state == NES_CM_STATE_ONE_SIDE_ESTABLISHED) {
+                       cm_node->state = NES_CM_STATE_ESTABLISHED;
+                       /* send final handshake ACK */
+                       ret = send_ack(cm_node);
+                       if (ret < 0)
+                               return ret;
+
+                               cm_node->state = NES_CM_STATE_MPAREQ_SENT;
+                               ret = send_mpa_request(cm_node);
+                               if (ret < 0)
+                                       return ret;
+               }
+       }
+
+       if (tcph->fin) {
+               cm_node->tcp_cntxt.rcv_nxt++;
+               switch (cm_node->state) {
+                       case NES_CM_STATE_SYN_RCVD:
+                       case NES_CM_STATE_SYN_SENT:
+                       case NES_CM_STATE_ONE_SIDE_ESTABLISHED:
+                       case NES_CM_STATE_ESTABLISHED:
+                       case NES_CM_STATE_ACCEPTING:
+                       case NES_CM_STATE_MPAREQ_SENT:
+                               cm_node->state = NES_CM_STATE_CLOSE_WAIT;
+                               cm_node->state = NES_CM_STATE_LAST_ACK;
+                               ret = send_fin(cm_node, NULL);
+                               break;
+                       case NES_CM_STATE_FIN_WAIT1:
+                               cm_node->state = NES_CM_STATE_CLOSING;
+                               ret = send_ack(cm_node);
+                               break;
+                       case NES_CM_STATE_FIN_WAIT2:
+                               cm_node->state = NES_CM_STATE_TIME_WAIT;
+                               cm_node->tcp_cntxt.loc_seq_num ++;
+                               ret = send_ack(cm_node);
+                               /* need to schedule this to happen in 2MSL timeouts */
+                               cm_node->state = NES_CM_STATE_CLOSED;
+                               break;
+                       case NES_CM_STATE_CLOSE_WAIT:
+                       case NES_CM_STATE_LAST_ACK:
+                       case NES_CM_STATE_CLOSING:
+                       case NES_CM_STATE_TSA:
+                       default:
+                               nes_debug(NES_DBG_CM, "Received a fin while in %x state\n",
+                                               cm_node->state);
+                               ret = -EINVAL;
+                               break;
+               }
+       }
+
+       if (datasize) {
+               u8 *dataloc = skb->data;
+               /* figure out what state we are in and handle transition to next state */
+               switch (cm_node->state) {
+                       case NES_CM_STATE_LISTENING:
+                       case NES_CM_STATE_SYN_RCVD:
+                       case NES_CM_STATE_SYN_SENT:
+                       case NES_CM_STATE_FIN_WAIT1:
+                       case NES_CM_STATE_FIN_WAIT2:
+                       case NES_CM_STATE_CLOSE_WAIT:
+                       case NES_CM_STATE_LAST_ACK:
+                       case NES_CM_STATE_CLOSING:
+                               break;
+                       case  NES_CM_STATE_MPAREQ_SENT:
+                               /* recv the mpa res frame, ret=frame len (incl priv data) */
+                               ret = parse_mpa(cm_node, dataloc, datasize);
+                               if (ret < 0)
+                                       break;
+                               /* set the req frame payload len in skb */
+                               /* we are done handling this state, set node to a TSA state */
+                               cm_node->state = NES_CM_STATE_TSA;
+                               send_ack(cm_node);
+                               create_event(cm_node, NES_CM_EVENT_CONNECTED);
+                               break;
+
+                       case  NES_CM_STATE_ESTABLISHED:
+                               /* we are expecting an MPA req frame */
+                               ret = parse_mpa(cm_node, dataloc, datasize);
+                               if (ret < 0) {
+                                       break;
+                               }
+                               cm_node->state = NES_CM_STATE_TSA;
+                               send_ack(cm_node);
+                               /* we got a valid MPA request, create an event */
+                               create_event(cm_node, NES_CM_EVENT_MPA_REQ);
+                               break;
+                       case  NES_CM_STATE_TSA:
+                               handle_exception_pkt(cm_node, skb);
+                               break;
+                       case NES_CM_STATE_UNKNOWN:
+                       case NES_CM_STATE_INITED:
+                       default:
+                               ret = -1;
+               }
+       }
+
+       return ret;
+}
+
+
+/**
+ * mini_cm_listen - create a listen node with params
+ */
+static struct nes_cm_listener *mini_cm_listen(struct nes_cm_core *cm_core,
+               struct nes_vnic *nesvnic, struct nes_cm_info *cm_info)
+{
+       struct nes_cm_listener *listener;
+       unsigned long flags;
+
+       nes_debug(NES_DBG_CM, "Search for 0x%08x : 0x%04x\n",
+               cm_info->loc_addr, cm_info->loc_port);
+
+       /* cannot have multiple matching listeners */
+       listener = find_listener(cm_core, htonl(cm_info->loc_addr),
+                       htons(cm_info->loc_port), NES_CM_LISTENER_EITHER_STATE);
+       if (listener && listener->listener_state == NES_CM_LISTENER_ACTIVE_STATE) {
+               /* find automatically incs ref count ??? */
+               atomic_dec(&listener->ref_count);
+               nes_debug(NES_DBG_CM, "Not creating listener since it already exists\n");
+               return NULL;
+       }
+
+       if (!listener) {
+               /* create a CM listen node (1/2 node to compare incoming traffic to) */
+               listener = kzalloc(sizeof(*listener), GFP_ATOMIC);
+               if (!listener) {
+                       nes_debug(NES_DBG_CM, "Not creating listener memory allocation failed\n");
+                       return NULL;
+               }
+
+               memset(listener, 0, sizeof(struct nes_cm_listener));
+               listener->loc_addr = htonl(cm_info->loc_addr);
+               listener->loc_port = htons(cm_info->loc_port);
+               listener->reused_node = 0;
+
+               atomic_set(&listener->ref_count, 1);
+       }
+       /* pasive case */
+       /* find already inc'ed the ref count */
+       else {
+               listener->reused_node = 1;
+       }
+
+       listener->cm_id = cm_info->cm_id;
+       atomic_set(&listener->pend_accepts_cnt, 0);
+       listener->cm_core = cm_core;
+       listener->nesvnic = nesvnic;
+       atomic_inc(&cm_core->node_cnt);
+       atomic_inc(&cm_core->session_id);
+
+       listener->session_id = (u32)(atomic_read(&cm_core->session_id) + current->tgid);
+       listener->conn_type = cm_info->conn_type;
+       listener->backlog = cm_info->backlog;
+       listener->listener_state = NES_CM_LISTENER_ACTIVE_STATE;
+
+       if (!listener->reused_node) {
+               spin_lock_irqsave(&cm_core->listen_list_lock, flags);
+               list_add(&listener->list, &cm_core->listen_list.list);
+               spin_unlock_irqrestore(&cm_core->listen_list_lock, flags);
+               atomic_inc(&cm_core->listen_node_cnt);
+       }
+
+       nes_debug(NES_DBG_CM, "Api - listen(): addr=0x%08X, port=0x%04x,"
+                       " listener = %p, backlog = %d, cm_id = %p.\n",
+                       cm_info->loc_addr, cm_info->loc_port,
+                       listener, listener->backlog, listener->cm_id);
+
+       return listener;
+}
+
+
+/**
+ * mini_cm_connect - make a connection node with params
+ */
+struct nes_cm_node *mini_cm_connect(struct nes_cm_core *cm_core,
+               struct nes_vnic *nesvnic, struct ietf_mpa_frame *mpa_frame,
+               struct nes_cm_info *cm_info)
+{
+       int ret = 0;
+       struct nes_cm_node *cm_node;
+       struct nes_cm_listener *loopbackremotelistener;
+       struct nes_cm_node *loopbackremotenode;
+       struct nes_cm_info loopback_cm_info;
+
+       u16 mpa_frame_size = sizeof(struct ietf_mpa_frame) +
+                       ntohs(mpa_frame->priv_data_len);
+
+       cm_info->loc_addr = htonl(cm_info->loc_addr);
+       cm_info->rem_addr = htonl(cm_info->rem_addr);
+       cm_info->loc_port = htons(cm_info->loc_port);
+       cm_info->rem_port = htons(cm_info->rem_port);
+
+       /* create a CM connection node */
+       cm_node = make_cm_node(cm_core, nesvnic, cm_info, NULL);
+       if (!cm_node)
+               return NULL;
+
+       // set our node side to client (active) side
+       cm_node->tcp_cntxt.client = 1;
+       cm_node->tcp_cntxt.rcv_wscale = NES_CM_DEFAULT_RCV_WND_SCALE;
+
+       if (cm_info->loc_addr == cm_info->rem_addr) {
+               loopbackremotelistener = find_listener(cm_core, cm_node->rem_addr,
+                               cm_node->rem_port, NES_CM_LISTENER_ACTIVE_STATE);
+               if (loopbackremotelistener == NULL) {
+                       create_event(cm_node, NES_CM_EVENT_ABORTED);
+               } else {
+                       atomic_inc(&cm_loopbacks);
+                       loopback_cm_info = *cm_info;
+                       loopback_cm_info.loc_port = cm_info->rem_port;
+                       loopback_cm_info.rem_port = cm_info->loc_port;
+                       loopback_cm_info.cm_id = loopbackremotelistener->cm_id;
+                       loopbackremotenode = make_cm_node(cm_core, nesvnic, &loopback_cm_info,
+                                       loopbackremotelistener);
+                       loopbackremotenode->loopbackpartner = cm_node;
+                       loopbackremotenode->tcp_cntxt.rcv_wscale = NES_CM_DEFAULT_RCV_WND_SCALE;
+                       cm_node->loopbackpartner = loopbackremotenode;
+                       memcpy(loopbackremotenode->mpa_frame_buf, &mpa_frame->priv_data,
+                                       mpa_frame_size);
+                       loopbackremotenode->mpa_frame_size = mpa_frame_size -
+                                       sizeof(struct ietf_mpa_frame);
+
+                       // we are done handling this state, set node to a TSA state
+                       cm_node->state = NES_CM_STATE_TSA;
+                       cm_node->tcp_cntxt.rcv_nxt = loopbackremotenode->tcp_cntxt.loc_seq_num;
+                       loopbackremotenode->tcp_cntxt.rcv_nxt = cm_node->tcp_cntxt.loc_seq_num;
+                       cm_node->tcp_cntxt.max_snd_wnd = loopbackremotenode->tcp_cntxt.rcv_wnd;
+                       loopbackremotenode->tcp_cntxt.max_snd_wnd = cm_node->tcp_cntxt.rcv_wnd;
+                       cm_node->tcp_cntxt.snd_wnd = loopbackremotenode->tcp_cntxt.rcv_wnd;
+                       loopbackremotenode->tcp_cntxt.snd_wnd = cm_node->tcp_cntxt.rcv_wnd;
+                       cm_node->tcp_cntxt.snd_wscale = loopbackremotenode->tcp_cntxt.rcv_wscale;
+                       loopbackremotenode->tcp_cntxt.snd_wscale = cm_node->tcp_cntxt.rcv_wscale;
+
+                       create_event(loopbackremotenode, NES_CM_EVENT_MPA_REQ);
+               }
+               return cm_node;
+       }
+
+       /* set our node side to client (active) side */
+       cm_node->tcp_cntxt.client = 1;
+       /* init our MPA frame ptr */
+       memcpy(&cm_node->mpa_frame, mpa_frame, mpa_frame_size);
+       cm_node->mpa_frame_size = mpa_frame_size;
+
+       /* send a syn and goto syn sent state */
+       cm_node->state = NES_CM_STATE_SYN_SENT;
+       ret = send_syn(cm_node, 0);
+
+       nes_debug(NES_DBG_CM, "Api - connect(): dest addr=0x%08X, port=0x%04x,"
+                       " cm_node=%p, cm_id = %p.\n",
+                       cm_node->rem_addr, cm_node->rem_port, cm_node, cm_node->cm_id);
+
+       return cm_node;
+}
+
+
+/**
+ * mini_cm_accept - accept a connection
+ * This function is never called
+ */
+int mini_cm_accept(struct nes_cm_core *cm_core, struct ietf_mpa_frame *mpa_frame,
+               struct nes_cm_node *cm_node)
+{
+       return 0;
+}
+
+
+/**
+ * mini_cm_reject - reject and teardown a connection
+ */
+int mini_cm_reject(struct nes_cm_core *cm_core,
+               struct ietf_mpa_frame *mpa_frame,
+               struct nes_cm_node *cm_node)
+{
+       int ret = 0;
+       struct sk_buff *skb;
+       u16 mpa_frame_size = sizeof(struct ietf_mpa_frame) +
+                       ntohs(mpa_frame->priv_data_len);
+
+       skb = get_free_pkt(cm_node);
+       if (!skb) {
+               nes_debug(NES_DBG_CM, "Failed to get a Free pkt\n");
+               return -1;
+       }
+
+       /* send an MPA Request frame */
+       form_cm_frame(skb, cm_node, NULL, 0, mpa_frame, mpa_frame_size, SET_ACK | SET_FIN);
+       ret = schedule_nes_timer(cm_node, skb, NES_TIMER_TYPE_SEND, 1, 0);
+
+       cm_node->state = NES_CM_STATE_CLOSED;
+       ret = send_fin(cm_node, NULL);
+
+       if (ret < 0) {
+               printk(KERN_INFO PFX "failed to send MPA Reply (reject)\n");
+               return ret;
+       }
+
+       return ret;
+}
+
+
+/**
+ * mini_cm_close
+ */
+int mini_cm_close(struct nes_cm_core *cm_core, struct nes_cm_node *cm_node)
+{
+       int ret = 0;
+
+       if (!cm_core || !cm_node)
+               return -EINVAL;
+
+       switch (cm_node->state) {
+               /* if passed in node is null, create a reference key node for node search */
+               /* check if we found an owner node for this pkt */
+               case NES_CM_STATE_SYN_RCVD:
+               case NES_CM_STATE_SYN_SENT:
+               case NES_CM_STATE_ONE_SIDE_ESTABLISHED:
+               case NES_CM_STATE_ESTABLISHED:
+               case NES_CM_STATE_ACCEPTING:
+               case NES_CM_STATE_MPAREQ_SENT:
+                       cm_node->state = NES_CM_STATE_FIN_WAIT1;
+                       send_fin(cm_node, NULL);
+                       break;
+               case NES_CM_STATE_CLOSE_WAIT:
+                       cm_node->state = NES_CM_STATE_LAST_ACK;
+                       send_fin(cm_node, NULL);
+                       break;
+               case NES_CM_STATE_FIN_WAIT1:
+               case NES_CM_STATE_FIN_WAIT2:
+               case NES_CM_STATE_LAST_ACK:
+               case NES_CM_STATE_TIME_WAIT:
+               case NES_CM_STATE_CLOSING:
+                       ret = -1;
+                       break;
+               case NES_CM_STATE_LISTENING:
+               case NES_CM_STATE_UNKNOWN:
+               case NES_CM_STATE_INITED:
+               case NES_CM_STATE_CLOSED:
+               case NES_CM_STATE_TSA:
+                       ret = rem_ref_cm_node(cm_core, cm_node);
+                       break;
+       }
+       cm_node->cm_id = NULL;
+       return ret;
+}
+
+
+/**
+ * recv_pkt - recv an ETHERNET packet, and process it through CM
+ * node state machine
+ */
+int mini_cm_recv_pkt(struct nes_cm_core *cm_core, struct nes_vnic *nesvnic,
+               struct sk_buff *skb)
+{
+       struct nes_cm_node *cm_node = NULL;
+       struct nes_cm_listener *listener = NULL;
+       struct iphdr *iph;
+       struct tcphdr *tcph;
+       struct nes_cm_info nfo;
+       int ret = 0;
+
+       if (!skb || skb->len < sizeof(struct iphdr) + sizeof(struct tcphdr)) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       iph = (struct iphdr *)skb->data;
+       tcph = (struct tcphdr *)(skb->data + sizeof(struct iphdr));
+       skb_reset_network_header(skb);
+       skb_set_transport_header(skb, sizeof(*tcph));
+       skb->len = ntohs(iph->tot_len);
+
+       nfo.loc_addr = ntohl(iph->daddr);
+       nfo.loc_port = ntohs(tcph->dest);
+       nfo.rem_addr = ntohl(iph->saddr);
+       nfo.rem_port = ntohs(tcph->source);
+
+       nes_debug(NES_DBG_CM, "Received packet: dest=0x%08X:0x%04X src=0x%08X:0x%04X\n",
+                       iph->daddr, tcph->dest, iph->saddr, tcph->source);
+
+       /* note: this call is going to increment cm_node ref count */
+       cm_node = find_node(cm_core,
+                       nfo.rem_port, nfo.rem_addr,
+                       nfo.loc_port, nfo.loc_addr);
+
+       if (!cm_node) {
+               listener = find_listener(cm_core, nfo.loc_addr, nfo.loc_port,
+                               NES_CM_LISTENER_ACTIVE_STATE);
+               if (listener) {
+                       nfo.cm_id = listener->cm_id;
+                       nfo.conn_type = listener->conn_type;
+               } else {
+                       nfo.cm_id = NULL;
+                       nfo.conn_type = 0;
+               }
+
+               cm_node = make_cm_node(cm_core, nesvnic, &nfo, listener);
+               if (!cm_node) {
+                       nes_debug(NES_DBG_CM, "Unable to allocate node\n");
+                       if (listener) {
+                               nes_debug(NES_DBG_CM, "unable to allocate node and decrementing listener refcount\n");
+                               atomic_dec(&listener->ref_count);
+                       }
+                       ret = -1;
+                       goto out;
+               }
+               if (!listener) {
+                       nes_debug(NES_DBG_CM, "Packet found for unknown port %x refcnt=%d\n",
+                                       nfo.loc_port, atomic_read(&cm_node->ref_count));
+                       if (!tcph->rst) {
+                               nes_debug(NES_DBG_CM, "Packet found for unknown port=%d"
+                                               " rem_port=%d refcnt=%d\n",
+                                               nfo.loc_port, nfo.rem_port, atomic_read(&cm_node->ref_count));
+
+                               cm_node->tcp_cntxt.rcv_nxt = ntohl(tcph->seq);
+                               cm_node->tcp_cntxt.loc_seq_num = ntohl(tcph->ack_seq);
+                               send_reset(cm_node);
+                       }
+                       rem_ref_cm_node(cm_core, cm_node);
+                       ret = -1;
+                       goto out;
+               }
+               add_ref_cm_node(cm_node);
+               cm_node->state = NES_CM_STATE_LISTENING;
+       }
+
+       nes_debug(NES_DBG_CM, "Processing Packet for node %p, data = (%p):\n",
+                       cm_node, skb->data);
+       process_packet(cm_node, skb, cm_core);
+
+       rem_ref_cm_node(cm_core, cm_node);
+       out:
+       if (skb)
+               dev_kfree_skb_any(skb);
+       return ret;
+}
+
+
+/**
+ * nes_cm_alloc_core - allocate a top level instance of a cm core
+ */
+struct nes_cm_core *nes_cm_alloc_core(void)
+{
+       int i;
+
+       struct nes_cm_core *cm_core;
+       struct sk_buff *skb = NULL;
+
+       /* setup the CM core */
+       /* alloc top level core control structure */
+       cm_core = kzalloc(sizeof(*cm_core), GFP_KERNEL);
+       if (!cm_core)
+               return NULL;
+
+       INIT_LIST_HEAD(&cm_core->connected_nodes);
+       init_timer(&cm_core->tcp_timer);
+       cm_core->tcp_timer.function = nes_cm_timer_tick;
+
+       cm_core->mtu   = NES_CM_DEFAULT_MTU;
+       cm_core->state = NES_CM_STATE_INITED;
+       cm_core->free_tx_pkt_max = NES_CM_DEFAULT_FREE_PKTS;
+
+       atomic_set(&cm_core->session_id, 0);
+       atomic_set(&cm_core->events_posted, 0);
+
+       /* init the packet lists */
+       skb_queue_head_init(&cm_core->tx_free_list);
+
+       for (i = 0; i < NES_CM_DEFAULT_FRAME_CNT; i++) {
+               skb = dev_alloc_skb(cm_core->mtu);
+               if (!skb) {
+                       kfree(cm_core);
+                       return NULL;
+               }
+               /* add 'raw' skb to free frame list */
+               skb_queue_head(&cm_core->tx_free_list, skb);
+       }
+
+       cm_core->api = &nes_cm_api;
+
+       spin_lock_init(&cm_core->ht_lock);
+       spin_lock_init(&cm_core->listen_list_lock);
+
+       INIT_LIST_HEAD(&cm_core->listen_list.list);
+
+       nes_debug(NES_DBG_CM, "Init CM Core completed -- cm_core=%p\n", cm_core);
+
+       nes_debug(NES_DBG_CM, "Enable QUEUE EVENTS\n");
+       cm_core->event_wq = create_singlethread_workqueue("nesewq");
+       cm_core->post_event = nes_cm_post_event;
+       nes_debug(NES_DBG_CM, "Enable QUEUE DISCONNECTS\n");
+       cm_core->disconn_wq = create_singlethread_workqueue("nesdwq");
+
+       print_core(cm_core);
+       return cm_core;
+}
+
+
+/**
+ * mini_cm_dealloc_core - deallocate a top level instance of a cm core
+ */
+int mini_cm_dealloc_core(struct nes_cm_core *cm_core)
+{
+       nes_debug(NES_DBG_CM, "De-Alloc CM Core (%p)\n", cm_core);
+
+       if (!cm_core)
+               return -EINVAL;
+
+       barrier();
+
+       if (timer_pending(&cm_core->tcp_timer)) {
+               del_timer(&cm_core->tcp_timer);
+       }
+
+       destroy_workqueue(cm_core->event_wq);
+       destroy_workqueue(cm_core->disconn_wq);
+       nes_debug(NES_DBG_CM, "\n");
+       kfree(cm_core);
+
+       return 0;
+}
+
+
+/**
+ * mini_cm_get
+ */
+int mini_cm_get(struct nes_cm_core *cm_core)
+{
+       return cm_core->state;
+}
+
+
+/**
+ * mini_cm_set
+ */
+int mini_cm_set(struct nes_cm_core *cm_core, u32 type, u32 value)
+{
+       int ret = 0;
+
+       switch (type) {
+               case NES_CM_SET_PKT_SIZE:
+                       cm_core->mtu = value;
+                       break;
+               case NES_CM_SET_FREE_PKT_Q_SIZE:
+                       cm_core->free_tx_pkt_max = value;
+                       break;
+               default:
+                       /* unknown set option */
+                       ret = -EINVAL;
+       }
+
+       return ret;
+}
+
+
+/**
+ * nes_cm_init_tsa_conn setup HW; MPA frames must be
+ * successfully exchanged when this is called
+ */
+static int nes_cm_init_tsa_conn(struct nes_qp *nesqp, struct nes_cm_node *cm_node)
+{
+       int ret = 0;
+
+       if (!nesqp)
+               return -EINVAL;
+
+       nesqp->nesqp_context->misc |= cpu_to_le32(NES_QPCONTEXT_MISC_IPV4 |
+                       NES_QPCONTEXT_MISC_NO_NAGLE | NES_QPCONTEXT_MISC_DO_NOT_FRAG |
+                       NES_QPCONTEXT_MISC_DROS);
+
+       if (cm_node->tcp_cntxt.snd_wscale || cm_node->tcp_cntxt.rcv_wscale)
+               nesqp->nesqp_context->misc |= cpu_to_le32(NES_QPCONTEXT_MISC_WSCALE);
+
+       nesqp->nesqp_context->misc2 |= cpu_to_le32(64 << NES_QPCONTEXT_MISC2_TTL_SHIFT);
+
+       nesqp->nesqp_context->mss |= cpu_to_le32(((u32)cm_node->tcp_cntxt.mss) << 16);
+
+       nesqp->nesqp_context->tcp_state_flow_label |= cpu_to_le32(
+                       (u32)NES_QPCONTEXT_TCPSTATE_EST << NES_QPCONTEXT_TCPFLOW_TCP_STATE_SHIFT);
+
+       nesqp->nesqp_context->pd_index_wscale |= cpu_to_le32(
+                       (cm_node->tcp_cntxt.snd_wscale << NES_QPCONTEXT_PDWSCALE_SND_WSCALE_SHIFT) &
+                       NES_QPCONTEXT_PDWSCALE_SND_WSCALE_MASK);
+
+       nesqp->nesqp_context->pd_index_wscale |= cpu_to_le32(
+                       (cm_node->tcp_cntxt.rcv_wscale << NES_QPCONTEXT_PDWSCALE_RCV_WSCALE_SHIFT) &
+                       NES_QPCONTEXT_PDWSCALE_RCV_WSCALE_MASK);
+
+       nesqp->nesqp_context->keepalive = cpu_to_le32(0x80);
+       nesqp->nesqp_context->ts_recent = 0;
+       nesqp->nesqp_context->ts_age = 0;
+       nesqp->nesqp_context->snd_nxt = cpu_to_le32(cm_node->tcp_cntxt.loc_seq_num);
+       nesqp->nesqp_context->snd_wnd = cpu_to_le32(cm_node->tcp_cntxt.snd_wnd);
+       nesqp->nesqp_context->rcv_nxt = cpu_to_le32(cm_node->tcp_cntxt.rcv_nxt);
+       nesqp->nesqp_context->rcv_wnd = cpu_to_le32(cm_node->tcp_cntxt.rcv_wnd <<
+                       cm_node->tcp_cntxt.rcv_wscale);
+       nesqp->nesqp_context->snd_max = cpu_to_le32(cm_node->tcp_cntxt.loc_seq_num);
+       nesqp->nesqp_context->snd_una = cpu_to_le32(cm_node->tcp_cntxt.loc_seq_num);
+       nesqp->nesqp_context->srtt = 0;
+       nesqp->nesqp_context->rttvar = cpu_to_le32(0x6);
+       nesqp->nesqp_context->ssthresh = cpu_to_le32(0x3FFFC000);
+       nesqp->nesqp_context->cwnd = cpu_to_le32(2*cm_node->tcp_cntxt.mss);
+       nesqp->nesqp_context->snd_wl1 = cpu_to_le32(cm_node->tcp_cntxt.rcv_nxt);
+       nesqp->nesqp_context->snd_wl2 = cpu_to_le32(cm_node->tcp_cntxt.loc_seq_num);
+       nesqp->nesqp_context->max_snd_wnd = cpu_to_le32(cm_node->tcp_cntxt.max_snd_wnd);
+
+       nes_debug(NES_DBG_CM, "QP%u: rcv_nxt = 0x%08X, snd_nxt = 0x%08X,"
+                       " Setting MSS to %u, PDWscale = 0x%08X, rcv_wnd = %u, context misc = 0x%08X.\n",
+                       nesqp->hwqp.qp_id, le32_to_cpu(nesqp->nesqp_context->rcv_nxt),
+                       le32_to_cpu(nesqp->nesqp_context->snd_nxt),
+                       cm_node->tcp_cntxt.mss, le32_to_cpu(nesqp->nesqp_context->pd_index_wscale),
+                       le32_to_cpu(nesqp->nesqp_context->rcv_wnd),
+                       le32_to_cpu(nesqp->nesqp_context->misc));
+       nes_debug(NES_DBG_CM, "  snd_wnd  = 0x%08X.\n", le32_to_cpu(nesqp->nesqp_context->snd_wnd));
+       nes_debug(NES_DBG_CM, "  snd_cwnd = 0x%08X.\n", le32_to_cpu(nesqp->nesqp_context->cwnd));
+       nes_debug(NES_DBG_CM, "  max_swnd = 0x%08X.\n", le32_to_cpu(nesqp->nesqp_context->max_snd_wnd));
+
+       nes_debug(NES_DBG_CM, "Change cm_node state to TSA\n");
+       cm_node->state = NES_CM_STATE_TSA;
+
+       return ret;
+}
+
+
+/**
+ * nes_cm_disconn
+ */
+int nes_cm_disconn(struct nes_qp *nesqp)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&nesqp->lock, flags);
+       if (nesqp->disconn_pending == 0) {
+               nesqp->disconn_pending++;
+               spin_unlock_irqrestore(&nesqp->lock, flags);
+               /* nes_add_ref(&nesqp->ibqp); */
+               /* init our disconnect work element, to */
+               INIT_WORK(&nesqp->disconn_work, nes_disconnect_worker);
+
+               queue_work(g_cm_core->disconn_wq, &nesqp->disconn_work);
+       } else {
+               spin_unlock_irqrestore(&nesqp->lock, flags);
+               nes_rem_ref(&nesqp->ibqp);
+       }
+
+       return 0;
+}
+
+
+/**
+ * nes_disconnect_worker
+ */
+void nes_disconnect_worker(struct work_struct *work)
+{
+       struct nes_qp *nesqp = container_of(work, struct nes_qp, disconn_work);
+
+       nes_debug(NES_DBG_CM, "processing AEQE id 0x%04X for QP%u.\n",
+                       nesqp->last_aeq, nesqp->hwqp.qp_id);
+       nes_cm_disconn_true(nesqp);
+}
+
+
+/**
+ * nes_cm_disconn_true
+ */
+int nes_cm_disconn_true(struct nes_qp *nesqp)
+{
+       unsigned long flags;
+       int ret = 0;
+       struct iw_cm_id *cm_id;
+       struct iw_cm_event cm_event;
+       struct nes_vnic *nesvnic;
+       u16 last_ae;
+       u8 original_hw_tcp_state;
+       u8 original_ibqp_state;
+       u8 issued_disconnect_reset = 0;
+
+       if (!nesqp) {
+               nes_debug(NES_DBG_CM, "disconnect_worker nesqp is NULL\n");
+               return -1;
+       }
+
+       spin_lock_irqsave(&nesqp->lock, flags);
+       cm_id = nesqp->cm_id;
+       /* make sure we havent already closed this connection */
+       if (!cm_id) {
+               nes_debug(NES_DBG_CM, "QP%u disconnect_worker cmid is NULL\n",
+                               nesqp->hwqp.qp_id);
+               spin_unlock_irqrestore(&nesqp->lock, flags);
+               nes_rem_ref(&nesqp->ibqp);
+               return -1;
+       }
+
+       nesvnic = to_nesvnic(nesqp->ibqp.device);
+       nes_debug(NES_DBG_CM, "Disconnecting QP%u\n", nesqp->hwqp.qp_id);
+
+       original_hw_tcp_state = nesqp->hw_tcp_state;
+       original_ibqp_state   = nesqp->ibqp_state;
+       last_ae = nesqp->last_aeq;
+
+
+       nes_debug(NES_DBG_CM, "set ibqp_state=%u\n", nesqp->ibqp_state);
+
+       if ((nesqp->cm_id) && (cm_id->event_handler)) {
+               if ((original_hw_tcp_state == NES_AEQE_TCP_STATE_CLOSE_WAIT) ||
+                               ((original_ibqp_state == IB_QPS_RTS) &&
+                               (last_ae == NES_AEQE_AEID_LLP_CONNECTION_RESET))) {
+                       atomic_inc(&cm_disconnects);
+                       cm_event.event = IW_CM_EVENT_DISCONNECT;
+                       if (last_ae == NES_AEQE_AEID_LLP_CONNECTION_RESET) {
+                               issued_disconnect_reset = 1;
+                               cm_event.status = IW_CM_EVENT_STATUS_RESET;
+                               nes_debug(NES_DBG_CM, "Generating a CM Disconnect Event (status reset) for "
+                                               " QP%u, cm_id = %p. \n",
+                                               nesqp->hwqp.qp_id, cm_id);
+                       } else {
+                               cm_event.status = IW_CM_EVENT_STATUS_OK;
+                       }
+
+                       cm_event.local_addr = cm_id->local_addr;
+                       cm_event.remote_addr = cm_id->remote_addr;
+                       cm_event.private_data = NULL;
+                       cm_event.private_data_len = 0;
+
+                       nes_debug(NES_DBG_CM, "Generating a CM Disconnect Event for "
+                                       " QP%u, SQ Head = %u, SQ Tail = %u. cm_id = %p, refcount = %u.\n",
+                                       nesqp->hwqp.qp_id,
+                                       nesqp->hwqp.sq_head, nesqp->hwqp.sq_tail, cm_id,
+                                       atomic_read(&nesqp->refcount));
+
+                       spin_unlock_irqrestore(&nesqp->lock, flags);
+                       ret = cm_id->event_handler(cm_id, &cm_event);
+                       if (ret)
+                               nes_debug(NES_DBG_CM, "OFA CM event_handler returned, ret=%d\n", ret);
+                       spin_lock_irqsave(&nesqp->lock, flags);
+               }
+
+               nesqp->disconn_pending = 0;
+               /* There might have been another AE while the lock was released */
+               original_hw_tcp_state = nesqp->hw_tcp_state;
+               original_ibqp_state   = nesqp->ibqp_state;
+               last_ae = nesqp->last_aeq;
+
+               if ((issued_disconnect_reset == 0) && (nesqp->cm_id) &&
+                               ((original_hw_tcp_state == NES_AEQE_TCP_STATE_CLOSED) ||
+                                (original_hw_tcp_state == NES_AEQE_TCP_STATE_TIME_WAIT) ||
+                                (last_ae == NES_AEQE_AEID_RDMAP_ROE_BAD_LLP_CLOSE) ||
+                                (last_ae == NES_AEQE_AEID_LLP_CONNECTION_RESET))) {
+                       atomic_inc(&cm_closes);
+                       nesqp->cm_id = NULL;
+                       nesqp->in_disconnect = 0;
+                       spin_unlock_irqrestore(&nesqp->lock, flags);
+                       nes_disconnect(nesqp, 1);
+
+                       cm_id->provider_data = nesqp;
+                       /* Send up the close complete event */
+                       cm_event.event = IW_CM_EVENT_CLOSE;
+                       cm_event.status = IW_CM_EVENT_STATUS_OK;
+                       cm_event.provider_data = cm_id->provider_data;
+                       cm_event.local_addr = cm_id->local_addr;
+                       cm_event.remote_addr = cm_id->remote_addr;
+                       cm_event.private_data = NULL;
+                       cm_event.private_data_len = 0;
+
+                       ret = cm_id->event_handler(cm_id, &cm_event);
+                       if (ret) {
+                               nes_debug(NES_DBG_CM, "OFA CM event_handler returned, ret=%d\n", ret);
+                       }
+
+                       cm_id->rem_ref(cm_id);
+
+                       spin_lock_irqsave(&nesqp->lock, flags);
+                       if (nesqp->flush_issued == 0) {
+                               nesqp->flush_issued = 1;
+                               spin_unlock_irqrestore(&nesqp->lock, flags);
+                               flush_wqes(nesvnic->nesdev, nesqp, NES_CQP_FLUSH_RQ, 1);
+                       } else {
+                               spin_unlock_irqrestore(&nesqp->lock, flags);
+                       }
+
+                       /* This reference is from either ModifyQP or the AE processing,
+                                       there is still a race here with modifyqp */
+                       nes_rem_ref(&nesqp->ibqp);
+
+               } else {
+                       cm_id = nesqp->cm_id;
+                       spin_unlock_irqrestore(&nesqp->lock, flags);
+                       /* check to see if the inbound reset beat the outbound reset */
+                       if ((!cm_id) && (last_ae==NES_AEQE_AEID_RESET_SENT)) {
+                               nes_debug(NES_DBG_CM, "QP%u: Decing refcount due to inbound reset"
+                                               " beating the outbound reset.\n",
+                                               nesqp->hwqp.qp_id);
+                               nes_rem_ref(&nesqp->ibqp);
+                       }
+               }
+       } else {
+               nesqp->disconn_pending = 0;
+               spin_unlock_irqrestore(&nesqp->lock, flags);
+       }
+       nes_rem_ref(&nesqp->ibqp);
+
+       return 0;
+}
+
+
+/**
+ * nes_disconnect
+ */
+int nes_disconnect(struct nes_qp *nesqp, int abrupt)
+{
+       int ret = 0;
+       struct nes_vnic *nesvnic;
+       struct nes_device *nesdev;
+
+       nesvnic = to_nesvnic(nesqp->ibqp.device);
+       if (!nesvnic)
+               return -EINVAL;
+
+       nesdev = nesvnic->nesdev;
+
+       nes_debug(NES_DBG_CM, "netdev refcnt = %u.\n",
+                       atomic_read(&nesvnic->netdev->refcnt));
+
+       if (nesqp->active_conn) {
+
+               /* indicate this connection is NOT active */
+               nesqp->active_conn = 0;
+       } else {
+               /* Need to free the Last Streaming Mode Message */
+               if (nesqp->ietf_frame) {
+                       pci_free_consistent(nesdev->pcidev,
+                                       nesqp->private_data_len+sizeof(struct ietf_mpa_frame),
+                                       nesqp->ietf_frame, nesqp->ietf_frame_pbase);
+               }
+       }
+
+       /* close the CM node down if it is still active */
+       if (nesqp->cm_node) {
+               nes_debug(NES_DBG_CM, "Call close API\n");
+
+               g_cm_core->api->close(g_cm_core, nesqp->cm_node);
+               nesqp->cm_node = NULL;
+       }
+
+       return ret;
+}
+
+
+/**
+ * nes_accept
+ */
+int nes_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
+{
+       u64 u64temp;
+       struct ib_qp *ibqp;
+       struct nes_qp *nesqp;
+       struct nes_vnic *nesvnic;
+       struct nes_device *nesdev;
+       struct nes_cm_node *cm_node;
+       struct nes_adapter *adapter;
+       struct ib_qp_attr attr;
+       struct iw_cm_event cm_event;
+       struct nes_hw_qp_wqe *wqe;
+       struct nes_v4_quad nes_quad;
+       int ret;
+
+       ibqp = nes_get_qp(cm_id->device, conn_param->qpn);
+       if (!ibqp)
+               return -EINVAL;
+
+       /* get all our handles */
+       nesqp = to_nesqp(ibqp);
+       nesvnic = to_nesvnic(nesqp->ibqp.device);
+       nesdev = nesvnic->nesdev;
+       adapter = nesdev->nesadapter;
+
+       nes_debug(NES_DBG_CM, "nesvnic=%p, netdev=%p, %s\n",
+                       nesvnic, nesvnic->netdev, nesvnic->netdev->name);
+
+       /* since this is from a listen, we were able to put node handle into cm_id */
+       cm_node = (struct nes_cm_node *)cm_id->provider_data;
+
+       /* associate the node with the QP */
+       nesqp->cm_node = (void *)cm_node;
+
+       nes_debug(NES_DBG_CM, "QP%u, cm_node=%p, jiffies = %lu\n",
+                       nesqp->hwqp.qp_id, cm_node, jiffies);
+       atomic_inc(&cm_accepts);
+
+       nes_debug(NES_DBG_CM, "netdev refcnt = %u.\n",
+                       atomic_read(&nesvnic->netdev->refcnt));
+
+               /* allocate the ietf frame and space for private data */
+               nesqp->ietf_frame = pci_alloc_consistent(nesdev->pcidev,
+                               sizeof(struct ietf_mpa_frame) + conn_param->private_data_len,
+                               &nesqp->ietf_frame_pbase);
+
+               if (!nesqp->ietf_frame) {
+                       nes_debug(NES_DBG_CM, "Unable to allocate memory for private data\n");
+                       return -ENOMEM;
+               }
+
+
+               /* setup the MPA frame */
+               nesqp->private_data_len = conn_param->private_data_len;
+               memcpy(nesqp->ietf_frame->key, IEFT_MPA_KEY_REP, IETF_MPA_KEY_SIZE);
+
+               memcpy(nesqp->ietf_frame->priv_data, conn_param->private_data,
+                               conn_param->private_data_len);
+
+               nesqp->ietf_frame->priv_data_len = cpu_to_be16(conn_param->private_data_len);
+               nesqp->ietf_frame->rev = mpa_version;
+               nesqp->ietf_frame->flags = IETF_MPA_FLAGS_CRC;
+
+               /* setup our first outgoing iWarp send WQE (the IETF frame response) */
+               wqe = &nesqp->hwqp.sq_vbase[0];
+
+               if (cm_id->remote_addr.sin_addr.s_addr != cm_id->local_addr.sin_addr.s_addr) {
+                       u64temp = (unsigned long)nesqp;
+                       u64temp |= NES_SW_CONTEXT_ALIGN>>1;
+                       set_wqe_64bit_value(wqe->wqe_words, NES_IWARP_SQ_WQE_COMP_CTX_LOW_IDX,
+                                           u64temp);
+                       wqe->wqe_words[NES_IWARP_SQ_WQE_MISC_IDX] =
+                                       cpu_to_le32(NES_IWARP_SQ_WQE_STREAMING | NES_IWARP_SQ_WQE_WRPDU);
+                       wqe->wqe_words[NES_IWARP_SQ_WQE_TOTAL_PAYLOAD_IDX] =
+                                       cpu_to_le32(conn_param->private_data_len + sizeof(struct ietf_mpa_frame));
+                       wqe->wqe_words[NES_IWARP_SQ_WQE_FRAG0_LOW_IDX] =
+                                       cpu_to_le32((u32)nesqp->ietf_frame_pbase);
+                       wqe->wqe_words[NES_IWARP_SQ_WQE_FRAG0_HIGH_IDX] =
+                                       cpu_to_le32((u32)((u64)nesqp->ietf_frame_pbase >> 32));
+                       wqe->wqe_words[NES_IWARP_SQ_WQE_LENGTH0_IDX] =
+                                       cpu_to_le32(conn_param->private_data_len + sizeof(struct ietf_mpa_frame));
+                       wqe->wqe_words[NES_IWARP_SQ_WQE_STAG0_IDX] = 0;
+
+                       nesqp->nesqp_context->ird_ord_sizes |= cpu_to_le32(
+                                       NES_QPCONTEXT_ORDIRD_LSMM_PRESENT | NES_QPCONTEXT_ORDIRD_WRPDU);
+               } else {
+                       nesqp->nesqp_context->ird_ord_sizes |= cpu_to_le32((NES_QPCONTEXT_ORDIRD_LSMM_PRESENT |
+                                       NES_QPCONTEXT_ORDIRD_WRPDU | NES_QPCONTEXT_ORDIRD_ALSMM));
+               }
+               nesqp->skip_lsmm = 1;
+
+
+       /* Cache the cm_id in the qp */
+       nesqp->cm_id = cm_id;
+       cm_node->cm_id = cm_id;
+
+       /*  nesqp->cm_node = (void *)cm_id->provider_data; */
+       cm_id->provider_data = nesqp;
+       nesqp->active_conn   = 0;
+
+       nes_cm_init_tsa_conn(nesqp, cm_node);
+
+       nesqp->nesqp_context->tcpPorts[0] = cpu_to_le16(ntohs(cm_id->local_addr.sin_port));
+       nesqp->nesqp_context->tcpPorts[1] = cpu_to_le16(ntohs(cm_id->remote_addr.sin_port));
+       nesqp->nesqp_context->ip0 = cpu_to_le32(ntohl(cm_id->remote_addr.sin_addr.s_addr));
+
+       nesqp->nesqp_context->misc2 |= cpu_to_le32(
+                       (u32)PCI_FUNC(nesdev->pcidev->devfn) << NES_QPCONTEXT_MISC2_SRC_IP_SHIFT);
+
+       nesqp->nesqp_context->arp_index_vlan |= cpu_to_le32(
+                       nes_arp_table(nesdev, le32_to_cpu(nesqp->nesqp_context->ip0), NULL,
+                       NES_ARP_RESOLVE) << 16);
+
+       nesqp->nesqp_context->ts_val_delta = cpu_to_le32(
+                       jiffies - nes_read_indexed(nesdev, NES_IDX_TCP_NOW));
+
+       nesqp->nesqp_context->ird_index = cpu_to_le32(nesqp->hwqp.qp_id);
+
+       nesqp->nesqp_context->ird_ord_sizes |= cpu_to_le32(
+                       ((u32)1 << NES_QPCONTEXT_ORDIRD_IWARP_MODE_SHIFT));
+       nesqp->nesqp_context->ird_ord_sizes |= cpu_to_le32((u32)conn_param->ord);
+
+       memset(&nes_quad, 0, sizeof(nes_quad));
+       nes_quad.DstIpAdrIndex = cpu_to_le32((u32)PCI_FUNC(nesdev->pcidev->devfn) << 24);
+       nes_quad.SrcIpadr      = cm_id->remote_addr.sin_addr.s_addr;
+       nes_quad.TcpPorts[0]   = cm_id->remote_addr.sin_port;
+       nes_quad.TcpPorts[1]   = cm_id->local_addr.sin_port;
+
+       /* Produce hash key */
+       nesqp->hte_index = cpu_to_be32(
+                       crc32c(~0, (void *)&nes_quad, sizeof(nes_quad)) ^ 0xffffffff);
+       nes_debug(NES_DBG_CM, "HTE Index = 0x%08X, CRC = 0x%08X\n",
+                       nesqp->hte_index, nesqp->hte_index & adapter->hte_index_mask);
+
+       nesqp->hte_index &= adapter->hte_index_mask;
+       nesqp->nesqp_context->hte_index = cpu_to_le32(nesqp->hte_index);
+
+       cm_node->cm_core->api->accelerated(cm_node->cm_core, cm_node);
+
+       nes_debug(NES_DBG_CM, "QP%u, Destination IP = 0x%08X:0x%04X, local = 0x%08X:0x%04X,"
+                       " rcv_nxt=0x%08X, snd_nxt=0x%08X, mpa + private data length=%zu.\n",
+                       nesqp->hwqp.qp_id,
+                       ntohl(cm_id->remote_addr.sin_addr.s_addr),
+                       ntohs(cm_id->remote_addr.sin_port),
+                       ntohl(cm_id->local_addr.sin_addr.s_addr),
+                       ntohs(cm_id->local_addr.sin_port),
+                       le32_to_cpu(nesqp->nesqp_context->rcv_nxt),
+                       le32_to_cpu(nesqp->nesqp_context->snd_nxt),
+                       conn_param->private_data_len+sizeof(struct ietf_mpa_frame));
+
+       attr.qp_state = IB_QPS_RTS;
+       nes_modify_qp(&nesqp->ibqp, &attr, IB_QP_STATE, NULL);
+
+       /* notify OF layer that accept event was successfull */
+       cm_id->add_ref(cm_id);
+
+       cm_event.event = IW_CM_EVENT_ESTABLISHED;
+       cm_event.status = IW_CM_EVENT_STATUS_ACCEPTED;
+       cm_event.provider_data = (void *)nesqp;
+       cm_event.local_addr = cm_id->local_addr;
+       cm_event.remote_addr = cm_id->remote_addr;
+       cm_event.private_data = NULL;
+       cm_event.private_data_len = 0;
+       ret = cm_id->event_handler(cm_id, &cm_event);
+       if (cm_node->loopbackpartner) {
+               cm_node->loopbackpartner->mpa_frame_size = nesqp->private_data_len;
+               /* copy entire MPA frame to our cm_node's frame */
+               memcpy(cm_node->loopbackpartner->mpa_frame_buf, nesqp->ietf_frame->priv_data,
+                          nesqp->private_data_len);
+               create_event(cm_node->loopbackpartner, NES_CM_EVENT_CONNECTED);
+       }
+       if (ret)
+               printk("%s[%u] OFA CM event_handler returned, ret=%d\n",
+                               __FUNCTION__, __LINE__, ret);
+
+       return 0;
+}
+
+
+/**
+ * nes_reject
+ */
+int nes_reject(struct iw_cm_id *cm_id, const void *pdata, u8 pdata_len)
+{
+       struct nes_cm_node *cm_node;
+       struct nes_cm_core *cm_core;
+
+       atomic_inc(&cm_rejects);
+       cm_node = (struct nes_cm_node *) cm_id->provider_data;
+       cm_core = cm_node->cm_core;
+       cm_node->mpa_frame_size = sizeof(struct ietf_mpa_frame) + pdata_len;
+
+       strcpy(&cm_node->mpa_frame.key[0], IEFT_MPA_KEY_REP);
+       memcpy(&cm_node->mpa_frame.priv_data, pdata, pdata_len);
+
+       cm_node->mpa_frame.priv_data_len = cpu_to_be16(pdata_len);
+       cm_node->mpa_frame.rev = mpa_version;
+       cm_node->mpa_frame.flags = IETF_MPA_FLAGS_CRC | IETF_MPA_FLAGS_REJECT;
+
+       cm_core->api->reject(cm_core, &cm_node->mpa_frame, cm_node);
+
+       return 0;
+}
+
+
+/**
+ * nes_connect
+ * setup and launch cm connect node
+ */
+int nes_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
+{
+       struct ib_qp *ibqp;
+       struct nes_qp *nesqp;
+       struct nes_vnic *nesvnic;
+       struct nes_device *nesdev;
+       struct nes_cm_node *cm_node;
+       struct nes_cm_info cm_info;
+
+       ibqp = nes_get_qp(cm_id->device, conn_param->qpn);
+       if (!ibqp)
+               return -EINVAL;
+       nesqp = to_nesqp(ibqp);
+       if (!nesqp)
+               return -EINVAL;
+       nesvnic = to_nesvnic(nesqp->ibqp.device);
+       if (!nesvnic)
+               return -EINVAL;
+       nesdev  = nesvnic->nesdev;
+       if (!nesdev)
+               return -EINVAL;
+
+       atomic_inc(&cm_connects);
+
+       nesqp->ietf_frame = kzalloc(sizeof(struct ietf_mpa_frame) +
+                       conn_param->private_data_len, GFP_KERNEL);
+       if (!nesqp->ietf_frame)
+               return -ENOMEM;
+
+       /* set qp as having an active connection */
+       nesqp->active_conn = 1;
+
+       nes_debug(NES_DBG_CM, "QP%u, Destination IP = 0x%08X:0x%04X, local = 0x%08X:0x%04X.\n",
+                       nesqp->hwqp.qp_id,
+                       ntohl(cm_id->remote_addr.sin_addr.s_addr),
+                       ntohs(cm_id->remote_addr.sin_port),
+                       ntohl(cm_id->local_addr.sin_addr.s_addr),
+                       ntohs(cm_id->local_addr.sin_port));
+
+       /* cache the cm_id in the qp */
+       nesqp->cm_id = cm_id;
+
+       cm_id->provider_data = nesqp;
+
+       /* copy the private data */
+       if (conn_param->private_data_len) {
+               memcpy(nesqp->ietf_frame->priv_data, conn_param->private_data,
+                               conn_param->private_data_len);
+       }
+
+       nesqp->private_data_len = conn_param->private_data_len;
+       nesqp->nesqp_context->ird_ord_sizes |= cpu_to_le32((u32)conn_param->ord);
+       nes_debug(NES_DBG_CM, "requested ord = 0x%08X.\n", (u32)conn_param->ord);
+       nes_debug(NES_DBG_CM, "mpa private data len =%u\n", conn_param->private_data_len);
+
+       strcpy(&nesqp->ietf_frame->key[0], IEFT_MPA_KEY_REQ);
+       nesqp->ietf_frame->flags = IETF_MPA_FLAGS_CRC;
+       nesqp->ietf_frame->rev = IETF_MPA_VERSION;
+       nesqp->ietf_frame->priv_data_len = htons(conn_param->private_data_len);
+
+       if (cm_id->local_addr.sin_addr.s_addr != cm_id->remote_addr.sin_addr.s_addr)
+               nes_manage_apbvt(nesvnic, ntohs(cm_id->local_addr.sin_port),
+                               PCI_FUNC(nesdev->pcidev->devfn), NES_MANAGE_APBVT_ADD);
+
+       /* set up the connection params for the node */
+       cm_info.loc_addr = (cm_id->local_addr.sin_addr.s_addr);
+       cm_info.loc_port = (cm_id->local_addr.sin_port);
+       cm_info.rem_addr = (cm_id->remote_addr.sin_addr.s_addr);
+       cm_info.rem_port = (cm_id->remote_addr.sin_port);
+       cm_info.cm_id = cm_id;
+       cm_info.conn_type = NES_CM_IWARP_CONN_TYPE;
+
+       cm_id->add_ref(cm_id);
+       nes_add_ref(&nesqp->ibqp);
+
+       /* create a connect CM node connection */
+       cm_node = g_cm_core->api->connect(g_cm_core, nesvnic, nesqp->ietf_frame, &cm_info);
+       if (!cm_node) {
+               if (cm_id->local_addr.sin_addr.s_addr != cm_id->remote_addr.sin_addr.s_addr)
+                       nes_manage_apbvt(nesvnic, ntohs(cm_id->local_addr.sin_port),
+                                       PCI_FUNC(nesdev->pcidev->devfn), NES_MANAGE_APBVT_DEL);
+               nes_rem_ref(&nesqp->ibqp);
+               kfree(nesqp->ietf_frame);
+               nesqp->ietf_frame = NULL;
+               cm_id->rem_ref(cm_id);
+               return -ENOMEM;
+       }
+
+       cm_node->apbvt_set = 1;
+       nesqp->cm_node = cm_node;
+
+       return 0;
+}
+
+
+/**
+ * nes_create_listen
+ */
+int nes_create_listen(struct iw_cm_id *cm_id, int backlog)
+{
+       struct nes_vnic *nesvnic;
+       struct nes_cm_listener *cm_node;
+       struct nes_cm_info cm_info;
+       struct nes_adapter *adapter;
+       int err;
+
+
+       nes_debug(NES_DBG_CM, "cm_id = %p, local port = 0x%04X.\n",
+                       cm_id, ntohs(cm_id->local_addr.sin_port));
+
+       nesvnic = to_nesvnic(cm_id->device);
+       if (!nesvnic)
+               return -EINVAL;
+       adapter = nesvnic->nesdev->nesadapter;
+       nes_debug(NES_DBG_CM, "nesvnic=%p, netdev=%p, %s\n",
+                       nesvnic, nesvnic->netdev, nesvnic->netdev->name);
+
+       nes_debug(NES_DBG_CM, "nesvnic->local_ipaddr=0x%08x, sin_addr.s_addr=0x%08x\n",
+                       nesvnic->local_ipaddr, cm_id->local_addr.sin_addr.s_addr);
+
+       /* setup listen params in our api call struct */
+       cm_info.loc_addr = nesvnic->local_ipaddr;
+       cm_info.loc_port = cm_id->local_addr.sin_port;
+       cm_info.backlog = backlog;
+       cm_info.cm_id = cm_id;
+
+       cm_info.conn_type = NES_CM_IWARP_CONN_TYPE;
+
+
+       cm_node = g_cm_core->api->listen(g_cm_core, nesvnic, &cm_info);
+       if (!cm_node) {
+               printk("%s[%u] Error returned from listen API call\n",
+                               __FUNCTION__, __LINE__);
+               return -ENOMEM;
+       }
+
+       cm_id->provider_data = cm_node;
+
+       if (!cm_node->reused_node) {
+               err = nes_manage_apbvt(nesvnic, ntohs(cm_id->local_addr.sin_port),
+                               PCI_FUNC(nesvnic->nesdev->pcidev->devfn), NES_MANAGE_APBVT_ADD);
+               if (err) {
+                       printk("nes_manage_apbvt call returned %d.\n", err);
+                       g_cm_core->api->stop_listener(g_cm_core, (void *)cm_node);
+                       return err;
+               }
+               cm_listens_created++;
+       }
+
+       cm_id->add_ref(cm_id);
+       cm_id->provider_data = (void *)cm_node;
+
+
+       return 0;
+}
+
+
+/**
+ * nes_destroy_listen
+ */
+int nes_destroy_listen(struct iw_cm_id *cm_id)
+{
+       if (cm_id->provider_data)
+               g_cm_core->api->stop_listener(g_cm_core, cm_id->provider_data);
+       else
+               nes_debug(NES_DBG_CM, "cm_id->provider_data was NULL\n");
+
+       cm_id->rem_ref(cm_id);
+
+       return 0;
+}
+
+
+/**
+ * nes_cm_recv
+ */
+int nes_cm_recv(struct sk_buff *skb, struct net_device *netdevice)
+{
+       cm_packets_received++;
+       if ((g_cm_core) && (g_cm_core->api)) {
+               g_cm_core->api->recv_pkt(g_cm_core, netdev_priv(netdevice), skb);
+       } else {
+               nes_debug(NES_DBG_CM, "Unable to process packet for CM,"
+                               " cm is not setup properly.\n");
+       }
+
+       return 0;
+}
+
+
+/**
+ * nes_cm_start
+ * Start and init a cm core module
+ */
+int nes_cm_start(void)
+{
+       nes_debug(NES_DBG_CM, "\n");
+       /* create the primary CM core, pass this handle to subsequent core inits */
+       g_cm_core = nes_cm_alloc_core();
+       if (g_cm_core) {
+               return 0;
+       } else {
+               return -ENOMEM;
+       }
+}
+
+
+/**
+ * nes_cm_stop
+ * stop and dealloc all cm core instances
+ */
+int nes_cm_stop(void)
+{
+       g_cm_core->api->destroy_cm_core(g_cm_core);
+       return 0;
+}
+
+
+/**
+ * cm_event_connected
+ * handle a connected event, setup QPs and HW
+ */
+void cm_event_connected(struct nes_cm_event *event)
+{
+       u64 u64temp;
+       struct nes_qp *nesqp;
+       struct nes_vnic *nesvnic;
+       struct nes_device *nesdev;
+       struct nes_cm_node *cm_node;
+       struct nes_adapter *nesadapter;
+       struct ib_qp_attr attr;
+       struct iw_cm_id *cm_id;
+       struct iw_cm_event cm_event;
+       struct nes_hw_qp_wqe *wqe;
+       struct nes_v4_quad nes_quad;
+       int ret;
+
+       /* get all our handles */
+       cm_node = event->cm_node;
+       cm_id = cm_node->cm_id;
+       nes_debug(NES_DBG_CM, "cm_event_connected - %p - cm_id = %p\n", cm_node, cm_id);
+       nesqp = (struct nes_qp *)cm_id->provider_data;
+       nesvnic = to_nesvnic(nesqp->ibqp.device);
+       nesdev = nesvnic->nesdev;
+       nesadapter = nesdev->nesadapter;
+
+       if (nesqp->destroyed) {
+               return;
+       }
+       atomic_inc(&cm_connecteds);
+       nes_debug(NES_DBG_CM, "QP%u attempting to connect to  0x%08X:0x%04X on"
+                       " local port 0x%04X. jiffies = %lu.\n",
+                       nesqp->hwqp.qp_id,
+                       ntohl(cm_id->remote_addr.sin_addr.s_addr),
+                       ntohs(cm_id->remote_addr.sin_port),
+                       ntohs(cm_id->local_addr.sin_port),
+                       jiffies);
+
+       nes_cm_init_tsa_conn(nesqp, cm_node);
+
+       /* set the QP tsa context */
+       nesqp->nesqp_context->tcpPorts[0] = cpu_to_le16(ntohs(cm_id->local_addr.sin_port));
+       nesqp->nesqp_context->tcpPorts[1] = cpu_to_le16(ntohs(cm_id->remote_addr.sin_port));
+       nesqp->nesqp_context->ip0 = cpu_to_le32(ntohl(cm_id->remote_addr.sin_addr.s_addr));
+
+       nesqp->nesqp_context->misc2 |= cpu_to_le32(
+                       (u32)PCI_FUNC(nesdev->pcidev->devfn) << NES_QPCONTEXT_MISC2_SRC_IP_SHIFT);
+       nesqp->nesqp_context->arp_index_vlan |= cpu_to_le32(
+                       nes_arp_table(nesdev, le32_to_cpu(nesqp->nesqp_context->ip0),
+                       NULL, NES_ARP_RESOLVE) << 16);
+       nesqp->nesqp_context->ts_val_delta = cpu_to_le32(
+                       jiffies - nes_read_indexed(nesdev, NES_IDX_TCP_NOW));
+       nesqp->nesqp_context->ird_index = cpu_to_le32(nesqp->hwqp.qp_id);
+       nesqp->nesqp_context->ird_ord_sizes |=
+                       cpu_to_le32((u32)1 << NES_QPCONTEXT_ORDIRD_IWARP_MODE_SHIFT);
+
+       /* Adjust tail for not having a LSMM */
+       nesqp->hwqp.sq_tail = 1;
+
+#if defined(NES_SEND_FIRST_WRITE)
+               if (cm_node->send_write0) {
+                       nes_debug(NES_DBG_CM, "Sending first write.\n");
+                       wqe = &nesqp->hwqp.sq_vbase[0];
+                       u64temp = (unsigned long)nesqp;
+                       u64temp |= NES_SW_CONTEXT_ALIGN>>1;
+                       set_wqe_64bit_value(wqe->wqe_words, NES_IWARP_SQ_WQE_COMP_CTX_LOW_IDX,
+                                           u64temp);
+                       wqe->wqe_words[NES_IWARP_SQ_WQE_MISC_IDX] = cpu_to_le32(NES_IWARP_SQ_OP_RDMAW);
+                       wqe->wqe_words[NES_IWARP_SQ_WQE_TOTAL_PAYLOAD_IDX] = 0;
+                       wqe->wqe_words[NES_IWARP_SQ_WQE_FRAG0_LOW_IDX] = 0;
+                       wqe->wqe_words[NES_IWARP_SQ_WQE_FRAG0_HIGH_IDX] = 0;
+                       wqe->wqe_words[NES_IWARP_SQ_WQE_LENGTH0_IDX] = 0;
+                       wqe->wqe_words[NES_IWARP_SQ_WQE_STAG0_IDX] = 0;
+
+                       /* use the reserved spot on the WQ for the extra first WQE */
+                       nesqp->nesqp_context->ird_ord_sizes &= cpu_to_le32(~(NES_QPCONTEXT_ORDIRD_LSMM_PRESENT |
+                                       NES_QPCONTEXT_ORDIRD_WRPDU | NES_QPCONTEXT_ORDIRD_ALSMM));
+                       nesqp->skip_lsmm = 1;
+                       nesqp->hwqp.sq_tail = 0;
+                       nes_write32(nesdev->regs + NES_WQE_ALLOC,
+                                       (1 << 24) | 0x00800000 | nesqp->hwqp.qp_id);
+               }
+#endif
+
+       memset(&nes_quad, 0, sizeof(nes_quad));
+
+       nes_quad.DstIpAdrIndex = cpu_to_le32((u32)PCI_FUNC(nesdev->pcidev->devfn) << 24);
+       nes_quad.SrcIpadr = cm_id->remote_addr.sin_addr.s_addr;
+       nes_quad.TcpPorts[0] = cm_id->remote_addr.sin_port;
+       nes_quad.TcpPorts[1] = cm_id->local_addr.sin_port;
+
+       /* Produce hash key */
+       nesqp->hte_index = cpu_to_be32(
+                       crc32c(~0, (void *)&nes_quad, sizeof(nes_quad)) ^ 0xffffffff);
+       nes_debug(NES_DBG_CM, "HTE Index = 0x%08X, After CRC = 0x%08X\n",
+                       nesqp->hte_index, nesqp->hte_index & nesadapter->hte_index_mask);
+
+       nesqp->hte_index &= nesadapter->hte_index_mask;
+       nesqp->nesqp_context->hte_index = cpu_to_le32(nesqp->hte_index);
+
+       nesqp->ietf_frame = &cm_node->mpa_frame;
+       nesqp->private_data_len = (u8) cm_node->mpa_frame_size;
+       cm_node->cm_core->api->accelerated(cm_node->cm_core, cm_node);
+
+       /* modify QP state to rts */
+       attr.qp_state = IB_QPS_RTS;
+       nes_modify_qp(&nesqp->ibqp, &attr, IB_QP_STATE, NULL);
+
+       /* notify OF layer we successfully created the requested connection */
+       cm_event.event = IW_CM_EVENT_CONNECT_REPLY;
+       cm_event.status = IW_CM_EVENT_STATUS_ACCEPTED;
+       cm_event.provider_data = cm_id->provider_data;
+       cm_event.local_addr.sin_family = AF_INET;
+       cm_event.local_addr.sin_port = cm_id->local_addr.sin_port;
+       cm_event.remote_addr = cm_id->remote_addr;
+
+               cm_event.private_data = (void *)event->cm_node->mpa_frame_buf;
+               cm_event.private_data_len = (u8) event->cm_node->mpa_frame_size;
+
+       cm_event.local_addr.sin_addr.s_addr = event->cm_info.rem_addr;
+       ret = cm_id->event_handler(cm_id, &cm_event);
+       nes_debug(NES_DBG_CM, "OFA CM event_handler returned, ret=%d\n", ret);
+
+       if (ret)
+               printk("%s[%u] OFA CM event_handler returned, ret=%d\n",
+                               __FUNCTION__, __LINE__, ret);
+       nes_debug(NES_DBG_CM, "Exiting connect thread for QP%u. jiffies = %lu\n",
+                       nesqp->hwqp.qp_id, jiffies );
+
+       nes_rem_ref(&nesqp->ibqp);
+
+       return;
+}
+
+
+/**
+ * cm_event_connect_error
+ */
+void cm_event_connect_error(struct nes_cm_event *event)
+{
+       struct nes_qp *nesqp;
+       struct iw_cm_id *cm_id;
+       struct iw_cm_event cm_event;
+       /* struct nes_cm_info cm_info; */
+       int ret;
+
+       if (!event->cm_node)
+               return;
+
+       cm_id = event->cm_node->cm_id;
+       if (!cm_id) {
+               return;
+       }
+
+       nes_debug(NES_DBG_CM, "cm_node=%p, cm_id=%p\n", event->cm_node, cm_id);
+       nesqp = cm_id->provider_data;
+
+       if (!nesqp) {
+               return;
+       }
+
+       /* notify OF layer about this connection error event */
+       /* cm_id->rem_ref(cm_id); */
+       nesqp->cm_id = NULL;
+       cm_id->provider_data = NULL;
+       cm_event.event = IW_CM_EVENT_CONNECT_REPLY;
+       cm_event.status = IW_CM_EVENT_STATUS_REJECTED;
+       cm_event.provider_data = cm_id->provider_data;
+       cm_event.local_addr = cm_id->local_addr;
+       cm_event.remote_addr = cm_id->remote_addr;
+       cm_event.private_data = NULL;
+       cm_event.private_data_len = 0;
+
+       nes_debug(NES_DBG_CM, "call CM_EVENT REJECTED, local_addr=%08x, remove_addr=%08x\n",
+                       cm_event.local_addr.sin_addr.s_addr, cm_event.remote_addr.sin_addr.s_addr);
+
+       ret = cm_id->event_handler(cm_id, &cm_event);
+       nes_debug(NES_DBG_CM, "OFA CM event_handler returned, ret=%d\n", ret);
+       if (ret)
+               printk("%s[%u] OFA CM event_handler returned, ret=%d\n",
+                               __FUNCTION__, __LINE__, ret);
+       nes_rem_ref(&nesqp->ibqp);
+               cm_id->rem_ref(cm_id);
+
+       return;
+}
+
+
+/**
+ * cm_event_reset
+ */
+void cm_event_reset(struct nes_cm_event *event)
+{
+       struct nes_qp *nesqp;
+       struct iw_cm_id *cm_id;
+       struct iw_cm_event cm_event;
+       /* struct nes_cm_info cm_info; */
+       int ret;
+
+       if (!event->cm_node)
+               return;
+
+       if (!event->cm_node->cm_id)
+               return;
+
+       cm_id = event->cm_node->cm_id;
+
+       nes_debug(NES_DBG_CM, "%p - cm_id = %p\n", event->cm_node, cm_id);
+       nesqp = cm_id->provider_data;
+
+       nesqp->cm_id = NULL;
+       /* cm_id->provider_data = NULL; */
+       cm_event.event = IW_CM_EVENT_DISCONNECT;
+       cm_event.status = IW_CM_EVENT_STATUS_RESET;
+       cm_event.provider_data = cm_id->provider_data;
+       cm_event.local_addr = cm_id->local_addr;
+       cm_event.remote_addr = cm_id->remote_addr;
+       cm_event.private_data = NULL;
+       cm_event.private_data_len = 0;
+
+       ret = cm_id->event_handler(cm_id, &cm_event);
+       nes_debug(NES_DBG_CM, "OFA CM event_handler returned, ret=%d\n", ret);
+
+
+       /* notify OF layer about this connection error event */
+       cm_id->rem_ref(cm_id);
+
+       return;
+}
+
+
+/**
+ * cm_event_mpa_req
+ */
+void cm_event_mpa_req(struct nes_cm_event *event)
+{
+       struct iw_cm_id   *cm_id;
+       struct iw_cm_event cm_event;
+       int ret;
+       struct nes_cm_node *cm_node;
+
+       cm_node = event->cm_node;
+       if (!cm_node)
+               return;
+       cm_id = cm_node->cm_id;
+
+       atomic_inc(&cm_connect_reqs);
+       nes_debug(NES_DBG_CM, "cm_node = %p - cm_id = %p, jiffies = %lu\n",
+                       cm_node, cm_id, jiffies);
+
+       cm_event.event = IW_CM_EVENT_CONNECT_REQUEST;
+       cm_event.status = IW_CM_EVENT_STATUS_OK;
+       cm_event.provider_data = (void *)cm_node;
+
+       cm_event.local_addr.sin_family = AF_INET;
+       cm_event.local_addr.sin_port = htons(event->cm_info.loc_port);
+       cm_event.local_addr.sin_addr.s_addr = htonl(event->cm_info.loc_addr);
+
+       cm_event.remote_addr.sin_family = AF_INET;
+       cm_event.remote_addr.sin_port = htons(event->cm_info.rem_port);
+       cm_event.remote_addr.sin_addr.s_addr = htonl(event->cm_info.rem_addr);
+
+               cm_event.private_data                = cm_node->mpa_frame_buf;
+               cm_event.private_data_len            = (u8) cm_node->mpa_frame_size;
+
+       ret = cm_id->event_handler(cm_id, &cm_event);
+       if (ret)
+               printk("%s[%u] OFA CM event_handler returned, ret=%d\n",
+                               __FUNCTION__, __LINE__, ret);
+
+       return;
+}
+
+
+static void nes_cm_event_handler(struct work_struct *);
+
+/**
+ * nes_cm_post_event
+ * post an event to the cm event handler
+ */
+int nes_cm_post_event(struct nes_cm_event *event)
+{
+       atomic_inc(&event->cm_node->cm_core->events_posted);
+       add_ref_cm_node(event->cm_node);
+       event->cm_info.cm_id->add_ref(event->cm_info.cm_id);
+       INIT_WORK(&event->event_work, nes_cm_event_handler);
+       nes_debug(NES_DBG_CM, "queue_work, event=%p\n", event);
+
+       queue_work(event->cm_node->cm_core->event_wq, &event->event_work);
+
+       nes_debug(NES_DBG_CM, "Exit\n");
+       return 0;
+}
+
+
+/**
+ * nes_cm_event_handler
+ * worker function to handle cm events
+ * will free instance of nes_cm_event
+ */
+static void nes_cm_event_handler(struct work_struct *work)
+{
+       struct nes_cm_event *event = container_of(work, struct nes_cm_event, event_work);
+       struct nes_cm_core *cm_core;
+
+       if ((!event) || (!event->cm_node) || (!event->cm_node->cm_core)) {
+               return;
+       }
+       cm_core = event->cm_node->cm_core;
+       nes_debug(NES_DBG_CM, "event=%p, event->type=%u, events posted=%u\n",
+                       event, event->type, atomic_read(&cm_core->events_posted));
+
+       switch (event->type) {
+               case NES_CM_EVENT_MPA_REQ:
+                       cm_event_mpa_req(event);
+                       nes_debug(NES_DBG_CM, "CM Event: MPA REQUEST\n");
+                       break;
+               case NES_CM_EVENT_RESET:
+                       nes_debug(NES_DBG_CM, "CM Event: RESET\n");
+                       cm_event_reset(event);
+                       break;
+               case NES_CM_EVENT_CONNECTED:
+                       if ((!event->cm_node->cm_id) ||
+                               (event->cm_node->state != NES_CM_STATE_TSA)) {
+                               break;
+                       }
+                       cm_event_connected(event);
+                       nes_debug(NES_DBG_CM, "CM Event: CONNECTED\n");
+                       break;
+               case NES_CM_EVENT_ABORTED:
+                       if ((!event->cm_node->cm_id) || (event->cm_node->state == NES_CM_STATE_TSA)) {
+                               break;
+                       }
+                       cm_event_connect_error(event);
+                       nes_debug(NES_DBG_CM, "CM Event: ABORTED\n");
+                       break;
+               case NES_CM_EVENT_DROPPED_PKT:
+                       nes_debug(NES_DBG_CM, "CM Event: DROPPED PKT\n");
+                       break;
+               default:
+                       nes_debug(NES_DBG_CM, "CM Event: UNKNOWN EVENT TYPE\n");
+                       break;
+       }
+
+       atomic_dec(&cm_core->events_posted);
+       event->cm_info.cm_id->rem_ref(event->cm_info.cm_id);
+       rem_ref_cm_node(cm_core, event->cm_node);
+       kfree(event);
+
+       return;
+}
diff --git a/drivers/infiniband/hw/nes/nes_cm.h b/drivers/infiniband/hw/nes/nes_cm.h
new file mode 100644 (file)
index 0000000..a59f0a7
--- /dev/null
@@ -0,0 +1,433 @@
+/*
+ * Copyright (c) 2006 - 2008 NetEffect, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * 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.
+ *
+ */
+
+#ifndef NES_CM_H
+#define NES_CM_H
+
+#define QUEUE_EVENTS
+
+#define NES_MANAGE_APBVT_DEL 0
+#define NES_MANAGE_APBVT_ADD 1
+
+/* IETF MPA -- defines, enums, structs */
+#define IEFT_MPA_KEY_REQ  "MPA ID Req Frame"
+#define IEFT_MPA_KEY_REP  "MPA ID Rep Frame"
+#define IETF_MPA_KEY_SIZE 16
+#define IETF_MPA_VERSION  1
+
+enum ietf_mpa_flags {
+       IETF_MPA_FLAGS_MARKERS = 0x80,  /* receive Markers */
+       IETF_MPA_FLAGS_CRC     = 0x40,  /* receive Markers */
+       IETF_MPA_FLAGS_REJECT  = 0x20,  /* Reject */
+};
+
+struct ietf_mpa_frame {
+       u8 key[IETF_MPA_KEY_SIZE];
+       u8 flags;
+       u8 rev;
+       __be16 priv_data_len;
+       u8 priv_data[0];
+};
+
+#define ietf_mpa_req_resp_frame ietf_mpa_frame
+
+struct nes_v4_quad {
+       u32 rsvd0;
+       __le32 DstIpAdrIndex;   /* Only most significant 5 bits are valid */
+       __be32 SrcIpadr;
+       __be16 TcpPorts[2];             /* src is low, dest is high */
+};
+
+struct nes_cm_node;
+enum nes_timer_type {
+       NES_TIMER_TYPE_SEND,
+       NES_TIMER_TYPE_RECV,
+       NES_TIMER_NODE_CLEANUP,
+       NES_TIMER_TYPE_CLOSE,
+};
+
+#define MAX_NES_IFS 4
+
+#define SET_ACK 1
+#define SET_SYN 2
+#define SET_FIN 4
+#define SET_RST 8
+
+struct option_base {
+       u8 optionnum;
+       u8 length;
+};
+
+enum option_numbers {
+       OPTION_NUMBER_END,
+       OPTION_NUMBER_NONE,
+       OPTION_NUMBER_MSS,
+       OPTION_NUMBER_WINDOW_SCALE,
+       OPTION_NUMBER_SACK_PERM,
+       OPTION_NUMBER_SACK,
+       OPTION_NUMBER_WRITE0 = 0xbc
+};
+
+struct option_mss {
+       u8 optionnum;
+       u8 length;
+       __be16 mss;
+};
+
+struct option_windowscale {
+       u8 optionnum;
+       u8 length;
+       u8 shiftcount;
+};
+
+union all_known_options {
+       char as_end;
+       struct option_base as_base;
+       struct option_mss as_mss;
+       struct option_windowscale as_windowscale;
+};
+
+struct nes_timer_entry {
+       struct list_head list;
+       unsigned long timetosend;       /* jiffies */
+       struct sk_buff *skb;
+       u32 type;
+       u32 retrycount;
+       u32 retranscount;
+       u32 context;
+       u32 seq_num;
+       u32 send_retrans;
+       int close_when_complete;
+       struct net_device *netdev;
+};
+
+#define NES_DEFAULT_RETRYS  64
+#define NES_DEFAULT_RETRANS 8
+#ifdef CONFIG_INFINIBAND_NES_DEBUG
+#define NES_RETRY_TIMEOUT   (1000*HZ/1000)
+#else
+#define NES_RETRY_TIMEOUT   (3000*HZ/1000)
+#endif
+#define NES_SHORT_TIME      (10)
+#define NES_LONG_TIME       (2000*HZ/1000)
+
+#define NES_CM_HASHTABLE_SIZE         1024
+#define NES_CM_TCP_TIMER_INTERVAL     3000
+#define NES_CM_DEFAULT_MTU            1540
+#define NES_CM_DEFAULT_FRAME_CNT      10
+#define NES_CM_THREAD_STACK_SIZE      256
+#define NES_CM_DEFAULT_RCV_WND        64240    // before we know that window scaling is allowed
+#define NES_CM_DEFAULT_RCV_WND_SCALED 256960  // after we know that window scaling is allowed
+#define NES_CM_DEFAULT_RCV_WND_SCALE  2
+#define NES_CM_DEFAULT_FREE_PKTS      0x000A
+#define NES_CM_FREE_PKT_LO_WATERMARK  2
+
+#define NES_CM_DEFAULT_MSS   536
+
+#define NES_CM_DEF_SEQ       0x159bf75f
+#define NES_CM_DEF_LOCAL_ID  0x3b47
+
+#define NES_CM_DEF_SEQ2      0x18ed5740
+#define NES_CM_DEF_LOCAL_ID2 0xb807
+
+typedef u32 nes_addr_t;
+
+#define nes_cm_tsa_context nes_qp_context
+
+struct nes_qp;
+
+/* cm node transition states */
+enum nes_cm_node_state {
+       NES_CM_STATE_UNKNOWN,
+       NES_CM_STATE_INITED,
+       NES_CM_STATE_LISTENING,
+       NES_CM_STATE_SYN_RCVD,
+       NES_CM_STATE_SYN_SENT,
+       NES_CM_STATE_ONE_SIDE_ESTABLISHED,
+       NES_CM_STATE_ESTABLISHED,
+       NES_CM_STATE_ACCEPTING,
+       NES_CM_STATE_MPAREQ_SENT,
+       NES_CM_STATE_TSA,
+       NES_CM_STATE_FIN_WAIT1,
+       NES_CM_STATE_FIN_WAIT2,
+       NES_CM_STATE_CLOSE_WAIT,
+       NES_CM_STATE_TIME_WAIT,
+       NES_CM_STATE_LAST_ACK,
+       NES_CM_STATE_CLOSING,
+       NES_CM_STATE_CLOSED
+};
+
+/* type of nes connection */
+enum nes_cm_conn_type {
+       NES_CM_IWARP_CONN_TYPE,
+};
+
+/* CM context params */
+struct nes_cm_tcp_context {
+       u8  client;
+
+       u32 loc_seq_num;
+       u32 loc_ack_num;
+       u32 rem_ack_num;
+       u32 rcv_nxt;
+
+       u32 loc_id;
+       u32 rem_id;
+
+       u32 snd_wnd;
+       u32 max_snd_wnd;
+
+       u32 rcv_wnd;
+       u32 mss;
+       u8  snd_wscale;
+       u8  rcv_wscale;
+
+       struct nes_cm_tsa_context tsa_cntxt;
+       struct timeval            sent_ts;
+};
+
+
+enum nes_cm_listener_state {
+       NES_CM_LISTENER_PASSIVE_STATE=1,
+       NES_CM_LISTENER_ACTIVE_STATE=2,
+       NES_CM_LISTENER_EITHER_STATE=3
+};
+
+struct nes_cm_listener {
+       struct list_head           list;
+       u64                        session_id;
+       struct nes_cm_core         *cm_core;
+       u8                         loc_mac[ETH_ALEN];
+       nes_addr_t                 loc_addr;
+       u16                        loc_port;
+       struct iw_cm_id            *cm_id;
+       enum nes_cm_conn_type      conn_type;
+       atomic_t                   ref_count;
+       struct nes_vnic            *nesvnic;
+       atomic_t                   pend_accepts_cnt;
+       int                        backlog;
+       enum nes_cm_listener_state listener_state;
+       u32                        reused_node;
+};
+
+/* per connection node and node state information */
+struct nes_cm_node {
+       u64                       session_id;
+       u32                       hashkey;
+
+       nes_addr_t                loc_addr, rem_addr;
+       u16                       loc_port, rem_port;
+
+       u8                        loc_mac[ETH_ALEN];
+       u8                        rem_mac[ETH_ALEN];
+
+       enum nes_cm_node_state    state;
+       struct nes_cm_tcp_context tcp_cntxt;
+       struct nes_cm_core        *cm_core;
+       struct sk_buff_head       resend_list;
+       atomic_t                  ref_count;
+       struct net_device         *netdev;
+
+       struct nes_cm_node        *loopbackpartner;
+       struct list_head          retrans_list;
+       spinlock_t                retrans_list_lock;
+       struct list_head          recv_list;
+       spinlock_t                recv_list_lock;
+
+       int                       send_write0;
+       union {
+               struct ietf_mpa_frame mpa_frame;
+               u8                    mpa_frame_buf[NES_CM_DEFAULT_MTU];
+       };
+       u16                       mpa_frame_size;
+       struct iw_cm_id           *cm_id;
+       struct list_head          list;
+       int                       accelerated;
+       struct nes_cm_listener    *listener;
+       enum nes_cm_conn_type     conn_type;
+       struct nes_vnic           *nesvnic;
+       int                       apbvt_set;
+       int                       accept_pend;
+};
+
+/* structure for client or CM to fill when making CM api calls. */
+/*     - only need to set relevant data, based on op. */
+struct nes_cm_info {
+       union {
+               struct iw_cm_id   *cm_id;
+               struct net_device *netdev;
+       };
+
+       u16 loc_port;
+       u16 rem_port;
+       nes_addr_t loc_addr;
+       nes_addr_t rem_addr;
+
+       enum nes_cm_conn_type  conn_type;
+       int backlog;
+};
+
+/* CM event codes */
+enum  nes_cm_event_type {
+       NES_CM_EVENT_UNKNOWN,
+       NES_CM_EVENT_ESTABLISHED,
+       NES_CM_EVENT_MPA_REQ,
+       NES_CM_EVENT_MPA_CONNECT,
+       NES_CM_EVENT_MPA_ACCEPT,
+       NES_CM_EVENT_MPA_ESTABLISHED,
+       NES_CM_EVENT_CONNECTED,
+       NES_CM_EVENT_CLOSED,
+       NES_CM_EVENT_RESET,
+       NES_CM_EVENT_DROPPED_PKT,
+       NES_CM_EVENT_CLOSE_IMMED,
+       NES_CM_EVENT_CLOSE_HARD,
+       NES_CM_EVENT_CLOSE_CLEAN,
+       NES_CM_EVENT_ABORTED,
+       NES_CM_EVENT_SEND_FIRST
+};
+
+/* event to post to CM event handler */
+struct nes_cm_event {
+       enum nes_cm_event_type type;
+
+       struct nes_cm_info cm_info;
+       struct work_struct event_work;
+       struct nes_cm_node *cm_node;
+};
+
+struct nes_cm_core {
+       enum nes_cm_node_state  state;
+       atomic_t                session_id;
+
+       atomic_t                listen_node_cnt;
+       struct nes_cm_node      listen_list;
+       spinlock_t              listen_list_lock;
+
+       u32                     mtu;
+       u32                     free_tx_pkt_max;
+       u32                     rx_pkt_posted;
+       struct sk_buff_head     tx_free_list;
+       atomic_t                ht_node_cnt;
+       struct list_head        connected_nodes;
+       /* struct list_head hashtable[NES_CM_HASHTABLE_SIZE]; */
+       spinlock_t              ht_lock;
+
+       struct timer_list       tcp_timer;
+
+       struct nes_cm_ops       *api;
+
+       int (*post_event)(struct nes_cm_event *event);
+       atomic_t                events_posted;
+       struct workqueue_struct *event_wq;
+       struct workqueue_struct *disconn_wq;
+
+       atomic_t                node_cnt;
+       u64                     aborted_connects;
+       u32                     options;
+
+       struct nes_cm_node      *current_listen_node;
+};
+
+
+#define NES_CM_SET_PKT_SIZE        (1 << 1)
+#define NES_CM_SET_FREE_PKT_Q_SIZE (1 << 2)
+
+/* CM ops/API for client interface */
+struct nes_cm_ops {
+       int (*accelerated)(struct nes_cm_core *, struct nes_cm_node *);
+       struct nes_cm_listener * (*listen)(struct nes_cm_core *, struct nes_vnic *,
+                       struct nes_cm_info *);
+       int (*stop_listener)(struct nes_cm_core *, struct nes_cm_listener *);
+       struct nes_cm_node * (*connect)(struct nes_cm_core *,
+                       struct nes_vnic *, struct ietf_mpa_frame *,
+                       struct nes_cm_info *);
+       int (*close)(struct nes_cm_core *, struct nes_cm_node *);
+       int (*accept)(struct nes_cm_core *, struct ietf_mpa_frame *,
+                       struct nes_cm_node *);
+       int (*reject)(struct nes_cm_core *, struct ietf_mpa_frame *,
+                       struct nes_cm_node *);
+       int (*recv_pkt)(struct nes_cm_core *, struct nes_vnic *,
+                       struct sk_buff *);
+       int (*destroy_cm_core)(struct nes_cm_core *);
+       int (*get)(struct nes_cm_core *);
+       int (*set)(struct nes_cm_core *, u32, u32);
+};
+
+
+int send_mpa_request(struct nes_cm_node *);
+struct sk_buff *form_cm_frame(struct sk_buff *, struct nes_cm_node *,
+               void *, u32, void *, u32, u8);
+int schedule_nes_timer(struct nes_cm_node *, struct sk_buff *,
+               enum nes_timer_type, int, int);
+void nes_cm_timer_tick(unsigned long);
+int send_syn(struct nes_cm_node *, u32);
+int send_reset(struct nes_cm_node *);
+int send_ack(struct nes_cm_node *);
+int send_fin(struct nes_cm_node *, struct sk_buff *);
+struct sk_buff *get_free_pkt(struct nes_cm_node *);
+int process_packet(struct nes_cm_node *, struct sk_buff *, struct nes_cm_core *);
+
+struct nes_cm_node * mini_cm_connect(struct nes_cm_core *,
+               struct nes_vnic *, struct ietf_mpa_frame *, struct nes_cm_info *);
+int mini_cm_accept(struct nes_cm_core *, struct ietf_mpa_frame *, struct nes_cm_node *);
+int mini_cm_reject(struct nes_cm_core *, struct ietf_mpa_frame *, struct nes_cm_node *);
+int mini_cm_close(struct nes_cm_core *, struct nes_cm_node *);
+int mini_cm_recv_pkt(struct nes_cm_core *, struct nes_vnic *, struct sk_buff *);
+struct nes_cm_core *mini_cm_alloc_core(struct nes_cm_info *);
+int mini_cm_dealloc_core(struct nes_cm_core *);
+int mini_cm_get(struct nes_cm_core *);
+int mini_cm_set(struct nes_cm_core *, u32, u32);
+
+int nes_cm_disconn(struct nes_qp *);
+void nes_disconnect_worker(struct work_struct *);
+int nes_cm_disconn_true(struct nes_qp *);
+int nes_disconnect(struct nes_qp *, int);
+
+int nes_accept(struct iw_cm_id *, struct iw_cm_conn_param *);
+int nes_reject(struct iw_cm_id *, const void *, u8);
+int nes_connect(struct iw_cm_id *, struct iw_cm_conn_param *);
+int nes_create_listen(struct iw_cm_id *, int);
+int nes_destroy_listen(struct iw_cm_id *);
+
+int nes_cm_recv(struct sk_buff *, struct net_device *);
+int nes_cm_start(void);
+int nes_cm_stop(void);
+
+/* CM event handler functions */
+void cm_event_connected(struct nes_cm_event *);
+void cm_event_connect_error(struct nes_cm_event *);
+void cm_event_reset(struct nes_cm_event *);
+void cm_event_mpa_req(struct nes_cm_event *);
+int nes_cm_post_event(struct nes_cm_event *);
+
+#endif                 /* NES_CM_H */
diff --git a/drivers/infiniband/hw/nes/nes_context.h b/drivers/infiniband/hw/nes/nes_context.h
new file mode 100644 (file)
index 0000000..da9daba
--- /dev/null
@@ -0,0 +1,193 @@
+/*
+ * Copyright (c) 2006 - 2008 NetEffect, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * 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.
+ */
+
+#ifndef NES_CONTEXT_H
+#define NES_CONTEXT_H
+
+struct nes_qp_context {
+       __le32   misc;
+       __le32   cqs;
+       __le32   sq_addr_low;
+       __le32   sq_addr_high;
+       __le32   rq_addr_low;
+       __le32   rq_addr_high;
+       __le32   misc2;
+       __le16   tcpPorts[2];
+       __le32   ip0;
+       __le32   ip1;
+       __le32   ip2;
+       __le32   ip3;
+       __le32   mss;
+       __le32   arp_index_vlan;
+       __le32   tcp_state_flow_label;
+       __le32   pd_index_wscale;
+       __le32   keepalive;
+       u32   ts_recent;
+       u32   ts_age;
+       __le32   snd_nxt;
+       __le32   snd_wnd;
+       __le32   rcv_nxt;
+       __le32   rcv_wnd;
+       __le32   snd_max;
+       __le32   snd_una;
+       u32   srtt;
+       __le32   rttvar;
+       __le32   ssthresh;
+       __le32   cwnd;
+       __le32   snd_wl1;
+       __le32   snd_wl2;
+       __le32   max_snd_wnd;
+       __le32   ts_val_delta;
+       u32   retransmit;
+       u32   probe_cnt;
+       u32   hte_index;
+       __le32   q2_addr_low;
+       __le32   q2_addr_high;
+       __le32   ird_index;
+       u32   Rsvd3;
+       __le32   ird_ord_sizes;
+       u32   mrkr_offset;
+       __le32   aeq_token_low;
+       __le32   aeq_token_high;
+};
+
+/* QP Context Misc Field */
+
+#define NES_QPCONTEXT_MISC_IWARP_VER_MASK    0x00000003
+#define NES_QPCONTEXT_MISC_IWARP_VER_SHIFT   0
+#define NES_QPCONTEXT_MISC_EFB_SIZE_MASK     0x000000C0
+#define NES_QPCONTEXT_MISC_EFB_SIZE_SHIFT    6
+#define NES_QPCONTEXT_MISC_RQ_SIZE_MASK      0x00000300
+#define NES_QPCONTEXT_MISC_RQ_SIZE_SHIFT     8
+#define NES_QPCONTEXT_MISC_SQ_SIZE_MASK      0x00000c00
+#define NES_QPCONTEXT_MISC_SQ_SIZE_SHIFT     10
+#define NES_QPCONTEXT_MISC_PCI_FCN_MASK      0x00007000
+#define NES_QPCONTEXT_MISC_PCI_FCN_SHIFT     12
+#define NES_QPCONTEXT_MISC_DUP_ACKS_MASK     0x00070000
+#define NES_QPCONTEXT_MISC_DUP_ACKS_SHIFT    16
+
+enum nes_qp_context_misc_bits {
+       NES_QPCONTEXT_MISC_RX_WQE_SIZE         = 0x00000004,
+       NES_QPCONTEXT_MISC_IPV4                = 0x00000008,
+       NES_QPCONTEXT_MISC_DO_NOT_FRAG         = 0x00000010,
+       NES_QPCONTEXT_MISC_INSERT_VLAN         = 0x00000020,
+       NES_QPCONTEXT_MISC_DROS                = 0x00008000,
+       NES_QPCONTEXT_MISC_WSCALE              = 0x00080000,
+       NES_QPCONTEXT_MISC_KEEPALIVE           = 0x00100000,
+       NES_QPCONTEXT_MISC_TIMESTAMP           = 0x00200000,
+       NES_QPCONTEXT_MISC_SACK                = 0x00400000,
+       NES_QPCONTEXT_MISC_RDMA_WRITE_EN       = 0x00800000,
+       NES_QPCONTEXT_MISC_RDMA_READ_EN        = 0x01000000,
+       NES_QPCONTEXT_MISC_WBIND_EN            = 0x10000000,
+       NES_QPCONTEXT_MISC_FAST_REGISTER_EN    = 0x20000000,
+       NES_QPCONTEXT_MISC_PRIV_EN             = 0x40000000,
+       NES_QPCONTEXT_MISC_NO_NAGLE            = 0x80000000
+};
+
+enum nes_qp_acc_wq_sizes {
+       HCONTEXT_TSA_WQ_SIZE_4 = 0,
+       HCONTEXT_TSA_WQ_SIZE_32 = 1,
+       HCONTEXT_TSA_WQ_SIZE_128 = 2,
+       HCONTEXT_TSA_WQ_SIZE_512 = 3
+};
+
+/* QP Context Misc2 Fields */
+#define NES_QPCONTEXT_MISC2_TTL_MASK            0x000000ff
+#define NES_QPCONTEXT_MISC2_TTL_SHIFT           0
+#define NES_QPCONTEXT_MISC2_HOP_LIMIT_MASK      0x000000ff
+#define NES_QPCONTEXT_MISC2_HOP_LIMIT_SHIFT     0
+#define NES_QPCONTEXT_MISC2_LIMIT_MASK          0x00000300
+#define NES_QPCONTEXT_MISC2_LIMIT_SHIFT         8
+#define NES_QPCONTEXT_MISC2_NIC_INDEX_MASK      0x0000fc00
+#define NES_QPCONTEXT_MISC2_NIC_INDEX_SHIFT     10
+#define NES_QPCONTEXT_MISC2_SRC_IP_MASK         0x001f0000
+#define NES_QPCONTEXT_MISC2_SRC_IP_SHIFT        16
+#define NES_QPCONTEXT_MISC2_TOS_MASK            0xff000000
+#define NES_QPCONTEXT_MISC2_TOS_SHIFT           24
+#define NES_QPCONTEXT_MISC2_TRAFFIC_CLASS_MASK  0xff000000
+#define NES_QPCONTEXT_MISC2_TRAFFIC_CLASS_SHIFT 24
+
+/* QP Context Tcp State/Flow Label Fields */
+#define NES_QPCONTEXT_TCPFLOW_FLOW_LABEL_MASK   0x000fffff
+#define NES_QPCONTEXT_TCPFLOW_FLOW_LABEL_SHIFT  0
+#define NES_QPCONTEXT_TCPFLOW_TCP_STATE_MASK    0xf0000000
+#define NES_QPCONTEXT_TCPFLOW_TCP_STATE_SHIFT   28
+
+enum nes_qp_tcp_state {
+       NES_QPCONTEXT_TCPSTATE_CLOSED = 1,
+       NES_QPCONTEXT_TCPSTATE_EST = 5,
+       NES_QPCONTEXT_TCPSTATE_TIME_WAIT = 11,
+};
+
+/* QP Context PD Index/wscale Fields */
+#define NES_QPCONTEXT_PDWSCALE_RCV_WSCALE_MASK  0x0000000f
+#define NES_QPCONTEXT_PDWSCALE_RCV_WSCALE_SHIFT 0
+#define NES_QPCONTEXT_PDWSCALE_SND_WSCALE_MASK  0x00000f00
+#define NES_QPCONTEXT_PDWSCALE_SND_WSCALE_SHIFT 8
+#define NES_QPCONTEXT_PDWSCALE_PDINDEX_MASK     0xffff0000
+#define NES_QPCONTEXT_PDWSCALE_PDINDEX_SHIFT    16
+
+/* QP Context Keepalive Fields */
+#define NES_QPCONTEXT_KEEPALIVE_DELTA_MASK      0x0000ffff
+#define NES_QPCONTEXT_KEEPALIVE_DELTA_SHIFT     0
+#define NES_QPCONTEXT_KEEPALIVE_PROBE_CNT_MASK  0x00ff0000
+#define NES_QPCONTEXT_KEEPALIVE_PROBE_CNT_SHIFT 16
+#define NES_QPCONTEXT_KEEPALIVE_INTV_MASK       0xff000000
+#define NES_QPCONTEXT_KEEPALIVE_INTV_SHIFT      24
+
+/* QP Context ORD/IRD Fields */
+#define NES_QPCONTEXT_ORDIRD_ORDSIZE_MASK       0x0000007f
+#define NES_QPCONTEXT_ORDIRD_ORDSIZE_SHIFT      0
+#define NES_QPCONTEXT_ORDIRD_IRDSIZE_MASK       0x00030000
+#define NES_QPCONTEXT_ORDIRD_IRDSIZE_SHIFT      16
+#define NES_QPCONTEXT_ORDIRD_IWARP_MODE_MASK    0x30000000
+#define NES_QPCONTEXT_ORDIRD_IWARP_MODE_SHIFT   28
+
+enum nes_ord_ird_bits {
+       NES_QPCONTEXT_ORDIRD_WRPDU                   = 0x02000000,
+       NES_QPCONTEXT_ORDIRD_LSMM_PRESENT            = 0x04000000,
+       NES_QPCONTEXT_ORDIRD_ALSMM                   = 0x08000000,
+       NES_QPCONTEXT_ORDIRD_AAH                     = 0x40000000,
+       NES_QPCONTEXT_ORDIRD_RNMC                    = 0x80000000
+};
+
+enum nes_iwarp_qp_state {
+       NES_QPCONTEXT_IWARP_STATE_NONEXIST  = 0,
+       NES_QPCONTEXT_IWARP_STATE_IDLE      = 1,
+       NES_QPCONTEXT_IWARP_STATE_RTS       = 2,
+       NES_QPCONTEXT_IWARP_STATE_CLOSING   = 3,
+       NES_QPCONTEXT_IWARP_STATE_TERMINATE = 5,
+       NES_QPCONTEXT_IWARP_STATE_ERROR     = 6
+};
+
+
+#endif         /* NES_CONTEXT_H */
diff --git a/drivers/infiniband/hw/nes/nes_hw.c b/drivers/infiniband/hw/nes/nes_hw.c
new file mode 100644 (file)
index 0000000..7c4c0fb
--- /dev/null
@@ -0,0 +1,3080 @@
+/*
+ * Copyright (c) 2006 - 2008 NetEffect, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/if_vlan.h>
+
+#include "nes.h"
+
+u32 crit_err_count = 0;
+u32 int_mod_timer_init;
+u32 int_mod_cq_depth_256;
+u32 int_mod_cq_depth_128;
+u32 int_mod_cq_depth_32;
+u32 int_mod_cq_depth_24;
+u32 int_mod_cq_depth_16;
+u32 int_mod_cq_depth_4;
+u32 int_mod_cq_depth_1;
+
+#include "nes_cm.h"
+
+
+#ifdef CONFIG_INFINIBAND_NES_DEBUG
+static unsigned char *nes_iwarp_state_str[] = {
+       "Non-Existant",
+       "Idle",
+       "RTS",
+       "Closing",
+       "RSVD1",
+       "Terminate",
+       "Error",
+       "RSVD2",
+};
+
+static unsigned char *nes_tcp_state_str[] = {
+       "Non-Existant",
+       "Closed",
+       "Listen",
+       "SYN Sent",
+       "SYN Rcvd",
+       "Established",
+       "Close Wait",
+       "FIN Wait 1",
+       "Closing",
+       "Last Ack",
+       "FIN Wait 2",
+       "Time Wait",
+       "RSVD1",
+       "RSVD2",
+       "RSVD3",
+       "RSVD4",
+};
+#endif
+
+
+/**
+ * nes_nic_init_timer_defaults
+ */
+void  nes_nic_init_timer_defaults(struct nes_device *nesdev, u8 jumbomode)
+{
+       unsigned long flags;
+       struct nes_adapter *nesadapter = nesdev->nesadapter;
+       struct nes_hw_tune_timer *shared_timer = &nesadapter->tune_timer;
+
+       spin_lock_irqsave(&nesadapter->periodic_timer_lock, flags);
+
+       shared_timer->timer_in_use_min = NES_NIC_FAST_TIMER_LOW;
+       shared_timer->timer_in_use_max = NES_NIC_FAST_TIMER_HIGH;
+       if (jumbomode) {
+               shared_timer->threshold_low    = DEFAULT_JUMBO_NES_QL_LOW;
+               shared_timer->threshold_target = DEFAULT_JUMBO_NES_QL_TARGET;
+               shared_timer->threshold_high   = DEFAULT_JUMBO_NES_QL_HIGH;
+       } else {
+               shared_timer->threshold_low    = DEFAULT_NES_QL_LOW;
+               shared_timer->threshold_target = DEFAULT_NES_QL_TARGET;
+               shared_timer->threshold_high   = DEFAULT_NES_QL_HIGH;
+       }
+
+       /* todo use netdev->mtu to set thresholds */
+       spin_unlock_irqrestore(&nesadapter->periodic_timer_lock, flags);
+}
+
+
+/**
+ * nes_nic_init_timer
+ */
+static void  nes_nic_init_timer(struct nes_device *nesdev)
+{
+       unsigned long flags;
+       struct nes_adapter *nesadapter = nesdev->nesadapter;
+       struct nes_hw_tune_timer *shared_timer = &nesadapter->tune_timer;
+
+       spin_lock_irqsave(&nesadapter->periodic_timer_lock, flags);
+
+       if (shared_timer->timer_in_use_old == 0) {
+               nesdev->deepcq_count = 0;
+               shared_timer->timer_direction_upward = 0;
+               shared_timer->timer_direction_downward = 0;
+               shared_timer->timer_in_use = NES_NIC_FAST_TIMER;
+               shared_timer->timer_in_use_old = 0;
+
+       }
+       if (shared_timer->timer_in_use != shared_timer->timer_in_use_old) {
+               shared_timer->timer_in_use_old = shared_timer->timer_in_use;
+               nes_write32(nesdev->regs+NES_PERIODIC_CONTROL,
+                       0x80000000 | ((u32)(shared_timer->timer_in_use*8)));
+       }
+       /* todo use netdev->mtu to set thresholds */
+       spin_unlock_irqrestore(&nesadapter->periodic_timer_lock, flags);
+}
+
+
+/**
+ * nes_nic_tune_timer
+ */
+static void nes_nic_tune_timer(struct nes_device *nesdev)
+{
+       unsigned long flags;
+       struct nes_adapter *nesadapter = nesdev->nesadapter;
+       struct nes_hw_tune_timer *shared_timer = &nesadapter->tune_timer;
+       u16 cq_count = nesdev->currcq_count;
+
+       spin_lock_irqsave(&nesadapter->periodic_timer_lock, flags);
+
+       if (shared_timer->cq_count_old < cq_count) {
+               if (cq_count > shared_timer->threshold_low)
+                       shared_timer->cq_direction_downward=0;
+       }
+       if (shared_timer->cq_count_old >= cq_count)
+               shared_timer->cq_direction_downward++;
+       shared_timer->cq_count_old = cq_count;
+       if (shared_timer->cq_direction_downward > NES_NIC_CQ_DOWNWARD_TREND) {
+               if (cq_count <= shared_timer->threshold_low) {
+                       shared_timer->threshold_low = shared_timer->threshold_low/2;
+                       shared_timer->cq_direction_downward=0;
+                       nesdev->currcq_count = 0;
+                       spin_unlock_irqrestore(&nesadapter->periodic_timer_lock, flags);
+                       return;
+               }
+       }
+
+       if (cq_count > 1) {
+               nesdev->deepcq_count += cq_count;
+               if (cq_count <= shared_timer->threshold_low) {       /* increase timer gently */
+                       shared_timer->timer_direction_upward++;
+                       shared_timer->timer_direction_downward = 0;
+               } else if (cq_count <= shared_timer->threshold_target) { /* balanced */
+                       shared_timer->timer_direction_upward = 0;
+                       shared_timer->timer_direction_downward = 0;
+               } else if (cq_count <= shared_timer->threshold_high) {  /* decrease timer gently */
+                       shared_timer->timer_direction_downward++;
+                       shared_timer->timer_direction_upward = 0;
+               } else if (cq_count <= (shared_timer->threshold_high) * 2) {
+                       shared_timer->timer_in_use -= 2;
+                       shared_timer->timer_direction_upward = 0;
+                       shared_timer->timer_direction_downward++;
+               } else {
+                       shared_timer->timer_in_use -= 4;
+                       shared_timer->timer_direction_upward = 0;
+                       shared_timer->timer_direction_downward++;
+               }
+
+               if (shared_timer->timer_direction_upward > 3 ) {  /* using history */
+                       shared_timer->timer_in_use += 3;
+                       shared_timer->timer_direction_upward = 0;
+                       shared_timer->timer_direction_downward = 0;
+               }
+               if (shared_timer->timer_direction_downward > 5) { /* using history */
+                       shared_timer->timer_in_use -= 4 ;
+                       shared_timer->timer_direction_downward = 0;
+                       shared_timer->timer_direction_upward = 0;
+               }
+       }
+
+       /* boundary checking */
+       if (shared_timer->timer_in_use > NES_NIC_FAST_TIMER_HIGH)
+               shared_timer->timer_in_use = NES_NIC_FAST_TIMER_HIGH;
+       else if (shared_timer->timer_in_use < NES_NIC_FAST_TIMER_LOW) {
+               shared_timer->timer_in_use = NES_NIC_FAST_TIMER_LOW;
+       }
+
+       nesdev->currcq_count = 0;
+
+       spin_unlock_irqrestore(&nesadapter->periodic_timer_lock, flags);
+}
+
+
+/**
+ * nes_init_adapter - initialize adapter
+ */
+struct nes_adapter *nes_init_adapter(struct nes_device *nesdev, u8 hw_rev) {
+       struct nes_adapter *nesadapter = NULL;
+       unsigned long num_pds;
+       u32 u32temp;
+       u32 port_count;
+       u16 max_rq_wrs;
+       u16 max_sq_wrs;
+       u32 max_mr;
+       u32 max_256pbl;
+       u32 max_4kpbl;
+       u32 max_qp;
+       u32 max_irrq;
+       u32 max_cq;
+       u32 hte_index_mask;
+       u32 adapter_size;
+       u32 arp_table_size;
+       u16 vendor_id;
+       u8  OneG_Mode;
+       u8  func_index;
+
+       /* search the list of existing adapters */
+       list_for_each_entry(nesadapter, &nes_adapter_list, list) {
+               nes_debug(NES_DBG_INIT, "Searching Adapter list for PCI devfn = 0x%X,"
+                               " adapter PCI slot/bus = %u/%u, pci devices PCI slot/bus = %u/%u, .\n",
+                               nesdev->pcidev->devfn,
+                               PCI_SLOT(nesadapter->devfn),
+                               nesadapter->bus_number,
+                               PCI_SLOT(nesdev->pcidev->devfn),
+                               nesdev->pcidev->bus->number );
+               if ((PCI_SLOT(nesadapter->devfn) == PCI_SLOT(nesdev->pcidev->devfn)) &&
+                               (nesadapter->bus_number == nesdev->pcidev->bus->number)) {
+                       nesadapter->ref_count++;
+                       return nesadapter;
+               }
+       }
+
+       /* no adapter found */
+       num_pds = pci_resource_len(nesdev->pcidev, BAR_1) >> PAGE_SHIFT;
+       if ((hw_rev != NE020_REV) && (hw_rev != NE020_REV1)) {
+               nes_debug(NES_DBG_INIT, "NE020 driver detected unknown hardware revision 0x%x\n",
+                               hw_rev);
+               return NULL;
+       }
+
+       nes_debug(NES_DBG_INIT, "Determine Soft Reset, QP_control=0x%x, CPU0=0x%x, CPU1=0x%x, CPU2=0x%x\n",
+                       nes_read_indexed(nesdev, NES_IDX_QP_CONTROL + PCI_FUNC(nesdev->pcidev->devfn) * 8),
+                       nes_read_indexed(nesdev, NES_IDX_INT_CPU_STATUS),
+                       nes_read_indexed(nesdev, NES_IDX_INT_CPU_STATUS + 4),
+                       nes_read_indexed(nesdev, NES_IDX_INT_CPU_STATUS + 8));
+
+       nes_debug(NES_DBG_INIT, "Reset and init NE020\n");
+
+
+       if ((port_count = nes_reset_adapter_ne020(nesdev, &OneG_Mode)) == 0)
+               return NULL;
+       if (nes_init_serdes(nesdev, hw_rev, port_count, OneG_Mode))
+               return NULL;
+       nes_init_csr_ne020(nesdev, hw_rev, port_count);
+
+       max_qp = nes_read_indexed(nesdev, NES_IDX_QP_CTX_SIZE);
+       nes_debug(NES_DBG_INIT, "QP_CTX_SIZE=%u\n", max_qp);
+
+       u32temp = nes_read_indexed(nesdev, NES_IDX_QUAD_HASH_TABLE_SIZE);
+       if (max_qp > ((u32)1 << (u32temp & 0x001f))) {
+               nes_debug(NES_DBG_INIT, "Reducing Max QPs to %u due to hash table size = 0x%08X\n",
+                               max_qp, u32temp);
+               max_qp = (u32)1 << (u32temp & 0x001f);
+       }
+
+       hte_index_mask = ((u32)1 << ((u32temp & 0x001f)+1))-1;
+       nes_debug(NES_DBG_INIT, "Max QP = %u, hte_index_mask = 0x%08X.\n",
+                       max_qp, hte_index_mask);
+
+       u32temp = nes_read_indexed(nesdev, NES_IDX_IRRQ_COUNT);
+
+       max_irrq = 1 << (u32temp & 0x001f);
+
+       if (max_qp > max_irrq) {
+               max_qp = max_irrq;
+               nes_debug(NES_DBG_INIT, "Reducing Max QPs to %u due to Available Q1s.\n",
+                               max_qp);
+       }
+
+       /* there should be no reason to allocate more pds than qps */
+       if (num_pds > max_qp)
+               num_pds = max_qp;
+
+       u32temp = nes_read_indexed(nesdev, NES_IDX_MRT_SIZE);
+       max_mr = (u32)8192 << (u32temp & 0x7);
+
+       u32temp = nes_read_indexed(nesdev, NES_IDX_PBL_REGION_SIZE);
+       max_256pbl = (u32)1 << (u32temp & 0x0000001f);
+       max_4kpbl = (u32)1 << ((u32temp >> 16) & 0x0000001f);
+       max_cq = nes_read_indexed(nesdev, NES_IDX_CQ_CTX_SIZE);
+
+       u32temp = nes_read_indexed(nesdev, NES_IDX_ARP_CACHE_SIZE);
+       arp_table_size = 1 << u32temp;
+
+       adapter_size = (sizeof(struct nes_adapter) +
+                       (sizeof(unsigned long)-1)) & (~(sizeof(unsigned long)-1));
+       adapter_size += sizeof(unsigned long) * BITS_TO_LONGS(max_qp);
+       adapter_size += sizeof(unsigned long) * BITS_TO_LONGS(max_mr);
+       adapter_size += sizeof(unsigned long) * BITS_TO_LONGS(max_cq);
+       adapter_size += sizeof(unsigned long) * BITS_TO_LONGS(num_pds);
+       adapter_size += sizeof(unsigned long) * BITS_TO_LONGS(arp_table_size);
+       adapter_size += sizeof(struct nes_qp **) * max_qp;
+
+       /* allocate a new adapter struct */
+       nesadapter = kzalloc(adapter_size, GFP_KERNEL);
+       if (nesadapter == NULL) {
+               return NULL;
+       }
+
+       nes_debug(NES_DBG_INIT, "Allocating new nesadapter @ %p, size = %u (actual size = %u).\n",
+                       nesadapter, (u32)sizeof(struct nes_adapter), adapter_size);
+
+       /* populate the new nesadapter */
+       nesadapter->devfn = nesdev->pcidev->devfn;
+       nesadapter->bus_number = nesdev->pcidev->bus->number;
+       nesadapter->ref_count = 1;
+       nesadapter->timer_int_req = 0xffff0000;
+       nesadapter->OneG_Mode = OneG_Mode;
+       nesadapter->doorbell_start = nesdev->doorbell_region;
+
+       /* nesadapter->tick_delta = clk_divisor; */
+       nesadapter->hw_rev = hw_rev;
+       nesadapter->port_count = port_count;
+
+       nesadapter->max_qp = max_qp;
+       nesadapter->hte_index_mask = hte_index_mask;
+       nesadapter->max_irrq = max_irrq;
+       nesadapter->max_mr = max_mr;
+       nesadapter->max_256pbl = max_256pbl - 1;
+       nesadapter->max_4kpbl = max_4kpbl - 1;
+       nesadapter->max_cq = max_cq;
+       nesadapter->free_256pbl = max_256pbl - 1;
+       nesadapter->free_4kpbl = max_4kpbl - 1;
+       nesadapter->max_pd = num_pds;
+       nesadapter->arp_table_size = arp_table_size;
+
+       nesadapter->et_pkt_rate_low = NES_TIMER_ENABLE_LIMIT;
+       if (nes_drv_opt & NES_DRV_OPT_DISABLE_INT_MOD) {
+               nesadapter->et_use_adaptive_rx_coalesce = 0;
+               nesadapter->timer_int_limit = NES_TIMER_INT_LIMIT;
+               nesadapter->et_rx_coalesce_usecs_irq = interrupt_mod_interval;
+       } else {
+               nesadapter->et_use_adaptive_rx_coalesce = 1;
+               nesadapter->timer_int_limit = NES_TIMER_INT_LIMIT_DYNAMIC;
+               nesadapter->et_rx_coalesce_usecs_irq = 0;
+               printk(PFX "%s: Using Adaptive Interrupt Moderation\n", __FUNCTION__);
+       }
+       /* Setup and enable the periodic timer */
+       if (nesadapter->et_rx_coalesce_usecs_irq)
+               nes_write32(nesdev->regs+NES_PERIODIC_CONTROL, 0x80000000 |
+                               ((u32)(nesadapter->et_rx_coalesce_usecs_irq * 8)));
+       else
+               nes_write32(nesdev->regs+NES_PERIODIC_CONTROL, 0x00000000);
+
+       nesadapter->base_pd = 1;
+
+       nesadapter->device_cap_flags =
+                       IB_DEVICE_ZERO_STAG | IB_DEVICE_SEND_W_INV | IB_DEVICE_MEM_WINDOW;
+
+       nesadapter->allocated_qps = (unsigned long *)&(((unsigned char *)nesadapter)
+                       [(sizeof(struct nes_adapter)+(sizeof(unsigned long)-1))&(~(sizeof(unsigned long)-1))]);
+       nesadapter->allocated_cqs = &nesadapter->allocated_qps[BITS_TO_LONGS(max_qp)];
+       nesadapter->allocated_mrs = &nesadapter->allocated_cqs[BITS_TO_LONGS(max_cq)];
+       nesadapter->allocated_pds = &nesadapter->allocated_mrs[BITS_TO_LONGS(max_mr)];
+       nesadapter->allocated_arps = &nesadapter->allocated_pds[BITS_TO_LONGS(num_pds)];
+       nesadapter->qp_table = (struct nes_qp **)(&nesadapter->allocated_arps[BITS_TO_LONGS(arp_table_size)]);
+
+
+       /* mark the usual suspect QPs and CQs as in use */
+       for (u32temp = 0; u32temp < NES_FIRST_QPN; u32temp++) {
+               set_bit(u32temp, nesadapter->allocated_qps);
+               set_bit(u32temp, nesadapter->allocated_cqs);
+       }
+
+       for (u32temp = 0; u32temp < 20; u32temp++)
+               set_bit(u32temp, nesadapter->allocated_pds);
+       u32temp = nes_read_indexed(nesdev, NES_IDX_QP_MAX_CFG_SIZES);
+
+       max_rq_wrs = ((u32temp >> 8) & 3);
+       switch (max_rq_wrs) {
+               case 0:
+                       max_rq_wrs = 4;
+                       break;
+               case 1:
+                       max_rq_wrs = 16;
+                       break;
+               case 2:
+                       max_rq_wrs = 32;
+                       break;
+               case 3:
+                       max_rq_wrs = 512;
+                       break;
+       }
+
+       max_sq_wrs = (u32temp & 3);
+       switch (max_sq_wrs) {
+               case 0:
+                       max_sq_wrs = 4;
+                       break;
+               case 1:
+                       max_sq_wrs = 16;
+                       break;
+               case 2:
+                       max_sq_wrs = 32;
+                       break;
+               case 3:
+                       max_sq_wrs = 512;
+                       break;
+       }
+       nesadapter->max_qp_wr = min(max_rq_wrs, max_sq_wrs);
+       nesadapter->max_irrq_wr = (u32temp >> 16) & 3;
+
+       nesadapter->max_sge = 4;
+       nesadapter->max_cqe = 32767;
+
+       if (nes_read_eeprom_values(nesdev, nesadapter)) {
+               printk(KERN_ERR PFX "Unable to read EEPROM data.\n");
+               kfree(nesadapter);
+               return NULL;
+       }
+
+       u32temp = nes_read_indexed(nesdev, NES_IDX_TCP_TIMER_CONFIG);
+       nes_write_indexed(nesdev, NES_IDX_TCP_TIMER_CONFIG,
+                       (u32temp & 0xff000000) | (nesadapter->tcp_timer_core_clk_divisor & 0x00ffffff));
+
+       /* setup port configuration */
+       if (nesadapter->port_count == 1) {
+               u32temp = 0x00000000;
+               if (nes_drv_opt & NES_DRV_OPT_DUAL_LOGICAL_PORT)
+                       nes_write_indexed(nesdev, NES_IDX_TX_POOL_SIZE, 0x00000002);
+               else
+                       nes_write_indexed(nesdev, NES_IDX_TX_POOL_SIZE, 0x00000003);
+       } else {
+               if (nesadapter->port_count == 2)
+                       u32temp = 0x00000044;
+               else
+                       u32temp = 0x000000e4;
+               nes_write_indexed(nesdev, NES_IDX_TX_POOL_SIZE, 0x00000003);
+       }
+
+       nes_write_indexed(nesdev, NES_IDX_NIC_LOGPORT_TO_PHYPORT, u32temp);
+       nes_debug(NES_DBG_INIT, "Probe time, LOG2PHY=%u\n",
+                       nes_read_indexed(nesdev, NES_IDX_NIC_LOGPORT_TO_PHYPORT));
+
+       spin_lock_init(&nesadapter->resource_lock);
+       spin_lock_init(&nesadapter->phy_lock);
+       spin_lock_init(&nesadapter->pbl_lock);
+       spin_lock_init(&nesadapter->periodic_timer_lock);
+
+       INIT_LIST_HEAD(&nesadapter->nesvnic_list[0]);
+       INIT_LIST_HEAD(&nesadapter->nesvnic_list[1]);
+       INIT_LIST_HEAD(&nesadapter->nesvnic_list[2]);
+       INIT_LIST_HEAD(&nesadapter->nesvnic_list[3]);
+
+       if ((!nesadapter->OneG_Mode) && (nesadapter->port_count == 2)) {
+               u32 pcs_control_status0, pcs_control_status1;
+               u32 reset_value;
+               u32 i = 0;
+               u32 int_cnt = 0;
+               u32 ext_cnt = 0;
+               unsigned long flags;
+               u32 j = 0;
+
+               pcs_control_status0 = nes_read_indexed(nesdev,
+                       NES_IDX_PHY_PCS_CONTROL_STATUS0);
+               pcs_control_status1 = nes_read_indexed(nesdev,
+                       NES_IDX_PHY_PCS_CONTROL_STATUS0 + 0x200);
+
+               for (i = 0; i < NES_MAX_LINK_CHECK; i++) {
+                       pcs_control_status0 = nes_read_indexed(nesdev,
+                                       NES_IDX_PHY_PCS_CONTROL_STATUS0);
+                       pcs_control_status1 = nes_read_indexed(nesdev,
+                                       NES_IDX_PHY_PCS_CONTROL_STATUS0 + 0x200);
+                       if ((0x0F000100 == (pcs_control_status0 & 0x0F000100))
+                           || (0x0F000100 == (pcs_control_status1 & 0x0F000100)))
+                               int_cnt++;
+                       msleep(1);
+               }
+               if (int_cnt > 1) {
+                       spin_lock_irqsave(&nesadapter->phy_lock, flags);
+                       nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL1, 0x0000F088);
+                       mh_detected++;
+                       reset_value = nes_read32(nesdev->regs+NES_SOFTWARE_RESET);
+                       reset_value |= 0x0000003d;
+                       nes_write32(nesdev->regs+NES_SOFTWARE_RESET, reset_value);
+
+                       while (((nes_read32(nesdev->regs+NES_SOFTWARE_RESET)
+                               & 0x00000040) != 0x00000040) && (j++ < 5000));
+                       spin_unlock_irqrestore(&nesadapter->phy_lock, flags);
+
+                       pcs_control_status0 = nes_read_indexed(nesdev,
+                                       NES_IDX_PHY_PCS_CONTROL_STATUS0);
+                       pcs_control_status1 = nes_read_indexed(nesdev,
+                                       NES_IDX_PHY_PCS_CONTROL_STATUS0 + 0x200);
+
+                       for (i = 0; i < NES_MAX_LINK_CHECK; i++) {
+                               pcs_control_status0 = nes_read_indexed(nesdev,
+                                       NES_IDX_PHY_PCS_CONTROL_STATUS0);
+                               pcs_control_status1 = nes_read_indexed(nesdev,
+                                       NES_IDX_PHY_PCS_CONTROL_STATUS0 + 0x200);
+                               if ((0x0F000100 == (pcs_control_status0 & 0x0F000100))
+                                       || (0x0F000100 == (pcs_control_status1 & 0x0F000100))) {
+                                       if (++ext_cnt > int_cnt) {
+                                               spin_lock_irqsave(&nesadapter->phy_lock, flags);
+                                               nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL1,
+                                                               0x0000F0C8);
+                                               mh_detected++;
+                                               reset_value = nes_read32(nesdev->regs+NES_SOFTWARE_RESET);
+                                               reset_value |= 0x0000003d;
+                                               nes_write32(nesdev->regs+NES_SOFTWARE_RESET, reset_value);
+
+                                               while (((nes_read32(nesdev->regs+NES_SOFTWARE_RESET)
+                                                       & 0x00000040) != 0x00000040) && (j++ < 5000));
+                                               spin_unlock_irqrestore(&nesadapter->phy_lock, flags);
+                                               break;
+                                       }
+                               }
+                               msleep(1);
+                       }
+               }
+       }
+
+       if (nesadapter->hw_rev == NE020_REV) {
+               init_timer(&nesadapter->mh_timer);
+               nesadapter->mh_timer.function = nes_mh_fix;
+               nesadapter->mh_timer.expires = jiffies + (HZ/5);  /* 1 second */
+               nesadapter->mh_timer.data = (unsigned long)nesdev;
+               add_timer(&nesadapter->mh_timer);
+       } else {
+               nes_write32(nesdev->regs+NES_INTF_INT_STAT, 0x0f000000);
+       }
+
+       init_timer(&nesadapter->lc_timer);
+       nesadapter->lc_timer.function = nes_clc;
+       nesadapter->lc_timer.expires = jiffies + 3600 * HZ;  /* 1 hour */
+       nesadapter->lc_timer.data = (unsigned long)nesdev;
+       add_timer(&nesadapter->lc_timer);
+
+       list_add_tail(&nesadapter->list, &nes_adapter_list);
+
+       for (func_index = 0; func_index < 8; func_index++) {
+               pci_bus_read_config_word(nesdev->pcidev->bus,
+                                       PCI_DEVFN(PCI_SLOT(nesdev->pcidev->devfn),
+                                       func_index), 0, &vendor_id);
+               if (vendor_id == 0xffff)
+                       break;
+       }
+       nes_debug(NES_DBG_INIT, "%s %d functions found for %s.\n", __FUNCTION__,
+               func_index, pci_name(nesdev->pcidev));
+       nesadapter->adapter_fcn_count = func_index;
+
+       return nesadapter;
+}
+
+
+/**
+ * nes_reset_adapter_ne020
+ */
+unsigned int nes_reset_adapter_ne020(struct nes_device *nesdev, u8 *OneG_Mode)
+{
+       u32 port_count;
+       u32 u32temp;
+       u32 i;
+
+       u32temp = nes_read32(nesdev->regs+NES_SOFTWARE_RESET);
+       port_count = ((u32temp & 0x00000300) >> 8) + 1;
+       /* TODO: assuming that both SERDES are set the same for now */
+       *OneG_Mode = (u32temp & 0x00003c00) ? 0 : 1;
+       nes_debug(NES_DBG_INIT, "Initial Software Reset = 0x%08X, port_count=%u\n",
+                       u32temp, port_count);
+       if (*OneG_Mode)
+               nes_debug(NES_DBG_INIT, "Running in 1G mode.\n");
+       u32temp &= 0xff00ffc0;
+       switch (port_count) {
+               case 1:
+                       u32temp |= 0x00ee0000;
+                       break;
+               case 2:
+                       u32temp |= 0x00cc0000;
+                       break;
+               case 4:
+                       u32temp |= 0x00000000;
+                       break;
+               default:
+                       return 0;
+                       break;
+       }
+
+       /* check and do full reset if needed */
+       if (nes_read_indexed(nesdev, NES_IDX_QP_CONTROL+(PCI_FUNC(nesdev->pcidev->devfn)*8))) {
+               nes_debug(NES_DBG_INIT, "Issuing Full Soft reset = 0x%08X\n", u32temp | 0xd);
+               nes_write32(nesdev->regs+NES_SOFTWARE_RESET, u32temp | 0xd);
+
+               i = 0;
+               while (((nes_read32(nesdev->regs+NES_SOFTWARE_RESET) & 0x00000040) == 0) && i++ < 10000)
+                       mdelay(1);
+               if (i >= 10000) {
+                       nes_debug(NES_DBG_INIT, "Did not see full soft reset done.\n");
+                       return 0;
+               }
+       }
+
+       /* port reset */
+       switch (port_count) {
+               case 1:
+                       u32temp |= 0x00ee0010;
+                       break;
+               case 2:
+                       u32temp |= 0x00cc0030;
+                       break;
+               case 4:
+                       u32temp |= 0x00000030;
+                       break;
+       }
+
+       nes_debug(NES_DBG_INIT, "Issuing Port Soft reset = 0x%08X\n", u32temp | 0xd);
+       nes_write32(nesdev->regs+NES_SOFTWARE_RESET, u32temp | 0xd);
+
+       i = 0;
+       while (((nes_read32(nesdev->regs+NES_SOFTWARE_RESET) & 0x00000040) == 0) && i++ < 10000)
+               mdelay(1);
+       if (i >= 10000) {
+               nes_debug(NES_DBG_INIT, "Did not see port soft reset done.\n");
+               return 0;
+       }
+
+       /* serdes 0 */
+       i = 0;
+       while (((u32temp = (nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_STATUS0)
+                       & 0x0000000f)) != 0x0000000f) && i++ < 5000)
+               mdelay(1);
+       if (i >= 5000) {
+               nes_debug(NES_DBG_INIT, "Serdes 0 not ready, status=%x\n", u32temp);
+               return 0;
+       }
+
+       /* serdes 1 */
+       if (port_count > 1) {
+               i = 0;
+               while (((u32temp = (nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_STATUS1)
+                               & 0x0000000f)) != 0x0000000f) && i++ < 5000)
+                       mdelay(1);
+               if (i >= 5000) {
+                       nes_debug(NES_DBG_INIT, "Serdes 1 not ready, status=%x\n", u32temp);
+                       return 0;
+               }
+       }
+
+
+
+       i = 0;
+       while ((nes_read_indexed(nesdev, NES_IDX_INT_CPU_STATUS) != 0x80) && i++ < 10000)
+               mdelay(1);
+       if (i >= 10000) {
+               printk(KERN_ERR PFX "Internal CPU not ready, status = %02X\n",
+                               nes_read_indexed(nesdev, NES_IDX_INT_CPU_STATUS));
+               return 0;
+       }
+
+       return port_count;
+}
+
+
+/**
+ * nes_init_serdes
+ */
+int nes_init_serdes(struct nes_device *nesdev, u8 hw_rev, u8 port_count, u8  OneG_Mode)
+{
+       int i;
+       u32 u32temp;
+
+       if (hw_rev != NE020_REV) {
+               /* init serdes 0 */
+
+               nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_CDR_CONTROL0, 0x000000FF);
+               if (!OneG_Mode)
+                       nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_TX_HIGHZ_LANE_MODE0, 0x11110000);
+               if (port_count > 1) {
+                       /* init serdes 1 */
+                       nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_CDR_CONTROL1, 0x000000FF);
+                       if (!OneG_Mode)
+                               nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_TX_HIGHZ_LANE_MODE1, 0x11110000);
+                       }
+       } else {
+               /* init serdes 0 */
+               nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL0, 0x00000008);
+               i = 0;
+               while (((u32temp = (nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_STATUS0)
+                               & 0x0000000f)) != 0x0000000f) && i++ < 5000)
+                       mdelay(1);
+               if (i >= 5000) {
+                       nes_debug(NES_DBG_PHY, "Init: serdes 0 not ready, status=%x\n", u32temp);
+                       return 1;
+               }
+               nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_TX_EMP0, 0x000bdef7);
+               nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_TX_DRIVE0, 0x9ce73000);
+               nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_RX_MODE0, 0x0ff00000);
+               nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_RX_SIGDET0, 0x00000000);
+               nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_BYPASS0, 0x00000000);
+               nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_LOOPBACK_CONTROL0, 0x00000000);
+               if (OneG_Mode)
+                       nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_RX_EQ_CONTROL0, 0xf0182222);
+               else
+                       nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_RX_EQ_CONTROL0, 0xf0042222);
+
+               nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_CDR_CONTROL0, 0x000000ff);
+               if (port_count > 1) {
+                       /* init serdes 1 */
+                       nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL1, 0x00000048);
+                       i = 0;
+                       while (((u32temp = (nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_STATUS1)
+                               & 0x0000000f)) != 0x0000000f) && (i++ < 5000))
+                               mdelay(1);
+                       if (i >= 5000) {
+                               printk("%s: Init: serdes 1 not ready, status=%x\n", __FUNCTION__, u32temp);
+                               /* return 1; */
+                       }
+                       nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_TX_EMP1, 0x000bdef7);
+                       nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_TX_DRIVE1, 0x9ce73000);
+                       nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_RX_MODE1, 0x0ff00000);
+                       nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_RX_SIGDET1, 0x00000000);
+                       nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_BYPASS1, 0x00000000);
+                       nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_LOOPBACK_CONTROL1, 0x00000000);
+                       nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_RX_EQ_CONTROL1, 0xf0002222);
+                       nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_CDR_CONTROL1, 0x000000ff);
+               }
+       }
+       return 0;
+}
+
+
+/**
+ * nes_init_csr_ne020
+ * Initialize registers for ne020 hardware
+ */
+void nes_init_csr_ne020(struct nes_device *nesdev, u8 hw_rev, u8 port_count)
+{
+       u32 u32temp;
+
+       nes_debug(NES_DBG_INIT, "port_count=%d\n", port_count);
+
+       nes_write_indexed(nesdev, 0x000001E4, 0x00000007);
+       /* nes_write_indexed(nesdev, 0x000001E8, 0x000208C4); */
+       nes_write_indexed(nesdev, 0x000001E8, 0x00020874);
+       nes_write_indexed(nesdev, 0x000001D8, 0x00048002);
+       /* nes_write_indexed(nesdev, 0x000001D8, 0x0004B002); */
+       nes_write_indexed(nesdev, 0x000001FC, 0x00050005);
+       nes_write_indexed(nesdev, 0x00000600, 0x55555555);
+       nes_write_indexed(nesdev, 0x00000604, 0x55555555);
+
+       /* TODO: move these MAC register settings to NIC bringup */
+       nes_write_indexed(nesdev, 0x00002000, 0x00000001);
+       nes_write_indexed(nesdev, 0x00002004, 0x00000001);
+       nes_write_indexed(nesdev, 0x00002008, 0x0000FFFF);
+       nes_write_indexed(nesdev, 0x0000200C, 0x00000001);
+       nes_write_indexed(nesdev, 0x00002010, 0x000003c1);
+       nes_write_indexed(nesdev, 0x0000201C, 0x75345678);
+       if (port_count > 1) {
+               nes_write_indexed(nesdev, 0x00002200, 0x00000001);
+               nes_write_indexed(nesdev, 0x00002204, 0x00000001);
+               nes_write_indexed(nesdev, 0x00002208, 0x0000FFFF);
+               nes_write_indexed(nesdev, 0x0000220C, 0x00000001);
+               nes_write_indexed(nesdev, 0x00002210, 0x000003c1);
+               nes_write_indexed(nesdev, 0x0000221C, 0x75345678);
+               nes_write_indexed(nesdev, 0x00000908, 0x20000001);
+       }
+       if (port_count > 2) {
+               nes_write_indexed(nesdev, 0x00002400, 0x00000001);
+               nes_write_indexed(nesdev, 0x00002404, 0x00000001);
+               nes_write_indexed(nesdev, 0x00002408, 0x0000FFFF);
+               nes_write_indexed(nesdev, 0x0000240C, 0x00000001);
+               nes_write_indexed(nesdev, 0x00002410, 0x000003c1);
+               nes_write_indexed(nesdev, 0x0000241C, 0x75345678);
+               nes_write_indexed(nesdev, 0x00000910, 0x20000001);
+
+               nes_write_indexed(nesdev, 0x00002600, 0x00000001);
+               nes_write_indexed(nesdev, 0x00002604, 0x00000001);
+               nes_write_indexed(nesdev, 0x00002608, 0x0000FFFF);
+               nes_write_indexed(nesdev, 0x0000260C, 0x00000001);
+               nes_write_indexed(nesdev, 0x00002610, 0x000003c1);
+               nes_write_indexed(nesdev, 0x0000261C, 0x75345678);
+               nes_write_indexed(nesdev, 0x00000918, 0x20000001);
+       }
+
+       nes_write_indexed(nesdev, 0x00005000, 0x00018000);
+       /* nes_write_indexed(nesdev, 0x00005000, 0x00010000); */
+       nes_write_indexed(nesdev, 0x00005004, 0x00020001);
+       nes_write_indexed(nesdev, 0x00005008, 0x1F1F1F1F);
+       nes_write_indexed(nesdev, 0x00005010, 0x1F1F1F1F);
+       nes_write_indexed(nesdev, 0x00005018, 0x1F1F1F1F);
+       nes_write_indexed(nesdev, 0x00005020, 0x1F1F1F1F);
+       nes_write_indexed(nesdev, 0x00006090, 0xFFFFFFFF);
+
+       /* TODO: move this to code, get from EEPROM */
+       nes_write_indexed(nesdev, 0x00000900, 0x20000001);
+       nes_write_indexed(nesdev, 0x000060C0, 0x0000028e);
+       nes_write_indexed(nesdev, 0x000060C8, 0x00000020);
+                                                                                                               //
+       nes_write_indexed(nesdev, 0x000001EC, 0x7b2625a0);
+       /* nes_write_indexed(nesdev, 0x000001EC, 0x5f2625a0); */
+
+       if (hw_rev != NE020_REV) {
+               u32temp = nes_read_indexed(nesdev, 0x000008e8);
+               u32temp |= 0x80000000;
+               nes_write_indexed(nesdev, 0x000008e8, u32temp);
+               u32temp = nes_read_indexed(nesdev, 0x000021f8);
+               u32temp &= 0x7fffffff;
+               u32temp |= 0x7fff0010;
+               nes_write_indexed(nesdev, 0x000021f8, u32temp);
+       }
+}
+
+
+/**
+ * nes_destroy_adapter - destroy the adapter structure
+ */
+void nes_destroy_adapter(struct nes_adapter *nesadapter)
+{
+       struct nes_adapter *tmp_adapter;
+
+       list_for_each_entry(tmp_adapter, &nes_adapter_list, list) {
+               nes_debug(NES_DBG_SHUTDOWN, "Nes Adapter list entry = 0x%p.\n",
+                               tmp_adapter);
+       }
+
+       nesadapter->ref_count--;
+       if (!nesadapter->ref_count) {
+               if (nesadapter->hw_rev == NE020_REV) {
+                       del_timer(&nesadapter->mh_timer);
+               }
+               del_timer(&nesadapter->lc_timer);
+
+               list_del(&nesadapter->list);
+               kfree(nesadapter);
+       }
+}
+
+
+/**
+ * nes_init_cqp
+ */
+int nes_init_cqp(struct nes_device *nesdev)
+{
+       struct nes_adapter *nesadapter = nesdev->nesadapter;
+       struct nes_hw_cqp_qp_context *cqp_qp_context;
+       struct nes_hw_cqp_wqe *cqp_wqe;
+       struct nes_hw_ceq *ceq;
+       struct nes_hw_ceq *nic_ceq;
+       struct nes_hw_aeq *aeq;
+       void *vmem;
+       dma_addr_t pmem;
+       u32 count=0;
+       u32 cqp_head;
+       u64 u64temp;
+       u32 u32temp;
+
+       /* allocate CQP memory */
+       /* Need to add max_cq to the aeq size once cq overflow checking is added back */
+       /* SQ is 512 byte aligned, others are 256 byte aligned */
+       nesdev->cqp_mem_size = 512 +
+                       (sizeof(struct nes_hw_cqp_wqe) * NES_CQP_SQ_SIZE) +
+                       (sizeof(struct nes_hw_cqe) * NES_CCQ_SIZE) +
+                       max(((u32)sizeof(struct nes_hw_ceqe) * NES_CCEQ_SIZE), (u32)256) +
+                       max(((u32)sizeof(struct nes_hw_ceqe) * NES_NIC_CEQ_SIZE), (u32)256) +
+                       (sizeof(struct nes_hw_aeqe) * nesadapter->max_qp) +
+                       sizeof(struct nes_hw_cqp_qp_context);
+
+       nesdev->cqp_vbase = pci_alloc_consistent(nesdev->pcidev, nesdev->cqp_mem_size,
+                       &nesdev->cqp_pbase);
+       if (!nesdev->cqp_vbase) {
+               nes_debug(NES_DBG_INIT, "Unable to allocate memory for host descriptor rings\n");
+               return -ENOMEM;
+       }
+       memset(nesdev->cqp_vbase, 0, nesdev->cqp_mem_size);
+
+       /* Allocate a twice the number of CQP requests as the SQ size */
+       nesdev->nes_cqp_requests = kzalloc(sizeof(struct nes_cqp_request) *
+                       2 * NES_CQP_SQ_SIZE, GFP_KERNEL);
+       if (nesdev->nes_cqp_requests == NULL) {
+               nes_debug(NES_DBG_INIT, "Unable to allocate memory CQP request entries.\n");
+               pci_free_consistent(nesdev->pcidev, nesdev->cqp_mem_size, nesdev->cqp.sq_vbase,
+                               nesdev->cqp.sq_pbase);
+               return -ENOMEM;
+       }
+
+       nes_debug(NES_DBG_INIT, "Allocated CQP structures at %p (phys = %016lX), size = %u.\n",
+                       nesdev->cqp_vbase, (unsigned long)nesdev->cqp_pbase, nesdev->cqp_mem_size);
+
+       spin_lock_init(&nesdev->cqp.lock);
+       init_waitqueue_head(&nesdev->cqp.waitq);
+
+       /* Setup Various Structures */
+       vmem = (void *)(((unsigned long)nesdev->cqp_vbase + (512 - 1)) &
+                       ~(unsigned long)(512 - 1));
+       pmem = (dma_addr_t)(((unsigned long long)nesdev->cqp_pbase + (512 - 1)) &
+                       ~(unsigned long long)(512 - 1));
+
+       nesdev->cqp.sq_vbase = vmem;
+       nesdev->cqp.sq_pbase = pmem;
+       nesdev->cqp.sq_size = NES_CQP_SQ_SIZE;
+       nesdev->cqp.sq_head = 0;
+       nesdev->cqp.sq_tail = 0;
+       nesdev->cqp.qp_id = PCI_FUNC(nesdev->pcidev->devfn);
+
+       vmem += (sizeof(struct nes_hw_cqp_wqe) * nesdev->cqp.sq_size);
+       pmem += (sizeof(struct nes_hw_cqp_wqe) * nesdev->cqp.sq_size);
+
+       nesdev->ccq.cq_vbase = vmem;
+       nesdev->ccq.cq_pbase = pmem;
+       nesdev->ccq.cq_size = NES_CCQ_SIZE;
+       nesdev->ccq.cq_head = 0;
+       nesdev->ccq.ce_handler = nes_cqp_ce_handler;
+       nesdev->ccq.cq_number = PCI_FUNC(nesdev->pcidev->devfn);
+
+       vmem += (sizeof(struct nes_hw_cqe) * nesdev->ccq.cq_size);
+       pmem += (sizeof(struct nes_hw_cqe) * nesdev->ccq.cq_size);
+
+       nesdev->ceq_index = PCI_FUNC(nesdev->pcidev->devfn);
+       ceq = &nesadapter->ceq[nesdev->ceq_index];
+       ceq->ceq_vbase = vmem;
+       ceq->ceq_pbase = pmem;
+       ceq->ceq_size = NES_CCEQ_SIZE;
+       ceq->ceq_head = 0;
+
+       vmem += max(((u32)sizeof(struct nes_hw_ceqe) * ceq->ceq_size), (u32)256);
+       pmem += max(((u32)sizeof(struct nes_hw_ceqe) * ceq->ceq_size), (u32)256);
+
+       nesdev->nic_ceq_index = PCI_FUNC(nesdev->pcidev->devfn) + 8;
+       nic_ceq = &nesadapter->ceq[nesdev->nic_ceq_index];
+       nic_ceq->ceq_vbase = vmem;
+       nic_ceq->ceq_pbase = pmem;
+       nic_ceq->ceq_size = NES_NIC_CEQ_SIZE;
+       nic_ceq->ceq_head = 0;
+
+       vmem += max(((u32)sizeof(struct nes_hw_ceqe) * nic_ceq->ceq_size), (u32)256);
+       pmem += max(((u32)sizeof(struct nes_hw_ceqe) * nic_ceq->ceq_size), (u32)256);
+
+       aeq = &nesadapter->aeq[PCI_FUNC(nesdev->pcidev->devfn)];
+       aeq->aeq_vbase = vmem;
+       aeq->aeq_pbase = pmem;
+       aeq->aeq_size = nesadapter->max_qp;
+       aeq->aeq_head = 0;
+
+       /* Setup QP Context */
+       vmem += (sizeof(struct nes_hw_aeqe) * aeq->aeq_size);
+       pmem += (sizeof(struct nes_hw_aeqe) * aeq->aeq_size);
+
+       cqp_qp_context = vmem;
+       cqp_qp_context->context_words[0] =
+                       cpu_to_le32((PCI_FUNC(nesdev->pcidev->devfn) << 12) + (2 << 10));
+       cqp_qp_context->context_words[1] = 0;
+       cqp_qp_context->context_words[2] = cpu_to_le32((u32)nesdev->cqp.sq_pbase);
+       cqp_qp_context->context_words[3] = cpu_to_le32(((u64)nesdev->cqp.sq_pbase) >> 32);
+
+
+       /* Write the address to Create CQP */
+       if ((sizeof(dma_addr_t) > 4)) {
+               nes_write_indexed(nesdev,
+                               NES_IDX_CREATE_CQP_HIGH + (PCI_FUNC(nesdev->pcidev->devfn) * 8),
+                               ((u64)pmem) >> 32);
+       } else {
+               nes_write_indexed(nesdev,
+                               NES_IDX_CREATE_CQP_HIGH + (PCI_FUNC(nesdev->pcidev->devfn) * 8), 0);
+       }
+       nes_write_indexed(nesdev,
+                       NES_IDX_CREATE_CQP_LOW + (PCI_FUNC(nesdev->pcidev->devfn) * 8),
+                       (u32)pmem);
+
+       INIT_LIST_HEAD(&nesdev->cqp_avail_reqs);
+       INIT_LIST_HEAD(&nesdev->cqp_pending_reqs);
+
+       for (count = 0; count < 2*NES_CQP_SQ_SIZE; count++) {
+               init_waitqueue_head(&nesdev->nes_cqp_requests[count].waitq);
+               list_add_tail(&nesdev->nes_cqp_requests[count].list, &nesdev->cqp_avail_reqs);
+       }
+
+       /* Write Create CCQ WQE */
+       cqp_head = nesdev->cqp.sq_head++;
+       cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
+       nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
+       set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_OPCODE_IDX,
+                       (NES_CQP_CREATE_CQ | NES_CQP_CQ_CEQ_VALID |
+                       NES_CQP_CQ_CHK_OVERFLOW | ((u32)nesdev->ccq.cq_size << 16)));
+       set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_ID_IDX,
+                           (nesdev->ccq.cq_number |
+                            ((u32)nesdev->ceq_index << 16)));
+       u64temp = (u64)nesdev->ccq.cq_pbase;
+       set_wqe_64bit_value(cqp_wqe->wqe_words, NES_CQP_CQ_WQE_PBL_LOW_IDX, u64temp);
+       cqp_wqe->wqe_words[NES_CQP_CQ_WQE_CQ_CONTEXT_HIGH_IDX] = 0;
+       u64temp = (unsigned long)&nesdev->ccq;
+       cqp_wqe->wqe_words[NES_CQP_CQ_WQE_CQ_CONTEXT_LOW_IDX] =
+                       cpu_to_le32((u32)(u64temp >> 1));
+       cqp_wqe->wqe_words[NES_CQP_CQ_WQE_CQ_CONTEXT_HIGH_IDX] =
+                       cpu_to_le32(((u32)((u64temp) >> 33)) & 0x7FFFFFFF);
+       cqp_wqe->wqe_words[NES_CQP_CQ_WQE_DOORBELL_INDEX_HIGH_IDX] = 0;
+
+       /* Write Create CEQ WQE */
+       cqp_head = nesdev->cqp.sq_head++;
+       cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
+       nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
+       set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_OPCODE_IDX,
+                           (NES_CQP_CREATE_CEQ + ((u32)nesdev->ceq_index << 8)));
+       set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_CEQ_WQE_ELEMENT_COUNT_IDX, ceq->ceq_size);
+       u64temp = (u64)ceq->ceq_pbase;
+       set_wqe_64bit_value(cqp_wqe->wqe_words, NES_CQP_CQ_WQE_PBL_LOW_IDX, u64temp);
+
+       /* Write Create AEQ WQE */
+       cqp_head = nesdev->cqp.sq_head++;
+       cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
+       nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
+       set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_OPCODE_IDX,
+                       (NES_CQP_CREATE_AEQ + ((u32)PCI_FUNC(nesdev->pcidev->devfn) << 8)));
+       set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_AEQ_WQE_ELEMENT_COUNT_IDX, aeq->aeq_size);
+       u64temp = (u64)aeq->aeq_pbase;
+       set_wqe_64bit_value(cqp_wqe->wqe_words, NES_CQP_CQ_WQE_PBL_LOW_IDX, u64temp);
+
+       /* Write Create NIC CEQ WQE */
+       cqp_head = nesdev->cqp.sq_head++;
+       cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
+       nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
+       set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_OPCODE_IDX,
+                       (NES_CQP_CREATE_CEQ + ((u32)nesdev->nic_ceq_index << 8)));
+       set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_CEQ_WQE_ELEMENT_COUNT_IDX, nic_ceq->ceq_size);
+       u64temp = (u64)nic_ceq->ceq_pbase;
+       set_wqe_64bit_value(cqp_wqe->wqe_words, NES_CQP_CQ_WQE_PBL_LOW_IDX, u64temp);
+
+       /* Poll until CCQP done */
+       count = 0;
+       do {
+               if (count++ > 1000) {
+                       printk(KERN_ERR PFX "Error creating CQP\n");
+                       pci_free_consistent(nesdev->pcidev, nesdev->cqp_mem_size,
+                                       nesdev->cqp_vbase, nesdev->cqp_pbase);
+                       return -1;
+               }
+               udelay(10);
+       } while (!(nes_read_indexed(nesdev,
+                       NES_IDX_QP_CONTROL + (PCI_FUNC(nesdev->pcidev->devfn) * 8)) & (1 << 8)));
+
+       nes_debug(NES_DBG_INIT, "CQP Status = 0x%08X\n", nes_read_indexed(nesdev,
+                       NES_IDX_QP_CONTROL+(PCI_FUNC(nesdev->pcidev->devfn)*8)));
+
+       u32temp = 0x04800000;
+       nes_write32(nesdev->regs+NES_WQE_ALLOC, u32temp | nesdev->cqp.qp_id);
+
+       /* wait for the CCQ, CEQ, and AEQ to get created */
+       count = 0;
+       do {
+               if (count++ > 1000) {
+                       printk(KERN_ERR PFX "Error creating CCQ, CEQ, and AEQ\n");
+                       pci_free_consistent(nesdev->pcidev, nesdev->cqp_mem_size,
+                                       nesdev->cqp_vbase, nesdev->cqp_pbase);
+                       return -1;
+               }
+               udelay(10);
+       } while (((nes_read_indexed(nesdev,
+                       NES_IDX_QP_CONTROL+(PCI_FUNC(nesdev->pcidev->devfn)*8)) & (15<<8)) != (15<<8)));
+
+       /* dump the QP status value */
+       nes_debug(NES_DBG_INIT, "QP Status = 0x%08X\n", nes_read_indexed(nesdev,
+                       NES_IDX_QP_CONTROL+(PCI_FUNC(nesdev->pcidev->devfn)*8)));
+
+       nesdev->cqp.sq_tail++;
+
+       return 0;
+}
+
+
+/**
+ * nes_destroy_cqp
+ */
+int nes_destroy_cqp(struct nes_device *nesdev)
+{
+       struct nes_hw_cqp_wqe *cqp_wqe;
+       u32 count = 0;
+       u32 cqp_head;
+       unsigned long flags;
+
+       do {
+               if (count++ > 1000)
+                       break;
+               udelay(10);
+       } while (!(nesdev->cqp.sq_head == nesdev->cqp.sq_tail));
+
+       /* Reset CCQ */
+       nes_write32(nesdev->regs+NES_CQE_ALLOC, NES_CQE_ALLOC_RESET |
+                       nesdev->ccq.cq_number);
+
+       /* Disable device interrupts */
+       nes_write32(nesdev->regs+NES_INT_MASK, 0x7fffffff);
+
+       spin_lock_irqsave(&nesdev->cqp.lock, flags);
+
+       /* Destroy the AEQ */
+       cqp_head = nesdev->cqp.sq_head++;
+       nesdev->cqp.sq_head &= nesdev->cqp.sq_size-1;
+       cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
+       cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] = cpu_to_le32(NES_CQP_DESTROY_AEQ |
+                       ((u32)PCI_FUNC(nesdev->pcidev->devfn) << 8));
+       cqp_wqe->wqe_words[NES_CQP_WQE_COMP_CTX_HIGH_IDX] = 0;
+
+       /* Destroy the NIC CEQ */
+       cqp_head = nesdev->cqp.sq_head++;
+       nesdev->cqp.sq_head &= nesdev->cqp.sq_size-1;
+       cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
+       cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] = cpu_to_le32(NES_CQP_DESTROY_CEQ |
+                       ((u32)nesdev->nic_ceq_index << 8));
+
+       /* Destroy the CEQ */
+       cqp_head = nesdev->cqp.sq_head++;
+       nesdev->cqp.sq_head &= nesdev->cqp.sq_size-1;
+       cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
+       cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] = cpu_to_le32(NES_CQP_DESTROY_CEQ |
+                       (nesdev->ceq_index << 8));
+
+       /* Destroy the CCQ */
+       cqp_head = nesdev->cqp.sq_head++;
+       nesdev->cqp.sq_head &= nesdev->cqp.sq_size-1;
+       cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
+       cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] = cpu_to_le32(NES_CQP_DESTROY_CQ);
+       cqp_wqe->wqe_words[NES_CQP_WQE_ID_IDX] = cpu_to_le32(nesdev->ccq.cq_number |
+                       ((u32)nesdev->ceq_index << 16));
+
+       /* Destroy CQP */
+       cqp_head = nesdev->cqp.sq_head++;
+       nesdev->cqp.sq_head &= nesdev->cqp.sq_size-1;
+       cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
+       cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] = cpu_to_le32(NES_CQP_DESTROY_QP |
+                       NES_CQP_QP_TYPE_CQP);
+       cqp_wqe->wqe_words[NES_CQP_WQE_ID_IDX] = cpu_to_le32(nesdev->cqp.qp_id);
+
+       barrier();
+       /* Ring doorbell (5 WQEs) */
+       nes_write32(nesdev->regs+NES_WQE_ALLOC, 0x05800000 | nesdev->cqp.qp_id);
+
+       spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+
+       /* wait for the CCQ, CEQ, and AEQ to get destroyed */
+       count = 0;
+       do {
+               if (count++ > 1000) {
+                       printk(KERN_ERR PFX "Function%d: Error destroying CCQ, CEQ, and AEQ\n",
+                                       PCI_FUNC(nesdev->pcidev->devfn));
+                       break;
+               }
+               udelay(10);
+       } while (((nes_read_indexed(nesdev,
+                       NES_IDX_QP_CONTROL + (PCI_FUNC(nesdev->pcidev->devfn)*8)) & (15 << 8)) != 0));
+
+       /* dump the QP status value */
+       nes_debug(NES_DBG_SHUTDOWN, "Function%d: QP Status = 0x%08X\n",
+                       PCI_FUNC(nesdev->pcidev->devfn),
+                       nes_read_indexed(nesdev,
+                       NES_IDX_QP_CONTROL+(PCI_FUNC(nesdev->pcidev->devfn)*8)));
+
+       kfree(nesdev->nes_cqp_requests);
+
+       /* Free the control structures */
+       pci_free_consistent(nesdev->pcidev, nesdev->cqp_mem_size, nesdev->cqp.sq_vbase,
+                       nesdev->cqp.sq_pbase);
+
+       return 0;
+}
+
+
+/**
+ * nes_init_phy
+ */
+int nes_init_phy(struct nes_device *nesdev)
+{
+       struct nes_adapter *nesadapter = nesdev->nesadapter;
+       u32 counter = 0;
+       u32 mac_index = nesdev->mac_index;
+       u32 tx_config;
+       u16 phy_data;
+
+       if (nesadapter->OneG_Mode) {
+               nes_debug(NES_DBG_PHY, "1G PHY, mac_index = %d.\n", mac_index);
+               if (nesadapter->phy_type[mac_index] == NES_PHY_TYPE_1G) {
+                       printk(PFX "%s: Programming mdc config for 1G\n", __FUNCTION__);
+                       tx_config = nes_read_indexed(nesdev, NES_IDX_MAC_TX_CONFIG);
+                       tx_config |= 0x04;
+                       nes_write_indexed(nesdev, NES_IDX_MAC_TX_CONFIG, tx_config);
+               }
+
+               nes_read_1G_phy_reg(nesdev, 1, nesadapter->phy_index[mac_index], &phy_data);
+               nes_debug(NES_DBG_PHY, "Phy data from register 1 phy address %u = 0x%X.\n",
+                               nesadapter->phy_index[mac_index], phy_data);
+               nes_write_1G_phy_reg(nesdev, 23, nesadapter->phy_index[mac_index],  0xb000);
+
+               /* Reset the PHY */
+               nes_write_1G_phy_reg(nesdev, 0, nesadapter->phy_index[mac_index], 0x8000);
+               udelay(100);
+               counter = 0;
+               do {
+                       nes_read_1G_phy_reg(nesdev, 0, nesadapter->phy_index[mac_index], &phy_data);
+                       nes_debug(NES_DBG_PHY, "Phy data from register 0 = 0x%X.\n", phy_data);
+                       if (counter++ > 100) break;
+               } while (phy_data & 0x8000);
+
+               /* Setting no phy loopback */
+               phy_data &= 0xbfff;
+               phy_data |= 0x1140;
+               nes_write_1G_phy_reg(nesdev, 0, nesadapter->phy_index[mac_index],  phy_data);
+               nes_read_1G_phy_reg(nesdev, 0, nesadapter->phy_index[mac_index], &phy_data);
+               nes_debug(NES_DBG_PHY, "Phy data from register 0 = 0x%X.\n", phy_data);
+
+               nes_read_1G_phy_reg(nesdev, 0x17, nesadapter->phy_index[mac_index], &phy_data);
+               nes_debug(NES_DBG_PHY, "Phy data from register 0x17 = 0x%X.\n", phy_data);
+
+               nes_read_1G_phy_reg(nesdev, 0x1e, nesadapter->phy_index[mac_index], &phy_data);
+               nes_debug(NES_DBG_PHY, "Phy data from register 0x1e = 0x%X.\n", phy_data);
+
+               /* Setting the interrupt mask */
+               nes_read_1G_phy_reg(nesdev, 0x19, nesadapter->phy_index[mac_index], &phy_data);
+               nes_debug(NES_DBG_PHY, "Phy data from register 0x19 = 0x%X.\n", phy_data);
+               nes_write_1G_phy_reg(nesdev, 0x19, nesadapter->phy_index[mac_index], 0xffee);
+
+               nes_read_1G_phy_reg(nesdev, 0x19, nesadapter->phy_index[mac_index], &phy_data);
+               nes_debug(NES_DBG_PHY, "Phy data from register 0x19 = 0x%X.\n", phy_data);
+
+               /* turning on flow control */
+               nes_read_1G_phy_reg(nesdev, 4, nesadapter->phy_index[mac_index], &phy_data);
+               nes_debug(NES_DBG_PHY, "Phy data from register 0x4 = 0x%X.\n", phy_data);
+               nes_write_1G_phy_reg(nesdev, 4, nesadapter->phy_index[mac_index],
+                               (phy_data & ~(0x03E0)) | 0xc00);
+               /* nes_write_1G_phy_reg(nesdev, 4, nesadapter->phy_index[mac_index],
+                               phy_data | 0xc00); */
+               nes_read_1G_phy_reg(nesdev, 4, nesadapter->phy_index[mac_index], &phy_data);
+               nes_debug(NES_DBG_PHY, "Phy data from register 0x4 = 0x%X.\n", phy_data);
+
+               nes_read_1G_phy_reg(nesdev, 9, nesadapter->phy_index[mac_index], &phy_data);
+               nes_debug(NES_DBG_PHY, "Phy data from register 0x9 = 0x%X.\n", phy_data);
+               /* Clear Half duplex */
+               nes_write_1G_phy_reg(nesdev, 9, nesadapter->phy_index[mac_index],
+                               phy_data & ~(0x0100));
+               nes_read_1G_phy_reg(nesdev, 9, nesadapter->phy_index[mac_index], &phy_data);
+               nes_debug(NES_DBG_PHY, "Phy data from register 0x9 = 0x%X.\n", phy_data);
+
+               nes_read_1G_phy_reg(nesdev, 0, nesadapter->phy_index[mac_index], &phy_data);
+               nes_write_1G_phy_reg(nesdev, 0, nesadapter->phy_index[mac_index], phy_data | 0x0300);
+       } else {
+               if (nesadapter->phy_type[mac_index] == NES_PHY_TYPE_IRIS) {
+                       /* setup 10G MDIO operation */
+                       tx_config = nes_read_indexed(nesdev, NES_IDX_MAC_TX_CONFIG);
+                       tx_config |= 0x14;
+                       nes_write_indexed(nesdev, NES_IDX_MAC_TX_CONFIG, tx_config);
+               }
+       }
+       return 0;
+}
+
+
+/**
+ * nes_replenish_nic_rq
+ */
+static void nes_replenish_nic_rq(struct nes_vnic *nesvnic)
+{
+       unsigned long flags;
+       dma_addr_t bus_address;
+       struct sk_buff *skb;
+       struct nes_hw_nic_rq_wqe *nic_rqe;
+       struct nes_hw_nic *nesnic;
+       struct nes_device *nesdev;
+       u32 rx_wqes_posted = 0;
+
+       nesnic = &nesvnic->nic;
+       nesdev = nesvnic->nesdev;
+       spin_lock_irqsave(&nesnic->rq_lock, flags);
+       if (nesnic->replenishing_rq !=0) {
+               if (((nesnic->rq_size-1) == atomic_read(&nesvnic->rx_skbs_needed)) &&
+                               (atomic_read(&nesvnic->rx_skb_timer_running) == 0)) {
+                       atomic_set(&nesvnic->rx_skb_timer_running, 1);
+                       spin_unlock_irqrestore(&nesnic->rq_lock, flags);
+                       nesvnic->rq_wqes_timer.expires = jiffies + (HZ/2);      /* 1/2 second */
+                       add_timer(&nesvnic->rq_wqes_timer);
+               } else
+               spin_unlock_irqrestore(&nesnic->rq_lock, flags);
+               return;
+       }
+       nesnic->replenishing_rq = 1;
+       spin_unlock_irqrestore(&nesnic->rq_lock, flags);
+       do {
+               skb = dev_alloc_skb(nesvnic->max_frame_size);
+               if (skb) {
+                       skb->dev = nesvnic->netdev;
+
+                       bus_address = pci_map_single(nesdev->pcidev,
+                                       skb->data, nesvnic->max_frame_size, PCI_DMA_FROMDEVICE);
+
+                       nic_rqe = &nesnic->rq_vbase[nesvnic->nic.rq_head];
+                       nic_rqe->wqe_words[NES_NIC_RQ_WQE_LENGTH_1_0_IDX] =
+                                       cpu_to_le32(nesvnic->max_frame_size);
+                       nic_rqe->wqe_words[NES_NIC_RQ_WQE_LENGTH_3_2_IDX] = 0;
+                       nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_LOW_IDX] =
+                                       cpu_to_le32((u32)bus_address);
+                       nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_HIGH_IDX] =
+                                       cpu_to_le32((u32)((u64)bus_address >> 32));
+                       nesnic->rx_skb[nesnic->rq_head] = skb;
+                       nesnic->rq_head++;
+                       nesnic->rq_head &= nesnic->rq_size - 1;
+                       atomic_dec(&nesvnic->rx_skbs_needed);
+                       barrier();
+                       if (++rx_wqes_posted == 255) {
+                               nes_write32(nesdev->regs+NES_WQE_ALLOC, (rx_wqes_posted << 24) | nesnic->qp_id);
+                               rx_wqes_posted = 0;
+                       }
+               } else {
+                       spin_lock_irqsave(&nesnic->rq_lock, flags);
+                       if (((nesnic->rq_size-1) == atomic_read(&nesvnic->rx_skbs_needed)) &&
+                                       (atomic_read(&nesvnic->rx_skb_timer_running) == 0)) {
+                               atomic_set(&nesvnic->rx_skb_timer_running, 1);
+                               spin_unlock_irqrestore(&nesnic->rq_lock, flags);
+                               nesvnic->rq_wqes_timer.expires = jiffies + (HZ/2);      /* 1/2 second */
+                               add_timer(&nesvnic->rq_wqes_timer);
+                       } else
+                               spin_unlock_irqrestore(&nesnic->rq_lock, flags);
+                       break;
+               }
+       } while (atomic_read(&nesvnic->rx_skbs_needed));
+       barrier();
+       if (rx_wqes_posted)
+               nes_write32(nesdev->regs+NES_WQE_ALLOC, (rx_wqes_posted << 24) | nesnic->qp_id);
+       nesnic->replenishing_rq = 0;
+}
+
+
+/**
+ * nes_rq_wqes_timeout
+ */
+static void nes_rq_wqes_timeout(unsigned long parm)
+{
+       struct nes_vnic *nesvnic = (struct nes_vnic *)parm;
+       printk("%s: Timer fired.\n", __FUNCTION__);
+       atomic_set(&nesvnic->rx_skb_timer_running, 0);
+       if (atomic_read(&nesvnic->rx_skbs_needed))
+               nes_replenish_nic_rq(nesvnic);
+}
+
+
+/**
+ * nes_init_nic_qp
+ */
+int nes_init_nic_qp(struct nes_device *nesdev, struct net_device *netdev)
+{
+       struct nes_hw_cqp_wqe *cqp_wqe;
+       struct nes_hw_nic_sq_wqe *nic_sqe;
+       struct nes_hw_nic_qp_context *nic_context;
+       struct sk_buff *skb;
+       struct nes_hw_nic_rq_wqe *nic_rqe;
+       struct nes_vnic *nesvnic = netdev_priv(netdev);
+       unsigned long flags;
+       void *vmem;
+       dma_addr_t pmem;
+       u64 u64temp;
+       int ret;
+       u32 cqp_head;
+       u32 counter;
+       u32 wqe_count;
+       u8 jumbomode=0;
+
+       /* Allocate fragment, SQ, RQ, and CQ; Reuse CEQ based on the PCI function */
+       nesvnic->nic_mem_size = 256 +
+                       (NES_NIC_WQ_SIZE * sizeof(struct nes_first_frag)) +
+                       (NES_NIC_WQ_SIZE * sizeof(struct nes_hw_nic_sq_wqe)) +
+                       (NES_NIC_WQ_SIZE * sizeof(struct nes_hw_nic_rq_wqe)) +
+                       (NES_NIC_WQ_SIZE * 2 * sizeof(struct nes_hw_nic_cqe)) +
+                       sizeof(struct nes_hw_nic_qp_context);
+
+       nesvnic->nic_vbase = pci_alloc_consistent(nesdev->pcidev, nesvnic->nic_mem_size,
+                       &nesvnic->nic_pbase);
+       if (!nesvnic->nic_vbase) {
+               nes_debug(NES_DBG_INIT, "Unable to allocate memory for NIC host descriptor rings\n");
+               return -ENOMEM;
+       }
+       memset(nesvnic->nic_vbase, 0, nesvnic->nic_mem_size);
+       nes_debug(NES_DBG_INIT, "Allocated NIC QP structures at %p (phys = %016lX), size = %u.\n",
+                       nesvnic->nic_vbase, (unsigned long)nesvnic->nic_pbase, nesvnic->nic_mem_size);
+
+       vmem = (void *)(((unsigned long)nesvnic->nic_vbase + (256 - 1)) &
+                       ~(unsigned long)(256 - 1));
+       pmem = (dma_addr_t)(((unsigned long long)nesvnic->nic_pbase + (256 - 1)) &
+                       ~(unsigned long long)(256 - 1));
+
+       /* Setup the first Fragment buffers */
+       nesvnic->nic.first_frag_vbase = vmem;
+
+       for (counter = 0; counter < NES_NIC_WQ_SIZE; counter++) {
+               nesvnic->nic.frag_paddr[counter] = pmem;
+               pmem += sizeof(struct nes_first_frag);
+       }
+
+       /* setup the SQ */
+       vmem += (NES_NIC_WQ_SIZE * sizeof(struct nes_first_frag));
+
+       nesvnic->nic.sq_vbase = (void *)vmem;
+       nesvnic->nic.sq_pbase = pmem;
+       nesvnic->nic.sq_head = 0;
+       nesvnic->nic.sq_tail = 0;
+       nesvnic->nic.sq_size = NES_NIC_WQ_SIZE;
+       for (counter = 0; counter < NES_NIC_WQ_SIZE; counter++) {
+               nic_sqe = &nesvnic->nic.sq_vbase[counter];
+               nic_sqe->wqe_words[NES_NIC_SQ_WQE_MISC_IDX] =
+                               cpu_to_le32(NES_NIC_SQ_WQE_DISABLE_CHKSUM |
+                               NES_NIC_SQ_WQE_COMPLETION);
+               nic_sqe->wqe_words[NES_NIC_SQ_WQE_LENGTH_0_TAG_IDX] =
+                               cpu_to_le32((u32)NES_FIRST_FRAG_SIZE << 16);
+               nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG0_LOW_IDX] =
+                               cpu_to_le32((u32)nesvnic->nic.frag_paddr[counter]);
+               nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG0_HIGH_IDX] =
+                               cpu_to_le32((u32)((u64)nesvnic->nic.frag_paddr[counter] >> 32));
+       }
+
+       nesvnic->get_cqp_request = nes_get_cqp_request;
+       nesvnic->post_cqp_request = nes_post_cqp_request;
+       nesvnic->mcrq_mcast_filter = NULL;
+
+       spin_lock_init(&nesvnic->nic.sq_lock);
+       spin_lock_init(&nesvnic->nic.rq_lock);
+
+       /* setup the RQ */
+       vmem += (NES_NIC_WQ_SIZE * sizeof(struct nes_hw_nic_sq_wqe));
+       pmem += (NES_NIC_WQ_SIZE * sizeof(struct nes_hw_nic_sq_wqe));
+
+
+       nesvnic->nic.rq_vbase = vmem;
+       nesvnic->nic.rq_pbase = pmem;
+       nesvnic->nic.rq_head = 0;
+       nesvnic->nic.rq_tail = 0;
+       nesvnic->nic.rq_size = NES_NIC_WQ_SIZE;
+
+       /* setup the CQ */
+       vmem += (NES_NIC_WQ_SIZE * sizeof(struct nes_hw_nic_rq_wqe));
+       pmem += (NES_NIC_WQ_SIZE * sizeof(struct nes_hw_nic_rq_wqe));
+
+       if (nesdev->nesadapter->netdev_count > 2)
+               nesvnic->mcrq_qp_id = nesvnic->nic_index + 32;
+       else
+               nesvnic->mcrq_qp_id = nesvnic->nic.qp_id + 4;
+
+       nesvnic->nic_cq.cq_vbase = vmem;
+       nesvnic->nic_cq.cq_pbase = pmem;
+       nesvnic->nic_cq.cq_head = 0;
+       nesvnic->nic_cq.cq_size = NES_NIC_WQ_SIZE * 2;
+
+       nesvnic->nic_cq.ce_handler = nes_nic_napi_ce_handler;
+
+       /* Send CreateCQ request to CQP */
+       spin_lock_irqsave(&nesdev->cqp.lock, flags);
+       cqp_head = nesdev->cqp.sq_head;
+
+       cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
+       nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
+
+       cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] = cpu_to_le32(
+                       NES_CQP_CREATE_CQ | NES_CQP_CQ_CEQ_VALID |
+                       ((u32)nesvnic->nic_cq.cq_size << 16));
+       cqp_wqe->wqe_words[NES_CQP_WQE_ID_IDX] = cpu_to_le32(
+                       nesvnic->nic_cq.cq_number | ((u32)nesdev->nic_ceq_index << 16));
+       u64temp = (u64)nesvnic->nic_cq.cq_pbase;
+       set_wqe_64bit_value(cqp_wqe->wqe_words, NES_CQP_CQ_WQE_PBL_LOW_IDX, u64temp);
+       cqp_wqe->wqe_words[NES_CQP_CQ_WQE_CQ_CONTEXT_HIGH_IDX] =  0;
+       u64temp = (unsigned long)&nesvnic->nic_cq;
+       cqp_wqe->wqe_words[NES_CQP_CQ_WQE_CQ_CONTEXT_LOW_IDX] =  cpu_to_le32((u32)(u64temp >> 1));
+       cqp_wqe->wqe_words[NES_CQP_CQ_WQE_CQ_CONTEXT_HIGH_IDX] =
+                       cpu_to_le32(((u32)((u64temp) >> 33)) & 0x7FFFFFFF);
+       cqp_wqe->wqe_words[NES_CQP_CQ_WQE_DOORBELL_INDEX_HIGH_IDX] = 0;
+       if (++cqp_head >= nesdev->cqp.sq_size)
+               cqp_head = 0;
+       cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
+       nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
+
+       /* Send CreateQP request to CQP */
+       nic_context = (void *)(&nesvnic->nic_cq.cq_vbase[nesvnic->nic_cq.cq_size]);
+       nic_context->context_words[NES_NIC_CTX_MISC_IDX] =
+                       cpu_to_le32((u32)NES_NIC_CTX_SIZE |
+                       ((u32)PCI_FUNC(nesdev->pcidev->devfn) << 12));
+       nes_debug(NES_DBG_INIT, "RX_WINDOW_BUFFER_PAGE_TABLE_SIZE = 0x%08X, RX_WINDOW_BUFFER_SIZE = 0x%08X\n",
+                       nes_read_indexed(nesdev, NES_IDX_RX_WINDOW_BUFFER_PAGE_TABLE_SIZE),
+                       nes_read_indexed(nesdev, NES_IDX_RX_WINDOW_BUFFER_SIZE));
+       if (nes_read_indexed(nesdev, NES_IDX_RX_WINDOW_BUFFER_SIZE) != 0) {
+               nic_context->context_words[NES_NIC_CTX_MISC_IDX] |= cpu_to_le32(NES_NIC_BACK_STORE);
+       }
+
+       u64temp = (u64)nesvnic->nic.sq_pbase;
+       nic_context->context_words[NES_NIC_CTX_SQ_LOW_IDX] = cpu_to_le32((u32)u64temp);
+       nic_context->context_words[NES_NIC_CTX_SQ_HIGH_IDX] = cpu_to_le32((u32)(u64temp >> 32));
+       u64temp = (u64)nesvnic->nic.rq_pbase;
+       nic_context->context_words[NES_NIC_CTX_RQ_LOW_IDX] = cpu_to_le32((u32)u64temp);
+       nic_context->context_words[NES_NIC_CTX_RQ_HIGH_IDX] = cpu_to_le32((u32)(u64temp >> 32));
+
+       cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] = cpu_to_le32(NES_CQP_CREATE_QP |
+                       NES_CQP_QP_TYPE_NIC);
+       cqp_wqe->wqe_words[NES_CQP_WQE_ID_IDX] = cpu_to_le32(nesvnic->nic.qp_id);
+       u64temp = (u64)nesvnic->nic_cq.cq_pbase +
+                       (nesvnic->nic_cq.cq_size * sizeof(struct nes_hw_nic_cqe));
+       set_wqe_64bit_value(cqp_wqe->wqe_words, NES_CQP_QP_WQE_CONTEXT_LOW_IDX, u64temp);
+
+       if (++cqp_head >= nesdev->cqp.sq_size)
+               cqp_head = 0;
+       nesdev->cqp.sq_head = cqp_head;
+
+       barrier();
+
+       /* Ring doorbell (2 WQEs) */
+       nes_write32(nesdev->regs+NES_WQE_ALLOC, 0x02800000 | nesdev->cqp.qp_id);
+
+       spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+       nes_debug(NES_DBG_INIT, "Waiting for create NIC QP%u to complete.\n",
+                       nesvnic->nic.qp_id);
+
+       ret = wait_event_timeout(nesdev->cqp.waitq, (nesdev->cqp.sq_tail == cqp_head),
+                       NES_EVENT_TIMEOUT);
+       nes_debug(NES_DBG_INIT, "Create NIC QP%u completed, wait_event_timeout ret = %u.\n",
+                       nesvnic->nic.qp_id, ret);
+       if (!ret) {
+               nes_debug(NES_DBG_INIT, "NIC QP%u create timeout expired\n", nesvnic->nic.qp_id);
+               pci_free_consistent(nesdev->pcidev, nesvnic->nic_mem_size, nesvnic->nic_vbase,
+                               nesvnic->nic_pbase);
+               return -EIO;
+       }
+
+       /* Populate the RQ */
+       for (counter = 0; counter < (NES_NIC_WQ_SIZE - 1); counter++) {
+               skb = dev_alloc_skb(nesvnic->max_frame_size);
+               if (!skb) {
+                       nes_debug(NES_DBG_INIT, "%s: out of memory for receive skb\n", netdev->name);
+
+                       nes_destroy_nic_qp(nesvnic);
+                       return -ENOMEM;
+               }
+
+               skb->dev = netdev;
+
+               pmem = pci_map_single(nesdev->pcidev, skb->data,
+                               nesvnic->max_frame_size, PCI_DMA_FROMDEVICE);
+
+               nic_rqe = &nesvnic->nic.rq_vbase[counter];
+               nic_rqe->wqe_words[NES_NIC_RQ_WQE_LENGTH_1_0_IDX] = cpu_to_le32(nesvnic->max_frame_size);
+               nic_rqe->wqe_words[NES_NIC_RQ_WQE_LENGTH_3_2_IDX] = 0;
+               nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_LOW_IDX] = cpu_to_le32((u32)pmem);
+               nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_HIGH_IDX] = cpu_to_le32((u32)((u64)pmem >> 32));
+               nesvnic->nic.rx_skb[counter] = skb;
+       }
+
+       wqe_count = NES_NIC_WQ_SIZE - 1;
+       nesvnic->nic.rq_head = wqe_count;
+       barrier();
+       do {
+               counter = min(wqe_count, ((u32)255));
+               wqe_count -= counter;
+               nes_write32(nesdev->regs+NES_WQE_ALLOC, (counter << 24) | nesvnic->nic.qp_id);
+       } while (wqe_count);
+       init_timer(&nesvnic->rq_wqes_timer);
+       nesvnic->rq_wqes_timer.function = nes_rq_wqes_timeout;
+       nesvnic->rq_wqes_timer.data = (unsigned long)nesvnic;
+       nes_debug(NES_DBG_INIT, "NAPI support Enabled\n");
+
+       if (nesdev->nesadapter->et_use_adaptive_rx_coalesce)
+       {
+               nes_nic_init_timer(nesdev);
+               if (netdev->mtu > 1500)
+                       jumbomode = 1;
+                nes_nic_init_timer_defaults(nesdev, jumbomode);
+       }
+
+       return 0;
+}
+
+
+/**
+ * nes_destroy_nic_qp
+ */
+void nes_destroy_nic_qp(struct nes_vnic *nesvnic)
+{
+       struct nes_device *nesdev = nesvnic->nesdev;
+       struct nes_hw_cqp_wqe *cqp_wqe;
+       struct nes_hw_nic_rq_wqe *nic_rqe;
+       u64 wqe_frag;
+       u32 cqp_head;
+       unsigned long flags;
+       int ret;
+
+       /* Free remaining NIC receive buffers */
+       while (nesvnic->nic.rq_head != nesvnic->nic.rq_tail) {
+               nic_rqe = &nesvnic->nic.rq_vbase[nesvnic->nic.rq_tail];
+               wqe_frag = (u64)le32_to_cpu(nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_LOW_IDX]);
+               wqe_frag |= ((u64)le32_to_cpu(nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_HIGH_IDX])) << 32;
+               pci_unmap_single(nesdev->pcidev, (dma_addr_t)wqe_frag,
+                               nesvnic->max_frame_size, PCI_DMA_FROMDEVICE);
+               dev_kfree_skb(nesvnic->nic.rx_skb[nesvnic->nic.rq_tail++]);
+               nesvnic->nic.rq_tail &= (nesvnic->nic.rq_size - 1);
+       }
+
+       spin_lock_irqsave(&nesdev->cqp.lock, flags);
+
+       /* Destroy NIC QP */
+       cqp_head = nesdev->cqp.sq_head;
+       cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
+       nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
+
+       set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_OPCODE_IDX,
+               (NES_CQP_DESTROY_QP | NES_CQP_QP_TYPE_NIC));
+       set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_ID_IDX,
+               nesvnic->nic.qp_id);
+
+       if (++cqp_head >= nesdev->cqp.sq_size)
+               cqp_head = 0;
+
+       cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
+
+       /* Destroy NIC CQ */
+       nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
+       set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_OPCODE_IDX,
+               (NES_CQP_DESTROY_CQ | ((u32)nesvnic->nic_cq.cq_size << 16)));
+       set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_ID_IDX,
+               (nesvnic->nic_cq.cq_number | ((u32)nesdev->nic_ceq_index << 16)));
+
+       if (++cqp_head >= nesdev->cqp.sq_size)
+               cqp_head = 0;
+
+       nesdev->cqp.sq_head = cqp_head;
+       barrier();
+
+       /* Ring doorbell (2 WQEs) */
+       nes_write32(nesdev->regs+NES_WQE_ALLOC, 0x02800000 | nesdev->cqp.qp_id);
+
+       spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+       nes_debug(NES_DBG_SHUTDOWN, "Waiting for CQP, cqp_head=%u, cqp.sq_head=%u,"
+                       " cqp.sq_tail=%u, cqp.sq_size=%u\n",
+                       cqp_head, nesdev->cqp.sq_head,
+                       nesdev->cqp.sq_tail, nesdev->cqp.sq_size);
+
+       ret = wait_event_timeout(nesdev->cqp.waitq, (nesdev->cqp.sq_tail == cqp_head),
+                       NES_EVENT_TIMEOUT);
+
+       nes_debug(NES_DBG_SHUTDOWN, "Destroy NIC QP returned, wait_event_timeout ret = %u, cqp_head=%u,"
+                       " cqp.sq_head=%u, cqp.sq_tail=%u\n",
+                       ret, cqp_head, nesdev->cqp.sq_head, nesdev->cqp.sq_tail);
+       if (!ret) {
+               nes_debug(NES_DBG_SHUTDOWN, "NIC QP%u destroy timeout expired\n",
+                               nesvnic->nic.qp_id);
+       }
+
+       pci_free_consistent(nesdev->pcidev, nesvnic->nic_mem_size, nesvnic->nic_vbase,
+                       nesvnic->nic_pbase);
+}
+
+/**
+ * nes_napi_isr
+ */
+int nes_napi_isr(struct nes_device *nesdev)
+{
+       struct nes_adapter *nesadapter = nesdev->nesadapter;
+       u32 int_stat;
+
+       if (nesdev->napi_isr_ran) {
+               /* interrupt status has already been read in ISR */
+               int_stat = nesdev->int_stat;
+       } else {
+               int_stat = nes_read32(nesdev->regs + NES_INT_STAT);
+               nesdev->int_stat = int_stat;
+               nesdev->napi_isr_ran = 1;
+       }
+
+       int_stat &= nesdev->int_req;
+       /* iff NIC, process here, else wait for DPC */
+       if ((int_stat) && ((int_stat & 0x0000ff00) == int_stat)) {
+               nesdev->napi_isr_ran = 0;
+               nes_write32(nesdev->regs+NES_INT_STAT,
+                               (int_stat &
+                               ~(NES_INT_INTF|NES_INT_TIMER|NES_INT_MAC0|NES_INT_MAC1|NES_INT_MAC2|NES_INT_MAC3)));
+
+               /* Process the CEQs */
+               nes_process_ceq(nesdev, &nesdev->nesadapter->ceq[nesdev->nic_ceq_index]);
+
+               if (unlikely((((nesadapter->et_rx_coalesce_usecs_irq) &&
+                                          (!nesadapter->et_use_adaptive_rx_coalesce)) ||
+                                         ((nesadapter->et_use_adaptive_rx_coalesce) &&
+                                          (nesdev->deepcq_count > nesadapter->et_pkt_rate_low)))) ) {
+                       if ((nesdev->int_req & NES_INT_TIMER) == 0) {
+                               /* Enable Periodic timer interrupts */
+                               nesdev->int_req |= NES_INT_TIMER;
+                               /* ack any pending periodic timer interrupts so we don't get an immediate interrupt */
+                               /* TODO: need to also ack other unused periodic timer values, get from nesadapter */
+                               nes_write32(nesdev->regs+NES_TIMER_STAT,
+                                               nesdev->timer_int_req  | ~(nesdev->nesadapter->timer_int_req));
+                               nes_write32(nesdev->regs+NES_INTF_INT_MASK,
+                                               ~(nesdev->intf_int_req | NES_INTF_PERIODIC_TIMER));
+                       }
+
+                       if (unlikely(nesadapter->et_use_adaptive_rx_coalesce))
+                       {
+                               nes_nic_init_timer(nesdev);
+                       }
+                       /* Enable interrupts, except CEQs */
+                       nes_write32(nesdev->regs+NES_INT_MASK, 0x0000ffff | (~nesdev->int_req));
+               } else {
+                       /* Enable interrupts, make sure timer is off */
+                       nesdev->int_req &= ~NES_INT_TIMER;
+                       nes_write32(nesdev->regs+NES_INTF_INT_MASK, ~(nesdev->intf_int_req));
+                       nes_write32(nesdev->regs+NES_INT_MASK, ~nesdev->int_req);
+                       nesadapter->tune_timer.timer_in_use_old = 0;
+               }
+               nesdev->deepcq_count = 0;
+               return 1;
+       } else {
+               return 0;
+       }
+}
+
+
+/**
+ * nes_dpc
+ */
+void nes_dpc(unsigned long param)
+{
+       struct nes_device *nesdev = (struct nes_device *)param;
+       struct nes_adapter *nesadapter = nesdev->nesadapter;
+       u32 counter;
+       u32 loop_counter = 0;
+       u32 int_status_bit;
+       u32 int_stat;
+       u32 timer_stat;
+       u32 temp_int_stat;
+       u32 intf_int_stat;
+       u32 debug_error;
+       u32 processed_intf_int = 0;
+       u16 processed_timer_int = 0;
+       u16 completion_ints = 0;
+       u16 timer_ints = 0;
+
+       /* nes_debug(NES_DBG_ISR, "\n"); */
+
+       do {
+               timer_stat = 0;
+               if (nesdev->napi_isr_ran) {
+                       nesdev->napi_isr_ran = 0;
+                       int_stat = nesdev->int_stat;
+               } else
+                       int_stat = nes_read32(nesdev->regs+NES_INT_STAT);
+               if (processed_intf_int != 0)
+                       int_stat &= nesdev->int_req & ~NES_INT_INTF;
+               else
+                       int_stat &= nesdev->int_req;
+               if (processed_timer_int == 0) {
+                       processed_timer_int = 1;
+                       if (int_stat & NES_INT_TIMER) {
+                               timer_stat = nes_read32(nesdev->regs + NES_TIMER_STAT);
+                               if ((timer_stat & nesdev->timer_int_req) == 0) {
+                                       int_stat &= ~NES_INT_TIMER;
+                               }
+                       }
+               } else {
+                       int_stat &= ~NES_INT_TIMER;
+               }
+
+               if (int_stat) {
+                       if (int_stat & ~(NES_INT_INTF|NES_INT_TIMER|NES_INT_MAC0|
+                                       NES_INT_MAC1|NES_INT_MAC2|NES_INT_MAC3)) {
+                               /* Ack the interrupts */
+                               nes_write32(nesdev->regs+NES_INT_STAT,
+                                               (int_stat & ~(NES_INT_INTF|NES_INT_TIMER|NES_INT_MAC0|
+                                               NES_INT_MAC1|NES_INT_MAC2|NES_INT_MAC3)));
+                       }
+
+                       temp_int_stat = int_stat;
+                       for (counter = 0, int_status_bit = 1; counter < 16; counter++) {
+                               if (int_stat & int_status_bit) {
+                                       nes_process_ceq(nesdev, &nesadapter->ceq[counter]);
+                                       temp_int_stat &= ~int_status_bit;
+                                       completion_ints = 1;
+                               }
+                               if (!(temp_int_stat & 0x0000ffff))
+                                       break;
+                               int_status_bit <<= 1;
+                       }
+
+                       /* Process the AEQ for this pci function */
+                       int_status_bit = 1 << (16 + PCI_FUNC(nesdev->pcidev->devfn));
+                       if (int_stat & int_status_bit) {
+                               nes_process_aeq(nesdev, &nesadapter->aeq[PCI_FUNC(nesdev->pcidev->devfn)]);
+                       }
+
+                       /* Process the MAC interrupt for this pci function */
+                       int_status_bit = 1 << (24 + nesdev->mac_index);
+                       if (int_stat & int_status_bit) {
+                               nes_process_mac_intr(nesdev, nesdev->mac_index);
+                       }
+
+                       if (int_stat & NES_INT_TIMER) {
+                               if (timer_stat & nesdev->timer_int_req) {
+                                       nes_write32(nesdev->regs + NES_TIMER_STAT,
+                                                       (timer_stat & nesdev->timer_int_req) |
+                                                       ~(nesdev->nesadapter->timer_int_req));
+                                       timer_ints = 1;
+                               }
+                       }
+
+                       if (int_stat & NES_INT_INTF) {
+                               processed_intf_int = 1;
+                               intf_int_stat = nes_read32(nesdev->regs+NES_INTF_INT_STAT);
+                               intf_int_stat &= nesdev->intf_int_req;
+                               if (NES_INTF_INT_CRITERR & intf_int_stat) {
+                                       debug_error = nes_read_indexed(nesdev, NES_IDX_DEBUG_ERROR_CONTROL_STATUS);
+                                       printk(KERN_ERR PFX "Critical Error reported by device!!! 0x%02X\n",
+                                                       (u16)debug_error);
+                                       nes_write_indexed(nesdev, NES_IDX_DEBUG_ERROR_CONTROL_STATUS,
+                                                       0x01010000 | (debug_error & 0x0000ffff));
+                                       /* BUG(); */
+                                       if (crit_err_count++ > 10)
+                                               nes_write_indexed(nesdev, NES_IDX_DEBUG_ERROR_MASKS1, 1 << 0x17);
+                               }
+                               if (NES_INTF_INT_PCIERR & intf_int_stat) {
+                                       printk(KERN_ERR PFX "PCI Error reported by device!!!\n");
+                                       BUG();
+                               }
+                               if (NES_INTF_INT_AEQ_OFLOW & intf_int_stat) {
+                                       printk(KERN_ERR PFX "AEQ Overflow reported by device!!!\n");
+                                       BUG();
+                               }
+                               nes_write32(nesdev->regs+NES_INTF_INT_STAT, intf_int_stat);
+                       }
+
+                       if (int_stat & NES_INT_TSW) {
+                       }
+               }
+               /* Don't use the interface interrupt bit stay in loop */
+               int_stat &= ~NES_INT_INTF|NES_INT_TIMER|NES_INT_MAC0|
+                               NES_INT_MAC1|NES_INT_MAC2|NES_INT_MAC3;
+       } while ((int_stat != 0) && (loop_counter++ < MAX_DPC_ITERATIONS));
+
+       if (timer_ints == 1) {
+               if ((nesadapter->et_rx_coalesce_usecs_irq) || (nesadapter->et_use_adaptive_rx_coalesce)) {
+                       if (completion_ints == 0) {
+                               nesdev->timer_only_int_count++;
+                               if (nesdev->timer_only_int_count>=nesadapter->timer_int_limit) {
+                                       nesdev->timer_only_int_count = 0;
+                                       nesdev->int_req &= ~NES_INT_TIMER;
+                                       nes_write32(nesdev->regs + NES_INTF_INT_MASK, ~(nesdev->intf_int_req));
+                                       nes_write32(nesdev->regs+NES_INT_MASK, ~nesdev->int_req);
+                                       nesdev->nesadapter->tune_timer.timer_in_use_old = 0;
+                               } else {
+                                       nes_write32(nesdev->regs+NES_INT_MASK, 0x0000ffff|(~nesdev->int_req));
+                               }
+                       } else {
+                               if (unlikely(nesadapter->et_use_adaptive_rx_coalesce))
+                               {
+                                       nes_nic_init_timer(nesdev);
+                               }
+                               nesdev->timer_only_int_count = 0;
+                               nes_write32(nesdev->regs+NES_INT_MASK, 0x0000ffff|(~nesdev->int_req));
+                       }
+               } else {
+                       nesdev->timer_only_int_count = 0;
+                       nesdev->int_req &= ~NES_INT_TIMER;
+                       nes_write32(nesdev->regs+NES_INTF_INT_MASK, ~(nesdev->intf_int_req));
+                       nes_write32(nesdev->regs+NES_TIMER_STAT,
+                                       nesdev->timer_int_req | ~(nesdev->nesadapter->timer_int_req));
+                       nes_write32(nesdev->regs+NES_INT_MASK, ~nesdev->int_req);
+               }
+       } else {
+               if ( (completion_ints == 1) &&
+                        (((nesadapter->et_rx_coalesce_usecs_irq) &&
+                          (!nesadapter->et_use_adaptive_rx_coalesce)) ||
+                         ((nesdev->deepcq_count > nesadapter->et_pkt_rate_low) &&
+                          (nesadapter->et_use_adaptive_rx_coalesce) )) ) {
+                       /* nes_debug(NES_DBG_ISR, "Enabling periodic timer interrupt.\n" ); */
+                       nesdev->timer_only_int_count = 0;
+                       nesdev->int_req |= NES_INT_TIMER;
+                       nes_write32(nesdev->regs+NES_TIMER_STAT,
+                                       nesdev->timer_int_req | ~(nesdev->nesadapter->timer_int_req));
+                       nes_write32(nesdev->regs+NES_INTF_INT_MASK,
+                                       ~(nesdev->intf_int_req | NES_INTF_PERIODIC_TIMER));
+                       nes_write32(nesdev->regs+NES_INT_MASK, 0x0000ffff | (~nesdev->int_req));
+               } else {
+                       nes_write32(nesdev->regs+NES_INT_MASK, ~nesdev->int_req);
+               }
+       }
+       nesdev->deepcq_count = 0;
+}
+
+
+/**
+ * nes_process_ceq
+ */
+void nes_process_ceq(struct nes_device *nesdev, struct nes_hw_ceq *ceq)
+{
+       u64 u64temp;
+       struct nes_hw_cq *cq;
+       u32 head;
+       u32 ceq_size;
+
+       /* nes_debug(NES_DBG_CQ, "\n"); */
+       head = ceq->ceq_head;
+       ceq_size = ceq->ceq_size;
+
+       do {
+               if (le32_to_cpu(ceq->ceq_vbase[head].ceqe_words[NES_CEQE_CQ_CTX_HIGH_IDX]) &
+                               NES_CEQE_VALID) {
+                       u64temp = (((u64)(le32_to_cpu(ceq->ceq_vbase[head].ceqe_words[NES_CEQE_CQ_CTX_HIGH_IDX])))<<32) |
+                                               ((u64)(le32_to_cpu(ceq->ceq_vbase[head].ceqe_words[NES_CEQE_CQ_CTX_LOW_IDX])));
+                       u64temp <<= 1;
+                       cq = *((struct nes_hw_cq **)&u64temp);
+                       /* nes_debug(NES_DBG_CQ, "pCQ = %p\n", cq); */
+                       barrier();
+                       ceq->ceq_vbase[head].ceqe_words[NES_CEQE_CQ_CTX_HIGH_IDX] = 0;
+
+                       /* call the event handler */
+                       cq->ce_handler(nesdev, cq);
+
+                       if (++head >= ceq_size)
+                               head = 0;
+               } else {
+                       break;
+               }
+
+       } while (1);
+
+       ceq->ceq_head = head;
+}
+
+
+/**
+ * nes_process_aeq
+ */
+void nes_process_aeq(struct nes_device *nesdev, struct nes_hw_aeq *aeq)
+{
+//     u64 u64temp;
+       u32 head;
+       u32 aeq_size;
+       u32 aeqe_misc;
+       u32 aeqe_cq_id;
+       struct nes_hw_aeqe volatile *aeqe;
+
+       head = aeq->aeq_head;
+       aeq_size = aeq->aeq_size;
+
+       do {
+               aeqe = &aeq->aeq_vbase[head];
+               if ((le32_to_cpu(aeqe->aeqe_words[NES_AEQE_MISC_IDX]) & NES_AEQE_VALID) == 0)
+                       break;
+               aeqe_misc  = le32_to_cpu(aeqe->aeqe_words[NES_AEQE_MISC_IDX]);
+               aeqe_cq_id = le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX]);
+               if (aeqe_misc & (NES_AEQE_QP|NES_AEQE_CQ)) {
+                       if (aeqe_cq_id >= NES_FIRST_QPN) {
+                               /* dealing with an accelerated QP related AE */
+//                             u64temp = (((u64)(le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_CTXT_HIGH_IDX])))<<32) |
+//                                     ((u64)(le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_CTXT_LOW_IDX])));
+                               nes_process_iwarp_aeqe(nesdev, (struct nes_hw_aeqe *)aeqe);
+                       } else {
+                               /* TODO: dealing with a CQP related AE */
+                               nes_debug(NES_DBG_AEQ, "Processing CQP related AE, misc = 0x%04X\n",
+                                               (u16)(aeqe_misc >> 16));
+                       }
+               }
+
+               aeqe->aeqe_words[NES_AEQE_MISC_IDX] = 0;
+
+               if (++head >= aeq_size)
+                       head = 0;
+       }
+       while (1);
+       aeq->aeq_head = head;
+}
+
+static void nes_reset_link(struct nes_device *nesdev, u32 mac_index)
+{
+       struct nes_adapter *nesadapter = nesdev->nesadapter;
+       u32 reset_value;
+       u32 i=0;
+       u32 u32temp;
+
+       if (nesadapter->hw_rev == NE020_REV) {
+               return;
+       }
+       mh_detected++;
+
+       reset_value = nes_read32(nesdev->regs+NES_SOFTWARE_RESET);
+
+       if ((mac_index == 0) || ((mac_index == 1) && (nesadapter->OneG_Mode)))
+               reset_value |= 0x0000001d;
+       else
+               reset_value |= 0x0000002d;
+
+       if (4 <= (nesadapter->link_interrupt_count[mac_index] / ((u16)NES_MAX_LINK_INTERRUPTS))) {
+               if ((!nesadapter->OneG_Mode) && (nesadapter->port_count == 2)) {
+                       nesadapter->link_interrupt_count[0] = 0;
+                       nesadapter->link_interrupt_count[1] = 0;
+                       u32temp = nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL1);
+                       if (0x00000040 & u32temp)
+                               nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL1, 0x0000F088);
+                       else
+                               nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL1, 0x0000F0C8);
+
+                       reset_value |= 0x0000003d;
+               }
+               nesadapter->link_interrupt_count[mac_index] = 0;
+       }
+
+       nes_write32(nesdev->regs+NES_SOFTWARE_RESET, reset_value);
+
+       while (((nes_read32(nesdev->regs+NES_SOFTWARE_RESET)
+                       & 0x00000040) != 0x00000040) && (i++ < 5000));
+
+       if (0x0000003d == (reset_value & 0x0000003d)) {
+               u32 pcs_control_status0, pcs_control_status1;
+
+               for (i = 0; i < 10; i++) {
+                       pcs_control_status0 = nes_read_indexed(nesdev, NES_IDX_PHY_PCS_CONTROL_STATUS0);
+                       pcs_control_status1 = nes_read_indexed(nesdev, NES_IDX_PHY_PCS_CONTROL_STATUS0 + 0x200);
+                       if (((0x0F000000 == (pcs_control_status0 & 0x0F000000))
+                            && (pcs_control_status0 & 0x00100000))
+                           || ((0x0F000000 == (pcs_control_status1 & 0x0F000000))
+                               && (pcs_control_status1 & 0x00100000)))
+                               continue;
+                       else
+                               break;
+               }
+               if (10 == i) {
+                       u32temp = nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL1);
+                       if (0x00000040 & u32temp)
+                               nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL1, 0x0000F088);
+                       else
+                               nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL1, 0x0000F0C8);
+
+                       nes_write32(nesdev->regs+NES_SOFTWARE_RESET, reset_value);
+
+                       while (((nes_read32(nesdev->regs + NES_SOFTWARE_RESET)
+                                & 0x00000040) != 0x00000040) && (i++ < 5000));
+               }
+       }
+}
+
+/**
+ * nes_process_mac_intr
+ */
+void nes_process_mac_intr(struct nes_device *nesdev, u32 mac_number)
+{
+       unsigned long flags;
+       u32 pcs_control_status;
+       struct nes_adapter *nesadapter = nesdev->nesadapter;
+       struct nes_vnic *nesvnic;
+       u32 mac_status;
+       u32 mac_index = nesdev->mac_index;
+       u32 u32temp;
+       u16 phy_data;
+       u16 temp_phy_data;
+
+       spin_lock_irqsave(&nesadapter->phy_lock, flags);
+       if (nesadapter->mac_sw_state[mac_number] != NES_MAC_SW_IDLE) {
+               spin_unlock_irqrestore(&nesadapter->phy_lock, flags);
+               return;
+       }
+       nesadapter->mac_sw_state[mac_number] = NES_MAC_SW_INTERRUPT;
+       spin_unlock_irqrestore(&nesadapter->phy_lock, flags);
+
+       /* ack the MAC interrupt */
+       mac_status = nes_read_indexed(nesdev, NES_IDX_MAC_INT_STATUS + (mac_index * 0x200));
+       /* Clear the interrupt */
+       nes_write_indexed(nesdev, NES_IDX_MAC_INT_STATUS + (mac_index * 0x200), mac_status);
+
+       nes_debug(NES_DBG_PHY, "MAC%u interrupt status = 0x%X.\n", mac_number, mac_status);
+
+       if (mac_status & (NES_MAC_INT_LINK_STAT_CHG | NES_MAC_INT_XGMII_EXT)) {
+               nesdev->link_status_interrupts++;
+               if (0 == (++nesadapter->link_interrupt_count[mac_index] % ((u16)NES_MAX_LINK_INTERRUPTS))) {
+                       spin_lock_irqsave(&nesadapter->phy_lock, flags);
+                       nes_reset_link(nesdev, mac_index);
+                       spin_unlock_irqrestore(&nesadapter->phy_lock, flags);
+               }
+               /* read the PHY interrupt status register */
+               if (nesadapter->OneG_Mode) {
+                       do {
+                               nes_read_1G_phy_reg(nesdev, 0x1a,
+                                               nesadapter->phy_index[mac_index], &phy_data);
+                               nes_debug(NES_DBG_PHY, "Phy%d data from register 0x1a = 0x%X.\n",
+                                               nesadapter->phy_index[mac_index], phy_data);
+                       } while (phy_data&0x8000);
+
+                       temp_phy_data = 0;
+                       do {
+                               nes_read_1G_phy_reg(nesdev, 0x11,
+                                               nesadapter->phy_index[mac_index], &phy_data);
+                               nes_debug(NES_DBG_PHY, "Phy%d data from register 0x11 = 0x%X.\n",
+                                               nesadapter->phy_index[mac_index], phy_data);
+                               if (temp_phy_data == phy_data)
+                                       break;
+                               temp_phy_data = phy_data;
+                       } while (1);
+
+                       nes_read_1G_phy_reg(nesdev, 0x1e,
+                                       nesadapter->phy_index[mac_index], &phy_data);
+                       nes_debug(NES_DBG_PHY, "Phy%d data from register 0x1e = 0x%X.\n",
+                                       nesadapter->phy_index[mac_index], phy_data);
+
+                       nes_read_1G_phy_reg(nesdev, 1,
+                                       nesadapter->phy_index[mac_index], &phy_data);
+                       nes_debug(NES_DBG_PHY, "1G phy%u data from register 1 = 0x%X\n",
+                                       nesadapter->phy_index[mac_index], phy_data);
+
+                       if (temp_phy_data & 0x1000) {
+                               nes_debug(NES_DBG_PHY, "The Link is up according to the PHY\n");
+                               phy_data = 4;
+                       } else {
+                               nes_debug(NES_DBG_PHY, "The Link is down according to the PHY\n");
+                       }
+               }
+               nes_debug(NES_DBG_PHY, "Eth SERDES Common Status: 0=0x%08X, 1=0x%08X\n",
+                               nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_STATUS0),
+                               nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_STATUS0+0x200));
+               pcs_control_status = nes_read_indexed(nesdev,
+                               NES_IDX_PHY_PCS_CONTROL_STATUS0 + ((mac_index&1)*0x200));
+               pcs_control_status = nes_read_indexed(nesdev,
+                               NES_IDX_PHY_PCS_CONTROL_STATUS0 + ((mac_index&1)*0x200));
+               nes_debug(NES_DBG_PHY, "PCS PHY Control/Status%u: 0x%08X\n",
+                               mac_index, pcs_control_status);
+               if (nesadapter->OneG_Mode) {
+                       u32temp = 0x01010000;
+                       if (nesadapter->port_count > 2) {
+                               u32temp |= 0x02020000;
+                       }
+                       if ((pcs_control_status & u32temp)!= u32temp) {
+                               phy_data = 0;
+                               nes_debug(NES_DBG_PHY, "PCS says the link is down\n");
+                       }
+               } else if (nesadapter->phy_type[mac_index] == NES_PHY_TYPE_IRIS) {
+                       nes_read_10G_phy_reg(nesdev, 1, nesadapter->phy_index[mac_index]);
+                       temp_phy_data = (u16)nes_read_indexed(nesdev,
+                                                               NES_IDX_MAC_MDIO_CONTROL);
+                       u32temp = 20;
+                       do {
+                               nes_read_10G_phy_reg(nesdev, 1, nesadapter->phy_index[mac_index]);
+                               phy_data = (u16)nes_read_indexed(nesdev,
+                                                               NES_IDX_MAC_MDIO_CONTROL);
+                               if ((phy_data == temp_phy_data) || (!(--u32temp)))
+                                       break;
+                               temp_phy_data = phy_data;
+                       } while (1);
+                       nes_debug(NES_DBG_PHY, "%s: Phy data = 0x%04X, link was %s.\n",
+                               __FUNCTION__, phy_data, nesadapter->mac_link_down ? "DOWN" : "UP");
+
+               } else {
+                       phy_data = (0x0f0f0000 == (pcs_control_status & 0x0f1f0000)) ? 4 : 0;
+               }
+
+               if (phy_data & 0x0004) {
+                       nesadapter->mac_link_down[mac_index] = 0;
+                       list_for_each_entry(nesvnic, &nesadapter->nesvnic_list[mac_index], list) {
+                               nes_debug(NES_DBG_PHY, "The Link is UP!!.  linkup was %d\n",
+                                               nesvnic->linkup);
+                               if (nesvnic->linkup == 0) {
+                                       printk(PFX "The Link is now up for port %u, netdev %p.\n",
+                                                       mac_index, nesvnic->netdev);
+                                       if (netif_queue_stopped(nesvnic->netdev))
+                                               netif_start_queue(nesvnic->netdev);
+                                       nesvnic->linkup = 1;
+                                       netif_carrier_on(nesvnic->netdev);
+                               }
+                       }
+               } else {
+                       nesadapter->mac_link_down[mac_index] = 1;
+                       list_for_each_entry(nesvnic, &nesadapter->nesvnic_list[mac_index], list) {
+                               nes_debug(NES_DBG_PHY, "The Link is Down!!. linkup was %d\n",
+                                               nesvnic->linkup);
+                               if (nesvnic->linkup == 1) {
+                                       printk(PFX "The Link is now down for port %u, netdev %p.\n",
+                                                       mac_index, nesvnic->netdev);
+                                       if (!(netif_queue_stopped(nesvnic->netdev)))
+                                               netif_stop_queue(nesvnic->netdev);
+                                       nesvnic->linkup = 0;
+                                       netif_carrier_off(nesvnic->netdev);
+                               }
+                       }
+               }
+       }
+
+       nesadapter->mac_sw_state[mac_number] = NES_MAC_SW_IDLE;
+}
+
+
+
+void nes_nic_napi_ce_handler(struct nes_device *nesdev, struct nes_hw_nic_cq *cq)
+{
+       struct nes_vnic *nesvnic = container_of(cq, struct nes_vnic, nic_cq);
+
+       netif_rx_schedule(nesdev->netdev[nesvnic->netdev_index], &nesvnic->napi);
+}
+
+
+/* The MAX_RQES_TO_PROCESS defines how many max read requests to complete before
+* getting out of nic_ce_handler
+*/
+#define        MAX_RQES_TO_PROCESS     384
+
+/**
+ * nes_nic_ce_handler
+ */
+void nes_nic_ce_handler(struct nes_device *nesdev, struct nes_hw_nic_cq *cq)
+{
+       u64 u64temp;
+       dma_addr_t bus_address;
+       struct nes_hw_nic *nesnic;
+       struct nes_vnic *nesvnic = container_of(cq, struct nes_vnic, nic_cq);
+       struct nes_adapter *nesadapter = nesdev->nesadapter;
+       struct nes_hw_nic_rq_wqe *nic_rqe;
+       struct nes_hw_nic_sq_wqe *nic_sqe;
+       struct sk_buff *skb;
+       struct sk_buff *rx_skb;
+       __le16 *wqe_fragment_length;
+       u32 head;
+       u32 cq_size;
+       u32 rx_pkt_size;
+       u32 cqe_count=0;
+       u32 cqe_errv;
+       u32 cqe_misc;
+       u16 wqe_fragment_index = 1;     /* first fragment (0) is used by copy buffer */
+       u16 vlan_tag;
+       u16 pkt_type;
+       u16 rqes_processed = 0;
+       u8 sq_cqes = 0;
+
+       head = cq->cq_head;
+       cq_size = cq->cq_size;
+       cq->cqes_pending = 1;
+       do {
+               if (le32_to_cpu(cq->cq_vbase[head].cqe_words[NES_NIC_CQE_MISC_IDX]) &
+                               NES_NIC_CQE_VALID) {
+                       nesnic = &nesvnic->nic;
+                       cqe_misc = le32_to_cpu(cq->cq_vbase[head].cqe_words[NES_NIC_CQE_MISC_IDX]);
+                       if (cqe_misc & NES_NIC_CQE_SQ) {
+                               sq_cqes++;
+                               wqe_fragment_index = 1;
+                               nic_sqe = &nesnic->sq_vbase[nesnic->sq_tail];
+                               skb = nesnic->tx_skb[nesnic->sq_tail];
+                               wqe_fragment_length = (__le16 *)&nic_sqe->wqe_words[NES_NIC_SQ_WQE_LENGTH_0_TAG_IDX];
+                               /* bump past the vlan tag */
+                               wqe_fragment_length++;
+                               if (le16_to_cpu(wqe_fragment_length[wqe_fragment_index]) != 0) {
+                                       u64temp = (u64) le32_to_cpu(nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG0_LOW_IDX+wqe_fragment_index*2]);
+                                       u64temp += ((u64)le32_to_cpu(nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG0_HIGH_IDX+wqe_fragment_index*2]))<<32;
+                                       bus_address = (dma_addr_t)u64temp;
+                                       if (test_and_clear_bit(nesnic->sq_tail, nesnic->first_frag_overflow)) {
+                                               pci_unmap_single(nesdev->pcidev,
+                                                               bus_address,
+                                                               le16_to_cpu(wqe_fragment_length[wqe_fragment_index++]),
+                                                               PCI_DMA_TODEVICE);
+                                       }
+                                       for (; wqe_fragment_index < 5; wqe_fragment_index++) {
+                                               if (wqe_fragment_length[wqe_fragment_index]) {
+                                                       u64temp = le32_to_cpu(nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG0_LOW_IDX+wqe_fragment_index*2]);
+                                                       u64temp += ((u64)le32_to_cpu(nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG0_HIGH_IDX+wqe_fragment_index*2]))<<32;
+                                                       bus_address = (dma_addr_t)u64temp;
+                                                       pci_unmap_page(nesdev->pcidev,
+                                                                       bus_address,
+                                                                       le16_to_cpu(wqe_fragment_length[wqe_fragment_index]),
+                                                                       PCI_DMA_TODEVICE);
+                                               } else
+                                                       break;
+                                       }
+                                       if (skb)
+                                               dev_kfree_skb_any(skb);
+                               }
+                               nesnic->sq_tail++;
+                               nesnic->sq_tail &= nesnic->sq_size-1;
+                               if (sq_cqes > 128) {
+                                       barrier();
+                               /* restart the queue if it had been stopped */
+                               if (netif_queue_stopped(nesvnic->netdev))
+                                       netif_wake_queue(nesvnic->netdev);
+                                       sq_cqes = 0;
+                               }
+                       } else {
+                               rqes_processed ++;
+
+                               cq->rx_cqes_completed++;
+                               cq->rx_pkts_indicated++;
+                               rx_pkt_size = cqe_misc & 0x0000ffff;
+                               nic_rqe = &nesnic->rq_vbase[nesnic->rq_tail];
+                               /* Get the skb */
+                               rx_skb = nesnic->rx_skb[nesnic->rq_tail];
+                               nic_rqe = &nesnic->rq_vbase[nesvnic->nic.rq_tail];
+                               bus_address = (dma_addr_t)le32_to_cpu(nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_LOW_IDX]);
+                               bus_address += ((u64)le32_to_cpu(nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_HIGH_IDX])) << 32;
+                               pci_unmap_single(nesdev->pcidev, bus_address,
+                                               nesvnic->max_frame_size, PCI_DMA_FROMDEVICE);
+                               /* rx_skb->tail = rx_skb->data + rx_pkt_size; */
+                               /* rx_skb->len = rx_pkt_size; */
+                               rx_skb->len = 0;  /* TODO: see if this is necessary */
+                               skb_put(rx_skb, rx_pkt_size);
+                               rx_skb->protocol = eth_type_trans(rx_skb, nesvnic->netdev);
+                               nesnic->rq_tail++;
+                               nesnic->rq_tail &= nesnic->rq_size - 1;
+
+                               atomic_inc(&nesvnic->rx_skbs_needed);
+                               if (atomic_read(&nesvnic->rx_skbs_needed) > (nesvnic->nic.rq_size>>1)) {
+                                       nes_write32(nesdev->regs+NES_CQE_ALLOC,
+                                                       cq->cq_number | (cqe_count << 16));
+//                                     nesadapter->tune_timer.cq_count += cqe_count;
+                                       nesdev->currcq_count += cqe_count;
+                                       cqe_count = 0;
+                                       nes_replenish_nic_rq(nesvnic);
+                               }
+                               pkt_type = (u16)(le32_to_cpu(cq->cq_vbase[head].cqe_words[NES_NIC_CQE_TAG_PKT_TYPE_IDX]));
+                               cqe_errv = (cqe_misc & NES_NIC_CQE_ERRV_MASK) >> NES_NIC_CQE_ERRV_SHIFT;
+                               rx_skb->ip_summed = CHECKSUM_NONE;
+
+                               if ((NES_PKT_TYPE_TCPV4_BITS == (pkt_type & NES_PKT_TYPE_TCPV4_MASK)) ||
+                                               (NES_PKT_TYPE_UDPV4_BITS == (pkt_type & NES_PKT_TYPE_UDPV4_MASK))) {
+                                       if ((cqe_errv &
+                                                       (NES_NIC_ERRV_BITS_IPV4_CSUM_ERR | NES_NIC_ERRV_BITS_TCPUDP_CSUM_ERR |
+                                                       NES_NIC_ERRV_BITS_IPH_ERR | NES_NIC_ERRV_BITS_WQE_OVERRUN)) == 0) {
+                                               if (nesvnic->rx_checksum_disabled == 0) {
+                                                       rx_skb->ip_summed = CHECKSUM_UNNECESSARY;
+                                               }
+                                       } else
+                                               nes_debug(NES_DBG_CQ, "%s: unsuccessfully checksummed TCP or UDP packet."
+                                                               " errv = 0x%X, pkt_type = 0x%X.\n",
+                                                               nesvnic->netdev->name, cqe_errv, pkt_type);
+
+                               } else if ((pkt_type & NES_PKT_TYPE_IPV4_MASK) == NES_PKT_TYPE_IPV4_BITS) {
+                                       if ((cqe_errv &
+                                                       (NES_NIC_ERRV_BITS_IPV4_CSUM_ERR | NES_NIC_ERRV_BITS_IPH_ERR |
+                                                       NES_NIC_ERRV_BITS_WQE_OVERRUN)) == 0) {
+                                               if (nesvnic->rx_checksum_disabled == 0) {
+                                                       rx_skb->ip_summed = CHECKSUM_UNNECESSARY;
+                                                       /* nes_debug(NES_DBG_CQ, "%s: Reporting successfully checksummed IPv4 packet.\n",
+                                                                 nesvnic->netdev->name); */
+                                               }
+                                       } else
+                                               nes_debug(NES_DBG_CQ, "%s: unsuccessfully checksummed TCP or UDP packet."
+                                                               " errv = 0x%X, pkt_type = 0x%X.\n",
+                                                               nesvnic->netdev->name, cqe_errv, pkt_type);
+                                       }
+                               /* nes_debug(NES_DBG_CQ, "pkt_type=%x, APBVT_MASK=%x\n",
+                                                       pkt_type, (pkt_type & NES_PKT_TYPE_APBVT_MASK)); */
+
+                               if ((pkt_type & NES_PKT_TYPE_APBVT_MASK) == NES_PKT_TYPE_APBVT_BITS) {
+                                       nes_cm_recv(rx_skb, nesvnic->netdev);
+                               } else {
+                                       if ((cqe_misc & NES_NIC_CQE_TAG_VALID) && (nesvnic->vlan_grp != NULL)) {
+                                               vlan_tag = (u16)(le32_to_cpu(
+                                                               cq->cq_vbase[head].cqe_words[NES_NIC_CQE_TAG_PKT_TYPE_IDX])
+                                                               >> 16);
+                                               nes_debug(NES_DBG_CQ, "%s: Reporting stripped VLAN packet. Tag = 0x%04X\n",
+                                                               nesvnic->netdev->name, vlan_tag);
+                                               nes_vlan_rx(rx_skb, nesvnic->vlan_grp, vlan_tag);
+                                       } else {
+                                               nes_netif_rx(rx_skb);
+                                       }
+                               }
+
+                               nesvnic->netdev->last_rx = jiffies;
+                               /* nesvnic->netstats.rx_packets++; */
+                               /* nesvnic->netstats.rx_bytes += rx_pkt_size; */
+                       }
+
+                       cq->cq_vbase[head].cqe_words[NES_NIC_CQE_MISC_IDX] = 0;
+                       /* Accounting... */
+                       cqe_count++;
+                       if (++head >= cq_size)
+                               head = 0;
+                       if (cqe_count == 255) {
+                               /* Replenish Nic CQ */
+                               nes_write32(nesdev->regs+NES_CQE_ALLOC,
+                                               cq->cq_number | (cqe_count << 16));
+//                             nesdev->nesadapter->tune_timer.cq_count += cqe_count;
+                               nesdev->currcq_count += cqe_count;
+                               cqe_count = 0;
+                       }
+
+                       if (cq->rx_cqes_completed >= nesvnic->budget)
+                               break;
+               } else {
+                       cq->cqes_pending = 0;
+                       break;
+               }
+
+       } while (1);
+
+       if (sq_cqes) {
+               barrier();
+               /* restart the queue if it had been stopped */
+               if (netif_queue_stopped(nesvnic->netdev))
+                       netif_wake_queue(nesvnic->netdev);
+       }
+
+       cq->cq_head = head;
+       /* nes_debug(NES_DBG_CQ, "CQ%u Processed = %u cqes, new head = %u.\n",
+                       cq->cq_number, cqe_count, cq->cq_head); */
+       cq->cqe_allocs_pending = cqe_count;
+       if (unlikely(nesadapter->et_use_adaptive_rx_coalesce))
+       {
+//             nesdev->nesadapter->tune_timer.cq_count += cqe_count;
+               nesdev->currcq_count += cqe_count;
+               nes_nic_tune_timer(nesdev);
+       }
+       if (atomic_read(&nesvnic->rx_skbs_needed))
+               nes_replenish_nic_rq(nesvnic);
+       }
+
+
+/**
+ * nes_cqp_ce_handler
+ */
+void nes_cqp_ce_handler(struct nes_device *nesdev, struct nes_hw_cq *cq)
+{
+       u64 u64temp;
+       unsigned long flags;
+       struct nes_hw_cqp *cqp = NULL;
+       struct nes_cqp_request *cqp_request;
+       struct nes_hw_cqp_wqe *cqp_wqe;
+       u32 head;
+       u32 cq_size;
+       u32 cqe_count=0;
+       u32 error_code;
+       /* u32 counter; */
+
+       head = cq->cq_head;
+       cq_size = cq->cq_size;
+
+       do {
+               /* process the CQE */
+               /* nes_debug(NES_DBG_CQP, "head=%u cqe_words=%08X\n", head,
+                         le32_to_cpu(cq->cq_vbase[head].cqe_words[NES_CQE_OPCODE_IDX])); */
+
+               if (le32_to_cpu(cq->cq_vbase[head].cqe_words[NES_CQE_OPCODE_IDX]) & NES_CQE_VALID) {
+                       u64temp = (((u64)(le32_to_cpu(cq->cq_vbase[head].
+                                       cqe_words[NES_CQE_COMP_COMP_CTX_HIGH_IDX])))<<32) |
+                                       ((u64)(le32_to_cpu(cq->cq_vbase[head].
+                                       cqe_words[NES_CQE_COMP_COMP_CTX_LOW_IDX])));
+                       cqp = *((struct nes_hw_cqp **)&u64temp);
+
+                       error_code = le32_to_cpu(cq->cq_vbase[head].cqe_words[NES_CQE_ERROR_CODE_IDX]);
+                       if (error_code) {
+                               nes_debug(NES_DBG_CQP, "Bad Completion code for opcode 0x%02X from CQP,"
+                                               " Major/Minor codes = 0x%04X:%04X.\n",
+                                               le32_to_cpu(cq->cq_vbase[head].cqe_words[NES_CQE_OPCODE_IDX])&0x3f,
+                                               (u16)(error_code >> 16),
+                                               (u16)error_code);
+                               nes_debug(NES_DBG_CQP, "cqp: qp_id=%u, sq_head=%u, sq_tail=%u\n",
+                                               cqp->qp_id, cqp->sq_head, cqp->sq_tail);
+                       }
+
+                       u64temp = (((u64)(le32_to_cpu(nesdev->cqp.sq_vbase[cqp->sq_tail].
+                                       wqe_words[NES_CQP_WQE_COMP_SCRATCH_HIGH_IDX])))<<32) |
+                                       ((u64)(le32_to_cpu(nesdev->cqp.sq_vbase[cqp->sq_tail].
+                                       wqe_words[NES_CQP_WQE_COMP_SCRATCH_LOW_IDX])));
+                       cqp_request = *((struct nes_cqp_request **)&u64temp);
+                       if (cqp_request) {
+                               if (cqp_request->waiting) {
+                                       /* nes_debug(NES_DBG_CQP, "%s: Waking up requestor\n"); */
+                                       cqp_request->major_code = (u16)(error_code >> 16);
+                                       cqp_request->minor_code = (u16)error_code;
+                                       barrier();
+                                       cqp_request->request_done = 1;
+                                       wake_up(&cqp_request->waitq);
+                                       if (atomic_dec_and_test(&cqp_request->refcount)) {
+                                               nes_debug(NES_DBG_CQP, "CQP request %p (opcode 0x%02X) freed.\n",
+                                                               cqp_request,
+                                                               le32_to_cpu(cqp_request->cqp_wqe.wqe_words[NES_CQP_WQE_OPCODE_IDX])&0x3f);
+                                               if (cqp_request->dynamic) {
+                                                       kfree(cqp_request);
+                                               } else {
+                                                       spin_lock_irqsave(&nesdev->cqp.lock, flags);
+                                                       list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs);
+                                                       spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+                                               }
+                                       }
+                               } else if (cqp_request->callback) {
+                                       /* Envoke the callback routine */
+                                       cqp_request->cqp_callback(nesdev, cqp_request);
+                                       if (cqp_request->dynamic) {
+                                               kfree(cqp_request);
+                                       } else {
+                                               spin_lock_irqsave(&nesdev->cqp.lock, flags);
+                                               list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs);
+                                               spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+                                       }
+                               } else {
+                                       nes_debug(NES_DBG_CQP, "CQP request %p (opcode 0x%02X) freed.\n",
+                                                       cqp_request,
+                                                       le32_to_cpu(cqp_request->cqp_wqe.wqe_words[NES_CQP_WQE_OPCODE_IDX])&0x3f);
+                                       if (cqp_request->dynamic) {
+                                               kfree(cqp_request);
+                                       } else {
+                                               spin_lock_irqsave(&nesdev->cqp.lock, flags);
+                                               list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs);
+                                               spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+                                       }
+                               }
+                       } else {
+                               wake_up(&nesdev->cqp.waitq);
+                       }
+
+                       cq->cq_vbase[head].cqe_words[NES_CQE_OPCODE_IDX] = 0;
+                       nes_write32(nesdev->regs+NES_CQE_ALLOC, cq->cq_number | (1 << 16));
+                       if (++cqp->sq_tail >= cqp->sq_size)
+                               cqp->sq_tail = 0;
+
+                       /* Accounting... */
+                       cqe_count++;
+                       if (++head >= cq_size)
+                               head = 0;
+               } else {
+                       break;
+               }
+       } while (1);
+       cq->cq_head = head;
+
+       spin_lock_irqsave(&nesdev->cqp.lock, flags);
+       while ((!list_empty(&nesdev->cqp_pending_reqs)) &&
+                       ((((nesdev->cqp.sq_tail+nesdev->cqp.sq_size)-nesdev->cqp.sq_head) &
+                       (nesdev->cqp.sq_size - 1)) != 1)) {
+               cqp_request = list_entry(nesdev->cqp_pending_reqs.next,
+                               struct nes_cqp_request, list);
+               list_del_init(&cqp_request->list);
+               head = nesdev->cqp.sq_head++;
+               nesdev->cqp.sq_head &= nesdev->cqp.sq_size-1;
+               cqp_wqe = &nesdev->cqp.sq_vbase[head];
+               memcpy(cqp_wqe, &cqp_request->cqp_wqe, sizeof(*cqp_wqe));
+               barrier();
+               cqp_wqe->wqe_words[NES_CQP_WQE_COMP_SCRATCH_LOW_IDX] =
+                       cpu_to_le32((u32)((unsigned long)cqp_request));
+               cqp_wqe->wqe_words[NES_CQP_WQE_COMP_SCRATCH_HIGH_IDX] =
+                       cpu_to_le32((u32)(upper_32_bits((unsigned long)cqp_request)));
+               nes_debug(NES_DBG_CQP, "CQP request %p (opcode 0x%02X) put on CQPs SQ wqe%u.\n",
+                               cqp_request, le32_to_cpu(cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX])&0x3f, head);
+               /* Ring doorbell (1 WQEs) */
+               barrier();
+               nes_write32(nesdev->regs+NES_WQE_ALLOC, 0x01800000 | nesdev->cqp.qp_id);
+       }
+       spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+
+       /* Arm the CCQ */
+       nes_write32(nesdev->regs+NES_CQE_ALLOC, NES_CQE_ALLOC_NOTIFY_NEXT |
+                       cq->cq_number);
+       nes_read32(nesdev->regs+NES_CQE_ALLOC);
+}
+
+
+/**
+ * nes_process_iwarp_aeqe
+ */
+void nes_process_iwarp_aeqe(struct nes_device *nesdev, struct nes_hw_aeqe *aeqe)
+{
+       u64 context;
+       u64 aeqe_context = 0;
+       unsigned long flags;
+       struct nes_qp *nesqp;
+       int resource_allocated;
+       /* struct iw_cm_id *cm_id; */
+       struct nes_adapter *nesadapter = nesdev->nesadapter;
+       struct ib_event ibevent;
+       /* struct iw_cm_event cm_event; */
+       u32 aeq_info;
+       u32 next_iwarp_state = 0;
+       u16 async_event_id;
+       u8 tcp_state;
+       u8 iwarp_state;
+
+       nes_debug(NES_DBG_AEQ, "\n");
+       aeq_info = le32_to_cpu(aeqe->aeqe_words[NES_AEQE_MISC_IDX]);
+       if ((NES_AEQE_INBOUND_RDMA&aeq_info) || (!(NES_AEQE_QP&aeq_info))) {
+               context = le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_CTXT_LOW_IDX]);
+               context += ((u64)le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_CTXT_HIGH_IDX])) << 32;
+       } else {
+               aeqe_context = le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_CTXT_LOW_IDX]);
+               aeqe_context += ((u64)le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_CTXT_HIGH_IDX])) << 32;
+               context = (unsigned long)nesadapter->qp_table[le32_to_cpu(
+                                               aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX])-NES_FIRST_QPN];
+               BUG_ON(!context);
+       }
+
+       async_event_id = (u16)aeq_info;
+       tcp_state = (aeq_info & NES_AEQE_TCP_STATE_MASK) >> NES_AEQE_TCP_STATE_SHIFT;
+       iwarp_state = (aeq_info & NES_AEQE_IWARP_STATE_MASK) >> NES_AEQE_IWARP_STATE_SHIFT;
+       nes_debug(NES_DBG_AEQ, "aeid = 0x%04X, qp-cq id = %d, aeqe = %p,"
+                       " Tcp state = %s, iWARP state = %s\n",
+                       async_event_id,
+                       le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX]), aeqe,
+                       nes_tcp_state_str[tcp_state], nes_iwarp_state_str[iwarp_state]);
+
+
+       switch (async_event_id) {
+               case NES_AEQE_AEID_LLP_FIN_RECEIVED:
+                       nesqp = *((struct nes_qp **)&context);
+                       if (atomic_inc_return(&nesqp->close_timer_started) == 1) {
+                               nesqp->cm_id->add_ref(nesqp->cm_id);
+                               nes_add_ref(&nesqp->ibqp);
+                               schedule_nes_timer(nesqp->cm_node, (struct sk_buff *)nesqp,
+                                               NES_TIMER_TYPE_CLOSE, 1, 0);
+                               nes_debug(NES_DBG_AEQ, "QP%u Not decrementing QP refcount (%d),"
+                                               " need ae to finish up, original_last_aeq = 0x%04X."
+                                               " last_aeq = 0x%04X, scheduling timer. TCP state = %d\n",
+                                               nesqp->hwqp.qp_id, atomic_read(&nesqp->refcount),
+                                               async_event_id, nesqp->last_aeq, tcp_state);
+                       }
+                       if ((tcp_state != NES_AEQE_TCP_STATE_CLOSE_WAIT) ||
+                                       (nesqp->ibqp_state != IB_QPS_RTS)) {
+                               /* FIN Received but tcp state or IB state moved on,
+                                               should expect a close complete */
+                               return;
+                       }
+               case NES_AEQE_AEID_LLP_CLOSE_COMPLETE:
+               case NES_AEQE_AEID_LLP_CONNECTION_RESET:
+               case NES_AEQE_AEID_TERMINATE_SENT:
+               case NES_AEQE_AEID_RDMAP_ROE_BAD_LLP_CLOSE:
+               case NES_AEQE_AEID_RESET_SENT:
+                       nesqp = *((struct nes_qp **)&context);
+                       if (async_event_id == NES_AEQE_AEID_RESET_SENT) {
+                               tcp_state = NES_AEQE_TCP_STATE_CLOSED;
+                       }
+                       nes_add_ref(&nesqp->ibqp);
+                       spin_lock_irqsave(&nesqp->lock, flags);
+                       nesqp->hw_iwarp_state = iwarp_state;
+                       nesqp->hw_tcp_state = tcp_state;
+                       nesqp->last_aeq = async_event_id;
+
+                       if ((tcp_state == NES_AEQE_TCP_STATE_CLOSED) ||
+                                       (tcp_state == NES_AEQE_TCP_STATE_TIME_WAIT)) {
+                               nesqp->hte_added = 0;
+                               spin_unlock_irqrestore(&nesqp->lock, flags);
+                               nes_debug(NES_DBG_AEQ, "issuing hw modifyqp for QP%u to remove hte\n",
+                                               nesqp->hwqp.qp_id);
+                               nes_hw_modify_qp(nesdev, nesqp,
+                                               NES_CQP_QP_IWARP_STATE_ERROR | NES_CQP_QP_DEL_HTE, 0);
+                               spin_lock_irqsave(&nesqp->lock, flags);
+                       }
+
+                       if ((nesqp->ibqp_state == IB_QPS_RTS) &&
+                                       ((tcp_state == NES_AEQE_TCP_STATE_CLOSE_WAIT) ||
+                                       (async_event_id == NES_AEQE_AEID_LLP_CONNECTION_RESET))) {
+                               switch (nesqp->hw_iwarp_state) {
+                                       case NES_AEQE_IWARP_STATE_RTS:
+                                               next_iwarp_state = NES_CQP_QP_IWARP_STATE_CLOSING;
+                                               nesqp->hw_iwarp_state = NES_AEQE_IWARP_STATE_CLOSING;
+                                               break;
+                                       case NES_AEQE_IWARP_STATE_TERMINATE:
+                                               next_iwarp_state = NES_CQP_QP_IWARP_STATE_TERMINATE;
+                                               nesqp->hw_iwarp_state = NES_AEQE_IWARP_STATE_TERMINATE;
+                                               if (async_event_id == NES_AEQE_AEID_RDMAP_ROE_BAD_LLP_CLOSE) {
+                                                       next_iwarp_state |= 0x02000000;
+                                                       nesqp->hw_tcp_state = NES_AEQE_TCP_STATE_CLOSED;
+                                               }
+                                               break;
+                                       default:
+                                               next_iwarp_state = 0;
+                               }
+                               spin_unlock_irqrestore(&nesqp->lock, flags);
+                               if (next_iwarp_state) {
+                                       nes_add_ref(&nesqp->ibqp);
+                                       nes_debug(NES_DBG_AEQ, "issuing hw modifyqp for QP%u. next state = 0x%08X,"
+                                                       " also added another reference\n",
+                                                       nesqp->hwqp.qp_id, next_iwarp_state);
+                                       nes_hw_modify_qp(nesdev, nesqp, next_iwarp_state, 0);
+                               }
+                               nes_cm_disconn(nesqp);
+                       } else {
+                               if (async_event_id ==  NES_AEQE_AEID_LLP_FIN_RECEIVED) {
+                                       /* FIN Received but ib state not RTS,
+                                                       close complete will be on its way */
+                                       spin_unlock_irqrestore(&nesqp->lock, flags);
+                                       nes_rem_ref(&nesqp->ibqp);
+                                       return;
+                               }
+                               spin_unlock_irqrestore(&nesqp->lock, flags);
+                               if (async_event_id == NES_AEQE_AEID_RDMAP_ROE_BAD_LLP_CLOSE) {
+                                       next_iwarp_state = NES_CQP_QP_IWARP_STATE_TERMINATE | 0x02000000;
+                                       nesqp->hw_tcp_state = NES_AEQE_TCP_STATE_CLOSED;
+                                       nes_debug(NES_DBG_AEQ, "issuing hw modifyqp for QP%u. next state = 0x%08X,"
+                                                       " also added another reference\n",
+                                                       nesqp->hwqp.qp_id, next_iwarp_state);
+                                       nes_hw_modify_qp(nesdev, nesqp, next_iwarp_state, 0);
+                               }
+                               nes_cm_disconn(nesqp);
+                       }
+                       break;
+               case NES_AEQE_AEID_LLP_TERMINATE_RECEIVED:
+                       nesqp = *((struct nes_qp **)&context);
+                       spin_lock_irqsave(&nesqp->lock, flags);
+                       nesqp->hw_iwarp_state = iwarp_state;
+                       nesqp->hw_tcp_state = tcp_state;
+                       nesqp->last_aeq = async_event_id;
+                       spin_unlock_irqrestore(&nesqp->lock, flags);
+                       nes_debug(NES_DBG_AEQ, "Processing an NES_AEQE_AEID_LLP_TERMINATE_RECEIVED"
+                                       " event on QP%u \n  Q2 Data:\n",
+                                       nesqp->hwqp.qp_id);
+                       if (nesqp->ibqp.event_handler) {
+                               ibevent.device = nesqp->ibqp.device;
+                               ibevent.element.qp = &nesqp->ibqp;
+                               ibevent.event = IB_EVENT_QP_FATAL;
+                               nesqp->ibqp.event_handler(&ibevent, nesqp->ibqp.qp_context);
+                       }
+                       if ((tcp_state == NES_AEQE_TCP_STATE_CLOSE_WAIT) ||
+                                       ((nesqp->ibqp_state == IB_QPS_RTS)&&
+                                       (async_event_id == NES_AEQE_AEID_LLP_CONNECTION_RESET))) {
+                               nes_add_ref(&nesqp->ibqp);
+                               nes_cm_disconn(nesqp);
+                       } else {
+                               nesqp->in_disconnect = 0;
+                               wake_up(&nesqp->kick_waitq);
+                       }
+                       break;
+               case NES_AEQE_AEID_LLP_TOO_MANY_RETRIES:
+                       nesqp = *((struct nes_qp **)&context);
+                       nes_add_ref(&nesqp->ibqp);
+                       spin_lock_irqsave(&nesqp->lock, flags);
+                       nesqp->hw_iwarp_state = NES_AEQE_IWARP_STATE_ERROR;
+                       nesqp->hw_tcp_state = NES_AEQE_TCP_STATE_CLOSED;
+                       nesqp->last_aeq = async_event_id;
+                       if (nesqp->cm_id) {
+                               nes_debug(NES_DBG_AEQ, "Processing an NES_AEQE_AEID_LLP_TOO_MANY_RETRIES"
+                                               " event on QP%u, remote IP = 0x%08X \n",
+                                               nesqp->hwqp.qp_id,
+                                               ntohl(nesqp->cm_id->remote_addr.sin_addr.s_addr));
+                       } else {
+                               nes_debug(NES_DBG_AEQ, "Processing an NES_AEQE_AEID_LLP_TOO_MANY_RETRIES"
+                                               " event on QP%u \n",
+                                               nesqp->hwqp.qp_id);
+                       }
+                       spin_unlock_irqrestore(&nesqp->lock, flags);
+                       next_iwarp_state = NES_CQP_QP_IWARP_STATE_ERROR | NES_CQP_QP_RESET;
+                       nes_hw_modify_qp(nesdev, nesqp, next_iwarp_state, 0);
+                       if (nesqp->ibqp.event_handler) {
+                               ibevent.device = nesqp->ibqp.device;
+                               ibevent.element.qp = &nesqp->ibqp;
+                               ibevent.event = IB_EVENT_QP_FATAL;
+                               nesqp->ibqp.event_handler(&ibevent, nesqp->ibqp.qp_context);
+                       }
+                       break;
+               case NES_AEQE_AEID_AMP_BAD_STAG_INDEX:
+                       if (NES_AEQE_INBOUND_RDMA&aeq_info) {
+                               nesqp = nesadapter->qp_table[le32_to_cpu(
+                                               aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX])-NES_FIRST_QPN];
+                       } else {
+                               /* TODO: get the actual WQE and mask off wqe index */
+                               context &= ~((u64)511);
+                               nesqp = *((struct nes_qp **)&context);
+                       }
+                       spin_lock_irqsave(&nesqp->lock, flags);
+                       nesqp->hw_iwarp_state = iwarp_state;
+                       nesqp->hw_tcp_state = tcp_state;
+                       nesqp->last_aeq = async_event_id;
+                       spin_unlock_irqrestore(&nesqp->lock, flags);
+                       nes_debug(NES_DBG_AEQ, "Processing an NES_AEQE_AEID_AMP_BAD_STAG_INDEX event on QP%u\n",
+                                       nesqp->hwqp.qp_id);
+                       if (nesqp->ibqp.event_handler) {
+                               ibevent.device = nesqp->ibqp.device;
+                               ibevent.element.qp = &nesqp->ibqp;
+                               ibevent.event = IB_EVENT_QP_ACCESS_ERR;
+                               nesqp->ibqp.event_handler(&ibevent, nesqp->ibqp.qp_context);
+                       }
+                       break;
+               case NES_AEQE_AEID_AMP_UNALLOCATED_STAG:
+                       nesqp = *((struct nes_qp **)&context);
+                       spin_lock_irqsave(&nesqp->lock, flags);
+                       nesqp->hw_iwarp_state = iwarp_state;
+                       nesqp->hw_tcp_state = tcp_state;
+                       nesqp->last_aeq = async_event_id;
+                       spin_unlock_irqrestore(&nesqp->lock, flags);
+                       nes_debug(NES_DBG_AEQ, "Processing an NES_AEQE_AEID_AMP_UNALLOCATED_STAG event on QP%u\n",
+                                       nesqp->hwqp.qp_id);
+                       if (nesqp->ibqp.event_handler) {
+                               ibevent.device = nesqp->ibqp.device;
+                               ibevent.element.qp = &nesqp->ibqp;
+                               ibevent.event = IB_EVENT_QP_ACCESS_ERR;
+                               nesqp->ibqp.event_handler(&ibevent, nesqp->ibqp.qp_context);
+                       }
+                       break;
+               case NES_AEQE_AEID_PRIV_OPERATION_DENIED:
+                       nesqp = nesadapter->qp_table[le32_to_cpu(aeqe->aeqe_words
+                                       [NES_AEQE_COMP_QP_CQ_ID_IDX])-NES_FIRST_QPN];
+                       spin_lock_irqsave(&nesqp->lock, flags);
+                       nesqp->hw_iwarp_state = iwarp_state;
+                       nesqp->hw_tcp_state = tcp_state;
+                       nesqp->last_aeq = async_event_id;
+                       spin_unlock_irqrestore(&nesqp->lock, flags);
+                       nes_debug(NES_DBG_AEQ, "Processing an NES_AEQE_AEID_PRIV_OPERATION_DENIED event on QP%u,"
+                                       " nesqp = %p, AE reported %p\n",
+                                       nesqp->hwqp.qp_id, nesqp, *((struct nes_qp **)&context));
+                       if (nesqp->ibqp.event_handler) {
+                               ibevent.device = nesqp->ibqp.device;
+                               ibevent.element.qp = &nesqp->ibqp;
+                               ibevent.event = IB_EVENT_QP_ACCESS_ERR;
+                               nesqp->ibqp.event_handler(&ibevent, nesqp->ibqp.qp_context);
+                       }
+                       break;
+               case NES_AEQE_AEID_CQ_OPERATION_ERROR:
+                       context <<= 1;
+                       nes_debug(NES_DBG_AEQ, "Processing an NES_AEQE_AEID_CQ_OPERATION_ERROR event on CQ%u, %p\n",
+                                       le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX]), (void *)(unsigned long)context);
+                       resource_allocated = nes_is_resource_allocated(nesadapter, nesadapter->allocated_cqs,
+                                       le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX]));
+                       if (resource_allocated) {
+                               printk(KERN_ERR PFX "%s: Processing an NES_AEQE_AEID_CQ_OPERATION_ERROR event on CQ%u\n",
+                                               __FUNCTION__, le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX]));
+                       }
+                       break;
+               case NES_AEQE_AEID_DDP_UBE_DDP_MESSAGE_TOO_LONG_FOR_AVAILABLE_BUFFER:
+                       nesqp = nesadapter->qp_table[le32_to_cpu(
+                                       aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX])-NES_FIRST_QPN];
+                       spin_lock_irqsave(&nesqp->lock, flags);
+                       nesqp->hw_iwarp_state = iwarp_state;
+                       nesqp->hw_tcp_state = tcp_state;
+                       nesqp->last_aeq = async_event_id;
+                       spin_unlock_irqrestore(&nesqp->lock, flags);
+                       nes_debug(NES_DBG_AEQ, "Processing an NES_AEQE_AEID_DDP_UBE_DDP_MESSAGE_TOO_LONG"
+                                       "_FOR_AVAILABLE_BUFFER event on QP%u\n",
+                                       nesqp->hwqp.qp_id);
+                       if (nesqp->ibqp.event_handler) {
+                               ibevent.device = nesqp->ibqp.device;
+                               ibevent.element.qp = &nesqp->ibqp;
+                               ibevent.event = IB_EVENT_QP_ACCESS_ERR;
+                               nesqp->ibqp.event_handler(&ibevent, nesqp->ibqp.qp_context);
+                       }
+                       /* tell cm to disconnect, cm will queue work to thread */
+                       nes_add_ref(&nesqp->ibqp);
+                       nes_cm_disconn(nesqp);
+                       break;
+               case NES_AEQE_AEID_DDP_UBE_INVALID_MSN_NO_BUFFER_AVAILABLE:
+                       nesqp = *((struct nes_qp **)&context);
+                       spin_lock_irqsave(&nesqp->lock, flags);
+                       nesqp->hw_iwarp_state = iwarp_state;
+                       nesqp->hw_tcp_state = tcp_state;
+                       nesqp->last_aeq = async_event_id;
+                       spin_unlock_irqrestore(&nesqp->lock, flags);
+                       nes_debug(NES_DBG_AEQ, "Processing an NES_AEQE_AEID_DDP_UBE_INVALID_MSN"
+                                       "_NO_BUFFER_AVAILABLE event on QP%u\n",
+                                       nesqp->hwqp.qp_id);
+                       if (nesqp->ibqp.event_handler) {
+                               ibevent.device = nesqp->ibqp.device;
+                               ibevent.element.qp = &nesqp->ibqp;
+                               ibevent.event = IB_EVENT_QP_FATAL;
+                               nesqp->ibqp.event_handler(&ibevent, nesqp->ibqp.qp_context);
+                       }
+                       /* tell cm to disconnect, cm will queue work to thread */
+                       nes_add_ref(&nesqp->ibqp);
+                       nes_cm_disconn(nesqp);
+                       break;
+               case NES_AEQE_AEID_LLP_RECEIVED_MPA_CRC_ERROR:
+                       nesqp = *((struct nes_qp **)&context);
+                       spin_lock_irqsave(&nesqp->lock, flags);
+                       nesqp->hw_iwarp_state = iwarp_state;
+                       nesqp->hw_tcp_state = tcp_state;
+                       nesqp->last_aeq = async_event_id;
+                       spin_unlock_irqrestore(&nesqp->lock, flags);
+                       nes_debug(NES_DBG_AEQ, "Processing an NES_AEQE_AEID_LLP_RECEIVED_MPA_CRC_ERROR"
+                                       " event on QP%u \n  Q2 Data:\n",
+                                       nesqp->hwqp.qp_id);
+                       if (nesqp->ibqp.event_handler) {
+                               ibevent.device = nesqp->ibqp.device;
+                               ibevent.element.qp = &nesqp->ibqp;
+                               ibevent.event = IB_EVENT_QP_FATAL;
+                               nesqp->ibqp.event_handler(&ibevent, nesqp->ibqp.qp_context);
+                       }
+                       /* tell cm to disconnect, cm will queue work to thread */
+                       nes_add_ref(&nesqp->ibqp);
+                       nes_cm_disconn(nesqp);
+                       break;
+                       /* TODO: additional AEs need to be here */
+               default:
+                       nes_debug(NES_DBG_AEQ, "Processing an iWARP related AE for QP, misc = 0x%04X\n",
+                                       async_event_id);
+                       break;
+       }
+
+}
+
+
+/**
+ * nes_iwarp_ce_handler
+ */
+void nes_iwarp_ce_handler(struct nes_device *nesdev, struct nes_hw_cq *hw_cq)
+{
+       struct nes_cq *nescq = container_of(hw_cq, struct nes_cq, hw_cq);
+
+       /* nes_debug(NES_DBG_CQ, "Processing completion event for iWARP CQ%u.\n",
+                       nescq->hw_cq.cq_number); */
+       nes_write32(nesdev->regs+NES_CQ_ACK, nescq->hw_cq.cq_number);
+
+       if (nescq->ibcq.comp_handler)
+               nescq->ibcq.comp_handler(&nescq->ibcq, nescq->ibcq.cq_context);
+
+       return;
+}
+
+
+/**
+ * nes_manage_apbvt()
+ */
+int nes_manage_apbvt(struct nes_vnic *nesvnic, u32 accel_local_port,
+               u32 nic_index, u32 add_port)
+{
+       struct nes_device *nesdev = nesvnic->nesdev;
+       struct nes_hw_cqp_wqe *cqp_wqe;
+       unsigned long flags;
+       struct nes_cqp_request *cqp_request;
+       int ret = 0;
+       u16 major_code;
+
+       /* Send manage APBVT request to CQP */
+       cqp_request = nes_get_cqp_request(nesdev);
+       if (cqp_request == NULL) {
+               nes_debug(NES_DBG_QP, "Failed to get a cqp_request.\n");
+               return -ENOMEM;
+       }
+       cqp_request->waiting = 1;
+       cqp_wqe = &cqp_request->cqp_wqe;
+
+       nes_debug(NES_DBG_QP, "%s APBV for local port=%u(0x%04x), nic_index=%u\n",
+                       (add_port == NES_MANAGE_APBVT_ADD) ? "ADD" : "DEL",
+                       accel_local_port, accel_local_port, nic_index);
+
+       nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
+       set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_OPCODE_IDX, (NES_CQP_MANAGE_APBVT |
+                       ((add_port == NES_MANAGE_APBVT_ADD) ? NES_CQP_APBVT_ADD : 0)));
+       set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_ID_IDX,
+                       ((nic_index << NES_CQP_APBVT_NIC_SHIFT) | accel_local_port));
+
+       nes_debug(NES_DBG_QP, "Waiting for CQP completion for APBVT.\n");
+
+       atomic_set(&cqp_request->refcount, 2);
+       nes_post_cqp_request(nesdev, cqp_request, NES_CQP_REQUEST_RING_DOORBELL);
+
+       if (add_port == NES_MANAGE_APBVT_ADD)
+               ret = wait_event_timeout(cqp_request->waitq, (cqp_request->request_done != 0),
+                               NES_EVENT_TIMEOUT);
+       nes_debug(NES_DBG_QP, "Completed, ret=%u,  CQP Major:Minor codes = 0x%04X:0x%04X\n",
+                       ret, cqp_request->major_code, cqp_request->minor_code);
+       major_code = cqp_request->major_code;
+       if (atomic_dec_and_test(&cqp_request->refcount)) {
+               if (cqp_request->dynamic) {
+                       kfree(cqp_request);
+               } else {
+                       spin_lock_irqsave(&nesdev->cqp.lock, flags);
+                       list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs);
+                       spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+               }
+       }
+       if (!ret)
+               return -ETIME;
+       else if (major_code)
+               return -EIO;
+       else
+               return 0;
+}
+
+
+/**
+ * nes_manage_arp_cache
+ */
+void nes_manage_arp_cache(struct net_device *netdev, unsigned char *mac_addr,
+               u32 ip_addr, u32 action)
+{
+       struct nes_hw_cqp_wqe *cqp_wqe;
+       struct nes_vnic *nesvnic = netdev_priv(netdev);
+       struct nes_device *nesdev;
+       struct nes_cqp_request *cqp_request;
+       int arp_index;
+
+       nesdev = nesvnic->nesdev;
+       arp_index = nes_arp_table(nesdev, ip_addr, mac_addr, action);
+       if (arp_index == -1) {
+               return;
+       }
+
+       /* update the ARP entry */
+       cqp_request = nes_get_cqp_request(nesdev);
+       if (cqp_request == NULL) {
+               nes_debug(NES_DBG_NETDEV, "Failed to get a cqp_request.\n");
+               return;
+       }
+       cqp_request->waiting = 0;
+       cqp_wqe = &cqp_request->cqp_wqe;
+       nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
+
+       cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] = cpu_to_le32(
+                       NES_CQP_MANAGE_ARP_CACHE | NES_CQP_ARP_PERM);
+       cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] |= cpu_to_le32(
+                       (u32)PCI_FUNC(nesdev->pcidev->devfn) << NES_CQP_ARP_AEQ_INDEX_SHIFT);
+       cqp_wqe->wqe_words[NES_CQP_WQE_ID_IDX] = cpu_to_le32(arp_index);
+
+       if (action == NES_ARP_ADD) {
+               cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] |= cpu_to_le32(NES_CQP_ARP_VALID);
+               cqp_wqe->wqe_words[NES_CQP_ARP_WQE_MAC_ADDR_LOW_IDX] = cpu_to_le32(
+                               (((u32)mac_addr[2]) << 24) | (((u32)mac_addr[3]) << 16) |
+                               (((u32)mac_addr[4]) << 8) | (u32)mac_addr[5]);
+               cqp_wqe->wqe_words[NES_CQP_ARP_WQE_MAC_HIGH_IDX] = cpu_to_le32(
+                               (((u32)mac_addr[0]) << 16) | (u32)mac_addr[1]);
+       } else {
+               cqp_wqe->wqe_words[NES_CQP_ARP_WQE_MAC_ADDR_LOW_IDX] = 0;
+               cqp_wqe->wqe_words[NES_CQP_ARP_WQE_MAC_HIGH_IDX] = 0;
+       }
+
+       nes_debug(NES_DBG_NETDEV, "Not waiting for CQP, cqp.sq_head=%u, cqp.sq_tail=%u\n",
+                       nesdev->cqp.sq_head, nesdev->cqp.sq_tail);
+
+       atomic_set(&cqp_request->refcount, 1);
+       nes_post_cqp_request(nesdev, cqp_request, NES_CQP_REQUEST_RING_DOORBELL);
+}
+
+
+/**
+ * flush_wqes
+ */
+void flush_wqes(struct nes_device *nesdev, struct nes_qp *nesqp,
+               u32 which_wq, u32 wait_completion)
+{
+       unsigned long flags;
+       struct nes_cqp_request *cqp_request;
+       struct nes_hw_cqp_wqe *cqp_wqe;
+       int ret;
+
+       cqp_request = nes_get_cqp_request(nesdev);
+       if (cqp_request == NULL) {
+               nes_debug(NES_DBG_QP, "Failed to get a cqp_request.\n");
+               return;
+       }
+       if (wait_completion) {
+               cqp_request->waiting = 1;
+               atomic_set(&cqp_request->refcount, 2);
+       } else {
+               cqp_request->waiting = 0;
+       }
+       cqp_wqe = &cqp_request->cqp_wqe;
+       nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
+
+       cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] =
+                       cpu_to_le32(NES_CQP_FLUSH_WQES | which_wq);
+       cqp_wqe->wqe_words[NES_CQP_WQE_ID_IDX] = cpu_to_le32(nesqp->hwqp.qp_id);
+
+       nes_post_cqp_request(nesdev, cqp_request, NES_CQP_REQUEST_RING_DOORBELL);
+
+       if (wait_completion) {
+               /* Wait for CQP */
+               ret = wait_event_timeout(cqp_request->waitq, (cqp_request->request_done != 0),
+                               NES_EVENT_TIMEOUT);
+               nes_debug(NES_DBG_QP, "Flush SQ QP WQEs completed, ret=%u,"
+                               " CQP Major:Minor codes = 0x%04X:0x%04X\n",
+                               ret, cqp_request->major_code, cqp_request->minor_code);
+               if (atomic_dec_and_test(&cqp_request->refcount)) {
+                       if (cqp_request->dynamic) {
+                               kfree(cqp_request);
+                       } else {
+                               spin_lock_irqsave(&nesdev->cqp.lock, flags);
+                               list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs);
+                               spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+                       }
+               }
+       }
+}
diff --git a/drivers/infiniband/hw/nes/nes_hw.h b/drivers/infiniband/hw/nes/nes_hw.h
new file mode 100644 (file)
index 0000000..1e10df5
--- /dev/null
@@ -0,0 +1,1206 @@
+/*
+* Copyright (c) 2006 - 2008 NetEffect, Inc. All rights reserved.
+*
+* This software is available to you under a choice of one of two
+* licenses.  You may choose to be licensed under the terms of the GNU
+* General Public License (GPL) Version 2, available from the file
+* COPYING in the main directory of this source tree, or the
+* OpenIB.org BSD license below:
+*
+*     Redistribution and use in source and binary forms, with or
+*     without modification, are permitted provided that the following
+*     conditions are met:
+*
+*      - Redistributions of source code must retain the above
+*        copyright notice, this list of conditions and the following
+*        disclaimer.
+*
+*      - Redistributions in binary form must reproduce the above
+*        copyright notice, this list of conditions and the following
+*        disclaimer in the documentation and/or other materials
+*        provided with the distribution.
+*
+* 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.
+*/
+
+#ifndef __NES_HW_H
+#define __NES_HW_H
+
+#define NES_PHY_TYPE_1G   2
+#define NES_PHY_TYPE_IRIS 3
+#define NES_PHY_TYPE_PUMA_10G  6
+
+#define NES_MULTICAST_PF_MAX 8
+
+enum pci_regs {
+       NES_INT_STAT = 0x0000,
+       NES_INT_MASK = 0x0004,
+       NES_INT_PENDING = 0x0008,
+       NES_INTF_INT_STAT = 0x000C,
+       NES_INTF_INT_MASK = 0x0010,
+       NES_TIMER_STAT = 0x0014,
+       NES_PERIODIC_CONTROL = 0x0018,
+       NES_ONE_SHOT_CONTROL = 0x001C,
+       NES_EEPROM_COMMAND = 0x0020,
+       NES_EEPROM_DATA = 0x0024,
+       NES_FLASH_COMMAND = 0x0028,
+       NES_FLASH_DATA  = 0x002C,
+       NES_SOFTWARE_RESET = 0x0030,
+       NES_CQ_ACK = 0x0034,
+       NES_WQE_ALLOC = 0x0040,
+       NES_CQE_ALLOC = 0x0044,
+};
+
+enum indexed_regs {
+       NES_IDX_CREATE_CQP_LOW = 0x0000,
+       NES_IDX_CREATE_CQP_HIGH = 0x0004,
+       NES_IDX_QP_CONTROL = 0x0040,
+       NES_IDX_FLM_CONTROL = 0x0080,
+       NES_IDX_INT_CPU_STATUS = 0x00a0,
+       NES_IDX_GPIO_CONTROL = 0x00f0,
+       NES_IDX_GPIO_DATA = 0x00f4,
+       NES_IDX_TCP_CONFIG0 = 0x01e4,
+       NES_IDX_TCP_TIMER_CONFIG = 0x01ec,
+       NES_IDX_TCP_NOW = 0x01f0,
+       NES_IDX_QP_MAX_CFG_SIZES = 0x0200,
+       NES_IDX_QP_CTX_SIZE = 0x0218,
+       NES_IDX_TCP_TIMER_SIZE0 = 0x0238,
+       NES_IDX_TCP_TIMER_SIZE1 = 0x0240,
+       NES_IDX_ARP_CACHE_SIZE = 0x0258,
+       NES_IDX_CQ_CTX_SIZE = 0x0260,
+       NES_IDX_MRT_SIZE = 0x0278,
+       NES_IDX_PBL_REGION_SIZE = 0x0280,
+       NES_IDX_IRRQ_COUNT = 0x02b0,
+       NES_IDX_RX_WINDOW_BUFFER_PAGE_TABLE_SIZE = 0x02f0,
+       NES_IDX_RX_WINDOW_BUFFER_SIZE = 0x0300,
+       NES_IDX_DST_IP_ADDR = 0x0400,
+       NES_IDX_PCIX_DIAG = 0x08e8,
+       NES_IDX_MPP_DEBUG = 0x0a00,
+       NES_IDX_PORT_RX_DISCARDS = 0x0a30,
+       NES_IDX_PORT_TX_DISCARDS = 0x0a34,
+       NES_IDX_MPP_LB_DEBUG = 0x0b00,
+       NES_IDX_DENALI_CTL_22 = 0x1058,
+       NES_IDX_MAC_TX_CONTROL = 0x2000,
+       NES_IDX_MAC_TX_CONFIG = 0x2004,
+       NES_IDX_MAC_TX_PAUSE_QUANTA = 0x2008,
+       NES_IDX_MAC_RX_CONTROL = 0x200c,
+       NES_IDX_MAC_RX_CONFIG = 0x2010,
+       NES_IDX_MAC_EXACT_MATCH_BOTTOM = 0x201c,
+       NES_IDX_MAC_MDIO_CONTROL = 0x2084,
+       NES_IDX_MAC_TX_OCTETS_LOW = 0x2100,
+       NES_IDX_MAC_TX_OCTETS_HIGH = 0x2104,
+       NES_IDX_MAC_TX_FRAMES_LOW = 0x2108,
+       NES_IDX_MAC_TX_FRAMES_HIGH = 0x210c,
+       NES_IDX_MAC_TX_PAUSE_FRAMES = 0x2118,
+       NES_IDX_MAC_TX_ERRORS = 0x2138,
+       NES_IDX_MAC_RX_OCTETS_LOW = 0x213c,
+       NES_IDX_MAC_RX_OCTETS_HIGH = 0x2140,
+       NES_IDX_MAC_RX_FRAMES_LOW = 0x2144,
+       NES_IDX_MAC_RX_FRAMES_HIGH = 0x2148,
+       NES_IDX_MAC_RX_BC_FRAMES_LOW = 0x214c,
+       NES_IDX_MAC_RX_MC_FRAMES_HIGH = 0x2150,
+       NES_IDX_MAC_RX_PAUSE_FRAMES = 0x2154,
+       NES_IDX_MAC_RX_SHORT_FRAMES = 0x2174,
+       NES_IDX_MAC_RX_OVERSIZED_FRAMES = 0x2178,
+       NES_IDX_MAC_RX_JABBER_FRAMES = 0x217c,
+       NES_IDX_MAC_RX_CRC_ERR_FRAMES = 0x2180,
+       NES_IDX_MAC_RX_LENGTH_ERR_FRAMES = 0x2184,
+       NES_IDX_MAC_RX_SYMBOL_ERR_FRAMES = 0x2188,
+       NES_IDX_MAC_INT_STATUS = 0x21f0,
+       NES_IDX_MAC_INT_MASK = 0x21f4,
+       NES_IDX_PHY_PCS_CONTROL_STATUS0 = 0x2800,
+       NES_IDX_PHY_PCS_CONTROL_STATUS1 = 0x2a00,
+       NES_IDX_ETH_SERDES_COMMON_CONTROL0 = 0x2808,
+       NES_IDX_ETH_SERDES_COMMON_CONTROL1 = 0x2a08,
+       NES_IDX_ETH_SERDES_COMMON_STATUS0 = 0x280c,
+       NES_IDX_ETH_SERDES_COMMON_STATUS1 = 0x2a0c,
+       NES_IDX_ETH_SERDES_TX_EMP0 = 0x2810,
+       NES_IDX_ETH_SERDES_TX_EMP1 = 0x2a10,
+       NES_IDX_ETH_SERDES_TX_DRIVE0 = 0x2814,
+       NES_IDX_ETH_SERDES_TX_DRIVE1 = 0x2a14,
+       NES_IDX_ETH_SERDES_RX_MODE0 = 0x2818,
+       NES_IDX_ETH_SERDES_RX_MODE1 = 0x2a18,
+       NES_IDX_ETH_SERDES_RX_SIGDET0 = 0x281c,
+       NES_IDX_ETH_SERDES_RX_SIGDET1 = 0x2a1c,
+       NES_IDX_ETH_SERDES_BYPASS0 = 0x2820,
+       NES_IDX_ETH_SERDES_BYPASS1 = 0x2a20,
+       NES_IDX_ETH_SERDES_LOOPBACK_CONTROL0 = 0x2824,
+       NES_IDX_ETH_SERDES_LOOPBACK_CONTROL1 = 0x2a24,
+       NES_IDX_ETH_SERDES_RX_EQ_CONTROL0 = 0x2828,
+       NES_IDX_ETH_SERDES_RX_EQ_CONTROL1 = 0x2a28,
+       NES_IDX_ETH_SERDES_RX_EQ_STATUS0 = 0x282c,
+       NES_IDX_ETH_SERDES_RX_EQ_STATUS1 = 0x2a2c,
+       NES_IDX_ETH_SERDES_CDR_RESET0 = 0x2830,
+       NES_IDX_ETH_SERDES_CDR_RESET1 = 0x2a30,
+       NES_IDX_ETH_SERDES_CDR_CONTROL0 = 0x2834,
+       NES_IDX_ETH_SERDES_CDR_CONTROL1 = 0x2a34,
+       NES_IDX_ETH_SERDES_TX_HIGHZ_LANE_MODE0 = 0x2838,
+       NES_IDX_ETH_SERDES_TX_HIGHZ_LANE_MODE1 = 0x2a38,
+       NES_IDX_ENDNODE0_NSTAT_RX_DISCARD = 0x3080,
+       NES_IDX_ENDNODE0_NSTAT_RX_OCTETS_LO = 0x3000,
+       NES_IDX_ENDNODE0_NSTAT_RX_OCTETS_HI = 0x3004,
+       NES_IDX_ENDNODE0_NSTAT_RX_FRAMES_LO = 0x3008,
+       NES_IDX_ENDNODE0_NSTAT_RX_FRAMES_HI = 0x300c,
+       NES_IDX_ENDNODE0_NSTAT_TX_OCTETS_LO = 0x7000,
+       NES_IDX_ENDNODE0_NSTAT_TX_OCTETS_HI = 0x7004,
+       NES_IDX_ENDNODE0_NSTAT_TX_FRAMES_LO = 0x7008,
+       NES_IDX_ENDNODE0_NSTAT_TX_FRAMES_HI = 0x700c,
+       NES_IDX_CM_CONFIG = 0x5100,
+       NES_IDX_NIC_LOGPORT_TO_PHYPORT = 0x6000,
+       NES_IDX_NIC_PHYPORT_TO_USW = 0x6008,
+       NES_IDX_NIC_ACTIVE = 0x6010,
+       NES_IDX_NIC_UNICAST_ALL = 0x6018,
+       NES_IDX_NIC_MULTICAST_ALL = 0x6020,
+       NES_IDX_NIC_MULTICAST_ENABLE = 0x6028,
+       NES_IDX_NIC_BROADCAST_ON = 0x6030,
+       NES_IDX_USED_CHUNKS_TX = 0x60b0,
+       NES_IDX_TX_POOL_SIZE = 0x60b8,
+       NES_IDX_QUAD_HASH_TABLE_SIZE = 0x6148,
+       NES_IDX_PERFECT_FILTER_LOW = 0x6200,
+       NES_IDX_PERFECT_FILTER_HIGH = 0x6204,
+       NES_IDX_IPV4_TCP_REXMITS = 0x7080,
+       NES_IDX_DEBUG_ERROR_CONTROL_STATUS = 0x913c,
+       NES_IDX_DEBUG_ERROR_MASKS0 = 0x9140,
+       NES_IDX_DEBUG_ERROR_MASKS1 = 0x9144,
+       NES_IDX_DEBUG_ERROR_MASKS2 = 0x9148,
+       NES_IDX_DEBUG_ERROR_MASKS3 = 0x914c,
+       NES_IDX_DEBUG_ERROR_MASKS4 = 0x9150,
+       NES_IDX_DEBUG_ERROR_MASKS5 = 0x9154,
+};
+
+#define NES_IDX_MAC_TX_CONFIG_ENABLE_PAUSE   1
+#define NES_IDX_MPP_DEBUG_PORT_DISABLE_PAUSE (1 << 17)
+
+enum nes_cqp_opcodes {
+       NES_CQP_CREATE_QP = 0x00,
+       NES_CQP_MODIFY_QP = 0x01,
+       NES_CQP_DESTROY_QP = 0x02,
+       NES_CQP_CREATE_CQ = 0x03,
+       NES_CQP_MODIFY_CQ = 0x04,
+       NES_CQP_DESTROY_CQ = 0x05,
+       NES_CQP_ALLOCATE_STAG = 0x09,
+       NES_CQP_REGISTER_STAG = 0x0a,
+       NES_CQP_QUERY_STAG = 0x0b,
+       NES_CQP_REGISTER_SHARED_STAG = 0x0c,
+       NES_CQP_DEALLOCATE_STAG = 0x0d,
+       NES_CQP_MANAGE_ARP_CACHE = 0x0f,
+       NES_CQP_SUSPEND_QPS = 0x11,
+       NES_CQP_UPLOAD_CONTEXT = 0x13,
+       NES_CQP_CREATE_CEQ = 0x16,
+       NES_CQP_DESTROY_CEQ = 0x18,
+       NES_CQP_CREATE_AEQ = 0x19,
+       NES_CQP_DESTROY_AEQ = 0x1b,
+       NES_CQP_LMI_ACCESS = 0x20,
+       NES_CQP_FLUSH_WQES = 0x22,
+       NES_CQP_MANAGE_APBVT = 0x23
+};
+
+enum nes_cqp_wqe_word_idx {
+       NES_CQP_WQE_OPCODE_IDX = 0,
+       NES_CQP_WQE_ID_IDX = 1,
+       NES_CQP_WQE_COMP_CTX_LOW_IDX = 2,
+       NES_CQP_WQE_COMP_CTX_HIGH_IDX = 3,
+       NES_CQP_WQE_COMP_SCRATCH_LOW_IDX = 4,
+       NES_CQP_WQE_COMP_SCRATCH_HIGH_IDX = 5,
+};
+
+enum nes_cqp_cq_wqeword_idx {
+       NES_CQP_CQ_WQE_PBL_LOW_IDX = 6,
+       NES_CQP_CQ_WQE_PBL_HIGH_IDX = 7,
+       NES_CQP_CQ_WQE_CQ_CONTEXT_LOW_IDX = 8,
+       NES_CQP_CQ_WQE_CQ_CONTEXT_HIGH_IDX = 9,
+       NES_CQP_CQ_WQE_DOORBELL_INDEX_HIGH_IDX = 10,
+};
+
+enum nes_cqp_stag_wqeword_idx {
+       NES_CQP_STAG_WQE_PBL_BLK_COUNT_IDX = 1,
+       NES_CQP_STAG_WQE_LEN_HIGH_PD_IDX = 6,
+       NES_CQP_STAG_WQE_LEN_LOW_IDX = 7,
+       NES_CQP_STAG_WQE_STAG_IDX = 8,
+       NES_CQP_STAG_WQE_VA_LOW_IDX = 10,
+       NES_CQP_STAG_WQE_VA_HIGH_IDX = 11,
+       NES_CQP_STAG_WQE_PA_LOW_IDX = 12,
+       NES_CQP_STAG_WQE_PA_HIGH_IDX = 13,
+       NES_CQP_STAG_WQE_PBL_LEN_IDX = 14
+};
+
+#define NES_CQP_OP_IWARP_STATE_SHIFT 28
+
+enum nes_cqp_qp_bits {
+       NES_CQP_QP_ARP_VALID = (1<<8),
+       NES_CQP_QP_WINBUF_VALID = (1<<9),
+       NES_CQP_QP_CONTEXT_VALID = (1<<10),
+       NES_CQP_QP_ORD_VALID = (1<<11),
+       NES_CQP_QP_WINBUF_DATAIND_EN = (1<<12),
+       NES_CQP_QP_VIRT_WQS = (1<<13),
+       NES_CQP_QP_DEL_HTE = (1<<14),
+       NES_CQP_QP_CQS_VALID = (1<<15),
+       NES_CQP_QP_TYPE_TSA = 0,
+       NES_CQP_QP_TYPE_IWARP = (1<<16),
+       NES_CQP_QP_TYPE_CQP = (4<<16),
+       NES_CQP_QP_TYPE_NIC = (5<<16),
+       NES_CQP_QP_MSS_CHG = (1<<20),
+       NES_CQP_QP_STATIC_RESOURCES = (1<<21),
+       NES_CQP_QP_IGNORE_MW_BOUND = (1<<22),
+       NES_CQP_QP_VWQ_USE_LMI = (1<<23),
+       NES_CQP_QP_IWARP_STATE_IDLE = (1<<NES_CQP_OP_IWARP_STATE_SHIFT),
+       NES_CQP_QP_IWARP_STATE_RTS = (2<<NES_CQP_OP_IWARP_STATE_SHIFT),
+       NES_CQP_QP_IWARP_STATE_CLOSING = (3<<NES_CQP_OP_IWARP_STATE_SHIFT),
+       NES_CQP_QP_IWARP_STATE_TERMINATE = (5<<NES_CQP_OP_IWARP_STATE_SHIFT),
+       NES_CQP_QP_IWARP_STATE_ERROR = (6<<NES_CQP_OP_IWARP_STATE_SHIFT),
+       NES_CQP_QP_IWARP_STATE_MASK = (7<<NES_CQP_OP_IWARP_STATE_SHIFT),
+       NES_CQP_QP_RESET = (1<<31),
+};
+
+enum nes_cqp_qp_wqe_word_idx {
+       NES_CQP_QP_WQE_CONTEXT_LOW_IDX = 6,
+       NES_CQP_QP_WQE_CONTEXT_HIGH_IDX = 7,
+       NES_CQP_QP_WQE_NEW_MSS_IDX = 15,
+};
+
+enum nes_nic_ctx_bits {
+       NES_NIC_CTX_RQ_SIZE_32 = (3<<8),
+       NES_NIC_CTX_RQ_SIZE_512 = (3<<8),
+       NES_NIC_CTX_SQ_SIZE_32 = (1<<10),
+       NES_NIC_CTX_SQ_SIZE_512 = (3<<10),
+};
+
+enum nes_nic_qp_ctx_word_idx {
+       NES_NIC_CTX_MISC_IDX = 0,
+       NES_NIC_CTX_SQ_LOW_IDX = 2,
+       NES_NIC_CTX_SQ_HIGH_IDX = 3,
+       NES_NIC_CTX_RQ_LOW_IDX = 4,
+       NES_NIC_CTX_RQ_HIGH_IDX = 5,
+};
+
+enum nes_cqp_cq_bits {
+       NES_CQP_CQ_CEQE_MASK = (1<<9),
+       NES_CQP_CQ_CEQ_VALID = (1<<10),
+       NES_CQP_CQ_RESIZE = (1<<11),
+       NES_CQP_CQ_CHK_OVERFLOW = (1<<12),
+       NES_CQP_CQ_4KB_CHUNK = (1<<14),
+       NES_CQP_CQ_VIRT = (1<<15),
+};
+
+enum nes_cqp_stag_bits {
+       NES_CQP_STAG_VA_TO = (1<<9),
+       NES_CQP_STAG_DEALLOC_PBLS = (1<<10),
+       NES_CQP_STAG_PBL_BLK_SIZE = (1<<11),
+       NES_CQP_STAG_MR = (1<<13),
+       NES_CQP_STAG_RIGHTS_LOCAL_READ = (1<<16),
+       NES_CQP_STAG_RIGHTS_LOCAL_WRITE = (1<<17),
+       NES_CQP_STAG_RIGHTS_REMOTE_READ = (1<<18),
+       NES_CQP_STAG_RIGHTS_REMOTE_WRITE = (1<<19),
+       NES_CQP_STAG_RIGHTS_WINDOW_BIND = (1<<20),
+       NES_CQP_STAG_REM_ACC_EN = (1<<21),
+       NES_CQP_STAG_LEAVE_PENDING = (1<<31),
+};
+
+enum nes_cqp_ceq_wqeword_idx {
+       NES_CQP_CEQ_WQE_ELEMENT_COUNT_IDX = 1,
+       NES_CQP_CEQ_WQE_PBL_LOW_IDX = 6,
+       NES_CQP_CEQ_WQE_PBL_HIGH_IDX = 7,
+};
+
+enum nes_cqp_ceq_bits {
+       NES_CQP_CEQ_4KB_CHUNK = (1<<14),
+       NES_CQP_CEQ_VIRT = (1<<15),
+};
+
+enum nes_cqp_aeq_wqeword_idx {
+       NES_CQP_AEQ_WQE_ELEMENT_COUNT_IDX = 1,
+       NES_CQP_AEQ_WQE_PBL_LOW_IDX = 6,
+       NES_CQP_AEQ_WQE_PBL_HIGH_IDX = 7,
+};
+
+enum nes_cqp_aeq_bits {
+       NES_CQP_AEQ_4KB_CHUNK = (1<<14),
+       NES_CQP_AEQ_VIRT = (1<<15),
+};
+
+enum nes_cqp_lmi_wqeword_idx {
+       NES_CQP_LMI_WQE_LMI_OFFSET_IDX = 1,
+       NES_CQP_LMI_WQE_FRAG_LOW_IDX = 8,
+       NES_CQP_LMI_WQE_FRAG_HIGH_IDX = 9,
+       NES_CQP_LMI_WQE_FRAG_LEN_IDX = 10,
+};
+
+enum nes_cqp_arp_wqeword_idx {
+       NES_CQP_ARP_WQE_MAC_ADDR_LOW_IDX = 6,
+       NES_CQP_ARP_WQE_MAC_HIGH_IDX = 7,
+       NES_CQP_ARP_WQE_REACHABILITY_MAX_IDX = 1,
+};
+
+enum nes_cqp_upload_wqeword_idx {
+       NES_CQP_UPLOAD_WQE_CTXT_LOW_IDX = 6,
+       NES_CQP_UPLOAD_WQE_CTXT_HIGH_IDX = 7,
+       NES_CQP_UPLOAD_WQE_HTE_IDX = 8,
+};
+
+enum nes_cqp_arp_bits {
+       NES_CQP_ARP_VALID = (1<<8),
+       NES_CQP_ARP_PERM = (1<<9),
+};
+
+enum nes_cqp_flush_bits {
+       NES_CQP_FLUSH_SQ = (1<<30),
+       NES_CQP_FLUSH_RQ = (1<<31),
+};
+
+enum nes_cqe_opcode_bits {
+       NES_CQE_STAG_VALID = (1<<6),
+       NES_CQE_ERROR = (1<<7),
+       NES_CQE_SQ = (1<<8),
+       NES_CQE_SE = (1<<9),
+       NES_CQE_PSH = (1<<29),
+       NES_CQE_FIN = (1<<30),
+       NES_CQE_VALID = (1<<31),
+};
+
+
+enum nes_cqe_word_idx {
+       NES_CQE_PAYLOAD_LENGTH_IDX = 0,
+       NES_CQE_COMP_COMP_CTX_LOW_IDX = 2,
+       NES_CQE_COMP_COMP_CTX_HIGH_IDX = 3,
+       NES_CQE_INV_STAG_IDX = 4,
+       NES_CQE_QP_ID_IDX = 5,
+       NES_CQE_ERROR_CODE_IDX = 6,
+       NES_CQE_OPCODE_IDX = 7,
+};
+
+enum nes_ceqe_word_idx {
+       NES_CEQE_CQ_CTX_LOW_IDX = 0,
+       NES_CEQE_CQ_CTX_HIGH_IDX = 1,
+};
+
+enum nes_ceqe_status_bit {
+       NES_CEQE_VALID = (1<<31),
+};
+
+enum nes_int_bits {
+       NES_INT_CEQ0 = (1<<0),
+       NES_INT_CEQ1 = (1<<1),
+       NES_INT_CEQ2 = (1<<2),
+       NES_INT_CEQ3 = (1<<3),
+       NES_INT_CEQ4 = (1<<4),
+       NES_INT_CEQ5 = (1<<5),
+       NES_INT_CEQ6 = (1<<6),
+       NES_INT_CEQ7 = (1<<7),
+       NES_INT_CEQ8 = (1<<8),
+       NES_INT_CEQ9 = (1<<9),
+       NES_INT_CEQ10 = (1<<10),
+       NES_INT_CEQ11 = (1<<11),
+       NES_INT_CEQ12 = (1<<12),
+       NES_INT_CEQ13 = (1<<13),
+       NES_INT_CEQ14 = (1<<14),
+       NES_INT_CEQ15 = (1<<15),
+       NES_INT_AEQ0 = (1<<16),
+       NES_INT_AEQ1 = (1<<17),
+       NES_INT_AEQ2 = (1<<18),
+       NES_INT_AEQ3 = (1<<19),
+       NES_INT_AEQ4 = (1<<20),
+       NES_INT_AEQ5 = (1<<21),
+       NES_INT_AEQ6 = (1<<22),
+       NES_INT_AEQ7 = (1<<23),
+       NES_INT_MAC0 = (1<<24),
+       NES_INT_MAC1 = (1<<25),
+       NES_INT_MAC2 = (1<<26),
+       NES_INT_MAC3 = (1<<27),
+       NES_INT_TSW = (1<<28),
+       NES_INT_TIMER = (1<<29),
+       NES_INT_INTF = (1<<30),
+};
+
+enum nes_intf_int_bits {
+       NES_INTF_INT_PCIERR = (1<<0),
+       NES_INTF_PERIODIC_TIMER = (1<<2),
+       NES_INTF_ONE_SHOT_TIMER = (1<<3),
+       NES_INTF_INT_CRITERR = (1<<14),
+       NES_INTF_INT_AEQ0_OFLOW = (1<<16),
+       NES_INTF_INT_AEQ1_OFLOW = (1<<17),
+       NES_INTF_INT_AEQ2_OFLOW = (1<<18),
+       NES_INTF_INT_AEQ3_OFLOW = (1<<19),
+       NES_INTF_INT_AEQ4_OFLOW = (1<<20),
+       NES_INTF_INT_AEQ5_OFLOW = (1<<21),
+       NES_INTF_INT_AEQ6_OFLOW = (1<<22),
+       NES_INTF_INT_AEQ7_OFLOW = (1<<23),
+       NES_INTF_INT_AEQ_OFLOW = (0xff<<16),
+};
+
+enum nes_mac_int_bits {
+       NES_MAC_INT_LINK_STAT_CHG = (1<<1),
+       NES_MAC_INT_XGMII_EXT = (1<<2),
+       NES_MAC_INT_TX_UNDERFLOW = (1<<6),
+       NES_MAC_INT_TX_ERROR = (1<<7),
+};
+
+enum nes_cqe_allocate_bits {
+       NES_CQE_ALLOC_INC_SELECT = (1<<28),
+       NES_CQE_ALLOC_NOTIFY_NEXT = (1<<29),
+       NES_CQE_ALLOC_NOTIFY_SE = (1<<30),
+       NES_CQE_ALLOC_RESET = (1<<31),
+};
+
+enum nes_nic_rq_wqe_word_idx {
+       NES_NIC_RQ_WQE_LENGTH_1_0_IDX = 0,
+       NES_NIC_RQ_WQE_LENGTH_3_2_IDX = 1,
+       NES_NIC_RQ_WQE_FRAG0_LOW_IDX = 2,
+       NES_NIC_RQ_WQE_FRAG0_HIGH_IDX = 3,
+       NES_NIC_RQ_WQE_FRAG1_LOW_IDX = 4,
+       NES_NIC_RQ_WQE_FRAG1_HIGH_IDX = 5,
+       NES_NIC_RQ_WQE_FRAG2_LOW_IDX = 6,
+       NES_NIC_RQ_WQE_FRAG2_HIGH_IDX = 7,
+       NES_NIC_RQ_WQE_FRAG3_LOW_IDX = 8,
+       NES_NIC_RQ_WQE_FRAG3_HIGH_IDX = 9,
+};
+
+enum nes_nic_sq_wqe_word_idx {
+       NES_NIC_SQ_WQE_MISC_IDX = 0,
+       NES_NIC_SQ_WQE_TOTAL_LENGTH_IDX = 1,
+       NES_NIC_SQ_WQE_LSO_INFO_IDX = 2,
+       NES_NIC_SQ_WQE_LENGTH_0_TAG_IDX = 3,
+       NES_NIC_SQ_WQE_LENGTH_2_1_IDX = 4,
+       NES_NIC_SQ_WQE_LENGTH_4_3_IDX = 5,
+       NES_NIC_SQ_WQE_FRAG0_LOW_IDX = 6,
+       NES_NIC_SQ_WQE_FRAG0_HIGH_IDX = 7,
+       NES_NIC_SQ_WQE_FRAG1_LOW_IDX = 8,
+       NES_NIC_SQ_WQE_FRAG1_HIGH_IDX = 9,
+       NES_NIC_SQ_WQE_FRAG2_LOW_IDX = 10,
+       NES_NIC_SQ_WQE_FRAG2_HIGH_IDX = 11,
+       NES_NIC_SQ_WQE_FRAG3_LOW_IDX = 12,
+       NES_NIC_SQ_WQE_FRAG3_HIGH_IDX = 13,
+       NES_NIC_SQ_WQE_FRAG4_LOW_IDX = 14,
+       NES_NIC_SQ_WQE_FRAG4_HIGH_IDX = 15,
+};
+
+enum nes_iwarp_sq_wqe_word_idx {
+       NES_IWARP_SQ_WQE_MISC_IDX = 0,
+       NES_IWARP_SQ_WQE_TOTAL_PAYLOAD_IDX = 1,
+       NES_IWARP_SQ_WQE_COMP_CTX_LOW_IDX = 2,
+       NES_IWARP_SQ_WQE_COMP_CTX_HIGH_IDX = 3,
+       NES_IWARP_SQ_WQE_COMP_SCRATCH_LOW_IDX = 4,
+       NES_IWARP_SQ_WQE_COMP_SCRATCH_HIGH_IDX = 5,
+       NES_IWARP_SQ_WQE_INV_STAG_LOW_IDX = 7,
+       NES_IWARP_SQ_WQE_RDMA_TO_LOW_IDX = 8,
+       NES_IWARP_SQ_WQE_RDMA_TO_HIGH_IDX = 9,
+       NES_IWARP_SQ_WQE_RDMA_LENGTH_IDX = 10,
+       NES_IWARP_SQ_WQE_RDMA_STAG_IDX = 11,
+       NES_IWARP_SQ_WQE_IMM_DATA_START_IDX = 12,
+       NES_IWARP_SQ_WQE_FRAG0_LOW_IDX = 16,
+       NES_IWARP_SQ_WQE_FRAG0_HIGH_IDX = 17,
+       NES_IWARP_SQ_WQE_LENGTH0_IDX = 18,
+       NES_IWARP_SQ_WQE_STAG0_IDX = 19,
+       NES_IWARP_SQ_WQE_FRAG1_LOW_IDX = 20,
+       NES_IWARP_SQ_WQE_FRAG1_HIGH_IDX = 21,
+       NES_IWARP_SQ_WQE_LENGTH1_IDX = 22,
+       NES_IWARP_SQ_WQE_STAG1_IDX = 23,
+       NES_IWARP_SQ_WQE_FRAG2_LOW_IDX = 24,
+       NES_IWARP_SQ_WQE_FRAG2_HIGH_IDX = 25,
+       NES_IWARP_SQ_WQE_LENGTH2_IDX = 26,
+       NES_IWARP_SQ_WQE_STAG2_IDX = 27,
+       NES_IWARP_SQ_WQE_FRAG3_LOW_IDX = 28,
+       NES_IWARP_SQ_WQE_FRAG3_HIGH_IDX = 29,
+       NES_IWARP_SQ_WQE_LENGTH3_IDX = 30,
+       NES_IWARP_SQ_WQE_STAG3_IDX = 31,
+};
+
+enum nes_iwarp_sq_bind_wqe_word_idx {
+       NES_IWARP_SQ_BIND_WQE_MR_IDX = 6,
+       NES_IWARP_SQ_BIND_WQE_MW_IDX = 7,
+       NES_IWARP_SQ_BIND_WQE_LENGTH_LOW_IDX = 8,
+       NES_IWARP_SQ_BIND_WQE_LENGTH_HIGH_IDX = 9,
+       NES_IWARP_SQ_BIND_WQE_VA_FBO_LOW_IDX = 10,
+       NES_IWARP_SQ_BIND_WQE_VA_FBO_HIGH_IDX = 11,
+};
+
+enum nes_iwarp_sq_fmr_wqe_word_idx {
+       NES_IWARP_SQ_FMR_WQE_MR_STAG_IDX = 7,
+       NES_IWARP_SQ_FMR_WQE_LENGTH_LOW_IDX = 8,
+       NES_IWARP_SQ_FMR_WQE_LENGTH_HIGH_IDX = 9,
+       NES_IWARP_SQ_FMR_WQE_VA_FBO_LOW_IDX = 10,
+       NES_IWARP_SQ_FMR_WQE_VA_FBO_HIGH_IDX = 11,
+       NES_IWARP_SQ_FMR_WQE_PBL_ADDR_LOW_IDX = 12,
+       NES_IWARP_SQ_FMR_WQE_PBL_ADDR_HIGH_IDX = 13,
+       NES_IWARP_SQ_FMR_WQE_PBL_LENGTH_IDX = 14,
+};
+
+enum nes_iwarp_sq_locinv_wqe_word_idx {
+       NES_IWARP_SQ_LOCINV_WQE_INV_STAG_IDX = 6,
+};
+
+
+enum nes_iwarp_rq_wqe_word_idx {
+       NES_IWARP_RQ_WQE_TOTAL_PAYLOAD_IDX = 1,
+       NES_IWARP_RQ_WQE_COMP_CTX_LOW_IDX = 2,
+       NES_IWARP_RQ_WQE_COMP_CTX_HIGH_IDX = 3,
+       NES_IWARP_RQ_WQE_COMP_SCRATCH_LOW_IDX = 4,
+       NES_IWARP_RQ_WQE_COMP_SCRATCH_HIGH_IDX = 5,
+       NES_IWARP_RQ_WQE_FRAG0_LOW_IDX = 8,
+       NES_IWARP_RQ_WQE_FRAG0_HIGH_IDX = 9,
+       NES_IWARP_RQ_WQE_LENGTH0_IDX = 10,
+       NES_IWARP_RQ_WQE_STAG0_IDX = 11,
+       NES_IWARP_RQ_WQE_FRAG1_LOW_IDX = 12,
+       NES_IWARP_RQ_WQE_FRAG1_HIGH_IDX = 13,
+       NES_IWARP_RQ_WQE_LENGTH1_IDX = 14,
+       NES_IWARP_RQ_WQE_STAG1_IDX = 15,
+       NES_IWARP_RQ_WQE_FRAG2_LOW_IDX = 16,
+       NES_IWARP_RQ_WQE_FRAG2_HIGH_IDX = 17,
+       NES_IWARP_RQ_WQE_LENGTH2_IDX = 18,
+       NES_IWARP_RQ_WQE_STAG2_IDX = 19,
+       NES_IWARP_RQ_WQE_FRAG3_LOW_IDX = 20,
+       NES_IWARP_RQ_WQE_FRAG3_HIGH_IDX = 21,
+       NES_IWARP_RQ_WQE_LENGTH3_IDX = 22,
+       NES_IWARP_RQ_WQE_STAG3_IDX = 23,
+};
+
+enum nes_nic_sq_wqe_bits {
+       NES_NIC_SQ_WQE_PHDR_CS_READY =  (1<<21),
+       NES_NIC_SQ_WQE_LSO_ENABLE = (1<<22),
+       NES_NIC_SQ_WQE_TAGVALUE_ENABLE = (1<<23),
+       NES_NIC_SQ_WQE_DISABLE_CHKSUM = (1<<30),
+       NES_NIC_SQ_WQE_COMPLETION = (1<<31),
+};
+
+enum nes_nic_cqe_word_idx {
+       NES_NIC_CQE_ACCQP_ID_IDX = 0,
+       NES_NIC_CQE_TAG_PKT_TYPE_IDX = 2,
+       NES_NIC_CQE_MISC_IDX = 3,
+};
+
+#define NES_PKT_TYPE_APBVT_BITS 0xC112
+#define NES_PKT_TYPE_APBVT_MASK 0xff3e
+
+#define NES_PKT_TYPE_PVALID_BITS 0x10000000
+#define NES_PKT_TYPE_PVALID_MASK 0x30000000
+
+#define NES_PKT_TYPE_TCPV4_BITS 0x0110
+#define NES_PKT_TYPE_TCPV4_MASK 0x3f30
+
+#define NES_PKT_TYPE_UDPV4_BITS 0x0210
+#define NES_PKT_TYPE_UDPV4_MASK 0x3f30
+
+#define NES_PKT_TYPE_IPV4_BITS  0x0010
+#define NES_PKT_TYPE_IPV4_MASK  0x3f30
+
+#define NES_PKT_TYPE_OTHER_BITS 0x0000
+#define NES_PKT_TYPE_OTHER_MASK 0x0030
+
+#define NES_NIC_CQE_ERRV_SHIFT 16
+enum nes_nic_ev_bits {
+       NES_NIC_ERRV_BITS_MODE = (1<<0),
+       NES_NIC_ERRV_BITS_IPV4_CSUM_ERR = (1<<1),
+       NES_NIC_ERRV_BITS_TCPUDP_CSUM_ERR = (1<<2),
+       NES_NIC_ERRV_BITS_WQE_OVERRUN = (1<<3),
+       NES_NIC_ERRV_BITS_IPH_ERR = (1<<4),
+};
+
+enum nes_nic_cqe_bits {
+       NES_NIC_CQE_ERRV_MASK = (0xff<<NES_NIC_CQE_ERRV_SHIFT),
+       NES_NIC_CQE_SQ = (1<<24),
+       NES_NIC_CQE_ACCQP_PORT = (1<<28),
+       NES_NIC_CQE_ACCQP_VALID = (1<<29),
+       NES_NIC_CQE_TAG_VALID = (1<<30),
+       NES_NIC_CQE_VALID = (1<<31),
+};
+
+enum nes_aeqe_word_idx {
+       NES_AEQE_COMP_CTXT_LOW_IDX = 0,
+       NES_AEQE_COMP_CTXT_HIGH_IDX = 1,
+       NES_AEQE_COMP_QP_CQ_ID_IDX = 2,
+       NES_AEQE_MISC_IDX = 3,
+};
+
+enum nes_aeqe_bits {
+       NES_AEQE_QP = (1<<16),
+       NES_AEQE_CQ = (1<<17),
+       NES_AEQE_SQ = (1<<18),
+       NES_AEQE_INBOUND_RDMA = (1<<19),
+       NES_AEQE_IWARP_STATE_MASK = (7<<20),
+       NES_AEQE_TCP_STATE_MASK = (0xf<<24),
+       NES_AEQE_VALID = (1<<31),
+};
+
+#define NES_AEQE_IWARP_STATE_SHIFT     20
+#define NES_AEQE_TCP_STATE_SHIFT       24
+
+enum nes_aeqe_iwarp_state {
+       NES_AEQE_IWARP_STATE_NON_EXISTANT = 0,
+       NES_AEQE_IWARP_STATE_IDLE = 1,
+       NES_AEQE_IWARP_STATE_RTS = 2,
+       NES_AEQE_IWARP_STATE_CLOSING = 3,
+       NES_AEQE_IWARP_STATE_TERMINATE = 5,
+       NES_AEQE_IWARP_STATE_ERROR = 6
+};
+
+enum nes_aeqe_tcp_state {
+       NES_AEQE_TCP_STATE_NON_EXISTANT = 0,
+       NES_AEQE_TCP_STATE_CLOSED = 1,
+       NES_AEQE_TCP_STATE_LISTEN = 2,
+       NES_AEQE_TCP_STATE_SYN_SENT = 3,
+       NES_AEQE_TCP_STATE_SYN_RCVD = 4,
+       NES_AEQE_TCP_STATE_ESTABLISHED = 5,
+       NES_AEQE_TCP_STATE_CLOSE_WAIT = 6,
+       NES_AEQE_TCP_STATE_FIN_WAIT_1 = 7,
+       NES_AEQE_TCP_STATE_CLOSING = 8,
+       NES_AEQE_TCP_STATE_LAST_ACK = 9,
+       NES_AEQE_TCP_STATE_FIN_WAIT_2 = 10,
+       NES_AEQE_TCP_STATE_TIME_WAIT = 11
+};
+
+enum nes_aeqe_aeid {
+       NES_AEQE_AEID_AMP_UNALLOCATED_STAG                            = 0x0102,
+       NES_AEQE_AEID_AMP_INVALID_STAG                                = 0x0103,
+       NES_AEQE_AEID_AMP_BAD_QP                                      = 0x0104,
+       NES_AEQE_AEID_AMP_BAD_PD                                      = 0x0105,
+       NES_AEQE_AEID_AMP_BAD_STAG_KEY                                = 0x0106,
+       NES_AEQE_AEID_AMP_BAD_STAG_INDEX                              = 0x0107,
+       NES_AEQE_AEID_AMP_BOUNDS_VIOLATION                            = 0x0108,
+       NES_AEQE_AEID_AMP_RIGHTS_VIOLATION                            = 0x0109,
+       NES_AEQE_AEID_AMP_TO_WRAP                                     = 0x010a,
+       NES_AEQE_AEID_AMP_FASTREG_SHARED                              = 0x010b,
+       NES_AEQE_AEID_AMP_FASTREG_VALID_STAG                          = 0x010c,
+       NES_AEQE_AEID_AMP_FASTREG_MW_STAG                             = 0x010d,
+       NES_AEQE_AEID_AMP_FASTREG_INVALID_RIGHTS                      = 0x010e,
+       NES_AEQE_AEID_AMP_FASTREG_PBL_TABLE_OVERFLOW                  = 0x010f,
+       NES_AEQE_AEID_AMP_FASTREG_INVALID_LENGTH                      = 0x0110,
+       NES_AEQE_AEID_AMP_INVALIDATE_SHARED                           = 0x0111,
+       NES_AEQE_AEID_AMP_INVALIDATE_NO_REMOTE_ACCESS_RIGHTS          = 0x0112,
+       NES_AEQE_AEID_AMP_INVALIDATE_MR_WITH_BOUND_WINDOWS            = 0x0113,
+       NES_AEQE_AEID_AMP_MWBIND_VALID_STAG                           = 0x0114,
+       NES_AEQE_AEID_AMP_MWBIND_OF_MR_STAG                           = 0x0115,
+       NES_AEQE_AEID_AMP_MWBIND_TO_ZERO_BASED_STAG                   = 0x0116,
+       NES_AEQE_AEID_AMP_MWBIND_TO_MW_STAG                           = 0x0117,
+       NES_AEQE_AEID_AMP_MWBIND_INVALID_RIGHTS                       = 0x0118,
+       NES_AEQE_AEID_AMP_MWBIND_INVALID_BOUNDS                       = 0x0119,
+       NES_AEQE_AEID_AMP_MWBIND_TO_INVALID_PARENT                    = 0x011a,
+       NES_AEQE_AEID_AMP_MWBIND_BIND_DISABLED                        = 0x011b,
+       NES_AEQE_AEID_BAD_CLOSE                                       = 0x0201,
+       NES_AEQE_AEID_RDMAP_ROE_BAD_LLP_CLOSE                         = 0x0202,
+       NES_AEQE_AEID_CQ_OPERATION_ERROR                              = 0x0203,
+       NES_AEQE_AEID_PRIV_OPERATION_DENIED                           = 0x0204,
+       NES_AEQE_AEID_RDMA_READ_WHILE_ORD_ZERO                        = 0x0205,
+       NES_AEQE_AEID_STAG_ZERO_INVALID                               = 0x0206,
+       NES_AEQE_AEID_DDP_INVALID_MSN_GAP_IN_MSN                      = 0x0301,
+       NES_AEQE_AEID_DDP_INVALID_MSN_RANGE_IS_NOT_VALID              = 0x0302,
+       NES_AEQE_AEID_DDP_UBE_DDP_MESSAGE_TOO_LONG_FOR_AVAILABLE_BUFFER = 0x0303,
+       NES_AEQE_AEID_DDP_UBE_INVALID_DDP_VERSION                     = 0x0304,
+       NES_AEQE_AEID_DDP_UBE_INVALID_MO                              = 0x0305,
+       NES_AEQE_AEID_DDP_UBE_INVALID_MSN_NO_BUFFER_AVAILABLE         = 0x0306,
+       NES_AEQE_AEID_DDP_UBE_INVALID_QN                              = 0x0307,
+       NES_AEQE_AEID_DDP_NO_L_BIT                                    = 0x0308,
+       NES_AEQE_AEID_RDMAP_ROE_INVALID_RDMAP_VERSION                 = 0x0311,
+       NES_AEQE_AEID_RDMAP_ROE_UNEXPECTED_OPCODE                     = 0x0312,
+       NES_AEQE_AEID_ROE_INVALID_RDMA_READ_REQUEST                   = 0x0313,
+       NES_AEQE_AEID_ROE_INVALID_RDMA_WRITE_OR_READ_RESP             = 0x0314,
+       NES_AEQE_AEID_INVALID_ARP_ENTRY                               = 0x0401,
+       NES_AEQE_AEID_INVALID_TCP_OPTION_RCVD                         = 0x0402,
+       NES_AEQE_AEID_STALE_ARP_ENTRY                                 = 0x0403,
+       NES_AEQE_AEID_LLP_CLOSE_COMPLETE                              = 0x0501,
+       NES_AEQE_AEID_LLP_CONNECTION_RESET                            = 0x0502,
+       NES_AEQE_AEID_LLP_FIN_RECEIVED                                = 0x0503,
+       NES_AEQE_AEID_LLP_RECEIVED_MARKER_AND_LENGTH_FIELDS_DONT_MATCH =  0x0504,
+       NES_AEQE_AEID_LLP_RECEIVED_MPA_CRC_ERROR                      = 0x0505,
+       NES_AEQE_AEID_LLP_SEGMENT_TOO_LARGE                           = 0x0506,
+       NES_AEQE_AEID_LLP_SEGMENT_TOO_SMALL                           = 0x0507,
+       NES_AEQE_AEID_LLP_SYN_RECEIVED                                = 0x0508,
+       NES_AEQE_AEID_LLP_TERMINATE_RECEIVED                          = 0x0509,
+       NES_AEQE_AEID_LLP_TOO_MANY_RETRIES                            = 0x050a,
+       NES_AEQE_AEID_LLP_TOO_MANY_KEEPALIVE_RETRIES                  = 0x050b,
+       NES_AEQE_AEID_RESET_SENT                                      = 0x0601,
+       NES_AEQE_AEID_TERMINATE_SENT                                  = 0x0602,
+       NES_AEQE_AEID_DDP_LCE_LOCAL_CATASTROPHIC                      = 0x0700
+};
+
+enum nes_iwarp_sq_opcodes {
+       NES_IWARP_SQ_WQE_WRPDU = (1<<15),
+       NES_IWARP_SQ_WQE_PSH = (1<<21),
+       NES_IWARP_SQ_WQE_STREAMING = (1<<23),
+       NES_IWARP_SQ_WQE_IMM_DATA = (1<<28),
+       NES_IWARP_SQ_WQE_READ_FENCE = (1<<29),
+       NES_IWARP_SQ_WQE_LOCAL_FENCE = (1<<30),
+       NES_IWARP_SQ_WQE_SIGNALED_COMPL = (1<<31),
+};
+
+enum nes_iwarp_sq_wqe_bits {
+       NES_IWARP_SQ_OP_RDMAW = 0,
+       NES_IWARP_SQ_OP_RDMAR = 1,
+       NES_IWARP_SQ_OP_SEND = 3,
+       NES_IWARP_SQ_OP_SENDINV = 4,
+       NES_IWARP_SQ_OP_SENDSE = 5,
+       NES_IWARP_SQ_OP_SENDSEINV = 6,
+       NES_IWARP_SQ_OP_BIND = 8,
+       NES_IWARP_SQ_OP_FAST_REG = 9,
+       NES_IWARP_SQ_OP_LOCINV = 10,
+       NES_IWARP_SQ_OP_RDMAR_LOCINV = 11,
+       NES_IWARP_SQ_OP_NOP = 12,
+};
+
+#define NES_EEPROM_READ_REQUEST (1<<16)
+#define NES_MAC_ADDR_VALID      (1<<20)
+
+/*
+ * NES index registers init values.
+ */
+struct nes_init_values {
+       u32 index;
+       u32 data;
+       u8  wrt;
+};
+
+/*
+ * NES registers in BAR0.
+ */
+struct nes_pci_regs {
+       u32 int_status;
+       u32 int_mask;
+       u32 int_pending;
+       u32 intf_int_status;
+       u32 intf_int_mask;
+       u32 other_regs[59];      /* pad out to 256 bytes for now */
+};
+
+#define NES_CQP_SQ_SIZE    128
+#define NES_CCQ_SIZE       128
+#define NES_NIC_WQ_SIZE    512
+#define NES_NIC_CTX_SIZE   ((NES_NIC_CTX_RQ_SIZE_512) | (NES_NIC_CTX_SQ_SIZE_512))
+#define NES_NIC_BACK_STORE 0x00038000
+
+struct nes_device;
+
+struct nes_hw_nic_qp_context {
+       __le32 context_words[6];
+};
+
+struct nes_hw_nic_sq_wqe {
+       __le32 wqe_words[16];
+};
+
+struct nes_hw_nic_rq_wqe {
+       __le32 wqe_words[16];
+};
+
+struct nes_hw_nic_cqe {
+       __le32 cqe_words[4];
+};
+
+struct nes_hw_cqp_qp_context {
+       __le32 context_words[4];
+};
+
+struct nes_hw_cqp_wqe {
+       __le32 wqe_words[16];
+};
+
+struct nes_hw_qp_wqe {
+       __le32 wqe_words[32];
+};
+
+struct nes_hw_cqe {
+       __le32 cqe_words[8];
+};
+
+struct nes_hw_ceqe {
+       __le32 ceqe_words[2];
+};
+
+struct nes_hw_aeqe {
+       __le32 aeqe_words[4];
+};
+
+struct nes_cqp_request {
+       union {
+               u64 cqp_callback_context;
+               void *cqp_callback_pointer;
+       };
+       wait_queue_head_t     waitq;
+       struct nes_hw_cqp_wqe cqp_wqe;
+       struct list_head      list;
+       atomic_t              refcount;
+       void (*cqp_callback)(struct nes_device *nesdev, struct nes_cqp_request *cqp_request);
+       u16                   major_code;
+       u16                   minor_code;
+       u8                    waiting;
+       u8                    request_done;
+       u8                    dynamic;
+       u8                    callback;
+};
+
+struct nes_hw_cqp {
+       struct nes_hw_cqp_wqe *sq_vbase;
+       dma_addr_t            sq_pbase;
+       spinlock_t            lock;
+       wait_queue_head_t     waitq;
+       u16                   qp_id;
+       u16                   sq_head;
+       u16                   sq_tail;
+       u16                   sq_size;
+};
+
+#define NES_FIRST_FRAG_SIZE 128
+struct nes_first_frag {
+       u8 buffer[NES_FIRST_FRAG_SIZE];
+};
+
+struct nes_hw_nic {
+       struct nes_first_frag    *first_frag_vbase;     /* virtual address of first frags */
+       struct nes_hw_nic_sq_wqe *sq_vbase;                     /* virtual address of sq */
+       struct nes_hw_nic_rq_wqe *rq_vbase;                     /* virtual address of rq */
+       struct sk_buff           *tx_skb[NES_NIC_WQ_SIZE];
+       struct sk_buff           *rx_skb[NES_NIC_WQ_SIZE];
+       dma_addr_t frag_paddr[NES_NIC_WQ_SIZE];
+       unsigned long first_frag_overflow[BITS_TO_LONGS(NES_NIC_WQ_SIZE)];
+       dma_addr_t sq_pbase;                    /* PCI memory for host rings */
+       dma_addr_t rq_pbase;                    /* PCI memory for host rings */
+
+       u16 qp_id;
+       u16 sq_head;
+       u16 sq_tail;
+       u16 sq_size;
+       u16 rq_head;
+       u16 rq_tail;
+       u16 rq_size;
+       u8 replenishing_rq;
+       u8 reserved;
+
+       spinlock_t sq_lock;
+       spinlock_t rq_lock;
+};
+
+struct nes_hw_nic_cq {
+       struct nes_hw_nic_cqe volatile *cq_vbase;       /* PCI memory for host rings */
+       void (*ce_handler)(struct nes_device *nesdev, struct nes_hw_nic_cq *cq);
+       dma_addr_t cq_pbase;    /* PCI memory for host rings */
+       int rx_cqes_completed;
+       int cqe_allocs_pending;
+       int rx_pkts_indicated;
+       u16 cq_head;
+       u16 cq_size;
+       u16 cq_number;
+       u8  cqes_pending;
+};
+
+struct nes_hw_qp {
+       struct nes_hw_qp_wqe *sq_vbase;         /* PCI memory for host rings */
+       struct nes_hw_qp_wqe *rq_vbase;         /* PCI memory for host rings */
+       void                 *q2_vbase;                 /* PCI memory for host rings */
+       dma_addr_t sq_pbase;    /* PCI memory for host rings */
+       dma_addr_t rq_pbase;    /* PCI memory for host rings */
+       dma_addr_t q2_pbase;    /* PCI memory for host rings */
+       u32 qp_id;
+       u16 sq_head;
+       u16 sq_tail;
+       u16 sq_size;
+       u16 rq_head;
+       u16 rq_tail;
+       u16 rq_size;
+       u8  rq_encoded_size;
+       u8  sq_encoded_size;
+};
+
+struct nes_hw_cq {
+       struct nes_hw_cqe volatile *cq_vbase;   /* PCI memory for host rings */
+       void (*ce_handler)(struct nes_device *nesdev, struct nes_hw_cq *cq);
+       dma_addr_t cq_pbase;    /* PCI memory for host rings */
+       u16 cq_head;
+       u16 cq_size;
+       u16 cq_number;
+};
+
+struct nes_hw_ceq {
+       struct nes_hw_ceqe volatile *ceq_vbase; /* PCI memory for host rings */
+       dma_addr_t ceq_pbase;   /* PCI memory for host rings */
+       u16 ceq_head;
+       u16 ceq_size;
+};
+
+struct nes_hw_aeq {
+       struct nes_hw_aeqe volatile *aeq_vbase; /* PCI memory for host rings */
+       dma_addr_t aeq_pbase;   /* PCI memory for host rings */
+       u16 aeq_head;
+       u16 aeq_size;
+};
+
+struct nic_qp_map {
+       u8 qpid;
+       u8 nic_index;
+       u8 logical_port;
+       u8 is_hnic;
+};
+
+#define        NES_CQP_ARP_AEQ_INDEX_MASK  0x000f0000
+#define        NES_CQP_ARP_AEQ_INDEX_SHIFT 16
+
+#define NES_CQP_APBVT_ADD                      0x00008000
+#define NES_CQP_APBVT_NIC_SHIFT                16
+
+#define NES_ARP_ADD     1
+#define NES_ARP_DELETE  2
+#define NES_ARP_RESOLVE 3
+
+#define NES_MAC_SW_IDLE      0
+#define NES_MAC_SW_INTERRUPT 1
+#define NES_MAC_SW_MH        2
+
+struct nes_arp_entry {
+       u32 ip_addr;
+       u8  mac_addr[ETH_ALEN];
+};
+
+#define NES_NIC_FAST_TIMER          96
+#define NES_NIC_FAST_TIMER_LOW      40
+#define NES_NIC_FAST_TIMER_HIGH     1000
+#define DEFAULT_NES_QL_HIGH         256
+#define DEFAULT_NES_QL_LOW          16
+#define DEFAULT_NES_QL_TARGET       64
+#define DEFAULT_JUMBO_NES_QL_LOW    12
+#define DEFAULT_JUMBO_NES_QL_TARGET 40
+#define DEFAULT_JUMBO_NES_QL_HIGH   128
+#define NES_NIC_CQ_DOWNWARD_TREND   8
+
+struct nes_hw_tune_timer {
+    //u16 cq_count;
+    u16 threshold_low;
+    u16 threshold_target;
+    u16 threshold_high;
+    u16 timer_in_use;
+    u16 timer_in_use_old;
+    u16 timer_in_use_min;
+    u16 timer_in_use_max;
+    u8  timer_direction_upward;
+    u8  timer_direction_downward;
+    u16 cq_count_old;
+    u8  cq_direction_downward;
+};
+
+#define NES_TIMER_INT_LIMIT         2
+#define NES_TIMER_INT_LIMIT_DYNAMIC 10
+#define NES_TIMER_ENABLE_LIMIT      4
+#define NES_MAX_LINK_INTERRUPTS                128
+#define NES_MAX_LINK_CHECK             200
+
+struct nes_adapter {
+       u64              fw_ver;
+       unsigned long    *allocated_qps;
+       unsigned long    *allocated_cqs;
+       unsigned long    *allocated_mrs;
+       unsigned long    *allocated_pds;
+       unsigned long    *allocated_arps;
+       struct nes_qp    **qp_table;
+       struct workqueue_struct *work_q;
+
+       struct list_head list;
+       struct list_head active_listeners;
+       /* list of the netdev's associated with each logical port */
+       struct list_head nesvnic_list[4];
+
+       struct timer_list  mh_timer;
+       struct timer_list  lc_timer;
+       struct work_struct work;
+       spinlock_t         resource_lock;
+       spinlock_t         phy_lock;
+       spinlock_t         pbl_lock;
+       spinlock_t         periodic_timer_lock;
+
+       struct nes_arp_entry arp_table[NES_MAX_ARP_TABLE_SIZE];
+
+       /* Adapter CEQ and AEQs */
+       struct nes_hw_ceq ceq[16];
+       struct nes_hw_aeq aeq[8];
+
+       struct nes_hw_tune_timer tune_timer;
+
+       unsigned long doorbell_start;
+
+       u32 hw_rev;
+       u32 vendor_id;
+       u32 vendor_part_id;
+       u32 device_cap_flags;
+       u32 tick_delta;
+       u32 timer_int_req;
+       u32 arp_table_size;
+       u32 next_arp_index;
+
+       u32 max_mr;
+       u32 max_256pbl;
+       u32 max_4kpbl;
+       u32 free_256pbl;
+       u32 free_4kpbl;
+       u32 max_mr_size;
+       u32 max_qp;
+       u32 next_qp;
+       u32 max_irrq;
+       u32 max_qp_wr;
+       u32 max_sge;
+       u32 max_cq;
+       u32 next_cq;
+       u32 max_cqe;
+       u32 max_pd;
+       u32 base_pd;
+       u32 next_pd;
+       u32 hte_index_mask;
+
+       /* EEPROM information */
+       u32 rx_pool_size;
+       u32 tx_pool_size;
+       u32 rx_threshold;
+       u32 tcp_timer_core_clk_divisor;
+       u32 iwarp_config;
+       u32 cm_config;
+       u32 sws_timer_config;
+       u32 tcp_config1;
+       u32 wqm_wat;
+       u32 core_clock;
+       u32 firmware_version;
+
+       u32 nic_rx_eth_route_err;
+
+       u32 et_rx_coalesce_usecs;
+       u32     et_rx_max_coalesced_frames;
+       u32 et_rx_coalesce_usecs_irq;
+       u32 et_rx_max_coalesced_frames_irq;
+       u32 et_pkt_rate_low;
+       u32 et_rx_coalesce_usecs_low;
+       u32 et_rx_max_coalesced_frames_low;
+       u32 et_pkt_rate_high;
+       u32 et_rx_coalesce_usecs_high;
+       u32 et_rx_max_coalesced_frames_high;
+       u32 et_rate_sample_interval;
+       u32 timer_int_limit;
+
+       /* Adapter base MAC address */
+       u32 mac_addr_low;
+       u16 mac_addr_high;
+
+       u16 firmware_eeprom_offset;
+       u16 software_eeprom_offset;
+
+       u16 max_irrq_wr;
+
+       /* pd config for each port */
+       u16 pd_config_size[4];
+       u16 pd_config_base[4];
+
+       u16 link_interrupt_count[4];
+
+       /* the phy index for each port */
+       u8  phy_index[4];
+       u8  mac_sw_state[4];
+       u8  mac_link_down[4];
+       u8  phy_type[4];
+
+       /* PCI information */
+       unsigned int  devfn;
+       unsigned char bus_number;
+       unsigned char OneG_Mode;
+
+       unsigned char ref_count;
+       u8            netdev_count;
+       u8            netdev_max;       /* from host nic address count in EEPROM */
+       u8            port_count;
+       u8            virtwq;
+       u8            et_use_adaptive_rx_coalesce;
+       u8            adapter_fcn_count;
+};
+
+struct nes_pbl {
+       u64              *pbl_vbase;
+       dma_addr_t       pbl_pbase;
+       struct page      *page;
+       unsigned long    user_base;
+       u32              pbl_size;
+       struct list_head list;
+       /* TODO: need to add list for two level tables */
+};
+
+struct nes_listener {
+       struct work_struct      work;
+       struct workqueue_struct *wq;
+       struct nes_vnic         *nesvnic;
+       struct iw_cm_id         *cm_id;
+       struct list_head        list;
+       unsigned long           socket;
+       u8                      accept_failed;
+};
+
+struct nes_ib_device;
+
+struct nes_vnic {
+       struct nes_ib_device *nesibdev;
+       u64 sq_full;
+       u64 sq_locked;
+       u64 tso_requests;
+       u64 segmented_tso_requests;
+       u64 linearized_skbs;
+       u64 tx_sw_dropped;
+       u64 endnode_nstat_rx_discard;
+       u64 endnode_nstat_rx_octets;
+       u64 endnode_nstat_rx_frames;
+       u64 endnode_nstat_tx_octets;
+       u64 endnode_nstat_tx_frames;
+       u64 endnode_ipv4_tcp_retransmits;
+       /* void *mem; */
+       struct nes_device *nesdev;
+       struct net_device *netdev;
+       struct vlan_group *vlan_grp;
+       atomic_t          rx_skbs_needed;
+       atomic_t          rx_skb_timer_running;
+       int               budget;
+       u32               msg_enable;
+       /* u32 tx_avail; */
+       __be32            local_ipaddr;
+       struct napi_struct   napi;
+       spinlock_t           tx_lock;   /* could use netdev tx lock? */
+       struct timer_list    rq_wqes_timer;
+       u32                  nic_mem_size;
+       void                 *nic_vbase;
+       dma_addr_t           nic_pbase;
+       struct nes_hw_nic    nic;
+       struct nes_hw_nic_cq nic_cq;
+       u32    mcrq_qp_id;
+       struct nes_ucontext *mcrq_ucontext;
+       struct nes_cqp_request* (*get_cqp_request)(struct nes_device *nesdev);
+       void (*post_cqp_request)(struct nes_device*, struct nes_cqp_request *, int);
+       int (*mcrq_mcast_filter)( struct nes_vnic* nesvnic, __u8* dmi_addr );
+       struct net_device_stats netstats;
+       /* used to put the netdev on the adapters logical port list */
+       struct list_head list;
+       u16 max_frame_size;
+       u8  netdev_open;
+       u8  linkup;
+       u8  logical_port;
+       u8  netdev_index;  /* might not be needed, indexes nesdev->netdev */
+       u8  perfect_filter_index;
+       u8  nic_index;
+       u8  qp_nic_index[4];
+       u8  next_qp_nic_index;
+       u8  of_device_registered;
+       u8  rdma_enabled;
+       u8  rx_checksum_disabled;
+};
+
+struct nes_ib_device {
+       struct ib_device ibdev;
+       struct nes_vnic *nesvnic;
+
+       /* Virtual RNIC Limits */
+       u32 max_mr;
+       u32 max_qp;
+       u32 max_cq;
+       u32 max_pd;
+       u32 num_mr;
+       u32 num_qp;
+       u32 num_cq;
+       u32 num_pd;
+};
+
+#define nes_vlan_rx vlan_hwaccel_receive_skb
+#define nes_netif_rx netif_receive_skb
+
+#endif         /* __NES_HW_H */
diff --git a/drivers/infiniband/hw/nes/nes_nic.c b/drivers/infiniband/hw/nes/nes_nic.c
new file mode 100644 (file)
index 0000000..b6cc265
--- /dev/null
@@ -0,0 +1,1703 @@
+/*
+ * Copyright (c) 2006 - 2008 NetEffect, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/if_arp.h>
+#include <linux/if_vlan.h>
+#include <linux/ethtool.h>
+#include <net/tcp.h>
+
+#include <net/inet_common.h>
+#include <linux/inet.h>
+
+#include "nes.h"
+
+static struct nic_qp_map nic_qp_mapping_0[] = {
+       {16,0,0,1},{24,4,0,0},{28,8,0,0},{32,12,0,0},
+       {20,2,2,1},{26,6,2,0},{30,10,2,0},{34,14,2,0},
+       {18,1,1,1},{25,5,1,0},{29,9,1,0},{33,13,1,0},
+       {22,3,3,1},{27,7,3,0},{31,11,3,0},{35,15,3,0}
+};
+
+static struct nic_qp_map nic_qp_mapping_1[] = {
+       {18,1,1,1},{25,5,1,0},{29,9,1,0},{33,13,1,0},
+       {22,3,3,1},{27,7,3,0},{31,11,3,0},{35,15,3,0}
+};
+
+static struct nic_qp_map nic_qp_mapping_2[] = {
+       {20,2,2,1},{26,6,2,0},{30,10,2,0},{34,14,2,0}
+};
+
+static struct nic_qp_map nic_qp_mapping_3[] = {
+       {22,3,3,1},{27,7,3,0},{31,11,3,0},{35,15,3,0}
+};
+
+static struct nic_qp_map nic_qp_mapping_4[] = {
+       {28,8,0,0},{32,12,0,0}
+};
+
+static struct nic_qp_map nic_qp_mapping_5[] = {
+       {29,9,1,0},{33,13,1,0}
+};
+
+static struct nic_qp_map nic_qp_mapping_6[] = {
+       {30,10,2,0},{34,14,2,0}
+};
+
+static struct nic_qp_map nic_qp_mapping_7[] = {
+       {31,11,3,0},{35,15,3,0}
+};
+
+static struct nic_qp_map *nic_qp_mapping_per_function[] = {
+       nic_qp_mapping_0, nic_qp_mapping_1, nic_qp_mapping_2, nic_qp_mapping_3,
+       nic_qp_mapping_4, nic_qp_mapping_5, nic_qp_mapping_6, nic_qp_mapping_7
+};
+
+static const u32 default_msg = NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK
+               | NETIF_MSG_IFUP | NETIF_MSG_IFDOWN;
+static int debug = -1;
+
+
+static int nes_netdev_open(struct net_device *);
+static int nes_netdev_stop(struct net_device *);
+static int nes_netdev_start_xmit(struct sk_buff *, struct net_device *);
+static struct net_device_stats *nes_netdev_get_stats(struct net_device *);
+static void nes_netdev_tx_timeout(struct net_device *);
+static int nes_netdev_set_mac_address(struct net_device *, void *);
+static int nes_netdev_change_mtu(struct net_device *, int);
+
+/**
+ * nes_netdev_poll
+ */
+static int nes_netdev_poll(struct napi_struct *napi, int budget)
+{
+       struct nes_vnic *nesvnic = container_of(napi, struct nes_vnic, napi);
+       struct net_device *netdev = nesvnic->netdev;
+       struct nes_device *nesdev = nesvnic->nesdev;
+       struct nes_hw_nic_cq *nescq = &nesvnic->nic_cq;
+
+       nesvnic->budget = budget;
+       nescq->cqes_pending = 0;
+       nescq->rx_cqes_completed = 0;
+       nescq->cqe_allocs_pending = 0;
+       nescq->rx_pkts_indicated = 0;
+
+       nes_nic_ce_handler(nesdev, nescq);
+
+       if (nescq->cqes_pending == 0) {
+               netif_rx_complete(netdev, napi);
+               /* clear out completed cqes and arm */
+               nes_write32(nesdev->regs+NES_CQE_ALLOC, NES_CQE_ALLOC_NOTIFY_NEXT |
+                               nescq->cq_number | (nescq->cqe_allocs_pending << 16));
+               nes_read32(nesdev->regs+NES_CQE_ALLOC);
+       } else {
+               /* clear out completed cqes but don't arm */
+               nes_write32(nesdev->regs+NES_CQE_ALLOC,
+                               nescq->cq_number | (nescq->cqe_allocs_pending << 16));
+               nes_debug(NES_DBG_NETDEV, "%s: exiting with work pending\n",
+                               nesvnic->netdev->name);
+       }
+       return nescq->rx_pkts_indicated;
+}
+
+
+/**
+ * nes_netdev_open - Activate the network interface; ifconfig
+ * ethx up.
+ */
+static int nes_netdev_open(struct net_device *netdev)
+{
+       u32 macaddr_low;
+       u16 macaddr_high;
+       struct nes_vnic *nesvnic = netdev_priv(netdev);
+       struct nes_device *nesdev = nesvnic->nesdev;
+       int ret;
+       int i;
+       struct nes_vnic *first_nesvnic;
+       u32 nic_active_bit;
+       u32 nic_active;
+
+       assert(nesdev != NULL);
+
+       first_nesvnic = list_entry(nesdev->nesadapter->nesvnic_list[nesdev->mac_index].next,
+                       struct nes_vnic, list);
+
+       if (netif_msg_ifup(nesvnic))
+               printk(KERN_INFO PFX "%s: enabling interface\n", netdev->name);
+
+       ret = nes_init_nic_qp(nesdev, netdev);
+       if (ret) {
+               return ret;
+       }
+
+       netif_carrier_off(netdev);
+       netif_stop_queue(netdev);
+
+       if ((!nesvnic->of_device_registered) && (nesvnic->rdma_enabled)) {
+               nesvnic->nesibdev = nes_init_ofa_device(netdev);
+               if (nesvnic->nesibdev == NULL) {
+                       printk(KERN_ERR PFX "%s: nesvnic->nesibdev alloc failed", netdev->name);
+               } else {
+                       nesvnic->nesibdev->nesvnic = nesvnic;
+                       ret = nes_register_ofa_device(nesvnic->nesibdev);
+                       if (ret) {
+                               printk(KERN_ERR PFX "%s: Unable to register RDMA device, ret = %d\n",
+                                               netdev->name, ret);
+                       }
+               }
+       }
+       /* Set packet filters */
+       nic_active_bit = 1 << nesvnic->nic_index;
+       nic_active = nes_read_indexed(nesdev, NES_IDX_NIC_ACTIVE);
+       nic_active |= nic_active_bit;
+       nes_write_indexed(nesdev, NES_IDX_NIC_ACTIVE, nic_active);
+       nic_active = nes_read_indexed(nesdev, NES_IDX_NIC_MULTICAST_ENABLE);
+       nic_active |= nic_active_bit;
+       nes_write_indexed(nesdev, NES_IDX_NIC_MULTICAST_ENABLE, nic_active);
+       nic_active = nes_read_indexed(nesdev, NES_IDX_NIC_BROADCAST_ON);
+       nic_active |= nic_active_bit;
+       nes_write_indexed(nesdev, NES_IDX_NIC_BROADCAST_ON, nic_active);
+
+       macaddr_high = ((u16)netdev->dev_addr[0]) << 8;
+       macaddr_high += (u16)netdev->dev_addr[1];
+       macaddr_low = ((u32)netdev->dev_addr[2]) << 24;
+       macaddr_low += ((u32)netdev->dev_addr[3]) << 16;
+       macaddr_low += ((u32)netdev->dev_addr[4]) << 8;
+       macaddr_low += (u32)netdev->dev_addr[5];
+
+       /* Program the various MAC regs */
+       for (i = 0; i < NES_MAX_PORT_COUNT; i++) {
+               if (nesvnic->qp_nic_index[i] == 0xf) {
+                       break;
+               }
+               nes_debug(NES_DBG_NETDEV, "i=%d, perfect filter table index= %d, PERF FILTER LOW"
+                               " (Addr:%08X) = %08X, HIGH = %08X.\n",
+                               i, nesvnic->qp_nic_index[i],
+                               NES_IDX_PERFECT_FILTER_LOW+((nesvnic->perfect_filter_index + i) * 8),
+                               macaddr_low,
+                               (u32)macaddr_high | NES_MAC_ADDR_VALID |
+                               ((((u32)nesvnic->nic_index) << 16)));
+               nes_write_indexed(nesdev,
+                               NES_IDX_PERFECT_FILTER_LOW + (nesvnic->qp_nic_index[i] * 8),
+                               macaddr_low);
+               nes_write_indexed(nesdev,
+                               NES_IDX_PERFECT_FILTER_HIGH + (nesvnic->qp_nic_index[i] * 8),
+                               (u32)macaddr_high | NES_MAC_ADDR_VALID |
+                               ((((u32)nesvnic->nic_index) << 16)));
+       }
+
+
+       nes_write32(nesdev->regs+NES_CQE_ALLOC, NES_CQE_ALLOC_NOTIFY_NEXT |
+                       nesvnic->nic_cq.cq_number);
+       nes_read32(nesdev->regs+NES_CQE_ALLOC);
+
+       if (first_nesvnic->linkup) {
+               /* Enable network packets */
+               nesvnic->linkup = 1;
+               netif_start_queue(netdev);
+               netif_carrier_on(netdev);
+       }
+       napi_enable(&nesvnic->napi);
+       nesvnic->netdev_open = 1;
+
+       return 0;
+}
+
+
+/**
+ * nes_netdev_stop
+ */
+static int nes_netdev_stop(struct net_device *netdev)
+{
+       struct nes_vnic *nesvnic = netdev_priv(netdev);
+       struct nes_device *nesdev = nesvnic->nesdev;
+       u32 nic_active_mask;
+       u32 nic_active;
+
+       nes_debug(NES_DBG_SHUTDOWN, "nesvnic=%p, nesdev=%p, netdev=%p %s\n",
+                       nesvnic, nesdev, netdev, netdev->name);
+       if (nesvnic->netdev_open == 0)
+               return 0;
+
+       if (netif_msg_ifdown(nesvnic))
+               printk(KERN_INFO PFX "%s: disabling interface\n", netdev->name);
+
+       /* Disable network packets */
+       napi_disable(&nesvnic->napi);
+       netif_stop_queue(netdev);
+       if ((nesdev->netdev[0] == netdev) & (nesvnic->logical_port == nesdev->mac_index)) {
+               nes_write_indexed(nesdev,
+                               NES_IDX_MAC_INT_MASK+(0x200*nesdev->mac_index), 0xffffffff);
+       }
+
+       nic_active_mask = ~((u32)(1 << nesvnic->nic_index));
+       nes_write_indexed(nesdev, NES_IDX_PERFECT_FILTER_HIGH+
+                       (nesvnic->perfect_filter_index*8), 0);
+       nic_active = nes_read_indexed(nesdev, NES_IDX_NIC_ACTIVE);
+       nic_active &= nic_active_mask;
+       nes_write_indexed(nesdev, NES_IDX_NIC_ACTIVE, nic_active);
+       nic_active = nes_read_indexed(nesdev, NES_IDX_NIC_MULTICAST_ALL);
+       nic_active &= nic_active_mask;
+       nes_write_indexed(nesdev, NES_IDX_NIC_MULTICAST_ALL, nic_active);
+       nic_active = nes_read_indexed(nesdev, NES_IDX_NIC_MULTICAST_ENABLE);
+       nic_active &= nic_active_mask;
+       nes_write_indexed(nesdev, NES_IDX_NIC_MULTICAST_ENABLE, nic_active);
+       nic_active = nes_read_indexed(nesdev, NES_IDX_NIC_UNICAST_ALL);
+       nic_active &= nic_active_mask;
+       nes_write_indexed(nesdev, NES_IDX_NIC_UNICAST_ALL, nic_active);
+       nic_active = nes_read_indexed(nesdev, NES_IDX_NIC_BROADCAST_ON);
+       nic_active &= nic_active_mask;
+       nes_write_indexed(nesdev, NES_IDX_NIC_BROADCAST_ON, nic_active);
+
+
+       if (nesvnic->of_device_registered) {
+               nes_destroy_ofa_device(nesvnic->nesibdev);
+               nesvnic->nesibdev = NULL;
+               nesvnic->of_device_registered = 0;
+       }
+       nes_destroy_nic_qp(nesvnic);
+
+       nesvnic->netdev_open = 0;
+
+       return 0;
+}
+
+
+/**
+ * nes_nic_send
+ */
+static int nes_nic_send(struct sk_buff *skb, struct net_device *netdev)
+{
+       struct nes_vnic *nesvnic = netdev_priv(netdev);
+       struct nes_device *nesdev = nesvnic->nesdev;
+       struct nes_hw_nic *nesnic = &nesvnic->nic;
+       struct nes_hw_nic_sq_wqe *nic_sqe;
+       struct tcphdr *tcph;
+       __le16 *wqe_fragment_length;
+       u32 wqe_misc;
+       u16 wqe_fragment_index = 1;     /* first fragment (0) is used by copy buffer */
+       u16 skb_fragment_index;
+       dma_addr_t bus_address;
+
+       nic_sqe = &nesnic->sq_vbase[nesnic->sq_head];
+       wqe_fragment_length = (__le16 *)&nic_sqe->wqe_words[NES_NIC_SQ_WQE_LENGTH_0_TAG_IDX];
+
+       /* setup the VLAN tag if present */
+       if (vlan_tx_tag_present(skb)) {
+               nes_debug(NES_DBG_NIC_TX, "%s: VLAN packet to send... VLAN = %08X\n",
+                               netdev->name, vlan_tx_tag_get(skb));
+               wqe_misc = NES_NIC_SQ_WQE_TAGVALUE_ENABLE;
+               wqe_fragment_length[0] = (__force __le16) vlan_tx_tag_get(skb);
+       } else
+               wqe_misc = 0;
+
+       /* bump past the vlan tag */
+       wqe_fragment_length++;
+       /*      wqe_fragment_address = (u64 *)&nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG0_LOW_IDX]; */
+
+       if (skb->ip_summed == CHECKSUM_PARTIAL) {
+               tcph = tcp_hdr(skb);
+               if (1) {
+                       if (skb_is_gso(skb)) {
+                               /* nes_debug(NES_DBG_NIC_TX, "%s: TSO request... seg size = %u\n",
+                                               netdev->name, skb_is_gso(skb)); */
+                               wqe_misc |= NES_NIC_SQ_WQE_LSO_ENABLE |
+                                               NES_NIC_SQ_WQE_COMPLETION | (u16)skb_is_gso(skb);
+                               set_wqe_32bit_value(nic_sqe->wqe_words, NES_NIC_SQ_WQE_LSO_INFO_IDX,
+                                               ((u32)tcph->doff) |
+                                               (((u32)(((unsigned char *)tcph) - skb->data)) << 4));
+                       } else {
+                               wqe_misc |= NES_NIC_SQ_WQE_COMPLETION;
+                       }
+               }
+       } else {        /* CHECKSUM_HW */
+               wqe_misc |= NES_NIC_SQ_WQE_DISABLE_CHKSUM | NES_NIC_SQ_WQE_COMPLETION;
+       }
+
+       set_wqe_32bit_value(nic_sqe->wqe_words, NES_NIC_SQ_WQE_TOTAL_LENGTH_IDX,
+                               skb->len);
+       memcpy(&nesnic->first_frag_vbase[nesnic->sq_head].buffer,
+                       skb->data, min(((unsigned int)NES_FIRST_FRAG_SIZE), skb_headlen(skb)));
+       wqe_fragment_length[0] = cpu_to_le16(min(((unsigned int)NES_FIRST_FRAG_SIZE),
+                       skb_headlen(skb)));
+       wqe_fragment_length[1] = 0;
+       if (skb_headlen(skb) > NES_FIRST_FRAG_SIZE) {
+               if ((skb_shinfo(skb)->nr_frags + 1) > 4) {
+                       nes_debug(NES_DBG_NIC_TX, "%s: Packet with %u fragments not sent, skb_headlen=%u\n",
+                                       netdev->name, skb_shinfo(skb)->nr_frags + 2, skb_headlen(skb));
+                       kfree_skb(skb);
+                       nesvnic->tx_sw_dropped++;
+                       return NETDEV_TX_LOCKED;
+               }
+               set_bit(nesnic->sq_head, nesnic->first_frag_overflow);
+               bus_address = pci_map_single(nesdev->pcidev, skb->data + NES_FIRST_FRAG_SIZE,
+                               skb_headlen(skb) - NES_FIRST_FRAG_SIZE, PCI_DMA_TODEVICE);
+               wqe_fragment_length[wqe_fragment_index++] =
+                               cpu_to_le16(skb_headlen(skb) - NES_FIRST_FRAG_SIZE);
+               wqe_fragment_length[wqe_fragment_index] = 0;
+               set_wqe_64bit_value(nic_sqe->wqe_words, NES_NIC_SQ_WQE_FRAG1_LOW_IDX,
+                               ((u64)(bus_address)));
+               nesnic->tx_skb[nesnic->sq_head] = skb;
+       }
+
+       if (skb_headlen(skb) == skb->len) {
+               if (skb_headlen(skb) <= NES_FIRST_FRAG_SIZE) {
+                       nic_sqe->wqe_words[NES_NIC_SQ_WQE_LENGTH_2_1_IDX] = 0;
+                       nesnic->tx_skb[nesnic->sq_head] = NULL;
+                       dev_kfree_skb(skb);
+               }
+       } else {
+               /* Deal with Fragments */
+               nesnic->tx_skb[nesnic->sq_head] = skb;
+               for (skb_fragment_index = 0; skb_fragment_index < skb_shinfo(skb)->nr_frags;
+                               skb_fragment_index++) {
+                       bus_address = pci_map_page( nesdev->pcidev,
+                                       skb_shinfo(skb)->frags[skb_fragment_index].page,
+                                       skb_shinfo(skb)->frags[skb_fragment_index].page_offset,
+                                       skb_shinfo(skb)->frags[skb_fragment_index].size,
+                                       PCI_DMA_TODEVICE);
+                       wqe_fragment_length[wqe_fragment_index] =
+                                       cpu_to_le16(skb_shinfo(skb)->frags[skb_fragment_index].size);
+                       set_wqe_64bit_value(nic_sqe->wqe_words, NES_NIC_SQ_WQE_FRAG0_LOW_IDX+(2*wqe_fragment_index),
+                               bus_address);
+                       wqe_fragment_index++;
+                       if (wqe_fragment_index < 5)
+                               wqe_fragment_length[wqe_fragment_index] = 0;
+               }
+       }
+
+       set_wqe_32bit_value(nic_sqe->wqe_words, NES_NIC_SQ_WQE_MISC_IDX, wqe_misc);
+       nesnic->sq_head++;
+       nesnic->sq_head &= nesnic->sq_size - 1;
+
+       return NETDEV_TX_OK;
+}
+
+
+/**
+ * nes_netdev_start_xmit
+ */
+static int nes_netdev_start_xmit(struct sk_buff *skb, struct net_device *netdev)
+{
+       struct nes_vnic *nesvnic = netdev_priv(netdev);
+       struct nes_device *nesdev = nesvnic->nesdev;
+       struct nes_hw_nic *nesnic = &nesvnic->nic;
+       struct nes_hw_nic_sq_wqe *nic_sqe;
+       struct tcphdr *tcph;
+       /* struct udphdr *udph; */
+#define NES_MAX_TSO_FRAGS 18
+       /* 64K segment plus overflow on each side */
+       dma_addr_t tso_bus_address[NES_MAX_TSO_FRAGS];
+       dma_addr_t bus_address;
+       u32 tso_frag_index;
+       u32 tso_frag_count;
+       u32 tso_wqe_length;
+       u32 curr_tcp_seq;
+       u32 wqe_count=1;
+       u32 send_rc;
+       struct iphdr *iph;
+       unsigned long flags;
+       __le16 *wqe_fragment_length;
+       u32 nr_frags;
+       u32 original_first_length;
+//     u64 *wqe_fragment_address;
+       /* first fragment (0) is used by copy buffer */
+       u16 wqe_fragment_index=1;
+       u16 hoffset;
+       u16 nhoffset;
+       u16 wqes_needed;
+       u16 wqes_available;
+       u32 old_head;
+       u32 wqe_misc;
+
+       /* nes_debug(NES_DBG_NIC_TX, "%s Request to tx NIC packet length %u, headlen %u,"
+                       " (%u frags), tso_size=%u\n",
+                       netdev->name, skb->len, skb_headlen(skb),
+                       skb_shinfo(skb)->nr_frags, skb_is_gso(skb));
+       */
+
+       if (!netif_carrier_ok(netdev))
+               return NETDEV_TX_OK;
+
+       if (netif_queue_stopped(netdev))
+               return NETDEV_TX_BUSY;
+
+       local_irq_save(flags);
+       if (!spin_trylock(&nesnic->sq_lock)) {
+               local_irq_restore(flags);
+               nesvnic->sq_locked++;
+               return NETDEV_TX_LOCKED;
+       }
+
+       /* Check if SQ is full */
+       if ((((nesnic->sq_tail+(nesnic->sq_size*2))-nesnic->sq_head) & (nesnic->sq_size - 1)) == 1) {
+               if (!netif_queue_stopped(netdev)) {
+                       netif_stop_queue(netdev);
+                       barrier();
+                       if ((((((volatile u16)nesnic->sq_tail)+(nesnic->sq_size*2))-nesnic->sq_head) & (nesnic->sq_size - 1)) != 1) {
+                               netif_start_queue(netdev);
+                               goto sq_no_longer_full;
+                       }
+               }
+               nesvnic->sq_full++;
+               spin_unlock_irqrestore(&nesnic->sq_lock, flags);
+               return NETDEV_TX_BUSY;
+       }
+
+sq_no_longer_full:
+       nr_frags = skb_shinfo(skb)->nr_frags;
+       if (skb_headlen(skb) > NES_FIRST_FRAG_SIZE) {
+               nr_frags++;
+       }
+       /* Check if too many fragments */
+       if (unlikely((nr_frags > 4))) {
+               if (skb_is_gso(skb)) {
+                       nesvnic->segmented_tso_requests++;
+                       nesvnic->tso_requests++;
+                       old_head = nesnic->sq_head;
+                       /* Basically 4 fragments available per WQE with extended fragments */
+                       wqes_needed = nr_frags >> 2;
+                       wqes_needed += (nr_frags&3)?1:0;
+                       wqes_available = (((nesnic->sq_tail+nesnic->sq_size)-nesnic->sq_head) - 1) &
+                                       (nesnic->sq_size - 1);
+
+                       if (unlikely(wqes_needed > wqes_available)) {
+                               if (!netif_queue_stopped(netdev)) {
+                                       netif_stop_queue(netdev);
+                                       barrier();
+                                       wqes_available = (((((volatile u16)nesnic->sq_tail)+nesnic->sq_size)-nesnic->sq_head) - 1) &
+                                               (nesnic->sq_size - 1);
+                                       if (wqes_needed <= wqes_available) {
+                                               netif_start_queue(netdev);
+                                               goto tso_sq_no_longer_full;
+                                       }
+                               }
+                               nesvnic->sq_full++;
+                               spin_unlock_irqrestore(&nesnic->sq_lock, flags);
+                               nes_debug(NES_DBG_NIC_TX, "%s: HNIC SQ full- TSO request has too many frags!\n",
+                                               netdev->name);
+                               return NETDEV_TX_BUSY;
+                       }
+tso_sq_no_longer_full:
+                       /* Map all the buffers */
+                       for (tso_frag_count=0; tso_frag_count < skb_shinfo(skb)->nr_frags;
+                                       tso_frag_count++) {
+                               tso_bus_address[tso_frag_count] = pci_map_page( nesdev->pcidev,
+                                               skb_shinfo(skb)->frags[tso_frag_count].page,
+                                               skb_shinfo(skb)->frags[tso_frag_count].page_offset,
+                                               skb_shinfo(skb)->frags[tso_frag_count].size,
+                                               PCI_DMA_TODEVICE);
+                       }
+
+                       tso_frag_index = 0;
+                       curr_tcp_seq = ntohl(tcp_hdr(skb)->seq);
+                       hoffset = skb_transport_header(skb) - skb->data;
+                       nhoffset = skb_network_header(skb) - skb->data;
+                       original_first_length = hoffset + ((((struct tcphdr *)skb_transport_header(skb))->doff)<<2);
+
+                       for (wqe_count=0; wqe_count<((u32)wqes_needed); wqe_count++) {
+                               tso_wqe_length = 0;
+                               nic_sqe = &nesnic->sq_vbase[nesnic->sq_head];
+                               wqe_fragment_length =
+                                               (__le16 *)&nic_sqe->wqe_words[NES_NIC_SQ_WQE_LENGTH_0_TAG_IDX];
+                               /* setup the VLAN tag if present */
+                               if (vlan_tx_tag_present(skb)) {
+                                       nes_debug(NES_DBG_NIC_TX, "%s: VLAN packet to send... VLAN = %08X\n",
+                                                       netdev->name, vlan_tx_tag_get(skb) );
+                                       wqe_misc = NES_NIC_SQ_WQE_TAGVALUE_ENABLE;
+                                       wqe_fragment_length[0] = (__force __le16) vlan_tx_tag_get(skb);
+                               } else
+                                       wqe_misc = 0;
+
+                               /* bump past the vlan tag */
+                               wqe_fragment_length++;
+
+                               /* Assumes header totally fits in allocated buffer and is in first fragment */
+                               if (original_first_length > NES_FIRST_FRAG_SIZE) {
+                                       nes_debug(NES_DBG_NIC_TX, "ERROR: SKB header too big, headlen=%u, FIRST_FRAG_SIZE=%u\n",
+                                                       original_first_length, NES_FIRST_FRAG_SIZE);
+                                       nes_debug(NES_DBG_NIC_TX, "%s Request to tx NIC packet length %u, headlen %u,"
+                                                       " (%u frags), tso_size=%u\n",
+                                                       netdev->name,
+                                                       skb->len, skb_headlen(skb),
+                                                       skb_shinfo(skb)->nr_frags, skb_is_gso(skb));
+                               }
+                               memcpy(&nesnic->first_frag_vbase[nesnic->sq_head].buffer,
+                                               skb->data, min(((unsigned int)NES_FIRST_FRAG_SIZE),
+                                               original_first_length));
+                               iph = (struct iphdr *)
+                               (&nesnic->first_frag_vbase[nesnic->sq_head].buffer[nhoffset]);
+                               tcph = (struct tcphdr *)
+                               (&nesnic->first_frag_vbase[nesnic->sq_head].buffer[hoffset]);
+                               if ((wqe_count+1)!=(u32)wqes_needed) {
+                                       tcph->fin = 0;
+                                       tcph->psh = 0;
+                                       tcph->rst = 0;
+                                       tcph->urg = 0;
+                               }
+                               if (wqe_count) {
+                                       tcph->syn = 0;
+                               }
+                               tcph->seq = htonl(curr_tcp_seq);
+                               wqe_fragment_length[0] = cpu_to_le16(min(((unsigned int)NES_FIRST_FRAG_SIZE),
+                                               original_first_length));
+
+                               wqe_fragment_index = 1;
+                               if ((wqe_count==0) && (skb_headlen(skb) > original_first_length)) {
+                                       set_bit(nesnic->sq_head, nesnic->first_frag_overflow);
+                                       bus_address = pci_map_single(nesdev->pcidev, skb->data + original_first_length,
+                                                       skb_headlen(skb) - original_first_length, PCI_DMA_TODEVICE);
+                                       wqe_fragment_length[wqe_fragment_index++] =
+                                               cpu_to_le16(skb_headlen(skb) - original_first_length);
+                                       wqe_fragment_length[wqe_fragment_index] = 0;
+                                       set_wqe_64bit_value(nic_sqe->wqe_words, NES_NIC_SQ_WQE_FRAG1_LOW_IDX,
+                                                                       bus_address);
+                               }
+                               while (wqe_fragment_index < 5) {
+                                       wqe_fragment_length[wqe_fragment_index] =
+                                                       cpu_to_le16(skb_shinfo(skb)->frags[tso_frag_index].size);
+                                       set_wqe_64bit_value(nic_sqe->wqe_words, NES_NIC_SQ_WQE_FRAG0_LOW_IDX+(2*wqe_fragment_index),
+                                               (u64)tso_bus_address[tso_frag_index]);
+                                       wqe_fragment_index++;
+                                       tso_wqe_length += skb_shinfo(skb)->frags[tso_frag_index++].size;
+                                       if (wqe_fragment_index < 5)
+                                               wqe_fragment_length[wqe_fragment_index] = 0;
+                                       if (tso_frag_index == tso_frag_count)
+                                               break;
+                               }
+                               if ((wqe_count+1) == (u32)wqes_needed) {
+                                       nesnic->tx_skb[nesnic->sq_head] = skb;
+                               } else {
+                                       nesnic->tx_skb[nesnic->sq_head] = NULL;
+                               }
+                               wqe_misc |= NES_NIC_SQ_WQE_COMPLETION | (u16)skb_is_gso(skb);
+                               if ((tso_wqe_length + original_first_length) > skb_is_gso(skb)) {
+                                       wqe_misc |= NES_NIC_SQ_WQE_LSO_ENABLE;
+                               } else {
+                                       iph->tot_len = htons(tso_wqe_length + original_first_length - nhoffset);
+                               }
+
+                               set_wqe_32bit_value(nic_sqe->wqe_words, NES_NIC_SQ_WQE_MISC_IDX,
+                                                wqe_misc);
+                               set_wqe_32bit_value(nic_sqe->wqe_words, NES_NIC_SQ_WQE_LSO_INFO_IDX,
+                                               ((u32)tcph->doff) | (((u32)hoffset) << 4));
+
+                               set_wqe_32bit_value(nic_sqe->wqe_words, NES_NIC_SQ_WQE_TOTAL_LENGTH_IDX,
+                                               tso_wqe_length + original_first_length);
+                               curr_tcp_seq += tso_wqe_length;
+                               nesnic->sq_head++;
+                               nesnic->sq_head &= nesnic->sq_size-1;
+                       }
+               } else {
+                       nesvnic->linearized_skbs++;
+                       hoffset = skb_transport_header(skb) - skb->data;
+                       nhoffset = skb_network_header(skb) - skb->data;
+                       skb_linearize(skb);
+                       skb_set_transport_header(skb, hoffset);
+                       skb_set_network_header(skb, nhoffset);
+                       send_rc = nes_nic_send(skb, netdev);
+                       if (send_rc != NETDEV_TX_OK) {
+                               spin_unlock_irqrestore(&nesnic->sq_lock, flags);
+                               return NETDEV_TX_OK;
+                       }
+               }
+       } else {
+               send_rc = nes_nic_send(skb, netdev);
+               if (send_rc != NETDEV_TX_OK) {
+                       spin_unlock_irqrestore(&nesnic->sq_lock, flags);
+                       return NETDEV_TX_OK;
+               }
+       }
+
+       barrier();
+
+       if (wqe_count)
+               nes_write32(nesdev->regs+NES_WQE_ALLOC,
+                               (wqe_count << 24) | (1 << 23) | nesvnic->nic.qp_id);
+
+       netdev->trans_start = jiffies;
+       spin_unlock_irqrestore(&nesnic->sq_lock, flags);
+
+       return NETDEV_TX_OK;
+}
+
+
+/**
+ * nes_netdev_get_stats
+ */
+static struct net_device_stats *nes_netdev_get_stats(struct net_device *netdev)
+{
+       struct nes_vnic *nesvnic = netdev_priv(netdev);
+       struct nes_device *nesdev = nesvnic->nesdev;
+       u64 u64temp;
+       u32 u32temp;
+
+       u32temp = nes_read_indexed(nesdev,
+                       NES_IDX_ENDNODE0_NSTAT_RX_DISCARD + (nesvnic->nic_index*0x200));
+       nesvnic->netstats.rx_dropped += u32temp;
+       nesvnic->endnode_nstat_rx_discard += u32temp;
+
+       u64temp = (u64)nes_read_indexed(nesdev,
+                       NES_IDX_ENDNODE0_NSTAT_RX_OCTETS_LO + (nesvnic->nic_index*0x200));
+       u64temp += ((u64)nes_read_indexed(nesdev,
+                       NES_IDX_ENDNODE0_NSTAT_RX_OCTETS_HI + (nesvnic->nic_index*0x200))) << 32;
+
+       nesvnic->endnode_nstat_rx_octets += u64temp;
+       nesvnic->netstats.rx_bytes += u64temp;
+
+       u64temp = (u64)nes_read_indexed(nesdev,
+                       NES_IDX_ENDNODE0_NSTAT_RX_FRAMES_LO + (nesvnic->nic_index*0x200));
+       u64temp += ((u64)nes_read_indexed(nesdev,
+                       NES_IDX_ENDNODE0_NSTAT_RX_FRAMES_HI + (nesvnic->nic_index*0x200))) << 32;
+
+       nesvnic->endnode_nstat_rx_frames += u64temp;
+       nesvnic->netstats.rx_packets += u64temp;
+
+       u64temp = (u64)nes_read_indexed(nesdev,
+                       NES_IDX_ENDNODE0_NSTAT_TX_OCTETS_LO + (nesvnic->nic_index*0x200));
+       u64temp += ((u64)nes_read_indexed(nesdev,
+                       NES_IDX_ENDNODE0_NSTAT_TX_OCTETS_HI + (nesvnic->nic_index*0x200))) << 32;
+
+       nesvnic->endnode_nstat_tx_octets += u64temp;
+       nesvnic->netstats.tx_bytes += u64temp;
+
+       u64temp = (u64)nes_read_indexed(nesdev,
+                       NES_IDX_ENDNODE0_NSTAT_TX_FRAMES_LO + (nesvnic->nic_index*0x200));
+       u64temp += ((u64)nes_read_indexed(nesdev,
+                       NES_IDX_ENDNODE0_NSTAT_TX_FRAMES_HI + (nesvnic->nic_index*0x200))) << 32;
+
+       nesvnic->endnode_nstat_tx_frames += u64temp;
+       nesvnic->netstats.tx_packets += u64temp;
+
+       u32temp = nes_read_indexed(nesdev,
+                       NES_IDX_MAC_RX_SHORT_FRAMES + (nesvnic->nesdev->mac_index*0x200));
+       nesvnic->netstats.rx_dropped += u32temp;
+       nesvnic->nesdev->mac_rx_errors += u32temp;
+       nesvnic->nesdev->mac_rx_short_frames += u32temp;
+
+       u32temp = nes_read_indexed(nesdev,
+                       NES_IDX_MAC_RX_OVERSIZED_FRAMES + (nesvnic->nesdev->mac_index*0x200));
+       nesvnic->netstats.rx_dropped += u32temp;
+       nesvnic->nesdev->mac_rx_errors += u32temp;
+       nesvnic->nesdev->mac_rx_oversized_frames += u32temp;
+
+       u32temp = nes_read_indexed(nesdev,
+                       NES_IDX_MAC_RX_JABBER_FRAMES + (nesvnic->nesdev->mac_index*0x200));
+       nesvnic->netstats.rx_dropped += u32temp;
+       nesvnic->nesdev->mac_rx_errors += u32temp;
+       nesvnic->nesdev->mac_rx_jabber_frames += u32temp;
+
+       u32temp = nes_read_indexed(nesdev,
+                       NES_IDX_MAC_RX_SYMBOL_ERR_FRAMES + (nesvnic->nesdev->mac_index*0x200));
+       nesvnic->netstats.rx_dropped += u32temp;
+       nesvnic->nesdev->mac_rx_errors += u32temp;
+       nesvnic->nesdev->mac_rx_symbol_err_frames += u32temp;
+
+       u32temp = nes_read_indexed(nesdev,
+                       NES_IDX_MAC_RX_LENGTH_ERR_FRAMES + (nesvnic->nesdev->mac_index*0x200));
+       nesvnic->netstats.rx_length_errors += u32temp;
+       nesvnic->nesdev->mac_rx_errors += u32temp;
+
+       u32temp = nes_read_indexed(nesdev,
+                       NES_IDX_MAC_RX_CRC_ERR_FRAMES + (nesvnic->nesdev->mac_index*0x200));
+       nesvnic->nesdev->mac_rx_errors += u32temp;
+       nesvnic->nesdev->mac_rx_crc_errors += u32temp;
+       nesvnic->netstats.rx_crc_errors += u32temp;
+
+       u32temp = nes_read_indexed(nesdev,
+                       NES_IDX_MAC_TX_ERRORS + (nesvnic->nesdev->mac_index*0x200));
+       nesvnic->nesdev->mac_tx_errors += u32temp;
+       nesvnic->netstats.tx_errors += u32temp;
+
+       return &nesvnic->netstats;
+}
+
+
+/**
+ * nes_netdev_tx_timeout
+ */
+static void nes_netdev_tx_timeout(struct net_device *netdev)
+{
+       struct nes_vnic *nesvnic = netdev_priv(netdev);
+
+       if (netif_msg_timer(nesvnic))
+               nes_debug(NES_DBG_NIC_TX, "%s: tx timeout\n", netdev->name);
+}
+
+
+/**
+ * nes_netdev_set_mac_address
+ */
+static int nes_netdev_set_mac_address(struct net_device *netdev, void *p)
+{
+       struct nes_vnic *nesvnic = netdev_priv(netdev);
+       struct nes_device *nesdev = nesvnic->nesdev;
+       struct sockaddr *mac_addr = p;
+       int i;
+       u32 macaddr_low;
+       u16 macaddr_high;
+
+       if (!is_valid_ether_addr(mac_addr->sa_data))
+               return -EADDRNOTAVAIL;
+
+       memcpy(netdev->dev_addr, mac_addr->sa_data, netdev->addr_len);
+       printk(PFX "%s: Address length = %d, Address = %02X%02X%02X%02X%02X%02X..\n",
+                  __FUNCTION__, netdev->addr_len,
+                  mac_addr->sa_data[0], mac_addr->sa_data[1],
+                  mac_addr->sa_data[2], mac_addr->sa_data[3],
+                  mac_addr->sa_data[4], mac_addr->sa_data[5]);
+       macaddr_high = ((u16)netdev->dev_addr[0]) << 8;
+       macaddr_high += (u16)netdev->dev_addr[1];
+       macaddr_low = ((u32)netdev->dev_addr[2]) << 24;
+       macaddr_low += ((u32)netdev->dev_addr[3]) << 16;
+       macaddr_low += ((u32)netdev->dev_addr[4]) << 8;
+       macaddr_low += (u32)netdev->dev_addr[5];
+
+       for (i = 0; i < NES_MAX_PORT_COUNT; i++) {
+               if (nesvnic->qp_nic_index[i] == 0xf) {
+                       break;
+               }
+               nes_write_indexed(nesdev,
+                               NES_IDX_PERFECT_FILTER_LOW + (nesvnic->qp_nic_index[i] * 8),
+                               macaddr_low);
+               nes_write_indexed(nesdev,
+                               NES_IDX_PERFECT_FILTER_HIGH + (nesvnic->qp_nic_index[i] * 8),
+                               (u32)macaddr_high | NES_MAC_ADDR_VALID |
+                               ((((u32)nesvnic->nic_index) << 16)));
+       }
+       return 0;
+}
+
+
+/**
+ * nes_netdev_set_multicast_list
+ */
+void nes_netdev_set_multicast_list(struct net_device *netdev)
+{
+       struct nes_vnic *nesvnic = netdev_priv(netdev);
+       struct nes_device *nesdev = nesvnic->nesdev;
+       struct dev_mc_list *multicast_addr;
+       u32 nic_active_bit;
+       u32 nic_active;
+       u32 perfect_filter_register_address;
+       u32 macaddr_low;
+       u16 macaddr_high;
+       u8 mc_all_on = 0;
+       u8 mc_index;
+       int mc_nic_index = -1;
+
+       nic_active_bit = 1 << nesvnic->nic_index;
+
+       if (netdev->flags & IFF_PROMISC) {
+               nic_active = nes_read_indexed(nesdev, NES_IDX_NIC_MULTICAST_ALL);
+               nic_active |= nic_active_bit;
+               nes_write_indexed(nesdev, NES_IDX_NIC_MULTICAST_ALL, nic_active);
+               nic_active = nes_read_indexed(nesdev, NES_IDX_NIC_UNICAST_ALL);
+               nic_active |= nic_active_bit;
+               nes_write_indexed(nesdev, NES_IDX_NIC_UNICAST_ALL, nic_active);
+               mc_all_on = 1;
+       } else if ((netdev->flags & IFF_ALLMULTI) || (netdev->mc_count > NES_MULTICAST_PF_MAX) ||
+                          (nesvnic->nic_index > 3)) {
+               nic_active = nes_read_indexed(nesdev, NES_IDX_NIC_MULTICAST_ALL);
+               nic_active |= nic_active_bit;
+               nes_write_indexed(nesdev, NES_IDX_NIC_MULTICAST_ALL, nic_active);
+               nic_active = nes_read_indexed(nesdev, NES_IDX_NIC_UNICAST_ALL);
+               nic_active &= ~nic_active_bit;
+               nes_write_indexed(nesdev, NES_IDX_NIC_UNICAST_ALL, nic_active);
+               mc_all_on = 1;
+       } else {
+               nic_active = nes_read_indexed(nesdev, NES_IDX_NIC_MULTICAST_ALL);
+               nic_active &= ~nic_active_bit;
+               nes_write_indexed(nesdev, NES_IDX_NIC_MULTICAST_ALL, nic_active);
+               nic_active = nes_read_indexed(nesdev, NES_IDX_NIC_UNICAST_ALL);
+               nic_active &= ~nic_active_bit;
+               nes_write_indexed(nesdev, NES_IDX_NIC_UNICAST_ALL, nic_active);
+       }
+
+       nes_debug(NES_DBG_NIC_RX, "Number of MC entries = %d, Promiscous = %d, All Multicast = %d.\n",
+                         netdev->mc_count, (netdev->flags & IFF_PROMISC)?1:0,
+                         (netdev->flags & IFF_ALLMULTI)?1:0);
+       if (!mc_all_on) {
+               multicast_addr = netdev->mc_list;
+               perfect_filter_register_address = NES_IDX_PERFECT_FILTER_LOW + 0x80;
+               perfect_filter_register_address += nesvnic->nic_index*0x40;
+               for (mc_index=0; mc_index < NES_MULTICAST_PF_MAX; mc_index++) {
+                       while (multicast_addr && nesvnic->mcrq_mcast_filter && ((mc_nic_index = nesvnic->mcrq_mcast_filter(nesvnic, multicast_addr->dmi_addr)) == 0))
+                               multicast_addr = multicast_addr->next;
+
+                       if (mc_nic_index < 0)
+                               mc_nic_index = nesvnic->nic_index;
+                       if (multicast_addr) {
+                               nes_debug(NES_DBG_NIC_RX, "Assigning MC Address = %02X%02X%02X%02X%02X%02X to register 0x%04X nic_idx=%d\n",
+                                                 multicast_addr->dmi_addr[0], multicast_addr->dmi_addr[1],
+                                                 multicast_addr->dmi_addr[2], multicast_addr->dmi_addr[3],
+                                                 multicast_addr->dmi_addr[4], multicast_addr->dmi_addr[5],
+                                                 perfect_filter_register_address+(mc_index * 8), mc_nic_index);
+                               macaddr_high = ((u16)multicast_addr->dmi_addr[0]) << 8;
+                               macaddr_high += (u16)multicast_addr->dmi_addr[1];
+                               macaddr_low = ((u32)multicast_addr->dmi_addr[2]) << 24;
+                               macaddr_low += ((u32)multicast_addr->dmi_addr[3]) << 16;
+                               macaddr_low += ((u32)multicast_addr->dmi_addr[4]) << 8;
+                               macaddr_low += (u32)multicast_addr->dmi_addr[5];
+                               nes_write_indexed(nesdev,
+                                               perfect_filter_register_address+(mc_index * 8),
+                                               macaddr_low);
+                               nes_write_indexed(nesdev,
+                                               perfect_filter_register_address+4+(mc_index * 8),
+                                               (u32)macaddr_high | NES_MAC_ADDR_VALID |
+                                               ((((u32)(1<<mc_nic_index)) << 16)));
+                               multicast_addr = multicast_addr->next;
+                       } else {
+                               nes_debug(NES_DBG_NIC_RX, "Clearing MC Address at register 0x%04X\n",
+                                                 perfect_filter_register_address+(mc_index * 8));
+                               nes_write_indexed(nesdev,
+                                               perfect_filter_register_address+4+(mc_index * 8),
+                                               0);
+                       }
+               }
+       }
+}
+
+
+/**
+ * nes_netdev_change_mtu
+ */
+static int nes_netdev_change_mtu(struct        net_device *netdev,     int     new_mtu)
+{
+       struct nes_vnic *nesvnic = netdev_priv(netdev);
+       struct nes_device *nesdev =     nesvnic->nesdev;
+       int     ret     = 0;
+       u8 jumbomode=0;
+
+       if ((new_mtu < ETH_ZLEN) ||     (new_mtu > max_mtu))
+               return -EINVAL;
+
+       netdev->mtu     = new_mtu;
+       nesvnic->max_frame_size = new_mtu+ETH_HLEN;
+
+       if (netdev->mtu > 1500) {
+               jumbomode=1;
+       }
+       nes_nic_init_timer_defaults(nesdev,     jumbomode);
+
+       if (netif_running(netdev)) {
+               nes_netdev_stop(netdev);
+               nes_netdev_open(netdev);
+       }
+
+       return ret;
+}
+
+
+/**
+ * nes_netdev_exit - destroy network device
+ */
+void nes_netdev_exit(struct nes_vnic *nesvnic)
+{
+       struct net_device *netdev = nesvnic->netdev;
+       struct nes_ib_device *nesibdev = nesvnic->nesibdev;
+
+       nes_debug(NES_DBG_SHUTDOWN, "\n");
+
+       // destroy the ibdevice if RDMA enabled
+       if ((nesvnic->rdma_enabled)&&(nesvnic->of_device_registered)) {
+               nes_destroy_ofa_device( nesibdev );
+               nesvnic->of_device_registered = 0;
+               nesvnic->nesibdev = NULL;
+       }
+       unregister_netdev(netdev);
+       nes_debug(NES_DBG_SHUTDOWN, "\n");
+}
+
+
+#define NES_ETHTOOL_STAT_COUNT 55
+static const char nes_ethtool_stringset[NES_ETHTOOL_STAT_COUNT][ETH_GSTRING_LEN] = {
+       "Link Change Interrupts",
+       "Linearized SKBs",
+       "T/GSO Requests",
+       "Pause Frames Sent",
+       "Pause Frames Received",
+       "Internal Routing Errors",
+       "SQ SW Dropped SKBs",
+       "SQ Locked",
+       "SQ Full",
+       "Segmented TSO Requests",
+       "Rx Symbol Errors",
+       "Rx Jabber Errors",
+       "Rx Oversized Frames",
+       "Rx Short Frames",
+       "Endnode Rx Discards",
+       "Endnode Rx Octets",
+       "Endnode Rx Frames",
+       "Endnode Tx Octets",
+       "Endnode Tx Frames",
+       "mh detected",
+       "mh pauses",
+       "Retransmission Count",
+       "CM Connects",
+       "CM Accepts",
+       "Disconnects",
+       "Connected Events",
+       "Connect Requests",
+       "CM Rejects",
+       "ModifyQP Timeouts",
+       "CreateQPs",
+       "SW DestroyQPs",
+       "DestroyQPs",
+       "CM Closes",
+       "CM Packets Sent",
+       "CM Packets Bounced",
+       "CM Packets Created",
+       "CM Packets Rcvd",
+       "CM Packets Dropped",
+       "CM Packets Retrans",
+       "CM Listens Created",
+       "CM Listens Destroyed",
+       "CM Backlog Drops",
+       "CM Loopbacks",
+       "CM Nodes Created",
+       "CM Nodes Destroyed",
+       "CM Accel Drops",
+       "CM Resets Received",
+       "Timer Inits",
+       "CQ Depth 1",
+       "CQ Depth 4",
+       "CQ Depth 16",
+       "CQ Depth 24",
+       "CQ Depth 32",
+       "CQ Depth 128",
+       "CQ Depth 256",
+};
+
+
+/**
+ * nes_netdev_get_rx_csum
+ */
+static u32 nes_netdev_get_rx_csum (struct net_device *netdev)
+{
+       struct nes_vnic *nesvnic = netdev_priv(netdev);
+
+       if (nesvnic->rx_checksum_disabled)
+               return 0;
+       else
+               return 1;
+}
+
+
+/**
+ * nes_netdev_set_rc_csum
+ */
+static int nes_netdev_set_rx_csum(struct net_device *netdev, u32 enable)
+{
+       struct nes_vnic *nesvnic = netdev_priv(netdev);
+
+       if (enable)
+               nesvnic->rx_checksum_disabled = 0;
+       else
+               nesvnic->rx_checksum_disabled = 1;
+       return 0;
+}
+
+
+/**
+ * nes_netdev_get_stats_count
+ */
+static int nes_netdev_get_stats_count(struct net_device *netdev)
+{
+       return NES_ETHTOOL_STAT_COUNT;
+}
+
+
+/**
+ * nes_netdev_get_strings
+ */
+static void nes_netdev_get_strings(struct net_device *netdev, u32 stringset,
+               u8 *ethtool_strings)
+{
+       if (stringset == ETH_SS_STATS)
+               memcpy(ethtool_strings,
+                               &nes_ethtool_stringset,
+                               sizeof(nes_ethtool_stringset));
+}
+
+
+/**
+ * nes_netdev_get_ethtool_stats
+ */
+static void nes_netdev_get_ethtool_stats(struct net_device *netdev,
+               struct ethtool_stats *target_ethtool_stats, u64 *target_stat_values)
+{
+       u64 u64temp;
+       struct nes_vnic *nesvnic = netdev_priv(netdev);
+       struct nes_device *nesdev = nesvnic->nesdev;
+       u32 nic_count;
+       u32 u32temp;
+
+       target_ethtool_stats->n_stats = NES_ETHTOOL_STAT_COUNT;
+       target_stat_values[0] = nesvnic->nesdev->link_status_interrupts;
+       target_stat_values[1] = nesvnic->linearized_skbs;
+       target_stat_values[2] = nesvnic->tso_requests;
+
+       u32temp = nes_read_indexed(nesdev,
+                       NES_IDX_MAC_TX_PAUSE_FRAMES + (nesvnic->nesdev->mac_index*0x200));
+       nesvnic->nesdev->mac_pause_frames_sent += u32temp;
+       target_stat_values[3] = nesvnic->nesdev->mac_pause_frames_sent;
+
+       u32temp = nes_read_indexed(nesdev,
+                       NES_IDX_MAC_RX_PAUSE_FRAMES + (nesvnic->nesdev->mac_index*0x200));
+       nesvnic->nesdev->mac_pause_frames_received += u32temp;
+
+       u32temp = nes_read_indexed(nesdev,
+                       NES_IDX_PORT_RX_DISCARDS + (nesvnic->nesdev->mac_index*0x40));
+       nesvnic->nesdev->port_rx_discards += u32temp;
+       nesvnic->netstats.rx_dropped += u32temp;
+
+       u32temp = nes_read_indexed(nesdev,
+                       NES_IDX_PORT_TX_DISCARDS + (nesvnic->nesdev->mac_index*0x40));
+       nesvnic->nesdev->port_tx_discards += u32temp;
+       nesvnic->netstats.tx_dropped += u32temp;
+
+       for (nic_count = 0; nic_count < NES_MAX_PORT_COUNT; nic_count++) {
+               if (nesvnic->qp_nic_index[nic_count] == 0xf)
+                       break;
+
+               u32temp = nes_read_indexed(nesdev,
+                               NES_IDX_ENDNODE0_NSTAT_RX_DISCARD +
+                               (nesvnic->qp_nic_index[nic_count]*0x200));
+               nesvnic->netstats.rx_dropped += u32temp;
+               nesvnic->endnode_nstat_rx_discard += u32temp;
+
+               u64temp = (u64)nes_read_indexed(nesdev,
+                               NES_IDX_ENDNODE0_NSTAT_RX_OCTETS_LO +
+                               (nesvnic->qp_nic_index[nic_count]*0x200));
+               u64temp += ((u64)nes_read_indexed(nesdev,
+                               NES_IDX_ENDNODE0_NSTAT_RX_OCTETS_HI +
+                               (nesvnic->qp_nic_index[nic_count]*0x200))) << 32;
+
+               nesvnic->endnode_nstat_rx_octets += u64temp;
+               nesvnic->netstats.rx_bytes += u64temp;
+
+               u64temp = (u64)nes_read_indexed(nesdev,
+                               NES_IDX_ENDNODE0_NSTAT_RX_FRAMES_LO +
+                               (nesvnic->qp_nic_index[nic_count]*0x200));
+               u64temp += ((u64)nes_read_indexed(nesdev,
+                               NES_IDX_ENDNODE0_NSTAT_RX_FRAMES_HI +
+                               (nesvnic->qp_nic_index[nic_count]*0x200))) << 32;
+
+               nesvnic->endnode_nstat_rx_frames += u64temp;
+               nesvnic->netstats.rx_packets += u64temp;
+
+               u64temp = (u64)nes_read_indexed(nesdev,
+                               NES_IDX_ENDNODE0_NSTAT_TX_OCTETS_LO +
+                               (nesvnic->qp_nic_index[nic_count]*0x200));
+               u64temp += ((u64)nes_read_indexed(nesdev,
+                               NES_IDX_ENDNODE0_NSTAT_TX_OCTETS_HI +
+                               (nesvnic->qp_nic_index[nic_count]*0x200))) << 32;
+
+               nesvnic->endnode_nstat_tx_octets += u64temp;
+               nesvnic->netstats.tx_bytes += u64temp;
+
+               u64temp = (u64)nes_read_indexed(nesdev,
+                               NES_IDX_ENDNODE0_NSTAT_TX_FRAMES_LO +
+                               (nesvnic->qp_nic_index[nic_count]*0x200));
+               u64temp += ((u64)nes_read_indexed(nesdev,
+                               NES_IDX_ENDNODE0_NSTAT_TX_FRAMES_HI +
+                               (nesvnic->qp_nic_index[nic_count]*0x200))) << 32;
+
+               nesvnic->endnode_nstat_tx_frames += u64temp;
+               nesvnic->netstats.tx_packets += u64temp;
+
+               u32temp = nes_read_indexed(nesdev,
+                               NES_IDX_IPV4_TCP_REXMITS + (nesvnic->qp_nic_index[nic_count]*0x200));
+               nesvnic->endnode_ipv4_tcp_retransmits += u32temp;
+       }
+
+       target_stat_values[4] = nesvnic->nesdev->mac_pause_frames_received;
+       target_stat_values[5] = nesdev->nesadapter->nic_rx_eth_route_err;
+       target_stat_values[6] = nesvnic->tx_sw_dropped;
+       target_stat_values[7] = nesvnic->sq_locked;
+       target_stat_values[8] = nesvnic->sq_full;
+       target_stat_values[9] = nesvnic->segmented_tso_requests;
+       target_stat_values[10] = nesvnic->nesdev->mac_rx_symbol_err_frames;
+       target_stat_values[11] = nesvnic->nesdev->mac_rx_jabber_frames;
+       target_stat_values[12] = nesvnic->nesdev->mac_rx_oversized_frames;
+       target_stat_values[13] = nesvnic->nesdev->mac_rx_short_frames;
+       target_stat_values[14] = nesvnic->endnode_nstat_rx_discard;
+       target_stat_values[15] = nesvnic->endnode_nstat_rx_octets;
+       target_stat_values[16] = nesvnic->endnode_nstat_rx_frames;
+       target_stat_values[17] = nesvnic->endnode_nstat_tx_octets;
+       target_stat_values[18] = nesvnic->endnode_nstat_tx_frames;
+       target_stat_values[19] = mh_detected;
+       target_stat_values[20] = mh_pauses_sent;
+       target_stat_values[21] = nesvnic->endnode_ipv4_tcp_retransmits;
+       target_stat_values[22] = atomic_read(&cm_connects);
+       target_stat_values[23] = atomic_read(&cm_accepts);
+       target_stat_values[24] = atomic_read(&cm_disconnects);
+       target_stat_values[25] = atomic_read(&cm_connecteds);
+       target_stat_values[26] = atomic_read(&cm_connect_reqs);
+       target_stat_values[27] = atomic_read(&cm_rejects);
+       target_stat_values[28] = atomic_read(&mod_qp_timouts);
+       target_stat_values[29] = atomic_read(&qps_created);
+       target_stat_values[30] = atomic_read(&sw_qps_destroyed);
+       target_stat_values[31] = atomic_read(&qps_destroyed);
+       target_stat_values[32] = atomic_read(&cm_closes);
+       target_stat_values[33] = cm_packets_sent;
+       target_stat_values[34] = cm_packets_bounced;
+       target_stat_values[35] = cm_packets_created;
+       target_stat_values[36] = cm_packets_received;
+       target_stat_values[37] = cm_packets_dropped;
+       target_stat_values[38] = cm_packets_retrans;
+       target_stat_values[39] = cm_listens_created;
+       target_stat_values[40] = cm_listens_destroyed;
+       target_stat_values[41] = cm_backlog_drops;
+       target_stat_values[42] = atomic_read(&cm_loopbacks);
+       target_stat_values[43] = atomic_read(&cm_nodes_created);
+       target_stat_values[44] = atomic_read(&cm_nodes_destroyed);
+       target_stat_values[45] = atomic_read(&cm_accel_dropped_pkts);
+       target_stat_values[46] = atomic_read(&cm_resets_recvd);
+       target_stat_values[47] = int_mod_timer_init;
+       target_stat_values[48] = int_mod_cq_depth_1;
+       target_stat_values[49] = int_mod_cq_depth_4;
+       target_stat_values[50] = int_mod_cq_depth_16;
+       target_stat_values[51] = int_mod_cq_depth_24;
+       target_stat_values[52] = int_mod_cq_depth_32;
+       target_stat_values[53] = int_mod_cq_depth_128;
+       target_stat_values[54] = int_mod_cq_depth_256;
+
+}
+
+
+/**
+ * nes_netdev_get_drvinfo
+ */
+static void nes_netdev_get_drvinfo(struct net_device *netdev,
+               struct ethtool_drvinfo *drvinfo)
+{
+       struct nes_vnic *nesvnic = netdev_priv(netdev);
+
+       strcpy(drvinfo->driver, DRV_NAME);
+       strcpy(drvinfo->bus_info, pci_name(nesvnic->nesdev->pcidev));
+       strcpy(drvinfo->fw_version, "TBD");
+       strcpy(drvinfo->version, DRV_VERSION);
+       drvinfo->n_stats = nes_netdev_get_stats_count(netdev);
+       drvinfo->testinfo_len = 0;
+       drvinfo->eedump_len = 0;
+       drvinfo->regdump_len = 0;
+}
+
+
+/**
+ * nes_netdev_set_coalesce
+ */
+static int nes_netdev_set_coalesce(struct net_device *netdev,
+               struct ethtool_coalesce *et_coalesce)
+{
+       struct nes_vnic *nesvnic = netdev_priv(netdev);
+       struct nes_device *nesdev =     nesvnic->nesdev;
+       struct nes_adapter *nesadapter = nesdev->nesadapter;
+       struct nes_hw_tune_timer *shared_timer = &nesadapter->tune_timer;
+       unsigned long flags;
+
+       spin_lock_irqsave(&nesadapter->periodic_timer_lock,     flags);
+       if (et_coalesce->rx_max_coalesced_frames_low) {
+               shared_timer->threshold_low      = et_coalesce->rx_max_coalesced_frames_low;
+       }
+       if (et_coalesce->rx_max_coalesced_frames_irq) {
+               shared_timer->threshold_target = et_coalesce->rx_max_coalesced_frames_irq;
+       }
+       if (et_coalesce->rx_max_coalesced_frames_high) {
+               shared_timer->threshold_high = et_coalesce->rx_max_coalesced_frames_high;
+       }
+       if (et_coalesce->rx_coalesce_usecs_low) {
+               shared_timer->timer_in_use_min = et_coalesce->rx_coalesce_usecs_low;
+       }
+       if (et_coalesce->rx_coalesce_usecs_high) {
+               shared_timer->timer_in_use_max = et_coalesce->rx_coalesce_usecs_high;
+       }
+       spin_unlock_irqrestore(&nesadapter->periodic_timer_lock, flags);
+
+       /* using this to drive total interrupt moderation */
+       nesadapter->et_rx_coalesce_usecs_irq = et_coalesce->rx_coalesce_usecs_irq;
+       if (et_coalesce->use_adaptive_rx_coalesce) {
+               nesadapter->et_use_adaptive_rx_coalesce = 1;
+               nesadapter->timer_int_limit     = NES_TIMER_INT_LIMIT_DYNAMIC;
+               nesadapter->et_rx_coalesce_usecs_irq = 0;
+               if (et_coalesce->pkt_rate_low) {
+                       nesadapter->et_pkt_rate_low     = et_coalesce->pkt_rate_low;
+               }
+       } else {
+               nesadapter->et_use_adaptive_rx_coalesce = 0;
+               nesadapter->timer_int_limit     = NES_TIMER_INT_LIMIT;
+               if (nesadapter->et_rx_coalesce_usecs_irq) {
+                       nes_write32(nesdev->regs+NES_PERIODIC_CONTROL,
+                                       0x80000000 | ((u32)(nesadapter->et_rx_coalesce_usecs_irq*8)));
+               }
+       }
+       return 0;
+}
+
+
+/**
+ * nes_netdev_get_coalesce
+ */
+static int nes_netdev_get_coalesce(struct net_device *netdev,
+               struct ethtool_coalesce *et_coalesce)
+{
+       struct nes_vnic *nesvnic = netdev_priv(netdev);
+       struct nes_device *nesdev =     nesvnic->nesdev;
+       struct nes_adapter *nesadapter = nesdev->nesadapter;
+       struct ethtool_coalesce temp_et_coalesce;
+       struct nes_hw_tune_timer *shared_timer = &nesadapter->tune_timer;
+       unsigned long flags;
+
+       memset(&temp_et_coalesce, 0, sizeof(temp_et_coalesce));
+       temp_et_coalesce.rx_coalesce_usecs_irq = nesadapter->et_rx_coalesce_usecs_irq;
+       temp_et_coalesce.use_adaptive_rx_coalesce =     nesadapter->et_use_adaptive_rx_coalesce;
+       temp_et_coalesce.rate_sample_interval = nesadapter->et_rate_sample_interval;
+       temp_et_coalesce.pkt_rate_low = nesadapter->et_pkt_rate_low;
+       spin_lock_irqsave(&nesadapter->periodic_timer_lock,     flags);
+       temp_et_coalesce.rx_max_coalesced_frames_low =  shared_timer->threshold_low;
+       temp_et_coalesce.rx_max_coalesced_frames_irq =  shared_timer->threshold_target;
+       temp_et_coalesce.rx_max_coalesced_frames_high = shared_timer->threshold_high;
+       temp_et_coalesce.rx_coalesce_usecs_low = shared_timer->timer_in_use_min;
+       temp_et_coalesce.rx_coalesce_usecs_high = shared_timer->timer_in_use_max;
+       if (nesadapter->et_use_adaptive_rx_coalesce) {
+               temp_et_coalesce.rx_coalesce_usecs_irq = shared_timer->timer_in_use;
+       }
+       spin_unlock_irqrestore(&nesadapter->periodic_timer_lock, flags);
+       memcpy(et_coalesce,     &temp_et_coalesce, sizeof(*et_coalesce));
+       return 0;
+}
+
+
+/**
+ * nes_netdev_get_pauseparam
+ */
+static void nes_netdev_get_pauseparam(struct net_device *netdev,
+               struct ethtool_pauseparam *et_pauseparam)
+{
+       struct nes_vnic *nesvnic = netdev_priv(netdev);
+
+       et_pauseparam->autoneg = 0;
+       et_pauseparam->rx_pause = (nesvnic->nesdev->disable_rx_flow_control == 0) ? 1:0;
+       et_pauseparam->tx_pause = (nesvnic->nesdev->disable_tx_flow_control == 0) ? 1:0;
+}
+
+
+/**
+ * nes_netdev_set_pauseparam
+ */
+static int nes_netdev_set_pauseparam(struct net_device *netdev,
+               struct ethtool_pauseparam *et_pauseparam)
+{
+       struct nes_vnic *nesvnic = netdev_priv(netdev);
+       struct nes_device *nesdev = nesvnic->nesdev;
+       u32 u32temp;
+
+       if (et_pauseparam->autoneg) {
+               /* TODO: should return unsupported */
+               return 0;
+       }
+       if ((et_pauseparam->tx_pause == 1) && (nesdev->disable_tx_flow_control == 1)) {
+               u32temp = nes_read_indexed(nesdev,
+                               NES_IDX_MAC_TX_CONFIG + (nesdev->mac_index*0x200));
+               u32temp |= NES_IDX_MAC_TX_CONFIG_ENABLE_PAUSE;
+               nes_write_indexed(nesdev,
+                               NES_IDX_MAC_TX_CONFIG_ENABLE_PAUSE + (nesdev->mac_index*0x200), u32temp);
+               nesdev->disable_tx_flow_control = 0;
+       } else if ((et_pauseparam->tx_pause == 0) && (nesdev->disable_tx_flow_control == 0)) {
+               u32temp = nes_read_indexed(nesdev,
+                               NES_IDX_MAC_TX_CONFIG + (nesdev->mac_index*0x200));
+               u32temp &= ~NES_IDX_MAC_TX_CONFIG_ENABLE_PAUSE;
+               nes_write_indexed(nesdev,
+                               NES_IDX_MAC_TX_CONFIG_ENABLE_PAUSE + (nesdev->mac_index*0x200), u32temp);
+               nesdev->disable_tx_flow_control = 1;
+       }
+       if ((et_pauseparam->rx_pause == 1) && (nesdev->disable_rx_flow_control == 1)) {
+               u32temp = nes_read_indexed(nesdev,
+                               NES_IDX_MPP_DEBUG + (nesdev->mac_index*0x40));
+               u32temp &= ~NES_IDX_MPP_DEBUG_PORT_DISABLE_PAUSE;
+               nes_write_indexed(nesdev,
+                               NES_IDX_MPP_DEBUG + (nesdev->mac_index*0x40), u32temp);
+               nesdev->disable_rx_flow_control = 0;
+       } else if ((et_pauseparam->rx_pause == 0) && (nesdev->disable_rx_flow_control == 0)) {
+               u32temp = nes_read_indexed(nesdev,
+                               NES_IDX_MPP_DEBUG + (nesdev->mac_index*0x40));
+               u32temp |= NES_IDX_MPP_DEBUG_PORT_DISABLE_PAUSE;
+               nes_write_indexed(nesdev,
+                               NES_IDX_MPP_DEBUG + (nesdev->mac_index*0x40), u32temp);
+               nesdev->disable_rx_flow_control = 1;
+       }
+
+       return 0;
+}
+
+
+/**
+ * nes_netdev_get_settings
+ */
+static int nes_netdev_get_settings(struct net_device *netdev, struct ethtool_cmd *et_cmd)
+{
+       struct nes_vnic *nesvnic = netdev_priv(netdev);
+       struct nes_device *nesdev = nesvnic->nesdev;
+       struct nes_adapter *nesadapter = nesdev->nesadapter;
+       u16 phy_data;
+
+       et_cmd->duplex = DUPLEX_FULL;
+       et_cmd->port = PORT_MII;
+       if (nesadapter->OneG_Mode) {
+               et_cmd->supported = SUPPORTED_1000baseT_Full|SUPPORTED_Autoneg;
+               et_cmd->advertising = ADVERTISED_1000baseT_Full|ADVERTISED_Autoneg;
+               et_cmd->speed = SPEED_1000;
+               nes_read_1G_phy_reg(nesdev, 0, nesadapter->phy_index[nesdev->mac_index],
+                               &phy_data);
+               if (phy_data&0x1000) {
+                       et_cmd->autoneg = AUTONEG_ENABLE;
+               } else {
+                       et_cmd->autoneg = AUTONEG_DISABLE;
+               }
+               et_cmd->transceiver = XCVR_EXTERNAL;
+               et_cmd->phy_address = nesadapter->phy_index[nesdev->mac_index];
+       } else {
+               if (nesadapter->phy_type[nesvnic->logical_port] == NES_PHY_TYPE_IRIS) {
+                       et_cmd->transceiver = XCVR_EXTERNAL;
+                       et_cmd->port = PORT_FIBRE;
+                       et_cmd->supported = SUPPORTED_FIBRE;
+                       et_cmd->advertising = ADVERTISED_FIBRE;
+                       et_cmd->phy_address = nesadapter->phy_index[nesdev->mac_index];
+               } else {
+                       et_cmd->transceiver = XCVR_INTERNAL;
+                       et_cmd->supported = SUPPORTED_10000baseT_Full;
+                       et_cmd->advertising = ADVERTISED_10000baseT_Full;
+                       et_cmd->phy_address = nesdev->mac_index;
+               }
+               et_cmd->speed = SPEED_10000;
+               et_cmd->autoneg = AUTONEG_DISABLE;
+       }
+       et_cmd->maxtxpkt = 511;
+       et_cmd->maxrxpkt = 511;
+       return 0;
+}
+
+
+/**
+ * nes_netdev_set_settings
+ */
+static int nes_netdev_set_settings(struct net_device *netdev, struct ethtool_cmd *et_cmd)
+{
+       struct nes_vnic *nesvnic = netdev_priv(netdev);
+       struct nes_device *nesdev = nesvnic->nesdev;
+       struct nes_adapter *nesadapter = nesdev->nesadapter;
+       u16 phy_data;
+
+       if (nesadapter->OneG_Mode) {
+               nes_read_1G_phy_reg(nesdev, 0, nesadapter->phy_index[nesdev->mac_index],
+                               &phy_data);
+               if (et_cmd->autoneg) {
+                       /* Turn on Full duplex, Autoneg, and restart autonegotiation */
+                       phy_data |= 0x1300;
+               } else {
+                       // Turn off autoneg
+                       phy_data &= ~0x1000;
+               }
+               nes_write_1G_phy_reg(nesdev, 0, nesadapter->phy_index[nesdev->mac_index],
+                               phy_data);
+       }
+
+       return 0;
+}
+
+
+static struct ethtool_ops nes_ethtool_ops = {
+       .get_link = ethtool_op_get_link,
+       .get_settings = nes_netdev_get_settings,
+       .set_settings = nes_netdev_set_settings,
+       .get_tx_csum = ethtool_op_get_tx_csum,
+       .get_rx_csum = nes_netdev_get_rx_csum,
+       .get_sg = ethtool_op_get_sg,
+       .get_strings = nes_netdev_get_strings,
+       .get_stats_count = nes_netdev_get_stats_count,
+       .get_ethtool_stats = nes_netdev_get_ethtool_stats,
+       .get_drvinfo = nes_netdev_get_drvinfo,
+       .get_coalesce = nes_netdev_get_coalesce,
+       .set_coalesce = nes_netdev_set_coalesce,
+       .get_pauseparam = nes_netdev_get_pauseparam,
+       .set_pauseparam = nes_netdev_set_pauseparam,
+       .set_tx_csum = ethtool_op_set_tx_csum,
+       .set_rx_csum = nes_netdev_set_rx_csum,
+       .set_sg = ethtool_op_set_sg,
+       .get_tso = ethtool_op_get_tso,
+       .set_tso = ethtool_op_set_tso,
+};
+
+
+static void nes_netdev_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp)
+{
+       struct nes_vnic *nesvnic = netdev_priv(netdev);
+       struct nes_device *nesdev = nesvnic->nesdev;
+       u32 u32temp;
+
+       nesvnic->vlan_grp = grp;
+
+       /* Enable/Disable VLAN Stripping */
+       u32temp = nes_read_indexed(nesdev, NES_IDX_PCIX_DIAG);
+       if (grp)
+               u32temp &= 0xfdffffff;
+       else
+               u32temp |= 0x02000000;
+
+       nes_write_indexed(nesdev, NES_IDX_PCIX_DIAG, u32temp);
+}
+
+
+/**
+ * nes_netdev_init - initialize network device
+ */
+struct net_device *nes_netdev_init(struct nes_device *nesdev,
+               void __iomem *mmio_addr)
+{
+       u64 u64temp;
+       struct nes_vnic *nesvnic = NULL;
+       struct net_device *netdev;
+       struct nic_qp_map *curr_qp_map;
+       u32 u32temp;
+       u16 phy_data;
+       u16 temp_phy_data;
+
+       netdev = alloc_etherdev(sizeof(struct nes_vnic));
+       if (!netdev) {
+               printk(KERN_ERR PFX "nesvnic etherdev alloc failed");
+               return NULL;
+       }
+
+       nes_debug(NES_DBG_INIT, "netdev = %p, %s\n", netdev, netdev->name);
+
+       SET_NETDEV_DEV(netdev, &nesdev->pcidev->dev);
+
+       nesvnic = netdev_priv(netdev);
+       memset(nesvnic, 0, sizeof(*nesvnic));
+
+       netdev->open = nes_netdev_open;
+       netdev->stop = nes_netdev_stop;
+       netdev->hard_start_xmit = nes_netdev_start_xmit;
+       netdev->get_stats = nes_netdev_get_stats;
+       netdev->tx_timeout = nes_netdev_tx_timeout;
+       netdev->set_mac_address = nes_netdev_set_mac_address;
+       netdev->set_multicast_list = nes_netdev_set_multicast_list;
+       netdev->change_mtu = nes_netdev_change_mtu;
+       netdev->watchdog_timeo = NES_TX_TIMEOUT;
+       netdev->irq = nesdev->pcidev->irq;
+       netdev->mtu = ETH_DATA_LEN;
+       netdev->hard_header_len = ETH_HLEN;
+       netdev->addr_len = ETH_ALEN;
+       netdev->type = ARPHRD_ETHER;
+       netdev->features = NETIF_F_HIGHDMA;
+       netdev->ethtool_ops = &nes_ethtool_ops;
+       netif_napi_add(netdev, &nesvnic->napi, nes_netdev_poll, 128);
+       nes_debug(NES_DBG_INIT, "Enabling VLAN Insert/Delete.\n");
+       netdev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
+       netdev->vlan_rx_register = nes_netdev_vlan_rx_register;
+       netdev->features |= NETIF_F_LLTX;
+
+       /* Fill in the port structure */
+       nesvnic->netdev = netdev;
+       nesvnic->nesdev = nesdev;
+       nesvnic->msg_enable = netif_msg_init(debug, default_msg);
+       nesvnic->netdev_index = nesdev->netdev_count;
+       nesvnic->perfect_filter_index = nesdev->nesadapter->netdev_count;
+       nesvnic->max_frame_size = netdev->mtu+netdev->hard_header_len;
+
+       curr_qp_map = nic_qp_mapping_per_function[PCI_FUNC(nesdev->pcidev->devfn)];
+       nesvnic->nic.qp_id = curr_qp_map[nesdev->netdev_count].qpid;
+       nesvnic->nic_index = curr_qp_map[nesdev->netdev_count].nic_index;
+       nesvnic->logical_port = curr_qp_map[nesdev->netdev_count].logical_port;
+
+       /* Setup the burned in MAC address */
+       u64temp = (u64)nesdev->nesadapter->mac_addr_low;
+       u64temp += ((u64)nesdev->nesadapter->mac_addr_high) << 32;
+       u64temp += nesvnic->nic_index;
+       netdev->dev_addr[0] = (u8)(u64temp>>40);
+       netdev->dev_addr[1] = (u8)(u64temp>>32);
+       netdev->dev_addr[2] = (u8)(u64temp>>24);
+       netdev->dev_addr[3] = (u8)(u64temp>>16);
+       netdev->dev_addr[4] = (u8)(u64temp>>8);
+       netdev->dev_addr[5] = (u8)u64temp;
+       memcpy(netdev->perm_addr, netdev->dev_addr, 6);
+
+       if ((nesvnic->logical_port < 2) || (nesdev->nesadapter->hw_rev != NE020_REV)) {
+               netdev->features |= NETIF_F_TSO | NETIF_F_SG | NETIF_F_IP_CSUM;
+               netdev->features |= NETIF_F_GSO | NETIF_F_TSO | NETIF_F_SG | NETIF_F_IP_CSUM;
+       } else {
+               netdev->features |= NETIF_F_SG | NETIF_F_IP_CSUM;
+       }
+
+       nes_debug(NES_DBG_INIT, "nesvnic = %p, reported features = 0x%lX, QPid = %d,"
+                       " nic_index = %d, logical_port = %d, mac_index = %d.\n",
+                       nesvnic, (unsigned long)netdev->features, nesvnic->nic.qp_id,
+                       nesvnic->nic_index, nesvnic->logical_port,  nesdev->mac_index);
+
+       if (nesvnic->nesdev->nesadapter->port_count == 1) {
+               nesvnic->qp_nic_index[0] = nesvnic->nic_index;
+               nesvnic->qp_nic_index[1] = nesvnic->nic_index + 1;
+               if (nes_drv_opt & NES_DRV_OPT_DUAL_LOGICAL_PORT) {
+                       nesvnic->qp_nic_index[2] = 0xf;
+                       nesvnic->qp_nic_index[3] = 0xf;
+               } else {
+                       nesvnic->qp_nic_index[2] = nesvnic->nic_index + 2;
+                       nesvnic->qp_nic_index[3] = nesvnic->nic_index + 3;
+               }
+       } else {
+               if (nesvnic->nesdev->nesadapter->port_count == 2) {
+                       nesvnic->qp_nic_index[0] = nesvnic->nic_index;
+                       nesvnic->qp_nic_index[1] = nesvnic->nic_index + 2;
+                       nesvnic->qp_nic_index[2] = 0xf;
+                       nesvnic->qp_nic_index[3] = 0xf;
+               } else {
+                       nesvnic->qp_nic_index[0] = nesvnic->nic_index;
+                       nesvnic->qp_nic_index[1] = 0xf;
+                       nesvnic->qp_nic_index[2] = 0xf;
+                       nesvnic->qp_nic_index[3] = 0xf;
+               }
+       }
+       nesvnic->next_qp_nic_index = 0;
+
+       if (nesdev->netdev_count == 0) {
+               nesvnic->rdma_enabled = 1;
+       } else {
+               nesvnic->rdma_enabled = 0;
+       }
+       nesvnic->nic_cq.cq_number = nesvnic->nic.qp_id;
+       spin_lock_init(&nesvnic->tx_lock);
+       nesdev->netdev[nesdev->netdev_count] = netdev;
+
+       nes_debug(NES_DBG_INIT, "Adding nesvnic (%p) to the adapters nesvnic_list for MAC%d.\n",
+                       nesvnic, nesdev->mac_index);
+       list_add_tail(&nesvnic->list, &nesdev->nesadapter->nesvnic_list[nesdev->mac_index]);
+
+       if ((nesdev->netdev_count == 0) &&
+                       (PCI_FUNC(nesdev->pcidev->devfn) == nesdev->mac_index)) {
+               nes_debug(NES_DBG_INIT, "Setting up PHY interrupt mask. Using register index 0x%04X\n",
+                               NES_IDX_PHY_PCS_CONTROL_STATUS0+(0x200*(nesvnic->logical_port&1)));
+               u32temp = nes_read_indexed(nesdev, NES_IDX_PHY_PCS_CONTROL_STATUS0 +
+                               (0x200*(nesvnic->logical_port&1)));
+               u32temp |= 0x00200000;
+               nes_write_indexed(nesdev, NES_IDX_PHY_PCS_CONTROL_STATUS0 +
+                               (0x200*(nesvnic->logical_port&1)), u32temp);
+               u32temp = nes_read_indexed(nesdev, NES_IDX_PHY_PCS_CONTROL_STATUS0 +
+                               (0x200*(nesvnic->logical_port&1)) );
+               if ((u32temp&0x0f1f0000) == 0x0f0f0000) {
+                       if (nesdev->nesadapter->phy_type[nesvnic->logical_port] == NES_PHY_TYPE_IRIS) {
+                               nes_init_phy(nesdev);
+                               nes_read_10G_phy_reg(nesdev, 1,
+                                               nesdev->nesadapter->phy_index[nesvnic->logical_port]);
+                               temp_phy_data = (u16)nes_read_indexed(nesdev,
+                                                                       NES_IDX_MAC_MDIO_CONTROL);
+                               u32temp = 20;
+                               do {
+                                       nes_read_10G_phy_reg(nesdev, 1,
+                                                       nesdev->nesadapter->phy_index[nesvnic->logical_port]);
+                                       phy_data = (u16)nes_read_indexed(nesdev,
+                                                                       NES_IDX_MAC_MDIO_CONTROL);
+                                       if ((phy_data == temp_phy_data) || (!(--u32temp)))
+                                               break;
+                                       temp_phy_data = phy_data;
+                               } while (1);
+                               if (phy_data & 4) {
+                                       nes_debug(NES_DBG_INIT, "The Link is UP!!.\n");
+                                       nesvnic->linkup = 1;
+                               } else {
+                                       nes_debug(NES_DBG_INIT, "The Link is DOWN!!.\n");
+                               }
+                       } else {
+                               nes_debug(NES_DBG_INIT, "The Link is UP!!.\n");
+                               nesvnic->linkup = 1;
+                       }
+               }
+               nes_debug(NES_DBG_INIT, "Setting up MAC interrupt mask.\n");
+               /* clear the MAC interrupt status, assumes direct logical to physical mapping */
+               u32temp = nes_read_indexed(nesdev, NES_IDX_MAC_INT_STATUS+(0x200*nesvnic->logical_port));
+               nes_debug(NES_DBG_INIT, "Phy interrupt status = 0x%X.\n", u32temp);
+               nes_write_indexed(nesdev, NES_IDX_MAC_INT_STATUS+(0x200*nesvnic->logical_port), u32temp);
+
+               if (nesdev->nesadapter->phy_type[nesvnic->logical_port] != NES_PHY_TYPE_IRIS)
+                       nes_init_phy(nesdev);
+
+               nes_write_indexed(nesdev, NES_IDX_MAC_INT_MASK+(0x200*nesvnic->logical_port),
+                               ~(NES_MAC_INT_LINK_STAT_CHG | NES_MAC_INT_XGMII_EXT |
+                               NES_MAC_INT_TX_UNDERFLOW | NES_MAC_INT_TX_ERROR));
+       }
+
+       return netdev;
+}
+
+
+/**
+ * nes_netdev_destroy - destroy network device structure
+ */
+void nes_netdev_destroy(struct net_device *netdev)
+{
+       struct nes_vnic *nesvnic = netdev_priv(netdev);
+
+       /* make sure 'stop' method is called by Linux stack */
+       /* nes_netdev_stop(netdev); */
+
+       list_del(&nesvnic->list);
+
+       if (nesvnic->of_device_registered) {
+               nes_destroy_ofa_device(nesvnic->nesibdev);
+       }
+
+       free_netdev(netdev);
+}
+
+
+/**
+ * nes_nic_cm_xmit -- CM calls this to send out pkts
+ */
+int nes_nic_cm_xmit(struct sk_buff *skb, struct net_device *netdev)
+{
+       int ret;
+
+       skb->dev = netdev;
+       ret = dev_queue_xmit(skb);
+       if (ret) {
+               nes_debug(NES_DBG_CM, "Bad return code from dev_queue_xmit %d\n", ret);
+       }
+
+       return ret;
+}
diff --git a/drivers/infiniband/hw/nes/nes_user.h b/drivers/infiniband/hw/nes/nes_user.h
new file mode 100644 (file)
index 0000000..e64306b
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2006 - 2008 NetEffect.  All rights reserved.
+ * Copyright (c) 2005 Topspin Communications.  All rights reserved.
+ * Copyright (c) 2005 Cisco Systems.  All rights reserved.
+ * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * 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.
+ *
+ */
+
+#ifndef NES_USER_H
+#define NES_USER_H
+
+#include <linux/types.h>
+
+#define NES_ABI_USERSPACE_VER 1
+#define NES_ABI_KERNEL_VER    1
+
+/*
+ * Make sure that all structs defined in this file remain laid out so
+ * that they pack the same way on 32-bit and 64-bit architectures (to
+ * avoid incompatibility between 32-bit userspace and 64-bit kernels).
+ * In particular do not use pointer types -- pass pointers in __u64
+ * instead.
+ */
+
+struct nes_alloc_ucontext_req {
+       __u32 reserved32;
+       __u8  userspace_ver;
+       __u8  reserved8[3];
+};
+
+struct nes_alloc_ucontext_resp {
+       __u32 max_pds; /* maximum pds allowed for this user process */
+       __u32 max_qps; /* maximum qps allowed for this user process */
+       __u32 wq_size; /* size of the WQs (sq+rq) allocated to the mmaped area */
+       __u8  virtwq;  /* flag to indicate if virtual WQ are to be used or not */
+       __u8  kernel_ver;
+       __u8  reserved[2];
+};
+
+struct nes_alloc_pd_resp {
+       __u32 pd_id;
+       __u32 mmap_db_index;
+};
+
+struct nes_create_cq_req {
+       __u64 user_cq_buffer;
+       __u32 mcrqf;
+       __u8 reserved[4];
+};
+
+struct nes_create_qp_req {
+       __u64 user_wqe_buffers;
+};
+
+enum iwnes_memreg_type {
+       IWNES_MEMREG_TYPE_MEM = 0x0000,
+       IWNES_MEMREG_TYPE_QP = 0x0001,
+       IWNES_MEMREG_TYPE_CQ = 0x0002,
+       IWNES_MEMREG_TYPE_MW = 0x0003,
+       IWNES_MEMREG_TYPE_FMR = 0x0004,
+};
+
+struct nes_mem_reg_req {
+       __u32 reg_type; /* indicates if id is memory, QP or CQ */
+       __u32 reserved;
+};
+
+struct nes_create_cq_resp {
+       __u32 cq_id;
+       __u32 cq_size;
+       __u32 mmap_db_index;
+       __u32 reserved;
+};
+
+struct nes_create_qp_resp {
+       __u32 qp_id;
+       __u32 actual_sq_size;
+       __u32 actual_rq_size;
+       __u32 mmap_sq_db_index;
+       __u32 mmap_rq_db_index;
+       __u32 nes_drv_opt;
+};
+
+#endif                         /* NES_USER_H */
diff --git a/drivers/infiniband/hw/nes/nes_utils.c b/drivers/infiniband/hw/nes/nes_utils.c
new file mode 100644 (file)
index 0000000..c4ec6ac
--- /dev/null
@@ -0,0 +1,917 @@
+/*
+ * Copyright (c) 2006 - 2008 NetEffect, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include <linux/if_vlan.h>
+#include <linux/crc32.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/byteorder.h>
+
+#include "nes.h"
+
+
+
+static u16 nes_read16_eeprom(void __iomem *addr, u16 offset);
+
+u32 mh_detected;
+u32 mh_pauses_sent;
+
+/**
+ * nes_read_eeprom_values -
+ */
+int nes_read_eeprom_values(struct nes_device *nesdev, struct nes_adapter *nesadapter)
+{
+       u32 mac_addr_low;
+       u16 mac_addr_high;
+       u16 eeprom_data;
+       u16 eeprom_offset;
+       u16 next_section_address;
+       u16 sw_section_ver;
+       u8  major_ver = 0;
+       u8  minor_ver = 0;
+
+       /* TODO: deal with EEPROM endian issues */
+       if (nesadapter->firmware_eeprom_offset == 0) {
+               /* Read the EEPROM Parameters */
+               eeprom_data = nes_read16_eeprom(nesdev->regs, 0);
+               nes_debug(NES_DBG_HW, "EEPROM Offset 0  = 0x%04X\n", eeprom_data);
+               eeprom_offset = 2 + (((eeprom_data & 0x007f) << 3) <<
+                               ((eeprom_data & 0x0080) >> 7));
+               nes_debug(NES_DBG_HW, "Firmware Offset = 0x%04X\n", eeprom_offset);
+               nesadapter->firmware_eeprom_offset = eeprom_offset;
+               eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset + 4);
+               if (eeprom_data != 0x5746) {
+                       nes_debug(NES_DBG_HW, "Not a valid Firmware Image = 0x%04X\n", eeprom_data);
+                       return -1;
+               }
+
+               eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset + 2);
+               nes_debug(NES_DBG_HW, "EEPROM Offset %u  = 0x%04X\n",
+                               eeprom_offset + 2, eeprom_data);
+               eeprom_offset += ((eeprom_data & 0x00ff) << 3) << ((eeprom_data & 0x0100) >> 8);
+               nes_debug(NES_DBG_HW, "Software Offset = 0x%04X\n", eeprom_offset);
+               nesadapter->software_eeprom_offset = eeprom_offset;
+               eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset + 4);
+               if (eeprom_data != 0x5753) {
+                       printk("Not a valid Software Image = 0x%04X\n", eeprom_data);
+                       return -1;
+               }
+               sw_section_ver = nes_read16_eeprom(nesdev->regs, nesadapter->software_eeprom_offset  + 6);
+               nes_debug(NES_DBG_HW, "Software section version number = 0x%04X\n",
+                               sw_section_ver);
+
+               eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset + 2);
+               nes_debug(NES_DBG_HW, "EEPROM Offset %u (next section)  = 0x%04X\n",
+                               eeprom_offset + 2, eeprom_data);
+               next_section_address = eeprom_offset + (((eeprom_data & 0x00ff) << 3) <<
+                               ((eeprom_data & 0x0100) >> 8));
+               eeprom_data = nes_read16_eeprom(nesdev->regs, next_section_address + 4);
+               if (eeprom_data != 0x414d) {
+                       nes_debug(NES_DBG_HW, "EEPROM Changed offset should be 0x414d but was 0x%04X\n",
+                                       eeprom_data);
+                       goto no_fw_rev;
+               }
+               eeprom_offset = next_section_address;
+
+               eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset + 2);
+               nes_debug(NES_DBG_HW, "EEPROM Offset %u (next section)  = 0x%04X\n",
+                               eeprom_offset + 2, eeprom_data);
+               next_section_address = eeprom_offset + (((eeprom_data & 0x00ff) << 3) <<
+                               ((eeprom_data & 0x0100) >> 8));
+               eeprom_data = nes_read16_eeprom(nesdev->regs, next_section_address + 4);
+               if (eeprom_data != 0x4f52) {
+                       nes_debug(NES_DBG_HW, "EEPROM Changed offset should be 0x4f52 but was 0x%04X\n",
+                                       eeprom_data);
+                       goto no_fw_rev;
+               }
+               eeprom_offset = next_section_address;
+
+               eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset + 2);
+               nes_debug(NES_DBG_HW, "EEPROM Offset %u (next section)  = 0x%04X\n",
+                               eeprom_offset + 2, eeprom_data);
+               next_section_address = eeprom_offset + ((eeprom_data & 0x00ff) << 3);
+               eeprom_data = nes_read16_eeprom(nesdev->regs, next_section_address + 4);
+               if (eeprom_data != 0x5746) {
+                       nes_debug(NES_DBG_HW, "EEPROM Changed offset should be 0x5746 but was 0x%04X\n",
+                                       eeprom_data);
+                       goto no_fw_rev;
+               }
+               eeprom_offset = next_section_address;
+
+               eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset + 2);
+               nes_debug(NES_DBG_HW, "EEPROM Offset %u (next section)  = 0x%04X\n",
+                               eeprom_offset + 2, eeprom_data);
+               next_section_address = eeprom_offset + ((eeprom_data & 0x00ff) << 3);
+               eeprom_data = nes_read16_eeprom(nesdev->regs, next_section_address + 4);
+               if (eeprom_data != 0x5753) {
+                       nes_debug(NES_DBG_HW, "EEPROM Changed offset should be 0x5753 but was 0x%04X\n",
+                                       eeprom_data);
+                       goto no_fw_rev;
+               }
+               eeprom_offset = next_section_address;
+
+               eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset + 2);
+               nes_debug(NES_DBG_HW, "EEPROM Offset %u (next section)  = 0x%04X\n",
+                               eeprom_offset + 2, eeprom_data);
+               next_section_address = eeprom_offset + ((eeprom_data & 0x00ff) << 3);
+               eeprom_data = nes_read16_eeprom(nesdev->regs, next_section_address + 4);
+               if (eeprom_data != 0x414d) {
+                       nes_debug(NES_DBG_HW, "EEPROM Changed offset should be 0x414d but was 0x%04X\n",
+                                       eeprom_data);
+                       goto no_fw_rev;
+               }
+               eeprom_offset = next_section_address;
+
+               eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset + 2);
+               nes_debug(NES_DBG_HW, "EEPROM Offset %u (next section)  = 0x%04X\n",
+                               eeprom_offset + 2, eeprom_data);
+               next_section_address = eeprom_offset + ((eeprom_data & 0x00ff) << 3);
+               eeprom_data = nes_read16_eeprom(nesdev->regs, next_section_address + 4);
+               if (eeprom_data != 0x464e) {
+                       nes_debug(NES_DBG_HW, "EEPROM Changed offset should be 0x464e but was 0x%04X\n",
+                                       eeprom_data);
+                       goto no_fw_rev;
+               }
+               eeprom_data = nes_read16_eeprom(nesdev->regs, next_section_address + 8);
+               printk(PFX "Firmware version %u.%u\n", (u8)(eeprom_data>>8), (u8)eeprom_data);
+               major_ver = (u8)(eeprom_data >> 8);
+               minor_ver = (u8)(eeprom_data);
+
+               if (nes_drv_opt & NES_DRV_OPT_DISABLE_VIRT_WQ) {
+                       nes_debug(NES_DBG_HW, "Virtual WQs have been disabled\n");
+               } else if (((major_ver == 2) && (minor_ver > 21)) || ((major_ver > 2) && (major_ver != 255))) {
+                       nesadapter->virtwq = 1;
+               }
+               nesadapter->firmware_version = (((u32)(u8)(eeprom_data>>8))  <<  16) +
+                               (u32)((u8)eeprom_data);
+
+no_fw_rev:
+               /* eeprom is valid */
+               eeprom_offset = nesadapter->software_eeprom_offset;
+               eeprom_offset += 8;
+               nesadapter->netdev_max = (u8)nes_read16_eeprom(nesdev->regs, eeprom_offset);
+               eeprom_offset += 2;
+               mac_addr_high = nes_read16_eeprom(nesdev->regs, eeprom_offset);
+               eeprom_offset += 2;
+               mac_addr_low = (u32)nes_read16_eeprom(nesdev->regs, eeprom_offset);
+               eeprom_offset += 2;
+               mac_addr_low <<= 16;
+               mac_addr_low += (u32)nes_read16_eeprom(nesdev->regs, eeprom_offset);
+               nes_debug(NES_DBG_HW, "Base MAC Address = 0x%04X%08X\n",
+                               mac_addr_high, mac_addr_low);
+               nes_debug(NES_DBG_HW, "MAC Address count = %u\n", nesadapter->netdev_max);
+
+               nesadapter->mac_addr_low = mac_addr_low;
+               nesadapter->mac_addr_high = mac_addr_high;
+
+               /* Read the Phy Type array */
+               eeprom_offset += 10;
+               eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset);
+               nesadapter->phy_type[0] = (u8)(eeprom_data >> 8);
+               nesadapter->phy_type[1] = (u8)eeprom_data;
+
+               /* Read the port array */
+               eeprom_offset += 2;
+               eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset);
+               nesadapter->phy_type[2] = (u8)(eeprom_data >> 8);
+               nesadapter->phy_type[3] = (u8)eeprom_data;
+               /* port_count is set by soft reset reg */
+               nes_debug(NES_DBG_HW, "port_count = %u, port 0 -> %u, port 1 -> %u,"
+                               " port 2 -> %u, port 3 -> %u\n",
+                               nesadapter->port_count,
+                               nesadapter->phy_type[0], nesadapter->phy_type[1],
+                               nesadapter->phy_type[2], nesadapter->phy_type[3]);
+
+               /* Read PD config array */
+               eeprom_offset += 10;
+               eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset);
+               nesadapter->pd_config_size[0] = eeprom_data;
+               eeprom_offset += 2;
+               eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset);
+               nesadapter->pd_config_base[0] = eeprom_data;
+               nes_debug(NES_DBG_HW, "PD0 config, size=0x%04x, base=0x%04x\n",
+                               nesadapter->pd_config_size[0], nesadapter->pd_config_base[0]);
+
+               eeprom_offset += 2;
+               eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset);
+               nesadapter->pd_config_size[1] = eeprom_data;
+               eeprom_offset += 2;
+               eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset);
+               nesadapter->pd_config_base[1] = eeprom_data;
+               nes_debug(NES_DBG_HW, "PD1 config, size=0x%04x, base=0x%04x\n",
+                               nesadapter->pd_config_size[1], nesadapter->pd_config_base[1]);
+
+               eeprom_offset += 2;
+               eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset);
+               nesadapter->pd_config_size[2] = eeprom_data;
+               eeprom_offset += 2;
+               eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset);
+               nesadapter->pd_config_base[2] = eeprom_data;
+               nes_debug(NES_DBG_HW, "PD2 config, size=0x%04x, base=0x%04x\n",
+                               nesadapter->pd_config_size[2], nesadapter->pd_config_base[2]);
+
+               eeprom_offset += 2;
+               eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset);
+               nesadapter->pd_config_size[3] = eeprom_data;
+               eeprom_offset += 2;
+               eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset);
+               nesadapter->pd_config_base[3] = eeprom_data;
+               nes_debug(NES_DBG_HW, "PD3 config, size=0x%04x, base=0x%04x\n",
+                               nesadapter->pd_config_size[3], nesadapter->pd_config_base[3]);
+
+               /* Read Rx Pool Size */
+               eeprom_offset += 22;   /* 46 */
+               eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset);
+               eeprom_offset += 2;
+               nesadapter->rx_pool_size = (((u32)eeprom_data) << 16) +
+                               nes_read16_eeprom(nesdev->regs, eeprom_offset);
+               nes_debug(NES_DBG_HW, "rx_pool_size = 0x%08X\n", nesadapter->rx_pool_size);
+
+               eeprom_offset += 2;
+               eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset);
+               eeprom_offset += 2;
+               nesadapter->tx_pool_size = (((u32)eeprom_data) << 16) +
+                               nes_read16_eeprom(nesdev->regs, eeprom_offset);
+               nes_debug(NES_DBG_HW, "tx_pool_size = 0x%08X\n", nesadapter->tx_pool_size);
+
+               eeprom_offset += 2;
+               eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset);
+               eeprom_offset += 2;
+               nesadapter->rx_threshold = (((u32)eeprom_data) << 16) +
+                               nes_read16_eeprom(nesdev->regs, eeprom_offset);
+               nes_debug(NES_DBG_HW, "rx_threshold = 0x%08X\n", nesadapter->rx_threshold);
+
+               eeprom_offset += 2;
+               eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset);
+               eeprom_offset += 2;
+               nesadapter->tcp_timer_core_clk_divisor = (((u32)eeprom_data) << 16) +
+                               nes_read16_eeprom(nesdev->regs, eeprom_offset);
+               nes_debug(NES_DBG_HW, "tcp_timer_core_clk_divisor = 0x%08X\n",
+                               nesadapter->tcp_timer_core_clk_divisor);
+
+               eeprom_offset += 2;
+               eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset);
+               eeprom_offset += 2;
+               nesadapter->iwarp_config = (((u32)eeprom_data) << 16) +
+                               nes_read16_eeprom(nesdev->regs, eeprom_offset);
+               nes_debug(NES_DBG_HW, "iwarp_config = 0x%08X\n", nesadapter->iwarp_config);
+
+               eeprom_offset += 2;
+               eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset);
+               eeprom_offset += 2;
+               nesadapter->cm_config = (((u32)eeprom_data) << 16) +
+                               nes_read16_eeprom(nesdev->regs, eeprom_offset);
+               nes_debug(NES_DBG_HW, "cm_config = 0x%08X\n", nesadapter->cm_config);
+
+               eeprom_offset += 2;
+               eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset);
+               eeprom_offset += 2;
+               nesadapter->sws_timer_config = (((u32)eeprom_data) << 16) +
+                               nes_read16_eeprom(nesdev->regs, eeprom_offset);
+               nes_debug(NES_DBG_HW, "sws_timer_config = 0x%08X\n", nesadapter->sws_timer_config);
+
+               eeprom_offset += 2;
+               eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset);
+               eeprom_offset += 2;
+               nesadapter->tcp_config1 = (((u32)eeprom_data) << 16) +
+                               nes_read16_eeprom(nesdev->regs, eeprom_offset);
+               nes_debug(NES_DBG_HW, "tcp_config1 = 0x%08X\n", nesadapter->tcp_config1);
+
+               eeprom_offset += 2;
+               eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset);
+               eeprom_offset += 2;
+               nesadapter->wqm_wat = (((u32)eeprom_data) << 16) +
+                               nes_read16_eeprom(nesdev->regs, eeprom_offset);
+               nes_debug(NES_DBG_HW, "wqm_wat = 0x%08X\n", nesadapter->wqm_wat);
+
+               eeprom_offset += 2;
+               eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset);
+               eeprom_offset += 2;
+               nesadapter->core_clock = (((u32)eeprom_data) << 16) +
+                               nes_read16_eeprom(nesdev->regs, eeprom_offset);
+               nes_debug(NES_DBG_HW, "core_clock = 0x%08X\n", nesadapter->core_clock);
+
+               if ((sw_section_ver) && (nesadapter->hw_rev != NE020_REV)) {
+                       eeprom_offset += 2;
+                       eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset);
+                       nesadapter->phy_index[0] = (eeprom_data & 0xff00)>>8;
+                       nesadapter->phy_index[1] = eeprom_data & 0x00ff;
+                       eeprom_offset += 2;
+                       eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset);
+                       nesadapter->phy_index[2] = (eeprom_data & 0xff00)>>8;
+                       nesadapter->phy_index[3] = eeprom_data & 0x00ff;
+               } else {
+                       nesadapter->phy_index[0] = 4;
+                       nesadapter->phy_index[1] = 5;
+                       nesadapter->phy_index[2] = 6;
+                       nesadapter->phy_index[3] = 7;
+               }
+               nes_debug(NES_DBG_HW, "Phy address map = 0 > %u,  1 > %u, 2 > %u, 3 > %u\n",
+                          nesadapter->phy_index[0],nesadapter->phy_index[1],
+                          nesadapter->phy_index[2],nesadapter->phy_index[3]);
+       }
+
+       return 0;
+}
+
+
+/**
+ * nes_read16_eeprom
+ */
+static u16 nes_read16_eeprom(void __iomem *addr, u16 offset)
+{
+       writel(NES_EEPROM_READ_REQUEST + (offset >> 1),
+                       (void __iomem *)addr + NES_EEPROM_COMMAND);
+
+       do {
+       } while (readl((void __iomem *)addr + NES_EEPROM_COMMAND) &
+                       NES_EEPROM_READ_REQUEST);
+
+       return readw((void __iomem *)addr + NES_EEPROM_DATA);
+}
+
+
+/**
+ * nes_write_1G_phy_reg
+ */
+void nes_write_1G_phy_reg(struct nes_device *nesdev, u8 phy_reg, u8 phy_addr, u16 data)
+{
+       struct nes_adapter *nesadapter = nesdev->nesadapter;
+       u32 u32temp;
+       u32 counter;
+       unsigned long flags;
+
+       spin_lock_irqsave(&nesadapter->phy_lock, flags);
+
+       nes_write_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL,
+                       0x50020000 | data | ((u32)phy_reg << 18) | ((u32)phy_addr << 23));
+       for (counter = 0; counter < 100 ; counter++) {
+               udelay(30);
+               u32temp = nes_read_indexed(nesdev, NES_IDX_MAC_INT_STATUS);
+               if (u32temp & 1) {
+                       /* nes_debug(NES_DBG_PHY, "Phy interrupt status = 0x%X.\n", u32temp); */
+                       nes_write_indexed(nesdev, NES_IDX_MAC_INT_STATUS, 1);
+                       break;
+               }
+       }
+       if (!(u32temp & 1))
+               nes_debug(NES_DBG_PHY, "Phy is not responding. interrupt status = 0x%X.\n",
+                               u32temp);
+
+       spin_unlock_irqrestore(&nesadapter->phy_lock, flags);
+}
+
+
+/**
+ * nes_read_1G_phy_reg
+ * This routine only issues the read, the data must be read
+ * separately.
+ */
+void nes_read_1G_phy_reg(struct nes_device *nesdev, u8 phy_reg, u8 phy_addr, u16 *data)
+{
+       struct nes_adapter *nesadapter = nesdev->nesadapter;
+       u32 u32temp;
+       u32 counter;
+       unsigned long flags;
+
+       /* nes_debug(NES_DBG_PHY, "phy addr = %d, mac_index = %d\n",
+                       phy_addr, nesdev->mac_index); */
+       spin_lock_irqsave(&nesadapter->phy_lock, flags);
+
+       nes_write_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL,
+                       0x60020000 | ((u32)phy_reg << 18) | ((u32)phy_addr << 23));
+       for (counter = 0; counter < 100 ; counter++) {
+               udelay(30);
+               u32temp = nes_read_indexed(nesdev, NES_IDX_MAC_INT_STATUS);
+               if (u32temp & 1) {
+                       /* nes_debug(NES_DBG_PHY, "Phy interrupt status = 0x%X.\n", u32temp); */
+                       nes_write_indexed(nesdev, NES_IDX_MAC_INT_STATUS, 1);
+                       break;
+               }
+       }
+       if (!(u32temp & 1)) {
+               nes_debug(NES_DBG_PHY, "Phy is not responding. interrupt status = 0x%X.\n",
+                               u32temp);
+               *data = 0xffff;
+       } else {
+               *data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL);
+       }
+       spin_unlock_irqrestore(&nesadapter->phy_lock, flags);
+}
+
+
+/**
+ * nes_write_10G_phy_reg
+ */
+void nes_write_10G_phy_reg(struct nes_device *nesdev, u16 phy_reg,
+               u8 phy_addr, u16 data)
+{
+       u32 dev_addr;
+       u32 port_addr;
+       u32 u32temp;
+       u32 counter;
+
+       dev_addr = 1;
+       port_addr = phy_addr;
+
+       /* set address */
+       nes_write_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL,
+                       0x00020000 | (u32)phy_reg | (((u32)dev_addr) << 18) | (((u32)port_addr) << 23));
+       for (counter = 0; counter < 100 ; counter++) {
+               udelay(30);
+               u32temp = nes_read_indexed(nesdev, NES_IDX_MAC_INT_STATUS);
+               if (u32temp & 1) {
+                       nes_write_indexed(nesdev, NES_IDX_MAC_INT_STATUS, 1);
+                       break;
+               }
+       }
+       if (!(u32temp & 1))
+               nes_debug(NES_DBG_PHY, "Phy is not responding. interrupt status = 0x%X.\n",
+                               u32temp);
+
+       /* set data */
+       nes_write_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL,
+                       0x10020000 | (u32)data | (((u32)dev_addr) << 18) | (((u32)port_addr) << 23));
+       for (counter = 0; counter < 100 ; counter++) {
+               udelay(30);
+               u32temp = nes_read_indexed(nesdev, NES_IDX_MAC_INT_STATUS);
+               if (u32temp & 1) {
+                       nes_write_indexed(nesdev, NES_IDX_MAC_INT_STATUS, 1);
+                       break;
+               }
+       }
+       if (!(u32temp & 1))
+               nes_debug(NES_DBG_PHY, "Phy is not responding. interrupt status = 0x%X.\n",
+                               u32temp);
+}
+
+
+/**
+ * nes_read_10G_phy_reg
+ * This routine only issues the read, the data must be read
+ * separately.
+ */
+void nes_read_10G_phy_reg(struct nes_device *nesdev, u16 phy_reg, u8 phy_addr)
+{
+       u32 dev_addr;
+       u32 port_addr;
+       u32 u32temp;
+       u32 counter;
+
+       dev_addr = 1;
+       port_addr = phy_addr;
+
+       /* set address */
+       nes_write_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL,
+                       0x00020000 | (u32)phy_reg | (((u32)dev_addr) << 18) | (((u32)port_addr) << 23));
+       for (counter = 0; counter < 100 ; counter++) {
+               udelay(30);
+               u32temp = nes_read_indexed(nesdev, NES_IDX_MAC_INT_STATUS);
+               if (u32temp & 1) {
+                       nes_write_indexed(nesdev, NES_IDX_MAC_INT_STATUS, 1);
+                       break;
+               }
+       }
+       if (!(u32temp & 1))
+               nes_debug(NES_DBG_PHY, "Phy is not responding. interrupt status = 0x%X.\n",
+                               u32temp);
+
+       /* issue read */
+       nes_write_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL,
+                       0x30020000 | (((u32)dev_addr) << 18) | (((u32)port_addr) << 23));
+       for (counter = 0; counter < 100 ; counter++) {
+               udelay(30);
+               u32temp = nes_read_indexed(nesdev, NES_IDX_MAC_INT_STATUS);
+               if (u32temp & 1) {
+                       nes_write_indexed(nesdev, NES_IDX_MAC_INT_STATUS, 1);
+                       break;
+               }
+       }
+       if (!(u32temp & 1))
+               nes_debug(NES_DBG_PHY, "Phy is not responding. interrupt status = 0x%X.\n",
+                               u32temp);
+}
+
+
+/**
+ * nes_get_cqp_request
+ */
+struct nes_cqp_request *nes_get_cqp_request(struct nes_device *nesdev)
+{
+       unsigned long flags;
+       struct nes_cqp_request *cqp_request = NULL;
+
+       if (!list_empty(&nesdev->cqp_avail_reqs)) {
+               spin_lock_irqsave(&nesdev->cqp.lock, flags);
+               cqp_request = list_entry(nesdev->cqp_avail_reqs.next,
+                               struct nes_cqp_request, list);
+               list_del_init(&cqp_request->list);
+               spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+       } else {
+               cqp_request = kzalloc(sizeof(struct nes_cqp_request), GFP_KERNEL);
+               if (cqp_request) {
+                       cqp_request->dynamic = 1;
+                       INIT_LIST_HEAD(&cqp_request->list);
+               }
+       }
+
+       if (cqp_request) {
+               init_waitqueue_head(&cqp_request->waitq);
+               cqp_request->waiting = 0;
+               cqp_request->request_done = 0;
+               cqp_request->callback = 0;
+               init_waitqueue_head(&cqp_request->waitq);
+               nes_debug(NES_DBG_CQP, "Got cqp request %p from the available list \n",
+                               cqp_request);
+       } else
+               printk(KERN_ERR PFX "%s: Could not allocated a CQP request.\n",
+                          __FUNCTION__);
+
+       return cqp_request;
+}
+
+
+/**
+ * nes_post_cqp_request
+ */
+void nes_post_cqp_request(struct nes_device *nesdev,
+               struct nes_cqp_request *cqp_request, int ring_doorbell)
+{
+       struct nes_hw_cqp_wqe *cqp_wqe;
+       unsigned long flags;
+       u32 cqp_head;
+       u64 u64temp;
+
+       spin_lock_irqsave(&nesdev->cqp.lock, flags);
+
+       if (((((nesdev->cqp.sq_tail+(nesdev->cqp.sq_size*2))-nesdev->cqp.sq_head) &
+                       (nesdev->cqp.sq_size - 1)) != 1)
+                       && (list_empty(&nesdev->cqp_pending_reqs))) {
+               cqp_head = nesdev->cqp.sq_head++;
+               nesdev->cqp.sq_head &= nesdev->cqp.sq_size-1;
+               cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
+               memcpy(cqp_wqe, &cqp_request->cqp_wqe, sizeof(*cqp_wqe));
+               barrier();
+               u64temp = (unsigned long)cqp_request;
+               set_wqe_64bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_COMP_SCRATCH_LOW_IDX,
+                                   u64temp);
+               nes_debug(NES_DBG_CQP, "CQP request (opcode 0x%02X), line 1 = 0x%08X put on CQPs SQ,"
+                               " request = %p, cqp_head = %u, cqp_tail = %u, cqp_size = %u,"
+                               " waiting = %d, refcount = %d.\n",
+                               le32_to_cpu(cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX])&0x3f,
+                               le32_to_cpu(cqp_wqe->wqe_words[NES_CQP_WQE_ID_IDX]), cqp_request,
+                               nesdev->cqp.sq_head, nesdev->cqp.sq_tail, nesdev->cqp.sq_size,
+                               cqp_request->waiting, atomic_read(&cqp_request->refcount));
+               barrier();
+               if (ring_doorbell) {
+                       /* Ring doorbell (1 WQEs) */
+                       nes_write32(nesdev->regs+NES_WQE_ALLOC, 0x01800000 | nesdev->cqp.qp_id);
+               }
+
+               barrier();
+       } else {
+               nes_debug(NES_DBG_CQP, "CQP request %p (opcode 0x%02X), line 1 = 0x%08X"
+                               " put on the pending queue.\n",
+                               cqp_request,
+                               le32_to_cpu(cqp_request->cqp_wqe.wqe_words[NES_CQP_WQE_OPCODE_IDX])&0x3f,
+                               le32_to_cpu(cqp_request->cqp_wqe.wqe_words[NES_CQP_WQE_ID_IDX]));
+               list_add_tail(&cqp_request->list, &nesdev->cqp_pending_reqs);
+       }
+
+       spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+
+       return;
+}
+
+
+/**
+ * nes_arp_table
+ */
+int nes_arp_table(struct nes_device *nesdev, u32 ip_addr, u8 *mac_addr, u32 action)
+{
+       struct nes_adapter *nesadapter = nesdev->nesadapter;
+       int arp_index;
+       int err = 0;
+
+       for (arp_index = 0; (u32) arp_index < nesadapter->arp_table_size; arp_index++) {
+               if (nesadapter->arp_table[arp_index].ip_addr == ip_addr)
+                       break;
+       }
+
+       if (action == NES_ARP_ADD) {
+               if (arp_index != nesadapter->arp_table_size) {
+                       return -1;
+               }
+
+               arp_index = 0;
+               err = nes_alloc_resource(nesadapter, nesadapter->allocated_arps,
+                               nesadapter->arp_table_size, (u32 *)&arp_index, &nesadapter->next_arp_index);
+               if (err) {
+                       nes_debug(NES_DBG_NETDEV, "nes_alloc_resource returned error = %u\n", err);
+                       return err;
+               }
+               nes_debug(NES_DBG_NETDEV, "ADD, arp_index=%d\n", arp_index);
+
+               nesadapter->arp_table[arp_index].ip_addr = ip_addr;
+               memcpy(nesadapter->arp_table[arp_index].mac_addr, mac_addr, ETH_ALEN);
+               return arp_index;
+       }
+
+       /* DELETE or RESOLVE */
+       if (arp_index == nesadapter->arp_table_size) {
+               nes_debug(NES_DBG_NETDEV, "mac address not in ARP table - cannot delete or resolve\n");
+               return -1;
+       }
+
+       if (action == NES_ARP_RESOLVE) {
+               nes_debug(NES_DBG_NETDEV, "RESOLVE, arp_index=%d\n", arp_index);
+               return arp_index;
+       }
+
+       if (action == NES_ARP_DELETE) {
+               nes_debug(NES_DBG_NETDEV, "DELETE, arp_index=%d\n", arp_index);
+               nesadapter->arp_table[arp_index].ip_addr = 0;
+               memset(nesadapter->arp_table[arp_index].mac_addr, 0x00, ETH_ALEN);
+               nes_free_resource(nesadapter, nesadapter->allocated_arps, arp_index);
+               return arp_index;
+       }
+
+       return -1;
+}
+
+
+/**
+ * nes_mh_fix
+ */
+void nes_mh_fix(unsigned long parm)
+{
+       unsigned long flags;
+       struct nes_device *nesdev = (struct nes_device *)parm;
+       struct nes_adapter *nesadapter = nesdev->nesadapter;
+       struct nes_vnic *nesvnic;
+       u32 used_chunks_tx;
+       u32 temp_used_chunks_tx;
+       u32 temp_last_used_chunks_tx;
+       u32 used_chunks_mask;
+       u32 mac_tx_frames_low;
+       u32 mac_tx_frames_high;
+       u32 mac_tx_pauses;
+       u32 serdes_status;
+       u32 reset_value;
+       u32 tx_control;
+       u32 tx_config;
+       u32 tx_pause_quanta;
+       u32 rx_control;
+       u32 rx_config;
+       u32 mac_exact_match;
+       u32 mpp_debug;
+       u32 i=0;
+       u32 chunks_tx_progress = 0;
+
+       spin_lock_irqsave(&nesadapter->phy_lock, flags);
+       if ((nesadapter->mac_sw_state[0] != NES_MAC_SW_IDLE) || (nesadapter->mac_link_down[0])) {
+               spin_unlock_irqrestore(&nesadapter->phy_lock, flags);
+               goto no_mh_work;
+       }
+       nesadapter->mac_sw_state[0] = NES_MAC_SW_MH;
+       spin_unlock_irqrestore(&nesadapter->phy_lock, flags);
+       do {
+               mac_tx_frames_low = nes_read_indexed(nesdev, NES_IDX_MAC_TX_FRAMES_LOW);
+               mac_tx_frames_high = nes_read_indexed(nesdev, NES_IDX_MAC_TX_FRAMES_HIGH);
+               mac_tx_pauses = nes_read_indexed(nesdev, NES_IDX_MAC_TX_PAUSE_FRAMES);
+               used_chunks_tx = nes_read_indexed(nesdev, NES_IDX_USED_CHUNKS_TX);
+               nesdev->mac_pause_frames_sent += mac_tx_pauses;
+               used_chunks_mask = 0;
+               temp_used_chunks_tx = used_chunks_tx;
+               temp_last_used_chunks_tx = nesdev->last_used_chunks_tx;
+
+               if (nesdev->netdev[0]) {
+                       nesvnic = netdev_priv(nesdev->netdev[0]);
+               } else {
+                       break;
+               }
+
+               for (i=0; i<4; i++) {
+                       used_chunks_mask <<= 8;
+                       if (nesvnic->qp_nic_index[i] != 0xff) {
+                               used_chunks_mask |= 0xff;
+                               if ((temp_used_chunks_tx&0xff)<(temp_last_used_chunks_tx&0xff)) {
+                                       chunks_tx_progress = 1;
+                               }
+                       }
+                       temp_used_chunks_tx >>= 8;
+                       temp_last_used_chunks_tx >>= 8;
+               }
+               if ((mac_tx_frames_low) || (mac_tx_frames_high) ||
+                       (!(used_chunks_tx&used_chunks_mask)) ||
+                       (!(nesdev->last_used_chunks_tx&used_chunks_mask)) ||
+                       (chunks_tx_progress) ) {
+                       nesdev->last_used_chunks_tx = used_chunks_tx;
+                       break;
+               }
+               nesdev->last_used_chunks_tx = used_chunks_tx;
+               barrier();
+
+               nes_write_indexed(nesdev, NES_IDX_MAC_TX_CONTROL, 0x00000005);
+               mh_pauses_sent++;
+               mac_tx_pauses = nes_read_indexed(nesdev, NES_IDX_MAC_TX_PAUSE_FRAMES);
+               if (mac_tx_pauses) {
+                       nesdev->mac_pause_frames_sent += mac_tx_pauses;
+                       break;
+               }
+
+               tx_control = nes_read_indexed(nesdev, NES_IDX_MAC_TX_CONTROL);
+               tx_config = nes_read_indexed(nesdev, NES_IDX_MAC_TX_CONFIG);
+               tx_pause_quanta = nes_read_indexed(nesdev, NES_IDX_MAC_TX_PAUSE_QUANTA);
+               rx_control = nes_read_indexed(nesdev, NES_IDX_MAC_RX_CONTROL);
+               rx_config = nes_read_indexed(nesdev, NES_IDX_MAC_RX_CONFIG);
+               mac_exact_match = nes_read_indexed(nesdev, NES_IDX_MAC_EXACT_MATCH_BOTTOM);
+               mpp_debug = nes_read_indexed(nesdev, NES_IDX_MPP_DEBUG);
+
+               /* one last ditch effort to avoid a false positive */
+               mac_tx_pauses = nes_read_indexed(nesdev, NES_IDX_MAC_TX_PAUSE_FRAMES);
+               if (mac_tx_pauses) {
+                       nesdev->last_mac_tx_pauses = nesdev->mac_pause_frames_sent;
+                       nes_debug(NES_DBG_HW, "failsafe caught slow outbound pause\n");
+                       break;
+               }
+               mh_detected++;
+
+               nes_write_indexed(nesdev, NES_IDX_MAC_TX_CONTROL, 0x00000000);
+               nes_write_indexed(nesdev, NES_IDX_MAC_TX_CONFIG, 0x00000000);
+               reset_value = nes_read32(nesdev->regs+NES_SOFTWARE_RESET);
+
+               nes_write32(nesdev->regs+NES_SOFTWARE_RESET, reset_value | 0x0000001d);
+
+               while (((nes_read32(nesdev->regs+NES_SOFTWARE_RESET)
+                               & 0x00000040) != 0x00000040) && (i++ < 5000)) {
+                       /* mdelay(1); */
+               }
+
+               nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL0, 0x00000008);
+               serdes_status = nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_STATUS0);
+
+               nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_TX_EMP0, 0x000bdef7);
+               nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_TX_DRIVE0, 0x9ce73000);
+               nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_RX_MODE0, 0x0ff00000);
+               nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_RX_SIGDET0, 0x00000000);
+               nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_BYPASS0, 0x00000000);
+               nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_LOOPBACK_CONTROL0, 0x00000000);
+               if (nesadapter->OneG_Mode) {
+                       nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_RX_EQ_CONTROL0, 0xf0182222);
+               } else {
+                       nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_RX_EQ_CONTROL0, 0xf0042222);
+               }
+               serdes_status = nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_RX_EQ_STATUS0);
+               nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_CDR_CONTROL0, 0x000000ff);
+
+               nes_write_indexed(nesdev, NES_IDX_MAC_TX_CONTROL, tx_control);
+               nes_write_indexed(nesdev, NES_IDX_MAC_TX_CONFIG, tx_config);
+               nes_write_indexed(nesdev, NES_IDX_MAC_TX_PAUSE_QUANTA, tx_pause_quanta);
+               nes_write_indexed(nesdev, NES_IDX_MAC_RX_CONTROL, rx_control);
+               nes_write_indexed(nesdev, NES_IDX_MAC_RX_CONFIG, rx_config);
+               nes_write_indexed(nesdev, NES_IDX_MAC_EXACT_MATCH_BOTTOM, mac_exact_match);
+               nes_write_indexed(nesdev, NES_IDX_MPP_DEBUG, mpp_debug);
+
+       } while (0);
+
+       nesadapter->mac_sw_state[0] = NES_MAC_SW_IDLE;
+no_mh_work:
+       nesdev->nesadapter->mh_timer.expires = jiffies + (HZ/5);
+       add_timer(&nesdev->nesadapter->mh_timer);
+}
+
+/**
+ * nes_clc
+ */
+void nes_clc(unsigned long parm)
+{
+       unsigned long flags;
+       struct nes_device *nesdev = (struct nes_device *)parm;
+       struct nes_adapter *nesadapter = nesdev->nesadapter;
+
+       spin_lock_irqsave(&nesadapter->phy_lock, flags);
+    nesadapter->link_interrupt_count[0] = 0;
+    nesadapter->link_interrupt_count[1] = 0;
+    nesadapter->link_interrupt_count[2] = 0;
+    nesadapter->link_interrupt_count[3] = 0;
+       spin_unlock_irqrestore(&nesadapter->phy_lock, flags);
+
+       nesadapter->lc_timer.expires = jiffies + 3600 * HZ;  /* 1 hour */
+       add_timer(&nesadapter->lc_timer);
+}
+
+
+/**
+ * nes_dump_mem
+ */
+void nes_dump_mem(unsigned int dump_debug_level, void *addr, int length)
+{
+       char  xlate[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+               'a', 'b', 'c', 'd', 'e', 'f'};
+       char  *ptr;
+       char  hex_buf[80];
+       char  ascii_buf[20];
+       int   num_char;
+       int   num_ascii;
+       int   num_hex;
+
+       if (!(nes_debug_level & dump_debug_level)) {
+               return;
+       }
+
+       ptr = addr;
+       if (length > 0x100) {
+               nes_debug(dump_debug_level, "Length truncated from %x to %x\n", length, 0x100);
+               length = 0x100;
+       }
+       nes_debug(dump_debug_level, "Address=0x%p, length=0x%x (%d)\n", ptr, length, length);
+
+       memset(ascii_buf, 0, 20);
+       memset(hex_buf, 0, 80);
+
+       num_ascii = 0;
+       num_hex = 0;
+       for (num_char = 0; num_char < length; num_char++) {
+               if (num_ascii == 8) {
+                       ascii_buf[num_ascii++] = ' ';
+                       hex_buf[num_hex++] = '-';
+                       hex_buf[num_hex++] = ' ';
+               }
+
+               if (*ptr < 0x20 || *ptr > 0x7e)
+                       ascii_buf[num_ascii++] = '.';
+               else
+                       ascii_buf[num_ascii++] = *ptr;
+               hex_buf[num_hex++] = xlate[((*ptr & 0xf0) >> 4)];
+               hex_buf[num_hex++] = xlate[*ptr & 0x0f];
+               hex_buf[num_hex++] = ' ';
+               ptr++;
+
+               if (num_ascii >= 17) {
+                       /* output line and reset */
+                       nes_debug(dump_debug_level, "   %s |  %s\n", hex_buf, ascii_buf);
+                       memset(ascii_buf, 0, 20);
+                       memset(hex_buf, 0, 80);
+                       num_ascii = 0;
+                       num_hex = 0;
+               }
+       }
+
+       /* output the rest */
+       if (num_ascii) {
+               while (num_ascii < 17) {
+                       if (num_ascii == 8) {
+                               hex_buf[num_hex++] = ' ';
+                               hex_buf[num_hex++] = ' ';
+                       }
+                       hex_buf[num_hex++] = ' ';
+                       hex_buf[num_hex++] = ' ';
+                       hex_buf[num_hex++] = ' ';
+                       num_ascii++;
+               }
+
+               nes_debug(dump_debug_level, "   %s |  %s\n", hex_buf, ascii_buf);
+       }
+}
diff --git a/drivers/infiniband/hw/nes/nes_verbs.c b/drivers/infiniband/hw/nes/nes_verbs.c
new file mode 100644 (file)
index 0000000..ffd4b42
--- /dev/null
@@ -0,0 +1,3917 @@
+/*
+ * Copyright (c) 2006 - 2008 NetEffect, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/random.h>
+#include <linux/highmem.h>
+#include <asm/byteorder.h>
+
+#include <rdma/ib_verbs.h>
+#include <rdma/iw_cm.h>
+#include <rdma/ib_user_verbs.h>
+
+#include "nes.h"
+
+#include <rdma/ib_umem.h>
+
+atomic_t mod_qp_timouts;
+atomic_t qps_created;
+atomic_t sw_qps_destroyed;
+
+
+/**
+ * nes_alloc_mw
+ */
+static struct ib_mw *nes_alloc_mw(struct ib_pd *ibpd) {
+       unsigned long flags;
+       struct nes_pd *nespd = to_nespd(ibpd);
+       struct nes_vnic *nesvnic = to_nesvnic(ibpd->device);
+       struct nes_device *nesdev = nesvnic->nesdev;
+       struct nes_adapter *nesadapter = nesdev->nesadapter;
+       struct nes_cqp_request *cqp_request;
+       struct nes_mr *nesmr;
+       struct ib_mw *ibmw;
+       struct nes_hw_cqp_wqe *cqp_wqe;
+       int ret;
+       u32 stag;
+       u32 stag_index = 0;
+       u32 next_stag_index = 0;
+       u32 driver_key = 0;
+       u8 stag_key = 0;
+
+       get_random_bytes(&next_stag_index, sizeof(next_stag_index));
+       stag_key = (u8)next_stag_index;
+
+       driver_key = 0;
+
+       next_stag_index >>= 8;
+       next_stag_index %= nesadapter->max_mr;
+
+       ret = nes_alloc_resource(nesadapter, nesadapter->allocated_mrs,
+                       nesadapter->max_mr, &stag_index, &next_stag_index);
+       if (ret) {
+               return ERR_PTR(ret);
+       }
+
+       nesmr = kzalloc(sizeof(*nesmr), GFP_KERNEL);
+       if (!nesmr) {
+               nes_free_resource(nesadapter, nesadapter->allocated_mrs, stag_index);
+               return ERR_PTR(-ENOMEM);
+       }
+
+       stag = stag_index << 8;
+       stag |= driver_key;
+       stag += (u32)stag_key;
+
+       nes_debug(NES_DBG_MR, "Registering STag 0x%08X, index = 0x%08X\n",
+                       stag, stag_index);
+
+       /* Register the region with the adapter */
+       cqp_request = nes_get_cqp_request(nesdev);
+       if (cqp_request == NULL) {
+               kfree(nesmr);
+               nes_free_resource(nesadapter, nesadapter->allocated_mrs, stag_index);
+               return ERR_PTR(-ENOMEM);
+       }
+
+       cqp_request->waiting = 1;
+       cqp_wqe = &cqp_request->cqp_wqe;
+
+       cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] =
+                       cpu_to_le32( NES_CQP_ALLOCATE_STAG | NES_CQP_STAG_RIGHTS_REMOTE_READ |
+                       NES_CQP_STAG_RIGHTS_REMOTE_WRITE | NES_CQP_STAG_VA_TO |
+                       NES_CQP_STAG_REM_ACC_EN);
+
+       nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
+       set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_STAG_WQE_LEN_HIGH_PD_IDX, (nespd->pd_id & 0x00007fff));
+       set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_STAG_WQE_STAG_IDX, stag);
+
+       atomic_set(&cqp_request->refcount, 2);
+       nes_post_cqp_request(nesdev, cqp_request, NES_CQP_REQUEST_RING_DOORBELL);
+
+       /* Wait for CQP */
+       ret = wait_event_timeout(cqp_request->waitq, (cqp_request->request_done != 0),
+                       NES_EVENT_TIMEOUT);
+       nes_debug(NES_DBG_MR, "Register STag 0x%08X completed, wait_event_timeout ret = %u,"
+                       " CQP Major:Minor codes = 0x%04X:0x%04X.\n",
+                       stag, ret, cqp_request->major_code, cqp_request->minor_code);
+       if ((!ret) || (cqp_request->major_code)) {
+               if (atomic_dec_and_test(&cqp_request->refcount)) {
+                       if (cqp_request->dynamic) {
+                               kfree(cqp_request);
+                       } else {
+                               spin_lock_irqsave(&nesdev->cqp.lock, flags);
+                               list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs);
+                               spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+                       }
+               }
+               kfree(nesmr);
+               nes_free_resource(nesadapter, nesadapter->allocated_mrs, stag_index);
+               if (!ret) {
+                       return ERR_PTR(-ETIME);
+               } else {
+                       return ERR_PTR(-ENOMEM);
+               }
+       } else {
+               if (atomic_dec_and_test(&cqp_request->refcount)) {
+                       if (cqp_request->dynamic) {
+                               kfree(cqp_request);
+                       } else {
+                               spin_lock_irqsave(&nesdev->cqp.lock, flags);
+                               list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs);
+                               spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+                       }
+               }
+       }
+
+       nesmr->ibmw.rkey = stag;
+       nesmr->mode = IWNES_MEMREG_TYPE_MW;
+       ibmw = &nesmr->ibmw;
+       nesmr->pbl_4k = 0;
+       nesmr->pbls_used = 0;
+
+       return ibmw;
+}
+
+
+/**
+ * nes_dealloc_mw
+ */
+static int nes_dealloc_mw(struct ib_mw *ibmw)
+{
+       struct nes_mr *nesmr = to_nesmw(ibmw);
+       struct nes_vnic *nesvnic = to_nesvnic(ibmw->device);
+       struct nes_device *nesdev = nesvnic->nesdev;
+       struct nes_adapter *nesadapter = nesdev->nesadapter;
+       struct nes_hw_cqp_wqe *cqp_wqe;
+       struct nes_cqp_request *cqp_request;
+       int err = 0;
+       unsigned long flags;
+       int ret;
+
+       /* Deallocate the window with the adapter */
+       cqp_request = nes_get_cqp_request(nesdev);
+       if (cqp_request == NULL) {
+               nes_debug(NES_DBG_MR, "Failed to get a cqp_request.\n");
+               return -ENOMEM;
+       }
+       cqp_request->waiting = 1;
+       cqp_wqe = &cqp_request->cqp_wqe;
+       nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
+       set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_OPCODE_IDX, NES_CQP_DEALLOCATE_STAG);
+       set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_STAG_WQE_STAG_IDX, ibmw->rkey);
+
+       atomic_set(&cqp_request->refcount, 2);
+       nes_post_cqp_request(nesdev, cqp_request, NES_CQP_REQUEST_RING_DOORBELL);
+
+       /* Wait for CQP */
+       nes_debug(NES_DBG_MR, "Waiting for deallocate STag 0x%08X to complete.\n",
+                       ibmw->rkey);
+       ret = wait_event_timeout(cqp_request->waitq, (0 != cqp_request->request_done),
+                       NES_EVENT_TIMEOUT);
+       nes_debug(NES_DBG_MR, "Deallocate STag completed, wait_event_timeout ret = %u,"
+                       " CQP Major:Minor codes = 0x%04X:0x%04X.\n",
+                       ret, cqp_request->major_code, cqp_request->minor_code);
+       if ((!ret) || (cqp_request->major_code)) {
+               if (atomic_dec_and_test(&cqp_request->refcount)) {
+                       if (cqp_request->dynamic) {
+                               kfree(cqp_request);
+                       } else {
+                               spin_lock_irqsave(&nesdev->cqp.lock, flags);
+                               list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs);
+                               spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+                       }
+               }
+               if (!ret) {
+                       err = -ETIME;
+               } else {
+                       err = -EIO;
+               }
+       } else {
+               if (atomic_dec_and_test(&cqp_request->refcount)) {
+                       if (cqp_request->dynamic) {
+                               kfree(cqp_request);
+                       } else {
+                               spin_lock_irqsave(&nesdev->cqp.lock, flags);
+                               list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs);
+                               spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+                       }
+               }
+       }
+
+       nes_free_resource(nesadapter, nesadapter->allocated_mrs,
+                       (ibmw->rkey & 0x0fffff00) >> 8);
+       kfree(nesmr);
+
+       return err;
+}
+
+
+/**
+ * nes_bind_mw
+ */
+static int nes_bind_mw(struct ib_qp *ibqp, struct ib_mw *ibmw,
+               struct ib_mw_bind *ibmw_bind)
+{
+       u64 u64temp;
+       struct nes_vnic *nesvnic = to_nesvnic(ibqp->device);
+       struct nes_device *nesdev = nesvnic->nesdev;
+       /* struct nes_mr *nesmr = to_nesmw(ibmw); */
+       struct nes_qp *nesqp = to_nesqp(ibqp);
+       struct nes_hw_qp_wqe *wqe;
+       unsigned long flags = 0;
+       u32 head;
+       u32 wqe_misc = 0;
+       u32 qsize;
+
+       if (nesqp->ibqp_state > IB_QPS_RTS)
+               return -EINVAL;
+
+               spin_lock_irqsave(&nesqp->lock, flags);
+
+       head = nesqp->hwqp.sq_head;
+       qsize = nesqp->hwqp.sq_tail;
+
+       /* Check for SQ overflow */
+       if (((head + (2 * qsize) - nesqp->hwqp.sq_tail) % qsize) == (qsize - 1)) {
+                       spin_unlock_irqrestore(&nesqp->lock, flags);
+               return -EINVAL;
+       }
+
+       wqe = &nesqp->hwqp.sq_vbase[head];
+       /* nes_debug(NES_DBG_MR, "processing sq wqe at %p, head = %u.\n", wqe, head); */
+       nes_fill_init_qp_wqe(wqe, nesqp, head);
+       u64temp = ibmw_bind->wr_id;
+       set_wqe_64bit_value(wqe->wqe_words, NES_IWARP_SQ_WQE_COMP_SCRATCH_LOW_IDX, u64temp);
+       wqe_misc = NES_IWARP_SQ_OP_BIND;
+
+       wqe_misc |= NES_IWARP_SQ_WQE_LOCAL_FENCE;
+
+       if (ibmw_bind->send_flags & IB_SEND_SIGNALED)
+               wqe_misc |= NES_IWARP_SQ_WQE_SIGNALED_COMPL;
+
+       if (ibmw_bind->mw_access_flags & IB_ACCESS_REMOTE_WRITE) {
+               wqe_misc |= NES_CQP_STAG_RIGHTS_REMOTE_WRITE;
+       }
+       if (ibmw_bind->mw_access_flags & IB_ACCESS_REMOTE_READ) {
+               wqe_misc |= NES_CQP_STAG_RIGHTS_REMOTE_READ;
+       }
+
+       set_wqe_32bit_value(wqe->wqe_words, NES_IWARP_SQ_WQE_MISC_IDX, wqe_misc);
+       set_wqe_32bit_value(wqe->wqe_words, NES_IWARP_SQ_BIND_WQE_MR_IDX, ibmw_bind->mr->lkey);
+       set_wqe_32bit_value(wqe->wqe_words, NES_IWARP_SQ_BIND_WQE_MW_IDX, ibmw->rkey);
+       set_wqe_32bit_value(wqe->wqe_words, NES_IWARP_SQ_BIND_WQE_LENGTH_LOW_IDX,
+                       ibmw_bind->length);
+       wqe->wqe_words[NES_IWARP_SQ_BIND_WQE_LENGTH_HIGH_IDX] = 0;
+       u64temp = (u64)ibmw_bind->addr;
+       set_wqe_64bit_value(wqe->wqe_words, NES_IWARP_SQ_BIND_WQE_VA_FBO_LOW_IDX, u64temp);
+
+       head++;
+       if (head >= qsize)
+               head = 0;
+
+       nesqp->hwqp.sq_head = head;
+       barrier();
+
+       nes_write32(nesdev->regs+NES_WQE_ALLOC,
+                       (1 << 24) | 0x00800000 | nesqp->hwqp.qp_id);
+
+               spin_unlock_irqrestore(&nesqp->lock, flags);
+
+       return 0;
+}
+
+
+/**
+ * nes_alloc_fmr
+ */
+static struct ib_fmr *nes_alloc_fmr(struct ib_pd *ibpd,
+               int ibmr_access_flags,
+               struct ib_fmr_attr *ibfmr_attr)
+{
+       unsigned long flags;
+       struct nes_pd *nespd = to_nespd(ibpd);
+       struct nes_vnic *nesvnic = to_nesvnic(ibpd->device);
+       struct nes_device *nesdev = nesvnic->nesdev;
+       struct nes_adapter *nesadapter = nesdev->nesadapter;
+       struct nes_fmr *nesfmr;
+       struct nes_cqp_request *cqp_request;
+       struct nes_hw_cqp_wqe *cqp_wqe;
+       int ret;
+       u32 stag;
+       u32 stag_index = 0;
+       u32 next_stag_index = 0;
+       u32 driver_key = 0;
+       u32 opcode = 0;
+       u8 stag_key = 0;
+       int i=0;
+       struct nes_vpbl vpbl;
+
+       get_random_bytes(&next_stag_index, sizeof(next_stag_index));
+       stag_key = (u8)next_stag_index;
+
+       driver_key = 0;
+
+       next_stag_index >>= 8;
+       next_stag_index %= nesadapter->max_mr;
+
+       ret = nes_alloc_resource(nesadapter, nesadapter->allocated_mrs,
+                       nesadapter->max_mr, &stag_index, &next_stag_index);
+       if (ret) {
+               goto failed_resource_alloc;
+       }
+
+       nesfmr = kzalloc(sizeof(*nesfmr), GFP_KERNEL);
+       if (!nesfmr) {
+               ret = -ENOMEM;
+               goto failed_fmr_alloc;
+       }
+
+       nesfmr->nesmr.mode = IWNES_MEMREG_TYPE_FMR;
+       if (ibfmr_attr->max_pages == 1) {
+               /* use zero length PBL */
+               nesfmr->nesmr.pbl_4k = 0;
+               nesfmr->nesmr.pbls_used = 0;
+       } else if (ibfmr_attr->max_pages <= 32) {
+               /* use PBL 256 */
+               nesfmr->nesmr.pbl_4k = 0;
+               nesfmr->nesmr.pbls_used = 1;
+       } else if (ibfmr_attr->max_pages <= 512) {
+               /* use 4K PBLs */
+               nesfmr->nesmr.pbl_4k = 1;
+               nesfmr->nesmr.pbls_used = 1;
+       } else {
+               /* use two level 4K PBLs */
+               /* add support for two level 256B PBLs */
+               nesfmr->nesmr.pbl_4k = 1;
+               nesfmr->nesmr.pbls_used = 1 + (ibfmr_attr->max_pages >> 9) +
+                               ((ibfmr_attr->max_pages & 511) ? 1 : 0);
+       }
+       /* Register the region with the adapter */
+       spin_lock_irqsave(&nesadapter->pbl_lock, flags);
+
+       /* track PBL resources */
+       if (nesfmr->nesmr.pbls_used != 0) {
+               if (nesfmr->nesmr.pbl_4k) {
+                       if (nesfmr->nesmr.pbls_used > nesadapter->free_4kpbl) {
+                               spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
+                               ret = -ENOMEM;
+                               goto failed_vpbl_alloc;
+                       } else {
+                               nesadapter->free_4kpbl -= nesfmr->nesmr.pbls_used;
+                       }
+               } else {
+                       if (nesfmr->nesmr.pbls_used > nesadapter->free_256pbl) {
+                               spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
+                               ret = -ENOMEM;
+                               goto failed_vpbl_alloc;
+                       } else {
+                               nesadapter->free_256pbl -= nesfmr->nesmr.pbls_used;
+                       }
+               }
+       }
+
+       /* one level pbl */
+       if (nesfmr->nesmr.pbls_used == 0) {
+               nesfmr->root_vpbl.pbl_vbase = NULL;
+               nes_debug(NES_DBG_MR,  "zero level pbl \n");
+       } else if (nesfmr->nesmr.pbls_used == 1) {
+               /* can change it to kmalloc & dma_map_single */
+               nesfmr->root_vpbl.pbl_vbase = pci_alloc_consistent(nesdev->pcidev, 4096,
+                               &nesfmr->root_vpbl.pbl_pbase);
+               if (!nesfmr->root_vpbl.pbl_vbase) {
+                       spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
+                       ret = -ENOMEM;
+                       goto failed_vpbl_alloc;
+               }
+               nesfmr->leaf_pbl_cnt = 0;
+               nes_debug(NES_DBG_MR, "one level pbl, root_vpbl.pbl_vbase=%p \n",
+                               nesfmr->root_vpbl.pbl_vbase);
+       }
+       /* two level pbl */
+       else {
+               nesfmr->root_vpbl.pbl_vbase = pci_alloc_consistent(nesdev->pcidev, 8192,
+                               &nesfmr->root_vpbl.pbl_pbase);
+               if (!nesfmr->root_vpbl.pbl_vbase) {
+                       spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
+                       ret = -ENOMEM;
+                       goto failed_vpbl_alloc;
+               }
+
+               nesfmr->root_vpbl.leaf_vpbl = kzalloc(sizeof(*nesfmr->root_vpbl.leaf_vpbl)*1024, GFP_KERNEL);
+               if (!nesfmr->root_vpbl.leaf_vpbl) {
+                       spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
+                       ret = -ENOMEM;
+                       goto failed_leaf_vpbl_alloc;
+               }
+
+               nesfmr->leaf_pbl_cnt = nesfmr->nesmr.pbls_used-1;
+               nes_debug(NES_DBG_MR, "two level pbl, root_vpbl.pbl_vbase=%p"
+                               " leaf_pbl_cnt=%d root_vpbl.leaf_vpbl=%p\n",
+                               nesfmr->root_vpbl.pbl_vbase, nesfmr->leaf_pbl_cnt, nesfmr->root_vpbl.leaf_vpbl);
+
+               for (i=0; i<nesfmr->leaf_pbl_cnt; i++)
+                       nesfmr->root_vpbl.leaf_vpbl[i].pbl_vbase = NULL;
+
+               for (i=0; i<nesfmr->leaf_pbl_cnt; i++) {
+                       vpbl.pbl_vbase = pci_alloc_consistent(nesdev->pcidev, 4096,
+                                       &vpbl.pbl_pbase);
+
+                       if (!vpbl.pbl_vbase) {
+                               ret = -ENOMEM;
+                               spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
+                               goto failed_leaf_vpbl_pages_alloc;
+                       }
+
+                       nesfmr->root_vpbl.pbl_vbase[i].pa_low = cpu_to_le32((u32)vpbl.pbl_pbase);
+                       nesfmr->root_vpbl.pbl_vbase[i].pa_high = cpu_to_le32((u32)((((u64)vpbl.pbl_pbase)>>32)));
+                       nesfmr->root_vpbl.leaf_vpbl[i] = vpbl;
+
+                       nes_debug(NES_DBG_MR, "pbase_low=0x%x, pbase_high=0x%x, vpbl=%p\n",
+                                       nesfmr->root_vpbl.pbl_vbase[i].pa_low,
+                                       nesfmr->root_vpbl.pbl_vbase[i].pa_high,
+                                       &nesfmr->root_vpbl.leaf_vpbl[i]);
+               }
+       }
+       nesfmr->ib_qp = NULL;
+       nesfmr->access_rights =0;
+
+       stag = stag_index << 8;
+       stag |= driver_key;
+       stag += (u32)stag_key;
+
+       spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
+       cqp_request = nes_get_cqp_request(nesdev);
+       if (cqp_request == NULL) {
+               nes_debug(NES_DBG_MR, "Failed to get a cqp_request.\n");
+               ret = -ENOMEM;
+               goto failed_leaf_vpbl_pages_alloc;
+       }
+       cqp_request->waiting = 1;
+       cqp_wqe = &cqp_request->cqp_wqe;
+
+       nes_debug(NES_DBG_MR, "Registering STag 0x%08X, index = 0x%08X\n",
+                       stag, stag_index);
+
+       opcode = NES_CQP_ALLOCATE_STAG | NES_CQP_STAG_VA_TO | NES_CQP_STAG_MR;
+
+       if (nesfmr->nesmr.pbl_4k == 1)
+               opcode |= NES_CQP_STAG_PBL_BLK_SIZE;
+
+       if (ibmr_access_flags & IB_ACCESS_REMOTE_WRITE) {
+               opcode |= NES_CQP_STAG_RIGHTS_REMOTE_WRITE |
+                               NES_CQP_STAG_RIGHTS_LOCAL_WRITE | NES_CQP_STAG_REM_ACC_EN;
+               nesfmr->access_rights |=
+                               NES_CQP_STAG_RIGHTS_REMOTE_WRITE | NES_CQP_STAG_RIGHTS_LOCAL_WRITE |
+                               NES_CQP_STAG_REM_ACC_EN;
+       }
+
+       if (ibmr_access_flags & IB_ACCESS_REMOTE_READ) {
+               opcode |= NES_CQP_STAG_RIGHTS_REMOTE_READ |
+                               NES_CQP_STAG_RIGHTS_LOCAL_READ | NES_CQP_STAG_REM_ACC_EN;
+               nesfmr->access_rights |=
+                               NES_CQP_STAG_RIGHTS_REMOTE_READ | NES_CQP_STAG_RIGHTS_LOCAL_READ |
+                               NES_CQP_STAG_REM_ACC_EN;
+       }
+
+       nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
+       set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_OPCODE_IDX, opcode);
+       set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_STAG_WQE_LEN_HIGH_PD_IDX, (nespd->pd_id & 0x00007fff));
+       set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_STAG_WQE_STAG_IDX, stag);
+
+       cqp_wqe->wqe_words[NES_CQP_STAG_WQE_PBL_BLK_COUNT_IDX] =
+                       cpu_to_le32((nesfmr->nesmr.pbls_used>1) ?
+                       (nesfmr->nesmr.pbls_used-1) : nesfmr->nesmr.pbls_used);
+
+       atomic_set(&cqp_request->refcount, 2);
+       nes_post_cqp_request(nesdev, cqp_request, NES_CQP_REQUEST_RING_DOORBELL);
+
+       /* Wait for CQP */
+       ret = wait_event_timeout(cqp_request->waitq, (cqp_request->request_done != 0),
+                       NES_EVENT_TIMEOUT);
+       nes_debug(NES_DBG_MR, "Register STag 0x%08X completed, wait_event_timeout ret = %u,"
+                       " CQP Major:Minor codes = 0x%04X:0x%04X.\n",
+                       stag, ret, cqp_request->major_code, cqp_request->minor_code);
+
+       if ((!ret) || (cqp_request->major_code)) {
+               if (atomic_dec_and_test(&cqp_request->refcount)) {
+                       if (cqp_request->dynamic) {
+                               kfree(cqp_request);
+                       } else {
+                               spin_lock_irqsave(&nesdev->cqp.lock, flags);
+                               list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs);
+                               spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+                       }
+               }
+               ret = (!ret) ? -ETIME : -EIO;
+               goto failed_leaf_vpbl_pages_alloc;
+       } else {
+               if (atomic_dec_and_test(&cqp_request->refcount)) {
+                       if (cqp_request->dynamic) {
+                               kfree(cqp_request);
+                       } else {
+                               spin_lock_irqsave(&nesdev->cqp.lock, flags);
+                               list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs);
+                               spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+                       }
+               }
+       }
+
+       nesfmr->nesmr.ibfmr.lkey = stag;
+       nesfmr->nesmr.ibfmr.rkey = stag;
+       nesfmr->attr = *ibfmr_attr;
+
+       return &nesfmr->nesmr.ibfmr;
+
+       failed_leaf_vpbl_pages_alloc:
+       /* unroll all allocated pages */
+       for (i=0; i<nesfmr->leaf_pbl_cnt; i++) {
+               if (nesfmr->root_vpbl.leaf_vpbl[i].pbl_vbase) {
+                       pci_free_consistent(nesdev->pcidev, 4096, nesfmr->root_vpbl.leaf_vpbl[i].pbl_vbase,
+                                       nesfmr->root_vpbl.leaf_vpbl[i].pbl_pbase);
+               }
+       }
+       if (nesfmr->root_vpbl.leaf_vpbl)
+               kfree(nesfmr->root_vpbl.leaf_vpbl);
+
+       failed_leaf_vpbl_alloc:
+       if (nesfmr->leaf_pbl_cnt == 0) {
+               if (nesfmr->root_vpbl.pbl_vbase)
+                       pci_free_consistent(nesdev->pcidev, 4096, nesfmr->root_vpbl.pbl_vbase,
+                                       nesfmr->root_vpbl.pbl_pbase);
+       } else
+               pci_free_consistent(nesdev->pcidev, 8192, nesfmr->root_vpbl.pbl_vbase,
+                               nesfmr->root_vpbl.pbl_pbase);
+
+       failed_vpbl_alloc:
+       kfree(nesfmr);
+
+       failed_fmr_alloc:
+       nes_free_resource(nesadapter, nesadapter->allocated_mrs, stag_index);
+
+       failed_resource_alloc:
+       return ERR_PTR(ret);
+}
+
+
+/**
+ * nes_dealloc_fmr
+ */
+static int nes_dealloc_fmr(struct ib_fmr *ibfmr)
+{
+       struct nes_mr *nesmr = to_nesmr_from_ibfmr(ibfmr);
+       struct nes_fmr *nesfmr = to_nesfmr(nesmr);
+       struct nes_vnic *nesvnic = to_nesvnic(ibfmr->device);
+       struct nes_device *nesdev = nesvnic->nesdev;
+       struct nes_mr temp_nesmr = *nesmr;
+       int i = 0;
+
+       temp_nesmr.ibmw.device = ibfmr->device;
+       temp_nesmr.ibmw.pd = ibfmr->pd;
+       temp_nesmr.ibmw.rkey = ibfmr->rkey;
+       temp_nesmr.ibmw.uobject = NULL;
+
+       /* free the resources */
+       if (nesfmr->leaf_pbl_cnt == 0) {
+               /* single PBL case */
+               if (nesfmr->root_vpbl.pbl_vbase)
+                       pci_free_consistent(nesdev->pcidev, 4096, nesfmr->root_vpbl.pbl_vbase,
+                                       nesfmr->root_vpbl.pbl_pbase);
+       } else {
+               for (i = 0; i < nesfmr->leaf_pbl_cnt; i++) {
+                       pci_free_consistent(nesdev->pcidev, 4096, nesfmr->root_vpbl.leaf_vpbl[i].pbl_vbase,
+                                       nesfmr->root_vpbl.leaf_vpbl[i].pbl_pbase);
+               }
+               kfree(nesfmr->root_vpbl.leaf_vpbl);
+               pci_free_consistent(nesdev->pcidev, 8192, nesfmr->root_vpbl.pbl_vbase,
+                               nesfmr->root_vpbl.pbl_pbase);
+       }
+
+       return nes_dealloc_mw(&temp_nesmr.ibmw);
+}
+
+
+/**
+ * nes_map_phys_fmr
+ */
+static int nes_map_phys_fmr(struct ib_fmr *ibfmr, u64 *page_list,
+               int list_len, u64 iova)
+{
+       return 0;
+}
+
+
+/**
+ * nes_unmap_frm
+ */
+static int nes_unmap_fmr(struct list_head *ibfmr_list)
+{
+       return 0;
+}
+
+
+
+/**
+ * nes_query_device
+ */
+static int nes_query_device(struct ib_device *ibdev, struct ib_device_attr *props)
+{
+       struct nes_vnic *nesvnic = to_nesvnic(ibdev);
+       struct nes_device *nesdev = nesvnic->nesdev;
+       struct nes_ib_device *nesibdev = nesvnic->nesibdev;
+
+       memset(props, 0, sizeof(*props));
+       memcpy(&props->sys_image_guid, nesvnic->netdev->dev_addr, 6);
+
+       props->fw_ver = nesdev->nesadapter->fw_ver;
+       props->device_cap_flags = nesdev->nesadapter->device_cap_flags;
+       props->vendor_id = nesdev->nesadapter->vendor_id;
+       props->vendor_part_id = nesdev->nesadapter->vendor_part_id;
+       props->hw_ver = nesdev->nesadapter->hw_rev;
+       props->max_mr_size = 0x80000000;
+       props->max_qp = nesibdev->max_qp;
+       props->max_qp_wr = nesdev->nesadapter->max_qp_wr - 2;
+       props->max_sge = nesdev->nesadapter->max_sge;
+       props->max_cq = nesibdev->max_cq;
+       props->max_cqe = nesdev->nesadapter->max_cqe - 1;
+       props->max_mr = nesibdev->max_mr;
+       props->max_mw = nesibdev->max_mr;
+       props->max_pd = nesibdev->max_pd;
+       props->max_sge_rd = 1;
+       switch (nesdev->nesadapter->max_irrq_wr) {
+               case 0:
+                       props->max_qp_rd_atom = 1;
+                       break;
+               case 1:
+                       props->max_qp_rd_atom = 4;
+                       break;
+               case 2:
+                       props->max_qp_rd_atom = 16;
+                       break;
+               case 3:
+                       props->max_qp_rd_atom = 32;
+                       break;
+               default:
+                       props->max_qp_rd_atom = 0;
+       }
+       props->max_qp_init_rd_atom = props->max_qp_wr;
+       props->atomic_cap = IB_ATOMIC_NONE;
+       props->max_map_per_fmr = 1;
+
+       return 0;
+}
+
+
+/**
+ * nes_query_port
+ */
+static int nes_query_port(struct ib_device *ibdev, u8 port, struct ib_port_attr *props)
+{
+       memset(props, 0, sizeof(*props));
+
+       props->max_mtu = IB_MTU_2048;
+       props->active_mtu = IB_MTU_2048;
+       props->lid = 1;
+       props->lmc = 0;
+       props->sm_lid = 0;
+       props->sm_sl = 0;
+       props->state = IB_PORT_ACTIVE;
+       props->phys_state = 0;
+       props->port_cap_flags = IB_PORT_CM_SUP | IB_PORT_REINIT_SUP |
+                       IB_PORT_VENDOR_CLASS_SUP | IB_PORT_BOOT_MGMT_SUP;
+       props->gid_tbl_len = 1;
+       props->pkey_tbl_len = 1;
+       props->qkey_viol_cntr = 0;
+       props->active_width = IB_WIDTH_4X;
+       props->active_speed = 1;
+       props->max_msg_sz = 0x80000000;
+
+       return 0;
+}
+
+
+/**
+ * nes_modify_port
+ */
+static int nes_modify_port(struct ib_device *ibdev, u8 port,
+               int port_modify_mask, struct ib_port_modify *props)
+{
+       return 0;
+}
+
+
+/**
+ * nes_query_pkey
+ */
+static int nes_query_pkey(struct ib_device *ibdev, u8 port, u16 index, u16 *pkey)
+{
+       *pkey = 0;
+       return 0;
+}
+
+
+/**
+ * nes_query_gid
+ */
+static int nes_query_gid(struct ib_device *ibdev, u8 port,
+               int index, union ib_gid *gid)
+{
+       struct nes_vnic *nesvnic = to_nesvnic(ibdev);
+
+       memset(&(gid->raw[0]), 0, sizeof(gid->raw));
+       memcpy(&(gid->raw[0]), nesvnic->netdev->dev_addr, 6);
+
+       return 0;
+}
+
+
+/**
+ * nes_alloc_ucontext - Allocate the user context data structure. This keeps track
+ * of all objects associated with a particular user-mode client.
+ */
+static struct ib_ucontext *nes_alloc_ucontext(struct ib_device *ibdev,
+               struct ib_udata *udata)
+{
+       struct nes_vnic *nesvnic = to_nesvnic(ibdev);
+       struct nes_device *nesdev = nesvnic->nesdev;
+       struct nes_adapter *nesadapter = nesdev->nesadapter;
+       struct nes_alloc_ucontext_req req;
+       struct nes_alloc_ucontext_resp uresp;
+       struct nes_ucontext *nes_ucontext;
+       struct nes_ib_device *nesibdev = nesvnic->nesibdev;
+
+
+       if (ib_copy_from_udata(&req, udata, sizeof(struct nes_alloc_ucontext_req))) {
+               printk(KERN_ERR PFX "Invalid structure size on allocate user context.\n");
+               return ERR_PTR(-EINVAL);
+       }
+
+       if (req.userspace_ver != NES_ABI_USERSPACE_VER) {
+               printk(KERN_ERR PFX "Invalid userspace driver version detected. Detected version %d, should be %d\n",
+                       req.userspace_ver, NES_ABI_USERSPACE_VER);
+               return ERR_PTR(-EINVAL);
+       }
+
+
+       memset(&uresp, 0, sizeof uresp);
+
+       uresp.max_qps = nesibdev->max_qp;
+       uresp.max_pds = nesibdev->max_pd;
+       uresp.wq_size = nesdev->nesadapter->max_qp_wr * 2;
+       uresp.virtwq = nesadapter->virtwq;
+       uresp.kernel_ver = NES_ABI_KERNEL_VER;
+
+       nes_ucontext = kzalloc(sizeof *nes_ucontext, GFP_KERNEL);
+       if (!nes_ucontext)
+               return ERR_PTR(-ENOMEM);
+
+       nes_ucontext->nesdev = nesdev;
+       nes_ucontext->mmap_wq_offset = uresp.max_pds;
+       nes_ucontext->mmap_cq_offset = nes_ucontext->mmap_wq_offset +
+                       ((sizeof(struct nes_hw_qp_wqe) * uresp.max_qps * 2) + PAGE_SIZE-1) /
+                       PAGE_SIZE;
+
+
+       if (ib_copy_to_udata(udata, &uresp, sizeof uresp)) {
+               kfree(nes_ucontext);
+               return ERR_PTR(-EFAULT);
+       }
+
+       INIT_LIST_HEAD(&nes_ucontext->cq_reg_mem_list);
+       INIT_LIST_HEAD(&nes_ucontext->qp_reg_mem_list);
+       atomic_set(&nes_ucontext->usecnt, 1);
+       return &nes_ucontext->ibucontext;
+}
+
+
+/**
+ * nes_dealloc_ucontext
+ */
+static int nes_dealloc_ucontext(struct ib_ucontext *context)
+{
+       /* struct nes_vnic *nesvnic = to_nesvnic(context->device); */
+       /* struct nes_device *nesdev = nesvnic->nesdev; */
+       struct nes_ucontext *nes_ucontext = to_nesucontext(context);
+
+       if (!atomic_dec_and_test(&nes_ucontext->usecnt))
+         return 0;
+       kfree(nes_ucontext);
+       return 0;
+}
+
+
+/**
+ * nes_mmap
+ */
+static int nes_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
+{
+       unsigned long index;
+       struct nes_vnic *nesvnic = to_nesvnic(context->device);
+       struct nes_device *nesdev = nesvnic->nesdev;
+       /* struct nes_adapter *nesadapter = nesdev->nesadapter; */
+       struct nes_ucontext *nes_ucontext;
+       struct nes_qp *nesqp;
+
+       nes_ucontext = to_nesucontext(context);
+
+
+       if (vma->vm_pgoff >= nes_ucontext->mmap_wq_offset) {
+               index = (vma->vm_pgoff - nes_ucontext->mmap_wq_offset) * PAGE_SIZE;
+               index /= ((sizeof(struct nes_hw_qp_wqe) * nesdev->nesadapter->max_qp_wr * 2) +
+                               PAGE_SIZE-1) & (~(PAGE_SIZE-1));
+               if (!test_bit(index, nes_ucontext->allocated_wqs)) {
+                       nes_debug(NES_DBG_MMAP, "wq %lu not allocated\n", index);
+                       return -EFAULT;
+               }
+               nesqp = nes_ucontext->mmap_nesqp[index];
+               if (nesqp == NULL) {
+                       nes_debug(NES_DBG_MMAP, "wq %lu has a NULL QP base.\n", index);
+                       return -EFAULT;
+               }
+               if (remap_pfn_range(vma, vma->vm_start,
+                               virt_to_phys(nesqp->hwqp.sq_vbase) >> PAGE_SHIFT,
+                               vma->vm_end - vma->vm_start,
+                               vma->vm_page_prot)) {
+                       nes_debug(NES_DBG_MMAP, "remap_pfn_range failed.\n");
+                       return -EAGAIN;
+               }
+               vma->vm_private_data = nesqp;
+               return 0;
+       } else {
+               index = vma->vm_pgoff;
+               if (!test_bit(index, nes_ucontext->allocated_doorbells))
+                       return -EFAULT;
+
+               vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+               if (io_remap_pfn_range(vma, vma->vm_start,
+                               (nesdev->doorbell_start +
+                               ((nes_ucontext->mmap_db_index[index] - nesdev->base_doorbell_index) * 4096))
+                               >> PAGE_SHIFT, PAGE_SIZE, vma->vm_page_prot))
+                       return -EAGAIN;
+               vma->vm_private_data = nes_ucontext;
+               return 0;
+       }
+
+       return -ENOSYS;
+}
+
+
+/**
+ * nes_alloc_pd
+ */
+static struct ib_pd *nes_alloc_pd(struct ib_device *ibdev,
+               struct ib_ucontext *context, struct ib_udata *udata)
+{
+       struct nes_pd *nespd;
+       struct nes_vnic *nesvnic = to_nesvnic(ibdev);
+       struct nes_device *nesdev = nesvnic->nesdev;
+       struct nes_adapter *nesadapter = nesdev->nesadapter;
+       struct nes_ucontext *nesucontext;
+       struct nes_alloc_pd_resp uresp;
+       u32 pd_num = 0;
+       int err;
+
+       nes_debug(NES_DBG_PD, "nesvnic=%p, netdev=%p %s, ibdev=%p, context=%p, netdev refcnt=%u\n",
+                       nesvnic, nesdev->netdev[0], nesdev->netdev[0]->name, ibdev, context,
+                       atomic_read(&nesvnic->netdev->refcnt));
+
+       err = nes_alloc_resource(nesadapter, nesadapter->allocated_pds,
+                       nesadapter->max_pd, &pd_num, &nesadapter->next_pd);
+       if (err) {
+               return ERR_PTR(err);
+       }
+
+       nespd = kzalloc(sizeof (struct nes_pd), GFP_KERNEL);
+       if (!nespd) {
+               nes_free_resource(nesadapter, nesadapter->allocated_pds, pd_num);
+               return ERR_PTR(-ENOMEM);
+       }
+
+       nes_debug(NES_DBG_PD, "Allocating PD (%p) for ib device %s\n",
+                       nespd, nesvnic->nesibdev->ibdev.name);
+
+       nespd->pd_id = (pd_num << (PAGE_SHIFT-12)) + nesadapter->base_pd;
+
+       if (context) {
+               nesucontext = to_nesucontext(context);
+               nespd->mmap_db_index = find_next_zero_bit(nesucontext->allocated_doorbells,
+                               NES_MAX_USER_DB_REGIONS, nesucontext->first_free_db);
+               nes_debug(NES_DBG_PD, "find_first_zero_biton doorbells returned %u, mapping pd_id %u.\n",
+                               nespd->mmap_db_index, nespd->pd_id);
+               if (nespd->mmap_db_index > NES_MAX_USER_DB_REGIONS) {
+                       nes_debug(NES_DBG_PD, "mmap_db_index > MAX\n");
+                       nes_free_resource(nesadapter, nesadapter->allocated_pds, pd_num);
+                       kfree(nespd);
+                       return ERR_PTR(-ENOMEM);
+               }
+
+               uresp.pd_id = nespd->pd_id;
+               uresp.mmap_db_index = nespd->mmap_db_index;
+               if (ib_copy_to_udata(udata, &uresp, sizeof (struct nes_alloc_pd_resp))) {
+                       nes_free_resource(nesadapter, nesadapter->allocated_pds, pd_num);
+                       kfree(nespd);
+                       return ERR_PTR(-EFAULT);
+               }
+
+               set_bit(nespd->mmap_db_index, nesucontext->allocated_doorbells);
+               nesucontext->mmap_db_index[nespd->mmap_db_index] = nespd->pd_id;
+               nesucontext->first_free_db = nespd->mmap_db_index + 1;
+       }
+
+       nes_debug(NES_DBG_PD, "PD%u structure located @%p.\n", nespd->pd_id, nespd);
+       return &nespd->ibpd;
+}
+
+
+/**
+ * nes_dealloc_pd
+ */
+static int nes_dealloc_pd(struct ib_pd *ibpd)
+{
+       struct nes_ucontext *nesucontext;
+       struct nes_pd *nespd = to_nespd(ibpd);
+       struct nes_vnic *nesvnic = to_nesvnic(ibpd->device);
+       struct nes_device *nesdev = nesvnic->nesdev;
+       struct nes_adapter *nesadapter = nesdev->nesadapter;
+
+       if ((ibpd->uobject) && (ibpd->uobject->context)) {
+               nesucontext = to_nesucontext(ibpd->uobject->context);
+               nes_debug(NES_DBG_PD, "Clearing bit %u from allocated doorbells\n",
+                               nespd->mmap_db_index);
+               clear_bit(nespd->mmap_db_index, nesucontext->allocated_doorbells);
+               nesucontext->mmap_db_index[nespd->mmap_db_index] = 0;
+               if (nesucontext->first_free_db > nespd->mmap_db_index) {
+                       nesucontext->first_free_db = nespd->mmap_db_index;
+               }
+       }
+
+       nes_debug(NES_DBG_PD, "Deallocating PD%u structure located @%p.\n",
+                       nespd->pd_id, nespd);
+       nes_free_resource(nesadapter, nesadapter->allocated_pds,
+                       (nespd->pd_id-nesadapter->base_pd)>>(PAGE_SHIFT-12));
+       kfree(nespd);
+
+       return 0;
+}
+
+
+/**
+ * nes_create_ah
+ */
+static struct ib_ah *nes_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr)
+{
+       return ERR_PTR(-ENOSYS);
+}
+
+
+/**
+ * nes_destroy_ah
+ */
+static int nes_destroy_ah(struct ib_ah *ah)
+{
+       return -ENOSYS;
+}
+
+
+/**
+ * nes_get_encoded_size
+ */
+static inline u8 nes_get_encoded_size(int *size)
+{
+       u8 encoded_size = 0;
+       if (*size <= 32) {
+               *size = 32;
+               encoded_size = 1;
+       } else if (*size <= 128) {
+               *size = 128;
+               encoded_size = 2;
+       } else if (*size <= 512) {
+               *size = 512;
+               encoded_size = 3;
+       }
+       return (encoded_size);
+}
+
+
+
+/**
+ * nes_setup_virt_qp
+ */
+static int nes_setup_virt_qp(struct nes_qp *nesqp, struct nes_pbl *nespbl,
+               struct nes_vnic *nesvnic, int sq_size, int rq_size)
+{
+       unsigned long flags;
+       void *mem;
+       __le64 *pbl = NULL;
+       __le64 *tpbl;
+       __le64 *pblbuffer;
+       struct nes_device *nesdev = nesvnic->nesdev;
+       struct nes_adapter *nesadapter = nesdev->nesadapter;
+       u32 pbl_entries;
+       u8 rq_pbl_entries;
+       u8 sq_pbl_entries;
+
+       pbl_entries = nespbl->pbl_size >> 3;
+       nes_debug(NES_DBG_QP, "Userspace PBL, pbl_size=%u, pbl_entries = %d pbl_vbase=%p, pbl_pbase=%p\n",
+                       nespbl->pbl_size, pbl_entries,
+                       (void *)nespbl->pbl_vbase,
+                       (void *)nespbl->pbl_pbase);
+       pbl = (__le64 *) nespbl->pbl_vbase; /* points to first pbl entry */
+       /* now lets set the sq_vbase as well as rq_vbase addrs we will assign */
+       /* the first pbl to be fro the rq_vbase... */
+       rq_pbl_entries = (rq_size * sizeof(struct nes_hw_qp_wqe)) >> 12;
+       sq_pbl_entries = (sq_size * sizeof(struct nes_hw_qp_wqe)) >> 12;
+       nesqp->hwqp.sq_pbase = (le32_to_cpu(((__le32 *)pbl)[0])) | ((u64)((le32_to_cpu(((__le32 *)pbl)[1]))) << 32);
+       if (!nespbl->page) {
+               nes_debug(NES_DBG_QP, "QP nespbl->page is NULL \n");
+               kfree(nespbl);
+               return -ENOMEM;
+       }
+
+       nesqp->hwqp.sq_vbase = kmap(nespbl->page);
+       nesqp->page = nespbl->page;
+       if (!nesqp->hwqp.sq_vbase) {
+               nes_debug(NES_DBG_QP, "QP sq_vbase kmap failed\n");
+               kfree(nespbl);
+               return -ENOMEM;
+       }
+
+       /* Now to get to sq.. we need to calculate how many */
+       /* PBL entries were used by the rq.. */
+       pbl += sq_pbl_entries;
+       nesqp->hwqp.rq_pbase = (le32_to_cpu(((__le32 *)pbl)[0])) | ((u64)((le32_to_cpu(((__le32 *)pbl)[1]))) << 32);
+       /* nesqp->hwqp.rq_vbase = bus_to_virt(*pbl); */
+       /*nesqp->hwqp.rq_vbase = phys_to_virt(*pbl); */
+
+       nes_debug(NES_DBG_QP, "QP sq_vbase= %p sq_pbase=%p rq_vbase=%p rq_pbase=%p\n",
+                       nesqp->hwqp.sq_vbase, (void *)nesqp->hwqp.sq_pbase,
+                       nesqp->hwqp.rq_vbase, (void *)nesqp->hwqp.rq_pbase);
+       spin_lock_irqsave(&nesadapter->pbl_lock, flags);
+       if (!nesadapter->free_256pbl) {
+               pci_free_consistent(nesdev->pcidev, nespbl->pbl_size, nespbl->pbl_vbase,
+                               nespbl->pbl_pbase);
+               spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
+               kunmap(nesqp->page);
+               kfree(nespbl);
+               return -ENOMEM;
+       }
+       nesadapter->free_256pbl--;
+       spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
+
+       nesqp->pbl_vbase = pci_alloc_consistent(nesdev->pcidev, 256, &nesqp->pbl_pbase);
+       pblbuffer = nesqp->pbl_vbase;
+       if (!nesqp->pbl_vbase) {
+               /* memory allocated during nes_reg_user_mr() */
+               pci_free_consistent(nesdev->pcidev, nespbl->pbl_size, nespbl->pbl_vbase,
+                                   nespbl->pbl_pbase);
+               kfree(nespbl);
+               spin_lock_irqsave(&nesadapter->pbl_lock, flags);
+               nesadapter->free_256pbl++;
+               spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
+               kunmap(nesqp->page);
+               return -ENOMEM;
+       }
+       memset(nesqp->pbl_vbase, 0, 256);
+       /* fill in the page address in the pbl buffer.. */
+       tpbl = pblbuffer + 16;
+       pbl = (__le64 *)nespbl->pbl_vbase;
+       while (sq_pbl_entries--)
+               *tpbl++ = *pbl++;
+       tpbl = pblbuffer;
+       while (rq_pbl_entries--)
+               *tpbl++ = *pbl++;
+
+       /* done with memory allocated during nes_reg_user_mr() */
+       pci_free_consistent(nesdev->pcidev, nespbl->pbl_size, nespbl->pbl_vbase,
+                           nespbl->pbl_pbase);
+       kfree(nespbl);
+
+       nesqp->qp_mem_size =
+                       max((u32)sizeof(struct nes_qp_context), ((u32)256)) + 256;     /* this is Q2 */
+       /* Round up to a multiple of a page */
+       nesqp->qp_mem_size += PAGE_SIZE - 1;
+       nesqp->qp_mem_size &= ~(PAGE_SIZE - 1);
+
+       mem = pci_alloc_consistent(nesdev->pcidev, nesqp->qp_mem_size,
+                       &nesqp->hwqp.q2_pbase);
+
+       if (!mem) {
+               pci_free_consistent(nesdev->pcidev, 256, nesqp->pbl_vbase, nesqp->pbl_pbase);
+               nesqp->pbl_vbase = NULL;
+               spin_lock_irqsave(&nesadapter->pbl_lock, flags);
+               nesadapter->free_256pbl++;
+               spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
+               kunmap(nesqp->page);
+               return -ENOMEM;
+       }
+       nesqp->hwqp.q2_vbase = mem;
+       mem += 256;
+       memset(nesqp->hwqp.q2_vbase, 0, 256);
+       nesqp->nesqp_context = mem;
+       memset(nesqp->nesqp_context, 0, sizeof(*nesqp->nesqp_context));
+       nesqp->nesqp_context_pbase = nesqp->hwqp.q2_pbase + 256;
+
+       return 0;
+}
+
+
+/**
+ * nes_setup_mmap_qp
+ */
+static int nes_setup_mmap_qp(struct nes_qp *nesqp, struct nes_vnic *nesvnic,
+               int sq_size, int rq_size)
+{
+       void *mem;
+       struct nes_device *nesdev = nesvnic->nesdev;
+
+       nesqp->qp_mem_size = (sizeof(struct nes_hw_qp_wqe) * sq_size) +
+                       (sizeof(struct nes_hw_qp_wqe) * rq_size) +
+                       max((u32)sizeof(struct nes_qp_context), ((u32)256)) +
+                       256; /* this is Q2 */
+       /* Round up to a multiple of a page */
+       nesqp->qp_mem_size += PAGE_SIZE - 1;
+       nesqp->qp_mem_size &= ~(PAGE_SIZE - 1);
+
+       mem = pci_alloc_consistent(nesdev->pcidev, nesqp->qp_mem_size,
+                       &nesqp->hwqp.sq_pbase);
+       if (!mem)
+               return -ENOMEM;
+       nes_debug(NES_DBG_QP, "PCI consistent memory for "
+                       "host descriptor rings located @ %p (pa = 0x%08lX.) size = %u.\n",
+                       mem, (unsigned long)nesqp->hwqp.sq_pbase, nesqp->qp_mem_size);
+
+       memset(mem, 0, nesqp->qp_mem_size);
+
+       nesqp->hwqp.sq_vbase = mem;
+       mem += sizeof(struct nes_hw_qp_wqe) * sq_size;
+
+       nesqp->hwqp.rq_vbase = mem;
+       nesqp->hwqp.rq_pbase = nesqp->hwqp.sq_pbase +
+                       sizeof(struct nes_hw_qp_wqe) * sq_size;
+       mem += sizeof(struct nes_hw_qp_wqe) * rq_size;
+
+       nesqp->hwqp.q2_vbase = mem;
+       nesqp->hwqp.q2_pbase = nesqp->hwqp.rq_pbase +
+                       sizeof(struct nes_hw_qp_wqe) * rq_size;
+       mem += 256;
+       memset(nesqp->hwqp.q2_vbase, 0, 256);
+
+       nesqp->nesqp_context = mem;
+       nesqp->nesqp_context_pbase = nesqp->hwqp.q2_pbase + 256;
+       memset(nesqp->nesqp_context, 0, sizeof(*nesqp->nesqp_context));
+       return 0;
+}
+
+
+/**
+ * nes_free_qp_mem() is to free up the qp's pci_alloc_consistent() memory.
+ */
+static inline void nes_free_qp_mem(struct nes_device *nesdev,
+               struct nes_qp *nesqp, int virt_wqs)
+{
+       unsigned long flags;
+       struct nes_adapter *nesadapter = nesdev->nesadapter;
+       if (!virt_wqs) {
+               pci_free_consistent(nesdev->pcidev, nesqp->qp_mem_size,
+                               nesqp->hwqp.sq_vbase, nesqp->hwqp.sq_pbase);
+       }else {
+               spin_lock_irqsave(&nesadapter->pbl_lock, flags);
+               nesadapter->free_256pbl++;
+               spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
+               pci_free_consistent(nesdev->pcidev, nesqp->qp_mem_size, nesqp->hwqp.q2_vbase, nesqp->hwqp.q2_pbase);
+               pci_free_consistent(nesdev->pcidev, 256, nesqp->pbl_vbase, nesqp->pbl_pbase );
+               nesqp->pbl_vbase = NULL;
+               kunmap(nesqp->page);
+       }
+}
+
+
+/**
+ * nes_create_qp
+ */
+static struct ib_qp *nes_create_qp(struct ib_pd *ibpd,
+               struct ib_qp_init_attr *init_attr, struct ib_udata *udata)
+{
+       u64 u64temp= 0;
+       u64 u64nesqp = 0;
+       struct nes_pd *nespd = to_nespd(ibpd);
+       struct nes_vnic *nesvnic = to_nesvnic(ibpd->device);
+       struct nes_device *nesdev = nesvnic->nesdev;
+       struct nes_adapter *nesadapter = nesdev->nesadapter;
+       struct nes_qp *nesqp;
+       struct nes_cq *nescq;
+       struct nes_ucontext *nes_ucontext;
+       struct nes_hw_cqp_wqe *cqp_wqe;
+       struct nes_cqp_request *cqp_request;
+       struct nes_create_qp_req req;
+       struct nes_create_qp_resp uresp;
+       struct nes_pbl  *nespbl = NULL;
+       u32 qp_num = 0;
+       u32 opcode = 0;
+       /* u32 counter = 0; */
+       void *mem;
+       unsigned long flags;
+       int ret;
+       int err;
+       int virt_wqs = 0;
+       int sq_size;
+       int rq_size;
+       u8 sq_encoded_size;
+       u8 rq_encoded_size;
+       /* int counter; */
+
+       atomic_inc(&qps_created);
+       switch (init_attr->qp_type) {
+               case IB_QPT_RC:
+                       if (nes_drv_opt & NES_DRV_OPT_NO_INLINE_DATA) {
+                               init_attr->cap.max_inline_data = 0;
+                       } else {
+                               init_attr->cap.max_inline_data = 64;
+                       }
+                       sq_size = init_attr->cap.max_send_wr;
+                       rq_size = init_attr->cap.max_recv_wr;
+
+                       // check if the encoded sizes are OK or not...
+                       sq_encoded_size = nes_get_encoded_size(&sq_size);
+                       rq_encoded_size = nes_get_encoded_size(&rq_size);
+
+                       if ((!sq_encoded_size) || (!rq_encoded_size)) {
+                               nes_debug(NES_DBG_QP, "ERROR bad rq (%u) or sq (%u) size\n",
+                                               rq_size, sq_size);
+                               return ERR_PTR(-EINVAL);
+                       }
+
+                       init_attr->cap.max_send_wr = sq_size -2;
+                       init_attr->cap.max_recv_wr = rq_size -1;
+                       nes_debug(NES_DBG_QP, "RQ size=%u, SQ Size=%u\n", rq_size, sq_size);
+
+                       ret = nes_alloc_resource(nesadapter, nesadapter->allocated_qps,
+                                       nesadapter->max_qp, &qp_num, &nesadapter->next_qp);
+                       if (ret) {
+                               return ERR_PTR(ret);
+                       }
+
+                       /* Need 512 (actually now 1024) byte alignment on this structure */
+                       mem = kzalloc(sizeof(*nesqp)+NES_SW_CONTEXT_ALIGN-1, GFP_KERNEL);
+                       if (!mem) {
+                               nes_free_resource(nesadapter, nesadapter->allocated_qps, qp_num);
+                               nes_debug(NES_DBG_QP, "Unable to allocate QP\n");
+                               return ERR_PTR(-ENOMEM);
+                       }
+                       u64nesqp = (unsigned long)mem;
+                       u64nesqp += ((u64)NES_SW_CONTEXT_ALIGN) - 1;
+                       u64temp = ((u64)NES_SW_CONTEXT_ALIGN) - 1;
+                       u64nesqp &= ~u64temp;
+                       nesqp = (struct nes_qp *)(unsigned long)u64nesqp;
+                       /* nes_debug(NES_DBG_QP, "nesqp=%p, allocated buffer=%p.  Rounded to closest %u\n",
+                                       nesqp, mem, NES_SW_CONTEXT_ALIGN); */
+                       nesqp->allocated_buffer = mem;
+
+                       if (udata) {
+                               if (ib_copy_from_udata(&req, udata, sizeof(struct nes_create_qp_req))) {
+                                       nes_free_resource(nesadapter, nesadapter->allocated_qps, qp_num);
+                                       kfree(nesqp->allocated_buffer);
+                                       nes_debug(NES_DBG_QP, "ib_copy_from_udata() Failed \n");
+                                       return NULL;
+                               }
+                               if (req.user_wqe_buffers) {
+                                       virt_wqs = 1;
+                               }
+                               if ((ibpd->uobject) && (ibpd->uobject->context)) {
+                                       nesqp->user_mode = 1;
+                                       nes_ucontext = to_nesucontext(ibpd->uobject->context);
+                                       if (virt_wqs) {
+                                               err = 1;
+                                               list_for_each_entry(nespbl, &nes_ucontext->qp_reg_mem_list, list) {
+                                                       if (nespbl->user_base == (unsigned long )req.user_wqe_buffers) {
+                                                               list_del(&nespbl->list);
+                                                               err = 0;
+                                                               nes_debug(NES_DBG_QP, "Found PBL for virtual QP. nespbl=%p. user_base=0x%lx\n",
+                                                                         nespbl, nespbl->user_base);
+                                                               break;
+                                                       }
+                                               }
+                                               if (err) {
+                                                       nes_debug(NES_DBG_QP, "Didn't Find PBL for virtual QP. address = %llx.\n",
+                                                                 (long long unsigned int)req.user_wqe_buffers);
+                                                       nes_free_resource(nesadapter, nesadapter->allocated_qps, qp_num);
+                                                       kfree(nesqp->allocated_buffer);
+                                                       return ERR_PTR(-ENOMEM);
+                                               }
+                                       }
+
+                                       nes_ucontext = to_nesucontext(ibpd->uobject->context);
+                                       nesqp->mmap_sq_db_index =
+                                               find_next_zero_bit(nes_ucontext->allocated_wqs,
+                                                                  NES_MAX_USER_WQ_REGIONS, nes_ucontext->first_free_wq);
+                                       /* nes_debug(NES_DBG_QP, "find_first_zero_biton wqs returned %u\n",
+                                                       nespd->mmap_db_index); */
+                                       if (nesqp->mmap_sq_db_index > NES_MAX_USER_WQ_REGIONS) {
+                                               nes_debug(NES_DBG_QP,
+                                                         "db index > max user regions, failing create QP\n");
+                                               nes_free_resource(nesadapter, nesadapter->allocated_qps, qp_num);
+                                               if (virt_wqs) {
+                                                       pci_free_consistent(nesdev->pcidev, nespbl->pbl_size, nespbl->pbl_vbase,
+                                                                           nespbl->pbl_pbase);
+                                                       kfree(nespbl);
+                                               }
+                                               kfree(nesqp->allocated_buffer);
+                                               return ERR_PTR(-ENOMEM);
+                                       }
+                                       set_bit(nesqp->mmap_sq_db_index, nes_ucontext->allocated_wqs);
+                                       nes_ucontext->mmap_nesqp[nesqp->mmap_sq_db_index] = nesqp;
+                                       nes_ucontext->first_free_wq = nesqp->mmap_sq_db_index + 1;
+                               } else {
+                                       nes_free_resource(nesadapter, nesadapter->allocated_qps, qp_num);
+                                       kfree(nesqp->allocated_buffer);
+                                       return ERR_PTR(-EFAULT);
+                               }
+                       }
+                       err = (!virt_wqs) ? nes_setup_mmap_qp(nesqp, nesvnic, sq_size, rq_size) :
+                                       nes_setup_virt_qp(nesqp, nespbl, nesvnic, sq_size, rq_size);
+                       if (err) {
+                               nes_debug(NES_DBG_QP,
+                                         "error geting qp mem code = %d\n", err);
+                               nes_free_resource(nesadapter, nesadapter->allocated_qps, qp_num);
+                               kfree(nesqp->allocated_buffer);
+                               return ERR_PTR(-ENOMEM);
+                       }
+
+                       nesqp->hwqp.sq_size = sq_size;
+                       nesqp->hwqp.sq_encoded_size = sq_encoded_size;
+                       nesqp->hwqp.sq_head = 1;
+                       nesqp->hwqp.rq_size = rq_size;
+                       nesqp->hwqp.rq_encoded_size = rq_encoded_size;
+                       /* nes_debug(NES_DBG_QP, "nesqp->nesqp_context_pbase = %p\n",
+                                       (void *)nesqp->nesqp_context_pbase);
+                       */
+                       nesqp->hwqp.qp_id = qp_num;
+                       nesqp->ibqp.qp_num = nesqp->hwqp.qp_id;
+                       nesqp->nespd = nespd;
+
+                       nescq = to_nescq(init_attr->send_cq);
+                       nesqp->nesscq = nescq;
+                       nescq = to_nescq(init_attr->recv_cq);
+                       nesqp->nesrcq = nescq;
+
+                       nesqp->nesqp_context->misc |= cpu_to_le32((u32)PCI_FUNC(nesdev->pcidev->devfn) <<
+                                       NES_QPCONTEXT_MISC_PCI_FCN_SHIFT);
+                       nesqp->nesqp_context->misc |= cpu_to_le32((u32)nesqp->hwqp.rq_encoded_size <<
+                                       NES_QPCONTEXT_MISC_RQ_SIZE_SHIFT);
+                       nesqp->nesqp_context->misc |= cpu_to_le32((u32)nesqp->hwqp.sq_encoded_size <<
+                                       NES_QPCONTEXT_MISC_SQ_SIZE_SHIFT);
+                               nesqp->nesqp_context->misc |= cpu_to_le32(NES_QPCONTEXT_MISC_PRIV_EN);
+                               nesqp->nesqp_context->misc |= cpu_to_le32(NES_QPCONTEXT_MISC_FAST_REGISTER_EN);
+                       nesqp->nesqp_context->cqs = cpu_to_le32(nesqp->nesscq->hw_cq.cq_number +
+                                       ((u32)nesqp->nesrcq->hw_cq.cq_number << 16));
+                       u64temp = (u64)nesqp->hwqp.sq_pbase;
+                       nesqp->nesqp_context->sq_addr_low = cpu_to_le32((u32)u64temp);
+                       nesqp->nesqp_context->sq_addr_high = cpu_to_le32((u32)(u64temp >> 32));
+
+
+                       if (!virt_wqs) {
+                               u64temp = (u64)nesqp->hwqp.sq_pbase;
+                               nesqp->nesqp_context->sq_addr_low = cpu_to_le32((u32)u64temp);
+                               nesqp->nesqp_context->sq_addr_high = cpu_to_le32((u32)(u64temp >> 32));
+                               u64temp = (u64)nesqp->hwqp.rq_pbase;
+                               nesqp->nesqp_context->rq_addr_low = cpu_to_le32((u32)u64temp);
+                               nesqp->nesqp_context->rq_addr_high = cpu_to_le32((u32)(u64temp >> 32));
+                       } else {
+                               u64temp = (u64)nesqp->pbl_pbase;
+                               nesqp->nesqp_context->rq_addr_low = cpu_to_le32((u32)u64temp);
+                               nesqp->nesqp_context->rq_addr_high = cpu_to_le32((u32)(u64temp >> 32));
+                       }
+
+                       /* nes_debug(NES_DBG_QP, "next_qp_nic_index=%u, using nic_index=%d\n",
+                                       nesvnic->next_qp_nic_index,
+                                       nesvnic->qp_nic_index[nesvnic->next_qp_nic_index]); */
+                       spin_lock_irqsave(&nesdev->cqp.lock, flags);
+                       nesqp->nesqp_context->misc2 |= cpu_to_le32(
+                                       (u32)nesvnic->qp_nic_index[nesvnic->next_qp_nic_index] <<
+                                       NES_QPCONTEXT_MISC2_NIC_INDEX_SHIFT);
+                       nesvnic->next_qp_nic_index++;
+                       if ((nesvnic->next_qp_nic_index > 3) ||
+                                       (nesvnic->qp_nic_index[nesvnic->next_qp_nic_index] == 0xf)) {
+                               nesvnic->next_qp_nic_index = 0;
+                       }
+                       spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+
+                       nesqp->nesqp_context->pd_index_wscale |= cpu_to_le32((u32)nesqp->nespd->pd_id << 16);
+                       u64temp = (u64)nesqp->hwqp.q2_pbase;
+                       nesqp->nesqp_context->q2_addr_low = cpu_to_le32((u32)u64temp);
+                       nesqp->nesqp_context->q2_addr_high = cpu_to_le32((u32)(u64temp >> 32));
+                       nesqp->nesqp_context->aeq_token_low =  cpu_to_le32((u32)((unsigned long)(nesqp)));
+                       nesqp->nesqp_context->aeq_token_high =  cpu_to_le32((u32)(upper_32_bits((unsigned long)(nesqp))));
+                       nesqp->nesqp_context->ird_ord_sizes = cpu_to_le32(NES_QPCONTEXT_ORDIRD_ALSMM |
+                                       ((((u32)nesadapter->max_irrq_wr) <<
+                                       NES_QPCONTEXT_ORDIRD_IRDSIZE_SHIFT) & NES_QPCONTEXT_ORDIRD_IRDSIZE_MASK));
+                       if (disable_mpa_crc) {
+                               nes_debug(NES_DBG_QP, "Disabling MPA crc checking due to module option.\n");
+                               nesqp->nesqp_context->ird_ord_sizes |= cpu_to_le32(NES_QPCONTEXT_ORDIRD_RNMC);
+                       }
+
+
+                       /* Create the QP */
+                       cqp_request = nes_get_cqp_request(nesdev);
+                       if (cqp_request == NULL) {
+                               nes_debug(NES_DBG_QP, "Failed to get a cqp_request\n");
+                               nes_free_resource(nesadapter, nesadapter->allocated_qps, qp_num);
+                               nes_free_qp_mem(nesdev, nesqp,virt_wqs);
+                               kfree(nesqp->allocated_buffer);
+                               return ERR_PTR(-ENOMEM);
+                       }
+                       cqp_request->waiting = 1;
+                       cqp_wqe = &cqp_request->cqp_wqe;
+
+                       if (!virt_wqs) {
+                               opcode = NES_CQP_CREATE_QP | NES_CQP_QP_TYPE_IWARP |
+                                       NES_CQP_QP_IWARP_STATE_IDLE;
+                       } else {
+                               opcode = NES_CQP_CREATE_QP | NES_CQP_QP_TYPE_IWARP | NES_CQP_QP_VIRT_WQS |
+                                       NES_CQP_QP_IWARP_STATE_IDLE;
+                       }
+                       opcode |= NES_CQP_QP_CQS_VALID;
+                       nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
+                       set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_OPCODE_IDX, opcode);
+                       set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_ID_IDX, nesqp->hwqp.qp_id);
+
+                       u64temp = (u64)nesqp->nesqp_context_pbase;
+                       set_wqe_64bit_value(cqp_wqe->wqe_words, NES_CQP_QP_WQE_CONTEXT_LOW_IDX, u64temp);
+
+                       atomic_set(&cqp_request->refcount, 2);
+                       nes_post_cqp_request(nesdev, cqp_request, NES_CQP_REQUEST_RING_DOORBELL);
+
+                       /* Wait for CQP */
+                       nes_debug(NES_DBG_QP, "Waiting for create iWARP QP%u to complete.\n",
+                                       nesqp->hwqp.qp_id);
+                       ret = wait_event_timeout(cqp_request->waitq,
+                                       (cqp_request->request_done != 0), NES_EVENT_TIMEOUT);
+                       nes_debug(NES_DBG_QP, "Create iwarp QP%u completed, wait_event_timeout ret=%u,"
+                                       " nesdev->cqp_head = %u, nesdev->cqp.sq_tail = %u,"
+                                       " CQP Major:Minor codes = 0x%04X:0x%04X.\n",
+                                       nesqp->hwqp.qp_id, ret, nesdev->cqp.sq_head, nesdev->cqp.sq_tail,
+                                       cqp_request->major_code, cqp_request->minor_code);
+                       if ((!ret) || (cqp_request->major_code)) {
+                               if (atomic_dec_and_test(&cqp_request->refcount)) {
+                                       if (cqp_request->dynamic) {
+                                               kfree(cqp_request);
+                                       } else {
+                                               spin_lock_irqsave(&nesdev->cqp.lock, flags);
+                                               list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs);
+                                               spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+                                       }
+                               }
+                               nes_free_resource(nesadapter, nesadapter->allocated_qps, qp_num);
+                               nes_free_qp_mem(nesdev, nesqp,virt_wqs);
+                               kfree(nesqp->allocated_buffer);
+                               if (!ret) {
+                                       return ERR_PTR(-ETIME);
+                               } else {
+                                       return ERR_PTR(-EIO);
+                               }
+                       } else {
+                               if (atomic_dec_and_test(&cqp_request->refcount)) {
+                                       if (cqp_request->dynamic) {
+                                               kfree(cqp_request);
+                                       } else {
+                                               spin_lock_irqsave(&nesdev->cqp.lock, flags);
+                                               list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs);
+                                               spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+                                       }
+                               }
+                       }
+
+                       if (ibpd->uobject) {
+                               uresp.mmap_sq_db_index = nesqp->mmap_sq_db_index;
+                               uresp.actual_sq_size = sq_size;
+                               uresp.actual_rq_size = rq_size;
+                               uresp.qp_id = nesqp->hwqp.qp_id;
+                               uresp.nes_drv_opt = nes_drv_opt;
+                               if (ib_copy_to_udata(udata, &uresp, sizeof uresp)) {
+                                       nes_free_resource(nesadapter, nesadapter->allocated_qps, qp_num);
+                                       nes_free_qp_mem(nesdev, nesqp,virt_wqs);
+                                       kfree(nesqp->allocated_buffer);
+                                       return ERR_PTR(-EFAULT);
+                               }
+                       }
+
+                       nes_debug(NES_DBG_QP, "QP%u structure located @%p.Size = %u.\n",
+                                       nesqp->hwqp.qp_id, nesqp, (u32)sizeof(*nesqp));
+                       spin_lock_init(&nesqp->lock);
+                       init_waitqueue_head(&nesqp->state_waitq);
+                       init_waitqueue_head(&nesqp->kick_waitq);
+                       nes_add_ref(&nesqp->ibqp);
+                       break;
+               default:
+                       nes_debug(NES_DBG_QP, "Invalid QP type: %d\n", init_attr->qp_type);
+                       return ERR_PTR(-EINVAL);
+                       break;
+       }
+
+       /* update the QP table */
+       nesdev->nesadapter->qp_table[nesqp->hwqp.qp_id-NES_FIRST_QPN] = nesqp;
+       nes_debug(NES_DBG_QP, "netdev refcnt=%u\n",
+                       atomic_read(&nesvnic->netdev->refcnt));
+
+       return &nesqp->ibqp;
+}
+
+
+/**
+ * nes_destroy_qp
+ */
+static int nes_destroy_qp(struct ib_qp *ibqp)
+{
+       struct nes_qp *nesqp = to_nesqp(ibqp);
+       /* struct nes_vnic *nesvnic = to_nesvnic(ibqp->device); */
+       struct nes_ucontext *nes_ucontext;
+       struct ib_qp_attr attr;
+       struct iw_cm_id *cm_id;
+       struct iw_cm_event cm_event;
+       int ret;
+
+       atomic_inc(&sw_qps_destroyed);
+       nesqp->destroyed = 1;
+
+       /* Blow away the connection if it exists. */
+       if (nesqp->ibqp_state >= IB_QPS_INIT && nesqp->ibqp_state <= IB_QPS_RTS) {
+               /* if (nesqp->ibqp_state == IB_QPS_RTS) { */
+               attr.qp_state = IB_QPS_ERR;
+               nes_modify_qp(&nesqp->ibqp, &attr, IB_QP_STATE, NULL);
+       }
+
+       if (((nesqp->ibqp_state == IB_QPS_INIT) ||
+                       (nesqp->ibqp_state == IB_QPS_RTR)) && (nesqp->cm_id)) {
+               cm_id = nesqp->cm_id;
+               cm_event.event = IW_CM_EVENT_CONNECT_REPLY;
+               cm_event.status = IW_CM_EVENT_STATUS_TIMEOUT;
+               cm_event.local_addr = cm_id->local_addr;
+               cm_event.remote_addr = cm_id->remote_addr;
+               cm_event.private_data = NULL;
+               cm_event.private_data_len = 0;
+
+               nes_debug(NES_DBG_QP, "Generating a CM Timeout Event for "
+                               "QP%u. cm_id = %p, refcount = %u. \n",
+                               nesqp->hwqp.qp_id, cm_id, atomic_read(&nesqp->refcount));
+
+               cm_id->rem_ref(cm_id);
+               ret = cm_id->event_handler(cm_id, &cm_event);
+               if (ret)
+                       nes_debug(NES_DBG_QP, "OFA CM event_handler returned, ret=%d\n", ret);
+       }
+
+
+       if (nesqp->user_mode) {
+               if ((ibqp->uobject)&&(ibqp->uobject->context)) {
+                       nes_ucontext = to_nesucontext(ibqp->uobject->context);
+                       clear_bit(nesqp->mmap_sq_db_index, nes_ucontext->allocated_wqs);
+                       nes_ucontext->mmap_nesqp[nesqp->mmap_sq_db_index] = NULL;
+                       if (nes_ucontext->first_free_wq > nesqp->mmap_sq_db_index) {
+                               nes_ucontext->first_free_wq = nesqp->mmap_sq_db_index;
+                       }
+               }
+               if (nesqp->pbl_pbase)
+                       kunmap(nesqp->page);
+       }
+
+       nes_rem_ref(&nesqp->ibqp);
+       return 0;
+}
+
+
+/**
+ * nes_create_cq
+ */
+static struct ib_cq *nes_create_cq(struct ib_device *ibdev, int entries,
+               int comp_vector,
+               struct ib_ucontext *context, struct ib_udata *udata)
+{
+       u64 u64temp;
+       struct nes_vnic *nesvnic = to_nesvnic(ibdev);
+       struct nes_device *nesdev = nesvnic->nesdev;
+       struct nes_adapter *nesadapter = nesdev->nesadapter;
+       struct nes_cq *nescq;
+       struct nes_ucontext *nes_ucontext = NULL;
+       struct nes_cqp_request *cqp_request;
+       void *mem = NULL;
+       struct nes_hw_cqp_wqe *cqp_wqe;
+       struct nes_pbl *nespbl = NULL;
+       struct nes_create_cq_req req;
+       struct nes_create_cq_resp resp;
+       u32 cq_num = 0;
+       u32 opcode = 0;
+       u32 pbl_entries = 1;
+       int err;
+       unsigned long flags;
+       int ret;
+
+       err = nes_alloc_resource(nesadapter, nesadapter->allocated_cqs,
+                       nesadapter->max_cq, &cq_num, &nesadapter->next_cq);
+       if (err) {
+               return ERR_PTR(err);
+       }
+
+       nescq = kzalloc(sizeof(struct nes_cq), GFP_KERNEL);
+       if (!nescq) {
+               nes_free_resource(nesadapter, nesadapter->allocated_cqs, cq_num);
+               nes_debug(NES_DBG_CQ, "Unable to allocate nes_cq struct\n");
+               return ERR_PTR(-ENOMEM);
+       }
+
+       nescq->hw_cq.cq_size = max(entries + 1, 5);
+       nescq->hw_cq.cq_number = cq_num;
+       nescq->ibcq.cqe = nescq->hw_cq.cq_size - 1;
+
+
+       if (context) {
+               nes_ucontext = to_nesucontext(context);
+               if (ib_copy_from_udata(&req, udata, sizeof (struct nes_create_cq_req))) {
+                       nes_free_resource(nesadapter, nesadapter->allocated_cqs, cq_num);
+                       kfree(nescq);
+                       return ERR_PTR(-EFAULT);
+               }
+               nesvnic->mcrq_ucontext = nes_ucontext;
+               nes_ucontext->mcrqf = req.mcrqf;
+               if (nes_ucontext->mcrqf) {
+                       if (nes_ucontext->mcrqf & 0x80000000)
+                               nescq->hw_cq.cq_number = nesvnic->nic.qp_id + 12 + (nes_ucontext->mcrqf & 0xf) - 1;
+                       else if (nes_ucontext->mcrqf & 0x40000000)
+                               nescq->hw_cq.cq_number = nes_ucontext->mcrqf & 0xffff;
+                       else
+                               nescq->hw_cq.cq_number = nesvnic->mcrq_qp_id + nes_ucontext->mcrqf-1;
+                       nes_free_resource(nesadapter, nesadapter->allocated_cqs, cq_num);
+               }
+               nes_debug(NES_DBG_CQ, "CQ Virtual Address = %08lX, size = %u.\n",
+                               (unsigned long)req.user_cq_buffer, entries);
+               list_for_each_entry(nespbl, &nes_ucontext->cq_reg_mem_list, list) {
+                       if (nespbl->user_base == (unsigned long )req.user_cq_buffer) {
+                               list_del(&nespbl->list);
+                               err = 0;
+                               nes_debug(NES_DBG_CQ, "Found PBL for virtual CQ. nespbl=%p.\n",
+                                               nespbl);
+                               break;
+                       }
+               }
+               if (err) {
+                       nes_free_resource(nesadapter, nesadapter->allocated_cqs, cq_num);
+                       kfree(nescq);
+                       return ERR_PTR(err);
+               }
+
+               pbl_entries = nespbl->pbl_size >> 3;
+               nescq->cq_mem_size = 0;
+       } else {
+               nescq->cq_mem_size = nescq->hw_cq.cq_size * sizeof(struct nes_hw_cqe);
+               nes_debug(NES_DBG_CQ, "Attempting to allocate pci memory (%u entries, %u bytes) for CQ%u.\n",
+                               entries, nescq->cq_mem_size, nescq->hw_cq.cq_number);
+
+               /* allocate the physical buffer space */
+               mem = pci_alloc_consistent(nesdev->pcidev, nescq->cq_mem_size,
+                               &nescq->hw_cq.cq_pbase);
+               if (!mem) {
+                       printk(KERN_ERR PFX "Unable to allocate pci memory for cq\n");
+                       nes_free_resource(nesadapter, nesadapter->allocated_cqs, cq_num);
+                       kfree(nescq);
+                       return ERR_PTR(-ENOMEM);
+               }
+
+               memset(mem, 0, nescq->cq_mem_size);
+               nescq->hw_cq.cq_vbase = mem;
+               nescq->hw_cq.cq_head = 0;
+               nes_debug(NES_DBG_CQ, "CQ%u virtual address @ %p, phys = 0x%08X\n",
+                               nescq->hw_cq.cq_number, nescq->hw_cq.cq_vbase,
+                               (u32)nescq->hw_cq.cq_pbase);
+       }
+
+       nescq->hw_cq.ce_handler = nes_iwarp_ce_handler;
+       spin_lock_init(&nescq->lock);
+
+       /* send CreateCQ request to CQP */
+       cqp_request = nes_get_cqp_request(nesdev);
+       if (cqp_request == NULL) {
+               nes_debug(NES_DBG_CQ, "Failed to get a cqp_request.\n");
+               if (!context)
+                       pci_free_consistent(nesdev->pcidev, nescq->cq_mem_size, mem,
+                                       nescq->hw_cq.cq_pbase);
+               nes_free_resource(nesadapter, nesadapter->allocated_cqs, cq_num);
+               kfree(nescq);
+               return ERR_PTR(-ENOMEM);
+       }
+       cqp_request->waiting = 1;
+       cqp_wqe = &cqp_request->cqp_wqe;
+
+       opcode = NES_CQP_CREATE_CQ | NES_CQP_CQ_CEQ_VALID |
+                       NES_CQP_CQ_CHK_OVERFLOW |
+                       NES_CQP_CQ_CEQE_MASK | ((u32)nescq->hw_cq.cq_size << 16);
+
+       spin_lock_irqsave(&nesadapter->pbl_lock, flags);
+
+       if (pbl_entries != 1) {
+               if (pbl_entries > 32) {
+                       /* use 4k pbl */
+                       nes_debug(NES_DBG_CQ, "pbl_entries=%u, use a 4k PBL\n", pbl_entries);
+                       if (nesadapter->free_4kpbl == 0) {
+                               if (cqp_request->dynamic) {
+                                       spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
+                                       kfree(cqp_request);
+                               } else {
+                                       list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs);
+                                       spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
+                               }
+                               if (!context)
+                                       pci_free_consistent(nesdev->pcidev, nescq->cq_mem_size, mem,
+                                                       nescq->hw_cq.cq_pbase);
+                               nes_free_resource(nesadapter, nesadapter->allocated_cqs, cq_num);
+                               kfree(nescq);
+                               return ERR_PTR(-ENOMEM);
+                       } else {
+                               opcode |= (NES_CQP_CQ_VIRT | NES_CQP_CQ_4KB_CHUNK);
+                               nescq->virtual_cq = 2;
+                               nesadapter->free_4kpbl--;
+                       }
+               } else {
+                       /* use 256 byte pbl */
+                       nes_debug(NES_DBG_CQ, "pbl_entries=%u, use a 256 byte PBL\n", pbl_entries);
+                       if (nesadapter->free_256pbl == 0) {
+                               if (cqp_request->dynamic) {
+                                       spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
+                                       kfree(cqp_request);
+                               } else {
+                                       list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs);
+                                       spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
+                               }
+                               if (!context)
+                                       pci_free_consistent(nesdev->pcidev, nescq->cq_mem_size, mem,
+                                                       nescq->hw_cq.cq_pbase);
+                               nes_free_resource(nesadapter, nesadapter->allocated_cqs, cq_num);
+                               kfree(nescq);
+                               return ERR_PTR(-ENOMEM);
+                       } else {
+                               opcode |= NES_CQP_CQ_VIRT;
+                               nescq->virtual_cq = 1;
+                               nesadapter->free_256pbl--;
+                       }
+               }
+       }
+
+       spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
+
+       nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
+       set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_OPCODE_IDX, opcode);
+       set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_ID_IDX,
+                       (nescq->hw_cq.cq_number | ((u32)nesdev->ceq_index << 16)));
+
+       if (context) {
+               if (pbl_entries != 1)
+                       u64temp = (u64)nespbl->pbl_pbase;
+               else
+                       u64temp = le64_to_cpu(nespbl->pbl_vbase[0]);
+               set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_CQ_WQE_DOORBELL_INDEX_HIGH_IDX,
+                               nes_ucontext->mmap_db_index[0]);
+       } else {
+               u64temp = (u64)nescq->hw_cq.cq_pbase;
+               cqp_wqe->wqe_words[NES_CQP_CQ_WQE_DOORBELL_INDEX_HIGH_IDX] = 0;
+       }
+       set_wqe_64bit_value(cqp_wqe->wqe_words, NES_CQP_CQ_WQE_PBL_LOW_IDX, u64temp);
+       cqp_wqe->wqe_words[NES_CQP_CQ_WQE_CQ_CONTEXT_HIGH_IDX] = 0;
+       u64temp = (u64)(unsigned long)&nescq->hw_cq;
+       cqp_wqe->wqe_words[NES_CQP_CQ_WQE_CQ_CONTEXT_LOW_IDX] =
+                       cpu_to_le32((u32)(u64temp >> 1));
+       cqp_wqe->wqe_words[NES_CQP_CQ_WQE_CQ_CONTEXT_HIGH_IDX] =
+                       cpu_to_le32(((u32)((u64temp) >> 33)) & 0x7FFFFFFF);
+
+       atomic_set(&cqp_request->refcount, 2);
+       nes_post_cqp_request(nesdev, cqp_request, NES_CQP_REQUEST_RING_DOORBELL);
+
+       /* Wait for CQP */
+       nes_debug(NES_DBG_CQ, "Waiting for create iWARP CQ%u to complete.\n",
+                       nescq->hw_cq.cq_number);
+       ret = wait_event_timeout(cqp_request->waitq, (0 != cqp_request->request_done),
+                       NES_EVENT_TIMEOUT * 2);
+       nes_debug(NES_DBG_CQ, "Create iWARP CQ%u completed, wait_event_timeout ret = %d.\n",
+                       nescq->hw_cq.cq_number, ret);
+       if ((!ret) || (cqp_request->major_code)) {
+               if (atomic_dec_and_test(&cqp_request->refcount)) {
+                       if (cqp_request->dynamic) {
+                               kfree(cqp_request);
+                       } else {
+                               spin_lock_irqsave(&nesdev->cqp.lock, flags);
+                               list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs);
+                               spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+                       }
+               }
+               nes_debug(NES_DBG_CQ, "iWARP CQ%u create timeout expired, major code = 0x%04X,"
+                               " minor code = 0x%04X\n",
+                               nescq->hw_cq.cq_number, cqp_request->major_code, cqp_request->minor_code);
+               if (!context)
+                       pci_free_consistent(nesdev->pcidev, nescq->cq_mem_size, mem,
+                                       nescq->hw_cq.cq_pbase);
+               nes_free_resource(nesadapter, nesadapter->allocated_cqs, cq_num);
+               kfree(nescq);
+               return ERR_PTR(-EIO);
+       } else {
+               if (atomic_dec_and_test(&cqp_request->refcount)) {
+                       if (cqp_request->dynamic) {
+                               kfree(cqp_request);
+                       } else {
+                               spin_lock_irqsave(&nesdev->cqp.lock, flags);
+                               list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs);
+                               spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+                       }
+               }
+       }
+
+       if (context) {
+               /* free the nespbl */
+               pci_free_consistent(nesdev->pcidev, nespbl->pbl_size, nespbl->pbl_vbase,
+                               nespbl->pbl_pbase);
+               kfree(nespbl);
+               resp.cq_id = nescq->hw_cq.cq_number;
+               resp.cq_size = nescq->hw_cq.cq_size;
+               resp.mmap_db_index = 0;
+               if (ib_copy_to_udata(udata, &resp, sizeof resp)) {
+                       nes_free_resource(nesadapter, nesadapter->allocated_cqs, cq_num);
+                       kfree(nescq);
+                       return ERR_PTR(-EFAULT);
+               }
+       }
+
+       return &nescq->ibcq;
+}
+
+
+/**
+ * nes_destroy_cq
+ */
+static int nes_destroy_cq(struct ib_cq *ib_cq)
+{
+       struct nes_cq *nescq;
+       struct nes_device *nesdev;
+       struct nes_vnic *nesvnic;
+       struct nes_adapter *nesadapter;
+       struct nes_hw_cqp_wqe *cqp_wqe;
+       struct nes_cqp_request *cqp_request;
+       unsigned long flags;
+       u32 opcode = 0;
+       int ret;
+
+       if (ib_cq == NULL)
+               return 0;
+
+       nescq = to_nescq(ib_cq);
+       nesvnic = to_nesvnic(ib_cq->device);
+       nesdev = nesvnic->nesdev;
+       nesadapter = nesdev->nesadapter;
+
+       nes_debug(NES_DBG_CQ, "Destroy CQ%u\n", nescq->hw_cq.cq_number);
+
+       /* Send DestroyCQ request to CQP */
+       cqp_request = nes_get_cqp_request(nesdev);
+       if (cqp_request == NULL) {
+               nes_debug(NES_DBG_CQ, "Failed to get a cqp_request.\n");
+               return -ENOMEM;
+       }
+       cqp_request->waiting = 1;
+       cqp_wqe = &cqp_request->cqp_wqe;
+       opcode = NES_CQP_DESTROY_CQ | (nescq->hw_cq.cq_size << 16);
+       spin_lock_irqsave(&nesadapter->pbl_lock, flags);
+       if (nescq->virtual_cq == 1) {
+               nesadapter->free_256pbl++;
+               if (nesadapter->free_256pbl > nesadapter->max_256pbl) {
+                       printk(KERN_ERR PFX "%s: free 256B PBLs(%u) has exceeded the max(%u)\n",
+                                       __FUNCTION__, nesadapter->free_256pbl, nesadapter->max_256pbl);
+               }
+       } else if (nescq->virtual_cq == 2) {
+               nesadapter->free_4kpbl++;
+               if (nesadapter->free_4kpbl > nesadapter->max_4kpbl) {
+                       printk(KERN_ERR PFX "%s: free 4K PBLs(%u) has exceeded the max(%u)\n",
+                                       __FUNCTION__, nesadapter->free_4kpbl, nesadapter->max_4kpbl);
+               }
+               opcode |= NES_CQP_CQ_4KB_CHUNK;
+       }
+
+       spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
+
+       nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
+       set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_OPCODE_IDX, opcode);
+       set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_ID_IDX,
+               (nescq->hw_cq.cq_number | ((u32)PCI_FUNC(nesdev->pcidev->devfn) << 16)));
+       nes_free_resource(nesadapter, nesadapter->allocated_cqs, nescq->hw_cq.cq_number);
+       atomic_set(&cqp_request->refcount, 2);
+       nes_post_cqp_request(nesdev, cqp_request, NES_CQP_REQUEST_RING_DOORBELL);
+
+       /* Wait for CQP */
+       nes_debug(NES_DBG_CQ, "Waiting for destroy iWARP CQ%u to complete.\n",
+                       nescq->hw_cq.cq_number);
+       ret = wait_event_timeout(cqp_request->waitq, (0 != cqp_request->request_done),
+                       NES_EVENT_TIMEOUT);
+       nes_debug(NES_DBG_CQ, "Destroy iWARP CQ%u completed, wait_event_timeout ret = %u,"
+                       " CQP Major:Minor codes = 0x%04X:0x%04X.\n",
+                       nescq->hw_cq.cq_number, ret, cqp_request->major_code,
+                       cqp_request->minor_code);
+       if ((!ret) || (cqp_request->major_code)) {
+               if (atomic_dec_and_test(&cqp_request->refcount)) {
+                       if (cqp_request->dynamic) {
+                               kfree(cqp_request);
+                       } else {
+                               spin_lock_irqsave(&nesdev->cqp.lock, flags);
+                               list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs);
+                               spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+                       }
+               }
+               if (!ret) {
+                       nes_debug(NES_DBG_CQ, "iWARP CQ%u destroy timeout expired\n",
+                                       nescq->hw_cq.cq_number);
+                       ret = -ETIME;
+               } else {
+                       nes_debug(NES_DBG_CQ, "iWARP CQ%u destroy failed\n",
+                                       nescq->hw_cq.cq_number);
+                       ret = -EIO;
+               }
+       } else {
+               ret = 0;
+               if (atomic_dec_and_test(&cqp_request->refcount)) {
+                       if (cqp_request->dynamic) {
+                               kfree(cqp_request);
+                       } else {
+                               spin_lock_irqsave(&nesdev->cqp.lock, flags);
+                               list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs);
+                               spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+                       }
+               }
+       }
+
+       if (nescq->cq_mem_size)
+               pci_free_consistent(nesdev->pcidev, nescq->cq_mem_size,
+                               (void *)nescq->hw_cq.cq_vbase, nescq->hw_cq.cq_pbase);
+       kfree(nescq);
+
+       return ret;
+}
+
+
+/**
+ * nes_reg_mr
+ */
+static int nes_reg_mr(struct nes_device *nesdev, struct nes_pd *nespd,
+               u32 stag, u64 region_length, struct nes_root_vpbl *root_vpbl,
+               dma_addr_t single_buffer, u16 pbl_count, u16 residual_page_count,
+               int acc, u64 *iova_start)
+{
+       struct nes_hw_cqp_wqe *cqp_wqe;
+       struct nes_cqp_request *cqp_request;
+       unsigned long flags;
+       int ret;
+       struct nes_adapter *nesadapter = nesdev->nesadapter;
+       /* int count; */
+       u32 opcode = 0;
+       u16 major_code;
+
+       /* Register the region with the adapter */
+       cqp_request = nes_get_cqp_request(nesdev);
+       if (cqp_request == NULL) {
+               nes_debug(NES_DBG_MR, "Failed to get a cqp_request.\n");
+               return -ENOMEM;
+       }
+       cqp_request->waiting = 1;
+       cqp_wqe = &cqp_request->cqp_wqe;
+
+       spin_lock_irqsave(&nesadapter->pbl_lock, flags);
+       /* track PBL resources */
+       if (pbl_count != 0) {
+               if (pbl_count > 1) {
+                       /* Two level PBL */
+                       if ((pbl_count+1) > nesadapter->free_4kpbl) {
+                               nes_debug(NES_DBG_MR, "Out of 4KB Pbls for two level request.\n");
+                               if (cqp_request->dynamic) {
+                                       spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
+                                       kfree(cqp_request);
+                               } else {
+                                       list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs);
+                                       spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
+                               }
+                               return -ENOMEM;
+                       } else {
+                               nesadapter->free_4kpbl -= pbl_count+1;
+                       }
+               } else if (residual_page_count > 32) {
+                       if (pbl_count > nesadapter->free_4kpbl) {
+                               nes_debug(NES_DBG_MR, "Out of 4KB Pbls.\n");
+                               if (cqp_request->dynamic) {
+                                       spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
+                                       kfree(cqp_request);
+                               } else {
+                                       list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs);
+                                       spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
+                               }
+                               return -ENOMEM;
+                       } else {
+                               nesadapter->free_4kpbl -= pbl_count;
+                       }
+               } else {
+                       if (pbl_count > nesadapter->free_256pbl) {
+                               nes_debug(NES_DBG_MR, "Out of 256B Pbls.\n");
+                               if (cqp_request->dynamic) {
+                                       spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
+                                       kfree(cqp_request);
+                               } else {
+                                       list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs);
+                                       spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
+                               }
+                               return -ENOMEM;
+                       } else {
+                               nesadapter->free_256pbl -= pbl_count;
+                       }
+               }
+       }
+
+       spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
+
+       opcode = NES_CQP_REGISTER_STAG | NES_CQP_STAG_RIGHTS_LOCAL_READ |
+                                       NES_CQP_STAG_VA_TO | NES_CQP_STAG_MR;
+       if (acc & IB_ACCESS_LOCAL_WRITE)
+               opcode |= NES_CQP_STAG_RIGHTS_LOCAL_WRITE;
+       if (acc & IB_ACCESS_REMOTE_WRITE)
+               opcode |= NES_CQP_STAG_RIGHTS_REMOTE_WRITE | NES_CQP_STAG_REM_ACC_EN;
+       if (acc & IB_ACCESS_REMOTE_READ)
+               opcode |= NES_CQP_STAG_RIGHTS_REMOTE_READ | NES_CQP_STAG_REM_ACC_EN;
+       if (acc & IB_ACCESS_MW_BIND)
+               opcode |= NES_CQP_STAG_RIGHTS_WINDOW_BIND | NES_CQP_STAG_REM_ACC_EN;
+
+       nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
+       set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_OPCODE_IDX, opcode);
+       set_wqe_64bit_value(cqp_wqe->wqe_words, NES_CQP_STAG_WQE_VA_LOW_IDX, *iova_start);
+       set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_STAG_WQE_LEN_LOW_IDX, region_length);
+
+       cqp_wqe->wqe_words[NES_CQP_STAG_WQE_LEN_HIGH_PD_IDX] =
+                       cpu_to_le32((u32)(region_length >> 8) & 0xff000000);
+       cqp_wqe->wqe_words[NES_CQP_STAG_WQE_LEN_HIGH_PD_IDX] |=
+                       cpu_to_le32(nespd->pd_id & 0x00007fff);
+       set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_STAG_WQE_STAG_IDX, stag);
+
+       if (pbl_count == 0) {
+               set_wqe_64bit_value(cqp_wqe->wqe_words, NES_CQP_STAG_WQE_PA_LOW_IDX, single_buffer);
+       } else {
+               set_wqe_64bit_value(cqp_wqe->wqe_words, NES_CQP_STAG_WQE_PA_LOW_IDX, root_vpbl->pbl_pbase);
+               set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_STAG_WQE_PBL_BLK_COUNT_IDX, pbl_count);
+               set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_STAG_WQE_PBL_LEN_IDX,
+                               (((pbl_count - 1) * 4096) + (residual_page_count*8)));
+
+               if ((pbl_count > 1) || (residual_page_count > 32))
+                       cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] |= cpu_to_le32(NES_CQP_STAG_PBL_BLK_SIZE);
+       }
+       barrier();
+
+       atomic_set(&cqp_request->refcount, 2);
+       nes_post_cqp_request(nesdev, cqp_request, NES_CQP_REQUEST_RING_DOORBELL);
+
+       /* Wait for CQP */
+       ret = wait_event_timeout(cqp_request->waitq, (0 != cqp_request->request_done),
+                       NES_EVENT_TIMEOUT);
+       nes_debug(NES_DBG_MR, "Register STag 0x%08X completed, wait_event_timeout ret = %u,"
+                       " CQP Major:Minor codes = 0x%04X:0x%04X.\n",
+                       stag, ret, cqp_request->major_code, cqp_request->minor_code);
+       major_code = cqp_request->major_code;
+       if (atomic_dec_and_test(&cqp_request->refcount)) {
+               if (cqp_request->dynamic) {
+                       kfree(cqp_request);
+               } else {
+                       spin_lock_irqsave(&nesdev->cqp.lock, flags);
+                       list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs);
+                       spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+               }
+       }
+       if (!ret)
+               return -ETIME;
+       else if (major_code)
+               return -EIO;
+       else
+               return 0;
+
+       return 0;
+}
+
+
+/**
+ * nes_reg_phys_mr
+ */
+static struct ib_mr *nes_reg_phys_mr(struct ib_pd *ib_pd,
+               struct ib_phys_buf *buffer_list, int num_phys_buf, int acc,
+               u64 * iova_start)
+{
+       u64 region_length;
+       struct nes_pd *nespd = to_nespd(ib_pd);
+       struct nes_vnic *nesvnic = to_nesvnic(ib_pd->device);
+       struct nes_device *nesdev = nesvnic->nesdev;
+       struct nes_adapter *nesadapter = nesdev->nesadapter;
+       struct nes_mr *nesmr;
+       struct ib_mr *ibmr;
+       struct nes_vpbl vpbl;
+       struct nes_root_vpbl root_vpbl;
+       u32 stag;
+       u32 i;
+       u32 stag_index = 0;
+       u32 next_stag_index = 0;
+       u32 driver_key = 0;
+       u32 root_pbl_index = 0;
+       u32 cur_pbl_index = 0;
+       int err = 0, pbl_depth = 0;
+       int ret = 0;
+       u16 pbl_count = 0;
+       u8 single_page = 1;
+       u8 stag_key = 0;
+
+       pbl_depth = 0;
+       region_length = 0;
+       vpbl.pbl_vbase = NULL;
+       root_vpbl.pbl_vbase = NULL;
+       root_vpbl.pbl_pbase = 0;
+
+       get_random_bytes(&next_stag_index, sizeof(next_stag_index));
+       stag_key = (u8)next_stag_index;
+
+       driver_key = 0;
+
+       next_stag_index >>= 8;
+       next_stag_index %= nesadapter->max_mr;
+       if (num_phys_buf > (1024*512)) {
+               return ERR_PTR(-E2BIG);
+       }
+
+       err = nes_alloc_resource(nesadapter, nesadapter->allocated_mrs, nesadapter->max_mr,
+                       &stag_index, &next_stag_index);
+       if (err) {
+               return ERR_PTR(err);
+       }
+
+       nesmr = kzalloc(sizeof(*nesmr), GFP_KERNEL);
+       if (!nesmr) {
+               nes_free_resource(nesadapter, nesadapter->allocated_mrs, stag_index);
+               return ERR_PTR(-ENOMEM);
+       }
+
+       for (i = 0; i < num_phys_buf; i++) {
+
+               if ((i & 0x01FF) == 0) {
+                       if (root_pbl_index == 1) {
+                               /* Allocate the root PBL */
+                               root_vpbl.pbl_vbase = pci_alloc_consistent(nesdev->pcidev, 8192,
+                                               &root_vpbl.pbl_pbase);
+                               nes_debug(NES_DBG_MR, "Allocating root PBL, va = %p, pa = 0x%08X\n",
+                                               root_vpbl.pbl_vbase, (unsigned int)root_vpbl.pbl_pbase);
+                               if (!root_vpbl.pbl_vbase) {
+                                       pci_free_consistent(nesdev->pcidev, 4096, vpbl.pbl_vbase,
+                                                       vpbl.pbl_pbase);
+                                       nes_free_resource(nesadapter, nesadapter->allocated_mrs, stag_index);
+                                       kfree(nesmr);
+                                       return ERR_PTR(-ENOMEM);
+                               }
+                               root_vpbl.leaf_vpbl = kzalloc(sizeof(*root_vpbl.leaf_vpbl)*1024, GFP_KERNEL);
+                               if (!root_vpbl.leaf_vpbl) {
+                                       pci_free_consistent(nesdev->pcidev, 8192, root_vpbl.pbl_vbase,
+                                                       root_vpbl.pbl_pbase);
+                                       pci_free_consistent(nesdev->pcidev, 4096, vpbl.pbl_vbase,
+                                                       vpbl.pbl_pbase);
+                                       nes_free_resource(nesadapter, nesadapter->allocated_mrs, stag_index);
+                                       kfree(nesmr);
+                                       return ERR_PTR(-ENOMEM);
+                               }
+                               root_vpbl.pbl_vbase[0].pa_low = cpu_to_le32((u32)vpbl.pbl_pbase);
+                               root_vpbl.pbl_vbase[0].pa_high =
+                                               cpu_to_le32((u32)((((u64)vpbl.pbl_pbase) >> 32)));
+                               root_vpbl.leaf_vpbl[0] = vpbl;
+                       }
+                       /* Allocate a 4K buffer for the PBL */
+                       vpbl.pbl_vbase = pci_alloc_consistent(nesdev->pcidev, 4096,
+                                       &vpbl.pbl_pbase);
+                       nes_debug(NES_DBG_MR, "Allocating leaf PBL, va = %p, pa = 0x%016lX\n",
+                                       vpbl.pbl_vbase, (unsigned long)vpbl.pbl_pbase);
+                       if (!vpbl.pbl_vbase) {
+                               nes_free_resource(nesadapter, nesadapter->allocated_mrs, stag_index);
+                               ibmr = ERR_PTR(-ENOMEM);
+                               kfree(nesmr);
+                               goto reg_phys_err;
+                       }
+                       /* Fill in the root table */
+                       if (1 <= root_pbl_index) {
+                               root_vpbl.pbl_vbase[root_pbl_index].pa_low =
+                                               cpu_to_le32((u32)vpbl.pbl_pbase);
+                               root_vpbl.pbl_vbase[root_pbl_index].pa_high =
+                                               cpu_to_le32((u32)((((u64)vpbl.pbl_pbase) >> 32)));
+                               root_vpbl.leaf_vpbl[root_pbl_index] = vpbl;
+                       }
+                       root_pbl_index++;
+                       cur_pbl_index = 0;
+               }
+               if (buffer_list[i].addr & ~PAGE_MASK) {
+                       /* TODO: Unwind allocated buffers */
+                       nes_free_resource(nesadapter, nesadapter->allocated_mrs, stag_index);
+                       nes_debug(NES_DBG_MR, "Unaligned Memory Buffer: 0x%x\n",
+                                       (unsigned int) buffer_list[i].addr);
+                       ibmr = ERR_PTR(-EINVAL);
+                       kfree(nesmr);
+                       goto reg_phys_err;
+               }
+
+               if (!buffer_list[i].size) {
+                       nes_free_resource(nesadapter, nesadapter->allocated_mrs, stag_index);
+                       nes_debug(NES_DBG_MR, "Invalid Buffer Size\n");
+                       ibmr = ERR_PTR(-EINVAL);
+                       kfree(nesmr);
+                       goto reg_phys_err;
+               }
+
+               region_length += buffer_list[i].size;
+               if ((i != 0) && (single_page)) {
+                       if ((buffer_list[i-1].addr+PAGE_SIZE) != buffer_list[i].addr)
+                               single_page = 0;
+               }
+               vpbl.pbl_vbase[cur_pbl_index].pa_low = cpu_to_le32((u32)buffer_list[i].addr);
+               vpbl.pbl_vbase[cur_pbl_index++].pa_high =
+                               cpu_to_le32((u32)((((u64)buffer_list[i].addr) >> 32)));
+       }
+
+       stag = stag_index << 8;
+       stag |= driver_key;
+       stag += (u32)stag_key;
+
+       nes_debug(NES_DBG_MR, "Registering STag 0x%08X, VA = 0x%016lX,"
+                       " length = 0x%016lX, index = 0x%08X\n",
+                       stag, (unsigned long)*iova_start, (unsigned long)region_length, stag_index);
+
+       region_length -= (*iova_start)&PAGE_MASK;
+
+       /* Make the leaf PBL the root if only one PBL */
+       if (root_pbl_index == 1) {
+               root_vpbl.pbl_pbase = vpbl.pbl_pbase;
+       }
+
+       if (single_page) {
+               pbl_count = 0;
+       } else {
+               pbl_count = root_pbl_index;
+       }
+       ret = nes_reg_mr(nesdev, nespd, stag, region_length, &root_vpbl,
+                       buffer_list[0].addr, pbl_count, (u16)cur_pbl_index, acc, iova_start);
+
+       if (ret == 0) {
+               nesmr->ibmr.rkey = stag;
+               nesmr->ibmr.lkey = stag;
+               nesmr->mode = IWNES_MEMREG_TYPE_MEM;
+               ibmr = &nesmr->ibmr;
+               nesmr->pbl_4k = ((pbl_count > 1) || (cur_pbl_index > 32)) ? 1 : 0;
+               nesmr->pbls_used = pbl_count;
+               if (pbl_count > 1) {
+                       nesmr->pbls_used++;
+               }
+       } else {
+               kfree(nesmr);
+               ibmr = ERR_PTR(-ENOMEM);
+       }
+
+       reg_phys_err:
+       /* free the resources */
+       if (root_pbl_index == 1) {
+               /* single PBL case */
+               pci_free_consistent(nesdev->pcidev, 4096, vpbl.pbl_vbase, vpbl.pbl_pbase);
+       } else {
+               for (i=0; i<root_pbl_index; i++) {
+                       pci_free_consistent(nesdev->pcidev, 4096, root_vpbl.leaf_vpbl[i].pbl_vbase,
+                                       root_vpbl.leaf_vpbl[i].pbl_pbase);
+               }
+               kfree(root_vpbl.leaf_vpbl);
+               pci_free_consistent(nesdev->pcidev, 8192, root_vpbl.pbl_vbase,
+                               root_vpbl.pbl_pbase);
+       }
+
+       return ibmr;
+}
+
+
+/**
+ * nes_get_dma_mr
+ */
+static struct ib_mr *nes_get_dma_mr(struct ib_pd *pd, int acc)
+{
+       struct ib_phys_buf bl;
+       u64 kva = 0;
+
+       nes_debug(NES_DBG_MR, "\n");
+
+       bl.size = (u64)0xffffffffffULL;
+       bl.addr = 0;
+       return nes_reg_phys_mr(pd, &bl, 1, acc, &kva);
+}
+
+
+/**
+ * nes_reg_user_mr
+ */
+static struct ib_mr *nes_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
+               u64 virt, int acc, struct ib_udata *udata)
+{
+       u64 iova_start;
+       __le64 *pbl;
+       u64 region_length;
+       dma_addr_t last_dma_addr = 0;
+       dma_addr_t first_dma_addr = 0;
+       struct nes_pd *nespd = to_nespd(pd);
+       struct nes_vnic *nesvnic = to_nesvnic(pd->device);
+       struct nes_device *nesdev = nesvnic->nesdev;
+       struct nes_adapter *nesadapter = nesdev->nesadapter;
+       struct ib_mr *ibmr = ERR_PTR(-EINVAL);
+       struct ib_umem_chunk *chunk;
+       struct nes_ucontext *nes_ucontext;
+       struct nes_pbl *nespbl;
+       struct nes_mr *nesmr;
+       struct ib_umem *region;
+       struct nes_mem_reg_req req;
+       struct nes_vpbl vpbl;
+       struct nes_root_vpbl root_vpbl;
+       int nmap_index, page_index;
+       int page_count = 0;
+       int err, pbl_depth = 0;
+       int chunk_pages;
+       int ret;
+       u32 stag;
+       u32 stag_index = 0;
+       u32 next_stag_index;
+       u32 driver_key;
+       u32 root_pbl_index = 0;
+       u32 cur_pbl_index = 0;
+       u32 skip_pages;
+       u16 pbl_count;
+       u8 single_page = 1;
+       u8 stag_key;
+
+       region = ib_umem_get(pd->uobject->context, start, length, acc);
+       if (IS_ERR(region)) {
+               return (struct ib_mr *)region;
+       }
+
+       nes_debug(NES_DBG_MR, "User base = 0x%lX, Virt base = 0x%lX, length = %u,"
+                       " offset = %u, page size = %u.\n",
+                       (unsigned long int)start, (unsigned long int)virt, (u32)length,
+                       region->offset, region->page_size);
+
+       skip_pages = ((u32)region->offset) >> 12;
+
+       if (ib_copy_from_udata(&req, udata, sizeof(req)))
+               return ERR_PTR(-EFAULT);
+       nes_debug(NES_DBG_MR, "Memory Registration type = %08X.\n", req.reg_type);
+
+       switch (req.reg_type) {
+               case IWNES_MEMREG_TYPE_MEM:
+                       pbl_depth = 0;
+                       region_length = 0;
+                       vpbl.pbl_vbase = NULL;
+                       root_vpbl.pbl_vbase = NULL;
+                       root_vpbl.pbl_pbase = 0;
+
+                       get_random_bytes(&next_stag_index, sizeof(next_stag_index));
+                       stag_key = (u8)next_stag_index;
+
+                       driver_key = next_stag_index & 0x70000000;
+
+                       next_stag_index >>= 8;
+                       next_stag_index %= nesadapter->max_mr;
+
+                       err = nes_alloc_resource(nesadapter, nesadapter->allocated_mrs,
+                                       nesadapter->max_mr, &stag_index, &next_stag_index);
+                       if (err) {
+                               ib_umem_release(region);
+                               return ERR_PTR(err);
+                       }
+
+                       nesmr = kzalloc(sizeof(*nesmr), GFP_KERNEL);
+                       if (!nesmr) {
+                               ib_umem_release(region);
+                               nes_free_resource(nesadapter, nesadapter->allocated_mrs, stag_index);
+                               return ERR_PTR(-ENOMEM);
+                       }
+                       nesmr->region = region;
+
+                       list_for_each_entry(chunk, &region->chunk_list, list) {
+                               nes_debug(NES_DBG_MR, "Chunk: nents = %u, nmap = %u .\n",
+                                               chunk->nents, chunk->nmap);
+                               for (nmap_index = 0; nmap_index < chunk->nmap; ++nmap_index) {
+                                       if (sg_dma_address(&chunk->page_list[nmap_index]) & ~PAGE_MASK) {
+                                               ib_umem_release(region);
+                                               nes_free_resource(nesadapter, nesadapter->allocated_mrs, stag_index);
+                                               nes_debug(NES_DBG_MR, "Unaligned Memory Buffer: 0x%x\n",
+                                                               (unsigned int) sg_dma_address(&chunk->page_list[nmap_index]));
+                                               ibmr = ERR_PTR(-EINVAL);
+                                               kfree(nesmr);
+                                               goto reg_user_mr_err;
+                                       }
+
+                                       if (!sg_dma_len(&chunk->page_list[nmap_index])) {
+                                               ib_umem_release(region);
+                                               nes_free_resource(nesadapter, nesadapter->allocated_mrs,
+                                                               stag_index);
+                                               nes_debug(NES_DBG_MR, "Invalid Buffer Size\n");
+                                               ibmr = ERR_PTR(-EINVAL);
+                                               kfree(nesmr);
+                                               goto reg_user_mr_err;
+                                       }
+
+                                       region_length += sg_dma_len(&chunk->page_list[nmap_index]);
+                                       chunk_pages = sg_dma_len(&chunk->page_list[nmap_index]) >> 12;
+                                       region_length -= skip_pages << 12;
+                                       for (page_index=skip_pages; page_index < chunk_pages; page_index++) {
+                                               skip_pages = 0;
+                                               if ((page_count!=0)&&(page_count<<12)-(region->offset&(4096-1))>=region->length)
+                                                       goto enough_pages;
+                                               if ((page_count&0x01FF) == 0) {
+                                                       if (page_count>(1024*512)) {
+                                                               ib_umem_release(region);
+                                                               pci_free_consistent(nesdev->pcidev, 4096, vpbl.pbl_vbase,
+                                                                               vpbl.pbl_pbase);
+                                                               nes_free_resource(nesadapter,
+                                                                               nesadapter->allocated_mrs, stag_index);
+                                                               kfree(nesmr);
+                                                               ibmr = ERR_PTR(-E2BIG);
+                                                               goto reg_user_mr_err;
+                                                       }
+                                                       if (root_pbl_index == 1) {
+                                                               root_vpbl.pbl_vbase = pci_alloc_consistent(nesdev->pcidev,
+                                                                               8192, &root_vpbl.pbl_pbase);
+                                                               nes_debug(NES_DBG_MR, "Allocating root PBL, va = %p, pa = 0x%08X\n",
+                                                                               root_vpbl.pbl_vbase, (unsigned int)root_vpbl.pbl_pbase);
+                                                               if (!root_vpbl.pbl_vbase) {
+                                                                       ib_umem_release(region);
+                                                                       pci_free_consistent(nesdev->pcidev, 4096, vpbl.pbl_vbase,
+                                                                                       vpbl.pbl_pbase);
+                                                                       nes_free_resource(nesadapter, nesadapter->allocated_mrs,
+                                                                                       stag_index);
+                                                                       kfree(nesmr);
+                                                                       ibmr = ERR_PTR(-ENOMEM);
+                                                                       goto reg_user_mr_err;
+                                                               }
+                                                               root_vpbl.leaf_vpbl = kzalloc(sizeof(*root_vpbl.leaf_vpbl)*1024,
+                                                                               GFP_KERNEL);
+                                                               if (!root_vpbl.leaf_vpbl) {
+                                                                       ib_umem_release(region);
+                                                                       pci_free_consistent(nesdev->pcidev, 8192, root_vpbl.pbl_vbase,
+                                                                                       root_vpbl.pbl_pbase);
+                                                                       pci_free_consistent(nesdev->pcidev, 4096, vpbl.pbl_vbase,
+                                                                                       vpbl.pbl_pbase);
+                                                                       nes_free_resource(nesadapter, nesadapter->allocated_mrs,
+                                                                                       stag_index);
+                                                                       kfree(nesmr);
+                                                                       ibmr = ERR_PTR(-ENOMEM);
+                                                                       goto reg_user_mr_err;
+                                                               }
+                                                               root_vpbl.pbl_vbase[0].pa_low =
+                                                                               cpu_to_le32((u32)vpbl.pbl_pbase);
+                                                               root_vpbl.pbl_vbase[0].pa_high =
+                                                                               cpu_to_le32((u32)((((u64)vpbl.pbl_pbase) >> 32)));
+                                                               root_vpbl.leaf_vpbl[0] = vpbl;
+                                                       }
+                                                       vpbl.pbl_vbase = pci_alloc_consistent(nesdev->pcidev, 4096,
+                                                                       &vpbl.pbl_pbase);
+                                                       nes_debug(NES_DBG_MR, "Allocating leaf PBL, va = %p, pa = 0x%08X\n",
+                                                                       vpbl.pbl_vbase, (unsigned int)vpbl.pbl_pbase);
+                                                       if (!vpbl.pbl_vbase) {
+                                                               ib_umem_release(region);
+                                                               nes_free_resource(nesadapter, nesadapter->allocated_mrs, stag_index);
+                                                               ibmr = ERR_PTR(-ENOMEM);
+                                                               kfree(nesmr);
+                                                               goto reg_user_mr_err;
+                                                       }
+                                                       if (1 <= root_pbl_index) {
+                                                               root_vpbl.pbl_vbase[root_pbl_index].pa_low =
+                                                                               cpu_to_le32((u32)vpbl.pbl_pbase);
+                                                               root_vpbl.pbl_vbase[root_pbl_index].pa_high =
+                                                                               cpu_to_le32((u32)((((u64)vpbl.pbl_pbase)>>32)));
+                                                               root_vpbl.leaf_vpbl[root_pbl_index] = vpbl;
+                                                       }
+                                                       root_pbl_index++;
+                                                       cur_pbl_index = 0;
+                                               }
+                                               if (single_page) {
+                                                       if (page_count != 0) {
+                                                               if ((last_dma_addr+4096) !=
+                                                                               (sg_dma_address(&chunk->page_list[nmap_index])+
+                                                                               (page_index*4096)))
+                                                                       single_page = 0;
+                                                               last_dma_addr = sg_dma_address(&chunk->page_list[nmap_index])+
+                                                                               (page_index*4096);
+                                                       } else {
+                                                               first_dma_addr = sg_dma_address(&chunk->page_list[nmap_index])+
+                                                                               (page_index*4096);
+                                                               last_dma_addr = first_dma_addr;
+                                                       }
+                                               }
+
+                                               vpbl.pbl_vbase[cur_pbl_index].pa_low =
+                                                               cpu_to_le32((u32)(sg_dma_address(&chunk->page_list[nmap_index])+
+                                                               (page_index*4096)));
+                                               vpbl.pbl_vbase[cur_pbl_index].pa_high =
+                                                               cpu_to_le32((u32)((((u64)(sg_dma_address(&chunk->page_list[nmap_index])+
+                                                               (page_index*4096))) >> 32)));
+                                               cur_pbl_index++;
+                                               page_count++;
+                                       }
+                               }
+                       }
+                       enough_pages:
+                       nes_debug(NES_DBG_MR, "calculating stag, stag_index=0x%08x, driver_key=0x%08x,"
+                                       " stag_key=0x%08x\n",
+                                       stag_index, driver_key, stag_key);
+                       stag = stag_index << 8;
+                       stag |= driver_key;
+                       stag += (u32)stag_key;
+                       if (stag == 0) {
+                               stag = 1;
+                       }
+
+                       iova_start = virt;
+                       /* Make the leaf PBL the root if only one PBL */
+                       if (root_pbl_index == 1) {
+                               root_vpbl.pbl_pbase = vpbl.pbl_pbase;
+                       }
+
+                       if (single_page) {
+                               pbl_count = 0;
+                       } else {
+                               pbl_count = root_pbl_index;
+                               first_dma_addr = 0;
+                       }
+                       nes_debug(NES_DBG_MR, "Registering STag 0x%08X, VA = 0x%08X, length = 0x%08X,"
+                                       " index = 0x%08X, region->length=0x%08llx, pbl_count = %u\n",
+                                       stag, (unsigned int)iova_start,
+                                       (unsigned int)region_length, stag_index,
+                                       (unsigned long long)region->length, pbl_count);
+                       ret = nes_reg_mr( nesdev, nespd, stag, region->length, &root_vpbl,
+                                       first_dma_addr, pbl_count, (u16)cur_pbl_index, acc, &iova_start);
+
+                       nes_debug(NES_DBG_MR, "ret=%d\n", ret);
+
+                       if (ret == 0) {
+                               nesmr->ibmr.rkey = stag;
+                               nesmr->ibmr.lkey = stag;
+                               nesmr->mode = IWNES_MEMREG_TYPE_MEM;
+                               ibmr = &nesmr->ibmr;
+                               nesmr->pbl_4k = ((pbl_count > 1) || (cur_pbl_index > 32)) ? 1 : 0;
+                               nesmr->pbls_used = pbl_count;
+                               if (pbl_count > 1) {
+                                       nesmr->pbls_used++;
+                               }
+                       } else {
+                               ib_umem_release(region);
+                               kfree(nesmr);
+                               ibmr = ERR_PTR(-ENOMEM);
+                       }
+
+                       reg_user_mr_err:
+                       /* free the resources */
+                       if (root_pbl_index == 1) {
+                               pci_free_consistent(nesdev->pcidev, 4096, vpbl.pbl_vbase,
+                                               vpbl.pbl_pbase);
+                       } else {
+                               for (page_index=0; page_index<root_pbl_index; page_index++) {
+                                       pci_free_consistent(nesdev->pcidev, 4096,
+                                                       root_vpbl.leaf_vpbl[page_index].pbl_vbase,
+                                                       root_vpbl.leaf_vpbl[page_index].pbl_pbase);
+                               }
+                               kfree(root_vpbl.leaf_vpbl);
+                               pci_free_consistent(nesdev->pcidev, 8192, root_vpbl.pbl_vbase,
+                                               root_vpbl.pbl_pbase);
+                       }
+
+                       nes_debug(NES_DBG_MR, "Leaving, ibmr=%p", ibmr);
+
+                       return ibmr;
+                       break;
+               case IWNES_MEMREG_TYPE_QP:
+               case IWNES_MEMREG_TYPE_CQ:
+                       nespbl = kzalloc(sizeof(*nespbl), GFP_KERNEL);
+                       if (!nespbl) {
+                               nes_debug(NES_DBG_MR, "Unable to allocate PBL\n");
+                               ib_umem_release(region);
+                               return ERR_PTR(-ENOMEM);
+                       }
+                       nesmr = kzalloc(sizeof(*nesmr), GFP_KERNEL);
+                       if (!nesmr) {
+                               ib_umem_release(region);
+                               kfree(nespbl);
+                               nes_debug(NES_DBG_MR, "Unable to allocate nesmr\n");
+                               return ERR_PTR(-ENOMEM);
+                       }
+                       nesmr->region = region;
+                       nes_ucontext = to_nesucontext(pd->uobject->context);
+                       pbl_depth = region->length >> 12;
+                       pbl_depth += (region->length & (4096-1)) ? 1 : 0;
+                       nespbl->pbl_size = pbl_depth*sizeof(u64);
+                       if (req.reg_type == IWNES_MEMREG_TYPE_QP) {
+                               nes_debug(NES_DBG_MR, "Attempting to allocate QP PBL memory");
+                       } else {
+                               nes_debug(NES_DBG_MR, "Attempting to allocate CP PBL memory");
+                       }
+
+                       nes_debug(NES_DBG_MR, " %u bytes, %u entries.\n",
+                                       nespbl->pbl_size, pbl_depth);
+                       pbl = pci_alloc_consistent(nesdev->pcidev, nespbl->pbl_size,
+                                       &nespbl->pbl_pbase);
+                       if (!pbl) {
+                               ib_umem_release(region);
+                               kfree(nesmr);
+                               kfree(nespbl);
+                               nes_debug(NES_DBG_MR, "Unable to allocate PBL memory\n");
+                               return ERR_PTR(-ENOMEM);
+                       }
+
+                       nespbl->pbl_vbase = (u64 *)pbl;
+                       nespbl->user_base = start;
+                       nes_debug(NES_DBG_MR, "Allocated PBL memory, %u bytes, pbl_pbase=%p,"
+                                       " pbl_vbase=%p user_base=0x%lx\n",
+                                       nespbl->pbl_size, (void *)nespbl->pbl_pbase,
+                                       (void*)nespbl->pbl_vbase, nespbl->user_base);
+
+                       list_for_each_entry(chunk, &region->chunk_list, list) {
+                               for (nmap_index = 0; nmap_index < chunk->nmap; ++nmap_index) {
+                                       chunk_pages = sg_dma_len(&chunk->page_list[nmap_index]) >> 12;
+                                       chunk_pages += (sg_dma_len(&chunk->page_list[nmap_index]) & (4096-1)) ? 1 : 0;
+                                       nespbl->page = sg_page(&chunk->page_list[0]);
+                                       for (page_index=0; page_index<chunk_pages; page_index++) {
+                                               ((__le32 *)pbl)[0] = cpu_to_le32((u32)
+                                                               (sg_dma_address(&chunk->page_list[nmap_index])+
+                                                               (page_index*4096)));
+                                               ((__le32 *)pbl)[1] = cpu_to_le32(((u64)
+                                                               (sg_dma_address(&chunk->page_list[nmap_index])+
+                                                               (page_index*4096)))>>32);
+                                               nes_debug(NES_DBG_MR, "pbl=%p, *pbl=0x%016llx, 0x%08x%08x\n", pbl,
+                                                               (unsigned long long)*pbl,
+                                                               le32_to_cpu(((__le32 *)pbl)[1]), le32_to_cpu(((__le32 *)pbl)[0]));
+                                               pbl++;
+                                       }
+                               }
+                       }
+                       if (req.reg_type == IWNES_MEMREG_TYPE_QP) {
+                               list_add_tail(&nespbl->list, &nes_ucontext->qp_reg_mem_list);
+                       } else {
+                               list_add_tail(&nespbl->list, &nes_ucontext->cq_reg_mem_list);
+                       }
+                       nesmr->ibmr.rkey = -1;
+                       nesmr->ibmr.lkey = -1;
+                       nesmr->mode = req.reg_type;
+                       return &nesmr->ibmr;
+                       break;
+       }
+
+       return ERR_PTR(-ENOSYS);
+}
+
+
+/**
+ * nes_dereg_mr
+ */
+static int nes_dereg_mr(struct ib_mr *ib_mr)
+{
+       struct nes_mr *nesmr = to_nesmr(ib_mr);
+       struct nes_vnic *nesvnic = to_nesvnic(ib_mr->device);
+       struct nes_device *nesdev = nesvnic->nesdev;
+       struct nes_adapter *nesadapter = nesdev->nesadapter;
+       struct nes_hw_cqp_wqe *cqp_wqe;
+       struct nes_cqp_request *cqp_request;
+       unsigned long flags;
+       int ret;
+       u16 major_code;
+       u16 minor_code;
+
+       if (nesmr->region) {
+               ib_umem_release(nesmr->region);
+       }
+       if (nesmr->mode != IWNES_MEMREG_TYPE_MEM) {
+               kfree(nesmr);
+               return 0;
+       }
+
+       /* Deallocate the region with the adapter */
+
+       cqp_request = nes_get_cqp_request(nesdev);
+       if (cqp_request == NULL) {
+               nes_debug(NES_DBG_MR, "Failed to get a cqp_request.\n");
+               return -ENOMEM;
+       }
+       cqp_request->waiting = 1;
+       cqp_wqe = &cqp_request->cqp_wqe;
+
+       spin_lock_irqsave(&nesadapter->pbl_lock, flags);
+       if (nesmr->pbls_used != 0) {
+               if (nesmr->pbl_4k) {
+                       nesadapter->free_4kpbl += nesmr->pbls_used;
+                       if (nesadapter->free_4kpbl > nesadapter->max_4kpbl) {
+                               printk(KERN_ERR PFX "free 4KB PBLs(%u) has exceeded the max(%u)\n",
+                                               nesadapter->free_4kpbl, nesadapter->max_4kpbl);
+                       }
+               } else {
+                       nesadapter->free_256pbl += nesmr->pbls_used;
+                       if (nesadapter->free_256pbl > nesadapter->max_256pbl) {
+                               printk(KERN_ERR PFX "free 256B PBLs(%u) has exceeded the max(%u)\n",
+                                               nesadapter->free_256pbl, nesadapter->max_256pbl);
+                       }
+               }
+       }
+
+       spin_unlock_irqrestore(&nesadapter->pbl_lock, flags);
+       nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
+       set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_OPCODE_IDX,
+                       NES_CQP_DEALLOCATE_STAG | NES_CQP_STAG_VA_TO |
+                       NES_CQP_STAG_DEALLOC_PBLS | NES_CQP_STAG_MR);
+       set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_STAG_WQE_STAG_IDX, ib_mr->rkey);
+
+       atomic_set(&cqp_request->refcount, 2);
+       nes_post_cqp_request(nesdev, cqp_request, NES_CQP_REQUEST_RING_DOORBELL);
+
+       /* Wait for CQP */
+       nes_debug(NES_DBG_MR, "Waiting for deallocate STag 0x%08X completed\n", ib_mr->rkey);
+       ret = wait_event_timeout(cqp_request->waitq, (cqp_request->request_done != 0),
+                       NES_EVENT_TIMEOUT);
+       nes_debug(NES_DBG_MR, "Deallocate STag 0x%08X completed, wait_event_timeout ret = %u,"
+                       " CQP Major:Minor codes = 0x%04X:0x%04X\n",
+                       ib_mr->rkey, ret, cqp_request->major_code, cqp_request->minor_code);
+
+       nes_free_resource(nesadapter, nesadapter->allocated_mrs,
+                       (ib_mr->rkey & 0x0fffff00) >> 8);
+
+       kfree(nesmr);
+
+       major_code = cqp_request->major_code;
+       minor_code = cqp_request->minor_code;
+       if (atomic_dec_and_test(&cqp_request->refcount)) {
+               if (cqp_request->dynamic) {
+                       kfree(cqp_request);
+               } else {
+                       spin_lock_irqsave(&nesdev->cqp.lock, flags);
+                       list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs);
+                       spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+               }
+       }
+       if (!ret) {
+               nes_debug(NES_DBG_MR, "Timeout waiting to destroy STag,"
+                               " ib_mr=%p, rkey = 0x%08X\n",
+                               ib_mr, ib_mr->rkey);
+               return -ETIME;
+       } else if (major_code) {
+               nes_debug(NES_DBG_MR, "Error (0x%04X:0x%04X) while attempting"
+                               " to destroy STag, ib_mr=%p, rkey = 0x%08X\n",
+                               major_code, minor_code, ib_mr, ib_mr->rkey);
+               return -EIO;
+       } else
+               return 0;
+}
+
+
+/**
+ * show_rev
+ */
+static ssize_t show_rev(struct class_device *cdev, char *buf)
+{
+       struct nes_ib_device *nesibdev =
+                       container_of(cdev, struct nes_ib_device, ibdev.class_dev);
+       struct nes_vnic *nesvnic = nesibdev->nesvnic;
+
+       nes_debug(NES_DBG_INIT, "\n");
+       return sprintf(buf, "%x\n", nesvnic->nesdev->nesadapter->hw_rev);
+}
+
+
+/**
+ * show_fw_ver
+ */
+static ssize_t show_fw_ver(struct class_device *cdev, char *buf)
+{
+       struct nes_ib_device *nesibdev =
+                       container_of(cdev, struct nes_ib_device, ibdev.class_dev);
+       struct nes_vnic *nesvnic = nesibdev->nesvnic;
+
+       nes_debug(NES_DBG_INIT, "\n");
+       return sprintf(buf, "%x.%x.%x\n",
+                       (int)(nesvnic->nesdev->nesadapter->fw_ver >> 32),
+                       (int)(nesvnic->nesdev->nesadapter->fw_ver >> 16) & 0xffff,
+                       (int)(nesvnic->nesdev->nesadapter->fw_ver & 0xffff));
+}
+
+
+/**
+ * show_hca
+ */
+static ssize_t show_hca(struct class_device *cdev, char *buf)
+{
+       nes_debug(NES_DBG_INIT, "\n");
+       return sprintf(buf, "NES020\n");
+}
+
+
+/**
+ * show_board
+ */
+static ssize_t show_board(struct class_device *cdev, char *buf)
+{
+       nes_debug(NES_DBG_INIT, "\n");
+       return sprintf(buf, "%.*s\n", 32, "NES020 Board ID");
+}
+
+
+static CLASS_DEVICE_ATTR(hw_rev, S_IRUGO, show_rev, NULL);
+static CLASS_DEVICE_ATTR(fw_ver, S_IRUGO, show_fw_ver, NULL);
+static CLASS_DEVICE_ATTR(hca_type, S_IRUGO, show_hca, NULL);
+static CLASS_DEVICE_ATTR(board_id, S_IRUGO, show_board, NULL);
+
+static struct class_device_attribute *nes_class_attributes[] = {
+       &class_device_attr_hw_rev,
+       &class_device_attr_fw_ver,
+       &class_device_attr_hca_type,
+       &class_device_attr_board_id
+};
+
+
+/**
+ * nes_query_qp
+ */
+static int nes_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
+               int attr_mask, struct ib_qp_init_attr *init_attr)
+{
+       struct nes_qp *nesqp = to_nesqp(ibqp);
+
+       nes_debug(NES_DBG_QP, "\n");
+
+       attr->qp_access_flags = 0;
+       attr->cap.max_send_wr = nesqp->hwqp.sq_size;
+       attr->cap.max_recv_wr = nesqp->hwqp.rq_size;
+       attr->cap.max_recv_sge = 1;
+       if (nes_drv_opt & NES_DRV_OPT_NO_INLINE_DATA) {
+               init_attr->cap.max_inline_data = 0;
+       } else {
+               init_attr->cap.max_inline_data = 64;
+       }
+
+       init_attr->event_handler = nesqp->ibqp.event_handler;
+       init_attr->qp_context = nesqp->ibqp.qp_context;
+       init_attr->send_cq = nesqp->ibqp.send_cq;
+       init_attr->recv_cq = nesqp->ibqp.recv_cq;
+       init_attr->srq = nesqp->ibqp.srq = nesqp->ibqp.srq;
+       init_attr->cap = attr->cap;
+
+       return 0;
+}
+
+
+/**
+ * nes_hw_modify_qp
+ */
+int nes_hw_modify_qp(struct nes_device *nesdev, struct nes_qp *nesqp,
+               u32 next_iwarp_state, u32 wait_completion)
+{
+       struct nes_hw_cqp_wqe *cqp_wqe;
+       /* struct iw_cm_id *cm_id = nesqp->cm_id; */
+       /* struct iw_cm_event cm_event; */
+       struct nes_cqp_request *cqp_request;
+       unsigned long flags;
+       int ret;
+       u16 major_code;
+
+       nes_debug(NES_DBG_MOD_QP, "QP%u, refcount=%d\n",
+                       nesqp->hwqp.qp_id, atomic_read(&nesqp->refcount));
+
+       cqp_request = nes_get_cqp_request(nesdev);
+       if (cqp_request == NULL) {
+               nes_debug(NES_DBG_MOD_QP, "Failed to get a cqp_request.\n");
+               return -ENOMEM;
+       }
+       if (wait_completion) {
+               cqp_request->waiting = 1;
+       } else {
+               cqp_request->waiting = 0;
+       }
+       cqp_wqe = &cqp_request->cqp_wqe;
+
+       set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_OPCODE_IDX,
+                       NES_CQP_MODIFY_QP | NES_CQP_QP_TYPE_IWARP | next_iwarp_state);
+       nes_debug(NES_DBG_MOD_QP, "using next_iwarp_state=%08x, wqe_words=%08x\n",
+                       next_iwarp_state, le32_to_cpu(cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX]));
+       nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
+       set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_ID_IDX, nesqp->hwqp.qp_id);
+       set_wqe_64bit_value(cqp_wqe->wqe_words, NES_CQP_QP_WQE_CONTEXT_LOW_IDX, (u64)nesqp->nesqp_context_pbase);
+
+       atomic_set(&cqp_request->refcount, 2);
+       nes_post_cqp_request(nesdev, cqp_request, NES_CQP_REQUEST_RING_DOORBELL);
+
+       /* Wait for CQP */
+       if (wait_completion) {
+               /* nes_debug(NES_DBG_MOD_QP, "Waiting for modify iWARP QP%u to complete.\n",
+                               nesqp->hwqp.qp_id); */
+               ret = wait_event_timeout(cqp_request->waitq, (cqp_request->request_done != 0),
+                               NES_EVENT_TIMEOUT);
+               nes_debug(NES_DBG_MOD_QP, "Modify iwarp QP%u completed, wait_event_timeout ret=%u, "
+                               "CQP Major:Minor codes = 0x%04X:0x%04X.\n",
+                               nesqp->hwqp.qp_id, ret, cqp_request->major_code, cqp_request->minor_code);
+               major_code = cqp_request->major_code;
+               if (major_code) {
+                       nes_debug(NES_DBG_MOD_QP, "Modify iwarp QP%u failed"
+                                       "CQP Major:Minor codes = 0x%04X:0x%04X, intended next state = 0x%08X.\n",
+                                       nesqp->hwqp.qp_id, cqp_request->major_code,
+                                       cqp_request->minor_code, next_iwarp_state);
+               }
+               if (atomic_dec_and_test(&cqp_request->refcount)) {
+                       if (cqp_request->dynamic) {
+                               kfree(cqp_request);
+                       } else {
+                               spin_lock_irqsave(&nesdev->cqp.lock, flags);
+                               list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs);
+                               spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+                       }
+               }
+               if (!ret)
+                       return -ETIME;
+               else if (major_code)
+                       return -EIO;
+               else
+                       return 0;
+       } else {
+               return 0;
+       }
+}
+
+
+/**
+ * nes_modify_qp
+ */
+int nes_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
+               int attr_mask, struct ib_udata *udata)
+{
+       struct nes_qp *nesqp = to_nesqp(ibqp);
+       struct nes_vnic *nesvnic = to_nesvnic(ibqp->device);
+       struct nes_device *nesdev = nesvnic->nesdev;
+       /* u32 cqp_head; */
+       /* u32 counter; */
+       u32 next_iwarp_state = 0;
+       int err;
+       unsigned long qplockflags;
+       int ret;
+       u16 original_last_aeq;
+       u8 issue_modify_qp = 0;
+       u8 issue_disconnect = 0;
+       u8 dont_wait = 0;
+
+       nes_debug(NES_DBG_MOD_QP, "QP%u: QP State=%u, cur QP State=%u,"
+                       " iwarp_state=0x%X, refcount=%d\n",
+                       nesqp->hwqp.qp_id, attr->qp_state, nesqp->ibqp_state,
+                       nesqp->iwarp_state, atomic_read(&nesqp->refcount));
+
+       nes_add_ref(&nesqp->ibqp);
+       spin_lock_irqsave(&nesqp->lock, qplockflags);
+
+       nes_debug(NES_DBG_MOD_QP, "QP%u: hw_iwarp_state=0x%X, hw_tcp_state=0x%X,"
+                       " QP Access Flags=0x%X, attr_mask = 0x%0x\n",
+                       nesqp->hwqp.qp_id, nesqp->hw_iwarp_state,
+                       nesqp->hw_tcp_state, attr->qp_access_flags, attr_mask);
+
+       if (attr_mask & IB_QP_STATE) {
+               switch (attr->qp_state) {
+                       case IB_QPS_INIT:
+                               nes_debug(NES_DBG_MOD_QP, "QP%u: new state = init\n",
+                                               nesqp->hwqp.qp_id);
+                               if (nesqp->iwarp_state > (u32)NES_CQP_QP_IWARP_STATE_IDLE) {
+                                       spin_unlock_irqrestore(&nesqp->lock, qplockflags);
+                                       nes_rem_ref(&nesqp->ibqp);
+                                       return -EINVAL;
+                               }
+                               next_iwarp_state = NES_CQP_QP_IWARP_STATE_IDLE;
+                               issue_modify_qp = 1;
+                               break;
+                       case IB_QPS_RTR:
+                               nes_debug(NES_DBG_MOD_QP, "QP%u: new state = rtr\n",
+                                               nesqp->hwqp.qp_id);
+                               if (nesqp->iwarp_state>(u32)NES_CQP_QP_IWARP_STATE_IDLE) {
+                                       spin_unlock_irqrestore(&nesqp->lock, qplockflags);
+                                       nes_rem_ref(&nesqp->ibqp);
+                                       return -EINVAL;
+                               }
+                               next_iwarp_state = NES_CQP_QP_IWARP_STATE_IDLE;
+                               issue_modify_qp = 1;
+                               break;
+                       case IB_QPS_RTS:
+                               nes_debug(NES_DBG_MOD_QP, "QP%u: new state = rts\n",
+                                               nesqp->hwqp.qp_id);
+                               if (nesqp->iwarp_state>(u32)NES_CQP_QP_IWARP_STATE_RTS) {
+                                       spin_unlock_irqrestore(&nesqp->lock, qplockflags);
+                                       nes_rem_ref(&nesqp->ibqp);
+                                       return -EINVAL;
+                               }
+                               if (nesqp->cm_id == NULL) {
+                                       nes_debug(NES_DBG_MOD_QP, "QP%u: Failing attempt to move QP to RTS without a CM_ID. \n",
+                                                       nesqp->hwqp.qp_id );
+                                       spin_unlock_irqrestore(&nesqp->lock, qplockflags);
+                                       nes_rem_ref(&nesqp->ibqp);
+                                       return -EINVAL;
+                               }
+                               next_iwarp_state = NES_CQP_QP_IWARP_STATE_RTS;
+                               if (nesqp->iwarp_state != NES_CQP_QP_IWARP_STATE_RTS)
+                                       next_iwarp_state |= NES_CQP_QP_CONTEXT_VALID |
+                                                       NES_CQP_QP_ARP_VALID | NES_CQP_QP_ORD_VALID;
+                               issue_modify_qp = 1;
+                               nesqp->hw_tcp_state = NES_AEQE_TCP_STATE_ESTABLISHED;
+                               nesqp->hw_iwarp_state = NES_AEQE_IWARP_STATE_RTS;
+                               nesqp->hte_added = 1;
+                               break;
+                       case IB_QPS_SQD:
+                               issue_modify_qp = 1;
+                               nes_debug(NES_DBG_MOD_QP, "QP%u: new state=closing. SQ head=%u, SQ tail=%u\n",
+                                               nesqp->hwqp.qp_id, nesqp->hwqp.sq_head, nesqp->hwqp.sq_tail);
+                               if (nesqp->iwarp_state == (u32)NES_CQP_QP_IWARP_STATE_CLOSING) {
+                                       spin_unlock_irqrestore(&nesqp->lock, qplockflags);
+                                       nes_rem_ref(&nesqp->ibqp);
+                                       return 0;
+                               } else {
+                                       if (nesqp->iwarp_state > (u32)NES_CQP_QP_IWARP_STATE_CLOSING) {
+                                               nes_debug(NES_DBG_MOD_QP, "QP%u: State change to closing"
+                                                               " ignored due to current iWARP state\n",
+                                                               nesqp->hwqp.qp_id);
+                                               spin_unlock_irqrestore(&nesqp->lock, qplockflags);
+                                               nes_rem_ref(&nesqp->ibqp);
+                                               return -EINVAL;
+                                       }
+                                       if (nesqp->hw_iwarp_state != NES_AEQE_IWARP_STATE_RTS) {
+                                               nes_debug(NES_DBG_MOD_QP, "QP%u: State change to closing"
+                                                               " already done based on hw state.\n",
+                                                               nesqp->hwqp.qp_id);
+                                               issue_modify_qp = 0;
+                                               nesqp->in_disconnect = 0;
+                                       }
+                                       switch (nesqp->hw_iwarp_state) {
+                                               case NES_AEQE_IWARP_STATE_CLOSING:
+                                                       next_iwarp_state = NES_CQP_QP_IWARP_STATE_CLOSING;
+                                               case NES_AEQE_IWARP_STATE_TERMINATE:
+                                                       next_iwarp_state = NES_CQP_QP_IWARP_STATE_TERMINATE;
+                                                       break;
+                                               case NES_AEQE_IWARP_STATE_ERROR:
+                                                       next_iwarp_state = NES_CQP_QP_IWARP_STATE_ERROR;
+                                                       break;
+                                               default:
+                                                       next_iwarp_state = NES_CQP_QP_IWARP_STATE_CLOSING;
+                                                       nesqp->in_disconnect = 1;
+                                                       nesqp->hw_iwarp_state = NES_AEQE_IWARP_STATE_CLOSING;
+                                                       break;
+                                       }
+                               }
+                               break;
+                       case IB_QPS_SQE:
+                               nes_debug(NES_DBG_MOD_QP, "QP%u: new state = terminate\n",
+                                               nesqp->hwqp.qp_id);
+                               if (nesqp->iwarp_state>=(u32)NES_CQP_QP_IWARP_STATE_TERMINATE) {
+                                       spin_unlock_irqrestore(&nesqp->lock, qplockflags);
+                                       nes_rem_ref(&nesqp->ibqp);
+                                       return -EINVAL;
+                               }
+                               /* next_iwarp_state = (NES_CQP_QP_IWARP_STATE_TERMINATE | 0x02000000); */
+                               next_iwarp_state = NES_CQP_QP_IWARP_STATE_TERMINATE;
+                               nesqp->hw_iwarp_state = NES_AEQE_IWARP_STATE_TERMINATE;
+                               issue_modify_qp = 1;
+                               nesqp->in_disconnect = 1;
+                               break;
+                       case IB_QPS_ERR:
+                       case IB_QPS_RESET:
+                               if (nesqp->iwarp_state == (u32)NES_CQP_QP_IWARP_STATE_ERROR) {
+                                       spin_unlock_irqrestore(&nesqp->lock, qplockflags);
+                                       nes_rem_ref(&nesqp->ibqp);
+                                       return -EINVAL;
+                               }
+                               nes_debug(NES_DBG_MOD_QP, "QP%u: new state = error\n",
+                                               nesqp->hwqp.qp_id);
+                               next_iwarp_state = NES_CQP_QP_IWARP_STATE_ERROR;
+                               /* next_iwarp_state = (NES_CQP_QP_IWARP_STATE_TERMINATE | 0x02000000); */
+                                       if (nesqp->hte_added) {
+                                               nes_debug(NES_DBG_MOD_QP, "set CQP_QP_DEL_HTE\n");
+                                               next_iwarp_state |= NES_CQP_QP_DEL_HTE;
+                                               nesqp->hte_added = 0;
+                                       }
+                               if ((nesqp->hw_tcp_state > NES_AEQE_TCP_STATE_CLOSED) &&
+                                               (nesqp->hw_tcp_state != NES_AEQE_TCP_STATE_TIME_WAIT)) {
+                                       next_iwarp_state |= NES_CQP_QP_RESET;
+                                       nesqp->in_disconnect = 1;
+                               } else {
+                                       nes_debug(NES_DBG_MOD_QP, "QP%u NOT setting NES_CQP_QP_RESET since TCP state = %u\n",
+                                                       nesqp->hwqp.qp_id, nesqp->hw_tcp_state);
+                                       dont_wait = 1;
+                               }
+                               issue_modify_qp = 1;
+                               nesqp->hw_iwarp_state = NES_AEQE_IWARP_STATE_ERROR;
+                               break;
+                       default:
+                               spin_unlock_irqrestore(&nesqp->lock, qplockflags);
+                               nes_rem_ref(&nesqp->ibqp);
+                               return -EINVAL;
+                               break;
+               }
+
+               nesqp->ibqp_state = attr->qp_state;
+               if (((nesqp->iwarp_state & NES_CQP_QP_IWARP_STATE_MASK) ==
+                               (u32)NES_CQP_QP_IWARP_STATE_RTS) &&
+                               ((next_iwarp_state & NES_CQP_QP_IWARP_STATE_MASK) >
+                               (u32)NES_CQP_QP_IWARP_STATE_RTS)) {
+                       nesqp->iwarp_state = next_iwarp_state & NES_CQP_QP_IWARP_STATE_MASK;
+                       nes_debug(NES_DBG_MOD_QP, "Change nesqp->iwarp_state=%08x\n",
+                                       nesqp->iwarp_state);
+                       issue_disconnect = 1;
+               } else {
+                       nesqp->iwarp_state = next_iwarp_state & NES_CQP_QP_IWARP_STATE_MASK;
+                       nes_debug(NES_DBG_MOD_QP, "Change nesqp->iwarp_state=%08x\n",
+                                       nesqp->iwarp_state);
+               }
+       }
+
+       if (attr_mask & IB_QP_ACCESS_FLAGS) {
+               if (attr->qp_access_flags & IB_ACCESS_LOCAL_WRITE) {
+                       nesqp->nesqp_context->misc |= cpu_to_le32(NES_QPCONTEXT_MISC_RDMA_WRITE_EN |
+                                       NES_QPCONTEXT_MISC_RDMA_READ_EN);
+                       issue_modify_qp = 1;
+               }
+               if (attr->qp_access_flags & IB_ACCESS_REMOTE_WRITE) {
+                       nesqp->nesqp_context->misc |= cpu_to_le32(NES_QPCONTEXT_MISC_RDMA_WRITE_EN);
+                       issue_modify_qp = 1;
+               }
+               if (attr->qp_access_flags & IB_ACCESS_REMOTE_READ) {
+                       nesqp->nesqp_context->misc |= cpu_to_le32(NES_QPCONTEXT_MISC_RDMA_READ_EN);
+                       issue_modify_qp = 1;
+               }
+               if (attr->qp_access_flags & IB_ACCESS_MW_BIND) {
+                       nesqp->nesqp_context->misc |= cpu_to_le32(NES_QPCONTEXT_MISC_WBIND_EN);
+                       issue_modify_qp = 1;
+               }
+
+               if (nesqp->user_mode) {
+                       nesqp->nesqp_context->misc |= cpu_to_le32(NES_QPCONTEXT_MISC_RDMA_WRITE_EN |
+                                       NES_QPCONTEXT_MISC_RDMA_READ_EN);
+                       issue_modify_qp = 1;
+               }
+       }
+
+       original_last_aeq = nesqp->last_aeq;
+       spin_unlock_irqrestore(&nesqp->lock, qplockflags);
+
+       nes_debug(NES_DBG_MOD_QP, "issue_modify_qp=%u\n", issue_modify_qp);
+
+       ret = 0;
+
+
+       if (issue_modify_qp) {
+               nes_debug(NES_DBG_MOD_QP, "call nes_hw_modify_qp\n");
+               ret = nes_hw_modify_qp(nesdev, nesqp, next_iwarp_state, 1);
+               if (ret)
+                       nes_debug(NES_DBG_MOD_QP, "nes_hw_modify_qp (next_iwarp_state = 0x%08X)"
+                                       " failed for QP%u.\n",
+                                       next_iwarp_state, nesqp->hwqp.qp_id);
+
+       }
+
+       if ((issue_modify_qp) && (nesqp->ibqp_state > IB_QPS_RTS)) {
+               nes_debug(NES_DBG_MOD_QP, "QP%u Issued ModifyQP refcount (%d),"
+                               " original_last_aeq = 0x%04X. last_aeq = 0x%04X.\n",
+                               nesqp->hwqp.qp_id, atomic_read(&nesqp->refcount),
+                               original_last_aeq, nesqp->last_aeq);
+               if ((!ret) ||
+                               ((original_last_aeq != NES_AEQE_AEID_RDMAP_ROE_BAD_LLP_CLOSE) &&
+                               (ret))) {
+                       if (dont_wait) {
+                               if (nesqp->cm_id && nesqp->hw_tcp_state != 0) {
+                                       nes_debug(NES_DBG_MOD_QP, "QP%u Queuing fake disconnect for QP refcount (%d),"
+                                                       " original_last_aeq = 0x%04X. last_aeq = 0x%04X.\n",
+                                                       nesqp->hwqp.qp_id, atomic_read(&nesqp->refcount),
+                                                       original_last_aeq, nesqp->last_aeq);
+                                       /* this one is for the cm_disconnect thread */
+                                       nes_add_ref(&nesqp->ibqp);
+                                       spin_lock_irqsave(&nesqp->lock, qplockflags);
+                                       nesqp->hw_tcp_state = NES_AEQE_TCP_STATE_CLOSED;
+                                       nesqp->last_aeq = NES_AEQE_AEID_RESET_SENT;
+                                       spin_unlock_irqrestore(&nesqp->lock, qplockflags);
+                                       nes_cm_disconn(nesqp);
+                               } else {
+                                       nes_debug(NES_DBG_MOD_QP, "QP%u No fake disconnect, QP refcount=%d\n",
+                                                       nesqp->hwqp.qp_id, atomic_read(&nesqp->refcount));
+                                       nes_rem_ref(&nesqp->ibqp);
+                               }
+                       } else {
+                               spin_lock_irqsave(&nesqp->lock, qplockflags);
+                               if (nesqp->cm_id) {
+                                       /* These two are for the timer thread */
+                                       if (atomic_inc_return(&nesqp->close_timer_started) == 1) {
+                                               nes_add_ref(&nesqp->ibqp);
+                                               nesqp->cm_id->add_ref(nesqp->cm_id);
+                                               nes_debug(NES_DBG_MOD_QP, "QP%u Not decrementing QP refcount (%d),"
+                                                               " need ae to finish up, original_last_aeq = 0x%04X."
+                                                               " last_aeq = 0x%04X, scheduling timer.\n",
+                                                               nesqp->hwqp.qp_id, atomic_read(&nesqp->refcount),
+                                                               original_last_aeq, nesqp->last_aeq);
+                                               schedule_nes_timer(nesqp->cm_node, (struct sk_buff *) nesqp, NES_TIMER_TYPE_CLOSE, 1, 0);
+                                       }
+                                       spin_unlock_irqrestore(&nesqp->lock, qplockflags);
+                               } else {
+                                       spin_unlock_irqrestore(&nesqp->lock, qplockflags);
+                                       nes_debug(NES_DBG_MOD_QP, "QP%u Not decrementing QP refcount (%d),"
+                                                       " need ae to finish up, original_last_aeq = 0x%04X."
+                                                       " last_aeq = 0x%04X.\n",
+                                                       nesqp->hwqp.qp_id, atomic_read(&nesqp->refcount),
+                                                       original_last_aeq, nesqp->last_aeq);
+                               }
+                       }
+               } else {
+                       nes_debug(NES_DBG_MOD_QP, "QP%u Decrementing QP refcount (%d), No ae to finish up,"
+                                       " original_last_aeq = 0x%04X. last_aeq = 0x%04X.\n",
+                                       nesqp->hwqp.qp_id, atomic_read(&nesqp->refcount),
+                                       original_last_aeq, nesqp->last_aeq);
+                       nes_rem_ref(&nesqp->ibqp);
+               }
+       } else {
+               nes_debug(NES_DBG_MOD_QP, "QP%u Decrementing QP refcount (%d), No ae to finish up,"
+                               " original_last_aeq = 0x%04X. last_aeq = 0x%04X.\n",
+                               nesqp->hwqp.qp_id, atomic_read(&nesqp->refcount),
+                               original_last_aeq, nesqp->last_aeq);
+               nes_rem_ref(&nesqp->ibqp);
+       }
+
+       err = 0;
+
+       nes_debug(NES_DBG_MOD_QP, "QP%u Leaving, refcount=%d\n",
+                       nesqp->hwqp.qp_id, atomic_read(&nesqp->refcount));
+
+       return err;
+}
+
+
+/**
+ * nes_muticast_attach
+ */
+static int nes_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
+{
+       nes_debug(NES_DBG_INIT, "\n");
+       return -ENOSYS;
+}
+
+
+/**
+ * nes_multicast_detach
+ */
+static int nes_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
+{
+       nes_debug(NES_DBG_INIT, "\n");
+       return -ENOSYS;
+}
+
+
+/**
+ * nes_process_mad
+ */
+static int nes_process_mad(struct ib_device *ibdev, int mad_flags,
+               u8 port_num, struct ib_wc *in_wc, struct ib_grh *in_grh,
+               struct ib_mad *in_mad, struct ib_mad *out_mad)
+{
+       nes_debug(NES_DBG_INIT, "\n");
+       return -ENOSYS;
+}
+
+static inline void
+fill_wqe_sg_send(struct nes_hw_qp_wqe *wqe, struct ib_send_wr *ib_wr, u32 uselkey)
+{
+       int sge_index;
+       int total_payload_length = 0;
+       for (sge_index = 0; sge_index < ib_wr->num_sge; sge_index++) {
+               set_wqe_64bit_value(wqe->wqe_words, NES_IWARP_SQ_WQE_FRAG0_LOW_IDX+(sge_index*4),
+                       ib_wr->sg_list[sge_index].addr);
+               set_wqe_32bit_value(wqe->wqe_words, NES_IWARP_SQ_WQE_LENGTH0_IDX + (sge_index*4),
+                       ib_wr->sg_list[sge_index].length);
+               if (uselkey)
+                       set_wqe_32bit_value(wqe->wqe_words, NES_IWARP_SQ_WQE_STAG0_IDX + (sge_index*4),
+                                               (ib_wr->sg_list[sge_index].lkey));
+               else
+                       set_wqe_32bit_value(wqe->wqe_words, NES_IWARP_SQ_WQE_STAG0_IDX + (sge_index*4), 0);
+
+               total_payload_length += ib_wr->sg_list[sge_index].length;
+       }
+       nes_debug(NES_DBG_IW_TX, "UC UC UC, sending total_payload_length=%u \n",
+                       total_payload_length);
+       set_wqe_32bit_value(wqe->wqe_words, NES_IWARP_SQ_WQE_TOTAL_PAYLOAD_IDX,
+                               total_payload_length);
+}
+
+/**
+ * nes_post_send
+ */
+static int nes_post_send(struct ib_qp *ibqp, struct ib_send_wr *ib_wr,
+               struct ib_send_wr **bad_wr)
+{
+       u64 u64temp;
+       unsigned long flags = 0;
+       struct nes_vnic *nesvnic = to_nesvnic(ibqp->device);
+       struct nes_device *nesdev = nesvnic->nesdev;
+       struct nes_qp *nesqp = to_nesqp(ibqp);
+       struct nes_hw_qp_wqe *wqe;
+       int err;
+       u32 qsize = nesqp->hwqp.sq_size;
+       u32 head;
+       u32 wqe_misc;
+       u32 wqe_count;
+       u32 counter;
+       u32 total_payload_length;
+
+       err = 0;
+       wqe_misc = 0;
+       wqe_count = 0;
+       total_payload_length = 0;
+
+       if (nesqp->ibqp_state > IB_QPS_RTS)
+               return -EINVAL;
+
+               spin_lock_irqsave(&nesqp->lock, flags);
+
+       head = nesqp->hwqp.sq_head;
+
+       while (ib_wr) {
+               /* Check for SQ overflow */
+               if (((head + (2 * qsize) - nesqp->hwqp.sq_tail) % qsize) == (qsize - 1)) {
+                       err = -EINVAL;
+                       break;
+               }
+
+               wqe = &nesqp->hwqp.sq_vbase[head];
+               /* nes_debug(NES_DBG_IW_TX, "processing sq wqe for QP%u at %p, head = %u.\n",
+                               nesqp->hwqp.qp_id, wqe, head); */
+               nes_fill_init_qp_wqe(wqe, nesqp, head);
+               u64temp = (u64)(ib_wr->wr_id);
+               set_wqe_64bit_value(wqe->wqe_words, NES_IWARP_SQ_WQE_COMP_SCRATCH_LOW_IDX,
+                                       u64temp);
+                       switch (ib_wr->opcode) {
+                               case IB_WR_SEND:
+                                       if (ib_wr->send_flags & IB_SEND_SOLICITED) {
+                                               wqe_misc = NES_IWARP_SQ_OP_SENDSE;
+                                       } else {
+                                               wqe_misc = NES_IWARP_SQ_OP_SEND;
+                                       }
+                                       if (ib_wr->num_sge > nesdev->nesadapter->max_sge) {
+                                               err = -EINVAL;
+                                               break;
+                                       }
+                                       if (ib_wr->send_flags & IB_SEND_FENCE) {
+                                               wqe_misc |= NES_IWARP_SQ_WQE_LOCAL_FENCE;
+                                       }
+                                       if ((ib_wr->send_flags & IB_SEND_INLINE) &&
+                                                       ((nes_drv_opt & NES_DRV_OPT_NO_INLINE_DATA) == 0) &&
+                                                       (ib_wr->sg_list[0].length <= 64)) {
+                                               memcpy(&wqe->wqe_words[NES_IWARP_SQ_WQE_IMM_DATA_START_IDX],
+                                                              (void *)(unsigned long)ib_wr->sg_list[0].addr, ib_wr->sg_list[0].length);
+                                               set_wqe_32bit_value(wqe->wqe_words, NES_IWARP_SQ_WQE_TOTAL_PAYLOAD_IDX,
+                                                               ib_wr->sg_list[0].length);
+                                               wqe_misc |= NES_IWARP_SQ_WQE_IMM_DATA;
+                                       } else {
+                                               fill_wqe_sg_send(wqe, ib_wr, 1);
+                                       }
+
+                                       break;
+                               case IB_WR_RDMA_WRITE:
+                                       wqe_misc = NES_IWARP_SQ_OP_RDMAW;
+                                       if (ib_wr->num_sge > nesdev->nesadapter->max_sge) {
+                                               nes_debug(NES_DBG_IW_TX, "Exceeded max sge, ib_wr=%u, max=%u\n",
+                                                               ib_wr->num_sge,
+                                                               nesdev->nesadapter->max_sge);
+                                               err = -EINVAL;
+                                               break;
+                                       }
+                                       if (ib_wr->send_flags & IB_SEND_FENCE) {
+                                               wqe_misc |= NES_IWARP_SQ_WQE_LOCAL_FENCE;
+                                       }
+
+                                       set_wqe_32bit_value(wqe->wqe_words, NES_IWARP_SQ_WQE_RDMA_STAG_IDX,
+                                                       ib_wr->wr.rdma.rkey);
+                                       set_wqe_64bit_value(wqe->wqe_words, NES_IWARP_SQ_WQE_RDMA_TO_LOW_IDX,
+                                                       ib_wr->wr.rdma.remote_addr);
+
+                                       if ((ib_wr->send_flags & IB_SEND_INLINE) &&
+                                                       ((nes_drv_opt & NES_DRV_OPT_NO_INLINE_DATA) == 0) &&
+                                                       (ib_wr->sg_list[0].length <= 64)) {
+                                               memcpy(&wqe->wqe_words[NES_IWARP_SQ_WQE_IMM_DATA_START_IDX],
+                                                              (void *)(unsigned long)ib_wr->sg_list[0].addr, ib_wr->sg_list[0].length);
+                                               set_wqe_32bit_value(wqe->wqe_words, NES_IWARP_SQ_WQE_TOTAL_PAYLOAD_IDX,
+                                                               ib_wr->sg_list[0].length);
+                                               wqe_misc |= NES_IWARP_SQ_WQE_IMM_DATA;
+                                       } else {
+                                               fill_wqe_sg_send(wqe, ib_wr, 1);
+                                       }
+                                       wqe->wqe_words[NES_IWARP_SQ_WQE_RDMA_LENGTH_IDX] =
+                                                       wqe->wqe_words[NES_IWARP_SQ_WQE_TOTAL_PAYLOAD_IDX];
+                                       break;
+                               case IB_WR_RDMA_READ:
+                                       /* iWARP only supports 1 sge for RDMA reads */
+                                       if (ib_wr->num_sge > 1) {
+                                               nes_debug(NES_DBG_IW_TX, "Exceeded max sge, ib_wr=%u, max=1\n",
+                                                               ib_wr->num_sge);
+                                               err = -EINVAL;
+                                               break;
+                                       }
+                                       wqe_misc = NES_IWARP_SQ_OP_RDMAR;
+                                       set_wqe_64bit_value(wqe->wqe_words, NES_IWARP_SQ_WQE_RDMA_TO_LOW_IDX,
+                                                       ib_wr->wr.rdma.remote_addr);
+                                       set_wqe_32bit_value(wqe->wqe_words, NES_IWARP_SQ_WQE_RDMA_STAG_IDX,
+                                                       ib_wr->wr.rdma.rkey);
+                                       set_wqe_32bit_value(wqe->wqe_words, NES_IWARP_SQ_WQE_RDMA_LENGTH_IDX,
+                                                       ib_wr->sg_list->length);
+                                       set_wqe_64bit_value(wqe->wqe_words, NES_IWARP_SQ_WQE_FRAG0_LOW_IDX,
+                                                       ib_wr->sg_list->addr);
+                                       set_wqe_32bit_value(wqe->wqe_words, NES_IWARP_SQ_WQE_STAG0_IDX,
+                                                       ib_wr->sg_list->lkey);
+                                       break;
+                               default:
+                                       /* error */
+                                       err = -EINVAL;
+                                       break;
+                       }
+
+               if (ib_wr->send_flags & IB_SEND_SIGNALED) {
+                       wqe_misc |= NES_IWARP_SQ_WQE_SIGNALED_COMPL;
+               }
+               wqe->wqe_words[NES_IWARP_SQ_WQE_MISC_IDX] = cpu_to_le32(wqe_misc);
+
+               ib_wr = ib_wr->next;
+               head++;
+               wqe_count++;
+               if (head >= qsize)
+                       head = 0;
+
+       }
+
+       nesqp->hwqp.sq_head = head;
+       barrier();
+       while (wqe_count) {
+               counter = min(wqe_count, ((u32)255));
+               wqe_count -= counter;
+               nes_write32(nesdev->regs + NES_WQE_ALLOC,
+                               (counter << 24) | 0x00800000 | nesqp->hwqp.qp_id);
+       }
+
+               spin_unlock_irqrestore(&nesqp->lock, flags);
+
+       if (err)
+               *bad_wr = ib_wr;
+       return err;
+}
+
+
+/**
+ * nes_post_recv
+ */
+static int nes_post_recv(struct ib_qp *ibqp, struct ib_recv_wr *ib_wr,
+               struct ib_recv_wr **bad_wr)
+{
+       u64 u64temp;
+       unsigned long flags = 0;
+       struct nes_vnic *nesvnic = to_nesvnic(ibqp->device);
+       struct nes_device *nesdev = nesvnic->nesdev;
+       struct nes_qp *nesqp = to_nesqp(ibqp);
+       struct nes_hw_qp_wqe *wqe;
+       int err = 0;
+       int sge_index;
+       u32 qsize = nesqp->hwqp.rq_size;
+       u32 head;
+       u32 wqe_count = 0;
+       u32 counter;
+       u32 total_payload_length;
+
+       if (nesqp->ibqp_state > IB_QPS_RTS)
+               return -EINVAL;
+
+               spin_lock_irqsave(&nesqp->lock, flags);
+
+       head = nesqp->hwqp.rq_head;
+
+       while (ib_wr) {
+               if (ib_wr->num_sge > nesdev->nesadapter->max_sge) {
+                       err = -EINVAL;
+                       break;
+               }
+               /* Check for RQ overflow */
+               if (((head + (2 * qsize) - nesqp->hwqp.rq_tail) % qsize) == (qsize - 1)) {
+                       err = -EINVAL;
+                       break;
+               }
+
+               nes_debug(NES_DBG_IW_RX, "ibwr sge count = %u.\n", ib_wr->num_sge);
+               wqe = &nesqp->hwqp.rq_vbase[head];
+
+               /* nes_debug(NES_DBG_IW_RX, "QP%u:processing rq wqe at %p, head = %u.\n",
+                               nesqp->hwqp.qp_id, wqe, head); */
+               nes_fill_init_qp_wqe(wqe, nesqp, head);
+               u64temp = (u64)(ib_wr->wr_id);
+               set_wqe_64bit_value(wqe->wqe_words, NES_IWARP_SQ_WQE_COMP_SCRATCH_LOW_IDX,
+                                       u64temp);
+               total_payload_length = 0;
+               for (sge_index=0; sge_index < ib_wr->num_sge; sge_index++) {
+                       set_wqe_64bit_value(wqe->wqe_words, NES_IWARP_RQ_WQE_FRAG0_LOW_IDX+(sge_index*4),
+                                       ib_wr->sg_list[sge_index].addr);
+                       set_wqe_32bit_value(wqe->wqe_words, NES_IWARP_RQ_WQE_LENGTH0_IDX+(sge_index*4),
+                                       ib_wr->sg_list[sge_index].length);
+                       set_wqe_32bit_value(wqe->wqe_words,NES_IWARP_RQ_WQE_STAG0_IDX+(sge_index*4),
+                                       ib_wr->sg_list[sge_index].lkey);
+
+                       total_payload_length += ib_wr->sg_list[sge_index].length;
+               }
+               set_wqe_32bit_value(wqe->wqe_words, NES_IWARP_RQ_WQE_TOTAL_PAYLOAD_IDX,
+                                       total_payload_length);
+
+               ib_wr = ib_wr->next;
+               head++;
+               wqe_count++;
+               if (head >= qsize)
+                       head = 0;
+       }
+
+       nesqp->hwqp.rq_head = head;
+       barrier();
+       while (wqe_count) {
+               counter = min(wqe_count, ((u32)255));
+               wqe_count -= counter;
+               nes_write32(nesdev->regs+NES_WQE_ALLOC, (counter<<24) | nesqp->hwqp.qp_id);
+       }
+
+               spin_unlock_irqrestore(&nesqp->lock, flags);
+
+       if (err)
+               *bad_wr = ib_wr;
+       return err;
+}
+
+
+/**
+ * nes_poll_cq
+ */
+static int nes_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry)
+{
+       u64 u64temp;
+       u64 wrid;
+       /* u64 u64temp; */
+       unsigned long flags = 0;
+       struct nes_vnic *nesvnic = to_nesvnic(ibcq->device);
+       struct nes_device *nesdev = nesvnic->nesdev;
+       struct nes_cq *nescq = to_nescq(ibcq);
+       struct nes_qp *nesqp;
+       struct nes_hw_cqe cqe;
+       u32 head;
+       u32 wq_tail;
+       u32 cq_size;
+       u32 cqe_count = 0;
+       u32 wqe_index;
+       u32 u32temp;
+       /* u32 counter; */
+
+       nes_debug(NES_DBG_CQ, "\n");
+
+               spin_lock_irqsave(&nescq->lock, flags);
+
+       head = nescq->hw_cq.cq_head;
+       cq_size = nescq->hw_cq.cq_size;
+
+       while (cqe_count < num_entries) {
+               if (le32_to_cpu(nescq->hw_cq.cq_vbase[head].cqe_words[NES_CQE_OPCODE_IDX]) &
+                               NES_CQE_VALID) {
+                       cqe = nescq->hw_cq.cq_vbase[head];
+                       nescq->hw_cq.cq_vbase[head].cqe_words[NES_CQE_OPCODE_IDX] = 0;
+                       u32temp = le32_to_cpu(cqe.cqe_words[NES_CQE_COMP_COMP_CTX_LOW_IDX]);
+                       wqe_index = u32temp &
+                                       (nesdev->nesadapter->max_qp_wr - 1);
+                       u32temp &= ~(NES_SW_CONTEXT_ALIGN-1);
+                       /* parse CQE, get completion context from WQE (either rq or sq */
+                       u64temp = (((u64)(le32_to_cpu(cqe.cqe_words[NES_CQE_COMP_COMP_CTX_HIGH_IDX])))<<32) |
+                                       ((u64)u32temp);
+                       nesqp = *((struct nes_qp **)&u64temp);
+                       memset(entry, 0, sizeof *entry);
+                       if (cqe.cqe_words[NES_CQE_ERROR_CODE_IDX] == 0) {
+                               entry->status = IB_WC_SUCCESS;
+                       } else {
+                               entry->status = IB_WC_WR_FLUSH_ERR;
+                       }
+
+                       entry->qp = &nesqp->ibqp;
+                       entry->src_qp = nesqp->hwqp.qp_id;
+
+                       if (le32_to_cpu(cqe.cqe_words[NES_CQE_OPCODE_IDX]) & NES_CQE_SQ) {
+                               if (nesqp->skip_lsmm) {
+                                       nesqp->skip_lsmm = 0;
+                                       wq_tail = nesqp->hwqp.sq_tail++;
+                               }
+
+                               /* Working on a SQ Completion*/
+                               wq_tail = wqe_index;
+                               nesqp->hwqp.sq_tail = (wqe_index+1)&(nesqp->hwqp.sq_size - 1);
+                               wrid = (((u64)(cpu_to_le32((u32)nesqp->hwqp.sq_vbase[wq_tail].
+                                               wqe_words[NES_IWARP_SQ_WQE_COMP_SCRATCH_HIGH_IDX]))) << 32) |
+                                               ((u64)(cpu_to_le32((u32)nesqp->hwqp.sq_vbase[wq_tail].
+                                               wqe_words[NES_IWARP_SQ_WQE_COMP_SCRATCH_LOW_IDX])));
+                               entry->byte_len = le32_to_cpu(nesqp->hwqp.sq_vbase[wq_tail].
+                                               wqe_words[NES_IWARP_SQ_WQE_TOTAL_PAYLOAD_IDX]);
+
+                               switch (le32_to_cpu(nesqp->hwqp.sq_vbase[wq_tail].
+                                               wqe_words[NES_IWARP_SQ_WQE_MISC_IDX]) & 0x3f) {
+                                       case NES_IWARP_SQ_OP_RDMAW:
+                                               nes_debug(NES_DBG_CQ, "Operation = RDMA WRITE.\n");
+                                               entry->opcode = IB_WC_RDMA_WRITE;
+                                               break;
+                                       case NES_IWARP_SQ_OP_RDMAR:
+                                               nes_debug(NES_DBG_CQ, "Operation = RDMA READ.\n");
+                                               entry->opcode = IB_WC_RDMA_READ;
+                                               entry->byte_len = le32_to_cpu(nesqp->hwqp.sq_vbase[wq_tail].
+                                                               wqe_words[NES_IWARP_SQ_WQE_RDMA_LENGTH_IDX]);
+                                               break;
+                                       case NES_IWARP_SQ_OP_SENDINV:
+                                       case NES_IWARP_SQ_OP_SENDSEINV:
+                                       case NES_IWARP_SQ_OP_SEND:
+                                       case NES_IWARP_SQ_OP_SENDSE:
+                                               nes_debug(NES_DBG_CQ, "Operation = Send.\n");
+                                               entry->opcode = IB_WC_SEND;
+                                               break;
+                               }
+                       } else {
+                               /* Working on a RQ Completion*/
+                               wq_tail = wqe_index;
+                                       nesqp->hwqp.rq_tail = (wqe_index+1)&(nesqp->hwqp.rq_size - 1);
+                               entry->byte_len = le32_to_cpu(cqe.cqe_words[NES_CQE_PAYLOAD_LENGTH_IDX]);
+                               wrid = ((u64)(le32_to_cpu(nesqp->hwqp.rq_vbase[wq_tail].wqe_words[NES_IWARP_RQ_WQE_COMP_SCRATCH_LOW_IDX]))) |
+                                       ((u64)(le32_to_cpu(nesqp->hwqp.rq_vbase[wq_tail].wqe_words[NES_IWARP_RQ_WQE_COMP_SCRATCH_HIGH_IDX]))<<32);
+                                       entry->opcode = IB_WC_RECV;
+                       }
+                       entry->wr_id = wrid;
+
+                       if (++head >= cq_size)
+                               head = 0;
+                       cqe_count++;
+                       nescq->polled_completions++;
+                       if ((nescq->polled_completions > (cq_size / 2)) ||
+                                       (nescq->polled_completions == 255)) {
+                               nes_debug(NES_DBG_CQ, "CQ%u Issuing CQE Allocate since more than half of cqes"
+                                               " are pending %u of %u.\n",
+                                               nescq->hw_cq.cq_number, nescq->polled_completions, cq_size);
+                               nes_write32(nesdev->regs+NES_CQE_ALLOC,
+                                               nescq->hw_cq.cq_number | (nescq->polled_completions << 16));
+                               nescq->polled_completions = 0;
+                       }
+                       entry++;
+               } else
+                       break;
+       }
+
+       if (nescq->polled_completions) {
+               nes_write32(nesdev->regs+NES_CQE_ALLOC,
+                               nescq->hw_cq.cq_number | (nescq->polled_completions << 16));
+               nescq->polled_completions = 0;
+       }
+
+       nescq->hw_cq.cq_head = head;
+       nes_debug(NES_DBG_CQ, "Reporting %u completions for CQ%u.\n",
+                       cqe_count, nescq->hw_cq.cq_number);
+
+               spin_unlock_irqrestore(&nescq->lock, flags);
+
+       return cqe_count;
+}
+
+
+/**
+ * nes_req_notify_cq
+ */
+static int nes_req_notify_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags notify_flags)
+               {
+       struct nes_vnic *nesvnic = to_nesvnic(ibcq->device);
+       struct nes_device *nesdev = nesvnic->nesdev;
+       struct nes_cq *nescq = to_nescq(ibcq);
+       u32 cq_arm;
+
+       nes_debug(NES_DBG_CQ, "Requesting notification for CQ%u.\n",
+                       nescq->hw_cq.cq_number);
+
+       cq_arm = nescq->hw_cq.cq_number;
+       if ((notify_flags & IB_CQ_SOLICITED_MASK) == IB_CQ_NEXT_COMP)
+               cq_arm |= NES_CQE_ALLOC_NOTIFY_NEXT;
+       else if ((notify_flags & IB_CQ_SOLICITED_MASK) == IB_CQ_SOLICITED)
+               cq_arm |= NES_CQE_ALLOC_NOTIFY_SE;
+       else
+               return -EINVAL;
+
+       nes_write32(nesdev->regs+NES_CQE_ALLOC, cq_arm);
+       nes_read32(nesdev->regs+NES_CQE_ALLOC);
+
+       return 0;
+}
+
+
+/**
+ * nes_init_ofa_device
+ */
+struct nes_ib_device *nes_init_ofa_device(struct net_device *netdev)
+{
+       struct nes_ib_device *nesibdev;
+       struct nes_vnic *nesvnic = netdev_priv(netdev);
+       struct nes_device *nesdev = nesvnic->nesdev;
+
+       nesibdev = (struct nes_ib_device *)ib_alloc_device(sizeof(struct nes_ib_device));
+       if (nesibdev == NULL) {
+               return NULL;
+       }
+       strlcpy(nesibdev->ibdev.name, "nes%d", IB_DEVICE_NAME_MAX);
+       nesibdev->ibdev.owner = THIS_MODULE;
+
+       nesibdev->ibdev.node_type = RDMA_NODE_RNIC;
+       memset(&nesibdev->ibdev.node_guid, 0, sizeof(nesibdev->ibdev.node_guid));
+       memcpy(&nesibdev->ibdev.node_guid, netdev->dev_addr, 6);
+
+       nesibdev->ibdev.uverbs_cmd_mask =
+                       (1ull << IB_USER_VERBS_CMD_GET_CONTEXT) |
+                       (1ull << IB_USER_VERBS_CMD_QUERY_DEVICE) |
+                       (1ull << IB_USER_VERBS_CMD_QUERY_PORT) |
+                       (1ull << IB_USER_VERBS_CMD_ALLOC_PD) |
+                       (1ull << IB_USER_VERBS_CMD_DEALLOC_PD) |
+                       (1ull << IB_USER_VERBS_CMD_REG_MR) |
+                       (1ull << IB_USER_VERBS_CMD_DEREG_MR) |
+                       (1ull << IB_USER_VERBS_CMD_CREATE_COMP_CHANNEL) |
+                       (1ull << IB_USER_VERBS_CMD_CREATE_CQ) |
+                       (1ull << IB_USER_VERBS_CMD_DESTROY_CQ) |
+                       (1ull << IB_USER_VERBS_CMD_CREATE_AH) |
+                       (1ull << IB_USER_VERBS_CMD_DESTROY_AH) |
+                       (1ull << IB_USER_VERBS_CMD_REQ_NOTIFY_CQ) |
+                       (1ull << IB_USER_VERBS_CMD_CREATE_QP) |
+                       (1ull << IB_USER_VERBS_CMD_MODIFY_QP) |
+                       (1ull << IB_USER_VERBS_CMD_POLL_CQ) |
+                       (1ull << IB_USER_VERBS_CMD_DESTROY_QP) |
+                       (1ull << IB_USER_VERBS_CMD_ALLOC_MW) |
+                       (1ull << IB_USER_VERBS_CMD_BIND_MW) |
+                       (1ull << IB_USER_VERBS_CMD_DEALLOC_MW) |
+                       (1ull << IB_USER_VERBS_CMD_POST_RECV) |
+                       (1ull << IB_USER_VERBS_CMD_POST_SEND);
+
+       nesibdev->ibdev.phys_port_cnt = 1;
+       nesibdev->ibdev.num_comp_vectors = 1;
+       nesibdev->ibdev.dma_device = &nesdev->pcidev->dev;
+       nesibdev->ibdev.class_dev.dev = &nesdev->pcidev->dev;
+       nesibdev->ibdev.query_device = nes_query_device;
+       nesibdev->ibdev.query_port = nes_query_port;
+       nesibdev->ibdev.modify_port = nes_modify_port;
+       nesibdev->ibdev.query_pkey = nes_query_pkey;
+       nesibdev->ibdev.query_gid = nes_query_gid;
+       nesibdev->ibdev.alloc_ucontext = nes_alloc_ucontext;
+       nesibdev->ibdev.dealloc_ucontext = nes_dealloc_ucontext;
+       nesibdev->ibdev.mmap = nes_mmap;
+       nesibdev->ibdev.alloc_pd = nes_alloc_pd;
+       nesibdev->ibdev.dealloc_pd = nes_dealloc_pd;
+       nesibdev->ibdev.create_ah = nes_create_ah;
+       nesibdev->ibdev.destroy_ah = nes_destroy_ah;
+       nesibdev->ibdev.create_qp = nes_create_qp;
+       nesibdev->ibdev.modify_qp = nes_modify_qp;
+       nesibdev->ibdev.query_qp = nes_query_qp;
+       nesibdev->ibdev.destroy_qp = nes_destroy_qp;
+       nesibdev->ibdev.create_cq = nes_create_cq;
+       nesibdev->ibdev.destroy_cq = nes_destroy_cq;
+       nesibdev->ibdev.poll_cq = nes_poll_cq;
+       nesibdev->ibdev.get_dma_mr = nes_get_dma_mr;
+       nesibdev->ibdev.reg_phys_mr = nes_reg_phys_mr;
+       nesibdev->ibdev.reg_user_mr = nes_reg_user_mr;
+       nesibdev->ibdev.dereg_mr = nes_dereg_mr;
+       nesibdev->ibdev.alloc_mw = nes_alloc_mw;
+       nesibdev->ibdev.dealloc_mw = nes_dealloc_mw;
+       nesibdev->ibdev.bind_mw = nes_bind_mw;
+
+       nesibdev->ibdev.alloc_fmr = nes_alloc_fmr;
+       nesibdev->ibdev.unmap_fmr = nes_unmap_fmr;
+       nesibdev->ibdev.dealloc_fmr = nes_dealloc_fmr;
+       nesibdev->ibdev.map_phys_fmr = nes_map_phys_fmr;
+
+       nesibdev->ibdev.attach_mcast = nes_multicast_attach;
+       nesibdev->ibdev.detach_mcast = nes_multicast_detach;
+       nesibdev->ibdev.process_mad = nes_process_mad;
+
+       nesibdev->ibdev.req_notify_cq = nes_req_notify_cq;
+       nesibdev->ibdev.post_send = nes_post_send;
+       nesibdev->ibdev.post_recv = nes_post_recv;
+
+       nesibdev->ibdev.iwcm = kzalloc(sizeof(*nesibdev->ibdev.iwcm), GFP_KERNEL);
+       if (nesibdev->ibdev.iwcm == NULL) {
+               ib_dealloc_device(&nesibdev->ibdev);
+               return NULL;
+       }
+       nesibdev->ibdev.iwcm->add_ref = nes_add_ref;
+       nesibdev->ibdev.iwcm->rem_ref = nes_rem_ref;
+       nesibdev->ibdev.iwcm->get_qp = nes_get_qp;
+       nesibdev->ibdev.iwcm->connect = nes_connect;
+       nesibdev->ibdev.iwcm->accept = nes_accept;
+       nesibdev->ibdev.iwcm->reject = nes_reject;
+       nesibdev->ibdev.iwcm->create_listen = nes_create_listen;
+       nesibdev->ibdev.iwcm->destroy_listen = nes_destroy_listen;
+
+       return nesibdev;
+}
+
+
+/**
+ * nes_destroy_ofa_device
+ */
+void nes_destroy_ofa_device(struct nes_ib_device *nesibdev)
+{
+       if (nesibdev == NULL)
+               return;
+
+       nes_unregister_ofa_device(nesibdev);
+
+       kfree(nesibdev->ibdev.iwcm);
+       ib_dealloc_device(&nesibdev->ibdev);
+}
+
+
+/**
+ * nes_register_ofa_device
+ */
+int nes_register_ofa_device(struct nes_ib_device *nesibdev)
+{
+       struct nes_vnic *nesvnic = nesibdev->nesvnic;
+       struct nes_device *nesdev = nesvnic->nesdev;
+       struct nes_adapter *nesadapter = nesdev->nesadapter;
+       int i, ret;
+
+       ret = ib_register_device(&nesvnic->nesibdev->ibdev);
+       if (ret) {
+               return ret;
+       }
+
+       /* Get the resources allocated to this device */
+       nesibdev->max_cq = (nesadapter->max_cq-NES_FIRST_QPN) / nesadapter->port_count;
+       nesibdev->max_mr = nesadapter->max_mr / nesadapter->port_count;
+       nesibdev->max_qp = (nesadapter->max_qp-NES_FIRST_QPN) / nesadapter->port_count;
+       nesibdev->max_pd = nesadapter->max_pd / nesadapter->port_count;
+
+       for (i = 0; i < ARRAY_SIZE(nes_class_attributes); ++i) {
+               ret = class_device_create_file(&nesibdev->ibdev.class_dev, nes_class_attributes[i]);
+               if (ret) {
+                       while (i > 0) {
+                               i--;
+                               class_device_remove_file(&nesibdev->ibdev.class_dev,
+                                               nes_class_attributes[i]);
+                       }
+                       ib_unregister_device(&nesibdev->ibdev);
+                       return ret;
+               }
+       }
+
+       nesvnic->of_device_registered = 1;
+
+       return 0;
+}
+
+
+/**
+ * nes_unregister_ofa_device
+ */
+void nes_unregister_ofa_device(struct nes_ib_device *nesibdev)
+{
+       struct nes_vnic *nesvnic = nesibdev->nesvnic;
+       int i;
+
+       if (nesibdev == NULL)
+               return;
+
+       for (i = 0; i < ARRAY_SIZE(nes_class_attributes); ++i) {
+               class_device_remove_file(&nesibdev->ibdev.class_dev, nes_class_attributes[i]);
+       }
+
+       if (nesvnic->of_device_registered) {
+               ib_unregister_device(&nesibdev->ibdev);
+       }
+
+       nesvnic->of_device_registered = 0;
+}
diff --git a/drivers/infiniband/hw/nes/nes_verbs.h b/drivers/infiniband/hw/nes/nes_verbs.h
new file mode 100644 (file)
index 0000000..6c6b4da
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 2006 - 2008 NetEffect, Inc. All rights reserved.
+ * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * 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.
+ *
+ */
+
+#ifndef NES_VERBS_H
+#define NES_VERBS_H
+
+struct nes_device;
+
+#define NES_MAX_USER_DB_REGIONS  4096
+#define NES_MAX_USER_WQ_REGIONS  4096
+
+struct nes_ucontext {
+       struct ib_ucontext ibucontext;
+       struct nes_device  *nesdev;
+       unsigned long      mmap_wq_offset;
+       unsigned long      mmap_cq_offset; /* to be removed */
+       int                index;               /* rnic index (minor) */
+       unsigned long      allocated_doorbells[BITS_TO_LONGS(NES_MAX_USER_DB_REGIONS)];
+       u16                mmap_db_index[NES_MAX_USER_DB_REGIONS];
+       u16                first_free_db;
+       unsigned long      allocated_wqs[BITS_TO_LONGS(NES_MAX_USER_WQ_REGIONS)];
+       struct nes_qp      *mmap_nesqp[NES_MAX_USER_WQ_REGIONS];
+       u16                first_free_wq;
+       struct list_head   cq_reg_mem_list;
+       struct list_head   qp_reg_mem_list;
+       u32                mcrqf;
+       atomic_t           usecnt;
+};
+
+struct nes_pd {
+       struct ib_pd ibpd;
+       u16          pd_id;
+       atomic_t     sqp_count;
+       u16          mmap_db_index;
+};
+
+struct nes_mr {
+       union {
+               struct ib_mr  ibmr;
+               struct ib_mw  ibmw;
+               struct ib_fmr ibfmr;
+       };
+       struct ib_umem    *region;
+       u16               pbls_used;
+       u8                mode;
+       u8                pbl_4k;
+};
+
+struct nes_hw_pb {
+       __le32 pa_low;
+       __le32 pa_high;
+};
+
+struct nes_vpbl {
+       dma_addr_t       pbl_pbase;
+       struct nes_hw_pb *pbl_vbase;
+};
+
+struct nes_root_vpbl {
+       dma_addr_t       pbl_pbase;
+       struct nes_hw_pb *pbl_vbase;
+       struct nes_vpbl  *leaf_vpbl;
+};
+
+struct nes_fmr {
+       struct nes_mr        nesmr;
+       u32                  leaf_pbl_cnt;
+       struct nes_root_vpbl root_vpbl;
+       struct ib_qp         *ib_qp;
+       int                  access_rights;
+       struct ib_fmr_attr   attr;
+};
+
+struct nes_av;
+
+struct nes_cq {
+       struct ib_cq     ibcq;
+       struct nes_hw_cq hw_cq;
+       u32              polled_completions;
+       u32              cq_mem_size;
+       spinlock_t       lock;
+       u8               virtual_cq;
+       u8               pad[3];
+};
+
+struct nes_wq {
+       spinlock_t lock;
+};
+
+struct iw_cm_id;
+struct ietf_mpa_frame;
+
+struct nes_qp {
+       struct ib_qp          ibqp;
+       void                  *allocated_buffer;
+       struct iw_cm_id       *cm_id;
+       struct workqueue_struct *wq;
+       struct work_struct    disconn_work;
+       struct nes_cq         *nesscq;
+       struct nes_cq         *nesrcq;
+       struct nes_pd         *nespd;
+       void *cm_node; /* handle of the node this QP is associated with */
+       struct ietf_mpa_frame *ietf_frame;
+       dma_addr_t            ietf_frame_pbase;
+       wait_queue_head_t     state_waitq;
+       unsigned long         socket;
+       struct nes_hw_qp      hwqp;
+       struct work_struct    work;
+       struct work_struct    ae_work;
+       enum ib_qp_state      ibqp_state;
+       u32                   iwarp_state;
+       u32                   hte_index;
+       u32                   last_aeq;
+       u32                   qp_mem_size;
+       atomic_t              refcount;
+       atomic_t              close_timer_started;
+       u32                   mmap_sq_db_index;
+       u32                   mmap_rq_db_index;
+       spinlock_t            lock;
+       struct nes_qp_context *nesqp_context;
+       dma_addr_t            nesqp_context_pbase;
+       void                  *pbl_vbase;
+       dma_addr_t            pbl_pbase;
+       struct page           *page;
+       wait_queue_head_t     kick_waitq;
+       u16                   in_disconnect;
+       u16                   private_data_len;
+       u8                    active_conn;
+       u8                    skip_lsmm;
+       u8                    user_mode;
+       u8                    hte_added;
+       u8                    hw_iwarp_state;
+       u8                    flush_issued;
+       u8                    hw_tcp_state;
+       u8                    disconn_pending;
+       u8                    destroyed;
+};
+#endif                 /* NES_VERBS_H */
index a082466f4a83d58858120addcd7dbb77c73fb47f..09f5371137a13aba0e5c7add61c1f1d0e3115ef6 100644 (file)
@@ -680,12 +680,7 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
                neigh = *to_ipoib_neigh(skb->dst->neighbour);
 
-               if (ipoib_cm_get(neigh)) {
-                       if (ipoib_cm_up(neigh)) {
-                               ipoib_cm_send(dev, skb, ipoib_cm_get(neigh));
-                               goto out;
-                       }
-               } else if (neigh->ah) {
+               if (neigh->ah)
                        if (unlikely((memcmp(&neigh->dgid.raw,
                                            skb->dst->neighbour->ha + 4,
                                            sizeof(union ib_gid))) ||
@@ -706,6 +701,12 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev)
                                goto out;
                        }
 
+               if (ipoib_cm_get(neigh)) {
+                       if (ipoib_cm_up(neigh)) {
+                               ipoib_cm_send(dev, skb, ipoib_cm_get(neigh));
+                               goto out;
+                       }
+               } else if (neigh->ah) {
                        ipoib_send(dev, skb, neigh->ah, IPOIB_QPN(skb->dst->neighbour->ha));
                        goto out;
                }
@@ -813,11 +814,9 @@ static void ipoib_neigh_cleanup(struct neighbour *n)
        struct ipoib_ah *ah = NULL;
 
        neigh = *to_ipoib_neigh(n);
-       if (neigh) {
+       if (neigh)
                priv = netdev_priv(neigh->dev);
-               ipoib_dbg(priv, "neigh_destructor for bonding device: %s\n",
-                         n->dev->name);
-       } else
+       else
                return;
        ipoib_dbg(priv,
                  "neigh_cleanup for %06x " IPOIB_GID_FMT "\n",
index 195ce7c123191896aa2946b0dc2499f13d23cbfb..fd4a49fc4773eecb1bcf8d714c29cb83479eb963 100644 (file)
@@ -204,6 +204,22 @@ out:
        return ret;
 }
 
+static int srp_new_cm_id(struct srp_target_port *target)
+{
+       struct ib_cm_id *new_cm_id;
+
+       new_cm_id = ib_create_cm_id(target->srp_host->dev->dev,
+                                   srp_cm_handler, target);
+       if (IS_ERR(new_cm_id))
+               return PTR_ERR(new_cm_id);
+
+       if (target->cm_id)
+               ib_destroy_cm_id(target->cm_id);
+       target->cm_id = new_cm_id;
+
+       return 0;
+}
+
 static int srp_create_target_ib(struct srp_target_port *target)
 {
        struct ib_qp_init_attr *init_attr;
@@ -436,6 +452,7 @@ static void srp_remove_work(struct work_struct *work)
 
 static int srp_connect_target(struct srp_target_port *target)
 {
+       int retries = 3;
        int ret;
 
        ret = srp_lookup_path(target);
@@ -468,6 +485,21 @@ static int srp_connect_target(struct srp_target_port *target)
                case SRP_DLID_REDIRECT:
                        break;
 
+               case SRP_STALE_CONN:
+                       /* Our current CM id was stale, and is now in timewait.
+                        * Try to reconnect with a new one.
+                        */
+                       if (!retries-- || srp_new_cm_id(target)) {
+                               shost_printk(KERN_ERR, target->scsi_host, PFX
+                                            "giving up on stale connection\n");
+                               target->status = -ECONNRESET;
+                               return target->status;
+                       }
+
+                       shost_printk(KERN_ERR, target->scsi_host, PFX
+                                    "retrying stale connection\n");
+                       break;
+
                default:
                        return target->status;
                }
@@ -507,7 +539,6 @@ static void srp_reset_req(struct srp_target_port *target, struct srp_request *re
 
 static int srp_reconnect_target(struct srp_target_port *target)
 {
-       struct ib_cm_id *new_cm_id;
        struct ib_qp_attr qp_attr;
        struct srp_request *req, *tmp;
        struct ib_wc wc;
@@ -526,14 +557,9 @@ static int srp_reconnect_target(struct srp_target_port *target)
         * Now get a new local CM ID so that we avoid confusing the
         * target in case things are really fouled up.
         */
-       new_cm_id = ib_create_cm_id(target->srp_host->dev->dev,
-                                   srp_cm_handler, target);
-       if (IS_ERR(new_cm_id)) {
-               ret = PTR_ERR(new_cm_id);
+       ret = srp_new_cm_id(target);
+       if (ret)
                goto err;
-       }
-       ib_destroy_cm_id(target->cm_id);
-       target->cm_id = new_cm_id;
 
        qp_attr.qp_state = IB_QPS_RESET;
        ret = ib_modify_qp(target->qp, &qp_attr, IB_QP_STATE);
@@ -1171,6 +1197,11 @@ static void srp_cm_rej_handler(struct ib_cm_id *cm_id,
                target->status = -ECONNRESET;
                break;
 
+       case IB_CM_REJ_STALE_CONN:
+               shost_printk(KERN_WARNING, shost, "  REJ reason: stale connection\n");
+               target->status = SRP_STALE_CONN;
+               break;
+
        default:
                shost_printk(KERN_WARNING, shost, "  REJ reason 0x%x\n",
                             event->param.rej_rcvd.reason);
@@ -1862,11 +1893,9 @@ static ssize_t srp_create_target(struct class_device *class_dev,
        if (ret)
                goto err;
 
-       target->cm_id = ib_create_cm_id(host->dev->dev, srp_cm_handler, target);
-       if (IS_ERR(target->cm_id)) {
-               ret = PTR_ERR(target->cm_id);
+       ret = srp_new_cm_id(target);
+       if (ret)
                goto err_free;
-       }
 
        target->qp_in_error = 0;
        ret = srp_connect_target(target);
index 4a3c1f37e4c206bea4674e76576596ac5a851bca..cb6eb816024a881061d0ac48c4a423fa118fd2e8 100644 (file)
@@ -54,6 +54,7 @@ enum {
 
        SRP_PORT_REDIRECT       = 1,
        SRP_DLID_REDIRECT       = 2,
+       SRP_STALE_CONN          = 3,
 
        SRP_MAX_LUN             = 512,
        SRP_DEF_SG_TABLESIZE    = 12,
index 1dc2ac9f3d1cce12d1516c07b567c4656b28ee54..c5600ac5feb3aa6c99dba80628d501d515488ebf 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/init.h>
 #include <linux/gameport.h>
 #include <linux/wait.h>
-#include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
 #include <linux/kthread.h>
index e5f4da9283406920945cee029758f3d0f8fbab94..05e3494cf8b87f4bb80fc9b904cda36099e6b6e5 100644 (file)
@@ -42,7 +42,6 @@
 #include <linux/delay.h>
 #include <linux/platform_device.h>
 #include <linux/input.h>
-#include <linux/irq.h>
 
 #include <asm/portmux.h>
 #include <asm/mach/bf54x_keys.h>
index e6696b3c9416c066c6c7411e7318df4cb6326e1d..986f93cfc6b8a0211020e8978f374c9c29b272d2 100644 (file)
@@ -17,7 +17,6 @@
  */
 #include <linux/device.h>
 #include <linux/errno.h>
-#include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
 #include <linux/input.h>
index 3e99df6be08465affbbb0550fd5be59688f71c39..adc3bd6e7f7bbc9a0d038d748dd3f95794a46f8f 100644 (file)
@@ -141,7 +141,7 @@ static void gscps2_flush(struct gscps2port *ps2port)
 /*
  * gscps2_writeb_output() - write a byte to the port
  *
- * returns 1 on sucess, 0 on error
+ * returns 1 on success, 0 on error
  */
 
 static inline int gscps2_writeb_output(struct gscps2port *ps2port, u8 data)
index 7549939b9535634de87ddb09a829b186758303e0..986a8365e37fb6e867248932bc6f7a66edc97784 100644 (file)
@@ -27,7 +27,6 @@
 #include <linux/kthread.h>
 #include <linux/freezer.h>
 
-#include <sound/driver.h>
 #include <sound/core.h>
 #include <sound/ac97_codec.h>
 
index a19b7ffe9aceabdfbbf3fb5d7b5af01d4c0c8749..e39c5c1f623edf096ba9fb7c86ba34bc4a3849e7 100644 (file)
@@ -106,7 +106,7 @@ DbgRegister (char *drvName, char *drvTag, unsigned long dbgMask)
   return (1) ;
  }
 /*
- * Check if we registered whith an old maint driver (see debuglib.h)
+ * Check if we registered with an old maint driver (see debuglib.h)
  */
  if ( myDriverDebugHandle.dbg_end != NULL
    /* location of 'dbg_prt' in _OldDbgHandle_ struct */
index 11b3b9edd1d6f8f1a15dcd9137f02add7f73d887..016410cf227340e679e81a88f662e7fc8a1b14cb 100644 (file)
@@ -177,7 +177,7 @@ DBG_DECL(PRV3)
 } }
 #endif
 /*
- * For event level debug use a separate define, the paramete are
+ * For event level debug use a separate define, the parameter are
  * different and cause compiler errors on some systems.
  */
 #define DBG_EVL_ID(args) \
index ce8df38789087c4f7c85b056ba033644d3a1be00..10760b3c5eb56bda220b5b6b0d7390241d2b0a6d 100644 (file)
@@ -285,7 +285,7 @@ byte pr_dpc(ADAPTER * a)
                 a->ram_in(a, &RcIn->RcId),
                 a->ram_in(a, &RcIn->RcCh),
                 a->ram_inw(a, &RcIn->Reference),
-                tmp[0],  /* type of extended informtion */
+                tmp[0],  /* type of extended information */
                 tmp[1]); /* extended information        */
         a->ram_out(a, &RcIn->Rc, 0);
       }
index ccd35d047ec8c314dc337e827ca3ad58b45ae767..b9177ca4369a8d614eb8005335bacef00843fd0e 100644 (file)
@@ -4941,7 +4941,7 @@ void sig_ind(PLCI   * plci)
       /* b = IE1                */
       /* S = IE1 length + cont. */
       /* b = IE2                */
-      /* S = IE2 lenght + cont. */
+      /* S = IE2 length + cont. */
       sendf(plci->appl,
         _MANUFACTURER_I,
         Id,
index f85450146bdcb8e18e8c192199c086f063c1efa1..d3999a8e9f88cb55516cde292fd04af447ae32b5 100644 (file)
@@ -541,7 +541,7 @@ hycapi_rx_capipkt(hysdn_card * card, unsigned char *buf, unsigned short len)
        }
        ctrl = &cinfo->capi_ctrl;
        if(len < CAPI_MSG_BASELEN) {
-               printk(KERN_ERR "HYSDN Card%d: invalid CAPI-message, lenght %d!\n",
+               printk(KERN_ERR "HYSDN Card%d: invalid CAPI-message, length %d!\n",
                       card->myid, len);
                return;
        }       
index 64c66b3769c99edf05af6ae8d104a70a8240f2e1..4a938780dfc380e187b058afcd4da96be6cdf3f8 100644 (file)
@@ -137,12 +137,14 @@ err_out:
 EXPORT_SYMBOL_GPL(led_classdev_register);
 
 /**
- * led_classdev_unregister - unregisters a object of led_properties class.
+ * __led_classdev_unregister - unregisters a object of led_properties class.
  * @led_cdev: the led device to unregister
+ * @suspended: indicates whether system-wide suspend or resume is in progress
  *
  * Unregisters a previously registered via led_classdev_register object.
  */
-void led_classdev_unregister(struct led_classdev *led_cdev)
+void __led_classdev_unregister(struct led_classdev *led_cdev,
+                                     bool suspended)
 {
        device_remove_file(led_cdev->dev, &dev_attr_brightness);
 #ifdef CONFIG_LEDS_TRIGGERS
@@ -153,13 +155,16 @@ void led_classdev_unregister(struct led_classdev *led_cdev)
        up_write(&led_cdev->trigger_lock);
 #endif
 
-       device_unregister(led_cdev->dev);
+       if (suspended)
+               device_pm_schedule_removal(led_cdev->dev);
+       else
+               device_unregister(led_cdev->dev);
 
        down_write(&leds_list_lock);
        list_del(&led_cdev->node);
        up_write(&leds_list_lock);
 }
-EXPORT_SYMBOL_GPL(led_classdev_unregister);
+EXPORT_SYMBOL_GPL(__led_classdev_unregister);
 
 static int __init leds_init(void)
 {
index e2eec38c83c2ef21248353d132e3308810e1e17d..84f85e23cca7a65a86b3ffa3647953373c5339b3 100644 (file)
@@ -52,57 +52,82 @@ struct lguest_device {
 /*D:130
  * Device configurations
  *
- * The configuration information for a device consists of a series of fields.
- * We don't really care what they are: the Launcher set them up, and the driver
- * will look at them during setup.
+ * The configuration information for a device consists of one or more
+ * virtqueues, a feature bitmaks, and some configuration bytes.  The
+ * configuration bytes don't really matter to us: the Launcher sets them up, and
+ * the driver will look at them during setup.
  *
- * For us these fields come immediately after that device's descriptor in the
- * lguest_devices page.
- *
- * Each field starts with a "type" byte, a "length" byte, then that number of
- * bytes of configuration information.  The device descriptor tells us the
- * total configuration length so we know when we've reached the last field. */
+ * A convenient routine to return the device's virtqueue config array:
+ * immediately after the descriptor. */
+static struct lguest_vqconfig *lg_vq(const struct lguest_device_desc *desc)
+{
+       return (void *)(desc + 1);
+}
 
-/* type + length bytes */
-#define FHDR_LEN 2
+/* The features come immediately after the virtqueues. */
+static u8 *lg_features(const struct lguest_device_desc *desc)
+{
+       return (void *)(lg_vq(desc) + desc->num_vq);
+}
 
-/* This finds the first field of a given type for a device's configuration. */
-static void *lg_find(struct virtio_device *vdev, u8 type, unsigned int *len)
+/* The config space comes after the two feature bitmasks. */
+static u8 *lg_config(const struct lguest_device_desc *desc)
 {
-       struct lguest_device_desc *desc = to_lgdev(vdev)->desc;
-       int i;
-
-       for (i = 0; i < desc->config_len; i += FHDR_LEN + desc->config[i+1]) {
-               if (desc->config[i] == type) {
-                       /* Mark it used, so Host can know we looked at it, and
-                        * also so we won't find the same one twice. */
-                       desc->config[i] |= 0x80;
-                       /* Remember, the second byte is the length. */
-                       *len = desc->config[i+1];
-                       /* We return a pointer to the field header. */
-                       return desc->config + i;
-               }
-       }
+       return lg_features(desc) + desc->feature_len * 2;
+}
 
-       /* Not found: return NULL for failure. */
-       return NULL;
+/* The total size of the config page used by this device (incl. desc) */
+static unsigned desc_size(const struct lguest_device_desc *desc)
+{
+       return sizeof(*desc)
+               + desc->num_vq * sizeof(struct lguest_vqconfig)
+               + desc->feature_len * 2
+               + desc->config_len;
+}
+
+/* This tests (and acknowleges) a feature bit. */
+static bool lg_feature(struct virtio_device *vdev, unsigned fbit)
+{
+       struct lguest_device_desc *desc = to_lgdev(vdev)->desc;
+       u8 *features;
+
+       /* Obviously if they ask for a feature off the end of our feature
+        * bitmap, it's not set. */
+       if (fbit / 8 > desc->feature_len)
+               return false;
+
+       /* The feature bitmap comes after the virtqueues. */
+       features = lg_features(desc);
+       if (!(features[fbit / 8] & (1 << (fbit % 8))))
+               return false;
+
+       /* We set the matching bit in the other half of the bitmap to tell the
+        * Host we want to use this feature.  We don't use this yet, but we
+        * could in future. */
+       features[desc->feature_len + fbit / 8] |= (1 << (fbit % 8));
+       return true;
 }
 
 /* Once they've found a field, getting a copy of it is easy. */
-static void lg_get(struct virtio_device *vdev, void *token,
+static void lg_get(struct virtio_device *vdev, unsigned int offset,
                   void *buf, unsigned len)
 {
-       /* Check they didn't ask for more than the length of the field! */
-       BUG_ON(len > ((u8 *)token)[1]);
-       memcpy(buf, token + FHDR_LEN, len);
+       struct lguest_device_desc *desc = to_lgdev(vdev)->desc;
+
+       /* Check they didn't ask for more than the length of the config! */
+       BUG_ON(offset + len > desc->config_len);
+       memcpy(buf, lg_config(desc) + offset, len);
 }
 
 /* Setting the contents is also trivial. */
-static void lg_set(struct virtio_device *vdev, void *token,
+static void lg_set(struct virtio_device *vdev, unsigned int offset,
                   const void *buf, unsigned len)
 {
-       BUG_ON(len > ((u8 *)token)[1]);
-       memcpy(token + FHDR_LEN, buf, len);
+       struct lguest_device_desc *desc = to_lgdev(vdev)->desc;
+
+       /* Check they didn't ask for more than the length of the config! */
+       BUG_ON(offset + len > desc->config_len);
+       memcpy(lg_config(desc) + offset, buf, len);
 }
 
 /* The operations to get and set the status word just access the status field
@@ -114,9 +139,20 @@ static u8 lg_get_status(struct virtio_device *vdev)
 
 static void lg_set_status(struct virtio_device *vdev, u8 status)
 {
+       BUG_ON(!status);
        to_lgdev(vdev)->desc->status = status;
 }
 
+/* To reset the device, we (ab)use the NOTIFY hypercall, with the descriptor
+ * address of the device.  The Host will zero the status and all the
+ * features. */
+static void lg_reset(struct virtio_device *vdev)
+{
+       unsigned long offset = (void *)to_lgdev(vdev)->desc - lguest_devices;
+
+       hcall(LHCALL_NOTIFY, (max_pfn<<PAGE_SHIFT) + offset, 0, 0);
+}
+
 /*
  * Virtqueues
  *
@@ -165,39 +201,29 @@ static void lg_notify(struct virtqueue *vq)
  *
  * So we provide devices with a "find virtqueue and set it up" function. */
 static struct virtqueue *lg_find_vq(struct virtio_device *vdev,
-                                   bool (*callback)(struct virtqueue *vq))
+                                   unsigned index,
+                                   void (*callback)(struct virtqueue *vq))
 {
+       struct lguest_device *ldev = to_lgdev(vdev);
        struct lguest_vq_info *lvq;
        struct virtqueue *vq;
-       unsigned int len;
-       void *token;
        int err;
 
-       /* Look for a field of the correct type to mark a virtqueue.  Note that
-        * if this succeeds, then the type will be changed so it won't be found
-        * again, and future lg_find_vq() calls will find the next
-        * virtqueue (if any). */
-       token = vdev->config->find(vdev, VIRTIO_CONFIG_F_VIRTQUEUE, &len);
-       if (!token)
+       /* We must have this many virtqueues. */
+       if (index >= ldev->desc->num_vq)
                return ERR_PTR(-ENOENT);
 
        lvq = kmalloc(sizeof(*lvq), GFP_KERNEL);
        if (!lvq)
                return ERR_PTR(-ENOMEM);
 
-       /* Note: we could use a configuration space inside here, just like we
-        * do for the device.  This would allow expansion in future, because
-        * our configuration system is designed to be expansible.  But this is
-        * way easier. */
-       if (len != sizeof(lvq->config)) {
-               dev_err(&vdev->dev, "Unexpected virtio config len %u\n", len);
-               err = -EIO;
-               goto free_lvq;
-       }
-       /* Make a copy of the "struct lguest_vqconfig" field.  We need a copy
-        * because the config space might not be aligned correctly. */
-       vdev->config->get(vdev, token, &lvq->config, sizeof(lvq->config));
+       /* Make a copy of the "struct lguest_vqconfig" entry, which sits after
+        * the descriptor.  We need a copy because the config space might not
+        * be aligned correctly. */
+       memcpy(&lvq->config, lg_vq(ldev->desc)+index, sizeof(lvq->config));
 
+       printk("Mapping virtqueue %i addr %lx\n", index,
+              (unsigned long)lvq->config.pfn << PAGE_SHIFT);
        /* Figure out how many pages the ring will take, and map that memory */
        lvq->pages = lguest_map((unsigned long)lvq->config.pfn << PAGE_SHIFT,
                                DIV_ROUND_UP(vring_size(lvq->config.num,
@@ -259,11 +285,12 @@ static void lg_del_vq(struct virtqueue *vq)
 
 /* The ops structure which hooks everything together. */
 static struct virtio_config_ops lguest_config_ops = {
-       .find = lg_find,
+       .feature = lg_feature,
        .get = lg_get,
        .set = lg_set,
        .get_status = lg_get_status,
        .set_status = lg_set_status,
+       .reset = lg_reset,
        .find_vq = lg_find_vq,
        .del_vq = lg_del_vq,
 };
@@ -329,13 +356,14 @@ static void scan_devices(void)
        struct lguest_device_desc *d;
 
        /* We start at the page beginning, and skip over each entry. */
-       for (i = 0; i < PAGE_SIZE; i += sizeof(*d) + d->config_len) {
+       for (i = 0; i < PAGE_SIZE; i += desc_size(d)) {
                d = lguest_devices + i;
 
                /* Once we hit a zero, stop. */
                if (d->type == 0)
                        break;
 
+               printk("Device at %i has size %u\n", i, desc_size(d));
                add_lguest_device(d);
        }
 }
index 61f2f8eb8cad7edb744559c873a854b483a3fcdc..635187812d52b11cf85ed65a3ae88ef6fabf6f7f 100644 (file)
@@ -94,7 +94,7 @@ static void copy_in_guest_info(struct lg_cpu *cpu, struct lguest_pages *pages)
        /* Set up the two "TSS" members which tell the CPU what stack to use
         * for traps which do directly into the Guest (ie. traps at privilege
         * level 1). */
-       pages->state.guest_tss.esp1 = cpu->esp1;
+       pages->state.guest_tss.sp1 = cpu->esp1;
        pages->state.guest_tss.ss1 = cpu->ss1;
 
        /* Copy direct-to-Guest trap entries. */
index 7ce0ea64465ccd666b5b2c234db58ac497cd7e03..28958101061f9a922cf4c79f7cd41c8ec3472e45 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/completion.h>
 #include <linux/device.h>
 #include <linux/kthread.h>
+#include <linux/platform_device.h>
 
 #include <asm/uaccess.h>
 #include <asm/semaphore.h>
index 18dde2a27209e91ba85a7a9adf4b933780e7732f..936788272a5f671e435ca220f8ecf5d4f9e9093b 100644 (file)
@@ -78,12 +78,14 @@ struct media_bay_info {
        int                             cached_gpio;
        int                             sleeping;
        struct semaphore                lock;
-#ifdef CONFIG_BLK_DEV_IDE
+#ifdef CONFIG_BLK_DEV_IDE_PMAC
        void __iomem                    *cd_base;
-       int                             cd_index;
        int                             cd_irq;
        int                             cd_retry;
 #endif
+#if defined(CONFIG_BLK_DEV_IDE_PMAC) || defined(CONFIG_MAC_FLOPPY)
+       int                             cd_index;
+#endif
 };
 
 #define MAX_BAYS       2
@@ -91,7 +93,7 @@ struct media_bay_info {
 static struct media_bay_info media_bays[MAX_BAYS];
 int media_bay_count = 0;
 
-#ifdef CONFIG_BLK_DEV_IDE
+#ifdef CONFIG_BLK_DEV_IDE_PMAC
 /* check the busy bit in the media-bay ide interface
    (assumes the media-bay contains an ide device) */
 #define MB_IDE_READY(i)        ((readb(media_bays[i].cd_base + 0x70) & 0x80) == 0)
@@ -401,7 +403,7 @@ static void poll_media_bay(struct media_bay_info* bay)
                                set_mb_power(bay, id != MB_NO);
                                bay->content_id = id;
                                if (id == MB_NO) {
-#ifdef CONFIG_BLK_DEV_IDE
+#ifdef CONFIG_BLK_DEV_IDE_PMAC
                                        bay->cd_retry = 0;
 #endif
                                        printk(KERN_INFO "media bay %d is empty\n", bay->index);
@@ -414,9 +416,9 @@ static void poll_media_bay(struct media_bay_info* bay)
        }
 }
 
+#ifdef CONFIG_MAC_FLOPPY
 int check_media_bay(struct device_node *which_bay, int what)
 {
-#ifdef CONFIG_BLK_DEV_IDE
        int     i;
 
        for (i=0; i<media_bay_count; i++)
@@ -426,14 +428,14 @@ int check_media_bay(struct device_node *which_bay, int what)
                        media_bays[i].cd_index = -1;
                        return -EINVAL;
                }
-#endif /* CONFIG_BLK_DEV_IDE */
        return -ENODEV;
 }
 EXPORT_SYMBOL(check_media_bay);
+#endif /* CONFIG_MAC_FLOPPY */
 
+#ifdef CONFIG_BLK_DEV_IDE_PMAC
 int check_media_bay_by_base(unsigned long base, int what)
 {
-#ifdef CONFIG_BLK_DEV_IDE
        int     i;
 
        for (i=0; i<media_bay_count; i++)
@@ -443,15 +445,13 @@ int check_media_bay_by_base(unsigned long base, int what)
                        media_bays[i].cd_index = -1;
                        return -EINVAL;
                } 
-#endif
-       
+
        return -ENODEV;
 }
 
 int media_bay_set_ide_infos(struct device_node* which_bay, unsigned long base,
-       int irq, int index)
+                           int irq, int index)
 {
-#ifdef CONFIG_BLK_DEV_IDE
        int     i;
 
        for (i=0; i<media_bay_count; i++) {
@@ -483,10 +483,10 @@ int media_bay_set_ide_infos(struct device_node* which_bay, unsigned long base,
                        return -ENODEV;
                }
        }
-#endif /* CONFIG_BLK_DEV_IDE */
-       
+
        return -ENODEV;
 }
+#endif /* CONFIG_BLK_DEV_IDE_PMAC */
 
 static void media_bay_step(int i)
 {
@@ -521,14 +521,13 @@ static void media_bay_step(int i)
                bay->state = mb_resetting;
                MBDBG("mediabay%d: waiting reset (kind:%d)\n", i, bay->content_id);
                break;
-           
        case mb_resetting:
                if (bay->content_id != MB_CD) {
                        MBDBG("mediabay%d: bay is up (kind:%d)\n", i, bay->content_id);
                        bay->state = mb_up;
                        break;
                }
-#ifdef CONFIG_BLK_DEV_IDE
+#ifdef CONFIG_BLK_DEV_IDE_PMAC
                MBDBG("mediabay%d: waiting IDE reset (kind:%d)\n", i, bay->content_id);
                bay->ops->un_reset_ide(bay);
                bay->timer = msecs_to_jiffies(MB_IDE_WAIT);
@@ -536,16 +535,14 @@ static void media_bay_step(int i)
 #else
                printk(KERN_DEBUG "media-bay %d is ide (not compiled in kernel)\n", i);
                set_mb_power(bay, 0);
-#endif /* CONFIG_BLK_DEV_IDE */
+#endif /* CONFIG_BLK_DEV_IDE_PMAC */
                break;
-           
-#ifdef CONFIG_BLK_DEV_IDE
+#ifdef CONFIG_BLK_DEV_IDE_PMAC
        case mb_ide_resetting:
                bay->timer = msecs_to_jiffies(MB_IDE_TIMEOUT);
                bay->state = mb_ide_waiting;
                MBDBG("mediabay%d: waiting IDE ready (kind:%d)\n", i, bay->content_id);
                break;
-           
        case mb_ide_waiting:
                if (bay->cd_base == NULL) {
                        bay->timer = 0;
@@ -587,15 +584,14 @@ static void media_bay_step(int i)
                        bay->timer = 0;
                }
                break;
-#endif /* CONFIG_BLK_DEV_IDE */
-
+#endif /* CONFIG_BLK_DEV_IDE_PMAC */
        case mb_powering_down:
                bay->state = mb_empty;
-#ifdef CONFIG_BLK_DEV_IDE
+#ifdef CONFIG_BLK_DEV_IDE_PMAC
                if (bay->cd_index >= 0) {
                        printk(KERN_DEBUG "Unregistering mb %d ide, index:%d\n", i,
                               bay->cd_index);
-                       ide_unregister(bay->cd_index);
+                       ide_unregister(bay->cd_index, 1, 1);
                        bay->cd_index = -1;
                }
                if (bay->cd_retry) {
@@ -607,7 +603,7 @@ static void media_bay_step(int i)
                                bay->content_id = MB_NO;
                        }
                }
-#endif /* CONFIG_BLK_DEV_IDE */    
+#endif /* CONFIG_BLK_DEV_IDE_PMAC */
                MBDBG("mediabay%d: end of power down\n", i);
                break;
        }
@@ -739,7 +735,7 @@ static int media_bay_resume(struct macio_dev *mdev)
                bay->last_value = bay->content_id;
                bay->value_count = msecs_to_jiffies(MB_STABLE_DELAY);
                bay->timer = msecs_to_jiffies(MB_POWER_DELAY);
-#ifdef CONFIG_BLK_DEV_IDE
+#ifdef CONFIG_BLK_DEV_IDE_PMAC
                bay->cd_retry = 0;
 #endif
                do {
@@ -829,7 +825,7 @@ static int __init media_bay_init(void)
        for (i=0; i<MAX_BAYS; i++) {
                memset((char *)&media_bays[i], 0, sizeof(struct media_bay_info));
                media_bays[i].content_id        = -1;
-#ifdef CONFIG_BLK_DEV_IDE
+#ifdef CONFIG_BLK_DEV_IDE_PMAC
                media_bays[i].cd_index          = -1;
 #endif
        }
index d409f67594828e5501e754edc1fb60e5337b2f3d..8ba49385c3ff4fd149c21980eabf0cc1996ee32b 100644 (file)
@@ -12,7 +12,7 @@
  *  - maybe add timeout to commands ?
  *  - blocking version of time functions
  *  - polling version of i2c commands (including timer that works with
- *    interrutps off)
+ *    interrupts off)
  *  - maybe avoid some data copies with i2c by directly using the smu cmd
  *    buffer and a lower level internal interface
  *  - understand SMU -> CPU events and implement reception of them via
@@ -179,7 +179,7 @@ static irqreturn_t smu_db_intr(int irq, void *arg)
                /* CPU might have brought back the cache line, so we need
                 * to flush again before peeking at the SMU response. We
                 * flush the entire buffer for now as we haven't read the
-                * reply lenght (it's only 2 cache lines anyway)
+                * reply length (it's only 2 cache lines anyway)
                 */
                faddr = (unsigned long)smu->cmd_buf;
                flush_inval_dcache_range(faddr, faddr + 256);
index 01b8eca7ccd56e33cb5dcf27605bddffd1a27f64..6e6dd17ab572f81bd775293ad907b8024407d2ee 100644 (file)
@@ -111,7 +111,7 @@ static enum macii_state {
 static struct adb_request *current_req; /* first request struct in the queue */
 static struct adb_request *last_req;     /* last request struct in the queue */
 static unsigned char reply_buf[16];        /* storage for autopolled replies */
-static unsigned char *reply_ptr;      /* next byte in req->data or reply_buf */
+static unsigned char *reply_ptr;     /* next byte in reply_buf or req->reply */
 static int reading_reply;        /* store reply in reply_buf else req->reply */
 static int data_index;      /* index of the next byte to send from req->data */
 static int reply_len; /* number of bytes received in reply_buf or req->reply */
index 7d04a6fd1acb03affddb06faada0a40018066a19..168a8d3a5e556e889b7b44033b06531addb9faf8 100644 (file)
@@ -388,7 +388,7 @@ static int saa7146_init_one(struct pci_dev *pci, const struct pci_device_id *ent
        }
        dev->revision &= 0xf;
 
-       /* remap the memory from virtual to physical adress */
+       /* remap the memory from virtual to physical address */
 
        err = pci_request_region(pci, 0, "saa7146");
        if (err < 0)
index a33eb5988c42e8aa1fcf64c1959084617c3d8e8e..ed3f8268ed11445e60fce10500a66e15d3e3be53 100644 (file)
@@ -681,7 +681,7 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
                                                        drop = 1;
                                                /* else: destination address matches the MAC address of our receiver device */
                                        }
-                                       /* else: promiscious mode; pass everything up the stack */
+                                       /* else: promiscuous mode; pass everything up the stack */
 
                                        if (drop) {
 #ifdef ULE_DEBUG
index 63a47cd4c161110796503cfc3a83fa5412e9ba7a..7374c02dd183fc1a5d457b8899828dab9c195dd8 100644 (file)
@@ -4344,7 +4344,7 @@ static void rv605_muxsel(struct bttv *btv, unsigned int input)
        gpio_bits(0x200,0x000);
        mdelay(1);
 
-       /* create a new conection */
+       /* create a new connection */
        gpio_bits(0x480,0x080);
        gpio_bits(0x480,0x480);
        mdelay(1);
index 8735227f7e47b5e798d7291b01883628f0f9367a..316b106c3511b2a15981e692c6e4c7cd9884c6cd 100644 (file)
@@ -33,7 +33,6 @@
 #include <linux/pci.h>
 
 #include <asm/delay.h>
-#include <sound/driver.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
index 5c2c4029ff86bd76a3872152b198b58259e73936..84b9e4f2b3b3fcef7c25b2b60d88df30925d44f6 100644 (file)
@@ -326,7 +326,7 @@ static int indycam_attach(struct i2c_adapter *adap, int addr, int kind)
        // initialize
        err = indycam_write_block(client, 0, sizeof(initseq), (u8 *)&initseq);
        if (err) {
-               printk(KERN_ERR "IndyCam initalization failed\n");
+               printk(KERN_ERR "IndyCam initialization failed\n");
                err = -EIO;
                goto out_detach_client;
        }
index b630c26cfe856b9b45ead161d34ee013fddbeadc..58bab653330fee8ce0b6e26d618cd02c3c9fb37e 100644 (file)
@@ -369,7 +369,7 @@ static struct dvb_tuner_ops mt2032_tuner_ops = {
        .get_frequency     = microtune_get_frequency,
 };
 
-// Initalization as described in "MT203x Programming Procedures", Rev 1.2, Feb.2001
+// Initialization as described in "MT203x Programming Procedures", Rev 1.2, Feb.2001
 static int mt2032_init(struct dvb_frontend *fe)
 {
        struct microtune_priv *priv = fe->tuner_priv;
index 074533e9c21ee69079ed0de2ea15df86bed86b04..1a9a4baf12b84664821c42b862789f68a4fcf20d 100644 (file)
@@ -27,7 +27,7 @@
    might want to increase this - however the driver operation will not
    be impaired if it is too small.  Instead additional units just
    won't have an ID assigned and it might not be possible to specify
-   module paramters for those extra units. */
+   module parameters for those extra units. */
 #define PVR_NUM 20
 
 #endif /* __PVRUSB2_H */
index 7300ace8f44ed1331bb5f385b3821dfb749aedf9..f991d72fe10808d29263e7c0cb6411e9f93bc0b1 100644 (file)
@@ -542,7 +542,7 @@ int pwc_handle_frame(struct pwc_device *pdev)
        }
 
        if (pdev->read_frame != NULL) {
-               /* Decompression is a lenghty process, so it's outside of the lock.
+               /* Decompression is a lengthy process, so it's outside of the lock.
                   This gives the isoc_handler the opportunity to fill more frames
                   in the mean time.
                */
index ba2531034a91264f763d53daabab533a98469bcb..047add8f3010efae75fd7128e2d293b75206e1e4 100644 (file)
@@ -21,7 +21,6 @@
 #include <linux/time.h>
 #include <linux/wait.h>
 #include <linux/module.h>
-#include <sound/driver.h>
 #include <sound/core.h>
 #include <sound/control.h>
 #include <sound/pcm.h>
index ce450304fb5364503c7c42433927148954e211a0..b88ca995fafbbd75f6e394c8b283a09e2efe67d8 100644 (file)
@@ -38,7 +38,6 @@
 #include <media/ir-common.h>
 #include <media/ir-kbd-i2c.h>
 #include <media/videobuf-dma-sg.h>
-#include <sound/driver.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #if defined(CONFIG_VIDEO_SAA7134_DVB) || defined(CONFIG_VIDEO_SAA7134_DVB_MODULE)
index e0ff811fab6f3e69a69af355e287f4d6db29c92e..ca05cd65508765559524b104dc7805ab5dad278f 100644 (file)
@@ -57,7 +57,7 @@ static int tea6420_switch(struct i2c_client *client, int i, int o, int g)
 
        dprintk("adr:0x%02x, i:%d, o:%d, g:%d\n", client->addr, i, o, g);
 
-       /* check if the paramters are valid */
+       /* check if the parameters are valid */
        if (i < 1 || i > 6 || o < 1 || o > 4 || g < 0 || g > 6 || g % 2 != 0)
                return -1;
 
index d847273eeba0c247c4f707a4fed3b00feef04b3e..5e7b795013706591aff8dfb09099d9dd60a8fff1 100644 (file)
@@ -258,7 +258,7 @@ static void qcm_hsv2rgb(u16 hue, u16 sat, u16 val, u16 *r, u16 *g, u16 *b)
        unsigned int p;
 
        /*
-       the registers controling gain are 8 bit of which
+       the registers controlling gain are 8 bit of which
        we affect only the last 4 bits with our gain.
        we know that if saturation is 0, (unsaturated) then
        we're grayscale (center axis of the colour cone) so
index b52b826a30be8b5fb38f03ed38de20dc3e338ee9..df52f8a602155c6c32e26011f6dd93f0c6c7b097 100644 (file)
@@ -131,7 +131,7 @@ static struct usbvision_v4l2_format_st usbvision_v4l2_format[] = {
 /* Function prototypes */
 static void usbvision_release(struct usb_usbvision *usbvision);
 
-/* Default initalization of device driver parameters */
+/* Default initialization of device driver parameters */
 /* Set the default format for ISOC endpoint */
 static int isocMode = ISOC_MODE_COMPRESS;
 /* Set the default Debug Mode of the device driver */
index 8ef31ed7d3f1133edfe514ba0b34445d3aaed3a6..a9133858e913552e62474792ad6b647a0865edd5 100644 (file)
@@ -566,7 +566,7 @@ vpx3220_init_client (struct i2c_client *client)
 }
 
 /* -----------------------------------------------------------------------
- * Client managment code
+ * Client management code
  */
 
 /*
index 6e0ac4c5c379683187645e104e467b82c171b196..690281bb59ee616f71db4393d7b63a4080455284 100644 (file)
@@ -1270,7 +1270,7 @@ zoran_setup_videocodec (struct zoran *zr,
 }
 
 /*
- *   Scan for a Buz card (actually for the PCI contoler ZR36057),
+ *   Scan for a Buz card (actually for the PCI controller ZR36057),
  *   request the irq and map the io memory
  */
 static int __devinit
index 9f622e00c479b573875bd062886afa8688063c5c..faae4ec3ea0bf5288f12a1c52a78ce75e12bd7c2 100644 (file)
@@ -161,7 +161,7 @@ zr36050_wait_end (struct zr36050 *ptr)
                udelay(1);
                if (i++ > 200000) {     // 200ms, there is for sure something wrong!!!
                        dprintk(1,
-                               "%s: timout at wait_end (last status: 0x%02x)\n",
+                               "%s: timeout at wait_end (last status: 0x%02x)\n",
                                ptr->name, ptr->status1);
                        break;
                }
index 1ef14fef08e624a85c2a2733fb39fa04c2685344..7849b65969d0741e624b350aa80e79eb18d50321 100644 (file)
@@ -163,7 +163,7 @@ zr36060_wait_end (struct zr36060 *ptr)
                udelay(1);
                if (i++ > 200000) {     // 200ms, there is for sure something wrong!!!
                        dprintk(1,
-                               "%s: timout at wait_end (last status: 0x%02x)\n",
+                               "%s: timeout at wait_end (last status: 0x%02x)\n",
                                ptr->name, ptr->status);
                        break;
                }
index 6be1f6b65777a07208da7ad26eb084c7c8308b7e..af9da03e95e571f7677f5092d6dd7e123eedd59a 100644 (file)
 #define PL_LOGINFO_SUB_CODE_FRAME_XFER_ERROR                 (0x00000400) /* Bits 0-3 encode Transport Status Register (offset 0x08) */
                                                                           /* Bit 0 is Status Bit 0: FrameXferErr */
                                                                           /* Bit 1 & 2 are Status Bits 16 and 17: FrameXmitErrStatus */
-                                                                          /* Bit 3 is Status Bit 18 WriteDataLenghtGTDataLengthErr */
+                                                                          /* Bit 3 is Status Bit 18 WriteDataLengthGTDataLengthErr */
 
 #define PL_LOGINFO_SUB_CODE_TX_FM_CONNECTED_LOW              (0x00000500)
 #define PL_LOGINFO_SUB_CODE_SATA_NON_NCQ_RW_ERR_BIT_SET      (0x00000600)
index 6029509702d35e02b92f76fc1546007c39ee5299..e630b50966ec5ba0192a36acb9e22a328e9b5675 100644 (file)
@@ -1708,7 +1708,7 @@ mptctl_replace_fw (unsigned long arg)
  *
  * Outputs:    None.
  * Return:     0 if successful
- *             -EBUSY  if previous command timout and IOC reset is not complete.
+ *             -EBUSY  if previous command timeout and IOC reset is not complete.
  *             -EFAULT if data unavailable
  *             -ENODEV if no such device/adapter
  *             -ETIME  if timer expires
@@ -1748,7 +1748,7 @@ mptctl_mpt_command (unsigned long arg)
  *
  * Outputs:    None.
  * Return:     0 if successful
- *             -EBUSY  if previous command timout and IOC reset is not complete.
+ *             -EBUSY  if previous command timeout and IOC reset is not complete.
  *             -EFAULT if data unavailable
  *             -ENODEV if no such device/adapter
  *             -ETIME  if timer expires
@@ -2316,7 +2316,7 @@ done_free_mem:
  * Outputs:    None.
  * Return:     0 if successful
  *             -EFAULT if data unavailable
- *             -EBUSY  if previous command timout and IOC reset is not complete.
+ *             -EBUSY  if previous command timeout and IOC reset is not complete.
  *             -ENODEV if no such device/adapter
  *             -ETIME  if timer expires
  *             -ENOMEM if memory allocation error
@@ -2553,7 +2553,7 @@ mptctl_hp_hostinfo(unsigned long arg, unsigned int data_size)
  * Outputs:    None.
  * Return:     0 if successful
  *             -EFAULT if data unavailable
- *             -EBUSY  if previous command timout and IOC reset is not complete.
+ *             -EBUSY  if previous command timeout and IOC reset is not complete.
  *             -ENODEV if no such device/adapter
  *             -ETIME  if timer expires
  *             -ENOMEM if memory allocation error
index 5c614ec38cc494da6671db10a964302cca993127..af1de0ccee2f54c37c3567585e9e73db6f83bfe4 100644 (file)
@@ -1736,7 +1736,7 @@ mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, i
  fail_out:
 
        /*
-        * Free task managment mf, and corresponding tm flags
+        * Free task management mf, and corresponding tm flags
         */
        mpt_free_msg_frame(ioc, mf);
        hd->tmPending = 0;
index 7814a06ae970f515cc43e21051e0bb13a09c53a9..da715e11c1b28cc493de7047e1772074c804e981 100644 (file)
@@ -916,7 +916,7 @@ static int i2o_parse_hrt(struct i2o_controller *c)
  *     status block. The status block could then be accessed through
  *     c->status_block.
  *
- *     Returns 0 on sucess or negative error code on failure.
+ *     Returns 0 on success or negative error code on failure.
  */
 int i2o_status_get(struct i2o_controller *c)
 {
index c73e96bfafc636047bbe9bebef7067b4a79d4bb3..90acf57c19bd29962197cf9ed83fa332e3888a4c 100644 (file)
@@ -376,7 +376,7 @@ static int DoC_IdentChip(struct DiskOnChip *doc, int floor, int chip)
         * hardware restriction. */
        if (doc->mfr) {
                if (doc->mfr == mfr && doc->id == id)
-                       return 1;       /* This is another the same the first */
+                       return 1;       /* This is the same as the first */
                else
                        printk(KERN_WARNING
                               "Flash chip at floor %d, chip %d is different:\n",
index e3744eb8eccba4a68f3780379911a1eff7df2ef5..dd38011ee0b7326096973b694a3339467bc984f5 100644 (file)
@@ -20,7 +20,7 @@
  *
  *     02-12-2002 TG   Cleanup of module params
  *
- *     02-20-2002 TG   adjusted for different rd/wr adress support
+ *     02-20-2002 TG   adjusted for different rd/wr address support
  *                     added support for read device ready/busy line
  *                     added page_cache
  *
@@ -144,7 +144,7 @@ static int __init autcpu12_init(void)
                goto out;
        }
 
-       /* map physical adress */
+       /* map physical address */
        autcpu12_fio_base = ioremap(AUTCPU12_PHYS_SMC, SZ_1K);
        if (!autcpu12_fio_base) {
                printk("Ioremap autcpu12 SmartMedia Card failed\n");
@@ -227,7 +227,7 @@ static void __exit autcpu12_cleanup(void)
        /* Release resources, unregister device */
        nand_release(autcpu12_mtd);
 
-       /* unmap physical adress */
+       /* unmap physical address */
        iounmap(autcpu12_fio_base);
 
        /* Free the MTD device structure */
index 1657ecd74881ee4eebd9ce1752ef692a11c05c8b..a52f3a737c39a606e0832b3db47f19effa274a83 100644 (file)
@@ -4,7 +4,7 @@
  *     http://blackfin.uclinux.org/
  *     Bryan Wu <bryan.wu@analog.com>
  *
- * Blackfin BF5xx on-chip NAND flash controler driver
+ * Blackfin BF5xx on-chip NAND flash controller driver
  *
  * Derived from drivers/mtd/nand/s3c2410.c
  * Copyright (c) 2007 Ben Dooks <ben@simtec.co.uk>
index 89deff007116388b718c5828f476ce4bb507c841..19e1594421a476cae392e4b5f2b6b48c6fb18bb3 100644 (file)
@@ -337,7 +337,7 @@ static void __exit cs553x_cleanup(void)
                nand_release(cs553x_mtd[i]);
                cs553x_mtd[i] = NULL;
 
-               /* unmap physical adress */
+               /* unmap physical address */
                iounmap(mmio_base);
 
                /* Free the MTD device structure */
index 0146cdc48039617259a72c5a8c094d6a53c18cc5..ba67bbec20d3a4fbab3ac9733d05ee7cc3f61229 100644 (file)
@@ -125,7 +125,7 @@ static int __init ep7312_init(void)
                return -ENOMEM;
        }
 
-       /* map physical adress */
+       /* map physical address */
        ep7312_fio_base = ioremap(ep7312_fio_pbase, SZ_1K);
        if (!ep7312_fio_base) {
                printk("ioremap EDB7312 NAND flash failed\n");
index e29c1da7f56e82530a987beb96ab84a735a2b637..ddd4fc019042ff72250c887944a3410ec6b69459 100644 (file)
@@ -89,7 +89,7 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
                             struct mtd_oob_ops *ops);
 
 /*
- * For devices which display every fart in the system on a seperate LED. Is
+ * For devices which display every fart in the system on a separate LED. Is
  * compiled away when LED support is disabled.
  */
 DEFINE_LED_TRIGGER(nand_led_trigger);
index 10490b48d9f75844c81a00dc8f32825475345afc..bb885d1fcab5e9bbb87a085f0af76a76ea5e88bb 100644 (file)
@@ -210,7 +210,7 @@ MODULE_PARM_DESC(overridesize,   "Specifies the NAND Flash size overriding the I
 #define STATE_CMD_RESET        0x0000000C /* reset */
 #define STATE_CMD_MASK         0x0000000F /* command states mask */
 
-/* After an addres is input, the simulator goes to one of these states */
+/* After an address is input, the simulator goes to one of these states */
 #define STATE_ADDR_PAGE        0x00000010 /* full (row, column) address is accepted */
 #define STATE_ADDR_SEC         0x00000020 /* sector address was accepted */
 #define STATE_ADDR_ZERO        0x00000030 /* one byte zero address was accepted */
index 66f76e9618ddd9005edcb60faf2b66ea2ec539b2..2bd0737572c6fe9146a5b26d6f4147a2e76daea8 100644 (file)
@@ -8,7 +8,7 @@
  *
  * Changelog:
  *     21-Sep-2004  BJD  Initial version
- *     23-Sep-2004  BJD  Mulitple device support
+ *     23-Sep-2004  BJD  Multiple device support
  *     28-Sep-2004  BJD  Fixed ECC placement for Hardware mode
  *     12-Oct-2004  BJD  Fixed errors in use of platform data
  *     18-Feb-2005  BJD  Fix sparse errors
index 51c7288ab49a0fe4e0d251ba35c680e651378c58..033f8800b1e69224d81c15dd670bc24e95190a7f 100644 (file)
@@ -165,7 +165,7 @@ static int __init sharpsl_nand_init(void)
                return -ENOMEM;
        }
 
-       /* map physical adress */
+       /* map physical address */
        sharpsl_io_base = ioremap(sharpsl_phys_base, 0x1000);
        if (!sharpsl_io_base) {
                printk("ioremap to access Sharp SL NAND chip failed\n");
index 067262ee8df0fa2683c7a7bfd8582919fc0f5909..0513cbc8834d66b78d7e0c85d1f6532447048044 100644 (file)
@@ -429,7 +429,7 @@ static void check_sectors_in_chain(struct NFTLrecord *nftl, unsigned int first_b
        }
 }
 
-/* calc_chain_lenght: Walk through a Virtual Unit Chain and estimate chain length */
+/* calc_chain_length: Walk through a Virtual Unit Chain and estimate chain length */
 static int calc_chain_length(struct NFTLrecord *nftl, unsigned int first_block)
 {
        unsigned int length = 0, block = first_block;
index 389980f0e59e7385d608e3cc2b7aed58ac2be115..9cc25fd80b605c742411b3042c27808976199453 100644 (file)
@@ -814,8 +814,8 @@ config ULTRA32
          will be called smc-ultra32.
 
 config BFIN_MAC
-       tristate "Blackfin 536/537 on-chip mac support"
-       depends on NET_ETHERNET && (BF537 || BF536) && (!BF537_PORT_H)
+       tristate "Blackfin 527/536/537 on-chip mac support"
+       depends on NET_ETHERNET && (BF527 || BF537 || BF536) && (!BF537_PORT_H)
        select CRC32
        select MII
        select PHYLIB
@@ -828,7 +828,7 @@ config BFIN_MAC
 
 config BFIN_MAC_USE_L1
        bool "Use L1 memory for rx/tx packets"
-       depends on BFIN_MAC && BF537
+       depends on BFIN_MAC && (BF527 || BF537)
        default y
        help
          To get maximum network performance, you should use L1 memory as rx/tx buffers.
@@ -855,7 +855,8 @@ config BFIN_RX_DESC_NUM
 config BFIN_MAC_RMII
        bool "RMII PHY Interface (EXPERIMENTAL)"
        depends on BFIN_MAC && EXPERIMENTAL
-       default n
+       default y if BFIN527_EZKIT
+       default n if BFIN537_STAMP
        help
          Use Reduced PHY MII Interface
 
@@ -919,8 +920,7 @@ config ENC28J60
        ---help---
          Support for the Microchip EN28J60 ethernet chip.
 
-         To compile this driver as a module, choose M here and read
-         <file:Documentation/networking/net-modules.txt>.  The module will be
+         To compile this driver as a module, choose M here. The module will be
          called enc28j60.
 
 config ENC28J60_WRITEVERIFY
@@ -1199,7 +1199,7 @@ config NE2_MCA
 
 config IBMLANA
        tristate "IBM LAN Adapter/A support"
-       depends on MCA && MCA_LEGACY
+       depends on MCA
        ---help---
          This is a Micro Channel Ethernet adapter.  You need to set
          CONFIG_MCA to use this driver.  It is both available as an in-kernel
@@ -1737,10 +1737,8 @@ config SC92031
 
 config CPMAC
        tristate "TI AR7 CPMAC Ethernet support (EXPERIMENTAL)"
-       depends on NET_ETHERNET && EXPERIMENTAL && AR7
+       depends on NET_ETHERNET && EXPERIMENTAL && AR7 && BROKEN
        select PHYLIB
-       select FIXED_PHY
-       select FIXED_MII_100_FDX
        help
          TI AR7 CPMAC Ethernet support
 
@@ -2040,8 +2038,7 @@ config IGB
          More specific information on configuring the driver is in
          <file:Documentation/networking/e1000.txt>.
 
-         To compile this driver as a module, choose M here and read
-         <file:Documentation/networking/net-modules.txt>.  The module
+         To compile this driver as a module, choose M here. The module
          will be called igb.
 
 source "drivers/net/ixp2000/Kconfig"
@@ -3113,6 +3110,7 @@ config VIRTIO_NET
        tristate "Virtio network driver (EXPERIMENTAL)"
        depends on EXPERIMENTAL && VIRTIO
        ---help---
-         This is the virtual network driver for lguest.  Say Y or M.
+         This is the virtual network driver for virtio.  It can be used with
+          lguest or QEMU based VMMs (like KVM or Xen).  Say Y or M.
 
 endif # NETDEVICES
index 25b114a4e2b16f57373481da83b6066090518543..0ae0d83e5d2254b1db9b531103a3f88d4b50b7e3 100644 (file)
@@ -384,7 +384,7 @@ static void reset_phy(struct net_device *dev)
        /* Wait until PHY reset is complete */
        do {
                read_phy(lp->phy_address, MII_BMCR, &bmcr);
-       } while (!(bmcr && BMCR_RESET));
+       } while (!(bmcr & BMCR_RESET));
 
        disable_mdi();
        spin_unlock_irq(&lp->lock);
index 7495a9ee8f4bff6dde5b7c7666398d35882059fd..194949afacd05142655f7d1a42e00b8b894f6697 100644 (file)
@@ -137,11 +137,12 @@ static int ax_initial_check(struct net_device *dev)
 static void ax_reset_8390(struct net_device *dev)
 {
        struct ei_device *ei_local = netdev_priv(dev);
+       struct ax_device  *ax = to_ax_dev(dev);
        unsigned long reset_start_time = jiffies;
        void __iomem *addr = (void __iomem *)dev->base_addr;
 
        if (ei_debug > 1)
-               printk(KERN_DEBUG "resetting the 8390 t=%ld...", jiffies);
+               dev_dbg(&ax->dev->dev, "resetting the 8390 t=%ld\n", jiffies);
 
        ei_outb(ei_inb(addr + NE_RESET), addr + NE_RESET);
 
@@ -151,7 +152,7 @@ static void ax_reset_8390(struct net_device *dev)
        /* This check _should_not_ be necessary, omit eventually. */
        while ((ei_inb(addr + EN0_ISR) & ENISR_RESET) == 0) {
                if (jiffies - reset_start_time > 2*HZ/100) {
-                       printk(KERN_WARNING "%s: %s did not complete.\n",
+                       dev_warn(&ax->dev->dev, "%s: %s did not complete.\n",
                               __FUNCTION__, dev->name);
                        break;
                }
@@ -165,13 +166,15 @@ static void ax_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
                            int ring_page)
 {
        struct ei_device *ei_local = netdev_priv(dev);
+       struct ax_device  *ax = to_ax_dev(dev);
        void __iomem *nic_base = ei_local->mem;
 
        /* This *shouldn't* happen. If it does, it's the last thing you'll see */
        if (ei_status.dmaing) {
-               printk(KERN_EMERG "%s: DMAing conflict in %s [DMAstat:%d][irqlock:%d].\n",
+               dev_err(&ax->dev->dev, "%s: DMAing conflict in %s "
+                       "[DMAstat:%d][irqlock:%d].\n",
                        dev->name, __FUNCTION__,
-                      ei_status.dmaing, ei_status.irqlock);
+                       ei_status.dmaing, ei_status.irqlock);
                return;
        }
 
@@ -204,13 +207,16 @@ static void ax_block_input(struct net_device *dev, int count,
                           struct sk_buff *skb, int ring_offset)
 {
        struct ei_device *ei_local = netdev_priv(dev);
+       struct ax_device  *ax = to_ax_dev(dev);
        void __iomem *nic_base = ei_local->mem;
        char *buf = skb->data;
 
        if (ei_status.dmaing) {
-               printk(KERN_EMERG "%s: DMAing conflict in ax_block_input "
+               dev_err(&ax->dev->dev,
+                       "%s: DMAing conflict in %s "
                        "[DMAstat:%d][irqlock:%d].\n",
-                       dev->name, ei_status.dmaing, ei_status.irqlock);
+                       dev->name, __FUNCTION__,
+                       ei_status.dmaing, ei_status.irqlock);
                return;
        }
 
@@ -239,6 +245,7 @@ static void ax_block_output(struct net_device *dev, int count,
                            const unsigned char *buf, const int start_page)
 {
        struct ei_device *ei_local = netdev_priv(dev);
+       struct ax_device  *ax = to_ax_dev(dev);
        void __iomem *nic_base = ei_local->mem;
        unsigned long dma_start;
 
@@ -251,7 +258,7 @@ static void ax_block_output(struct net_device *dev, int count,
 
        /* This *shouldn't* happen. If it does, it's the last thing you'll see */
        if (ei_status.dmaing) {
-               printk(KERN_EMERG "%s: DMAing conflict in %s."
+               dev_err(&ax->dev->dev, "%s: DMAing conflict in %s."
                        "[DMAstat:%d][irqlock:%d]\n",
                        dev->name, __FUNCTION__,
                       ei_status.dmaing, ei_status.irqlock);
@@ -281,7 +288,8 @@ static void ax_block_output(struct net_device *dev, int count,
 
        while ((ei_inb(nic_base + EN0_ISR) & ENISR_RDC) == 0) {
                if (jiffies - dma_start > 2*HZ/100) {           /* 20ms */
-                       printk(KERN_WARNING "%s: timeout waiting for Tx RDC.\n", dev->name);
+                       dev_warn(&ax->dev->dev,
+                                "%s: timeout waiting for Tx RDC.\n", dev->name);
                        ax_reset_8390(dev);
                        ax_NS8390_init(dev,1);
                        break;
@@ -424,10 +432,11 @@ static void
 ax_phy_write(struct net_device *dev, int phy_addr, int reg, int value)
 {
        struct ei_device *ei = (struct ei_device *) netdev_priv(dev);
+       struct ax_device  *ax = to_ax_dev(dev);
        unsigned long flags;
 
-       printk(KERN_DEBUG "%s: %p, %04x, %04x %04x\n",
-              __FUNCTION__, dev, phy_addr, reg, value);
+       dev_dbg(&ax->dev->dev, "%s: %p, %04x, %04x %04x\n",
+               __FUNCTION__, dev, phy_addr, reg, value);
 
        spin_lock_irqsave(&ei->page_lock, flags);
 
@@ -750,14 +759,11 @@ static int ax_init_dev(struct net_device *dev, int first_init)
        ax_NS8390_init(dev, 0);
 
        if (first_init) {
-               printk("AX88796: %dbit, irq %d, %lx, MAC: ",
-                      ei_status.word16 ? 16:8, dev->irq, dev->base_addr);
-
-               for (i = 0; i < ETHER_ADDR_LEN; i++)
-                       printk("%2.2x%c", dev->dev_addr[i],
-                              (i < (ETHER_ADDR_LEN-1) ? ':' : ' '));
+               DECLARE_MAC_BUF(mac);
 
-               printk("\n");
+               dev_info(&ax->dev->dev, "%dbit, irq %d, %lx, MAC: %s\n",
+                        ei_status.word16 ? 16:8, dev->irq, dev->base_addr,
+                        print_mac(mac, dev->dev_addr));
        }
 
        ret = register_netdev(dev);
index eb971755a3ff34c5b8f76d5b8b63bf5f3a83aad0..c993a32b3f50c1b0389a90ee193aa7bb24e94ba4 100644 (file)
@@ -1,34 +1,11 @@
 /*
- * File:       drivers/net/bfin_mac.c
- * Based on:
- * Maintainer:
- *             Bryan Wu <bryan.wu@analog.com>
+ * Blackfin On-Chip MAC Driver
  *
- * Original author:
- *             Luke Yang <luke.yang@analog.com>
+ * Copyright 2004-2007 Analog Devices Inc.
  *
- * Created:
- * Description:
+ * Enter bugs at http://blackfin.uclinux.org/
  *
- * Modified:
- *             Copyright 2004-2006 Analog Devices Inc.
- *
- * Bugs:       Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software ;  you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation ;  either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY ;  without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program ;  see the file COPYING.
- * If not, write to the Free Software Foundation,
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Licensed under the GPL-2 or later.
  */
 
 #include <linux/init.h>
@@ -65,7 +42,7 @@
 #define DRV_NAME       "bfin_mac"
 #define DRV_VERSION    "1.1"
 #define DRV_AUTHOR     "Bryan Wu, Luke Yang"
-#define DRV_DESC       "Blackfin BF53[67] on-chip Ethernet MAC driver"
+#define DRV_DESC       "Blackfin BF53[67] BF527 on-chip Ethernet MAC driver"
 
 MODULE_AUTHOR(DRV_AUTHOR);
 MODULE_LICENSE("GPL");
@@ -296,7 +273,7 @@ static void mdio_poll(void)
 
        /* poll the STABUSY bit */
        while ((bfin_read_EMAC_STAADD()) & STABUSY) {
-               mdelay(10);
+               udelay(1);
                if (timeout_cnt-- < 0) {
                        printk(KERN_ERR DRV_NAME
                        ": wait MDC/MDIO transaction to complete timeout\n");
@@ -412,20 +389,26 @@ static void bf537_adjust_link(struct net_device *dev)
        spin_unlock_irqrestore(&lp->lock, flags);
 }
 
+/* MDC  = 2.5 MHz */
+#define MDC_CLK 2500000
+
 static int mii_probe(struct net_device *dev)
 {
        struct bf537mac_local *lp = netdev_priv(dev);
        struct phy_device *phydev = NULL;
        unsigned short sysctl;
        int i;
+       u32 sclk, mdc_div;
 
        /* Enable PHY output early */
        if (!(bfin_read_VR_CTL() & PHYCLKOE))
                bfin_write_VR_CTL(bfin_read_VR_CTL() | PHYCLKOE);
 
-       /* MDC  = 2.5 MHz */
+       sclk = get_sclk();
+       mdc_div = ((sclk / MDC_CLK) / 2) - 1;
+
        sysctl = bfin_read_EMAC_SYSCTL();
-       sysctl |= SET_MDCDIV(24);
+       sysctl = (sysctl & ~MDCDIV) | SET_MDCDIV(mdc_div);
        bfin_write_EMAC_SYSCTL(sysctl);
 
        /* search for connect PHY device */
@@ -477,8 +460,10 @@ static int mii_probe(struct net_device *dev)
        lp->phydev = phydev;
 
        printk(KERN_INFO "%s: attached PHY driver [%s] "
-              "(mii_bus:phy_addr=%s, irq=%d)\n",
-              DRV_NAME, phydev->drv->name, phydev->dev.bus_id, phydev->irq);
+              "(mii_bus:phy_addr=%s, irq=%d, mdc_clk=%dHz(mdc_div=%d)"
+              "@sclk=%dMHz)\n",
+              DRV_NAME, phydev->drv->name, phydev->dev.bus_id, phydev->irq,
+              MDC_CLK, mdc_div, sclk/1000000);
 
        return 0;
 }
@@ -551,7 +536,7 @@ static void adjust_tx_list(void)
         */
        if (current_tx_ptr->next->next == tx_list_head) {
                while (tx_list_head->status.status_word == 0) {
-                       mdelay(10);
+                       mdelay(1);
                        if (tx_list_head->status.status_word != 0
                            || !(bfin_read_DMA2_IRQ_STATUS() & 0x08)) {
                                goto adjust_head;
@@ -666,6 +651,12 @@ static void bf537mac_rx(struct net_device *dev)
        current_rx_ptr->skb = new_skb;
        current_rx_ptr->desc_a.start_addr = (unsigned long)new_skb->data - 2;
 
+       /* Invidate the data cache of skb->data range when it is write back
+        * cache. It will prevent overwritting the new data from DMA
+        */
+       blackfin_dcache_invalidate_range((unsigned long)new_skb->head,
+                                        (unsigned long)new_skb->end);
+
        len = (unsigned short)((current_rx_ptr->status.status_word) & RX_FRLEN);
        skb_put(skb, len);
        blackfin_dcache_invalidate_range((unsigned long)skb->head,
@@ -767,7 +758,7 @@ static void bf537mac_enable(void)
 
 #if defined(CONFIG_BFIN_MAC_RMII)
        opmode |= RMII; /* For Now only 100MBit are supported */
-#ifdef CONFIG_BF_REV_0_2
+#if (defined(CONFIG_BF537) || defined(CONFIG_BF536)) && CONFIG_BF_REV_0_2
        opmode |= TE;
 #endif
 #endif
@@ -792,6 +783,39 @@ static void bf537mac_timeout(struct net_device *dev)
        netif_wake_queue(dev);
 }
 
+static void bf537mac_multicast_hash(struct net_device *dev)
+{
+       u32 emac_hashhi, emac_hashlo;
+       struct dev_mc_list *dmi = dev->mc_list;
+       char *addrs;
+       int i;
+       u32 crc;
+
+       emac_hashhi = emac_hashlo = 0;
+
+       for (i = 0; i < dev->mc_count; i++) {
+               addrs = dmi->dmi_addr;
+               dmi = dmi->next;
+
+               /* skip non-multicast addresses */
+               if (!(*addrs & 1))
+                       continue;
+
+               crc = ether_crc(ETH_ALEN, addrs);
+               crc >>= 26;
+
+               if (crc & 0x20)
+                       emac_hashhi |= 1 << (crc & 0x1f);
+               else
+                       emac_hashlo |= 1 << (crc & 0x1f);
+       }
+
+       bfin_write_EMAC_HASHHI(emac_hashhi);
+       bfin_write_EMAC_HASHLO(emac_hashlo);
+
+       return;
+}
+
 /*
  * This routine will, depending on the values passed to it,
  * either make it accept multicast packets, go into
@@ -807,11 +831,17 @@ static void bf537mac_set_multicast_list(struct net_device *dev)
                sysctl = bfin_read_EMAC_OPMODE();
                sysctl |= RAF;
                bfin_write_EMAC_OPMODE(sysctl);
-       } else if (dev->flags & IFF_ALLMULTI || dev->mc_count) {
+       } else if (dev->flags & IFF_ALLMULTI) {
                /* accept all multicast */
                sysctl = bfin_read_EMAC_OPMODE();
                sysctl |= PAM;
                bfin_write_EMAC_OPMODE(sysctl);
+       } else if (dev->mc_count) {
+               /* set up multicast hash table */
+               sysctl = bfin_read_EMAC_OPMODE();
+               sysctl |= HM;
+               bfin_write_EMAC_OPMODE(sysctl);
+               bf537mac_multicast_hash(dev);
        } else {
                /* clear promisc or multicast mode */
                sysctl = bfin_read_EMAC_OPMODE();
@@ -860,10 +890,10 @@ static int bf537mac_open(struct net_device *dev)
                return retval;
 
        phy_start(lp->phydev);
+       phy_write(lp->phydev, MII_BMCR, BMCR_RESET);
        setup_system_regs(dev);
        bf537mac_disable();
        bf537mac_enable();
-
        pr_debug("hardware init finished\n");
        netif_start_queue(dev);
        netif_carrier_on(dev);
@@ -886,6 +916,7 @@ static int bf537mac_close(struct net_device *dev)
        netif_carrier_off(dev);
 
        phy_stop(lp->phydev);
+       phy_write(lp->phydev, MII_BMCR, BMCR_PDOWN);
 
        /* clear everything */
        bf537mac_shutdown(dev);
@@ -970,7 +1001,7 @@ static int __init bf537mac_probe(struct net_device *dev)
        /* register irq handler */
        if (request_irq
            (IRQ_MAC_RX, bf537mac_interrupt, IRQF_DISABLED | IRQF_SHARED,
-            "BFIN537_MAC_RX", dev)) {
+            "EMAC_RX", dev)) {
                printk(KERN_WARNING DRV_NAME
                       ": Unable to attach BlackFin MAC RX interrupt\n");
                return -EBUSY;
index 5970ea7142cd53c3e5f1d4234110a484f8af0191..f774d5a36942aa4dcaf6f1e6078b9aa84d521ebf 100644 (file)
@@ -1,34 +1,11 @@
 /*
- * File:       drivers/net/bfin_mac.c
- * Based on:
- * Maintainer:
- *             Bryan Wu <bryan.wu@analog.com>
+ * Blackfin On-Chip MAC Driver
  *
- * Original author:
- *             Luke Yang <luke.yang@analog.com>
+ * Copyright 2004-2007 Analog Devices Inc.
  *
- * Created:
- * Description:
+ * Enter bugs at http://blackfin.uclinux.org/
  *
- * Modified:
- *             Copyright 2004-2006 Analog Devices Inc.
- *
- * Bugs:       Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software ;  you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation ;  either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY ;  without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program ;  see the file COPYING.
- * If not, write to the Free Software Foundation,
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Licensed under the GPL-2 or later.
  */
 
 #define BFIN_MAC_CSUM_OFFLOAD
index 34aebc6e75896011fae724cf0d44b8b19868c31c..8b552c6dd2e7b053248eff254abc103cbef38e87 100644 (file)
@@ -56,8 +56,8 @@
 
 #define DRV_MODULE_NAME                "bnx2"
 #define PFX DRV_MODULE_NAME    ": "
-#define DRV_MODULE_VERSION     "1.7.2"
-#define DRV_MODULE_RELDATE     "January 21, 2008"
+#define DRV_MODULE_VERSION     "1.7.3"
+#define DRV_MODULE_RELDATE     "January 29, 2008"
 
 #define RUN_AT(x) (jiffies + (x))
 
@@ -265,6 +265,18 @@ bnx2_reg_wr_ind(struct bnx2 *bp, u32 offset, u32 val)
        spin_unlock_bh(&bp->indirect_lock);
 }
 
+static void
+bnx2_shmem_wr(struct bnx2 *bp, u32 offset, u32 val)
+{
+       bnx2_reg_wr_ind(bp, bp->shmem_base + offset, val);
+}
+
+static u32
+bnx2_shmem_rd(struct bnx2 *bp, u32 offset)
+{
+       return (bnx2_reg_rd_ind(bp, bp->shmem_base + offset));
+}
+
 static void
 bnx2_ctx_wr(struct bnx2 *bp, u32 cid_addr, u32 offset, u32 val)
 {
@@ -685,7 +697,7 @@ bnx2_report_fw_link(struct bnx2 *bp)
        else
                fw_link_status = BNX2_LINK_STATUS_LINK_DOWN;
 
-       REG_WR_IND(bp, bp->shmem_base + BNX2_LINK_STATUS, fw_link_status);
+       bnx2_shmem_wr(bp, BNX2_LINK_STATUS, fw_link_status);
 }
 
 static char *
@@ -980,6 +992,42 @@ bnx2_copper_linkup(struct bnx2 *bp)
        return 0;
 }
 
+static void
+bnx2_init_rx_context0(struct bnx2 *bp)
+{
+       u32 val, rx_cid_addr = GET_CID_ADDR(RX_CID);
+
+       val = BNX2_L2CTX_CTX_TYPE_CTX_BD_CHN_TYPE_VALUE;
+       val |= BNX2_L2CTX_CTX_TYPE_SIZE_L2;
+       val |= 0x02 << 8;
+
+       if (CHIP_NUM(bp) == CHIP_NUM_5709) {
+               u32 lo_water, hi_water;
+
+               if (bp->flow_ctrl & FLOW_CTRL_TX)
+                       lo_water = BNX2_L2CTX_LO_WATER_MARK_DEFAULT;
+               else
+                       lo_water = BNX2_L2CTX_LO_WATER_MARK_DIS;
+               if (lo_water >= bp->rx_ring_size)
+                       lo_water = 0;
+
+               hi_water = bp->rx_ring_size / 4;
+
+               if (hi_water <= lo_water)
+                       lo_water = 0;
+
+               hi_water /= BNX2_L2CTX_HI_WATER_MARK_SCALE;
+               lo_water /= BNX2_L2CTX_LO_WATER_MARK_SCALE;
+
+               if (hi_water > 0xf)
+                       hi_water = 0xf;
+               else if (hi_water == 0)
+                       lo_water = 0;
+               val |= lo_water | (hi_water << BNX2_L2CTX_HI_WATER_MARK_SHIFT);
+       }
+       bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_CTX_TYPE, val);
+}
+
 static int
 bnx2_set_mac_link(struct bnx2 *bp)
 {
@@ -1044,6 +1092,9 @@ bnx2_set_mac_link(struct bnx2 *bp)
        /* Acknowledge the interrupt. */
        REG_WR(bp, BNX2_EMAC_STATUS, BNX2_EMAC_STATUS_LINK_CHANGE);
 
+       if (CHIP_NUM(bp) == CHIP_NUM_5709)
+               bnx2_init_rx_context0(bp);
+
        return 0;
 }
 
@@ -1378,14 +1429,14 @@ bnx2_setup_remote_phy(struct bnx2 *bp, u8 port)
 
        if (pause_adv & (ADVERTISE_1000XPAUSE | ADVERTISE_PAUSE_CAP))
                speed_arg |= BNX2_NETLINK_SET_LINK_FC_SYM_PAUSE;
-       if (pause_adv & (ADVERTISE_1000XPSE_ASYM | ADVERTISE_1000XPSE_ASYM))
+       if (pause_adv & (ADVERTISE_1000XPSE_ASYM | ADVERTISE_PAUSE_ASYM))
                speed_arg |= BNX2_NETLINK_SET_LINK_FC_ASYM_PAUSE;
 
        if (port == PORT_TP)
                speed_arg |= BNX2_NETLINK_SET_LINK_PHY_APP_REMOTE |
                             BNX2_NETLINK_SET_LINK_ETH_AT_WIRESPEED;
 
-       REG_WR_IND(bp, bp->shmem_base + BNX2_DRV_MB_ARG0, speed_arg);
+       bnx2_shmem_wr(bp, BNX2_DRV_MB_ARG0, speed_arg);
 
        spin_unlock_bh(&bp->phy_lock);
        bnx2_fw_sync(bp, BNX2_DRV_MSG_CODE_CMD_SET_LINK, 0);
@@ -1530,9 +1581,9 @@ bnx2_set_default_remote_link(struct bnx2 *bp)
        u32 link;
 
        if (bp->phy_port == PORT_TP)
-               link = REG_RD_IND(bp, bp->shmem_base + BNX2_RPHY_COPPER_LINK);
+               link = bnx2_shmem_rd(bp, BNX2_RPHY_COPPER_LINK);
        else
-               link = REG_RD_IND(bp, bp->shmem_base + BNX2_RPHY_SERDES_LINK);
+               link = bnx2_shmem_rd(bp, BNX2_RPHY_SERDES_LINK);
 
        if (link & BNX2_NETLINK_SET_LINK_ENABLE_AUTONEG) {
                bp->req_line_speed = 0;
@@ -1584,7 +1635,7 @@ bnx2_set_default_link(struct bnx2 *bp)
 
                bp->advertising = ETHTOOL_ALL_FIBRE_SPEED | ADVERTISED_Autoneg;
 
-               reg = REG_RD_IND(bp, bp->shmem_base + BNX2_PORT_HW_CFG_CONFIG);
+               reg = bnx2_shmem_rd(bp, BNX2_PORT_HW_CFG_CONFIG);
                reg &= BNX2_PORT_HW_CFG_CFG_DFLT_LINK_MASK;
                if (reg == BNX2_PORT_HW_CFG_CFG_DFLT_LINK_1G) {
                        bp->autoneg = 0;
@@ -1616,7 +1667,7 @@ bnx2_remote_phy_event(struct bnx2 *bp)
        u8 link_up = bp->link_up;
        u8 old_port;
 
-       msg = REG_RD_IND(bp, bp->shmem_base + BNX2_LINK_STATUS);
+       msg = bnx2_shmem_rd(bp, BNX2_LINK_STATUS);
 
        if (msg & BNX2_LINK_STATUS_HEART_BEAT_EXPIRED)
                bnx2_send_heart_beat(bp);
@@ -1693,7 +1744,7 @@ bnx2_set_remote_link(struct bnx2 *bp)
 {
        u32 evt_code;
 
-       evt_code = REG_RD_IND(bp, bp->shmem_base + BNX2_FW_EVT_CODE_MB);
+       evt_code = bnx2_shmem_rd(bp, BNX2_FW_EVT_CODE_MB);
        switch (evt_code) {
                case BNX2_FW_EVT_CODE_LINK_EVENT:
                        bnx2_remote_phy_event(bp);
@@ -1905,14 +1956,13 @@ bnx2_init_5708s_phy(struct bnx2 *bp)
                bnx2_write_phy(bp, BCM5708S_BLK_ADDR, BCM5708S_BLK_ADDR_DIG);
        }
 
-       val = REG_RD_IND(bp, bp->shmem_base + BNX2_PORT_HW_CFG_CONFIG) &
+       val = bnx2_shmem_rd(bp, BNX2_PORT_HW_CFG_CONFIG) &
              BNX2_PORT_HW_CFG_CFG_TXCTL3_MASK;
 
        if (val) {
                u32 is_backplane;
 
-               is_backplane = REG_RD_IND(bp, bp->shmem_base +
-                                         BNX2_SHARED_HW_CFG_CONFIG);
+               is_backplane = bnx2_shmem_rd(bp, BNX2_SHARED_HW_CFG_CONFIG);
                if (is_backplane & BNX2_SHARED_HW_CFG_PHY_BACKPLANE) {
                        bnx2_write_phy(bp, BCM5708S_BLK_ADDR,
                                       BCM5708S_BLK_ADDR_TX_MISC);
@@ -2111,13 +2161,13 @@ bnx2_fw_sync(struct bnx2 *bp, u32 msg_data, int silent)
        bp->fw_wr_seq++;
        msg_data |= bp->fw_wr_seq;
 
-       REG_WR_IND(bp, bp->shmem_base + BNX2_DRV_MB, msg_data);
+       bnx2_shmem_wr(bp, BNX2_DRV_MB, msg_data);
 
        /* wait for an acknowledgement. */
        for (i = 0; i < (FW_ACK_TIME_OUT_MS / 10); i++) {
                msleep(10);
 
-               val = REG_RD_IND(bp, bp->shmem_base + BNX2_FW_MB);
+               val = bnx2_shmem_rd(bp, BNX2_FW_MB);
 
                if ((val & BNX2_FW_MSG_ACK) == (msg_data & BNX2_DRV_MSG_SEQ))
                        break;
@@ -2134,7 +2184,7 @@ bnx2_fw_sync(struct bnx2 *bp, u32 msg_data, int silent)
                msg_data &= ~BNX2_DRV_MSG_CODE;
                msg_data |= BNX2_DRV_MSG_CODE_FW_TIMEOUT;
 
-               REG_WR_IND(bp, bp->shmem_base + BNX2_DRV_MB, msg_data);
+               bnx2_shmem_wr(bp, BNX2_DRV_MB, msg_data);
 
                return -EBUSY;
        }
@@ -2226,7 +2276,7 @@ bnx2_init_context(struct bnx2 *bp)
 
                        /* Zero out the context. */
                        for (offset = 0; offset < PHY_CTX_SIZE; offset += 4)
-                               CTX_WR(bp, vcid_addr, offset, 0);
+                               bnx2_ctx_wr(bp, vcid_addr, offset, 0);
                }
        }
 }
@@ -2251,11 +2301,12 @@ bnx2_alloc_bad_rbuf(struct bnx2 *bp)
        good_mbuf_cnt = 0;
 
        /* Allocate a bunch of mbufs and save the good ones in an array. */
-       val = REG_RD_IND(bp, BNX2_RBUF_STATUS1);
+       val = bnx2_reg_rd_ind(bp, BNX2_RBUF_STATUS1);
        while (val & BNX2_RBUF_STATUS1_FREE_COUNT) {
-               REG_WR_IND(bp, BNX2_RBUF_COMMAND, BNX2_RBUF_COMMAND_ALLOC_REQ);
+               bnx2_reg_wr_ind(bp, BNX2_RBUF_COMMAND,
+                               BNX2_RBUF_COMMAND_ALLOC_REQ);
 
-               val = REG_RD_IND(bp, BNX2_RBUF_FW_BUF_ALLOC);
+               val = bnx2_reg_rd_ind(bp, BNX2_RBUF_FW_BUF_ALLOC);
 
                val &= BNX2_RBUF_FW_BUF_ALLOC_VALUE;
 
@@ -2265,7 +2316,7 @@ bnx2_alloc_bad_rbuf(struct bnx2 *bp)
                        good_mbuf_cnt++;
                }
 
-               val = REG_RD_IND(bp, BNX2_RBUF_STATUS1);
+               val = bnx2_reg_rd_ind(bp, BNX2_RBUF_STATUS1);
        }
 
        /* Free the good ones back to the mbuf pool thus discarding
@@ -2276,7 +2327,7 @@ bnx2_alloc_bad_rbuf(struct bnx2 *bp)
                val = good_mbuf[good_mbuf_cnt];
                val = (val << 9) | val | 1;
 
-               REG_WR_IND(bp, BNX2_RBUF_FW_BUF_FREE, val);
+               bnx2_reg_wr_ind(bp, BNX2_RBUF_FW_BUF_FREE, val);
        }
        kfree(good_mbuf);
        return 0;
@@ -3151,10 +3202,10 @@ load_cpu_fw(struct bnx2 *bp, struct cpu_reg *cpu_reg, struct fw_info *fw)
        int rc;
 
        /* Halt the CPU. */
-       val = REG_RD_IND(bp, cpu_reg->mode);
+       val = bnx2_reg_rd_ind(bp, cpu_reg->mode);
        val |= cpu_reg->mode_value_halt;
-       REG_WR_IND(bp, cpu_reg->mode, val);
-       REG_WR_IND(bp, cpu_reg->state, cpu_reg->state_value_clear);
+       bnx2_reg_wr_ind(bp, cpu_reg->mode, val);
+       bnx2_reg_wr_ind(bp, cpu_reg->state, cpu_reg->state_value_clear);
 
        /* Load the Text area. */
        offset = cpu_reg->spad_base + (fw->text_addr - cpu_reg->mips_view_base);
@@ -3167,7 +3218,7 @@ load_cpu_fw(struct bnx2 *bp, struct cpu_reg *cpu_reg, struct fw_info *fw)
                        return rc;
 
                for (j = 0; j < (fw->text_len / 4); j++, offset += 4) {
-                       REG_WR_IND(bp, offset, le32_to_cpu(fw->text[j]));
+                       bnx2_reg_wr_ind(bp, offset, le32_to_cpu(fw->text[j]));
                }
        }
 
@@ -3177,7 +3228,7 @@ load_cpu_fw(struct bnx2 *bp, struct cpu_reg *cpu_reg, struct fw_info *fw)
                int j;
 
                for (j = 0; j < (fw->data_len / 4); j++, offset += 4) {
-                       REG_WR_IND(bp, offset, fw->data[j]);
+                       bnx2_reg_wr_ind(bp, offset, fw->data[j]);
                }
        }
 
@@ -3187,7 +3238,7 @@ load_cpu_fw(struct bnx2 *bp, struct cpu_reg *cpu_reg, struct fw_info *fw)
                int j;
 
                for (j = 0; j < (fw->sbss_len / 4); j++, offset += 4) {
-                       REG_WR_IND(bp, offset, 0);
+                       bnx2_reg_wr_ind(bp, offset, 0);
                }
        }
 
@@ -3197,7 +3248,7 @@ load_cpu_fw(struct bnx2 *bp, struct cpu_reg *cpu_reg, struct fw_info *fw)
                int j;
 
                for (j = 0; j < (fw->bss_len/4); j++, offset += 4) {
-                       REG_WR_IND(bp, offset, 0);
+                       bnx2_reg_wr_ind(bp, offset, 0);
                }
        }
 
@@ -3208,19 +3259,19 @@ load_cpu_fw(struct bnx2 *bp, struct cpu_reg *cpu_reg, struct fw_info *fw)
                int j;
 
                for (j = 0; j < (fw->rodata_len / 4); j++, offset += 4) {
-                       REG_WR_IND(bp, offset, fw->rodata[j]);
+                       bnx2_reg_wr_ind(bp, offset, fw->rodata[j]);
                }
        }
 
        /* Clear the pre-fetch instruction. */
-       REG_WR_IND(bp, cpu_reg->inst, 0);
-       REG_WR_IND(bp, cpu_reg->pc, fw->start_addr);
+       bnx2_reg_wr_ind(bp, cpu_reg->inst, 0);
+       bnx2_reg_wr_ind(bp, cpu_reg->pc, fw->start_addr);
 
        /* Start the CPU. */
-       val = REG_RD_IND(bp, cpu_reg->mode);
+       val = bnx2_reg_rd_ind(bp, cpu_reg->mode);
        val &= ~cpu_reg->mode_value_halt;
-       REG_WR_IND(bp, cpu_reg->state, cpu_reg->state_value_clear);
-       REG_WR_IND(bp, cpu_reg->mode, val);
+       bnx2_reg_wr_ind(bp, cpu_reg->state, cpu_reg->state_value_clear);
+       bnx2_reg_wr_ind(bp, cpu_reg->mode, val);
 
        return 0;
 }
@@ -3833,7 +3884,7 @@ bnx2_init_nvram(struct bnx2 *bp)
        }
 
 get_flash_size:
-       val = REG_RD_IND(bp, bp->shmem_base + BNX2_SHARED_HW_CFG_CONFIG2);
+       val = bnx2_shmem_rd(bp, BNX2_SHARED_HW_CFG_CONFIG2);
        val &= BNX2_SHARED_HW_CFG2_NVM_SIZE_MASK;
        if (val)
                bp->flash_size = val;
@@ -4142,14 +4193,14 @@ bnx2_init_remote_phy(struct bnx2 *bp)
        if (!(bp->phy_flags & BNX2_PHY_FLAG_SERDES))
                return;
 
-       val = REG_RD_IND(bp, bp->shmem_base + BNX2_FW_CAP_MB);
+       val = bnx2_shmem_rd(bp, BNX2_FW_CAP_MB);
        if ((val & BNX2_FW_CAP_SIGNATURE_MASK) != BNX2_FW_CAP_SIGNATURE)
                return;
 
        if (val & BNX2_FW_CAP_REMOTE_PHY_CAPABLE) {
                bp->phy_flags |= BNX2_PHY_FLAG_REMOTE_PHY_CAP;
 
-               val = REG_RD_IND(bp, bp->shmem_base + BNX2_LINK_STATUS);
+               val = bnx2_shmem_rd(bp, BNX2_LINK_STATUS);
                if (val & BNX2_LINK_STATUS_SERDES_LINK)
                        bp->phy_port = PORT_FIBRE;
                else
@@ -4167,8 +4218,7 @@ bnx2_init_remote_phy(struct bnx2 *bp)
                        }
                        sig = BNX2_DRV_ACK_CAP_SIGNATURE |
                              BNX2_FW_CAP_REMOTE_PHY_CAPABLE;
-                       REG_WR_IND(bp, bp->shmem_base + BNX2_DRV_ACK_CAP_MB,
-                                  sig);
+                       bnx2_shmem_wr(bp, BNX2_DRV_ACK_CAP_MB, sig);
                }
        }
 }
@@ -4204,8 +4254,8 @@ bnx2_reset_chip(struct bnx2 *bp, u32 reset_code)
 
        /* Deposit a driver reset signature so the firmware knows that
         * this is a soft reset. */
-       REG_WR_IND(bp, bp->shmem_base + BNX2_DRV_RESET_SIGNATURE,
-                  BNX2_DRV_RESET_SIGNATURE_MAGIC);
+       bnx2_shmem_wr(bp, BNX2_DRV_RESET_SIGNATURE,
+                     BNX2_DRV_RESET_SIGNATURE_MAGIC);
 
        /* Do a dummy read to force the chip to complete all current transaction
         * before we issue a reset. */
@@ -4438,18 +4488,21 @@ bnx2_init_chip(struct bnx2 *bp)
        }
 
        if (bp->flags & BNX2_FLAG_USING_MSIX) {
+               u32 base = ((BNX2_TX_VEC - 1) * BNX2_HC_SB_CONFIG_SIZE) +
+                          BNX2_HC_SB_CONFIG_1;
+
                REG_WR(bp, BNX2_HC_MSIX_BIT_VECTOR,
                       BNX2_HC_MSIX_BIT_VECTOR_VAL);
 
-               REG_WR(bp, BNX2_HC_SB_CONFIG_1,
+               REG_WR(bp, base,
                        BNX2_HC_SB_CONFIG_1_TX_TMR_MODE |
                        BNX2_HC_SB_CONFIG_1_ONE_SHOT);
 
-               REG_WR(bp, BNX2_HC_TX_QUICK_CONS_TRIP_1,
+               REG_WR(bp, base + BNX2_HC_TX_QUICK_CONS_TRIP_OFF,
                        (bp->tx_quick_cons_trip_int << 16) |
                         bp->tx_quick_cons_trip);
 
-               REG_WR(bp, BNX2_HC_TX_TICKS_1,
+               REG_WR(bp, base + BNX2_HC_TX_TICKS_OFF,
                        (bp->tx_ticks_int << 16) | bp->tx_ticks);
 
                val |= BNX2_HC_CONFIG_SB_ADDR_INC_128B;
@@ -4509,6 +4562,7 @@ static void
 bnx2_init_tx_context(struct bnx2 *bp, u32 cid)
 {
        u32 val, offset0, offset1, offset2, offset3;
+       u32 cid_addr = GET_CID_ADDR(cid);
 
        if (CHIP_NUM(bp) == CHIP_NUM_5709) {
                offset0 = BNX2_L2CTX_TYPE_XI;
@@ -4522,16 +4576,16 @@ bnx2_init_tx_context(struct bnx2 *bp, u32 cid)
                offset3 = BNX2_L2CTX_TBDR_BHADDR_LO;
        }
        val = BNX2_L2CTX_TYPE_TYPE_L2 | BNX2_L2CTX_TYPE_SIZE_L2;
-       CTX_WR(bp, GET_CID_ADDR(cid), offset0, val);
+       bnx2_ctx_wr(bp, cid_addr, offset0, val);
 
        val = BNX2_L2CTX_CMD_TYPE_TYPE_L2 | (8 << 16);
-       CTX_WR(bp, GET_CID_ADDR(cid), offset1, val);
+       bnx2_ctx_wr(bp, cid_addr, offset1, val);
 
        val = (u64) bp->tx_desc_mapping >> 32;
-       CTX_WR(bp, GET_CID_ADDR(cid), offset2, val);
+       bnx2_ctx_wr(bp, cid_addr, offset2, val);
 
        val = (u64) bp->tx_desc_mapping & 0xffffffff;
-       CTX_WR(bp, GET_CID_ADDR(cid), offset3, val);
+       bnx2_ctx_wr(bp, cid_addr, offset3, val);
 }
 
 static void
@@ -4601,36 +4655,38 @@ bnx2_init_rx_ring(struct bnx2 *bp)
        bnx2_init_rxbd_rings(bp->rx_desc_ring, bp->rx_desc_mapping,
                             bp->rx_buf_use_size, bp->rx_max_ring);
 
-       CTX_WR(bp, rx_cid_addr, BNX2_L2CTX_PG_BUF_SIZE, 0);
+       bnx2_init_rx_context0(bp);
+
+       if (CHIP_NUM(bp) == CHIP_NUM_5709) {
+               val = REG_RD(bp, BNX2_MQ_MAP_L2_5);
+               REG_WR(bp, BNX2_MQ_MAP_L2_5, val | BNX2_MQ_MAP_L2_5_ARM);
+       }
+
+       bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_PG_BUF_SIZE, 0);
        if (bp->rx_pg_ring_size) {
                bnx2_init_rxbd_rings(bp->rx_pg_desc_ring,
                                     bp->rx_pg_desc_mapping,
                                     PAGE_SIZE, bp->rx_max_pg_ring);
                val = (bp->rx_buf_use_size << 16) | PAGE_SIZE;
-               CTX_WR(bp, rx_cid_addr, BNX2_L2CTX_PG_BUF_SIZE, val);
-               CTX_WR(bp, rx_cid_addr, BNX2_L2CTX_RBDC_KEY,
+               bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_PG_BUF_SIZE, val);
+               bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_RBDC_KEY,
                       BNX2_L2CTX_RBDC_JUMBO_KEY);
 
                val = (u64) bp->rx_pg_desc_mapping[0] >> 32;
-               CTX_WR(bp, rx_cid_addr, BNX2_L2CTX_NX_PG_BDHADDR_HI, val);
+               bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_NX_PG_BDHADDR_HI, val);
 
                val = (u64) bp->rx_pg_desc_mapping[0] & 0xffffffff;
-               CTX_WR(bp, rx_cid_addr, BNX2_L2CTX_NX_PG_BDHADDR_LO, val);
+               bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_NX_PG_BDHADDR_LO, val);
 
                if (CHIP_NUM(bp) == CHIP_NUM_5709)
                        REG_WR(bp, BNX2_MQ_MAP_L2_3, BNX2_MQ_MAP_L2_3_DEFAULT);
        }
 
-       val = BNX2_L2CTX_CTX_TYPE_CTX_BD_CHN_TYPE_VALUE;
-       val |= BNX2_L2CTX_CTX_TYPE_SIZE_L2;
-       val |= 0x02 << 8;
-       CTX_WR(bp, rx_cid_addr, BNX2_L2CTX_CTX_TYPE, val);
-
        val = (u64) bp->rx_desc_mapping[0] >> 32;
-       CTX_WR(bp, rx_cid_addr, BNX2_L2CTX_NX_BDHADDR_HI, val);
+       bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_NX_BDHADDR_HI, val);
 
        val = (u64) bp->rx_desc_mapping[0] & 0xffffffff;
-       CTX_WR(bp, rx_cid_addr, BNX2_L2CTX_NX_BDHADDR_LO, val);
+       bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_NX_BDHADDR_LO, val);
 
        ring_prod = prod = bnapi->rx_pg_prod;
        for (i = 0; i < bp->rx_pg_ring_size; i++) {
@@ -5003,9 +5059,9 @@ bnx2_do_mem_test(struct bnx2 *bp, u32 start, u32 size)
 
                for (offset = 0; offset < size; offset += 4) {
 
-                       REG_WR_IND(bp, start + offset, test_pattern[i]);
+                       bnx2_reg_wr_ind(bp, start + offset, test_pattern[i]);
 
-                       if (REG_RD_IND(bp, start + offset) !=
+                       if (bnx2_reg_rd_ind(bp, start + offset) !=
                                test_pattern[i]) {
                                return -ENODEV;
                        }
@@ -5315,7 +5371,7 @@ bnx2_5706_serdes_has_link(struct bnx2 *bp)
        bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &an_dbg);
        bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &an_dbg);
 
-       if (an_dbg & MISC_SHDW_AN_DBG_NOSYNC)
+       if (an_dbg & (MISC_SHDW_AN_DBG_NOSYNC | MISC_SHDW_AN_DBG_RUDI_INVALID))
                return 0;
 
        bnx2_write_phy(bp, MII_BNX2_DSP_ADDRESS, MII_EXPAND_REG1);
@@ -5440,7 +5496,8 @@ bnx2_timer(unsigned long data)
 
        bnx2_send_heart_beat(bp);
 
-       bp->stats_blk->stat_FwRxDrop = REG_RD_IND(bp, BNX2_FW_RX_DROP_COUNT);
+       bp->stats_blk->stat_FwRxDrop =
+               bnx2_reg_rd_ind(bp, BNX2_FW_RX_DROP_COUNT);
 
        /* workaround occasional corrupted counters */
        if (CHIP_NUM(bp) == CHIP_NUM_5708 && bp->stats_ticks)
@@ -7155,20 +7212,20 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
 
        bnx2_init_nvram(bp);
 
-       reg = REG_RD_IND(bp, BNX2_SHM_HDR_SIGNATURE);
+       reg = bnx2_reg_rd_ind(bp, BNX2_SHM_HDR_SIGNATURE);
 
        if ((reg & BNX2_SHM_HDR_SIGNATURE_SIG_MASK) ==
            BNX2_SHM_HDR_SIGNATURE_SIG) {
                u32 off = PCI_FUNC(pdev->devfn) << 2;
 
-               bp->shmem_base = REG_RD_IND(bp, BNX2_SHM_HDR_ADDR_0 + off);
+               bp->shmem_base = bnx2_reg_rd_ind(bp, BNX2_SHM_HDR_ADDR_0 + off);
        } else
                bp->shmem_base = HOST_VIEW_SHMEM_BASE;
 
        /* Get the permanent MAC address.  First we need to make sure the
         * firmware is actually running.
         */
-       reg = REG_RD_IND(bp, bp->shmem_base + BNX2_DEV_INFO_SIGNATURE);
+       reg = bnx2_shmem_rd(bp, BNX2_DEV_INFO_SIGNATURE);
 
        if ((reg & BNX2_DEV_INFO_SIGNATURE_MAGIC_MASK) !=
            BNX2_DEV_INFO_SIGNATURE_MAGIC) {
@@ -7177,7 +7234,7 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
                goto err_out_unmap;
        }
 
-       reg = REG_RD_IND(bp, bp->shmem_base + BNX2_DEV_INFO_BC_REV);
+       reg = bnx2_shmem_rd(bp, BNX2_DEV_INFO_BC_REV);
        for (i = 0, j = 0; i < 3; i++) {
                u8 num, k, skip0;
 
@@ -7191,7 +7248,7 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
                if (i != 2)
                        bp->fw_version[j++] = '.';
        }
-       reg = REG_RD_IND(bp, bp->shmem_base + BNX2_PORT_FEATURE);
+       reg = bnx2_shmem_rd(bp, BNX2_PORT_FEATURE);
        if (reg & BNX2_PORT_FEATURE_WOL_ENABLED)
                bp->wol = 1;
 
@@ -7199,34 +7256,33 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
                bp->flags |= BNX2_FLAG_ASF_ENABLE;
 
                for (i = 0; i < 30; i++) {
-                       reg = REG_RD_IND(bp, bp->shmem_base +
-                                            BNX2_BC_STATE_CONDITION);
+                       reg = bnx2_shmem_rd(bp, BNX2_BC_STATE_CONDITION);
                        if (reg & BNX2_CONDITION_MFW_RUN_MASK)
                                break;
                        msleep(10);
                }
        }
-       reg = REG_RD_IND(bp, bp->shmem_base + BNX2_BC_STATE_CONDITION);
+       reg = bnx2_shmem_rd(bp, BNX2_BC_STATE_CONDITION);
        reg &= BNX2_CONDITION_MFW_RUN_MASK;
        if (reg != BNX2_CONDITION_MFW_RUN_UNKNOWN &&
            reg != BNX2_CONDITION_MFW_RUN_NONE) {
                int i;
-               u32 addr = REG_RD_IND(bp, bp->shmem_base + BNX2_MFW_VER_PTR);
+               u32 addr = bnx2_shmem_rd(bp, BNX2_MFW_VER_PTR);
 
                bp->fw_version[j++] = ' ';
                for (i = 0; i < 3; i++) {
-                       reg = REG_RD_IND(bp, addr + i * 4);
+                       reg = bnx2_reg_rd_ind(bp, addr + i * 4);
                        reg = swab32(reg);
                        memcpy(&bp->fw_version[j], &reg, 4);
                        j += 4;
                }
        }
 
-       reg = REG_RD_IND(bp, bp->shmem_base + BNX2_PORT_HW_CFG_MAC_UPPER);
+       reg = bnx2_shmem_rd(bp, BNX2_PORT_HW_CFG_MAC_UPPER);
        bp->mac_addr[0] = (u8) (reg >> 8);
        bp->mac_addr[1] = (u8) reg;
 
-       reg = REG_RD_IND(bp, bp->shmem_base + BNX2_PORT_HW_CFG_MAC_LOWER);
+       reg = bnx2_shmem_rd(bp, BNX2_PORT_HW_CFG_MAC_LOWER);
        bp->mac_addr[2] = (u8) (reg >> 24);
        bp->mac_addr[3] = (u8) (reg >> 16);
        bp->mac_addr[4] = (u8) (reg >> 8);
@@ -7265,8 +7321,7 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
        bp->phy_port = PORT_TP;
        if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
                bp->phy_port = PORT_FIBRE;
-               reg = REG_RD_IND(bp, bp->shmem_base +
-                                    BNX2_SHARED_HW_CFG_CONFIG);
+               reg = bnx2_shmem_rd(bp, BNX2_SHARED_HW_CFG_CONFIG);
                if (!(reg & BNX2_SHARED_HW_CFG_GIG_LINK_ON_VAUX)) {
                        bp->flags |= BNX2_FLAG_NO_WOL;
                        bp->wol = 0;
index d8e034700c363420e1aef24dd27a01bf56358da8..3aa0364942e294047096f544b1644430f6483bb5 100644 (file)
@@ -348,6 +348,12 @@ struct l2_fhdr {
 #define BNX2_L2CTX_BD_PRE_READ                         0x00000000
 #define BNX2_L2CTX_CTX_SIZE                            0x00000000
 #define BNX2_L2CTX_CTX_TYPE                            0x00000000
+#define BNX2_L2CTX_LO_WATER_MARK_DEFAULT                32
+#define BNX2_L2CTX_LO_WATER_MARK_SCALE                  4
+#define BNX2_L2CTX_LO_WATER_MARK_DIS                    0
+#define BNX2_L2CTX_HI_WATER_MARK_SHIFT                  4
+#define BNX2_L2CTX_HI_WATER_MARK_SCALE                  16
+#define BNX2_L2CTX_WATER_MARKS_MSK                      0x000000ff
 #define BNX2_L2CTX_CTX_TYPE_SIZE_L2                     ((0x20/20)<<16)
 #define BNX2_L2CTX_CTX_TYPE_CTX_BD_CHN_TYPE             (0xf<<28)
 #define BNX2_L2CTX_CTX_TYPE_CTX_BD_CHN_TYPE_UNDEFINED   (0<<28)
@@ -4494,6 +4500,9 @@ struct l2_fhdr {
 #define BNX2_MQ_MAP_L2_3_ENA                            (0x1L<<31)
 #define BNX2_MQ_MAP_L2_3_DEFAULT                        0x82004646
 
+#define BNX2_MQ_MAP_L2_5                               0x00003d34
+#define BNX2_MQ_MAP_L2_5_ARM                            (0x3L<<26)
+
 /*
  *  tsch_reg definition
  *  offset: 0x4c00
@@ -5510,6 +5519,15 @@ struct l2_fhdr {
 #define BNX2_HC_PERIODIC_TICKS_8_HC_PERIODIC_TICKS      (0xffffL<<0)
 #define BNX2_HC_PERIODIC_TICKS_8_HC_INT_PERIODIC_TICKS  (0xffffL<<16)
 
+#define BNX2_HC_SB_CONFIG_SIZE (BNX2_HC_SB_CONFIG_2 - BNX2_HC_SB_CONFIG_1)
+#define BNX2_HC_COMP_PROD_TRIP_OFF     (BNX2_HC_COMP_PROD_TRIP_1 -     \
+                                        BNX2_HC_SB_CONFIG_1)
+#define BNX2_HC_COM_TICKS_OFF  (BNX2_HC_COM_TICKS_1 - BNX2_HC_SB_CONFIG_1)
+#define BNX2_HC_CMD_TICKS_OFF  (BNX2_HC_CMD_TICKS_1 - BNX2_HC_SB_CONFIG_1)
+#define BNX2_HC_TX_QUICK_CONS_TRIP_OFF (BNX2_HC_TX_QUICK_CONS_TRIP_1 - \
+                                        BNX2_HC_SB_CONFIG_1)
+#define BNX2_HC_TX_TICKS_OFF   (BNX2_HC_TX_TICKS_1 - BNX2_HC_SB_CONFIG_1)
+
 
 /*
  *  txp_reg definition
@@ -6346,11 +6364,12 @@ struct l2_fhdr {
 #define MII_BNX2_DSP_EXPAND_REG                         0x0f00
 #define MII_EXPAND_REG1                                  (MII_BNX2_DSP_EXPAND_REG | 1)
 #define MII_EXPAND_REG1_RUDI_C                    0x20
-#define MII_EXPAND_SERDES_CTL                    (MII_BNX2_DSP_EXPAND_REG | 2)
+#define MII_EXPAND_SERDES_CTL                    (MII_BNX2_DSP_EXPAND_REG | 3)
 
 #define MII_BNX2_MISC_SHADOW                   0x1c
 #define MISC_SHDW_AN_DBG                        0x6800
 #define MISC_SHDW_AN_DBG_NOSYNC                          0x0002
+#define MISC_SHDW_AN_DBG_RUDI_INVALID            0x0100
 #define MISC_SHDW_MODE_CTL                      0x7c00
 #define MISC_SHDW_MODE_CTL_SIG_DET               0x0010
 
@@ -6395,7 +6414,7 @@ struct l2_fhdr {
 
 #define RX_COPY_THRESH                 128
 
-#define BNX2_MISC_ENABLE_DEFAULT       0x7ffffff
+#define BNX2_MISC_ENABLE_DEFAULT       0x17ffffff
 
 #define DMA_READ_CHANS 5
 #define DMA_WRITE_CHANS        3
@@ -6795,9 +6814,6 @@ struct bnx2 {
        int                     irq_nvecs;
 };
 
-static u32 bnx2_reg_rd_ind(struct bnx2 *bp, u32 offset);
-static void bnx2_reg_wr_ind(struct bnx2 *bp, u32 offset, u32 val);
-
 #define REG_RD(bp, offset)                                     \
        readl(bp->regview + offset)
 
@@ -6807,19 +6823,6 @@ static void bnx2_reg_wr_ind(struct bnx2 *bp, u32 offset, u32 val);
 #define REG_WR16(bp, offset, val)                              \
        writew(val, bp->regview + offset)
 
-#define REG_RD_IND(bp, offset)                                 \
-       bnx2_reg_rd_ind(bp, offset)
-
-#define REG_WR_IND(bp, offset, val)                            \
-       bnx2_reg_wr_ind(bp, offset, val)
-
-/* Indirect context access.  Unlike the MBQ_WR, these macros will not
- * trigger a chip event. */
-static void bnx2_ctx_wr(struct bnx2 *bp, u32 cid_addr, u32 offset, u32 val);
-
-#define CTX_WR(bp, cid_addr, offset, val)                      \
-       bnx2_ctx_wr(bp, cid_addr, offset, val)
-
 struct cpu_reg {
        u32 mode;
        u32 mode_value_halt;
index c1ad4dd38c32e4d87613e7d79f519ae337178964..3b839d4626fe8ab9132ba1cfd7a4b3b19762bfc9 100644 (file)
@@ -2168,760 +2168,761 @@ static struct fw_info bnx2_cp_fw_06 = {
 };
 
 static u8 bnx2_RXP_b06FwText[] = {
-       0xec, 0x5b, 0x6d, 0x6c, 0x5c, 0x57, 0x5a, 0x7e, 0xef, 0x99, 0xb1, 0x3d,
-       0x76, 0x6c, 0xe7, 0xda, 0x99, 0xa6, 0x93, 0xe2, 0x6e, 0x67, 0xec, 0x6b,
-       0x7b, 0xba, 0x36, 0xe5, 0x3a, 0x4c, 0x5b, 0xaf, 0x18, 0xb6, 0xc3, 0x1d,
-       0x27, 0x75, 0x77, 0x83, 0xe4, 0xb6, 0x61, 0x37, 0x82, 0xae, 0xb0, 0x66,
-       0x12, 0x51, 0x84, 0x10, 0x21, 0x82, 0xaa, 0x2c, 0x5d, 0x65, 0x34, 0x76,
-       0x53, 0xb7, 0x3b, 0xf1, 0x0c, 0x89, 0x4b, 0xf8, 0xd8, 0x1f, 0xee, 0xd8,
-       0x4e, 0x0a, 0x9a, 0x78, 0xba, 0xcb, 0x8f, 0x5d, 0x56, 0x4d, 0x63, 0xd2,
-       0x12, 0xfa, 0x03, 0x89, 0x16, 0x56, 0x50, 0x89, 0x85, 0x86, 0x24, 0xdb,
-       0x14, 0x09, 0x41, 0x77, 0x01, 0x6d, 0xa1, 0x69, 0x2f, 0xcf, 0x73, 0xee,
-       0xbd, 0xc9, 0xc4, 0x35, 0x6c, 0x7f, 0xf0, 0xf3, 0x1e, 0xc9, 0xba, 0xf7,
-       0x9e, 0xf3, 0x9e, 0xf7, 0xbc, 0xdf, 0x1f, 0x67, 0x92, 0xdf, 0xe8, 0x96,
-       0x2e, 0xf1, 0x47, 0x0f, 0xfe, 0x32, 0x87, 0x9f, 0x3c, 0x72, 0xef, 0x3d,
-       0xf6, 0x3d, 0xfc, 0x8e, 0xb4, 0x49, 0x94, 0x4f, 0x43, 0xc2, 0x11, 0x8e,
-       0x70, 0x84, 0x23, 0x1c, 0xe1, 0x08, 0x47, 0x38, 0xc2, 0x11, 0x8e, 0x70,
-       0x84, 0x23, 0x1c, 0xe1, 0x08, 0x47, 0x38, 0xc2, 0x11, 0x8e, 0x70, 0x84,
-       0x23, 0x1c, 0xe1, 0x08, 0x47, 0x38, 0xc2, 0x11, 0x8e, 0x70, 0x84, 0x23,
-       0x1c, 0xe1, 0x08, 0x47, 0x38, 0xc2, 0x11, 0x8e, 0x70, 0x84, 0x23, 0x1c,
-       0xe1, 0x08, 0x47, 0x38, 0xc2, 0x11, 0x8e, 0x70, 0x84, 0x23, 0x1c, 0xe1,
-       0x08, 0x47, 0x38, 0xc2, 0xf1, 0xff, 0x39, 0x22, 0x22, 0x26, 0x9f, 0x3d,
-       0xfe, 0x9f, 0xc4, 0x54, 0x56, 0x8e, 0x38, 0x96, 0xc4, 0x22, 0xd9, 0xd5,
-       0x27, 0x8a, 0x96, 0x48, 0xae, 0x31, 0x96, 0xcc, 0xcb, 0x87, 0x6e, 0x29,
-       0x1e, 0x15, 0xce, 0xdf, 0x99, 0xbd, 0x7e, 0xf4, 0xdc, 0xfd, 0xa9, 0xf7,
-       0x96, 0x23, 0x12, 0x33, 0xb3, 0x6f, 0x4c, 0x98, 0x23, 0x12, 0x1b, 0xc0,
-       0x9e, 0xaf, 0x8d, 0xbe, 0xbc, 0x5d, 0x7a, 0x03, 0x5c, 0x22, 0xf5, 0x4a,
-       0xca, 0xde, 0x2b, 0x63, 0xe6, 0x05, 0x89, 0x4a, 0x0e, 0x67, 0x9c, 0x6e,
-       0x88, 0x94, 0x2b, 0x06, 0x71, 0x48, 0xb9, 0x11, 0x93, 0x4b, 0x11, 0x42,
-       0x7d, 0xcb, 0x70, 0xaa, 0x1f, 0xb9, 0xb9, 0x28, 0xce, 0xb5, 0xf0, 0xde,
-       0x0c, 0xe6, 0x63, 0xa2, 0xb2, 0xa9, 0x84, 0x13, 0x99, 0x96, 0xc2, 0x92,
-       0xeb, 0xce, 0xdb, 0xb7, 0x03, 0x47, 0xbf, 0xcc, 0x5b, 0xde, 0xb7, 0x63,
-       0x7f, 0xda, 0x9c, 0x92, 0x1d, 0x98, 0x8b, 0x88, 0xb2, 0xee, 0xc0, 0xdf,
-       0x57, 0x0d, 0x67, 0xa5, 0x5b, 0xca, 0x55, 0xc9, 0x39, 0x76, 0x0c, 0xf3,
-       0x09, 0x99, 0xab, 0x26, 0x0d, 0xe7, 0xa4, 0x21, 0xc5, 0x0c, 0xde, 0x9b,
-       0xae, 0x38, 0xf6, 0x47, 0xae, 0x63, 0x11, 0xff, 0x92, 0xe1, 0x9c, 0xf9,
-       0xc8, 0x55, 0x96, 0x65, 0x16, 0x84, 0xdf, 0x09, 0x29, 0x37, 0x89, 0x87,
-       0xef, 0xc4, 0x73, 0xc9, 0x3d, 0x37, 0x9a, 0x90, 0x6f, 0x34, 0xe3, 0xf2,
-       0xf5, 0xa6, 0x29, 0x2f, 0x35, 0x07, 0xe4, 0x7c, 0xd3, 0x75, 0xbf, 0x6e,
-       0xbb, 0xee, 0x1b, 0xf8, 0xfb, 0x81, 0x7d, 0x83, 0x66, 0x8c, 0x92, 0x31,
-       0xd5, 0xfc, 0xc3, 0x6e, 0xe9, 0x4d, 0x25, 0x45, 0x75, 0xe3, 0xcc, 0x84,
-       0xcc, 0x57, 0x2b, 0xc6, 0xc3, 0x67, 0x16, 0x8d, 0x99, 0x33, 0x35, 0x23,
-       0x7f, 0x26, 0x8a, 0x39, 0x29, 0x95, 0xed, 0x17, 0x8d, 0x7c, 0x73, 0xc1,
-       0x78, 0xe4, 0x4c, 0xaf, 0xa6, 0xad, 0x5c, 0xdd, 0x09, 0xda, 0xae, 0x83,
-       0x26, 0xca, 0x34, 0x65, 0xfe, 0x3c, 0xc4, 0xec, 0x54, 0xc8, 0x57, 0xbb,
-       0xe4, 0xe2, 0x5c, 0x77, 0x5d, 0x95, 0x75, 0x8f, 0x3a, 0x19, 0xcb, 0x2c,
-       0x0b, 0xe9, 0xd3, 0x73, 0xe7, 0x23, 0xa0, 0x39, 0x2f, 0xa7, 0x41, 0x7f,
-       0xb7, 0x91, 0x3f, 0x15, 0x05, 0x1d, 0x32, 0x10, 0x11, 0xee, 0x1b, 0x4e,
-       0x14, 0xa4, 0x81, 0x33, 0xc4, 0x54, 0x59, 0xca, 0x11, 0x34, 0x83, 0x96,
-       0x6f, 0x54, 0xc1, 0x43, 0x15, 0x3c, 0x54, 0xc9, 0x5b, 0x52, 0xce, 0x8d,
-       0x06, 0xbc, 0xb9, 0xee, 0x5f, 0xdb, 0xa4, 0x3d, 0x95, 0xcc, 0xa9, 0x80,
-       0x4f, 0xd7, 0xfd, 0xbe, 0x4d, 0x5e, 0xc9, 0x8f, 0xeb, 0xbe, 0x64, 0x53,
-       0x86, 0xee, 0x79, 0x65, 0x55, 0xc0, 0x8b, 0x05, 0xfc, 0x94, 0xef, 0x22,
-       0x78, 0x58, 0x00, 0x7f, 0xa7, 0xc1, 0x5b, 0x0d, 0x74, 0xfc, 0xa8, 0xf3,
-       0x4a, 0x46, 0x7e, 0xf4, 0x86, 0xbc, 0x92, 0x94, 0x71, 0x61, 0x55, 0x41,
-       0xd6, 0xdb, 0xa4, 0xb0, 0x6c, 0xca, 0xec, 0x6a, 0xb0, 0x3f, 0xd0, 0xfb,
-       0x61, 0xd9, 0x57, 0xed, 0x87, 0x6c, 0x28, 0xcb, 0x94, 0x2d, 0x42, 0xbd,
-       0x95, 0xd3, 0x4a, 0xc4, 0x28, 0xd8, 0x47, 0xb5, 0xbe, 0x57, 0x2d, 0xc9,
-       0x15, 0x6c, 0xca, 0x51, 0x92, 0x05, 0xbb, 0x94, 0x88, 0xc2, 0xbe, 0x56,
-       0xad, 0x92, 0x19, 0x15, 0xca, 0x31, 0x95, 0xf8, 0x32, 0x64, 0x79, 0xa8,
-       0x22, 0xb9, 0xcf, 0x55, 0x02, 0x19, 0x7b, 0xf2, 0xfd, 0x7c, 0xe5, 0xa7,
-       0x7b, 0xa4, 0x4b, 0x7d, 0xaa, 0x4d, 0x7e, 0x15, 0x7b, 0x89, 0xfb, 0x96,
-       0xbd, 0xd8, 0xe7, 0xc1, 0x79, 0x7b, 0x53, 0x07, 0x44, 0x08, 0x5b, 0x1e,
-       0x6a, 0xf3, 0x7c, 0xc2, 0x70, 0xac, 0x52, 0x22, 0x02, 0xb8, 0x82, 0x94,
-       0x27, 0xfc, 0xb9, 0x36, 0xc7, 0xba, 0x1e, 0x99, 0xb7, 0x53, 0xc9, 0xb2,
-       0x5c, 0x8f, 0x5c, 0xb4, 0xf5, 0x5c, 0xa7, 0x63, 0xb9, 0xb2, 0x06, 0xec,
-       0xcf, 0xc0, 0xfe, 0x2f, 0x80, 0xa3, 0x5f, 0xae, 0xe8, 0xf9, 0x1e, 0xec,
-       0x4f, 0xb7, 0x01, 0x67, 0x97, 0xa4, 0xd2, 0x75, 0xcc, 0x5f, 0xf4, 0xe6,
-       0xfb, 0x3c, 0xbc, 0xe5, 0xa1, 0x2e, 0x8d, 0x5b, 0xe4, 0x45, 0x6f, 0xfe,
-       0x36, 0x0f, 0x77, 0xf9, 0x6e, 0xcc, 0x03, 0xff, 0xc8, 0xf4, 0xa8, 0xa1,
-       0xe7, 0x77, 0xd1, 0x7f, 0x7e, 0xa9, 0x72, 0x3d, 0xb2, 0x66, 0xbb, 0x92,
-       0x9f, 0x18, 0x99, 0x1e, 0x31, 0x3c, 0x7c, 0xc7, 0xbc, 0x7d, 0x77, 0x7a,
-       0xf8, 0x46, 0xa6, 0xd3, 0x86, 0x87, 0x6f, 0xb5, 0xa2, 0xf7, 0x4a, 0xa1,
-       0x42, 0xd8, 0x91, 0x69, 0xcb, 0xb8, 0x53, 0x66, 0xfb, 0x46, 0xa6, 0x07,
-       0x0d, 0xf5, 0xa9, 0x6d, 0x1e, 0x1f, 0xa9, 0x80, 0x86, 0x6d, 0x9a, 0x06,
-       0x9e, 0xab, 0xe7, 0x87, 0x1d, 0xab, 0x7c, 0xf7, 0x36, 0x7d, 0x3e, 0xcf,
-       0xd4, 0x73, 0x77, 0x93, 0x2e, 0x9e, 0x5d, 0x9c, 0xb8, 0xe5, 0xdc, 0x1f,
-       0xbf, 0x29, 0x9f, 0xad, 0xce, 0xe4, 0x79, 0x12, 0x8b, 0x66, 0xa3, 0x13,
-       0xf3, 0x95, 0xc3, 0xe2, 0x54, 0x93, 0x32, 0x37, 0xde, 0x29, 0xb3, 0xe6,
-       0xd0, 0xec, 0x3e, 0x61, 0xac, 0x89, 0x4d, 0x14, 0x7d, 0x1d, 0xe6, 0xc5,
-       0x90, 0x39, 0xf0, 0xb8, 0xaf, 0x21, 0x31, 0x03, 0xf0, 0x43, 0x8d, 0xa8,
-       0x3c, 0xdb, 0x34, 0xa4, 0x5d, 0xfb, 0x67, 0xca, 0xdc, 0x80, 0x1d, 0x3e,
-       0x5d, 0xa5, 0x1d, 0xd3, 0x66, 0x25, 0x57, 0x87, 0x9d, 0x9e, 0xd7, 0xbe,
-       0xda, 0x45, 0xbd, 0x96, 0x4a, 0x02, 0x57, 0xcc, 0x5a, 0x66, 0x5d, 0x3a,
-       0x24, 0x37, 0x23, 0x25, 0xae, 0xfb, 0xbe, 0x93, 0x58, 0x91, 0x73, 0xb0,
-       0x01, 0x31, 0x9d, 0x0c, 0xe7, 0x09, 0xdf, 0x02, 0x6b, 0x7a, 0x7e, 0x17,
-       0x81, 0xdf, 0x15, 0x33, 0x84, 0x95, 0x92, 0x93, 0xa1, 0xef, 0xc1, 0x16,
-       0x9b, 0xbb, 0x7a, 0xbc, 0xd8, 0x86, 0xd8, 0x12, 0xef, 0x86, 0x8f, 0x7f,
-       0x0a, 0xfe, 0x37, 0x60, 0x38, 0xa7, 0x5c, 0xb7, 0x68, 0x4b, 0x5c, 0x09,
-       0xfd, 0x0f, 0xbe, 0xde, 0xe4, 0x5a, 0x37, 0xe6, 0xc5, 0x9c, 0xb3, 0xfb,
-       0xc0, 0x9f, 0xeb, 0x4e, 0xdb, 0x49, 0x29, 0xdb, 0xdb, 0xb1, 0xaf, 0x4d,
-       0xfa, 0x2c, 0xda, 0x3b, 0x7d, 0x7a, 0x1b, 0xce, 0x33, 0xf8, 0xdd, 0x8b,
-       0xf3, 0x7a, 0x30, 0x97, 0x98, 0xa3, 0x1f, 0x67, 0xc6, 0xc0, 0xbf, 0x17,
-       0x2f, 0x45, 0xde, 0x06, 0xad, 0xdc, 0xa3, 0xe1, 0x62, 0x1d, 0xd9, 0x8c,
-       0x5c, 0xab, 0xec, 0x92, 0x4b, 0x71, 0xf2, 0x0f, 0x9c, 0x55, 0xc4, 0xc4,
-       0xb8, 0x01, 0xfa, 0x13, 0x7e, 0xdc, 0xdb, 0xe1, 0x7f, 0x1b, 0x77, 0x79,
-       0x67, 0x88, 0x19, 0xc9, 0xf6, 0x4a, 0x5e, 0xcf, 0x89, 0x52, 0x13, 0xdb,
-       0xfc, 0xf5, 0x5e, 0x63, 0xef, 0x29, 0x25, 0xa3, 0xf7, 0x21, 0x66, 0xe1,
-       0xac, 0x8b, 0x96, 0xeb, 0x5e, 0xb4, 0xbf, 0x0f, 0x9f, 0x57, 0xd2, 0x66,
-       0xfd, 0x63, 0xaf, 0x74, 0x41, 0x9e, 0x55, 0xa3, 0x45, 0x86, 0x09, 0x39,
-       0x56, 0xe5, 0x9e, 0x92, 0x44, 0x2d, 0xc2, 0x10, 0xfe, 0xef, 0x01, 0x17,
-       0x91, 0x0e, 0xf8, 0xe2, 0x05, 0x3b, 0x4e, 0x7a, 0xb7, 0x7b, 0xf0, 0x7d,
-       0x38, 0x83, 0xb4, 0xd3, 0xf7, 0x5c, 0xed, 0x7b, 0x4e, 0x44, 0xe5, 0xa6,
-       0x96, 0xe0, 0x49, 0xe3, 0x94, 0xb7, 0xd3, 0x87, 0x50, 0x2f, 0x73, 0xa3,
-       0x25, 0x53, 0x69, 0x5d, 0x8b, 0xe4, 0x2b, 0x77, 0xc9, 0xbc, 0x8d, 0xf3,
-       0xac, 0x28, 0x68, 0x66, 0x9c, 0x19, 0x2e, 0x45, 0x14, 0x3c, 0xac, 0x9f,
-       0xb2, 0x0a, 0x68, 0x7d, 0x0b, 0xe7, 0x95, 0x8c, 0xa8, 0xc5, 0x33, 0xbe,
-       0xe4, 0xcb, 0x87, 0x76, 0x67, 0x8b, 0x53, 0xe9, 0xe6, 0x37, 0xe8, 0xe8,
-       0xd2, 0x74, 0x44, 0xb2, 0x5a, 0x77, 0x86, 0xca, 0x52, 0x96, 0x6d, 0x3e,
-       0x3d, 0xb7, 0xe0, 0x01, 0x1f, 0xdc, 0x6b, 0x61, 0x6f, 0x0c, 0x34, 0xf6,
-       0xb4, 0xd0, 0xdf, 0x45, 0x78, 0xc8, 0x2a, 0xe6, 0x9f, 0xa1, 0xf9, 0x36,
-       0x3c, 0xbe, 0x03, 0x59, 0x7d, 0x1b, 0xb2, 0xfa, 0xc0, 0x1d, 0xdd, 0x4d,
-       0x1c, 0x19, 0xe0, 0x60, 0x1e, 0x62, 0xbc, 0x62, 0x8c, 0x32, 0x6f, 0xe0,
-       0x82, 0x1f, 0xa8, 0x48, 0xb6, 0x5b, 0xf2, 0xa6, 0xce, 0x01, 0x80, 0x9d,
-       0x14, 0x1d, 0xe3, 0x2d, 0xf2, 0xe8, 0x7f, 0x5b, 0x29, 0x6d, 0x37, 0x85,
-       0x1a, 0xf3, 0xc0, 0x57, 0x40, 0xdb, 0x46, 0x4a, 0x69, 0xd6, 0xba, 0x21,
-       0x73, 0x89, 0xb5, 0x65, 0xdf, 0x90, 0xb5, 0x8a, 0xda, 0xd9, 0x2e, 0xdb,
-       0x65, 0x06, 0x32, 0xaa, 0x4f, 0x22, 0x7f, 0x8e, 0x77, 0x4b, 0xe4, 0x1e,
-       0xe6, 0x81, 0x04, 0x68, 0xdd, 0x48, 0x99, 0x72, 0xdd, 0x55, 0x23, 0xd8,
-       0x3f, 0x0e, 0x3d, 0xec, 0xa7, 0x4e, 0x95, 0x0f, 0x47, 0x98, 0x08, 0x65,
-       0xde, 0xdf, 0x2e, 0xc4, 0xcd, 0xb5, 0xb1, 0x84, 0x29, 0x9c, 0xef, 0x84,
-       0x5e, 0xb9, 0x97, 0xfc, 0x79, 0x7b, 0x3e, 0xce, 0x5f, 0xb0, 0x4e, 0x99,
-       0x51, 0x76, 0xb0, 0x31, 0xf0, 0xe8, 0xd8, 0x3f, 0xeb, 0xcb, 0xe6, 0x76,
-       0xb9, 0x64, 0x8a, 0x51, 0xb7, 0x6f, 0x6b, 0x91, 0x1f, 0x79, 0xee, 0xdb,
-       0xc4, 0x33, 0x71, 0x6c, 0xcd, 0xf7, 0xc1, 0x1a, 0xcf, 0xf4, 0xce, 0x9e,
-       0xb7, 0x36, 0x52, 0x51, 0xb9, 0x55, 0xbe, 0xd0, 0xa5, 0x14, 0x2b, 0xb4,
-       0x8d, 0x76, 0x29, 0xa0, 0xfe, 0xb0, 0x77, 0x23, 0xa8, 0x3c, 0xa2, 0x64,
-       0xe2, 0x3e, 0xe2, 0xfc, 0x3b, 0xf2, 0x34, 0x99, 0x54, 0x86, 0x14, 0xec,
-       0xce, 0x16, 0x7d, 0x71, 0xae, 0xd5, 0xb6, 0xbf, 0xed, 0xdb, 0xf6, 0x07,
-       0xee, 0xc4, 0xee, 0x40, 0xef, 0x90, 0xd7, 0xc7, 0xf6, 0x08, 0xf4, 0xfc,
-       0x7f, 0xed, 0xa1, 0xad, 0xc4, 0x36, 0xed, 0x29, 0x6d, 0xb1, 0x67, 0x87,
-       0xc8, 0x17, 0xe8, 0x43, 0x3d, 0x7e, 0xcc, 0x08, 0x7c, 0x2a, 0xc0, 0x03,
-       0xdd, 0x68, 0x5b, 0xe5, 0xdc, 0x56, 0xbe, 0x48, 0x1c, 0xc4, 0xc5, 0xbd,
-       0x84, 0x09, 0x72, 0x2a, 0xd4, 0x21, 0x5b, 0xe6, 0x55, 0x8c, 0x69, 0xbc,
-       0x2b, 0xc4, 0xa1, 0xd6, 0xfc, 0xca, 0x39, 0x13, 0xdf, 0x53, 0x78, 0x5a,
-       0x52, 0x68, 0xd0, 0x9f, 0xb8, 0x9f, 0xf9, 0xf6, 0x5d, 0x3f, 0x7e, 0x76,
-       0xcf, 0x46, 0xb3, 0x71, 0xc4, 0x4f, 0x99, 0x29, 0x57, 0x8e, 0xba, 0x11,
-       0x4b, 0x4a, 0x77, 0x64, 0x69, 0x1f, 0xdd, 0x93, 0x88, 0x91, 0x33, 0xe5,
-       0x06, 0xeb, 0x22, 0x84, 0x31, 0xec, 0x43, 0x8e, 0x8e, 0xa9, 0xc5, 0x58,
-       0xe9, 0xc7, 0xb2, 0x8c, 0xcb, 0x49, 0x49, 0x36, 0xde, 0x43, 0xdd, 0x61,
-       0x8a, 0xa3, 0x6d, 0xed, 0xf9, 0x5d, 0xa4, 0xb7, 0x8c, 0x1a, 0x22, 0x9a,
-       0x95, 0xa8, 0xca, 0xb6, 0xc7, 0xe6, 0x32, 0xdd, 0xe2, 0x64, 0xa6, 0x77,
-       0xa9, 0xf5, 0x7d, 0xbb, 0x22, 0xeb, 0x3b, 0x67, 0xdb, 0xb2, 0xa5, 0x5d,
-       0x6a, 0x51, 0x64, 0xa5, 0x22, 0x0a, 0x75, 0x4d, 0xe2, 0xa0, 0xe0, 0x7b,
-       0xfd, 0xd1, 0x47, 0x55, 0x36, 0x02, 0xdd, 0xca, 0x53, 0xab, 0x99, 0x28,
-       0x6b, 0xc6, 0xe4, 0x8c, 0x3c, 0x85, 0x3a, 0xf1, 0x49, 0x99, 0xab, 0x80,
-       0x2e, 0xcd, 0x77, 0x02, 0xfc, 0x0e, 0x00, 0x37, 0x69, 0x8f, 0x23, 0xc6,
-       0x7a, 0xb4, 0x83, 0xe6, 0x5c, 0x9e, 0x75, 0x52, 0x86, 0x79, 0xe5, 0x3d,
-       0xd8, 0x0f, 0xfd, 0xe5, 0x5f, 0x64, 0xcd, 0xea, 0x94, 0x82, 0x17, 0x1f,
-       0x68, 0xaf, 0x58, 0x7b, 0xd7, 0x5f, 0xbb, 0x8a, 0x35, 0xda, 0xef, 0xb6,
-       0x16, 0x1d, 0x7e, 0x55, 0xd7, 0x3a, 0x17, 0x6d, 0xbe, 0x13, 0xf6, 0x2f,
-       0x27, 0x3c, 0xd8, 0xd7, 0x27, 0xd6, 0xac, 0x47, 0xb7, 0x4b, 0x97, 0x49,
-       0xbd, 0xe1, 0x9c, 0x38, 0x63, 0x2c, 0xd6, 0x2f, 0xf9, 0xb8, 0xbe, 0x0b,
-       0x5c, 0xdd, 0xa4, 0x1b, 0x23, 0x8a, 0x75, 0xd0, 0x87, 0x9a, 0xa7, 0x70,
-       0x23, 0xd6, 0x10, 0xf6, 0x65, 0x1f, 0xd7, 0xb7, 0x5a, 0x70, 0x71, 0x8d,
-       0x4f, 0x9e, 0x89, 0xb3, 0xbb, 0xc8, 0x1b, 0xf9, 0xa1, 0x0e, 0xa8, 0x8f,
-       0xb4, 0x31, 0x83, 0xd8, 0x3e, 0xd3, 0xd4, 0xb5, 0x9d, 0x91, 0xaf, 0xa2,
-       0xe6, 0x6a, 0x3e, 0x0f, 0x1a, 0x59, 0xc3, 0x0e, 0xfa, 0xf5, 0x35, 0xed,
-       0x68, 0x43, 0xdb, 0x23, 0xe3, 0x4e, 0x59, 0xdb, 0xd5, 0x6b, 0x9e, 0x5d,
-       0x59, 0xd4, 0xcd, 0x6b, 0x32, 0xd8, 0xa8, 0x6c, 0xf7, 0xfe, 0xaf, 0xb6,
-       0x29, 0x11, 0xad, 0x4f, 0xe6, 0x37, 0xda, 0xd8, 0xed, 0x88, 0xeb, 0xee,
-       0x0f, 0x99, 0x67, 0x66, 0x98, 0x83, 0x66, 0x98, 0x3b, 0x0c, 0x3f, 0x1e,
-       0x26, 0x5b, 0x70, 0x24, 0x81, 0xa3, 0xee, 0xdb, 0xef, 0x73, 0x3e, 0xae,
-       0xa0, 0xfe, 0x0c, 0x62, 0xea, 0xef, 0xdf, 0x71, 0xeb, 0xfa, 0x47, 0x3e,
-       0x7d, 0xed, 0x3a, 0x1e, 0xc3, 0xd6, 0x41, 0x7f, 0x72, 0x56, 0xc1, 0xbe,
-       0xf2, 0x0d, 0x4f, 0x1f, 0xf0, 0x7d, 0xd8, 0x1e, 0x5f, 0x03, 0xdd, 0x7a,
-       0xf5, 0xb7, 0x27, 0x03, 0xea, 0x34, 0x47, 0xbe, 0x73, 0x51, 0xd2, 0xd2,
-       0x9c, 0xc6, 0x7e, 0x39, 0xcc, 0xdc, 0x58, 0x00, 0x1f, 0x07, 0xcd, 0x31,
-       0x73, 0x8e, 0xb8, 0xe3, 0x02, 0x9c, 0xa8, 0x25, 0xb3, 0x1d, 0xbe, 0x9e,
-       0xbf, 0xc9, 0xf3, 0x81, 0x7b, 0x1b, 0xbf, 0xf1, 0xfc, 0xa6, 0x4f, 0xcf,
-       0x95, 0x5e, 0x8f, 0x9e, 0x60, 0x7d, 0xd0, 0xbc, 0xf5, 0xbb, 0xbe, 0xcb,
-       0x97, 0x27, 0xde, 0x9f, 0xf4, 0xe9, 0xa2, 0x6e, 0x5a, 0x69, 0xa2, 0x5e,
-       0xfe, 0x1d, 0x78, 0x74, 0xad, 0x51, 0x52, 0x59, 0xd4, 0x2e, 0x19, 0xe6,
-       0xac, 0xd4, 0x64, 0x4e, 0x2c, 0xe8, 0x24, 0x65, 0xcf, 0x62, 0xd7, 0xbb,
-       0x15, 0xea, 0xf9, 0x3a, 0x62, 0x35, 0xf5, 0xfe, 0xbe, 0xcc, 0x57, 0x86,
-       0xec, 0x76, 0x83, 0xfe, 0x9a, 0x4a, 0x9f, 0x96, 0x31, 0xfb, 0xb4, 0xae,
-       0xa1, 0x52, 0xc9, 0x63, 0x42, 0xd9, 0x5e, 0x97, 0x61, 0x5d, 0xdb, 0xbc,
-       0x2f, 0x16, 0xe4, 0x32, 0x53, 0x85, 0x8f, 0xed, 0xfe, 0x57, 0x57, 0xd7,
-       0xa4, 0x08, 0x6f, 0xef, 0x6c, 0x81, 0xeb, 0x75, 0x8d, 0x87, 0xf8, 0x5a,
-       0x71, 0x19, 0xd2, 0xb1, 0x3b, 0xc0, 0x67, 0xc9, 0x42, 0x33, 0xc0, 0x19,
-       0x45, 0x5c, 0x46, 0x0c, 0xd8, 0xfd, 0x05, 0x5f, 0x1f, 0x7c, 0x7f, 0xd3,
-       0x65, 0x2d, 0xa4, 0xb2, 0xa7, 0xfc, 0xb9, 0x3f, 0xa3, 0x0c, 0xf0, 0x1d,
-       0xc8, 0xfd, 0x79, 0x3f, 0xde, 0x94, 0x8c, 0x5c, 0x93, 0x32, 0xa0, 0xad,
-       0x40, 0xff, 0xda, 0x3e, 0xe1, 0x33, 0xd5, 0xcf, 0x22, 0x66, 0xf5, 0x79,
-       0xf5, 0x03, 0x7a, 0xb0, 0x5c, 0x93, 0x73, 0x1b, 0x1d, 0x8e, 0xdd, 0xe6,
-       0xfb, 0xd2, 0x3e, 0xcc, 0xcd, 0xe0, 0x8f, 0xb2, 0x23, 0xcc, 0x7e, 0xbc,
-       0xe7, 0x7c, 0x38, 0x99, 0x74, 0x90, 0xbb, 0x72, 0xfb, 0xa7, 0xf0, 0x6d,
-       0xf8, 0x7d, 0x96, 0x96, 0x7b, 0x0d, 0xb5, 0x0a, 0xe4, 0x39, 0x0c, 0x7e,
-       0x92, 0x32, 0xd5, 0x84, 0xce, 0x6f, 0xc4, 0xb3, 0x1b, 0x30, 0xa5, 0x9b,
-       0x30, 0x5e, 0xec, 0x9b, 0x6a, 0xbe, 0xe5, 0x32, 0x1e, 0xfc, 0x89, 0xf6,
-       0x97, 0x24, 0x68, 0x0f, 0x7a, 0xb5, 0x9c, 0xf1, 0x70, 0x75, 0xda, 0x78,
-       0xa4, 0xca, 0x3d, 0xea, 0x6b, 0xfd, 0x62, 0x25, 0x1d, 0x85, 0x3a, 0x75,
-       0x77, 0x2f, 0xce, 0x3c, 0x06, 0xdb, 0x28, 0x19, 0x33, 0xa3, 0xdb, 0xa5,
-       0x90, 0xee, 0x07, 0xcd, 0xf7, 0xe3, 0xd9, 0x8e, 0xf9, 0x9f, 0xc2, 0x3c,
-       0xec, 0x28, 0x4d, 0xff, 0xe8, 0xd4, 0xbd, 0xe4, 0xac, 0x49, 0x1a, 0x87,
-       0x7d, 0xdb, 0xfa, 0x8e, 0xe9, 0xd9, 0xd2, 0x13, 0xf8, 0xde, 0x86, 0xf9,
-       0x5f, 0xc0, 0x13, 0xb9, 0x6c, 0x77, 0x30, 0x4f, 0x1f, 0x9c, 0xc4, 0xfc,
-       0xbd, 0xc0, 0xf1, 0xdb, 0x78, 0xbf, 0x0b, 0xef, 0xbf, 0xb5, 0x69, 0xef,
-       0x6f, 0xf2, 0x6c, 0xcc, 0x3b, 0x9b, 0xe6, 0x83, 0xf8, 0xcd, 0xf3, 0x44,
-       0xfa, 0xd6, 0xc1, 0xf8, 0x7a, 0x4c, 0x76, 0x9c, 0xee, 0x12, 0x55, 0xf7,
-       0x62, 0xb8, 0xaa, 0x9b, 0xd2, 0x7f, 0x9a, 0xf1, 0xfb, 0xaf, 0xb0, 0xc7,
-       0x12, 0xb5, 0x0e, 0xa5, 0x51, 0xb7, 0xda, 0x47, 0x0f, 0x1c, 0x19, 0x5c,
-       0xe6, 0x73, 0xf6, 0xc8, 0x44, 0x83, 0x30, 0x7c, 0x7f, 0xec, 0xc8, 0x60,
-       0xe3, 0x6f, 0x01, 0x0b, 0xb9, 0x54, 0x03, 0xfc, 0x84, 0xff, 0xd3, 0x4d,
-       0x67, 0x6a, 0xd9, 0xe2, 0x4c, 0xfa, 0xfd, 0x81, 0x23, 0x4e, 0x8d, 0x75,
-       0x42, 0x2a, 0x21, 0xba, 0x16, 0x9f, 0x3d, 0x52, 0x44, 0x7e, 0x8c, 0x68,
-       0x5a, 0x82, 0x75, 0xae, 0x51, 0x0f, 0x5b, 0xd1, 0x46, 0xba, 0x5a, 0xf1,
-       0x30, 0xcf, 0x10, 0xcf, 0x63, 0xc0, 0x93, 0x06, 0x1e, 0xe6, 0x1b, 0x8f,
-       0xde, 0xe4, 0xf2, 0x56, 0xb4, 0x11, 0x17, 0xcf, 0x0a, 0xf0, 0xf5, 0x8b,
-       0x3a, 0xfd, 0x26, 0xe9, 0x35, 0x59, 0xdb, 0x7a, 0xb1, 0xa6, 0x4d, 0x0a,
-       0x27, 0x99, 0xb3, 0x77, 0xfb, 0xdf, 0x71, 0x93, 0x3d, 0x77, 0x52, 0x71,
-       0x9e, 0x4f, 0xac, 0x65, 0xee, 0xc4, 0x1c, 0xbe, 0x57, 0x02, 0x58, 0xe5,
-       0xc3, 0xf6, 0xb4, 0xf0, 0xdd, 0xe6, 0xcb, 0x9a, 0x67, 0x06, 0xbd, 0x67,
-       0x2b, 0x2d, 0x00, 0x85, 0x1e, 0xfa, 0x6e, 0xe8, 0x21, 0xe0, 0x13, 0x0b,
-       0xeb, 0xa4, 0x2d, 0x0d, 0x5e, 0x03, 0xda, 0x3e, 0xa9, 0xfe, 0xb8, 0x37,
-       0x8d, 0xbf, 0xe0, 0xbc, 0x40, 0x06, 0xa4, 0x8b, 0x4f, 0xd8, 0xf2, 0xc7,
-       0x7a, 0xe7, 0x34, 0xfc, 0x8e, 0xf7, 0x1e, 0xae, 0xbb, 0x66, 0x53, 0xf6,
-       0x1d, 0xd0, 0x3b, 0x79, 0x31, 0xd0, 0x4b, 0x28, 0xd6, 0x74, 0x49, 0xf6,
-       0xac, 0x87, 0xe4, 0x6d, 0xe0, 0xca, 0xa1, 0xaf, 0xf4, 0x7a, 0xa3, 0x59,
-       0xc4, 0xc7, 0x0d, 0xd8, 0xe7, 0x45, 0x8b, 0xf7, 0x2f, 0x51, 0xe6, 0x3b,
-       0x29, 0x37, 0xfe, 0x19, 0x30, 0xac, 0xaf, 0x6e, 0xde, 0xad, 0x2c, 0x03,
-       0x66, 0x05, 0x6b, 0xc7, 0xbc, 0xb8, 0xcc, 0xd8, 0xee, 0x2a, 0xd4, 0x1e,
-       0x45, 0xeb, 0xbf, 0x5d, 0xd6, 0x59, 0x37, 0x61, 0xb7, 0xba, 0x0b, 0x41,
-       0xce, 0x59, 0x4a, 0x2d, 0x2c, 0x23, 0x86, 0xd7, 0x2c, 0xb5, 0x43, 0x69,
-       0x8b, 0x4c, 0xd5, 0x10, 0x93, 0xd0, 0xf5, 0xa6, 0x92, 0xcb, 0xf2, 0x03,
-       0xad, 0x87, 0x36, 0x6b, 0xcc, 0xec, 0x57, 0x5f, 0xa4, 0x5d, 0x69, 0xca,
-       0x23, 0x27, 0x90, 0x97, 0xc7, 0x1f, 0x46, 0xce, 0x81, 0xbc, 0x4e, 0x94,
-       0xd0, 0xc9, 0xd3, 0x46, 0x36, 0x7e, 0xbd, 0x68, 0x79, 0x7d, 0x80, 0xce,
-       0x67, 0xe2, 0xf1, 0x18, 0x39, 0xd1, 0xad, 0xe3, 0x4c, 0x41, 0xc7, 0x9b,
-       0x21, 0x73, 0x46, 0x75, 0xa1, 0xc6, 0x40, 0x01, 0x8a, 0x0a, 0xc7, 0x1c,
-       0x11, 0x19, 0x5c, 0x44, 0x5c, 0x41, 0x1c, 0x1e, 0x5c, 0x47, 0x74, 0x3b,
-       0x41, 0x78, 0x25, 0xd1, 0x13, 0x11, 0x69, 0x3b, 0xc1, 0xfb, 0x10, 0xd9,
-       0x89, 0x7e, 0x8c, 0x38, 0x07, 0xa3, 0x78, 0x4e, 0xe1, 0x6f, 0x0f, 0x6a,
-       0x2b, 0x13, 0x35, 0xf2, 0x16, 0xf0, 0x80, 0xe5, 0x9e, 0xad, 0xe0, 0xbb,
-       0xfb, 0xa4, 0x2b, 0x86, 0x3d, 0x84, 0x8f, 0x82, 0x8e, 0x9d, 0xa0, 0xc7,
-       0x3b, 0x9f, 0x38, 0xa2, 0x27, 0x44, 0x86, 0x16, 0xa5, 0x5f, 0xe9, 0x3d,
-       0x51, 0x29, 0x66, 0xb8, 0xd6, 0x0d, 0x78, 0xee, 0xc3, 0x9a, 0xde, 0xe7,
-       0xdd, 0x2b, 0x15, 0x6e, 0xd2, 0x8d, 0x39, 0x03, 0xef, 0xa8, 0xa7, 0x32,
-       0xa6, 0x0c, 0xd5, 0x3d, 0xd8, 0xc1, 0xf5, 0x43, 0x78, 0x92, 0x57, 0x8f,
-       0x36, 0x85, 0x9a, 0xb8, 0x00, 0xa9, 0x46, 0x47, 0x78, 0x3f, 0x43, 0x18,
-       0xf6, 0xb5, 0xdd, 0x1a, 0xc6, 0x1c, 0xa1, 0xfc, 0xbc, 0x39, 0xa5, 0xfe,
-       0xb7, 0x7b, 0x97, 0xd6, 0x9a, 0x42, 0xfb, 0x0a, 0xf6, 0x7f, 0x45, 0xfb,
-       0x8a, 0xa8, 0xa4, 0xef, 0x2b, 0xf8, 0x5e, 0xe1, 0x77, 0x90, 0x8b, 0x7f,
-       0xed, 0x0e, 0x2f, 0xde, 0xbb, 0x32, 0x67, 0xf3, 0x0e, 0xc3, 0x95, 0x8b,
-       0x76, 0xc9, 0x78, 0xf0, 0x96, 0x3a, 0x33, 0xad, 0xf3, 0x73, 0x11, 0xb2,
-       0xbf, 0xdc, 0xd0, 0x3d, 0x9b, 0x5c, 0x6a, 0xc4, 0xe4, 0xca, 0x6a, 0x97,
-       0x5c, 0x5e, 0xf6, 0x6c, 0xfe, 0xf2, 0x32, 0xed, 0xdc, 0x94, 0xef, 0xad,
-       0x5a, 0x58, 0x4b, 0xe3, 0xaf, 0x5f, 0xde, 0x59, 0xbd, 0xb5, 0xee, 0x3c,
-       0xdf, 0x7c, 0x00, 0xb4, 0xf4, 0x4b, 0xc4, 0x72, 0x75, 0xff, 0x95, 0x47,
-       0xee, 0x2b, 0xc9, 0x94, 0x14, 0xaa, 0x43, 0xe8, 0x01, 0x91, 0x9c, 0xa3,
-       0xcc, 0x41, 0xd0, 0x7f, 0xf5, 0x33, 0xa8, 0x4d, 0x52, 0x70, 0x9e, 0x21,
-       0x7d, 0x8f, 0xf8, 0x33, 0xd1, 0x7e, 0x69, 0xb7, 0xbe, 0xdc, 0xe7, 0xe5,
-       0x2a, 0xd3, 0xeb, 0x53, 0xad, 0x20, 0x5f, 0xbf, 0x0e, 0xdc, 0xe3, 0xb0,
-       0x53, 0xda, 0xa6, 0x0d, 0x9b, 0x35, 0x65, 0x6d, 0x34, 0x55, 0x2b, 0x09,
-       0xe3, 0x43, 0x06, 0x67, 0x7e, 0x08, 0x9e, 0xd3, 0x90, 0x47, 0xa7, 0xae,
-       0x85, 0x72, 0x0a, 0xba, 0x5d, 0x9c, 0x97, 0x42, 0xf3, 0x57, 0x80, 0x2f,
-       0x27, 0xb3, 0xcd, 0x49, 0x9c, 0x75, 0x1c, 0x76, 0x3b, 0xda, 0x2f, 0x5d,
-       0x3c, 0x27, 0x03, 0x1a, 0xef, 0x97, 0xe2, 0xc9, 0x79, 0x39, 0x58, 0x25,
-       0x9d, 0xc8, 0x25, 0x76, 0x2a, 0x9d, 0x97, 0xb1, 0xe4, 0x2a, 0x6a, 0x27,
-       0xcf, 0x1f, 0xb3, 0x52, 0x3c, 0x05, 0x1c, 0x55, 0xde, 0x03, 0x0c, 0xc1,
-       0x6e, 0xc6, 0x74, 0x5f, 0x33, 0xab, 0xe3, 0x0e, 0xe7, 0xdf, 0x84, 0x9e,
-       0x86, 0x4a, 0x7b, 0x00, 0x57, 0x40, 0x0f, 0x34, 0x83, 0x7a, 0x79, 0xa5,
-       0x8a, 0x7e, 0xcf, 0x8e, 0xb0, 0xf6, 0x52, 0xea, 0x9e, 0x01, 0xa9, 0x57,
-       0xc7, 0x4c, 0xa5, 0x58, 0x53, 0x51, 0x17, 0x5c, 0xa3, 0x7f, 0x27, 0x54,
-       0xd4, 0x1a, 0x90, 0xd5, 0x6a, 0x09, 0x7d, 0xb3, 0xf2, 0xef, 0x35, 0x4a,
-       0x62, 0x5a, 0x5e, 0xdc, 0xcb, 0x29, 0xf2, 0x8d, 0xfa, 0xb3, 0xf9, 0x59,
-       0xd0, 0x98, 0x4b, 0x9a, 0x72, 0x14, 0xf4, 0xe1, 0x7d, 0x05, 0x36, 0xbe,
-       0xc8, 0x1a, 0x2e, 0x87, 0xb5, 0xac, 0x1c, 0x3e, 0x33, 0x03, 0x1a, 0x7a,
-       0x65, 0xe8, 0x77, 0xe9, 0x63, 0x07, 0x30, 0xc7, 0xef, 0x14, 0xec, 0xf5,
-       0x31, 0xbc, 0x13, 0x36, 0x81, 0x27, 0xe5, 0x30, 0x80, 0xa7, 0x09, 0x5a,
-       0x62, 0x5e, 0x6f, 0xb2, 0x3f, 0x29, 0xf5, 0x93, 0xf7, 0xc9, 0xec, 0xca,
-       0x7d, 0xc0, 0xff, 0x36, 0xfa, 0x02, 0xe4, 0xb7, 0x15, 0x9e, 0xc5, 0xfa,
-       0x8f, 0xe7, 0x74, 0xf4, 0x6b, 0xdf, 0x58, 0xe4, 0x3c, 0x9f, 0xfb, 0xb0,
-       0x1f, 0x3d, 0x46, 0x35, 0x27, 0xc5, 0x2a, 0xcf, 0x82, 0xee, 0x50, 0x4f,
-       0x15, 0x4e, 0xce, 0xf8, 0x3a, 0xee, 0x97, 0x7c, 0xbc, 0xc4, 0xfe, 0x02,
-       0x79, 0x62, 0x79, 0xc2, 0xa9, 0xa4, 0x4c, 0x47, 0x11, 0x57, 0x5a, 0x98,
-       0x1b, 0xbc, 0xb9, 0x98, 0x58, 0x8b, 0xe8, 0x6d, 0xb3, 0x5c, 0x3b, 0xea,
-       0xdf, 0x1d, 0x10, 0xd7, 0x5b, 0x32, 0x05, 0x1b, 0x1b, 0x5a, 0x1c, 0x47,
-       0x2d, 0xfc, 0x5d, 0xd4, 0x92, 0x77, 0xfa, 0x32, 0x98, 0xf4, 0x6d, 0xa3,
-       0xab, 0xc5, 0x26, 0xa0, 0xe7, 0x2a, 0x74, 0x5f, 0x85, 0x1d, 0x20, 0x56,
-       0xbf, 0x74, 0xc3, 0x3e, 0x26, 0x5b, 0x6a, 0xcc, 0x1e, 0xf9, 0x8b, 0x5a,
-       0x2a, 0xbd, 0x01, 0xfb, 0x79, 0x07, 0xbd, 0xc0, 0x06, 0x7a, 0xd5, 0xcb,
-       0xe8, 0xeb, 0x56, 0x2a, 0xfb, 0x41, 0x3f, 0x6b, 0x4a, 0x7e, 0x27, 0x74,
-       0xad, 0xd3, 0x61, 0x1d, 0xbb, 0x43, 0xdf, 0xed, 0xca, 0xfe, 0x7e, 0xf6,
-       0x9a, 0xec, 0xcb, 0x79, 0x0f, 0x7d, 0x05, 0x7a, 0xdc, 0x30, 0xb9, 0x1e,
-       0xec, 0x63, 0x2f, 0x10, 0xd8, 0x0f, 0x69, 0xa1, 0xfd, 0x70, 0x0f, 0x61,
-       0xfa, 0xb5, 0x9f, 0x14, 0x34, 0x3e, 0xda, 0xec, 0x8b, 0x7d, 0x9e, 0x9f,
-       0xe9, 0x3a, 0xcb, 0xbc, 0x24, 0x81, 0xfd, 0xbe, 0xef, 0xb2, 0xaf, 0x73,
-       0x46, 0x11, 0xbb, 0x9b, 0xae, 0x3c, 0x67, 0xdf, 0xea, 0x77, 0x7b, 0xab,
-       0x81, 0x9c, 0x28, 0xc7, 0xfd, 0x72, 0xac, 0x99, 0x82, 0x4f, 0x50, 0x86,
-       0x56, 0x8b, 0x0c, 0x45, 0xfe, 0xa8, 0x2a, 0xf2, 0x62, 0x95, 0x6b, 0x5a,
-       0x86, 0x09, 0x27, 0xd2, 0xa5, 0xef, 0xd2, 0x0b, 0xf2, 0x1d, 0x39, 0xb8,
-       0x24, 0x72, 0x06, 0xeb, 0x6b, 0x55, 0xfa, 0xea, 0x38, 0xea, 0xd7, 0x6d,
-       0x52, 0x5f, 0x46, 0x4f, 0x56, 0x95, 0x59, 0xe7, 0x5e, 0xe6, 0x9b, 0x98,
-       0x5c, 0xd6, 0x77, 0xb2, 0x22, 0x23, 0x67, 0xa3, 0x12, 0x3d, 0x8b, 0xe6,
-       0x0f, 0xb2, 0x3f, 0x37, 0x1a, 0xdc, 0xd1, 0x7a, 0x3e, 0x5f, 0xae, 0x60,
-       0x6f, 0x75, 0x48, 0xc7, 0xc9, 0x72, 0xa3, 0x28, 0x85, 0x1a, 0xcf, 0xc2,
-       0x73, 0x39, 0x89, 0xb5, 0x8c, 0xcc, 0x9d, 0x1c, 0x97, 0xa7, 0x71, 0x06,
-       0xfa, 0x3f, 0x9c, 0x31, 0x25, 0xa5, 0x33, 0x98, 0x6f, 0x5c, 0x95, 0xe5,
-       0xd5, 0xa2, 0xd4, 0x6b, 0xe7, 0x5d, 0xaf, 0x8f, 0x20, 0x3e, 0x7c, 0x2f,
-       0xb7, 0xf6, 0xb2, 0xfb, 0xd9, 0xcf, 0xa0, 0x57, 0xb5, 0xf0, 0x0d, 0x99,
-       0x35, 0xe6, 0x66, 0x6f, 0xbd, 0x33, 0x6e, 0xed, 0x61, 0xa7, 0x65, 0xa1,
-       0x9a, 0x91, 0xf2, 0xc9, 0x71, 0x7d, 0xd7, 0xd0, 0x91, 0x3d, 0xfc, 0xc4,
-       0x35, 0xe4, 0x8a, 0x69, 0x7d, 0x67, 0x7c, 0x5d, 0x1e, 0xb2, 0x17, 0xe4,
-       0x90, 0xb5, 0x4f, 0x8e, 0xa1, 0xbe, 0xfe, 0x1c, 0x7a, 0xfd, 0x64, 0x1f,
-       0xf5, 0x08, 0x7a, 0x2d, 0xf6, 0xa0, 0xae, 0x4c, 0xd9, 0x9f, 0x36, 0x9f,
-       0x65, 0x97, 0xd0, 0x60, 0x9e, 0xfc, 0x2f, 0x37, 0x87, 0xbc, 0x77, 0x0d,
-       0xbd, 0x63, 0x4e, 0xc3, 0x19, 0x1e, 0x5c, 0x8d, 0x70, 0x63, 0xe6, 0x73,
-       0x84, 0x5b, 0x36, 0x7c, 0x38, 0x03, 0x70, 0x11, 0xb9, 0x60, 0x47, 0x61,
-       0x23, 0xd3, 0xe0, 0x13, 0x31, 0x7e, 0xa2, 0xc7, 0xaf, 0x83, 0x3b, 0x91,
-       0x5b, 0x6f, 0xee, 0x7f, 0xd5, 0xdf, 0xff, 0xb4, 0xbf, 0xff, 0xe2, 0x8d,
-       0xfd, 0x41, 0x7e, 0xfd, 0xd0, 0x95, 0x16, 0xba, 0x5e, 0xad, 0x78, 0xf0,
-       0x0b, 0x3e, 0x5d, 0x17, 0x6f, 0xd0, 0x15, 0xc0, 0x43, 0x9e, 0x9a, 0x67,
-       0xc6, 0x66, 0xc6, 0xe8, 0x21, 0xc8, 0xd1, 0x95, 0xbc, 0x0d, 0xdf, 0xa8,
-       0xa6, 0x26, 0x4b, 0xfa, 0x4e, 0x4d, 0xc9, 0x46, 0x7c, 0x41, 0xa6, 0xad,
-       0xd4, 0xe4, 0x9c, 0x44, 0x60, 0xcb, 0x8c, 0x2d, 0x11, 0xa9, 0x33, 0xe6,
-       0xe0, 0x59, 0xb0, 0xb7, 0xa6, 0xf5, 0x4a, 0x0b, 0xad, 0x91, 0x17, 0x48,
-       0xa3, 0x47, 0x6b, 0x6c, 0xf8, 0x26, 0xad, 0x1e, 0xbc, 0x47, 0xeb, 0x95,
-       0x4a, 0x0b, 0xfc, 0xd9, 0xa8, 0x0f, 0x1f, 0x6d, 0x81, 0xa7, 0x3d, 0xb3,
-       0xae, 0xa0, 0x3d, 0x93, 0xb6, 0x9f, 0x80, 0x6f, 0x48, 0xac, 0x33, 0x7b,
-       0xf8, 0xc8, 0xdd, 0xc3, 0xae, 0xc4, 0x50, 0x6f, 0xb4, 0x63, 0xed, 0x72,
-       0x8d, 0xb5, 0x88, 0x1a, 0x6c, 0x97, 0x11, 0xd8, 0x2c, 0x75, 0xe7, 0xdd,
-       0x0d, 0x3e, 0xa4, 0x6b, 0x02, 0x57, 0x0e, 0xd9, 0xa4, 0xe5, 0x3f, 0xdd,
-       0x17, 0xe3, 0x23, 0x76, 0x59, 0x46, 0xcd, 0x76, 0x9c, 0x5f, 0x6f, 0x6a,
-       0x9c, 0x69, 0xd2, 0x72, 0x7a, 0x74, 0xc8, 0xfc, 0x73, 0xf0, 0x39, 0x55,
-       0x33, 0xa4, 0x6e, 0xa5, 0x12, 0xe7, 0x80, 0x63, 0x0f, 0x74, 0x53, 0x1f,
-       0x27, 0x3d, 0x22, 0x07, 0x61, 0xdf, 0x75, 0x9d, 0x17, 0x69, 0xc7, 0xa9,
-       0xe9, 0x12, 0x6a, 0x9d, 0x3f, 0xd6, 0xb9, 0xcd, 0x75, 0xaf, 0x21, 0xbf,
-       0x4d, 0x6f, 0xb2, 0x3d, 0x75, 0xd6, 0xb3, 0x3d, 0x75, 0x16, 0x3d, 0xf0,
-       0xf1, 0x98, 0x74, 0xac, 0xc1, 0x7f, 0x5e, 0xd8, 0xe9, 0xd5, 0x73, 0x2f,
-       0x24, 0x8d, 0xfc, 0x49, 0xc4, 0xbb, 0xe3, 0x51, 0xb1, 0x8e, 0xeb, 0x7c,
-       0x00, 0x79, 0x4f, 0xc9, 0xdc, 0x29, 0xc6, 0x54, 0x4b, 0x86, 0x8f, 0x53,
-       0x1f, 0xac, 0x6b, 0x96, 0x27, 0x8a, 0xf0, 0x91, 0x79, 0xc4, 0x05, 0xb5,
-       0xf6, 0xae, 0x14, 0x2d, 0xca, 0xa1, 0x57, 0xba, 0xd6, 0xd0, 0x8f, 0xaf,
-       0x21, 0x36, 0xac, 0x25, 0xa4, 0x0d, 0xbe, 0xa5, 0xce, 0xc6, 0x8d, 0xf2,
-       0xd2, 0x0f, 0xe1, 0x0f, 0xfc, 0x0d, 0x07, 0xb5, 0xe5, 0xd9, 0x84, 0x41,
-       0xdf, 0x52, 0x67, 0x69, 0xe7, 0x28, 0xa7, 0xce, 0xd2, 0xce, 0x49, 0x47,
-       0xe0, 0x2f, 0x78, 0x3f, 0x3b, 0xae, 0xef, 0xa9, 0xaf, 0xd9, 0xe4, 0xe5,
-       0x6f, 0xc4, 0xa9, 0xb1, 0x46, 0x24, 0x3f, 0xd2, 0x87, 0x5a, 0x66, 0xbb,
-       0x63, 0x0f, 0x4f, 0x5e, 0x96, 0x4f, 0xca, 0xd7, 0xed, 0x9f, 0x80, 0x2f,
-       0xf2, 0xd1, 0xca, 0x17, 0x79, 0xea, 0x95, 0x36, 0xcd, 0x57, 0xc0, 0x0f,
-       0x04, 0x0d, 0x7e, 0x06, 0x8f, 0x27, 0x80, 0xff, 0x31, 0xc4, 0x80, 0x01,
-       0x3c, 0x0f, 0xe0, 0x89, 0x94, 0x76, 0x96, 0xbc, 0x93, 0xd7, 0x77, 0x50,
-       0x37, 0x06, 0x7c, 0xce, 0xe2, 0xfd, 0x15, 0x99, 0x5b, 0x72, 0x8f, 0x22,
-       0xaf, 0xf2, 0x0e, 0xbd, 0xdf, 0xbb, 0x0f, 0xde, 0xcc, 0xfb, 0x2b, 0xe2,
-       0xc9, 0x27, 0x65, 0xd6, 0x05, 0xef, 0xab, 0x9b, 0x65, 0xd1, 0x1a, 0x3b,
-       0x12, 0xba, 0x0e, 0x3f, 0xd8, 0x60, 0x9c, 0xa0, 0x8c, 0xde, 0x11, 0x67,
-       0x89, 0xf7, 0x5f, 0x1e, 0xbe, 0xd9, 0x46, 0x10, 0x37, 0x5a, 0xf7, 0xd8,
-       0x80, 0x1b, 0x00, 0x1c, 0xe9, 0xda, 0xa0, 0xfc, 0x10, 0x73, 0x76, 0xb5,
-       0xc4, 0x9a, 0xd6, 0x7d, 0x93, 0xf2, 0x0c, 0xea, 0x80, 0x57, 0xed, 0x5b,
-       0xe4, 0x3a, 0xcb, 0x5a, 0xa8, 0xde, 0x98, 0x81, 0x4f, 0xb6, 0x21, 0x96,
-       0x99, 0x72, 0xb9, 0xd2, 0x2e, 0x75, 0xd4, 0x3b, 0x2b, 0xab, 0x8c, 0x85,
-       0xa4, 0xbd, 0x0b, 0xf3, 0x5e, 0xfc, 0x62, 0xac, 0xbd, 0x5c, 0x41, 0x9e,
-       0x85, 0x6f, 0x5f, 0xae, 0xc4, 0xf1, 0x1c, 0xc0, 0xd3, 0xc2, 0x33, 0x89,
-       0x67, 0x1a, 0xcf, 0x71, 0x3c, 0xc7, 0xf1, 0xb4, 0xb0, 0x37, 0x81, 0x67,
-       0xd0, 0x33, 0x10, 0xd7, 0x4d, 0xbe, 0xcb, 0xfa, 0x3c, 0xd4, 0x8a, 0x16,
-       0x73, 0x5a, 0xd4, 0xce, 0xa3, 0x8f, 0x70, 0xc6, 0x75, 0xad, 0x87, 0xfc,
-       0xf6, 0x91, 0x6b, 0x5a, 0xec, 0xcb, 0x4b, 0xc6, 0x9e, 0x51, 0xe6, 0x85,
-       0x1a, 0xf2, 0xc2, 0x7f, 0xec, 0x40, 0xff, 0x68, 0xee, 0xd5, 0x77, 0x47,
-       0x4b, 0xf8, 0xe6, 0x3b, 0x7a, 0xde, 0xf8, 0x3c, 0xf2, 0x14, 0xe3, 0xa7,
-       0x8b, 0x3d, 0x05, 0xc4, 0xf1, 0xed, 0xf0, 0xbf, 0x1c, 0xe2, 0x36, 0xde,
-       0x97, 0x37, 0x76, 0x78, 0x39, 0x15, 0xf5, 0xbb, 0xda, 0x7c, 0x5f, 0x63,
-       0x63, 0xcf, 0x56, 0xbd, 0x41, 0x0f, 0x70, 0xa4, 0x6a, 0xcb, 0xf0, 0xc1,
-       0x37, 0xed, 0xa3, 0xba, 0xb6, 0xa3, 0x2e, 0x9e, 0x46, 0x8d, 0x9a, 0x5f,
-       0x64, 0x0d, 0xf3, 0x14, 0xfa, 0x12, 0xf4, 0x67, 0x71, 0xf6, 0xe4, 0xcc,
-       0x05, 0xba, 0x16, 0x8d, 0x4b, 0x17, 0xf3, 0xc0, 0x15, 0x9c, 0x07, 0xbe,
-       0x56, 0x5c, 0xc8, 0xec, 0x41, 0xd4, 0x84, 0xae, 0x1b, 0xb5, 0xf6, 0x48,
-       0xf2, 0x11, 0xc6, 0x1c, 0xc1, 0x7e, 0x53, 0xbc, 0x7b, 0x75, 0xc4, 0xdd,
-       0x19, 0xfd, 0xfb, 0x30, 0x8c, 0x6b, 0x1c, 0x7b, 0x6f, 0x13, 0xef, 0xb7,
-       0x5c, 0xde, 0x69, 0x8b, 0xec, 0x59, 0xf4, 0x6a, 0x5a, 0x65, 0xb5, 0xe2,
-       0xfb, 0x49, 0x1f, 0x1f, 0xd7, 0x95, 0xff, 0xdb, 0xc6, 0x4e, 0xc8, 0x08,
-       0xfe, 0x00, 0x1d, 0x1f, 0x43, 0xfd, 0x7c, 0x01, 0x7a, 0x79, 0x15, 0x3a,
-       0x79, 0xad, 0x42, 0x5b, 0x1f, 0x83, 0xdd, 0x43, 0x86, 0x33, 0xfa, 0x0c,
-       0x7d, 0xf6, 0x85, 0x0a, 0x62, 0x27, 0xe3, 0x9f, 0xfa, 0x52, 0x9c, 0xf5,
-       0x21, 0xf3, 0xa0, 0x87, 0x67, 0xc0, 0x83, 0x93, 0x60, 0x6d, 0x87, 0xa6,
-       0xa7, 0xae, 0xef, 0xc1, 0x28, 0x27, 0xd8, 0x20, 0x7f, 0x23, 0xd0, 0x30,
-       0x5f, 0x8c, 0xeb, 0x7b, 0x78, 0xc5, 0x39, 0xf2, 0x31, 0x2e, 0xce, 0x62,
-       0xb0, 0xaf, 0x0f, 0xfb, 0x3a, 0x5b, 0x70, 0xdd, 0xbe, 0x89, 0x07, 0xe5,
-       0xf3, 0xc0, 0xf5, 0xcd, 0x75, 0x7f, 0xca, 0x2c, 0xdd, 0xb8, 0x1b, 0x66,
-       0xfe, 0xa5, 0x6e, 0x32, 0xd8, 0x1f, 0xe8, 0x67, 0xc0, 0xef, 0x05, 0x52,
-       0x0b, 0xe8, 0x23, 0x20, 0x7f, 0xea, 0x68, 0x92, 0xf1, 0x09, 0xf8, 0x6d,
-       0xa9, 0x55, 0x3a, 0x44, 0xf5, 0xb3, 0x37, 0x66, 0xad, 0xdc, 0x7a, 0xe6,
-       0x2f, 0xfa, 0x67, 0xa2, 0x9f, 0x3e, 0xc1, 0xba, 0x59, 0xe7, 0x19, 0xc0,
-       0x74, 0x6f, 0xa2, 0xed, 0xe7, 0x7c, 0x38, 0xae, 0xa7, 0xa5, 0x84, 0x3a,
-       0x34, 0xbf, 0x88, 0x8a, 0x1e, 0xf1, 0x5b, 0x65, 0xf9, 0xbb, 0x16, 0xef,
-       0xf0, 0xc6, 0x92, 0x73, 0xa0, 0xb1, 0x64, 0xe6, 0x78, 0x6f, 0x06, 0x1c,
-       0xbb, 0x36, 0xe1, 0x98, 0xf2, 0x71, 0x4c, 0x49, 0xf9, 0xd4, 0x34, 0x7c,
-       0x2d, 0x87, 0xfc, 0x3e, 0x64, 0x3e, 0x28, 0x9f, 0x41, 0x73, 0x8d, 0xb9,
-       0x33, 0xe3, 0xd0, 0x93, 0xeb, 0xee, 0xb1, 0xf7, 0x83, 0xee, 0x97, 0x91,
-       0x5b, 0x83, 0x9a, 0xa7, 0x9c, 0x88, 0x20, 0x87, 0x1d, 0xd6, 0xbf, 0xc3,
-       0x96, 0x4c, 0x13, 0xf6, 0xaa, 0x8c, 0xb1, 0x34, 0xda, 0x7b, 0xe4, 0xb7,
-       0x05, 0xe4, 0x2a, 0xf2, 0xd9, 0x23, 0x65, 0xd3, 0x78, 0x20, 0x82, 0xba,
-       0xc6, 0x59, 0xa4, 0x1f, 0xc9, 0x70, 0x24, 0xdb, 0x8e, 0x9a, 0xd4, 0x95,
-       0xef, 0xd9, 0xfc, 0x77, 0x09, 0x0b, 0x72, 0xa1, 0x61, 0xe2, 0x79, 0x0e,
-       0x7a, 0xf8, 0x3d, 0xbc, 0xff, 0x53, 0x3f, 0xea, 0x3e, 0xac, 0xe4, 0x60,
-       0xbb, 0x69, 0x5d, 0xcf, 0xb0, 0x8e, 0xa8, 0x23, 0xdf, 0x2a, 0xe4, 0x1a,
-       0xd4, 0x55, 0x93, 0xac, 0x5d, 0x9f, 0x59, 0xb9, 0x2a, 0xaf, 0x2d, 0xf1,
-       0x77, 0x50, 0xe6, 0xe5, 0x7d, 0x8c, 0x07, 0xe6, 0x7c, 0x06, 0x73, 0xab,
-       0x8c, 0x65, 0xf8, 0x6e, 0xc2, 0x81, 0xfa, 0x51, 0x23, 0xa0, 0xd6, 0xbe,
-       0x6c, 0xa5, 0xc1, 0xe7, 0x55, 0xb9, 0xb0, 0x14, 0x95, 0x15, 0x8b, 0x75,
-       0x91, 0x24, 0x1d, 0xc0, 0x5e, 0x58, 0xfd, 0x07, 0xcf, 0x26, 0x08, 0x8f,
-       0x9e, 0xa7, 0x84, 0xba, 0xee, 0x41, 0xbd, 0xf7, 0x47, 0xe9, 0x99, 0x34,
-       0xb5, 0xf6, 0x79, 0x45, 0xb9, 0x40, 0x7f, 0xd2, 0xbf, 0x51, 0xb0, 0x36,
-       0x78, 0x0a, 0x36, 0xcb, 0xda, 0x9d, 0xfd, 0x00, 0xde, 0x1b, 0x5c, 0x27,
-       0xef, 0x78, 0x2e, 0x0f, 0x41, 0x36, 0xf4, 0x7b, 0xde, 0x89, 0x21, 0x8f,
-       0x2a, 0xfa, 0x7a, 0x59, 0xc7, 0x82, 0x72, 0xb5, 0x88, 0x9c, 0x82, 0x18,
-       0x60, 0xef, 0x82, 0x2d, 0xce, 0x40, 0x97, 0x93, 0x80, 0xdb, 0x94, 0x4b,
-       0xd6, 0xcb, 0xba, 0x2e, 0x53, 0xa7, 0x6f, 0xde, 0xdf, 0x14, 0xe0, 0x3f,
-       0x6a, 0x1d, 0xb6, 0x05, 0x1f, 0x52, 0xeb, 0x71, 0x3c, 0x11, 0x8f, 0xd7,
-       0xd1, 0x5f, 0x54, 0x78, 0x3f, 0x84, 0xde, 0xa0, 0xc2, 0xbb, 0x93, 0x34,
-       0x9e, 0xe3, 0xbc, 0x2f, 0xf2, 0xe3, 0x1a, 0xf1, 0x93, 0x8e, 0x20, 0xbe,
-       0xb0, 0x96, 0x64, 0x7c, 0x09, 0xea, 0x49, 0xcf, 0x16, 0x8e, 0x55, 0x19,
-       0x43, 0x68, 0xd7, 0x43, 0x88, 0x5b, 0xb4, 0x05, 0xaf, 0x96, 0x5c, 0xad,
-       0x79, 0x32, 0x9b, 0x6b, 0x9e, 0xd7, 0x39, 0x62, 0xaf, 0x58, 0xb0, 0x31,
-       0xca, 0x0e, 0x6b, 0x3a, 0x07, 0x9c, 0x93, 0x9c, 0x7e, 0x52, 0x66, 0xaf,
-       0x48, 0x6e, 0x75, 0x5c, 0x9e, 0xd3, 0x71, 0x2b, 0x88, 0x59, 0xac, 0x21,
-       0xf9, 0xfb, 0x71, 0x5a, 0x9e, 0x3d, 0x79, 0x55, 0x9c, 0xe7, 0x19, 0xb7,
-       0xc6, 0x12, 0x9d, 0x06, 0x63, 0x95, 0x2b, 0x0d, 0xe4, 0xa6, 0x07, 0x6d,
-       0xfe, 0x5b, 0x80, 0x08, 0x7a, 0x3a, 0x57, 0xda, 0x27, 0x52, 0x76, 0xd2,
-       0x18, 0x3a, 0xd0, 0x69, 0x30, 0x37, 0x8e, 0x99, 0x8f, 0x4b, 0x70, 0x1f,
-       0xd5, 0x21, 0x8f, 0xeb, 0xbb, 0x0a, 0xb8, 0xed, 0xe2, 0x07, 0xfa, 0x77,
-       0x94, 0x6b, 0x19, 0xca, 0x1a, 0xdf, 0xeb, 0x9c, 0x2f, 0xc5, 0xae, 0x65,
-       0xda, 0xa4, 0x7c, 0x9b, 0xeb, 0x1e, 0x9a, 0x98, 0xd8, 0xe1, 0xfd, 0x7b,
-       0x91, 0x23, 0xb7, 0x79, 0xb1, 0xa0, 0xe0, 0x7f, 0xaf, 0xe1, 0x49, 0xdb,
-       0x66, 0xbe, 0x65, 0x7e, 0xa4, 0xde, 0xf0, 0x5c, 0xe5, 0x3b, 0x73, 0xef,
-       0x02, 0x72, 0x2f, 0xf3, 0xe5, 0x76, 0xc9, 0xf3, 0x77, 0x3e, 0xa5, 0xe7,
-       0x4b, 0x5e, 0x2d, 0xed, 0xc3, 0xd5, 0x66, 0x65, 0xae, 0xc6, 0x1a, 0xea,
-       0x02, 0x72, 0xd9, 0x28, 0x6c, 0x95, 0x39, 0xed, 0x28, 0xf2, 0x39, 0x7f,
-       0x9f, 0xc6, 0xda, 0x32, 0xf7, 0xa5, 0xd2, 0x49, 0xd5, 0xfa, 0xbb, 0xd2,
-       0xd5, 0x38, 0xef, 0xa3, 0xce, 0x8d, 0x42, 0xef, 0xbf, 0xc3, 0xde, 0x62,
-       0x58, 0xdb, 0x88, 0xf3, 0x02, 0x65, 0xef, 0xfd, 0x7e, 0x2d, 0x7d, 0x9e,
-       0x0f, 0xb0, 0x0e, 0xf8, 0x3c, 0xe4, 0xb2, 0xd7, 0xbe, 0xca, 0xdc, 0xfd,
-       0x6f, 0xca, 0x1a, 0x4b, 0x3f, 0x6e, 0xd0, 0xb7, 0xf1, 0xbd, 0x1a, 0x91,
-       0xe5, 0x38, 0xf9, 0x87, 0xbc, 0x0c, 0xfa, 0xce, 0x56, 0x72, 0xd8, 0x2c,
-       0x83, 0x3f, 0x80, 0x0c, 0x28, 0xcb, 0x40, 0x06, 0x7c, 0x9f, 0x86, 0xbe,
-       0xd8, 0x33, 0x0c, 0xe9, 0x3e, 0xb2, 0xdc, 0xf4, 0xce, 0x2e, 0x57, 0x5b,
-       0x69, 0x26, 0xbd, 0xd4, 0xe9, 0x39, 0xc9, 0x6b, 0xfd, 0x2e, 0x48, 0xbe,
-       0x76, 0x4e, 0xf6, 0xd4, 0x16, 0xe4, 0x21, 0xeb, 0x01, 0xf0, 0x7b, 0xc9,
-       0x2d, 0x5a, 0xba, 0x57, 0x99, 0x2c, 0xe0, 0xec, 0xe2, 0xff, 0x74, 0x6e,
-       0xb5, 0xbf, 0x6d, 0x55, 0x67, 0xfc, 0xf1, 0xb5, 0x9d, 0xa4, 0xa1, 0x09,
-       0xb7, 0xae, 0x93, 0xb8, 0x69, 0x0a, 0x76, 0x7c, 0xdb, 0x46, 0x24, 0xad,
-       0x6e, 0x43, 0x46, 0xa3, 0x2e, 0x53, 0x4c, 0x12, 0xba, 0x74, 0xeb, 0x44,
-       0xda, 0x75, 0x5d, 0x37, 0xd0, 0x64, 0x9c, 0xb4, 0x14, 0x98, 0x54, 0x28,
-       0xac, 0x43, 0x08, 0xa9, 0xc6, 0x6d, 0x35, 0xa6, 0xa5, 0x71, 0xfa, 0x46,
-       0x10, 0x5f, 0xb0, 0x92, 0xb4, 0x65, 0x52, 0x84, 0x5b, 0x04, 0xdb, 0x3e,
-       0xb0, 0xd1, 0xa5, 0x8c, 0x3f, 0x60, 0xfb, 0x30, 0x26, 0xb1, 0x29, 0x2b,
-       0xb0, 0xb1, 0x7d, 0xea, 0x07, 0x26, 0x75, 0xda, 0x8a, 0xf7, 0xfb, 0x3d,
-       0xe7, 0x5e, 0xc7, 0x36, 0x41, 0x48, 0x8b, 0x14, 0xf9, 0x9e, 0x97, 0x7b,
-       0xee, 0xb9, 0xe7, 0x79, 0x7f, 0x9e, 0xdf, 0xed, 0x59, 0x27, 0x9f, 0xc0,
-       0xef, 0x38, 0x35, 0x67, 0x4b, 0xda, 0xee, 0x97, 0x9f, 0x6a, 0x2e, 0x9f,
-       0xf1, 0x49, 0x00, 0x3e, 0xa9, 0xc1, 0x16, 0x48, 0x8b, 0x13, 0xbb, 0x21,
-       0xf4, 0x29, 0xc3, 0xa0, 0x75, 0xdc, 0xf8, 0xcd, 0xb6, 0x19, 0xdf, 0x74,
-       0x06, 0xbe, 0xbb, 0xbb, 0xad, 0xc5, 0xcf, 0xf9, 0x1a, 0xff, 0xf6, 0x7d,
-       0xaf, 0x86, 0xd6, 0x2f, 0xd3, 0xd8, 0xcf, 0x9b, 0xaa, 0x67, 0x1d, 0xf0,
-       0x12, 0x73, 0xd3, 0x31, 0xcd, 0x3f, 0x84, 0xa7, 0xa8, 0xa3, 0xae, 0x40,
-       0x47, 0x0d, 0x50, 0x77, 0x0d, 0xce, 0xb9, 0xcc, 0x0f, 0x44, 0xe5, 0x0f,
-       0x93, 0xd4, 0xc3, 0x71, 0xf9, 0xfd, 0xe4, 0xb3, 0xd8, 0x4f, 0xa2, 0xc0,
-       0x1c, 0xe5, 0xf5, 0xe9, 0xac, 0x62, 0x92, 0x86, 0xd5, 0x07, 0x7e, 0x5a,
-       0xed, 0x40, 0xdc, 0xca, 0xad, 0x0d, 0xab, 0xbe, 0x39, 0xa2, 0xb5, 0xdd,
-       0xb8, 0xd5, 0x21, 0xd7, 0xcf, 0x1b, 0x1d, 0x1b, 0x9e, 0x8a, 0x06, 0x86,
-       0xe7, 0x69, 0x97, 0x92, 0xb1, 0x8c, 0x55, 0x2f, 0x07, 0xa3, 0xcc, 0x3d,
-       0xa7, 0xa8, 0x9f, 0x61, 0x0b, 0xbb, 0xed, 0x8c, 0xd5, 0xe0, 0xd9, 0x9f,
-       0x58, 0x8d, 0x9e, 0x3d, 0xe2, 0xe9, 0x59, 0x8e, 0xa5, 0x40, 0x53, 0xda,
-       0xa2, 0xc4, 0xf4, 0x88, 0x95, 0x84, 0xcd, 0xc3, 0xf5, 0x02, 0xd7, 0x8f,
-       0xcb, 0xd1, 0x85, 0xc3, 0xf0, 0xbf, 0xbb, 0xed, 0xbd, 0xb4, 0xab, 0xf6,
-       0x00, 0xf1, 0x38, 0x78, 0xfe, 0x86, 0x9a, 0xb5, 0x1e, 0xf6, 0xd6, 0xe2,
-       0x38, 0xe4, 0x7c, 0x8a, 0xf5, 0xda, 0x7a, 0xe6, 0x73, 0x74, 0xaf, 0xd5,
-       0x73, 0xf7, 0x94, 0x9f, 0x7b, 0x32, 0xef, 0x78, 0x58, 0x30, 0xfc, 0xc2,
-       0x17, 0xfa, 0x76, 0x84, 0xcf, 0xe4, 0xf3, 0x9a, 0x65, 0x68, 0x3f, 0xf4,
-       0xcb, 0x14, 0xff, 0xb3, 0x5e, 0xed, 0x0a, 0xf1, 0x4a, 0xb4, 0x7d, 0x05,
-       0xdb, 0xf4, 0x35, 0x6f, 0xbd, 0xad, 0xad, 0xd2, 0x18, 0xad, 0x98, 0xcf,
-       0xdc, 0x0a, 0xdb, 0x71, 0xc9, 0x2e, 0xf0, 0xb7, 0x54, 0x8a, 0x38, 0x75,
-       0xb2, 0xd7, 0x5e, 0x5f, 0xb3, 0xc6, 0x16, 0xf4, 0x19, 0x9f, 0x20, 0x38,
-       0x15, 0xf0, 0x7c, 0x8b, 0xbb, 0xe9, 0x37, 0x79, 0xd7, 0x0d, 0x9a, 0x93,
-       0x89, 0x5b, 0xed, 0x35, 0xef, 0x71, 0x77, 0xd9, 0x0e, 0xc7, 0x2d, 0xea,
-       0xce, 0x60, 0x54, 0x9a, 0xc9, 0x43, 0x25, 0xf5, 0xe3, 0x43, 0x8e, 0xc1,
-       0x5c, 0x44, 0x9d, 0xf1, 0x56, 0xe6, 0xec, 0xdf, 0xd1, 0x73, 0x6b, 0xa2,
-       0x4f, 0x80, 0x6b, 0xf0, 0xc9, 0xe7, 0xf2, 0xbd, 0xcc, 0xf5, 0x62, 0xfd,
-       0x46, 0xae, 0xef, 0x7a, 0xe7, 0x9c, 0x70, 0xb3, 0xd6, 0x7d, 0x92, 0x39,
-       0x6f, 0xf8, 0x6f, 0xc8, 0x01, 0xef, 0x35, 0xa3, 0x3d, 0x4f, 0x9b, 0xf0,
-       0x45, 0xeb, 0xf8, 0xb6, 0xa1, 0x4b, 0x6d, 0xc3, 0x89, 0x3c, 0xf9, 0x93,
-       0x7c, 0xe9, 0xf3, 0xa3, 0xaf, 0xf3, 0xc8, 0xa3, 0xd4, 0xb3, 0xfd, 0x72,
-       0x26, 0xcf, 0xb3, 0x49, 0x69, 0x4d, 0x6b, 0xe3, 0xd9, 0x71, 0xc5, 0x64,
-       0x75, 0x4e, 0x25, 0x5e, 0xce, 0xca, 0xa0, 0x5c, 0x71, 0x79, 0x66, 0x89,
-       0x42, 0x3a, 0xd8, 0x54, 0xf1, 0xfe, 0xfb, 0xf5, 0xcc, 0xc2, 0xea, 0x33,
-       0xc6, 0x30, 0xf7, 0x79, 0x8f, 0xde, 0xcd, 0x7a, 0xb6, 0xe9, 0x2a, 0xfa,
-       0x7c, 0x53, 0xcf, 0x29, 0x0c, 0x9d, 0xc8, 0xfa, 0x7e, 0x38, 0xc2, 0x7b,
-       0xf8, 0x5c, 0xfa, 0x7c, 0x7c, 0x16, 0x79, 0xaf, 0x13, 0x16, 0xbb, 0x57,
-       0x82, 0x3b, 0x20, 0xfa, 0x3b, 0x58, 0x47, 0x0e, 0x40, 0x56, 0x37, 0x1a,
-       0x0c, 0xcc, 0x98, 0xf1, 0x35, 0xd2, 0xd6, 0x55, 0x9c, 0x23, 0x62, 0x15,
-       0xf8, 0xd1, 0x27, 0x5e, 0xba, 0x8d, 0xf5, 0xd2, 0x9e, 0xbf, 0xde, 0x87,
-       0xf5, 0x1d, 0xaf, 0xae, 0x3e, 0xb9, 0x8d, 0xbc, 0x3a, 0xa2, 0xf5, 0x41,
-       0xde, 0x43, 0x39, 0xe6, 0x99, 0x91, 0x2e, 0xef, 0xe3, 0x7e, 0xb6, 0xb7,
-       0xd4, 0xd0, 0x31, 0xe9, 0xed, 0xcf, 0x1f, 0x0f, 0x4b, 0xb8, 0x95, 0x3a,
-       0x2e, 0x2a, 0xc9, 0x29, 0xc6, 0x2c, 0xb0, 0x5d, 0x63, 0x5c, 0xeb, 0xcb,
-       0x75, 0x71, 0xfa, 0xff, 0xd4, 0xc5, 0x69, 0xeb, 0x23, 0xe5, 0x9d, 0xb0,
-       0xe6, 0xb1, 0xbe, 0x98, 0xae, 0x85, 0x2a, 0xba, 0xfa, 0xb5, 0xfb, 0x68,
-       0x99, 0x8e, 0x3f, 0xc9, 0xd3, 0x5e, 0xa5, 0x34, 0xa7, 0xfc, 0xb7, 0x49,
-       0x9e, 0x2d, 0xf7, 0x78, 0x85, 0x7b, 0x1c, 0x5c, 0x74, 0x89, 0x83, 0xf9,
-       0x96, 0xca, 0xf0, 0xa9, 0x3c, 0x75, 0x4c, 0x93, 0xcc, 0x4d, 0xfb, 0x7a,
-       0x66, 0xd4, 0xf3, 0x71, 0x73, 0x6b, 0xeb, 0x54, 0xcf, 0xc0, 0xbb, 0x71,
-       0x86, 0x3d, 0xfb, 0xd2, 0x21, 0xb3, 0xe7, 0x69, 0x77, 0x93, 0xe8, 0x8b,
-       0x06, 0x66, 0xe7, 0x59, 0x9b, 0x24, 0x16, 0x65, 0x50, 0x58, 0xf7, 0x1f,
-       0xb6, 0x4f, 0x40, 0xde, 0x62, 0xf2, 0xe1, 0x24, 0x7d, 0xfa, 0x3a, 0xf8,
-       0xc6, 0xcd, 0x35, 0xe7, 0xbb, 0xbd, 0xec, 0x13, 0x56, 0xd3, 0xbd, 0xa3,
-       0x4d, 0x1a, 0xc9, 0xe7, 0x8e, 0x7d, 0x5d, 0xe8, 0x83, 0xf1, 0x3a, 0x83,
-       0x58, 0x80, 0xb1, 0x47, 0x5c, 0x63, 0x8f, 0xd9, 0x02, 0xfb, 0x9a, 0xbc,
-       0xbc, 0x52, 0x93, 0xf2, 0x0a, 0xf9, 0x2d, 0xad, 0xfe, 0xf7, 0x80, 0xea,
-       0xac, 0xdc, 0x64, 0xb7, 0xc1, 0xb1, 0xd8, 0x31, 0xe5, 0x3d, 0xa9, 0xe2,
-       0xbd, 0x98, 0xef, 0x4b, 0xb6, 0x19, 0xdf, 0xca, 0x56, 0x7d, 0x13, 0xd6,
-       0x79, 0xb4, 0x2b, 0x5c, 0x9f, 0xbc, 0x41, 0x1e, 0xa1, 0xce, 0xf3, 0xe7,
-       0xf9, 0xf4, 0xf0, 0xdb, 0x9c, 0x4f, 0xfe, 0xaf, 0xc4, 0x22, 0xf8, 0xb2,
-       0xea, 0xf7, 0xf9, 0x72, 0xc7, 0xb1, 0x4a, 0x9b, 0x40, 0xb9, 0xab, 0xac,
-       0x4f, 0xda, 0x12, 0x99, 0x5a, 0xa6, 0xcb, 0x50, 0x2f, 0xf7, 0xff, 0x3c,
-       0x73, 0xbb, 0x90, 0xb7, 0x95, 0x68, 0x73, 0x4c, 0x69, 0x93, 0x06, 0x6d,
-       0x22, 0x4a, 0x1b, 0xc6, 0x7b, 0x4f, 0x79, 0xfc, 0xd6, 0x84, 0xf3, 0x62,
-       0xae, 0x16, 0xba, 0x6e, 0x1f, 0x75, 0xfe, 0x33, 0x6d, 0x5a, 0x1f, 0x74,
-       0xa8, 0xfb, 0x56, 0x43, 0x9f, 0xb1, 0xbd, 0x59, 0xfd, 0x11, 0x13, 0x6f,
-       0xc5, 0x35, 0x0f, 0x1a, 0x84, 0x7e, 0x9e, 0x9d, 0x84, 0xaf, 0x46, 0xdc,
-       0x5b, 0x15, 0xad, 0x1e, 0xf7, 0xce, 0xeb, 0x55, 0xa5, 0x0d, 0x65, 0x80,
-       0x7a, 0x73, 0x0d, 0xd6, 0xdb, 0x13, 0xed, 0x01, 0x7f, 0xbd, 0x82, 0xfe,
-       0x8d, 0x1a, 0x4f, 0x04, 0x21, 0xf3, 0x37, 0x26, 0x5b, 0xbd, 0x18, 0xce,
-       0x41, 0x1b, 0x71, 0xeb, 0x64, 0x84, 0x31, 0x05, 0xda, 0x5d, 0x52, 0x37,
-       0x85, 0xf8, 0x15, 0x7a, 0x7c, 0x51, 0xed, 0x51, 0x0f, 0xc6, 0xef, 0x20,
-       0xce, 0x0f, 0xd7, 0x87, 0x71, 0x5f, 0xb7, 0xc1, 0x22, 0x44, 0x37, 0xe9,
-       0x99, 0xce, 0x4e, 0x26, 0x62, 0x87, 0xc4, 0xeb, 0x1b, 0x73, 0x55, 0x1f,
-       0x2c, 0xef, 0xeb, 0x01, 0xd9, 0x53, 0xb6, 0x17, 0x8c, 0xa3, 0xe1, 0xc3,
-       0x4f, 0x1b, 0x7b, 0x90, 0x2b, 0xf4, 0x28, 0x3e, 0x2a, 0x38, 0xb0, 0x80,
-       0xb3, 0xa4, 0x4f, 0xba, 0x04, 0x3f, 0xdc, 0xc5, 0x19, 0xd2, 0xef, 0x2e,
-       0x1d, 0x3f, 0xe9, 0xa6, 0x58, 0x1f, 0x83, 0x3e, 0x38, 0x2e, 0xc3, 0x88,
-       0x0b, 0x86, 0x83, 0xcd, 0xcc, 0x2b, 0xc3, 0x37, 0xcc, 0x7a, 0xb9, 0xc7,
-       0x1e, 0xe6, 0x4c, 0xe5, 0xec, 0x3c, 0xf7, 0x4e, 0xd9, 0x36, 0xb1, 0xf7,
-       0xec, 0x24, 0xf7, 0x6b, 0xf2, 0x10, 0x6c, 0x5b, 0x53, 0x2e, 0x7e, 0x79,
-       0x16, 0x7d, 0xf8, 0xed, 0x87, 0x3c, 0x70, 0x2e, 0x7e, 0xe7, 0x97, 0xe4,
-       0xbd, 0xf3, 0xbe, 0x6d, 0x0f, 0xc8, 0xbb, 0x4e, 0xe9, 0xf8, 0x09, 0x77,
-       0x2d, 0xcf, 0xc0, 0xcd, 0xb2, 0x66, 0xed, 0x38, 0x6e, 0x4e, 0x4a, 0xa5,
-       0x45, 0x77, 0x71, 0xad, 0xa5, 0xb4, 0xa4, 0xfc, 0x7f, 0x80, 0x33, 0xbc,
-       0x76, 0xaf, 0x25, 0x86, 0x7e, 0xa4, 0xcd, 0xe7, 0x6b, 0x7f, 0x95, 0xb6,
-       0xc0, 0xd7, 0x7f, 0xe4, 0x47, 0xf2, 0xe5, 0x92, 0xec, 0x54, 0xfd, 0xbf,
-       0xd2, 0x7d, 0x95, 0xba, 0xdf, 0xf7, 0x6f, 0xa9, 0xdf, 0xc9, 0x8b, 0x31,
-       0x8d, 0x0f, 0x36, 0x4d, 0xd5, 0xea, 0x84, 0x1f, 0x78, 0x75, 0x85, 0x95,
-       0x78, 0xef, 0x80, 0xa7, 0x17, 0x52, 0xea, 0x3b, 0xa7, 0x6c, 0xea, 0x07,
-       0xee, 0xa7, 0x51, 0xc6, 0x67, 0x6e, 0x83, 0x26, 0xbe, 0x0e, 0x66, 0xdc,
-       0xe7, 0xeb, 0x8e, 0x66, 0xcf, 0x17, 0xb6, 0xa4, 0xf3, 0x2c, 0x7d, 0x27,
-       0x07, 0x7a, 0xb4, 0x45, 0xd2, 0x63, 0x41, 0x49, 0x9e, 0x6d, 0x89, 0x19,
-       0x5f, 0x97, 0xfc, 0x07, 0x79, 0xd3, 0x3e, 0xb6, 0x37, 0xa0, 0xff, 0x4e,
-       0xe1, 0xb3, 0x0d, 0x3f, 0x43, 0x9e, 0xf7, 0xf9, 0x63, 0x76, 0x0d, 0x8f,
-       0xee, 0xf0, 0x78, 0x94, 0xe3, 0x96, 0xa9, 0x7f, 0x60, 0x6e, 0xe7, 0x59,
-       0xee, 0xd1, 0xdc, 0xd7, 0x79, 0xd6, 0xc4, 0xeb, 0xd5, 0xf7, 0xf5, 0x94,
-       0xef, 0xc3, 0x78, 0x97, 0x62, 0xc3, 0xb0, 0xf6, 0xce, 0x7e, 0xf8, 0x74,
-       0x3d, 0xb4, 0x39, 0xb4, 0xdf, 0x1b, 0xdd, 0x9d, 0x42, 0x7e, 0x4f, 0x78,
-       0x3c, 0x47, 0x7d, 0x13, 0xf1, 0xf4, 0xcd, 0xb2, 0x7d, 0x19, 0x36, 0xf8,
-       0x13, 0xe6, 0x44, 0x2a, 0xec, 0xcb, 0x43, 0xe6, 0xdd, 0xaa, 0xec, 0xcb,
-       0x9d, 0xde, 0x3a, 0xfe, 0x98, 0xaf, 0x57, 0xfc, 0xb6, 0xaf, 0x57, 0x6a,
-       0x7d, 0x5a, 0x9f, 0xf6, 0xd5, 0xb8, 0xaf, 0xca, 0x98, 0x2f, 0xb7, 0x62,
-       0xde, 0x25, 0x83, 0x98, 0x8d, 0x3e, 0x65, 0x22, 0x6b, 0x30, 0xd3, 0xd6,
-       0x19, 0x8b, 0xb8, 0x0f, 0xe7, 0x67, 0x32, 0x14, 0xb9, 0xad, 0xb1, 0xf5,
-       0xa9, 0x99, 0x51, 0xcd, 0xf3, 0xcc, 0xba, 0x9e, 0xde, 0x89, 0xee, 0x86,
-       0x5c, 0xcd, 0x47, 0x96, 0x31, 0x45, 0x4f, 0x1e, 0x1b, 0x82, 0x1d, 0x4a,
-       0x69, 0xbd, 0xec, 0x71, 0xec, 0xb7, 0x5f, 0xf1, 0x5c, 0xab, 0x9c, 0xe7,
-       0x64, 0x97, 0x5d, 0xd2, 0xda, 0x4d, 0xc3, 0x40, 0xf6, 0x58, 0xc3, 0x69,
-       0x9f, 0xef, 0xc9, 0x4f, 0x4f, 0x1e, 0x1b, 0x9f, 0x2e, 0x0d, 0x86, 0xb6,
-       0x75, 0xdb, 0x39, 0x59, 0x0f, 0x9a, 0x0f, 0xca, 0xa3, 0x8a, 0x1d, 0x7e,
-       0x0d, 0xe3, 0xfb, 0x18, 0x5f, 0x26, 0x42, 0x8a, 0x09, 0x4e, 0xc4, 0x26,
-       0x20, 0x8b, 0x19, 0x37, 0xd1, 0x35, 0x14, 0x5c, 0xcd, 0xdc, 0x0d, 0x62,
-       0x66, 0xfa, 0x59, 0xc4, 0x14, 0x3c, 0x2b, 0x87, 0xdc, 0x8d, 0xee, 0xa2,
-       0x64, 0x3d, 0x4c, 0x3e, 0x6b, 0x42, 0xf5, 0x32, 0xe1, 0x86, 0x1a, 0x86,
-       0x8a, 0x46, 0x06, 0x46, 0x82, 0xa9, 0x55, 0x27, 0x9d, 0x68, 0xc3, 0xce,
-       0x22, 0x64, 0xbc, 0x08, 0xfd, 0x5f, 0x8c, 0x05, 0x86, 0x15, 0x9b, 0xf6,
-       0x55, 0x19, 0x6a, 0xa5, 0x9f, 0x4f, 0x7d, 0xf2, 0x35, 0xb9, 0x61, 0x6f,
-       0x96, 0x1b, 0x5d, 0xc4, 0x63, 0xf6, 0xa2, 0x4d, 0x5d, 0xd2, 0x8f, 0xbe,
-       0x24, 0xfa, 0x1a, 0x94, 0x1f, 0x35, 0x3e, 0x83, 0xce, 0xba, 0x61, 0x53,
-       0x57, 0xdd, 0xc5, 0x5f, 0xbc, 0xeb, 0x9f, 0x41, 0x13, 0x62, 0x3b, 0xb6,
-       0xa0, 0x4d, 0x1d, 0x67, 0xd7, 0xf4, 0xb7, 0xa3, 0x7d, 0x2f, 0xd6, 0xa8,
-       0xd3, 0xf7, 0xb3, 0x9c, 0x6d, 0xa6, 0xce, 0x59, 0x35, 0x67, 0x4d, 0x4d,
-       0xfb, 0xdd, 0x16, 0x83, 0x4f, 0xb8, 0x45, 0x7a, 0x67, 0x53, 0xb2, 0xab,
-       0xad, 0xba, 0xfd, 0xcf, 0x9a, 0x76, 0xb3, 0xac, 0x6a, 0x21, 0x19, 0x9e,
-       0x68, 0xad, 0xee, 0xf7, 0xf9, 0xc9, 0x6f, 0xb7, 0xe1, 0x7d, 0x13, 0x30,
-       0x78, 0x49, 0x8d, 0xa5, 0x6e, 0x44, 0xf9, 0xac, 0xbf, 0xd6, 0xdc, 0xc3,
-       0x6b, 0xde, 0xc3, 0x7b, 0x99, 0xd7, 0xfb, 0x37, 0xfb, 0x71, 0x0f, 0x73,
-       0x02, 0xcc, 0x6b, 0x90, 0x67, 0x57, 0x8a, 0xb3, 0x38, 0xe7, 0xf3, 0xf9,
-       0x86, 0x74, 0x99, 0xf7, 0x7c, 0xbd, 0x12, 0x2b, 0x63, 0xd5, 0x76, 0xe6,
-       0xfd, 0x9c, 0x30, 0x69, 0xa7, 0x35, 0xa9, 0xd8, 0x75, 0xd0, 0xf9, 0x20,
-       0xe8, 0xfc, 0x40, 0x90, 0x71, 0x61, 0xa3, 0x47, 0x6b, 0x47, 0x86, 0x8b,
-       0x6f, 0x43, 0xc6, 0xc9, 0xa3, 0xf0, 0x29, 0x8a, 0x96, 0x87, 0xcf, 0xe8,
-       0x83, 0x4d, 0x73, 0x25, 0xa8, 0x79, 0x07, 0xc4, 0xf7, 0x73, 0xd7, 0x64,
-       0x78, 0x92, 0x39, 0x01, 0xf2, 0x33, 0xe3, 0xfa, 0x14, 0xc6, 0x6e, 0x62,
-       0xae, 0x0b, 0x19, 0x1e, 0x05, 0xbf, 0x86, 0xc4, 0x99, 0xda, 0x22, 0xd9,
-       0xb1, 0x51, 0xf5, 0x01, 0x3a, 0x61, 0xa3, 0x4e, 0xb8, 0x23, 0x72, 0xf2,
-       0xf2, 0xdd, 0x90, 0x55, 0xc6, 0xfd, 0x9a, 0xd3, 0x28, 0x85, 0xd5, 0x37,
-       0xa7, 0xcf, 0xc1, 0x3c, 0x9c, 0xa9, 0x31, 0x1b, 0xb9, 0x7d, 0x24, 0x26,
-       0xcd, 0x23, 0x32, 0x3d, 0x63, 0x2b, 0xde, 0x25, 0x25, 0xb7, 0x4b, 0xa4,
-       0x5d, 0x66, 0x5f, 0x1c, 0xba, 0x8a, 0xbe, 0x7c, 0x2e, 0x62, 0xce, 0x72,
-       0x74, 0x1d, 0x63, 0xe2, 0xe4, 0x54, 0xe5, 0x1a, 0x8a, 0x91, 0xc1, 0xd8,
-       0xa5, 0x16, 0x23, 0x33, 0x8c, 0x8f, 0x3f, 0x2a, 0xa5, 0xa2, 0x7c, 0x26,
-       0xe7, 0xb2, 0x76, 0x4b, 0x1e, 0xe1, 0xde, 0xfe, 0xe3, 0xf1, 0xf2, 0x4b,
-       0x58, 0x2f, 0x2e, 0x9d, 0xaf, 0x8f, 0x6a, 0x5c, 0x7f, 0xa2, 0x2a, 0x86,
-       0x35, 0xf9, 0x02, 0x13, 0xc7, 0x5e, 0x93, 0x89, 0x05, 0xd2, 0x87, 0x36,
-       0x3e, 0x20, 0x3f, 0x77, 0xba, 0xed, 0xc7, 0xb4, 0xd6, 0x98, 0x48, 0xb1,
-       0x3e, 0xd3, 0xe8, 0x24, 0xed, 0x39, 0x09, 0xf5, 0x7f, 0x03, 0xd7, 0x8c,
-       0x6b, 0x73, 0x6e, 0xb7, 0xfb, 0x98, 0xf8, 0x38, 0x90, 0x8d, 0xa9, 0xfa,
-       0xc0, 0xad, 0xd2, 0xb5, 0x7d, 0x9c, 0x63, 0x70, 0x20, 0x12, 0x20, 0xad,
-       0x3e, 0xb8, 0x8b, 0xf8, 0x99, 0xea, 0xfc, 0xdf, 0xfd, 0x47, 0xf6, 0xf6,
-       0x25, 0x5e, 0x64, 0x0c, 0x1b, 0x76, 0x0e, 0xac, 0x33, 0xef, 0x9a, 0xcd,
-       0xae, 0x11, 0xad, 0x9f, 0x1d, 0xfd, 0xbb, 0x43, 0x3c, 0x44, 0x22, 0x56,
-       0x6f, 0x31, 0x0f, 0x4e, 0x1d, 0xc7, 0x9a, 0x0a, 0x73, 0x6e, 0xc4, 0xf2,
-       0x37, 0xc8, 0xa5, 0x1e, 0x4b, 0xee, 0x0f, 0xa5, 0xe2, 0x96, 0x6c, 0x8a,
-       0x9f, 0x15, 0x3c, 0x93, 0xf5, 0x95, 0x85, 0x44, 0x96, 0xf3, 0x43, 0x53,
-       0x5c, 0x2f, 0xae, 0xf1, 0x4a, 0x72, 0x53, 0xa9, 0xf4, 0x94, 0x2b, 0x81,
-       0xe4, 0xd6, 0x8f, 0x4b, 0xac, 0x85, 0x5b, 0xaf, 0x7f, 0x11, 0x4e, 0x41,
-       0xbf, 0x1d, 0x98, 0x30, 0x98, 0xc3, 0x89, 0xa3, 0x9d, 0x0b, 0x6c, 0xa7,
-       0x77, 0x99, 0xf6, 0x61, 0xb4, 0xeb, 0x3c, 0xac, 0xd3, 0x0f, 0x8f, 0x76,
-       0x16, 0x9e, 0x58, 0x67, 0xe2, 0xef, 0x25, 0xc5, 0x7f, 0xbd, 0x53, 0x15,
-       0xd3, 0xa4, 0x02, 0x63, 0xf9, 0xd1, 0xc0, 0x68, 0xde, 0xea, 0x69, 0x00,
-       0xad, 0xe6, 0x5d, 0xe6, 0x6a, 0xfc, 0x9c, 0x15, 0xf3, 0xfd, 0x22, 0x4f,
-       0x2a, 0x46, 0x8a, 0x35, 0x45, 0x4b, 0x7d, 0xa1, 0x83, 0xf3, 0xcc, 0xf1,
-       0x47, 0x54, 0x1f, 0x1c, 0x5a, 0x68, 0x96, 0x9c, 0xbd, 0x56, 0x72, 0x2a,
-       0xe3, 0x51, 0xd5, 0x01, 0x96, 0xb3, 0x15, 0x7d, 0xdc, 0xf7, 0x43, 0x8a,
-       0x8b, 0x78, 0x23, 0xdf, 0x8e, 0x36, 0x73, 0xcd, 0xdb, 0x6b, 0xfa, 0x2b,
-       0xeb, 0xb2, 0x09, 0xdb, 0xb2, 0x6a, 0x6b, 0xb2, 0xec, 0xab, 0xad, 0xc5,
-       0x9e, 0x92, 0x6b, 0xe4, 0x9b, 0xa2, 0x9f, 0x73, 0x77, 0xbd, 0x9c, 0xfb,
-       0xf7, 0xb1, 0x26, 0xd7, 0x96, 0x74, 0x68, 0xa0, 0xa1, 0xe7, 0xc4, 0x64,
-       0xf0, 0xe6, 0x72, 0xfe, 0x14, 0xed, 0x85, 0x72, 0xad, 0x1c, 0x63, 0xcf,
-       0xc0, 0x17, 0xc9, 0xc1, 0xaf, 0xc8, 0x7a, 0xdf, 0x1f, 0x70, 0xbc, 0x7c,
-       0xff, 0x97, 0xec, 0xa9, 0x51, 0xeb, 0xec, 0x56, 0x55, 0x9d, 0xfd, 0x7b,
-       0xb8, 0x97, 0x35, 0xf6, 0x6c, 0xa9, 0x0e, 0xbc, 0x5b, 0x47, 0x9c, 0x48,
-       0x79, 0x3e, 0x75, 0xbc, 0xea, 0x72, 0x5d, 0x6b, 0xa7, 0xb7, 0x56, 0x10,
-       0x7a, 0x7e, 0x7c, 0xd2, 0x9f, 0x73, 0x5c, 0xea, 0x7b, 0x13, 0xb1, 0xa0,
-       0xc5, 0x39, 0x46, 0xdf, 0x0f, 0xb9, 0xc7, 0xa1, 0xc7, 0xa9, 0xf3, 0xf9,
-       0xde, 0x0e, 0x7c, 0x3d, 0xea, 0x02, 0xea, 0x73, 0xb5, 0x01, 0xf1, 0x1c,
-       0x74, 0xfd, 0x70, 0xd1, 0x7c, 0xeb, 0xf5, 0xf5, 0x60, 0x62, 0x3a, 0xa3,
-       0xba, 0x01, 0xfe, 0x5e, 0xf1, 0x0d, 0xe6, 0x83, 0x5e, 0x94, 0x40, 0x65,
-       0x9d, 0x86, 0xb1, 0x19, 0x6b, 0x1a, 0x4d, 0xd0, 0x0d, 0x22, 0x57, 0xc0,
-       0x1b, 0x57, 0xe7, 0xc9, 0xaf, 0xc1, 0x56, 0x13, 0x5f, 0x2d, 0x6e, 0xb7,
-       0xa4, 0x55, 0x6b, 0x9f, 0x39, 0x27, 0x42, 0xff, 0x64, 0x30, 0xd9, 0x0b,
-       0x3f, 0x5b, 0xb1, 0x07, 0xcc, 0x57, 0x8e, 0x23, 0x1e, 0xab, 0xcc, 0xb1,
-       0x40, 0xbe, 0xc6, 0xd8, 0x9f, 0x81, 0x5f, 0xb9, 0x5c, 0xf7, 0xc8, 0x15,
-       0x4e, 0x6a, 0x6e, 0x73, 0x76, 0xbe, 0x49, 0x75, 0xec, 0x6c, 0x61, 0x04,
-       0xe7, 0x22, 0x9b, 0xad, 0x81, 0x9c, 0xd7, 0x1f, 0x96, 0x42, 0x81, 0x6d,
-       0xe9, 0xa8, 0xd3, 0x73, 0xf7, 0x6b, 0x3b, 0xb6, 0xcc, 0xc1, 0x57, 0x2c,
-       0x2c, 0x38, 0xf8, 0xef, 0xc2, 0x7f, 0x0f, 0xfe, 0x77, 0xcb, 0xd0, 0x14,
-       0xfd, 0x57, 0xd6, 0x72, 0x9a, 0x6a, 0x9e, 0x4f, 0x1f, 0xa9, 0x43, 0x71,
-       0x60, 0x39, 0x2f, 0xce, 0xc9, 0x15, 0x6a, 0xe5, 0x84, 0x79, 0x52, 0x5f,
-       0x47, 0x30, 0x5f, 0xea, 0xd7, 0xfa, 0x2a, 0x6b, 0x58, 0x96, 0x57, 0xf7,
-       0x22, 0x4f, 0x37, 0xca, 0xa1, 0x82, 0x5f, 0xbb, 0x8a, 0xc9, 0xa3, 0xe5,
-       0xda, 0x95, 0xa4, 0x83, 0x03, 0xb7, 0x1e, 0xcc, 0x4c, 0x2a, 0x9e, 0xc0,
-       0xb2, 0x06, 0xae, 0x3d, 0x38, 0xb1, 0xf0, 0xee, 0x83, 0xcb, 0x98, 0x70,
-       0x8c, 0x2d, 0xac, 0x84, 0x19, 0x22, 0x96, 0xee, 0x33, 0xf2, 0x10, 0x0d,
-       0x27, 0xf6, 0xed, 0xc7, 0x3c, 0xc4, 0xd9, 0x6d, 0xb0, 0x97, 0xf1, 0xcb,
-       0x7e, 0x3c, 0x4a, 0x1c, 0x29, 0xef, 0xab, 0xc4, 0x7e, 0x84, 0x70, 0xfe,
-       0x12, 0xb0, 0x9c, 0x2c, 0xf6, 0x71, 0xa1, 0xdd, 0xf8, 0x81, 0xc4, 0x99,
-       0x26, 0x2a, 0xb0, 0x47, 0x3e, 0xd6, 0xf4, 0x65, 0xac, 0x95, 0x96, 0xdf,
-       0x14, 0x1f, 0x96, 0x5f, 0x16, 0x47, 0x21, 0xdf, 0x13, 0x58, 0xf3, 0x80,
-       0xfc, 0xa2, 0xb8, 0x4f, 0xde, 0x2a, 0x8e, 0xc9, 0x9b, 0xc5, 0xdd, 0x88,
-       0xa9, 0x46, 0x88, 0xf5, 0xf4, 0xb0, 0xd2, 0x83, 0x32, 0x7e, 0x4e, 0x31,
-       0x80, 0x37, 0xe9, 0xf7, 0x1c, 0x55, 0x3f, 0x9b, 0xf8, 0xfa, 0xc4, 0xaf,
-       0x18, 0xcf, 0x13, 0x9b, 0x59, 0x28, 0xfa, 0x18, 0x8e, 0x89, 0x0e, 0x3c,
-       0xdb, 0xe6, 0xb7, 0x29, 0xc3, 0xe7, 0x22, 0x81, 0x91, 0x73, 0xa1, 0xc0,
-       0x03, 0xfa, 0x9d, 0x0b, 0xeb, 0x9d, 0x25, 0x39, 0xe9, 0x3a, 0xe4, 0xcd,
-       0xfe, 0x61, 0xc8, 0xc2, 0x08, 0x54, 0xfd, 0x2e, 0x67, 0xad, 0x80, 0xa4,
-       0xa9, 0x4f, 0xe0, 0x67, 0x26, 0x4f, 0xbb, 0x92, 0xc9, 0xcf, 0x05, 0x0c,
-       0x1e, 0xcd, 0x46, 0xbb, 0x07, 0xed, 0x57, 0xbd, 0xf6, 0x0e, 0xc9, 0xcc,
-       0x48, 0xea, 0x43, 0xf5, 0x87, 0x5f, 0xf1, 0xfa, 0xfa, 0xd1, 0x07, 0xce,
-       0xbc, 0xc0, 0xbe, 0x0b, 0x5e, 0x1f, 0xcf, 0x84, 0xb5, 0xfa, 0xb8, 0xf2,
-       0x55, 0xc6, 0x1e, 0x13, 0xfd, 0xae, 0x41, 0x6b, 0xf1, 0x4b, 0xed, 0x46,
-       0xb7, 0x11, 0x13, 0xf8, 0x8f, 0x76, 0xc6, 0x60, 0x05, 0xc8, 0xd7, 0x5d,
-       0xd0, 0x89, 0x7f, 0xd9, 0xbc, 0xdc, 0xb6, 0x06, 0x3e, 0xad, 0xc0, 0x68,
-       0x7f, 0x2a, 0x9d, 0x0b, 0xff, 0xf2, 0xf0, 0xbc, 0x07, 0xf1, 0x6e, 0x38,
-       0xab, 0x3c, 0x71, 0xe3, 0x71, 0xc8, 0x76, 0x93, 0xac, 0x3d, 0x43, 0x7a,
-       0x75, 0x43, 0x57, 0xa7, 0x20, 0xb7, 0xae, 0xcc, 0x17, 0x43, 0x81, 0xe1,
-       0x7c, 0x4a, 0x0c, 0x9e, 0xda, 0x92, 0x74, 0x34, 0x25, 0xa7, 0xfa, 0x12,
-       0x5d, 0xcc, 0x43, 0x66, 0x7a, 0x5d, 0xb9, 0x58, 0xa4, 0x3d, 0xce, 0xca,
-       0xa5, 0xbe, 0x84, 0x5b, 0x10, 0xe2, 0x62, 0x5c, 0xb9, 0x04, 0xd9, 0xfc,
-       0xdd, 0xb9, 0xdd, 0xf2, 0x68, 0x5e, 0xfd, 0xe0, 0xee, 0xb0, 0xbc, 0x20,
-       0x17, 0xfb, 0x5e, 0xb8, 0x79, 0xd1, 0x7d, 0x04, 0x67, 0x4a, 0x3e, 0xcc,
-       0x74, 0x98, 0x7d, 0x2b, 0x0e, 0x49, 0x98, 0x0f, 0xd1, 0x9a, 0x9a, 0x53,
-       0x2f, 0x43, 0xfb, 0x23, 0x5e, 0x5c, 0x0e, 0x9f, 0x3b, 0xe0, 0x9a, 0x7a,
-       0x4a, 0xc0, 0xdf, 0x67, 0x18, 0x7e, 0x0c, 0xef, 0xf3, 0x69, 0xe3, 0xaf,
-       0xd3, 0x1e, 0x18, 0x9a, 0x69, 0x96, 0xd0, 0x85, 0xaf, 0x80, 0xae, 0x21,
-       0x39, 0xd8, 0x5b, 0x2a, 0x7d, 0xc7, 0x0d, 0xc5, 0x27, 0x10, 0xa3, 0x60,
-       0xff, 0xb2, 0xe6, 0x74, 0x0b, 0x68, 0xd2, 0x20, 0xd1, 0xd3, 0xfe, 0xf3,
-       0xea, 0x3d, 0x2c, 0xc3, 0x99, 0x35, 0xc6, 0x96, 0xf9, 0xd8, 0x06, 0x7f,
-       0x3d, 0x83, 0x29, 0xeb, 0xb4, 0x7a, 0x03, 0xde, 0x77, 0x12, 0x5e, 0x7b,
-       0x6b, 0xe0, 0xfe, 0x50, 0xab, 0x84, 0x9c, 0x67, 0xd7, 0x13, 0x1b, 0xb9,
-       0x98, 0xf7, 0xfb, 0xe1, 0x27, 0x86, 0x7c, 0x7f, 0x58, 0xb6, 0x2d, 0x9f,
-       0xb5, 0x6c, 0xeb, 0x5c, 0xf8, 0xae, 0xb7, 0x66, 0xca, 0x9b, 0x8b, 0x98,
-       0x23, 0xb6, 0x5a, 0xed, 0x93, 0x99, 0xfb, 0x5f, 0x79, 0xba, 0x37, 0xf1,
-       0x9a, 0xe2, 0x64, 0xcb, 0xf7, 0x70, 0x1c, 0x31, 0x64, 0x51, 0xef, 0x89,
-       0xed, 0x01, 0x7d, 0xd3, 0xb1, 0x7b, 0xec, 0x39, 0x2b, 0x18, 0x30, 0xfe,
-       0x48, 0x9d, 0xfc, 0x28, 0x0a, 0xbb, 0xcd, 0x6f, 0x58, 0x98, 0xff, 0x72,
-       0x6f, 0x7b, 0x7e, 0x0a, 0xfb, 0x12, 0x2f, 0x26, 0xad, 0x34, 0xf6, 0xc7,
-       0x33, 0x20, 0x06, 0xd4, 0x02, 0x9d, 0xda, 0xf1, 0x7e, 0x88, 0x9f, 0x7a,
-       0xfd, 0xf7, 0x5f, 0x03, 0x1d, 0xc6, 0xfd, 0x1b, 0x5c, 0x98, 0x58, 0xcc,
-       0x85, 0x0c, 0x7a, 0x18, 0xd8, 0x4a, 0xb9, 0xf5, 0xb1, 0xb1, 0x3e, 0x9e,
-       0x8e, 0x18, 0xa5, 0x18, 0xfc, 0x40, 0xca, 0x04, 0x79, 0xb3, 0x0d, 0xfd,
-       0xab, 0x6e, 0xa5, 0xf4, 0xd5, 0xfd, 0xbe, 0x8f, 0xcb, 0xd8, 0xee, 0x89,
-       0xfc, 0x3e, 0x83, 0xcd, 0xb3, 0x96, 0x24, 0xd5, 0x91, 0xb4, 0x4f, 0x62,
-       0xbf, 0x43, 0xa1, 0x44, 0x21, 0x2b, 0x31, 0x99, 0x83, 0xbe, 0xb8, 0x0a,
-       0xd9, 0x7f, 0xab, 0xc8, 0xef, 0x6d, 0x53, 0x72, 0x28, 0x0f, 0x83, 0x3e,
-       0xa3, 0xdf, 0x7e, 0x41, 0xef, 0x0f, 0xc8, 0x6c, 0x3e, 0xd1, 0x35, 0x07,
-       0xfe, 0x9b, 0xcb, 0x13, 0x5f, 0xd4, 0x1d, 0x1f, 0xc1, 0x8a, 0x8b, 0xf9,
-       0x8d, 0xb0, 0x0f, 0x92, 0xba, 0x08, 0xff, 0xe7, 0x62, 0xb1, 0x0b, 0x7c,
-       0x86, 0xf1, 0xa2, 0x83, 0x5f, 0xe8, 0xcc, 0x62, 0x1f, 0xe4, 0x9c, 0x7b,
-       0xb1, 0x65, 0x7e, 0x33, 0xce, 0x8e, 0x38, 0x22, 0xc5, 0x8f, 0x7f, 0x86,
-       0xf3, 0xf5, 0xdf, 0x7b, 0xbb, 0xda, 0xe9, 0x39, 0xdd, 0x17, 0xec, 0x32,
-       0x62, 0x80, 0x4c, 0xaf, 0xb1, 0xdb, 0x43, 0x91, 0x16, 0x19, 0xba, 0x87,
-       0x76, 0xbc, 0x55, 0x63, 0x44, 0xe5, 0xc5, 0x08, 0xc7, 0x7f, 0xbb, 0xde,
-       0xd0, 0x2f, 0x5c, 0xd3, 0x7e, 0x1b, 0xbf, 0xcd, 0xd2, 0xe6, 0xf0, 0xd7,
-       0xc6, 0xef, 0xb5, 0xf5, 0xac, 0xef, 0xb6, 0x39, 0x49, 0x3c, 0xeb, 0xd7,
-       0x5e, 0xbe, 0x00, 0xd7, 0x73, 0xbc, 0x67, 0x9d, 0xf7, 0x5c, 0xae, 0xdb,
-       0x8c, 0x75, 0x9a, 0xbc, 0x67, 0x35, 0x6b, 0x7e, 0xd2, 0x3c, 0x0b, 0x31,
-       0x6e, 0xfe, 0x4f, 0xeb, 0x79, 0x86, 0xfc, 0xde, 0xb8, 0xba, 0xfd, 0xc7,
-       0xf5, 0xc4, 0xcd, 0xb5, 0x39, 0xcd, 0x8a, 0xf1, 0xbc, 0xd1, 0xda, 0x8a,
-       0x6b, 0x3e, 0x93, 0x73, 0x4c, 0x3e, 0x7c, 0xb6, 0xc8, 0xf5, 0xd9, 0x4e,
-       0xc9, 0x31, 0xcd, 0x67, 0x18, 0x2c, 0xdf, 0x6c, 0xfe, 0x3e, 0x99, 0x38,
-       0xa7, 0xf8, 0xba, 0xe9, 0x9c, 0xc5, 0xef, 0x5e, 0xf8, 0xbd, 0x1c, 0x7d,
-       0x89, 0x51, 0x19, 0xc7, 0xf9, 0x5d, 0x82, 0x4f, 0xb5, 0x68, 0xbe, 0x8b,
-       0xc5, 0xdf, 0x01, 0x9c, 0x4b, 0x08, 0x32, 0x46, 0x19, 0xa5, 0x4c, 0xe1,
-       0xfc, 0xc6, 0x6c, 0x79, 0xaf, 0x8f, 0xf2, 0xdc, 0x27, 0x97, 0xcb, 0xf2,
-       0x9c, 0x85, 0x3c, 0x53, 0x96, 0xb3, 0x90, 0x69, 0xc3, 0xd7, 0xfb, 0x11,
-       0x63, 0xa4, 0x62, 0xb0, 0x57, 0xea, 0x43, 0xbc, 0x0c, 0xbe, 0xb6, 0xbd,
-       0x6f, 0xa5, 0x02, 0x9a, 0xc3, 0xc9, 0xcc, 0xd4, 0x79, 0xdf, 0x01, 0xe0,
-       0xfa, 0xf2, 0x73, 0x32, 0x34, 0xd3, 0x88, 0x7d, 0x6f, 0xe8, 0xe0, 0x99,
-       0x65, 0x2e, 0xf3, 0xdf, 0xe7, 0x45, 0xe2, 0x4d, 0xe9, 0xcf, 0xf2, 0x9a,
-       0x71, 0xde, 0x7a, 0xcc, 0xe9, 0x07, 0x9d, 0x1b, 0xb1, 0x3e, 0xf7, 0xb8,
-       0xd2, 0x3c, 0x8e, 0x87, 0x2a, 0xf0, 0xa9, 0x3e, 0xbd, 0x57, 0xeb, 0x33,
-       0x33, 0xbd, 0x8d, 0xde, 0xfb, 0xf1, 0x1c, 0xc8, 0xf7, 0x31, 0xf0, 0x2d,
-       0x7d, 0x62, 0xf2, 0x4b, 0x4a, 0xcf, 0x61, 0x36, 0x4f, 0xfe, 0x0d, 0x69,
-       0x0e, 0x23, 0x03, 0xdb, 0xb2, 0x57, 0xe7, 0xc7, 0x96, 0xe5, 0xbb, 0x23,
-       0xa0, 0x71, 0x77, 0x26, 0xbf, 0x4a, 0x3a, 0x55, 0x07, 0x75, 0x78, 0xbc,
-       0x0d, 0x7b, 0xa1, 0x58, 0xee, 0x03, 0x72, 0xb4, 0xd8, 0x0f, 0x3a, 0xc4,
-       0xe4, 0x29, 0xf8, 0xcd, 0xcf, 0x14, 0xef, 0x90, 0xa5, 0x08, 0xf6, 0x55,
-       0x96, 0xb1, 0x41, 0xf9, 0xf1, 0xdc, 0x06, 0xef, 0x3a, 0xe1, 0x2e, 0x59,
-       0xdb, 0xb1, 0x07, 0xca, 0x13, 0xe5, 0x8a, 0xf3, 0x82, 0x88, 0x45, 0xb8,
-       0xee, 0x11, 0xa3, 0xdb, 0xb0, 0x6e, 0x21, 0x42, 0xf9, 0xe5, 0xde, 0x42,
-       0x9e, 0xcc, 0x32, 0xae, 0xe2, 0x3b, 0x1b, 0x9b, 0x94, 0xae, 0x3a, 0x8b,
-       0x84, 0xe2, 0x40, 0x97, 0xcf, 0xc0, 0x5f, 0xc7, 0x97, 0x4b, 0xff, 0x3b,
-       0x0a, 0xea, 0x51, 0xd8, 0xca, 0x3c, 0x6c, 0x65, 0x1e, 0x36, 0x12, 0xb2,
-       0xf0, 0x56, 0x1e, 0x36, 0x32, 0x0f, 0x1b, 0x09, 0x7d, 0xf6, 0x06, 0x62,
-       0xbb, 0xab, 0xe0, 0x21, 0xe3, 0x6b, 0x1f, 0xa6, 0xaf, 0x8d, 0xbf, 0xff,
-       0x01, 0x88, 0x97, 0xee, 0xe9, 0xc4, 0x71, 0x00, 0x00, 0x00 };
+       0xec, 0x5b, 0x5d, 0x70, 0x5c, 0xd7, 0x5d, 0xff, 0xdf, 0xb3, 0x2b, 0x69,
+       0x2d, 0x4b, 0xf2, 0x95, 0xbc, 0x71, 0x56, 0xa9, 0x92, 0xec, 0x5a, 0x57,
+       0xd2, 0xa6, 0x12, 0xe1, 0xca, 0x6c, 0x12, 0x75, 0xd8, 0x69, 0xb6, 0xbb,
+       0xb2, 0xa3, 0xb4, 0x66, 0x46, 0x49, 0x0d, 0xcd, 0xb4, 0x65, 0x10, 0xbb,
+       0x0e, 0xa4, 0x0f, 0x0c, 0xc6, 0x40, 0x26, 0x80, 0xc1, 0xcb, 0x4a, 0x71,
+       0x94, 0x74, 0xad, 0xdd, 0xda, 0x0a, 0x86, 0x69, 0x61, 0x94, 0xd5, 0x87,
+       0x53, 0x66, 0xad, 0x4d, 0xcb, 0x4b, 0x99, 0xd6, 0xb1, 0xea, 0xb8, 0x26,
+       0x0f, 0x3c, 0xa4, 0x94, 0xce, 0x64, 0x20, 0x33, 0x35, 0xb2, 0x63, 0xfb,
+       0x81, 0x8f, 0xc0, 0x4c, 0x49, 0x20, 0x6e, 0x2e, 0xbf, 0xdf, 0xb9, 0xf7,
+       0xca, 0x2b, 0x45, 0xd0, 0x3c, 0xf0, 0x78, 0xcf, 0x8c, 0xe6, 0xde, 0x7b,
+       0xce, 0xff, 0xfc, 0xcf, 0xff, 0xfb, 0xe3, 0xac, 0xfd, 0x3b, 0x1d, 0xd2,
+       0x2e, 0xde, 0xe8, 0xc4, 0x5f, 0xea, 0xc8, 0x33, 0x47, 0x47, 0xef, 0x1f,
+       0xbd, 0x9f, 0xdf, 0x21, 0xc3, 0x08, 0xf3, 0x69, 0x48, 0x30, 0x82, 0x11,
+       0x8c, 0x60, 0x04, 0x23, 0x18, 0xc1, 0x08, 0x46, 0x30, 0x82, 0x11, 0x8c,
+       0x60, 0x04, 0x23, 0x18, 0xc1, 0x08, 0x46, 0x30, 0x82, 0x11, 0x8c, 0x60,
+       0x04, 0x23, 0x18, 0xc1, 0x08, 0x46, 0x30, 0x82, 0x11, 0x8c, 0x60, 0x04,
+       0x23, 0x18, 0xc1, 0x08, 0x46, 0x30, 0x82, 0x11, 0x8c, 0x60, 0x04, 0x23,
+       0x18, 0xc1, 0x08, 0x46, 0x30, 0x82, 0x11, 0x8c, 0x60, 0x04, 0x23, 0x18,
+       0xc1, 0x08, 0x46, 0x30, 0xfe, 0x3f, 0x47, 0x48, 0xc4, 0xe4, 0xb3, 0xd3,
+       0xfb, 0x93, 0x88, 0x4a, 0xc7, 0x8f, 0x66, 0x2d, 0x89, 0x84, 0xd2, 0x97,
+       0x9e, 0x2e, 0x58, 0x22, 0x99, 0xfa, 0x70, 0x3c, 0x27, 0x3f, 0x71, 0x8a,
+       0xd1, 0xb0, 0x70, 0xfe, 0xee, 0xf4, 0xad, 0xe3, 0xe7, 0x1f, 0x4a, 0xbc,
+       0xb3, 0x10, 0x92, 0x88, 0x99, 0x7e, 0x63, 0xd4, 0x1c, 0x94, 0x48, 0x1f,
+       0xf6, 0x7c, 0x6d, 0x68, 0x6d, 0x97, 0x74, 0xf9, 0xb8, 0x44, 0x6a, 0xe5,
+       0x84, 0x7d, 0x40, 0x86, 0xcd, 0x8b, 0x12, 0x96, 0x0c, 0xce, 0x58, 0xa9,
+       0x8b, 0x94, 0xca, 0x06, 0x71, 0x48, 0xa9, 0x1e, 0x91, 0x2b, 0x21, 0x42,
+       0x7d, 0xcb, 0xc8, 0x56, 0x3e, 0x70, 0x32, 0x61, 0x9c, 0x6b, 0xe1, 0xbd,
+       0xe1, 0xcf, 0x47, 0x44, 0xa5, 0x13, 0xc9, 0x6c, 0x68, 0x42, 0x6a, 0xf3,
+       0x8e, 0x33, 0x63, 0x7f, 0x0c, 0x38, 0x7a, 0x64, 0xc6, 0x72, 0xbf, 0xb3,
+       0xf6, 0xc7, 0xcd, 0x71, 0xb9, 0x13, 0x73, 0x21, 0x51, 0xd6, 0x5d, 0xf8,
+       0x8b, 0x1b, 0xb9, 0xd3, 0x5f, 0x36, 0xb2, 0x8b, 0x1d, 0x52, 0xaa, 0x38,
+       0x52, 0xb0, 0x25, 0x93, 0xb5, 0x77, 0x60, 0xfd, 0x03, 0xa7, 0xb0, 0xb1,
+       0x67, 0xd8, 0xcc, 0x49, 0x8b, 0x64, 0xa2, 0x31, 0xc0, 0xcc, 0x1b, 0xb9,
+       0xb3, 0x7f, 0xdd, 0x21, 0xed, 0xa0, 0x27, 0xc5, 0xef, 0x0f, 0x9c, 0x90,
+       0x65, 0x61, 0x9d, 0xe7, 0xe3, 0xbb, 0x41, 0xbc, 0x7c, 0x27, 0xce, 0x2b,
+       0xce, 0xf9, 0xa1, 0x98, 0x7c, 0xb3, 0x11, 0x95, 0x6f, 0x34, 0x4c, 0x79,
+       0xa5, 0xd1, 0x27, 0x17, 0x1a, 0x8e, 0xf3, 0x0d, 0xdb, 0x71, 0xde, 0xc0,
+       0xdf, 0x7f, 0xd8, 0x1b, 0x3c, 0x60, 0x14, 0x8d, 0xf1, 0xc6, 0x57, 0x3b,
+       0xa4, 0x2b, 0x11, 0x17, 0xd5, 0x21, 0xd3, 0x95, 0x98, 0xcc, 0x54, 0xca,
+       0xc6, 0x63, 0x67, 0xe7, 0x8c, 0xc9, 0xb3, 0x55, 0x9c, 0x19, 0xc6, 0x9c,
+       0x14, 0x4b, 0xf6, 0xcb, 0x46, 0xae, 0x31, 0x6b, 0x3c, 0x7e, 0xb6, 0x0b,
+       0x34, 0xf2, 0xfc, 0x3d, 0x46, 0xf6, 0xf4, 0x2d, 0xc9, 0xda, 0x94, 0x71,
+       0xc2, 0xfc, 0x3c, 0xc4, 0x9e, 0x2d, 0x93, 0xe6, 0x56, 0x8f, 0x5e, 0xc7,
+       0x51, 0x69, 0xe7, 0x78, 0x36, 0x65, 0x99, 0x25, 0x21, 0x7d, 0x7a, 0xee,
+       0x82, 0x4b, 0xf3, 0x8a, 0x91, 0x3d, 0xdb, 0x61, 0xe4, 0xce, 0x84, 0x41,
+       0x87, 0xf4, 0x85, 0x84, 0xfb, 0x06, 0x62, 0x79, 0xa9, 0xe3, 0x0c, 0x31,
+       0x55, 0x9a, 0x72, 0x05, 0xcd, 0xa0, 0xe5, 0x9b, 0x15, 0xf0, 0x50, 0x01,
+       0x0f, 0x15, 0xf2, 0x16, 0x97, 0xf3, 0x43, 0x3e, 0x6f, 0x8e, 0xf3, 0x77,
+       0x36, 0x69, 0x4f, 0xc4, 0x33, 0xca, 0xe7, 0xd3, 0x71, 0xfe, 0xdd, 0x26,
+       0xaf, 0xe4, 0xc7, 0x71, 0x5e, 0xb1, 0x63, 0xa0, 0xdd, 0xb9, 0xa0, 0xac,
+       0x32, 0x78, 0xb1, 0x80, 0x9f, 0xb2, 0x9e, 0x03, 0x0f, 0xb3, 0xe0, 0x6f,
+       0x05, 0xbc, 0x55, 0x41, 0xc7, 0x4f, 0x3b, 0xaf, 0x68, 0xe4, 0x86, 0x36,
+       0xe4, 0x15, 0xa7, 0x8c, 0xf3, 0x4b, 0x0a, 0xb2, 0xde, 0x29, 0xf9, 0x05,
+       0x53, 0xa6, 0x96, 0xfc, 0xfd, 0xbe, 0x1d, 0x1c, 0x91, 0x83, 0x95, 0x1e,
+       0xc8, 0x86, 0xb2, 0x4c, 0xd8, 0x22, 0x0e, 0x64, 0x54, 0x4a, 0x2a, 0x11,
+       0x23, 0x6f, 0x1f, 0xd7, 0xfa, 0x5f, 0xb2, 0x24, 0x93, 0xb7, 0x29, 0x47,
+       0x89, 0xe7, 0xed, 0x62, 0x2c, 0x0c, 0x7b, 0x5b, 0xb2, 0x8a, 0x66, 0x58,
+       0x28, 0xc7, 0x44, 0xec, 0xf7, 0x21, 0xcb, 0x27, 0xcb, 0x92, 0xf9, 0x74,
+       0xd9, 0x97, 0xb1, 0x2b, 0xdf, 0xcf, 0x94, 0x3f, 0xd5, 0x29, 0xed, 0xea,
+       0x9e, 0x16, 0xf9, 0x0d, 0xec, 0x25, 0xee, 0x4d, 0x7b, 0xb1, 0xcf, 0x85,
+       0x73, 0xf7, 0x26, 0x9e, 0x10, 0x21, 0x6c, 0xa9, 0xbf, 0x45, 0xfb, 0x88,
+       0x18, 0x59, 0xab, 0x18, 0x0b, 0x01, 0x2e, 0x2f, 0xa5, 0x51, 0x6f, 0xae,
+       0x25, 0x6b, 0xdd, 0x0a, 0xcd, 0xd8, 0x89, 0x78, 0x49, 0x6e, 0x85, 0x2e,
+       0xdb, 0x7a, 0x6e, 0x47, 0xd6, 0x72, 0x64, 0x19, 0xd8, 0x9f, 0x83, 0x3f,
+       0x5c, 0x04, 0x47, 0x5f, 0x2a, 0xeb, 0xf9, 0x4e, 0xec, 0x4f, 0xb6, 0x00,
+       0x67, 0xbb, 0x24, 0x92, 0x35, 0xcc, 0x5f, 0x76, 0xe7, 0xbb, 0x5d, 0xbc,
+       0xa5, 0xfe, 0x76, 0x8d, 0x5b, 0xe4, 0x65, 0x77, 0xfe, 0x0e, 0x17, 0x77,
+       0xe9, 0x3e, 0xcc, 0x03, 0xff, 0xe0, 0xc4, 0x90, 0xa1, 0xe7, 0x7b, 0xe9,
+       0x4f, 0xbf, 0x5e, 0xbe, 0x15, 0x5a, 0xb6, 0x1d, 0xc9, 0x8d, 0x0e, 0x4e,
+       0x0c, 0x1a, 0x2e, 0xbe, 0x13, 0xee, 0xbe, 0xbb, 0x5d, 0x7c, 0x83, 0x13,
+       0x49, 0xc3, 0xc5, 0xb7, 0x54, 0xd6, 0x7b, 0x25, 0x5f, 0x26, 0xec, 0xe0,
+       0x84, 0x65, 0xdc, 0x2d, 0x53, 0xdd, 0x83, 0x13, 0x7b, 0x0d, 0x75, 0xcf,
+       0x4e, 0x97, 0x8f, 0x84, 0x4f, 0xc3, 0x4e, 0x4d, 0x03, 0xcf, 0xd5, 0xf3,
+       0x03, 0x59, 0xab, 0x74, 0xdf, 0x4e, 0x7d, 0x3e, 0xcf, 0xd4, 0x73, 0xf7,
+       0x91, 0x2e, 0x9e, 0x5d, 0x18, 0xdd, 0x74, 0xee, 0xcf, 0xdc, 0x96, 0xcf,
+       0x76, 0x67, 0xf2, 0x3c, 0x89, 0x84, 0xd3, 0xe1, 0xd1, 0x99, 0xf2, 0x11,
+       0xc9, 0x56, 0xe2, 0x32, 0x3d, 0xb2, 0x43, 0xa6, 0xcc, 0xfe, 0xa9, 0x83,
+       0xc2, 0xd8, 0x13, 0x19, 0x2d, 0x78, 0x3a, 0xcc, 0x89, 0x21, 0xd3, 0xe0,
+       0xf1, 0x60, 0x5d, 0x22, 0x06, 0xe0, 0xfb, 0xeb, 0x61, 0x79, 0xbe, 0x61,
+       0x48, 0xab, 0xf6, 0xcf, 0x84, 0xb9, 0x06, 0x3b, 0x7c, 0xb6, 0x42, 0x3b,
+       0xa6, 0xcd, 0x4a, 0xa6, 0x06, 0x3b, 0xbd, 0xa0, 0x7d, 0xb5, 0x9d, 0x7a,
+       0x2d, 0x16, 0x05, 0xae, 0x98, 0xb6, 0xcc, 0x9a, 0xb4, 0x49, 0x66, 0x52,
+       0x8a, 0x5c, 0xf7, 0x7c, 0x27, 0xb6, 0x28, 0xdf, 0x85, 0x0d, 0x88, 0x99,
+       0x4d, 0x71, 0x9e, 0xf0, 0x4d, 0xb0, 0xa6, 0xeb, 0x77, 0x21, 0xf8, 0x5d,
+       0x21, 0x45, 0x58, 0x29, 0xea, 0x58, 0xd1, 0x80, 0x2d, 0x36, 0xee, 0xee,
+       0x74, 0x63, 0x5d, 0x04, 0xfe, 0xd9, 0x01, 0x1f, 0xbf, 0x07, 0xfe, 0xd7,
+       0x67, 0x64, 0xcf, 0x38, 0x0e, 0x62, 0x4f, 0x54, 0x09, 0xfd, 0x0f, 0xbe,
+       0xde, 0xe0, 0x5a, 0x07, 0xe6, 0xc5, 0x9c, 0xb6, 0xbb, 0xc1, 0x9f, 0xe3,
+       0x4c, 0xd8, 0x71, 0x29, 0xd9, 0xbb, 0xb0, 0xaf, 0x45, 0xba, 0x2d, 0xda,
+       0x3b, 0x7d, 0x7a, 0x27, 0xce, 0x33, 0xf8, 0xdd, 0x85, 0xf3, 0x3a, 0x31,
+       0x17, 0x9b, 0xa6, 0x1f, 0xa7, 0x18, 0xb3, 0xdc, 0xf8, 0x29, 0x72, 0x15,
+       0xb4, 0x72, 0x8f, 0x86, 0x8b, 0xb4, 0xa5, 0x53, 0x72, 0xa3, 0xdc, 0x2b,
+       0x57, 0xa2, 0xe4, 0x1f, 0x38, 0x2b, 0x88, 0x87, 0x51, 0x03, 0xf4, 0x93,
+       0x6e, 0xc6, 0xbf, 0xdd, 0xde, 0xb7, 0x71, 0xaf, 0x7b, 0x86, 0x98, 0xa1,
+       0x74, 0x97, 0xe4, 0xf4, 0x9c, 0x28, 0x35, 0xba, 0xd3, 0x5b, 0xef, 0x32,
+       0x0e, 0x9c, 0x51, 0x32, 0xf4, 0x20, 0x62, 0x16, 0xce, 0xba, 0x6c, 0x39,
+       0xce, 0x65, 0xfb, 0xc7, 0xf0, 0x79, 0x25, 0x2d, 0xd6, 0x7a, 0x97, 0xb4,
+       0x43, 0x9e, 0x15, 0xa3, 0x49, 0x86, 0x31, 0x39, 0x51, 0xe1, 0x9e, 0xa2,
+       0x84, 0x2d, 0xc2, 0x10, 0xfe, 0x47, 0x80, 0x0b, 0x49, 0x1b, 0x7c, 0xf1,
+       0xa2, 0x1d, 0x25, 0xbd, 0xbb, 0x5c, 0xf8, 0x6e, 0x9c, 0x41, 0xda, 0xe9,
+       0x7b, 0x8e, 0xf6, 0xbd, 0x6c, 0x48, 0x65, 0xc6, 0xe7, 0xe1, 0x49, 0x23,
+       0x94, 0x77, 0xb6, 0x1b, 0xa1, 0x5f, 0xa6, 0x87, 0x8a, 0xa6, 0xd2, 0xba,
+       0x16, 0xc9, 0x95, 0xef, 0x95, 0x19, 0x1b, 0xe7, 0x59, 0x61, 0xd0, 0xcc,
+       0x38, 0x33, 0x50, 0x0c, 0x29, 0x78, 0x58, 0x0f, 0x65, 0xe5, 0xd3, 0xfa,
+       0x16, 0xce, 0x2b, 0x1a, 0x61, 0x8b, 0x67, 0xfc, 0xb2, 0x27, 0x1f, 0xda,
+       0x9d, 0x2d, 0xd9, 0x72, 0x07, 0xbf, 0x41, 0x47, 0xbb, 0xa6, 0x23, 0x94,
+       0xd6, 0xba, 0x33, 0x54, 0xda, 0x8f, 0xff, 0x04, 0xdd, 0x84, 0x07, 0x7c,
+       0x70, 0xaf, 0x85, 0xbd, 0x11, 0xd0, 0xd8, 0xd9, 0x44, 0x7f, 0x3b, 0xe1,
+       0x21, 0xab, 0x88, 0x77, 0x86, 0xe6, 0xdb, 0x70, 0xf9, 0xf6, 0x65, 0xf5,
+       0x2a, 0x64, 0xf5, 0xbe, 0x33, 0xb4, 0x8f, 0x38, 0x52, 0xc0, 0x01, 0xb9,
+       0x9b, 0x8c, 0x57, 0x8c, 0x51, 0xe6, 0x06, 0x2e, 0xf8, 0x81, 0x0a, 0xa5,
+       0x3b, 0x24, 0x67, 0xea, 0x1c, 0x00, 0xd8, 0x31, 0xd1, 0x31, 0xde, 0x22,
+       0x8f, 0xde, 0xb7, 0x95, 0xd0, 0x76, 0x93, 0xaf, 0x32, 0x0f, 0xfc, 0x31,
+       0x68, 0x5b, 0x4b, 0x28, 0xcd, 0x5a, 0x07, 0x64, 0x2e, 0x91, 0x96, 0xf4,
+       0x1b, 0xb2, 0x5c, 0x56, 0x7b, 0x5a, 0x65, 0x97, 0x4c, 0x42, 0x46, 0xb5,
+       0x31, 0xe4, 0xaf, 0x91, 0x0e, 0x09, 0xdd, 0xcf, 0x3c, 0x10, 0x03, 0xad,
+       0x6b, 0x09, 0x53, 0x6e, 0x39, 0x6a, 0x10, 0xfb, 0x47, 0xa0, 0x87, 0x43,
+       0xd4, 0xa9, 0xf2, 0xe0, 0x08, 0x13, 0xa2, 0xcc, 0x7b, 0x5a, 0x85, 0xb8,
+       0xb9, 0x36, 0x1c, 0x33, 0x85, 0xf3, 0xc8, 0x95, 0x93, 0xdc, 0x4b, 0xfe,
+       0xdc, 0x3d, 0x1f, 0xe6, 0xcf, 0x5f, 0xa7, 0xcc, 0x28, 0x3b, 0xd8, 0x18,
+       0x78, 0xcc, 0xda, 0xbf, 0xe0, 0xc9, 0xe6, 0x4e, 0xb9, 0x62, 0x8a, 0x51,
+       0xb3, 0xef, 0x68, 0x92, 0x1f, 0x79, 0xee, 0xde, 0xc2, 0x33, 0x71, 0x6c,
+       0xcf, 0xf7, 0xe1, 0x2a, 0xcf, 0x74, 0xcf, 0x9e, 0xb1, 0xd6, 0x12, 0x61,
+       0xd9, 0x2c, 0x5f, 0xe8, 0x52, 0x0a, 0x65, 0xda, 0x46, 0xab, 0xe4, 0x51,
+       0x8f, 0xd8, 0xfb, 0x10, 0x54, 0x1e, 0x57, 0x32, 0xfa, 0x20, 0x71, 0xfe,
+       0x23, 0x79, 0x1a, 0x8b, 0x2b, 0x43, 0xf2, 0x3a, 0xf7, 0xfb, 0xfa, 0xe2,
+       0x5c, 0xb3, 0x6d, 0xbf, 0xea, 0xd9, 0xf6, 0xfb, 0xce, 0xe8, 0x3e, 0x5f,
+       0xef, 0x90, 0xd7, 0x87, 0xf6, 0x08, 0xf4, 0xfc, 0x7f, 0xed, 0xa1, 0xad,
+       0x44, 0xb6, 0xec, 0x29, 0x6e, 0xb3, 0x67, 0xb7, 0xc8, 0x2f, 0xd1, 0x87,
+       0xba, 0xbd, 0x98, 0xe1, 0xfb, 0x94, 0x8f, 0x07, 0xba, 0xd1, 0xb6, 0xca,
+       0xb9, 0xed, 0x7c, 0x91, 0x38, 0x88, 0x8b, 0x7b, 0x09, 0xe3, 0xe7, 0x54,
+       0xa8, 0x43, 0xb6, 0xcd, 0xab, 0x18, 0x13, 0x78, 0x57, 0x88, 0x43, 0xcd,
+       0xf9, 0x95, 0x73, 0x26, 0xbe, 0xc7, 0xf1, 0xb4, 0x24, 0x5f, 0xa7, 0x3f,
+       0x71, 0x3f, 0xf3, 0xed, 0x4d, 0x2f, 0x7e, 0x76, 0x4c, 0x85, 0xd3, 0x51,
+       0xc4, 0x4f, 0x99, 0x2c, 0x95, 0x8f, 0xa3, 0x26, 0x92, 0xe2, 0x5d, 0x69,
+       0xda, 0x47, 0xc7, 0x18, 0x62, 0xe4, 0x64, 0xa9, 0xce, 0xba, 0x08, 0x61,
+       0x0c, 0xfb, 0x90, 0xa3, 0x23, 0x6a, 0x2e, 0x52, 0xfc, 0x58, 0x9a, 0x71,
+       0x39, 0x2e, 0xf1, 0xfa, 0x3b, 0xa8, 0x3b, 0x4c, 0xc9, 0x6a, 0x5b, 0xfb,
+       0xb3, 0x5e, 0xd2, 0x5b, 0x42, 0x0d, 0x11, 0x4e, 0x4b, 0x58, 0xa5, 0x5b,
+       0x23, 0xd3, 0xa9, 0x0e, 0xd4, 0x5a, 0x13, 0xbd, 0x6a, 0xf5, 0x60, 0x6f,
+       0x68, 0x75, 0xcf, 0x54, 0x4b, 0xba, 0xd8, 0xab, 0xe6, 0x44, 0x16, 0xcb,
+       0xa2, 0x50, 0xd7, 0xc4, 0x0e, 0x0b, 0xbe, 0x57, 0x3f, 0xfb, 0x59, 0x95,
+       0x0e, 0x41, 0xb7, 0x72, 0x6c, 0x29, 0x15, 0x66, 0x0d, 0x19, 0x9f, 0x94,
+       0x63, 0xa8, 0x1b, 0x9f, 0x91, 0xe9, 0x32, 0xe8, 0xd2, 0x7c, 0xc7, 0xc0,
+       0x6f, 0x1f, 0x70, 0x93, 0xf6, 0x28, 0x62, 0xac, 0x4b, 0x3b, 0x68, 0xce,
+       0xe4, 0x58, 0x27, 0xa5, 0x98, 0x57, 0xde, 0x81, 0xfd, 0xd0, 0x5f, 0xfe,
+       0x59, 0x96, 0xad, 0x1d, 0x92, 0x77, 0xe3, 0x03, 0xed, 0x15, 0x6b, 0x37,
+       0xbd, 0xb5, 0x6b, 0x58, 0xa3, 0xfd, 0xee, 0x6c, 0xd2, 0xe1, 0x97, 0x75,
+       0xad, 0x73, 0xd9, 0xe6, 0x3b, 0x61, 0xff, 0x76, 0xd4, 0x85, 0x7d, 0x7d,
+       0x74, 0xd9, 0xfa, 0xdc, 0x2e, 0x69, 0x37, 0xa9, 0x37, 0x9c, 0x13, 0x65,
+       0x8c, 0xc5, 0xfa, 0x15, 0x0f, 0xd7, 0x5b, 0xc0, 0xd5, 0x41, 0xba, 0x31,
+       0xc2, 0x58, 0x07, 0x7d, 0xa8, 0x79, 0xf2, 0x1b, 0xb1, 0x86, 0xb0, 0xdf,
+       0xf1, 0x70, 0x7d, 0xab, 0x09, 0x17, 0xd7, 0xf8, 0xe4, 0x99, 0x38, 0xbb,
+       0x9d, 0xbc, 0x91, 0x1f, 0xea, 0x80, 0xfa, 0x48, 0x1a, 0x93, 0x88, 0xed,
+       0x93, 0x0d, 0x5d, 0xdb, 0x19, 0xb9, 0x0a, 0x6a, 0xae, 0xc6, 0x8b, 0xa0,
+       0x11, 0xb5, 0x58, 0x63, 0xd0, 0xab, 0xb7, 0x69, 0x47, 0x6b, 0xda, 0x1e,
+       0x19, 0x77, 0x4a, 0xda, 0xae, 0x2e, 0xb9, 0x76, 0x65, 0x51, 0x37, 0x97,
+       0x64, 0x6f, 0xbd, 0xba, 0xcb, 0xfd, 0xbf, 0xdb, 0xa6, 0x84, 0xb4, 0x3e,
+       0x99, 0xdf, 0x68, 0x63, 0x77, 0x22, 0xae, 0x3b, 0xef, 0x32, 0xcf, 0x4c,
+       0x32, 0x07, 0x4d, 0x32, 0x77, 0x18, 0x5e, 0x3c, 0x8c, 0x37, 0xe1, 0x88,
+       0x03, 0xc7, 0x8a, 0x67, 0xbf, 0x73, 0x1e, 0x2e, 0xbf, 0xfe, 0xf4, 0x63,
+       0xea, 0x9f, 0xdf, 0xb5, 0x79, 0x5d, 0x99, 0xee, 0x77, 0xab, 0x8e, 0xc7,
+       0xb0, 0x75, 0xd0, 0x1f, 0x9f, 0x52, 0xb0, 0xaf, 0x5c, 0xdd, 0xd5, 0x07,
+       0x7c, 0x1f, 0xb6, 0xc7, 0x57, 0x5f, 0xb7, 0x6e, 0xfd, 0xed, 0xca, 0x80,
+       0x3a, 0xcd, 0x90, 0xef, 0x4c, 0x98, 0xb4, 0x34, 0x26, 0xb0, 0x5f, 0x8e,
+       0x30, 0x37, 0xe6, 0xc1, 0xc7, 0x61, 0x73, 0xd8, 0x9c, 0x26, 0xee, 0xa8,
+       0x00, 0x27, 0x6a, 0xc9, 0x74, 0x9b, 0xa7, 0xe7, 0x6f, 0xf3, 0x7c, 0xe0,
+       0xde, 0xc9, 0x6f, 0x3c, 0xbf, 0xed, 0xd1, 0x73, 0xa3, 0xcb, 0xa5, 0xc7,
+       0x5f, 0x1f, 0x34, 0x37, 0x7f, 0xaf, 0xf4, 0x7a, 0xf2, 0xc4, 0xfb, 0x33,
+       0x1e, 0x5d, 0xd4, 0x4d, 0x33, 0x4d, 0xd4, 0xcb, 0xbb, 0xc0, 0xa3, 0x6b,
+       0x8d, 0xa2, 0x4a, 0xa3, 0x76, 0x49, 0x31, 0x67, 0x25, 0xc6, 0x32, 0x62,
+       0x41, 0x27, 0x09, 0x7b, 0x0a, 0xbb, 0x6e, 0x96, 0xa9, 0xe7, 0x5b, 0x88,
+       0xd5, 0xd4, 0xfb, 0x7b, 0x32, 0x53, 0xee, 0xb7, 0x5b, 0x0d, 0xfa, 0x6b,
+       0x22, 0xb9, 0x22, 0xc3, 0xf6, 0x8a, 0xae, 0xa1, 0x12, 0xf1, 0x13, 0x42,
+       0xd9, 0xde, 0x92, 0x01, 0x5d, 0xdb, 0xbc, 0x27, 0x16, 0xe4, 0x32, 0x59,
+       0x81, 0x8f, 0xed, 0xfb, 0x57, 0x47, 0xd7, 0xa4, 0x08, 0x6f, 0xd7, 0xb7,
+       0xc1, 0xf5, 0xba, 0xc6, 0x43, 0x7c, 0xcd, 0xb8, 0x0c, 0x69, 0xdb, 0xe7,
+       0xe3, 0xb3, 0x64, 0xb6, 0xe1, 0xe3, 0x0c, 0x23, 0x2e, 0x23, 0x06, 0xec,
+       0xfb, 0xbc, 0x67, 0x2f, 0x7c, 0xff, 0xbe, 0xc3, 0x5a, 0x48, 0xa5, 0xbf,
+       0xea, 0xcd, 0x7d, 0x8f, 0x32, 0xc0, 0xb7, 0x2f, 0xf7, 0x17, 0xbd, 0x78,
+       0x53, 0x34, 0x32, 0x0d, 0xca, 0x80, 0xb6, 0x02, 0xfd, 0x6b, 0xfb, 0x84,
+       0xcf, 0x54, 0x3e, 0x89, 0x98, 0xd5, 0xed, 0xd6, 0x0f, 0xe8, 0xaf, 0x32,
+       0x0d, 0xce, 0xad, 0xb5, 0x65, 0xed, 0x16, 0xcf, 0x97, 0x0e, 0x62, 0x6e,
+       0x12, 0x7f, 0x94, 0x1d, 0x61, 0x0e, 0xe1, 0x3d, 0xe3, 0xc1, 0xc9, 0x58,
+       0x16, 0xb9, 0x2b, 0x73, 0x68, 0x1c, 0xdf, 0x86, 0xd7, 0x67, 0x69, 0xb9,
+       0x57, 0x51, 0xab, 0x40, 0x9e, 0x03, 0xe0, 0x27, 0x2e, 0xe3, 0x0d, 0xe8,
+       0x7c, 0x23, 0x9e, 0x6d, 0xc0, 0x14, 0x6f, 0xc3, 0xb8, 0xb1, 0x6f, 0xbc,
+       0xf1, 0xa6, 0xc3, 0x78, 0xf0, 0x57, 0xda, 0x5f, 0xe2, 0xa0, 0xdd, 0xef,
+       0xd5, 0x32, 0xc6, 0x63, 0x95, 0x09, 0xe3, 0xf1, 0x0a, 0xf7, 0xa8, 0xaf,
+       0xf5, 0x88, 0x15, 0xcf, 0x2a, 0xd4, 0xa9, 0xfb, 0xba, 0x70, 0xe6, 0x09,
+       0xd8, 0x46, 0xd1, 0x98, 0x1c, 0xda, 0x25, 0xf9, 0x64, 0x0f, 0x68, 0x7e,
+       0x08, 0xcf, 0x56, 0xcc, 0xff, 0x3c, 0xe6, 0x61, 0x47, 0x49, 0xfa, 0xc7,
+       0x0e, 0xdd, 0x5b, 0x4e, 0x99, 0xa4, 0x71, 0xc0, 0xb3, 0xad, 0x37, 0x4d,
+       0xd7, 0x96, 0x9e, 0xc6, 0xf7, 0x4e, 0xcc, 0x7f, 0x01, 0x4f, 0xe4, 0xb2,
+       0x7d, 0xfe, 0x3c, 0x7d, 0x70, 0x0c, 0xf3, 0x0f, 0x00, 0xc7, 0x1f, 0xe0,
+       0xfd, 0x5e, 0xbc, 0xff, 0xde, 0x96, 0xbd, 0xbf, 0xcb, 0xb3, 0x31, 0x9f,
+       0xdd, 0x32, 0xef, 0xc7, 0x6f, 0x9e, 0x27, 0xd2, 0xbd, 0x0a, 0xc6, 0x57,
+       0x23, 0xb2, 0x7b, 0xa5, 0x5d, 0x54, 0xcd, 0x8d, 0xe1, 0xaa, 0x66, 0x4a,
+       0xcf, 0x0a, 0xe3, 0xf7, 0x0f, 0xb0, 0xc7, 0x12, 0xb5, 0x0a, 0xa5, 0x51,
+       0xb7, 0xda, 0x47, 0x9f, 0x39, 0xba, 0x77, 0x81, 0xcf, 0xe2, 0xd1, 0xd1,
+       0x3a, 0x61, 0xf8, 0x7e, 0xec, 0xe8, 0xde, 0xfa, 0x3f, 0x00, 0x16, 0x72,
+       0xa9, 0xf8, 0xf8, 0x09, 0x7f, 0x7e, 0xcb, 0x99, 0x5a, 0xb6, 0x38, 0x93,
+       0x7e, 0xff, 0xcc, 0xd1, 0x6c, 0x95, 0x75, 0x42, 0x22, 0x26, 0xba, 0x16,
+       0x2f, 0x1e, 0x2d, 0x20, 0x3f, 0x86, 0x34, 0x2d, 0xfe, 0x3a, 0xd7, 0xa8,
+       0x87, 0xed, 0x68, 0x23, 0x5d, 0xcd, 0x78, 0x98, 0x67, 0x88, 0xe7, 0x18,
+       0xf0, 0x24, 0x81, 0x87, 0xf9, 0xc6, 0xa5, 0x37, 0xbe, 0xb0, 0x1d, 0x6d,
+       0xc4, 0xc5, 0xb3, 0x7c, 0x7c, 0x3d, 0xa2, 0x56, 0x7e, 0x48, 0x7a, 0x4d,
+       0xd6, 0xb6, 0x6e, 0xac, 0x69, 0x91, 0xfc, 0x69, 0xe6, 0xec, 0x7d, 0xde,
+       0x37, 0xca, 0x18, 0xf4, 0xdc, 0x71, 0xc5, 0x79, 0x3e, 0xb1, 0x96, 0x62,
+       0xb9, 0x82, 0xef, 0x45, 0x1f, 0x56, 0x79, 0xb0, 0x9d, 0x4d, 0x7c, 0xb7,
+       0x78, 0xb2, 0xe6, 0x99, 0x7e, 0xef, 0xd9, 0x4c, 0x0b, 0x40, 0xa1, 0x87,
+       0xee, 0x0d, 0x3d, 0xf8, 0x7c, 0x62, 0x61, 0x95, 0xb4, 0x25, 0xc1, 0xab,
+       0x4f, 0xdb, 0x47, 0xd5, 0x1f, 0xf7, 0x26, 0xf1, 0xe7, 0x9f, 0xe7, 0xcb,
+       0x80, 0x74, 0xf1, 0x09, 0x5b, 0xfe, 0x50, 0xef, 0x9c, 0x84, 0xdf, 0xf1,
+       0x1e, 0xc4, 0x71, 0x96, 0x6d, 0xca, 0xbe, 0x0d, 0x7a, 0x27, 0x2f, 0x06,
+       0x7a, 0x09, 0xc5, 0x9a, 0x2e, 0xce, 0x9e, 0xf5, 0x49, 0xb9, 0x0a, 0x5c,
+       0x19, 0xf4, 0x95, 0x6e, 0x6f, 0x34, 0x85, 0xf8, 0xb8, 0x06, 0xfb, 0xbc,
+       0x6c, 0xf1, 0x3e, 0x26, 0xcc, 0x7c, 0x27, 0xa5, 0xfa, 0xbf, 0x00, 0x86,
+       0xf5, 0xd5, 0xed, 0xbb, 0x96, 0x05, 0xc0, 0x2c, 0x62, 0xed, 0x84, 0x1b,
+       0x97, 0x19, 0xdb, 0x1d, 0x85, 0xda, 0xa3, 0x60, 0xfd, 0xb7, 0xc3, 0x3a,
+       0xeb, 0x36, 0xec, 0x76, 0x77, 0x21, 0xc8, 0x39, 0xf3, 0x89, 0xd9, 0x05,
+       0xc4, 0xf0, 0xaa, 0xa5, 0x76, 0x2b, 0x6d, 0x91, 0x89, 0x2a, 0x62, 0x12,
+       0xba, 0xde, 0x44, 0x7c, 0x41, 0xfe, 0x53, 0xeb, 0xa1, 0xc5, 0x1a, 0x36,
+       0x7b, 0xd4, 0xe7, 0x68, 0x57, 0x9a, 0xf2, 0xd0, 0x29, 0xe4, 0xe5, 0x91,
+       0xc7, 0x90, 0x73, 0x20, 0xaf, 0x53, 0x45, 0x74, 0xf2, 0xb4, 0x91, 0x37,
+       0x7e, 0xab, 0x60, 0xb9, 0x7d, 0x80, 0xce, 0x67, 0xe2, 0xf2, 0x18, 0x3a,
+       0xd5, 0xa1, 0xe3, 0x4c, 0x5e, 0xc7, 0x9b, 0x7e, 0x73, 0x52, 0xb5, 0xa3,
+       0xc6, 0x40, 0x01, 0x8a, 0x0a, 0xc7, 0x1c, 0x14, 0xd9, 0x3b, 0x87, 0xb8,
+       0x82, 0x38, 0xbc, 0x77, 0x15, 0xd1, 0xed, 0x14, 0xe1, 0x95, 0x84, 0x4f,
+       0x85, 0xa4, 0xe5, 0x14, 0xef, 0x43, 0x64, 0x0f, 0xfa, 0x31, 0xe2, 0xdc,
+       0x1b, 0xc6, 0x73, 0x1c, 0x7f, 0xfb, 0x51, 0x5b, 0x99, 0xa8, 0x91, 0xb7,
+       0x81, 0x07, 0x2c, 0xf7, 0x6c, 0x07, 0x6f, 0x76, 0x4b, 0x7b, 0x04, 0x7b,
+       0x08, 0x1f, 0x06, 0x1d, 0x7b, 0x40, 0x8f, 0x7b, 0x3e, 0x71, 0x84, 0x4f,
+       0x89, 0xf4, 0xcf, 0x49, 0x8f, 0xd2, 0x7b, 0xc2, 0x52, 0x48, 0x71, 0xad,
+       0x03, 0xf0, 0xdc, 0x87, 0x35, 0xbd, 0xcf, 0xbd, 0x57, 0xca, 0xdf, 0xa6,
+       0x1b, 0x73, 0x06, 0xde, 0x51, 0x4f, 0xa5, 0x4c, 0xe9, 0xaf, 0xb9, 0xb0,
+       0x7b, 0x57, 0xbf, 0xd4, 0xcd, 0xbb, 0x29, 0x65, 0xb9, 0xb4, 0x29, 0xd4,
+       0xc4, 0x79, 0x48, 0x35, 0x3c, 0xc8, 0xfb, 0x19, 0xc2, 0xb0, 0xaf, 0x35,
+       0x35, 0x8c, 0x39, 0x48, 0xf9, 0xb9, 0x73, 0x4a, 0xfd, 0x6f, 0xf7, 0x2e,
+       0xcd, 0x35, 0x85, 0xf6, 0x15, 0xec, 0xff, 0x43, 0xed, 0x2b, 0xa2, 0xe2,
+       0x9e, 0xaf, 0xe0, 0x7b, 0x91, 0xdf, 0x7e, 0x2e, 0xfe, 0xed, 0xbb, 0xdc,
+       0x78, 0xef, 0xc8, 0xb4, 0xcd, 0x3b, 0x0c, 0x47, 0x2e, 0xdb, 0x45, 0xe3,
+       0x91, 0x4d, 0x75, 0x66, 0x52, 0xe7, 0xe7, 0x02, 0x64, 0xbf, 0x5e, 0xd7,
+       0x3d, 0x9b, 0x5c, 0xa9, 0x47, 0xe4, 0xea, 0x52, 0xbb, 0xac, 0x2f, 0xb8,
+       0x36, 0xbf, 0xbe, 0x40, 0x3b, 0x37, 0xe5, 0xed, 0x25, 0x0b, 0x6b, 0x49,
+       0xfc, 0xf5, 0xc8, 0xf5, 0xa5, 0xcd, 0x75, 0xe7, 0x85, 0xc6, 0xc3, 0xa0,
+       0xa5, 0x47, 0x42, 0x96, 0xa3, 0xfb, 0xaf, 0x1c, 0x72, 0x5f, 0x51, 0xc6,
+       0x25, 0x5f, 0xe9, 0x47, 0x0f, 0x88, 0xe4, 0x1c, 0x66, 0x0e, 0x82, 0xfe,
+       0x2b, 0x9f, 0x40, 0x6d, 0x92, 0x80, 0xf3, 0xf4, 0xeb, 0x7b, 0xc5, 0x4f,
+       0x85, 0x7b, 0xa4, 0xd5, 0xfa, 0xa3, 0x6e, 0x37, 0x57, 0x99, 0x6e, 0x9f,
+       0x6a, 0xf9, 0xf9, 0xfa, 0x75, 0xe0, 0x1e, 0x81, 0x9d, 0xd2, 0x36, 0x6d,
+       0xd8, 0xac, 0x29, 0xcb, 0x43, 0x89, 0x6a, 0x51, 0x18, 0x1f, 0x52, 0x38,
+       0xd3, 0xc0, 0xbe, 0x24, 0xe4, 0xb1, 0x43, 0xd7, 0x42, 0x19, 0x05, 0xdd,
+       0xce, 0xcd, 0x48, 0xbe, 0xf1, 0x9b, 0x98, 0xcf, 0xc8, 0x54, 0x63, 0x0c,
+       0x67, 0x9d, 0xa4, 0xdd, 0xf6, 0x48, 0x3b, 0xcf, 0x49, 0x81, 0xc6, 0x87,
+       0xa4, 0x70, 0x7a, 0x46, 0x0e, 0x57, 0x48, 0x27, 0xef, 0x19, 0x13, 0xc9,
+       0x9c, 0x0c, 0xc7, 0x97, 0x50, 0x3b, 0xb9, 0xfe, 0x98, 0x96, 0xc2, 0x19,
+       0xe0, 0xa8, 0xf0, 0x1e, 0xa0, 0x1f, 0x76, 0x33, 0xac, 0xfb, 0x9a, 0x29,
+       0x1d, 0x77, 0x38, 0xff, 0x43, 0xe8, 0xa9, 0xbf, 0xb8, 0x1f, 0x70, 0x79,
+       0xf4, 0x40, 0x93, 0xa8, 0x97, 0x17, 0x2b, 0xe8, 0xf7, 0xec, 0x10, 0x6b,
+       0x2f, 0xa5, 0xee, 0xef, 0x93, 0x5a, 0x65, 0xd8, 0x54, 0x8a, 0x35, 0x15,
+       0x75, 0xc1, 0x35, 0xfa, 0x77, 0x4c, 0x85, 0xad, 0x3e, 0x59, 0xaa, 0x14,
+       0xd1, 0x37, 0x2b, 0xef, 0x5e, 0x03, 0x16, 0x60, 0xb9, 0x71, 0x2f, 0xa3,
+       0xc8, 0x37, 0xea, 0xcf, 0xc6, 0x27, 0x41, 0x63, 0x26, 0x6e, 0xca, 0x71,
+       0xd0, 0x87, 0xf7, 0x45, 0xd8, 0xf8, 0x1c, 0x6b, 0xb8, 0x0c, 0xd6, 0xd2,
+       0x72, 0xe4, 0xec, 0x24, 0x68, 0xe8, 0x92, 0xfe, 0x3f, 0xa1, 0x8f, 0x3d,
+       0x81, 0x39, 0x7e, 0x27, 0x60, 0xaf, 0x5f, 0xc4, 0x3b, 0x61, 0x63, 0x78,
+       0x52, 0x0e, 0x7d, 0x78, 0x9a, 0xa0, 0x25, 0xe2, 0xf6, 0x26, 0x87, 0xe2,
+       0x52, 0x3b, 0xfd, 0xa0, 0x4c, 0x2d, 0x3e, 0x08, 0xfc, 0x3f, 0x42, 0x5f,
+       0x80, 0xfc, 0xb6, 0xc8, 0xb3, 0x58, 0xff, 0xf1, 0x9c, 0x9d, 0x3d, 0xda,
+       0x37, 0xe6, 0x38, 0xcf, 0xe7, 0x41, 0xec, 0x47, 0x8f, 0x51, 0xc9, 0x48,
+       0xa1, 0xc2, 0xb3, 0xa0, 0x3b, 0xd4, 0x53, 0xf9, 0xd3, 0x93, 0x9e, 0x8e,
+       0x7b, 0x24, 0x17, 0x2d, 0xb2, 0xbf, 0x40, 0x9e, 0x58, 0x18, 0xcd, 0x96,
+       0x13, 0x66, 0x56, 0x11, 0x57, 0x52, 0x98, 0x1b, 0xdc, 0xb9, 0x88, 0x58,
+       0x73, 0xe8, 0x6d, 0xd3, 0x5c, 0x3b, 0xee, 0xdd, 0x1d, 0x10, 0xd7, 0x9b,
+       0x32, 0x0e, 0x1b, 0xeb, 0x9f, 0x1b, 0x41, 0x2d, 0xfc, 0x16, 0x6a, 0xc9,
+       0x84, 0x27, 0x83, 0x31, 0xcf, 0x36, 0xda, 0x9b, 0x6c, 0x02, 0x7a, 0xae,
+       0x40, 0xf7, 0x15, 0xd8, 0x01, 0x62, 0xf5, 0x2b, 0x1b, 0xf6, 0x31, 0xd6,
+       0x54, 0x63, 0x76, 0xca, 0xdf, 0x54, 0x13, 0xc9, 0x35, 0xd8, 0xcf, 0x75,
+       0xf4, 0x02, 0x6b, 0xe8, 0x55, 0xd7, 0xd1, 0xd7, 0x2d, 0x96, 0x0f, 0x81,
+       0x7e, 0xd6, 0x94, 0xfc, 0x8e, 0xe9, 0x5a, 0xa7, 0xcd, 0x7a, 0xe1, 0x2e,
+       0x7d, 0xb7, 0x2b, 0x4f, 0xf4, 0xb0, 0xd7, 0x64, 0x5f, 0xce, 0x7b, 0xe9,
+       0xab, 0xd0, 0xe3, 0x9a, 0xc9, 0x75, 0x7f, 0x1f, 0x7b, 0x01, 0xdf, 0x7e,
+       0x48, 0x0b, 0xed, 0x87, 0x7b, 0x08, 0xd3, 0xa3, 0xfd, 0x24, 0xaf, 0xf1,
+       0xd1, 0x66, 0xeb, 0xdd, 0xae, 0x9f, 0xe9, 0x3a, 0xcb, 0xbc, 0x22, 0xbe,
+       0xfd, 0xbe, 0xe7, 0xb0, 0xaf, 0xcb, 0x0e, 0x21, 0x76, 0x37, 0x1c, 0x79,
+       0xc1, 0xde, 0xec, 0x77, 0x07, 0x2a, 0xbe, 0x9c, 0x28, 0xc7, 0x43, 0x72,
+       0xa2, 0x91, 0x80, 0x4f, 0x50, 0x86, 0x56, 0x93, 0x0c, 0x45, 0xbe, 0x5e,
+       0x11, 0x79, 0xb9, 0xc2, 0x35, 0x2d, 0xc3, 0x58, 0x36, 0xd4, 0xce, 0xbb,
+       0x75, 0xd8, 0xe5, 0xdf, 0xcb, 0xe1, 0x79, 0x91, 0xb3, 0x58, 0x5f, 0xae,
+       0xd0, 0x57, 0x47, 0x50, 0xbf, 0xee, 0x94, 0xda, 0x02, 0x7a, 0xb2, 0x8a,
+       0x4c, 0x65, 0x1f, 0x60, 0xbe, 0x89, 0xc8, 0xba, 0xbe, 0x93, 0x15, 0x19,
+       0x3c, 0x17, 0x96, 0xf0, 0x39, 0x34, 0x7f, 0x90, 0xfd, 0xf9, 0x21, 0xff,
+       0x8e, 0xd6, 0xf5, 0xf9, 0x52, 0x19, 0x7b, 0x2b, 0xfd, 0x3a, 0x4e, 0x96,
+       0xea, 0x05, 0xc9, 0x57, 0x79, 0x16, 0x9e, 0x0b, 0x71, 0xac, 0xa5, 0x64,
+       0xfa, 0xf4, 0x88, 0x3c, 0x8b, 0x33, 0xd0, 0xff, 0xe1, 0x8c, 0x71, 0x29,
+       0x9e, 0xc5, 0x7c, 0xfd, 0x9a, 0x2c, 0x2c, 0x15, 0xa4, 0x56, 0xbd, 0xd0,
+       0x74, 0xf7, 0x8e, 0xef, 0x85, 0xe6, 0x5e, 0xf6, 0x10, 0xfb, 0x19, 0xf4,
+       0xaa, 0x16, 0xbe, 0x21, 0xb3, 0xfa, 0xf4, 0xd4, 0xe6, 0x3b, 0xe3, 0xe6,
+       0x1e, 0x76, 0x42, 0x66, 0x2b, 0x29, 0x29, 0x9d, 0x1e, 0xd1, 0x77, 0x0d,
+       0x6d, 0xe9, 0xea, 0xd3, 0x37, 0x90, 0x2b, 0x26, 0xf4, 0x9d, 0xf1, 0x2d,
+       0x79, 0xd4, 0x9e, 0x95, 0x27, 0xad, 0x83, 0x72, 0x02, 0xf5, 0xf5, 0xa7,
+       0xd1, 0xeb, 0xc7, 0xbb, 0xa9, 0x47, 0xd0, 0x6b, 0xb1, 0x07, 0x75, 0x64,
+       0xdc, 0xfe, 0xb8, 0xf9, 0x3c, 0x24, 0x7b, 0xb5, 0xce, 0x3c, 0xf9, 0x5f,
+       0x4e, 0x06, 0x79, 0xef, 0x06, 0x7a, 0xc7, 0x8c, 0x86, 0x33, 0x5c, 0xb8,
+       0x2a, 0xe1, 0x86, 0xcd, 0x17, 0x08, 0xb7, 0x60, 0x78, 0x70, 0x06, 0xe0,
+       0x42, 0x72, 0xd1, 0x0e, 0xc3, 0x46, 0x26, 0xc0, 0x27, 0x62, 0xfc, 0x68,
+       0xa7, 0x57, 0x07, 0xef, 0x40, 0x6e, 0xbd, 0xbd, 0xff, 0x35, 0x6f, 0xff,
+       0xb3, 0xde, 0xfe, 0xcb, 0x1b, 0xfb, 0xfd, 0xfc, 0xfa, 0x13, 0x47, 0x9a,
+       0xe8, 0x7a, 0xad, 0xec, 0xc2, 0xcf, 0x7a, 0x74, 0x5d, 0xde, 0xa0, 0xcb,
+       0x87, 0x87, 0x3c, 0x35, 0xcf, 0x8c, 0xcd, 0x8c, 0xd1, 0xfd, 0x90, 0xa3,
+       0x23, 0x39, 0x1b, 0xbe, 0x51, 0x49, 0x8c, 0x15, 0xf5, 0x9d, 0x9a, 0x92,
+       0xb5, 0xe8, 0xac, 0x4c, 0x58, 0x89, 0xb1, 0x69, 0x09, 0xc1, 0x96, 0x19,
+       0x5b, 0x42, 0x52, 0x63, 0xcc, 0xc1, 0x33, 0x6f, 0x6f, 0x4f, 0xeb, 0xd5,
+       0x26, 0x5a, 0x43, 0x2f, 0x91, 0x46, 0x97, 0xd6, 0xc8, 0xc0, 0x6d, 0x5a,
+       0x5d, 0x78, 0x97, 0xd6, 0xab, 0xe5, 0x26, 0xf8, 0x73, 0x61, 0x0f, 0x3e,
+       0xdc, 0x04, 0x4f, 0x7b, 0x66, 0x5d, 0x41, 0x7b, 0x26, 0x6d, 0x3f, 0x0b,
+       0xdf, 0x90, 0xc8, 0x8e, 0x74, 0xf5, 0xe8, 0x7d, 0x03, 0x8e, 0x44, 0x50,
+       0x6f, 0xb4, 0x62, 0x6d, 0xbd, 0xca, 0x5a, 0x44, 0xed, 0x6d, 0x95, 0x41,
+       0xd8, 0x2c, 0x75, 0xe7, 0xde, 0x0d, 0x3e, 0xaa, 0x6b, 0x02, 0x47, 0x9e,
+       0xb4, 0x49, 0xcb, 0x8f, 0x9d, 0x97, 0xa3, 0x83, 0x76, 0x49, 0x86, 0xcc,
+       0x56, 0x9c, 0x5f, 0x6b, 0x68, 0x9c, 0x49, 0xd2, 0xb2, 0x32, 0xd4, 0x6f,
+       0x7e, 0x0f, 0x7c, 0x8e, 0x57, 0x0d, 0xa9, 0x59, 0x89, 0xd8, 0x79, 0xe0,
+       0xd8, 0x0f, 0xdd, 0xd4, 0x46, 0x48, 0x8f, 0xc8, 0x61, 0xd8, 0x77, 0x4d,
+       0xe7, 0x45, 0xda, 0x71, 0x62, 0xa2, 0x88, 0x5a, 0xe7, 0x2f, 0x75, 0x6e,
+       0x73, 0x9c, 0x1b, 0xc8, 0x6f, 0x13, 0x5b, 0x6c, 0x4f, 0x9d, 0x73, 0x6d,
+       0x4f, 0x9d, 0x43, 0x0f, 0x7c, 0x32, 0x22, 0x6d, 0xcb, 0xf0, 0x9f, 0x97,
+       0xf6, 0xb8, 0xf5, 0xdc, 0x4b, 0xfc, 0xdd, 0x09, 0xf1, 0xee, 0x64, 0x58,
+       0xac, 0x93, 0x3a, 0x1f, 0x40, 0xde, 0xe3, 0x32, 0x7d, 0x86, 0x31, 0xd5,
+       0x92, 0x81, 0x93, 0xd4, 0x07, 0xeb, 0x9a, 0x85, 0xd1, 0x02, 0x7c, 0x64,
+       0x06, 0x71, 0x41, 0x2d, 0xdf, 0x94, 0x82, 0x45, 0x39, 0x74, 0x49, 0xfb,
+       0x32, 0xfa, 0xf1, 0x65, 0xc4, 0x86, 0xe5, 0x98, 0xb4, 0xc0, 0xb7, 0xd4,
+       0xb9, 0xa8, 0x51, 0x9a, 0x7f, 0x17, 0xfe, 0xc0, 0xdf, 0x70, 0x50, 0x5b,
+       0x9e, 0x8b, 0x19, 0xf4, 0x2d, 0x75, 0x8e, 0x76, 0x8e, 0x72, 0xea, 0x1c,
+       0xed, 0x9c, 0x74, 0xf8, 0xfe, 0x82, 0xf7, 0x73, 0x23, 0xfa, 0x9e, 0xfa,
+       0x86, 0x4d, 0x5e, 0x7e, 0x20, 0xd9, 0x2a, 0x6b, 0x44, 0xf2, 0x23, 0xdd,
+       0xa8, 0x65, 0x76, 0x65, 0xed, 0x81, 0xb1, 0x75, 0xf9, 0xa8, 0x7c, 0xdd,
+       0xf9, 0x11, 0xf8, 0x22, 0x1f, 0xcd, 0x7c, 0x91, 0xa7, 0x2e, 0x69, 0xd1,
+       0x7c, 0xf9, 0xfc, 0x40, 0xd0, 0xe0, 0x67, 0xef, 0xc9, 0x18, 0xf0, 0x7f,
+       0x11, 0x31, 0xa0, 0x0f, 0xcf, 0x27, 0xf0, 0x44, 0x4a, 0x3b, 0x47, 0xde,
+       0xc9, 0xeb, 0x75, 0xd4, 0x8d, 0x3e, 0x9f, 0x53, 0x78, 0x7f, 0x55, 0xa6,
+       0xe7, 0x9d, 0xe3, 0xc8, 0xab, 0xbc, 0x43, 0xef, 0x71, 0xef, 0x83, 0xb7,
+       0xf2, 0xfe, 0xaa, 0xb8, 0xf2, 0x49, 0x98, 0x35, 0xc1, 0xfb, 0xd2, 0x56,
+       0x59, 0x34, 0xc7, 0x8e, 0x98, 0xae, 0xc3, 0x0f, 0xd7, 0x19, 0x27, 0x28,
+       0xa3, 0xeb, 0x92, 0x9d, 0xe7, 0xfd, 0x97, 0x8b, 0x6f, 0xaa, 0xee, 0xc7,
+       0x8d, 0xe6, 0x3d, 0x36, 0xe0, 0xfa, 0x00, 0x47, 0xba, 0xd6, 0x28, 0x3f,
+       0xc4, 0x9c, 0xde, 0xa6, 0x58, 0xd3, 0xbc, 0x6f, 0x4c, 0x9e, 0x43, 0x1d,
+       0xf0, 0x9a, 0xbd, 0x49, 0xae, 0x53, 0xac, 0x85, 0x6a, 0xf5, 0x49, 0xf8,
+       0x64, 0x0b, 0x62, 0x99, 0x29, 0xeb, 0xe5, 0x56, 0xa9, 0xa1, 0xde, 0x59,
+       0x5c, 0x62, 0x2c, 0x24, 0xed, 0xed, 0x98, 0x77, 0xe3, 0x17, 0x63, 0xed,
+       0x7a, 0x19, 0x79, 0x16, 0xbe, 0xbd, 0x5e, 0x8e, 0xe2, 0xd9, 0x87, 0xa7,
+       0x85, 0x67, 0x1c, 0xcf, 0x24, 0x9e, 0x23, 0x78, 0x8e, 0xe0, 0x69, 0x61,
+       0x6f, 0x0c, 0x4f, 0xbf, 0x67, 0x20, 0xae, 0xdb, 0x7c, 0x97, 0xf4, 0x79,
+       0xa8, 0x15, 0x2d, 0xe6, 0xb4, 0xb0, 0x9d, 0x43, 0x1f, 0x91, 0x1d, 0x61,
+       0xad, 0xc7, 0x9a, 0xef, 0x03, 0xc7, 0xb4, 0xd8, 0x97, 0x17, 0x8d, 0xfd,
+       0x43, 0xcc, 0x0b, 0x55, 0xe4, 0x85, 0xf7, 0x76, 0xa3, 0x7f, 0x34, 0x0f,
+       0xe8, 0xbb, 0xa3, 0x79, 0x7c, 0xf3, 0x1d, 0x3d, 0x6f, 0x74, 0x06, 0x79,
+       0x8a, 0xf1, 0xd3, 0xc1, 0x9e, 0x3c, 0xe2, 0xf8, 0x2e, 0xf8, 0x5f, 0x06,
+       0x71, 0x1b, 0xef, 0x0b, 0x97, 0x76, 0xbb, 0x39, 0x15, 0xf9, 0x56, 0x6d,
+       0xbd, 0xaf, 0xb1, 0xb1, 0x67, 0xbb, 0xde, 0xa0, 0x13, 0x38, 0x12, 0xd5,
+       0x05, 0xf8, 0xe0, 0xf7, 0xed, 0xe3, 0xba, 0xb6, 0xa3, 0x2e, 0x9e, 0x45,
+       0x8d, 0x9a, 0x9b, 0x63, 0x0d, 0x73, 0x0c, 0x7d, 0x09, 0xfa, 0xb3, 0x28,
+       0x7b, 0x72, 0xe6, 0x02, 0x5d, 0x8b, 0x46, 0xa5, 0x9d, 0x79, 0xe0, 0x06,
+       0xce, 0x03, 0x5f, 0x8b, 0x0e, 0x64, 0xf6, 0x08, 0x6a, 0x42, 0xc7, 0x09,
+       0x5b, 0xfb, 0x25, 0xfe, 0x38, 0x63, 0x8e, 0x60, 0xbf, 0x29, 0xee, 0xbd,
+       0x3a, 0xe2, 0xee, 0xa4, 0xfe, 0xbd, 0x18, 0xc6, 0x65, 0x63, 0xef, 0x1d,
+       0xc0, 0xc5, 0x79, 0xde, 0x69, 0x8b, 0xec, 0x9f, 0x73, 0x6b, 0x5a, 0x65,
+       0x35, 0xe3, 0xfb, 0x39, 0x0f, 0x1f, 0xd7, 0x95, 0xf7, 0xdb, 0xc6, 0x1e,
+       0xc8, 0x08, 0xfe, 0x00, 0x1d, 0x9f, 0x40, 0xfd, 0x7c, 0x11, 0x7a, 0x79,
+       0x0d, 0x3a, 0xb9, 0x54, 0xa6, 0xad, 0x0f, 0xc3, 0xee, 0x21, 0xc3, 0x49,
+       0xe2, 0x1a, 0xd1, 0x67, 0x5f, 0x2c, 0x23, 0x76, 0x32, 0xfe, 0xa9, 0x5f,
+       0x8d, 0xb2, 0x3e, 0x64, 0x1e, 0x74, 0xf1, 0xf4, 0xb9, 0x70, 0xe2, 0xaf,
+       0xed, 0xd6, 0xf4, 0xd4, 0xf4, 0x3d, 0x18, 0xe5, 0x04, 0x1b, 0xe4, 0x6f,
+       0x04, 0x1a, 0xe6, 0x0b, 0x51, 0x7d, 0x0f, 0xaf, 0x38, 0x47, 0x3e, 0x46,
+       0x24, 0x3b, 0xe7, 0xef, 0xeb, 0xc6, 0xbe, 0x1d, 0x4d, 0xb8, 0xee, 0xdc,
+       0xc2, 0x83, 0xf2, 0x78, 0xe0, 0xfa, 0xd6, 0xba, 0x3f, 0x61, 0x16, 0x37,
+       0xee, 0x86, 0x99, 0x7f, 0xa9, 0x9b, 0x14, 0xf6, 0xfb, 0xfa, 0xe9, 0xf3,
+       0x7a, 0x81, 0xc4, 0x6c, 0x51, 0x58, 0xab, 0x50, 0x47, 0x63, 0xf0, 0x6b,
+       0x13, 0xf8, 0x6d, 0xa9, 0x96, 0xdb, 0x44, 0xf5, 0xb0, 0x37, 0x66, 0xad,
+       0xdc, 0x7c, 0xe6, 0xaf, 0x78, 0x67, 0xa2, 0x9f, 0x3e, 0xc5, 0xba, 0x59,
+       0xe7, 0x19, 0xc0, 0x74, 0x6c, 0xa1, 0xed, 0x17, 0x3d, 0x38, 0xae, 0x27,
+       0xa5, 0x88, 0x3a, 0x34, 0x37, 0x87, 0x8a, 0x1e, 0xf1, 0x5b, 0xa5, 0xf9,
+       0xbb, 0x16, 0xef, 0xf0, 0x86, 0xe3, 0xd3, 0xa0, 0xb1, 0x68, 0x66, 0x78,
+       0x6f, 0x06, 0x1c, 0xbd, 0x5b, 0x70, 0x8c, 0x7b, 0x38, 0xc6, 0xa5, 0x74,
+       0x66, 0x02, 0xbe, 0x96, 0x41, 0x7e, 0xef, 0x37, 0x1f, 0x91, 0x4f, 0xa0,
+       0xb9, 0xc6, 0xdc, 0xd9, 0x11, 0xe8, 0xc9, 0x71, 0xf6, 0xdb, 0x87, 0x40,
+       0xf7, 0x77, 0x90, 0x5b, 0xfd, 0x9a, 0xa7, 0x14, 0x0b, 0x21, 0x87, 0x1d,
+       0xd1, 0xbf, 0xc3, 0x16, 0x4d, 0x13, 0xf6, 0xaa, 0x8c, 0xe1, 0x24, 0xda,
+       0x7b, 0xe4, 0xb7, 0x59, 0xe4, 0x2a, 0xf2, 0xd9, 0x29, 0x25, 0xd3, 0x78,
+       0x38, 0x84, 0xba, 0x26, 0x3b, 0x47, 0x3f, 0x92, 0x81, 0x50, 0xba, 0x15,
+       0x35, 0xa9, 0x23, 0x6f, 0xdb, 0xfc, 0x77, 0x0a, 0xb3, 0x72, 0xb1, 0x6e,
+       0xe2, 0xf9, 0x5d, 0xe8, 0xe1, 0x4f, 0xf1, 0xfe, 0x76, 0x0f, 0xea, 0x3e,
+       0xac, 0x64, 0x60, 0xbb, 0x49, 0x5d, 0xcf, 0xb0, 0x8e, 0xa8, 0x21, 0xdf,
+       0x2a, 0xe4, 0x1a, 0xd4, 0x55, 0x63, 0xac, 0x5d, 0x9f, 0x5b, 0xbc, 0x26,
+       0x97, 0xe6, 0xf9, 0x3b, 0x28, 0xf3, 0xf2, 0x41, 0xc6, 0x03, 0x73, 0x26,
+       0x85, 0xb9, 0x25, 0xc6, 0x32, 0x7c, 0x37, 0xe0, 0x40, 0x3d, 0xa8, 0x11,
+       0x50, 0x6b, 0xaf, 0x5b, 0x49, 0xf0, 0x79, 0x4d, 0x2e, 0xce, 0x87, 0x65,
+       0xd1, 0x62, 0x5d, 0x24, 0xf1, 0x2c, 0x60, 0x2f, 0x2e, 0xfd, 0x93, 0x6b,
+       0x13, 0x84, 0x47, 0xcf, 0x53, 0x44, 0x5d, 0xf7, 0x88, 0xde, 0xfb, 0xd3,
+       0xf4, 0x4c, 0x9a, 0x9a, 0xfb, 0xbc, 0x82, 0x5c, 0xa4, 0x3f, 0xe9, 0xdf,
+       0x28, 0x58, 0x1b, 0x1c, 0x83, 0xcd, 0xb2, 0x76, 0x67, 0x3f, 0x80, 0xf7,
+       0x3a, 0xd7, 0xc9, 0x3b, 0x9e, 0x0b, 0xfd, 0x90, 0x0d, 0xfd, 0x9e, 0x77,
+       0x62, 0xc8, 0xa3, 0x8a, 0xbe, 0x5e, 0xd2, 0xb1, 0xa0, 0x54, 0x29, 0x20,
+       0xa7, 0x20, 0x06, 0xd8, 0xbd, 0xb0, 0xc5, 0x49, 0xe8, 0x72, 0x0c, 0x70,
+       0x5b, 0x72, 0xc9, 0x6a, 0x49, 0xd7, 0x65, 0x6a, 0xe5, 0xf6, 0xfd, 0x4d,
+       0x1e, 0xfe, 0xa3, 0x56, 0x61, 0x5b, 0xf0, 0x21, 0xb5, 0x1a, 0xc5, 0x13,
+       0xf1, 0x78, 0x15, 0xfd, 0x45, 0x99, 0xf7, 0x43, 0xe8, 0x0d, 0xca, 0xbc,
+       0x3b, 0x49, 0xe2, 0x39, 0xc2, 0xfb, 0x22, 0x2f, 0xae, 0x11, 0x3f, 0xe9,
+       0xf0, 0xe3, 0x0b, 0x6b, 0x49, 0xc6, 0x17, 0xbf, 0x9e, 0x74, 0x6d, 0xe1,
+       0x44, 0x85, 0x31, 0x84, 0x76, 0xdd, 0x8f, 0xb8, 0x45, 0x5b, 0x70, 0x6b,
+       0xc9, 0xa5, 0xaa, 0x2b, 0xb3, 0xe9, 0xc6, 0x05, 0x9d, 0x23, 0x0e, 0x88,
+       0x05, 0x1b, 0xa3, 0xec, 0xb0, 0xa6, 0x73, 0xc0, 0x79, 0xc9, 0xe8, 0x27,
+       0x65, 0xf6, 0xaa, 0x64, 0x96, 0x46, 0xe4, 0x05, 0x1d, 0xb7, 0xfc, 0x98,
+       0xc5, 0x1a, 0x92, 0xbf, 0x1f, 0x27, 0xe5, 0xf9, 0xd3, 0xd7, 0x24, 0xfb,
+       0x22, 0xe3, 0xd6, 0x70, 0x6c, 0x87, 0xc1, 0x58, 0xe5, 0x48, 0x1d, 0xb9,
+       0xe9, 0x11, 0x9b, 0xff, 0x16, 0x20, 0x84, 0x9e, 0xce, 0x91, 0xd6, 0xd1,
+       0x84, 0x1d, 0x37, 0xfa, 0x9f, 0xd8, 0x61, 0x30, 0x37, 0x0e, 0x9b, 0x4f,
+       0x89, 0x7f, 0x1f, 0xd5, 0x26, 0x4f, 0xe9, 0xbb, 0x0a, 0xb8, 0xed, 0xdc,
+       0xfb, 0xfa, 0x77, 0x94, 0x1b, 0x29, 0xca, 0x1a, 0xdf, 0xab, 0x9c, 0x2f,
+       0x46, 0x6e, 0xa4, 0x5a, 0xa4, 0x74, 0x87, 0xe3, 0x3c, 0x39, 0xfa, 0xc0,
+       0x6e, 0xf7, 0xdf, 0x8b, 0x3c, 0x7d, 0x87, 0x1b, 0x0b, 0x7e, 0xcd, 0xfb,
+       0xfe, 0x3a, 0x9e, 0xb4, 0x6d, 0xe6, 0x5b, 0xe6, 0x47, 0xea, 0x0d, 0xcf,
+       0x25, 0xbe, 0x33, 0xf7, 0xce, 0x22, 0xf7, 0x32, 0x5f, 0xee, 0x92, 0x1c,
+       0x7f, 0xe7, 0x53, 0x7a, 0xbe, 0xe8, 0xd6, 0xd2, 0x1e, 0x5c, 0x75, 0x4a,
+       0xa6, 0xab, 0xac, 0xa1, 0x2e, 0x22, 0x97, 0x0d, 0xc1, 0x56, 0x99, 0xd3,
+       0x8e, 0x23, 0x9f, 0xf3, 0xf7, 0x69, 0xac, 0x2d, 0x70, 0x5f, 0x22, 0x19,
+       0x57, 0xcd, 0xbf, 0x2b, 0xdd, 0x8c, 0xf2, 0x3e, 0xea, 0xfc, 0x10, 0xf4,
+       0xfe, 0x15, 0xf6, 0x16, 0x03, 0xda, 0x46, 0xb2, 0x2f, 0x51, 0xf6, 0xee,
+       0xef, 0xd7, 0xd2, 0xed, 0xfa, 0x00, 0xeb, 0x80, 0xcf, 0x40, 0x2e, 0x07,
+       0xec, 0x6b, 0xcc, 0xdd, 0xff, 0xa6, 0xac, 0xe1, 0xe4, 0x53, 0x06, 0x7d,
+       0x1b, 0xdf, 0x4b, 0x21, 0x59, 0x88, 0x92, 0x7f, 0xc8, 0xcb, 0xa0, 0xef,
+       0x6c, 0x27, 0x87, 0xad, 0x32, 0xf8, 0x0b, 0xc8, 0x80, 0xb2, 0xf4, 0x65,
+       0xc0, 0xf7, 0x09, 0xe8, 0x8b, 0x3d, 0x43, 0xbf, 0xee, 0x23, 0x4b, 0x0d,
+       0xf7, 0xec, 0x52, 0xa5, 0x99, 0x66, 0xd2, 0x4b, 0x9d, 0x9e, 0x97, 0x9c,
+       0xd6, 0xef, 0xac, 0xe4, 0xaa, 0xe7, 0x65, 0x7f, 0x75, 0x56, 0x1e, 0xb5,
+       0x1e, 0x06, 0xbf, 0x57, 0x9c, 0x82, 0xa5, 0x7b, 0x95, 0xb1, 0x3c, 0xce,
+       0x2e, 0x8c, 0xf4, 0xca, 0x4d, 0xd4, 0x1d, 0xcf, 0x2e, 0x9a, 0xf2, 0x3f,
+       0x9d, 0x5b, 0x5f, 0x6c, 0x5b, 0xd5, 0x19, 0xff, 0x7c, 0x6d, 0x27, 0x69,
+       0x68, 0xc2, 0xad, 0xeb, 0x24, 0x6e, 0x9a, 0x51, 0x3b, 0xbe, 0x6d, 0x23,
+       0x92, 0xa2, 0xdb, 0x10, 0x68, 0xd4, 0x65, 0x8a, 0x71, 0x42, 0x17, 0xb6,
+       0x22, 0xd2, 0xae, 0xab, 0x2a, 0x8d, 0x81, 0xe5, 0xa6, 0x7f, 0xd8, 0xc3,
+       0x0a, 0x85, 0x75, 0x08, 0x21, 0xd5, 0xb8, 0xe9, 0xd6, 0x69, 0x21, 0x4e,
+       0xff, 0x2d, 0x8c, 0x87, 0xcd, 0x4a, 0xd2, 0x96, 0x4d, 0x11, 0x2e, 0x88,
+       0xb2, 0x3d, 0x6c, 0xa3, 0x4a, 0x01, 0xed, 0x79, 0x7b, 0x99, 0x34, 0x36,
+       0x65, 0x05, 0x36, 0x5e, 0x36, 0xf5, 0x81, 0x07, 0xa6, 0xd1, 0x79, 0xbf,
+       0xdf, 0x77, 0xee, 0x75, 0x6c, 0x13, 0x84, 0xb4, 0x48, 0x91, 0xef, 0x39,
+       0xf7, 0xdc, 0x73, 0xce, 0x3d, 0xdf, 0xff, 0xef, 0xfb, 0xdd, 0x8c, 0x3d,
+       0x28, 0x3f, 0xd2, 0x5c, 0x3e, 0xe3, 0x93, 0x00, 0x7c, 0x52, 0x83, 0x2d,
+       0x90, 0x36, 0x27, 0x76, 0x53, 0xe8, 0x53, 0x86, 0x41, 0xeb, 0xb8, 0xf1,
+       0x9b, 0x6d, 0x73, 0x7f, 0xcb, 0x59, 0xf8, 0xee, 0xee, 0x7d, 0x6d, 0x7e,
+       0xce, 0xd7, 0xf8, 0xb7, 0x7f, 0xf2, 0x6a, 0x68, 0x83, 0x32, 0x83, 0xfd,
+       0xbc, 0xa1, 0x7a, 0xd6, 0x01, 0x2f, 0x31, 0x37, 0x1d, 0xd3, 0xfc, 0x43,
+       0x78, 0x9a, 0x3a, 0xea, 0x2a, 0x74, 0xd4, 0x10, 0x75, 0xd7, 0xf0, 0xbc,
+       0xcb, 0xfc, 0x40, 0x54, 0xfe, 0x38, 0x45, 0x3d, 0x1c, 0x97, 0x3f, 0x4c,
+       0x3d, 0x8b, 0xfd, 0x24, 0x8a, 0xcc, 0x51, 0xde, 0x98, 0xc9, 0xd1, 0x4f,
+       0x52, 0x7f, 0x3e, 0xed, 0x3e, 0xad, 0x76, 0x20, 0x6e, 0xe5, 0xd7, 0x87,
+       0x55, 0xdf, 0x1c, 0xd3, 0xda, 0x6e, 0xdc, 0xea, 0x92, 0x1b, 0x17, 0x8c,
+       0x8e, 0x0d, 0x4f, 0x47, 0x03, 0x23, 0x0b, 0xb4, 0x4b, 0xc9, 0x58, 0xd6,
+       0x6a, 0x94, 0x43, 0x51, 0xe6, 0x9e, 0x53, 0xd4, 0xcf, 0xb0, 0x85, 0xbd,
+       0x76, 0xd6, 0x6a, 0xf2, 0xec, 0x4f, 0xac, 0x4e, 0xcf, 0x1e, 0xf3, 0xf4,
+       0x2c, 0xef, 0xa5, 0x68, 0x03, 0x20, 0x93, 0x89, 0x99, 0x51, 0x2b, 0x09,
+       0x9b, 0x87, 0xeb, 0x45, 0xce, 0x1f, 0x97, 0xe3, 0x8b, 0x47, 0xe1, 0x7f,
+       0xf7, 0xda, 0x7b, 0x69, 0x57, 0xed, 0x21, 0xe2, 0x71, 0xb0, 0xfe, 0x97,
+       0xea, 0xe6, 0x7a, 0xd4, 0x9b, 0x8b, 0xf7, 0x21, 0xe7, 0xd3, 0xac, 0xd7,
+       0x36, 0x32, 0x9f, 0xa3, 0x7b, 0xad, 0x1d, 0xbb, 0xa7, 0xb2, 0xee, 0x64,
+       0xc1, 0xf1, 0xb0, 0x61, 0xf8, 0x85, 0x2f, 0xf4, 0x8d, 0x08, 0xd7, 0xe4,
+       0x7a, 0xad, 0x92, 0xde, 0x0f, 0xfd, 0x32, 0xcd, 0xff, 0x9c, 0x57, 0xbb,
+       0x42, 0xbc, 0x12, 0xed, 0x5c, 0xc5, 0x36, 0x7d, 0xc5, 0x9b, 0xaf, 0xbf,
+       0x5d, 0x9a, 0xa3, 0x55, 0xe3, 0x99, 0x5b, 0x61, 0x3b, 0x2e, 0xb9, 0x45,
+       0xfe, 0x96, 0xcb, 0x11, 0xa7, 0x41, 0xf6, 0xda, 0x1b, 0xeb, 0xe6, 0xd8,
+       0x86, 0x3e, 0xe3, 0x13, 0x04, 0xa7, 0x03, 0x9e, 0x6f, 0xb1, 0x89, 0x7e,
+       0x93, 0x77, 0xdd, 0xa4, 0x39, 0x99, 0xb8, 0xd5, 0x59, 0xf7, 0x1e, 0x9b,
+       0x2a, 0x76, 0x38, 0x6e, 0x51, 0x77, 0x36, 0x46, 0xa5, 0x95, 0x3c, 0x54,
+       0x56, 0x3f, 0x3e, 0xe4, 0x18, 0xcc, 0x45, 0xd4, 0x39, 0xd2, 0xce, 0x9c,
+       0xfd, 0x5b, 0x7a, 0x6e, 0x2d, 0xf4, 0x09, 0x70, 0x0d, 0x3e, 0xf9, 0x4c,
+       0xbe, 0x97, 0xb9, 0x5e, 0xcc, 0xdf, 0xcc, 0xf9, 0x5d, 0xef, 0x9c, 0x13,
+       0x6e, 0xce, 0xba, 0x5f, 0xb2, 0x17, 0x0c, 0xff, 0xa5, 0x1d, 0xf0, 0x5e,
+       0x2b, 0xda, 0x0b, 0xb4, 0x09, 0x9f, 0x37, 0x8f, 0x6f, 0x1b, 0x7a, 0xd4,
+       0x36, 0x9c, 0x2a, 0x90, 0x3f, 0xc9, 0x97, 0x3e, 0x3f, 0xfa, 0x3a, 0x8f,
+       0x3c, 0x4a, 0x3d, 0x3b, 0x28, 0x67, 0x0b, 0x3c, 0x9b, 0x94, 0xd6, 0xb4,
+       0x36, 0x9f, 0x3b, 0xa8, 0x98, 0xac, 0xee, 0xe9, 0xc4, 0x4b, 0x39, 0x19,
+       0x96, 0xab, 0x2e, 0xcf, 0x2c, 0x51, 0xcc, 0x04, 0x5b, 0xaa, 0xde, 0x7f,
+       0xbf, 0x9e, 0x59, 0x58, 0x7d, 0xc6, 0x18, 0xc6, 0x3e, 0xef, 0xd1, 0xbb,
+       0x55, 0xcf, 0x36, 0x53, 0x43, 0x9f, 0xaf, 0xeb, 0x39, 0x85, 0xa1, 0x13,
+       0x59, 0xdf, 0x0f, 0x47, 0xf8, 0x0c, 0xd7, 0xa5, 0xcf, 0xc7, 0xb5, 0xc8,
+       0x7b, 0xdd, 0xb0, 0xd8, 0xfd, 0x12, 0xdc, 0x09, 0xd1, 0xdf, 0xc9, 0x3a,
+       0x72, 0x00, 0xb2, 0xba, 0xd9, 0x60, 0x60, 0xc6, 0x8d, 0xaf, 0x91, 0xb1,
+       0xae, 0xe1, 0x1c, 0x11, 0xab, 0xc0, 0x8f, 0x3e, 0xf5, 0x93, 0xdb, 0x98,
+       0x2f, 0xe3, 0xf9, 0xeb, 0x03, 0x98, 0xdf, 0xf1, 0xea, 0xea, 0x53, 0xdb,
+       0xc9, 0xab, 0xa3, 0x5a, 0x1f, 0xe4, 0x33, 0x94, 0x63, 0x9e, 0x19, 0xe9,
+       0xf2, 0x1e, 0x9e, 0x67, 0x7b, 0x5b, 0x1d, 0x1d, 0x93, 0xde, 0xfe, 0xfc,
+       0xfb, 0x61, 0x09, 0xb7, 0x53, 0xc7, 0x45, 0x25, 0x39, 0xcd, 0x98, 0x05,
+       0xb6, 0x6b, 0x9c, 0x73, 0x7d, 0xb1, 0x2e, 0xce, 0xfc, 0x9f, 0xba, 0x38,
+       0x63, 0x7d, 0xa4, 0xbc, 0x13, 0xd6, 0x3c, 0xd6, 0xe7, 0xd3, 0xb5, 0x58,
+       0x43, 0x57, 0xbf, 0x76, 0x1f, 0xad, 0xd0, 0xf1, 0x87, 0x05, 0xda, 0xab,
+       0x94, 0xe6, 0x94, 0xff, 0x3e, 0xc5, 0xb3, 0xe5, 0x1e, 0xaf, 0x72, 0x8f,
+       0xc3, 0x4b, 0x8a, 0x83, 0x7c, 0x58, 0x65, 0xf8, 0x74, 0x81, 0x3a, 0xa6,
+       0x45, 0xe6, 0x67, 0x7c, 0x3d, 0x33, 0xe6, 0xf9, 0xb8, 0xf9, 0xf5, 0x0d,
+       0xaa, 0x67, 0xe0, 0xdd, 0x38, 0x23, 0x9e, 0x7d, 0xe9, 0x92, 0xb9, 0x0b,
+       0xb4, 0xbb, 0x49, 0xf4, 0x45, 0x03, 0x73, 0x0b, 0xac, 0x4d, 0x12, 0x8b,
+       0x32, 0x2c, 0xac, 0xfb, 0x8f, 0xd8, 0xa7, 0x20, 0x6f, 0x31, 0x79, 0x7f,
+       0x8a, 0x3e, 0x7d, 0x03, 0x7c, 0xe3, 0xd6, 0xba, 0xf3, 0xdd, 0x51, 0xf1,
+       0x09, 0x6b, 0xe9, 0x1e, 0xef, 0x90, 0x66, 0xf2, 0xb9, 0x63, 0xdf, 0x10,
+       0xfa, 0x60, 0xbc, 0xce, 0x22, 0x16, 0x60, 0xec, 0x11, 0xd7, 0xd8, 0x63,
+       0xae, 0xc8, 0xbe, 0x16, 0x2f, 0xaf, 0xd4, 0xa2, 0xbc, 0x42, 0x7e, 0xcb,
+       0xa8, 0xff, 0x3d, 0xa4, 0x3a, 0x2b, 0x3f, 0xd5, 0x6b, 0x70, 0x2c, 0x76,
+       0x4c, 0x79, 0x4f, 0x6a, 0x78, 0x2f, 0xe6, 0xad, 0x3d, 0xd6, 0x61, 0x7c,
+       0x2b, 0x5b, 0xf5, 0x4d, 0x58, 0xc7, 0xd1, 0xae, 0x70, 0x7e, 0xf2, 0x06,
+       0x79, 0x84, 0x3a, 0xcf, 0x1f, 0xe7, 0xd3, 0xc3, 0x6f, 0x73, 0x3c, 0xf9,
+       0xbf, 0x1a, 0x8b, 0xe0, 0xcb, 0xaa, 0xdf, 0xe7, 0xcb, 0x1d, 0xef, 0x55,
+       0xdb, 0x04, 0xca, 0x5d, 0x75, 0x7d, 0xd2, 0x96, 0xc8, 0xf4, 0x0a, 0x5d,
+       0xd2, 0xfd, 0xdc, 0xff, 0xf3, 0xcc, 0xed, 0x42, 0xde, 0x56, 0xa3, 0xcd,
+       0x09, 0xa5, 0x4d, 0x06, 0xb4, 0x89, 0x28, 0x6d, 0x18, 0xef, 0x3d, 0xe5,
+       0xf1, 0x5b, 0x0b, 0xce, 0x8b, 0xb9, 0x5a, 0xe8, 0xba, 0x7d, 0xd4, 0xf9,
+       0xcf, 0x76, 0x68, 0x7d, 0xd0, 0xa1, 0xee, 0x5b, 0x0b, 0x7d, 0xc6, 0xf6,
+       0x56, 0xf5, 0x47, 0x4c, 0xbc, 0x15, 0xd7, 0x3c, 0x68, 0x10, 0xfa, 0x79,
+       0x6e, 0x0a, 0xbe, 0x1a, 0x71, 0x6f, 0x35, 0xb4, 0xfa, 0x8e, 0x77, 0x5e,
+       0xf3, 0x4a, 0x1b, 0xca, 0x00, 0xf5, 0xe6, 0x3a, 0xcc, 0xb7, 0x27, 0xda,
+       0x07, 0xfe, 0xfa, 0x19, 0xfa, 0x37, 0x6b, 0x3c, 0x11, 0x84, 0xcc, 0xdf,
+       0x9c, 0x6a, 0xf7, 0x62, 0x38, 0x07, 0x6d, 0xc4, 0xad, 0x53, 0x11, 0xc6,
+       0x14, 0x68, 0xf7, 0x48, 0xc3, 0x34, 0xe2, 0x57, 0xe8, 0xf1, 0x25, 0xb5,
+       0x47, 0x7d, 0xb8, 0x7f, 0x07, 0x71, 0x7e, 0xb8, 0x3e, 0x8a, 0xe7, 0x7a,
+       0x0d, 0x16, 0x21, 0xba, 0x45, 0xcf, 0x74, 0x6e, 0x2a, 0x11, 0x3b, 0x2c,
+       0x5e, 0xdf, 0xb8, 0xab, 0xfa, 0x60, 0x65, 0x5f, 0x0f, 0xca, 0x9e, 0x8a,
+       0xbd, 0x60, 0x1c, 0x0d, 0x1f, 0x7e, 0xc6, 0xd8, 0x83, 0x7c, 0xb1, 0x4f,
+       0xf1, 0x51, 0xc1, 0xa1, 0x45, 0x9c, 0x25, 0x7d, 0xd2, 0x65, 0xf8, 0xe1,
+       0x2e, 0xce, 0x90, 0x7e, 0x77, 0xf9, 0xe4, 0xa4, 0x9b, 0x62, 0x7d, 0x0c,
+       0xfa, 0xe0, 0xa4, 0x8c, 0x20, 0x2e, 0x18, 0x09, 0xb6, 0x32, 0xaf, 0x0c,
+       0xdf, 0x30, 0xe7, 0xe5, 0x1e, 0xfb, 0x98, 0x33, 0x95, 0x73, 0x0b, 0xdc,
+       0x3b, 0x65, 0xdb, 0xc4, 0xde, 0x73, 0x53, 0xdc, 0xaf, 0xc9, 0x43, 0xb0,
+       0x6d, 0x4d, 0xbb, 0xf8, 0xe5, 0x59, 0x0c, 0xe0, 0x77, 0x10, 0xf2, 0xc0,
+       0xb1, 0xf8, 0x5d, 0x58, 0x96, 0x77, 0x2f, 0xf8, 0xb6, 0x3d, 0x20, 0x6f,
+       0x3b, 0xe5, 0x93, 0xa7, 0xdc, 0xf5, 0x3c, 0x03, 0x37, 0xc7, 0x9a, 0xb5,
+       0xe3, 0xb8, 0x79, 0x29, 0x97, 0x97, 0xdc, 0xa5, 0xf5, 0x96, 0xd2, 0x92,
+       0xf2, 0xbf, 0x8c, 0x33, 0xbc, 0x7e, 0xaf, 0x25, 0x86, 0x7e, 0xa4, 0xcd,
+       0x67, 0x6b, 0x7f, 0xd5, 0xb6, 0xc0, 0xd7, 0x7f, 0xe4, 0x47, 0xf2, 0xe5,
+       0xb2, 0xec, 0x52, 0xfd, 0xbf, 0xda, 0x73, 0xd5, 0xba, 0xdf, 0xf7, 0x6f,
+       0xa9, 0xdf, 0xb5, 0xfe, 0xa3, 0xf1, 0xc1, 0x96, 0xe9, 0x7a, 0x9d, 0xf0,
+       0x98, 0x57, 0x57, 0x58, 0x8d, 0xf7, 0x0e, 0x78, 0x7a, 0x21, 0xa5, 0xbe,
+       0x73, 0xca, 0xa6, 0x7e, 0xe0, 0x7e, 0x9a, 0xe5, 0xe0, 0xec, 0x6d, 0xd0,
+       0xc4, 0xd7, 0xc1, 0x8c, 0xfb, 0x7c, 0xdd, 0xd1, 0xea, 0xf9, 0xc2, 0x96,
+       0x74, 0x9f, 0xa3, 0xef, 0xe4, 0x40, 0x8f, 0xb6, 0x49, 0x66, 0x3c, 0x28,
+       0xc9, 0x73, 0x1b, 0x62, 0xc6, 0xd7, 0x25, 0xff, 0x41, 0xde, 0xb4, 0x4f,
+       0x7d, 0x51, 0xf4, 0xdf, 0x29, 0x5c, 0xdb, 0xf0, 0x33, 0xe4, 0x79, 0x9f,
+       0x7f, 0xcf, 0xae, 0xe3, 0xd1, 0x9d, 0x1e, 0x8f, 0xf2, 0xbe, 0x65, 0xea,
+       0x1f, 0x18, 0xdb, 0x7d, 0x8e, 0x7b, 0x34, 0xcf, 0x75, 0x9f, 0x33, 0xf1,
+       0x7a, 0xed, 0x73, 0x7d, 0x95, 0xe7, 0x70, 0xbf, 0x47, 0xb1, 0x61, 0x98,
+       0x7b, 0xd7, 0x20, 0x7c, 0xba, 0x3e, 0xda, 0x1c, 0xda, 0xef, 0xcd, 0xee,
+       0x2e, 0x21, 0xbf, 0x27, 0x3c, 0x9e, 0xa3, 0xbe, 0x89, 0x78, 0xfa, 0x66,
+       0xc5, 0xbe, 0x8c, 0x18, 0xfc, 0x09, 0x73, 0x22, 0x55, 0xf6, 0xe5, 0x71,
+       0xf3, 0x6e, 0x35, 0xf6, 0xe5, 0x4e, 0x6f, 0x1e, 0xff, 0x9e, 0xaf, 0x57,
+       0xfc, 0xb6, 0xaf, 0x57, 0xea, 0x7d, 0x5a, 0x9f, 0xf6, 0xb5, 0xb8, 0xaf,
+       0xea, 0x98, 0x2f, 0xbf, 0x6a, 0xde, 0x25, 0x8b, 0x98, 0x8d, 0x3e, 0x65,
+       0x22, 0x67, 0x30, 0xd3, 0xd6, 0x59, 0x8b, 0xb8, 0x0f, 0xe7, 0xc7, 0x92,
+       0x8e, 0xdc, 0xd6, 0xd8, 0xfa, 0xf4, 0xec, 0x98, 0xe6, 0x79, 0xe6, 0x5c,
+       0x4f, 0xef, 0x44, 0x77, 0x43, 0xae, 0x5e, 0x89, 0xac, 0x60, 0x8a, 0x66,
+       0x4e, 0xa4, 0x61, 0x87, 0x52, 0x5a, 0x2f, 0xfb, 0x2e, 0xf6, 0x3b, 0xa8,
+       0x78, 0xae, 0x35, 0xce, 0x73, 0xf2, 0x90, 0x5d, 0xd6, 0xda, 0x4d, 0xd3,
+       0x50, 0xf1, 0x44, 0xd3, 0x8b, 0x3e, 0xdf, 0x93, 0x9f, 0x66, 0x4e, 0x1c,
+       0x9c, 0x29, 0x0f, 0x87, 0xb6, 0xf7, 0xda, 0x79, 0x21, 0x66, 0x7f, 0x58,
+       0x8e, 0x28, 0x76, 0xf8, 0x15, 0xdc, 0xdf, 0xc7, 0xf8, 0x32, 0x11, 0x52,
+       0x4c, 0x70, 0x22, 0x36, 0x01, 0x59, 0xcc, 0xba, 0xc4, 0xf8, 0xaf, 0x55,
+       0xac, 0xff, 0x9c, 0xd0, 0xcf, 0x22, 0xa6, 0xe0, 0x59, 0x39, 0xec, 0x6e,
+       0x76, 0x97, 0xc4, 0xf8, 0xbf, 0x59, 0xad, 0x09, 0x35, 0xca, 0x84, 0x1b,
+       0x6a, 0x4a, 0x97, 0x8c, 0x0c, 0x8c, 0x06, 0x53, 0x6b, 0x26, 0x9d, 0x68,
+       0xd3, 0xae, 0x12, 0x64, 0xbc, 0x04, 0xfd, 0x5f, 0x8a, 0x05, 0x46, 0x14,
+       0x9b, 0xf6, 0x65, 0x49, 0xb7, 0xd3, 0xcf, 0xa7, 0x3e, 0xf9, 0x8a, 0xdc,
+       0xb4, 0xb7, 0xca, 0xcd, 0x1e, 0xe2, 0x31, 0xfb, 0xd1, 0xa6, 0x2e, 0x19,
+       0x44, 0x5f, 0x12, 0x7d, 0x4d, 0xca, 0x8f, 0x1a, 0x9f, 0x41, 0x67, 0xdd,
+       0xb4, 0xa9, 0xab, 0xee, 0xe2, 0x2f, 0xde, 0xf5, 0x6f, 0xa0, 0x09, 0xb1,
+       0x1d, 0xdb, 0xd0, 0xa6, 0x8e, 0xb3, 0xeb, 0xfa, 0x3b, 0xd1, 0xbe, 0x17,
+       0x73, 0x34, 0xe8, 0xfb, 0x59, 0xce, 0x76, 0x53, 0xe7, 0xac, 0x19, 0xb3,
+       0xae, 0xae, 0xfd, 0xfb, 0x36, 0x83, 0x4f, 0xf8, 0x94, 0xf4, 0xce, 0xa5,
+       0xe4, 0xe1, 0x8e, 0xda, 0xf6, 0xbf, 0xea, 0xda, 0xad, 0xb2, 0xa6, 0x8d,
+       0x64, 0x38, 0xd6, 0x5e, 0xdb, 0xef, 0xf3, 0x93, 0xdf, 0xee, 0xc0, 0xfb,
+       0x42, 0x66, 0xac, 0xa4, 0xc6, 0x52, 0x37, 0xa3, 0x5c, 0xeb, 0xc3, 0xba,
+       0x67, 0x78, 0xcd, 0x67, 0xf8, 0x2c, 0xf3, 0x7a, 0xb7, 0xd9, 0x8f, 0x67,
+       0x98, 0x13, 0x60, 0x5e, 0x83, 0x3c, 0xbb, 0x5a, 0x9c, 0xc5, 0x31, 0x9f,
+       0xcd, 0x37, 0x64, 0x2a, 0xbc, 0xe7, 0xeb, 0x95, 0x58, 0x05, 0xab, 0xb6,
+       0xab, 0xe0, 0xe7, 0x84, 0x49, 0x3b, 0xad, 0x49, 0xc5, 0x6e, 0x80, 0xce,
+       0x87, 0x40, 0xe7, 0x07, 0x83, 0x8c, 0x0b, 0x9b, 0x3d, 0x5a, 0x3b, 0x32,
+       0x52, 0xfa, 0x0d, 0x64, 0x9c, 0x3c, 0x0a, 0x9f, 0xa2, 0x64, 0x79, 0xf8,
+       0x8c, 0x01, 0xd8, 0x34, 0x57, 0x82, 0x9a, 0x77, 0x40, 0x7c, 0x3f, 0x7f,
+       0x5d, 0x46, 0xa6, 0x98, 0x13, 0x20, 0x3f, 0x33, 0xae, 0x4f, 0xe1, 0xde,
+       0x2d, 0x8c, 0x75, 0x21, 0xc3, 0x63, 0xe0, 0xd7, 0x90, 0x38, 0xd3, 0xdb,
+       0x24, 0x37, 0x3e, 0xa6, 0x3e, 0x40, 0x37, 0x6c, 0xd4, 0x29, 0x77, 0x54,
+       0x26, 0xaf, 0x6c, 0x82, 0xac, 0x32, 0xee, 0xd7, 0x9c, 0x46, 0x39, 0xac,
+       0xbe, 0x39, 0x7d, 0x0e, 0xe6, 0xe1, 0x4c, 0x8d, 0xd9, 0xc8, 0xed, 0xa1,
+       0x98, 0xb4, 0x8e, 0xca, 0xcc, 0xac, 0xad, 0x78, 0x97, 0x94, 0xdc, 0x2e,
+       0x93, 0x76, 0xd9, 0x7d, 0x71, 0xe8, 0x2a, 0xfa, 0xf2, 0x3f, 0x88, 0x98,
+       0xb3, 0xdc, 0xbd, 0x81, 0x31, 0x71, 0x72, 0xba, 0x7a, 0x0e, 0xc5, 0xc8,
+       0xe0, 0xde, 0x2f, 0xdb, 0x8c, 0xcc, 0x30, 0x3e, 0xfe, 0xa0, 0x9c, 0x8a,
+       0x72, 0x4d, 0x8e, 0x65, 0xed, 0x96, 0x3c, 0xc2, 0xbd, 0xfd, 0xc7, 0xe3,
+       0xe5, 0x97, 0x31, 0x5f, 0x5c, 0xba, 0x5f, 0x1d, 0xd3, 0xb8, 0xfe, 0x54,
+       0x4d, 0x0c, 0x6b, 0xf2, 0x05, 0x26, 0x8e, 0xbd, 0x2e, 0x13, 0x8b, 0xa4,
+       0x0f, 0x6d, 0x7c, 0x40, 0x7e, 0xe1, 0xf4, 0xda, 0x4f, 0x68, 0xad, 0x31,
+       0x91, 0x62, 0x7d, 0xa6, 0xd9, 0x49, 0xda, 0xf3, 0x12, 0x1a, 0xfc, 0x1a,
+       0xae, 0x19, 0xd7, 0xe6, 0xdd, 0x5e, 0xf7, 0x09, 0xf1, 0x71, 0x20, 0x9b,
+       0x53, 0x8d, 0x81, 0x4f, 0xca, 0xd7, 0xf7, 0x71, 0x8c, 0xc1, 0x81, 0x48,
+       0x80, 0xb4, 0x7a, 0xef, 0x2e, 0xe2, 0x67, 0x6a, 0xf3, 0x7f, 0x0f, 0x1c,
+       0xdb, 0x3b, 0x90, 0x38, 0xc3, 0x18, 0x36, 0xec, 0x3c, 0xba, 0xc1, 0xbc,
+       0x6b, 0x2e, 0xb7, 0x4e, 0xb4, 0x7e, 0x76, 0xfc, 0x1f, 0x0e, 0xf1, 0x10,
+       0x89, 0x58, 0xa3, 0xc5, 0x3c, 0x38, 0x75, 0x1c, 0x6b, 0x2a, 0xcc, 0xb9,
+       0x11, 0xcb, 0xdf, 0x24, 0x97, 0xfb, 0x2c, 0x79, 0x20, 0x94, 0x8a, 0x5b,
+       0xb2, 0x25, 0x7e, 0x4e, 0xb0, 0x26, 0xeb, 0x2b, 0x8b, 0x89, 0x1c, 0xc7,
+       0x87, 0xa6, 0x39, 0x5f, 0x5c, 0xe3, 0x95, 0xe4, 0x96, 0x72, 0xf9, 0x29,
+       0x57, 0x02, 0xc9, 0x7b, 0x3e, 0x2c, 0xb3, 0x16, 0x6e, 0xbd, 0xfa, 0x79,
+       0x38, 0x05, 0xea, 0x0a, 0x7b, 0xc2, 0x60, 0x0e, 0x27, 0x8f, 0x77, 0x2f,
+       0xb2, 0xfd, 0xe4, 0x43, 0xa6, 0x7d, 0x06, 0xed, 0x06, 0x0f, 0xeb, 0x34,
+       0x75, 0xbc, 0xbb, 0x78, 0x6c, 0x83, 0x89, 0xbf, 0x97, 0x15, 0xff, 0xf5,
+       0x56, 0x4d, 0x4c, 0x93, 0x0a, 0x8c, 0x17, 0xc6, 0x02, 0x63, 0x05, 0xab,
+       0xaf, 0x09, 0xb4, 0x5a, 0x70, 0x99, 0xab, 0xf1, 0x73, 0x56, 0xcc, 0xf7,
+       0x8b, 0x3c, 0xa9, 0x18, 0x29, 0xd6, 0x14, 0x2d, 0xf5, 0x85, 0x0e, 0x2d,
+       0x30, 0xc7, 0x1f, 0x51, 0x7d, 0x70, 0x78, 0xb1, 0x55, 0xf2, 0xf6, 0x7a,
+       0xc9, 0xab, 0x8c, 0x47, 0x55, 0x07, 0x58, 0xce, 0x3d, 0xe8, 0xe3, 0xbe,
+       0x1f, 0x57, 0x5c, 0xc4, 0xeb, 0x85, 0x4e, 0xb4, 0x99, 0x6b, 0xde, 0x51,
+       0xd7, 0x5f, 0x5d, 0x97, 0x4d, 0xd8, 0x96, 0x55, 0x5f, 0x93, 0x65, 0x5f,
+       0x7d, 0x2d, 0xf6, 0xb4, 0x5c, 0x27, 0xdf, 0x94, 0xfc, 0x9c, 0xbb, 0xeb,
+       0xe5, 0xdc, 0x1f, 0xc3, 0x9c, 0x9c, 0x5b, 0x32, 0xa1, 0xa1, 0xa6, 0xbe,
+       0x53, 0x53, 0xc1, 0x5b, 0x2b, 0xf9, 0x53, 0xb4, 0x17, 0x2b, 0xb5, 0x72,
+       0xdc, 0x7b, 0x06, 0xbe, 0x48, 0x1e, 0x7e, 0x45, 0xce, 0xfb, 0xfe, 0x80,
+       0xf7, 0x2b, 0xcf, 0x7f, 0xc1, 0x9e, 0x9a, 0xb5, 0xce, 0x6e, 0xd5, 0xd4,
+       0xd9, 0xbf, 0x8d, 0x67, 0x59, 0x63, 0xcf, 0x95, 0x1b, 0xc0, 0xbb, 0x0d,
+       0xc4, 0x89, 0x54, 0xc6, 0x53, 0xc7, 0xab, 0x2e, 0xd7, 0xb9, 0x76, 0x79,
+       0x73, 0x05, 0xa1, 0xe7, 0x0f, 0x4e, 0xf9, 0x63, 0x4e, 0x4a, 0x63, 0x7f,
+       0x22, 0x16, 0xb4, 0x38, 0xc6, 0xe8, 0xfb, 0xb4, 0x7b, 0x12, 0x7a, 0x9c,
+       0x3a, 0x9f, 0xef, 0xed, 0xc0, 0xd7, 0xa3, 0x2e, 0xa0, 0x3e, 0x57, 0x1b,
+       0x10, 0xcf, 0x43, 0xd7, 0x8f, 0x94, 0x34, 0x97, 0x1f, 0xfb, 0x6a, 0x30,
+       0x31, 0x93, 0x55, 0xdd, 0x00, 0x7f, 0xaf, 0xf4, 0x26, 0xf3, 0x41, 0x67,
+       0x24, 0x50, 0x5d, 0xa7, 0x61, 0x6c, 0xc6, 0x9a, 0x46, 0x0b, 0x74, 0x83,
+       0xc8, 0x55, 0xf0, 0xc6, 0x6b, 0x0b, 0xe4, 0xd7, 0x60, 0xbb, 0x89, 0xaf,
+       0x96, 0x76, 0x58, 0xd2, 0xae, 0xb5, 0xcf, 0xbc, 0x13, 0xa1, 0x7f, 0x32,
+       0x9c, 0xec, 0x87, 0x9f, 0xad, 0xd8, 0x03, 0xe6, 0x2b, 0x0f, 0x22, 0x1e,
+       0xab, 0xce, 0xb1, 0x40, 0xbe, 0xc6, 0xd9, 0x9f, 0x85, 0x5f, 0xb9, 0x52,
+       0xf7, 0xc8, 0x17, 0x27, 0x35, 0xb7, 0x39, 0xb7, 0xd0, 0xa2, 0x3a, 0x76,
+       0xae, 0x38, 0x86, 0x73, 0x91, 0xad, 0xd6, 0x50, 0xde, 0xeb, 0x0f, 0x4b,
+       0xb1, 0xc8, 0xb6, 0x74, 0x35, 0xe8, 0xb9, 0xfb, 0xb5, 0x1d, 0x5b, 0xe6,
+       0xe1, 0x2b, 0x16, 0x17, 0x1d, 0xfc, 0xf7, 0xe0, 0xbf, 0x0f, 0xff, 0xbb,
+       0x25, 0x3d, 0x4d, 0xff, 0x95, 0xb5, 0x9c, 0x96, 0xba, 0xf5, 0xe9, 0x23,
+       0x75, 0x29, 0x0e, 0x2c, 0xef, 0xc5, 0x39, 0xf9, 0x62, 0xbd, 0x9c, 0x30,
+       0x4f, 0xea, 0xeb, 0x08, 0xe6, 0x4b, 0xfd, 0x5a, 0x5f, 0x75, 0x0d, 0xcb,
+       0xf2, 0xea, 0x5e, 0xe4, 0xe9, 0x66, 0x39, 0x5c, 0xf4, 0x6b, 0x57, 0x31,
+       0x39, 0x52, 0xa9, 0x5d, 0x49, 0x26, 0x38, 0xf4, 0xc9, 0x23, 0xd9, 0x29,
+       0xc5, 0x13, 0x58, 0xd6, 0xd0, 0xf5, 0x47, 0x26, 0x16, 0xdf, 0x7e, 0x64,
+       0x05, 0x13, 0x8e, 0x7b, 0x8b, 0xab, 0x61, 0x86, 0x88, 0xa5, 0xe3, 0xb7,
+       0x72, 0xea, 0xbb, 0x61, 0xdf, 0x7e, 0xcc, 0x43, 0x9c, 0x1d, 0xf4, 0x4c,
+       0xf3, 0x0a, 0x76, 0xd7, 0xc4, 0xa3, 0xc4, 0x91, 0xf2, 0xb9, 0x6a, 0xec,
+       0x47, 0x08, 0xe7, 0x2f, 0x01, 0xcb, 0xc9, 0x61, 0x1f, 0x3f, 0xed, 0x34,
+       0x7e, 0x20, 0x71, 0xa6, 0x89, 0x2a, 0xec, 0x91, 0x8f, 0x35, 0x7d, 0x09,
+       0x73, 0x65, 0xe4, 0x77, 0xa5, 0x47, 0xe5, 0x57, 0xa5, 0x31, 0xc8, 0xf7,
+       0x04, 0xe6, 0x3c, 0x20, 0x6f, 0x96, 0xf6, 0xc9, 0xb5, 0xd2, 0xb8, 0xbc,
+       0x51, 0xda, 0x8d, 0x98, 0x6a, 0x94, 0x58, 0x4f, 0x0f, 0x2b, 0x3d, 0x2c,
+       0x07, 0xcf, 0x2b, 0x06, 0xf0, 0x16, 0xfd, 0x9e, 0xe3, 0xea, 0x67, 0x13,
+       0x5f, 0x9f, 0xf8, 0x35, 0xe3, 0x79, 0x62, 0x33, 0x8b, 0x25, 0x1f, 0xc3,
+       0x71, 0xb4, 0x0b, 0x6b, 0xdb, 0xfc, 0x36, 0x65, 0xe4, 0x7c, 0x24, 0x30,
+       0x7a, 0x3e, 0x14, 0x78, 0x50, 0xbf, 0x73, 0x61, 0xbd, 0xb3, 0x2c, 0x93,
+       0xae, 0x43, 0xde, 0x1c, 0x1c, 0x81, 0x2c, 0x8c, 0x42, 0xd5, 0x3f, 0xe4,
+       0xac, 0x17, 0x90, 0x34, 0xf5, 0x11, 0xfc, 0xcc, 0xe4, 0x8b, 0xae, 0x64,
+       0x0b, 0xf3, 0x01, 0x83, 0x47, 0xb3, 0xd1, 0xee, 0x43, 0xfb, 0xe7, 0x5e,
+       0x7b, 0xa7, 0x64, 0x67, 0x25, 0xf5, 0xbe, 0xfa, 0xc3, 0x2f, 0x7b, 0x7d,
+       0x83, 0xe8, 0x03, 0x67, 0x5e, 0x64, 0xdf, 0x45, 0xaf, 0x8f, 0x67, 0xc2,
+       0x5a, 0x7d, 0x5c, 0xf9, 0x2a, 0x6b, 0x8f, 0x8b, 0x7e, 0xd7, 0xa0, 0xb5,
+       0xf8, 0x0f, 0x3a, 0x8d, 0x6e, 0x23, 0x26, 0xf0, 0x9f, 0x9d, 0x8c, 0xc1,
+       0x8a, 0x90, 0xaf, 0xbb, 0xa0, 0x13, 0xff, 0xba, 0x75, 0xa5, 0x6d, 0x0d,
+       0x7d, 0x5c, 0x85, 0xd1, 0xfe, 0x58, 0xba, 0x17, 0xff, 0xed, 0xe1, 0x79,
+       0x9f, 0xc0, 0xbb, 0xe1, 0xac, 0x0a, 0xc4, 0x8d, 0xc7, 0x21, 0xdb, 0x2d,
+       0xb2, 0xfe, 0x2c, 0xe9, 0xd5, 0x0b, 0x5d, 0x9d, 0x82, 0xdc, 0xba, 0xb2,
+       0x50, 0x0a, 0x05, 0x46, 0x0a, 0x29, 0x31, 0x78, 0x6a, 0x4b, 0x32, 0xd1,
+       0x94, 0x9c, 0x1e, 0x48, 0xf4, 0x30, 0x0f, 0x99, 0xed, 0x77, 0xe5, 0x52,
+       0x89, 0xf6, 0x38, 0x27, 0x97, 0x07, 0x12, 0x6e, 0x51, 0x88, 0x8b, 0x71,
+       0xe5, 0x32, 0x64, 0xf3, 0x9d, 0xf3, 0xbb, 0xe5, 0x48, 0x41, 0xfd, 0xe0,
+       0xde, 0xb0, 0xbc, 0x20, 0x97, 0x06, 0x5e, 0xb8, 0x75, 0xc9, 0x3d, 0x84,
+       0x33, 0x25, 0x1f, 0x1e, 0xee, 0x32, 0xfb, 0x56, 0x1c, 0x92, 0x30, 0x1f,
+       0xa2, 0x35, 0x35, 0xa7, 0x51, 0xd2, 0xfb, 0x23, 0x5e, 0x5c, 0x0e, 0x9f,
+       0x3b, 0x30, 0x60, 0xea, 0x29, 0x01, 0x7f, 0x9f, 0x61, 0xf8, 0x31, 0x7c,
+       0xce, 0xa7, 0x8d, 0x3f, 0x4f, 0x67, 0x20, 0x3d, 0xdb, 0x2a, 0xa1, 0x8b,
+       0xf7, 0x81, 0xae, 0x21, 0x39, 0xd4, 0x5f, 0x2e, 0x7f, 0xd3, 0x0d, 0xc5,
+       0x27, 0x10, 0xa3, 0x60, 0xff, 0xb2, 0xee, 0xc5, 0x36, 0xd0, 0xa4, 0x49,
+       0xa2, 0x2f, 0xfa, 0xeb, 0x35, 0x7a, 0x58, 0x86, 0x8b, 0xeb, 0x8c, 0x2d,
+       0xf3, 0xb1, 0x0d, 0xfe, 0x7c, 0x06, 0x53, 0xd6, 0x6d, 0xf5, 0x07, 0xbc,
+       0xef, 0x24, 0xbc, 0xf6, 0x3d, 0x81, 0x07, 0x42, 0xed, 0x12, 0x72, 0x9e,
+       0xdf, 0x48, 0x6c, 0xe4, 0x52, 0xc1, 0xef, 0x87, 0x9f, 0x18, 0xf2, 0xfd,
+       0x61, 0xd9, 0xbe, 0x72, 0xd6, 0xb2, 0xbd, 0x7b, 0xf1, 0x5b, 0xde, 0x9c,
+       0x29, 0x6f, 0x2c, 0x62, 0x8e, 0xd8, 0x5a, 0xb5, 0x4f, 0x66, 0xec, 0xa7,
+       0xf2, 0x74, 0x7f, 0xe2, 0x15, 0xc5, 0xc9, 0x56, 0x9e, 0xe1, 0x7d, 0xc4,
+       0x90, 0x25, 0x7d, 0x26, 0xb6, 0x07, 0xf4, 0xcd, 0xc4, 0xee, 0xb6, 0xe7,
+       0xad, 0x60, 0xc0, 0xf8, 0x23, 0x0d, 0xf2, 0xbd, 0x28, 0xec, 0x36, 0xbf,
+       0x61, 0x61, 0xfe, 0xcb, 0xbd, 0xed, 0xf9, 0x29, 0xec, 0x4b, 0x9c, 0x49,
+       0x5a, 0x13, 0xd8, 0x1f, 0xcf, 0x80, 0x18, 0x50, 0x0b, 0x74, 0xea, 0xc4,
+       0xfb, 0x21, 0x7e, 0xea, 0xf7, 0xdf, 0x7f, 0x1d, 0x74, 0x18, 0xf7, 0x6f,
+       0x70, 0x61, 0x62, 0x31, 0x17, 0x32, 0xec, 0x61, 0x60, 0xab, 0xe5, 0xd6,
+       0xc7, 0xc6, 0xfa, 0x78, 0x3a, 0x62, 0x94, 0x62, 0xf0, 0x03, 0x29, 0x13,
+       0xe4, 0xcd, 0x0e, 0xf4, 0xaf, 0xf9, 0x24, 0xa5, 0xaf, 0xee, 0xf7, 0x7d,
+       0x58, 0xc1, 0x76, 0x4f, 0x14, 0xf6, 0x19, 0x6c, 0x9e, 0xb5, 0x2c, 0xa9,
+       0xae, 0xa4, 0x3d, 0x89, 0xfd, 0xa6, 0x43, 0x89, 0x62, 0x4e, 0x62, 0x32,
+       0x0f, 0x7d, 0xf1, 0x1a, 0x64, 0xff, 0x5a, 0x29, 0x1e, 0x48, 0x63, 0x4f,
+       0x87, 0x0b, 0x43, 0x32, 0x31, 0xab, 0xdf, 0x7e, 0x41, 0xef, 0x0f, 0xc9,
+       0x5c, 0x21, 0xd1, 0x33, 0x0f, 0xfe, 0x9b, 0x2f, 0x10, 0x5f, 0xd4, 0x1b,
+       0x1f, 0xc5, 0x8c, 0x4b, 0x85, 0xcd, 0xb0, 0x0f, 0x92, 0xba, 0x04, 0xff,
+       0xe7, 0x52, 0xa9, 0x07, 0x7c, 0x86, 0xfb, 0x25, 0x07, 0xbf, 0xd0, 0x99,
+       0xa5, 0x01, 0xc8, 0x39, 0xf7, 0x62, 0xcb, 0xc2, 0x56, 0x9c, 0x1d, 0x71,
+       0x44, 0x8a, 0x1f, 0xff, 0x2f, 0xce, 0xd7, 0x7f, 0xef, 0x1d, 0x6a, 0xa7,
+       0xe7, 0x75, 0x5f, 0xb0, 0xcb, 0x88, 0x01, 0xb2, 0xfd, 0xc6, 0x6e, 0xa7,
+       0x23, 0x6d, 0x92, 0xbe, 0x9b, 0x76, 0xbc, 0x5d, 0x63, 0x44, 0xe5, 0xc5,
+       0x08, 0xef, 0xbf, 0xb3, 0xd1, 0xd0, 0x2f, 0x5c, 0xd7, 0xbe, 0x8e, 0xdf,
+       0x56, 0xe9, 0x70, 0xf8, 0x6b, 0xe3, 0xf7, 0xed, 0x8d, 0xac, 0xef, 0x76,
+       0x38, 0x49, 0xac, 0xf5, 0x5b, 0x2f, 0x5f, 0x80, 0xeb, 0x79, 0x3e, 0xb3,
+       0xc1, 0x5b, 0x97, 0xf3, 0xb6, 0x62, 0x9e, 0x16, 0x6f, 0xad, 0x56, 0xcd,
+       0x4f, 0x9a, 0xb5, 0x10, 0xe3, 0x16, 0xfe, 0xb2, 0x51, 0xbf, 0x35, 0x86,
+       0xbd, 0xa8, 0x6d, 0xff, 0x79, 0x23, 0x71, 0x73, 0x1d, 0x4e, 0xab, 0x62,
+       0x3c, 0x6f, 0xb6, 0xb7, 0xe3, 0x9a, 0x6b, 0x72, 0x8c, 0xc9, 0x87, 0xcf,
+       0x95, 0x38, 0x3f, 0xdb, 0x29, 0x39, 0xa1, 0xf9, 0x0c, 0x83, 0xe5, 0x9b,
+       0x2b, 0xdc, 0x2f, 0x13, 0xe7, 0x15, 0x5f, 0x37, 0x93, 0xb7, 0xf8, 0xdd,
+       0x0b, 0xbf, 0x97, 0xa3, 0x2f, 0x31, 0x26, 0x07, 0x71, 0x7e, 0x97, 0xe1,
+       0x53, 0x2d, 0x99, 0xef, 0x62, 0xf1, 0x77, 0x00, 0xe7, 0x12, 0x82, 0x8c,
+       0x51, 0x46, 0x29, 0x53, 0x38, 0xbf, 0x71, 0x5b, 0xde, 0x1d, 0xa0, 0x3c,
+       0x0f, 0xc8, 0x95, 0x8a, 0x3c, 0xe7, 0x20, 0xcf, 0x94, 0xe5, 0x1c, 0x64,
+       0xda, 0xf0, 0xf5, 0x7e, 0x7e, 0x67, 0x1d, 0x83, 0xbd, 0x52, 0x1f, 0xe2,
+       0x25, 0xf0, 0xb5, 0xed, 0x7d, 0x2b, 0x15, 0xd0, 0x1c, 0x4e, 0x76, 0xb6,
+       0xc1, 0xfb, 0x0e, 0x00, 0xd7, 0x57, 0x9e, 0x93, 0xf4, 0x6c, 0x33, 0xbf,
+       0xe7, 0xea, 0xe2, 0x99, 0x65, 0xaf, 0xf0, 0xdf, 0xe7, 0x45, 0xe2, 0x4d,
+       0xe9, 0xcf, 0xf2, 0x9a, 0x71, 0xde, 0x26, 0x8c, 0x19, 0x04, 0x9d, 0x9b,
+       0x31, 0x3f, 0xf7, 0xb8, 0xda, 0x38, 0xde, 0x0f, 0x55, 0xe1, 0x53, 0x7d,
+       0x7a, 0xaf, 0xd5, 0x35, 0xb3, 0xfd, 0xcd, 0xde, 0xfb, 0xf1, 0x1c, 0x94,
+       0xef, 0xc1, 0xb7, 0xf4, 0x89, 0xc9, 0x2f, 0x29, 0x3d, 0x87, 0xb9, 0x02,
+       0xf9, 0x37, 0xa4, 0x39, 0x8c, 0x2c, 0x6c, 0xcb, 0x5e, 0x1d, 0x1f, 0x5b,
+       0x91, 0xef, 0xae, 0x80, 0xc6, 0xdd, 0xd9, 0xc2, 0x1a, 0xe9, 0x56, 0x1d,
+       0xd4, 0xe5, 0xf1, 0x36, 0xec, 0x85, 0x62, 0xb9, 0x0f, 0xc8, 0xf1, 0xd2,
+       0x20, 0xe8, 0x10, 0x93, 0xa7, 0xe0, 0x37, 0x3f, 0x53, 0xba, 0x43, 0x96,
+       0x23, 0xd8, 0x57, 0x45, 0xc6, 0x86, 0xe5, 0xfb, 0xf3, 0x09, 0xef, 0x3a,
+       0xe1, 0x2e, 0x5b, 0x3b, 0xb0, 0x07, 0xca, 0x13, 0xe5, 0x8a, 0xe3, 0x82,
+       0x88, 0x45, 0x38, 0xef, 0xd3, 0x46, 0xb7, 0x61, 0xde, 0x62, 0x84, 0xf2,
+       0xcb, 0xbd, 0x85, 0x3c, 0x99, 0x65, 0x5c, 0xc5, 0x77, 0x36, 0x36, 0x29,
+       0x53, 0x73, 0x16, 0x09, 0xc5, 0x81, 0xae, 0x9c, 0x81, 0x3f, 0x8f, 0x2f,
+       0x97, 0xfe, 0x77, 0x14, 0xd4, 0xa3, 0xb0, 0x95, 0x05, 0xd8, 0xca, 0x02,
+       0x6c, 0x24, 0x64, 0xe1, 0x5a, 0x01, 0x36, 0xb2, 0x00, 0x1b, 0x09, 0x7d,
+       0xf6, 0x3a, 0x62, 0xbb, 0xd7, 0xc0, 0x43, 0xc6, 0xd7, 0x3e, 0x4a, 0x5f,
+       0x1b, 0x7f, 0xff, 0x03, 0x4c, 0x03, 0x3a, 0xe1, 0xd4, 0x71, 0x00, 0x00,
+       0x00 };
 
 static const u32 bnx2_RXP_b06FwData[(0x0/4) + 1] = { 0x0 };
 static const u32 bnx2_RXP_b06FwRodata[(0x24/4) + 1] = {
-       0x08004580, 0x08004580, 0x080044f8, 0x08004530, 0x08004564, 0x08004588,
-       0x08004588, 0x08004588, 0x08004468, 0x00000000 };
+       0x08004590, 0x08004590, 0x08004508, 0x08004540, 0x08004574, 0x08004598,
+       0x08004598, 0x08004598, 0x08004478, 0x00000000 };
 
 static struct fw_info bnx2_rxp_fw_06 = {
-       /* Firmware version: 4.0.5 */
+       /* Firmware version: 4.1.1 */
        .ver_major                      = 0x4,
-       .ver_minor                      = 0x0,
-       .ver_fix                        = 0x5,
+       .ver_minor                      = 0x1,
+       .ver_fix                        = 0x1,
 
        .start_addr                     = 0x080031d0,
 
        .text_addr                      = 0x08000000,
-       .text_len                       = 0x71c0,
+       .text_len                       = 0x71d0,
        .text_index                     = 0x0,
        .gz_text                        = bnx2_RXP_b06FwText,
        .gz_text_len                    = sizeof(bnx2_RXP_b06FwText),
@@ -2931,22 +2932,22 @@ static struct fw_info bnx2_rxp_fw_06 = {
        .data_index                     = 0x0,
        .data                           = bnx2_RXP_b06FwData,
 
-       .sbss_addr                      = 0x08007200,
+       .sbss_addr                      = 0x08007220,
        .sbss_len                       = 0x58,
        .sbss_index                     = 0x0,
 
-       .bss_addr                       = 0x08007258,
+       .bss_addr                       = 0x08007278,
        .bss_len                        = 0x44c,
        .bss_index                      = 0x0,
 
-       .rodata_addr                    = 0x080071c0,
+       .rodata_addr                    = 0x080071d0,
        .rodata_len                     = 0x24,
        .rodata_index                   = 0x0,
        .rodata                         = bnx2_RXP_b06FwRodata,
 };
 
 static u8 bnx2_rv2p_proc1[] = {
-       /* Date:        12/07/2007 14:57 */
+       /* Date:        12/07/2007 15:02 */
        0xd5, 0x56, 0x41, 0x6b, 0x13, 0x51, 0x10, 0x9e, 0xdd, 0x6c, 0xbb, 0xdb,
        0x64, 0xb3, 0x59, 0xaa, 0xd6, 0x50, 0x53, 0x93, 0x06, 0x2f, 0xad, 0x29,
        0x6d, 0xaa, 0x82, 0x42, 0xa1, 0x92, 0x4b, 0xc1, 0xf6, 0x20, 0xf5, 0x22,
@@ -3032,7 +3033,7 @@ static u8 bnx2_rv2p_proc1[] = {
        0xa7, 0xd8, 0x0d, 0x00, 0x00, 0x00 };
 
 static u8 bnx2_rv2p_proc2[] = {
-       /* Date:        12/07/2007 14:57 */
+       /* Date:        12/07/2007 15:02 */
        0xed, 0x59, 0x5d, 0x6c, 0x54, 0xc7, 0x15, 0x9e, 0xbd, 0xbb, 0x7b, 0xf7,
        0x7a, 0x7d, 0xf7, 0xae, 0x71, 0xa8, 0xff, 0xf9, 0xb3, 0x09, 0xd8, 0xa9,
        0x21, 0xce, 0x9a, 0x98, 0x02, 0x55, 0x63, 0x39, 0x95, 0x81, 0xa6, 0x55,
index 13b222eb2f63efc064a896aa321e020354d5b56b..e6ffa2769f3d471d92d54cb67998a88d38aeedfa 100644 (file)
@@ -3173,250 +3173,250 @@ static struct fw_info bnx2_rxp_fw_09 = {
 };
 
 static u8 bnx2_xi_rv2p_proc1[] = {
-       /* Date:        12/07/2007 16:21 */
-       0xc5, 0x56, 0xcd, 0x6b, 0x13, 0x51, 0x10, 0x9f, 0xdd, 0xa4, 0xd9, 0x34,
-       0xd9, 0x64, 0x97, 0xaa, 0x25, 0xb4, 0x91, 0xa6, 0x55, 0x0f, 0x69, 0x23,
-       0xb6, 0xea, 0xc1, 0x43, 0xc1, 0xda, 0x8b, 0xa0, 0x9e, 0x7a, 0x10, 0xf1,
-       0xdb, 0x20, 0x05, 0xf1, 0x8f, 0x70, 0x51, 0xab, 0x20, 0x78, 0x28, 0x6a,
-       0xb0, 0x0a, 0xea, 0x49, 0x45, 0x3c, 0x34, 0x07, 0x41, 0x50, 0x14, 0x14,
-       0x3c, 0xe9, 0x4d, 0xf0, 0xe3, 0x50, 0x15, 0x3f, 0x0e, 0x7a, 0x13, 0x8f,
-       0xda, 0xf8, 0xde, 0xcc, 0xef, 0xd9, 0xdd, 0x4d, 0xd3, 0x14, 0x0f, 0xba,
-       0xd0, 0xfc, 0xfa, 0xde, 0x9b, 0x37, 0x6f, 0xe6, 0x37, 0xf3, 0x66, 0x9e,
-       0x4f, 0x44, 0x36, 0x05, 0xf5, 0x3e, 0x85, 0x94, 0xb5, 0x12, 0x69, 0x05,
-       0x16, 0xd1, 0x5d, 0x97, 0x31, 0xd8, 0x40, 0xf2, 0x0d, 0x09, 0x04, 0x43,
-       0xbe, 0xfa, 0xfd, 0x4e, 0x5b, 0x4b, 0x1a, 0x13, 0xb4, 0xb5, 0x5f, 0xe3,
-       0x36, 0x7a, 0x5c, 0x2a, 0x28, 0xfc, 0xd5, 0xa0, 0x40, 0x8f, 0xd7, 0xcc,
-       0xde, 0xaf, 0x67, 0x59, 0xef, 0x3b, 0xec, 0x7f, 0x9d, 0x10, 0xdc, 0x52,
-       0x49, 0x8b, 0x1e, 0x20, 0xad, 0xf7, 0x19, 0x5e, 0x4e, 0xeb, 0x71, 0xd1,
-       0x0a, 0xd6, 0xe3, 0x7c, 0x5b, 0xe6, 0xe7, 0xa6, 0x3d, 0x3d, 0x4f, 0xef,
-       0xc7, 0xf5, 0xd8, 0xcb, 0x9c, 0xae, 0xa7, 0x59, 0xaf, 0xac, 0x77, 0x65,
-       0x4e, 0xf3, 0x3e, 0xd7, 0x12, 0x7d, 0xea, 0x8f, 0xf7, 0x6f, 0x56, 0x7a,
-       0x60, 0x37, 0x89, 0x9e, 0x43, 0x25, 0x3d, 0x3f, 0x06, 0xb9, 0x51, 0xc8,
-       0x15, 0x9b, 0xe4, 0xe6, 0xa6, 0x35, 0x3a, 0x54, 0xad, 0x68, 0x7f, 0xfa,
-       0x95, 0xa1, 0xae, 0xf0, 0xd3, 0x27, 0xfe, 0x4e, 0xc2, 0xec, 0x77, 0x83,
-       0xfa, 0x1f, 0x65, 0xdb, 0xa0, 0x96, 0x9b, 0x53, 0x7e, 0x1b, 0x7f, 0x8d,
-       0xbc, 0xc8, 0x39, 0xac, 0xe7, 0xad, 0x5a, 0x37, 0x7e, 0x85, 0xfd, 0xc9,
-       0x86, 0xfc, 0x89, 0xf9, 0xd9, 0xe4, 0x57, 0x98, 0xa7, 0xf4, 0x22, 0x76,
-       0xeb, 0x73, 0x94, 0x0d, 0x7c, 0x4e, 0x0a, 0xfc, 0xa6, 0x62, 0xfb, 0x52,
-       0x2d, 0xf6, 0x7d, 0x6a, 0x2c, 0xf8, 0x69, 0xd6, 0xf5, 0xfc, 0xd3, 0x85,
-       0xf9, 0x72, 0x74, 0x5d, 0xfc, 0xef, 0x80, 0xff, 0x8f, 0xe0, 0xdf, 0x0e,
-       0x5a, 0x6b, 0x17, 0x78, 0x3d, 0xc9, 0xfb, 0x7b, 0x95, 0x3d, 0x1a, 0x57,
-       0x03, 0xfb, 0x81, 0x07, 0x81, 0x07, 0x80, 0xab, 0x80, 0x2b, 0x81, 0x2b,
-       0x80, 0x5d, 0xc0, 0xcb, 0x40, 0x1f, 0xe8, 0x01, 0xf3, 0xc0, 0x8b, 0x40,
-       0x17, 0x98, 0x05, 0xd6, 0x80, 0x57, 0x81, 0x69, 0xe0, 0x31, 0xe0, 0x23,
-       0xe0, 0x13, 0xe0, 0x37, 0xe0, 0x39, 0xa3, 0xcf, 0xc2, 0xb9, 0x40, 0x42,
-       0x3e, 0x58, 0x31, 0x9e, 0xae, 0x21, 0xef, 0x35, 0xcf, 0x58, 0x2f, 0x1b,
-       0x39, 0xc4, 0x97, 0x79, 0x9a, 0x81, 0x5c, 0xd7, 0xec, 0x8d, 0xd8, 0xfd,
-       0x28, 0xb5, 0xbd, 0x17, 0xf1, 0xb8, 0x79, 0xec, 0xcf, 0xe1, 0xed, 0x1e,
-       0x9f, 0x93, 0x4f, 0xc9, 0xbc, 0x31, 0x6b, 0x8f, 0x27, 0x78, 0x34, 0x23,
-       0xf8, 0x39, 0xd3, 0xa9, 0x7e, 0x1b, 0x8d, 0xc9, 0xac, 0x8c, 0x8f, 0xe4,
-       0x0c, 0xcf, 0x46, 0x8f, 0xb1, 0xa7, 0x9d, 0x1d, 0xad, 0xce, 0x33, 0x76,
-       0xb5, 0x3b, 0x57, 0xb0, 0x6a, 0x47, 0xfd, 0xbf, 0x32, 0x2c, 0x98, 0x1c,
-       0x61, 0xa8, 0xb8, 0xa9, 0xa4, 0xc6, 0xcd, 0xee, 0x33, 0x73, 0x8e, 0x46,
-       0xb7, 0x50, 0xe3, 0xfb, 0x92, 0xa4, 0x5a, 0x4a, 0xeb, 0xfd, 0xd9, 0x38,
-       0x2f, 0x72, 0x3d, 0x47, 0x5e, 0x30, 0x16, 0xae, 0x3c, 0x17, 0xf9, 0x57,
-       0x25, 0x97, 0x71, 0xf7, 0x10, 0xc5, 0x3e, 0xb3, 0x2e, 0xf7, 0x31, 0x60,
-       0xbb, 0x7f, 0x58, 0x41, 0xdd, 0x9c, 0x83, 0x7d, 0xc7, 0x4d, 0x1c, 0x7d,
-       0xb6, 0x73, 0x80, 0x64, 0x3c, 0x51, 0x96, 0xf5, 0x89, 0x32, 0xee, 0xf3,
-       0x40, 0x34, 0x1f, 0xe4, 0x5e, 0x24, 0x10, 0xef, 0x7d, 0xb8, 0x17, 0xf1,
-       0x7b, 0x9c, 0x9e, 0xbd, 0x31, 0x1d, 0xce, 0x97, 0x02, 0x55, 0x47, 0x60,
-       0x4f, 0x53, 0x9c, 0x4d, 0x3d, 0x36, 0xf9, 0xce, 0xd3, 0xb3, 0x41, 0x22,
-       0xc2, 0xdf, 0x18, 0x55, 0xc2, 0x71, 0xb2, 0x16, 0xc9, 0x97, 0x76, 0xe7,
-       0x44, 0xf4, 0xe5, 0x55, 0x04, 0xa8, 0x39, 0x8f, 0x1d, 0xf8, 0x35, 0x86,
-       0x3c, 0xee, 0x6d, 0xca, 0x63, 0x53, 0xe7, 0x25, 0x9f, 0x5b, 0xd5, 0xaf,
-       0xbf, 0xaf, 0xcf, 0x22, 0x17, 0x84, 0xf2, 0xd3, 0xd4, 0x43, 0xf0, 0xe4,
-       0xb0, 0x5c, 0x71, 0xee, 0x9e, 0xc4, 0x4d, 0xea, 0xb8, 0x4a, 0xc6, 0x20,
-       0x6a, 0xa7, 0x63, 0xfc, 0xeb, 0x0b, 0xd7, 0xc1, 0x75, 0x2d, 0xe2, 0x15,
-       0xae, 0xbb, 0x71, 0x5e, 0xa2, 0x79, 0x2f, 0xf1, 0xcf, 0x80, 0xa7, 0xde,
-       0x36, 0x75, 0xa1, 0x13, 0x72, 0xdd, 0x4b, 0xc8, 0x89, 0xde, 0xf1, 0x72,
-       0xb8, 0x8e, 0xf8, 0x0d, 0xd4, 0xc1, 0x3f, 0x71, 0x78, 0xd8, 0x22, 0x0e,
-       0xa3, 0xff, 0x37, 0x0e, 0xe8, 0xa7, 0xed, 0xe2, 0x40, 0xb1, 0x38, 0xfc,
-       0x98, 0x5f, 0x5e, 0x1c, 0x08, 0x3c, 0x51, 0x8b, 0x38, 0xa4, 0xc0, 0xd7,
-       0xd7, 0xf9, 0xa5, 0xe3, 0x90, 0x85, 0xdc, 0xe7, 0x90, 0x1c, 0xdb, 0x3d,
-       0x2a, 0xf7, 0xd4, 0xa9, 0x7e, 0x89, 0xf1, 0x3b, 0x52, 0xd1, 0xf5, 0xe7,
-       0x04, 0xd5, 0xe1, 0xff, 0x9b, 0x08, 0x0f, 0x39, 0x65, 0x9f, 0xbc, 0x23,
-       0x6e, 0xd7, 0x0d, 0x5f, 0xb2, 0x5c, 0xaa, 0x08, 0xde, 0x62, 0x79, 0x3f,
-       0xc4, 0x5b, 0x94, 0x5f, 0xe1, 0xcd, 0xa7, 0x9b, 0x7f, 0xea, 0x92, 0xc7,
-       0xfa, 0x86, 0x51, 0xd7, 0x0f, 0xa3, 0xbe, 0x7e, 0xc8, 0x48, 0xfd, 0xae,
-       0xee, 0xe4, 0x3a, 0x4b, 0xdd, 0xa8, 0xb3, 0xd5, 0x9c, 0x8c, 0x7b, 0x72,
-       0xf2, 0x6e, 0x19, 0x76, 0x5c, 0x96, 0xeb, 0xc9, 0x09, 0x76, 0x67, 0xf5,
-       0xbe, 0x02, 0x7d, 0xdc, 0xc5, 0xe2, 0x95, 0x19, 0x57, 0xea, 0xed, 0xcc,
-       0x73, 0xd4, 0x7f, 0xcf, 0xf0, 0x04, 0x7f, 0x37, 0xe9, 0xf9, 0x6e, 0x55,
-       0xef, 0xc2, 0xfc, 0x2a, 0x99, 0x41, 0xb1, 0xef, 0x3a, 0xac, 0x2f, 0x99,
-       0x7d, 0x7d, 0x9a, 0xcf, 0x07, 0xf3, 0xa6, 0xbf, 0x0c, 0x6c, 0xd7, 0xf6,
-       0x78, 0x94, 0x77, 0x24, 0x9e, 0x82, 0x4a, 0xce, 0x76, 0xf4, 0xb6, 0xe2,
-       0x94, 0x2d, 0xe3, 0xa9, 0x93, 0xac, 0x66, 0xd7, 0x94, 0x99, 0x1f, 0xe7,
-       0x44, 0x9e, 0xb8, 0xf3, 0x94, 0xe7, 0xf3, 0xf5, 0x84, 0xcc, 0x3b, 0x3b,
-       0x0d, 0x1f, 0x1e, 0xfb, 0x57, 0x13, 0x3e, 0xf6, 0x5f, 0x12, 0xdc, 0xab,
-       0x9e, 0x22, 0xfa, 0xcb, 0xd4, 0x5c, 0xe9, 0x3f, 0x33, 0x6e, 0x9a, 0x91,
-       0x98, 0x0f, 0x7b, 0xa3, 0xf4, 0x91, 0x0e, 0xd4, 0xff, 0xce, 0x50, 0x9c,
-       0xe2, 0x7d, 0x79, 0xb9, 0xf1, 0x0a, 0xf7, 0x0b, 0xd3, 0x47, 0xe2, 0x7d,
-       0x21, 0x87, 0x3c, 0xbb, 0xdc, 0x26, 0x1f, 0x4d, 0x9d, 0xbd, 0x80, 0x7b,
-       0xb0, 0x58, 0x3f, 0xd6, 0x98, 0x6f, 0xf1, 0x8e, 0x28, 0x22, 0xff, 0x4c,
-       0xdf, 0x5c, 0xec, 0xbd, 0x20, 0xf2, 0xcb, 0x7b, 0x27, 0xf8, 0x2d, 0xde,
-       0x09, 0xff, 0xec, 0x3d, 0x50, 0x58, 0x88, 0xa3, 0xc9, 0xd3, 0x70, 0x1c,
-       0xc3, 0xf9, 0x1a, 0xef, 0xd7, 0x4b, 0xf5, 0xe9, 0x3c, 0x78, 0x9e, 0x04,
-       0xcf, 0x49, 0xea, 0x48, 0x30, 0x31, 0x6e, 0xf2, 0x14, 0xeb, 0xb5, 0xa7,
-       0x6c, 0x16, 0x77, 0x3b, 0xce, 0x58, 0x1a, 0xf3, 0xee, 0x19, 0x91, 0x4b,
-       0xca, 0x7c, 0xc1, 0xe0, 0xd9, 0x53, 0xf2, 0x3e, 0xb4, 0xe9, 0x37, 0xf9,
-       0x0f, 0x65, 0x7b, 0x50, 0x0d, 0x00, 0x00, 0x00 };
+       /* Date:        01/14/2008 15:44 */
+       0xc5, 0x56, 0xcd, 0x6b, 0x13, 0x51, 0x10, 0x9f, 0xdd, 0x7c, 0x6c, 0x9a,
+       0x6c, 0xb2, 0xa1, 0x6a, 0x09, 0x35, 0xd2, 0x58, 0x7a, 0x30, 0x6d, 0xc4,
+       0x56, 0x3d, 0x78, 0x28, 0x54, 0x7a, 0x11, 0xac, 0xa7, 0x1e, 0x44, 0xc4,
+       0xcf, 0x20, 0x05, 0xf5, 0x8f, 0x70, 0x51, 0xab, 0x20, 0x78, 0x28, 0x68,
+       0xb4, 0x7e, 0xa0, 0x27, 0x15, 0xf1, 0x90, 0x1c, 0x04, 0x05, 0x45, 0x50,
+       0xf0, 0xa4, 0x37, 0x41, 0xbd, 0x54, 0xc5, 0x0f, 0xf0, 0xe2, 0x45, 0x8f,
+       0xda, 0xf8, 0xde, 0xcc, 0xef, 0xd9, 0xdd, 0x4d, 0xd2, 0x14, 0x0f, 0x1a,
+       0x68, 0x7f, 0xec, 0xdb, 0xdf, 0x9b, 0x37, 0xf3, 0x9b, 0x79, 0x33, 0x9b,
+       0x27, 0x22, 0x9b, 0xfc, 0xc6, 0x80, 0x42, 0x72, 0xad, 0x58, 0x4a, 0x81,
+       0x45, 0x74, 0xcf, 0x65, 0xf4, 0x37, 0x91, 0xfc, 0x46, 0x04, 0xfc, 0x91,
+       0xbc, 0xfa, 0xff, 0x9d, 0x26, 0x4a, 0x1a, 0x63, 0x34, 0xb1, 0x5e, 0xe3,
+       0x24, 0x3d, 0x29, 0x15, 0x14, 0xfe, 0x6a, 0x92, 0xaf, 0x9f, 0x87, 0xea,
+       0x0f, 0x1a, 0x19, 0xb6, 0xfb, 0x0e, 0xfb, 0xdf, 0xc4, 0x04, 0xb7, 0x55,
+       0x52, 0x62, 0x07, 0x48, 0x1b, 0xf3, 0x0c, 0xaf, 0xe6, 0xf4, 0x73, 0xd1,
+       0xf2, 0x37, 0xe2, 0x7c, 0x5b, 0xd6, 0x17, 0xe6, 0x3c, 0xbd, 0x4e, 0xef,
+       0x27, 0xf5, 0xb3, 0x97, 0x3e, 0xdd, 0x48, 0xb1, 0x5d, 0x79, 0xdf, 0x9b,
+       0x3e, 0xcd, 0xfb, 0x5c, 0x4b, 0xec, 0xa9, 0x3f, 0xde, 0xbf, 0x55, 0xd9,
+       0x81, 0xdf, 0x24, 0x76, 0x0e, 0x96, 0xf4, 0xfa, 0x76, 0xf0, 0xc6, 0xc1,
+       0x2b, 0xb6, 0xf0, 0x16, 0xe6, 0x34, 0x3a, 0x54, 0xad, 0xe8, 0x78, 0x06,
+       0x49, 0xe2, 0x49, 0xd0, 0x4c, 0xca, 0x15, 0x9d, 0x06, 0x84, 0xfd, 0x6e,
+       0x58, 0xef, 0x57, 0xbe, 0x0d, 0x6b, 0xde, 0x82, 0x8a, 0xdb, 0xc4, 0x1b,
+       0xe6, 0x39, 0x15, 0x63, 0x57, 0xf3, 0xde, 0x2a, 0x9e, 0x89, 0x2f, 0x18,
+       0x57, 0x26, 0x10, 0x57, 0x24, 0xde, 0x96, 0xf8, 0x82, 0x7a, 0xa5, 0xda,
+       0xf8, 0xaf, 0xcf, 0x51, 0xbe, 0xf0, 0x39, 0x49, 0xe8, 0x9c, 0x8c, 0xec,
+       0x4b, 0x76, 0x88, 0xfb, 0x93, 0x35, 0xb3, 0x21, 0xec, 0x3f, 0x91, 0xb6,
+       0xf7, 0x54, 0xf9, 0x8d, 0xf5, 0x72, 0x3b, 0x1d, 0x12, 0xd0, 0xe1, 0x31,
+       0xe2, 0x9b, 0xa2, 0x21, 0xbb, 0xc0, 0xef, 0xe3, 0xbc, 0x7f, 0xad, 0xf2,
+       0x47, 0xe3, 0x3a, 0xe0, 0x7a, 0xe0, 0x01, 0xe0, 0x7e, 0xe0, 0x1a, 0xe0,
+       0x6a, 0xe0, 0x2a, 0x60, 0x2f, 0xf0, 0x32, 0x30, 0x0f, 0xf4, 0x80, 0x39,
+       0xe0, 0x05, 0xa0, 0x0b, 0xcc, 0x00, 0x6b, 0xc0, 0xab, 0xc0, 0x14, 0xf0,
+       0x28, 0xf0, 0x21, 0xf0, 0x31, 0xf0, 0x0b, 0xf0, 0x1c, 0xd0, 0xb1, 0x60,
+       0x0f, 0xa8, 0x7e, 0x3e, 0xee, 0x47, 0x48, 0xa7, 0xeb, 0xa8, 0x7f, 0xad,
+       0x33, 0xde, 0x97, 0x0d, 0x0f, 0xf9, 0x65, 0x9d, 0x2e, 0x83, 0xd7, 0x5b,
+       0xbf, 0x19, 0xb9, 0x27, 0xa5, 0xae, 0xf7, 0x23, 0x9a, 0x37, 0x8f, 0xe3,
+       0x39, 0xb4, 0xc3, 0xe3, 0x73, 0x72, 0x49, 0x59, 0x37, 0x6e, 0xed, 0xf1,
+       0x04, 0x8f, 0xa4, 0x05, 0x3f, 0xa7, 0x7b, 0xd4, 0xff, 0x66, 0x73, 0x26,
+       0x23, 0xcf, 0x87, 0xb3, 0x46, 0x67, 0x63, 0xc7, 0xf8, 0xd3, 0xcd, 0x8f,
+       0x4e, 0xe7, 0x19, 0xbf, 0xba, 0x9d, 0x2b, 0x58, 0xb5, 0xc3, 0xf1, 0x5f,
+       0x19, 0x15, 0x8c, 0x8f, 0x31, 0x54, 0xdc, 0x64, 0x5c, 0xe3, 0x56, 0xf7,
+       0xb9, 0x39, 0x47, 0xa3, 0x5b, 0xa8, 0xf1, 0x7d, 0x89, 0x53, 0x2d, 0xa9,
+       0xed, 0xfe, 0x6c, 0x9e, 0x17, 0x5e, 0xff, 0xe1, 0x97, 0x8c, 0x85, 0x2b,
+       0x2f, 0x84, 0xff, 0xba, 0xe4, 0x32, 0xee, 0x1e, 0xa1, 0xc8, 0xcf, 0xbc,
+       0x97, 0xfb, 0xe8, 0xb3, 0xdf, 0x3f, 0x2c, 0xbf, 0x61, 0xce, 0xc1, 0xbe,
+       0xe3, 0x26, 0x8f, 0x79, 0xf6, 0x73, 0x90, 0xe4, 0x79, 0xba, 0x2c, 0xef,
+       0xa7, 0xcb, 0xb8, 0xcf, 0x83, 0xe1, 0x7a, 0x90, 0x7b, 0x11, 0x43, 0xbe,
+       0xf7, 0xe2, 0x5e, 0x44, 0xef, 0x71, 0xaa, 0x7e, 0x73, 0x2e, 0x58, 0x2f,
+       0x05, 0xaa, 0x8e, 0xc1, 0x9f, 0x96, 0x3c, 0x9b, 0xbe, 0x6c, 0xea, 0x9d,
+       0x97, 0xeb, 0x7e, 0x2c, 0xa4, 0xdf, 0x76, 0xaa, 0x04, 0xf3, 0x64, 0xb5,
+       0xa9, 0x97, 0x6e, 0xe7, 0x84, 0xec, 0xe5, 0x54, 0x06, 0xa8, 0xb5, 0x8e,
+       0x1d, 0xc4, 0x35, 0x81, 0x3a, 0x5e, 0xdb, 0x52, 0xc7, 0xa6, 0xdf, 0x4b,
+       0x3d, 0x77, 0xea, 0x5f, 0x7f, 0xdf, 0xa7, 0x85, 0xe7, 0x07, 0xea, 0xd3,
+       0xf4, 0x43, 0xe8, 0xe4, 0x30, 0xaf, 0xb8, 0x70, 0x5f, 0xf2, 0x26, 0xfd,
+       0x5c, 0x15, 0xa3, 0x1f, 0xf6, 0xd3, 0x31, 0xf1, 0x0d, 0x04, 0xfb, 0xe7,
+       0x50, 0x87, 0x7c, 0x05, 0xfb, 0x6e, 0x54, 0x97, 0x70, 0xdd, 0x4b, 0xfe,
+       0xd3, 0xd0, 0xa9, 0xbf, 0x4b, 0x5f, 0xe8, 0x01, 0x6f, 0xcd, 0x32, 0x3c,
+       0xb1, 0x3b, 0x59, 0x0e, 0xf6, 0x11, 0xaf, 0x89, 0xfe, 0x87, 0x7d, 0x7d,
+       0xf5, 0x47, 0x1d, 0xf2, 0x30, 0xfe, 0x7f, 0xf3, 0x80, 0xf9, 0x52, 0xb4,
+       0x24, 0x0f, 0x09, 0x5a, 0x99, 0xbe, 0x84, 0xf8, 0xa9, 0x83, 0xbe, 0x49,
+       0xe8, 0xf0, 0x6d, 0x71, 0x79, 0x7d, 0x33, 0xe0, 0x7d, 0x0d, 0xf0, 0xb8,
+       0x2e, 0xc6, 0xe5, 0xfe, 0x39, 0xd5, 0x2f, 0x11, 0xdd, 0xc6, 0x2a, 0xba,
+       0xaf, 0x9c, 0xa0, 0x06, 0xe2, 0x7a, 0x1b, 0x8a, 0x2f, 0xab, 0xfc, 0x93,
+       0xef, 0x84, 0x3b, 0x0d, 0xa3, 0x83, 0xbc, 0x2e, 0x55, 0x04, 0x6f, 0x33,
+       0x3f, 0x1f, 0xd0, 0x23, 0xac, 0x9b, 0xe8, 0x91, 0xa7, 0x5b, 0x7f, 0xfa,
+       0x8d, 0xc7, 0xf6, 0x46, 0xd1, 0xaf, 0x0f, 0xa1, 0x6f, 0x7e, 0x48, 0x4b,
+       0x5f, 0xae, 0x4e, 0x71, 0xff, 0xa4, 0x3e, 0xf4, 0xcf, 0x6a, 0x56, 0x9e,
+       0xfb, 0xb3, 0xf2, 0x1d, 0x36, 0xea, 0xb8, 0xcc, 0xeb, 0xcf, 0x0a, 0xf6,
+       0x65, 0xf4, 0xbe, 0x02, 0x7d, 0xdc, 0xc5, 0xf4, 0xca, 0xbc, 0x2b, 0x7d,
+       0x74, 0xfe, 0x05, 0xfa, 0xba, 0x67, 0x74, 0x42, 0xbc, 0x5b, 0xf4, 0x7a,
+       0x1f, 0x7f, 0xf2, 0x2c, 0xe9, 0xab, 0x38, 0xc3, 0xe2, 0xdf, 0x0d, 0x78,
+       0x5f, 0x32, 0xfb, 0x06, 0xb4, 0x9e, 0x4f, 0x16, 0xcd, 0xdc, 0x18, 0xdc,
+       0xa1, 0xfd, 0xf1, 0x28, 0xe7, 0x48, 0x3e, 0x05, 0x15, 0xcf, 0x76, 0xf4,
+       0xb6, 0xe2, 0xac, 0x2d, 0xcf, 0xb3, 0x27, 0xd9, 0xcc, 0xae, 0x59, 0xb3,
+       0x3e, 0xc9, 0x05, 0x3a, 0x7d, 0xf7, 0x19, 0xaf, 0xe7, 0x1a, 0x31, 0x59,
+       0x77, 0xa6, 0x8c, 0x1e, 0x1e, 0xc7, 0x57, 0x13, 0x3d, 0xf6, 0x5d, 0x14,
+       0xdc, 0x4b, 0x3b, 0x19, 0xd3, 0x35, 0x57, 0xe6, 0xca, 0xbc, 0x9b, 0x62,
+       0x24, 0xd6, 0xc3, 0xde, 0x2c, 0xf3, 0x21, 0x81, 0xbe, 0xde, 0x13, 0xc8,
+       0x53, 0x74, 0xde, 0xae, 0x34, 0x5f, 0xc1, 0x39, 0x60, 0xe6, 0x43, 0xb4,
+       0xdf, 0x67, 0x51, 0x67, 0xd7, 0xba, 0xd4, 0xa3, 0xe9, 0x9f, 0x97, 0x16,
+       0xe5, 0x1e, 0xb4, 0x9b, 0xb3, 0x1a, 0x73, 0x1d, 0xbe, 0x0f, 0x8a, 0xa8,
+       0x3f, 0x33, 0x0f, 0xdb, 0x7d, 0x07, 0x08, 0x7f, 0x65, 0xf3, 0x3f, 0xdf,
+       0x61, 0xfe, 0xff, 0xb3, 0x39, 0x5f, 0x58, 0xca, 0xa3, 0xa9, 0xd3, 0x60,
+       0x1e, 0x83, 0xf5, 0x1a, 0x9d, 0xc3, 0xcb, 0xcd, 0xdf, 0x1c, 0x74, 0x3e,
+       0x06, 0x9d, 0xe3, 0x94, 0x88, 0xb1, 0x30, 0x6e, 0xfc, 0x14, 0xdb, 0xb5,
+       0x67, 0x6d, 0xa6, 0xbb, 0x89, 0x33, 0x96, 0xc6, 0x9c, 0x7b, 0x46, 0x78,
+       0x71, 0x59, 0x2f, 0x18, 0x3c, 0x7b, 0x4a, 0xbe, 0xfb, 0x6c, 0xfa, 0x0d,
+       0x6d, 0x29, 0x98, 0xe1, 0x30, 0x0d, 0x00, 0x00, 0x00 };
 
 static u8 bnx2_xi_rv2p_proc2[] = {
-       /* Date:        12/07/2007 16:21 */
-       0xad, 0x58, 0x5d, 0x6c, 0xd3, 0x55, 0x14, 0xbf, 0xfd, 0x58, 0xdb, 0xb5,
+       /* Date:        01/14/2008 15:44 */
+       0xad, 0x58, 0x5d, 0x6c, 0xd3, 0x55, 0x14, 0xbf, 0xfd, 0x58, 0xdb, 0x75,
        0xff, 0xb6, 0x63, 0x9b, 0xdd, 0xa7, 0x6e, 0x6e, 0x61, 0x6c, 0xd8, 0xcd,
        0xd1, 0x8d, 0x4f, 0x4d, 0x5c, 0x86, 0x19, 0x20, 0x26, 0x8c, 0x61, 0xd4,
-       0x37, 0xd8, 0x90, 0xb2, 0xb1, 0x8d, 0x2c, 0x8c, 0xf0, 0xc0, 0x8b, 0x0d,
+       0x37, 0xd8, 0x90, 0xb2, 0xb2, 0x8d, 0x2c, 0x8c, 0xf0, 0xc0, 0x8b, 0x0d,
        0xd3, 0xf1, 0xd2, 0x07, 0x47, 0xb2, 0x0d, 0x8d, 0xc1, 0x45, 0x7d, 0x40,
-       0x9f, 0xec, 0x83, 0x32, 0x30, 0xc6, 0xc4, 0xe8, 0x42, 0xf0, 0x01, 0x48,
+       0x9f, 0xec, 0x83, 0x52, 0x30, 0xc6, 0xc4, 0xe8, 0x42, 0xf0, 0x01, 0x48,
        0x30, 0xc6, 0x68, 0x48, 0x08, 0xea, 0x32, 0x10, 0x75, 0x0c, 0xfb, 0x64,
-       0x98, 0xf7, 0x9e, 0xdf, 0xb9, 0xff, 0xfe, 0xff, 0x6d, 0x27, 0x18, 0xec,
+       0x98, 0xf7, 0x9e, 0xdf, 0xb9, 0xff, 0xfe, 0xff, 0x5d, 0x27, 0x18, 0xec,
        0x43, 0x4f, 0xef, 0xbd, 0xe7, 0x9e, 0x7b, 0x3e, 0x7e, 0xe7, 0x9c, 0x7b,
-       0x5b, 0x24, 0x84, 0x70, 0x8a, 0x44, 0xaa, 0x46, 0x52, 0x11, 0x70, 0xb8,
-       0x04, 0x3e, 0x6b, 0x8b, 0x88, 0x5c, 0x4b, 0xf9, 0xe4, 0x77, 0x81, 0x78,
-       0xc9, 0x59, 0x4e, 0x63, 0xb7, 0x50, 0x34, 0x2c, 0x44, 0xc2, 0x4a, 0x4b,
-       0x98, 0x5e, 0x65, 0xfa, 0x3b, 0xd3, 0xc7, 0x1d, 0xa0, 0x57, 0x78, 0xbc,
-       0x85, 0xc7, 0xd7, 0x78, 0xfc, 0x23, 0xd3, 0x8d, 0x3c, 0xbf, 0x99, 0x69,
-       0x92, 0xe9, 0x76, 0x5e, 0x9f, 0x65, 0x2a, 0x3f, 0x09, 0x43, 0x7e, 0xc9,
-       0xe5, 0x26, 0xad, 0xa7, 0x81, 0xe9, 0x26, 0xe8, 0xbb, 0xa7, 0x56, 0xf1,
-       0x2d, 0x2c, 0x67, 0xf8, 0x30, 0x7f, 0x7d, 0x02, 0xb4, 0x06, 0xbb, 0x3e,
-       0x4e, 0x3c, 0xad, 0xf7, 0x83, 0xf4, 0x06, 0x41, 0xfb, 0xd8, 0xfe, 0x8e,
-       0x28, 0x91, 0xe4, 0x7e, 0x27, 0xc6, 0x5d, 0x0d, 0xca, 0x0f, 0xc5, 0xc2,
-       0xed, 0x54, 0x72, 0x5a, 0x7c, 0x9e, 0xf3, 0x98, 0x7f, 0x35, 0x0c, 0xfa,
-       0x9a, 0x1f, 0xf4, 0x17, 0x7f, 0xa1, 0xfc, 0x5e, 0x5e, 0x8e, 0x07, 0x58,
-       0xbe, 0xc1, 0x6a, 0x07, 0xb0, 0x7f, 0xce, 0x80, 0x1e, 0x2f, 0xd7, 0x42,
+       0x5b, 0x2c, 0x84, 0x70, 0x8a, 0x44, 0xaa, 0x56, 0x52, 0x61, 0x38, 0x5c,
+       0x02, 0x9f, 0xb5, 0xc5, 0x44, 0xae, 0xa5, 0x7c, 0xf2, 0xbb, 0x40, 0xbc,
+       0xe4, 0xac, 0xa0, 0xb1, 0x5b, 0x28, 0x1a, 0x12, 0x22, 0x61, 0xa5, 0xa5,
+       0x4c, 0xaf, 0x32, 0xfd, 0x9d, 0xe9, 0xe3, 0x0e, 0xd0, 0x2b, 0x3c, 0xde,
+       0xc2, 0xe3, 0x6b, 0x3c, 0xfe, 0x91, 0xe9, 0x46, 0x9e, 0xdf, 0xcc, 0x34,
+       0xc9, 0x74, 0x3b, 0xaf, 0xa7, 0x99, 0xca, 0x4f, 0xc2, 0x90, 0x5f, 0x72,
+       0xb9, 0x59, 0xeb, 0x69, 0x60, 0xba, 0x19, 0xfa, 0xee, 0xa9, 0x53, 0x7c,
+       0xf3, 0x4b, 0x59, 0x3e, 0xcc, 0x5f, 0x9f, 0x00, 0xad, 0xc5, 0xae, 0x8f,
+       0x13, 0x4f, 0xeb, 0xfd, 0x20, 0x7d, 0x01, 0xd0, 0x7e, 0xb6, 0xbf, 0x33,
+       0x42, 0x24, 0xb9, 0xdf, 0x89, 0x71, 0x77, 0xa3, 0xf2, 0x43, 0x89, 0x70,
+       0x3b, 0x95, 0x9c, 0x56, 0x9f, 0xe7, 0x3c, 0xe6, 0x5f, 0x0d, 0x81, 0xbe,
+       0xe6, 0x07, 0xfd, 0xc5, 0x5f, 0x28, 0xbf, 0x97, 0x96, 0x62, 0x45, 0x2c,
+       0xdf, 0x60, 0xb5, 0x8b, 0xb0, 0x7f, 0xd6, 0x80, 0x1e, 0x2f, 0xd7, 0x41,
        0xbf, 0xef, 0x9f, 0x52, 0xf3, 0x2e, 0x91, 0x60, 0x39, 0x42, 0x68, 0x3d,
-       0x79, 0x7d, 0x10, 0xfb, 0x56, 0xad, 0xc1, 0xea, 0x5b, 0x71, 0x8c, 0xab,
-       0x3e, 0x28, 0xa2, 0xb8, 0x9c, 0x4e, 0x69, 0xfe, 0x7c, 0x72, 0xdd, 0x52,
-       0x2e, 0xe4, 0x8b, 0x3a, 0x1f, 0x29, 0x93, 0x88, 0x82, 0x8a, 0xe6, 0xec,
-       0x73, 0x20, 0x7f, 0x6a, 0xb5, 0x9a, 0x77, 0x8a, 0x1e, 0x97, 0x9a, 0xf7,
-       0x88, 0x9e, 0x01, 0xed, 0x5f, 0xac, 0xc7, 0x3d, 0x44, 0xca, 0x7b, 0xc7,
-       0x95, 0x9d, 0x61, 0xb1, 0xcf, 0x19, 0x26, 0x7e, 0xf8, 0xc5, 0xe5, 0x33,
-       0x3e, 0x03, 0xff, 0x97, 0x35, 0x06, 0xd9, 0x12, 0x6f, 0xc3, 0xbe, 0xd2,
-       0x18, 0xe8, 0x64, 0xac, 0x40, 0x91, 0x68, 0x7c, 0x94, 0x86, 0x2d, 0x37,
-       0xd7, 0xf9, 0x88, 0x2f, 0xd1, 0xac, 0xe3, 0xa7, 0xe3, 0xa5, 0xe2, 0xf8,
-       0x89, 0x8c, 0x23, 0xbb, 0xa5, 0x1e, 0x7e, 0xfd, 0x75, 0xb5, 0xe2, 0x97,
-       0xce, 0xad, 0xc3, 0x39, 0x19, 0xfd, 0xac, 0xf1, 0xff, 0xe8, 0x3f, 0xc4,
-       0x5f, 0xc9, 0xeb, 0x60, 0xbf, 0xd4, 0x4a, 0xbf, 0x28, 0x5a, 0xed, 0x48,
-       0x34, 0xdb, 0xe3, 0x71, 0x7d, 0x22, 0x4c, 0xbf, 0x6f, 0x75, 0x16, 0x91,
-       0x5f, 0x77, 0x61, 0xfe, 0x54, 0xd7, 0x39, 0xc4, 0x63, 0x07, 0xd9, 0x2f,
-       0xfc, 0x6f, 0x7c, 0x8a, 0x5d, 0xbd, 0x41, 0x35, 0x7e, 0xa5, 0x3d, 0x7e,
-       0x01, 0xeb, 0x05, 0x63, 0xf0, 0xeb, 0x2e, 0x96, 0xba, 0xc3, 0xe5, 0x50,
-       0x24, 0xe9, 0x19, 0xa3, 0xa1, 0x31, 0x47, 0xeb, 0x86, 0x38, 0x99, 0xc2,
-       0xfa, 0xe1, 0x80, 0x1a, 0xef, 0x8a, 0x2e, 0x60, 0x1c, 0x1d, 0x18, 0xe7,
-       0x8d, 0x4e, 0xf8, 0xe1, 0x96, 0x13, 0xf2, 0x18, 0x5e, 0x7e, 0x37, 0xc5,
-       0xc1, 0x21, 0x8c, 0x2e, 0xd0, 0x37, 0x69, 0xfd, 0x6f, 0x47, 0x92, 0xec,
-       0xee, 0x0a, 0xb9, 0xcf, 0x81, 0x91, 0x71, 0x6d, 0xe2, 0x56, 0xe3, 0xfe,
-       0x61, 0xf1, 0x3b, 0x6e, 0x68, 0xbc, 0xb2, 0xff, 0xd9, 0xbf, 0xef, 0x89,
-       0x6c, 0x9c, 0x82, 0x76, 0x35, 0x80, 0x7a, 0xea, 0xb3, 0xf1, 0xaa, 0xf1,
-       0x69, 0xf7, 0x33, 0xc7, 0xc7, 0x82, 0x17, 0x22, 0x12, 0x27, 0x36, 0xdc,
-       0x30, 0x4e, 0x2b, 0xa4, 0xbf, 0x74, 0xfc, 0x95, 0x20, 0xaf, 0x18, 0x64,
-       0x79, 0x03, 0x6c, 0xd7, 0x10, 0xdb, 0x75, 0xc7, 0xaf, 0xfd, 0xaa, 0xed,
-       0x01, 0x3d, 0x69, 0xb3, 0xc7, 0x21, 0xf1, 0x64, 0xc7, 0x21, 0xeb, 0x93,
-       0xfc, 0xa6, 0x0e, 0x3f, 0xaa, 0xea, 0x41, 0x4d, 0x3b, 0x1b, 0x14, 0x9f,
-       0x27, 0x36, 0x9d, 0xb2, 0xe3, 0x50, 0xe7, 0xe3, 0x9e, 0x5a, 0x2d, 0x5f,
-       0xe1, 0x32, 0x2d, 0x71, 0x89, 0xb8, 0x9d, 0x4e, 0x59, 0xf3, 0xb3, 0x32,
-       0x4f, 0x7e, 0xda, 0xf3, 0x42, 0xfb, 0xe5, 0x70, 0x90, 0x0a, 0x54, 0xfb,
-       0xe5, 0x79, 0xfb, 0x79, 0xc0, 0xb7, 0xd7, 0xc4, 0x4f, 0xe9, 0x06, 0xf6,
-       0x1f, 0xd3, 0xc8, 0x46, 0x25, 0xaf, 0x9b, 0xe5, 0xb7, 0xb2, 0x7c, 0xc3,
-       0x92, 0x77, 0x4a, 0xbf, 0x4e, 0x33, 0xdf, 0x74, 0xdc, 0x32, 0x79, 0xa7,
-       0xfd, 0x47, 0xe7, 0x47, 0x2f, 0xcf, 0xab, 0xfd, 0x55, 0x0f, 0xc8, 0xc3,
-       0x4d, 0xa6, 0xbc, 0xef, 0xcc, 0x7c, 0x53, 0xeb, 0x01, 0xf1, 0x1c, 0x0f,
-       0xed, 0xf5, 0xe4, 0x4f, 0x59, 0x4f, 0xc8, 0x0e, 0x9f, 0x71, 0x8e, 0xeb,
-       0xc7, 0xa8, 0x3a, 0xa7, 0x9c, 0xf5, 0x2e, 0x67, 0xbd, 0x65, 0xbf, 0x6a,
-       0xe6, 0x3a, 0xb3, 0xd7, 0x5a, 0x2f, 0xd6, 0x5a, 0xf2, 0x5e, 0x8d, 0x1b,
-       0x97, 0x73, 0xfb, 0x85, 0xcd, 0x9f, 0x09, 0x41, 0xfe, 0xf7, 0x72, 0x7c,
+       0x79, 0x7d, 0x10, 0xfb, 0x56, 0xad, 0xc1, 0xea, 0x5b, 0x31, 0x8c, 0xab,
+       0x3f, 0x28, 0xa6, 0xb8, 0x9c, 0x4e, 0x69, 0xfe, 0x7c, 0x72, 0xdd, 0x52,
+       0x2e, 0xe4, 0x8b, 0x7a, 0x1f, 0x29, 0x93, 0x88, 0x80, 0x8a, 0x96, 0xdc,
+       0x73, 0x20, 0x7f, 0x6a, 0xb5, 0x9a, 0x77, 0x8a, 0x5e, 0x97, 0x9a, 0xf7,
+       0x88, 0xde, 0xb8, 0xf6, 0x2f, 0xd6, 0x63, 0x1e, 0x22, 0x15, 0x7d, 0xe3,
+       0xca, 0xce, 0x90, 0xd8, 0xe7, 0x0c, 0x11, 0x3f, 0xfc, 0xe2, 0xf2, 0x19,
+       0x9f, 0x81, 0xff, 0xcb, 0x5a, 0x83, 0x6c, 0x89, 0xb5, 0x63, 0x5f, 0x59,
+       0x14, 0x74, 0x32, 0x5a, 0xa0, 0x48, 0x24, 0x36, 0x4a, 0xc3, 0xd6, 0x9b,
+       0xeb, 0x7c, 0xc4, 0x97, 0x68, 0xd1, 0xf1, 0xd3, 0xf1, 0x52, 0x71, 0xfc,
+       0x44, 0xc6, 0x91, 0xdd, 0xd2, 0x00, 0xbf, 0xfe, 0xba, 0x5a, 0xf1, 0x4b,
+       0xe7, 0xd6, 0xe3, 0x9c, 0xac, 0x7e, 0xd6, 0xf8, 0x7f, 0xf4, 0x1f, 0xe2,
+       0xaf, 0xe4, 0x75, 0xb2, 0x5f, 0xea, 0xa4, 0x5f, 0x14, 0xad, 0x71, 0x24,
+       0x5a, 0xec, 0xf1, 0xb8, 0x3e, 0x11, 0xa2, 0xdf, 0xb7, 0xba, 0x8a, 0xc9,
+       0xaf, 0xbb, 0x30, 0x7f, 0xaa, 0xfb, 0x1c, 0xe2, 0xb1, 0x83, 0xec, 0x17,
+       0xfe, 0x37, 0x3e, 0xc5, 0xae, 0xbe, 0x80, 0x1a, 0xbf, 0xd2, 0x11, 0xbb,
+       0x80, 0xf5, 0x82, 0x31, 0xf8, 0x75, 0x17, 0x4b, 0xdd, 0xe1, 0x72, 0x28,
+       0x92, 0xf4, 0x8c, 0xd1, 0xd0, 0x98, 0xa5, 0x75, 0x43, 0x9c, 0x4c, 0x61,
+       0xfd, 0x70, 0x91, 0x1a, 0xef, 0x8a, 0xcc, 0x63, 0x1c, 0x89, 0x8f, 0xf3,
+       0x46, 0x27, 0xfc, 0x70, 0xcb, 0x09, 0x79, 0x0c, 0x2f, 0xbf, 0x9b, 0xe2,
+       0xe0, 0x10, 0x46, 0x37, 0xe8, 0x9b, 0xb4, 0xfe, 0xb7, 0x23, 0x49, 0x76,
+       0x77, 0x07, 0xdd, 0xe7, 0xc0, 0xc8, 0xb8, 0x36, 0x71, 0xab, 0x71, 0xff,
+       0xb0, 0xf8, 0x1d, 0x37, 0x34, 0x5e, 0xd9, 0xff, 0xec, 0xdf, 0xf7, 0x44,
+       0x2e, 0x4e, 0x41, 0xbb, 0x1b, 0x41, 0x3d, 0x0d, 0xb9, 0x78, 0xd5, 0xf8,
+       0xb4, 0xfb, 0x99, 0xe3, 0x63, 0xc1, 0x0b, 0x11, 0x89, 0x13, 0x1b, 0x6e,
+       0x18, 0xa7, 0x95, 0xd2, 0x5f, 0x3a, 0xfe, 0x4a, 0x90, 0x57, 0x0c, 0xb2,
+       0xbc, 0x38, 0xdb, 0x35, 0xc4, 0x76, 0xdd, 0xf1, 0x6b, 0xbf, 0x6a, 0x7b,
+       0x40, 0x4f, 0xda, 0xec, 0x71, 0x48, 0x3c, 0xd9, 0x71, 0xc8, 0xfa, 0x24,
+       0xbf, 0xa9, 0xc7, 0x8f, 0xea, 0x06, 0x50, 0xd3, 0xce, 0x46, 0xc5, 0xe7,
+       0x89, 0x4e, 0xa7, 0xec, 0x38, 0xd4, 0xf9, 0xb8, 0xa7, 0x4e, 0xcb, 0x57,
+       0xb8, 0xcc, 0x48, 0x5c, 0x22, 0x6e, 0xa7, 0x53, 0xd6, 0xfc, 0xac, 0xca,
+       0x93, 0x9f, 0xf6, 0xbc, 0xd0, 0x7e, 0x39, 0x1c, 0xa0, 0x02, 0xd5, 0x71,
+       0x79, 0xce, 0x7e, 0x1e, 0xf0, 0xed, 0x35, 0xf1, 0x53, 0xb6, 0x81, 0xfd,
+       0xc7, 0x34, 0xbc, 0x51, 0xc9, 0xeb, 0x61, 0xf9, 0x6d, 0x2c, 0xdf, 0xb0,
+       0xe4, 0x9d, 0xd2, 0xaf, 0xcb, 0xcc, 0x37, 0x1d, 0xb7, 0x6c, 0xde, 0x69,
+       0xff, 0xd1, 0xf9, 0x91, 0xcb, 0x73, 0x6a, 0x7f, 0xf5, 0x03, 0xf2, 0x70,
+       0x93, 0x29, 0xef, 0x3b, 0x33, 0xdf, 0xd4, 0x7a, 0x91, 0x78, 0x8e, 0x87,
+       0xf6, 0x7a, 0xf2, 0xa7, 0xac, 0x27, 0x64, 0x87, 0xcf, 0x38, 0xc7, 0xf5,
+       0x63, 0x54, 0x9d, 0x53, 0xc1, 0x7a, 0x57, 0xb0, 0xde, 0xb2, 0x5f, 0xb5,
+       0x70, 0x9d, 0xd9, 0x6b, 0xad, 0x17, 0x6b, 0x2d, 0x79, 0xaf, 0xc6, 0x4d,
+       0x4b, 0xcb, 0xfb, 0x85, 0xcd, 0x9f, 0x09, 0x41, 0xfe, 0xf7, 0x72, 0x7c,
        0x3c, 0x79, 0xfa, 0x8b, 0xe6, 0x07, 0xbe, 0xb6, 0x11, 0xbf, 0xcf, 0xc4,
-       0xbf, 0xdd, 0xde, 0xca, 0x3c, 0x75, 0x27, 0xdb, 0x7e, 0xf8, 0xb3, 0xd7,
-       0x19, 0x24, 0xbe, 0x1b, 0x23, 0x6a, 0xdf, 0x49, 0x87, 0xf6, 0x53, 0x07,
-       0xea, 0x90, 0x03, 0xf6, 0x56, 0xb3, 0xbd, 0x72, 0xb9, 0x99, 0xf0, 0xef,
+       0xbf, 0xdd, 0xde, 0xaa, 0x3c, 0x75, 0x27, 0xd7, 0x7e, 0xf8, 0xb3, 0xcf,
+       0x19, 0x20, 0xbe, 0x1b, 0x23, 0x6a, 0xdf, 0x49, 0x87, 0xf6, 0x53, 0x27,
+       0xea, 0x90, 0x03, 0xf6, 0xd6, 0xb0, 0xbd, 0x72, 0xb9, 0x85, 0xf0, 0xef,
        0xbb, 0x31, 0x62, 0xb5, 0xd7, 0xf8, 0x97, 0xf3, 0xec, 0xb8, 0x19, 0xe1,
-       0x3e, 0xd6, 0x87, 0xbc, 0xf0, 0xed, 0xff, 0x5c, 0xeb, 0xc3, 0xe7, 0x86,
-       0xf5, 0xf9, 0x4a, 0x5e, 0x95, 0x98, 0x1f, 0x55, 0xfb, 0x1f, 0x13, 0x0c,
-       0x33, 0x31, 0xdc, 0x88, 0xfa, 0x77, 0xe7, 0x00, 0xf4, 0x1f, 0x6e, 0xd0,
+       0x3e, 0xd6, 0x8f, 0xbc, 0xf0, 0xed, 0xff, 0x5c, 0xeb, 0xc3, 0xe7, 0x86,
+       0xf4, 0xf9, 0x4a, 0x5e, 0xb5, 0x98, 0x1b, 0x55, 0xfb, 0x1f, 0x13, 0x0c,
+       0x33, 0x31, 0xdc, 0x84, 0xfa, 0x77, 0xe7, 0x00, 0xf4, 0x1f, 0x6e, 0xd4,
        0x7d, 0x1c, 0x38, 0x16, 0x5c, 0xff, 0xbf, 0x9e, 0xc8, 0xe7, 0x97, 0x41,
-       0x07, 0xf8, 0x4a, 0xd9, 0xae, 0x22, 0xb6, 0x2b, 0x2a, 0xb2, 0xeb, 0xec,
-       0x5e, 0xca, 0x97, 0x0e, 0xe6, 0x7b, 0x56, 0xd7, 0xe3, 0x1c, 0x3e, 0xd8,
-       0x5f, 0xc0, 0xe7, 0xe7, 0xf3, 0x57, 0x3e, 0xb9, 0xb3, 0x8c, 0xa3, 0x7e,
-       0xe6, 0x73, 0xe7, 0xa9, 0xf3, 0x18, 0xa5, 0xd7, 0x50, 0x9d, 0x3f, 0x73,
-       0x7c, 0x56, 0xf1, 0x05, 0x4d, 0x9c, 0xdb, 0xed, 0xfa, 0xe9, 0xfe, 0xa3,
-       0xfb, 0x5f, 0xf1, 0x45, 0xc4, 0xc1, 0xd0, 0x4a, 0x7e, 0x76, 0xab, 0xe9,
-       0x99, 0xc5, 0x59, 0x1d, 0x27, 0x83, 0xec, 0x9c, 0x1f, 0x55, 0xe7, 0x7f,
-       0x98, 0xe5, 0x7f, 0xa7, 0xc5, 0xff, 0xe0, 0x7f, 0x22, 0xfa, 0xa8, 0x7e,
-       0xcf, 0xd7, 0x97, 0xbf, 0xb8, 0x9f, 0x9b, 0x27, 0x6a, 0xfe, 0xc2, 0x43,
-       0xfb, 0x63, 0x77, 0x9b, 0xd5, 0xfe, 0x7a, 0x31, 0x97, 0x42, 0x7e, 0x75,
-       0x33, 0x0e, 0xf7, 0x71, 0xbd, 0xbe, 0xe1, 0x57, 0x13, 0x3e, 0xd1, 0xb7,
-       0x93, 0xfc, 0x21, 0x22, 0x01, 0xf8, 0xa7, 0xef, 0x45, 0xed, 0x4f, 0xcc,
-       0x57, 0x52, 0xbf, 0x75, 0x89, 0x6e, 0xaf, 0x41, 0xfc, 0x95, 0x41, 0xd0,
-       0x08, 0xd7, 0xf9, 0x39, 0xb3, 0x8f, 0x81, 0x9e, 0xf6, 0xe8, 0xba, 0x8c,
-       0x7e, 0xfe, 0x95, 0x47, 0x31, 0xc8, 0x20, 0x35, 0xa1, 0x3e, 0x77, 0x36,
-       0x18, 0xb4, 0xde, 0xd3, 0x04, 0x3c, 0x89, 0x3a, 0xdd, 0xe7, 0xf0, 0xe1,
-       0x3e, 0x50, 0x99, 0xe9, 0x77, 0xd6, 0x7e, 0x58, 0x68, 0xe9, 0x07, 0xfa,
+       0x07, 0xf8, 0xca, 0xd8, 0xae, 0x62, 0xb6, 0x2b, 0x22, 0x72, 0xeb, 0xec,
+       0x5e, 0xca, 0x97, 0x4e, 0xe6, 0x7b, 0x56, 0xd7, 0xe3, 0x65, 0x7c, 0xb0,
+       0xbf, 0x80, 0xcf, 0xcf, 0xe7, 0xaf, 0x7c, 0x72, 0xd3, 0x8c, 0xa3, 0x01,
+       0xe6, 0x73, 0xe7, 0xa9, 0xf3, 0x18, 0x65, 0xd6, 0x50, 0x9d, 0x3f, 0x73,
+       0x3c, 0xad, 0xf8, 0x02, 0x26, 0xce, 0xed, 0x76, 0xfd, 0x74, 0xff, 0xd1,
+       0xfd, 0xaf, 0xf8, 0xc2, 0xe2, 0x60, 0x70, 0x25, 0x3f, 0xbb, 0xd5, 0xf4,
+       0xcc, 0x42, 0x5a, 0xc7, 0xc9, 0x20, 0x3b, 0xe7, 0x46, 0xd5, 0xf9, 0x1f,
+       0xe6, 0xf8, 0xdf, 0x69, 0xf1, 0x3f, 0xf8, 0x9f, 0x88, 0x3c, 0xaa, 0xdf,
+       0xf3, 0xf5, 0xe5, 0x2f, 0xee, 0x2f, 0xcf, 0x13, 0x35, 0x7f, 0xe1, 0xa1,
+       0xfd, 0xb1, 0xbb, 0xdd, 0x6a, 0x7f, 0x83, 0x98, 0x4d, 0x21, 0xbf, 0x7a,
+       0x18, 0x87, 0xfb, 0xb8, 0x5e, 0xdf, 0xf0, 0xab, 0x09, 0x9f, 0xe8, 0xdf,
+       0x49, 0xfe, 0x10, 0xe1, 0x22, 0xf8, 0xa7, 0xff, 0x45, 0xed, 0x4f, 0xcc,
+       0x57, 0x51, 0xbf, 0x75, 0x89, 0x1e, 0xaf, 0x41, 0xfc, 0x55, 0x01, 0xd0,
+       0x30, 0xd7, 0xf9, 0x59, 0xb3, 0x8f, 0x81, 0x9e, 0xf6, 0xe8, 0xba, 0x8c,
+       0x7e, 0xfe, 0x95, 0x47, 0x31, 0xc8, 0x20, 0x35, 0xa3, 0x3e, 0x77, 0x35,
+       0x1a, 0xb4, 0xde, 0xdb, 0x0c, 0x3c, 0x89, 0x7a, 0xdd, 0xe7, 0xf0, 0xe1,
+       0x3e, 0x50, 0x95, 0xed, 0x77, 0xd6, 0x7e, 0x58, 0x68, 0xe9, 0x07, 0xfa,
        0x3c, 0xed, 0x47, 0x2d, 0x97, 0x86, 0xb2, 0xaf, 0x58, 0xfb, 0xa1, 0xee,
-       0x13, 0x4b, 0xdc, 0x27, 0x4a, 0xc4, 0xc5, 0x14, 0xec, 0x9a, 0x4b, 0x65,
-       0xe3, 0x4f, 0x9f, 0xa7, 0xe5, 0x41, 0x6f, 0x6d, 0x47, 0x46, 0x3e, 0xce,
-       0x3f, 0xc0, 0x7a, 0xfe, 0x4c, 0xf7, 0xd8, 0x08, 0xdb, 0xa3, 0xe4, 0x62,
-       0x7e, 0x3b, 0xf7, 0xe7, 0x84, 0x39, 0xb6, 0xf7, 0xd5, 0x6e, 0xd2, 0xab,
-       0x98, 0xf1, 0x16, 0xb1, 0xe4, 0x03, 0xf8, 0x4b, 0x5b, 0x41, 0x27, 0x5b,
-       0x75, 0x1c, 0x74, 0xbc, 0x74, 0x7c, 0x10, 0xc7, 0xc8, 0x3a, 0x62, 0x6b,
-       0xef, 0x5b, 0x47, 0x7d, 0xa4, 0xb5, 0x6f, 0x51, 0xe3, 0x0f, 0xfb, 0x77,
-       0x47, 0x15, 0xff, 0xeb, 0xe2, 0x2a, 0xe1, 0x50, 0x88, 0x1f, 0x98, 0x66,
-       0xfa, 0x15, 0x07, 0xc0, 0xcc, 0x57, 0x8e, 0x5f, 0x01, 0x4f, 0xb7, 0xe9,
-       0x7a, 0xae, 0xe3, 0x65, 0xcd, 0xd7, 0x78, 0x0e, 0x6e, 0x33, 0x75, 0x59,
-       0xdb, 0xa9, 0xf8, 0xa3, 0x8c, 0x47, 0x9f, 0xe8, 0xdc, 0x86, 0x7b, 0x6e,
-       0xc8, 0x8b, 0xba, 0x1f, 0xf2, 0x5a, 0xe3, 0x25, 0x71, 0x51, 0xe8, 0x55,
-       0xc3, 0xea, 0xe2, 0x42, 0xb2, 0xe7, 0xd4, 0xa5, 0x6f, 0x69, 0xf9, 0xfd,
-       0xe9, 0x00, 0xe6, 0xcb, 0x76, 0x86, 0xc9, 0x1f, 0x53, 0xc0, 0xf3, 0xbb,
-       0x93, 0xa0, 0xef, 0x88, 0x17, 0xb0, 0xbf, 0xf8, 0x04, 0xdd, 0x03, 0x7d,
-       0x65, 0x8c, 0xcf, 0x72, 0xd4, 0x89, 0xe4, 0x34, 0xdd, 0x4b, 0x96, 0x97,
-       0x45, 0x50, 0x51, 0x8f, 0xd9, 0x6f, 0x80, 0x4f, 0xb7, 0x25, 0xce, 0x0f,
-       0xc2, 0x2b, 0xdd, 0x2b, 0x25, 0x1e, 0xb1, 0x9d, 0x71, 0xeb, 0xcb, 0xc6,
-       0xad, 0xf6, 0x47, 0xb9, 0x33, 0x2f, 0x4e, 0x37, 0xd8, 0x71, 0xea, 0x61,
-       0x9c, 0xde, 0x33, 0xfb, 0x7b, 0xae, 0x5c, 0xf4, 0xf9, 0x8b, 0xff, 0x1b,
-       0x6e, 0x41, 0xb7, 0xd7, 0xab, 0xf3, 0xcb, 0x72, 0xea, 0x71, 0x8d, 0x2d,
-       0xce, 0x4d, 0xf7, 0xb5, 0x5e, 0x27, 0x3c, 0xd6, 0xf5, 0x66, 0xb3, 0x9f,
-       0x1d, 0xe1, 0x77, 0x5e, 0xda, 0xa0, 0x1f, 0xb1, 0x3b, 0x49, 0x1a, 0x1a,
-       0x15, 0x67, 0x15, 0x5f, 0x63, 0xec, 0x08, 0xd7, 0xdb, 0x4b, 0x2e, 0xd4,
-       0x9b, 0xfe, 0x03, 0x18, 0x5f, 0xe6, 0xfa, 0x71, 0x77, 0x0d, 0xd5, 0xe5,
-       0xd8, 0x91, 0xf3, 0x5a, 0x1e, 0xc9, 0x31, 0xd2, 0x5c, 0xd7, 0x9f, 0x77,
-       0x71, 0xbd, 0x25, 0xbf, 0xb9, 0x63, 0x7f, 0xd0, 0x7d, 0xc6, 0x2d, 0x3a,
-       0x9f, 0x54, 0xb4, 0x42, 0xd6, 0x6f, 0x3e, 0xff, 0x19, 0xd0, 0x1e, 0x2f,
-       0xa8, 0x68, 0xb2, 0xc7, 0x43, 0x98, 0x76, 0x61, 0xe4, 0xa9, 0x63, 0x39,
-       0xbd, 0x18, 0x7b, 0xf9, 0x5e, 0x36, 0xcd, 0x7e, 0x0a, 0x91, 0x3f, 0x8a,
-       0xa4, 0x9d, 0x8a, 0x86, 0x63, 0xa3, 0xb3, 0xd0, 0x7f, 0x68, 0x2b, 0xec,
-       0x5b, 0x62, 0xbb, 0x99, 0x86, 0xde, 0x1e, 0x23, 0xfc, 0x85, 0xc6, 0xf1,
-       0x0e, 0x09, 0x79, 0xc6, 0x60, 0xc7, 0x50, 0x1a, 0xe3, 0xa5, 0xcd, 0xa0,
-       0x7f, 0x6d, 0xc1, 0xbe, 0xa3, 0xc7, 0xd9, 0x1f, 0x5b, 0xf3, 0xef, 0xeb,
-       0xbf, 0x07, 0xbe, 0xe1, 0x46, 0x75, 0xfe, 0xe0, 0x0c, 0xbf, 0x5f, 0xc4,
-       0x80, 0x4b, 0x8d, 0x07, 0x8c, 0x34, 0x8f, 0x0f, 0x71, 0x7d, 0xbf, 0xcd,
-       0xef, 0x8d, 0xa1, 0xac, 0xf7, 0xc6, 0x02, 0xee, 0x99, 0x33, 0xe9, 0x24,
-       0x70, 0x91, 0x28, 0xcc, 0x7e, 0xaf, 0xaa, 0x71, 0x75, 0xac, 0x8c, 0xe3,
-       0x54, 0xba, 0x1e, 0x74, 0x72, 0x3d, 0xde, 0x09, 0x43, 0xc7, 0xd8, 0x2f,
-       0xed, 0x14, 0xa7, 0x96, 0xc5, 0xd9, 0x95, 0xde, 0xc9, 0xe0, 0x9b, 0xe2,
-       0x73, 0x23, 0xdc, 0x4f, 0x22, 0xc8, 0x3f, 0x51, 0x9e, 0xe4, 0x77, 0xcb,
-       0x04, 0xee, 0x9d, 0x53, 0x06, 0x68, 0x24, 0xa8, 0xf5, 0x45, 0x3e, 0x26,
-       0x52, 0xc8, 0x3b, 0xac, 0x3b, 0x2c, 0xeb, 0x7c, 0x1f, 0xc9, 0x79, 0xe7,
-       0x28, 0xba, 0xe4, 0x28, 0x71, 0x68, 0x3b, 0xb1, 0xda, 0x17, 0x54, 0xf8,
-       0xbd, 0x69, 0xe6, 0xd5, 0x02, 0xf9, 0xad, 0x6a, 0x26, 0x4d, 0xfa, 0x57,
-       0x8a, 0x12, 0xea, 0xc3, 0x15, 0xa1, 0x45, 0xf8, 0x31, 0x36, 0xcd, 0xfe,
-       0x1f, 0xd9, 0x04, 0x7a, 0x8c, 0xf1, 0xa7, 0x71, 0x75, 0x65, 0xa3, 0x41,
-       0xfb, 0xe6, 0x47, 0x71, 0x8e, 0xbe, 0x47, 0x64, 0xbf, 0xc7, 0x35, 0x1e,
-       0x2b, 0xda, 0x50, 0x48, 0xfb, 0x8f, 0xaa, 0x73, 0x82, 0x12, 0x47, 0x4a,
-       0x7f, 0xe9, 0x13, 0xce, 0x47, 0x3b, 0x4e, 0x15, 0x8e, 0x75, 0x7e, 0x58,
-       0xf1, 0x9d, 0x9d, 0xef, 0x19, 0xbc, 0x86, 0xe8, 0x5e, 0x2e, 0x8b, 0x5c,
-       0x82, 0xdf, 0x4d, 0x7c, 0x3f, 0x58, 0x29, 0x7e, 0x6f, 0x23, 0x7e, 0x31,
-       0xd6, 0xdb, 0x18, 0x18, 0x43, 0x5f, 0x1c, 0x67, 0x1c, 0x2d, 0x34, 0xf2,
-       0xfd, 0x87, 0xf5, 0xfb, 0x8d, 0xdf, 0x67, 0xc0, 0x9b, 0xd7, 0x88, 0xcf,
-       0x32, 0xbe, 0x18, 0xf7, 0x87, 0xd8, 0xee, 0xdb, 0xb0, 0xdb, 0xd0, 0x76,
-       0x0f, 0x98, 0x76, 0xeb, 0xfb, 0x95, 0x55, 0x4e, 0xb1, 0xc4, 0xad, 0xa2,
-       0xab, 0x8c, 0x2b, 0x54, 0xcf, 0x0a, 0xd8, 0x4e, 0xc9, 0xd7, 0xa6, 0xec,
-       0x09, 0xb1, 0x3d, 0x41, 0x71, 0xb0, 0xc5, 0xba, 0x2f, 0xc0, 0xfb, 0xfc,
-       0x72, 0x1f, 0xe6, 0x51, 0x17, 0x8c, 0x15, 0xfc, 0xa9, 0xfc, 0xa6, 0xe5,
-       0x66, 0xe7, 0xbd, 0xd5, 0x7f, 0x74, 0x23, 0xa5, 0x0f, 0xea, 0x9b, 0x8c,
-       0x53, 0x33, 0xfe, 0x3f, 0xd0, 0xf5, 0xed, 0x2e, 0xdd, 0x5f, 0xfd, 0x67,
-       0x86, 0x51, 0x9f, 0xce, 0x0c, 0x9f, 0xe5, 0x77, 0x07, 0xfb, 0xa5, 0x9b,
-       0xfe, 0xb7, 0x90, 0xb1, 0xab, 0xb3, 0xd7, 0x37, 0xbb, 0x1e, 0x55, 0x16,
-       0x3d, 0xf4, 0xb9, 0xff, 0x00, 0x0e, 0x4b, 0x7c, 0x26, 0x30, 0x14, 0x00,
+       0x13, 0x8b, 0xdc, 0x27, 0x4a, 0xc5, 0xc5, 0x14, 0xec, 0x9a, 0x4d, 0xe5,
+       0xe2, 0x4f, 0x9f, 0xa7, 0xe5, 0x41, 0x6f, 0x6d, 0x47, 0x56, 0x3e, 0xce,
+       0x3f, 0xc0, 0x7a, 0xfe, 0x4c, 0xf7, 0xd8, 0x30, 0xdb, 0xa3, 0xe4, 0x62,
+       0x7e, 0x3b, 0xf7, 0xe7, 0x84, 0x39, 0xb6, 0xf7, 0xd5, 0x1e, 0xd2, 0xab,
+       0x84, 0xf1, 0x16, 0xb6, 0xe4, 0x03, 0xf8, 0xcb, 0xda, 0x40, 0x27, 0xdb,
+       0x74, 0x1c, 0x74, 0xbc, 0x74, 0x7c, 0x10, 0xc7, 0xf0, 0x3a, 0x62, 0xeb,
+       0xe8, 0x5f, 0x47, 0x7d, 0xa4, 0xad, 0x7f, 0x41, 0xe3, 0x0f, 0xfb, 0x77,
+       0x47, 0x14, 0xff, 0xeb, 0xe2, 0x2a, 0xe1, 0x50, 0x88, 0x1f, 0x98, 0x66,
+       0xfb, 0x15, 0x07, 0xc0, 0xcc, 0x57, 0x8e, 0x5f, 0x01, 0x4f, 0xb7, 0xeb,
+       0x7a, 0xae, 0xe3, 0x65, 0xcd, 0xd7, 0xd8, 0x32, 0xdc, 0x66, 0xeb, 0xb2,
+       0xb6, 0x53, 0xf1, 0x47, 0x18, 0x8f, 0x3e, 0xd1, 0xb5, 0x0d, 0xf7, 0xdc,
+       0xa0, 0x17, 0x75, 0x3f, 0xe8, 0xb5, 0xc6, 0x4b, 0xe2, 0xa2, 0xd0, 0xab,
+       0x86, 0x35, 0x25, 0x85, 0x64, 0xcf, 0xa9, 0x4b, 0xdf, 0xd2, 0xf2, 0xfb,
+       0xd3, 0x45, 0x98, 0x2f, 0xdf, 0x19, 0x22, 0x7f, 0x4c, 0x01, 0xcf, 0xef,
+       0x4e, 0x82, 0xbe, 0x23, 0x5e, 0xc0, 0xfe, 0x92, 0x13, 0x74, 0x0f, 0xf4,
+       0x95, 0x33, 0x3e, 0x2b, 0x50, 0x27, 0x92, 0xd3, 0x74, 0x2f, 0x59, 0x5a,
+       0x12, 0x01, 0x45, 0x3d, 0x66, 0xbf, 0x01, 0x3e, 0xdd, 0x96, 0x38, 0x3f,
+       0x08, 0xaf, 0x74, 0xaf, 0x94, 0x78, 0xc4, 0x76, 0xc6, 0xad, 0x2f, 0x17,
+       0xb7, 0xda, 0x1f, 0x15, 0xce, 0xbc, 0x38, 0xdd, 0x60, 0xc7, 0xa9, 0x87,
+       0x71, 0x7a, 0xcf, 0xec, 0xef, 0xcb, 0xe5, 0xa2, 0xcf, 0x5f, 0xfc, 0xdf,
+       0x70, 0x0b, 0xba, 0xbd, 0x41, 0x9d, 0x5f, 0xbe, 0xac, 0x1e, 0xd7, 0xda,
+       0xe2, 0xdc, 0x7c, 0x5f, 0xeb, 0x75, 0xc2, 0x63, 0x5d, 0x6f, 0x31, 0xfb,
+       0xd9, 0x11, 0x7e, 0xe7, 0x65, 0x0c, 0xfa, 0x11, 0xbd, 0x93, 0xa4, 0xa1,
+       0x51, 0x79, 0x56, 0xf1, 0x35, 0x45, 0x8f, 0x70, 0xbd, 0xbd, 0xe4, 0x42,
+       0xbd, 0x19, 0x38, 0x80, 0xf1, 0x65, 0xae, 0x1f, 0x77, 0xd7, 0x50, 0x5d,
+       0x8e, 0x1e, 0x39, 0xaf, 0xe5, 0x91, 0x1c, 0x23, 0xc3, 0x75, 0xfd, 0x79,
+       0x17, 0xd7, 0x5b, 0xf2, 0x9b, 0x3b, 0xfa, 0x07, 0xdd, 0x67, 0xdc, 0xa2,
+       0xeb, 0x49, 0x45, 0x2b, 0x65, 0xfd, 0xe6, 0xf3, 0x9f, 0x01, 0xed, 0xf5,
+       0x82, 0x8a, 0x66, 0x7b, 0x3c, 0x84, 0x69, 0x17, 0x46, 0x9e, 0x7a, 0x96,
+       0xd3, 0x87, 0xb1, 0x97, 0xef, 0x65, 0xd3, 0xec, 0xa7, 0x20, 0xf9, 0xa3,
+       0x58, 0xda, 0xa9, 0x68, 0x28, 0x3a, 0x9a, 0x86, 0xfe, 0x43, 0x5b, 0x61,
+       0xdf, 0x22, 0xdb, 0xcd, 0x34, 0xf8, 0xf6, 0x18, 0xe1, 0x2f, 0x38, 0x8e,
+       0x77, 0x48, 0xd0, 0x33, 0x06, 0x3b, 0x86, 0x32, 0x18, 0x2f, 0x6e, 0x06,
+       0xfd, 0x6b, 0x0b, 0xf6, 0x1d, 0x3d, 0xce, 0xfe, 0xd8, 0x9a, 0x7f, 0xdf,
+       0xc0, 0x3d, 0xf0, 0x0d, 0x37, 0xa9, 0xf3, 0x07, 0x67, 0xf8, 0xfd, 0x22,
+       0xe2, 0x2e, 0x35, 0x8e, 0x1b, 0x19, 0x1e, 0x1f, 0xe2, 0xfa, 0x7e, 0x9b,
+       0xdf, 0x1b, 0x43, 0x39, 0xef, 0x8d, 0x79, 0xdc, 0x33, 0x67, 0x32, 0x49,
+       0xe0, 0x22, 0x51, 0x98, 0xfb, 0x5e, 0x55, 0xe3, 0x9a, 0x68, 0x39, 0xc7,
+       0xa9, 0x6c, 0x3d, 0xe8, 0xe4, 0x7a, 0xbc, 0x13, 0x86, 0x8e, 0xb1, 0x5f,
+       0x3a, 0x28, 0x4e, 0xad, 0x0b, 0xe9, 0x95, 0xde, 0xc9, 0xe0, 0x9b, 0xe2,
+       0x73, 0xc3, 0xdc, 0x4f, 0xc2, 0xc8, 0x3f, 0x51, 0x91, 0xe4, 0x77, 0xcb,
+       0x04, 0xee, 0x9d, 0x53, 0x06, 0x68, 0x38, 0xa0, 0xf5, 0x45, 0x3e, 0x26,
+       0x52, 0xc8, 0x3b, 0xac, 0x3b, 0x2c, 0xeb, 0x7c, 0x1f, 0x59, 0xf6, 0xce,
+       0x51, 0x74, 0xd1, 0x51, 0xea, 0xd0, 0x76, 0x62, 0xb5, 0x3f, 0xa0, 0xf0,
+       0x7b, 0xd3, 0xcc, 0xab, 0x79, 0xf2, 0x5b, 0xf5, 0x4c, 0x86, 0xf4, 0xaf,
+       0x12, 0xa5, 0xd4, 0x87, 0x2b, 0x83, 0x0b, 0xf0, 0x63, 0x74, 0x9a, 0xfd,
+       0x3f, 0xb2, 0x09, 0xf4, 0x18, 0xe3, 0x4f, 0xe3, 0xea, 0xca, 0x46, 0x83,
+       0xf6, 0xcd, 0x8d, 0xe2, 0x1c, 0x7d, 0x8f, 0xc8, 0x7d, 0x8f, 0x6b, 0x3c,
+       0x56, 0xb6, 0xa3, 0x90, 0x0e, 0x1c, 0x55, 0xe7, 0x04, 0x24, 0x8e, 0x94,
+       0xfe, 0xd2, 0x27, 0x9c, 0x8f, 0x76, 0x9c, 0x2a, 0x1c, 0xeb, 0xfc, 0xb0,
+       0xe2, 0x3b, 0x37, 0xdf, 0xb3, 0x78, 0x0d, 0xd2, 0xbd, 0x5c, 0x16, 0xb9,
+       0x04, 0xbf, 0x9b, 0xf8, 0x7e, 0xb0, 0x52, 0xfc, 0xde, 0x46, 0xfc, 0xa2,
+       0xac, 0xb7, 0x11, 0x1f, 0x43, 0x5f, 0x1c, 0x67, 0x1c, 0xcd, 0x37, 0xf1,
+       0xfd, 0x87, 0xf5, 0xfb, 0x8d, 0xdf, 0x67, 0xc0, 0x9b, 0xd7, 0x88, 0xa5,
+       0x19, 0x5f, 0x8c, 0xfb, 0x43, 0x6c, 0xf7, 0x6d, 0xd8, 0x6d, 0x68, 0xbb,
+       0xe3, 0xa6, 0xdd, 0xfa, 0x7e, 0x65, 0x95, 0x53, 0x22, 0x71, 0xab, 0xe8,
+       0x2a, 0xe3, 0x0a, 0xd5, 0xb3, 0x02, 0xb6, 0x53, 0xf2, 0xb5, 0x2b, 0x7b,
+       0x82, 0x6c, 0x4f, 0x40, 0x1c, 0x6c, 0xb5, 0xee, 0x2b, 0xe2, 0x7d, 0x7e,
+       0xb9, 0x0f, 0xf3, 0xa8, 0x0b, 0xc6, 0x0a, 0xfe, 0x54, 0x7e, 0xd3, 0x72,
+       0x73, 0xf3, 0xde, 0xea, 0x3f, 0xba, 0x91, 0xd2, 0x07, 0xf5, 0x4d, 0xc6,
+       0xa9, 0x05, 0xff, 0x1f, 0xe8, 0xfa, 0x76, 0x97, 0xee, 0xaf, 0xfe, 0x33,
+       0xc3, 0xa8, 0x4f, 0x67, 0x86, 0xcf, 0xf2, 0xbb, 0x83, 0xfd, 0xd2, 0x43,
+       0xff, 0x5b, 0xc8, 0xd8, 0xd5, 0xdb, 0xeb, 0x9b, 0x5d, 0x8f, 0x6a, 0x8b,
+       0x1e, 0xfa, 0xdc, 0x7f, 0x00, 0x5a, 0x33, 0xe6, 0xc0, 0x30, 0x14, 0x00,
        0x00, 0x00 };
 
 static u8 bnx2_TPAT_b09FwText[] = {
index 2039f7838f2df713a0afe9a4bbe1aecc8955e617..0942d82f7cbf721f62c364941a13b31373668c5b 100644 (file)
@@ -1464,10 +1464,12 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
                        dev_set_allmulti(slave_dev, 1);
                }
 
+               netif_tx_lock_bh(bond_dev);
                /* upload master's mc_list to new slave */
                for (dmi = bond_dev->mc_list; dmi; dmi = dmi->next) {
                        dev_mc_add (slave_dev, dmi->dmi_addr, dmi->dmi_addrlen, 0);
                }
+               netif_tx_unlock_bh(bond_dev);
        }
 
        if (bond->params.mode == BOND_MODE_8023AD) {
@@ -1821,7 +1823,9 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
                }
 
                /* flush master's mc_list from slave */
+               netif_tx_lock_bh(bond_dev);
                bond_mc_list_flush(bond_dev, slave_dev);
+               netif_tx_unlock_bh(bond_dev);
        }
 
        netdev_set_master(slave_dev, NULL);
@@ -1942,7 +1946,9 @@ static int bond_release_all(struct net_device *bond_dev)
                        }
 
                        /* flush master's mc_list from slave */
+                       netif_tx_lock_bh(bond_dev);
                        bond_mc_list_flush(bond_dev, slave_dev);
+                       netif_tx_unlock_bh(bond_dev);
                }
 
                netdev_set_master(slave_dev, NULL);
@@ -2795,14 +2801,11 @@ void bond_loadbalance_arp_mon(struct work_struct *work)
        }
 
        if (do_failover) {
-               rtnl_lock();
                write_lock_bh(&bond->curr_slave_lock);
 
                bond_select_active_slave(bond);
 
                write_unlock_bh(&bond->curr_slave_lock);
-               rtnl_unlock();
-
        }
 
 re_arm:
@@ -2859,8 +2862,6 @@ void bond_activebackup_arp_mon(struct work_struct *work)
 
                                slave->link = BOND_LINK_UP;
 
-                               rtnl_lock();
-
                                write_lock_bh(&bond->curr_slave_lock);
 
                                if ((!bond->curr_active_slave) &&
@@ -2896,7 +2897,6 @@ void bond_activebackup_arp_mon(struct work_struct *work)
                                }
 
                                write_unlock_bh(&bond->curr_slave_lock);
-                               rtnl_unlock();
                        }
                } else {
                        read_lock(&bond->curr_slave_lock);
@@ -2966,7 +2966,6 @@ void bond_activebackup_arp_mon(struct work_struct *work)
                               bond->dev->name,
                               slave->dev->name);
 
-                       rtnl_lock();
                        write_lock_bh(&bond->curr_slave_lock);
 
                        bond_select_active_slave(bond);
@@ -2974,8 +2973,6 @@ void bond_activebackup_arp_mon(struct work_struct *work)
 
                        write_unlock_bh(&bond->curr_slave_lock);
 
-                       rtnl_unlock();
-
                        bond->current_arp_slave = slave;
 
                        if (slave) {
@@ -2993,13 +2990,10 @@ void bond_activebackup_arp_mon(struct work_struct *work)
                               bond->primary_slave->dev->name);
 
                        /* primary is up so switch to it */
-                       rtnl_lock();
                        write_lock_bh(&bond->curr_slave_lock);
                        bond_change_active_slave(bond, bond->primary_slave);
                        write_unlock_bh(&bond->curr_slave_lock);
 
-                       rtnl_unlock();
-
                        slave = bond->primary_slave;
                        slave->jiffies = jiffies;
                } else {
@@ -3769,42 +3763,45 @@ static struct net_device_stats *bond_get_stats(struct net_device *bond_dev)
 {
        struct bonding *bond = bond_dev->priv;
        struct net_device_stats *stats = &(bond->stats), *sstats;
+       struct net_device_stats local_stats;
        struct slave *slave;
        int i;
 
-       memset(stats, 0, sizeof(struct net_device_stats));
+       memset(&local_stats, 0, sizeof(struct net_device_stats));
 
        read_lock_bh(&bond->lock);
 
        bond_for_each_slave(bond, slave, i) {
                sstats = slave->dev->get_stats(slave->dev);
-               stats->rx_packets += sstats->rx_packets;
-               stats->rx_bytes += sstats->rx_bytes;
-               stats->rx_errors += sstats->rx_errors;
-               stats->rx_dropped += sstats->rx_dropped;
+               local_stats.rx_packets += sstats->rx_packets;
+               local_stats.rx_bytes += sstats->rx_bytes;
+               local_stats.rx_errors += sstats->rx_errors;
+               local_stats.rx_dropped += sstats->rx_dropped;
 
-               stats->tx_packets += sstats->tx_packets;
-               stats->tx_bytes += sstats->tx_bytes;
-               stats->tx_errors += sstats->tx_errors;
-               stats->tx_dropped += sstats->tx_dropped;
+               local_stats.tx_packets += sstats->tx_packets;
+               local_stats.tx_bytes += sstats->tx_bytes;
+               local_stats.tx_errors += sstats->tx_errors;
+               local_stats.tx_dropped += sstats->tx_dropped;
 
-               stats->multicast += sstats->multicast;
-               stats->collisions += sstats->collisions;
+               local_stats.multicast += sstats->multicast;
+               local_stats.collisions += sstats->collisions;
 
-               stats->rx_length_errors += sstats->rx_length_errors;
-               stats->rx_over_errors += sstats->rx_over_errors;
-               stats->rx_crc_errors += sstats->rx_crc_errors;
-               stats->rx_frame_errors += sstats->rx_frame_errors;
-               stats->rx_fifo_errors += sstats->rx_fifo_errors;
-               stats->rx_missed_errors += sstats->rx_missed_errors;
+               local_stats.rx_length_errors += sstats->rx_length_errors;
+               local_stats.rx_over_errors += sstats->rx_over_errors;
+               local_stats.rx_crc_errors += sstats->rx_crc_errors;
+               local_stats.rx_frame_errors += sstats->rx_frame_errors;
+               local_stats.rx_fifo_errors += sstats->rx_fifo_errors;
+               local_stats.rx_missed_errors += sstats->rx_missed_errors;
 
-               stats->tx_aborted_errors += sstats->tx_aborted_errors;
-               stats->tx_carrier_errors += sstats->tx_carrier_errors;
-               stats->tx_fifo_errors += sstats->tx_fifo_errors;
-               stats->tx_heartbeat_errors += sstats->tx_heartbeat_errors;
-               stats->tx_window_errors += sstats->tx_window_errors;
+               local_stats.tx_aborted_errors += sstats->tx_aborted_errors;
+               local_stats.tx_carrier_errors += sstats->tx_carrier_errors;
+               local_stats.tx_fifo_errors += sstats->tx_fifo_errors;
+               local_stats.tx_heartbeat_errors += sstats->tx_heartbeat_errors;
+               local_stats.tx_window_errors += sstats->tx_window_errors;
        }
 
+       memcpy(stats, &local_stats, sizeof(struct net_device_stats));
+
        read_unlock_bh(&bond->lock);
 
        return stats;
@@ -3937,8 +3934,6 @@ static void bond_set_multicast_list(struct net_device *bond_dev)
        struct bonding *bond = bond_dev->priv;
        struct dev_mc_list *dmi;
 
-       write_lock_bh(&bond->lock);
-
        /*
         * Do promisc before checking multicast_mode
         */
@@ -3959,6 +3954,8 @@ static void bond_set_multicast_list(struct net_device *bond_dev)
                bond_set_allmulti(bond, -1);
        }
 
+       read_lock(&bond->lock);
+
        bond->flags = bond_dev->flags;
 
        /* looking for addresses to add to slaves' mc list */
@@ -3979,7 +3976,7 @@ static void bond_set_multicast_list(struct net_device *bond_dev)
        bond_mc_list_destroy(bond);
        bond_mc_list_copy(bond_dev->mc_list, bond, GFP_ATOMIC);
 
-       write_unlock_bh(&bond->lock);
+       read_unlock(&bond->lock);
 }
 
 /*
@@ -4526,7 +4523,9 @@ static void bond_free_all(void)
                struct net_device *bond_dev = bond->dev;
 
                bond_work_cancel_all(bond);
+               netif_tx_lock_bh(bond_dev);
                bond_mc_list_destroy(bond);
+               netif_tx_unlock_bh(bond_dev);
                /* Release the bonded slaves */
                bond_release_all(bond_dev);
                bond_deinit(bond_dev);
@@ -4549,14 +4548,19 @@ static void bond_free_all(void)
 int bond_parse_parm(const char *buf, struct bond_parm_tbl *tbl)
 {
        int mode = -1, i, rv;
-       char modestr[BOND_MAX_MODENAME_LEN + 1] = { 0, };
+       char *p, modestr[BOND_MAX_MODENAME_LEN + 1] = { 0, };
 
-       rv = sscanf(buf, "%d", &mode);
-       if (!rv) {
+       for (p = (char *)buf; *p; p++)
+               if (!(isdigit(*p) || isspace(*p)))
+                       break;
+
+       if (*p)
                rv = sscanf(buf, "%20s", modestr);
-               if (!rv)
-                       return -1;
-       }
+       else
+               rv = sscanf(buf, "%d", &mode);
+
+       if (!rv)
+               return -1;
 
        for (i = 0; tbl[i].modename; i++) {
                if (mode == tbl[i].mode)
@@ -4883,14 +4887,16 @@ int bond_create(char *name, struct bond_params *params, struct bonding **newbond
        down_write(&bonding_rwsem);
 
        /* Check to see if the bond already exists. */
-       list_for_each_entry_safe(bond, nxt, &bond_dev_list, bond_list)
-               if (strnicmp(bond->dev->name, name, IFNAMSIZ) == 0) {
-                       printk(KERN_ERR DRV_NAME
+       if (name) {
+               list_for_each_entry_safe(bond, nxt, &bond_dev_list, bond_list)
+                       if (strnicmp(bond->dev->name, name, IFNAMSIZ) == 0) {
+                               printk(KERN_ERR DRV_NAME
                               ": cannot add bond %s; it already exists\n",
-                              name);
-                       res = -EPERM;
-                       goto out_rtnl;
-               }
+                                      name);
+                               res = -EPERM;
+                               goto out_rtnl;
+                       }
+       }
 
        bond_dev = alloc_netdev(sizeof(struct bonding), name ? name : "",
                                ether_setup);
index 6d83be49899a496fe5125ad3e95d081634a7c269..67ccad69d445f097675c9c724b7a632bca10a4cd 100644 (file)
@@ -22,8 +22,8 @@
 #include "bond_3ad.h"
 #include "bond_alb.h"
 
-#define DRV_VERSION    "3.2.3"
-#define DRV_RELDATE    "December 6, 2007"
+#define DRV_VERSION    "3.2.4"
+#define DRV_RELDATE    "January 28, 2008"
 #define DRV_NAME       "bonding"
 #define DRV_DESCRIPTION        "Ethernet Channel Bonding Driver"
 
index 6ccebb830ff90bc86f4b00ed0f622f8fe0c0245b..c85194f2cd2dc2b8a9bf5628e63b9189db0ec2cd 100644 (file)
@@ -845,15 +845,6 @@ static void cpmac_adjust_link(struct net_device *dev)
        spin_unlock(&priv->lock);
 }
 
-static int cpmac_link_update(struct net_device *dev,
-                            struct fixed_phy_status *status)
-{
-       status->link = 1;
-       status->speed = 100;
-       status->duplex = 1;
-       return 0;
-}
-
 static int cpmac_open(struct net_device *dev)
 {
        int i, size, res;
@@ -996,11 +987,11 @@ static int external_switch;
 static int __devinit cpmac_probe(struct platform_device *pdev)
 {
        int rc, phy_id, i;
+       int mdio_bus_id = cpmac_mii.id;
        struct resource *mem;
        struct cpmac_priv *priv;
        struct net_device *dev;
        struct plat_cpmac_data *pdata;
-       struct fixed_info *fixed_phy;
        DECLARE_MAC_BUF(mac);
 
        pdata = pdev->dev.platform_data;
@@ -1014,9 +1005,23 @@ static int __devinit cpmac_probe(struct platform_device *pdev)
        }
 
        if (phy_id == PHY_MAX_ADDR) {
-               if (external_switch || dumb_switch)
+               if (external_switch || dumb_switch) {
+                       struct fixed_phy_status status = {};
+
+                       mdio_bus_id = 0;
+
+                       /*
+                        * FIXME: this should be in the platform code!
+                        * Since there is not platform code at all (that is,
+                        * no mainline users of that driver), place it here
+                        * for now.
+                        */
                        phy_id = 0;
-               else {
+                       status.link = 1;
+                       status.duplex = 1;
+                       status.speed = 100;
+                       fixed_phy_add(PHY_POLL, phy_id, &status);
+               } else {
                        printk(KERN_ERR "cpmac: no PHY present\n");
                        return -ENODEV;
                }
@@ -1060,32 +1065,8 @@ static int __devinit cpmac_probe(struct platform_device *pdev)
        priv->msg_enable = netif_msg_init(debug_level, 0xff);
        memcpy(dev->dev_addr, pdata->dev_addr, sizeof(dev->dev_addr));
 
-       if (phy_id == 31) {
-               snprintf(priv->phy_name, BUS_ID_SIZE, PHY_ID_FMT, cpmac_mii.id,
-                        phy_id);
-       } else {
-               /* Let's try to get a free fixed phy... */
-               for (i = 0; i < MAX_PHY_AMNT; i++) {
-                       fixed_phy = fixed_mdio_get_phydev(i);
-                       if (!fixed_phy)
-                               continue;
-                       if (!fixed_phy->phydev->attached_dev) {
-                               strncpy(priv->phy_name,
-                                       fixed_phy->phydev->dev.bus_id,
-                                       BUS_ID_SIZE);
-                               fixed_mdio_set_link_update(fixed_phy->phydev,
-                                                          &cpmac_link_update);
-                               goto phy_found;
-                       }
-               }
-               if (netif_msg_drv(priv))
-                       printk(KERN_ERR "%s: Could not find fixed PHY\n",
-                              dev->name);
-               rc = -ENODEV;
-               goto fail;
-       }
+       snprintf(priv->phy_name, BUS_ID_SIZE, PHY_ID_FMT, mdio_bus_id, phy_id);
 
-phy_found:
        priv->phy = phy_connect(dev, priv->phy_name, &cpmac_adjust_link, 0,
                                PHY_INTERFACE_MODE_MII);
        if (IS_ERR(priv->phy)) {
index d48c396bdabb9858f15f8f0264557bb68890d9e4..901c824bfe6d5bda0f8a9d85a97b00bc91c1bf50 100644 (file)
@@ -1070,9 +1070,7 @@ void *cxgb_alloc_mem(unsigned long size)
  */
 void cxgb_free_mem(void *addr)
 {
-       unsigned long p = (unsigned long)addr;
-
-       if (p >= VMALLOC_START && p < VMALLOC_END)
+       if (is_vmalloc_addr(addr))
                vfree(addr);
        else
                kfree(addr);
index 84c1ffa8e2d38561bf68f40b5d506782f2b9aea0..4c4d6e877ea698baf6ed92bbfc606f1b389dc476 100644 (file)
@@ -452,7 +452,7 @@ void t3_mc5_intr_handler(struct mc5 *mc5)
        t3_write_reg(adap, A_MC5_DB_INT_CAUSE, cause);
 }
 
-void __devinit t3_mc5_prep(struct adapter *adapter, struct mc5 *mc5, int mode)
+void t3_mc5_prep(struct adapter *adapter, struct mc5 *mc5, int mode)
 {
 #define K * 1024
 
index cb684d30831fcc228da571e80ec9b96b0ee47a8b..9ca8c66abd16193fddea7d0a5118ba2db2175505 100644 (file)
@@ -2836,7 +2836,7 @@ void t3_sge_init(struct adapter *adap, struct sge_params *p)
  *     defaults for the assorted SGE parameters, which admins can change until
  *     they are used to initialize the SGE.
  */
-void __devinit t3_sge_prep(struct adapter *adap, struct sge_params *p)
+void t3_sge_prep(struct adapter *adap, struct sge_params *p)
 {
        int i;
 
index 7469935877bd746370dc183ec7eaabbfc813b3da..a99496a431c423f260b41fc6ae06fa4cd3ae1dcf 100644 (file)
@@ -2675,7 +2675,7 @@ void t3_tp_set_max_rxsize(struct adapter *adap, unsigned int size)
                     V_PMMAXXFERLEN0(size) | V_PMMAXXFERLEN1(size));
 }
 
-static void __devinit init_mtus(unsigned short mtus[])
+static void init_mtus(unsigned short mtus[])
 {
        /*
         * See draft-mathis-plpmtud-00.txt for the values.  The min is 88 so
@@ -2703,7 +2703,7 @@ static void __devinit init_mtus(unsigned short mtus[])
 /*
  * Initial congestion control parameters.
  */
-static void __devinit init_cong_ctrl(unsigned short *a, unsigned short *b)
+static void init_cong_ctrl(unsigned short *a, unsigned short *b)
 {
        a[0] = a[1] = a[2] = a[3] = a[4] = a[5] = a[6] = a[7] = a[8] = 1;
        a[9] = 2;
@@ -3354,8 +3354,7 @@ out_err:
  *     Determines a card's PCI mode and associated parameters, such as speed
  *     and width.
  */
-static void __devinit get_pci_mode(struct adapter *adapter,
-                                  struct pci_params *p)
+static void get_pci_mode(struct adapter *adapter, struct pci_params *p)
 {
        static unsigned short speed_map[] = { 33, 66, 100, 133 };
        u32 pci_mode, pcie_cap;
@@ -3395,8 +3394,7 @@ static void __devinit get_pci_mode(struct adapter *adapter,
  *     capabilities and default speed/duplex/flow-control/autonegotiation
  *     settings.
  */
-static void __devinit init_link_config(struct link_config *lc,
-                                      unsigned int caps)
+static void init_link_config(struct link_config *lc, unsigned int caps)
 {
        lc->supported = caps;
        lc->requested_speed = lc->speed = SPEED_INVALID;
@@ -3419,7 +3417,7 @@ static void __devinit init_link_config(struct link_config *lc,
  *     Calculates the size of an MC7 memory in bytes from the value of its
  *     configuration register.
  */
-static unsigned int __devinit mc7_calc_size(u32 cfg)
+static unsigned int mc7_calc_size(u32 cfg)
 {
        unsigned int width = G_WIDTH(cfg);
        unsigned int banks = !!(cfg & F_BKS) + 1;
@@ -3430,8 +3428,8 @@ static unsigned int __devinit mc7_calc_size(u32 cfg)
        return MBs << 20;
 }
 
-static void __devinit mc7_prep(struct adapter *adapter, struct mc7 *mc7,
-                              unsigned int base_addr, const char *name)
+static void mc7_prep(struct adapter *adapter, struct mc7 *mc7,
+                    unsigned int base_addr, const char *name)
 {
        u32 cfg;
 
@@ -3517,7 +3515,7 @@ static int t3_reset_adapter(struct adapter *adapter)
        return 0;
 }
 
-static int __devinit init_parity(struct adapter *adap)
+static int init_parity(struct adapter *adap)
 {
                int i, err, addr;
 
@@ -3552,8 +3550,8 @@ static int __devinit init_parity(struct adapter *adap)
  * for some adapter tunables, take PHYs out of reset, and initialize the MDIO
  * interface.
  */
-int __devinit t3_prep_adapter(struct adapter *adapter,
-                             const struct adapter_info *ai, int reset)
+int t3_prep_adapter(struct adapter *adapter, const struct adapter_info *ai,
+                   int reset)
 {
        int ret;
        unsigned int i, j = 0;
index d66c605b4075bc3650f2717af9dc4ea583754fa5..266ec8777ca81797f0dfd92b22875229644e5584 100644 (file)
@@ -388,8 +388,8 @@ enum _mii_mssr {
        MII_MSSR_CFG_RES = 0x4000,
        MII_MSSR_LOCAL_RCV_STATUS = 0x2000,
        MII_MSSR_REMOTE_RCVR = 0x1000,
-       MII_MSSR_LP_1000BT_HD = 0x0800,
-       MII_MSSR_LP_1000BT_FD = 0x0400,
+       MII_MSSR_LP_1000BT_FD = 0x0800,
+       MII_MSSR_LP_1000BT_HD = 0x0400,
        MII_MSSR_IDLE_ERR_COUNT = 0x00ff,
 };
 
index 51cf577035bed0c466a45a4470102c3db56ef6db..36ba6dc96acc8494605c41315a8acecaa13f702f 100644 (file)
@@ -94,7 +94,7 @@
  *     enabled.  82557 pads with 7Eh, while the later controllers pad
  *     with 00h.
  *
- *     IV.  Recieve
+ *     IV.  Receive
  *
  *     The Receive Frame Area (RFA) comprises a ring of Receive Frame
  *     Descriptors (RFD) + data buffer, thus forming the simplified mode
  *     and Rx indication and re-allocation happen in the same context,
  *     therefore no locking is required.  A software-generated interrupt
  *     is generated from the watchdog to recover from a failed allocation
- *     senario where all Rx resources have been indicated and none re-
+ *     scenario where all Rx resources have been indicated and none re-
  *     placed.
  *
  *     V.   Miscellaneous
@@ -954,7 +954,7 @@ static void e100_get_defaults(struct nic *nic)
        /* Quadwords to DMA into FIFO before starting frame transmit */
        nic->tx_threshold = 0xE0;
 
-       /* no interrupt for every tx completion, delay = 256us if not 557*/
+       /* no interrupt for every tx completion, delay = 256us if not 557 */
        nic->tx_command = cpu_to_le16(cb_tx | cb_tx_sf |
                ((nic->mac >= mac_82558_D101_A4) ? cb_cid : cb_i));
 
@@ -1497,7 +1497,7 @@ static void e100_update_stats(struct nic *nic)
                &s->complete;
 
        /* Device's stats reporting may take several microseconds to
-        * complete, so where always waiting for results of the
+        * complete, so we're always waiting for results of the
         * previous command. */
 
        if(*complete == cpu_to_le32(cuc_dump_reset_complete)) {
@@ -1958,7 +1958,7 @@ static void e100_rx_clean(struct nic *nic, unsigned int *work_done,
 
        if(restart_required) {
                // ack the rnr?
-               writeb(stat_ack_rnr, &nic->csr->scb.stat_ack);
+               iowrite8(stat_ack_rnr, &nic->csr->scb.stat_ack);
                e100_start_receiver(nic, nic->rx_to_clean);
                if(work_done)
                        (*work_done)++;
@@ -2774,7 +2774,7 @@ static void __devexit e100_remove(struct pci_dev *pdev)
                struct nic *nic = netdev_priv(netdev);
                unregister_netdev(netdev);
                e100_free(nic);
-               iounmap(nic->csr);
+               pci_iounmap(pdev, nic->csr);
                free_netdev(netdev);
                pci_release_regions(pdev);
                pci_disable_device(pdev);
@@ -2858,17 +2858,17 @@ static void e100_shutdown(struct pci_dev *pdev)
 /**
  * e100_io_error_detected - called when PCI error is detected.
  * @pdev: Pointer to PCI device
- * @state: The current pci conneection state
+ * @state: The current pci connection state
  */
 static pci_ers_result_t e100_io_error_detected(struct pci_dev *pdev, pci_channel_state_t state)
 {
        struct net_device *netdev = pci_get_drvdata(pdev);
        struct nic *nic = netdev_priv(netdev);
 
-       /* Similar to calling e100_down(), but avoids adpater I/O. */
+       /* Similar to calling e100_down(), but avoids adapter I/O. */
        netdev->stop(netdev);
 
-       /* Detach; put netif into state similar to hotplug unplug. */
+       /* Detach; put netif into state similar to hotplug unplug. */
        napi_enable(&nic->napi);
        netif_device_detach(netdev);
        pci_disable_device(pdev);
index 8c87940a9ce86341eacda17d1a3ad94106e32921..7c5b05a82f0e7c9a27b77a9f3d943fcf3baf2931 100644 (file)
@@ -853,7 +853,7 @@ e1000_reset(struct e1000_adapter *adapter)
 /**
  *  Dump the eeprom for users having checksum issues
  **/
-void e1000_dump_eeprom(struct e1000_adapter *adapter)
+static void e1000_dump_eeprom(struct e1000_adapter *adapter)
 {
        struct net_device *netdev = adapter->netdev;
        struct ethtool_eeprom eeprom;
index f2175ea46b830a438380a54d0571bb3c92683586..6232c3e96689668cb15748e88a82ddc856c1714f 100644 (file)
@@ -63,6 +63,7 @@
 #define E1000_WUFC_EX   0x00000004 /* Directed Exact Wakeup Enable */
 #define E1000_WUFC_MC   0x00000008 /* Directed Multicast Wakeup Enable */
 #define E1000_WUFC_BC   0x00000010 /* Broadcast Wakeup Enable */
+#define E1000_WUFC_ARP  0x00000020 /* ARP Request Packet Wakeup Enable */
 
 /* Extended Device Control */
 #define E1000_CTRL_EXT_SDP7_DATA 0x00000080 /* Value of SW Defineable Pin 7 */
index 6d9c27fd0b53b86953ecf3548d59c4825de1e626..f77a7427d3a079bf9ad714bf9cfc8f416851fb59 100644 (file)
@@ -690,8 +690,8 @@ err_setup:
        return err;
 }
 
-bool reg_pattern_test_array(struct e1000_adapter *adapter, u64 *data,
-                           int reg, int offset, u32 mask, u32 write)
+static bool reg_pattern_test_array(struct e1000_adapter *adapter, u64 *data,
+                                  int reg, int offset, u32 mask, u32 write)
 {
        int i;
        u32 read;
@@ -1632,7 +1632,8 @@ static void e1000_get_wol(struct net_device *netdev,
                return;
 
        wol->supported = WAKE_UCAST | WAKE_MCAST |
-                        WAKE_BCAST | WAKE_MAGIC;
+                        WAKE_BCAST | WAKE_MAGIC |
+                        WAKE_PHY | WAKE_ARP;
 
        /* apply any specific unsupported masks here */
        if (adapter->flags & FLAG_NO_WAKE_UCAST) {
@@ -1651,6 +1652,10 @@ static void e1000_get_wol(struct net_device *netdev,
                wol->wolopts |= WAKE_BCAST;
        if (adapter->wol & E1000_WUFC_MAG)
                wol->wolopts |= WAKE_MAGIC;
+       if (adapter->wol & E1000_WUFC_LNKC)
+               wol->wolopts |= WAKE_PHY;
+       if (adapter->wol & E1000_WUFC_ARP)
+               wol->wolopts |= WAKE_ARP;
 }
 
 static int e1000_set_wol(struct net_device *netdev,
@@ -1658,7 +1663,7 @@ static int e1000_set_wol(struct net_device *netdev,
 {
        struct e1000_adapter *adapter = netdev_priv(netdev);
 
-       if (wol->wolopts & (WAKE_PHY | WAKE_ARP | WAKE_MAGICSECURE))
+       if (wol->wolopts & WAKE_MAGICSECURE)
                return -EOPNOTSUPP;
 
        if (!(adapter->flags & FLAG_HAS_WOL))
@@ -1675,6 +1680,10 @@ static int e1000_set_wol(struct net_device *netdev,
                adapter->wol |= E1000_WUFC_BC;
        if (wol->wolopts & WAKE_MAGIC)
                adapter->wol |= E1000_WUFC_MAG;
+       if (wol->wolopts & WAKE_PHY)
+               adapter->wol |= E1000_WUFC_LNKC;
+       if (wol->wolopts & WAKE_ARP)
+               adapter->wol |= E1000_WUFC_ARP;
 
        return 0;
 }
index 0a2cb7960c9e8d8dcb85063773a3d800068a9a9d..f58f017ee47ae837a45e3f0fcba3e2bafcf81d06 100644 (file)
@@ -945,11 +945,7 @@ static int e1000_request_irq(struct e1000_adapter *adapter)
        int irq_flags = IRQF_SHARED;
        int err;
 
-       err = pci_enable_msi(adapter->pdev);
-       if (err) {
-               ndev_warn(netdev,
-                "Unable to allocate MSI interrupt Error: %d\n", err);
-       } else {
+       if (!pci_enable_msi(adapter->pdev)) {
                adapter->flags |= FLAG_MSI_ENABLED;
                handler = e1000_intr_msi;
                irq_flags = 0;
@@ -958,10 +954,12 @@ static int e1000_request_irq(struct e1000_adapter *adapter)
        err = request_irq(adapter->pdev->irq, handler, irq_flags, netdev->name,
                          netdev);
        if (err) {
+               ndev_err(netdev,
+                      "Unable to allocate %s interrupt (return: %d)\n",
+                       adapter->flags & FLAG_MSI_ENABLED ? "MSI":"INTx",
+                       err);
                if (adapter->flags & FLAG_MSI_ENABLED)
                        pci_disable_msi(adapter->pdev);
-               ndev_err(netdev,
-                      "Unable to allocate interrupt Error: %d\n", err);
        }
 
        return err;
index d5459a8056b1a4f60f8207b1651385e5ff2856d1..2eb82aba4a8bc7c0a2ee5e26b959a1c33dbce4ba 100644 (file)
@@ -9,7 +9,7 @@
  * Many modifications, and currently maintained, by
  *  Philip Blundell <philb@gnu.org>
  * Added the Compaq LTE  Alan Cox <alan@redhat.com>
- * Added MCA support Adam Fritzler <mid@auk.cx>
+ * Added MCA support Adam Fritzler
  *
  * Note - this driver is experimental still - it has problems on faster
  * machines. Someone needs to sit down and go through it line by line with
index 5f82a4647eee4dcec3240be6ec51932926efae16..88fb53eba715368e9685ff5dbd6db275bc826626 100644 (file)
@@ -458,4 +458,7 @@ void ehea_set_ethtool_ops(struct net_device *netdev);
 int ehea_sense_port_attr(struct ehea_port *port);
 int ehea_set_portspeed(struct ehea_port *port, u32 port_speed);
 
+extern u64 ehea_driver_flags;
+extern struct work_struct ehea_rereg_mr_task;
+
 #endif /* __EHEA_H__ */
index 679f40ee957263af5ee375f5e76df76e42b45c52..d768852233663008eaf4cd5a9e324af68da3627b 100644 (file)
@@ -40,7 +40,7 @@ static int ehea_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
                return ret;
 
        if (netif_carrier_ok(dev)) {
-               switch(port->port_speed) {
+               switch (port->port_speed) {
                case EHEA_SPEED_10M: cmd->speed = SPEED_10; break;
                case EHEA_SPEED_100M: cmd->speed = SPEED_100; break;
                case EHEA_SPEED_1G: cmd->speed = SPEED_1000; break;
@@ -78,7 +78,7 @@ static int ehea_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
                goto doit;
        }
 
-       switch(cmd->speed) {
+       switch (cmd->speed) {
        case SPEED_10:
                if (cmd->duplex == DUPLEX_FULL)
                        sp = H_SPEED_10M_F;
index 1af7ca499ec517232e7c83dc845f2f336c07430c..567981b4b2cc351a01a54460ea512f970203ef8a 100644 (file)
 #ifndef __EHEA_HW_H__
 #define __EHEA_HW_H__
 
-#define QPX_SQA_VALUE   EHEA_BMASK_IBM(48,63)
-#define QPX_RQ1A_VALUE  EHEA_BMASK_IBM(48,63)
-#define QPX_RQ2A_VALUE  EHEA_BMASK_IBM(48,63)
-#define QPX_RQ3A_VALUE  EHEA_BMASK_IBM(48,63)
+#define QPX_SQA_VALUE   EHEA_BMASK_IBM(48, 63)
+#define QPX_RQ1A_VALUE  EHEA_BMASK_IBM(48, 63)
+#define QPX_RQ2A_VALUE  EHEA_BMASK_IBM(48, 63)
+#define QPX_RQ3A_VALUE  EHEA_BMASK_IBM(48, 63)
 
 #define QPTEMM_OFFSET(x) offsetof(struct ehea_qptemm, x)
 
index 869e1604b16ea0e4b5555acbe77dff969f42cb5b..c051c7e09b9a0b600f4202e5febba3b5ee0f7723 100644 (file)
@@ -6,9 +6,9 @@
  *  (C) Copyright IBM Corp. 2006
  *
  *  Authors:
- *       Christoph Raisch <raisch@de.ibm.com>
- *       Jan-Bernd Themann <themann@de.ibm.com>
- *       Thomas Klein <tklein@de.ibm.com>
+ *      Christoph Raisch <raisch@de.ibm.com>
+ *      Jan-Bernd Themann <themann@de.ibm.com>
+ *      Thomas Klein <tklein@de.ibm.com>
  *
  *
  * This program is free software; you can redistribute it and/or modify
@@ -54,11 +54,11 @@ static int rq1_entries = EHEA_DEF_ENTRIES_RQ1;
 static int rq2_entries = EHEA_DEF_ENTRIES_RQ2;
 static int rq3_entries = EHEA_DEF_ENTRIES_RQ3;
 static int sq_entries = EHEA_DEF_ENTRIES_SQ;
-static int use_mcs = 0;
-static int use_lro = 0;
+static int use_mcs;
+static int use_lro;
 static int lro_max_aggr = EHEA_LRO_MAX_AGGR;
 static int num_tx_qps = EHEA_NUM_TX_QP;
-static int prop_carrier_state = 0;
+static int prop_carrier_state;
 
 module_param(msg_level, int, 0);
 module_param(rq1_entries, int, 0);
@@ -94,9 +94,9 @@ MODULE_PARM_DESC(lro_max_aggr, " LRO: Max packets to be aggregated. Default = "
 MODULE_PARM_DESC(use_lro, " Large Receive Offload, 1: enable, 0: disable, "
                 "Default = 0");
 
-static int port_name_cnt = 0;
+static int port_name_cnt;
 static LIST_HEAD(adapter_list);
-u64 ehea_driver_flags = 0;
+u64 ehea_driver_flags;
 struct work_struct ehea_rereg_mr_task;
 
 struct semaphore dlpar_mem_lock;
@@ -121,12 +121,13 @@ static struct of_platform_driver ehea_driver = {
        .remove = ehea_remove,
 };
 
-void ehea_dump(void *adr, int len, char *msg) {
+void ehea_dump(void *adr, int len, char *msg)
+{
        int x;
        unsigned char *deb = adr;
        for (x = 0; x < len; x += 16) {
                printk(DRV_NAME " %s adr=%p ofs=%04x %016lx %016lx\n", msg,
-                         deb, x, *((u64*)&deb[0]), *((u64*)&deb[8]));
+                         deb, x, *((u64 *)&deb[0]), *((u64 *)&deb[8]));
                deb += 16;
        }
 }
@@ -518,7 +519,8 @@ static int ehea_proc_rwqes(struct net_device *dev,
                last_wqe_index = wqe_index;
                rmb();
                if (!ehea_check_cqe(cqe, &rq)) {
-                       if (rq == 1) {  /* LL RQ1 */
+                       if (rq == 1) {
+                               /* LL RQ1 */
                                skb = get_skb_by_index_ll(skb_arr_rq1,
                                                          skb_arr_rq1_len,
                                                          wqe_index);
@@ -531,10 +533,11 @@ static int ehea_proc_rwqes(struct net_device *dev,
                                        if (!skb)
                                                break;
                                }
-                               skb_copy_to_linear_data(skb, ((char*)cqe) + 64,
+                               skb_copy_to_linear_data(skb, ((char *)cqe) + 64,
                                                 cqe->num_bytes_transfered - 4);
                                ehea_fill_skb(dev, skb, cqe);
-                       } else if (rq == 2) {  /* RQ2 */
+                       } else if (rq == 2) {
+                               /* RQ2 */
                                skb = get_skb_by_index(skb_arr_rq2,
                                                       skb_arr_rq2_len, cqe);
                                if (unlikely(!skb)) {
@@ -544,7 +547,8 @@ static int ehea_proc_rwqes(struct net_device *dev,
                                }
                                ehea_fill_skb(dev, skb, cqe);
                                processed_rq2++;
-                       } else {  /* RQ3 */
+                       } else {
+                               /* RQ3 */
                                skb = get_skb_by_index(skb_arr_rq3,
                                                       skb_arr_rq3_len, cqe);
                                if (unlikely(!skb)) {
@@ -592,7 +596,7 @@ static struct ehea_cqe *ehea_proc_cqes(struct ehea_port_res *pr, int my_quota)
        unsigned long flags;
 
        cqe = ehea_poll_cq(send_cq);
-       while(cqe && (quota > 0)) {
+       while (cqe && (quota > 0)) {
                ehea_inc_cq(send_cq);
 
                cqe_counter++;
@@ -643,7 +647,8 @@ static struct ehea_cqe *ehea_proc_cqes(struct ehea_port_res *pr, int my_quota)
 
 static int ehea_poll(struct napi_struct *napi, int budget)
 {
-       struct ehea_port_res *pr = container_of(napi, struct ehea_port_res, napi);
+       struct ehea_port_res *pr = container_of(napi, struct ehea_port_res,
+                                               napi);
        struct net_device *dev = pr->port->netdev;
        struct ehea_cqe *cqe;
        struct ehea_cqe *cqe_skb = NULL;
@@ -743,8 +748,9 @@ int ehea_sense_port_attr(struct ehea_port *port)
        u64 hret;
        struct hcp_ehea_port_cb0 *cb0;
 
-       cb0 = kzalloc(PAGE_SIZE, GFP_ATOMIC);   /* May be called via */
-       if (!cb0) {                             /* ehea_neq_tasklet() */
+       /* may be called via ehea_neq_tasklet() */
+       cb0 = kzalloc(PAGE_SIZE, GFP_ATOMIC);
+       if (!cb0) {
                ehea_error("no mem for cb0");
                ret = -ENOMEM;
                goto out;
@@ -762,7 +768,7 @@ int ehea_sense_port_attr(struct ehea_port *port)
        /* MAC address */
        port->mac_addr = cb0->port_mac_addr << 16;
 
-       if (!is_valid_ether_addr((u8*)&port->mac_addr)) {
+       if (!is_valid_ether_addr((u8 *)&port->mac_addr)) {
                ret = -EADDRNOTAVAIL;
                goto out_free;
        }
@@ -994,7 +1000,7 @@ static void ehea_parse_eqe(struct ehea_adapter *adapter, u64 eqe)
 
 static void ehea_neq_tasklet(unsigned long data)
 {
-       struct ehea_adapter *adapter = (struct ehea_adapter*)data;
+       struct ehea_adapter *adapter = (struct ehea_adapter *)data;
        struct ehea_eqe *eqe;
        u64 event_mask;
 
@@ -1204,7 +1210,7 @@ int ehea_rem_smrs(struct ehea_port_res *pr)
 
 static int ehea_init_q_skba(struct ehea_q_skb_arr *q_skba, int max_q_entries)
 {
-       int arr_size = sizeof(void*) * max_q_entries;
+       int arr_size = sizeof(void *) * max_q_entries;
 
        q_skba->arr = vmalloc(arr_size);
        if (!q_skba->arr)
@@ -1489,7 +1495,7 @@ static inline void write_swqe2_data(struct sk_buff *skb, struct net_device *dev,
 
        nfrags = skb_shinfo(skb)->nr_frags;
        sg1entry = &swqe->u.immdata_desc.sg_entry;
-       sg_list = (struct ehea_vsgentry*)&swqe->u.immdata_desc.sg_list;
+       sg_list = (struct ehea_vsgentry *)&swqe->u.immdata_desc.sg_list;
        swqe->descriptors = 0;
        sg1entry_contains_frag_data = 0;
 
@@ -1542,7 +1548,7 @@ static int ehea_broadcast_reg_helper(struct ehea_port *port, u32 hcallid)
                                     reg_type, port->mac_addr, 0, hcallid);
        if (hret != H_SUCCESS) {
                ehea_error("%sregistering bc address failed (tagged)",
-                           hcallid == H_REG_BCMC ? "" : "de");
+                          hcallid == H_REG_BCMC ? "" : "de");
                ret = -EIO;
                goto out_herr;
        }
@@ -1732,7 +1738,7 @@ static void ehea_allmulti(struct net_device *dev, int enable)
                }
 }
 
-static void ehea_add_multicast_entry(struct ehea_port* port, u8* mc_mac_addr)
+static void ehea_add_multicast_entry(struct ehea_port *port, u8 *mc_mac_addr)
 {
        struct ehea_mc_list *ehea_mcl_entry;
        u64 hret;
@@ -1791,11 +1797,10 @@ static void ehea_set_multicast_list(struct net_device *dev)
                        goto out;
                }
 
-               for (i = 0, k_mcl_entry = dev->mc_list;
-                    i < dev->mc_count;
-                    i++, k_mcl_entry = k_mcl_entry->next) {
+               for (i = 0, k_mcl_entry = dev->mc_list; i < dev->mc_count; i++,
+                            k_mcl_entry = k_mcl_entry->next)
                        ehea_add_multicast_entry(port, k_mcl_entry->dmi_addr);
-               }
+
        }
 out:
        return;
@@ -1925,12 +1930,12 @@ static inline int ehea_hash_skb(struct sk_buff *skb, int num_qps)
 
        if ((skb->protocol == htons(ETH_P_IP)) &&
            (ip_hdr(skb)->protocol == IPPROTO_TCP)) {
-               tcp = (struct tcphdr*)(skb_network_header(skb) + (ip_hdr(skb)->ihl * 4));
+               tcp = (struct tcphdr *)(skb_network_header(skb) +
+                                       (ip_hdr(skb)->ihl * 4));
                tmp = (tcp->source + (tcp->dest << 16)) % 31;
                tmp += ip_hdr(skb)->daddr % 31;
                return tmp % num_qps;
-       }
-       else
+       } else
                return 0;
 }
 
@@ -2122,7 +2127,7 @@ int ehea_activate_qp(struct ehea_adapter *adapter, struct ehea_qp *qp)
        u64 hret;
        u16 dummy16 = 0;
        u64 dummy64 = 0;
-       struct hcp_modify_qp_cb0cb0;
+       struct hcp_modify_qp_cb0 *cb0;
 
        cb0 = kzalloc(PAGE_SIZE, GFP_KERNEL);
        if (!cb0) {
@@ -2248,7 +2253,7 @@ static int ehea_clean_all_portres(struct ehea_port *port)
        int ret = 0;
        int i;
 
-       for(i = 0; i < port->num_def_qps + port->num_add_tx_qps; i++)
+       for (i = 0; i < port->num_def_qps + port->num_add_tx_qps; i++)
                ret |= ehea_clean_portres(port, &port->port_res[i]);
 
        ret |= ehea_destroy_eq(port->qp_eq);
@@ -2300,7 +2305,7 @@ static int ehea_up(struct net_device *dev)
                goto out_clean_pr;
        }
 
-       for(i = 0; i < port->num_def_qps + port->num_add_tx_qps; i++) {
+       for (i = 0; i < port->num_def_qps + port->num_add_tx_qps; i++) {
                ret = ehea_activate_qp(port->adapter, port->port_res[i].qp);
                if (ret) {
                        ehea_error("activate_qp failed");
@@ -2308,7 +2313,7 @@ static int ehea_up(struct net_device *dev)
                }
        }
 
-       for(i = 0; i < port->num_def_qps; i++) {
+       for (i = 0; i < port->num_def_qps; i++) {
                ret = ehea_fill_port_res(&port->port_res[i]);
                if (ret) {
                        ehea_error("out_free_irqs");
@@ -2425,7 +2430,7 @@ int ehea_stop_qps(struct net_device *dev)
 {
        struct ehea_port *port = netdev_priv(dev);
        struct ehea_adapter *adapter = port->adapter;
-       struct hcp_modify_qp_cb0cb0;
+       struct hcp_modify_qp_cb0 *cb0;
        int ret = -EIO;
        int dret;
        int i;
@@ -2490,7 +2495,7 @@ out:
        return ret;
 }
 
-void ehea_update_rqs(struct ehea_qp *orig_qp, struct ehea_port_res * pr)
+void ehea_update_rqs(struct ehea_qp *orig_qp, struct ehea_port_res *pr)
 {
        struct ehea_qp qp = *orig_qp;
        struct ehea_qp_init_attr *init_attr = &qp.init_attr;
@@ -2530,7 +2535,7 @@ int ehea_restart_qps(struct net_device *dev)
        int ret = 0;
        int i;
 
-       struct hcp_modify_qp_cb0cb0;
+       struct hcp_modify_qp_cb0 *cb0;
        u64 hret;
        u64 dummy64 = 0;
        u16 dummy16 = 0;
@@ -2804,34 +2809,6 @@ static void __devinit logical_port_release(struct device *dev)
        of_node_put(port->ofdev.node);
 }
 
-static int ehea_driver_sysfs_add(struct device *dev,
-                                struct device_driver *driver)
-{
-       int ret;
-
-       ret = sysfs_create_link(&driver->kobj, &dev->kobj,
-                               kobject_name(&dev->kobj));
-       if (ret == 0) {
-               ret = sysfs_create_link(&dev->kobj, &driver->kobj,
-                                       "driver");
-               if (ret)
-                       sysfs_remove_link(&driver->kobj,
-                                         kobject_name(&dev->kobj));
-       }
-       return ret;
-}
-
-static void ehea_driver_sysfs_remove(struct device *dev,
-                                    struct device_driver *driver)
-{
-       struct device_driver *drv = driver;
-
-       if (drv) {
-               sysfs_remove_link(&drv->kobj, kobject_name(&dev->kobj));
-               sysfs_remove_link(&dev->kobj, "driver");
-       }
-}
-
 static struct device *ehea_register_port(struct ehea_port *port,
                                         struct device_node *dn)
 {
@@ -2856,16 +2833,8 @@ static struct device *ehea_register_port(struct ehea_port *port,
                goto out_unreg_of_dev;
        }
 
-       ret = ehea_driver_sysfs_add(&port->ofdev.dev, &ehea_driver.driver);
-       if (ret) {
-               ehea_error("failed to register sysfs driver link");
-               goto out_rem_dev_file;
-       }
-
        return &port->ofdev.dev;
 
-out_rem_dev_file:
-       device_remove_file(&port->ofdev.dev, &dev_attr_log_port_id);
 out_unreg_of_dev:
        of_device_unregister(&port->ofdev);
 out:
@@ -2874,7 +2843,6 @@ out:
 
 static void ehea_unregister_port(struct ehea_port *port)
 {
-       ehea_driver_sysfs_remove(&port->ofdev.dev, &ehea_driver.driver);
        device_remove_file(&port->ofdev.dev, &dev_attr_log_port_id);
        of_device_unregister(&port->ofdev);
 }
@@ -3109,7 +3077,7 @@ static ssize_t ehea_probe_port(struct device *dev,
        of_node_put(eth_dn);
 
        if (port) {
-               for (i=0; i < EHEA_MAX_PORTS; i++)
+               for (i = 0; i < EHEA_MAX_PORTS; i++)
                        if (!adapter->port[i]) {
                                adapter->port[i] = port;
                                break;
@@ -3144,7 +3112,7 @@ static ssize_t ehea_remove_port(struct device *dev,
 
                ehea_shutdown_single_port(port);
 
-               for (i=0; i < EHEA_MAX_PORTS; i++)
+               for (i = 0; i < EHEA_MAX_PORTS; i++)
                        if (adapter->port[i] == port) {
                                adapter->port[i] = NULL;
                                break;
@@ -3313,7 +3281,7 @@ static int ehea_reboot_notifier(struct notifier_block *nb,
 }
 
 static struct notifier_block ehea_reboot_nb = {
-        .notifier_call = ehea_reboot_notifier,
+       .notifier_call = ehea_reboot_notifier,
 };
 
 static int check_module_parm(void)
index 95c4a7f9cc88aacbaf64cbbbec35f089bcc2adbd..156eb6320b4ee209369a80f5ec83f4740b7c63bf 100644 (file)
@@ -6,9 +6,9 @@
  *  (C) Copyright IBM Corp. 2006
  *
  *  Authors:
- *       Christoph Raisch <raisch@de.ibm.com>
- *       Jan-Bernd Themann <themann@de.ibm.com>
- *       Thomas Klein <tklein@de.ibm.com>
+ *      Christoph Raisch <raisch@de.ibm.com>
+ *      Jan-Bernd Themann <themann@de.ibm.com>
+ *      Thomas Klein <tklein@de.ibm.com>
  *
  *
  * This program is free software; you can redistribute it and/or modify
@@ -38,11 +38,11 @@ static inline u16 get_order_of_qentries(u16 queue_entries)
 }
 
 /* Defines for H_CALL H_ALLOC_RESOURCE */
-#define H_ALL_RES_TYPE_QP        1
-#define H_ALL_RES_TYPE_CQ        2
-#define H_ALL_RES_TYPE_EQ        3
-#define H_ALL_RES_TYPE_MR        5
-#define H_ALL_RES_TYPE_MW        6
+#define H_ALL_RES_TYPE_QP       1
+#define H_ALL_RES_TYPE_CQ       2
+#define H_ALL_RES_TYPE_EQ       3
+#define H_ALL_RES_TYPE_MR       5
+#define H_ALL_RES_TYPE_MW       6
 
 static long ehea_plpar_hcall_norets(unsigned long opcode,
                                    unsigned long arg1,
@@ -137,77 +137,77 @@ u64 ehea_h_query_ehea_qp(const u64 adapter_handle, const u8 qp_category,
                         const u64 qp_handle, const u64 sel_mask, void *cb_addr)
 {
        return ehea_plpar_hcall_norets(H_QUERY_HEA_QP,
-                                      adapter_handle,          /* R4 */
-                                      qp_category,             /* R5 */
-                                      qp_handle,               /* R6 */
-                                      sel_mask,                /* R7 */
+                                      adapter_handle,          /* R4 */
+                                      qp_category,             /* R5 */
+                                      qp_handle,               /* R6 */
+                                      sel_mask,                /* R7 */
                                       virt_to_abs(cb_addr),    /* R8 */
                                       0, 0);
 }
 
 /* input param R5 */
-#define H_ALL_RES_QP_EQPO         EHEA_BMASK_IBM(9, 11)
-#define H_ALL_RES_QP_QPP          EHEA_BMASK_IBM(12, 12)
-#define H_ALL_RES_QP_RQR          EHEA_BMASK_IBM(13, 15)
-#define H_ALL_RES_QP_EQEG         EHEA_BMASK_IBM(16, 16)
-#define H_ALL_RES_QP_LL_QP        EHEA_BMASK_IBM(17, 17)
-#define H_ALL_RES_QP_DMA128       EHEA_BMASK_IBM(19, 19)
-#define H_ALL_RES_QP_HSM          EHEA_BMASK_IBM(20, 21)
-#define H_ALL_RES_QP_SIGT         EHEA_BMASK_IBM(22, 23)
-#define H_ALL_RES_QP_TENURE       EHEA_BMASK_IBM(48, 55)
-#define H_ALL_RES_QP_RES_TYP      EHEA_BMASK_IBM(56, 63)
+#define H_ALL_RES_QP_EQPO        EHEA_BMASK_IBM(9, 11)
+#define H_ALL_RES_QP_QPP         EHEA_BMASK_IBM(12, 12)
+#define H_ALL_RES_QP_RQR         EHEA_BMASK_IBM(13, 15)
+#define H_ALL_RES_QP_EQEG        EHEA_BMASK_IBM(16, 16)
+#define H_ALL_RES_QP_LL_QP       EHEA_BMASK_IBM(17, 17)
+#define H_ALL_RES_QP_DMA128      EHEA_BMASK_IBM(19, 19)
+#define H_ALL_RES_QP_HSM         EHEA_BMASK_IBM(20, 21)
+#define H_ALL_RES_QP_SIGT        EHEA_BMASK_IBM(22, 23)
+#define H_ALL_RES_QP_TENURE      EHEA_BMASK_IBM(48, 55)
+#define H_ALL_RES_QP_RES_TYP     EHEA_BMASK_IBM(56, 63)
 
 /* input param R9  */
-#define H_ALL_RES_QP_TOKEN        EHEA_BMASK_IBM(0, 31)
-#define H_ALL_RES_QP_PD           EHEA_BMASK_IBM(32,63)
+#define H_ALL_RES_QP_TOKEN       EHEA_BMASK_IBM(0, 31)
+#define H_ALL_RES_QP_PD                  EHEA_BMASK_IBM(32, 63)
 
 /* input param R10 */
-#define H_ALL_RES_QP_MAX_SWQE     EHEA_BMASK_IBM(4, 7)
-#define H_ALL_RES_QP_MAX_R1WQE    EHEA_BMASK_IBM(12, 15)
-#define H_ALL_RES_QP_MAX_R2WQE    EHEA_BMASK_IBM(20, 23)
-#define H_ALL_RES_QP_MAX_R3WQE    EHEA_BMASK_IBM(28, 31)
+#define H_ALL_RES_QP_MAX_SWQE    EHEA_BMASK_IBM(4, 7)
+#define H_ALL_RES_QP_MAX_R1WQE   EHEA_BMASK_IBM(12, 15)
+#define H_ALL_RES_QP_MAX_R2WQE   EHEA_BMASK_IBM(20, 23)
+#define H_ALL_RES_QP_MAX_R3WQE   EHEA_BMASK_IBM(28, 31)
 /* Max Send Scatter Gather Elements */
-#define H_ALL_RES_QP_MAX_SSGE     EHEA_BMASK_IBM(37, 39)
-#define H_ALL_RES_QP_MAX_R1SGE    EHEA_BMASK_IBM(45, 47)
+#define H_ALL_RES_QP_MAX_SSGE    EHEA_BMASK_IBM(37, 39)
+#define H_ALL_RES_QP_MAX_R1SGE   EHEA_BMASK_IBM(45, 47)
 /* Max Receive SG Elements RQ1 */
-#define H_ALL_RES_QP_MAX_R2SGE    EHEA_BMASK_IBM(53, 55)
-#define H_ALL_RES_QP_MAX_R3SGE    EHEA_BMASK_IBM(61, 63)
+#define H_ALL_RES_QP_MAX_R2SGE   EHEA_BMASK_IBM(53, 55)
+#define H_ALL_RES_QP_MAX_R3SGE   EHEA_BMASK_IBM(61, 63)
 
 /* input param R11 */
-#define H_ALL_RES_QP_SWQE_IDL     EHEA_BMASK_IBM(0, 7)
+#define H_ALL_RES_QP_SWQE_IDL    EHEA_BMASK_IBM(0, 7)
 /* max swqe immediate data length */
-#define H_ALL_RES_QP_PORT_NUM     EHEA_BMASK_IBM(48, 63)
+#define H_ALL_RES_QP_PORT_NUM    EHEA_BMASK_IBM(48, 63)
 
 /* input param R12 */
-#define H_ALL_RES_QP_TH_RQ2       EHEA_BMASK_IBM(0, 15)
+#define H_ALL_RES_QP_TH_RQ2      EHEA_BMASK_IBM(0, 15)
 /* Threshold RQ2 */
-#define H_ALL_RES_QP_TH_RQ3       EHEA_BMASK_IBM(16, 31)
+#define H_ALL_RES_QP_TH_RQ3      EHEA_BMASK_IBM(16, 31)
 /* Threshold RQ3 */
 
 /* output param R6 */
-#define H_ALL_RES_QP_ACT_SWQE     EHEA_BMASK_IBM(0, 15)
-#define H_ALL_RES_QP_ACT_R1WQE    EHEA_BMASK_IBM(16, 31)
-#define H_ALL_RES_QP_ACT_R2WQE    EHEA_BMASK_IBM(32, 47)
-#define H_ALL_RES_QP_ACT_R3WQE    EHEA_BMASK_IBM(48, 63)
+#define H_ALL_RES_QP_ACT_SWQE    EHEA_BMASK_IBM(0, 15)
+#define H_ALL_RES_QP_ACT_R1WQE   EHEA_BMASK_IBM(16, 31)
+#define H_ALL_RES_QP_ACT_R2WQE   EHEA_BMASK_IBM(32, 47)
+#define H_ALL_RES_QP_ACT_R3WQE   EHEA_BMASK_IBM(48, 63)
 
 /* output param, R7 */
-#define H_ALL_RES_QP_ACT_SSGE     EHEA_BMASK_IBM(0, 7)
-#define H_ALL_RES_QP_ACT_R1SGE    EHEA_BMASK_IBM(8, 15)
-#define H_ALL_RES_QP_ACT_R2SGE    EHEA_BMASK_IBM(16, 23)
-#define H_ALL_RES_QP_ACT_R3SGE    EHEA_BMASK_IBM(24, 31)
+#define H_ALL_RES_QP_ACT_SSGE    EHEA_BMASK_IBM(0, 7)
+#define H_ALL_RES_QP_ACT_R1SGE   EHEA_BMASK_IBM(8, 15)
+#define H_ALL_RES_QP_ACT_R2SGE   EHEA_BMASK_IBM(16, 23)
+#define H_ALL_RES_QP_ACT_R3SGE   EHEA_BMASK_IBM(24, 31)
 #define H_ALL_RES_QP_ACT_SWQE_IDL EHEA_BMASK_IBM(32, 39)
 
 /* output param R8,R9 */
-#define H_ALL_RES_QP_SIZE_SQ      EHEA_BMASK_IBM(0, 31)
-#define H_ALL_RES_QP_SIZE_RQ1     EHEA_BMASK_IBM(32, 63)
-#define H_ALL_RES_QP_SIZE_RQ2     EHEA_BMASK_IBM(0, 31)
-#define H_ALL_RES_QP_SIZE_RQ3     EHEA_BMASK_IBM(32, 63)
+#define H_ALL_RES_QP_SIZE_SQ     EHEA_BMASK_IBM(0, 31)
+#define H_ALL_RES_QP_SIZE_RQ1    EHEA_BMASK_IBM(32, 63)
+#define H_ALL_RES_QP_SIZE_RQ2    EHEA_BMASK_IBM(0, 31)
+#define H_ALL_RES_QP_SIZE_RQ3    EHEA_BMASK_IBM(32, 63)
 
 /* output param R11,R12 */
-#define H_ALL_RES_QP_LIOBN_SQ     EHEA_BMASK_IBM(0, 31)
-#define H_ALL_RES_QP_LIOBN_RQ1    EHEA_BMASK_IBM(32, 63)
-#define H_ALL_RES_QP_LIOBN_RQ2    EHEA_BMASK_IBM(0, 31)
-#define H_ALL_RES_QP_LIOBN_RQ3    EHEA_BMASK_IBM(32, 63)
+#define H_ALL_RES_QP_LIOBN_SQ    EHEA_BMASK_IBM(0, 31)
+#define H_ALL_RES_QP_LIOBN_RQ1   EHEA_BMASK_IBM(32, 63)
+#define H_ALL_RES_QP_LIOBN_RQ2   EHEA_BMASK_IBM(0, 31)
+#define H_ALL_RES_QP_LIOBN_RQ3   EHEA_BMASK_IBM(32, 63)
 
 u64 ehea_h_alloc_resource_qp(const u64 adapter_handle,
                             struct ehea_qp_init_attr *init_attr, const u32 pd,
@@ -334,28 +334,28 @@ u64 ehea_h_alloc_resource_cq(const u64 adapter_handle,
 }
 
 /* Defines for H_CALL H_ALLOC_RESOURCE */
-#define H_ALL_RES_TYPE_QP        1
-#define H_ALL_RES_TYPE_CQ        2
-#define H_ALL_RES_TYPE_EQ        3
-#define H_ALL_RES_TYPE_MR        5
-#define H_ALL_RES_TYPE_MW        6
+#define H_ALL_RES_TYPE_QP       1
+#define H_ALL_RES_TYPE_CQ       2
+#define H_ALL_RES_TYPE_EQ       3
+#define H_ALL_RES_TYPE_MR       5
+#define H_ALL_RES_TYPE_MW       6
 
 /*  input param R5 */
-#define H_ALL_RES_EQ_NEQ             EHEA_BMASK_IBM(0, 0)
+#define H_ALL_RES_EQ_NEQ            EHEA_BMASK_IBM(0, 0)
 #define H_ALL_RES_EQ_NON_NEQ_ISN     EHEA_BMASK_IBM(6, 7)
 #define H_ALL_RES_EQ_INH_EQE_GEN     EHEA_BMASK_IBM(16, 16)
-#define H_ALL_RES_EQ_RES_TYPE        EHEA_BMASK_IBM(56, 63)
+#define H_ALL_RES_EQ_RES_TYPE       EHEA_BMASK_IBM(56, 63)
 /*  input param R6 */
-#define H_ALL_RES_EQ_MAX_EQE         EHEA_BMASK_IBM(32, 63)
+#define H_ALL_RES_EQ_MAX_EQE        EHEA_BMASK_IBM(32, 63)
 
 /*  output param R6 */
-#define H_ALL_RES_EQ_LIOBN           EHEA_BMASK_IBM(32, 63)
+#define H_ALL_RES_EQ_LIOBN          EHEA_BMASK_IBM(32, 63)
 
 /*  output param R7 */
-#define H_ALL_RES_EQ_ACT_EQE         EHEA_BMASK_IBM(32, 63)
+#define H_ALL_RES_EQ_ACT_EQE        EHEA_BMASK_IBM(32, 63)
 
 /*  output param R8 */
-#define H_ALL_RES_EQ_ACT_PS          EHEA_BMASK_IBM(32, 63)
+#define H_ALL_RES_EQ_ACT_PS         EHEA_BMASK_IBM(32, 63)
 
 /*  output param R9 */
 #define H_ALL_RES_EQ_ACT_EQ_IST_C    EHEA_BMASK_IBM(30, 31)
@@ -453,12 +453,12 @@ u64 ehea_h_register_smr(const u64 adapter_handle, const u64 orig_mr_handle,
 
        hret = ehea_plpar_hcall9(H_REGISTER_SMR,
                                 outs,
-                                adapter_handle       ,          /* R4 */
-                                orig_mr_handle,                 /* R5 */
-                                vaddr_in,                       /* R6 */
-                                (((u64)access_ctrl) << 32ULL),  /* R7 */
-                                pd,                             /* R8 */
-                                0, 0, 0, 0);                    /* R9-R12 */
+                                adapter_handle       ,          /* R4 */
+                                orig_mr_handle,                 /* R5 */
+                                vaddr_in,                       /* R6 */
+                                (((u64)access_ctrl) << 32ULL),  /* R7 */
+                                pd,                             /* R8 */
+                                0, 0, 0, 0);                    /* R9-R12 */
 
        mr->handle = outs[0];
        mr->lkey = (u32)outs[2];
@@ -471,11 +471,11 @@ u64 ehea_h_disable_and_get_hea(const u64 adapter_handle, const u64 qp_handle)
        u64 outs[PLPAR_HCALL9_BUFSIZE];
 
        return ehea_plpar_hcall9(H_DISABLE_AND_GET_HEA,
-                                        outs,
+                                outs,
                                 adapter_handle,                /* R4 */
                                 H_DISABLE_GET_EHEA_WQE_P,      /* R5 */
                                 qp_handle,                     /* R6 */
-                                0, 0, 0, 0, 0, 0);             /* R7-R12 */
+                                0, 0, 0, 0, 0, 0);             /* R7-R12 */
 }
 
 u64 ehea_h_free_resource(const u64 adapter_handle, const u64 res_handle,
@@ -483,9 +483,9 @@ u64 ehea_h_free_resource(const u64 adapter_handle, const u64 res_handle,
 {
        return ehea_plpar_hcall_norets(H_FREE_RESOURCE,
                                       adapter_handle,     /* R4 */
-                                      res_handle,         /* R5 */
+                                      res_handle,         /* R5 */
                                       force_bit,
-                                      0, 0, 0, 0);        /* R7-R10 */
+                                      0, 0, 0, 0);        /* R7-R10 */
 }
 
 u64 ehea_h_alloc_resource_mr(const u64 adapter_handle, const u64 vaddr,
@@ -493,13 +493,13 @@ u64 ehea_h_alloc_resource_mr(const u64 adapter_handle, const u64 vaddr,
                             const u32 pd, u64 *mr_handle, u32 *lkey)
 {
        u64 hret;
-       u64 outs[PLPAR_HCALL9_BUFSIZE];
+       u64 outs[PLPAR_HCALL9_BUFSIZE];
 
        hret = ehea_plpar_hcall9(H_ALLOC_HEA_RESOURCE,
                                 outs,
                                 adapter_handle,                   /* R4 */
                                 5,                                /* R5 */
-                                vaddr,                            /* R6 */
+                                vaddr,                            /* R6 */
                                 length,                           /* R7 */
                                 (((u64) access_ctrl) << 32ULL),   /* R8 */
                                 pd,                               /* R9 */
@@ -619,8 +619,8 @@ u64 ehea_h_error_data(const u64 adapter_handle, const u64 ressource_handle,
                      void *rblock)
 {
        return ehea_plpar_hcall_norets(H_ERROR_DATA,
-                                      adapter_handle,          /* R4 */
-                                      ressource_handle,        /* R5 */
-                                      virt_to_abs(rblock),     /* R6 */
-                                      0, 0, 0, 0);             /* R7-R12 */
+                                      adapter_handle,          /* R4 */
+                                      ressource_handle,        /* R5 */
+                                      virt_to_abs(rblock),     /* R6 */
+                                      0, 0, 0, 0);             /* R7-R12 */
 }
index faa191d23b8614f095bb0a39bc93673304cb330d..f3628c803567674c4b5650a9d71389b5aea0290e 100644 (file)
@@ -93,7 +93,7 @@ static inline void hcp_epas_ctor(struct h_epas *epas, u64 paddr_kernel,
 static inline void hcp_epas_dtor(struct h_epas *epas)
 {
        if (epas->kernel.addr)
-               iounmap((void __iomem*)((u64)epas->kernel.addr & PAGE_MASK));
+               iounmap((void __iomem *)((u64)epas->kernel.addr & PAGE_MASK));
 
        epas->user.addr = 0;
        epas->kernel.addr = 0;
@@ -388,23 +388,23 @@ u64 ehea_h_modify_ehea_qp(const u64 adapter_handle,
                          const u64 qp_handle,
                          const u64 sel_mask,
                          void *cb_addr,
-                         u64 * inv_attr_id,
-                         u64 * proc_mask, u16 * out_swr, u16 * out_rwr);
+                         u64 *inv_attr_id,
+                         u64 *proc_mask, u16 *out_swr, u16 *out_rwr);
 
 u64 ehea_h_alloc_resource_eq(const u64 adapter_handle,
-                            struct ehea_eq_attr *eq_attr, u64 * eq_handle);
+                            struct ehea_eq_attr *eq_attr, u64 *eq_handle);
 
 u64 ehea_h_alloc_resource_cq(const u64 adapter_handle,
                             struct ehea_cq_attr *cq_attr,
-                            u64 * cq_handle, struct h_epas *epas);
+                            u64 *cq_handle, struct h_epas *epas);
 
 u64 ehea_h_alloc_resource_qp(const u64 adapter_handle,
                             struct ehea_qp_init_attr *init_attr,
                             const u32 pd,
-                            u64 * qp_handle, struct h_epas *h_epas);
+                            u64 *qp_handle, struct h_epas *h_epas);
 
-#define H_REG_RPAGE_PAGE_SIZE          EHEA_BMASK_IBM(48,55)
-#define H_REG_RPAGE_QT                 EHEA_BMASK_IBM(62,63)
+#define H_REG_RPAGE_PAGE_SIZE          EHEA_BMASK_IBM(48, 55)
+#define H_REG_RPAGE_QT                 EHEA_BMASK_IBM(62, 63)
 
 u64 ehea_h_register_rpage(const u64 adapter_handle,
                          const u8 pagesize,
@@ -426,7 +426,7 @@ u64 ehea_h_free_resource(const u64 adapter_handle, const u64 res_handle,
 
 u64 ehea_h_alloc_resource_mr(const u64 adapter_handle, const u64 vaddr,
                             const u64 length, const u32 access_ctrl,
-                            const u32 pd, u64 * mr_handle, u32 * lkey);
+                            const u32 pd, u64 *mr_handle, u32 *lkey);
 
 u64 ehea_h_register_rpage_mr(const u64 adapter_handle, const u64 mr_handle,
                             const u8 pagesize, const u8 queue_type,
@@ -439,8 +439,8 @@ u64 ehea_h_register_smr(const u64 adapter_handle, const u64 orig_mr_handle,
 u64 ehea_h_query_ehea(const u64 adapter_handle, void *cb_addr);
 
 /* output param R5 */
-#define H_MEHEAPORT_CAT                EHEA_BMASK_IBM(40,47)
-#define H_MEHEAPORT_PN         EHEA_BMASK_IBM(48,63)
+#define H_MEHEAPORT_CAT                EHEA_BMASK_IBM(40, 47)
+#define H_MEHEAPORT_PN         EHEA_BMASK_IBM(48, 63)
 
 u64 ehea_h_query_ehea_port(const u64 adapter_handle, const u16 port_num,
                           const u8 cb_cat, const u64 select_mask,
index 83b76432b41a8cc6c299ad3530b4e4bd98b5ac2a..d522e905f460585364a659d8f8cfb2c11d818d14 100644 (file)
@@ -33,8 +33,6 @@
 
 
 struct ehea_busmap ehea_bmap = { 0, 0, NULL };
-extern u64 ehea_driver_flags;
-extern struct work_struct ehea_rereg_mr_task;
 
 
 static void *hw_qpageit_get_inc(struct hw_queue *queue)
@@ -65,7 +63,7 @@ static int hw_queue_ctor(struct hw_queue *queue, const u32 nr_of_pages,
        }
 
        queue->queue_length = nr_of_pages * pagesize;
-       queue->queue_pages = kmalloc(nr_of_pages * sizeof(void*), GFP_KERNEL);
+       queue->queue_pages = kmalloc(nr_of_pages * sizeof(void *), GFP_KERNEL);
        if (!queue->queue_pages) {
                ehea_error("no mem for queue_pages");
                return -ENOMEM;
@@ -78,11 +76,11 @@ static int hw_queue_ctor(struct hw_queue *queue, const u32 nr_of_pages,
         */
        i = 0;
        while (i < nr_of_pages) {
-               u8 *kpage = (u8*)get_zeroed_page(GFP_KERNEL);
+               u8 *kpage = (u8 *)get_zeroed_page(GFP_KERNEL);
                if (!kpage)
                        goto out_nomem;
                for (k = 0; k < pages_per_kpage && i < nr_of_pages; k++) {
-                       (queue->queue_pages)[i] = (struct ehea_page*)kpage;
+                       (queue->queue_pages)[i] = (struct ehea_page *)kpage;
                        kpage += pagesize;
                        i++;
                }
@@ -235,8 +233,8 @@ int ehea_destroy_cq(struct ehea_cq *cq)
                return 0;
 
        hcp_epas_dtor(&cq->epas);
-
-       if ((hret = ehea_destroy_cq_res(cq, NORMAL_FREE)) == H_R_STATE) {
+       hret = ehea_destroy_cq_res(cq, NORMAL_FREE);
+       if (hret == H_R_STATE) {
                ehea_error_data(cq->adapter, cq->fw_handle);
                hret = ehea_destroy_cq_res(cq, FORCE_FREE);
        }
@@ -301,13 +299,13 @@ struct ehea_eq *ehea_create_eq(struct ehea_adapter *adapter,
                if (i == (eq->attr.nr_pages - 1)) {
                        /* last page */
                        vpage = hw_qpageit_get_inc(&eq->hw_queue);
-                       if ((hret != H_SUCCESS) || (vpage)) {
+                       if ((hret != H_SUCCESS) || (vpage))
                                goto out_kill_hwq;
-                       }
+
                } else {
-                       if ((hret != H_PAGE_REGISTERED) || (!vpage)) {
+                       if ((hret != H_PAGE_REGISTERED) || (!vpage))
                                goto out_kill_hwq;
-                       }
+
                }
        }
 
@@ -331,7 +329,7 @@ struct ehea_eqe *ehea_poll_eq(struct ehea_eq *eq)
        unsigned long flags;
 
        spin_lock_irqsave(&eq->spinlock, flags);
-       eqe = (struct ehea_eqe*)hw_eqit_eq_get_inc_valid(&eq->hw_queue);
+       eqe = (struct ehea_eqe *)hw_eqit_eq_get_inc_valid(&eq->hw_queue);
        spin_unlock_irqrestore(&eq->spinlock, flags);
 
        return eqe;
@@ -364,7 +362,8 @@ int ehea_destroy_eq(struct ehea_eq *eq)
 
        hcp_epas_dtor(&eq->epas);
 
-       if ((hret = ehea_destroy_eq_res(eq, NORMAL_FREE)) == H_R_STATE) {
+       hret = ehea_destroy_eq_res(eq, NORMAL_FREE);
+       if (hret == H_R_STATE) {
                ehea_error_data(eq->adapter, eq->fw_handle);
                hret = ehea_destroy_eq_res(eq, FORCE_FREE);
        }
@@ -546,7 +545,8 @@ int ehea_destroy_qp(struct ehea_qp *qp)
 
        hcp_epas_dtor(&qp->epas);
 
-       if ((hret = ehea_destroy_qp_res(qp, NORMAL_FREE)) == H_R_STATE) {
+       hret = ehea_destroy_qp_res(qp, NORMAL_FREE);
+       if (hret == H_R_STATE) {
                ehea_error_data(qp->adapter, qp->fw_handle);
                hret = ehea_destroy_qp_res(qp, FORCE_FREE);
        }
@@ -559,7 +559,7 @@ int ehea_destroy_qp(struct ehea_qp *qp)
        return 0;
 }
 
-int ehea_create_busmap( void )
+int ehea_create_busmap(void)
 {
        u64 vaddr = EHEA_BUSMAP_START;
        unsigned long high_section_index = 0;
@@ -595,7 +595,7 @@ int ehea_create_busmap( void )
        return 0;
 }
 
-void ehea_destroy_busmap( void )
+void ehea_destroy_busmap(void)
 {
        vfree(ehea_bmap.vaddr);
 }
index bc62d389c166578fe179567968009bc8b6752b60..0bb6f92fa2f8ed7743c07dd883d67bfcb7e74b6e 100644 (file)
@@ -41,8 +41,8 @@
 #define EHEA_SECTSIZE          (1UL << 24)
 #define EHEA_PAGES_PER_SECTION (EHEA_SECTSIZE >> EHEA_PAGESHIFT)
 
-#if (1UL << SECTION_SIZE_BITS) < EHEA_SECTSIZE
-#error eHEA module can't work if kernel sectionsize < ehea sectionsize
+#if ((1UL << SECTION_SIZE_BITS) < EHEA_SECTSIZE)
+#error eHEA module cannot work if kernel sectionsize < ehea sectionsize
 #endif
 
 /* Some abbreviations used here:
@@ -188,8 +188,8 @@ struct ehea_eqe {
        u64 entry;
 };
 
-#define ERROR_DATA_LENGTH  EHEA_BMASK_IBM(52,63)
-#define ERROR_DATA_TYPE    EHEA_BMASK_IBM(0,7)
+#define ERROR_DATA_LENGTH  EHEA_BMASK_IBM(52, 63)
+#define ERROR_DATA_TYPE    EHEA_BMASK_IBM(0, 7)
 
 static inline void *hw_qeit_calc(struct hw_queue *queue, u64 q_offset)
 {
@@ -279,7 +279,7 @@ static inline void *hw_qeit_eq_get_inc(struct hw_queue *queue)
 static inline void *hw_eqit_eq_get_inc_valid(struct hw_queue *queue)
 {
        void *retvalue = hw_qeit_get(queue);
-       u32 qe = *(u8*)retvalue;
+       u32 qe = *(u8 *)retvalue;
        if ((qe >> 7) == (queue->toggle_state & 1))
                hw_qeit_eq_get_inc(queue);
        else
@@ -364,7 +364,7 @@ struct ehea_cq *ehea_create_cq(struct ehea_adapter *adapter, int cqe,
 
 int ehea_destroy_cq(struct ehea_cq *cq);
 
-struct ehea_qp *ehea_create_qp(struct ehea_adapter * adapter, u32 pd,
+struct ehea_qp *ehea_create_qp(struct ehea_adapter *adapter, u32 pd,
                               struct ehea_qp_init_attr *init_attr);
 
 int ehea_destroy_qp(struct ehea_qp *qp);
@@ -378,8 +378,8 @@ int ehea_rem_mr(struct ehea_mr *mr);
 
 void ehea_error_data(struct ehea_adapter *adapter, u64 res_handle);
 
-int ehea_create_busmap( void );
-void ehea_destroy_busmap( void );
+int ehea_create_busmap(void);
+void ehea_destroy_busmap(void);
 u64 ehea_map_vaddr(void *caddr);
 
 #endif /* __EHEA_QMR_H__ */
index 7667a62ac31f33c822c03f6ad11619d54e91d7ac..36342230a6deeb79ea89c5cb011c1724b1040bca 100644 (file)
@@ -13,7 +13,7 @@
  * Copyright (C) 2004 Andrew de Quincey (wol support)
  * Copyright (C) 2004 Carl-Daniel Hailfinger (invalid MAC handling, insane
  *             IRQ rate fixes, bigendian fixes, cleanups, verification)
- * Copyright (c) 2004,5,6 NVIDIA Corporation
+ * Copyright (c) 2004,2005,2006,2007,2008 NVIDIA 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
@@ -226,7 +226,7 @@ enum {
 #define NVREG_MISC1_HD         0x02
 #define NVREG_MISC1_FORCE      0x3b0f3c
 
-       NvRegMacReset = 0x3c,
+       NvRegMacReset = 0x34,
 #define NVREG_MAC_RESET_ASSERT 0x0F3
        NvRegTransmitterControl = 0x084,
 #define NVREG_XMITCTL_START    0x01
@@ -277,7 +277,9 @@ enum {
 #define NVREG_MCASTADDRA_FORCE 0x01
        NvRegMulticastAddrB = 0xB4,
        NvRegMulticastMaskA = 0xB8,
+#define NVREG_MCASTMASKA_NONE          0xffffffff
        NvRegMulticastMaskB = 0xBC,
+#define NVREG_MCASTMASKB_NONE          0xffff
 
        NvRegPhyInterface = 0xC0,
 #define PHY_RGMII              0x10000000
@@ -316,8 +318,8 @@ enum {
        NvRegTxRingPhysAddrHigh = 0x148,
        NvRegRxRingPhysAddrHigh = 0x14C,
        NvRegTxPauseFrame = 0x170,
-#define NVREG_TX_PAUSEFRAME_DISABLE    0x1ff0080
-#define NVREG_TX_PAUSEFRAME_ENABLE     0x0c00030
+#define NVREG_TX_PAUSEFRAME_DISABLE    0x01ff0080
+#define NVREG_TX_PAUSEFRAME_ENABLE     0x01800010
        NvRegMIIStatus = 0x180,
 #define NVREG_MIISTAT_ERROR            0x0001
 #define NVREG_MIISTAT_LINKCHANGE       0x0008
@@ -471,9 +473,9 @@ union ring_type {
 #define NV_RX_AVAIL            (1<<31)
 
 #define NV_RX2_CHECKSUMMASK    (0x1C000000)
-#define NV_RX2_CHECKSUMOK1     (0x10000000)
-#define NV_RX2_CHECKSUMOK2     (0x14000000)
-#define NV_RX2_CHECKSUMOK3     (0x18000000)
+#define NV_RX2_CHECKSUM_IP     (0x10000000)
+#define NV_RX2_CHECKSUM_IP_TCP (0x14000000)
+#define NV_RX2_CHECKSUM_IP_UDP (0x18000000)
 #define NV_RX2_DESCRIPTORVALID (1<<29)
 #define NV_RX2_SUBSTRACT1      (1<<25)
 #define NV_RX2_ERROR1          (1<<18)
@@ -2375,14 +2377,9 @@ static int nv_rx_process(struct net_device *dev, int limit)
                                                goto next_pkt;
                                        }
                                }
-                               if ((flags & NV_RX2_CHECKSUMMASK) == NV_RX2_CHECKSUMOK2)/*ip and tcp */ {
+                               if (((flags & NV_RX2_CHECKSUMMASK) == NV_RX2_CHECKSUM_IP_TCP) || /*ip and tcp */
+                                   ((flags & NV_RX2_CHECKSUMMASK) == NV_RX2_CHECKSUM_IP_UDP))   /*ip and udp */
                                        skb->ip_summed = CHECKSUM_UNNECESSARY;
-                               } else {
-                                       if ((flags & NV_RX2_CHECKSUMMASK) == NV_RX2_CHECKSUMOK1 ||
-                                           (flags & NV_RX2_CHECKSUMMASK) == NV_RX2_CHECKSUMOK3) {
-                                               skb->ip_summed = CHECKSUM_UNNECESSARY;
-                                       }
-                               }
                        } else {
                                dev_kfree_skb(skb);
                                goto next_pkt;
@@ -2474,14 +2471,9 @@ static int nv_rx_process_optimized(struct net_device *dev, int limit)
                                }
                        }
 
-                       if ((flags & NV_RX2_CHECKSUMMASK) == NV_RX2_CHECKSUMOK2)/*ip and tcp */ {
+                       if (((flags & NV_RX2_CHECKSUMMASK) == NV_RX2_CHECKSUM_IP_TCP) || /*ip and tcp */
+                           ((flags & NV_RX2_CHECKSUMMASK) == NV_RX2_CHECKSUM_IP_UDP))   /*ip and udp */
                                skb->ip_summed = CHECKSUM_UNNECESSARY;
-                       } else {
-                               if ((flags & NV_RX2_CHECKSUMMASK) == NV_RX2_CHECKSUMOK1 ||
-                                   (flags & NV_RX2_CHECKSUMMASK) == NV_RX2_CHECKSUMOK3) {
-                                       skb->ip_summed = CHECKSUM_UNNECESSARY;
-                               }
-                       }
 
                        /* got a valid packet - forward it to the network core */
                        skb_put(skb, len);
@@ -2703,6 +2695,9 @@ static void nv_set_multicast(struct net_device *dev)
                        addr[1] = alwaysOn[1];
                        mask[0] = alwaysOn[0] | alwaysOff[0];
                        mask[1] = alwaysOn[1] | alwaysOff[1];
+               } else {
+                       mask[0] = NVREG_MCASTMASKA_NONE;
+                       mask[1] = NVREG_MCASTMASKB_NONE;
                }
        }
        addr[0] |= NVREG_MCASTADDRA_FORCE;
@@ -4813,8 +4808,8 @@ static int nv_open(struct net_device *dev)
                nv_mac_reset(dev);
        writel(NVREG_MCASTADDRA_FORCE, base + NvRegMulticastAddrA);
        writel(0, base + NvRegMulticastAddrB);
-       writel(0, base + NvRegMulticastMaskA);
-       writel(0, base + NvRegMulticastMaskB);
+       writel(NVREG_MCASTMASKA_NONE, base + NvRegMulticastMaskA);
+       writel(NVREG_MCASTMASKB_NONE, base + NvRegMulticastMaskB);
        writel(0, base + NvRegPacketFilterFlags);
 
        writel(0, base + NvRegTransmitterControl);
@@ -4908,8 +4903,8 @@ static int nv_open(struct net_device *dev)
        spin_lock_irq(&np->lock);
        writel(NVREG_MCASTADDRA_FORCE, base + NvRegMulticastAddrA);
        writel(0, base + NvRegMulticastAddrB);
-       writel(0, base + NvRegMulticastMaskA);
-       writel(0, base + NvRegMulticastMaskB);
+       writel(NVREG_MCASTMASKA_NONE, base + NvRegMulticastMaskA);
+       writel(NVREG_MCASTMASKB_NONE, base + NvRegMulticastMaskB);
        writel(NVREG_PFF_ALWAYS|NVREG_PFF_MYADDR, base + NvRegPacketFilterFlags);
        /* One manual link speed update: Interrupts are enabled, future link
         * speed changes cause interrupts and are handled by nv_link_irq().
@@ -5603,35 +5598,35 @@ static struct pci_device_id pci_tbl[] = {
        },
        {       /* MCP77 Ethernet Controller */
                PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_32),
-               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR,
        },
        {       /* MCP77 Ethernet Controller */
                PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_33),
-               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR,
        },
        {       /* MCP77 Ethernet Controller */
                PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_34),
-               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR,
        },
        {       /* MCP77 Ethernet Controller */
                PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_35),
-               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR,
        },
        {       /* MCP79 Ethernet Controller */
                PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_36),
-               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR,
        },
        {       /* MCP79 Ethernet Controller */
                PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_37),
-               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR,
        },
        {       /* MCP79 Ethernet Controller */
                PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_38),
-               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR,
        },
        {       /* MCP79 Ethernet Controller */
                PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_39),
-               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR,
        },
        {0,},
 };
index 11b83dae00ac762f8732ccefaf92ab92716a9959..e04bf992644197f4eb211e1ff42122cb7e2fbcb2 100644 (file)
@@ -262,8 +262,8 @@ static void tm_isr(struct scc_priv *priv);
 
 static int io[MAX_NUM_DEVS] __initdata = { 0, };
 
-/* Beware! hw[] is also used in cleanup_module(). */
-static struct scc_hardware hw[NUM_TYPES] __initdata_or_module = HARDWARE;
+/* Beware! hw[] is also used in dmascc_exit(). */
+static struct scc_hardware hw[NUM_TYPES] = HARDWARE;
 
 
 /* Global variables */
index 46e2c52c7862f436248d85942e6c4cb418b16023..95e3464068db540c1d2a3f530960586ee2d0cfe0 100644 (file)
@@ -901,12 +901,12 @@ static short ibmlana_adapter_ids[] __initdata = {
        0x0000
 };
 
-static char *ibmlana_adapter_names[] __initdata = {
+static char *ibmlana_adapter_names[] __devinitdata = {
        "IBM LAN Adapter/A",
        NULL
 };
 
-static int ibmlana_init_one(struct device *kdev)
+static int __devinit ibmlana_init_one(struct device *kdev)
 {
        struct mca_device *mdev = to_mca_device(kdev);
        struct net_device *dev;
index f3c144d5d72fb5606d3c621ef3bc1b6c22660900..d4eb8e2d87202b681cff99ff6cd8ec1eec1f3664 100644 (file)
@@ -438,7 +438,6 @@ static int igb_request_irq(struct igb_adapter *adapter)
        if (adapter->msix_entries) {
                err = igb_request_msix(adapter);
                if (!err) {
-                       struct e1000_hw *hw = &adapter->hw;
                        /* enable IAM, auto-mask,
                         * DO NOT USE EIAME or IAME in legacy mode */
                        wr32(E1000_IAM, IMS_ENABLE_MASK);
index e489c6661ee8b6372dd63860cdf039f0c7389c9e..07876578887fb66661cdbcfb925aa2ba29619c28 100644 (file)
@@ -173,13 +173,13 @@ struct st_fifo {
 
 struct frame_cb {
        void *start; /* Start of frame in DMA mem */
-       int len;     /* Lenght of frame in DMA mem */
+       int len;     /* Length of frame in DMA mem */
 };
 
 struct tx_fifo {
        struct frame_cb queue[MAX_TX_WINDOW]; /* Info about frames in queue */
        int             ptr;                  /* Currently being sent */
-       int             len;                  /* Lenght of queue */
+       int             len;                  /* Length of queue */
        int             free;                 /* Next free slot */
        void           *tail;                 /* Next free start in DMA mem */
 };
index bbdc97ff83cae11df92933f9cb7cb4b55cef2f5e..29398a4f73fd2cd004005846076f4bef1137470d 100644 (file)
@@ -231,13 +231,13 @@ struct st_fifo {
 
 struct frame_cb {
        void *start; /* Start of frame in DMA mem */
-       int len;     /* Lenght of frame in DMA mem */
+       int len;     /* Length of frame in DMA mem */
 };
 
 struct tx_fifo {
        struct frame_cb queue[MAX_TX_WINDOW]; /* Info about frames in queue */
        int             ptr;                  /* Currently being sent */
-       int             len;                  /* Lenght of queue */
+       int             len;                  /* Length of queue */
        int             free;                 /* Next free slot */
        void           *tail;                 /* Next free start in DMA mem */
 };
index 204b1b34ffc7a69a7b7908049529018e7a93026b..9d012f0dbd3089594d7d38cd1845886d06373d83 100644 (file)
@@ -54,13 +54,13 @@ struct st_fifo {
 
 struct frame_cb {
        void *start;            /* Start of frame in DMA mem */
-       int len;                /* Lenght of frame in DMA mem */
+       int len;                /* Length of frame in DMA mem */
 };
 
 struct tx_fifo {
        struct frame_cb queue[MAX_TX_WINDOW + 2];       /* Info about frames in queue */
        int ptr;                /* Currently being sent */
-       int len;                /* Lenght of queue */
+       int len;                /* Length of queue */
        int free;               /* Next free slot */
        void *tail;             /* Next free start in DMA mem */
 };
index c429a5002dd6c3116b343d2ab7e1100314a70d87..0c5447dac03b4a483c8294fe2cfb3b23fab7f1e4 100644 (file)
@@ -148,7 +148,7 @@ static void __NS8390_init(struct net_device *dev, int startp);
  *
  *     "The author (me) didn't use spin_lock_irqsave because the slowness of the
  *     card means that approach caused horrible problems like losing serial data
- *     at 38400 baud on some chips. Rememeber many 8390 nics on PCI were ISA
+ *     at 38400 baud on some chips. Remember many 8390 nics on PCI were ISA
  *     chips with FPGA front ends.
  *     
  *     Ok the logic behind the 8390 is very simple:
index e10528ed90814b626751d5488e5bb26233bed360..81bf005ff280dd4b556c0c599a9670bc473c47bd 100644 (file)
@@ -1084,7 +1084,7 @@ static int macb_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
        return phy_mii_ioctl(phydev, if_mii(rq), cmd);
 }
 
-static int __devinit macb_probe(struct platform_device *pdev)
+static int __init macb_probe(struct platform_device *pdev)
 {
        struct eth_platform_data *pdata;
        struct resource *regs;
@@ -1248,7 +1248,7 @@ err_out:
        return err;
 }
 
-static int __devexit macb_remove(struct platform_device *pdev)
+static int __exit macb_remove(struct platform_device *pdev)
 {
        struct net_device *dev;
        struct macb *bp;
@@ -1276,8 +1276,7 @@ static int __devexit macb_remove(struct platform_device *pdev)
 }
 
 static struct platform_driver macb_driver = {
-       .probe          = macb_probe,
-       .remove         = __devexit_p(macb_remove),
+       .remove         = __exit_p(macb_remove),
        .driver         = {
                .name           = "macb",
        },
@@ -1285,7 +1284,7 @@ static struct platform_driver macb_driver = {
 
 static int __init macb_init(void)
 {
-       return platform_driver_register(&macb_driver);
+       return platform_driver_probe(&macb_driver, macb_probe);
 }
 
 static void __exit macb_exit(void)
index 6ef6b8b39e71dd5001d1f87c5bc3753ba045b790..f651a816b280bfcb04d1d6fdda8d12e2819b4ce5 100644 (file)
@@ -508,7 +508,7 @@ static int __init macvlan_init_module(void)
                goto err1;
        return 0;
 err1:
-       macvlan_handle_frame_hook = macvlan_handle_frame;
+       macvlan_handle_frame_hook = NULL;
        unregister_netdevice_notifier(&macvlan_notifier_block);
        return err;
 }
index aafc3ce59cbbd78206ee3121477aa16723bbeb82..6d343efb2717311c1049d4962e7ae9a1ca042653 100644 (file)
@@ -4,8 +4,6 @@
  * for more details.
  */
 
-#define DEBUG
-
 #include <linux/init.h>
 #include <linux/io.h>
 #include <linux/kernel.h>
 #include <linux/platform_device.h>
 #include <asm/mips-boards/simint.h>
 
-#include "mipsnet.h"           /* actual device IO mapping */
+#define MIPSNET_VERSION "2007-11-17"
+
+/*
+ * Net status/control block as seen by sw in the core.
+ */
+struct mipsnet_regs {
+       /*
+        * Device info for probing, reads as MIPSNET%d where %d is some
+        * form of version.
+        */
+       u64 devId;              /*0x00 */
 
-#define MIPSNET_VERSION "2005-06-20"
+       /*
+        * read only busy flag.
+        * Set and cleared by the Net Device to indicate that an rx or a tx
+        * is in progress.
+        */
+       u32 busy;               /*0x08 */
 
-#define mipsnet_reg_address(dev, field) (dev->base_addr + field_offset(field))
+       /*
+        * Set by the Net Device.
+        * The device will set it once data has been received.
+        * The value is the number of bytes that should be read from
+        * rxDataBuffer.  The value will decrease till 0 until all the data
+        * from rxDataBuffer has been read.
+        */
+       u32 rxDataCount;        /*0x0c */
+#define MIPSNET_MAX_RXTX_DATACOUNT (1 << 16)
+
+       /*
+        * Settable from the MIPS core, cleared by the Net Device.
+        * The core should set the number of bytes it wants to send,
+        * then it should write those bytes of data to txDataBuffer.
+        * The device will clear txDataCount has been processed (not
+        * necessarily sent).
+        */
+       u32 txDataCount;        /*0x10 */
+
+       /*
+        * Interrupt control
+        *
+        * Used to clear the interrupted generated by this dev.
+        * Write a 1 to clear the interrupt. (except bit31).
+        *
+        * Bit0 is set if it was a tx-done interrupt.
+        * Bit1 is set when new rx-data is available.
+        *    Until this bit is cleared there will be no other RXs.
+        *
+        * Bit31 is used for testing, it clears after a read.
+        *    Writing 1 to this bit will cause an interrupt to be generated.
+        *    To clear the test interrupt, write 0 to this register.
+        */
+       u32 interruptControl;   /*0x14 */
+#define MIPSNET_INTCTL_TXDONE     (1u << 0)
+#define MIPSNET_INTCTL_RXDONE     (1u << 1)
+#define MIPSNET_INTCTL_TESTBIT    (1u << 31)
+
+       /*
+        * Readonly core-specific interrupt info for the device to signal
+        * the core. The meaning of the contents of this field might change.
+        */
+       /* XXX: the whole memIntf interrupt scheme is messy: the device
+        * should have no control what so ever of what VPE/register set is
+        * being used.
+        * The MemIntf should only expose interrupt lines, and something in
+        * the config should be responsible for the line<->core/vpe bindings.
+        */
+       u32 interruptInfo;      /*0x18 */
+
+       /*
+        * This is where the received data is read out.
+        * There is more data to read until rxDataReady is 0.
+        * Only 1 byte at this regs offset is used.
+        */
+       u32 rxDataBuffer;       /*0x1c */
+
+       /*
+        * This is where the data to transmit is written.
+        * Data should be written for the amount specified in the
+        * txDataCount register.
+        * Only 1 byte at this regs offset is used.
+        */
+       u32 txDataBuffer;       /*0x20 */
+};
+
+#define regaddr(dev, field) \
+  (dev->base_addr + offsetof(struct mipsnet_regs, field))
 
 static char mipsnet_string[] = "mipsnet";
 
@@ -29,32 +109,27 @@ static char mipsnet_string[] = "mipsnet";
 static int ioiocpy_frommipsnet(struct net_device *dev, unsigned char *kdata,
                        int len)
 {
-       uint32_t available_len = inl(mipsnet_reg_address(dev, rxDataCount));
-
-       if (available_len < len)
-               return -EFAULT;
-
        for (; len > 0; len--, kdata++)
-               *kdata = inb(mipsnet_reg_address(dev, rxDataBuffer));
+               *kdata = inb(regaddr(dev, rxDataBuffer));
 
-       return inl(mipsnet_reg_address(dev, rxDataCount));
+       return inl(regaddr(dev, rxDataCount));
 }
 
-static inline ssize_t mipsnet_put_todevice(struct net_device *dev,
+static inline void mipsnet_put_todevice(struct net_device *dev,
        struct sk_buff *skb)
 {
        int count_to_go = skb->len;
        char *buf_ptr = skb->data;
 
-       outl(skb->len, mipsnet_reg_address(dev, txDataCount));
+       outl(skb->len, regaddr(dev, txDataCount));
 
        for (; count_to_go; buf_ptr++, count_to_go--)
-               outb(*buf_ptr, mipsnet_reg_address(dev, txDataBuffer));
+               outb(*buf_ptr, regaddr(dev, txDataBuffer));
 
        dev->stats.tx_packets++;
        dev->stats.tx_bytes += skb->len;
 
-       return skb->len;
+       dev_kfree_skb(skb);
 }
 
 static int mipsnet_xmit(struct sk_buff *skb, struct net_device *dev)
@@ -69,18 +144,20 @@ static int mipsnet_xmit(struct sk_buff *skb, struct net_device *dev)
        return 0;
 }
 
-static inline ssize_t mipsnet_get_fromdev(struct net_device *dev, size_t count)
+static inline ssize_t mipsnet_get_fromdev(struct net_device *dev, size_t len)
 {
        struct sk_buff *skb;
-       size_t len = count;
 
-       skb = alloc_skb(len + 2, GFP_KERNEL);
+       if (!len)
+               return len;
+
+       skb = dev_alloc_skb(len + NET_IP_ALIGN);
        if (!skb) {
                dev->stats.rx_dropped++;
                return -ENOMEM;
        }
 
-       skb_reserve(skb, 2);
+       skb_reserve(skb, NET_IP_ALIGN);
        if (ioiocpy_frommipsnet(dev, skb_put(skb, len), len))
                return -EFAULT;
 
@@ -92,50 +169,42 @@ static inline ssize_t mipsnet_get_fromdev(struct net_device *dev, size_t count)
        dev->stats.rx_packets++;
        dev->stats.rx_bytes += len;
 
-       return count;
+       return len;
 }
 
 static irqreturn_t mipsnet_interrupt(int irq, void *dev_id)
 {
        struct net_device *dev = dev_id;
-
-       irqreturn_t retval = IRQ_NONE;
-       uint64_t interruptFlags;
-
-       if (irq == dev->irq) {
-               retval = IRQ_HANDLED;
-
-               interruptFlags =
-                   inl(mipsnet_reg_address(dev, interruptControl));
-
-               if (interruptFlags & MIPSNET_INTCTL_TXDONE) {
-                       outl(MIPSNET_INTCTL_TXDONE,
-                            mipsnet_reg_address(dev, interruptControl));
-                       /* only one packet at a time, we are done. */
-                       netif_wake_queue(dev);
-               } else if (interruptFlags & MIPSNET_INTCTL_RXDONE) {
-                       mipsnet_get_fromdev(dev,
-                                   inl(mipsnet_reg_address(dev, rxDataCount)));
-                       outl(MIPSNET_INTCTL_RXDONE,
-                            mipsnet_reg_address(dev, interruptControl));
-
-               } else if (interruptFlags & MIPSNET_INTCTL_TESTBIT) {
-                       /*
-                        * TESTBIT is cleared on read.
-                        * And takes effect after a write with 0
-                        */
-                       outl(0, mipsnet_reg_address(dev, interruptControl));
-               } else {
-                       /* Maybe shared IRQ, just ignore, no clearing. */
-                       retval = IRQ_NONE;
-               }
-
-       } else {
-               printk(KERN_INFO "%s: %s(): irq %d for unknown device\n",
-                      dev->name, __FUNCTION__, irq);
-               retval = IRQ_NONE;
+       u32 int_flags;
+       irqreturn_t ret = IRQ_NONE;
+
+       if (irq != dev->irq)
+               goto out_badirq;
+
+       /* TESTBIT is cleared on read. */
+       int_flags = inl(regaddr(dev, interruptControl));
+       if (int_flags & MIPSNET_INTCTL_TESTBIT) {
+               /* TESTBIT takes effect after a write with 0. */
+               outl(0, regaddr(dev, interruptControl));
+               ret = IRQ_HANDLED;
+       } else if (int_flags & MIPSNET_INTCTL_TXDONE) {
+               /* Only one packet at a time, we are done. */
+               dev->stats.tx_packets++;
+               netif_wake_queue(dev);
+               outl(MIPSNET_INTCTL_TXDONE,
+                    regaddr(dev, interruptControl));
+               ret = IRQ_HANDLED;
+       } else if (int_flags & MIPSNET_INTCTL_RXDONE) {
+               mipsnet_get_fromdev(dev, inl(regaddr(dev, rxDataCount)));
+               outl(MIPSNET_INTCTL_RXDONE, regaddr(dev, interruptControl));
+               ret = IRQ_HANDLED;
        }
-       return retval;
+       return ret;
+
+out_badirq:
+       printk(KERN_INFO "%s: %s(): irq %d for unknown device\n",
+              dev->name, __FUNCTION__, irq);
+       return ret;
 }
 
 static int mipsnet_open(struct net_device *dev)
@@ -144,18 +213,15 @@ static int mipsnet_open(struct net_device *dev)
 
        err = request_irq(dev->irq, &mipsnet_interrupt,
                          IRQF_SHARED, dev->name, (void *) dev);
-
        if (err) {
-               release_region(dev->base_addr, MIPSNET_IO_EXTENT);
+               release_region(dev->base_addr, sizeof(struct mipsnet_regs));
                return err;
        }
 
        netif_start_queue(dev);
 
        /* test interrupt handler */
-       outl(MIPSNET_INTCTL_TESTBIT,
-            mipsnet_reg_address(dev, interruptControl));
-
+       outl(MIPSNET_INTCTL_TESTBIT, regaddr(dev, interruptControl));
 
        return 0;
 }
@@ -163,7 +229,7 @@ static int mipsnet_open(struct net_device *dev)
 static int mipsnet_close(struct net_device *dev)
 {
        netif_stop_queue(dev);
-
+       free_irq(dev->irq, dev);
        return 0;
 }
 
@@ -194,10 +260,11 @@ static int __init mipsnet_probe(struct device *dev)
         */
        netdev->base_addr = 0x4200;
        netdev->irq = MIPS_CPU_IRQ_BASE + MIPSCPU_INT_MB0 +
-                     inl(mipsnet_reg_address(netdev, interruptInfo));
+                     inl(regaddr(netdev, interruptInfo));
 
        /* Get the io region now, get irq on open() */
-       if (!request_region(netdev->base_addr, MIPSNET_IO_EXTENT, "mipsnet")) {
+       if (!request_region(netdev->base_addr, sizeof(struct mipsnet_regs),
+                           "mipsnet")) {
                err = -EBUSY;
                goto out_free_netdev;
        }
@@ -217,7 +284,7 @@ static int __init mipsnet_probe(struct device *dev)
        return 0;
 
 out_free_region:
-       release_region(netdev->base_addr, MIPSNET_IO_EXTENT);
+       release_region(netdev->base_addr, sizeof(struct mipsnet_regs));
 
 out_free_netdev:
        free_netdev(netdev);
@@ -231,7 +298,7 @@ static int __devexit mipsnet_device_remove(struct device *device)
        struct net_device *dev = dev_get_drvdata(device);
 
        unregister_netdev(dev);
-       release_region(dev->base_addr, MIPSNET_IO_EXTENT);
+       release_region(dev->base_addr, sizeof(struct mipsnet_regs));
        free_netdev(dev);
        dev_set_drvdata(device, NULL);
 
diff --git a/drivers/net/mipsnet.h b/drivers/net/mipsnet.h
deleted file mode 100644 (file)
index 0132c67..0000000
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * 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 __MIPSNET_H
-#define __MIPSNET_H
-
-/*
- *  Id of this Net device, as seen by the core.
- */
-#define MIPS_NET_DEV_ID ((uint64_t)       \
-                            ((uint64_t) 'M' <<  0)| \
-                            ((uint64_t) 'I' <<  8)| \
-                            ((uint64_t) 'P' << 16)| \
-                            ((uint64_t) 'S' << 24)| \
-                            ((uint64_t) 'N' << 32)| \
-                            ((uint64_t) 'E' << 40)| \
-                            ((uint64_t) 'T' << 48)| \
-                            ((uint64_t) '0' << 56))
-
-/*
- * Net status/control block as seen by sw in the core.
- * (Why not use bit fields? can't be bothered with cross-platform struct
- *  packing.)
- */
-struct net_control_block {
-       /*
-        * dev info for probing
-        * reads as MIPSNET%d where %d is some form of version
-        */
-       uint64_t devId;         /* 0x00 */
-
-       /*
-        * read only busy flag.
-        * Set and cleared by the Net Device to indicate that an rx or a tx
-        * is in progress.
-        */
-       uint32_t busy;          /* 0x08 */
-
-       /*
-        * Set by the Net Device.
-        * The device will set it once data has been received.
-        * The value is the number of bytes that should be read from
-        * rxDataBuffer.  The value will decrease till 0 until all the data
-        * from rxDataBuffer has been read.
-        */
-       uint32_t rxDataCount;   /* 0x0c */
-#define MIPSNET_MAX_RXTX_DATACOUNT (1<<16)
-
-       /*
-        * Settable from the MIPS core, cleared by the Net Device.  The core
-        * should set the number of bytes it wants to send, then it should
-        * write those bytes of data to txDataBuffer.  The device will clear
-        * txDataCount has been processed (not necessarily sent).
-        */
-       uint32_t txDataCount;   /* 0x10 */
-
-       /*
-        * Interrupt control
-        *
-        * Used to clear the interrupted generated by this dev.
-        * Write a 1 to clear the interrupt. (except bit31).
-        *
-        * Bit0 is set if it was a tx-done interrupt.
-        * Bit1 is set when new rx-data is available.
-        *      Until this bit is cleared there will be no other RXs.
-        *
-        * Bit31 is used for testing, it clears after a read.
-        *    Writing 1 to this bit will cause an interrupt to be generated.
-        *    To clear the test interrupt, write 0 to this register.
-        */
-       uint32_t interruptControl;      /*0x14 */
-#define MIPSNET_INTCTL_TXDONE     ((uint32_t)(1 <<  0))
-#define MIPSNET_INTCTL_RXDONE     ((uint32_t)(1 <<  1))
-#define MIPSNET_INTCTL_TESTBIT    ((uint32_t)(1 << 31))
-#define MIPSNET_INTCTL_ALLSOURCES      (MIPSNET_INTCTL_TXDONE | \
-                                        MIPSNET_INTCTL_RXDONE | \
-                                        MIPSNET_INTCTL_TESTBIT)
-
-       /*
-        * Readonly core-specific interrupt info for the device to signal the
-        * core.  The meaning of the contents of this field might change.
-        *
-        * TODO: the whole memIntf interrupt scheme is messy: the device should
-        *       have no control what so ever of what VPE/register set is being
-        *       used.  The MemIntf should only expose interrupt lines, and
-        *       something in the config should be responsible for the
-        *       line<->core/vpe bindings.
-        */
-       uint32_t interruptInfo; /* 0x18 */
-
-       /*
-        *  This is where the received data is read out.
-        *  There is more data to read until rxDataReady is 0.
-        *  Only 1 byte at this regs offset is used.
-        */
-       uint32_t rxDataBuffer;  /* 0x1c */
-
-       /*
-        * This is where the data to transmit is written.  Data should be
-        * written for the amount specified in the txDataCount register.  Only
-        * 1 byte at this regs offset is used.
-        */
-       uint32_t txDataBuffer;  /* 0x20 */
-};
-
-#define MIPSNET_IO_EXTENT 0x40 /* being generous */
-
-#define field_offset(field) (offsetof(struct net_control_block, field))
-
-#endif /* __MIPSNET_H */
index 535a4461d88c6d720758e15d7fd21a67676a0fd9..61dc4951d6b0a61b2e1af9e535d0c14384c79e8e 100644 (file)
@@ -617,9 +617,6 @@ int mlx4_QUERY_ADAPTER(struct mlx4_dev *dev, struct mlx4_adapter *adapter)
        int err;
 
 #define QUERY_ADAPTER_OUT_SIZE             0x100
-#define QUERY_ADAPTER_VENDOR_ID_OFFSET     0x00
-#define QUERY_ADAPTER_DEVICE_ID_OFFSET     0x04
-#define QUERY_ADAPTER_REVISION_ID_OFFSET   0x08
 #define QUERY_ADAPTER_INTA_PIN_OFFSET      0x10
 #define QUERY_ADAPTER_VSD_OFFSET           0x20
 
@@ -633,9 +630,6 @@ int mlx4_QUERY_ADAPTER(struct mlx4_dev *dev, struct mlx4_adapter *adapter)
        if (err)
                goto out;
 
-       MLX4_GET(adapter->vendor_id, outbox,   QUERY_ADAPTER_VENDOR_ID_OFFSET);
-       MLX4_GET(adapter->device_id, outbox,   QUERY_ADAPTER_DEVICE_ID_OFFSET);
-       MLX4_GET(adapter->revision_id, outbox, QUERY_ADAPTER_REVISION_ID_OFFSET);
        MLX4_GET(adapter->inta_pin, outbox,    QUERY_ADAPTER_INTA_PIN_OFFSET);
 
        get_board_id(outbox + QUERY_ADAPTER_VSD_OFFSET / 4,
index 7e1dd9e25cfbabb9fa995d51c2c1fbf149518de6..e16dec890413dddbfcce48e7b79686f068703c8c 100644 (file)
@@ -99,9 +99,6 @@ struct mlx4_dev_cap {
 };
 
 struct mlx4_adapter {
-       u32  vendor_id;
-       u32  device_id;
-       u32  revision_id;
        char board_id[MLX4_BOARD_ID_LEN];
        u8   inta_pin;
 };
index 89b3f0b7cdc0f81a42a79eb2ecca2df0092e78ea..08bfc130a33eb7d63dac009d338e4464a34b4499 100644 (file)
@@ -71,7 +71,7 @@ MODULE_PARM_DESC(msi_x, "attempt to use MSI-X if nonzero");
 
 #endif /* CONFIG_PCI_MSI */
 
-static const char mlx4_version[] __devinitdata =
+static char mlx4_version[] __devinitdata =
        DRV_NAME ": Mellanox ConnectX core driver v"
        DRV_VERSION " (" DRV_RELDATE ")\n";
 
@@ -163,7 +163,7 @@ static int mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
        return 0;
 }
 
-static int __devinit mlx4_load_fw(struct mlx4_dev *dev)
+static int mlx4_load_fw(struct mlx4_dev *dev)
 {
        struct mlx4_priv *priv = mlx4_priv(dev);
        int err;
@@ -197,8 +197,8 @@ err_free:
        return err;
 }
 
-static int __devinit mlx4_init_cmpt_table(struct mlx4_dev *dev, u64 cmpt_base,
-                                         int cmpt_entry_sz)
+static int mlx4_init_cmpt_table(struct mlx4_dev *dev, u64 cmpt_base,
+                               int cmpt_entry_sz)
 {
        struct mlx4_priv *priv = mlx4_priv(dev);
        int err;
@@ -534,7 +534,6 @@ static int mlx4_init_hca(struct mlx4_dev *dev)
        }
 
        priv->eq_table.inta_pin = adapter.inta_pin;
-       dev->rev_id             = adapter.revision_id;
        memcpy(dev->board_id, adapter.board_id, sizeof dev->board_id);
 
        return 0;
@@ -688,7 +687,7 @@ err_uar_table_free:
        return err;
 }
 
-static void __devinit mlx4_enable_msi_x(struct mlx4_dev *dev)
+static void mlx4_enable_msi_x(struct mlx4_dev *dev)
 {
        struct mlx4_priv *priv = mlx4_priv(dev);
        struct msix_entry entries[MLX4_NUM_EQ];
index 0c05a10bae3bfcd290b2797b006a2b33df09ab11..9c9e308d0917d2e26161221a0a9f393db91289d3 100644 (file)
@@ -122,7 +122,7 @@ static void mlx4_buddy_free(struct mlx4_buddy *buddy, u32 seg, int order)
        spin_unlock(&buddy->lock);
 }
 
-static int __devinit mlx4_buddy_init(struct mlx4_buddy *buddy, int max_order)
+static int mlx4_buddy_init(struct mlx4_buddy *buddy, int max_order)
 {
        int i, s;
 
index c329a4f5840c7c22ee80a2882343888ea13ffbde..0a3e60418e53372beec40c8d50a1a78e086c8534 100644 (file)
@@ -203,22 +203,8 @@ skbuff at an offset of "+2", 16-byte aligning the IP header.
 IIId. Synchronization
 
 Most operations are synchronized on the np->lock irq spinlock, except the
-performance critical codepaths:
-
-The rx process only runs in the interrupt handler. Access from outside
-the interrupt handler is only permitted after disable_irq().
-
-The rx process usually runs under the netif_tx_lock. If np->intr_tx_reap
-is set, then access is permitted under spin_lock_irq(&np->lock).
-
-Thus configuration functions that want to access everything must call
-       disable_irq(dev->irq);
-       netif_tx_lock_bh(dev);
-       spin_lock_irq(&np->lock);
-
-IV. Notes
-
-NatSemi PCI network controllers are very uncommon.
+recieve and transmit paths which are synchronised using a combination of
+hardware descriptor ownership, disabling interrupts and NAPI poll scheduling.
 
 IVb. References
 
index bb88a41b759103e5601b22a4831f81f225513245..2e39e0285d8f9d2a6a9712ce33249749ede49377 100644 (file)
 
 #define LRO_MAX_AGGR 64
 
+#define PE_MIN_MTU     64
+#define PE_MAX_MTU     1500
+#define PE_DEF_MTU     ETH_DATA_LEN
+
 #define DEFAULT_MSG_ENABLE       \
        (NETIF_MSG_DRV          | \
         NETIF_MSG_PROBE        | \
@@ -82,8 +86,6 @@
                                 & ((ring)->size - 1))
 #define RING_AVAIL(ring)       ((ring->size) - RING_USED(ring))
 
-#define BUF_SIZE 1646 /* 1500 MTU + ETH_HLEN + VLAN_HLEN + 2 64B cachelines */
-
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR ("Olof Johansson <olof@lixom.net>");
 MODULE_DESCRIPTION("PA Semi PWRficient Ethernet driver");
@@ -175,6 +177,24 @@ static int mac_to_intf(struct pasemi_mac *mac)
        return -1;
 }
 
+static void pasemi_mac_intf_disable(struct pasemi_mac *mac)
+{
+       unsigned int flags;
+
+       flags = read_mac_reg(mac, PAS_MAC_CFG_PCFG);
+       flags &= ~PAS_MAC_CFG_PCFG_PE;
+       write_mac_reg(mac, PAS_MAC_CFG_PCFG, flags);
+}
+
+static void pasemi_mac_intf_enable(struct pasemi_mac *mac)
+{
+       unsigned int flags;
+
+       flags = read_mac_reg(mac, PAS_MAC_CFG_PCFG);
+       flags |= PAS_MAC_CFG_PCFG_PE;
+       write_mac_reg(mac, PAS_MAC_CFG_PCFG, flags);
+}
+
 static int pasemi_get_mac_addr(struct pasemi_mac *mac)
 {
        struct pci_dev *pdev = mac->pdev;
@@ -221,6 +241,33 @@ static int pasemi_get_mac_addr(struct pasemi_mac *mac)
        return 0;
 }
 
+static int pasemi_mac_set_mac_addr(struct net_device *dev, void *p)
+{
+       struct pasemi_mac *mac = netdev_priv(dev);
+       struct sockaddr *addr = p;
+       unsigned int adr0, adr1;
+
+       if (!is_valid_ether_addr(addr->sa_data))
+               return -EINVAL;
+
+       memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+
+       adr0 = dev->dev_addr[2] << 24 |
+              dev->dev_addr[3] << 16 |
+              dev->dev_addr[4] << 8 |
+              dev->dev_addr[5];
+       adr1 = read_mac_reg(mac, PAS_MAC_CFG_ADR1);
+       adr1 &= ~0xffff;
+       adr1 |= dev->dev_addr[0] << 8 | dev->dev_addr[1];
+
+       pasemi_mac_intf_disable(mac);
+       write_mac_reg(mac, PAS_MAC_CFG_ADR0, adr0);
+       write_mac_reg(mac, PAS_MAC_CFG_ADR1, adr1);
+       pasemi_mac_intf_enable(mac);
+
+       return 0;
+}
+
 static int get_skb_hdr(struct sk_buff *skb, void **iphdr,
                       void **tcph, u64 *hdr_flags, void *data)
 {
@@ -453,7 +500,7 @@ static void pasemi_mac_free_tx_resources(struct pasemi_mac *mac)
 
 }
 
-static void pasemi_mac_free_rx_resources(struct pasemi_mac *mac)
+static void pasemi_mac_free_rx_buffers(struct pasemi_mac *mac)
 {
        struct pasemi_mac_rxring *rx = rx_ring(mac);
        unsigned int i;
@@ -473,7 +520,12 @@ static void pasemi_mac_free_rx_resources(struct pasemi_mac *mac)
        }
 
        for (i = 0; i < RX_RING_SIZE; i++)
-               RX_DESC(rx, i) = 0;
+               RX_BUFF(rx, i) = 0;
+}
+
+static void pasemi_mac_free_rx_resources(struct pasemi_mac *mac)
+{
+       pasemi_mac_free_rx_buffers(mac);
 
        dma_free_coherent(&mac->dma_pdev->dev, RX_RING_SIZE * sizeof(u64),
                          rx_ring(mac)->buffers, rx_ring(mac)->buf_dma);
@@ -503,14 +555,14 @@ static void pasemi_mac_replenish_rx_ring(const struct net_device *dev,
                /* Entry in use? */
                WARN_ON(*buff);
 
-               skb = dev_alloc_skb(BUF_SIZE);
+               skb = dev_alloc_skb(mac->bufsz);
                skb_reserve(skb, LOCAL_SKB_ALIGN);
 
                if (unlikely(!skb))
                        break;
 
                dma = pci_map_single(mac->dma_pdev, skb->data,
-                                    BUF_SIZE - LOCAL_SKB_ALIGN,
+                                    mac->bufsz - LOCAL_SKB_ALIGN,
                                     PCI_DMA_FROMDEVICE);
 
                if (unlikely(dma_mapping_error(dma))) {
@@ -520,7 +572,7 @@ static void pasemi_mac_replenish_rx_ring(const struct net_device *dev,
 
                info->skb = skb;
                info->dma = dma;
-               *buff = XCT_RXB_LEN(BUF_SIZE) | XCT_RXB_ADDR(dma);
+               *buff = XCT_RXB_LEN(mac->bufsz) | XCT_RXB_ADDR(dma);
                fill++;
        }
 
@@ -650,7 +702,7 @@ static int pasemi_mac_clean_rx(struct pasemi_mac_rxring *rx,
 
                len = (macrx & XCT_MACRX_LLEN_M) >> XCT_MACRX_LLEN_S;
 
-               pci_unmap_single(pdev, dma, BUF_SIZE-LOCAL_SKB_ALIGN,
+               pci_unmap_single(pdev, dma, mac->bufsz - LOCAL_SKB_ALIGN,
                                 PCI_DMA_FROMDEVICE);
 
                if (macrx & XCT_MACRX_CRC) {
@@ -874,24 +926,6 @@ static irqreturn_t pasemi_mac_tx_intr(int irq, void *data)
        return IRQ_HANDLED;
 }
 
-static void pasemi_mac_intf_disable(struct pasemi_mac *mac)
-{
-       unsigned int flags;
-
-       flags = read_mac_reg(mac, PAS_MAC_CFG_PCFG);
-       flags &= ~PAS_MAC_CFG_PCFG_PE;
-       write_mac_reg(mac, PAS_MAC_CFG_PCFG, flags);
-}
-
-static void pasemi_mac_intf_enable(struct pasemi_mac *mac)
-{
-       unsigned int flags;
-
-       flags = read_mac_reg(mac, PAS_MAC_CFG_PCFG);
-       flags |= PAS_MAC_CFG_PCFG_PE;
-       write_mac_reg(mac, PAS_MAC_CFG_PCFG, flags);
-}
-
 static void pasemi_adjust_link(struct net_device *dev)
 {
        struct pasemi_mac *mac = netdev_priv(dev);
@@ -1148,11 +1182,71 @@ out_rx_resources:
 
 #define MAX_RETRIES 5000
 
+static void pasemi_mac_pause_txchan(struct pasemi_mac *mac)
+{
+       unsigned int sta, retries;
+       int txch = tx_ring(mac)->chan.chno;
+
+       write_dma_reg(PAS_DMA_TXCHAN_TCMDSTA(txch),
+                     PAS_DMA_TXCHAN_TCMDSTA_ST);
+
+       for (retries = 0; retries < MAX_RETRIES; retries++) {
+               sta = read_dma_reg(PAS_DMA_TXCHAN_TCMDSTA(txch));
+               if (!(sta & PAS_DMA_TXCHAN_TCMDSTA_ACT))
+                       break;
+               cond_resched();
+       }
+
+       if (sta & PAS_DMA_TXCHAN_TCMDSTA_ACT)
+               dev_err(&mac->dma_pdev->dev,
+                       "Failed to stop tx channel, tcmdsta %08x\n", sta);
+
+       write_dma_reg(PAS_DMA_TXCHAN_TCMDSTA(txch), 0);
+}
+
+static void pasemi_mac_pause_rxchan(struct pasemi_mac *mac)
+{
+       unsigned int sta, retries;
+       int rxch = rx_ring(mac)->chan.chno;
+
+       write_dma_reg(PAS_DMA_RXCHAN_CCMDSTA(rxch),
+                     PAS_DMA_RXCHAN_CCMDSTA_ST);
+       for (retries = 0; retries < MAX_RETRIES; retries++) {
+               sta = read_dma_reg(PAS_DMA_RXCHAN_CCMDSTA(rxch));
+               if (!(sta & PAS_DMA_RXCHAN_CCMDSTA_ACT))
+                       break;
+               cond_resched();
+       }
+
+       if (sta & PAS_DMA_RXCHAN_CCMDSTA_ACT)
+               dev_err(&mac->dma_pdev->dev,
+                       "Failed to stop rx channel, ccmdsta 08%x\n", sta);
+       write_dma_reg(PAS_DMA_RXCHAN_CCMDSTA(rxch), 0);
+}
+
+static void pasemi_mac_pause_rxint(struct pasemi_mac *mac)
+{
+       unsigned int sta, retries;
+
+       write_dma_reg(PAS_DMA_RXINT_RCMDSTA(mac->dma_if),
+                     PAS_DMA_RXINT_RCMDSTA_ST);
+       for (retries = 0; retries < MAX_RETRIES; retries++) {
+               sta = read_dma_reg(PAS_DMA_RXINT_RCMDSTA(mac->dma_if));
+               if (!(sta & PAS_DMA_RXINT_RCMDSTA_ACT))
+                       break;
+               cond_resched();
+       }
+
+       if (sta & PAS_DMA_RXINT_RCMDSTA_ACT)
+               dev_err(&mac->dma_pdev->dev,
+                       "Failed to stop rx interface, rcmdsta %08x\n", sta);
+       write_dma_reg(PAS_DMA_RXINT_RCMDSTA(mac->dma_if), 0);
+}
+
 static int pasemi_mac_close(struct net_device *dev)
 {
        struct pasemi_mac *mac = netdev_priv(dev);
        unsigned int sta;
-       int retries;
        int rxch, txch;
 
        rxch = rx_ring(mac)->chan.chno;
@@ -1190,51 +1284,10 @@ static int pasemi_mac_close(struct net_device *dev)
        pasemi_mac_clean_tx(tx_ring(mac));
        pasemi_mac_clean_rx(rx_ring(mac), RX_RING_SIZE);
 
-       /* Disable interface */
-       write_dma_reg(PAS_DMA_TXCHAN_TCMDSTA(txch),
-                     PAS_DMA_TXCHAN_TCMDSTA_ST);
-       write_dma_reg( PAS_DMA_RXINT_RCMDSTA(mac->dma_if),
-                     PAS_DMA_RXINT_RCMDSTA_ST);
-       write_dma_reg(PAS_DMA_RXCHAN_CCMDSTA(rxch),
-                     PAS_DMA_RXCHAN_CCMDSTA_ST);
-
-       for (retries = 0; retries < MAX_RETRIES; retries++) {
-               sta = read_dma_reg(PAS_DMA_TXCHAN_TCMDSTA(rxch));
-               if (!(sta & PAS_DMA_TXCHAN_TCMDSTA_ACT))
-                       break;
-               cond_resched();
-       }
-
-       if (sta & PAS_DMA_TXCHAN_TCMDSTA_ACT)
-               dev_err(&mac->dma_pdev->dev, "Failed to stop tx channel\n");
-
-       for (retries = 0; retries < MAX_RETRIES; retries++) {
-               sta = read_dma_reg(PAS_DMA_RXCHAN_CCMDSTA(rxch));
-               if (!(sta & PAS_DMA_RXCHAN_CCMDSTA_ACT))
-                       break;
-               cond_resched();
-       }
-
-       if (sta & PAS_DMA_RXCHAN_CCMDSTA_ACT)
-               dev_err(&mac->dma_pdev->dev, "Failed to stop rx channel\n");
-
-       for (retries = 0; retries < MAX_RETRIES; retries++) {
-               sta = read_dma_reg(PAS_DMA_RXINT_RCMDSTA(mac->dma_if));
-               if (!(sta & PAS_DMA_RXINT_RCMDSTA_ACT))
-                       break;
-               cond_resched();
-       }
-
-       if (sta & PAS_DMA_RXINT_RCMDSTA_ACT)
-               dev_err(&mac->dma_pdev->dev, "Failed to stop rx interface\n");
-
-       /* Then, disable the channel. This must be done separately from
-        * stopping, since you can't disable when active.
-        */
-
-       write_dma_reg(PAS_DMA_TXCHAN_TCMDSTA(txch), 0);
-       write_dma_reg(PAS_DMA_RXCHAN_CCMDSTA(rxch), 0);
-       write_dma_reg(PAS_DMA_RXINT_RCMDSTA(mac->dma_if), 0);
+       pasemi_mac_pause_txchan(mac);
+       pasemi_mac_pause_rxint(mac);
+       pasemi_mac_pause_rxchan(mac);
+       pasemi_mac_intf_disable(mac);
 
        free_irq(mac->tx->chan.irq, mac->tx);
        free_irq(mac->rx->chan.irq, mac->rx);
@@ -1388,6 +1441,62 @@ static int pasemi_mac_poll(struct napi_struct *napi, int budget)
        return pkts;
 }
 
+static int pasemi_mac_change_mtu(struct net_device *dev, int new_mtu)
+{
+       struct pasemi_mac *mac = netdev_priv(dev);
+       unsigned int reg;
+       unsigned int rcmdsta;
+       int running;
+
+       if (new_mtu < PE_MIN_MTU || new_mtu > PE_MAX_MTU)
+               return -EINVAL;
+
+       running = netif_running(dev);
+
+       if (running) {
+               /* Need to stop the interface, clean out all already
+                * received buffers, free all unused buffers on the RX
+                * interface ring, then finally re-fill the rx ring with
+                * the new-size buffers and restart.
+                */
+
+               napi_disable(&mac->napi);
+               netif_tx_disable(dev);
+               pasemi_mac_intf_disable(mac);
+
+               rcmdsta = read_dma_reg(PAS_DMA_RXINT_RCMDSTA(mac->dma_if));
+               pasemi_mac_pause_rxint(mac);
+               pasemi_mac_clean_rx(rx_ring(mac), RX_RING_SIZE);
+               pasemi_mac_free_rx_buffers(mac);
+       }
+
+       /* Change maxf, i.e. what size frames are accepted.
+        * Need room for ethernet header and CRC word
+        */
+       reg = read_mac_reg(mac, PAS_MAC_CFG_MACCFG);
+       reg &= ~PAS_MAC_CFG_MACCFG_MAXF_M;
+       reg |= PAS_MAC_CFG_MACCFG_MAXF(new_mtu + ETH_HLEN + 4);
+       write_mac_reg(mac, PAS_MAC_CFG_MACCFG, reg);
+
+       dev->mtu = new_mtu;
+       /* MTU + ETH_HLEN + VLAN_HLEN + 2 64B cachelines */
+       mac->bufsz = new_mtu + ETH_HLEN + ETH_FCS_LEN + LOCAL_SKB_ALIGN + 128;
+
+       if (running) {
+               write_dma_reg(PAS_DMA_RXINT_RCMDSTA(mac->dma_if),
+                             rcmdsta | PAS_DMA_RXINT_RCMDSTA_EN);
+
+               rx_ring(mac)->next_to_fill = 0;
+               pasemi_mac_replenish_rx_ring(dev, RX_RING_SIZE-1);
+
+               napi_enable(&mac->napi);
+               netif_start_queue(dev);
+               pasemi_mac_intf_enable(mac);
+       }
+
+       return 0;
+}
+
 static int __devinit
 pasemi_mac_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
@@ -1475,6 +1584,12 @@ pasemi_mac_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        dev->stop = pasemi_mac_close;
        dev->hard_start_xmit = pasemi_mac_start_tx;
        dev->set_multicast_list = pasemi_mac_set_rx_mode;
+       dev->set_mac_address = pasemi_mac_set_mac_addr;
+       dev->mtu = PE_DEF_MTU;
+       /* 1500 MTU + ETH_HLEN + VLAN_HLEN + 2 64B cachelines */
+       mac->bufsz = dev->mtu + ETH_HLEN + ETH_FCS_LEN + LOCAL_SKB_ALIGN + 128;
+
+       dev->change_mtu = pasemi_mac_change_mtu;
 
        if (err)
                goto out;
index 8bee2a664c83760d12a897eb4230331f6e99c229..99e7b9329a6fb5366936d62f399b513a676b5897 100644 (file)
@@ -59,6 +59,7 @@ struct pasemi_mac {
        struct phy_device *phydev;
        struct napi_struct napi;
 
+       int             bufsz; /* RX ring buffer size */
        u8              type;
 #define MAC_TYPE_GMAC  1
 #define MAC_TYPE_XAUI  2
@@ -96,6 +97,9 @@ struct pasemi_mac_buffer {
 /* MAC CFG register offsets */
 enum {
        PAS_MAC_CFG_PCFG = 0x80,
+       PAS_MAC_CFG_MACCFG = 0x84,
+       PAS_MAC_CFG_ADR0 = 0x8c,
+       PAS_MAC_CFG_ADR1 = 0x90,
        PAS_MAC_CFG_TXP = 0x98,
        PAS_MAC_IPC_CHNL = 0x208,
 };
@@ -130,6 +134,18 @@ enum {
 #define PAS_MAC_CFG_PCFG_SPD_100M      0x00000001
 #define PAS_MAC_CFG_PCFG_SPD_1G                0x00000002
 #define PAS_MAC_CFG_PCFG_SPD_10G       0x00000003
+
+#define PAS_MAC_CFG_MACCFG_TXT_M       0x70000000
+#define PAS_MAC_CFG_MACCFG_TXT_S       28
+#define PAS_MAC_CFG_MACCFG_PRES_M      0x0f000000
+#define PAS_MAC_CFG_MACCFG_PRES_S      24
+#define PAS_MAC_CFG_MACCFG_MAXF_M      0x00ffff00
+#define PAS_MAC_CFG_MACCFG_MAXF_S      8
+#define PAS_MAC_CFG_MACCFG_MAXF(x)     (((x) << PAS_MAC_CFG_MACCFG_MAXF_S) & \
+                                        PAS_MAC_CFG_MACCFG_MAXF_M)
+#define PAS_MAC_CFG_MACCFG_MINF_M      0x000000ff
+#define PAS_MAC_CFG_MACCFG_MINF_S      0
+
 #define PAS_MAC_CFG_TXP_FCF            0x01000000
 #define PAS_MAC_CFG_TXP_FCE            0x00800000
 #define PAS_MAC_CFG_TXP_FC             0x00400000
index ed402e00e730e1c0c2eadfa1ac13a5cfe3cb9aa9..fffc49befe042c7b514745d688cfd5817a44a9dc 100644 (file)
@@ -541,7 +541,7 @@ static void netdrv_hw_start (struct net_device *dev);
 #define NETDRV_W32_F(reg, val32)       do { writel ((val32), ioaddr + (reg)); readl (ioaddr + (reg)); } while (0)
 
 
-#if MMIO_FLUSH_AUDIT_COMPLETE
+#ifdef MMIO_FLUSH_AUDIT_COMPLETE
 
 /* write MMIO register */
 #define NETDRV_W8(reg, val8)   writeb ((val8), ioaddr + (reg))
@@ -603,7 +603,7 @@ static int __devinit netdrv_init_board (struct pci_dev *pdev,
                return -ENOMEM;
        }
        SET_NETDEV_DEV(dev, &pdev->dev);
-       tp = dev->priv;
+       tp = netdev_priv(dev);
 
        /* enable device (incl. PCI PM wakeup), and bus-mastering */
        rc = pci_enable_device (pdev);
@@ -759,7 +759,7 @@ static int __devinit netdrv_init_one (struct pci_dev *pdev,
                return i;
        }
 
-       tp = dev->priv;
+       tp = netdev_priv(dev);
 
        assert (ioaddr != NULL);
        assert (dev != NULL);
@@ -783,7 +783,7 @@ static int __devinit netdrv_init_one (struct pci_dev *pdev,
        dev->base_addr = (unsigned long) ioaddr;
 
        /* dev->priv/tp zeroed and aligned in alloc_etherdev */
-       tp = dev->priv;
+       tp = netdev_priv(dev);
 
        /* note: tp->chipset set in netdrv_init_board */
        tp->drv_flags = PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
@@ -841,7 +841,7 @@ static void __devexit netdrv_remove_one (struct pci_dev *pdev)
 
        assert (dev != NULL);
 
-       np = dev->priv;
+       np = netdev_priv(dev);
        assert (np != NULL);
 
        unregister_netdev (dev);
@@ -974,7 +974,7 @@ static void mdio_sync (void *mdio_addr)
 
 static int mdio_read (struct net_device *dev, int phy_id, int location)
 {
-       struct netdrv_private *tp = dev->priv;
+       struct netdrv_private *tp = netdev_priv(dev);
        void *mdio_addr = tp->mmio_addr + Config4;
        int mii_cmd = (0xf6 << 10) | (phy_id << 5) | location;
        int retval = 0;
@@ -1017,7 +1017,7 @@ static int mdio_read (struct net_device *dev, int phy_id, int location)
 static void mdio_write (struct net_device *dev, int phy_id, int location,
                        int value)
 {
-       struct netdrv_private *tp = dev->priv;
+       struct netdrv_private *tp = netdev_priv(dev);
        void *mdio_addr = tp->mmio_addr + Config4;
        int mii_cmd =
            (0x5002 << 16) | (phy_id << 23) | (location << 18) | value;
@@ -1060,7 +1060,7 @@ static void mdio_write (struct net_device *dev, int phy_id, int location,
 
 static int netdrv_open (struct net_device *dev)
 {
-       struct netdrv_private *tp = dev->priv;
+       struct netdrv_private *tp = netdev_priv(dev);
        int retval;
 #ifdef NETDRV_DEBUG
        void *ioaddr = tp->mmio_addr;
@@ -1121,7 +1121,7 @@ static int netdrv_open (struct net_device *dev)
 /* Start the hardware at open or resume. */
 static void netdrv_hw_start (struct net_device *dev)
 {
-       struct netdrv_private *tp = dev->priv;
+       struct netdrv_private *tp = netdev_priv(dev);
        void *ioaddr = tp->mmio_addr;
        u32 i;
 
@@ -1191,7 +1191,7 @@ static void netdrv_hw_start (struct net_device *dev)
 /* Initialize the Rx and Tx rings, along with various 'dev' bits. */
 static void netdrv_init_ring (struct net_device *dev)
 {
-       struct netdrv_private *tp = dev->priv;
+       struct netdrv_private *tp = netdev_priv(dev);
        int i;
 
        DPRINTK ("ENTER\n");
@@ -1213,7 +1213,7 @@ static void netdrv_init_ring (struct net_device *dev)
 static void netdrv_timer (unsigned long data)
 {
        struct net_device *dev = (struct net_device *) data;
-       struct netdrv_private *tp = dev->priv;
+       struct netdrv_private *tp = netdev_priv(dev);
        void *ioaddr = tp->mmio_addr;
        int next_tick = 60 * HZ;
        int mii_lpa;
@@ -1252,9 +1252,10 @@ static void netdrv_timer (unsigned long data)
 }
 
 
-static void netdrv_tx_clear (struct netdrv_private *tp)
+static void netdrv_tx_clear (struct net_device *dev)
 {
        int i;
+       struct netdrv_private *tp = netdev_priv(dev);
 
        atomic_set (&tp->cur_tx, 0);
        atomic_set (&tp->dirty_tx, 0);
@@ -1278,7 +1279,7 @@ static void netdrv_tx_clear (struct netdrv_private *tp)
 
 static void netdrv_tx_timeout (struct net_device *dev)
 {
-       struct netdrv_private *tp = dev->priv;
+       struct netdrv_private *tp = netdev_priv(dev);
        void *ioaddr = tp->mmio_addr;
        int i;
        u8 tmp8;
@@ -1311,7 +1312,7 @@ static void netdrv_tx_timeout (struct net_device *dev)
        /* Stop a shared interrupt from scavenging while we are. */
        spin_lock_irqsave (&tp->lock, flags);
 
-       netdrv_tx_clear (tp);
+       netdrv_tx_clear (dev);
 
        spin_unlock_irqrestore (&tp->lock, flags);
 
@@ -1325,7 +1326,7 @@ static void netdrv_tx_timeout (struct net_device *dev)
 
 static int netdrv_start_xmit (struct sk_buff *skb, struct net_device *dev)
 {
-       struct netdrv_private *tp = dev->priv;
+       struct netdrv_private *tp = netdev_priv(dev);
        void *ioaddr = tp->mmio_addr;
        int entry;
 
@@ -1525,7 +1526,7 @@ static void netdrv_rx_interrupt (struct net_device *dev,
                DPRINTK ("%s:  netdrv_rx() status %4.4x, size %4.4x,"
                         " cur %4.4x.\n", dev->name, rx_status,
                         rx_size, cur_rx);
-#if NETDRV_DEBUG > 2
+#if defined(NETDRV_DEBUG) && (NETDRV_DEBUG > 2)
                {
                        int i;
                        DPRINTK ("%s: Frame contents ", dev->name);
@@ -1648,7 +1649,7 @@ static void netdrv_weird_interrupt (struct net_device *dev,
 static irqreturn_t netdrv_interrupt (int irq, void *dev_instance)
 {
        struct net_device *dev = (struct net_device *) dev_instance;
-       struct netdrv_private *tp = dev->priv;
+       struct netdrv_private *tp = netdev_priv(dev);
        int boguscnt = max_interrupt_work;
        void *ioaddr = tp->mmio_addr;
        int status = 0, link_changed = 0; /* avoid bogus "uninit" warning */
@@ -1711,7 +1712,7 @@ static irqreturn_t netdrv_interrupt (int irq, void *dev_instance)
 
 static int netdrv_close (struct net_device *dev)
 {
-       struct netdrv_private *tp = dev->priv;
+       struct netdrv_private *tp = netdev_priv(dev);
        void *ioaddr = tp->mmio_addr;
        unsigned long flags;
 
@@ -1738,10 +1739,10 @@ static int netdrv_close (struct net_device *dev)
 
        spin_unlock_irqrestore (&tp->lock, flags);
 
-       synchronize_irq ();
+       synchronize_irq (dev->irq);
        free_irq (dev->irq, dev);
 
-       netdrv_tx_clear (tp);
+       netdrv_tx_clear (dev);
 
        pci_free_consistent(tp->pci_dev, RX_BUF_TOT_LEN,
                            tp->rx_ring, tp->rx_ring_dma);
@@ -1762,7 +1763,7 @@ static int netdrv_close (struct net_device *dev)
 
 static int netdrv_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
 {
-       struct netdrv_private *tp = dev->priv;
+       struct netdrv_private *tp = netdev_priv(dev);
        struct mii_ioctl_data *data = if_mii(rq);
        unsigned long flags;
        int rc = 0;
@@ -1805,7 +1806,7 @@ static int netdrv_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
 
 static void netdrv_set_rx_mode (struct net_device *dev)
 {
-       struct netdrv_private *tp = dev->priv;
+       struct netdrv_private *tp = netdev_priv(dev);
        void *ioaddr = tp->mmio_addr;
        u32 mc_filter[2];       /* Multicast hash filter */
        int i, rx_mode;
@@ -1862,7 +1863,7 @@ static void netdrv_set_rx_mode (struct net_device *dev)
 static int netdrv_suspend (struct pci_dev *pdev, pm_message_t state)
 {
        struct net_device *dev = pci_get_drvdata (pdev);
-       struct netdrv_private *tp = dev->priv;
+       struct netdrv_private *tp = netdev_priv(dev);
        void *ioaddr = tp->mmio_addr;
        unsigned long flags;
 
@@ -1892,7 +1893,7 @@ static int netdrv_suspend (struct pci_dev *pdev, pm_message_t state)
 static int netdrv_resume (struct pci_dev *pdev)
 {
        struct net_device *dev = pci_get_drvdata (pdev);
-       struct netdrv_private *tp = dev->priv;
+       /*struct netdrv_private *tp = netdev_priv(dev);*/
 
        if (!netif_running(dev))
                return 0;
index 36a7ba3134ce7468b643138f3d57ea95334b95bc..3b78a3819bb3d2ae33cb47e1da8cbddb58739013 100644 (file)
@@ -230,10 +230,11 @@ static char mii_preamble_required = 0;
 static int tc574_config(struct pcmcia_device *link);
 static void tc574_release(struct pcmcia_device *link);
 
-static void mdio_sync(kio_addr_t ioaddr, int bits);
-static int mdio_read(kio_addr_t ioaddr, int phy_id, int location);
-static void mdio_write(kio_addr_t ioaddr, int phy_id, int location, int value);
-static unsigned short read_eeprom(kio_addr_t ioaddr, int index);
+static void mdio_sync(unsigned int ioaddr, int bits);
+static int mdio_read(unsigned int ioaddr, int phy_id, int location);
+static void mdio_write(unsigned int ioaddr, int phy_id, int location,
+                      int value);
+static unsigned short read_eeprom(unsigned int ioaddr, int index);
 static void tc574_wait_for_completion(struct net_device *dev, int cmd);
 
 static void tc574_reset(struct net_device *dev);
@@ -341,7 +342,7 @@ static int tc574_config(struct pcmcia_device *link)
        tuple_t tuple;
        __le16 buf[32];
        int last_fn, last_ret, i, j;
-       kio_addr_t ioaddr;
+       unsigned int ioaddr;
        __be16 *phys_addr;
        char *cardname;
        __u32 config;
@@ -515,7 +516,7 @@ static int tc574_resume(struct pcmcia_device *link)
 
 static void dump_status(struct net_device *dev)
 {
-       kio_addr_t ioaddr = dev->base_addr;
+       unsigned int ioaddr = dev->base_addr;
        EL3WINDOW(1);
        printk(KERN_INFO "  irq status %04x, rx status %04x, tx status "
                   "%02x, tx free %04x\n", inw(ioaddr+EL3_STATUS),
@@ -544,7 +545,7 @@ static void tc574_wait_for_completion(struct net_device *dev, int cmd)
 /* Read a word from the EEPROM using the regular EEPROM access register.
    Assume that we are in register window zero.
  */
-static unsigned short read_eeprom(kio_addr_t ioaddr, int index)
+static unsigned short read_eeprom(unsigned int ioaddr, int index)
 {
        int timer;
        outw(EEPROM_Read + index, ioaddr + Wn0EepromCmd);
@@ -572,9 +573,9 @@ static unsigned short read_eeprom(kio_addr_t ioaddr, int index)
 
 /* Generate the preamble required for initial synchronization and
    a few older transceivers. */
-static void mdio_sync(kio_addr_t ioaddr, int bits)
+static void mdio_sync(unsigned int ioaddr, int bits)
 {
-       kio_addr_t mdio_addr = ioaddr + Wn4_PhysicalMgmt;
+       unsigned int mdio_addr = ioaddr + Wn4_PhysicalMgmt;
 
        /* Establish sync by sending at least 32 logic ones. */
        while (-- bits >= 0) {
@@ -583,12 +584,12 @@ static void mdio_sync(kio_addr_t ioaddr, int bits)
        }
 }
 
-static int mdio_read(kio_addr_t ioaddr, int phy_id, int location)
+static int mdio_read(unsigned int ioaddr, int phy_id, int location)
 {
        int i;
        int read_cmd = (0xf6 << 10) | (phy_id << 5) | location;
        unsigned int retval = 0;
-       kio_addr_t mdio_addr = ioaddr + Wn4_PhysicalMgmt;
+       unsigned int mdio_addr = ioaddr + Wn4_PhysicalMgmt;
 
        if (mii_preamble_required)
                mdio_sync(ioaddr, 32);
@@ -608,10 +609,10 @@ static int mdio_read(kio_addr_t ioaddr, int phy_id, int location)
        return (retval>>1) & 0xffff;
 }
 
-static void mdio_write(kio_addr_t ioaddr, int phy_id, int location, int value)
+static void mdio_write(unsigned int ioaddr, int phy_id, int location, int value)
 {
        int write_cmd = 0x50020000 | (phy_id << 23) | (location << 18) | value;
-       kio_addr_t mdio_addr = ioaddr + Wn4_PhysicalMgmt;
+       unsigned int mdio_addr = ioaddr + Wn4_PhysicalMgmt;
        int i;
 
        if (mii_preamble_required)
@@ -637,7 +638,7 @@ static void tc574_reset(struct net_device *dev)
 {
        struct el3_private *lp = netdev_priv(dev);
        int i;
-       kio_addr_t ioaddr = dev->base_addr;
+       unsigned int ioaddr = dev->base_addr;
        unsigned long flags;
 
        tc574_wait_for_completion(dev, TotalReset|0x10);
@@ -695,7 +696,7 @@ static void tc574_reset(struct net_device *dev)
        mdio_write(ioaddr, lp->phys, 4, lp->advertising);
        if (!auto_polarity) {
                /* works for TDK 78Q2120 series MII's */
-               int i = mdio_read(ioaddr, lp->phys, 16) | 0x20;
+               i = mdio_read(ioaddr, lp->phys, 16) | 0x20;
                mdio_write(ioaddr, lp->phys, 16, i);
        }
 
@@ -741,7 +742,7 @@ static int el3_open(struct net_device *dev)
 static void el3_tx_timeout(struct net_device *dev)
 {
        struct el3_private *lp = netdev_priv(dev);
-       kio_addr_t ioaddr = dev->base_addr;
+       unsigned int ioaddr = dev->base_addr;
        
        printk(KERN_NOTICE "%s: Transmit timed out!\n", dev->name);
        dump_status(dev);
@@ -756,7 +757,7 @@ static void el3_tx_timeout(struct net_device *dev)
 static void pop_tx_status(struct net_device *dev)
 {
        struct el3_private *lp = netdev_priv(dev);
-       kio_addr_t ioaddr = dev->base_addr;
+       unsigned int ioaddr = dev->base_addr;
        int i;
     
        /* Clear the Tx status stack. */
@@ -779,7 +780,7 @@ static void pop_tx_status(struct net_device *dev)
 
 static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-       kio_addr_t ioaddr = dev->base_addr;
+       unsigned int ioaddr = dev->base_addr;
        struct el3_private *lp = netdev_priv(dev);
        unsigned long flags;
 
@@ -813,7 +814,7 @@ static irqreturn_t el3_interrupt(int irq, void *dev_id)
 {
        struct net_device *dev = (struct net_device *) dev_id;
        struct el3_private *lp = netdev_priv(dev);
-       kio_addr_t ioaddr;
+       unsigned int ioaddr;
        unsigned status;
        int work_budget = max_interrupt_work;
        int handled = 0;
@@ -907,7 +908,7 @@ static void media_check(unsigned long arg)
 {
        struct net_device *dev = (struct net_device *) arg;
        struct el3_private *lp = netdev_priv(dev);
-       kio_addr_t ioaddr = dev->base_addr;
+       unsigned int ioaddr = dev->base_addr;
        unsigned long flags;
        unsigned short /* cable, */ media, partner;
 
@@ -996,7 +997,7 @@ static struct net_device_stats *el3_get_stats(struct net_device *dev)
 static void update_stats(struct net_device *dev)
 {
        struct el3_private *lp = netdev_priv(dev);
-       kio_addr_t ioaddr = dev->base_addr;
+       unsigned int ioaddr = dev->base_addr;
        u8 rx, tx, up;
 
        DEBUG(2, "%s: updating the statistics.\n", dev->name);
@@ -1033,7 +1034,7 @@ static void update_stats(struct net_device *dev)
 static int el3_rx(struct net_device *dev, int worklimit)
 {
        struct el3_private *lp = netdev_priv(dev);
-       kio_addr_t ioaddr = dev->base_addr;
+       unsigned int ioaddr = dev->base_addr;
        short rx_status;
        
        DEBUG(3, "%s: in rx_packet(), status %4.4x, rx_status %4.4x.\n",
@@ -1094,7 +1095,7 @@ static const struct ethtool_ops netdev_ethtool_ops = {
 static int el3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
        struct el3_private *lp = netdev_priv(dev);
-       kio_addr_t ioaddr = dev->base_addr;
+       unsigned int ioaddr = dev->base_addr;
        u16 *data = (u16 *)&rq->ifr_ifru;
        int phy = lp->phys & 0x1f;
 
@@ -1148,7 +1149,7 @@ static int el3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 
 static void set_rx_mode(struct net_device *dev)
 {
-       kio_addr_t ioaddr = dev->base_addr;
+       unsigned int ioaddr = dev->base_addr;
 
        if (dev->flags & IFF_PROMISC)
                outw(SetRxFilter | RxStation | RxMulticast | RxBroadcast | RxProm,
@@ -1161,7 +1162,7 @@ static void set_rx_mode(struct net_device *dev)
 
 static int el3_close(struct net_device *dev)
 {
-       kio_addr_t ioaddr = dev->base_addr;
+       unsigned int ioaddr = dev->base_addr;
        struct el3_private *lp = netdev_priv(dev);
        struct pcmcia_device *link = lp->p_dev;
 
index e862d14ece79a6afe1069150a1e65fe3bed6acae..1b1abb19c911d1623e722a8ef18056adbfeb11a8 100644 (file)
@@ -145,7 +145,7 @@ DRV_NAME ".c " DRV_VERSION " 2001/10/13 00:08:50 (David Hinds)";
 static int tc589_config(struct pcmcia_device *link);
 static void tc589_release(struct pcmcia_device *link);
 
-static u16 read_eeprom(kio_addr_t ioaddr, int index);
+static u16 read_eeprom(unsigned int ioaddr, int index);
 static void tc589_reset(struct net_device *dev);
 static void media_check(unsigned long arg);
 static int el3_config(struct net_device *dev, struct ifmap *map);
@@ -254,7 +254,7 @@ static int tc589_config(struct pcmcia_device *link)
     __le16 buf[32];
     __be16 *phys_addr;
     int last_fn, last_ret, i, j, multi = 0, fifo;
-    kio_addr_t ioaddr;
+    unsigned int ioaddr;
     char *ram_split[] = {"5:3", "3:1", "1:1", "3:5"};
     DECLARE_MAC_BUF(mac);
     
@@ -403,7 +403,7 @@ static void tc589_wait_for_completion(struct net_device *dev, int cmd)
   Read a word from the EEPROM using the regular EEPROM access register.
   Assume that we are in register window zero.
 */
-static u16 read_eeprom(kio_addr_t ioaddr, int index)
+static u16 read_eeprom(unsigned int ioaddr, int index)
 {
     int i;
     outw(EEPROM_READ + index, ioaddr + 10);
@@ -421,7 +421,7 @@ static u16 read_eeprom(kio_addr_t ioaddr, int index)
 static void tc589_set_xcvr(struct net_device *dev, int if_port)
 {
     struct el3_private *lp = netdev_priv(dev);
-    kio_addr_t ioaddr = dev->base_addr;
+    unsigned int ioaddr = dev->base_addr;
     
     EL3WINDOW(0);
     switch (if_port) {
@@ -443,7 +443,7 @@ static void tc589_set_xcvr(struct net_device *dev, int if_port)
 
 static void dump_status(struct net_device *dev)
 {
-    kio_addr_t ioaddr = dev->base_addr;
+    unsigned int ioaddr = dev->base_addr;
     EL3WINDOW(1);
     printk(KERN_INFO "  irq status %04x, rx status %04x, tx status "
           "%02x  tx free %04x\n", inw(ioaddr+EL3_STATUS),
@@ -459,7 +459,7 @@ static void dump_status(struct net_device *dev)
 /* Reset and restore all of the 3c589 registers. */
 static void tc589_reset(struct net_device *dev)
 {
-    kio_addr_t ioaddr = dev->base_addr;
+    unsigned int ioaddr = dev->base_addr;
     int i;
     
     EL3WINDOW(0);
@@ -567,7 +567,7 @@ static int el3_open(struct net_device *dev)
 static void el3_tx_timeout(struct net_device *dev)
 {
     struct el3_private *lp = netdev_priv(dev);
-    kio_addr_t ioaddr = dev->base_addr;
+    unsigned int ioaddr = dev->base_addr;
     
     printk(KERN_WARNING "%s: Transmit timed out!\n", dev->name);
     dump_status(dev);
@@ -582,7 +582,7 @@ static void el3_tx_timeout(struct net_device *dev)
 static void pop_tx_status(struct net_device *dev)
 {
     struct el3_private *lp = netdev_priv(dev);
-    kio_addr_t ioaddr = dev->base_addr;
+    unsigned int ioaddr = dev->base_addr;
     int i;
     
     /* Clear the Tx status stack. */
@@ -604,7 +604,7 @@ static void pop_tx_status(struct net_device *dev)
 
 static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-    kio_addr_t ioaddr = dev->base_addr;
+    unsigned int ioaddr = dev->base_addr;
     struct el3_private *priv = netdev_priv(dev);
     unsigned long flags;
 
@@ -641,7 +641,7 @@ static irqreturn_t el3_interrupt(int irq, void *dev_id)
 {
     struct net_device *dev = (struct net_device *) dev_id;
     struct el3_private *lp = netdev_priv(dev);
-    kio_addr_t ioaddr;
+    unsigned int ioaddr;
     __u16 status;
     int i = 0, handled = 1;
     
@@ -727,7 +727,7 @@ static void media_check(unsigned long arg)
 {
     struct net_device *dev = (struct net_device *)(arg);
     struct el3_private *lp = netdev_priv(dev);
-    kio_addr_t ioaddr = dev->base_addr;
+    unsigned int ioaddr = dev->base_addr;
     u16 media, errs;
     unsigned long flags;
 
@@ -828,7 +828,7 @@ static struct net_device_stats *el3_get_stats(struct net_device *dev)
 static void update_stats(struct net_device *dev)
 {
     struct el3_private *lp = netdev_priv(dev);
-    kio_addr_t ioaddr = dev->base_addr;
+    unsigned int ioaddr = dev->base_addr;
 
     DEBUG(2, "%s: updating the statistics.\n", dev->name);
     /* Turn off statistics updates while reading. */
@@ -855,7 +855,7 @@ static void update_stats(struct net_device *dev)
 static int el3_rx(struct net_device *dev)
 {
     struct el3_private *lp = netdev_priv(dev);
-    kio_addr_t ioaddr = dev->base_addr;
+    unsigned int ioaddr = dev->base_addr;
     int worklimit = 32;
     short rx_status;
     
@@ -909,7 +909,7 @@ static void set_multicast_list(struct net_device *dev)
 {
     struct el3_private *lp = netdev_priv(dev);
     struct pcmcia_device *link = lp->p_dev;
-    kio_addr_t ioaddr = dev->base_addr;
+    unsigned int ioaddr = dev->base_addr;
     u16 opts = SetRxFilter | RxStation | RxBroadcast;
 
     if (!pcmcia_dev_present(link)) return;
@@ -924,7 +924,7 @@ static int el3_close(struct net_device *dev)
 {
     struct el3_private *lp = netdev_priv(dev);
     struct pcmcia_device *link = lp->p_dev;
-    kio_addr_t ioaddr = dev->base_addr;
+    unsigned int ioaddr = dev->base_addr;
     
     DEBUG(1, "%s: shutting down ethercard.\n", dev->name);
 
index 6d342f6c14f643a67a8ee6d78429a1480828f32f..e8a63e483a2be034f9c4a057d0b3cc8457ac645a 100644 (file)
@@ -96,8 +96,8 @@ static irqreturn_t ei_irq_wrapper(int irq, void *dev_id);
 static void ei_watchdog(u_long arg);
 static void axnet_reset_8390(struct net_device *dev);
 
-static int mdio_read(kio_addr_t addr, int phy_id, int loc);
-static void mdio_write(kio_addr_t addr, int phy_id, int loc, int value);
+static int mdio_read(unsigned int addr, int phy_id, int loc);
+static void mdio_write(unsigned int addr, int phy_id, int loc, int value);
 
 static void get_8390_hdr(struct net_device *,
                         struct e8390_pkt_hdr *, int);
@@ -203,7 +203,7 @@ static void axnet_detach(struct pcmcia_device *link)
 static int get_prom(struct pcmcia_device *link)
 {
     struct net_device *dev = link->priv;
-    kio_addr_t ioaddr = dev->base_addr;
+    unsigned int ioaddr = dev->base_addr;
     int i, j;
 
     /* This is based on drivers/net/ne.c */
@@ -473,7 +473,7 @@ static int axnet_resume(struct pcmcia_device *link)
 #define MDIO_MASK              0x0f
 #define MDIO_ENB_IN            0x02
 
-static void mdio_sync(kio_addr_t addr)
+static void mdio_sync(unsigned int addr)
 {
     int bits;
     for (bits = 0; bits < 32; bits++) {
@@ -482,7 +482,7 @@ static void mdio_sync(kio_addr_t addr)
     }
 }
 
-static int mdio_read(kio_addr_t addr, int phy_id, int loc)
+static int mdio_read(unsigned int addr, int phy_id, int loc)
 {
     u_int cmd = (0xf6<<10)|(phy_id<<5)|loc;
     int i, retval = 0;
@@ -501,7 +501,7 @@ static int mdio_read(kio_addr_t addr, int phy_id, int loc)
     return (retval>>1) & 0xffff;
 }
 
-static void mdio_write(kio_addr_t addr, int phy_id, int loc, int value)
+static void mdio_write(unsigned int addr, int phy_id, int loc, int value)
 {
     u_int cmd = (0x05<<28)|(phy_id<<23)|(loc<<18)|(1<<17)|value;
     int i;
@@ -575,7 +575,7 @@ static int axnet_close(struct net_device *dev)
 
 static void axnet_reset_8390(struct net_device *dev)
 {
-    kio_addr_t nic_base = dev->base_addr;
+    unsigned int nic_base = dev->base_addr;
     int i;
 
     ei_status.txing = ei_status.dmaing = 0;
@@ -610,8 +610,8 @@ static void ei_watchdog(u_long arg)
 {
     struct net_device *dev = (struct net_device *)(arg);
     axnet_dev_t *info = PRIV(dev);
-    kio_addr_t nic_base = dev->base_addr;
-    kio_addr_t mii_addr = nic_base + AXNET_MII_EEP;
+    unsigned int nic_base = dev->base_addr;
+    unsigned int mii_addr = nic_base + AXNET_MII_EEP;
     u_short link;
 
     if (!netif_device_present(dev)) goto reschedule;
@@ -681,7 +681,7 @@ static int axnet_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
     axnet_dev_t *info = PRIV(dev);
     u16 *data = (u16 *)&rq->ifr_ifru;
-    kio_addr_t mii_addr = dev->base_addr + AXNET_MII_EEP;
+    unsigned int mii_addr = dev->base_addr + AXNET_MII_EEP;
     switch (cmd) {
     case SIOCGMIIPHY:
        data[0] = info->phy_id;
@@ -703,7 +703,7 @@ static void get_8390_hdr(struct net_device *dev,
                         struct e8390_pkt_hdr *hdr,
                         int ring_page)
 {
-    kio_addr_t nic_base = dev->base_addr;
+    unsigned int nic_base = dev->base_addr;
 
     outb_p(0, nic_base + EN0_RSARLO);          /* On page boundary */
     outb_p(ring_page, nic_base + EN0_RSARHI);
@@ -721,7 +721,7 @@ static void get_8390_hdr(struct net_device *dev,
 static void block_input(struct net_device *dev, int count,
                        struct sk_buff *skb, int ring_offset)
 {
-    kio_addr_t nic_base = dev->base_addr;
+    unsigned int nic_base = dev->base_addr;
     int xfer_count = count;
     char *buf = skb->data;
 
@@ -744,7 +744,7 @@ static void block_input(struct net_device *dev, int count,
 static void block_output(struct net_device *dev, int count,
                         const u_char *buf, const int start_page)
 {
-    kio_addr_t nic_base = dev->base_addr;
+    unsigned int nic_base = dev->base_addr;
 
 #ifdef PCMCIA_DEBUG
     if (ei_debug > 4)
@@ -991,7 +991,7 @@ static int ax_open(struct net_device *dev)
  *
  * Opposite of ax_open(). Only used when "ifconfig <devname> down" is done.
  */
-int ax_close(struct net_device *dev)
+static int ax_close(struct net_device *dev)
 {
        unsigned long flags;
 
@@ -1014,7 +1014,7 @@ int ax_close(struct net_device *dev)
  * completed (or failed) - i.e. never posted a Tx related interrupt.
  */
 
-void ei_tx_timeout(struct net_device *dev)
+static void ei_tx_timeout(struct net_device *dev)
 {
        long e8390_base = dev->base_addr;
        struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
@@ -1087,8 +1087,8 @@ static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev)
        
        ei_local->irqlock = 1;
 
-       send_length = ETH_ZLEN < length ? length : ETH_ZLEN;
-       
+       send_length = max(length, ETH_ZLEN);
+
        /*
         * We have two Tx slots available for use. Find the first free
         * slot, and then perform some sanity checks. With two Tx bufs,
index 949c6df74c97d18eeada6281d3d2e25f4449fa27..8f328a03847b8340ae02d92bf2060ac5252c7ff7 100644 (file)
@@ -298,7 +298,8 @@ do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
 static int mfc_try_io_port(struct pcmcia_device *link)
 {
     int i, ret;
-    static const kio_addr_t serial_base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 };
+    static const unsigned int serial_base[5] =
+       { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 };
 
     for (i = 0; i < 5; i++) {
        link->io.BasePort2 = serial_base[i];
@@ -316,7 +317,7 @@ static int mfc_try_io_port(struct pcmcia_device *link)
 static int ungermann_try_io_port(struct pcmcia_device *link)
 {
     int ret;
-    kio_addr_t ioaddr;
+    unsigned int ioaddr;
     /*
        Ungermann-Bass Access/CARD accepts 0x300,0x320,0x340,0x360
        0x380,0x3c0 only for ioport.
@@ -342,7 +343,7 @@ static int fmvj18x_config(struct pcmcia_device *link)
     cisparse_t parse;
     u_short buf[32];
     int i, last_fn = 0, last_ret = 0, ret;
-    kio_addr_t ioaddr;
+    unsigned int ioaddr;
     cardtype_t cardtype;
     char *card_name = "unknown";
     u_char *node_id;
@@ -610,7 +611,7 @@ static int fmvj18x_setup_mfc(struct pcmcia_device *link)
     u_char __iomem *base;
     int i, j;
     struct net_device *dev = link->priv;
-    kio_addr_t ioaddr;
+    unsigned int ioaddr;
 
     /* Allocate a small memory window */
     req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE;
@@ -735,7 +736,7 @@ static irqreturn_t fjn_interrupt(int dummy, void *dev_id)
 {
     struct net_device *dev = dev_id;
     local_info_t *lp = netdev_priv(dev);
-    kio_addr_t ioaddr;
+    unsigned int ioaddr;
     unsigned short tx_stat, rx_stat;
 
     ioaddr = dev->base_addr;
@@ -789,7 +790,7 @@ static irqreturn_t fjn_interrupt(int dummy, void *dev_id)
 static void fjn_tx_timeout(struct net_device *dev)
 {
     struct local_info_t *lp = netdev_priv(dev);
-    kio_addr_t ioaddr = dev->base_addr;
+    unsigned int ioaddr = dev->base_addr;
 
     printk(KERN_NOTICE "%s: transmit timed out with status %04x, %s?\n",
           dev->name, htons(inw(ioaddr + TX_STATUS)),
@@ -819,7 +820,7 @@ static void fjn_tx_timeout(struct net_device *dev)
 static int fjn_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
     struct local_info_t *lp = netdev_priv(dev);
-    kio_addr_t ioaddr = dev->base_addr;
+    unsigned int ioaddr = dev->base_addr;
     short length = skb->len;
     
     if (length < ETH_ZLEN)
@@ -892,7 +893,7 @@ static int fjn_start_xmit(struct sk_buff *skb, struct net_device *dev)
 static void fjn_reset(struct net_device *dev)
 {
     struct local_info_t *lp = netdev_priv(dev);
-    kio_addr_t ioaddr = dev->base_addr;
+    unsigned int ioaddr = dev->base_addr;
     int i;
 
     DEBUG(4, "fjn_reset(%s) called.\n",dev->name);
@@ -971,7 +972,7 @@ static void fjn_reset(struct net_device *dev)
 static void fjn_rx(struct net_device *dev)
 {
     struct local_info_t *lp = netdev_priv(dev);
-    kio_addr_t ioaddr = dev->base_addr;
+    unsigned int ioaddr = dev->base_addr;
     int boguscount = 10;       /* 5 -> 10: by agy 19940922 */
 
     DEBUG(4, "%s: in rx_packet(), rx_status %02x.\n",
@@ -1125,7 +1126,7 @@ static int fjn_close(struct net_device *dev)
 {
     struct local_info_t *lp = netdev_priv(dev);
     struct pcmcia_device *link = lp->p_dev;
-    kio_addr_t ioaddr = dev->base_addr;
+    unsigned int ioaddr = dev->base_addr;
 
     DEBUG(4, "fjn_close('%s').\n", dev->name);
 
@@ -1168,7 +1169,7 @@ static struct net_device_stats *fjn_get_stats(struct net_device *dev)
 
 static void set_rx_mode(struct net_device *dev)
 {
-    kio_addr_t ioaddr = dev->base_addr;
+    unsigned int ioaddr = dev->base_addr;
     u_char mc_filter[8];                /* Multicast hash filter */
     u_long flags;
     int i;
@@ -1197,8 +1198,7 @@ static void set_rx_mode(struct net_device *dev)
        outb(1, ioaddr + RX_MODE);      /* Ignore almost all multicasts. */
     } else {
        struct dev_mc_list *mclist;
-       int i;
-       
+
        memset(mc_filter, 0, sizeof(mc_filter));
        for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
             i++, mclist = mclist->next) {
index a355a93b908b05222e97b992d4b46a04e55810f8..cfcbea9b7e2e374e36e45e986aac3d5d69af4681 100644 (file)
@@ -518,7 +518,7 @@ mace_read
        assuming that during normal operation, the MACE is always in
        bank 0.
 ---------------------------------------------------------------------------- */
-static int mace_read(mace_private *lp, kio_addr_t ioaddr, int reg)
+static int mace_read(mace_private *lp, unsigned int ioaddr, int reg)
 {
   int data = 0xFF;
   unsigned long flags;
@@ -545,7 +545,8 @@ mace_write
        are assuming that during normal operation, the MACE is always in
        bank 0.
 ---------------------------------------------------------------------------- */
-static void mace_write(mace_private *lp, kio_addr_t ioaddr, int reg, int data)
+static void mace_write(mace_private *lp, unsigned int ioaddr, int reg,
+                      int data)
 {
   unsigned long flags;
 
@@ -567,7 +568,7 @@ static void mace_write(mace_private *lp, kio_addr_t ioaddr, int reg, int data)
 mace_init
        Resets the MACE chip.
 ---------------------------------------------------------------------------- */
-static int mace_init(mace_private *lp, kio_addr_t ioaddr, char *enet_addr)
+static int mace_init(mace_private *lp, unsigned int ioaddr, char *enet_addr)
 {
   int i;
   int ct = 0;
@@ -657,7 +658,7 @@ static int nmclan_config(struct pcmcia_device *link)
   tuple_t tuple;
   u_char buf[64];
   int i, last_ret, last_fn;
-  kio_addr_t ioaddr;
+  unsigned int ioaddr;
   DECLARE_MAC_BUF(mac);
 
   DEBUG(0, "nmclan_config(0x%p)\n", link);
@@ -839,7 +840,7 @@ mace_open
 ---------------------------------------------------------------------------- */
 static int mace_open(struct net_device *dev)
 {
-  kio_addr_t ioaddr = dev->base_addr;
+  unsigned int ioaddr = dev->base_addr;
   mace_private *lp = netdev_priv(dev);
   struct pcmcia_device *link = lp->p_dev;
 
@@ -862,7 +863,7 @@ mace_close
 ---------------------------------------------------------------------------- */
 static int mace_close(struct net_device *dev)
 {
-  kio_addr_t ioaddr = dev->base_addr;
+  unsigned int ioaddr = dev->base_addr;
   mace_private *lp = netdev_priv(dev);
   struct pcmcia_device *link = lp->p_dev;
 
@@ -935,7 +936,7 @@ static void mace_tx_timeout(struct net_device *dev)
 static int mace_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
   mace_private *lp = netdev_priv(dev);
-  kio_addr_t ioaddr = dev->base_addr;
+  unsigned int ioaddr = dev->base_addr;
 
   netif_stop_queue(dev);
 
@@ -996,7 +997,7 @@ static irqreturn_t mace_interrupt(int irq, void *dev_id)
 {
   struct net_device *dev = (struct net_device *) dev_id;
   mace_private *lp = netdev_priv(dev);
-  kio_addr_t ioaddr;
+  unsigned int ioaddr;
   int status;
   int IntrCnt = MACE_MAX_IR_ITERATIONS;
 
@@ -1140,7 +1141,7 @@ mace_rx
 static int mace_rx(struct net_device *dev, unsigned char RxCnt)
 {
   mace_private *lp = netdev_priv(dev);
-  kio_addr_t ioaddr = dev->base_addr;
+  unsigned int ioaddr = dev->base_addr;
   unsigned char rx_framecnt;
   unsigned short rx_status;
 
@@ -1302,7 +1303,7 @@ update_stats
        card's SRAM fast enough.  If this happens, something is
        seriously wrong with the hardware.
 ---------------------------------------------------------------------------- */
-static void update_stats(kio_addr_t ioaddr, struct net_device *dev)
+static void update_stats(unsigned int ioaddr, struct net_device *dev)
 {
   mace_private *lp = netdev_priv(dev);
 
@@ -1448,7 +1449,7 @@ static void restore_multicast_list(struct net_device *dev)
   mace_private *lp = netdev_priv(dev);
   int num_addrs = lp->multicast_num_addrs;
   int *ladrf = lp->multicast_ladrf;
-  kio_addr_t ioaddr = dev->base_addr;
+  unsigned int ioaddr = dev->base_addr;
   int i;
 
   DEBUG(2, "%s: restoring Rx mode to %d addresses.\n",
@@ -1540,7 +1541,7 @@ static void set_multicast_list(struct net_device *dev)
 
 static void restore_multicast_list(struct net_device *dev)
 {
-  kio_addr_t ioaddr = dev->base_addr;
+  unsigned int ioaddr = dev->base_addr;
   mace_private *lp = netdev_priv(dev);
 
   DEBUG(2, "%s: restoring Rx mode to %d addresses.\n", dev->name,
index 9ba56aa26a1b2326f8a684b1c68166297e781185..6323988dfa1d162423839f5805fda55de61aab00 100644 (file)
@@ -349,7 +349,7 @@ static hw_info_t *get_hwinfo(struct pcmcia_device *link)
 static hw_info_t *get_prom(struct pcmcia_device *link)
 {
     struct net_device *dev = link->priv;
-    kio_addr_t ioaddr = dev->base_addr;
+    unsigned int ioaddr = dev->base_addr;
     u_char prom[32];
     int i, j;
 
@@ -425,7 +425,7 @@ static hw_info_t *get_dl10019(struct pcmcia_device *link)
 static hw_info_t *get_ax88190(struct pcmcia_device *link)
 {
     struct net_device *dev = link->priv;
-    kio_addr_t ioaddr = dev->base_addr;
+    unsigned int ioaddr = dev->base_addr;
     int i, j;
 
     /* Not much of a test, but the alternatives are messy */
@@ -521,7 +521,7 @@ static int pcnet_config(struct pcmcia_device *link)
     int i, last_ret, last_fn, start_pg, stop_pg, cm_offset;
     int has_shmem = 0;
     u_short buf[64];
-    hw_info_t *hw_info;
+    hw_info_t *local_hw_info;
     DECLARE_MAC_BUF(mac);
 
     DEBUG(0, "pcnet_config(0x%p)\n", link);
@@ -590,23 +590,23 @@ static int pcnet_config(struct pcmcia_device *link)
        dev->if_port = 0;
     }
 
-    hw_info = get_hwinfo(link);
-    if (hw_info == NULL)
-       hw_info = get_prom(link);
-    if (hw_info == NULL)
-       hw_info = get_dl10019(link);
-    if (hw_info == NULL)
-       hw_info = get_ax88190(link);
-    if (hw_info == NULL)
-       hw_info = get_hwired(link);
-
-    if (hw_info == NULL) {
+    local_hw_info = get_hwinfo(link);
+    if (local_hw_info == NULL)
+       local_hw_info = get_prom(link);
+    if (local_hw_info == NULL)
+       local_hw_info = get_dl10019(link);
+    if (local_hw_info == NULL)
+       local_hw_info = get_ax88190(link);
+    if (local_hw_info == NULL)
+       local_hw_info = get_hwired(link);
+
+    if (local_hw_info == NULL) {
        printk(KERN_NOTICE "pcnet_cs: unable to read hardware net"
               " address for io base %#3lx\n", dev->base_addr);
        goto failed;
     }
 
-    info->flags = hw_info->flags;
+    info->flags = local_hw_info->flags;
     /* Check for user overrides */
     info->flags |= (delay_output) ? DELAY_OUTPUT : 0;
     if ((link->manf_id == MANFID_SOCKET) &&
@@ -756,7 +756,7 @@ static int pcnet_resume(struct pcmcia_device *link)
 #define MDIO_DATA_READ         0x10
 #define MDIO_MASK              0x0f
 
-static void mdio_sync(kio_addr_t addr)
+static void mdio_sync(unsigned int addr)
 {
     int bits, mask = inb(addr) & MDIO_MASK;
     for (bits = 0; bits < 32; bits++) {
@@ -765,7 +765,7 @@ static void mdio_sync(kio_addr_t addr)
     }
 }
 
-static int mdio_read(kio_addr_t addr, int phy_id, int loc)
+static int mdio_read(unsigned int addr, int phy_id, int loc)
 {
     u_int cmd = (0x06<<10)|(phy_id<<5)|loc;
     int i, retval = 0, mask = inb(addr) & MDIO_MASK;
@@ -784,7 +784,7 @@ static int mdio_read(kio_addr_t addr, int phy_id, int loc)
     return (retval>>1) & 0xffff;
 }
 
-static void mdio_write(kio_addr_t addr, int phy_id, int loc, int value)
+static void mdio_write(unsigned int addr, int phy_id, int loc, int value)
 {
     u_int cmd = (0x05<<28)|(phy_id<<23)|(loc<<18)|(1<<17)|value;
     int i, mask = inb(addr) & MDIO_MASK;
@@ -818,10 +818,10 @@ static void mdio_write(kio_addr_t addr, int phy_id, int loc, int value)
 
 #define DL19FDUPLX     0x0400  /* DL10019 Full duplex mode */
 
-static int read_eeprom(kio_addr_t ioaddr, int location)
+static int read_eeprom(unsigned int ioaddr, int location)
 {
     int i, retval = 0;
-    kio_addr_t ee_addr = ioaddr + DLINK_EEPROM;
+    unsigned int ee_addr = ioaddr + DLINK_EEPROM;
     int read_cmd = location | (EE_READ_CMD << 8);
 
     outb(0, ee_addr);
@@ -852,10 +852,10 @@ static int read_eeprom(kio_addr_t ioaddr, int location)
     In ASIC mode, EE_ADOT is used to output the data to the ASIC.
 */
 
-static void write_asic(kio_addr_t ioaddr, int location, short asic_data)
+static void write_asic(unsigned int ioaddr, int location, short asic_data)
 {
        int i;
-       kio_addr_t ee_addr = ioaddr + DLINK_EEPROM;
+       unsigned int ee_addr = ioaddr + DLINK_EEPROM;
        short dataval;
        int read_cmd = location | (EE_READ_CMD << 8);
 
@@ -897,7 +897,7 @@ static void write_asic(kio_addr_t ioaddr, int location, short asic_data)
 
 static void set_misc_reg(struct net_device *dev)
 {
-    kio_addr_t nic_base = dev->base_addr;
+    unsigned int nic_base = dev->base_addr;
     pcnet_dev_t *info = PRIV(dev);
     u_char tmp;
 
@@ -936,7 +936,7 @@ static void set_misc_reg(struct net_device *dev)
 static void mii_phy_probe(struct net_device *dev)
 {
     pcnet_dev_t *info = PRIV(dev);
-    kio_addr_t mii_addr = dev->base_addr + DLINK_GPIO;
+    unsigned int mii_addr = dev->base_addr + DLINK_GPIO;
     int i;
     u_int tmp, phyid;
 
@@ -1014,7 +1014,7 @@ static int pcnet_close(struct net_device *dev)
 
 static void pcnet_reset_8390(struct net_device *dev)
 {
-    kio_addr_t nic_base = dev->base_addr;
+    unsigned int nic_base = dev->base_addr;
     int i;
 
     ei_status.txing = ei_status.dmaing = 0;
@@ -1074,8 +1074,8 @@ static void ei_watchdog(u_long arg)
 {
     struct net_device *dev = (struct net_device *)arg;
     pcnet_dev_t *info = PRIV(dev);
-    kio_addr_t nic_base = dev->base_addr;
-    kio_addr_t mii_addr = nic_base + DLINK_GPIO;
+    unsigned int nic_base = dev->base_addr;
+    unsigned int mii_addr = nic_base + DLINK_GPIO;
     u_short link;
 
     if (!netif_device_present(dev)) goto reschedule;
@@ -1177,7 +1177,7 @@ static int ei_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
     pcnet_dev_t *info = PRIV(dev);
     u16 *data = (u16 *)&rq->ifr_ifru;
-    kio_addr_t mii_addr = dev->base_addr + DLINK_GPIO;
+    unsigned int mii_addr = dev->base_addr + DLINK_GPIO;
     switch (cmd) {
     case SIOCGMIIPHY:
        data[0] = info->phy_id;
@@ -1199,7 +1199,7 @@ static void dma_get_8390_hdr(struct net_device *dev,
                             struct e8390_pkt_hdr *hdr,
                             int ring_page)
 {
-    kio_addr_t nic_base = dev->base_addr;
+    unsigned int nic_base = dev->base_addr;
 
     if (ei_status.dmaing) {
        printk(KERN_NOTICE "%s: DMAing conflict in dma_block_input."
@@ -1230,7 +1230,7 @@ static void dma_get_8390_hdr(struct net_device *dev,
 static void dma_block_input(struct net_device *dev, int count,
                            struct sk_buff *skb, int ring_offset)
 {
-    kio_addr_t nic_base = dev->base_addr;
+    unsigned int nic_base = dev->base_addr;
     int xfer_count = count;
     char *buf = skb->data;
 
@@ -1285,7 +1285,7 @@ static void dma_block_input(struct net_device *dev, int count,
 static void dma_block_output(struct net_device *dev, int count,
                             const u_char *buf, const int start_page)
 {
-    kio_addr_t nic_base = dev->base_addr;
+    unsigned int nic_base = dev->base_addr;
     pcnet_dev_t *info = PRIV(dev);
 #ifdef PCMCIA_DEBUG
     int retries = 0;
index c9868e9dac4caa70675f9367498e93dc8a63ae99..f18eca9831e88f8169ad944d7e8f363cd5b26300 100644 (file)
@@ -295,7 +295,7 @@ static int s9k_config(struct net_device *dev, struct ifmap *map);
 static void smc_set_xcvr(struct net_device *dev, int if_port);
 static void smc_reset(struct net_device *dev);
 static void media_check(u_long arg);
-static void mdio_sync(kio_addr_t addr);
+static void mdio_sync(unsigned int addr);
 static int mdio_read(struct net_device *dev, int phy_id, int loc);
 static void mdio_write(struct net_device *dev, int phy_id, int loc, int value);
 static int smc_link_ok(struct net_device *dev);
@@ -601,8 +601,8 @@ static void mot_config(struct pcmcia_device *link)
 {
     struct net_device *dev = link->priv;
     struct smc_private *smc = netdev_priv(dev);
-    kio_addr_t ioaddr = dev->base_addr;
-    kio_addr_t iouart = link->io.BasePort2;
+    unsigned int ioaddr = dev->base_addr;
+    unsigned int iouart = link->io.BasePort2;
 
     /* Set UART base address and force map with COR bit 1 */
     writeb(iouart & 0xff,        smc->base + MOT_UART + CISREG_IOBASE_0);
@@ -621,7 +621,7 @@ static void mot_config(struct pcmcia_device *link)
 static int mot_setup(struct pcmcia_device *link)
 {
     struct net_device *dev = link->priv;
-    kio_addr_t ioaddr = dev->base_addr;
+    unsigned int ioaddr = dev->base_addr;
     int i, wait, loop;
     u_int addr;
 
@@ -754,7 +754,7 @@ free_cfg_mem:
 static int osi_config(struct pcmcia_device *link)
 {
     struct net_device *dev = link->priv;
-    static const kio_addr_t com[4] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 };
+    static const unsigned int com[4] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 };
     int i, j;
 
     link->conf.Attributes |= CONF_ENABLE_SPKR;
@@ -900,7 +900,7 @@ static int smc91c92_resume(struct pcmcia_device *link)
 static int check_sig(struct pcmcia_device *link)
 {
     struct net_device *dev = link->priv;
-    kio_addr_t ioaddr = dev->base_addr;
+    unsigned int ioaddr = dev->base_addr;
     int width;
     u_short s;
 
@@ -960,7 +960,7 @@ static int smc91c92_config(struct pcmcia_device *link)
     struct smc_private *smc = netdev_priv(dev);
     char *name;
     int i, j, rev;
-    kio_addr_t ioaddr;
+    unsigned int ioaddr;
     u_long mir;
     DECLARE_MAC_BUF(mac);
 
@@ -1136,7 +1136,7 @@ static void smc91c92_release(struct pcmcia_device *link)
 #define MDIO_DATA_WRITE1       (MDIO_DIR_WRITE | MDIO_DATA_OUT)
 #define MDIO_DATA_READ         0x02
 
-static void mdio_sync(kio_addr_t addr)
+static void mdio_sync(unsigned int addr)
 {
     int bits;
     for (bits = 0; bits < 32; bits++) {
@@ -1147,7 +1147,7 @@ static void mdio_sync(kio_addr_t addr)
 
 static int mdio_read(struct net_device *dev, int phy_id, int loc)
 {
-    kio_addr_t addr = dev->base_addr + MGMT;
+    unsigned int addr = dev->base_addr + MGMT;
     u_int cmd = (0x06<<10)|(phy_id<<5)|loc;
     int i, retval = 0;
 
@@ -1167,7 +1167,7 @@ static int mdio_read(struct net_device *dev, int phy_id, int loc)
 
 static void mdio_write(struct net_device *dev, int phy_id, int loc, int value)
 {
-    kio_addr_t addr = dev->base_addr + MGMT;
+    unsigned int addr = dev->base_addr + MGMT;
     u_int cmd = (0x05<<28)|(phy_id<<23)|(loc<<18)|(1<<17)|value;
     int i;
 
@@ -1193,7 +1193,7 @@ static void mdio_write(struct net_device *dev, int phy_id, int loc, int value)
 #ifdef PCMCIA_DEBUG
 static void smc_dump(struct net_device *dev)
 {
-    kio_addr_t ioaddr = dev->base_addr;
+    unsigned int ioaddr = dev->base_addr;
     u_short i, w, save;
     save = inw(ioaddr + BANK_SELECT);
     for (w = 0; w < 4; w++) {
@@ -1248,7 +1248,7 @@ static int smc_close(struct net_device *dev)
 {
     struct smc_private *smc = netdev_priv(dev);
     struct pcmcia_device *link = smc->p_dev;
-    kio_addr_t ioaddr = dev->base_addr;
+    unsigned int ioaddr = dev->base_addr;
 
     DEBUG(0, "%s: smc_close(), status %4.4x.\n",
          dev->name, inw(ioaddr + BANK_SELECT));
@@ -1285,7 +1285,7 @@ static void smc_hardware_send_packet(struct net_device * dev)
 {
     struct smc_private *smc = netdev_priv(dev);
     struct sk_buff *skb = smc->saved_skb;
-    kio_addr_t ioaddr = dev->base_addr;
+    unsigned int ioaddr = dev->base_addr;
     u_char packet_no;
 
     if (!skb) {
@@ -1349,7 +1349,7 @@ static void smc_hardware_send_packet(struct net_device * dev)
 static void smc_tx_timeout(struct net_device *dev)
 {
     struct smc_private *smc = netdev_priv(dev);
-    kio_addr_t ioaddr = dev->base_addr;
+    unsigned int ioaddr = dev->base_addr;
 
     printk(KERN_NOTICE "%s: SMC91c92 transmit timed out, "
           "Tx_status %2.2x status %4.4x.\n",
@@ -1364,7 +1364,7 @@ static void smc_tx_timeout(struct net_device *dev)
 static int smc_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
     struct smc_private *smc = netdev_priv(dev);
-    kio_addr_t ioaddr = dev->base_addr;
+    unsigned int ioaddr = dev->base_addr;
     u_short num_pages;
     short time_out, ir;
     unsigned long flags;
@@ -1434,7 +1434,7 @@ static int smc_start_xmit(struct sk_buff *skb, struct net_device *dev)
 static void smc_tx_err(struct net_device * dev)
 {
     struct smc_private *smc = netdev_priv(dev);
-    kio_addr_t ioaddr = dev->base_addr;
+    unsigned int ioaddr = dev->base_addr;
     int saved_packet = inw(ioaddr + PNR_ARR) & 0xff;
     int packet_no = inw(ioaddr + FIFO_PORTS) & 0x7f;
     int tx_status;
@@ -1478,7 +1478,7 @@ static void smc_tx_err(struct net_device * dev)
 static void smc_eph_irq(struct net_device *dev)
 {
     struct smc_private *smc = netdev_priv(dev);
-    kio_addr_t ioaddr = dev->base_addr;
+    unsigned int ioaddr = dev->base_addr;
     u_short card_stats, ephs;
 
     SMC_SELECT_BANK(0);
@@ -1513,7 +1513,7 @@ static irqreturn_t smc_interrupt(int irq, void *dev_id)
 {
     struct net_device *dev = dev_id;
     struct smc_private *smc = netdev_priv(dev);
-    kio_addr_t ioaddr;
+    unsigned int ioaddr;
     u_short saved_bank, saved_pointer, mask, status;
     unsigned int handled = 1;
     char bogus_cnt = INTR_WORK;                /* Work we are willing to do. */
@@ -1633,7 +1633,7 @@ irq_done:
 static void smc_rx(struct net_device *dev)
 {
     struct smc_private *smc = netdev_priv(dev);
-    kio_addr_t ioaddr = dev->base_addr;
+    unsigned int ioaddr = dev->base_addr;
     int rx_status;
     int packet_length; /* Caution: not frame length, rather words
                           to transfer from the chip. */
@@ -1738,7 +1738,7 @@ static void fill_multicast_tbl(int count, struct dev_mc_list *addrs,
 
 static void set_rx_mode(struct net_device *dev)
 {
-    kio_addr_t ioaddr = dev->base_addr;
+    unsigned int ioaddr = dev->base_addr;
     struct smc_private *smc = netdev_priv(dev);
     u_int multicast_table[ 2 ] = { 0, };
     unsigned long flags;
@@ -1804,7 +1804,7 @@ static int s9k_config(struct net_device *dev, struct ifmap *map)
 static void smc_set_xcvr(struct net_device *dev, int if_port)
 {
     struct smc_private *smc = netdev_priv(dev);
-    kio_addr_t ioaddr = dev->base_addr;
+    unsigned int ioaddr = dev->base_addr;
     u_short saved_bank;
 
     saved_bank = inw(ioaddr + BANK_SELECT);
@@ -1827,7 +1827,7 @@ static void smc_set_xcvr(struct net_device *dev, int if_port)
 
 static void smc_reset(struct net_device *dev)
 {
-    kio_addr_t ioaddr = dev->base_addr;
+    unsigned int ioaddr = dev->base_addr;
     struct smc_private *smc = netdev_priv(dev);
     int i;
 
@@ -1904,7 +1904,7 @@ static void media_check(u_long arg)
 {
     struct net_device *dev = (struct net_device *) arg;
     struct smc_private *smc = netdev_priv(dev);
-    kio_addr_t ioaddr = dev->base_addr;
+    unsigned int ioaddr = dev->base_addr;
     u_short i, media, saved_bank;
     u_short link;
     unsigned long flags;
@@ -2021,7 +2021,7 @@ reschedule:
 
 static int smc_link_ok(struct net_device *dev)
 {
-    kio_addr_t ioaddr = dev->base_addr;
+    unsigned int ioaddr = dev->base_addr;
     struct smc_private *smc = netdev_priv(dev);
 
     if (smc->cfg & CFG_MII_SELECT) {
@@ -2035,7 +2035,7 @@ static int smc_link_ok(struct net_device *dev)
 static int smc_netdev_get_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd)
 {
     u16 tmp;
-    kio_addr_t ioaddr = dev->base_addr;
+    unsigned int ioaddr = dev->base_addr;
 
     ecmd->supported = (SUPPORTED_TP | SUPPORTED_AUI |
        SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full);
@@ -2057,7 +2057,7 @@ static int smc_netdev_get_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd)
 static int smc_netdev_set_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd)
 {
     u16 tmp;
-    kio_addr_t ioaddr = dev->base_addr;
+    unsigned int ioaddr = dev->base_addr;
 
     if (ecmd->speed != SPEED_10)
        return -EINVAL;
@@ -2100,7 +2100,7 @@ static void smc_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info
 static int smc_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
 {
        struct smc_private *smc = netdev_priv(dev);
-       kio_addr_t ioaddr = dev->base_addr;
+       unsigned int ioaddr = dev->base_addr;
        u16 saved_bank = inw(ioaddr + BANK_SELECT);
        int ret;
 
@@ -2118,7 +2118,7 @@ static int smc_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
 static int smc_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
 {
        struct smc_private *smc = netdev_priv(dev);
-       kio_addr_t ioaddr = dev->base_addr;
+       unsigned int ioaddr = dev->base_addr;
        u16 saved_bank = inw(ioaddr + BANK_SELECT);
        int ret;
 
@@ -2136,7 +2136,7 @@ static int smc_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
 static u32 smc_get_link(struct net_device *dev)
 {
        struct smc_private *smc = netdev_priv(dev);
-       kio_addr_t ioaddr = dev->base_addr;
+       unsigned int ioaddr = dev->base_addr;
        u16 saved_bank = inw(ioaddr + BANK_SELECT);
        u32 ret;
 
@@ -2164,7 +2164,7 @@ static int smc_nway_reset(struct net_device *dev)
 {
        struct smc_private *smc = netdev_priv(dev);
        if (smc->cfg & CFG_MII_SELECT) {
-               kio_addr_t ioaddr = dev->base_addr;
+               unsigned int ioaddr = dev->base_addr;
                u16 saved_bank = inw(ioaddr + BANK_SELECT);
                int res;
 
@@ -2196,7 +2196,7 @@ static int smc_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
        struct mii_ioctl_data *mii = if_mii(rq);
        int rc = 0;
        u16 saved_bank;
-       kio_addr_t ioaddr = dev->base_addr;
+       unsigned int ioaddr = dev->base_addr;
 
        if (!netif_running(dev))
                return -EINVAL;
index 1f09bea6db5ab8024c87f6dc37ff13a1707f3a2d..d041f831a18d7d392f426b3dde3c75576bc30158 100644 (file)
@@ -273,12 +273,12 @@ INT_MODULE_PARM(lockup_hack,      0);  /* anti lockup hack */
 static unsigned maxrx_bytes = 22000;
 
 /* MII management prototypes */
-static void mii_idle(kio_addr_t ioaddr);
-static void mii_putbit(kio_addr_t ioaddr, unsigned data);
-static int  mii_getbit(kio_addr_t ioaddr);
-static void mii_wbits(kio_addr_t ioaddr, unsigned data, int len);
-static unsigned mii_rd(kio_addr_t ioaddr, u_char phyaddr, u_char phyreg);
-static void mii_wr(kio_addr_t ioaddr, u_char phyaddr, u_char phyreg,
+static void mii_idle(unsigned int ioaddr);
+static void mii_putbit(unsigned int ioaddr, unsigned data);
+static int  mii_getbit(unsigned int ioaddr);
+static void mii_wbits(unsigned int ioaddr, unsigned data, int len);
+static unsigned mii_rd(unsigned int ioaddr, u_char phyaddr, u_char phyreg);
+static void mii_wr(unsigned int ioaddr, u_char phyaddr, u_char phyreg,
                   unsigned data, int len);
 
 /*
@@ -403,7 +403,7 @@ next_tuple(struct pcmcia_device *handle, tuple_t *tuple, cisparse_t *parse)
 static void
 PrintRegisters(struct net_device *dev)
 {
-    kio_addr_t ioaddr = dev->base_addr;
+    unsigned int ioaddr = dev->base_addr;
 
     if (pc_debug > 1) {
        int i, page;
@@ -439,7 +439,7 @@ PrintRegisters(struct net_device *dev)
  * Turn around for read
  */
 static void
-mii_idle(kio_addr_t ioaddr)
+mii_idle(unsigned int ioaddr)
 {
     PutByte(XIRCREG2_GPR2, 0x04|0); /* drive MDCK low */
     udelay(1);
@@ -451,7 +451,7 @@ mii_idle(kio_addr_t ioaddr)
  * Write a bit to MDI/O
  */
 static void
-mii_putbit(kio_addr_t ioaddr, unsigned data)
+mii_putbit(unsigned int ioaddr, unsigned data)
 {
   #if 1
     if (data) {
@@ -484,7 +484,7 @@ mii_putbit(kio_addr_t ioaddr, unsigned data)
  * Get a bit from MDI/O
  */
 static int
-mii_getbit(kio_addr_t ioaddr)
+mii_getbit(unsigned int ioaddr)
 {
     unsigned d;
 
@@ -497,7 +497,7 @@ mii_getbit(kio_addr_t ioaddr)
 }
 
 static void
-mii_wbits(kio_addr_t ioaddr, unsigned data, int len)
+mii_wbits(unsigned int ioaddr, unsigned data, int len)
 {
     unsigned m = 1 << (len-1);
     for (; m; m >>= 1)
@@ -505,7 +505,7 @@ mii_wbits(kio_addr_t ioaddr, unsigned data, int len)
 }
 
 static unsigned
-mii_rd(kio_addr_t ioaddr,      u_char phyaddr, u_char phyreg)
+mii_rd(unsigned int ioaddr,    u_char phyaddr, u_char phyreg)
 {
     int i;
     unsigned data=0, m;
@@ -527,7 +527,8 @@ mii_rd(kio_addr_t ioaddr,   u_char phyaddr, u_char phyreg)
 }
 
 static void
-mii_wr(kio_addr_t ioaddr, u_char phyaddr, u_char phyreg, unsigned data, int len)
+mii_wr(unsigned int ioaddr, u_char phyaddr, u_char phyreg, unsigned data,
+       int len)
 {
     int i;
 
@@ -726,7 +727,7 @@ xirc2ps_config(struct pcmcia_device * link)
     local_info_t *local = netdev_priv(dev);
     tuple_t tuple;
     cisparse_t parse;
-    kio_addr_t ioaddr;
+    unsigned int ioaddr;
     int err, i;
     u_char buf[64];
     cistpl_lan_node_id_t *node_id = (cistpl_lan_node_id_t*)parse.funce.data;
@@ -1104,7 +1105,7 @@ xirc2ps_interrupt(int irq, void *dev_id)
 {
     struct net_device *dev = (struct net_device *)dev_id;
     local_info_t *lp = netdev_priv(dev);
-    kio_addr_t ioaddr;
+    unsigned int ioaddr;
     u_char saved_page;
     unsigned bytes_rcvd;
     unsigned int_status, eth_status, rx_status, tx_status;
@@ -1209,7 +1210,7 @@ xirc2ps_interrupt(int irq, void *dev_id)
                    unsigned i;
                    u_long *p = skb_put(skb, pktlen);
                    register u_long a;
-                   kio_addr_t edpreg = ioaddr+XIRCREG_EDP-2;
+                   unsigned int edpreg = ioaddr+XIRCREG_EDP-2;
                    for (i=0; i < len ; i += 4, p++) {
                        a = inl(edpreg);
                        __asm__("rorl $16,%0\n\t"
@@ -1346,7 +1347,7 @@ static int
 do_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
     local_info_t *lp = netdev_priv(dev);
-    kio_addr_t ioaddr = dev->base_addr;
+    unsigned int ioaddr = dev->base_addr;
     int okay;
     unsigned freespace;
     unsigned pktlen = skb->len;
@@ -1415,7 +1416,7 @@ do_get_stats(struct net_device *dev)
 static void
 set_addresses(struct net_device *dev)
 {
-    kio_addr_t ioaddr = dev->base_addr;
+    unsigned int ioaddr = dev->base_addr;
     local_info_t *lp = netdev_priv(dev);
     struct dev_mc_list *dmi = dev->mc_list;
     unsigned char *addr;
@@ -1459,7 +1460,7 @@ set_addresses(struct net_device *dev)
 static void
 set_multicast_list(struct net_device *dev)
 {
-    kio_addr_t ioaddr = dev->base_addr;
+    unsigned int ioaddr = dev->base_addr;
 
     SelectPage(0x42);
     if (dev->flags & IFF_PROMISC) { /* snoop */
@@ -1543,7 +1544,7 @@ static int
 do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
     local_info_t *local = netdev_priv(dev);
-    kio_addr_t ioaddr = dev->base_addr;
+    unsigned int ioaddr = dev->base_addr;
     u16 *data = (u16 *)&rq->ifr_ifru;
 
     DEBUG(1, "%s: ioctl(%-.6s, %#04x) %04x %04x %04x %04x\n",
@@ -1575,7 +1576,7 @@ static void
 hardreset(struct net_device *dev)
 {
     local_info_t *local = netdev_priv(dev);
-    kio_addr_t ioaddr = dev->base_addr;
+    unsigned int ioaddr = dev->base_addr;
 
     SelectPage(4);
     udelay(1);
@@ -1592,7 +1593,7 @@ static void
 do_reset(struct net_device *dev, int full)
 {
     local_info_t *local = netdev_priv(dev);
-    kio_addr_t ioaddr = dev->base_addr;
+    unsigned int ioaddr = dev->base_addr;
     unsigned value;
 
     DEBUG(0, "%s: do_reset(%p,%d)\n", dev? dev->name:"eth?", dev, full);
@@ -1753,7 +1754,7 @@ static int
 init_mii(struct net_device *dev)
 {
     local_info_t *local = netdev_priv(dev);
-    kio_addr_t ioaddr = dev->base_addr;
+    unsigned int ioaddr = dev->base_addr;
     unsigned control, status, linkpartner;
     int i;
 
@@ -1826,7 +1827,7 @@ static void
 do_powerdown(struct net_device *dev)
 {
 
-    kio_addr_t ioaddr = dev->base_addr;
+    unsigned int ioaddr = dev->base_addr;
 
     DEBUG(0, "do_powerdown(%p)\n", dev);
 
@@ -1838,7 +1839,7 @@ do_powerdown(struct net_device *dev)
 static int
 do_stop(struct net_device *dev)
 {
-    kio_addr_t ioaddr = dev->base_addr;
+    unsigned int ioaddr = dev->base_addr;
     local_info_t *lp = netdev_priv(dev);
     struct pcmcia_device *link = lp->p_dev;
 
index 7fe03ce774b1e99d4c07f3b877f6a8a7d3d06841..f4ca0591231d233f63a2d98cb6036f106fde21c4 100644 (file)
@@ -60,6 +60,11 @@ config ICPLUS_PHY
        ---help---
          Currently supports the IP175C PHY.
 
+config REALTEK_PHY
+       tristate "Drivers for Realtek PHYs"
+       ---help---
+         Supports the Realtek 821x PHY.
+
 config FIXED_PHY
        bool "Driver for MDIO Bus/PHY emulation with fixed speed/link PHYs"
        ---help---
index 3d6cc7b67a800f209fc26b354a69c2eba3e8501c..5997d6ef702b979742d30642099411bb6aea815c 100644 (file)
@@ -12,5 +12,6 @@ obj-$(CONFIG_SMSC_PHY)                += smsc.o
 obj-$(CONFIG_VITESSE_PHY)      += vitesse.o
 obj-$(CONFIG_BROADCOM_PHY)     += broadcom.o
 obj-$(CONFIG_ICPLUS_PHY)       += icplus.o
+obj-$(CONFIG_REALTEK_PHY)      += realtek.o
 obj-$(CONFIG_FIXED_PHY)                += fixed.o
 obj-$(CONFIG_MDIO_BITBANG)     += mdio-bitbang.o
index 29666c85ed55936683e4cfc4b7dc0a1f03efb8dd..5b80358af65840926a1de33d4517e41396d6f835 100644 (file)
@@ -141,6 +141,20 @@ static struct phy_driver bcm5461_driver = {
        .driver         = { .owner = THIS_MODULE },
 };
 
+static struct phy_driver bcm5482_driver = {
+    .phy_id            = 0x0143bcb0,
+       .phy_id_mask    = 0xfffffff0,
+       .name           = "Broadcom BCM5482",
+       .features       = PHY_GBIT_FEATURES,
+       .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
+       .config_init    = bcm54xx_config_init,
+       .config_aneg    = genphy_config_aneg,
+       .read_status    = genphy_read_status,
+       .ack_interrupt  = bcm54xx_ack_interrupt,
+       .config_intr    = bcm54xx_config_intr,
+       .driver         = { .owner = THIS_MODULE },
+};
+
 static int __init broadcom_init(void)
 {
        int ret;
@@ -154,8 +168,13 @@ static int __init broadcom_init(void)
        ret = phy_driver_register(&bcm5461_driver);
        if (ret)
                goto out_5461;
+       ret = phy_driver_register(&bcm5482_driver);
+       if (ret)
+               goto out_5482;
        return ret;
 
+out_5482:
+       phy_driver_unregister(&bcm5461_driver);
 out_5461:
        phy_driver_unregister(&bcm5421_driver);
 out_5421:
@@ -166,6 +185,7 @@ out_5411:
 
 static void __exit broadcom_exit(void)
 {
+       phy_driver_unregister(&bcm5482_driver);
        phy_driver_unregister(&bcm5461_driver);
        phy_driver_unregister(&bcm5421_driver);
        phy_driver_unregister(&bcm5411_driver);
index c30196d0ad1681de95f5c14df66d8568c1200bd9..6e9f619c491f74837a7f356943683094169e28bf 100644 (file)
@@ -49,7 +49,7 @@ int mdiobus_register(struct mii_bus *bus)
        int i;
        int err = 0;
 
-       spin_lock_init(&bus->mdio_lock);
+       mutex_init(&bus->mdio_lock);
 
        if (NULL == bus || NULL == bus->name ||
                        NULL == bus->read ||
index 7c9e6e349503eaf2a7b91448a05a73d19e499bb8..12fccb1c76dc0c147e3291aaad803c8d5dbc9caf 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
-#include <linux/spinlock.h>
 #include <linux/mm.h>
 #include <linux/module.h>
 #include <linux/mii.h>
@@ -72,9 +71,11 @@ int phy_read(struct phy_device *phydev, u16 regnum)
        int retval;
        struct mii_bus *bus = phydev->bus;
 
-       spin_lock_bh(&bus->mdio_lock);
+       BUG_ON(in_interrupt());
+
+       mutex_lock(&bus->mdio_lock);
        retval = bus->read(bus, phydev->addr, regnum);
-       spin_unlock_bh(&bus->mdio_lock);
+       mutex_unlock(&bus->mdio_lock);
 
        return retval;
 }
@@ -95,9 +96,11 @@ int phy_write(struct phy_device *phydev, u16 regnum, u16 val)
        int err;
        struct mii_bus *bus = phydev->bus;
 
-       spin_lock_bh(&bus->mdio_lock);
+       BUG_ON(in_interrupt());
+
+       mutex_lock(&bus->mdio_lock);
        err = bus->write(bus, phydev->addr, regnum, val);
-       spin_unlock_bh(&bus->mdio_lock);
+       mutex_unlock(&bus->mdio_lock);
 
        return err;
 }
@@ -428,7 +431,7 @@ int phy_start_aneg(struct phy_device *phydev)
 {
        int err;
 
-       spin_lock_bh(&phydev->lock);
+       mutex_lock(&phydev->lock);
 
        if (AUTONEG_DISABLE == phydev->autoneg)
                phy_sanitize_settings(phydev);
@@ -449,13 +452,14 @@ int phy_start_aneg(struct phy_device *phydev)
        }
 
 out_unlock:
-       spin_unlock_bh(&phydev->lock);
+       mutex_unlock(&phydev->lock);
        return err;
 }
 EXPORT_SYMBOL(phy_start_aneg);
 
 
 static void phy_change(struct work_struct *work);
+static void phy_state_machine(struct work_struct *work);
 static void phy_timer(unsigned long data);
 
 /**
@@ -476,6 +480,7 @@ void phy_start_machine(struct phy_device *phydev,
 {
        phydev->adjust_state = handler;
 
+       INIT_WORK(&phydev->state_queue, phy_state_machine);
        init_timer(&phydev->phy_timer);
        phydev->phy_timer.function = &phy_timer;
        phydev->phy_timer.data = (unsigned long) phydev;
@@ -493,11 +498,12 @@ void phy_start_machine(struct phy_device *phydev,
 void phy_stop_machine(struct phy_device *phydev)
 {
        del_timer_sync(&phydev->phy_timer);
+       cancel_work_sync(&phydev->state_queue);
 
-       spin_lock_bh(&phydev->lock);
+       mutex_lock(&phydev->lock);
        if (phydev->state > PHY_UP)
                phydev->state = PHY_UP;
-       spin_unlock_bh(&phydev->lock);
+       mutex_unlock(&phydev->lock);
 
        phydev->adjust_state = NULL;
 }
@@ -541,9 +547,9 @@ static void phy_force_reduction(struct phy_device *phydev)
  */
 void phy_error(struct phy_device *phydev)
 {
-       spin_lock_bh(&phydev->lock);
+       mutex_lock(&phydev->lock);
        phydev->state = PHY_HALTED;
-       spin_unlock_bh(&phydev->lock);
+       mutex_unlock(&phydev->lock);
 }
 
 /**
@@ -705,10 +711,10 @@ static void phy_change(struct work_struct *work)
        if (err)
                goto phy_err;
 
-       spin_lock_bh(&phydev->lock);
+       mutex_lock(&phydev->lock);
        if ((PHY_RUNNING == phydev->state) || (PHY_NOLINK == phydev->state))
                phydev->state = PHY_CHANGELINK;
-       spin_unlock_bh(&phydev->lock);
+       mutex_unlock(&phydev->lock);
 
        atomic_dec(&phydev->irq_disable);
        enable_irq(phydev->irq);
@@ -735,7 +741,7 @@ phy_err:
  */
 void phy_stop(struct phy_device *phydev)
 {
-       spin_lock_bh(&phydev->lock);
+       mutex_lock(&phydev->lock);
 
        if (PHY_HALTED == phydev->state)
                goto out_unlock;
@@ -751,7 +757,7 @@ void phy_stop(struct phy_device *phydev)
        phydev->state = PHY_HALTED;
 
 out_unlock:
-       spin_unlock_bh(&phydev->lock);
+       mutex_unlock(&phydev->lock);
 
        /*
         * Cannot call flush_scheduled_work() here as desired because
@@ -773,7 +779,7 @@ out_unlock:
  */
 void phy_start(struct phy_device *phydev)
 {
-       spin_lock_bh(&phydev->lock);
+       mutex_lock(&phydev->lock);
 
        switch (phydev->state) {
                case PHY_STARTING:
@@ -787,19 +793,26 @@ void phy_start(struct phy_device *phydev)
                default:
                        break;
        }
-       spin_unlock_bh(&phydev->lock);
+       mutex_unlock(&phydev->lock);
 }
 EXPORT_SYMBOL(phy_stop);
 EXPORT_SYMBOL(phy_start);
 
-/* PHY timer which handles the state machine */
-static void phy_timer(unsigned long data)
+/**
+ * phy_state_machine - Handle the state machine
+ * @work: work_struct that describes the work to be done
+ *
+ * Description: Scheduled by the state_queue workqueue each time
+ *   phy_timer is triggered.
+ */
+static void phy_state_machine(struct work_struct *work)
 {
-       struct phy_device *phydev = (struct phy_device *)data;
+       struct phy_device *phydev =
+                       container_of(work, struct phy_device, state_queue);
        int needs_aneg = 0;
        int err = 0;
 
-       spin_lock_bh(&phydev->lock);
+       mutex_lock(&phydev->lock);
 
        if (phydev->adjust_state)
                phydev->adjust_state(phydev->attached_dev);
@@ -965,7 +978,7 @@ static void phy_timer(unsigned long data)
                        break;
        }
 
-       spin_unlock_bh(&phydev->lock);
+       mutex_unlock(&phydev->lock);
 
        if (needs_aneg)
                err = phy_start_aneg(phydev);
@@ -976,3 +989,14 @@ static void phy_timer(unsigned long data)
        mod_timer(&phydev->phy_timer, jiffies + PHY_STATE_TIME * HZ);
 }
 
+/* PHY timer which schedules the state machine work */
+static void phy_timer(unsigned long data)
+{
+       struct phy_device *phydev = (struct phy_device *)data;
+
+       /*
+        * PHY I/O operations can potentially sleep so we ensure that
+        * it's done from a process context
+        */
+       schedule_work(&phydev->state_queue);
+}
index 5b9e1751e1b414fc0e50a99b13e0770cf69811a0..f4c4fd85425f6807bf8258da78cb14bb7ee7bd35 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
-#include <linux/spinlock.h>
 #include <linux/mm.h>
 #include <linux/module.h>
 #include <linux/mii.h>
@@ -80,7 +79,7 @@ struct phy_device* phy_device_create(struct mii_bus *bus, int addr, int phy_id)
 
        dev->state = PHY_DOWN;
 
-       spin_lock_init(&dev->lock);
+       mutex_init(&dev->lock);
 
        return dev;
 }
@@ -656,7 +655,7 @@ static int phy_probe(struct device *dev)
        if (!(phydrv->flags & PHY_HAS_INTERRUPT))
                phydev->irq = PHY_POLL;
 
-       spin_lock_bh(&phydev->lock);
+       mutex_lock(&phydev->lock);
 
        /* Start out supporting everything. Eventually,
         * a controller will attach, and may modify one
@@ -670,7 +669,7 @@ static int phy_probe(struct device *dev)
        if (phydev->drv->probe)
                err = phydev->drv->probe(phydev);
 
-       spin_unlock_bh(&phydev->lock);
+       mutex_unlock(&phydev->lock);
 
        return err;
 
@@ -682,9 +681,9 @@ static int phy_remove(struct device *dev)
 
        phydev = to_phy_device(dev);
 
-       spin_lock_bh(&phydev->lock);
+       mutex_lock(&phydev->lock);
        phydev->state = PHY_DOWN;
-       spin_unlock_bh(&phydev->lock);
+       mutex_unlock(&phydev->lock);
 
        if (phydev->drv->remove)
                phydev->drv->remove(phydev);
diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c
new file mode 100644 (file)
index 0000000..a052a67
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * drivers/net/phy/realtek.c
+ *
+ * Driver for Realtek PHYs
+ *
+ * Author: Johnson Leung <r58129@freescale.com>
+ *
+ * Copyright (c) 2004 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ */
+#include <linux/phy.h>
+
+#define RTL821x_PHYSR          0x11
+#define RTL821x_PHYSR_DUPLEX   0x2000
+#define RTL821x_PHYSR_SPEED    0xc000
+#define RTL821x_INER           0x12
+#define RTL821x_INER_INIT      0x6400
+#define RTL821x_INSR           0x13
+
+MODULE_DESCRIPTION("Realtek PHY driver");
+MODULE_AUTHOR("Johnson Leung");
+MODULE_LICENSE("GPL");
+
+static int rtl821x_ack_interrupt(struct phy_device *phydev)
+{
+       int err;
+
+       err = phy_read(phydev, RTL821x_INSR);
+
+       return (err < 0) ? err : 0;
+}
+
+static int rtl821x_config_intr(struct phy_device *phydev)
+{
+       int err;
+
+       if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
+               err = phy_write(phydev, RTL821x_INER,
+                               RTL821x_INER_INIT);
+       else
+               err = phy_write(phydev, RTL821x_INER, 0);
+
+       return err;
+}
+
+/* RTL8211B */
+static struct phy_driver rtl821x_driver = {
+       .phy_id         = 0x001cc912,
+       .name           = "RTL821x Gigabit Ethernet",
+       .phy_id_mask    = 0x001fffff,
+       .features       = PHY_GBIT_FEATURES,
+       .flags          = PHY_HAS_INTERRUPT,
+       .config_aneg    = &genphy_config_aneg,
+       .read_status    = &genphy_read_status,
+       .ack_interrupt  = &rtl821x_ack_interrupt,
+       .config_intr    = &rtl821x_config_intr,
+       .driver         = { .owner = THIS_MODULE,},
+};
+
+static int __init realtek_init(void)
+{
+       int ret;
+
+       ret = phy_driver_register(&rtl821x_driver);
+
+       return ret;
+}
+
+static void __exit realtek_exit(void)
+{
+       phy_driver_unregister(&rtl821x_driver);
+}
+
+module_init(realtek_init);
+module_exit(realtek_exit);
index 5fab7d7b5d74a430dd9e72870ba347fa38d07f47..6179a0a2032c0ec50681d8f02bb5a693baf6b8d4 100644 (file)
@@ -8118,7 +8118,7 @@ static void initiate_new_session(struct lro *lro, u8 *l2h,
        lro->iph = ip;
        lro->tcph = tcp;
        lro->tcp_next_seq = tcp_pyld_len + ntohl(tcp->seq);
-       lro->tcp_ack = ntohl(tcp->ack_seq);
+       lro->tcp_ack = tcp->ack_seq;
        lro->sg_num = 1;
        lro->total_len = ntohs(ip->tot_len);
        lro->frags_len = 0;
@@ -8127,10 +8127,10 @@ static void initiate_new_session(struct lro *lro, u8 *l2h,
         * already been done.
         */
        if (tcp->doff == 8) {
-               u32 *ptr;
-               ptr = (u32 *)(tcp+1);
+               __be32 *ptr;
+               ptr = (__be32 *)(tcp+1);
                lro->saw_ts = 1;
-               lro->cur_tsval = *(ptr+1);
+               lro->cur_tsval = ntohl(*(ptr+1));
                lro->cur_tsecr = *(ptr+2);
        }
        lro->in_use = 1;
@@ -8156,7 +8156,7 @@ static void update_L3L4_header(struct s2io_nic *sp, struct lro *lro)
 
        /* Update tsecr field if this session has timestamps enabled */
        if (lro->saw_ts) {
-               u32 *ptr = (u32 *)(tcp + 1);
+               __be32 *ptr = (__be32 *)(tcp + 1);
                *(ptr+2) = lro->cur_tsecr;
        }
 
@@ -8181,10 +8181,10 @@ static void aggregate_new_rx(struct lro *lro, struct iphdr *ip,
        lro->window = tcp->window;
 
        if (lro->saw_ts) {
-               u32 *ptr;
+               __be32 *ptr;
                /* Update tsecr and tsval from this packet */
-               ptr = (u32 *) (tcp + 1);
-               lro->cur_tsval = *(ptr + 1);
+               ptr = (__be32 *)(tcp+1);
+               lro->cur_tsval = ntohl(*(ptr+1));
                lro->cur_tsecr = *(ptr + 2);
        }
 }
@@ -8235,11 +8235,11 @@ static int verify_l3_l4_lro_capable(struct lro *l_lro, struct iphdr *ip,
 
                /* Ensure timestamp value increases monotonically */
                if (l_lro)
-                       if (l_lro->cur_tsval > *((u32 *)(ptr+2)))
+                       if (l_lro->cur_tsval > ntohl(*((__be32 *)(ptr+2))))
                                return -1;
 
                /* timestamp echo reply should be non-zero */
-               if (*((u32 *)(ptr+6)) == 0)
+               if (*((__be32 *)(ptr+6)) == 0)
                        return -1;
        }
 
index 9f6016c6f135a1fc9c7336bf8fd0df4ebba98b76..64b88eb48287d2d583897af67889e6474beebaa6 100644 (file)
@@ -809,7 +809,7 @@ struct lro {
        int             in_use;
        __be16          window;
        u32             cur_tsval;
-       u32             cur_tsecr;
+       __be32          cur_tsecr;
        u8              saw_ts;
 };
 
index b570402f7feda2a06fc975a5aaf82e19b1f45432..2e9e88be7b33f59558a06a22f06fee363805755d 100644 (file)
@@ -326,7 +326,7 @@ static const struct {
        { "SiS 191 PCI Gigabit Ethernet adapter" },
 };
 
-static struct pci_device_id sis190_pci_tbl[] __devinitdata = {
+static struct pci_device_id sis190_pci_tbl[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_SI, 0x0190), 0, 0, 0 },
        { PCI_DEVICE(PCI_VENDOR_ID_SI, 0x0191), 0, 0, 1 },
        { 0, },
index 62b01328c496c4e3678bf8b5b7fe7e1950470895..889f987246104a7765930e2b953e4c0826d9e2e3 100644 (file)
@@ -598,7 +598,7 @@ static void ess_send_alc_req(struct s_smc *smc)
        req->cmd.sba_cmd = REQUEST_ALLOCATION ;
 
        /*
-        * set the parameter type and parameter lenght of all used
+        * set the parameter type and parameter length of all used
         * parameters
         */
 
index a45205da8033d6eb8aea4d56df39fe4375ffb99b..76dc8adc9441ea3f563d72b63491259d2ad3563f 100644 (file)
@@ -398,7 +398,7 @@ static void copy_tx_mac(struct s_smc *smc, u_long td, struct fddi_mac *mac,
 /* u_long td;           transmit descriptor */
 /* struct fddi_mac *mac; mac frame pointer */
 /* unsigned off;        start address within buffer memory */
-/* int len ;            lenght of the frame including the FC */
+/* int len ;            length of the frame including the FC */
 {
        int     i ;
        u_int   *p ;
index 8a430a36654705fdc5fba5be36b20d3342db5aa4..46e339315656b793315097cc722b1cf726b29791 100644 (file)
@@ -1185,7 +1185,7 @@ void process_receive(struct s_smc *smc)
 
                DB_RX("frame length = %d",len,0,4) ;
                /*
-                * check the frame_lenght and all error flags
+                * check the frame_length and all error flags
                 */
                if (rfsw & (RX_MSRABT|RX_FS_E|RX_FS_CRC|RX_FS_IMPL)){
                        if (rfsw & RD_S_MSRABT) {
index 626190eb91e7ba567ea3c35ef9d26dac2aaf9b7e..dc062367a1c8b515138b7023921d81e31eac82d4 100644 (file)
@@ -623,6 +623,7 @@ static void sky2_phy_power(struct sky2_hw *hw, unsigned port, int onoff)
        static const u32 phy_power[] = { PCI_Y2_PHY1_POWD, PCI_Y2_PHY2_POWD };
        static const u32 coma_mode[] = { PCI_Y2_PHY1_COMA, PCI_Y2_PHY2_COMA };
 
+       sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON);
        reg1 = sky2_pci_read32(hw, PCI_DEV_REG1);
        /* Turn on/off phy power saving */
        if (onoff)
@@ -634,7 +635,8 @@ static void sky2_phy_power(struct sky2_hw *hw, unsigned port, int onoff)
                reg1 |= coma_mode[port];
 
        sky2_pci_write32(hw, PCI_DEV_REG1, reg1);
-       reg1 = sky2_pci_read32(hw, PCI_DEV_REG1);
+       sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
+       sky2_pci_read32(hw, PCI_DEV_REG1);
 
        udelay(100);
 }
@@ -1422,6 +1424,7 @@ static int sky2_up(struct net_device *dev)
        imask |= portirq_msk[port];
        sky2_write32(hw, B0_IMSK, imask);
 
+       sky2_set_multicast(dev);
        return 0;
 
 err_out:
@@ -2436,6 +2439,7 @@ static void sky2_hw_intr(struct sky2_hw *hw)
        if (status & (Y2_IS_MST_ERR | Y2_IS_IRQ_STAT)) {
                u16 pci_err;
 
+               sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON);
                pci_err = sky2_pci_read16(hw, PCI_STATUS);
                if (net_ratelimit())
                        dev_err(&pdev->dev, "PCI hardware error (0x%x)\n",
@@ -2443,12 +2447,14 @@ static void sky2_hw_intr(struct sky2_hw *hw)
 
                sky2_pci_write16(hw, PCI_STATUS,
                                      pci_err | PCI_STATUS_ERROR_BITS);
+               sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
        }
 
        if (status & Y2_IS_PCI_EXP) {
                /* PCI-Express uncorrectable Error occurred */
                u32 err;
 
+               sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON);
                err = sky2_read32(hw, Y2_CFG_AER + PCI_ERR_UNCOR_STATUS);
                sky2_write32(hw, Y2_CFG_AER + PCI_ERR_UNCOR_STATUS,
                             0xfffffffful);
@@ -2456,6 +2462,7 @@ static void sky2_hw_intr(struct sky2_hw *hw)
                        dev_err(&pdev->dev, "PCI Express error (0x%x)\n", err);
 
                sky2_read32(hw, Y2_CFG_AER + PCI_ERR_UNCOR_STATUS);
+               sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
        }
 
        if (status & Y2_HWE_L1_MASK)
@@ -2831,6 +2838,7 @@ static void sky2_reset(struct sky2_hw *hw)
        }
 
        sky2_power_on(hw);
+       sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
 
        for (i = 0; i < hw->ports; i++) {
                sky2_write8(hw, SK_REG(i, GMAC_LINK_CTRL), GMLC_RST_SET);
@@ -3554,8 +3562,6 @@ static int sky2_set_ringparam(struct net_device *dev,
                err = sky2_up(dev);
                if (err)
                        dev_close(dev);
-               else
-                       sky2_set_multicast(dev);
        }
 
        return err;
@@ -4389,8 +4395,6 @@ static int sky2_resume(struct pci_dev *pdev)
                                dev_close(dev);
                                goto out;
                        }
-
-                       sky2_set_multicast(dev);
                }
        }
 
index fe3ac6f9ae89cd77d26328f50654ba95b180ddd9..0e4a88d16327914a42af9116cdbc8db42443dd27 100644 (file)
@@ -1075,7 +1075,7 @@ static const struct ethtool_ops bigmac_ethtool_ops = {
        .get_link               = bigmac_get_link,
 };
 
-static int __init bigmac_ether_init(struct sbus_dev *qec_sdev)
+static int __devinit bigmac_ether_init(struct sbus_dev *qec_sdev)
 {
        struct net_device *dev;
        static int version_printed;
index ff23c6489efd33033d4cfd3f287cdd343805f0a7..e811331d4608a86abc8514848cdacddf73b83123 100644 (file)
@@ -747,7 +747,7 @@ static inline void qec_init_once(struct sunqec *qecp, struct sbus_dev *qsdev)
                    qecp->gregs + GLOB_RSIZE);
 }
 
-static u8 __init qec_get_burst(struct device_node *dp)
+static u8 __devinit qec_get_burst(struct device_node *dp)
 {
        u8 bsizes, bsizes_more;
 
@@ -767,7 +767,7 @@ static u8 __init qec_get_burst(struct device_node *dp)
        return bsizes;
 }
 
-static struct sunqec * __init get_qec(struct sbus_dev *child_sdev)
+static struct sunqec * __devinit get_qec(struct sbus_dev *child_sdev)
 {
        struct sbus_dev *qec_sdev = child_sdev->parent;
        struct sunqec *qecp;
@@ -823,7 +823,7 @@ fail:
        return NULL;
 }
 
-static int __init qec_ether_init(struct sbus_dev *sdev)
+static int __devinit qec_ether_init(struct sbus_dev *sdev)
 {
        static unsigned version_printed;
        struct net_device *dev;
index 4a0035f7a842471df9e39e0dfd8bef3d896b24cc..6415ce15c2efef51721b0a50b181ee296f98ad28 100644 (file)
@@ -1130,7 +1130,7 @@ static struct vio_driver_ops vnet_vio_ops = {
        .handshake_complete     = vnet_handshake_complete,
 };
 
-static void print_version(void)
+static void __devinit print_version(void)
 {
        static int version_printed;
 
index 124cfd4fbcf4f7004941dadefff88345c9320a11..7a7de0469eae098412036df35e8b9b636e291622 100644 (file)
@@ -10,7 +10,7 @@
  *      - Madge Smart 16/4 PCI Mk2
  *
  *  Maintainer(s):
- *    AF       Adam Fritzler           mid@auk.cx
+ *    AF       Adam Fritzler
  *
  *  Modification History:
  *     30-Dec-99       AF      Split off from the tms380tr driver.
index 0ee6e4f085b157dedcb306337011c7043f016fc6..b0a473b89133b03199a6822de64cd37592418556 100644 (file)
@@ -2,7 +2,7 @@
  * abyss.h: Header for the abyss tms380tr module
  *
  * Authors:
- * - Adam Fritzler <mid@auk.cx>
+ * - Adam Fritzler
  */
 
 #ifndef __LINUX_MADGETR_H
index 5a4151362fc064034389861794e2cee6cc0e0ddb..c9c5a2b1ed9e9ea6a49d8e5f2af22e9799adb403 100644 (file)
@@ -11,7 +11,7 @@
  *     - Madge Smart 16/4 Ringnode MC32 (??)
  *
  *  Maintainer(s):
- *    AF       Adam Fritzler           mid@auk.cx
+ *    AF       Adam Fritzler
  *
  *  Modification History:
  *     16-Jan-00       AF      Created
index 2dd822203809053248721d79f93d65a869c7cfca..fe88e272c531c85020204516e0aeae60853938d9 100644 (file)
@@ -2,7 +2,7 @@
  * madgemc.h: Header for the madgemc tms380tr module
  *
  * Authors:
- * - Adam Fritzler <mid@auk.cx>
+ * - Adam Fritzler
  */
 
 #ifndef __LINUX_MADGEMC_H
index e7b4adc5c4e79d3ed3faee86b992669b895c56e3..433c994ea9d87e2daf5aa2504e42a8f4b791a8d3 100644 (file)
@@ -434,7 +434,7 @@ static int __devinit olympic_init(struct net_device *dev)
 
 }
 
-static int olympic_open(struct net_device *dev) 
+static int __devinit olympic_open(struct net_device *dev) 
 {
        struct olympic_private *olympic_priv=netdev_priv(dev);
        u8 __iomem *olympic_mmio=olympic_priv->olympic_mmio,*init_srb;
index ca6b65919b3d0bf00806b64349cef355a7edb919..00ea94513460d5e118b811a3496625b98ad4a9cb 100644 (file)
@@ -12,7 +12,7 @@
  *     - Proteon 1392, 1392+
  *
  *  Maintainer(s):
- *    AF        Adam Fritzler           mid@auk.cx
+ *    AF        Adam Fritzler
  *    JF       Jochen Friedrich        jochen@scram.de
  *
  *  Modification History:
index 32e8d5a9f958fa354067b98da188dbebe5a23b57..41b6999a0f33487719f56898a489c9748b975f7f 100644 (file)
@@ -13,7 +13,7 @@
  *     - SysKonnect TR4/16(+) ISA      (SK-4190)
  *
  *  Maintainer(s):
- *    AF        Adam Fritzler           mid@auk.cx
+ *    AF        Adam Fritzler
  *    JF       Jochen Friedrich        jochen@scram.de
  *
  *  Modification History:
index d5fa36d3651591d62b8f1fb3cb305500b187d551..d07c4523c847a1ceb3c4e98876c1cce025459b2c 100644 (file)
@@ -30,7 +30,7 @@
  *  Maintainer(s):
  *    JS       Jay Schulist            jschlst@samba.org
  *    CG       Christoph Goos          cgoos@syskonnect.de
- *    AF       Adam Fritzler           mid@auk.cx
+ *    AF       Adam Fritzler
  *    MLP       Mike Phillips           phillim@amtrak.com
  *    JF       Jochen Friedrich        jochen@scram.de
  *     
index 7daf74e31ccd58a2426c5c33512e93ecec2f2e7e..7af76d7088490f61b57af4adcf832c7b16a018f7 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Authors:
  * - Christoph Goos <cgoos@syskonnect.de>
- * - Adam Fritzler <mid@auk.cx>
+ * - Adam Fritzler
  */
 
 #ifndef __LINUX_TMS380TR_H
index 1c18f782f522225fb0467b8fcb460a4aa33afa98..5f0ee880cfff1f7fa4d7c5096265322f043bef39 100644 (file)
@@ -14,7 +14,7 @@
  *      - 3Com 3C339 Token Link Velocity
  *
  *  Maintainer(s):
- *    AF       Adam Fritzler           mid@auk.cx
+ *    AF       Adam Fritzler
  *
  *  Modification History:
  *     30-Dec-99       AF      Split off from the tms380tr driver.
index 46339f6bcd004b9ca6b443cad05df2c82742cf32..038c1ef94d2e72e7332a4e28a86cbd82be14788a 100644 (file)
@@ -529,9 +529,13 @@ static int tun_set_iff(struct file *file, struct ifreq *ifr)
 
        if (ifr->ifr_flags & IFF_NO_PI)
                tun->flags |= TUN_NO_PI;
+       else
+               tun->flags &= ~TUN_NO_PI;
 
        if (ifr->ifr_flags & IFF_ONE_QUEUE)
                tun->flags |= TUN_ONE_QUEUE;
+       else
+               tun->flags &= ~TUN_ONE_QUEUE;
 
        file->private_data = tun;
        tun->attached = 1;
index 4ffd8739f8b72aacaff9f0aa908b0b3cc00e135f..fba0811d2608824bfebd0535b37cc21d14dd9859 100644 (file)
@@ -2084,8 +2084,10 @@ static void ucc_geth_memclean(struct ucc_geth_private *ugeth)
        if (!ugeth)
                return;
 
-       if (ugeth->uccf)
+       if (ugeth->uccf) {
                ucc_fast_free(ugeth->uccf);
+               ugeth->uccf = NULL;
+       }
 
        if (ugeth->p_thread_data_tx) {
                qe_muram_free(ugeth->thread_dat_tx_offset);
@@ -2305,10 +2307,6 @@ static int ucc_struct_init(struct ucc_geth_private *ugeth)
        ug_info = ugeth->ug_info;
        uf_info = &ug_info->uf_info;
 
-       /* Create CQs for hash tables */
-       INIT_LIST_HEAD(&ugeth->group_hash_q);
-       INIT_LIST_HEAD(&ugeth->ind_hash_q);
-
        if (!((uf_info->bd_mem_part == MEM_PART_SYSTEM) ||
              (uf_info->bd_mem_part == MEM_PART_MURAM))) {
                if (netif_msg_probe(ugeth))
@@ -3668,6 +3666,23 @@ static irqreturn_t ucc_geth_irq_handler(int irq, void *info)
        return IRQ_HANDLED;
 }
 
+#ifdef CONFIG_NET_POLL_CONTROLLER
+/*
+ * Polling 'interrupt' - used by things like netconsole to send skbs
+ * without having to re-enable interrupts. It's not called while
+ * the interrupt routine is executing.
+ */
+static void ucc_netpoll(struct net_device *dev)
+{
+       struct ucc_geth_private *ugeth = netdev_priv(dev);
+       int irq = ugeth->ug_info->uf_info.irq;
+
+       disable_irq(irq);
+       ucc_geth_irq_handler(irq, dev);
+       enable_irq(irq);
+}
+#endif /* CONFIG_NET_POLL_CONTROLLER */
+
 /* Called when something needs to use the ethernet device */
 /* Returns 0 for success. */
 static int ucc_geth_open(struct net_device *dev)
@@ -3990,6 +4005,10 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma
        ugeth = netdev_priv(dev);
        spin_lock_init(&ugeth->lock);
 
+       /* Create CQs for hash tables */
+       INIT_LIST_HEAD(&ugeth->group_hash_q);
+       INIT_LIST_HEAD(&ugeth->ind_hash_q);
+
        dev_set_drvdata(device, dev);
 
        /* Set the dev->base_addr to the gfar reg region */
@@ -4006,6 +4025,9 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma
 #ifdef CONFIG_UGETH_NAPI
        netif_napi_add(dev, &ugeth->napi, ucc_geth_poll, UCC_GETH_DEV_WEIGHT);
 #endif                         /* CONFIG_UGETH_NAPI */
+#ifdef CONFIG_NET_POLL_CONTROLLER
+       dev->poll_controller = ucc_netpoll;
+#endif
        dev->stop = ucc_geth_close;
 //    dev->change_mtu = ucc_geth_change_mtu;
        dev->mtu = 1500;
@@ -4040,9 +4062,10 @@ static int ucc_geth_remove(struct of_device* ofdev)
        struct net_device *dev = dev_get_drvdata(device);
        struct ucc_geth_private *ugeth = netdev_priv(dev);
 
-       dev_set_drvdata(device, NULL);
-       ucc_geth_memclean(ugeth);
+       unregister_netdev(dev);
        free_netdev(dev);
+       ucc_geth_memclean(ugeth);
+       dev_set_drvdata(device, NULL);
 
        return 0;
 }
index 569028b2baf2d8930a21bca17b775c764f793c39..6f245cfb662419f3f173a65073d873f4195768db 100644 (file)
@@ -33,8 +33,7 @@
 #include <linux/mii.h>
 #include <linux/usb.h>
 #include <linux/crc32.h>
-
-#include "usbnet.h"
+#include <linux/usb/usbnet.h>
 
 #define DRIVER_VERSION "14-Jun-2006"
 static const char driver_name [] = "asix";
index a42acc3cc60983233b2a57d92512abcc9918fa60..a934428a5890ba26adf4df7e00588d57a08ef786 100644 (file)
@@ -31,8 +31,7 @@
 #include <linux/mii.h>
 #include <linux/usb.h>
 #include <linux/usb/cdc.h>
-
-#include "usbnet.h"
+#include <linux/usb/usbnet.h>
 
 
 #if defined(CONFIG_USB_NET_RNDIS_HOST) || defined(CONFIG_USB_NET_RNDIS_HOST_MODULE)
@@ -228,15 +227,16 @@ next_desc:
                buf += buf [0];
        }
 
-       /* Microsoft ActiveSync based RNDIS devices lack the CDC descriptors,
-        * so we'll hard-wire the interfaces and not check for descriptors.
+       /* Microsoft ActiveSync based and some regular RNDIS devices lack the
+        * CDC descriptors, so we'll hard-wire the interfaces and not check
+        * for descriptors.
         */
-       if (is_activesync(&intf->cur_altsetting->desc) && !info->u) {
+       if (rndis && !info->u) {
                info->control = usb_ifnum_to_if(dev->udev, 0);
                info->data = usb_ifnum_to_if(dev->udev, 1);
                if (!info->control || !info->data) {
                        dev_dbg(&intf->dev,
-                               "activesync: master #0/%p slave #1/%p\n",
+                               "rndis: master #0/%p slave #1/%p\n",
                                info->control,
                                info->data);
                        goto bad_desc;
@@ -316,7 +316,6 @@ void usbnet_cdc_unbind(struct usbnet *dev, struct usb_interface *intf)
 }
 EXPORT_SYMBOL_GPL(usbnet_cdc_unbind);
 
-\f
 /*-------------------------------------------------------------------------
  *
  * Communications Device Class, Ethernet Control model
index 943988ed01d8492f1787add1db757f4faf3af2a4..0ec7936cbe2139d3085d5388165f4b308c611b17 100644 (file)
@@ -26,8 +26,7 @@
 #include <linux/workqueue.h>
 #include <linux/mii.h>
 #include <linux/usb.h>
-
-#include "usbnet.h"
+#include <linux/usb/usbnet.h>
 
 
 /*
index 633a511d6cb671151aa7c62e8bbf796f828f09d5..4b131a6c6b70bfcd7d169f9110c7b7fb2c343341 100644 (file)
@@ -20,8 +20,7 @@
 #include <linux/mii.h>
 #include <linux/usb.h>
 #include <linux/crc32.h>
-
-#include "usbnet.h"
+#include <linux/usb/usbnet.h>
 
 /* datasheet:
  http://www.davicom.com.tw/big5/download/Data%20Sheet/DM9601-DS-P01-930914.pdf
index 031cf5ca4dbb1eddb846665e4606f290eec863fc..f7ccfad9384e60024bccb27ce03a8391089a52a5 100644 (file)
@@ -29,8 +29,7 @@
 #include <linux/workqueue.h>
 #include <linux/mii.h>
 #include <linux/usb.h>
-
-#include "usbnet.h"
+#include <linux/usb/usbnet.h>
 
 
 /*
index 5ea7411e13375812f13aa3cb6ccd3a81d50c47bb..c3d119f997f5d69e725b8c25346db8e9a6125989 100644 (file)
@@ -31,8 +31,7 @@
 #include <linux/module.h>
 #include <linux/netdevice.h>
 #include <linux/usb.h>
-
-#include "usbnet.h"
+#include <linux/usb/usbnet.h>
 
 /* requests */
 #define MCS7830_RD_BMREQ       (USB_DIR_IN  | USB_TYPE_VENDOR | \
index 19bf8dae70c9ddb3081fdec476b2757c4bc1000a..034e8a73ca6b487dc7ab32e02ba11d77d71ab72e 100644 (file)
 #include <linux/workqueue.h>
 #include <linux/mii.h>
 #include <linux/usb.h>
+#include <linux/usb/usbnet.h>
 
 #include <asm/unaligned.h>
 
-#include "usbnet.h"
-
 
 /*
  * Netchip 1080 driver ... http://www.netchip.com
index 45300939d185403e46bd7a73388c7c4e2e85398e..08555f8b15f41c7b86833a2ee7e3729ffdd3556f 100644 (file)
@@ -28,8 +28,7 @@
 #include <linux/workqueue.h>
 #include <linux/mii.h>
 #include <linux/usb.h>
-
-#include "usbnet.h"
+#include <linux/usb/usbnet.h>
 
 
 /*
index 1ebe3259be0d1dd937c9807249b3d657e8ef15a6..a61324757b179b04d67673d26c2484580d5a8676 100644 (file)
@@ -29,8 +29,8 @@
 #include <linux/mii.h>
 #include <linux/usb.h>
 #include <linux/usb/cdc.h>
-
-#include "usbnet.h"
+#include <linux/usb/usbnet.h>
+#include <linux/usb/rndis_host.h>
 
 
 /*
  * currently rare) "Ethernet Emulation Model" (EEM).
  */
 
-/*
- * CONTROL uses CDC "encapsulated commands" with funky notifications.
- *  - control-out:  SEND_ENCAPSULATED
- *  - interrupt-in:  RESPONSE_AVAILABLE
- *  - control-in:  GET_ENCAPSULATED
- *
- * We'll try to ignore the RESPONSE_AVAILABLE notifications.
- *
- * REVISIT some RNDIS implementations seem to have curious issues still
- * to be resolved.
- */
-struct rndis_msg_hdr {
-       __le32  msg_type;                       /* RNDIS_MSG_* */
-       __le32  msg_len;
-       // followed by data that varies between messages
-       __le32  request_id;
-       __le32  status;
-       // ... and more
-} __attribute__ ((packed));
-
-/* MS-Windows uses this strange size, but RNDIS spec says 1024 minimum */
-#define        CONTROL_BUFFER_SIZE             1025
-
-/* RNDIS defines an (absurdly huge) 10 second control timeout,
- * but ActiveSync seems to use a more usual 5 second timeout
- * (which matches the USB 2.0 spec).
- */
-#define        RNDIS_CONTROL_TIMEOUT_MS        (5 * 1000)
-
-
-#define ccpu2 __constant_cpu_to_le32
-
-#define RNDIS_MSG_COMPLETION   ccpu2(0x80000000)
-
-/* codes for "msg_type" field of rndis messages;
- * only the data channel uses packet messages (maybe batched);
- * everything else goes on the control channel.
- */
-#define RNDIS_MSG_PACKET       ccpu2(0x00000001)       /* 1-N packets */
-#define RNDIS_MSG_INIT         ccpu2(0x00000002)
-#define RNDIS_MSG_INIT_C       (RNDIS_MSG_INIT|RNDIS_MSG_COMPLETION)
-#define RNDIS_MSG_HALT         ccpu2(0x00000003)
-#define RNDIS_MSG_QUERY                ccpu2(0x00000004)
-#define RNDIS_MSG_QUERY_C      (RNDIS_MSG_QUERY|RNDIS_MSG_COMPLETION)
-#define RNDIS_MSG_SET          ccpu2(0x00000005)
-#define RNDIS_MSG_SET_C                (RNDIS_MSG_SET|RNDIS_MSG_COMPLETION)
-#define RNDIS_MSG_RESET                ccpu2(0x00000006)
-#define RNDIS_MSG_RESET_C      (RNDIS_MSG_RESET|RNDIS_MSG_COMPLETION)
-#define RNDIS_MSG_INDICATE     ccpu2(0x00000007)
-#define RNDIS_MSG_KEEPALIVE    ccpu2(0x00000008)
-#define RNDIS_MSG_KEEPALIVE_C  (RNDIS_MSG_KEEPALIVE|RNDIS_MSG_COMPLETION)
-
-/* codes for "status" field of completion messages */
-#define        RNDIS_STATUS_SUCCESS            ccpu2(0x00000000)
-#define        RNDIS_STATUS_FAILURE            ccpu2(0xc0000001)
-#define        RNDIS_STATUS_INVALID_DATA       ccpu2(0xc0010015)
-#define        RNDIS_STATUS_NOT_SUPPORTED      ccpu2(0xc00000bb)
-#define        RNDIS_STATUS_MEDIA_CONNECT      ccpu2(0x4001000b)
-#define        RNDIS_STATUS_MEDIA_DISCONNECT   ccpu2(0x4001000c)
-
-
-struct rndis_data_hdr {
-       __le32  msg_type;               /* RNDIS_MSG_PACKET */
-       __le32  msg_len;                // rndis_data_hdr + data_len + pad
-       __le32  data_offset;            // 36 -- right after header
-       __le32  data_len;               // ... real packet size
-
-       __le32  oob_data_offset;        // zero
-       __le32  oob_data_len;           // zero
-       __le32  num_oob;                // zero
-       __le32  packet_data_offset;     // zero
-
-       __le32  packet_data_len;        // zero
-       __le32  vc_handle;              // zero
-       __le32  reserved;               // zero
-} __attribute__ ((packed));
-
-struct rndis_init {            /* OUT */
-       // header and:
-       __le32  msg_type;                       /* RNDIS_MSG_INIT */
-       __le32  msg_len;                        // 24
-       __le32  request_id;
-       __le32  major_version;                  // of rndis (1.0)
-       __le32  minor_version;
-       __le32  max_transfer_size;
-} __attribute__ ((packed));
-
-struct rndis_init_c {          /* IN */
-       // header and:
-       __le32  msg_type;                       /* RNDIS_MSG_INIT_C */
-       __le32  msg_len;
-       __le32  request_id;
-       __le32  status;
-       __le32  major_version;                  // of rndis (1.0)
-       __le32  minor_version;
-       __le32  device_flags;
-       __le32  medium;                         // zero == 802.3
-       __le32  max_packets_per_message;
-       __le32  max_transfer_size;
-       __le32  packet_alignment;               // max 7; (1<<n) bytes
-       __le32  af_list_offset;                 // zero
-       __le32  af_list_size;                   // zero
-} __attribute__ ((packed));
-
-struct rndis_halt {            /* OUT (no reply) */
-       // header and:
-       __le32  msg_type;                       /* RNDIS_MSG_HALT */
-       __le32  msg_len;
-       __le32  request_id;
-} __attribute__ ((packed));
-
-struct rndis_query {           /* OUT */
-       // header and:
-       __le32  msg_type;                       /* RNDIS_MSG_QUERY */
-       __le32  msg_len;
-       __le32  request_id;
-       __le32  oid;
-       __le32  len;
-       __le32  offset;
-/*?*/  __le32  handle;                         // zero
-} __attribute__ ((packed));
-
-struct rndis_query_c {         /* IN */
-       // header and:
-       __le32  msg_type;                       /* RNDIS_MSG_QUERY_C */
-       __le32  msg_len;
-       __le32  request_id;
-       __le32  status;
-       __le32  len;
-       __le32  offset;
-} __attribute__ ((packed));
-
-struct rndis_set {             /* OUT */
-       // header and:
-       __le32  msg_type;                       /* RNDIS_MSG_SET */
-       __le32  msg_len;
-       __le32  request_id;
-       __le32  oid;
-       __le32  len;
-       __le32  offset;
-/*?*/  __le32  handle;                         // zero
-} __attribute__ ((packed));
-
-struct rndis_set_c {           /* IN */
-       // header and:
-       __le32  msg_type;                       /* RNDIS_MSG_SET_C */
-       __le32  msg_len;
-       __le32  request_id;
-       __le32  status;
-} __attribute__ ((packed));
-
-struct rndis_reset {           /* IN */
-       // header and:
-       __le32  msg_type;                       /* RNDIS_MSG_RESET */
-       __le32  msg_len;
-       __le32  reserved;
-} __attribute__ ((packed));
-
-struct rndis_reset_c {         /* OUT */
-       // header and:
-       __le32  msg_type;                       /* RNDIS_MSG_RESET_C */
-       __le32  msg_len;
-       __le32  status;
-       __le32  addressing_lost;
-} __attribute__ ((packed));
-
-struct rndis_indicate {                /* IN (unrequested) */
-       // header and:
-       __le32  msg_type;                       /* RNDIS_MSG_INDICATE */
-       __le32  msg_len;
-       __le32  status;
-       __le32  length;
-       __le32  offset;
-/**/   __le32  diag_status;
-       __le32  error_offset;
-/**/   __le32  message;
-} __attribute__ ((packed));
-
-struct rndis_keepalive {       /* OUT (optionally IN) */
-       // header and:
-       __le32  msg_type;                       /* RNDIS_MSG_KEEPALIVE */
-       __le32  msg_len;
-       __le32  request_id;
-} __attribute__ ((packed));
-
-struct rndis_keepalive_c {     /* IN (optionally OUT) */
-       // header and:
-       __le32  msg_type;                       /* RNDIS_MSG_KEEPALIVE_C */
-       __le32  msg_len;
-       __le32  request_id;
-       __le32  status;
-} __attribute__ ((packed));
-
-/* NOTE:  about 30 OIDs are "mandatory" for peripherals to support ... and
- * there are gobs more that may optionally be supported.  We'll avoid as much
- * of that mess as possible.
- */
-#define OID_802_3_PERMANENT_ADDRESS    ccpu2(0x01010101)
-#define OID_GEN_MAXIMUM_FRAME_SIZE     ccpu2(0x00010106)
-#define OID_GEN_CURRENT_PACKET_FILTER  ccpu2(0x0001010e)
-
 /*
  * RNDIS notifications from device: command completion; "reverse"
  * keepalives; etc
  */
-static void rndis_status(struct usbnet *dev, struct urb *urb)
+void rndis_status(struct usbnet *dev, struct urb *urb)
 {
        devdbg(dev, "rndis status urb, len %d stat %d",
                urb->actual_length, urb->status);
        // FIXME for keepalives, respond immediately (asynchronously)
        // if not an RNDIS status, do like cdc_status(dev,urb) does
 }
+EXPORT_SYMBOL_GPL(rndis_status);
 
 /*
  * RPC done RNDIS-style.  Caller guarantees:
@@ -278,7 +78,7 @@ static void rndis_status(struct usbnet *dev, struct urb *urb)
  * Call context is likely probe(), before interface name is known,
  * which is why we won't try to use it in the diagnostics.
  */
-static int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf)
+int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf)
 {
        struct cdc_state        *info = (void *) &dev->data;
        int                     master_ifnum;
@@ -347,10 +147,26 @@ static int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf)
                                        request_id, xid);
                                /* then likely retry */
                        } else switch (buf->msg_type) {
-                       case RNDIS_MSG_INDICATE: {      /* fault */
-                               // struct rndis_indicate *msg = (void *)buf;
-                               dev_info(&info->control->dev,
-                                       "rndis fault indication\n");
+                       case RNDIS_MSG_INDICATE: {      /* fault/event */
+                               struct rndis_indicate *msg = (void *)buf;
+                               int state = 0;
+
+                               switch (msg->status) {
+                               case RNDIS_STATUS_MEDIA_CONNECT:
+                                       state = 1;
+                               case RNDIS_STATUS_MEDIA_DISCONNECT:
+                                       dev_info(&info->control->dev,
+                                               "rndis media %sconnect\n",
+                                               !state?"dis":"");
+                                       if (dev->driver_info->link_change)
+                                               dev->driver_info->link_change(
+                                                       dev, state);
+                                       break;
+                               default:
+                                       dev_info(&info->control->dev,
+                                               "rndis indication: 0x%08x\n",
+                                               le32_to_cpu(msg->status));
+                               }
                                }
                                break;
                        case RNDIS_MSG_KEEPALIVE: {     /* ping */
@@ -387,6 +203,7 @@ static int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf)
        dev_dbg(&info->control->dev, "rndis response timeout\n");
        return -ETIMEDOUT;
 }
+EXPORT_SYMBOL_GPL(rndis_command);
 
 /*
  * rndis_query:
@@ -453,7 +270,8 @@ response_error:
        return -EDOM;
 }
 
-static int rndis_bind(struct usbnet *dev, struct usb_interface *intf)
+int
+generic_rndis_bind(struct usbnet *dev, struct usb_interface *intf, int flags)
 {
        int                     retval;
        struct net_device       *net = dev->net;
@@ -467,8 +285,9 @@ static int rndis_bind(struct usbnet *dev, struct usb_interface *intf)
                struct rndis_query_c    *get_c;
                struct rndis_set        *set;
                struct rndis_set_c      *set_c;
+               struct rndis_halt       *halt;
        } u;
-       u32                     tmp;
+       u32                     tmp, *phym;
        int                     reply_len;
        unsigned char           *bp;
 
@@ -517,7 +336,7 @@ static int rndis_bind(struct usbnet *dev, struct usb_interface *intf)
                                "dev can't take %u byte packets (max %u)\n",
                                dev->hard_mtu, tmp);
                        retval = -EINVAL;
-                       goto fail_and_release;
+                       goto halt_fail_and_release;
                }
                dev->hard_mtu = tmp;
                net->mtu = dev->hard_mtu - net->hard_header_len;
@@ -533,13 +352,43 @@ static int rndis_bind(struct usbnet *dev, struct usb_interface *intf)
                dev->hard_mtu, tmp, dev->rx_urb_size,
                1 << le32_to_cpu(u.init_c->packet_alignment));
 
+       /* module has some device initialization code needs to be done right
+        * after RNDIS_INIT */
+       if (dev->driver_info->early_init &&
+                       dev->driver_info->early_init(dev) != 0)
+               goto halt_fail_and_release;
+
+       /* Check physical medium */
+       reply_len = sizeof *phym;
+       retval = rndis_query(dev, intf, u.buf, OID_GEN_PHYSICAL_MEDIUM,
+                       0, (void **) &phym, &reply_len);
+       if (retval != 0)
+               /* OID is optional so don't fail here. */
+               *phym = RNDIS_PHYSICAL_MEDIUM_UNSPECIFIED;
+       if ((flags & FLAG_RNDIS_PHYM_WIRELESS) &&
+                       *phym != RNDIS_PHYSICAL_MEDIUM_WIRELESS_LAN) {
+               if (netif_msg_probe(dev))
+                       dev_dbg(&intf->dev, "driver requires wireless "
+                               "physical medium, but device is not.\n");
+               retval = -ENODEV;
+               goto halt_fail_and_release;
+       }
+       if ((flags & FLAG_RNDIS_PHYM_NOT_WIRELESS) &&
+                       *phym == RNDIS_PHYSICAL_MEDIUM_WIRELESS_LAN) {
+               if (netif_msg_probe(dev))
+                       dev_dbg(&intf->dev, "driver requires non-wireless "
+                               "physical medium, but device is wireless.\n");
+               retval = -ENODEV;
+               goto halt_fail_and_release;
+       }
+
        /* Get designated host ethernet address */
        reply_len = ETH_ALEN;
        retval = rndis_query(dev, intf, u.buf, OID_802_3_PERMANENT_ADDRESS,
                        48, (void **) &bp, &reply_len);
        if (unlikely(retval< 0)) {
                dev_err(&intf->dev, "rndis get ethaddr, %d\n", retval);
-               goto fail_and_release;
+               goto halt_fail_and_release;
        }
        memcpy(net->dev_addr, bp, ETH_ALEN);
 
@@ -550,12 +399,12 @@ static int rndis_bind(struct usbnet *dev, struct usb_interface *intf)
        u.set->oid = OID_GEN_CURRENT_PACKET_FILTER;
        u.set->len = ccpu2(4);
        u.set->offset = ccpu2((sizeof *u.set) - 8);
-       *(__le32 *)(u.buf + sizeof *u.set) = ccpu2(DEFAULT_FILTER);
+       *(__le32 *)(u.buf + sizeof *u.set) = RNDIS_DEFAULT_FILTER;
 
        retval = rndis_command(dev, u.header);
        if (unlikely(retval < 0)) {
                dev_err(&intf->dev, "rndis set packet filter, %d\n", retval);
-               goto fail_and_release;
+               goto halt_fail_and_release;
        }
 
        retval = 0;
@@ -563,6 +412,11 @@ static int rndis_bind(struct usbnet *dev, struct usb_interface *intf)
        kfree(u.buf);
        return retval;
 
+halt_fail_and_release:
+       memset(u.halt, 0, sizeof *u.halt);
+       u.halt->msg_type = RNDIS_MSG_HALT;
+       u.halt->msg_len = ccpu2(sizeof *u.halt);
+       (void) rndis_command(dev, (void *)u.halt);
 fail_and_release:
        usb_set_intfdata(info->data, NULL);
        usb_driver_release_interface(driver_of(intf), info->data);
@@ -571,13 +425,19 @@ fail:
        kfree(u.buf);
        return retval;
 }
+EXPORT_SYMBOL_GPL(generic_rndis_bind);
+
+static int rndis_bind(struct usbnet *dev, struct usb_interface *intf)
+{
+       return generic_rndis_bind(dev, intf, FLAG_RNDIS_PHYM_NOT_WIRELESS);
+}
 
-static void rndis_unbind(struct usbnet *dev, struct usb_interface *intf)
+void rndis_unbind(struct usbnet *dev, struct usb_interface *intf)
 {
        struct rndis_halt       *halt;
 
        /* try to clear any rndis state/activity (no i/o from stack!) */
-       halt = kzalloc(sizeof *halt, GFP_KERNEL);
+       halt = kzalloc(CONTROL_BUFFER_SIZE, GFP_KERNEL);
        if (halt) {
                halt->msg_type = RNDIS_MSG_HALT;
                halt->msg_len = ccpu2(sizeof *halt);
@@ -585,13 +445,14 @@ static void rndis_unbind(struct usbnet *dev, struct usb_interface *intf)
                kfree(halt);
        }
 
-       return usbnet_cdc_unbind(dev, intf);
+       usbnet_cdc_unbind(dev, intf);
 }
+EXPORT_SYMBOL_GPL(rndis_unbind);
 
 /*
  * DATA -- host must not write zlps
  */
-static int rndis_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
+int rndis_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
 {
        /* peripheral may have batched packets to us... */
        while (likely(skb->len)) {
@@ -633,8 +494,9 @@ static int rndis_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
        /* caller will usbnet_skb_return the remaining packet */
        return 1;
 }
+EXPORT_SYMBOL_GPL(rndis_rx_fixup);
 
-static struct sk_buff *
+struct sk_buff *
 rndis_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags)
 {
        struct rndis_data_hdr   *hdr;
@@ -679,6 +541,7 @@ fill:
        /* FIXME make the last packet always be short ... */
        return skb;
 }
+EXPORT_SYMBOL_GPL(rndis_tx_fixup);
 
 
 static const struct driver_info        rndis_info = {
index 33cbc306226c67a9a98019d34c4b7eb1ba52b0d5..7e1f00131f91160833e023f416ae2834afeb52cf 100644 (file)
@@ -926,7 +926,6 @@ static int rtl8150_probe(struct usb_interface *intf,
        netdev->set_multicast_list = rtl8150_set_multicast;
        netdev->set_mac_address = rtl8150_set_mac_address;
        netdev->get_stats = rtl8150_netdev_stats;
-       netdev->mtu = RTL8150_MTU;
        SET_ETHTOOL_OPS(netdev, &ops);
        dev->intr_interval = 100;       /* 100ms */
 
index 8ed1fc5cbc7025127ec289b494f433e6545f7ed3..8463efb9e0b119417b8199c78c53d6a0151ffe43 100644 (file)
@@ -41,8 +41,7 @@
 #include <linux/workqueue.h>
 #include <linux/mii.h>
 #include <linux/usb.h>
-
-#include "usbnet.h"
+#include <linux/usb/usbnet.h>
 
 #define DRIVER_VERSION         "22-Aug-2005"
 
@@ -1204,6 +1203,9 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
                if ((dev->driver_info->flags & FLAG_ETHER) != 0
                                && (net->dev_addr [0] & 0x02) == 0)
                        strcpy (net->name, "eth%d");
+               /* WLAN devices should always be named "wlan%d" */
+               if ((dev->driver_info->flags & FLAG_WLAN) != 0)
+                       strcpy(net->name, "wlan%d");
 
                /* maybe the remote can't receive an Ethernet MTU */
                if (net->mtu > (dev->hard_mtu - net->hard_header_len))
index 9f98e8ce487ab389694353ae31de484537087cad..e24f7b3ace4bd470fcfbf65dffc69bf2df20f383 100644 (file)
@@ -29,8 +29,7 @@
 #include <linux/crc32.h>
 #include <linux/usb.h>
 #include <linux/usb/cdc.h>
-
-#include "usbnet.h"
+#include <linux/usb/usbnet.h>
 
 
 /*
index 87c180b563d36dc6623c52df7a5fb2111e8155c1..7c851b1e6daa4ba99e4d107213fca4abb34c76b4 100644 (file)
@@ -606,7 +606,7 @@ static int rhine_napipoll(struct napi_struct *napi, int budget)
 }
 #endif
 
-static void rhine_hw_init(struct net_device *dev, long pioaddr)
+static void __devinit rhine_hw_init(struct net_device *dev, long pioaddr)
 {
        struct rhine_private *rp = netdev_priv(dev);
 
index 35cd65d6b9edcdad5080e31ba52cc56b77b6b777..8c9fb824cbd4015afe9685ba9b8bc20a0c4b13e8 100644 (file)
@@ -8,7 +8,6 @@
  * for 64bit hardware platforms.
  *
  * TODO
- *     Big-endian support
  *     rx_copybreak/alignment
  *     Scatter gather
  *     More testing
@@ -681,7 +680,7 @@ static void velocity_rx_reset(struct velocity_info *vptr)
         *      Init state, all RD entries belong to the NIC
         */
        for (i = 0; i < vptr->options.numrx; ++i)
-               vptr->rd_ring[i].rdesc0.owner = OWNED_BY_NIC;
+               vptr->rd_ring[i].rdesc0.len |= OWNED_BY_NIC;
 
        writew(vptr->options.numrx, &regs->RBRDU);
        writel(vptr->rd_pool_dma, &regs->RDBaseLo);
@@ -777,7 +776,7 @@ static void velocity_init_registers(struct velocity_info *vptr,
 
                vptr->int_mask = INT_MASK_DEF;
 
-               writel(cpu_to_le32(vptr->rd_pool_dma), &regs->RDBaseLo);
+               writel(vptr->rd_pool_dma, &regs->RDBaseLo);
                writew(vptr->options.numrx - 1, &regs->RDCSize);
                mac_rx_queue_run(regs);
                mac_rx_queue_wake(regs);
@@ -785,7 +784,7 @@ static void velocity_init_registers(struct velocity_info *vptr,
                writew(vptr->options.numtx - 1, &regs->TDCSize);
 
                for (i = 0; i < vptr->num_txq; i++) {
-                       writel(cpu_to_le32(vptr->td_pool_dma[i]), &(regs->TDBaseLo[i]));
+                       writel(vptr->td_pool_dma[i], &regs->TDBaseLo[i]);
                        mac_tx_queue_run(regs, i);
                }
 
@@ -1195,7 +1194,7 @@ static inline void velocity_give_many_rx_descs(struct velocity_info *vptr)
        dirty = vptr->rd_dirty - unusable;
        for (avail = vptr->rd_filled & 0xfffc; avail; avail--) {
                dirty = (dirty > 0) ? dirty - 1 : vptr->options.numrx - 1;
-               vptr->rd_ring[dirty].rdesc0.owner = OWNED_BY_NIC;
+               vptr->rd_ring[dirty].rdesc0.len |= OWNED_BY_NIC;
        }
 
        writew(vptr->rd_filled & 0xfffc, &regs->RBRDU);
@@ -1210,7 +1209,7 @@ static int velocity_rx_refill(struct velocity_info *vptr)
                struct rx_desc *rd = vptr->rd_ring + dirty;
 
                /* Fine for an all zero Rx desc at init time as well */
-               if (rd->rdesc0.owner == OWNED_BY_NIC)
+               if (rd->rdesc0.len & OWNED_BY_NIC)
                        break;
 
                if (!vptr->rd_info[dirty].skb) {
@@ -1413,7 +1412,7 @@ static int velocity_rx_srv(struct velocity_info *vptr, int status)
                if (!vptr->rd_info[rd_curr].skb)
                        break;
 
-               if (rd->rdesc0.owner == OWNED_BY_NIC)
+               if (rd->rdesc0.len & OWNED_BY_NIC)
                        break;
 
                rmb();
@@ -1421,7 +1420,7 @@ static int velocity_rx_srv(struct velocity_info *vptr, int status)
                /*
                 *      Don't drop CE or RL error frame although RXOK is off
                 */
-               if ((rd->rdesc0.RSR & RSR_RXOK) || (!(rd->rdesc0.RSR & RSR_RXOK) && (rd->rdesc0.RSR & (RSR_CE | RSR_RL)))) {
+               if (rd->rdesc0.RSR & (RSR_RXOK | RSR_CE | RSR_RL)) {
                        if (velocity_receive_frame(vptr, rd_curr) < 0)
                                stats->rx_dropped++;
                } else {
@@ -1433,7 +1432,7 @@ static int velocity_rx_srv(struct velocity_info *vptr, int status)
                        stats->rx_dropped++;
                }
 
-               rd->inten = 1;
+               rd->size |= RX_INTEN;
 
                vptr->dev->last_rx = jiffies;
 
@@ -1554,7 +1553,7 @@ static int velocity_receive_frame(struct velocity_info *vptr, int idx)
        struct net_device_stats *stats = &vptr->stats;
        struct velocity_rd_info *rd_info = &(vptr->rd_info[idx]);
        struct rx_desc *rd = &(vptr->rd_ring[idx]);
-       int pkt_len = rd->rdesc0.len;
+       int pkt_len = le16_to_cpu(rd->rdesc0.len) & 0x3fff;
        struct sk_buff *skb;
 
        if (rd->rdesc0.RSR & (RSR_STP | RSR_EDP)) {
@@ -1637,8 +1636,7 @@ static int velocity_alloc_rx_buf(struct velocity_info *vptr, int idx)
         */
 
        *((u32 *) & (rd->rdesc0)) = 0;
-       rd->len = cpu_to_le32(vptr->rx_buf_sz);
-       rd->inten = 1;
+       rd->size = cpu_to_le16(vptr->rx_buf_sz) | RX_INTEN;
        rd->pa_low = cpu_to_le32(rd_info->skb_dma);
        rd->pa_high = 0;
        return 0;
@@ -1674,7 +1672,7 @@ static int velocity_tx_srv(struct velocity_info *vptr, u32 status)
                        td = &(vptr->td_rings[qnum][idx]);
                        tdinfo = &(vptr->td_infos[qnum][idx]);
 
-                       if (td->tdesc0.owner == OWNED_BY_NIC)
+                       if (td->tdesc0.len & OWNED_BY_NIC)
                                break;
 
                        if ((works++ > 15))
@@ -1874,7 +1872,7 @@ static void velocity_free_tx_buf(struct velocity_info *vptr, struct velocity_td_
 
                for (i = 0; i < tdinfo->nskb_dma; i++) {
 #ifdef VELOCITY_ZERO_COPY_SUPPORT
-                       pci_unmap_single(vptr->pdev, tdinfo->skb_dma[i], td->tdesc1.len, PCI_DMA_TODEVICE);
+                       pci_unmap_single(vptr->pdev, tdinfo->skb_dma[i], le16_to_cpu(td->tdesc1.len), PCI_DMA_TODEVICE);
 #else
                        pci_unmap_single(vptr->pdev, tdinfo->skb_dma[i], skb->len, PCI_DMA_TODEVICE);
 #endif
@@ -2067,8 +2065,8 @@ static int velocity_xmit(struct sk_buff *skb, struct net_device *dev)
        struct velocity_td_info *tdinfo;
        unsigned long flags;
        int index;
-
        int pktlen = skb->len;
+       __le16 len = cpu_to_le16(pktlen);
 
 #ifdef VELOCITY_ZERO_COPY_SUPPORT
        if (skb_shinfo(skb)->nr_frags > 6 && __skb_linearize(skb)) {
@@ -2083,9 +2081,8 @@ static int velocity_xmit(struct sk_buff *skb, struct net_device *dev)
        td_ptr = &(vptr->td_rings[qnum][index]);
        tdinfo = &(vptr->td_infos[qnum][index]);
 
-       td_ptr->tdesc1.TCPLS = TCPLS_NORMAL;
        td_ptr->tdesc1.TCR = TCR0_TIC;
-       td_ptr->td_buf[0].queue = 0;
+       td_ptr->td_buf[0].size &= ~TD_QUEUE;
 
        /*
         *      Pad short frames.
@@ -2093,16 +2090,16 @@ static int velocity_xmit(struct sk_buff *skb, struct net_device *dev)
        if (pktlen < ETH_ZLEN) {
                /* Cannot occur until ZC support */
                pktlen = ETH_ZLEN;
+               len = cpu_to_le16(ETH_ZLEN);
                skb_copy_from_linear_data(skb, tdinfo->buf, skb->len);
                memset(tdinfo->buf + skb->len, 0, ETH_ZLEN - skb->len);
                tdinfo->skb = skb;
                tdinfo->skb_dma[0] = tdinfo->buf_dma;
-               td_ptr->tdesc0.pktsize = pktlen;
+               td_ptr->tdesc0.len = len;
                td_ptr->td_buf[0].pa_low = cpu_to_le32(tdinfo->skb_dma[0]);
                td_ptr->td_buf[0].pa_high = 0;
-               td_ptr->td_buf[0].bufsize = td_ptr->tdesc0.pktsize;
+               td_ptr->td_buf[0].size = len;   /* queue is 0 anyway */
                tdinfo->nskb_dma = 1;
-               td_ptr->tdesc1.CMDZ = 2;
        } else
 #ifdef VELOCITY_ZERO_COPY_SUPPORT
        if (skb_shinfo(skb)->nr_frags > 0) {
@@ -2111,36 +2108,35 @@ static int velocity_xmit(struct sk_buff *skb, struct net_device *dev)
                if (nfrags > 6) {
                        skb_copy_from_linear_data(skb, tdinfo->buf, skb->len);
                        tdinfo->skb_dma[0] = tdinfo->buf_dma;
-                       td_ptr->tdesc0.pktsize =
+                       td_ptr->tdesc0.len = len;
                        td_ptr->td_buf[0].pa_low = cpu_to_le32(tdinfo->skb_dma[0]);
                        td_ptr->td_buf[0].pa_high = 0;
-                       td_ptr->td_buf[0].bufsize = td_ptr->tdesc0.pktsize;
+                       td_ptr->td_buf[0].size = len;   /* queue is 0 anyway */
                        tdinfo->nskb_dma = 1;
-                       td_ptr->tdesc1.CMDZ = 2;
                } else {
                        int i = 0;
                        tdinfo->nskb_dma = 0;
-                       tdinfo->skb_dma[i] = pci_map_single(vptr->pdev, skb->data, skb->len - skb->data_len, PCI_DMA_TODEVICE);
+                       tdinfo->skb_dma[i] = pci_map_single(vptr->pdev, skb->data,
+                                               skb_headlen(skb), PCI_DMA_TODEVICE);
 
-                       td_ptr->tdesc0.pktsize = pktlen;
+                       td_ptr->tdesc0.len = len;
 
                        /* FIXME: support 48bit DMA later */
                        td_ptr->td_buf[i].pa_low = cpu_to_le32(tdinfo->skb_dma);
                        td_ptr->td_buf[i].pa_high = 0;
-                       td_ptr->td_buf[i].bufsize = skb->len->skb->data_len;
+                       td_ptr->td_buf[i].size = cpu_to_le16(skb_headlen(skb));
 
                        for (i = 0; i < nfrags; i++) {
                                skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
-                               void *addr = ((void *) page_address(frag->page + frag->page_offset));
+                               void *addr = (void *)page_address(frag->page) + frag->page_offset;
 
                                tdinfo->skb_dma[i + 1] = pci_map_single(vptr->pdev, addr, frag->size, PCI_DMA_TODEVICE);
 
                                td_ptr->td_buf[i + 1].pa_low = cpu_to_le32(tdinfo->skb_dma[i + 1]);
                                td_ptr->td_buf[i + 1].pa_high = 0;
-                               td_ptr->td_buf[i + 1].bufsize = frag->size;
+                               td_ptr->td_buf[i + 1].size = cpu_to_le16(frag->size);
                        }
                        tdinfo->nskb_dma = i - 1;
-                       td_ptr->tdesc1.CMDZ = i;
                }
 
        } else
@@ -2152,18 +2148,16 @@ static int velocity_xmit(struct sk_buff *skb, struct net_device *dev)
                 */
                tdinfo->skb = skb;
                tdinfo->skb_dma[0] = pci_map_single(vptr->pdev, skb->data, pktlen, PCI_DMA_TODEVICE);
-               td_ptr->tdesc0.pktsize = pktlen;
+               td_ptr->tdesc0.len = len;
                td_ptr->td_buf[0].pa_low = cpu_to_le32(tdinfo->skb_dma[0]);
                td_ptr->td_buf[0].pa_high = 0;
-               td_ptr->td_buf[0].bufsize = td_ptr->tdesc0.pktsize;
+               td_ptr->td_buf[0].size = len;
                tdinfo->nskb_dma = 1;
-               td_ptr->tdesc1.CMDZ = 2;
        }
+       td_ptr->tdesc1.cmd = TCPLS_NORMAL + (tdinfo->nskb_dma + 1) * 16;
 
        if (vptr->vlgrp && vlan_tx_tag_present(skb)) {
-               td_ptr->tdesc1.pqinf.VID = vlan_tx_tag_get(skb);
-               td_ptr->tdesc1.pqinf.priority = 0;
-               td_ptr->tdesc1.pqinf.CFI = 0;
+               td_ptr->tdesc1.vlan = cpu_to_le16(vlan_tx_tag_get(skb));
                td_ptr->tdesc1.TCR |= TCR0_VETAG;
        }
 
@@ -2185,7 +2179,7 @@ static int velocity_xmit(struct sk_buff *skb, struct net_device *dev)
 
                if (prev < 0)
                        prev = vptr->options.numtx - 1;
-               td_ptr->tdesc0.owner = OWNED_BY_NIC;
+               td_ptr->tdesc0.len |= OWNED_BY_NIC;
                vptr->td_used[qnum]++;
                vptr->td_curr[qnum] = (index + 1) % vptr->options.numtx;
 
@@ -2193,7 +2187,7 @@ static int velocity_xmit(struct sk_buff *skb, struct net_device *dev)
                        netif_stop_queue(dev);
 
                td_ptr = &(vptr->td_rings[qnum][prev]);
-               td_ptr->td_buf[0].queue = 1;
+               td_ptr->td_buf[0].size |= TD_QUEUE;
                mac_tx_queue_wake(vptr->mac_regs, qnum);
        }
        dev->trans_start = jiffies;
@@ -3410,7 +3404,7 @@ static int velocity_suspend(struct pci_dev *pdev, pm_message_t state)
                velocity_save_context(vptr, &vptr->context);
                velocity_shutdown(vptr);
                velocity_set_wol(vptr);
-               pci_enable_wake(pdev, 3, 1);
+               pci_enable_wake(pdev, PCI_D3hot, 1);
                pci_set_power_state(pdev, PCI_D3hot);
        } else {
                velocity_save_context(vptr, &vptr->context);
index aa9179623d9048957f50037cd0c7f7a285532342..7387be4f428d66aa1ea29324c718e498303b25d9 100644 (file)
  * Bits in the RSR0 register
  */
 
-#define RSR_DETAG          0x0080
-#define RSR_SNTAG          0x0040
-#define RSR_RXER           0x0020
-#define RSR_RL             0x0010
-#define RSR_CE             0x0008
-#define RSR_FAE            0x0004
-#define RSR_CRC            0x0002
-#define RSR_VIDM           0x0001
+#define RSR_DETAG      cpu_to_le16(0x0080)
+#define RSR_SNTAG      cpu_to_le16(0x0040)
+#define RSR_RXER       cpu_to_le16(0x0020)
+#define RSR_RL         cpu_to_le16(0x0010)
+#define RSR_CE         cpu_to_le16(0x0008)
+#define RSR_FAE                cpu_to_le16(0x0004)
+#define RSR_CRC                cpu_to_le16(0x0002)
+#define RSR_VIDM       cpu_to_le16(0x0001)
 
 /*
  * Bits in the RSR1 register
  */
 
-#define RSR_RXOK           0x8000      // rx OK
-#define RSR_PFT            0x4000      // Perfect filtering address match
-#define RSR_MAR            0x2000      // MAC accept multicast address packet
-#define RSR_BAR            0x1000      // MAC accept broadcast address packet
-#define RSR_PHY            0x0800      // MAC accept physical address packet
-#define RSR_VTAG           0x0400      // 802.1p/1q tagging packet indicator
-#define RSR_STP            0x0200      // start of packet
-#define RSR_EDP            0x0100      // end of packet
-
-/*
- * Bits in the RSR1 register
- */
-
-#define RSR1_RXOK           0x80       // rx OK
-#define RSR1_PFT            0x40       // Perfect filtering address match
-#define RSR1_MAR            0x20       // MAC accept multicast address packet
-#define RSR1_BAR            0x10       // MAC accept broadcast address packet
-#define RSR1_PHY            0x08       // MAC accept physical address packet
-#define RSR1_VTAG           0x04       // 802.1p/1q tagging packet indicator
-#define RSR1_STP            0x02       // start of packet
-#define RSR1_EDP            0x01       // end of packet
+#define RSR_RXOK       cpu_to_le16(0x8000) // rx OK
+#define RSR_PFT                cpu_to_le16(0x4000) // Perfect filtering address match
+#define RSR_MAR                cpu_to_le16(0x2000) // MAC accept multicast address packet
+#define RSR_BAR                cpu_to_le16(0x1000) // MAC accept broadcast address packet
+#define RSR_PHY                cpu_to_le16(0x0800) // MAC accept physical address packet
+#define RSR_VTAG       cpu_to_le16(0x0400) // 802.1p/1q tagging packet indicator
+#define RSR_STP                cpu_to_le16(0x0200) // start of packet
+#define RSR_EDP                cpu_to_le16(0x0100) // end of packet
 
 /*
  * Bits in the CSM register
  * Bits in the TSR0 register
  */
 
-#define TSR0_ABT            0x0080     // Tx abort because of excessive collision
-#define TSR0_OWT            0x0040     // Jumbo frame Tx abort
-#define TSR0_OWC            0x0020     // Out of window collision
-#define TSR0_COLS           0x0010     // experience collision in this transmit event
-#define TSR0_NCR3           0x0008     // collision retry counter[3]
-#define TSR0_NCR2           0x0004     // collision retry counter[2]
-#define TSR0_NCR1           0x0002     // collision retry counter[1]
-#define TSR0_NCR0           0x0001     // collision retry counter[0]
-#define TSR0_TERR           0x8000     //
-#define TSR0_FDX            0x4000     // current transaction is serviced by full duplex mode
-#define TSR0_GMII           0x2000     // current transaction is serviced by GMII mode
-#define TSR0_LNKFL          0x1000     // packet serviced during link down
-#define TSR0_SHDN           0x0400     // shutdown case
-#define TSR0_CRS            0x0200     // carrier sense lost
-#define TSR0_CDH            0x0100     // AQE test fail (CD heartbeat)
-
-/*
- * Bits in the TSR1 register
- */
-
-#define TSR1_TERR           0x80       //
-#define TSR1_FDX            0x40       // current transaction is serviced by full duplex mode
-#define TSR1_GMII           0x20       // current transaction is serviced by GMII mode
-#define TSR1_LNKFL          0x10       // packet serviced during link down
-#define TSR1_SHDN           0x04       // shutdown case
-#define TSR1_CRS            0x02       // carrier sense lost
-#define TSR1_CDH            0x01       // AQE test fail (CD heartbeat)
+#define TSR0_ABT       cpu_to_le16(0x0080) // Tx abort because of excessive collision
+#define TSR0_OWT       cpu_to_le16(0x0040) // Jumbo frame Tx abort
+#define TSR0_OWC       cpu_to_le16(0x0020) // Out of window collision
+#define TSR0_COLS      cpu_to_le16(0x0010) // experience collision in this transmit event
+#define TSR0_NCR3      cpu_to_le16(0x0008) // collision retry counter[3]
+#define TSR0_NCR2      cpu_to_le16(0x0004) // collision retry counter[2]
+#define TSR0_NCR1      cpu_to_le16(0x0002) // collision retry counter[1]
+#define TSR0_NCR0      cpu_to_le16(0x0001) // collision retry counter[0]
+#define TSR0_TERR      cpu_to_le16(0x8000) //
+#define TSR0_FDX       cpu_to_le16(0x4000) // current transaction is serviced by full duplex mode
+#define TSR0_GMII      cpu_to_le16(0x2000) // current transaction is serviced by GMII mode
+#define TSR0_LNKFL     cpu_to_le16(0x1000) // packet serviced during link down
+#define TSR0_SHDN      cpu_to_le16(0x0400) // shutdown case
+#define TSR0_CRS       cpu_to_le16(0x0200) // carrier sense lost
+#define TSR0_CDH       cpu_to_le16(0x0100) // AQE test fail (CD heartbeat)
 
 //
 // Bits in the TCR0 register
  */
 
 struct rdesc0 {
-       u16 RSR;                /* Receive status */
-       u16 len:14;             /* Received packet length */
-       u16 reserved:1;
-       u16 owner:1;            /* Who owns this buffer ? */
+       __le16 RSR;             /* Receive status */
+       __le16 len;             /* bits 0--13; bit 15 - owner */
 };
 
 struct rdesc1 {
-       u16 PQTAG;
+       __le16 PQTAG;
        u8 CSM;
        u8 IPKT;
 };
 
+enum {
+       RX_INTEN = __constant_cpu_to_le16(0x8000)
+};
+
 struct rx_desc {
        struct rdesc0 rdesc0;
        struct rdesc1 rdesc1;
-       u32 pa_low;             /* Low 32 bit PCI address */
-       u16 pa_high;            /* Next 16 bit PCI address (48 total) */
-       u16 len:15;             /* Frame size */
-       u16 inten:1;            /* Enable interrupt */
+       __le32 pa_low;          /* Low 32 bit PCI address */
+       __le16 pa_high;         /* Next 16 bit PCI address (48 total) */
+       __le16 size;            /* bits 0--14 - frame size, bit 15 - enable int. */
 } __attribute__ ((__packed__));
 
 /*
@@ -223,32 +199,24 @@ struct rx_desc {
  */
 
 struct tdesc0 {
-       u16 TSR;                /* Transmit status register */
-       u16 pktsize:14;         /* Size of frame */
-       u16 reserved:1;
-       u16 owner:1;            /* Who owns the buffer */
+       __le16 TSR;             /* Transmit status register */
+       __le16 len;             /* bits 0--13 - size of frame, bit 15 - owner */
 };
 
-struct pqinf {                 /* Priority queue info */
-       u16 VID:12;
-       u16 CFI:1;
-       u16 priority:3;
-} __attribute__ ((__packed__));
-
 struct tdesc1 {
-       struct pqinf pqinf;
+       __le16 vlan;
        u8 TCR;
-       u8 TCPLS:2;
-       u8 reserved:2;
-       u8 CMDZ:4;
+       u8 cmd;                 /* bits 0--1 - TCPLS, bits 4--7 - CMDZ */
 } __attribute__ ((__packed__));
 
+enum {
+       TD_QUEUE = __constant_cpu_to_le16(0x8000)
+};
+
 struct td_buf {
-       u32 pa_low;
-       u16 pa_high;
-       u16 bufsize:14;
-       u16 reserved:1;
-       u16 queue:1;
+       __le32 pa_low;
+       __le16 pa_high;
+       __le16 size;            /* bits 0--13 - size, bit 15 - queue */
 } __attribute__ ((__packed__));
 
 struct tx_desc {
@@ -276,7 +244,7 @@ struct velocity_td_info {
 
 enum  velocity_owner {
        OWNED_BY_HOST = 0,
-       OWNED_BY_NIC = 1
+       OWNED_BY_NIC = __constant_cpu_to_le16(0x8000)
 };
 
 
@@ -1012,45 +980,45 @@ struct mac_regs {
        volatile u8 RCR;
        volatile u8 TCR;
 
-       volatile u32 CR0Set;            /* 0x08 */
-       volatile u32 CR0Clr;            /* 0x0C */
+       volatile __le32 CR0Set;         /* 0x08 */
+       volatile __le32 CR0Clr;         /* 0x0C */
 
        volatile u8 MARCAM[8];          /* 0x10 */
 
-       volatile u32 DecBaseHi;         /* 0x18 */
-       volatile u16 DbfBaseHi;         /* 0x1C */
-       volatile u16 reserved_1E;
+       volatile __le32 DecBaseHi;      /* 0x18 */
+       volatile __le16 DbfBaseHi;      /* 0x1C */
+       volatile __le16 reserved_1E;
 
-       volatile u16 ISRCTL;            /* 0x20 */
+       volatile __le16 ISRCTL;         /* 0x20 */
        volatile u8 TXESR;
        volatile u8 RXESR;
 
-       volatile u32 ISR;               /* 0x24 */
-       volatile u32 IMR;
+       volatile __le32 ISR;            /* 0x24 */
+       volatile __le32 IMR;
 
-       volatile u32 TDStatusPort;      /* 0x2C */
+       volatile __le32 TDStatusPort;   /* 0x2C */
 
-       volatile u16 TDCSRSet;          /* 0x30 */
+       volatile __le16 TDCSRSet;       /* 0x30 */
        volatile u8 RDCSRSet;
        volatile u8 reserved_33;
-       volatile u16 TDCSRClr;
+       volatile __le16 TDCSRClr;
        volatile u8 RDCSRClr;
        volatile u8 reserved_37;
 
-       volatile u32 RDBaseLo;          /* 0x38 */
-       volatile u16 RDIdx;             /* 0x3C */
-       volatile u16 reserved_3E;
+       volatile __le32 RDBaseLo;       /* 0x38 */
+       volatile __le16 RDIdx;          /* 0x3C */
+       volatile __le16 reserved_3E;
 
-       volatile u32 TDBaseLo[4];       /* 0x40 */
+       volatile __le32 TDBaseLo[4];    /* 0x40 */
 
-       volatile u16 RDCSize;           /* 0x50 */
-       volatile u16 TDCSize;           /* 0x52 */
-       volatile u16 TDIdx[4];          /* 0x54 */
-       volatile u16 tx_pause_timer;    /* 0x5C */
-       volatile u16 RBRDU;             /* 0x5E */
+       volatile __le16 RDCSize;        /* 0x50 */
+       volatile __le16 TDCSize;        /* 0x52 */
+       volatile __le16 TDIdx[4];       /* 0x54 */
+       volatile __le16 tx_pause_timer; /* 0x5C */
+       volatile __le16 RBRDU;          /* 0x5E */
 
-       volatile u32 FIFOTest0;         /* 0x60 */
-       volatile u32 FIFOTest1;         /* 0x64 */
+       volatile __le32 FIFOTest0;      /* 0x60 */
+       volatile __le32 FIFOTest1;      /* 0x64 */
 
        volatile u8 CAMADDR;            /* 0x68 */
        volatile u8 CAMCR;              /* 0x69 */
@@ -1063,18 +1031,18 @@ struct mac_regs {
        volatile u8 PHYSR1;
        volatile u8 MIICR;
        volatile u8 MIIADR;
-       volatile u16 MIIDATA;
+       volatile __le16 MIIDATA;
 
-       volatile u16 SoftTimer0;        /* 0x74 */
-       volatile u16 SoftTimer1;
+       volatile __le16 SoftTimer0;     /* 0x74 */
+       volatile __le16 SoftTimer1;
 
        volatile u8 CFGA;               /* 0x78 */
        volatile u8 CFGB;
        volatile u8 CFGC;
        volatile u8 CFGD;
 
-       volatile u16 DCFG;              /* 0x7C */
-       volatile u16 MCFG;
+       volatile __le16 DCFG;           /* 0x7C */
+       volatile __le16 MCFG;
 
        volatile u8 TBIST;              /* 0x80 */
        volatile u8 RBIST;
@@ -1086,9 +1054,9 @@ struct mac_regs {
        volatile u8 rev_id;
        volatile u8 PORSTS;
 
-       volatile u32 MIBData;           /* 0x88 */
+       volatile __le32 MIBData;        /* 0x88 */
 
-       volatile u16 EEWrData;
+       volatile __le16 EEWrData;
 
        volatile u8 reserved_8E;
        volatile u8 BPMDWr;
@@ -1098,7 +1066,7 @@ struct mac_regs {
        volatile u8 EECHKSUM;           /* 0x92 */
        volatile u8 EECSR;
 
-       volatile u16 EERdData;          /* 0x94 */
+       volatile __le16 EERdData;       /* 0x94 */
        volatile u8 EADDR;
        volatile u8 EMBCMD;
 
@@ -1112,22 +1080,22 @@ struct mac_regs {
        volatile u8 DEBUG;
        volatile u8 CHIPGCR;
 
-       volatile u16 WOLCRSet;          /* 0xA0 */
+       volatile __le16 WOLCRSet;       /* 0xA0 */
        volatile u8 PWCFGSet;
        volatile u8 WOLCFGSet;
 
-       volatile u16 WOLCRClr;          /* 0xA4 */
+       volatile __le16 WOLCRClr;       /* 0xA4 */
        volatile u8 PWCFGCLR;
        volatile u8 WOLCFGClr;
 
-       volatile u16 WOLSRSet;          /* 0xA8 */
-       volatile u16 reserved_AA;
+       volatile __le16 WOLSRSet;       /* 0xA8 */
+       volatile __le16 reserved_AA;
 
-       volatile u16 WOLSRClr;          /* 0xAC */
-       volatile u16 reserved_AE;
+       volatile __le16 WOLSRClr;       /* 0xAC */
+       volatile __le16 reserved_AE;
 
-       volatile u16 PatternCRC[8];     /* 0xB0 */
-       volatile u32 ByteMask[4][4];    /* 0xC0 */
+       volatile __le16 PatternCRC[8];  /* 0xB0 */
+       volatile __le32 ByteMask[4][4]; /* 0xC0 */
 } __attribute__ ((__packed__));
 
 
@@ -1238,12 +1206,12 @@ typedef u8 MCAM_ADDR[ETH_ALEN];
 struct arp_packet {
        u8 dest_mac[ETH_ALEN];
        u8 src_mac[ETH_ALEN];
-       u16 type;
-       u16 ar_hrd;
-       u16 ar_pro;
+       __be16 type;
+       __be16 ar_hrd;
+       __be16 ar_pro;
        u8 ar_hln;
        u8 ar_pln;
-       u16 ar_op;
+       __be16 ar_op;
        u8 ar_sha[ETH_ALEN];
        u8 ar_sip[4];
        u8 ar_tha[ETH_ALEN];
@@ -1253,7 +1221,7 @@ struct arp_packet {
 struct _magic_packet {
        u8 dest_mac[6];
        u8 src_mac[6];
-       u16 type;
+       __be16 type;
        u8 MAC[16][6];
        u8 password[6];
 } __attribute__ ((__packed__));
index 5413dbf3d4ac25ab688bb1a965ccf981f230addc..e66de0c12fc10e1455e4137f8f68271ca44505b5 100644 (file)
 #include <linux/virtio_net.h>
 #include <linux/scatterlist.h>
 
+static int napi_weight = 128;
+module_param(napi_weight, int, 0444);
+
+static int csum = 1, gso = 1;
+module_param(csum, bool, 0444);
+module_param(gso, bool, 0444);
+
 /* FIXME: MTU in config. */
 #define MAX_PACKET_LEN (ETH_HLEN+ETH_DATA_LEN)
 
@@ -52,13 +59,14 @@ static inline void vnet_hdr_to_sg(struct scatterlist *sg, struct sk_buff *skb)
        sg_init_one(sg, skb_vnet_hdr(skb), sizeof(struct virtio_net_hdr));
 }
 
-static bool skb_xmit_done(struct virtqueue *rvq)
+static void skb_xmit_done(struct virtqueue *svq)
 {
-       struct virtnet_info *vi = rvq->vdev->priv;
+       struct virtnet_info *vi = svq->vdev->priv;
 
-       /* In case we were waiting for output buffers. */
+       /* Suppress further interrupts. */
+       svq->vq_ops->disable_cb(svq);
+       /* We were waiting for more output buffers. */
        netif_wake_queue(vi->dev);
-       return true;
 }
 
 static void receive_skb(struct net_device *dev, struct sk_buff *skb,
@@ -83,28 +91,16 @@ static void receive_skb(struct net_device *dev, struct sk_buff *skb,
 
        if (hdr->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) {
                pr_debug("Needs csum!\n");
-               skb->ip_summed = CHECKSUM_PARTIAL;
-               skb->csum_start = hdr->csum_start;
-               skb->csum_offset = hdr->csum_offset;
-               if (skb->csum_start > skb->len - 2
-                   || skb->csum_offset > skb->len - 2) {
-                       if (net_ratelimit())
-                               printk(KERN_WARNING "%s: csum=%u/%u len=%u\n",
-                                      dev->name, skb->csum_start,
-                                      skb->csum_offset, skb->len);
+               if (!skb_partial_csum_set(skb,hdr->csum_start,hdr->csum_offset))
                        goto frame_err;
-               }
        }
 
        if (hdr->gso_type != VIRTIO_NET_HDR_GSO_NONE) {
                pr_debug("GSO!\n");
-               switch (hdr->gso_type) {
+               switch (hdr->gso_type & ~VIRTIO_NET_HDR_GSO_ECN) {
                case VIRTIO_NET_HDR_GSO_TCPV4:
                        skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4;
                        break;
-               case VIRTIO_NET_HDR_GSO_TCPV4_ECN:
-                       skb_shinfo(skb)->gso_type = SKB_GSO_TCP_ECN;
-                       break;
                case VIRTIO_NET_HDR_GSO_UDP:
                        skb_shinfo(skb)->gso_type = SKB_GSO_UDP;
                        break;
@@ -118,6 +114,9 @@ static void receive_skb(struct net_device *dev, struct sk_buff *skb,
                        goto frame_err;
                }
 
+               if (hdr->gso_type & VIRTIO_NET_HDR_GSO_ECN)
+                       skb_shinfo(skb)->gso_type |= SKB_GSO_TCP_ECN;
+
                skb_shinfo(skb)->gso_size = hdr->gso_size;
                if (skb_shinfo(skb)->gso_size == 0) {
                        if (net_ratelimit())
@@ -170,12 +169,14 @@ static void try_fill_recv(struct virtnet_info *vi)
        vi->rvq->vq_ops->kick(vi->rvq);
 }
 
-static bool skb_recv_done(struct virtqueue *rvq)
+static void skb_recv_done(struct virtqueue *rvq)
 {
        struct virtnet_info *vi = rvq->vdev->priv;
-       netif_rx_schedule(vi->dev, &vi->napi);
-       /* Suppress further interrupts. */
-       return false;
+       /* Schedule NAPI, Suppress further interrupts if successful. */
+       if (netif_rx_schedule_prep(vi->dev, &vi->napi)) {
+               rvq->vq_ops->disable_cb(rvq);
+               __netif_rx_schedule(vi->dev, &vi->napi);
+       }
 }
 
 static int virtnet_poll(struct napi_struct *napi, int budget)
@@ -201,7 +202,7 @@ again:
        /* Out of packets? */
        if (received < budget) {
                netif_rx_complete(vi->dev, napi);
-               if (unlikely(!vi->rvq->vq_ops->restart(vi->rvq))
+               if (unlikely(!vi->rvq->vq_ops->enable_cb(vi->rvq))
                    && netif_rx_reschedule(vi->dev, napi))
                        goto again;
        }
@@ -236,8 +237,6 @@ static int start_xmit(struct sk_buff *skb, struct net_device *dev)
 
        pr_debug("%s: xmit %p %s\n", dev->name, skb, print_mac(mac, dest));
 
-       free_old_xmit_skbs(vi);
-
        /* Encode metadata header at front. */
        hdr = skb_vnet_hdr(skb);
        if (skb->ip_summed == CHECKSUM_PARTIAL) {
@@ -250,10 +249,9 @@ static int start_xmit(struct sk_buff *skb, struct net_device *dev)
        }
 
        if (skb_is_gso(skb)) {
+               hdr->hdr_len = skb_transport_header(skb) - skb->data;
                hdr->gso_size = skb_shinfo(skb)->gso_size;
-               if (skb_shinfo(skb)->gso_type & SKB_GSO_TCP_ECN)
-                       hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV4_ECN;
-               else if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4)
+               if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4)
                        hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV4;
                else if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6)
                        hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV6;
@@ -261,19 +259,34 @@ static int start_xmit(struct sk_buff *skb, struct net_device *dev)
                        hdr->gso_type = VIRTIO_NET_HDR_GSO_UDP;
                else
                        BUG();
+               if (skb_shinfo(skb)->gso_type & SKB_GSO_TCP_ECN)
+                       hdr->gso_type |= VIRTIO_NET_HDR_GSO_ECN;
        } else {
                hdr->gso_type = VIRTIO_NET_HDR_GSO_NONE;
-               hdr->gso_size = 0;
+               hdr->gso_size = hdr->hdr_len = 0;
        }
 
        vnet_hdr_to_sg(sg, skb);
        num = skb_to_sgvec(skb, sg+1, 0, skb->len) + 1;
        __skb_queue_head(&vi->send, skb);
+
+again:
+       /* Free up any pending old buffers before queueing new ones. */
+       free_old_xmit_skbs(vi);
        err = vi->svq->vq_ops->add_buf(vi->svq, sg, num, 0, skb);
        if (err) {
                pr_debug("%s: virtio not prepared to send\n", dev->name);
-               skb_unlink(skb, &vi->send);
                netif_stop_queue(dev);
+
+               /* Activate callback for using skbs: if this fails it
+                * means some were used in the meantime. */
+               if (unlikely(!vi->svq->vq_ops->enable_cb(vi->svq))) {
+                       printk("Unlikely: restart svq failed\n");
+                       netif_start_queue(dev);
+                       goto again;
+               }
+               __skb_unlink(skb, &vi->send);
+
                return NETDEV_TX_BUSY;
        }
        vi->svq->vq_ops->kick(vi->svq);
@@ -285,45 +298,31 @@ static int virtnet_open(struct net_device *dev)
 {
        struct virtnet_info *vi = netdev_priv(dev);
 
-       try_fill_recv(vi);
+       napi_enable(&vi->napi);
 
-       /* If we didn't even get one input buffer, we're useless. */
-       if (vi->num == 0)
-               return -ENOMEM;
+       /* If all buffers were filled by other side before we napi_enabled, we
+        * won't get another interrupt, so process any outstanding packets
+        * now.  virtnet_poll wants re-enable the queue, so we disable here. */
+       vi->rvq->vq_ops->disable_cb(vi->rvq);
+       netif_rx_schedule(vi->dev, &vi->napi);
 
-       napi_enable(&vi->napi);
        return 0;
 }
 
 static int virtnet_close(struct net_device *dev)
 {
        struct virtnet_info *vi = netdev_priv(dev);
-       struct sk_buff *skb;
 
        napi_disable(&vi->napi);
 
-       /* networking core has neutered skb_xmit_done/skb_recv_done, so don't
-        * worry about races vs. get(). */
-       vi->rvq->vq_ops->shutdown(vi->rvq);
-       while ((skb = __skb_dequeue(&vi->recv)) != NULL) {
-               kfree_skb(skb);
-               vi->num--;
-       }
-       vi->svq->vq_ops->shutdown(vi->svq);
-       while ((skb = __skb_dequeue(&vi->send)) != NULL)
-               kfree_skb(skb);
-
-       BUG_ON(vi->num != 0);
        return 0;
 }
 
 static int virtnet_probe(struct virtio_device *vdev)
 {
        int err;
-       unsigned int len;
        struct net_device *dev;
        struct virtnet_info *vi;
-       void *token;
 
        /* Allocate ourselves a network device with room for our info */
        dev = alloc_etherdev(sizeof(struct virtnet_info));
@@ -331,7 +330,6 @@ static int virtnet_probe(struct virtio_device *vdev)
                return -ENOMEM;
 
        /* Set up network device as normal. */
-       ether_setup(dev);
        dev->open = virtnet_open;
        dev->stop = virtnet_close;
        dev->hard_start_xmit = start_xmit;
@@ -339,42 +337,37 @@ static int virtnet_probe(struct virtio_device *vdev)
        SET_NETDEV_DEV(dev, &vdev->dev);
 
        /* Do we support "hardware" checksums? */
-       token = vdev->config->find(vdev, VIRTIO_CONFIG_NET_F, &len);
-       if (virtio_use_bit(vdev, token, len, VIRTIO_NET_F_NO_CSUM)) {
+       if (csum && vdev->config->feature(vdev, VIRTIO_NET_F_CSUM)) {
                /* This opens up the world of extra features. */
                dev->features |= NETIF_F_HW_CSUM|NETIF_F_SG|NETIF_F_FRAGLIST;
-               if (virtio_use_bit(vdev, token, len, VIRTIO_NET_F_TSO4))
-                       dev->features |= NETIF_F_TSO;
-               if (virtio_use_bit(vdev, token, len, VIRTIO_NET_F_UFO))
-                       dev->features |= NETIF_F_UFO;
-               if (virtio_use_bit(vdev, token, len, VIRTIO_NET_F_TSO4_ECN))
-                       dev->features |= NETIF_F_TSO_ECN;
-               if (virtio_use_bit(vdev, token, len, VIRTIO_NET_F_TSO6))
-                       dev->features |= NETIF_F_TSO6;
+               if (gso && vdev->config->feature(vdev, VIRTIO_NET_F_GSO)) {
+                       dev->features |= NETIF_F_TSO | NETIF_F_UFO
+                               | NETIF_F_TSO_ECN | NETIF_F_TSO6;
+               }
        }
 
        /* Configuration may specify what MAC to use.  Otherwise random. */
-       token = vdev->config->find(vdev, VIRTIO_CONFIG_NET_MAC_F, &len);
-       if (token) {
-               dev->addr_len = len;
-               vdev->config->get(vdev, token, dev->dev_addr, len);
+       if (vdev->config->feature(vdev, VIRTIO_NET_F_MAC)) {
+               vdev->config->get(vdev,
+                                 offsetof(struct virtio_net_config, mac),
+                                 dev->dev_addr, dev->addr_len);
        } else
                random_ether_addr(dev->dev_addr);
 
        /* Set up our device-specific information */
        vi = netdev_priv(dev);
-       netif_napi_add(dev, &vi->napi, virtnet_poll, 16);
+       netif_napi_add(dev, &vi->napi, virtnet_poll, napi_weight);
        vi->dev = dev;
        vi->vdev = vdev;
 
        /* We expect two virtqueues, receive then send. */
-       vi->rvq = vdev->config->find_vq(vdev, skb_recv_done);
+       vi->rvq = vdev->config->find_vq(vdev, 0, skb_recv_done);
        if (IS_ERR(vi->rvq)) {
                err = PTR_ERR(vi->rvq);
                goto free;
        }
 
-       vi->svq = vdev->config->find_vq(vdev, skb_xmit_done);
+       vi->svq = vdev->config->find_vq(vdev, 1, skb_xmit_done);
        if (IS_ERR(vi->svq)) {
                err = PTR_ERR(vi->svq);
                goto free_recv;
@@ -389,10 +382,22 @@ static int virtnet_probe(struct virtio_device *vdev)
                pr_debug("virtio_net: registering device failed\n");
                goto free_send;
        }
+
+       /* Last of all, set up some receive buffers. */
+       try_fill_recv(vi);
+
+       /* If we didn't even get one input buffer, we're useless. */
+       if (vi->num == 0) {
+               err = -ENOMEM;
+               goto unregister;
+       }
+
        pr_debug("virtnet: registered device %s\n", dev->name);
        vdev->priv = vi;
        return 0;
 
+unregister:
+       unregister_netdev(dev);
 free_send:
        vdev->config->del_vq(vi->svq);
 free_recv:
@@ -405,6 +410,20 @@ free:
 static void virtnet_remove(struct virtio_device *vdev)
 {
        struct virtnet_info *vi = vdev->priv;
+       struct sk_buff *skb;
+
+       /* Stop all the virtqueues. */
+       vdev->config->reset(vdev);
+
+       /* Free our skbs in send and recv queues, if any. */
+       while ((skb = __skb_dequeue(&vi->recv)) != NULL) {
+               kfree_skb(skb);
+               vi->num--;
+       }
+       while ((skb = __skb_dequeue(&vi->send)) != NULL)
+               kfree_skb(skb);
+
+       BUG_ON(vi->num != 0);
 
        vdev->config->del_vq(vi->svq);
        vdev->config->del_vq(vi->rvq);
index d347d59db656057cffdc3c27260d8866188374be..d14e6678deed2456be4df506a4094aaf4be20f68 100644 (file)
@@ -322,7 +322,7 @@ static int cycx_data_boot(void __iomem *addr, u8 *code, u32 len)
        void __iomem *pt_boot_cmd = addr + CMD_OFFSET;
        u32 i;
 
-       /* boot buffer lenght */
+       /* boot buffer length */
        writew(CFM_LOAD_BUFSZ, pt_boot_cmd + sizeof(u16));
        writew(GEN_DEFPAR, pt_boot_cmd);
 
@@ -353,7 +353,7 @@ static int cycx_code_boot(void __iomem *addr, u8 *code, u32 len)
        void __iomem *pt_boot_cmd = addr + CMD_OFFSET;
        u32 i;
 
-       /* boot buffer lenght */
+       /* boot buffer length */
        writew(CFM_LOAD_BUFSZ, pt_boot_cmd + sizeof(u16));
        writew(GEN_DEFPAR, pt_boot_cmd);
 
index f372960904b21a6d7364a8e5e70785878290341e..714a6ca30ad2abe7314768f1ab9031da6b4b04c6 100644 (file)
@@ -545,6 +545,34 @@ config USB_ZD1201
          To compile this driver as a module, choose M here: the
          module will be called zd1201.
 
+config USB_NET_RNDIS_WLAN
+       tristate "Wireless RNDIS USB support"
+       depends on USB && WLAN_80211 && EXPERIMENTAL
+       select USB_USBNET
+       select USB_NET_CDCETHER
+       select USB_NET_RNDIS_HOST
+       select WIRELESS_EXT
+       ---help---
+         This is a driver for wireless RNDIS devices.
+         These are USB based adapters found in devices such as:
+
+         Buffalo WLI-U2-KG125S
+         U.S. Robotics USR5421
+         Belkin F5D7051
+         Linksys WUSB54GSv2
+         Linksys WUSB54GSC
+         Asus WL169gE
+         Eminent EM4045
+         BT Voyager 1055
+         Linksys WUSB54GSv1
+         U.S. Robotics USR5420
+         BUFFALO WLI-USB-G54
+
+         All of these devices are based on Broadcom 4320 chip which is the
+         only wireless RNDIS chip known to date.
+
+         If you choose to build a module, it'll be called rndis_wlan.
+
 config RTL8180
        tristate "Realtek 8180/8185 PCI support"
        depends on MAC80211 && PCI && WLAN_80211 && EXPERIMENTAL
index 6af7b158624ec07797998e93e2ce25653e6aad64..091dfe2e574e7104e52d4e7f15fdedca86b722f1 100644 (file)
@@ -44,6 +44,8 @@ obj-$(CONFIG_ZD1211RW)                += zd1211rw/
 obj-$(CONFIG_PCMCIA_RAYCS)     += ray_cs.o
 obj-$(CONFIG_PCMCIA_WL3501)    += wl3501_cs.o
 
+obj-$(CONFIG_USB_NET_RNDIS_WLAN)       += rndis_wlan.o
+
 obj-$(CONFIG_USB_ZD1201)       += zd1201.o
 obj-$(CONFIG_LIBERTAS)         += libertas/
 
index 72bcf321d1ce26dbd6c4b741bd9115919d0c361d..ddc87149fe31d098730a27eee9b7df871f5d18f9 100644 (file)
@@ -153,7 +153,7 @@ static int          ath5k_pci_resume(struct pci_dev *pdev);
 #define ath5k_pci_resume NULL
 #endif /* CONFIG_PM */
 
-static struct pci_driver ath5k_pci_drv_id = {
+static struct pci_driver ath5k_pci_driver = {
        .name           = "ath5k_pci",
        .id_table       = ath5k_pci_id_table,
        .probe          = ath5k_pci_probe,
@@ -329,7 +329,7 @@ init_ath5k_pci(void)
 
        ath5k_debug_init();
 
-       ret = pci_register_driver(&ath5k_pci_drv_id);
+       ret = pci_register_driver(&ath5k_pci_driver);
        if (ret) {
                printk(KERN_ERR "ath5k_pci: can't register pci driver\n");
                return ret;
@@ -341,7 +341,7 @@ init_ath5k_pci(void)
 static void __exit
 exit_ath5k_pci(void)
 {
-       pci_unregister_driver(&ath5k_pci_drv_id);
+       pci_unregister_driver(&ath5k_pci_driver);
 
        ath5k_debug_finish();
 }
@@ -1980,7 +1980,7 @@ ath5k_beacon_send(struct ath5k_softc *sc)
        struct ath5k_buf *bf = sc->bbuf;
        struct ath5k_hw *ah = sc->ah;
 
-       ATH5K_DBG(sc, ATH5K_DEBUG_BEACON_PROC, "in beacon_send\n");
+       ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON, "in beacon_send\n");
 
        if (unlikely(bf->skb == NULL || sc->opmode == IEEE80211_IF_TYPE_STA ||
                        sc->opmode == IEEE80211_IF_TYPE_MNTR)) {
@@ -1996,10 +1996,10 @@ ath5k_beacon_send(struct ath5k_softc *sc)
         */
        if (unlikely(ath5k_hw_num_tx_pending(ah, sc->bhalq) != 0)) {
                sc->bmisscount++;
-               ATH5K_DBG(sc, ATH5K_DEBUG_BEACON_PROC,
+               ATH5K_DBG(sc, ATH5K_DEBUG_BEACON,
                        "missed %u consecutive beacons\n", sc->bmisscount);
                if (sc->bmisscount > 3) {               /* NB: 3 is a guess */
-                       ATH5K_DBG(sc, ATH5K_DEBUG_BEACON_PROC,
+                       ATH5K_DBG(sc, ATH5K_DEBUG_BEACON,
                                "stuck beacon time (%u missed)\n",
                                sc->bmisscount);
                        tasklet_schedule(&sc->restq);
@@ -2007,7 +2007,7 @@ ath5k_beacon_send(struct ath5k_softc *sc)
                return;
        }
        if (unlikely(sc->bmisscount != 0)) {
-               ATH5K_DBG(sc, ATH5K_DEBUG_BEACON_PROC,
+               ATH5K_DBG(sc, ATH5K_DEBUG_BEACON,
                        "resume beacon xmit after %u misses\n",
                        sc->bmisscount);
                sc->bmisscount = 0;
@@ -2027,7 +2027,7 @@ ath5k_beacon_send(struct ath5k_softc *sc)
 
        ath5k_hw_put_tx_buf(ah, sc->bhalq, bf->daddr);
        ath5k_hw_tx_start(ah, sc->bhalq);
-       ATH5K_DBG(sc, ATH5K_DEBUG_BEACON_PROC, "TXDP[%u] = %llx (%p)\n",
+       ATH5K_DBG(sc, ATH5K_DEBUG_BEACON, "TXDP[%u] = %llx (%p)\n",
                sc->bhalq, (unsigned long long)bf->daddr, bf->desc);
 
        sc->bsent++;
index 4ba649e20269fcd357457555e0b5de90f057ffd5..bb581ef6d1efa51ae0bbca075498fabea129685f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007 Bruno Randolf <bruno@thinktube.com>
+ * Copyright (c) 2007-2008 Bruno Randolf <bruno@thinktube.com>
  *
  *  This file is free software: you may copy, redistribute and/or modify it
  *  under the terms of the GNU General Public License as published by the
@@ -200,7 +200,7 @@ static ssize_t read_file_tsf(struct file *file, char __user *user_buf,
 {
        struct ath5k_softc *sc = file->private_data;
        char buf[100];
-       snprintf(buf, 100, "0x%016llx\n", ath5k_hw_get_tsf64(sc->ah));
+       snprintf(buf, sizeof(buf), "0x%016llx\n", ath5k_hw_get_tsf64(sc->ah));
        return simple_read_from_buffer(user_buf, count, ppos, buf, 19);
 }
 
@@ -209,7 +209,12 @@ static ssize_t write_file_tsf(struct file *file,
                                 size_t count, loff_t *ppos)
 {
        struct ath5k_softc *sc = file->private_data;
-       if (strncmp(userbuf, "reset", 5) == 0) {
+       char buf[20];
+
+       if (copy_from_user(buf, userbuf, min(count, sizeof(buf))))
+               return -EFAULT;
+
+       if (strncmp(buf, "reset", 5) == 0) {
                ath5k_hw_reset_tsf(sc->ah);
                printk(KERN_INFO "debugfs reset TSF\n");
        }
@@ -231,8 +236,8 @@ static ssize_t read_file_beacon(struct file *file, char __user *user_buf,
 {
        struct ath5k_softc *sc = file->private_data;
        struct ath5k_hw *ah = sc->ah;
-       char buf[1000];
-       int len = 0;
+       char buf[500];
+       unsigned int len = 0;
        unsigned int v;
        u64 tsf;
 
@@ -277,11 +282,15 @@ static ssize_t write_file_beacon(struct file *file,
 {
        struct ath5k_softc *sc = file->private_data;
        struct ath5k_hw *ah = sc->ah;
+       char buf[20];
+
+       if (copy_from_user(buf, userbuf, min(count, sizeof(buf))))
+               return -EFAULT;
 
-       if (strncmp(userbuf, "disable", 7) == 0) {
+       if (strncmp(buf, "disable", 7) == 0) {
                AR5K_REG_DISABLE_BITS(ah, AR5K_BEACON, AR5K_BEACON_ENABLE);
                printk(KERN_INFO "debugfs disable beacons\n");
-       } else if (strncmp(userbuf, "enable", 6) == 0) {
+       } else if (strncmp(buf, "enable", 6) == 0) {
                AR5K_REG_ENABLE_BITS(ah, AR5K_BEACON, AR5K_BEACON_ENABLE);
                printk(KERN_INFO "debugfs enable beacons\n");
        }
@@ -314,6 +323,82 @@ static const struct file_operations fops_reset = {
 };
 
 
+/* debugfs: debug level */
+
+static struct {
+       enum ath5k_debug_level level;
+       const char *name;
+       const char *desc;
+} dbg_info[] = {
+       { ATH5K_DEBUG_RESET,    "reset",        "reset and initialization" },
+       { ATH5K_DEBUG_INTR,     "intr",         "interrupt handling" },
+       { ATH5K_DEBUG_MODE,     "mode",         "mode init/setup" },
+       { ATH5K_DEBUG_XMIT,     "xmit",         "basic xmit operation" },
+       { ATH5K_DEBUG_BEACON,   "beacon",       "beacon handling" },
+       { ATH5K_DEBUG_CALIBRATE, "calib",       "periodic calibration" },
+       { ATH5K_DEBUG_TXPOWER,  "txpower",      "transmit power setting" },
+       { ATH5K_DEBUG_LED,      "led",          "LED mamagement" },
+       { ATH5K_DEBUG_DUMP_RX,  "dumprx",       "print received skb content" },
+       { ATH5K_DEBUG_DUMP_TX,  "dumptx",       "print transmit skb content" },
+       { ATH5K_DEBUG_DUMPMODES, "dumpmodes",   "dump modes" },
+       { ATH5K_DEBUG_TRACE,    "trace",        "trace function calls" },
+       { ATH5K_DEBUG_ANY,      "all",          "show all debug levels" },
+};
+
+static ssize_t read_file_debug(struct file *file, char __user *user_buf,
+                                  size_t count, loff_t *ppos)
+{
+       struct ath5k_softc *sc = file->private_data;
+       char buf[700];
+       unsigned int len = 0;
+       unsigned int i;
+
+       len += snprintf(buf+len, sizeof(buf)-len,
+               "DEBUG LEVEL: 0x%08x\n\n", sc->debug.level);
+
+       for (i = 0; i < ARRAY_SIZE(dbg_info) - 1; i++) {
+               len += snprintf(buf+len, sizeof(buf)-len,
+                       "%10s %c 0x%08x - %s\n", dbg_info[i].name,
+                       sc->debug.level & dbg_info[i].level ? '+' : ' ',
+                       dbg_info[i].level, dbg_info[i].desc);
+       }
+       len += snprintf(buf+len, sizeof(buf)-len,
+               "%10s %c 0x%08x - %s\n", dbg_info[i].name,
+               sc->debug.level == dbg_info[i].level ? '+' : ' ',
+               dbg_info[i].level, dbg_info[i].desc);
+
+       return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t write_file_debug(struct file *file,
+                                const char __user *userbuf,
+                                size_t count, loff_t *ppos)
+{
+       struct ath5k_softc *sc = file->private_data;
+       unsigned int i;
+       char buf[20];
+
+       if (copy_from_user(buf, userbuf, min(count, sizeof(buf))))
+               return -EFAULT;
+
+       for (i = 0; i < ARRAY_SIZE(dbg_info); i++) {
+               if (strncmp(buf, dbg_info[i].name,
+                                       strlen(dbg_info[i].name)) == 0) {
+                       sc->debug.level ^= dbg_info[i].level; /* toggle bit */
+                       break;
+               }
+       }
+       return count;
+}
+
+static const struct file_operations fops_debug = {
+       .read = read_file_debug,
+       .write = write_file_debug,
+       .open = ath5k_debugfs_open,
+       .owner = THIS_MODULE,
+};
+
+
 /* init */
 
 void
@@ -326,26 +411,24 @@ void
 ath5k_debug_init_device(struct ath5k_softc *sc)
 {
        sc->debug.level = ath5k_debug;
+
        sc->debug.debugfs_phydir = debugfs_create_dir(wiphy_name(sc->hw->wiphy),
-                       ath5k_global_debugfs);
-       sc->debug.debugfs_debug = debugfs_create_u32("debug",
-                       0666, sc->debug.debugfs_phydir, &sc->debug.level);
+                               ath5k_global_debugfs);
+
+       sc->debug.debugfs_debug = debugfs_create_file("debug", 0666,
+                               sc->debug.debugfs_phydir, sc, &fops_debug);
 
        sc->debug.debugfs_registers = debugfs_create_file("registers", 0444,
-                               sc->debug.debugfs_phydir,
-                               sc, &fops_registers);
+                               sc->debug.debugfs_phydir, sc, &fops_registers);
 
        sc->debug.debugfs_tsf = debugfs_create_file("tsf", 0666,
-                               sc->debug.debugfs_phydir,
-                               sc, &fops_tsf);
+                               sc->debug.debugfs_phydir, sc, &fops_tsf);
 
        sc->debug.debugfs_beacon = debugfs_create_file("beacon", 0666,
-                               sc->debug.debugfs_phydir,
-                               sc, &fops_beacon);
+                               sc->debug.debugfs_phydir, sc, &fops_beacon);
 
        sc->debug.debugfs_reset = debugfs_create_file("reset", 0222,
-                               sc->debug.debugfs_phydir,
-                               sc, &fops_reset);
+                               sc->debug.debugfs_phydir, sc, &fops_reset);
 }
 
 void
@@ -415,8 +498,7 @@ ath5k_debug_printrxbuffs(struct ath5k_softc *sc, struct ath5k_hw *ah)
        struct ath5k_buf *bf;
        int status;
 
-       if (likely(!(sc->debug.level &
-           (ATH5K_DEBUG_RESET | ATH5K_DEBUG_FATAL))))
+       if (likely(!(sc->debug.level & ATH5K_DEBUG_RESET)))
                return;
 
        printk(KERN_DEBUG "rx queue %x, link %p\n",
@@ -426,7 +508,7 @@ ath5k_debug_printrxbuffs(struct ath5k_softc *sc, struct ath5k_hw *ah)
        list_for_each_entry(bf, &sc->rxbuf, list) {
                ds = bf->desc;
                status = ah->ah_proc_rx_desc(ah, ds);
-               if (!status || (sc->debug.level & ATH5K_DEBUG_FATAL))
+               if (!status)
                        ath5k_debug_printrxbuf(bf, status == 0);
        }
        spin_unlock_bh(&sc->rxbuflock);
index 2b491cbc8c802dd2958c1b00f92a0ab4c3c4f92f..c4fd8c43df0c913515f7ee80262de128015ccd47 100644 (file)
@@ -91,7 +91,6 @@ struct ath5k_dbg_info {
  * @ATH5K_DEBUG_MODE: mode init/setup
  * @ATH5K_DEBUG_XMIT: basic xmit operation
  * @ATH5K_DEBUG_BEACON: beacon handling
- * @ATH5K_DEBUG_BEACON_PROC: beacon ISR proc
  * @ATH5K_DEBUG_CALIBRATE: periodic calibration
  * @ATH5K_DEBUG_TXPOWER: transmit power setting
  * @ATH5K_DEBUG_LED: led management
@@ -99,7 +98,6 @@ struct ath5k_dbg_info {
  * @ATH5K_DEBUG_DUMP_TX: print transmit skb content
  * @ATH5K_DEBUG_DUMPMODES: dump modes
  * @ATH5K_DEBUG_TRACE: trace function calls
- * @ATH5K_DEBUG_FATAL: fatal errors
  * @ATH5K_DEBUG_ANY: show at any debug level
  *
  * The debug level is used to control the amount and type of debugging output
@@ -115,15 +113,13 @@ enum ath5k_debug_level {
        ATH5K_DEBUG_MODE        = 0x00000004,
        ATH5K_DEBUG_XMIT        = 0x00000008,
        ATH5K_DEBUG_BEACON      = 0x00000010,
-       ATH5K_DEBUG_BEACON_PROC = 0x00000020,
-       ATH5K_DEBUG_CALIBRATE   = 0x00000100,
-       ATH5K_DEBUG_TXPOWER     = 0x00000200,
-       ATH5K_DEBUG_LED         = 0x00000400,
-       ATH5K_DEBUG_DUMP_RX     = 0x00001000,
-       ATH5K_DEBUG_DUMP_TX     = 0x00002000,
-       ATH5K_DEBUG_DUMPMODES   = 0x00004000,
-       ATH5K_DEBUG_TRACE       = 0x00010000,
-       ATH5K_DEBUG_FATAL       = 0x80000000,
+       ATH5K_DEBUG_CALIBRATE   = 0x00000020,
+       ATH5K_DEBUG_TXPOWER     = 0x00000040,
+       ATH5K_DEBUG_LED         = 0x00000080,
+       ATH5K_DEBUG_DUMP_RX     = 0x00000100,
+       ATH5K_DEBUG_DUMP_TX     = 0x00000200,
+       ATH5K_DEBUG_DUMPMODES   = 0x00000400,
+       ATH5K_DEBUG_TRACE       = 0x00001000,
        ATH5K_DEBUG_ANY         = 0xffffffff
 };
 
index 32a24f5c4fa61c5a0ce26364a79a032487e4435d..08a011f0834a045e8547a421654bc496bd367341 100644 (file)
@@ -724,6 +724,7 @@ struct b43_wldev {
        bool short_preamble;    /* TRUE, if short preamble is enabled. */
        bool short_slot;        /* TRUE, if short slot timing is enabled. */
        bool radio_hw_enable;   /* saved state of radio hardware enabled state */
+       bool suspend_in_progress;       /* TRUE, if we are in a suspend/resume cycle */
 
        /* PHY/Radio device. */
        struct b43_phy phy;
index 3e73d2a523aa98563ada01db749da1ccaaa7b5a5..8a708b77925df438ab5eb959b15edd025da31c96 100644 (file)
@@ -1114,7 +1114,7 @@ static int dma_tx_fragment(struct b43_dmaring *ring,
 {
        const struct b43_dma_ops *ops = ring->ops;
        u8 *header;
-       int slot;
+       int slot, old_top_slot, old_used_slots;
        int err;
        struct b43_dmadesc_generic *desc;
        struct b43_dmadesc_meta *meta;
@@ -1126,6 +1126,9 @@ static int dma_tx_fragment(struct b43_dmaring *ring,
 #define SLOTS_PER_PACKET  2
        B43_WARN_ON(skb_shinfo(skb)->nr_frags);
 
+       old_top_slot = ring->current_slot;
+       old_used_slots = ring->used_slots;
+
        /* Get a slot for the header. */
        slot = request_slot(ring);
        desc = ops->idx2desc(ring, slot, &meta_hdr);
@@ -1133,13 +1136,21 @@ static int dma_tx_fragment(struct b43_dmaring *ring,
 
        header = &(ring->txhdr_cache[slot * hdrsize]);
        cookie = generate_cookie(ring, slot);
-       b43_generate_txhdr(ring->dev, header,
-                          skb->data, skb->len, ctl, cookie);
+       err = b43_generate_txhdr(ring->dev, header,
+                                skb->data, skb->len, ctl, cookie);
+       if (unlikely(err)) {
+               ring->current_slot = old_top_slot;
+               ring->used_slots = old_used_slots;
+               return err;
+       }
 
        meta_hdr->dmaaddr = map_descbuffer(ring, (unsigned char *)header,
                                           hdrsize, 1);
-       if (dma_mapping_error(meta_hdr->dmaaddr))
+       if (dma_mapping_error(meta_hdr->dmaaddr)) {
+               ring->current_slot = old_top_slot;
+               ring->used_slots = old_used_slots;
                return -EIO;
+       }
        ops->fill_descriptor(ring, desc, meta_hdr->dmaaddr,
                             hdrsize, 1, 0, 0);
 
@@ -1157,6 +1168,8 @@ static int dma_tx_fragment(struct b43_dmaring *ring,
        if (dma_mapping_error(meta->dmaaddr)) {
                bounce_skb = __dev_alloc_skb(skb->len, GFP_ATOMIC | GFP_DMA);
                if (!bounce_skb) {
+                       ring->current_slot = old_top_slot;
+                       ring->used_slots = old_used_slots;
                        err = -ENOMEM;
                        goto out_unmap_hdr;
                }
@@ -1167,6 +1180,8 @@ static int dma_tx_fragment(struct b43_dmaring *ring,
                meta->skb = skb;
                meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1);
                if (dma_mapping_error(meta->dmaaddr)) {
+                       ring->current_slot = old_top_slot;
+                       ring->used_slots = old_used_slots;
                        err = -EIO;
                        goto out_free_bounce;
                }
@@ -1252,6 +1267,13 @@ int b43_dma_tx(struct b43_wldev *dev,
        B43_WARN_ON(ring->stopped);
 
        err = dma_tx_fragment(ring, skb, ctl);
+       if (unlikely(err == -ENOKEY)) {
+               /* Drop this packet, as we don't have the encryption key
+                * anymore and must not transmit it unencrypted. */
+               dev_kfree_skb_any(skb);
+               err = 0;
+               goto out_unlock;
+       }
        if (unlikely(err)) {
                b43err(dev->wl, "DMA tx mapping failure\n");
                goto out_unlock;
index 4b590d8c65ff08317fc6405546545e64bc104115..0908335892dbba7214fc1d995d7a9af2da7f54e5 100644 (file)
@@ -116,7 +116,10 @@ static void b43_unregister_led(struct b43_led *led)
 {
        if (!led->dev)
                return;
-       led_classdev_unregister(&led->led_dev);
+       if (led->dev->suspend_in_progress)
+               led_classdev_unregister_suspended(&led->led_dev);
+       else
+               led_classdev_unregister(&led->led_dev);
        b43_led_turn_off(led->dev, led->index, led->activelow);
        led->dev = NULL;
 }
index 88d2c15d3fbeccc5332cf55e3582a71e5174e3ef..ef65c41af00fc022e4841baa843571f1ae107fda 100644 (file)
@@ -38,6 +38,7 @@
 #include <linux/wireless.h>
 #include <linux/workqueue.h>
 #include <linux/skbuff.h>
+#include <linux/io.h>
 #include <linux/dma-mapping.h>
 #include <asm/unaligned.h>
 
@@ -2554,10 +2555,10 @@ static int b43_rng_read(struct hwrng *rng, u32 * data)
        return (sizeof(u16));
 }
 
-static void b43_rng_exit(struct b43_wl *wl)
+static void b43_rng_exit(struct b43_wl *wl, bool suspended)
 {
        if (wl->rng_initialized)
-               hwrng_unregister(&wl->rng);
+               __hwrng_unregister(&wl->rng, suspended);
 }
 
 static int b43_rng_init(struct b43_wl *wl)
@@ -3417,8 +3418,10 @@ static void b43_wireless_core_exit(struct b43_wldev *dev)
        macctl |= B43_MACCTL_PSM_JMP0;
        b43_write32(dev, B43_MMIO_MACCTL, macctl);
 
-       b43_leds_exit(dev);
-       b43_rng_exit(dev->wl);
+       if (!dev->suspend_in_progress) {
+               b43_leds_exit(dev);
+               b43_rng_exit(dev->wl, false);
+       }
        b43_dma_free(dev);
        b43_chip_exit(dev);
        b43_radio_turn_off(dev, 1);
@@ -3532,15 +3535,15 @@ static int b43_wireless_core_init(struct b43_wldev *dev)
        b43_bluetooth_coext_enable(dev);
 
        ssb_bus_powerup(bus, 1);        /* Enable dynamic PCTL */
-       memset(wl->bssid, 0, ETH_ALEN);
-       memset(wl->mac_addr, 0, ETH_ALEN);
        b43_upload_card_macaddress(dev);
        b43_security_init(dev);
-       b43_rng_init(wl);
+       if (!dev->suspend_in_progress)
+               b43_rng_init(wl);
 
        b43_set_status(dev, B43_STAT_INITIALIZED);
 
-       b43_leds_init(dev);
+       if (!dev->suspend_in_progress)
+               b43_leds_init(dev);
 out:
        return err;
 
@@ -3630,6 +3633,15 @@ static int b43_op_start(struct ieee80211_hw *hw)
        struct b43_wldev *dev = wl->current_dev;
        int did_init = 0;
        int err = 0;
+       bool do_rfkill_exit = 0;
+
+       /* Kill all old instance specific information to make sure
+        * the card won't use it in the short timeframe between start
+        * and mac80211 reconfiguring it. */
+       memset(wl->bssid, 0, ETH_ALEN);
+       memset(wl->mac_addr, 0, ETH_ALEN);
+       wl->filter_flags = 0;
+       wl->radiotap_enabled = 0;
 
        /* First register RFkill.
         * LEDs that are registered later depend on it. */
@@ -3639,8 +3651,10 @@ static int b43_op_start(struct ieee80211_hw *hw)
 
        if (b43_status(dev) < B43_STAT_INITIALIZED) {
                err = b43_wireless_core_init(dev);
-               if (err)
+               if (err) {
+                       do_rfkill_exit = 1;
                        goto out_mutex_unlock;
+               }
                did_init = 1;
        }
 
@@ -3649,6 +3663,7 @@ static int b43_op_start(struct ieee80211_hw *hw)
                if (err) {
                        if (did_init)
                                b43_wireless_core_exit(dev);
+                       do_rfkill_exit = 1;
                        goto out_mutex_unlock;
                }
        }
@@ -3656,6 +3671,9 @@ static int b43_op_start(struct ieee80211_hw *hw)
  out_mutex_unlock:
        mutex_unlock(&wl->mutex);
 
+       if (do_rfkill_exit)
+               b43_rfkill_exit(dev);
+
        return err;
 }
 
@@ -4122,6 +4140,7 @@ static int b43_suspend(struct ssb_device *dev, pm_message_t state)
        b43dbg(wl, "Suspending...\n");
 
        mutex_lock(&wl->mutex);
+       wldev->suspend_in_progress = true;
        wldev->suspend_init_status = b43_status(wldev);
        if (wldev->suspend_init_status >= B43_STAT_STARTED)
                b43_wireless_core_stop(wldev);
@@ -4153,15 +4172,17 @@ static int b43_resume(struct ssb_device *dev)
        if (wldev->suspend_init_status >= B43_STAT_STARTED) {
                err = b43_wireless_core_start(wldev);
                if (err) {
+                       b43_leds_exit(wldev);
+                       b43_rng_exit(wldev->wl, true);
                        b43_wireless_core_exit(wldev);
                        b43err(wl, "Resume failed at core start\n");
                        goto out;
                }
        }
-       mutex_unlock(&wl->mutex);
-
        b43dbg(wl, "Device resumed.\n");
-      out:
+ out:
+       wldev->suspend_in_progress = false;
+       mutex_unlock(&wl->mutex);
        return err;
 }
 
index 3fc53e8b4416092c26a2f2bbb7ead93b4ecda98b..7caa26eb410588a8b4de1a03328141db52888787 100644 (file)
@@ -178,12 +178,12 @@ static u8 b43_calc_fallback_rate(u8 bitrate)
 }
 
 /* Generate a TX data header. */
-void b43_generate_txhdr(struct b43_wldev *dev,
-                       u8 *_txhdr,
-                       const unsigned char *fragment_data,
-                       unsigned int fragment_len,
-                       const struct ieee80211_tx_control *txctl,
-                       u16 cookie)
+int b43_generate_txhdr(struct b43_wldev *dev,
+                      u8 *_txhdr,
+                      const unsigned char *fragment_data,
+                      unsigned int fragment_len,
+                      const struct ieee80211_tx_control *txctl,
+                      u16 cookie)
 {
        struct b43_txhdr *txhdr = (struct b43_txhdr *)_txhdr;
        const struct b43_phy *phy = &dev->phy;
@@ -237,7 +237,15 @@ void b43_generate_txhdr(struct b43_wldev *dev,
 
                B43_WARN_ON(key_idx >= dev->max_nr_keys);
                key = &(dev->key[key_idx]);
-               B43_WARN_ON(!key->keyconf);
+
+               if (unlikely(!key->keyconf)) {
+                       /* This key is invalid. This might only happen
+                        * in a short timeframe after machine resume before
+                        * we were able to reconfigure keys.
+                        * Drop this packet completely. Do not transmit it
+                        * unencrypted to avoid leaking information. */
+                       return -ENOKEY;
+               }
 
                /* Hardware appends ICV. */
                plcp_fragment_len += txctl->icv_len;
@@ -408,6 +416,7 @@ void b43_generate_txhdr(struct b43_wldev *dev,
        txhdr->phy_ctl = cpu_to_le16(phy_ctl);
        txhdr->extra_ft = extra_ft;
 
+       return 0;
 }
 
 static s8 b43_rssi_postprocess(struct b43_wldev *dev,
index ca2a2ab8654c5d7102e07e7c5698d89c536b7680..41765039552bdf6792bd7b4e3cae14ba02fec0ef 100644 (file)
@@ -174,11 +174,11 @@ size_t b43_txhdr_size(struct b43_wldev *dev)
 }
 
 
-void b43_generate_txhdr(struct b43_wldev *dev,
-                       u8 * txhdr,
-                       const unsigned char *fragment_data,
-                       unsigned int fragment_len,
-                       const struct ieee80211_tx_control *txctl, u16 cookie);
+int b43_generate_txhdr(struct b43_wldev *dev,
+                      u8 * txhdr,
+                      const unsigned char *fragment_data,
+                      unsigned int fragment_len,
+                      const struct ieee80211_tx_control *txctl, u16 cookie);
 
 /* Transmit Status */
 struct b43_txstatus {
index 93419adb925e41454bf369e944eb536b3581ceb6..c80edd2b90444f9342fa41ab64a23e0f5d75689d 100644 (file)
@@ -23,7 +23,7 @@
 #include "phy.h"
 
 
-#define B43legacy_IRQWAIT_MAX_RETRIES  100
+#define B43legacy_IRQWAIT_MAX_RETRIES  20
 
 #define B43legacy_RX_MAX_SSI           60 /* best guess at max ssi */
 
@@ -40,9 +40,8 @@
 #define B43legacy_MMIO_DMA4_IRQ_MASK   0x44
 #define B43legacy_MMIO_DMA5_REASON     0x48
 #define B43legacy_MMIO_DMA5_IRQ_MASK   0x4C
-#define B43legacy_MMIO_MACCTL          0x120
-#define B43legacy_MMIO_STATUS_BITFIELD 0x120
-#define B43legacy_MMIO_STATUS2_BITFIELD        0x124
+#define B43legacy_MMIO_MACCTL          0x120   /* MAC control */
+#define B43legacy_MMIO_MACCMD          0x124   /* MAC command */
 #define B43legacy_MMIO_GEN_IRQ_REASON  0x128
 #define B43legacy_MMIO_GEN_IRQ_MASK    0x12C
 #define B43legacy_MMIO_RAM_CONTROL     0x130
 #define B43legacy_RADIOCTL_ID          0x01
 
 /* MAC Control bitfield */
+#define B43legacy_MACCTL_ENABLED       0x00000001 /* MAC Enabled */
+#define B43legacy_MACCTL_PSM_RUN       0x00000002 /* Run Microcode */
+#define B43legacy_MACCTL_PSM_JMP0      0x00000004 /* Microcode jump to 0 */
+#define B43legacy_MACCTL_SHM_ENABLED   0x00000100 /* SHM Enabled */
 #define B43legacy_MACCTL_IHR_ENABLED   0x00000400 /* IHR Region Enabled */
+#define B43legacy_MACCTL_BE            0x00010000 /* Big Endian mode */
 #define B43legacy_MACCTL_INFRA         0x00020000 /* Infrastructure mode */
 #define B43legacy_MACCTL_AP            0x00040000 /* AccessPoint mode */
+#define B43legacy_MACCTL_RADIOLOCK     0x00080000 /* Radio lock */
 #define B43legacy_MACCTL_BEACPROMISC   0x00100000 /* Beacon Promiscuous */
 #define B43legacy_MACCTL_KEEP_BADPLCP  0x00200000 /* Keep bad PLCP frames */
 #define B43legacy_MACCTL_KEEP_CTL      0x00400000 /* Keep control frames */
 #define B43legacy_MACCTL_KEEP_BAD      0x00800000 /* Keep bad frames (FCS) */
 #define B43legacy_MACCTL_PROMISC       0x01000000 /* Promiscuous mode */
+#define B43legacy_MACCTL_HWPS          0x02000000 /* Hardware Power Saving */
+#define B43legacy_MACCTL_AWAKE         0x04000000 /* Device is awake */
+#define B43legacy_MACCTL_TBTTHOLD      0x10000000 /* TBTT Hold */
 #define B43legacy_MACCTL_GMODE         0x80000000 /* G Mode */
 
-/* StatusBitField */
-#define B43legacy_SBF_MAC_ENABLED      0x00000001
-#define B43legacy_SBF_CORE_READY       0x00000004
-#define B43legacy_SBF_400              0x00000400 /*FIXME: fix name*/
-#define B43legacy_SBF_XFER_REG_BYTESWAP        0x00010000
-#define B43legacy_SBF_MODE_NOTADHOC    0x00020000
-#define B43legacy_SBF_MODE_AP          0x00040000
-#define B43legacy_SBF_RADIOREG_LOCK    0x00080000
-#define B43legacy_SBF_MODE_MONITOR     0x00400000
-#define B43legacy_SBF_MODE_PROMISC     0x01000000
-#define B43legacy_SBF_PS1              0x02000000
-#define B43legacy_SBF_PS2              0x04000000
-#define B43legacy_SBF_NO_SSID_BCAST    0x08000000
-#define B43legacy_SBF_TIME_UPDATE      0x10000000
-
 /* 802.11 core specific TM State Low flags */
 #define B43legacy_TMSLOW_GMODE         0x20000000 /* G Mode Enable */
 #define B43legacy_TMSLOW_PLLREFSEL     0x00200000 /* PLL Freq Ref Select */
index 4ed4243feeaa7cf659910b40e8f6bccbdbe8c2db..aa20d5d56e2f479d625c2411c53228ebaa3876e9 100644 (file)
@@ -225,8 +225,8 @@ static void b43legacy_ram_write(struct b43legacy_wldev *dev, u16 offset,
 
        B43legacy_WARN_ON(offset % 4 != 0);
 
-       status = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD);
-       if (status & B43legacy_SBF_XFER_REG_BYTESWAP)
+       status = b43legacy_read32(dev, B43legacy_MMIO_MACCTL);
+       if (status & B43legacy_MACCTL_BE)
                val = swab32(val);
 
        b43legacy_write32(dev, B43legacy_MMIO_RAM_CONTROL, offset);
@@ -434,9 +434,9 @@ static void b43legacy_time_lock(struct b43legacy_wldev *dev)
 {
        u32 status;
 
-       status = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD);
-       status |= B43legacy_SBF_TIME_UPDATE;
-       b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, status);
+       status = b43legacy_read32(dev, B43legacy_MMIO_MACCTL);
+       status |= B43legacy_MACCTL_TBTTHOLD;
+       b43legacy_write32(dev, B43legacy_MMIO_MACCTL, status);
        mmiowb();
 }
 
@@ -444,9 +444,9 @@ static void b43legacy_time_unlock(struct b43legacy_wldev *dev)
 {
        u32 status;
 
-       status = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD);
-       status &= ~B43legacy_SBF_TIME_UPDATE;
-       b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, status);
+       status = b43legacy_read32(dev, B43legacy_MMIO_MACCTL);
+       status &= ~B43legacy_MACCTL_TBTTHOLD;
+       b43legacy_write32(dev, B43legacy_MMIO_MACCTL, status);
 }
 
 static void b43legacy_tsf_write_locked(struct b43legacy_wldev *dev, u64 tsf)
@@ -647,7 +647,7 @@ void b43legacy_dummy_transmission(struct b43legacy_wldev *dev)
                b43legacy_ram_write(dev, i * 4, buffer[i]);
 
        /* dummy read follows */
-       b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD);
+       b43legacy_read32(dev, B43legacy_MMIO_MACCTL);
 
        b43legacy_write16(dev, 0x0568, 0x0000);
        b43legacy_write16(dev, 0x07C0, 0x0000);
@@ -794,9 +794,9 @@ static void b43legacy_jssi_write(struct b43legacy_wldev *dev, u32 jssi)
 static void b43legacy_generate_noise_sample(struct b43legacy_wldev *dev)
 {
        b43legacy_jssi_write(dev, 0x7F7F7F7F);
-       b43legacy_write32(dev, B43legacy_MMIO_STATUS2_BITFIELD,
+       b43legacy_write32(dev, B43legacy_MMIO_MACCMD,
                          b43legacy_read32(dev,
-                         B43legacy_MMIO_STATUS2_BITFIELD)
+                         B43legacy_MMIO_MACCMD)
                          | (1 << 4));
        B43legacy_WARN_ON(dev->noisecalc.channel_at_start !=
                            dev->phy.channel);
@@ -895,8 +895,8 @@ static void handle_irq_atim_end(struct b43legacy_wldev *dev)
 {
        if (!dev->reg124_set_0x4) /*FIXME rename this variable*/
                return;
-       b43legacy_write32(dev, B43legacy_MMIO_STATUS2_BITFIELD,
-                         b43legacy_read32(dev, B43legacy_MMIO_STATUS2_BITFIELD)
+       b43legacy_write32(dev, B43legacy_MMIO_MACCMD,
+                         b43legacy_read32(dev, B43legacy_MMIO_MACCMD)
                          | 0x4);
 }
 
@@ -1106,9 +1106,9 @@ static void b43legacy_update_templates(struct b43legacy_wldev *dev)
        b43legacy_write_probe_resp_template(dev, 0x268, 0x4A,
                                            B43legacy_CCK_RATE_11MB);
 
-       status = b43legacy_read32(dev, B43legacy_MMIO_STATUS2_BITFIELD);
+       status = b43legacy_read32(dev, B43legacy_MMIO_MACCMD);
        status |= 0x03;
-       b43legacy_write32(dev, B43legacy_MMIO_STATUS2_BITFIELD, status);
+       b43legacy_write32(dev, B43legacy_MMIO_MACCMD, status);
 }
 
 static void b43legacy_refresh_templates(struct b43legacy_wldev *dev,
@@ -1166,7 +1166,7 @@ static void handle_irq_beacon(struct b43legacy_wldev *dev)
                return;
 
        dev->irq_savedstate &= ~B43legacy_IRQ_BEACON;
-       status = b43legacy_read32(dev, B43legacy_MMIO_STATUS2_BITFIELD);
+       status = b43legacy_read32(dev, B43legacy_MMIO_MACCMD);
 
        if (!dev->cached_beacon || ((status & 0x1) && (status & 0x2))) {
                /* ACK beacon IRQ. */
@@ -1182,14 +1182,14 @@ static void handle_irq_beacon(struct b43legacy_wldev *dev)
                b43legacy_write_beacon_template(dev, 0x68, 0x18,
                                                B43legacy_CCK_RATE_1MB);
                status |= 0x1;
-               b43legacy_write32(dev, B43legacy_MMIO_STATUS2_BITFIELD,
+               b43legacy_write32(dev, B43legacy_MMIO_MACCMD,
                                  status);
        }
        if (!(status & 0x2)) {
                b43legacy_write_beacon_template(dev, 0x468, 0x1A,
                                                B43legacy_CCK_RATE_1MB);
                status |= 0x2;
-               b43legacy_write32(dev, B43legacy_MMIO_STATUS2_BITFIELD,
+               b43legacy_write32(dev, B43legacy_MMIO_MACCMD,
                                  status);
        }
 }
@@ -1548,9 +1548,20 @@ static int b43legacy_upload_microcode(struct b43legacy_wldev *dev)
        u16 fwpatch;
        u16 fwdate;
        u16 fwtime;
-       u32 tmp;
+       u32 tmp, macctl;
        int err = 0;
 
+       /* Jump the microcode PSM to offset 0 */
+       macctl = b43legacy_read32(dev, B43legacy_MMIO_MACCTL);
+       B43legacy_WARN_ON(macctl & B43legacy_MACCTL_PSM_RUN);
+       macctl |= B43legacy_MACCTL_PSM_JMP0;
+       b43legacy_write32(dev, B43legacy_MMIO_MACCTL, macctl);
+       /* Zero out all microcode PSM registers and shared memory. */
+       for (i = 0; i < 64; i++)
+               b43legacy_shm_write16(dev, B43legacy_SHM_WIRELESS, i, 0);
+       for (i = 0; i < 4096; i += 2)
+               b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, i, 0);
+
        /* Upload Microcode. */
        data = (__be32 *) (dev->fw.ucode->data + hdr_len);
        len = (dev->fw.ucode->size - hdr_len) / sizeof(__be32);
@@ -1581,7 +1592,12 @@ static int b43legacy_upload_microcode(struct b43legacy_wldev *dev)
 
        b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_REASON,
                          B43legacy_IRQ_ALL);
-       b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, 0x00020402);
+
+       /* Start the microcode PSM */
+       macctl = b43legacy_read32(dev, B43legacy_MMIO_MACCTL);
+       macctl &= ~B43legacy_MACCTL_PSM_JMP0;
+       macctl |= B43legacy_MACCTL_PSM_RUN;
+       b43legacy_write32(dev, B43legacy_MMIO_MACCTL, macctl);
 
        /* Wait for the microcode to load and respond */
        i = 0;
@@ -1594,9 +1610,13 @@ static int b43legacy_upload_microcode(struct b43legacy_wldev *dev)
                        b43legacyerr(dev->wl, "Microcode not responding\n");
                        b43legacy_print_fw_helptext(dev->wl);
                        err = -ENODEV;
-                       goto out;
+                       goto error;
+               }
+               msleep_interruptible(50);
+               if (signal_pending(current)) {
+                       err = -EINTR;
+                       goto error;
                }
-               udelay(10);
        }
        /* dummy read follows */
        b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_REASON);
@@ -1617,9 +1637,8 @@ static int b43legacy_upload_microcode(struct b43legacy_wldev *dev)
                             " is supported. You must change your firmware"
                             " files.\n");
                b43legacy_print_fw_helptext(dev->wl);
-               b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, 0);
                err = -EOPNOTSUPP;
-               goto out;
+               goto error;
        }
        b43legacydbg(dev->wl, "Loading firmware version 0x%X, patch level %u "
               "(20%.2i-%.2i-%.2i %.2i:%.2i:%.2i)\n", fwrev, fwpatch,
@@ -1629,7 +1648,14 @@ static int b43legacy_upload_microcode(struct b43legacy_wldev *dev)
        dev->fw.rev = fwrev;
        dev->fw.patch = fwpatch;
 
-out:
+       return 0;
+
+error:
+       macctl = b43legacy_read32(dev, B43legacy_MMIO_MACCTL);
+       macctl &= ~B43legacy_MACCTL_PSM_RUN;
+       macctl |= B43legacy_MACCTL_PSM_JMP0;
+       b43legacy_write32(dev, B43legacy_MMIO_MACCTL, macctl);
+
        return err;
 }
 
@@ -1736,9 +1762,9 @@ static int b43legacy_gpio_init(struct b43legacy_wldev *dev)
        u32 mask;
        u32 set;
 
-       b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD,
+       b43legacy_write32(dev, B43legacy_MMIO_MACCTL,
                          b43legacy_read32(dev,
-                         B43legacy_MMIO_STATUS_BITFIELD)
+                         B43legacy_MMIO_MACCTL)
                          & 0xFFFF3FFF);
 
        b43legacy_write16(dev, B43legacy_MMIO_GPIO_MASK,
@@ -1798,14 +1824,14 @@ void b43legacy_mac_enable(struct b43legacy_wldev *dev)
        B43legacy_WARN_ON(dev->mac_suspended < 0);
        B43legacy_WARN_ON(irqs_disabled());
        if (dev->mac_suspended == 0) {
-               b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD,
+               b43legacy_write32(dev, B43legacy_MMIO_MACCTL,
                                  b43legacy_read32(dev,
-                                 B43legacy_MMIO_STATUS_BITFIELD)
-                                 | B43legacy_SBF_MAC_ENABLED);
+                                 B43legacy_MMIO_MACCTL)
+                                 | B43legacy_MACCTL_ENABLED);
                b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_REASON,
                                  B43legacy_IRQ_MAC_SUSPENDED);
                /* the next two are dummy reads */
-               b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD);
+               b43legacy_read32(dev, B43legacy_MMIO_MACCTL);
                b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_REASON);
                b43legacy_power_saving_ctl_bits(dev, -1, -1);
 
@@ -1836,10 +1862,10 @@ void b43legacy_mac_suspend(struct b43legacy_wldev *dev)
                dev->irq_savedstate = tmp;
 
                b43legacy_power_saving_ctl_bits(dev, -1, 1);
-               b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD,
+               b43legacy_write32(dev, B43legacy_MMIO_MACCTL,
                                  b43legacy_read32(dev,
-                                 B43legacy_MMIO_STATUS_BITFIELD)
-                                 & ~B43legacy_SBF_MAC_ENABLED);
+                                 B43legacy_MMIO_MACCTL)
+                                 & ~B43legacy_MACCTL_ENABLED);
                b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_REASON);
                for (i = 40; i; i--) {
                        tmp = b43legacy_read32(dev,
@@ -2007,12 +2033,15 @@ static int b43legacy_chip_init(struct b43legacy_wldev *dev)
        struct b43legacy_phy *phy = &dev->phy;
        int err;
        int tmp;
-       u32 value32;
+       u32 value32, macctl;
        u16 value16;
 
-       b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD,
-                         B43legacy_SBF_CORE_READY
-                         | B43legacy_SBF_400);
+       /* Initialize the MAC control */
+       macctl = B43legacy_MACCTL_IHR_ENABLED | B43legacy_MACCTL_SHM_ENABLED;
+       if (dev->phy.gmode)
+               macctl |= B43legacy_MACCTL_GMODE;
+       macctl |= B43legacy_MACCTL_INFRA;
+       b43legacy_write32(dev, B43legacy_MMIO_MACCTL, macctl);
 
        err = b43legacy_request_firmware(dev);
        if (err)
@@ -2052,12 +2081,12 @@ static int b43legacy_chip_init(struct b43legacy_wldev *dev)
        if (dev->dev->id.revision < 5)
                b43legacy_write32(dev, 0x010C, 0x01000000);
 
-       value32 = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD);
-       value32 &= ~B43legacy_SBF_MODE_NOTADHOC;
-       b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, value32);
-       value32 = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD);
-       value32 |= B43legacy_SBF_MODE_NOTADHOC;
-       b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, value32);
+       value32 = b43legacy_read32(dev, B43legacy_MMIO_MACCTL);
+       value32 &= ~B43legacy_MACCTL_INFRA;
+       b43legacy_write32(dev, B43legacy_MMIO_MACCTL, value32);
+       value32 = b43legacy_read32(dev, B43legacy_MMIO_MACCTL);
+       value32 |= B43legacy_MACCTL_INFRA;
+       b43legacy_write32(dev, B43legacy_MMIO_MACCTL, value32);
 
        if (b43legacy_using_pio(dev)) {
                b43legacy_write32(dev, 0x0210, 0x00000100);
@@ -2951,12 +2980,19 @@ static void b43legacy_wireless_core_exit(struct b43legacy_wldev *dev)
 {
        struct b43legacy_wl *wl = dev->wl;
        struct b43legacy_phy *phy = &dev->phy;
+       u32 macctl;
 
        B43legacy_WARN_ON(b43legacy_status(dev) > B43legacy_STAT_INITIALIZED);
        if (b43legacy_status(dev) != B43legacy_STAT_INITIALIZED)
                return;
        b43legacy_set_status(dev, B43legacy_STAT_UNINIT);
 
+       /* Stop the microcode PSM. */
+       macctl = b43legacy_read32(dev, B43legacy_MMIO_MACCTL);
+       macctl &= ~B43legacy_MACCTL_PSM_RUN;
+       macctl |= B43legacy_MACCTL_PSM_JMP0;
+       b43legacy_write32(dev, B43legacy_MMIO_MACCTL, macctl);
+
        mutex_unlock(&wl->mutex);
        /* Must unlock as it would otherwise deadlock. No races here.
         * Cancel possibly pending workqueues. */
@@ -3221,6 +3257,7 @@ static int b43legacy_op_start(struct ieee80211_hw *hw)
        struct b43legacy_wldev *dev = wl->current_dev;
        int did_init = 0;
        int err = 0;
+       bool do_rfkill_exit = 0;
 
        /* First register RFkill.
         * LEDs that are registered later depend on it. */
@@ -3230,8 +3267,10 @@ static int b43legacy_op_start(struct ieee80211_hw *hw)
 
        if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED) {
                err = b43legacy_wireless_core_init(dev);
-               if (err)
+               if (err) {
+                       do_rfkill_exit = 1;
                        goto out_mutex_unlock;
+               }
                did_init = 1;
        }
 
@@ -3240,6 +3279,7 @@ static int b43legacy_op_start(struct ieee80211_hw *hw)
                if (err) {
                        if (did_init)
                                b43legacy_wireless_core_exit(dev);
+                       do_rfkill_exit = 1;
                        goto out_mutex_unlock;
                }
        }
@@ -3247,6 +3287,9 @@ static int b43legacy_op_start(struct ieee80211_hw *hw)
 out_mutex_unlock:
        mutex_unlock(&wl->mutex);
 
+       if (do_rfkill_exit)
+               b43legacy_rfkill_exit(dev);
+
        return err;
 }
 
index c16febbdbf5d7da9023ec33b855bc198bd4ac206..8e5c09b818715e87baf89a3c012d2cf8a1110c32 100644 (file)
@@ -140,7 +140,7 @@ void b43legacy_phy_calibrate(struct b43legacy_wldev *dev)
 {
        struct b43legacy_phy *phy = &dev->phy;
 
-       b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD); /* Dummy read. */
+       b43legacy_read32(dev, B43legacy_MMIO_MACCTL); /* Dummy read. */
        if (phy->calibrated)
                return;
        if (phy->type == B43legacy_PHYTYPE_G && phy->rev == 1) {
@@ -2231,16 +2231,16 @@ bit26 = 1;
                 *      or the latest PS-Poll packet sent was successful,
                 *      set bit26  */
        }
-       status = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD);
+       status = b43legacy_read32(dev, B43legacy_MMIO_MACCTL);
        if (bit25)
-               status |= B43legacy_SBF_PS1;
+               status |= B43legacy_MACCTL_HWPS;
        else
-               status &= ~B43legacy_SBF_PS1;
+               status &= ~B43legacy_MACCTL_HWPS;
        if (bit26)
-               status |= B43legacy_SBF_PS2;
+               status |= B43legacy_MACCTL_AWAKE;
        else
-               status &= ~B43legacy_SBF_PS2;
-       b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, status);
+               status &= ~B43legacy_MACCTL_AWAKE;
+       b43legacy_write32(dev, B43legacy_MMIO_MACCTL, status);
        if (bit26 && dev->dev->id.revision >= 5) {
                for (i = 0; i < 100; i++) {
                        if (b43legacy_shm_read32(dev, B43legacy_SHM_SHARED,
index de843ac147ae4016625bd12401d0bd02243d017f..e4f4c5c39e334ebf4c37c0e903b66ec989f71b82 100644 (file)
@@ -334,9 +334,9 @@ struct b43legacy_pioqueue *b43legacy_setup_pioqueue(struct b43legacy_wldev *dev,
        tasklet_init(&queue->txtask, tx_tasklet,
                     (unsigned long)queue);
 
-       value = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD);
-       value &= ~B43legacy_SBF_XFER_REG_BYTESWAP;
-       b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, value);
+       value = b43legacy_read32(dev, B43legacy_MMIO_MACCTL);
+       value &= ~B43legacy_MACCTL_BE;
+       b43legacy_write32(dev, B43legacy_MMIO_MACCTL, value);
 
        qsize = b43legacy_read16(dev, queue->mmio_base
                                 + B43legacy_PIO_TXQBUFSIZE);
index 318a270cf9b424d5b12fac7a6086c4f9b7f7ea3e..955832e8654f18dd12e537a973a8345ee6bc1e1c 100644 (file)
@@ -91,10 +91,10 @@ void b43legacy_radio_lock(struct b43legacy_wldev *dev)
 {
        u32 status;
 
-       status = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD);
-       B43legacy_WARN_ON(status & B43legacy_SBF_RADIOREG_LOCK);
-       status |= B43legacy_SBF_RADIOREG_LOCK;
-       b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, status);
+       status = b43legacy_read32(dev, B43legacy_MMIO_MACCTL);
+       B43legacy_WARN_ON(status & B43legacy_MACCTL_RADIOLOCK);
+       status |= B43legacy_MACCTL_RADIOLOCK;
+       b43legacy_write32(dev, B43legacy_MMIO_MACCTL, status);
        mmiowb();
        udelay(10);
 }
@@ -104,10 +104,10 @@ void b43legacy_radio_unlock(struct b43legacy_wldev *dev)
        u32 status;
 
        b43legacy_read16(dev, B43legacy_MMIO_PHY_VER); /* dummy read */
-       status = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD);
-       B43legacy_WARN_ON(!(status & B43legacy_SBF_RADIOREG_LOCK));
-       status &= ~B43legacy_SBF_RADIOREG_LOCK;
-       b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, status);
+       status = b43legacy_read32(dev, B43legacy_MMIO_MACCTL);
+       B43legacy_WARN_ON(!(status & B43legacy_MACCTL_RADIOLOCK));
+       status &= ~B43legacy_MACCTL_RADIOLOCK;
+       b43legacy_write32(dev, B43legacy_MMIO_MACCTL, status);
        mmiowb();
 }
 
index d6b9362a3d5cd00f2d046f2afa86b071841b799c..3694b1eba521cbca531bb56574abb643da79f9a8 100644 (file)
@@ -71,11 +71,6 @@ struct hostap_80211_rx_status {
        u16 rate; /* in 100 kbps */
 };
 
-
-void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb,
-                    struct hostap_80211_rx_status *rx_stats);
-
-
 /* prism2_rx_80211 'type' argument */
 enum {
        PRISM2_RX_MONITOR, PRISM2_RX_MGMT, PRISM2_RX_NON_ASSOC,
index 07593803065ae142277cc33b276c0e64e9a7e339..437a9bcc9bd3793cee25bce11c381fdae75ab2f3 100644 (file)
@@ -891,6 +891,9 @@ static struct pcmcia_device_id hostap_cs_ids[] = {
        PCMCIA_DEVICE_PROD_ID123(
                "The Linksys Group, Inc.", "Wireless Network CF Card", "ISL37300P",
                0xa5f472c2, 0x9c05598d, 0xc9049a39),
+       PCMCIA_DEVICE_PROD_ID123(
+               "Wireless LAN" , "11Mbps PC Card", "Version 01.02",
+               0x4b8870ff, 0x70e946d1, 0x4b74baa0),
        PCMCIA_DEVICE_NULL
 };
 MODULE_DEVICE_TABLE(pcmcia, hostap_cs_ids);
index 2ab107f457937b96b339711d6c7eaa6ffa8f79c0..5bf9e00b070c4478706ff094c8828c80b8efb7cd 100644 (file)
@@ -162,7 +162,7 @@ that only one external action is invoked at a time.
 #include <linux/firmware.h>
 #include <linux/acpi.h>
 #include <linux/ctype.h>
-#include <linux/latency.h>
+#include <linux/pm_qos_params.h>
 
 #include "ipw2100.h"
 
@@ -1701,7 +1701,7 @@ static int ipw2100_up(struct ipw2100_priv *priv, int deferred)
        /* the ipw2100 hardware really doesn't want power management delays
         * longer than 175usec
         */
-       modify_acceptable_latency("ipw2100", 175);
+       pm_qos_update_requirement(PM_QOS_CPU_DMA_LATENCY, "ipw2100", 175);
 
        /* If the interrupt is enabled, turn it off... */
        spin_lock_irqsave(&priv->low_lock, flags);
@@ -1856,7 +1856,8 @@ static void ipw2100_down(struct ipw2100_priv *priv)
        ipw2100_disable_interrupts(priv);
        spin_unlock_irqrestore(&priv->low_lock, flags);
 
-       modify_acceptable_latency("ipw2100", INFINITE_LATENCY);
+       pm_qos_update_requirement(PM_QOS_CPU_DMA_LATENCY, "ipw2100",
+                       PM_QOS_DEFAULT_VALUE);
 
        /* We have to signal any supplicant if we are disassociating */
        if (associated)
@@ -6554,7 +6555,8 @@ static int __init ipw2100_init(void)
        if (ret)
                goto out;
 
-       set_acceptable_latency("ipw2100", INFINITE_LATENCY);
+       pm_qos_add_requirement(PM_QOS_CPU_DMA_LATENCY, "ipw2100",
+                       PM_QOS_DEFAULT_VALUE);
 #ifdef CONFIG_IPW2100_DEBUG
        ipw2100_debug_level = debug;
        ret = driver_create_file(&ipw2100_pci_driver.driver,
@@ -6576,7 +6578,7 @@ static void __exit ipw2100_exit(void)
                           &driver_attr_debug_level);
 #endif
        pci_unregister_driver(&ipw2100_pci_driver);
-       remove_acceptable_latency("ipw2100");
+       pm_qos_remove_requirement(PM_QOS_CPU_DMA_LATENCY, "ipw2100");
 }
 
 module_init(ipw2100_init);
index 6e0187393af473f01df67b9a7817bca1371bf9e6..571815d7e8bf8909327e07f07453fd36396883e2 100644 (file)
@@ -373,7 +373,7 @@ struct iwl3945_eeprom {
 #define CSR_INT_BIT_HW_ERR       (1 << 29) /* DMA hardware error FH_INT[31] */
 #define CSR_INT_BIT_DNLD         (1 << 28) /* uCode Download */
 #define CSR_INT_BIT_FH_TX        (1 << 27) /* Tx DMA FH_INT[1:0] */
-#define CSR_INT_BIT_MAC_CLK_ACTV (1 << 26) /* NIC controller's clock toggled on/off */
+#define CSR_INT_BIT_SCD          (1 << 26) /* TXQ pointer advanced */
 #define CSR_INT_BIT_SW_ERR       (1 << 25) /* uCode error */
 #define CSR_INT_BIT_RF_KILL      (1 << 7)  /* HW RFKILL switch GP_CNTRL[27] toggled */
 #define CSR_INT_BIT_CT_KILL      (1 << 6)  /* Critical temp (chip too hot) rfkill */
index 76c4ed1135f272dd587e2ce44aa597689ad1e65f..8d4d91d35fd29f14ed3b8c21323da34c7122c264 100644 (file)
@@ -238,9 +238,10 @@ void iwl3945_hw_rx_statistics(struct iwl3945_priv *priv, struct iwl3945_rx_mem_b
        priv->last_statistics_time = jiffies;
 }
 
-void iwl3945_add_radiotap(struct iwl3945_priv *priv, struct sk_buff *skb,
-                         struct iwl3945_rx_frame_hdr *rx_hdr,
-                         struct ieee80211_rx_status *stats)
+static void iwl3945_add_radiotap(struct iwl3945_priv *priv,
+                                struct sk_buff *skb,
+                                struct iwl3945_rx_frame_hdr *rx_hdr,
+                                struct ieee80211_rx_status *stats)
 {
        /* First cache any information we need before we overwrite
         * the information provided in the skb from the hardware */
@@ -2369,18 +2370,4 @@ struct pci_device_id iwl3945_hw_card_ids[] = {
        {0}
 };
 
-/*
- * Clear the OWNER_MSK, to establish driver (instead of uCode running on
- * embedded controller) as EEPROM reader; each read is a series of pulses
- * to/from the EEPROM chip, not a single event, so even reads could conflict
- * if they weren't arbitrated by some ownership mechanism.  Here, the driver
- * simply claims ownership, which should be safe when this function is called
- * (i.e. before loading uCode!).
- */
-inline int iwl3945_eeprom_acquire_semaphore(struct iwl3945_priv *priv)
-{
-       _iwl3945_clear_bit(priv, CSR_EEPROM_GP, CSR_EEPROM_GP_IF_OWNER_MSK);
-       return 0;
-}
-
 MODULE_DEVICE_TABLE(pci, iwl3945_hw_card_ids);
index 20b925f57e355f2bd5fb36b1884aa5359ecf0d95..1da14f9bbe0f02fb1b2142f0ed1e0302bd86478b 100644 (file)
@@ -671,7 +671,6 @@ extern int iwl3945_hw_channel_switch(struct iwl3945_priv *priv, u16 channel);
 /*
  * Forward declare iwl-3945.c functions for iwl-base.c
  */
-extern int iwl3945_eeprom_acquire_semaphore(struct iwl3945_priv *priv);
 extern __le32 iwl3945_get_antenna_flags(const struct iwl3945_priv *priv);
 extern int iwl3945_init_hw_rate_table(struct iwl3945_priv *priv);
 extern void iwl3945_reg_txpower_periodic(struct iwl3945_priv *priv);
@@ -791,7 +790,6 @@ struct iwl3945_priv {
        u16 active_rate_basic;
 
        u8 call_post_assoc_from_beacon;
-       u8 assoc_station_added;
        /* Rate scaling data */
        s8 data_retry_limit;
        u8 retry_rate;
index ff71c09ab1a7f73d053e855ee17c2c3f03e8974f..ffe1e9dfdec7bc5da5b2e0c909a41f7f710c4a8d 100644 (file)
@@ -465,7 +465,7 @@ struct iwl4965_eeprom {
 #define CSR_INT_BIT_HW_ERR       (1 << 29) /* DMA hardware error FH_INT[31] */
 #define CSR_INT_BIT_DNLD         (1 << 28) /* uCode Download */
 #define CSR_INT_BIT_FH_TX        (1 << 27) /* Tx DMA FH_INT[1:0] */
-#define CSR_INT_BIT_MAC_CLK_ACTV (1 << 26) /* NIC controller's clock toggled on/off */
+#define CSR_INT_BIT_SCD          (1 << 26) /* TXQ pointer advanced */
 #define CSR_INT_BIT_SW_ERR       (1 << 25) /* uCode error */
 #define CSR_INT_BIT_RF_KILL      (1 << 7)  /* HW RFKILL switch GP_CNTRL[27] toggled */
 #define CSR_INT_BIT_CT_KILL      (1 << 6)  /* Critical temp (chip too hot) rfkill */
index 04db34ba814be632871270d17d890bf6e3cacaf6..d727de8b96fef956d3020bdde0428336ebb9d7a1 100644 (file)
@@ -4658,17 +4658,30 @@ void iwl4965_set_ht_add_station(struct iwl4965_priv *priv, u8 index,
                                struct ieee80211_ht_info *sta_ht_inf)
 {
        __le32 sta_flags;
+       u8 mimo_ps_mode;
 
        if (!sta_ht_inf || !sta_ht_inf->ht_supported)
                goto done;
 
+       mimo_ps_mode = (sta_ht_inf->cap & IEEE80211_HT_CAP_MIMO_PS) >> 2;
+
        sta_flags = priv->stations[index].sta.station_flags;
 
-       if (((sta_ht_inf->cap & IEEE80211_HT_CAP_MIMO_PS >> 2))
-                                               == IWL_MIMO_PS_DYNAMIC)
+       sta_flags &= ~(STA_FLG_RTS_MIMO_PROT_MSK | STA_FLG_MIMO_DIS_MSK);
+
+       switch (mimo_ps_mode) {
+       case WLAN_HT_CAP_MIMO_PS_STATIC:
+               sta_flags |= STA_FLG_MIMO_DIS_MSK;
+               break;
+       case WLAN_HT_CAP_MIMO_PS_DYNAMIC:
                sta_flags |= STA_FLG_RTS_MIMO_PROT_MSK;
-       else
-               sta_flags &= ~STA_FLG_RTS_MIMO_PROT_MSK;
+               break;
+       case WLAN_HT_CAP_MIMO_PS_DISABLED:
+               break;
+       default:
+               IWL_WARNING("Invalid MIMO PS mode %d", mimo_ps_mode);
+               break;
+       }
 
        sta_flags |= cpu_to_le32(
              (u32)sta_ht_inf->ampdu_factor << STA_FLG_MAX_AGG_SIZE_POS);
@@ -4679,7 +4692,7 @@ void iwl4965_set_ht_add_station(struct iwl4965_priv *priv, u8 index,
        if (iwl4965_is_fat_tx_allowed(priv, sta_ht_inf))
                sta_flags |= STA_FLG_FAT_EN_MSK;
        else
-               sta_flags &= (~STA_FLG_FAT_EN_MSK);
+               sta_flags &= ~STA_FLG_FAT_EN_MSK;
 
        priv->stations[index].sta.station_flags = sta_flags;
  done:
@@ -4961,11 +4974,4 @@ int iwl4965_eeprom_acquire_semaphore(struct iwl4965_priv *priv)
        return rc;
 }
 
-inline void iwl4965_eeprom_release_semaphore(struct iwl4965_priv *priv)
-{
-       iwl4965_clear_bit(priv, CSR_HW_IF_CONFIG_REG,
-               CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM);
-}
-
-
 MODULE_DEVICE_TABLE(pci, iwl4965_hw_card_ids);
index 78bc148c9f7f4c9cc1566790c52ce25f742ae573..9cb82be0ff80a19b0e5b7fa179625bcb2f21c086 100644 (file)
@@ -750,7 +750,6 @@ struct iwl4965_priv;
  * Forward declare iwl-4965.c functions for iwl-base.c
  */
 extern int iwl4965_eeprom_acquire_semaphore(struct iwl4965_priv *priv);
-extern void iwl4965_eeprom_release_semaphore(struct iwl4965_priv *priv);
 
 extern int iwl4965_tx_queue_update_wr_ptr(struct iwl4965_priv *priv,
                                          struct iwl4965_tx_queue *txq,
index cd2eb184831068c74d3318ab35681e326a6e849d..8993cca81b40c033cb561188aeb37210caaffa57 100644 (file)
@@ -147,9 +147,6 @@ static inline struct ieee80211_conf *ieee80211_get_hw_conf(
 
 #define QOS_CONTROL_LEN 2
 
-#define IEEE80211_STYPE_BACK_REQ       0x0080
-#define IEEE80211_STYPE_BACK           0x0090
-
 
 static inline int ieee80211_is_management(u16 fc)
 {
@@ -246,10 +243,10 @@ static inline int iwl_check_bits(unsigned long field, unsigned long mask)
 static inline unsigned long elapsed_jiffies(unsigned long start,
                                            unsigned long end)
 {
-       if (end > start)
+       if (end >= start)
                return end - start;
 
-       return end + (MAX_JIFFY_OFFSET - start);
+       return end + (MAX_JIFFY_OFFSET - start) + 1;
 }
 
 static inline u8 iwl_get_dma_hi_address(dma_addr_t addr)
index 748ac1222abb908d2c18a79c35a389a393bab250..f55c75712b555bfc179628964cff723cd6fa85ff 100644 (file)
@@ -1557,6 +1557,20 @@ static void get_eeprom_mac(struct iwl3945_priv *priv, u8 *mac)
        memcpy(mac, priv->eeprom.mac_address, 6);
 }
 
+/*
+ * Clear the OWNER_MSK, to establish driver (instead of uCode running on
+ * embedded controller) as EEPROM reader; each read is a series of pulses
+ * to/from the EEPROM chip, not a single event, so even reads could conflict
+ * if they weren't arbitrated by some ownership mechanism.  Here, the driver
+ * simply claims ownership, which should be safe when this function is called
+ * (i.e. before loading uCode!).
+ */
+static inline int iwl3945_eeprom_acquire_semaphore(struct iwl3945_priv *priv)
+{
+       _iwl3945_clear_bit(priv, CSR_EEPROM_GP, CSR_EEPROM_GP_IF_OWNER_MSK);
+       return 0;
+}
+
 /**
  * iwl3945_eeprom_init - read EEPROM contents
  *
@@ -2792,7 +2806,7 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv,
 #endif
 
        /* drop all data frame if we are not associated */
-       if (!iwl3945_is_associated(priv) && !priv->assoc_id &&
+       if ((!iwl3945_is_associated(priv) || !priv->assoc_id) &&
            ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA)) {
                IWL_DEBUG_DROP("Dropping - !iwl3945_is_associated\n");
                goto drop_unlock;
@@ -4745,8 +4759,9 @@ static void iwl3945_irq_tasklet(struct iwl3945_priv *priv)
 #ifdef CONFIG_IWL3945_DEBUG
        if (iwl3945_debug_level & (IWL_DL_ISR)) {
                /* NIC fires this, but we don't use it, redundant with WAKEUP */
-               if (inta & CSR_INT_BIT_MAC_CLK_ACTV)
-                       IWL_DEBUG_ISR("Microcode started or stopped.\n");
+               if (inta & CSR_INT_BIT_SCD)
+                       IWL_DEBUG_ISR("Scheduler finished to transmit "
+                                     "the frame/frames.\n");
 
                /* Alive notification via Rx interrupt will do the real work */
                if (inta & CSR_INT_BIT_ALIVE)
@@ -4754,7 +4769,7 @@ static void iwl3945_irq_tasklet(struct iwl3945_priv *priv)
        }
 #endif
        /* Safely ignore these bits for debug checks below */
-       inta &= ~(CSR_INT_BIT_MAC_CLK_ACTV | CSR_INT_BIT_ALIVE);
+       inta &= ~(CSR_INT_BIT_SCD | CSR_INT_BIT_ALIVE);
 
        /* HW RF KILL switch toggled (4965 only) */
        if (inta & CSR_INT_BIT_RF_KILL) {
@@ -4890,8 +4905,11 @@ static irqreturn_t iwl3945_isr(int irq, void *data)
        IWL_DEBUG_ISR("ISR inta 0x%08x, enabled 0x%08x, fh 0x%08x\n",
                      inta, inta_mask, inta_fh);
 
+       inta &= ~CSR_INT_BIT_SCD;
+
        /* iwl3945_irq_tasklet() will service interrupts and re-enable them */
-       tasklet_schedule(&priv->irq_tasklet);
+       if (likely(inta || inta_fh))
+               tasklet_schedule(&priv->irq_tasklet);
 unplugged:
        spin_unlock(&priv->lock);
 
@@ -5146,6 +5164,15 @@ static int iwl3945_init_channel_map(struct iwl3945_priv *priv)
        return 0;
 }
 
+/*
+ * iwl3945_free_channel_map - undo allocations in iwl3945_init_channel_map
+ */
+static void iwl3945_free_channel_map(struct iwl3945_priv *priv)
+{
+       kfree(priv->channel_info);
+       priv->channel_count = 0;
+}
+
 /* For active scan, listen ACTIVE_DWELL_TIME (msec) on each channel after
  * sending probe req.  This should be set long enough to hear probe responses
  * from more than one AP.  */
@@ -5471,6 +5498,17 @@ static int iwl3945_init_geos(struct iwl3945_priv *priv)
        return 0;
 }
 
+/*
+ * iwl3945_free_geos - undo allocations in iwl3945_init_geos
+ */
+static void iwl3945_free_geos(struct iwl3945_priv *priv)
+{
+       kfree(priv->modes);
+       kfree(priv->ieee_channels);
+       kfree(priv->ieee_rates);
+       clear_bit(STATUS_GEO_CONFIGURED, &priv->status);
+}
+
 /******************************************************************************
  *
  * uCode download functions
@@ -6130,15 +6168,6 @@ static void iwl3945_alive_start(struct iwl3945_priv *priv)
        /* Clear out the uCode error bit if it is set */
        clear_bit(STATUS_FW_ERROR, &priv->status);
 
-       rc = iwl3945_init_channel_map(priv);
-       if (rc) {
-               IWL_ERROR("initializing regulatory failed: %d\n", rc);
-               return;
-       }
-
-       iwl3945_init_geos(priv);
-       iwl3945_reset_channel_flag(priv);
-
        if (iwl3945_is_rfkill(priv))
                return;
 
@@ -6301,6 +6330,11 @@ static int __iwl3945_up(struct iwl3945_priv *priv)
                return -ENODEV;
        }
 
+       if (!priv->ucode_data_backup.v_addr || !priv->ucode_data.v_addr) {
+               IWL_ERROR("ucode not available for device bringup\n");
+               return -EIO;
+       }
+
        /* If platform's RF_KILL switch is NOT set to KILL */
        if (iwl3945_read32(priv, CSR_GP_CNTRL) &
                                CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)
@@ -6313,11 +6347,6 @@ static int __iwl3945_up(struct iwl3945_priv *priv)
                }
        }
 
-       if (!priv->ucode_data_backup.v_addr || !priv->ucode_data.v_addr) {
-               IWL_ERROR("ucode not available for device bringup\n");
-               return -EIO;
-       }
-
        iwl3945_write32(priv, CSR_INT, 0xFFFFFFFF);
 
        rc = iwl3945_hw_nic_init(priv);
@@ -6599,7 +6628,7 @@ static void iwl3945_bg_request_scan(struct work_struct *data)
         * that based on the direct_mask added to each channel entry */
        scan->tx_cmd.len = cpu_to_le16(
                iwl3945_fill_probe_req(priv, (struct ieee80211_mgmt *)scan->data,
-                       IWL_MAX_SCAN_SIZE - sizeof(scan), 0));
+                       IWL_MAX_SCAN_SIZE - sizeof(*scan), 0));
        scan->tx_cmd.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK;
        scan->tx_cmd.sta_id = priv->hw_setting.bcast_sta_id;
        scan->tx_cmd.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
@@ -7120,7 +7149,7 @@ static void iwl3945_config_ap(struct iwl3945_priv *priv)
 {
        int rc = 0;
 
-       if (priv->status & STATUS_EXIT_PENDING)
+       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
                return;
 
        /* The following should be done only at AP bring up */
@@ -8614,11 +8643,24 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
        IWL_DEBUG_INFO("MAC address: %s\n", print_mac(mac, priv->mac_addr));
        SET_IEEE80211_PERM_ADDR(priv->hw, priv->mac_addr);
 
+       err = iwl3945_init_channel_map(priv);
+       if (err) {
+               IWL_ERROR("initializing regulatory failed: %d\n", err);
+               goto out_remove_sysfs;
+       }
+
+       err = iwl3945_init_geos(priv);
+       if (err) {
+               IWL_ERROR("initializing geos failed: %d\n", err);
+               goto out_free_channel_map;
+       }
+       iwl3945_reset_channel_flag(priv);
+
        iwl3945_rate_control_register(priv->hw);
        err = ieee80211_register_hw(priv->hw);
        if (err) {
                IWL_ERROR("Failed to register network device (error %d)\n", err);
-               goto out_remove_sysfs;
+               goto out_free_geos;
        }
 
        priv->hw->conf.beacon_int = 100;
@@ -8628,6 +8670,10 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
 
        return 0;
 
+ out_free_geos:
+       iwl3945_free_geos(priv);
+ out_free_channel_map:
+       iwl3945_free_channel_map(priv);
  out_remove_sysfs:
        sysfs_remove_group(&pdev->dev.kobj, &iwl3945_attribute_group);
 
@@ -8702,10 +8748,8 @@ static void iwl3945_pci_remove(struct pci_dev *pdev)
        pci_disable_device(pdev);
        pci_set_drvdata(pdev, NULL);
 
-       kfree(priv->channel_info);
-
-       kfree(priv->ieee_channels);
-       kfree(priv->ieee_rates);
+       iwl3945_free_channel_map(priv);
+       iwl3945_free_geos(priv);
 
        if (priv->ibss_beacon)
                dev_kfree_skb(priv->ibss_beacon);
index c86da5cd1df19466fe230393a98e74e3475ede16..f423241b95674ad7cca340fa591f27c48a10bd13 100644 (file)
@@ -1639,6 +1639,12 @@ static void get_eeprom_mac(struct iwl4965_priv *priv, u8 *mac)
        memcpy(mac, priv->eeprom.mac_address, 6);
 }
 
+static inline void iwl4965_eeprom_release_semaphore(struct iwl4965_priv *priv)
+{
+       iwl4965_clear_bit(priv, CSR_HW_IF_CONFIG_REG,
+               CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM);
+}
+
 /**
  * iwl4965_eeprom_init - read EEPROM contents
  *
@@ -2927,8 +2933,10 @@ static int iwl4965_tx_skb(struct iwl4965_priv *priv,
 #endif
 
        /* drop all data frame if we are not associated */
-       if (!iwl4965_is_associated(priv) && !priv->assoc_id &&
-           ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA)) {
+       if (((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) &&
+          (!iwl4965_is_associated(priv) ||
+           !priv->assoc_id ||
+           !priv->assoc_station_added)) {
                IWL_DEBUG_DROP("Dropping - !iwl4965_is_associated\n");
                goto drop_unlock;
        }
@@ -5131,8 +5139,9 @@ static void iwl4965_irq_tasklet(struct iwl4965_priv *priv)
 #ifdef CONFIG_IWL4965_DEBUG
        if (iwl4965_debug_level & (IWL_DL_ISR)) {
                /* NIC fires this, but we don't use it, redundant with WAKEUP */
-               if (inta & CSR_INT_BIT_MAC_CLK_ACTV)
-                       IWL_DEBUG_ISR("Microcode started or stopped.\n");
+               if (inta & CSR_INT_BIT_SCD)
+                       IWL_DEBUG_ISR("Scheduler finished to transmit "
+                                     "the frame/frames.\n");
 
                /* Alive notification via Rx interrupt will do the real work */
                if (inta & CSR_INT_BIT_ALIVE)
@@ -5140,7 +5149,7 @@ static void iwl4965_irq_tasklet(struct iwl4965_priv *priv)
        }
 #endif
        /* Safely ignore these bits for debug checks below */
-       inta &= ~(CSR_INT_BIT_MAC_CLK_ACTV | CSR_INT_BIT_ALIVE);
+       inta &= ~(CSR_INT_BIT_SCD | CSR_INT_BIT_ALIVE);
 
        /* HW RF KILL switch toggled */
        if (inta & CSR_INT_BIT_RF_KILL) {
@@ -5269,8 +5278,11 @@ static irqreturn_t iwl4965_isr(int irq, void *data)
        IWL_DEBUG_ISR("ISR inta 0x%08x, enabled 0x%08x, fh 0x%08x\n",
                      inta, inta_mask, inta_fh);
 
+       inta &= ~CSR_INT_BIT_SCD;
+
        /* iwl4965_irq_tasklet() will service interrupts and re-enable them */
-       tasklet_schedule(&priv->irq_tasklet);
+       if (likely(inta || inta_fh))
+               tasklet_schedule(&priv->irq_tasklet);
 
  unplugged:
        spin_unlock(&priv->lock);
@@ -5576,6 +5588,15 @@ static int iwl4965_init_channel_map(struct iwl4965_priv *priv)
        return 0;
 }
 
+/*
+ * iwl4965_free_channel_map - undo allocations in iwl4965_init_channel_map
+ */
+static void iwl4965_free_channel_map(struct iwl4965_priv *priv)
+{
+       kfree(priv->channel_info);
+       priv->channel_count = 0;
+}
+
 /* For active scan, listen ACTIVE_DWELL_TIME (msec) on each channel after
  * sending probe req.  This should be set long enough to hear probe responses
  * from more than one AP.  */
@@ -5909,6 +5930,17 @@ static int iwl4965_init_geos(struct iwl4965_priv *priv)
        return 0;
 }
 
+/*
+ * iwl4965_free_geos - undo allocations in iwl4965_init_geos
+ */
+static void iwl4965_free_geos(struct iwl4965_priv *priv)
+{
+       kfree(priv->modes);
+       kfree(priv->ieee_channels);
+       kfree(priv->ieee_rates);
+       clear_bit(STATUS_GEO_CONFIGURED, &priv->status);
+}
+
 /******************************************************************************
  *
  * uCode download functions
@@ -6560,15 +6592,6 @@ static void iwl4965_alive_start(struct iwl4965_priv *priv)
        /* Clear out the uCode error bit if it is set */
        clear_bit(STATUS_FW_ERROR, &priv->status);
 
-       rc = iwl4965_init_channel_map(priv);
-       if (rc) {
-               IWL_ERROR("initializing regulatory failed: %d\n", rc);
-               return;
-       }
-
-       iwl4965_init_geos(priv);
-       iwl4965_reset_channel_flag(priv);
-
        if (iwl4965_is_rfkill(priv))
                return;
 
@@ -6732,6 +6755,11 @@ static int __iwl4965_up(struct iwl4965_priv *priv)
                return -ENODEV;
        }
 
+       if (!priv->ucode_data_backup.v_addr || !priv->ucode_data.v_addr) {
+               IWL_ERROR("ucode not available for device bringup\n");
+               return -EIO;
+       }
+
        /* If platform's RF_KILL switch is NOT set to KILL */
        if (iwl4965_read32(priv, CSR_GP_CNTRL) &
                                CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)
@@ -6744,11 +6772,6 @@ static int __iwl4965_up(struct iwl4965_priv *priv)
                }
        }
 
-       if (!priv->ucode_data_backup.v_addr || !priv->ucode_data.v_addr) {
-               IWL_ERROR("ucode not available for device bringup\n");
-               return -EIO;
-       }
-
        iwl4965_write32(priv, CSR_INT, 0xFFFFFFFF);
 
        rc = iwl4965_hw_nic_init(priv);
@@ -7023,7 +7046,7 @@ static void iwl4965_bg_request_scan(struct work_struct *data)
         * that based on the direct_mask added to each channel entry */
        scan->tx_cmd.len = cpu_to_le16(
                iwl4965_fill_probe_req(priv, (struct ieee80211_mgmt *)scan->data,
-                       IWL_MAX_SCAN_SIZE - sizeof(scan), 0));
+                       IWL_MAX_SCAN_SIZE - sizeof(*scan), 0));
        scan->tx_cmd.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK;
        scan->tx_cmd.sta_id = priv->hw_setting.bcast_sta_id;
        scan->tx_cmd.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
@@ -7448,7 +7471,7 @@ static int iwl4965_mac_add_interface(struct ieee80211_hw *hw,
 
        if (priv->vif) {
                IWL_DEBUG_MAC80211("leave - vif != NULL\n");
-               return 0;
+               return -EOPNOTSUPP;
        }
 
        spin_lock_irqsave(&priv->lock, flags);
@@ -7580,7 +7603,7 @@ static void iwl4965_config_ap(struct iwl4965_priv *priv)
 {
        int rc = 0;
 
-       if (priv->status & STATUS_EXIT_PENDING)
+       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
                return;
 
        /* The following should be done only at AP bring up */
@@ -9198,11 +9221,24 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
        IWL_DEBUG_INFO("MAC address: %s\n", print_mac(mac, priv->mac_addr));
        SET_IEEE80211_PERM_ADDR(priv->hw, priv->mac_addr);
 
+       err = iwl4965_init_channel_map(priv);
+       if (err) {
+               IWL_ERROR("initializing regulatory failed: %d\n", err);
+               goto out_remove_sysfs;
+       }
+
+       err = iwl4965_init_geos(priv);
+       if (err) {
+               IWL_ERROR("initializing geos failed: %d\n", err);
+               goto out_free_channel_map;
+       }
+       iwl4965_reset_channel_flag(priv);
+
        iwl4965_rate_control_register(priv->hw);
        err = ieee80211_register_hw(priv->hw);
        if (err) {
                IWL_ERROR("Failed to register network device (error %d)\n", err);
-               goto out_remove_sysfs;
+               goto out_free_geos;
        }
 
        priv->hw->conf.beacon_int = 100;
@@ -9212,6 +9248,10 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
 
        return 0;
 
+ out_free_geos:
+       iwl4965_free_geos(priv);
+ out_free_channel_map:
+       iwl4965_free_channel_map(priv);
  out_remove_sysfs:
        sysfs_remove_group(&pdev->dev.kobj, &iwl4965_attribute_group);
 
@@ -9286,10 +9326,8 @@ static void iwl4965_pci_remove(struct pci_dev *pdev)
        pci_disable_device(pdev);
        pci_set_drvdata(pdev, NULL);
 
-       kfree(priv->channel_info);
-
-       kfree(priv->ieee_channels);
-       kfree(priv->ieee_rates);
+       iwl4965_free_channel_map(priv);
+       iwl4965_free_geos(priv);
 
        if (priv->ibss_beacon)
                dev_kfree_skb(priv->ibss_beacon);
index c622e9b63cd1cc62a0233e9fb30a8d6ae1853440..87e145ffe8f1a6e72bd6cdf9045e2901b79b89d1 100644 (file)
 #include "cmd.h"
 
 
-static const u8 bssid_any[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
-static const u8 bssid_off[ETH_ALEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+static const u8 bssid_any[ETH_ALEN]  __attribute__ ((aligned (2))) =
+       { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
+static const u8 bssid_off[ETH_ALEN]  __attribute__ ((aligned (2))) =
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
 
 
 static int assoc_helper_essid(struct lbs_private *priv,
index 58d7ef6b5ff5b127591c65bd9d60ffb731c87e9d..5a69f2b608655aee1305177d11851047e589c222 100644 (file)
@@ -349,7 +349,7 @@ struct assoc_request {
        u8 channel;
        u8 band;
        u8 mode;
-       u8 bssid[ETH_ALEN];
+       u8 bssid[ETH_ALEN] __attribute__ ((aligned (2)));
 
        /** WEP keys */
        struct enc_key wep_keys[4];
index 4b5ab9a6b97b78687e56d1e5070addd9c7a1d8d9..5a9cadb97503fbf6ab8b4ba68a18d7da4a5e2ed6 100644 (file)
@@ -249,14 +249,14 @@ static irqreturn_t if_cs_interrupt(int irq, void *data)
        lbs_deb_enter(LBS_DEB_CS);
 
        int_cause = if_cs_read16(card, IF_CS_C_INT_CAUSE);
-       if(int_cause == 0x0) {
+       if (int_cause == 0x0) {
                /* Not for us */
                return IRQ_NONE;
 
        } else if (int_cause == 0xffff) {
                /* Read in junk, the card has probably been removed */
                card->priv->surpriseremoved = 1;
-
+               return IRQ_HANDLED;
        } else {
                if (int_cause & IF_CS_H_IC_TX_OVER)
                        lbs_host_to_card_done(card->priv);
@@ -717,8 +717,8 @@ static void if_cs_release(struct pcmcia_device *p_dev)
 
        lbs_deb_enter(LBS_DEB_CS);
 
-       pcmcia_disable_device(p_dev);
        free_irq(p_dev->irq.AssignedIRQ, card);
+       pcmcia_disable_device(p_dev);
        if (card->iobase)
                ioport_unmap(card->iobase);
 
index 9a61188b62e92cf2fe9984c5ca58f4ac8cbd8570..69f94c92b32d8986a5221658b180d09c94b0a6d7 100644 (file)
@@ -1473,7 +1473,7 @@ int lbs_get_scan(struct net_device *dev, struct iw_request_info *info,
  *  Called via lbs_prepare_and_send_command(priv, CMD_802_11_SCAN, ...)
  *  from cmd.c
  *
- *  Sends a fixed lenght data part (specifying the BSS type and BSSID filters)
+ *  Sends a fixed length data part (specifying the BSS type and BSSID filters)
  *  as well as a variable number/length of TLVs to the firmware.
  *
  *  @param priv       A pointer to struct lbs_private structure
index d2fa079fbc4c140f0719192d73a984be10f0cd65..f479c1af67822dfdf3813c22e8e9f60846401da7 100644 (file)
@@ -195,7 +195,7 @@ static int netwave_pcmcia_config(struct pcmcia_device *arg); /* Runs after card
 static void netwave_detach(struct pcmcia_device *p_dev);    /* Destroy instance */
 
 /* Hardware configuration */
-static void netwave_doreset(kio_addr_t iobase, u_char __iomem *ramBase);
+static void netwave_doreset(unsigned int iobase, u_char __iomem *ramBase);
 static void netwave_reset(struct net_device *dev);
 
 /* Misc device stuff */
@@ -309,7 +309,7 @@ static inline void wait_WOC(unsigned int iobase)
 }
 
 static void netwave_snapshot(netwave_private *priv, u_char __iomem *ramBase, 
-                            kio_addr_t iobase) {
+                            unsigned int iobase) {
     u_short resultBuffer;
 
     /* if time since last snapshot is > 1 sec. (100 jiffies?)  then take 
@@ -340,7 +340,7 @@ static void netwave_snapshot(netwave_private *priv, u_char __iomem *ramBase,
 static struct iw_statistics *netwave_get_wireless_stats(struct net_device *dev)
 {      
     unsigned long flags;
-    kio_addr_t iobase = dev->base_addr;
+    unsigned int iobase = dev->base_addr;
     netwave_private *priv = netdev_priv(dev);
     u_char __iomem *ramBase = priv->ramBase;
     struct iw_statistics* wstats;
@@ -471,7 +471,7 @@ static int netwave_set_nwid(struct net_device *dev,
                            char *extra)
 {
        unsigned long flags;
-       kio_addr_t iobase = dev->base_addr;
+       unsigned int iobase = dev->base_addr;
        netwave_private *priv = netdev_priv(dev);
        u_char __iomem *ramBase = priv->ramBase;
 
@@ -518,7 +518,7 @@ static int netwave_set_scramble(struct net_device *dev,
                                char *key)
 {
        unsigned long flags;
-       kio_addr_t iobase = dev->base_addr;
+       unsigned int iobase = dev->base_addr;
        netwave_private *priv = netdev_priv(dev);
        u_char __iomem *ramBase = priv->ramBase;
 
@@ -621,7 +621,7 @@ static int netwave_get_snap(struct net_device *dev,
                            char *extra)
 {
        unsigned long flags;
-       kio_addr_t iobase = dev->base_addr;
+       unsigned int iobase = dev->base_addr;
        netwave_private *priv = netdev_priv(dev);
        u_char __iomem *ramBase = priv->ramBase;
 
@@ -874,7 +874,7 @@ static int netwave_resume(struct pcmcia_device *link)
  *
  *    Proper hardware reset of the card.
  */
-static void netwave_doreset(kio_addr_t ioBase, u_char __iomem *ramBase)
+static void netwave_doreset(unsigned int ioBase, u_char __iomem *ramBase)
 {
     /* Reset card */
     wait_WOC(ioBase);
@@ -892,7 +892,7 @@ static void netwave_reset(struct net_device *dev) {
     /* u_char state; */
     netwave_private *priv = netdev_priv(dev);
     u_char __iomem *ramBase = priv->ramBase;
-    kio_addr_t iobase = dev->base_addr;
+    unsigned int iobase = dev->base_addr;
 
     DEBUG(0, "netwave_reset: Done with hardware reset\n");
 
@@ -973,7 +973,7 @@ static int netwave_hw_xmit(unsigned char* data, int len,
        
     netwave_private *priv = netdev_priv(dev);
     u_char __iomem * ramBase = priv->ramBase;
-    kio_addr_t iobase = dev->base_addr;
+    unsigned int iobase = dev->base_addr;
 
     /* Disable interrupts & save flags */
     spin_lock_irqsave(&priv->spinlock, flags);
@@ -1065,7 +1065,7 @@ static int netwave_start_xmit(struct sk_buff *skb, struct net_device *dev) {
  */
 static irqreturn_t netwave_interrupt(int irq, void* dev_id)
 {
-    kio_addr_t iobase;
+    unsigned int iobase;
     u_char __iomem *ramBase;
     struct net_device *dev = (struct net_device *)dev_id;
     struct netwave_private *priv = netdev_priv(dev);
@@ -1235,7 +1235,7 @@ static int netwave_rx(struct net_device *dev)
 {
     netwave_private *priv = netdev_priv(dev);
     u_char __iomem *ramBase = priv->ramBase;
-    kio_addr_t iobase = dev->base_addr;
+    unsigned int iobase = dev->base_addr;
     u_char rxStatus;
     struct sk_buff *skb = NULL;
     unsigned int curBuffer,
@@ -1388,7 +1388,7 @@ module_exit(exit_netwave_cs);
  */
 static void set_multicast_list(struct net_device *dev)
 {
-    kio_addr_t iobase = dev->base_addr;
+    unsigned int iobase = dev->base_addr;
     netwave_private *priv = netdev_priv(dev);
     u_char __iomem * ramBase = priv->ramBase;
     u_char  rcvMode = 0;
diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c
new file mode 100644 (file)
index 0000000..d3ecf89
--- /dev/null
@@ -0,0 +1,2757 @@
+/*
+ * Driver for RNDIS based wireless USB devices.
+ *
+ * Copyright (C) 2007 by Bjorge Dijkstra <bjd@jooz.net>
+ * Copyright (C) 2008 by Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ *  Portions of this file are based on NDISwrapper project,
+ *  Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani
+ *  http://ndiswrapper.sourceforge.net/
+ */
+
+// #define     DEBUG                   // error path messages, extra info
+// #define     VERBOSE                 // more; success messages
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/workqueue.h>
+#include <linux/mutex.h>
+#include <linux/mii.h>
+#include <linux/usb.h>
+#include <linux/usb/cdc.h>
+#include <linux/wireless.h>
+#include <linux/if_arp.h>
+#include <linux/ctype.h>
+#include <linux/spinlock.h>
+#include <net/iw_handler.h>
+#include <net/ieee80211.h>
+#include <linux/usb/usbnet.h>
+#include <linux/usb/rndis_host.h>
+
+
+/* NOTE: All these are settings for Broadcom chipset */
+static char modparam_country[4] = "EU";
+module_param_string(country, modparam_country, 4, 0444);
+MODULE_PARM_DESC(country, "Country code (ISO 3166-1 alpha-2), default: EU");
+
+static int modparam_frameburst = 1;
+module_param_named(frameburst, modparam_frameburst, int, 0444);
+MODULE_PARM_DESC(frameburst, "enable frame bursting (default: on)");
+
+static int modparam_afterburner = 0;
+module_param_named(afterburner, modparam_afterburner, int, 0444);
+MODULE_PARM_DESC(afterburner,
+       "enable afterburner aka '125 High Speed Mode' (default: off)");
+
+static int modparam_power_save = 0;
+module_param_named(power_save, modparam_power_save, int, 0444);
+MODULE_PARM_DESC(power_save,
+       "set power save mode: 0=off, 1=on, 2=fast (default: off)");
+
+static int modparam_power_output = 3;
+module_param_named(power_output, modparam_power_output, int, 0444);
+MODULE_PARM_DESC(power_output,
+       "set power output: 0=25%, 1=50%, 2=75%, 3=100% (default: 100%)");
+
+static int modparam_roamtrigger = -70;
+module_param_named(roamtrigger, modparam_roamtrigger, int, 0444);
+MODULE_PARM_DESC(roamtrigger,
+       "set roaming dBm trigger: -80=optimize for distance, "
+                               "-60=bandwidth (default: -70)");
+
+static int modparam_roamdelta = 1;
+module_param_named(roamdelta, modparam_roamdelta, int, 0444);
+MODULE_PARM_DESC(roamdelta,
+       "set roaming tendency: 0=aggressive, 1=moderate, "
+                               "2=conservative (default: moderate)");
+
+static int modparam_workaround_interval = 500;
+module_param_named(workaround_interval, modparam_workaround_interval,
+                                                       int, 0444);
+MODULE_PARM_DESC(workaround_interval,
+       "set stall workaround interval in msecs (default: 500)");
+
+
+/* various RNDIS OID defs */
+#define OID_GEN_LINK_SPEED                     ccpu2(0x00010107)
+#define OID_GEN_RNDIS_CONFIG_PARAMETER         ccpu2(0x0001021b)
+
+#define OID_GEN_XMIT_OK                                ccpu2(0x00020101)
+#define OID_GEN_RCV_OK                         ccpu2(0x00020102)
+#define OID_GEN_XMIT_ERROR                     ccpu2(0x00020103)
+#define OID_GEN_RCV_ERROR                      ccpu2(0x00020104)
+#define OID_GEN_RCV_NO_BUFFER                  ccpu2(0x00020105)
+
+#define OID_802_3_PERMANENT_ADDRESS            ccpu2(0x01010101)
+#define OID_802_3_CURRENT_ADDRESS              ccpu2(0x01010102)
+#define OID_802_3_MULTICAST_LIST               ccpu2(0x01010103)
+#define OID_802_3_MAXIMUM_LIST_SIZE            ccpu2(0x01010104)
+
+#define OID_802_11_BSSID                       ccpu2(0x0d010101)
+#define OID_802_11_SSID                                ccpu2(0x0d010102)
+#define OID_802_11_INFRASTRUCTURE_MODE         ccpu2(0x0d010108)
+#define OID_802_11_ADD_WEP                     ccpu2(0x0d010113)
+#define OID_802_11_REMOVE_WEP                  ccpu2(0x0d010114)
+#define OID_802_11_DISASSOCIATE                        ccpu2(0x0d010115)
+#define OID_802_11_AUTHENTICATION_MODE         ccpu2(0x0d010118)
+#define OID_802_11_PRIVACY_FILTER              ccpu2(0x0d010119)
+#define OID_802_11_BSSID_LIST_SCAN             ccpu2(0x0d01011a)
+#define OID_802_11_ENCRYPTION_STATUS           ccpu2(0x0d01011b)
+#define OID_802_11_ADD_KEY                     ccpu2(0x0d01011d)
+#define OID_802_11_REMOVE_KEY                  ccpu2(0x0d01011e)
+#define OID_802_11_PMKID                       ccpu2(0x0d010123)
+#define OID_802_11_NETWORK_TYPES_SUPPORTED     ccpu2(0x0d010203)
+#define OID_802_11_NETWORK_TYPE_IN_USE         ccpu2(0x0d010204)
+#define OID_802_11_TX_POWER_LEVEL              ccpu2(0x0d010205)
+#define OID_802_11_RSSI                                ccpu2(0x0d010206)
+#define OID_802_11_RSSI_TRIGGER                        ccpu2(0x0d010207)
+#define OID_802_11_FRAGMENTATION_THRESHOLD     ccpu2(0x0d010209)
+#define OID_802_11_RTS_THRESHOLD               ccpu2(0x0d01020a)
+#define OID_802_11_SUPPORTED_RATES             ccpu2(0x0d01020e)
+#define OID_802_11_CONFIGURATION               ccpu2(0x0d010211)
+#define OID_802_11_BSSID_LIST                  ccpu2(0x0d010217)
+
+
+/* Typical noise/maximum signal level values taken from ndiswrapper iw_ndis.h */
+#define        WL_NOISE        -96     /* typical noise level in dBm */
+#define        WL_SIGMAX       -32     /* typical maximum signal level in dBm */
+
+
+/* Assume that Broadcom 4320 (only chipset at time of writing known to be
+ * based on wireless rndis) has default txpower of 13dBm.
+ * This value is from Linksys WUSB54GSC User Guide, Appendix F: Specifications.
+ *   13dBm == 19.9mW
+ */
+#define BCM4320_DEFAULT_TXPOWER 20
+
+
+/* codes for "status" field of completion messages */
+#define RNDIS_STATUS_ADAPTER_NOT_READY         ccpu2(0xc0010011)
+#define RNDIS_STATUS_ADAPTER_NOT_OPEN          ccpu2(0xc0010012)
+
+
+/* NDIS data structures. Taken from wpa_supplicant driver_ndis.c
+ * slightly modified for datatype endianess, etc
+ */
+#define NDIS_802_11_LENGTH_SSID 32
+#define NDIS_802_11_LENGTH_RATES 8
+#define NDIS_802_11_LENGTH_RATES_EX 16
+
+struct NDIS_802_11_SSID {
+       __le32 SsidLength;
+       u8 Ssid[NDIS_802_11_LENGTH_SSID];
+} __attribute__((packed));
+
+enum NDIS_802_11_NETWORK_TYPE {
+       Ndis802_11FH,
+       Ndis802_11DS,
+       Ndis802_11OFDM5,
+       Ndis802_11OFDM24,
+       Ndis802_11NetworkTypeMax
+};
+
+struct NDIS_802_11_CONFIGURATION_FH {
+       __le32 Length;
+       __le32 HopPattern;
+       __le32 HopSet;
+       __le32 DwellTime;
+} __attribute__((packed));
+
+struct NDIS_802_11_CONFIGURATION {
+       __le32 Length;
+       __le32 BeaconPeriod;
+       __le32 ATIMWindow;
+       __le32 DSConfig;
+       struct NDIS_802_11_CONFIGURATION_FH FHConfig;
+} __attribute__((packed));
+
+enum NDIS_802_11_NETWORK_INFRASTRUCTURE {
+       Ndis802_11IBSS,
+       Ndis802_11Infrastructure,
+       Ndis802_11AutoUnknown,
+       Ndis802_11InfrastructureMax
+};
+
+enum NDIS_802_11_AUTHENTICATION_MODE {
+       Ndis802_11AuthModeOpen,
+       Ndis802_11AuthModeShared,
+       Ndis802_11AuthModeAutoSwitch,
+       Ndis802_11AuthModeWPA,
+       Ndis802_11AuthModeWPAPSK,
+       Ndis802_11AuthModeWPANone,
+       Ndis802_11AuthModeWPA2,
+       Ndis802_11AuthModeWPA2PSK,
+       Ndis802_11AuthModeMax
+};
+
+enum NDIS_802_11_ENCRYPTION_STATUS {
+       Ndis802_11WEPEnabled,
+       Ndis802_11Encryption1Enabled = Ndis802_11WEPEnabled,
+       Ndis802_11WEPDisabled,
+       Ndis802_11EncryptionDisabled = Ndis802_11WEPDisabled,
+       Ndis802_11WEPKeyAbsent,
+       Ndis802_11Encryption1KeyAbsent = Ndis802_11WEPKeyAbsent,
+       Ndis802_11WEPNotSupported,
+       Ndis802_11EncryptionNotSupported = Ndis802_11WEPNotSupported,
+       Ndis802_11Encryption2Enabled,
+       Ndis802_11Encryption2KeyAbsent,
+       Ndis802_11Encryption3Enabled,
+       Ndis802_11Encryption3KeyAbsent
+};
+
+enum NDIS_802_11_PRIVACY_FILTER {
+       Ndis802_11PrivFilterAcceptAll,
+       Ndis802_11PrivFilter8021xWEP
+};
+
+struct NDIS_WLAN_BSSID_EX {
+       __le32 Length;
+       u8 MacAddress[6];
+       u8 Padding[2];
+       struct NDIS_802_11_SSID Ssid;
+       __le32 Privacy;
+       __le32 Rssi;
+       enum NDIS_802_11_NETWORK_TYPE NetworkTypeInUse;
+       struct NDIS_802_11_CONFIGURATION Configuration;
+       enum NDIS_802_11_NETWORK_INFRASTRUCTURE InfrastructureMode;
+       u8 SupportedRates[NDIS_802_11_LENGTH_RATES_EX];
+       __le32 IELength;
+       u8 IEs[0];
+} __attribute__((packed));
+
+struct NDIS_802_11_BSSID_LIST_EX {
+       __le32 NumberOfItems;
+       struct NDIS_WLAN_BSSID_EX Bssid[0];
+} __attribute__((packed));
+
+struct NDIS_802_11_FIXED_IEs {
+       u8 Timestamp[8];
+       __le16 BeaconInterval;
+       __le16 Capabilities;
+} __attribute__((packed));
+
+struct NDIS_802_11_WEP {
+       __le32 Length;
+       __le32 KeyIndex;
+       __le32 KeyLength;
+       u8 KeyMaterial[32];
+} __attribute__((packed));
+
+struct NDIS_802_11_KEY {
+       __le32 Length;
+       __le32 KeyIndex;
+       __le32 KeyLength;
+       u8 Bssid[6];
+       u8 Padding[6];
+       __le64 KeyRSC;
+       u8 KeyMaterial[32];
+} __attribute__((packed));
+
+struct NDIS_802_11_REMOVE_KEY {
+       __le32 Length;
+       __le32 KeyIndex;
+       u8 Bssid[6];
+} __attribute__((packed));
+
+struct RNDIS_CONFIG_PARAMETER_INFOBUFFER {
+       __le32 ParameterNameOffset;
+       __le32 ParameterNameLength;
+       __le32 ParameterType;
+       __le32 ParameterValueOffset;
+       __le32 ParameterValueLength;
+} __attribute__((packed));
+
+/* these have to match what is in wpa_supplicant */
+enum { WPA_ALG_NONE, WPA_ALG_WEP, WPA_ALG_TKIP, WPA_ALG_CCMP } wpa_alg;
+enum { CIPHER_NONE, CIPHER_WEP40, CIPHER_TKIP, CIPHER_CCMP, CIPHER_WEP104 }
+       wpa_cipher;
+enum { KEY_MGMT_802_1X, KEY_MGMT_PSK, KEY_MGMT_NONE, KEY_MGMT_802_1X_NO_WPA,
+       KEY_MGMT_WPA_NONE } wpa_key_mgmt;
+
+/*
+ *  private data
+ */
+#define NET_TYPE_11FB  0
+
+#define CAP_MODE_80211A                1
+#define CAP_MODE_80211B                2
+#define CAP_MODE_80211G                4
+#define CAP_MODE_MASK          7
+#define CAP_SUPPORT_TXPOWER    8
+
+#define WORK_CONNECTION_EVENT  (1<<0)
+#define WORK_SET_MULTICAST_LIST        (1<<1)
+
+/* RNDIS device private data */
+struct rndis_wext_private {
+       char name[32];
+
+       struct usbnet *usbdev;
+
+       struct workqueue_struct *workqueue;
+       struct delayed_work stats_work;
+       struct work_struct work;
+       struct mutex command_lock;
+       spinlock_t stats_lock;
+       unsigned long work_pending;
+
+       struct iw_statistics iwstats;
+       struct iw_statistics privstats;
+
+       int  nick_len;
+       char nick[32];
+
+       int caps;
+       int multicast_size;
+
+       /* module parameters */
+       char param_country[4];
+       int  param_frameburst;
+       int  param_afterburner;
+       int  param_power_save;
+       int  param_power_output;
+       int  param_roamtrigger;
+       int  param_roamdelta;
+       u32  param_workaround_interval;
+
+       /* hardware state */
+       int radio_on;
+       int infra_mode;
+       struct NDIS_802_11_SSID essid;
+
+       /* encryption stuff */
+       int  encr_tx_key_index;
+       char encr_keys[4][32];
+       int  encr_key_len[4];
+       int  wpa_version;
+       int  wpa_keymgmt;
+       int  wpa_authalg;
+       int  wpa_ie_len;
+       u8  *wpa_ie;
+       int  wpa_cipher_pair;
+       int  wpa_cipher_group;
+};
+
+
+static const int freq_chan[] = { 2412, 2417, 2422, 2427, 2432, 2437, 2442,
+                               2447, 2452, 2457, 2462, 2467, 2472, 2484 };
+
+static const int rates_80211g[8] = { 6, 9, 12, 18, 24, 36, 48, 54 };
+
+static const int bcm4320_power_output[4] = { 25, 50, 75, 100 };
+
+static const unsigned char zero_bssid[ETH_ALEN] = {0,};
+static const unsigned char ffff_bssid[ETH_ALEN] = { 0xff, 0xff, 0xff,
+                                                       0xff, 0xff, 0xff };
+
+
+static struct rndis_wext_private *get_rndis_wext_priv(struct usbnet *dev)
+{
+       return (struct rndis_wext_private *)dev->driver_priv;
+}
+
+
+static u32 get_bcm4320_power(struct rndis_wext_private *priv)
+{
+       return BCM4320_DEFAULT_TXPOWER *
+               bcm4320_power_output[priv->param_power_output] / 100;
+}
+
+
+/* translate error code */
+static int rndis_error_status(__le32 rndis_status)
+{
+       int ret = -EINVAL;
+       switch (rndis_status) {
+       case RNDIS_STATUS_SUCCESS:
+               ret = 0;
+               break;
+       case RNDIS_STATUS_FAILURE:
+       case RNDIS_STATUS_INVALID_DATA:
+               ret = -EINVAL;
+               break;
+       case RNDIS_STATUS_NOT_SUPPORTED:
+               ret = -EOPNOTSUPP;
+               break;
+       case RNDIS_STATUS_ADAPTER_NOT_READY:
+       case RNDIS_STATUS_ADAPTER_NOT_OPEN:
+               ret = -EBUSY;
+               break;
+       }
+       return ret;
+}
+
+
+static int rndis_query_oid(struct usbnet *dev, __le32 oid, void *data, int *len)
+{
+       struct rndis_wext_private *priv = get_rndis_wext_priv(dev);
+       union {
+               void                    *buf;
+               struct rndis_msg_hdr    *header;
+               struct rndis_query      *get;
+               struct rndis_query_c    *get_c;
+       } u;
+       int ret, buflen;
+
+       buflen = *len + sizeof(*u.get);
+       if (buflen < CONTROL_BUFFER_SIZE)
+               buflen = CONTROL_BUFFER_SIZE;
+       u.buf = kmalloc(buflen, GFP_KERNEL);
+       if (!u.buf)
+               return -ENOMEM;
+       memset(u.get, 0, sizeof *u.get);
+       u.get->msg_type = RNDIS_MSG_QUERY;
+       u.get->msg_len = ccpu2(sizeof *u.get);
+       u.get->oid = oid;
+
+       mutex_lock(&priv->command_lock);
+       ret = rndis_command(dev, u.header);
+       mutex_unlock(&priv->command_lock);
+
+       if (ret == 0) {
+               ret = le32_to_cpu(u.get_c->len);
+               *len = (*len > ret) ? ret : *len;
+               memcpy(data, u.buf + le32_to_cpu(u.get_c->offset) + 8, *len);
+               ret = rndis_error_status(u.get_c->status);
+       }
+
+       kfree(u.buf);
+       return ret;
+}
+
+
+static int rndis_set_oid(struct usbnet *dev, __le32 oid, void *data, int len)
+{
+       struct rndis_wext_private *priv = get_rndis_wext_priv(dev);
+       union {
+               void                    *buf;
+               struct rndis_msg_hdr    *header;
+               struct rndis_set        *set;
+               struct rndis_set_c      *set_c;
+       } u;
+       int ret, buflen;
+
+       buflen = len + sizeof(*u.set);
+       if (buflen < CONTROL_BUFFER_SIZE)
+               buflen = CONTROL_BUFFER_SIZE;
+       u.buf = kmalloc(buflen, GFP_KERNEL);
+       if (!u.buf)
+               return -ENOMEM;
+
+       memset(u.set, 0, sizeof *u.set);
+       u.set->msg_type = RNDIS_MSG_SET;
+       u.set->msg_len = cpu_to_le32(sizeof(*u.set) + len);
+       u.set->oid = oid;
+       u.set->len = cpu_to_le32(len);
+       u.set->offset = ccpu2(sizeof(*u.set) - 8);
+       u.set->handle = ccpu2(0);
+       memcpy(u.buf + sizeof(*u.set), data, len);
+
+       mutex_lock(&priv->command_lock);
+       ret = rndis_command(dev, u.header);
+       mutex_unlock(&priv->command_lock);
+
+       if (ret == 0)
+               ret = rndis_error_status(u.set_c->status);
+
+       kfree(u.buf);
+       return ret;
+}
+
+
+/*
+ * Specs say that we can only set config parameters only soon after device
+ * initialization.
+ *   value_type: 0 = u32, 2 = unicode string
+ */
+static int rndis_set_config_parameter(struct usbnet *dev, char *param,
+                                               int value_type, void *value)
+{
+       struct RNDIS_CONFIG_PARAMETER_INFOBUFFER *infobuf;
+       int value_len, info_len, param_len, ret, i;
+       __le16 *unibuf;
+       __le32 *dst_value;
+
+       if (value_type == 0)
+               value_len = sizeof(__le32);
+       else if (value_type == 2)
+               value_len = strlen(value) * sizeof(__le16);
+       else
+               return -EINVAL;
+
+       param_len = strlen(param) * sizeof(__le16);
+       info_len = sizeof(*infobuf) + param_len + value_len;
+
+#ifdef DEBUG
+       info_len += 12;
+#endif
+       infobuf = kmalloc(info_len, GFP_KERNEL);
+       if (!infobuf)
+               return -ENOMEM;
+
+#ifdef DEBUG
+       info_len -= 12;
+       /* extra 12 bytes are for padding (debug output) */
+       memset(infobuf, 0xCC, info_len + 12);
+#endif
+
+       if (value_type == 2)
+               devdbg(dev, "setting config parameter: %s, value: %s",
+                                               param, (u8 *)value);
+       else
+               devdbg(dev, "setting config parameter: %s, value: %d",
+                                               param, *(u32 *)value);
+
+       infobuf->ParameterNameOffset = cpu_to_le32(sizeof(*infobuf));
+       infobuf->ParameterNameLength = cpu_to_le32(param_len);
+       infobuf->ParameterType = cpu_to_le32(value_type);
+       infobuf->ParameterValueOffset = cpu_to_le32(sizeof(*infobuf) +
+                                                               param_len);
+       infobuf->ParameterValueLength = cpu_to_le32(value_len);
+
+       /* simple string to unicode string conversion */
+       unibuf = (void *)infobuf + sizeof(*infobuf);
+       for (i = 0; i < param_len / sizeof(__le16); i++)
+               unibuf[i] = cpu_to_le16(param[i]);
+
+       if (value_type == 2) {
+               unibuf = (void *)infobuf + sizeof(*infobuf) + param_len;
+               for (i = 0; i < value_len / sizeof(__le16); i++)
+                       unibuf[i] = cpu_to_le16(((u8 *)value)[i]);
+       } else {
+               dst_value = (void *)infobuf + sizeof(*infobuf) + param_len;
+               *dst_value = cpu_to_le32(*(u32 *)value);
+       }
+
+#ifdef DEBUG
+       devdbg(dev, "info buffer (len: %d):", info_len);
+       for (i = 0; i < info_len; i += 12) {
+               u32 *tmp = (u32 *)((u8 *)infobuf + i);
+               devdbg(dev, "%08X:%08X:%08X",
+                       cpu_to_be32(tmp[0]),
+                       cpu_to_be32(tmp[1]),
+                       cpu_to_be32(tmp[2]));
+       }
+#endif
+
+       ret = rndis_set_oid(dev, OID_GEN_RNDIS_CONFIG_PARAMETER,
+                                                       infobuf, info_len);
+       if (ret != 0)
+               devdbg(dev, "setting rndis config paramater failed, %d.", ret);
+
+       kfree(infobuf);
+       return ret;
+}
+
+static int rndis_set_config_parameter_str(struct usbnet *dev,
+                                               char *param, char *value)
+{
+       return(rndis_set_config_parameter(dev, param, 2, value));
+}
+
+/*static int rndis_set_config_parameter_u32(struct usbnet *dev,
+                                               char *param, u32 value)
+{
+       return(rndis_set_config_parameter(dev, param, 0, &value));
+}*/
+
+
+/*
+ * data conversion functions
+ */
+static int level_to_qual(int level)
+{
+       int qual = 100 * (level - WL_NOISE) / (WL_SIGMAX - WL_NOISE);
+       return qual >= 0 ? (qual <= 100 ? qual : 100) : 0;
+}
+
+
+static void dsconfig_to_freq(unsigned int dsconfig, struct iw_freq *freq)
+{
+       freq->e = 0;
+       freq->i = 0;
+       freq->flags = 0;
+
+       /* see comment in wireless.h above the "struct iw_freq"
+        * definition for an explanation of this if
+        * NOTE: 1000000 is due to the kHz
+        */
+       if (dsconfig > 1000000) {
+               freq->m = dsconfig / 10;
+               freq->e = 1;
+       } else
+               freq->m = dsconfig;
+
+       /* convert from kHz to Hz */
+       freq->e += 3;
+}
+
+
+static int freq_to_dsconfig(struct iw_freq *freq, unsigned int *dsconfig)
+{
+       if (freq->m < 1000 && freq->e == 0) {
+               if (freq->m >= 1 &&
+                       freq->m <= (sizeof(freq_chan) / sizeof(freq_chan[0])))
+                       *dsconfig = freq_chan[freq->m - 1] * 1000;
+               else
+                       return -1;
+       } else {
+               int i;
+               *dsconfig = freq->m;
+               for (i = freq->e; i > 0; i--)
+                       *dsconfig *= 10;
+               *dsconfig /= 1000;
+       }
+
+       return 0;
+}
+
+
+/*
+ * common functions
+ */
+static int
+add_wep_key(struct usbnet *usbdev, char *key, int key_len, int index);
+
+static int get_essid(struct usbnet *usbdev, struct NDIS_802_11_SSID *ssid)
+{
+       int ret, len;
+
+       len = sizeof(*ssid);
+       ret = rndis_query_oid(usbdev, OID_802_11_SSID, ssid, &len);
+
+       if (ret != 0)
+               ssid->SsidLength = 0;
+
+#ifdef DEBUG
+       {
+               unsigned char tmp[NDIS_802_11_LENGTH_SSID + 1];
+
+               memcpy(tmp, ssid->Ssid, le32_to_cpu(ssid->SsidLength));
+               tmp[le32_to_cpu(ssid->SsidLength)] = 0;
+               devdbg(usbdev, "get_essid: '%s', ret: %d", tmp, ret);
+       }
+#endif
+       return ret;
+}
+
+
+static int set_essid(struct usbnet *usbdev, struct NDIS_802_11_SSID *ssid)
+{
+       struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
+       int ret;
+
+       ret = rndis_set_oid(usbdev, OID_802_11_SSID, ssid, sizeof(*ssid));
+       if (ret == 0) {
+               memcpy(&priv->essid, ssid, sizeof(priv->essid));
+               priv->radio_on = 1;
+               devdbg(usbdev, "set_essid: radio_on = 1");
+       }
+
+       return ret;
+}
+
+
+static int get_bssid(struct usbnet *usbdev, u8 bssid[ETH_ALEN])
+{
+       int ret, len;
+
+       len = ETH_ALEN;
+       ret = rndis_query_oid(usbdev, OID_802_11_BSSID, bssid, &len);
+
+       if (ret != 0)
+               memset(bssid, 0, ETH_ALEN);
+
+       return ret;
+}
+
+
+static int is_associated(struct usbnet *usbdev)
+{
+       u8 bssid[ETH_ALEN];
+       int ret;
+
+       ret = get_bssid(usbdev, bssid);
+
+       return(ret == 0 && memcmp(bssid, zero_bssid, ETH_ALEN) != 0);
+}
+
+
+static int disassociate(struct usbnet *usbdev, int reset_ssid)
+{
+       struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
+       struct NDIS_802_11_SSID ssid;
+       int i, ret = 0;
+
+       if (priv->radio_on) {
+               ret = rndis_set_oid(usbdev, OID_802_11_DISASSOCIATE, NULL, 0);
+               if (ret == 0) {
+                       priv->radio_on = 0;
+                       devdbg(usbdev, "disassociate: radio_on = 0");
+
+                       if (reset_ssid)
+                               msleep(100);
+               }
+       }
+
+       /* disassociate causes radio to be turned off; if reset_ssid
+        * is given, set random ssid to enable radio */
+       if (reset_ssid) {
+               ssid.SsidLength = cpu_to_le32(sizeof(ssid.Ssid));
+               get_random_bytes(&ssid.Ssid[2], sizeof(ssid.Ssid)-2);
+               ssid.Ssid[0] = 0x1;
+               ssid.Ssid[1] = 0xff;
+               for (i = 2; i < sizeof(ssid.Ssid); i++)
+                       ssid.Ssid[i] = 0x1 + (ssid.Ssid[i] * 0xfe / 0xff);
+               ret = set_essid(usbdev, &ssid);
+       }
+       return ret;
+}
+
+
+static int set_auth_mode(struct usbnet *usbdev, int wpa_version, int authalg)
+{
+       struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
+       __le32 tmp;
+       int auth_mode, ret;
+
+       devdbg(usbdev, "set_auth_mode: wpa_version=0x%x authalg=0x%x "
+               "keymgmt=0x%x", wpa_version, authalg, priv->wpa_keymgmt);
+
+       if (wpa_version & IW_AUTH_WPA_VERSION_WPA2) {
+               if (priv->wpa_keymgmt & IW_AUTH_KEY_MGMT_802_1X)
+                       auth_mode = Ndis802_11AuthModeWPA2;
+               else
+                       auth_mode = Ndis802_11AuthModeWPA2PSK;
+       } else if (wpa_version & IW_AUTH_WPA_VERSION_WPA) {
+               if (priv->wpa_keymgmt & IW_AUTH_KEY_MGMT_802_1X)
+                       auth_mode = Ndis802_11AuthModeWPA;
+               else if (priv->wpa_keymgmt & IW_AUTH_KEY_MGMT_PSK)
+                       auth_mode = Ndis802_11AuthModeWPAPSK;
+               else
+                       auth_mode = Ndis802_11AuthModeWPANone;
+       } else if (authalg & IW_AUTH_ALG_SHARED_KEY) {
+               if (authalg & IW_AUTH_ALG_OPEN_SYSTEM)
+                       auth_mode = Ndis802_11AuthModeAutoSwitch;
+               else
+                       auth_mode = Ndis802_11AuthModeShared;
+       } else
+               auth_mode = Ndis802_11AuthModeOpen;
+
+       tmp = cpu_to_le32(auth_mode);
+       ret = rndis_set_oid(usbdev, OID_802_11_AUTHENTICATION_MODE, &tmp,
+                                                               sizeof(tmp));
+       if (ret != 0) {
+               devwarn(usbdev, "setting auth mode failed (%08X)", ret);
+               return ret;
+       }
+
+       priv->wpa_version = wpa_version;
+       priv->wpa_authalg = authalg;
+       return 0;
+}
+
+
+static int set_priv_filter(struct usbnet *usbdev)
+{
+       struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
+       __le32 tmp;
+
+       devdbg(usbdev, "set_priv_filter: wpa_version=0x%x", priv->wpa_version);
+
+       if (priv->wpa_version & IW_AUTH_WPA_VERSION_WPA2 ||
+           priv->wpa_version & IW_AUTH_WPA_VERSION_WPA)
+               tmp = cpu_to_le32(Ndis802_11PrivFilter8021xWEP);
+       else
+               tmp = cpu_to_le32(Ndis802_11PrivFilterAcceptAll);
+
+       return rndis_set_oid(usbdev, OID_802_11_PRIVACY_FILTER, &tmp,
+                                                               sizeof(tmp));
+}
+
+
+static int set_encr_mode(struct usbnet *usbdev, int pairwise, int groupwise)
+{
+       struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
+       __le32 tmp;
+       int encr_mode, ret;
+
+       devdbg(usbdev, "set_encr_mode: cipher_pair=0x%x cipher_group=0x%x",
+               pairwise,
+               groupwise);
+
+       if (pairwise & IW_AUTH_CIPHER_CCMP)
+               encr_mode = Ndis802_11Encryption3Enabled;
+       else if (pairwise & IW_AUTH_CIPHER_TKIP)
+               encr_mode = Ndis802_11Encryption2Enabled;
+       else if (pairwise &
+                (IW_AUTH_CIPHER_WEP40 | IW_AUTH_CIPHER_WEP104))
+               encr_mode = Ndis802_11Encryption1Enabled;
+       else if (groupwise & IW_AUTH_CIPHER_CCMP)
+               encr_mode = Ndis802_11Encryption3Enabled;
+       else if (groupwise & IW_AUTH_CIPHER_TKIP)
+               encr_mode = Ndis802_11Encryption2Enabled;
+       else
+               encr_mode = Ndis802_11EncryptionDisabled;
+
+       tmp = cpu_to_le32(encr_mode);
+       ret = rndis_set_oid(usbdev, OID_802_11_ENCRYPTION_STATUS, &tmp,
+                                                               sizeof(tmp));
+       if (ret != 0) {
+               devwarn(usbdev, "setting encr mode failed (%08X)", ret);
+               return ret;
+       }
+
+       priv->wpa_cipher_pair = pairwise;
+       priv->wpa_cipher_group = groupwise;
+       return 0;
+}
+
+
+static int set_assoc_params(struct usbnet *usbdev)
+{
+       struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
+
+       set_auth_mode(usbdev, priv->wpa_version, priv->wpa_authalg);
+       set_priv_filter(usbdev);
+       set_encr_mode(usbdev, priv->wpa_cipher_pair, priv->wpa_cipher_group);
+
+       return 0;
+}
+
+
+static int set_infra_mode(struct usbnet *usbdev, int mode)
+{
+       struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
+       __le32 tmp;
+       int ret, i;
+
+       devdbg(usbdev, "set_infra_mode: infra_mode=0x%x", priv->infra_mode);
+
+       tmp = cpu_to_le32(mode);
+       ret = rndis_set_oid(usbdev, OID_802_11_INFRASTRUCTURE_MODE, &tmp,
+                                                               sizeof(tmp));
+       if (ret != 0) {
+               devwarn(usbdev, "setting infra mode failed (%08X)", ret);
+               return ret;
+       }
+
+       /* NDIS drivers clear keys when infrastructure mode is
+        * changed. But Linux tools assume otherwise. So set the
+        * keys */
+       if (priv->wpa_keymgmt == 0 ||
+               priv->wpa_keymgmt == IW_AUTH_KEY_MGMT_802_1X) {
+               for (i = 0; i < 4; i++) {
+                       if (priv->encr_key_len[i] > 0)
+                               add_wep_key(usbdev, priv->encr_keys[i],
+                                               priv->encr_key_len[i], i);
+               }
+       }
+
+       priv->infra_mode = mode;
+       return 0;
+}
+
+
+static void set_default_iw_params(struct usbnet *usbdev)
+{
+       struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
+
+       priv->wpa_keymgmt = 0;
+       priv->wpa_version = 0;
+
+       set_infra_mode(usbdev, Ndis802_11Infrastructure);
+       set_auth_mode(usbdev, IW_AUTH_WPA_VERSION_DISABLED,
+                               IW_AUTH_ALG_OPEN_SYSTEM);
+       set_priv_filter(usbdev);
+       set_encr_mode(usbdev, IW_AUTH_CIPHER_NONE, IW_AUTH_CIPHER_NONE);
+}
+
+
+static int deauthenticate(struct usbnet *usbdev)
+{
+       int ret;
+
+       ret = disassociate(usbdev, 1);
+       set_default_iw_params(usbdev);
+       return ret;
+}
+
+
+/* index must be 0 - N, as per NDIS  */
+static int add_wep_key(struct usbnet *usbdev, char *key, int key_len, int index)
+{
+       struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
+       struct NDIS_802_11_WEP ndis_key;
+       int ret;
+
+       if (key_len <= 0 || key_len > 32 || index < 0 || index >= 4)
+               return -EINVAL;
+
+       memset(&ndis_key, 0, sizeof(ndis_key));
+
+       ndis_key.Length = cpu_to_le32(sizeof(ndis_key));
+       ndis_key.KeyLength = cpu_to_le32(key_len);
+       ndis_key.KeyIndex = cpu_to_le32(index);
+       memcpy(&ndis_key.KeyMaterial, key, key_len);
+
+       if (index == priv->encr_tx_key_index) {
+               ndis_key.KeyIndex |= cpu_to_le32(1 << 31);
+               ret = set_encr_mode(usbdev, IW_AUTH_CIPHER_WEP104,
+                                               IW_AUTH_CIPHER_NONE);
+               if (ret)
+                       devwarn(usbdev, "encryption couldn't be enabled (%08X)",
+                                                                       ret);
+       }
+
+       ret = rndis_set_oid(usbdev, OID_802_11_ADD_WEP, &ndis_key,
+                                                       sizeof(ndis_key));
+       if (ret != 0) {
+               devwarn(usbdev, "adding encryption key %d failed (%08X)",
+                                                       index+1, ret);
+               return ret;
+       }
+
+       priv->encr_key_len[index] = key_len;
+       memcpy(&priv->encr_keys[index], key, key_len);
+
+       return 0;
+}
+
+
+/* remove_key is for both wep and wpa */
+static int remove_key(struct usbnet *usbdev, int index, u8 bssid[ETH_ALEN])
+{
+       struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
+       struct NDIS_802_11_REMOVE_KEY remove_key;
+       __le32 keyindex;
+       int ret;
+
+       if (priv->encr_key_len[index] == 0)
+               return 0;
+
+       priv->encr_key_len[index] = 0;
+       memset(&priv->encr_keys[index], 0, sizeof(priv->encr_keys[index]));
+
+       if (priv->wpa_cipher_pair == IW_AUTH_CIPHER_TKIP ||
+           priv->wpa_cipher_pair == IW_AUTH_CIPHER_CCMP ||
+           priv->wpa_cipher_group == IW_AUTH_CIPHER_TKIP ||
+           priv->wpa_cipher_group == IW_AUTH_CIPHER_CCMP) {
+               remove_key.Length = cpu_to_le32(sizeof(remove_key));
+               remove_key.KeyIndex = cpu_to_le32(index);
+               if (bssid) {
+                       /* pairwise key */
+                       if (memcmp(bssid, ffff_bssid, ETH_ALEN) != 0)
+                               remove_key.KeyIndex |= cpu_to_le32(1 << 30);
+                       memcpy(remove_key.Bssid, bssid,
+                                       sizeof(remove_key.Bssid));
+               } else
+                       memset(remove_key.Bssid, 0xff,
+                                               sizeof(remove_key.Bssid));
+
+               ret = rndis_set_oid(usbdev, OID_802_11_REMOVE_KEY, &remove_key,
+                                                       sizeof(remove_key));
+               if (ret != 0)
+                       return ret;
+       } else {
+               keyindex = cpu_to_le32(index);
+               ret = rndis_set_oid(usbdev, OID_802_11_REMOVE_WEP, &keyindex,
+                                                       sizeof(keyindex));
+               if (ret != 0) {
+                       devwarn(usbdev,
+                               "removing encryption key %d failed (%08X)",
+                               index, ret);
+                       return ret;
+               }
+       }
+
+       /* if it is transmit key, disable encryption */
+       if (index == priv->encr_tx_key_index)
+               set_encr_mode(usbdev, IW_AUTH_CIPHER_NONE, IW_AUTH_CIPHER_NONE);
+
+       return 0;
+}
+
+
+static void set_multicast_list(struct usbnet *usbdev)
+{
+       struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
+       struct dev_mc_list *mclist;
+       __le32 filter;
+       int ret, i, size;
+       char *buf;
+
+       filter = RNDIS_PACKET_TYPE_DIRECTED | RNDIS_PACKET_TYPE_BROADCAST;
+
+       if (usbdev->net->flags & IFF_PROMISC) {
+               filter |= RNDIS_PACKET_TYPE_PROMISCUOUS |
+                       RNDIS_PACKET_TYPE_ALL_LOCAL;
+       } else if (usbdev->net->flags & IFF_ALLMULTI ||
+                  usbdev->net->mc_count > priv->multicast_size) {
+               filter |= RNDIS_PACKET_TYPE_ALL_MULTICAST;
+       } else if (usbdev->net->mc_count > 0) {
+               size = min(priv->multicast_size, usbdev->net->mc_count);
+               buf = kmalloc(size * ETH_ALEN, GFP_KERNEL);
+               if (!buf) {
+                       devwarn(usbdev,
+                               "couldn't alloc %d bytes of memory",
+                               size * ETH_ALEN);
+                       return;
+               }
+
+               mclist = usbdev->net->mc_list;
+               for (i = 0; i < size && mclist; mclist = mclist->next) {
+                       if (mclist->dmi_addrlen != ETH_ALEN)
+                               continue;
+
+                       memcpy(buf + i * ETH_ALEN, mclist->dmi_addr, ETH_ALEN);
+                       i++;
+               }
+
+               ret = rndis_set_oid(usbdev, OID_802_3_MULTICAST_LIST, buf,
+                                                               i * ETH_ALEN);
+               if (ret == 0 && i > 0)
+                       filter |= RNDIS_PACKET_TYPE_MULTICAST;
+               else
+                       filter |= RNDIS_PACKET_TYPE_ALL_MULTICAST;
+
+               devdbg(usbdev, "OID_802_3_MULTICAST_LIST(%d, max: %d) -> %d",
+                                               i, priv->multicast_size, ret);
+
+               kfree(buf);
+       }
+
+       ret = rndis_set_oid(usbdev, OID_GEN_CURRENT_PACKET_FILTER, &filter,
+                                                       sizeof(filter));
+       if (ret < 0) {
+               devwarn(usbdev, "couldn't set packet filter: %08x",
+                                                       le32_to_cpu(filter));
+       }
+
+       devdbg(usbdev, "OID_GEN_CURRENT_PACKET_FILTER(%08x) -> %d",
+                                               le32_to_cpu(filter), ret);
+}
+
+
+/*
+ * wireless extension handlers
+ */
+
+static int rndis_iw_commit(struct net_device *dev,
+    struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
+{
+       /* dummy op */
+       return 0;
+}
+
+
+static int rndis_iw_get_range(struct net_device *dev,
+    struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
+{
+       struct iw_range *range = (struct iw_range *)extra;
+       struct usbnet *usbdev = dev->priv;
+       struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
+       int len, ret, i, j, num, has_80211g_rates;
+       u8 rates[8];
+       __le32 tx_power;
+
+       devdbg(usbdev, "SIOCGIWRANGE");
+
+       /* clear iw_range struct */
+       memset(range, 0, sizeof(*range));
+       wrqu->data.length = sizeof(*range);
+
+       range->txpower_capa = IW_TXPOW_MWATT;
+       range->num_txpower = 1;
+       if (priv->caps & CAP_SUPPORT_TXPOWER) {
+               len = sizeof(tx_power);
+               ret = rndis_query_oid(usbdev, OID_802_11_TX_POWER_LEVEL,
+                                               &tx_power, &len);
+               if (ret == 0 && le32_to_cpu(tx_power) != 0xFF)
+                       range->txpower[0] = le32_to_cpu(tx_power);
+               else
+                       range->txpower[0] = get_bcm4320_power(priv);
+       } else
+               range->txpower[0] = get_bcm4320_power(priv);
+
+       len = sizeof(rates);
+       ret = rndis_query_oid(usbdev, OID_802_11_SUPPORTED_RATES, &rates,
+                                                               &len);
+       has_80211g_rates = 0;
+       if (ret == 0) {
+               j = 0;
+               for (i = 0; i < len; i++) {
+                       if (rates[i] == 0)
+                               break;
+                       range->bitrate[j] = (rates[i] & 0x7f) * 500000;
+                       /* check for non 802.11b rates */
+                       if (range->bitrate[j] == 6000000 ||
+                               range->bitrate[j] == 9000000 ||
+                               (range->bitrate[j] >= 12000000 &&
+                               range->bitrate[j] != 22000000))
+                               has_80211g_rates = 1;
+                       j++;
+               }
+               range->num_bitrates = j;
+       } else
+               range->num_bitrates = 0;
+
+       /* fill in 802.11g rates */
+       if (has_80211g_rates) {
+               num = range->num_bitrates;
+               for (i = 0; i < sizeof(rates_80211g); i++) {
+                       for (j = 0; j < num; j++) {
+                               if (range->bitrate[j] ==
+                                       rates_80211g[i] * 1000000)
+                                       break;
+                       }
+                       if (j == num)
+                               range->bitrate[range->num_bitrates++] =
+                                       rates_80211g[i] * 1000000;
+                       if (range->num_bitrates == IW_MAX_BITRATES)
+                               break;
+               }
+
+               /* estimated max real througput in bps */
+               range->throughput = 54 * 1000 * 1000 / 2;
+
+               /* ~35% more with afterburner */
+               if (priv->param_afterburner)
+                       range->throughput = range->throughput / 100 * 135;
+       } else {
+               /* estimated max real througput in bps */
+               range->throughput = 11 * 1000 * 1000 / 2;
+       }
+
+       range->num_channels = (sizeof(freq_chan)/sizeof(freq_chan[0]));
+
+       for (i = 0; i < (sizeof(freq_chan)/sizeof(freq_chan[0])) &&
+                       i < IW_MAX_FREQUENCIES; i++) {
+               range->freq[i].i = i + 1;
+               range->freq[i].m = freq_chan[i] * 100000;
+               range->freq[i].e = 1;
+       }
+       range->num_frequency = i;
+
+       range->min_rts = 0;
+       range->max_rts = 2347;
+       range->min_frag = 256;
+       range->max_frag = 2346;
+
+       range->max_qual.qual = 100;
+       range->max_qual.level = 154;
+       range->max_qual.updated = IW_QUAL_QUAL_UPDATED
+                               | IW_QUAL_LEVEL_UPDATED
+                               | IW_QUAL_NOISE_INVALID;
+
+       range->we_version_compiled = WIRELESS_EXT;
+       range->we_version_source = WIRELESS_EXT;
+
+       range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 |
+                       IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP;
+       return 0;
+}
+
+
+static int rndis_iw_get_name(struct net_device *dev,
+    struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
+{
+       struct usbnet *usbdev = dev->priv;
+       struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
+
+       strcpy(wrqu->name, priv->name);
+       return 0;
+}
+
+
+static int rndis_iw_set_essid(struct net_device *dev,
+    struct iw_request_info *info, union iwreq_data *wrqu, char *essid)
+{
+       struct NDIS_802_11_SSID ssid;
+       int length = wrqu->essid.length;
+       struct usbnet *usbdev = dev->priv;
+
+       devdbg(usbdev, "SIOCSIWESSID: [flags:%d,len:%d] '%.32s'",
+               wrqu->essid.flags, wrqu->essid.length, essid);
+
+       if (length > NDIS_802_11_LENGTH_SSID)
+               length = NDIS_802_11_LENGTH_SSID;
+
+       ssid.SsidLength = cpu_to_le32(length);
+       if (length > 0)
+               memcpy(ssid.Ssid, essid, length);
+       else
+               memset(ssid.Ssid, 0, NDIS_802_11_LENGTH_SSID);
+
+       set_assoc_params(usbdev);
+
+       if (!wrqu->essid.flags || length == 0)
+               return disassociate(usbdev, 1);
+       else
+               return set_essid(usbdev, &ssid);
+}
+
+
+static int rndis_iw_get_essid(struct net_device *dev,
+    struct iw_request_info *info, union iwreq_data *wrqu, char *essid)
+{
+       struct NDIS_802_11_SSID ssid;
+       struct usbnet *usbdev = dev->priv;
+       int ret;
+
+       ret = get_essid(usbdev, &ssid);
+
+       if (ret == 0 && le32_to_cpu(ssid.SsidLength) > 0) {
+               wrqu->essid.flags = 1;
+               wrqu->essid.length = le32_to_cpu(ssid.SsidLength);
+               memcpy(essid, ssid.Ssid, wrqu->essid.length);
+               essid[wrqu->essid.length] = 0;
+       } else {
+               memset(essid, 0, sizeof(NDIS_802_11_LENGTH_SSID));
+               wrqu->essid.flags = 0;
+               wrqu->essid.length = 0;
+       }
+       devdbg(usbdev, "SIOCGIWESSID: %s", essid);
+       return ret;
+}
+
+
+static int rndis_iw_get_bssid(struct net_device *dev,
+    struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
+{
+       struct usbnet *usbdev = dev->priv;
+       unsigned char bssid[ETH_ALEN];
+       int ret;
+       DECLARE_MAC_BUF(mac);
+
+       ret = get_bssid(usbdev, bssid);
+
+       if (ret == 0)
+               devdbg(usbdev, "SIOCGIWAP: %s", print_mac(mac, bssid));
+       else
+               devdbg(usbdev, "SIOCGIWAP: <not associated>");
+
+       wrqu->ap_addr.sa_family = ARPHRD_ETHER;
+       memcpy(wrqu->ap_addr.sa_data, bssid, ETH_ALEN);
+
+       return ret;
+}
+
+
+static int rndis_iw_set_bssid(struct net_device *dev,
+    struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
+{
+       struct usbnet *usbdev = dev->priv;
+       u8 *bssid = (u8 *)wrqu->ap_addr.sa_data;
+       DECLARE_MAC_BUF(mac);
+       int ret;
+
+       devdbg(usbdev, "SIOCSIWAP: %s", print_mac(mac, bssid));
+
+       ret = rndis_set_oid(usbdev, OID_802_11_BSSID, bssid, ETH_ALEN);
+
+       /* user apps may set ap's mac address, which is not required;
+        * they may fail to work if this function fails, so return
+        * success */
+       if (ret)
+               devwarn(usbdev, "setting AP mac address failed (%08X)", ret);
+
+       return 0;
+}
+
+
+static int rndis_iw_set_auth(struct net_device *dev,
+    struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
+{
+       struct iw_param *p = &wrqu->param;
+       struct usbnet *usbdev = dev->priv;
+       struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
+       int ret = -ENOTSUPP;
+
+       switch (p->flags & IW_AUTH_INDEX) {
+       case IW_AUTH_WPA_VERSION:
+               devdbg(usbdev, "SIOCSIWAUTH: WPA_VERSION, %08x", p->value);
+               priv->wpa_version = p->value;
+               ret = 0;
+               break;
+
+       case IW_AUTH_CIPHER_PAIRWISE:
+               devdbg(usbdev, "SIOCSIWAUTH: CIPHER_PAIRWISE, %08x", p->value);
+               priv->wpa_cipher_pair = p->value;
+               ret = 0;
+               break;
+
+       case IW_AUTH_CIPHER_GROUP:
+               devdbg(usbdev, "SIOCSIWAUTH: CIPHER_GROUP, %08x", p->value);
+               priv->wpa_cipher_group = p->value;
+               ret = 0;
+               break;
+
+       case IW_AUTH_KEY_MGMT:
+               devdbg(usbdev, "SIOCSIWAUTH: KEY_MGMT, %08x", p->value);
+               priv->wpa_keymgmt = p->value;
+               ret = 0;
+               break;
+
+       case IW_AUTH_TKIP_COUNTERMEASURES:
+               devdbg(usbdev, "SIOCSIWAUTH: TKIP_COUNTERMEASURES, %08x",
+                                                               p->value);
+               ret = 0;
+               break;
+
+       case IW_AUTH_DROP_UNENCRYPTED:
+               devdbg(usbdev, "SIOCSIWAUTH: DROP_UNENCRYPTED, %08x", p->value);
+               ret = 0;
+               break;
+
+       case IW_AUTH_80211_AUTH_ALG:
+               devdbg(usbdev, "SIOCSIWAUTH: 80211_AUTH_ALG, %08x", p->value);
+               priv->wpa_authalg = p->value;
+               ret = 0;
+               break;
+
+       case IW_AUTH_WPA_ENABLED:
+               devdbg(usbdev, "SIOCSIWAUTH: WPA_ENABLED, %08x", p->value);
+               if (wrqu->param.value)
+                       deauthenticate(usbdev);
+               ret = 0;
+               break;
+
+       case IW_AUTH_RX_UNENCRYPTED_EAPOL:
+               devdbg(usbdev, "SIOCSIWAUTH: RX_UNENCRYPTED_EAPOL, %08x",
+                                                               p->value);
+               ret = 0;
+               break;
+
+       case IW_AUTH_ROAMING_CONTROL:
+               devdbg(usbdev, "SIOCSIWAUTH: ROAMING_CONTROL, %08x", p->value);
+               ret = 0;
+               break;
+
+       case IW_AUTH_PRIVACY_INVOKED:
+               devdbg(usbdev, "SIOCSIWAUTH: invalid cmd %d",
+                               wrqu->param.flags & IW_AUTH_INDEX);
+               return -EOPNOTSUPP;
+
+       default:
+               devdbg(usbdev, "SIOCSIWAUTH: UNKNOWN  %08x, %08x",
+                       p->flags & IW_AUTH_INDEX, p->value);
+       }
+       return ret;
+}
+
+
+static int rndis_iw_get_auth(struct net_device *dev,
+    struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
+{
+       struct iw_param *p = &wrqu->param;
+       struct usbnet *usbdev = dev->priv;
+       struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
+
+       switch (p->flags & IW_AUTH_INDEX) {
+       case IW_AUTH_WPA_VERSION:
+               p->value = priv->wpa_version;
+               break;
+       case IW_AUTH_CIPHER_PAIRWISE:
+               p->value = priv->wpa_cipher_pair;
+               break;
+       case IW_AUTH_CIPHER_GROUP:
+               p->value = priv->wpa_cipher_group;
+               break;
+       case IW_AUTH_KEY_MGMT:
+               p->value = priv->wpa_keymgmt;
+               break;
+       case IW_AUTH_80211_AUTH_ALG:
+               p->value = priv->wpa_authalg;
+               break;
+       default:
+               devdbg(usbdev, "SIOCGIWAUTH: invalid cmd %d",
+                               wrqu->param.flags & IW_AUTH_INDEX);
+               return -EOPNOTSUPP;
+       }
+       return 0;
+}
+
+
+static int rndis_iw_get_mode(struct net_device *dev,
+                               struct iw_request_info *info,
+                               union iwreq_data *wrqu, char *extra)
+{
+       struct usbnet *usbdev = dev->priv;
+       struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
+
+       switch (priv->infra_mode) {
+       case Ndis802_11IBSS:
+               wrqu->mode = IW_MODE_ADHOC;
+               break;
+       case Ndis802_11Infrastructure:
+               wrqu->mode = IW_MODE_INFRA;
+               break;
+       /*case Ndis802_11AutoUnknown:*/
+       default:
+               wrqu->mode = IW_MODE_AUTO;
+               break;
+       }
+       devdbg(usbdev, "SIOCGIWMODE: %08x", wrqu->mode);
+       return 0;
+}
+
+
+static int rndis_iw_set_mode(struct net_device *dev,
+    struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
+{
+       struct usbnet *usbdev = dev->priv;
+       int mode;
+
+       devdbg(usbdev, "SIOCSIWMODE: %08x", wrqu->mode);
+
+       switch (wrqu->mode) {
+       case IW_MODE_ADHOC:
+               mode = Ndis802_11IBSS;
+               break;
+       case IW_MODE_INFRA:
+               mode = Ndis802_11Infrastructure;
+               break;
+       /*case IW_MODE_AUTO:*/
+       default:
+               mode = Ndis802_11AutoUnknown;
+               break;
+       }
+
+       return set_infra_mode(usbdev, mode);
+}
+
+
+static int rndis_iw_set_encode(struct net_device *dev,
+    struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
+{
+       struct usbnet *usbdev = dev->priv;
+       struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
+       int ret, index, key_len;
+       u8 *key;
+
+       index = (wrqu->encoding.flags & IW_ENCODE_INDEX);
+
+       /* iwconfig gives index as 1 - N */
+       if (index > 0)
+               index--;
+       else
+               index = priv->encr_tx_key_index;
+
+       if (index < 0 || index >= 4) {
+               devwarn(usbdev, "encryption index out of range (%u)", index);
+               return -EINVAL;
+       }
+
+       /* remove key if disabled */
+       if (wrqu->data.flags & IW_ENCODE_DISABLED) {
+               if (remove_key(usbdev, index, NULL))
+                       return -EINVAL;
+               else
+                       return 0;
+       }
+
+       /* global encryption state (for all keys) */
+       if (wrqu->data.flags & IW_ENCODE_OPEN)
+               ret = set_auth_mode(usbdev, IW_AUTH_WPA_VERSION_DISABLED,
+                                               IW_AUTH_ALG_OPEN_SYSTEM);
+       else /*if (wrqu->data.flags & IW_ENCODE_RESTRICTED)*/
+               ret = set_auth_mode(usbdev, IW_AUTH_WPA_VERSION_DISABLED,
+                                               IW_AUTH_ALG_SHARED_KEY);
+       if (ret != 0)
+               return ret;
+
+       if (wrqu->data.length > 0) {
+               key_len = wrqu->data.length;
+               key = extra;
+       } else {
+               /* must be set as tx key */
+               if (priv->encr_key_len[index] == 0)
+                       return -EINVAL;
+               key_len = priv->encr_key_len[index];
+               key = priv->encr_keys[index];
+               priv->encr_tx_key_index = index;
+       }
+
+       if (add_wep_key(usbdev, key, key_len, index) != 0)
+               return -EINVAL;
+
+       if (index == priv->encr_tx_key_index)
+               /* ndis drivers want essid to be set after setting encr */
+               set_essid(usbdev, &priv->essid);
+
+       return 0;
+}
+
+
+static int rndis_iw_set_encode_ext(struct net_device *dev,
+    struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
+{
+       struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
+       struct usbnet *usbdev = dev->priv;
+       struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
+       struct NDIS_802_11_KEY ndis_key;
+       int i, keyidx, ret;
+       u8 *addr;
+
+       keyidx = wrqu->encoding.flags & IW_ENCODE_INDEX;
+
+       /* iwconfig gives index as 1 - N */
+       if (keyidx)
+               keyidx--;
+       else
+               keyidx = priv->encr_tx_key_index;
+
+       if (keyidx < 0 || keyidx >= 4)
+               return -EINVAL;
+
+       if (ext->alg == WPA_ALG_WEP) {
+               if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY)
+                       priv->encr_tx_key_index = keyidx;
+               return add_wep_key(usbdev, ext->key, ext->key_len, keyidx);
+       }
+
+       if ((wrqu->encoding.flags & IW_ENCODE_DISABLED) ||
+           ext->alg == IW_ENCODE_ALG_NONE || ext->key_len == 0)
+               return remove_key(usbdev, keyidx, NULL);
+
+       if (ext->key_len > sizeof(ndis_key.KeyMaterial))
+               return -1;
+
+       memset(&ndis_key, 0, sizeof(ndis_key));
+
+       ndis_key.Length = cpu_to_le32(sizeof(ndis_key) -
+                               sizeof(ndis_key.KeyMaterial) + ext->key_len);
+       ndis_key.KeyLength = cpu_to_le32(ext->key_len);
+       ndis_key.KeyIndex = cpu_to_le32(keyidx);
+
+       if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) {
+               for (i = 0; i < 6; i++)
+                       ndis_key.KeyRSC |=
+                               cpu_to_le64(ext->rx_seq[i] << (i * 8));
+               ndis_key.KeyIndex |= cpu_to_le32(1 << 29);
+       }
+
+       addr = ext->addr.sa_data;
+       if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
+               /* group key */
+               if (priv->infra_mode == Ndis802_11IBSS)
+                       memset(ndis_key.Bssid, 0xff, ETH_ALEN);
+               else
+                       get_bssid(usbdev, ndis_key.Bssid);
+       } else {
+               /* pairwise key */
+               ndis_key.KeyIndex |= cpu_to_le32(1 << 30);
+               memcpy(ndis_key.Bssid, addr, ETH_ALEN);
+       }
+
+       if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY)
+               ndis_key.KeyIndex |= cpu_to_le32(1 << 31);
+
+       if (ext->alg == IW_ENCODE_ALG_TKIP && ext->key_len == 32) {
+               /* wpa_supplicant gives us the Michael MIC RX/TX keys in
+                * different order than NDIS spec, so swap the order here. */
+               memcpy(ndis_key.KeyMaterial, ext->key, 16);
+               memcpy(ndis_key.KeyMaterial + 16, ext->key + 24, 8);
+               memcpy(ndis_key.KeyMaterial + 24, ext->key + 16, 8);
+       } else
+               memcpy(ndis_key.KeyMaterial, ext->key, ext->key_len);
+
+       ret = rndis_set_oid(usbdev, OID_802_11_ADD_KEY, &ndis_key,
+                                       le32_to_cpu(ndis_key.Length));
+       devdbg(usbdev, "SIOCSIWENCODEEXT: OID_802_11_ADD_KEY -> %08X", ret);
+       if (ret != 0)
+               return ret;
+
+       priv->encr_key_len[keyidx] = ext->key_len;
+       memcpy(&priv->encr_keys[keyidx], ndis_key.KeyMaterial, ext->key_len);
+       if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY)
+               priv->encr_tx_key_index = keyidx;
+
+       return 0;
+}
+
+
+static int rndis_iw_set_scan(struct net_device *dev,
+    struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
+{
+       struct iw_param *param = &wrqu->param;
+       struct usbnet *usbdev = dev->priv;
+       union iwreq_data evt;
+       int ret = -EINVAL;
+       __le32 tmp;
+
+       devdbg(usbdev, "SIOCSIWSCAN");
+
+       if (param->flags == 0) {
+               tmp = ccpu2(1);
+               ret = rndis_set_oid(usbdev, OID_802_11_BSSID_LIST_SCAN, &tmp,
+                                                               sizeof(tmp));
+               evt.data.flags = 0;
+               evt.data.length = 0;
+               wireless_send_event(dev, SIOCGIWSCAN, &evt, NULL);
+       }
+       return ret;
+}
+
+
+static char *rndis_translate_scan(struct net_device *dev,
+    char *cev, char *end_buf, struct NDIS_WLAN_BSSID_EX *bssid)
+{
+#ifdef DEBUG
+       struct usbnet *usbdev = dev->priv;
+#endif
+       struct ieee80211_info_element *ie;
+       char *current_val;
+       int bssid_len, ie_len, i;
+       u32 beacon, atim;
+       struct iw_event iwe;
+       unsigned char sbuf[32];
+       DECLARE_MAC_BUF(mac);
+
+       bssid_len = le32_to_cpu(bssid->Length);
+
+       devdbg(usbdev, "BSSID %s", print_mac(mac, bssid->MacAddress));
+       iwe.cmd = SIOCGIWAP;
+       iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
+       memcpy(iwe.u.ap_addr.sa_data, bssid->MacAddress, ETH_ALEN);
+       cev = iwe_stream_add_event(cev, end_buf, &iwe, IW_EV_ADDR_LEN);
+
+       devdbg(usbdev, "SSID(%d) %s",
+               le32_to_cpu(bssid->Ssid.SsidLength),
+               bssid->Ssid.Ssid);
+       iwe.cmd = SIOCGIWESSID;
+       iwe.u.essid.length = le32_to_cpu(bssid->Ssid.SsidLength);
+       iwe.u.essid.flags = 1;
+       cev = iwe_stream_add_point(cev, end_buf, &iwe,
+                                               bssid->Ssid.Ssid);
+
+       devdbg(usbdev, "MODE %d",
+                       le32_to_cpu(bssid->InfrastructureMode));
+       iwe.cmd = SIOCGIWMODE;
+       switch (le32_to_cpu(bssid->InfrastructureMode)) {
+       case Ndis802_11IBSS:
+               iwe.u.mode = IW_MODE_ADHOC;
+               break;
+       case Ndis802_11Infrastructure:
+               iwe.u.mode = IW_MODE_INFRA;
+               break;
+       /*case Ndis802_11AutoUnknown:*/
+       default:
+               iwe.u.mode = IW_MODE_AUTO;
+               break;
+       }
+       cev = iwe_stream_add_event(cev, end_buf, &iwe, IW_EV_UINT_LEN);
+
+       devdbg(usbdev, "FREQ %d kHz",
+               le32_to_cpu(bssid->Configuration.DSConfig));
+       iwe.cmd = SIOCGIWFREQ;
+       dsconfig_to_freq(le32_to_cpu(bssid->Configuration.DSConfig),
+                                                               &iwe.u.freq);
+       cev = iwe_stream_add_event(cev, end_buf, &iwe, IW_EV_FREQ_LEN);
+
+       devdbg(usbdev, "QUAL %d", le32_to_cpu(bssid->Rssi));
+       iwe.cmd = IWEVQUAL;
+       iwe.u.qual.qual  = level_to_qual(le32_to_cpu(bssid->Rssi));
+       iwe.u.qual.level = le32_to_cpu(bssid->Rssi);
+       iwe.u.qual.updated = IW_QUAL_QUAL_UPDATED
+                       | IW_QUAL_LEVEL_UPDATED
+                       | IW_QUAL_NOISE_INVALID;
+       cev = iwe_stream_add_event(cev, end_buf, &iwe, IW_EV_QUAL_LEN);
+
+       devdbg(usbdev, "ENCODE %d", le32_to_cpu(bssid->Privacy));
+       iwe.cmd = SIOCGIWENCODE;
+       iwe.u.data.length = 0;
+       if (le32_to_cpu(bssid->Privacy) == Ndis802_11PrivFilterAcceptAll)
+               iwe.u.data.flags = IW_ENCODE_DISABLED;
+       else
+               iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
+
+       cev = iwe_stream_add_point(cev, end_buf, &iwe, NULL);
+
+       devdbg(usbdev, "RATES:");
+       current_val = cev + IW_EV_LCP_LEN;
+       iwe.cmd = SIOCGIWRATE;
+       for (i = 0; i < sizeof(bssid->SupportedRates); i++) {
+               if (bssid->SupportedRates[i] & 0x7f) {
+                       iwe.u.bitrate.value =
+                               ((bssid->SupportedRates[i] & 0x7f) *
+                               500000);
+                       devdbg(usbdev, " %d", iwe.u.bitrate.value);
+                       current_val = iwe_stream_add_value(cev,
+                               current_val, end_buf, &iwe,
+                               IW_EV_PARAM_LEN);
+               }
+       }
+
+       if ((current_val - cev) > IW_EV_LCP_LEN)
+               cev = current_val;
+
+       beacon = le32_to_cpu(bssid->Configuration.BeaconPeriod);
+       devdbg(usbdev, "BCN_INT %d", beacon);
+       iwe.cmd = IWEVCUSTOM;
+       snprintf(sbuf, sizeof(sbuf), "bcn_int=%d", beacon);
+       iwe.u.data.length = strlen(sbuf);
+       cev = iwe_stream_add_point(cev, end_buf, &iwe, sbuf);
+
+       atim = le32_to_cpu(bssid->Configuration.ATIMWindow);
+       devdbg(usbdev, "ATIM %d", atim);
+       iwe.cmd = IWEVCUSTOM;
+       snprintf(sbuf, sizeof(sbuf), "atim=%u", atim);
+       iwe.u.data.length = strlen(sbuf);
+       cev = iwe_stream_add_point(cev, end_buf, &iwe, sbuf);
+
+       ie = (void *)(bssid->IEs + sizeof(struct NDIS_802_11_FIXED_IEs));
+       ie_len = min(bssid_len - (int)sizeof(*bssid),
+                                       (int)le32_to_cpu(bssid->IELength));
+       ie_len -= sizeof(struct NDIS_802_11_FIXED_IEs);
+       while (ie_len >= sizeof(*ie) && sizeof(*ie) + ie->len <= ie_len) {
+               if ((ie->id == MFIE_TYPE_GENERIC && ie->len >= 4 &&
+                               memcmp(ie->data, "\x00\x50\xf2\x01", 4) == 0) ||
+                               ie->id == MFIE_TYPE_RSN) {
+                       devdbg(usbdev, "IE: WPA%d",
+                                       (ie->id == MFIE_TYPE_RSN) ? 2 : 1);
+                       iwe.cmd = IWEVGENIE;
+                       iwe.u.data.length = min(ie->len + 2, MAX_WPA_IE_LEN);
+                       cev = iwe_stream_add_point(cev, end_buf, &iwe,
+                                                               (u8 *)ie);
+               }
+
+               ie_len -= sizeof(*ie) + ie->len;
+               ie = (struct ieee80211_info_element *)&ie->data[ie->len];
+       }
+
+       return cev;
+}
+
+
+static int rndis_iw_get_scan(struct net_device *dev,
+    struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
+{
+       struct usbnet *usbdev = dev->priv;
+       void *buf = NULL;
+       char *cev = extra;
+       struct NDIS_802_11_BSSID_LIST_EX *bssid_list;
+       struct NDIS_WLAN_BSSID_EX *bssid;
+       int ret = -EINVAL, len, count, bssid_len;
+
+       devdbg(usbdev, "SIOCGIWSCAN");
+
+       len = CONTROL_BUFFER_SIZE;
+       buf = kmalloc(len, GFP_KERNEL);
+       if (!buf) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       ret = rndis_query_oid(usbdev, OID_802_11_BSSID_LIST, buf, &len);
+
+       if (ret != 0)
+               goto out;
+
+       bssid_list = buf;
+       bssid = bssid_list->Bssid;
+       bssid_len = le32_to_cpu(bssid->Length);
+       count = le32_to_cpu(bssid_list->NumberOfItems);
+       devdbg(usbdev, "SIOCGIWSCAN: %d BSSIDs found", count);
+
+       while (count && ((void *)bssid + bssid_len) <= (buf + len)) {
+               cev = rndis_translate_scan(dev, cev, extra + IW_SCAN_MAX_DATA,
+                                                                       bssid);
+               bssid = (void *)bssid + bssid_len;
+               bssid_len = le32_to_cpu(bssid->Length);
+               count--;
+       }
+
+out:
+       wrqu->data.length = cev - extra;
+       wrqu->data.flags = 0;
+       kfree(buf);
+       return ret;
+}
+
+
+static int rndis_iw_set_genie(struct net_device *dev,
+    struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
+{
+       struct usbnet *usbdev = dev->priv;
+       struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
+       int ret = 0;
+
+#ifdef DEBUG
+       int j;
+       u8 *gie = extra;
+       for (j = 0; j < wrqu->data.length; j += 8)
+               devdbg(usbdev,
+                       "SIOCSIWGENIE %04x - "
+                       "%02x %02x %02x %02x %02x %02x %02x %02x", j,
+                       gie[j + 0], gie[j + 1], gie[j + 2], gie[j + 3],
+                       gie[j + 4], gie[j + 5], gie[j + 6], gie[j + 7]);
+#endif
+       /* clear existing IEs */
+       if (priv->wpa_ie_len) {
+               kfree(priv->wpa_ie);
+               priv->wpa_ie_len = 0;
+       }
+
+       /* set new IEs */
+       priv->wpa_ie = kmalloc(wrqu->data.length, GFP_KERNEL);
+       if (priv->wpa_ie) {
+               priv->wpa_ie_len = wrqu->data.length;
+               memcpy(priv->wpa_ie, extra, priv->wpa_ie_len);
+       } else
+               ret = -ENOMEM;
+       return ret;
+}
+
+
+static int rndis_iw_get_genie(struct net_device *dev,
+    struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
+{
+       struct usbnet *usbdev = dev->priv;
+       struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
+
+       devdbg(usbdev, "SIOCGIWGENIE");
+
+       if (priv->wpa_ie_len == 0 || priv->wpa_ie == NULL) {
+               wrqu->data.length = 0;
+               return 0;
+       }
+
+       if (wrqu->data.length < priv->wpa_ie_len)
+               return -E2BIG;
+
+       wrqu->data.length = priv->wpa_ie_len;
+       memcpy(extra, priv->wpa_ie, priv->wpa_ie_len);
+
+       return 0;
+}
+
+
+static int rndis_iw_set_rts(struct net_device *dev,
+    struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
+{
+       struct usbnet *usbdev = dev->priv;
+       __le32 tmp;
+       devdbg(usbdev, "SIOCSIWRTS");
+
+       tmp = cpu_to_le32(wrqu->rts.value);
+       return rndis_set_oid(usbdev, OID_802_11_RTS_THRESHOLD, &tmp,
+                                                               sizeof(tmp));
+}
+
+
+static int rndis_iw_get_rts(struct net_device *dev,
+    struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
+{
+       struct usbnet *usbdev = dev->priv;
+       __le32 tmp;
+       int len, ret;
+
+       len = sizeof(tmp);
+       ret = rndis_query_oid(usbdev, OID_802_11_RTS_THRESHOLD, &tmp, &len);
+       if (ret == 0) {
+               wrqu->rts.value = le32_to_cpu(tmp);
+               wrqu->rts.flags = 1;
+               wrqu->rts.disabled = 0;
+       }
+
+       devdbg(usbdev, "SIOCGIWRTS: %d", wrqu->rts.value);
+
+       return ret;
+}
+
+
+static int rndis_iw_set_frag(struct net_device *dev,
+    struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
+{
+       struct usbnet *usbdev = dev->priv;
+       __le32 tmp;
+
+       devdbg(usbdev, "SIOCSIWFRAG");
+
+       tmp = cpu_to_le32(wrqu->frag.value);
+       return rndis_set_oid(usbdev, OID_802_11_FRAGMENTATION_THRESHOLD, &tmp,
+                                                               sizeof(tmp));
+}
+
+
+static int rndis_iw_get_frag(struct net_device *dev,
+    struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
+{
+       struct usbnet *usbdev = dev->priv;
+       __le32 tmp;
+       int len, ret;
+
+       len = sizeof(tmp);
+       ret = rndis_query_oid(usbdev, OID_802_11_FRAGMENTATION_THRESHOLD, &tmp,
+                                                                       &len);
+       if (ret == 0) {
+               wrqu->frag.value = le32_to_cpu(tmp);
+               wrqu->frag.flags = 1;
+               wrqu->frag.disabled = 0;
+       }
+       devdbg(usbdev, "SIOCGIWFRAG: %d", wrqu->frag.value);
+       return ret;
+}
+
+
+static int rndis_iw_set_nick(struct net_device *dev,
+    struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
+{
+       struct usbnet *usbdev = dev->priv;
+       struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
+
+       devdbg(usbdev, "SIOCSIWNICK");
+
+       priv->nick_len = wrqu->data.length;
+       if (priv->nick_len > 32)
+               priv->nick_len = 32;
+
+       memcpy(priv->nick, extra, priv->nick_len);
+       return 0;
+}
+
+
+static int rndis_iw_get_nick(struct net_device *dev,
+    struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
+{
+       struct usbnet *usbdev = dev->priv;
+       struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
+
+       wrqu->data.flags = 1;
+       wrqu->data.length = priv->nick_len;
+       memcpy(extra, priv->nick, priv->nick_len);
+
+       devdbg(usbdev, "SIOCGIWNICK: '%s'", priv->nick);
+
+       return 0;
+}
+
+
+static int rndis_iw_set_freq(struct net_device *dev,
+    struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
+{
+       struct usbnet *usbdev = dev->priv;
+       struct NDIS_802_11_CONFIGURATION config;
+       unsigned int dsconfig;
+       int len, ret;
+
+       /* this OID is valid only when not associated */
+       if (is_associated(usbdev))
+               return 0;
+
+       dsconfig = 0;
+       if (freq_to_dsconfig(&wrqu->freq, &dsconfig))
+               return -EINVAL;
+
+       len = sizeof(config);
+       ret = rndis_query_oid(usbdev, OID_802_11_CONFIGURATION, &config, &len);
+       if (ret != 0) {
+               devdbg(usbdev, "SIOCSIWFREQ: querying configuration failed");
+               return 0;
+       }
+
+       config.DSConfig = cpu_to_le32(dsconfig);
+
+       devdbg(usbdev, "SIOCSIWFREQ: %d * 10^%d", wrqu->freq.m, wrqu->freq.e);
+       return rndis_set_oid(usbdev, OID_802_11_CONFIGURATION, &config,
+                                                               sizeof(config));
+}
+
+
+static int rndis_iw_get_freq(struct net_device *dev,
+    struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
+{
+       struct usbnet *usbdev = dev->priv;
+       struct NDIS_802_11_CONFIGURATION config;
+       int len, ret;
+
+       len = sizeof(config);
+       ret = rndis_query_oid(usbdev, OID_802_11_CONFIGURATION, &config, &len);
+       if (ret == 0)
+               dsconfig_to_freq(le32_to_cpu(config.DSConfig), &wrqu->freq);
+
+       devdbg(usbdev, "SIOCGIWFREQ: %d", wrqu->freq.m);
+       return ret;
+}
+
+
+static int rndis_iw_get_txpower(struct net_device *dev,
+    struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
+{
+       struct usbnet *usbdev = dev->priv;
+       struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
+       __le32 tx_power;
+       int ret = 0, len;
+
+       if (priv->radio_on) {
+               if (priv->caps & CAP_SUPPORT_TXPOWER) {
+                       len = sizeof(tx_power);
+                       ret = rndis_query_oid(usbdev, OID_802_11_TX_POWER_LEVEL,
+                                                       &tx_power, &len);
+                       if (ret != 0)
+                               return ret;
+               } else
+                       /* fake incase not supported */
+                       tx_power = cpu_to_le32(get_bcm4320_power(priv));
+
+               wrqu->txpower.flags = IW_TXPOW_MWATT;
+               wrqu->txpower.value = le32_to_cpu(tx_power);
+               wrqu->txpower.disabled = 0;
+       } else {
+               wrqu->txpower.flags = IW_TXPOW_MWATT;
+               wrqu->txpower.value = 0;
+               wrqu->txpower.disabled = 1;
+       }
+
+       devdbg(usbdev, "SIOCGIWTXPOW: %d", wrqu->txpower.value);
+
+       return ret;
+}
+
+
+static int rndis_iw_set_txpower(struct net_device *dev,
+    struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
+{
+       struct usbnet *usbdev = dev->priv;
+       struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
+       __le32 tx_power = 0;
+       int ret = 0;
+
+       if (!wrqu->txpower.disabled) {
+               if (wrqu->txpower.flags == IW_TXPOW_MWATT)
+                       tx_power = cpu_to_le32(wrqu->txpower.value);
+               else { /* wrqu->txpower.flags == IW_TXPOW_DBM */
+                       if (wrqu->txpower.value > 20)
+                               tx_power = cpu_to_le32(128);
+                       else if (wrqu->txpower.value < -43)
+                               tx_power = cpu_to_le32(127);
+                       else {
+                               signed char tmp;
+                               tmp = wrqu->txpower.value;
+                               tmp = -12 - tmp;
+                               tmp <<= 2;
+                               tx_power = cpu_to_le32((unsigned char)tmp);
+                       }
+               }
+       }
+
+       devdbg(usbdev, "SIOCSIWTXPOW: %d", le32_to_cpu(tx_power));
+
+       if (le32_to_cpu(tx_power) != 0) {
+               if (priv->caps & CAP_SUPPORT_TXPOWER) {
+                       /* turn radio on first */
+                       if (!priv->radio_on)
+                               disassociate(usbdev, 1);
+
+                       ret = rndis_set_oid(usbdev, OID_802_11_TX_POWER_LEVEL,
+                                               &tx_power, sizeof(tx_power));
+                       if (ret != 0)
+                               ret = -EOPNOTSUPP;
+                       return ret;
+               } else {
+                       /* txpower unsupported, just turn radio on */
+                       if (!priv->radio_on)
+                               return disassociate(usbdev, 1);
+                       return 0; /* all ready on */
+               }
+       }
+
+       /* tx_power == 0, turn off radio */
+       return disassociate(usbdev, 0);
+}
+
+
+static int rndis_iw_get_rate(struct net_device *dev,
+    struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
+{
+       struct usbnet *usbdev = dev->priv;
+       __le32 tmp;
+       int ret, len;
+
+       len = sizeof(tmp);
+       ret = rndis_query_oid(usbdev, OID_GEN_LINK_SPEED, &tmp, &len);
+       if (ret == 0) {
+               wrqu->bitrate.value = le32_to_cpu(tmp) * 100;
+               wrqu->bitrate.disabled = 0;
+               wrqu->bitrate.flags = 1;
+       }
+       return ret;
+}
+
+
+static int rndis_iw_set_mlme(struct net_device *dev,
+    struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
+{
+       struct usbnet *usbdev = dev->priv;
+       struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
+       struct iw_mlme *mlme = (struct iw_mlme *)extra;
+       unsigned char bssid[ETH_ALEN];
+
+       get_bssid(usbdev, bssid);
+
+       if (memcmp(bssid, mlme->addr.sa_data, ETH_ALEN))
+               return -EINVAL;
+
+       switch (mlme->cmd) {
+       case IW_MLME_DEAUTH:
+               return deauthenticate(usbdev);
+       case IW_MLME_DISASSOC:
+               return disassociate(usbdev, priv->radio_on);
+       default:
+               return -EOPNOTSUPP;
+       }
+
+       return 0;
+}
+
+
+static struct iw_statistics *rndis_get_wireless_stats(struct net_device *dev)
+{
+       struct usbnet *usbdev = dev->priv;
+       struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
+       unsigned long flags;
+
+       spin_lock_irqsave(&priv->stats_lock, flags);
+       memcpy(&priv->iwstats, &priv->privstats, sizeof(priv->iwstats));
+       spin_unlock_irqrestore(&priv->stats_lock, flags);
+
+       return &priv->iwstats;
+}
+
+
+#define IW_IOCTL(x) [(x) - SIOCSIWCOMMIT]
+static const iw_handler rndis_iw_handler[] =
+{
+       IW_IOCTL(SIOCSIWCOMMIT)    = rndis_iw_commit,
+       IW_IOCTL(SIOCGIWNAME)      = rndis_iw_get_name,
+       IW_IOCTL(SIOCSIWFREQ)      = rndis_iw_set_freq,
+       IW_IOCTL(SIOCGIWFREQ)      = rndis_iw_get_freq,
+       IW_IOCTL(SIOCSIWMODE)      = rndis_iw_set_mode,
+       IW_IOCTL(SIOCGIWMODE)      = rndis_iw_get_mode,
+       IW_IOCTL(SIOCGIWRANGE)     = rndis_iw_get_range,
+       IW_IOCTL(SIOCSIWAP)        = rndis_iw_set_bssid,
+       IW_IOCTL(SIOCGIWAP)        = rndis_iw_get_bssid,
+       IW_IOCTL(SIOCSIWSCAN)      = rndis_iw_set_scan,
+       IW_IOCTL(SIOCGIWSCAN)      = rndis_iw_get_scan,
+       IW_IOCTL(SIOCSIWESSID)     = rndis_iw_set_essid,
+       IW_IOCTL(SIOCGIWESSID)     = rndis_iw_get_essid,
+       IW_IOCTL(SIOCSIWNICKN)     = rndis_iw_set_nick,
+       IW_IOCTL(SIOCGIWNICKN)     = rndis_iw_get_nick,
+       IW_IOCTL(SIOCGIWRATE)      = rndis_iw_get_rate,
+       IW_IOCTL(SIOCSIWRTS)       = rndis_iw_set_rts,
+       IW_IOCTL(SIOCGIWRTS)       = rndis_iw_get_rts,
+       IW_IOCTL(SIOCSIWFRAG)      = rndis_iw_set_frag,
+       IW_IOCTL(SIOCGIWFRAG)      = rndis_iw_get_frag,
+       IW_IOCTL(SIOCSIWTXPOW)     = rndis_iw_set_txpower,
+       IW_IOCTL(SIOCGIWTXPOW)     = rndis_iw_get_txpower,
+       IW_IOCTL(SIOCSIWENCODE)    = rndis_iw_set_encode,
+       IW_IOCTL(SIOCSIWENCODEEXT) = rndis_iw_set_encode_ext,
+       IW_IOCTL(SIOCSIWAUTH)      = rndis_iw_set_auth,
+       IW_IOCTL(SIOCGIWAUTH)      = rndis_iw_get_auth,
+       IW_IOCTL(SIOCSIWGENIE)     = rndis_iw_set_genie,
+       IW_IOCTL(SIOCGIWGENIE)     = rndis_iw_get_genie,
+       IW_IOCTL(SIOCSIWMLME)      = rndis_iw_set_mlme,
+};
+
+static const iw_handler rndis_wext_private_handler[] = {
+};
+
+static const struct iw_priv_args rndis_wext_private_args[] = {
+};
+
+
+static const struct iw_handler_def rndis_iw_handlers = {
+       .num_standard = ARRAY_SIZE(rndis_iw_handler),
+       .num_private  = ARRAY_SIZE(rndis_wext_private_handler),
+       .num_private_args = ARRAY_SIZE(rndis_wext_private_args),
+       .standard = (iw_handler *)rndis_iw_handler,
+       .private  = (iw_handler *)rndis_wext_private_handler,
+       .private_args = (struct iw_priv_args *)rndis_wext_private_args,
+       .get_wireless_stats = rndis_get_wireless_stats,
+};
+
+
+static void rndis_wext_worker(struct work_struct *work)
+{
+       struct rndis_wext_private *priv =
+               container_of(work, struct rndis_wext_private, work);
+       struct usbnet *usbdev = priv->usbdev;
+       union iwreq_data evt;
+       unsigned char bssid[ETH_ALEN];
+       int ret;
+
+       if (test_and_clear_bit(WORK_CONNECTION_EVENT, &priv->work_pending)) {
+               ret = get_bssid(usbdev, bssid);
+
+               if (!ret) {
+                       evt.data.flags = 0;
+                       evt.data.length = 0;
+                       memcpy(evt.ap_addr.sa_data, bssid, ETH_ALEN);
+                       wireless_send_event(usbdev->net, SIOCGIWAP, &evt, NULL);
+               }
+       }
+
+       if (test_and_clear_bit(WORK_SET_MULTICAST_LIST, &priv->work_pending))
+               set_multicast_list(usbdev);
+}
+
+static void rndis_wext_set_multicast_list(struct net_device *dev)
+{
+       struct usbnet *usbdev = dev->priv;
+       struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
+
+       set_bit(WORK_SET_MULTICAST_LIST, &priv->work_pending);
+       queue_work(priv->workqueue, &priv->work);
+}
+
+static void rndis_wext_link_change(struct usbnet *dev, int state)
+{
+       struct rndis_wext_private *priv = get_rndis_wext_priv(dev);
+       union iwreq_data evt;
+
+       if (state) {
+               /* queue work to avoid recursive calls into rndis_command */
+               set_bit(WORK_CONNECTION_EVENT, &priv->work_pending);
+               queue_work(priv->workqueue, &priv->work);
+       } else {
+               evt.data.flags = 0;
+               evt.data.length = 0;
+               memset(evt.ap_addr.sa_data, 0, ETH_ALEN);
+               wireless_send_event(dev->net, SIOCGIWAP, &evt, NULL);
+       }
+}
+
+
+static int rndis_wext_get_caps(struct usbnet *dev)
+{
+       struct {
+               __le32  num_items;
+               __le32  items[8];
+       } networks_supported;
+       int len, retval, i, n;
+       __le32 tx_power;
+       struct rndis_wext_private *priv = get_rndis_wext_priv(dev);
+
+       /* determine if supports setting txpower */
+       len = sizeof(tx_power);
+       retval = rndis_query_oid(dev, OID_802_11_TX_POWER_LEVEL, &tx_power,
+                                                               &len);
+       if (retval == 0 && le32_to_cpu(tx_power) != 0xFF)
+               priv->caps |= CAP_SUPPORT_TXPOWER;
+
+       /* determine supported modes */
+       len = sizeof(networks_supported);
+       retval = rndis_query_oid(dev, OID_802_11_NETWORK_TYPES_SUPPORTED,
+                                               &networks_supported, &len);
+       if (retval >= 0) {
+               n = le32_to_cpu(networks_supported.num_items);
+               if (n > 8)
+                       n = 8;
+               for (i = 0; i < n; i++) {
+                       switch (le32_to_cpu(networks_supported.items[i])) {
+                       case Ndis802_11FH:
+                       case Ndis802_11DS:
+                               priv->caps |= CAP_MODE_80211B;
+                               break;
+                       case Ndis802_11OFDM5:
+                               priv->caps |= CAP_MODE_80211A;
+                               break;
+                       case Ndis802_11OFDM24:
+                               priv->caps |= CAP_MODE_80211G;
+                               break;
+                       }
+               }
+               if (priv->caps & CAP_MODE_80211A)
+                       strcat(priv->name, "a");
+               if (priv->caps & CAP_MODE_80211B)
+                       strcat(priv->name, "b");
+               if (priv->caps & CAP_MODE_80211G)
+                       strcat(priv->name, "g");
+       }
+
+       return retval;
+}
+
+
+#define STATS_UPDATE_JIFFIES (HZ)
+static void rndis_update_wireless_stats(struct work_struct *work)
+{
+       struct rndis_wext_private *priv =
+               container_of(work, struct rndis_wext_private, stats_work.work);
+       struct usbnet *usbdev = priv->usbdev;
+       struct iw_statistics iwstats;
+       __le32 rssi, tmp;
+       int len, ret, bitrate, j;
+       unsigned long flags;
+       int update_jiffies = STATS_UPDATE_JIFFIES;
+       void *buf;
+
+       spin_lock_irqsave(&priv->stats_lock, flags);
+       memcpy(&iwstats, &priv->privstats, sizeof(iwstats));
+       spin_unlock_irqrestore(&priv->stats_lock, flags);
+
+       /* only update stats when connected */
+       if (!is_associated(usbdev)) {
+               iwstats.qual.qual = 0;
+               iwstats.qual.level = 0;
+               iwstats.qual.updated = IW_QUAL_QUAL_UPDATED
+                               | IW_QUAL_LEVEL_UPDATED
+                               | IW_QUAL_NOISE_INVALID
+                               | IW_QUAL_QUAL_INVALID
+                               | IW_QUAL_LEVEL_INVALID;
+               goto end;
+       }
+
+       len = sizeof(rssi);
+       ret = rndis_query_oid(usbdev, OID_802_11_RSSI, &rssi, &len);
+
+       devdbg(usbdev, "stats: OID_802_11_RSSI -> %d, rssi:%d", ret,
+                                                       le32_to_cpu(rssi));
+       if (ret == 0) {
+               memset(&iwstats.qual, 0, sizeof(iwstats.qual));
+               iwstats.qual.qual  = level_to_qual(le32_to_cpu(rssi));
+               iwstats.qual.level = le32_to_cpu(rssi);
+               iwstats.qual.updated = IW_QUAL_QUAL_UPDATED
+                               | IW_QUAL_LEVEL_UPDATED
+                               | IW_QUAL_NOISE_INVALID;
+       }
+
+       memset(&iwstats.discard, 0, sizeof(iwstats.discard));
+
+       len = sizeof(tmp);
+       ret = rndis_query_oid(usbdev, OID_GEN_XMIT_ERROR, &tmp, &len);
+       if (ret == 0)
+               iwstats.discard.misc += le32_to_cpu(tmp);
+
+       len = sizeof(tmp);
+       ret = rndis_query_oid(usbdev, OID_GEN_RCV_ERROR, &tmp, &len);
+       if (ret == 0)
+               iwstats.discard.misc += le32_to_cpu(tmp);
+
+       len = sizeof(tmp);
+       ret = rndis_query_oid(usbdev, OID_GEN_RCV_NO_BUFFER, &tmp, &len);
+       if (ret == 0)
+               iwstats.discard.misc += le32_to_cpu(tmp);
+
+       /* Workaround transfer stalls on poor quality links. */
+       len = sizeof(tmp);
+       ret = rndis_query_oid(usbdev, OID_GEN_LINK_SPEED, &tmp, &len);
+       if (ret == 0) {
+               bitrate = le32_to_cpu(tmp) * 100;
+               if (bitrate > 11000000)
+                       goto end;
+
+               /* Decrease stats worker interval to catch stalls.
+                * faster. Faster than 400-500ms causes packet loss,
+                * Slower doesn't catch stalls fast enough.
+                */
+               j = msecs_to_jiffies(priv->param_workaround_interval);
+               if (j > STATS_UPDATE_JIFFIES)
+                       j = STATS_UPDATE_JIFFIES;
+               else if (j <= 0)
+                       j = 1;
+               update_jiffies = j;
+
+               /* Send scan OID. Use of both OIDs is required to get device
+                * working.
+                */
+               tmp = ccpu2(1);
+               rndis_set_oid(usbdev, OID_802_11_BSSID_LIST_SCAN, &tmp,
+                                                               sizeof(tmp));
+
+               len = CONTROL_BUFFER_SIZE;
+               buf = kmalloc(len, GFP_KERNEL);
+               if (!buf)
+                       goto end;
+
+               rndis_query_oid(usbdev, OID_802_11_BSSID_LIST, buf, &len);
+               kfree(buf);
+       }
+end:
+       spin_lock_irqsave(&priv->stats_lock, flags);
+       memcpy(&priv->privstats, &iwstats, sizeof(iwstats));
+       spin_unlock_irqrestore(&priv->stats_lock, flags);
+
+       if (update_jiffies >= HZ)
+               update_jiffies = round_jiffies_relative(update_jiffies);
+       else {
+               j = round_jiffies_relative(update_jiffies);
+               if (abs(j - update_jiffies) <= 10)
+                       update_jiffies = j;
+       }
+
+       queue_delayed_work(priv->workqueue, &priv->stats_work, update_jiffies);
+}
+
+
+static int bcm4320_early_init(struct usbnet *dev)
+{
+       struct rndis_wext_private *priv = get_rndis_wext_priv(dev);
+       char buf[8];
+
+       /* Early initialization settings, setting these won't have effect
+        * if called after generic_rndis_bind().
+        */
+
+       priv->param_country[0] = modparam_country[0];
+       priv->param_country[1] = modparam_country[1];
+       priv->param_country[2] = 0;
+       priv->param_frameburst   = modparam_frameburst;
+       priv->param_afterburner  = modparam_afterburner;
+       priv->param_power_save   = modparam_power_save;
+       priv->param_power_output = modparam_power_output;
+       priv->param_roamtrigger  = modparam_roamtrigger;
+       priv->param_roamdelta    = modparam_roamdelta;
+       priv->param_workaround_interval = modparam_workaround_interval;
+
+       priv->param_country[0] = toupper(priv->param_country[0]);
+       priv->param_country[1] = toupper(priv->param_country[1]);
+       /* doesn't support EU as country code, use FI instead */
+       if (!strcmp(priv->param_country, "EU"))
+               strcpy(priv->param_country, "FI");
+
+       if (priv->param_power_save < 0)
+               priv->param_power_save = 0;
+       else if (priv->param_power_save > 2)
+               priv->param_power_save = 2;
+
+       if (priv->param_roamtrigger < -80)
+               priv->param_roamtrigger = -80;
+       else if (priv->param_roamtrigger > -60)
+               priv->param_roamtrigger = -60;
+
+       if (priv->param_roamdelta < 0)
+               priv->param_roamdelta = 0;
+       else if (priv->param_roamdelta > 2)
+               priv->param_roamdelta = 2;
+
+       if (priv->param_workaround_interval < 0)
+               priv->param_workaround_interval = 500;
+
+       rndis_set_config_parameter_str(dev, "Country", priv->param_country);
+       rndis_set_config_parameter_str(dev, "FrameBursting",
+                                       priv->param_frameburst ? "1" : "0");
+       rndis_set_config_parameter_str(dev, "Afterburner",
+                                       priv->param_afterburner ? "1" : "0");
+       sprintf(buf, "%d", priv->param_power_save);
+       rndis_set_config_parameter_str(dev, "PowerSaveMode", buf);
+       sprintf(buf, "%d", priv->param_power_output);
+       rndis_set_config_parameter_str(dev, "PwrOut", buf);
+       sprintf(buf, "%d", priv->param_roamtrigger);
+       rndis_set_config_parameter_str(dev, "RoamTrigger", buf);
+       sprintf(buf, "%d", priv->param_roamdelta);
+       rndis_set_config_parameter_str(dev, "RoamDelta", buf);
+
+       return 0;
+}
+
+
+static int rndis_wext_bind(struct usbnet *dev, struct usb_interface *intf)
+{
+       struct net_device *net = dev->net;
+       struct rndis_wext_private *priv;
+       int retval, len;
+       __le32 tmp;
+
+       /* allocate rndis private data */
+       priv = kmalloc(sizeof(struct rndis_wext_private), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       /* These have to be initialized before calling generic_rndis_bind().
+        * Otherwise we'll be in big trouble in rndis_wext_early_init().
+        */
+       dev->driver_priv = priv;
+       memset(priv, 0, sizeof(*priv));
+       memset(priv->name, 0, sizeof(priv->name));
+       strcpy(priv->name, "IEEE802.11");
+       net->wireless_handlers = &rndis_iw_handlers;
+       priv->usbdev = dev;
+
+       mutex_init(&priv->command_lock);
+       spin_lock_init(&priv->stats_lock);
+
+       /* try bind rndis_host */
+       retval = generic_rndis_bind(dev, intf, FLAG_RNDIS_PHYM_WIRELESS);
+       if (retval < 0)
+               goto fail;
+
+       /* generic_rndis_bind set packet filter to multicast_all+
+        * promisc mode which doesn't work well for our devices (device
+        * picks up rssi to closest station instead of to access point).
+        *
+        * rndis_host wants to avoid all OID as much as possible
+        * so do promisc/multicast handling in rndis_wext.
+        */
+       dev->net->set_multicast_list = rndis_wext_set_multicast_list;
+       tmp = RNDIS_PACKET_TYPE_DIRECTED | RNDIS_PACKET_TYPE_BROADCAST;
+       retval = rndis_set_oid(dev, OID_GEN_CURRENT_PACKET_FILTER, &tmp,
+                                                               sizeof(tmp));
+
+       len = sizeof(tmp);
+       retval = rndis_query_oid(dev, OID_802_3_MAXIMUM_LIST_SIZE, &tmp, &len);
+       priv->multicast_size = le32_to_cpu(tmp);
+       if (retval < 0 || priv->multicast_size < 0)
+               priv->multicast_size = 0;
+       if (priv->multicast_size > 0)
+               dev->net->flags |= IFF_MULTICAST;
+       else
+               dev->net->flags &= ~IFF_MULTICAST;
+
+       priv->iwstats.qual.qual = 0;
+       priv->iwstats.qual.level = 0;
+       priv->iwstats.qual.updated = IW_QUAL_QUAL_UPDATED
+                                       | IW_QUAL_LEVEL_UPDATED
+                                       | IW_QUAL_NOISE_INVALID
+                                       | IW_QUAL_QUAL_INVALID
+                                       | IW_QUAL_LEVEL_INVALID;
+
+       rndis_wext_get_caps(dev);
+       set_default_iw_params(dev);
+
+       /* turn radio on */
+       priv->radio_on = 1;
+       disassociate(dev, 1);
+
+       /* because rndis_command() sleeps we need to use workqueue */
+       priv->workqueue = create_singlethread_workqueue("rndis_wlan");
+       INIT_DELAYED_WORK(&priv->stats_work, rndis_update_wireless_stats);
+       queue_delayed_work(priv->workqueue, &priv->stats_work,
+               round_jiffies_relative(STATS_UPDATE_JIFFIES));
+       INIT_WORK(&priv->work, rndis_wext_worker);
+
+       return 0;
+
+fail:
+       kfree(priv);
+       return retval;
+}
+
+
+static void rndis_wext_unbind(struct usbnet *dev, struct usb_interface *intf)
+{
+       struct rndis_wext_private *priv = get_rndis_wext_priv(dev);
+
+       /* turn radio off */
+       disassociate(dev, 0);
+
+       cancel_delayed_work_sync(&priv->stats_work);
+       cancel_work_sync(&priv->work);
+       flush_workqueue(priv->workqueue);
+       destroy_workqueue(priv->workqueue);
+
+       if (priv && priv->wpa_ie_len)
+               kfree(priv->wpa_ie);
+       kfree(priv);
+
+       rndis_unbind(dev, intf);
+}
+
+
+static int rndis_wext_reset(struct usbnet *dev)
+{
+       return deauthenticate(dev);
+}
+
+
+static const struct driver_info        bcm4320b_info = {
+       .description =  "Wireless RNDIS device, BCM4320b based",
+       .flags =        FLAG_WLAN | FLAG_FRAMING_RN | FLAG_NO_SETINT,
+       .bind =         rndis_wext_bind,
+       .unbind =       rndis_wext_unbind,
+       .status =       rndis_status,
+       .rx_fixup =     rndis_rx_fixup,
+       .tx_fixup =     rndis_tx_fixup,
+       .reset =        rndis_wext_reset,
+       .early_init =   bcm4320_early_init,
+       .link_change =  rndis_wext_link_change,
+};
+
+static const struct driver_info        bcm4320a_info = {
+       .description =  "Wireless RNDIS device, BCM4320a based",
+       .flags =        FLAG_WLAN | FLAG_FRAMING_RN | FLAG_NO_SETINT,
+       .bind =         rndis_wext_bind,
+       .unbind =       rndis_wext_unbind,
+       .status =       rndis_status,
+       .rx_fixup =     rndis_rx_fixup,
+       .tx_fixup =     rndis_tx_fixup,
+       .reset =        rndis_wext_reset,
+       .early_init =   bcm4320_early_init,
+       .link_change =  rndis_wext_link_change,
+};
+
+static const struct driver_info rndis_wext_info = {
+       .description =  "Wireless RNDIS device",
+       .flags =        FLAG_WLAN | FLAG_FRAMING_RN | FLAG_NO_SETINT,
+       .bind =         rndis_wext_bind,
+       .unbind =       rndis_wext_unbind,
+       .status =       rndis_status,
+       .rx_fixup =     rndis_rx_fixup,
+       .tx_fixup =     rndis_tx_fixup,
+       .reset =        rndis_wext_reset,
+       .early_init =   bcm4320_early_init,
+       .link_change =  rndis_wext_link_change,
+};
+
+/*-------------------------------------------------------------------------*/
+
+static const struct usb_device_id products [] = {
+#define        RNDIS_MASTER_INTERFACE \
+       .bInterfaceClass        = USB_CLASS_COMM, \
+       .bInterfaceSubClass     = 2 /* ACM */, \
+       .bInterfaceProtocol     = 0x0ff
+
+/* INF driver for these devices have DriverVer >= 4.xx.xx.xx and many custom
+ * parameters available. Chipset marked as 'BCM4320SKFBG' in NDISwrapper-wiki.
+ */
+{
+       .match_flags    =   USB_DEVICE_ID_MATCH_INT_INFO
+                         | USB_DEVICE_ID_MATCH_DEVICE,
+       .idVendor               = 0x0411,
+       .idProduct              = 0x00bc,       /* Buffalo WLI-U2-KG125S */
+       RNDIS_MASTER_INTERFACE,
+       .driver_info            = (unsigned long) &bcm4320b_info,
+}, {
+       .match_flags    =   USB_DEVICE_ID_MATCH_INT_INFO
+                         | USB_DEVICE_ID_MATCH_DEVICE,
+       .idVendor               = 0x0baf,
+       .idProduct              = 0x011b,       /* U.S. Robotics USR5421 */
+       RNDIS_MASTER_INTERFACE,
+       .driver_info            = (unsigned long) &bcm4320b_info,
+}, {
+       .match_flags    =   USB_DEVICE_ID_MATCH_INT_INFO
+                         | USB_DEVICE_ID_MATCH_DEVICE,
+       .idVendor               = 0x050d,
+       .idProduct              = 0x011b,       /* Belkin F5D7051 */
+       RNDIS_MASTER_INTERFACE,
+       .driver_info            = (unsigned long) &bcm4320b_info,
+}, {
+       .match_flags    =   USB_DEVICE_ID_MATCH_INT_INFO
+                         | USB_DEVICE_ID_MATCH_DEVICE,
+       .idVendor               = 0x1799,       /* Belkin has two vendor ids */
+       .idProduct              = 0x011b,       /* Belkin F5D7051 */
+       RNDIS_MASTER_INTERFACE,
+       .driver_info            = (unsigned long) &bcm4320b_info,
+}, {
+       .match_flags    =   USB_DEVICE_ID_MATCH_INT_INFO
+                         | USB_DEVICE_ID_MATCH_DEVICE,
+       .idVendor               = 0x13b1,
+       .idProduct              = 0x0014,       /* Linksys WUSB54GSv2 */
+       RNDIS_MASTER_INTERFACE,
+       .driver_info            = (unsigned long) &bcm4320b_info,
+}, {
+       .match_flags    =   USB_DEVICE_ID_MATCH_INT_INFO
+                         | USB_DEVICE_ID_MATCH_DEVICE,
+       .idVendor               = 0x13b1,
+       .idProduct              = 0x0026,       /* Linksys WUSB54GSC */
+       RNDIS_MASTER_INTERFACE,
+       .driver_info            = (unsigned long) &bcm4320b_info,
+}, {
+       .match_flags    =   USB_DEVICE_ID_MATCH_INT_INFO
+                         | USB_DEVICE_ID_MATCH_DEVICE,
+       .idVendor               = 0x0b05,
+       .idProduct              = 0x1717,       /* Asus WL169gE */
+       RNDIS_MASTER_INTERFACE,
+       .driver_info            = (unsigned long) &bcm4320b_info,
+}, {
+       .match_flags    =   USB_DEVICE_ID_MATCH_INT_INFO
+                         | USB_DEVICE_ID_MATCH_DEVICE,
+       .idVendor               = 0x0a5c,
+       .idProduct              = 0xd11b,       /* Eminent EM4045 */
+       RNDIS_MASTER_INTERFACE,
+       .driver_info            = (unsigned long) &bcm4320b_info,
+}, {
+       .match_flags    =   USB_DEVICE_ID_MATCH_INT_INFO
+                         | USB_DEVICE_ID_MATCH_DEVICE,
+       .idVendor               = 0x1690,
+       .idProduct              = 0x0715,       /* BT Voyager 1055 */
+       RNDIS_MASTER_INTERFACE,
+       .driver_info            = (unsigned long) &bcm4320b_info,
+},
+/* These devices have DriverVer < 4.xx.xx.xx and do not have any custom
+ * parameters available, hardware probably contain older firmware version with
+ * no way of updating. Chipset marked as 'BCM4320????' in NDISwrapper-wiki.
+ */
+{
+       .match_flags    =   USB_DEVICE_ID_MATCH_INT_INFO
+                         | USB_DEVICE_ID_MATCH_DEVICE,
+       .idVendor               = 0x13b1,
+       .idProduct              = 0x000e,       /* Linksys WUSB54GSv1 */
+       RNDIS_MASTER_INTERFACE,
+       .driver_info            = (unsigned long) &bcm4320a_info,
+}, {
+       .match_flags    =   USB_DEVICE_ID_MATCH_INT_INFO
+                         | USB_DEVICE_ID_MATCH_DEVICE,
+       .idVendor               = 0x0baf,
+       .idProduct              = 0x0111,       /* U.S. Robotics USR5420 */
+       RNDIS_MASTER_INTERFACE,
+       .driver_info            = (unsigned long) &bcm4320a_info,
+}, {
+       .match_flags    =   USB_DEVICE_ID_MATCH_INT_INFO
+                         | USB_DEVICE_ID_MATCH_DEVICE,
+       .idVendor               = 0x0411,
+       .idProduct              = 0x004b,       /* BUFFALO WLI-USB-G54 */
+       RNDIS_MASTER_INTERFACE,
+       .driver_info            = (unsigned long) &bcm4320a_info,
+},
+/* Generic Wireless RNDIS devices that we don't have exact
+ * idVendor/idProduct/chip yet.
+ */
+{
+       /* RNDIS is MSFT's un-official variant of CDC ACM */
+       USB_INTERFACE_INFO(USB_CLASS_COMM, 2 /* ACM */, 0x0ff),
+       .driver_info = (unsigned long) &rndis_wext_info,
+}, {
+       /* "ActiveSync" is an undocumented variant of RNDIS, used in WM5 */
+       USB_INTERFACE_INFO(USB_CLASS_MISC, 1, 1),
+       .driver_info = (unsigned long) &rndis_wext_info,
+},
+       { },            // END
+};
+MODULE_DEVICE_TABLE(usb, products);
+
+static struct usb_driver rndis_wlan_driver = {
+       .name =         "rndis_wlan",
+       .id_table =     products,
+       .probe =        usbnet_probe,
+       .disconnect =   usbnet_disconnect,
+       .suspend =      usbnet_suspend,
+       .resume =       usbnet_resume,
+};
+
+static int __init rndis_wlan_init(void)
+{
+       return usb_register(&rndis_wlan_driver);
+}
+module_init(rndis_wlan_init);
+
+static void __exit rndis_wlan_exit(void)
+{
+       usb_deregister(&rndis_wlan_driver);
+}
+module_exit(rndis_wlan_exit);
+
+MODULE_AUTHOR("Bjorge Dijkstra");
+MODULE_AUTHOR("Jussi Kivilinna");
+MODULE_DESCRIPTION("Driver for RNDIS based USB Wireless adapters");
+MODULE_LICENSE("GPL");
+
index ab52f221cd718c06411d50c76b06c308be7b4f3b..b31f0c26c32b7bb889ba789a562aeb7ae3f889ba 100644 (file)
@@ -1736,7 +1736,8 @@ static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev)
                        WARNING(rt2x00dev,
                                "TX status report missed for entry %p\n",
                                entry_done);
-                       rt2x00lib_txdone(entry_done, TX_FAIL_OTHER, 0);
+                       rt2x00pci_txdone(rt2x00dev, entry_done, TX_FAIL_OTHER,
+                                        0);
                        entry_done = rt2x00_get_data_entry_done(ring);
                }
 
index 07f37b0ccf913e56a3c83b1f7db39d90404decf0..27ebd689aa2127f9bbf0e47f29114c9c98dabbd9 100644 (file)
@@ -36,6 +36,7 @@ MODULE_LICENSE("GPL");
 static struct pci_device_id rtl8180_table[] __devinitdata = {
        /* rtl8185 */
        { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8185) },
+       { PCI_DEVICE(PCI_VENDOR_ID_BELKIN, 0x700f) },
        { PCI_DEVICE(PCI_VENDOR_ID_BELKIN, 0x701f) },
 
        /* rtl8180 */
index c2037b2a05bf664c5e37192bb6cc9f37956230e6..06eea6ab7bf065278f46d12bae48149d0c579d53 100644 (file)
@@ -149,7 +149,7 @@ psa_write(struct net_device *       dev,
   net_local *lp = netdev_priv(dev);
   u_char __iomem *ptr = lp->mem + PSA_ADDR + (o << 1);
   int          count = 0;
-  kio_addr_t   base = dev->base_addr;
+  unsigned int base = dev->base_addr;
   /* As there seem to have no flag PSA_BUSY as in the ISA model, we are
    * oblige to verify this address to know when the PSA is ready... */
   volatile u_char __iomem *verify = lp->mem + PSA_ADDR +
@@ -708,7 +708,7 @@ static void wl_update_history(wavepoint_history *wavepoint, unsigned char sigqua
 /* Perform a handover to a new WavePoint */
 static void wv_roam_handover(wavepoint_history *wavepoint, net_local *lp)
 {
-  kio_addr_t           base = lp->dev->base_addr;
+  unsigned int         base = lp->dev->base_addr;
   mm_t                  m;
   unsigned long         flags;
 
@@ -821,7 +821,7 @@ wv_82593_cmd(struct net_device *    dev,
             int        cmd,
             int        result)
 {
-  kio_addr_t   base = dev->base_addr;
+  unsigned int base = dev->base_addr;
   int          status;
   int          wait_completed;
   long         spin;
@@ -945,7 +945,7 @@ read_ringbuf(struct net_device *    dev,
             char *     buf,
             int        len)
 {
-  kio_addr_t   base = dev->base_addr;
+  unsigned int base = dev->base_addr;
   int          ring_ptr = addr;
   int          chunk_len;
   char *       buf_ptr = buf;
@@ -1096,7 +1096,7 @@ wv_psa_show(psa_t *       p)
 static void
 wv_mmc_show(struct net_device *        dev)
 {
-  kio_addr_t   base = dev->base_addr;
+  unsigned int base = dev->base_addr;
   net_local *  lp = netdev_priv(dev);
   mmr_t                m;
 
@@ -1275,7 +1275,7 @@ wv_packet_info(u_char *           p,              /* Packet to dump */
 static inline void
 wv_init_info(struct net_device *       dev)
 {
-  kio_addr_t   base = dev->base_addr;
+  unsigned int base = dev->base_addr;
   psa_t                psa;
   DECLARE_MAC_BUF(mac);
 
@@ -1294,7 +1294,7 @@ wv_init_info(struct net_device *  dev)
 
 #ifdef DEBUG_BASIC_SHOW
   /* Now, let's go for the basic stuff */
-  printk(KERN_NOTICE "%s: WaveLAN: port %#lx, irq %d, "
+  printk(KERN_NOTICE "%s: WaveLAN: port %#x, irq %d, "
         "hw_addr %s",
         dev->name, base, dev->irq,
         print_mac(mac, dev->dev_addr));
@@ -1828,7 +1828,7 @@ static int wavelan_set_nwid(struct net_device *dev,
                            union iwreq_data *wrqu,
                            char *extra)
 {
-       kio_addr_t base = dev->base_addr;
+       unsigned int base = dev->base_addr;
        net_local *lp = netdev_priv(dev);
        psa_t psa;
        mm_t m;
@@ -1918,7 +1918,7 @@ static int wavelan_set_freq(struct net_device *dev,
                            union iwreq_data *wrqu,
                            char *extra)
 {
-       kio_addr_t base = dev->base_addr;
+       unsigned int base = dev->base_addr;
        net_local *lp = netdev_priv(dev);
        unsigned long flags;
        int ret;
@@ -1948,7 +1948,7 @@ static int wavelan_get_freq(struct net_device *dev,
                            union iwreq_data *wrqu,
                            char *extra)
 {
-       kio_addr_t base = dev->base_addr;
+       unsigned int base = dev->base_addr;
        net_local *lp = netdev_priv(dev);
        psa_t psa;
        unsigned long flags;
@@ -1994,7 +1994,7 @@ static int wavelan_set_sens(struct net_device *dev,
                            union iwreq_data *wrqu,
                            char *extra)
 {
-       kio_addr_t base = dev->base_addr;
+       unsigned int base = dev->base_addr;
        net_local *lp = netdev_priv(dev);
        psa_t psa;
        unsigned long flags;
@@ -2060,7 +2060,7 @@ static int wavelan_set_encode(struct net_device *dev,
                              union iwreq_data *wrqu,
                              char *extra)
 {
-       kio_addr_t base = dev->base_addr;
+       unsigned int base = dev->base_addr;
        net_local *lp = netdev_priv(dev);
        unsigned long flags;
        psa_t psa;
@@ -2130,7 +2130,7 @@ static int wavelan_get_encode(struct net_device *dev,
                              union iwreq_data *wrqu,
                              char *extra)
 {
-       kio_addr_t base = dev->base_addr;
+       unsigned int base = dev->base_addr;
        net_local *lp = netdev_priv(dev);
        psa_t psa;
        unsigned long flags;
@@ -2349,7 +2349,7 @@ static int wavelan_get_range(struct net_device *dev,
                             union iwreq_data *wrqu,
                             char *extra)
 {
-       kio_addr_t base = dev->base_addr;
+       unsigned int base = dev->base_addr;
        net_local *lp = netdev_priv(dev);
        struct iw_range *range = (struct iw_range *) extra;
        unsigned long flags;
@@ -2425,7 +2425,7 @@ static int wavelan_set_qthr(struct net_device *dev,
                            union iwreq_data *wrqu,
                            char *extra)
 {
-       kio_addr_t base = dev->base_addr;
+       unsigned int base = dev->base_addr;
        net_local *lp = netdev_priv(dev);
        psa_t psa;
        unsigned long flags;
@@ -2701,7 +2701,7 @@ static const struct iw_handler_def        wavelan_handler_def =
 static iw_stats *
 wavelan_get_wireless_stats(struct net_device * dev)
 {
-  kio_addr_t           base = dev->base_addr;
+  unsigned int         base = dev->base_addr;
   net_local *          lp = netdev_priv(dev);
   mmr_t                        m;
   iw_stats *           wstats;
@@ -2764,7 +2764,7 @@ wv_start_of_frame(struct net_device *     dev,
                  int           rfp,    /* end of frame */
                  int           wrap)   /* start of buffer */
 {
-  kio_addr_t   base = dev->base_addr;
+  unsigned int base = dev->base_addr;
   int          rp;
   int          len;
 
@@ -2925,7 +2925,7 @@ wv_packet_read(struct net_device *                dev,
 static inline void
 wv_packet_rcv(struct net_device *      dev)
 {
-  kio_addr_t   base = dev->base_addr;
+  unsigned int base = dev->base_addr;
   net_local *  lp = netdev_priv(dev);
   int          newrfp;
   int          rp;
@@ -3062,7 +3062,7 @@ wv_packet_write(struct net_device *       dev,
                short           length)
 {
   net_local *          lp = netdev_priv(dev);
-  kio_addr_t           base = dev->base_addr;
+  unsigned int         base = dev->base_addr;
   unsigned long                flags;
   int                  clen = length;
   register u_short     xmtdata_base = TX_BASE;
@@ -3183,7 +3183,7 @@ wavelan_packet_xmit(struct sk_buff *      skb,
 static inline int
 wv_mmc_init(struct net_device *        dev)
 {
-  kio_addr_t   base = dev->base_addr;
+  unsigned int base = dev->base_addr;
   psa_t                psa;
   mmw_t                m;
   int          configured;
@@ -3377,7 +3377,7 @@ wv_mmc_init(struct net_device *   dev)
 static int
 wv_ru_stop(struct net_device * dev)
 {
-  kio_addr_t   base = dev->base_addr;
+  unsigned int base = dev->base_addr;
   net_local *  lp = netdev_priv(dev);
   unsigned long        flags;
   int          status;
@@ -3440,7 +3440,7 @@ wv_ru_stop(struct net_device *    dev)
 static int
 wv_ru_start(struct net_device *        dev)
 {
-  kio_addr_t   base = dev->base_addr;
+  unsigned int base = dev->base_addr;
   net_local *  lp = netdev_priv(dev);
   unsigned long        flags;
 
@@ -3528,7 +3528,7 @@ wv_ru_start(struct net_device *   dev)
 static int
 wv_82593_config(struct net_device *    dev)
 {
-  kio_addr_t                   base = dev->base_addr;
+  unsigned int                 base = dev->base_addr;
   net_local *                  lp = netdev_priv(dev);
   struct i82593_conf_block     cfblk;
   int                          ret = TRUE;
@@ -3765,7 +3765,7 @@ static int
 wv_hw_config(struct net_device *       dev)
 {
   net_local *          lp = netdev_priv(dev);
-  kio_addr_t           base = dev->base_addr;
+  unsigned int         base = dev->base_addr;
   unsigned long                flags;
   int                  ret = FALSE;
 
@@ -4047,7 +4047,7 @@ wavelan_interrupt(int             irq,
 {
   struct net_device *  dev = dev_id;
   net_local *  lp;
-  kio_addr_t   base;
+  unsigned int base;
   int          status0;
   u_int                tx_status;
 
@@ -4306,7 +4306,7 @@ static void
 wavelan_watchdog(struct net_device *   dev)
 {
   net_local *          lp = netdev_priv(dev);
-  kio_addr_t           base = dev->base_addr;
+  unsigned int         base = dev->base_addr;
   unsigned long                flags;
   int                  aborted = FALSE;
 
@@ -4382,7 +4382,7 @@ wavelan_open(struct net_device *  dev)
 {
   net_local *  lp = netdev_priv(dev);
   struct pcmcia_device *       link = lp->link;
-  kio_addr_t   base = dev->base_addr;
+  unsigned int base = dev->base_addr;
 
 #ifdef DEBUG_CALLBACK_TRACE
   printk(KERN_DEBUG "%s: ->wavelan_open(dev=0x%x)\n", dev->name,
@@ -4436,7 +4436,7 @@ static int
 wavelan_close(struct net_device *      dev)
 {
   struct pcmcia_device *       link = ((net_local *)netdev_priv(dev))->link;
-  kio_addr_t   base = dev->base_addr;
+  unsigned int base = dev->base_addr;
 
 #ifdef DEBUG_CALLBACK_TRACE
   printk(KERN_DEBUG "%s: ->wavelan_close(dev=0x%x)\n", dev->name,
index f5ef03cf9879de87cdfee0f3dc61fa50a1c1dee9..21bda2031e7e3c7e90d33c86ebeaab2f76e20e17 100644 (file)
@@ -4,5 +4,4 @@
 
 obj-y   := nubus.o
 
-obj-$(CONFIG_MODULES) += nubus_syms.o 
 obj-$(CONFIG_PROC_FS) += proc.o
index e503c9c980321ccb81e11c3a5efa0eae780c6da3..2f047e573d86cda7210d2346582324b5f126518e 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/delay.h>
+#include <linux/module.h>
 #include <asm/setup.h>
 #include <asm/system.h>
 #include <asm/page.h>
@@ -186,6 +187,7 @@ void nubus_get_rsrc_mem(void *dest, const struct nubus_dirent* dirent,
                len--;
        }
 }
+EXPORT_SYMBOL(nubus_get_rsrc_mem);
 
 void nubus_get_rsrc_str(void *dest, const struct nubus_dirent* dirent,
                        int len)
@@ -200,6 +202,7 @@ void nubus_get_rsrc_str(void *dest, const struct nubus_dirent* dirent,
                len--;
        }
 }
+EXPORT_SYMBOL(nubus_get_rsrc_str);
 
 int nubus_get_root_dir(const struct nubus_board* board,
                       struct nubus_dir* dir)
@@ -209,6 +212,7 @@ int nubus_get_root_dir(const struct nubus_board* board,
        dir->mask = board->lanes;
        return 0;
 }
+EXPORT_SYMBOL(nubus_get_root_dir);
 
 /* This is a slyly renamed version of the above */
 int nubus_get_func_dir(const struct nubus_dev* dev,
@@ -219,6 +223,7 @@ int nubus_get_func_dir(const struct nubus_dev* dev,
        dir->mask = dev->board->lanes;
        return 0;
 }
+EXPORT_SYMBOL(nubus_get_func_dir);
 
 int nubus_get_board_dir(const struct nubus_board* board,
                        struct nubus_dir* dir)
@@ -237,6 +242,7 @@ int nubus_get_board_dir(const struct nubus_board* board,
                return -1;
        return 0;
 }
+EXPORT_SYMBOL(nubus_get_board_dir);
 
 int nubus_get_subdir(const struct nubus_dirent *ent,
                     struct nubus_dir *dir)
@@ -246,6 +252,7 @@ int nubus_get_subdir(const struct nubus_dirent *ent,
        dir->mask = ent->mask;
        return 0;
 }
+EXPORT_SYMBOL(nubus_get_subdir);
 
 int nubus_readdir(struct nubus_dir *nd, struct nubus_dirent *ent)
 {
@@ -274,12 +281,14 @@ int nubus_readdir(struct nubus_dir *nd, struct nubus_dirent *ent)
        ent->mask  = nd->mask;
        return 0;
 }
+EXPORT_SYMBOL(nubus_readdir);
 
 int nubus_rewinddir(struct nubus_dir* dir)
 {
        dir->ptr = dir->base;
        return 0;
 }
+EXPORT_SYMBOL(nubus_rewinddir);
 
 /* Driver interface functions, more or less like in pci.c */
 
@@ -303,6 +312,7 @@ nubus_find_device(unsigned short category,
        }
        return NULL;
 }
+EXPORT_SYMBOL(nubus_find_device);
 
 struct nubus_dev*
 nubus_find_type(unsigned short category,
@@ -320,6 +330,7 @@ nubus_find_type(unsigned short category,
        }
        return NULL;
 }
+EXPORT_SYMBOL(nubus_find_type);
 
 struct nubus_dev*
 nubus_find_slot(unsigned int slot,
@@ -335,6 +346,7 @@ nubus_find_slot(unsigned int slot,
        }
        return NULL;
 }
+EXPORT_SYMBOL(nubus_find_slot);
 
 int
 nubus_find_rsrc(struct nubus_dir* dir, unsigned char rsrc_type,
@@ -346,13 +358,14 @@ nubus_find_rsrc(struct nubus_dir* dir, unsigned char rsrc_type,
        }       
        return -1;
 }
+EXPORT_SYMBOL(nubus_find_rsrc);
 
 /* Initialization functions - decide which slots contain stuff worth
    looking at, and print out lots and lots of information from the
    resource blocks. */
 
 /* FIXME: A lot of this stuff will eventually be useful after
-   initializaton, for intelligently probing Ethernet and video chips,
+   initialization, for intelligently probing Ethernet and video chips,
    among other things.  The rest of it should go in the /proc code.
    For now, we just use it to give verbose boot logs. */
 
diff --git a/drivers/nubus/nubus_syms.c b/drivers/nubus/nubus_syms.c
deleted file mode 100644 (file)
index 9204f04..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-/* Exported symbols for NuBus services
-
-   (c) 1999 David Huggins-Daines <dhd@debian.org> */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/nubus.h>
-
-#ifdef CONFIG_PROC_FS
-EXPORT_SYMBOL(nubus_proc_attach_device);
-EXPORT_SYMBOL(nubus_proc_detach_device);
-#endif
-
-MODULE_LICENSE("GPL");
-
-EXPORT_SYMBOL(nubus_find_device);
-EXPORT_SYMBOL(nubus_find_type);
-EXPORT_SYMBOL(nubus_find_slot);
-EXPORT_SYMBOL(nubus_get_root_dir);
-EXPORT_SYMBOL(nubus_get_board_dir);
-EXPORT_SYMBOL(nubus_get_func_dir);
-EXPORT_SYMBOL(nubus_readdir);
-EXPORT_SYMBOL(nubus_find_rsrc);
-EXPORT_SYMBOL(nubus_rewinddir);
-EXPORT_SYMBOL(nubus_get_subdir);
-EXPORT_SYMBOL(nubus_get_rsrc_mem);
-EXPORT_SYMBOL(nubus_get_rsrc_str);
-
index 5271a4a7af26f7884283bac95457c0c1ef8a04f1..e07492be1f4ac36a418896f77f45a4a25fffdaa7 100644 (file)
@@ -22,6 +22,8 @@
 #include <linux/nubus.h>
 #include <linux/proc_fs.h>
 #include <linux/init.h>
+#include <linux/module.h>
+
 #include <asm/uaccess.h>
 #include <asm/byteorder.h>
 
@@ -140,6 +142,7 @@ int nubus_proc_attach_device(struct nubus_dev *dev)
 
        return 0;
 }
+EXPORT_SYMBOL(nubus_proc_attach_device);
 
 /* FIXME: this is certainly broken! */
 int nubus_proc_detach_device(struct nubus_dev *dev)
@@ -154,6 +157,7 @@ int nubus_proc_detach_device(struct nubus_dev *dev)
        }
        return 0;
 }
+EXPORT_SYMBOL(nubus_proc_detach_device);
 
 void __init proc_bus_nubus_add_devices(void)
 {
index b306fef1ac4151dffe03a89d4328ca4e6f703547..80c9deca5f35aa3313245d099215d5f387c687b1 100644 (file)
@@ -137,6 +137,31 @@ struct device_node *of_get_parent(const struct device_node *node)
 }
 EXPORT_SYMBOL(of_get_parent);
 
+/**
+ *     of_get_next_parent - Iterate to a node's parent
+ *     @node:  Node to get parent of
+ *
+ *     This is like of_get_parent() except that it drops the
+ *     refcount on the passed node, making it suitable for iterating
+ *     through a node's parents.
+ *
+ *     Returns a node pointer with refcount incremented, use
+ *     of_node_put() on it when done.
+ */
+struct device_node *of_get_next_parent(struct device_node *node)
+{
+       struct device_node *parent;
+
+       if (!node)
+               return NULL;
+
+       read_lock(&devtree_lock);
+       parent = of_node_get(node->parent);
+       of_node_put(node);
+       read_unlock(&devtree_lock);
+       return parent;
+}
+
 /**
  *     of_get_next_child - Iterate a node childs
  *     @node:  parent node
index b47bb2d7476a82e5618fc50c0772cfea9ddd46ec..ca09a63a64db7bdf66a03f0da0069518615e3d6f 100644 (file)
@@ -85,6 +85,15 @@ static int of_platform_device_resume(struct device * dev)
        return error;
 }
 
+static void of_platform_device_shutdown(struct device *dev)
+{
+       struct of_device *of_dev = to_of_device(dev);
+       struct of_platform_driver *drv = to_of_platform_driver(dev->driver);
+
+       if (dev->driver && drv->shutdown)
+               drv->shutdown(of_dev);
+}
+
 int of_bus_type_init(struct bus_type *bus, const char *name)
 {
        bus->name = name;
@@ -93,6 +102,7 @@ int of_bus_type_init(struct bus_type *bus, const char *name)
        bus->remove = of_platform_device_remove;
        bus->suspend = of_platform_device_suspend;
        bus->resume = of_platform_device_resume;
+       bus->shutdown = of_platform_device_shutdown;
        return bus_register(bus);
 }
 
index 7c60cbd85dc8505883e14ad9091f456badfdb427..d08b284de196b2e807518ac656d678e585f9560c 100644 (file)
@@ -363,7 +363,7 @@ ccio_alloc_range(struct ioc *ioc, size_t size)
        if (pages_needed <= 8) {
                /*
                 * LAN traffic will not thrash the TLB IFF the same NIC
-                * uses 8 adjacent pages to map seperate payload data.
+                * uses 8 adjacent pages to map separate payload data.
                 * ie the same byte in the resource bit map.
                 */
 #if 0
@@ -941,7 +941,7 @@ ccio_map_sg(struct device *dev, struct scatterlist *sglist, int nents,
        ** w/o this association, we wouldn't have coherent DMA!
        ** Access to the virtual address is what forces a two pass algorithm.
        */
-       coalesced = iommu_coalesce_chunks(ioc, sglist, nents, ccio_alloc_range);
+       coalesced = iommu_coalesce_chunks(ioc, dev, sglist, nents, ccio_alloc_range);
 
        /*
        ** Program the I/O Pdir
@@ -1589,7 +1589,7 @@ static int __init ccio_probe(struct parisc_device *dev)
 }
 
 /**
- * ccio_init - ccio initalization procedure.
+ * ccio_init - ccio initialization procedure.
  *
  * Register this driver.
  */
index a728a7cd2fc80156ae3fd1b1d358e6b87934eb87..65eee67aa2ae66d9ac9130c9ee7efb6fab896a74 100644 (file)
@@ -95,7 +95,7 @@ static struct parisc_driver hppb_driver = {
 };
 
 /**
- * hppb_init - HP-PB bus initalization procedure.
+ * hppb_init - HP-PB bus initialization procedure.
  *
  * Register this driver.   
  */
index 0a1f99a2e93edf262b904fe886f1c2fc074c6de4..97ba8286c5969285294c2dd886a0e375071f4878 100644 (file)
@@ -95,12 +95,14 @@ iommu_fill_pdir(struct ioc *ioc, struct scatterlist *startsg, int nents,
 */
 
 static inline unsigned int
-iommu_coalesce_chunks(struct ioc *ioc, struct scatterlist *startsg, int nents,
+iommu_coalesce_chunks(struct ioc *ioc, struct device *dev,
+                     struct scatterlist *startsg, int nents,
                      int (*iommu_alloc_range)(struct ioc *, size_t))
 {
        struct scatterlist *contig_sg;     /* contig chunk head */
        unsigned long dma_offset, dma_len; /* start/len of DMA stream */
        unsigned int n_mappings = 0;
+       unsigned int max_seg_size = dma_get_max_seg_size(dev);
 
        while (nents > 0) {
 
@@ -142,6 +144,9 @@ iommu_coalesce_chunks(struct ioc *ioc, struct scatterlist *startsg, int nents,
                                            IOVP_SIZE) > DMA_CHUNK_SIZE))
                                break;
 
+                       if (startsg->length + dma_len > max_seg_size)
+                               break;
+
                        /*
                        ** Next see if we can append the next chunk (i.e.
                        ** it must end on one page and begin on another
index e527a0e1d6c01820c7fa24d911d9e5bacb6e33a4..d06627c3f353a607f7730b300af68a3d607b83b6 100644 (file)
@@ -946,7 +946,7 @@ sba_map_sg(struct device *dev, struct scatterlist *sglist, int nents,
        ** w/o this association, we wouldn't have coherent DMA!
        ** Access to the virtual address is what forces a two pass algorithm.
        */
-       coalesced = iommu_coalesce_chunks(ioc, sglist, nents, sba_alloc_range);
+       coalesced = iommu_coalesce_chunks(ioc, dev, sglist, nents, sba_alloc_range);
 
        /*
        ** Program the I/O Pdir
index 853a15f44f8889f7f1b5d401df730677633232f6..cd565bb4e1a990ba303aa308a6094c7466b3e331 100644 (file)
@@ -163,7 +163,7 @@ static ssize_t parport_read_device_id (struct parport *port, char *buffer,
        idlens[1] = idlens[0]+2;
        if (belen != lelen) {
                int off = 2;
-               /* Don't try lenghts of 0x100 and 0x200 as 1 and 2 */
+               /* Don't try lengths of 0x100 and 0x200 as 1 and 2 */
                if (idlens[0] <= 2)
                        off = 0;
                idlens[off] = max(belen, lelen);
index f697f3d728eb6317ad048cd087ceb26af8962117..9f04d17576d6fb37e1f58368dfa5326264369208 100644 (file)
@@ -13,6 +13,9 @@ obj-$(CONFIG_HOTPLUG) += hotplug.o
 
 # Build the PCI Hotplug drivers if we were asked to
 obj-$(CONFIG_HOTPLUG_PCI) += hotplug/
+ifdef CONFIG_HOTPLUG_PCI
+obj-y += hotplug-pci.o
+endif
 
 # Build the PCI MSI interrupt support
 obj-$(CONFIG_PCI_MSI) += msi.o
index 9e5ea074ad20f56d041a2fbf82d19ab27f7dca43..ef5a6a245f5fa36363d513e5aa35fef248a499a4 100644 (file)
@@ -108,6 +108,7 @@ int pci_bus_add_device(struct pci_dev *dev)
 void pci_bus_add_devices(struct pci_bus *bus)
 {
        struct pci_dev *dev;
+       struct pci_bus *child_bus;
        int retval;
 
        list_for_each_entry(dev, &bus->devices, bus_list) {
@@ -138,11 +139,19 @@ void pci_bus_add_devices(struct pci_bus *bus)
                               up_write(&pci_bus_sem);
                        }
                        pci_bus_add_devices(dev->subordinate);
-                       retval = sysfs_create_link(&dev->subordinate->class_dev.kobj,
-                                                  &dev->dev.kobj, "bridge");
+
+                       /* register the bus with sysfs as the parent is now
+                        * properly registered. */
+                       child_bus = dev->subordinate;
+                       child_bus->dev.parent = child_bus->bridge;
+                       retval = device_register(&child_bus->dev);
+                       if (!retval)
+                               retval = device_create_file(&child_bus->dev,
+                                                       &dev_attr_cpuaffinity);
                        if (retval)
-                               dev_err(&dev->dev, "Error creating sysfs "
-                                       "bridge symlink, continuing...\n");
+                               dev_err(&dev->dev, "Error registering pci_bus"
+                                       " device bridge symlink,"
+                                       " continuing...\n");
                }
        }
 }
@@ -204,7 +213,6 @@ void pci_walk_bus(struct pci_bus *top, void (*cb)(struct pci_dev *, void *),
        }
        up_read(&pci_bus_sem);
 }
-EXPORT_SYMBOL_GPL(pci_walk_bus);
 
 EXPORT_SYMBOL(pci_bus_alloc_resource);
 EXPORT_SYMBOL_GPL(pci_bus_add_device);
index 5dfdfdac92e1bc83862707aab71d356d47a36eff..91b2dc956be5de68e1ebefe1585e6e79cea62fab 100644 (file)
@@ -25,6 +25,7 @@
 
 #include <linux/pci.h>
 #include <linux/dmar.h>
+#include "iova.h"
 
 #undef PREFIX
 #define PREFIX "DMAR:"
@@ -263,8 +264,8 @@ parse_dmar_table(void)
        if (!dmar)
                return -ENODEV;
 
-       if (!dmar->width) {
-               printk (KERN_WARNING PREFIX "Zero: Invalid DMAR haw\n");
+       if (dmar->width < PAGE_SHIFT_4K - 1) {
+               printk(KERN_WARNING PREFIX "Invalid DMAR haw\n");
                return -EINVAL;
        }
 
@@ -301,11 +302,24 @@ parse_dmar_table(void)
 int __init dmar_table_init(void)
 {
 
-       parse_dmar_table();
+       int ret;
+
+       ret = parse_dmar_table();
+       if (ret) {
+               printk(KERN_INFO PREFIX "parse DMAR table failure.\n");
+               return ret;
+       }
+
        if (list_empty(&dmar_drhd_units)) {
                printk(KERN_INFO PREFIX "No DMAR devices found\n");
                return -ENODEV;
        }
+
+       if (list_empty(&dmar_rmrr_units)) {
+               printk(KERN_INFO PREFIX "No RMRR found\n");
+               return -ENODEV;
+       }
+
        return 0;
 }
 
diff --git a/drivers/pci/hotplug-pci.c b/drivers/pci/hotplug-pci.c
new file mode 100644 (file)
index 0000000..a590ef6
--- /dev/null
@@ -0,0 +1,20 @@
+/* Core PCI functionality used only by PCI hotplug */
+
+#include <linux/pci.h>
+#include "pci.h"
+
+
+unsigned int pci_do_scan_bus(struct pci_bus *bus)
+{
+       unsigned int max;
+
+       max = pci_scan_child_bus(bus);
+
+       /*
+        * Make the discovered devices available.
+        */
+       pci_bus_add_devices(bus);
+
+       return max;
+}
+EXPORT_SYMBOL(pci_do_scan_bus);
index a64449d489d635b9743ce79f2cf52c8904feb125..2cdd8326f1363d5916db000f1af7f2f6a5b22a2a 100644 (file)
@@ -3,8 +3,8 @@
 #
 
 menuconfig HOTPLUG_PCI
-       tristate "Support for PCI Hotplug (EXPERIMENTAL)"
-       depends on PCI && EXPERIMENTAL && HOTPLUG
+       tristate "Support for PCI Hotplug"
+       depends on PCI && HOTPLUG
        ---help---
          Say Y here if you have a motherboard with a PCI Hotplug controller.
          This allows you to add and remove PCI cards while the machine is
index 34a1891191fd4c06261de07a8671512869e3d08d..9bdbe1a6688f728b815014607e8bb8a5ef6ef562 100644 (file)
@@ -3,7 +3,6 @@
 #
 
 obj-$(CONFIG_HOTPLUG_PCI)              += pci_hotplug.o
-obj-$(CONFIG_HOTPLUG_PCI_FAKE)         += fakephp.o 
 obj-$(CONFIG_HOTPLUG_PCI_COMPAQ)       += cpqphp.o
 obj-$(CONFIG_HOTPLUG_PCI_IBM)          += ibmphp.o
 obj-$(CONFIG_HOTPLUG_PCI_ACPI)         += acpiphp.o
@@ -16,6 +15,9 @@ obj-$(CONFIG_HOTPLUG_PCI_RPA)         += rpaphp.o
 obj-$(CONFIG_HOTPLUG_PCI_RPA_DLPAR)    += rpadlpar_io.o
 obj-$(CONFIG_HOTPLUG_PCI_SGI)          += sgi_hotplug.o
 
+# Link this last so it doesn't claim devices that have a real hotplug driver
+obj-$(CONFIG_HOTPLUG_PCI_FAKE)         += fakephp.o
+
 pci_hotplug-objs       :=      pci_hotplug_core.o
 
 ifdef CONFIG_HOTPLUG_PCI_CPCI
index 1ef417cca2db2a370be207ce8db51146e5386cd5..7a29164d4b325aa2ee4219398b679b066f0e27a6 100644 (file)
@@ -113,7 +113,6 @@ struct acpiphp_slot {
        u8              device;         /* pci device# */
 
        u32             sun;            /* ACPI _SUN (slot unique number) */
-       u32             slotno;         /* slot number relative to bridge */
        u32             flags;          /* see below */
 };
 
index ff1b1c71291a84412086b25db6b99c0a1efc29d3..cf22f9e01e005721257bd61c7a2894008f65b497 100644 (file)
@@ -102,7 +102,7 @@ static int is_ejectable(acpi_handle handle)
 }
 
 
-/* callback routine to check the existence of ejectable slots */
+/* callback routine to check for the existence of ejectable slots */
 static acpi_status
 is_ejectable_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
 {
@@ -117,7 +117,7 @@ is_ejectable_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
        }
 }
 
-/* callback routine to check for the existance of a pci dock device */
+/* callback routine to check for the existence of a pci dock device */
 static acpi_status
 is_pci_dock_device(acpi_handle handle, u32 lvl, void *context, void **rv)
 {
@@ -1528,7 +1528,6 @@ check_sub_bridges(acpi_handle handle, u32 lvl, void *context, void **rv)
                acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
                dbg("%s: re-enumerating slots under %s\n",
                        __FUNCTION__, objname);
-               acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
                acpiphp_check_bridge(bridge);
        }
        return AE_OK ;
index d7a293e3faf5debc9fb8d3df0b571bde3e663c33..94b640146d4456b4aa0b96b1022f7efcfadbd256 100644 (file)
@@ -39,6 +39,7 @@
 #include <linux/init.h>
 #include <linux/string.h>
 #include <linux/slab.h>
+#include <linux/workqueue.h>
 #include "../pci.h"
 
 #if !defined(MODULE)
@@ -63,10 +64,16 @@ struct dummy_slot {
        struct list_head node;
        struct hotplug_slot *slot;
        struct pci_dev *dev;
+       struct work_struct remove_work;
+       unsigned long removed;
 };
 
 static int debug;
 static LIST_HEAD(slot_list);
+static struct workqueue_struct *dummyphp_wq;
+
+static void pci_rescan_worker(struct work_struct *work);
+static DECLARE_WORK(pci_rescan_work, pci_rescan_worker);
 
 static int enable_slot (struct hotplug_slot *slot);
 static int disable_slot (struct hotplug_slot *slot);
@@ -109,7 +116,7 @@ static int add_slot(struct pci_dev *dev)
        slot->name = &dev->dev.bus_id[0];
        dbg("slot->name = %s\n", slot->name);
 
-       dslot = kmalloc(sizeof(struct dummy_slot), GFP_KERNEL);
+       dslot = kzalloc(sizeof(struct dummy_slot), GFP_KERNEL);
        if (!dslot)
                goto error_info;
 
@@ -164,6 +171,14 @@ static void remove_slot(struct dummy_slot *dslot)
                err("Problem unregistering a slot %s\n", dslot->slot->name);
 }
 
+/* called from the single-threaded workqueue handler to remove a slot */
+static void remove_slot_worker(struct work_struct *work)
+{
+       struct dummy_slot *dslot =
+               container_of(work, struct dummy_slot, remove_work);
+       remove_slot(dslot);
+}
+
 /**
  * pci_rescan_slot - Rescan slot
  * @temp: Device template. Should be set: bus and devfn.
@@ -267,11 +282,17 @@ static inline void pci_rescan(void) {
        pci_rescan_buses(&pci_root_buses);
 }
 
+/* called from the single-threaded workqueue handler to rescan all pci buses */
+static void pci_rescan_worker(struct work_struct *work)
+{
+       pci_rescan();
+}
 
 static int enable_slot(struct hotplug_slot *hotplug_slot)
 {
        /* mis-use enable_slot for rescanning of the pci bus */
-       pci_rescan();
+       cancel_work_sync(&pci_rescan_work);
+       queue_work(dummyphp_wq, &pci_rescan_work);
        return -ENODEV;
 }
 
@@ -306,6 +327,10 @@ static int disable_slot(struct hotplug_slot *slot)
                err("Can't remove PCI devices with other PCI devices behind it yet.\n");
                return -ENODEV;
        }
+       if (test_and_set_bit(0, &dslot->removed)) {
+               dbg("Slot already scheduled for removal\n");
+               return -ENODEV;
+       }
        /* search for subfunctions and disable them first */
        if (!(dslot->dev->devfn & 7)) {
                for (func = 1; func < 8; func++) {
@@ -328,8 +353,9 @@ static int disable_slot(struct hotplug_slot *slot)
        /* remove the device from the pci core */
        pci_remove_bus_device(dslot->dev);
 
-       /* blow away this sysfs entry and other parts. */
-       remove_slot(dslot);
+       /* queue work item to blow away this sysfs entry and other parts. */
+       INIT_WORK(&dslot->remove_work, remove_slot_worker);
+       queue_work(dummyphp_wq, &dslot->remove_work);
 
        return 0;
 }
@@ -340,6 +366,7 @@ static void cleanup_slots (void)
        struct list_head *next;
        struct dummy_slot *dslot;
 
+       destroy_workqueue(dummyphp_wq);
        list_for_each_safe (tmp, next, &slot_list) {
                dslot = list_entry (tmp, struct dummy_slot, node);
                remove_slot(dslot);
@@ -351,6 +378,10 @@ static int __init dummyphp_init(void)
 {
        info(DRIVER_DESC "\n");
 
+       dummyphp_wq = create_singlethread_workqueue(MY_NAME);
+       if (!dummyphp_wq)
+               return -ENOMEM;
+
        return pci_scan_buses();
 }
 
index a90c28d0c69df75c3cb62b2ca19d3073b49839d1..87b6b8b280e65024fe112e06f1fe59e75a297aeb 100644 (file)
@@ -761,10 +761,13 @@ static void ibm_unconfigure_device(struct pci_func *func)
        debug("func->device << 3 | 0x0  = %x\n", func->device << 3 | 0x0);
 
        for (j = 0; j < 0x08; j++) {
-               temp = pci_find_slot(func->busno, (func->device << 3) | j);
-               if (temp)
+               temp = pci_get_bus_and_slot(func->busno, (func->device << 3) | j);
+               if (temp) {
                        pci_remove_bus_device(temp);
+                       pci_dev_put(temp);
+               }
        }
+       pci_dev_put(func->dev);
 }
 
 /*
@@ -823,7 +826,7 @@ static int ibm_configure_device(struct pci_func *func)
        if (!(bus_structure_fixup(func->busno)))
                flag = 1;
        if (func->dev == NULL)
-               func->dev = pci_find_slot(func->busno,
+               func->dev = pci_get_bus_and_slot(func->busno,
                                PCI_DEVFN(func->device, func->function));
 
        if (func->dev == NULL) {
@@ -836,7 +839,7 @@ static int ibm_configure_device(struct pci_func *func)
                if (num)
                        pci_bus_add_devices(bus);
 
-               func->dev = pci_find_slot(func->busno,
+               func->dev = pci_get_bus_and_slot(func->busno,
                                PCI_DEVFN(func->device, func->function));
                if (func->dev == NULL) {
                        err("ERROR... : pci_dev still NULL\n");
index 47bb0e1ff3faff303a72cbe17963da8e34f675fc..dd59a050260fe81035bd42193b1c5613d8c70b84 100644 (file)
@@ -137,7 +137,7 @@ static int get_##name (struct hotplug_slot *slot, type *value)              \
        int retval = 0;                                                 \
        if (try_module_get(ops->owner)) {                               \
                if (ops->get_##name)                                    \
-                       retval = ops->get_##name (slot, value);         \
+                       retval = ops->get_##name(slot, value);          \
                else                                                    \
                        *value = slot->info->name;                      \
                module_put(ops->owner);                                 \
@@ -625,7 +625,7 @@ int pci_hp_register (struct hotplug_slot *slot)
        if ((slot->info == NULL) || (slot->ops == NULL))
                return -EINVAL;
        if (slot->release == NULL) {
-               dbg("Why are you trying to register a hotplug slot"
+               dbg("Why are you trying to register a hotplug slot "
                    "without a proper release function?\n");
                return -EINVAL;
        }
index 7959c222dc24e939c7734fc201fab8491004a3b0..ca656b27a500bb1eb861284fae3a193d2d3181ec 100644 (file)
@@ -82,24 +82,18 @@ struct event_info {
 };
 
 struct controller {
-       struct controller *next;
        struct mutex crit_sect;         /* critical section mutex */
        struct mutex ctrl_lock;         /* controller lock */
        int num_slots;                  /* Number of slots on ctlr */
        int slot_num_inc;               /* 1 or -1 */
        struct pci_dev *pci_dev;
        struct list_head slot_list;
-       struct slot *slot;
        struct hpc_ops *hpc_ops;
        wait_queue_head_t queue;        /* sleep & wake process */
-       u8 bus;
-       u8 device;
-       u8 function;
        u8 slot_device_offset;
        u32 first_slot;         /* First physical slot number */  /* PCIE only has 1 slot */
        u8 slot_bus;            /* Bus where the slots handled by this controller sit */
        u8 ctrlcap;
-       u16 vendor_id;
        u8 cap_base;
        struct timer_list poll_timer;
        volatile int cmd_busy;
@@ -161,6 +155,9 @@ extern int pciehp_configure_device(struct slot *p_slot);
 extern int pciehp_unconfigure_device(struct slot *p_slot);
 extern void pciehp_queue_pushbutton_work(struct work_struct *work);
 int pcie_init(struct controller *ctrl, struct pcie_device *dev);
+int pciehp_enable_slot(struct slot *p_slot);
+int pciehp_disable_slot(struct slot *p_slot);
+int pcie_init_hardware_part2(struct controller *ctrl, struct pcie_device *dev);
 
 static inline struct slot *pciehp_find_slot(struct controller *ctrl, u8 device)
 {
index 6462ac3b405fcc722f1f57e345e441a94138410a..7f4836b8e71e31e9c68071d120114d9a4b8a3317 100644 (file)
@@ -453,13 +453,9 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_
 
        pci_set_drvdata(pdev, ctrl);
 
-       ctrl->bus = pdev->bus->number;  /* ctrl bus */
-       ctrl->slot_bus = pdev->subordinate->number;  /* bus controlled by this HPC */
-
-       ctrl->device = PCI_SLOT(pdev->devfn);
-       ctrl->function = PCI_FUNC(pdev->devfn);
-       dbg("%s: ctrl bus=0x%x, device=%x, function=%x, irq=%x\n", __FUNCTION__,
-               ctrl->bus, ctrl->device, ctrl->function, pdev->irq);
+       dbg("%s: ctrl bus=0x%x, device=%x, function=%x, irq=%x\n",
+           __FUNCTION__, pdev->bus->number, PCI_SLOT(pdev->devfn),
+           PCI_FUNC(pdev->devfn), pdev->irq);
 
        /* Setup the slot information structures */
        rc = init_slots(ctrl);
@@ -471,6 +467,11 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_
        t_slot = pciehp_find_slot(ctrl, ctrl->slot_device_offset);
 
        t_slot->hpc_ops->get_adapter_status(t_slot, &value); /* Check if slot is occupied */
+       if (value) {
+               rc = pciehp_enable_slot(t_slot);
+               if (rc) /* -ENODEV: shouldn't happen, but deal with it */
+                       value = 0;
+       }
        if ((POWER_CTRL(ctrl->ctrlcap)) && !value) {
                rc = t_slot->hpc_ops->power_off_slot(t_slot); /* Power off slot if not occupied*/
                if (rc)
@@ -509,6 +510,24 @@ static int pciehp_suspend (struct pcie_device *dev, pm_message_t state)
 static int pciehp_resume (struct pcie_device *dev)
 {
        printk("%s ENTRY\n", __FUNCTION__);
+       if (pciehp_force) {
+               struct pci_dev *pdev = dev->port;
+               struct controller *ctrl = pci_get_drvdata(pdev);
+               struct slot *t_slot;
+               u8 status;
+
+               /* reinitialize the chipset's event detection logic */
+               pcie_init_hardware_part2(ctrl, dev);
+
+               t_slot = pciehp_find_slot(ctrl, ctrl->slot_device_offset);
+
+               /* Check if slot is occupied */
+               t_slot->hpc_ops->get_adapter_status(t_slot, &status);
+               if (status)
+                       pciehp_enable_slot(t_slot);
+               else
+                       pciehp_disable_slot(t_slot);
+       }
        return 0;
 }
 #endif
index f1e0966cee95b164d458c3126466d62f063cf00c..b23061c56115f9c65e5fb6dadedf3a1d5339d725 100644 (file)
@@ -37,8 +37,6 @@
 #include "pciehp.h"
 
 static void interrupt_event_handler(struct work_struct *work);
-static int pciehp_enable_slot(struct slot *p_slot);
-static int pciehp_disable_slot(struct slot *p_slot);
 
 static int queue_interrupt_event(struct slot *p_slot, u32 event_type)
 {
@@ -197,12 +195,6 @@ static void set_slot_off(struct controller *ctrl, struct slot * pslot)
                            __FUNCTION__);
                        return;
                }
-               /*
-                * After turning power off, we must wait for at least
-                * 1 second before taking any action that relies on
-                * power having been removed from the slot/adapter.
-                */
-               msleep(1000);
        }
 }
 
@@ -215,15 +207,12 @@ static void set_slot_off(struct controller *ctrl, struct slot * pslot)
  */
 static int board_added(struct slot *p_slot)
 {
-       u8 hp_slot;
        int retval = 0;
        struct controller *ctrl = p_slot->ctrl;
 
-       hp_slot = p_slot->device - ctrl->slot_device_offset;
-
        dbg("%s: slot device, slot offset, hp slot = %d, %d ,%d\n",
                        __FUNCTION__, p_slot->device,
-                       ctrl->slot_device_offset, hp_slot);
+                       ctrl->slot_device_offset, p_slot->hp_slot);
 
        if (POWER_CTRL(ctrl->ctrlcap)) {
                /* Power on slot */
@@ -281,8 +270,6 @@ err_exit:
  */
 static int remove_board(struct slot *p_slot)
 {
-       u8 device;
-       u8 hp_slot;
        int retval = 0;
        struct controller *ctrl = p_slot->ctrl;
 
@@ -290,11 +277,7 @@ static int remove_board(struct slot *p_slot)
        if (retval)
                return retval;
 
-       device = p_slot->device;
-       hp_slot = p_slot->device - ctrl->slot_device_offset;
-       p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
-
-       dbg("In %s, hp_slot = %d\n", __FUNCTION__, hp_slot);
+       dbg("In %s, hp_slot = %d\n", __FUNCTION__, p_slot->hp_slot);
 
        if (POWER_CTRL(ctrl->ctrlcap)) {
                /* power off slot */
@@ -621,12 +604,6 @@ int pciehp_disable_slot(struct slot *p_slot)
                        mutex_unlock(&p_slot->ctrl->crit_sect);
                        return -EINVAL;
                }
-               /*
-                * After turning power off, we must wait for at least
-                * 1 second before taking any action that relies on
-                * power having been removed from the slot/adapter.
-                */
-               msleep(1000);
        }
 
        ret = remove_board(p_slot);
index 06d025b8b13f6a8f276e396bfc36a742c5a676a4..6eba9b2cfb90b359fc1fb92b45408846b4694f6f 100644 (file)
@@ -636,15 +636,57 @@ static int hpc_power_on_slot(struct slot * slot)
        return retval;
 }
 
+static inline int pcie_mask_bad_dllp(struct controller *ctrl)
+{
+       struct pci_dev *dev = ctrl->pci_dev;
+       int pos;
+       u32 reg;
+
+       pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
+       if (!pos)
+               return 0;
+       pci_read_config_dword(dev, pos + PCI_ERR_COR_MASK, &reg);
+       if (reg & PCI_ERR_COR_BAD_DLLP)
+               return 0;
+       reg |= PCI_ERR_COR_BAD_DLLP;
+       pci_write_config_dword(dev, pos + PCI_ERR_COR_MASK, reg);
+       return 1;
+}
+
+static inline void pcie_unmask_bad_dllp(struct controller *ctrl)
+{
+       struct pci_dev *dev = ctrl->pci_dev;
+       u32 reg;
+       int pos;
+
+       pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
+       if (!pos)
+               return;
+       pci_read_config_dword(dev, pos + PCI_ERR_COR_MASK, &reg);
+       if (!(reg & PCI_ERR_COR_BAD_DLLP))
+               return;
+       reg &= ~PCI_ERR_COR_BAD_DLLP;
+       pci_write_config_dword(dev, pos + PCI_ERR_COR_MASK, reg);
+}
+
 static int hpc_power_off_slot(struct slot * slot)
 {
        struct controller *ctrl = slot->ctrl;
        u16 slot_cmd;
        u16 cmd_mask;
        int retval = 0;
+       int changed;
 
        dbg("%s: slot->hp_slot %x\n", __FUNCTION__, slot->hp_slot);
 
+       /*
+        * Set Bad DLLP Mask bit in Correctable Error Mask
+        * Register. This is the workaround against Bad DLLP error
+        * that sometimes happens during turning power off the slot
+        * which conforms to PCI Express 1.0a spec.
+        */
+       changed = pcie_mask_bad_dllp(ctrl);
+
        slot_cmd = POWER_OFF;
        cmd_mask = PWR_CTRL;
        /*
@@ -674,6 +716,16 @@ static int hpc_power_off_slot(struct slot * slot)
        dbg("%s: SLOTCTRL %x write cmd %x\n",
            __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd);
 
+       /*
+        * After turning power off, we must wait for at least 1 second
+        * before taking any action that relies on power having been
+        * removed from the slot/adapter.
+        */
+       msleep(1000);
+
+       if (changed)
+               pcie_unmask_bad_dllp(ctrl);
+
        return retval;
 }
 
@@ -1067,13 +1119,143 @@ int pciehp_acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev)
 }
 #endif
 
-int pcie_init(struct controller * ctrl, struct pcie_device *dev)
+static int pcie_init_hardware_part1(struct controller *ctrl,
+                                   struct pcie_device *dev)
+{
+       int rc;
+       u16 temp_word;
+       u32 slot_cap;
+       u16 slot_status;
+
+       rc = pciehp_readl(ctrl, SLOTCAP, &slot_cap);
+       if (rc) {
+               err("%s: Cannot read SLOTCAP register\n", __FUNCTION__);
+               return -1;
+       }
+
+       /* Mask Hot-plug Interrupt Enable */
+       rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word);
+       if (rc) {
+               err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
+               return -1;
+       }
+
+       dbg("%s: SLOTCTRL %x value read %x\n",
+           __FUNCTION__, ctrl->cap_base + SLOTCTRL, temp_word);
+       temp_word = (temp_word & ~HP_INTR_ENABLE & ~CMD_CMPL_INTR_ENABLE) |
+               0x00;
+
+       rc = pciehp_writew(ctrl, SLOTCTRL, temp_word);
+       if (rc) {
+               err("%s: Cannot write to SLOTCTRL register\n", __FUNCTION__);
+               return -1;
+       }
+
+       rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
+       if (rc) {
+               err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__);
+               return -1;
+       }
+
+       temp_word = 0x1F; /* Clear all events */
+       rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word);
+       if (rc) {
+               err("%s: Cannot write to SLOTSTATUS register\n", __FUNCTION__);
+               return -1;
+       }
+       return 0;
+}
+
+int pcie_init_hardware_part2(struct controller *ctrl, struct pcie_device *dev)
 {
        int rc;
        u16 temp_word;
-       u16 cap_reg;
        u16 intr_enable = 0;
        u32 slot_cap;
+       u16 slot_status;
+
+       rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word);
+       if (rc) {
+               err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
+               goto abort;
+       }
+
+       intr_enable = intr_enable | PRSN_DETECT_ENABLE;
+
+       rc = pciehp_readl(ctrl, SLOTCAP, &slot_cap);
+       if (rc) {
+               err("%s: Cannot read SLOTCAP register\n", __FUNCTION__);
+               goto abort;
+       }
+
+       if (ATTN_BUTTN(slot_cap))
+               intr_enable = intr_enable | ATTN_BUTTN_ENABLE;
+
+       if (POWER_CTRL(slot_cap))
+               intr_enable = intr_enable | PWR_FAULT_DETECT_ENABLE;
+
+       if (MRL_SENS(slot_cap))
+               intr_enable = intr_enable | MRL_DETECT_ENABLE;
+
+       temp_word = (temp_word & ~intr_enable) | intr_enable;
+
+       if (pciehp_poll_mode) {
+               temp_word = (temp_word & ~HP_INTR_ENABLE) | 0x0;
+       } else {
+               temp_word = (temp_word & ~HP_INTR_ENABLE) | HP_INTR_ENABLE;
+       }
+
+       /*
+        * Unmask Hot-plug Interrupt Enable for the interrupt
+        * notification mechanism case.
+        */
+       rc = pciehp_writew(ctrl, SLOTCTRL, temp_word);
+       if (rc) {
+               err("%s: Cannot write to SLOTCTRL register\n", __FUNCTION__);
+               goto abort;
+       }
+       rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
+       if (rc) {
+               err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__);
+               goto abort_disable_intr;
+       }
+
+       temp_word =  0x1F; /* Clear all events */
+       rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word);
+       if (rc) {
+               err("%s: Cannot write to SLOTSTATUS register\n", __FUNCTION__);
+               goto abort_disable_intr;
+       }
+
+       if (pciehp_force) {
+               dbg("Bypassing BIOS check for pciehp use on %s\n",
+                               pci_name(ctrl->pci_dev));
+       } else {
+               rc = pciehp_get_hp_hw_control_from_firmware(ctrl->pci_dev);
+               if (rc)
+                       goto abort_disable_intr;
+       }
+
+       return 0;
+
+       /* We end up here for the many possible ways to fail this API. */
+abort_disable_intr:
+       rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word);
+       if (!rc) {
+               temp_word &= ~(intr_enable | HP_INTR_ENABLE);
+               rc = pciehp_writew(ctrl, SLOTCTRL, temp_word);
+       }
+       if (rc)
+               err("%s : disabling interrupts failed\n", __FUNCTION__);
+abort:
+       return -1;
+}
+
+int pcie_init(struct controller *ctrl, struct pcie_device *dev)
+{
+       int rc;
+       u16 cap_reg;
+       u32 slot_cap;
        int cap_base;
        u16 slot_status, slot_ctrl;
        struct pci_dev *pdev;
@@ -1084,9 +1266,10 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
        dbg("%s: hotplug controller vendor id 0x%x device id 0x%x\n",
                        __FUNCTION__, pdev->vendor, pdev->device);
 
-       if ((cap_base = pci_find_capability(pdev, PCI_CAP_ID_EXP)) == 0) {
+       cap_base = pci_find_capability(pdev, PCI_CAP_ID_EXP);
+       if (cap_base == 0) {
                dbg("%s: Can't find PCI_CAP_ID_EXP (0x10)\n", __FUNCTION__);
-               goto abort_free_ctlr;
+               goto abort;
        }
 
        ctrl->cap_base = cap_base;
@@ -1096,7 +1279,7 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
        rc = pciehp_readw(ctrl, CAPREG, &cap_reg);
        if (rc) {
                err("%s: Cannot read CAPREG register\n", __FUNCTION__);
-               goto abort_free_ctlr;
+               goto abort;
        }
        dbg("%s: CAPREG offset %x cap_reg %x\n",
            __FUNCTION__, ctrl->cap_base + CAPREG, cap_reg);
@@ -1106,26 +1289,26 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
                && ((cap_reg & DEV_PORT_TYPE) != 0x0060))) {
                dbg("%s : This is not a root port or the port is not "
                    "connected to a slot\n", __FUNCTION__);
-               goto abort_free_ctlr;
+               goto abort;
        }
 
        rc = pciehp_readl(ctrl, SLOTCAP, &slot_cap);
        if (rc) {
                err("%s: Cannot read SLOTCAP register\n", __FUNCTION__);
-               goto abort_free_ctlr;
+               goto abort;
        }
        dbg("%s: SLOTCAP offset %x slot_cap %x\n",
            __FUNCTION__, ctrl->cap_base + SLOTCAP, slot_cap);
 
        if (!(slot_cap & HP_CAP)) {
                dbg("%s : This slot is not hot-plug capable\n", __FUNCTION__);
-               goto abort_free_ctlr;
+               goto abort;
        }
        /* For debugging purpose */
        rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
        if (rc) {
                err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__);
-               goto abort_free_ctlr;
+               goto abort;
        }
        dbg("%s: SLOTSTATUS offset %x slot_status %x\n",
            __FUNCTION__, ctrl->cap_base + SLOTSTATUS, slot_status);
@@ -1133,7 +1316,7 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
        rc = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
        if (rc) {
                err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
-               goto abort_free_ctlr;
+               goto abort;
        }
        dbg("%s: SLOTCTRL offset %x slot_ctrl %x\n",
            __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_ctrl);
@@ -1161,36 +1344,9 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
        ctrl->first_slot = slot_cap >> 19;
        ctrl->ctrlcap = slot_cap & 0x0000007f;
 
-       /* Mask Hot-plug Interrupt Enable */
-       rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word);
-       if (rc) {
-               err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
-               goto abort_free_ctlr;
-       }
-
-       dbg("%s: SLOTCTRL %x value read %x\n",
-           __FUNCTION__, ctrl->cap_base + SLOTCTRL, temp_word);
-       temp_word = (temp_word & ~HP_INTR_ENABLE & ~CMD_CMPL_INTR_ENABLE) |
-               0x00;
-
-       rc = pciehp_writew(ctrl, SLOTCTRL, temp_word);
-       if (rc) {
-               err("%s: Cannot write to SLOTCTRL register\n", __FUNCTION__);
-               goto abort_free_ctlr;
-       }
-
-       rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
-       if (rc) {
-               err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__);
-               goto abort_free_ctlr;
-       }
-
-       temp_word = 0x1F; /* Clear all events */
-       rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word);
-       if (rc) {
-               err("%s: Cannot write to SLOTSTATUS register\n", __FUNCTION__);
-               goto abort_free_ctlr;
-       }
+       rc = pcie_init_hardware_part1(ctrl, dev);
+       if (rc)
+               goto abort;
 
        if (pciehp_poll_mode) {
                /* Install interrupt polling timer. Start with 10 sec delay */
@@ -1206,7 +1362,7 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
                if (rc) {
                        err("Can't get irq %d for the hotplug controller\n",
                            ctrl->pci_dev->irq);
-                       goto abort_free_ctlr;
+                       goto abort;
                }
        }
        dbg("pciehp ctrl b:d:f:irq=0x%x:%x:%x:%x\n", pdev->bus->number,
@@ -1224,82 +1380,16 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
                }
        }
 
-       rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word);
-       if (rc) {
-               err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
-               goto abort_free_irq;
+       rc = pcie_init_hardware_part2(ctrl, dev);
+       if (rc == 0) {
+               ctrl->hpc_ops = &pciehp_hpc_ops;
+               return 0;
        }
-
-       intr_enable = intr_enable | PRSN_DETECT_ENABLE;
-
-       if (ATTN_BUTTN(slot_cap))
-               intr_enable = intr_enable | ATTN_BUTTN_ENABLE;
-
-       if (POWER_CTRL(slot_cap))
-               intr_enable = intr_enable | PWR_FAULT_DETECT_ENABLE;
-
-       if (MRL_SENS(slot_cap))
-               intr_enable = intr_enable | MRL_DETECT_ENABLE;
-
-       temp_word = (temp_word & ~intr_enable) | intr_enable;
-
-       if (pciehp_poll_mode) {
-               temp_word = (temp_word & ~HP_INTR_ENABLE) | 0x0;
-       } else {
-               temp_word = (temp_word & ~HP_INTR_ENABLE) | HP_INTR_ENABLE;
-       }
-
-       /*
-        * Unmask Hot-plug Interrupt Enable for the interrupt
-        * notification mechanism case.
-        */
-       rc = pciehp_writew(ctrl, SLOTCTRL, temp_word);
-       if (rc) {
-               err("%s: Cannot write to SLOTCTRL register\n", __FUNCTION__);
-               goto abort_free_irq;
-       }
-       rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
-       if (rc) {
-               err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__);
-               goto abort_disable_intr;
-       }
-
-       temp_word =  0x1F; /* Clear all events */
-       rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word);
-       if (rc) {
-               err("%s: Cannot write to SLOTSTATUS register\n", __FUNCTION__);
-               goto abort_disable_intr;
-       }
-
-       if (pciehp_force) {
-               dbg("Bypassing BIOS check for pciehp use on %s\n",
-                               pci_name(ctrl->pci_dev));
-       } else {
-               rc = pciehp_get_hp_hw_control_from_firmware(ctrl->pci_dev);
-               if (rc)
-                       goto abort_disable_intr;
-       }
-
-       ctrl->hpc_ops = &pciehp_hpc_ops;
-
-       return 0;
-
-       /* We end up here for the many possible ways to fail this API. */
-abort_disable_intr:
-       rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word);
-       if (!rc) {
-               temp_word &= ~(intr_enable | HP_INTR_ENABLE);
-               rc = pciehp_writew(ctrl, SLOTCTRL, temp_word);
-       }
-       if (rc)
-               err("%s : disabling interrupts failed\n", __FUNCTION__);
-
 abort_free_irq:
        if (pciehp_poll_mode)
                del_timer_sync(&ctrl->poll_timer);
        else
                free_irq(ctrl->pci_dev->irq, ctrl);
-
-abort_free_ctlr:
+abort:
        return -1;
 }
index c424aded13fb43fb108d41870d1c4f46c207de28..dd50713966d1b011bc480aa9d2cab642c63bb7c9 100644 (file)
@@ -105,12 +105,7 @@ static void program_hpp_type2(struct pci_dev *dev, struct hpp_type2 *hpp)
        }
 
        /* Find Advanced Error Reporting Enhanced Capability */
-       pos = 256;
-       do {
-               pci_read_config_dword(dev, pos, &reg32);
-               if (PCI_EXT_CAP_ID(reg32) == PCI_EXT_CAP_ID_ERR)
-                       break;
-       } while ((pos = PCI_EXT_CAP_NEXT(reg32)));
+       pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
        if (!pos)
                return;
 
@@ -248,11 +243,15 @@ int pciehp_unconfigure_device(struct slot *p_slot)
        u8 bctl = 0;
        u8 presence = 0;
        struct pci_bus *parent = p_slot->ctrl->pci_dev->subordinate;
+       u16 command;
 
        dbg("%s: bus/dev = %x/%x\n", __FUNCTION__, p_slot->bus,
                                p_slot->device);
+       ret = p_slot->hpc_ops->get_adapter_status(p_slot, &presence);
+       if (ret)
+               presence = 0;
 
-       for (j=0; j<8 ; j++) {
+       for (j = 0; j < 8; j++) {
                struct pci_dev* temp = pci_get_slot(parent,
                                (p_slot->device << 3) | j);
                if (!temp)
@@ -263,21 +262,26 @@ int pciehp_unconfigure_device(struct slot *p_slot)
                        pci_dev_put(temp);
                        continue;
                }
-               if (temp->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
-                       ret = p_slot->hpc_ops->get_adapter_status(p_slot,
-                                                               &presence);
-                       if (!ret && presence) {
-                               pci_read_config_byte(temp, PCI_BRIDGE_CONTROL,
-                                       &bctl);
-                               if (bctl & PCI_BRIDGE_CTL_VGA) {
-                                       err("Cannot remove display device %s\n",
-                                               pci_name(temp));
-                                       pci_dev_put(temp);
-                                       continue;
-                               }
+               if (temp->hdr_type == PCI_HEADER_TYPE_BRIDGE && presence) {
+                       pci_read_config_byte(temp, PCI_BRIDGE_CONTROL, &bctl);
+                       if (bctl & PCI_BRIDGE_CTL_VGA) {
+                               err("Cannot remove display device %s\n",
+                                   pci_name(temp));
+                               pci_dev_put(temp);
+                               continue;
                        }
                }
                pci_remove_bus_device(temp);
+               /*
+                * Ensure that no new Requests will be generated from
+                * the device.
+                */
+               if (presence) {
+                       pci_read_config_word(temp, PCI_COMMAND, &command);
+                       command &= ~(PCI_COMMAND_MASTER | PCI_COMMAND_SERR);
+                       command |= PCI_COMMAND_INTX_DISABLE;
+                       pci_write_config_word(temp, PCI_COMMAND, command);
+               }
                pci_dev_put(temp);
        }
        /*
@@ -288,4 +292,3 @@ int pciehp_unconfigure_device(struct slot *p_slot)
 
        return rc;
 }
-
index c822a779653fd8cdf86e6d4056c5d1000c1a3897..7d5921b1ee7820960afcc6b2b0ae9d711172ea49 100644 (file)
@@ -74,7 +74,6 @@ struct slot {
        u32 type;
        u32 power_domain;
        char *name;
-       char *location;
        struct device_node *dn;
        struct pci_bus *bus;
        struct list_head *pci_devs;
index 0de84533cd80ffc196845677790fcea7211670ce..6571e9b4c2ec95b9f25df46bfd292a20e8160b2b 100644 (file)
@@ -64,19 +64,6 @@ int rpaphp_get_sensor_state(struct slot *slot, int *state)
        return rc;
 }
 
-static void set_slot_name(struct slot *slot)
-{
-       struct pci_bus *bus = slot->bus;
-       struct pci_dev *bridge;
-
-       bridge = bus->self;
-       if (bridge)
-               strcpy(slot->name, pci_name(bridge));
-       else
-               sprintf(slot->name, "%04x:%02x:00.0", pci_domain_nr(bus),
-                       bus->number);
-}
-
 /**
  * rpaphp_enable_slot - record slot state, config pci device
  * @slot: target &slot
@@ -115,7 +102,6 @@ int rpaphp_enable_slot(struct slot *slot)
        info->adapter_status = EMPTY;
        slot->bus = bus;
        slot->pci_devs = &bus->devices;
-       set_slot_name(slot);
 
        /* if there's an adapter in the slot, go add the pci devices */
        if (state == PRESENT) {
index d4ee8723fcb3d6f609b2ac24570e3464648280cd..8ad3debb3794a742db476d28f41ee5aef906a204 100644 (file)
 #include <asm/rtas.h>
 #include "rpaphp.h"
 
-static ssize_t location_read_file (struct hotplug_slot *php_slot, char *buf)
+static ssize_t address_read_file (struct hotplug_slot *php_slot, char *buf)
 {
-       char *value;
-       int retval = -ENOENT;
+       int retval;
        struct slot *slot = (struct slot *)php_slot->private;
+       struct pci_bus *bus;
 
        if (!slot)
-               return retval;
+               return -ENOENT;
+
+       bus = slot->bus;
+       if (!bus)
+               return -ENOENT;
+
+       if (bus->self)
+               retval = sprintf(buf, pci_name(bus->self));
+       else
+               retval = sprintf(buf, "%04x:%02x:00.0",
+                       pci_domain_nr(bus), bus->number);
 
-       value = slot->location;
-       retval = sprintf (buf, "%s\n", value);
        return retval;
 }
 
-static struct hotplug_slot_attribute php_attr_location = {
-       .attr = {.name = "phy_location", .mode = S_IFREG | S_IRUGO},
-       .show = location_read_file,
+static struct hotplug_slot_attribute php_attr_address = {
+       .attr = {.name = "address", .mode = S_IFREG | S_IRUGO},
+       .show = address_read_file,
 };
 
 /* free up the memory used by a slot */
@@ -64,7 +72,6 @@ void dealloc_slot_struct(struct slot *slot)
        kfree(slot->hotplug_slot->info);
        kfree(slot->hotplug_slot->name);
        kfree(slot->hotplug_slot);
-       kfree(slot->location);
        kfree(slot);
 }
 
@@ -83,16 +90,13 @@ struct slot *alloc_slot_struct(struct device_node *dn,
                                           GFP_KERNEL);
        if (!slot->hotplug_slot->info)
                goto error_hpslot;
-       slot->hotplug_slot->name = kmalloc(BUS_ID_SIZE + 1, GFP_KERNEL);
+       slot->hotplug_slot->name = kmalloc(strlen(drc_name) + 1, GFP_KERNEL);
        if (!slot->hotplug_slot->name)
                goto error_info;        
-       slot->location = kmalloc(strlen(drc_name) + 1, GFP_KERNEL);
-       if (!slot->location)
-               goto error_name;
        slot->name = slot->hotplug_slot->name;
+       strcpy(slot->name, drc_name);
        slot->dn = dn;
        slot->index = drc_index;
-       strcpy(slot->location, drc_name);
        slot->power_domain = power_domain;
        slot->hotplug_slot->private = slot;
        slot->hotplug_slot->ops = &rpaphp_hotplug_slot_ops;
@@ -100,8 +104,6 @@ struct slot *alloc_slot_struct(struct device_node *dn,
        
        return (slot);
 
-error_name:
-       kfree(slot->hotplug_slot->name);
 error_info:
        kfree(slot->hotplug_slot->info);
 error_hpslot:
@@ -133,8 +135,8 @@ int rpaphp_deregister_slot(struct slot *slot)
 
        list_del(&slot->rpaphp_slot_list);
        
-       /* remove "phy_location" file */
-       sysfs_remove_file(&php_slot->kobj, &php_attr_location.attr);
+       /* remove "address" file */
+       sysfs_remove_file(&php_slot->kobj, &php_attr_address.attr);
 
        retval = pci_hp_deregister(php_slot);
        if (retval)
@@ -166,8 +168,8 @@ int rpaphp_register_slot(struct slot *slot)
                return retval;
        }
 
-       /* create "phy_location" file */
-       retval = sysfs_create_file(&php_slot->kobj, &php_attr_location.attr);
+       /* create "address" file */
+       retval = sysfs_create_file(&php_slot->kobj, &php_attr_address.attr);
        if (retval) {
                err("sysfs_create_file failed with error %d\n", retval);
                goto sysfs_fail;
@@ -175,8 +177,7 @@ int rpaphp_register_slot(struct slot *slot)
 
        /* add slot to our internal list */
        list_add(&slot->rpaphp_slot_list, &rpaphp_slot_head);
-       info("Slot [%s](PCI location=%s) registered\n", slot->name,
-                       slot->location);
+       info("Slot [%s] registered\n", slot->name);
        return 0;
 
 sysfs_fail:
index 5183a45d45b50f6a02b5ada18cdeb9e9a0893624..e8aa138128ce7c740a2d8a7c227791cc8df75a2c 100644 (file)
@@ -597,7 +597,7 @@ static void hpc_release_ctlr(struct controller *ctrl)
        cleanup_slots(ctrl);
 
        /*
-        * Mask SERR and System Interrut generation
+        * Mask SERR and System Interrupt generation
         */
        serr_int = shpc_readl(ctrl, SERR_INTR_ENABLE);
        serr_int |= (GLOBAL_INTR_MASK  | GLOBAL_SERR_MASK |
index e079a5237c9424e7064e1c0892377f2d9b78536b..4e01df99681ac79c1bbd0842d57ead2933af11d3 100644 (file)
@@ -1781,7 +1781,7 @@ __intel_alloc_iova(struct device *dev, struct dmar_domain *domain,
                /*
                 * First try to allocate an io virtual address in
                 * DMA_32BIT_MASK and if that fails then try allocating
-                * from higer range
+                * from higher range
                 */
                iova = iommu_alloc_iova(domain, size, DMA_32BIT_MASK);
                if (!iova)
index 07c9f09c856dba943a15f7e794ba8e1eaef78387..26938da8f4380c5fd0bdb1786c71f8adb8418046 100644 (file)
 
 static int pci_msi_enable = 1;
 
+/* Arch hooks */
+
+int __attribute__ ((weak))
+arch_msi_check_device(struct pci_dev *dev, int nvec, int type)
+{
+       return 0;
+}
+
+int __attribute__ ((weak))
+arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *entry)
+{
+       return 0;
+}
+
+int __attribute__ ((weak))
+arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
+{
+       struct msi_desc *entry;
+       int ret;
+
+       list_for_each_entry(entry, &dev->msi_list, list) {
+               ret = arch_setup_msi_irq(dev, entry);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+void __attribute__ ((weak)) arch_teardown_msi_irq(unsigned int irq)
+{
+       return;
+}
+
+void __attribute__ ((weak))
+arch_teardown_msi_irqs(struct pci_dev *dev)
+{
+       struct msi_desc *entry;
+
+       list_for_each_entry(entry, &dev->msi_list, list) {
+               if (entry->irq != 0)
+                       arch_teardown_msi_irq(entry->irq);
+       }
+}
+
 static void msi_set_enable(struct pci_dev *dev, int enable)
 {
        int pos;
@@ -230,7 +275,6 @@ static void pci_intx_for_msi(struct pci_dev *dev, int enable)
                pci_intx(dev, enable);
 }
 
-#ifdef CONFIG_PM
 static void __pci_restore_msi_state(struct pci_dev *dev)
 {
        int pos;
@@ -288,7 +332,7 @@ void pci_restore_msi_state(struct pci_dev *dev)
        __pci_restore_msi_state(dev);
        __pci_restore_msix_state(dev);
 }
-#endif /* CONFIG_PM */
+EXPORT_SYMBOL_GPL(pci_restore_msi_state);
 
 /**
  * msi_capability_init - configure device's MSI capability structure
@@ -683,49 +727,3 @@ void pci_msi_init_pci_dev(struct pci_dev *dev)
 {
        INIT_LIST_HEAD(&dev->msi_list);
 }
-
-
-/* Arch hooks */
-
-int __attribute__ ((weak))
-arch_msi_check_device(struct pci_dev* dev, int nvec, int type)
-{
-       return 0;
-}
-
-int __attribute__ ((weak))
-arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *entry)
-{
-       return 0;
-}
-
-int __attribute__ ((weak))
-arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
-{
-       struct msi_desc *entry;
-       int ret;
-
-       list_for_each_entry(entry, &dev->msi_list, list) {
-               ret = arch_setup_msi_irq(dev, entry);
-               if (ret)
-                       return ret;
-       }
-
-       return 0;
-}
-
-void __attribute__ ((weak)) arch_teardown_msi_irq(unsigned int irq)
-{
-       return;
-}
-
-void __attribute__ ((weak))
-arch_teardown_msi_irqs(struct pci_dev *dev)
-{
-       struct msi_desc *entry;
-
-       list_for_each_entry(entry, &dev->msi_list, list) {
-               if (entry->irq != 0)
-                       arch_teardown_msi_irq(entry->irq);
-       }
-}
index 5c6a5d043007ebec1418fe2d9a70cf5071cc06eb..e569645d59e2f3ef429cac60e1da67840277a348 100644 (file)
@@ -156,13 +156,13 @@ run_osc_out:
 }
 
 /**
- * pci_osc_support_set - register OS support to Firmware
+ * __pci_osc_support_set - register OS support to Firmware
  * @flags: OS support bits
  *
  * Update OS support fields and doing a _OSC Query to obtain an update
  * from Firmware on supported control bits.
  **/
-acpi_status pci_osc_support_set(u32 flags)
+acpi_status __pci_osc_support_set(u32 flags, const char *hid)
 {
        u32 temp;
        acpi_status retval;
@@ -176,7 +176,7 @@ acpi_status pci_osc_support_set(u32 flags)
        temp = ctrlset_buf[OSC_CONTROL_TYPE];
        ctrlset_buf[OSC_QUERY_TYPE] = OSC_QUERY_ENABLE;
        ctrlset_buf[OSC_CONTROL_TYPE] = OSC_CONTROL_MASKS;
-       acpi_get_devices ( PCI_ROOT_HID_STRING,
+       acpi_get_devices(hid,
                        acpi_query_osc,
                        ctrlset_buf,
                        (void **) &retval );
@@ -188,7 +188,6 @@ acpi_status pci_osc_support_set(u32 flags)
        }
        return AE_OK;
 }
-EXPORT_SYMBOL(pci_osc_support_set);
 
 /**
  * pci_osc_control_set - commit requested control to Firmware
index c4fa35d1dd7721d7a8288b1bcba6978b6b9412a5..e571c72e67531017f140ee6e323e89644f7320b0 100644 (file)
@@ -186,13 +186,11 @@ static int pci_call_probe(struct pci_driver *drv, struct pci_dev *dev,
            set_cpus_allowed(current, node_to_cpumask(node));
        /* And set default memory allocation policy */
        oldpol = current->mempolicy;
-       current->mempolicy = &default_policy;
-       mpol_get(current->mempolicy);
+       current->mempolicy = NULL;      /* fall back to system default policy */
 #endif
        error = drv->probe(dev, id);
 #ifdef CONFIG_NUMA
        set_cpus_allowed(current, oldmask);
-       mpol_free(current->mempolicy);
        current->mempolicy = oldpol;
 #endif
        return error;
index 7d1877341aada287783065bf15ab9f6349b2b07a..8dcf1458aa2fafe6e0433efd1dfb515ce503271a 100644 (file)
@@ -358,7 +358,7 @@ pci_read_legacy_io(struct kobject *kobj, struct bin_attribute *bin_attr,
                   char *buf, loff_t off, size_t count)
 {
         struct pci_bus *bus = to_pci_bus(container_of(kobj,
-                                                      struct class_device,
+                                                      struct device,
                                                      kobj));
 
         /* Only support 1, 2 or 4 byte accesses */
@@ -383,7 +383,7 @@ pci_write_legacy_io(struct kobject *kobj, struct bin_attribute *bin_attr,
                    char *buf, loff_t off, size_t count)
 {
         struct pci_bus *bus = to_pci_bus(container_of(kobj,
-                                                     struct class_device,
+                                                     struct device,
                                                      kobj));
         /* Only support 1, 2 or 4 byte accesses */
         if (count != 1 && count != 2 && count != 4)
@@ -407,7 +407,7 @@ pci_mmap_legacy_mem(struct kobject *kobj, struct bin_attribute *attr,
                     struct vm_area_struct *vma)
 {
         struct pci_bus *bus = to_pci_bus(container_of(kobj,
-                                                      struct class_device,
+                                                      struct device,
                                                      kobj));
 
         return pci_mmap_legacy_page_range(bus, vma);
index 71d561fda0a2bb0903cf91ccaf78ae6a9b37f07d..ae3df46eaabf29db0f1af949e8926f0abbb8ec1a 100644 (file)
@@ -314,6 +314,24 @@ int pci_find_ht_capability(struct pci_dev *dev, int ht_cap)
 }
 EXPORT_SYMBOL_GPL(pci_find_ht_capability);
 
+void pcie_wait_pending_transaction(struct pci_dev *dev)
+{
+       int pos;
+       u16 reg16;
+
+       pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
+       if (!pos)
+               return;
+       while (1) {
+               pci_read_config_word(dev, pos + PCI_EXP_DEVSTA, &reg16);
+               if (!(reg16 & PCI_EXP_DEVSTA_TRPND))
+                       break;
+               cpu_relax();
+       }
+
+}
+EXPORT_SYMBOL_GPL(pcie_wait_pending_transaction);
+
 /**
  * pci_find_parent_resource - return resource region of parent bus of given region
  * @dev: PCI device structure contains resources to be searched
@@ -353,7 +371,7 @@ pci_find_parent_resource(const struct pci_dev *dev, struct resource *res)
  * Restore the BAR values for a given device, so as to make it
  * accessible by its driver.
  */
-void
+static void
 pci_restore_bars(struct pci_dev *dev)
 {
        int i, numres;
@@ -551,6 +569,7 @@ static int pci_save_pcie_state(struct pci_dev *dev)
        int pos, i = 0;
        struct pci_cap_saved_state *save_state;
        u16 *cap;
+       int found = 0;
 
        pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
        if (pos <= 0)
@@ -559,6 +578,8 @@ static int pci_save_pcie_state(struct pci_dev *dev)
        save_state = pci_find_saved_cap(dev, PCI_CAP_ID_EXP);
        if (!save_state)
                save_state = kzalloc(sizeof(*save_state) + sizeof(u16) * 4, GFP_KERNEL);
+       else
+               found = 1;
        if (!save_state) {
                dev_err(&dev->dev, "Out of memory in pci_save_pcie_state\n");
                return -ENOMEM;
@@ -569,7 +590,9 @@ static int pci_save_pcie_state(struct pci_dev *dev)
        pci_read_config_word(dev, pos + PCI_EXP_LNKCTL, &cap[i++]);
        pci_read_config_word(dev, pos + PCI_EXP_SLTCTL, &cap[i++]);
        pci_read_config_word(dev, pos + PCI_EXP_RTCTL, &cap[i++]);
-       pci_add_saved_cap(dev, save_state);
+       save_state->cap_nr = PCI_CAP_ID_EXP;
+       if (!found)
+               pci_add_saved_cap(dev, save_state);
        return 0;
 }
 
@@ -597,14 +620,17 @@ static int pci_save_pcix_state(struct pci_dev *dev)
        int pos, i = 0;
        struct pci_cap_saved_state *save_state;
        u16 *cap;
+       int found = 0;
 
        pos = pci_find_capability(dev, PCI_CAP_ID_PCIX);
        if (pos <= 0)
                return 0;
 
-       save_state = pci_find_saved_cap(dev, PCI_CAP_ID_EXP);
+       save_state = pci_find_saved_cap(dev, PCI_CAP_ID_PCIX);
        if (!save_state)
                save_state = kzalloc(sizeof(*save_state) + sizeof(u16), GFP_KERNEL);
+       else
+               found = 1;
        if (!save_state) {
                dev_err(&dev->dev, "Out of memory in pci_save_pcie_state\n");
                return -ENOMEM;
@@ -612,7 +638,9 @@ static int pci_save_pcix_state(struct pci_dev *dev)
        cap = (u16 *)&save_state->data[0];
 
        pci_read_config_word(dev, pos + PCI_X_CMD, &cap[i++]);
-       pci_add_saved_cap(dev, save_state);
+       save_state->cap_nr = PCI_CAP_ID_PCIX;
+       if (!found)
+               pci_add_saved_cap(dev, save_state);
        return 0;
 }
 
@@ -713,29 +741,51 @@ int pci_reenable_device(struct pci_dev *dev)
        return 0;
 }
 
-/**
- * pci_enable_device_bars - Initialize some of a device for use
- * @dev: PCI device to be initialized
- * @bars: bitmask of BAR's that must be configured
- *
- *  Initialize device before it's used by a driver. Ask low-level code
- *  to enable selected I/O and memory resources. Wake up the device if it
- *  was suspended. Beware, this function can fail.
- */
-int
-pci_enable_device_bars(struct pci_dev *dev, int bars)
+static int __pci_enable_device_flags(struct pci_dev *dev,
+                                    resource_size_t flags)
 {
        int err;
+       int i, bars = 0;
 
        if (atomic_add_return(1, &dev->enable_cnt) > 1)
                return 0;               /* already enabled */
 
+       for (i = 0; i < DEVICE_COUNT_RESOURCE; i++)
+               if (dev->resource[i].flags & flags)
+                       bars |= (1 << i);
+
        err = do_pci_enable_device(dev, bars);
        if (err < 0)
                atomic_dec(&dev->enable_cnt);
        return err;
 }
 
+/**
+ * pci_enable_device_io - Initialize a device for use with IO space
+ * @dev: PCI device to be initialized
+ *
+ *  Initialize device before it's used by a driver. Ask low-level code
+ *  to enable I/O resources. Wake up the device if it was suspended.
+ *  Beware, this function can fail.
+ */
+int pci_enable_device_io(struct pci_dev *dev)
+{
+       return __pci_enable_device_flags(dev, IORESOURCE_IO);
+}
+
+/**
+ * pci_enable_device_mem - Initialize a device for use with Memory space
+ * @dev: PCI device to be initialized
+ *
+ *  Initialize device before it's used by a driver. Ask low-level code
+ *  to enable Memory resources. Wake up the device if it was suspended.
+ *  Beware, this function can fail.
+ */
+int pci_enable_device_mem(struct pci_dev *dev)
+{
+       return __pci_enable_device_flags(dev, IORESOURCE_MEM);
+}
+
 /**
  * pci_enable_device - Initialize device before it's used by a driver.
  * @dev: PCI device to be initialized
@@ -749,7 +799,7 @@ pci_enable_device_bars(struct pci_dev *dev, int bars)
  */
 int pci_enable_device(struct pci_dev *dev)
 {
-       return pci_enable_device_bars(dev, (1 << PCI_NUM_RESOURCES) - 1);
+       return __pci_enable_device_flags(dev, IORESOURCE_MEM | IORESOURCE_IO);
 }
 
 /*
@@ -823,7 +873,8 @@ int pcim_enable_device(struct pci_dev *pdev)
        dr = get_pci_dr(pdev);
        if (unlikely(!dr))
                return -ENOMEM;
-       WARN_ON(!!dr->enabled);
+       if (dr->enabled)
+               return 0;
 
        rc = pci_enable_device(pdev);
        if (!rc) {
@@ -884,6 +935,9 @@ pci_disable_device(struct pci_dev *dev)
        if (atomic_sub_return(1, &dev->enable_cnt) != 0)
                return;
 
+       /* Wait for all transactions are finished before disabling the device */
+       pcie_wait_pending_transaction(dev);
+
        pci_read_config_word(dev, PCI_COMMAND, &pci_command);
        if (pci_command & PCI_COMMAND_MASTER) {
                pci_command &= ~PCI_COMMAND_MASTER;
@@ -1397,6 +1451,22 @@ pci_set_consistent_dma_mask(struct pci_dev *dev, u64 mask)
 }
 #endif
 
+#ifndef HAVE_ARCH_PCI_SET_DMA_MAX_SEGMENT_SIZE
+int pci_set_dma_max_seg_size(struct pci_dev *dev, unsigned int size)
+{
+       return dma_set_max_seg_size(&dev->dev, size);
+}
+EXPORT_SYMBOL(pci_set_dma_max_seg_size);
+#endif
+
+#ifndef HAVE_ARCH_PCI_SET_DMA_SEGMENT_BOUNDARY
+int pci_set_dma_seg_boundary(struct pci_dev *dev, unsigned long mask)
+{
+       return dma_set_seg_boundary(&dev->dev, mask);
+}
+EXPORT_SYMBOL(pci_set_dma_seg_boundary);
+#endif
+
 /**
  * pcix_get_max_mmrbc - get PCI-X maximum designed memory read byte count
  * @dev: PCI device to query
@@ -1618,9 +1688,9 @@ early_param("pci", pci_setup);
 
 device_initcall(pci_init);
 
-EXPORT_SYMBOL_GPL(pci_restore_bars);
 EXPORT_SYMBOL(pci_reenable_device);
-EXPORT_SYMBOL(pci_enable_device_bars);
+EXPORT_SYMBOL(pci_enable_device_io);
+EXPORT_SYMBOL(pci_enable_device_mem);
 EXPORT_SYMBOL(pci_enable_device);
 EXPORT_SYMBOL(pcim_enable_device);
 EXPORT_SYMBOL(pcim_pin_device);
index fc87e14b50de9a15b491ed800320fd9e01f6e7e5..eabeb1f2ec998b0cf39de823b7c0bfd7a237b6ba 100644 (file)
@@ -6,8 +6,10 @@ extern void pci_remove_sysfs_dev_files(struct pci_dev *pdev);
 extern void pci_cleanup_rom(struct pci_dev *dev);
 
 /* Firmware callbacks */
-extern pci_power_t (*platform_pci_choose_state)(struct pci_dev *dev, pm_message_t state);
-extern int (*platform_pci_set_power_state)(struct pci_dev *dev, pci_power_t state);
+extern pci_power_t (*platform_pci_choose_state)(struct pci_dev *dev,
+                                               pm_message_t state);
+extern int (*platform_pci_set_power_state)(struct pci_dev *dev,
+                                               pci_power_t state);
 
 extern int pci_user_read_config_byte(struct pci_dev *dev, int where, u8 *val);
 extern int pci_user_read_config_word(struct pci_dev *dev, int where, u16 *val);
@@ -45,12 +47,6 @@ static inline void pci_no_msi(void) { }
 static inline void pci_msi_init_pci_dev(struct pci_dev *dev) { }
 #endif
 
-#if defined(CONFIG_PCI_MSI) && defined(CONFIG_PM)
-void pci_restore_msi_state(struct pci_dev *dev);
-#else
-static inline void pci_restore_msi_state(struct pci_dev *dev) {}
-#endif
-
 #ifdef CONFIG_PCIEAER
 void pci_no_aer(void);
 #else
@@ -68,14 +64,14 @@ static inline int pci_no_d1d2(struct pci_dev *dev)
 }
 extern int pcie_mch_quirk;
 extern struct device_attribute pci_dev_attrs[];
-extern struct class_device_attribute class_device_attr_cpuaffinity;
+extern struct device_attribute dev_attr_cpuaffinity;
 
 /**
  * pci_match_one_device - Tell if a PCI device structure has a matching
  *                        PCI device id structure
  * @id: single PCI device id structure to match
  * @dev: the PCI device structure to match against
- * 
+ *
  * Returns the matching pci_device_id structure or %NULL if there is no match.
  */
 static inline const struct pci_device_id *
index 1a1eb45a779e3862f8ef634cd425d4f117444661..8c199ae84f6dbadc59d46d876448b3f522bd849b 100644 (file)
@@ -31,26 +31,16 @@ int aer_osc_setup(struct pcie_device *pciedev)
 {
        acpi_status status = AE_NOT_FOUND;
        struct pci_dev *pdev = pciedev->port;
-       acpi_handle handle = DEVICE_ACPI_HANDLE(&pdev->dev);
-       struct pci_bus *parent;
+       acpi_handle handle = 0;
 
-       while (!handle) {
-               if (!pdev || !pdev->bus->parent)
-                       break;
-               parent = pdev->bus->parent;
-               if (!parent->self)
-                       /* Parent must be a host bridge */
-                       handle = acpi_get_pci_rootbridge_handle(
-                                       pci_domain_nr(parent),
-                                       parent->number);
-               else
-                       handle = DEVICE_ACPI_HANDLE(
-                                       &(parent->self->dev));
-               pdev = parent->self;
-       }
+       /* Find root host bridge */
+       while (pdev->bus && pdev->bus->self)
+               pdev = pdev->bus->self;
+       handle = acpi_get_pci_rootbridge_handle(
+               pci_domain_nr(pdev->bus), pdev->bus->number);
 
        if (handle) {
-               pci_osc_support_set(OSC_EXT_PCI_CONFIG_SUPPORT);
+               pcie_osc_support_set(OSC_EXT_PCI_CONFIG_SUPPORT);
                status = pci_osc_control_set(handle,
                                        OSC_PCI_EXPRESS_AER_CONTROL |
                                        OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL);
index b20a9b81dae2df5e9cca491b4c1504def575858c..23d9eb073296dea5e974141c008ee2154b9b6257 100644 (file)
@@ -192,9 +192,8 @@ static int get_port_device_capability(struct pci_dev *dev)
                if (reg32 & SLOT_HP_CAPABLE_MASK)
                        services |= PCIE_PORT_SERVICE_HP;
        } 
-       /* PME Capable */
-       pos = pci_find_capability(dev, PCI_CAP_ID_PME);
-       if (pos) 
+       /* PME Capable - root port capability */
+       if (((reg16 >> 4) & PORT_TYPE_MASK) == PCIE_RC_PORT)
                services |= PCIE_PORT_SERVICE_PME;
        
        pos = PCI_CFG_SPACE_SIZE;
index 5fd585293e7954c777094b6331e5a5fae9c094ca..4d23b9fb551bc129239f07404e04f6a4102ae092 100644 (file)
@@ -53,7 +53,7 @@ static void pci_create_legacy_files(struct pci_bus *b)
                b->legacy_io->attr.mode = S_IRUSR | S_IWUSR;
                b->legacy_io->read = pci_read_legacy_io;
                b->legacy_io->write = pci_write_legacy_io;
-               class_device_create_bin_file(&b->class_dev, b->legacy_io);
+               device_create_bin_file(&b->dev, b->legacy_io);
 
                /* Allocated above after the legacy_io struct */
                b->legacy_mem = b->legacy_io + 1;
@@ -61,15 +61,15 @@ static void pci_create_legacy_files(struct pci_bus *b)
                b->legacy_mem->size = 1024*1024;
                b->legacy_mem->attr.mode = S_IRUSR | S_IWUSR;
                b->legacy_mem->mmap = pci_mmap_legacy_mem;
-               class_device_create_bin_file(&b->class_dev, b->legacy_mem);
+               device_create_bin_file(&b->dev, b->legacy_mem);
        }
 }
 
 void pci_remove_legacy_files(struct pci_bus *b)
 {
        if (b->legacy_io) {
-               class_device_remove_bin_file(&b->class_dev, b->legacy_io);
-               class_device_remove_bin_file(&b->class_dev, b->legacy_mem);
+               device_remove_bin_file(&b->dev, b->legacy_io);
+               device_remove_bin_file(&b->dev, b->legacy_mem);
                kfree(b->legacy_io); /* both are allocated here */
        }
 }
@@ -81,26 +81,27 @@ void pci_remove_legacy_files(struct pci_bus *bus) { return; }
 /*
  * PCI Bus Class Devices
  */
-static ssize_t pci_bus_show_cpuaffinity(struct class_device *class_dev,
+static ssize_t pci_bus_show_cpuaffinity(struct device *dev,
+                                       struct device_attribute *attr,
                                        char *buf)
 {
        int ret;
        cpumask_t cpumask;
 
-       cpumask = pcibus_to_cpumask(to_pci_bus(class_dev));
+       cpumask = pcibus_to_cpumask(to_pci_bus(dev));
        ret = cpumask_scnprintf(buf, PAGE_SIZE, cpumask);
        if (ret < PAGE_SIZE)
                buf[ret++] = '\n';
        return ret;
 }
-CLASS_DEVICE_ATTR(cpuaffinity, S_IRUGO, pci_bus_show_cpuaffinity, NULL);
+DEVICE_ATTR(cpuaffinity, S_IRUGO, pci_bus_show_cpuaffinity, NULL);
 
 /*
  * PCI Bus Class
  */
-static void release_pcibus_dev(struct class_device *class_dev)
+static void release_pcibus_dev(struct device *dev)
 {
-       struct pci_bus *pci_bus = to_pci_bus(class_dev);
+       struct pci_bus *pci_bus = to_pci_bus(dev);
 
        if (pci_bus->bridge)
                put_device(pci_bus->bridge);
@@ -109,7 +110,7 @@ static void release_pcibus_dev(struct class_device *class_dev)
 
 static struct class pcibus_class = {
        .name           = "pci_bus",
-       .release        = &release_pcibus_dev,
+       .dev_release    = &release_pcibus_dev,
 };
 
 static int __init pcibus_class_init(void)
@@ -392,7 +393,6 @@ pci_alloc_child_bus(struct pci_bus *parent, struct pci_dev *bridge, int busnr)
 {
        struct pci_bus *child;
        int i;
-       int retval;
 
        /*
         * Allocate a new bus, and inherit stuff from the parent..
@@ -408,15 +408,12 @@ pci_alloc_child_bus(struct pci_bus *parent, struct pci_dev *bridge, int busnr)
        child->bus_flags = parent->bus_flags;
        child->bridge = get_device(&bridge->dev);
 
-       child->class_dev.class = &pcibus_class;
-       sprintf(child->class_dev.class_id, "%04x:%02x", pci_domain_nr(child), busnr);
-       retval = class_device_register(&child->class_dev);
-       if (retval)
-               goto error_register;
-       retval = class_device_create_file(&child->class_dev,
-                                         &class_device_attr_cpuaffinity);
-       if (retval)
-               goto error_file_create;
+       /* initialize some portions of the bus device, but don't register it
+        * now as the parent is not properly set up yet.  This device will get
+        * registered later in pci_bus_add_devices()
+        */
+       child->dev.class = &pcibus_class;
+       sprintf(child->dev.bus_id, "%04x:%02x", pci_domain_nr(child), busnr);
 
        /*
         * Set up the primary, secondary and subordinate
@@ -434,15 +431,9 @@ pci_alloc_child_bus(struct pci_bus *parent, struct pci_dev *bridge, int busnr)
        bridge->subordinate = child;
 
        return child;
-
-error_file_create:
-       class_device_unregister(&child->class_dev);
-error_register:
-       kfree(child);
-       return NULL;
 }
 
-struct pci_bus *pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev, int busnr)
+struct pci_bus *__ref pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev, int busnr)
 {
        struct pci_bus *child;
 
@@ -471,8 +462,6 @@ static void pci_fixup_parent_subordinate_busnr(struct pci_bus *child, int max)
        }
 }
 
-unsigned int pci_scan_child_bus(struct pci_bus *bus);
-
 /*
  * If it's a bridge, configure it and scan the bus behind it.
  * For CardBus bridges, we don't scan behind as the devices will
@@ -641,13 +630,13 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max, int pass
                    (child->number > bus->subordinate) ||
                    (child->number < bus->number) ||
                    (child->subordinate < bus->number)) {
-                       pr_debug("PCI: Bus #%02x (-#%02x) is %s"
+                       pr_debug("PCI: Bus #%02x (-#%02x) is %s "
                                "hidden behind%s bridge #%02x (-#%02x)\n",
                                child->number, child->subordinate,
                                (bus->number > child->subordinate &&
                                 bus->subordinate < child->number) ?
-                                       "wholly " : " partially",
-                               bus->self->transparent ? " transparent" : " ",
+                                       "wholly" : "partially",
+                               bus->self->transparent ? " transparent" : "",
                                bus->number, bus->subordinate);
                }
                bus = bus->parent;
@@ -944,8 +933,12 @@ void pci_device_add(struct pci_dev *dev, struct pci_bus *bus)
 
        set_dev_node(&dev->dev, pcibus_to_node(bus));
        dev->dev.dma_mask = &dev->dma_mask;
+       dev->dev.dma_parms = &dev->dma_parms;
        dev->dev.coherent_dma_mask = 0xffffffffull;
 
+       pci_set_dma_max_seg_size(dev, 65536);
+       pci_set_dma_seg_boundary(dev, 0xffffffff);
+
        /* Fix up broken headers */
        pci_fixup_device(pci_fixup_header, dev);
 
@@ -959,7 +952,7 @@ void pci_device_add(struct pci_dev *dev, struct pci_bus *bus)
        up_write(&pci_bus_sem);
 }
 
-struct pci_dev *pci_scan_single_device(struct pci_bus *bus, int devfn)
+struct pci_dev *__ref pci_scan_single_device(struct pci_bus *bus, int devfn)
 {
        struct pci_dev *dev;
 
@@ -971,6 +964,7 @@ struct pci_dev *pci_scan_single_device(struct pci_bus *bus, int devfn)
 
        return dev;
 }
+EXPORT_SYMBOL(pci_scan_single_device);
 
 /**
  * pci_scan_slot - scan a PCI slot on a bus for devices.
@@ -1050,20 +1044,6 @@ unsigned int pci_scan_child_bus(struct pci_bus *bus)
        return max;
 }
 
-unsigned int __devinit pci_do_scan_bus(struct pci_bus *bus)
-{
-       unsigned int max;
-
-       max = pci_scan_child_bus(bus);
-
-       /*
-        * Make the discovered devices available.
-        */
-       pci_bus_add_devices(bus);
-
-       return max;
-}
-
 struct pci_bus * pci_create_bus(struct device *parent,
                int bus, struct pci_ops *ops, void *sysdata)
 {
@@ -1103,32 +1083,27 @@ struct pci_bus * pci_create_bus(struct device *parent,
                goto dev_reg_err;
        b->bridge = get_device(dev);
 
-       b->class_dev.class = &pcibus_class;
-       sprintf(b->class_dev.class_id, "%04x:%02x", pci_domain_nr(b), bus);
-       error = class_device_register(&b->class_dev);
+       b->dev.class = &pcibus_class;
+       b->dev.parent = b->bridge;
+       sprintf(b->dev.bus_id, "%04x:%02x", pci_domain_nr(b), bus);
+       error = device_register(&b->dev);
        if (error)
                goto class_dev_reg_err;
-       error = class_device_create_file(&b->class_dev, &class_device_attr_cpuaffinity);
+       error = device_create_file(&b->dev, &dev_attr_cpuaffinity);
        if (error)
-               goto class_dev_create_file_err;
+               goto dev_create_file_err;
 
        /* Create legacy_io and legacy_mem files for this bus */
        pci_create_legacy_files(b);
 
-       error = sysfs_create_link(&b->class_dev.kobj, &b->bridge->kobj, "bridge");
-       if (error)
-               goto sys_create_link_err;
-
        b->number = b->secondary = bus;
        b->resource[0] = &ioport_resource;
        b->resource[1] = &iomem_resource;
 
        return b;
 
-sys_create_link_err:
-       class_device_remove_file(&b->class_dev, &class_device_attr_cpuaffinity);
-class_dev_create_file_err:
-       class_device_unregister(&b->class_dev);
+dev_create_file_err:
+       device_unregister(&b->dev);
 class_dev_reg_err:
        device_unregister(dev);
 dev_reg_err:
@@ -1140,7 +1115,6 @@ err_out:
        kfree(b);
        return NULL;
 }
-EXPORT_SYMBOL_GPL(pci_create_bus);
 
 struct pci_bus *pci_scan_bus_parented(struct device *parent,
                int bus, struct pci_ops *ops, void *sysdata)
@@ -1156,10 +1130,8 @@ EXPORT_SYMBOL(pci_scan_bus_parented);
 
 #ifdef CONFIG_HOTPLUG
 EXPORT_SYMBOL(pci_add_new_bus);
-EXPORT_SYMBOL(pci_do_scan_bus);
 EXPORT_SYMBOL(pci_scan_slot);
 EXPORT_SYMBOL(pci_scan_bridge);
-EXPORT_SYMBOL(pci_scan_single_device);
 EXPORT_SYMBOL_GPL(pci_scan_child_bus);
 #endif
 
index 716439e25dd283fcf4ecce43c9966bd33d044a27..68aeeb7206de61bfefb9d0b6e2ac8250da933a62 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/module.h>
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
+#include <linux/smp_lock.h>
 #include <linux/capability.h>
 #include <asm/uaccess.h>
 #include <asm/byteorder.h>
@@ -202,15 +203,18 @@ struct pci_filp_private {
        int write_combine;
 };
 
-static int proc_bus_pci_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+static long proc_bus_pci_ioctl(struct file *file, unsigned int cmd,
+                              unsigned long arg)
 {
-       const struct proc_dir_entry *dp = PDE(inode);
+       const struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode);
        struct pci_dev *dev = dp->data;
 #ifdef HAVE_PCI_MMAP
        struct pci_filp_private *fpriv = file->private_data;
 #endif /* HAVE_PCI_MMAP */
        int ret = 0;
 
+       lock_kernel();
+
        switch (cmd) {
        case PCIIOC_CONTROLLER:
                ret = pci_domain_nr(dev->bus);
@@ -239,6 +243,7 @@ static int proc_bus_pci_ioctl(struct inode *inode, struct file *file, unsigned i
                break;
        };
 
+       unlock_kernel();
        return ret;
 }
 
@@ -291,7 +296,7 @@ static const struct file_operations proc_bus_pci_operations = {
        .llseek         = proc_bus_pci_lseek,
        .read           = proc_bus_pci_read,
        .write          = proc_bus_pci_write,
-       .ioctl          = proc_bus_pci_ioctl,
+       .unlocked_ioctl = proc_bus_pci_ioctl,
 #ifdef HAVE_PCI_MMAP
        .open           = proc_bus_pci_open,
        .release        = proc_bus_pci_release,
@@ -370,7 +375,7 @@ static int show_device(struct seq_file *m, void *v)
        return 0;
 }
 
-static struct seq_operations proc_bus_pci_devices_op = {
+static const struct seq_operations proc_bus_pci_devices_op = {
        .start  = pci_seq_start,
        .next   = pci_seq_next,
        .stop   = pci_seq_stop,
@@ -480,7 +485,3 @@ static int __init pci_proc_init(void)
 
 __initcall(pci_proc_init);
 
-#ifdef CONFIG_HOTPLUG
-EXPORT_SYMBOL(pci_proc_detach_bus);
-#endif
-
index 72e0bd5d80aced43ef522ff52efdeebd65b86aa6..0a953d43b9a207961a6d41dbb1872d105f978982 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/acpi.h>
+#include <linux/kallsyms.h>
 #include "pci.h"
 
 /* The Mellanox Tavor device gives false positive parity errors
@@ -46,14 +47,14 @@ static void quirk_passive_release(struct pci_dev *dev)
        while ((d = pci_get_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_0, d))) {
                pci_read_config_byte(d, 0x82, &dlc);
                if (!(dlc & 1<<1)) {
-                       printk(KERN_ERR "PCI: PIIX3: Enabling Passive Release on %s\n", pci_name(d));
+                       dev_err(&d->dev, "PIIX3: Enabling Passive Release\n");
                        dlc |= 1<<1;
                        pci_write_config_byte(d, 0x82, dlc);
                }
        }
 }
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82441,      quirk_passive_release );
-DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_82441,      quirk_passive_release );
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82441,      quirk_passive_release);
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_82441,      quirk_passive_release);
 
 /*  The VIA VP2/VP3/MVP3 seem to have some 'features'. There may be a workaround
     but VIA don't answer queries. If you happen to have good contacts at VIA
@@ -68,20 +69,20 @@ static void __devinit quirk_isa_dma_hangs(struct pci_dev *dev)
 {
        if (!isa_dma_bridge_buggy) {
                isa_dma_bridge_buggy=1;
-               printk(KERN_INFO "Activating ISA DMA hang workarounds.\n");
+               dev_info(&dev->dev, "Activating ISA DMA hang workarounds\n");
        }
 }
        /*
         * Its not totally clear which chipsets are the problematic ones
         * We know 82C586 and 82C596 variants are affected.
         */
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA,     PCI_DEVICE_ID_VIA_82C586_0,     quirk_isa_dma_hangs );
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA,     PCI_DEVICE_ID_VIA_82C596,       quirk_isa_dma_hangs );
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_82371SB_0,  quirk_isa_dma_hangs );
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL,      PCI_DEVICE_ID_AL_M1533,         quirk_isa_dma_hangs );
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NEC,     PCI_DEVICE_ID_NEC_CBUS_1,       quirk_isa_dma_hangs );
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NEC,     PCI_DEVICE_ID_NEC_CBUS_2,       quirk_isa_dma_hangs );
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NEC,     PCI_DEVICE_ID_NEC_CBUS_3,       quirk_isa_dma_hangs );
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA,     PCI_DEVICE_ID_VIA_82C586_0,     quirk_isa_dma_hangs);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA,     PCI_DEVICE_ID_VIA_82C596,       quirk_isa_dma_hangs);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_82371SB_0,  quirk_isa_dma_hangs);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL,      PCI_DEVICE_ID_AL_M1533,         quirk_isa_dma_hangs);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NEC,     PCI_DEVICE_ID_NEC_CBUS_1,       quirk_isa_dma_hangs);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NEC,     PCI_DEVICE_ID_NEC_CBUS_2,       quirk_isa_dma_hangs);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NEC,     PCI_DEVICE_ID_NEC_CBUS_3,       quirk_isa_dma_hangs);
 
 int pci_pci_problems;
 EXPORT_SYMBOL(pci_pci_problems);
@@ -92,12 +93,12 @@ EXPORT_SYMBOL(pci_pci_problems);
 static void __devinit quirk_nopcipci(struct pci_dev *dev)
 {
        if ((pci_pci_problems & PCIPCI_FAIL)==0) {
-               printk(KERN_INFO "Disabling direct PCI/PCI transfers.\n");
+               dev_info(&dev->dev, "Disabling direct PCI/PCI transfers\n");
                pci_pci_problems |= PCIPCI_FAIL;
        }
 }
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI,      PCI_DEVICE_ID_SI_5597,          quirk_nopcipci );
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI,      PCI_DEVICE_ID_SI_496,           quirk_nopcipci );
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI,      PCI_DEVICE_ID_SI_5597,          quirk_nopcipci);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI,      PCI_DEVICE_ID_SI_496,           quirk_nopcipci);
 
 static void __devinit quirk_nopciamd(struct pci_dev *dev)
 {
@@ -105,11 +106,11 @@ static void __devinit quirk_nopciamd(struct pci_dev *dev)
        pci_read_config_byte(dev, 0x08, &rev);
        if (rev == 0x13) {
                /* Erratum 24 */
-               printk(KERN_INFO "Chipset erratum: Disabling direct PCI/AGP transfers.\n");
+               dev_info(&dev->dev, "Chipset erratum: Disabling direct PCI/AGP transfers\n");
                pci_pci_problems |= PCIAGP_FAIL;
        }
 }
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD,     PCI_DEVICE_ID_AMD_8151_0,       quirk_nopciamd );
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD,     PCI_DEVICE_ID_AMD_8151_0,       quirk_nopciamd);
 
 /*
  *     Triton requires workarounds to be used by the drivers
@@ -117,14 +118,14 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD,        PCI_DEVICE_ID_AMD_8151_0,       quirk_nopci
 static void __devinit quirk_triton(struct pci_dev *dev)
 {
        if ((pci_pci_problems&PCIPCI_TRITON)==0) {
-               printk(KERN_INFO "Limiting direct PCI/PCI transfers.\n");
+               dev_info(&dev->dev, "Limiting direct PCI/PCI transfers\n");
                pci_pci_problems |= PCIPCI_TRITON;
        }
 }
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82437,      quirk_triton ); 
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82437VX,    quirk_triton ); 
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82439,      quirk_triton ); 
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82439TX,    quirk_triton ); 
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82437,      quirk_triton);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82437VX,    quirk_triton);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82439,      quirk_triton);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82439TX,    quirk_triton);
 
 /*
  *     VIA Apollo KT133 needs PCI latency patch
@@ -139,25 +140,22 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,      PCI_DEVICE_ID_INTEL_82439TX,    quir
 static void quirk_vialatency(struct pci_dev *dev)
 {
        struct pci_dev *p;
-       u8 rev;
        u8 busarb;
        /* Ok we have a potential problem chipset here. Now see if we have
           a buggy southbridge */
           
        p = pci_get_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686, NULL);
        if (p!=NULL) {
-               pci_read_config_byte(p, PCI_CLASS_REVISION, &rev);
                /* 0x40 - 0x4f == 686B, 0x10 - 0x2f == 686A; thanks Dan Hollis */
                /* Check for buggy part revisions */
-               if (rev < 0x40 || rev > 0x42)
+               if (p->revision < 0x40 || p->revision > 0x42)
                        goto exit;
        } else {
                p = pci_get_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8231, NULL);
                if (p==NULL)    /* No problem parts */
                        goto exit;
-               pci_read_config_byte(p, PCI_CLASS_REVISION, &rev);
                /* Check for buggy part revisions */
-               if (rev < 0x10 || rev > 0x12) 
+               if (p->revision < 0x10 || p->revision > 0x12)
                        goto exit;
        }
        
@@ -180,17 +178,17 @@ static void quirk_vialatency(struct pci_dev *dev)
        busarb &= ~(1<<5);
        busarb |= (1<<4);
        pci_write_config_byte(dev, 0x76, busarb);
-       printk(KERN_INFO "Applying VIA southbridge workaround.\n");
+       dev_info(&dev->dev, "Applying VIA southbridge workaround\n");
 exit:
        pci_dev_put(p);
 }
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA,     PCI_DEVICE_ID_VIA_8363_0,       quirk_vialatency );
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA,     PCI_DEVICE_ID_VIA_8371_1,       quirk_vialatency );
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA,     PCI_DEVICE_ID_VIA_8361,         quirk_vialatency );
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA,     PCI_DEVICE_ID_VIA_8363_0,       quirk_vialatency);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA,     PCI_DEVICE_ID_VIA_8371_1,       quirk_vialatency);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA,     PCI_DEVICE_ID_VIA_8361,         quirk_vialatency);
 /* Must restore this on a resume from RAM */
-DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA,    PCI_DEVICE_ID_VIA_8363_0,       quirk_vialatency );
-DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA,    PCI_DEVICE_ID_VIA_8371_1,       quirk_vialatency );
-DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA,    PCI_DEVICE_ID_VIA_8361,         quirk_vialatency );
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA,    PCI_DEVICE_ID_VIA_8363_0,       quirk_vialatency);
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA,    PCI_DEVICE_ID_VIA_8371_1,       quirk_vialatency);
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA,    PCI_DEVICE_ID_VIA_8361,         quirk_vialatency);
 
 /*
  *     VIA Apollo VP3 needs ETBF on BT848/878
@@ -198,20 +196,20 @@ DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA,       PCI_DEVICE_ID_VIA_8361,         quirk_viala
 static void __devinit quirk_viaetbf(struct pci_dev *dev)
 {
        if ((pci_pci_problems&PCIPCI_VIAETBF)==0) {
-               printk(KERN_INFO "Limiting direct PCI/PCI transfers.\n");
+               dev_info(&dev->dev, "Limiting direct PCI/PCI transfers\n");
                pci_pci_problems |= PCIPCI_VIAETBF;
        }
 }
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA,     PCI_DEVICE_ID_VIA_82C597_0,     quirk_viaetbf );
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA,     PCI_DEVICE_ID_VIA_82C597_0,     quirk_viaetbf);
 
 static void __devinit quirk_vsfx(struct pci_dev *dev)
 {
        if ((pci_pci_problems&PCIPCI_VSFX)==0) {
-               printk(KERN_INFO "Limiting direct PCI/PCI transfers.\n");
+               dev_info(&dev->dev, "Limiting direct PCI/PCI transfers\n");
                pci_pci_problems |= PCIPCI_VSFX;
        }
 }
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA,     PCI_DEVICE_ID_VIA_82C576,       quirk_vsfx );
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA,     PCI_DEVICE_ID_VIA_82C576,       quirk_vsfx);
 
 /*
  *     Ali Magik requires workarounds to be used by the drivers
@@ -222,12 +220,12 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA,        PCI_DEVICE_ID_VIA_82C576,       quirk_vsfx
 static void __init quirk_alimagik(struct pci_dev *dev)
 {
        if ((pci_pci_problems&PCIPCI_ALIMAGIK)==0) {
-               printk(KERN_INFO "Limiting direct PCI/PCI transfers.\n");
+               dev_info(&dev->dev, "Limiting direct PCI/PCI transfers\n");
                pci_pci_problems |= PCIPCI_ALIMAGIK|PCIPCI_TRITON;
        }
 }
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL,      PCI_DEVICE_ID_AL_M1647,         quirk_alimagik );
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL,      PCI_DEVICE_ID_AL_M1651,         quirk_alimagik );
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL,      PCI_DEVICE_ID_AL_M1647,         quirk_alimagik);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL,      PCI_DEVICE_ID_AL_M1651,         quirk_alimagik);
 
 /*
  *     Natoma has some interesting boundary conditions with Zoran stuff
@@ -236,16 +234,16 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL,         PCI_DEVICE_ID_AL_M1651,         quirk_alimag
 static void __devinit quirk_natoma(struct pci_dev *dev)
 {
        if ((pci_pci_problems&PCIPCI_NATOMA)==0) {
-               printk(KERN_INFO "Limiting direct PCI/PCI transfers.\n");
+               dev_info(&dev->dev, "Limiting direct PCI/PCI transfers\n");
                pci_pci_problems |= PCIPCI_NATOMA;
        }
 }
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82441,      quirk_natoma ); 
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82443LX_0,  quirk_natoma ); 
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82443LX_1,  quirk_natoma ); 
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82443BX_0,  quirk_natoma ); 
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82443BX_1,  quirk_natoma ); 
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82443BX_2,  quirk_natoma );
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82441,      quirk_natoma);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82443LX_0,  quirk_natoma);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82443LX_1,  quirk_natoma);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82443BX_0,  quirk_natoma);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82443BX_1,  quirk_natoma);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82443BX_2,  quirk_natoma);
 
 /*
  *  This chip can cause PCI parity errors if config register 0xA0 is read
@@ -255,7 +253,7 @@ static void __devinit quirk_citrine(struct pci_dev *dev)
 {
        dev->cfg_size = 0xA0;
 }
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_IBM,    PCI_DEVICE_ID_IBM_CITRINE,      quirk_citrine );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_IBM,    PCI_DEVICE_ID_IBM_CITRINE,      quirk_citrine);
 
 /*
  *  S3 868 and 968 chips report region size equal to 32M, but they decode 64M.
@@ -270,8 +268,8 @@ static void __devinit quirk_s3_64M(struct pci_dev *dev)
                r->end = 0x3ffffff;
        }
 }
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_S3,     PCI_DEVICE_ID_S3_868,           quirk_s3_64M );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_S3,     PCI_DEVICE_ID_S3_968,           quirk_s3_64M );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_S3,     PCI_DEVICE_ID_S3_868,           quirk_s3_64M);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_S3,     PCI_DEVICE_ID_S3_968,           quirk_s3_64M);
 
 static void __devinit quirk_io_region(struct pci_dev *dev, unsigned region,
        unsigned size, int nr, const char *name)
@@ -292,7 +290,7 @@ static void __devinit quirk_io_region(struct pci_dev *dev, unsigned region,
                pcibios_bus_to_resource(dev, res, &bus_region);
 
                pci_claim_resource(dev, nr);
-               printk("PCI quirk: region %04x-%04x claimed by %s\n", region, region + size - 1, name);
+               dev_info(&dev->dev, "quirk: region %04x-%04x claimed by %s\n", region, region + size - 1, name);
        }
 }      
 
@@ -302,12 +300,12 @@ static void __devinit quirk_io_region(struct pci_dev *dev, unsigned region,
  */
 static void __devinit quirk_ati_exploding_mce(struct pci_dev *dev)
 {
-       printk(KERN_INFO "ATI Northbridge, reserving I/O ports 0x3b0 to 0x3bb.\n");
+       dev_info(&dev->dev, "ATI Northbridge, reserving I/O ports 0x3b0 to 0x3bb\n");
        /* Mae rhaid i ni beidio ag edrych ar y lleoliadiau I/O hyn */
        request_region(0x3b0, 0x0C, "RadeonIGP");
        request_region(0x3d3, 0x01, "RadeonIGP");
 }
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI,     PCI_DEVICE_ID_ATI_RS100,   quirk_ati_exploding_mce );
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI,     PCI_DEVICE_ID_ATI_RS100,   quirk_ati_exploding_mce);
 
 /*
  * Let's make the southbridge information explicit instead
@@ -329,7 +327,7 @@ static void __devinit quirk_ali7101_acpi(struct pci_dev *dev)
        pci_read_config_word(dev, 0xE2, &region);
        quirk_io_region(dev, region, 32, PCI_BRIDGE_RESOURCES+1, "ali7101 SMB");
 }
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AL,     PCI_DEVICE_ID_AL_M7101,         quirk_ali7101_acpi );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AL,     PCI_DEVICE_ID_AL_M7101,         quirk_ali7101_acpi);
 
 static void piix4_io_quirk(struct pci_dev *dev, const char *name, unsigned int port, unsigned int enable)
 {
@@ -354,7 +352,7 @@ static void piix4_io_quirk(struct pci_dev *dev, const char *name, unsigned int p
         * let's get enough confirmation reports first. 
         */
        base &= -size;
-       printk("%s PIO at %04x-%04x\n", name, base, base + size - 1);
+       dev_info(&dev->dev, "%s PIO at %04x-%04x\n", name, base, base + size - 1);
 }
 
 static void piix4_mem_quirk(struct pci_dev *dev, const char *name, unsigned int port, unsigned int enable)
@@ -379,7 +377,7 @@ static void piix4_mem_quirk(struct pci_dev *dev, const char *name, unsigned int
         * reserve it, but let's get enough confirmation reports first. 
         */
        base &= -size;
-       printk("%s MMIO at %04x-%04x\n", name, base, base + size - 1);
+       dev_info(&dev->dev, "%s MMIO at %04x-%04x\n", name, base, base + size - 1);
 }
 
 /*
@@ -418,8 +416,8 @@ static void __devinit quirk_piix4_acpi(struct pci_dev *dev)
        piix4_io_quirk(dev, "PIIX4 devres I", 0x78, 1 << 20);
        piix4_io_quirk(dev, "PIIX4 devres J", 0x7c, 1 << 20);
 }
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_82371AB_3,  quirk_piix4_acpi );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_82443MX_3,  quirk_piix4_acpi );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_82371AB_3,  quirk_piix4_acpi);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_82443MX_3,  quirk_piix4_acpi);
 
 /*
  * ICH4, ICH4-M, ICH5, ICH5-M ACPI: Three IO regions pointed to by longwords at
@@ -436,16 +434,16 @@ static void __devinit quirk_ich4_lpc_acpi(struct pci_dev *dev)
        pci_read_config_dword(dev, 0x58, &region);
        quirk_io_region(dev, region, 64, PCI_BRIDGE_RESOURCES+1, "ICH4 GPIO");
 }
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_82801AA_0,                quirk_ich4_lpc_acpi );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_82801AB_0,                quirk_ich4_lpc_acpi );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_82801BA_0,                quirk_ich4_lpc_acpi );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_82801BA_10,       quirk_ich4_lpc_acpi );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_82801CA_0,                quirk_ich4_lpc_acpi );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_82801CA_12,       quirk_ich4_lpc_acpi );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_82801DB_0,                quirk_ich4_lpc_acpi );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_82801DB_12,       quirk_ich4_lpc_acpi );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_82801EB_0,                quirk_ich4_lpc_acpi );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_ESB_1,            quirk_ich4_lpc_acpi );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_82801AA_0,                quirk_ich4_lpc_acpi);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_82801AB_0,                quirk_ich4_lpc_acpi);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_82801BA_0,                quirk_ich4_lpc_acpi);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_82801BA_10,       quirk_ich4_lpc_acpi);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_82801CA_0,                quirk_ich4_lpc_acpi);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_82801CA_12,       quirk_ich4_lpc_acpi);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_82801DB_0,                quirk_ich4_lpc_acpi);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_82801DB_12,       quirk_ich4_lpc_acpi);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_82801EB_0,                quirk_ich4_lpc_acpi);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_ESB_1,            quirk_ich4_lpc_acpi);
 
 static void __devinit quirk_ich6_lpc_acpi(struct pci_dev *dev)
 {
@@ -457,20 +455,20 @@ static void __devinit quirk_ich6_lpc_acpi(struct pci_dev *dev)
        pci_read_config_dword(dev, 0x48, &region);
        quirk_io_region(dev, region, 64, PCI_BRIDGE_RESOURCES+1, "ICH6 GPIO");
 }
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_ICH6_0, quirk_ich6_lpc_acpi );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_ICH6_1, quirk_ich6_lpc_acpi );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_ICH7_0, quirk_ich6_lpc_acpi );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_ICH7_1, quirk_ich6_lpc_acpi );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_ICH7_31, quirk_ich6_lpc_acpi );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_ICH8_0, quirk_ich6_lpc_acpi );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_ICH8_2, quirk_ich6_lpc_acpi );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_ICH8_3, quirk_ich6_lpc_acpi );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_ICH8_1, quirk_ich6_lpc_acpi );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_ICH8_4, quirk_ich6_lpc_acpi );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_ICH9_2, quirk_ich6_lpc_acpi );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_ICH9_4, quirk_ich6_lpc_acpi );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_ICH9_7, quirk_ich6_lpc_acpi );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_ICH9_8, quirk_ich6_lpc_acpi );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_ICH6_0, quirk_ich6_lpc_acpi);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_ICH6_1, quirk_ich6_lpc_acpi);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_ICH7_0, quirk_ich6_lpc_acpi);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_ICH7_1, quirk_ich6_lpc_acpi);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_ICH7_31, quirk_ich6_lpc_acpi);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_ICH8_0, quirk_ich6_lpc_acpi);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_ICH8_2, quirk_ich6_lpc_acpi);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_ICH8_3, quirk_ich6_lpc_acpi);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_ICH8_1, quirk_ich6_lpc_acpi);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_ICH8_4, quirk_ich6_lpc_acpi);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_ICH9_2, quirk_ich6_lpc_acpi);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_ICH9_4, quirk_ich6_lpc_acpi);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_ICH9_7, quirk_ich6_lpc_acpi);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_ICH9_8, quirk_ich6_lpc_acpi);
 
 /*
  * VIA ACPI: One IO region pointed to by longword at
@@ -486,7 +484,7 @@ static void __devinit quirk_vt82c586_acpi(struct pci_dev *dev)
                quirk_io_region(dev, region, 256, PCI_BRIDGE_RESOURCES, "vt82c586 ACPI");
        }
 }
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA,    PCI_DEVICE_ID_VIA_82C586_3,     quirk_vt82c586_acpi );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA,    PCI_DEVICE_ID_VIA_82C586_3,     quirk_vt82c586_acpi);
 
 /*
  * VIA VT82C686 ACPI: Three IO region pointed to by (long)words at
@@ -509,7 +507,7 @@ static void __devinit quirk_vt82c686_acpi(struct pci_dev *dev)
        smb &= PCI_BASE_ADDRESS_IO_MASK;
        quirk_io_region(dev, smb, 16, PCI_BRIDGE_RESOURCES + 2, "vt82c686 SMB");
 }
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA,    PCI_DEVICE_ID_VIA_82C686_4,     quirk_vt82c686_acpi );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA,    PCI_DEVICE_ID_VIA_82C686_4,     quirk_vt82c686_acpi);
 
 /*
  * VIA VT8235 ISA Bridge: Two IO regions pointed to by words at
@@ -551,14 +549,14 @@ static void quirk_via_ioapic(struct pci_dev *dev)
        else
                tmp = 0x1f; /* all known bits (4-0) routed to external APIC */
                
-       printk(KERN_INFO "PCI: %sbling Via external APIC routing\n",
+       dev_info(&dev->dev, "%sbling VIA external APIC routing\n",
               tmp == 0 ? "Disa" : "Ena");
 
        /* Offset 0x58: External APIC IRQ output control */
        pci_write_config_byte (dev, 0x58, tmp);
 }
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA,     PCI_DEVICE_ID_VIA_82C686,       quirk_via_ioapic );
-DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA,    PCI_DEVICE_ID_VIA_82C686,       quirk_via_ioapic );
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA,     PCI_DEVICE_ID_VIA_82C686,       quirk_via_ioapic);
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA,    PCI_DEVICE_ID_VIA_82C686,       quirk_via_ioapic);
 
 /*
  * VIA 8237: Some BIOSs don't set the 'Bypass APIC De-Assert Message' Bit.
@@ -573,7 +571,7 @@ static void quirk_via_vt8237_bypass_apic_deassert(struct pci_dev *dev)
 
        pci_read_config_byte(dev, 0x5B, &misc_control2);
        if (!(misc_control2 & BYPASS_APIC_DEASSERT)) {
-               printk(KERN_INFO "PCI: Bypassing VIA 8237 APIC De-Assert Message\n");
+               dev_info(&dev->dev, "Bypassing VIA 8237 APIC De-Assert Message\n");
                pci_write_config_byte(dev, 0x5B, misc_control2|BYPASS_APIC_DEASSERT);
        }
 }
@@ -592,18 +590,18 @@ DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA,       PCI_DEVICE_ID_VIA_8237,         quirk_via_v
 static void __devinit quirk_amd_ioapic(struct pci_dev *dev)
 {
        if (dev->revision >= 0x02) {
-               printk(KERN_WARNING "I/O APIC: AMD Erratum #22 may be present. In the event of instability try\n");
-               printk(KERN_WARNING "        : booting with the \"noapic\" option.\n");
+               dev_warn(&dev->dev, "I/O APIC: AMD Erratum #22 may be present. In the event of instability try\n");
+               dev_warn(&dev->dev, "        : booting with the \"noapic\" option\n");
        }
 }
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD,     PCI_DEVICE_ID_AMD_VIPER_7410,   quirk_amd_ioapic );
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD,     PCI_DEVICE_ID_AMD_VIPER_7410,   quirk_amd_ioapic);
 
 static void __init quirk_ioapic_rmw(struct pci_dev *dev)
 {
        if (dev->devfn == 0 && dev->bus->number == 0)
                sis_apic_bug = 1;
 }
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI,      PCI_ANY_ID,                     quirk_ioapic_rmw );
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI,      PCI_ANY_ID,                     quirk_ioapic_rmw);
 
 #define AMD8131_revA0        0x01
 #define AMD8131_revB0        0x11
@@ -617,7 +615,7 @@ static void quirk_amd_8131_ioapic(struct pci_dev *dev)
                 return;
 
         if (dev->revision == AMD8131_revA0 || dev->revision == AMD8131_revB0) {
-                printk(KERN_INFO "Fixing up AMD8131 IOAPIC mode\n"); 
+                dev_info(&dev->dev, "Fixing up AMD8131 IOAPIC mode\n");
                 pci_read_config_byte( dev, AMD8131_MISC, &tmp);
                 tmp &= ~(1 << AMD8131_NIOAMODE_BIT);
                 pci_write_config_byte( dev, AMD8131_MISC, tmp);
@@ -634,8 +632,8 @@ DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8131_BRIDGE, quirk
 static void __init quirk_amd_8131_mmrbc(struct pci_dev *dev)
 {
        if (dev->subordinate && dev->revision <= 0x12) {
-               printk(KERN_INFO "AMD8131 rev %x detected, disabling PCI-X "
-                               "MMRBC\n", dev->revision);
+               dev_info(&dev->dev, "AMD8131 rev %x detected; "
+                       "disabling PCI-X MMRBC\n", dev->revision);
                dev->subordinate->bus_flags |= PCI_BUS_FLAGS_NO_MMRBC;
        }
 }
@@ -660,8 +658,8 @@ static void __devinit quirk_via_acpi(struct pci_dev *d)
        if (irq && (irq != 2))
                d->irq = irq;
 }
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA,    PCI_DEVICE_ID_VIA_82C586_3,     quirk_via_acpi );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA,    PCI_DEVICE_ID_VIA_82C686_4,     quirk_via_acpi );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA,    PCI_DEVICE_ID_VIA_82C586_3,     quirk_via_acpi);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA,    PCI_DEVICE_ID_VIA_82C686_4,     quirk_via_acpi);
 
 
 /*
@@ -742,8 +740,8 @@ static void quirk_via_vlink(struct pci_dev *dev)
 
        pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
        if (new_irq != irq) {
-               printk(KERN_INFO "PCI: VIA VLink IRQ fixup for %s, from %d to %d\n",
-                       pci_name(dev), irq, new_irq);
+               dev_info(&dev->dev, "VIA VLink IRQ fixup, from %d to %d\n",
+                       irq, new_irq);
                udelay(15);     /* unknown if delay really needed */
                pci_write_config_byte(dev, PCI_INTERRUPT_LINE, new_irq);
        }
@@ -761,7 +759,7 @@ static void __devinit quirk_vt82c598_id(struct pci_dev *dev)
        pci_write_config_byte(dev, 0xfc, 0);
        pci_read_config_word(dev, PCI_DEVICE_ID, &dev->device);
 }
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA,    PCI_DEVICE_ID_VIA_82C597_0,     quirk_vt82c598_id );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA,    PCI_DEVICE_ID_VIA_82C597_0,     quirk_vt82c598_id);
 
 /*
  * CardBus controllers have a legacy base address that enables them
@@ -791,15 +789,15 @@ static void quirk_amd_ordering(struct pci_dev *dev)
        pci_read_config_dword(dev, 0x4C, &pcic);
        if ((pcic&6)!=6) {
                pcic |= 6;
-               printk(KERN_WARNING "BIOS failed to enable PCI standards compliance, fixing this error.\n");
+               dev_warn(&dev->dev, "BIOS failed to enable PCI standards compliance; fixing this error\n");
                pci_write_config_dword(dev, 0x4C, pcic);
                pci_read_config_dword(dev, 0x84, &pcic);
                pcic |= (1<<23);        /* Required in this mode */
                pci_write_config_dword(dev, 0x84, pcic);
        }
 }
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD,     PCI_DEVICE_ID_AMD_FE_GATE_700C, quirk_amd_ordering );
-DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_AMD,    PCI_DEVICE_ID_AMD_FE_GATE_700C, quirk_amd_ordering );
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD,     PCI_DEVICE_ID_AMD_FE_GATE_700C, quirk_amd_ordering);
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_AMD,    PCI_DEVICE_ID_AMD_FE_GATE_700C, quirk_amd_ordering);
 
 /*
  *     DreamWorks provided workaround for Dunord I-3000 problem
@@ -814,7 +812,7 @@ static void __devinit quirk_dunord ( struct pci_dev * dev )
        r->start = 0;
        r->end = 0xffffff;
 }
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_DUNORD, PCI_DEVICE_ID_DUNORD_I3000,     quirk_dunord );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_DUNORD, PCI_DEVICE_ID_DUNORD_I3000,     quirk_dunord);
 
 /*
  * i82380FB mobile docking controller: its PCI-to-PCI bridge
@@ -826,8 +824,8 @@ static void __devinit quirk_transparent_bridge(struct pci_dev *dev)
 {
        dev->transparent = 1;
 }
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_82380FB,    quirk_transparent_bridge );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_TOSHIBA,        0x605,  quirk_transparent_bridge );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_82380FB,    quirk_transparent_bridge);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_TOSHIBA,        0x605,  quirk_transparent_bridge);
 
 /*
  * Common misconfiguration of the MediaGX/Geode PCI master that will
@@ -841,12 +839,12 @@ static void quirk_mediagx_master(struct pci_dev *dev)
        pci_read_config_byte(dev, 0x41, &reg);
        if (reg & 2) {
                reg &= ~2;
-               printk(KERN_INFO "PCI: Fixup for MediaGX/Geode Slave Disconnect Boundary (0x41=0x%02x)\n", reg);
+               dev_info(&dev->dev, "Fixup for MediaGX/Geode Slave Disconnect Boundary (0x41=0x%02x)\n", reg);
                 pci_write_config_byte(dev, 0x41, reg);
        }
 }
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CYRIX,   PCI_DEVICE_ID_CYRIX_PCI_MASTER, quirk_mediagx_master );
-DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_CYRIX,  PCI_DEVICE_ID_CYRIX_PCI_MASTER, quirk_mediagx_master );
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CYRIX,   PCI_DEVICE_ID_CYRIX_PCI_MASTER, quirk_mediagx_master);
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_CYRIX,  PCI_DEVICE_ID_CYRIX_PCI_MASTER, quirk_mediagx_master);
 
 /*
  *     Ensure C0 rev restreaming is off. This is normally done by
@@ -863,11 +861,11 @@ static void quirk_disable_pxb(struct pci_dev *pdev)
        if (config & (1<<6)) {
                config &= ~(1<<6);
                pci_write_config_word(pdev, 0x40, config);
-               printk(KERN_INFO "PCI: C0 revision 450NX. Disabling PCI restreaming.\n");
+               dev_info(&pdev->dev, "C0 revision 450NX. Disabling PCI restreaming\n");
        }
 }
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82454NX,    quirk_disable_pxb );
-DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_82454NX,    quirk_disable_pxb );
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82454NX,    quirk_disable_pxb);
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_82454NX,    quirk_disable_pxb);
 
 
 static void __devinit quirk_sb600_sata(struct pci_dev *pdev)
@@ -902,7 +900,7 @@ static void __devinit quirk_svwks_csb5ide(struct pci_dev *pdev)
                /* PCI layer will sort out resources */
        }
 }
-DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5IDE, quirk_svwks_csb5ide );
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5IDE, quirk_svwks_csb5ide);
 
 /*
  *     Intel 82801CAM ICH3-M datasheet says IDE modes must be the same
@@ -914,7 +912,7 @@ static void __init quirk_ide_samemode(struct pci_dev *pdev)
        pci_read_config_byte(pdev, PCI_CLASS_PROG, &prog);
 
        if (((prog & 1) && !(prog & 4)) || ((prog & 4) && !(prog & 1))) {
-               printk(KERN_INFO "PCI: IDE mode mismatch; forcing legacy mode\n");
+               dev_info(&pdev->dev, "IDE mode mismatch; forcing legacy mode\n");
                prog &= ~5;
                pdev->class &= ~5;
                pci_write_config_byte(pdev, PCI_CLASS_PROG, prog);
@@ -929,7 +927,7 @@ static void __init quirk_eisa_bridge(struct pci_dev *dev)
 {
        dev->class = PCI_CLASS_BRIDGE_EISA << 8;
 }
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_82375,      quirk_eisa_bridge );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_82375,      quirk_eisa_bridge);
 
 
 /*
@@ -1022,6 +1020,11 @@ static void __init asus_hides_smbus_hostbridge(struct pci_dev *dev)
                        case 0x12bd: /* HP D530 */
                                asus_hides_smbus = 1;
                        }
+               else if (dev->device == PCI_DEVICE_ID_INTEL_82875_HB)
+                       switch (dev->subsystem_device) {
+                       case 0x12bf: /* HP xw4100 */
+                               asus_hides_smbus = 1;
+                       }
                else if (dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB)
                        switch (dev->subsystem_device) {
                        case 0x099c: /* HP Compaq nx6110 */
@@ -1049,17 +1052,18 @@ static void __init asus_hides_smbus_hostbridge(struct pci_dev *dev)
                        }
        }
 }
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_82845_HB,   asus_hides_smbus_hostbridge );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_82845G_HB,  asus_hides_smbus_hostbridge );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_82850_HB,   asus_hides_smbus_hostbridge );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_82865_HB,   asus_hides_smbus_hostbridge );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_7205_0,     asus_hides_smbus_hostbridge );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_E7501_MCH,  asus_hides_smbus_hostbridge );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_82855PM_HB, asus_hides_smbus_hostbridge );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_82855GM_HB, asus_hides_smbus_hostbridge );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_82915GM_HB, asus_hides_smbus_hostbridge );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_82845_HB,   asus_hides_smbus_hostbridge);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_82845G_HB,  asus_hides_smbus_hostbridge);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_82850_HB,   asus_hides_smbus_hostbridge);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_82865_HB,   asus_hides_smbus_hostbridge);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_82875_HB,   asus_hides_smbus_hostbridge);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_7205_0,     asus_hides_smbus_hostbridge);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_E7501_MCH,  asus_hides_smbus_hostbridge);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_82855PM_HB, asus_hides_smbus_hostbridge);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_82855GM_HB, asus_hides_smbus_hostbridge);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_82915GM_HB, asus_hides_smbus_hostbridge);
 
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_82810_IG3,  asus_hides_smbus_hostbridge );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_82810_IG3,  asus_hides_smbus_hostbridge);
 
 static void asus_hides_smbus_lpc(struct pci_dev *dev)
 {
@@ -1073,25 +1077,25 @@ static void asus_hides_smbus_lpc(struct pci_dev *dev)
                pci_write_config_word(dev, 0xF2, val & (~0x8));
                pci_read_config_word(dev, 0xF2, &val);
                if (val & 0x8)
-                       printk(KERN_INFO "PCI: i801 SMBus device continues to play 'hide and seek'! 0x%x\n", val);
+                       dev_info(&dev->dev, "i801 SMBus device continues to play 'hide and seek'! 0x%x\n", val);
                else
-                       printk(KERN_INFO "PCI: Enabled i801 SMBus device\n");
+                       dev_info(&dev->dev, "Enabled i801 SMBus device\n");
        }
 }
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_82801AA_0,  asus_hides_smbus_lpc );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_82801DB_0,  asus_hides_smbus_lpc );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_82801BA_0,  asus_hides_smbus_lpc );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_82801CA_0,  asus_hides_smbus_lpc );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_82801CA_12, asus_hides_smbus_lpc );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_82801DB_12, asus_hides_smbus_lpc );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_82801EB_0,  asus_hides_smbus_lpc );
-DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_82801AA_0,  asus_hides_smbus_lpc );
-DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_82801DB_0,  asus_hides_smbus_lpc );
-DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_82801BA_0,  asus_hides_smbus_lpc );
-DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_82801CA_0,  asus_hides_smbus_lpc );
-DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_82801CA_12, asus_hides_smbus_lpc );
-DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_82801DB_12, asus_hides_smbus_lpc );
-DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_82801EB_0,  asus_hides_smbus_lpc );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_82801AA_0,  asus_hides_smbus_lpc);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_82801DB_0,  asus_hides_smbus_lpc);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_82801BA_0,  asus_hides_smbus_lpc);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_82801CA_0,  asus_hides_smbus_lpc);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_82801CA_12, asus_hides_smbus_lpc);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_82801DB_12, asus_hides_smbus_lpc);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_82801EB_0,  asus_hides_smbus_lpc);
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_82801AA_0,  asus_hides_smbus_lpc);
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_82801DB_0,  asus_hides_smbus_lpc);
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_82801BA_0,  asus_hides_smbus_lpc);
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_82801CA_0,  asus_hides_smbus_lpc);
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_82801CA_12, asus_hides_smbus_lpc);
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_82801DB_12, asus_hides_smbus_lpc);
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_82801EB_0,  asus_hides_smbus_lpc);
 
 static void asus_hides_smbus_lpc_ich6(struct pci_dev *dev)
 {
@@ -1106,10 +1110,10 @@ static void asus_hides_smbus_lpc_ich6(struct pci_dev *dev)
        val=readl(base + 0x3418); /* read the Function Disable register, dword mode only */
        writel(val & 0xFFFFFFF7, base + 0x3418); /* enable the SMBus device */
        iounmap(base);
-       printk(KERN_INFO "PCI: Enabled ICH6/i801 SMBus device\n");
+       dev_info(&dev->dev, "Enabled ICH6/i801 SMBus device\n");
 }
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_ICH6_1,     asus_hides_smbus_lpc_ich6 );
-DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_ICH6_1,     asus_hides_smbus_lpc_ich6 );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_ICH6_1,     asus_hides_smbus_lpc_ich6);
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_ICH6_1,     asus_hides_smbus_lpc_ich6);
 
 /*
  * SiS 96x south bridge: BIOS typically hides SMBus device...
@@ -1119,18 +1123,18 @@ static void quirk_sis_96x_smbus(struct pci_dev *dev)
        u8 val = 0;
        pci_read_config_byte(dev, 0x77, &val);
        if (val & 0x10) {
-               printk(KERN_INFO "Enabling SiS 96x SMBus.\n");
+               dev_info(&dev->dev, "Enabling SiS 96x SMBus\n");
                pci_write_config_byte(dev, 0x77, val & ~0x10);
        }
 }
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI,     PCI_DEVICE_ID_SI_961,           quirk_sis_96x_smbus );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI,     PCI_DEVICE_ID_SI_962,           quirk_sis_96x_smbus );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI,     PCI_DEVICE_ID_SI_963,           quirk_sis_96x_smbus );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI,     PCI_DEVICE_ID_SI_LPC,           quirk_sis_96x_smbus );
-DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI,     PCI_DEVICE_ID_SI_961,           quirk_sis_96x_smbus );
-DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI,     PCI_DEVICE_ID_SI_962,           quirk_sis_96x_smbus );
-DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI,     PCI_DEVICE_ID_SI_963,           quirk_sis_96x_smbus );
-DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI,     PCI_DEVICE_ID_SI_LPC,           quirk_sis_96x_smbus );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI,     PCI_DEVICE_ID_SI_961,           quirk_sis_96x_smbus);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI,     PCI_DEVICE_ID_SI_962,           quirk_sis_96x_smbus);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI,     PCI_DEVICE_ID_SI_963,           quirk_sis_96x_smbus);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI,     PCI_DEVICE_ID_SI_LPC,           quirk_sis_96x_smbus);
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI,     PCI_DEVICE_ID_SI_961,           quirk_sis_96x_smbus);
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI,     PCI_DEVICE_ID_SI_962,           quirk_sis_96x_smbus);
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI,     PCI_DEVICE_ID_SI_963,           quirk_sis_96x_smbus);
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI,     PCI_DEVICE_ID_SI_LPC,           quirk_sis_96x_smbus);
 
 /*
  * ... This is further complicated by the fact that some SiS96x south
@@ -1163,8 +1167,8 @@ static void quirk_sis_503(struct pci_dev *dev)
        dev->device = devid;
        quirk_sis_96x_smbus(dev);
 }
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI,     PCI_DEVICE_ID_SI_503,           quirk_sis_503 );
-DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI,     PCI_DEVICE_ID_SI_503,           quirk_sis_503 );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI,     PCI_DEVICE_ID_SI_503,           quirk_sis_503);
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI,     PCI_DEVICE_ID_SI_503,           quirk_sis_503);
 
 
 /*
@@ -1191,13 +1195,13 @@ static void asus_hides_ac97_lpc(struct pci_dev *dev)
                pci_write_config_byte(dev, 0x50, val & (~0xc0));
                pci_read_config_byte(dev, 0x50, &val);
                if (val & 0xc0)
-                       printk(KERN_INFO "PCI: onboard AC97/MC97 devices continue to play 'hide and seek'! 0x%x\n", val);
+                       dev_info(&dev->dev, "Onboard AC97/MC97 devices continue to play 'hide and seek'! 0x%x\n", val);
                else
-                       printk(KERN_INFO "PCI: enabled onboard AC97/MC97 devices\n");
+                       dev_info(&dev->dev, "Enabled onboard AC97/MC97 devices\n");
        }
 }
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA,    PCI_DEVICE_ID_VIA_8237, asus_hides_ac97_lpc );
-DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA,    PCI_DEVICE_ID_VIA_8237, asus_hides_ac97_lpc );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA,    PCI_DEVICE_ID_VIA_8237, asus_hides_ac97_lpc);
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA,    PCI_DEVICE_ID_VIA_8237, asus_hides_ac97_lpc);
 
 #if defined(CONFIG_ATA) || defined(CONFIG_ATA_MODULE)
 
@@ -1292,7 +1296,7 @@ static void __init quirk_alder_ioapic(struct pci_dev *pdev)
        }
 
 }
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_EESSC,      quirk_alder_ioapic );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_EESSC,      quirk_alder_ioapic);
 #endif
 
 int pcie_mch_quirk;
@@ -1302,9 +1306,9 @@ static void __devinit quirk_pcie_mch(struct pci_dev *pdev)
 {
        pcie_mch_quirk = 1;
 }
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_E7520_MCH,  quirk_pcie_mch );
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_E7320_MCH,  quirk_pcie_mch );
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_E7525_MCH,  quirk_pcie_mch );
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_E7520_MCH,  quirk_pcie_mch);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_E7320_MCH,  quirk_pcie_mch);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_E7525_MCH,  quirk_pcie_mch);
 
 
 /*
@@ -1314,11 +1318,8 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,     PCI_DEVICE_ID_INTEL_E7525_MCH,  quir
 static void __devinit quirk_pcie_pxh(struct pci_dev *dev)
 {
        pci_msi_off(dev);
-
        dev->no_msi = 1;
-
-       printk(KERN_WARNING "PCI: PXH quirk detected, "
-               "disabling MSI for SHPC device\n");
+       dev_warn(&dev->dev, "PXH quirk detected; SHPC device MSI disabled\n");
 }
 DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_PXHD_0,     quirk_pcie_pxh);
 DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_PXHD_1,     quirk_pcie_pxh);
@@ -1399,7 +1400,7 @@ static void __devinit quirk_netmos(struct pci_dev *dev)
        case PCI_DEVICE_ID_NETMOS_9855:
                if ((dev->class >> 8) == PCI_CLASS_COMMUNICATION_SERIAL &&
                    num_parallel) {
-                       printk(KERN_INFO "PCI: Netmos %04x (%u parallel, "
+                       dev_info(&dev->dev, "Netmos %04x (%u parallel, "
                                "%u serial); changing class SERIAL to OTHER "
                                "(use parport_serial)\n",
                                dev->device, num_parallel, num_serial);
@@ -1412,9 +1413,10 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NETMOS, PCI_ANY_ID, quirk_netmos);
 
 static void __devinit quirk_e100_interrupt(struct pci_dev *dev)
 {
-       u16 command;
+       u16 command, pmcsr;
        u8 __iomem *csr;
        u8 cmd_hi;
+       int pm;
 
        switch (dev->device) {
        /* PCI IDs taken from drivers/net/e100.c */
@@ -1448,18 +1450,28 @@ static void __devinit quirk_e100_interrupt(struct pci_dev *dev)
        if (!(command & PCI_COMMAND_MEMORY) || !pci_resource_start(dev, 0))
                return;
 
+       /*
+        * Check that the device is in the D0 power state. If it's not,
+        * there is no point to look any further.
+        */
+       pm = pci_find_capability(dev, PCI_CAP_ID_PM);
+       if (pm) {
+               pci_read_config_word(dev, pm + PCI_PM_CTRL, &pmcsr);
+               if ((pmcsr & PCI_PM_CTRL_STATE_MASK) != PCI_D0)
+                       return;
+       }
+
        /* Convert from PCI bus to resource space.  */
        csr = ioremap(pci_resource_start(dev, 0), 8);
        if (!csr) {
-               printk(KERN_WARNING "PCI: Can't map %s e100 registers\n",
-                       pci_name(dev));
+               dev_warn(&dev->dev, "Can't map e100 registers\n");
                return;
        }
 
        cmd_hi = readb(csr + 3);
        if (cmd_hi == 0) {
-               printk(KERN_WARNING "PCI: Firmware left %s e100 interrupts "
-                       "enabled, disabling\n", pci_name(dev));
+               dev_warn(&dev->dev, "Firmware left e100 interrupts enabled; "
+                       "disabling\n");
                writeb(1, csr + 3);
        }
 
@@ -1474,7 +1486,7 @@ static void __devinit fixup_rev1_53c810(struct pci_dev* dev)
         */
 
        if (dev->class == PCI_CLASS_NOT_DEFINED) {
-               printk(KERN_INFO "NCR 53c810 rev 1 detected, setting PCI class.\n");
+               dev_info(&dev->dev, "NCR 53c810 rev 1 detected; setting PCI class\n");
                dev->class = PCI_CLASS_STORAGE_SCSI;
        }
 }
@@ -1485,7 +1497,11 @@ static void pci_do_fixups(struct pci_dev *dev, struct pci_fixup *f, struct pci_f
        while (f < end) {
                if ((f->vendor == dev->vendor || f->vendor == (u16) PCI_ANY_ID) &&
                    (f->device == dev->device || f->device == (u16) PCI_ANY_ID)) {
-                       pr_debug("PCI: Calling quirk %p for %s\n", f->hook, pci_name(dev));
+#ifdef DEBUG
+                       dev_dbg(&dev->dev, "calling quirk 0x%p", f->hook);
+                       print_fn_descriptor_symbol(": %s()\n",
+                               (unsigned long) f->hook);
+#endif
                        f->hook(dev);
                }
                f++;
@@ -1553,7 +1569,7 @@ static void __devinit quirk_p64h2_1k_io(struct pci_dev *dev)
        pci_read_config_word(dev, 0x40, &en1k);
 
        if (en1k & 0x200) {
-               printk(KERN_INFO "PCI: Enable I/O Space to 1 KB Granularity\n");
+               dev_info(&dev->dev, "Enable I/O Space to 1KB granularity\n");
 
                pci_read_config_byte(dev, PCI_IO_BASE, &io_base_lo);
                pci_read_config_byte(dev, PCI_IO_LIMIT, &io_limit_lo);
@@ -1585,7 +1601,7 @@ static void __devinit quirk_p64h2_1k_io_fix_iobl(struct pci_dev *dev)
                iobl_adr_1k = iobl_adr | (res->start >> 8) | (res->end & 0xfc00);
 
                if (iobl_adr != iobl_adr_1k) {
-                       printk(KERN_INFO "PCI: Fixing P64H2 IOBL_ADR from 0x%x to 0x%x for 1 KB Granularity\n",
+                       dev_info(&dev->dev, "Fixing P64H2 IOBL_ADR from 0x%x to 0x%x for 1KB granularity\n",
                                iobl_adr,iobl_adr_1k);
                        pci_write_config_word(dev, PCI_IO_BASE, iobl_adr_1k);
                }
@@ -1603,9 +1619,8 @@ static void quirk_nvidia_ck804_pcie_aer_ext_cap(struct pci_dev *dev)
        if (pci_read_config_byte(dev, 0xf41, &b) == 0) {
                if (!(b & 0x20)) {
                        pci_write_config_byte(dev, 0xf41, b | 0x20);
-                       printk(KERN_INFO
-                              "PCI: Linking AER extended capability on %s\n",
-                              pci_name(dev));
+                       dev_info(&dev->dev,
+                              "Linking AER extended capability\n");
                }
        }
 }
@@ -1614,6 +1629,34 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA,  PCI_DEVICE_ID_NVIDIA_CK804_PCIE,
 DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_NVIDIA,  PCI_DEVICE_ID_NVIDIA_CK804_PCIE,
                        quirk_nvidia_ck804_pcie_aer_ext_cap);
 
+static void __devinit quirk_via_cx700_pci_parking_caching(struct pci_dev *dev)
+{
+       /*
+        * Disable PCI Bus Parking and PCI Master read caching on CX700
+        * which causes unspecified timing errors with a VT6212L on the PCI
+        * bus leading to USB2.0 packet loss. The defaults are that these
+        * features are turned off but some BIOSes turn them on.
+        */
+
+       uint8_t b;
+       if (pci_read_config_byte(dev, 0x76, &b) == 0) {
+               if (b & 0x40) {
+                       /* Turn off PCI Bus Parking */
+                       pci_write_config_byte(dev, 0x76, b ^ 0x40);
+
+                       /* Turn off PCI Master read caching */
+                       pci_write_config_byte(dev, 0x72, 0x0);
+                       pci_write_config_byte(dev, 0x75, 0x1);
+                       pci_write_config_byte(dev, 0x77, 0x0);
+
+                       printk(KERN_INFO
+                               "PCI: VIA CX700 PCI parking/caching fixup on %s\n",
+                               pci_name(dev));
+               }
+       }
+}
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_VIA, 0x324e, quirk_via_cx700_pci_parking_caching);
+
 #ifdef CONFIG_PCI_MSI
 /* Some chipsets do not support MSI. We cannot easily rely on setting
  * PCI_BUS_FLAGS_NO_MSI in its bus flags because there are actually
@@ -1624,7 +1667,7 @@ DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_NVIDIA,  PCI_DEVICE_ID_NVIDIA_CK804_PCIE,
 static void __init quirk_disable_all_msi(struct pci_dev *dev)
 {
        pci_no_msi();
-       printk(KERN_WARNING "PCI: MSI quirk detected. MSI deactivated.\n");
+       dev_warn(&dev->dev, "MSI quirk detected; MSI disabled\n");
 }
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_GCNB_LE, quirk_disable_all_msi);
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RS400_200, quirk_disable_all_msi);
@@ -1635,9 +1678,8 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VT3351, quirk_disab
 static void __devinit quirk_disable_msi(struct pci_dev *dev)
 {
        if (dev->subordinate) {
-               printk(KERN_WARNING "PCI: MSI quirk detected. "
-                      "PCI_BUS_FLAGS_NO_MSI set for %s subordinate bus.\n",
-                      pci_name(dev));
+               dev_warn(&dev->dev, "MSI quirk detected; "
+                       "subordinate MSI disabled\n");
                dev->subordinate->bus_flags |= PCI_BUS_FLAGS_NO_MSI;
        }
 }
@@ -1656,9 +1698,9 @@ static int __devinit msi_ht_cap_enabled(struct pci_dev *dev)
                if (pci_read_config_byte(dev, pos + HT_MSI_FLAGS,
                                         &flags) == 0)
                {
-                       printk(KERN_INFO "PCI: Found %s HT MSI Mapping on %s\n",
+                       dev_info(&dev->dev, "Found %s HT MSI Mapping\n",
                                flags & HT_MSI_FLAGS_ENABLE ?
-                               "enabled" : "disabled", pci_name(dev));
+                               "enabled" : "disabled");
                        return (flags & HT_MSI_FLAGS_ENABLE) != 0;
                }
 
@@ -1672,17 +1714,40 @@ static int __devinit msi_ht_cap_enabled(struct pci_dev *dev)
 static void __devinit quirk_msi_ht_cap(struct pci_dev *dev)
 {
        if (dev->subordinate && !msi_ht_cap_enabled(dev)) {
-               printk(KERN_WARNING "PCI: MSI quirk detected. "
-                      "MSI disabled on chipset %s.\n",
-                      pci_name(dev));
+               dev_warn(&dev->dev, "MSI quirk detected; "
+                       "subordinate MSI disabled\n");
                dev->subordinate->bus_flags |= PCI_BUS_FLAGS_NO_MSI;
        }
 }
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_HT2000_PCIE,
                        quirk_msi_ht_cap);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SERVERWORKS,
-                       PCI_DEVICE_ID_SERVERWORKS_HT1000_PXB,
-                       quirk_msi_ht_cap);
+
+
+/*
+ *  Force enable MSI mapping capability on HT bridges
+ */
+static void __devinit quirk_msi_ht_cap_enable(struct pci_dev *dev)
+{
+       int pos, ttl = 48;
+
+       pos = pci_find_ht_capability(dev, HT_CAPTYPE_MSI_MAPPING);
+       while (pos && ttl--) {
+               u8 flags;
+
+               if (pci_read_config_byte(dev, pos + HT_MSI_FLAGS, &flags) == 0) {
+                       printk(KERN_INFO "PCI: Enabling HT MSI Mapping on %s\n",
+                              pci_name(dev));
+
+                       pci_write_config_byte(dev, pos + HT_MSI_FLAGS,
+                                             flags | HT_MSI_FLAGS_ENABLE);
+               }
+               pos = pci_find_next_ht_capability(dev, pos,
+                                                 HT_CAPTYPE_MSI_MAPPING);
+       }
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SERVERWORKS,
+                        PCI_DEVICE_ID_SERVERWORKS_HT1000_PXB,
+                        quirk_msi_ht_cap_enable);
 
 /* The nVidia CK804 chipset may have 2 HT MSI mappings.
  * MSI are supported if the MSI capability set in any of these mappings.
@@ -1701,9 +1766,8 @@ static void __devinit quirk_nvidia_ck804_msi_ht_cap(struct pci_dev *dev)
        if (!pdev)
                return;
        if (!msi_ht_cap_enabled(dev) && !msi_ht_cap_enabled(pdev)) {
-               printk(KERN_WARNING "PCI: MSI quirk detected. "
-                      "MSI disabled on chipset %s.\n",
-                      pci_name(dev));
+               dev_warn(&dev->dev, "MSI quirk detected; "
+                       "subordinate MSI disabled\n");
                dev->subordinate->bus_flags |= PCI_BUS_FLAGS_NO_MSI;
        }
        pci_dev_put(pdev);
@@ -1715,6 +1779,23 @@ static void __devinit quirk_msi_intx_disable_bug(struct pci_dev *dev)
 {
        dev->dev_flags |= PCI_DEV_FLAGS_MSI_INTX_DISABLE_BUG;
 }
+static void __devinit quirk_msi_intx_disable_ati_bug(struct pci_dev *dev)
+{
+       struct pci_dev *p;
+
+       /* SB700 MSI issue will be fixed at HW level from revision A21,
+        * we need check PCI REVISION ID of SMBus controller to get SB700
+        * revision.
+        */
+       p = pci_get_device(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_SBX00_SMBUS,
+                          NULL);
+       if (!p)
+               return;
+
+       if ((p->revision < 0x3B) && (p->revision >= 0x30))
+               dev->dev_flags |= PCI_DEV_FLAGS_MSI_INTX_DISABLE_BUG;
+       pci_dev_put(p);
+}
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_BROADCOM,
                        PCI_DEVICE_ID_TIGON3_5780,
                        quirk_msi_intx_disable_bug);
@@ -1735,17 +1816,15 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_BROADCOM,
                        quirk_msi_intx_disable_bug);
 
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x4390,
-                       quirk_msi_intx_disable_bug);
+                       quirk_msi_intx_disable_ati_bug);
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x4391,
-                       quirk_msi_intx_disable_bug);
+                       quirk_msi_intx_disable_ati_bug);
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x4392,
-                       quirk_msi_intx_disable_bug);
+                       quirk_msi_intx_disable_ati_bug);
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x4393,
-                       quirk_msi_intx_disable_bug);
+                       quirk_msi_intx_disable_ati_bug);
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x4394,
-                       quirk_msi_intx_disable_bug);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x4395,
-                       quirk_msi_intx_disable_bug);
+                       quirk_msi_intx_disable_ati_bug);
 
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x4373,
                        quirk_msi_intx_disable_bug);
index 430281b2e9212400af4b8bf3dd9aa1fa72c41855..9684e1bde277a1e012fae641363178f394071323 100644 (file)
@@ -74,10 +74,8 @@ void pci_remove_bus(struct pci_bus *pci_bus)
        list_del(&pci_bus->node);
        up_write(&pci_bus_sem);
        pci_remove_legacy_files(pci_bus);
-       class_device_remove_file(&pci_bus->class_dev,
-               &class_device_attr_cpuaffinity);
-       sysfs_remove_link(&pci_bus->class_dev.kobj, "bridge");
-       class_device_unregister(&pci_bus->class_dev);
+       device_remove_file(&pci_bus->dev, &dev_attr_cpuaffinity);
+       device_unregister(&pci_bus->dev);
 }
 EXPORT_SYMBOL(pci_remove_bus);
 
index dbbcc04abd1af1fe06eafc7be1a647d847233e25..a98b2470b9ea5f85b95a3ae3c9da79aeafb29363 100644 (file)
@@ -162,6 +162,7 @@ void __iomem *pci_map_rom(struct pci_dev *pdev, size_t *size)
        return rom;
 }
 
+#if 0
 /**
  * pci_map_rom_copy - map a PCI ROM to kernel space, create a copy
  * @pdev: pointer to pci device struct
@@ -196,6 +197,7 @@ void __iomem *pci_map_rom_copy(struct pci_dev *pdev, size_t *size)
 
        return (void __iomem *)(unsigned long)res->start;
 }
+#endif  /*  0  */
 
 /**
  * pci_unmap_rom - unmap the ROM from kernel space
@@ -218,6 +220,7 @@ void pci_unmap_rom(struct pci_dev *pdev, void __iomem *rom)
                pci_disable_rom(pdev);
 }
 
+#if 0
 /**
  * pci_remove_rom - disable the ROM and remove its sysfs attribute
  * @pdev: pointer to pci device struct
@@ -236,6 +239,7 @@ void pci_remove_rom(struct pci_dev *pdev)
                            IORESOURCE_ROM_COPY)))
                pci_disable_rom(pdev);
 }
+#endif  /*  0  */
 
 /**
  * pci_cleanup_rom - internal routine for freeing the ROM copy created
@@ -256,6 +260,4 @@ void pci_cleanup_rom(struct pci_dev *pdev)
 }
 
 EXPORT_SYMBOL(pci_map_rom);
-EXPORT_SYMBOL(pci_map_rom_copy);
 EXPORT_SYMBOL(pci_unmap_rom);
-EXPORT_SYMBOL(pci_remove_rom);
index 401e03c920bdf034c3849ea01c03d6a5adc8fabc..262b0439abe9e41a476629d9ac35927f2491620f 100644 (file)
@@ -89,8 +89,9 @@ void pci_setup_cardbus(struct pci_bus *bus)
                 * The IO resource is allocated a range twice as large as it
                 * would normally need.  This allows us to set both IO regs.
                 */
-               printk("  IO window: %08lx-%08lx\n",
-                       region.start, region.end);
+               printk(KERN_INFO "  IO window: 0x%08lx-0x%08lx\n",
+                      (unsigned long)region.start,
+                      (unsigned long)region.end);
                pci_write_config_dword(bridge, PCI_CB_IO_BASE_0,
                                        region.start);
                pci_write_config_dword(bridge, PCI_CB_IO_LIMIT_0,
@@ -99,8 +100,9 @@ void pci_setup_cardbus(struct pci_bus *bus)
 
        pcibios_resource_to_bus(bridge, &region, bus->resource[1]);
        if (bus->resource[1]->flags & IORESOURCE_IO) {
-               printk("  IO window: %08lx-%08lx\n",
-                       region.start, region.end);
+               printk(KERN_INFO "  IO window: 0x%08lx-0x%08lx\n",
+                      (unsigned long)region.start,
+                      (unsigned long)region.end);
                pci_write_config_dword(bridge, PCI_CB_IO_BASE_1,
                                        region.start);
                pci_write_config_dword(bridge, PCI_CB_IO_LIMIT_1,
@@ -109,8 +111,9 @@ void pci_setup_cardbus(struct pci_bus *bus)
 
        pcibios_resource_to_bus(bridge, &region, bus->resource[2]);
        if (bus->resource[2]->flags & IORESOURCE_MEM) {
-               printk("  PREFETCH window: %08lx-%08lx\n",
-                       region.start, region.end);
+               printk(KERN_INFO "  PREFETCH window: 0x%08lx-0x%08lx\n",
+                      (unsigned long)region.start,
+                      (unsigned long)region.end);
                pci_write_config_dword(bridge, PCI_CB_MEMORY_BASE_0,
                                        region.start);
                pci_write_config_dword(bridge, PCI_CB_MEMORY_LIMIT_0,
@@ -119,8 +122,9 @@ void pci_setup_cardbus(struct pci_bus *bus)
 
        pcibios_resource_to_bus(bridge, &region, bus->resource[3]);
        if (bus->resource[3]->flags & IORESOURCE_MEM) {
-               printk("  MEM window: %08lx-%08lx\n",
-                       region.start, region.end);
+               printk(KERN_INFO "  MEM window: 0x%08lx-0x%08lx\n",
+                      (unsigned long)region.start,
+                      (unsigned long)region.end);
                pci_write_config_dword(bridge, PCI_CB_MEMORY_BASE_1,
                                        region.start);
                pci_write_config_dword(bridge, PCI_CB_MEMORY_LIMIT_1,
@@ -145,7 +149,7 @@ pci_setup_bridge(struct pci_bus *bus)
 {
        struct pci_dev *bridge = bus->self;
        struct pci_bus_region region;
-       u32 l, io_upper16;
+       u32 l, bu, lu, io_upper16;
 
        DBG(KERN_INFO "PCI: Bridge: %s\n", pci_name(bridge));
 
@@ -159,7 +163,8 @@ pci_setup_bridge(struct pci_bus *bus)
                /* Set up upper 16 bits of I/O base/limit. */
                io_upper16 = (region.end & 0xffff0000) | (region.start >> 16);
                DBG(KERN_INFO "  IO window: %04lx-%04lx\n",
-                               region.start, region.end);
+                   (unsigned long)region.start,
+                   (unsigned long)region.end);
        }
        else {
                /* Clear upper 16 bits of I/O base/limit. */
@@ -180,8 +185,9 @@ pci_setup_bridge(struct pci_bus *bus)
        if (bus->resource[1]->flags & IORESOURCE_MEM) {
                l = (region.start >> 16) & 0xfff0;
                l |= region.end & 0xfff00000;
-               DBG(KERN_INFO "  MEM window: %08lx-%08lx\n",
-                               region.start, region.end);
+               DBG(KERN_INFO "  MEM window: 0x%08lx-0x%08lx\n",
+                   (unsigned long)region.start,
+                   (unsigned long)region.end);
        }
        else {
                l = 0x0000fff0;
@@ -195,12 +201,18 @@ pci_setup_bridge(struct pci_bus *bus)
        pci_write_config_dword(bridge, PCI_PREF_LIMIT_UPPER32, 0);
 
        /* Set up PREF base/limit. */
+       bu = lu = 0;
        pcibios_resource_to_bus(bridge, &region, bus->resource[2]);
        if (bus->resource[2]->flags & IORESOURCE_PREFETCH) {
                l = (region.start >> 16) & 0xfff0;
                l |= region.end & 0xfff00000;
-               DBG(KERN_INFO "  PREFETCH window: %08lx-%08lx\n",
-                               region.start, region.end);
+#ifdef CONFIG_RESOURCES_64BIT
+               bu = region.start >> 32;
+               lu = region.end >> 32;
+#endif
+               DBG(KERN_INFO "  PREFETCH window: 0x%016llx-0x%016llx\n",
+                   (unsigned long long)region.start,
+                   (unsigned long long)region.end);
        }
        else {
                l = 0x0000fff0;
@@ -208,8 +220,9 @@ pci_setup_bridge(struct pci_bus *bus)
        }
        pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, l);
 
-       /* Clear out the upper 32 bits of PREF base. */
-       pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32, 0);
+       /* Set the upper 32 bits of PREF base & limit. */
+       pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32, bu);
+       pci_write_config_dword(bridge, PCI_PREF_LIMIT_UPPER32, lu);
 
        pci_write_config_word(bridge, PCI_BRIDGE_CONTROL, bus->bridge_ctl);
 }
@@ -323,8 +336,8 @@ static void pbus_size_io(struct pci_bus *bus)
 static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, unsigned long type)
 {
        struct pci_dev *dev;
-       unsigned long min_align, align, size;
-       unsigned long aligns[12];       /* Alignments from 1Mb to 2Gb */
+       resource_size_t min_align, align, size;
+       resource_size_t aligns[12];     /* Alignments from 1Mb to 2Gb */
        int order, max_order;
        struct resource *b_res = find_free_bus_resource(bus, type);
 
@@ -340,7 +353,7 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, unsigned long
                
                for (i = 0; i < PCI_NUM_RESOURCES; i++) {
                        struct resource *r = &dev->resource[i];
-                       unsigned long r_size;
+                       resource_size_t r_size;
 
                        if (r->parent || (r->flags & mask) != type)
                                continue;
@@ -350,10 +363,10 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, unsigned long
                        order = __ffs(align) - 20;
                        if (order > 11) {
                                printk(KERN_WARNING "PCI: region %s/%d "
-                                      "too large: %llx-%llx\n",
+                                      "too large: 0x%016llx-0x%016llx\n",
                                        pci_name(dev), i,
-                                       (unsigned long long)r->start,
-                                       (unsigned long long)r->end);
+                                      (unsigned long long)r->start,
+                                      (unsigned long long)r->end);
                                r->flags = 0;
                                continue;
                        }
@@ -372,8 +385,11 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, unsigned long
        align = 0;
        min_align = 0;
        for (order = 0; order <= max_order; order++) {
-               unsigned long align1 = 1UL << (order + 20);
-
+#ifdef CONFIG_RESOURCES_64BIT
+               resource_size_t align1 = 1ULL << (order + 20);
+#else
+               resource_size_t align1 = 1U << (order + 20);
+#endif
                if (!align)
                        min_align = align1;
                else if (ALIGN(align + min_align, min_align) < align1)
@@ -440,7 +456,7 @@ pci_bus_size_cardbus(struct pci_bus *bus)
        }
 }
 
-void pci_bus_size_bridges(struct pci_bus *bus)
+void __ref pci_bus_size_bridges(struct pci_bus *bus)
 {
        struct pci_dev *dev;
        unsigned long mask, prefmask;
@@ -495,7 +511,7 @@ void pci_bus_size_bridges(struct pci_bus *bus)
 }
 EXPORT_SYMBOL(pci_bus_size_bridges);
 
-void pci_bus_assign_resources(struct pci_bus *bus)
+void __ref pci_bus_assign_resources(struct pci_bus *bus)
 {
        struct pci_bus *b;
        struct pci_dev *dev;
index 6dfd86167e39107fe92058b92a5ade8d90784566..4be7ccf7e3ae9f4984b3ccae7563e23beb601d5b 100644 (file)
@@ -51,10 +51,12 @@ pci_update_resource(struct pci_dev *dev, struct resource *res, int resno)
 
        pcibios_resource_to_bus(dev, &region, res);
 
-       pr_debug("  got res [%llx:%llx] bus [%lx:%lx] flags %lx for "
+       pr_debug("  got res [%llx:%llx] bus [%llx:%llx] flags %lx for "
                 "BAR %d of %s\n", (unsigned long long)res->start,
                 (unsigned long long)res->end,
-                region.start, region.end, res->flags, resno, pci_name(dev));
+                (unsigned long long)region.start,
+                (unsigned long long)region.end,
+                (unsigned long)res->flags, resno, pci_name(dev));
 
        new = region.start | (res->flags & PCI_REGION_FLAG_MASK);
        if (res->flags & IORESOURCE_IO)
@@ -125,7 +127,6 @@ int pci_claim_resource(struct pci_dev *dev, int resource)
 
        return err;
 }
-EXPORT_SYMBOL_GPL(pci_claim_resource);
 
 int pci_assign_resource(struct pci_dev *dev, int resno)
 {
index 2ac050d7f8cffbc12e57384ee96894917236c73e..645d7a60e412ce3d970044ca89a823db3e21007c 100644 (file)
@@ -34,7 +34,6 @@ sys_pciconfig_read(unsigned long bus, unsigned long dfn,
        if (!dev)
                goto error;
 
-       lock_kernel();
        switch (len) {
        case 1:
                cfg_ret = pci_user_read_config_byte(dev, off, &byte);
@@ -47,10 +46,8 @@ sys_pciconfig_read(unsigned long bus, unsigned long dfn,
                break;
        default:
                err = -EINVAL;
-               unlock_kernel();
                goto error;
        };
-       unlock_kernel();
 
        err = -EIO;
        if (cfg_ret != PCIBIOS_SUCCESSFUL)
@@ -107,7 +104,6 @@ sys_pciconfig_write(unsigned long bus, unsigned long dfn,
        if (!dev)
                return -ENODEV;
 
-       lock_kernel();
        switch(len) {
        case 1:
                err = get_user(byte, (u8 __user *)buf);
@@ -140,7 +136,6 @@ sys_pciconfig_write(unsigned long bus, unsigned long dfn,
                err = -EINVAL;
                break;
        }
-       unlock_kernel();
        pci_dev_put(dev);
        return err;
 }
index eb6abd3f9221a896f1375ff855c2ac419491e630..385e145e1acc5688bed7b7869fe6aa40020ada9d 100644 (file)
@@ -21,9 +21,9 @@
 #include <asm/hardware.h>
 #include <asm/io.h>
 #include <asm/sizes.h>
+#include <asm/gpio.h>
 
 #include <asm/arch/board.h>
-#include <asm/arch/gpio.h>
 #include <asm/arch/at91rm9200_mc.h>
 
 
@@ -56,7 +56,7 @@ struct at91_cf_socket {
 
 static inline int at91_cf_present(struct at91_cf_socket *cf)
 {
-       return !at91_get_gpio_value(cf->board->det_pin);
+       return !gpio_get_value(cf->board->det_pin);
 }
 
 /*--------------------------------------------------------------------------*/
@@ -100,9 +100,9 @@ static int at91_cf_get_status(struct pcmcia_socket *s, u_int *sp)
                int vcc = cf->board->vcc_pin;
 
                *sp = SS_DETECT | SS_3VCARD;
-               if (!rdy || at91_get_gpio_value(rdy))
+               if (!rdy || gpio_get_value(rdy))
                        *sp |= SS_READY;
-               if (!vcc || at91_get_gpio_value(vcc))
+               if (!vcc || gpio_get_value(vcc))
                        *sp |= SS_POWERON;
        } else
                *sp = 0;
@@ -121,10 +121,10 @@ at91_cf_set_socket(struct pcmcia_socket *sock, struct socket_state_t *s)
        if (cf->board->vcc_pin) {
                switch (s->Vcc) {
                        case 0:
-                               at91_set_gpio_value(cf->board->vcc_pin, 0);
+                               gpio_set_value(cf->board->vcc_pin, 0);
                                break;
                        case 33:
-                               at91_set_gpio_value(cf->board->vcc_pin, 1);
+                               gpio_set_value(cf->board->vcc_pin, 1);
                                break;
                        default:
                                return -EINVAL;
@@ -132,7 +132,7 @@ at91_cf_set_socket(struct pcmcia_socket *sock, struct socket_state_t *s)
        }
 
        /* toggle reset if needed */
-       at91_set_gpio_value(cf->board->rst_pin, s->flags & SS_RESET);
+       gpio_set_value(cf->board->rst_pin, s->flags & SS_RESET);
 
        pr_debug("%s: Vcc %d, io_irq %d, flags %04x csc %04x\n",
                driver_name, s->Vcc, s->io_irq, s->flags, s->csc_mask);
@@ -239,11 +239,24 @@ static int __init at91_cf_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, cf);
 
        /* must be a GPIO; ergo must trigger on both edges */
-       status = request_irq(board->det_pin, at91_cf_irq, 0, driver_name, cf);
+       status = gpio_request(board->det_pin, "cf_det");
        if (status < 0)
                goto fail0;
+       status = request_irq(board->det_pin, at91_cf_irq, 0, driver_name, cf);
+       if (status < 0)
+               goto fail00;
        device_init_wakeup(&pdev->dev, 1);
 
+       status = gpio_request(board->rst_pin, "cf_rst");
+       if (status < 0)
+               goto fail0a;
+
+       if (board->vcc_pin) {
+               status = gpio_request(board->vcc_pin, "cf_vcc");
+               if (status < 0)
+                       goto fail0b;
+       }
+
        /*
         * The card driver will request this irq later as needed.
         * but it causes lots of "irqNN: nobody cared" messages
@@ -251,16 +264,20 @@ static int __init at91_cf_probe(struct platform_device *pdev)
         * (Note:  DK board doesn't wire the IRQ pin...)
         */
        if (board->irq_pin) {
+               status = gpio_request(board->irq_pin, "cf_irq");
+               if (status < 0)
+                       goto fail0c;
                status = request_irq(board->irq_pin, at91_cf_irq,
                                IRQF_SHARED, driver_name, cf);
                if (status < 0)
-                       goto fail0a;
+                       goto fail0d;
                cf->socket.pci_irq = board->irq_pin;
        } else
                cf->socket.pci_irq = NR_IRQS + 1;
 
        /* pcmcia layer only remaps "real" memory not iospace */
-       cf->socket.io_offset = (unsigned long) ioremap(cf->phys_baseaddr + CF_IO_PHYS, SZ_2K);
+       cf->socket.io_offset = (unsigned long)
+                       ioremap(cf->phys_baseaddr + CF_IO_PHYS, SZ_2K);
        if (!cf->socket.io_offset) {
                status = -ENXIO;
                goto fail1;
@@ -296,11 +313,21 @@ fail2:
 fail1:
        if (cf->socket.io_offset)
                iounmap((void __iomem *) cf->socket.io_offset);
-       if (board->irq_pin)
+       if (board->irq_pin) {
                free_irq(board->irq_pin, cf);
+fail0d:
+               gpio_free(board->irq_pin);
+       }
+fail0c:
+       if (board->vcc_pin)
+               gpio_free(board->vcc_pin);
+fail0b:
+       gpio_free(board->rst_pin);
 fail0a:
        device_init_wakeup(&pdev->dev, 0);
        free_irq(board->det_pin, cf);
+fail00:
+       gpio_free(board->det_pin);
 fail0:
        kfree(cf);
        return status;
@@ -313,13 +340,18 @@ static int __exit at91_cf_remove(struct platform_device *pdev)
        struct resource         *io = cf->socket.io[0].res;
 
        pcmcia_unregister_socket(&cf->socket);
-       if (board->irq_pin)
+       release_mem_region(io->start, io->end + 1 - io->start);
+       iounmap((void __iomem *) cf->socket.io_offset);
+       if (board->irq_pin) {
                free_irq(board->irq_pin, cf);
+               gpio_free(board->irq_pin);
+       }
+       if (board->vcc_pin)
+               gpio_free(board->vcc_pin);
+       gpio_free(board->rst_pin);
        device_init_wakeup(&pdev->dev, 0);
        free_irq(board->det_pin, cf);
-       iounmap((void __iomem *) cf->socket.io_offset);
-       release_mem_region(io->start, io->end + 1 - io->start);
-
+       gpio_free(board->det_pin);
        kfree(cf);
        return 0;
 }
index a1bd763b4e336e94b277a6fe650adf2107044807..714baaeb6da1257a264c903b4b36d67570c15486 100644 (file)
@@ -143,7 +143,7 @@ int read_cb_mem(struct pcmcia_socket * s, int space, u_int addr, u_int len, void
        /* Config space? */
        if (space == 0) {
                if (addr + len > 0x100)
-                       goto fail;
+                       goto failput;
                for (; len; addr++, ptr++, len--)
                        pci_read_config_byte(dev, addr, ptr);
                return 0;
@@ -171,6 +171,8 @@ int read_cb_mem(struct pcmcia_socket * s, int space, u_int addr, u_int len, void
        memcpy_fromio(ptr, s->cb_cis_virt + addr, len);
        return 0;
 
+failput:
+       pci_dev_put(dev);
 fail:
        memset(ptr, 0xff, len);
        return -1;
index 15c18f5246d6d21bbd2c849892ef0f88d536395c..5a85871f5ee919ff3bdb18f10be8715132b037de 100644 (file)
@@ -865,11 +865,12 @@ static int pcmcia_load_firmware(struct pcmcia_device *dev, char * filename)
        ds_dbg(1, "trying to load CIS file %s\n", filename);
 
        if (strlen(filename) > 14) {
-               printk(KERN_WARNING "pcmcia: CIS filename is too long\n");
+               printk(KERN_WARNING "pcmcia: CIS filename is too long [%s]\n",
+                       filename);
                return -EINVAL;
        }
 
-       snprintf(path, 20, "%s", filename);
+       snprintf(path, sizeof(path), "%s", filename);
 
        if (request_firmware(&fw, path, &dev->dev) == 0) {
                if (fw->size >= CISTPL_MAX_CIS_SIZE) {
@@ -1130,8 +1131,6 @@ static int runtime_suspend(struct device *dev)
        down(&dev->sem);
        rc = pcmcia_dev_suspend(dev, PMSG_SUSPEND);
        up(&dev->sem);
-       if (!rc)
-               dev->power.power_state.event = PM_EVENT_SUSPEND;
        return rc;
 }
 
@@ -1142,8 +1141,6 @@ static void runtime_resume(struct device *dev)
        down(&dev->sem);
        rc = pcmcia_dev_resume(dev);
        up(&dev->sem);
-       if (!rc)
-               dev->power.power_state.event = PM_EVENT_ON;
 }
 
 /************************ per-device sysfs output ***************************/
@@ -1265,6 +1262,9 @@ static int pcmcia_dev_suspend(struct device * dev, pm_message_t state)
        struct pcmcia_driver *p_drv = NULL;
        int ret = 0;
 
+       if (p_dev->suspended)
+               return 0;
+
        ds_dbg(2, "suspending %s\n", dev->bus_id);
 
        if (dev->driver)
@@ -1301,6 +1301,9 @@ static int pcmcia_dev_resume(struct device * dev)
         struct pcmcia_driver *p_drv = NULL;
        int ret = 0;
 
+       if (!p_dev->suspended)
+               return 0;
+
        ds_dbg(2, "resuming %s\n", dev->bus_id);
 
        if (dev->driver)
index df21e2d16f87858632d6f8f44343eefcf8df6b8c..749515534cc0ea2c4394c32ae1af6c2724ffe898 100644 (file)
@@ -82,7 +82,7 @@ struct socket_info {
                                    1 = empty socket, 
                                    2 = card but not initialized,
                                    3 = operational card */
-       kio_addr_t io_base;     /* base io address of the socket */
+       unsigned int io_base;   /* base io address of the socket */
        
        struct pcmcia_socket socket;
        struct pci_dev *dev;    /* The PCI device for the socket */
index 839bb1c0db58c9af53211483cc735370217cd3d6..32a2ab119798ccfc2f18c1df52377b7da2009ad3 100644 (file)
@@ -164,7 +164,7 @@ struct i82365_socket {
     u_short            type, flags;
     struct pcmcia_socket       socket;
     unsigned int       number;
-    kio_addr_t         ioaddr;
+    unsigned int       ioaddr;
     u_short            psock;
     u_char             cs_irq, intr;
     union {
@@ -238,7 +238,7 @@ static u_char i365_get(u_short sock, u_short reg)
     unsigned long flags;
     spin_lock_irqsave(&bus_lock,flags);
     {
-       kio_addr_t port = socket[sock].ioaddr;
+       unsigned int port = socket[sock].ioaddr;
        u_char val;
        reg = I365_REG(socket[sock].psock, reg);
        outb(reg, port); val = inb(port+1);
@@ -252,7 +252,7 @@ static void i365_set(u_short sock, u_short reg, u_char data)
     unsigned long flags;
     spin_lock_irqsave(&bus_lock,flags);
     {
-       kio_addr_t port = socket[sock].ioaddr;
+       unsigned int port = socket[sock].ioaddr;
        u_char val = I365_REG(socket[sock].psock, reg);
        outb(val, port); outb(data, port+1);
        spin_unlock_irqrestore(&bus_lock,flags);
@@ -588,7 +588,7 @@ static int to_cycles(int ns)
 
 /*====================================================================*/
 
-static int __init identify(kio_addr_t port, u_short sock)
+static int __init identify(unsigned int port, u_short sock)
 {
     u_char val;
     int type = -1;
@@ -659,7 +659,7 @@ static int __init identify(kio_addr_t port, u_short sock)
 static int __init is_alive(u_short sock)
 {
     u_char stat;
-    kio_addr_t start, stop;
+    unsigned int start, stop;
     
     stat = i365_get(sock, I365_STATUS);
     start = i365_get_pair(sock, I365_IO(0)+I365_W_START);
@@ -678,7 +678,7 @@ static int __init is_alive(u_short sock)
 
 /*====================================================================*/
 
-static void __init add_socket(kio_addr_t port, int psock, int type)
+static void __init add_socket(unsigned int port, int psock, int type)
 {
     socket[sockets].ioaddr = port;
     socket[sockets].psock = psock;
@@ -698,7 +698,7 @@ static void __init add_pcic(int ns, int type)
     base = sockets-ns;
     if (base == 0) printk("\n");
     printk(KERN_INFO "  %s", pcic[type].name);
-    printk(" ISA-to-PCMCIA at port %#lx ofs 0x%02x",
+    printk(" ISA-to-PCMCIA at port %#x ofs 0x%02x",
               t->ioaddr, t->psock*0x40);
     printk(", %d socket%s\n", ns, ((ns > 1) ? "s" : ""));
 
@@ -772,7 +772,7 @@ static struct pnp_dev *i82365_pnpdev;
 static void __init isa_probe(void)
 {
     int i, j, sock, k, ns, id;
-    kio_addr_t port;
+    unsigned int port;
 #ifdef CONFIG_PNP
     struct isapnp_device_id *devid;
     struct pnp_dev *dev;
@@ -1053,7 +1053,7 @@ static int i365_set_io_map(u_short sock, struct pccard_io_map *io)
     u_char map, ioctl;
     
     debug(1, "SetIOMap(%d, %d, %#2.2x, %d ns, "
-         "%#lx-%#lx)\n", sock, io->map, io->flags,
+         "%#x-%#x)\n", sock, io->map, io->flags,
          io->speed, io->start, io->stop);
     map = io->map;
     if ((map > 1) || (io->start > 0xffff) || (io->stop > 0xffff) ||
index 91da15b5a81ea0e3df861a7923fae76b9538faea..3616da22715239ca658d0bd5816e01eb170d94f5 100644 (file)
@@ -58,7 +58,7 @@ typedef struct pcc_socket {
        u_short                 type, flags;
        struct pcmcia_socket    socket;
        unsigned int            number;
-       kio_addr_t              ioaddr;
+       unsigned int            ioaddr;
        u_long                  mapaddr;
        u_long                  base;   /* PCC register base */
        u_char                  cs_irq1, cs_irq2, intr;
@@ -298,7 +298,8 @@ static int __init is_alive(u_short sock)
        return 0;
 }
 
-static void add_pcc_socket(ulong base, int irq, ulong mapaddr, kio_addr_t ioaddr)
+static void add_pcc_socket(ulong base, int irq, ulong mapaddr,
+                          unsigned int ioaddr)
 {
        pcc_socket_t *t = &socket[pcc_sockets];
 
@@ -738,7 +739,7 @@ static int __init init_m32r_pcc(void)
 #else  /* CONFIG_PLAT_USRV */
        {
                ulong base, mapaddr;
-               kio_addr_t ioaddr;
+               unsigned int ioaddr;
 
                for (i = 0 ; i < M32R_MAX_PCC ; i++) {
                        base = (ulong)PLD_CFRSTCR;
index c5e0d89c3ecefecf09cc03e5558b4c0aff4ca315..2b42b7155e34a9571b89df20dd990bfb76b5ba46 100644 (file)
@@ -65,7 +65,7 @@ typedef struct pcc_socket {
        u_short                 type, flags;
        struct pcmcia_socket    socket;
        unsigned int            number;
-       kio_addr_t              ioaddr;
+       unsigned int            ioaddr;
        u_long                  mapaddr;
        u_long                  base;   /* PCC register base */
        u_char                  cs_irq, intr;
@@ -310,7 +310,8 @@ static int __init is_alive(u_short sock)
        return 0;
 }
 
-static void add_pcc_socket(ulong base, int irq, ulong mapaddr, kio_addr_t ioaddr)
+static void add_pcc_socket(ulong base, int irq, ulong mapaddr,
+                          unsigned int ioaddr)
 {
        pcc_socket_t *t = &socket[pcc_sockets];
 
@@ -368,7 +369,7 @@ static irqreturn_t pcc_interrupt(int irq, void *dev)
                        handled = 1;
                        irc = pcc_get(i, PCIRC);
                        irc >>=16;
-                       debug(2, "m32r-pcc:interrput: socket %d pcirc 0x%02x ", i, irc);
+                       debug(2, "m32r-pcc:interrupt: socket %d pcirc 0x%02x ", i, irc);
                        if (!irc)
                                continue;
 
@@ -491,7 +492,7 @@ static int _pcc_set_io_map(u_short sock, struct pccard_io_map *io)
        u_char map;
 
        debug(3, "m32r-pcc: SetIOMap(%d, %d, %#2.2x, %d ns, "
-                 "%#lx-%#lx)\n", sock, io->map, io->flags,
+                 "%#x-%#x)\n", sock, io->map, io->flags,
                  io->speed, io->start, io->stop);
        map = io->map;
 
index d182760f035b1e7f8fed9d516ec4d02bdf9baa0b..ac70d2cb7dd409764deb755e13e821d366702d5f 100644 (file)
@@ -851,7 +851,7 @@ static int m8xx_set_socket(struct pcmcia_socket *sock, socket_state_t * state)
           I tried to control the CxOE signal with SS_OUTPUT_ENA,
           but the reset signal seems connected via the 541.
           If the CxOE is left high are some signals tristated and
-          no pullups are present -> the cards act wierd.
+          no pullups are present -> the cards act weird.
           So right now the buffers are enabled if the power is on. */
 
        if (state->Vcc || state->Vpp)
@@ -1174,8 +1174,10 @@ static int __init m8xx_probe(struct of_device *ofdev,
 
        pcmcia_schlvl = irq_of_parse_and_map(np, 0);
        hwirq = irq_map[pcmcia_schlvl].hwirq;
-       if (pcmcia_schlvl < 0)
+       if (pcmcia_schlvl < 0) {
+               iounmap(pcmcia);
                return -EINVAL;
+       }
 
        m8xx_pgcrx[0] = &pcmcia->pcmc_pgcra;
        m8xx_pgcrx[1] = &pcmcia->pcmc_pgcrb;
@@ -1189,6 +1191,7 @@ static int __init m8xx_probe(struct of_device *ofdev,
                        driver_name, socket)) {
                pcmcia_error("Cannot allocate IRQ %u for SCHLVL!\n",
                             pcmcia_schlvl);
+               iounmap(pcmcia);
                return -1;
        }
 
@@ -1284,6 +1287,7 @@ static int m8xx_remove(struct of_device *ofdev)
        }
        for (i = 0; i < PCMCIA_SOCKETS_NO; i++)
                pcmcia_unregister_socket(&socket[i].socket);
+       iounmap(pcmcia);
 
        free_irq(pcmcia_schlvl, NULL);
 
index 0ce39de834c477785a0b04ba580c80cffc4dd41e..1d128fbd1a92d9f4dcdaed4a3065c3365b5fce68 100644 (file)
@@ -65,23 +65,23 @@ extern int ds_pc_debug;
  * Special stuff for managing IO windows, because they are scarce
  */
 
-static int alloc_io_space(struct pcmcia_socket *s, u_int attr, ioaddr_t *base,
-                         ioaddr_t num, u_int lines)
+static int alloc_io_space(struct pcmcia_socket *s, u_int attr,
+                         unsigned int *base, unsigned int num, u_int lines)
 {
        int i;
-       kio_addr_t try, align;
+       unsigned int try, align;
 
        align = (*base) ? (lines ? 1<<lines : 0) : 1;
        if (align && (align < num)) {
                if (*base) {
-                       ds_dbg(s, 0, "odd IO request: num %#x align %#lx\n",
+                       ds_dbg(s, 0, "odd IO request: num %#x align %#x\n",
                               num, align);
                        align = 0;
                } else
                        while (align && (align < num)) align <<= 1;
        }
        if (*base & ~(align-1)) {
-               ds_dbg(s, 0, "odd IO request: base %#x align %#lx\n",
+               ds_dbg(s, 0, "odd IO request: base %#x align %#x\n",
                       *base, align);
                align = 0;
        }
@@ -132,8 +132,8 @@ static int alloc_io_space(struct pcmcia_socket *s, u_int attr, ioaddr_t *base,
 } /* alloc_io_space */
 
 
-static void release_io_space(struct pcmcia_socket *s, ioaddr_t base,
-                            ioaddr_t num)
+static void release_io_space(struct pcmcia_socket *s, unsigned int base,
+                            unsigned int num)
 {
        int i;
 
index bfcaad6021cf05dead89b7a63052b282f457158d..a8d1007077213c96cdc6fe02b7c75d7b198fcde3 100644 (file)
@@ -186,15 +186,16 @@ static int sub_interval(struct resource_map *map, u_long base, u_long num)
 ======================================================================*/
 
 #ifdef CONFIG_PCMCIA_PROBE
-static void do_io_probe(struct pcmcia_socket *s, kio_addr_t base, kio_addr_t num)
+static void do_io_probe(struct pcmcia_socket *s, unsigned int base,
+                       unsigned int num)
 {
     struct resource *res;
     struct socket_data *s_data = s->resource_data;
-    kio_addr_t i, j, bad;
+    unsigned int i, j, bad;
     int any;
     u_char *b, hole, most;
 
-    printk(KERN_INFO "cs: IO port probe %#lx-%#lx:",
+    printk(KERN_INFO "cs: IO port probe %#x-%#x:",
           base, base+num-1);
 
     /* First, what does a floating port look like? */
@@ -233,7 +234,7 @@ static void do_io_probe(struct pcmcia_socket *s, kio_addr_t base, kio_addr_t num
        } else {
            if (bad) {
                sub_interval(&s_data->io_db, bad, i-bad);
-               printk(" %#lx-%#lx", bad, i-1);
+               printk(" %#x-%#x", bad, i-1);
                bad = 0;
            }
        }
@@ -244,7 +245,7 @@ static void do_io_probe(struct pcmcia_socket *s, kio_addr_t base, kio_addr_t num
            return;
        } else {
            sub_interval(&s_data->io_db, bad, i-bad);
-           printk(" %#lx-%#lx", bad, i-1);
+           printk(" %#x-%#x", bad, i-1);
        }
     }
 
index af485ae386024fbf560d260b52a83db25e1a5b2f..6284c35dabc687f6ee1fc5afbf89bda6276ffd46 100644 (file)
@@ -101,7 +101,7 @@ static struct pcmcia_low_level jornada720_pcmcia_ops = {
   .socket_suspend      = sa1111_pcmcia_socket_suspend,
 };
 
-int __init pcmcia_jornada720_init(struct device *dev)
+int __devinit pcmcia_jornada720_init(struct device *dev)
 {
        int ret = -ENODEV;
 
index 749ac3710914e519c122284a4bd0f32670b990ee..5792bd5c54f93a4a3a3394d665145209b2f5c5e8 100644 (file)
@@ -719,7 +719,7 @@ static int tcic_set_io_map(struct pcmcia_socket *sock, struct pccard_io_map *io)
     u_short base, len, ioctl;
     
     debug(1, "SetIOMap(%d, %d, %#2.2x, %d ns, "
-         "%#lx-%#lx)\n", psock, io->map, io->flags,
+         "%#x-%#x)\n", psock, io->map, io->flags,
          io->speed, io->start, io->stop);
     if ((io->map > 1) || (io->start > 0xffff) || (io->stop > 0xffff) ||
        (io->stop < io->start)) return -EINVAL;
index 7e29b90a4f6377d51351828a8bf3daded4ad9d49..a4892275659dc02ffb1d12b85d0774a86bda8b08 100644 (file)
@@ -13,7 +13,7 @@
 #include <linux/power_supply.h>
 #include <linux/apm-emulation.h>
 
-static DEFINE_MUTEX(apm_mutex);
+
 #define PSY_PROP(psy, prop, val) psy->get_property(psy, \
                         POWER_SUPPLY_PROP_##prop, val)
 
@@ -22,8 +22,15 @@ static DEFINE_MUTEX(apm_mutex);
 
 #define MPSY_PROP(prop, val) _MPSY_PROP(POWER_SUPPLY_PROP_##prop, val)
 
+static DEFINE_MUTEX(apm_mutex);
 static struct power_supply *main_battery;
 
+enum apm_source {
+       SOURCE_ENERGY,
+       SOURCE_CHARGE,
+       SOURCE_VOLTAGE,
+};
+
 struct find_bat_param {
        struct power_supply *main;
        struct power_supply *bat;
@@ -107,7 +114,7 @@ static void find_main_battery(void)
        }
 }
 
-static int calculate_time(int status, int using_charge)
+static int do_calculate_time(int status, enum apm_source source)
 {
        union power_supply_propval full;
        union power_supply_propval empty;
@@ -126,20 +133,37 @@ static int calculate_time(int status, int using_charge)
                        return -1;
        }
 
-       if (using_charge) {
+       if (!I.intval)
+               return 0;
+
+       switch (source) {
+       case SOURCE_CHARGE:
                full_prop = POWER_SUPPLY_PROP_CHARGE_FULL;
                full_design_prop = POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN;
                empty_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY;
                empty_design_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY;
                cur_avg_prop = POWER_SUPPLY_PROP_CHARGE_AVG;
                cur_now_prop = POWER_SUPPLY_PROP_CHARGE_NOW;
-       } else {
+               break;
+       case SOURCE_ENERGY:
                full_prop = POWER_SUPPLY_PROP_ENERGY_FULL;
                full_design_prop = POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN;
                empty_prop = POWER_SUPPLY_PROP_ENERGY_EMPTY;
                empty_design_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY;
                cur_avg_prop = POWER_SUPPLY_PROP_ENERGY_AVG;
                cur_now_prop = POWER_SUPPLY_PROP_ENERGY_NOW;
+               break;
+       case SOURCE_VOLTAGE:
+               full_prop = POWER_SUPPLY_PROP_VOLTAGE_MAX;
+               full_design_prop = POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN;
+               empty_prop = POWER_SUPPLY_PROP_VOLTAGE_MIN;
+               empty_design_prop = POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN;
+               cur_avg_prop = POWER_SUPPLY_PROP_VOLTAGE_AVG;
+               cur_now_prop = POWER_SUPPLY_PROP_VOLTAGE_NOW;
+               break;
+       default:
+               printk(KERN_ERR "Unsupported source: %d\n", source);
+               return -1;
        }
 
        if (_MPSY_PROP(full_prop, &full)) {
@@ -166,7 +190,26 @@ static int calculate_time(int status, int using_charge)
                return -((cur.intval - empty.intval) * 60L) / I.intval;
 }
 
-static int calculate_capacity(int using_charge)
+static int calculate_time(int status)
+{
+       int time;
+
+       time = do_calculate_time(status, SOURCE_ENERGY);
+       if (time != -1)
+               return time;
+
+       time = do_calculate_time(status, SOURCE_CHARGE);
+       if (time != -1)
+               return time;
+
+       time = do_calculate_time(status, SOURCE_VOLTAGE);
+       if (time != -1)
+               return time;
+
+       return -1;
+}
+
+static int calculate_capacity(enum apm_source source)
 {
        enum power_supply_property full_prop, empty_prop;
        enum power_supply_property full_design_prop, empty_design_prop;
@@ -174,20 +217,33 @@ static int calculate_capacity(int using_charge)
        union power_supply_propval empty, full, cur;
        int ret;
 
-       if (using_charge) {
+       switch (source) {
+       case SOURCE_CHARGE:
                full_prop = POWER_SUPPLY_PROP_CHARGE_FULL;
                empty_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY;
                full_design_prop = POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN;
                empty_design_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY_DESIGN;
                now_prop = POWER_SUPPLY_PROP_CHARGE_NOW;
                avg_prop = POWER_SUPPLY_PROP_CHARGE_AVG;
-       } else {
+               break;
+       case SOURCE_ENERGY:
                full_prop = POWER_SUPPLY_PROP_ENERGY_FULL;
                empty_prop = POWER_SUPPLY_PROP_ENERGY_EMPTY;
                full_design_prop = POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN;
                empty_design_prop = POWER_SUPPLY_PROP_ENERGY_EMPTY_DESIGN;
                now_prop = POWER_SUPPLY_PROP_ENERGY_NOW;
                avg_prop = POWER_SUPPLY_PROP_ENERGY_AVG;
+       case SOURCE_VOLTAGE:
+               full_prop = POWER_SUPPLY_PROP_VOLTAGE_MAX;
+               empty_prop = POWER_SUPPLY_PROP_VOLTAGE_MIN;
+               full_design_prop = POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN;
+               empty_design_prop = POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN;
+               now_prop = POWER_SUPPLY_PROP_VOLTAGE_NOW;
+               avg_prop = POWER_SUPPLY_PROP_VOLTAGE_AVG;
+               break;
+       default:
+               printk(KERN_ERR "Unsupported source: %d\n", source);
+               return -1;
        }
 
        if (_MPSY_PROP(full_prop, &full)) {
@@ -254,10 +310,12 @@ static void apm_battery_apm_get_power_status(struct apm_power_info *info)
                info->battery_life = capacity.intval;
        } else {
                /* try calculate using energy */
-               info->battery_life = calculate_capacity(0);
+               info->battery_life = calculate_capacity(SOURCE_ENERGY);
                /* if failed try calculate using charge instead */
                if (info->battery_life == -1)
-                       info->battery_life = calculate_capacity(1);
+                       info->battery_life = calculate_capacity(SOURCE_CHARGE);
+               if (info->battery_life == -1)
+                       info->battery_life = calculate_capacity(SOURCE_VOLTAGE);
        }
 
        /* charging status */
@@ -280,22 +338,16 @@ static void apm_battery_apm_get_power_status(struct apm_power_info *info)
 
        if (status.intval == POWER_SUPPLY_STATUS_CHARGING) {
                if (!MPSY_PROP(TIME_TO_FULL_AVG, &time_to_full) ||
-                               !MPSY_PROP(TIME_TO_FULL_NOW, &time_to_full)) {
+                               !MPSY_PROP(TIME_TO_FULL_NOW, &time_to_full))
                        info->time = time_to_full.intval / 60;
-               } else {
-                       info->time = calculate_time(status.intval, 0);
-                       if (info->time == -1)
-                               info->time = calculate_time(status.intval, 1);
-               }
+               else
+                       info->time = calculate_time(status.intval);
        } else {
                if (!MPSY_PROP(TIME_TO_EMPTY_AVG, &time_to_empty) ||
-                             !MPSY_PROP(TIME_TO_EMPTY_NOW, &time_to_empty)) {
+                             !MPSY_PROP(TIME_TO_EMPTY_NOW, &time_to_empty))
                        info->time = time_to_empty.intval / 60;
-               } else {
-                       info->time = calculate_time(status.intval, 0);
-                       if (info->time == -1)
-                               info->time = calculate_time(status.intval, 1);
-               }
+               else
+                       info->time = calculate_time(status.intval);
        }
 
        mutex_unlock(&apm_mutex);
index c998e68d060f912ffe49b90edf482a1cc8640746..af7a231092a461052af4408f6e127901622e4f29 100644 (file)
@@ -226,14 +226,6 @@ static int olpc_bat_get_property(struct power_supply *psy,
                        return ret;
                val->intval = ec_byte;
                break;
-       case POWER_SUPPLY_PROP_CAPACITY_LEVEL:
-               if (ec_byte & BAT_STAT_FULL)
-                       val->intval = POWER_SUPPLY_CAPACITY_LEVEL_FULL;
-               else if (ec_byte & BAT_STAT_LOW)
-                       val->intval = POWER_SUPPLY_CAPACITY_LEVEL_LOW;
-               else
-                       val->intval = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
-               break;
        case POWER_SUPPLY_PROP_TEMP:
                ret = olpc_ec_cmd(EC_BAT_TEMP, NULL, 0, (void *)&ec_word, 2);
                if (ret)
@@ -265,7 +257,6 @@ static enum power_supply_property olpc_bat_props[] = {
        POWER_SUPPLY_PROP_VOLTAGE_AVG,
        POWER_SUPPLY_PROP_CURRENT_AVG,
        POWER_SUPPLY_PROP_CAPACITY,
-       POWER_SUPPLY_PROP_CAPACITY_LEVEL,
        POWER_SUPPLY_PROP_TEMP,
        POWER_SUPPLY_PROP_TEMP_AMBIENT,
        POWER_SUPPLY_PROP_MANUFACTURER,
index c058f285be1a2c8e850ebfec9b9db0a3d29ef017..c8aa55b81fd86458f7c5dbcdcbc486a81c8cb5a7 100644 (file)
@@ -32,6 +32,18 @@ static struct pda_power_pdata *pdata;
 static struct resource *ac_irq, *usb_irq;
 static struct timer_list charger_timer;
 static struct timer_list supply_timer;
+static struct timer_list polling_timer;
+static int polling;
+
+enum {
+       PDA_PSY_OFFLINE = 0,
+       PDA_PSY_ONLINE = 1,
+       PDA_PSY_TO_CHANGE,
+};
+static int new_ac_status = -1;
+static int new_usb_status = -1;
+static int ac_status = -1;
+static int usb_status = -1;
 
 static int pda_power_get_property(struct power_supply *psy,
                                  enum power_supply_property psp,
@@ -61,36 +73,44 @@ static char *pda_power_supplied_to[] = {
        "backup-battery",
 };
 
-static struct power_supply pda_power_supplies[] = {
-       {
-               .name = "ac",
-               .type = POWER_SUPPLY_TYPE_MAINS,
-               .supplied_to = pda_power_supplied_to,
-               .num_supplicants = ARRAY_SIZE(pda_power_supplied_to),
-               .properties = pda_power_props,
-               .num_properties = ARRAY_SIZE(pda_power_props),
-               .get_property = pda_power_get_property,
-       },
-       {
-               .name = "usb",
-               .type = POWER_SUPPLY_TYPE_USB,
-               .supplied_to = pda_power_supplied_to,
-               .num_supplicants = ARRAY_SIZE(pda_power_supplied_to),
-               .properties = pda_power_props,
-               .num_properties = ARRAY_SIZE(pda_power_props),
-               .get_property = pda_power_get_property,
-       },
+static struct power_supply pda_psy_ac = {
+       .name = "ac",
+       .type = POWER_SUPPLY_TYPE_MAINS,
+       .supplied_to = pda_power_supplied_to,
+       .num_supplicants = ARRAY_SIZE(pda_power_supplied_to),
+       .properties = pda_power_props,
+       .num_properties = ARRAY_SIZE(pda_power_props),
+       .get_property = pda_power_get_property,
 };
 
+static struct power_supply pda_psy_usb = {
+       .name = "usb",
+       .type = POWER_SUPPLY_TYPE_USB,
+       .supplied_to = pda_power_supplied_to,
+       .num_supplicants = ARRAY_SIZE(pda_power_supplied_to),
+       .properties = pda_power_props,
+       .num_properties = ARRAY_SIZE(pda_power_props),
+       .get_property = pda_power_get_property,
+};
+
+static void update_status(void)
+{
+       if (pdata->is_ac_online)
+               new_ac_status = !!pdata->is_ac_online();
+
+       if (pdata->is_usb_online)
+               new_usb_status = !!pdata->is_usb_online();
+}
+
 static void update_charger(void)
 {
        if (!pdata->set_charge)
                return;
 
-       if (pdata->is_ac_online && pdata->is_ac_online()) {
+       if (new_ac_status > 0) {
                dev_dbg(dev, "charger on (AC)\n");
                pdata->set_charge(PDA_POWER_CHARGE_AC);
-       } else if (pdata->is_usb_online && pdata->is_usb_online()) {
+       } else if (new_usb_status > 0) {
                dev_dbg(dev, "charger on (USB)\n");
                pdata->set_charge(PDA_POWER_CHARGE_USB);
        } else {
@@ -99,34 +119,81 @@ static void update_charger(void)
        }
 }
 
-static void supply_timer_func(unsigned long power_supply_ptr)
+static void supply_timer_func(unsigned long unused)
 {
-       void *power_supply = (void *)power_supply_ptr;
+       if (ac_status == PDA_PSY_TO_CHANGE) {
+               ac_status = new_ac_status;
+               power_supply_changed(&pda_psy_ac);
+       }
 
-       power_supply_changed(power_supply);
+       if (usb_status == PDA_PSY_TO_CHANGE) {
+               usb_status = new_usb_status;
+               power_supply_changed(&pda_psy_usb);
+       }
 }
 
-static void charger_timer_func(unsigned long power_supply_ptr)
+static void psy_changed(void)
 {
        update_charger();
 
-       /* Okay, charger set. Now wait a bit before notifying supplicants,
-        * charge power should stabilize. */
-       supply_timer.data = power_supply_ptr;
+       /*
+        * Okay, charger set. Now wait a bit before notifying supplicants,
+        * charge power should stabilize.
+        */
        mod_timer(&supply_timer,
                  jiffies + msecs_to_jiffies(pdata->wait_for_charger));
 }
 
+static void charger_timer_func(unsigned long unused)
+{
+       update_status();
+       psy_changed();
+}
+
 static irqreturn_t power_changed_isr(int irq, void *power_supply)
 {
-       /* Wait a bit before reading ac/usb line status and setting charger,
-        * because ac/usb status readings may lag from irq. */
-       charger_timer.data = (unsigned long)power_supply;
+       if (power_supply == &pda_psy_ac)
+               ac_status = PDA_PSY_TO_CHANGE;
+       else if (power_supply == &pda_psy_usb)
+               usb_status = PDA_PSY_TO_CHANGE;
+       else
+               return IRQ_NONE;
+
+       /*
+        * Wait a bit before reading ac/usb line status and setting charger,
+        * because ac/usb status readings may lag from irq.
+        */
        mod_timer(&charger_timer,
                  jiffies + msecs_to_jiffies(pdata->wait_for_status));
+
        return IRQ_HANDLED;
 }
 
+static void polling_timer_func(unsigned long unused)
+{
+       int changed = 0;
+
+       dev_dbg(dev, "polling...\n");
+
+       update_status();
+
+       if (!ac_irq && new_ac_status != ac_status) {
+               ac_status = PDA_PSY_TO_CHANGE;
+               changed = 1;
+       }
+
+       if (!usb_irq && new_usb_status != usb_status) {
+               usb_status = PDA_PSY_TO_CHANGE;
+               changed = 1;
+       }
+
+       if (changed)
+               psy_changed();
+
+       mod_timer(&polling_timer,
+                 jiffies + msecs_to_jiffies(pdata->polling_interval));
+}
+
 static int pda_power_probe(struct platform_device *pdev)
 {
        int ret = 0;
@@ -142,6 +209,7 @@ static int pda_power_probe(struct platform_device *pdev)
 
        pdata = pdev->dev.platform_data;
 
+       update_status();
        update_charger();
 
        if (!pdata->wait_for_status)
@@ -150,86 +218,138 @@ static int pda_power_probe(struct platform_device *pdev)
        if (!pdata->wait_for_charger)
                pdata->wait_for_charger = 500;
 
+       if (!pdata->polling_interval)
+               pdata->polling_interval = 2000;
+
        setup_timer(&charger_timer, charger_timer_func, 0);
        setup_timer(&supply_timer, supply_timer_func, 0);
 
        ac_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "ac");
        usb_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "usb");
-       if (!ac_irq && !usb_irq) {
-               dev_err(dev, "no ac/usb irq specified\n");
-               ret = -ENODEV;
-               goto noirqs;
-       }
 
        if (pdata->supplied_to) {
-               pda_power_supplies[0].supplied_to = pdata->supplied_to;
-               pda_power_supplies[1].supplied_to = pdata->supplied_to;
-               pda_power_supplies[0].num_supplicants = pdata->num_supplicants;
-               pda_power_supplies[1].num_supplicants = pdata->num_supplicants;
+               pda_psy_ac.supplied_to = pdata->supplied_to;
+               pda_psy_ac.num_supplicants = pdata->num_supplicants;
+               pda_psy_usb.supplied_to = pdata->supplied_to;
+               pda_psy_usb.num_supplicants = pdata->num_supplicants;
        }
 
-       ret = power_supply_register(&pdev->dev, &pda_power_supplies[0]);
-       if (ret) {
-               dev_err(dev, "failed to register %s power supply\n",
-                       pda_power_supplies[0].name);
-               goto supply0_failed;
-       }
+       if (pdata->is_ac_online) {
+               ret = power_supply_register(&pdev->dev, &pda_psy_ac);
+               if (ret) {
+                       dev_err(dev, "failed to register %s power supply\n",
+                               pda_psy_ac.name);
+                       goto ac_supply_failed;
+               }
 
-       ret = power_supply_register(&pdev->dev, &pda_power_supplies[1]);
-       if (ret) {
-               dev_err(dev, "failed to register %s power supply\n",
-                       pda_power_supplies[1].name);
-               goto supply1_failed;
+               if (ac_irq) {
+                       ret = request_irq(ac_irq->start, power_changed_isr,
+                                         get_irq_flags(ac_irq), ac_irq->name,
+                                         &pda_psy_ac);
+                       if (ret) {
+                               dev_err(dev, "request ac irq failed\n");
+                               goto ac_irq_failed;
+                       }
+               } else {
+                       polling = 1;
+               }
        }
 
-       if (ac_irq) {
-               ret = request_irq(ac_irq->start, power_changed_isr,
-                                 get_irq_flags(ac_irq), ac_irq->name,
-                                 &pda_power_supplies[0]);
+       if (pdata->is_usb_online) {
+               ret = power_supply_register(&pdev->dev, &pda_psy_usb);
                if (ret) {
-                       dev_err(dev, "request ac irq failed\n");
-                       goto ac_irq_failed;
+                       dev_err(dev, "failed to register %s power supply\n",
+                               pda_psy_usb.name);
+                       goto usb_supply_failed;
                }
-       }
 
-       if (usb_irq) {
-               ret = request_irq(usb_irq->start, power_changed_isr,
-                                 get_irq_flags(usb_irq), usb_irq->name,
-                                 &pda_power_supplies[1]);
-               if (ret) {
-                       dev_err(dev, "request usb irq failed\n");
-                       goto usb_irq_failed;
+               if (usb_irq) {
+                       ret = request_irq(usb_irq->start, power_changed_isr,
+                                         get_irq_flags(usb_irq),
+                                         usb_irq->name, &pda_psy_usb);
+                       if (ret) {
+                               dev_err(dev, "request usb irq failed\n");
+                               goto usb_irq_failed;
+                       }
+               } else {
+                       polling = 1;
                }
        }
 
-       goto success;
+       if (polling) {
+               dev_dbg(dev, "will poll for status\n");
+               setup_timer(&polling_timer, polling_timer_func, 0);
+               mod_timer(&polling_timer,
+                         jiffies + msecs_to_jiffies(pdata->polling_interval));
+       }
+
+       if (ac_irq || usb_irq)
+               device_init_wakeup(&pdev->dev, 1);
+
+       return 0;
 
 usb_irq_failed:
-       if (ac_irq)
-               free_irq(ac_irq->start, &pda_power_supplies[0]);
+       if (pdata->is_usb_online)
+               power_supply_unregister(&pda_psy_usb);
+usb_supply_failed:
+       if (pdata->is_ac_online && ac_irq)
+               free_irq(ac_irq->start, &pda_psy_ac);
 ac_irq_failed:
-       power_supply_unregister(&pda_power_supplies[1]);
-supply1_failed:
-       power_supply_unregister(&pda_power_supplies[0]);
-supply0_failed:
-noirqs:
+       if (pdata->is_ac_online)
+               power_supply_unregister(&pda_psy_ac);
+ac_supply_failed:
 wrongid:
-success:
        return ret;
 }
 
 static int pda_power_remove(struct platform_device *pdev)
 {
-       if (usb_irq)
-               free_irq(usb_irq->start, &pda_power_supplies[1]);
-       if (ac_irq)
-               free_irq(ac_irq->start, &pda_power_supplies[0]);
+       if (pdata->is_usb_online && usb_irq)
+               free_irq(usb_irq->start, &pda_psy_usb);
+       if (pdata->is_ac_online && ac_irq)
+               free_irq(ac_irq->start, &pda_psy_ac);
+
+       if (polling)
+               del_timer_sync(&polling_timer);
        del_timer_sync(&charger_timer);
        del_timer_sync(&supply_timer);
-       power_supply_unregister(&pda_power_supplies[1]);
-       power_supply_unregister(&pda_power_supplies[0]);
+
+       if (pdata->is_usb_online)
+               power_supply_unregister(&pda_psy_usb);
+       if (pdata->is_ac_online)
+               power_supply_unregister(&pda_psy_ac);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int pda_power_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       if (device_may_wakeup(&pdev->dev)) {
+               if (ac_irq)
+                       enable_irq_wake(ac_irq->start);
+               if (usb_irq)
+                       enable_irq_wake(usb_irq->start);
+       }
+
+       return 0;
+}
+
+static int pda_power_resume(struct platform_device *pdev)
+{
+       if (device_may_wakeup(&pdev->dev)) {
+               if (usb_irq)
+                       disable_irq_wake(usb_irq->start);
+               if (ac_irq)
+                       disable_irq_wake(ac_irq->start);
+       }
+
        return 0;
 }
+#else
+#define pda_power_suspend NULL
+#define pda_power_resume NULL
+#endif /* CONFIG_PM */
 
 static struct platform_driver pda_power_pdrv = {
        .driver = {
@@ -237,6 +357,8 @@ static struct platform_driver pda_power_pdrv = {
        },
        .probe = pda_power_probe,
        .remove = pda_power_remove,
+       .suspend = pda_power_suspend,
+       .resume = pda_power_resume,
 };
 
 static int __init pda_power_init(void)
index 7f8f3590b02e6934e6066e5d63bb40a6f7440af9..fa3034f85c382d4a3dc3b5bdb6ed36469c46042a 100644 (file)
  *  You may use this code as per GPL version 2
  */
 
+#include <linux/kernel.h>
 #include <linux/power_supply.h>
 
+#include "power_supply.h"
+
 /* Battery specific LEDs triggers. */
 
 static void power_supply_update_bat_leds(struct power_supply *psy)
@@ -46,28 +49,20 @@ static int power_supply_create_bat_triggers(struct power_supply *psy)
 {
        int rc = 0;
 
-       psy->charging_full_trig_name = kmalloc(strlen(psy->name) +
-                                 sizeof("-charging-or-full"), GFP_KERNEL);
+       psy->charging_full_trig_name = kasprintf(GFP_KERNEL,
+                                       "%s-charging-or-full", psy->name);
        if (!psy->charging_full_trig_name)
                goto charging_full_failed;
 
-       psy->charging_trig_name = kmalloc(strlen(psy->name) +
-                                         sizeof("-charging"), GFP_KERNEL);
+       psy->charging_trig_name = kasprintf(GFP_KERNEL,
+                                       "%s-charging", psy->name);
        if (!psy->charging_trig_name)
                goto charging_failed;
 
-       psy->full_trig_name = kmalloc(strlen(psy->name) +
-                                     sizeof("-full"), GFP_KERNEL);
+       psy->full_trig_name = kasprintf(GFP_KERNEL, "%s-full", psy->name);
        if (!psy->full_trig_name)
                goto full_failed;
 
-       strcpy(psy->charging_full_trig_name, psy->name);
-       strcat(psy->charging_full_trig_name, "-charging-or-full");
-       strcpy(psy->charging_trig_name, psy->name);
-       strcat(psy->charging_trig_name, "-charging");
-       strcpy(psy->full_trig_name, psy->name);
-       strcat(psy->full_trig_name, "-full");
-
        led_trigger_register_simple(psy->charging_full_trig_name,
                                    &psy->charging_full_trig);
        led_trigger_register_simple(psy->charging_trig_name,
@@ -118,14 +113,10 @@ static int power_supply_create_gen_triggers(struct power_supply *psy)
 {
        int rc = 0;
 
-       psy->online_trig_name = kmalloc(strlen(psy->name) + sizeof("-online"),
-                                       GFP_KERNEL);
+       psy->online_trig_name = kasprintf(GFP_KERNEL, "%s-online", psy->name);
        if (!psy->online_trig_name)
                goto online_failed;
 
-       strcpy(psy->online_trig_name, psy->name);
-       strcat(psy->online_trig_name, "-online");
-
        led_trigger_register_simple(psy->online_trig_name, &psy->online_trig);
 
        goto success;
index 249f61bae6396105b2466739c504dd2b6557b775..d4824840c5bfc9c8bb877399014e01305adf3862 100644 (file)
@@ -14,6 +14,8 @@
 #include <linux/ctype.h>
 #include <linux/power_supply.h>
 
+#include "power_supply.h"
+
 /*
  * This is because the name "current" breaks the device attr macro.
  * The "current" word resolves to "(get_current())" so instead of
@@ -46,10 +48,8 @@ static ssize_t power_supply_show_property(struct device *dev,
                "Unspecified failure"
        };
        static char *technology_text[] = {
-               "Unknown", "NiMH", "Li-ion", "Li-poly", "LiFe", "NiCd"
-       };
-       static char *capacity_level_text[] = {
-               "Unknown", "Critical", "Low", "Normal", "High", "Full"
+               "Unknown", "NiMH", "Li-ion", "Li-poly", "LiFe", "NiCd",
+               "LiMn"
        };
        ssize_t ret;
        struct power_supply *psy = dev_get_drvdata(dev);
@@ -71,9 +71,6 @@ static ssize_t power_supply_show_property(struct device *dev,
                return sprintf(buf, "%s\n", health_text[value.intval]);
        else if (off == POWER_SUPPLY_PROP_TECHNOLOGY)
                return sprintf(buf, "%s\n", technology_text[value.intval]);
-       else if (off == POWER_SUPPLY_PROP_CAPACITY_LEVEL)
-               return sprintf(buf, "%s\n",
-                              capacity_level_text[value.intval]);
        else if (off >= POWER_SUPPLY_PROP_MODEL_NAME)
                return sprintf(buf, "%s\n", value.strval);
 
@@ -88,6 +85,8 @@ static struct device_attribute power_supply_attrs[] = {
        POWER_SUPPLY_ATTR(present),
        POWER_SUPPLY_ATTR(online),
        POWER_SUPPLY_ATTR(technology),
+       POWER_SUPPLY_ATTR(voltage_max),
+       POWER_SUPPLY_ATTR(voltage_min),
        POWER_SUPPLY_ATTR(voltage_max_design),
        POWER_SUPPLY_ATTR(voltage_min_design),
        POWER_SUPPLY_ATTR(voltage_now),
@@ -159,8 +158,7 @@ dynamics_failed:
                           &power_supply_attrs[psy->properties[j]]);
 statics_failed:
        while (i--)
-               device_remove_file(psy->dev,
-                          &power_supply_static_attrs[psy->properties[i]]);
+               device_remove_file(psy->dev, &power_supply_static_attrs[i]);
 succeed:
        return rc;
 }
@@ -170,8 +168,7 @@ void power_supply_remove_attrs(struct power_supply *psy)
        int i;
 
        for (i = 0; i < ARRAY_SIZE(power_supply_static_attrs); i++)
-               device_remove_file(psy->dev,
-                           &power_supply_static_attrs[i]);
+               device_remove_file(psy->dev, &power_supply_static_attrs[i]);
 
        for (i = 0; i < psy->num_properties; i++)
                device_remove_file(psy->dev,
index d640427c74c816172b38cfae6bb2529f7b344e37..d984e0fae63054fe1c53a249534a85603ea8887d 100644 (file)
@@ -1057,12 +1057,11 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
                if (device->features & DASD_FEATURE_ERPLOG) {
                        dasd_log_sense(cqr, irb);
                }
-               /* If we have no sense data, or we just don't want complex ERP
-                * for this request, but if we have retries left, then just
-                * reset this request and retry it in the fastpath
+               /*
+                * If we don't want complex ERP for this request, then just
+                * reset this and retry it in the fastpath
                 */
-               if (!(cqr->irb.esw.esw0.erw.cons &&
-                     test_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags)) &&
+               if (!test_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags) &&
                    cqr->retries > 0) {
                        DEV_MESSAGE(KERN_DEBUG, device,
                                    "default ERP in fastpath (%i retries left)",
@@ -1707,7 +1706,7 @@ static void __dasd_cleanup_cqr(struct dasd_ccw_req *cqr)
 
        req = (struct request *) cqr->callback_data;
        dasd_profile_end(cqr->block, cqr, req);
-       status = cqr->memdev->discipline->free_cp(cqr, req);
+       status = cqr->block->base->discipline->free_cp(cqr, req);
        if (status <= 0)
                error = status ? status : -EIO;
        dasd_end_request(req, error);
@@ -1742,12 +1741,8 @@ restart:
 
                /*  Process requests that may be recovered */
                if (cqr->status == DASD_CQR_NEED_ERP) {
-                       if (cqr->irb.esw.esw0.erw.cons &&
-                           test_bit(DASD_CQR_FLAGS_USE_ERP,
-                                    &cqr->flags)) {
-                               erp_fn = base->discipline->erp_action(cqr);
-                               erp_fn(cqr);
-                       }
+                       erp_fn = base->discipline->erp_action(cqr);
+                       erp_fn(cqr);
                        goto restart;
                }
 
index c361ab69ec0023c3eae201d50b4d10a2acb6b595..f69714a0e9e7bf3ed750e3b497ce429d2f459ffb 100644 (file)
@@ -164,7 +164,7 @@ dasd_3990_erp_alternate_path(struct dasd_ccw_req * erp)
 
                /* reset status to submit the request again... */
                erp->status = DASD_CQR_FILLED;
-               erp->retries = 1;
+               erp->retries = 10;
        } else {
                DEV_MESSAGE(KERN_ERR, device,
                            "No alternate channel path left (lpum=%x / "
@@ -301,8 +301,7 @@ dasd_3990_erp_action_4(struct dasd_ccw_req * erp, char *sense)
                erp->function = dasd_3990_erp_action_4;
 
        } else {
-
-               if (sense[25] == 0x1D) {        /* state change pending */
+               if (sense && (sense[25] == 0x1D)) { /* state change pending */
 
                        DEV_MESSAGE(KERN_INFO, device,
                                    "waiting for state change pending "
@@ -311,7 +310,7 @@ dasd_3990_erp_action_4(struct dasd_ccw_req * erp, char *sense)
 
                        dasd_3990_erp_block_queue(erp, 30*HZ);
 
-                } else if (sense[25] == 0x1E) {        /* busy */
+               } else if (sense && (sense[25] == 0x1E)) {      /* busy */
                        DEV_MESSAGE(KERN_INFO, device,
                                    "busy - redriving request later, "
                                    "%d retries left",
@@ -2119,6 +2118,34 @@ dasd_3990_erp_inspect_32(struct dasd_ccw_req * erp, char *sense)
  *****************************************************************************
  */
 
+/*
+ * DASD_3990_ERP_CONTROL_CHECK
+ *
+ * DESCRIPTION
+ *   Does a generic inspection if a control check occured and sets up
+ *   the related error recovery procedure
+ *
+ * PARAMETER
+ *   erp               pointer to the currently created default ERP
+ *
+ * RETURN VALUES
+ *   erp_filled                pointer to the erp
+ */
+
+static struct dasd_ccw_req *
+dasd_3990_erp_control_check(struct dasd_ccw_req *erp)
+{
+       struct dasd_device *device = erp->startdev;
+
+       if (erp->refers->irb.scsw.cstat & (SCHN_STAT_INTF_CTRL_CHK
+                                          | SCHN_STAT_CHN_CTRL_CHK)) {
+               DEV_MESSAGE(KERN_DEBUG, device, "%s",
+                           "channel or interface control check");
+               erp = dasd_3990_erp_action_4(erp, NULL);
+       }
+       return erp;
+}
+
 /*
  * DASD_3990_ERP_INSPECT
  *
@@ -2145,8 +2172,11 @@ dasd_3990_erp_inspect(struct dasd_ccw_req * erp)
        if (erp_new)
                return erp_new;
 
+       /* check if no concurrent sens is available */
+       if (!erp->refers->irb.esw.esw0.erw.cons)
+               erp_new = dasd_3990_erp_control_check(erp);
        /* distinguish between 24 and 32 byte sense data */
-       if (sense[27] & DASD_SENSE_BIT_0) {
+       else if (sense[27] & DASD_SENSE_BIT_0) {
 
                /* inspect the 24 byte sense data */
                erp_new = dasd_3990_erp_inspect_24(erp, sense);
@@ -2285,6 +2315,17 @@ dasd_3990_erp_error_match(struct dasd_ccw_req *cqr1, struct dasd_ccw_req *cqr2)
                //      return 0;       /* CCW doesn't match */
        }
 
+       if (cqr1->irb.esw.esw0.erw.cons != cqr2->irb.esw.esw0.erw.cons)
+               return 0;
+
+       if ((cqr1->irb.esw.esw0.erw.cons == 0) &&
+           (cqr2->irb.esw.esw0.erw.cons == 0)) {
+               if ((cqr1->irb.scsw.cstat & (SCHN_STAT_INTF_CTRL_CHK |
+                                            SCHN_STAT_CHN_CTRL_CHK)) ==
+                   (cqr2->irb.scsw.cstat & (SCHN_STAT_INTF_CTRL_CHK |
+                                            SCHN_STAT_CHN_CTRL_CHK)))
+                       return 1; /* match with ifcc*/
+       }
        /* check sense data; byte 0-2,25,27 */
        if (!((memcmp (cqr1->irb.ecw, cqr2->irb.ecw, 3) == 0) &&
              (cqr1->irb.ecw[27] == cqr2->irb.ecw[27]) &&
@@ -2560,17 +2601,6 @@ dasd_3990_erp_action(struct dasd_ccw_req * cqr)
 
                return cqr;
        }
-       /* check if sense data are available */
-       if (!cqr->irb.ecw) {
-               DEV_MESSAGE(KERN_DEBUG, device,
-                           "ERP called witout sense data avail ..."
-                           "request %p - NO ERP possible", cqr);
-
-               cqr->status = DASD_CQR_FAILED;
-
-               return cqr;
-
-       }
 
        /* check if error happened before */
        erp = dasd_3990_erp_in_erp(cqr);
index 7779bfce1c3181518f2f11debd7a70081be40753..3faf0538b328d8b029357c7aa15cd0d397e3a78e 100644 (file)
@@ -415,6 +415,8 @@ dcssblk_add_store(struct device *dev, struct device_attribute *attr, const char
        dev_info->gd->queue = dev_info->dcssblk_queue;
        dev_info->gd->private_data = dev_info;
        dev_info->gd->driverfs_dev = &dev_info->dev;
+       blk_queue_make_request(dev_info->dcssblk_queue, dcssblk_make_request);
+       blk_queue_hardsect_size(dev_info->dcssblk_queue, 4096);
        /*
         * load the segment
         */
@@ -472,9 +474,6 @@ dcssblk_add_store(struct device *dev, struct device_attribute *attr, const char
        if (rc)
                goto unregister_dev;
 
-       blk_queue_make_request(dev_info->dcssblk_queue, dcssblk_make_request);
-       blk_queue_hardsect_size(dev_info->dcssblk_queue, 4096);
-
        add_disk(dev_info->gd);
 
        switch (dev_info->segment_type) {
index e3b3d390b4a3b2294f23428c6e5b70b688298f23..2e616e33891d9816cbda04295eff5b5ec0d963d9 100644 (file)
@@ -332,7 +332,7 @@ sclp_tty_write_string(const unsigned char *str, int count)
                if (sclp_ttybuf == NULL) {
                        while (list_empty(&sclp_tty_pages)) {
                                spin_unlock_irqrestore(&sclp_tty_lock, flags);
-                               if (in_interrupt())
+                               if (in_atomic())
                                        sclp_sync_wait();
                                else
                                        wait_event(sclp_tty_waitq,
index 40cd21bc5cc4dc936191b3b68e1e9febc4c62710..68071622d4bb13bf768ef2494dd040f2972508d7 100644 (file)
@@ -400,7 +400,7 @@ __sclp_vt220_write(const unsigned char *buf, int count, int do_schedule,
                        while (list_empty(&sclp_vt220_empty)) {
                                spin_unlock_irqrestore(&sclp_vt220_lock,
                                                       flags);
-                               if (in_interrupt())
+                               if (in_atomic())
                                        sclp_sync_wait();
                                else
                                        wait_event(sclp_vt220_waitq,
index 3964056a9a4745f05b607c86a1a837eaa961c0eb..03914fa811740084be75306421803bd74285f6e2 100644 (file)
@@ -391,12 +391,24 @@ ccwgroup_remove (struct device *dev)
        return 0;
 }
 
+static void ccwgroup_shutdown(struct device *dev)
+{
+       struct ccwgroup_device *gdev;
+       struct ccwgroup_driver *gdrv;
+
+       gdev = to_ccwgroupdev(dev);
+       gdrv = to_ccwgroupdrv(dev->driver);
+       if (gdrv && gdrv->shutdown)
+               gdrv->shutdown(gdev);
+}
+
 static struct bus_type ccwgroup_bus_type = {
        .name   = "ccwgroup",
        .match  = ccwgroup_bus_match,
        .uevent = ccwgroup_uevent,
        .probe  = ccwgroup_probe,
        .remove = ccwgroup_remove,
+       .shutdown = ccwgroup_shutdown,
 };
 
 /**
index e7ba16a74ef7bf49cb4b19c5cb91b9b5a8cc12d5..007aaeb4f53214533f7dc8c6b8bca62922d28442 100644 (file)
 
 static void *sei_page;
 
+static int chsc_error_from_response(int response)
+{
+       switch (response) {
+       case 0x0001:
+               return 0;
+       case 0x0002:
+       case 0x0003:
+       case 0x0006:
+       case 0x0007:
+       case 0x0008:
+       case 0x000a:
+               return -EINVAL;
+       case 0x0004:
+               return -EOPNOTSUPP;
+       default:
+               return -EIO;
+       }
+}
+
 struct chsc_ssd_area {
        struct chsc_header request;
        u16 :10;
@@ -75,11 +94,11 @@ int chsc_get_ssd_info(struct subchannel_id schid, struct chsc_ssd_info *ssd)
                ret = (ccode == 3) ? -ENODEV : -EBUSY;
                goto out_free;
        }
-       if (ssd_area->response.code != 0x0001) {
+       ret = chsc_error_from_response(ssd_area->response.code);
+       if (ret != 0) {
                CIO_MSG_EVENT(2, "chsc: ssd failed for 0.%x.%04x (rc=%04x)\n",
                              schid.ssid, schid.sch_no,
                              ssd_area->response.code);
-               ret = -EIO;
                goto out_free;
        }
        if (!ssd_area->sch_valid) {
@@ -717,36 +736,15 @@ __chsc_do_secm(struct channel_subsystem *css, int enable, void *page)
                return (ccode == 3) ? -ENODEV : -EBUSY;
 
        switch (secm_area->response.code) {
-       case 0x0001: /* Success. */
-               ret = 0;
-               break;
-       case 0x0003: /* Invalid block. */
-       case 0x0007: /* Invalid format. */
-       case 0x0008: /* Other invalid block. */
-               CIO_CRW_EVENT(2, "Error in chsc request block!\n");
-               ret = -EINVAL;
-               break;
-       case 0x0004: /* Command not provided in model. */
-               CIO_CRW_EVENT(2, "Model does not provide secm\n");
-               ret = -EOPNOTSUPP;
-               break;
-       case 0x0102: /* cub adresses incorrect */
-               CIO_CRW_EVENT(2, "Invalid addresses in chsc request block\n");
-               ret = -EINVAL;
-               break;
-       case 0x0103: /* key error */
-               CIO_CRW_EVENT(2, "Access key error in secm\n");
+       case 0x0102:
+       case 0x0103:
                ret = -EINVAL;
-               break;
-       case 0x0105: /* error while starting */
-               CIO_CRW_EVENT(2, "Error while starting channel measurement\n");
-               ret = -EIO;
-               break;
        default:
-               CIO_CRW_EVENT(2, "Unknown CHSC response %d\n",
-                             secm_area->response.code);
-               ret = -EIO;
+               ret = chsc_error_from_response(secm_area->response.code);
        }
+       if (ret != 0)
+               CIO_CRW_EVENT(2, "chsc: secm failed (rc=%04x)\n",
+                             secm_area->response.code);
        return ret;
 }
 
@@ -827,27 +825,14 @@ int chsc_determine_channel_path_description(struct chp_id chpid,
                goto out;
        }
 
-       switch (scpd_area->response.code) {
-       case 0x0001: /* Success. */
+       ret = chsc_error_from_response(scpd_area->response.code);
+       if (ret == 0)
+               /* Success. */
                memcpy(desc, &scpd_area->desc,
                       sizeof(struct channel_path_desc));
-               ret = 0;
-               break;
-       case 0x0003: /* Invalid block. */
-       case 0x0007: /* Invalid format. */
-       case 0x0008: /* Other invalid block. */
-               CIO_CRW_EVENT(2, "Error in chsc request block!\n");
-               ret = -EINVAL;
-               break;
-       case 0x0004: /* Command not provided in model. */
-               CIO_CRW_EVENT(2, "Model does not provide scpd\n");
-               ret = -EOPNOTSUPP;
-               break;
-       default:
-               CIO_CRW_EVENT(2, "Unknown CHSC response %d\n",
+       else
+               CIO_CRW_EVENT(2, "chsc: scpd failed (rc=%04x)\n",
                              scpd_area->response.code);
-               ret = -EIO;
-       }
 out:
        free_page((unsigned long)scpd_area);
        return ret;
@@ -923,8 +908,9 @@ int chsc_get_channel_measurement_chars(struct channel_path *chp)
                goto out;
        }
 
-       switch (scmc_area->response.code) {
-       case 0x0001: /* Success. */
+       ret = chsc_error_from_response(scmc_area->response.code);
+       if (ret == 0) {
+               /* Success. */
                if (!scmc_area->not_valid) {
                        chp->cmg = scmc_area->cmg;
                        chp->shared = scmc_area->shared;
@@ -935,22 +921,9 @@ int chsc_get_channel_measurement_chars(struct channel_path *chp)
                        chp->cmg = -1;
                        chp->shared = -1;
                }
-               ret = 0;
-               break;
-       case 0x0003: /* Invalid block. */
-       case 0x0007: /* Invalid format. */
-       case 0x0008: /* Invalid bit combination. */
-               CIO_CRW_EVENT(2, "Error in chsc request block!\n");
-               ret = -EINVAL;
-               break;
-       case 0x0004: /* Command not provided. */
-               CIO_CRW_EVENT(2, "Model does not provide scmc\n");
-               ret = -EOPNOTSUPP;
-               break;
-       default:
-               CIO_CRW_EVENT(2, "Unknown CHSC response %d\n",
+       } else {
+               CIO_CRW_EVENT(2, "chsc: scmc failed (rc=%04x)\n",
                              scmc_area->response.code);
-               ret = -EIO;
        }
 out:
        free_page((unsigned long)scmc_area);
@@ -1002,21 +975,17 @@ chsc_enable_facility(int operation_code)
                ret = (ret == 3) ? -ENODEV : -EBUSY;
                goto out;
        }
+
        switch (sda_area->response.code) {
-       case 0x0001: /* everything ok */
-               ret = 0;
-               break;
-       case 0x0003: /* invalid request block */
-       case 0x0007:
-               ret = -EINVAL;
-               break;
-       case 0x0004: /* command not provided */
-       case 0x0101: /* facility not provided */
+       case 0x0101:
                ret = -EOPNOTSUPP;
                break;
-       default: /* something went wrong */
-               ret = -EIO;
+       default:
+               ret = chsc_error_from_response(sda_area->response.code);
        }
+       if (ret != 0)
+               CIO_CRW_EVENT(2, "chsc: sda (oc=%x) failed (rc=%04x)\n",
+                             operation_code, sda_area->response.code);
  out:
        free_page((unsigned long)sda_area);
        return ret;
@@ -1041,33 +1010,27 @@ chsc_determine_css_characteristics(void)
        } __attribute__ ((packed)) *scsc_area;
 
        scsc_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
-       if (!scsc_area) {
-               CIO_MSG_EVENT(0, "Was not able to determine available "
-                             "CHSCs due to no memory.\n");
+       if (!scsc_area)
                return -ENOMEM;
-       }
 
        scsc_area->request.length = 0x0010;
        scsc_area->request.code = 0x0010;
 
        result = chsc(scsc_area);
        if (result) {
-               CIO_MSG_EVENT(0, "Was not able to determine available CHSCs, "
-                             "cc=%i.\n", result);
-               result = -EIO;
+               result = (result == 3) ? -ENODEV : -EBUSY;
                goto exit;
        }
 
-       if (scsc_area->response.code != 1) {
-               CIO_MSG_EVENT(0, "Was not able to determine "
-                             "available CHSCs.\n");
-               result = -EIO;
-               goto exit;
-       }
-       memcpy(&css_general_characteristics, scsc_area->general_char,
-              sizeof(css_general_characteristics));
-       memcpy(&css_chsc_characteristics, scsc_area->chsc_char,
-              sizeof(css_chsc_characteristics));
+       result = chsc_error_from_response(scsc_area->response.code);
+       if (result == 0) {
+               memcpy(&css_general_characteristics, scsc_area->general_char,
+                      sizeof(css_general_characteristics));
+               memcpy(&css_chsc_characteristics, scsc_area->chsc_char,
+                      sizeof(css_chsc_characteristics));
+       } else
+               CIO_CRW_EVENT(2, "chsc: scsc failed (rc=%04x)\n",
+                             scsc_area->response.code);
 exit:
        free_page ((unsigned long) scsc_area);
        return result;
index 918b8b89cf9a26c3fef86b8cd6d6f9d04a17b851..dc4d87f77f6c4bbb45dd1e15fe9582c5cf3f474f 100644 (file)
 #include "ioasm.h"
 #include "io_sch.h"
 
-/*
- * Input :
- *   devno - device number
- *   ps           - pointer to sense ID data area
- * Output : none
+/**
+ * vm_vdev_to_cu_type - Convert vm virtual device into control unit type
+ *                     for certain devices.
+ * @class: virtual device class
+ * @type: virtual device type
+ *
+ * Returns control unit type if a match was made or %0xffff otherwise.
  */
-static void
-VM_virtual_device_info (__u16 devno, struct senseid *ps)
+static int vm_vdev_to_cu_type(int class, int type)
 {
        static struct {
-               int vrdcvcla, vrdcvtyp, cu_type;
+               int class, type, cu_type;
        } vm_devices[] = {
                { 0x08, 0x01, 0x3480 },
                { 0x08, 0x02, 0x3430 },
@@ -68,8 +69,26 @@ VM_virtual_device_info (__u16 devno, struct senseid *ps)
                { 0x40, 0xc0, 0x5080 },
                { 0x80, 0x00, 0x3215 },
        };
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(vm_devices); i++)
+               if (class == vm_devices[i].class && type == vm_devices[i].type)
+                       return vm_devices[i].cu_type;
+
+       return 0xffff;
+}
+
+/**
+ * diag_get_dev_info - retrieve device information via DIAG X'210'
+ * @devno: device number
+ * @ps: pointer to sense ID data area
+ *
+ * Returns zero on success, non-zero otherwise.
+ */
+static int diag_get_dev_info(u16 devno, struct senseid *ps)
+{
        struct diag210 diag_data;
-       int ccode, i;
+       int ccode;
 
        CIO_TRACE_EVENT (4, "VMvdinf");
 
@@ -79,21 +98,21 @@ VM_virtual_device_info (__u16 devno, struct senseid *ps)
        };
 
        ccode = diag210 (&diag_data);
-       ps->reserved = 0xff;
+       if ((ccode == 0) || (ccode == 2)) {
+               ps->reserved = 0xff;
 
-       /* Special case for bloody osa devices. */
-       if (diag_data.vrdcvcla == 0x02 &&
-           diag_data.vrdcvtyp == 0x20) {
-               ps->cu_type = 0x3088;
-               ps->cu_model = 0x60;
-               return;
-       }
-       for (i = 0; i < ARRAY_SIZE(vm_devices); i++)
-               if (diag_data.vrdcvcla == vm_devices[i].vrdcvcla &&
-                   diag_data.vrdcvtyp == vm_devices[i].vrdcvtyp) {
-                       ps->cu_type = vm_devices[i].cu_type;
-                       return;
+               /* Special case for osa devices. */
+               if (diag_data.vrdcvcla == 0x02 && diag_data.vrdcvtyp == 0x20) {
+                       ps->cu_type = 0x3088;
+                       ps->cu_model = 0x60;
+                       return 0;
                }
+               ps->cu_type = vm_vdev_to_cu_type(diag_data.vrdcvcla,
+                                               diag_data.vrdcvtyp);
+               if (ps->cu_type != 0xffff)
+                       return 0;
+       }
+
        CIO_MSG_EVENT(0, "DIAG X'210' for device %04X returned (cc = %d):"
                      "vdev class : %02X, vdev type : %04X \n ...  "
                      "rdev class : %02X, rdev type : %04X, "
@@ -102,6 +121,8 @@ VM_virtual_device_info (__u16 devno, struct senseid *ps)
                      diag_data.vrdcvcla, diag_data.vrdcvtyp,
                      diag_data.vrdcrccl, diag_data.vrdccrty,
                      diag_data.vrdccrmd);
+
+       return -ENODEV;
 }
 
 /*
@@ -130,6 +151,7 @@ __ccw_device_sense_id_start(struct ccw_device *cdev)
        /* Try on every path. */
        ret = -ENODEV;
        while (cdev->private->imask != 0) {
+               cdev->private->senseid.cu_type = 0xFFFF;
                if ((sch->opm & cdev->private->imask) != 0 &&
                    cdev->private->iretry > 0) {
                        cdev->private->iretry--;
@@ -153,7 +175,6 @@ ccw_device_sense_id_start(struct ccw_device *cdev)
        int ret;
 
        memset (&cdev->private->senseid, 0, sizeof (struct senseid));
-       cdev->private->senseid.cu_type = 0xFFFF;
        cdev->private->imask = 0x80;
        cdev->private->iretry = 5;
        ret = __ccw_device_sense_id_start(cdev);
@@ -173,13 +194,7 @@ ccw_device_check_sense_id(struct ccw_device *cdev)
 
        sch = to_subchannel(cdev->dev.parent);
        irb = &cdev->private->irb;
-       /* Did we get a proper answer ? */
-       if (cdev->private->senseid.cu_type != 0xFFFF && 
-           cdev->private->senseid.reserved == 0xFF) {
-               if (irb->scsw.count < sizeof (struct senseid) - 8)
-                       cdev->private->flags.esid = 1;
-               return 0; /* Success */
-       }
+
        /* Check the error cases. */
        if (irb->scsw.fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) {
                /* Retry Sense ID if requested. */
@@ -231,6 +246,15 @@ ccw_device_check_sense_id(struct ccw_device *cdev)
                                      sch->schid.ssid, sch->schid.sch_no);
                return -EACCES;
        }
+
+       /* Did we get a proper answer ? */
+       if (irb->scsw.cc == 0 && cdev->private->senseid.cu_type != 0xFFFF &&
+           cdev->private->senseid.reserved == 0xFF) {
+               if (irb->scsw.count < sizeof(struct senseid) - 8)
+                       cdev->private->flags.esid = 1;
+               return 0; /* Success */
+       }
+
        /* Hmm, whatever happened, try again. */
        CIO_MSG_EVENT(2, "SenseID : start_IO() for device %04x on "
                      "subchannel 0.%x.%04x returns status %02X%02X\n",
@@ -283,20 +307,17 @@ ccw_device_sense_id_irq(struct ccw_device *cdev, enum dev_event dev_event)
                        break;
                /* fall through. */
        default:                /* Sense ID failed. Try asking VM. */
-               if (MACHINE_IS_VM) {
-                       VM_virtual_device_info (cdev->private->dev_id.devno,
+               if (MACHINE_IS_VM)
+                       ret = diag_get_dev_info(cdev->private->dev_id.devno,
                                                &cdev->private->senseid);
-                       if (cdev->private->senseid.cu_type != 0xFFFF) {
-                               /* Got the device information from VM. */
-                               ccw_device_sense_id_done(cdev, 0);
-                               return;
-                       }
-               }
-               /*
-                * If we can't couldn't identify the device type we
-                *  consider the device "not operational".
-                */
-               ccw_device_sense_id_done(cdev, -ENODEV);
+               else
+                       /*
+                        * If we can't couldn't identify the device type we
+                        *  consider the device "not operational".
+                        */
+                       ret = -ENODEV;
+
+               ccw_device_sense_id_done(cdev, ret);
                break;
        }
 }
index d85cb73a9f69f217cdcf9e9c779bde8dc3da3947..00a0ba040dba58ad7203d392123077bd629a7812 100644 (file)
@@ -1,6 +1,6 @@
 /* NCR53C9x.c:  Defines and structures for the NCR53C9x generic driver.
  *
- * Originaly esp.h:  Defines and structures for the Sparc ESP 
+ * Originally esp.h:  Defines and structures for the Sparc ESP 
  *                   (Enhanced SCSI Processor) driver under Linux.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
index 0e8267c1e9155a29df404823454a47268442a667..fb0886140dd788efa31f220558247e16439fab98 100644 (file)
@@ -449,9 +449,6 @@ static int aac_slave_configure(struct scsi_device *sdev)
                else if (depth < 2)
                        depth = 2;
                scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, depth);
-               if (!(((struct aac_dev *)host->hostdata)->adapter_info.options &
-                               AAC_OPT_NEW_COMM))
-                       blk_queue_max_segment_size(sdev->request_queue, 65536);
        } else
                scsi_adjust_queue_depth(sdev, 0, 1);
 
@@ -1133,6 +1130,12 @@ static int __devinit aac_probe_one(struct pci_dev *pdev,
        if (error < 0)
                goto out_deinit;
 
+       if (!(aac->adapter_info.options & AAC_OPT_NEW_COMM)) {
+               error = pci_set_dma_max_seg_size(pdev, 65536);
+               if (error)
+                       goto out_deinit;
+       }
+
        /*
         * Lets override negotiations and drop the maximum SG limit to 34
         */
index 190568ebea3c12e15131bfb6868c212c9463caa0..5a1471c370fa70f601a845fb66e762701bc2d1a8 100644 (file)
@@ -21,7 +21,7 @@
  *  Modified by Chris Faulhaber <jedgar@fxp.org>
  *        Added module command-line options
  *        19-Jul-99
- *  Modified by Adam Fritzler <mid@auk.cx>
+ *  Modified by Adam Fritzler
  *        Added proper detection of the AHA-1640 (MCA version of AHA-1540)
  */
 
index e4f70c563bc295cc6b0a6a022f83998708964183..4c549540a35dcccfce967d2e53f498a8a987801c 100644 (file)
@@ -44,13 +44,8 @@ clean-files += aic79xx_seq.h aic79xx_reg.h aic79xx_reg_print.c
 
 # Dependencies for generated files need to be listed explicitly
 
-$(obj)/aic7xxx_core.o: $(obj)/aic7xxx_seq.h
-$(obj)/aic7xxx_core.o: $(obj)/aic7xxx_reg.h
-$(obj)/aic79xx_core.o: $(obj)/aic79xx_seq.h
-$(obj)/aic79xx_core.o: $(obj)/aic79xx_reg.h
-
-$(addprefix $(obj)/,$(aic7xxx-y)): $(obj)/aic7xxx_seq.h
-$(addprefix $(obj)/,$(aic79xx-y)): $(obj)/aic79xx_seq.h
+$(addprefix $(src)/,$(aic7xxx-y:.o=.c)): $(obj)/aic7xxx_seq.h $(obj)/aic7xxx_reg.h
+$(addprefix $(src)/,$(aic79xx-y:.o=.c)): $(obj)/aic79xx_seq.h $(obj)/aic79xx_reg.h
 
 aic7xxx-gen-$(CONFIG_AIC7XXX_BUILD_FIRMWARE)   := $(obj)/aic7xxx_reg.h
 aic7xxx-gen-$(CONFIG_AIC7XXX_REG_PRETTY_PRINT) += $(obj)/aic7xxx_reg_print.c
index 2ceb67f4af2a6ab1cfb7dac81fe3e86b4a2d5c2d..45e55575a0fad6c997f725d1489e815af31c4fff 100644 (file)
@@ -417,7 +417,7 @@ ahd_targetcmd_offset(struct ahd_softc *ahd, u_int index)
               - (uint8_t *)ahd->qoutfifo);
 }
 
-/*********************** Miscelaneous Support Functions ***********************/
+/*********************** Miscellaneous Support Functions ***********************/
 static __inline struct ahd_initiator_tinfo *
                        ahd_fetch_transinfo(struct ahd_softc *ahd,
                                            char channel, u_int our_id,
index 01465479290135bcd4d03719880bc360fc28947e..72fccd9f40df544e0686f8ea2681c34efb7bb448 100644 (file)
@@ -325,7 +325,7 @@ MODULE_PARM_DESC(aic79xx,
 "      verbose                 Enable verbose/diagnostic logging\n"
 "      allow_memio             Allow device registers to be memory mapped\n"
 "      debug                   Bitmask of debug values to enable\n"
-"      no_reset                Supress initial bus resets\n"
+"      no_reset                Suppress initial bus resets\n"
 "      extended                Enable extended geometry on all controllers\n"
 "      periodic_otag           Send an ordered tagged transaction\n"
 "                              periodically to prevent tag starvation.\n"
index df853676e66a8d7174c81862e65559c99fd45121..c9f79fdf913105d77046db61619c6432a4123dd6 100644 (file)
@@ -979,7 +979,7 @@ ahd_aic790X_setup(struct ahd_softc *ahd)
                          |  AHD_FAINT_LED_BUG;
 
                /*
-                * IO Cell paramter setup.
+                * IO Cell parameter setup.
                 */
                AHD_SET_PRECOMP(ahd, AHD_PRECOMP_CUTBACK_29);
 
@@ -1006,7 +1006,7 @@ ahd_aic790X_setup(struct ahd_softc *ahd)
                        ahd->bugs |= AHD_INTCOLLISION_BUG|AHD_ABORT_LQI_BUG;
 
                /*
-                * IO Cell paramter setup.
+                * IO Cell parameter setup.
                 */
                AHD_SET_PRECOMP(ahd, AHD_PRECOMP_CUTBACK_29);
                AHD_SET_SLEWRATE(ahd, AHD_SLEWRATE_DEF_REVB);
index 8e1954cdd84f67cd114491ad0c0072d3aaec175f..cba2f23bbe7954974aab44408b480269d16bae92 100644 (file)
@@ -229,7 +229,7 @@ ahc_name(struct ahc_softc *ahc)
        return (ahc->name);
 }
 
-/*********************** Miscelaneous Support Functions ***********************/
+/*********************** Miscellaneous Support Functions ***********************/
 
 static __inline void   ahc_update_residual(struct ahc_softc *ahc,
                                            struct scb *scb);
index 99a3b33a3233591834e670c95b8152af9df3d12d..282aff6f852e85bb5b9bae950e2da1f423e5df34 100644 (file)
@@ -347,7 +347,7 @@ MODULE_PARM_DESC(aic7xxx,
 "      debug                   Bitmask of debug values to enable\n"
 "      no_probe                Toggle EISA/VLB controller probing\n"
 "      probe_eisa_vl           Toggle EISA/VLB controller probing\n"
-"      no_reset                Supress initial bus resets\n"
+"      no_reset                Suppress initial bus resets\n"
 "      extended                Enable extended geometry on all controllers\n"
 "      periodic_otag           Send an ordered tagged transaction\n"
 "                              periodically to prevent tag starvation.\n"
index db8bc20539e193f0b8ad9b1949d0214e5dcda64e..68e5c632c5d55ca7b909643c3cf2f2a1adff3889 100644 (file)
@@ -1,7 +1,6 @@
 /*
- * linux/drivers/scsi/ide-scsi.c       Version 0.9             Jul   4, 1999
- *
- * Copyright (C) 1996 - 1999 Gadi Oxman <gadio@netvision.net.il>
+ * Copyright (C) 1996-1999  Gadi Oxman <gadio@netvision.net.il>
+ * Copyright (C) 2004-2005  Bartlomiej Zolnierkiewicz
  */
 
 /*
@@ -288,7 +287,7 @@ static int idescsi_end_request(ide_drive_t *, int, int);
 static ide_startstop_t
 idescsi_atapi_error(ide_drive_t *drive, struct request *rq, u8 stat, u8 err)
 {
-       if (HWIF(drive)->INB(IDE_STATUS_REG) & (BUSY_STAT|DRQ_STAT))
+       if (ide_read_status(drive) & (BUSY_STAT | DRQ_STAT))
                /* force an abort */
                HWIF(drive)->OUTB(WIN_IDLEIMMEDIATE,IDE_COMMAND_REG);
 
@@ -424,7 +423,7 @@ static ide_startstop_t idescsi_pc_intr (ide_drive_t *drive)
        }
 
        /* Clear the interrupt */
-       stat = drive->hwif->INB(IDE_STATUS_REG);
+       stat = ide_read_status(drive);
 
        if ((stat & DRQ_STAT) == 0) {
                /* No more interrupts */
@@ -589,19 +588,14 @@ static ide_startstop_t idescsi_issue_pc (ide_drive_t *drive, idescsi_pc_t *pc)
                hwif->sg_mapped = 0;
        }
 
-       SELECT_DRIVE(drive);
-
        ide_pktcmd_tf_load(drive, IDE_TFLAG_NO_SELECT_MASK, bcount, dma);
 
        if (dma)
                set_bit(PC_DMA_OK, &pc->flags);
 
        if (test_bit(IDESCSI_DRQ_INTERRUPT, &scsi->flags)) {
-               BUG_ON(HWGROUP(drive)->handler != NULL);
-               ide_set_handler(drive, &idescsi_transfer_pc,
-                               get_timeout(pc), idescsi_expiry);
-               /* Issue the packet command */
-               HWIF(drive)->OUTB(WIN_PACKETCMD, IDE_COMMAND_REG);
+               ide_execute_command(drive, WIN_PACKETCMD, &idescsi_transfer_pc,
+                                   get_timeout(pc), idescsi_expiry);
                return ide_started;
        } else {
                /* Issue the packet command */
index 73270ff892d9699c63cd5388ae0ace773dcfc3de..2074701f7e7612959568535cfaec21bdc05b76b7 100644 (file)
@@ -7053,7 +7053,7 @@ static pci_ers_result_t ipr_pci_error_detected(struct pci_dev *pdev,
  * where it can accept new commands.
 
  * Return value:
- *     0 on sucess / -EIO on failure
+ *     0 on success / -EIO on failure
  **/
 static int __devinit ipr_probe_ioa_part2(struct ipr_ioa_cfg *ioa_cfg)
 {
index 7505cca8e68e3d1825e06c9a977e948c3a0dacf2..bb152fb9fec7dc4b3260c2b4add978ba4af0e314 100644 (file)
@@ -1309,7 +1309,7 @@ ips_intr_copperhead(ips_ha_t * ha)
                        cstatus.value = (*ha->func.statupd) (ha);
 
                if (cstatus.fields.command_id > (IPS_MAX_CMDS - 1)) {
-                       /* Spurious Interupt ? */
+                       /* Spurious Interrupt ? */
                        continue;
                }
 
index f26b9538affe232079d94cd4b9179815af441958..83567b9755b4bf9946f0be2764715d7e85c2f9d2 100644 (file)
@@ -325,7 +325,7 @@ struct lpfc_vport {
 
 #define WORKER_MBOX_TMO                0x100   /* hba: MBOX timeout */
 #define WORKER_HB_TMO                  0x200   /* hba: Heart beat timeout */
-#define WORKER_FABRIC_BLOCK_TMO        0x400   /* hba: fabric block timout */
+#define WORKER_FABRIC_BLOCK_TMO        0x400   /* hba: fabric block timeout */
 #define WORKER_RAMP_DOWN_QUEUE         0x800   /* hba: Decrease Q depth */
 #define WORKER_RAMP_UP_QUEUE           0x1000  /* hba: Increase Q depth */
 
index 3205f7488d1c49b6f24b17391f77ccf6a25e5908..6cfeba7454d46e534b35f88b36d50a20d73f721e 100644 (file)
@@ -1894,7 +1894,7 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
        uint16_t iotag;
        int bars = pci_select_bars(pdev, IORESOURCE_MEM);
 
-       if (pci_enable_device_bars(pdev, bars))
+       if (pci_enable_device_mem(pdev))
                goto out;
        if (pci_request_selected_regions(pdev, bars, LPFC_DRIVER_NAME))
                goto out_disable_device;
@@ -2296,10 +2296,9 @@ static pci_ers_result_t lpfc_io_slot_reset(struct pci_dev *pdev)
        struct Scsi_Host *shost = pci_get_drvdata(pdev);
        struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
        struct lpfc_sli *psli = &phba->sli;
-       int bars = pci_select_bars(pdev, IORESOURCE_MEM);
 
        dev_printk(KERN_INFO, &pdev->dev, "recovering from a slot reset.\n");
-       if (pci_enable_device_bars(pdev, bars)) {
+       if (pci_enable_device_mem(pdev)) {
                printk(KERN_ERR "lpfc: Cannot re-enable "
                        "PCI device after reset.\n");
                return PCI_ERS_RESULT_DISCONNECT;
index dfc63f6ccd7bac89c8a98a41afa5e7042cea2250..7a9be4c5b7cb224128faaacba8d4dc8f9cbb3a0a 100644 (file)
@@ -880,7 +880,7 @@ lpfc_mbox_get(struct lpfc_hba * phba)
 void
 lpfc_mbox_cmpl_put(struct lpfc_hba * phba, LPFC_MBOXQ_t * mbq)
 {
-       /* This function expects to be called from interupt context */
+       /* This function expects to be called from interrupt context */
        spin_lock(&phba->hbalock);
        list_add_tail(&mbq->list, &phba->sli.mboxq_cmpl);
        spin_unlock(&phba->hbalock);
index 6db77c00e3eed4b802eeab7b9ec662194522d526..9f041929aca52ee1d978c2652c995125798fa9ce 100644 (file)
@@ -3464,12 +3464,12 @@ megaraid_mbox_setup_device_map(adapter_t *adapter)
 /*
  * START: Interface for the common management module
  *
- * This is the module, which interfaces with the common mangement module to
+ * This is the module, which interfaces with the common management module to
  * provide support for ioctl and sysfs
  */
 
 /**
- * megaraid_cmm_register - register with the mangement module
+ * megaraid_cmm_register - register with the management module
  * @adapter            : HBA soft state
  *
  * Register with the management module, which allows applications to issue
@@ -3557,7 +3557,7 @@ megaraid_cmm_register(adapter_t *adapter)
 
 
 /**
- * megaraid_cmm_unregister - un-register with the mangement module
+ * megaraid_cmm_unregister - un-register with the management module
  * @adapter            : HBA soft state
  *
  * Un-register with the management module.
@@ -3579,7 +3579,7 @@ megaraid_cmm_unregister(adapter_t *adapter)
  * @kioc               : CMM interface packet
  * @action             : command action
  *
- * This routine is invoked whenever the Common Mangement Module (CMM) has a
+ * This routine is invoked whenever the Common Management Module (CMM) has a
  * command for us. The 'action' parameter specifies if this is a new command
  * or otherwise.
  */
@@ -3944,7 +3944,7 @@ megaraid_sysfs_get_ldmap_timeout(unsigned long data)
  *
  * This routine will be called whenever user reads the logical drive
  * attributes, go get the current logical drive mapping table from the
- * firmware. We use the managment API's to issue commands to the controller.
+ * firmware. We use the management API's to issue commands to the controller.
  *
  * NOTE: The commands issuance functionality is not generalized and
  * implemented in context of "get ld map" command only. If required, the
index 4b82b2021981a5598c4861867d6d31236bc8f532..d8b99351b053b256e3ad0bd4af7854ef5f77ba65 100644 (file)
@@ -130,7 +130,7 @@ static int fdomain_config(struct pcmcia_device *link)
     cisparse_t parse;
     int i, last_ret, last_fn;
     u_char tuple_data[64];
-    char str[16];
+    char str[22];
     struct Scsi_Host *host;
 
     DEBUG(0, "fdomain_config(0x%p)\n", link);
index 6f129da3758942fec786136fecd4eed5a9b5e4d0..b72c7f170854a9b8f93e9a0ceb7929684e770633 100644 (file)
@@ -2268,6 +2268,7 @@ typedef struct scsi_qla_host {
        spinlock_t              hardware_lock ____cacheline_aligned;
 
        int             bars;
+       int             mem_only;
        device_reg_t __iomem *iobase;           /* Base I/O address */
        resource_size_t pio_address;
 #define MIN_IOBASE_LEN         0x100
index eb0784c9ff83af88fa9c291eaed5281041cb541b..6226d88479f59fa2a1ded8423180281a98393ab0 100644 (file)
@@ -1094,7 +1094,7 @@ qla2x00_sns_rnn_id(scsi_qla_host_t *ha)
 }
 
 /**
- * qla2x00_mgmt_svr_login() - Login to fabric Managment Service.
+ * qla2x00_mgmt_svr_login() - Login to fabric Management Service.
  * @ha: HA context
  *
  * Returns 0 on success.
index 3954ed2d7b517acbd183f30049625bf43a3750b2..8f69caf8327254dc12d55bff8487d3dfadbf318b 100644 (file)
@@ -1564,7 +1564,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
        char pci_info[30];
        char fw_str[30];
        struct scsi_host_template *sht;
-       int bars;
+       int bars, mem_only = 0;
 
        bars = pci_select_bars(pdev, IORESOURCE_MEM | IORESOURCE_IO);
        sht = &qla2x00_driver_template;
@@ -1575,10 +1575,16 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
            pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2532) {
                bars = pci_select_bars(pdev, IORESOURCE_MEM);
                sht = &qla24xx_driver_template;
+               mem_only = 1;
        }
 
-       if (pci_enable_device_bars(pdev, bars))
-               goto probe_out;
+       if (mem_only) {
+               if (pci_enable_device_mem(pdev))
+                       goto probe_out;
+       } else {
+               if (pci_enable_device(pdev))
+                       goto probe_out;
+       }
 
        if (pci_find_aer_capability(pdev))
                if (pci_enable_pcie_error_reporting(pdev))
@@ -1601,6 +1607,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
        sprintf(ha->host_str, "%s_%ld", QLA2XXX_DRIVER_NAME, ha->host_no);
        ha->parent = NULL;
        ha->bars = bars;
+       ha->mem_only = mem_only;
 
        /* Set ISP-type information. */
        qla2x00_set_isp_flags(ha);
@@ -2875,8 +2882,14 @@ qla2xxx_pci_slot_reset(struct pci_dev *pdev)
 {
        pci_ers_result_t ret = PCI_ERS_RESULT_DISCONNECT;
        scsi_qla_host_t *ha = pci_get_drvdata(pdev);
+       int rc;
+
+       if (ha->mem_only)
+               rc = pci_enable_device_mem(pdev);
+       else
+               rc = pci_enable_device(pdev);
 
-       if (pci_enable_device_bars(pdev, ha->bars)) {
+       if (rc) {
                qla_printk(KERN_WARNING, ha,
                    "Can't re-enable PCI device after reset.\n");
 
index accaf690eaf0c393f620750d705c650cbee04705..d6be0762eb918977b27bd428f7057a8e25bba3af 100644 (file)
 #define MAX_REQS_SERVICED_PER_INTR     16
 
 #define ISCSI_IPADDR_SIZE              4       /* IP address size */
-#define ISCSI_ALIAS_SIZE               32      /* ISCSI Alais name size */
+#define ISCSI_ALIAS_SIZE               32      /* ISCSI Alias name size */
 #define ISCSI_NAME_SIZE                        0xE0    /* ISCSI Name size */
 
 #define LSDW(x) ((u32)((u64)(x)))
index cbe0a17ced5f9b97cde9e21e8c41640b41b16c3b..49925f92555e8a3b485316d5963bc0dd8ef6d49f 100644 (file)
@@ -1098,7 +1098,7 @@ static int qla4xxx_start_firmware(struct scsi_qla_host *ha)
                }
                config_chip = 1;
 
-               /* Reset clears the semaphore, so aquire again */
+               /* Reset clears the semaphore, so acquire again */
                if (ql4xxx_lock_drvr_wait(ha) != QLA_SUCCESS)
                        return QLA_ERROR;
        }
index b12fb310e3999af497c21778b62f40c46892e8fd..f243fc30c908dce70387e776aa945cde84e5bc4a 100644 (file)
@@ -1569,6 +1569,7 @@ struct request_queue *__scsi_alloc_queue(struct Scsi_Host *shost,
                                         request_fn_proc *request_fn)
 {
        struct request_queue *q;
+       struct device *dev = shost->shost_gendev.parent;
 
        q = blk_init_queue(request_fn, NULL);
        if (!q)
@@ -1583,6 +1584,9 @@ struct request_queue *__scsi_alloc_queue(struct Scsi_Host *shost,
        blk_queue_max_sectors(q, shost->max_sectors);
        blk_queue_bounce_limit(q, scsi_calculate_bounce_limit(shost));
        blk_queue_segment_boundary(q, shost->dma_boundary);
+       dma_set_seg_boundary(dev, shost->dma_boundary);
+
+       blk_queue_max_segment_size(q, dma_get_max_seg_size(dev));
 
        if (!shost->use_clustering)
                clear_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags);
index 91630baea532e0656883ee2c427b21467a9bf629..3677fbb30b720d50b6777a395125ba03ae1c492b 100644 (file)
@@ -320,7 +320,7 @@ int scsi_tgt_queue_command(struct scsi_cmnd *cmd, u64 itn_id,
 EXPORT_SYMBOL_GPL(scsi_tgt_queue_command);
 
 /*
- * This is run from a interrpt handler normally and the unmap
+ * This is run from a interrupt handler normally and the unmap
  * needs process context so we must queue
  */
 static void scsi_tgt_cmd_done(struct scsi_cmnd *cmd)
index f2149d0bb9997a4caff68d9900eeb6da8de8832a..43a964d635b4e19b30d5d76c4dafcc090e8a5a14 100644 (file)
@@ -6,7 +6,7 @@
  *
  * The SAS transport class contains common code to deal with SAS HBAs,
  * an aproximated representation of SAS topologies in the driver model,
- * and various sysfs attributes to expose these topologies and managment
+ * and various sysfs attributes to expose these topologies and management
  * interfaces to userspace.
  *
  * In addition to the basic SCSI core objects this transport class
index 6a48dfa1efe8552fcaa8453d0800a2d58437c764..0276471cb25ec933819088d784935a69363ec8ac 100644 (file)
@@ -237,6 +237,12 @@ serial21285_set_termios(struct uart_port *port, struct ktermios *termios,
        baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); 
        quot = uart_get_divisor(port, baud);
 
+       if (port->info && port->info->tty) {
+               struct tty_struct *tty = port->info->tty;
+               unsigned int b = port->uartclk / (16 * quot);
+               tty_encode_baud_rate(tty, b, b);
+       }
+
        switch (termios->c_cflag & CSIZE) {
        case CS5:
                h_lcr = 0x00;
@@ -277,8 +283,6 @@ serial21285_set_termios(struct uart_port *port, struct ktermios *termios,
        if (termios->c_iflag & INPCK)
                port->read_status_mask |= RXSTAT_FRAME | RXSTAT_PARITY;
 
-       tty_encode_baud_rate(tty,  baud, baud);
-
        /*
         * Which character status flags should we ignore?
         */
index aad4012bbb30510a66c2f7983f07473a9885f5d4..0d99120ab5a26bb3bc0540cb60f0139ed7d800a9 100644 (file)
@@ -1410,7 +1410,7 @@ rs68328_init(void)
 
            if (request_irq(uart_irqs[i],
                            rs_interrupt,
-                           IRQ_FLG_STD,
+                           IRQF_DISABLED,
                            "M68328_UART", NULL))
                 panic("Unable to attach 68328 serial interrupt\n");
        }
index f94109cbb46e683a6a6f7d2fee29d7915b21cc93..b8a4bd94f51d5501cbf813d38f75147a9e180ab9 100644 (file)
@@ -2047,7 +2047,7 @@ serial8250_set_termios(struct uart_port *port, struct ktermios *termios,
         * Oxford Semi 952 rev B workaround
         */
        if (up->bugs & UART_BUG_QUOT && (quot & 0xff) == 0)
-               quot ++;
+               quot++;
 
        if (up->capabilities & UART_CAP_FIFO && up->port.fifosize > 1) {
                if (baud < 2400)
@@ -2662,16 +2662,17 @@ static int __devinit serial8250_probe(struct platform_device *dev)
        memset(&port, 0, sizeof(struct uart_port));
 
        for (i = 0; p && p->flags != 0; p++, i++) {
-               port.iobase     = p->iobase;
-               port.membase    = p->membase;
-               port.irq        = p->irq;
-               port.uartclk    = p->uartclk;
-               port.regshift   = p->regshift;
-               port.iotype     = p->iotype;
-               port.flags      = p->flags;
-               port.mapbase    = p->mapbase;
-               port.hub6       = p->hub6;
-               port.dev        = &dev->dev;
+               port.iobase             = p->iobase;
+               port.membase            = p->membase;
+               port.irq                = p->irq;
+               port.uartclk            = p->uartclk;
+               port.regshift           = p->regshift;
+               port.iotype             = p->iotype;
+               port.flags              = p->flags;
+               port.mapbase            = p->mapbase;
+               port.hub6               = p->hub6;
+               port.private_data       = p->private_data;
+               port.dev                = &dev->dev;
                if (share_irqs)
                        port.flags |= UPF_SHARE_IRQ;
                ret = serial8250_register_port(&port);
@@ -2812,15 +2813,16 @@ int serial8250_register_port(struct uart_port *port)
        if (uart) {
                uart_remove_one_port(&serial8250_reg, &uart->port);
 
-               uart->port.iobase   = port->iobase;
-               uart->port.membase  = port->membase;
-               uart->port.irq      = port->irq;
-               uart->port.uartclk  = port->uartclk;
-               uart->port.fifosize = port->fifosize;
-               uart->port.regshift = port->regshift;
-               uart->port.iotype   = port->iotype;
-               uart->port.flags    = port->flags | UPF_BOOT_AUTOCONF;
-               uart->port.mapbase  = port->mapbase;
+               uart->port.iobase       = port->iobase;
+               uart->port.membase      = port->membase;
+               uart->port.irq          = port->irq;
+               uart->port.uartclk      = port->uartclk;
+               uart->port.fifosize     = port->fifosize;
+               uart->port.regshift     = port->regshift;
+               uart->port.iotype       = port->iotype;
+               uart->port.flags        = port->flags | UPF_BOOT_AUTOCONF;
+               uart->port.mapbase      = port->mapbase;
+               uart->port.private_data = port->private_data;
                if (port->dev)
                        uart->port.dev = port->dev;
 
index ceb03c9e749f8f918732d88c635de618d1f04125..0a4ac2b6eb5a2a8d5c0a25da3a1a0bdf40c4f317 100644 (file)
@@ -105,6 +105,32 @@ setup_port(struct serial_private *priv, struct uart_port *port,
        return 0;
 }
 
+/*
+ * ADDI-DATA GmbH communication cards <info@addi-data.com>
+ */
+static int addidata_apci7800_setup(struct serial_private *priv,
+                               struct pciserial_board *board,
+                               struct uart_port *port, int idx)
+{
+       unsigned int bar = 0, offset = board->first_offset;
+       bar = FL_GET_BASE(board->flags);
+
+       if (idx < 2) {
+               offset += idx * board->uart_offset;
+       } else if ((idx >= 2) && (idx < 4)) {
+               bar += 1;
+               offset += ((idx - 2) * board->uart_offset);
+       } else if ((idx >= 4) && (idx < 6)) {
+               bar += 2;
+               offset += ((idx - 4) * board->uart_offset);
+       } else if (idx >= 6) {
+               bar += 3;
+               offset += ((idx - 6) * board->uart_offset);
+       }
+
+       return setup_port(priv, port, bar, offset, board->reg_shift);
+}
+
 /*
  * AFAVLAB uses a different mixture of BARs and offsets
  * Not that ugly ;) -- HW
@@ -751,6 +777,16 @@ pci_default_setup(struct serial_private *priv, struct pciserial_board *board,
  * Specific entries must come before more generic entries.
  */
 static struct pci_serial_quirk pci_serial_quirks[] = {
+       /*
+       * ADDI-DATA GmbH communication cards <info@addi-data.com>
+       */
+       {
+               .vendor         = PCI_VENDOR_ID_ADDIDATA_OLD,
+               .device         = PCI_DEVICE_ID_ADDIDATA_APCI7800,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .setup          = addidata_apci7800_setup,
+       },
        /*
         * AFAVLAB cards - these may be called via parport_serial
         *  It is not clear whether this applies to all products.
@@ -1179,6 +1215,12 @@ static struct pciserial_board pci_boards[] __devinitdata = {
                .base_baud      = 115200,
                .uart_offset    = 8,
        },
+       [pbn_b0_8_115200] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 8,
+               .base_baud      = 115200,
+               .uart_offset    = 8,
+       },
 
        [pbn_b0_1_921600] = {
                .flags          = FL_BASE0,
@@ -2696,6 +2738,97 @@ static struct pci_device_id serial_pci_tbl[] = {
                PCI_ANY_ID, PCI_ANY_ID, 0, 0,
                pbn_pasemi_1682M },
 
+       /*
+       * ADDI-DATA GmbH communication cards <info@addi-data.com>
+       */
+       {       PCI_VENDOR_ID_ADDIDATA,
+               PCI_DEVICE_ID_ADDIDATA_APCI7500,
+               PCI_ANY_ID,
+               PCI_ANY_ID,
+               0,
+               0,
+               pbn_b0_4_115200 },
+
+       {       PCI_VENDOR_ID_ADDIDATA,
+               PCI_DEVICE_ID_ADDIDATA_APCI7420,
+               PCI_ANY_ID,
+               PCI_ANY_ID,
+               0,
+               0,
+               pbn_b0_2_115200 },
+
+       {       PCI_VENDOR_ID_ADDIDATA,
+               PCI_DEVICE_ID_ADDIDATA_APCI7300,
+               PCI_ANY_ID,
+               PCI_ANY_ID,
+               0,
+               0,
+               pbn_b0_1_115200 },
+
+       {       PCI_VENDOR_ID_ADDIDATA_OLD,
+               PCI_DEVICE_ID_ADDIDATA_APCI7800,
+               PCI_ANY_ID,
+               PCI_ANY_ID,
+               0,
+               0,
+               pbn_b1_8_115200 },
+
+       {       PCI_VENDOR_ID_ADDIDATA,
+               PCI_DEVICE_ID_ADDIDATA_APCI7500_2,
+               PCI_ANY_ID,
+               PCI_ANY_ID,
+               0,
+               0,
+               pbn_b0_4_115200 },
+
+       {       PCI_VENDOR_ID_ADDIDATA,
+               PCI_DEVICE_ID_ADDIDATA_APCI7420_2,
+               PCI_ANY_ID,
+               PCI_ANY_ID,
+               0,
+               0,
+               pbn_b0_2_115200 },
+
+       {       PCI_VENDOR_ID_ADDIDATA,
+               PCI_DEVICE_ID_ADDIDATA_APCI7300_2,
+               PCI_ANY_ID,
+               PCI_ANY_ID,
+               0,
+               0,
+               pbn_b0_1_115200 },
+
+       {       PCI_VENDOR_ID_ADDIDATA,
+               PCI_DEVICE_ID_ADDIDATA_APCI7500_3,
+               PCI_ANY_ID,
+               PCI_ANY_ID,
+               0,
+               0,
+               pbn_b0_4_115200 },
+
+       {       PCI_VENDOR_ID_ADDIDATA,
+               PCI_DEVICE_ID_ADDIDATA_APCI7420_3,
+               PCI_ANY_ID,
+               PCI_ANY_ID,
+               0,
+               0,
+               pbn_b0_2_115200 },
+
+       {       PCI_VENDOR_ID_ADDIDATA,
+               PCI_DEVICE_ID_ADDIDATA_APCI7300_3,
+               PCI_ANY_ID,
+               PCI_ANY_ID,
+               0,
+               0,
+               pbn_b0_1_115200 },
+
+       {       PCI_VENDOR_ID_ADDIDATA,
+               PCI_DEVICE_ID_ADDIDATA_APCI7800_3,
+               PCI_ANY_ID,
+               PCI_ANY_ID,
+               0,
+               0,
+               pbn_b0_8_115200 },
+
        /*
         * These entries match devices with class COMMUNICATION_SERIAL,
         * COMMUNICATION_MODEM or COMMUNICATION_MULTISERIAL
index 1de098e754978810db03ea655480bb4c9e213e45..6f09cbd7fc488ac53286c92ba1ce0698f11ba0bd 100644 (file)
@@ -414,8 +414,9 @@ static int __devinit check_resources(struct pnp_option *option)
  */
 static int __devinit serial_pnp_guess_board(struct pnp_dev *dev, int *flags)
 {
-       if (!(check_name(pnp_dev_name(dev)) || (dev->card && check_name(dev->card->name))))
-               return -ENODEV;
+       if (!(check_name(pnp_dev_name(dev)) ||
+               (dev->card && check_name(dev->card->name))))
+                       return -ENODEV;
 
        if (check_resources(dev->independent))
                return 0;
@@ -452,8 +453,9 @@ serial_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
                return -ENODEV;
 
 #ifdef SERIAL_DEBUG_PNP
-       printk("Setup PNP port: port %x, mem 0x%lx, irq %d, type %d\n",
-              port.iobase, port.mapbase, port.irq, port.iotype);
+       printk(KERN_DEBUG
+               "Setup PNP port: port %x, mem 0x%lx, irq %d, type %d\n",
+                      port.iobase, port.mapbase, port.irq, port.iotype);
 #endif
 
        port.flags |= UPF_SKIP_TEST | UPF_BOOT_AUTOCONF;
index d9d7673b712bd2fdee078cf66d3304db2bb2cd43..ddfb1eab736371a6676ccdd637d197865b32ea2f 100644 (file)
@@ -960,6 +960,30 @@ config SERIAL_COLDFIRE
          This driver supports the built-in serial ports of the Motorola ColdFire
          family of CPUs.
 
+config SERIAL_MCF
+       bool "Coldfire serial support (new style driver)"
+       depends on COLDFIRE
+       select SERIAL_CORE
+       help
+         This new serial driver supports the Freescale Coldfire serial ports
+         using the new serial driver subsystem.
+
+config SERIAL_MCF_BAUDRATE
+       int "Default baudrate for Coldfire serial ports"
+       depends on SERIAL_MCF
+       default 19200
+       help
+         This setting lets you define what the default baudrate is for the
+         ColdFire serial ports. The usual default varies from board to board,
+         and this setting is a way of catering for that.
+
+config SERIAL_MCF_CONSOLE
+       bool "Coldfire serial console support"
+       depends on SERIAL_MCF
+       select SERIAL_CORE_CONSOLE
+       help
+         Enable a ColdFire internal serial port to be the system console.
+
 config SERIAL_68360_SMC
        bool "68360 SMC uart support"
        depends on M68360
@@ -1271,8 +1295,8 @@ config SERIAL_NETX_CONSOLE
        depends on SERIAL_NETX
        select SERIAL_CORE_CONSOLE
        help
-         If you have enabled the serial port on the Motorola IMX
-         CPU you can make it the console by answering Y to this option.
+         If you have enabled the serial port on the Hilscher NetX SoC
+         you can make it the console by answering Y to this option.
 
 config SERIAL_OF_PLATFORM
        tristate "Serial port on Open Firmware platform bus"
index 7eb45534778e5b3011d381a2987ce8670210c58f..2dd41b4cc8dbf1cc930b852a8d4c0fea67d94db0 100644 (file)
@@ -39,6 +39,7 @@ obj-$(CONFIG_SERIAL_MUX) += mux.o
 obj-$(CONFIG_SERIAL_68328) += 68328serial.o
 obj-$(CONFIG_SERIAL_68360) += 68360serial.o
 obj-$(CONFIG_SERIAL_COLDFIRE) += mcfserial.o
+obj-$(CONFIG_SERIAL_MCF) += mcf.o
 obj-$(CONFIG_V850E_UART) += v850e_uart.o
 obj-$(CONFIG_SERIAL_PMACZILOG) += pmac_zilog.o
 obj-$(CONFIG_SERIAL_LH7A40X) += serial_lh7a40x.o
index 111da57f533414671f9a924456ebcf1d08b32553..60f52904aad0fc4bfe7142d348c35a434dac1731 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/tty_flip.h>
 #include <linux/platform_device.h>
 #include <linux/atmel_pdc.h>
+#include <linux/atmel_serial.h>
 
 #include <asm/io.h>
 
@@ -45,8 +46,6 @@
 #include <asm/arch/gpio.h>
 #endif
 
-#include "atmel_serial.h"
-
 #if defined(CONFIG_SERIAL_ATMEL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
 #define SUPPORT_SYSRQ
 #endif
index 0274554967453b632be192c2ae180877d865d73b..c8029e0025c97e400ad8f674dc48d87a49982a4c 100644 (file)
@@ -20,7 +20,7 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-#include<linux/serial_core.h>
+#include <linux/serial_core.h>
 
 #define BAUD_TABLE_LIMIT       ((sizeof(icom_acfg_baud)/sizeof(int)) - 1)
 static int icom_acfg_baud[] = {
index a7d4360ea7df4957ba3fe6df381b1a6631951795..e76fc72c9b3610ab54dd2aec9b5814653e2257fe 100644 (file)
@@ -69,7 +69,7 @@ static unsigned int mcf_tx_empty(struct uart_port *port)
 
 static unsigned int mcf_get_mctrl(struct uart_port *port)
 {
-       struct mcf_uart *pp = (struct mcf_uart *) port;
+       struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
        unsigned long flags;
        unsigned int sigs;
 
@@ -87,7 +87,7 @@ static unsigned int mcf_get_mctrl(struct uart_port *port)
 
 static void mcf_set_mctrl(struct uart_port *port, unsigned int sigs)
 {
-       struct mcf_uart *pp = (struct mcf_uart *) port;
+       struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
        unsigned long flags;
 
        spin_lock_irqsave(&port->lock, flags);
@@ -104,7 +104,7 @@ static void mcf_set_mctrl(struct uart_port *port, unsigned int sigs)
 
 static void mcf_start_tx(struct uart_port *port)
 {
-       struct mcf_uart *pp = (struct mcf_uart *) port;
+       struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
        unsigned long flags;
 
        spin_lock_irqsave(&port->lock, flags);
@@ -117,7 +117,7 @@ static void mcf_start_tx(struct uart_port *port)
 
 static void mcf_stop_tx(struct uart_port *port)
 {
-       struct mcf_uart *pp = (struct mcf_uart *) port;
+       struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
        unsigned long flags;
 
        spin_lock_irqsave(&port->lock, flags);
@@ -130,7 +130,7 @@ static void mcf_stop_tx(struct uart_port *port)
 
 static void mcf_stop_rx(struct uart_port *port)
 {
-       struct mcf_uart *pp = (struct mcf_uart *) port;
+       struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
        unsigned long flags;
 
        spin_lock_irqsave(&port->lock, flags);
@@ -163,7 +163,7 @@ static void mcf_enable_ms(struct uart_port *port)
 
 static int mcf_startup(struct uart_port *port)
 {
-       struct mcf_uart *pp = (struct mcf_uart *) port;
+       struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
        unsigned long flags;
 
        spin_lock_irqsave(&port->lock, flags);
@@ -189,7 +189,7 @@ static int mcf_startup(struct uart_port *port)
 
 static void mcf_shutdown(struct uart_port *port)
 {
-       struct mcf_uart *pp = (struct mcf_uart *) port;
+       struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
        unsigned long flags;
 
        spin_lock_irqsave(&port->lock, flags);
@@ -273,7 +273,7 @@ static void mcf_set_termios(struct uart_port *port, struct ktermios *termios,
 
 static void mcf_rx_chars(struct mcf_uart *pp)
 {
-       struct uart_port *port = (struct uart_port *) pp;
+       struct uart_port *port = &pp->port;
        unsigned char status, ch, flag;
 
        while ((status = readb(port->membase + MCFUART_USR)) & MCFUART_USR_RXREADY) {
@@ -319,7 +319,7 @@ static void mcf_rx_chars(struct mcf_uart *pp)
 
 static void mcf_tx_chars(struct mcf_uart *pp)
 {
-       struct uart_port *port = (struct uart_port *) pp;
+       struct uart_port *port = &pp->port;
        struct circ_buf *xmit = &port->info->xmit;
 
        if (port->x_char) {
@@ -352,7 +352,7 @@ static void mcf_tx_chars(struct mcf_uart *pp)
 static irqreturn_t mcf_interrupt(int irq, void *data)
 {
        struct uart_port *port = data;
-       struct mcf_uart *pp = (struct mcf_uart *) port;
+       struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
        unsigned int isr;
 
        isr = readb(port->membase + MCFUART_UISR) & pp->imr;
@@ -434,7 +434,7 @@ static struct uart_ops mcf_uart_ops = {
 
 static struct mcf_uart mcf_ports[3];
 
-#define        MCF_MAXPORTS    (sizeof(mcf_ports) / sizeof(struct mcf_uart))
+#define        MCF_MAXPORTS    ARRAY_SIZE(mcf_ports)
 
 /****************************************************************************/
 #if defined(CONFIG_SERIAL_MCF_CONSOLE)
index 4d643c9266578d86defb7e9a5b05a138dd161a5b..cb3a91967742b83f96e30c09225f03f4bca80de5 100644 (file)
@@ -612,6 +612,7 @@ static void mpsc_hw_init(struct mpsc_port_info *pi)
 
        /* No preamble, 16x divider, low-latency, */
        writel(0x04400400, pi->mpsc_base + MPSC_MMCRH);
+       mpsc_set_baudrate(pi, pi->default_baud);
 
        if (pi->mirror_regs) {
                pi->MPSC_CHR_1_m = 0;
index 83211013deb87603e3f764106509e4454afad569..e94031731a4797af1d94b9f47db6fc51d0a8bc8c 100644 (file)
@@ -582,7 +582,7 @@ static struct parisc_driver serial_mux_driver = {
 };
 
 /**
- * mux_init - Serial MUX initalization procedure.
+ * mux_init - Serial MUX initialization procedure.
  *
  * Register the Serial MUX driver.
  */
index e773c8e1496245bcaca63984bc9ff07ac055c4f9..45de19366030f248dbda1e33d457e8c75cac7e93 100644 (file)
@@ -1527,7 +1527,7 @@ static inline void s3c2440_serial_exit(void)
 #define s3c2440_uart_inf_at NULL
 #endif /* CONFIG_CPU_S3C2440 */
 
-#if defined(CONFIG_CPU_S3C2412) || defined(CONFIG_CPU_S3C2413)
+#if defined(CONFIG_CPU_S3C2412)
 
 static int s3c2412_serial_setsource(struct uart_port *port,
                                     struct s3c24xx_uart_clksrc *clk)
index 3bb5d241dd40b2a13424aa42a86acba5ff4b44a3..276da148c57e015a6a148ec60a028d3d2e840ba6 100644 (file)
@@ -371,7 +371,8 @@ uart_get_baud_rate(struct uart_port *port, struct ktermios *termios,
                 */
                termios->c_cflag &= ~CBAUD;
                if (old) {
-                       termios->c_cflag |= old->c_cflag & CBAUD;
+                       baud = tty_termios_baud_rate(old);
+                       tty_termios_encode_baud_rate(termios, baud, baud);
                        old = NULL;
                        continue;
                }
@@ -380,7 +381,7 @@ uart_get_baud_rate(struct uart_port *port, struct ktermios *termios,
                 * As a last resort, if the quotient is zero,
                 * default to 9600 bps
                 */
-               termios->c_cflag |= B9600;
+               tty_termios_encode_baud_rate(termios, 9600, 9600);
        }
 
        return 0;
@@ -1977,6 +1978,7 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *port)
 
        if (state->info && state->info->flags & UIF_INITIALIZED) {
                const struct uart_ops *ops = port->ops;
+               int tries;
 
                state->info->flags = (state->info->flags & ~UIF_INITIALIZED)
                                     | UIF_SUSPENDED;
@@ -1990,9 +1992,14 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *port)
                /*
                 * Wait for the transmitter to empty.
                 */
-               while (!ops->tx_empty(port)) {
+               for (tries = 3; !ops->tx_empty(port) && tries; tries--) {
                        msleep(10);
                }
+               if (!tries)
+                       printk(KERN_ERR "%s%s%s%d: Unable to drain transmitter\n",
+                              port->dev ? port->dev->bus_id : "",
+                              port->dev ? ": " : "",
+                              drv->dev_name, port->line);
 
                ops->shutdown(port);
        }
@@ -2029,8 +2036,6 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *port)
        }
        port->suspended = 0;
 
-       uart_change_pm(state, 0);
-
        /*
         * Re-enable the console device after suspending.
         */
@@ -2049,6 +2054,7 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *port)
                if (state->info && state->info->tty && termios.c_cflag == 0)
                        termios = *state->info->tty->termios;
 
+               uart_change_pm(state, 0);
                port->ops->set_termios(port, &termios, NULL);
                console_start(port->cons);
        }
@@ -2057,6 +2063,7 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *port)
                const struct uart_ops *ops = port->ops;
                int ret;
 
+               uart_change_pm(state, 0);
                ops->set_mctrl(port, 0);
                ret = ops->startup(port);
                if (ret == 0) {
@@ -2150,10 +2157,11 @@ uart_configure_port(struct uart_driver *drv, struct uart_state *state,
 
                /*
                 * Ensure that the modem control lines are de-activated.
+                * keep the DTR setting that is set in uart_set_options()
                 * We probably don't need a spinlock around this, but
                 */
                spin_lock_irqsave(&port->lock, flags);
-               port->ops->set_mctrl(port, 0);
+               port->ops->set_mctrl(port, port->mctrl & TIOCM_DTR);
                spin_unlock_irqrestore(&port->lock, flags);
 
                /*
index d8b660061c1339855edb1d56af7e87a71490192d..164d2a42eb59fe5a5a58e9ea26d13830d493a28c 100644 (file)
@@ -389,7 +389,7 @@ static void serial_detach(struct pcmcia_device *link)
 /*====================================================================*/
 
 static int setup_serial(struct pcmcia_device *handle, struct serial_info * info,
-                       kio_addr_t iobase, int irq)
+                       unsigned int iobase, int irq)
 {
        struct uart_port port;
        int line;
@@ -456,7 +456,7 @@ next_tuple(struct pcmcia_device *handle, tuple_t * tuple, cisparse_t * parse)
 
 static int simple_config(struct pcmcia_device *link)
 {
-       static const kio_addr_t base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 };
+       static const unsigned int base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 };
        static const int size_table[2] = { 8, 16 };
        struct serial_info *info = link->priv;
        struct serial_cfg_mem *cfg_mem;
@@ -480,7 +480,7 @@ static int simple_config(struct pcmcia_device *link)
        /* If the card is already configured, look up the port and irq */
        i = pcmcia_get_configuration_info(link, &config);
        if ((i == CS_SUCCESS) && (config.Attributes & CONF_VALID_CLIENT)) {
-               kio_addr_t port = 0;
+               unsigned int port = 0;
                if ((config.BasePort2 != 0) && (config.NumPorts2 == 8)) {
                        port = config.BasePort2;
                        info->slave = 1;
index 2cd8573fb09c0a5f514440de93c8dd6459e6ed6e..639963eb1ac124d21d53628e052e10ac5be3f59d 100644 (file)
 #define SPI_FIFO_BYTE_WIDTH            (2)
 #define SPI_FIFO_OVERFLOW_MARGIN       (2)
 
-/* DMA burst lenght for half full/empty request trigger */
+/* DMA burst length for half full/empty request trigger */
 #define SPI_DMA_BLR                    (SPI_FIFO_DEPTH * SPI_FIFO_BYTE_WIDTH / 2)
 
 /* Dummy char output to achieve reads.
index 1a31f7a72848d0cb8329c95c73b94f18efe27b51..2d27d6d6d08ebe40fdf4b02e4c4a66b601307e11 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Broadcom 43xx PCI-SSB bridge module
  *
- * This technically is a seperate PCI driver module, but
+ * This technically is a separate PCI driver module, but
  * because of its small size we include it in the SSB core
  * instead of creating a standalone module.
  *
index 7a6499008b897e65450b16bdee378cffe7f54856..755823cdf62a992b83d24fb894d186ed58e0761e 100644 (file)
@@ -42,6 +42,10 @@ config USB_ARCH_HAS_OHCI
        default y if PPC_MPC52xx
        # MIPS:
        default y if SOC_AU1X00
+       # SH:
+       default y if CPU_SUBTYPE_SH7720
+       default y if CPU_SUBTYPE_SH7721
+       default y if CPU_SUBTYPE_SH7763
        # more:
        default PCI
 
@@ -50,6 +54,7 @@ config USB_ARCH_HAS_EHCI
        boolean
        default y if PPC_83xx
        default y if SOC_AU1200
+       default y if ARCH_IXP4XX
        default PCI
 
 # ARM SA1111 chips have a non-PCI based "OHCI-compatible" USB host interface.
index b450cbaa3a0baf91d445c5a43b0dd8d66b701646..86e64035edb01b04ec7439c1c450bad641a14085 100644 (file)
@@ -2,10 +2,7 @@
 # USB/ATM DSL configuration
 #
 
-menu "USB DSL modem support"
-       depends on USB
-
-config USB_ATM
+menuconfig USB_ATM
        tristate "USB DSL modem support"
        depends on USB && ATM
        select CRC32
@@ -18,6 +15,8 @@ config USB_ATM
          To compile this driver as a module, choose M here: the
          module will be called usbatm.
 
+if USB_ATM
+
 config USB_SPEEDTOUCH
        tristate "Speedtouch USB support"
        depends on USB_ATM
@@ -70,4 +69,4 @@ config USB_XUSBATM
          To compile this driver as a module, choose M here: the
          module will be called xusbatm.
 
-endmenu
+endif # USB_ATM
index 389c5b164eb2557a89775fbd9785540647c0af21..c5ec1a55eee3e9956806a1b48222fc67dc6e76f4 100644 (file)
@@ -999,7 +999,7 @@ static void __uea_load_page_e4(struct uea_softc *sc, u8 pageno, int boot)
                bi.dwAddress = swab32(blockidx->PageAddress);
 
                uea_dbg(INS_TO_USBDEV(sc),
-                      "sending block %u for DSP page %u size %u adress %x\n",
+                      "sending block %u for DSP page %u size %u address %x\n",
                       blockno, pageno, blocksize, le32_to_cpu(blockidx->PageAddress));
 
                /* send block info through the IDMA pipe */
@@ -1990,7 +1990,7 @@ static void uea_dispatch_cmv_e1(struct uea_softc *sc, struct intr_pkt *intr)
        return;
 
 bad2:
-       uea_err(INS_TO_USBDEV(sc), "unexpected cmv received,"
+       uea_err(INS_TO_USBDEV(sc), "unexpected cmv received, "
                        "Function : %d, Subfunction : %d\n",
                        E1_FUNCTION_TYPE(cmv->bFunction),
                        E1_FUNCTION_SUBTYPE(cmv->bFunction));
@@ -2038,7 +2038,7 @@ static void uea_dispatch_cmv_e4(struct uea_softc *sc, struct intr_pkt *intr)
        return;
 
 bad2:
-       uea_err(INS_TO_USBDEV(sc), "unexpected cmv received,"
+       uea_err(INS_TO_USBDEV(sc), "unexpected cmv received, "
                        "Function : %d, Subfunction : %d\n",
                        E4_FUNCTION_TYPE(cmv->wFunction),
                        E4_FUNCTION_SUBTYPE(cmv->wFunction));
index 912d97aaf9bf7b7ad52068dc850a8332aa4a76e5..bcc42136c93fcc15d31b193317163805de50dd50 100644 (file)
@@ -496,10 +496,19 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp)
           otherwise it is scheduled, and with high data rates data can get lost. */
        tty->low_latency = 1;
 
+       if (usb_autopm_get_interface(acm->control)) {
+               mutex_unlock(&open_mutex);
+               return -EIO;
+       }
+
+       mutex_lock(&acm->mutex);
+       mutex_unlock(&open_mutex);
        if (acm->used++) {
+               usb_autopm_put_interface(acm->control);
                goto done;
         }
 
+
        acm->ctrlurb->dev = acm->dev;
        if (usb_submit_urb(acm->ctrlurb, GFP_KERNEL)) {
                dbg("usb_submit_urb(ctrl irq) failed");
@@ -526,14 +535,15 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp)
 
 done:
 err_out:
-       mutex_unlock(&open_mutex);
+       mutex_unlock(&acm->mutex);
        return rv;
 
 full_bailout:
        usb_kill_urb(acm->ctrlurb);
 bail_out:
+       usb_autopm_put_interface(acm->control);
        acm->used--;
-       mutex_unlock(&open_mutex);
+       mutex_unlock(&acm->mutex);
        return -EIO;
 }
 
@@ -570,6 +580,7 @@ static void acm_tty_close(struct tty_struct *tty, struct file *filp)
                        usb_kill_urb(acm->writeurb);
                        for (i = 0; i < nr; i++)
                                usb_kill_urb(acm->ru[i].urb);
+                       usb_autopm_put_interface(acm->control);
                } else
                        acm_tty_unregister(acm);
        }
@@ -904,7 +915,7 @@ next_desc:
        }
        
        if (data_interface_num != call_interface_num)
-               dev_dbg(&intf->dev,"Seperate call control interface. That is not fully supported.\n");
+               dev_dbg(&intf->dev,"Separate call control interface. That is not fully supported.\n");
 
 skip_normal_probe:
 
@@ -980,6 +991,7 @@ skip_normal_probe:
        spin_lock_init(&acm->throttle_lock);
        spin_lock_init(&acm->write_lock);
        spin_lock_init(&acm->read_lock);
+       mutex_init(&acm->mutex);
        acm->write_ready = 1;
        acm->rx_endpoint = usb_rcvbulkpipe(usb_dev, epread->bEndpointAddress);
 
@@ -1096,6 +1108,25 @@ alloc_fail:
        return -ENOMEM;
 }
 
+static void stop_data_traffic(struct acm *acm)
+{
+       int i;
+
+       tasklet_disable(&acm->urb_task);
+
+       usb_kill_urb(acm->ctrlurb);
+       usb_kill_urb(acm->writeurb);
+       for (i = 0; i < acm->rx_buflimit; i++)
+               usb_kill_urb(acm->ru[i].urb);
+
+       INIT_LIST_HEAD(&acm->filled_read_bufs);
+       INIT_LIST_HEAD(&acm->spare_read_bufs);
+
+       tasklet_enable(&acm->urb_task);
+
+       cancel_work_sync(&acm->work);
+}
+
 static void acm_disconnect(struct usb_interface *intf)
 {
        struct acm *acm = usb_get_intfdata(intf);
@@ -1123,19 +1154,7 @@ static void acm_disconnect(struct usb_interface *intf)
        usb_set_intfdata(acm->control, NULL);
        usb_set_intfdata(acm->data, NULL);
 
-       tasklet_disable(&acm->urb_task);
-
-       usb_kill_urb(acm->ctrlurb);
-       usb_kill_urb(acm->writeurb);
-       for (i = 0; i < acm->rx_buflimit; i++)
-               usb_kill_urb(acm->ru[i].urb);
-
-       INIT_LIST_HEAD(&acm->filled_read_bufs);
-       INIT_LIST_HEAD(&acm->spare_read_bufs);
-
-       tasklet_enable(&acm->urb_task);
-
-       flush_scheduled_work(); /* wait for acm_softint */
+       stop_data_traffic(acm);
 
        acm_write_buffers_free(acm);
        usb_buffer_free(usb_dev, acm->ctrlsize, acm->ctrl_buffer, acm->ctrl_dma);
@@ -1156,6 +1175,46 @@ static void acm_disconnect(struct usb_interface *intf)
                tty_hangup(acm->tty);
 }
 
+static int acm_suspend(struct usb_interface *intf, pm_message_t message)
+{
+       struct acm *acm = usb_get_intfdata(intf);
+
+       if (acm->susp_count++)
+               return 0;
+       /*
+       we treat opened interfaces differently,
+       we must guard against open
+       */
+       mutex_lock(&acm->mutex);
+
+       if (acm->used)
+               stop_data_traffic(acm);
+
+       mutex_unlock(&acm->mutex);
+       return 0;
+}
+
+static int acm_resume(struct usb_interface *intf)
+{
+       struct acm *acm = usb_get_intfdata(intf);
+       int rv = 0;
+
+       if (--acm->susp_count)
+               return 0;
+
+       mutex_lock(&acm->mutex);
+       if (acm->used) {
+               rv = usb_submit_urb(acm->ctrlurb, GFP_NOIO);
+               if (rv < 0)
+               goto err_out;
+
+               tasklet_schedule(&acm->urb_task);
+       }
+
+err_out:
+       mutex_unlock(&acm->mutex);
+       return rv;
+}
 /*
  * USB driver structure.
  */
@@ -1208,7 +1267,10 @@ static struct usb_driver acm_driver = {
        .name =         "cdc_acm",
        .probe =        acm_probe,
        .disconnect =   acm_disconnect,
+       .suspend =      acm_suspend,
+       .resume =       acm_resume,
        .id_table =     acm_ids,
+       .supports_autosuspend = 1,
 };
 
 /*
index 09f7765dbf8dc74ad223f42a3455d4dddb221c8d..8df6a57dcf9e4ca188b368f62ca2f0b4b86df4c6 100644 (file)
@@ -107,6 +107,7 @@ struct acm {
        int write_used;                                 /* number of non-empty write buffers */
        int write_ready;                                /* write urb is not running */
        spinlock_t write_lock;
+       struct mutex mutex;
        struct usb_cdc_line_coding line;                /* bits, stop, parity */
        struct work_struct work;                        /* work queue entry for line discipline waking up */
        struct tasklet_struct urb_task;                 /* rx processing */
@@ -120,6 +121,7 @@ struct acm {
        unsigned char throttle;                         /* throttled by tty layer */
        unsigned char clocal;                           /* termios CLOCAL */
        unsigned int ctrl_caps;                         /* control capabilities from the class specific header */
+       unsigned int susp_count;                        /* number of suspended interfaces */
 };
 
 #define CDC_DATA_INTERFACE_TYPE        0x0a
index 97b09f282705bb4c4249e733d89ea3ca43876cd2..5c33cdb9cac7131a0e4d2715ecbcec538903406f 100644 (file)
@@ -9,6 +9,21 @@ config USB_DEBUG
          of debug messages to the system log. Select this if you are having a
          problem with USB support and want to see more of what is going on.
 
+config USB_ANNOUNCE_NEW_DEVICES
+       bool "USB announce new devices"
+       depends on USB
+       default N
+       help
+         Say Y here if you want the USB core to always announce the
+         idVendor, idProduct, Manufacturer, Product, and SerialNumber
+         strings for every new USB device to the syslog.  This option is
+         usually used by distro vendors to help with debugging and to
+         let users know what specific device was added to the machine
+         in what location.
+
+         If you do not want this kind of information sent to the system
+         log, or have any doubts about this, say N here.
+
 comment "Miscellaneous USB options"
        depends on USB
 
index 28d4972f7ad5493f449dd1ae0fe07cab446bb264..cadb2dc1d28ae4ccee6cec683979938d874f6008 100644 (file)
@@ -53,11 +53,13 @@ int hcd_buffer_create(struct usb_hcd *hcd)
        char            name[16];
        int             i, size;
 
-       if (!hcd->self.controller->dma_mask)
+       if (!hcd->self.controller->dma_mask &&
+           !(hcd->driver->flags & HCD_LOCAL_MEM))
                return 0;
 
-       for (i = 0; i < HCD_BUFFER_POOLS; i++) { 
-               if (!(size = pool_max [i]))
+       for (i = 0; i < HCD_BUFFER_POOLS; i++) {
+               size = pool_max[i];
+               if (!size)
                        continue;
                snprintf(name, sizeof name, "buffer-%d", size);
                hcd->pool[i] = dma_pool_create(name, hcd->self.controller,
@@ -80,10 +82,10 @@ int hcd_buffer_create(struct usb_hcd *hcd)
  */
 void hcd_buffer_destroy(struct usb_hcd *hcd)
 {
-       int             i;
+       int i;
 
-       for (i = 0; i < HCD_BUFFER_POOLS; i++) { 
-               struct dma_pool         *pool = hcd->pool[i];
+       for (i = 0; i < HCD_BUFFER_POOLS; i++) {
+               struct dma_pool *pool = hcd->pool[i];
                if (pool) {
                        dma_pool_destroy(pool);
                        hcd->pool[i] = NULL;
@@ -107,7 +109,8 @@ void *hcd_buffer_alloc(
        int                     i;
 
        /* some USB hosts just use PIO */
-       if (!bus->controller->dma_mask) {
+       if (!bus->controller->dma_mask &&
+           !(hcd->driver->flags & HCD_LOCAL_MEM)) {
                *dma = ~(dma_addr_t) 0;
                return kmalloc(size, mem_flags);
        }
@@ -132,7 +135,8 @@ void hcd_buffer_free(
        if (!addr)
                return;
 
-       if (!bus->controller->dma_mask) {
+       if (!bus->controller->dma_mask &&
+           !(hcd->driver->flags & HCD_LOCAL_MEM)) {
                kfree(addr);
                return;
        }
index 1a8edcee7f303af3d1f3a5c6931ca5f9a7620dc0..a92122a216bcc8dbb4f7ea092fa3108cdaaba36a 100644 (file)
@@ -238,7 +238,7 @@ static int usb_parse_interface(struct device *ddev, int cfgno,
 
        /* Allocate space for the right(?) number of endpoints */
        num_ep = num_ep_orig = alt->desc.bNumEndpoints;
-       alt->desc.bNumEndpoints = 0;            // Use as a counter
+       alt->desc.bNumEndpoints = 0;            /* Use as a counter */
        if (num_ep > USB_MAXENDPOINTS) {
                dev_warn(ddev, "too many endpoints for config %d interface %d "
                    "altsetting %d: %d, using maximum allowed: %d\n",
@@ -246,7 +246,8 @@ static int usb_parse_interface(struct device *ddev, int cfgno,
                num_ep = USB_MAXENDPOINTS;
        }
 
-       if (num_ep > 0) {       /* Can't allocate 0 bytes */
+       if (num_ep > 0) {
+               /* Can't allocate 0 bytes */
                len = sizeof(struct usb_host_endpoint) * num_ep;
                alt->endpoint = kzalloc(len, GFP_KERNEL);
                if (!alt->endpoint)
@@ -475,8 +476,9 @@ static int usb_parse_configuration(struct device *ddev, int cfgidx,
        return 0;
 }
 
-// hub-only!! ... and only exported for reset/reinit path.
-// otherwise used internally on disconnect/destroy path
+/* hub-only!! ... and only exported for reset/reinit path.
+ * otherwise used internally on disconnect/destroy path
+ */
 void usb_destroy_configuration(struct usb_device *dev)
 {
        int c, i;
@@ -498,7 +500,7 @@ void usb_destroy_configuration(struct usb_device *dev)
                kfree(cf->string);
                for (i = 0; i < cf->desc.bNumInterfaces; i++) {
                        if (cf->intf_cache[i])
-                               kref_put(&cf->intf_cache[i]->ref, 
+                               kref_put(&cf->intf_cache[i]->ref,
                                          usb_release_interface_cache);
                }
        }
@@ -525,7 +527,7 @@ int usb_get_configuration(struct usb_device *dev)
        unsigned int cfgno, length;
        unsigned char *buffer;
        unsigned char *bigbuffer;
-       struct usb_config_descriptor *desc;
+       struct usb_config_descriptor *desc;
 
        cfgno = 0;
        if (dev->authorized == 0)       /* Not really an error */
index 87c794d60aa021ee3b6f1108e2cef34fb519f4c4..83d9dc379d968c7ecc87f759251f16e926ff4d89 100644 (file)
@@ -89,7 +89,7 @@ static const char *format_string_serialnumber =
 static const char *format_bandwidth =
 /* B:  Alloc=ddd/ddd us (xx%), #Int=ddd, #Iso=ddd */
   "B:  Alloc=%3d/%3d us (%2d%%), #Int=%3d, #Iso=%3d\n";
-  
+
 static const char *format_device1 =
 /* D:  Ver=xx.xx Cls=xx(sssss) Sub=xx Prot=xx MxPS=dd #Cfgs=dd */
   "D:  Ver=%2x.%02x Cls=%02x(%-5s) Sub=%02x Prot=%02x MxPS=%2d #Cfgs=%3d\n";
@@ -101,7 +101,7 @@ static const char *format_device2 =
 static const char *format_config =
 /* C:  #Ifs=dd Cfg#=dd Atr=xx MPwr=dddmA */
   "C:%c #Ifs=%2d Cfg#=%2d Atr=%02x MxPwr=%3dmA\n";
-  
+
 static const char *format_iad =
 /* A:  FirstIf#=dd IfCount=dd Cls=xx(sssss) Sub=xx Prot=xx */
   "A:  FirstIf#=%2d IfCount=%2d Cls=%02x(%-5s) Sub=%02x Prot=%02x\n";
@@ -122,7 +122,7 @@ static const char *format_endpt =
  */
 
 static DECLARE_WAIT_QUEUE_HEAD(deviceconndiscwq);
-static unsigned int conndiscevcnt = 0;
+static unsigned int conndiscevcnt;
 
 /* this struct stores the poll state for <mountpoint>/devices pollers */
 struct usb_device_status {
@@ -172,12 +172,8 @@ static const char *class_decode(const int class)
        return clas_info[ix].class_name;
 }
 
-static char *usb_dump_endpoint_descriptor(
-       int speed,
-       char *start,
-       char *end,
-       const struct usb_endpoint_descriptor *desc
-)
+static char *usb_dump_endpoint_descriptor(int speed, char *start, char *end,
+                               const struct usb_endpoint_descriptor *desc)
 {
        char dir, unit, *type;
        unsigned interval, bandwidth = 1;
@@ -235,22 +231,24 @@ static char *usb_dump_endpoint_descriptor(
 
        start += sprintf(start, format_endpt, desc->bEndpointAddress, dir,
                         desc->bmAttributes, type,
-                        (le16_to_cpu(desc->wMaxPacketSize) & 0x07ff) * bandwidth,
+                        (le16_to_cpu(desc->wMaxPacketSize) & 0x07ff) *
+                        bandwidth,
                         interval, unit);
        return start;
 }
 
 static char *usb_dump_interface_descriptor(char *start, char *end,
-       const struct usb_interface_cache *intfc,
-       const struct usb_interface *iface,
-       int setno)
+                                       const struct usb_interface_cache *intfc,
+                                       const struct usb_interface *iface,
+                                       int setno)
 {
-       const struct usb_interface_descriptor *desc = &intfc->altsetting[setno].desc;
+       const struct usb_interface_descriptor *desc;
        const char *driver_name = "";
        int active = 0;
 
        if (start > end)
                return start;
+       desc = &intfc->altsetting[setno].desc;
        if (iface) {
                driver_name = (iface->dev.driver
                                ? iface->dev.driver->name
@@ -270,14 +268,10 @@ static char *usb_dump_interface_descriptor(char *start, char *end,
        return start;
 }
 
-static char *usb_dump_interface(
-       int speed,
-       char *start,
-       char *end,
-       const struct usb_interface_cache *intfc,
-       const struct usb_interface *iface,
-       int setno
-) {
+static char *usb_dump_interface(int speed, char *start, char *end,
+                               const struct usb_interface_cache *intfc,
+                               const struct usb_interface *iface, int setno)
+{
        const struct usb_host_interface *desc = &intfc->altsetting[setno];
        int i;
 
@@ -292,7 +286,7 @@ static char *usb_dump_interface(
 }
 
 static char *usb_dump_iad_descriptor(char *start, char *end,
-       const struct usb_interface_assoc_descriptor *iad)
+                       const struct usb_interface_assoc_descriptor *iad)
 {
        if (start > end)
                return start;
@@ -311,13 +305,15 @@ static char *usb_dump_iad_descriptor(char *start, char *end,
  * 1. marking active interface altsettings (code lists all, but should mark
  *    which ones are active, if any)
  */
-
-static char *usb_dump_config_descriptor(char *start, char *end, const struct usb_config_descriptor *desc, int active)
+static char *usb_dump_config_descriptor(char *start, char *end,
+                               const struct usb_config_descriptor *desc,
+                               int active)
 {
        if (start > end)
                return start;
        start += sprintf(start, format_config,
-                        active ? '*' : ' ',    /* mark active/actual/current cfg. */
+                        /* mark active/actual/current cfg. */
+                        active ? '*' : ' ',
                         desc->bNumInterfaces,
                         desc->bConfigurationValue,
                         desc->bmAttributes,
@@ -325,13 +321,8 @@ static char *usb_dump_config_descriptor(char *start, char *end, const struct usb
        return start;
 }
 
-static char *usb_dump_config (
-       int speed,
-       char *start,
-       char *end,
-       const struct usb_host_config *config,
-       int active
-)
+static char *usb_dump_config(int speed, char *start, char *end,
+                            const struct usb_host_config *config, int active)
 {
        int i, j;
        struct usb_interface_cache *intfc;
@@ -339,7 +330,8 @@ static char *usb_dump_config (
 
        if (start > end)
                return start;
-       if (!config)            /* getting these some in 2.3.7; none in 2.3.6 */
+       if (!config)
+               /* getting these some in 2.3.7; none in 2.3.6 */
                return start + sprintf(start, "(null Cfg. desc.)\n");
        start = usb_dump_config_descriptor(start, end, &config->desc, active);
        for (i = 0; i < USB_MAXIADS; i++) {
@@ -364,7 +356,8 @@ static char *usb_dump_config (
 /*
  * Dump the different USB descriptors.
  */
-static char *usb_dump_device_descriptor(char *start, char *end, const struct usb_device_descriptor *desc)
+static char *usb_dump_device_descriptor(char *start, char *end,
+                               const struct usb_device_descriptor *desc)
 {
        u16 bcdUSB = le16_to_cpu(desc->bcdUSB);
        u16 bcdDevice = le16_to_cpu(desc->bcdDevice);
@@ -374,7 +367,7 @@ static char *usb_dump_device_descriptor(char *start, char *end, const struct usb
        start += sprintf(start, format_device1,
                          bcdUSB >> 8, bcdUSB & 0xff,
                          desc->bDeviceClass,
-                         class_decode (desc->bDeviceClass),
+                         class_decode(desc->bDeviceClass),
                          desc->bDeviceSubClass,
                          desc->bDeviceProtocol,
                          desc->bMaxPacketSize0,
@@ -391,12 +384,14 @@ static char *usb_dump_device_descriptor(char *start, char *end, const struct usb
 /*
  * Dump the different strings that this device holds.
  */
-static char *usb_dump_device_strings(char *start, char *end, struct usb_device *dev)
+static char *usb_dump_device_strings(char *start, char *end,
+                                    struct usb_device *dev)
 {
        if (start > end)
                return start;
        if (dev->manufacturer)
-               start += sprintf(start, format_string_manufacturer, dev->manufacturer);
+               start += sprintf(start, format_string_manufacturer,
+                                dev->manufacturer);
        if (start > end)
                goto out;
        if (dev->product)
@@ -405,7 +400,8 @@ static char *usb_dump_device_strings(char *start, char *end, struct usb_device *
                goto out;
 #ifdef ALLOW_SERIAL_NUMBER
        if (dev->serial)
-               start += sprintf(start, format_string_serialnumber, dev->serial);
+               start += sprintf(start, format_string_serialnumber,
+                                dev->serial);
 #endif
  out:
        return start;
@@ -417,12 +413,12 @@ static char *usb_dump_desc(char *start, char *end, struct usb_device *dev)
 
        if (start > end)
                return start;
-               
+
        start = usb_dump_device_descriptor(start, end, &dev->descriptor);
 
        if (start > end)
                return start;
-       
+
        start = usb_dump_device_strings(start, end, dev);
 
        for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
@@ -439,7 +435,8 @@ static char *usb_dump_desc(char *start, char *end, struct usb_device *dev)
 
 #ifdef PROC_EXTRA /* TBD: may want to add this code later */
 
-static char *usb_dump_hub_descriptor(char *start, char *end, const struct usb_hub_descriptor * desc)
+static char *usb_dump_hub_descriptor(char *start, char *end,
+                                    const struct usb_hub_descriptor *desc)
 {
        int leng = USB_DT_HUB_NONVAR_SIZE;
        unsigned char *ptr = (unsigned char *)desc;
@@ -455,13 +452,16 @@ static char *usb_dump_hub_descriptor(char *start, char *end, const struct usb_hu
        return start;
 }
 
-static char *usb_dump_string(char *start, char *end, const struct usb_device *dev, char *id, int index)
+static char *usb_dump_string(char *start, char *end,
+                            const struct usb_device *dev, char *id, int index)
 {
        if (start > end)
                return start;
        start += sprintf(start, "Interface:");
-       if (index <= dev->maxstring && dev->stringindex && dev->stringindex[index])
-               start += sprintf(start, "%s: %.100s ", id, dev->stringindex[index]);
+       if (index <= dev->maxstring && dev->stringindex &&
+           dev->stringindex[index])
+               start += sprintf(start, "%s: %.100s ", id,
+                                dev->stringindex[index]);
        return start;
 }
 
@@ -476,8 +476,10 @@ static char *usb_dump_string(char *start, char *end, const struct usb_device *de
  * file_offset - the offset into the devices file on completion
  * The caller must own the device lock.
  */
-static ssize_t usb_device_dump(char __user **buffer, size_t *nbytes, loff_t *skip_bytes, loff_t *file_offset,
-                               struct usb_device *usbdev, struct usb_bus *bus, int level, int index, int count)
+static ssize_t usb_device_dump(char __user **buffer, size_t *nbytes,
+                              loff_t *skip_bytes, loff_t *file_offset,
+                              struct usb_device *usbdev, struct usb_bus *bus,
+                              int level, int index, int count)
 {
        int chix;
        int ret, cnt = 0;
@@ -485,17 +487,19 @@ static ssize_t usb_device_dump(char __user **buffer, size_t *nbytes, loff_t *ski
        char *pages_start, *data_end, *speed;
        unsigned int length;
        ssize_t total_written = 0;
-       
+
        /* don't bother with anything else if we're not writing any data */
        if (*nbytes <= 0)
                return 0;
-       
+
        if (level > MAX_TOPO_LEVEL)
                return 0;
-       /* allocate 2^1 pages = 8K (on i386); should be more than enough for one device */
-        if (!(pages_start = (char*) __get_free_pages(GFP_KERNEL,1)))
-                return -ENOMEM;
-               
+       /* allocate 2^1 pages = 8K (on i386);
+        * should be more than enough for one device */
+       pages_start = (char *)__get_free_pages(GFP_KERNEL, 1);
+       if (!pages_start)
+               return -ENOMEM;
+
        if (usbdev->parent && usbdev->parent->devnum != -1)
                parent_devnum = usbdev->parent->devnum;
        /*
@@ -541,15 +545,16 @@ static ssize_t usb_device_dump(char __user **buffer, size_t *nbytes, loff_t *ski
                                bus->bandwidth_allocated, max,
                                (100 * bus->bandwidth_allocated + max / 2)
                                        / max,
-                                bus->bandwidth_int_reqs,
-                                bus->bandwidth_isoc_reqs);
-       
+                               bus->bandwidth_int_reqs,
+                               bus->bandwidth_isoc_reqs);
+
        }
-       data_end = usb_dump_desc(data_end, pages_start + (2 * PAGE_SIZE) - 256, usbdev);
-       
+       data_end = usb_dump_desc(data_end, pages_start + (2 * PAGE_SIZE) - 256,
+                                usbdev);
+
        if (data_end > (pages_start + (2 * PAGE_SIZE) - 256))
                data_end += sprintf(data_end, "(truncated)\n");
-       
+
        length = data_end - pages_start;
        /* if we can start copying some data to the user */
        if (length > *skip_bytes) {
@@ -567,17 +572,18 @@ static ssize_t usb_device_dump(char __user **buffer, size_t *nbytes, loff_t *ski
                *skip_bytes = 0;
        } else
                *skip_bytes -= length;
-       
+
        free_pages((unsigned long)pages_start, 1);
-       
+
        /* Now look at all of this device's children. */
        for (chix = 0; chix < usbdev->maxchild; chix++) {
                struct usb_device *childdev = usbdev->children[chix];
 
                if (childdev) {
                        usb_lock_device(childdev);
-                       ret = usb_device_dump(buffer, nbytes, skip_bytes, file_offset, childdev,
-                                       bus, level + 1, chix, ++cnt);
+                       ret = usb_device_dump(buffer, nbytes, skip_bytes,
+                                             file_offset, childdev, bus,
+                                             level + 1, chix, ++cnt);
                        usb_unlock_device(childdev);
                        if (ret == -EFAULT)
                                return total_written;
@@ -587,7 +593,8 @@ static ssize_t usb_device_dump(char __user **buffer, size_t *nbytes, loff_t *ski
        return total_written;
 }
 
-static ssize_t usb_device_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
+static ssize_t usb_device_read(struct file *file, char __user *buf,
+                              size_t nbytes, loff_t *ppos)
 {
        struct usb_bus *bus;
        ssize_t ret, total_written = 0;
@@ -607,7 +614,8 @@ static ssize_t usb_device_read(struct file *file, char __user *buf, size_t nbyte
                if (!bus->root_hub)
                        continue;
                usb_lock_device(bus->root_hub);
-               ret = usb_device_dump(&buf, &nbytes, &skip_bytes, ppos, bus->root_hub, bus, 0, 0, 0);
+               ret = usb_device_dump(&buf, &nbytes, &skip_bytes, ppos,
+                                     bus->root_hub, bus, 0, 0, 0);
                usb_unlock_device(bus->root_hub);
                if (ret < 0) {
                        mutex_unlock(&usb_bus_list_lock);
@@ -620,7 +628,8 @@ static ssize_t usb_device_read(struct file *file, char __user *buf, size_t nbyte
 }
 
 /* Kernel lock for "lastev" protection */
-static unsigned int usb_device_poll(struct file *file, struct poll_table_struct *wait)
+static unsigned int usb_device_poll(struct file *file,
+                                   struct poll_table_struct *wait)
 {
        struct usb_device_status *st = file->private_data;
        unsigned int mask = 0;
@@ -629,7 +638,8 @@ static unsigned int usb_device_poll(struct file *file, struct poll_table_struct
        if (!st) {
                st = kmalloc(sizeof(struct usb_device_status), GFP_KERNEL);
 
-               /* we may have dropped BKL - need to check for having lost the race */
+               /* we may have dropped BKL -
+                * need to check for having lost the race */
                if (file->private_data) {
                        kfree(st);
                        st = file->private_data;
@@ -652,7 +662,7 @@ static unsigned int usb_device_poll(struct file *file, struct poll_table_struct
        }
 lost_race:
        if (file->f_mode & FMODE_READ)
-                poll_wait(file, &deviceconndiscwq, wait);
+               poll_wait(file, &deviceconndiscwq, wait);
        if (st->lastev != conndiscevcnt)
                mask |= POLLIN;
        st->lastev = conndiscevcnt;
@@ -662,18 +672,18 @@ lost_race:
 
 static int usb_device_open(struct inode *inode, struct file *file)
 {
-        file->private_data = NULL;
-        return 0;
+       file->private_data = NULL;
+       return 0;
 }
 
 static int usb_device_release(struct inode *inode, struct file *file)
 {
        kfree(file->private_data);
        file->private_data = NULL;
-        return 0;
+       return 0;
 }
 
-static loff_t usb_device_lseek(struct file * file, loff_t offset, int orig)
+static loff_t usb_device_lseek(struct file *file, loff_t offset, int orig)
 {
        loff_t ret;
 
index 1f4f6d02fe25598e22a62b785b1b7140913b7c12..ae94176c64e41245efa23335d6a4787741ef9e7f 100644 (file)
@@ -75,14 +75,14 @@ struct async {
        u32 secid;
 };
 
-static int usbfs_snoop = 0;
-module_param (usbfs_snoop, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC (usbfs_snoop, "true to log all usbfs traffic");
+static int usbfs_snoop;
+module_param(usbfs_snoop, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(usbfs_snoop, "true to log all usbfs traffic");
 
 #define snoop(dev, format, arg...)                             \
        do {                                                    \
                if (usbfs_snoop)                                \
-                       dev_info( dev , format , ## arg);       \
+                       dev_info(dev , format , ## arg);        \
        } while (0)
 
 #define USB_DEVICE_DEV         MKDEV(USB_DEVICE_MAJOR, 0)
@@ -90,7 +90,7 @@ MODULE_PARM_DESC (usbfs_snoop, "true to log all usbfs traffic");
 
 #define        MAX_USBFS_BUFFER_SIZE   16384
 
-static inline int connected (struct dev_state *ps)
+static inline int connected(struct dev_state *ps)
 {
        return (!list_empty(&ps->list) &&
                        ps->dev->state != USB_STATE_NOTATTACHED);
@@ -120,7 +120,8 @@ static loff_t usbdev_lseek(struct file *file, loff_t offset, int orig)
        return ret;
 }
 
-static ssize_t usbdev_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
+static ssize_t usbdev_read(struct file *file, char __user *buf, size_t nbytes,
+                          loff_t *ppos)
 {
        struct dev_state *ps = file->private_data;
        struct usb_device *dev = ps->dev;
@@ -140,7 +141,8 @@ static ssize_t usbdev_read(struct file *file, char __user *buf, size_t nbytes, l
        }
 
        if (pos < sizeof(struct usb_device_descriptor)) {
-               struct usb_device_descriptor temp_desc ; /* 18 bytes - fits on the stack */
+               /* 18 bytes - fits on the stack */
+               struct usb_device_descriptor temp_desc;
 
                memcpy(&temp_desc, &dev->descriptor, sizeof(dev->descriptor));
                le16_to_cpus(&temp_desc.bcdUSB);
@@ -210,17 +212,17 @@ err:
 
 static struct async *alloc_async(unsigned int numisoframes)
 {
-        unsigned int assize = sizeof(struct async) + numisoframes * sizeof(struct usb_iso_packet_descriptor);
-        struct async *as = kzalloc(assize, GFP_KERNEL);
+       struct async *as;
 
-        if (!as)
-                return NULL;
+       as = kzalloc(sizeof(struct async), GFP_KERNEL);
+       if (!as)
+               return NULL;
        as->urb = usb_alloc_urb(numisoframes, GFP_KERNEL);
        if (!as->urb) {
                kfree(as);
                return NULL;
        }
-        return as;
+       return as;
 }
 
 static void free_async(struct async *as)
@@ -234,52 +236,54 @@ static void free_async(struct async *as)
 
 static inline void async_newpending(struct async *as)
 {
-        struct dev_state *ps = as->ps;
-        unsigned long flags;
-        
-        spin_lock_irqsave(&ps->lock, flags);
-        list_add_tail(&as->asynclist, &ps->async_pending);
-        spin_unlock_irqrestore(&ps->lock, flags);
+       struct dev_state *ps = as->ps;
+       unsigned long flags;
+
+       spin_lock_irqsave(&ps->lock, flags);
+       list_add_tail(&as->asynclist, &ps->async_pending);
+       spin_unlock_irqrestore(&ps->lock, flags);
 }
 
 static inline void async_removepending(struct async *as)
 {
-        struct dev_state *ps = as->ps;
-        unsigned long flags;
-        
-        spin_lock_irqsave(&ps->lock, flags);
-        list_del_init(&as->asynclist);
-        spin_unlock_irqrestore(&ps->lock, flags);
+       struct dev_state *ps = as->ps;
+       unsigned long flags;
+
+       spin_lock_irqsave(&ps->lock, flags);
+       list_del_init(&as->asynclist);
+       spin_unlock_irqrestore(&ps->lock, flags);
 }
 
 static inline struct async *async_getcompleted(struct dev_state *ps)
 {
-        unsigned long flags;
-        struct async *as = NULL;
-
-        spin_lock_irqsave(&ps->lock, flags);
-        if (!list_empty(&ps->async_completed)) {
-                as = list_entry(ps->async_completed.next, struct async, asynclist);
-                list_del_init(&as->asynclist);
-        }
-        spin_unlock_irqrestore(&ps->lock, flags);
-        return as;
+       unsigned long flags;
+       struct async *as = NULL;
+
+       spin_lock_irqsave(&ps->lock, flags);
+       if (!list_empty(&ps->async_completed)) {
+               as = list_entry(ps->async_completed.next, struct async,
+                               asynclist);
+               list_del_init(&as->asynclist);
+       }
+       spin_unlock_irqrestore(&ps->lock, flags);
+       return as;
 }
 
-static inline struct async *async_getpending(struct dev_state *ps, void __user *userurb)
+static inline struct async *async_getpending(struct dev_state *ps,
+                                            void __user *userurb)
 {
-        unsigned long flags;
-        struct async *as;
+       unsigned long flags;
+       struct async *as;
 
-        spin_lock_irqsave(&ps->lock, flags);
+       spin_lock_irqsave(&ps->lock, flags);
        list_for_each_entry(as, &ps->async_pending, asynclist)
                if (as->userurb == userurb) {
                        list_del_init(&as->asynclist);
                        spin_unlock_irqrestore(&ps->lock, flags);
                        return as;
                }
-        spin_unlock_irqrestore(&ps->lock, flags);
-        return NULL;
+       spin_unlock_irqrestore(&ps->lock, flags);
+       return NULL;
 }
 
 static void snoop_urb(struct urb *urb, void __user *userurb)
@@ -298,19 +302,19 @@ static void snoop_urb(struct urb *urb, void __user *userurb)
        dev_info(&urb->dev->dev, "actual_length=%d\n", urb->actual_length);
        dev_info(&urb->dev->dev, "data: ");
        for (j = 0; j < urb->transfer_buffer_length; ++j)
-               printk ("%02x ", data[j]);
+               printk("%02x ", data[j]);
        printk("\n");
 }
 
 static void async_completed(struct urb *urb)
 {
-        struct async *as = urb->context;
-        struct dev_state *ps = as->ps;
+       struct async *as = urb->context;
+       struct dev_state *ps = as->ps;
        struct siginfo sinfo;
 
-        spin_lock(&ps->lock);
-        list_move_tail(&as->asynclist, &ps->async_completed);
-        spin_unlock(&ps->lock);
+       spin_lock(&ps->lock);
+       list_move_tail(&as->asynclist, &ps->async_completed);
+       spin_unlock(&ps->lock);
        as->status = urb->status;
        if (as->signr) {
                sinfo.si_signo = as->signr;
@@ -325,7 +329,7 @@ static void async_completed(struct urb *urb)
        wake_up(&ps->wait);
 }
 
-static void destroy_async (struct dev_state *ps, struct list_head *list)
+static void destroy_async(struct dev_state *ps, struct list_head *list)
 {
        struct async *as;
        unsigned long flags;
@@ -348,7 +352,8 @@ static void destroy_async (struct dev_state *ps, struct list_head *list)
        }
 }
 
-static void destroy_async_on_interface (struct dev_state *ps, unsigned int ifnum)
+static void destroy_async_on_interface(struct dev_state *ps,
+                                      unsigned int ifnum)
 {
        struct list_head *p, *q, hitlist;
        unsigned long flags;
@@ -364,7 +369,7 @@ static void destroy_async_on_interface (struct dev_state *ps, unsigned int ifnum
 
 static inline void destroy_all_async(struct dev_state *ps)
 {
-               destroy_async(ps, &ps->async_pending);
+       destroy_async(ps, &ps->async_pending);
 }
 
 /*
@@ -373,15 +378,15 @@ static inline void destroy_all_async(struct dev_state *ps)
  * they're also undone when devices disconnect.
  */
 
-static int driver_probe (struct usb_interface *intf,
-                        const struct usb_device_id *id)
+static int driver_probe(struct usb_interface *intf,
+                       const struct usb_device_id *id)
 {
        return -ENODEV;
 }
 
 static void driver_disconnect(struct usb_interface *intf)
 {
-       struct dev_state *ps = usb_get_intfdata (intf);
+       struct dev_state *ps = usb_get_intfdata(intf);
        unsigned int ifnum = intf->altsetting->desc.bInterfaceNumber;
 
        if (!ps)
@@ -396,16 +401,31 @@ static void driver_disconnect(struct usb_interface *intf)
        else
                warn("interface number %u out of range", ifnum);
 
-       usb_set_intfdata (intf, NULL);
+       usb_set_intfdata(intf, NULL);
 
        /* force async requests to complete */
        destroy_async_on_interface(ps, ifnum);
 }
 
+/* The following routines are merely placeholders.  There is no way
+ * to inform a user task about suspend or resumes.
+ */
+static int driver_suspend(struct usb_interface *intf, pm_message_t msg)
+{
+       return 0;
+}
+
+static int driver_resume(struct usb_interface *intf)
+{
+       return 0;
+}
+
 struct usb_driver usbfs_driver = {
        .name =         "usbfs",
        .probe =        driver_probe,
        .disconnect =   driver_disconnect,
+       .suspend =      driver_suspend,
+       .resume =       driver_resume,
 };
 
 static int claimintf(struct dev_state *ps, unsigned int ifnum)
@@ -459,15 +479,16 @@ static int checkintf(struct dev_state *ps, unsigned int ifnum)
        if (test_bit(ifnum, &ps->ifclaimed))
                return 0;
        /* if not yet claimed, claim it for the driver */
-       dev_warn(&ps->dev->dev, "usbfs: process %d (%s) did not claim interface %u before use\n",
-              task_pid_nr(current), current->comm, ifnum);
+       dev_warn(&ps->dev->dev, "usbfs: process %d (%s) did not claim "
+                "interface %u before use\n", task_pid_nr(current),
+                current->comm, ifnum);
        return claimintf(ps, ifnum);
 }
 
 static int findintfep(struct usb_device *dev, unsigned int ep)
 {
        unsigned int i, j, e;
-        struct usb_interface *intf;
+       struct usb_interface *intf;
        struct usb_host_interface *alts;
        struct usb_endpoint_descriptor *endpt;
 
@@ -478,7 +499,7 @@ static int findintfep(struct usb_device *dev, unsigned int ep)
        for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) {
                intf = dev->actconfig->interface[i];
                for (j = 0; j < intf->num_altsetting; j++) {
-                        alts = &intf->altsetting[j];
+                       alts = &intf->altsetting[j];
                        for (e = 0; e < alts->desc.bNumEndpoints; e++) {
                                endpt = &alts->endpoint[e].desc;
                                if (endpt->bEndpointAddress == ep)
@@ -486,10 +507,11 @@ static int findintfep(struct usb_device *dev, unsigned int ep)
                        }
                }
        }
-       return -ENOENT; 
+       return -ENOENT;
 }
 
-static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype, unsigned int index)
+static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype,
+                          unsigned int index)
 {
        int ret = 0;
 
@@ -502,7 +524,8 @@ static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype, unsig
        index &= 0xff;
        switch (requesttype & USB_RECIP_MASK) {
        case USB_RECIP_ENDPOINT:
-               if ((ret = findintfep(ps->dev, index)) >= 0)
+               ret = findintfep(ps->dev, index);
+               if (ret >= 0)
                        ret = checkintf(ps, ret);
                break;
 
@@ -546,7 +569,8 @@ static int usbdev_open(struct inode *inode, struct file *file)
        mutex_lock(&usbfs_mutex);
 
        ret = -ENOMEM;
-       if (!(ps = kmalloc(sizeof(struct dev_state), GFP_KERNEL)))
+       ps = kmalloc(sizeof(struct dev_state), GFP_KERNEL);
+       if (!ps)
                goto out;
 
        ret = -ENOENT;
@@ -627,15 +651,18 @@ static int proc_control(struct dev_state *ps, void __user *arg)
 
        if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
                return -EFAULT;
-       if ((ret = check_ctrlrecip(ps, ctrl.bRequestType, ctrl.wIndex)))
+       ret = check_ctrlrecip(ps, ctrl.bRequestType, ctrl.wIndex);
+       if (ret)
                return ret;
        if (ctrl.wLength > PAGE_SIZE)
                return -EINVAL;
-       if (!(tbuf = (unsigned char *)__get_free_page(GFP_KERNEL)))
+       tbuf = (unsigned char *)__get_free_page(GFP_KERNEL);
+       if (!tbuf)
                return -ENOMEM;
        tmo = ctrl.timeout;
        if (ctrl.bRequestType & 0x80) {
-               if (ctrl.wLength && !access_ok(VERIFY_WRITE, ctrl.data, ctrl.wLength)) {
+               if (ctrl.wLength && !access_ok(VERIFY_WRITE, ctrl.data,
+                                              ctrl.wLength)) {
                        free_page((unsigned long)tbuf);
                        return -EINVAL;
                }
@@ -646,14 +673,15 @@ static int proc_control(struct dev_state *ps, void __user *arg)
                                ctrl.wIndex, ctrl.wLength);
 
                usb_unlock_device(dev);
-               i = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), ctrl.bRequest, ctrl.bRequestType,
-                                      ctrl.wValue, ctrl.wIndex, tbuf, ctrl.wLength, tmo);
+               i = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), ctrl.bRequest,
+                                   ctrl.bRequestType, ctrl.wValue, ctrl.wIndex,
+                                   tbuf, ctrl.wLength, tmo);
                usb_lock_device(dev);
                if ((i > 0) && ctrl.wLength) {
                        if (usbfs_snoop) {
                                dev_info(&dev->dev, "control read: data ");
                                for (j = 0; j < i; ++j)
-                                       printk("%02x ", (unsigned char)(tbuf)[j]);
+                                       printk("%02x ", (u8)(tbuf)[j]);
                                printk("\n");
                        }
                        if (copy_to_user(ctrl.data, tbuf, i)) {
@@ -680,12 +708,13 @@ static int proc_control(struct dev_state *ps, void __user *arg)
                        printk("\n");
                }
                usb_unlock_device(dev);
-               i = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), ctrl.bRequest, ctrl.bRequestType,
-                                      ctrl.wValue, ctrl.wIndex, tbuf, ctrl.wLength, tmo);
+               i = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), ctrl.bRequest,
+                                   ctrl.bRequestType, ctrl.wValue, ctrl.wIndex,
+                                   tbuf, ctrl.wLength, tmo);
                usb_lock_device(dev);
        }
        free_page((unsigned long)tbuf);
-       if (i<0 && i != -EPIPE) {
+       if (i < 0 && i != -EPIPE) {
                dev_printk(KERN_DEBUG, &dev->dev, "usbfs: USBDEVFS_CONTROL "
                           "failed cmd %s rqt %u rq %u len %u ret %d\n",
                           current->comm, ctrl.bRequestType, ctrl.bRequest,
@@ -705,9 +734,11 @@ static int proc_bulk(struct dev_state *ps, void __user *arg)
 
        if (copy_from_user(&bulk, arg, sizeof(bulk)))
                return -EFAULT;
-       if ((ret = findintfep(ps->dev, bulk.ep)) < 0)
+       ret = findintfep(ps->dev, bulk.ep);
+       if (ret < 0)
                return ret;
-       if ((ret = checkintf(ps, ret)))
+       ret = checkintf(ps, ret);
+       if (ret)
                return ret;
        if (bulk.ep & USB_DIR_IN)
                pipe = usb_rcvbulkpipe(dev, bulk.ep & 0x7f);
@@ -735,7 +766,7 @@ static int proc_bulk(struct dev_state *ps, void __user *arg)
                        if (usbfs_snoop) {
                                dev_info(&dev->dev, "bulk read: data ");
                                for (j = 0; j < len2; ++j)
-                                       printk("%02x ", (unsigned char)(tbuf)[j]);
+                                       printk("%02x ", (u8)(tbuf)[j]);
                                printk("\n");
                        }
                        if (copy_to_user(bulk.data, tbuf, len2)) {
@@ -775,9 +806,11 @@ static int proc_resetep(struct dev_state *ps, void __user *arg)
 
        if (get_user(ep, (unsigned int __user *)arg))
                return -EFAULT;
-       if ((ret = findintfep(ps->dev, ep)) < 0)
+       ret = findintfep(ps->dev, ep);
+       if (ret < 0)
                return ret;
-       if ((ret = checkintf(ps, ret)))
+       ret = checkintf(ps, ret);
+       if (ret)
                return ret;
        usb_settoggle(ps->dev, ep & 0xf, !(ep & USB_DIR_IN), 0);
        return 0;
@@ -791,18 +824,19 @@ static int proc_clearhalt(struct dev_state *ps, void __user *arg)
 
        if (get_user(ep, (unsigned int __user *)arg))
                return -EFAULT;
-       if ((ret = findintfep(ps->dev, ep)) < 0)
+       ret = findintfep(ps->dev, ep);
+       if (ret < 0)
                return ret;
-       if ((ret = checkintf(ps, ret)))
+       ret = checkintf(ps, ret);
+       if (ret)
                return ret;
        if (ep & USB_DIR_IN)
-                pipe = usb_rcvbulkpipe(ps->dev, ep & 0x7f);
-        else
-                pipe = usb_sndbulkpipe(ps->dev, ep & 0x7f);
+               pipe = usb_rcvbulkpipe(ps->dev, ep & 0x7f);
+       else
+               pipe = usb_sndbulkpipe(ps->dev, ep & 0x7f);
 
        return usb_clear_halt(ps->dev, pipe);
 }
-               
 
 static int proc_getdriver(struct dev_state *ps, void __user *arg)
 {
@@ -856,23 +890,23 @@ static int proc_setconfig(struct dev_state *ps, void __user *arg)
 {
        int u;
        int status = 0;
-       struct usb_host_config *actconfig;
+       struct usb_host_config *actconfig;
 
        if (get_user(u, (int __user *)arg))
                return -EFAULT;
 
-       actconfig = ps->dev->actconfig;
-       /* Don't touch the device if any interfaces are claimed.
-        * It could interfere with other drivers' operations, and if
+       actconfig = ps->dev->actconfig;
+
+       /* Don't touch the device if any interfaces are claimed.
+        * It could interfere with other drivers' operations, and if
         * an interface is claimed by usbfs it could easily deadlock.
         */
-       if (actconfig) {
-               int i;
-               for (i = 0; i < actconfig->desc.bNumInterfaces; ++i) {
-                       if (usb_interface_claimed(actconfig->interface[i])) {
-                               dev_warn (&ps->dev->dev,
+       if (actconfig) {
+               int i;
+
+               for (i = 0; i < actconfig->desc.bNumInterfaces; ++i) {
+                       if (usb_interface_claimed(actconfig->interface[i])) {
+                               dev_warn(&ps->dev->dev,
                                        "usbfs: interface %d claimed by %s "
                                        "while '%s' sets config #%d\n",
                                        actconfig->interface[i]
@@ -881,11 +915,11 @@ static int proc_setconfig(struct dev_state *ps, void __user *arg)
                                        actconfig->interface[i]
                                                ->dev.driver->name,
                                        current->comm, u);
-                               status = -EBUSY;
+                               status = -EBUSY;
                                break;
                        }
-               }
-       }
+               }
+       }
 
        /* SET_CONFIGURATION is often abused as a "cheap" driver reset,
         * so avoid usb_set_configuration()'s kick to sysfs
@@ -901,8 +935,8 @@ static int proc_setconfig(struct dev_state *ps, void __user *arg)
 }
 
 static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
-                            struct usbdevfs_iso_packet_desc __user *iso_frame_desc,
-                            void __user *arg)
+                       struct usbdevfs_iso_packet_desc __user *iso_frame_desc,
+                       void __user *arg)
 {
        struct usbdevfs_iso_packet_desc *isopkt = NULL;
        struct usb_host_endpoint *ep;
@@ -917,12 +951,16 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
                return -EINVAL;
        if (!uurb->buffer)
                return -EINVAL;
-       if (uurb->signr != 0 && (uurb->signr < SIGRTMIN || uurb->signr > SIGRTMAX))
+       if (uurb->signr != 0 && (uurb->signr < SIGRTMIN ||
+                                uurb->signr > SIGRTMAX))
                return -EINVAL;
-       if (!(uurb->type == USBDEVFS_URB_TYPE_CONTROL && (uurb->endpoint & ~USB_ENDPOINT_DIR_MASK) == 0)) {
-               if ((ifnum = findintfep(ps->dev, uurb->endpoint)) < 0)
+       if (!(uurb->type == USBDEVFS_URB_TYPE_CONTROL &&
+           (uurb->endpoint & ~USB_ENDPOINT_DIR_MASK) == 0)) {
+               ifnum = findintfep(ps->dev, uurb->endpoint);
+               if (ifnum < 0)
                        return ifnum;
-               if ((ret = checkintf(ps, ifnum)))
+               ret = checkintf(ps, ifnum);
+               if (ret)
                        return ret;
        }
        if ((uurb->endpoint & USB_ENDPOINT_DIR_MASK) != 0) {
@@ -938,10 +976,13 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
        case USBDEVFS_URB_TYPE_CONTROL:
                if (!usb_endpoint_xfer_control(&ep->desc))
                        return -EINVAL;
-               /* min 8 byte setup packet, max 8 byte setup plus an arbitrary data stage */
-               if (uurb->buffer_length < 8 || uurb->buffer_length > (8 + MAX_USBFS_BUFFER_SIZE))
+               /* min 8 byte setup packet,
+                * max 8 byte setup plus an arbitrary data stage */
+               if (uurb->buffer_length < 8 ||
+                   uurb->buffer_length > (8 + MAX_USBFS_BUFFER_SIZE))
                        return -EINVAL;
-               if (!(dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL)))
+               dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
+               if (!dr)
                        return -ENOMEM;
                if (copy_from_user(dr, uurb->buffer, 8)) {
                        kfree(dr);
@@ -951,7 +992,9 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
                        kfree(dr);
                        return -EINVAL;
                }
-               if ((ret = check_ctrlrecip(ps, dr->bRequestType, le16_to_cpup(&dr->wIndex)))) {
+               ret = check_ctrlrecip(ps, dr->bRequestType,
+                                     le16_to_cpup(&dr->wIndex));
+               if (ret) {
                        kfree(dr);
                        return ret;
                }
@@ -997,11 +1040,13 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
 
        case USBDEVFS_URB_TYPE_ISO:
                /* arbitrary limit */
-               if (uurb->number_of_packets < 1 || uurb->number_of_packets > 128)
+               if (uurb->number_of_packets < 1 ||
+                   uurb->number_of_packets > 128)
                        return -EINVAL;
                if (!usb_endpoint_xfer_isoc(&ep->desc))
                        return -EINVAL;
-               isofrmlen = sizeof(struct usbdevfs_iso_packet_desc) * uurb->number_of_packets;
+               isofrmlen = sizeof(struct usbdevfs_iso_packet_desc) *
+                                  uurb->number_of_packets;
                if (!(isopkt = kmalloc(isofrmlen, GFP_KERNEL)))
                        return -ENOMEM;
                if (copy_from_user(isopkt, iso_frame_desc, isofrmlen)) {
@@ -1009,7 +1054,8 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
                        return -EFAULT;
                }
                for (totlen = u = 0; u < uurb->number_of_packets; u++) {
-                       /* arbitrary limit, sufficient for USB 2.0 high-bandwidth iso */
+                       /* arbitrary limit,
+                        * sufficient for USB 2.0 high-bandwidth iso */
                        if (isopkt[u].length > 8192) {
                                kfree(isopkt);
                                return -EINVAL;
@@ -1039,25 +1085,27 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
        default:
                return -EINVAL;
        }
-       if (!(as = alloc_async(uurb->number_of_packets))) {
+       as = alloc_async(uurb->number_of_packets);
+       if (!as) {
                kfree(isopkt);
                kfree(dr);
                return -ENOMEM;
        }
-       if (!(as->urb->transfer_buffer = kmalloc(uurb->buffer_length, GFP_KERNEL))) {
+       as->urb->transfer_buffer = kmalloc(uurb->buffer_length, GFP_KERNEL);
+       if (!as->urb->transfer_buffer) {
                kfree(isopkt);
                kfree(dr);
                free_async(as);
                return -ENOMEM;
        }
-        as->urb->dev = ps->dev;
-        as->urb->pipe = (uurb->type << 30) |
+       as->urb->dev = ps->dev;
+       as->urb->pipe = (uurb->type << 30) |
                        __create_pipe(ps->dev, uurb->endpoint & 0xf) |
                        (uurb->endpoint & USB_DIR_IN);
-        as->urb->transfer_flags = uurb->flags |
+       as->urb->transfer_flags = uurb->flags |
                        (is_in ? URB_DIR_IN : URB_DIR_OUT);
        as->urb->transfer_buffer_length = uurb->buffer_length;
-       as->urb->setup_packet = (unsigned char*)dr;
+       as->urb->setup_packet = (unsigned char *)dr;
        as->urb->start_frame = uurb->start_frame;
        as->urb->number_of_packets = uurb->number_of_packets;
        if (uurb->type == USBDEVFS_URB_TYPE_ISO ||
@@ -1065,8 +1113,8 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
                as->urb->interval = 1 << min(15, ep->desc.bInterval - 1);
        else
                as->urb->interval = ep->desc.bInterval;
-        as->urb->context = as;
-        as->urb->complete = async_completed;
+       as->urb->context = as;
+       as->urb->complete = async_completed;
        for (totlen = u = 0; u < uurb->number_of_packets; u++) {
                as->urb->iso_frame_desc[u].offset = totlen;
                as->urb->iso_frame_desc[u].length = isopkt[u].length;
@@ -1074,7 +1122,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
        }
        kfree(isopkt);
        as->ps = ps;
-        as->userurb = arg;
+       as->userurb = arg;
        if (uurb->endpoint & USB_DIR_IN)
                as->userbuffer = uurb->buffer;
        else
@@ -1093,14 +1141,15 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
                }
        }
        snoop_urb(as->urb, as->userurb);
-        async_newpending(as);
-        if ((ret = usb_submit_urb(as->urb, GFP_KERNEL))) {
-               dev_printk(KERN_DEBUG, &ps->dev->dev, "usbfs: usb_submit_urb returned %d\n", ret);
-                async_removepending(as);
-                free_async(as);
-                return ret;
-        }
-        return 0;
+       async_newpending(as);
+       if ((ret = usb_submit_urb(as->urb, GFP_KERNEL))) {
+               dev_printk(KERN_DEBUG, &ps->dev->dev,
+                          "usbfs: usb_submit_urb returned %d\n", ret);
+               async_removepending(as);
+               free_async(as);
+               return ret;
+       }
+       return 0;
 }
 
 static int proc_submiturb(struct dev_state *ps, void __user *arg)
@@ -1110,7 +1159,9 @@ static int proc_submiturb(struct dev_state *ps, void __user *arg)
        if (copy_from_user(&uurb, arg, sizeof(uurb)))
                return -EFAULT;
 
-       return proc_do_submiturb(ps, &uurb, (((struct usbdevfs_urb __user *)arg)->iso_frame_desc), arg);
+       return proc_do_submiturb(ps, &uurb,
+                       (((struct usbdevfs_urb __user *)arg)->iso_frame_desc),
+                       arg);
 }
 
 static int proc_unlinkurb(struct dev_state *ps, void __user *arg)
@@ -1132,7 +1183,8 @@ static int processcompl(struct async *as, void __user * __user *arg)
        unsigned int i;
 
        if (as->userbuffer)
-               if (copy_to_user(as->userbuffer, urb->transfer_buffer, urb->transfer_buffer_length))
+               if (copy_to_user(as->userbuffer, urb->transfer_buffer,
+                                urb->transfer_buffer_length))
                        return -EFAULT;
        if (put_user(as->status, &userurb->status))
                return -EFAULT;
@@ -1159,16 +1211,17 @@ static int processcompl(struct async *as, void __user * __user *arg)
        return 0;
 }
 
-static struct asyncreap_as(struct dev_state *ps)
+static struct async *reap_as(struct dev_state *ps)
 {
-        DECLARE_WAITQUEUE(wait, current);
+       DECLARE_WAITQUEUE(wait, current);
        struct async *as = NULL;
        struct usb_device *dev = ps->dev;
 
        add_wait_queue(&ps->wait, &wait);
        for (;;) {
                __set_current_state(TASK_INTERRUPTIBLE);
-               if ((as = async_getcompleted(ps)))
+               as = async_getcompleted(ps);
+               if (as)
                        break;
                if (signal_pending(current))
                        break;
@@ -1232,10 +1285,12 @@ static int proc_submiturb_compat(struct dev_state *ps, void __user *arg)
 {
        struct usbdevfs_urb uurb;
 
-       if (get_urb32(&uurb,(struct usbdevfs_urb32 __user *)arg))
+       if (get_urb32(&uurb, (struct usbdevfs_urb32 __user *)arg))
                return -EFAULT;
 
-       return proc_do_submiturb(ps, &uurb, ((struct usbdevfs_urb32 __user *)arg)->iso_frame_desc, arg);
+       return proc_do_submiturb(ps, &uurb,
+                       ((struct usbdevfs_urb32 __user *)arg)->iso_frame_desc,
+                       arg);
 }
 
 static int processcompl_compat(struct async *as, void __user * __user *arg)
@@ -1246,7 +1301,8 @@ static int processcompl_compat(struct async *as, void __user * __user *arg)
        unsigned int i;
 
        if (as->userbuffer)
-               if (copy_to_user(as->userbuffer, urb->transfer_buffer, urb->transfer_buffer_length))
+               if (copy_to_user(as->userbuffer, urb->transfer_buffer,
+                                urb->transfer_buffer_length))
                        return -EFAULT;
        if (put_user(as->status, &userurb->status))
                return -EFAULT;
@@ -1337,16 +1393,16 @@ static int proc_ioctl(struct dev_state *ps, struct usbdevfs_ioctl *ctl)
        struct usb_driver       *driver = NULL;
 
        /* alloc buffer */
-       if ((size = _IOC_SIZE (ctl->ioctl_code)) > 0) {
-               if ((buf = kmalloc (size, GFP_KERNEL)) == NULL)
+       if ((size = _IOC_SIZE(ctl->ioctl_code)) > 0) {
+               if ((buf = kmalloc(size, GFP_KERNEL)) == NULL)
                        return -ENOMEM;
                if ((_IOC_DIR(ctl->ioctl_code) & _IOC_WRITE)) {
-                       if (copy_from_user (buf, ctl->data, size)) {
+                       if (copy_from_user(buf, ctl->data, size)) {
                                kfree(buf);
                                return -EFAULT;
                        }
                } else {
-                       memset (buf, 0, size);
+                       memset(buf, 0, size);
                }
        }
 
@@ -1357,15 +1413,15 @@ static int proc_ioctl(struct dev_state *ps, struct usbdevfs_ioctl *ctl)
 
        if (ps->dev->state != USB_STATE_CONFIGURED)
                retval = -EHOSTUNREACH;
-       else if (!(intf = usb_ifnum_to_if (ps->dev, ctl->ifno)))
-               retval = -EINVAL;
+       else if (!(intf = usb_ifnum_to_if(ps->dev, ctl->ifno)))
+               retval = -EINVAL;
        else switch (ctl->ioctl_code) {
 
        /* disconnect kernel driver from interface */
        case USBDEVFS_DISCONNECT:
                if (intf->dev.driver) {
                        driver = to_usb_driver(intf->dev.driver);
-                       dev_dbg (&intf->dev, "disconnect by usbfs\n");
+                       dev_dbg(&intf->dev, "disconnect by usbfs\n");
                        usb_driver_release_interface(driver, intf);
                } else
                        retval = -ENODATA;
@@ -1373,9 +1429,10 @@ static int proc_ioctl(struct dev_state *ps, struct usbdevfs_ioctl *ctl)
 
        /* let kernel drivers try to (re)bind to the interface */
        case USBDEVFS_CONNECT:
-               usb_unlock_device(ps->dev);
-               retval = bus_rescan_devices(intf->dev.bus);
-               usb_lock_device(ps->dev);
+               if (!intf->dev.driver)
+                       retval = device_attach(&intf->dev);
+               else
+                       retval = -EBUSY;
                break;
 
        /* talk directly to the interface's driver */
@@ -1385,7 +1442,7 @@ static int proc_ioctl(struct dev_state *ps, struct usbdevfs_ioctl *ctl)
                if (driver == NULL || driver->ioctl == NULL) {
                        retval = -ENOTTY;
                } else {
-                       retval = driver->ioctl (intf, ctl->ioctl_code, buf);
+                       retval = driver->ioctl(intf, ctl->ioctl_code, buf);
                        if (retval == -ENOIOCTLCMD)
                                retval = -ENOTTY;
                }
@@ -1393,9 +1450,9 @@ static int proc_ioctl(struct dev_state *ps, struct usbdevfs_ioctl *ctl)
 
        /* cleanup and return */
        if (retval >= 0
-                       && (_IOC_DIR (ctl->ioctl_code) & _IOC_READ) != 0
+                       && (_IOC_DIR(ctl->ioctl_code) & _IOC_READ) != 0
                        && size > 0
-                       && copy_to_user (ctl->data, buf, size) != 0)
+                       && copy_to_user(ctl->data, buf, size) != 0)
                retval = -EFAULT;
 
        kfree(buf);
@@ -1406,7 +1463,7 @@ static int proc_ioctl_default(struct dev_state *ps, void __user *arg)
 {
        struct usbdevfs_ioctl   ctrl;
 
-       if (copy_from_user(&ctrl, arg, sizeof (ctrl)))
+       if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
                return -EFAULT;
        return proc_ioctl(ps, &ctrl);
 }
@@ -1434,7 +1491,8 @@ static int proc_ioctl_compat(struct dev_state *ps, compat_uptr_t arg)
  * are assuming that somehow the configuration has been prevented from
  * changing.  But there's no mechanism to ensure that...
  */
-static int usbdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+static int usbdev_ioctl(struct inode *inode, struct file *file,
+                       unsigned int cmd, unsigned long arg)
 {
        struct dev_state *ps = file->private_data;
        struct usb_device *dev = ps->dev;
@@ -1577,7 +1635,8 @@ static int usbdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
 }
 
 /* No kernel lock - fine */
-static unsigned int usbdev_poll(struct file *file, struct poll_table_struct *wait)
+static unsigned int usbdev_poll(struct file *file,
+                               struct poll_table_struct *wait)
 {
        struct dev_state *ps = file->private_data;
        unsigned int mask = 0;
@@ -1648,7 +1707,7 @@ int __init usb_devio_init(void)
        int retval;
 
        retval = register_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX,
-                       "usb_device");
+                                       "usb_device");
        if (retval) {
                err("unable to register minors for usb_device");
                goto out;
index 7c3aaa9c5402bf55a0738e0b310943fa81dde777..801b6f142fa7f874650a99c4d28c268c887a3114 100644 (file)
@@ -202,10 +202,10 @@ static int usb_probe_interface(struct device *dev)
        intf = to_usb_interface(dev);
        udev = interface_to_usbdev(intf);
 
-       if (udev->authorized == 0) {
-               dev_err(&intf->dev, "Device is not authorized for usage\n");
-               return -ENODEV;
-       }
+       if (udev->authorized == 0) {
+               dev_err(&intf->dev, "Device is not authorized for usage\n");
+               return -ENODEV;
+       }
 
        id = usb_match_id(intf, driver->id_table);
        if (!id)
@@ -299,7 +299,7 @@ static int usb_unbind_interface(struct device *dev)
  * lock.
  */
 int usb_driver_claim_interface(struct usb_driver *driver,
-                               struct usb_interface *iface, voidpriv)
+                               struct usb_interface *iface, void *priv)
 {
        struct device *dev = &iface->dev;
        struct usb_device *udev = interface_to_usbdev(iface);
@@ -325,7 +325,7 @@ int usb_driver_claim_interface(struct usb_driver *driver,
 
        return retval;
 }
-EXPORT_SYMBOL(usb_driver_claim_interface);
+EXPORT_SYMBOL_GPL(usb_driver_claim_interface);
 
 /**
  * usb_driver_release_interface - unbind a driver from an interface
@@ -370,7 +370,7 @@ void usb_driver_release_interface(struct usb_driver *driver,
        iface->needs_remote_wakeup = 0;
        usb_pm_unlock(udev);
 }
-EXPORT_SYMBOL(usb_driver_release_interface);
+EXPORT_SYMBOL_GPL(usb_driver_release_interface);
 
 /* returns 0 if no match, 1 if match */
 int usb_match_device(struct usb_device *dev, const struct usb_device_id *id)
@@ -398,7 +398,7 @@ int usb_match_device(struct usb_device *dev, const struct usb_device_id *id)
                return 0;
 
        if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_SUBCLASS) &&
-           (id->bDeviceSubClass!= dev->descriptor.bDeviceSubClass))
+           (id->bDeviceSubClass != dev->descriptor.bDeviceSubClass))
                return 0;
 
        if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_PROTOCOL) &&
@@ -534,15 +534,15 @@ const struct usb_device_id *usb_match_id(struct usb_interface *interface,
           id->driver_info is the way to create an entry that
           indicates that the driver want to examine every
           device and interface. */
-       for (; id->idVendor || id->bDeviceClass || id->bInterfaceClass ||
-              id->driver_info; id++) {
+       for (; id->idVendor || id->idProduct || id->bDeviceClass ||
+              id->bInterfaceClass || id->driver_info; id++) {
                if (usb_match_one_id(interface, id))
                        return id;
        }
 
        return NULL;
 }
-EXPORT_SYMBOL_GPL_FUTURE(usb_match_id);
+EXPORT_SYMBOL_GPL(usb_match_id);
 
 static int usb_device_match(struct device *dev, struct device_driver *drv)
 {
@@ -586,7 +586,7 @@ static int usb_uevent(struct device *dev, struct kobj_uevent_env *env)
        struct usb_device *usb_dev;
 
        /* driver is often null here; dev_dbg() would oops */
-       pr_debug ("usb %s: uevent\n", dev->bus_id);
+       pr_debug("usb %s: uevent\n", dev->bus_id);
 
        if (is_usb_device(dev))
                usb_dev = to_usb_device(dev);
@@ -596,11 +596,11 @@ static int usb_uevent(struct device *dev, struct kobj_uevent_env *env)
        }
 
        if (usb_dev->devnum < 0) {
-               pr_debug ("usb %s: already deleted?\n", dev->bus_id);
+               pr_debug("usb %s: already deleted?\n", dev->bus_id);
                return -ENODEV;
        }
        if (!usb_dev->bus) {
-               pr_debug ("usb %s: bus removed?\n", dev->bus_id);
+               pr_debug("usb %s: bus removed?\n", dev->bus_id);
                return -ENODEV;
        }
 
@@ -745,7 +745,7 @@ int usb_register_driver(struct usb_driver *new_driver, struct module *owner,
 
        return retval;
 }
-EXPORT_SYMBOL_GPL_FUTURE(usb_register_driver);
+EXPORT_SYMBOL_GPL(usb_register_driver);
 
 /**
  * usb_deregister - unregister a USB interface driver
@@ -769,7 +769,7 @@ void usb_deregister(struct usb_driver *driver)
 
        usbfs_update_special();
 }
-EXPORT_SYMBOL_GPL_FUTURE(usb_deregister);
+EXPORT_SYMBOL_GPL(usb_deregister);
 
 #ifdef CONFIG_PM
 
@@ -854,8 +854,10 @@ static int usb_suspend_interface(struct usb_interface *intf, pm_message_t msg)
                        dev_err(&intf->dev, "%s error %d\n",
                                        "suspend", status);
        } else {
-               // FIXME else if there's no suspend method, disconnect...
-               // Not possible if auto_pm is set...
+               /*
+                * FIXME else if there's no suspend method, disconnect...
+                * Not possible if auto_pm is set...
+                */
                dev_warn(&intf->dev, "no suspend for driver %s?\n",
                                driver->name);
                mark_quiesced(intf);
@@ -894,7 +896,7 @@ static int usb_resume_interface(struct usb_interface *intf, int reset_resume)
                                dev_err(&intf->dev, "%s error %d\n",
                                                "reset_resume", status);
                } else {
-                       // status = -EOPNOTSUPP;
+                       /* status = -EOPNOTSUPP; */
                        dev_warn(&intf->dev, "no %s for driver %s?\n",
                                        "reset_resume", driver->name);
                }
@@ -905,7 +907,7 @@ static int usb_resume_interface(struct usb_interface *intf, int reset_resume)
                                dev_err(&intf->dev, "%s error %d\n",
                                                "resume", status);
                } else {
-                       // status = -EOPNOTSUPP;
+                       /* status = -EOPNOTSUPP; */
                        dev_warn(&intf->dev, "no %s for driver %s?\n",
                                        "resume", driver->name);
                }
@@ -1175,7 +1177,7 @@ static int usb_resume_both(struct usb_device *udev)
                         * so if a root hub's controller is suspended
                         * then we're stuck. */
                        status = usb_resume_device(udev);
-               }
+               }
        } else {
 
                /* Needed for setting udev->dev.power.power_state.event,
index 5d860bc9b42143f6729a9df40521ec42943b21b1..8133c99c6c5caf7cb1f384c71360f15e6c4fbf54 100644 (file)
@@ -204,7 +204,7 @@ int usb_register_dev(struct usb_interface *intf,
 exit:
        return retval;
 }
-EXPORT_SYMBOL(usb_register_dev);
+EXPORT_SYMBOL_GPL(usb_register_dev);
 
 /**
  * usb_deregister_dev - deregister a USB device's dynamic minor.
@@ -245,4 +245,4 @@ void usb_deregister_dev(struct usb_interface *intf,
        intf->minor = -1;
        destroy_usb_class();
 }
-EXPORT_SYMBOL(usb_deregister_dev);
+EXPORT_SYMBOL_GPL(usb_deregister_dev);
index 3fb9af80cbf4319e133f1434453a38ae538944d2..84760ddbc3325cba6cfdc8b219c3d70f32e0a5ab 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * (C) Copyright David Brownell 2000-2002
- * 
+ *
  * 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
@@ -55,7 +55,7 @@
  *
  * Store this function in the HCD's struct pci_driver as probe().
  */
-int usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id)
+int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
 {
        struct hc_driver        *driver;
        struct usb_hcd          *hcd;
@@ -64,66 +64,71 @@ int usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id)
        if (usb_disabled())
                return -ENODEV;
 
-       if (!id || !(driver = (struct hc_driver *) id->driver_data))
+       if (!id)
+               return -EINVAL;
+       driver = (struct hc_driver *)id->driver_data;
+       if (!driver)
                return -EINVAL;
 
-       if (pci_enable_device (dev) < 0)
+       if (pci_enable_device(dev) < 0)
                return -ENODEV;
        dev->current_state = PCI_D0;
        dev->dev.power.power_state = PMSG_ON;
-       
-        if (!dev->irq) {
-               dev_err (&dev->dev,
+
+       if (!dev->irq) {
+               dev_err(&dev->dev,
                        "Found HC with no IRQ.  Check BIOS/PCI %s setup!\n",
                        pci_name(dev));
-               retval = -ENODEV;
+               retval = -ENODEV;
                goto err1;
-        }
+       }
 
-       hcd = usb_create_hcd (driver, &dev->dev, pci_name(dev));
+       hcd = usb_create_hcd(driver, &dev->dev, pci_name(dev));
        if (!hcd) {
                retval = -ENOMEM;
                goto err1;
        }
 
-       if (driver->flags & HCD_MEMORY) {       // EHCI, OHCI
-               hcd->rsrc_start = pci_resource_start (dev, 0);
-               hcd->rsrc_len = pci_resource_len (dev, 0);
-               if (!request_mem_region (hcd->rsrc_start, hcd->rsrc_len,
+       if (driver->flags & HCD_MEMORY) {
+               /* EHCI, OHCI */
+               hcd->rsrc_start = pci_resource_start(dev, 0);
+               hcd->rsrc_len = pci_resource_len(dev, 0);
+               if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len,
                                driver->description)) {
-                       dev_dbg (&dev->dev, "controller already in use\n");
+                       dev_dbg(&dev->dev, "controller already in use\n");
                        retval = -EBUSY;
                        goto err2;
                }
-               hcd->regs = ioremap_nocache (hcd->rsrc_start, hcd->rsrc_len);
+               hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);
                if (hcd->regs == NULL) {
-                       dev_dbg (&dev->dev, "error mapping memory\n");
+                       dev_dbg(&dev->dev, "error mapping memory\n");
                        retval = -EFAULT;
                        goto err3;
                }
 
-       } else {                                // UHCI
+       } else {
+               /* UHCI */
                int     region;
 
                for (region = 0; region < PCI_ROM_RESOURCE; region++) {
-                       if (!(pci_resource_flags (dev, region) &
+                       if (!(pci_resource_flags(dev, region) &
                                        IORESOURCE_IO))
                                continue;
 
-                       hcd->rsrc_start = pci_resource_start (dev, region);
-                       hcd->rsrc_len = pci_resource_len (dev, region);
-                       if (request_region (hcd->rsrc_start, hcd->rsrc_len,
+                       hcd->rsrc_start = pci_resource_start(dev, region);
+                       hcd->rsrc_len = pci_resource_len(dev, region);
+                       if (request_region(hcd->rsrc_start, hcd->rsrc_len,
                                        driver->description))
                                break;
                }
                if (region == PCI_ROM_RESOURCE) {
-                       dev_dbg (&dev->dev, "no i/o regions available\n");
+                       dev_dbg(&dev->dev, "no i/o regions available\n");
                        retval = -EBUSY;
                        goto err1;
                }
        }
 
-       pci_set_master (dev);
+       pci_set_master(dev);
 
        retval = usb_add_hcd(hcd, dev->irq, IRQF_DISABLED | IRQF_SHARED);
        if (retval != 0)
@@ -132,19 +137,19 @@ int usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id)
 
  err4:
        if (driver->flags & HCD_MEMORY) {
-               iounmap (hcd->regs);
+               iounmap(hcd->regs);
  err3:
-               release_mem_region (hcd->rsrc_start, hcd->rsrc_len);
+               release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
        } else
-               release_region (hcd->rsrc_start, hcd->rsrc_len);
+               release_region(hcd->rsrc_start, hcd->rsrc_len);
  err2:
-       usb_put_hcd (hcd);
+       usb_put_hcd(hcd);
  err1:
-       pci_disable_device (dev);
-       dev_err (&dev->dev, "init %s fail, %d\n", pci_name(dev), retval);
+       pci_disable_device(dev);
+       dev_err(&dev->dev, "init %s fail, %d\n", pci_name(dev), retval);
        return retval;
-} 
-EXPORT_SYMBOL (usb_hcd_pci_probe);
+}
+EXPORT_SYMBOL_GPL(usb_hcd_pci_probe);
 
 
 /* may be called without controller electrically present */
@@ -161,7 +166,7 @@ EXPORT_SYMBOL (usb_hcd_pci_probe);
  *
  * Store this function in the HCD's struct pci_driver as remove().
  */
-void usb_hcd_pci_remove (struct pci_dev *dev)
+void usb_hcd_pci_remove(struct pci_dev *dev)
 {
        struct usb_hcd          *hcd;
 
@@ -169,17 +174,17 @@ void usb_hcd_pci_remove (struct pci_dev *dev)
        if (!hcd)
                return;
 
-       usb_remove_hcd (hcd);
+       usb_remove_hcd(hcd);
        if (hcd->driver->flags & HCD_MEMORY) {
-               iounmap (hcd->regs);
-               release_mem_region (hcd->rsrc_start, hcd->rsrc_len);
+               iounmap(hcd->regs);
+               release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
        } else {
-               release_region (hcd->rsrc_start, hcd->rsrc_len);
+               release_region(hcd->rsrc_start, hcd->rsrc_len);
        }
-       usb_put_hcd (hcd);
+       usb_put_hcd(hcd);
        pci_disable_device(dev);
 }
-EXPORT_SYMBOL (usb_hcd_pci_remove);
+EXPORT_SYMBOL_GPL(usb_hcd_pci_remove);
 
 
 #ifdef CONFIG_PM
@@ -191,7 +196,7 @@ EXPORT_SYMBOL (usb_hcd_pci_remove);
  *
  * Store this function in the HCD's struct pci_driver as suspend().
  */
-int usb_hcd_pci_suspend (struct pci_dev *dev, pm_message_t message)
+int usb_hcd_pci_suspend(struct pci_dev *dev, pm_message_t message)
 {
        struct usb_hcd          *hcd;
        int                     retval = 0;
@@ -246,12 +251,18 @@ int usb_hcd_pci_suspend (struct pci_dev *dev, pm_message_t message)
 
                /* no DMA or IRQs except when HC is active */
                if (dev->current_state == PCI_D0) {
-                       pci_save_state (dev);
-                       pci_disable_device (dev);
+                       pci_save_state(dev);
+                       pci_disable_device(dev);
+               }
+
+               if (message.event == PM_EVENT_FREEZE ||
+                               message.event == PM_EVENT_PRETHAW) {
+                       dev_dbg(hcd->self.controller, "--> no state change\n");
+                       goto done;
                }
 
                if (!has_pci_pm) {
-                       dev_dbg (hcd->self.controller, "--> PCI D0/legacy\n");
+                       dev_dbg(hcd->self.controller, "--> PCI D0/legacy\n");
                        goto done;
                }
 
@@ -260,30 +271,30 @@ int usb_hcd_pci_suspend (struct pci_dev *dev, pm_message_t message)
                 * 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);
+               retval = pci_set_power_state(dev, PCI_D3hot);
                suspend_report_result(pci_set_power_state, retval);
                if (retval == 0) {
                        int wake = device_can_wakeup(&hcd->self.root_hub->dev);
 
                        wake = wake && device_may_wakeup(hcd->self.controller);
 
-                       dev_dbg (hcd->self.controller, "--> PCI D3%s\n",
+                       dev_dbg(hcd->self.controller, "--> PCI D3%s\n",
                                        wake ? "/wakeup" : "");
 
                        /* Ignore these return values.  We rely on pci code to
                         * reject requests the hardware can't implement, rather
                         * than coding the same thing.
                         */
-                       (void) pci_enable_wake (dev, PCI_D3hot, wake);
-                       (void) pci_enable_wake (dev, PCI_D3cold, wake);
+                       (void) pci_enable_wake(dev, PCI_D3hot, wake);
+                       (void) pci_enable_wake(dev, PCI_D3cold, wake);
                } else {
-                       dev_dbg (&dev->dev, "PCI D3 suspend fail, %d\n",
+                       dev_dbg(&dev->dev, "PCI D3 suspend fail, %d\n",
                                        retval);
-                       (void) usb_hcd_pci_resume (dev);
+                       (void) usb_hcd_pci_resume(dev);
                }
 
        } else if (hcd->state != HC_STATE_HALT) {
-               dev_dbg (hcd->self.controller, "hcd state %d; not suspended\n",
+               dev_dbg(hcd->self.controller, "hcd state %d; not suspended\n",
                        hcd->state);
                WARN_ON(1);
                retval = -EINVAL;
@@ -298,7 +309,7 @@ done:
                if (machine_is(powermac)) {
                        struct device_node      *of_node;
 
-                       of_node = pci_device_to_OF_node (dev);
+                       of_node = pci_device_to_OF_node(dev);
                        if (of_node)
                                pmac_call_feature(PMAC_FTR_USB_ENABLE,
                                                        of_node, 0, 0);
@@ -308,7 +319,7 @@ done:
 
        return retval;
 }
-EXPORT_SYMBOL (usb_hcd_pci_suspend);
+EXPORT_SYMBOL_GPL(usb_hcd_pci_suspend);
 
 /**
  * usb_hcd_pci_resume - power management resume of a PCI-based HCD
@@ -316,14 +327,14 @@ EXPORT_SYMBOL (usb_hcd_pci_suspend);
  *
  * Store this function in the HCD's struct pci_driver as resume().
  */
-int usb_hcd_pci_resume (struct pci_dev *dev)
+int usb_hcd_pci_resume(struct pci_dev *dev)
 {
        struct usb_hcd          *hcd;
        int                     retval;
 
        hcd = pci_get_drvdata(dev);
        if (hcd->state != HC_STATE_SUSPENDED) {
-               dev_dbg (hcd->self.controller, 
+               dev_dbg(hcd->self.controller,
                                "can't resume, not suspended!\n");
                return 0;
        }
@@ -333,9 +344,9 @@ int usb_hcd_pci_resume (struct pci_dev *dev)
        if (machine_is(powermac)) {
                struct device_node *of_node;
 
-               of_node = pci_device_to_OF_node (dev);
+               of_node = pci_device_to_OF_node(dev);
                if (of_node)
-                       pmac_call_feature (PMAC_FTR_USB_ENABLE,
+                       pmac_call_feature(PMAC_FTR_USB_ENABLE,
                                                of_node, 0, 1);
        }
 #endif
@@ -374,8 +385,8 @@ int usb_hcd_pci_resume (struct pci_dev *dev)
                }
 #endif
                /* yes, ignore these results too... */
-               (void) pci_enable_wake (dev, dev->current_state, 0);
-               (void) pci_enable_wake (dev, PCI_D3cold, 0);
+               (void) pci_enable_wake(dev, dev->current_state, 0);
+               (void) pci_enable_wake(dev, PCI_D3cold, 0);
        } else {
                /* Same basic cases: clean (powered/not), dirty */
                dev_dbg(hcd->self.controller, "PCI legacy resume\n");
@@ -386,14 +397,14 @@ int usb_hcd_pci_resume (struct pci_dev *dev)
         * but that won't re-enable bus mastering.  Yet pci_disable_device()
         * explicitly disables bus mastering...
         */
-       retval = pci_enable_device (dev);
+       retval = pci_enable_device(dev);
        if (retval < 0) {
-               dev_err (hcd->self.controller,
+               dev_err(hcd->self.controller,
                        "can't re-enable after resume, %d!\n", retval);
                return retval;
        }
-       pci_set_master (dev);
-       pci_restore_state (dev);
+       pci_set_master(dev);
+       pci_restore_state(dev);
 
        dev->dev.power.power_state = PMSG_ON;
 
@@ -402,15 +413,15 @@ int usb_hcd_pci_resume (struct pci_dev *dev)
        if (hcd->driver->resume) {
                retval = hcd->driver->resume(hcd);
                if (retval) {
-                       dev_err (hcd->self.controller,
+                       dev_err(hcd->self.controller,
                                "PCI post-resume error %d!\n", retval);
-                       usb_hc_died (hcd);
+                       usb_hc_died(hcd);
                }
        }
 
        return retval;
 }
-EXPORT_SYMBOL (usb_hcd_pci_resume);
+EXPORT_SYMBOL_GPL(usb_hcd_pci_resume);
 
 #endif /* CONFIG_PM */
 
@@ -418,7 +429,7 @@ EXPORT_SYMBOL (usb_hcd_pci_resume);
  * usb_hcd_pci_shutdown - shutdown host controller
  * @dev: USB Host Controller being shutdown
  */
-void usb_hcd_pci_shutdown (struct pci_dev *dev)
+void usb_hcd_pci_shutdown(struct pci_dev *dev)
 {
        struct usb_hcd          *hcd;
 
@@ -429,5 +440,5 @@ void usb_hcd_pci_shutdown (struct pci_dev *dev)
        if (hcd->driver->shutdown)
                hcd->driver->shutdown(hcd);
 }
-EXPORT_SYMBOL (usb_hcd_pci_shutdown);
+EXPORT_SYMBOL_GPL(usb_hcd_pci_shutdown);
 
index d5ed3fa9e304b5d76b859b31203ab6bb866a3aa1..e52ed1663b3c566ae5d0aa53799faa46f2f00324 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/mutex.h>
 #include <asm/irq.h>
 #include <asm/byteorder.h>
+#include <asm/unaligned.h>
 #include <linux/platform_device.h>
 #include <linux/workqueue.h>
 
@@ -131,8 +132,8 @@ static const u8 usb2_rh_dev_descriptor [18] = {
        0x01,       /*  __u8  bDeviceProtocol; [ usb 2.0 single TT ]*/
        0x40,       /*  __u8  bMaxPacketSize0; 64 Bytes */
 
-       0x00, 0x00, /*  __le16 idVendor; */
-       0x00, 0x00, /*  __le16 idProduct; */
+       0x6b, 0x1d, /*  __le16 idVendor; Linux Foundation */
+       0x02, 0x00, /*  __le16 idProduct; device 0x0002 */
        KERNEL_VER, KERNEL_REL, /*  __le16 bcdDevice */
 
        0x03,       /*  __u8  iManufacturer; */
@@ -154,8 +155,8 @@ static const u8 usb11_rh_dev_descriptor [18] = {
        0x00,       /*  __u8  bDeviceProtocol; [ low/full speeds only ] */
        0x40,       /*  __u8  bMaxPacketSize0; 64 Bytes */
 
-       0x00, 0x00, /*  __le16 idVendor; */
-       0x00, 0x00, /*  __le16 idProduct; */
+       0x6b, 0x1d, /*  __le16 idVendor; Linux Foundation */
+       0x01, 0x00, /*  __le16 idProduct; device 0x0001 */
        KERNEL_VER, KERNEL_REL, /*  __le16 bcdDevice */
 
        0x03,       /*  __u8  iManufacturer; */
@@ -807,13 +808,13 @@ static int usb_register_bus(struct usb_bus *bus)
        }
        set_bit (busnum, busmap.busmap);
        bus->busnum = busnum;
-       bus->class_dev = class_device_create(usb_host_class, NULL, MKDEV(0,0),
-                                            bus->controller, "usb_host%d",
-                                            busnum);
-       result = PTR_ERR(bus->class_dev);
-       if (IS_ERR(bus->class_dev))
+
+       bus->dev = device_create(usb_host_class, bus->controller, MKDEV(0, 0),
+                                "usb_host%d", busnum);
+       result = PTR_ERR(bus->dev);
+       if (IS_ERR(bus->dev))
                goto error_create_class_dev;
-       class_set_devdata(bus->class_dev, bus);
+       dev_set_drvdata(bus->dev, bus);
 
        /* Add it to the local list of buses */
        list_add (&bus->bus_list, &usb_bus_list);
@@ -857,7 +858,7 @@ static void usb_deregister_bus (struct usb_bus *bus)
 
        clear_bit (bus->busnum, busmap.busmap);
 
-       class_device_unregister(bus->class_dev);
+       device_unregister(bus->dev);
 }
 
 /**
@@ -970,7 +971,7 @@ long usb_calc_bus_time (int speed, int is_input, int isoc, int bytecount)
                return -1;
        }
 }
-EXPORT_SYMBOL (usb_calc_bus_time);
+EXPORT_SYMBOL_GPL(usb_calc_bus_time);
 
 
 /*-------------------------------------------------------------------------*/
@@ -1112,48 +1113,177 @@ void usb_hcd_unlink_urb_from_ep(struct usb_hcd *hcd, struct urb *urb)
 }
 EXPORT_SYMBOL_GPL(usb_hcd_unlink_urb_from_ep);
 
-static void map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)
+/*
+ * Some usb host controllers can only perform dma using a small SRAM area.
+ * The usb core itself is however optimized for host controllers that can dma
+ * using regular system memory - like pci devices doing bus mastering.
+ *
+ * To support host controllers with limited dma capabilites we provide dma
+ * bounce buffers. This feature can be enabled using the HCD_LOCAL_MEM flag.
+ * For this to work properly the host controller code must first use the
+ * function dma_declare_coherent_memory() to point out which memory area
+ * that should be used for dma allocations.
+ *
+ * The HCD_LOCAL_MEM flag then tells the usb code to allocate all data for
+ * dma using dma_alloc_coherent() which in turn allocates from the memory
+ * area pointed out with dma_declare_coherent_memory().
+ *
+ * So, to summarize...
+ *
+ * - We need "local" memory, canonical example being
+ *   a small SRAM on a discrete controller being the
+ *   only memory that the controller can read ...
+ *   (a) "normal" kernel memory is no good, and
+ *   (b) there's not enough to share
+ *
+ * - The only *portable* hook for such stuff in the
+ *   DMA framework is dma_declare_coherent_memory()
+ *
+ * - So we use that, even though the primary requirement
+ *   is that the memory be "local" (hence addressible
+ *   by that device), not "coherent".
+ *
+ */
+
+static int hcd_alloc_coherent(struct usb_bus *bus,
+                             gfp_t mem_flags, dma_addr_t *dma_handle,
+                             void **vaddr_handle, size_t size,
+                             enum dma_data_direction dir)
+{
+       unsigned char *vaddr;
+
+       vaddr = hcd_buffer_alloc(bus, size + sizeof(vaddr),
+                                mem_flags, dma_handle);
+       if (!vaddr)
+               return -ENOMEM;
+
+       /*
+        * Store the virtual address of the buffer at the end
+        * of the allocated dma buffer. The size of the buffer
+        * may be uneven so use unaligned functions instead
+        * of just rounding up. It makes sense to optimize for
+        * memory footprint over access speed since the amount
+        * of memory available for dma may be limited.
+        */
+       put_unaligned((unsigned long)*vaddr_handle,
+                     (unsigned long *)(vaddr + size));
+
+       if (dir == DMA_TO_DEVICE)
+               memcpy(vaddr, *vaddr_handle, size);
+
+       *vaddr_handle = vaddr;
+       return 0;
+}
+
+static void hcd_free_coherent(struct usb_bus *bus, dma_addr_t *dma_handle,
+                             void **vaddr_handle, size_t size,
+                             enum dma_data_direction dir)
+{
+       unsigned char *vaddr = *vaddr_handle;
+
+       vaddr = (void *)get_unaligned((unsigned long *)(vaddr + size));
+
+       if (dir == DMA_FROM_DEVICE)
+               memcpy(vaddr, *vaddr_handle, size);
+
+       hcd_buffer_free(bus, size + sizeof(vaddr), *vaddr_handle, *dma_handle);
+
+       *vaddr_handle = vaddr;
+       *dma_handle = 0;
+}
+
+static int map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
+                          gfp_t mem_flags)
 {
+       enum dma_data_direction dir;
+       int ret = 0;
+
        /* 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.
         */
-       if (hcd->self.uses_dma && !is_root_hub(urb->dev)) {
-               if (usb_endpoint_xfer_control(&urb->ep->desc)
-                       && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP))
-                       urb->setup_dma = dma_map_single (
+       if (is_root_hub(urb->dev))
+               return 0;
+
+       if (usb_endpoint_xfer_control(&urb->ep->desc)
+           && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) {
+               if (hcd->self.uses_dma)
+                       urb->setup_dma = dma_map_single(
                                        hcd->self.controller,
                                        urb->setup_packet,
-                                       sizeof (struct usb_ctrlrequest),
+                                       sizeof(struct usb_ctrlrequest),
+                                       DMA_TO_DEVICE);
+               else if (hcd->driver->flags & HCD_LOCAL_MEM)
+                       ret = hcd_alloc_coherent(
+                                       urb->dev->bus, mem_flags,
+                                       &urb->setup_dma,
+                                       (void **)&urb->setup_packet,
+                                       sizeof(struct usb_ctrlrequest),
                                        DMA_TO_DEVICE);
-               if (urb->transfer_buffer_length != 0
-                       && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP))
+       }
+
+       dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
+       if (ret == 0 && urb->transfer_buffer_length != 0
+           && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)) {
+               if (hcd->self.uses_dma)
                        urb->transfer_dma = dma_map_single (
                                        hcd->self.controller,
                                        urb->transfer_buffer,
                                        urb->transfer_buffer_length,
-                                       usb_urb_dir_in(urb)
-                                           ? DMA_FROM_DEVICE
-                                           : DMA_TO_DEVICE);
+                                       dir);
+               else if (hcd->driver->flags & HCD_LOCAL_MEM) {
+                       ret = hcd_alloc_coherent(
+                                       urb->dev->bus, mem_flags,
+                                       &urb->transfer_dma,
+                                       &urb->transfer_buffer,
+                                       urb->transfer_buffer_length,
+                                       dir);
+
+                       if (ret && usb_endpoint_xfer_control(&urb->ep->desc)
+                           && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP))
+                               hcd_free_coherent(urb->dev->bus,
+                                       &urb->setup_dma,
+                                       (void **)&urb->setup_packet,
+                                       sizeof(struct usb_ctrlrequest),
+                                       DMA_TO_DEVICE);
+               }
        }
+       return ret;
 }
 
 static void unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)
 {
-       if (hcd->self.uses_dma && !is_root_hub(urb->dev)) {
-               if (usb_endpoint_xfer_control(&urb->ep->desc)
-                       && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP))
+       enum dma_data_direction dir;
+
+       if (is_root_hub(urb->dev))
+               return;
+
+       if (usb_endpoint_xfer_control(&urb->ep->desc)
+           && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) {
+               if (hcd->self.uses_dma)
                        dma_unmap_single(hcd->self.controller, urb->setup_dma,
                                        sizeof(struct usb_ctrlrequest),
                                        DMA_TO_DEVICE);
-               if (urb->transfer_buffer_length != 0
-                       && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP))
+               else if (hcd->driver->flags & HCD_LOCAL_MEM)
+                       hcd_free_coherent(urb->dev->bus, &urb->setup_dma,
+                                       (void **)&urb->setup_packet,
+                                       sizeof(struct usb_ctrlrequest),
+                                       DMA_TO_DEVICE);
+       }
+
+       dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
+       if (urb->transfer_buffer_length != 0
+           && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)) {
+               if (hcd->self.uses_dma)
                        dma_unmap_single(hcd->self.controller,
                                        urb->transfer_dma,
                                        urb->transfer_buffer_length,
-                                       usb_urb_dir_in(urb)
-                                           ? DMA_FROM_DEVICE
-                                           : DMA_TO_DEVICE);
+                                       dir);
+               else if (hcd->driver->flags & HCD_LOCAL_MEM)
+                       hcd_free_coherent(urb->dev->bus, &urb->transfer_dma,
+                                       &urb->transfer_buffer,
+                                       urb->transfer_buffer_length,
+                                       dir);
        }
 }
 
@@ -1185,7 +1315,12 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags)
         * URBs must be submitted in process context with interrupts
         * enabled.
         */
-       map_urb_for_dma(hcd, urb);
+       status = map_urb_for_dma(hcd, urb, mem_flags);
+       if (unlikely(status)) {
+               usbmon_urb_submit_error(&hcd->self, urb, status);
+               goto error;
+       }
+
        if (is_root_hub(urb->dev))
                status = rh_urb_enqueue(hcd, urb);
        else
@@ -1194,6 +1329,7 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags)
        if (unlikely(status)) {
                usbmon_urb_submit_error(&hcd->self, urb, status);
                unmap_urb_for_dma(hcd, urb);
+ error:
                urb->hcpriv = NULL;
                INIT_LIST_HEAD(&urb->urb_list);
                atomic_dec(&urb->use_count);
@@ -1291,7 +1427,7 @@ void usb_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb, int status)
                wake_up (&usb_kill_urb_queue);
        usb_put_urb (urb);
 }
-EXPORT_SYMBOL (usb_hcd_giveback_urb);
+EXPORT_SYMBOL_GPL(usb_hcd_giveback_urb);
 
 /*-------------------------------------------------------------------------*/
 
@@ -1531,7 +1667,7 @@ int usb_bus_start_enum(struct usb_bus *bus, unsigned port_num)
                mod_timer(&hcd->rh_timer, jiffies + msecs_to_jiffies(10));
        return status;
 }
-EXPORT_SYMBOL (usb_bus_start_enum);
+EXPORT_SYMBOL_GPL(usb_bus_start_enum);
 
 #endif
 
@@ -1638,7 +1774,7 @@ struct usb_hcd *usb_create_hcd (const struct hc_driver *driver,
                        "USB Host Controller";
        return hcd;
 }
-EXPORT_SYMBOL (usb_create_hcd);
+EXPORT_SYMBOL_GPL(usb_create_hcd);
 
 static void hcd_release (struct kref *kref)
 {
@@ -1653,14 +1789,14 @@ struct usb_hcd *usb_get_hcd (struct usb_hcd *hcd)
                kref_get (&hcd->kref);
        return hcd;
 }
-EXPORT_SYMBOL (usb_get_hcd);
+EXPORT_SYMBOL_GPL(usb_get_hcd);
 
 void usb_put_hcd (struct usb_hcd *hcd)
 {
        if (hcd)
                kref_put (&hcd->kref, hcd_release);
 }
-EXPORT_SYMBOL (usb_put_hcd);
+EXPORT_SYMBOL_GPL(usb_put_hcd);
 
 /**
  * usb_add_hcd - finish generic HCD structure initialization and register
@@ -1786,7 +1922,7 @@ err_register_bus:
        hcd_buffer_destroy(hcd);
        return retval;
 } 
-EXPORT_SYMBOL (usb_add_hcd);
+EXPORT_SYMBOL_GPL(usb_add_hcd);
 
 /**
  * usb_remove_hcd - shutdown processing for generic HCDs
@@ -1828,7 +1964,7 @@ void usb_remove_hcd(struct usb_hcd *hcd)
        usb_deregister_bus(&hcd->self);
        hcd_buffer_destroy(hcd);
 }
-EXPORT_SYMBOL (usb_remove_hcd);
+EXPORT_SYMBOL_GPL(usb_remove_hcd);
 
 void
 usb_hcd_platform_shutdown(struct platform_device* dev)
@@ -1838,7 +1974,7 @@ usb_hcd_platform_shutdown(struct platform_device* dev)
        if (hcd->driver->shutdown)
                hcd->driver->shutdown(hcd);
 }
-EXPORT_SYMBOL (usb_hcd_platform_shutdown);
+EXPORT_SYMBOL_GPL(usb_hcd_platform_shutdown);
 
 /*-------------------------------------------------------------------------*/
 
index 98e24194a4ab61f3be641fd38d9eeb6283bca289..2d1c3d5e47b8b3e791bbbed28f857247da6ad2e9 100644 (file)
@@ -125,7 +125,7 @@ struct usb_hcd {
 
        /* more shared queuing code would be good; it should support
         * smarter scheduling, handle transaction translators, etc;
-        * input size of periodic table to an interrupt scheduler. 
+        * input size of periodic table to an interrupt scheduler.
         * (ohci 32, uhci 1024, ehci 256/512/1024).
         */
 
@@ -133,16 +133,16 @@ struct usb_hcd {
         * this structure.
         */
        unsigned long hcd_priv[0]
-                       __attribute__ ((aligned (sizeof(unsigned long))));
+                       __attribute__ ((aligned(sizeof(unsigned long))));
 };
 
 /* 2.4 does this a bit differently ... */
-static inline struct usb_bus *hcd_to_bus (struct usb_hcd *hcd)
+static inline struct usb_bus *hcd_to_bus(struct usb_hcd *hcd)
 {
        return &hcd->self;
 }
 
-static inline struct usb_hcd *bus_to_hcd (struct usb_bus *bus)
+static inline struct usb_hcd *bus_to_hcd(struct usb_bus *bus)
 {
        return container_of(bus, struct usb_hcd, self);
 }
@@ -165,6 +165,7 @@ struct hc_driver {
 
        int     flags;
 #define        HCD_MEMORY      0x0001          /* HC regs use memory (else I/O) */
+#define        HCD_LOCAL_MEM   0x0002          /* HC needs local memory */
 #define        HCD_USB11       0x0010          /* USB 1.1 */
 #define        HCD_USB2        0x0020          /* USB 2.0 */
 
@@ -201,15 +202,18 @@ struct hc_driver {
                        struct usb_host_endpoint *ep);
 
        /* root hub support */
-       int             (*hub_status_data) (struct usb_hcd *hcd, char *buf);
-       int             (*hub_control) (struct usb_hcd *hcd,
+       int     (*hub_status_data) (struct usb_hcd *hcd, char *buf);
+       int     (*hub_control) (struct usb_hcd *hcd,
                                u16 typeReq, u16 wValue, u16 wIndex,
                                char *buf, u16 wLength);
-       int             (*bus_suspend)(struct usb_hcd *);
-       int             (*bus_resume)(struct usb_hcd *);
-       int             (*start_port_reset)(struct usb_hcd *, unsigned port_num);
-       void            (*hub_irq_enable)(struct usb_hcd *);
+       int     (*bus_suspend)(struct usb_hcd *);
+       int     (*bus_resume)(struct usb_hcd *);
+       int     (*start_port_reset)(struct usb_hcd *, unsigned port_num);
+       void    (*hub_irq_enable)(struct usb_hcd *);
                /* Needed only if port-change IRQs are level-triggered */
+
+               /* force handover of high-speed port to full-speed companion */
+       void    (*relinquish_port)(struct usb_hcd *, int);
 };
 
 extern int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb);
@@ -217,56 +221,56 @@ extern int usb_hcd_check_unlink_urb(struct usb_hcd *hcd, struct urb *urb,
                int status);
 extern void usb_hcd_unlink_urb_from_ep(struct usb_hcd *hcd, struct urb *urb);
 
-extern int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags);
-extern int usb_hcd_unlink_urb (struct urb *urb, int status);
+extern int usb_hcd_submit_urb(struct urb *urb, gfp_t mem_flags);
+extern int usb_hcd_unlink_urb(struct urb *urb, int status);
 extern void usb_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb,
                int status);
 extern void usb_hcd_flush_endpoint(struct usb_device *udev,
                struct usb_host_endpoint *ep);
 extern void usb_hcd_disable_endpoint(struct usb_device *udev,
                struct usb_host_endpoint *ep);
-extern int usb_hcd_get_frame_number (struct usb_device *udev);
+extern int usb_hcd_get_frame_number(struct usb_device *udev);
 
-extern struct usb_hcd *usb_create_hcd (const struct hc_driver *driver,
+extern struct usb_hcd *usb_create_hcd(const struct hc_driver *driver,
                struct device *dev, char *bus_name);
-extern struct usb_hcd *usb_get_hcd (struct usb_hcd *hcd);
-extern void usb_put_hcd (struct usb_hcd *hcd);
+extern struct usb_hcd *usb_get_hcd(struct usb_hcd *hcd);
+extern void usb_put_hcd(struct usb_hcd *hcd);
 extern int usb_add_hcd(struct usb_hcd *hcd,
                unsigned int irqnum, unsigned long irqflags);
 extern void usb_remove_hcd(struct usb_hcd *hcd);
 
 struct platform_device;
-extern void usb_hcd_platform_shutdown(struct platform_devicedev);
+extern void usb_hcd_platform_shutdown(struct platform_device *dev);
 
 #ifdef CONFIG_PCI
 struct pci_dev;
 struct pci_device_id;
-extern int usb_hcd_pci_probe (struct pci_dev *dev,
+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);
+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 state);
-extern int usb_hcd_pci_resume (struct pci_dev *dev);
+extern int usb_hcd_pci_suspend(struct pci_dev *dev, pm_message_t state);
+extern int usb_hcd_pci_resume(struct pci_dev *dev);
 #endif /* CONFIG_PM */
 
-extern void usb_hcd_pci_shutdown (struct pci_dev *dev);
+extern void usb_hcd_pci_shutdown(struct pci_dev *dev);
 
 #endif /* CONFIG_PCI */
 
 /* pci-ish (pdev null is ok) buffer alloc/mapping support */
-int hcd_buffer_create (struct usb_hcd *hcd);
-void hcd_buffer_destroy (struct usb_hcd *hcd);
+int hcd_buffer_create(struct usb_hcd *hcd);
+void hcd_buffer_destroy(struct usb_hcd *hcd);
 
-void *hcd_buffer_alloc (struct usb_bus *bus, size_t size,
+void *hcd_buffer_alloc(struct usb_bus *bus, size_t size,
        gfp_t mem_flags, dma_addr_t *dma);
-void hcd_buffer_free (struct usb_bus *bus, size_t size,
+void hcd_buffer_free(struct usb_bus *bus, size_t size,
        void *addr, dma_addr_t dma);
 
 /* generic bus glue, needed for host controllers that don't use PCI */
-extern irqreturn_t usb_hcd_irq (int irq, void *__hcd);
+extern irqreturn_t usb_hcd_irq(int irq, void *__hcd);
 
-extern void usb_hc_died (struct usb_hcd *hcd);
+extern void usb_hc_died(struct usb_hcd *hcd);
 extern void usb_hcd_poll_rh_status(struct usb_hcd *hcd);
 
 /* -------------------------------------------------------------------------- */
@@ -319,9 +323,9 @@ extern void usb_destroy_configuration(struct usb_device *dev);
  * Generic bandwidth allocation constants/support
  */
 #define FRAME_TIME_USECS       1000L
-#define BitTime(bytecount)  (7 * 8 * bytecount / 6)  /* with integer truncation */
+#define BitTime(bytecount) (7 * 8 * bytecount / 6) /* with integer truncation */
                /* Trying not to use worst-case bit-stuffing
-                   of (7/6 * 8 * bytecount) = 9.33 * bytecount */
+                * of (7/6 * 8 * bytecount) = 9.33 * bytecount */
                /* bytecount = data payload byte count */
 
 #define NS_TO_US(ns)   ((ns + 500L) / 1000L)
@@ -333,9 +337,9 @@ extern void usb_destroy_configuration(struct usb_device *dev);
  */
 #define BW_HOST_DELAY  1000L           /* nanoseconds */
 #define BW_HUB_LS_SETUP        333L            /* nanoseconds */
-                        /* 4 full-speed bit times (est.) */
+                       /* 4 full-speed bit times (est.) */
 
-#define FRAME_TIME_BITS         12000L         /* frame = 1 millisecond */
+#define FRAME_TIME_BITS                        12000L  /* frame = 1 millisecond */
 #define FRAME_TIME_MAX_BITS_ALLOC      (90L * FRAME_TIME_BITS / 100L)
 #define FRAME_TIME_MAX_USECS_ALLOC     (90L * FRAME_TIME_USECS / 100L)
 
@@ -345,16 +349,16 @@ extern void usb_destroy_configuration(struct usb_device *dev);
  * to preallocate bandwidth)
  */
 #define USB2_HOST_DELAY        5       /* nsec, guess */
-#define HS_NSECS(bytes) ( ((55 * 8 * 2083) \
+#define HS_NSECS(bytes) (((55 * 8 * 2083) \
        + (2083UL * (3 + BitTime(bytes))))/1000 \
        + USB2_HOST_DELAY)
-#define HS_NSECS_ISO(bytes) ( ((38 * 8 * 2083) \
+#define HS_NSECS_ISO(bytes) (((38 * 8 * 2083) \
        + (2083UL * (3 + BitTime(bytes))))/1000 \
        + USB2_HOST_DELAY)
 #define HS_USECS(bytes) NS_TO_US (HS_NSECS(bytes))
 #define HS_USECS_ISO(bytes) NS_TO_US (HS_NSECS_ISO(bytes))
 
-extern long usb_calc_bus_time (int speed, int is_input,
+extern long usb_calc_bus_time(int speed, int is_input,
                        int isoc, int bytecount);
 
 /*-------------------------------------------------------------------------*/
@@ -370,16 +374,16 @@ extern struct list_head usb_bus_list;
 extern struct mutex usb_bus_list_lock;
 extern wait_queue_head_t usb_kill_urb_queue;
 
-extern void usb_enable_root_hub_irq (struct usb_bus *bus);
+extern void usb_enable_root_hub_irq(struct usb_bus *bus);
 
-extern int usb_find_interface_driver (struct usb_device *dev,
+extern int usb_find_interface_driver(struct usb_device *dev,
        struct usb_interface *interface);
 
 #define usb_endpoint_out(ep_dir)       (!((ep_dir) & USB_DIR_IN))
 
 #ifdef CONFIG_PM
-extern void usb_hcd_resume_root_hub (struct usb_hcd *hcd);
-extern void usb_root_hub_lost_power (struct usb_device *rhdev);
+extern void usb_hcd_resume_root_hub(struct usb_hcd *hcd);
+extern void usb_root_hub_lost_power(struct usb_device *rhdev);
 extern int hcd_bus_suspend(struct usb_device *rhdev);
 extern int hcd_bus_resume(struct usb_device *rhdev);
 #else
@@ -399,13 +403,13 @@ static inline void usb_hcd_resume_root_hub(struct usb_hcd *hcd)
  * these are expected to be called from the USB core/hub thread
  * with the kernel lock held
  */
-extern void usbfs_update_special (void);
+extern void usbfs_update_special(void);
 extern int usbfs_init(void);
 extern void usbfs_cleanup(void);
 
 #else /* CONFIG_USB_DEVICEFS */
 
-static inline void usbfs_update_special (void) {}
+static inline void usbfs_update_special(void) {}
 static inline int usbfs_init(void) { return 0; }
 static inline void usbfs_cleanup(void) { }
 
@@ -460,7 +464,7 @@ static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb,
 /*-------------------------------------------------------------------------*/
 
 /* hub.h ... DeviceRemovable in 2.4.2-ac11, gone in 2.4.10 */
-// bleech -- resurfaced in 2.4.11 or 2.4.12
+/* bleech -- resurfaced in 2.4.11 or 2.4.12 */
 #define bitmap         DeviceRemovable
 
 
@@ -468,8 +472,8 @@ static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb,
 
 /* random stuff */
 
-#define        RUN_CONTEXT (in_irq () ? "in_irq" \
-               : (in_interrupt () ? "in_interrupt" : "can sleep"))
+#define        RUN_CONTEXT (in_irq() ? "in_irq" \
+               : (in_interrupt() ? "in_interrupt" : "can sleep"))
 
 
 /* This rwsem is for use only by the hub driver and ehci-hcd.
index b04d232d4c6561720f219ff506fcd2a35a9c0caf..68fc5219ca152ae45144cd541f85ff0f0008a8d4 100644 (file)
 #define        USB_PERSIST     0
 #endif
 
+/* if we are in debug mode, always announce new devices */
+#ifdef DEBUG
+#ifndef CONFIG_USB_ANNOUNCE_NEW_DEVICES
+#define CONFIG_USB_ANNOUNCE_NEW_DEVICES
+#endif
+#endif
+
 struct usb_hub {
        struct device           *intfdev;       /* the "interface" device */
        struct usb_device       *hdev;
@@ -487,6 +494,7 @@ void usb_hub_tt_clear_buffer (struct usb_device *udev, int pipe)
        schedule_work (&tt->kevent);
        spin_unlock_irqrestore (&tt->lock, flags);
 }
+EXPORT_SYMBOL_GPL(usb_hub_tt_clear_buffer);
 
 static void hub_power_on(struct usb_hub *hub)
 {
@@ -1027,8 +1035,10 @@ static void recursively_mark_NOTATTACHED(struct usb_device *udev)
                if (udev->children[i])
                        recursively_mark_NOTATTACHED(udev->children[i]);
        }
-       if (udev->state == USB_STATE_SUSPENDED)
+       if (udev->state == USB_STATE_SUSPENDED) {
                udev->discon_suspended = 1;
+               udev->active_duration -= jiffies;
+       }
        udev->state = USB_STATE_NOTATTACHED;
 }
 
@@ -1077,6 +1087,12 @@ void usb_set_device_state(struct usb_device *udev,
                        else
                                device_init_wakeup(&udev->dev, 0);
                }
+               if (udev->state == USB_STATE_SUSPENDED &&
+                       new_state != USB_STATE_SUSPENDED)
+                       udev->active_duration -= jiffies;
+               else if (new_state == USB_STATE_SUSPENDED &&
+                               udev->state != USB_STATE_SUSPENDED)
+                       udev->active_duration += jiffies;
                udev->state = new_state;
        } else
                recursively_mark_NOTATTACHED(udev);
@@ -1207,7 +1223,7 @@ void usb_disconnect(struct usb_device **pdev)
        put_device(&udev->dev);
 }
 
-#ifdef DEBUG
+#ifdef CONFIG_USB_ANNOUNCE_NEW_DEVICES
 static void show_string(struct usb_device *udev, char *id, char *string)
 {
        if (!string)
@@ -1215,12 +1231,24 @@ static void show_string(struct usb_device *udev, char *id, char *string)
        dev_printk(KERN_INFO, &udev->dev, "%s: %s\n", id, string);
 }
 
+static void announce_device(struct usb_device *udev)
+{
+       dev_info(&udev->dev, "New USB device found, idVendor=%04x, idProduct=%04x\n",
+               le16_to_cpu(udev->descriptor.idVendor),
+               le16_to_cpu(udev->descriptor.idProduct));
+       dev_info(&udev->dev, "New USB device strings: Mfr=%d, Product=%d, "
+               "SerialNumber=%d\n",
+               udev->descriptor.iManufacturer,
+               udev->descriptor.iProduct,
+               udev->descriptor.iSerialNumber);
+       show_string(udev, "Product", udev->product);
+       show_string(udev, "Manufacturer", udev->manufacturer);
+       show_string(udev, "SerialNumber", udev->serial);
+}
 #else
-static inline void show_string(struct usb_device *udev, char *id, char *string)
-{}
+static inline void announce_device(struct usb_device *udev) { }
 #endif
 
-
 #ifdef CONFIG_USB_OTG
 #include "otg_whitelist.h"
 #endif
@@ -1390,14 +1418,7 @@ int usb_new_device(struct usb_device *udev)
        }
 
        /* Tell the world! */
-       dev_dbg(&udev->dev, "new device strings: Mfr=%d, Product=%d, "
-               "SerialNumber=%d\n",
-               udev->descriptor.iManufacturer,
-               udev->descriptor.iProduct,
-               udev->descriptor.iSerialNumber);
-       show_string(udev, "Product", udev->product);
-       show_string(udev, "Manufacturer", udev->manufacturer);
-       show_string(udev, "SerialNumber", udev->serial);
+       announce_device(udev);
        return err;
 
 fail:
@@ -2482,6 +2503,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
 {
        struct usb_device *hdev = hub->hdev;
        struct device *hub_dev = hub->intfdev;
+       struct usb_hcd *hcd = bus_to_hcd(hdev->bus);
        u16 wHubCharacteristics = le16_to_cpu(hub->descriptor->wHubCharacteristics);
        int status, i;
  
@@ -2645,6 +2667,8 @@ loop:
  
 done:
        hub_port_disable(hub, port1, 1);
+       if (hcd->driver->relinquish_port && !hub->hdev->parent)
+               hcd->driver->relinquish_port(hcd, port1);
 }
 
 static void hub_events(void)
@@ -2946,7 +2970,7 @@ static int config_descriptors_changed(struct usb_device *udev)
                if (len < le16_to_cpu(udev->config[index].desc.wTotalLength))
                        len = le16_to_cpu(udev->config[index].desc.wTotalLength);
        }
-       buf = kmalloc (len, GFP_KERNEL);
+       buf = kmalloc(len, GFP_NOIO);
        if (buf == NULL) {
                dev_err(&udev->dev, "no mem to re-read configs after reset\n");
                /* assume the worst */
@@ -3093,7 +3117,7 @@ re_enumerate:
        hub_port_logical_disconnect(parent_hub, port1);
        return -ENODEV;
 }
-EXPORT_SYMBOL(usb_reset_device);
+EXPORT_SYMBOL_GPL(usb_reset_device);
 
 /**
  * usb_reset_composite_device - warn interface drivers and perform a USB port reset
@@ -3110,16 +3134,12 @@ EXPORT_SYMBOL(usb_reset_device);
  * this from a driver probe() routine after downloading new firmware.
  * For calls that might not occur during probe(), drivers should lock
  * the device using usb_lock_device_for_reset().
- *
- * The interface locks are acquired during the pre_reset stage and released
- * during the post_reset stage.  However if iface is not NULL and is
- * currently being probed, we assume that the caller already owns its
- * lock.
  */
 int usb_reset_composite_device(struct usb_device *udev,
                struct usb_interface *iface)
 {
        int ret;
+       int i;
        struct usb_host_config *config = udev->actconfig;
 
        if (udev->state == USB_STATE_NOTATTACHED ||
@@ -3136,16 +3156,11 @@ int usb_reset_composite_device(struct usb_device *udev,
                iface = NULL;
 
        if (config) {
-               int i;
-               struct usb_interface *cintf;
-               struct usb_driver *drv;
-
                for (i = 0; i < config->desc.bNumInterfaces; ++i) {
-                       cintf = config->interface[i];
-                       if (cintf != iface)
-                               down(&cintf->dev.sem);
-                       if (device_is_registered(&cintf->dev) &&
-                                       cintf->dev.driver) {
+                       struct usb_interface *cintf = config->interface[i];
+                       struct usb_driver *drv;
+
+                       if (cintf->dev.driver) {
                                drv = to_usb_driver(cintf->dev.driver);
                                if (drv->pre_reset)
                                        (drv->pre_reset)(cintf);
@@ -3157,25 +3172,20 @@ int usb_reset_composite_device(struct usb_device *udev,
        ret = usb_reset_device(udev);
 
        if (config) {
-               int i;
-               struct usb_interface *cintf;
-               struct usb_driver *drv;
-
                for (i = config->desc.bNumInterfaces - 1; i >= 0; --i) {
-                       cintf = config->interface[i];
-                       if (device_is_registered(&cintf->dev) &&
-                                       cintf->dev.driver) {
+                       struct usb_interface *cintf = config->interface[i];
+                       struct usb_driver *drv;
+
+                       if (cintf->dev.driver) {
                                drv = to_usb_driver(cintf->dev.driver);
                                if (drv->post_reset)
                                        (drv->post_reset)(cintf);
        /* FIXME: Unbind if post_reset returns an error or isn't defined */
                        }
-                       if (cintf != iface)
-                               up(&cintf->dev.sem);
                }
        }
 
        usb_autosuspend_device(udev);
        return ret;
 }
-EXPORT_SYMBOL(usb_reset_composite_device);
+EXPORT_SYMBOL_GPL(usb_reset_composite_device);
index cf9559c6c9b64587829b894286754bb865b8546a..1551aed65e05c7dcc585e07883cd216dd8ed7718 100644 (file)
 #define USB_PORT_FEAT_TEST              21
 #define USB_PORT_FEAT_INDICATOR         22
 
-/* 
+/*
  * Hub Status and Hub Change results
  * See USB 2.0 spec Table 11-19 and Table 11-20
  */
 struct usb_port_status {
        __le16 wPortStatus;
-       __le16 wPortChange;     
+       __le16 wPortChange;
 } __attribute__ ((packed));
 
-/* 
+/*
  * wPortStatus bit field
  * See USB 2.0 spec Table 11-21
  */
@@ -81,7 +81,7 @@ struct usb_port_status {
 #define USB_PORT_STAT_INDICATOR         0x1000
 /* bits 13 to 15 are reserved */
 
-/* 
+/*
  * wPortChange bit field
  * See USB 2.0 spec Table 11-22
  * Bits 0 to 4 shown, bits 5 to 15 are reserved
@@ -93,7 +93,7 @@ struct usb_port_status {
 #define USB_PORT_STAT_C_RESET          0x0010
 
 /*
- * wHubCharacteristics (masks) 
+ * wHubCharacteristics (masks)
  * See USB 2.0 spec Table 11-13, offset 3
  */
 #define HUB_CHAR_LPSM          0x0003 /* D1 .. D0 */
@@ -119,8 +119,8 @@ struct usb_hub_status {
 #define HUB_CHANGE_OVERCURRENT 0x0002
 
 
-/* 
- * Hub descriptor 
+/*
+ * Hub descriptor
  * See USB 2.0 spec Table 11-13
  */
 
@@ -134,7 +134,7 @@ struct usb_hub_descriptor {
        __le16 wHubCharacteristics;
        __u8  bPwrOn2PwrGood;
        __u8  bHubContrCurrent;
-               /* add 1 bit for hub status change; round to bytes */
+               /* add 1 bit for hub status change; round to bytes */
        __u8  DeviceRemovable[(USB_MAXCHILDREN + 1 + 7) / 8];
        __u8  PortPwrCtrlMask[(USB_MAXCHILDREN + 1 + 7) / 8];
 } __attribute__ ((packed));
@@ -190,6 +190,6 @@ struct usb_tt_clear {
        u16                     devinfo;
 };
 
-extern void usb_hub_tt_clear_buffer (struct usb_device *dev, int pipe);
+extern void usb_hub_tt_clear_buffer(struct usb_device *dev, int pipe);
 
 #endif /* __LINUX_HUB_H */
index cd4f11157280de78cd5e73e82f043bde7d247182..83a373e9cc3624c66f09bac2c5383221e0eef8d2 100644 (file)
 #include <linux/usbdevice_fs.h>
 #include <linux/parser.h>
 #include <linux/notifier.h>
+#include <linux/seq_file.h>
 #include <asm/byteorder.h>
 #include "usb.h"
 #include "hcd.h"
 
+#define USBFS_DEFAULT_DEVMODE (S_IWUSR | S_IRUGO)
+#define USBFS_DEFAULT_BUSMODE (S_IXUGO | S_IRUGO)
+#define USBFS_DEFAULT_LISTMODE S_IRUGO
+
 static struct super_operations usbfs_ops;
 static const struct file_operations default_file_operations;
 static struct vfsmount *usbfs_mount;
@@ -57,9 +62,33 @@ static uid_t listuid;        /* = 0 */
 static gid_t devgid;   /* = 0 */
 static gid_t busgid;   /* = 0 */
 static gid_t listgid;  /* = 0 */
-static umode_t devmode = S_IWUSR | S_IRUGO;
-static umode_t busmode = S_IXUGO | S_IRUGO;
-static umode_t listmode = S_IRUGO;
+static umode_t devmode = USBFS_DEFAULT_DEVMODE;
+static umode_t busmode = USBFS_DEFAULT_BUSMODE;
+static umode_t listmode = USBFS_DEFAULT_LISTMODE;
+
+static int usbfs_show_options(struct seq_file *seq, struct vfsmount *mnt)
+{
+       if (devuid != 0)
+               seq_printf(seq, ",devuid=%u", devuid);
+       if (devgid != 0)
+               seq_printf(seq, ",devgid=%u", devgid);
+       if (devmode != USBFS_DEFAULT_DEVMODE)
+               seq_printf(seq, ",devmode=%o", devmode);
+       if (busuid != 0)
+               seq_printf(seq, ",busuid=%u", busuid);
+       if (busgid != 0)
+               seq_printf(seq, ",busgid=%u", busgid);
+       if (busmode != USBFS_DEFAULT_BUSMODE)
+               seq_printf(seq, ",busmode=%o", busmode);
+       if (listuid != 0)
+               seq_printf(seq, ",listuid=%u", listuid);
+       if (listgid != 0)
+               seq_printf(seq, ",listgid=%u", listgid);
+       if (listmode != USBFS_DEFAULT_LISTMODE)
+               seq_printf(seq, ",listmode=%o", listmode);
+
+       return 0;
+}
 
 enum {
        Opt_devuid, Opt_devgid, Opt_devmode,
@@ -93,9 +122,9 @@ static int parse_options(struct super_block *s, char *data)
        devgid = 0;
        busgid = 0;
        listgid = 0;
-       devmode = S_IWUSR | S_IRUGO;
-       busmode = S_IXUGO | S_IRUGO;
-       listmode = S_IRUGO;
+       devmode = USBFS_DEFAULT_DEVMODE;
+       busmode = USBFS_DEFAULT_BUSMODE;
+       listmode = USBFS_DEFAULT_LISTMODE;
 
        while ((p = strsep(&data, ",")) != NULL) {
                substring_t args[MAX_OPT_ARGS];
@@ -418,6 +447,7 @@ static struct super_operations usbfs_ops = {
        .statfs =       simple_statfs,
        .drop_inode =   generic_delete_inode,
        .remount_fs =   remount,
+       .show_options = usbfs_show_options,
 };
 
 static int usbfs_fill_super(struct super_block *sb, void *data, int silent)
index fcd40ecbeecce3276a8a1ecb31a0f204c1bf54f5..fefb92296e8f5a921edf849a30caf808cf904793 100644 (file)
@@ -39,7 +39,7 @@ static void usb_api_blocking_completion(struct urb *urb)
  * own interruptible routines.
  */
 static int usb_start_wait_urb(struct urb *urb, int timeout, int *actual_length)
-{ 
+{
        struct api_context ctx;
        unsigned long expire;
        int retval;
@@ -74,9 +74,9 @@ out:
 }
 
 /*-------------------------------------------------------------------*/
-// returns status (negative) or length (positive)
+/* returns status (negative) or length (positive) */
 static int usb_internal_control_msg(struct usb_device *usb_dev,
-                                   unsigned int pipe, 
+                                   unsigned int pipe,
                                    struct usb_ctrlrequest *cmd,
                                    void *data, int len, int timeout)
 {
@@ -87,7 +87,7 @@ static int usb_internal_control_msg(struct usb_device *usb_dev,
        urb = usb_alloc_urb(0, GFP_NOIO);
        if (!urb)
                return -ENOMEM;
-  
+
        usb_fill_control_urb(urb, usb_dev, pipe, (unsigned char *)cmd, data,
                             len, usb_api_blocking_completion, NULL);
 
@@ -99,47 +99,51 @@ static int usb_internal_control_msg(struct usb_device *usb_dev,
 }
 
 /**
- *     usb_control_msg - Builds a control urb, sends it off and waits for completion
- *     @dev: pointer to the usb device to send the message to
- *     @pipe: endpoint "pipe" to send the message to
- *     @request: USB message request value
- *     @requesttype: USB message request type value
- *     @value: USB message value
- *     @index: USB message index value
- *     @data: pointer to the data to send
- *     @size: length in bytes of the data to send
- *     @timeout: time in msecs to wait for the message to complete before
- *             timing out (if 0 the wait is forever)
- *     Context: !in_interrupt ()
- *
- *     This function sends a simple control message to a specified endpoint
- *     and waits for the message to complete, or timeout.
- *     
- *     If successful, it returns the number of bytes transferred, otherwise a negative error number.
- *
- *     Don't use this function from within an interrupt context, like a
- *     bottom half handler.  If you need an asynchronous message, or need to send
- *     a message from within interrupt context, use usb_submit_urb()
- *      If a thread in your driver uses this call, make sure your disconnect()
- *      method can wait for it to complete.  Since you don't have a handle on
- *      the URB used, you can't cancel the request.
+ * usb_control_msg - Builds a control urb, sends it off and waits for completion
+ * @dev: pointer to the usb device to send the message to
+ * @pipe: endpoint "pipe" to send the message to
+ * @request: USB message request value
+ * @requesttype: USB message request type value
+ * @value: USB message value
+ * @index: USB message index value
+ * @data: pointer to the data to send
+ * @size: length in bytes of the data to send
+ * @timeout: time in msecs to wait for the message to complete before timing
+ *     out (if 0 the wait is forever)
+ *
+ * Context: !in_interrupt ()
+ *
+ * This function sends a simple control message to a specified endpoint and
+ * waits for the message to complete, or timeout.
+ *
+ * If successful, it returns the number of bytes transferred, otherwise a
+ * negative error number.
+ *
+ * Don't use this function from within an interrupt context, like a bottom half
+ * handler.  If you need an asynchronous message, or need to send a message
+ * from within interrupt context, use usb_submit_urb().
+ * If a thread in your driver uses this call, make sure your disconnect()
+ * method can wait for it to complete.  Since you don't have a handle on the
+ * URB used, you can't cancel the request.
  */
-int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype,
-                        __u16 value, __u16 index, void *data, __u16 size, int timeout)
+int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request,
+                   __u8 requesttype, __u16 value, __u16 index, void *data,
+                   __u16 size, int timeout)
 {
-       struct usb_ctrlrequest *dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_NOIO);
+       struct usb_ctrlrequest *dr;
        int ret;
-       
+
+       dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_NOIO);
        if (!dr)
                return -ENOMEM;
 
-       dr->bRequestType= requesttype;
+       dr->bRequestType = requesttype;
        dr->bRequest = request;
        dr->wValue = cpu_to_le16p(&value);
        dr->wIndex = cpu_to_le16p(&index);
        dr->wLength = cpu_to_le16p(&size);
 
-       //dbg("usb_control_msg");       
+       /* dbg("usb_control_msg"); */
 
        ret = usb_internal_control_msg(dev, pipe, dr, data, size, timeout);
 
@@ -147,7 +151,7 @@ int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u
 
        return ret;
 }
-
+EXPORT_SYMBOL_GPL(usb_control_msg);
 
 /**
  * usb_interrupt_msg - Builds an interrupt urb, sends it off and waits for completion
@@ -155,9 +159,11 @@ int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u
  * @pipe: endpoint "pipe" to send the message to
  * @data: pointer to the data to send
  * @len: length in bytes of the data to send
- * @actual_length: pointer to a location to put the actual length transferred in bytes
+ * @actual_length: pointer to a location to put the actual length transferred
+ *     in bytes
  * @timeout: time in msecs to wait for the message to complete before
  *     timing out (if 0 the wait is forever)
+ *
  * Context: !in_interrupt ()
  *
  * This function sends a simple interrupt message to a specified endpoint and
@@ -181,38 +187,38 @@ int usb_interrupt_msg(struct usb_device *usb_dev, unsigned int pipe,
 EXPORT_SYMBOL_GPL(usb_interrupt_msg);
 
 /**
- *     usb_bulk_msg - Builds a bulk urb, sends it off and waits for completion
- *     @usb_dev: pointer to the usb device to send the message to
- *     @pipe: endpoint "pipe" to send the message to
- *     @data: pointer to the data to send
- *     @len: length in bytes of the data to send
- *     @actual_length: pointer to a location to put the actual length transferred in bytes
- *     @timeout: time in msecs to wait for the message to complete before
- *             timing out (if 0 the wait is forever)
- *     Context: !in_interrupt ()
- *
- *     This function sends a simple bulk message to a specified endpoint
- *     and waits for the message to complete, or timeout.
- *     
- *     If successful, it returns 0, otherwise a negative error number.
- *     The number of actual bytes transferred will be stored in the 
- *     actual_length paramater.
- *
- *     Don't use this function from within an interrupt context, like a
- *     bottom half handler.  If you need an asynchronous message, or need to
- *     send a message from within interrupt context, use usb_submit_urb()
- *      If a thread in your driver uses this call, make sure your disconnect()
- *      method can wait for it to complete.  Since you don't have a handle on
- *      the URB used, you can't cancel the request.
- *
- *     Because there is no usb_interrupt_msg() and no USBDEVFS_INTERRUPT
- *     ioctl, users are forced to abuse this routine by using it to submit
- *     URBs for interrupt endpoints.  We will take the liberty of creating
- *     an interrupt URB (with the default interval) if the target is an
- *     interrupt endpoint.
+ * usb_bulk_msg - Builds a bulk urb, sends it off and waits for completion
+ * @usb_dev: pointer to the usb device to send the message to
+ * @pipe: endpoint "pipe" to send the message to
+ * @data: pointer to the data to send
+ * @len: length in bytes of the data to send
+ * @actual_length: pointer to a location to put the actual length transferred
+ *     in bytes
+ * @timeout: time in msecs to wait for the message to complete before
+ *     timing out (if 0 the wait is forever)
+ *
+ * Context: !in_interrupt ()
+ *
+ * This function sends a simple bulk message to a specified endpoint
+ * and waits for the message to complete, or timeout.
+ *
+ * If successful, it returns 0, otherwise a negative error number.  The number
+ * of actual bytes transferred will be stored in the actual_length paramater.
+ *
+ * Don't use this function from within an interrupt context, like a bottom half
+ * handler.  If you need an asynchronous message, or need to send a message
+ * from within interrupt context, use usb_submit_urb() If a thread in your
+ * driver uses this call, make sure your disconnect() method can wait for it to
+ * complete.  Since you don't have a handle on the URB used, you can't cancel
+ * the request.
+ *
+ * Because there is no usb_interrupt_msg() and no USBDEVFS_INTERRUPT ioctl,
+ * users are forced to abuse this routine by using it to submit URBs for
+ * interrupt endpoints.  We will take the liberty of creating an interrupt URB
+ * (with the default interval) if the target is an interrupt endpoint.
  */
-int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, 
-                       void *data, int len, int *actual_length, int timeout)
+int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe,
+                void *data, int len, int *actual_length, int timeout)
 {
        struct urb *urb;
        struct usb_host_endpoint *ep;
@@ -238,29 +244,30 @@ int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe,
 
        return usb_start_wait_urb(urb, timeout, actual_length);
 }
+EXPORT_SYMBOL_GPL(usb_bulk_msg);
 
 /*-------------------------------------------------------------------*/
 
-static void sg_clean (struct usb_sg_request *io)
+static void sg_clean(struct usb_sg_request *io)
 {
        if (io->urbs) {
                while (io->entries--)
-                       usb_free_urb (io->urbs [io->entries]);
-               kfree (io->urbs);
+                       usb_free_urb(io->urbs [io->entries]);
+               kfree(io->urbs);
                io->urbs = NULL;
        }
        if (io->dev->dev.dma_mask != NULL)
-               usb_buffer_unmap_sg (io->dev, usb_pipein(io->pipe),
-                               io->sg, io->nents);
+               usb_buffer_unmap_sg(io->dev, usb_pipein(io->pipe),
+                                   io->sg, io->nents);
        io->dev = NULL;
 }
 
-static void sg_complete (struct urb *urb)
+static void sg_complete(struct urb *urb)
 {
-       struct usb_sg_request   *io = urb->context;
+       struct usb_sg_request *io = urb->context;
        int status = urb->status;
 
-       spin_lock (&io->lock);
+       spin_lock(&io->lock);
 
        /* In 2.5 we require hcds' endpoint queues not to progress after fault
         * reports, until the completion callback (this!) returns.  That lets
@@ -276,13 +283,13 @@ static void sg_complete (struct urb *urb)
                        && (io->status != -ECONNRESET
                                || status != -ECONNRESET)
                        && urb->actual_length) {
-               dev_err (io->dev->bus->controller,
+               dev_err(io->dev->bus->controller,
                        "dev %s ep%d%s scatterlist error %d/%d\n",
                        io->dev->devpath,
                        usb_endpoint_num(&urb->ep->desc),
                        usb_urb_dir_in(urb) ? "in" : "out",
                        status, io->status);
-               // BUG ();
+               /* BUG (); */
        }
 
        if (io->status == 0 && status && status != -ECONNRESET) {
@@ -294,22 +301,22 @@ static void sg_complete (struct urb *urb)
                 * unlink pending urbs so they won't rx/tx bad data.
                 * careful: unlink can sometimes be synchronous...
                 */
-               spin_unlock (&io->lock);
+               spin_unlock(&io->lock);
                for (i = 0, found = 0; i < io->entries; i++) {
                        if (!io->urbs [i] || !io->urbs [i]->dev)
                                continue;
                        if (found) {
-                               retval = usb_unlink_urb (io->urbs [i]);
+                               retval = usb_unlink_urb(io->urbs [i]);
                                if (retval != -EINPROGRESS &&
                                    retval != -ENODEV &&
                                    retval != -EBUSY)
-                                       dev_err (&io->dev->dev,
+                                       dev_err(&io->dev->dev,
                                                "%s, unlink --> %d\n",
                                                __FUNCTION__, retval);
                        } else if (urb == io->urbs [i])
                                found = 1;
                }
-               spin_lock (&io->lock);
+               spin_lock(&io->lock);
        }
        urb->dev = NULL;
 
@@ -317,9 +324,9 @@ static void sg_complete (struct urb *urb)
        io->bytes += urb->actual_length;
        io->count--;
        if (!io->count)
-               complete (&io->complete);
+               complete(&io->complete);
 
-       spin_unlock (&io->lock);
+       spin_unlock(&io->lock);
 }
 
 
@@ -348,28 +355,21 @@ static void sg_complete (struct urb *urb)
  * The request may be canceled with usb_sg_cancel(), either before or after
  * usb_sg_wait() is called.
  */
-int usb_sg_init (
-       struct usb_sg_request   *io,
-       struct usb_device       *dev,
-       unsigned                pipe, 
-       unsigned                period,
-       struct scatterlist      *sg,
-       int                     nents,
-       size_t                  length,
-       gfp_t                   mem_flags
-)
+int usb_sg_init(struct usb_sg_request *io, struct usb_device *dev,
+               unsigned pipe, unsigned period, struct scatterlist *sg,
+               int nents, size_t length, gfp_t mem_flags)
 {
-       int                     i;
-       int                     urb_flags;
-       int                     dma;
+       int i;
+       int urb_flags;
+       int dma;
 
        if (!io || !dev || !sg
-                       || usb_pipecontrol (pipe)
-                       || usb_pipeisoc (pipe)
+                       || usb_pipecontrol(pipe)
+                       || usb_pipeisoc(pipe)
                        || nents <= 0)
                return -EINVAL;
 
-       spin_lock_init (&io->lock);
+       spin_lock_init(&io->lock);
        io->dev = dev;
        io->pipe = pipe;
        io->sg = sg;
@@ -381,7 +381,7 @@ int usb_sg_init (
        dma = (dev->dev.dma_mask != NULL);
        if (dma)
                io->entries = usb_buffer_map_sg(dev, usb_pipein(pipe),
-                               sg, nents);
+                                               sg, nents);
        else
                io->entries = nents;
 
@@ -390,30 +390,30 @@ int usb_sg_init (
                return io->entries;
 
        io->count = io->entries;
-       io->urbs = kmalloc (io->entries * sizeof *io->urbs, mem_flags);
+       io->urbs = kmalloc(io->entries * sizeof *io->urbs, mem_flags);
        if (!io->urbs)
                goto nomem;
 
        urb_flags = URB_NO_TRANSFER_DMA_MAP | URB_NO_INTERRUPT;
-       if (usb_pipein (pipe))
+       if (usb_pipein(pipe))
                urb_flags |= URB_SHORT_NOT_OK;
 
        for (i = 0; i < io->entries; i++) {
-               unsigned                len;
+               unsigned len;
 
-               io->urbs [i] = usb_alloc_urb (0, mem_flags);
-               if (!io->urbs [i]) {
+               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]->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;
+               io->urbs[i]->complete = sg_complete;
+               io->urbs[i]->context = io;
 
                /*
                 * Some systems need to revert to PIO when DMA is temporarily
@@ -432,8 +432,8 @@ int usb_sg_init (
                 * to prevent stale pointers and to help spot bugs.
                 */
                if (dma) {
-                       io->urbs [i]->transfer_dma = sg_dma_address (sg + i);
-                       len = sg_dma_len (sg + i);
+                       io->urbs[i]->transfer_dma = sg_dma_address(sg + i);
+                       len = sg_dma_len(sg + i);
 #if defined(CONFIG_HIGHMEM) || defined(CONFIG_GART_IOMMU)
                        io->urbs[i]->transfer_buffer = NULL;
 #else
@@ -441,31 +441,31 @@ int usb_sg_init (
 #endif
                } else {
                        /* hc may use _only_ transfer_buffer */
-                       io->urbs [i]->transfer_buffer = sg_virt(&sg[i]);
-                       len = sg [i].length;
+                       io->urbs[i]->transfer_buffer = sg_virt(&sg[i]);
+                       len = sg[i].length;
                }
 
                if (length) {
-                       len = min_t (unsigned, len, 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->status = 0;
        io->bytes = 0;
-       init_completion (&io->complete);
+       init_completion(&io->complete);
        return 0;
 
 nomem:
-       sg_clean (io);
+       sg_clean(io);
        return -ENOMEM;
 }
-
+EXPORT_SYMBOL_GPL(usb_sg_init);
 
 /**
  * usb_sg_wait - synchronously execute scatter/gather request
@@ -506,31 +506,32 @@ nomem:
  * speed interrupt endpoints, which allow at most one packet per millisecond,
  * of at most 8 or 64 bytes (respectively).
  */
-void usb_sg_wait (struct usb_sg_request *io)
+void usb_sg_wait(struct usb_sg_request *io)
 {
-       int             i, entries = io->entries;
+       int i;
+       int entries = io->entries;
 
        /* queue the urbs.  */
-       spin_lock_irq (&io->lock);
+       spin_lock_irq(&io->lock);
        i = 0;
        while (i < entries && !io->status) {
-               int     retval;
+               int retval;
 
-               io->urbs [i]->dev = io->dev;
-               retval = usb_submit_urb (io->urbs [i], GFP_ATOMIC);
+               io->urbs[i]->dev = io->dev;
+               retval = usb_submit_urb(io->urbs [i], GFP_ATOMIC);
 
                /* after we submit, let completions or cancelations fire;
                 * we handshake using io->status.
                 */
-               spin_unlock_irq (&io->lock);
+               spin_unlock_irq(&io->lock);
                switch (retval) {
                        /* maybe we retrying will recover */
-               case -ENXIO:    // hc didn't queue this one
+               case -ENXIO:    /* hc didn't queue this one */
                case -EAGAIN:
                case -ENOMEM:
                        io->urbs[i]->dev = NULL;
                        retval = 0;
-                       yield ();
+                       yield();
                        break;
 
                        /* no error? continue immediately.
@@ -541,34 +542,35 @@ void usb_sg_wait (struct usb_sg_request *io)
                         */
                case 0:
                        ++i;
-                       cpu_relax ();
+                       cpu_relax();
                        break;
 
                        /* fail any uncompleted urbs */
                default:
-                       io->urbs [i]->dev = NULL;
-                       io->urbs [i]->status = retval;
-                       dev_dbg (&io->dev->dev, "%s, submit --> %d\n",
+                       io->urbs[i]->dev = NULL;
+                       io->urbs[i]->status = retval;
+                       dev_dbg(&io->dev->dev, "%s, submit --> %d\n",
                                __FUNCTION__, retval);
-                       usb_sg_cancel (io);
+                       usb_sg_cancel(io);
                }
-               spin_lock_irq (&io->lock);
+               spin_lock_irq(&io->lock);
                if (retval && (io->status == 0 || io->status == -ECONNRESET))
                        io->status = retval;
        }
        io->count -= entries - i;
        if (io->count == 0)
-               complete (&io->complete);
-       spin_unlock_irq (&io->lock);
+               complete(&io->complete);
+       spin_unlock_irq(&io->lock);
 
        /* OK, yes, this could be packaged as non-blocking.
         * So could the submit loop above ... but it's easier to
         * solve neither problem than to solve both!
         */
-       wait_for_completion (&io->complete);
+       wait_for_completion(&io->complete);
 
-       sg_clean (io);
+       sg_clean(io);
 }
+EXPORT_SYMBOL_GPL(usb_sg_wait);
 
 /**
  * usb_sg_cancel - stop scatter/gather i/o issued by usb_sg_wait()
@@ -578,32 +580,33 @@ void usb_sg_wait (struct usb_sg_request *io)
  * It can also prevents one initialized by usb_sg_init() from starting,
  * so that call just frees resources allocated to the request.
  */
-void usb_sg_cancel (struct usb_sg_request *io)
+void usb_sg_cancel(struct usb_sg_request *io)
 {
-       unsigned long   flags;
+       unsigned long flags;
 
-       spin_lock_irqsave (&io->lock, flags);
+       spin_lock_irqsave(&io->lock, flags);
 
        /* shut everything down, if it didn't already */
        if (!io->status) {
-               int     i;
+               int i;
 
                io->status = -ECONNRESET;
-               spin_unlock (&io->lock);
+               spin_unlock(&io->lock);
                for (i = 0; i < io->entries; i++) {
-                       int     retval;
+                       int retval;
 
                        if (!io->urbs [i]->dev)
                                continue;
-                       retval = usb_unlink_urb (io->urbs [i]);
+                       retval = usb_unlink_urb(io->urbs [i]);
                        if (retval != -EINPROGRESS && retval != -EBUSY)
-                               dev_warn (&io->dev->dev, "%s, unlink --> %d\n",
+                               dev_warn(&io->dev->dev, "%s, unlink --> %d\n",
                                        __FUNCTION__, retval);
                }
-               spin_lock (&io->lock);
+               spin_lock(&io->lock);
        }
-       spin_unlock_irqrestore (&io->lock, flags);
+       spin_unlock_irqrestore(&io->lock, flags);
 }
+EXPORT_SYMBOL_GPL(usb_sg_cancel);
 
 /*-------------------------------------------------------------------*/
 
@@ -629,12 +632,13 @@ void usb_sg_cancel (struct usb_sg_request *io)
  * Returns the number of bytes received on success, or else the status code
  * returned by the underlying usb_control_msg() call.
  */
-int usb_get_descriptor(struct usb_device *dev, unsigned char type, unsigned char index, void *buf, int size)
+int usb_get_descriptor(struct usb_device *dev, unsigned char type,
+                      unsigned char index, void *buf, int size)
 {
        int i;
        int result;
-       
-       memset(buf,0,size);     // Make sure we parse really received data
+
+       memset(buf, 0, size);   /* Make sure we parse really received data */
 
        for (i = 0; i < 3; ++i) {
                /* retry on length 0 or error; some devices are flakey */
@@ -652,6 +656,7 @@ int usb_get_descriptor(struct usb_device *dev, unsigned char type, unsigned char
        }
        return result;
 }
+EXPORT_SYMBOL_GPL(usb_get_descriptor);
 
 /**
  * usb_get_string - gets a string descriptor
@@ -708,7 +713,7 @@ static void usb_try_string_workarounds(unsigned char *buf, int *length)
 }
 
 static int usb_string_sub(struct usb_device *dev, unsigned int langid,
-               unsigned int index, unsigned char *buf)
+                         unsigned int index, unsigned char *buf)
 {
        int rc;
 
@@ -751,7 +756,7 @@ static int usb_string_sub(struct usb_device *dev, unsigned int langid,
  * @buf: where to put the string
  * @size: how big is "buf"?
  * 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
@@ -787,23 +792,23 @@ int usb_string(struct usb_device *dev, int index, char *buf, size_t size)
        if (!dev->have_langid) {
                err = usb_string_sub(dev, 0, 0, tbuf);
                if (err < 0) {
-                       dev_err (&dev->dev,
+                       dev_err(&dev->dev,
                                "string descriptor 0 read error: %d\n",
                                err);
                        goto errout;
                } else if (err < 4) {
-                       dev_err (&dev->dev, "string descriptor 0 too short\n");
+                       dev_err(&dev->dev, "string descriptor 0 too short\n");
                        err = -EINVAL;
                        goto errout;
                } else {
                        dev->have_langid = 1;
-                       dev->string_langid = tbuf[2] | (tbuf[3]<< 8);
-                               /* always use the first langid listed */
-                       dev_dbg (&dev->dev, "default language 0x%04x\n",
+                       dev->string_langid = tbuf[2] | (tbuf[3] << 8);
+                       /* always use the first langid listed */
+                       dev_dbg(&dev->dev, "default language 0x%04x\n",
                                dev->string_langid);
                }
        }
-       
+
        err = usb_string_sub(dev, dev->string_langid, index, tbuf);
        if (err < 0)
                goto errout;
@@ -821,12 +826,15 @@ int usb_string(struct usb_device *dev, int index, char *buf, size_t size)
        err = idx;
 
        if (tbuf[1] != USB_DT_STRING)
-               dev_dbg(&dev->dev, "wrong descriptor type %02x for string %d (\"%s\")\n", tbuf[1], index, buf);
+               dev_dbg(&dev->dev,
+                       "wrong descriptor type %02x for string %d (\"%s\")\n",
+                       tbuf[1], index, buf);
 
  errout:
        kfree(tbuf);
        return err;
 }
+EXPORT_SYMBOL_GPL(usb_string);
 
 /**
  * usb_cache_string - read a string descriptor and cache it for later use
@@ -842,9 +850,15 @@ char *usb_cache_string(struct usb_device *udev, int index)
        char *smallbuf = NULL;
        int len;
 
-       if (index > 0 && (buf = kmalloc(256, GFP_KERNEL)) != NULL) {
-               if ((len = usb_string(udev, index, buf, 256)) > 0) {
-                       if ((smallbuf = kmalloc(++len, GFP_KERNEL)) == NULL)
+       if (index <= 0)
+               return NULL;
+
+       buf = kmalloc(256, GFP_KERNEL);
+       if (buf) {
+               len = usb_string(udev, index, buf, 256);
+               if (len > 0) {
+                       smallbuf = kmalloc(++len, GFP_KERNEL);
+                       if (!smallbuf)
                                return buf;
                        memcpy(smallbuf, buf, len);
                }
@@ -883,7 +897,7 @@ int usb_get_device_descriptor(struct usb_device *dev, unsigned int size)
                return -ENOMEM;
 
        ret = usb_get_descriptor(dev, USB_DT_DEVICE, 0, desc, size);
-       if (ret >= 0) 
+       if (ret >= 0)
                memcpy(&dev->descriptor, desc, size);
        kfree(desc);
        return ret;
@@ -927,6 +941,7 @@ int usb_get_status(struct usb_device *dev, int type, int target, void *data)
        kfree(status);
        return ret;
 }
+EXPORT_SYMBOL_GPL(usb_get_status);
 
 /**
  * usb_clear_halt - tells device to clear endpoint halt/stall condition
@@ -955,8 +970,8 @@ int usb_clear_halt(struct usb_device *dev, int pipe)
 {
        int result;
        int endp = usb_pipeendpoint(pipe);
-       
-       if (usb_pipein (pipe))
+
+       if (usb_pipein(pipe))
                endp |= USB_DIR_IN;
 
        /* we don't care if it wasn't halted first. in fact some devices
@@ -985,6 +1000,7 @@ int usb_clear_halt(struct usb_device *dev, int pipe)
 
        return 0;
 }
+EXPORT_SYMBOL_GPL(usb_clear_halt);
 
 /**
  * usb_disable_endpoint -- Disable an endpoint by address
@@ -1038,7 +1054,7 @@ void usb_disable_interface(struct usb_device *dev, struct usb_interface *intf)
        }
 }
 
-/*
+/**
  * usb_disable_device - Disable all the endpoints for a USB device
  * @dev: the device whose endpoints are being disabled
  * @skip_ep0: 0 to disable endpoint 0, 1 to skip it.
@@ -1053,7 +1069,7 @@ void usb_disable_device(struct usb_device *dev, int skip_ep0)
        int i;
 
        dev_dbg(&dev->dev, "%s nuking %s URBs\n", __FUNCTION__,
-                       skip_ep0 ? "non-ep0" : "all");
+               skip_ep0 ? "non-ep0" : "all");
        for (i = skip_ep0; i < 16; ++i) {
                usb_disable_endpoint(dev, i);
                usb_disable_endpoint(dev, i + USB_DIR_IN);
@@ -1071,17 +1087,17 @@ void usb_disable_device(struct usb_device *dev, int skip_ep0)
                        interface = dev->actconfig->interface[i];
                        if (!device_is_registered(&interface->dev))
                                continue;
-                       dev_dbg (&dev->dev, "unregistering interface %s\n",
+                       dev_dbg(&dev->dev, "unregistering interface %s\n",
                                interface->dev.bus_id);
                        usb_remove_sysfs_intf_files(interface);
-                       device_del (&interface->dev);
+                       device_del(&interface->dev);
                }
 
                /* Now that the interfaces are unbound, nobody should
                 * try to access them.
                 */
                for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) {
-                       put_device (&dev->actconfig->interface[i]->dev);
+                       put_device(&dev->actconfig->interface[i]->dev);
                        dev->actconfig->interface[i] = NULL;
                }
                dev->actconfig = NULL;
@@ -1090,8 +1106,7 @@ void usb_disable_device(struct usb_device *dev, int skip_ep0)
        }
 }
 
-
-/*
+/**
  * usb_enable_endpoint - Enable an endpoint for USB communications
  * @dev: the device whose interface is being enabled
  * @ep: the endpoint
@@ -1116,7 +1131,7 @@ void usb_enable_endpoint(struct usb_device *dev, struct usb_host_endpoint *ep)
        ep->enabled = 1;
 }
 
-/*
+/**
  * usb_enable_interface - Enable all the endpoints for an interface
  * @dev: the device whose interface is being enabled
  * @intf: pointer to the interface descriptor
@@ -1172,6 +1187,8 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)
        struct usb_host_interface *alt;
        int ret;
        int manual = 0;
+       unsigned int epaddr;
+       unsigned int pipe;
 
        if (dev->state == USB_STATE_SUSPENDED)
                return -EHOSTUNREACH;
@@ -1226,11 +1243,11 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)
                int i;
 
                for (i = 0; i < alt->desc.bNumEndpoints; i++) {
-                       unsigned int epaddr =
-                               alt->endpoint[i].desc.bEndpointAddress;
-                       unsigned int pipe =
-       __create_pipe(dev, USB_ENDPOINT_NUMBER_MASK & epaddr)
-       | (usb_endpoint_out(epaddr) ? USB_DIR_OUT : USB_DIR_IN);
+                       epaddr = alt->endpoint[i].desc.bEndpointAddress;
+                       pipe = __create_pipe(dev,
+                                       USB_ENDPOINT_NUMBER_MASK & epaddr) |
+                                       (usb_endpoint_out(epaddr) ?
+                                       USB_DIR_OUT : USB_DIR_IN);
 
                        usb_clear_halt(dev, pipe);
                }
@@ -1253,6 +1270,7 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)
 
        return 0;
 }
+EXPORT_SYMBOL_GPL(usb_set_interface);
 
 /**
  * usb_reset_configuration - lightweight device reset
@@ -1328,6 +1346,7 @@ int usb_reset_configuration(struct usb_device *dev)
        }
        return 0;
 }
+EXPORT_SYMBOL_GPL(usb_reset_configuration);
 
 static void usb_release_interface(struct device *dev)
 {
@@ -1357,7 +1376,8 @@ static int usb_if_uevent(struct device *dev, struct kobj_uevent_env *env)
                return -ENOMEM;
 
        if (add_uevent_var(env,
-                  "MODALIAS=usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic%02Xisc%02Xip%02X",
+                  "MODALIAS=usb:"
+                  "v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic%02Xisc%02Xip%02X",
                   le16_to_cpu(usb_dev->descriptor.idVendor),
                   le16_to_cpu(usb_dev->descriptor.idProduct),
                   le16_to_cpu(usb_dev->descriptor.bcdDevice),
@@ -1387,8 +1407,8 @@ struct device_type usb_if_device_type = {
 };
 
 static struct usb_interface_assoc_descriptor *find_iad(struct usb_device *dev,
-                                                      struct usb_host_config *config,
-                                                      u8 inum)
+                                               struct usb_host_config *config,
+                                               u8 inum)
 {
        struct usb_interface_assoc_descriptor *retval = NULL;
        struct usb_interface_assoc_descriptor *intf_assoc;
@@ -1415,7 +1435,6 @@ static struct usb_interface_assoc_descriptor *find_iad(struct usb_device *dev,
        return retval;
 }
 
-
 /*
  * usb_set_configuration - Makes a particular device setting be current
  * @dev: the device whose configuration is being updated
@@ -1533,12 +1552,12 @@ free_interfaces:
         * getting rid of old interfaces means unbinding their drivers.
         */
        if (dev->state != USB_STATE_ADDRESS)
-               usb_disable_device (dev, 1);    // Skip ep0
-
-       if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
-                       USB_REQ_SET_CONFIGURATION, 0, configuration, 0,
-                       NULL, 0, USB_CTRL_SET_TIMEOUT)) < 0) {
+               usb_disable_device(dev, 1);     /* Skip ep0 */
 
+       ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+                             USB_REQ_SET_CONFIGURATION, 0, configuration, 0,
+                             NULL, 0, USB_CTRL_SET_TIMEOUT);
+       if (ret < 0) {
                /* All the old state is gone, so what else can we do?
                 * The device is probably useless now anyway.
                 */
@@ -1585,11 +1604,11 @@ free_interfaces:
                intf->dev.bus = &usb_bus_type;
                intf->dev.type = &usb_if_device_type;
                intf->dev.dma_mask = dev->dev.dma_mask;
-               device_initialize (&intf->dev);
+               device_initialize(&intf->dev);
                mark_quiesced(intf);
-               sprintf (&intf->dev.bus_id[0], "%d-%s:%d.%d",
-                        dev->bus->busnum, dev->devpath,
-                        configuration, alt->desc.bInterfaceNumber);
+               sprintf(&intf->dev.bus_id[0], "%d-%s:%d.%d",
+                       dev->bus->busnum, dev->devpath,
+                       configuration, alt->desc.bInterfaceNumber);
        }
        kfree(new_interfaces);
 
@@ -1605,11 +1624,11 @@ free_interfaces:
        for (i = 0; i < nintf; ++i) {
                struct usb_interface *intf = cp->interface[i];
 
-               dev_dbg (&dev->dev,
+               dev_dbg(&dev->dev,
                        "adding %s (config #%d, interface %d)\n",
                        intf->dev.bus_id, configuration,
                        intf->cur_altsetting->desc.bInterfaceNumber);
-               ret = device_add (&intf->dev);
+               ret = device_add(&intf->dev);
                if (ret != 0) {
                        dev_err(&dev->dev, "device_add(%s) --> %d\n",
                                intf->dev.bus_id, ret);
@@ -1677,22 +1696,3 @@ int usb_driver_set_configuration(struct usb_device *udev, int config)
        return 0;
 }
 EXPORT_SYMBOL_GPL(usb_driver_set_configuration);
-
-// synchronous request completion model
-EXPORT_SYMBOL(usb_control_msg);
-EXPORT_SYMBOL(usb_bulk_msg);
-
-EXPORT_SYMBOL(usb_sg_init);
-EXPORT_SYMBOL(usb_sg_cancel);
-EXPORT_SYMBOL(usb_sg_wait);
-
-// synchronous control message convenience routines
-EXPORT_SYMBOL(usb_get_descriptor);
-EXPORT_SYMBOL(usb_get_status);
-EXPORT_SYMBOL(usb_string);
-
-// synchronous calls that also maintain usbcore state
-EXPORT_SYMBOL(usb_clear_halt);
-EXPORT_SYMBOL(usb_reset_configuration);
-EXPORT_SYMBOL(usb_set_interface);
-
index 6b36897ca151998ab28f07c12f0e9baef9e372fe..7542dce3f5a1e2b01bcbd2ef78c08bd870c31b1a 100644 (file)
@@ -33,7 +33,7 @@ EXPORT_SYMBOL_GPL(usb_register_notify);
  * usb_unregister_notify - unregister a notifier callback
  * @nb: pointer to the notifier block for the callback events.
  *
- * usb_register_notifier() must have been previously called for this function
+ * usb_register_notify() must have been previously called for this function
  * to work properly.
  */
 void usb_unregister_notify(struct notifier_block *nb)
index 7f31a495a25d31f327f3bbf63239a9cd5d6a5349..e8cdce571bb1cb3ae4b1748638bf817b86839160 100644 (file)
@@ -14,7 +14,7 @@
  * mostly use of USB_DEVICE() or USB_DEVICE_VER() entries..
  *
  * YOU _SHOULD_ CHANGE THIS LIST TO MATCH YOUR PRODUCT AND ITS TESTING!
- */ 
+ */
 
 static struct usb_device_id whitelist_table [] = {
 
@@ -55,7 +55,7 @@ static int is_targeted(struct usb_device *dev)
                return 1;
 
        /* HNP test device is _never_ targeted (see OTG spec 6.6.6) */
-       if ((le16_to_cpu(dev->descriptor.idVendor) == 0x1a0a && 
+       if ((le16_to_cpu(dev->descriptor.idVendor) == 0x1a0a &&
             le16_to_cpu(dev->descriptor.idProduct) == 0xbadd))
                return 0;
 
@@ -86,7 +86,7 @@ static int is_targeted(struct usb_device *dev)
                        continue;
 
                if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_SUBCLASS) &&
-                   (id->bDeviceSubClass!= dev->descriptor.bDeviceSubClass))
+                   (id->bDeviceSubClass != dev->descriptor.bDeviceSubClass))
                        continue;
 
                if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_PROTOCOL) &&
index 32bd130b1eed33fc542fc39bc5f10c1de4695916..a37ccbd1e007c478022ff02b22beeef3fd81976f 100644 (file)
@@ -72,7 +72,7 @@ set_bConfigurationValue(struct device *dev, struct device_attribute *attr,
        return (value < 0) ? value : count;
 }
 
-static DEVICE_ATTR(bConfigurationValue, S_IRUGO | S_IWUSR, 
+static DEVICE_ATTR(bConfigurationValue, S_IRUGO | S_IWUSR,
                show_bConfigurationValue, set_bConfigurationValue);
 
 /* String fields */
@@ -248,6 +248,41 @@ static void remove_persist_attributes(struct device *dev)
 
 #ifdef CONFIG_USB_SUSPEND
 
+static ssize_t
+show_connected_duration(struct device *dev, struct device_attribute *attr,
+               char *buf)
+{
+       struct usb_device *udev = to_usb_device(dev);
+
+       return sprintf(buf, "%u\n",
+                       jiffies_to_msecs(jiffies - udev->connect_time));
+}
+
+static DEVICE_ATTR(connected_duration, S_IRUGO, show_connected_duration, NULL);
+
+/*
+ * If the device is resumed, the last time the device was suspended has
+ * been pre-subtracted from active_duration.  We add the current time to
+ * get the duration that the device was actually active.
+ *
+ * If the device is suspended, the active_duration is up-to-date.
+ */
+static ssize_t
+show_active_duration(struct device *dev, struct device_attribute *attr,
+               char *buf)
+{
+       struct usb_device *udev = to_usb_device(dev);
+       int duration;
+
+       if (udev->state != USB_STATE_SUSPENDED)
+               duration = jiffies_to_msecs(jiffies + udev->active_duration);
+       else
+               duration = jiffies_to_msecs(udev->active_duration);
+       return sprintf(buf, "%u\n", duration);
+}
+
+static DEVICE_ATTR(active_duration, S_IRUGO, show_active_duration, NULL);
+
 static ssize_t
 show_autosuspend(struct device *dev, struct device_attribute *attr, char *buf)
 {
@@ -365,12 +400,26 @@ static int add_power_attributes(struct device *dev)
                        rc = sysfs_add_file_to_group(&dev->kobj,
                                        &dev_attr_level.attr,
                                        power_group);
+               if (rc == 0)
+                       rc = sysfs_add_file_to_group(&dev->kobj,
+                                       &dev_attr_connected_duration.attr,
+                                       power_group);
+               if (rc == 0)
+                       rc = sysfs_add_file_to_group(&dev->kobj,
+                                       &dev_attr_active_duration.attr,
+                                       power_group);
        }
        return rc;
 }
 
 static void remove_power_attributes(struct device *dev)
 {
+       sysfs_remove_file_from_group(&dev->kobj,
+                       &dev_attr_active_duration.attr,
+                       power_group);
+       sysfs_remove_file_from_group(&dev->kobj,
+                       &dev_attr_connected_duration.attr,
+                       power_group);
        sysfs_remove_file_from_group(&dev->kobj,
                        &dev_attr_level.attr,
                        power_group);
@@ -601,21 +650,21 @@ void usb_remove_sysfs_dev_files(struct usb_device *udev)
 /* Interface Accociation Descriptor fields */
 #define usb_intf_assoc_attr(field, format_string)                      \
 static ssize_t                                                         \
-show_iad_##field (struct device *dev, struct device_attribute *attr,   \
+show_iad_##field(struct device *dev, struct device_attribute *attr,    \
                char *buf)                                              \
 {                                                                      \
-       struct usb_interface *intf = to_usb_interface (dev);            \
+       struct usb_interface *intf = to_usb_interface(dev);             \
                                                                        \
-       return sprintf (buf, format_string,                             \
-                       intf->intf_assoc->field);               \
+       return sprintf(buf, format_string,                              \
+                       intf->intf_assoc->field);                       \
 }                                                                      \
 static DEVICE_ATTR(iad_##field, S_IRUGO, show_iad_##field, NULL);
 
-usb_intf_assoc_attr (bFirstInterface, "%02x\n")
-usb_intf_assoc_attr (bInterfaceCount, "%02d\n")
-usb_intf_assoc_attr (bFunctionClass, "%02x\n")
-usb_intf_assoc_attr (bFunctionSubClass, "%02x\n")
-usb_intf_assoc_attr (bFunctionProtocol, "%02x\n")
+usb_intf_assoc_attr(bFirstInterface, "%02x\n")
+usb_intf_assoc_attr(bInterfaceCount, "%02d\n")
+usb_intf_assoc_attr(bFunctionClass, "%02x\n")
+usb_intf_assoc_attr(bFunctionSubClass, "%02x\n")
+usb_intf_assoc_attr(bFunctionProtocol, "%02x\n")
 
 /* Interface fields */
 #define usb_intf_attr(field, format_string)                            \
index d05ead20081c6cdb2ae9ce6c16be8a99c2862bfc..9d7e63292c01175647503b65e821cdd3b94dc381 100644 (file)
@@ -42,6 +42,7 @@ void usb_init_urb(struct urb *urb)
                INIT_LIST_HEAD(&urb->anchor_list);
        }
 }
+EXPORT_SYMBOL_GPL(usb_init_urb);
 
 /**
  * usb_alloc_urb - creates a new urb for a USB driver to use
@@ -73,6 +74,7 @@ struct urb *usb_alloc_urb(int iso_packets, gfp_t mem_flags)
        usb_init_urb(urb);
        return urb;
 }
+EXPORT_SYMBOL_GPL(usb_alloc_urb);
 
 /**
  * usb_free_urb - frees the memory used by a urb when all users of it are finished
@@ -89,6 +91,7 @@ void usb_free_urb(struct urb *urb)
        if (urb)
                kref_put(&urb->kref, urb_destroy);
 }
+EXPORT_SYMBOL_GPL(usb_free_urb);
 
 /**
  * usb_get_urb - increments the reference count of the urb
@@ -100,12 +103,13 @@ void usb_free_urb(struct urb *urb)
  *
  * A pointer to the urb with the incremented reference counter is returned.
  */
-struct urb * usb_get_urb(struct urb *urb)
+struct urb *usb_get_urb(struct urb *urb)
 {
        if (urb)
                kref_get(&urb->kref);
        return urb;
 }
+EXPORT_SYMBOL_GPL(usb_get_urb);
 
 /**
  * usb_anchor_urb - anchors an URB while it is processed
@@ -172,7 +176,7 @@ EXPORT_SYMBOL_GPL(usb_unanchor_urb);
  * describing that request to the USB subsystem.  Request completion will
  * be indicated later, asynchronously, by calling the completion handler.
  * The three types of completion are success, error, and unlink
- * (a software-induced fault, also called "request cancellation").  
+ * (a software-induced fault, also called "request cancellation").
  *
  * URBs may be submitted in interrupt context.
  *
@@ -255,7 +259,7 @@ EXPORT_SYMBOL_GPL(usb_unanchor_urb);
  *       semaphores), or
  *   (c) current->state != TASK_RUNNING, this is the case only after
  *       you've changed it.
- * 
+ *
  * GFP_NOIO is used in the block io path and error handling of storage
  * devices.
  *
@@ -284,7 +288,8 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
 
        if (!urb || urb->hcpriv || !urb->complete)
                return -EINVAL;
-       if (!(dev = urb->dev) || dev->state < USB_STATE_DEFAULT)
+       dev = urb->dev;
+       if ((!dev) || (dev->state < USB_STATE_DEFAULT))
                return -ENODEV;
 
        /* For now, get the endpoint from the pipe.  Eventually drivers
@@ -347,11 +352,11 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
                        max *= mult;
                }
 
-               if (urb->number_of_packets <= 0)                    
+               if (urb->number_of_packets <= 0)
                        return -EINVAL;
                for (n = 0; n < urb->number_of_packets; n++) {
                        len = urb->iso_frame_desc[n].length;
-                       if (len < 0 || len > max) 
+                       if (len < 0 || len > max)
                                return -EMSGSIZE;
                        urb->iso_frame_desc[n].status = -EXDEV;
                        urb->iso_frame_desc[n].actual_length = 0;
@@ -416,7 +421,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
                /* too big? */
                switch (dev->speed) {
                case USB_SPEED_HIGH:    /* units are microframes */
-                       // NOTE usb handles 2^15
+                       /* NOTE usb handles 2^15 */
                        if (urb->interval > (1024 * 8))
                                urb->interval = 1024 * 8;
                        max = 1024 * 8;
@@ -426,12 +431,12 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
                        if (xfertype == USB_ENDPOINT_XFER_INT) {
                                if (urb->interval > 255)
                                        return -EINVAL;
-                               // NOTE ohci only handles up to 32
+                               /* NOTE ohci only handles up to 32 */
                                max = 128;
                        } else {
                                if (urb->interval > 1024)
                                        urb->interval = 1024;
-                               // NOTE usb and ohci handle up to 2^15
+                               /* NOTE usb and ohci handle up to 2^15 */
                                max = 1024;
                        }
                        break;
@@ -444,6 +449,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
 
        return usb_hcd_submit_urb(urb, mem_flags);
 }
+EXPORT_SYMBOL_GPL(usb_submit_urb);
 
 /*-------------------------------------------------------------------*/
 
@@ -514,6 +520,7 @@ int usb_unlink_urb(struct urb *urb)
                return -EIDRM;
        return usb_hcd_unlink_urb(urb, -ECONNRESET);
 }
+EXPORT_SYMBOL_GPL(usb_unlink_urb);
 
 /**
  * usb_kill_urb - cancel a transfer request and wait for it to finish
@@ -553,6 +560,7 @@ void usb_kill_urb(struct urb *urb)
        --urb->reject;
        mutex_unlock(&reject_mutex);
 }
+EXPORT_SYMBOL_GPL(usb_kill_urb);
 
 /**
  * usb_kill_anchored_urbs - cancel transfer requests en masse
@@ -567,7 +575,8 @@ void usb_kill_anchored_urbs(struct usb_anchor *anchor)
 
        spin_lock_irq(&anchor->lock);
        while (!list_empty(&anchor->urb_list)) {
-               victim = list_entry(anchor->urb_list.prev, struct urb, anchor_list);
+               victim = list_entry(anchor->urb_list.prev, struct urb,
+                                   anchor_list);
                /* we must make sure the URB isn't freed before we kill it*/
                usb_get_urb(victim);
                spin_unlock_irq(&anchor->lock);
@@ -595,11 +604,3 @@ int usb_wait_anchor_empty_timeout(struct usb_anchor *anchor,
                                  msecs_to_jiffies(timeout));
 }
 EXPORT_SYMBOL_GPL(usb_wait_anchor_empty_timeout);
-
-EXPORT_SYMBOL(usb_init_urb);
-EXPORT_SYMBOL(usb_alloc_urb);
-EXPORT_SYMBOL(usb_free_urb);
-EXPORT_SYMBOL(usb_get_urb);
-EXPORT_SYMBOL(usb_submit_urb);
-EXPORT_SYMBOL(usb_unlink_urb);
-EXPORT_SYMBOL(usb_kill_urb);
index 8f142370103d48400d3adb6cb6b6f36eab5e4070..4e984060c984b4cbb715607f26ab13dfb05d357e 100644 (file)
@@ -96,6 +96,7 @@ struct usb_interface *usb_ifnum_to_if(const struct usb_device *dev,
 
        return NULL;
 }
+EXPORT_SYMBOL_GPL(usb_ifnum_to_if);
 
 /**
  * usb_altnum_to_altsetting - get the altsetting structure with a given
@@ -115,8 +116,9 @@ struct usb_interface *usb_ifnum_to_if(const struct usb_device *dev,
  * Don't call this function unless you are bound to the intf interface
  * or you have locked the device!
  */
-struct usb_host_interface *usb_altnum_to_altsetting(const struct usb_interface *intf,
-                                                   unsigned int altnum)
+struct usb_host_interface *usb_altnum_to_altsetting(
+                                       const struct usb_interface *intf,
+                                       unsigned int altnum)
 {
        int i;
 
@@ -126,13 +128,14 @@ struct usb_host_interface *usb_altnum_to_altsetting(const struct usb_interface *
        }
        return NULL;
 }
+EXPORT_SYMBOL_GPL(usb_altnum_to_altsetting);
 
 struct find_interface_arg {
        int minor;
        struct usb_interface *interface;
 };
 
-static int __find_interface(struct device * dev, void * data)
+static int __find_interface(struct device *dev, void *data)
 {
        struct find_interface_arg *arg = data;
        struct usb_interface *intf;
@@ -154,7 +157,7 @@ static int __find_interface(struct device * dev, void * data)
  * @drv: the driver whose current configuration is considered
  * @minor: the minor number of the desired device
  *
- * This walks the driver device list and returns a pointer to the interface 
+ * This walks the driver device list and returns a pointer to the interface
  * with the matching minor.  Note, this only works for devices that share the
  * USB major number.
  */
@@ -170,6 +173,7 @@ struct usb_interface *usb_find_interface(struct usb_driver *drv, int minor)
                                        __find_interface);
        return argb.interface;
 }
+EXPORT_SYMBOL_GPL(usb_find_interface);
 
 /**
  * usb_release_dev - free a usb device structure when all users of it are finished.
@@ -230,7 +234,7 @@ static int ksuspend_usb_init(void)
         * singlethreaded.  Its job doesn't justify running on more
         * than one CPU.
         */
-       ksuspend_usb_wq = create_freezeable_workqueue("ksuspend_usbd");
+       ksuspend_usb_wq = create_singlethread_workqueue("ksuspend_usbd");
        if (!ksuspend_usb_wq)
                return -ENOMEM;
        return 0;
@@ -269,8 +273,8 @@ static unsigned usb_bus_is_wusb(struct usb_bus *bus)
  *
  * This call may not be used in a non-sleeping context.
  */
-struct usb_device *
-usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1)
+struct usb_device *usb_alloc_dev(struct usb_device *parent,
+                                struct usb_bus *bus, unsigned port1)
 {
        struct usb_device *dev;
        struct usb_hcd *usb_hcd = container_of(bus, struct usb_hcd, self);
@@ -339,6 +343,8 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1)
        mutex_init(&dev->pm_mutex);
        INIT_DELAYED_WORK(&dev->autosuspend, usb_autosuspend_work);
        dev->autosuspend_delay = usb_autosuspend_delay * HZ;
+       dev->connect_time = jiffies;
+       dev->active_duration = -jiffies;
 #endif
        if (root_hub)   /* Root hub always ok [and always wired] */
                dev->authorized = 1;
@@ -367,6 +373,7 @@ struct usb_device *usb_get_dev(struct usb_device *dev)
                get_device(&dev->dev);
        return dev;
 }
+EXPORT_SYMBOL_GPL(usb_get_dev);
 
 /**
  * usb_put_dev - release a use of the usb device structure
@@ -380,6 +387,7 @@ void usb_put_dev(struct usb_device *dev)
        if (dev)
                put_device(&dev->dev);
 }
+EXPORT_SYMBOL_GPL(usb_put_dev);
 
 /**
  * usb_get_intf - increments the reference count of the usb interface structure
@@ -400,6 +408,7 @@ struct usb_interface *usb_get_intf(struct usb_interface *intf)
                get_device(&intf->dev);
        return intf;
 }
+EXPORT_SYMBOL_GPL(usb_get_intf);
 
 /**
  * usb_put_intf - release a use of the usb interface structure
@@ -414,7 +423,7 @@ void usb_put_intf(struct usb_interface *intf)
        if (intf)
                put_device(&intf->dev);
 }
-
+EXPORT_SYMBOL_GPL(usb_put_intf);
 
 /*                     USB device locking
  *
@@ -461,11 +470,11 @@ int usb_lock_device_for_reset(struct usb_device *udev,
                return -EHOSTUNREACH;
        if (iface) {
                switch (iface->condition) {
-                 case USB_INTERFACE_BINDING:
+               case USB_INTERFACE_BINDING:
                        return 0;
-                 case USB_INTERFACE_BOUND:
+               case USB_INTERFACE_BOUND:
                        break;
-                 default:
+               default:
                        return -EINTR;
                }
        }
@@ -487,7 +496,7 @@ int usb_lock_device_for_reset(struct usb_device *udev,
        }
        return 1;
 }
-
+EXPORT_SYMBOL_GPL(usb_lock_device_for_reset);
 
 static struct usb_device *match_device(struct usb_device *dev,
                                       u16 vendor_id, u16 product_id)
@@ -540,10 +549,10 @@ struct usb_device *usb_find_device(u16 vendor_id, u16 product_id)
        struct list_head *buslist;
        struct usb_bus *bus;
        struct usb_device *dev = NULL;
-       
+
        mutex_lock(&usb_bus_list_lock);
        for (buslist = usb_bus_list.next;
-            buslist != &usb_bus_list; 
+            buslist != &usb_bus_list;
             buslist = buslist->next) {
                bus = container_of(buslist, struct usb_bus, bus_list);
                if (!bus->root_hub)
@@ -576,6 +585,7 @@ int usb_get_current_frame_number(struct usb_device *dev)
 {
        return usb_hcd_get_frame_number(dev);
 }
+EXPORT_SYMBOL_GPL(usb_get_current_frame_number);
 
 /*-------------------------------------------------------------------*/
 /*
@@ -584,7 +594,7 @@ int usb_get_current_frame_number(struct usb_device *dev)
  */
 
 int __usb_get_extra_descriptor(char *buffer, unsigned size,
-       unsigned char type, void **ptr)
+                              unsigned char type, void **ptr)
 {
        struct usb_descriptor_header *header;
 
@@ -595,7 +605,7 @@ int __usb_get_extra_descriptor(char *buffer, unsigned size,
                        printk(KERN_ERR
                                "%s: bogus descriptor, type %d length %d\n",
                                usbcore_name,
-                               header->bDescriptorType, 
+                               header->bDescriptorType,
                                header->bLength);
                        return -1;
                }
@@ -610,6 +620,7 @@ int __usb_get_extra_descriptor(char *buffer, unsigned size,
        }
        return -1;
 }
+EXPORT_SYMBOL_GPL(__usb_get_extra_descriptor);
 
 /**
  * usb_buffer_alloc - allocate dma-consistent buffer for URB_NO_xxx_DMA_MAP
@@ -633,17 +644,14 @@ int __usb_get_extra_descriptor(char *buffer, unsigned size,
  *
  * When the buffer is no longer used, free it with usb_buffer_free().
  */
-void *usb_buffer_alloc(
-       struct usb_device *dev,
-       size_t size,
-       gfp_t mem_flags,
-       dma_addr_t *dma
-)
+void *usb_buffer_alloc(struct usb_device *dev, size_t size, gfp_t mem_flags,
+                      dma_addr_t *dma)
 {
        if (!dev || !dev->bus)
                return NULL;
        return hcd_buffer_alloc(dev->bus, size, mem_flags, dma);
 }
+EXPORT_SYMBOL_GPL(usb_buffer_alloc);
 
 /**
  * usb_buffer_free - free memory allocated with usb_buffer_alloc()
@@ -656,12 +664,8 @@ void *usb_buffer_alloc(
  * been allocated using usb_buffer_alloc(), and the parameters must match
  * those provided in that allocation request.
  */
-void usb_buffer_free(
-       struct usb_device *dev,
-       size_t size,
-       void *addr,
-       dma_addr_t dma
-)
+void usb_buffer_free(struct usb_device *dev, size_t size, void *addr,
+                    dma_addr_t dma)
 {
        if (!dev || !dev->bus)
                return;
@@ -669,6 +673,7 @@ void usb_buffer_free(
                return;
        hcd_buffer_free(dev->bus, size, addr, dma);
 }
+EXPORT_SYMBOL_GPL(usb_buffer_free);
 
 /**
  * usb_buffer_map - create DMA mapping(s) for an urb
@@ -708,14 +713,15 @@ struct urb *usb_buffer_map(struct urb *urb)
                                        urb->setup_packet,
                                        sizeof(struct usb_ctrlrequest),
                                        DMA_TO_DEVICE);
-       // FIXME generic api broken like pci, can't report errors
-       // if (urb->transfer_dma == DMA_ADDR_INVALID) return 0;
+       /* FIXME generic api broken like pci, can't report errors */
+       /* if (urb->transfer_dma == DMA_ADDR_INVALID) return 0; */
        } else
                urb->transfer_dma = ~0;
        urb->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP
                                | URB_NO_SETUP_DMA_MAP);
        return urb;
 }
+EXPORT_SYMBOL_GPL(usb_buffer_map);
 #endif  /*  0  */
 
 /* XXX DISABLED, no users currently.  If you wish to re-enable this
@@ -753,6 +759,7 @@ void usb_buffer_dmasync(struct urb *urb)
                                        DMA_TO_DEVICE);
        }
 }
+EXPORT_SYMBOL_GPL(usb_buffer_dmasync);
 #endif
 
 /**
@@ -788,6 +795,7 @@ void usb_buffer_unmap(struct urb *urb)
        urb->transfer_flags &= ~(URB_NO_TRANSFER_DMA_MAP
                                | URB_NO_SETUP_DMA_MAP);
 }
+EXPORT_SYMBOL_GPL(usb_buffer_unmap);
 #endif  /*  0  */
 
 /**
@@ -828,10 +836,11 @@ int usb_buffer_map_sg(const struct usb_device *dev, int is_in,
                        || !controller->dma_mask)
                return -1;
 
-       // FIXME generic api broken like pci, can't report errors
+       /* FIXME generic api broken like pci, can't report errors */
        return dma_map_sg(controller, sg, nents,
                        is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
 }
+EXPORT_SYMBOL_GPL(usb_buffer_map_sg);
 
 /* XXX DISABLED, no users currently.  If you wish to re-enable this
  * XXX please determine whether the sync is to transfer ownership of
@@ -865,6 +874,7 @@ void usb_buffer_dmasync_sg(const struct usb_device *dev, int is_in,
        dma_sync_sg(controller, sg, n_hw_ents,
                        is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
 }
+EXPORT_SYMBOL_GPL(usb_buffer_dmasync_sg);
 #endif
 
 /**
@@ -891,6 +901,7 @@ void usb_buffer_unmap_sg(const struct usb_device *dev, int is_in,
        dma_unmap_sg(controller, sg, n_hw_ents,
                        is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
 }
+EXPORT_SYMBOL_GPL(usb_buffer_unmap_sg);
 
 /* format to disable USB on kernel command line is: nousb */
 __module_param_call("", nousb, param_set_bool, param_get_bool, &nousb, 0444);
@@ -902,6 +913,7 @@ int usb_disabled(void)
 {
        return nousb;
 }
+EXPORT_SYMBOL_GPL(usb_disabled);
 
 /*
  * Init
@@ -918,7 +930,7 @@ static int __init usb_init(void)
        if (retval)
                goto out;
        retval = bus_register(&usb_bus_type);
-       if (retval) 
+       if (retval)
                goto bus_register_failed;
        retval = usb_host_init();
        if (retval)
@@ -983,45 +995,4 @@ static void __exit usb_exit(void)
 
 subsys_initcall(usb_init);
 module_exit(usb_exit);
-
-/*
- * USB may be built into the kernel or be built as modules.
- * These symbols are exported for device (or host controller)
- * driver modules to use.
- */
-
-EXPORT_SYMBOL(usb_disabled);
-
-EXPORT_SYMBOL_GPL(usb_get_intf);
-EXPORT_SYMBOL_GPL(usb_put_intf);
-
-EXPORT_SYMBOL(usb_put_dev);
-EXPORT_SYMBOL(usb_get_dev);
-EXPORT_SYMBOL(usb_hub_tt_clear_buffer);
-
-EXPORT_SYMBOL(usb_lock_device_for_reset);
-
-EXPORT_SYMBOL(usb_find_interface);
-EXPORT_SYMBOL(usb_ifnum_to_if);
-EXPORT_SYMBOL(usb_altnum_to_altsetting);
-
-EXPORT_SYMBOL(__usb_get_extra_descriptor);
-
-EXPORT_SYMBOL(usb_get_current_frame_number);
-
-EXPORT_SYMBOL(usb_buffer_alloc);
-EXPORT_SYMBOL(usb_buffer_free);
-
-#if 0
-EXPORT_SYMBOL(usb_buffer_map);
-EXPORT_SYMBOL(usb_buffer_dmasync);
-EXPORT_SYMBOL(usb_buffer_unmap);
-#endif
-
-EXPORT_SYMBOL(usb_buffer_map_sg);
-#if 0
-EXPORT_SYMBOL(usb_buffer_dmasync_sg);
-#endif
-EXPORT_SYMBOL(usb_buffer_unmap_sg);
-
 MODULE_LICENSE("GPL");
index c52626c51f70bd99859c170739eb20b7695937bb..2375194a9d43a7d9a6440f097e951d2f8b27f56d 100644 (file)
@@ -1,22 +1,23 @@
 /* Functions local to drivers/usb/core/ */
 
-extern int usb_create_sysfs_dev_files (struct usb_device *dev);
-extern void usb_remove_sysfs_dev_files (struct usb_device *dev);
-extern int usb_create_sysfs_intf_files (struct usb_interface *intf);
-extern void usb_remove_sysfs_intf_files (struct usb_interface *intf);
-extern int usb_create_ep_files(struct device *parent, struct usb_host_endpoint *endpoint,
+extern int usb_create_sysfs_dev_files(struct usb_device *dev);
+extern void usb_remove_sysfs_dev_files(struct usb_device *dev);
+extern int usb_create_sysfs_intf_files(struct usb_interface *intf);
+extern void usb_remove_sysfs_intf_files(struct usb_interface *intf);
+extern int usb_create_ep_files(struct device *parent,
+                               struct usb_host_endpoint *endpoint,
                                struct usb_device *udev);
 extern void usb_remove_ep_files(struct usb_host_endpoint *endpoint);
 
 extern void usb_enable_endpoint(struct usb_device *dev,
                struct usb_host_endpoint *ep);
-extern void usb_disable_endpoint (struct usb_device *dev, unsigned int epaddr);
-extern void usb_disable_interface (struct usb_device *dev,
+extern void usb_disable_endpoint(struct usb_device *dev, unsigned int epaddr);
+extern void usb_disable_interface(struct usb_device *dev,
                struct usb_interface *intf);
 extern void usb_release_interface_cache(struct kref *ref);
-extern void usb_disable_device (struct usb_device *dev, int skip_ep0);
-extern int usb_deauthorize_device (struct usb_device *);
-extern int usb_authorize_device (struct usb_device *);
+extern void usb_disable_device(struct usb_device *dev, int skip_ep0);
+extern int usb_deauthorize_device(struct usb_device *);
+extern int usb_authorize_device(struct usb_device *);
 extern void usb_detect_quirks(struct usb_device *udev);
 
 extern int usb_get_device_descriptor(struct usb_device *dev,
index 77a3759d6fc7552c83f01139cff84d46f6f85b2c..c1395516468618c3683fccac3d27bc22bc5a0759 100644 (file)
 # With help from a special transceiver and a "Mini-AB" jack, systems with
 # both kinds of controller can also support "USB On-the-Go" (CONFIG_USB_OTG).
 #
-menu "USB Gadget Support"
 
-config USB_GADGET
-       tristate "Support for USB Gadgets"
+menuconfig USB_GADGET
+       tristate "USB Gadget Support"
        help
           USB is a master/slave protocol, organized with one master
           host (such as a PC) controlling up to 127 peripheral devices.
@@ -42,6 +41,8 @@ config USB_GADGET
           For more information, see <http://www.linux-usb.org/gadget> and
           the kernel DocBook documentation for this API.
 
+if USB_GADGET
+
 config USB_GADGET_DEBUG
        boolean "Debugging messages"
        depends on USB_GADGET && DEBUG_KERNEL && EXPERIMENTAL
@@ -220,6 +221,16 @@ config USB_M66592
        default USB_GADGET
        select USB_GADGET_SELECTED
 
+config SUPERH_BUILT_IN_M66592
+       boolean "Enable SuperH built-in USB like the M66592"
+       depends on USB_GADGET_M66592 && CPU_SUBTYPE_SH7722
+       help
+          SH7722 has USB like the M66592.
+
+          The transfer rate is very slow when use "Ethernet Gadget".
+          However, this problem is improved if change a value of
+          NET_IP_ALIGN to 4.
+
 config USB_GADGET_GOKU
        boolean "Toshiba TC86C001 'Goku-S'"
        depends on PCI
@@ -538,6 +549,20 @@ config USB_MIDI_GADGET
          Say "y" to link the driver statically, or "m" to build a
          dynamically linked module called "g_midi".
 
+config USB_G_PRINTER
+       tristate "Printer Gadget"
+       help
+         The Printer Gadget channels data between the USB host and a
+         userspace program driving the print engine. The user space
+         program reads and writes the device file /dev/g_printer to
+         receive or send printer data. It can use ioctl calls to
+         the device file to get or set printer status.
+
+         Say "y" to link the driver statically, or "m" to build a
+         dynamically linked module called "g_printer".
+
+         For more information, see Documentation/usb/gadget_printer.txt
+         which includes sample code for accessing the device file.
 
 # put drivers that need isochronous transfer support (for audio
 # or video class gadget drivers), or specific hardware, here.
@@ -546,4 +571,4 @@ config USB_MIDI_GADGET
 
 endchoice
 
-endmenu
+endif # USB_GADGET
index 904e57bf61124e8bb2e996df679a35a3d628c743..c3aab80b6c76e33095556539f15f2377a14d8adf 100644 (file)
@@ -28,6 +28,8 @@ g_midi-objs                   := gmidi.o usbstring.o config.o epautoconf.o
 gadgetfs-objs                  := inode.o
 g_file_storage-objs            := file_storage.o usbstring.o config.o \
                                        epautoconf.o
+g_printer-objs                 := printer.o usbstring.o config.o \
+                                       epautoconf.o
 
 ifeq ($(CONFIG_USB_ETH_RNDIS),y)
        g_ether-objs            += rndis.o
@@ -38,5 +40,6 @@ obj-$(CONFIG_USB_ETH)         += g_ether.o
 obj-$(CONFIG_USB_GADGETFS)     += gadgetfs.o
 obj-$(CONFIG_USB_FILE_STORAGE) += g_file_storage.o
 obj-$(CONFIG_USB_G_SERIAL)     += g_serial.o
+obj-$(CONFIG_USB_G_PRINTER)    += g_printer.o
 obj-$(CONFIG_USB_MIDI_GADGET)  += g_midi.o
 
index c72e9620bf8dc67164dfc64eaa9da2488e834282..b663f23f2642ab5a157039e98c1f92b678927ee1 100644 (file)
@@ -1244,7 +1244,7 @@ udc_queue(struct usb_ep *usbep, struct usb_request *usbreq, gfp_t gfp)
                /* stop OUT naking */
                if (!ep->in) {
                        if (!use_dma && udc_rxfifo_pending) {
-                               DBG(dev, "udc_queue(): pending bytes in"
+                               DBG(dev, "udc_queue(): pending bytes in "
                                        "rxfifo after nyet\n");
                                /*
                                 * read pending bytes afer nyet:
@@ -2038,6 +2038,7 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
        spin_unlock_irqrestore(&dev->lock, flags);
 
        driver->unbind(&dev->gadget);
+       dev->gadget.dev.driver = NULL;
        dev->driver = NULL;
 
        /* set SD */
index cd62b029d1766e606945e2c8a12e1ecc08fd119f..a83e8b798ec9d30d70ca38bd7cebc37576c217ba 100644 (file)
@@ -21,8 +21,7 @@
  * Boston, MA  02111-1307, USA.
  */
 
-#undef DEBUG
-#undef VERBOSE
+#undef VERBOSE_DEBUG
 #undef PACKET_TRACE
 
 #include <linux/kernel.h>
@@ -46,8 +45,8 @@
 #include <asm/irq.h>
 #include <asm/system.h>
 #include <asm/mach-types.h>
+#include <asm/gpio.h>
 
-#include <asm/arch/gpio.h>
 #include <asm/arch/board.h>
 #include <asm/arch/cpu.h>
 #include <asm/arch/at91sam9261_matrix.h>
@@ -580,7 +579,7 @@ static int at91_ep_disable (struct usb_ep * _ep)
  */
 
 static struct usb_request *
-at91_ep_alloc_request(struct usb_ep *_ep, unsigned int gfp_flags)
+at91_ep_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags)
 {
        struct at91_request *req;
 
@@ -881,6 +880,8 @@ static void clk_off(struct at91_udc *udc)
  */
 static void pullup(struct at91_udc *udc, int is_on)
 {
+       int     active = !udc->board.pullup_active_low;
+
        if (!udc->enabled || !udc->vbus)
                is_on = 0;
        DBG("%sactive\n", is_on ? "" : "in");
@@ -890,7 +891,7 @@ static void pullup(struct at91_udc *udc, int is_on)
                at91_udp_write(udc, AT91_UDP_ICR, AT91_UDP_RXRSM);
                at91_udp_write(udc, AT91_UDP_TXVC, 0);
                if (cpu_is_at91rm9200())
-                       at91_set_gpio_value(udc->board.pullup_pin, 1);
+                       gpio_set_value(udc->board.pullup_pin, active);
                else if (cpu_is_at91sam9260() || cpu_is_at91sam9263()) {
                        u32     txvc = at91_udp_read(udc, AT91_UDP_TXVC);
 
@@ -908,7 +909,7 @@ static void pullup(struct at91_udc *udc, int is_on)
                at91_udp_write(udc, AT91_UDP_IDR, AT91_UDP_RXRSM);
                at91_udp_write(udc, AT91_UDP_TXVC, AT91_UDP_TXVC_TXVDIS);
                if (cpu_is_at91rm9200())
-                       at91_set_gpio_value(udc->board.pullup_pin, 0);
+                       gpio_set_value(udc->board.pullup_pin, !active);
                else if (cpu_is_at91sam9260() || cpu_is_at91sam9263()) {
                        u32     txvc = at91_udp_read(udc, AT91_UDP_TXVC);
 
@@ -1153,7 +1154,7 @@ static void handle_setup(struct at91_udc *udc, struct at91_ep *ep, u32 csr)
                        | USB_REQ_GET_STATUS:
                tmp = w_index & USB_ENDPOINT_NUMBER_MASK;
                ep = &udc->ep[tmp];
-               if (tmp > NUM_ENDPOINTS || (tmp && !ep->desc))
+               if (tmp >= NUM_ENDPOINTS || (tmp && !ep->desc))
                        goto stall;
 
                if (tmp) {
@@ -1176,7 +1177,7 @@ static void handle_setup(struct at91_udc *udc, struct at91_ep *ep, u32 csr)
                        | USB_REQ_SET_FEATURE:
                tmp = w_index & USB_ENDPOINT_NUMBER_MASK;
                ep = &udc->ep[tmp];
-               if (w_value != USB_ENDPOINT_HALT || tmp > NUM_ENDPOINTS)
+               if (w_value != USB_ENDPOINT_HALT || tmp >= NUM_ENDPOINTS)
                        goto stall;
                if (!ep->desc || ep->is_iso)
                        goto stall;
@@ -1195,7 +1196,7 @@ static void handle_setup(struct at91_udc *udc, struct at91_ep *ep, u32 csr)
                        | USB_REQ_CLEAR_FEATURE:
                tmp = w_index & USB_ENDPOINT_NUMBER_MASK;
                ep = &udc->ep[tmp];
-               if (w_value != USB_ENDPOINT_HALT || tmp > NUM_ENDPOINTS)
+               if (w_value != USB_ENDPOINT_HALT || tmp >= NUM_ENDPOINTS)
                        goto stall;
                if (tmp == 0)
                        goto succeed;
@@ -1551,7 +1552,7 @@ static irqreturn_t at91_vbus_irq(int irq, void *_udc)
 
        /* vbus needs at least brief debouncing */
        udelay(10);
-       value = at91_get_gpio_value(udc->board.vbus_pin);
+       value = gpio_get_value(udc->board.vbus_pin);
        if (value != udc->vbus)
                at91_vbus_session(&udc->gadget, value);
 
@@ -1616,6 +1617,8 @@ int usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
        local_irq_enable();
 
        driver->unbind(&udc->gadget);
+       udc->gadget.dev.driver = NULL;
+       udc->gadget.dev.driver_data = NULL;
        udc->driver = NULL;
 
        DBG("unbound from %s\n", driver->driver.name);
@@ -1645,12 +1648,12 @@ static int __init at91udc_probe(struct platform_device *pdev)
        }
 
        if (pdev->num_resources != 2) {
-               DBG("invalid num_resources");
+               DBG("invalid num_resources\n");
                return -ENODEV;
        }
        if ((pdev->resource[0].flags != IORESOURCE_MEM)
                        || (pdev->resource[1].flags != IORESOURCE_IRQ)) {
-               DBG("invalid resource type");
+               DBG("invalid resource type\n");
                return -ENODEV;
        }
 
@@ -1672,10 +1675,26 @@ static int __init at91udc_probe(struct platform_device *pdev)
        udc->pdev = pdev;
        udc->enabled = 0;
 
+       /* rm9200 needs manual D+ pullup; off by default */
+       if (cpu_is_at91rm9200()) {
+               if (udc->board.pullup_pin <= 0) {
+                       DBG("no D+ pullup?\n");
+                       retval = -ENODEV;
+                       goto fail0;
+               }
+               retval = gpio_request(udc->board.pullup_pin, "udc_pullup");
+               if (retval) {
+                       DBG("D+ pullup is busy\n");
+                       goto fail0;
+               }
+               gpio_direction_output(udc->board.pullup_pin,
+                               udc->board.pullup_active_low);
+       }
+
        udc->udp_baseaddr = ioremap(res->start, res->end - res->start + 1);
        if (!udc->udp_baseaddr) {
-               release_mem_region(res->start, res->end - res->start + 1);
-               return -ENOMEM;
+               retval = -ENOMEM;
+               goto fail0a;
        }
 
        udc_reinit(udc);
@@ -1686,12 +1705,13 @@ static int __init at91udc_probe(struct platform_device *pdev)
        if (IS_ERR(udc->iclk) || IS_ERR(udc->fclk)) {
                DBG("clocks missing\n");
                retval = -ENODEV;
-               goto fail0;
+               /* NOTE: we "know" here that refcounts on these are NOPs */
+               goto fail0b;
        }
 
        retval = device_register(&udc->gadget.dev);
        if (retval < 0)
-               goto fail0;
+               goto fail0b;
 
        /* don't do anything until we have both gadget driver and VBUS */
        clk_enable(udc->iclk);
@@ -1703,25 +1723,32 @@ static int __init at91udc_probe(struct platform_device *pdev)
 
        /* request UDC and maybe VBUS irqs */
        udc->udp_irq = platform_get_irq(pdev, 0);
-       if (request_irq(udc->udp_irq, at91_udc_irq,
-                       IRQF_DISABLED, driver_name, udc)) {
+       retval = request_irq(udc->udp_irq, at91_udc_irq,
+                       IRQF_DISABLED, driver_name, udc);
+       if (retval < 0) {
                DBG("request irq %d failed\n", udc->udp_irq);
-               retval = -EBUSY;
                goto fail1;
        }
        if (udc->board.vbus_pin > 0) {
+               retval = gpio_request(udc->board.vbus_pin, "udc_vbus");
+               if (retval < 0) {
+                       DBG("request vbus pin failed\n");
+                       goto fail2;
+               }
+               gpio_direction_input(udc->board.vbus_pin);
+
                /*
                 * Get the initial state of VBUS - we cannot expect
                 * a pending interrupt.
                 */
-               udc->vbus = at91_get_gpio_value(udc->board.vbus_pin);
+               udc->vbus = gpio_get_value(udc->board.vbus_pin);
                if (request_irq(udc->board.vbus_pin, at91_vbus_irq,
                                IRQF_DISABLED, driver_name, udc)) {
                        DBG("request vbus irq %d failed\n",
                                        udc->board.vbus_pin);
                        free_irq(udc->udp_irq, udc);
                        retval = -EBUSY;
-                       goto fail1;
+                       goto fail3;
                }
        } else {
                DBG("no VBUS detection, assuming always-on\n");
@@ -1734,8 +1761,18 @@ static int __init at91udc_probe(struct platform_device *pdev)
        INFO("%s version %s\n", driver_name, DRIVER_VERSION);
        return 0;
 
+fail3:
+       if (udc->board.vbus_pin > 0)
+               gpio_free(udc->board.vbus_pin);
+fail2:
+       free_irq(udc->udp_irq, udc);
 fail1:
        device_unregister(&udc->gadget.dev);
+fail0b:
+       iounmap(udc->udp_baseaddr);
+fail0a:
+       if (cpu_is_at91rm9200())
+               gpio_free(udc->board.pullup_pin);
 fail0:
        release_mem_region(res->start, res->end - res->start + 1);
        DBG("%s probe failed, %d\n", driver_name, retval);
@@ -1756,12 +1793,18 @@ static int __exit at91udc_remove(struct platform_device *pdev)
 
        device_init_wakeup(&pdev->dev, 0);
        remove_debug_file(udc);
-       if (udc->board.vbus_pin > 0)
+       if (udc->board.vbus_pin > 0) {
                free_irq(udc->board.vbus_pin, udc);
+               gpio_free(udc->board.vbus_pin);
+       }
        free_irq(udc->udp_irq, udc);
        device_unregister(&udc->gadget.dev);
 
        iounmap(udc->udp_baseaddr);
+
+       if (cpu_is_at91rm9200())
+               gpio_free(udc->board.pullup_pin);
+
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        release_mem_region(res->start, res->end - res->start + 1);
 
index 7e34e2f864f9d70efcfd41ed1c2e6719e91dcb30..a973f2a50fb959509472aa66db390817c78f1a7d 100644 (file)
@@ -53,7 +53,7 @@
 #define     AT91_UDP_RXRSM     (1 <<  9)       /* USB Resume Interrupt Status */
 #define     AT91_UDP_EXTRSM    (1 << 10)       /* External Resume Interrupt Status [AT91RM9200 only] */
 #define     AT91_UDP_SOFINT    (1 << 11)       /* Start of Frame Interrupt Status */
-#define     AT91_UDP_ENDBUSRES (1 << 12)       /* End of Bus Reset Interrpt Status */
+#define     AT91_UDP_ENDBUSRES (1 << 12)       /* End of Bus Reset Interrupt Status */
 #define     AT91_UDP_WAKEUP    (1 << 13)       /* USB Wakeup Interrupt Status [AT91RM9200 only] */
 
 #define AT91_UDP_ICR           0x20            /* Interrupt Clear Register */
@@ -158,13 +158,7 @@ struct at91_request {
 
 /*-------------------------------------------------------------------------*/
 
-#ifdef DEBUG
-#define DBG(stuff...)          printk(KERN_DEBUG "udc: " stuff)
-#else
-#define DBG(stuff...)          do{}while(0)
-#endif
-
-#ifdef VERBOSE
+#ifdef VERBOSE_DEBUG
 #    define VDBG               DBG
 #else
 #    define VDBG(stuff...)     do{}while(0)
@@ -176,9 +170,10 @@ struct at91_request {
 #    define PACKET(stuff...)   do{}while(0)
 #endif
 
-#define ERR(stuff...)          printk(KERN_ERR "udc: " stuff)
-#define WARN(stuff...)         printk(KERN_WARNING "udc: " stuff)
-#define INFO(stuff...)         printk(KERN_INFO "udc: " stuff)
+#define ERR(stuff...)          pr_err("udc: " stuff)
+#define WARN(stuff...)         pr_warning("udc: " stuff)
+#define INFO(stuff...)         pr_info("udc: " stuff)
+#define DBG(stuff...)          pr_debug("udc: " stuff)
 
 #endif
 
index 4fb5ff469574dd4c944f7a3a1d18713d955a100a..af8b2a3a2d4a3042c1b28783c2254114646a1533 100644 (file)
@@ -1384,8 +1384,7 @@ delegate:
        return retval;
 
 stall:
-       printk(KERN_ERR
-               "udc: %s: Invalid setup request: %02x.%02x v%04x i%04x l%d, "
+       pr_err("udc: %s: Invalid setup request: %02x.%02x v%04x i%04x l%d, "
                "halting endpoint...\n",
                ep->ep.name, crq->bRequestType, crq->bRequest,
                le16_to_cpu(crq->wValue), le16_to_cpu(crq->wIndex),
@@ -1456,8 +1455,7 @@ restart:
                                set_protocol_stall(udc, ep);
                        break;
                default:
-                       printk(KERN_ERR
-                               "udc: %s: TXCOMP: Invalid endpoint state %d, "
+                       pr_err("udc: %s: TXCOMP: Invalid endpoint state %d, "
                                "halting endpoint...\n",
                                ep->ep.name, ep->state);
                        set_protocol_stall(udc, ep);
@@ -1486,8 +1484,7 @@ restart:
                default:
                        usba_ep_writel(ep, CLR_STA, USBA_RX_BK_RDY);
                        usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY);
-                       printk(KERN_ERR
-                               "udc: %s: RXRDY: Invalid endpoint state %d, "
+                       pr_err("udc: %s: RXRDY: Invalid endpoint state %d, "
                                "halting endpoint...\n",
                                ep->ep.name, ep->state);
                        set_protocol_stall(udc, ep);
@@ -1532,7 +1529,7 @@ restart:
                pkt_len = USBA_BFEXT(BYTE_COUNT, usba_ep_readl(ep, STA));
                DBG(DBG_HW, "Packet length: %u\n", pkt_len);
                if (pkt_len != sizeof(crq)) {
-                       printk(KERN_WARNING "udc: Invalid packet length %u "
+                       pr_warning("udc: Invalid packet length %u "
                                "(expected %lu)\n", pkt_len, sizeof(crq));
                        set_protocol_stall(udc, ep);
                        return;
index a68304e31a684791d606e1590998b68142f5e948..08bf6f9aaf7ee32ed1cb167da98f42e13fa17c40 100644 (file)
 #define FIFO_IOMEM_ID  0
 #define CTRL_IOMEM_ID  1
 
-#ifdef DEBUG
 #define DBG_ERR                0x0001  /* report all error returns */
 #define DBG_HW         0x0002  /* debug hardware initialization */
 #define DBG_GADGET     0x0004  /* calls to/from gadget driver */
 #define DBG_NONE       0x0000
 
 #define DEBUG_LEVEL    (DBG_ERR)
+
 #define DBG(level, fmt, ...)                                   \
        do {                                                    \
                if ((level) & DEBUG_LEVEL)                      \
-                       printk(KERN_DEBUG "udc: " fmt, ## __VA_ARGS__); \
+                       pr_debug("udc: " fmt, ## __VA_ARGS__);  \
        } while (0)
-#else
-#define DBG(level, fmt...)
-#endif
 
 enum usba_ctrl_state {
        WAIT_FOR_SETUP,
index 9db2482bdfa2c5c46618697ba09d8ecc901d1f45..cbe44535c0f0a4520af8b004ff84bad0264e1008 100644 (file)
@@ -61,6 +61,8 @@
 #define DRIVER_DESC    "USB Host+Gadget Emulator"
 #define DRIVER_VERSION "02 May 2005"
 
+#define POWER_BUDGET   500     /* in mA; use 8 for low-power port testing */
+
 static const char      driver_name [] = "dummy_hcd";
 static const char      driver_desc [] = "USB Host+Gadget Emulator";
 
@@ -772,18 +774,17 @@ usb_gadget_register_driver (struct usb_gadget_driver *driver)
        list_del_init (&dum->ep [0].ep.ep_list);
        INIT_LIST_HEAD(&dum->fifo_req.queue);
 
+       driver->driver.bus = NULL;
        dum->driver = driver;
        dum->gadget.dev.driver = &driver->driver;
        dev_dbg (udc_dev(dum), "binding gadget driver '%s'\n",
                        driver->driver.name);
-       if ((retval = driver->bind (&dum->gadget)) != 0)
-               goto err_bind_gadget;
-
-       driver->driver.bus = dum->gadget.dev.parent->bus;
-       if ((retval = driver_register (&driver->driver)) != 0)
-               goto err_register;
-       if ((retval = device_bind_driver (&dum->gadget.dev)) != 0)
-               goto err_bind_driver;
+       retval = driver->bind(&dum->gadget);
+       if (retval) {
+               dum->driver = NULL;
+               dum->gadget.dev.driver = NULL;
+               return retval;
+       }
 
        /* khubd will enumerate this in a while */
        spin_lock_irq (&dum->lock);
@@ -793,20 +794,6 @@ usb_gadget_register_driver (struct usb_gadget_driver *driver)
 
        usb_hcd_poll_rh_status (dummy_to_hcd (dum));
        return 0;
-
-err_bind_driver:
-       driver_unregister (&driver->driver);
-err_register:
-       if (driver->unbind)
-               driver->unbind (&dum->gadget);
-       spin_lock_irq (&dum->lock);
-       dum->pullup = 0;
-       set_link_state (dum);
-       spin_unlock_irq (&dum->lock);
-err_bind_gadget:
-       dum->driver = NULL;
-       dum->gadget.dev.driver = NULL;
-       return retval;
 }
 EXPORT_SYMBOL (usb_gadget_register_driver);
 
@@ -830,11 +817,9 @@ usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
        spin_unlock_irqrestore (&dum->lock, flags);
 
        driver->unbind (&dum->gadget);
+       dum->gadget.dev.driver = NULL;
        dum->driver = NULL;
 
-       device_release_driver (&dum->gadget.dev);
-       driver_unregister (&driver->driver);
-
        spin_lock_irqsave (&dum->lock, flags);
        dum->pullup = 0;
        set_link_state (dum);
@@ -1827,8 +1812,7 @@ static int dummy_start (struct usb_hcd *hcd)
 
        INIT_LIST_HEAD (&dum->urbp_list);
 
-       /* only show a low-power port: just 8mA */
-       hcd->power_budget = 8;
+       hcd->power_budget = POWER_BUDGET;
        hcd->state = HC_STATE_RUNNING;
        hcd->uses_new_polling = 1;
 
index 9e732bff9df0608670dcf88b5db1f6d2f5b95ce2..a70e255402b86e60aed06c1e54194909d25b916a 100644 (file)
@@ -1067,19 +1067,19 @@ done:
 
        /* on error, disable any endpoints  */
        if (result < 0) {
-               if (!subset_active(dev))
+               if (!subset_active(dev) && dev->status_ep)
                        (void) usb_ep_disable (dev->status_ep);
                dev->status = NULL;
                (void) usb_ep_disable (dev->in_ep);
                (void) usb_ep_disable (dev->out_ep);
                dev->in = NULL;
                dev->out = NULL;
-       } else
+       }
 
        /* activate non-CDC configs right away
         * this isn't strictly according to the RNDIS spec
         */
-       if (!cdc_active (dev)) {
+       else if (!cdc_active (dev)) {
                netif_carrier_on (dev->net);
                if (netif_running (dev->net)) {
                        spin_unlock (&dev->lock);
index 1d174dcb3ac9e6a4ea5ce8133d6e4519d32d9783..3301167d4f2a9eba4827b818dbaaf67fbf1ddc90 100644 (file)
@@ -275,19 +275,15 @@ MODULE_LICENSE("Dual BSD/GPL");
 
 /*-------------------------------------------------------------------------*/
 
-#ifdef DEBUG
 #define LDBG(lun,fmt,args...) \
        dev_dbg(&(lun)->dev , fmt , ## args)
 #define MDBG(fmt,args...) \
-       printk(KERN_DEBUG DRIVER_NAME ": " fmt , ## args)
-#else
-#define LDBG(lun,fmt,args...) \
-       do { } while (0)
-#define MDBG(fmt,args...) \
-       do { } while (0)
+       pr_debug(DRIVER_NAME ": " fmt , ## args)
+
+#ifndef DEBUG
 #undef VERBOSE_DEBUG
 #undef DUMP_MSGS
-#endif /* DEBUG */
+#endif /* !DEBUG */
 
 #ifdef VERBOSE_DEBUG
 #define VLDBG  LDBG
@@ -304,7 +300,7 @@ MODULE_LICENSE("Dual BSD/GPL");
        dev_info(&(lun)->dev , fmt , ## args)
 
 #define MINFO(fmt,args...) \
-       printk(KERN_INFO DRIVER_NAME ": " fmt , ## args)
+       pr_info(DRIVER_NAME ": " fmt , ## args)
 
 #define DBG(d, fmt, args...) \
        dev_dbg(&(d)->gadget->dev , fmt , ## args)
index 038e7d7b4da1c13845ae944f07b5aaeabf27b0ec..63e8fa3a69e19bc55dbb5bc78d53ccc91871016f 100644 (file)
@@ -776,7 +776,7 @@ fsl_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
                VDBG("%s, bad params\n", __FUNCTION__);
                return -EINVAL;
        }
-       if (!_ep || (!ep->desc && ep_index(ep))) {
+       if (unlikely(!_ep || !ep->desc)) {
                VDBG("%s, bad ep\n", __FUNCTION__);
                return -EINVAL;
        }
@@ -1896,7 +1896,7 @@ static int fsl_proc_read(char *page, char **start, off_t off, int count,
 
        spin_lock_irqsave(&udc->lock, flags);
 
-       /* ------basic driver infomation ---- */
+       /* ------basic driver information ---- */
        t = scnprintf(next, size,
                        DRIVER_DESC "\n"
                        "%s version: %s\n"
index 832ab82b4882c9ad1d4ae7b5eb0e2aaff921c233..9fb0b1ec85266322054422db511f337e53459efd 100644 (file)
@@ -551,9 +551,9 @@ static void dump_msg(const char *label, const u8 * buf, unsigned int length)
 #define VDBG(stuff...) do{}while(0)
 #endif
 
-#define ERR(stuff...)          printk(KERN_ERR "udc: " stuff)
-#define WARN(stuff...)         printk(KERN_WARNING "udc: " stuff)
-#define INFO(stuff...)         printk(KERN_INFO "udc: " stuff)
+#define ERR(stuff...)          pr_err("udc: " stuff)
+#define WARN(stuff...)         pr_warning("udc: " stuff)
+#define INFO(stuff...)         pr_info("udc: " stuff)
 
 /*-------------------------------------------------------------------------*/
 
index 0689189550bce6cab8b1800c4c161fdc14416e77..5b42ccd0035fee4364d4d8021c0e72814015775a 100644 (file)
@@ -24,7 +24,6 @@
 #include <linux/utsname.h>
 #include <linux/device.h>
 
-#include <sound/driver.h>
 #include <sound/core.h>
 #include <sound/initval.h>
 #include <sound/rawmidi.h>
@@ -1159,7 +1158,7 @@ static int __devinit gmidi_bind(struct usb_gadget *gadget)
        /* support optional vendor/distro customization */
        if (idVendor) {
                if (!idProduct) {
-                       printk(KERN_ERR "idVendor needs idProduct!\n");
+                       pr_err("idVendor needs idProduct!\n");
                        return -ENODEV;
                }
                device_desc.idVendor = cpu_to_le16(idVendor);
@@ -1191,7 +1190,7 @@ static int __devinit gmidi_bind(struct usb_gadget *gadget)
        in_ep = usb_ep_autoconfig(gadget, &bulk_in_desc);
        if (!in_ep) {
 autoconf_fail:
-               printk(KERN_ERR "%s: can't autoconfigure on %s\n",
+               pr_err("%s: can't autoconfigure on %s\n",
                        shortname, gadget->name);
                return -ENODEV;
        }
@@ -1213,7 +1212,7 @@ autoconf_fail:
                 * it SHOULD NOT have problems with bulk-capable hardware.
                 * so warn about unrecognized controllers, don't panic.
                 */
-               printk(KERN_WARNING "%s: controller '%s' not recognized\n",
+               pr_warning("%s: controller '%s' not recognized\n",
                        shortname, gadget->name);
                device_desc.bcdDevice = __constant_cpu_to_le16(0x9999);
        }
index 2ec9d196a8cfdc798232d2d51f1d4aad6686338f..d3e702576de6e23c7aca952bc40cc3288de1dd59 100644 (file)
@@ -1422,6 +1422,7 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
        spin_unlock_irqrestore(&dev->lock, flags);
 
        driver->unbind(&dev->gadget);
+       dev->gadget.dev.driver = NULL;
 
        DBG(dev, "unregistered driver '%s'\n", driver->driver.name);
        return 0;
index 47ef8bd58a00c1f99f9ef8a937801bbd12e0095d..805602a687cbc7bfd2b225d5e247a6f4f8c19cc5 100644 (file)
@@ -1699,7 +1699,7 @@ gadgetfs_bind (struct usb_gadget *gadget)
        if (!dev)
                return -ESRCH;
        if (0 != strcmp (CHIP, gadget->name)) {
-               printk (KERN_ERR "%s expected %s controller not %s\n",
+               pr_err("%s expected %s controller not %s\n",
                        shortname, CHIP, gadget->name);
                return -ENODEV;
        }
index 367b75c0b25b3e8f9a4af753fa9c6cea8578d097..37243ef7104ef7d0f24ff1369c99cf33fcb947c6 100644 (file)
@@ -474,6 +474,7 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
        spin_unlock_irqrestore(&dev->lock, flags);
 
        driver->unbind(&dev->gadget);
+       dev->gadget.dev.driver = NULL;
        device_del(&dev->gadget.dev);
 
        udc_disable(dev);
index ebc5536aa271d8ad78b76dcf701670ee76b1982c..835948f0715a9118f18e90a83fb2e2ff28161895 100644 (file)
@@ -36,9 +36,14 @@ MODULE_DESCRIPTION("M66592 USB gadget driver");
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Yoshihiro Shimoda");
 
-#define DRIVER_VERSION "29 May 2007"
+#define DRIVER_VERSION "18 Oct 2007"
 
 /* module parameters */
+#if defined(CONFIG_SUPERH_BUILT_IN_M66592)
+static unsigned short endian = M66592_LITTLE;
+module_param(endian, ushort, 0644);
+MODULE_PARM_DESC(endian, "data endian: big=0, little=0 (default=0)");
+#else
 static unsigned short clock = M66592_XTAL24;
 module_param(clock, ushort, 0644);
 MODULE_PARM_DESC(clock, "input clock: 48MHz=32768, 24MHz=16384, 12MHz=0 "
@@ -56,6 +61,7 @@ static unsigned short irq_sense = M66592_INTL;
 module_param(irq_sense, ushort, 0644);
 MODULE_PARM_DESC(irq_sense, "IRQ sense: low level=2, falling edge=0 "
                "(default=2)");
+#endif
 
 static const char udc_name[] = "m66592_udc";
 static const char *m66592_ep_name[] = {
@@ -141,7 +147,7 @@ static inline u16 control_reg_get_pid(struct m66592 *m66592, u16 pipenum)
                offset = get_pipectr_addr(pipenum);
                pid = m66592_read(m66592, offset) & M66592_PID;
        } else
-               printk(KERN_ERR "unexpect pipe num (%d)\n", pipenum);
+               pr_err("unexpect pipe num (%d)\n", pipenum);
 
        return pid;
 }
@@ -157,7 +163,7 @@ static inline void control_reg_set_pid(struct m66592 *m66592, u16 pipenum,
                offset = get_pipectr_addr(pipenum);
                m66592_mdfy(m66592, pid, M66592_PID, offset);
        } else
-               printk(KERN_ERR "unexpect pipe num (%d)\n", pipenum);
+               pr_err("unexpect pipe num (%d)\n", pipenum);
 }
 
 static inline void pipe_start(struct m66592 *m66592, u16 pipenum)
@@ -186,7 +192,7 @@ static inline u16 control_reg_get(struct m66592 *m66592, u16 pipenum)
                offset = get_pipectr_addr(pipenum);
                ret = m66592_read(m66592, offset);
        } else
-               printk(KERN_ERR "unexpect pipe num (%d)\n", pipenum);
+               pr_err("unexpect pipe num (%d)\n", pipenum);
 
        return ret;
 }
@@ -203,7 +209,7 @@ static inline void control_reg_sqclr(struct m66592 *m66592, u16 pipenum)
                offset = get_pipectr_addr(pipenum);
                m66592_bset(m66592, M66592_SQCLR, offset);
        } else
-               printk(KERN_ERR "unexpect pipe num(%d)\n", pipenum);
+               pr_err("unexpect pipe num(%d)\n", pipenum);
 }
 
 static inline int get_buffer_size(struct m66592 *m66592, u16 pipenum)
@@ -285,7 +291,7 @@ static int pipe_buffer_setting(struct m66592 *m66592,
                break;
        }
        if (m66592->bi_bufnum > M66592_MAX_BUFNUM) {
-               printk(KERN_ERR "m66592 pipe memory is insufficient(%d)\n",
+               pr_err("m66592 pipe memory is insufficient(%d)\n",
                                m66592->bi_bufnum);
                return -ENOMEM;
        }
@@ -326,7 +332,7 @@ static void pipe_buffer_release(struct m66592 *m66592,
                if (info->type == M66592_BULK)
                        m66592->bulk--;
        } else
-               printk(KERN_ERR "ep_release: unexpect pipenum (%d)\n",
+               pr_err("ep_release: unexpect pipenum (%d)\n",
                                info->pipe);
 }
 
@@ -360,6 +366,7 @@ static void m66592_ep_setting(struct m66592 *m66592, struct m66592_ep *ep,
                        ep->fifosel = M66592_D0FIFOSEL;
                        ep->fifoctr = M66592_D0FIFOCTR;
                        ep->fifotrn = M66592_D0FIFOTRN;
+#if !defined(CONFIG_SUPERH_BUILT_IN_M66592)
                } else if (m66592->num_dma == 1) {
                        m66592->num_dma++;
                        ep->use_dma = 1;
@@ -367,6 +374,7 @@ static void m66592_ep_setting(struct m66592 *m66592, struct m66592_ep *ep,
                        ep->fifosel = M66592_D1FIFOSEL;
                        ep->fifoctr = M66592_D1FIFOCTR;
                        ep->fifotrn = M66592_D1FIFOTRN;
+#endif
                } else {
                        ep->use_dma = 0;
                        ep->fifoaddr = M66592_CFIFO;
@@ -422,7 +430,7 @@ static int alloc_pipe_config(struct m66592_ep *ep,
        case USB_ENDPOINT_XFER_BULK:
                if (m66592->bulk >= M66592_MAX_NUM_BULK) {
                        if (m66592->isochronous >= M66592_MAX_NUM_ISOC) {
-                               printk(KERN_ERR "bulk pipe is insufficient\n");
+                               pr_err("bulk pipe is insufficient\n");
                                return -ENODEV;
                        } else {
                                info.pipe = M66592_BASE_PIPENUM_ISOC
@@ -438,7 +446,7 @@ static int alloc_pipe_config(struct m66592_ep *ep,
                break;
        case USB_ENDPOINT_XFER_INT:
                if (m66592->interrupt >= M66592_MAX_NUM_INT) {
-                       printk(KERN_ERR "interrupt pipe is insufficient\n");
+                       pr_err("interrupt pipe is insufficient\n");
                        return -ENODEV;
                }
                info.pipe = M66592_BASE_PIPENUM_INT + m66592->interrupt;
@@ -447,7 +455,7 @@ static int alloc_pipe_config(struct m66592_ep *ep,
                break;
        case USB_ENDPOINT_XFER_ISOC:
                if (m66592->isochronous >= M66592_MAX_NUM_ISOC) {
-                       printk(KERN_ERR "isochronous pipe is insufficient\n");
+                       pr_err("isochronous pipe is insufficient\n");
                        return -ENODEV;
                }
                info.pipe = M66592_BASE_PIPENUM_ISOC + m66592->isochronous;
@@ -455,7 +463,7 @@ static int alloc_pipe_config(struct m66592_ep *ep,
                counter = &m66592->isochronous;
                break;
        default:
-               printk(KERN_ERR "unexpect xfer type\n");
+               pr_err("unexpect xfer type\n");
                return -EINVAL;
        }
        ep->type = info.type;
@@ -470,7 +478,7 @@ static int alloc_pipe_config(struct m66592_ep *ep,
 
        ret = pipe_buffer_setting(m66592, &info);
        if (ret < 0) {
-               printk(KERN_ERR "pipe_buffer_setting fail\n");
+               pr_err("pipe_buffer_setting fail\n");
                return ret;
        }
 
@@ -606,11 +614,33 @@ static void start_ep0(struct m66592_ep *ep, struct m66592_request *req)
                control_end(ep->m66592, 0);
                break;
        default:
-               printk(KERN_ERR "start_ep0: unexpect ctsq(%x)\n", ctsq);
+               pr_err("start_ep0: unexpect ctsq(%x)\n", ctsq);
                break;
        }
 }
 
+#if defined(CONFIG_SUPERH_BUILT_IN_M66592)
+static void init_controller(struct m66592 *m66592)
+{
+       usbf_start_clock();
+       m66592_bset(m66592, M66592_HSE, M66592_SYSCFG);         /* High spd */
+       m66592_bclr(m66592, M66592_USBE, M66592_SYSCFG);
+       m66592_bclr(m66592, M66592_DPRPU, M66592_SYSCFG);
+       m66592_bset(m66592, M66592_USBE, M66592_SYSCFG);
+
+       /* This is a workaound for SH7722 2nd cut */
+       m66592_bset(m66592, 0x8000, M66592_DVSTCTR);
+       m66592_bset(m66592, 0x1000, M66592_TESTMODE);
+       m66592_bclr(m66592, 0x8000, M66592_DVSTCTR);
+
+       m66592_bset(m66592, M66592_INTL, M66592_INTENB1);
+
+       m66592_write(m66592, 0, M66592_CFBCFG);
+       m66592_write(m66592, 0, M66592_D0FBCFG);
+       m66592_bset(m66592, endian, M66592_CFBCFG);
+       m66592_bset(m66592, endian, M66592_D0FBCFG);
+}
+#else  /* #if defined(CONFIG_SUPERH_BUILT_IN_M66592) */
 static void init_controller(struct m66592 *m66592)
 {
        m66592_bset(m66592, (vif & M66592_LDRV) | (endian & M66592_BIGEND),
@@ -636,9 +666,13 @@ static void init_controller(struct m66592 *m66592)
        m66592_write(m66592, M66592_BURST | M66592_CPU_ADR_RD_WR,
                        M66592_DMA0CFG);
 }
+#endif /* #if defined(CONFIG_SUPERH_BUILT_IN_M66592) */
 
 static void disable_controller(struct m66592 *m66592)
 {
+#if defined(CONFIG_SUPERH_BUILT_IN_M66592)
+       usbf_stop_clock();
+#else
        m66592_bclr(m66592, M66592_SCKE, M66592_SYSCFG);
        udelay(1);
        m66592_bclr(m66592, M66592_PLLC, M66592_SYSCFG);
@@ -646,15 +680,20 @@ static void disable_controller(struct m66592 *m66592)
        m66592_bclr(m66592, M66592_RCKE, M66592_SYSCFG);
        udelay(1);
        m66592_bclr(m66592, M66592_XCKE, M66592_SYSCFG);
+#endif
 }
 
 static void m66592_start_xclock(struct m66592 *m66592)
 {
+#if defined(CONFIG_SUPERH_BUILT_IN_M66592)
+       usbf_start_clock();
+#else
        u16 tmp;
 
        tmp = m66592_read(m66592, M66592_SYSCFG);
        if (!(tmp & M66592_XCKE))
                m66592_bset(m66592, M66592_XCKE, M66592_SYSCFG);
+#endif
 }
 
 /*-------------------------------------------------------------------------*/
@@ -709,7 +748,7 @@ static void irq_ep0_write(struct m66592_ep *ep, struct m66592_request *req)
        do {
                tmp = m66592_read(m66592, ep->fifoctr);
                if (i++ > 100000) {
-                       printk(KERN_ERR "pipe0 is busy. maybe cpu i/o bus"
+                       pr_err("pipe0 is busy. maybe cpu i/o bus "
                                "conflict. please power off this controller.");
                        return;
                }
@@ -759,7 +798,7 @@ static void irq_packet_write(struct m66592_ep *ep, struct m66592_request *req)
        if (unlikely((tmp & M66592_FRDY) == 0)) {
                pipe_stop(m66592, pipenum);
                pipe_irq_disable(m66592, pipenum);
-               printk(KERN_ERR "write fifo not ready. pipnum=%d\n", pipenum);
+               pr_err("write fifo not ready. pipnum=%d\n", pipenum);
                return;
        }
 
@@ -808,7 +847,7 @@ static void irq_packet_read(struct m66592_ep *ep, struct m66592_request *req)
                req->req.status = -EPIPE;
                pipe_stop(m66592, pipenum);
                pipe_irq_disable(m66592, pipenum);
-               printk(KERN_ERR "read fifo not ready");
+               pr_err("read fifo not ready");
                return;
        }
 
@@ -1063,7 +1102,7 @@ static void m66592_update_usb_speed(struct m66592 *m66592)
                break;
        default:
                m66592->gadget.speed = USB_SPEED_UNKNOWN;
-               printk(KERN_ERR "USB speed unknown\n");
+               pr_err("USB speed unknown\n");
        }
 }
 
@@ -1122,7 +1161,7 @@ __acquires(m66592->lock)
                control_end(m66592, 0);
                break;
        default:
-               printk(KERN_ERR "ctrl_stage: unexpect ctsq(%x)\n", ctsq);
+               pr_err("ctrl_stage: unexpect ctsq(%x)\n", ctsq);
                break;
        }
 }
@@ -1142,6 +1181,19 @@ static irqreturn_t m66592_irq(int irq, void *_m66592)
        intsts0 = m66592_read(m66592, M66592_INTSTS0);
        intenb0 = m66592_read(m66592, M66592_INTENB0);
 
+#if defined(CONFIG_SUPERH_BUILT_IN_M66592)
+       if (!intsts0 && !intenb0) {
+               /*
+                * When USB clock stops, it cannot read register. Even if a
+                * clock stops, the interrupt occurs. So this driver turn on
+                * a clock by this timing and do re-reading of register.
+                */
+               m66592_start_xclock(m66592);
+               intsts0 = m66592_read(m66592, M66592_INTSTS0);
+               intenb0 = m66592_read(m66592, M66592_INTENB0);
+       }
+#endif
+
        savepipe = m66592_read(m66592, M66592_CFIFOSEL);
 
        mask0 = intsts0 & intenb0;
@@ -1409,13 +1461,13 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
 
        retval = device_add(&m66592->gadget.dev);
        if (retval) {
-               printk(KERN_ERR "device_add error (%d)\n", retval);
+               pr_err("device_add error (%d)\n", retval);
                goto error;
        }
 
        retval = driver->bind (&m66592->gadget);
        if (retval) {
-               printk(KERN_ERR "bind to driver error (%d)\n", retval);
+               pr_err("bind to driver error (%d)\n", retval);
                device_del(&m66592->gadget.dev);
                goto error;
        }
@@ -1456,6 +1508,7 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
        m66592_bclr(m66592, M66592_VBSE | M66592_URST, M66592_INTENB0);
 
        driver->unbind(&m66592->gadget);
+       m66592->gadget.dev.driver = NULL;
 
        init_controller(m66592);
        disable_controller(m66592);
@@ -1485,6 +1538,7 @@ static int __exit m66592_remove(struct platform_device *pdev)
        iounmap(m66592->reg);
        free_irq(platform_get_irq(pdev, 0), m66592);
        m66592_free_request(&m66592->ep[0].ep, m66592->ep0_req);
+       usbf_stop_clock();
        kfree(m66592);
        return 0;
 }
@@ -1508,28 +1562,28 @@ static int __init m66592_probe(struct platform_device *pdev)
                        (char *)udc_name);
        if (!res) {
                ret = -ENODEV;
-               printk(KERN_ERR "platform_get_resource_byname error.\n");
+               pr_err("platform_get_resource_byname error.\n");
                goto clean_up;
        }
 
        irq = platform_get_irq(pdev, 0);
        if (irq < 0) {
                ret = -ENODEV;
-               printk(KERN_ERR "platform_get_irq error.\n");
+               pr_err("platform_get_irq error.\n");
                goto clean_up;
        }
 
        reg = ioremap(res->start, resource_len(res));
        if (reg == NULL) {
                ret = -ENOMEM;
-               printk(KERN_ERR "ioremap error.\n");
+               pr_err("ioremap error.\n");
                goto clean_up;
        }
 
        /* initialize ucd */
        m66592 = kzalloc(sizeof(struct m66592), GFP_KERNEL);
        if (m66592 == NULL) {
-               printk(KERN_ERR "kzalloc error\n");
+               pr_err("kzalloc error\n");
                goto clean_up;
        }
 
@@ -1555,7 +1609,7 @@ static int __init m66592_probe(struct platform_device *pdev)
        ret = request_irq(irq, m66592_irq, IRQF_DISABLED | IRQF_SHARED,
                        udc_name, m66592);
        if (ret < 0) {
-               printk(KERN_ERR "request_irq error (%d)\n", ret);
+               pr_err("request_irq error (%d)\n", ret);
                goto clean_up;
        }
 
index bfa0c645f229b97752c5362c8503cf1e8f8e46f3..17b792b7f6bfc43d3879fc316b188f0a12ae36f4 100644 (file)
 #define   M66592_P_TST_J        0x0001         /* PERI TEST J */
 #define   M66592_P_TST_NORMAL   0x0000         /* PERI Normal Mode */
 
+#if defined(CONFIG_SUPERH_BUILT_IN_M66592)
+#define M66592_CFBCFG          0x0A
+#define M66592_D0FBCFG         0x0C
+#define M66592_LITTLE          0x0100  /* b8: Little endian mode */
+#else
 #define M66592_PINCFG          0x0A
 #define M66592_LDRV            0x8000  /* b15: Drive Current Adjust */
 #define M66592_BIGEND          0x0100  /* b8: Big endian mode */
@@ -91,6 +96,7 @@
 #define M66592_PKTM            0x0020  /* b5: Packet mode */
 #define M66592_DENDE           0x0010  /* b4: Dend enable */
 #define M66592_OBUS            0x0004  /* b2: OUTbus mode */
+#endif /* #if defined(CONFIG_SUPERH_BUILT_IN_M66592) */
 
 #define M66592_CFIFO           0x10
 #define M66592_D0FIFO          0x14
 #define M66592_REW             0x4000  /* b14: Buffer rewind */
 #define M66592_DCLRM           0x2000  /* b13: DMA buffer clear mode */
 #define M66592_DREQE           0x1000  /* b12: DREQ output enable */
+#if defined(CONFIG_SUPERH_BUILT_IN_M66592)
+#define M66592_MBW             0x0800  /* b11: Maximum bit width for FIFO */
+#else
 #define M66592_MBW             0x0400  /* b10: Maximum bit width for FIFO */
 #define   M66592_MBW_8          0x0000   /*  8bit */
 #define   M66592_MBW_16                 0x0400   /* 16bit */
+#endif /* #if defined(CONFIG_SUPERH_BUILT_IN_M66592) */
 #define M66592_TRENB           0x0200  /* b9: Transaction counter enable */
 #define M66592_TRCLR           0x0100  /* b8: Transaction counter clear */
 #define M66592_DEZPM           0x0080  /* b7: Zero-length packet mode */
@@ -530,8 +540,13 @@ static inline void m66592_read_fifo(struct m66592 *m66592,
 {
        unsigned long fifoaddr = (unsigned long)m66592->reg + offset;
 
+#if defined(CONFIG_SUPERH_BUILT_IN_M66592)
+       len = (len + 3) / 4;
+       insl(fifoaddr, buf, len);
+#else
        len = (len + 1) / 2;
        insw(fifoaddr, buf, len);
+#endif
 }
 
 static inline void m66592_write(struct m66592 *m66592, u16 val,
@@ -545,6 +560,24 @@ static inline void m66592_write_fifo(struct m66592 *m66592,
                void *buf, unsigned long len)
 {
        unsigned long fifoaddr = (unsigned long)m66592->reg + offset;
+#if defined(CONFIG_SUPERH_BUILT_IN_M66592)
+       unsigned long count;
+       unsigned char *pb;
+       int i;
+
+       count = len / 4;
+       outsl(fifoaddr, buf, count);
+
+       if (len & 0x00000003) {
+               pb = buf + count * 4;
+               for (i = 0; i < (len & 0x00000003); i++) {
+                       if (m66592_read(m66592, M66592_CFBCFG)) /* little */
+                               outb(pb[i], fifoaddr + (3 - i));
+                       else
+                               outb(pb[i], fifoaddr + i);
+               }
+       }
+#else
        unsigned long odd = len & 0x0001;
 
        len = len / 2;
@@ -553,6 +586,7 @@ static inline void m66592_write_fifo(struct m66592 *m66592,
                unsigned char *p = buf + len*2;
                outb(*p, fifoaddr);
        }
+#endif /* #if defined(CONFIG_SUPERH_BUILT_IN_M66592) */
 }
 
 static inline void m66592_mdfy(struct m66592 *m66592, u16 val, u16 pat,
@@ -570,6 +604,26 @@ static inline void m66592_mdfy(struct m66592 *m66592, u16 val, u16 pat,
 #define m66592_bset(m66592, val, offset)       \
                        m66592_mdfy(m66592, val, 0, offset)
 
+#if defined(CONFIG_SUPERH_BUILT_IN_M66592)
+#include <asm/io.h>
+#define MSTPCR2                0xA4150038      /* for SH7722 */
+#define MSTPCR2_USB    0x00000800
+
+static inline void usbf_start_clock(void)
+{
+       ctrl_outl(ctrl_inl(MSTPCR2) & ~MSTPCR2_USB, MSTPCR2);
+}
+
+static inline void usbf_stop_clock(void)
+{
+       ctrl_outl(ctrl_inl(MSTPCR2) | MSTPCR2_USB, MSTPCR2);
+}
+
+#else
+#define usbf_start_clock(x)
+#define usbf_stop_clock(x)
+#endif /* if defined(CONFIG_SUPERH_BUILT_IN_M66592) */
+
 #endif /* ifndef __M66592_UDC_H__ */
 
 
index d5d473f8144b5332a550f07a9ece5df1ab4cc946..33469cf5aec35af86933b39d3781a409ffc9f97c 100644 (file)
@@ -2435,7 +2435,7 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat)
                        break;
                default:
 delegate:
-                       VDEBUG (dev, "setup %02x.%02x v%04x i%04x l%04x"
+                       VDEBUG (dev, "setup %02x.%02x v%04x i%04x l%04x "
                                "ep_cfg %08x\n",
                                u.r.bRequestType, u.r.bRequest,
                                w_value, w_index, w_length,
index d377154658b5abe624568eabecde914a107caff6..e6d68bda428a850d6d98ac05d06abf83aa604b18 100644 (file)
@@ -4,6 +4,8 @@
  * Copyright (C) 2004 Texas Instruments, Inc.
  * Copyright (C) 2004-2005 David Brownell
  *
+ * OMAP2 & DMA support by Kyungmin Park <kyungmin.park@samsung.com>
+ *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
 /* bulk DMA seems to be behaving for both IN and OUT */
 #define        USE_DMA
 
-/* FIXME: OMAP2 currently has some problem in DMA mode */
-#ifdef CONFIG_ARCH_OMAP2
-#undef USE_DMA
-#endif
-
 /* ISO too */
 #define        USE_ISO
 
@@ -73,6 +70,8 @@
 
 #define        DMA_ADDR_INVALID        (~(dma_addr_t)0)
 
+#define OMAP2_DMA_CH(ch)       (((ch) - 1) << 1)
+#define OMAP24XX_DMA(name, ch) (OMAP24XX_DMA_##name + OMAP2_DMA_CH(ch))
 
 /*
  * The OMAP UDC needs _very_ early endpoint setup:  before enabling the
@@ -571,20 +570,25 @@ static void next_in_dma(struct omap_ep *ep, struct omap_req *req)
        const int       sync_mode = cpu_is_omap15xx()
                                ? OMAP_DMA_SYNC_FRAME
                                : OMAP_DMA_SYNC_ELEMENT;
+       int             dma_trigger = 0;
+
+       if (cpu_is_omap24xx())
+               dma_trigger = OMAP24XX_DMA(USB_W2FC_TX0, ep->dma_channel);
 
        /* measure length in either bytes or packets */
        if ((cpu_is_omap16xx() && length <= UDC_TXN_TSC)
+                       || (cpu_is_omap24xx() && length < ep->maxpacket)
                        || (cpu_is_omap15xx() && length < ep->maxpacket)) {
                txdma_ctrl = UDC_TXN_EOT | length;
                omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S8,
-                               length, 1, sync_mode, 0, 0);
+                               length, 1, sync_mode, dma_trigger, 0);
        } else {
                length = min(length / ep->maxpacket,
                                (unsigned) UDC_TXN_TSC + 1);
                txdma_ctrl = length;
                omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S16,
                                ep->ep.maxpacket >> 1, length, sync_mode,
-                               0, 0);
+                               dma_trigger, 0);
                length *= ep->maxpacket;
        }
        omap_set_dma_src_params(ep->lch, OMAP_DMA_PORT_EMIFF,
@@ -622,20 +626,31 @@ static void finish_in_dma(struct omap_ep *ep, struct omap_req *req, int status)
 
 static void next_out_dma(struct omap_ep *ep, struct omap_req *req)
 {
-       unsigned packets;
+       unsigned packets = req->req.length - req->req.actual;
+       int dma_trigger = 0;
+
+       if (cpu_is_omap24xx())
+               dma_trigger = OMAP24XX_DMA(USB_W2FC_RX0, ep->dma_channel);
 
        /* NOTE:  we filtered out "short reads" before, so we know
         * the buffer has only whole numbers of packets.
+        * except MODE SELECT(6) sent the 24 bytes data in OMAP24XX DMA mode
         */
-
-       /* set up this DMA transfer, enable the fifo, start */
-       packets = (req->req.length - req->req.actual) / ep->ep.maxpacket;
-       packets = min(packets, (unsigned)UDC_RXN_TC + 1);
-       req->dma_bytes = packets * ep->ep.maxpacket;
-       omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S16,
-                       ep->ep.maxpacket >> 1, packets,
-                       OMAP_DMA_SYNC_ELEMENT,
-                       0, 0);
+       if (cpu_is_omap24xx() && packets < ep->maxpacket) {
+               omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S8,
+                               packets, 1, OMAP_DMA_SYNC_ELEMENT,
+                               dma_trigger, 0);
+               req->dma_bytes = packets;
+       } else {
+               /* set up this DMA transfer, enable the fifo, start */
+               packets /= ep->ep.maxpacket;
+               packets = min(packets, (unsigned)UDC_RXN_TC + 1);
+               req->dma_bytes = packets * ep->ep.maxpacket;
+               omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S16,
+                               ep->ep.maxpacket >> 1, packets,
+                               OMAP_DMA_SYNC_ELEMENT,
+                               dma_trigger, 0);
+       }
        omap_set_dma_dest_params(ep->lch, OMAP_DMA_PORT_EMIFF,
                OMAP_DMA_AMODE_POST_INC, req->req.dma + req->req.actual,
                0, 0);
@@ -743,6 +758,7 @@ static void dma_channel_claim(struct omap_ep *ep, unsigned channel)
 {
        u16     reg;
        int     status, restart, is_in;
+       int     dma_channel;
 
        is_in = ep->bEndpointAddress & USB_DIR_IN;
        if (is_in)
@@ -769,11 +785,15 @@ static void dma_channel_claim(struct omap_ep *ep, unsigned channel)
        ep->dma_channel = channel;
 
        if (is_in) {
-               status = omap_request_dma(OMAP_DMA_USB_W2FC_TX0 - 1 + channel,
+               if (cpu_is_omap24xx())
+                       dma_channel = OMAP24XX_DMA(USB_W2FC_TX0, channel);
+               else
+                       dma_channel = OMAP_DMA_USB_W2FC_TX0 - 1 + channel;
+               status = omap_request_dma(dma_channel,
                        ep->ep.name, dma_error, ep, &ep->lch);
                if (status == 0) {
                        UDC_TXDMA_CFG_REG = reg;
-                       /* EMIFF */
+                       /* EMIFF or SDRC */
                        omap_set_dma_src_burst_mode(ep->lch,
                                                OMAP_DMA_DATA_BURST_4);
                        omap_set_dma_src_data_pack(ep->lch, 1);
@@ -785,7 +805,12 @@ static void dma_channel_claim(struct omap_ep *ep, unsigned channel)
                                0, 0);
                }
        } else {
-               status = omap_request_dma(OMAP_DMA_USB_W2FC_RX0 - 1 + channel,
+               if (cpu_is_omap24xx())
+                       dma_channel = OMAP24XX_DMA(USB_W2FC_RX0, channel);
+               else
+                       dma_channel = OMAP_DMA_USB_W2FC_RX0 - 1 + channel;
+
+               status = omap_request_dma(dma_channel,
                        ep->ep.name, dma_error, ep, &ep->lch);
                if (status == 0) {
                        UDC_RXDMA_CFG_REG = reg;
@@ -795,7 +820,7 @@ static void dma_channel_claim(struct omap_ep *ep, unsigned channel)
                                OMAP_DMA_AMODE_CONSTANT,
                                (unsigned long) io_v2p((u32)&UDC_DATA_DMA_REG),
                                0, 0);
-                       /* EMIFF */
+                       /* EMIFF or SDRC */
                        omap_set_dma_dest_burst_mode(ep->lch,
                                                OMAP_DMA_DATA_BURST_4);
                        omap_set_dma_dest_data_pack(ep->lch, 1);
@@ -808,7 +833,7 @@ static void dma_channel_claim(struct omap_ep *ep, unsigned channel)
                omap_disable_dma_irq(ep->lch, OMAP_DMA_BLOCK_IRQ);
 
                /* channel type P: hw synch (fifo) */
-               if (!cpu_is_omap15xx())
+               if (cpu_class_is_omap1() && !cpu_is_omap15xx())
                        OMAP1_DMA_LCH_CTRL_REG(ep->lch) = 2;
        }
 
@@ -926,11 +951,13 @@ omap_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
 
        /* this isn't bogus, but OMAP DMA isn't the only hardware to
         * have a hard time with partial packet reads...  reject it.
+        * Except OMAP2 can handle the small packets.
         */
        if (use_dma
                        && ep->has_dma
                        && ep->bEndpointAddress != 0
                        && (ep->bEndpointAddress & USB_DIR_IN) == 0
+                       && !cpu_class_is_omap2()
                        && (req->req.length % ep->ep.maxpacket) != 0) {
                DBG("%s, no partial packet OUT reads\n", __FUNCTION__);
                return -EMSGSIZE;
@@ -1001,7 +1028,7 @@ omap_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
 
                                /* STATUS for zero length DATA stages is
                                 * always an IN ... even for IN transfers,
-                                * a wierd case which seem to stall OMAP.
+                                * a weird case which seem to stall OMAP.
                                 */
                                UDC_EP_NUM_REG = (UDC_EP_SEL|UDC_EP_DIR);
                                UDC_CTRL_REG = UDC_CLR_EP;
index 1dc398bb9ab2ae408f0d77ee2c24d3d9c966c838..c6b9cbc7230a5bb121feb288dd9ce3228c9f984d 100644 (file)
@@ -182,21 +182,16 @@ struct omap_udc {
 
 /*-------------------------------------------------------------------------*/
 
-#ifdef DEBUG
-#define DBG(stuff...)          printk(KERN_DEBUG "udc: " stuff)
-#else
-#define DBG(stuff...)          do{}while(0)
-#endif
-
 #ifdef VERBOSE
 #    define VDBG               DBG
 #else
 #    define VDBG(stuff...)     do{}while(0)
 #endif
 
-#define ERR(stuff...)          printk(KERN_ERR "udc: " stuff)
-#define WARN(stuff...)         printk(KERN_WARNING "udc: " stuff)
-#define INFO(stuff...)         printk(KERN_INFO "udc: " stuff)
+#define ERR(stuff...)          pr_err("udc: " stuff)
+#define WARN(stuff...)         pr_warning("udc: " stuff)
+#define INFO(stuff...)         pr_info("udc: " stuff)
+#define DBG(stuff...)          pr_debug("udc: " stuff)
 
 /*-------------------------------------------------------------------------*/
 
diff --git a/drivers/usb/gadget/printer.c b/drivers/usb/gadget/printer.c
new file mode 100644 (file)
index 0000000..9fdabc8
--- /dev/null
@@ -0,0 +1,1592 @@
+/*
+ * printer.c -- Printer gadget driver
+ *
+ * Copyright (C) 2003-2005 David Brownell
+ * Copyright (C) 2006 Craig W. Nadler
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/module.h>
+#include <linux/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/utsname.h>
+#include <linux/device.h>
+#include <linux/moduleparam.h>
+#include <linux/fs.h>
+#include <linux/poll.h>
+#include <linux/types.h>
+#include <linux/ctype.h>
+#include <linux/cdev.h>
+
+#include <asm/byteorder.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <asm/system.h>
+#include <linux/uaccess.h>
+#include <asm/unaligned.h>
+
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/g_printer.h>
+
+#include "gadget_chips.h"
+
+#define DRIVER_DESC            "Printer Gadget"
+#define DRIVER_VERSION         "2007 OCT 06"
+
+static const char shortname [] = "printer";
+static const char driver_desc [] = DRIVER_DESC;
+
+static dev_t g_printer_devno;
+
+static struct class *usb_gadget_class;
+
+/*-------------------------------------------------------------------------*/
+
+struct printer_dev {
+       spinlock_t              lock;           /* lock this structure */
+       /* lock buffer lists during read/write calls */
+       spinlock_t              lock_printer_io;
+       struct usb_gadget       *gadget;
+       struct usb_request      *req;           /* for control responses */
+       u8                      config;
+       s8                      interface;
+       struct usb_ep           *in_ep, *out_ep;
+       const struct usb_endpoint_descriptor
+                               *in, *out;
+       struct list_head        rx_reqs;        /* List of free RX structs */
+       struct list_head        rx_reqs_active; /* List of Active RX xfers */
+       struct list_head        rx_buffers;     /* List of completed xfers */
+       /* wait until there is data to be read. */
+       wait_queue_head_t       rx_wait;
+       struct list_head        tx_reqs;        /* List of free TX structs */
+       struct list_head        tx_reqs_active; /* List of Active TX xfers */
+       /* Wait until there are write buffers available to use. */
+       wait_queue_head_t       tx_wait;
+       /* Wait until all write buffers have been sent. */
+       wait_queue_head_t       tx_flush_wait;
+       struct usb_request      *current_rx_req;
+       size_t                  current_rx_bytes;
+       u8                      *current_rx_buf;
+       u8                      printer_status;
+       u8                      reset_printer;
+       struct class_device     *printer_class_dev;
+       struct cdev             printer_cdev;
+       struct device           *pdev;
+       u8                      printer_cdev_open;
+       wait_queue_head_t       wait;
+};
+
+static struct printer_dev usb_printer_gadget;
+
+/*-------------------------------------------------------------------------*/
+
+/* 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 PRINTER_VENDOR_NUM     0x0525          /* NetChip */
+#define PRINTER_PRODUCT_NUM    0xa4a8          /* Linux-USB Printer Gadget */
+
+/* Some systems will want different product identifers published in the
+ * device descriptor, either numbers or strings or both.  These string
+ * parameters are in UTF-8 (superset of ASCII's 7 bit characters).
+ */
+
+static ushort __initdata idVendor;
+module_param(idVendor, ushort, S_IRUGO);
+MODULE_PARM_DESC(idVendor, "USB Vendor ID");
+
+static ushort __initdata idProduct;
+module_param(idProduct, ushort, S_IRUGO);
+MODULE_PARM_DESC(idProduct, "USB Product ID");
+
+static ushort __initdata bcdDevice;
+module_param(bcdDevice, ushort, S_IRUGO);
+MODULE_PARM_DESC(bcdDevice, "USB Device version (BCD)");
+
+static char *__initdata iManufacturer;
+module_param(iManufacturer, charp, S_IRUGO);
+MODULE_PARM_DESC(iManufacturer, "USB Manufacturer string");
+
+static char *__initdata iProduct;
+module_param(iProduct, charp, S_IRUGO);
+MODULE_PARM_DESC(iProduct, "USB Product string");
+
+static char *__initdata iSerialNum;
+module_param(iSerialNum, charp, S_IRUGO);
+MODULE_PARM_DESC(iSerialNum, "1");
+
+static char *__initdata iPNPstring;
+module_param(iPNPstring, charp, S_IRUGO);
+MODULE_PARM_DESC(iPNPstring, "MFG:linux;MDL:g_printer;CLS:PRINTER;SN:1;");
+
+/* Number of requests to allocate per endpoint, not used for ep0. */
+static unsigned qlen = 10;
+module_param(qlen, uint, S_IRUGO|S_IWUSR);
+
+#define QLEN   qlen
+
+#ifdef CONFIG_USB_GADGET_DUALSPEED
+#define DEVSPEED       USB_SPEED_HIGH
+#else   /* full speed (low speed doesn't do bulk) */
+#define DEVSPEED        USB_SPEED_FULL
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+#define xprintk(d, level, fmt, args...) \
+       printk(level "%s: " fmt, DRIVER_DESC, ## args)
+
+#ifdef DEBUG
+#define DBG(dev, fmt, args...) \
+       xprintk(dev, KERN_DEBUG, fmt, ## args)
+#else
+#define DBG(dev, fmt, args...) \
+       do { } while (0)
+#endif /* DEBUG */
+
+#ifdef VERBOSE
+#define VDBG(dev, fmt, args...) \
+       xprintk(dev, KERN_DEBUG, fmt, ## args)
+#else
+#define VDBG(dev, fmt, args...) \
+       do { } while (0)
+#endif /* VERBOSE */
+
+#define ERROR(dev, fmt, args...) \
+       xprintk(dev, KERN_ERR, fmt, ## args)
+#define WARN(dev, fmt, args...) \
+       xprintk(dev, KERN_WARNING, fmt, ## args)
+#define INFO(dev, fmt, args...) \
+       xprintk(dev, KERN_INFO, fmt, ## args)
+
+/*-------------------------------------------------------------------------*/
+
+/* USB DRIVER HOOKUP (to the hardware driver, below us), mostly
+ * ep0 implementation:  descriptors, config management, setup().
+ * also optional class-specific notification interrupt transfer.
+ */
+
+/*
+ * DESCRIPTORS ... most are static, but strings and (full) configuration
+ * descriptors are built on demand.
+ */
+
+#define STRING_MANUFACTURER            1
+#define STRING_PRODUCT                 2
+#define STRING_SERIALNUM               3
+
+/* holds our biggest descriptor */
+#define USB_DESC_BUFSIZE               256
+#define USB_BUFSIZE                    8192
+
+/* This device advertises one configuration. */
+#define DEV_CONFIG_VALUE               1
+#define        PRINTER_INTERFACE               0
+
+static struct usb_device_descriptor device_desc = {
+       .bLength =              sizeof device_desc,
+       .bDescriptorType =      USB_DT_DEVICE,
+       .bcdUSB =               __constant_cpu_to_le16(0x0200),
+       .bDeviceClass =         USB_CLASS_PER_INTERFACE,
+       .bDeviceSubClass =      0,
+       .bDeviceProtocol =      0,
+       .idVendor =             __constant_cpu_to_le16(PRINTER_VENDOR_NUM),
+       .idProduct =            __constant_cpu_to_le16(PRINTER_PRODUCT_NUM),
+       .iManufacturer =        STRING_MANUFACTURER,
+       .iProduct =             STRING_PRODUCT,
+       .iSerialNumber =        STRING_SERIALNUM,
+       .bNumConfigurations =   1
+};
+
+static struct usb_otg_descriptor otg_desc = {
+       .bLength =              sizeof otg_desc,
+       .bDescriptorType =      USB_DT_OTG,
+       .bmAttributes =         USB_OTG_SRP
+};
+
+static struct usb_config_descriptor config_desc = {
+       .bLength =              sizeof config_desc,
+       .bDescriptorType =      USB_DT_CONFIG,
+
+       /* compute wTotalLength on the fly */
+       .bNumInterfaces =       1,
+       .bConfigurationValue =  DEV_CONFIG_VALUE,
+       .iConfiguration =       0,
+       .bmAttributes =         USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
+       .bMaxPower =            1       /* Self-Powered */
+};
+
+static struct usb_interface_descriptor intf_desc = {
+       .bLength =              sizeof intf_desc,
+       .bDescriptorType =      USB_DT_INTERFACE,
+       .bInterfaceNumber =     PRINTER_INTERFACE,
+       .bNumEndpoints =        2,
+       .bInterfaceClass =      USB_CLASS_PRINTER,
+       .bInterfaceSubClass =   1,      /* Printer Sub-Class */
+       .bInterfaceProtocol =   2,      /* Bi-Directional */
+       .iInterface =           0
+};
+
+static struct usb_endpoint_descriptor fs_ep_in_desc = {
+       .bLength =              USB_DT_ENDPOINT_SIZE,
+       .bDescriptorType =      USB_DT_ENDPOINT,
+       .bEndpointAddress =     USB_DIR_IN,
+       .bmAttributes =         USB_ENDPOINT_XFER_BULK
+};
+
+static struct usb_endpoint_descriptor fs_ep_out_desc = {
+       .bLength =              USB_DT_ENDPOINT_SIZE,
+       .bDescriptorType =      USB_DT_ENDPOINT,
+       .bEndpointAddress =     USB_DIR_OUT,
+       .bmAttributes =         USB_ENDPOINT_XFER_BULK
+};
+
+static const struct usb_descriptor_header *fs_printer_function [11] = {
+       (struct usb_descriptor_header *) &otg_desc,
+       (struct usb_descriptor_header *) &intf_desc,
+       (struct usb_descriptor_header *) &fs_ep_in_desc,
+       (struct usb_descriptor_header *) &fs_ep_out_desc,
+       NULL
+};
+
+#ifdef CONFIG_USB_GADGET_DUALSPEED
+
+/*
+ * usb 2.0 devices need to expose both high speed and full speed
+ * descriptors, unless they only run at full speed.
+ */
+
+static struct usb_endpoint_descriptor hs_ep_in_desc = {
+       .bLength =              USB_DT_ENDPOINT_SIZE,
+       .bDescriptorType =      USB_DT_ENDPOINT,
+       .bmAttributes =         USB_ENDPOINT_XFER_BULK,
+       .wMaxPacketSize =       __constant_cpu_to_le16(512)
+};
+
+static struct usb_endpoint_descriptor hs_ep_out_desc = {
+       .bLength =              USB_DT_ENDPOINT_SIZE,
+       .bDescriptorType =      USB_DT_ENDPOINT,
+       .bmAttributes =         USB_ENDPOINT_XFER_BULK,
+       .wMaxPacketSize =       __constant_cpu_to_le16(512)
+};
+
+static struct usb_qualifier_descriptor dev_qualifier = {
+       .bLength =              sizeof dev_qualifier,
+       .bDescriptorType =      USB_DT_DEVICE_QUALIFIER,
+       .bcdUSB =               __constant_cpu_to_le16(0x0200),
+       .bDeviceClass =         USB_CLASS_PRINTER,
+       .bNumConfigurations =   1
+};
+
+static const struct usb_descriptor_header *hs_printer_function [11] = {
+       (struct usb_descriptor_header *) &otg_desc,
+       (struct usb_descriptor_header *) &intf_desc,
+       (struct usb_descriptor_header *) &hs_ep_in_desc,
+       (struct usb_descriptor_header *) &hs_ep_out_desc,
+       NULL
+};
+
+/* maxpacket and other transfer characteristics vary by speed. */
+#define ep_desc(g, hs, fs) (((g)->speed == USB_SPEED_HIGH)?(hs):(fs))
+
+#else
+
+/* if there's no high speed support, maxpacket doesn't change. */
+#define ep_desc(g, hs, fs) (((void)(g)), (fs))
+
+#endif /* !CONFIG_USB_GADGET_DUALSPEED */
+
+/*-------------------------------------------------------------------------*/
+
+/* descriptors that are built on-demand */
+
+static char                            manufacturer [50];
+static char                            product_desc [40] = DRIVER_DESC;
+static char                            serial_num [40] = "1";
+static char                            pnp_string [1024] =
+       "XXMFG:linux;MDL:g_printer;CLS:PRINTER;SN:1;";
+
+/* static strings, in UTF-8 */
+static struct usb_string               strings [] = {
+       { STRING_MANUFACTURER,  manufacturer, },
+       { STRING_PRODUCT,       product_desc, },
+       { STRING_SERIALNUM,     serial_num, },
+       {  }            /* end of list */
+};
+
+static struct usb_gadget_strings       stringtab = {
+       .language       = 0x0409,       /* en-us */
+       .strings        = strings,
+};
+
+/*-------------------------------------------------------------------------*/
+
+static struct usb_request *
+printer_req_alloc(struct usb_ep *ep, unsigned len, gfp_t gfp_flags)
+{
+       struct usb_request      *req;
+
+       req = usb_ep_alloc_request(ep, gfp_flags);
+
+       if (req != NULL) {
+               req->length = len;
+               req->buf = kmalloc(len, gfp_flags);
+               if (req->buf == NULL) {
+                       usb_ep_free_request(ep, req);
+                       return NULL;
+               }
+       }
+
+       return req;
+}
+
+static void
+printer_req_free(struct usb_ep *ep, struct usb_request *req)
+{
+       if (ep != NULL && req != NULL) {
+               kfree(req->buf);
+               usb_ep_free_request(ep, req);
+       }
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void rx_complete(struct usb_ep *ep, struct usb_request *req)
+{
+       struct printer_dev      *dev = ep->driver_data;
+       int                     status = req->status;
+       unsigned long           flags;
+
+       spin_lock_irqsave(&dev->lock, flags);
+
+       list_del_init(&req->list);      /* Remode from Active List */
+
+       switch (status) {
+
+       /* normal completion */
+       case 0:
+               list_add_tail(&req->list, &dev->rx_buffers);
+               wake_up_interruptible(&dev->rx_wait);
+               DBG(dev, "G_Printer : rx length %d\n", req->actual);
+               break;
+
+       /* software-driven interface shutdown */
+       case -ECONNRESET:               /* unlink */
+       case -ESHUTDOWN:                /* disconnect etc */
+               VDBG(dev, "rx shutdown, code %d\n", status);
+               list_add(&req->list, &dev->rx_reqs);
+               break;
+
+       /* for hardware automagic (such as pxa) */
+       case -ECONNABORTED:             /* endpoint reset */
+               DBG(dev, "rx %s reset\n", ep->name);
+               list_add(&req->list, &dev->rx_reqs);
+               break;
+
+       /* data overrun */
+       case -EOVERFLOW:
+               /* FALLTHROUGH */
+
+       default:
+               DBG(dev, "rx status %d\n", status);
+               list_add(&req->list, &dev->rx_reqs);
+               break;
+       }
+       spin_unlock_irqrestore(&dev->lock, flags);
+}
+
+static void tx_complete(struct usb_ep *ep, struct usb_request *req)
+{
+       struct printer_dev      *dev = ep->driver_data;
+
+       switch (req->status) {
+       default:
+               VDBG(dev, "tx err %d\n", req->status);
+               /* FALLTHROUGH */
+       case -ECONNRESET:               /* unlink */
+       case -ESHUTDOWN:                /* disconnect etc */
+               break;
+       case 0:
+               break;
+       }
+
+       spin_lock(&dev->lock);
+       /* Take the request struct off the active list and put it on the
+        * free list.
+        */
+       list_del_init(&req->list);
+       list_add(&req->list, &dev->tx_reqs);
+       wake_up_interruptible(&dev->tx_wait);
+       if (likely(list_empty(&dev->tx_reqs_active)))
+               wake_up_interruptible(&dev->tx_flush_wait);
+
+       spin_unlock(&dev->lock);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int
+printer_open(struct inode *inode, struct file *fd)
+{
+       struct printer_dev      *dev;
+       unsigned long           flags;
+       int                     ret = -EBUSY;
+
+       dev = container_of(inode->i_cdev, struct printer_dev, printer_cdev);
+
+       spin_lock_irqsave(&dev->lock, flags);
+
+       if (!dev->printer_cdev_open) {
+               dev->printer_cdev_open = 1;
+               fd->private_data = dev;
+               ret = 0;
+               /* Change the printer status to show that it's on-line. */
+               dev->printer_status |= PRINTER_SELECTED;
+       }
+
+       spin_unlock_irqrestore(&dev->lock, flags);
+
+       DBG(dev, "printer_open returned %x\n", ret);
+
+       return ret;
+}
+
+static int
+printer_close(struct inode *inode, struct file *fd)
+{
+       struct printer_dev      *dev = fd->private_data;
+       unsigned long           flags;
+
+       spin_lock_irqsave(&dev->lock, flags);
+       dev->printer_cdev_open = 0;
+       fd->private_data = NULL;
+       /* Change printer status to show that the printer is off-line. */
+       dev->printer_status &= ~PRINTER_SELECTED;
+       spin_unlock_irqrestore(&dev->lock, flags);
+
+       DBG(dev, "printer_close\n");
+
+       return 0;
+}
+
+static ssize_t
+printer_read(struct file *fd, char __user *buf, size_t len, loff_t *ptr)
+{
+       struct printer_dev              *dev = fd->private_data;
+       unsigned long                   flags;
+       size_t                          size;
+       size_t                          bytes_copied;
+       struct usb_request              *req;
+       /* This is a pointer to the current USB rx request. */
+       struct usb_request              *current_rx_req;
+       /* This is the number of bytes in the current rx buffer. */
+       size_t                          current_rx_bytes;
+       /* This is a pointer to the current rx buffer. */
+       u8                              *current_rx_buf;
+
+       if (len == 0)
+               return -EINVAL;
+
+       DBG(dev, "printer_read trying to read %d bytes\n", (int)len);
+
+       spin_lock(&dev->lock_printer_io);
+       spin_lock_irqsave(&dev->lock, flags);
+
+       /* We will use this flag later to check if a printer reset happened
+        * after we turn interrupts back on.
+        */
+       dev->reset_printer = 0;
+
+       while (likely(!list_empty(&dev->rx_reqs))) {
+               int error;
+
+               req = container_of(dev->rx_reqs.next,
+                               struct usb_request, list);
+               list_del_init(&req->list);
+
+               /* The USB Host sends us whatever amount of data it wants to
+                * so we always set the length field to the full USB_BUFSIZE.
+                * If the amount of data is more than the read() caller asked
+                * for it will be stored in the request buffer until it is
+                * asked for by read().
+                */
+               req->length = USB_BUFSIZE;
+               req->complete = rx_complete;
+
+               error = usb_ep_queue(dev->out_ep, req, GFP_ATOMIC);
+               if (error) {
+                       DBG(dev, "rx submit --> %d\n", error);
+                       list_add(&req->list, &dev->rx_reqs);
+                       break;
+               } else {
+                       list_add(&req->list, &dev->rx_reqs_active);
+               }
+       }
+
+       bytes_copied = 0;
+       current_rx_req = dev->current_rx_req;
+       current_rx_bytes = dev->current_rx_bytes;
+       current_rx_buf = dev->current_rx_buf;
+       dev->current_rx_req = NULL;
+       dev->current_rx_bytes = 0;
+       dev->current_rx_buf = NULL;
+
+       /* Check if there is any data in the read buffers. Please note that
+        * current_rx_bytes is the number of bytes in the current rx buffer.
+        * If it is zero then check if there are any other rx_buffers that
+        * are on the completed list. We are only out of data if all rx
+        * buffers are empty.
+        */
+       if ((current_rx_bytes == 0) &&
+                       (likely(list_empty(&dev->rx_buffers)))) {
+               /* Turn interrupts back on before sleeping. */
+               spin_unlock_irqrestore(&dev->lock, flags);
+
+               /*
+                * If no data is available check if this is a NON-Blocking
+                * call or not.
+                */
+               if (fd->f_flags & (O_NONBLOCK|O_NDELAY)) {
+                       spin_unlock(&dev->lock_printer_io);
+                       return -EAGAIN;
+               }
+
+               /* Sleep until data is available */
+               wait_event_interruptible(dev->rx_wait,
+                               (likely(!list_empty(&dev->rx_buffers))));
+               spin_lock_irqsave(&dev->lock, flags);
+       }
+
+       /* We have data to return then copy it to the caller's buffer.*/
+       while ((current_rx_bytes || likely(!list_empty(&dev->rx_buffers)))
+                       && len) {
+               if (current_rx_bytes == 0) {
+                       req = container_of(dev->rx_buffers.next,
+                                       struct usb_request, list);
+                       list_del_init(&req->list);
+
+                       if (req->actual && req->buf) {
+                               current_rx_req = req;
+                               current_rx_bytes = req->actual;
+                               current_rx_buf = req->buf;
+                       } else {
+                               list_add(&req->list, &dev->rx_reqs);
+                               continue;
+                       }
+               }
+
+               /* Don't leave irqs off while doing memory copies */
+               spin_unlock_irqrestore(&dev->lock, flags);
+
+               if (len > current_rx_bytes)
+                       size = current_rx_bytes;
+               else
+                       size = len;
+
+               size -= copy_to_user(buf, current_rx_buf, size);
+               bytes_copied += size;
+               len -= size;
+               buf += size;
+
+               spin_lock_irqsave(&dev->lock, flags);
+
+               /* We've disconnected or reset free the req and buffer */
+               if (dev->reset_printer) {
+                       printer_req_free(dev->out_ep, current_rx_req);
+                       spin_unlock_irqrestore(&dev->lock, flags);
+                       spin_unlock(&dev->lock_printer_io);
+                       return -EAGAIN;
+               }
+
+               /* If we not returning all the data left in this RX request
+                * buffer then adjust the amount of data left in the buffer.
+                * Othewise if we are done with this RX request buffer then
+                * requeue it to get any incoming data from the USB host.
+                */
+               if (size < current_rx_bytes) {
+                       current_rx_bytes -= size;
+                       current_rx_buf += size;
+               } else {
+                       list_add(&current_rx_req->list, &dev->rx_reqs);
+                       current_rx_bytes = 0;
+                       current_rx_buf = NULL;
+                       current_rx_req = NULL;
+               }
+       }
+
+       dev->current_rx_req = current_rx_req;
+       dev->current_rx_bytes = current_rx_bytes;
+       dev->current_rx_buf = current_rx_buf;
+
+       spin_unlock_irqrestore(&dev->lock, flags);
+       spin_unlock(&dev->lock_printer_io);
+
+       DBG(dev, "printer_read returned %d bytes\n", (int)bytes_copied);
+
+       if (bytes_copied)
+               return bytes_copied;
+       else
+               return -EAGAIN;
+}
+
+static ssize_t
+printer_write(struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
+{
+       struct printer_dev      *dev = fd->private_data;
+       unsigned long           flags;
+       size_t                  size;   /* Amount of data in a TX request. */
+       size_t                  bytes_copied = 0;
+       struct usb_request      *req;
+
+       DBG(dev, "printer_write trying to send %d bytes\n", (int)len);
+
+       if (len == 0)
+               return -EINVAL;
+
+       spin_lock(&dev->lock_printer_io);
+       spin_lock_irqsave(&dev->lock, flags);
+
+       /* Check if a printer reset happens while we have interrupts on */
+       dev->reset_printer = 0;
+
+       /* Check if there is any available write buffers */
+       if (likely(list_empty(&dev->tx_reqs))) {
+               /* Turn interrupts back on before sleeping. */
+               spin_unlock_irqrestore(&dev->lock, flags);
+
+               /*
+                * If write buffers are available check if this is
+                * a NON-Blocking call or not.
+                */
+               if (fd->f_flags & (O_NONBLOCK|O_NDELAY)) {
+                       spin_unlock(&dev->lock_printer_io);
+                       return -EAGAIN;
+               }
+
+               /* Sleep until a write buffer is available */
+               wait_event_interruptible(dev->tx_wait,
+                               (likely(!list_empty(&dev->tx_reqs))));
+               spin_lock_irqsave(&dev->lock, flags);
+       }
+
+       while (likely(!list_empty(&dev->tx_reqs)) && len) {
+
+               if (len > USB_BUFSIZE)
+                       size = USB_BUFSIZE;
+               else
+                       size = len;
+
+               req = container_of(dev->tx_reqs.next, struct usb_request,
+                               list);
+               list_del_init(&req->list);
+
+               req->complete = tx_complete;
+               req->length = size;
+
+               /* Check if we need to send a zero length packet. */
+               if (len > size)
+                       /* They will be more TX requests so no yet. */
+                       req->zero = 0;
+               else
+                       /* If the data amount is not a multple of the
+                        * maxpacket size then send a zero length packet.
+                        */
+                       req->zero = ((len % dev->in_ep->maxpacket) == 0);
+
+               /* Don't leave irqs off while doing memory copies */
+               spin_unlock_irqrestore(&dev->lock, flags);
+
+               if (copy_from_user(req->buf, buf, size)) {
+                       list_add(&req->list, &dev->tx_reqs);
+                       spin_unlock(&dev->lock_printer_io);
+                       return bytes_copied;
+               }
+
+               bytes_copied += size;
+               len -= size;
+               buf += size;
+
+               spin_lock_irqsave(&dev->lock, flags);
+
+               /* We've disconnected or reset so free the req and buffer */
+               if (dev->reset_printer) {
+                       printer_req_free(dev->in_ep, req);
+                       spin_unlock_irqrestore(&dev->lock, flags);
+                       spin_unlock(&dev->lock_printer_io);
+                       return -EAGAIN;
+               }
+
+               if (usb_ep_queue(dev->in_ep, req, GFP_ATOMIC)) {
+                       list_add(&req->list, &dev->tx_reqs);
+                       spin_unlock_irqrestore(&dev->lock, flags);
+                       spin_unlock(&dev->lock_printer_io);
+                       return -EAGAIN;
+               }
+
+               list_add(&req->list, &dev->tx_reqs_active);
+
+       }
+
+       spin_unlock_irqrestore(&dev->lock, flags);
+       spin_unlock(&dev->lock_printer_io);
+
+       DBG(dev, "printer_write sent %d bytes\n", (int)bytes_copied);
+
+       if (bytes_copied) {
+               return bytes_copied;
+       } else {
+               return -EAGAIN;
+       }
+}
+
+static int
+printer_fsync(struct file *fd, struct dentry *dentry, int datasync)
+{
+       struct printer_dev      *dev = fd->private_data;
+       unsigned long           flags;
+       int                     tx_list_empty;
+
+       spin_lock_irqsave(&dev->lock, flags);
+       tx_list_empty = (likely(list_empty(&dev->tx_reqs)));
+       spin_unlock_irqrestore(&dev->lock, flags);
+
+       if (!tx_list_empty) {
+               /* Sleep until all data has been sent */
+               wait_event_interruptible(dev->tx_flush_wait,
+                               (likely(list_empty(&dev->tx_reqs_active))));
+       }
+
+       return 0;
+}
+
+static unsigned int
+printer_poll(struct file *fd, poll_table *wait)
+{
+       struct printer_dev      *dev = fd->private_data;
+       unsigned long           flags;
+       int                     status = 0;
+
+       poll_wait(fd, &dev->rx_wait, wait);
+       poll_wait(fd, &dev->tx_wait, wait);
+
+       spin_lock_irqsave(&dev->lock, flags);
+       if (likely(!list_empty(&dev->tx_reqs)))
+               status |= POLLOUT | POLLWRNORM;
+
+       if (likely(!list_empty(&dev->rx_buffers)))
+               status |= POLLIN | POLLRDNORM;
+
+       spin_unlock_irqrestore(&dev->lock, flags);
+
+       return status;
+}
+
+static int
+printer_ioctl(struct inode *inode, struct file *fd, unsigned int code,
+               unsigned long arg)
+{
+       struct printer_dev      *dev = fd->private_data;
+       unsigned long           flags;
+       int                     status = 0;
+
+       DBG(dev, "printer_ioctl: cmd=0x%4.4x, arg=%lu\n", code, arg);
+
+       /* handle ioctls */
+
+       spin_lock_irqsave(&dev->lock, flags);
+
+       switch (code) {
+       case GADGET_GET_PRINTER_STATUS:
+               status = (int)dev->printer_status;
+               break;
+       case GADGET_SET_PRINTER_STATUS:
+               dev->printer_status = (u8)arg;
+               break;
+       default:
+               /* could not handle ioctl */
+               DBG(dev, "printer_ioctl: ERROR cmd=0x%4.4xis not supported\n",
+                               code);
+               status = -ENOTTY;
+       }
+
+       spin_unlock_irqrestore(&dev->lock, flags);
+
+       return status;
+}
+
+/* used after endpoint configuration */
+static struct file_operations printer_io_operations = {
+       .owner =        THIS_MODULE,
+       .open =         printer_open,
+       .read =         printer_read,
+       .write =        printer_write,
+       .fsync =        printer_fsync,
+       .poll =         printer_poll,
+       .ioctl =        printer_ioctl,
+       .release =      printer_close
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int
+set_printer_interface(struct printer_dev *dev)
+{
+       int                     result = 0;
+
+       dev->in = ep_desc(dev->gadget, &hs_ep_in_desc, &fs_ep_in_desc);
+       dev->in_ep->driver_data = dev;
+
+       dev->out = ep_desc(dev->gadget, &hs_ep_out_desc, &fs_ep_out_desc);
+       dev->out_ep->driver_data = dev;
+
+       result = usb_ep_enable(dev->in_ep, dev->in);
+       if (result != 0) {
+               DBG(dev, "enable %s --> %d\n", dev->in_ep->name, result);
+               goto done;
+       }
+
+       result = usb_ep_enable(dev->out_ep, dev->out);
+       if (result != 0) {
+               DBG(dev, "enable %s --> %d\n", dev->in_ep->name, result);
+               goto done;
+       }
+
+done:
+       /* on error, disable any endpoints  */
+       if (result != 0) {
+               (void) usb_ep_disable(dev->in_ep);
+               (void) usb_ep_disable(dev->out_ep);
+               dev->in = NULL;
+               dev->out = NULL;
+       }
+
+       /* caller is responsible for cleanup on error */
+       return result;
+}
+
+static void printer_reset_interface(struct printer_dev *dev)
+{
+       if (dev->interface < 0)
+               return;
+
+       DBG(dev, "%s\n", __FUNCTION__);
+
+       if (dev->in)
+               usb_ep_disable(dev->in_ep);
+
+       if (dev->out)
+               usb_ep_disable(dev->out_ep);
+
+       dev->interface = -1;
+}
+
+/* change our operational config.  must agree with the code
+ * that returns config descriptors, and altsetting code.
+ */
+static int
+printer_set_config(struct printer_dev *dev, unsigned number)
+{
+       int                     result = 0;
+       struct usb_gadget       *gadget = dev->gadget;
+
+       if (gadget_is_sa1100(gadget) && dev->config) {
+               /* tx fifo is full, but we can't clear it...*/
+               INFO(dev, "can't change configurations\n");
+               return -ESPIPE;
+       }
+
+       switch (number) {
+       case DEV_CONFIG_VALUE:
+               result = 0;
+               break;
+       default:
+               result = -EINVAL;
+               /* FALL THROUGH */
+       case 0:
+               break;
+       }
+
+       if (result) {
+               usb_gadget_vbus_draw(dev->gadget,
+                               dev->gadget->is_otg ? 8 : 100);
+       } else {
+               char *speed;
+               unsigned power;
+
+               power = 2 * config_desc.bMaxPower;
+               usb_gadget_vbus_draw(dev->gadget, power);
+
+               switch (gadget->speed) {
+               case USB_SPEED_FULL:    speed = "full"; break;
+#ifdef CONFIG_USB_GADGET_DUALSPEED
+               case USB_SPEED_HIGH:    speed = "high"; break;
+#endif
+               default:                speed = "?"; break;
+               }
+
+               dev->config = number;
+               INFO(dev, "%s speed config #%d: %d mA, %s\n",
+                               speed, number, power, driver_desc);
+       }
+       return result;
+}
+
+static int
+config_buf(enum usb_device_speed speed, u8 *buf, u8 type, unsigned index,
+               int is_otg)
+{
+       int                                     len;
+       const struct usb_descriptor_header      **function;
+#ifdef CONFIG_USB_GADGET_DUALSPEED
+       int                                     hs = (speed == USB_SPEED_HIGH);
+
+       if (type == USB_DT_OTHER_SPEED_CONFIG)
+               hs = !hs;
+
+       if (hs) {
+               function = hs_printer_function;
+       } else {
+               function = fs_printer_function;
+       }
+#else
+       function = fs_printer_function;
+#endif
+
+       if (index >= device_desc.bNumConfigurations)
+               return -EINVAL;
+
+       /* for now, don't advertise srp-only devices */
+       if (!is_otg)
+               function++;
+
+       len = usb_gadget_config_buf(&config_desc, buf, USB_DESC_BUFSIZE,
+                       function);
+       if (len < 0)
+               return len;
+       ((struct usb_config_descriptor *) buf)->bDescriptorType = type;
+       return len;
+}
+
+/* Change our operational Interface. */
+static int
+set_interface(struct printer_dev *dev, unsigned number)
+{
+       int                     result = 0;
+
+       if (gadget_is_sa1100(dev->gadget) && dev->interface < 0) {
+               /* tx fifo is full, but we can't clear it...*/
+               INFO(dev, "can't change interfaces\n");
+               return -ESPIPE;
+       }
+
+       /* Free the current interface */
+       switch (dev->interface) {
+       case PRINTER_INTERFACE:
+               printer_reset_interface(dev);
+               break;
+       }
+
+       switch (number) {
+       case PRINTER_INTERFACE:
+               result = set_printer_interface(dev);
+               if (result) {
+                       printer_reset_interface(dev);
+               } else {
+                       dev->interface = PRINTER_INTERFACE;
+               }
+               break;
+       default:
+               result = -EINVAL;
+               /* FALL THROUGH */
+       }
+
+       if (!result)
+               INFO(dev, "Using interface %x\n", number);
+
+       return result;
+}
+
+static void printer_setup_complete(struct usb_ep *ep, struct usb_request *req)
+{
+       if (req->status || req->actual != req->length)
+               DBG((struct printer_dev *) ep->driver_data,
+                               "setup complete --> %d, %d/%d\n",
+                               req->status, req->actual, req->length);
+}
+
+static void printer_soft_reset(struct printer_dev *dev)
+{
+       struct usb_request      *req;
+
+       INFO(dev, "Received Printer Reset Request\n");
+
+       if (usb_ep_disable(dev->in_ep))
+               DBG(dev, "Failed to disable USB in_ep\n");
+       if (usb_ep_disable(dev->out_ep))
+               DBG(dev, "Failed to disable USB out_ep\n");
+
+       if (dev->current_rx_req != NULL) {
+               list_add(&dev->current_rx_req->list, &dev->rx_reqs);
+               dev->current_rx_req = NULL;
+       }
+       dev->current_rx_bytes = 0;
+       dev->current_rx_buf = NULL;
+       dev->reset_printer = 1;
+
+       while (likely(!(list_empty(&dev->rx_buffers)))) {
+               req = container_of(dev->rx_buffers.next, struct usb_request,
+                               list);
+               list_del_init(&req->list);
+               list_add(&req->list, &dev->rx_reqs);
+       }
+
+       while (likely(!(list_empty(&dev->rx_reqs_active)))) {
+               req = container_of(dev->rx_buffers.next, struct usb_request,
+                               list);
+               list_del_init(&req->list);
+               list_add(&req->list, &dev->rx_reqs);
+       }
+
+       while (likely(!(list_empty(&dev->tx_reqs_active)))) {
+               req = container_of(dev->tx_reqs_active.next,
+                               struct usb_request, list);
+               list_del_init(&req->list);
+               list_add(&req->list, &dev->tx_reqs);
+       }
+
+       if (usb_ep_enable(dev->in_ep, dev->in))
+               DBG(dev, "Failed to enable USB in_ep\n");
+       if (usb_ep_enable(dev->out_ep, dev->out))
+               DBG(dev, "Failed to enable USB out_ep\n");
+
+       wake_up_interruptible(&dev->tx_wait);
+       wake_up_interruptible(&dev->tx_flush_wait);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * The setup() callback implements all the ep0 functionality that's not
+ * handled lower down.
+ */
+static int
+printer_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
+{
+       struct printer_dev      *dev = get_gadget_data(gadget);
+       struct usb_request      *req = dev->req;
+       int                     value = -EOPNOTSUPP;
+       u16                     wIndex = le16_to_cpu(ctrl->wIndex);
+       u16                     wValue = le16_to_cpu(ctrl->wValue);
+       u16                     wLength = le16_to_cpu(ctrl->wLength);
+
+       DBG(dev, "ctrl req%02x.%02x v%04x i%04x l%d\n",
+               ctrl->bRequestType, ctrl->bRequest, wValue, wIndex, wLength);
+
+       req->complete = printer_setup_complete;
+
+       switch (ctrl->bRequestType&USB_TYPE_MASK) {
+
+       case USB_TYPE_STANDARD:
+               switch (ctrl->bRequest) {
+
+               case USB_REQ_GET_DESCRIPTOR:
+                       if (ctrl->bRequestType != USB_DIR_IN)
+                               break;
+                       switch (wValue >> 8) {
+
+                       case USB_DT_DEVICE:
+                               value = min(wLength, (u16) sizeof device_desc);
+                               memcpy(req->buf, &device_desc, value);
+                               break;
+#ifdef CONFIG_USB_GADGET_DUALSPEED
+                       case USB_DT_DEVICE_QUALIFIER:
+                               if (!gadget->is_dualspeed)
+                                       break;
+                               value = min(wLength,
+                                               (u16) sizeof dev_qualifier);
+                               memcpy(req->buf, &dev_qualifier, value);
+                               break;
+
+                       case USB_DT_OTHER_SPEED_CONFIG:
+                               if (!gadget->is_dualspeed)
+                                       break;
+                               /* FALLTHROUGH */
+#endif /* CONFIG_USB_GADGET_DUALSPEED */
+                       case USB_DT_CONFIG:
+                               value = config_buf(gadget->speed, req->buf,
+                                               wValue >> 8,
+                                               wValue & 0xff,
+                                               gadget->is_otg);
+                               if (value >= 0)
+                                       value = min(wLength, (u16) value);
+                               break;
+
+                       case USB_DT_STRING:
+                               value = usb_gadget_get_string(&stringtab,
+                                               wValue & 0xff, req->buf);
+                               if (value >= 0)
+                                       value = min(wLength, (u16) value);
+                               break;
+                       }
+                       break;
+
+               case USB_REQ_SET_CONFIGURATION:
+                       if (ctrl->bRequestType != 0)
+                               break;
+                       if (gadget->a_hnp_support)
+                               DBG(dev, "HNP available\n");
+                       else if (gadget->a_alt_hnp_support)
+                               DBG(dev, "HNP needs a different root port\n");
+                       value = printer_set_config(dev, wValue);
+                       break;
+               case USB_REQ_GET_CONFIGURATION:
+                       if (ctrl->bRequestType != USB_DIR_IN)
+                               break;
+                       *(u8 *)req->buf = dev->config;
+                       value = min(wLength, (u16) 1);
+                       break;
+
+               case USB_REQ_SET_INTERFACE:
+                       if (ctrl->bRequestType != USB_RECIP_INTERFACE ||
+                                       !dev->config)
+                               break;
+
+                       value = set_interface(dev, PRINTER_INTERFACE);
+                       break;
+               case USB_REQ_GET_INTERFACE:
+                       if (ctrl->bRequestType !=
+                                       (USB_DIR_IN|USB_RECIP_INTERFACE)
+                                       || !dev->config)
+                               break;
+
+                       *(u8 *)req->buf = dev->interface;
+                       value = min(wLength, (u16) 1);
+                       break;
+
+               default:
+                       goto unknown;
+               }
+               break;
+
+       case USB_TYPE_CLASS:
+               switch (ctrl->bRequest) {
+               case 0: /* Get the IEEE-1284 PNP String */
+                       /* Only one printer interface is supported. */
+                       if ((wIndex>>8) != PRINTER_INTERFACE)
+                               break;
+
+                       value = (pnp_string[0]<<8)|pnp_string[1];
+                       memcpy(req->buf, pnp_string, value);
+                       DBG(dev, "1284 PNP String: %x %s\n", value,
+                                       &pnp_string[2]);
+                       break;
+
+               case 1: /* Get Port Status */
+                       /* Only one printer interface is supported. */
+                       if (wIndex != PRINTER_INTERFACE)
+                               break;
+
+                       *(u8 *)req->buf = dev->printer_status;
+                       value = min(wLength, (u16) 1);
+                       break;
+
+               case 2: /* Soft Reset */
+                       /* Only one printer interface is supported. */
+                       if (wIndex != PRINTER_INTERFACE)
+                               break;
+
+                       printer_soft_reset(dev);
+
+                       value = 0;
+                       break;
+
+               default:
+                       goto unknown;
+               }
+               break;
+
+       default:
+unknown:
+               VDBG(dev,
+                       "unknown ctrl req%02x.%02x v%04x i%04x l%d\n",
+                       ctrl->bRequestType, ctrl->bRequest,
+                       wValue, wIndex, wLength);
+               break;
+       }
+
+       /* respond with data transfer before status phase? */
+       if (value >= 0) {
+               req->length = value;
+               req->zero = value < wLength
+                               && (value % gadget->ep0->maxpacket) == 0;
+               value = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC);
+               if (value < 0) {
+                       DBG(dev, "ep_queue --> %d\n", value);
+                       req->status = 0;
+                       printer_setup_complete(gadget->ep0, req);
+               }
+       }
+
+       /* host either stalls (value < 0) or reports success */
+       return value;
+}
+
+static void
+printer_disconnect(struct usb_gadget *gadget)
+{
+       struct printer_dev      *dev = get_gadget_data(gadget);
+       unsigned long           flags;
+
+       DBG(dev, "%s\n", __FUNCTION__);
+
+       spin_lock_irqsave(&dev->lock, flags);
+
+       printer_reset_interface(dev);
+
+       spin_unlock_irqrestore(&dev->lock, flags);
+}
+
+static void
+printer_unbind(struct usb_gadget *gadget)
+{
+       struct printer_dev      *dev = get_gadget_data(gadget);
+       struct usb_request      *req;
+
+
+       DBG(dev, "%s\n", __FUNCTION__);
+
+       /* Remove sysfs files */
+       device_destroy(usb_gadget_class, g_printer_devno);
+
+       /* Remove Character Device */
+       cdev_del(&dev->printer_cdev);
+
+       /* we must already have been disconnected ... no i/o may be active */
+       WARN_ON(!list_empty(&dev->tx_reqs_active));
+       WARN_ON(!list_empty(&dev->rx_reqs_active));
+
+       /* Free all memory for this driver. */
+       while (!list_empty(&dev->tx_reqs)) {
+               req = container_of(dev->tx_reqs.next, struct usb_request,
+                               list);
+               list_del(&req->list);
+               printer_req_free(dev->in_ep, req);
+       }
+
+       if (dev->current_rx_req != NULL);
+               printer_req_free(dev->out_ep, dev->current_rx_req);
+
+       while (!list_empty(&dev->rx_reqs)) {
+               req = container_of(dev->rx_reqs.next,
+                               struct usb_request, list);
+               list_del(&req->list);
+               printer_req_free(dev->out_ep, req);
+       }
+
+       while (!list_empty(&dev->rx_buffers)) {
+               req = container_of(dev->rx_buffers.next,
+                               struct usb_request, list);
+               list_del(&req->list);
+               printer_req_free(dev->out_ep, req);
+       }
+
+       if (dev->req) {
+               printer_req_free(gadget->ep0, dev->req);
+               dev->req = NULL;
+       }
+
+       set_gadget_data(gadget, NULL);
+}
+
+static int __init
+printer_bind(struct usb_gadget *gadget)
+{
+       struct printer_dev      *dev;
+       struct usb_ep           *in_ep, *out_ep;
+       int                     status = -ENOMEM;
+       int                     gcnum;
+       size_t                  len;
+       u32                     i;
+       struct usb_request      *req;
+
+       dev = &usb_printer_gadget;
+
+
+       /* Setup the sysfs files for the printer gadget. */
+       dev->pdev = device_create(usb_gadget_class, NULL, g_printer_devno,
+                       "g_printer");
+       if (IS_ERR(dev->pdev)) {
+               ERROR(dev, "Failed to create device: g_printer\n");
+               goto fail;
+       }
+
+       /*
+        * Register a character device as an interface to a user mode
+        * program that handles the printer specific functionality.
+        */
+       cdev_init(&dev->printer_cdev, &printer_io_operations);
+       dev->printer_cdev.owner = THIS_MODULE;
+       status = cdev_add(&dev->printer_cdev, g_printer_devno, 1);
+       if (status) {
+               ERROR(dev, "Failed to open char device\n");
+               goto fail;
+       }
+
+       if (gadget_is_sa1100(gadget)) {
+               /* hardware can't write zero length packets. */
+               ERROR(dev, "SA1100 controller is unsupport by this driver\n");
+               goto fail;
+       }
+
+       gcnum = usb_gadget_controller_number(gadget);
+       if (gcnum >= 0) {
+               device_desc.bcdDevice = cpu_to_le16(0x0200 + gcnum);
+       } else {
+               dev_warn(&gadget->dev, "controller '%s' not recognized\n",
+                       gadget->name);
+               /* unrecognized, but safe unless bulk is REALLY quirky */
+               device_desc.bcdDevice =
+                       __constant_cpu_to_le16(0xFFFF);
+       }
+       snprintf(manufacturer, sizeof(manufacturer), "%s %s with %s",
+               init_utsname()->sysname, init_utsname()->release,
+               gadget->name);
+
+       device_desc.idVendor =
+               __constant_cpu_to_le16(PRINTER_VENDOR_NUM);
+       device_desc.idProduct =
+               __constant_cpu_to_le16(PRINTER_PRODUCT_NUM);
+
+       /* support optional vendor/distro customization */
+       if (idVendor) {
+               if (!idProduct) {
+                       dev_err(&gadget->dev, "idVendor needs idProduct!\n");
+                       return -ENODEV;
+               }
+               device_desc.idVendor = cpu_to_le16(idVendor);
+               device_desc.idProduct = cpu_to_le16(idProduct);
+               if (bcdDevice)
+                       device_desc.bcdDevice = cpu_to_le16(bcdDevice);
+       }
+
+       if (iManufacturer)
+               strlcpy(manufacturer, iManufacturer, sizeof manufacturer);
+
+       if (iProduct)
+               strlcpy(product_desc, iProduct, sizeof product_desc);
+
+       if (iSerialNum)
+               strlcpy(serial_num, iSerialNum, sizeof serial_num);
+
+       if (iPNPstring)
+               strlcpy(&pnp_string[2], iPNPstring, (sizeof pnp_string)-2);
+
+       len = strlen(pnp_string);
+       pnp_string[0] = (len >> 8) & 0xFF;
+       pnp_string[1] = len & 0xFF;
+
+       /* all we really need is bulk IN/OUT */
+       usb_ep_autoconfig_reset(gadget);
+       in_ep = usb_ep_autoconfig(gadget, &fs_ep_in_desc);
+       if (!in_ep) {
+autoconf_fail:
+               dev_err(&gadget->dev, "can't autoconfigure on %s\n",
+                       gadget->name);
+               return -ENODEV;
+       }
+       in_ep->driver_data = in_ep;     /* claim */
+
+       out_ep = usb_ep_autoconfig(gadget, &fs_ep_out_desc);
+       if (!out_ep)
+               goto autoconf_fail;
+       out_ep->driver_data = out_ep;   /* claim */
+
+#ifdef CONFIG_USB_GADGET_DUALSPEED
+       /* assumes ep0 uses the same value for both speeds ... */
+       dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0;
+
+       /* and that all endpoints are dual-speed */
+       hs_ep_in_desc.bEndpointAddress = fs_ep_in_desc.bEndpointAddress;
+       hs_ep_out_desc.bEndpointAddress = fs_ep_out_desc.bEndpointAddress;
+#endif /* DUALSPEED */
+
+       device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
+       usb_gadget_set_selfpowered(gadget);
+
+       if (gadget->is_otg) {
+               otg_desc.bmAttributes |= USB_OTG_HNP,
+               config_desc.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+               config_desc.bMaxPower = 4;
+       }
+
+       spin_lock_init(&dev->lock);
+       spin_lock_init(&dev->lock_printer_io);
+       INIT_LIST_HEAD(&dev->tx_reqs);
+       INIT_LIST_HEAD(&dev->tx_reqs_active);
+       INIT_LIST_HEAD(&dev->rx_reqs);
+       INIT_LIST_HEAD(&dev->rx_reqs_active);
+       INIT_LIST_HEAD(&dev->rx_buffers);
+       init_waitqueue_head(&dev->rx_wait);
+       init_waitqueue_head(&dev->tx_wait);
+       init_waitqueue_head(&dev->tx_flush_wait);
+
+       dev->config = 0;
+       dev->interface = -1;
+       dev->printer_cdev_open = 0;
+       dev->printer_status = PRINTER_NOT_ERROR;
+       dev->current_rx_req = NULL;
+       dev->current_rx_bytes = 0;
+       dev->current_rx_buf = NULL;
+
+       dev->in_ep = in_ep;
+       dev->out_ep = out_ep;
+
+       /* preallocate control message data and buffer */
+       dev->req = printer_req_alloc(gadget->ep0, USB_DESC_BUFSIZE,
+                       GFP_KERNEL);
+       if (!dev->req) {
+               status = -ENOMEM;
+               goto fail;
+       }
+
+       for (i = 0; i < QLEN; i++) {
+               req = printer_req_alloc(dev->in_ep, USB_BUFSIZE, GFP_KERNEL);
+               if (!req) {
+                       while (!list_empty(&dev->tx_reqs)) {
+                               req = container_of(dev->tx_reqs.next,
+                                               struct usb_request, list);
+                               list_del(&req->list);
+                               printer_req_free(dev->in_ep, req);
+                       }
+                       return -ENOMEM;
+               }
+               list_add(&req->list, &dev->tx_reqs);
+       }
+
+       for (i = 0; i < QLEN; i++) {
+               req = printer_req_alloc(dev->out_ep, USB_BUFSIZE, GFP_KERNEL);
+               if (!req) {
+                       while (!list_empty(&dev->rx_reqs)) {
+                               req = container_of(dev->rx_reqs.next,
+                                               struct usb_request, list);
+                               list_del(&req->list);
+                               printer_req_free(dev->out_ep, req);
+                       }
+                       return -ENOMEM;
+               }
+               list_add(&req->list, &dev->rx_reqs);
+       }
+
+       dev->req->complete = printer_setup_complete;
+
+       /* finish hookup to lower layer ... */
+       dev->gadget = gadget;
+       set_gadget_data(gadget, dev);
+       gadget->ep0->driver_data = dev;
+
+       INFO(dev, "%s, version: " DRIVER_VERSION "\n", driver_desc);
+       INFO(dev, "using %s, OUT %s IN %s\n", gadget->name, out_ep->name,
+                       in_ep->name);
+
+       return 0;
+
+fail:
+       printer_unbind(gadget);
+       return status;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static struct usb_gadget_driver printer_driver = {
+       .speed          = DEVSPEED,
+
+       .function       = (char *) driver_desc,
+       .bind           = printer_bind,
+       .unbind         = printer_unbind,
+
+       .setup          = printer_setup,
+       .disconnect     = printer_disconnect,
+
+       .driver         = {
+               .name           = (char *) shortname,
+               .owner          = THIS_MODULE,
+       },
+};
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_AUTHOR("Craig Nadler");
+MODULE_LICENSE("GPL");
+
+static int __init
+init(void)
+{
+       int status;
+
+       usb_gadget_class = class_create(THIS_MODULE, "usb_printer_gadget");
+       if (IS_ERR(usb_gadget_class)) {
+               status = PTR_ERR(usb_gadget_class);
+               ERROR(dev, "unable to create usb_gadget class %d\n", status);
+               return status;
+       }
+
+       status = alloc_chrdev_region(&g_printer_devno, 0, 1,
+                       "USB printer gadget");
+       if (status) {
+               ERROR(dev, "alloc_chrdev_region %d\n", status);
+               class_destroy(usb_gadget_class);
+               return status;
+       }
+
+       status = usb_gadget_register_driver(&printer_driver);
+       if (status) {
+               class_destroy(usb_gadget_class);
+               unregister_chrdev_region(g_printer_devno, 1);
+               DBG(dev, "usb_gadget_register_driver %x\n", status);
+       }
+
+       return status;
+}
+module_init(init);
+
+static void __exit
+cleanup(void)
+{
+       int status;
+
+       spin_lock(&usb_printer_gadget.lock_printer_io);
+       class_destroy(usb_gadget_class);
+       unregister_chrdev_region(g_printer_devno, 2);
+
+       status = usb_gadget_unregister_driver(&printer_driver);
+       if (status)
+               ERROR(dev, "usb_gadget_unregister_driver %x\n", status);
+
+       spin_unlock(&usb_printer_gadget.lock_printer_io);
+}
+module_exit(cleanup);
index 3173b39f0bfdf52d79034b6e5214cf260d33a637..4402d6f042d971bd42d6a1453bb3c0bef85172ee 100644 (file)
@@ -24,7 +24,7 @@
  *
  */
 
-// #define     VERBOSE DBG_VERBOSE
+/* #define VERBOSE_DEBUG */
 
 #include <linux/device.h>
 #include <linux/module.h>
 #include <linux/timer.h>
 #include <linux/list.h>
 #include <linux/interrupt.h>
-#include <linux/proc_fs.h>
 #include <linux/mm.h>
 #include <linux/platform_device.h>
 #include <linux/dma-mapping.h>
 #include <linux/irq.h>
 #include <linux/clk.h>
 #include <linux/err.h>
+#include <linux/seq_file.h>
+#include <linux/debugfs.h>
 
 #include <asm/byteorder.h>
 #include <asm/dma.h>
@@ -127,8 +128,10 @@ static int is_vbus_present(void)
 {
        struct pxa2xx_udc_mach_info             *mach = the_controller->mach;
 
-       if (mach->gpio_vbus)
-               return gpio_get_value(mach->gpio_vbus);
+       if (mach->gpio_vbus) {
+               int value = gpio_get_value(mach->gpio_vbus);
+               return mach->gpio_vbus_inverted ? !value : value;
+       }
        if (mach->udc_is_connected)
                return mach->udc_is_connected();
        return 1;
@@ -677,7 +680,7 @@ pxa2xx_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
 
        /* kickstart this i/o queue? */
        if (list_empty(&ep->queue) && !ep->stopped) {
-               if (ep->desc == /* ep0 */) {
+               if (ep->desc == NULL/* ep0 */) {
                        unsigned        length = _req->length;
 
                        switch (dev->ep0state) {
@@ -731,7 +734,7 @@ pxa2xx_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
        }
 
        /* pio or dma irq handler advances the queue. */
-       if (likely (req != 0))
+       if (likely(req != NULL))
                list_add_tail(&req->queue, &ep->queue);
        local_irq_restore(flags);
 
@@ -991,45 +994,32 @@ static const struct usb_gadget_ops pxa2xx_udc_ops = {
 
 /*-------------------------------------------------------------------------*/
 
-#ifdef CONFIG_USB_GADGET_DEBUG_FILES
-
-static const char proc_node_name [] = "driver/udc";
+#ifdef CONFIG_USB_GADGET_DEBUG_FS
 
 static int
-udc_proc_read(char *page, char **start, off_t off, int count,
-               int *eof, void *_dev)
+udc_seq_show(struct seq_file *m, void *d)
 {
-       char                    *buf = page;
-       struct pxa2xx_udc       *dev = _dev;
-       char                    *next = buf;
-       unsigned                size = count;
+       struct pxa2xx_udc       *dev = m->private;
        unsigned long           flags;
-       int                     i, t;
+       int                     i;
        u32                     tmp;
 
-       if (off != 0)
-               return 0;
-
        local_irq_save(flags);
 
        /* basic device status */
-       t = scnprintf(next, size, DRIVER_DESC "\n"
+       seq_printf(m, DRIVER_DESC "\n"
                "%s version: %s\nGadget driver: %s\nHost %s\n\n",
                driver_name, DRIVER_VERSION SIZE_STR "(pio)",
                dev->driver ? dev->driver->driver.name : "(none)",
                is_vbus_present() ? "full speed" : "disconnected");
-       size -= t;
-       next += t;
 
        /* registers for device and ep0 */
-       t = scnprintf(next, size,
+       seq_printf(m,
                "uicr %02X.%02X, usir %02X.%02x, ufnr %02X.%02X\n",
                UICR1, UICR0, USIR1, USIR0, UFNRH, UFNRL);
-       size -= t;
-       next += t;
 
        tmp = UDCCR;
-       t = scnprintf(next, size,
+       seq_printf(m,
                "udccr %02X =%s%s%s%s%s%s%s%s\n", tmp,
                (tmp & UDCCR_REM) ? " rem" : "",
                (tmp & UDCCR_RSTIR) ? " rstir" : "",
@@ -1039,11 +1029,9 @@ udc_proc_read(char *page, char **start, off_t off, int count,
                (tmp & UDCCR_RSM) ? " rsm" : "",
                (tmp & UDCCR_UDA) ? " uda" : "",
                (tmp & UDCCR_UDE) ? " ude" : "");
-       size -= t;
-       next += t;
 
        tmp = UDCCS0;
-       t = scnprintf(next, size,
+       seq_printf(m,
                "udccs0 %02X =%s%s%s%s%s%s%s%s\n", tmp,
                (tmp & UDCCS0_SA) ? " sa" : "",
                (tmp & UDCCS0_RNE) ? " rne" : "",
@@ -1053,28 +1041,22 @@ udc_proc_read(char *page, char **start, off_t off, int count,
                (tmp & UDCCS0_FTF) ? " ftf" : "",
                (tmp & UDCCS0_IPR) ? " ipr" : "",
                (tmp & UDCCS0_OPR) ? " opr" : "");
-       size -= t;
-       next += t;
 
        if (dev->has_cfr) {
                tmp = UDCCFR;
-               t = scnprintf(next, size,
+               seq_printf(m,
                        "udccfr %02X =%s%s\n", tmp,
                        (tmp & UDCCFR_AREN) ? " aren" : "",
                        (tmp & UDCCFR_ACM) ? " acm" : "");
-               size -= t;
-               next += t;
        }
 
        if (!is_vbus_present() || !dev->driver)
                goto done;
 
-       t = scnprintf(next, size, "ep0 IN %lu/%lu, OUT %lu/%lu\nirqs %lu\n\n",
+       seq_printf(m, "ep0 IN %lu/%lu, OUT %lu/%lu\nirqs %lu\n\n",
                dev->stats.write.bytes, dev->stats.write.ops,
                dev->stats.read.bytes, dev->stats.read.ops,
                dev->stats.irqs);
-       size -= t;
-       next += t;
 
        /* dump endpoint queues */
        for (i = 0; i < PXA_UDC_NUM_ENDPOINTS; i++) {
@@ -1082,61 +1064,68 @@ udc_proc_read(char *page, char **start, off_t off, int count,
                struct pxa2xx_request   *req;
 
                if (i != 0) {
-                       const struct usb_endpoint_descriptor    *d;
+                       const struct usb_endpoint_descriptor    *desc;
 
-                       d = ep->desc;
-                       if (!d)
+                       desc = ep->desc;
+                       if (!desc)
                                continue;
                        tmp = *dev->ep [i].reg_udccs;
-                       t = scnprintf(next, size,
+                       seq_printf(m,
                                "%s max %d %s udccs %02x irqs %lu\n",
-                               ep->ep.name, le16_to_cpu (d->wMaxPacketSize),
+                               ep->ep.name, le16_to_cpu(desc->wMaxPacketSize),
                                "pio", tmp, ep->pio_irqs);
                        /* TODO translate all five groups of udccs bits! */
 
                } else /* ep0 should only have one transfer queued */
-                       t = scnprintf(next, size, "ep0 max 16 pio irqs %lu\n",
+                       seq_printf(m, "ep0 max 16 pio irqs %lu\n",
                                ep->pio_irqs);
-               if (t <= 0 || t > size)
-                       goto done;
-               size -= t;
-               next += t;
 
                if (list_empty(&ep->queue)) {
-                       t = scnprintf(next, size, "\t(nothing queued)\n");
-                       if (t <= 0 || t > size)
-                               goto done;
-                       size -= t;
-                       next += t;
+                       seq_printf(m, "\t(nothing queued)\n");
                        continue;
                }
                list_for_each_entry(req, &ep->queue, queue) {
-                       t = scnprintf(next, size,
+                       seq_printf(m,
                                        "\treq %p len %d/%d buf %p\n",
                                        &req->req, req->req.actual,
                                        req->req.length, req->req.buf);
-                       if (t <= 0 || t > size)
-                               goto done;
-                       size -= t;
-                       next += t;
                }
        }
 
 done:
        local_irq_restore(flags);
-       *eof = 1;
-       return count - size;
+       return 0;
 }
 
-#define create_proc_files() \
-       create_proc_read_entry(proc_node_name, 0, NULL, udc_proc_read, dev)
-#define remove_proc_files() \
-       remove_proc_entry(proc_node_name, NULL)
+static int
+udc_debugfs_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, udc_seq_show, inode->i_private);
+}
+
+static const struct file_operations debug_fops = {
+       .open           = udc_debugfs_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+       .owner          = THIS_MODULE,
+};
+
+#define create_debug_files(dev) \
+       do { \
+               dev->debugfs_udc = debugfs_create_file(dev->gadget.name, \
+                       S_IRUGO, NULL, dev, &debug_fops); \
+       } while (0)
+#define remove_debug_files(dev) \
+       do { \
+               if (dev->debugfs_udc) \
+                       debugfs_remove(dev->debugfs_udc); \
+       } while (0)
 
 #else  /* !CONFIG_USB_GADGET_DEBUG_FILES */
 
-#define create_proc_files() do {} while (0)
-#define remove_proc_files() do {} while (0)
+#define create_debug_files(dev) do {} while (0)
+#define remove_debug_files(dev) do {} while (0)
 
 #endif /* CONFIG_USB_GADGET_DEBUG_FILES */
 
@@ -1345,6 +1334,7 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
        local_irq_enable();
 
        driver->unbind(&dev->gadget);
+       dev->gadget.dev.driver = NULL;
        dev->driver = NULL;
 
        device_del (&dev->gadget.dev);
@@ -1397,6 +1387,9 @@ static irqreturn_t udc_vbus_irq(int irq, void *_dev)
        struct pxa2xx_udc       *dev = _dev;
        int                     vbus = gpio_get_value(dev->mach->gpio_vbus);
 
+       if (dev->mach->gpio_vbus_inverted)
+               vbus = !vbus;
+
        pxa2xx_udc_vbus_session(&dev->gadget, vbus);
        return IRQ_HANDLED;
 }
@@ -2099,7 +2092,7 @@ static int __init pxa2xx_udc_probe(struct platform_device *pdev)
        /* insist on Intel/ARM/XScale */
        asm("mrc%? p15, 0, %0, c0, c0" : "=r" (chiprev));
        if ((chiprev & CP15R0_VENDOR_MASK) != CP15R0_XSCALE_VALUE) {
-               printk(KERN_ERR "%s: not XScale!\n", driver_name);
+               pr_err("%s: not XScale!\n", driver_name);
                return -ENODEV;
        }
 
@@ -2128,7 +2121,7 @@ static int __init pxa2xx_udc_probe(struct platform_device *pdev)
                break;
 #endif
        default:
-               printk(KERN_ERR "%s: unrecognized processor: %08x\n",
+               pr_err("%s: unrecognized processor: %08x\n",
                        driver_name, chiprev);
                /* iop3xx, ixp4xx, ... */
                return -ENODEV;
@@ -2199,7 +2192,7 @@ static int __init pxa2xx_udc_probe(struct platform_device *pdev)
        retval = request_irq(irq, pxa2xx_udc_irq,
                        IRQF_DISABLED, driver_name, dev);
        if (retval != 0) {
-               printk(KERN_ERR "%s: can't get irq %d, err %d\n",
+               pr_err("%s: can't get irq %d, err %d\n",
                        driver_name, irq, retval);
                goto err_irq1;
        }
@@ -2212,7 +2205,7 @@ static int __init pxa2xx_udc_probe(struct platform_device *pdev)
                                IRQF_DISABLED | IRQF_SAMPLE_RANDOM,
                                driver_name, dev);
                if (retval != 0) {
-                       printk(KERN_ERR "%s: can't get irq %i, err %d\n",
+                       pr_err("%s: can't get irq %i, err %d\n",
                                driver_name, LUBBOCK_USB_DISC_IRQ, retval);
 lubbock_fail0:
                        goto err_irq_lub;
@@ -2222,7 +2215,7 @@ lubbock_fail0:
                                IRQF_DISABLED | IRQF_SAMPLE_RANDOM,
                                driver_name, dev);
                if (retval != 0) {
-                       printk(KERN_ERR "%s: can't get irq %i, err %d\n",
+                       pr_err("%s: can't get irq %i, err %d\n",
                                driver_name, LUBBOCK_USB_IRQ, retval);
                        free_irq(LUBBOCK_USB_DISC_IRQ, dev);
                        goto lubbock_fail0;
@@ -2235,12 +2228,12 @@ lubbock_fail0:
                                IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
                                driver_name, dev);
                if (retval != 0) {
-                       printk(KERN_ERR "%s: can't get irq %i, err %d\n",
+                       pr_err("%s: can't get irq %i, err %d\n",
                                driver_name, vbus_irq, retval);
                        goto err_vbus_irq;
                }
        }
-       create_proc_files();
+       create_debug_files(dev);
 
        return 0;
 
@@ -2277,7 +2270,7 @@ static int __exit pxa2xx_udc_remove(struct platform_device *pdev)
                return -EBUSY;
 
        udc_disable(dev);
-       remove_proc_files();
+       remove_debug_files(dev);
 
        if (dev->got_irq) {
                free_irq(platform_get_irq(pdev, 0), dev);
@@ -2361,7 +2354,7 @@ static struct platform_driver udc_driver = {
 
 static int __init udc_init(void)
 {
-       printk(KERN_INFO "%s: version %s\n", driver_name, DRIVER_VERSION);
+       pr_info("%s: version %s\n", driver_name, DRIVER_VERSION);
        return platform_driver_probe(&udc_driver, pxa2xx_udc_probe);
 }
 module_init(udc_init);
index 1db46d705777a39881cca5f395700e8410e84feb..b67e3ff5e4eb5baf648b0fcceb457e7e3456af69 100644 (file)
@@ -129,6 +129,10 @@ struct pxa2xx_udc {
        struct pxa2xx_udc_mach_info             *mach;
        u64                                     dma_mask;
        struct pxa2xx_ep                        ep [PXA_UDC_NUM_ENDPOINTS];
+
+#ifdef CONFIG_USB_GADGET_DEBUG_FS
+       struct dentry                           *debugfs_udc;
+#endif
 };
 
 /*-------------------------------------------------------------------------*/
@@ -151,17 +155,19 @@ static struct pxa2xx_udc *the_controller;
 #define DBG_NOISY      3       /* ... even more: request level */
 #define DBG_VERY_NOISY 4       /* ... even more: packet level */
 
+#define DMSG(stuff...) pr_debug("udc: " stuff)
+
 #ifdef DEBUG
 
+static int is_vbus_present(void);
+
 static const char *state_name[] = {
        "EP0_IDLE",
        "EP0_IN_DATA_PHASE", "EP0_OUT_DATA_PHASE",
        "EP0_END_XFER", "EP0_STALL"
 };
 
-#define DMSG(stuff...) printk(KERN_DEBUG "udc: " stuff)
-
-#ifdef VERBOSE
+#ifdef VERBOSE_DEBUG
 #    define UDC_DEBUG DBG_VERBOSE
 #else
 #    define UDC_DEBUG DBG_NORMAL
@@ -207,7 +213,7 @@ dump_state(struct pxa2xx_udc *dev)
        unsigned        i;
 
        DMSG("%s %s, uicr %02X.%02X, usir %02X.%02x, ufnr %02X.%02X\n",
-               is_usb_connected() ? "host " : "disconnected",
+               is_vbus_present() ? "host " : "disconnected",
                state_name[dev->ep0state],
                UICR1, UICR0, USIR1, USIR0, UFNRH, UFNRL);
        dump_udccr("udccr");
@@ -224,7 +230,7 @@ dump_state(struct pxa2xx_udc *dev)
        } else
                DMSG("ep0 driver '%s'\n", dev->driver->driver.name);
 
-       if (!is_usb_connected())
+       if (!is_vbus_present())
                return;
 
        dump_udccs0 ("udccs0");
@@ -233,7 +239,7 @@ dump_state(struct pxa2xx_udc *dev)
                dev->stats.read.bytes, dev->stats.read.ops);
 
        for (i = 1; i < PXA_UDC_NUM_ENDPOINTS; i++) {
-               if (dev->ep [i].desc == 0)
+               if (dev->ep [i].desc == NULL)
                        continue;
                DMSG ("udccs%d = %02x\n", i, *dev->ep->reg_udccs);
        }
@@ -241,8 +247,6 @@ dump_state(struct pxa2xx_udc *dev)
 
 #else
 
-#define DMSG(stuff...)         do{}while(0)
-
 #define        dump_udccr(x)   do{}while(0)
 #define        dump_udccs0(x)  do{}while(0)
 #define        dump_state(x)   do{}while(0)
@@ -253,8 +257,9 @@ dump_state(struct pxa2xx_udc *dev)
 
 #define DBG(lvl, stuff...) do{if ((lvl) <= UDC_DEBUG) DMSG(stuff);}while(0)
 
-#define WARN(stuff...) printk(KERN_WARNING "udc: " stuff)
-#define INFO(stuff...) printk(KERN_INFO "udc: " stuff)
+#define ERR(stuff...)          pr_err("udc: " stuff)
+#define WARN(stuff...)         pr_warning("udc: " stuff)
+#define INFO(stuff...)         pr_info("udc: " stuff)
 
 
 #endif /* __LINUX_USB_GADGET_PXA2XX_H */
index db1b2bfcee4e65eb91cc0c9070f55cea556a76bc..3d036647431fdbd8f409a30cf327d74acceb82c5 100644 (file)
  */
 
 #if 0
-#define DBG(str,args...) do { \
-       if (rndis_debug) \
-               printk(KERN_DEBUG str , ## args ); \
-       } while (0)
 static int rndis_debug = 0;
-
 module_param (rndis_debug, int, 0);
 MODULE_PARM_DESC (rndis_debug, "enable debugging");
-
 #else
-
 #define rndis_debug            0
-#define DBG(str,args...)       do{}while(0)
 #endif
 
+#define DBG(str,args...) do { \
+       if (rndis_debug) \
+               pr_debug(str , ## args); \
+       } while (0)
+
 #define RNDIS_MAX_CONFIGS      1
 
 
@@ -679,7 +676,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
 #endif
 
        default:
-               printk (KERN_WARNING "%s: query unknown OID 0x%08X\n",
+               pr_warning("%s: query unknown OID 0x%08X\n",
                         __FUNCTION__, OID);
        }
        if (retval < 0)
@@ -804,7 +801,7 @@ update_linkstate:
 #endif /* RNDIS_PM */
 
        default:
-               printk (KERN_WARNING "%s: set unknown OID 0x%08X, size %d\n",
+               pr_warning("%s: set unknown OID 0x%08X, size %d\n",
                         __FUNCTION__, OID, buf_len);
        }
 
@@ -1126,8 +1123,7 @@ int rndis_msg_parser (u8 configNr, u8 *buf)
                 * In one case those messages seemed to relate to the host
                 * suspending itself.
                 */
-               printk (KERN_WARNING
-                       "%s: unknown RNDIS message 0x%08X len %d\n",
+               pr_warning("%s: unknown RNDIS message 0x%08X len %d\n",
                        __FUNCTION__ , MsgType, MsgLength);
                {
                        unsigned i;
index 4ce050c3d13fad9199d91697c4490ede73c70ae5..aadc4204d6f9435a32282e92bc28ee3eccf0e383 100644 (file)
@@ -893,7 +893,7 @@ static void s3c2410_udc_handle_ep(struct s3c2410_ep *ep)
 /*
  *     s3c2410_udc_irq - interrupt handler
  */
-static irqreturn_t s3c2410_udc_irq(int irq, void *_dev)
+static irqreturn_t s3c2410_udc_irq(int dummy, void *_dev)
 {
        struct s3c2410_udc *dev = _dev;
        int usb_status;
@@ -1016,7 +1016,7 @@ static irqreturn_t s3c2410_udc_irq(int irq, void *_dev)
                }
        }
 
-       dprintk(DEBUG_VERBOSE, "irq: %d s3c2410_udc_done.\n", irq);
+       dprintk(DEBUG_VERBOSE, "irq: %d s3c2410_udc_done.\n", IRQ_USBD);
 
        /* Restore old index */
        udc_write(idx, S3C2410_UDC_INDEX_REG);
index f5738eb8e76522ae43c12c3c9a8b56f3732a2fe3..f5c3896b1d959a5cbf66e705ba21038ef51553e5 100644 (file)
@@ -89,9 +89,9 @@ static int debug = 1;
 #endif
 
 #define gs_debug(format, arg...) \
-       do { if (debug) printk(KERN_DEBUG format, ## arg); } while(0)
+       do { if (debug) pr_debug(format, ## arg); } while (0)
 #define gs_debug_level(level, format, arg...) \
-       do { if (debug>=level) printk(KERN_DEBUG format, ## arg); } while(0)
+       do { if (debug >= level) pr_debug(format, ## arg); } while (0)
 
 
 /* Thanks to NetChip Technologies for donating this product ID.
@@ -553,7 +553,8 @@ static int __init gs_module_init(void)
 
        retval = usb_gadget_register_driver(&gs_gadget_driver);
        if (retval) {
-               printk(KERN_ERR "gs_module_init: cannot register gadget driver, ret=%d\n", retval);
+               pr_err("gs_module_init: cannot register gadget driver, "
+                       "ret=%d\n", retval);
                return retval;
        }
 
@@ -579,11 +580,13 @@ static int __init gs_module_init(void)
        if (retval) {
                usb_gadget_unregister_driver(&gs_gadget_driver);
                put_tty_driver(gs_tty_driver);
-               printk(KERN_ERR "gs_module_init: cannot register tty driver, ret=%d\n", retval);
+               pr_err("gs_module_init: cannot register tty driver, "
+                               "ret=%d\n", retval);
                return retval;
        }
 
-       printk(KERN_INFO "gs_module_init: %s %s loaded\n", GS_LONG_NAME, GS_VERSION_STR);
+       pr_info("gs_module_init: %s %s loaded\n",
+                       GS_LONG_NAME, GS_VERSION_STR);
        return 0;
 }
 
@@ -598,7 +601,8 @@ static void __exit gs_module_exit(void)
        put_tty_driver(gs_tty_driver);
        usb_gadget_unregister_driver(&gs_gadget_driver);
 
-       printk(KERN_INFO "gs_module_exit: %s %s unloaded\n", GS_LONG_NAME, GS_VERSION_STR);
+       pr_info("gs_module_exit: %s %s unloaded\n",
+                       GS_LONG_NAME, GS_VERSION_STR);
 }
 
 /* TTY Driver */
@@ -621,7 +625,7 @@ static int gs_open(struct tty_struct *tty, struct file *file)
        gs_debug("gs_open: (%d,%p,%p)\n", port_num, tty, file);
 
        if (port_num < 0 || port_num >= GS_NUM_PORTS) {
-               printk(KERN_ERR "gs_open: (%d,%p,%p) invalid port number\n",
+               pr_err("gs_open: (%d,%p,%p) invalid port number\n",
                        port_num, tty, file);
                return -ENODEV;
        }
@@ -629,15 +633,14 @@ static int gs_open(struct tty_struct *tty, struct file *file)
        dev = gs_device;
 
        if (dev == NULL) {
-               printk(KERN_ERR "gs_open: (%d,%p,%p) NULL device pointer\n",
+               pr_err("gs_open: (%d,%p,%p) NULL device pointer\n",
                        port_num, tty, file);
                return -ENODEV;
        }
 
        mtx = &gs_open_close_lock[port_num];
        if (mutex_lock_interruptible(mtx)) {
-               printk(KERN_ERR
-               "gs_open: (%d,%p,%p) interrupted waiting for mutex\n",
+               pr_err("gs_open: (%d,%p,%p) interrupted waiting for mutex\n",
                        port_num, tty, file);
                return -ERESTARTSYS;
        }
@@ -645,8 +648,7 @@ static int gs_open(struct tty_struct *tty, struct file *file)
        spin_lock_irqsave(&dev->dev_lock, flags);
 
        if (dev->dev_config == GS_NO_CONFIG_ID) {
-               printk(KERN_ERR
-                       "gs_open: (%d,%p,%p) device is not connected\n",
+               pr_err("gs_open: (%d,%p,%p) device is not connected\n",
                        port_num, tty, file);
                ret = -ENODEV;
                goto exit_unlock_dev;
@@ -655,7 +657,7 @@ static int gs_open(struct tty_struct *tty, struct file *file)
        port = dev->dev_port[port_num];
 
        if (port == NULL) {
-               printk(KERN_ERR "gs_open: (%d,%p,%p) NULL port pointer\n",
+               pr_err("gs_open: (%d,%p,%p) NULL port pointer\n",
                        port_num, tty, file);
                ret = -ENODEV;
                goto exit_unlock_dev;
@@ -665,7 +667,7 @@ static int gs_open(struct tty_struct *tty, struct file *file)
        spin_unlock(&dev->dev_lock);
 
        if (port->port_dev == NULL) {
-               printk(KERN_ERR "gs_open: (%d,%p,%p) port disconnected (1)\n",
+               pr_err("gs_open: (%d,%p,%p) port disconnected (1)\n",
                        port_num, tty, file);
                ret = -EIO;
                goto exit_unlock_port;
@@ -692,8 +694,7 @@ static int gs_open(struct tty_struct *tty, struct file *file)
 
                /* might have been disconnected while asleep, check */
                if (port->port_dev == NULL) {
-                       printk(KERN_ERR
-                               "gs_open: (%d,%p,%p) port disconnected (2)\n",
+                       pr_err("gs_open: (%d,%p,%p) port disconnected (2)\n",
                                port_num, tty, file);
                        port->port_in_use = 0;
                        ret = -EIO;
@@ -701,7 +702,8 @@ static int gs_open(struct tty_struct *tty, struct file *file)
                }
 
                if ((port->port_write_buf=buf) == NULL) {
-                       printk(KERN_ERR "gs_open: (%d,%p,%p) cannot allocate port write buffer\n",
+                       pr_err("gs_open: (%d,%p,%p) cannot allocate "
+                               "port write buffer\n",
                                port_num, tty, file);
                        port->port_in_use = 0;
                        ret = -ENOMEM;
@@ -714,7 +716,7 @@ static int gs_open(struct tty_struct *tty, struct file *file)
 
        /* might have been disconnected while asleep, check */
        if (port->port_dev == NULL) {
-               printk(KERN_ERR "gs_open: (%d,%p,%p) port disconnected (3)\n",
+               pr_err("gs_open: (%d,%p,%p) port disconnected (3)\n",
                        port_num, tty, file);
                port->port_in_use = 0;
                ret = -EIO;
@@ -762,7 +764,7 @@ static void gs_close(struct tty_struct *tty, struct file *file)
        struct mutex *mtx;
 
        if (port == NULL) {
-               printk(KERN_ERR "gs_close: NULL port pointer\n");
+               pr_err("gs_close: NULL port pointer\n");
                return;
        }
 
@@ -774,8 +776,7 @@ static void gs_close(struct tty_struct *tty, struct file *file)
        spin_lock_irq(&port->port_lock);
 
        if (port->port_open_count == 0) {
-               printk(KERN_ERR
-                       "gs_close: (%d,%p,%p) port is already closed\n",
+               pr_err("gs_close: (%d,%p,%p) port is already closed\n",
                        port->port_num, tty, file);
                goto exit;
        }
@@ -837,7 +838,7 @@ static int gs_write(struct tty_struct *tty, const unsigned char *buf, int count)
        int ret;
 
        if (port == NULL) {
-               printk(KERN_ERR "gs_write: NULL port pointer\n");
+               pr_err("gs_write: NULL port pointer\n");
                return -EIO;
        }
 
@@ -850,14 +851,14 @@ static int gs_write(struct tty_struct *tty, const unsigned char *buf, int count)
        spin_lock_irqsave(&port->port_lock, flags);
 
        if (port->port_dev == NULL) {
-               printk(KERN_ERR "gs_write: (%d,%p) port is not connected\n",
+               pr_err("gs_write: (%d,%p) port is not connected\n",
                        port->port_num, tty);
                ret = -EIO;
                goto exit;
        }
 
        if (port->port_open_count == 0) {
-               printk(KERN_ERR "gs_write: (%d,%p) port is closed\n",
+               pr_err("gs_write: (%d,%p) port is closed\n",
                        port->port_num, tty);
                ret = -EBADF;
                goto exit;
@@ -888,7 +889,7 @@ static void gs_put_char(struct tty_struct *tty, unsigned char ch)
        struct gs_port *port = tty->driver_data;
 
        if (port == NULL) {
-               printk(KERN_ERR "gs_put_char: NULL port pointer\n");
+               pr_err("gs_put_char: NULL port pointer\n");
                return;
        }
 
@@ -898,13 +899,13 @@ static void gs_put_char(struct tty_struct *tty, unsigned char ch)
        spin_lock_irqsave(&port->port_lock, flags);
 
        if (port->port_dev == NULL) {
-               printk(KERN_ERR "gs_put_char: (%d,%p) port is not connected\n",
+               pr_err("gs_put_char: (%d,%p) port is not connected\n",
                        port->port_num, tty);
                goto exit;
        }
 
        if (port->port_open_count == 0) {
-               printk(KERN_ERR "gs_put_char: (%d,%p) port is closed\n",
+               pr_err("gs_put_char: (%d,%p) port is closed\n",
                        port->port_num, tty);
                goto exit;
        }
@@ -924,7 +925,7 @@ static void gs_flush_chars(struct tty_struct *tty)
        struct gs_port *port = tty->driver_data;
 
        if (port == NULL) {
-               printk(KERN_ERR "gs_flush_chars: NULL port pointer\n");
+               pr_err("gs_flush_chars: NULL port pointer\n");
                return;
        }
 
@@ -933,14 +934,13 @@ static void gs_flush_chars(struct tty_struct *tty)
        spin_lock_irqsave(&port->port_lock, flags);
 
        if (port->port_dev == NULL) {
-               printk(KERN_ERR
-                       "gs_flush_chars: (%d,%p) port is not connected\n",
+               pr_err("gs_flush_chars: (%d,%p) port is not connected\n",
                        port->port_num, tty);
                goto exit;
        }
 
        if (port->port_open_count == 0) {
-               printk(KERN_ERR "gs_flush_chars: (%d,%p) port is closed\n",
+               pr_err("gs_flush_chars: (%d,%p) port is closed\n",
                        port->port_num, tty);
                goto exit;
        }
@@ -1038,7 +1038,7 @@ static int gs_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd,
        struct gs_port *port = tty->driver_data;
 
        if (port == NULL) {
-               printk(KERN_ERR "gs_ioctl: NULL port pointer\n");
+               pr_err("gs_ioctl: NULL port pointer\n");
                return -EIO;
        }
 
@@ -1076,7 +1076,7 @@ static int gs_send(struct gs_dev *dev)
        struct gs_req_entry *req_entry;
 
        if (dev == NULL) {
-               printk(KERN_ERR "gs_send: NULL device pointer\n");
+               pr_err("gs_send: NULL device pointer\n");
                return -ENODEV;
        }
 
@@ -1103,7 +1103,7 @@ static int gs_send(struct gs_dev *dev)
                        req->length = len;
                        spin_unlock_irqrestore(&dev->dev_lock, flags);
                        if ((ret=usb_ep_queue(ep, req, GFP_ATOMIC))) {
-                               printk(KERN_ERR
+                               pr_err(
                                "gs_send: cannot queue read request, ret=%d\n",
                                        ret);
                                spin_lock_irqsave(&dev->dev_lock, flags);
@@ -1144,9 +1144,7 @@ static int gs_send_packet(struct gs_dev *dev, char *packet, unsigned int size)
        port = dev->dev_port[0];
 
        if (port == NULL) {
-               printk(KERN_ERR
-                       "gs_send_packet: port=%d, NULL port pointer\n",
-                       0);
+               pr_err("gs_send_packet: port=%d, NULL port pointer\n", 0);
                return -EIO;
        }
 
@@ -1193,7 +1191,7 @@ static int gs_recv_packet(struct gs_dev *dev, char *packet, unsigned int size)
        port = dev->dev_port[0];
 
        if (port == NULL) {
-               printk(KERN_ERR "gs_recv_packet: port=%d, NULL port pointer\n",
+               pr_err("gs_recv_packet: port=%d, NULL port pointer\n",
                        port->port_num);
                return -EIO;
        }
@@ -1201,7 +1199,7 @@ static int gs_recv_packet(struct gs_dev *dev, char *packet, unsigned int size)
        spin_lock(&port->port_lock);
 
        if (port->port_open_count == 0) {
-               printk(KERN_ERR "gs_recv_packet: port=%d, port is closed\n",
+               pr_err("gs_recv_packet: port=%d, port is closed\n",
                        port->port_num);
                ret = -EIO;
                goto exit;
@@ -1211,14 +1209,14 @@ static int gs_recv_packet(struct gs_dev *dev, char *packet, unsigned int size)
        tty = port->port_tty;
 
        if (tty == NULL) {
-               printk(KERN_ERR "gs_recv_packet: port=%d, NULL tty pointer\n",
+               pr_err("gs_recv_packet: port=%d, NULL tty pointer\n",
                        port->port_num);
                ret = -EIO;
                goto exit;
        }
 
        if (port->port_tty->magic != TTY_MAGIC) {
-               printk(KERN_ERR "gs_recv_packet: port=%d, bad tty magic\n",
+               pr_err("gs_recv_packet: port=%d, bad tty magic\n",
                        port->port_num);
                ret = -EIO;
                goto exit;
@@ -1245,7 +1243,7 @@ static void gs_read_complete(struct usb_ep *ep, struct usb_request *req)
        struct gs_dev *dev = ep->driver_data;
 
        if (dev == NULL) {
-               printk(KERN_ERR "gs_read_complete: NULL device pointer\n");
+               pr_err("gs_read_complete: NULL device pointer\n");
                return;
        }
 
@@ -1256,7 +1254,7 @@ static void gs_read_complete(struct usb_ep *ep, struct usb_request *req)
 requeue:
                req->length = ep->maxpacket;
                if ((ret=usb_ep_queue(ep, req, GFP_ATOMIC))) {
-                       printk(KERN_ERR
+                       pr_err(
                        "gs_read_complete: cannot queue read request, ret=%d\n",
                                ret);
                }
@@ -1270,7 +1268,7 @@ requeue:
 
        default:
                /* unexpected */
-               printk(KERN_ERR
+               pr_err(
                "gs_read_complete: unexpected status error, status=%d\n",
                        req->status);
                goto requeue;
@@ -1287,7 +1285,7 @@ static void gs_write_complete(struct usb_ep *ep, struct usb_request *req)
        struct gs_req_entry *gs_req = req->context;
 
        if (dev == NULL) {
-               printk(KERN_ERR "gs_write_complete: NULL device pointer\n");
+               pr_err("gs_write_complete: NULL device pointer\n");
                return;
        }
 
@@ -1296,8 +1294,7 @@ static void gs_write_complete(struct usb_ep *ep, struct usb_request *req)
                /* normal completion */
 requeue:
                if (gs_req == NULL) {
-                       printk(KERN_ERR
-                               "gs_write_complete: NULL request pointer\n");
+                       pr_err("gs_write_complete: NULL request pointer\n");
                        return;
                }
 
@@ -1316,7 +1313,7 @@ requeue:
                break;
 
        default:
-               printk(KERN_ERR
+               pr_err(
                "gs_write_complete: unexpected status error, status=%d\n",
                        req->status);
                goto requeue;
@@ -1351,7 +1348,7 @@ static int __init gs_bind(struct usb_gadget *gadget)
                gs_device_desc.bcdDevice =
                                cpu_to_le16(GS_VERSION_NUM | gcnum);
        else {
-               printk(KERN_WARNING "gs_bind: controller '%s' not recognized\n",
+               pr_warning("gs_bind: controller '%s' not recognized\n",
                        gadget->name);
                /* unrecognized, but safe unless bulk is REALLY quirky */
                gs_device_desc.bcdDevice =
@@ -1375,7 +1372,7 @@ static int __init gs_bind(struct usb_gadget *gadget)
        if (use_acm) {
                ep = usb_ep_autoconfig(gadget, &gs_fullspeed_notify_desc);
                if (!ep) {
-                       printk(KERN_ERR "gs_bind: cannot run ACM on %s\n", gadget->name);
+                       pr_err("gs_bind: cannot run ACM on %s\n", gadget->name);
                        goto autoconf_fail;
                }
                gs_device_desc.idProduct = __constant_cpu_to_le16(
@@ -1425,7 +1422,7 @@ static int __init gs_bind(struct usb_gadget *gadget)
        set_gadget_data(gadget, dev);
 
        if ((ret=gs_alloc_ports(dev, GFP_KERNEL)) != 0) {
-               printk(KERN_ERR "gs_bind: cannot allocate ports\n");
+               pr_err("gs_bind: cannot allocate ports\n");
                gs_unbind(gadget);
                return ret;
        }
@@ -1441,13 +1438,13 @@ static int __init gs_bind(struct usb_gadget *gadget)
 
        gadget->ep0->driver_data = dev;
 
-       printk(KERN_INFO "gs_bind: %s %s bound\n",
+       pr_info("gs_bind: %s %s bound\n",
                GS_LONG_NAME, GS_VERSION_STR);
 
        return 0;
 
 autoconf_fail:
-       printk(KERN_ERR "gs_bind: cannot autoconfigure on %s\n", gadget->name);
+       pr_err("gs_bind: cannot autoconfigure on %s\n", gadget->name);
        return -ENODEV;
 }
 
@@ -1480,7 +1477,7 @@ static void /* __init_or_exit */ gs_unbind(struct usb_gadget *gadget)
                set_gadget_data(gadget, NULL);
        }
 
-       printk(KERN_INFO "gs_unbind: %s %s unbound\n", GS_LONG_NAME,
+       pr_info("gs_unbind: %s %s unbound\n", GS_LONG_NAME,
                GS_VERSION_STR);
 }
 
@@ -1513,7 +1510,8 @@ static int gs_setup(struct usb_gadget *gadget,
                break;
 
        default:
-               printk(KERN_ERR "gs_setup: unknown request, type=%02x, request=%02x, value=%04x, index=%04x, length=%d\n",
+               pr_err("gs_setup: unknown request, type=%02x, request=%02x, "
+                       "value=%04x, index=%04x, length=%d\n",
                        ctrl->bRequestType, ctrl->bRequest,
                        wValue, wIndex, wLength);
                break;
@@ -1526,7 +1524,7 @@ static int gs_setup(struct usb_gadget *gadget,
                                && (ret % gadget->ep0->maxpacket) == 0;
                ret = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC);
                if (ret < 0) {
-                       printk(KERN_ERR "gs_setup: cannot queue response, ret=%d\n",
+                       pr_err("gs_setup: cannot queue response, ret=%d\n",
                                ret);
                        req->status = 0;
                        gs_setup_complete(gadget->ep0, req);
@@ -1656,7 +1654,8 @@ set_interface_done:
                break;
 
        default:
-               printk(KERN_ERR "gs_setup: unknown standard request, type=%02x, request=%02x, value=%04x, index=%04x, length=%d\n",
+               pr_err("gs_setup: unknown standard request, type=%02x, "
+                       "request=%02x, value=%04x, index=%04x, length=%d\n",
                        ctrl->bRequestType, ctrl->bRequest,
                        wValue, wIndex, wLength);
                break;
@@ -1682,7 +1681,7 @@ static int gs_setup_class(struct usb_gadget *gadget,
                 * handler copy that data to port->port_line_coding (iff
                 * it's valid) and maybe pass it on.  Until then, fail.
                 */
-               printk(KERN_WARNING "gs_setup: set_line_coding "
+               pr_warning("gs_setup: set_line_coding "
                                "unuspported\n");
                break;
 
@@ -1702,12 +1701,12 @@ static int gs_setup_class(struct usb_gadget *gadget,
                 * handler use that to set the state (iff it's valid) and
                 * maybe pass it on.  Until then, fail.
                 */
-               printk(KERN_WARNING "gs_setup: set_control_line_state "
+               pr_warning("gs_setup: set_control_line_state "
                                "unuspported\n");
                break;
 
        default:
-               printk(KERN_ERR "gs_setup: unknown class request, "
+               pr_err("gs_setup: unknown class request, "
                                "type=%02x, request=%02x, value=%04x, "
                                "index=%04x, length=%d\n",
                        ctrl->bRequestType, ctrl->bRequest,
@@ -1724,7 +1723,8 @@ static int gs_setup_class(struct usb_gadget *gadget,
 static void gs_setup_complete(struct usb_ep *ep, struct usb_request *req)
 {
        if (req->status || req->actual != req->length) {
-               printk(KERN_ERR "gs_setup_complete: status error, status=%d, actual=%d, length=%d\n",
+               pr_err("gs_setup_complete: status error, status=%d, "
+                       "actual=%d, length=%d\n",
                        req->status, req->actual, req->length);
        }
 }
@@ -1751,11 +1751,11 @@ static void gs_disconnect(struct usb_gadget *gadget)
 
        /* re-allocate ports for the next connection */
        if (gs_alloc_ports(dev, GFP_ATOMIC) != 0)
-               printk(KERN_ERR "gs_disconnect: cannot re-allocate ports\n");
+               pr_err("gs_disconnect: cannot re-allocate ports\n");
 
        spin_unlock_irqrestore(&dev->dev_lock, flags);
 
-       printk(KERN_INFO "gs_disconnect: %s disconnected\n", GS_LONG_NAME);
+       pr_info("gs_disconnect: %s disconnected\n", GS_LONG_NAME);
 }
 
 /*
@@ -1778,7 +1778,7 @@ static int gs_set_config(struct gs_dev *dev, unsigned config)
        struct gs_req_entry *req_entry;
 
        if (dev == NULL) {
-               printk(KERN_ERR "gs_set_config: NULL device pointer\n");
+               pr_err("gs_set_config: NULL device pointer\n");
                return 0;
        }
 
@@ -1823,7 +1823,8 @@ static int gs_set_config(struct gs_dev *dev, unsigned config)
                                dev->dev_notify_ep = ep;
                                dev->dev_notify_ep_desc = ep_desc;
                        } else {
-                               printk(KERN_ERR "gs_set_config: cannot enable notify endpoint %s, ret=%d\n",
+                               pr_err("gs_set_config: cannot enable NOTIFY "
+                                       "endpoint %s, ret=%d\n",
                                        ep->name, ret);
                                goto exit_reset_config;
                        }
@@ -1839,7 +1840,8 @@ static int gs_set_config(struct gs_dev *dev, unsigned config)
                                dev->dev_in_ep = ep;
                                dev->dev_in_ep_desc = ep_desc;
                        } else {
-                               printk(KERN_ERR "gs_set_config: cannot enable in endpoint %s, ret=%d\n",
+                               pr_err("gs_set_config: cannot enable IN "
+                                       "endpoint %s, ret=%d\n",
                                        ep->name, ret);
                                goto exit_reset_config;
                        }
@@ -1855,7 +1857,8 @@ static int gs_set_config(struct gs_dev *dev, unsigned config)
                                dev->dev_out_ep = ep;
                                dev->dev_out_ep_desc = ep_desc;
                        } else {
-                               printk(KERN_ERR "gs_set_config: cannot enable out endpoint %s, ret=%d\n",
+                               pr_err("gs_set_config: cannot enable OUT "
+                                       "endpoint %s, ret=%d\n",
                                        ep->name, ret);
                                goto exit_reset_config;
                        }
@@ -1865,7 +1868,7 @@ static int gs_set_config(struct gs_dev *dev, unsigned config)
 
        if (dev->dev_in_ep == NULL || dev->dev_out_ep == NULL
        || (config != GS_BULK_CONFIG_ID && dev->dev_notify_ep == NULL)) {
-               printk(KERN_ERR "gs_set_config: cannot find endpoints\n");
+               pr_err("gs_set_config: cannot find endpoints\n");
                ret = -ENODEV;
                goto exit_reset_config;
        }
@@ -1876,11 +1879,12 @@ static int gs_set_config(struct gs_dev *dev, unsigned config)
                if ((req=gs_alloc_req(ep, ep->maxpacket, GFP_ATOMIC))) {
                        req->complete = gs_read_complete;
                        if ((ret=usb_ep_queue(ep, req, GFP_ATOMIC))) {
-                               printk(KERN_ERR "gs_set_config: cannot queue read request, ret=%d\n",
-                                       ret);
+                               pr_err("gs_set_config: cannot queue read "
+                                       "request, ret=%d\n", ret);
                        }
                } else {
-                       printk(KERN_ERR "gs_set_config: cannot allocate read requests\n");
+                       pr_err("gs_set_config: cannot allocate "
+                                       "read requests\n");
                        ret = -ENOMEM;
                        goto exit_reset_config;
                }
@@ -1893,13 +1897,14 @@ static int gs_set_config(struct gs_dev *dev, unsigned config)
                        req_entry->re_req->complete = gs_write_complete;
                        list_add(&req_entry->re_entry, &dev->dev_req_list);
                } else {
-                       printk(KERN_ERR "gs_set_config: cannot allocate write requests\n");
+                       pr_err("gs_set_config: cannot allocate "
+                                       "write requests\n");
                        ret = -ENOMEM;
                        goto exit_reset_config;
                }
        }
 
-       printk(KERN_INFO "gs_set_config: %s configured, %s speed %s config\n",
+       pr_info("gs_set_config: %s configured, %s speed %s config\n",
                GS_LONG_NAME,
                gadget->speed == USB_SPEED_HIGH ? "high" : "full",
                config == GS_BULK_CONFIG_ID ? "BULK" : "CDC-ACM");
@@ -1926,7 +1931,7 @@ static void gs_reset_config(struct gs_dev *dev)
        struct gs_req_entry *req_entry;
 
        if (dev == NULL) {
-               printk(KERN_ERR "gs_reset_config: NULL device pointer\n");
+               pr_err("gs_reset_config: NULL device pointer\n");
                return;
        }
 
index fcde5d9c87df11eb6d867f7ff4a3bee075c96bc4..d3d4f4048e6c39f7f958e263cf1761d194c25d34 100644 (file)
@@ -1115,7 +1115,7 @@ zero_bind (struct usb_gadget *gadget)
        ep = usb_ep_autoconfig (gadget, &fs_source_desc);
        if (!ep) {
 autoconf_fail:
-               printk (KERN_ERR "%s: can't autoconfigure on %s\n",
+               pr_err("%s: can't autoconfigure on %s\n",
                        shortname, gadget->name);
                return -ENODEV;
        }
@@ -1139,7 +1139,7 @@ autoconf_fail:
                 * things like configuration and altsetting numbering
                 * can need hardware-specific attention though.
                 */
-               printk (KERN_WARNING "%s: controller '%s' not recognized\n",
+               pr_warning("%s: controller '%s' not recognized\n",
                        shortname, gadget->name);
                device_desc.bcdDevice = __constant_cpu_to_le16 (0x9999);
        }
index 49a91c5ee51bc4574808302dbf52a1960f703c12..d97b16b52efa051f39c3d2fd1cf97a1b961a58d6 100644 (file)
@@ -29,15 +29,6 @@ config USB_EHCI_HCD
          To compile this driver as a module, choose M here: the
          module will be called ehci-hcd.
 
-config USB_EHCI_SPLIT_ISO
-       bool "Full speed ISO transactions (EXPERIMENTAL)"
-       depends on USB_EHCI_HCD && EXPERIMENTAL
-       default n
-       ---help---
-         This code is new and hasn't been used with many different
-         EHCI or USB 2.0 transaction translator implementations.
-         It should work for ISO-OUT transfers, like audio.
-
 config USB_EHCI_ROOT_HUB_TT
        bool "Root Hub Transaction Translators (EXPERIMENTAL)"
        depends on USB_EHCI_HCD && EXPERIMENTAL
@@ -69,21 +60,30 @@ config USB_EHCI_TT_NEWSCHED
 
 config USB_EHCI_BIG_ENDIAN_MMIO
        bool
-       depends on USB_EHCI_HCD && (PPC_CELLEB || PPC_PS3 || 440EPX)
+       depends on USB_EHCI_HCD && (PPC_CELLEB || PPC_PS3 || 440EPX || ARCH_IXP4XX)
        default y
 
 config USB_EHCI_BIG_ENDIAN_DESC
        bool
-       depends on USB_EHCI_HCD && 440EPX
+       depends on USB_EHCI_HCD && (440EPX || ARCH_IXP4XX)
        default y
 
 config USB_EHCI_FSL
        bool
+       depends on USB_EHCI_HCD
        select USB_EHCI_ROOT_HUB_TT
        default y if MPC834x || PPC_MPC831x
        ---help---
          Variation of ARC USB block used in some Freescale chips.
 
+config USB_EHCI_HCD_PPC_OF
+       bool "EHCI support for PPC USB controller on OF platform bus"
+       depends on USB_EHCI_HCD && PPC_OF
+       default y
+       ---help---
+         Enables support for the USB controller present on the PowerPC
+         OpenFirmware platform bus.
+
 config USB_ISP116X_HCD
        tristate "ISP116X HCD support"
        depends on USB
index 766ef68a0b43a98d81168ec781a9b01623a337f1..da7532d38bf1622044ed654147d25116a46a9b26 100644 (file)
@@ -222,6 +222,7 @@ static const struct hc_driver ehci_au1xxx_hc_driver = {
        .hub_control = ehci_hub_control,
        .bus_suspend = ehci_bus_suspend,
        .bus_resume = ehci_bus_resume,
+       .relinquish_port = ehci_relinquish_port,
 };
 
 /*-------------------------------------------------------------------------*/
index c9cc4413198e15d977a5d1e8b4d671eb2d72188a..64ebfc5548a31c04735bcb428aa040a68e4a2598 100644 (file)
@@ -323,7 +323,43 @@ static inline void remove_debug_files (struct ehci_hcd *bus) { }
 
 #else
 
-/* troubleshooting help: expose state in sysfs */
+/* troubleshooting help: expose state in debugfs */
+
+static int debug_async_open(struct inode *, struct file *);
+static int debug_periodic_open(struct inode *, struct file *);
+static int debug_registers_open(struct inode *, struct file *);
+static int debug_async_open(struct inode *, struct file *);
+static ssize_t debug_output(struct file*, char __user*, size_t, loff_t*);
+static int debug_close(struct inode *, struct file *);
+
+static const struct file_operations debug_async_fops = {
+       .owner          = THIS_MODULE,
+       .open           = debug_async_open,
+       .read           = debug_output,
+       .release        = debug_close,
+};
+static const struct file_operations debug_periodic_fops = {
+       .owner          = THIS_MODULE,
+       .open           = debug_periodic_open,
+       .read           = debug_output,
+       .release        = debug_close,
+};
+static const struct file_operations debug_registers_fops = {
+       .owner          = THIS_MODULE,
+       .open           = debug_registers_open,
+       .read           = debug_output,
+       .release        = debug_close,
+};
+
+static struct dentry *ehci_debug_root;
+
+struct debug_buffer {
+       ssize_t (*fill_func)(struct debug_buffer *);    /* fill method */
+       struct usb_bus *bus;
+       struct mutex mutex;     /* protect filling of buffer */
+       size_t count;           /* number of characters filled into buffer */
+       char *page;
+};
 
 #define speed_char(info1) ({ char tmp; \
                switch (info1 & (3 << 12)) { \
@@ -441,10 +477,8 @@ done:
        *nextp = next;
 }
 
-static ssize_t
-show_async (struct class_device *class_dev, char *buf)
+static ssize_t fill_async_buffer(struct debug_buffer *buf)
 {
-       struct usb_bus          *bus;
        struct usb_hcd          *hcd;
        struct ehci_hcd         *ehci;
        unsigned long           flags;
@@ -452,14 +486,13 @@ show_async (struct class_device *class_dev, char *buf)
        char                    *next;
        struct ehci_qh          *qh;
 
-       *buf = 0;
-
-       bus = class_get_devdata(class_dev);
-       hcd = bus_to_hcd(bus);
+       hcd = bus_to_hcd(buf->bus);
        ehci = hcd_to_ehci (hcd);
-       next = buf;
+       next = buf->page;
        size = PAGE_SIZE;
 
+       *next = 0;
+
        /* dumps a snapshot of the async schedule.
         * usually empty except for long-term bulk reads, or head.
         * one QH per line, and TDs we know about
@@ -477,16 +510,12 @@ show_async (struct class_device *class_dev, char *buf)
        }
        spin_unlock_irqrestore (&ehci->lock, flags);
 
-       return strlen (buf);
+       return strlen(buf->page);
 }
-static CLASS_DEVICE_ATTR (async, S_IRUGO, show_async, NULL);
 
 #define DBG_SCHED_LIMIT 64
-
-static ssize_t
-show_periodic (struct class_device *class_dev, char *buf)
+static ssize_t fill_periodic_buffer(struct debug_buffer *buf)
 {
-       struct usb_bus          *bus;
        struct usb_hcd          *hcd;
        struct ehci_hcd         *ehci;
        unsigned long           flags;
@@ -500,10 +529,9 @@ show_periodic (struct class_device *class_dev, char *buf)
                return 0;
        seen_count = 0;
 
-       bus = class_get_devdata(class_dev);
-       hcd = bus_to_hcd(bus);
+       hcd = bus_to_hcd(buf->bus);
        ehci = hcd_to_ehci (hcd);
-       next = buf;
+       next = buf->page;
        size = PAGE_SIZE;
 
        temp = scnprintf (next, size, "size = %d\n", ehci->periodic_size);
@@ -623,14 +651,10 @@ show_periodic (struct class_device *class_dev, char *buf)
 
        return PAGE_SIZE - size;
 }
-static CLASS_DEVICE_ATTR (periodic, S_IRUGO, show_periodic, NULL);
-
 #undef DBG_SCHED_LIMIT
 
-static ssize_t
-show_registers (struct class_device *class_dev, char *buf)
+static ssize_t fill_registers_buffer(struct debug_buffer *buf)
 {
-       struct usb_bus          *bus;
        struct usb_hcd          *hcd;
        struct ehci_hcd         *ehci;
        unsigned long           flags;
@@ -639,15 +663,14 @@ show_registers (struct class_device *class_dev, char *buf)
        static char             fmt [] = "%*s\n";
        static char             label [] = "";
 
-       bus = class_get_devdata(class_dev);
-       hcd = bus_to_hcd(bus);
+       hcd = bus_to_hcd(buf->bus);
        ehci = hcd_to_ehci (hcd);
-       next = buf;
+       next = buf->page;
        size = PAGE_SIZE;
 
        spin_lock_irqsave (&ehci->lock, flags);
 
-       if (bus->controller->power.power_state.event) {
+       if (buf->bus->controller->power.power_state.event) {
                size = scnprintf (next, size,
                        "bus %s, device %s (driver " DRIVER_VERSION ")\n"
                        "%s\n"
@@ -763,9 +786,7 @@ show_registers (struct class_device *class_dev, char *buf)
        }
 
        if (ehci->reclaim) {
-               temp = scnprintf (next, size, "reclaim qh %p%s\n",
-                               ehci->reclaim,
-                               ehci->reclaim_ready ? " ready" : "");
+               temp = scnprintf(next, size, "reclaim qh %p\n", ehci->reclaim);
                size -= temp;
                next += temp;
        }
@@ -789,26 +810,150 @@ done:
 
        return PAGE_SIZE - size;
 }
-static CLASS_DEVICE_ATTR (registers, S_IRUGO, show_registers, NULL);
 
-static inline void create_debug_files (struct ehci_hcd *ehci)
+static struct debug_buffer *alloc_buffer(struct usb_bus *bus,
+                               ssize_t (*fill_func)(struct debug_buffer *))
 {
-       struct class_device *cldev = ehci_to_hcd(ehci)->self.class_dev;
-       int retval;
+       struct debug_buffer *buf;
+
+       buf = kzalloc(sizeof(struct debug_buffer), GFP_KERNEL);
 
-       retval = class_device_create_file(cldev, &class_device_attr_async);
-       retval = class_device_create_file(cldev, &class_device_attr_periodic);
-       retval = class_device_create_file(cldev, &class_device_attr_registers);
+       if (buf) {
+               buf->bus = bus;
+               buf->fill_func = fill_func;
+               mutex_init(&buf->mutex);
+       }
+
+       return buf;
 }
 
-static inline void remove_debug_files (struct ehci_hcd *ehci)
+static int fill_buffer(struct debug_buffer *buf)
 {
-       struct class_device *cldev = ehci_to_hcd(ehci)->self.class_dev;
+       int ret = 0;
+
+       if (!buf->page)
+               buf->page = (char *)get_zeroed_page(GFP_KERNEL);
+
+       if (!buf->page) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       ret = buf->fill_func(buf);
 
-       class_device_remove_file(cldev, &class_device_attr_async);
-       class_device_remove_file(cldev, &class_device_attr_periodic);
-       class_device_remove_file(cldev, &class_device_attr_registers);
+       if (ret >= 0) {
+               buf->count = ret;
+               ret = 0;
+       }
+
+out:
+       return ret;
 }
 
-#endif /* STUB_DEBUG_FILES */
+static ssize_t debug_output(struct file *file, char __user *user_buf,
+                           size_t len, loff_t *offset)
+{
+       struct debug_buffer *buf = file->private_data;
+       int ret = 0;
+
+       mutex_lock(&buf->mutex);
+       if (buf->count == 0) {
+               ret = fill_buffer(buf);
+               if (ret != 0) {
+                       mutex_unlock(&buf->mutex);
+                       goto out;
+               }
+       }
+       mutex_unlock(&buf->mutex);
+
+       ret = simple_read_from_buffer(user_buf, len, offset,
+                                     buf->page, buf->count);
+
+out:
+       return ret;
+
+}
+
+static int debug_close(struct inode *inode, struct file *file)
+{
+       struct debug_buffer *buf = file->private_data;
 
+       if (buf) {
+               if (buf->page)
+                       free_page((unsigned long)buf->page);
+               kfree(buf);
+       }
+
+       return 0;
+}
+static int debug_async_open(struct inode *inode, struct file *file)
+{
+       file->private_data = alloc_buffer(inode->i_private, fill_async_buffer);
+
+       return file->private_data ? 0 : -ENOMEM;
+}
+
+static int debug_periodic_open(struct inode *inode, struct file *file)
+{
+       file->private_data = alloc_buffer(inode->i_private,
+                                         fill_periodic_buffer);
+
+       return file->private_data ? 0 : -ENOMEM;
+}
+
+static int debug_registers_open(struct inode *inode, struct file *file)
+{
+       file->private_data = alloc_buffer(inode->i_private,
+                                         fill_registers_buffer);
+
+       return file->private_data ? 0 : -ENOMEM;
+}
+
+static inline void create_debug_files (struct ehci_hcd *ehci)
+{
+       struct usb_bus *bus = &ehci_to_hcd(ehci)->self;
+
+       ehci->debug_dir = debugfs_create_dir(bus->bus_name, ehci_debug_root);
+       if (!ehci->debug_dir)
+               goto dir_error;
+
+       ehci->debug_async = debugfs_create_file("async", S_IRUGO,
+                                               ehci->debug_dir, bus,
+                                               &debug_async_fops);
+       if (!ehci->debug_async)
+               goto async_error;
+
+       ehci->debug_periodic = debugfs_create_file("periodic", S_IRUGO,
+                                                  ehci->debug_dir, bus,
+                                                  &debug_periodic_fops);
+       if (!ehci->debug_periodic)
+               goto periodic_error;
+
+       ehci->debug_registers = debugfs_create_file("registers", S_IRUGO,
+                                                   ehci->debug_dir, bus,
+                                                   &debug_registers_fops);
+       if (!ehci->debug_registers)
+               goto registers_error;
+       return;
+
+registers_error:
+       debugfs_remove(ehci->debug_periodic);
+periodic_error:
+       debugfs_remove(ehci->debug_async);
+async_error:
+       debugfs_remove(ehci->debug_dir);
+dir_error:
+       ehci->debug_periodic = NULL;
+       ehci->debug_async = NULL;
+       ehci->debug_dir = NULL;
+}
+
+static inline void remove_debug_files (struct ehci_hcd *ehci)
+{
+       debugfs_remove(ehci->debug_registers);
+       debugfs_remove(ehci->debug_periodic);
+       debugfs_remove(ehci->debug_async);
+       debugfs_remove(ehci->debug_dir);
+}
+
+#endif /* STUB_DEBUG_FILES */
index 430821cb95c8f32dae781f26a44290ae9138a7e3..adb0defa1631f0de75baaf6d1777119c1ba0d434 100644 (file)
@@ -25,7 +25,7 @@
 
 #include "ehci-fsl.h"
 
-/* FIXME: Power Managment is un-ported so temporarily disable it */
+/* FIXME: Power Management is un-ported so temporarily disable it */
 #undef CONFIG_PM
 
 /* PCI-based HCs are common, but plenty of non-PCI HCs are used too */
@@ -323,6 +323,7 @@ static const struct hc_driver ehci_fsl_hc_driver = {
        .hub_control = ehci_hub_control,
        .bus_suspend = ehci_bus_suspend,
        .bus_resume = ehci_bus_resume,
+       .relinquish_port = ehci_relinquish_port,
 };
 
 static int ehci_fsl_drv_probe(struct platform_device *pdev)
index 5f2d74ed5ad73a299480022938645551d5179b09..4caa6a8b9a3772246dcb140dde02e5765104374f 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/usb.h>
 #include <linux/moduleparam.h>
 #include <linux/dma-mapping.h>
+#include <linux/debugfs.h>
 
 #include "../core/hcd.h"
 
@@ -109,7 +110,7 @@ static const char   hcd_name [] = "ehci_hcd";
 #define        EHCI_TUNE_MULT_TT       1
 #define        EHCI_TUNE_FLS           2       /* (small) 256 frame schedule */
 
-#define EHCI_IAA_JIFFIES       (HZ/100)        /* arbitrary; ~10 msec */
+#define EHCI_IAA_MSECS         10              /* arbitrary */
 #define EHCI_IO_JIFFIES                (HZ/10)         /* io watchdog > irq_thresh */
 #define EHCI_ASYNC_JIFFIES     (HZ/20)         /* async idle timeout */
 #define EHCI_SHRINK_JIFFIES    (HZ/200)        /* async qh unlink delay */
@@ -266,6 +267,7 @@ static void ehci_quiesce (struct ehci_hcd *ehci)
 
 /*-------------------------------------------------------------------------*/
 
+static void end_unlink_async(struct ehci_hcd *ehci);
 static void ehci_work(struct ehci_hcd *ehci);
 
 #include "ehci-hub.c"
@@ -275,25 +277,41 @@ static void ehci_work(struct ehci_hcd *ehci);
 
 /*-------------------------------------------------------------------------*/
 
-static void ehci_watchdog (unsigned long param)
+static void ehci_iaa_watchdog(unsigned long param)
 {
        struct ehci_hcd         *ehci = (struct ehci_hcd *) param;
        unsigned long           flags;
+       u32                     status, cmd;
 
        spin_lock_irqsave (&ehci->lock, flags);
+       WARN_ON(!ehci->reclaim);
 
-       /* lost IAA irqs wedge things badly; seen with a vt8235 */
+       status = ehci_readl(ehci, &ehci->regs->status);
+       cmd = ehci_readl(ehci, &ehci->regs->command);
+       ehci_dbg(ehci, "IAA watchdog: status %x cmd %x\n", status, cmd);
+
+       /* lost IAA irqs wedge things badly; seen first with a vt8235 */
        if (ehci->reclaim) {
-               u32             status = ehci_readl(ehci, &ehci->regs->status);
                if (status & STS_IAA) {
                        ehci_vdbg (ehci, "lost IAA\n");
                        COUNT (ehci->stats.lost_iaa);
                        ehci_writel(ehci, STS_IAA, &ehci->regs->status);
-                       ehci->reclaim_ready = 1;
                }
+               ehci_writel(ehci, cmd & ~CMD_IAAD, &ehci->regs->command);
+               end_unlink_async(ehci);
        }
 
-       /* stop async processing after it's idled a bit */
+       spin_unlock_irqrestore(&ehci->lock, flags);
+}
+
+static void ehci_watchdog(unsigned long param)
+{
+       struct ehci_hcd         *ehci = (struct ehci_hcd *) param;
+       unsigned long           flags;
+
+       spin_lock_irqsave(&ehci->lock, flags);
+
+       /* stop async processing after it's idled a bit */
        if (test_bit (TIMER_ASYNC_OFF, &ehci->actions))
                start_unlink_async (ehci, ehci->async);
 
@@ -363,8 +381,6 @@ static void ehci_port_power (struct ehci_hcd *ehci, int is_on)
 static void ehci_work (struct ehci_hcd *ehci)
 {
        timer_action_done (ehci, TIMER_IO_WATCHDOG);
-       if (ehci->reclaim_ready)
-               end_unlink_async (ehci);
 
        /* another CPU may drop ehci->lock during a schedule scan while
         * it reports urb completions.  this flag guards against bogus
@@ -399,6 +415,7 @@ static void ehci_stop (struct usb_hcd *hcd)
 
        /* no more interrupts ... */
        del_timer_sync (&ehci->watchdog);
+       del_timer_sync(&ehci->iaa_watchdog);
 
        spin_lock_irq(&ehci->lock);
        if (HC_IS_RUNNING (hcd->state))
@@ -447,6 +464,10 @@ static int ehci_init(struct usb_hcd *hcd)
        ehci->watchdog.function = ehci_watchdog;
        ehci->watchdog.data = (unsigned long) ehci;
 
+       init_timer(&ehci->iaa_watchdog);
+       ehci->iaa_watchdog.function = ehci_iaa_watchdog;
+       ehci->iaa_watchdog.data = (unsigned long) ehci;
+
        /*
         * hw default: 1K periodic list heads, one per frame.
         * periodic_size can shrink by USBCMD update if hcc_params allows.
@@ -463,7 +484,6 @@ static int ehci_init(struct usb_hcd *hcd)
                ehci->i_thresh = 2 + HCC_ISOC_THRES(hcc_params);
 
        ehci->reclaim = NULL;
-       ehci->reclaim_ready = 0;
        ehci->next_uframe = -1;
 
        /*
@@ -654,8 +674,7 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
        /* complete the unlinking of some qh [4.15.2.3] */
        if (status & STS_IAA) {
                COUNT (ehci->stats.reclaim);
-               ehci->reclaim_ready = 1;
-               bh = 1;
+               end_unlink_async(ehci);
        }
 
        /* remote wakeup [4.3.1] */
@@ -761,10 +780,16 @@ static int ehci_urb_enqueue (
 
 static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
 {
-       /* if we need to use IAA and it's busy, defer */
-       if (qh->qh_state == QH_STATE_LINKED
-                       && ehci->reclaim
-                       && HC_IS_RUNNING (ehci_to_hcd(ehci)->state)) {
+       /* failfast */
+       if (!HC_IS_RUNNING(ehci_to_hcd(ehci)->state))
+               end_unlink_async(ehci);
+
+       /* if it's not linked then there's nothing to do */
+       if (qh->qh_state != QH_STATE_LINKED)
+               ;
+
+       /* defer till later if busy */
+       else if (ehci->reclaim) {
                struct ehci_qh          *last;
 
                for (last = ehci->reclaim;
@@ -774,12 +799,8 @@ static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
                qh->qh_state = QH_STATE_UNLINK_WAIT;
                last->reclaim = qh;
 
-       /* bypass IAA if the hc can't care */
-       } else if (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state) && ehci->reclaim)
-               end_unlink_async (ehci);
-
-       /* something else might have unlinked the qh by now */
-       if (qh->qh_state == QH_STATE_LINKED)
+       /* start IAA cycle */
+       } else
                start_unlink_async (ehci, qh);
 }
 
@@ -806,7 +827,19 @@ static int ehci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
                qh = (struct ehci_qh *) urb->hcpriv;
                if (!qh)
                        break;
-               unlink_async (ehci, qh);
+               switch (qh->qh_state) {
+               case QH_STATE_LINKED:
+               case QH_STATE_COMPLETING:
+                       unlink_async(ehci, qh);
+                       break;
+               case QH_STATE_UNLINK:
+               case QH_STATE_UNLINK_WAIT:
+                       /* already started */
+                       break;
+               case QH_STATE_IDLE:
+                       WARN_ON(1);
+                       break;
+               }
                break;
 
        case PIPE_INTERRUPT:
@@ -829,16 +862,16 @@ static int ehci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
                /* reschedule QH iff another request is queued */
                if (!list_empty (&qh->qtd_list)
                                && HC_IS_RUNNING (hcd->state)) {
-                       int status;
+                       int schedule_status;
 
-                       status = qh_schedule (ehci, qh);
+                       schedule_status = qh_schedule (ehci, qh);
                        spin_unlock_irqrestore (&ehci->lock, flags);
 
-                       if (status != 0) {
+                       if (schedule_status != 0) {
                                // shouldn't happen often, but ...
                                // FIXME kill those tds' urbs
                                err ("can't reschedule qh %p, err %d",
-                                       qh, status);
+                                       qh, schedule_status);
                        }
                        return status;
                }
@@ -898,6 +931,7 @@ rescan:
                unlink_async (ehci, qh);
                /* FALL THROUGH */
        case QH_STATE_UNLINK:           /* wait for hw to finish? */
+       case QH_STATE_UNLINK_WAIT:
 idle_timeout:
                spin_unlock_irqrestore (&ehci->lock, flags);
                schedule_timeout_uninterruptible(1);
@@ -959,11 +993,26 @@ MODULE_LICENSE ("GPL");
 #define        PS3_SYSTEM_BUS_DRIVER   ps3_ehci_driver
 #endif
 
-#ifdef CONFIG_440EPX
+#if defined(CONFIG_440EPX) && !defined(CONFIG_PPC_MERGE)
 #include "ehci-ppc-soc.c"
 #define        PLATFORM_DRIVER         ehci_ppc_soc_driver
 #endif
 
+#ifdef CONFIG_USB_EHCI_HCD_PPC_OF
+#include "ehci-ppc-of.c"
+#define OF_PLATFORM_DRIVER     ehci_hcd_ppc_of_driver
+#endif
+
+#ifdef CONFIG_ARCH_ORION
+#include "ehci-orion.c"
+#define        PLATFORM_DRIVER         ehci_orion_driver
+#endif
+
+#ifdef CONFIG_ARCH_IXP4XX
+#include "ehci-ixp4xx.c"
+#define        PLATFORM_DRIVER         ixp4xx_ehci_driver
+#endif
+
 #if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \
     !defined(PS3_SYSTEM_BUS_DRIVER)
 #error "missing bus glue for ehci-hcd"
@@ -978,41 +1027,66 @@ static int __init ehci_hcd_init(void)
                 sizeof(struct ehci_qh), sizeof(struct ehci_qtd),
                 sizeof(struct ehci_itd), sizeof(struct ehci_sitd));
 
+#ifdef DEBUG
+       ehci_debug_root = debugfs_create_dir("ehci", NULL);
+       if (!ehci_debug_root)
+               return -ENOENT;
+#endif
+
 #ifdef PLATFORM_DRIVER
        retval = platform_driver_register(&PLATFORM_DRIVER);
        if (retval < 0)
-               return retval;
+               goto clean0;
 #endif
 
 #ifdef PCI_DRIVER
        retval = pci_register_driver(&PCI_DRIVER);
-       if (retval < 0) {
-#ifdef PLATFORM_DRIVER
-               platform_driver_unregister(&PLATFORM_DRIVER);
-#endif
-               return retval;
-       }
+       if (retval < 0)
+               goto clean1;
 #endif
 
 #ifdef PS3_SYSTEM_BUS_DRIVER
        retval = ps3_ehci_driver_register(&PS3_SYSTEM_BUS_DRIVER);
-       if (retval < 0) {
-#ifdef PLATFORM_DRIVER
-               platform_driver_unregister(&PLATFORM_DRIVER);
+       if (retval < 0)
+               goto clean2;
+#endif
+
+#ifdef OF_PLATFORM_DRIVER
+       retval = of_register_platform_driver(&OF_PLATFORM_DRIVER);
+       if (retval < 0)
+               goto clean3;
+#endif
+       return retval;
+
+#ifdef OF_PLATFORM_DRIVER
+       /* of_unregister_platform_driver(&OF_PLATFORM_DRIVER); */
+clean3:
+#endif
+#ifdef PS3_SYSTEM_BUS_DRIVER
+       ps3_ehci_driver_unregister(&PS3_SYSTEM_BUS_DRIVER);
+clean2:
 #endif
 #ifdef PCI_DRIVER
-               pci_unregister_driver(&PCI_DRIVER);
+       pci_unregister_driver(&PCI_DRIVER);
+clean1:
 #endif
-               return retval;
-       }
+#ifdef PLATFORM_DRIVER
+       platform_driver_unregister(&PLATFORM_DRIVER);
+clean0:
+#endif
+#ifdef DEBUG
+       debugfs_remove(ehci_debug_root);
+       ehci_debug_root = NULL;
 #endif
-
        return retval;
 }
 module_init(ehci_hcd_init);
 
 static void __exit ehci_hcd_cleanup(void)
 {
+#ifdef OF_PLATFORM_DRIVER
+       of_unregister_platform_driver(&OF_PLATFORM_DRIVER);
+#endif
 #ifdef PLATFORM_DRIVER
        platform_driver_unregister(&PLATFORM_DRIVER);
 #endif
@@ -1022,6 +1096,9 @@ static void __exit ehci_hcd_cleanup(void)
 #ifdef PS3_SYSTEM_BUS_DRIVER
        ps3_ehci_driver_unregister(&PS3_SYSTEM_BUS_DRIVER);
 #endif
+#ifdef DEBUG
+       debugfs_remove(ehci_debug_root);
+#endif
 }
 module_exit(ehci_hcd_cleanup);
 
index 735db4aec831cc2302a761801f51eccc25efdeb7..40e8240b7851f012e0e4fe9e71c37ab27d99d67a 100644 (file)
@@ -123,6 +123,8 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
 
        if (time_before (jiffies, ehci->next_statechange))
                msleep(5);
+       del_timer_sync(&ehci->watchdog);
+       del_timer_sync(&ehci->iaa_watchdog);
 
        port = HCS_N_PORTS (ehci->hcs_params);
        spin_lock_irq (&ehci->lock);
@@ -134,7 +136,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
        }
        ehci->command = ehci_readl(ehci, &ehci->regs->command);
        if (ehci->reclaim)
-               ehci->reclaim_ready = 1;
+               end_unlink_async(ehci);
        ehci_work(ehci);
 
        /* Unlike other USB host controller types, EHCI doesn't have
@@ -170,8 +172,11 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
                }
        }
 
+       /* Apparently some devices need a >= 1-uframe delay here */
+       if (ehci->bus_suspended)
+               udelay(150);
+
        /* turn off now-idle HC */
-       del_timer_sync (&ehci->watchdog);
        ehci_halt (ehci);
        hcd->state = HC_STATE_SUSPENDED;
 
@@ -291,14 +296,16 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
 /*-------------------------------------------------------------------------*/
 
 /* Display the ports dedicated to the companion controller */
-static ssize_t show_companion(struct class_device *class_dev, char *buf)
+static ssize_t show_companion(struct device *dev,
+                             struct device_attribute *attr,
+                             char *buf)
 {
        struct ehci_hcd         *ehci;
        int                     nports, index, n;
        int                     count = PAGE_SIZE;
        char                    *ptr = buf;
 
-       ehci = hcd_to_ehci(bus_to_hcd(class_get_devdata(class_dev)));
+       ehci = hcd_to_ehci(bus_to_hcd(dev_get_drvdata(dev)));
        nports = HCS_N_PORTS(ehci->hcs_params);
 
        for (index = 0; index < nports; ++index) {
@@ -312,40 +319,21 @@ static ssize_t show_companion(struct class_device *class_dev, char *buf)
 }
 
 /*
- * Dedicate or undedicate a port to the companion controller.
- * Syntax is "[-]portnum", where a leading '-' sign means
- * return control of the port to the EHCI controller.
+ * Sets the owner of a port
  */
-static ssize_t store_companion(struct class_device *class_dev,
-               const char *buf, size_t count)
+static void set_owner(struct ehci_hcd *ehci, int portnum, int new_owner)
 {
-       struct ehci_hcd         *ehci;
-       int                     portnum, new_owner, try;
        u32 __iomem             *status_reg;
        u32                     port_status;
+       int                     try;
 
-       ehci = hcd_to_ehci(bus_to_hcd(class_get_devdata(class_dev)));
-       new_owner = PORT_OWNER;         /* Owned by companion */
-       if (sscanf(buf, "%d", &portnum) != 1)
-               return -EINVAL;
-       if (portnum < 0) {
-               portnum = - portnum;
-               new_owner = 0;          /* Owned by EHCI */
-       }
-       if (portnum <= 0 || portnum > HCS_N_PORTS(ehci->hcs_params))
-               return -ENOENT;
-       status_reg = &ehci->regs->port_status[--portnum];
-       if (new_owner)
-               set_bit(portnum, &ehci->companion_ports);
-       else
-               clear_bit(portnum, &ehci->companion_ports);
+       status_reg = &ehci->regs->port_status[portnum];
 
        /*
         * The controller won't set the OWNER bit if the port is
         * enabled, so this loop will sometimes require at least two
         * iterations: one to disable the port and one to set OWNER.
         */
-
        for (try = 4; try > 0; --try) {
                spin_lock_irq(&ehci->lock);
                port_status = ehci_readl(ehci, status_reg);
@@ -362,9 +350,39 @@ static ssize_t store_companion(struct class_device *class_dev,
                if (try > 1)
                        msleep(5);
        }
+}
+
+/*
+ * Dedicate or undedicate a port to the companion controller.
+ * Syntax is "[-]portnum", where a leading '-' sign means
+ * return control of the port to the EHCI controller.
+ */
+static ssize_t store_companion(struct device *dev,
+                              struct device_attribute *attr,
+                              const char *buf, size_t count)
+{
+       struct ehci_hcd         *ehci;
+       int                     portnum, new_owner;
+
+       ehci = hcd_to_ehci(bus_to_hcd(dev_get_drvdata(dev)));
+       new_owner = PORT_OWNER;         /* Owned by companion */
+       if (sscanf(buf, "%d", &portnum) != 1)
+               return -EINVAL;
+       if (portnum < 0) {
+               portnum = - portnum;
+               new_owner = 0;          /* Owned by EHCI */
+       }
+       if (portnum <= 0 || portnum > HCS_N_PORTS(ehci->hcs_params))
+               return -ENOENT;
+       portnum--;
+       if (new_owner)
+               set_bit(portnum, &ehci->companion_ports);
+       else
+               clear_bit(portnum, &ehci->companion_ports);
+       set_owner(ehci, portnum, new_owner);
        return count;
 }
-static CLASS_DEVICE_ATTR(companion, 0644, show_companion, store_companion);
+static DEVICE_ATTR(companion, 0644, show_companion, store_companion);
 
 static inline void create_companion_file(struct ehci_hcd *ehci)
 {
@@ -372,16 +390,16 @@ static inline void create_companion_file(struct ehci_hcd *ehci)
 
        /* with integrated TT there is no companion! */
        if (!ehci_is_TDI(ehci))
-               i = class_device_create_file(ehci_to_hcd(ehci)->self.class_dev,
-                               &class_device_attr_companion);
+               i = device_create_file(ehci_to_hcd(ehci)->self.dev,
+                                      &dev_attr_companion);
 }
 
 static inline void remove_companion_file(struct ehci_hcd *ehci)
 {
        /* with integrated TT there is no companion! */
        if (!ehci_is_TDI(ehci))
-               class_device_remove_file(ehci_to_hcd(ehci)->self.class_dev,
-                               &class_device_attr_companion);
+               device_remove_file(ehci_to_hcd(ehci)->self.dev,
+                                  &dev_attr_companion);
 }
 
 
@@ -393,10 +411,8 @@ static int check_reset_complete (
        u32 __iomem     *status_reg,
        int             port_status
 ) {
-       if (!(port_status & PORT_CONNECT)) {
-               ehci->reset_done [index] = 0;
+       if (!(port_status & PORT_CONNECT))
                return port_status;
-       }
 
        /* if reset finished and it's still not enabled -- handoff */
        if (!(port_status & PORT_PE)) {
@@ -475,8 +491,6 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf)
                 * controller by the user.
                 */
 
-               if (!(temp & PORT_CONNECT))
-                       ehci->reset_done [i] = 0;
                if ((temp & mask) != 0
                                || ((temp & PORT_RESUME) != 0
                                        && time_after_eq(jiffies,
@@ -864,3 +878,13 @@ error:
        spin_unlock_irqrestore (&ehci->lock, flags);
        return retval;
 }
+
+static void ehci_relinquish_port(struct usb_hcd *hcd, int portnum)
+{
+       struct ehci_hcd         *ehci = hcd_to_ehci(hcd);
+
+       if (ehci_is_TDI(ehci))
+               return;
+       set_owner(ehci, --portnum, PORT_OWNER);
+}
+
diff --git a/drivers/usb/host/ehci-ixp4xx.c b/drivers/usb/host/ehci-ixp4xx.c
new file mode 100644 (file)
index 0000000..3041d8f
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+ * IXP4XX EHCI Host Controller Driver
+ *
+ * Author: Vladimir Barinov <vbarinov@ru.mvista.com>
+ *
+ * Based on "ehci-fsl.c" by Randy Vinson <rvinson@mvista.com>
+ *
+ * 2007 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+
+#include <linux/platform_device.h>
+
+static int ixp4xx_ehci_init(struct usb_hcd *hcd)
+{
+       struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+       int retval = 0;
+
+       ehci->big_endian_desc = 1;
+       ehci->big_endian_mmio = 1;
+
+       ehci->caps = hcd->regs + 0x100;
+       ehci->regs = hcd->regs + 0x100
+               + HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
+       ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
+
+       ehci->is_tdi_rh_tt = 1;
+       ehci_reset(ehci);
+
+       retval = ehci_init(hcd);
+       if (retval)
+               return retval;
+
+       ehci_port_power(ehci, 0);
+
+       return retval;
+}
+
+static const struct hc_driver ixp4xx_ehci_hc_driver = {
+       .description            = hcd_name,
+       .product_desc           = "IXP4XX EHCI Host Controller",
+       .hcd_priv_size          = sizeof(struct ehci_hcd),
+       .irq                    = ehci_irq,
+       .flags                  = HCD_MEMORY | HCD_USB2,
+       .reset                  = ixp4xx_ehci_init,
+       .start                  = ehci_run,
+       .stop                   = ehci_stop,
+       .shutdown               = ehci_shutdown,
+       .urb_enqueue            = ehci_urb_enqueue,
+       .urb_dequeue            = ehci_urb_dequeue,
+       .endpoint_disable       = ehci_endpoint_disable,
+       .get_frame_number       = ehci_get_frame,
+       .hub_status_data        = ehci_hub_status_data,
+       .hub_control            = ehci_hub_control,
+#if defined(CONFIG_PM)
+       .bus_suspend            = ehci_bus_suspend,
+       .bus_resume             = ehci_bus_resume,
+#endif
+};
+
+static int ixp4xx_ehci_probe(struct platform_device *pdev)
+{
+       struct usb_hcd *hcd;
+       const struct hc_driver *driver = &ixp4xx_ehci_hc_driver;
+       struct resource *res;
+       int irq;
+       int retval;
+
+       if (usb_disabled())
+               return -ENODEV;
+
+       res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (!res) {
+               dev_err(&pdev->dev,
+                       "Found HC with no IRQ. Check %s setup!\n",
+                       pdev->dev.bus_id);
+               return -ENODEV;
+       }
+       irq = res->start;
+
+       hcd = usb_create_hcd(driver, &pdev->dev, pdev->dev.bus_id);
+       if (!hcd) {
+               retval = -ENOMEM;
+               goto fail_create_hcd;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(&pdev->dev,
+                       "Found HC with no register addr. Check %s setup!\n",
+                       pdev->dev.bus_id);
+               retval = -ENODEV;
+               goto fail_request_resource;
+       }
+       hcd->rsrc_start = res->start;
+       hcd->rsrc_len = res->end - res->start + 1;
+
+       if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len,
+                               driver->description)) {
+               dev_dbg(&pdev->dev, "controller already in use\n");
+               retval = -EBUSY;
+               goto fail_request_resource;
+       }
+
+       hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);
+       if (hcd->regs == NULL) {
+               dev_dbg(&pdev->dev, "error mapping memory\n");
+               retval = -EFAULT;
+               goto fail_ioremap;
+       }
+
+       retval = usb_add_hcd(hcd, irq, IRQF_SHARED);
+       if (retval)
+               goto fail_add_hcd;
+
+       return retval;
+
+fail_add_hcd:
+       iounmap(hcd->regs);
+fail_ioremap:
+       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+fail_request_resource:
+       usb_put_hcd(hcd);
+fail_create_hcd:
+       dev_err(&pdev->dev, "init %s fail, %d\n", pdev->dev.bus_id, retval);
+       return retval;
+}
+
+static int ixp4xx_ehci_remove(struct platform_device *pdev)
+{
+       struct usb_hcd *hcd = platform_get_drvdata(pdev);
+
+       usb_remove_hcd(hcd);
+       iounmap(hcd->regs);
+       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+       usb_put_hcd(hcd);
+
+       return 0;
+}
+
+MODULE_ALIAS("ixp4xx-ehci");
+
+static struct platform_driver ixp4xx_ehci_driver = {
+       .probe = ixp4xx_ehci_probe,
+       .remove = ixp4xx_ehci_remove,
+       .driver = {
+               .name = "ixp4xx-ehci",
+               .bus = &platform_bus_type
+       },
+};
diff --git a/drivers/usb/host/ehci-orion.c b/drivers/usb/host/ehci-orion.c
new file mode 100644 (file)
index 0000000..e129981
--- /dev/null
@@ -0,0 +1,272 @@
+/*
+ * drivers/usb/host/ehci-orion.c
+ *
+ * Tzachi Perelstein <tzachi@marvell.com>
+ *
+ * This file is licensed under  the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <asm/arch/orion.h>
+
+#define rdl(off)       __raw_readl(hcd->regs + (off))
+#define wrl(off, val)  __raw_writel((val), hcd->regs + (off))
+
+#define USB_CAUSE              0x310
+#define USB_MASK               0x314
+#define USB_CMD                        0x140
+#define USB_MODE               0x1a8
+#define USB_IPG                        0x360
+#define USB_PHY_PWR_CTRL       0x400
+#define USB_PHY_TX_CTRL                0x420
+#define USB_PHY_RX_CTRL                0x430
+#define USB_PHY_IVREF_CTRL     0x440
+#define USB_PHY_TST_GRP_CTRL   0x450
+
+/*
+ * Implement Orion USB controller specification guidelines
+ */
+static void orion_usb_setup(struct usb_hcd *hcd)
+{
+       /*
+        * Clear interrupt cause and mask
+        */
+       wrl(USB_CAUSE, 0);
+       wrl(USB_MASK, 0);
+
+       /*
+        * Reset controller
+        */
+       wrl(USB_CMD, rdl(USB_CMD) | 0x2);
+       while (rdl(USB_CMD) & 0x2);
+
+       /*
+        * GL# USB-10: Set IPG for non start of frame packets
+        * Bits[14:8]=0xc
+        */
+       wrl(USB_IPG, (rdl(USB_IPG) & ~0x7f00) | 0xc00);
+
+       /*
+        * GL# USB-9: USB 2.0 Power Control
+        * BG_VSEL[7:6]=0x1
+        */
+       wrl(USB_PHY_PWR_CTRL, (rdl(USB_PHY_PWR_CTRL) & ~0xc0)| 0x40);
+
+       /*
+        * GL# USB-1: USB PHY Tx Control - force calibration to '8'
+        * TXDATA_BLOCK_EN[21]=0x1, EXT_RCAL_EN[13]=0x1, IMP_CAL[6:3]=0x8
+        */
+       wrl(USB_PHY_TX_CTRL, (rdl(USB_PHY_TX_CTRL) & ~0x78) | 0x202040);
+
+       /*
+        * GL# USB-3 GL# USB-9: USB PHY Rx Control
+        * RXDATA_BLOCK_LENGHT[31:30]=0x3, EDGE_DET_SEL[27:26]=0,
+        * CDR_FASTLOCK_EN[21]=0, DISCON_THRESHOLD[9:8]=0, SQ_THRESH[7:4]=0x1
+        */
+       wrl(USB_PHY_RX_CTRL, (rdl(USB_PHY_RX_CTRL) & ~0xc2003f0) | 0xc0000010);
+
+       /*
+        * GL# USB-3 GL# USB-9: USB PHY IVREF Control
+        * PLLVDD12[1:0]=0x2, RXVDD[5:4]=0x3, Reserved[19]=0
+        */
+       wrl(USB_PHY_IVREF_CTRL, (rdl(USB_PHY_IVREF_CTRL) & ~0x80003 ) | 0x32);
+
+       /*
+        * GL# USB-3 GL# USB-9: USB PHY Test Group Control
+        * REG_FIFO_SQ_RST[15]=0
+        */
+       wrl(USB_PHY_TST_GRP_CTRL, rdl(USB_PHY_TST_GRP_CTRL) & ~0x8000);
+
+       /*
+        * Stop and reset controller
+        */
+       wrl(USB_CMD, rdl(USB_CMD) & ~0x1);
+       wrl(USB_CMD, rdl(USB_CMD) | 0x2);
+       while (rdl(USB_CMD) & 0x2);
+
+       /*
+        * GL# USB-5 Streaming disable REG_USB_MODE[4]=1
+        * TBD: This need to be done after each reset!
+        * GL# USB-4 Setup USB Host mode
+        */
+       wrl(USB_MODE, 0x13);
+}
+
+static int ehci_orion_setup(struct usb_hcd *hcd)
+{
+       struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+       int retval;
+
+       retval = ehci_halt(ehci);
+       if (retval)
+               return retval;
+
+       /*
+        * data structure init
+        */
+       retval = ehci_init(hcd);
+       if (retval)
+               return retval;
+
+       ehci_reset(ehci);
+       ehci_port_power(ehci, 0);
+
+       return retval;
+}
+
+static const struct hc_driver ehci_orion_hc_driver = {
+       .description = hcd_name,
+       .product_desc = "Marvell Orion EHCI",
+       .hcd_priv_size = sizeof(struct ehci_hcd),
+
+       /*
+        * generic hardware linkage
+        */
+       .irq = ehci_irq,
+       .flags = HCD_MEMORY | HCD_USB2,
+
+       /*
+        * basic lifecycle operations
+        */
+       .reset = ehci_orion_setup,
+       .start = ehci_run,
+#ifdef CONFIG_PM
+       .suspend = ehci_bus_suspend,
+       .resume = ehci_bus_resume,
+#endif
+       .stop = ehci_stop,
+       .shutdown = ehci_shutdown,
+
+       /*
+        * managing i/o requests and associated device resources
+        */
+       .urb_enqueue = ehci_urb_enqueue,
+       .urb_dequeue = ehci_urb_dequeue,
+       .endpoint_disable = ehci_endpoint_disable,
+
+       /*
+        * scheduling support
+        */
+       .get_frame_number = ehci_get_frame,
+
+       /*
+        * root hub support
+        */
+       .hub_status_data = ehci_hub_status_data,
+       .hub_control = ehci_hub_control,
+       .bus_suspend = ehci_bus_suspend,
+       .bus_resume = ehci_bus_resume,
+};
+
+static int __init ehci_orion_drv_probe(struct platform_device *pdev)
+{
+       struct resource *res;
+       struct usb_hcd *hcd;
+       struct ehci_hcd *ehci;
+       void __iomem *regs;
+       int irq, err;
+
+       if (usb_disabled())
+               return -ENODEV;
+
+       pr_debug("Initializing Orion-SoC USB Host Controller\n");
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq <= 0) {
+               dev_err(&pdev->dev,
+                       "Found HC with no IRQ. Check %s setup!\n",
+                       pdev->dev.bus_id);
+               err = -ENODEV;
+               goto err1;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(&pdev->dev,
+                       "Found HC with no register addr. Check %s setup!\n",
+                       pdev->dev.bus_id);
+               err = -ENODEV;
+               goto err1;
+       }
+
+       if (!request_mem_region(res->start, res->end - res->start + 1,
+                               ehci_orion_hc_driver.description)) {
+               dev_dbg(&pdev->dev, "controller already in use\n");
+               err = -EBUSY;
+               goto err1;
+       }
+
+       regs = ioremap(res->start, res->end - res->start + 1);
+       if (regs == NULL) {
+               dev_dbg(&pdev->dev, "error mapping memory\n");
+               err = -EFAULT;
+               goto err2;
+       }
+
+       hcd = usb_create_hcd(&ehci_orion_hc_driver,
+                       &pdev->dev, pdev->dev.bus_id);
+       if (!hcd) {
+               err = -ENOMEM;
+               goto err3;
+       }
+
+       hcd->rsrc_start = res->start;
+       hcd->rsrc_len = res->end - res->start + 1;
+       hcd->regs = regs;
+
+       ehci = hcd_to_ehci(hcd);
+       ehci->caps = hcd->regs + 0x100;
+       ehci->regs = hcd->regs + 0x100 +
+               HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
+       ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
+       ehci->is_tdi_rh_tt = 1;
+       ehci->sbrn = 0x20;
+
+       /*
+        * setup Orion USB controller
+        */
+       orion_usb_setup(hcd);
+
+       err = usb_add_hcd(hcd, irq, IRQF_SHARED | IRQF_DISABLED);
+       if (err)
+               goto err4;
+
+       return 0;
+
+err4:
+       usb_put_hcd(hcd);
+err3:
+       iounmap(regs);
+err2:
+       release_mem_region(res->start, res->end - res->start + 1);
+err1:
+       dev_err(&pdev->dev, "init %s fail, %d\n",
+               pdev->dev.bus_id, err);
+
+       return err;
+}
+
+static int __exit ehci_orion_drv_remove(struct platform_device *pdev)
+{
+       struct usb_hcd *hcd = platform_get_drvdata(pdev);
+
+       usb_remove_hcd(hcd);
+       iounmap(hcd->regs);
+       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+       usb_put_hcd(hcd);
+
+       return 0;
+}
+
+MODULE_ALIAS("platform:orion-ehci");
+
+static struct platform_driver ehci_orion_driver = {
+       .probe          = ehci_orion_drv_probe,
+       .remove         = __exit_p(ehci_orion_drv_remove),
+       .shutdown       = usb_hcd_platform_shutdown,
+       .driver.name    = "orion-ehci",
+};
index ad0d4965f2fb5df834cc54d0f5b6eed29d1e5e3b..3ba01664f82154b00bef518eea7c3e809566f63b 100644 (file)
@@ -305,7 +305,7 @@ static int ehci_pci_resume(struct usb_hcd *hcd)
        /* emptying the schedule aborts any urbs */
        spin_lock_irq(&ehci->lock);
        if (ehci->reclaim)
-               ehci->reclaim_ready = 1;
+               end_unlink_async(ehci);
        ehci_work(ehci);
        spin_unlock_irq(&ehci->lock);
 
@@ -364,6 +364,7 @@ static const struct hc_driver ehci_pci_hc_driver = {
        .hub_control =          ehci_hub_control,
        .bus_suspend =          ehci_bus_suspend,
        .bus_resume =           ehci_bus_resume,
+       .relinquish_port =      ehci_relinquish_port,
 };
 
 /*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/host/ehci-ppc-of.c b/drivers/usb/host/ehci-ppc-of.c
new file mode 100644 (file)
index 0000000..ee305b1
--- /dev/null
@@ -0,0 +1,238 @@
+/*
+ * EHCI HCD (Host Controller Driver) for USB.
+ *
+ * Bus Glue for PPC On-Chip EHCI driver on the of_platform bus
+ * Tested on AMCC PPC 440EPx
+ *
+ * Valentine Barshak <vbarshak@ru.mvista.com>
+ *
+ * Based on "ehci-ppc-soc.c" by Stefan Roese <sr@denx.de>
+ * and "ohci-ppc-of.c" by Sylvain Munaut <tnt@246tNt.com>
+ *
+ * This file is licenced under the GPL.
+ */
+
+#include <linux/signal.h>
+
+#include <linux/of.h>
+#include <linux/of_platform.h>
+
+/* called during probe() after chip reset completes */
+static int ehci_ppc_of_setup(struct usb_hcd *hcd)
+{
+       struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+       int             retval;
+
+       retval = ehci_halt(ehci);
+       if (retval)
+               return retval;
+
+       retval = ehci_init(hcd);
+       if (retval)
+               return retval;
+
+       ehci->sbrn = 0x20;
+       return ehci_reset(ehci);
+}
+
+
+static const struct hc_driver ehci_ppc_of_hc_driver = {
+       .description            = hcd_name,
+       .product_desc           = "OF EHCI",
+       .hcd_priv_size          = sizeof(struct ehci_hcd),
+
+       /*
+        * generic hardware linkage
+        */
+       .irq                    = ehci_irq,
+       .flags                  = HCD_MEMORY | HCD_USB2,
+
+       /*
+        * basic lifecycle operations
+        */
+       .reset                  = ehci_ppc_of_setup,
+       .start                  = ehci_run,
+       .stop                   = ehci_stop,
+       .shutdown               = ehci_shutdown,
+
+       /*
+        * managing i/o requests and associated device resources
+        */
+       .urb_enqueue            = ehci_urb_enqueue,
+       .urb_dequeue            = ehci_urb_dequeue,
+       .endpoint_disable       = ehci_endpoint_disable,
+
+       /*
+        * scheduling support
+        */
+       .get_frame_number       = ehci_get_frame,
+
+       /*
+        * root hub support
+        */
+       .hub_status_data        = ehci_hub_status_data,
+       .hub_control            = ehci_hub_control,
+#ifdef CONFIG_PM
+       .bus_suspend            = ehci_bus_suspend,
+       .bus_resume             = ehci_bus_resume,
+#endif
+};
+
+
+/*
+ * 440EPx Errata USBH_3
+ * Fix: Enable Break Memory Transfer (BMT) in INSNREG3
+ */
+#define PPC440EPX_EHCI0_INSREG_BMT     (0x1 << 0)
+static int __devinit
+ppc44x_enable_bmt(struct device_node *dn)
+{
+       __iomem u32 *insreg_virt;
+
+       insreg_virt = of_iomap(dn, 1);
+       if (!insreg_virt)
+               return  -EINVAL;
+
+       out_be32(insreg_virt + 3, PPC440EPX_EHCI0_INSREG_BMT);
+
+       iounmap(insreg_virt);
+       return 0;
+}
+
+
+static int __devinit
+ehci_hcd_ppc_of_probe(struct of_device *op, const struct of_device_id *match)
+{
+       struct device_node *dn = op->node;
+       struct usb_hcd *hcd;
+       struct ehci_hcd *ehci;
+       struct resource res;
+       int irq;
+       int rv;
+
+       if (usb_disabled())
+               return -ENODEV;
+
+       dev_dbg(&op->dev, "initializing PPC-OF USB Controller\n");
+
+       rv = of_address_to_resource(dn, 0, &res);
+       if (rv)
+               return rv;
+
+       hcd = usb_create_hcd(&ehci_ppc_of_hc_driver, &op->dev, "PPC-OF USB");
+       if (!hcd)
+               return -ENOMEM;
+
+       hcd->rsrc_start = res.start;
+       hcd->rsrc_len = res.end - res.start + 1;
+
+       if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
+               printk(KERN_ERR __FILE__ ": request_mem_region failed\n");
+               rv = -EBUSY;
+               goto err_rmr;
+       }
+
+       irq = irq_of_parse_and_map(dn, 0);
+       if (irq == NO_IRQ) {
+               printk(KERN_ERR __FILE__ ": irq_of_parse_and_map failed\n");
+               rv = -EBUSY;
+               goto err_irq;
+       }
+
+       hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+       if (!hcd->regs) {
+               printk(KERN_ERR __FILE__ ": ioremap failed\n");
+               rv = -ENOMEM;
+               goto err_ioremap;
+       }
+
+       ehci = hcd_to_ehci(hcd);
+
+       if (of_get_property(dn, "big-endian", NULL)) {
+               ehci->big_endian_mmio = 1;
+               ehci->big_endian_desc = 1;
+       }
+       if (of_get_property(dn, "big-endian-regs", NULL))
+               ehci->big_endian_mmio = 1;
+       if (of_get_property(dn, "big-endian-desc", NULL))
+               ehci->big_endian_desc = 1;
+
+       ehci->caps = hcd->regs;
+       ehci->regs = hcd->regs +
+                       HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
+
+       /* cache this readonly data; minimize chip reads */
+       ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
+
+       if (of_device_is_compatible(dn, "ibm,usb-ehci-440epx")) {
+               rv = ppc44x_enable_bmt(dn);
+               ehci_dbg(ehci, "Break Memory Transfer (BMT) is %senabled!\n",
+                               rv ? "NOT ": "");
+       }
+
+       rv = usb_add_hcd(hcd, irq, 0);
+       if (rv == 0)
+               return 0;
+
+       iounmap(hcd->regs);
+err_ioremap:
+       irq_dispose_mapping(irq);
+err_irq:
+       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+err_rmr:
+       usb_put_hcd(hcd);
+
+       return rv;
+}
+
+
+static int ehci_hcd_ppc_of_remove(struct of_device *op)
+{
+       struct usb_hcd *hcd = dev_get_drvdata(&op->dev);
+       dev_set_drvdata(&op->dev, NULL);
+
+       dev_dbg(&op->dev, "stopping PPC-OF USB Controller\n");
+
+       usb_remove_hcd(hcd);
+
+       iounmap(hcd->regs);
+       irq_dispose_mapping(hcd->irq);
+       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+
+       usb_put_hcd(hcd);
+
+       return 0;
+}
+
+
+static int ehci_hcd_ppc_of_shutdown(struct of_device *op)
+{
+       struct usb_hcd *hcd = dev_get_drvdata(&op->dev);
+
+       if (hcd->driver->shutdown)
+               hcd->driver->shutdown(hcd);
+
+       return 0;
+}
+
+
+static struct of_device_id ehci_hcd_ppc_of_match[] = {
+       {
+               .compatible = "usb-ehci",
+       },
+       {},
+};
+MODULE_DEVICE_TABLE(of, ehci_hcd_ppc_of_match);
+
+
+static struct of_platform_driver ehci_hcd_ppc_of_driver = {
+       .name           = "ppc-of-ehci",
+       .match_table    = ehci_hcd_ppc_of_match,
+       .probe          = ehci_hcd_ppc_of_probe,
+       .remove         = ehci_hcd_ppc_of_remove,
+       .shutdown       = ehci_hcd_ppc_of_shutdown,
+       .driver         = {
+               .name   = "ppc-of-ehci",
+               .owner  = THIS_MODULE,
+       },
+};
index 452d4b1bc85927e4d21c3bb91caea7e14dc16d8a..a3249078c8085af2d7aa28be8fb739c2e8fcb788 100644 (file)
@@ -162,6 +162,7 @@ static const struct hc_driver ehci_ppc_soc_hc_driver = {
        .hub_control = ehci_hub_control,
        .bus_suspend = ehci_bus_suspend,
        .bus_resume = ehci_bus_resume,
+       .relinquish_port = ehci_relinquish_port,
 };
 
 static int ehci_hcd_ppc_soc_drv_probe(struct platform_device *pdev)
index 03a6b2f4e6ed81e722d855ee3bc76bdf6242648e..bbda58eb881304052be475a0604c682cd87d6041 100644 (file)
@@ -72,6 +72,7 @@ static const struct hc_driver ps3_ehci_hc_driver = {
        .bus_suspend            = ehci_bus_suspend,
        .bus_resume             = ehci_bus_resume,
 #endif
+       .relinquish_port        = ehci_relinquish_port,
 };
 
 static int ps3_ehci_probe(struct ps3_system_bus_device *dev)
index b10f39c047e944848f3ac2aa4067e820d2f5df90..776a97f33914e05511bc85dcdced2b4febe6a89b 100644 (file)
@@ -198,7 +198,8 @@ static int qtd_copy_status (
 
                /* if async CSPLIT failed, try cleaning out the TT buffer */
                if (status != -EPIPE
-                               && urb->dev->tt && !usb_pipeint (urb->pipe)
+                               && urb->dev->tt
+                               && !usb_pipeint(urb->pipe)
                                && ((token & QTD_STS_MMF) != 0
                                        || QTD_CERR(token) == 0)
                                && (!ehci_is_TDI(ehci)
@@ -211,6 +212,9 @@ static int qtd_copy_status (
                                urb->dev->ttport, urb->dev->devnum,
                                usb_pipeendpoint (urb->pipe), token);
 #endif /* DEBUG */
+                       /* REVISIT ARC-derived cores don't clear the root
+                        * hub TT buffer in this way...
+                        */
                        usb_hub_tt_clear_buffer (urb->dev, urb->pipe);
                }
        }
@@ -638,6 +642,7 @@ qh_make (
        u32                     info1 = 0, info2 = 0;
        int                     is_input, type;
        int                     maxp = 0;
+       struct usb_tt           *tt = urb->dev->tt;
 
        if (!qh)
                return qh;
@@ -661,8 +666,9 @@ qh_make (
         * For control/bulk requests, the HC or TT handles these.
         */
        if (type == PIPE_INTERRUPT) {
-               qh->usecs = NS_TO_US (usb_calc_bus_time (USB_SPEED_HIGH, is_input, 0,
-                               hb_mult (maxp) * max_packet (maxp)));
+               qh->usecs = NS_TO_US(usb_calc_bus_time(USB_SPEED_HIGH,
+                               is_input, 0,
+                               hb_mult(maxp) * max_packet(maxp)));
                qh->start = NO_FRAME;
 
                if (urb->dev->speed == USB_SPEED_HIGH) {
@@ -680,7 +686,6 @@ qh_make (
                                goto done;
                        }
                } else {
-                       struct usb_tt   *tt = urb->dev->tt;
                        int             think_time;
 
                        /* gap is f(FS/LS transfer times) */
@@ -736,10 +741,8 @@ qh_make (
                /* set the address of the TT; for TDI's integrated
                 * root hub tt, leave it zeroed.
                 */
-               if (!ehci_is_TDI(ehci)
-                               || urb->dev->tt->hub !=
-                                       ehci_to_hcd(ehci)->self.root_hub)
-                       info2 |= urb->dev->tt->hub->devnum << 16;
+               if (tt && tt->hub != ehci_to_hcd(ehci)->self.root_hub)
+                       info2 |= tt->hub->devnum << 16;
 
                /* NOTE:  if (PIPE_INTERRUPT) { scheduler sets c-mask } */
 
@@ -973,7 +976,7 @@ static void end_unlink_async (struct ehci_hcd *ehci)
        struct ehci_qh          *qh = ehci->reclaim;
        struct ehci_qh          *next;
 
-       timer_action_done (ehci, TIMER_IAA_WATCHDOG);
+       iaa_watchdog_done(ehci);
 
        // qh->hw_next = cpu_to_hc32(qh->qh_dma);
        qh->qh_state = QH_STATE_IDLE;
@@ -983,7 +986,6 @@ static void end_unlink_async (struct ehci_hcd *ehci)
        /* other unlink(s) may be pending (in QH_STATE_UNLINK_WAIT) */
        next = qh->reclaim;
        ehci->reclaim = next;
-       ehci->reclaim_ready = 0;
        qh->reclaim = NULL;
 
        qh_completions (ehci, qh);
@@ -1059,11 +1061,10 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
                return;
        }
 
-       ehci->reclaim_ready = 0;
        cmd |= CMD_IAAD;
        ehci_writel(ehci, cmd, &ehci->regs->command);
        (void)ehci_readl(ehci, &ehci->regs->command);
-       timer_action (ehci, TIMER_IAA_WATCHDOG);
+       iaa_watchdog_start(ehci);
 }
 
 /*-------------------------------------------------------------------------*/
index 80d99bce2b38fb3d5a6459cdff8eeb5642fa0b06..8a8e08a51ba33cd55b57c127d550d7c54e40a5ca 100644 (file)
@@ -119,7 +119,8 @@ periodic_usecs (struct ehci_hcd *ehci, unsigned frame, unsigned uframe)
                        q = &q->fstn->fstn_next;
                        break;
                case Q_TYPE_ITD:
-                       usecs += q->itd->usecs [uframe];
+                       if (q->itd->hw_transaction[uframe])
+                               usecs += q->itd->stream->usecs;
                        hw_p = &q->itd->hw_next;
                        q = &q->itd->itd_next;
                        break;
@@ -211,7 +212,7 @@ static inline void carryover_tt_bandwidth(unsigned short tt_usecs[8])
  * low/fullspeed transfer can "carry over" from one uframe to the next,
  * since the TT just performs downstream transfers in sequence.
  *
- * For example two seperate 100 usec transfers can start in the same uframe,
+ * For example two separate 100 usec transfers can start in the same uframe,
  * and the second one would "carry over" 75 usecs into the next uframe.
  */
 static void
@@ -1536,7 +1537,6 @@ itd_link_urb (
                uframe = next_uframe & 0x07;
                frame = next_uframe >> 3;
 
-               itd->usecs [uframe] = stream->usecs;
                itd_patch(ehci, itd, iso_sched, packet, uframe);
 
                next_uframe += stream->interval;
@@ -1565,6 +1565,16 @@ itd_link_urb (
 
 #define        ISO_ERRS (EHCI_ISOC_BUF_ERR | EHCI_ISOC_BABBLE | EHCI_ISOC_XACTERR)
 
+/* Process and recycle a completed ITD.  Return true iff its urb completed,
+ * and hence its completion callback probably added things to the hardware
+ * schedule.
+ *
+ * Note that we carefully avoid recycling this descriptor until after any
+ * completion callback runs, so that it won't be reused quickly.  That is,
+ * assuming (a) no more than two urbs per frame on this endpoint, and also
+ * (b) only this endpoint's completions submit URBs.  It seems some silicon
+ * corrupts things if you reuse completed descriptors very quickly...
+ */
 static unsigned
 itd_complete (
        struct ehci_hcd *ehci,
@@ -1577,6 +1587,7 @@ itd_complete (
        int                                     urb_index = -1;
        struct ehci_iso_stream                  *stream = itd->stream;
        struct usb_device                       *dev;
+       unsigned                                retval = false;
 
        /* for each uframe with a packet */
        for (uframe = 0; uframe < 8; uframe++) {
@@ -1610,30 +1621,21 @@ itd_complete (
                }
        }
 
-       usb_put_urb (urb);
-       itd->urb = NULL;
-       itd->stream = NULL;
-       list_move (&itd->itd_list, &stream->free_list);
-       iso_stream_put (ehci, stream);
-
        /* handle completion now? */
        if (likely ((urb_index + 1) != urb->number_of_packets))
-               return 0;
+               goto done;
 
        /* ASSERT: it's really the last itd for this urb
        list_for_each_entry (itd, &stream->td_list, itd_list)
                BUG_ON (itd->urb == urb);
         */
 
-       /* give urb back to the driver ... can be out-of-order */
+       /* give urb back to the driver; completion often (re)submits */
        dev = urb->dev;
        ehci_urb_done(ehci, urb, 0);
+       retval = true;
        urb = NULL;
-
-       /* defer stopping schedule; completion can submit */
        ehci->periodic_sched--;
-       if (unlikely (!ehci->periodic_sched))
-               (void) disable_periodic (ehci);
        ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs--;
 
        if (unlikely (list_empty (&stream->td_list))) {
@@ -1645,8 +1647,15 @@ itd_complete (
                        (stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out");
        }
        iso_stream_put (ehci, stream);
+       /* OK to recycle this ITD now that its completion callback ran. */
+done:
+       usb_put_urb(urb);
+       itd->urb = NULL;
+       itd->stream = NULL;
+       list_move(&itd->itd_list, &stream->free_list);
+       iso_stream_put(ehci, stream);
 
-       return 1;
+       return retval;
 }
 
 /*-------------------------------------------------------------------------*/
@@ -1712,8 +1721,6 @@ done:
        return status;
 }
 
-#ifdef CONFIG_USB_EHCI_SPLIT_ISO
-
 /*-------------------------------------------------------------------------*/
 
 /*
@@ -1950,6 +1957,16 @@ sitd_link_urb (
 #define        SITD_ERRS (SITD_STS_ERR | SITD_STS_DBE | SITD_STS_BABBLE \
                                | SITD_STS_XACT | SITD_STS_MMF)
 
+/* Process and recycle a completed SITD.  Return true iff its urb completed,
+ * and hence its completion callback probably added things to the hardware
+ * schedule.
+ *
+ * Note that we carefully avoid recycling this descriptor until after any
+ * completion callback runs, so that it won't be reused quickly.  That is,
+ * assuming (a) no more than two urbs per frame on this endpoint, and also
+ * (b) only this endpoint's completions submit URBs.  It seems some silicon
+ * corrupts things if you reuse completed descriptors very quickly...
+ */
 static unsigned
 sitd_complete (
        struct ehci_hcd         *ehci,
@@ -1961,6 +1978,7 @@ sitd_complete (
        int                                     urb_index = -1;
        struct ehci_iso_stream                  *stream = sitd->stream;
        struct usb_device                       *dev;
+       unsigned                                retval = false;
 
        urb_index = sitd->index;
        desc = &urb->iso_frame_desc [urb_index];
@@ -1981,32 +1999,23 @@ sitd_complete (
                desc->status = 0;
                desc->actual_length = desc->length - SITD_LENGTH (t);
        }
-
-       usb_put_urb (urb);
-       sitd->urb = NULL;
-       sitd->stream = NULL;
-       list_move (&sitd->sitd_list, &stream->free_list);
        stream->depth -= stream->interval << 3;
-       iso_stream_put (ehci, stream);
 
        /* handle completion now? */
        if ((urb_index + 1) != urb->number_of_packets)
-               return 0;
+               goto done;
 
        /* ASSERT: it's really the last sitd for this urb
        list_for_each_entry (sitd, &stream->td_list, sitd_list)
                BUG_ON (sitd->urb == urb);
         */
 
-       /* give urb back to the driver */
+       /* give urb back to the driver; completion often (re)submits */
        dev = urb->dev;
        ehci_urb_done(ehci, urb, 0);
+       retval = true;
        urb = NULL;
-
-       /* defer stopping schedule; completion can submit */
        ehci->periodic_sched--;
-       if (!ehci->periodic_sched)
-               (void) disable_periodic (ehci);
        ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs--;
 
        if (list_empty (&stream->td_list)) {
@@ -2018,8 +2027,15 @@ sitd_complete (
                        (stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out");
        }
        iso_stream_put (ehci, stream);
+       /* OK to recycle this SITD now that its completion callback ran. */
+done:
+       usb_put_urb(urb);
+       sitd->urb = NULL;
+       sitd->stream = NULL;
+       list_move(&sitd->sitd_list, &stream->free_list);
+       iso_stream_put(ehci, stream);
 
-       return 1;
+       return retval;
 }
 
 
@@ -2082,26 +2098,6 @@ done:
        return status;
 }
 
-#else
-
-static inline int
-sitd_submit (struct ehci_hcd *ehci, struct urb *urb, gfp_t mem_flags)
-{
-       ehci_dbg (ehci, "split iso support is disabled\n");
-       return -ENOSYS;
-}
-
-static inline unsigned
-sitd_complete (
-       struct ehci_hcd         *ehci,
-       struct ehci_sitd        *sitd
-) {
-       ehci_err (ehci, "sitd_complete %p?\n", sitd);
-       return 0;
-}
-
-#endif /* USB_EHCI_SPLIT_ISO */
-
 /*-------------------------------------------------------------------------*/
 
 static void
@@ -2127,17 +2123,9 @@ scan_periodic (struct ehci_hcd *ehci)
        for (;;) {
                union ehci_shadow       q, *q_p;
                __hc32                  type, *hw_p;
-               unsigned                uframes;
+               unsigned                incomplete = false;
 
-               /* don't scan past the live uframe */
                frame = now_uframe >> 3;
-               if (frame == (clock >> 3))
-                       uframes = now_uframe & 0x07;
-               else {
-                       /* safe to scan the whole frame at once */
-                       now_uframe |= 0x07;
-                       uframes = 8;
-               }
 
 restart:
                /* scan each element in frame's queue for completions */
@@ -2175,12 +2163,15 @@ restart:
                                q = q.fstn->fstn_next;
                                break;
                        case Q_TYPE_ITD:
-                               /* skip itds for later in the frame */
+                               /* If this ITD is still active, leave it for
+                                * later processing ... check the next entry.
+                                */
                                rmb ();
-                               for (uf = live ? uframes : 8; uf < 8; uf++) {
+                               for (uf = 0; uf < 8 && live; uf++) {
                                        if (0 == (q.itd->hw_transaction [uf]
                                                        & ITD_ACTIVE(ehci)))
                                                continue;
+                                       incomplete = true;
                                        q_p = &q.itd->itd_next;
                                        hw_p = &q.itd->hw_next;
                                        type = Q_NEXT_TYPE(ehci,
@@ -2188,10 +2179,12 @@ restart:
                                        q = *q_p;
                                        break;
                                }
-                               if (uf != 8)
+                               if (uf < 8 && live)
                                        break;
 
-                               /* this one's ready ... HC won't cache the
+                               /* Take finished ITDs out of the schedule
+                                * and process them:  recycle, maybe report
+                                * URB completion.  HC won't cache the
                                 * pointer for much longer, if at all.
                                 */
                                *q_p = q.itd->itd_next;
@@ -2202,8 +2195,12 @@ restart:
                                q = *q_p;
                                break;
                        case Q_TYPE_SITD:
+                               /* If this SITD is still active, leave it for
+                                * later processing ... check the next entry.
+                                */
                                if ((q.sitd->hw_results & SITD_ACTIVE(ehci))
                                                && live) {
+                                       incomplete = true;
                                        q_p = &q.sitd->sitd_next;
                                        hw_p = &q.sitd->hw_next;
                                        type = Q_NEXT_TYPE(ehci,
@@ -2211,6 +2208,11 @@ restart:
                                        q = *q_p;
                                        break;
                                }
+
+                               /* Take finished SITDs out of the schedule
+                                * and process them:  recycle, maybe report
+                                * URB completion.
+                                */
                                *q_p = q.sitd->sitd_next;
                                *hw_p = q.sitd->hw_next;
                                type = Q_NEXT_TYPE(ehci, q.sitd->hw_next);
@@ -2226,11 +2228,24 @@ restart:
                        }
 
                        /* assume completion callbacks modify the queue */
-                       if (unlikely (modified))
-                               goto restart;
+                       if (unlikely (modified)) {
+                               if (likely(ehci->periodic_sched > 0))
+                                       goto restart;
+                               /* maybe we can short-circuit this scan! */
+                               disable_periodic(ehci);
+                               now_uframe = clock;
+                               break;
+                       }
                }
 
-               /* stop when we catch up to the HC */
+               /* If we can tell we caught up to the hardware, stop now.
+                * We can't advance our scan without collecting the ISO
+                * transfers that are still pending in this frame.
+                */
+               if (incomplete && HC_IS_RUNNING(ehci_to_hcd(ehci)->state)) {
+                       ehci->next_uframe = now_uframe;
+                       break;
+               }
 
                // FIXME:  this assumes we won't get lapped when
                // latencies climb; that should be rare, but...
@@ -2243,7 +2258,8 @@ restart:
                if (now_uframe == clock) {
                        unsigned        now;
 
-                       if (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state))
+                       if (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state)
+                                       || ehci->periodic_sched == 0)
                                break;
                        ehci->next_uframe = now_uframe;
                        now = ehci_readl(ehci, &ehci->regs->frame_index) % mod;
index 951d69fec513a2b12fa7c5f666844af4f0729128..bf92d209a1a9bad0091983ce0d35ff5ee0fc011e 100644 (file)
@@ -74,7 +74,6 @@ struct ehci_hcd {                     /* one per controller */
        /* async schedule support */
        struct ehci_qh          *async;
        struct ehci_qh          *reclaim;
-       unsigned                reclaim_ready : 1;
        unsigned                scanning : 1;
 
        /* periodic schedule support */
@@ -105,6 +104,7 @@ struct ehci_hcd {                   /* one per controller */
        struct dma_pool         *itd_pool;      /* itd per iso urb */
        struct dma_pool         *sitd_pool;     /* sitd per split iso urb */
 
+       struct timer_list       iaa_watchdog;
        struct timer_list       watchdog;
        unsigned long           actions;
        unsigned                stamp;
@@ -126,6 +126,14 @@ struct ehci_hcd {                  /* one per controller */
 #      define COUNT(x) do { (x)++; } while (0)
 #else
 #      define COUNT(x) do {} while (0)
+#endif
+
+       /* debug files */
+#ifdef DEBUG
+       struct dentry           *debug_dir;
+       struct dentry           *debug_async;
+       struct dentry           *debug_periodic;
+       struct dentry           *debug_registers;
 #endif
 };
 
@@ -140,9 +148,21 @@ static inline struct usb_hcd *ehci_to_hcd (struct ehci_hcd *ehci)
 }
 
 
+static inline void
+iaa_watchdog_start(struct ehci_hcd *ehci)
+{
+       WARN_ON(timer_pending(&ehci->iaa_watchdog));
+       mod_timer(&ehci->iaa_watchdog,
+                       jiffies + msecs_to_jiffies(EHCI_IAA_MSECS));
+}
+
+static inline void iaa_watchdog_done(struct ehci_hcd *ehci)
+{
+       del_timer(&ehci->iaa_watchdog);
+}
+
 enum ehci_timer_action {
        TIMER_IO_WATCHDOG,
-       TIMER_IAA_WATCHDOG,
        TIMER_ASYNC_SHRINK,
        TIMER_ASYNC_OFF,
 };
@@ -160,9 +180,6 @@ timer_action (struct ehci_hcd *ehci, enum ehci_timer_action action)
                unsigned long t;
 
                switch (action) {
-               case TIMER_IAA_WATCHDOG:
-                       t = EHCI_IAA_JIFFIES;
-                       break;
                case TIMER_IO_WATCHDOG:
                        t = EHCI_IO_JIFFIES;
                        break;
@@ -179,8 +196,7 @@ timer_action (struct ehci_hcd *ehci, enum ehci_timer_action action)
                // async queue SHRINK often precedes IAA.  while it's ready
                // to go OFF neither can matter, and afterwards the IO
                // watchdog stops unless there's still periodic traffic.
-               if (action != TIMER_IAA_WATCHDOG
-                               && t > ehci->watchdog.expires
+               if (time_before_eq(t, ehci->watchdog.expires)
                                && timer_pending (&ehci->watchdog))
                        return;
                mod_timer (&ehci->watchdog, t);
@@ -534,8 +550,8 @@ struct ehci_iso_stream {
         * trusting urb->interval == f(epdesc->bInterval) and
         * including the extra info for hw_bufp[0..2]
         */
-       u8                      interval;
        u8                      usecs, c_usecs;
+       u16                     interval;
        u16                     tt_usecs;
        u16                     maxp;
        u16                     raw_mask;
@@ -586,7 +602,6 @@ struct ehci_itd {
        unsigned                frame;          /* where scheduled */
        unsigned                pg;
        unsigned                index[8];       /* in urb->iso_frame_desc */
-       u8                      usecs[8];
 } __attribute__ ((aligned (32)));
 
 /*-------------------------------------------------------------------------*/
@@ -725,11 +740,16 @@ ehci_port_speed(struct ehci_hcd *ehci, unsigned int portsc)
  * definition below can die once the 4xx support is
  * finally ported over.
  */
-#if defined(CONFIG_PPC)
+#if defined(CONFIG_PPC) && !defined(CONFIG_PPC_MERGE)
 #define readl_be(addr)         in_be32((__force unsigned *)addr)
 #define writel_be(val, addr)   out_be32((__force unsigned *)addr, val)
 #endif
 
+#if defined(CONFIG_ARM) && defined(CONFIG_ARCH_IXP4XX)
+#define readl_be(addr)         __raw_readl((__force unsigned *)addr)
+#define writel_be(val, addr)   __raw_writel(val, (__force unsigned *)addr)
+#endif
+
 static inline unsigned int ehci_readl(const struct ehci_hcd *ehci,
                __u32 __iomem * regs)
 {
index c27417f5b9d8635320a491bd5fbdad1c8f4b366c..0130fd8571e4018549db9a5003bd432b72645878 100644 (file)
@@ -918,7 +918,6 @@ static int isp116x_hub_status_data(struct usb_hcd *hcd, char *buf)
                              | RH_PS_OCIC | RH_PS_PRSC)) {
                        changed = 1;
                        buf[0] |= 1 << (i + 1);
-                       continue;
                }
        }
        spin_unlock_irqrestore(&isp116x->lock, flags);
index d849c809acbdca97394fa7b8dcd8225733a91f5a..126fcbdd6408a2fed44fec58a0b3c74798200d0e 100644 (file)
@@ -17,6 +17,8 @@
 
 #include <asm/mach-types.h>
 #include <asm/hardware.h>
+#include <asm/gpio.h>
+
 #include <asm/arch/board.h>
 #include <asm/arch/cpu.h>
 
@@ -271,12 +273,41 @@ static const struct hc_driver ohci_at91_hc_driver = {
 
 static int ohci_hcd_at91_drv_probe(struct platform_device *pdev)
 {
+       struct at91_usbh_data   *pdata = pdev->dev.platform_data;
+       int                     i;
+
+       if (pdata) {
+               /* REVISIT make the driver support per-port power switching,
+                * and also overcurrent detection.  Here we assume the ports
+                * are always powered while this driver is active, and use
+                * active-low power switches.
+                */
+               for (i = 0; i < pdata->ports; i++) {
+                       if (pdata->vbus_pin[i] <= 0)
+                               continue;
+                       gpio_request(pdata->vbus_pin[i], "ohci_vbus");
+                       gpio_direction_output(pdata->vbus_pin[i], 0);
+               }
+       }
+
        device_init_wakeup(&pdev->dev, 1);
        return usb_hcd_at91_probe(&ohci_at91_hc_driver, pdev);
 }
 
 static int ohci_hcd_at91_drv_remove(struct platform_device *pdev)
 {
+       struct at91_usbh_data   *pdata = pdev->dev.platform_data;
+       int                     i;
+
+       if (pdata) {
+               for (i = 0; i < pdata->ports; i++) {
+                       if (pdata->vbus_pin[i] <= 0)
+                               continue;
+                       gpio_direction_output(pdata->vbus_pin[i], 1);
+                       gpio_free(pdata->vbus_pin[i]);
+               }
+       }
+
        device_init_wakeup(&pdev->dev, 0);
        return usb_hcd_at91_remove(platform_get_drvdata(pdev), pdev);
 }
index ebab5ce8f5ce7d760b48e9fb5e1df650c7ffded5..a22c30aa745d69f1a15b3fa85d844a2d768f99ce 100644 (file)
@@ -401,6 +401,42 @@ static inline void remove_debug_files (struct ohci_hcd *bus) { }
 
 #else
 
+static int debug_async_open(struct inode *, struct file *);
+static int debug_periodic_open(struct inode *, struct file *);
+static int debug_registers_open(struct inode *, struct file *);
+static int debug_async_open(struct inode *, struct file *);
+static ssize_t debug_output(struct file*, char __user*, size_t, loff_t*);
+static int debug_close(struct inode *, struct file *);
+
+static const struct file_operations debug_async_fops = {
+       .owner          = THIS_MODULE,
+       .open           = debug_async_open,
+       .read           = debug_output,
+       .release        = debug_close,
+};
+static const struct file_operations debug_periodic_fops = {
+       .owner          = THIS_MODULE,
+       .open           = debug_periodic_open,
+       .read           = debug_output,
+       .release        = debug_close,
+};
+static const struct file_operations debug_registers_fops = {
+       .owner          = THIS_MODULE,
+       .open           = debug_registers_open,
+       .read           = debug_output,
+       .release        = debug_close,
+};
+
+static struct dentry *ohci_debug_root;
+
+struct debug_buffer {
+       ssize_t (*fill_func)(struct debug_buffer *);    /* fill method */
+       struct device *dev;
+       struct mutex mutex;     /* protect filling of buffer */
+       size_t count;           /* number of characters filled into buffer */
+       char *page;
+};
+
 static ssize_t
 show_list (struct ohci_hcd *ohci, char *buf, size_t count, struct ed *ed)
 {
@@ -467,8 +503,7 @@ show_list (struct ohci_hcd *ohci, char *buf, size_t count, struct ed *ed)
        return count - size;
 }
 
-static ssize_t
-show_async (struct class_device *class_dev, char *buf)
+static ssize_t fill_async_buffer(struct debug_buffer *buf)
 {
        struct usb_bus          *bus;
        struct usb_hcd          *hcd;
@@ -476,25 +511,23 @@ show_async (struct class_device *class_dev, char *buf)
        size_t                  temp;
        unsigned long           flags;
 
-       bus = class_get_devdata(class_dev);
+       bus = dev_get_drvdata(buf->dev);
        hcd = bus_to_hcd(bus);
        ohci = hcd_to_ohci(hcd);
 
        /* display control and bulk lists together, for simplicity */
        spin_lock_irqsave (&ohci->lock, flags);
-       temp = show_list (ohci, buf, PAGE_SIZE, ohci->ed_controltail);
-       temp += show_list (ohci, buf + temp, PAGE_SIZE - temp, ohci->ed_bulktail);
+       temp = show_list(ohci, buf->page, buf->count, ohci->ed_controltail);
+       temp += show_list(ohci, buf->page + temp, buf->count - temp,
+                         ohci->ed_bulktail);
        spin_unlock_irqrestore (&ohci->lock, flags);
 
        return temp;
 }
-static CLASS_DEVICE_ATTR (async, S_IRUGO, show_async, NULL);
-
 
 #define DBG_SCHED_LIMIT 64
 
-static ssize_t
-show_periodic (struct class_device *class_dev, char *buf)
+static ssize_t fill_periodic_buffer(struct debug_buffer *buf)
 {
        struct usb_bus          *bus;
        struct usb_hcd          *hcd;
@@ -509,10 +542,10 @@ show_periodic (struct class_device *class_dev, char *buf)
                return 0;
        seen_count = 0;
 
-       bus = class_get_devdata(class_dev);
+       bus = (struct usb_bus *)dev_get_drvdata(buf->dev);
        hcd = bus_to_hcd(bus);
        ohci = hcd_to_ohci(hcd);
-       next = buf;
+       next = buf->page;
        size = PAGE_SIZE;
 
        temp = scnprintf (next, size, "size = %d\n", NUM_INTS);
@@ -589,13 +622,9 @@ show_periodic (struct class_device *class_dev, char *buf)
 
        return PAGE_SIZE - size;
 }
-static CLASS_DEVICE_ATTR (periodic, S_IRUGO, show_periodic, NULL);
-
-
 #undef DBG_SCHED_LIMIT
 
-static ssize_t
-show_registers (struct class_device *class_dev, char *buf)
+static ssize_t fill_registers_buffer(struct debug_buffer *buf)
 {
        struct usb_bus          *bus;
        struct usb_hcd          *hcd;
@@ -606,11 +635,11 @@ show_registers (struct class_device *class_dev, char *buf)
        char                    *next;
        u32                     rdata;
 
-       bus = class_get_devdata(class_dev);
+       bus = (struct usb_bus *)dev_get_drvdata(buf->dev);
        hcd = bus_to_hcd(bus);
        ohci = hcd_to_ohci(hcd);
        regs = ohci->regs;
-       next = buf;
+       next = buf->page;
        size = PAGE_SIZE;
 
        spin_lock_irqsave (&ohci->lock, flags);
@@ -677,29 +706,155 @@ show_registers (struct class_device *class_dev, char *buf)
 
 done:
        spin_unlock_irqrestore (&ohci->lock, flags);
+
        return PAGE_SIZE - size;
 }
-static CLASS_DEVICE_ATTR (registers, S_IRUGO, show_registers, NULL);
 
+static struct debug_buffer *alloc_buffer(struct device *dev,
+                               ssize_t (*fill_func)(struct debug_buffer *))
+{
+       struct debug_buffer *buf;
+
+       buf = kzalloc(sizeof(struct debug_buffer), GFP_KERNEL);
 
+       if (buf) {
+               buf->dev = dev;
+               buf->fill_func = fill_func;
+               mutex_init(&buf->mutex);
+       }
+
+       return buf;
+}
+
+static int fill_buffer(struct debug_buffer *buf)
+{
+       int ret = 0;
+
+       if (!buf->page)
+               buf->page = (char *)get_zeroed_page(GFP_KERNEL);
+
+       if (!buf->page) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       ret = buf->fill_func(buf);
+
+       if (ret >= 0) {
+               buf->count = ret;
+               ret = 0;
+       }
+
+out:
+       return ret;
+}
+
+static ssize_t debug_output(struct file *file, char __user *user_buf,
+                       size_t len, loff_t *offset)
+{
+       struct debug_buffer *buf = file->private_data;
+       int ret = 0;
+
+       mutex_lock(&buf->mutex);
+       if (buf->count == 0) {
+               ret = fill_buffer(buf);
+               if (ret != 0) {
+                       mutex_unlock(&buf->mutex);
+                       goto out;
+               }
+       }
+       mutex_unlock(&buf->mutex);
+
+       ret = simple_read_from_buffer(user_buf, len, offset,
+                                     buf->page, buf->count);
+
+out:
+       return ret;
+
+}
+
+static int debug_close(struct inode *inode, struct file *file)
+{
+       struct debug_buffer *buf = file->private_data;
+
+       if (buf) {
+               if (buf->page)
+                       free_page((unsigned long)buf->page);
+               kfree(buf);
+       }
+
+       return 0;
+}
+static int debug_async_open(struct inode *inode, struct file *file)
+{
+       file->private_data = alloc_buffer(inode->i_private, fill_async_buffer);
+
+       return file->private_data ? 0 : -ENOMEM;
+}
+
+static int debug_periodic_open(struct inode *inode, struct file *file)
+{
+       file->private_data = alloc_buffer(inode->i_private,
+                                         fill_periodic_buffer);
+
+       return file->private_data ? 0 : -ENOMEM;
+}
+
+static int debug_registers_open(struct inode *inode, struct file *file)
+{
+       file->private_data = alloc_buffer(inode->i_private,
+                                         fill_registers_buffer);
+
+       return file->private_data ? 0 : -ENOMEM;
+}
 static inline void create_debug_files (struct ohci_hcd *ohci)
 {
-       struct class_device *cldev = ohci_to_hcd(ohci)->self.class_dev;
-       int retval;
+       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,
+                                               &debug_async_fops);
+       if (!ohci->debug_async)
+               goto async_error;
+
+       ohci->debug_periodic = debugfs_create_file("periodic", S_IRUGO,
+                                                  ohci->debug_dir, dev,
+                                                  &debug_periodic_fops);
+       if (!ohci->debug_periodic)
+               goto periodic_error;
+
+       ohci->debug_registers = debugfs_create_file("registers", S_IRUGO,
+                                                   ohci->debug_dir, dev,
+                                                   &debug_registers_fops);
+       if (!ohci->debug_registers)
+               goto registers_error;
 
-       retval = class_device_create_file(cldev, &class_device_attr_async);
-       retval = class_device_create_file(cldev, &class_device_attr_periodic);
-       retval = class_device_create_file(cldev, &class_device_attr_registers);
        ohci_dbg (ohci, "created debug files\n");
+       return;
+
+registers_error:
+       debugfs_remove(ohci->debug_periodic);
+periodic_error:
+       debugfs_remove(ohci->debug_async);
+async_error:
+       debugfs_remove(ohci->debug_dir);
+dir_error:
+       ohci->debug_periodic = NULL;
+       ohci->debug_async = NULL;
+       ohci->debug_dir = NULL;
 }
 
 static inline void remove_debug_files (struct ohci_hcd *ohci)
 {
-       struct class_device *cldev = ohci_to_hcd(ohci)->self.class_dev;
-
-       class_device_remove_file(cldev, &class_device_attr_async);
-       class_device_remove_file(cldev, &class_device_attr_periodic);
-       class_device_remove_file(cldev, &class_device_attr_registers);
+       debugfs_remove(ohci->debug_registers);
+       debugfs_remove(ohci->debug_periodic);
+       debugfs_remove(ohci->debug_async);
+       debugfs_remove(ohci->debug_dir);
 }
 
 #endif
index ddd4ee1f2413633bccd1ae9d9309a2a7a86b9e32..dd4798ee028edba1e9612bfaa8d77a34afa2e8b3 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/dmapool.h>
 #include <linux/reboot.h>
 #include <linux/workqueue.h>
+#include <linux/debugfs.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
@@ -809,13 +810,9 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)
        }
 
        if (ints & OHCI_INTR_WDH) {
-               if (HC_IS_RUNNING(hcd->state))
-                       ohci_writel (ohci, OHCI_INTR_WDH, &regs->intrdisable);
                spin_lock (&ohci->lock);
                dl_done_list (ohci);
                spin_unlock (&ohci->lock);
-               if (HC_IS_RUNNING(hcd->state))
-                       ohci_writel (ohci, OHCI_INTR_WDH, &regs->intrenable);
        }
 
        if (quirk_zfmicro(ohci) && (ints & OHCI_INTR_SF)) {
@@ -1032,6 +1029,13 @@ MODULE_LICENSE ("GPL");
 #define PLATFORM_DRIVER                usb_hcd_pnx4008_driver
 #endif
 
+#if defined(CONFIG_CPU_SUBTYPE_SH7720) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7721) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7763)
+#include "ohci-sh.c"
+#define PLATFORM_DRIVER                ohci_hcd_sh_driver
+#endif
+
 
 #ifdef CONFIG_USB_OHCI_HCD_PPC_OF
 #include "ohci-ppc-of.c"
@@ -1048,6 +1052,11 @@ MODULE_LICENSE ("GPL");
 #define SSB_OHCI_DRIVER                ssb_ohci_driver
 #endif
 
+#ifdef CONFIG_MFD_SM501
+#include "ohci-sm501.c"
+#define PLATFORM_DRIVER                ohci_hcd_sm501_driver
+#endif
+
 #if    !defined(PCI_DRIVER) &&         \
        !defined(PLATFORM_DRIVER) &&    \
        !defined(OF_PLATFORM_DRIVER) && \
@@ -1068,6 +1077,14 @@ static int __init ohci_hcd_mod_init(void)
        pr_debug ("%s: block sizes: ed %Zd td %Zd\n", hcd_name,
                sizeof (struct ed), sizeof (struct td));
 
+#ifdef DEBUG
+       ohci_debug_root = debugfs_create_dir("ohci", NULL);
+       if (!ohci_debug_root) {
+               retval = -ENOENT;
+               goto error_debug;
+       }
+#endif
+
 #ifdef PS3_SYSTEM_BUS_DRIVER
        retval = ps3_ohci_driver_register(&PS3_SYSTEM_BUS_DRIVER);
        if (retval < 0)
@@ -1130,6 +1147,12 @@ static int __init ohci_hcd_mod_init(void)
        ps3_ohci_driver_unregister(&PS3_SYSTEM_BUS_DRIVER);
  error_ps3:
 #endif
+#ifdef DEBUG
+       debugfs_remove(ohci_debug_root);
+       ohci_debug_root = NULL;
+ error_debug:
+#endif
+
        return retval;
 }
 module_init(ohci_hcd_mod_init);
@@ -1154,6 +1177,9 @@ static void __exit ohci_hcd_mod_exit(void)
 #ifdef PS3_SYSTEM_BUS_DRIVER
        ps3_ohci_driver_unregister(&PS3_SYSTEM_BUS_DRIVER);
 #endif
+#ifdef DEBUG
+       debugfs_remove(ohci_debug_root);
+#endif
 }
 module_exit(ohci_hcd_mod_exit);
 
diff --git a/drivers/usb/host/ohci-sh.c b/drivers/usb/host/ohci-sh.c
new file mode 100644 (file)
index 0000000..5309ac0
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * OHCI HCD (Host Controller Driver) for USB.
+ *
+ * Copyright (C) 2008 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
+ *
+ */
+
+#include <linux/platform_device.h>
+
+static int ohci_sh_start(struct usb_hcd *hcd)
+{
+       struct ohci_hcd *ohci = hcd_to_ohci(hcd);
+
+       ohci_hcd_init(ohci);
+       ohci_init(ohci);
+       ohci_run(ohci);
+       hcd->state = HC_STATE_RUNNING;
+       return 0;
+}
+
+static const struct hc_driver ohci_sh_hc_driver = {
+       .description =          hcd_name,
+       .product_desc =         "SuperH OHCI",
+       .hcd_priv_size =        sizeof(struct ohci_hcd),
+
+       /*
+        * generic hardware linkage
+        */
+       .irq =                  ohci_irq,
+       .flags =                HCD_USB11 | HCD_MEMORY,
+
+       /*
+        * basic lifecycle operations
+        */
+       .start =                ohci_sh_start,
+       .stop =                 ohci_stop,
+       .shutdown =             ohci_shutdown,
+
+       /*
+        * managing i/o requests and associated device resources
+        */
+       .urb_enqueue =          ohci_urb_enqueue,
+       .urb_dequeue =          ohci_urb_dequeue,
+       .endpoint_disable =     ohci_endpoint_disable,
+
+       /*
+        * scheduling support
+        */
+       .get_frame_number =     ohci_get_frame,
+
+       /*
+        * root hub support
+        */
+       .hub_status_data =      ohci_hub_status_data,
+       .hub_control =          ohci_hub_control,
+       .hub_irq_enable =       ohci_rhsc_enable,
+#ifdef CONFIG_PM
+       .bus_suspend =          ohci_bus_suspend,
+       .bus_resume =           ohci_bus_resume,
+#endif
+       .start_port_reset =     ohci_start_port_reset,
+};
+
+/*-------------------------------------------------------------------------*/
+
+#define resource_len(r) (((r)->end - (r)->start) + 1)
+static int ohci_hcd_sh_probe(struct platform_device *pdev)
+{
+       struct resource *res = NULL;
+       struct usb_hcd *hcd = NULL;
+       int irq = -1;
+       int ret;
+
+       if (usb_disabled())
+               return -ENODEV;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               err("platform_get_resource error.");
+               return -ENODEV;
+       }
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               err("platform_get_irq error.");
+               return -ENODEV;
+       }
+
+       /* initialize hcd */
+       hcd = usb_create_hcd(&ohci_sh_hc_driver, &pdev->dev, (char *)hcd_name);
+       if (!hcd) {
+               err("Failed to create hcd");
+               return -ENOMEM;
+       }
+
+       hcd->regs = (void __iomem *)res->start;
+       hcd->rsrc_start = res->start;
+       hcd->rsrc_len = resource_len(res);
+       ret = usb_add_hcd(hcd, irq, IRQF_DISABLED);
+       if (ret != 0) {
+               err("Failed to add hcd");
+               usb_put_hcd(hcd);
+               return ret;
+       }
+
+       return ret;
+}
+
+static int ohci_hcd_sh_remove(struct platform_device *pdev)
+{
+       struct usb_hcd *hcd = platform_get_drvdata(pdev);
+
+       usb_remove_hcd(hcd);
+       usb_put_hcd(hcd);
+
+       return 0;
+}
+
+static struct platform_driver ohci_hcd_sh_driver = {
+       .probe          = ohci_hcd_sh_probe,
+       .remove         = ohci_hcd_sh_remove,
+       .shutdown       = usb_hcd_platform_shutdown,
+       .driver         = {
+               .name   = "sh_ohci",
+               .owner  = THIS_MODULE,
+       },
+};
+
diff --git a/drivers/usb/host/ohci-sm501.c b/drivers/usb/host/ohci-sm501.c
new file mode 100644 (file)
index 0000000..a970701
--- /dev/null
@@ -0,0 +1,264 @@
+/*
+ * OHCI HCD (Host Controller Driver) for USB.
+ *
+ * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
+ * (C) Copyright 2000-2005 David Brownell
+ * (C) Copyright 2002 Hewlett-Packard Company
+ * (C) Copyright 2008 Magnus Damm
+ *
+ * SM501 Bus Glue - based on ohci-omap.c
+ *
+ * This file is licenced under the GPL.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/jiffies.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/sm501.h>
+#include <linux/sm501-regs.h>
+
+static int ohci_sm501_init(struct usb_hcd *hcd)
+{
+       return ohci_init(hcd_to_ohci(hcd));
+}
+
+static int ohci_sm501_start(struct usb_hcd *hcd)
+{
+       struct device *dev = hcd->self.controller;
+       int ret;
+
+       ret = ohci_run(hcd_to_ohci(hcd));
+       if (ret < 0) {
+               dev_err(dev, "can't start %s", hcd->self.bus_name);
+               ohci_stop(hcd);
+       }
+
+       return ret;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static const struct hc_driver ohci_sm501_hc_driver = {
+       .description =          hcd_name,
+       .product_desc =         "SM501 OHCI",
+       .hcd_priv_size =        sizeof(struct ohci_hcd),
+
+       /*
+        * generic hardware linkage
+        */
+       .irq =                  ohci_irq,
+       .flags =                HCD_USB11 | HCD_MEMORY | HCD_LOCAL_MEM,
+
+       /*
+        * basic lifecycle operations
+        */
+       .reset =                ohci_sm501_init,
+       .start =                ohci_sm501_start,
+       .stop =                 ohci_stop,
+       .shutdown =             ohci_shutdown,
+
+       /*
+        * managing i/o requests and associated device resources
+        */
+       .urb_enqueue =          ohci_urb_enqueue,
+       .urb_dequeue =          ohci_urb_dequeue,
+       .endpoint_disable =     ohci_endpoint_disable,
+
+       /*
+        * scheduling support
+        */
+       .get_frame_number =     ohci_get_frame,
+
+       /*
+        * root hub support
+        */
+       .hub_status_data =      ohci_hub_status_data,
+       .hub_control =          ohci_hub_control,
+       .hub_irq_enable =       ohci_rhsc_enable,
+#ifdef CONFIG_PM
+       .bus_suspend =          ohci_bus_suspend,
+       .bus_resume =           ohci_bus_resume,
+#endif
+       .start_port_reset =     ohci_start_port_reset,
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int ohci_hcd_sm501_drv_probe(struct platform_device *pdev)
+{
+       const struct hc_driver *driver = &ohci_sm501_hc_driver;
+       struct device *dev = &pdev->dev;
+       struct resource *res, *mem;
+       int retval, irq;
+       struct usb_hcd *hcd = 0;
+
+       irq = retval = platform_get_irq(pdev, 0);
+       if (retval < 0)
+               goto err0;
+
+       mem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       if (mem == NULL) {
+               dev_err(dev, "no resource definition for memory\n");
+               retval = -ENOENT;
+               goto err0;
+       }
+
+       if (!request_mem_region(mem->start, mem->end - mem->start + 1,
+                               pdev->name)) {
+               dev_err(dev, "request_mem_region failed\n");
+               retval = -EBUSY;
+               goto err0;
+       }
+
+       /* The sm501 chip is equipped with local memory that may be used
+        * by on-chip devices such as the video controller and the usb host.
+        * This driver uses dma_declare_coherent_memory() to make sure
+        * usb allocations with dma_alloc_coherent() allocate from
+        * this local memory. The dma_handle returned by dma_alloc_coherent()
+        * will be an offset starting from 0 for the first local memory byte.
+        *
+        * So as long as data is allocated using dma_alloc_coherent() all is
+        * fine. This is however not always the case - buffers may be allocated
+        * using kmalloc() - so the usb core needs to be told that it must copy
+        * data into our local memory if the buffers happen to be placed in
+        * regular memory. The HCD_LOCAL_MEM flag does just that.
+        */
+
+       if (!dma_declare_coherent_memory(dev, mem->start,
+                                        mem->start - mem->parent->start,
+                                        (mem->end - mem->start) + 1,
+                                        DMA_MEMORY_MAP |
+                                        DMA_MEMORY_EXCLUSIVE)) {
+               dev_err(dev, "cannot declare coherent memory\n");
+               retval = -ENXIO;
+               goto err1;
+       }
+
+       /* allocate, reserve and remap resources for registers */
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (res == NULL) {
+               dev_err(dev, "no resource definition for registers\n");
+               retval = -ENOENT;
+               goto err2;
+       }
+
+       hcd = usb_create_hcd(driver, &pdev->dev, pdev->dev.bus_id);
+       if (!hcd) {
+               retval = -ENOMEM;
+               goto err2;
+       }
+
+       hcd->rsrc_start = res->start;
+       hcd->rsrc_len = res->end - res->start + 1;
+
+       if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, pdev->name)) {
+               dev_err(dev, "request_mem_region failed\n");
+               retval = -EBUSY;
+               goto err3;
+       }
+
+       hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+       if (hcd->regs == NULL) {
+               dev_err(dev, "cannot remap registers\n");
+               retval = -ENXIO;
+               goto err4;
+       }
+
+       ohci_hcd_init(hcd_to_ohci(hcd));
+
+       retval = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
+       if (retval)
+               goto err4;
+
+       /* enable power and unmask interrupts */
+
+       sm501_unit_power(dev->parent, SM501_GATE_USB_HOST, 1);
+       sm501_modify_reg(dev->parent, SM501_IRQ_MASK, 1 << 6, 0);
+
+       return 0;
+err4:
+       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+err3:
+       usb_put_hcd(hcd);
+err2:
+       dma_release_declared_memory(dev);
+err1:
+       release_mem_region(mem->start, mem->end - mem->start + 1);
+err0:
+       return retval;
+}
+
+static int ohci_hcd_sm501_drv_remove(struct platform_device *pdev)
+{
+       struct usb_hcd *hcd = platform_get_drvdata(pdev);
+       struct resource *mem;
+
+       usb_remove_hcd(hcd);
+       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+       usb_put_hcd(hcd);
+       dma_release_declared_memory(&pdev->dev);
+       mem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       release_mem_region(mem->start, mem->end - mem->start + 1);
+
+       /* mask interrupts and disable power */
+
+       sm501_modify_reg(pdev->dev.parent, SM501_IRQ_MASK, 0, 1 << 6);
+       sm501_unit_power(pdev->dev.parent, SM501_GATE_USB_HOST, 0);
+
+       platform_set_drvdata(pdev, NULL);
+       return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef CONFIG_PM
+static int ohci_sm501_suspend(struct platform_device *pdev, pm_message_t msg)
+{
+       struct device *dev = &pdev->dev;
+       struct ohci_hcd *ohci = hcd_to_ohci(platform_get_drvdata(pdev));
+
+       if (time_before(jiffies, ohci->next_statechange))
+               msleep(5);
+       ohci->next_statechange = jiffies;
+
+       sm501_unit_power(dev->parent, SM501_GATE_USB_HOST, 0);
+       ohci_to_hcd(ohci)->state = HC_STATE_SUSPENDED;
+       dev->power.power_state = PMSG_SUSPEND;
+       return 0;
+}
+
+static int ohci_sm501_resume(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct ohci_hcd *ohci = hcd_to_ohci(platform_get_drvdata(pdev));
+
+       if (time_before(jiffies, ohci->next_statechange))
+               msleep(5);
+       ohci->next_statechange = jiffies;
+
+       sm501_unit_power(dev->parent, SM501_GATE_USB_HOST, 1);
+       dev->power.power_state = PMSG_ON;
+       usb_hcd_resume_root_hub(platform_get_drvdata(pdev));
+       return 0;
+}
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * Driver definition to register with the SM501 bus
+ */
+static struct platform_driver ohci_hcd_sm501_driver = {
+       .probe          = ohci_hcd_sm501_drv_probe,
+       .remove         = ohci_hcd_sm501_drv_remove,
+       .shutdown       = usb_hcd_platform_shutdown,
+#ifdef CONFIG_PM
+       .suspend        = ohci_sm501_suspend,
+       .resume         = ohci_sm501_resume,
+#endif
+       .driver         = {
+               .owner  = THIS_MODULE,
+               .name   = "sm501-usb",
+       },
+};
index 47c5c66a282c55fdc24f0f6b654c39fb7137f9ee..dc544ddc784962831637e749c4d50420ee24aa0b 100644 (file)
@@ -408,6 +408,13 @@ struct ohci_hcd {
        unsigned                eds_scheduled;
        struct ed               *ed_to_check;
        unsigned                zf_delay;
+
+#ifdef DEBUG
+       struct dentry           *debug_dir;
+       struct dentry           *debug_async;
+       struct dentry           *debug_periodic;
+       struct dentry           *debug_registers;
+#endif
 };
 
 #ifdef CONFIG_PCI
index c225159ca3d346759a33b73b49743d64914ba778..0ee694f043cc9b84d0a6aef45980a97212da1fdc 100644 (file)
@@ -190,9 +190,8 @@ static void __devinit quirk_usb_handoff_ohci(struct pci_dev *pdev)
                        msleep(10);
                }
                if (wait_time <= 0)
-                       printk(KERN_WARNING "%s %s: BIOS handoff "
-                                       "failed (BIOS bug ?) %08x\n",
-                                       pdev->dev.bus_id, "OHCI",
+                       dev_warn(&pdev->dev, "OHCI: BIOS handoff failed"
+                                       " (BIOS bug?) %08x\n",
                                        readl(base + OHCI_CONTROL));
 
                /* reset controller, preserving RWC */
@@ -243,8 +242,7 @@ static void __devinit quirk_usb_disable_ehci(struct pci_dev *pdev)
                switch (cap & 0xff) {
                case 1:                 /* BIOS/SMM/... handoff support */
                        if ((cap & EHCI_USBLEGSUP_BIOS)) {
-                               pr_debug("%s %s: BIOS handoff\n",
-                                               pdev->dev.bus_id, "EHCI");
+                               dev_dbg(&pdev->dev, "EHCI: BIOS handoff\n");
 
 #if 0
 /* aleksey_gorelov@phoenix.com reports that some systems need SMI forced on,
@@ -285,9 +283,8 @@ static void __devinit quirk_usb_disable_ehci(struct pci_dev *pdev)
                                /* well, possibly buggy BIOS... try to shut
                                 * it down, and hope nothing goes too wrong
                                 */
-                               printk(KERN_WARNING "%s %s: BIOS handoff "
-                                               "failed (BIOS bug ?) %08x\n",
-                                       pdev->dev.bus_id, "EHCI", cap);
+                               dev_warn(&pdev->dev, "EHCI: BIOS handoff failed"
+                                               " (BIOS bug?) %08x\n", cap);
                                pci_write_config_byte(pdev, offset + 2, 0);
                        }
 
@@ -306,17 +303,14 @@ static void __devinit quirk_usb_disable_ehci(struct pci_dev *pdev)
                        cap = 0;
                        /* FALLTHROUGH */
                default:
-                       printk(KERN_WARNING "%s %s: unrecognized "
-                                       "capability %02x\n",
-                                       pdev->dev.bus_id, "EHCI",
-                                       cap & 0xff);
+                       dev_warn(&pdev->dev, "EHCI: unrecognized capability "
+                                       "%02x\n", cap & 0xff);
                        break;
                }
                offset = (cap >> 8) & 0xff;
        }
        if (!count)
-               printk(KERN_DEBUG "%s %s: capability loop?\n",
-                               pdev->dev.bus_id, "EHCI");
+               dev_printk(KERN_DEBUG, &pdev->dev, "EHCI: capability loop?\n");
 
        /*
         * halt EHCI & disable its interrupts in any case
index fe9ceb077d9bbddaf38f7dd6998ca73d1bea7b1a..57388252b693cb7ca6e79fa75c251b1abc64f708 100644 (file)
 
 struct r8a66597_pipe_info {
        u16 pipenum;
-       u16 address;    /* R8A66597 HCD usb addres */
+       u16 address;    /* R8A66597 HCD usb address */
        u16 epnum;
        u16 maxpacket;
        u16 type;
index d1131a87a5b13ad72e40e4f573a6a7ace8979445..0fb114ca1eba9d598da09483f7565451b351822a 100644 (file)
@@ -478,8 +478,6 @@ static int mdc800_usb_probe (struct usb_interface *intf,
                                {
                                        irq_interval=intf_desc->endpoint [j].desc.bInterval;
                                }
-
-                               continue;
                        }
                }
                if (mdc800->endpoint[i] == -1)
index d721380b242d69a9e4c4addcb21bfdb47d363ec9..937940404b7a316600aff66c83e1d36372b81405 100644 (file)
@@ -1,7 +1,7 @@
 /*
 * cypress_cy7c63.c
 *
-* Copyright (c) 2006 Oliver Bock (o.bock@fh-wolfenbuettel.de)
+* Copyright (c) 2006-2007 Oliver Bock (bock@tfh-berlin.de)
 *
 *      This driver is based on the Cypress USB Driver by Marcus Maul
 *      (cyport) and the 2.0 version of Greg Kroah-Hartman's
@@ -21,6 +21,9 @@
 *      Supported functions:    Read/Write Ports
 *
 *
+*      For up-to-date information please visit:
+*      http://www.obock.de/kernel/cypress
+*
 *      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.
@@ -31,7 +34,7 @@
 #include <linux/kernel.h>
 #include <linux/usb.h>
 
-#define DRIVER_AUTHOR          "Oliver Bock (o.bock@fh-wolfenbuettel.de)"
+#define DRIVER_AUTHOR          "Oliver Bock (bock@tfh-berlin.de)"
 #define DRIVER_DESC            "Cypress CY7C63xxx USB driver"
 
 #define CYPRESS_VENDOR_ID      0xa2c
index 764696ff1e8e27838255834b79f084f6358751f8..801070502cc1b14faa0bd3769247154f2935736f 100644 (file)
@@ -715,7 +715,7 @@ static unsigned iowarrior_poll(struct file *file, poll_table * wait)
  * would use "struct net_driver" instead, and a serial
  * device would use "struct tty_driver".
  */
-static struct file_operations iowarrior_fops = {
+static const struct file_operations iowarrior_fops = {
        .owner = THIS_MODULE,
        .write = iowarrior_write,
        .read = iowarrior_read,
index aab320085ebf007af652cfa797d93c5ac09de1ce..6664043f4645bc0d13fa0ac51a3c6f017356cbbb 100644 (file)
@@ -205,7 +205,7 @@ static DEFINE_MUTEX(open_disc_mutex);
 
 /* Structure to hold all of our device specific stuff */
 struct lego_usb_tower {
-       struct semaphore        sem;            /* locks this structure */
+       struct mutex            lock;           /* locks this structure */
        struct usb_device*      udev;           /* save off the usb device pointer */
        unsigned char           minor;          /* the starting minor number for this device */
 
@@ -361,7 +361,7 @@ static int tower_open (struct inode *inode, struct file *file)
        }
 
        /* lock this device */
-       if (down_interruptible (&dev->sem)) {
+       if (mutex_lock_interruptible(&dev->lock)) {
                mutex_unlock(&open_disc_mutex);
                retval = -ERESTARTSYS;
                goto exit;
@@ -421,7 +421,7 @@ static int tower_open (struct inode *inode, struct file *file)
        file->private_data = dev;
 
 unlock_exit:
-       up (&dev->sem);
+       mutex_unlock(&dev->lock);
 
 exit:
        dbg(2, "%s: leave, return value %d ", __FUNCTION__, retval);
@@ -448,7 +448,7 @@ static int tower_release (struct inode *inode, struct file *file)
        }
 
        mutex_lock(&open_disc_mutex);
-       if (down_interruptible (&dev->sem)) {
+       if (mutex_lock_interruptible(&dev->lock)) {
                retval = -ERESTARTSYS;
                goto exit;
        }
@@ -460,7 +460,9 @@ static int tower_release (struct inode *inode, struct file *file)
        }
        if (dev->udev == NULL) {
                /* the device was unplugged before the file was released */
-               up (&dev->sem); /* unlock here as tower_delete frees dev */
+
+               /* unlock here as tower_delete frees dev */
+               mutex_unlock(&dev->lock);
                tower_delete (dev);
                goto exit;
        }
@@ -473,7 +475,7 @@ static int tower_release (struct inode *inode, struct file *file)
        dev->open_count = 0;
 
 unlock_exit:
-       up (&dev->sem);
+       mutex_unlock(&dev->lock);
 
 exit:
        mutex_unlock(&open_disc_mutex);
@@ -586,7 +588,7 @@ static ssize_t tower_read (struct file *file, char __user *buffer, size_t count,
        dev = (struct lego_usb_tower *)file->private_data;
 
        /* lock this object */
-       if (down_interruptible (&dev->sem)) {
+       if (mutex_lock_interruptible(&dev->lock)) {
                retval = -ERESTARTSYS;
                goto exit;
        }
@@ -653,7 +655,7 @@ static ssize_t tower_read (struct file *file, char __user *buffer, size_t count,
 
 unlock_exit:
        /* unlock the device */
-       up (&dev->sem);
+       mutex_unlock(&dev->lock);
 
 exit:
        dbg(2, "%s: leave, return value %d", __FUNCTION__, retval);
@@ -675,7 +677,7 @@ static ssize_t tower_write (struct file *file, const char __user *buffer, size_t
        dev = (struct lego_usb_tower *)file->private_data;
 
        /* lock this object */
-       if (down_interruptible (&dev->sem)) {
+       if (mutex_lock_interruptible(&dev->lock)) {
                retval = -ERESTARTSYS;
                goto exit;
        }
@@ -737,7 +739,7 @@ static ssize_t tower_write (struct file *file, const char __user *buffer, size_t
 
 unlock_exit:
        /* unlock the device */
-       up (&dev->sem);
+       mutex_unlock(&dev->lock);
 
 exit:
        dbg(2, "%s: leave, return value %d", __FUNCTION__, retval);
@@ -862,7 +864,7 @@ static int tower_probe (struct usb_interface *interface, const struct usb_device
                goto exit;
        }
 
-       init_MUTEX (&dev->sem);
+       mutex_init(&dev->lock);
 
        dev->udev = udev;
        dev->open_count = 0;
@@ -1007,16 +1009,16 @@ static void tower_disconnect (struct usb_interface *interface)
        /* give back our minor */
        usb_deregister_dev (interface, &tower_class);
 
-       down (&dev->sem);
+       mutex_lock(&dev->lock);
        mutex_unlock(&open_disc_mutex);
 
        /* if the device is not opened, then we clean up right now */
        if (!dev->open_count) {
-               up (&dev->sem);
+               mutex_unlock(&dev->lock);
                tower_delete (dev);
        } else {
                dev->udev = NULL;
-               up (&dev->sem);
+               mutex_unlock(&dev->lock);
        }
 
        info("LEGO USB Tower #%d now disconnected", (minor - LEGO_USB_TOWER_MINOR_BASE));
index 9244d067cec1d9e3232d3379bae6cf46fa998925..cb7fa0eaf3ae9e264bc4fea418a6e70afe979021 100644 (file)
@@ -323,7 +323,7 @@ sisusb_bulkin_msg(struct sisusb_usb_data *sisusb, unsigned int pipe, void *data,
                        usb_kill_urb(urb);
                        retval = -ETIMEDOUT;
                } else {
-                       /* URB completed within timout */
+                       /* URB completed within timeout */
                        retval = urb->status;
                        readbytes = urb->actual_length;
                }
@@ -3195,20 +3195,6 @@ static int sisusb_probe(struct usb_interface *intf,
 
        sisusb->present = 1;
 
-#ifdef SISUSB_OLD_CONFIG_COMPAT
-       {
-       int ret;
-       /* Our ioctls are all "32/64bit compatible" */
-       ret =  register_ioctl32_conversion(SISUSB_GET_CONFIG_SIZE, NULL);
-       ret |= register_ioctl32_conversion(SISUSB_GET_CONFIG,      NULL);
-       ret |= register_ioctl32_conversion(SISUSB_COMMAND,         NULL);
-       if (ret)
-               dev_err(&sisusb->sisusb_dev->dev, "Error registering ioctl32 translations\n");
-       else
-               sisusb->ioctl32registered = 1;
-       }
-#endif
-
        if (dev->speed == USB_SPEED_HIGH) {
                int initscreen = 1;
 #ifdef INCL_SISUSB_CON
@@ -3271,19 +3257,6 @@ static void sisusb_disconnect(struct usb_interface *intf)
 
        usb_set_intfdata(intf, NULL);
 
-#ifdef SISUSB_OLD_CONFIG_COMPAT
-       if (sisusb->ioctl32registered) {
-               int ret;
-               sisusb->ioctl32registered = 0;
-               ret =  unregister_ioctl32_conversion(SISUSB_GET_CONFIG_SIZE);
-               ret |= unregister_ioctl32_conversion(SISUSB_GET_CONFIG);
-               ret |= unregister_ioctl32_conversion(SISUSB_COMMAND);
-               if (ret) {
-                       dev_err(&sisusb->sisusb_dev->dev, "Error unregistering ioctl32 translations\n");
-               }
-       }
-#endif
-
        sisusb->present = 0;
        sisusb->ready = 0;
 
index d2d7872cd0229622ba546f3fc3111b20bccc471e..cf0b4a5883f665f27f2f9d34d13e9854d080565f 100644 (file)
@@ -120,9 +120,6 @@ struct sisusb_usb_data {
        int isopen;             /* !=0 if open */
        int present;            /* !=0 if device is present on the bus */
        int ready;              /* !=0 if device is ready for userland */
-#ifdef SISUSB_OLD_CONFIG_COMPAT
-       int ioctl32registered;
-#endif
        int numobufs;           /* number of obufs = number of out urbs */
        char *obuf[NUMOBUFS], *ibuf;    /* transfer buffers */
        int obufsize, ibufsize;
index ea3162146481fa4791a4ec750b4c1f5a6b83bc77..da922dfc0dccfefa3c308d35301580fe1e39d82f 100644 (file)
@@ -6,6 +6,7 @@
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/scatterlist.h>
+#include <linux/mutex.h>
 
 #include <linux/usb.h>
 
@@ -64,7 +65,7 @@ struct usbtest_dev {
        int                     in_iso_pipe;
        int                     out_iso_pipe;
        struct usb_endpoint_descriptor  *iso_in, *iso_out;
-       struct semaphore        sem;
+       struct mutex            lock;
 
 #define TBUF_SIZE      256
        u8                      *buf;
@@ -1151,6 +1152,7 @@ static int verify_halted (int ep, struct urb *urb)
                dbg ("ep %02x couldn't get halt status, %d", ep, retval);
                return retval;
        }
+       le16_to_cpus(&status);
        if (status != 1) {
                dbg ("ep %02x bogus status: %04x != 1", ep, status);
                return -EINVAL;
@@ -1310,7 +1312,7 @@ static int ctrl_out (struct usbtest_dev *dev,
                len += vary;
 
                /* [real world] the "zero bytes IN" case isn't really used.
-                * hardware can easily trip up in this wierd case, since its
+                * hardware can easily trip up in this weird case, since its
                 * status stage is IN, not OUT like other ep0in transfers.
                 */
                if (len > length)
@@ -1558,11 +1560,11 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
                        || param->sglen < 0 || param->vary < 0)
                return -EINVAL;
 
-       if (down_interruptible (&dev->sem))
+       if (mutex_lock_interruptible(&dev->lock))
                return -ERESTARTSYS;
 
        if (intf->dev.power.power_state.event != PM_EVENT_ON) {
-               up (&dev->sem);
+               mutex_unlock(&dev->lock);
                return -EHOSTUNREACH;
        }
 
@@ -1574,7 +1576,7 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
                int     res;
 
                if (intf->altsetting->desc.bInterfaceNumber) {
-                       up (&dev->sem);
+                       mutex_unlock(&dev->lock);
                        return -ENODEV;
                }
                res = set_altsetting (dev, dev->info->alt);
@@ -1582,7 +1584,7 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
                        dev_err (&intf->dev,
                                        "set altsetting to %d failed, %d\n",
                                        dev->info->alt, res);
-                       up (&dev->sem);
+                       mutex_unlock(&dev->lock);
                        return res;
                }
        }
@@ -1855,7 +1857,7 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
                param->duration.tv_usec += 1000 * 1000;
                param->duration.tv_sec -= 1;
        }
-       up (&dev->sem);
+       mutex_unlock(&dev->lock);
        return retval;
 }
 
@@ -1905,7 +1907,7 @@ usbtest_probe (struct usb_interface *intf, const struct usb_device_id *id)
                return -ENOMEM;
        info = (struct usbtest_info *) id->driver_info;
        dev->info = info;
-       init_MUTEX (&dev->sem);
+       mutex_init(&dev->lock);
 
        dev->intf = intf;
 
@@ -1990,8 +1992,6 @@ static void usbtest_disconnect (struct usb_interface *intf)
 {
        struct usbtest_dev      *dev = usb_get_intfdata (intf);
 
-       down (&dev->sem);
-
        usb_set_intfdata (intf, NULL);
        dev_dbg (&intf->dev, "disconnect\n");
        kfree (dev);
index f06e4e2b49d3bdac755d8136077dcae352bcb19d..1774ba5c4c3bf8944118d7b13c944f07370a1529 100644 (file)
@@ -1026,6 +1026,8 @@ mon_bin_poll(struct file *file, struct poll_table_struct *wait)
        return mask;
 }
 
+#if 0
+
 /*
  * open and close: just keep track of how many times the device is
  * mapped, to use the proper memory allocation function.
@@ -1045,33 +1047,31 @@ static void mon_bin_vma_close(struct vm_area_struct *vma)
 /*
  * Map ring pages to user space.
  */
-struct page *mon_bin_vma_nopage(struct vm_area_struct *vma,
-                                unsigned long address, int *type)
+static int mon_bin_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
 {
        struct mon_reader_bin *rp = vma->vm_private_data;
        unsigned long offset, chunk_idx;
        struct page *pageptr;
 
-       offset = (address - vma->vm_start) + (vma->vm_pgoff << PAGE_SHIFT);
+       offset = vmf->pgoff << PAGE_SHIFT;
        if (offset >= rp->b_size)
-               return NOPAGE_SIGBUS;
+               return VM_FAULT_SIGBUS;
        chunk_idx = offset / CHUNK_SIZE;
        pageptr = rp->b_vec[chunk_idx].pg;
        get_page(pageptr);
-       if (type)
-               *type = VM_FAULT_MINOR;
-       return pageptr;
+       vmf->page = pageptr;
+       return 0;
 }
 
 struct vm_operations_struct mon_bin_vm_ops = {
        .open =     mon_bin_vma_open,
        .close =    mon_bin_vma_close,
-       .nopage =   mon_bin_vma_nopage,
+       .fault =    mon_bin_vma_fault,
 };
 
 int mon_bin_mmap(struct file *filp, struct vm_area_struct *vma)
 {
-       /* don't do anything here: "nopage" will set up page table entries */
+       /* don't do anything here: "fault" will set up page table entries */
        vma->vm_ops = &mon_bin_vm_ops;
        vma->vm_flags |= VM_RESERVED;
        vma->vm_private_data = filp->private_data;
@@ -1079,7 +1079,9 @@ int mon_bin_mmap(struct file *filp, struct vm_area_struct *vma)
        return 0;
 }
 
-struct file_operations mon_fops_binary = {
+#endif  /*  0  */
+
+static const struct file_operations mon_fops_binary = {
        .owner =        THIS_MODULE,
        .open =         mon_bin_open,
        .llseek =       no_llseek,
index 4a86696e6c7dd20240aca1776139669c9ac4005c..c1e65dfd93538349f07b4d056bbdc2d25a0709a5 100644 (file)
@@ -2,10 +2,7 @@
 # USB Serial device configuration
 #
 
-menu "USB Serial Converter support"
-       depends on USB!=n
-
-config USB_SERIAL
+menuconfig USB_SERIAL
        tristate "USB Serial Converter support"
        depends on USB
        ---help---
@@ -20,6 +17,8 @@ config USB_SERIAL
          To compile this driver as a module, choose M here: the
          module will be called usbserial.
 
+if USB_SERIAL
+
 config USB_SERIAL_CONSOLE
        bool "USB Serial Console device support (EXPERIMENTAL)"
        depends on USB_SERIAL=y && EXPERIMENTAL
@@ -43,6 +42,12 @@ config USB_SERIAL_CONSOLE
 
          If unsure, say N.
 
+config USB_EZUSB
+       bool "Functions for loading firmware on EZUSB chips"
+       depends on USB_SERIAL
+       help
+           Say Y here if you need EZUSB device support.
+
 config USB_SERIAL_GENERIC
        bool "USB Generic Serial Driver"
        depends on USB_SERIAL
@@ -105,6 +110,7 @@ config USB_SERIAL_CH341
 config USB_SERIAL_WHITEHEAT
        tristate "USB ConnectTech WhiteHEAT Serial Driver"
        depends on USB_SERIAL
+       select USB_EZUSB
        help
          Say Y here if you want to use a ConnectTech WhiteHEAT 4 port
          USB to serial converter device.
@@ -282,9 +288,21 @@ config USB_SERIAL_IPW
          To compile this driver as a module, choose M here: the
          module will be called ipw.
 
+config USB_SERIAL_IUU
+       tristate "USB Infinity USB Unlimited Phoenix Driver (Experimental)"
+       depends on USB_SERIAL && EXPERIMENTAL
+       help
+         Say Y here if you want to use a IUU in phoenix mode and get
+         an extra ttyUSBx device. More information available on
+         http://eczema.ecze.com/iuu_phoenix.html
+
+         To compile this driver as a module, choose M here: the
+         module will be called iuu_phoenix.o
+
 config USB_SERIAL_KEYSPAN_PDA
        tristate "USB Keyspan PDA Single Port Serial Driver"
        depends on USB_SERIAL
+       select USB_EZUSB
        help
          Say Y here if you want to use a Keyspan PDA single port USB to
          serial converter device.  This driver makes use of firmware
@@ -296,6 +314,7 @@ config USB_SERIAL_KEYSPAN_PDA
 config USB_SERIAL_KEYSPAN
        tristate "USB Keyspan USA-xxx Serial Driver"
        depends on USB_SERIAL
+       select USB_EZUSB
        ---help---
          Say Y here if you want to use Keyspan USB to serial converter
          devices.  This driver makes use of Keyspan's official firmware
@@ -538,6 +557,7 @@ config USB_SERIAL_CYBERJACK
 config USB_SERIAL_XIRCOM
        tristate "USB Xircom / Entregra Single Port Serial Driver"
        depends on USB_SERIAL
+       select USB_EZUSB
        help
          Say Y here if you want to use a Xircom or Entregra single port USB to
          serial converter device.  This driver makes use of firmware
@@ -585,11 +605,4 @@ config USB_SERIAL_DEBUG
          To compile this driver as a module, choose M here: the
          module will be called usb-debug.
 
-config USB_EZUSB
-       bool
-       depends on USB_SERIAL_KEYSPAN_PDA || USB_SERIAL_XIRCOM || USB_SERIAL_KEYSPAN || USB_SERIAL_WHITEHEAT
-       default y
-
-
-endmenu
-
+endif # USB_SERIAL
index d6fb384e52b24ab1dca674e1ceaa9bfd515595e0..0db109a54d10b621242f1ca489f23362ed2a3528 100644 (file)
@@ -30,6 +30,7 @@ obj-$(CONFIG_USB_SERIAL_GARMIN)                       += garmin_gps.o
 obj-$(CONFIG_USB_SERIAL_HP4X)                  += hp4x.o
 obj-$(CONFIG_USB_SERIAL_IPAQ)                  += ipaq.o
 obj-$(CONFIG_USB_SERIAL_IPW)                   += ipw.o
+obj-$(CONFIG_USB_SERIAL_IUU)                   += iuu_phoenix.o
 obj-$(CONFIG_USB_SERIAL_IR)                    += ir-usb.o
 obj-$(CONFIG_USB_SERIAL_KEYSPAN)               += keyspan.o
 obj-$(CONFIG_USB_SERIAL_KEYSPAN_PDA)           += keyspan_pda.o
index 77bb893bf2e922c51bb51ef4e2ac69f6d2cd2a86..f156dba0300f77168f7774199e988074bd249e8a 100644 (file)
@@ -217,7 +217,10 @@ static void airprime_close(struct usb_serial_port *port, struct file * filp)
        priv->rts_state = 0;
        priv->dtr_state = 0;
 
-       airprime_send_setup(port);
+       mutex_lock(&port->serial->disc_mutex);
+       if (!port->serial->disconnected)
+               airprime_send_setup(port);
+       mutex_lock(&port->serial->disc_mutex);
 
        for (i = 0; i < NUM_READ_URBS; ++i) {
                usb_kill_urb (priv->read_urbp[i]);
index ddfee918000dc5fd8b6b997d75a81625472821c4..fe2bfd67ba8e4717ef3b96657902663dbeedd22c 100644 (file)
@@ -151,8 +151,10 @@ static int ark3116_attach(struct usb_serial *serial)
        return 0;
 
 cleanup:
-       for (--i; i >= 0; --i)
+       for (--i; i >= 0; --i) {
+               kfree(usb_get_serial_port_data(serial->port[i]));
                usb_set_serial_port_data(serial->port[i], NULL);
+       }
        return -ENOMEM;
 }
 
index 86724e885704b01dcfb77d9291d3958690f32932..df0a2b3b02943e76d40a89f832c498eea0e964ca 100644 (file)
@@ -350,14 +350,12 @@ static void belkin_sa_set_termios (struct usb_serial_port *port, struct ktermios
        unsigned long control_state;
        int bad_flow_control;
        speed_t baud;
+       struct ktermios *termios = port->tty->termios;
        
-       if ((!port->tty) || (!port->tty->termios)) {
-               dbg ("%s - no tty or termios structure", __FUNCTION__);
-               return;
-       }
+       iflag = termios->c_iflag;
+       cflag = termios->c_cflag;
 
-       iflag = port->tty->termios->c_iflag;
-       cflag = port->tty->termios->c_cflag;
+       termios->c_cflag &= ~CMSPAR;
 
        /* get a local copy of the current port settings */
        spin_lock_irqsave(&priv->lock, flags);
@@ -369,33 +367,30 @@ static void belkin_sa_set_termios (struct usb_serial_port *port, struct ktermios
        old_cflag = old_termios->c_cflag;
 
        /* Set the baud rate */
-       if( (cflag&CBAUD) != (old_cflag&CBAUD) ) {
+       if ((cflag & CBAUD) != (old_cflag & CBAUD)) {
                /* reassert DTR and (maybe) RTS on transition from B0 */
                if( (old_cflag&CBAUD) == B0 ) {
                        control_state |= (TIOCM_DTR|TIOCM_RTS);
                        if (BSA_USB_CMD(BELKIN_SA_SET_DTR_REQUEST, 1) < 0)
                                err("Set DTR error");
                        /* don't set RTS if using hardware flow control */
-                       if (!(old_cflag&CRTSCTS) )
+                       if (!(old_cflag & CRTSCTS))
                                if (BSA_USB_CMD(BELKIN_SA_SET_RTS_REQUEST, 1) < 0)
                                        err("Set RTS error");
                }
        }
 
        baud = tty_get_baud_rate(port->tty);
-       if (baud == 0) {
-               dbg("%s - tty_get_baud_rate says 0 baud", __FUNCTION__);
-               return;
-       }
-       urb_value = BELKIN_SA_BAUD(baud);
-       /* Clip to maximum speed */
-       if (urb_value == 0)
-               urb_value = 1;
-       /* Turn it back into a resulting real baud rate */
-       baud = BELKIN_SA_BAUD(urb_value);
-       /* FIXME: Once the tty updates are done then push this back to the tty */
-
-       if ((cflag & CBAUD) != B0 ) {
+       if (baud) {
+               urb_value = BELKIN_SA_BAUD(baud);
+               /* Clip to maximum speed */
+               if (urb_value == 0)
+                       urb_value = 1;
+               /* Turn it back into a resulting real baud rate */
+               baud = BELKIN_SA_BAUD(urb_value);
+
+               /* Report the actual baud rate back to the caller */
+               tty_encode_baud_rate(port->tty, baud, baud);
                if (BSA_USB_CMD(BELKIN_SA_SET_BAUDRATE_REQUEST, urb_value) < 0)
                        err("Set baudrate error");
        } else {
index 0362654d3b52e8aa53453c6cb499a8d247a9f8b2..66ce30c1b75bba3db5e91e61f8105f10ba2a30d2 100644 (file)
@@ -64,8 +64,8 @@ static int usb_console_setup(struct console *co, char *options)
        struct usb_serial *serial;
        struct usb_serial_port *port;
        int retval = 0;
-       struct tty_struct *tty;
-       struct ktermios *termios;
+       struct tty_struct *tty = NULL;
+       struct ktermios *termios = NULL, dummy;
 
        dbg ("%s", __FUNCTION__);
 
@@ -133,11 +133,14 @@ static int usb_console_setup(struct console *co, char *options)
        }
        co->cflag = cflag;
 
-       /* grab the first serial port that happens to be connected */
-       serial = usb_serial_get_by_index(0);
+       /*
+        * no need to check the index here: if the index is wrong, console
+        * code won't call us
+        */
+       serial = usb_serial_get_by_index(co->index);
        if (serial == NULL) {
                /* no device is connected yet, sorry :( */
-               err ("No USB device connected to ttyUSB0");
+               err ("No USB device connected to ttyUSB%i", co->index);
                return -ENODEV;
        }
 
@@ -148,49 +151,64 @@ static int usb_console_setup(struct console *co, char *options)
         
        ++port->open_count;
        if (port->open_count == 1) {
+               if (serial->type->set_termios) {
+                       /*
+                        * allocate a fake tty so the driver can initialize
+                        * the termios structure, then later call set_termios to
+                        * configure according to command line arguments
+                        */
+                       tty = kzalloc(sizeof(*tty), GFP_KERNEL);
+                       if (!tty) {
+                               retval = -ENOMEM;
+                               err("no more memory");
+                               goto reset_open_count;
+                       }
+                       termios = kzalloc(sizeof(*termios), GFP_KERNEL);
+                       if (!termios) {
+                               retval = -ENOMEM;
+                               err("no more memory");
+                               goto free_tty;
+                       }
+                       memset(&dummy, 0, sizeof(struct ktermios));
+                       tty->termios = termios;
+                       port->tty = tty;
+               }
+
                /* only call the device specific open if this 
                 * is the first time the port is opened */
                if (serial->type->open)
                        retval = serial->type->open(port, NULL);
                else
                        retval = usb_serial_generic_open(port, NULL);
-               if (retval)
-                       port->open_count = 0;
-       }
 
-       if (retval) {
-               err ("could not open USB console port");
-               return retval;
-       }
-
-       if (serial->type->set_termios) {
-               struct ktermios dummy;
-               /* build up a fake tty structure so that the open call has something
-                * to look at to get the cflag value */
-               tty = kzalloc(sizeof(*tty), GFP_KERNEL);
-               if (!tty) {
-                       err ("no more memory");
-                       return -ENOMEM;
+               if (retval) {
+                       err("could not open USB console port");
+                       goto free_termios;
                }
-               termios = kzalloc(sizeof(*termios), GFP_KERNEL);
-               if (!termios) {
-                       err ("no more memory");
-                       kfree (tty);
-                       return -ENOMEM;
-               }
-               memset(&dummy, 0, sizeof(struct ktermios));
-               termios->c_cflag = cflag;
-               tty->termios = termios;
-               port->tty = tty;
 
-               /* set up the initial termios settings */
-               serial->type->set_termios(port, &dummy);
-               port->tty = NULL;
-               kfree (termios);
-               kfree (tty);
+               if (serial->type->set_termios) {
+                       termios->c_cflag = cflag;
+                       serial->type->set_termios(port, &dummy);
+
+                       port->tty = NULL;
+                       kfree(termios);
+                       kfree(tty);
+               }
        }
 
+       port->console = 1;
+       retval = 0;
+
+out:
        return retval;
+free_termios:
+       kfree(termios);
+       port->tty = NULL;
+free_tty:
+       kfree(tty);
+reset_open_count:
+       port->open_count = 0;
+goto out;
 }
 
 static void usb_console_write(struct console *co, const char *buf, unsigned count)
index 22833589c4bedcc17ea2120552f6eaf9118a88b3..f3ca66017a031ba81db256216b905b4cf3989efa 100644 (file)
@@ -59,6 +59,7 @@ static struct usb_device_id id_table [] = {
        { USB_DEVICE(0x10A6, 0xAA26) }, /* Knock-off DCU-11 cable */
        { USB_DEVICE(0x10AB, 0x10C5) }, /* Siemens MC60 Cable */
        { USB_DEVICE(0x10B5, 0xAC70) }, /* Nokia CA-42 USB */
+       { USB_DEVICE(0x10C4, 0x800A) }, /* SPORTident BSM7-D-USB main station */
        { USB_DEVICE(0x10C4, 0x803B) }, /* Pololu USB-serial converter */
        { USB_DEVICE(0x10C4, 0x8053) }, /* Enfora EDG1228 */
        { USB_DEVICE(0x10C4, 0x8066) }, /* Argussoft In-System Programmer */
@@ -76,8 +77,13 @@ static struct usb_device_id id_table [] = {
        { USB_DEVICE(0x10C4, 0x8218) }, /* Lipowsky Industrie Elektronik GmbH, HARP-1 */
        { USB_DEVICE(0x10C4, 0xEA60) }, /* Silicon Labs factory default */
        { USB_DEVICE(0x10C4, 0xEA61) }, /* Silicon Labs factory default */
+       { USB_DEVICE(0x10C4, 0xF001) }, /* Elan Digital Systems USBscope50 */
+       { USB_DEVICE(0x10C4, 0xF002) }, /* Elan Digital Systems USBwave12 */
+       { USB_DEVICE(0x10C4, 0xF003) }, /* Elan Digital Systems USBpulse100 */
+       { USB_DEVICE(0x10C4, 0xF004) }, /* Elan Digital Systems USBcount50 */
        { USB_DEVICE(0x10C5, 0xEA61) }, /* Silicon Labs MobiData GPRS USB Modem */
        { USB_DEVICE(0x13AD, 0x9999) }, /* Baltech card reader */
+       { USB_DEVICE(0x166A, 0x0303) }, /* Clipsal 5500PCU C-Bus USB interface */
        { USB_DEVICE(0x16D6, 0x0001) }, /* Jablotron serial interface */
        { } /* Terminating Entry */
 };
@@ -342,7 +348,10 @@ static void cp2101_close (struct usb_serial_port *port, struct file * filp)
        usb_kill_urb(port->write_urb);
        usb_kill_urb(port->read_urb);
 
-       cp2101_set_config_single(port, CP2101_UART, UART_DISABLE);
+       mutex_lock(&port->serial->disc_mutex);
+       if (!port->serial->disconnected)
+               cp2101_set_config_single(port, CP2101_UART, UART_DISABLE);
+       mutex_unlock(&port->serial->disc_mutex);
 }
 
 /*
index 4353df92487f528256ca27bb8169d287d3f85b63..8d9b045aa7e84b1e90f8f5431d088320466079b7 100644 (file)
@@ -319,7 +319,6 @@ static void cyberjack_read_int_callback( struct urb *urb )
        /* React only to interrupts signaling a bulk_in transfer */
        if( (urb->actual_length==4) && (data[0]==0x01) ) {
                short old_rdtodo;
-               int result;
 
                /* This is a announcement of coming bulk_ins. */
                unsigned short size = ((unsigned short)data[3]<<8)+data[2]+3;
index 163386336a5daa76852eda408974ace308bf2176..08c65c1a377163ded8eaf7f861674250852bcc6c 100644 (file)
@@ -682,7 +682,6 @@ static void cypress_close(struct usb_serial_port *port, struct file * filp)
 {
        struct cypress_private *priv = usb_get_serial_port_data(port);
        unsigned int c_cflag;
-       unsigned long flags;
        int bps;
        long timeout;
        wait_queue_t wait;
@@ -690,7 +689,7 @@ static void cypress_close(struct usb_serial_port *port, struct file * filp)
        dbg("%s - port %d", __FUNCTION__, port->number);
 
        /* wait for data to drain from buffer */
-       spin_lock_irqsave(&priv->lock, flags);
+       spin_lock_irq(&priv->lock);
        timeout = CYPRESS_CLOSING_WAIT;
        init_waitqueue_entry(&wait, current);
        add_wait_queue(&port->tty->write_wait, &wait);
@@ -698,18 +697,25 @@ static void cypress_close(struct usb_serial_port *port, struct file * filp)
                set_current_state(TASK_INTERRUPTIBLE);
                if (cypress_buf_data_avail(priv->buf) == 0
                || timeout == 0 || signal_pending(current)
-               || !usb_get_intfdata(port->serial->interface))
+               /* without mutex, allowed due to harmless failure mode */
+               || port->serial->disconnected)
                        break;
-               spin_unlock_irqrestore(&priv->lock, flags);
+               spin_unlock_irq(&priv->lock);
                timeout = schedule_timeout(timeout);
-               spin_lock_irqsave(&priv->lock, flags);
+               spin_lock_irq(&priv->lock);
        }
        set_current_state(TASK_RUNNING);
        remove_wait_queue(&port->tty->write_wait, &wait);
        /* clear out any remaining data in the buffer */
        cypress_buf_clear(priv->buf);
-       spin_unlock_irqrestore(&priv->lock, flags);
-       
+       spin_unlock_irq(&priv->lock);
+
+       /* writing is potentially harmful, lock must be taken */
+       mutex_lock(&port->serial->disc_mutex);
+       if (port->serial->disconnected) {
+               mutex_unlock(&port->serial->disc_mutex);
+               return;
+       }
        /* wait for characters to drain from device */
        bps = tty_get_baud_rate(port->tty);
        if (bps > 1200)
@@ -727,10 +733,10 @@ static void cypress_close(struct usb_serial_port *port, struct file * filp)
                if (c_cflag & HUPCL) {
                        /* drop dtr and rts */
                        priv = usb_get_serial_port_data(port);
-                       spin_lock_irqsave(&priv->lock, flags);
+                       spin_lock_irq(&priv->lock);
                        priv->line_control = 0;
                        priv->cmd_ctrl = 1;
-                       spin_unlock_irqrestore(&priv->lock, flags);
+                       spin_unlock_irq(&priv->lock);
                        cypress_write(port, NULL, 0);
                }
        }
@@ -738,6 +744,7 @@ static void cypress_close(struct usb_serial_port *port, struct file * filp)
        if (stats)
                dev_info (&port->dev, "Statistics: %d Bytes In | %d Bytes Out | %d Commands Issued\n",
                          priv->bytes_in, priv->bytes_out, priv->cmd_count);
+       mutex_unlock(&port->serial->disc_mutex);
 } /* cypress_close */
 
 
index ae410c4678ea697abe9f62a435a5aca73f87490e..5f9c6e46bee5712effaed0346d7ae5a31e305d60 100644 (file)
@@ -1405,19 +1405,19 @@ static void digi_close(struct usb_serial_port *port, struct file *filp)
        unsigned char buf[32];
        struct tty_struct *tty = port->tty;
        struct digi_port *priv = usb_get_serial_port_data(port);
-       unsigned long flags = 0;
 
        dbg("digi_close: TOP: port=%d, open_count=%d",
                priv->dp_port_num, port->open_count);
 
+       mutex_lock(&port->serial->disc_mutex);
        /* if disconnected, just clear flags */
-       if (!usb_get_intfdata(port->serial->interface))
+       if (port->serial->disconnected)
                goto exit;
 
        /* do cleanup only after final close on this port */
-       spin_lock_irqsave(&priv->dp_port_lock, flags);
+       spin_lock_irq(&priv->dp_port_lock);
        priv->dp_in_close = 1;
-       spin_unlock_irqrestore(&priv->dp_port_lock, flags);
+       spin_unlock_irq(&priv->dp_port_lock);
 
        /* tell line discipline to process only XON/XOFF */
        tty->closing = 1;
@@ -1482,11 +1482,12 @@ static void digi_close(struct usb_serial_port *port, struct file *filp)
        }
        tty->closing = 0;
 exit:
-       spin_lock_irqsave(&priv->dp_port_lock, flags);
+       spin_lock_irq(&priv->dp_port_lock);
        priv->dp_write_urb_in_use = 0;
        priv->dp_in_close = 0;
        wake_up_interruptible(&priv->dp_close_wait);
-       spin_unlock_irqrestore(&priv->dp_port_lock, flags);
+       spin_unlock_irq(&priv->dp_port_lock);
+       mutex_unlock(&port->serial->disc_mutex);
        dbg("digi_close: done");
 }
 
index 97ee718b1da2a29bf08ed4f30e88cff14bb3beb9..3f698baa0abb69d1015c4d69fa7576d357f0b9c5 100644 (file)
@@ -53,6 +53,6 @@ int ezusb_set_reset (struct usb_serial *serial, unsigned char reset_bit)
 }
 
 
-EXPORT_SYMBOL(ezusb_writememory);
-EXPORT_SYMBOL(ezusb_set_reset);
+EXPORT_SYMBOL_GPL(ezusb_writememory);
+EXPORT_SYMBOL_GPL(ezusb_set_reset);
 
index c40e77dccf8ea91224b94841e1f74efb9533613d..90dcc625f70deb008c45ca0c6c349ba0a6d6eb4e 100644 (file)
  * See http://ftdi-usb-sio.sourceforge.net for upto date testing info
  *     and extra documentation
  *
- * (21/Jul/2004) Ian Abbott
- *      Incorporated Steven Turner's code to add support for the FT2232C chip.
- *      The prelimilary port to the 2.6 kernel was by Rus V. Brushkoff.  I have
- *      fixed a couple of things.
- *
- * (27/May/2004) Ian Abbott
- *      Improved throttling code, mostly stolen from the WhiteHEAT driver.
- *
- * (26/Mar/2004) Jan Capek
- *      Added PID's for ICD-U20/ICD-U40 - incircuit PIC debuggers from CCS Inc.
- *
- * (09/Feb/2004) Ian Abbott
- *      Changed full name of USB-UIRT device to avoid "/" character.
- *      Added FTDI's alternate PID (0x6006) for FT232/245 devices.
- *      Added PID for "ELV USB Module UO100" from Stefan Frings.
- *
- * (21/Oct/2003) Ian Abbott
- *      Renamed some VID/PID macros for Matrix Orbital and Perle Systems
- *      devices.  Removed Matrix Orbital and Perle Systems devices from the
- *      8U232AM device table, but left them in the FT232BM table, as they are
- *      known to use only FT232BM.
- *
- * (17/Oct/2003) Scott Allen
- *      Added vid/pid for Perle Systems UltraPort USB serial converters
- *
- * (21/Sep/2003) Ian Abbott
- *      Added VID/PID for Omnidirectional Control Technology US101 USB to
- *      RS-232 adapter (also rebadged as Dick Smith Electronics XH6381).
- *      VID/PID supplied by Donald Gordon.
- *
- * (19/Aug/2003) Ian Abbott
- *      Freed urb's transfer buffer in write bulk callback.
- *      Omitted some paranoid checks in write bulk callback that don't matter.
- *      Scheduled work in write bulk callback regardless of port's open count.
- *
- * (05/Aug/2003) Ian Abbott
- *      Added VID/PID for ID TECH IDT1221U USB to RS-232 adapter.
- *      VID/PID provided by Steve Briggs.
- *
- * (23/Jul/2003) Ian Abbott
- *      Added PIDs for CrystalFontz 547, 633, 631, 635, 640 and 640 from
- *      Wayne Wylupski.
- *
- * (10/Jul/2003) David Glance
- *      Added PID for DSS-20 SyncStation cradle for Sony-Ericsson P800.
- *
- * (27/Jun/2003) Ian Abbott
- *     Reworked the urb handling logic.  We have no more pool, but dynamically
- *     allocate the urb and the transfer buffer on the fly.  In testing this
- *     does not incure any measurable overhead.  This also relies on the fact
- *     that we have proper reference counting logic for urbs.  I nicked this
- *     from Greg KH's Visor driver.
- *
- * (23/Jun/2003) Ian Abbott
- *      Reduced flip buffer pushes and corrected a data length test in
- *      ftdi_read_bulk_callback.
- *      Defererence pointers after any paranoid checks, not before.
- *
- * (21/Jun/2003) Erik Nygren
- *      Added support for Home Electronics Tira-1 IR transceiver using FT232BM chip.
- *      See <http://www.home-electro.com/tira1.htm>.  Only operates properly
- *      at 100000 and RTS-CTS, so set custom divisor mode on startup.
- *      Also force the Tira-1 and USB-UIRT to only use their custom baud rates.
- *
- * (18/Jun/2003) Ian Abbott
- *      Added Device ID of the USB relais from Rudolf Gugler (backported from
- *      Philipp Gühring's patch for 2.5.x kernel).
- *      Moved read transfer buffer reallocation into startup function.
- *      Free existing write urb and transfer buffer in startup function.
- *      Only use urbs in write urb pool that were successfully allocated.
- *      Moved some constant macros out of functions.
- *      Minor whitespace and comment changes.
- *
- * (12/Jun/2003) David Norwood
- *      Added support for USB-UIRT IR transceiver using 8U232AM chip.
- *      See <http://home.earthlink.net/~jrhees/USBUIRT/index.htm>.  Only
- *      operates properly at 312500, so set custom divisor mode on startup.
- *
- * (12/Jun/2003) Ian Abbott
- *      Added Sealevel SeaLINK+ 210x, 220x, 240x, 280x vid/pids from Tuan Hoang
- *      - I've eliminated some that don't seem to exist!
- *      Added Home Electronics Tira-1 IR transceiver pid from Chris Horn
- *      Some whitespace/coding-style cleanups
- *
- * (11/Jun/2003) Ian Abbott
- *      Fixed unsafe spinlock usage in ftdi_write
- *
- * (24/Feb/2003) Richard Shooter
- *      Increase read buffer size to improve read speeds at higher baud rates
- *      (specifically tested with up to 1Mb/sec at 1.5M baud)
- *
- * (23/Feb/2003) John Wilkins
- *      Added Xon/xoff flow control (activating support in the ftdi device)
- *      Added vid/pid for Videonetworks/Homechoice (UK ISP)
- *
- * (23/Feb/2003) Bill Ryder
- *      Added matrix orb device vid/pids from Wayne Wylupski
- *
- * (19/Feb/2003) Ian Abbott
- *      For TIOCSSERIAL, set alt_speed to 0 when ASYNC_SPD_MASK value has
- *      changed to something other than ASYNC_SPD_HI, ASYNC_SPD_VHI,
- *      ASYNC_SPD_SHI or ASYNC_SPD_WARP.  Also, unless ASYNC_SPD_CUST is in
- *      force, don't bother changing baud rate when custom_divisor has changed.
- *
- * (18/Feb/2003) Ian Abbott
- *      Fixed TIOCMGET handling to include state of DTR and RTS, the state
- *      of which are now saved by set_dtr() and set_rts().
- *      Fixed improper storage class for buf in set_dtr() and set_rts().
- *      Added FT232BM chip type and support for its extra baud rates (compared
- *      to FT8U232AM).
- *      Took account of special case divisor values for highest baud rates of
- *      FT8U232AM and FT232BM.
- *      For TIOCSSERIAL, forced alt_speed to 0 when ASYNC_SPD_CUST kludge used,
- *      as previous alt_speed setting is now stale.
- *      Moved startup code common between the startup routines for the
- *      different chip types into a common subroutine.
- *
- * (17/Feb/2003) Bill Ryder
- *      Added write urb buffer pool on a per device basis
- *      Added more checking for open file on callbacks (fixed OOPS)
- *      Added CrystalFontz 632 and 634 PIDs
- *         (thanx to CrystalFontz for the sample devices - they flushed out
- *           some driver bugs)
- *      Minor debugging message changes
- *      Added throttle, unthrottle and chars_in_buffer functions
- *      Fixed FTDI_SIO (the original device) bug
- *      Fixed some shutdown handling
- *
- *
- *
- *
- * (07/Jun/2002) Kuba Ober
- *     Changed FTDI_SIO_BASE_BAUD_TO_DIVISOR macro into ftdi_baud_to_divisor
- *     function. It was getting too complex.
- *     Fix the divisor calculation logic which was setting divisor of 0.125
- *     instead of 0.5 for fractional parts of divisor equal to 5/8, 6/8, 7/8.
- *     Also make it bump up the divisor to next integer in case of 7/8 - it's
- *     a better approximation.
- *
- * (25/Jul/2002) Bill Ryder inserted Dmitri's TIOCMIWAIT patch
- *      Not tested by me but it doesn't break anything I use.
- *
- * (04/Jan/2002) Kuba Ober
- *     Implemented 38400 baudrate kludge, where it can be substituted with other
- *       values. That's the only way to set custom baudrates.
- *     Implemented TIOCSSERIAL, TIOCGSERIAL ioctl's so that setserial is happy.
- *     FIXME: both baudrate things should eventually go to usbserial.c as other
- *       devices may need that functionality too. Actually, it can probably be
- *       merged in serial.c somehow - too many drivers repeat this code over
- *       and over.
- *     Fixed baudrate forgetfulness - open() used to reset baudrate to 9600 every time.
- *     Divisors for baudrates are calculated by a macro.
- *     Small code cleanups. Ugly whitespace changes for Plato's sake only ;-].
- *
- * (04/Nov/2001) Bill Ryder
- *     Fixed bug in read_bulk_callback where incorrect urb buffer was used.
- *     Cleaned up write offset calculation
- *     Added write_room since default values can be incorrect for sio
- *     Changed write_bulk_callback to use same queue_task as other drivers
- *        (the previous version caused panics)
- *     Removed port iteration code since the device only has one I/O port and it
- *       was wrong anyway.
- *
- * (31/May/2001) gkh
- *     Switched from using spinlock to a semaphore, which fixes lots of problems.
- *
- * (23/May/2001)   Bill Ryder
- *     Added runtime debug patch (thanx Tyson D Sawyer).
- *     Cleaned up comments for 8U232
- *     Added parity, framing and overrun error handling
- *     Added receive break handling.
- *
- * (04/08/2001) gb
- *     Identify version on module load.
- *
- * (18/March/2001) Bill Ryder
- *     (Not released)
- *     Added send break handling. (requires kernel patch too)
- *     Fixed 8U232AM hardware RTS/CTS etc status reporting.
- *     Added flipbuf fix copied from generic device
- *
- * (12/3/2000) Bill Ryder
- *     Added support for 8U232AM device.
- *     Moved PID and VIDs into header file only.
- *     Turned on low-latency for the tty (device will do high baudrates)
- *     Added shutdown routine to close files when device removed.
- *     More debug and error message cleanups.
- *
- * (11/13/2000) Bill Ryder
- *     Added spinlock protected open code and close code.
- *     Multiple opens work (sort of - see webpage mentioned above).
- *     Cleaned up comments. Removed multiple PID/VID definitions.
- *     Factorised cts/dtr code
- *     Made use of __FUNCTION__ in dbg's
- *
- * (11/01/2000) Adam J. Richter
- *     usb_device_id table support
- *
- * (10/05/2000) gkh
- *     Fixed bug with urb->dev not being set properly, now that the usb
- *     core needs it.
- *
- * (09/11/2000) gkh
- *     Removed DEBUG #ifdefs with call to usb_serial_debug_data
- *
- * (07/19/2000) gkh
- *     Added module_init and module_exit functions to handle the fact that this
- *     driver is a loadable module now.
- *
- * (04/04/2000) Bill Ryder
- *     Fixed bugs in TCGET/TCSET ioctls (by removing them - they are
- *        handled elsewhere in the tty io driver chain).
- *
- * (03/30/2000) Bill Ryder
- *     Implemented lots of ioctls
- *     Fixed a race condition in write
- *     Changed some dbg's to errs
- *
- * (03/26/2000) gkh
- *     Split driver up into device specific pieces.
+ * Change entries from 2004 and earlier can be found in versions of this
+ * file in kernel versions prior to the 2.6.24 release.
  *
  */
 
@@ -309,12 +91,12 @@ struct ftdi_sio_quirk {
        void (*port_probe)(struct ftdi_private *); /* Special settings for probed ports. */
 };
 
-static int   ftdi_olimex_probe         (struct usb_serial *serial);
+static int   ftdi_jtag_probe           (struct usb_serial *serial);
 static void  ftdi_USB_UIRT_setup       (struct ftdi_private *priv);
 static void  ftdi_HE_TIRA1_setup       (struct ftdi_private *priv);
 
-static struct ftdi_sio_quirk ftdi_olimex_quirk = {
-       .probe  = ftdi_olimex_probe,
+static struct ftdi_sio_quirk ftdi_jtag_quirk = {
+       .probe  = ftdi_jtag_probe,
 };
 
 static struct ftdi_sio_quirk ftdi_USB_UIRT_quirk = {
@@ -471,30 +253,28 @@ static struct usb_device_id id_table_combined [] = {
        { USB_DEVICE(FTDI_VID, FTDI_IBS_PEDO_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_IBS_PROD_PID) },
        /*
-        * These will probably use user-space drivers.  Uncomment them if
-        * you need them or use the user-specified vendor/product module
-        * parameters (see ftdi_sio.h for the numbers).  Make a fuss if
-        * you think the driver should recognize any of them by default.
+        * Due to many user requests for multiple ELV devices we enable
+        * them by default.
         */
-       /* { USB_DEVICE(FTDI_VID, FTDI_ELV_CLI7000_PID) }, */
-       /* { USB_DEVICE(FTDI_VID, FTDI_ELV_PPS7330_PID) }, */
-       /* { USB_DEVICE(FTDI_VID, FTDI_ELV_TFM100_PID) }, */
-       /* { USB_DEVICE(FTDI_VID, FTDI_ELV_UDF77_PID) }, */
-       /* { USB_DEVICE(FTDI_VID, FTDI_ELV_UIO88_PID) }, */
-       /* { USB_DEVICE(FTDI_VID, FTDI_ELV_UAD8_PID) }, */
-       /* { USB_DEVICE(FTDI_VID, FTDI_ELV_UDA7_PID) }, */
-       /* { USB_DEVICE(FTDI_VID, FTDI_ELV_USI2_PID) }, */
-       /* { USB_DEVICE(FTDI_VID, FTDI_ELV_T1100_PID) }, */
-       /* { USB_DEVICE(FTDI_VID, FTDI_ELV_PCD200_PID) }, */
-       /* { USB_DEVICE(FTDI_VID, FTDI_ELV_ULA200_PID) }, */
-       /* { USB_DEVICE(FTDI_VID, FTDI_ELV_CSI8_PID) }, */
-       /* { USB_DEVICE(FTDI_VID, FTDI_ELV_EM1000DL_PID) }, */
-       /* { USB_DEVICE(FTDI_VID, FTDI_ELV_PCK100_PID) }, */
-       /* { USB_DEVICE(FTDI_VID, FTDI_ELV_RFP500_PID) }, */
-       /* { USB_DEVICE(FTDI_VID, FTDI_ELV_FS20SIG_PID) }, */
-       /* { USB_DEVICE(FTDI_VID, FTDI_ELV_WS300PC_PID) }, */
-       /* { USB_DEVICE(FTDI_VID, FTDI_ELV_FHZ1300PC_PID) }, */
-       /* { USB_DEVICE(FTDI_VID, FTDI_ELV_WS500_PID) }, */
+       { USB_DEVICE(FTDI_VID, FTDI_ELV_CLI7000_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_ELV_PPS7330_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_ELV_TFM100_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_ELV_UDF77_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_ELV_UIO88_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_ELV_UAD8_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_ELV_UDA7_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_ELV_USI2_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_ELV_T1100_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_ELV_PCD200_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_ELV_ULA200_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_ELV_CSI8_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_ELV_EM1000DL_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_ELV_PCK100_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_ELV_RFP500_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_ELV_FS20SIG_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_ELV_WS300PC_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_ELV_FHZ1300PC_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_ELV_WS500_PID) },
        { USB_DEVICE(FTDI_VID, LINX_SDMUSBQSS_PID) },
        { USB_DEVICE(FTDI_VID, LINX_MASTERDEVEL2_PID) },
        { USB_DEVICE(FTDI_VID, LINX_FUTURE_0_PID) },
@@ -545,6 +325,7 @@ static struct usb_device_id id_table_combined [] = {
        { USB_DEVICE(FTDI_VID, FTDI_ATIK_ATK16C_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_ATIK_ATK16HR_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_ATIK_ATK16HRC_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_ATIK_ATK16IC_PID) },
        { USB_DEVICE(KOBIL_VID, KOBIL_CONV_B1_PID) },
        { USB_DEVICE(KOBIL_VID, KOBIL_CONV_KAAN_PID) },
        { USB_DEVICE(POSIFLEX_VID, POSIFLEX_PP7000_PID) },
@@ -569,8 +350,13 @@ static struct usb_device_id id_table_combined [] = {
        { USB_DEVICE(TELLDUS_VID, TELLDUS_TELLSTICK_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_MAXSTREAM_PID) },
        { USB_DEVICE(TML_VID, TML_USB_SERIAL_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_ELSTER_UNICOM_PID) },
        { USB_DEVICE(OLIMEX_VID, OLIMEX_ARM_USB_OCD_PID),
-               .driver_info = (kernel_ulong_t)&ftdi_olimex_quirk },
+               .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
+       { USB_DEVICE(FIC_VID, FIC_NEO1973_DEBUG_PID),
+               .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
+       { USB_DEVICE(FTDI_VID, FTDI_OOCDLINK_PID),
+               .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
        { },                                    /* Optional parameter entry */
        { }                                     /* Terminating entry */
 };
@@ -1283,10 +1069,11 @@ static void ftdi_HE_TIRA1_setup (struct ftdi_private *priv)
 } /* ftdi_HE_TIRA1_setup */
 
 /*
- * First port on Olimex arm-usb-ocd is reserved for JTAG interface
- * and can be accessed from userspace using openocd.
+ * First port on JTAG adaptors such as Olimex arm-usb-ocd or the FIC/OpenMoko
+ * Neo1973 Debug Board is reserved for JTAG interface and can be accessed from
+ * userspace using openocd.
  */
-static int ftdi_olimex_probe(struct usb_serial *serial)
+static int ftdi_jtag_probe(struct usb_serial *serial)
 {
        struct usb_device *udev = serial->dev;
        struct usb_interface *interface = serial->interface;
@@ -1294,7 +1081,7 @@ static int ftdi_olimex_probe(struct usb_serial *serial)
        dbg("%s",__FUNCTION__);
 
        if (interface == udev->actconfig->interface[0]) {
-               info("Ignoring reserved serial port on Olimex arm-usb-ocd\n");
+               info("Ignoring serial port reserved for JTAG");
                return -ENODEV;
        }
 
@@ -1411,7 +1198,8 @@ static void ftdi_close (struct usb_serial_port *port, struct file *filp)
 
        dbg("%s", __FUNCTION__);
 
-       if (c_cflag & HUPCL){
+       mutex_lock(&port->serial->disc_mutex);
+       if (c_cflag & HUPCL && !port->serial->disconnected){
                /* Disable flow control */
                if (usb_control_msg(port->serial->dev,
                                    usb_sndctrlpipe(port->serial->dev, 0),
@@ -1425,6 +1213,7 @@ static void ftdi_close (struct usb_serial_port *port, struct file *filp)
                /* drop RTS and DTR */
                clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
        } /* Note change no line if hupcl is off */
+       mutex_unlock(&port->serial->disc_mutex);
 
        /* cancel any scheduled reading */
        cancel_delayed_work(&priv->rx_work);
index b51cbb0eaa054491c8bcc2479788f28fa0a0afde..6eee2ab914eca092d1d3b53dc92b30ee294605d1 100644 (file)
 #define FTDI_MTXORB_5_PID      0xFA05  /* Matrix Orbital Product Id */
 #define FTDI_MTXORB_6_PID      0xFA06  /* Matrix Orbital Product Id */
 
+/* OOCDlink by Joern Kaipf <joernk@web.de>
+ * (http://www.joernonline.de/dw/doku.php?id=start&idx=projects:oocdlink) */
+#define FTDI_OOCDLINK_PID      0xbaf8  /* Amontec JTAGkey */
+
 /* Interbiometrics USB I/O Board */
 /* Developed for Interbiometrics by Rudolf Gugler */
 #define INTERBIOMETRICS_VID              0x1209
 #define FTDI_ELV_WS300PC_PID   0xE0F6  /* PC-Wetterstation (WS 300 PC) */
 #define FTDI_ELV_FHZ1300PC_PID 0xE0E8  /* FHZ 1300 PC */
 #define FTDI_ELV_WS500_PID     0xE0E9  /* PC-Wetterstation (WS 500) */
+#define FTDI_ELV_EM1010PC_PID  0xE0EF  /* Engery monitor EM 1010 PC */
 
 /*
  * Definitions for ID TECH (www.idt-net.com) devices
 #define FTDI_ATIK_ATK16C_PID   0xDF32  /* ATIK ATK-16C Colour Camera */
 #define FTDI_ATIK_ATK16HR_PID  0xDF31  /* ATIK ATK-16HR Grayscale Camera */
 #define FTDI_ATIK_ATK16HRC_PID 0xDF33  /* ATIK ATK-16HRC Colour Camera */
+#define FTDI_ATIK_ATK16IC_PID   0xDF35  /* ATIK ATK-16IC Grayscale Camera */
 
 /*
  * Protego product ids
 #define OLIMEX_VID                     0x15BA
 #define OLIMEX_ARM_USB_OCD_PID         0x0003
 
+/* www.elsterelectricity.com Elster Unicom III Optical Probe */
+#define FTDI_ELSTER_UNICOM_PID         0xE700 /* Product Id */
 
 /*
  * The Mobility Lab (TML)
 #define FTDI_SIO_GET_LATENCY_TIMER     10 /* Get the latency timer */
 
 
+/*
+ * FIC / OpenMoko, Inc. http://wiki.openmoko.org/wiki/Neo1973_Debug_Board_v3
+ * Submitted by Harald Welte <laforge@openmoko.org>
+ */
+#define        FIC_VID                 0x1457
+#define        FIC_NEO1973_DEBUG_PID   0x5118
+
 /*
  *   BmRequestType:  1100 0000b
  *   bRequest:       FTDI_E2_READ
index f1c90cfe72515365236c9ddf61e1c41ee90fe82a..d74e43d69230b5ea1d7b75a4b599f9052f658004 100644 (file)
@@ -1020,19 +1020,26 @@ static void garmin_close (struct usb_serial_port *port, struct file * filp)
        if (!serial)
                return;
 
-       garmin_clear(garmin_data_p);
+       mutex_lock(&port->serial->disc_mutex);
+       if (!port->serial->disconnected)
+               garmin_clear(garmin_data_p);
 
        /* shutdown our urbs */
        usb_kill_urb (port->read_urb);
        usb_kill_urb (port->write_urb);
 
-       if (noResponseFromAppLayer(garmin_data_p) ||
-           ((garmin_data_p->flags & CLEAR_HALT_REQUIRED) != 0)) {
-               process_resetdev_request(port);
-               garmin_data_p->state = STATE_RESET;
+       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 {
                garmin_data_p->state = STATE_DISCONNECTED;
        }
+       mutex_unlock(&port->serial->disc_mutex);
 }
 
 
index d41531139c55e249ce14cd0ca86ada8cd5024409..97fa3c4284350ab24a32cc9d46d69bc4e4fe39e2 100644 (file)
@@ -175,6 +175,14 @@ int usb_serial_generic_resume(struct usb_serial *serial)
        struct usb_serial_port *port;
        int i, c = 0, r;
 
+#ifdef CONFIG_PM
+       /*
+        * If this is an autoresume, don't submit URBs.
+        * They will be submitted in the open function instead.
+        */
+       if (serial->dev->auto_pm)
+               return 0;
+#endif
        for (i = 0; i < serial->num_ports; i++) {
                port = serial->port[i];
                if (port->open_count && port->read_urb) {
index a5d2e115e1675e954c28ad67490646a4de27976e..3428ccc28da7ca0a96ee284e0a300ba2a0313632 100644 (file)
@@ -959,7 +959,7 @@ static int edge_open (struct usb_serial_port *port, struct file * filp)
  *
  *     This function will block the close until one of the following:
  *             1. Response to our Chase comes from Edgeport
- *             2. A timout of 10 seconds without activity has expired
+ *             2. A timeout of 10 seconds without activity has expired
  *                (1K of Edgeport data @ 2400 baud ==> 4 sec to empty)
  *
  ************************************************************************/
@@ -999,7 +999,7 @@ static void block_until_chase_response(struct edgeport_port *edge_port)
                                return;
                        }
                } else {
-                       // Reset timout value back to 10 seconds
+                       // Reset timeout value back to 10 seconds
                        dbg("%s - Last %d, Current %d", __FUNCTION__, lastCredits, edge_port->txCredits);
                        loop = 10;
                }
@@ -1014,7 +1014,7 @@ static void block_until_chase_response(struct edgeport_port *edge_port)
  *     This function will block the close until one of the following:
  *             1. TX count are 0
  *             2. The edgeport has stopped
- *             3. A timout of 3 seconds without activity has expired
+ *             3. A timeout of 3 seconds without activity has expired
  *
  ************************************************************************/
 static void block_until_tx_empty (struct edgeport_port *edge_port)
@@ -1050,7 +1050,7 @@ static void block_until_tx_empty (struct edgeport_port *edge_port)
                                return;
                        }
                } else {
-                       // Reset timout value back to seconds
+                       // Reset timeout value back to seconds
                        loop = 30;
                }
        }
index b8670905bc3ac858d4e30aa91c2191e4c883c88e..cd3405953f741a4b4e103d482a0009db59453550 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/tty_flip.h>
 #include <linux/module.h>
 #include <linux/spinlock.h>
+#include <linux/mutex.h>
 #include <linux/serial.h>
 #include <linux/ioctl.h>
 #include <asm/uaccess.h>
@@ -133,7 +134,7 @@ struct edgeport_serial {
        struct product_info product_info;
        u8 TI_I2C_Type;                 // Type of I2C in UMP
        u8 TiReadI2C;                   // Set to TRUE if we have read the I2c in Boot Mode
-       struct semaphore es_sem;
+       struct mutex es_lock;
        int num_ports_open;
        struct usb_serial *serial;
 };
@@ -1978,7 +1979,7 @@ static int edge_open (struct usb_serial_port *port, struct file * filp)
        }
        
        /* set up the port settings */
-       edge_set_termios (port, NULL);
+       edge_set_termios (port, port->tty->termios);
 
        /* open up the port */
 
@@ -2044,7 +2045,7 @@ static int edge_open (struct usb_serial_port *port, struct file * filp)
        dbg ("ShadowMCR 0x%X", edge_port->shadow_mcr);
 
        edge_serial = edge_port->edge_serial;
-       if (down_interruptible(&edge_serial->es_sem))
+       if (mutex_lock_interruptible(&edge_serial->es_lock))
                return -ERESTARTSYS;
        if (edge_serial->num_ports_open == 0) {
                /* we are the first port to be opened, let's post the interrupt urb */
@@ -2052,7 +2053,7 @@ static int edge_open (struct usb_serial_port *port, struct file * filp)
                if (!urb) {
                        dev_err (&port->dev, "%s - no interrupt urb present, exiting\n", __FUNCTION__);
                        status = -EINVAL;
-                       goto up_es_sem;
+                       goto release_es_lock;
                }
                urb->complete = edge_interrupt_callback;
                urb->context = edge_serial;
@@ -2060,7 +2061,7 @@ static int edge_open (struct usb_serial_port *port, struct file * filp)
                status = usb_submit_urb (urb, GFP_KERNEL);
                if (status) {
                        dev_err (&port->dev, "%s - usb_submit_urb failed with value %d\n", __FUNCTION__, status);
-                       goto up_es_sem;
+                       goto release_es_lock;
                }
        }
 
@@ -2092,13 +2093,13 @@ static int edge_open (struct usb_serial_port *port, struct file * filp)
 
        dbg("%s - exited", __FUNCTION__);
 
-       goto up_es_sem;
+       goto release_es_lock;
 
 unlink_int_urb:
        if (edge_port->edge_serial->num_ports_open == 0)
                usb_kill_urb(port->serial->port[0]->interrupt_in_urb);
-up_es_sem:
-       up(&edge_serial->es_sem);
+release_es_lock:
+       mutex_unlock(&edge_serial->es_lock);
        return status;
 }
 
@@ -2137,14 +2138,14 @@ static void edge_close (struct usb_serial_port *port, struct file *filp)
                                     0,
                                     NULL,
                                     0);
-       down(&edge_serial->es_sem);
+       mutex_lock(&edge_serial->es_lock);
        --edge_port->edge_serial->num_ports_open;
        if (edge_port->edge_serial->num_ports_open <= 0) {
                /* last port is now closed, let's shut down our interrupt urb */
                usb_kill_urb(port->serial->port[0]->interrupt_in_urb);
                edge_port->edge_serial->num_ports_open = 0;
        }
-       up(&edge_serial->es_sem);
+       mutex_unlock(&edge_serial->es_lock);
        edge_port->close_pending = 0;
 
        dbg("%s - exited", __FUNCTION__);
@@ -2393,11 +2394,6 @@ static void change_port_settings (struct edgeport_port *edge_port, struct ktermi
        dbg("%s - port %d", __FUNCTION__, edge_port->port->number);
 
        tty = edge_port->port->tty;
-       if ((!tty) ||
-           (!tty->termios)) {
-               dbg("%s - no tty structures", __FUNCTION__);
-               return;
-       }
 
        config = kmalloc (sizeof (*config), GFP_KERNEL);
        if (!config) {
@@ -2492,15 +2488,21 @@ static void change_port_settings (struct edgeport_port *edge_port, struct ktermi
                }
        }
 
+       tty->termios->c_cflag &= ~CMSPAR;
+
        /* Round the baud rate */
        baud = tty_get_baud_rate(tty);
        if (!baud) {
                /* pick a default, any default... */
                baud = 9600;
-       }
+       } else
+               tty_encode_baud_rate(tty, baud, baud);
+
        edge_port->baud_rate = baud;
        config->wBaudRate = (__u16)((461550L + baud/2) / baud);
 
+       /* FIXME: Recompute actual baud from divisor here */
+
        dbg ("%s - baud rate = %d, wBaudRate = %d", __FUNCTION__, baud, config->wBaudRate);
 
        dbg ("wBaudRate:   %d", (int)(461550L / config->wBaudRate));
@@ -2538,19 +2540,12 @@ static void edge_set_termios (struct usb_serial_port *port, struct ktermios *old
        struct tty_struct *tty = port->tty;
        unsigned int cflag;
 
-       if (!port->tty || !port->tty->termios) {
-               dbg ("%s - no tty or termios", __FUNCTION__);
-               return;
-       }
-
        cflag = tty->termios->c_cflag;
 
        dbg("%s - clfag %08x iflag %08x", __FUNCTION__, 
            tty->termios->c_cflag, tty->termios->c_iflag);
-       if (old_termios) {
-               dbg("%s - old clfag %08x old iflag %08x", __FUNCTION__,
-                   old_termios->c_cflag, old_termios->c_iflag);
-       }
+       dbg("%s - old clfag %08x old iflag %08x", __FUNCTION__,
+           old_termios->c_cflag, old_termios->c_iflag);
 
        dbg("%s - port %d", __FUNCTION__, port->number);
 
@@ -2743,7 +2738,7 @@ static int edge_startup (struct usb_serial *serial)
                dev_err(&serial->dev->dev, "%s - Out of memory\n", __FUNCTION__);
                return -ENOMEM;
        }
-       sema_init(&edge_serial->es_sem, 1);
+       mutex_init(&edge_serial->es_lock);
        edge_serial->serial = serial;
        usb_set_serial_data(serial, edge_serial);
 
diff --git a/drivers/usb/serial/iuu_phoenix.c b/drivers/usb/serial/iuu_phoenix.c
new file mode 100644 (file)
index 0000000..fde188e
--- /dev/null
@@ -0,0 +1,1217 @@
+/*
+ * Infinity Unlimited USB Phoenix driver
+ *
+ * Copyright (C) 2007 Alain Degreffe (eczema@ecze.com)
+ *
+ * Original code taken from iuutool (Copyright (C) 2006 Juan Carlos Borrás)
+ *
+ *     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.
+ *
+ *  And tested with help of WB Electronics
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/serial.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/spinlock.h>
+#include <linux/uaccess.h>
+#include <linux/usb.h>
+#include <linux/usb/serial.h>
+#include "iuu_phoenix.h"
+#include <linux/random.h>
+
+
+#ifdef CONFIG_USB_SERIAL_DEBUG
+static int debug = 1;
+#else
+static int debug;
+#endif
+
+/*
+ * Version Information
+ */
+#define DRIVER_VERSION "v0.5"
+#define DRIVER_DESC "Infinity USB Unlimited Phoenix driver"
+
+static struct usb_device_id id_table[] = {
+       {USB_DEVICE(IUU_USB_VENDOR_ID, IUU_USB_PRODUCT_ID)},
+       {}                      /* Terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, id_table);
+
+static struct usb_driver iuu_driver = {
+       .name = "iuu_phoenix",
+       .probe = usb_serial_probe,
+       .disconnect = usb_serial_disconnect,
+       .id_table = id_table,
+       .no_dynamic_id = 1,
+};
+
+/* turbo parameter */
+static int boost = 100;
+static int clockmode = 1;
+static int cdmode = 1;
+static int iuu_cardin;
+static int iuu_cardout;
+static int xmas;
+
+static void read_rxcmd_callback(struct urb *urb);
+
+struct iuu_private {
+       spinlock_t lock;        /* store irq state */
+       wait_queue_head_t delta_msr_wait;
+       u8 line_control;
+       u8 line_status;
+       u8 termios_initialized;
+       int tiostatus;          /* store IUART SIGNAL for tiocmget call */
+       u8 reset;               /* if 1 reset is needed */
+       int poll;               /* number of poll */
+       u8 *writebuf;           /* buffer for writing to device */
+       int writelen;           /* num of byte to write to device */
+       u8 *buf;                /* used for initialize speed */
+       u8 *dbgbuf;             /* debug buffer */
+       u8 len;
+};
+
+
+static void iuu_free_buf(struct iuu_private *priv)
+{
+       kfree(priv->buf);
+       kfree(priv->dbgbuf);
+       kfree(priv->writebuf);
+}
+
+static int iuu_alloc_buf(struct iuu_private *priv)
+{
+       priv->buf = kzalloc(256, GFP_KERNEL);
+       priv->dbgbuf = kzalloc(256, GFP_KERNEL);
+       priv->writebuf = kzalloc(256, GFP_KERNEL);
+       if (!priv->buf || !priv->dbgbuf || !priv->writebuf) {
+               iuu_free_buf(priv);
+               dbg("%s problem allocation buffer", __FUNCTION__);
+               return -ENOMEM;
+       }
+       dbg("%s - Privates buffers allocation success", __FUNCTION__);
+       return 0;
+}
+
+static int iuu_startup(struct usb_serial *serial)
+{
+       struct iuu_private *priv;
+       priv = kzalloc(sizeof(struct iuu_private), GFP_KERNEL);
+       dbg("%s- priv allocation success", __FUNCTION__);
+       if (!priv)
+               return -ENOMEM;
+       if (iuu_alloc_buf(priv)) {
+               kfree(priv);
+               return -ENOMEM;
+       }
+       spin_lock_init(&priv->lock);
+       init_waitqueue_head(&priv->delta_msr_wait);
+       usb_set_serial_port_data(serial->port[0], priv);
+       return 0;
+}
+
+/* Shutdown function */
+static void iuu_shutdown(struct usb_serial *serial)
+{
+       struct usb_serial_port *port = serial->port[0];
+       struct iuu_private *priv = usb_get_serial_port_data(port);
+       if (!port)
+               return;
+
+       dbg("%s", __FUNCTION__);
+
+       if (priv) {
+               iuu_free_buf(priv);
+               dbg("%s - I will free all", __FUNCTION__);
+               usb_set_serial_port_data(port, NULL);
+
+               dbg("%s - priv is not anymore in port structure", __FUNCTION__);
+               kfree(priv);
+
+               dbg("%s priv is now kfree", __FUNCTION__);
+       }
+}
+
+static int iuu_tiocmset(struct usb_serial_port *port, struct file *file,
+                       unsigned int set, unsigned int clear)
+{
+       struct iuu_private *priv = usb_get_serial_port_data(port);
+       struct tty_struct *tty;
+       tty = port->tty;
+
+       dbg("%s (%d) msg : SET = 0x%04x, CLEAR = 0x%04x ", __FUNCTION__,
+           port->number, set, clear);
+       if (set & TIOCM_RTS)
+               priv->tiostatus = TIOCM_RTS;
+
+       if (!(set & TIOCM_RTS) && priv->tiostatus == TIOCM_RTS) {
+               dbg("%s TIOCMSET RESET called !!!", __FUNCTION__);
+               priv->reset = 1;
+               return 0;
+       }
+
+       return 0;
+}
+
+/* This is used to provide a carrier detect mechanism
+ * When a card is present, the response is 0x00
+ * When no card , the reader respond with TIOCM_CD
+ * This is known as CD autodetect mechanism
+ */
+static int iuu_tiocmget(struct usb_serial_port *port, struct file *file)
+{
+       struct iuu_private *priv = usb_get_serial_port_data(port);
+       return priv->tiostatus;
+}
+
+static void iuu_rxcmd(struct urb *urb)
+{
+       struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+       int result;
+       dbg("%s - enter", __FUNCTION__);
+
+       if (urb->status) {
+               dbg("%s - urb->status = %d", __FUNCTION__, urb->status);
+               /* error stop all */
+               return;
+       }
+
+
+       memset(port->write_urb->transfer_buffer, IUU_UART_RX, 1);
+       usb_fill_bulk_urb(port->write_urb, port->serial->dev,
+                         usb_sndbulkpipe(port->serial->dev,
+                                         port->bulk_out_endpointAddress),
+                         port->write_urb->transfer_buffer, 1,
+                         read_rxcmd_callback, port);
+       result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
+}
+
+static int iuu_reset(struct usb_serial_port *port, u8 wt)
+{
+       struct iuu_private *priv = usb_get_serial_port_data(port);
+       int result;
+       char *buf_ptr = port->write_urb->transfer_buffer;
+       dbg("%s - enter", __FUNCTION__);
+
+       /* Prepare the reset sequence */
+
+       *buf_ptr++ = IUU_RST_SET;
+       *buf_ptr++ = IUU_DELAY_MS;
+       *buf_ptr++ = wt;
+       *buf_ptr = IUU_RST_CLEAR;
+
+       /* send the sequence */
+
+       usb_fill_bulk_urb(port->write_urb,
+                         port->serial->dev,
+                         usb_sndbulkpipe(port->serial->dev,
+                                         port->bulk_out_endpointAddress),
+                         port->write_urb->transfer_buffer, 4, iuu_rxcmd, port);
+       result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
+       priv->reset = 0;
+       return result;
+}
+
+/* Status Function
+ * Return value is
+ * 0x00 = no card
+ * 0x01 = smartcard
+ * 0x02 = sim card
+ */
+static void iuu_update_status_callback(struct urb *urb)
+{
+       struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+       struct iuu_private *priv = usb_get_serial_port_data(port);
+       u8 *st;
+       dbg("%s - enter", __FUNCTION__);
+
+       if (urb->status) {
+               dbg("%s - urb->status = %d", __FUNCTION__, urb->status);
+               /* error stop all */
+               return;
+       }
+
+       st = urb->transfer_buffer;
+       dbg("%s - enter", __FUNCTION__);
+       if (urb->actual_length == 1) {
+               switch (st[0]) {
+               case 0x1:
+                       priv->tiostatus = iuu_cardout;
+                       break;
+               case 0x0:
+                       priv->tiostatus = iuu_cardin;
+                       break;
+               default:
+                       priv->tiostatus = iuu_cardin;
+               }
+       }
+       iuu_rxcmd(urb);
+}
+
+static void iuu_status_callback(struct urb *urb)
+{
+       struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+       int result;
+       dbg("%s - enter", __FUNCTION__);
+
+       dbg("%s - urb->status = %d", __FUNCTION__, urb->status);
+       usb_fill_bulk_urb(port->read_urb, port->serial->dev,
+                         usb_rcvbulkpipe(port->serial->dev,
+                                         port->bulk_in_endpointAddress),
+                         port->read_urb->transfer_buffer, 256,
+                         iuu_update_status_callback, port);
+       result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
+}
+
+static int iuu_status(struct usb_serial_port *port)
+{
+       int result;
+
+       dbg("%s - enter", __FUNCTION__);
+
+       memset(port->write_urb->transfer_buffer, IUU_GET_STATE_REGISTER, 1);
+       usb_fill_bulk_urb(port->write_urb, port->serial->dev,
+                         usb_sndbulkpipe(port->serial->dev,
+                                         port->bulk_out_endpointAddress),
+                         port->write_urb->transfer_buffer, 1,
+                         iuu_status_callback, port);
+       result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
+       return result;
+
+}
+
+static int bulk_immediate(struct usb_serial_port *port, u8 *buf, u8 count)
+{
+       int status;
+       struct usb_serial *serial = port->serial;
+       int actual = 0;
+
+       dbg("%s - enter", __FUNCTION__);
+
+       /* send the data out the bulk port */
+
+       status =
+           usb_bulk_msg(serial->dev,
+                        usb_sndbulkpipe(serial->dev,
+                                        port->bulk_out_endpointAddress), buf,
+                        count, &actual, HZ * 1);
+
+       if (status != IUU_OPERATION_OK) {
+               dbg("%s - error = %2x", __FUNCTION__, status);
+       } else {
+               dbg("%s - write OK !", __FUNCTION__);
+       }
+       return status;
+}
+
+static int read_immediate(struct usb_serial_port *port, u8 *buf, u8 count)
+{
+       int status;
+       struct usb_serial *serial = port->serial;
+       int actual = 0;
+
+       dbg("%s - enter", __FUNCTION__);
+
+       /* send the data out the bulk port */
+
+       status =
+           usb_bulk_msg(serial->dev,
+                        usb_rcvbulkpipe(serial->dev,
+                                        port->bulk_in_endpointAddress), buf,
+                        count, &actual, HZ * 1);
+
+       if (status != IUU_OPERATION_OK) {
+               dbg("%s - error = %2x", __FUNCTION__, status);
+       } else {
+               dbg("%s - read OK !", __FUNCTION__);
+       }
+
+       return status;
+}
+
+static int iuu_led(struct usb_serial_port *port, unsigned int R,
+                  unsigned int G, unsigned int B, u8 f)
+{
+       int status;
+       u8 *buf;
+       buf = kmalloc(8, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       dbg("%s - enter", __FUNCTION__);
+
+       buf[0] = IUU_SET_LED;
+       buf[1] = R & 0xFF;
+       buf[2] = (R >> 8) & 0xFF;
+       buf[3] = G & 0xFF;
+       buf[4] = (G >> 8) & 0xFF;
+       buf[5] = B & 0xFF;
+       buf[6] = (B >> 8) & 0xFF;
+       buf[7] = f;
+       status = bulk_immediate(port, buf, 8);
+       kfree(buf);
+       if (status != IUU_OPERATION_OK)
+               dbg("%s - led error status = %2x", __FUNCTION__, status);
+       else
+               dbg("%s - led OK !", __FUNCTION__);
+       return IUU_OPERATION_OK;
+}
+
+static void iuu_rgbf_fill_buffer(u8 *buf, u8 r1, u8 r2, u8 g1, u8 g2, u8 b1,
+                                u8 b2, u8 freq)
+{
+       *buf++ = IUU_SET_LED;
+       *buf++ = r1;
+       *buf++ = r2;
+       *buf++ = g1;
+       *buf++ = g2;
+       *buf++ = b1;
+       *buf++ = b2;
+       *buf = freq;
+}
+
+static void iuu_led_activity_on(struct urb *urb)
+{
+       struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+       int result;
+       char *buf_ptr = port->write_urb->transfer_buffer;
+       *buf_ptr++ = IUU_SET_LED;
+       if (xmas == 1) {
+               get_random_bytes(buf_ptr, 6);
+               *(buf_ptr+7) = 1;
+       } else {
+               iuu_rgbf_fill_buffer(buf_ptr, 255, 255, 0, 0, 0, 0, 255);
+       }
+
+       usb_fill_bulk_urb(port->write_urb, port->serial->dev,
+                         usb_sndbulkpipe(port->serial->dev,
+                                         port->bulk_out_endpointAddress),
+                         port->write_urb->transfer_buffer, 8 ,
+                         iuu_rxcmd, port);
+       result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
+}
+
+static void iuu_led_activity_off(struct urb *urb)
+{
+       struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+       int result;
+       char *buf_ptr = port->write_urb->transfer_buffer;
+       if (xmas == 1) {
+               iuu_rxcmd(urb);
+               return;
+       } else {
+               *buf_ptr++ = IUU_SET_LED;
+               iuu_rgbf_fill_buffer(buf_ptr, 0, 0, 255, 255, 0, 0, 255);
+       }
+       usb_fill_bulk_urb(port->write_urb, port->serial->dev,
+                         usb_sndbulkpipe(port->serial->dev,
+                                         port->bulk_out_endpointAddress),
+                         port->write_urb->transfer_buffer, 8 ,
+                         iuu_rxcmd, port);
+       result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
+}
+
+
+
+static int iuu_clk(struct usb_serial_port *port, int dwFrq)
+{
+       int status;
+       struct iuu_private *priv = usb_get_serial_port_data(port);
+       int Count = 0;
+       u8 FrqGenAdr = 0x69;
+       u8 DIV = 0;             /* 8bit */
+       u8 XDRV = 0;            /* 8bit */
+       u8 PUMP = 0;            /* 3bit */
+       u8 PBmsb = 0;           /* 2bit */
+       u8 PBlsb = 0;           /* 8bit */
+       u8 PO = 0;              /* 1bit */
+       u8 Q = 0;               /* 7bit */
+       /* 24bit = 3bytes */
+       unsigned int P = 0;
+       unsigned int P2 = 0;
+       int frq = (int)dwFrq;
+
+       dbg("%s - enter", __FUNCTION__);
+
+       if (frq == 0) {
+               priv->buf[Count++] = IUU_UART_WRITE_I2C;
+               priv->buf[Count++] = FrqGenAdr << 1;
+               priv->buf[Count++] = 0x09;
+               priv->buf[Count++] = 0x00;
+
+               status = bulk_immediate(port, (u8 *) priv->buf, Count);
+               if (status != 0) {
+                       dbg("%s - write error ", __FUNCTION__);
+                       return status;
+               }
+       } else if (frq == 3579000) {
+               DIV = 100;
+               P = 1193;
+               Q = 40;
+               XDRV = 0;
+       } else if (frq == 3680000) {
+               DIV = 105;
+               P = 161;
+               Q = 5;
+               XDRV = 0;
+       } else if (frq == 6000000) {
+               DIV = 66;
+               P = 66;
+               Q = 2;
+               XDRV = 0x28;
+       } else {
+               unsigned int result = 0;
+               unsigned int tmp = 0;
+               unsigned int check;
+               unsigned int check2;
+               char found = 0x00;
+               unsigned int lQ = 2;
+               unsigned int lP = 2055;
+               unsigned int lDiv = 4;
+
+               for (lQ = 2; lQ <= 47 && !found; lQ++)
+                       for (lP = 2055; lP >= 8 && !found; lP--)
+                               for (lDiv = 4; lDiv <= 127 && !found; lDiv++) {
+                                       tmp = (12000000 / lDiv) * (lP / lQ);
+                                       if (abs((int)(tmp - frq)) <
+                                           abs((int)(frq - result))) {
+                                               check2 = (12000000 / lQ);
+                                               if (check2 < 250000)
+                                                       continue;
+                                               check = (12000000 / lQ) * lP;
+                                               if (check > 400000000)
+                                                       continue;
+                                               if (check < 100000000)
+                                                       continue;
+                                               if (lDiv < 4 || lDiv > 127)
+                                                       continue;
+                                               result = tmp;
+                                               P = lP;
+                                               DIV = lDiv;
+                                               Q = lQ;
+                                               if (result == frq)
+                                                       found = 0x01;
+                                       }
+                               }
+       }
+       P2 = ((P - PO) / 2) - 4;
+       DIV = DIV;
+       PUMP = 0x04;
+       PBmsb = (P2 >> 8 & 0x03);
+       PBlsb = P2 & 0xFF;
+       PO = (P >> 10) & 0x01;
+       Q = Q - 2;
+
+       priv->buf[Count++] = IUU_UART_WRITE_I2C;        /* 0x4C */
+       priv->buf[Count++] = FrqGenAdr << 1;
+       priv->buf[Count++] = 0x09;
+       priv->buf[Count++] = 0x20;      /* Adr = 0x09 */
+       priv->buf[Count++] = IUU_UART_WRITE_I2C;        /* 0x4C */
+       priv->buf[Count++] = FrqGenAdr << 1;
+       priv->buf[Count++] = 0x0C;
+       priv->buf[Count++] = DIV;       /* Adr = 0x0C */
+       priv->buf[Count++] = IUU_UART_WRITE_I2C;        /* 0x4C */
+       priv->buf[Count++] = FrqGenAdr << 1;
+       priv->buf[Count++] = 0x12;
+       priv->buf[Count++] = XDRV;      /* Adr = 0x12 */
+       priv->buf[Count++] = IUU_UART_WRITE_I2C;        /*  0x4C */
+       priv->buf[Count++] = FrqGenAdr << 1;
+       priv->buf[Count++] = 0x13;
+       priv->buf[Count++] = 0x6B;      /* Adr = 0x13 */
+       priv->buf[Count++] = IUU_UART_WRITE_I2C;        /*  0x4C */
+       priv->buf[Count++] = FrqGenAdr << 1;
+       priv->buf[Count++] = 0x40;
+       priv->buf[Count++] = (0xC0 | ((PUMP & 0x07) << 2)) |
+                            (PBmsb & 0x03);    /* Adr = 0x40 */
+       priv->buf[Count++] = IUU_UART_WRITE_I2C;        /*  0x4C */
+       priv->buf[Count++] = FrqGenAdr << 1;
+       priv->buf[Count++] = 0x41;
+       priv->buf[Count++] = PBlsb;     /* Adr = 0x41 */
+       priv->buf[Count++] = IUU_UART_WRITE_I2C;        /*  0x4C */
+       priv->buf[Count++] = FrqGenAdr << 1;
+       priv->buf[Count++] = 0x42;
+       priv->buf[Count++] = Q | (((PO & 0x01) << 7));  /* Adr = 0x42 */
+       priv->buf[Count++] = IUU_UART_WRITE_I2C;        /*  0x4C */
+       priv->buf[Count++] = FrqGenAdr << 1;
+       priv->buf[Count++] = 0x44;
+       priv->buf[Count++] = (char)0xFF;        /* Adr = 0x44 */
+       priv->buf[Count++] = IUU_UART_WRITE_I2C;        /*  0x4C */
+       priv->buf[Count++] = FrqGenAdr << 1;
+       priv->buf[Count++] = 0x45;
+       priv->buf[Count++] = (char)0xFE;        /* Adr = 0x45 */
+       priv->buf[Count++] = IUU_UART_WRITE_I2C;        /*  0x4C */
+       priv->buf[Count++] = FrqGenAdr << 1;
+       priv->buf[Count++] = 0x46;
+       priv->buf[Count++] = 0x7F;      /* Adr = 0x46 */
+       priv->buf[Count++] = IUU_UART_WRITE_I2C;        /*  0x4C */
+       priv->buf[Count++] = FrqGenAdr << 1;
+       priv->buf[Count++] = 0x47;
+       priv->buf[Count++] = (char)0x84;        /* Adr = 0x47 */
+
+       status = bulk_immediate(port, (u8 *) priv->buf, Count);
+       if (status != IUU_OPERATION_OK)
+               dbg("%s - write error ", __FUNCTION__);
+       return status;
+}
+
+static int iuu_uart_flush(struct usb_serial_port *port)
+{
+       int i;
+       int status;
+       u8 rxcmd = IUU_UART_RX;
+       struct iuu_private *priv = usb_get_serial_port_data(port);
+
+       dbg("%s - enter", __FUNCTION__);
+
+       if (iuu_led(port, 0xF000, 0, 0, 0xFF) < 0)
+               return -EIO;
+
+       for (i = 0; i < 2; i++) {
+               status = bulk_immediate(port, &rxcmd, 1);
+               if (status != IUU_OPERATION_OK) {
+                       dbg("%s - uart_flush_write error", __FUNCTION__);
+                       return status;
+               }
+
+               status = read_immediate(port, &priv->len, 1);
+               if (status != IUU_OPERATION_OK) {
+                       dbg("%s - uart_flush_read error", __FUNCTION__);
+                       return status;
+               }
+
+               if (priv->len > 0) {
+                       dbg("%s - uart_flush datalen is : %i ", __FUNCTION__,
+                           priv->len);
+                       status = read_immediate(port, priv->buf, priv->len);
+                       if (status != IUU_OPERATION_OK) {
+                               dbg("%s - uart_flush_read error", __FUNCTION__);
+                               return status;
+                       }
+               }
+       }
+       dbg("%s - uart_flush_read OK!", __FUNCTION__);
+       iuu_led(port, 0, 0xF000, 0, 0xFF);
+       return status;
+}
+
+static void read_buf_callback(struct urb *urb)
+{
+       struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+       unsigned char *data = urb->transfer_buffer;
+       struct tty_struct *tty;
+       dbg("%s - urb->status = %d", __FUNCTION__, urb->status);
+
+       if (urb->status) {
+               dbg("%s - urb->status = %d", __FUNCTION__, urb->status);
+               if (urb->status == -EPROTO) {
+                       /* reschedule needed */
+               }
+               return;
+       }
+
+       dbg("%s - %i chars to write", __FUNCTION__, urb->actual_length);
+       tty = port->tty;
+       if (data == NULL)
+               dbg("%s - data is NULL !!!", __FUNCTION__);
+       if (tty && urb->actual_length && data) {
+               tty_insert_flip_string(tty, data, urb->actual_length);
+               tty_flip_buffer_push(tty);
+       }
+       iuu_led_activity_on(urb);
+}
+
+static int iuu_bulk_write(struct usb_serial_port *port)
+{
+       struct iuu_private *priv = usb_get_serial_port_data(port);
+       unsigned int flags;
+       int result;
+       int i;
+       char *buf_ptr = port->write_urb->transfer_buffer;
+       dbg("%s - enter", __FUNCTION__);
+
+       *buf_ptr++ = IUU_UART_ESC;
+       *buf_ptr++ = IUU_UART_TX;
+       *buf_ptr++ = priv->writelen;
+
+       memcpy(buf_ptr, priv->writebuf,
+              priv->writelen);
+       if (debug == 1) {
+               for (i = 0; i < priv->writelen; i++)
+                       sprintf(priv->dbgbuf + i*2 ,
+                               "%02X", priv->writebuf[i]);
+               priv->dbgbuf[priv->writelen+i*2] = 0;
+               dbg("%s - writing %i chars : %s", __FUNCTION__,
+                   priv->writelen, priv->dbgbuf);
+       }
+       usb_fill_bulk_urb(port->write_urb, port->serial->dev,
+                         usb_sndbulkpipe(port->serial->dev,
+                                         port->bulk_out_endpointAddress),
+                         port->write_urb->transfer_buffer, priv->writelen + 3,
+                         iuu_rxcmd, port);
+       result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
+       spin_lock_irqsave(&priv->lock, flags);
+       priv->writelen = 0;
+       spin_unlock_irqrestore(&priv->lock, flags);
+       usb_serial_port_softint(port);
+       return result;
+}
+
+static int iuu_read_buf(struct usb_serial_port *port, int len)
+{
+       int result;
+       dbg("%s - enter", __FUNCTION__);
+
+       usb_fill_bulk_urb(port->read_urb, port->serial->dev,
+                         usb_rcvbulkpipe(port->serial->dev,
+                                         port->bulk_in_endpointAddress),
+                         port->read_urb->transfer_buffer, len,
+                         read_buf_callback, port);
+       result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
+       return result;
+}
+
+static void iuu_uart_read_callback(struct urb *urb)
+{
+       struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+       struct iuu_private *priv = usb_get_serial_port_data(port);
+       unsigned int flags;
+       int status;
+       int error = 0;
+       int len = 0;
+       unsigned char *data = urb->transfer_buffer;
+       priv->poll++;
+
+       dbg("%s - enter", __FUNCTION__);
+
+       if (urb->status) {
+               dbg("%s - urb->status = %d", __FUNCTION__, urb->status);
+               /* error stop all */
+               return;
+       }
+       if (data == NULL)
+               dbg("%s - data is NULL !!!", __FUNCTION__);
+
+       if (urb->actual_length == 1  && data != NULL)
+               len = (int) data[0];
+
+       if (urb->actual_length > 1) {
+               dbg("%s - urb->actual_length = %i", __FUNCTION__,
+                   urb->actual_length);
+               error = 1;
+               return;
+       }
+       /* if len > 0 call readbuf */
+
+       if (len > 0 && error == 0) {
+               dbg("%s - call read buf - len to read is %i ",
+                       __FUNCTION__, len);
+               status = iuu_read_buf(port, len);
+               return;
+       }
+       /* need to update status  ? */
+       if (priv->poll > 99) {
+               status = iuu_status(port);
+               priv->poll = 0;
+               return;
+       }
+
+       /* reset waiting ? */
+
+       if (priv->reset == 1) {
+               status = iuu_reset(port, 0xC);
+               return;
+       }
+       /* Writebuf is waiting */
+       spin_lock_irqsave(&priv->lock, flags);
+       if (priv->writelen > 0) {
+               spin_unlock_irqrestore(&priv->lock, flags);
+               status = iuu_bulk_write(port);
+               return;
+       }
+       spin_unlock_irqrestore(&priv->lock, flags);
+       /* if nothing to write call again rxcmd */
+       dbg("%s - rxcmd recall", __FUNCTION__);
+       iuu_led_activity_off(urb);
+       return;
+}
+
+static int iuu_uart_write(struct usb_serial_port *port, const u8 *buf,
+                         int count)
+{
+       struct iuu_private *priv = usb_get_serial_port_data(port);
+       unsigned int flags;
+       dbg("%s - enter", __FUNCTION__);
+
+       if (count > 256)
+               return -ENOMEM;
+
+       spin_lock_irqsave(&priv->lock, flags);
+       if (priv->writelen > 0) {
+               /* buffer already filled but not commited */
+               spin_unlock_irqrestore(&priv->lock, flags);
+               return (0);
+       }
+       /* fill the buffer */
+       memcpy(priv->writebuf, buf, count);
+       priv->writelen = count;
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       return (count);
+}
+
+static void read_rxcmd_callback(struct urb *urb)
+{
+       struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+       int result;
+       dbg("%s - enter", __FUNCTION__);
+
+       dbg("%s - urb->status = %d", __FUNCTION__, urb->status);
+
+       if (urb->status) {
+               dbg("%s - urb->status = %d", __FUNCTION__, urb->status);
+               /* error stop all */
+               return;
+       }
+
+       usb_fill_bulk_urb(port->read_urb, port->serial->dev,
+                         usb_rcvbulkpipe(port->serial->dev,
+                                         port->bulk_in_endpointAddress),
+                         port->read_urb->transfer_buffer, 256,
+                         iuu_uart_read_callback, port);
+       result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
+       dbg("%s - submit result = %d", __FUNCTION__, result);
+       return;
+}
+
+static int iuu_uart_on(struct usb_serial_port *port)
+{
+       int status;
+       u8 *buf;
+
+       buf = kmalloc(sizeof(u8) * 4, GFP_KERNEL);
+
+       if (!buf)
+               return -ENOMEM;
+
+       buf[0] = IUU_UART_ENABLE;
+       buf[1] = (u8) ((IUU_BAUD_9600 >> 8) & 0x00FF);
+       buf[2] = (u8) (0x00FF & IUU_BAUD_9600);
+       buf[3] = (u8) (0x0F0 & IUU_TWO_STOP_BITS) | (0x07 & IUU_PARITY_EVEN);
+
+       status = bulk_immediate(port, buf, 4);
+       if (status != IUU_OPERATION_OK) {
+               dbg("%s - uart_on error", __FUNCTION__);
+               goto uart_enable_failed;
+       }
+       /*  iuu_reset() the card after iuu_uart_on() */
+       status = iuu_uart_flush(port);
+       if (status != IUU_OPERATION_OK)
+               dbg("%s - uart_flush error", __FUNCTION__);
+uart_enable_failed:
+       kfree(buf);
+       return status;
+}
+
+/*  Diables the IUU UART (a.k.a. the Phoenix voiderface) */
+static int iuu_uart_off(struct usb_serial_port *port)
+{
+       int status;
+       u8 *buf;
+       buf = kmalloc(1, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+       buf[0] = IUU_UART_DISABLE;
+
+       status = bulk_immediate(port, buf, 1);
+       if (status != IUU_OPERATION_OK)
+               dbg("%s - uart_off error", __FUNCTION__);
+
+       kfree(buf);
+       return status;
+}
+
+static int iuu_uart_baud(struct usb_serial_port *port, u32 baud,
+                        u32 *actual, u8 parity)
+{
+       int status;
+       u8 *dataout;
+       u8 DataCount = 0;
+       u8 T1Frekvens = 0;
+       u8 T1reload = 0;
+       unsigned int T1FrekvensHZ = 0;
+
+       dataout = kmalloc(sizeof(u8) * 5, GFP_KERNEL);
+
+       if (!dataout)
+               return -ENOMEM;
+
+       if (baud < 1200 || baud > 230400) {
+               kfree(dataout);
+               return IUU_INVALID_PARAMETER;
+       }
+       if (baud > 977) {
+               T1Frekvens = 3;
+               T1FrekvensHZ = 500000;
+       }
+
+       if (baud > 3906) {
+               T1Frekvens = 2;
+               T1FrekvensHZ = 2000000;
+       }
+
+       if (baud > 11718) {
+               T1Frekvens = 1;
+               T1FrekvensHZ = 6000000;
+       }
+
+       if (baud > 46875) {
+               T1Frekvens = 0;
+               T1FrekvensHZ = 24000000;
+       }
+
+       T1reload = 256 - (u8) (T1FrekvensHZ / (baud * 2));
+
+       /*  magic number here:  ENTER_FIRMWARE_UPDATE; */
+       dataout[DataCount++] = IUU_UART_ESC;
+       /*  magic number here:  CHANGE_BAUD; */
+       dataout[DataCount++] = IUU_UART_CHANGE;
+       dataout[DataCount++] = T1Frekvens;
+       dataout[DataCount++] = T1reload;
+
+       *actual = (T1FrekvensHZ / (256 - T1reload)) / 2;
+
+       switch (parity & 0x0F) {
+       case IUU_PARITY_NONE:
+               dataout[DataCount++] = 0x00;
+               break;
+       case IUU_PARITY_EVEN:
+               dataout[DataCount++] = 0x01;
+               break;
+       case IUU_PARITY_ODD:
+               dataout[DataCount++] = 0x02;
+               break;
+       case IUU_PARITY_MARK:
+               dataout[DataCount++] = 0x03;
+               break;
+       case IUU_PARITY_SPACE:
+               dataout[DataCount++] = 0x04;
+               break;
+       default:
+               kfree(dataout);
+               return IUU_INVALID_PARAMETER;
+               break;
+       }
+
+       switch (parity & 0xF0) {
+       case IUU_ONE_STOP_BIT:
+               dataout[DataCount - 1] |= IUU_ONE_STOP_BIT;
+               break;
+
+       case IUU_TWO_STOP_BITS:
+               dataout[DataCount - 1] |= IUU_TWO_STOP_BITS;
+               break;
+       default:
+               kfree(dataout);
+               return IUU_INVALID_PARAMETER;
+               break;
+       }
+
+       status = bulk_immediate(port, dataout, DataCount);
+       if (status != IUU_OPERATION_OK)
+               dbg("%s - uart_off error", __FUNCTION__);
+       kfree(dataout);
+       return status;
+}
+
+static int set_control_lines(struct usb_device *dev, u8 value)
+{
+       return 0;
+}
+
+static void iuu_close(struct usb_serial_port *port, struct file *filp)
+{
+       /* iuu_led (port,255,0,0,0); */
+       struct usb_serial *serial;
+       struct iuu_private *priv = usb_get_serial_port_data(port);
+       unsigned long flags;
+       unsigned int c_cflag;
+
+       serial = port->serial;
+       if (!serial)
+               return;
+
+       dbg("%s - port %d", __FUNCTION__, port->number);
+
+       iuu_uart_off(port);
+       if (serial->dev) {
+               if (port->tty) {
+                       c_cflag = port->tty->termios->c_cflag;
+                       if (c_cflag & HUPCL) {
+                               /* drop DTR and RTS */
+                               priv = usb_get_serial_port_data(port);
+                               spin_lock_irqsave(&priv->lock, flags);
+                               priv->line_control = 0;
+                               spin_unlock_irqrestore(&priv->lock, flags);
+                               set_control_lines(port->serial->dev, 0);
+                       }
+               }
+               /* free writebuf */
+               /* shutdown our urbs */
+               dbg("%s - shutting down urbs", __FUNCTION__);
+               usb_kill_urb(port->write_urb);
+               usb_kill_urb(port->read_urb);
+               usb_kill_urb(port->interrupt_in_urb);
+               msleep(1000);
+               /* wait one second to free all buffers */
+               iuu_led(port, 0, 0, 0xF000, 0xFF);
+               msleep(1000);
+               usb_reset_device(port->serial->dev);
+       }
+}
+
+static int iuu_open(struct usb_serial_port *port, struct file *filp)
+{
+       struct usb_serial *serial = port->serial;
+       u8 *buf;
+       int result;
+       u32 actual;
+       unsigned long flags;
+       struct iuu_private *priv = usb_get_serial_port_data(port);
+
+       dbg("%s -  port %d", __FUNCTION__, port->number);
+       usb_clear_halt(serial->dev, port->write_urb->pipe);
+       usb_clear_halt(serial->dev, port->read_urb->pipe);
+
+       buf = kmalloc(10, GFP_KERNEL);
+       if (buf == NULL)
+               return -ENOMEM;
+
+       /* fixup the endpoint buffer size */
+       kfree(port->bulk_out_buffer);
+       port->bulk_out_buffer = kmalloc(512, GFP_KERNEL);
+       port->bulk_out_size = 512;
+       kfree(port->bulk_in_buffer);
+       port->bulk_in_buffer = kmalloc(512, GFP_KERNEL);
+       port->bulk_in_size = 512;
+
+       if (!port->bulk_out_buffer || !port->bulk_in_buffer) {
+               kfree(port->bulk_out_buffer);
+               kfree(port->bulk_in_buffer);
+               kfree(buf);
+               return -ENOMEM;
+       }
+
+       usb_fill_bulk_urb(port->write_urb, port->serial->dev,
+                         usb_sndbulkpipe(port->serial->dev,
+                                         port->bulk_out_endpointAddress),
+                         port->bulk_out_buffer, 512,
+                         NULL, NULL);
+
+
+       usb_fill_bulk_urb(port->read_urb, port->serial->dev,
+                         usb_rcvbulkpipe(port->serial->dev,
+                                         port->bulk_in_endpointAddress),
+                         port->bulk_in_buffer, 512,
+                         NULL, NULL);
+
+       /* set the termios structure */
+       spin_lock_irqsave(&priv->lock, flags);
+       if (!priv->termios_initialized) {
+               *(port->tty->termios) = tty_std_termios;
+               port->tty->termios->c_cflag = CLOCAL | CREAD | CS8 | B9600
+                                               | TIOCM_CTS | CSTOPB | PARENB;
+               port->tty->termios->c_lflag = 0;
+               port->tty->termios->c_oflag = 0;
+               port->tty->termios->c_iflag = 0;
+               priv->termios_initialized = 1;
+               port->tty->low_latency = 1;
+               priv->poll = 0;
+        }
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       /* initialize writebuf */
+#define FISH(a, b, c, d) do { \
+       result = usb_control_msg(port->serial->dev,     \
+                               usb_rcvctrlpipe(port->serial->dev, 0),  \
+                               b, a, c, d, buf, 1, 1000); \
+       dbg("0x%x:0x%x:0x%x:0x%x  %d - %x", a, b, c, d, result, \
+                               buf[0]); } while (0);
+
+#define SOUP(a, b, c, d)  do { \
+       result = usb_control_msg(port->serial->dev,     \
+                               usb_sndctrlpipe(port->serial->dev, 0),  \
+                               b, a, c, d, NULL, 0, 1000); \
+       dbg("0x%x:0x%x:0x%x:0x%x  %d", a, b, c, d, result); } while (0)
+
+       /*  This is not UART related but IUU USB driver related or something */
+       /*  like that. Basically no IUU will accept any commands from the USB */
+       /*  host unless it has received the following message */
+       /* sprintf(buf ,"%c%c%c%c",0x03,0x02,0x02,0x0); */
+
+       SOUP(0x03, 0x02, 0x02, 0x0);
+       kfree(buf);
+       iuu_led(port, 0xF000, 0xF000, 0, 0xFF);
+       iuu_uart_on(port);
+       if (boost < 100)
+               boost = 100;
+       switch (clockmode) {
+       case 2:         /*  3.680 Mhz */
+               iuu_clk(port, IUU_CLK_3680000 * boost / 100);
+               result =
+                   iuu_uart_baud(port, 9600 * boost / 100, &actual,
+                                 IUU_PARITY_EVEN);
+               break;
+       case 3:         /*  6.00 Mhz */
+               iuu_clk(port, IUU_CLK_6000000 * boost / 100);
+               result =
+                   iuu_uart_baud(port, 16457 * boost / 100, &actual,
+                                 IUU_PARITY_EVEN);
+               break;
+       default:                /*  3.579 Mhz */
+               iuu_clk(port, IUU_CLK_3579000 * boost / 100);
+               result =
+                   iuu_uart_baud(port, 9600 * boost / 100, &actual,
+                                 IUU_PARITY_EVEN);
+       }
+
+       /* set the cardin cardout signals */
+       switch (cdmode) {
+       case 0:
+               iuu_cardin = 0;
+               iuu_cardout = 0;
+               break;
+       case 1:
+               iuu_cardin = TIOCM_CD;
+               iuu_cardout =  0;
+               break;
+       case 2:
+               iuu_cardin = 0;
+               iuu_cardout = TIOCM_CD;
+               break;
+       case 3:
+               iuu_cardin = TIOCM_DSR;
+               iuu_cardout = 0;
+               break;
+       case 4:
+               iuu_cardin = 0;
+               iuu_cardout = TIOCM_DSR;
+               break;
+       case 5:
+               iuu_cardin = TIOCM_CTS;
+               iuu_cardout = 0;
+               break;
+       case 6:
+               iuu_cardin = 0;
+               iuu_cardout = TIOCM_CTS;
+               break;
+       case 7:
+               iuu_cardin = TIOCM_RNG;
+               iuu_cardout = 0;
+               break;
+       case 8:
+               iuu_cardin = 0;
+               iuu_cardout = TIOCM_RNG;
+       }
+
+       iuu_uart_flush(port);
+
+       dbg("%s - initialization done", __FUNCTION__);
+
+       memset(port->write_urb->transfer_buffer, IUU_UART_RX, 1);
+       usb_fill_bulk_urb(port->write_urb, port->serial->dev,
+                         usb_sndbulkpipe(port->serial->dev,
+                                         port->bulk_out_endpointAddress),
+                         port->write_urb->transfer_buffer, 1,
+                         read_rxcmd_callback, port);
+       result = usb_submit_urb(port->write_urb, GFP_KERNEL);
+
+       if (result) {
+               dev_err(&port->dev, "%s - failed submitting read urb,"
+                       " error %d\n", __FUNCTION__, result);
+               iuu_close(port, NULL);
+               return -EPROTO;
+       } else {
+               dbg("%s - rxcmd OK", __FUNCTION__);
+       }
+       return result;
+}
+
+static struct usb_serial_driver iuu_device = {
+       .driver = {
+                  .owner = THIS_MODULE,
+                  .name = "iuu_phoenix",
+                  },
+       .id_table = id_table,
+       .num_interrupt_in = NUM_DONT_CARE,
+       .num_bulk_in = 1,
+       .num_bulk_out = 1,
+       .num_ports = 1,
+       .open = iuu_open,
+       .close = iuu_close,
+       .write = iuu_uart_write,
+       .read_bulk_callback = iuu_uart_read_callback,
+       .tiocmget = iuu_tiocmget,
+       .tiocmset = iuu_tiocmset,
+       .attach = iuu_startup,
+       .shutdown = iuu_shutdown,
+};
+
+static int __init iuu_init(void)
+{
+       int retval;
+       retval = usb_serial_register(&iuu_device);
+       if (retval)
+               goto failed_usb_serial_register;
+       retval = usb_register(&iuu_driver);
+       if (retval)
+               goto failed_usb_register;
+       info(DRIVER_DESC " " DRIVER_VERSION);
+       return 0;
+failed_usb_register:
+       usb_serial_deregister(&iuu_device);
+failed_usb_serial_register:
+       return retval;
+}
+
+static void __exit iuu_exit(void)
+{
+       usb_deregister(&iuu_driver);
+       usb_serial_deregister(&iuu_device);
+}
+
+module_init(iuu_init);
+module_exit(iuu_exit);
+
+MODULE_AUTHOR("Alain Degreffe eczema@ecze.com");
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+MODULE_VERSION(DRIVER_VERSION);
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug enabled or not");
+
+module_param(xmas, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(xmas, "xmas color enabled or not");
+
+module_param(boost, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(boost, "overclock boost percent 100 to 500");
+
+module_param(clockmode, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(clockmode, "1=3Mhz579,2=3Mhz680,3=6Mhz");
+
+module_param(cdmode, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(cdmode, "Card detect mode 0=none, 1=CD, 2=!CD, 3=DSR, "
+                "4=!DSR, 5=CTS, 6=!CTS, 7=RING, 8=!RING");
diff --git a/drivers/usb/serial/iuu_phoenix.h b/drivers/usb/serial/iuu_phoenix.h
new file mode 100644 (file)
index 0000000..b82630a
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * Infinity Unlimited USB Phoenix driver
+ *
+ * Copyright (C) 2007 Alain Degreffe (eczema@ecze.com)
+ *
+ *
+ * Original code taken from iuutool ( Copyright (C) 2006 Juan Carlos Borrás )
+ *
+ *     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.
+ *
+ *  And tested with help of WB Electronics
+ *
+ */
+
+#define   IUU_USB_VENDOR_ID  0x104f
+#define   IUU_USB_PRODUCT_ID  0x0004
+#define   IUU_USB_OP_TIMEOUT  0x0200
+
+/* Programmer commands */
+
+#define IUU_NO_OPERATION   0x00
+#define IUU_GET_FIRMWARE_VERSION   0x01
+#define IUU_GET_PRODUCT_NAME   0x02
+#define IUU_GET_STATE_REGISTER   0x03
+#define IUU_SET_LED   0x04
+#define IUU_WAIT_MUS   0x05
+#define IUU_WAIT_MS   0x06
+#define IUU_GET_LOADER_VERSION   0x50
+#define IUU_RST_SET   0x52
+#define IUU_RST_CLEAR   0x53
+#define IUU_SET_VCC   0x59
+#define IUU_UART_ENABLE   0x49
+#define IUU_UART_DISABLE   0x4A
+#define IUU_UART_WRITE_I2C   0x4C
+#define IUU_UART_ESC   0x5E
+#define IUU_UART_TRAP   0x54
+#define IUU_UART_TRAP_BREAK   0x5B
+#define IUU_UART_RX   0x56
+#define IUU_AVR_ON   0x21
+#define IUU_AVR_OFF   0x22
+#define IUU_AVR_1CLK   0x23
+#define IUU_AVR_RESET   0x24
+#define IUU_AVR_RESET_PC   0x25
+#define IUU_AVR_INC_PC   0x26
+#define IUU_AVR_INCN_PC   0x27
+#define IUU_AVR_PREAD   0x29
+#define IUU_AVR_PREADN   0x2A
+#define IUU_AVR_PWRITE   0x28
+#define IUU_AVR_DREAD   0x2C
+#define IUU_AVR_DREADN   0x2D
+#define IUU_AVR_DWRITE   0x2B
+#define IUU_AVR_PWRITEN   0x2E
+#define IUU_EEPROM_ON   0x37
+#define IUU_EEPROM_OFF   0x38
+#define IUU_EEPROM_WRITE   0x39
+#define IUU_EEPROM_WRITEX   0x3A
+#define IUU_EEPROM_WRITE8   0x3B
+#define IUU_EEPROM_WRITE16   0x3C
+#define IUU_EEPROM_WRITEX32   0x3D
+#define IUU_EEPROM_WRITEX64   0x3E
+#define IUU_EEPROM_READ   0x3F
+#define IUU_EEPROM_READX   0x40
+#define IUU_EEPROM_BREAD   0x41
+#define IUU_EEPROM_BREADX   0x42
+#define IUU_PIC_CMD   0x0A
+#define IUU_PIC_CMD_LOAD   0x0B
+#define IUU_PIC_CMD_READ   0x0C
+#define IUU_PIC_ON   0x0D
+#define IUU_PIC_OFF   0x0E
+#define IUU_PIC_RESET   0x16
+#define IUU_PIC_INC_PC   0x0F
+#define IUU_PIC_INCN_PC   0x10
+#define IUU_PIC_PWRITE   0x11
+#define IUU_PIC_PREAD   0x12
+#define IUU_PIC_PREADN   0x13
+#define IUU_PIC_DWRITE   0x14
+#define IUU_PIC_DREAD   0x15
+#define IUU_UART_NOP   0x00
+#define IUU_UART_CHANGE   0x02
+#define IUU_UART_TX   0x04
+#define IUU_DELAY_MS   0x06
+
+#define IUU_OPERATION_OK   0x00
+#define IUU_DEVICE_NOT_FOUND   0x01
+#define IUU_INVALID_HANDLE   0x02
+#define IUU_INVALID_PARAMETER   0x03
+#define IUU_INVALID_voidERFACE   0x04
+#define IUU_INVALID_REQUEST_LENGTH   0x05
+#define IUU_UART_NOT_ENABLED   0x06
+#define IUU_WRITE_ERROR   0x07
+#define IUU_READ_ERROR   0x08
+#define IUU_TX_ERROR   0x09
+#define IUU_RX_ERROR   0x0A
+
+#define IUU_PARITY_NONE   0x00
+#define IUU_PARITY_EVEN   0x01
+#define IUU_PARITY_ODD   0x02
+#define IUU_PARITY_MARK   0x03
+#define IUU_PARITY_SPACE   0x04
+#define IUU_SC_INSERTED   0x01
+#define IUU_VERIFY_ERROR   0x02
+#define IUU_SIM_INSERTED   0x04
+#define IUU_TWO_STOP_BITS   0x00
+#define IUU_ONE_STOP_BIT   0x20
+#define IUU_BAUD_2400   0x0398
+#define IUU_BAUD_9600   0x0298
+#define IUU_BAUD_19200   0x0164
+#define IUU_BAUD_28800   0x0198
+#define IUU_BAUD_38400   0x01B2
+#define IUU_BAUD_57600   0x0030
+#define IUU_BAUD_115200   0x0098
+#define IUU_CLK_3579000   3579000
+#define IUU_CLK_3680000   3680000
+#define IUU_CLK_6000000   6000000
+#define IUU_FULLCARD_IN   0x01
+#define IUU_DEV_ERROR   0x02
+#define IUU_MINICARD_IN   0x04
+#define IUU_VCC_5V   0x00
+#define IUU_VCC_3V   0x01
index 7c069a02c1dd40817d93b58dffed4217bd740ff2..ea7bba69f4da129397e111463a0ec13995d0ac5a 100644 (file)
@@ -838,7 +838,7 @@ static void usa49_indat_callback(struct urb *urb)
 
        port = (struct usb_serial_port *) urb->context;
        tty = port->tty;
-       if (urb->actual_length) {
+       if (tty && urb->actual_length) {
                /* 0x80 bit is error flag */
                if ((data[0] & 0x80) == 0) {
                        /* no error on any byte */
index be9ac20a8f10b3adeb456192f84246da79206419..b1fa5a376e96798fc6871b6a47e93c7bed2378a9 100644 (file)
@@ -303,7 +303,7 @@ static void keyspan_pda_rx_unthrottle (struct usb_serial_port *port)
 }
 
 
-static int keyspan_pda_setbaud (struct usb_serial *serial, int baud)
+static speed_t keyspan_pda_setbaud (struct usb_serial *serial, speed_t baud)
 {
        int rc;
        int bindex;
@@ -319,7 +319,9 @@ static int keyspan_pda_setbaud (struct usb_serial *serial, int baud)
                case 38400: bindex = 7; break;
                case 57600: bindex = 8; break;
                case 115200: bindex = 9; break;
-               default: return -EINVAL;
+               default:
+                       bindex = 5;     /* Default to 9600 */
+                       baud = 9600;
        }
 
        /* rather than figure out how to sleep while waiting for this
@@ -334,7 +336,9 @@ static int keyspan_pda_setbaud (struct usb_serial *serial, int baud)
                             NULL, /* &data */
                             0, /* size */
                             2000); /* timeout */
-       return(rc);
+       if (rc < 0)
+               return 0;
+       return baud;
 }
 
 
@@ -366,7 +370,7 @@ static void keyspan_pda_set_termios (struct usb_serial_port *port,
                                     struct ktermios *old_termios)
 {
        struct usb_serial *serial = port->serial;
-       unsigned int cflag = port->tty->termios->c_cflag;
+       speed_t speed;
 
        /* cflag specifies lots of stuff: number of stop bits, parity, number
           of data bits, baud. What can the device actually handle?:
@@ -388,22 +392,18 @@ static void keyspan_pda_set_termios (struct usb_serial_port *port,
 
           For now, just do baud. */
 
-       switch (cflag & CBAUD) {
-               /* we could support more values here, just need to calculate
-                  the necessary divisors in the firmware. <asm/termbits.h>
-                  has the Bnnn constants. */
-               case B110: keyspan_pda_setbaud(serial, 110); break;
-               case B300: keyspan_pda_setbaud(serial, 300); break;
-               case B1200: keyspan_pda_setbaud(serial, 1200); break;
-               case B2400: keyspan_pda_setbaud(serial, 2400); break;
-               case B4800: keyspan_pda_setbaud(serial, 4800); break;
-               case B9600: keyspan_pda_setbaud(serial, 9600); break;
-               case B19200: keyspan_pda_setbaud(serial, 19200); break;
-               case B38400: keyspan_pda_setbaud(serial, 38400); break;
-               case B57600: keyspan_pda_setbaud(serial, 57600); break;
-               case B115200: keyspan_pda_setbaud(serial, 115200); break;
-               default: dbg("can't handle requested baud rate"); break;
+       speed = tty_get_baud_rate(port->tty);
+       speed = keyspan_pda_setbaud(serial, speed);
+
+       if (speed == 0) {
+               dbg("can't handle requested baud rate");
+               /* It hasn't changed so.. */
+               speed = tty_termios_baud_rate(old_termios);
        }
+       /* Only speed can change so copy the old h/w parameters
+          then encode the new speed */
+       tty_termios_copy_hw(port->tty->termios, old_termios);
+       tty_encode_baud_rate(port->tty, speed, speed);
 }
 
 
index 90e3216abd1f006800f0d2ed018a83c12a9b5cc0..55736df7d2f4ed0232d2c33700d353a47336cafe 100644 (file)
@@ -461,17 +461,21 @@ static void klsi_105_close (struct usb_serial_port *port, struct file *filp)
 
        dbg("%s port %d", __FUNCTION__, port->number);
 
-       /* send READ_OFF */
-       rc = usb_control_msg (port->serial->dev,
-                             usb_sndctrlpipe(port->serial->dev, 0),
-                             KL5KUSB105A_SIO_CONFIGURE,
-                             USB_TYPE_VENDOR | USB_DIR_OUT,
-                             KL5KUSB105A_SIO_CONFIGURE_READ_OFF,
-                             0, /* index */
-                             NULL, 0,
-                             KLSI_TIMEOUT);
-       if (rc < 0)
-                   err("Disabling read failed (error = %d)", rc);
+       mutex_lock(&port->serial->disc_mutex);
+       if (!port->serial->disconnected) {
+               /* send READ_OFF */
+               rc = usb_control_msg (port->serial->dev,
+                                     usb_sndctrlpipe(port->serial->dev, 0),
+                                     KL5KUSB105A_SIO_CONFIGURE,
+                                     USB_TYPE_VENDOR | USB_DIR_OUT,
+                                     KL5KUSB105A_SIO_CONFIGURE_READ_OFF,
+                                     0, /* index */
+                                     NULL, 0,
+                                     KLSI_TIMEOUT);
+               if (rc < 0)
+                       err("Disabling read failed (error = %d)", rc);
+       }
+       mutex_unlock(&port->serial->disc_mutex);
 
        /* shutdown our bulk reads and writes */
        usb_kill_urb(port->write_urb);
index aee450246bfd8b0befa879ca9613415ad649d577..17b3baead4adec5acf81f4e9955d1c97f3bc59f0 100644 (file)
@@ -114,6 +114,7 @@ static struct usb_serial_driver kobil_device = {
        .usb_driver =           &kobil_driver,
        .id_table =             id_table,
        .num_interrupt_in =     NUM_DONT_CARE,
+       .num_interrupt_out =    NUM_DONT_CARE,
        .num_bulk_in =          0,
        .num_bulk_out =         0,
        .num_ports =            1,
index 0dc99f75bb09d13ab67072e4703c81a80894eb21..fc1cea4aba13979ff48ea6fbdd371787fc1cea5e 100644 (file)
@@ -182,10 +182,11 @@ struct mct_u232_private {
 /*
  * Later day 2.6.0-test kernels have new baud rates like B230400 which
  * we do not know how to support. We ignore them for the moment.
- * XXX Rate-limit the error message, it's user triggerable.
  */
-static int mct_u232_calculate_baud_rate(struct usb_serial *serial, speed_t value)
+static int mct_u232_calculate_baud_rate(struct usb_serial *serial, speed_t value, speed_t *result)
 {
+       *result = value;
+
        if (le16_to_cpu(serial->dev->descriptor.idProduct) == MCT_U232_SITECOM_PID
          || le16_to_cpu(serial->dev->descriptor.idProduct) == MCT_U232_BELKIN_F5U109_PID) {
                switch (value) {
@@ -200,11 +201,13 @@ static int mct_u232_calculate_baud_rate(struct usb_serial *serial, speed_t value
                case  57600: return 0x0b;
                case 115200: return 0x0c;
                default:
-                       err("MCT USB-RS232: unsupported baudrate request 0x%x,"
-                           " using default of B9600", value);
+                       *result = 9600;
                        return 0x08;
                }
        } else {
+               /* FIXME: Can we use any divider - should we do
+                  divider = 115200/value;
+                  real baud = 115200/divider */
                switch (value) {
                case 300: break;
                case 600: break;
@@ -217,9 +220,8 @@ static int mct_u232_calculate_baud_rate(struct usb_serial *serial, speed_t value
                case 57600: break;
                case 115200: break;
                default:
-                       err("MCT USB-RS232: unsupported baudrate request 0x%x,"
-                           " using default of B9600", value);
                        value = 9600;
+                       *result = 9600;
                }
                return 115200/value;
        }
@@ -232,16 +234,19 @@ static int mct_u232_set_baud_rate(struct usb_serial *serial, struct usb_serial_p
         int rc;
         unsigned char zero_byte = 0;
         unsigned char cts_enable_byte = 0;
+        speed_t speed;
 
-       divisor = cpu_to_le32(mct_u232_calculate_baud_rate(serial, value));
+       divisor = cpu_to_le32(mct_u232_calculate_baud_rate(serial, value, &speed));
 
         rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
                              MCT_U232_SET_BAUD_RATE_REQUEST,
                             MCT_U232_SET_REQUEST_TYPE,
                              0, 0, &divisor, MCT_U232_SET_BAUD_RATE_SIZE,
                             WDR_TIMEOUT);
-       if (rc < 0)
+       if (rc < 0)     /*FIXME: What value speed results */
                err("Set BAUD RATE %d failed (error = %d)", value, rc);
+       else
+               tty_encode_baud_rate(port->tty, speed, speed);
        dbg("set_baud_rate: value: 0x%x, divisor: 0x%x", value, divisor);
 
        /* Mimic the MCT-supplied Windows driver (version 1.21P.0104), which
@@ -482,21 +487,22 @@ error:
 static void mct_u232_close (struct usb_serial_port *port, struct file *filp)
 {
        unsigned int c_cflag;
-       unsigned long flags;
        unsigned int control_state;
        struct mct_u232_private *priv = usb_get_serial_port_data(port);
        dbg("%s port %d", __FUNCTION__, port->number);
 
        if (port->tty) {
                c_cflag = port->tty->termios->c_cflag;
-               if (c_cflag & HUPCL) {
-                  /* drop DTR and RTS */
-                  spin_lock_irqsave(&priv->lock, flags);
-                  priv->control_state &= ~(TIOCM_DTR | TIOCM_RTS);
-                  control_state = priv->control_state;
-                  spin_unlock_irqrestore(&priv->lock, flags);
-                  mct_u232_set_modem_ctrl(port->serial, control_state);
+               mutex_lock(&port->serial->disc_mutex);
+               if (c_cflag & HUPCL && !port->serial->disconnected) {
+                       /* drop DTR and RTS */
+                       spin_lock_irq(&priv->lock);
+                       priv->control_state &= ~(TIOCM_DTR | TIOCM_RTS);
+                       control_state = priv->control_state;
+                       spin_unlock_irq(&priv->lock);
+                       mct_u232_set_modem_ctrl(port->serial, control_state);
                }
+               mutex_unlock(&port->serial->disc_mutex);
        }
 
 
@@ -608,7 +614,8 @@ static void mct_u232_set_termios (struct usb_serial_port *port,
 {
        struct usb_serial *serial = port->serial;
        struct mct_u232_private *priv = usb_get_serial_port_data(port);
-       unsigned int cflag = port->tty->termios->c_cflag;
+       struct ktermios *termios = port->tty->termios;
+       unsigned int cflag = termios->c_cflag;
        unsigned int old_cflag = old_termios->c_cflag;
        unsigned long flags;
        unsigned int control_state;
@@ -670,6 +677,8 @@ static void mct_u232_set_termios (struct usb_serial_port *port,
                break;
        }
 
+       termios->c_cflag &= ~CMSPAR;
+
        /* set the number of stop bits */
        last_lcr |= (cflag & CSTOPB) ?
                MCT_U232_STOP_BITS_2 : MCT_U232_STOP_BITS_1;
index aae10c8174d6bb0fd51abd7fb397999bce64f237..07b6bec31dc898a2e6f9fcccc5ff1ab654b328c6 100644 (file)
@@ -79,7 +79,7 @@
  * and "Intel solution". They are the regular MCT and "Sitecom" for us.
  * This is pointless to document in the header, see the code for the bits.
  */
-static int mct_u232_calculate_baud_rate(struct usb_serial *serial, speed_t value);
+static int mct_u232_calculate_baud_rate(struct usb_serial *serial, speed_t value, speed_t *result);
 
 /*
  * Line Control Register (LCR)
index e02c198016b02204ee5ef92c43850356e99d9264..40f3a0188807d95c7e69a7a23001133678dbd9d1 100644 (file)
@@ -564,22 +564,25 @@ static void mos7720_close(struct usb_serial_port *port, struct file *filp)
        }
 
        /* While closing port, shutdown all bulk read, write  *
-        * and interrupt read if they exists                  */
-       if (serial->dev) {
-               dbg("Shutdown bulk write");
-               usb_kill_urb(port->write_urb);
-               dbg("Shutdown bulk read");
-               usb_kill_urb(port->read_urb);
+        * and interrupt read if they exists, otherwise nop   */
+       dbg("Shutdown bulk write");
+       usb_kill_urb(port->write_urb);
+       dbg("Shutdown bulk read");
+       usb_kill_urb(port->read_urb);
+
+       mutex_lock(&serial->disc_mutex);
+       /* these commands must not be issued if the device has
+        * been disconnected */
+       if (!serial->disconnected) {
+               data = 0x00;
+               send_mos_cmd(serial, MOS_WRITE, port->number - port->serial->minor,
+                            0x04, &data);
+
+               data = 0x00;
+               send_mos_cmd(serial, MOS_WRITE, port->number - port->serial->minor,
+                            0x01, &data);
        }
-
-       data = 0x00;
-       send_mos_cmd(serial, MOS_WRITE, port->number - port->serial->minor,
-                    0x04, &data);
-
-       data = 0x00;
-       send_mos_cmd(serial, MOS_WRITE, port->number - port->serial->minor,
-                    0x01, &data);
-
+       mutex_unlock(&serial->disc_mutex);
        mos7720_port->open = 0;
 
        dbg("Leaving %s", __FUNCTION__);
@@ -1040,11 +1043,6 @@ static void change_port_settings(struct moschip_port *mos7720_port,
 
        tty = mos7720_port->port->tty;
 
-       if ((!tty) || (!tty->termios)) {
-               dbg("%s - no tty structures", __FUNCTION__);
-               return;
-       }
-
        dbg("%s: Entering ..........", __FUNCTION__);
 
        lData = UART_LCR_WLEN8;
@@ -1175,7 +1173,10 @@ static void change_port_settings(struct moschip_port *mos7720_port,
 
        dbg("%s - baud rate = %d", __FUNCTION__, baud);
        status = send_cmd_write_baud_rate(mos7720_port, baud);
-
+       /* FIXME: needs to write actual resulting baud back not just
+          blindly do so */
+       if (cflag & CBAUD)
+               tty_encode_baud_rate(tty, baud, baud);
        /* Enable Interrupts */
        data = 0x0c;
        send_mos_cmd(serial, MOS_WRITE, port_number, UART_IER, &data);
@@ -1214,10 +1215,6 @@ static void mos7720_set_termios(struct usb_serial_port *port,
 
        tty = port->tty;
 
-       if (!port->tty || !port->tty->termios) {
-               dbg("%s - no tty or termios", __FUNCTION__);
-               return;
-       }
 
        if (!mos7720_port->open) {
                dbg("%s - port not opened", __FUNCTION__);
@@ -1228,19 +1225,13 @@ static void mos7720_set_termios(struct usb_serial_port *port,
 
        cflag = tty->termios->c_cflag;
 
-       if (!cflag) {
-               printk("%s %s\n",__FUNCTION__,"cflag is NULL");
-               return;
-       }
-
-       dbg("%s - clfag %08x iflag %08x", __FUNCTION__,
+       dbg("%s - cflag %08x iflag %08x", __FUNCTION__,
            tty->termios->c_cflag,
            RELEVANT_IFLAG(tty->termios->c_iflag));
 
-       if (old_termios)
-               dbg("%s - old clfag %08x old iflag %08x", __FUNCTION__,
-                   old_termios->c_cflag,
-                   RELEVANT_IFLAG(old_termios->c_iflag));
+       dbg("%s - old cflag %08x old iflag %08x", __FUNCTION__,
+           old_termios->c_cflag,
+           RELEVANT_IFLAG(old_termios->c_iflag));
 
        dbg("%s - port %d", __FUNCTION__, port->number);
 
index c29c91271133584bdc9369f40c3cfd1817ac154a..869ecd374cb49e8161b765d23791604c3aff6256 100644 (file)
@@ -1133,7 +1133,7 @@ static int mos7840_chars_in_buffer(struct usb_serial_port *port)
  *     This function will block the close until one of the following:
  *             1. TX count are 0
  *             2. The mos7840 has stopped
- *             3. A timout of 3 seconds without activity has expired
+ *             3. A timeout of 3 seconds without activity has expired
  *
  ************************************************************************/
 static void mos7840_block_until_tx_empty(struct moschip_port *mos7840_port)
@@ -1161,7 +1161,7 @@ static void mos7840_block_until_tx_empty(struct moschip_port *mos7840_port)
                        dbg("%s - TIMEOUT", __FUNCTION__);
                        return;
                } else {
-                       /* Reset timout value back to seconds */
+                       /* Reset timeout value back to seconds */
                        wait = 30;
                }
        }
@@ -1275,7 +1275,7 @@ static void mos7840_close(struct usb_serial_port *port, struct file *filp)
  *
  *     This function will block the close until one of the following:
  *             1. Response to our Chase comes from mos7840
- *             2. A timout of 10 seconds without activity has expired
+ *             2. A timeout of 10 seconds without activity has expired
  *                (1K of mos7840 data @ 2400 baud ==> 4 sec to empty)
  *
  ************************************************************************/
@@ -1304,7 +1304,7 @@ static void mos7840_block_until_chase_response(struct moschip_port
                        dbg("%s - TIMEOUT", __FUNCTION__);
                        return;
                } else {
-                       /* Reset timout value back to seconds */
+                       /* Reset timeout value back to seconds */
                        wait = 10;
                }
        }
index d1185f53447b3f0b915807376dc99867509e755c..5e8bf1bc1e50577fb6231e8088b63fdda307994c 100644 (file)
@@ -180,6 +180,7 @@ static struct usb_device_id option_ids[] = {
        { USB_DEVICE(DELL_VENDOR_ID, 0x8117) }, /* Dell Wireless 5700 Mobile Broadband CDMA/EVDO ExpressCard == Novatel Merlin XV620 CDMA/EV-DO */
        { USB_DEVICE(DELL_VENDOR_ID, 0x8118) }, /* Dell Wireless 5510 Mobile Broadband HSDPA ExpressCard == Novatel Merlin XU870 HSDPA/3G */
        { USB_DEVICE(DELL_VENDOR_ID, 0x8128) }, /* Dell Wireless 5700 Mobile Broadband CDMA/EVDO Mini-Card == Novatel Expedite E720 CDMA/EV-DO */
+       { USB_DEVICE(DELL_VENDOR_ID, 0x8136) }, /* Dell Wireless HSDPA 5520 == Novatel Expedite EU860D */
        { USB_DEVICE(DELL_VENDOR_ID, 0x8137) }, /* Dell Wireless HSDPA 5520 */
        { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_E100A) },
        { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_500A) },
@@ -640,7 +641,10 @@ static void option_close(struct usb_serial_port *port, struct file *filp)
        portdata->dtr_state = 0;
 
        if (serial->dev) {
-               option_send_setup(port);
+               mutex_lock(&serial->disc_mutex);
+               if (!serial->disconnected)
+                       option_send_setup(port);
+               mutex_unlock(&serial->disc_mutex);
 
                /* Stop reading/writing urbs */
                for (i = 0; i < N_IN_URB; i++)
index eea226ae37bd15bacf66e4057ce54b8152256469..a3847d6c946eac309fe899b8698cdb34bbe29276 100644 (file)
@@ -79,7 +79,7 @@ static int debug;
 #define PL2303_BUF_SIZE                1024
 #define PL2303_TMP_BUF_SIZE    1024
 
-struct pl2303_buf {
+struct oti6858_buf {
        unsigned int    buf_size;
        char            *buf_buf;
        char            *buf_get;
@@ -161,14 +161,14 @@ static int oti6858_startup(struct usb_serial *serial);
 static void oti6858_shutdown(struct usb_serial *serial);
 
 /* functions operating on buffers */
-static struct pl2303_buf *pl2303_buf_alloc(unsigned int size);
-static void pl2303_buf_free(struct pl2303_buf *pb);
-static void pl2303_buf_clear(struct pl2303_buf *pb);
-static unsigned int pl2303_buf_data_avail(struct pl2303_buf *pb);
-static unsigned int pl2303_buf_space_avail(struct pl2303_buf *pb);
-static unsigned int pl2303_buf_put(struct pl2303_buf *pb, const char *buf,
+static struct oti6858_buf *oti6858_buf_alloc(unsigned int size);
+static void oti6858_buf_free(struct oti6858_buf *pb);
+static void oti6858_buf_clear(struct oti6858_buf *pb);
+static unsigned int oti6858_buf_data_avail(struct oti6858_buf *pb);
+static unsigned int oti6858_buf_space_avail(struct oti6858_buf *pb);
+static unsigned int oti6858_buf_put(struct oti6858_buf *pb, const char *buf,
                                        unsigned int count);
-static unsigned int pl2303_buf_get(struct pl2303_buf *pb, char *buf,
+static unsigned int oti6858_buf_get(struct oti6858_buf *pb, char *buf,
                                        unsigned int count);
 
 
@@ -203,7 +203,7 @@ static struct usb_serial_driver oti6858_device = {
 struct oti6858_private {
        spinlock_t lock;
 
-       struct pl2303_buf *buf;
+       struct oti6858_buf *buf;
        struct oti6858_control_pkt status;
 
        struct {
@@ -316,7 +316,7 @@ void send_data(struct work_struct *work)
        }
        priv->flags.write_urb_in_use = 1;
 
-       count = pl2303_buf_data_avail(priv->buf);
+       count = oti6858_buf_data_avail(priv->buf);
        spin_unlock_irqrestore(&priv->lock, flags);
        if (count > port->bulk_out_size)
                count = port->bulk_out_size;
@@ -345,7 +345,7 @@ void send_data(struct work_struct *work)
        }
 
        spin_lock_irqsave(&priv->lock, flags);
-       pl2303_buf_get(priv->buf, port->write_urb->transfer_buffer, count);
+       oti6858_buf_get(priv->buf, port->write_urb->transfer_buffer, count);
        spin_unlock_irqrestore(&priv->lock, flags);
 
        port->write_urb->transfer_buffer_length = count;
@@ -370,7 +370,7 @@ static int oti6858_startup(struct usb_serial *serial)
                priv = kzalloc(sizeof(struct oti6858_private), GFP_KERNEL);
                if (!priv)
                        break;
-               priv->buf = pl2303_buf_alloc(PL2303_BUF_SIZE);
+               priv->buf = oti6858_buf_alloc(PL2303_BUF_SIZE);
                if (priv->buf == NULL) {
                        kfree(priv);
                        break;
@@ -391,7 +391,7 @@ static int oti6858_startup(struct usb_serial *serial)
 
        for (--i; i >= 0; --i) {
                priv = usb_get_serial_port_data(serial->port[i]);
-               pl2303_buf_free(priv->buf);
+               oti6858_buf_free(priv->buf);
                kfree(priv);
                usb_set_serial_port_data(serial->port[i], NULL);
        }
@@ -410,7 +410,7 @@ static int oti6858_write(struct usb_serial_port *port,
                return count;
 
        spin_lock_irqsave(&priv->lock, flags);
-       count = pl2303_buf_put(priv->buf, buf, count);
+       count = oti6858_buf_put(priv->buf, buf, count);
        spin_unlock_irqrestore(&priv->lock, flags);
 
        return count;
@@ -425,7 +425,7 @@ static int oti6858_write_room(struct usb_serial_port *port)
        dbg("%s(port = %d)", __FUNCTION__, port->number);
 
        spin_lock_irqsave(&priv->lock, flags);
-       room = pl2303_buf_space_avail(priv->buf);
+       room = oti6858_buf_space_avail(priv->buf);
        spin_unlock_irqrestore(&priv->lock, flags);
 
        return room;
@@ -440,7 +440,7 @@ static int oti6858_chars_in_buffer(struct usb_serial_port *port)
        dbg("%s(port = %d)", __FUNCTION__, port->number);
 
        spin_lock_irqsave(&priv->lock, flags);
-       chars = pl2303_buf_data_avail(priv->buf);
+       chars = oti6858_buf_data_avail(priv->buf);
        spin_unlock_irqrestore(&priv->lock, flags);
 
        return chars;
@@ -458,7 +458,7 @@ static void oti6858_set_termios(struct usb_serial_port *port,
 
        dbg("%s(port = %d)", __FUNCTION__, port->number);
 
-       if ((!port->tty) || (!port->tty->termios)) {
+       if (!port->tty || !port->tty->termios) {
                dbg("%s(): no tty structures", __FUNCTION__);
                return;
        }
@@ -468,6 +468,8 @@ static void oti6858_set_termios(struct usb_serial_port *port,
                *(port->tty->termios) = tty_std_termios;
                port->tty->termios->c_cflag = B38400 | CS8 | CREAD | HUPCL | CLOCAL;
                priv->flags.termios_initialized = 1;
+               port->tty->termios->c_ispeed = 38400;
+               port->tty->termios->c_ospeed = 38400;
        }
        spin_unlock_irqrestore(&priv->lock, flags);
 
@@ -504,19 +506,14 @@ static void oti6858_set_termios(struct usb_serial_port *port,
        br = tty_get_baud_rate(port->tty);
        if (br == 0) {
                divisor = 0;
-       } else if (br <= OTI6858_MAX_BAUD_RATE) {
+       } else {
                int real_br;
+               br = min(br, OTI6858_MAX_BAUD_RATE);
 
                divisor = (96000000 + 8 * br) / (16 * br);
                real_br = 96000000 / (16 * divisor);
-               if ((((real_br - br) * 100 + br - 1) / br) > 2) {
-                       dbg("%s(): baud rate %d is invalid", __FUNCTION__, br);
-                       return;
-               }
                divisor = cpu_to_le16(divisor);
-       } else {
-               dbg("%s(): baud rate %d is too high", __FUNCTION__, br);
-               return;
+               tty_encode_baud_rate(port->tty, real_br, real_br);
        }
 
        frame_fmt &= ~FMT_STOP_BITS_MASK;
@@ -650,9 +647,9 @@ static void oti6858_close(struct usb_serial_port *port, struct file *filp)
        dbg("%s(): entering wait loop", __FUNCTION__);
        for (;;) {
                set_current_state(TASK_INTERRUPTIBLE);
-               if (pl2303_buf_data_avail(priv->buf) == 0
+               if (oti6858_buf_data_avail(priv->buf) == 0
                || timeout == 0 || signal_pending(current)
-               || !usb_get_intfdata(port->serial->interface))  /* disconnect */
+               || port->serial->disconnected)
                        break;
                spin_unlock_irqrestore(&priv->lock, flags);
                timeout = schedule_timeout(timeout);
@@ -663,7 +660,7 @@ static void oti6858_close(struct usb_serial_port *port, struct file *filp)
        dbg("%s(): after wait loop", __FUNCTION__);
 
        /* clear out any remaining data in the buffer */
-       pl2303_buf_clear(priv->buf);
+       oti6858_buf_clear(priv->buf);
        spin_unlock_irqrestore(&priv->lock, flags);
 
        /* wait for characters to drain from the device */
@@ -831,21 +828,6 @@ static int oti6858_ioctl(struct usb_serial_port *port, struct file *file,
                                return -EFAULT;
                        return oti6858_tiocmset(port, NULL, 0, x);
 
-               case TIOCGSERIAL:
-                       if (copy_to_user(user_arg, port->tty->termios,
-                                               sizeof(struct ktermios))) {
-                               return -EFAULT;
-                       }
-                        return 0;
-
-               case TIOCSSERIAL:
-                       if (copy_from_user(port->tty->termios, user_arg,
-                                               sizeof(struct ktermios))) {
-                               return -EFAULT;
-                       }
-                       oti6858_set_termios(port, NULL);
-                       return 0;
-
                case TIOCMIWAIT:
                        dbg("%s(): TIOCMIWAIT", __FUNCTION__);
                        return wait_modem_info(port, arg);
@@ -887,7 +869,7 @@ static void oti6858_shutdown(struct usb_serial *serial)
        for (i = 0; i < serial->num_ports; ++i) {
                priv = usb_get_serial_port_data(serial->port[i]);
                if (priv) {
-                       pl2303_buf_free(priv->buf);
+                       oti6858_buf_free(priv->buf);
                        kfree(priv);
                        usb_set_serial_port_data(serial->port[i], NULL);
                }
@@ -987,7 +969,7 @@ static void oti6858_read_int_callback(struct urb *urb)
 
                spin_lock_irqsave(&priv->lock, flags);
                if (priv->flags.write_urb_in_use == 0
-                               && pl2303_buf_data_avail(priv->buf) != 0) {
+                               && oti6858_buf_data_avail(priv->buf) != 0) {
                        schedule_delayed_work(&priv->delayed_write_work,0);
                        resubmit = 0;
                }
@@ -1015,9 +997,8 @@ static void oti6858_read_bulk_callback(struct urb *urb)
        struct tty_struct *tty;
        unsigned char *data = urb->transfer_buffer;
        unsigned long flags;
-       int i, result;
        int status = urb->status;
-       char tty_flag;
+       int result;
 
        dbg("%s(port = %d, status = %d)",
                                __FUNCTION__, port->number, status);
@@ -1045,27 +1026,9 @@ static void oti6858_read_bulk_callback(struct urb *urb)
                return;
        }
 
-       // get tty_flag from status
-       tty_flag = TTY_NORMAL;
-
-/* FIXME: probably, errors will be signalled using interrupt pipe! */
-/*
-       // break takes precedence over parity,
-       // which takes precedence over framing errors
-       if (status & UART_BREAK_ERROR )
-               tty_flag = TTY_BREAK;
-       else if (status & UART_PARITY_ERROR)
-               tty_flag = TTY_PARITY;
-       else if (status & UART_FRAME_ERROR)
-               tty_flag = TTY_FRAME;
-       dbg("%s - tty_flag = %d", __FUNCTION__, tty_flag);
-*/
-
        tty = port->tty;
        if (tty != NULL && urb->actual_length > 0) {
-               tty_buffer_request_room(tty, urb->actual_length);
-               for (i = 0; i < urb->actual_length; ++i)
-                       tty_insert_flip_char(tty, data[i], tty_flag);
+               tty_insert_flip_string(tty, data, urb->actual_length);
                tty_flip_buffer_push(tty);
        }
 
@@ -1133,18 +1096,18 @@ static void oti6858_write_bulk_callback(struct urb *urb)
 
 
 /*
- * pl2303_buf_alloc
+ * oti6858_buf_alloc
  *
  * Allocate a circular buffer and all associated memory.
  */
-static struct pl2303_buf *pl2303_buf_alloc(unsigned int size)
+static struct oti6858_buf *oti6858_buf_alloc(unsigned int size)
 {
-       struct pl2303_buf *pb;
+       struct oti6858_buf *pb;
 
        if (size == 0)
                return NULL;
 
-       pb = kmalloc(sizeof(struct pl2303_buf), GFP_KERNEL);
+       pb = kmalloc(sizeof(struct oti6858_buf), GFP_KERNEL);
        if (pb == NULL)
                return NULL;
 
@@ -1161,11 +1124,11 @@ static struct pl2303_buf *pl2303_buf_alloc(unsigned int size)
 }
 
 /*
- * pl2303_buf_free
+ * oti6858_buf_free
  *
  * Free the buffer and all associated memory.
  */
-static void pl2303_buf_free(struct pl2303_buf *pb)
+static void oti6858_buf_free(struct oti6858_buf *pb)
 {
        if (pb) {
                kfree(pb->buf_buf);
@@ -1174,11 +1137,11 @@ static void pl2303_buf_free(struct pl2303_buf *pb)
 }
 
 /*
- * pl2303_buf_clear
+ * oti6858_buf_clear
  *
  * Clear out all data in the circular buffer.
  */
-static void pl2303_buf_clear(struct pl2303_buf *pb)
+static void oti6858_buf_clear(struct oti6858_buf *pb)
 {
        if (pb != NULL) {
                /* equivalent to a get of all data available */
@@ -1187,12 +1150,12 @@ static void pl2303_buf_clear(struct pl2303_buf *pb)
 }
 
 /*
- * pl2303_buf_data_avail
+ * oti6858_buf_data_avail
  *
  * Return the number of bytes of data available in the circular
  * buffer.
  */
-static unsigned int pl2303_buf_data_avail(struct pl2303_buf *pb)
+static unsigned int oti6858_buf_data_avail(struct oti6858_buf *pb)
 {
        if (pb == NULL)
                return 0;
@@ -1200,12 +1163,12 @@ static unsigned int pl2303_buf_data_avail(struct pl2303_buf *pb)
 }
 
 /*
- * pl2303_buf_space_avail
+ * oti6858_buf_space_avail
  *
  * Return the number of bytes of space available in the circular
  * buffer.
  */
-static unsigned int pl2303_buf_space_avail(struct pl2303_buf *pb)
+static unsigned int oti6858_buf_space_avail(struct oti6858_buf *pb)
 {
        if (pb == NULL)
                return 0;
@@ -1213,14 +1176,14 @@ static unsigned int pl2303_buf_space_avail(struct pl2303_buf *pb)
 }
 
 /*
- * pl2303_buf_put
+ * oti6858_buf_put
  *
  * Copy data data from a user buffer and put it into the circular buffer.
  * Restrict to the amount of space available.
  *
  * Return the number of bytes copied.
  */
-static unsigned int pl2303_buf_put(struct pl2303_buf *pb, const char *buf,
+static unsigned int oti6858_buf_put(struct oti6858_buf *pb, const char *buf,
                                        unsigned int count)
 {
        unsigned int len;
@@ -1228,7 +1191,7 @@ static unsigned int pl2303_buf_put(struct pl2303_buf *pb, const char *buf,
        if (pb == NULL)
                return 0;
 
-       len  = pl2303_buf_space_avail(pb);
+       len  = oti6858_buf_space_avail(pb);
        if (count > len)
                count = len;
 
@@ -1252,14 +1215,14 @@ static unsigned int pl2303_buf_put(struct pl2303_buf *pb, const char *buf,
 }
 
 /*
- * pl2303_buf_get
+ * oti6858_buf_get
  *
  * Get data from the circular buffer and copy to the given buffer.
  * Restrict to the amount of data available.
  *
  * Return the number of bytes copied.
  */
-static unsigned int pl2303_buf_get(struct pl2303_buf *pb, char *buf,
+static unsigned int oti6858_buf_get(struct oti6858_buf *pb, char *buf,
                                        unsigned int count)
 {
        unsigned int len;
@@ -1267,7 +1230,7 @@ static unsigned int pl2303_buf_get(struct pl2303_buf *pb, char *buf,
        if (pb == NULL)
                return 0;
 
-       len = pl2303_buf_data_avail(pb);
+       len = oti6858_buf_data_avail(pb);
        if (count > len)
                count = len;
 
index 0da1df9c79bf044677e703c125212a0dd5f0f52f..ae3ec1a64008b65e2b10f4a95152ea74e6c23729 100644 (file)
@@ -65,6 +65,7 @@ static struct usb_device_id id_table [] = {
        { USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID_2080) },
        { USB_DEVICE(MA620_VENDOR_ID, MA620_PRODUCT_ID) },
        { USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID) },
+       { USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID_USB60F) },
        { USB_DEVICE(TRIPP_VENDOR_ID, TRIPP_PRODUCT_ID) },
        { USB_DEVICE(RADIOSHACK_VENDOR_ID, RADIOSHACK_PRODUCT_ID) },
        { USB_DEVICE(DCU10_VENDOR_ID, DCU10_PRODUCT_ID) },
@@ -84,9 +85,10 @@ static struct usb_device_id id_table [] = {
        { USB_DEVICE(DATAPILOT_U2_VENDOR_ID, DATAPILOT_U2_PRODUCT_ID) },
        { USB_DEVICE(BELKIN_VENDOR_ID, BELKIN_PRODUCT_ID) },
        { USB_DEVICE(ALCOR_VENDOR_ID, ALCOR_PRODUCT_ID) },
-       { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_ID) },
        { USB_DEVICE(WS002IN_VENDOR_ID, WS002IN_PRODUCT_ID) },
        { USB_DEVICE(COREGA_VENDOR_ID, COREGA_PRODUCT_ID) },
+       { USB_DEVICE(HL340_VENDOR_ID, HL340_PRODUCT_ID) },
+       { USB_DEVICE(YCCABLE_VENDOR_ID, YCCABLE_PRODUCT_ID) },
        { }                                     /* Terminating entry */
 };
 
@@ -97,7 +99,10 @@ static struct usb_driver pl2303_driver = {
        .probe =        usb_serial_probe,
        .disconnect =   usb_serial_disconnect,
        .id_table =     id_table,
+       .suspend =      usb_serial_suspend,
+       .resume =       usb_serial_resume,
        .no_dynamic_id =        1,
+       .supports_autosuspend = 1,
 };
 
 #define SET_LINE_REQUEST_TYPE          0x21
@@ -310,12 +315,39 @@ static unsigned int pl2303_buf_get(struct pl2303_buf *pb, char *buf,
        return count;
 }
 
+static int pl2303_vendor_read(__u16 value, __u16 index,
+               struct usb_serial *serial, unsigned char *buf)
+{
+       int res = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
+                       VENDOR_READ_REQUEST, VENDOR_READ_REQUEST_TYPE,
+                       value, index, buf, 1, 100);
+       dbg("0x%x:0x%x:0x%x:0x%x  %d - %x", VENDOR_READ_REQUEST_TYPE,
+                       VENDOR_READ_REQUEST, value, index, res, buf[0]);
+       return res;
+}
+
+static int pl2303_vendor_write(__u16 value, __u16 index,
+               struct usb_serial *serial)
+{
+       int res = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+                       VENDOR_WRITE_REQUEST, VENDOR_WRITE_REQUEST_TYPE,
+                       value, index, NULL, 0, 100);
+       dbg("0x%x:0x%x:0x%x:0x%x  %d", VENDOR_WRITE_REQUEST_TYPE,
+                       VENDOR_WRITE_REQUEST, value, index, res);
+       return res;
+}
+
 static int pl2303_startup(struct usb_serial *serial)
 {
        struct pl2303_private *priv;
        enum pl2303_type type = type_0;
+       unsigned char *buf;
        int i;
 
+       buf = kmalloc(10, GFP_KERNEL);
+       if (buf == NULL)
+               return -ENOMEM;
+
        if (serial->dev->descriptor.bDeviceClass == 0x02)
                type = type_0;
        else if (serial->dev->descriptor.bMaxPacketSize0 == 0x40)
@@ -340,9 +372,27 @@ static int pl2303_startup(struct usb_serial *serial)
                priv->type = type;
                usb_set_serial_port_data(serial->port[i], priv);
        }
+
+       pl2303_vendor_read(0x8484, 0, serial, buf);
+       pl2303_vendor_write(0x0404, 0, serial);
+       pl2303_vendor_read(0x8484, 0, serial, buf);
+       pl2303_vendor_read(0x8383, 0, serial, buf);
+       pl2303_vendor_read(0x8484, 0, serial, buf);
+       pl2303_vendor_write(0x0404, 1, serial);
+       pl2303_vendor_read(0x8484, 0, serial, buf);
+       pl2303_vendor_read(0x8383, 0, serial, buf);
+       pl2303_vendor_write(0, 1, serial);
+       pl2303_vendor_write(1, 0, serial);
+       if (type == HX)
+               pl2303_vendor_write(2, 0x44, serial);
+       else
+               pl2303_vendor_write(2, 0x24, serial);
+
+       kfree(buf);
        return 0;
 
 cleanup:
+       kfree(buf);
        for (--i; i>=0; --i) {
                priv = usb_get_serial_port_data(serial->port[i]);
                pl2303_buf_free(priv->buf);
@@ -582,24 +632,12 @@ static void pl2303_set_termios(struct usb_serial_port *port,
             buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
 
        if (cflag & CRTSCTS) {
-               __u16 index;
                if (priv->type == HX)
-                       index = 0x61;
+                       pl2303_vendor_write(0x0, 0x61, serial);
                else
-                       index = 0x41;
-               i = usb_control_msg(serial->dev,
-                                   usb_sndctrlpipe(serial->dev, 0),
-                                   VENDOR_WRITE_REQUEST,
-                                   VENDOR_WRITE_REQUEST_TYPE,
-                                   0x0, index, NULL, 0, 100);
-               dbg("0x40:0x1:0x0:0x%x  %d", index, i);
+                       pl2303_vendor_write(0x0, 0x41, serial);
        } else {
-               i = usb_control_msg(serial->dev,
-                                   usb_sndctrlpipe(serial->dev, 0),
-                                   VENDOR_WRITE_REQUEST,
-                                   VENDOR_WRITE_REQUEST_TYPE,
-                                   0x0, 0x0, NULL, 0, 100);
-               dbg ("0x40:0x1:0x0:0x0  %d", i);
+               pl2303_vendor_write(0x0, 0x0, serial);
        }
 
        /* FIXME: Need to read back resulting baud rate */
@@ -629,7 +667,7 @@ static void pl2303_close(struct usb_serial_port *port, struct file *filp)
                set_current_state(TASK_INTERRUPTIBLE);
                if (pl2303_buf_data_avail(priv->buf) == 0 ||
                    timeout == 0 || signal_pending(current) ||
-                   !usb_get_intfdata(port->serial->interface)) /* disconnect */
+                   port->serial->disconnected)
                        break;
                spin_unlock_irqrestore(&priv->lock, flags);
                timeout = schedule_timeout(timeout);
@@ -678,7 +716,6 @@ static int pl2303_open(struct usb_serial_port *port, struct file *filp)
        struct ktermios tmp_termios;
        struct usb_serial *serial = port->serial;
        struct pl2303_private *priv = usb_get_serial_port_data(port);
-       unsigned char *buf;
        int result;
 
        dbg("%s -  port %d", __FUNCTION__, port->number);
@@ -686,45 +723,12 @@ static int pl2303_open(struct usb_serial_port *port, struct file *filp)
        if (priv->type != HX) {
                usb_clear_halt(serial->dev, port->write_urb->pipe);
                usb_clear_halt(serial->dev, port->read_urb->pipe);
-       }
-
-       buf = kmalloc(10, GFP_KERNEL);
-       if (buf==NULL)
-               return -ENOMEM;
-
-#define FISH(a,b,c,d)                                                          \
-       result=usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev,0),     \
-                              b, a, c, d, buf, 1, 100);                        \
-       dbg("0x%x:0x%x:0x%x:0x%x  %d - %x",a,b,c,d,result,buf[0]);
-
-#define SOUP(a,b,c,d)                                                          \
-       result=usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev,0),     \
-                              b, a, c, d, NULL, 0, 100);                       \
-       dbg("0x%x:0x%x:0x%x:0x%x  %d",a,b,c,d,result);
-
-       FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0);
-       SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 0x0404, 0);
-       FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0);
-       FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8383, 0);
-       FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0);
-       SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 0x0404, 1);
-       FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0);
-       FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8383, 0);
-       SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 0, 1);
-       SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 1, 0);
-
-       if (priv->type == HX) {
-               /* HX chip */
-               SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 2, 0x44);
-               /* reset upstream data pipes */
-               SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 8, 0);
-               SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 9, 0);
        } else {
-               SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 2, 0x24);
+               /* reset upstream data pipes */
+               pl2303_vendor_write(8, 0, serial);
+               pl2303_vendor_write(9, 0, serial);
        }
 
-       kfree(buf);
-
        /* Setup termios */
        if (port->tty) {
                pl2303_set_termios(port, &tmp_termios);
index d31f5d299989f2315b280c4ab3092edec912d002..237a41f6638ac239b9c3dc980230cf4c615537f5 100644 (file)
@@ -35,6 +35,7 @@
 
 #define RATOC_VENDOR_ID                0x0584
 #define RATOC_PRODUCT_ID       0xb000
+#define RATOC_PRODUCT_ID_USB60F        0xb020
 
 #define TRIPP_VENDOR_ID                0x2478
 #define TRIPP_PRODUCT_ID       0x2008
 #define ALCOR_VENDOR_ID                0x058F
 #define ALCOR_PRODUCT_ID       0x9720
 
-/* Huawei E620 UMTS/HSDPA card (ID: 12d1:1001) */
-#define HUAWEI_VENDOR_ID       0x12d1
-#define HUAWEI_PRODUCT_ID      0x1001
-
 /* Willcom WS002IN Data Driver (by NetIndex Inc.) */
 #define WS002IN_VENDOR_ID      0x11f6
 #define WS002IN_PRODUCT_ID     0x2001
 /* Corega CG-USBRS232R Serial Adapter */
 #define COREGA_VENDOR_ID       0x07aa
 #define COREGA_PRODUCT_ID      0x002a
+
+/* HL HL-340 (ID: 4348:5523) */
+#define HL340_VENDOR_ID                0x4348
+#define HL340_PRODUCT_ID       0x5523
+
+/* Y.C. Cable U.S.A., Inc - USB to RS-232 */
+#define YCCABLE_VENDOR_ID      0x05ad
+#define YCCABLE_PRODUCT_ID     0x0fba
index c295d0495f96f9a6a490494e504ee0510f9a40fb..4c925e3e8a6387663447f56cd07bc5532c931ddc 100644 (file)
@@ -1,7 +1,7 @@
 /*
   USB Driver for Sierra Wireless
 
-  Copyright (C) 2006, 2007  Kevin Lloyd <linux@sierrawireless.com>
+  Copyright (C) 2006, 2007, 2008  Kevin Lloyd <linux@sierrawireless.com>
 
   IMPORTANT DISCLAIMER: This driver is not commercially supported by
   Sierra Wireless. Use at your own risk.
@@ -14,7 +14,7 @@
   Whom based his on the Keyspan driver by Hugh Blemings <hugh@blemings.org>
 */
 
-#define DRIVER_VERSION "v.1.2.5b"
+#define DRIVER_VERSION "v.1.2.7"
 #define DRIVER_AUTHOR "Kevin Lloyd <linux@sierrawireless.com>"
 #define DRIVER_DESC "USB Driver for Sierra Wireless USB modems"
 
 #include <linux/module.h>
 #include <linux/usb.h>
 #include <linux/usb/serial.h>
+#include <linux/usb/ch9.h>
 
+#define SWIMS_USB_REQUEST_SetPower     0x00
+#define SWIMS_USB_REQUEST_SetNmea      0x07
 #define SWIMS_USB_REQUEST_SetMode      0x0B
-#define SWIMS_USB_REQUEST_TYPE_SetMode 0x40
-#define SWIMS_USB_INDEX_SetMode                0x0000
+#define SWIMS_USB_REQUEST_TYPE_VSC_SET 0x40
 #define SWIMS_SET_MODE_Modem           0x0001
 
 /* per port private data */
@@ -38,6 +40,8 @@
 #define IN_BUFLEN      4096
 
 static int debug;
+static int nmea;
+static int truinstall = 1;
 
 enum devicetype {
        DEVICE_3_PORT =         0,
@@ -50,48 +54,96 @@ static int sierra_set_power_state(struct usb_device *udev, __u16 swiState)
        int result;
        dev_dbg(&udev->dev, "%s", "SET POWER STATE\n");
        result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
-                       0x00,                   /* __u8 request      */
-                       0x40,                   /* __u8 request type */
-                       swiState,               /* __u16 value       */
-                       0,                      /* __u16 index       */
-                       NULL,                   /* void *data        */
-                       0,                      /* __u16 size        */
-                       USB_CTRL_SET_TIMEOUT);  /* int timeout       */
+                       SWIMS_USB_REQUEST_SetPower,     /* __u8 request      */
+                       SWIMS_USB_REQUEST_TYPE_VSC_SET, /* __u8 request type */
+                       swiState,                       /* __u16 value       */
+                       0,                              /* __u16 index       */
+                       NULL,                           /* void *data        */
+                       0,                              /* __u16 size        */
+                       USB_CTRL_SET_TIMEOUT);          /* int timeout       */
        return result;
 }
 
-static int sierra_set_ms_mode(struct usb_device *udev, __u16 eSocMode)
+static int sierra_set_ms_mode(struct usb_device *udev, __u16 eSWocMode)
 {
        int result;
        dev_dbg(&udev->dev, "%s", "DEVICE MODE SWITCH\n");
        result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
                        SWIMS_USB_REQUEST_SetMode,      /* __u8 request      */
-                       SWIMS_USB_REQUEST_TYPE_SetMode, /* __u8 request type */
-                       eSocMode,                       /* __u16 value       */
-                       SWIMS_USB_INDEX_SetMode,        /* __u16 index       */
+                       SWIMS_USB_REQUEST_TYPE_VSC_SET, /* __u8 request type */
+                       eSWocMode,                      /* __u16 value       */
+                       0x0000,                         /* __u16 index       */
                        NULL,                           /* void *data        */
                        0,                              /* __u16 size        */
                        USB_CTRL_SET_TIMEOUT);          /* int timeout       */
        return result;
 }
 
-static int sierra_probe(struct usb_interface *iface,
-                       const struct usb_device_id *id)
+static int sierra_vsc_set_nmea(struct usb_device *udev, __u16 enable)
+{
+       int result;
+       dev_dbg(&udev->dev, "%s", "NMEA Enable sent\n");
+       result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+                       SWIMS_USB_REQUEST_SetNmea,      /* __u8 request      */
+                       SWIMS_USB_REQUEST_TYPE_VSC_SET, /* __u8 request type */
+                       enable,                         /* __u16 value       */
+                       0x0000,                         /* __u16 index       */
+                       NULL,                           /* void *data        */
+                       0,                              /* __u16 size        */
+                       USB_CTRL_SET_TIMEOUT);          /* int timeout       */
+       return result;
+}
+
+static int sierra_calc_num_ports(struct usb_serial *serial)
 {
        int result;
+       int *num_ports = usb_get_serial_data(serial);
+
+       result = *num_ports;
+
+       if (result) {
+               kfree(num_ports);
+               usb_set_serial_data(serial, NULL);
+       }
+
+       return result;
+}
+
+static int sierra_probe(struct usb_serial *serial,
+                       const struct usb_device_id *id)
+{
+       int result = 0;
        struct usb_device *udev;
+       int *num_ports;
+       u8 ifnum;
+
+       num_ports = kmalloc(sizeof(*num_ports), GFP_KERNEL);
+       if (!num_ports)
+               return -ENOMEM;
 
-       udev = usb_get_dev(interface_to_usbdev(iface));
+       ifnum = serial->interface->cur_altsetting->desc.bInterfaceNumber;
+       udev = serial->dev;
 
        /* Check if in installer mode */
-       if (id->driver_info == DEVICE_INSTALLER) {
-               dev_dbg(&udev->dev, "%s", "FOUND DEVICE(SW)\n");
+       if (truinstall && id->driver_info == DEVICE_INSTALLER) {
+               dev_dbg(&udev->dev, "%s", "FOUND TRU-INSTALL DEVICE(SW)\n");
                result = sierra_set_ms_mode(udev, SWIMS_SET_MODE_Modem);
-               /*We do not want to bind to the device when in installer mode*/
+               /* Don't bind to the device when in installer mode */
+               kfree(num_ports);
                return -EIO;
-       }
+       } else if (id->driver_info == DEVICE_1_PORT)
+               *num_ports = 1;
+       else if (ifnum == 0x99)
+               *num_ports = 0;
+       else
+               *num_ports = 3;
+       /*
+        * 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);
 
-       return usb_serial_probe(iface, id);
+       return result;
 }
 
 static struct usb_device_id id_table [] = {
@@ -104,6 +156,7 @@ static struct usb_device_id id_table [] = {
        { USB_DEVICE(0x1199, 0x0019) }, /* Sierra Wireless AirCard 595 */
        { USB_DEVICE(0x1199, 0x0021) }, /* Sierra Wireless AirCard 597E */
        { USB_DEVICE(0x1199, 0x0120) }, /* Sierra Wireless USB Dongle 595U */
+       { USB_DEVICE(0x1199, 0x0023) }, /* Sierra Wireless AirCard */
 
        { USB_DEVICE(0x1199, 0x6802) }, /* Sierra Wireless MC8755 */
        { USB_DEVICE(0x1199, 0x6804) }, /* Sierra Wireless MC8755 */
@@ -117,56 +170,29 @@ static struct usb_device_id id_table [] = {
        { USB_DEVICE(0x1199, 0x6851) }, /* Sierra Wireless AirCard 881 */
        { USB_DEVICE(0x1199, 0x6852) }, /* Sierra Wireless AirCard 880 E */
        { USB_DEVICE(0x1199, 0x6853) }, /* Sierra Wireless AirCard 881 E */
+       { USB_DEVICE(0x1199, 0x6855) }, /* Sierra Wireless AirCard 880 U */
+       { USB_DEVICE(0x1199, 0x6856) }, /* Sierra Wireless AirCard 881 U */
+
+       { USB_DEVICE(0x1199, 0x6468) }, /* Sierra Wireless MP3G - EVDO */
+       { USB_DEVICE(0x1199, 0x6469) }, /* Sierra Wireless MP3G - UMTS/HSPA */
 
        { USB_DEVICE(0x1199, 0x0112), .driver_info = DEVICE_1_PORT }, /* Sierra Wireless AirCard 580 */
        { USB_DEVICE(0x0F3D, 0x0112), .driver_info = DEVICE_1_PORT }, /* Airprime/Sierra PC 5220 */
+       { USB_DEVICE(0x05C6, 0x6613), .driver_info = DEVICE_1_PORT }, /* Onda H600/ZTE MF330 */
 
        { USB_DEVICE(0x1199, 0x0FFF), .driver_info = DEVICE_INSTALLER},
        { }
 };
 MODULE_DEVICE_TABLE(usb, id_table);
 
-static struct usb_device_id id_table_1port [] = {
-       { USB_DEVICE(0x1199, 0x0112) }, /* Sierra Wireless AirCard 580 */
-       { USB_DEVICE(0x0F3D, 0x0112) }, /* AirPrime/Sierra PC 5220 */
-       { }
-};
-
-static struct usb_device_id id_table_3port [] = {
-       { USB_DEVICE(0x1199, 0x0017) }, /* Sierra Wireless EM5625 */
-       { USB_DEVICE(0x1199, 0x0018) }, /* Sierra Wireless MC5720 */
-       { USB_DEVICE(0x0f30, 0x1b1d) }, /* Sierra Wireless MC5720 */
-       { USB_DEVICE(0x1199, 0x0218) }, /* Sierra Wireless MC5720 */
-       { USB_DEVICE(0x1199, 0x0020) }, /* Sierra Wireless MC5725 */
-       { USB_DEVICE(0x1199, 0x0220) }, /* Sierra Wireless MC5725 */
-       { USB_DEVICE(0x1199, 0x0019) }, /* Sierra Wireless AirCard 595 */
-       { USB_DEVICE(0x1199, 0x0021) }, /* Sierra Wireless AirCard 597E */
-       { USB_DEVICE(0x1199, 0x0120) }, /* Sierra Wireless USB Dongle 595U*/
-
-       { USB_DEVICE(0x1199, 0x6802) }, /* Sierra Wireless MC8755 */
-       { USB_DEVICE(0x1199, 0x6804) }, /* Sierra Wireless MC8755 */
-       { USB_DEVICE(0x1199, 0x6803) }, /* Sierra Wireless MC8765 */
-       { USB_DEVICE(0x1199, 0x6812) }, /* Sierra Wireless MC8775 & AC 875U */
-       { USB_DEVICE(0x1199, 0x6813) }, /* Sierra Wireless MC8775 (Thinkpad internal) */
-       { USB_DEVICE(0x1199, 0x6820) }, /* Sierra Wireless AirCard 875 */
-       { USB_DEVICE(0x1199, 0x6832) }, /* Sierra Wireless MC8780*/
-       { USB_DEVICE(0x1199, 0x6833) }, /* Sierra Wireless MC8781*/
-       { USB_DEVICE(0x1199, 0x6850) }, /* Sierra Wireless AirCard 880 */
-       { USB_DEVICE(0x1199, 0x6851) }, /* Sierra Wireless AirCard 881 */
-       { USB_DEVICE(0x1199, 0x6852) }, /* Sierra Wireless AirCard 880E */
-       { USB_DEVICE(0x1199, 0x6853) }, /* Sierra Wireless AirCard 881E */
-       { }
-};
-
 static struct usb_driver sierra_driver = {
        .name       = "sierra",
-       .probe      = sierra_probe,
+       .probe      = usb_serial_probe,
        .disconnect = usb_serial_disconnect,
        .id_table   = id_table,
        .no_dynamic_id =        1,
 };
 
-
 struct sierra_port_private {
        spinlock_t lock;        /* lock the structure */
        int outstanding_urbs;   /* number of out urbs in flight */
@@ -188,6 +214,7 @@ static int sierra_send_setup(struct usb_serial_port *port)
 {
        struct usb_serial *serial = port->serial;
        struct sierra_port_private *portdata;
+       __u16 interface = 0;
 
        dbg("%s", __FUNCTION__);
 
@@ -200,9 +227,18 @@ static int sierra_send_setup(struct usb_serial_port *port)
                if (portdata->rts_state)
                        val |= 0x02;
 
+               /* Determine which port is targeted */
+               if (port->bulk_out_endpointAddress == 2)
+                       interface = 0;
+               else if (port->bulk_out_endpointAddress == 4)
+                       interface = 1;
+               else if (port->bulk_out_endpointAddress == 5)
+                       interface = 2;
+
                return usb_control_msg(serial->dev,
                                usb_rcvctrlpipe(serial->dev, 0),
-                               0x22,0x21,val,0,NULL,0,USB_CTRL_SET_TIMEOUT);
+                               0x22, 0x21, val, interface,
+                               NULL, 0, USB_CTRL_SET_TIMEOUT);
        }
 
        return 0;
@@ -561,7 +597,10 @@ static void sierra_close(struct usb_serial_port *port, struct file *filp)
        portdata->dtr_state = 0;
 
        if (serial->dev) {
-               sierra_send_setup(port);
+               mutex_lock(&serial->disc_mutex);
+               if (!serial->disconnected)
+                       sierra_send_setup(port);
+               mutex_unlock(&serial->disc_mutex);
 
                /* Stop reading/writing urbs */
                for (i = 0; i < N_IN_URB; i++)
@@ -583,9 +622,13 @@ static int sierra_startup(struct usb_serial *serial)
 
        dbg("%s", __FUNCTION__);
 
-       /*Set Device mode to D0 */
+       /* Set Device mode to D0 */
        sierra_set_power_state(serial->dev, 0x0000);
 
+       /* Check NMEA and set */
+       if (nmea)
+               sierra_vsc_set_nmea(serial->dev, 1);
+
        /* Now setup per port private data */
        for (i = 0; i < serial->num_ports; i++) {
                port = serial->port[i];
@@ -646,47 +689,19 @@ static void sierra_shutdown(struct usb_serial *serial)
        }
 }
 
-static struct usb_serial_driver sierra_1port_device = {
+static struct usb_serial_driver sierra_device = {
        .driver = {
                .owner =        THIS_MODULE,
                .name =         "sierra1",
        },
-       .description       = "Sierra USB modem (1 port)",
-       .id_table          = id_table_1port,
-       .usb_driver        = &sierra_driver,
-       .num_interrupt_in  = NUM_DONT_CARE,
-       .num_bulk_in       = 1,
-       .num_bulk_out      = 1,
-       .num_ports         = 1,
-       .open              = sierra_open,
-       .close             = sierra_close,
-       .write             = sierra_write,
-       .write_room        = sierra_write_room,
-       .chars_in_buffer   = sierra_chars_in_buffer,
-       .throttle          = sierra_rx_throttle,
-       .unthrottle        = sierra_rx_unthrottle,
-       .ioctl             = sierra_ioctl,
-       .set_termios       = sierra_set_termios,
-       .break_ctl         = sierra_break_ctl,
-       .tiocmget          = sierra_tiocmget,
-       .tiocmset          = sierra_tiocmset,
-       .attach            = sierra_startup,
-       .shutdown          = sierra_shutdown,
-       .read_int_callback = sierra_instat_callback,
-};
-
-static struct usb_serial_driver sierra_3port_device = {
-       .driver = {
-               .owner =        THIS_MODULE,
-               .name =         "sierra3",
-       },
-       .description       = "Sierra USB modem (3 port)",
-       .id_table          = id_table_3port,
+       .description       = "Sierra USB modem",
+       .id_table          = id_table,
        .usb_driver        = &sierra_driver,
        .num_interrupt_in  = NUM_DONT_CARE,
-       .num_bulk_in       = 3,
-       .num_bulk_out      = 3,
-       .num_ports         = 3,
+       .num_bulk_in       = NUM_DONT_CARE,
+       .num_bulk_out      = NUM_DONT_CARE,
+       .calc_num_ports    = sierra_calc_num_ports,
+       .probe             = sierra_probe,
        .open              = sierra_open,
        .close             = sierra_close,
        .write             = sierra_write,
@@ -708,12 +723,9 @@ static struct usb_serial_driver sierra_3port_device = {
 static int __init sierra_init(void)
 {
        int retval;
-       retval = usb_serial_register(&sierra_1port_device);
-       if (retval)
-               goto failed_1port_device_register;
-       retval = usb_serial_register(&sierra_3port_device);
+       retval = usb_serial_register(&sierra_device);
        if (retval)
-               goto failed_3port_device_register;
+               goto failed_device_register;
 
 
        retval = usb_register(&sierra_driver);
@@ -725,18 +737,15 @@ static int __init sierra_init(void)
        return 0;
 
 failed_driver_register:
-       usb_serial_deregister(&sierra_3port_device);
-failed_3port_device_register:
-       usb_serial_deregister(&sierra_1port_device);
-failed_1port_device_register:
+       usb_serial_deregister(&sierra_device);
+failed_device_register:
        return retval;
 }
 
 static void __exit sierra_exit(void)
 {
        usb_deregister (&sierra_driver);
-       usb_serial_deregister(&sierra_1port_device);
-       usb_serial_deregister(&sierra_3port_device);
+       usb_serial_deregister(&sierra_device);
 }
 
 module_init(sierra_init);
@@ -747,6 +756,12 @@ MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_VERSION(DRIVER_VERSION);
 MODULE_LICENSE("GPL");
 
+module_param(truinstall, bool, 0);
+MODULE_PARM_DESC(truinstall, "TRU-Install support");
+
+module_param(nmea, bool, 0);
+MODULE_PARM_DESC(nmea, "NMEA streaming");
+
 #ifdef CONFIG_USB_DEBUG
 module_param(debug, bool, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(debug, "Debug messages");
index 1f0149495fb4f218067433a53a07abe8721ace57..b517f93352ec414d8ee52258b5965868ea2fb5f2 100644 (file)
@@ -80,6 +80,7 @@
 #include <linux/ioctl.h>
 #include <linux/serial.h>
 #include <linux/circ_buf.h>
+#include <linux/mutex.h>
 #include <asm/uaccess.h>
 #include <asm/semaphore.h>
 #include <linux/usb.h>
@@ -139,7 +140,7 @@ struct ti_port {
 };
 
 struct ti_device {
-       struct semaphore        td_open_close_sem;
+       struct mutex            td_open_close_lock;
        int                     td_open_port_count;
        struct usb_serial       *td_serial;
        int                     td_is_3410;
@@ -424,7 +425,7 @@ static int ti_startup(struct usb_serial *serial)
                dev_err(&dev->dev, "%s - out of memory\n", __FUNCTION__);
                return -ENOMEM;
        }
-       sema_init(&tdev->td_open_close_sem, 1);
+       mutex_init(&tdev->td_open_close_lock);
        tdev->td_serial = serial;
        usb_set_serial_data(serial, tdev);
 
@@ -547,7 +548,7 @@ static int ti_open(struct usb_serial_port *port, struct file *file)
        tdev = tport->tp_tdev;
 
        /* only one open on any port on a device at a time */
-       if (down_interruptible(&tdev->td_open_close_sem))
+       if (mutex_lock_interruptible(&tdev->td_open_close_lock))
                return -ERESTARTSYS;
 
        if (port->tty)
@@ -568,7 +569,7 @@ static int ti_open(struct usb_serial_port *port, struct file *file)
                if (!urb) {
                        dev_err(&port->dev, "%s - no interrupt urb\n", __FUNCTION__);
                        status = -EINVAL;
-                       goto up_sem;
+                       goto release_lock;
                }
                urb->complete = ti_interrupt_callback;
                urb->context = tdev;
@@ -576,11 +577,11 @@ static int ti_open(struct usb_serial_port *port, struct file *file)
                status = usb_submit_urb(urb, GFP_KERNEL);
                if (status) {
                        dev_err(&port->dev, "%s - submit interrupt urb failed, %d\n", __FUNCTION__, status);
-                       goto up_sem;
+                       goto release_lock;
                }
        }
 
-       ti_set_termios(port, NULL);
+       ti_set_termios(port, port->tty->termios);
 
        dbg("%s - sending TI_OPEN_PORT", __FUNCTION__);
        status = ti_command_out_sync(tdev, TI_OPEN_PORT,
@@ -617,7 +618,7 @@ static int ti_open(struct usb_serial_port *port, struct file *file)
        usb_clear_halt(dev, port->write_urb->pipe);
        usb_clear_halt(dev, port->read_urb->pipe);
 
-       ti_set_termios(port, NULL);
+       ti_set_termios(port, port->tty->termios);
 
        dbg("%s - sending TI_OPEN_PORT (2)", __FUNCTION__);
        status = ti_command_out_sync(tdev, TI_OPEN_PORT,
@@ -656,13 +657,13 @@ static int ti_open(struct usb_serial_port *port, struct file *file)
        tport->tp_is_open = 1;
        ++tdev->td_open_port_count;
 
-       goto up_sem;
+       goto release_lock;
 
 unlink_int_urb:
        if (tdev->td_open_port_count == 0)
                usb_kill_urb(port->serial->port[0]->interrupt_in_urb);
-up_sem:
-       up(&tdev->td_open_close_sem);
+release_lock:
+       mutex_unlock(&tdev->td_open_close_lock);
        dbg("%s - exit %d", __FUNCTION__, status);
        return status;
 }
@@ -674,7 +675,7 @@ static void ti_close(struct usb_serial_port *port, struct file *file)
        struct ti_port *tport;
        int port_number;
        int status;
-       int do_up;
+       int do_unlock;
 
        dbg("%s - port %d", __FUNCTION__, port->number);
                         
@@ -699,16 +700,16 @@ static void ti_close(struct usb_serial_port *port, struct file *file)
        if (status)
                dev_err(&port->dev, "%s - cannot send close port command, %d\n" , __FUNCTION__, status);
 
-       /* if down is interrupted, continue anyway */
-       do_up = !down_interruptible(&tdev->td_open_close_sem);
+       /* if mutex_lock is interrupted, continue anyway */
+       do_unlock = !mutex_lock_interruptible(&tdev->td_open_close_lock);
        --tport->tp_tdev->td_open_port_count;
        if (tport->tp_tdev->td_open_port_count <= 0) {
                /* last port is closed, shut down interrupt urb */
                usb_kill_urb(port->serial->port[0]->interrupt_in_urb);
                tport->tp_tdev->td_open_port_count = 0;
        }
-       if (do_up)
-               up(&tdev->td_open_close_sem);
+       if (do_unlock)
+               mutex_unlock(&tdev->td_open_close_lock);
 
        dbg("%s - exit", __FUNCTION__);
 }
@@ -896,24 +897,11 @@ static void ti_set_termios(struct usb_serial_port *port,
 
        dbg("%s - port %d", __FUNCTION__, port->number);
 
-       if (!tty || !tty->termios) {
-               dbg("%s - no tty or termios", __FUNCTION__);
-               return;
-       }
-
        cflag = tty->termios->c_cflag;
        iflag = tty->termios->c_iflag;
 
-       if (old_termios && cflag == old_termios->c_cflag
-       && iflag == old_termios->c_iflag) {
-               dbg("%s - nothing to change", __FUNCTION__);
-               return;
-       }
-
-       dbg("%s - clfag %08x, iflag %08x", __FUNCTION__, cflag, iflag);
-
-       if (old_termios)
-               dbg("%s - old clfag %08x, old iflag %08x", __FUNCTION__, old_termios->c_cflag, old_termios->c_iflag);
+       dbg("%s - cflag %08x, iflag %08x", __FUNCTION__, cflag, iflag);
+       dbg("%s - old clfag %08x, old iflag %08x", __FUNCTION__, old_termios->c_cflag, old_termios->c_iflag);
 
        if (tport == NULL)
                return;
@@ -947,6 +935,9 @@ static void ti_set_termios(struct usb_serial_port *port,
                            break;
        }
 
+       /* CMSPAR isn't supported by this driver */
+       tty->termios->c_cflag &= ~CMSPAR;
+
        if (cflag & PARENB) {
                if (cflag & PARODD) {
                        config->wFlags |= TI_UART_ENABLE_PARITY_CHECKING;
@@ -989,12 +980,17 @@ static void ti_set_termios(struct usb_serial_port *port,
        }
 
        baud = tty_get_baud_rate(tty);
-       if (!baud) baud = 9600;
+       if (!baud)
+               baud = 9600;
        if (tport->tp_tdev->td_is_3410)
                config->wBaudRate = (__u16)((923077 + baud/2) / baud);
        else
                config->wBaudRate = (__u16)((461538 + baud/2) / baud);
 
+       /* FIXME: Should calculate resulting baud here and report it back */
+       if ((cflag & CBAUD) != B0)
+               tty_encode_baud_rate(tty, baud, baud);
+
        dbg("%s - BaudRate=%d, wBaudRate=%d, wFlags=0x%04X, bDataBits=%d, bParity=%d, bStopBits=%d, cXon=%d, cXoff=%d, bUartMode=%d",
        __FUNCTION__, baud, config->wBaudRate, config->wFlags, config->bDataBits, config->bParity, config->bStopBits, config->cXon, config->cXoff, config->bUartMode);
 
@@ -1497,11 +1493,10 @@ static void ti_drain(struct ti_port *tport, unsigned long timeout, int flush)
        struct ti_device *tdev = tport->tp_tdev;
        struct usb_serial_port *port = tport->tp_port;
        wait_queue_t wait;
-       unsigned long flags;
 
        dbg("%s - port %d", __FUNCTION__, port->number);
 
-       spin_lock_irqsave(&tport->tp_lock, flags);
+       spin_lock_irq(&tport->tp_lock);
 
        /* wait for data to drain from the buffer */
        tdev->td_urb_error = 0;
@@ -1512,11 +1507,11 @@ static void ti_drain(struct ti_port *tport, unsigned long timeout, int flush)
                if (ti_buf_data_avail(tport->tp_write_buf) == 0
                || timeout == 0 || signal_pending(current)
                || tdev->td_urb_error
-               || !usb_get_intfdata(port->serial->interface))  /* disconnect */
+               || port->serial->disconnected)  /* disconnect */
                        break;
-               spin_unlock_irqrestore(&tport->tp_lock, flags);
+               spin_unlock_irq(&tport->tp_lock);
                timeout = schedule_timeout(timeout);
-               spin_lock_irqsave(&tport->tp_lock, flags);
+               spin_lock_irq(&tport->tp_lock);
        }
        set_current_state(TASK_RUNNING);
        remove_wait_queue(&tport->tp_write_wait, &wait);
@@ -1525,19 +1520,23 @@ static void ti_drain(struct ti_port *tport, unsigned long timeout, int flush)
        if (flush)
                ti_buf_clear(tport->tp_write_buf);
 
-       spin_unlock_irqrestore(&tport->tp_lock, flags);
+       spin_unlock_irq(&tport->tp_lock);
 
+       mutex_lock(&port->serial->disc_mutex);
        /* wait for data to drain from the device */
        /* wait for empty tx register, plus 20 ms */
        timeout += jiffies;
        tport->tp_lsr &= ~TI_LSR_TX_EMPTY;
        while ((long)(jiffies - timeout) < 0 && !signal_pending(current)
        && !(tport->tp_lsr&TI_LSR_TX_EMPTY) && !tdev->td_urb_error
-       && usb_get_intfdata(port->serial->interface)) {  /* not disconnected */
+       && !port->serial->disconnected) {
                if (ti_get_lsr(tport))
                        break;
+               mutex_unlock(&port->serial->disc_mutex);
                msleep_interruptible(20);
+               mutex_lock(&port->serial->disc_mutex);
        }
+       mutex_unlock(&port->serial->disc_mutex);
 }
 
 
index 497e29a700ca8dccb20049e0aa0abf983dcbf40c..3ce98e8d7bce6103031af188dc56218693f8ac51 100644 (file)
@@ -225,16 +225,21 @@ static int serial_open (struct tty_struct *tty, struct file * filp)
                        goto bailout_mutex_unlock;
                }
 
+               retval = usb_autopm_get_interface(serial->interface);
+               if (retval)
+                       goto bailout_module_put;
                /* only call the device specific open if this 
                 * is the first time the port is opened */
                retval = serial->type->open(port, filp);
                if (retval)
-                       goto bailout_module_put;
+                       goto bailout_interface_put;
        }
 
        mutex_unlock(&port->mutex);
        return 0;
 
+bailout_interface_put:
+       usb_autopm_put_interface(serial->interface);
 bailout_module_put:
        module_put(serial->type->driver.owner);
 bailout_mutex_unlock:
@@ -264,17 +269,21 @@ static void serial_close(struct tty_struct *tty, struct file * filp)
        }
 
        --port->open_count;
-       if (port->open_count == 0) {
+       if (port->open_count == 0)
                /* only call the device specific close if this 
                 * port is being closed by the last owner */
                port->serial->type->close(port, filp);
 
+       if (port->open_count == (port->console? 1 : 0)) {
                if (port->tty) {
                        if (port->tty->driver_data)
                                port->tty->driver_data = NULL;
                        port->tty = NULL;
                }
+       }
 
+       if (port->open_count == 0) {
+               usb_autopm_put_interface(port->serial->interface);
                module_put(port->serial->type->driver.owner);
        }
 
@@ -625,6 +634,7 @@ static struct usb_serial * create_serial (struct usb_device *dev,
        serial->type = driver;
        serial->interface = interface;
        kref_init(&serial->kref);
+       mutex_init(&serial->disc_mutex);
 
        return serial;
 }
@@ -1080,20 +1090,22 @@ void usb_serial_disconnect(struct usb_interface *interface)
        usb_serial_console_disconnect(serial);
        dbg ("%s", __FUNCTION__);
 
+       mutex_lock(&serial->disc_mutex);
        usb_set_intfdata (interface, NULL);
-       if (serial) {
-               for (i = 0; i < serial->num_ports; ++i) {
-                       port = serial->port[i];
-                       if (port) {
-                               if (port->tty)
-                                       tty_hangup(port->tty);
-                               kill_traffic(port);
-                       }
+       /* must set a flag, to signal subdrivers */
+       serial->disconnected = 1;
+       for (i = 0; i < serial->num_ports; ++i) {
+               port = serial->port[i];
+               if (port) {
+                       if (port->tty)
+                               tty_hangup(port->tty);
+                       kill_traffic(port);
                }
-               /* let the last holder of this object 
-                * cause it to be cleaned up */
-               usb_serial_put(serial);
        }
+       /* let the last holder of this object
+        * cause it to be cleaned up */
+       mutex_unlock(&serial->disc_mutex);
+       usb_serial_put(serial);
        dev_info(dev, "device disconnected\n");
 }
 
@@ -1103,9 +1115,6 @@ int usb_serial_suspend(struct usb_interface *intf, pm_message_t message)
        struct usb_serial_port *port;
        int i, r = 0;
 
-       if (!serial) /* device has been disconnected */
-               return 0;
-
        for (i = 0; i < serial->num_ports; ++i) {
                port = serial->port[i];
                if (port)
@@ -1253,6 +1262,7 @@ static void fixup_generic(struct usb_serial_driver *device)
        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, resume);
 }
 
 int usb_serial_register(struct usb_serial_driver *driver) /* must be called with BKL held */
index 7ee087fed913fbeed34678caebbe15dc8a96567c..22b3f78a388ce0d40486ede8c98f9af41051dc49 100644 (file)
@@ -349,16 +349,20 @@ static void visor_close (struct usb_serial_port *port, struct file * filp)
        usb_kill_urb(port->read_urb);
        usb_kill_urb(port->interrupt_in_urb);
 
-       /* Try to send shutdown message, if the device is gone, this will just fail. */
-       transfer_buffer =  kmalloc (0x12, GFP_KERNEL);
-       if (transfer_buffer) {
-               usb_control_msg (port->serial->dev,
-                                usb_rcvctrlpipe(port->serial->dev, 0),
-                                VISOR_CLOSE_NOTIFICATION, 0xc2,
-                                0x0000, 0x0000, 
-                                transfer_buffer, 0x12, 300);
-               kfree (transfer_buffer);
+       mutex_lock(&port->serial->disc_mutex);
+       if (!port->serial->disconnected) {
+               /* Try to send shutdown message, unless the device is gone */
+               transfer_buffer =  kmalloc (0x12, GFP_KERNEL);
+               if (transfer_buffer) {
+                       usb_control_msg (port->serial->dev,
+                                        usb_rcvctrlpipe(port->serial->dev, 0),
+                                        VISOR_CLOSE_NOTIFICATION, 0xc2,
+                                        0x0000, 0x0000,
+                                        transfer_buffer, 0x12, 300);
+                       kfree (transfer_buffer);
+               }
        }
+       mutex_unlock(&port->serial->disc_mutex);
 
        if (stats)
                dev_info(&port->dev, "Bytes In = %d  Bytes Out = %d\n",
index ee5dd8b5a7131b23846d153586686f1163fa7dec..38726ef3132b70d83121d8bdaa894b47990f0843 100644 (file)
@@ -610,8 +610,7 @@ static int whiteheat_open (struct usb_serial_port *port, struct file *filp)
        if (retval)
                goto exit;
 
-       if (port->tty)
-               port->tty->low_latency = 1;
+       port->tty->low_latency = 1;
 
        /* send an open port command */
        retval = firm_open(port);
@@ -659,11 +658,14 @@ static void whiteheat_close(struct usb_serial_port *port, struct file * filp)
        struct list_head *tmp2;
 
        dbg("%s - port %d", __FUNCTION__, port->number);
-       
+
+       mutex_lock(&port->serial->disc_mutex);
        /* filp is NULL when called from usb_serial_disconnect */
-       if (filp && (tty_hung_up_p(filp))) {
+       if ((filp && (tty_hung_up_p(filp))) || port->serial->disconnected) {
+               mutex_unlock(&port->serial->disc_mutex);
                return;
        }
+       mutex_unlock(&port->serial->disc_mutex);
 
        port->tty->closing = 1;
 
index ee5b42aa53633b159b259d95bbf208e866a48492..187dd1e01093584c47d9da7f7c22f0f596a37c3c 100644 (file)
@@ -66,7 +66,8 @@ int usb_stor_ucr61s2b_init(struct us_data *us)
 {
        struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap*) us->iobuf;
        struct bulk_cs_wrap *bcs = (struct bulk_cs_wrap*) us->iobuf;
-       int res, partial;
+       int res;
+       unsigned int partial;
        static char init_string[] = "\xec\x0a\x06\x00$PCCHIPS";
 
        US_DEBUGP("Sending UCR-61S2B initialization packet...\n");
index 0db488624ab1c4983cf481ec637e29a9650bc586..2ae1e8673b195297aeea17e7f9333ba4fecd8c42 100644 (file)
@@ -48,7 +48,6 @@
 #include <linux/errno.h>
 #include <linux/slab.h>
 #include <linux/hdreg.h>
-#include <linux/ide.h>
 #include <linux/scatterlist.h>
 
 #include <scsi/scsi.h>
 #define REG_STATUS             0x80
 #define REG_COMMAND            0x80
 
+/* ATA registers offset definitions */
+#define ATA_REG_ERROR_OFFSET           1
+#define ATA_REG_LCYL_OFFSET            4
+#define ATA_REG_HCYL_OFFSET            5
+#define ATA_REG_STATUS_OFFSET          7
+
 /* ATA error definitions not in <linux/hdreg.h> */
 #define ATA_ERROR_MEDIA_CHANGE         0x20
 
@@ -360,7 +365,7 @@ static void isd200_build_sense(struct us_data *us, struct scsi_cmnd *srb)
 {
        struct isd200_info *info = (struct isd200_info *)us->extra;
        struct sense_data *buf = (struct sense_data *) &srb->sense_buffer[0];
-       unsigned char error = info->ATARegs[IDE_ERROR_OFFSET];
+       unsigned char error = info->ATARegs[ATA_REG_ERROR_OFFSET];
 
        if(error & ATA_ERROR_MEDIA_CHANGE) {
                buf->ErrorCode = 0x70 | SENSE_ERRCODE_VALID;
@@ -549,8 +554,8 @@ static int isd200_read_regs( struct us_data *us )
                retStatus = ISD200_ERROR;
        } else {
                memcpy(info->ATARegs, info->RegsBuf, sizeof(info->ATARegs));
-               US_DEBUGP("   Got ATA Register[IDE_ERROR_OFFSET] = 0x%x\n", 
-                         info->ATARegs[IDE_ERROR_OFFSET]);
+               US_DEBUGP("   Got ATA Register[ATA_REG_ERROR_OFFSET] = 0x%x\n",
+                         info->ATARegs[ATA_REG_ERROR_OFFSET]);
        }
 
        return retStatus;
@@ -892,7 +897,7 @@ static int isd200_try_enum(struct us_data *us, unsigned char master_slave,
                        break;
 
                if (!detect) {
-                       if (regs[IDE_STATUS_OFFSET] & BUSY_STAT ) {
+                       if (regs[ATA_REG_STATUS_OFFSET] & BUSY_STAT) {
                                US_DEBUGP("   %s status is still BSY, try again...\n",mstr);
                        } else {
                                US_DEBUGP("   %s status !BSY, continue with next operation\n",mstr);
@@ -902,12 +907,12 @@ static int isd200_try_enum(struct us_data *us, unsigned char master_slave,
                /* check for BUSY_STAT and */
                /* WRERR_STAT (workaround ATA Zip drive) and */ 
                /* ERR_STAT (workaround for Archos CD-ROM) */
-               else if (regs[IDE_STATUS_OFFSET] & 
+               else if (regs[ATA_REG_STATUS_OFFSET] &
                         (BUSY_STAT | WRERR_STAT | ERR_STAT )) {
                        US_DEBUGP("   Status indicates it is not ready, try again...\n");
                }
                /* check for DRDY, ATA devices set DRDY after SRST */
-               else if (regs[IDE_STATUS_OFFSET] & READY_STAT) {
+               else if (regs[ATA_REG_STATUS_OFFSET] & READY_STAT) {
                        US_DEBUGP("   Identified ATA device\n");
                        info->DeviceFlags |= DF_ATA_DEVICE;
                        info->DeviceHead = master_slave;
@@ -916,8 +921,8 @@ static int isd200_try_enum(struct us_data *us, unsigned char master_slave,
                /* check Cylinder High/Low to
                   determine if it is an ATAPI device
                */
-               else if ((regs[IDE_HCYL_OFFSET] == 0xEB) &&
-                        (regs[IDE_LCYL_OFFSET] == 0x14)) {
+               else if (regs[ATA_REG_HCYL_OFFSET] == 0xEB &&
+                        regs[ATA_REG_LCYL_OFFSET] == 0x14) {
                        /* It seems that the RICOH 
                           MP6200A CD/RW drive will 
                           report itself okay as a
@@ -1001,12 +1006,6 @@ static int isd200_manual_enum(struct us_data *us)
        return(retStatus);
 }
 
-/*
- *     We are the last non IDE user of the legacy IDE ident structures
- *     and we thus want to keep a private copy of this function so the
- *     driver can be used without the obsolete drivers/ide layer
- */
-
 static void isd200_fix_driveid (struct hd_driveid *id)
 {
 #ifndef __LITTLE_ENDIAN
index 6d6108b3993b3d33aea67adbaf6479a9e8deffa0..fe12737e0e2be566becbf4133d401a5ea4fba8dd 100644 (file)
@@ -86,6 +86,14 @@ UNUSUAL_DEV(  0x03f0, 0x0307, 0x0001, 0x0001,
                US_SC_8070, US_PR_USBAT, init_usbat_cd, 0),
 #endif
 
+/* Reported by Grant Grundler <grundler@parisc-linux.org>
+ * HP r707 camera in "Disk" mode with 2.00.23 or 2.00.24 firmware.
+ */
+UNUSUAL_DEV(  0x03f0, 0x4002, 0x0001, 0x0001,
+               "HP",
+               "PhotoSmart R707",
+               US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_CAPACITY),
+
 /* Reported by Sebastian Kapfer <sebastian_kapfer@gmx.net>
  * and Olaf Hering <olh@suse.de> (different bcd's, same vendor/product)
  * for USB floppies that need the SINGLE_LUN enforcement.
index 83ee3e75386cf7a4d1676a60d30b3f621d580989..675abdafc2d8d047741ed3b8fdf2c0291343440c 100644 (file)
@@ -2561,7 +2561,7 @@ static void radeon_set_suspend(struct radeonfb_info *rinfo, int suspend)
                        pci_read_config_dword(rinfo->pdev, i * 4,
                                              &rinfo->cfg_save[i]);
 
-               /* Switch PCI power managment to D2. */
+               /* Switch PCI power management to D2. */
                pci_disable_device(rinfo->pdev);
                for (;;) {
                        pci_read_config_word(
index e23324d10be269cf60767e2a486de897e39edb37..9704b73135f54588e08c1c57075bf61491c67dd7 100644 (file)
@@ -1156,7 +1156,7 @@ static struct fb_ops cyblafb_ops __devinitdata = {
 // need altered timings to display correctly. So I decided that it is much
 // better to provide a limited optimized set of modes plus the option of
 // using the mode in effect at startup time (might be selected using the
-// vga=??? paramter). After that the user might use fbset to select any
+// vga=??? parameter). After that the user might use fbset to select any
 // mode he likes, check_var will not try to alter geometry parameters as
 // it would be necessary otherwise.
 //
index 2fe3f7def5305ed5c422c0bed9db2a558bf591b4..8367961779420c275b0b5e2f0a693b2f702fa73c 100644 (file)
 
 #define FIXED_MODE(d) ((d)->fixed_mode)
 
-/*** Driver paramters ***/
+/*** Driver parameters ***/
 
 #define RINGBUFFER_SIZE                KB(64)
 #define HW_CURSOR_SIZE         KB(4)
index 9085188d815e0bd1e301523351f71eed38bb25cb..fb19ed4992dbc670d9f89c017995bd8c8faa9d5d 100644 (file)
@@ -312,7 +312,7 @@ static irqreturn_t lcdc_irq_handler(int irq, void *dev_id)
 /*
  * Change to a new video mode. We defer this to a later time to avoid any
  * flicker and not to mess up the current LCD DMA context. For this we disable
- * the LCD controler, which will generate a DONE irq after the last frame has
+ * the LCD controller, which will generate a DONE irq after the last frame has
  * been transferred. Then it'll be safe to reconfigure both the LCD controller
  * as well as the LCD DMA.
  */
index d53bf6945f0c9b427df8a07dc0c3add81fe48d8d..9b05da6268f7e8cfc72e6f07afb4b3460416dcdd 100644 (file)
 #include <linux/spinlock.h>
 
 #ifdef CONFIG_COMPAT
-#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,10)
-#include <linux/ioctl32.h>
-#define SIS_OLD_CONFIG_COMPAT
-#else
 #define SIS_NEW_CONFIG_COMPAT
-#endif
 #endif /* CONFIG_COMPAT */
 
 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8)
@@ -607,9 +602,6 @@ struct sis_video_info {
        int             haveXGIROM;
        int             registered;
        int             warncount;
-#ifdef SIS_OLD_CONFIG_COMPAT
-       int             ioctl32registered;
-#endif
 
        int             sisvga_engine;
        int             hwcursor_size;
index 37bd24b8d83b2568d516a16cd58e196e4e2e59f7..93ae747440cbb97b6f20d87642fbaa901655b90e 100644 (file)
@@ -5805,9 +5805,6 @@ sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        ivideo->pcifunc = PCI_FUNC(pdev->devfn);
        ivideo->subsysvendor = pdev->subsystem_vendor;
        ivideo->subsysdevice = pdev->subsystem_device;
-#ifdef SIS_OLD_CONFIG_COMPAT
-       ivideo->ioctl32registered = 0;
-#endif
 
 #ifndef MODULE
        if(sisfb_mode_idx == -1) {
@@ -6420,30 +6417,6 @@ error_3: vfree(ivideo->bios_abase);
                ivideo->next = card_list;
                card_list = ivideo;
 
-#ifdef SIS_OLD_CONFIG_COMPAT
-               {
-               int ret;
-               /* Our ioctls are all "32/64bit compatible" */
-               ret =  register_ioctl32_conversion(FBIO_ALLOC,             NULL);
-               ret |= register_ioctl32_conversion(FBIO_FREE,              NULL);
-               ret |= register_ioctl32_conversion(FBIOGET_VBLANK,         NULL);
-               ret |= register_ioctl32_conversion(SISFB_GET_INFO_SIZE,    NULL);
-               ret |= register_ioctl32_conversion(SISFB_GET_INFO,         NULL);
-               ret |= register_ioctl32_conversion(SISFB_GET_TVPOSOFFSET,  NULL);
-               ret |= register_ioctl32_conversion(SISFB_SET_TVPOSOFFSET,  NULL);
-               ret |= register_ioctl32_conversion(SISFB_SET_LOCK,         NULL);
-               ret |= register_ioctl32_conversion(SISFB_GET_VBRSTATUS,    NULL);
-               ret |= register_ioctl32_conversion(SISFB_GET_AUTOMAXIMIZE, NULL);
-               ret |= register_ioctl32_conversion(SISFB_SET_AUTOMAXIMIZE, NULL);
-               ret |= register_ioctl32_conversion(SISFB_COMMAND,          NULL);
-               if(ret)
-                       printk(KERN_ERR
-                               "sisfb: Error registering ioctl32 translations\n");
-               else
-                       ivideo->ioctl32registered = 1;
-               }
-#endif
-
                printk(KERN_INFO "sisfb: 2D acceleration is %s, y-panning %s\n",
                        ivideo->sisfb_accel ? "enabled" : "disabled",
                        ivideo->sisfb_ypan  ?
@@ -6473,27 +6446,6 @@ static void __devexit sisfb_remove(struct pci_dev *pdev)
        int                     registered = ivideo->registered;
        int                     modechanged = ivideo->modechanged;
 
-#ifdef SIS_OLD_CONFIG_COMPAT
-       if(ivideo->ioctl32registered) {
-               int ret;
-               ret =  unregister_ioctl32_conversion(FBIO_ALLOC);
-               ret |= unregister_ioctl32_conversion(FBIO_FREE);
-               ret |= unregister_ioctl32_conversion(FBIOGET_VBLANK);
-               ret |= unregister_ioctl32_conversion(SISFB_GET_INFO_SIZE);
-               ret |= unregister_ioctl32_conversion(SISFB_GET_INFO);
-               ret |= unregister_ioctl32_conversion(SISFB_GET_TVPOSOFFSET);
-               ret |= unregister_ioctl32_conversion(SISFB_SET_TVPOSOFFSET);
-               ret |= unregister_ioctl32_conversion(SISFB_SET_LOCK);
-               ret |= unregister_ioctl32_conversion(SISFB_GET_VBRSTATUS);
-               ret |= unregister_ioctl32_conversion(SISFB_GET_AUTOMAXIMIZE);
-               ret |= unregister_ioctl32_conversion(SISFB_SET_AUTOMAXIMIZE);
-               ret |= unregister_ioctl32_conversion(SISFB_COMMAND);
-               if(ret)
-                       printk(KERN_ERR
-                            "sisfb: Error unregistering ioctl32 translations\n");
-       }
-#endif
-
        /* Unmap */
        iounmap(ivideo->mmio_vbase);
        iounmap(ivideo->video_vbase);
index 1be95a68d69678d4ba05400bedd506467826cb99..58f200c69be31378585fa34961439c584ef3a441 100644 (file)
@@ -48,7 +48,7 @@ enum sm501_controller {
        HEAD_PANEL      = 1,
 };
 
-/* SM501 memory adress */
+/* SM501 memory address */
 struct sm501_mem {
        unsigned long    size;
        unsigned long    sm_addr;
index 9e33fc4da875010f11b95e1512f57ba69c593e01..3dd6294d10b64066b1660a33542ce2c726c2aa84 100644 (file)
@@ -1,8 +1,35 @@
 # Virtio always gets selected by whoever wants it.
 config VIRTIO
-       bool
+       tristate
 
 # Similarly the virtio ring implementation.
 config VIRTIO_RING
-       bool
+       tristate
        depends on VIRTIO
+
+config VIRTIO_PCI
+       tristate "PCI driver for virtio devices (EXPERIMENTAL)"
+       depends on PCI && EXPERIMENTAL
+       select VIRTIO
+       select VIRTIO_RING
+       ---help---
+         This drivers provides support for virtio based paravirtual device
+         drivers over PCI.  This requires that your VMM has appropriate PCI
+         virtio backends.  Most QEMU based VMMs should support these devices
+         (like KVM or Xen).
+
+         Currently, the ABI is not considered stable so there is no guarantee
+         that this version of the driver will work with your VMM.
+
+         If unsure, say M.
+
+config VIRTIO_BALLOON
+       tristate "Virtio balloon driver (EXPERIMENTAL)"
+       select VIRTIO
+       select VIRTIO_RING
+       ---help---
+        This driver supports increasing and decreasing the amount
+        of memory within a KVM guest.
+
+        If unsure, say M.
+
index f70e40971dd9bc93221aff170949f6d6674e1af2..6738c446c199e5af4ebfdb655166c1d7dc2fa065 100644 (file)
@@ -1,2 +1,4 @@
 obj-$(CONFIG_VIRTIO) += virtio.o
 obj-$(CONFIG_VIRTIO_RING) += virtio_ring.o
+obj-$(CONFIG_VIRTIO_PCI) += virtio_pci.o
+obj-$(CONFIG_VIRTIO_BALLOON) += virtio_balloon.o
index 69d7ea02cd489bac96c3e3051678b669547e0211..b535483bc556f5f153eb434583c8dc6593377164 100644 (file)
@@ -102,9 +102,13 @@ static int virtio_dev_remove(struct device *_d)
        struct virtio_driver *drv = container_of(dev->dev.driver,
                                                 struct virtio_driver, driver);
 
-       dev->config->set_status(dev, dev->config->get_status(dev)
-                               & ~VIRTIO_CONFIG_S_DRIVER);
        drv->remove(dev);
+
+       /* Driver should have reset device. */
+       BUG_ON(dev->config->get_status(dev));
+
+       /* Acknowledge the device's existence again. */
+       add_status(dev, VIRTIO_CONFIG_S_ACKNOWLEDGE);
        return 0;
 }
 
@@ -130,6 +134,10 @@ int register_virtio_device(struct virtio_device *dev)
        dev->dev.bus = &virtio_bus;
        sprintf(dev->dev.bus_id, "%u", dev->index);
 
+       /* We always start by resetting the device, in case a previous
+        * driver messed it up.  This also tests that code path a little. */
+       dev->config->reset(dev);
+
        /* Acknowledge that we've seen the device. */
        add_status(dev, VIRTIO_CONFIG_S_ACKNOWLEDGE);
 
@@ -148,55 +156,18 @@ void unregister_virtio_device(struct virtio_device *dev)
 }
 EXPORT_SYMBOL_GPL(unregister_virtio_device);
 
-int __virtio_config_val(struct virtio_device *vdev,
-                       u8 type, void *val, size_t size)
-{
-       void *token;
-       unsigned int len;
-
-       token = vdev->config->find(vdev, type, &len);
-       if (!token)
-               return -ENOENT;
-
-       if (len != size)
-               return -EIO;
-
-       vdev->config->get(vdev, token, val, size);
-       return 0;
-}
-EXPORT_SYMBOL_GPL(__virtio_config_val);
-
-int virtio_use_bit(struct virtio_device *vdev,
-                  void *token, unsigned int len, unsigned int bitnum)
-{
-       unsigned long bits[16];
-
-       /* This makes it convenient to pass-through find() results. */
-       if (!token)
-               return 0;
-
-       /* bit not in range of this bitfield? */
-       if (bitnum * 8 >= len / 2)
-               return 0;
-
-       /* Giant feature bitfields are silly. */
-       BUG_ON(len > sizeof(bits));
-       vdev->config->get(vdev, token, bits, len);
-
-       if (!test_bit(bitnum, bits))
-               return 0;
-
-       /* Set acknowledge bit, and write it back. */
-       set_bit(bitnum + len * 8 / 2, bits);
-       vdev->config->set(vdev, token, bits, len);
-       return 1;
-}
-EXPORT_SYMBOL_GPL(virtio_use_bit);
-
 static int virtio_init(void)
 {
        if (bus_register(&virtio_bus) != 0)
                panic("virtio bus registration failed");
        return 0;
 }
+
+static void __exit virtio_exit(void)
+{
+       bus_unregister(&virtio_bus);
+}
 core_initcall(virtio_init);
+module_exit(virtio_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c
new file mode 100644 (file)
index 0000000..622aece
--- /dev/null
@@ -0,0 +1,284 @@
+/* Virtio balloon implementation, inspired by Dor Loar and Marcelo
+ * Tosatti's implementations.
+ *
+ *  Copyright 2008 Rusty Russell IBM Corporation
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  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
+ */
+//#define DEBUG
+#include <linux/virtio.h>
+#include <linux/virtio_balloon.h>
+#include <linux/swap.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
+
+struct virtio_balloon
+{
+       struct virtio_device *vdev;
+       struct virtqueue *inflate_vq, *deflate_vq;
+
+       /* Where the ballooning thread waits for config to change. */
+       wait_queue_head_t config_change;
+
+       /* The thread servicing the balloon. */
+       struct task_struct *thread;
+
+       /* Waiting for host to ack the pages we released. */
+       struct completion acked;
+
+       /* Do we have to tell Host *before* we reuse pages? */
+       bool tell_host_first;
+
+       /* The pages we've told the Host we're not using. */
+       unsigned int num_pages;
+       struct list_head pages;
+
+       /* The array of pfns we tell the Host about. */
+       unsigned int num_pfns;
+       u32 pfns[256];
+};
+
+static struct virtio_device_id id_table[] = {
+       { VIRTIO_ID_BALLOON, VIRTIO_DEV_ANY_ID },
+       { 0 },
+};
+
+static void balloon_ack(struct virtqueue *vq)
+{
+       struct virtio_balloon *vb;
+       unsigned int len;
+
+       vb = vq->vq_ops->get_buf(vq, &len);
+       if (vb)
+               complete(&vb->acked);
+}
+
+static void tell_host(struct virtio_balloon *vb, struct virtqueue *vq)
+{
+       struct scatterlist sg;
+
+       sg_init_one(&sg, vb->pfns, sizeof(vb->pfns[0]) * vb->num_pfns);
+
+       init_completion(&vb->acked);
+
+       /* We should always be able to add one buffer to an empty queue. */
+       if (vq->vq_ops->add_buf(vq, &sg, 1, 0, vb) != 0)
+               BUG();
+       vq->vq_ops->kick(vq);
+
+       /* When host has read buffer, this completes via balloon_ack */
+       wait_for_completion(&vb->acked);
+}
+
+static void fill_balloon(struct virtio_balloon *vb, size_t num)
+{
+       /* We can only do one array worth at a time. */
+       num = min(num, ARRAY_SIZE(vb->pfns));
+
+       for (vb->num_pfns = 0; vb->num_pfns < num; vb->num_pfns++) {
+               struct page *page = alloc_page(GFP_HIGHUSER | __GFP_NORETRY);
+               if (!page) {
+                       if (printk_ratelimit())
+                               dev_printk(KERN_INFO, &vb->vdev->dev,
+                                          "Out of puff! Can't get %zu pages\n",
+                                          num);
+                       /* Sleep for at least 1/5 of a second before retry. */
+                       msleep(200);
+                       break;
+               }
+               vb->pfns[vb->num_pfns] = page_to_pfn(page);
+               totalram_pages--;
+               vb->num_pages++;
+               list_add(&page->lru, &vb->pages);
+       }
+
+       /* Didn't get any?  Oh well. */
+       if (vb->num_pfns == 0)
+               return;
+
+       tell_host(vb, vb->inflate_vq);
+}
+
+static void release_pages_by_pfn(const u32 pfns[], unsigned int num)
+{
+       unsigned int i;
+
+       for (i = 0; i < num; i++) {
+               __free_page(pfn_to_page(pfns[i]));
+               totalram_pages++;
+       }
+}
+
+static void leak_balloon(struct virtio_balloon *vb, size_t num)
+{
+       struct page *page;
+
+       /* We can only do one array worth at a time. */
+       num = min(num, ARRAY_SIZE(vb->pfns));
+
+       for (vb->num_pfns = 0; vb->num_pfns < num; vb->num_pfns++) {
+               page = list_first_entry(&vb->pages, struct page, lru);
+               list_del(&page->lru);
+               vb->pfns[vb->num_pfns] = page_to_pfn(page);
+               vb->num_pages--;
+       }
+
+       if (vb->tell_host_first) {
+               tell_host(vb, vb->deflate_vq);
+               release_pages_by_pfn(vb->pfns, vb->num_pfns);
+       } else {
+               release_pages_by_pfn(vb->pfns, vb->num_pfns);
+               tell_host(vb, vb->deflate_vq);
+       }
+}
+
+static void virtballoon_changed(struct virtio_device *vdev)
+{
+       struct virtio_balloon *vb = vdev->priv;
+
+       wake_up(&vb->config_change);
+}
+
+static inline int towards_target(struct virtio_balloon *vb)
+{
+       u32 v;
+       __virtio_config_val(vb->vdev,
+                           offsetof(struct virtio_balloon_config, num_pages),
+                           &v);
+       return v - vb->num_pages;
+}
+
+static void update_balloon_size(struct virtio_balloon *vb)
+{
+       __le32 actual = cpu_to_le32(vb->num_pages);
+
+       vb->vdev->config->set(vb->vdev,
+                             offsetof(struct virtio_balloon_config, actual),
+                             &actual, sizeof(actual));
+}
+
+static int balloon(void *_vballoon)
+{
+       struct virtio_balloon *vb = _vballoon;
+
+       set_freezable();
+       while (!kthread_should_stop()) {
+               int diff;
+
+               try_to_freeze();
+               wait_event_interruptible(vb->config_change,
+                                        (diff = towards_target(vb)) != 0
+                                        || kthread_should_stop());
+               if (diff > 0)
+                       fill_balloon(vb, diff);
+               else if (diff < 0)
+                       leak_balloon(vb, -diff);
+               update_balloon_size(vb);
+       }
+       return 0;
+}
+
+static int virtballoon_probe(struct virtio_device *vdev)
+{
+       struct virtio_balloon *vb;
+       int err;
+
+       vdev->priv = vb = kmalloc(sizeof(*vb), GFP_KERNEL);
+       if (!vb) {
+               err = -ENOMEM;
+               goto out;
+       }
+
+       INIT_LIST_HEAD(&vb->pages);
+       vb->num_pages = 0;
+       init_waitqueue_head(&vb->config_change);
+       vb->vdev = vdev;
+
+       /* We expect two virtqueues. */
+       vb->inflate_vq = vdev->config->find_vq(vdev, 0, balloon_ack);
+       if (IS_ERR(vb->inflate_vq)) {
+               err = PTR_ERR(vb->inflate_vq);
+               goto out_free_vb;
+       }
+
+       vb->deflate_vq = vdev->config->find_vq(vdev, 1, balloon_ack);
+       if (IS_ERR(vb->deflate_vq)) {
+               err = PTR_ERR(vb->deflate_vq);
+               goto out_del_inflate_vq;
+       }
+
+       vb->thread = kthread_run(balloon, vb, "vballoon");
+       if (IS_ERR(vb->thread)) {
+               err = PTR_ERR(vb->thread);
+               goto out_del_deflate_vq;
+       }
+
+       vb->tell_host_first
+               = vdev->config->feature(vdev, VIRTIO_BALLOON_F_MUST_TELL_HOST);
+
+       return 0;
+
+out_del_deflate_vq:
+       vdev->config->del_vq(vb->deflate_vq);
+out_del_inflate_vq:
+       vdev->config->del_vq(vb->inflate_vq);
+out_free_vb:
+       kfree(vb);
+out:
+       return err;
+}
+
+static void virtballoon_remove(struct virtio_device *vdev)
+{
+       struct virtio_balloon *vb = vdev->priv;
+
+       kthread_stop(vb->thread);
+
+       /* There might be pages left in the balloon: free them. */
+       while (vb->num_pages)
+               leak_balloon(vb, vb->num_pages);
+
+       /* Now we reset the device so we can clean up the queues. */
+       vdev->config->reset(vdev);
+
+       vdev->config->del_vq(vb->deflate_vq);
+       vdev->config->del_vq(vb->inflate_vq);
+       kfree(vb);
+}
+
+static struct virtio_driver virtio_balloon = {
+       .driver.name =  KBUILD_MODNAME,
+       .driver.owner = THIS_MODULE,
+       .id_table =     id_table,
+       .probe =        virtballoon_probe,
+       .remove =       __devexit_p(virtballoon_remove),
+       .config_changed = virtballoon_changed,
+};
+
+static int __init init(void)
+{
+       return register_virtio_driver(&virtio_balloon);
+}
+
+static void __exit fini(void)
+{
+       unregister_virtio_driver(&virtio_balloon);
+}
+module_init(init);
+module_exit(fini);
+
+MODULE_DEVICE_TABLE(virtio, id_table);
+MODULE_DESCRIPTION("Virtio balloon driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/virtio/virtio_pci.c b/drivers/virtio/virtio_pci.c
new file mode 100644 (file)
index 0000000..26f787d
--- /dev/null
@@ -0,0 +1,446 @@
+/*
+ * Virtio PCI driver
+ *
+ * This module allows virtio devices to be used over a virtual PCI device.
+ * This can be used with QEMU based VMMs like KVM or Xen.
+ *
+ * Copyright IBM Corp. 2007
+ *
+ * Authors:
+ *  Anthony Liguori  <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/virtio.h>
+#include <linux/virtio_config.h>
+#include <linux/virtio_ring.h>
+#include <linux/virtio_pci.h>
+#include <linux/highmem.h>
+#include <linux/spinlock.h>
+
+MODULE_AUTHOR("Anthony Liguori <aliguori@us.ibm.com>");
+MODULE_DESCRIPTION("virtio-pci");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("1");
+
+/* Our device structure */
+struct virtio_pci_device
+{
+       struct virtio_device vdev;
+       struct pci_dev *pci_dev;
+
+       /* the IO mapping for the PCI config space */
+       void *ioaddr;
+
+       /* a list of queues so we can dispatch IRQs */
+       spinlock_t lock;
+       struct list_head virtqueues;
+};
+
+struct virtio_pci_vq_info
+{
+       /* the actual virtqueue */
+       struct virtqueue *vq;
+
+       /* the number of entries in the queue */
+       int num;
+
+       /* the index of the queue */
+       int queue_index;
+
+       /* the virtual address of the ring queue */
+       void *queue;
+
+       /* the list node for the virtqueues list */
+       struct list_head node;
+};
+
+/* Qumranet donated their vendor ID for devices 0x1000 thru 0x10FF. */
+static struct pci_device_id virtio_pci_id_table[] = {
+       { 0x1af4, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+       { 0 },
+};
+
+MODULE_DEVICE_TABLE(pci, virtio_pci_id_table);
+
+/* A PCI device has it's own struct device and so does a virtio device so
+ * we create a place for the virtio devices to show up in sysfs.  I think it
+ * would make more sense for virtio to not insist on having it's own device. */
+static struct device virtio_pci_root = {
+       .parent         = NULL,
+       .bus_id         = "virtio-pci",
+};
+
+/* Unique numbering for devices under the kvm root */
+static unsigned int dev_index;
+
+/* Convert a generic virtio device to our structure */
+static struct virtio_pci_device *to_vp_device(struct virtio_device *vdev)
+{
+       return container_of(vdev, struct virtio_pci_device, vdev);
+}
+
+/* virtio config->feature() implementation */
+static bool vp_feature(struct virtio_device *vdev, unsigned bit)
+{
+       struct virtio_pci_device *vp_dev = to_vp_device(vdev);
+       u32 mask;
+
+       /* Since this function is supposed to have the side effect of
+        * enabling a queried feature, we simulate that by doing a read
+        * from the host feature bitmask and then writing to the guest
+        * feature bitmask */
+       mask = ioread32(vp_dev->ioaddr + VIRTIO_PCI_HOST_FEATURES);
+       if (mask & (1 << bit)) {
+               mask |= (1 << bit);
+               iowrite32(mask, vp_dev->ioaddr + VIRTIO_PCI_GUEST_FEATURES);
+       }
+
+       return !!(mask & (1 << bit));
+}
+
+/* virtio config->get() implementation */
+static void vp_get(struct virtio_device *vdev, unsigned offset,
+                  void *buf, unsigned len)
+{
+       struct virtio_pci_device *vp_dev = to_vp_device(vdev);
+       void *ioaddr = vp_dev->ioaddr + VIRTIO_PCI_CONFIG + offset;
+       u8 *ptr = buf;
+       int i;
+
+       for (i = 0; i < len; i++)
+               ptr[i] = ioread8(ioaddr + i);
+}
+
+/* the config->set() implementation.  it's symmetric to the config->get()
+ * implementation */
+static void vp_set(struct virtio_device *vdev, unsigned offset,
+                  const void *buf, unsigned len)
+{
+       struct virtio_pci_device *vp_dev = to_vp_device(vdev);
+       void *ioaddr = vp_dev->ioaddr + VIRTIO_PCI_CONFIG + offset;
+       const u8 *ptr = buf;
+       int i;
+
+       for (i = 0; i < len; i++)
+               iowrite8(ptr[i], ioaddr + i);
+}
+
+/* config->{get,set}_status() implementations */
+static u8 vp_get_status(struct virtio_device *vdev)
+{
+       struct virtio_pci_device *vp_dev = to_vp_device(vdev);
+       return ioread8(vp_dev->ioaddr + VIRTIO_PCI_STATUS);
+}
+
+static void vp_set_status(struct virtio_device *vdev, u8 status)
+{
+       struct virtio_pci_device *vp_dev = to_vp_device(vdev);
+       /* We should never be setting status to 0. */
+       BUG_ON(status == 0);
+       return iowrite8(status, vp_dev->ioaddr + VIRTIO_PCI_STATUS);
+}
+
+static void vp_reset(struct virtio_device *vdev)
+{
+       struct virtio_pci_device *vp_dev = to_vp_device(vdev);
+       /* 0 status means a reset. */
+       return iowrite8(0, vp_dev->ioaddr + VIRTIO_PCI_STATUS);
+}
+
+/* the notify function used when creating a virt queue */
+static void vp_notify(struct virtqueue *vq)
+{
+       struct virtio_pci_device *vp_dev = to_vp_device(vq->vdev);
+       struct virtio_pci_vq_info *info = vq->priv;
+
+       /* we write the queue's selector into the notification register to
+        * signal the other end */
+       iowrite16(info->queue_index, vp_dev->ioaddr + VIRTIO_PCI_QUEUE_NOTIFY);
+}
+
+/* A small wrapper to also acknowledge the interrupt when it's handled.
+ * I really need an EIO hook for the vring so I can ack the interrupt once we
+ * know that we'll be handling the IRQ but before we invoke the callback since
+ * the callback may notify the host which results in the host attempting to
+ * raise an interrupt that we would then mask once we acknowledged the
+ * interrupt. */
+static irqreturn_t vp_interrupt(int irq, void *opaque)
+{
+       struct virtio_pci_device *vp_dev = opaque;
+       struct virtio_pci_vq_info *info;
+       irqreturn_t ret = IRQ_NONE;
+       u8 isr;
+
+       /* reading the ISR has the effect of also clearing it so it's very
+        * important to save off the value. */
+       isr = ioread8(vp_dev->ioaddr + VIRTIO_PCI_ISR);
+
+       /* It's definitely not us if the ISR was not high */
+       if (!isr)
+               return IRQ_NONE;
+
+       /* Configuration change?  Tell driver if it wants to know. */
+       if (isr & VIRTIO_PCI_ISR_CONFIG) {
+               struct virtio_driver *drv;
+               drv = container_of(vp_dev->vdev.dev.driver,
+                                  struct virtio_driver, driver);
+
+               if (drv->config_changed)
+                       drv->config_changed(&vp_dev->vdev);
+       }
+
+       spin_lock(&vp_dev->lock);
+       list_for_each_entry(info, &vp_dev->virtqueues, node) {
+               if (vring_interrupt(irq, info->vq) == IRQ_HANDLED)
+                       ret = IRQ_HANDLED;
+       }
+       spin_unlock(&vp_dev->lock);
+
+       return ret;
+}
+
+/* the config->find_vq() implementation */
+static struct virtqueue *vp_find_vq(struct virtio_device *vdev, unsigned index,
+                                   void (*callback)(struct virtqueue *vq))
+{
+       struct virtio_pci_device *vp_dev = to_vp_device(vdev);
+       struct virtio_pci_vq_info *info;
+       struct virtqueue *vq;
+       u16 num;
+       int err;
+
+       /* Select the queue we're interested in */
+       iowrite16(index, vp_dev->ioaddr + VIRTIO_PCI_QUEUE_SEL);
+
+       /* Check if queue is either not available or already active. */
+       num = ioread16(vp_dev->ioaddr + VIRTIO_PCI_QUEUE_NUM);
+       if (!num || ioread32(vp_dev->ioaddr + VIRTIO_PCI_QUEUE_PFN))
+               return ERR_PTR(-ENOENT);
+
+       /* allocate and fill out our structure the represents an active
+        * queue */
+       info = kmalloc(sizeof(struct virtio_pci_vq_info), GFP_KERNEL);
+       if (!info)
+               return ERR_PTR(-ENOMEM);
+
+       info->queue_index = index;
+       info->num = num;
+
+       info->queue = kzalloc(PAGE_ALIGN(vring_size(num,PAGE_SIZE)), GFP_KERNEL);
+       if (info->queue == NULL) {
+               err = -ENOMEM;
+               goto out_info;
+       }
+
+       /* activate the queue */
+       iowrite32(virt_to_phys(info->queue) >> PAGE_SHIFT,
+                 vp_dev->ioaddr + VIRTIO_PCI_QUEUE_PFN);
+
+       /* create the vring */
+       vq = vring_new_virtqueue(info->num, vdev, info->queue,
+                                vp_notify, callback);
+       if (!vq) {
+               err = -ENOMEM;
+               goto out_activate_queue;
+       }
+
+       vq->priv = info;
+       info->vq = vq;
+
+       spin_lock(&vp_dev->lock);
+       list_add(&info->node, &vp_dev->virtqueues);
+       spin_unlock(&vp_dev->lock);
+
+       return vq;
+
+out_activate_queue:
+       iowrite32(0, vp_dev->ioaddr + VIRTIO_PCI_QUEUE_PFN);
+       kfree(info->queue);
+out_info:
+       kfree(info);
+       return ERR_PTR(err);
+}
+
+/* the config->del_vq() implementation */
+static void vp_del_vq(struct virtqueue *vq)
+{
+       struct virtio_pci_device *vp_dev = to_vp_device(vq->vdev);
+       struct virtio_pci_vq_info *info = vq->priv;
+
+       spin_lock(&vp_dev->lock);
+       list_del(&info->node);
+       spin_unlock(&vp_dev->lock);
+
+       vring_del_virtqueue(vq);
+
+       /* Select and deactivate the queue */
+       iowrite16(info->queue_index, vp_dev->ioaddr + VIRTIO_PCI_QUEUE_SEL);
+       iowrite32(0, vp_dev->ioaddr + VIRTIO_PCI_QUEUE_PFN);
+
+       kfree(info->queue);
+       kfree(info);
+}
+
+static struct virtio_config_ops virtio_pci_config_ops = {
+       .feature        = vp_feature,
+       .get            = vp_get,
+       .set            = vp_set,
+       .get_status     = vp_get_status,
+       .set_status     = vp_set_status,
+       .reset          = vp_reset,
+       .find_vq        = vp_find_vq,
+       .del_vq         = vp_del_vq,
+};
+
+/* the PCI probing function */
+static int __devinit virtio_pci_probe(struct pci_dev *pci_dev,
+                                     const struct pci_device_id *id)
+{
+       struct virtio_pci_device *vp_dev;
+       int err;
+
+       /* We only own devices >= 0x1000 and <= 0x103f: leave the rest. */
+       if (pci_dev->device < 0x1000 || pci_dev->device > 0x103f)
+               return -ENODEV;
+
+       if (pci_dev->revision != VIRTIO_PCI_ABI_VERSION) {
+               printk(KERN_ERR "virtio_pci: expected ABI version %d, got %d\n",
+                      VIRTIO_PCI_ABI_VERSION, pci_dev->revision);
+               return -ENODEV;
+       }
+
+       /* allocate our structure and fill it out */
+       vp_dev = kzalloc(sizeof(struct virtio_pci_device), GFP_KERNEL);
+       if (vp_dev == NULL)
+               return -ENOMEM;
+
+       snprintf(vp_dev->vdev.dev.bus_id, BUS_ID_SIZE, "virtio%d", dev_index);
+       vp_dev->vdev.index = dev_index;
+       dev_index++;
+
+       vp_dev->vdev.dev.parent = &virtio_pci_root;
+       vp_dev->vdev.config = &virtio_pci_config_ops;
+       vp_dev->pci_dev = pci_dev;
+       INIT_LIST_HEAD(&vp_dev->virtqueues);
+       spin_lock_init(&vp_dev->lock);
+
+       /* enable the device */
+       err = pci_enable_device(pci_dev);
+       if (err)
+               goto out;
+
+       err = pci_request_regions(pci_dev, "virtio-pci");
+       if (err)
+               goto out_enable_device;
+
+       vp_dev->ioaddr = pci_iomap(pci_dev, 0, 0);
+       if (vp_dev->ioaddr == NULL)
+               goto out_req_regions;
+
+       pci_set_drvdata(pci_dev, vp_dev);
+
+       /* we use the subsystem vendor/device id as the virtio vendor/device
+        * id.  this allows us to use the same PCI vendor/device id for all
+        * virtio devices and to identify the particular virtio driver by
+        * the subsytem ids */
+       vp_dev->vdev.id.vendor = pci_dev->subsystem_vendor;
+       vp_dev->vdev.id.device = pci_dev->subsystem_device;
+
+       /* register a handler for the queue with the PCI device's interrupt */
+       err = request_irq(vp_dev->pci_dev->irq, vp_interrupt, IRQF_SHARED,
+                         vp_dev->vdev.dev.bus_id, vp_dev);
+       if (err)
+               goto out_set_drvdata;
+
+       /* finally register the virtio device */
+       err = register_virtio_device(&vp_dev->vdev);
+       if (err)
+               goto out_req_irq;
+
+       return 0;
+
+out_req_irq:
+       free_irq(pci_dev->irq, vp_dev);
+out_set_drvdata:
+       pci_set_drvdata(pci_dev, NULL);
+       pci_iounmap(pci_dev, vp_dev->ioaddr);
+out_req_regions:
+       pci_release_regions(pci_dev);
+out_enable_device:
+       pci_disable_device(pci_dev);
+out:
+       kfree(vp_dev);
+       return err;
+}
+
+static void __devexit virtio_pci_remove(struct pci_dev *pci_dev)
+{
+       struct virtio_pci_device *vp_dev = pci_get_drvdata(pci_dev);
+
+       free_irq(pci_dev->irq, vp_dev);
+       pci_set_drvdata(pci_dev, NULL);
+       pci_iounmap(pci_dev, vp_dev->ioaddr);
+       pci_release_regions(pci_dev);
+       pci_disable_device(pci_dev);
+       kfree(vp_dev);
+}
+
+#ifdef CONFIG_PM
+static int virtio_pci_suspend(struct pci_dev *pci_dev, pm_message_t state)
+{
+       pci_save_state(pci_dev);
+       pci_set_power_state(pci_dev, PCI_D3hot);
+       return 0;
+}
+
+static int virtio_pci_resume(struct pci_dev *pci_dev)
+{
+       pci_restore_state(pci_dev);
+       pci_set_power_state(pci_dev, PCI_D0);
+       return 0;
+}
+#endif
+
+static struct pci_driver virtio_pci_driver = {
+       .name           = "virtio-pci",
+       .id_table       = virtio_pci_id_table,
+       .probe          = virtio_pci_probe,
+       .remove         = virtio_pci_remove,
+#ifdef CONFIG_PM
+       .suspend        = virtio_pci_suspend,
+       .resume         = virtio_pci_resume,
+#endif
+};
+
+static int __init virtio_pci_init(void)
+{
+       int err;
+
+       err = device_register(&virtio_pci_root);
+       if (err)
+               return err;
+
+       err = pci_register_driver(&virtio_pci_driver);
+       if (err)
+               device_unregister(&virtio_pci_root);
+
+       return err;
+}
+
+module_init(virtio_pci_init);
+
+static void __exit virtio_pci_exit(void)
+{
+       device_unregister(&virtio_pci_root);
+       pci_unregister_driver(&virtio_pci_driver);
+}
+
+module_exit(virtio_pci_exit);
index 1dc04b6684e6a3ce03451923d09164480932eebd..3a28c1382131d04940035448d24aada5244e7589 100644 (file)
@@ -87,6 +87,8 @@ static int vring_add_buf(struct virtqueue *_vq,
        if (vq->num_free < out + in) {
                pr_debug("Can't add buf len %i - avail = %i\n",
                         out + in, vq->num_free);
+               /* We notify *even if* VRING_USED_F_NO_NOTIFY is set here. */
+               vq->notify(&vq->vq);
                END_USE(vq);
                return -ENOSPC;
        }
@@ -97,16 +99,14 @@ static int vring_add_buf(struct virtqueue *_vq,
        head = vq->free_head;
        for (i = vq->free_head; out; i = vq->vring.desc[i].next, out--) {
                vq->vring.desc[i].flags = VRING_DESC_F_NEXT;
-               vq->vring.desc[i].addr = (page_to_pfn(sg_page(sg))<<PAGE_SHIFT)
-                       + sg->offset;
+               vq->vring.desc[i].addr = sg_phys(sg);
                vq->vring.desc[i].len = sg->length;
                prev = i;
                sg++;
        }
        for (; in; i = vq->vring.desc[i].next, in--) {
                vq->vring.desc[i].flags = VRING_DESC_F_NEXT|VRING_DESC_F_WRITE;
-               vq->vring.desc[i].addr = (page_to_pfn(sg_page(sg))<<PAGE_SHIFT)
-                       + sg->offset;
+               vq->vring.desc[i].addr = sg_phys(sg);
                vq->vring.desc[i].len = sg->length;
                prev = i;
                sg++;
@@ -171,16 +171,6 @@ static void detach_buf(struct vring_virtqueue *vq, unsigned int head)
        vq->num_free++;
 }
 
-/* FIXME: We need to tell other side about removal, to synchronize. */
-static void vring_shutdown(struct virtqueue *_vq)
-{
-       struct vring_virtqueue *vq = to_vvq(_vq);
-       unsigned int i;
-
-       for (i = 0; i < vq->vring.num; i++)
-               detach_buf(vq, i);
-}
-
 static inline bool more_used(const struct vring_virtqueue *vq)
 {
        return vq->last_used_idx != vq->vring.used->idx;
@@ -220,7 +210,17 @@ static void *vring_get_buf(struct virtqueue *_vq, unsigned int *len)
        return ret;
 }
 
-static bool vring_restart(struct virtqueue *_vq)
+static void vring_disable_cb(struct virtqueue *_vq)
+{
+       struct vring_virtqueue *vq = to_vvq(_vq);
+
+       START_USE(vq);
+       BUG_ON(vq->vring.avail->flags & VRING_AVAIL_F_NO_INTERRUPT);
+       vq->vring.avail->flags |= VRING_AVAIL_F_NO_INTERRUPT;
+       END_USE(vq);
+}
+
+static bool vring_enable_cb(struct virtqueue *_vq)
 {
        struct vring_virtqueue *vq = to_vvq(_vq);
 
@@ -253,26 +253,34 @@ irqreturn_t vring_interrupt(int irq, void *_vq)
        if (unlikely(vq->broken))
                return IRQ_HANDLED;
 
+       /* Other side may have missed us turning off the interrupt,
+        * but we should preserve disable semantic for virtio users. */
+       if (unlikely(vq->vring.avail->flags & VRING_AVAIL_F_NO_INTERRUPT)) {
+               pr_debug("virtqueue interrupt after disable for %p\n", vq);
+               return IRQ_HANDLED;
+       }
+
        pr_debug("virtqueue callback for %p (%p)\n", vq, vq->vq.callback);
-       if (vq->vq.callback && !vq->vq.callback(&vq->vq))
-               vq->vring.avail->flags |= VRING_AVAIL_F_NO_INTERRUPT;
+       if (vq->vq.callback)
+               vq->vq.callback(&vq->vq);
 
        return IRQ_HANDLED;
 }
+EXPORT_SYMBOL_GPL(vring_interrupt);
 
 static struct virtqueue_ops vring_vq_ops = {
        .add_buf = vring_add_buf,
        .get_buf = vring_get_buf,
        .kick = vring_kick,
-       .restart = vring_restart,
-       .shutdown = vring_shutdown,
+       .disable_cb = vring_disable_cb,
+       .enable_cb = vring_enable_cb,
 };
 
 struct virtqueue *vring_new_virtqueue(unsigned int num,
                                      struct virtio_device *vdev,
                                      void *pages,
                                      void (*notify)(struct virtqueue *),
-                                     bool (*callback)(struct virtqueue *))
+                                     void (*callback)(struct virtqueue *))
 {
        struct vring_virtqueue *vq;
        unsigned int i;
@@ -311,9 +319,12 @@ struct virtqueue *vring_new_virtqueue(unsigned int num,
 
        return &vq->vq;
 }
+EXPORT_SYMBOL_GPL(vring_new_virtqueue);
 
 void vring_del_virtqueue(struct virtqueue *vq)
 {
        kfree(to_vvq(vq));
 }
+EXPORT_SYMBOL_GPL(vring_del_virtqueue);
 
+MODULE_LICENSE("GPL");
index cecbedd473a4392436ea150e1446b66c0a4c4601..61dde863bd40c2da42f04a6472a8407249fd961d 100644 (file)
@@ -52,7 +52,7 @@
  * overflow periods respectively.
  *
  * Also, since we can't really expect userspace to be responsive enough
- * before the overflow happens, we maintain two seperate timers .. One in
+ * before the overflow happens, we maintain two separate timers .. One in
  * the kernel for clearing out WOVF every 2ms or so (again, this depends on
  * HZ == 1000), and another for monitoring userspace writes to the WDT device.
  *
index 219ec06a8c7e2cd057a28898c4827776a1abf0c3..ea5b359476234452070e5ba64f44eb404c4f2107 100644 (file)
@@ -1152,7 +1152,7 @@ config BEFS_DEBUG
        depends on BEFS_FS
        help
          If you say Y here, you can use the 'debug' mount option to enable
-         debugging output from the driver. 
+         debugging output from the driver.
 
 config BFS_FS
        tristate "BFS file system support (EXPERIMENTAL)"
@@ -1263,7 +1263,7 @@ config JFFS2_FS_XATTR
          Extended attributes are name:value pairs associated with inodes by
          the kernel or by users (see the attr(5) manual page, or visit
          <http://acl.bestbits.at/> for details).
-         
+
          If unsure, say N.
 
 config JFFS2_FS_POSIX_ACL
@@ -1274,10 +1274,10 @@ config JFFS2_FS_POSIX_ACL
        help
          Posix Access Control Lists (ACLs) support permissions for users and
          groups beyond the owner/group/world scheme.
-         
+
          To learn more about Access Control Lists, visit the Posix ACLs for
          Linux website <http://acl.bestbits.at/>.
-         
+
          If you don't know what Access Control Lists are, say N
 
 config JFFS2_FS_SECURITY
@@ -1289,7 +1289,7 @@ config JFFS2_FS_SECURITY
          implemented by security modules like SELinux.  This option
          enables an extended attribute handler for file security
          labels in the jffs2 filesystem.
-         
+
          If you are not using a security module that requires using
          extended attributes for file security labels, say N.
 
@@ -1674,6 +1674,8 @@ config NFSD
        select CRYPTO_MD5 if NFSD_V4
        select CRYPTO if NFSD_V4
        select FS_POSIX_ACL if NFSD_V4
+       select PROC_FS if NFSD_V4
+       select PROC_FS if SUNRPC_GSS
        help
          If you want your Linux box to act as an NFS *server*, so that other
          computers on your local network which support NFS can access certain
@@ -1833,7 +1835,7 @@ config RPCSEC_GSS_SPKM3
          If unsure, say N.
 
 config SMB_FS
-       tristate "SMB file system support (to mount Windows shares etc.)"
+       tristate "SMB file system support (OBSOLETE, please use CIFS)"
        depends on INET
        select NLS
        help
@@ -1856,8 +1858,8 @@ config SMB_FS
          General information about how to connect Linux, Windows machines and
          Macs is on the WWW at <http://www.eats.com/linux_mac_win.html>.
 
-         To compile the SMB support as a module, choose M here: the module will
-         be called smbfs.  Most people say N, however.
+         To compile the SMB support as a module, choose M here:
+         the module will be called smbfs.  Most people say N, however.
 
 config SMB_NLS_DEFAULT
        bool "Use a default NLS"
@@ -1889,7 +1891,7 @@ config SMB_NLS_REMOTE
          smbmount from samba 2.2.0 or later supports this.
 
 config CIFS
-       tristate "CIFS support (advanced network filesystem for Samba, Window and other CIFS compliant servers)"
+       tristate "CIFS support (advanced network filesystem, SMBFS successor)"
        depends on INET
        select NLS
        help
@@ -1947,16 +1949,16 @@ config CIFS_WEAK_PW_HASH
          LANMAN based servers such as OS/2 and Windows 95, but such
          mounts may be less secure than mounts using NTLM or more recent
          security mechanisms if you are on a public network.  Unless you
-         have a need to access old SMB servers (and are on a private 
+         have a need to access old SMB servers (and are on a private
          network) you probably want to say N.  Even if this support
          is enabled in the kernel build, LANMAN authentication will not be
          used automatically. At runtime LANMAN mounts are disabled but
          can be set to required (or optional) either in
          /proc/fs/cifs (see fs/cifs/README for more detail) or via an
-         option on the mount command. This support is disabled by 
+         option on the mount command. This support is disabled by
          default in order to reduce the possibility of a downgrade
          attack.
+
          If unsure, say N.
 
 config CIFS_XATTR
@@ -1997,7 +1999,7 @@ config CIFS_DEBUG2
           messages in some error paths, slowing performance. This
           option can be turned off unless you are debugging
           cifs problems.  If unsure, say N.
-          
+
 config CIFS_EXPERIMENTAL
          bool "CIFS Experimental Features (EXPERIMENTAL)"
          depends on CIFS && EXPERIMENTAL
@@ -2088,7 +2090,7 @@ config CODA_FS_OLD_API
          However this new API is not backward compatible with older
          clients. If you really need to run the old Coda userspace
          cache manager then say Y.
-         
+
          For most cases you probably want to say N.
 
 config AFS_FS
index af5bb93276f855ab6a3bdc8ec9cf632be8b5e22c..4202db7496cb51eb07cf3dfd7322b40dcc16ad08 100644 (file)
@@ -232,7 +232,7 @@ befs_bt_read_node(struct super_block *sb, befs_data_stream * ds,
  * @key: Key string to lookup in btree
  * @value: Value stored with @key
  *
- * On sucess, returns BEFS_OK and sets *@value to the value stored
+ * On success, returns BEFS_OK and sets *@value to the value stored
  * with @key (usually the disk block number of an inode).
  *
  * On failure, returns BEFS_ERR or BEFS_BT_NOT_FOUND.
index aacb4da6298aefe41200fb587784e09ce7d842ae..e3287d0d1a58815020044ef9f47383eec92cddcb 100644 (file)
@@ -236,7 +236,7 @@ befs_count_blocks(struct super_block * sb, befs_data_stream * ds)
        as in the indirect region code).
        
        When/if blockno is found, if blockno is inside of a block 
-       run as stored on disk, we offset the start and lenght members 
+       run as stored on disk, we offset the start and length members
        of the block run, so that blockno is the start and len is
        still valid (the run ends in the same place).
        
index 18ed6dd906c150208a4beb9230676a5a95de06d6..4628c42ca892ef9248dc7a6dc0f1ed2134211de6 100644 (file)
@@ -117,7 +117,7 @@ static int padzero(unsigned long elf_bss)
        return 0;
 }
 
-/* Let's use some macros to make this stack manipulation a litle clearer */
+/* Let's use some macros to make this stack manipulation a little clearer */
 #ifdef CONFIG_STACK_GROWSUP
 #define STACK_ADD(sp, items) ((elf_addr_t __user *)(sp) + (items))
 #define STACK_ROUND(sp, items) \
index 456c9ab7705b0fce1f7299ee455c26614330fb34..826baf4f04bc738fdfea27f6652bc3c0bfe9969d 100644 (file)
@@ -1798,7 +1798,7 @@ void page_zero_new_buffers(struct page *page, unsigned from, unsigned to)
                                        start = max(from, block_start);
                                        size = min(to, block_end) - start;
 
-                                       zero_user_page(page, start, size, KM_USER0);
+                                       zero_user(page, start, size);
                                        set_buffer_uptodate(bh);
                                }
 
@@ -1861,19 +1861,10 @@ static int __block_prepare_write(struct inode *inode, struct page *page,
                                        mark_buffer_dirty(bh);
                                        continue;
                                }
-                               if (block_end > to || block_start < from) {
-                                       void *kaddr;
-
-                                       kaddr = kmap_atomic(page, KM_USER0);
-                                       if (block_end > to)
-                                               memset(kaddr+to, 0,
-                                                       block_end-to);
-                                       if (block_start < from)
-                                               memset(kaddr+block_start,
-                                                       0, from-block_start);
-                                       flush_dcache_page(page);
-                                       kunmap_atomic(kaddr, KM_USER0);
-                               }
+                               if (block_end > to || block_start < from)
+                                       zero_user_segments(page,
+                                               to, block_end,
+                                               block_start, from);
                                continue;
                        }
                }
@@ -2104,8 +2095,7 @@ int block_read_full_page(struct page *page, get_block_t *get_block)
                                        SetPageError(page);
                        }
                        if (!buffer_mapped(bh)) {
-                               zero_user_page(page, i * blocksize, blocksize,
-                                               KM_USER0);
+                               zero_user(page, i * blocksize, blocksize);
                                if (!err)
                                        set_buffer_uptodate(bh);
                                continue;
@@ -2218,7 +2208,7 @@ int cont_expand_zero(struct file *file, struct address_space *mapping,
                                                &page, &fsdata);
                if (err)
                        goto out;
-               zero_user_page(page, zerofrom, len, KM_USER0);
+               zero_user(page, zerofrom, len);
                err = pagecache_write_end(file, mapping, curpos, len, len,
                                                page, fsdata);
                if (err < 0)
@@ -2245,7 +2235,7 @@ int cont_expand_zero(struct file *file, struct address_space *mapping,
                                                &page, &fsdata);
                if (err)
                        goto out;
-               zero_user_page(page, zerofrom, len, KM_USER0);
+               zero_user(page, zerofrom, len);
                err = pagecache_write_end(file, mapping, curpos, len, len,
                                                page, fsdata);
                if (err < 0)
@@ -2422,7 +2412,6 @@ int nobh_write_begin(struct file *file, struct address_space *mapping,
        unsigned block_in_page;
        unsigned block_start, block_end;
        sector_t block_in_file;
-       char *kaddr;
        int nr_reads = 0;
        int ret = 0;
        int is_mapped_to_disk = 1;
@@ -2493,13 +2482,8 @@ int nobh_write_begin(struct file *file, struct address_space *mapping,
                        continue;
                }
                if (buffer_new(bh) || !buffer_mapped(bh)) {
-                       kaddr = kmap_atomic(page, KM_USER0);
-                       if (block_start < from)
-                               memset(kaddr+block_start, 0, from-block_start);
-                       if (block_end > to)
-                               memset(kaddr + to, 0, block_end - to);
-                       flush_dcache_page(page);
-                       kunmap_atomic(kaddr, KM_USER0);
+                       zero_user_segments(page, block_start, from,
+                                                       to, block_end);
                        continue;
                }
                if (buffer_uptodate(bh))
@@ -2636,7 +2620,7 @@ int nobh_writepage(struct page *page, get_block_t *get_block,
         * the  page size, the remaining memory is zeroed when mapped, and
         * writes to that region are not written out to the file."
         */
-       zero_user_page(page, offset, PAGE_CACHE_SIZE - offset, KM_USER0);
+       zero_user_segment(page, offset, PAGE_CACHE_SIZE);
 out:
        ret = mpage_writepage(page, get_block, wbc);
        if (ret == -EAGAIN)
@@ -2709,7 +2693,7 @@ has_buffers:
                if (page_has_buffers(page))
                        goto has_buffers;
        }
-       zero_user_page(page, offset, length, KM_USER0);
+       zero_user(page, offset, length);
        set_page_dirty(page);
        err = 0;
 
@@ -2785,7 +2769,7 @@ int block_truncate_page(struct address_space *mapping,
                        goto unlock;
        }
 
-       zero_user_page(page, offset, length, KM_USER0);
+       zero_user(page, offset, length);
        mark_buffer_dirty(bh);
        err = 0;
 
@@ -2831,7 +2815,7 @@ int block_write_full_page(struct page *page, get_block_t *get_block,
         * the  page size, the remaining memory is zeroed when mapped, and
         * writes to that region are not written out to the file."
         */
-       zero_user_page(page, offset, PAGE_CACHE_SIZE - offset, KM_USER0);
+       zero_user_segment(page, offset, PAGE_CACHE_SIZE);
        return __block_write_full_page(inode, page, get_block, wbc);
 }
 
@@ -3169,7 +3153,7 @@ static void recalc_bh_state(void)
        
 struct buffer_head *alloc_buffer_head(gfp_t gfp_flags)
 {
-       struct buffer_head *ret = kmem_cache_zalloc(bh_cachep,
+       struct buffer_head *ret = kmem_cache_alloc(bh_cachep,
                                set_migrateflags(gfp_flags, __GFP_RECLAIMABLE));
        if (ret) {
                INIT_LIST_HEAD(&ret->b_assoc_buffers);
@@ -3257,12 +3241,24 @@ int bh_submit_read(struct buffer_head *bh)
 }
 EXPORT_SYMBOL(bh_submit_read);
 
+static void
+init_buffer_head(struct kmem_cache *cachep, void *data)
+{
+       struct buffer_head *bh = data;
+
+       memset(bh, 0, sizeof(*bh));
+       INIT_LIST_HEAD(&bh->b_assoc_buffers);
+}
+
 void __init buffer_init(void)
 {
        int nrpages;
 
-       bh_cachep = KMEM_CACHE(buffer_head,
-                       SLAB_RECLAIM_ACCOUNT|SLAB_PANIC|SLAB_MEM_SPREAD);
+       bh_cachep = kmem_cache_create("buffer_head",
+                       sizeof(struct buffer_head), 0,
+                               (SLAB_RECLAIM_ACCOUNT|SLAB_PANIC|
+                               SLAB_MEM_SPREAD),
+                               init_buffer_head);
 
        /*
         * Limit the bh occupancy to 10% of ZONE_NORMAL
index d9567ba2960bea58e679bd294ea150a609d537d7..47f2621001e4e09069c2c390f77fb95a4d3dd15f 100644 (file)
@@ -1386,7 +1386,7 @@ static int cifs_truncate_page(struct address_space *mapping, loff_t from)
        if (!page)
                return -ENOMEM;
 
-       zero_user_page(page, offset, PAGE_CACHE_SIZE - offset, KM_USER0);
+       zero_user_segment(page, offset, PAGE_CACHE_SIZE);
        unlock_page(page);
        page_cache_release(page);
        return rc;
index 5216c3fd751771ab4349753f68395b6daba74063..69baca5ad6089d3303ef5839e35c51b3f4a07ef9 100644 (file)
@@ -2206,19 +2206,41 @@ asmlinkage long compat_sys_signalfd(int ufd,
 
 #ifdef CONFIG_TIMERFD
 
-asmlinkage long compat_sys_timerfd(int ufd, int clockid, int flags,
-                                  const struct compat_itimerspec __user *utmr)
+asmlinkage long compat_sys_timerfd_settime(int ufd, int flags,
+                                  const struct compat_itimerspec __user *utmr,
+                                  struct compat_itimerspec __user *otmr)
 {
+       int error;
        struct itimerspec t;
        struct itimerspec __user *ut;
 
        if (get_compat_itimerspec(&t, utmr))
                return -EFAULT;
-       ut = compat_alloc_user_space(sizeof(*ut));
-       if (copy_to_user(ut, &t, sizeof(t)))
+       ut = compat_alloc_user_space(2 * sizeof(struct itimerspec));
+       if (copy_to_user(&ut[0], &t, sizeof(t)))
                return -EFAULT;
+       error = sys_timerfd_settime(ufd, flags, &ut[0], &ut[1]);
+       if (!error && otmr)
+               error = (copy_from_user(&t, &ut[1], sizeof(struct itimerspec)) ||
+                        put_compat_itimerspec(otmr, &t)) ? -EFAULT: 0;
+
+       return error;
+}
+
+asmlinkage long compat_sys_timerfd_gettime(int ufd,
+                                  struct compat_itimerspec __user *otmr)
+{
+       int error;
+       struct itimerspec t;
+       struct itimerspec __user *ut;
 
-       return sys_timerfd(ufd, clockid, flags, ut);
+       ut = compat_alloc_user_space(sizeof(struct itimerspec));
+       error = sys_timerfd_gettime(ufd, ut);
+       if (!error)
+               error = (copy_from_user(&t, ut, sizeof(struct itimerspec)) ||
+                        put_compat_itimerspec(otmr, &t)) ? -EFAULT: 0;
+
+       return error;
 }
 
 #endif /* CONFIG_TIMERFD */
index acf0da1bd257158fa79b0ba9f9f34b58a7207562..9e81addbd6ea7293ad3d2578d20bfeaf92cf8354 100644 (file)
@@ -878,8 +878,8 @@ do_holes:
                                        page_cache_release(page);
                                        goto out;
                                }
-                               zero_user_page(page, block_in_page << blkbits,
-                                               1 << blkbits, KM_USER0);
+                               zero_user(page, block_in_page << blkbits,
+                                               1 << blkbits);
                                dio->block_in_file++;
                                block_in_page++;
                                goto next_block;
index 32c5711d79a320593e9a536590f3b347905055bd..0535412d8c64a7793a64d5896c3c8ff031e5905f 100644 (file)
@@ -257,8 +257,7 @@ static int fill_zeros_to_end_of_page(struct page *page, unsigned int to)
        end_byte_in_page = i_size_read(inode) % PAGE_CACHE_SIZE;
        if (to > end_byte_in_page)
                end_byte_in_page = to;
-       zero_user_page(page, end_byte_in_page,
-               PAGE_CACHE_SIZE - end_byte_in_page, KM_USER0);
+       zero_user_segment(page, end_byte_in_page, PAGE_CACHE_SIZE);
 out:
        return 0;
 }
@@ -307,7 +306,7 @@ static int ecryptfs_prepare_write(struct file *file, struct page *page,
         */
        if ((i_size_read(page->mapping->host) == prev_page_end_size) &&
            (from != 0)) {
-               zero_user_page(page, 0, PAGE_CACHE_SIZE, KM_USER0);
+               zero_user(page, 0, PAGE_CACHE_SIZE);
        }
 out:
        return rc;
index 34f68f3a069a1b7d4924dc8be718927f9e6c791d..a415f42d32cf66aba720da4e05b2a0ccfdd55663 100644 (file)
@@ -353,7 +353,7 @@ static void ep_poll_safewake(struct poll_safewake *psw, wait_queue_head_t *wq)
        spin_unlock_irqrestore(&psw->lock, flags);
 
        /* Do really wake up now */
-       wake_up(wq);
+       wake_up_nested(wq, 1 + wake_nests);
 
        /* Remove the current task from the list */
        spin_lock_irqsave(&psw->lock, flags);
@@ -656,8 +656,7 @@ is_linked:
         * wait list.
         */
        if (waitqueue_active(&ep->wq))
-               __wake_up_locked(&ep->wq, TASK_UNINTERRUPTIBLE |
-                                TASK_INTERRUPTIBLE);
+               wake_up_locked(&ep->wq);
        if (waitqueue_active(&ep->poll_wait))
                pwake++;
 
@@ -780,7 +779,7 @@ static int ep_insert(struct eventpoll *ep, struct epoll_event *event,
 
                /* Notify waiting tasks that events are available */
                if (waitqueue_active(&ep->wq))
-                       __wake_up_locked(&ep->wq, TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE);
+                       wake_up_locked(&ep->wq);
                if (waitqueue_active(&ep->poll_wait))
                        pwake++;
        }
@@ -854,8 +853,7 @@ static int ep_modify(struct eventpoll *ep, struct epitem *epi, struct epoll_even
 
                        /* Notify waiting tasks that events are available */
                        if (waitqueue_active(&ep->wq))
-                               __wake_up_locked(&ep->wq, TASK_UNINTERRUPTIBLE |
-                                                TASK_INTERRUPTIBLE);
+                               wake_up_locked(&ep->wq);
                        if (waitqueue_active(&ep->poll_wait))
                                pwake++;
                }
@@ -978,8 +976,7 @@ errxit:
                 * wait list (delayed after we release the lock).
                 */
                if (waitqueue_active(&ep->wq))
-                       __wake_up_locked(&ep->wq, TASK_UNINTERRUPTIBLE |
-                                        TASK_INTERRUPTIBLE);
+                       wake_up_locked(&ep->wq);
                if (waitqueue_active(&ep->poll_wait))
                        pwake++;
        }
index 282240afe99e5e223b1732c4c1b58245d90618d8..be923e4bc38972954325aee09363cb38bff60884 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -760,7 +760,7 @@ static int de_thread(struct task_struct *tsk)
         */
        read_lock(&tasklist_lock);
        spin_lock_irq(lock);
-       if (sig->flags & SIGNAL_GROUP_EXIT) {
+       if (signal_group_exit(sig)) {
                /*
                 * Another group action in progress, just
                 * return so that the signal is processed.
@@ -778,6 +778,7 @@ static int de_thread(struct task_struct *tsk)
        if (unlikely(tsk->group_leader == task_child_reaper(tsk)))
                task_active_pid_ns(tsk)->child_reaper = tsk;
 
+       sig->group_exit_task = tsk;
        zap_other_threads(tsk);
        read_unlock(&tasklist_lock);
 
@@ -802,7 +803,6 @@ static int de_thread(struct task_struct *tsk)
        }
 
        sig->notify_count = count;
-       sig->group_exit_task = tsk;
        while (atomic_read(&sig->count) > count) {
                __set_current_state(TASK_UNINTERRUPTIBLE);
                spin_unlock_irq(lock);
@@ -871,15 +871,10 @@ static int de_thread(struct task_struct *tsk)
                leader->exit_state = EXIT_DEAD;
 
                write_unlock_irq(&tasklist_lock);
-        }
+       }
 
        sig->group_exit_task = NULL;
        sig->notify_count = 0;
-       /*
-        * There may be one thread left which is just exiting,
-        * but it's safe to stop telling the group to kill themselves.
-        */
-       sig->flags = 0;
 
 no_thread_group:
        exit_itimers(sig);
@@ -947,12 +942,13 @@ static void flush_old_files(struct files_struct * files)
        spin_unlock(&files->file_lock);
 }
 
-void get_task_comm(char *buf, struct task_struct *tsk)
+char *get_task_comm(char *buf, struct task_struct *tsk)
 {
        /* buf must be at least sizeof(tsk->comm) in size */
        task_lock(tsk);
        strncpy(buf, tsk->comm, sizeof(tsk->comm));
        task_unlock(tsk);
+       return buf;
 }
 
 void set_task_comm(struct task_struct *tsk, char *buf)
@@ -1548,7 +1544,7 @@ static inline int zap_threads(struct task_struct *tsk, struct mm_struct *mm,
        int err = -EAGAIN;
 
        spin_lock_irq(&tsk->sighand->siglock);
-       if (!(tsk->signal->flags & SIGNAL_GROUP_EXIT)) {
+       if (!signal_group_exit(tsk->signal)) {
                tsk->signal->group_exit_code = exit_code;
                zap_process(tsk);
                err = 0;
index 9b162cd6c16c170ce7c35c3fc2f993ccc648cbc3..07753543928865399d1be5bd9d551c52a006369b 100644 (file)
@@ -1845,7 +1845,7 @@ static int ext3_block_truncate_page(handle_t *handle, struct page *page,
         */
        if (!page_has_buffers(page) && test_opt(inode->i_sb, NOBH) &&
             ext3_should_writeback_data(inode) && PageUptodate(page)) {
-               zero_user_page(page, offset, length, KM_USER0);
+               zero_user(page, offset, length);
                set_page_dirty(page);
                goto unlock;
        }
@@ -1898,7 +1898,7 @@ static int ext3_block_truncate_page(handle_t *handle, struct page *page,
                        goto unlock;
        }
 
-       zero_user_page(page, offset, length, KM_USER0);
+       zero_user(page, offset, length);
        BUFFER_TRACE(bh, "zeroed end of block");
 
        err = 0;
index bb717cbb749c822265bccdd8159de7af456ad745..05c4145dd27d3e03b634d7525aea9fe472012a58 100644 (file)
@@ -1840,7 +1840,7 @@ int ext4_block_truncate_page(handle_t *handle, struct page *page,
         */
        if (!page_has_buffers(page) && test_opt(inode->i_sb, NOBH) &&
             ext4_should_writeback_data(inode) && PageUptodate(page)) {
-               zero_user_page(page, offset, length, KM_USER0);
+               zero_user(page, offset, length);
                set_page_dirty(page);
                goto unlock;
        }
@@ -1893,7 +1893,7 @@ int ext4_block_truncate_page(handle_t *handle, struct page *page,
                        goto unlock;
        }
 
-       zero_user_page(page, offset, length, KM_USER0);
+       zero_user(page, offset, length);
 
        BUFFER_TRACE(bh, "zeroed end of block");
 
index 3c96d6e6397868e28550c986a35ee6f4df5beefc..aaf1fb098639553fc6ad7a8d6c9e0ccd7162a9ce 100644 (file)
@@ -41,7 +41,7 @@
  * VxFS directory block header.
  *
  * This entry is the head of every filesystem block in a directory.
- * It is used for free space managment and additionally includes
+ * It is used for free space management and additionally includes
  * a hash for speeding up directory search (lookup).
  *
  * The hash may be empty and in fact we do not use it all in the
index 24b5a775ff960493a60df4d6c1cb36bdf54010be..8a5959a61ba9dbff4b9b713efa1f5d42da003e1f 100644 (file)
@@ -54,7 +54,7 @@ const struct inode_operations vxfs_immed_symlink_iops = {
 };
 
 /*
- * Adress space operations for immed files and directories.
+ * Address space operations for immed files and directories.
  */
 const struct address_space_operations vxfs_immed_aops = {
        .readpage =             vxfs_immed_readpage,
index 300324bd563c924ae87c10db7d5171726f8bffc1..0b3064079fa530e9c6d68739d931cff50af069a3 100644 (file)
@@ -284,7 +284,17 @@ __sync_single_inode(struct inode *inode, struct writeback_control *wbc)
                                 * soon as the queue becomes uncongested.
                                 */
                                inode->i_state |= I_DIRTY_PAGES;
-                               requeue_io(inode);
+                               if (wbc->nr_to_write <= 0) {
+                                       /*
+                                        * slice used up: queue for next turn
+                                        */
+                                       requeue_io(inode);
+                               } else {
+                                       /*
+                                        * somehow blocked: retry later
+                                        */
+                                       redirty_tail(inode);
+                               }
                        } else {
                                /*
                                 * Otherwise fully redirty the inode so that
@@ -334,9 +344,6 @@ __writeback_single_inode(struct inode *inode, struct writeback_control *wbc)
                WARN_ON(inode->i_state & I_WILL_FREE);
 
        if ((wbc->sync_mode != WB_SYNC_ALL) && (inode->i_state & I_SYNC)) {
-               struct address_space *mapping = inode->i_mapping;
-               int ret;
-
                /*
                 * We're skipping this inode because it's locked, and we're not
                 * doing writeback-for-data-integrity.  Move it to s_more_io so
@@ -345,15 +352,7 @@ __writeback_single_inode(struct inode *inode, struct writeback_control *wbc)
                 * completed a full scan of s_io.
                 */
                requeue_io(inode);
-
-               /*
-                * Even if we don't actually write the inode itself here,
-                * we can at least start some of the data writeout..
-                */
-               spin_unlock(&inode_lock);
-               ret = do_writepages(mapping, wbc);
-               spin_lock(&inode_lock);
-               return ret;
+               return 0;
        }
 
        /*
@@ -479,8 +478,12 @@ sync_sb_inodes(struct super_block *sb, struct writeback_control *wbc)
                iput(inode);
                cond_resched();
                spin_lock(&inode_lock);
-               if (wbc->nr_to_write <= 0)
+               if (wbc->nr_to_write <= 0) {
+                       wbc->more_io = 1;
                        break;
+               }
+               if (!list_empty(&sb->s_more_io))
+                       wbc->more_io = 1;
        }
        return;         /* Leave any unwritten inodes on s_io */
 }
index e4effc47abfc865f82f71b6855f06521253c25b5..e9456ebd3bb619c0dc269331ec793d54e3eee319 100644 (file)
@@ -932,7 +932,7 @@ static int gfs2_block_truncate_page(struct address_space *mapping)
        if (!gfs2_is_writeback(ip))
                gfs2_trans_add_bh(ip->i_gl, bh, 0);
 
-       zero_user_page(page, offset, length, KM_USER0);
+       zero_user(page, offset, length);
 
 unlock:
        unlock_page(page);
index 38dbe99a30ede1ac388596278ef02ca9e9590bae..ac772b6d9dbbfa6cde57fb366fdd54e11dd68d5a 100644 (file)
@@ -446,7 +446,7 @@ static int stuffed_readpage(struct gfs2_inode *ip, struct page *page)
         * so we need to supply one here. It doesn't happen often.
         */
        if (unlikely(page->index)) {
-               zero_user_page(page, 0, PAGE_CACHE_SIZE, KM_USER0);
+               zero_user(page, 0, PAGE_CACHE_SIZE);
                return 0;
        }
 
index b249e294a95bfa76cde2699716a3e96f817d6e03..6fb07d67ca8a41bef05b1940a6831fb2b2764139 100644 (file)
@@ -450,7 +450,7 @@ int gfs2_recover_journal(struct gfs2_jdesc *jd)
                fs_info(sdp, "jid=%u: Trying to acquire journal lock...\n",
                        jd->jd_jid);
 
-               /* Aquire the journal lock so we can do recovery */
+               /* Acquire the journal lock so we can do recovery */
 
                error = gfs2_glock_nq_num(sdp, jd->jd_jid, &gfs2_journal_glops,
                                          LM_ST_EXCLUSIVE,
index 35c1a9f33f47895958cb68aff7e449c06ce08f3a..53fd0a67c11abf148a76cea7820a1a3c782adc26 100644 (file)
@@ -285,17 +285,17 @@ int set_attr(const char *file, struct hostfs_iattr *attrs, int fd)
                        return err;
 
                times[0].tv_sec = atime_ts.tv_sec;
-               times[0].tv_usec = atime_ts.tv_nsec * 1000;
+               times[0].tv_usec = atime_ts.tv_nsec / 1000;
                times[1].tv_sec = mtime_ts.tv_sec;
-               times[1].tv_usec = mtime_ts.tv_nsec * 1000;
+               times[1].tv_usec = mtime_ts.tv_nsec / 1000;
 
                if (attrs->ia_valid & HOSTFS_ATTR_ATIME_SET) {
                        times[0].tv_sec = attrs->ia_atime.tv_sec;
-                       times[0].tv_usec = attrs->ia_atime.tv_nsec * 1000;
+                       times[0].tv_usec = attrs->ia_atime.tv_nsec / 1000;
                }
                if (attrs->ia_valid & HOSTFS_ATTR_MTIME_SET) {
                        times[1].tv_sec = attrs->ia_mtime.tv_sec;
-                       times[1].tv_usec = attrs->ia_mtime.tv_nsec * 1000;
+                       times[1].tv_usec = attrs->ia_mtime.tv_nsec / 1000;
                }
 
                if (fd >= 0) {
index 09ee07f026630501869eb0bd53131e46b7f8d82d..3b3cc28cdefcaf5929be2a3d13be24bf4791fd6c 100644 (file)
@@ -768,7 +768,7 @@ hugetlbfs_parse_options(char *options, struct hugetlbfs_config *pconfig)
                case Opt_mode:
                        if (match_octal(&args[0], &option))
                                goto bad_val;
-                       pconfig->mode = option & 0777U;
+                       pconfig->mode = option & 01777U;
                        break;
 
                case Opt_size: {
index 2eae5d2dbebed3707bf9805675822527a922045e..6c1ba3566f58b4c498c1cfa7a3a627db9e089eeb 100644 (file)
@@ -741,7 +741,7 @@ static inline int read_dnode(struct jffs2_sb_info *c, struct jffs2_raw_node_ref
                         * are not obsolete.
                         *
                         * Of course, this optimization only makes sense in case
-                        * of NAND flashes (or other flashes whith
+                        * of NAND flashes (or other flashes with
                         * !jffs2_can_mark_obsolete()), since on NOR flashes
                         * nodes are marked obsolete physically.
                         *
index 1543906a2e0dd29ac7008ac1204c490b765ba14b..a000aaa75136d68f9b064197af05388b2acf93cf 100644 (file)
@@ -3965,7 +3965,7 @@ s64 xtTruncate(tid_t tid, struct inode *ip, s64 newsize, int flag)
  *     xtTruncate_pmap()
  *
  * function:
- *     Perform truncate to zero lenghth for deleted file, leaving the
+ *     Perform truncate to zero length for deleted file, leaving the
  *     the xtree and working map untouched.  This allows the file to
  *     be accessed via open file handles, while the delete of the file
  *     is committed to disk.
index 6e68b700958d331e7e0c2446d54b7d9d06b8f3c2..5523bde963879d6060c9a9d19396e8a8615b40a2 100644 (file)
@@ -341,13 +341,10 @@ int simple_prepare_write(struct file *file, struct page *page,
                        unsigned from, unsigned to)
 {
        if (!PageUptodate(page)) {
-               if (to - from != PAGE_CACHE_SIZE) {
-                       void *kaddr = kmap_atomic(page, KM_USER0);
-                       memset(kaddr, 0, from);
-                       memset(kaddr + to, 0, PAGE_CACHE_SIZE - to);
-                       flush_dcache_page(page);
-                       kunmap_atomic(kaddr, KM_USER0);
-               }
+               if (to - from != PAGE_CACHE_SIZE)
+                       zero_user_segments(page,
+                               0, from,
+                               to, PAGE_CACHE_SIZE);
        }
        return 0;
 }
index 572601e98dcdec6d6d88da33ec0b757bd8b7d3f4..ca6b16fc3101a3df88d60350060eae56d6528535 100644 (file)
@@ -34,10 +34,10 @@ static DEFINE_MUTEX(nlm_host_mutex);
 
 static void                    nlm_gc_hosts(void);
 static struct nsm_handle *     __nsm_find(const struct sockaddr_in *,
-                                       const char *, int, int);
+                                       const char *, unsigned int, int);
 static struct nsm_handle *     nsm_find(const struct sockaddr_in *sin,
                                         const char *hostname,
-                                        int hostname_len);
+                                        unsigned int hostname_len);
 
 /*
  * Common host lookup routine for server & client
@@ -45,7 +45,8 @@ static struct nsm_handle *    nsm_find(const struct sockaddr_in *sin,
 static struct nlm_host *
 nlm_lookup_host(int server, const struct sockaddr_in *sin,
                int proto, int version, const char *hostname,
-               int hostname_len, const struct sockaddr_in *ssin)
+               unsigned int hostname_len,
+               const struct sockaddr_in *ssin)
 {
        struct hlist_head *chain;
        struct hlist_node *pos;
@@ -176,7 +177,7 @@ nlm_destroy_host(struct nlm_host *host)
  */
 struct nlm_host *
 nlmclnt_lookup_host(const struct sockaddr_in *sin, int proto, int version,
-                       const char *hostname, int hostname_len)
+                       const char *hostname, unsigned int hostname_len)
 {
        struct sockaddr_in ssin = {0};
 
@@ -189,7 +190,7 @@ nlmclnt_lookup_host(const struct sockaddr_in *sin, int proto, int version,
  */
 struct nlm_host *
 nlmsvc_lookup_host(struct svc_rqst *rqstp,
-                       const char *hostname, int hostname_len)
+                       const char *hostname, unsigned int hostname_len)
 {
        struct sockaddr_in ssin = {0};
 
@@ -307,7 +308,8 @@ void nlm_release_host(struct nlm_host *host)
  * Release all resources held by that peer.
  */
 void nlm_host_rebooted(const struct sockaddr_in *sin,
-                               const char *hostname, int hostname_len,
+                               const char *hostname,
+                               unsigned int hostname_len,
                                u32 new_state)
 {
        struct hlist_head *chain;
@@ -377,8 +379,13 @@ nlm_shutdown_hosts(void)
        /* First, make all hosts eligible for gc */
        dprintk("lockd: nuking all hosts...\n");
        for (chain = nlm_hosts; chain < nlm_hosts + NLM_HOST_NRHASH; ++chain) {
-               hlist_for_each_entry(host, pos, chain, h_hash)
+               hlist_for_each_entry(host, pos, chain, h_hash) {
                        host->h_expires = jiffies - 1;
+                       if (host->h_rpcclnt) {
+                               rpc_shutdown_client(host->h_rpcclnt);
+                               host->h_rpcclnt = NULL;
+                       }
+               }
        }
 
        /* Then, perform a garbage collection pass */
@@ -449,7 +456,7 @@ static DEFINE_MUTEX(nsm_mutex);
 
 static struct nsm_handle *
 __nsm_find(const struct sockaddr_in *sin,
-               const char *hostname, int hostname_len,
+               const char *hostname, unsigned int hostname_len,
                int create)
 {
        struct nsm_handle *nsm = NULL;
@@ -503,7 +510,8 @@ out:
 }
 
 static struct nsm_handle *
-nsm_find(const struct sockaddr_in *sin, const char *hostname, int hostname_len)
+nsm_find(const struct sockaddr_in *sin, const char *hostname,
+        unsigned int hostname_len)
 {
        return __nsm_find(sin, hostname, hostname_len, 1);
 }
index 82e2192a0d5c873a72b867702c511b0c8872f6a7..08226464e5638f1c9ec0636124800609ffb09b84 100644 (file)
@@ -219,19 +219,6 @@ lockd(struct svc_rqst *rqstp)
        module_put_and_exit(0);
 }
 
-
-static int find_socket(struct svc_serv *serv, int proto)
-{
-       struct svc_sock *svsk;
-       int found = 0;
-       list_for_each_entry(svsk, &serv->sv_permsocks, sk_list)
-               if (svsk->sk_sk->sk_protocol == proto) {
-                       found = 1;
-                       break;
-               }
-       return found;
-}
-
 /*
  * Make any sockets that are needed but not present.
  * If nlm_udpport or nlm_tcpport were set as module
@@ -240,17 +227,25 @@ static int find_socket(struct svc_serv *serv, int proto)
 static int make_socks(struct svc_serv *serv, int proto)
 {
        static int warned;
+       struct svc_xprt *xprt;
        int err = 0;
 
-       if (proto == IPPROTO_UDP || nlm_udpport)
-               if (!find_socket(serv, IPPROTO_UDP))
-                       err = svc_makesock(serv, IPPROTO_UDP, nlm_udpport,
-                                               SVC_SOCK_DEFAULTS);
-       if (err >= 0 && (proto == IPPROTO_TCP || nlm_tcpport))
-               if (!find_socket(serv, IPPROTO_TCP))
-                       err = svc_makesock(serv, IPPROTO_TCP, nlm_tcpport,
-                                               SVC_SOCK_DEFAULTS);
-
+       if (proto == IPPROTO_UDP || nlm_udpport) {
+               xprt = svc_find_xprt(serv, "udp", 0, 0);
+               if (!xprt)
+                       err = svc_create_xprt(serv, "udp", nlm_udpport,
+                                             SVC_SOCK_DEFAULTS);
+               else
+                       svc_xprt_put(xprt);
+       }
+       if (err >= 0 && (proto == IPPROTO_TCP || nlm_tcpport)) {
+               xprt = svc_find_xprt(serv, "tcp", 0, 0);
+               if (!xprt)
+                       err = svc_create_xprt(serv, "tcp", nlm_tcpport,
+                                             SVC_SOCK_DEFAULTS);
+               else
+                       svc_xprt_put(xprt);
+       }
        if (err >= 0) {
                warned = 0;
                err = 0;
index bf27b6c6cb6b6219f0518d856d77796ed9694828..385437e3387de895fde1540f58c7d3269a842373 100644 (file)
@@ -84,6 +84,7 @@ nlm4svc_proc_test(struct svc_rqst *rqstp, struct nlm_args *argp,
 {
        struct nlm_host *host;
        struct nlm_file *file;
+       int rc = rpc_success;
 
        dprintk("lockd: TEST4        called\n");
        resp->cookie = argp->cookie;
@@ -91,7 +92,7 @@ nlm4svc_proc_test(struct svc_rqst *rqstp, struct nlm_args *argp,
        /* Don't accept test requests during grace period */
        if (nlmsvc_grace_period) {
                resp->status = nlm_lck_denied_grace_period;
-               return rpc_success;
+               return rc;
        }
 
        /* Obtain client and file */
@@ -101,12 +102,13 @@ nlm4svc_proc_test(struct svc_rqst *rqstp, struct nlm_args *argp,
        /* Now check for conflicting locks */
        resp->status = nlmsvc_testlock(rqstp, file, &argp->lock, &resp->lock, &resp->cookie);
        if (resp->status == nlm_drop_reply)
-               return rpc_drop_reply;
+               rc = rpc_drop_reply;
+       else
+               dprintk("lockd: TEST4        status %d\n", ntohl(resp->status));
 
-       dprintk("lockd: TEST4          status %d\n", ntohl(resp->status));
        nlm_release_host(host);
        nlm_release_file(file);
-       return rpc_success;
+       return rc;
 }
 
 static __be32
@@ -115,6 +117,7 @@ nlm4svc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
 {
        struct nlm_host *host;
        struct nlm_file *file;
+       int rc = rpc_success;
 
        dprintk("lockd: LOCK          called\n");
 
@@ -123,7 +126,7 @@ nlm4svc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
        /* Don't accept new lock requests during grace period */
        if (nlmsvc_grace_period && !argp->reclaim) {
                resp->status = nlm_lck_denied_grace_period;
-               return rpc_success;
+               return rc;
        }
 
        /* Obtain client and file */
@@ -146,12 +149,13 @@ nlm4svc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
        resp->status = nlmsvc_lock(rqstp, file, &argp->lock,
                                        argp->block, &argp->cookie);
        if (resp->status == nlm_drop_reply)
-               return rpc_drop_reply;
+               rc = rpc_drop_reply;
+       else
+               dprintk("lockd: LOCK         status %d\n", ntohl(resp->status));
 
-       dprintk("lockd: LOCK          status %d\n", ntohl(resp->status));
        nlm_release_host(host);
        nlm_release_file(file);
-       return rpc_success;
+       return rc;
 }
 
 static __be32
index d120ec39bcb0ea5c472fc7c1f3ba277b9308709d..2f4d8fa666892b9fa8b41266a627608c55c1e8a0 100644 (file)
@@ -501,25 +501,29 @@ nlmsvc_testlock(struct svc_rqst *rqstp, struct nlm_file *file,
                        block, block->b_flags, block->b_fl);
                if (block->b_flags & B_TIMED_OUT) {
                        nlmsvc_unlink_block(block);
-                       return nlm_lck_denied;
+                       ret = nlm_lck_denied;
+                       goto out;
                }
                if (block->b_flags & B_GOT_CALLBACK) {
+                       nlmsvc_unlink_block(block);
                        if (block->b_fl != NULL
                                        && block->b_fl->fl_type != F_UNLCK) {
                                lock->fl = *block->b_fl;
                                goto conf_lock;
-                       }
-                       else {
-                               nlmsvc_unlink_block(block);
-                               return nlm_granted;
+                       } else {
+                               ret = nlm_granted;
+                               goto out;
                        }
                }
-               return nlm_drop_reply;
+               ret = nlm_drop_reply;
+               goto out;
        }
 
        error = vfs_test_lock(file->f_file, &lock->fl);
-       if (error == -EINPROGRESS)
-               return nlmsvc_defer_lock_rqst(rqstp, block);
+       if (error == -EINPROGRESS) {
+               ret = nlmsvc_defer_lock_rqst(rqstp, block);
+               goto out;
+       }
        if (error) {
                ret = nlm_lck_denied_nolocks;
                goto out;
index 9cd5c8b37593f099d3c64da583085b733175c038..88379cc6e0b1c0ee196c8686c3f0e7c46cabef9a 100644 (file)
@@ -113,6 +113,7 @@ nlmsvc_proc_test(struct svc_rqst *rqstp, struct nlm_args *argp,
 {
        struct nlm_host *host;
        struct nlm_file *file;
+       int rc = rpc_success;
 
        dprintk("lockd: TEST          called\n");
        resp->cookie = argp->cookie;
@@ -120,7 +121,7 @@ nlmsvc_proc_test(struct svc_rqst *rqstp, struct nlm_args *argp,
        /* Don't accept test requests during grace period */
        if (nlmsvc_grace_period) {
                resp->status = nlm_lck_denied_grace_period;
-               return rpc_success;
+               return rc;
        }
 
        /* Obtain client and file */
@@ -130,13 +131,14 @@ nlmsvc_proc_test(struct svc_rqst *rqstp, struct nlm_args *argp,
        /* Now check for conflicting locks */
        resp->status = cast_status(nlmsvc_testlock(rqstp, file, &argp->lock, &resp->lock, &resp->cookie));
        if (resp->status == nlm_drop_reply)
-               return rpc_drop_reply;
+               rc = rpc_drop_reply;
+       else
+               dprintk("lockd: TEST          status %d vers %d\n",
+                       ntohl(resp->status), rqstp->rq_vers);
 
-       dprintk("lockd: TEST          status %d vers %d\n",
-               ntohl(resp->status), rqstp->rq_vers);
        nlm_release_host(host);
        nlm_release_file(file);
-       return rpc_success;
+       return rc;
 }
 
 static __be32
@@ -145,6 +147,7 @@ nlmsvc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
 {
        struct nlm_host *host;
        struct nlm_file *file;
+       int rc = rpc_success;
 
        dprintk("lockd: LOCK          called\n");
 
@@ -153,7 +156,7 @@ nlmsvc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
        /* Don't accept new lock requests during grace period */
        if (nlmsvc_grace_period && !argp->reclaim) {
                resp->status = nlm_lck_denied_grace_period;
-               return rpc_success;
+               return rc;
        }
 
        /* Obtain client and file */
@@ -176,12 +179,13 @@ nlmsvc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
        resp->status = cast_status(nlmsvc_lock(rqstp, file, &argp->lock,
                                               argp->block, &argp->cookie));
        if (resp->status == nlm_drop_reply)
-               return rpc_drop_reply;
+               rc = rpc_drop_reply;
+       else
+               dprintk("lockd: LOCK         status %d\n", ntohl(resp->status));
 
-       dprintk("lockd: LOCK          status %d\n", ntohl(resp->status));
        nlm_release_host(host);
        nlm_release_file(file);
-       return rpc_success;
+       return rc;
 }
 
 static __be32
index 84ebba33b98d0ae2567cb79c45adbae5f9d751fb..dbbefbcd671255935c61783e5cf73d4122346cd7 100644 (file)
@@ -87,7 +87,7 @@ nlm_lookup_file(struct svc_rqst *rqstp, struct nlm_file **result,
        unsigned int    hash;
        __be32          nfserr;
 
-       nlm_debug_print_fh("nlm_file_lookup", f);
+       nlm_debug_print_fh("nlm_lookup_file", f);
 
        hash = file_hash(f);
 
index 8b8388eca05e88bde827d97bc71193247c190e86..49354b9c7dc1234779a7c21114e0c976d12e7e1d 100644 (file)
 #include <linux/syscalls.h>
 #include <linux/time.h>
 #include <linux/rcupdate.h>
+#include <linux/pid_namespace.h>
 
 #include <asm/semaphore.h>
 #include <asm/uaccess.h>
@@ -185,6 +186,7 @@ void locks_init_lock(struct file_lock *fl)
        fl->fl_fasync = NULL;
        fl->fl_owner = NULL;
        fl->fl_pid = 0;
+       fl->fl_nspid = NULL;
        fl->fl_file = NULL;
        fl->fl_flags = 0;
        fl->fl_type = 0;
@@ -553,6 +555,8 @@ static void locks_insert_lock(struct file_lock **pos, struct file_lock *fl)
 {
        list_add(&fl->fl_link, &file_lock_list);
 
+       fl->fl_nspid = get_pid(task_tgid(current));
+
        /* insert into file's list */
        fl->fl_next = *pos;
        *pos = fl;
@@ -584,6 +588,11 @@ static void locks_delete_lock(struct file_lock **thisfl_p)
        if (fl->fl_ops && fl->fl_ops->fl_remove)
                fl->fl_ops->fl_remove(fl);
 
+       if (fl->fl_nspid) {
+               put_pid(fl->fl_nspid);
+               fl->fl_nspid = NULL;
+       }
+
        locks_wake_up_blocks(fl);
        locks_free_lock(fl);
 }
@@ -634,33 +643,6 @@ static int flock_locks_conflict(struct file_lock *caller_fl, struct file_lock *s
        return (locks_conflict(caller_fl, sys_fl));
 }
 
-static int interruptible_sleep_on_locked(wait_queue_head_t *fl_wait, int timeout)
-{
-       int result = 0;
-       DECLARE_WAITQUEUE(wait, current);
-
-       __set_current_state(TASK_INTERRUPTIBLE);
-       add_wait_queue(fl_wait, &wait);
-       if (timeout == 0)
-               schedule();
-       else
-               result = schedule_timeout(timeout);
-       if (signal_pending(current))
-               result = -ERESTARTSYS;
-       remove_wait_queue(fl_wait, &wait);
-       __set_current_state(TASK_RUNNING);
-       return result;
-}
-
-static int locks_block_on_timeout(struct file_lock *blocker, struct file_lock *waiter, int time)
-{
-       int result;
-       locks_insert_block(blocker, waiter);
-       result = interruptible_sleep_on_locked(&waiter->fl_wait, time);
-       __locks_delete_block(waiter);
-       return result;
-}
-
 void
 posix_test_lock(struct file *filp, struct file_lock *fl)
 {
@@ -673,55 +655,67 @@ posix_test_lock(struct file *filp, struct file_lock *fl)
                if (posix_locks_conflict(fl, cfl))
                        break;
        }
-       if (cfl)
+       if (cfl) {
                __locks_copy_lock(fl, cfl);
-       else
+               if (cfl->fl_nspid)
+                       fl->fl_pid = pid_nr_ns(cfl->fl_nspid,
+                                               task_active_pid_ns(current));
+       } else
                fl->fl_type = F_UNLCK;
        unlock_kernel();
        return;
 }
-
 EXPORT_SYMBOL(posix_test_lock);
 
-/* This function tests for deadlock condition before putting a process to
- * sleep. The detection scheme is no longer recursive. Recursive was neat,
- * but dangerous - we risked stack corruption if the lock data was bad, or
- * if the recursion was too deep for any other reason.
+/*
+ * Deadlock detection:
+ *
+ * We attempt to detect deadlocks that are due purely to posix file
+ * locks.
  *
- * We rely on the fact that a task can only be on one lock's wait queue
- * at a time. When we find blocked_task on a wait queue we can re-search
- * with blocked_task equal to that queue's owner, until either blocked_task
- * isn't found, or blocked_task is found on a queue owned by my_task.
+ * We assume that a task can be waiting for at most one lock at a time.
+ * So for any acquired lock, the process holding that lock may be
+ * waiting on at most one other lock.  That lock in turns may be held by
+ * someone waiting for at most one other lock.  Given a requested lock
+ * caller_fl which is about to wait for a conflicting lock block_fl, we
+ * follow this chain of waiters to ensure we are not about to create a
+ * cycle.
  *
- * Note: the above assumption may not be true when handling lock requests
- * from a broken NFS client. But broken NFS clients have a lot more to
- * worry about than proper deadlock detection anyway... --okir
+ * Since we do this before we ever put a process to sleep on a lock, we
+ * are ensured that there is never a cycle; that is what guarantees that
+ * the while() loop in posix_locks_deadlock() eventually completes.
  *
- * However, the failure of this assumption (also possible in the case of
- * multiple tasks sharing the same open file table) also means there's no
- * guarantee that the loop below will terminate.  As a hack, we give up
- * after a few iterations.
+ * Note: the above assumption may not be true when handling lock
+ * requests from a broken NFS client. It may also fail in the presence
+ * of tasks (such as posix threads) sharing the same open file table.
+ *
+ * To handle those cases, we just bail out after a few iterations.
  */
 
 #define MAX_DEADLK_ITERATIONS 10
 
+/* Find a lock that the owner of the given block_fl is blocking on. */
+static struct file_lock *what_owner_is_waiting_for(struct file_lock *block_fl)
+{
+       struct file_lock *fl;
+
+       list_for_each_entry(fl, &blocked_list, fl_link) {
+               if (posix_same_owner(fl, block_fl))
+                       return fl->fl_next;
+       }
+       return NULL;
+}
+
 static int posix_locks_deadlock(struct file_lock *caller_fl,
                                struct file_lock *block_fl)
 {
-       struct file_lock *fl;
        int i = 0;
 
-next_task:
-       if (posix_same_owner(caller_fl, block_fl))
-               return 1;
-       list_for_each_entry(fl, &blocked_list, fl_link) {
-               if (posix_same_owner(fl, block_fl)) {
-                       if (i++ > MAX_DEADLK_ITERATIONS)
-                               return 0;
-                       fl = fl->fl_next;
-                       block_fl = fl;
-                       goto next_task;
-               }
+       while ((block_fl = what_owner_is_waiting_for(block_fl))) {
+               if (i++ > MAX_DEADLK_ITERATIONS)
+                       return 0;
+               if (posix_same_owner(caller_fl, block_fl))
+                       return 1;
        }
        return 0;
 }
@@ -1256,7 +1250,10 @@ restart:
                if (break_time == 0)
                        break_time++;
        }
-       error = locks_block_on_timeout(flock, new_fl, break_time);
+       locks_insert_block(flock, new_fl);
+       error = wait_event_interruptible_timeout(new_fl->fl_wait,
+                                               !new_fl->fl_next, break_time);
+       __locks_delete_block(new_fl);
        if (error >= 0) {
                if (error == 0)
                        time_out_leases(inode);
@@ -2084,6 +2081,12 @@ static void lock_get_status(struct seq_file *f, struct file_lock *fl,
                                                        int id, char *pfx)
 {
        struct inode *inode = NULL;
+       unsigned int fl_pid;
+
+       if (fl->fl_nspid)
+               fl_pid = pid_nr_ns(fl->fl_nspid, task_active_pid_ns(current));
+       else
+               fl_pid = fl->fl_pid;
 
        if (fl->fl_file != NULL)
                inode = fl->fl_file->f_path.dentry->d_inode;
@@ -2124,16 +2127,16 @@ static void lock_get_status(struct seq_file *f, struct file_lock *fl,
        }
        if (inode) {
 #ifdef WE_CAN_BREAK_LSLK_NOW
-               seq_printf(f, "%d %s:%ld ", fl->fl_pid,
+               seq_printf(f, "%d %s:%ld ", fl_pid,
                                inode->i_sb->s_id, inode->i_ino);
 #else
                /* userspace relies on this representation of dev_t ;-( */
-               seq_printf(f, "%d %02x:%02x:%ld ", fl->fl_pid,
+               seq_printf(f, "%d %02x:%02x:%ld ", fl_pid,
                                MAJOR(inode->i_sb->s_dev),
                                MINOR(inode->i_sb->s_dev), inode->i_ino);
 #endif
        } else {
-               seq_printf(f, "%d <none>:0 ", fl->fl_pid);
+               seq_printf(f, "%d <none>:0 ", fl_pid);
        }
        if (IS_POSIX(fl)) {
                if (fl->fl_end == OFFSET_MAX)
index d54f8f8972242a62e437bc904059773d2c697e6d..5df564366f36b5ea287245b3b5fd060ab1012f31 100644 (file)
@@ -276,9 +276,7 @@ do_mpage_readpage(struct bio *bio, struct page *page, unsigned nr_pages,
        }
 
        if (first_hole != blocks_per_page) {
-               zero_user_page(page, first_hole << blkbits,
-                               PAGE_CACHE_SIZE - (first_hole << blkbits),
-                               KM_USER0);
+               zero_user_segment(page, first_hole << blkbits, PAGE_CACHE_SIZE);
                if (first_hole == 0) {
                        SetPageUptodate(page);
                        unlock_page(page);
@@ -571,8 +569,7 @@ page_is_mapped:
 
                if (page->index > end_index || !offset)
                        goto confused;
-               zero_user_page(page, offset, PAGE_CACHE_SIZE - offset,
-                               KM_USER0);
+               zero_user_segment(page, offset, PAGE_CACHE_SIZE);
        }
 
        /*
index a94473d3072c606784f86cb058f5371e8b183ff1..5d8dcb9ee326ffcbb3b747666a9f44f1431f7bb8 100644 (file)
@@ -50,10 +50,6 @@ static int ncp_file_mmap_fault(struct vm_area_struct *area,
        pos = vmf->pgoff << PAGE_SHIFT;
 
        count = PAGE_SIZE;
-       if ((unsigned long)vmf->virtual_address + PAGE_SIZE > area->vm_end) {
-               WARN_ON(1); /* shouldn't happen? */
-               count = area->vm_end - (unsigned long)vmf->virtual_address;
-       }
        /* what we can read in one go */
        bufsize = NCP_SERVER(inode)->buffer_size;
 
index 9b6bbf1b978795b8ba29668db9313f1e86bb0d36..bd185a572a23aeb0d015b701d0786dab359f260a 100644 (file)
@@ -119,8 +119,8 @@ int nfs_callback_up(void)
        if (!serv)
                goto out_err;
 
-       ret = svc_makesock(serv, IPPROTO_TCP, nfs_callback_set_tcpport,
-                                                       SVC_SOCK_ANONYMOUS);
+       ret = svc_create_xprt(serv, "tcp", nfs_callback_set_tcpport,
+                             SVC_SOCK_ANONYMOUS);
        if (ret <= 0)
                goto out_destroy;
        nfs_callback_tcpport = ret;
index 685c43f810c10a476ada529d4e0a92075674ca9a..c5c0175898f68311f7a19c8c87e641de27acb30a 100644 (file)
@@ -386,7 +386,7 @@ found_client:
        if (new)
                nfs_free_client(new);
 
-       error = wait_event_interruptible(nfs_client_active_wq,
+       error = wait_event_killable(nfs_client_active_wq,
                                clp->cl_cons_state != NFS_CS_INITING);
        if (error < 0) {
                nfs_put_client(clp);
@@ -589,10 +589,6 @@ static int nfs_init_server_rpcclient(struct nfs_server *server,
        if (server->flags & NFS_MOUNT_SOFT)
                server->client->cl_softrtry = 1;
 
-       server->client->cl_intr = 0;
-       if (server->flags & NFS4_MOUNT_INTR)
-               server->client->cl_intr = 1;
-
        return 0;
 }
 
index f8e165c7d5a637de762e619e1ddd1a7db4436fb7..16844f98f50e4b6f6ad24eea74470fb6da263adf 100644 (file)
@@ -188,17 +188,12 @@ static void nfs_direct_req_release(struct nfs_direct_req *dreq)
 static ssize_t nfs_direct_wait(struct nfs_direct_req *dreq)
 {
        ssize_t result = -EIOCBQUEUED;
-       struct rpc_clnt *clnt;
-       sigset_t oldset;
 
        /* Async requests don't wait here */
        if (dreq->iocb)
                goto out;
 
-       clnt = NFS_CLIENT(dreq->inode);
-       rpc_clnt_sigmask(clnt, &oldset);
-       result = wait_for_completion_interruptible(&dreq->completion);
-       rpc_clnt_sigunmask(clnt, &oldset);
+       result = wait_for_completion_killable(&dreq->completion);
 
        if (!result)
                result = dreq->error;
index 3f332e54e760ad2056154c01491c8db9521b8319..966a8850aa30be5330a524699069718cd00932ce 100644 (file)
@@ -433,15 +433,11 @@ static int nfs_wait_schedule(void *word)
  */
 static int nfs_wait_on_inode(struct inode *inode)
 {
-       struct rpc_clnt *clnt = NFS_CLIENT(inode);
        struct nfs_inode *nfsi = NFS_I(inode);
-       sigset_t oldmask;
        int error;
 
-       rpc_clnt_sigmask(clnt, &oldmask);
        error = wait_on_bit_lock(&nfsi->flags, NFS_INO_REVALIDATING,
-                                       nfs_wait_schedule, TASK_INTERRUPTIBLE);
-       rpc_clnt_sigunmask(clnt, &oldmask);
+                                       nfs_wait_schedule, TASK_KILLABLE);
 
        return error;
 }
index 8afd9f7e7a97c075faad46eace3c3e111abb8053..49c7cd0502cc39b9411460ac7b27b6ac367781c2 100644 (file)
@@ -56,7 +56,7 @@ int nfs_mount(struct sockaddr *addr, size_t len, char *hostname, char *path,
                .program        = &mnt_program,
                .version        = version,
                .authflavor     = RPC_AUTH_UNIX,
-               .flags          = RPC_CLNT_CREATE_INTR,
+               .flags          = 0,
        };
        struct rpc_clnt         *mnt_clnt;
        int                     status;
index b353c1a05bfda77c7074fcc31d4dbac00b4c09c9..549dbce714a4bde33c55386ed18357ddf911eab4 100644 (file)
 static int
 nfs3_rpc_wrapper(struct rpc_clnt *clnt, struct rpc_message *msg, int flags)
 {
-       sigset_t oldset;
        int res;
-       rpc_clnt_sigmask(clnt, &oldset);
        do {
                res = rpc_call_sync(clnt, msg, flags);
                if (res != -EJUKEBOX)
                        break;
-               schedule_timeout_interruptible(NFS_JUKEBOX_RETRY_TIME);
+               schedule_timeout_killable(NFS_JUKEBOX_RETRY_TIME);
                res = -ERESTARTSYS;
-       } while (!signalled());
-       rpc_clnt_sigunmask(clnt, &oldset);
+       } while (!fatal_signal_pending(current));
        return res;
 }
 
index 5c189bd57eb2b6ea88bcc837bb8f821f04089fe4..027e1095256ebe09cb001d1736489a7216620d0d 100644 (file)
@@ -316,12 +316,9 @@ static void nfs4_opendata_put(struct nfs4_opendata *p)
 
 static int nfs4_wait_for_completion_rpc_task(struct rpc_task *task)
 {
-       sigset_t oldset;
        int ret;
 
-       rpc_clnt_sigmask(task->tk_client, &oldset);
        ret = rpc_wait_for_completion_task(task);
-       rpc_clnt_sigunmask(task->tk_client, &oldset);
        return ret;
 }
 
@@ -2785,9 +2782,9 @@ nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server)
        return 0;
 }
 
-static int nfs4_wait_bit_interruptible(void *word)
+static int nfs4_wait_bit_killable(void *word)
 {
-       if (signal_pending(current))
+       if (fatal_signal_pending(current))
                return -ERESTARTSYS;
        schedule();
        return 0;
@@ -2795,18 +2792,14 @@ static int nfs4_wait_bit_interruptible(void *word)
 
 static int nfs4_wait_clnt_recover(struct rpc_clnt *clnt, struct nfs_client *clp)
 {
-       sigset_t oldset;
        int res;
 
        might_sleep();
 
        rwsem_acquire(&clp->cl_sem.dep_map, 0, 0, _RET_IP_);
 
-       rpc_clnt_sigmask(clnt, &oldset);
        res = wait_on_bit(&clp->cl_state, NFS4CLNT_STATE_RECOVER,
-                       nfs4_wait_bit_interruptible,
-                       TASK_INTERRUPTIBLE);
-       rpc_clnt_sigunmask(clnt, &oldset);
+                       nfs4_wait_bit_killable, TASK_KILLABLE);
 
        rwsem_release(&clp->cl_sem.dep_map, 1, _RET_IP_);
        return res;
@@ -2814,7 +2807,6 @@ static int nfs4_wait_clnt_recover(struct rpc_clnt *clnt, struct nfs_client *clp)
 
 static int nfs4_delay(struct rpc_clnt *clnt, long *timeout)
 {
-       sigset_t oldset;
        int res = 0;
 
        might_sleep();
@@ -2823,14 +2815,9 @@ static int nfs4_delay(struct rpc_clnt *clnt, long *timeout)
                *timeout = NFS4_POLL_RETRY_MIN;
        if (*timeout > NFS4_POLL_RETRY_MAX)
                *timeout = NFS4_POLL_RETRY_MAX;
-       rpc_clnt_sigmask(clnt, &oldset);
-       if (clnt->cl_intr) {
-               schedule_timeout_interruptible(*timeout);
-               if (signalled())
-                       res = -ERESTARTSYS;
-       } else
-               schedule_timeout_uninterruptible(*timeout);
-       rpc_clnt_sigunmask(clnt, &oldset);
+       schedule_timeout_killable(*timeout);
+       if (fatal_signal_pending(current))
+               res = -ERESTARTSYS;
        *timeout <<= 1;
        return res;
 }
@@ -3069,7 +3056,7 @@ int nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4
 static unsigned long
 nfs4_set_lock_task_retry(unsigned long timeout)
 {
-       schedule_timeout_interruptible(timeout);
+       schedule_timeout_killable(timeout);
        timeout <<= 1;
        if (timeout > NFS4_LOCK_MAXTIMEOUT)
                return NFS4_LOCK_MAXTIMEOUT;
index 4b0334590ee5ebdd959fc29e629312296a767aed..531379d36823032c59740eecd738411cd4575593 100644 (file)
@@ -228,10 +228,7 @@ static int __init root_nfs_parse(char *name, char *buf)
                                nfs_data.flags &= ~NFS_MOUNT_SOFT;
                                break;
                        case Opt_intr:
-                               nfs_data.flags |= NFS_MOUNT_INTR;
-                               break;
                        case Opt_nointr:
-                               nfs_data.flags &= ~NFS_MOUNT_INTR;
                                break;
                        case Opt_posix:
                                nfs_data.flags |= NFS_MOUNT_POSIX;
index 3b3dbb94393de116c4bd8923aba8efa58bb3debb..7f079209d70a91ff79f036dbec62ace856023913 100644 (file)
@@ -58,7 +58,6 @@ nfs_create_request(struct nfs_open_context *ctx, struct inode *inode,
                   struct page *page,
                   unsigned int offset, unsigned int count)
 {
-       struct nfs_server *server = NFS_SERVER(inode);
        struct nfs_page         *req;
 
        for (;;) {
@@ -67,7 +66,7 @@ nfs_create_request(struct nfs_open_context *ctx, struct inode *inode,
                if (req != NULL)
                        break;
 
-               if (signalled() && (server->flags & NFS_MOUNT_INTR))
+               if (fatal_signal_pending(current))
                        return ERR_PTR(-ERESTARTSYS);
                yield();
        }
@@ -177,11 +176,11 @@ void nfs_release_request(struct nfs_page *req)
        kref_put(&req->wb_kref, nfs_free_request);
 }
 
-static int nfs_wait_bit_interruptible(void *word)
+static int nfs_wait_bit_killable(void *word)
 {
        int ret = 0;
 
-       if (signal_pending(current))
+       if (fatal_signal_pending(current))
                ret = -ERESTARTSYS;
        else
                schedule();
@@ -192,26 +191,18 @@ static int nfs_wait_bit_interruptible(void *word)
  * nfs_wait_on_request - Wait for a request to complete.
  * @req: request to wait upon.
  *
- * Interruptible by signals only if mounted with intr flag.
+ * Interruptible by fatal signals only.
  * The user is responsible for holding a count on the request.
  */
 int
 nfs_wait_on_request(struct nfs_page *req)
 {
-       struct rpc_clnt *clnt = NFS_CLIENT(req->wb_context->path.dentry->d_inode);
-       sigset_t oldmask;
        int ret = 0;
 
        if (!test_bit(PG_BUSY, &req->wb_flags))
                goto out;
-       /*
-        * Note: the call to rpc_clnt_sigmask() suffices to ensure that we
-        *       are not interrupted if intr flag is not set
-        */
-       rpc_clnt_sigmask(clnt, &oldmask);
        ret = out_of_line_wait_on_bit(&req->wb_flags, PG_BUSY,
-                       nfs_wait_bit_interruptible, TASK_INTERRUPTIBLE);
-       rpc_clnt_sigunmask(clnt, &oldmask);
+                       nfs_wait_bit_killable, TASK_KILLABLE);
 out:
        return ret;
 }
index 8fd6dfbe1bc3b8c248595a85fc5d3f3b86779ee3..3d7d9631e1254f7ad898863e66519740af1e34e9 100644 (file)
@@ -79,7 +79,7 @@ void nfs_readdata_release(void *data)
 static
 int nfs_return_empty_page(struct page *page)
 {
-       zero_user_page(page, 0, PAGE_CACHE_SIZE, KM_USER0);
+       zero_user(page, 0, PAGE_CACHE_SIZE);
        SetPageUptodate(page);
        unlock_page(page);
        return 0;
@@ -103,10 +103,10 @@ static void nfs_readpage_truncate_uninitialised_page(struct nfs_read_data *data)
        pglen = PAGE_CACHE_SIZE - base;
        for (;;) {
                if (remainder <= pglen) {
-                       zero_user_page(*pages, base, remainder, KM_USER0);
+                       zero_user(*pages, base, remainder);
                        break;
                }
-               zero_user_page(*pages, base, pglen, KM_USER0);
+               zero_user(*pages, base, pglen);
                pages++;
                remainder -= pglen;
                pglen = PAGE_CACHE_SIZE;
@@ -130,7 +130,7 @@ static int nfs_readpage_async(struct nfs_open_context *ctx, struct inode *inode,
                return PTR_ERR(new);
        }
        if (len < PAGE_CACHE_SIZE)
-               zero_user_page(page, len, PAGE_CACHE_SIZE - len, KM_USER0);
+               zero_user_segment(page, len, PAGE_CACHE_SIZE);
 
        nfs_list_add_request(new, &one_request);
        if (NFS_SERVER(inode)->rsize < PAGE_CACHE_SIZE)
@@ -532,7 +532,7 @@ readpage_async_filler(void *data, struct page *page)
                goto out_error;
 
        if (len < PAGE_CACHE_SIZE)
-               zero_user_page(page, len, PAGE_CACHE_SIZE - len, KM_USER0);
+               zero_user_segment(page, len, PAGE_CACHE_SIZE);
        nfs_pageio_add_request(desc->pgio, new);
        return 0;
 out_error:
index 22c49c02897d3244c8f53ffd9bb9537e90064238..7f4505f6ac6f55fd49c1a8c07bbb65ce63d41388 100644 (file)
@@ -448,7 +448,6 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss,
                const char *nostr;
        } nfs_info[] = {
                { NFS_MOUNT_SOFT, ",soft", ",hard" },
-               { NFS_MOUNT_INTR, ",intr", ",nointr" },
                { NFS_MOUNT_NOCTO, ",nocto", "" },
                { NFS_MOUNT_NOAC, ",noac", "" },
                { NFS_MOUNT_NONLM, ",nolock", "" },
@@ -708,10 +707,7 @@ static int nfs_parse_mount_options(char *raw,
                        mnt->flags &= ~NFS_MOUNT_SOFT;
                        break;
                case Opt_intr:
-                       mnt->flags |= NFS_MOUNT_INTR;
-                       break;
                case Opt_nointr:
-                       mnt->flags &= ~NFS_MOUNT_INTR;
                        break;
                case Opt_posix:
                        mnt->flags |= NFS_MOUNT_POSIX;
index 5ac5b27b639a85decb94b5d49c72aeb46361a9ff..b144b1957dd99f7e011e7f635454f4d9215e4757 100644 (file)
@@ -488,7 +488,7 @@ int nfs_reschedule_unstable_write(struct nfs_page *req)
 /*
  * Wait for a request to complete.
  *
- * Interruptible by signals only if mounted with intr flag.
+ * Interruptible by fatal signals only.
  */
 static int nfs_wait_on_requests_locked(struct inode *inode, pgoff_t idx_start, unsigned int npages)
 {
@@ -665,9 +665,7 @@ zero_page:
         * then we need to zero any uninitalised data. */
        if (req->wb_pgbase == 0 && req->wb_bytes != PAGE_CACHE_SIZE
                        && !PageUptodate(req->wb_page))
-               zero_user_page(req->wb_page, req->wb_bytes,
-                               PAGE_CACHE_SIZE - req->wb_bytes,
-                               KM_USER0);
+               zero_user_segment(req->wb_page, req->wb_bytes, PAGE_CACHE_SIZE);
        return req;
 }
 
index 21928056e35ecad1c8aa5cb656d9d495df6a3022..d13403e33622eaade5d483d4453f7d58ff4b9a8f 100644 (file)
@@ -11,8 +11,6 @@
 #include <linux/nfsd/nfsd.h>
 #include <linux/nfsd/export.h>
 
-#define        CAP_NFSD_MASK (CAP_FS_MASK|CAP_TO_MASK(CAP_SYS_RESOURCE))
-
 int nfsexp_flags(struct svc_rqst *rqstp, struct svc_export *exp)
 {
        struct exp_flavor_info *f;
@@ -69,10 +67,12 @@ int nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp)
        ret = set_current_groups(cred.cr_group_info);
        put_group_info(cred.cr_group_info);
        if ((cred.cr_uid)) {
-               cap_t(current->cap_effective) &= ~CAP_NFSD_MASK;
+               current->cap_effective =
+                       cap_drop_nfsd_set(current->cap_effective);
        } else {
-               cap_t(current->cap_effective) |= (CAP_NFSD_MASK &
-                                                 current->cap_permitted);
+               current->cap_effective =
+                       cap_raise_nfsd_set(current->cap_effective,
+                                          current->cap_permitted);
        }
        return ret;
 }
similarity index 87%
rename from include/linux/nfsd/auth.h
rename to fs/nfsd/auth.h
index 0fb9f7212195383e47c5354b33e7399ee29a75c0..78b3c0e9382279a5205cbb3e90dc86811a85a10c 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * include/linux/nfsd/auth.h
- *
  * nfsd-specific authentication stuff.
  * uid/gid mapping not yet implemented.
  *
@@ -10,8 +8,6 @@
 #ifndef LINUX_NFSD_AUTH_H
 #define LINUX_NFSD_AUTH_H
 
-#ifdef __KERNEL__
-
 #define nfsd_luid(rq, uid)     ((u32)(uid))
 #define nfsd_lgid(rq, gid)     ((u32)(gid))
 #define nfsd_ruid(rq, uid)     ((u32)(uid))
@@ -23,5 +19,4 @@
  */
 int nfsd_setuser(struct svc_rqst *, struct svc_export *);
 
-#endif /* __KERNEL__ */
 #endif /* LINUX_NFSD_AUTH_H */
index 66d0aeb32a47e5f4385e68c1947a8d8c1ab3a7e5..79b4bf8129602b9ebbbec979960d614e90b7185b 100644 (file)
@@ -1357,8 +1357,6 @@ exp_pseudoroot(struct svc_rqst *rqstp, struct svc_fh *fhp)
        mk_fsid(FSID_NUM, fsidv, 0, 0, 0, NULL);
 
        exp = rqst_exp_find(rqstp, FSID_NUM, fsidv);
-       if (PTR_ERR(exp) == -ENOENT)
-               return nfserr_perm;
        if (IS_ERR(exp))
                return nfserrno(PTR_ERR(exp));
        rv = fh_compose(fhp, exp, exp->ex_dentry, NULL);
@@ -1637,13 +1635,19 @@ exp_verify_string(char *cp, int max)
 /*
  * Initialize the exports module.
  */
-void
+int
 nfsd_export_init(void)
 {
+       int rv;
        dprintk("nfsd: initializing export module.\n");
 
-       cache_register(&svc_export_cache);
-       cache_register(&svc_expkey_cache);
+       rv = cache_register(&svc_export_cache);
+       if (rv)
+               return rv;
+       rv = cache_register(&svc_expkey_cache);
+       if (rv)
+               cache_unregister(&svc_export_cache);
+       return rv;
 
 }
 
@@ -1670,10 +1674,8 @@ nfsd_export_shutdown(void)
 
        exp_writelock();
 
-       if (cache_unregister(&svc_expkey_cache))
-               printk(KERN_ERR "nfsd: failed to unregister expkey cache\n");
-       if (cache_unregister(&svc_export_cache))
-               printk(KERN_ERR "nfsd: failed to unregister export cache\n");
+       cache_unregister(&svc_expkey_cache);
+       cache_unregister(&svc_export_cache);
        svcauth_unix_purge();
 
        exp_writeunlock();
index 0e5fa11e6b44c4fa114e5e48ef0408a4227a5c07..1c3b7654e966d9f02cd46d8284ee636e670dd882 100644 (file)
@@ -221,12 +221,17 @@ static int nfsaclsvc_encode_getaclres(struct svc_rqst *rqstp, __be32 *p,
                struct nfsd3_getaclres *resp)
 {
        struct dentry *dentry = resp->fh.fh_dentry;
-       struct inode *inode = dentry->d_inode;
+       struct inode *inode;
        struct kvec *head = rqstp->rq_res.head;
        unsigned int base;
        int n;
        int w;
 
+       /*
+        * Since this is version 2, the check for nfserr in
+        * nfsd_dispatch actually ensures the following cannot happen.
+        * However, it seems fragile to depend on that.
+        */
        if (dentry == NULL || dentry->d_inode == NULL)
                return 0;
        inode = dentry->d_inode;
index f917fd25858af81a4edaf712fffa3480ee3a8e6b..d7647f70e02b0b2cf219577a67ebdff68ce73116 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/sunrpc/svc.h>
 #include <linux/nfsd/nfsd.h>
 #include <linux/nfsd/xdr3.h>
+#include "auth.h"
 
 #define NFSDDBG_FACILITY               NFSDDBG_XDR
 
@@ -88,10 +89,10 @@ encode_fh(__be32 *p, struct svc_fh *fhp)
  * no slashes or null bytes.
  */
 static __be32 *
-decode_filename(__be32 *p, char **namp, int *lenp)
+decode_filename(__be32 *p, char **namp, unsigned int *lenp)
 {
        char            *name;
-       int             i;
+       unsigned int    i;
 
        if ((p = xdr_decode_string_inplace(p, namp, lenp, NFS3_MAXNAMLEN)) != NULL) {
                for (i = 0, name = *namp; i < *lenp; i++, name++) {
@@ -452,8 +453,7 @@ int
 nfs3svc_decode_symlinkargs(struct svc_rqst *rqstp, __be32 *p,
                                        struct nfsd3_symlinkargs *args)
 {
-       unsigned int len;
-       int avail;
+       unsigned int len, avail;
        char *old, *new;
        struct kvec *vec;
 
@@ -486,7 +486,8 @@ nfs3svc_decode_symlinkargs(struct svc_rqst *rqstp, __be32 *p,
        /* now copy next page if there is one */
        if (len && !avail && rqstp->rq_arg.page_len) {
                avail = rqstp->rq_arg.page_len;
-               if (avail > PAGE_SIZE) avail = PAGE_SIZE;
+               if (avail > PAGE_SIZE)
+                       avail = PAGE_SIZE;
                old = page_address(rqstp->rq_arg.pages[0]);
        }
        while (len && avail && *old) {
@@ -816,11 +817,11 @@ static __be32 *
 encode_entryplus_baggage(struct nfsd3_readdirres *cd, __be32 *p,
                struct svc_fh *fhp)
 {
-               p = encode_post_op_attr(cd->rqstp, p, fhp);
-               *p++ = xdr_one;                 /* yes, a file handle follows */
-               p = encode_fh(p, fhp);
-               fh_put(fhp);
-               return p;
+       p = encode_post_op_attr(cd->rqstp, p, fhp);
+       *p++ = xdr_one;                 /* yes, a file handle follows */
+       p = encode_fh(p, fhp);
+       fh_put(fhp);
+       return p;
 }
 
 static int
index 9d536a8cb3795651551af7b228407a09d890f7b7..aae2b29ae2c9e6d4b645f91bf68b50046030accc 100644 (file)
@@ -350,30 +350,6 @@ static struct rpc_version *        nfs_cb_version[] = {
 static int do_probe_callback(void *data)
 {
        struct nfs4_client *clp = data;
-       struct nfs4_callback *cb = &clp->cl_callback;
-       struct rpc_message msg = {
-               .rpc_proc       = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_NULL],
-               .rpc_argp       = clp,
-       };
-       int status;
-
-       status = rpc_call_sync(cb->cb_client, &msg, RPC_TASK_SOFT);
-
-       if (status) {
-               rpc_shutdown_client(cb->cb_client);
-               cb->cb_client = NULL;
-       } else
-               atomic_set(&cb->cb_set, 1);
-       put_nfs4_client(clp);
-       return 0;
-}
-
-/*
- * Set up the callback client and put a NFSPROC4_CB_NULL on the wire...
- */
-void
-nfsd4_probe_callback(struct nfs4_client *clp)
-{
        struct sockaddr_in      addr;
        struct nfs4_callback    *cb = &clp->cl_callback;
        struct rpc_timeout      timeparms = {
@@ -390,13 +366,15 @@ nfsd4_probe_callback(struct nfs4_client *clp)
                .timeout        = &timeparms,
                .program        = program,
                .version        = nfs_cb_version[1]->number,
-               .authflavor     = RPC_AUTH_UNIX,        /* XXX: need AUTH_GSS... */
+               .authflavor     = RPC_AUTH_UNIX, /* XXX: need AUTH_GSS... */
                .flags          = (RPC_CLNT_CREATE_NOPING),
        };
-       struct task_struct *t;
-
-       if (atomic_read(&cb->cb_set))
-               return;
+       struct rpc_message msg = {
+               .rpc_proc       = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_NULL],
+               .rpc_argp       = clp,
+       };
+       struct rpc_clnt *client;
+       int status;
 
        /* Initialize address */
        memset(&addr, 0, sizeof(addr));
@@ -416,29 +394,50 @@ nfsd4_probe_callback(struct nfs4_client *clp)
        program->stats->program = program;
 
        /* Create RPC client */
-       cb->cb_client = rpc_create(&args);
-       if (IS_ERR(cb->cb_client)) {
+       client = rpc_create(&args);
+       if (IS_ERR(client)) {
                dprintk("NFSD: couldn't create callback client\n");
+               status = PTR_ERR(client);
                goto out_err;
        }
 
+       status = rpc_call_sync(client, &msg, RPC_TASK_SOFT);
+
+       if (status)
+               goto out_release_client;
+
+       cb->cb_client = client;
+       atomic_set(&cb->cb_set, 1);
+       put_nfs4_client(clp);
+       return 0;
+out_release_client:
+       rpc_shutdown_client(client);
+out_err:
+       put_nfs4_client(clp);
+       dprintk("NFSD: warning: no callback path to client %.*s\n",
+               (int)clp->cl_name.len, clp->cl_name.data);
+       return status;
+}
+
+/*
+ * Set up the callback client and put a NFSPROC4_CB_NULL on the wire...
+ */
+void
+nfsd4_probe_callback(struct nfs4_client *clp)
+{
+       struct task_struct *t;
+
+       BUG_ON(atomic_read(&clp->cl_callback.cb_set));
+
        /* the task holds a reference to the nfs4_client struct */
        atomic_inc(&clp->cl_count);
 
        t = kthread_run(do_probe_callback, clp, "nfs4_cb_probe");
 
        if (IS_ERR(t))
-               goto out_release_clp;
+               atomic_dec(&clp->cl_count);
 
        return;
-
-out_release_clp:
-       atomic_dec(&clp->cl_count);
-       rpc_shutdown_client(cb->cb_client);
-out_err:
-       cb->cb_client = NULL;
-       dprintk("NFSD: warning: no callback path to client %.*s\n",
-               (int)clp->cl_name.len, clp->cl_name.data);
 }
 
 /*
@@ -458,9 +457,6 @@ nfsd4_cb_recall(struct nfs4_delegation *dp)
        int retries = 1;
        int status = 0;
 
-       if ((!atomic_read(&clp->cl_callback.cb_set)) || !clnt)
-               return;
-
        cbr->cbr_trunc = 0; /* XXX need to implement truncate optimization */
        cbr->cbr_dp = dp;
 
@@ -469,6 +465,7 @@ nfsd4_cb_recall(struct nfs4_delegation *dp)
                switch (status) {
                        case -EIO:
                                /* Network partition? */
+                               atomic_set(&clp->cl_callback.cb_set, 0);
                        case -EBADHANDLE:
                        case -NFS4ERR_BAD_STATEID:
                                /* Race: client probably got cb_recall
@@ -481,11 +478,10 @@ nfsd4_cb_recall(struct nfs4_delegation *dp)
                status = rpc_call_sync(clnt, &msg, RPC_TASK_SOFT);
        }
 out_put_cred:
-       if (status == -EIO)
-               atomic_set(&clp->cl_callback.cb_set, 0);
-       /* Success or failure, now we're either waiting for lease expiration
-        * or deleg_return. */
-       dprintk("NFSD: nfs4_cb_recall: dp %p dl_flock %p dl_count %d\n",dp, dp->dl_flock, atomic_read(&dp->dl_count));
+       /*
+        * Success or failure, now we're either waiting for lease expiration
+        * or deleg_return.
+        */
        put_nfs4_client(clp);
        nfs4_put_delegation(dp);
        return;
index 4c0c683ce07a8be9852f06370dfad35d3591a45a..996bd88b75ba4d4e094129d6e856c561f6843b57 100644 (file)
@@ -255,13 +255,10 @@ idtoname_parse(struct cache_detail *cd, char *buf, int buflen)
                goto out;
        if (len == 0)
                set_bit(CACHE_NEGATIVE, &ent.h.flags);
-       else {
-               if (error >= IDMAP_NAMESZ) {
-                       error = -EINVAL;
-                       goto out;
-               }
+       else if (len >= IDMAP_NAMESZ)
+               goto out;
+       else
                memcpy(ent.name, buf1, sizeof(ent.name));
-       }
        error = -ENOMEM;
        res = idtoname_update(&ent, res);
        if (res == NULL)
@@ -467,20 +464,25 @@ nametoid_update(struct ent *new, struct ent *old)
  * Exported API
  */
 
-void
+int
 nfsd_idmap_init(void)
 {
-       cache_register(&idtoname_cache);
-       cache_register(&nametoid_cache);
+       int rv;
+
+       rv = cache_register(&idtoname_cache);
+       if (rv)
+               return rv;
+       rv = cache_register(&nametoid_cache);
+       if (rv)
+               cache_unregister(&idtoname_cache);
+       return rv;
 }
 
 void
 nfsd_idmap_shutdown(void)
 {
-       if (cache_unregister(&idtoname_cache))
-               printk(KERN_ERR "nfsd: failed to unregister idtoname cache\n");
-       if (cache_unregister(&nametoid_cache))
-               printk(KERN_ERR "nfsd: failed to unregister nametoid cache\n");
+       cache_unregister(&idtoname_cache);
+       cache_unregister(&nametoid_cache);
 }
 
 /*
index 18ead1790bb388461b08d42e3e5fcc5c1d1807cd..c593db047d8bbd51babb22bbacc765f65636ff68 100644 (file)
@@ -750,7 +750,7 @@ _nfsd4_verify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
                                    cstate->current_fh.fh_export,
                                    cstate->current_fh.fh_dentry, buf,
                                    &count, verify->ve_bmval,
-                                   rqstp);
+                                   rqstp, 0);
 
        /* this means that nfsd4_encode_fattr() ran out of space */
        if (status == nfserr_resource && count == 0)
index 31673cd251c3c2936b99e566a34773f5a0dce0c1..f6744bc03dae28e5249132ccc719a47e25ffeb63 100644 (file)
@@ -61,7 +61,6 @@ static time_t lease_time = 90;     /* default lease time */
 static time_t user_lease_time = 90;
 static time_t boot_time;
 static int in_grace = 1;
-static u32 current_clientid = 1;
 static u32 current_ownerid = 1;
 static u32 current_fileid = 1;
 static u32 current_delegid = 1;
@@ -340,21 +339,20 @@ STALE_CLIENTID(clientid_t *clid)
  * This type of memory management is somewhat inefficient, but we use it
  * anyway since SETCLIENTID is not a common operation.
  */
-static inline struct nfs4_client *
-alloc_client(struct xdr_netobj name)
+static struct nfs4_client *alloc_client(struct xdr_netobj name)
 {
        struct nfs4_client *clp;
 
-       if ((clp = kzalloc(sizeof(struct nfs4_client), GFP_KERNEL))!= NULL) {
-               if ((clp->cl_name.data = kmalloc(name.len, GFP_KERNEL)) != NULL) {
-                       memcpy(clp->cl_name.data, name.data, name.len);
-                       clp->cl_name.len = name.len;
-               }
-               else {
-                       kfree(clp);
-                       clp = NULL;
-               }
+       clp = kzalloc(sizeof(struct nfs4_client), GFP_KERNEL);
+       if (clp == NULL)
+               return NULL;
+       clp->cl_name.data = kmalloc(name.len, GFP_KERNEL);
+       if (clp->cl_name.data == NULL) {
+               kfree(clp);
+               return NULL;
        }
+       memcpy(clp->cl_name.data, name.data, name.len);
+       clp->cl_name.len = name.len;
        return clp;
 }
 
@@ -363,8 +361,11 @@ shutdown_callback_client(struct nfs4_client *clp)
 {
        struct rpc_clnt *clnt = clp->cl_callback.cb_client;
 
-       /* shutdown rpc client, ending any outstanding recall rpcs */
        if (clnt) {
+               /*
+                * Callback threads take a reference on the client, so there
+                * should be no outstanding callbacks at this point.
+                */
                clp->cl_callback.cb_client = NULL;
                rpc_shutdown_client(clnt);
        }
@@ -422,12 +423,13 @@ expire_client(struct nfs4_client *clp)
        put_nfs4_client(clp);
 }
 
-static struct nfs4_client *
-create_client(struct xdr_netobj name, char *recdir) {
+static struct nfs4_client *create_client(struct xdr_netobj name, char *recdir)
+{
        struct nfs4_client *clp;
 
-       if (!(clp = alloc_client(name)))
-               goto out;
+       clp = alloc_client(name);
+       if (clp == NULL)
+               return NULL;
        memcpy(clp->cl_recdir, recdir, HEXDIR_LEN);
        atomic_set(&clp->cl_count, 1);
        atomic_set(&clp->cl_callback.cb_set, 0);
@@ -436,32 +438,30 @@ create_client(struct xdr_netobj name, char *recdir) {
        INIT_LIST_HEAD(&clp->cl_openowners);
        INIT_LIST_HEAD(&clp->cl_delegations);
        INIT_LIST_HEAD(&clp->cl_lru);
-out:
        return clp;
 }
 
-static void
-copy_verf(struct nfs4_client *target, nfs4_verifier *source) {
-       memcpy(target->cl_verifier.data, source->data, sizeof(target->cl_verifier.data));
+static void copy_verf(struct nfs4_client *target, nfs4_verifier *source)
+{
+       memcpy(target->cl_verifier.data, source->data,
+                       sizeof(target->cl_verifier.data));
 }
 
-static void
-copy_clid(struct nfs4_client *target, struct nfs4_client *source) {
+static void copy_clid(struct nfs4_client *target, struct nfs4_client *source)
+{
        target->cl_clientid.cl_boot = source->cl_clientid.cl_boot; 
        target->cl_clientid.cl_id = source->cl_clientid.cl_id; 
 }
 
-static void
-copy_cred(struct svc_cred *target, struct svc_cred *source) {
-
+static void copy_cred(struct svc_cred *target, struct svc_cred *source)
+{
        target->cr_uid = source->cr_uid;
        target->cr_gid = source->cr_gid;
        target->cr_group_info = source->cr_group_info;
        get_group_info(target->cr_group_info);
 }
 
-static inline int
-same_name(const char *n1, const char *n2)
+static int same_name(const char *n1, const char *n2)
 {
        return 0 == memcmp(n1, n2, HEXDIR_LEN);
 }
@@ -485,26 +485,26 @@ same_creds(struct svc_cred *cr1, struct svc_cred *cr2)
        return cr1->cr_uid == cr2->cr_uid;
 }
 
-static void
-gen_clid(struct nfs4_client *clp) {
+static void gen_clid(struct nfs4_client *clp)
+{
+       static u32 current_clientid = 1;
+
        clp->cl_clientid.cl_boot = boot_time;
        clp->cl_clientid.cl_id = current_clientid++; 
 }
 
-static void
-gen_confirm(struct nfs4_client *clp) {
-       struct timespec         tv;
-       u32 *                   p;
+static void gen_confirm(struct nfs4_client *clp)
+{
+       static u32 i;
+       u32 *p;
 
-       tv = CURRENT_TIME;
        p = (u32 *)clp->cl_confirm.data;
-       *p++ = tv.tv_sec;
-       *p++ = tv.tv_nsec;
+       *p++ = get_seconds();
+       *p++ = i++;
 }
 
-static int
-check_name(struct xdr_netobj name) {
-
+static int check_name(struct xdr_netobj name)
+{
        if (name.len == 0) 
                return 0;
        if (name.len > NFS4_OPAQUE_LIMIT) {
@@ -683,39 +683,6 @@ out_err:
        return;
 }
 
-/*
- * RFC 3010 has a complex implmentation description of processing a 
- * SETCLIENTID request consisting of 5 bullets, labeled as 
- * CASE0 - CASE4 below.
- *
- * NOTES:
- *     callback information will be processed in a future patch
- *
- *     an unconfirmed record is added when:
- *      NORMAL (part of CASE 4): there is no confirmed nor unconfirmed record.
- *     CASE 1: confirmed record found with matching name, principal,
- *             verifier, and clientid.
- *     CASE 2: confirmed record found with matching name, principal,
- *             and there is no unconfirmed record with matching
- *             name and principal
- *
- *      an unconfirmed record is replaced when:
- *     CASE 3: confirmed record found with matching name, principal,
- *             and an unconfirmed record is found with matching 
- *             name, principal, and with clientid and
- *             confirm that does not match the confirmed record.
- *     CASE 4: there is no confirmed record with matching name and 
- *             principal. there is an unconfirmed record with 
- *             matching name, principal.
- *
- *     an unconfirmed record is deleted when:
- *     CASE 1: an unconfirmed record that matches input name, verifier,
- *             and confirmed clientid.
- *     CASE 4: any unconfirmed records with matching name and principal
- *             that exist after an unconfirmed record has been replaced
- *             as described above.
- *
- */
 __be32
 nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
                  struct nfsd4_setclientid *setclid)
@@ -748,11 +715,7 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
        nfs4_lock_state();
        conf = find_confirmed_client_by_str(dname, strhashval);
        if (conf) {
-               /* 
-                * CASE 0:
-                * clname match, confirmed, different principal
-                * or different ip_address
-                */
+               /* RFC 3530 14.2.33 CASE 0: */
                status = nfserr_clid_inuse;
                if (!same_creds(&conf->cl_cred, &rqstp->rq_cred)
                                || conf->cl_addr != sin->sin_addr.s_addr) {
@@ -761,12 +724,17 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
                        goto out;
                }
        }
+       /*
+        * section 14.2.33 of RFC 3530 (under the heading "IMPLEMENTATION")
+        * has a description of SETCLIENTID request processing consisting
+        * of 5 bullet points, labeled as CASE0 - CASE4 below.
+        */
        unconf = find_unconfirmed_client_by_str(dname, strhashval);
        status = nfserr_resource;
        if (!conf) {
-               /* 
-                * CASE 4:
-                * placed first, because it is the normal case.
+               /*
+                * RFC 3530 14.2.33 CASE 4:
+                * placed first, because it is the normal case
                 */
                if (unconf)
                        expire_client(unconf);
@@ -776,17 +744,8 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
                gen_clid(new);
        } else if (same_verf(&conf->cl_verifier, &clverifier)) {
                /*
-                * CASE 1:
-                * cl_name match, confirmed, principal match
-                * verifier match: probable callback update
-                *
-                * remove any unconfirmed nfs4_client with 
-                * matching cl_name, cl_verifier, and cl_clientid
-                *
-                * create and insert an unconfirmed nfs4_client with same 
-                * cl_name, cl_verifier, and cl_clientid as existing 
-                * nfs4_client,  but with the new callback info and a 
-                * new cl_confirm
+                * RFC 3530 14.2.33 CASE 1:
+                * probable callback update
                 */
                if (unconf) {
                        /* Note this is removing unconfirmed {*x***},
@@ -802,43 +761,25 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
                copy_clid(new, conf);
        } else if (!unconf) {
                /*
-                * CASE 2:
-                * clname match, confirmed, principal match
-                * verfier does not match
-                * no unconfirmed. create a new unconfirmed nfs4_client
-                * using input clverifier, clname, and callback info
-                * and generate a new cl_clientid and cl_confirm.
+                * RFC 3530 14.2.33 CASE 2:
+                * probable client reboot; state will be removed if
+                * confirmed.
                 */
                new = create_client(clname, dname);
                if (new == NULL)
                        goto out;
                gen_clid(new);
-       } else if (!same_verf(&conf->cl_confirm, &unconf->cl_confirm)) {
-               /*      
-                * CASE3:
-                * confirmed found (name, principal match)
-                * confirmed verifier does not match input clverifier
-                *
-                * unconfirmed found (name match)
-                * confirmed->cl_confirm != unconfirmed->cl_confirm
-                *
-                * remove unconfirmed.
-                *
-                * create an unconfirmed nfs4_client 
-                * with same cl_name as existing confirmed nfs4_client, 
-                * but with new callback info, new cl_clientid,
-                * new cl_verifier and a new cl_confirm
+       } else {
+               /*
+                * RFC 3530 14.2.33 CASE 3:
+                * probable client reboot; state will be removed if
+                * confirmed.
                 */
                expire_client(unconf);
                new = create_client(clname, dname);
                if (new == NULL)
                        goto out;
                gen_clid(new);
-       } else {
-               /* No cases hit !!! */
-               status = nfserr_inval;
-               goto out;
-
        }
        copy_verf(new, &clverifier);
        new->cl_addr = sin->sin_addr.s_addr;
@@ -857,11 +798,9 @@ out:
 
 
 /*
- * RFC 3010 has a complex implmentation description of processing a 
- * SETCLIENTID_CONFIRM request consisting of 4 bullets describing
- * processing on a DRC miss, labeled as CASE1 - CASE4 below.
- *
- * NOTE: callback information will be processed here in a future patch
+ * Section 14.2.34 of RFC 3530 (under the heading "IMPLEMENTATION") has
+ * a description of SETCLIENTID_CONFIRM request processing consisting of 4
+ * bullets, labeled as CASE1 - CASE4 below.
  */
 __be32
 nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
@@ -892,16 +831,16 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
        if (unconf && unconf->cl_addr != sin->sin_addr.s_addr)
                goto out;
 
-       if ((conf && unconf) && 
-           (same_verf(&unconf->cl_confirm, &confirm)) &&
-           (same_verf(&conf->cl_verifier, &unconf->cl_verifier)) &&
-           (same_name(conf->cl_recdir,unconf->cl_recdir))  &&
-           (!same_verf(&conf->cl_confirm, &unconf->cl_confirm))) {
-               /* CASE 1:
-               * unconf record that matches input clientid and input confirm.
-               * conf record that matches input clientid.
-               * conf and unconf records match names, verifiers
-               */
+       /*
+        * section 14.2.34 of RFC 3530 has a description of
+        * SETCLIENTID_CONFIRM request processing consisting
+        * of 4 bullet points, labeled as CASE1 - CASE4 below.
+        */
+       if (conf && unconf && same_verf(&confirm, &unconf->cl_confirm)) {
+               /*
+                * RFC 3530 14.2.34 CASE 1:
+                * callback update
+                */
                if (!same_creds(&conf->cl_cred, &unconf->cl_cred))
                        status = nfserr_clid_inuse;
                else {
@@ -914,15 +853,11 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
                        status = nfs_ok;
 
                }
-       } else if ((conf && !unconf) ||
-           ((conf && unconf) && 
-            (!same_verf(&conf->cl_verifier, &unconf->cl_verifier) ||
-             !same_name(conf->cl_recdir, unconf->cl_recdir)))) {
-               /* CASE 2:
-                * conf record that matches input clientid.
-                * if unconf record matches input clientid, then
-                * unconf->cl_name or unconf->cl_verifier don't match the
-                * conf record.
+       } else if (conf && !unconf) {
+               /*
+                * RFC 3530 14.2.34 CASE 2:
+                * probable retransmitted request; play it safe and
+                * do nothing.
                 */
                if (!same_creds(&conf->cl_cred, &rqstp->rq_cred))
                        status = nfserr_clid_inuse;
@@ -930,10 +865,9 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
                        status = nfs_ok;
        } else if (!conf && unconf
                        && same_verf(&unconf->cl_confirm, &confirm)) {
-               /* CASE 3:
-                * conf record not found.
-                * unconf record found.
-                * unconf->cl_confirm matches input confirm
+               /*
+                * RFC 3530 14.2.34 CASE 3:
+                * Normal case; new or rebooted client:
                 */
                if (!same_creds(&unconf->cl_cred, &rqstp->rq_cred)) {
                        status = nfserr_clid_inuse;
@@ -948,16 +882,15 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
                        }
                        move_to_confirmed(unconf);
                        conf = unconf;
+                       nfsd4_probe_callback(conf);
                        status = nfs_ok;
                }
        } else if ((!conf || (conf && !same_verf(&conf->cl_confirm, &confirm)))
            && (!unconf || (unconf && !same_verf(&unconf->cl_confirm,
                                                                &confirm)))) {
-               /* CASE 4:
-                * conf record not found, or if conf, conf->cl_confirm does not
-                * match input confirm.
-                * unconf record not found, or if unconf, unconf->cl_confirm
-                * does not match input confirm.
+               /*
+                * RFC 3530 14.2.34 CASE 4:
+                * Client probably hasn't noticed that we rebooted yet.
                 */
                status = nfserr_stale_clientid;
        } else {
@@ -965,8 +898,6 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
                status = nfserr_clid_inuse;
        }
 out:
-       if (!status)
-               nfsd4_probe_callback(conf);
        nfs4_unlock_state();
        return status;
 }
@@ -1226,14 +1157,19 @@ find_file(struct inode *ino)
        return NULL;
 }
 
-static int access_valid(u32 x)
+static inline int access_valid(u32 x)
 {
-       return (x > 0 && x < 4);
+       if (x < NFS4_SHARE_ACCESS_READ)
+               return 0;
+       if (x > NFS4_SHARE_ACCESS_BOTH)
+               return 0;
+       return 1;
 }
 
-static int deny_valid(u32 x)
+static inline int deny_valid(u32 x)
 {
-       return (x >= 0 && x < 5);
+       /* Note: unlike access bits, deny bits may be zero. */
+       return x <= NFS4_SHARE_DENY_BOTH;
 }
 
 static void
@@ -2162,8 +2098,10 @@ nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *statei
                goto check_replay;
        }
 
+       *stpp = stp;
+       *sopp = sop = stp->st_stateowner;
+
        if (lock) {
-               struct nfs4_stateowner *sop = stp->st_stateowner;
                clientid_t *lockclid = &lock->v.new.clientid;
                struct nfs4_client *clp = sop->so_client;
                int lkflg = 0;
@@ -2193,9 +2131,6 @@ nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *statei
                return nfserr_bad_stateid;
        }
 
-       *stpp = stp;
-       *sopp = sop = stp->st_stateowner;
-
        /*
        *  We now validate the seqid and stateid generation numbers.
        *  For the moment, we ignore the possibility of 
index 57333944af7fe5c63937472088c29b4725f006d2..b0592e7c378dbdf29878528bdfd8e3def4c744ad 100644 (file)
@@ -148,12 +148,12 @@ xdr_error:                                        \
        }                                       \
 } while (0)
 
-static __be32 *read_buf(struct nfsd4_compoundargs *argp, int nbytes)
+static __be32 *read_buf(struct nfsd4_compoundargs *argp, u32 nbytes)
 {
        /* We want more bytes than seem to be available.
         * Maybe we need a new page, maybe we have just run out
         */
-       int avail = (char*)argp->end - (char*)argp->p;
+       unsigned int avail = (char *)argp->end - (char *)argp->p;
        __be32 *p;
        if (avail + argp->pagelen < nbytes)
                return NULL;
@@ -169,6 +169,11 @@ static __be32 *read_buf(struct nfsd4_compoundargs *argp, int nbytes)
                        return NULL;
                
        }
+       /*
+        * The following memcpy is safe because read_buf is always
+        * called with nbytes > avail, and the two cases above both
+        * guarantee p points to at least nbytes bytes.
+        */
        memcpy(p, argp->p, avail);
        /* step to next page */
        argp->p = page_address(argp->pagelist[0]);
@@ -1448,7 +1453,7 @@ static __be32 fattr_handle_absent_fs(u32 *bmval0, u32 *bmval1, u32 *rdattr_err)
 __be32
 nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
                struct dentry *dentry, __be32 *buffer, int *countp, u32 *bmval,
-               struct svc_rqst *rqstp)
+               struct svc_rqst *rqstp, int ignore_crossmnt)
 {
        u32 bmval0 = bmval[0];
        u32 bmval1 = bmval[1];
@@ -1828,7 +1833,12 @@ out_acl:
        if (bmval1 & FATTR4_WORD1_MOUNTED_ON_FILEID) {
                if ((buflen -= 8) < 0)
                        goto out_resource;
-               if (exp->ex_mnt->mnt_root->d_inode == dentry->d_inode) {
+               /*
+                * Get parent's attributes if not ignoring crossmount
+                * and this is the root of a cross-mounted filesystem.
+                */
+               if (ignore_crossmnt == 0 &&
+                   exp->ex_mnt->mnt_root->d_inode == dentry->d_inode) {
                        err = vfs_getattr(exp->ex_mnt->mnt_parent,
                                exp->ex_mnt->mnt_mountpoint, &stat);
                        if (err)
@@ -1864,13 +1874,25 @@ nfsd4_encode_dirent_fattr(struct nfsd4_readdir *cd,
        struct svc_export *exp = cd->rd_fhp->fh_export;
        struct dentry *dentry;
        __be32 nfserr;
+       int ignore_crossmnt = 0;
 
        dentry = lookup_one_len(name, cd->rd_fhp->fh_dentry, namlen);
        if (IS_ERR(dentry))
                return nfserrno(PTR_ERR(dentry));
 
        exp_get(exp);
-       if (d_mountpoint(dentry)) {
+       /*
+        * In the case of a mountpoint, the client may be asking for
+        * attributes that are only properties of the underlying filesystem
+        * as opposed to the cross-mounted file system. In such a case,
+        * we will not follow the cross mount and will fill the attribtutes
+        * directly from the mountpoint dentry.
+        */
+       if (d_mountpoint(dentry) &&
+           (cd->rd_bmval[0] & ~FATTR4_WORD0_RDATTR_ERROR) == 0 &&
+           (cd->rd_bmval[1] & ~FATTR4_WORD1_MOUNTED_ON_FILEID) == 0)
+               ignore_crossmnt = 1;
+       else if (d_mountpoint(dentry)) {
                int err;
 
                /*
@@ -1889,7 +1911,7 @@ nfsd4_encode_dirent_fattr(struct nfsd4_readdir *cd,
 
        }
        nfserr = nfsd4_encode_fattr(NULL, exp, dentry, p, buflen, cd->rd_bmval,
-                                       cd->rd_rqstp);
+                                       cd->rd_rqstp, ignore_crossmnt);
 out_put:
        dput(dentry);
        exp_put(exp);
@@ -2043,7 +2065,7 @@ nfsd4_encode_getattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4
        buflen = resp->end - resp->p - (COMPOUND_ERR_SLACK_SPACE >> 2);
        nfserr = nfsd4_encode_fattr(fhp, fhp->fh_export, fhp->fh_dentry,
                                    resp->p, &buflen, getattr->ga_bmval,
-                                   resp->rqstp);
+                                   resp->rqstp, 0);
        if (!nfserr)
                resp->p += buflen;
        return nfserr;
index 578f2c9d56bec09899d4dc1c0ca135320e7c6bf9..5bfc2ac60d543a07a8d70d71057cf880d1bb995e 100644 (file)
@@ -44,17 +44,17 @@ static int  nfsd_cache_append(struct svc_rqst *rqstp, struct kvec *vec);
  */
 static DEFINE_SPINLOCK(cache_lock);
 
-void
-nfsd_cache_init(void)
+int nfsd_reply_cache_init(void)
 {
        struct svc_cacherep     *rp;
        int                     i;
 
        INIT_LIST_HEAD(&lru_head);
        i = CACHESIZE;
-       while(i) {
+       while (i) {
                rp = kmalloc(sizeof(*rp), GFP_KERNEL);
-               if (!rp) break;
+               if (!rp)
+                       goto out_nomem;
                list_add(&rp->c_lru, &lru_head);
                rp->c_state = RC_UNUSED;
                rp->c_type = RC_NOCACHE;
@@ -62,23 +62,19 @@ nfsd_cache_init(void)
                i--;
        }
 
-       if (i)
-               printk (KERN_ERR "nfsd: cannot allocate all %d cache entries, only got %d\n",
-                       CACHESIZE, CACHESIZE-i);
-
        hash_list = kcalloc (HASHSIZE, sizeof(struct hlist_head), GFP_KERNEL);
-       if (!hash_list) {
-               nfsd_cache_shutdown();
-               printk (KERN_ERR "nfsd: cannot allocate %Zd bytes for hash list\n",
-                       HASHSIZE * sizeof(struct hlist_head));
-               return;
-       }
+       if (!hash_list)
+               goto out_nomem;
 
        cache_disabled = 0;
+       return 0;
+out_nomem:
+       printk(KERN_ERR "nfsd: failed to allocate reply cache\n");
+       nfsd_reply_cache_shutdown();
+       return -ENOMEM;
 }
 
-void
-nfsd_cache_shutdown(void)
+void nfsd_reply_cache_shutdown(void)
 {
        struct svc_cacherep     *rp;
 
index 77dc9893b7bab462b65ebd751d9cc0c01273891f..8516137cdbb055ac87d1673c482126d2e670f488 100644 (file)
@@ -304,6 +304,9 @@ static ssize_t write_filehandle(struct file *file, char *buf, size_t size)
        struct auth_domain *dom;
        struct knfsd_fh fh;
 
+       if (size == 0)
+               return -EINVAL;
+
        if (buf[size-1] != '\n')
                return -EINVAL;
        buf[size-1] = 0;
@@ -503,7 +506,7 @@ static ssize_t write_ports(struct file *file, char *buf, size_t size)
                int len = 0;
                lock_kernel();
                if (nfsd_serv)
-                       len = svc_sock_names(buf, nfsd_serv, NULL);
+                       len = svc_xprt_names(nfsd_serv, buf, 0);
                unlock_kernel();
                return len;
        }
@@ -540,7 +543,7 @@ static ssize_t write_ports(struct file *file, char *buf, size_t size)
                }
                return err < 0 ? err : 0;
        }
-       if (buf[0] == '-') {
+       if (buf[0] == '-' && isdigit(buf[1])) {
                char *toclose = kstrdup(buf+1, GFP_KERNEL);
                int len = 0;
                if (!toclose)
@@ -554,6 +557,53 @@ static ssize_t write_ports(struct file *file, char *buf, size_t size)
                kfree(toclose);
                return len;
        }
+       /*
+        * Add a transport listener by writing it's transport name
+        */
+       if (isalpha(buf[0])) {
+               int err;
+               char transport[16];
+               int port;
+               if (sscanf(buf, "%15s %4d", transport, &port) == 2) {
+                       err = nfsd_create_serv();
+                       if (!err) {
+                               err = svc_create_xprt(nfsd_serv,
+                                                     transport, port,
+                                                     SVC_SOCK_ANONYMOUS);
+                               if (err == -ENOENT)
+                                       /* Give a reasonable perror msg for
+                                        * bad transport string */
+                                       err = -EPROTONOSUPPORT;
+                       }
+                       return err < 0 ? err : 0;
+               }
+       }
+       /*
+        * Remove a transport by writing it's transport name and port number
+        */
+       if (buf[0] == '-' && isalpha(buf[1])) {
+               struct svc_xprt *xprt;
+               int err = -EINVAL;
+               char transport[16];
+               int port;
+               if (sscanf(&buf[1], "%15s %4d", transport, &port) == 2) {
+                       if (port == 0)
+                               return -EINVAL;
+                       lock_kernel();
+                       if (nfsd_serv) {
+                               xprt = svc_find_xprt(nfsd_serv, transport,
+                                                    AF_UNSPEC, port);
+                               if (xprt) {
+                                       svc_close_xprt(xprt);
+                                       svc_xprt_put(xprt);
+                                       err = 0;
+                               } else
+                                       err = -ENOTCONN;
+                       }
+                       unlock_kernel();
+                       return err < 0 ? err : 0;
+               }
+       }
        return -EINVAL;
 }
 
@@ -616,7 +666,7 @@ static ssize_t write_recoverydir(struct file *file, char *buf, size_t size)
        char *recdir;
        int len, status;
 
-       if (size > PATH_MAX || buf[size-1] != '\n')
+       if (size == 0 || size > PATH_MAX || buf[size-1] != '\n')
                return -EINVAL;
        buf[size-1] = 0;
 
@@ -674,6 +724,27 @@ static struct file_system_type nfsd_fs_type = {
        .kill_sb        = kill_litter_super,
 };
 
+#ifdef CONFIG_PROC_FS
+static int create_proc_exports_entry(void)
+{
+       struct proc_dir_entry *entry;
+
+       entry = proc_mkdir("fs/nfs", NULL);
+       if (!entry)
+               return -ENOMEM;
+       entry = create_proc_entry("fs/nfs/exports", 0, NULL);
+       if (!entry)
+               return -ENOMEM;
+       entry->proc_fops =  &exports_operations;
+       return 0;
+}
+#else /* CONFIG_PROC_FS */
+static int create_proc_exports_entry(void)
+{
+       return 0;
+}
+#endif
+
 static int __init init_nfsd(void)
 {
        int retval;
@@ -683,32 +754,43 @@ static int __init init_nfsd(void)
        if (retval)
                return retval;
        nfsd_stat_init();       /* Statistics */
-       nfsd_cache_init();      /* RPC reply cache */
-       nfsd_export_init();     /* Exports table */
+       retval = nfsd_reply_cache_init();
+       if (retval)
+               goto out_free_stat;
+       retval = nfsd_export_init();
+       if (retval)
+               goto out_free_cache;
        nfsd_lockd_init();      /* lockd->nfsd callbacks */
-       nfsd_idmap_init();      /* Name to ID mapping */
-       if (proc_mkdir("fs/nfs", NULL)) {
-               struct proc_dir_entry *entry;
-               entry = create_proc_entry("fs/nfs/exports", 0, NULL);
-               if (entry)
-                       entry->proc_fops =  &exports_operations;
-       }
+       retval = nfsd_idmap_init();
+       if (retval)
+               goto out_free_lockd;
+       retval = create_proc_exports_entry();
+       if (retval)
+               goto out_free_idmap;
        retval = register_filesystem(&nfsd_fs_type);
-       if (retval) {
-               nfsd_export_shutdown();
-               nfsd_cache_shutdown();
-               remove_proc_entry("fs/nfs/exports", NULL);
-               remove_proc_entry("fs/nfs", NULL);
-               nfsd_stat_shutdown();
-               nfsd_lockd_shutdown();
-       }
+       if (retval)
+               goto out_free_all;
+       return 0;
+out_free_all:
+       remove_proc_entry("fs/nfs/exports", NULL);
+       remove_proc_entry("fs/nfs", NULL);
+out_free_idmap:
+       nfsd_idmap_shutdown();
+out_free_lockd:
+       nfsd_lockd_shutdown();
+       nfsd_export_shutdown();
+out_free_cache:
+       nfsd_reply_cache_shutdown();
+out_free_stat:
+       nfsd_stat_shutdown();
+       nfsd4_free_slabs();
        return retval;
 }
 
 static void __exit exit_nfsd(void)
 {
        nfsd_export_shutdown();
-       nfsd_cache_shutdown();
+       nfsd_reply_cache_shutdown();
        remove_proc_entry("fs/nfs/exports", NULL);
        remove_proc_entry("fs/nfs", NULL);
        nfsd_stat_shutdown();
index 468f17a784416e96e11081d90230a8e6df4eec90..8fbd2dc08a92159a853ef748db561522ec0a0480 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/sunrpc/svc.h>
 #include <linux/sunrpc/svcauth_gss.h>
 #include <linux/nfsd/nfsd.h>
+#include "auth.h"
 
 #define NFSDDBG_FACILITY               NFSDDBG_FH
 
index 1190aeaa92be2e4563c759d04fe96bbc46a0b393..9647b0f7bc0c0d52610bf1419c9bafcd466b57dc 100644 (file)
@@ -155,8 +155,8 @@ static int killsig; /* signal that was used to kill last nfsd */
 static void nfsd_last_thread(struct svc_serv *serv)
 {
        /* When last nfsd thread exits we need to do some clean-up */
-       struct svc_sock *svsk;
-       list_for_each_entry(svsk, &serv->sv_permsocks, sk_list)
+       struct svc_xprt *xprt;
+       list_for_each_entry(xprt, &serv->sv_permsocks, xpt_list)
                lockd_down();
        nfsd_serv = NULL;
        nfsd_racache_shutdown();
@@ -236,7 +236,7 @@ static int nfsd_init_socks(int port)
 
        error = lockd_up(IPPROTO_UDP);
        if (error >= 0) {
-               error = svc_makesock(nfsd_serv, IPPROTO_UDP, port,
+               error = svc_create_xprt(nfsd_serv, "udp", port,
                                        SVC_SOCK_DEFAULTS);
                if (error < 0)
                        lockd_down();
@@ -247,7 +247,7 @@ static int nfsd_init_socks(int port)
 #ifdef CONFIG_NFSD_TCP
        error = lockd_up(IPPROTO_TCP);
        if (error >= 0) {
-               error = svc_makesock(nfsd_serv, IPPROTO_TCP, port,
+               error = svc_create_xprt(nfsd_serv, "tcp", port,
                                        SVC_SOCK_DEFAULTS);
                if (error < 0)
                        lockd_down();
index b86e3658a0af10ebce825e260ee1fc5fd879f367..61ad61743d9403524242e564523b4f3945aa25e3 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/nfsd/nfsd.h>
 #include <linux/nfsd/xdr.h>
 #include <linux/mm.h>
+#include "auth.h"
 
 #define NFSDDBG_FACILITY               NFSDDBG_XDR
 
@@ -62,10 +63,10 @@ encode_fh(__be32 *p, struct svc_fh *fhp)
  * no slashes or null bytes.
  */
 static __be32 *
-decode_filename(__be32 *p, char **namp, int *lenp)
+decode_filename(__be32 *p, char **namp, unsigned int *lenp)
 {
        char            *name;
-       int             i;
+       unsigned int    i;
 
        if ((p = xdr_decode_string_inplace(p, namp, lenp, NFS_MAXNAMLEN)) != NULL) {
                for (i = 0, name = *namp; i < *lenp; i++, name++) {
@@ -78,10 +79,10 @@ decode_filename(__be32 *p, char **namp, int *lenp)
 }
 
 static __be32 *
-decode_pathname(__be32 *p, char **namp, int *lenp)
+decode_pathname(__be32 *p, char **namp, unsigned int *lenp)
 {
        char            *name;
-       int             i;
+       unsigned int    i;
 
        if ((p = xdr_decode_string_inplace(p, namp, lenp, NFS_MAXPATHLEN)) != NULL) {
                for (i = 0, name = *namp; i < *lenp; i++, name++) {
index d0199189924cee7d5ea49aafd52dcc81fab21df2..cc75e4fcd02baf2a989573ac5aac2e16dad8df17 100644 (file)
@@ -132,7 +132,7 @@ out:
 
 __be32
 nfsd_lookup_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp,
-                  const char *name, int len,
+                  const char *name, unsigned int len,
                   struct svc_export **exp_ret, struct dentry **dentry_ret)
 {
        struct svc_export       *exp;
@@ -226,7 +226,7 @@ out_nfserr:
  */
 __be32
 nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
-                                       int len, struct svc_fh *resfh)
+                               unsigned int len, struct svc_fh *resfh)
 {
        struct svc_export       *exp;
        struct dentry           *dentry;
@@ -1151,6 +1151,26 @@ nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp,
 }
 #endif /* CONFIG_NFSD_V3 */
 
+__be32
+nfsd_create_setattr(struct svc_rqst *rqstp, struct svc_fh *resfhp,
+                       struct iattr *iap)
+{
+       /*
+        * Mode has already been set earlier in create:
+        */
+       iap->ia_valid &= ~ATTR_MODE;
+       /*
+        * Setting uid/gid works only for root.  Irix appears to
+        * send along the gid on create when it tries to implement
+        * setgid directories via NFS:
+        */
+       if (current->fsuid != 0)
+               iap->ia_valid &= ~(ATTR_UID|ATTR_GID);
+       if (iap->ia_valid)
+               return nfsd_setattr(rqstp, resfhp, iap, 0, (time_t)0);
+       return 0;
+}
+
 /*
  * Create a file (regular, directory, device, fifo); UNIX sockets 
  * not yet implemented.
@@ -1167,6 +1187,7 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
        struct dentry   *dentry, *dchild = NULL;
        struct inode    *dirp;
        __be32          err;
+       __be32          err2;
        int             host_err;
 
        err = nfserr_perm;
@@ -1257,16 +1278,9 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
        }
 
 
-       /* Set file attributes. Mode has already been set and
-        * setting uid/gid works only for root. Irix appears to
-        * send along the gid when it tries to implement setgid
-        * directories via NFS.
-        */
-       if ((iap->ia_valid &= ~(ATTR_UID|ATTR_GID|ATTR_MODE)) != 0) {
-               __be32 err2 = nfsd_setattr(rqstp, resfhp, iap, 0, (time_t)0);
-               if (err2)
-                       err = err2;
-       }
+       err2 = nfsd_create_setattr(rqstp, resfhp, iap);
+       if (err2)
+               err = err2;
        /*
         * Update the file handle to get the new inode info.
         */
@@ -1295,6 +1309,7 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp,
        struct dentry   *dentry, *dchild = NULL;
        struct inode    *dirp;
        __be32          err;
+       __be32          err2;
        int             host_err;
        __u32           v_mtime=0, v_atime=0;
 
@@ -1399,16 +1414,10 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp,
                iap->ia_atime.tv_nsec = 0;
        }
 
-       /* Set file attributes.
-        * Irix appears to send along the gid when it tries to
-        * implement setgid directories via NFS. Clear out all that cruft.
-        */
  set_attr:
-       if ((iap->ia_valid &= ~(ATTR_UID|ATTR_GID|ATTR_MODE)) != 0) {
-               __be32 err2 = nfsd_setattr(rqstp, resfhp, iap, 0, (time_t)0);
-               if (err2)
-                       err = err2;
-       }
+       err2 = nfsd_create_setattr(rqstp, resfhp, iap);
+       if (err2)
+               err = err2;
 
        /*
         * Update the filehandle to get the new inode info.
index ad87cb01299b6d8febb7ae670fddb36ce33cc666..00e9ccde8e42b787724bee44aedc432df37e7875 100644 (file)
@@ -87,13 +87,17 @@ static void ntfs_end_buffer_async_read(struct buffer_head *bh, int uptodate)
                /* Check for the current buffer head overflowing. */
                if (unlikely(file_ofs + bh->b_size > init_size)) {
                        int ofs;
+                       void *kaddr;
 
                        ofs = 0;
                        if (file_ofs < init_size)
                                ofs = init_size - file_ofs;
                        local_irq_save(flags);
-                       zero_user_page(page, bh_offset(bh) + ofs,
-                                        bh->b_size - ofs, KM_BIO_SRC_IRQ);
+                       kaddr = kmap_atomic(page, KM_BIO_SRC_IRQ);
+                       memset(kaddr + bh_offset(bh) + ofs, 0,
+                                       bh->b_size - ofs);
+                       flush_dcache_page(page);
+                       kunmap_atomic(kaddr, KM_BIO_SRC_IRQ);
                        local_irq_restore(flags);
                }
        } else {
@@ -334,7 +338,7 @@ handle_hole:
                bh->b_blocknr = -1UL;
                clear_buffer_mapped(bh);
 handle_zblock:
-               zero_user_page(page, i * blocksize, blocksize, KM_USER0);
+               zero_user(page, i * blocksize, blocksize);
                if (likely(!err))
                        set_buffer_uptodate(bh);
        } while (i++, iblock++, (bh = bh->b_this_page) != head);
@@ -410,7 +414,7 @@ retry_readpage:
        /* Is the page fully outside i_size? (truncate in progress) */
        if (unlikely(page->index >= (i_size + PAGE_CACHE_SIZE - 1) >>
                        PAGE_CACHE_SHIFT)) {
-               zero_user_page(page, 0, PAGE_CACHE_SIZE, KM_USER0);
+               zero_user(page, 0, PAGE_CACHE_SIZE);
                ntfs_debug("Read outside i_size - truncated?");
                goto done;
        }
@@ -459,7 +463,7 @@ retry_readpage:
         * ok to ignore the compressed flag here.
         */
        if (unlikely(page->index > 0)) {
-               zero_user_page(page, 0, PAGE_CACHE_SIZE, KM_USER0);
+               zero_user(page, 0, PAGE_CACHE_SIZE);
                goto done;
        }
        if (!NInoAttr(ni))
@@ -788,8 +792,7 @@ lock_retry_remap:
                if (err == -ENOENT || lcn == LCN_ENOENT) {
                        bh->b_blocknr = -1;
                        clear_buffer_dirty(bh);
-                       zero_user_page(page, bh_offset(bh), blocksize,
-                                       KM_USER0);
+                       zero_user(page, bh_offset(bh), blocksize);
                        set_buffer_uptodate(bh);
                        err = 0;
                        continue;
@@ -1414,8 +1417,7 @@ retry_writepage:
                if (page->index >= (i_size >> PAGE_CACHE_SHIFT)) {
                        /* The page straddles i_size. */
                        unsigned int ofs = i_size & ~PAGE_CACHE_MASK;
-                       zero_user_page(page, ofs, PAGE_CACHE_SIZE - ofs,
-                                       KM_USER0);
+                       zero_user_segment(page, ofs, PAGE_CACHE_SIZE);
                }
                /* Handle mst protected attributes. */
                if (NInoMstProtected(ni))
index d1619d05eb23bce83bea2d9f005e663625fa1f2e..33ff314cc5073cf9f88a3623db7129fd4ad4e772 100644 (file)
@@ -565,7 +565,7 @@ int ntfs_read_compressed_block(struct page *page)
        if (xpage >= max_page) {
                kfree(bhs);
                kfree(pages);
-               zero_user_page(page, 0, PAGE_CACHE_SIZE, KM_USER0);
+               zero_user(page, 0, PAGE_CACHE_SIZE);
                ntfs_debug("Compressed read outside i_size - truncated?");
                SetPageUptodate(page);
                unlock_page(page);
index 6cd08dfdc2ed17afcacb1985e2c444910f18e4dd..3c5550cd11d67b53a5d3ef6ff49dd6d4312f9d4c 100644 (file)
@@ -607,8 +607,8 @@ do_next_page:
                                        ntfs_submit_bh_for_read(bh);
                                        *wait_bh++ = bh;
                                } else {
-                                       zero_user_page(page, bh_offset(bh),
-                                                       blocksize, KM_USER0);
+                                       zero_user(page, bh_offset(bh),
+                                                       blocksize);
                                        set_buffer_uptodate(bh);
                                }
                        }
@@ -683,9 +683,8 @@ map_buffer_cached:
                                                ntfs_submit_bh_for_read(bh);
                                                *wait_bh++ = bh;
                                        } else {
-                                               zero_user_page(page,
-                                                       bh_offset(bh),
-                                                       blocksize, KM_USER0);
+                                               zero_user(page, bh_offset(bh),
+                                                               blocksize);
                                                set_buffer_uptodate(bh);
                                        }
                                }
@@ -703,8 +702,8 @@ map_buffer_cached:
                         */
                        if (bh_end <= pos || bh_pos >= end) {
                                if (!buffer_uptodate(bh)) {
-                                       zero_user_page(page, bh_offset(bh),
-                                                       blocksize, KM_USER0);
+                                       zero_user(page, bh_offset(bh),
+                                                       blocksize);
                                        set_buffer_uptodate(bh);
                                }
                                mark_buffer_dirty(bh);
@@ -743,8 +742,7 @@ map_buffer_cached:
                                if (!buffer_uptodate(bh))
                                        set_buffer_uptodate(bh);
                        } else if (!buffer_uptodate(bh)) {
-                               zero_user_page(page, bh_offset(bh), blocksize,
-                                               KM_USER0);
+                               zero_user(page, bh_offset(bh), blocksize);
                                set_buffer_uptodate(bh);
                        }
                        continue;
@@ -868,8 +866,8 @@ rl_not_mapped_enoent:
                                        if (!buffer_uptodate(bh))
                                                set_buffer_uptodate(bh);
                                } else if (!buffer_uptodate(bh)) {
-                                       zero_user_page(page, bh_offset(bh),
-                                                       blocksize, KM_USER0);
+                                       zero_user(page, bh_offset(bh),
+                                               blocksize);
                                        set_buffer_uptodate(bh);
                                }
                                continue;
@@ -1128,8 +1126,8 @@ rl_not_mapped_enoent:
 
                                if (likely(bh_pos < initialized_size))
                                        ofs = initialized_size - bh_pos;
-                               zero_user_page(page, bh_offset(bh) + ofs,
-                                               blocksize - ofs, KM_USER0);
+                               zero_user_segment(page, bh_offset(bh) + ofs,
+                                               blocksize);
                        }
                } else /* if (unlikely(!buffer_uptodate(bh))) */
                        err = -EIO;
@@ -1269,8 +1267,8 @@ rl_not_mapped_enoent:
                                if (PageUptodate(page))
                                        set_buffer_uptodate(bh);
                                else {
-                                       zero_user_page(page, bh_offset(bh),
-                                                       blocksize, KM_USER0);
+                                       zero_user(page, bh_offset(bh),
+                                                       blocksize);
                                        set_buffer_uptodate(bh);
                                }
                        }
@@ -1330,7 +1328,7 @@ err_out:
                len = PAGE_CACHE_SIZE;
                if (len > bytes)
                        len = bytes;
-               zero_user_page(*pages, 0, len, KM_USER0);
+               zero_user(*pages, 0, len);
        }
        goto out;
 }
@@ -1451,7 +1449,7 @@ err_out:
                len = PAGE_CACHE_SIZE;
                if (len > bytes)
                        len = bytes;
-               zero_user_page(*pages, 0, len, KM_USER0);
+               zero_user(*pages, 0, len);
        }
        goto out;
 }
index e38e402e410351c6a70ff9ae148f10133ee28177..cd0be3f5c3cd34a5d5209adafcf6ad518ff7da0b 100644 (file)
@@ -85,8 +85,7 @@ static inline void *ntfs_malloc_nofs_nofail(unsigned long size)
 
 static inline void ntfs_free(void *addr)
 {
-       if (likely(((unsigned long)addr < VMALLOC_START) ||
-                       ((unsigned long)addr >= VMALLOC_END ))) {
+       if (!is_vmalloc_addr(addr)) {
                kfree(addr);
                /* free_page((unsigned long)addr); */
                return;
index e6df06ac64059bb495a742f892530e1dd3212f3b..447206eb5c2e85fe1c0a4e1542f3a3083cac0982 100644 (file)
@@ -3338,7 +3338,7 @@ static int ocfs2_insert_path(struct inode *inode,
        if (insert->ins_split != SPLIT_NONE) {
                /*
                 * We could call ocfs2_insert_at_leaf() for some types
-                * of splits, but it's easier to just let one seperate
+                * of splits, but it's easier to just let one separate
                 * function sort it all out.
                 */
                ocfs2_split_record(inode, left_path, right_path,
@@ -5670,7 +5670,7 @@ static void ocfs2_map_and_dirty_page(struct inode *inode, handle_t *handle,
                mlog_errno(ret);
 
        if (zero)
-               zero_user_page(page, from, to - from, KM_USER0);
+               zero_user_segment(page, from, to);
 
        /*
         * Need to set the buffers we zero'd into uptodate
index bc7b4cbbe8eca6f418761b64d0ff8f24141242b0..82243127eebf6b81d80acd239609bdc1fd26ae43 100644 (file)
@@ -307,7 +307,7 @@ static int ocfs2_readpage(struct file *file, struct page *page)
         * XXX sys_readahead() seems to get that wrong?
         */
        if (start >= i_size_read(inode)) {
-               zero_user_page(page, 0, PAGE_SIZE, KM_USER0);
+               zero_user(page, 0, PAGE_SIZE);
                SetPageUptodate(page);
                ret = 0;
                goto out_alloc;
@@ -869,7 +869,7 @@ int ocfs2_map_page_blocks(struct page *page, u64 *p_blkno,
                if (block_start >= to)
                        break;
 
-               zero_user_page(page, block_start, bh->b_size, KM_USER0);
+               zero_user(page, block_start, bh->b_size);
                set_buffer_uptodate(bh);
                mark_buffer_dirty(bh);
 
@@ -1034,7 +1034,7 @@ static void ocfs2_zero_new_buffers(struct page *page, unsigned from, unsigned to
                                        start = max(from, block_start);
                                        end = min(to, block_end);
 
-                                       zero_user_page(page, start, end - start, KM_USER0);
+                                       zero_user_segment(page, start, end);
                                        set_buffer_uptodate(bh);
                                }
 
index 6b0107f21344734f583ea103b56cc10bee7d6b74..e280833ceb9aa76bd8404ded84b6047948b0ca9d 100644 (file)
@@ -1215,7 +1215,7 @@ static int ocfs2_expand_inline_dir(struct inode *dir, struct buffer_head *di_bh,
        down_write(&oi->ip_alloc_sem);
 
        /*
-        * Prepare for worst case allocation scenario of two seperate
+        * Prepare for worst case allocation scenario of two separate
         * extents.
         */
        if (alloc == 2)
index 0b499bccec5ae5be5771ddf22d10461a252bfc47..dfb313bda5dd618b95e431568bc818dcc34a1c3f 100644 (file)
@@ -77,7 +77,7 @@ struct ocfs1_disk_lock
 {
 /*00*/ __u32 curr_master;
        __u8 file_lock;
-       __u8 compat_pad[3];  /* Not in orignal definition.  Used to
+       __u8 compat_pad[3];  /* Not in original definition.  Used to
                                make the already existing alignment
                                explicit */
        __u64 last_write_time;
index 7e397e2c25dd219fd55e3f16c363488fb57223e6..72c198a004df46744c1c025e253763727ce635bb 100644 (file)
@@ -646,7 +646,7 @@ bail:
  * sync-data inodes."
  *
  * Note: OCFS2 already does this differently for metadata vs data
- * allocations, as those bitmaps are seperate and undo access is never
+ * allocations, as those bitmaps are separate and undo access is never
  * called on a metadata group descriptor.
  */
 static int ocfs2_test_bg_bit_allocatable(struct buffer_head *bg_bh,
index eb97f2897e2b50724046446be149951c1685c650..6ba2746e451706fc59beee9319cb896187958f05 100644 (file)
@@ -141,12 +141,7 @@ static const char *task_state_array[] = {
 
 static inline const char *get_task_state(struct task_struct *tsk)
 {
-       unsigned int state = (tsk->state & (TASK_RUNNING |
-                                           TASK_INTERRUPTIBLE |
-                                           TASK_UNINTERRUPTIBLE |
-                                           TASK_STOPPED |
-                                           TASK_TRACED)) |
-                                          tsk->exit_state;
+       unsigned int state = (tsk->state & TASK_REPORT) | tsk->exit_state;
        const char **p = &task_state_array[0];
 
        while (state) {
@@ -286,14 +281,23 @@ static inline char *task_sig(struct task_struct *p, char *buffer)
        return buffer;
 }
 
+static char *render_cap_t(const char *header, kernel_cap_t *a, char *buffer)
+{
+       unsigned __capi;
+
+       buffer += sprintf(buffer, "%s", header);
+       CAP_FOR_EACH_U32(__capi) {
+               buffer += sprintf(buffer, "%08x",
+                                 a->cap[(_LINUX_CAPABILITY_U32S-1) - __capi]);
+       }
+       return buffer + sprintf(buffer, "\n");
+}
+
 static inline char *task_cap(struct task_struct *p, char *buffer)
 {
-    return buffer + sprintf(buffer, "CapInh:\t%016x\n"
-                           "CapPrm:\t%016x\n"
-                           "CapEff:\t%016x\n",
-                           cap_t(p->cap_inheritable),
-                           cap_t(p->cap_permitted),
-                           cap_t(p->cap_effective));
+       buffer = render_cap_t("CapInh:\t", &p->cap_inheritable, buffer);
+       buffer = render_cap_t("CapPrm:\t", &p->cap_permitted, buffer);
+       return render_cap_t("CapEff:\t", &p->cap_effective, buffer);
 }
 
 static inline char *task_context_switch_counts(struct task_struct *p,
index 91fa8e6ce8ad6591cb496ca54731ab5531cef521..c59852b38787382a9399de7c69ae787ce22d9bf4 100644 (file)
  *     in /proc for a task before it execs a suid executable.
  */
 
-
-/* Worst case buffer size needed for holding an integer. */
-#define PROC_NUMBUF 13
-
 struct pid_entry {
        char *name;
        int len;
@@ -199,7 +195,7 @@ static int proc_root_link(struct inode *inode, struct dentry **dentry, struct vf
        (task == current || \
        (task->parent == current && \
        (task->ptrace & PT_PTRACED) && \
-        (task->state == TASK_STOPPED || task->state == TASK_TRACED) && \
+        (task_is_stopped_or_traced(task)) && \
         security_ptrace(current,task) == 0))
 
 struct mm_struct *mm_for_maps(struct task_struct *task)
@@ -787,7 +783,7 @@ out_no_task:
 }
 #endif
 
-static loff_t mem_lseek(struct file * file, loff_t offset, int orig)
+loff_t mem_lseek(struct file *file, loff_t offset, int orig)
 {
        switch (orig) {
        case 0:
@@ -935,42 +931,6 @@ static const struct file_operations proc_oom_adjust_operations = {
        .write          = oom_adjust_write,
 };
 
-#ifdef CONFIG_MMU
-static ssize_t clear_refs_write(struct file *file, const char __user *buf,
-                               size_t count, loff_t *ppos)
-{
-       struct task_struct *task;
-       char buffer[PROC_NUMBUF], *end;
-       struct mm_struct *mm;
-
-       memset(buffer, 0, sizeof(buffer));
-       if (count > sizeof(buffer) - 1)
-               count = sizeof(buffer) - 1;
-       if (copy_from_user(buffer, buf, count))
-               return -EFAULT;
-       if (!simple_strtol(buffer, &end, 0))
-               return -EINVAL;
-       if (*end == '\n')
-               end++;
-       task = get_proc_task(file->f_path.dentry->d_inode);
-       if (!task)
-               return -ESRCH;
-       mm = get_task_mm(task);
-       if (mm) {
-               clear_refs_smap(mm);
-               mmput(mm);
-       }
-       put_task_struct(task);
-       if (end - buffer == 0)
-               return -EIO;
-       return end - buffer;
-}
-
-static struct file_operations proc_clear_refs_operations = {
-       .write          = clear_refs_write,
-};
-#endif
-
 #ifdef CONFIG_AUDITSYSCALL
 #define TMPBUFLEN 21
 static ssize_t proc_loginuid_read(struct file * file, char __user * buf,
@@ -984,7 +944,7 @@ static ssize_t proc_loginuid_read(struct file * file, char __user * buf,
        if (!task)
                return -ESRCH;
        length = scnprintf(tmpbuf, TMPBUFLEN, "%u",
-                               audit_get_loginuid(task->audit_context));
+                               audit_get_loginuid(task));
        put_task_struct(task);
        return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
 }
@@ -2289,9 +2249,10 @@ static const struct pid_entry tgid_base_stuff[] = {
        LNK("exe",        exe),
        REG("mounts",     S_IRUGO, mounts),
        REG("mountstats", S_IRUSR, mountstats),
-#ifdef CONFIG_MMU
+#ifdef CONFIG_PROC_PAGE_MONITOR
        REG("clear_refs", S_IWUSR, clear_refs),
        REG("smaps",      S_IRUGO, smaps),
+       REG("pagemap",    S_IRUSR, pagemap),
 #endif
 #ifdef CONFIG_SECURITY
        DIR("attr",       S_IRUGO|S_IXUGO, attr_dir),
@@ -2360,7 +2321,8 @@ static void proc_flush_task_mnt(struct vfsmount *mnt, pid_t pid, pid_t tgid)
        name.len = snprintf(buf, sizeof(buf), "%d", pid);
        dentry = d_hash_and_lookup(mnt->mnt_root, &name);
        if (dentry) {
-               shrink_dcache_parent(dentry);
+               if (!(current->flags & PF_EXITING))
+                       shrink_dcache_parent(dentry);
                d_drop(dentry);
                dput(dentry);
        }
@@ -2617,9 +2579,10 @@ static const struct pid_entry tid_base_stuff[] = {
        LNK("root",      root),
        LNK("exe",       exe),
        REG("mounts",    S_IRUGO, mounts),
-#ifdef CONFIG_MMU
+#ifdef CONFIG_PROC_PAGE_MONITOR
        REG("clear_refs", S_IWUSR, clear_refs),
        REG("smaps",     S_IRUGO, smaps),
+       REG("pagemap",    S_IRUSR, pagemap),
 #endif
 #ifdef CONFIG_SECURITY
        DIR("attr",      S_IRUGO|S_IXUGO, attr_dir),
index 05b3e9006262c49145f640e482062bbd0b6d14ad..7d57e80699241fade80e341cd47ca057444a6f69 100644 (file)
@@ -52,15 +52,13 @@ extern int proc_tid_stat(struct task_struct *,  char *);
 extern int proc_tgid_stat(struct task_struct *, char *);
 extern int proc_pid_status(struct task_struct *, char *);
 extern int proc_pid_statm(struct task_struct *, char *);
+extern loff_t mem_lseek(struct file *file, loff_t offset, int orig);
 
 extern const struct file_operations proc_maps_operations;
 extern const struct file_operations proc_numa_maps_operations;
 extern const struct file_operations proc_smaps_operations;
-
-extern const struct file_operations proc_maps_operations;
-extern const struct file_operations proc_numa_maps_operations;
-extern const struct file_operations proc_smaps_operations;
-
+extern const struct file_operations proc_clear_refs_operations;
+extern const struct file_operations proc_pagemap_operations;
 
 void free_proc_entry(struct proc_dir_entry *de);
 
index 1be73082edd388bd443f0be5c559cdf756eccbbb..7dd26e18cbfd6f4941f9744d47381ada5c4bfcfe 100644 (file)
@@ -325,7 +325,7 @@ read_kcore(struct file *file, char __user *buffer, size_t buflen, loff_t *fpos)
                if (m == NULL) {
                        if (clear_user(buffer, tsz))
                                return -EFAULT;
-               } else if ((start >= VMALLOC_START) && (start < VMALLOC_END)) {
+               } else if (is_vmalloc_addr((void *)start)) {
                        char * elf_buf;
                        struct vm_struct *m;
                        unsigned long curstart = start;
index 3462bfde89f68224a4ec48629e26c81feee0e44b..51288db37a0cf2e25ed2037b3e5161f6bc52a49e 100644 (file)
@@ -46,6 +46,7 @@
 #include <linux/vmalloc.h>
 #include <linux/crash_dump.h>
 #include <linux/pid_namespace.h>
+#include <linux/bootmem.h>
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 #include <asm/io.h>
@@ -675,6 +676,137 @@ static const struct file_operations proc_sysrq_trigger_operations = {
 };
 #endif
 
+#ifdef CONFIG_PROC_PAGE_MONITOR
+#define KPMSIZE sizeof(u64)
+#define KPMMASK (KPMSIZE - 1)
+/* /proc/kpagecount - an array exposing page counts
+ *
+ * Each entry is a u64 representing the corresponding
+ * physical page count.
+ */
+static ssize_t kpagecount_read(struct file *file, char __user *buf,
+                            size_t count, loff_t *ppos)
+{
+       u64 __user *out = (u64 __user *)buf;
+       struct page *ppage;
+       unsigned long src = *ppos;
+       unsigned long pfn;
+       ssize_t ret = 0;
+       u64 pcount;
+
+       pfn = src / KPMSIZE;
+       count = min_t(size_t, count, (max_pfn * KPMSIZE) - src);
+       if (src & KPMMASK || count & KPMMASK)
+               return -EIO;
+
+       while (count > 0) {
+               ppage = NULL;
+               if (pfn_valid(pfn))
+                       ppage = pfn_to_page(pfn);
+               pfn++;
+               if (!ppage)
+                       pcount = 0;
+               else
+                       pcount = atomic_read(&ppage->_count);
+
+               if (put_user(pcount, out++)) {
+                       ret = -EFAULT;
+                       break;
+               }
+
+               count -= KPMSIZE;
+       }
+
+       *ppos += (char __user *)out - buf;
+       if (!ret)
+               ret = (char __user *)out - buf;
+       return ret;
+}
+
+static struct file_operations proc_kpagecount_operations = {
+       .llseek = mem_lseek,
+       .read = kpagecount_read,
+};
+
+/* /proc/kpageflags - an array exposing page flags
+ *
+ * Each entry is a u64 representing the corresponding
+ * physical page flags.
+ */
+
+/* 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_copy_bit(flags, srcpos, dstpos) (((flags >> srcpos) & 1) << dstpos)
+
+static ssize_t kpageflags_read(struct file *file, char __user *buf,
+                            size_t count, loff_t *ppos)
+{
+       u64 __user *out = (u64 __user *)buf;
+       struct page *ppage;
+       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);
+       if (src & KPMMASK || count & KPMMASK)
+               return -EIO;
+
+       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(KPF_LOCKED, PG_locked, kflags) |
+                       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++)) {
+                       ret = -EFAULT;
+                       break;
+               }
+
+               count -= KPMSIZE;
+       }
+
+       *ppos += (char __user *)out - buf;
+       if (!ret)
+               ret = (char __user *)out - buf;
+       return ret;
+}
+
+static struct file_operations proc_kpageflags_operations = {
+       .llseek = mem_lseek,
+       .read = kpageflags_read,
+};
+#endif /* CONFIG_PROC_PAGE_MONITOR */
+
 struct proc_dir_entry *proc_root_kcore;
 
 void create_seq_entry(char *name, mode_t mode, const struct file_operations *f)
@@ -755,6 +887,10 @@ void __init proc_misc_init(void)
                                (size_t)high_memory - PAGE_OFFSET + PAGE_SIZE;
        }
 #endif
+#ifdef CONFIG_PROC_PAGE_MONITOR
+       create_seq_entry("kpagecount", S_IRUSR, &proc_kpagecount_operations);
+       create_seq_entry("kpageflags", S_IRUSR, &proc_kpageflags_operations);
+#endif
 #ifdef CONFIG_PROC_VMCORE
        proc_vmcore = create_proc_entry("vmcore", S_IRUSR, NULL);
        if (proc_vmcore)
index 8043a3eab52ce49f14f0b23f863b8fb77c6916ba..38338ed98cc6df167febbe2fc962f55a700bfb19 100644 (file)
@@ -5,7 +5,10 @@
 #include <linux/highmem.h>
 #include <linux/ptrace.h>
 #include <linux/pagemap.h>
+#include <linux/ptrace.h>
 #include <linux/mempolicy.h>
+#include <linux/swap.h>
+#include <linux/swapops.h>
 
 #include <asm/elf.h>
 #include <asm/uaccess.h>
@@ -114,24 +117,124 @@ static void pad_len_spaces(struct seq_file *m, int len)
        seq_printf(m, "%*c", len, ' ');
 }
 
-struct mem_size_stats
+static void vma_stop(struct proc_maps_private *priv, struct vm_area_struct *vma)
 {
-       unsigned long resident;
-       unsigned long shared_clean;
-       unsigned long shared_dirty;
-       unsigned long private_clean;
-       unsigned long private_dirty;
-       unsigned long referenced;
-};
+       if (vma && vma != priv->tail_vma) {
+               struct mm_struct *mm = vma->vm_mm;
+               up_read(&mm->mmap_sem);
+               mmput(mm);
+       }
+}
 
-struct pmd_walker {
-       struct vm_area_struct *vma;
-       void *private;
-       void (*action)(struct vm_area_struct *, pmd_t *, unsigned long,
-                      unsigned long, void *);
-};
+static void *m_start(struct seq_file *m, loff_t *pos)
+{
+       struct proc_maps_private *priv = m->private;
+       unsigned long last_addr = m->version;
+       struct mm_struct *mm;
+       struct vm_area_struct *vma, *tail_vma = NULL;
+       loff_t l = *pos;
+
+       /* Clear the per syscall fields in priv */
+       priv->task = NULL;
+       priv->tail_vma = NULL;
+
+       /*
+        * We remember last_addr rather than next_addr to hit with
+        * mmap_cache most of the time. We have zero last_addr at
+        * the beginning and also after lseek. We will have -1 last_addr
+        * after the end of the vmas.
+        */
+
+       if (last_addr == -1UL)
+               return NULL;
+
+       priv->task = get_pid_task(priv->pid, PIDTYPE_PID);
+       if (!priv->task)
+               return NULL;
+
+       mm = mm_for_maps(priv->task);
+       if (!mm)
+               return NULL;
+
+       tail_vma = get_gate_vma(priv->task);
+       priv->tail_vma = tail_vma;
+
+       /* Start with last addr hint */
+       vma = find_vma(mm, last_addr);
+       if (last_addr && vma) {
+               vma = vma->vm_next;
+               goto out;
+       }
+
+       /*
+        * Check the vma index is within the range and do
+        * sequential scan until m_index.
+        */
+       vma = NULL;
+       if ((unsigned long)l < mm->map_count) {
+               vma = mm->mmap;
+               while (l-- && vma)
+                       vma = vma->vm_next;
+               goto out;
+       }
+
+       if (l != mm->map_count)
+               tail_vma = NULL; /* After gate vma */
+
+out:
+       if (vma)
+               return vma;
+
+       /* End of vmas has been reached */
+       m->version = (tail_vma != NULL)? 0: -1UL;
+       up_read(&mm->mmap_sem);
+       mmput(mm);
+       return tail_vma;
+}
 
-static int show_map_internal(struct seq_file *m, void *v, struct mem_size_stats *mss)
+static void *m_next(struct seq_file *m, void *v, loff_t *pos)
+{
+       struct proc_maps_private *priv = m->private;
+       struct vm_area_struct *vma = v;
+       struct vm_area_struct *tail_vma = priv->tail_vma;
+
+       (*pos)++;
+       if (vma && (vma != tail_vma) && vma->vm_next)
+               return vma->vm_next;
+       vma_stop(priv, vma);
+       return (vma != tail_vma)? tail_vma: NULL;
+}
+
+static void m_stop(struct seq_file *m, void *v)
+{
+       struct proc_maps_private *priv = m->private;
+       struct vm_area_struct *vma = v;
+
+       vma_stop(priv, vma);
+       if (priv->task)
+               put_task_struct(priv->task);
+}
+
+static int do_maps_open(struct inode *inode, struct file *file,
+                       struct seq_operations *ops)
+{
+       struct proc_maps_private *priv;
+       int ret = -ENOMEM;
+       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+       if (priv) {
+               priv->pid = proc_pid(inode);
+               ret = seq_open(file, ops);
+               if (!ret) {
+                       struct seq_file *m = file->private_data;
+                       m->private = priv;
+               } else {
+                       kfree(priv);
+               }
+       }
+       return ret;
+}
+
+static int show_map(struct seq_file *m, void *v)
 {
        struct proc_maps_private *priv = m->private;
        struct task_struct *task = priv->task;
@@ -191,41 +294,71 @@ static int show_map_internal(struct seq_file *m, void *v, struct mem_size_stats
        }
        seq_putc(m, '\n');
 
-       if (mss)
-               seq_printf(m,
-                          "Size:           %8lu kB\n"
-                          "Rss:            %8lu kB\n"
-                          "Shared_Clean:   %8lu kB\n"
-                          "Shared_Dirty:   %8lu kB\n"
-                          "Private_Clean:  %8lu kB\n"
-                          "Private_Dirty:  %8lu kB\n"
-                          "Referenced:     %8lu kB\n",
-                          (vma->vm_end - vma->vm_start) >> 10,
-                          mss->resident >> 10,
-                          mss->shared_clean  >> 10,
-                          mss->shared_dirty  >> 10,
-                          mss->private_clean >> 10,
-                          mss->private_dirty >> 10,
-                          mss->referenced >> 10);
-
        if (m->count < m->size)  /* vma is copied successfully */
                m->version = (vma != get_gate_vma(task))? vma->vm_start: 0;
        return 0;
 }
 
-static int show_map(struct seq_file *m, void *v)
+static struct seq_operations proc_pid_maps_op = {
+       .start  = m_start,
+       .next   = m_next,
+       .stop   = m_stop,
+       .show   = show_map
+};
+
+static int maps_open(struct inode *inode, struct file *file)
 {
-       return show_map_internal(m, v, NULL);
+       return do_maps_open(inode, file, &proc_pid_maps_op);
 }
 
-static void smaps_pte_range(struct vm_area_struct *vma, pmd_t *pmd,
-                           unsigned long addr, unsigned long end,
-                           void *private)
+const struct file_operations proc_maps_operations = {
+       .open           = maps_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = seq_release_private,
+};
+
+/*
+ * Proportional Set Size(PSS): my share of RSS.
+ *
+ * PSS of a process is the count of pages it has in memory, where each
+ * page is divided by the number of processes sharing it.  So if a
+ * process has 1000 pages all to itself, and 1000 shared with one other
+ * process, its PSS will be 1500.
+ *
+ * To keep (accumulated) division errors low, we adopt a 64bit
+ * fixed-point pss counter to minimize division errors. So (pss >>
+ * PSS_SHIFT) would be the real byte count.
+ *
+ * A shift of 12 before division means (assuming 4K page size):
+ *     - 1M 3-user-pages add up to 8KB errors;
+ *     - supports mapcount up to 2^24, or 16M;
+ *     - supports PSS up to 2^52 bytes, or 4PB.
+ */
+#define PSS_SHIFT 12
+
+#ifdef CONFIG_PROC_PAGE_MONITOR
+struct mem_size_stats
+{
+       struct vm_area_struct *vma;
+       unsigned long resident;
+       unsigned long shared_clean;
+       unsigned long shared_dirty;
+       unsigned long private_clean;
+       unsigned long private_dirty;
+       unsigned long referenced;
+       u64 pss;
+};
+
+static int smaps_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end,
+                          void *private)
 {
        struct mem_size_stats *mss = private;
+       struct vm_area_struct *vma = mss->vma;
        pte_t *pte, ptent;
        spinlock_t *ptl;
        struct page *page;
+       int mapcount;
 
        pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl);
        for (; addr != end; pte++, addr += PAGE_SIZE) {
@@ -242,26 +375,88 @@ static void smaps_pte_range(struct vm_area_struct *vma, pmd_t *pmd,
                /* Accumulate the size in pages that have been accessed. */
                if (pte_young(ptent) || PageReferenced(page))
                        mss->referenced += PAGE_SIZE;
-               if (page_mapcount(page) >= 2) {
+               mapcount = page_mapcount(page);
+               if (mapcount >= 2) {
                        if (pte_dirty(ptent))
                                mss->shared_dirty += PAGE_SIZE;
                        else
                                mss->shared_clean += PAGE_SIZE;
+                       mss->pss += (PAGE_SIZE << PSS_SHIFT) / mapcount;
                } else {
                        if (pte_dirty(ptent))
                                mss->private_dirty += PAGE_SIZE;
                        else
                                mss->private_clean += PAGE_SIZE;
+                       mss->pss += (PAGE_SIZE << PSS_SHIFT);
                }
        }
        pte_unmap_unlock(pte - 1, ptl);
        cond_resched();
+       return 0;
 }
 
-static void clear_refs_pte_range(struct vm_area_struct *vma, pmd_t *pmd,
-                                unsigned long addr, unsigned long end,
-                                void *private)
+static struct mm_walk smaps_walk = { .pmd_entry = smaps_pte_range };
+
+static int show_smap(struct seq_file *m, void *v)
 {
+       struct vm_area_struct *vma = v;
+       struct mem_size_stats mss;
+       int ret;
+
+       memset(&mss, 0, sizeof mss);
+       mss.vma = vma;
+       if (vma->vm_mm && !is_vm_hugetlb_page(vma))
+               walk_page_range(vma->vm_mm, vma->vm_start, vma->vm_end,
+                               &smaps_walk, &mss);
+
+       ret = show_map(m, v);
+       if (ret)
+               return ret;
+
+       seq_printf(m,
+                  "Size:           %8lu kB\n"
+                  "Rss:            %8lu kB\n"
+                  "Pss:            %8lu kB\n"
+                  "Shared_Clean:   %8lu kB\n"
+                  "Shared_Dirty:   %8lu kB\n"
+                  "Private_Clean:  %8lu kB\n"
+                  "Private_Dirty:  %8lu kB\n"
+                  "Referenced:     %8lu kB\n",
+                  (vma->vm_end - vma->vm_start) >> 10,
+                  mss.resident >> 10,
+                  (unsigned long)(mss.pss >> (10 + PSS_SHIFT)),
+                  mss.shared_clean  >> 10,
+                  mss.shared_dirty  >> 10,
+                  mss.private_clean >> 10,
+                  mss.private_dirty >> 10,
+                  mss.referenced >> 10);
+
+       return ret;
+}
+
+static struct seq_operations proc_pid_smaps_op = {
+       .start  = m_start,
+       .next   = m_next,
+       .stop   = m_stop,
+       .show   = show_smap
+};
+
+static int smaps_open(struct inode *inode, struct file *file)
+{
+       return do_maps_open(inode, file, &proc_pid_smaps_op);
+}
+
+const struct file_operations proc_smaps_operations = {
+       .open           = smaps_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = seq_release_private,
+};
+
+static int clear_refs_pte_range(pmd_t *pmd, unsigned long addr,
+                               unsigned long end, void *private)
+{
+       struct vm_area_struct *vma = private;
        pte_t *pte, ptent;
        spinlock_t *ptl;
        struct page *page;
@@ -282,235 +477,248 @@ static void clear_refs_pte_range(struct vm_area_struct *vma, pmd_t *pmd,
        }
        pte_unmap_unlock(pte - 1, ptl);
        cond_resched();
+       return 0;
 }
 
-static inline void walk_pmd_range(struct pmd_walker *walker, pud_t *pud,
-                                 unsigned long addr, unsigned long end)
+static struct mm_walk clear_refs_walk = { .pmd_entry = clear_refs_pte_range };
+
+static ssize_t clear_refs_write(struct file *file, const char __user *buf,
+                               size_t count, loff_t *ppos)
 {
-       pmd_t *pmd;
-       unsigned long next;
+       struct task_struct *task;
+       char buffer[PROC_NUMBUF], *end;
+       struct mm_struct *mm;
+       struct vm_area_struct *vma;
 
-       for (pmd = pmd_offset(pud, addr); addr != end;
-            pmd++, addr = next) {
-               next = pmd_addr_end(addr, end);
-               if (pmd_none_or_clear_bad(pmd))
-                       continue;
-               walker->action(walker->vma, pmd, addr, next, walker->private);
+       memset(buffer, 0, sizeof(buffer));
+       if (count > sizeof(buffer) - 1)
+               count = sizeof(buffer) - 1;
+       if (copy_from_user(buffer, buf, count))
+               return -EFAULT;
+       if (!simple_strtol(buffer, &end, 0))
+               return -EINVAL;
+       if (*end == '\n')
+               end++;
+       task = get_proc_task(file->f_path.dentry->d_inode);
+       if (!task)
+               return -ESRCH;
+       mm = get_task_mm(task);
+       if (mm) {
+               down_read(&mm->mmap_sem);
+               for (vma = mm->mmap; vma; vma = vma->vm_next)
+                       if (!is_vm_hugetlb_page(vma))
+                               walk_page_range(mm, vma->vm_start, vma->vm_end,
+                                               &clear_refs_walk, vma);
+               flush_tlb_mm(mm);
+               up_read(&mm->mmap_sem);
+               mmput(mm);
        }
+       put_task_struct(task);
+       if (end - buffer == 0)
+               return -EIO;
+       return end - buffer;
 }
 
-static inline void walk_pud_range(struct pmd_walker *walker, pgd_t *pgd,
-                                 unsigned long addr, unsigned long end)
-{
-       pud_t *pud;
-       unsigned long next;
+const struct file_operations proc_clear_refs_operations = {
+       .write          = clear_refs_write,
+};
 
-       for (pud = pud_offset(pgd, addr); addr != end;
-            pud++, addr = next) {
-               next = pud_addr_end(addr, end);
-               if (pud_none_or_clear_bad(pud))
-                       continue;
-               walk_pmd_range(walker, pud, addr, next);
+struct pagemapread {
+       char __user *out, *end;
+};
+
+#define PM_ENTRY_BYTES sizeof(u64)
+#define PM_RESERVED_BITS    3
+#define PM_RESERVED_OFFSET  (64 - PM_RESERVED_BITS)
+#define PM_RESERVED_MASK    (((1LL<<PM_RESERVED_BITS)-1) << PM_RESERVED_OFFSET)
+#define PM_SPECIAL(nr)      (((nr) << PM_RESERVED_OFFSET) | PM_RESERVED_MASK)
+#define PM_NOT_PRESENT      PM_SPECIAL(1LL)
+#define PM_SWAP             PM_SPECIAL(2LL)
+#define PM_END_OF_BUFFER    1
+
+static int add_to_pagemap(unsigned long addr, u64 pfn,
+                         struct pagemapread *pm)
+{
+       /*
+        * Make sure there's room in the buffer for an
+        * entire entry.  Otherwise, only copy part of
+        * the pfn.
+        */
+       if (pm->out + PM_ENTRY_BYTES >= pm->end) {
+               if (copy_to_user(pm->out, &pfn, pm->end - pm->out))
+                       return -EFAULT;
+               pm->out = pm->end;
+               return PM_END_OF_BUFFER;
        }
+
+       if (put_user(pfn, pm->out))
+               return -EFAULT;
+       pm->out += PM_ENTRY_BYTES;
+       return 0;
 }
 
-/*
- * walk_page_range - walk the page tables of a VMA with a callback
- * @vma - VMA to walk
- * @action - callback invoked for every bottom-level (PTE) page table
- * @private - private data passed to the callback function
- *
- * Recursively walk the page table for the memory area in a VMA, calling
- * a callback for every bottom-level (PTE) page table.
- */
-static inline void walk_page_range(struct vm_area_struct *vma,
-                                  void (*action)(struct vm_area_struct *,
-                                                 pmd_t *, unsigned long,
-                                                 unsigned long, void *),
-                                  void *private)
+static int pagemap_pte_hole(unsigned long start, unsigned long end,
+                               void *private)
 {
-       unsigned long addr = vma->vm_start;
-       unsigned long end = vma->vm_end;
-       struct pmd_walker walker = {
-               .vma            = vma,
-               .private        = private,
-               .action         = action,
-       };
-       pgd_t *pgd;
-       unsigned long next;
-
-       for (pgd = pgd_offset(vma->vm_mm, addr); addr != end;
-            pgd++, addr = next) {
-               next = pgd_addr_end(addr, end);
-               if (pgd_none_or_clear_bad(pgd))
-                       continue;
-               walk_pud_range(&walker, pgd, addr, next);
+       struct pagemapread *pm = private;
+       unsigned long addr;
+       int err = 0;
+       for (addr = start; addr < end; addr += PAGE_SIZE) {
+               err = add_to_pagemap(addr, PM_NOT_PRESENT, pm);
+               if (err)
+                       break;
        }
+       return err;
 }
 
-static int show_smap(struct seq_file *m, void *v)
+u64 swap_pte_to_pagemap_entry(pte_t pte)
 {
-       struct vm_area_struct *vma = v;
-       struct mem_size_stats mss;
-
-       memset(&mss, 0, sizeof mss);
-       if (vma->vm_mm && !is_vm_hugetlb_page(vma))
-               walk_page_range(vma, smaps_pte_range, &mss);
-       return show_map_internal(m, v, &mss);
+       swp_entry_t e = pte_to_swp_entry(pte);
+       return PM_SWAP | swp_type(e) | (swp_offset(e) << MAX_SWAPFILES_SHIFT);
 }
 
-void clear_refs_smap(struct mm_struct *mm)
+static int pagemap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end,
+                            void *private)
 {
-       struct vm_area_struct *vma;
+       struct pagemapread *pm = private;
+       pte_t *pte;
+       int err = 0;
+
+       for (; addr != end; addr += PAGE_SIZE) {
+               u64 pfn = PM_NOT_PRESENT;
+               pte = pte_offset_map(pmd, addr);
+               if (is_swap_pte(*pte))
+                       pfn = swap_pte_to_pagemap_entry(*pte);
+               else if (pte_present(*pte))
+                       pfn = pte_pfn(*pte);
+               /* unmap so we're not in atomic when we copy to userspace */
+               pte_unmap(pte);
+               err = add_to_pagemap(addr, pfn, pm);
+               if (err)
+                       return err;
+       }
 
-       down_read(&mm->mmap_sem);
-       for (vma = mm->mmap; vma; vma = vma->vm_next)
-               if (vma->vm_mm && !is_vm_hugetlb_page(vma))
-                       walk_page_range(vma, clear_refs_pte_range, NULL);
-       flush_tlb_mm(mm);
-       up_read(&mm->mmap_sem);
+       cond_resched();
+
+       return err;
 }
 
-static void *m_start(struct seq_file *m, loff_t *pos)
+static struct mm_walk pagemap_walk = {
+       .pmd_entry = pagemap_pte_range,
+       .pte_hole = pagemap_pte_hole
+};
+
+/*
+ * /proc/pid/pagemap - an array mapping virtual pages to pfns
+ *
+ * For each page in the address space, this file contains one 64-bit
+ * entry representing the corresponding physical page frame number
+ * (PFN) if the page is present. If there is a swap entry for the
+ * physical page, then an encoding of the swap file number and the
+ * page's offset into the swap file are returned. If no page is
+ * present at all, PM_NOT_PRESENT is returned. This allows determining
+ * precisely which pages are mapped (or in swap) and comparing mapped
+ * pages between processes.
+ *
+ * Efficient users of this interface will use /proc/pid/maps to
+ * determine which areas of memory are actually mapped and llseek to
+ * skip over unmapped regions.
+ */
+static ssize_t pagemap_read(struct file *file, char __user *buf,
+                           size_t count, loff_t *ppos)
 {
-       struct proc_maps_private *priv = m->private;
-       unsigned long last_addr = m->version;
+       struct task_struct *task = get_proc_task(file->f_path.dentry->d_inode);
+       struct page **pages, *page;
+       unsigned long uaddr, uend;
        struct mm_struct *mm;
-       struct vm_area_struct *vma, *tail_vma = NULL;
-       loff_t l = *pos;
-
-       /* Clear the per syscall fields in priv */
-       priv->task = NULL;
-       priv->tail_vma = NULL;
+       struct pagemapread pm;
+       int pagecount;
+       int ret = -ESRCH;
 
-       /*
-        * We remember last_addr rather than next_addr to hit with
-        * mmap_cache most of the time. We have zero last_addr at
-        * the beginning and also after lseek. We will have -1 last_addr
-        * after the end of the vmas.
-        */
+       if (!task)
+               goto out;
 
-       if (last_addr == -1UL)
-               return NULL;
+       ret = -EACCES;
+       if (!ptrace_may_attach(task))
+               goto out;
 
-       priv->task = get_pid_task(priv->pid, PIDTYPE_PID);
-       if (!priv->task)
-               return NULL;
+       ret = -EINVAL;
+       /* file position must be aligned */
+       if (*ppos % PM_ENTRY_BYTES)
+               goto out;
 
-       mm = mm_for_maps(priv->task);
+       ret = 0;
+       mm = get_task_mm(task);
        if (!mm)
-               return NULL;
-
-       priv->tail_vma = tail_vma = get_gate_vma(priv->task);
-
-       /* Start with last addr hint */
-       if (last_addr && (vma = find_vma(mm, last_addr))) {
-               vma = vma->vm_next;
                goto out;
-       }
 
-       /*
-        * Check the vma index is within the range and do
-        * sequential scan until m_index.
-        */
-       vma = NULL;
-       if ((unsigned long)l < mm->map_count) {
-               vma = mm->mmap;
-               while (l-- && vma)
-                       vma = vma->vm_next;
-               goto out;
-       }
+       ret = -ENOMEM;
+       uaddr = (unsigned long)buf & PAGE_MASK;
+       uend = (unsigned long)(buf + count);
+       pagecount = (PAGE_ALIGN(uend) - uaddr) / PAGE_SIZE;
+       pages = kmalloc(pagecount * sizeof(struct page *), GFP_KERNEL);
+       if (!pages)
+               goto out_task;
 
-       if (l != mm->map_count)
-               tail_vma = NULL; /* After gate vma */
+       down_read(&current->mm->mmap_sem);
+       ret = get_user_pages(current, current->mm, uaddr, pagecount,
+                            1, 0, pages, NULL);
+       up_read(&current->mm->mmap_sem);
 
-out:
-       if (vma)
-               return vma;
+       if (ret < 0)
+               goto out_free;
 
-       /* End of vmas has been reached */
-       m->version = (tail_vma != NULL)? 0: -1UL;
-       up_read(&mm->mmap_sem);
-       mmput(mm);
-       return tail_vma;
-}
+       pm.out = buf;
+       pm.end = buf + count;
 
-static void vma_stop(struct proc_maps_private *priv, struct vm_area_struct *vma)
-{
-       if (vma && vma != priv->tail_vma) {
-               struct mm_struct *mm = vma->vm_mm;
-               up_read(&mm->mmap_sem);
-               mmput(mm);
+       if (!ptrace_may_attach(task)) {
+               ret = -EIO;
+       } else {
+               unsigned long src = *ppos;
+               unsigned long svpfn = src / PM_ENTRY_BYTES;
+               unsigned long start_vaddr = svpfn << PAGE_SHIFT;
+               unsigned long end_vaddr = TASK_SIZE_OF(task);
+
+               /* watch out for wraparound */
+               if (svpfn > TASK_SIZE_OF(task) >> PAGE_SHIFT)
+                       start_vaddr = end_vaddr;
+
+               /*
+                * The odds are that this will stop walking way
+                * before end_vaddr, because the length of the
+                * user buffer is tracked in "pm", and the walk
+                * will stop when we hit the end of the buffer.
+                */
+               ret = walk_page_range(mm, start_vaddr, end_vaddr,
+                                       &pagemap_walk, &pm);
+               if (ret == PM_END_OF_BUFFER)
+                       ret = 0;
+               /* don't need mmap_sem for these, but this looks cleaner */
+               *ppos += pm.out - buf;
+               if (!ret)
+                       ret = pm.out - buf;
        }
-}
-
-static void *m_next(struct seq_file *m, void *v, loff_t *pos)
-{
-       struct proc_maps_private *priv = m->private;
-       struct vm_area_struct *vma = v;
-       struct vm_area_struct *tail_vma = priv->tail_vma;
-
-       (*pos)++;
-       if (vma && (vma != tail_vma) && vma->vm_next)
-               return vma->vm_next;
-       vma_stop(priv, vma);
-       return (vma != tail_vma)? tail_vma: NULL;
-}
-
-static void m_stop(struct seq_file *m, void *v)
-{
-       struct proc_maps_private *priv = m->private;
-       struct vm_area_struct *vma = v;
 
-       vma_stop(priv, vma);
-       if (priv->task)
-               put_task_struct(priv->task);
-}
-
-static struct seq_operations proc_pid_maps_op = {
-       .start  = m_start,
-       .next   = m_next,
-       .stop   = m_stop,
-       .show   = show_map
-};
-
-static struct seq_operations proc_pid_smaps_op = {
-       .start  = m_start,
-       .next   = m_next,
-       .stop   = m_stop,
-       .show   = show_smap
-};
-
-static int do_maps_open(struct inode *inode, struct file *file,
-                       struct seq_operations *ops)
-{
-       struct proc_maps_private *priv;
-       int ret = -ENOMEM;
-       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
-       if (priv) {
-               priv->pid = proc_pid(inode);
-               ret = seq_open(file, ops);
-               if (!ret) {
-                       struct seq_file *m = file->private_data;
-                       m->private = priv;
-               } else {
-                       kfree(priv);
-               }
+       for (; pagecount; pagecount--) {
+               page = pages[pagecount-1];
+               if (!PageReserved(page))
+                       SetPageDirty(page);
+               page_cache_release(page);
        }
+       mmput(mm);
+out_free:
+       kfree(pages);
+out_task:
+       put_task_struct(task);
+out:
        return ret;
 }
 
-static int maps_open(struct inode *inode, struct file *file)
-{
-       return do_maps_open(inode, file, &proc_pid_maps_op);
-}
-
-const struct file_operations proc_maps_operations = {
-       .open           = maps_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = seq_release_private,
+const struct file_operations proc_pagemap_operations = {
+       .llseek         = mem_lseek, /* borrow this */
+       .read           = pagemap_read,
 };
+#endif /* CONFIG_PROC_PAGE_MONITOR */
 
 #ifdef CONFIG_NUMA
 extern int show_numa_map(struct seq_file *m, void *v);
@@ -545,15 +753,3 @@ const struct file_operations proc_numa_maps_operations = {
        .release        = seq_release_private,
 };
 #endif
-
-static int smaps_open(struct inode *inode, struct file *file)
-{
-       return do_maps_open(inode, file, &proc_pid_smaps_op);
-}
-
-const struct file_operations proc_smaps_operations = {
-       .open           = smaps_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = seq_release_private,
-};
index efe52e67657719963d5ac1cd22df34e7465d4234..4e026e5407fb7516c3a52c8533f0159b6b7ecdd9 100644 (file)
@@ -30,7 +30,10 @@ int vfs_readdir(struct file *file, filldir_t filler, void *buf)
        if (res)
                goto out;
 
-       mutex_lock(&inode->i_mutex);
+       res = mutex_lock_killable(&inode->i_mutex);
+       if (res)
+               goto out;
+
        res = -ENOENT;
        if (!IS_DEADDIR(inode)) {
                res = file->f_op->readdir(file, buf, filler);
index 16b331dd9913a93f6575d8ec38dd9b63dcf05251..f491ceb5af02d9a8c089066e8a3ca908c641acaa 100644 (file)
@@ -272,7 +272,7 @@ static inline int block_group_used(struct super_block *s, u32 id)
 
        /* If we don't have cached information on this bitmap block, we're
         * going to have to load it later anyway. Loading it here allows us
-        * to make a better decision. This favors long-term performace gain
+        * to make a better decision. This favors long-term performance gain
         * with a better on-disk layout vs. a short term gain of skipping the
         * read and potentially having a bad placement. */
        if (info->free_count == UINT_MAX) {
@@ -663,7 +663,7 @@ static inline void new_hashed_relocation(reiserfs_blocknr_hint_t * hint)
 
 /*
  * Relocation based on dirid, hashing them into a given bitmap block
- * files. Formatted nodes are unaffected, a seperate policy covers them
+ * files. Formatted nodes are unaffected, a separate policy covers them
  */
 static void dirid_groups(reiserfs_blocknr_hint_t * hint)
 {
@@ -688,7 +688,7 @@ static void dirid_groups(reiserfs_blocknr_hint_t * hint)
 
 /*
  * Relocation based on oid, hashing them into a given bitmap block
- * files. Formatted nodes are unaffected, a seperate policy covers them
+ * files. Formatted nodes are unaffected, a separate policy covers them
  */
 static void oid_groups(reiserfs_blocknr_hint_t * hint)
 {
index 231fd5ccadc52040775842b7a8867c18656314b8..195309857e6323048e20b2286952e56b754b5301 100644 (file)
@@ -2143,7 +2143,7 @@ int reiserfs_truncate_file(struct inode *p_s_inode, int update_timestamps)
                /* if we are not on a block boundary */
                if (length) {
                        length = blocksize - length;
-                       zero_user_page(page, offset, length, KM_USER0);
+                       zero_user(page, offset, length);
                        if (buffer_mapped(bh) && bh->b_blocknr != 0) {
                                mark_buffer_dirty(bh);
                        }
@@ -2367,7 +2367,7 @@ static int reiserfs_write_full_page(struct page *page,
                        unlock_page(page);
                        return 0;
                }
-               zero_user_page(page, last_offset, PAGE_CACHE_SIZE - last_offset, KM_USER0);
+               zero_user_segment(page, last_offset, PAGE_CACHE_SIZE);
        }
        bh = head;
        block = page->index << (PAGE_CACHE_SHIFT - s->s_blocksize_bits);
index fb7f7e8034df512db10978276d7c2cf8f9cc0a75..2d3e107da2d3d009d49b505e1110c711f8d25112 100644 (file)
@@ -66,7 +66,7 @@ static int signalfd_copyinfo(struct signalfd_siginfo __user *uinfo,
        BUILD_BUG_ON(sizeof(struct signalfd_siginfo) != 128);
 
        /*
-        * Unused memebers should be zero ...
+        * Unused members should be zero ...
         */
        err = __clear_user(uinfo, sizeof(*uinfo));
 
index 9416ead0c7aae67ef1c2bd8b9d3ce12e79cdd9c8..4e5c22ca802e86f77380f51fdb402bcd7add26c9 100644 (file)
@@ -500,6 +500,13 @@ static int smb_fill_super(struct super_block *sb, void *raw_data, int silent)
        struct smb_fattr root;
        int ver;
        void *mem;
+       static int warn_count;
+
+       if (warn_count < 5) {
+               warn_count++;
+               printk(KERN_EMERG "smbfs is deprecated and will be removed"
+                       "from the 2.6.27 kernel.  Please migrate to cifs\n");
+       }
 
        if (!raw_data)
                goto out_no_data;
index ca4b2d59c0ca6f501ff11466af81a6111a182afc..45f45933e86279126f1f349b2381563c102d0559 100644 (file)
@@ -105,7 +105,7 @@ struct smb_request *smb_alloc_request(struct smb_sb_info *server, int bufsize)
                 if (nfs_try_to_free_pages(server))
                        continue;
 
-               if (signalled() && (server->flags & NFS_MOUNT_INTR))
+               if (fatal_signal_pending(current))
                        return ERR_PTR(-ERESTARTSYS);
                current->policy = SCHED_YIELD;
                schedule();
index 1577a7391d23fa47cd74fb5089278dba81daee55..4ee49e86edde5a2272781b6e49e0371b721ceb33 100644 (file)
@@ -1033,9 +1033,7 @@ ssize_t splice_direct_to_actor(struct file *in, struct splice_desc *sd,
 
 done:
        pipe->nrbufs = pipe->curbuf = 0;
-       if (bytes > 0)
-               file_accessed(in);
-
+       file_accessed(in);
        return bytes;
 
 out_release:
index 61983f3b107c5ee5d12521d3f38255a77bc6f781..10c80b59ec4bb7e542b8864f369ec10da7dc34f5 100644 (file)
@@ -25,13 +25,15 @@ struct timerfd_ctx {
        struct hrtimer tmr;
        ktime_t tintv;
        wait_queue_head_t wqh;
+       u64 ticks;
        int expired;
+       int clockid;
 };
 
 /*
  * This gets called when the timer event triggers. We set the "expired"
  * flag, but we do not re-arm the timer (in case it's necessary,
- * tintv.tv64 != 0) until the timer is read.
+ * tintv.tv64 != 0) until the timer is accessed.
  */
 static enum hrtimer_restart timerfd_tmrproc(struct hrtimer *htmr)
 {
@@ -40,13 +42,24 @@ static enum hrtimer_restart timerfd_tmrproc(struct hrtimer *htmr)
 
        spin_lock_irqsave(&ctx->wqh.lock, flags);
        ctx->expired = 1;
+       ctx->ticks++;
        wake_up_locked(&ctx->wqh);
        spin_unlock_irqrestore(&ctx->wqh.lock, flags);
 
        return HRTIMER_NORESTART;
 }
 
-static void timerfd_setup(struct timerfd_ctx *ctx, int clockid, int flags,
+static ktime_t timerfd_get_remaining(struct timerfd_ctx *ctx)
+{
+       ktime_t now, remaining;
+
+       now = ctx->tmr.base->get_time();
+       remaining = ktime_sub(ctx->tmr.expires, now);
+
+       return remaining.tv64 < 0 ? ktime_set(0, 0): remaining;
+}
+
+static void timerfd_setup(struct timerfd_ctx *ctx, int flags,
                          const struct itimerspec *ktmr)
 {
        enum hrtimer_mode htmode;
@@ -57,8 +70,9 @@ static void timerfd_setup(struct timerfd_ctx *ctx, int clockid, int flags,
 
        texp = timespec_to_ktime(ktmr->it_value);
        ctx->expired = 0;
+       ctx->ticks = 0;
        ctx->tintv = timespec_to_ktime(ktmr->it_interval);
-       hrtimer_init(&ctx->tmr, clockid, htmode);
+       hrtimer_init(&ctx->tmr, ctx->clockid, htmode);
        ctx->tmr.expires = texp;
        ctx->tmr.function = timerfd_tmrproc;
        if (texp.tv64 != 0)
@@ -83,7 +97,7 @@ static unsigned int timerfd_poll(struct file *file, poll_table *wait)
        poll_wait(file, &ctx->wqh, wait);
 
        spin_lock_irqsave(&ctx->wqh.lock, flags);
-       if (ctx->expired)
+       if (ctx->ticks)
                events |= POLLIN;
        spin_unlock_irqrestore(&ctx->wqh.lock, flags);
 
@@ -102,11 +116,11 @@ static ssize_t timerfd_read(struct file *file, char __user *buf, size_t count,
                return -EINVAL;
        spin_lock_irq(&ctx->wqh.lock);
        res = -EAGAIN;
-       if (!ctx->expired && !(file->f_flags & O_NONBLOCK)) {
+       if (!ctx->ticks && !(file->f_flags & O_NONBLOCK)) {
                __add_wait_queue(&ctx->wqh, &wait);
                for (res = 0;;) {
                        set_current_state(TASK_INTERRUPTIBLE);
-                       if (ctx->expired) {
+                       if (ctx->ticks) {
                                res = 0;
                                break;
                        }
@@ -121,22 +135,21 @@ static ssize_t timerfd_read(struct file *file, char __user *buf, size_t count,
                __remove_wait_queue(&ctx->wqh, &wait);
                __set_current_state(TASK_RUNNING);
        }
-       if (ctx->expired) {
-               ctx->expired = 0;
-               if (ctx->tintv.tv64 != 0) {
+       if (ctx->ticks) {
+               ticks = ctx->ticks;
+               if (ctx->expired && ctx->tintv.tv64) {
                        /*
                         * If tintv.tv64 != 0, this is a periodic timer that
                         * needs to be re-armed. We avoid doing it in the timer
                         * callback to avoid DoS attacks specifying a very
                         * short timer period.
                         */
-                       ticks = (u64)
-                               hrtimer_forward(&ctx->tmr,
-                                               hrtimer_cb_get_time(&ctx->tmr),
-                                               ctx->tintv);
+                       ticks += hrtimer_forward_now(&ctx->tmr,
+                                                    ctx->tintv) - 1;
                        hrtimer_restart(&ctx->tmr);
-               } else
-                       ticks = 1;
+               }
+               ctx->expired = 0;
+               ctx->ticks = 0;
        }
        spin_unlock_irq(&ctx->wqh.lock);
        if (ticks)
@@ -150,76 +163,132 @@ static const struct file_operations timerfd_fops = {
        .read           = timerfd_read,
 };
 
-asmlinkage long sys_timerfd(int ufd, int clockid, int flags,
-                           const struct itimerspec __user *utmr)
+static struct file *timerfd_fget(int fd)
+{
+       struct file *file;
+
+       file = fget(fd);
+       if (!file)
+               return ERR_PTR(-EBADF);
+       if (file->f_op != &timerfd_fops) {
+               fput(file);
+               return ERR_PTR(-EINVAL);
+       }
+
+       return file;
+}
+
+asmlinkage long sys_timerfd_create(int clockid, int flags)
 {
-       int error;
+       int error, ufd;
        struct timerfd_ctx *ctx;
        struct file *file;
        struct inode *inode;
-       struct itimerspec ktmr;
-
-       if (copy_from_user(&ktmr, utmr, sizeof(ktmr)))
-               return -EFAULT;
 
+       if (flags)
+               return -EINVAL;
        if (clockid != CLOCK_MONOTONIC &&
            clockid != CLOCK_REALTIME)
                return -EINVAL;
+
+       ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+       if (!ctx)
+               return -ENOMEM;
+
+       init_waitqueue_head(&ctx->wqh);
+       ctx->clockid = clockid;
+       hrtimer_init(&ctx->tmr, clockid, HRTIMER_MODE_ABS);
+
+       error = anon_inode_getfd(&ufd, &inode, &file, "[timerfd]",
+                                &timerfd_fops, ctx);
+       if (error) {
+               kfree(ctx);
+               return error;
+       }
+
+       return ufd;
+}
+
+asmlinkage long sys_timerfd_settime(int ufd, int flags,
+                                   const struct itimerspec __user *utmr,
+                                   struct itimerspec __user *otmr)
+{
+       struct file *file;
+       struct timerfd_ctx *ctx;
+       struct itimerspec ktmr, kotmr;
+
+       if (copy_from_user(&ktmr, utmr, sizeof(ktmr)))
+               return -EFAULT;
+
        if (!timespec_valid(&ktmr.it_value) ||
            !timespec_valid(&ktmr.it_interval))
                return -EINVAL;
 
-       if (ufd == -1) {
-               ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
-               if (!ctx)
-                       return -ENOMEM;
-
-               init_waitqueue_head(&ctx->wqh);
-
-               timerfd_setup(ctx, clockid, flags, &ktmr);
-
-               /*
-                * When we call this, the initialization must be complete, since
-                * anon_inode_getfd() will install the fd.
-                */
-               error = anon_inode_getfd(&ufd, &inode, &file, "[timerfd]",
-                                        &timerfd_fops, ctx);
-               if (error)
-                       goto err_tmrcancel;
-       } else {
-               file = fget(ufd);
-               if (!file)
-                       return -EBADF;
-               ctx = file->private_data;
-               if (file->f_op != &timerfd_fops) {
-                       fput(file);
-                       return -EINVAL;
-               }
-               /*
-                * We need to stop the existing timer before reprogramming
-                * it to the new values.
-                */
-               for (;;) {
-                       spin_lock_irq(&ctx->wqh.lock);
-                       if (hrtimer_try_to_cancel(&ctx->tmr) >= 0)
-                               break;
-                       spin_unlock_irq(&ctx->wqh.lock);
-                       cpu_relax();
-               }
-               /*
-                * Re-program the timer to the new value ...
-                */
-               timerfd_setup(ctx, clockid, flags, &ktmr);
+       file = timerfd_fget(ufd);
+       if (IS_ERR(file))
+               return PTR_ERR(file);
+       ctx = file->private_data;
 
+       /*
+        * We need to stop the existing timer before reprogramming
+        * it to the new values.
+        */
+       for (;;) {
+               spin_lock_irq(&ctx->wqh.lock);
+               if (hrtimer_try_to_cancel(&ctx->tmr) >= 0)
+                       break;
                spin_unlock_irq(&ctx->wqh.lock);
-               fput(file);
+               cpu_relax();
        }
 
-       return ufd;
+       /*
+        * If the timer is expired and it's periodic, we need to advance it
+        * because the caller may want to know the previous expiration time.
+        * We do not update "ticks" and "expired" since the timer will be
+        * re-programmed again in the following timerfd_setup() call.
+        */
+       if (ctx->expired && ctx->tintv.tv64)
+               hrtimer_forward_now(&ctx->tmr, ctx->tintv);
 
-err_tmrcancel:
-       hrtimer_cancel(&ctx->tmr);
-       kfree(ctx);
-       return error;
+       kotmr.it_value = ktime_to_timespec(timerfd_get_remaining(ctx));
+       kotmr.it_interval = ktime_to_timespec(ctx->tintv);
+
+       /*
+        * Re-program the timer to the new value ...
+        */
+       timerfd_setup(ctx, flags, &ktmr);
+
+       spin_unlock_irq(&ctx->wqh.lock);
+       fput(file);
+       if (otmr && copy_to_user(otmr, &kotmr, sizeof(kotmr)))
+               return -EFAULT;
+
+       return 0;
+}
+
+asmlinkage long sys_timerfd_gettime(int ufd, struct itimerspec __user *otmr)
+{
+       struct file *file;
+       struct timerfd_ctx *ctx;
+       struct itimerspec kotmr;
+
+       file = timerfd_fget(ufd);
+       if (IS_ERR(file))
+               return PTR_ERR(file);
+       ctx = file->private_data;
+
+       spin_lock_irq(&ctx->wqh.lock);
+       if (ctx->expired && ctx->tintv.tv64) {
+               ctx->expired = 0;
+               ctx->ticks +=
+                       hrtimer_forward_now(&ctx->tmr, ctx->tintv) - 1;
+               hrtimer_restart(&ctx->tmr);
+       }
+       kotmr.it_value = ktime_to_timespec(timerfd_get_remaining(ctx));
+       kotmr.it_interval = ktime_to_timespec(ctx->tintv);
+       spin_unlock_irq(&ctx->wqh.lock);
+       fput(file);
+
+       return copy_to_user(otmr, &kotmr, sizeof(kotmr)) ? -EFAULT: 0;
 }
 
index 6645b7313b3372a0a490bdc9b382f81fc8ace71c..f7c8f87bb39065c1ed6fa3011bbb653fcc029e5c 100644 (file)
@@ -104,6 +104,33 @@ out:
 }
 EXPORT_SYMBOL_GPL(vfs_setxattr);
 
+ssize_t
+xattr_getsecurity(struct inode *inode, const char *name, void *value,
+                       size_t size)
+{
+       void *buffer = NULL;
+       ssize_t len;
+
+       if (!value || !size) {
+               len = security_inode_getsecurity(inode, name, &buffer, false);
+               goto out_noalloc;
+       }
+
+       len = security_inode_getsecurity(inode, name, &buffer, true);
+       if (len < 0)
+               return len;
+       if (size < len) {
+               len = -ERANGE;
+               goto out;
+       }
+       memcpy(value, buffer, len);
+out:
+       security_release_secctx(buffer, len);
+out_noalloc:
+       return len;
+}
+EXPORT_SYMBOL_GPL(xattr_getsecurity);
+
 ssize_t
 vfs_getxattr(struct dentry *dentry, char *name, void *value, size_t size)
 {
@@ -118,23 +145,23 @@ vfs_getxattr(struct dentry *dentry, char *name, void *value, size_t size)
        if (error)
                return error;
 
-       if (inode->i_op->getxattr)
-               error = inode->i_op->getxattr(dentry, name, value, size);
-       else
-               error = -EOPNOTSUPP;
-
        if (!strncmp(name, XATTR_SECURITY_PREFIX,
                                XATTR_SECURITY_PREFIX_LEN)) {
                const char *suffix = name + XATTR_SECURITY_PREFIX_LEN;
-               int ret = security_inode_getsecurity(inode, suffix, value,
-                                                    size, error);
+               int ret = xattr_getsecurity(inode, suffix, value, size);
                /*
                 * Only overwrite the return value if a security module
                 * is actually active.
                 */
-               if (ret != -EOPNOTSUPP)
-                       error = ret;
+               if (ret == -EOPNOTSUPP)
+                       goto nolsm;
+               return ret;
        }
+nolsm:
+       if (inode->i_op->getxattr)
+               error = inode->i_op->getxattr(dentry, name, value, size);
+       else
+               error = -EOPNOTSUPP;
 
        return error;
 }
index ed2b16dff91434f2bd0b90d35dec3921c447cb27..e040f1ce1b6a71885c6453c620bcf3642ddd45c1 100644 (file)
@@ -92,8 +92,7 @@ kmem_zalloc_greedy(size_t *size, size_t minsize, size_t maxsize,
 void
 kmem_free(void *ptr, size_t size)
 {
-       if (((unsigned long)ptr < VMALLOC_START) ||
-           ((unsigned long)ptr >= VMALLOC_END)) {
+       if (!is_vmalloc_addr(ptr)) {
                kfree(ptr);
        } else {
                vfree(ptr);
index a49dd8d4b06974c9a9b8b20ca19bc0663dfe0471..0382c19d6523708792675b9215aebd4867801aa3 100644 (file)
@@ -709,8 +709,7 @@ static inline struct page *
 mem_to_page(
        void                    *addr)
 {
-       if (((unsigned long)addr < VMALLOC_START) ||
-           ((unsigned long)addr >= VMALLOC_END)) {
+       if ((!is_vmalloc_addr(addr))) {
                return virt_to_page(addr);
        } else {
                return vmalloc_to_page(addr);
index d6a8dddb2268bab8a341499d0debadba041f3928..6f614f35f65015140d2078a92484328d275e94c1 100644 (file)
@@ -155,7 +155,7 @@ xfs_iozero(
                if (status)
                        break;
 
-               zero_user_page(page, offset, bytes, KM_USER0);
+               zero_user(page, offset, bytes);
 
                status = pagecache_write_end(NULL, mapping, pos, bytes, bytes,
                                        page, fsdata);
index 9512f0456ad1f241df8ba36e64f1d0cb060fef6a..d970f7f99549639183b73d8324043c2805020dd5 100644 (file)
@@ -85,7 +85,7 @@ acpi_install_initialization_handler(acpi_init_handler handler, u32 function);
 #endif
 
 /*
- * ACPI Memory managment
+ * ACPI Memory management
  */
 void *acpi_allocate(u32 size);
 
@@ -335,6 +335,8 @@ acpi_status asmlinkage acpi_enter_sleep_state(u8 sleep_state);
 
 acpi_status asmlinkage acpi_enter_sleep_state_s4bios(void);
 
+acpi_status acpi_leave_sleep_state_prep(u8 sleep_state);
+
 acpi_status acpi_leave_sleep_state(u8 sleep_state);
 
 #endif                         /* __ACXFACE_H__ */
index 76411b1fc4fd4778e2e35cda00da46ead7b7dd5e..6e253b5b0f3bc33ba5d7c622bb0d689ee4df2c12 100644 (file)
@@ -182,7 +182,7 @@ struct acpi_processor_throttling {
 /* Limit Interface */
 
 struct acpi_processor_lx {
-       int px;                 /* performace state */
+       int px;                 /* performance state */
        int tx;                 /* throttle level */
 };
 
index f5cb7b878af25ba2dd69abb0343327db8c183dd4..ca88e54dec93774770f3eb93629d908db69e499e 100644 (file)
@@ -100,7 +100,7 @@ static __inline__ void atomic64_sub(long i, atomic64_t * v)
 /*
  * Same as above, but return the result value
  */
-static __inline__ long atomic_add_return(int i, atomic_t * v)
+static inline int atomic_add_return(int i, atomic_t *v)
 {
        long temp, result;
        smp_mb();
index 30ee7669b19f9622703478bd77c45aab598c628e..d5b10ef643642b292c7baad6098d06175520f8e9 100644 (file)
@@ -4,6 +4,7 @@
 #ifdef __KERNEL__
 
 #include <linux/spinlock.h>
+#include <linux/dma-mapping.h>
 #include <asm/scatterlist.h>
 #include <asm/machvec.h>
 
index 471864e8d4c370d17d3ff5a672c95cc71444087a..fdbedacc7375158990236e13b546a7fa1c92a8a6 100644 (file)
@@ -31,7 +31,7 @@ pgd_populate(struct mm_struct *mm, pgd_t *pgd, pmd_t *pmd)
 extern pgd_t *pgd_alloc(struct mm_struct *mm);
 
 static inline void
-pgd_free(pgd_t *pgd)
+pgd_free(struct mm_struct *mm, pgd_t *pgd)
 {
        free_page((unsigned long)pgd);
 }
@@ -44,7 +44,7 @@ pmd_alloc_one(struct mm_struct *mm, unsigned long address)
 }
 
 static inline void
-pmd_free(pmd_t *pmd)
+pmd_free(struct mm_struct *mm, pmd_t *pmd)
 {
        free_page((unsigned long)pmd);
 }
@@ -52,7 +52,7 @@ pmd_free(pmd_t *pmd)
 extern pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long addr);
 
 static inline void
-pte_free_kernel(pte_t *pte)
+pte_free_kernel(struct mm_struct *mm, pte_t *pte)
 {
        free_page((unsigned long)pte);
 }
@@ -67,7 +67,7 @@ pte_alloc_one(struct mm_struct *mm, unsigned long addr)
 }
 
 static inline void
-pte_free(struct page *page)
+pte_free(struct mm_struct *mm, struct page *page)
 {
        __free_page(page);
 }
index 1fede7f928600bd5e4b82ddbfe04c615c8f8b2f8..08c9793199290fefc36f027da65f7e7e50f9cd43 100644 (file)
@@ -60,4 +60,6 @@
 #define SO_SECURITY_ENCRYPTION_TRANSPORT       20
 #define SO_SECURITY_ENCRYPTION_NETWORK         21
 
+#define SO_MARK                        36
+
 #endif /* _ASM_SOCKET_H */
index aa91335533e0443b87a6b5863943716ff17e1d8b..c13636575fbab4fb14c17b75d53058b0f9181e1c 100644 (file)
@@ -9,7 +9,7 @@
 
 #include <asm-generic/tlb.h>
 
-#define __pte_free_tlb(tlb,pte)                        pte_free(pte)
-#define __pmd_free_tlb(tlb,pmd)                        pmd_free(pmd)
+#define __pte_free_tlb(tlb, pte)                       pte_free((tlb)->mm, pte)
+#define __pmd_free_tlb(tlb, pmd)                       pmd_free((tlb)->mm, pmd)
  
 #endif
index eefab3fb51ae87f76050c34118fabe6d31c87078..9d87aaa08c0df1cf093bbb90227a2f8470adb70e 100644 (file)
@@ -3,6 +3,7 @@
 
 #include <linux/mm.h>
 #include <asm/compiler.h>
+#include <asm/pgalloc.h>
 
 #ifndef __EXTERN_INLINE
 #define __EXTERN_INLINE extern inline
@@ -141,6 +142,10 @@ extern void flush_tlb_range(struct vm_area_struct *, unsigned long,
 
 #endif /* CONFIG_SMP */
 
-#define flush_tlb_kernel_range(start, end) flush_tlb_all()
+static inline void flush_tlb_kernel_range(unsigned long start,
+                                       unsigned long end)
+{
+       flush_tlb_all();
+}
 
 #endif /* _ALPHA_TLBFLUSH_H */
index 29bf2fdc91c0eefe194b5123774e88eb29c4f8b6..5b5c174859428edda511595e263a4540ce7d9354 100644 (file)
 #define __ARCH_WANT_OLD_READDIR
 #define __ARCH_WANT_STAT64
 #define __ARCH_WANT_SYS_GETHOSTNAME
-#define __ARCH_WANT_SYS_SOCKETCALL
 #define __ARCH_WANT_SYS_FADVISE64
 #define __ARCH_WANT_SYS_GETPGRP
 #define __ARCH_WANT_SYS_OLD_GETRLIMIT
index c2e11cc374ba6a28a1b33bf94f13a523bc73df90..1551fc24eb43b6bdaa14e590ae1a9ed175513c64 100644 (file)
@@ -89,7 +89,7 @@
 #define                AT91_MCI_ENDRX          (1 <<  6)       /* End of RX Buffer */
 #define                AT91_MCI_ENDTX          (1 <<  7)       /* End fo TX Buffer */
 #define                AT91_MCI_SDIOIRQA       (1 <<  8)       /* SDIO Interrupt for Slot A */
-#define                At91_MCI_SDIOIRQB       (1 <<  9)       /* SDIO Interrupt for Slot B [AT91RM9200 only] */
+#define                AT91_MCI_SDIOIRQB       (1 <<  9)       /* SDIO Interrupt for Slot B */
 #define                AT91_MCI_RXBUFF         (1 << 14)       /* RX Buffer Full */
 #define                AT91_MCI_TXBUFE         (1 << 15)       /* TX Buffer Empty */
 #define                AT91_MCI_RINDE          (1 << 16)       /* Response Index Error */
index 802891a9cd81d76089c980ae1ea02df5fa969e3f..e8fc0b1c33f4423647a60db76fac50f85b7f49d2 100644 (file)
 #define AT91_RTC       (0xfffffe00 - AT91_BASE_SYS)    /* Real-Time Clock */
 #define AT91_MC                (0xffffff00 - AT91_BASE_SYS)    /* Memory Controllers */
 
+#define AT91_USART0    AT91RM9200_BASE_US0
+#define AT91_USART1    AT91RM9200_BASE_US1
+#define AT91_USART2    AT91RM9200_BASE_US2
+#define AT91_USART3    AT91RM9200_BASE_US3
+
 #define AT91_MATRIX    0       /* not supported */
 
 /*
index 0427f8698c07a8e8f43ec675929b1fd907ebb033..c8934fe34dc512ff43b30518f8fe7ba480e86be0 100644 (file)
 #define AT91_WDT       (0xfffffd40 - AT91_BASE_SYS)
 #define AT91_GPBR      (0xfffffd50 - AT91_BASE_SYS)
 
+#define AT91_USART0    AT91SAM9260_BASE_US0
+#define AT91_USART1    AT91SAM9260_BASE_US1
+#define AT91_USART2    AT91SAM9260_BASE_US2
+#define AT91_USART3    AT91SAM9260_BASE_US3
+#define AT91_USART4    AT91SAM9260_BASE_US4
+#define AT91_USART5    AT91SAM9260_BASE_US5
+
 
 /*
  * Internal Memory.
index 9eb4595703307832b8cc2224fcab032f1a45ee08..c7c4778dac49bed468e44eab6a23a32dd468789a 100644 (file)
 #define AT91_WDT       (0xfffffd40 - AT91_BASE_SYS)
 #define AT91_GPBR      (0xfffffd50 - AT91_BASE_SYS)
 
+#define AT91_USART0    AT91SAM9261_BASE_US0
+#define AT91_USART1    AT91SAM9261_BASE_US1
+#define AT91_USART2    AT91SAM9261_BASE_US2
+
 
 /*
  * Internal Memory.
index 115c47ac7ebb0b22b75d00e1ddcfeaf1dee25a21..018a647311da97590a21677931ea21a8899301ea 100644 (file)
 #define AT91_RTT1      (0xfffffd50 - AT91_BASE_SYS)
 #define AT91_GPBR      (0xfffffd60 - AT91_BASE_SYS)
 
+#define AT91_USART0    AT91SAM9263_BASE_US0
+#define AT91_USART1    AT91SAM9263_BASE_US1
+#define AT91_USART2    AT91SAM9263_BASE_US2
+
 #define AT91_SMC       AT91_SMC0
 
 /*
index 8a9708a370c63fddc87b550d628eda108460dc49..16d2832f6c0abf04b2f8091f92d87af2af2cf2e9 100644 (file)
 #define AT91_GPBR      (0xfffffd60 - AT91_BASE_SYS)
 #define AT91_RTC       (0xfffffe00 - AT91_BASE_SYS)
 
+#define AT91_USART0    AT91SAM9RL_BASE_US0
+#define AT91_USART1    AT91SAM9RL_BASE_US1
+#define AT91_USART2    AT91SAM9RL_BASE_US2
+#define AT91_USART3    AT91SAM9RL_BASE_US3
+
 
 /*
  * Internal Memory.
index 55b07bd5316ccf446f6eb902776f53068e0222f6..dc189f01c5b3c969071057484e75b4d72df236db 100644 (file)
@@ -40,7 +40,8 @@
  /* USB Device */
 struct at91_udc_data {
        u8      vbus_pin;               /* high == host powering us */
-       u8      pullup_pin;             /* high == D+ pulled up */
+       u8      pullup_pin;             /* active == D+ pulled up */
+       u8      pullup_active_low;      /* true == pullup_pin is active low */
 };
 extern void __init at91_add_device_udc(struct at91_udc_data *data);
 
index 272a7e0dc6cf928c11a4328741a03e5302441c8e..f5636a8f6132989de20acf64b6e04fdcbbf3245d 100644 (file)
 #define __ASM_ARCH_UNCOMPRESS_H
 
 #include <asm/io.h>
-#include <asm/arch/at91_dbgu.h>
+#include <linux/atmel_serial.h>
+
+#if defined(CONFIG_AT91_EARLY_DBGU)
+#define UART_OFFSET (AT91_DBGU + AT91_BASE_SYS)
+#elif defined(CONFIG_AT91_EARLY_USART0)
+#define UART_OFFSET AT91_USART0
+#elif defined(CONFIG_AT91_EARLY_USART1)
+#define UART_OFFSET AT91_USART1
+#elif defined(CONFIG_AT91_EARLY_USART2)
+#define UART_OFFSET AT91_USART2
+#elif defined(CONFIG_AT91_EARLY_USART3)
+#define UART_OFFSET AT91_USART3
+#elif defined(CONFIG_AT91_EARLY_USART4)
+#define UART_OFFSET AT91_USART4
+#elif defined(CONFIG_AT91_EARLY_USART5)
+#define UART_OFFSET AT91_USART5
+#endif
 
 /*
  * The following code assumes the serial port has already been
  */
 static void putc(int c)
 {
-#ifdef AT91_DBGU
-       void __iomem *sys = (void __iomem *) AT91_BASE_SYS;     /* physical address */
+#ifdef UART_OFFSET
+       void __iomem *sys = (void __iomem *) UART_OFFSET;       /* physical address */
 
-       while (!(__raw_readl(sys + AT91_DBGU_SR) & AT91_DBGU_TXRDY))
+       while (!(__raw_readl(sys + ATMEL_US_CSR) & ATMEL_US_TXRDY))
                barrier();
-       __raw_writel(c, sys + AT91_DBGU_THR);
+       __raw_writel(c, sys + ATMEL_US_THR);
 #endif
 }
 
 static inline void flush(void)
 {
-#ifdef AT91_DBGU
-       void __iomem *sys = (void __iomem *) AT91_BASE_SYS;     /* physical address */
+#ifdef UART_OFFSET
+       void __iomem *sys = (void __iomem *) UART_OFFSET;       /* physical address */
 
        /* wait for transmission to complete */
-       while (!(__raw_readl(sys + AT91_DBGU_SR) & AT91_DBGU_TXEMPTY))
+       while (!(__raw_readl(sys + ATMEL_US_CSR) & ATMEL_US_TXEMPTY))
                barrier();
 #endif
 }
index d2523b326c6c2d1595dd1980fa7c4e9db09fc135..2fa3d6b8dbb8de9074b642e4593c7ee479b21fab 100644 (file)
@@ -28,4 +28,19 @@ extern unsigned int processor_id;
 #define cpu_is_ixp46x()        ((processor_id & IXP4XX_PROCESSOR_ID_MASK) == \
                          IXP465_PROCESSOR_ID_VALUE)
 
+static inline u32 ixp4xx_read_feature_bits(void)
+{
+       unsigned int val = ~*IXP4XX_EXP_CFG2;
+       val &= ~IXP4XX_FEATURE_RESERVED;
+       if (!cpu_is_ixp46x())
+               val &= ~IXP4XX_FEATURE_IXP46X_ONLY;
+
+       return val;
+}
+
+static inline void ixp4xx_write_feature_bits(u32 value)
+{
+       *IXP4XX_EXP_CFG2 = ~value;
+}
+
 #endif  /* _ASM_ARCH_CPU_H */
index a19605ad240da758f96d9acd59c6c49ed4d25dd3..b7673e171abe0c111bd9521e92d4fd45d02fe197 100644 (file)
 /* Buttons */
 
 #define DSMG600_PB_GPIO                15      /* power button */
-#define DSMG600_PB_BM          (1L << DSMG600_PB_GPIO)
-
 #define DSMG600_RB_GPIO                3       /* reset button */
 
-#define DSMG600_RB_IRQ         IRQ_IXP4XX_GPIO3
+/* Power control */
 
 #define DSMG600_PO_GPIO                2       /* power off */
 
 /* LEDs */
 
 #define DSMG600_LED_PWR_GPIO   0
-#define DSMG600_LED_PWR_BM     (1L << DSMG600_LED_PWR_GPIO)
-
 #define DSMG600_LED_WLAN_GPIO  14
-#define DSMG600_LED_WLAN_BM    (1L << DSMG600_LED_WLAN_GPIO)
index 297ceda08b61375fef91233b953c50374853f221..73e8dc36f6a4f11882dfde8aba7ecfa53cc15b7d 100644 (file)
 
 #define pcibios_assign_all_busses()    1
 
+/* Register locations and bits */
+#include "ixp4xx-regs.h"
+
 #ifndef __ASSEMBLER__
 #include <asm/arch/cpu.h>
 #endif
 
-/* Register locations and bits */
-#include "ixp4xx-regs.h"
-
 /* Platform helper functions and definitions */
 #include "platform.h"
 
index 9c5d2357aff3ac4689ae36747022f76cb2d6081a..de181ce958db86d23f4749e23ea2b0a8d4b43fb4 100644 (file)
@@ -13,6 +13,8 @@
 #ifndef __ASM_ARM_ARCH_IO_H
 #define __ASM_ARM_ARCH_IO_H
 
+#include <linux/bitops.h>
+
 #include <asm/hardware.h>
 
 #define IO_SPACE_LIMIT 0xffff0000
index 5d949d763a918810571f46f5b163cb61a740ca2a..68aca8554f5ad5556ddae23be4143563bb8e4d33 100644 (file)
  *
  */
 
-#ifndef __ASM_ARCH_HARDWARE_H__
-#error "Do not include this directly, instead #include <asm/hardware.h>"
-#endif
-
 #ifndef _ASM_ARM_IXP4XX_H_
 #define _ASM_ARM_IXP4XX_H_
 
 #define UICR1_IM14     (1 << 6)        /* Interrupt mask ep 14 */
 #define UICR1_IM15     (1 << 7)        /* Interrupt mask ep 15 */
 
-#define USIR0_IR0      (1 << 0)        /* Interrup request ep 0 */
-#define USIR0_IR1      (1 << 1)        /* Interrup request ep 1 */
-#define USIR0_IR2      (1 << 2)        /* Interrup request ep 2 */
-#define USIR0_IR3      (1 << 3)        /* Interrup request ep 3 */
-#define USIR0_IR4      (1 << 4)        /* Interrup request ep 4 */
-#define USIR0_IR5      (1 << 5)        /* Interrup request ep 5 */
-#define USIR0_IR6      (1 << 6)        /* Interrup request ep 6 */
-#define USIR0_IR7      (1 << 7)        /* Interrup request ep 7 */
-
-#define USIR1_IR8      (1 << 0)        /* Interrup request ep 8 */
-#define USIR1_IR9      (1 << 1)        /* Interrup request ep 9 */
-#define USIR1_IR10     (1 << 2)        /* Interrup request ep 10 */
-#define USIR1_IR11     (1 << 3)        /* Interrup request ep 11 */
-#define USIR1_IR12     (1 << 4)        /* Interrup request ep 12 */
-#define USIR1_IR13     (1 << 5)        /* Interrup request ep 13 */
-#define USIR1_IR14     (1 << 6)        /* Interrup request ep 14 */
-#define USIR1_IR15     (1 << 7)        /* Interrup request ep 15 */
+#define USIR0_IR0      (1 << 0)        /* Interrupt request ep 0 */
+#define USIR0_IR1      (1 << 1)        /* Interrupt request ep 1 */
+#define USIR0_IR2      (1 << 2)        /* Interrupt request ep 2 */
+#define USIR0_IR3      (1 << 3)        /* Interrupt request ep 3 */
+#define USIR0_IR4      (1 << 4)        /* Interrupt request ep 4 */
+#define USIR0_IR5      (1 << 5)        /* Interrupt request ep 5 */
+#define USIR0_IR6      (1 << 6)        /* Interrupt request ep 6 */
+#define USIR0_IR7      (1 << 7)        /* Interrupt request ep 7 */
+
+#define USIR1_IR8      (1 << 0)        /* Interrupt request ep 8 */
+#define USIR1_IR9      (1 << 1)        /* Interrupt request ep 9 */
+#define USIR1_IR10     (1 << 2)        /* Interrupt request ep 10 */
+#define USIR1_IR11     (1 << 3)        /* Interrupt request ep 11 */
+#define USIR1_IR12     (1 << 4)        /* Interrupt request ep 12 */
+#define USIR1_IR13     (1 << 5)        /* Interrupt request ep 13 */
+#define USIR1_IR14     (1 << 6)        /* Interrupt request ep 14 */
+#define USIR1_IR15     (1 << 7)        /* Interrupt request ep 15 */
 
 #define DCMD_LENGTH    0x01fff         /* length mask (max = 8K - 1) */
 
+/* "fuse" bits of IXP_EXP_CFG2 */
+#define IXP4XX_FEATURE_RCOMP           (1 << 0)
+#define IXP4XX_FEATURE_USB_DEVICE      (1 << 1)
+#define IXP4XX_FEATURE_HASH            (1 << 2)
+#define IXP4XX_FEATURE_AES             (1 << 3)
+#define IXP4XX_FEATURE_DES             (1 << 4)
+#define IXP4XX_FEATURE_HDLC            (1 << 5)
+#define IXP4XX_FEATURE_AAL             (1 << 6)
+#define IXP4XX_FEATURE_HSS             (1 << 7)
+#define IXP4XX_FEATURE_UTOPIA          (1 << 8)
+#define IXP4XX_FEATURE_NPEB_ETH0       (1 << 9)
+#define IXP4XX_FEATURE_NPEC_ETH                (1 << 10)
+#define IXP4XX_FEATURE_RESET_NPEA      (1 << 11)
+#define IXP4XX_FEATURE_RESET_NPEB      (1 << 12)
+#define IXP4XX_FEATURE_RESET_NPEC      (1 << 13)
+#define IXP4XX_FEATURE_PCI             (1 << 14)
+#define IXP4XX_FEATURE_ECC_TIMESYNC    (1 << 15)
+#define IXP4XX_FEATURE_UTOPIA_PHY_LIMIT        (3 << 16)
+#define IXP4XX_FEATURE_USB_HOST                (1 << 18)
+#define IXP4XX_FEATURE_NPEA_ETH                (1 << 19)
+#define IXP4XX_FEATURE_NPEB_ETH_1_TO_3 (1 << 20)
+#define IXP4XX_FEATURE_RSA             (1 << 21)
+#define IXP4XX_FEATURE_XSCALE_MAX_FREQ (3 << 22)
+#define IXP4XX_FEATURE_RESERVED                (0xFF << 24)
+
+#define IXP4XX_FEATURE_IXP46X_ONLY (IXP4XX_FEATURE_ECC_TIMESYNC |      \
+                                   IXP4XX_FEATURE_USB_HOST |           \
+                                   IXP4XX_FEATURE_NPEA_ETH |           \
+                                   IXP4XX_FEATURE_NPEB_ETH_1_TO_3 |    \
+                                   IXP4XX_FEATURE_RSA |                \
+                                   IXP4XX_FEATURE_XSCALE_MAX_FREQ)
+
 #endif
index 131e0a1d0df395f3d7740167e54b0b9419e5ad4d..98d937897bceba13b3489db3323b8fd750d6544b 100644 (file)
 
 /* Buttons */
 
-#define NAS100D_PB_GPIO         14
-#define NAS100D_RB_GPIO         4
+#define NAS100D_PB_GPIO         14   /* power button */
+#define NAS100D_RB_GPIO         4    /* reset button */
+
+/* Power control */
+
 #define NAS100D_PO_GPIO         12   /* power off */
 
-#define NAS100D_PB_IRQ          IRQ_IXP4XX_GPIO14
-#define NAS100D_RB_IRQ          IRQ_IXP4XX_GPIO4
+/* LEDs */
 
-/*
-#define NAS100D_PB_BM           (1L << NAS100D_PB_GPIO)
-#define NAS100D_PO_BM           (1L << NAS100D_PO_GPIO)
-#define NAS100D_RB_BM           (1L << NAS100D_RB_GPIO)
-*/
+#define NAS100D_LED_WLAN_GPIO  0
+#define NAS100D_LED_DISK_GPIO  3
+#define NAS100D_LED_PWR_GPIO   15
diff --git a/include/asm-arm/arch-ixp4xx/npe.h b/include/asm-arm/arch-ixp4xx/npe.h
new file mode 100644 (file)
index 0000000..37d0511
--- /dev/null
@@ -0,0 +1,39 @@
+#ifndef __IXP4XX_NPE_H
+#define __IXP4XX_NPE_H
+
+#include <linux/kernel.h>
+
+extern const char *npe_names[];
+
+struct npe_regs {
+       u32 exec_addr, exec_data, exec_status_cmd, exec_count;
+       u32 action_points[4];
+       u32 watchpoint_fifo, watch_count;
+       u32 profile_count;
+       u32 messaging_status, messaging_control;
+       u32 mailbox_status, /*messaging_*/ in_out_fifo;
+};
+
+struct npe {
+       struct resource *mem_res;
+       struct npe_regs __iomem *regs;
+       u32 regs_phys;
+       int id;
+       int valid;
+};
+
+
+static inline const char *npe_name(struct npe *npe)
+{
+       return npe_names[npe->id];
+}
+
+int npe_running(struct npe *npe);
+int npe_send_message(struct npe *npe, const void *msg, const char *what);
+int npe_recv_message(struct npe *npe, void *msg, const char *what);
+int npe_send_recv_message(struct npe *npe, void *msg, const char *what);
+int npe_load_firmware(struct npe *npe, const char *name, struct device *dev);
+struct npe *npe_request(int id);
+void npe_release(struct npe *npe);
+
+#endif /* __IXP4XX_NPE_H */
index 850fdc5b45da21eda6f6a3ad9d03a7a06b9d738a..714bbc65126af1c26a3303ab79c659dfd65f8bc3 100644 (file)
 
 /* Buttons */
 
-#define NSLU2_PB_GPIO          5
+#define NSLU2_PB_GPIO          5       /* power button */
 #define NSLU2_PO_GPIO          8       /* power off */
-#define NSLU2_RB_GPIO          12
-
-#define NSLU2_PB_IRQ           IRQ_IXP4XX_GPIO5
-#define NSLU2_RB_IRQ           IRQ_IXP4XX_GPIO12
-
-#define NSLU2_PB_BM            (1L << NSLU2_PB_GPIO)
-#define NSLU2_PO_BM            (1L << NSLU2_PO_GPIO)
-#define NSLU2_RB_BM            (1L << NSLU2_RB_GPIO)
+#define NSLU2_RB_GPIO          12      /* reset button */
 
 /* Buzzer */
 
 #define NSLU2_GPIO_BUZZ                4
-#define NSLU2_BZ_BM            (1L << NSLU2_GPIO_BUZZ)
 
 /* LEDs */
 
 #define NSLU2_LED_RED_GPIO     0
 #define NSLU2_LED_GRN_GPIO     1
-
-#define NSLU2_LED_RED_BM       (1L << NSLU2_LED_RED_GPIO)
-#define NSLU2_LED_GRN_BM       (1L << NSLU2_LED_GRN_GPIO)
-
 #define NSLU2_LED_DISK1_GPIO   3
 #define NSLU2_LED_DISK2_GPIO   2
-
-#define NSLU2_LED_DISK1_BM     (1L << NSLU2_LED_DISK1_GPIO)
-#define NSLU2_LED_DISK2_BM     (1L << NSLU2_LED_DISK2_GPIO)
-
-
index 2ce28e3fd325ba3898e23c26ed18ac6dad0554e9..a1f2b5404db1f95e6496676555e48629091c605a 100644 (file)
@@ -91,6 +91,27 @@ struct ixp4xx_pata_data {
 
 struct sys_timer;
 
+#define IXP4XX_ETH_NPEA                0x00
+#define IXP4XX_ETH_NPEB                0x10
+#define IXP4XX_ETH_NPEC                0x20
+
+/* Information about built-in Ethernet MAC interfaces */
+struct eth_plat_info {
+       u8 phy;         /* MII PHY ID, 0 - 31 */
+       u8 rxq;         /* configurable, currently 0 - 31 only */
+       u8 txreadyq;
+       u8 hwaddr[6];
+};
+
+/* Information about built-in HSS (synchronous serial) interfaces */
+struct hss_plat_info {
+       int (*set_clock)(int port, unsigned int clock_type);
+       int (*open)(int port, void *pdev,
+                   void (*set_carrier_cb)(void *pdev, int carrier));
+       void (*close)(int port, void *pdev);
+       u8 txreadyq;
+};
+
 /*
  * Frequency of clock used for primary clocksource
  */
diff --git a/include/asm-arm/arch-ixp4xx/qmgr.h b/include/asm-arm/arch-ixp4xx/qmgr.h
new file mode 100644 (file)
index 0000000..1e52b95
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2007 Krzysztof Halasa <khc@pm.waw.pl>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ */
+
+#ifndef IXP4XX_QMGR_H
+#define IXP4XX_QMGR_H
+
+#include <linux/io.h>
+#include <linux/kernel.h>
+
+#define HALF_QUEUES    32
+#define QUEUES         64      /* only 32 lower queues currently supported */
+#define MAX_QUEUE_LENGTH 4     /* in dwords */
+
+#define QUEUE_STAT1_EMPTY              1 /* queue status bits */
+#define QUEUE_STAT1_NEARLY_EMPTY       2
+#define QUEUE_STAT1_NEARLY_FULL                4
+#define QUEUE_STAT1_FULL               8
+#define QUEUE_STAT2_UNDERFLOW          1
+#define QUEUE_STAT2_OVERFLOW           2
+
+#define QUEUE_WATERMARK_0_ENTRIES      0
+#define QUEUE_WATERMARK_1_ENTRY                1
+#define QUEUE_WATERMARK_2_ENTRIES      2
+#define QUEUE_WATERMARK_4_ENTRIES      3
+#define QUEUE_WATERMARK_8_ENTRIES      4
+#define QUEUE_WATERMARK_16_ENTRIES     5
+#define QUEUE_WATERMARK_32_ENTRIES     6
+#define QUEUE_WATERMARK_64_ENTRIES     7
+
+/* queue interrupt request conditions */
+#define QUEUE_IRQ_SRC_EMPTY            0
+#define QUEUE_IRQ_SRC_NEARLY_EMPTY     1
+#define QUEUE_IRQ_SRC_NEARLY_FULL      2
+#define QUEUE_IRQ_SRC_FULL             3
+#define QUEUE_IRQ_SRC_NOT_EMPTY                4
+#define QUEUE_IRQ_SRC_NOT_NEARLY_EMPTY 5
+#define QUEUE_IRQ_SRC_NOT_NEARLY_FULL  6
+#define QUEUE_IRQ_SRC_NOT_FULL         7
+
+struct qmgr_regs {
+       u32 acc[QUEUES][MAX_QUEUE_LENGTH]; /* 0x000 - 0x3FF */
+       u32 stat1[4];           /* 0x400 - 0x40F */
+       u32 stat2[2];           /* 0x410 - 0x417 */
+       u32 statne_h;           /* 0x418 - queue nearly empty */
+       u32 statf_h;            /* 0x41C - queue full */
+       u32 irqsrc[4];          /* 0x420 - 0x42F IRC source */
+       u32 irqen[2];           /* 0x430 - 0x437 IRQ enabled */
+       u32 irqstat[2];         /* 0x438 - 0x43F - IRQ access only */
+       u32 reserved[1776];
+       u32 sram[2048];         /* 0x2000 - 0x3FFF - config and buffer */
+};
+
+void qmgr_set_irq(unsigned int queue, int src,
+                 void (*handler)(void *pdev), void *pdev);
+void qmgr_enable_irq(unsigned int queue);
+void qmgr_disable_irq(unsigned int queue);
+
+/* request_ and release_queue() must be called from non-IRQ context */
+int qmgr_request_queue(unsigned int queue, unsigned int len /* dwords */,
+                      unsigned int nearly_empty_watermark,
+                      unsigned int nearly_full_watermark);
+void qmgr_release_queue(unsigned int queue);
+
+
+static inline void qmgr_put_entry(unsigned int queue, u32 val)
+{
+       extern struct qmgr_regs __iomem *qmgr_regs;
+       __raw_writel(val, &qmgr_regs->acc[queue][0]);
+}
+
+static inline u32 qmgr_get_entry(unsigned int queue)
+{
+       extern struct qmgr_regs __iomem *qmgr_regs;
+       return __raw_readl(&qmgr_regs->acc[queue][0]);
+}
+
+static inline int qmgr_get_stat1(unsigned int queue)
+{
+       extern struct qmgr_regs __iomem *qmgr_regs;
+       return (__raw_readl(&qmgr_regs->stat1[queue >> 3])
+               >> ((queue & 7) << 2)) & 0xF;
+}
+
+static inline int qmgr_get_stat2(unsigned int queue)
+{
+       extern struct qmgr_regs __iomem *qmgr_regs;
+       return (__raw_readl(&qmgr_regs->stat2[queue >> 4])
+               >> ((queue & 0xF) << 1)) & 0x3;
+}
+
+static inline int qmgr_stat_empty(unsigned int queue)
+{
+       return !!(qmgr_get_stat1(queue) & QUEUE_STAT1_EMPTY);
+}
+
+static inline int qmgr_stat_nearly_empty(unsigned int queue)
+{
+       return !!(qmgr_get_stat1(queue) & QUEUE_STAT1_NEARLY_EMPTY);
+}
+
+static inline int qmgr_stat_nearly_full(unsigned int queue)
+{
+       return !!(qmgr_get_stat1(queue) & QUEUE_STAT1_NEARLY_FULL);
+}
+
+static inline int qmgr_stat_full(unsigned int queue)
+{
+       return !!(qmgr_get_stat1(queue) & QUEUE_STAT1_FULL);
+}
+
+static inline int qmgr_stat_underflow(unsigned int queue)
+{
+       return !!(qmgr_get_stat2(queue) & QUEUE_STAT2_UNDERFLOW);
+}
+
+static inline int qmgr_stat_overflow(unsigned int queue)
+{
+       return !!(qmgr_get_stat2(queue) & QUEUE_STAT2_OVERFLOW);
+}
+
+#endif
index f7a35b78823ff0227c44c6e4d9cc4d6052408ddd..34ef48fe327eff50b05329a9a053a61a758f724b 100644 (file)
@@ -13,7 +13,7 @@
 #ifndef _ARCH_UNCOMPRESS_H_
 #define _ARCH_UNCOMPRESS_H_
 
-#include <asm/hardware.h>
+#include "ixp4xx-regs.h"
 #include <asm/mach-types.h>
 #include <linux/serial_reg.h>
 
index 6662cb02bafc81cfda77a8d206188b98dbbf06ab..ccee3b0700b3381a6609afcf23ac8692a91d3b95 100644 (file)
@@ -31,7 +31,6 @@
 #include <asm/arch/hardware.h>
 #include <asm/irq.h>
 
-#include <sound/driver.h>
 #include <sound/core.h>
 
 /* master codec clock source */
index fcaf44c14714c8f36f2c9d75eec216bb01027f41..faa0ed23d4bad8fefedb69627aae17f085ea16e3 100644 (file)
@@ -40,7 +40,6 @@
 #ifndef __OMAP_ALSA_H
 #define __OMAP_ALSA_H
 
-#include <sound/driver.h>
 #include <asm/arch/dma.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
index 17eccd72013650e2bf93ee0e904add87114bd052..52bbe3bc25e1e5f283cc2d2d56603e06a127f4b1 100644 (file)
@@ -1,7 +1,6 @@
 #ifndef __ASM_ARCH_AUDIO_H__
 #define __ASM_ARCH_AUDIO_H__
 
-#include <sound/driver.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 
index 9dbc2dc794f777dfd18b4ad014dc5501b77075ed..bdbf5f9ffdd5df5694deb4ffd664f9e0d5ac9d29 100644 (file)
 #include <asm/irq.h>
 #include <asm/hardware.h>
 
-static inline int gpio_request(unsigned gpio, const char *label)
-{
-       return 0;
-}
+#include <asm-generic/gpio.h>
 
-static inline void gpio_free(unsigned gpio)
-{
-       return;
-}
 
-extern int gpio_direction_input(unsigned gpio);
-extern int gpio_direction_output(unsigned gpio, int value);
+/* NOTE: some PXAs have fewer on-chip GPIOs (like PXA255, with 85).
+ * Those cases currently cause holes in the GPIO number space.
+ */
+#define NR_BUILTIN_GPIO 128
 
-static inline int __gpio_get_value(unsigned gpio)
+static inline int gpio_get_value(unsigned gpio)
 {
-       return GPLR(gpio) & GPIO_bit(gpio);
+       if (__builtin_constant_p(gpio) && (gpio < NR_BUILTIN_GPIO))
+               return GPLR(gpio) & GPIO_bit(gpio);
+       else
+               return __gpio_get_value(gpio);
 }
 
-#define gpio_get_value(gpio)                   \
-       (__builtin_constant_p(gpio) ?           \
-        __gpio_get_value(gpio) :               \
-        pxa_gpio_get_value(gpio))
-
-static inline void __gpio_set_value(unsigned gpio, int value)
+static inline void gpio_set_value(unsigned gpio, int value)
 {
-       if (value)
-               GPSR(gpio) = GPIO_bit(gpio);
-       else
-               GPCR(gpio) = GPIO_bit(gpio);
+       if (__builtin_constant_p(gpio) && (gpio < NR_BUILTIN_GPIO)) {
+               if (value)
+                       GPSR(gpio) = GPIO_bit(gpio);
+               else
+                       GPCR(gpio) = GPIO_bit(gpio);
+       } else {
+               __gpio_set_value(gpio, value);
+       }
 }
 
-#define gpio_set_value(gpio,value)             \
-       (__builtin_constant_p(gpio) ?           \
-        __gpio_set_value(gpio, value) :        \
-        pxa_gpio_set_value(gpio, value))
-
-#include <asm-generic/gpio.h>                  /* cansleep wrappers */
+#define gpio_cansleep __gpio_cansleep
 
 #define gpio_to_irq(gpio)      IRQ_GPIO(gpio)
 #define irq_to_gpio(irq)       IRQ_TO_GPIO(irq)
index 442494d71f12d38ff4dfefb8b5e9246447b73201..ac175b4d10cbfa859880be062163be2526eaab4c 100644 (file)
 
 #define USIR0          __REG(0x40600058)  /* UDC Status Interrupt Register 0 */
 
-#define USIR0_IR0      (1 << 0)        /* Interrup request ep 0 */
-#define USIR0_IR1      (1 << 1)        /* Interrup request ep 1 */
-#define USIR0_IR2      (1 << 2)        /* Interrup request ep 2 */
-#define USIR0_IR3      (1 << 3)        /* Interrup request ep 3 */
-#define USIR0_IR4      (1 << 4)        /* Interrup request ep 4 */
-#define USIR0_IR5      (1 << 5)        /* Interrup request ep 5 */
-#define USIR0_IR6      (1 << 6)        /* Interrup request ep 6 */
-#define USIR0_IR7      (1 << 7)        /* Interrup request ep 7 */
+#define USIR0_IR0      (1 << 0)        /* Interrupt request ep 0 */
+#define USIR0_IR1      (1 << 1)        /* Interrupt request ep 1 */
+#define USIR0_IR2      (1 << 2)        /* Interrupt request ep 2 */
+#define USIR0_IR3      (1 << 3)        /* Interrupt request ep 3 */
+#define USIR0_IR4      (1 << 4)        /* Interrupt request ep 4 */
+#define USIR0_IR5      (1 << 5)        /* Interrupt request ep 5 */
+#define USIR0_IR6      (1 << 6)        /* Interrupt request ep 6 */
+#define USIR0_IR7      (1 << 7)        /* Interrupt request ep 7 */
 
 #define USIR1          __REG(0x4060005C)  /* UDC Status Interrupt Register 1 */
 
-#define USIR1_IR8      (1 << 0)        /* Interrup request ep 8 */
-#define USIR1_IR9      (1 << 1)        /* Interrup request ep 9 */
-#define USIR1_IR10     (1 << 2)        /* Interrup request ep 10 */
-#define USIR1_IR11     (1 << 3)        /* Interrup request ep 11 */
-#define USIR1_IR12     (1 << 4)        /* Interrup request ep 12 */
-#define USIR1_IR13     (1 << 5)        /* Interrup request ep 13 */
-#define USIR1_IR14     (1 << 6)        /* Interrup request ep 14 */
-#define USIR1_IR15     (1 << 7)        /* Interrup request ep 15 */
+#define USIR1_IR8      (1 << 0)        /* Interrupt request ep 8 */
+#define USIR1_IR9      (1 << 1)        /* Interrupt request ep 9 */
+#define USIR1_IR10     (1 << 2)        /* Interrupt request ep 10 */
+#define USIR1_IR11     (1 << 3)        /* Interrupt request ep 11 */
+#define USIR1_IR12     (1 << 4)        /* Interrupt request ep 12 */
+#define USIR1_IR13     (1 << 5)        /* Interrupt request ep 13 */
+#define USIR1_IR14     (1 << 6)        /* Interrupt request ep 14 */
+#define USIR1_IR15     (1 << 7)        /* Interrupt request ep 15 */
 
 #elif defined(CONFIG_PXA27x)
 
 #define ICSR0          __REG(0x40800014)  /* ICP Status Register 0 */
 #define ICSR1          __REG(0x40800018)  /* ICP Status Register 1 */
 
-#define ICCR0_AME      (1 << 7)        /* Adress match enable */
+#define ICCR0_AME      (1 << 7)        /* Address match enable */
 #define ICCR0_TIE      (1 << 6)        /* Transmit FIFO interrupt enable */
 #define ICCR0_RIE      (1 << 5)        /* Recieve FIFO interrupt enable */
 #define ICCR0_RXE      (1 << 4)        /* Receive enable */
  * General Purpose I/O
  */
 
+#define GPIO0_BASE     ((void __iomem *)io_p2v(0x40E00000))
+#define GPIO1_BASE     ((void __iomem *)io_p2v(0x40E00004))
+#define GPIO2_BASE     ((void __iomem *)io_p2v(0x40E00008))
+#define GPIO3_BASE     ((void __iomem *)io_p2v(0x40E00100))
+
+#define GPLR_OFFSET    0x00
+#define GPDR_OFFSET    0x0C
+#define GPSR_OFFSET    0x18
+#define GPCR_OFFSET    0x24
+#define GRER_OFFSET    0x30
+#define GFER_OFFSET    0x3C
+#define GEDR_OFFSET    0x48
+
 #define GPLR0          __REG(0x40E00000)  /* GPIO Pin-Level Register GPIO<31:0> */
 #define GPLR1          __REG(0x40E00004)  /* GPIO Pin-Level Register GPIO<63:32> */
 #define GPLR2          __REG(0x40E00008)  /* GPIO Pin-Level Register GPIO<80:64> */
index 66d54119757cb665a9a3af08b5afb1c8028d4d73..8e1b3ead827fc017fa35c7e09ad3e2681845c544 100644 (file)
 
 #ifndef __ASM_ARCH_PXA3XX_REGS_H
 #define __ASM_ARCH_PXA3XX_REGS_H
+/*
+ * Service Power Management Unit (MPMU)
+ */
+#define PMCR           __REG(0x40F50000)       /* Power Manager Control Register */
+#define PSR            __REG(0x40F50004)       /* Power Manager S2 Status Register */
+#define PSPR           __REG(0x40F50008)       /* Power Manager Scratch Pad Register */
+#define PCFR           __REG(0x40F5000C)       /* Power Manager General Configuration Register */
+#define PWER           __REG(0x40F50010)       /* Power Manager Wake-up Enable Register */
+#define PWSR           __REG(0x40F50014)       /* Power Manager Wake-up Status Register */
+#define PECR           __REG(0x40F50018)       /* Power Manager EXT_WAKEUP[1:0] Control Register */
+#define DCDCSR         __REG(0x40F50080)       /* DC-DC Controller Status Register */
+#define PVCR           __REG(0x40F50100)       /* Power Manager Voltage Change Control Register */
+#define PCMD(x)                __REG(0x40F50110 + ((x) << 2))
 
 /*
  * Slave Power Managment Unit
diff --git a/include/asm-arm/arch-realview/board-eb.h b/include/asm-arm/arch-realview/board-eb.h
new file mode 100644 (file)
index 0000000..3e437b7
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+ * include/asm-arm/arch-realview/board-eb.h
+ *
+ * Copyright (C) 2007 ARM Limited
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+
+#ifndef __ASM_ARCH_BOARD_EB_H
+#define __ASM_ARCH_BOARD_EB_H
+
+#include <asm/arch/platform.h>
+
+/*
+ * RealView EB + ARM11MPCore peripheral addresses
+ */
+#ifdef CONFIG_REALVIEW_EB_ARM11MP_REVB
+#define REALVIEW_EB11MP_SCU_BASE       0x10100000      /* SCU registers */
+#define REALVIEW_EB11MP_GIC_CPU_BASE   0x10100100      /* Generic interrupt controller CPU interface */
+#define REALVIEW_EB11MP_TWD_BASE       0x10100700
+#define REALVIEW_EB11MP_TWD_SIZE       0x00000100
+#define REALVIEW_EB11MP_GIC_DIST_BASE  0x10101000      /* Generic interrupt controller distributor */
+#define REALVIEW_EB11MP_L220_BASE      0x10102000      /* L220 registers */
+#define REALVIEW_EB11MP_SYS_PLD_CTRL1  0xD8            /* Register offset for MPCore sysctl */
+#else
+#define REALVIEW_EB11MP_SCU_BASE       0x1F000000      /* SCU registers */
+#define REALVIEW_EB11MP_GIC_CPU_BASE   0x1F000100      /* Generic interrupt controller CPU interface */
+#define REALVIEW_EB11MP_TWD_BASE       0x1F000700
+#define REALVIEW_EB11MP_TWD_SIZE       0x00000100
+#define REALVIEW_EB11MP_GIC_DIST_BASE  0x1F001000      /* Generic interrupt controller distributor */
+#define REALVIEW_EB11MP_L220_BASE      0x1F002000      /* L220 registers */
+#define REALVIEW_EB11MP_SYS_PLD_CTRL1  0x74            /* Register offset for MPCore sysctl */
+#endif
+
+#define IRQ_EB_GIC_START       32
+
+/*
+ * RealView EB interrupt sources
+ */
+#define IRQ_EB_WDOG            (IRQ_EB_GIC_START + 0)          /* Watchdog timer */
+#define IRQ_EB_SOFT            (IRQ_EB_GIC_START + 1)          /* Software interrupt */
+#define IRQ_EB_COMMRx          (IRQ_EB_GIC_START + 2)          /* Debug Comm Rx interrupt */
+#define IRQ_EB_COMMTx          (IRQ_EB_GIC_START + 3)          /* Debug Comm Tx interrupt */
+#define IRQ_EB_TIMER0_1                (IRQ_EB_GIC_START + 4)          /* Timer 0 and 1 */
+#define IRQ_EB_TIMER2_3                (IRQ_EB_GIC_START + 5)          /* Timer 2 and 3 */
+#define IRQ_EB_GPIO0           (IRQ_EB_GIC_START + 6)          /* GPIO 0 */
+#define IRQ_EB_GPIO1           (IRQ_EB_GIC_START + 7)          /* GPIO 1 */
+#define IRQ_EB_GPIO2           (IRQ_EB_GIC_START + 8)          /* GPIO 2 */
+                                                               /* 9 reserved */
+#define IRQ_EB_RTC             (IRQ_EB_GIC_START + 10)         /* Real Time Clock */
+#define IRQ_EB_SSP             (IRQ_EB_GIC_START + 11)         /* Synchronous Serial Port */
+#define IRQ_EB_UART0           (IRQ_EB_GIC_START + 12)         /* UART 0 on development chip */
+#define IRQ_EB_UART1           (IRQ_EB_GIC_START + 13)         /* UART 1 on development chip */
+#define IRQ_EB_UART2           (IRQ_EB_GIC_START + 14)         /* UART 2 on development chip */
+#define IRQ_EB_UART3           (IRQ_EB_GIC_START + 15)         /* UART 3 on development chip */
+#define IRQ_EB_SCI             (IRQ_EB_GIC_START + 16)         /* Smart Card Interface */
+#define IRQ_EB_MMCI0A          (IRQ_EB_GIC_START + 17)         /* Multimedia Card 0A */
+#define IRQ_EB_MMCI0B          (IRQ_EB_GIC_START + 18)         /* Multimedia Card 0B */
+#define IRQ_EB_AACI            (IRQ_EB_GIC_START + 19)         /* Audio Codec */
+#define IRQ_EB_KMI0            (IRQ_EB_GIC_START + 20)         /* Keyboard/Mouse port 0 */
+#define IRQ_EB_KMI1            (IRQ_EB_GIC_START + 21)         /* Keyboard/Mouse port 1 */
+#define IRQ_EB_CHARLCD         (IRQ_EB_GIC_START + 22)         /* Character LCD */
+#define IRQ_EB_CLCD            (IRQ_EB_GIC_START + 23)         /* CLCD controller */
+#define IRQ_EB_DMA             (IRQ_EB_GIC_START + 24)         /* DMA controller */
+#define IRQ_EB_PWRFAIL         (IRQ_EB_GIC_START + 25)         /* Power failure */
+#define IRQ_EB_PISMO           (IRQ_EB_GIC_START + 26)         /* PISMO interface */
+#define IRQ_EB_DoC             (IRQ_EB_GIC_START + 27)         /* Disk on Chip memory controller */
+#define IRQ_EB_ETH             (IRQ_EB_GIC_START + 28)         /* Ethernet controller */
+#define IRQ_EB_USB             (IRQ_EB_GIC_START + 29)         /* USB controller */
+#define IRQ_EB_TSPEN           (IRQ_EB_GIC_START + 30)         /* Touchscreen pen */
+#define IRQ_EB_TSKPAD          (IRQ_EB_GIC_START + 31)         /* Touchscreen keypad */
+
+/*
+ * RealView EB + ARM11MPCore interrupt sources (primary GIC on the core tile)
+ */
+#define IRQ_EB11MP_AACI                (IRQ_EB_GIC_START + 0)
+#define IRQ_EB11MP_TIMER0_1    (IRQ_EB_GIC_START + 1)
+#define IRQ_EB11MP_TIMER2_3    (IRQ_EB_GIC_START + 2)
+#define IRQ_EB11MP_USB         (IRQ_EB_GIC_START + 3)
+#define IRQ_EB11MP_UART0       (IRQ_EB_GIC_START + 4)
+#define IRQ_EB11MP_UART1       (IRQ_EB_GIC_START + 5)
+#define IRQ_EB11MP_RTC         (IRQ_EB_GIC_START + 6)
+#define IRQ_EB11MP_KMI0                (IRQ_EB_GIC_START + 7)
+#define IRQ_EB11MP_KMI1                (IRQ_EB_GIC_START + 8)
+#define IRQ_EB11MP_ETH         (IRQ_EB_GIC_START + 9)
+#define IRQ_EB11MP_EB_IRQ1     (IRQ_EB_GIC_START + 10)         /* main GIC */
+#define IRQ_EB11MP_EB_IRQ2     (IRQ_EB_GIC_START + 11)         /* tile GIC */
+#define IRQ_EB11MP_EB_FIQ1     (IRQ_EB_GIC_START + 12)         /* main GIC */
+#define IRQ_EB11MP_EB_FIQ2     (IRQ_EB_GIC_START + 13)         /* tile GIC */
+#define IRQ_EB11MP_MMCI0A      (IRQ_EB_GIC_START + 14)
+#define IRQ_EB11MP_MMCI0B      (IRQ_EB_GIC_START + 15)
+
+#define IRQ_EB11MP_PMU_CPU0    (IRQ_EB_GIC_START + 17)
+#define IRQ_EB11MP_PMU_CPU1    (IRQ_EB_GIC_START + 18)
+#define IRQ_EB11MP_PMU_CPU2    (IRQ_EB_GIC_START + 19)
+#define IRQ_EB11MP_PMU_CPU3    (IRQ_EB_GIC_START + 20)
+#define IRQ_EB11MP_PMU_SCU0    (IRQ_EB_GIC_START + 21)
+#define IRQ_EB11MP_PMU_SCU1    (IRQ_EB_GIC_START + 22)
+#define IRQ_EB11MP_PMU_SCU2    (IRQ_EB_GIC_START + 23)
+#define IRQ_EB11MP_PMU_SCU3    (IRQ_EB_GIC_START + 24)
+#define IRQ_EB11MP_PMU_SCU4    (IRQ_EB_GIC_START + 25)
+#define IRQ_EB11MP_PMU_SCU5    (IRQ_EB_GIC_START + 26)
+#define IRQ_EB11MP_PMU_SCU6    (IRQ_EB_GIC_START + 27)
+#define IRQ_EB11MP_PMU_SCU7    (IRQ_EB_GIC_START + 28)
+
+#define IRQ_EB11MP_L220_EVENT  (IRQ_EB_GIC_START + 29)
+#define IRQ_EB11MP_L220_SLAVE  (IRQ_EB_GIC_START + 30)
+#define IRQ_EB11MP_L220_DECODE (IRQ_EB_GIC_START + 31)
+
+#define IRQ_EB11MP_UART2       -1
+#define IRQ_EB11MP_UART3       -1
+#define IRQ_EB11MP_CLCD                -1
+#define IRQ_EB11MP_DMA         -1
+#define IRQ_EB11MP_WDOG                -1
+#define IRQ_EB11MP_GPIO0       -1
+#define IRQ_EB11MP_GPIO1       -1
+#define IRQ_EB11MP_GPIO2       -1
+#define IRQ_EB11MP_SCI         -1
+#define IRQ_EB11MP_SSP         -1
+
+#define NR_GIC_EB11MP          2
+
+/*
+ * Only define NR_IRQS if less than NR_IRQS_EB
+ */
+#define NR_IRQS_EB             (IRQ_EB_GIC_START + 96)
+
+#if defined(CONFIG_MACH_REALVIEW_EB) \
+       && (!defined(NR_IRQS) || (NR_IRQS < NR_IRQS_EB))
+#undef NR_IRQS
+#define NR_IRQS                        NR_IRQS_EB
+#endif
+
+#if defined(CONFIG_REALVIEW_EB_ARM11MP) \
+       && (!defined(MAX_GIC_NR) || (MAX_GIC_NR < NR_GIC_EB11MP))
+#undef MAX_GIC_NR
+#define MAX_GIC_NR             NR_GIC_EB11MP
+#endif
+
+/*
+ * Core tile identification (REALVIEW_SYS_PROCID)
+ */
+#define REALVIEW_EB_PROC_MASK          0xFF000000
+#define REALVIEW_EB_PROC_ARM7TDMI      0x00000000
+#define REALVIEW_EB_PROC_ARM9          0x02000000
+#define REALVIEW_EB_PROC_ARM11         0x04000000
+#define REALVIEW_EB_PROC_ARM11MP       0x06000000
+
+#define check_eb_proc(proc_type)                                               \
+       ((readl(__io_address(REALVIEW_SYS_PROCID)) & REALVIEW_EB_PROC_MASK)     \
+        == proc_type)
+
+#ifdef CONFIG_REALVIEW_EB_ARM11MP
+#define core_tile_eb11mp()     check_eb_proc(REALVIEW_EB_PROC_ARM11MP)
+#else
+#define core_tile_eb11mp()     0
+#endif
+
+#endif /* __ASM_ARCH_BOARD_EB_H */
index 3b4e2076603a5e23eb97f68f20c307ffd2d7384e..cd26306d8e57f8d2ecff1361ece23315485473d8 100644 (file)
@@ -14,7 +14,8 @@
                .endm
 
                .macro  get_irqnr_preamble, base, tmp
-               ldr     \base, =IO_ADDRESS(REALVIEW_GIC_CPU_BASE)
+               ldr     \base, =gic_cpu_base_addr
+               ldr     \base, [\base]
                .endm
 
                .macro  arch_ret_to_user, tmp1, tmp2
index aa78fe087ab2a39cf9ed841aac5e97f42e318ab1..bad8d7ce9bfe480e30b69c15dbfc75dfaf489cd0 100644 (file)
@@ -23,7 +23,6 @@
 #define __ASM_ARCH_HARDWARE_H
 
 #include <asm/sizes.h>
-#include <asm/arch/platform.h>
 
 /* macro to get at IO space when running virtually */
 #define IO_ADDRESS(x)          ((((x) & 0x0effffff) | (((x) >> 4) & 0x0f000000)) + 0xf0000000)
index 5a5db56f86b8cd9a712dc31fc8b630c4cf075e4f..ad0c911002fc29ddcfd0449c14cfa38ab9a49e36 100644 (file)
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
-#include <asm/arch/platform.h>
+#ifndef __ASM_ARCH_IRQS_H
+#define __ASM_ARCH_IRQS_H
 
-#define IRQ_LOCALTIMER                 29
-#define IRQ_LOCALWDOG                  30
+#include <asm/arch/board-eb.h>
 
-/* 
- *  IRQ interrupts definitions are the same the INT definitions
- *  held within platform.h
- */
-#define IRQ_GIC_START          32
-#define IRQ_WDOGINT            (IRQ_GIC_START + INT_WDOGINT)
-#define IRQ_SOFTINT            (IRQ_GIC_START + INT_SOFTINT)
-#define IRQ_COMMRx             (IRQ_GIC_START + INT_COMMRx)
-#define IRQ_COMMTx             (IRQ_GIC_START + INT_COMMTx)
-#define IRQ_TIMERINT0_1                (IRQ_GIC_START + INT_TIMERINT0_1)
-#define IRQ_TIMERINT2_3                (IRQ_GIC_START + INT_TIMERINT2_3)
-#define IRQ_GPIOINT0           (IRQ_GIC_START + INT_GPIOINT0)
-#define IRQ_GPIOINT1           (IRQ_GIC_START + INT_GPIOINT1)
-#define IRQ_GPIOINT2           (IRQ_GIC_START + INT_GPIOINT2)
-#define IRQ_GPIOINT3           (IRQ_GIC_START + INT_GPIOINT3)
-#define IRQ_RTCINT             (IRQ_GIC_START + INT_RTCINT)
-#define IRQ_SSPINT             (IRQ_GIC_START + INT_SSPINT)
-#define IRQ_UARTINT0           (IRQ_GIC_START + INT_UARTINT0)
-#define IRQ_UARTINT1           (IRQ_GIC_START + INT_UARTINT1)
-#define IRQ_UARTINT2           (IRQ_GIC_START + INT_UARTINT2)
-#define IRQ_UART3              (IRQ_GIC_START + INT_UARTINT3)
-#define IRQ_SCIINT             (IRQ_GIC_START + INT_SCIINT)
-#define IRQ_CLCDINT            (IRQ_GIC_START + INT_CLCDINT)
-#define IRQ_DMAINT             (IRQ_GIC_START + INT_DMAINT)
-#define IRQ_PWRFAILINT                 (IRQ_GIC_START + INT_PWRFAILINT)
-#define IRQ_MBXINT             (IRQ_GIC_START + INT_MBXINT)
-#define IRQ_GNDINT             (IRQ_GIC_START + INT_GNDINT)
-#define IRQ_MMCI0B             (IRQ_GIC_START + INT_MMCI0B)
-#define IRQ_MMCI1B             (IRQ_GIC_START + INT_MMCI1B)
-#define IRQ_KMI0               (IRQ_GIC_START + INT_KMI0)
-#define IRQ_KMI1               (IRQ_GIC_START + INT_KMI1)
-#define IRQ_SCI3               (IRQ_GIC_START + INT_SCI3)
-#define IRQ_CLCD               (IRQ_GIC_START + INT_CLCD)
-#define IRQ_TOUCH              (IRQ_GIC_START + INT_TOUCH)
-#define IRQ_KEYPAD             (IRQ_GIC_START + INT_KEYPAD)
-#define IRQ_DoC                        (IRQ_GIC_START + INT_DoC)
-#define IRQ_MMCI0A             (IRQ_GIC_START + INT_MMCI0A)
-#define IRQ_MMCI1A             (IRQ_GIC_START + INT_MMCI1A)
-#define IRQ_AACI               (IRQ_GIC_START + INT_AACI)
-#define IRQ_ETH                        (IRQ_GIC_START + INT_ETH)
-#define IRQ_USB                        (IRQ_GIC_START + INT_USB)
-#define IRQ_PMU_CPU0           (IRQ_GIC_START + INT_PMU_CPU0)
-#define IRQ_PMU_CPU1           (IRQ_GIC_START + INT_PMU_CPU1)
-#define IRQ_PMU_CPU2           (IRQ_GIC_START + INT_PMU_CPU2)
-#define IRQ_PMU_CPU3           (IRQ_GIC_START + INT_PMU_CPU3)
-#define IRQ_PMU_SCU0           (IRQ_GIC_START + INT_PMU_SCU0)
-#define IRQ_PMU_SCU1           (IRQ_GIC_START + INT_PMU_SCU1)
-#define IRQ_PMU_SCU2           (IRQ_GIC_START + INT_PMU_SCU2)
-#define IRQ_PMU_SCU3           (IRQ_GIC_START + INT_PMU_SCU3)
-#define IRQ_PMU_SCU4           (IRQ_GIC_START + INT_PMU_SCU4)
-#define IRQ_PMU_SCU5           (IRQ_GIC_START + INT_PMU_SCU5)
-#define IRQ_PMU_SCU6           (IRQ_GIC_START + INT_PMU_SCU6)
-#define IRQ_PMU_SCU7           (IRQ_GIC_START + INT_PMU_SCU7)
+#define IRQ_LOCALTIMER         29
+#define IRQ_LOCALWDOG          30
 
-#define IRQ_EB_IRQ1            (IRQ_GIC_START + INT_EB_IRQ1)
-#define IRQ_EB_IRQ2            (IRQ_GIC_START + INT_EB_IRQ2)
+#define IRQ_GIC_START          32
 
-#define IRQMASK_WDOGINT                INTMASK_WDOGINT
-#define IRQMASK_SOFTINT                INTMASK_SOFTINT
-#define IRQMASK_COMMRx                 INTMASK_COMMRx
-#define IRQMASK_COMMTx                 INTMASK_COMMTx
-#define IRQMASK_TIMERINT0_1    INTMASK_TIMERINT0_1
-#define IRQMASK_TIMERINT2_3    INTMASK_TIMERINT2_3
-#define IRQMASK_GPIOINT0       INTMASK_GPIOINT0
-#define IRQMASK_GPIOINT1       INTMASK_GPIOINT1
-#define IRQMASK_GPIOINT2       INTMASK_GPIOINT2
-#define IRQMASK_GPIOINT3       INTMASK_GPIOINT3
-#define IRQMASK_RTCINT                 INTMASK_RTCINT
-#define IRQMASK_SSPINT                 INTMASK_SSPINT
-#define IRQMASK_UARTINT0       INTMASK_UARTINT0
-#define IRQMASK_UARTINT1       INTMASK_UARTINT1
-#define IRQMASK_UARTINT2       INTMASK_UARTINT2
-#define IRQMASK_SCIINT                 INTMASK_SCIINT
-#define IRQMASK_CLCDINT                INTMASK_CLCDINT
-#define IRQMASK_DMAINT                 INTMASK_DMAINT
-#define IRQMASK_PWRFAILINT     INTMASK_PWRFAILINT
-#define IRQMASK_MBXINT                 INTMASK_MBXINT
-#define IRQMASK_GNDINT                 INTMASK_GNDINT
-#define IRQMASK_MMCI0B         INTMASK_MMCI0B
-#define IRQMASK_MMCI1B         INTMASK_MMCI1B
-#define IRQMASK_KMI0           INTMASK_KMI0
-#define IRQMASK_KMI1           INTMASK_KMI1
-#define IRQMASK_SCI3           INTMASK_SCI3
-#define IRQMASK_UART3          INTMASK_UART3
-#define IRQMASK_CLCD           INTMASK_CLCD
-#define IRQMASK_TOUCH          INTMASK_TOUCH
-#define IRQMASK_KEYPAD         INTMASK_KEYPAD
-#define IRQMASK_DoC            INTMASK_DoC
-#define IRQMASK_MMCI0A         INTMASK_MMCI0A
-#define IRQMASK_MMCI1A         INTMASK_MMCI1A
-#define IRQMASK_AACI           INTMASK_AACI
-#define IRQMASK_ETH            INTMASK_ETH
-#define IRQMASK_USB            INTMASK_USB
+#ifndef NR_IRQS
+#error "NR_IRQS not defined by the board-specific files"
+#endif
 
-#define NR_IRQS                        (IRQ_GIC_START + 96)
+#endif
index 6e0eab95a3a2ed3b8de1a0ae9044e5bc78c193c9..4fd351b5e4a2172a325e0edb45be7de43e68c0cb 100644 (file)
@@ -18,8 +18,8 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
-#ifndef __address_h
-#define __address_h                     1
+#ifndef __ASM_ARCH_PLATFORM_H
+#define __ASM_ARCH_PLATFORM_H
 
 /*
  * Memory definitions
 #define REALVIEW_SYS_24MHz_OFFSET            0x5C
 #define REALVIEW_SYS_MISC_OFFSET             0x60
 #define REALVIEW_SYS_IOSEL_OFFSET            0x70
-#define REALVIEW_SYS_TEST_OSC0_OFFSET        0x80
-#define REALVIEW_SYS_TEST_OSC1_OFFSET        0x84
-#define REALVIEW_SYS_TEST_OSC2_OFFSET        0x88
-#define REALVIEW_SYS_TEST_OSC3_OFFSET        0x8C
-#define REALVIEW_SYS_TEST_OSC4_OFFSET        0x90
+#define REALVIEW_SYS_PROCID_OFFSET           0x84
+#define REALVIEW_SYS_TEST_OSC0_OFFSET        0xC0
+#define REALVIEW_SYS_TEST_OSC1_OFFSET        0xC4
+#define REALVIEW_SYS_TEST_OSC2_OFFSET        0xC8
+#define REALVIEW_SYS_TEST_OSC3_OFFSET        0xCC
+#define REALVIEW_SYS_TEST_OSC4_OFFSET        0xD0
 
 #define REALVIEW_SYS_BASE                    0x10000000
 #define REALVIEW_SYS_ID                      (REALVIEW_SYS_BASE + REALVIEW_SYS_ID_OFFSET)
 #define REALVIEW_SYS_24MHz                   (REALVIEW_SYS_BASE + REALVIEW_SYS_24MHz_OFFSET)
 #define REALVIEW_SYS_MISC                    (REALVIEW_SYS_BASE + REALVIEW_SYS_MISC_OFFSET)
 #define REALVIEW_SYS_IOSEL                   (REALVIEW_SYS_BASE + REALVIEW_SYS_IOSEL_OFFSET)
+#define REALVIEW_SYS_PROCID                  (REALVIEW_SYS_BASE + REALVIEW_SYS_PROCID_OFFSET)
 #define REALVIEW_SYS_TEST_OSC0               (REALVIEW_SYS_BASE + REALVIEW_SYS_TEST_OSC0_OFFSET)
 #define REALVIEW_SYS_TEST_OSC1               (REALVIEW_SYS_BASE + REALVIEW_SYS_TEST_OSC1_OFFSET)
 #define REALVIEW_SYS_TEST_OSC2               (REALVIEW_SYS_BASE + REALVIEW_SYS_TEST_OSC2_OFFSET)
        /* Reserved 0x1001A000 - 0x1001FFFF */
 #define REALVIEW_CLCD_BASE            0x10020000       /* CLCD */
 #define REALVIEW_DMAC_BASE            0x10030000       /* DMA controller */
-#ifndef CONFIG_REALVIEW_MPCORE
 #define REALVIEW_GIC_CPU_BASE         0x10040000       /* Generic interrupt controller CPU interface */
 #define REALVIEW_GIC_DIST_BASE        0x10041000       /* Generic interrupt controller distributor */
-#else
-#ifdef CONFIG_REALVIEW_MPCORE_REVB
-#define REALVIEW_MPCORE_SCU_BASE       0x10100000      /*  SCU registers */
-#define REALVIEW_GIC_CPU_BASE          0x10100100      /* Generic interrupt controller CPU interface */
-#define REALVIEW_TWD_BASE              0x10100700
-#define REALVIEW_TWD_SIZE              0x00000100
-#define REALVIEW_GIC_DIST_BASE         0x10101000      /* Generic interrupt controller distributor */
-#define REALVIEW_MPCORE_L220_BASE      0x10102000      /* L220 registers */
-#define REALVIEW_MPCORE_SYS_PLD_CTRL1 0xD8             /*  Register offset for MPCore sysctl */
-#else
-#define REALVIEW_MPCORE_SCU_BASE      0x1F000000       /*  SCU registers */
-#define REALVIEW_GIC_CPU_BASE         0x1F000100       /* Generic interrupt controller CPU interface */
-#define REALVIEW_TWD_BASE             0x1F000700
-#define REALVIEW_TWD_SIZE             0x00000100
-#define REALVIEW_GIC_DIST_BASE        0x1F001000       /* Generic interrupt controller distributor */
-#define REALVIEW_MPCORE_L220_BASE     0x1F002000       /* L220 registers */
-#define REALVIEW_MPCORE_SYS_PLD_CTRL1 0x74             /*  Register offset for MPCore sysctl */
-#endif
-#define REALVIEW_GIC1_CPU_BASE        0x10040000       /* Generic interrupt controller CPU interface */
-#define REALVIEW_GIC1_DIST_BASE       0x10041000       /* Generic interrupt controller distributor */
-#endif
 #define REALVIEW_SMC_BASE             0x10080000       /* SMC */
        /* Reserved 0x10090000 - 0x100EFFFF */
 
 #define REALVIEW_INTREG_OFFSET         0x8     /* Interrupt control */
 #define REALVIEW_DECODE_OFFSET         0xC     /* Fitted logic modules */
 
-/* ------------------------------------------------------------------------
- *  Interrupts - bit assignment (primary)
- * ------------------------------------------------------------------------
- */
-#ifndef CONFIG_REALVIEW_MPCORE
-#define INT_WDOGINT                    0       /* Watchdog timer */
-#define INT_SOFTINT                    1       /* Software interrupt */
-#define INT_COMMRx                     2       /* Debug Comm Rx interrupt */
-#define INT_COMMTx                     3       /* Debug Comm Tx interrupt */
-#define INT_TIMERINT0_1                        4       /* Timer 0 and 1 */
-#define INT_TIMERINT2_3                        5       /* Timer 2 and 3 */
-#define INT_GPIOINT0                   6       /* GPIO 0 */
-#define INT_GPIOINT1                   7       /* GPIO 1 */
-#define INT_GPIOINT2                   8       /* GPIO 2 */
-/* 9 reserved */
-#define INT_RTCINT                     10      /* Real Time Clock */
-#define INT_SSPINT                     11      /* Synchronous Serial Port */
-#define INT_UARTINT0                   12      /* UART 0 on development chip */
-#define INT_UARTINT1                   13      /* UART 1 on development chip */
-#define INT_UARTINT2                   14      /* UART 2 on development chip */
-#define INT_UARTINT3                   15      /* UART 3 on development chip */
-#define INT_SCIINT                     16      /* Smart Card Interface */
-#define INT_MMCI0A                     17      /* Multimedia Card 0A */
-#define INT_MMCI0B                     18      /* Multimedia Card 0B */
-#define INT_AACI                       19      /* Audio Codec */
-#define INT_KMI0                       20      /* Keyboard/Mouse port 0 */
-#define INT_KMI1                       21      /* Keyboard/Mouse port 1 */
-#define INT_CHARLCD                    22      /* Character LCD */
-#define INT_CLCDINT                    23      /* CLCD controller */
-#define INT_DMAINT                     24      /* DMA controller */
-#define INT_PWRFAILINT                 25      /* Power failure */
-#define INT_PISMO                      26
-#define INT_DoC                                27      /* Disk on Chip memory controller */
-#define INT_ETH                                28      /* Ethernet controller */
-#define INT_USB                                29      /* USB controller */
-#define INT_TSPENINT                   30      /* Touchscreen pen */
-#define INT_TSKPADINT                  31      /* Touchscreen keypad */
-
-#else
-
-#define MAX_GIC_NR                     2
-
-#define INT_AACI                       0
-#define INT_TIMERINT0_1                        1
-#define INT_TIMERINT2_3                        2
-#define INT_USB                                3
-#define INT_UARTINT0                   4
-#define INT_UARTINT1                   5
-#define INT_RTCINT                     6
-#define INT_KMI0                       7
-#define INT_KMI1                       8
-#define INT_ETH                                9
-#define INT_EB_IRQ1                    10      /* main GIC */
-#define INT_EB_IRQ2                    11      /* tile GIC */
-#define INT_EB_FIQ1                    12      /* main GIC */
-#define INT_EB_FIQ2                    13      /* tile GIC */
-#define INT_MMCI0A                     14
-#define INT_MMCI0B                     15
-
-#define INT_PMU_CPU0                   17
-#define INT_PMU_CPU1                   18
-#define INT_PMU_CPU2                   19
-#define INT_PMU_CPU3                   20
-#define INT_PMU_SCU0                   21
-#define INT_PMU_SCU1                   22
-#define INT_PMU_SCU2                   23
-#define INT_PMU_SCU3                   24
-#define INT_PMU_SCU4                   25
-#define INT_PMU_SCU5                   26
-#define INT_PMU_SCU6                   27
-#define INT_PMU_SCU7                   28
-
-#define INT_L220_EVENT                 29
-#define INT_L220_SLAVE                 30
-#define INT_L220_DECODE                        31
-
-#define INT_UARTINT2                   -1
-#define INT_UARTINT3                   -1
-#define INT_CLCDINT                    -1
-#define INT_DMAINT                     -1
-#define INT_WDOGINT                    -1
-#define INT_GPIOINT0                   -1
-#define INT_GPIOINT1                   -1
-#define INT_GPIOINT2                   -1
-#define INT_SCIINT                     -1
-#define INT_SSPINT                     -1
-#endif
-
-/* 
- *  Interrupt bit positions
- * 
- */
-#define INTMASK_WDOGINT                        (1 << INT_WDOGINT)
-#define INTMASK_SOFTINT                        (1 << INT_SOFTINT)
-#define INTMASK_COMMRx                 (1 << INT_COMMRx)
-#define INTMASK_COMMTx                 (1 << INT_COMMTx)
-#define INTMASK_TIMERINT0_1            (1 << INT_TIMERINT0_1)
-#define INTMASK_TIMERINT2_3            (1 << INT_TIMERINT2_3)
-#define INTMASK_GPIOINT0               (1 << INT_GPIOINT0)
-#define INTMASK_GPIOINT1               (1 << INT_GPIOINT1)
-#define INTMASK_GPIOINT2               (1 << INT_GPIOINT2)
-#define INTMASK_RTCINT                 (1 << INT_RTCINT)
-#define INTMASK_SSPINT                 (1 << INT_SSPINT)
-#define INTMASK_UARTINT0               (1 << INT_UARTINT0)
-#define INTMASK_UARTINT1               (1 << INT_UARTINT1)
-#define INTMASK_UARTINT2               (1 << INT_UARTINT2)
-#define INTMASK_UARTINT3               (1 << INT_UARTINT3)
-#define INTMASK_SCIINT                 (1 << INT_SCIINT)
-#define INTMASK_MMCI0A                 (1 << INT_MMCI0A)
-#define INTMASK_MMCI0B                 (1 << INT_MMCI0B)
-#define INTMASK_AACI                   (1 << INT_AACI)
-#define INTMASK_KMI0                   (1 << INT_KMI0)
-#define INTMASK_KMI1                   (1 << INT_KMI1)
-#define INTMASK_CHARLCD                        (1 << INT_CHARLCD)
-#define INTMASK_CLCDINT                        (1 << INT_CLCDINT)
-#define INTMASK_DMAINT                 (1 << INT_DMAINT)
-#define INTMASK_PWRFAILINT             (1 << INT_PWRFAILINT)
-#define INTMASK_PISMO                  (1 << INT_PISMO)
-#define INTMASK_DoC                    (1 << INT_DoC)
-#define INTMASK_ETH                    (1 << INT_ETH)
-#define INTMASK_USB                    (1 << INT_USB)
-#define INTMASK_TSPENINT               (1 << INT_TSPENINT)
-#define INTMASK_TSKPADINT              (1 << INT_TSKPADINT)
-
-#define MAXIRQNUM                       31
-#define MAXFIQNUM                       31
-#define MAXSWINUM                       31
-
 /* 
  *  Application Flash
  * 
 #define REALVIEW_CSR_BASE             0x10000000
 #define REALVIEW_CSR_SIZE             0x10000000
 
-#endif
-
-/*     END */
+#endif /* __ASM_ARCH_PLATFORM_H */
index cc293640178ed02b56673ef183305374f8fbf080..08b3db883c361fb1ad20484d650589b88b146c87 100644 (file)
@@ -1,8 +1,8 @@
 #ifndef __ASMARM_ARCH_SCU_H
 #define __ASMARM_ARCH_SCU_H
 
-#include <asm/arch/platform.h>
+#include <asm/arch/board-eb.h>
 
-#define SCU_BASE       REALVIEW_MPCORE_SCU_BASE
+#define SCU_BASE       REALVIEW_EB11MP_SCU_BASE
 
 #endif
index f05631d767435f2f086c3ead981a95790b19ce08..3d5c2db07a2688c5b564a2ea046dda2e719d8a65 100644 (file)
@@ -19,6 +19,8 @@
  */
 #include <asm/hardware.h>
 
+#include <asm/arch/platform.h>
+
 #define AMBA_UART_DR   (*(volatile unsigned char *) (REALVIEW_UART0_BASE + 0x00))
 #define AMBA_UART_LCRH (*(volatile unsigned char *) (REALVIEW_UART0_BASE + 0x2c))
 #define AMBA_UART_CR   (*(volatile unsigned char *) (REALVIEW_UART0_BASE + 0x30))
index 745aa841b31ae8824739edc5678a8b4141650db2..f7263b99403b9b8cfc5cd014300b882a81fd6c28 100644 (file)
@@ -22,7 +22,7 @@
 #include <asm/arch/platform.h>
 
 /* 
- *  IRQ interrupts definitions are the same the INT definitions
+ *  IRQ interrupts definitions are the same as the INT definitions
  *  held within platform.h
  */
 #define IRQ_VIC_START          0
@@ -94,7 +94,7 @@
 #define IRQMASK_VICSOURCE31    INTMASK_VICSOURCE31
 
 /* 
- *  FIQ interrupts definitions are the same the INT definitions.
+ *  FIQ interrupts definitions are the same as the INT definitions.
  */
 #define FIQ_WDOGINT            INT_WDOGINT
 #define FIQ_SOFTINT            INT_SOFTINT
index 131d5b40e072934e2b3cd6a0477f5f6fdfe121da..e521b70713c8cff2f14cd90c00e1b39287291183 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef __ASM_HARDWARE_TWD_H
 #define __ASM_HARDWARE_TWD_H
 
-#define TWD_TIMER_LOAD                 0x00
+#define TWD_TIMER_LOAD                         0x00
 #define TWD_TIMER_COUNTER              0x04
 #define TWD_TIMER_CONTROL              0x08
 #define TWD_TIMER_INTSTAT              0x0C
@@ -13,4 +13,9 @@
 #define TWD_WDOG_RESETSTAT             0x30
 #define TWD_WDOG_DISABLE               0x34
 
+#define TWD_TIMER_CONTROL_ENABLE       (1 << 0)
+#define TWD_TIMER_CONTROL_ONESHOT      (0 << 1)
+#define TWD_TIMER_CONTROL_PERIODIC     (1 << 1)
+#define TWD_TIMER_CONTROL_IT_ENABLE    (1 << 2)
+
 #endif
index aaebb61aca4872cb7147a25653072db98c436e5b..74b5fff7f57575f3f67e3f085d6befb51a682d48 100644 (file)
@@ -42,7 +42,7 @@ extern unsigned long it8152_base_address;
 #define IT8152_GPIO_GPDR               __REG_IT8152(0x3f00500)
 
 /*
-  Interrup contoler per register summary:
+  Interrupt controller per register summary:
   ---------------------------------------
   LCDNIRR:
   IT8152_LD_IRQ(8) PCICLK stop
index 46dcc4d0b9bd9cbc520378521b5e9084259ad9aa..1ee17b6951d02f9057867594dbb5f3d268c4e038 100644 (file)
@@ -16,6 +16,9 @@
 
 #define KEXEC_BOOT_PARAMS_SIZE 1536
 
+#define KEXEC_ARM_ATAGS_OFFSET  0x1000
+#define KEXEC_ARM_ZIMAGE_OFFSET 0x8000
+
 #ifndef __ASSEMBLY__
 
 struct kimage;
index ff0a95715a07befda0621fcfca85d829b0ab53ed..f9f3606986c27fedea03382b9de34ba1a7667e89 100644 (file)
@@ -16,10 +16,12 @@ struct pxa2xx_udc_mach_info {
 #define        PXA2XX_UDC_CMD_DISCONNECT       1       /* so host won't see us */
 
        /* Boards following the design guidelines in the developer's manual,
-        * with on-chip GPIOs not Lubbock's wierd hardware, can have a sane
+        * with on-chip GPIOs not Lubbock's weird hardware, can have a sane
         * VBUS IRQ and omit the methods above.  Store the GPIO number
         * here; for GPIO 0, also mask in one of the pxa_gpio_mode() bits.
+        * Note that sometimes the signals go through inverters...
         */
+       bool    gpio_vbus_inverted;
        u16     gpio_vbus;                      /* high == vbus present */
        u16     gpio_pullup;                    /* high == pullup activated */
 };
index 4d43945529118a8ea7e92241771a6f3253a1e93a..fb6c6e3222bddc19131fc59408e12ffbfb824a22 100644 (file)
  * Since we have only two-level page tables, these are trivial
  */
 #define pmd_alloc_one(mm,addr)         ({ BUG(); ((pmd_t *)2); })
-#define pmd_free(pmd)                  do { } while (0)
+#define pmd_free(mm, pmd)              do { } while (0)
 #define pgd_populate(mm,pmd,pte)       BUG()
 
 extern pgd_t *get_pgd_slow(struct mm_struct *mm);
-extern void free_pgd_slow(pgd_t *pgd);
+extern void free_pgd_slow(struct mm_struct *mm, pgd_t *pgd);
 
 #define pgd_alloc(mm)                  get_pgd_slow(mm)
-#define pgd_free(pgd)                  free_pgd_slow(pgd)
+#define pgd_free(mm, pgd)              free_pgd_slow(mm, pgd)
 
 /*
  * Allocate one PTE table.
@@ -83,7 +83,7 @@ pte_alloc_one(struct mm_struct *mm, unsigned long addr)
 /*
  * Free one PTE table.
  */
-static inline void pte_free_kernel(pte_t *pte)
+static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte)
 {
        if (pte) {
                pte -= PTRS_PER_PTE;
@@ -91,7 +91,7 @@ static inline void pte_free_kernel(pte_t *pte)
        }
 }
 
-static inline void pte_free(struct page *pte)
+static inline void pte_free(struct mm_struct *mm, struct page *pte)
 {
        __free_page(pte);
 }
index f67acce387e7fc1bc0dd18326c5633e4fd2314c2..af99636db400e7e8cfbe81956faa1d84f11ebdf2 100644 (file)
@@ -60,6 +60,11 @@ extern void smp_cross_call(cpumask_t callmap);
  */
 extern void smp_send_timer(void);
 
+/*
+ * Broadcast a clock event to other CPUs.
+ */
+extern void smp_timer_broadcast(cpumask_t mask);
+
 /*
  * Boot a secondary CPU, and assign it the specified idle task.
  * This also gives us the initial stack to use for this CPU.
@@ -96,11 +101,12 @@ extern void platform_cpu_die(unsigned int cpu);
 extern int platform_cpu_kill(unsigned int cpu);
 extern void platform_cpu_enable(unsigned int cpu);
 
-#ifdef CONFIG_LOCAL_TIMERS
 /*
- * Setup a local timer interrupt for a CPU.
+ * Local timer interrupt handling function (can be IPI'ed).
  */
-extern void local_timer_setup(unsigned int cpu);
+extern void local_timer_interrupt(void);
+
+#ifdef CONFIG_LOCAL_TIMERS
 
 /*
  * Stop a local timer interrupt.
@@ -114,16 +120,17 @@ extern int local_timer_ack(void);
 
 #else
 
-static inline void local_timer_setup(unsigned int cpu)
-{
-}
-
 static inline void local_timer_stop(unsigned int cpu)
 {
 }
 
 #endif
 
+/*
+ * Setup a local timer interrupt for a CPU.
+ */
+extern void local_timer_setup(unsigned int cpu);
+
 /*
  * show local interrupt info
  */
index 65a1a64bf9340b2b8ec8d4321d26c1deb968739a..6817be9573a6bf65d29ef5092a4a869017cf87bc 100644 (file)
@@ -52,4 +52,6 @@
 #define SO_TIMESTAMPNS         35
 #define SCM_TIMESTAMPNS                SO_TIMESTAMPNS
 
+#define SO_MARK                        36
+
 #endif /* _ASM_SOCKET_H */
index cb740025d4131382de81ac3925ffd7b4359bf94f..36bd402a21cb12ad52ffd610e740fc83b265efde 100644 (file)
@@ -85,8 +85,8 @@ tlb_end_vma(struct mmu_gather *tlb, struct vm_area_struct *vma)
 }
 
 #define tlb_remove_page(tlb,page)      free_page_and_swap_cache(page)
-#define pte_free_tlb(tlb,ptep)         pte_free(ptep)
-#define pmd_free_tlb(tlb,pmdp)         pmd_free(pmdp)
+#define pte_free_tlb(tlb, ptep)                pte_free((tlb)->mm, ptep)
+#define pmd_free_tlb(tlb, pmdp)                pmd_free((tlb)->mm, pmdp)
 
 #define tlb_migrate_finish(mm)         do { } while (0)
 
index 99684d6f39677fbb29a1a4481be58bc226d31204..31e48b0e732414aff872d901dd4c0f33a5f5b54d 100644 (file)
@@ -13,8 +13,6 @@
 #define GPIO_PERIPH_A  0
 #define GPIO_PERIPH_B  1
 
-#define NR_GPIO_CONTROLLERS    4
-
 /*
  * Pin numbers identifying specific GPIO pins on the chip. They can
  * also be converted to IRQ numbers by passing them through
index af7f9535bab32bcaf29a1d253756cfb3f7526142..0180f584ef03d81cc432197e4a23f29eecc2f873 100644 (file)
@@ -5,20 +5,36 @@
 #include <asm/irq.h>
 
 
-/* Arch-neutral GPIO API */
-int __must_check gpio_request(unsigned int gpio, const char *label);
-void gpio_free(unsigned int gpio);
+/* Some GPIO chips can manage IRQs; some can't.  The exact numbers can
+ * be changed if needed, but for the moment they're not configurable.
+ */
+#define ARCH_NR_GPIOS  (NR_GPIO_IRQS + 2 * 32)
 
-int gpio_direction_input(unsigned int gpio);
-int gpio_direction_output(unsigned int gpio, int value);
-int gpio_get_value(unsigned int gpio);
-void gpio_set_value(unsigned int gpio, int value);
 
-#include <asm-generic/gpio.h>          /* cansleep wrappers */
+/* Arch-neutral GPIO API, supporting both "native" and external GPIOs. */
+#include <asm-generic/gpio.h>
+
+static inline int gpio_get_value(unsigned int gpio)
+{
+       return __gpio_get_value(gpio);
+}
+
+static inline void gpio_set_value(unsigned int gpio, int value)
+{
+       __gpio_set_value(gpio, value);
+}
+
+static inline int gpio_cansleep(unsigned int gpio)
+{
+       return __gpio_cansleep(gpio);
+}
+
 
 static inline int gpio_to_irq(unsigned int gpio)
 {
-       return gpio + GPIO_IRQ_BASE;
+       if (gpio < NR_GPIO_IRQS)
+               return gpio + GPIO_IRQ_BASE;
+       return -EINVAL;
 }
 
 static inline int irq_to_gpio(unsigned int irq)
index 5adffab9a577948bd3ed0d74b3a953838d118df9..608e350368c7c7ea58c74dcb2a924c46f9bb8834 100644 (file)
@@ -3,11 +3,11 @@
 
 #define EIM_IRQ_BASE   NR_INTERNAL_IRQS
 #define NR_EIM_IRQS    32
-
 #define AT32_EXTINT(n) (EIM_IRQ_BASE + (n))
 
 #define GPIO_IRQ_BASE  (EIM_IRQ_BASE + NR_EIM_IRQS)
-#define NR_GPIO_IRQS   (5 * 32)
+#define NR_GPIO_CTLR   (5 /*internal*/ + 1 /*external*/)
+#define NR_GPIO_IRQS   (NR_GPIO_CTLR * 32)
 
 #define NR_IRQS                (GPIO_IRQ_BASE + NR_GPIO_IRQS)
 
index 0e680f47209fbc87ca98f90683f8cc57510d10e8..b77e364b4c444a164c9741d2d6ab94df1dfc2e35 100644 (file)
@@ -30,7 +30,7 @@ static __inline__ pgd_t *pgd_alloc(struct mm_struct *mm)
        return kcalloc(USER_PTRS_PER_PGD, sizeof(pgd_t), GFP_KERNEL);
 }
 
-static inline void pgd_free(pgd_t *pgd)
+static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd)
 {
        kfree(pgd);
 }
@@ -55,12 +55,12 @@ static inline struct page *pte_alloc_one(struct mm_struct *mm,
        return pte;
 }
 
-static inline void pte_free_kernel(pte_t *pte)
+static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte)
 {
        free_page((unsigned long)pte);
 }
 
-static inline void pte_free(struct page *pte)
+static inline void pte_free(struct mm_struct *mm, struct page *pte)
 {
        __free_page(pte);
 }
index a0d0507a5034969b70bbc1139631ef5f4cdc077d..35863f260929abe002d57f154c3d5749b2ce1d69 100644 (file)
@@ -52,4 +52,6 @@
 #define SO_TIMESTAMPNS         35
 #define SCM_TIMESTAMPNS                SO_TIMESTAMPNS
 
+#define SO_MARK                        36
+
 #endif /* __ASM_AVR32_SOCKET_H */
index de09009593f84eb12d3e8fa38c0450df96777b7d..89861a27543ec58554f9ad957b84801a80885595 100644 (file)
 
 #define __NR_utimensat         278
 #define __NR_signalfd          279
-#define __NR_timerfd           280
+/* 280 was __NR_timerfd */
 #define __NR_eventfd           281
 
 #ifdef __KERNEL__
index 5213c96521860dc83b3ab8755f971ca2ac5c6887..2ca702e44d4759420051ed73dc9c3662eb2fb5c4 100644 (file)
@@ -50,4 +50,7 @@
 #define SO_PASSSEC             34
 #define SO_TIMESTAMPNS         35
 #define SCM_TIMESTAMPNS                SO_TIMESTAMPNS
+
+#define SO_MARK                        36
+
 #endif                         /* _ASM_SOCKET_H */
index e2f49c27ed297ab40dc7187de1639809fa1c9640..75ea6e0964839de32831162c7338218db9072435 100644 (file)
 #include <asm/atomic.h>
 #include <linux/compiler.h>
 
-/*
- * Some hacks to defeat gcc over-optimizations..
- */
-struct __dummy { unsigned long a[100]; };
-#define ADDR (*(struct __dummy *) addr)
-#define CONST_ADDR (*(const struct __dummy *) addr)
-
 /*
  * set_bit - Atomically set a bit in memory
  * @nr: the bit to set
index deaddfe79bbcd6527f968bc6bc3c4c1087e11440..8ddd66f8177346aeba8c6dd42bf1d313e2355b0a 100644 (file)
@@ -16,7 +16,7 @@ static inline pgd_t *pgd_alloc (struct mm_struct *mm)
        return (pgd_t *)get_zeroed_page(GFP_KERNEL);
 }
 
-static inline void pgd_free (pgd_t *pgd)
+static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd)
 {
        free_page((unsigned long)pgd);
 }
@@ -34,12 +34,12 @@ static inline struct page *pte_alloc_one(struct mm_struct *mm, unsigned long add
        return pte;
 }
 
-static inline void pte_free_kernel(pte_t *pte)
+static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte)
 {
        free_page((unsigned long)pte);
 }
 
-static inline void pte_free(struct page *pte)
+static inline void pte_free(struct mm_struct *mm, struct page *pte)
 {
        __free_page(pte);
 }
index 5b18dfdf1748f2c6538ab3ca2c65d7ef3468e342..9df0ca82f5dedf90437954406dc201e1d073f898 100644 (file)
@@ -54,6 +54,8 @@
 #define SO_TIMESTAMPNS         35
 #define SCM_TIMESTAMPNS                SO_TIMESTAMPNS
 
+#define SO_MARK                        36
+
 #endif /* _ASM_SOCKET_H */
 
 
index d425d8d0ad7758c73d40000a9a792f740ff78a5d..6ec494a5bc5ad91ccbbc7d40749a8b92e9fba913 100644 (file)
@@ -1,7 +1,7 @@
 /* atomic.h: atomic operation emulation for FR-V
  *
  * For an explanation of how atomic ops work in this arch, see:
- *   Documentation/fujitsu/frv/atomic-ops.txt
+ *   Documentation/frv/atomic-ops.txt
  *
  * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
  * Written by David Howells (dhowells@redhat.com)
index e29de7131b79dcca7250aad73b3d603fb1f53458..5f86b876b298b1382a6167e119cc29ea33d26aa2 100644 (file)
@@ -1,7 +1,7 @@
 /* bitops.h: bit operations for the Fujitsu FR-V CPUs
  *
  * For an explanation of how atomic ops work in this arch, see:
- *   Documentation/fujitsu/frv/atomic-ops.txt
+ *   Documentation/frv/atomic-ops.txt
  *
  * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
  * Written by David Howells (dhowells@redhat.com)
index 02500405a6fb26317ad2def7ea098ed3e93a3e0f..432a69e7f3d491488631a270b1cff0e8f2ac6daa 100644 (file)
@@ -29,7 +29,7 @@
 #define flush_dcache_mmap_unlock(mapping)      do {} while(0)
 
 /*
- * physically-indexed cache managment
+ * physically-indexed cache management
  * - see arch/frv/lib/cache.S
  */
 extern void frv_dcache_writeback(unsigned long start, unsigned long size);
index bcb2df68496e684d582f71d6a119f5398ee31c2f..2e8966ca030d46cd4b7514a3a0c4589aeba667b7 100644 (file)
@@ -16,16 +16,6 @@ extern unsigned long __nongprelbss dma_coherent_mem_end;
 void *dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, gfp_t gfp);
 void dma_free_coherent(struct device *dev, size_t size, void *vaddr, dma_addr_t dma_handle);
 
-/*
- * 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)
-
 /*
  * Map a single buffer of the indicated size for DMA in streaming mode.
  * The 32-bit bus address to use is returned.
index ff4d6cdeb1522811bd4131da61d68575ff55502b..26cefcde5cee9abba5df2dc5627d4f38b4016f05 100644 (file)
@@ -4,7 +4,7 @@
  * Written by David Howells (dhowells@redhat.com)
  * - Derived from include/asm-i386/highmem.h
  *
- * See Documentation/fujitsu/frv/mmu-layout.txt for more information.
+ * See Documentation/frv/mmu-layout.txt for more information.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
index aaf2a773d9d3d42070f221ca3443b24821a372cc..83532252b8be17f401d380ed78a0d5df5bbf7b42 100644 (file)
@@ -39,7 +39,7 @@
 
 #ifdef CONFIG_MMU
 
-/* see Documentation/fujitsu/frv/mmu-layout.txt */
+/* see Documentation/frv/mmu-layout.txt */
 #define KERNEL_LOWMEM_START            __UL(0xc0000000)
 #define KERNEL_LOWMEM_END              __UL(0xd0000000)
 #define VMALLOC_START                  __UL(0xd0000000)
index 213d92fd652aa24175ddd673c52cabb932d876be..bd9bd2d9cc7894294c737fa9fe4a2871050030a8 100644 (file)
@@ -76,10 +76,6 @@ extern unsigned long max_pfn;
 
 #endif /* __ASSEMBLY__ */
 
-#ifdef CONFIG_CONTIGUOUS_PAGE_ALLOC
-#define WANT_PAGE_VIRTUAL      1
-#endif
-
 #include <asm-generic/memory_model.h>
 #include <asm-generic/page.h>
 
index ce982a6c610f0081a97c836d6edbc17e52e98f5c..e89620ef08cab876e315ec845d6c96d0d6e1cc97 100644 (file)
@@ -31,18 +31,18 @@ do {                                                                                \
  */
 
 extern pgd_t *pgd_alloc(struct mm_struct *);
-extern void pgd_free(pgd_t *);
+extern void pgd_free(struct mm_struct *mm, pgd_t *);
 
 extern pte_t *pte_alloc_one_kernel(struct mm_struct *, unsigned long);
 
 extern struct page *pte_alloc_one(struct mm_struct *, unsigned long);
 
-static inline void pte_free_kernel(pte_t *pte)
+static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte)
 {
        free_page((unsigned long)pte);
 }
 
-static inline void pte_free(struct page *pte)
+static inline void pte_free(struct mm_struct *mm, struct page *pte)
 {
        __free_page(pte);
 }
@@ -55,7 +55,7 @@ static inline void pte_free(struct page *pte)
  * (In the PAE case we free the pmds as part of the pgd.)
  */
 #define pmd_alloc_one(mm, addr)                ({ BUG(); ((pmd_t *) 2); })
-#define pmd_free(x)                    do { } while (0)
+#define pmd_free(mm, x)                        do { } while (0)
 #define __pmd_free_tlb(tlb,x)          do { } while (0)
 
 #endif /* CONFIG_MMU */
index 147e995bec24e0b058c4a0911f92e8d1706c8763..6c0682ed5fc93db05ec12a27e9dabb6fee665cfc 100644 (file)
@@ -93,7 +93,7 @@ extern unsigned long empty_zero_page;
 
 /*
  * we use 2-level page tables, folding the PMD (mid-level table) into the PGE (top-level entry)
- * [see Documentation/fujitsu/frv/mmu-layout.txt]
+ * [see Documentation/frv/mmu-layout.txt]
  *
  * Page Directory:
  *  - Size: 16KB
@@ -226,7 +226,7 @@ static inline pud_t *pud_offset(pgd_t *pgd, unsigned long address)
  * inside the pgd, so has no extra memory associated with it.
  */
 #define pud_alloc_one(mm, address)             NULL
-#define pud_free(x)                            do { } while (0)
+#define pud_free(mm, x)                                do { } while (0)
 #define __pud_free_tlb(tlb, x)                 do { } while (0)
 
 /*
index 2e7143b5a7ad2921109e4bbf1ec3a4ec2d8d1e76..4bca8a28546c2474e6300d041e117186175dc0ea 100644 (file)
@@ -31,6 +31,16 @@ struct scatterlist {
        unsigned int    length;
 };
 
+/*
+ * 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)
+
 #define ISA_DMA_THRESHOLD (0xffffffffUL)
 
 #endif /* !_ASM_SCATTERLIST_H */
index a823befd11dd8f8ce35c0d3080717032d4c16d87..e51ca67b9356c5dfac236509c2ea00387a3ee911 100644 (file)
@@ -52,5 +52,7 @@
 #define SO_TIMESTAMPNS         35
 #define SCM_TIMESTAMPNS                SO_TIMESTAMPNS
 
+#define SO_MARK                        36
+
 #endif /* _ASM_SOCKET_H */
 
index cd84f1771e34b306397b99c1dfad730d2de63d22..e8c9866675321b1d0c601f500efccf1343a41230 100644 (file)
 #define __NR_epoll_pwait       319
 #define __NR_utimensat         320
 #define __NR_signalfd          321
-#define __NR_timerfd           322
+/* #define __NR_timerfd                322 removed */
 #define __NR_eventfd           323
 #define __NR_fallocate         324
 
index 7b88d3931e3426f96bd88f93b7934bc4023ec79a..9d40e879f99ea968e18e07f142519c5839392003 100644 (file)
@@ -28,7 +28,7 @@
 
 #undef pud_free_tlb
 #define pud_free_tlb(tlb, x)            do { } while (0)
-#define pud_free(x)                    do { } while (0)
+#define pud_free(mm, x)                        do { } while (0)
 #define __pud_free_tlb(tlb, x)         do { } while (0)
 
 #undef  pud_addr_end
index 2d0aab1d8611b756ec02e8f31378c7b6f3f5e828..f29a502f4a6c3d1a656ae5142f52b98fe6421408 100644 (file)
@@ -1,6 +1,102 @@
 #ifndef _ASM_GENERIC_GPIO_H
 #define _ASM_GENERIC_GPIO_H
 
+#ifdef CONFIG_HAVE_GPIO_LIB
+
+/* Platforms may implement their GPIO interface with library code,
+ * at a small performance cost for non-inlined operations and some
+ * extra memory (for code and for per-GPIO table entries).
+ *
+ * While the GPIO programming interface defines valid GPIO numbers
+ * to be in the range 0..MAX_INT, this library restricts them to the
+ * smaller range 0..ARCH_NR_GPIOS.
+ */
+
+#ifndef ARCH_NR_GPIOS
+#define ARCH_NR_GPIOS          256
+#endif
+
+struct seq_file;
+
+/**
+ * struct gpio_chip - abstract a GPIO controller
+ * @label: for diagnostics
+ * @direction_input: configures signal "offset" as input, or returns error
+ * @get: returns value for signal "offset"; for output signals this
+ *     returns either the value actually sensed, or zero
+ * @direction_output: configures signal "offset" as output, or returns error
+ * @set: assigns output value for signal "offset"
+ * @dbg_show: optional routine to show contents in debugfs; default code
+ *     will be used when this is omitted, but custom code can show extra
+ *     state (such as pullup/pulldown configuration).
+ * @base: identifies the first GPIO number handled by this chip; or, if
+ *     negative during registration, requests dynamic ID allocation.
+ * @ngpio: the number of GPIOs handled by this controller; the last GPIO
+ *     handled is (base + ngpio - 1).
+ * @can_sleep: flag must be set iff get()/set() methods sleep, as they
+ *     must while accessing GPIO expander chips over I2C or SPI
+ *
+ * A gpio_chip can help platforms abstract various sources of GPIOs so
+ * they can all be accessed through a common programing interface.
+ * Example sources would be SOC controllers, FPGAs, multifunction
+ * chips, dedicated GPIO expanders, and so on.
+ *
+ * Each chip controls a number of signals, identified in method calls
+ * by "offset" values in the range 0..(@ngpio - 1).  When those signals
+ * are referenced through calls like gpio_get_value(gpio), the offset
+ * is calculated by subtracting @base from the gpio number.
+ */
+struct gpio_chip {
+       char                    *label;
+
+       int                     (*direction_input)(struct gpio_chip *chip,
+                                               unsigned offset);
+       int                     (*get)(struct gpio_chip *chip,
+                                               unsigned offset);
+       int                     (*direction_output)(struct gpio_chip *chip,
+                                               unsigned offset, int value);
+       void                    (*set)(struct gpio_chip *chip,
+                                               unsigned offset, int value);
+       void                    (*dbg_show)(struct seq_file *s,
+                                               struct gpio_chip *chip);
+       int                     base;
+       u16                     ngpio;
+       unsigned                can_sleep:1;
+};
+
+extern const char *gpiochip_is_requested(struct gpio_chip *chip,
+                       unsigned offset);
+
+/* add/remove chips */
+extern int gpiochip_add(struct gpio_chip *chip);
+extern int __must_check gpiochip_remove(struct gpio_chip *chip);
+
+
+/* Always use the library code for GPIO management calls,
+ * or when sleeping may be involved.
+ */
+extern int gpio_request(unsigned gpio, const char *label);
+extern void gpio_free(unsigned gpio);
+
+extern int gpio_direction_input(unsigned gpio);
+extern int gpio_direction_output(unsigned gpio, int value);
+
+extern int gpio_get_value_cansleep(unsigned gpio);
+extern void gpio_set_value_cansleep(unsigned gpio, int value);
+
+
+/* A platform's <asm/gpio.h> code may want to inline the I/O calls when
+ * the GPIO is constant and refers to some always-present controller,
+ * giving direct access to chip registers and tight bitbanging loops.
+ */
+extern int __gpio_get_value(unsigned gpio);
+extern void __gpio_set_value(unsigned gpio, int value);
+
+extern int __gpio_cansleep(unsigned gpio);
+
+
+#else
+
 /* platforms that don't directly support access to GPIOs through I2C, SPI,
  * or other blocking infrastructure can use these wrappers.
  */
@@ -22,4 +118,6 @@ static inline void gpio_set_value_cansleep(unsigned gpio, int value)
        gpio_set_value(gpio, value);
 }
 
+#endif
+
 #endif /* _ASM_GENERIC_GPIO_H */
index 29ff5d84d8c32d2156201ae0eeceb00a4b5ad776..087325ede76cf31e4a9798664d36913928f058b3 100644 (file)
@@ -54,7 +54,7 @@ static inline pmd_t * pmd_offset(pud_t * pud, unsigned long address)
  * inside the pud, so has no extra memory associated with it.
  */
 #define pmd_alloc_one(mm, address)             NULL
-#define pmd_free(x)                            do { } while (0)
+#define pmd_free(mm, x)                                do { } while (0)
 #define __pmd_free_tlb(tlb, x)                 do { } while (0)
 
 #undef  pmd_addr_end
index 566464500558f19e2ec7a72f5985ce184ce81ae9..87cf449a6df380e6be3a11fd24648ef3aefe588b 100644 (file)
@@ -51,7 +51,7 @@ static inline pud_t * pud_offset(pgd_t * pgd, unsigned long address)
  * inside the pgd, so has no extra memory associated with it.
  */
 #define pud_alloc_one(mm, address)             NULL
-#define pud_free(x)                            do { } while (0)
+#define pud_free(mm, x)                                do { } while (0)
 #define __pud_free_tlb(tlb, x)                 do { } while (0)
 
 #undef  pud_addr_end
index d3238f1f70a684c109df2f4b976e2bc89eff22f2..dd1bed860e6487a3c325c2dfd66570efe8616066 100644 (file)
 static inline unsigned char rtc_is_updating(void)
 {
        unsigned char uip;
+       unsigned long flags;
 
-       spin_lock_irq(&rtc_lock);
+       spin_lock_irqsave(&rtc_lock, flags);
        uip = (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP);
-       spin_unlock_irq(&rtc_lock);
+       spin_unlock_irqrestore(&rtc_lock, flags);
        return uip;
 }
 
@@ -46,6 +47,8 @@ static inline unsigned int get_rtc_time(struct rtc_time *time)
 {
        unsigned long uip_watchdog = jiffies;
        unsigned char ctrl;
+       unsigned long flags;
+
 #ifdef CONFIG_MACH_DECSTATION
        unsigned int real_year;
 #endif
@@ -72,7 +75,7 @@ static inline unsigned int get_rtc_time(struct rtc_time *time)
         * RTC has RTC_DAY_OF_WEEK, we ignore it, as it is only updated
         * by the RTC when initially set to a non-zero value.
         */
-       spin_lock_irq(&rtc_lock);
+       spin_lock_irqsave(&rtc_lock, flags);
        time->tm_sec = CMOS_READ(RTC_SECONDS);
        time->tm_min = CMOS_READ(RTC_MINUTES);
        time->tm_hour = CMOS_READ(RTC_HOURS);
@@ -83,7 +86,7 @@ static inline unsigned int get_rtc_time(struct rtc_time *time)
        real_year = CMOS_READ(RTC_DEC_YEAR);
 #endif
        ctrl = CMOS_READ(RTC_CONTROL);
-       spin_unlock_irq(&rtc_lock);
+       spin_unlock_irqrestore(&rtc_lock, flags);
 
        if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
        {
index 6ce9f3ab928da00ba2f233b9439fdcb8b3cfce7c..f490e43a90b90a09e1cfe78a9f1215b66d3df74e 100644 (file)
@@ -14,7 +14,7 @@
 #define _ASM_GENERIC__TLB_H
 
 #include <linux/swap.h>
-#include <linux/quicklist.h>
+#include <asm/pgalloc.h>
 #include <asm/tlbflush.h>
 
 /*
index 39911d8c968406c5040dab05d8c8d5b792d09bec..da2520dbf2547e2643af27749b178e7e5a4dd0eb 100644 (file)
@@ -52,4 +52,6 @@
 #define SO_TIMESTAMPNS         35
 #define SCM_TIMESTAMPNS                SO_TIMESTAMPNS
 
+#define SO_MARK                        36
+
 #endif /* _ASM_SOCKET_H */
index a1b9719f5fbb7ba11071a92ddcd611e6945e2c2e..953d3df9dd22670f16fec92440a9dc18f5431593 100644 (file)
@@ -122,38 +122,40 @@ clear_bit_unlock (int nr, volatile void *addr)
 }
 
 /**
- * __clear_bit_unlock - Non-atomically clear a bit with release
+ * __clear_bit_unlock - Non-atomically clears a bit in memory with release
+ * @nr: Bit to clear
+ * @addr: Address to start counting from
  *
- * This is like clear_bit_unlock, but the implementation uses a store
+ * Similarly to clear_bit_unlock, the implementation uses a store
  * with release semantics. See also __raw_spin_unlock().
  */
 static __inline__ void
-__clear_bit_unlock(int nr, volatile void *addr)
+__clear_bit_unlock(int nr, void *addr)
 {
-       __u32 mask, new;
-       volatile __u32 *m;
+       __u32 * const m = (__u32 *) addr + (nr >> 5);
+       __u32 const new = *m & ~(1 << (nr & 31));
 
-       m = (volatile __u32 *)addr + (nr >> 5);
-       mask = ~(1 << (nr & 31));
-       new = *m & mask;
-       barrier();
        ia64_st4_rel_nta(m, new);
 }
 
 /**
  * __clear_bit - Clears a bit in memory (non-atomic version)
+ * @nr: the bit to clear
+ * @addr: the address to start counting from
+ *
+ * Unlike clear_bit(), this function is non-atomic and may be reordered.
+ * If it's called on the same region of memory simultaneously, the effect
+ * may be that only one operation succeeds.
  */
 static __inline__ void
 __clear_bit (int nr, volatile void *addr)
 {
-       volatile __u32 *p = (__u32 *) addr + (nr >> 5);
-       __u32 m = 1 << (nr & 31);
-       *p &= ~m;
+       *((__u32 *) addr + (nr >> 5)) &= ~(1 << (nr & 31));
 }
 
 /**
  * change_bit - Toggle a bit in memory
- * @nr: Bit to clear
+ * @nr: Bit to toggle
  * @addr: Address to start counting from
  *
  * change_bit() is atomic and may not be reordered.
@@ -178,7 +180,7 @@ change_bit (int nr, volatile void *addr)
 
 /**
  * __change_bit - Toggle a bit in memory
- * @nr: the bit to set
+ * @nr: the bit to toggle
  * @addr: the address to start counting from
  *
  * Unlike change_bit(), this function is non-atomic and may be reordered.
@@ -197,7 +199,7 @@ __change_bit (int nr, volatile void *addr)
  * @addr: Address to count from
  *
  * This operation is atomic and cannot be reordered.  
- * It also implies a memory barrier.
+ * It also implies the acquisition side of the memory barrier.
  */
 static __inline__ int
 test_and_set_bit (int nr, volatile void *addr)
@@ -247,11 +249,11 @@ __test_and_set_bit (int nr, volatile void *addr)
 
 /**
  * test_and_clear_bit - Clear a bit and return its old value
- * @nr: Bit to set
+ * @nr: Bit to clear
  * @addr: Address to count from
  *
  * This operation is atomic and cannot be reordered.  
- * It also implies a memory barrier.
+ * It also implies the acquisition side of the memory barrier.
  */
 static __inline__ int
 test_and_clear_bit (int nr, volatile void *addr)
@@ -272,7 +274,7 @@ test_and_clear_bit (int nr, volatile void *addr)
 
 /**
  * __test_and_clear_bit - Clear a bit and return its old value
- * @nr: Bit to set
+ * @nr: Bit to clear
  * @addr: Address to count from
  *
  * This operation is non-atomic and can be reordered.  
@@ -292,11 +294,11 @@ __test_and_clear_bit(int nr, volatile void * addr)
 
 /**
  * test_and_change_bit - Change a bit and return its old value
- * @nr: Bit to set
+ * @nr: Bit to change
  * @addr: Address to count from
  *
  * This operation is atomic and cannot be reordered.  
- * It also implies a memory barrier.
+ * It also implies the acquisition side of the memory barrier.
  */
 static __inline__ int
 test_and_change_bit (int nr, volatile void *addr)
@@ -315,8 +317,12 @@ test_and_change_bit (int nr, volatile void *addr)
        return (old & bit) != 0;
 }
 
-/*
- * WARNING: non atomic version.
+/**
+ * __test_and_change_bit - Change a bit and return its old value
+ * @nr: Bit to change
+ * @addr: Address to count from
+ *
+ * This operation is non-atomic and can be reordered.
  */
 static __inline__ int
 __test_and_change_bit (int nr, void *addr)
index 0f6e5264ab8fcccefa2da67faa794fec3d79d206..dfcf75b8426d8bde81dd8b7fda51ad5f12df137c 100644 (file)
@@ -181,7 +181,7 @@ struct compat_shmid64_ds {
 /*
  * A pointer passed in from user mode. This should not be used for syscall parameters,
  * just declare them as pointers because the syscall entry code will have appropriately
- * comverted them already.
+ * converted them already.
  */
 typedef        u32             compat_uptr_t;
 
index 5b6665c754c914213f4e6fa8fb76bc497e5bbf1c..de2ed2cbdd845d9404c4036de78cba661f7a6ea5 100644 (file)
@@ -24,7 +24,9 @@
 extern void ia64_bad_param_for_setreg (void);
 extern void ia64_bad_param_for_getreg (void);
 
+#ifdef __KERNEL__
 register unsigned long ia64_r13 asm ("r13") __used;
+#endif
 
 #define ia64_setreg(regnum, val)                                               \
 ({                                                                             \
index 823553bf12e6681861297cbcbcf746a1c0a1a460..f1663aa94a52422dd9c882ad5f3c2d543402ad21 100644 (file)
@@ -3,9 +3,9 @@
  * Purpose:    Machine check handling specific defines
  *
  * Copyright (C) 1999, 2004 Silicon Graphics, Inc.
- * Copyright (C) Vijay Chander (vijay@engr.sgi.com)
- * Copyright (C) Srinivasa Thirumalachar (sprasad@engr.sgi.com)
- * Copyright (C) Russ Anderson (rja@sgi.com)
+ * Copyright (C) Vijay Chander <vijay@engr.sgi.com>
+ * Copyright (C) Srinivasa Thirumalachar <sprasad@engr.sgi.com>
+ * Copyright (C) Russ Anderson <rja@sgi.com>
  */
 
 #ifndef _ASM_IA64_MCA_H
index 76203f9a8718d6706216a961684205f6beffbdaa..dd2a5b134390682b571be17cf5b2689bd2f7bfdc 100644 (file)
@@ -1,8 +1,9 @@
 /*
  * File:       mca_asm.h
+ * Purpose:    Machine check handling specific defines
  *
  * Copyright (C) 1999 Silicon Graphics, Inc.
- * Copyright (C) Vijay Chander (vijay@engr.sgi.com)
+ * Copyright (C) Vijay Chander <vijay@engr.sgi.com>
  * Copyright (C) Srinivasa Thirumalachar <sprasad@engr.sgi.com>
  * Copyright (C) 2000 Hewlett-Packard Co.
  * Copyright (C) 2000 David Mosberger-Tang <davidm@hpl.hp.com>
index 0095bcf798484d0988ff086bc0c5d0a167cd08ab..77f30b664b4eade81ca0985be35d97825fe0a3a8 100644 (file)
 
 #include <linux/threads.h>
 
+#ifdef CONFIG_SMP
+
 #ifdef HAVE_MODEL_SMALL_ATTRIBUTE
 # define PER_CPU_ATTRIBUTES    __attribute__((__model__ (__small__)))
 #endif
 
-#define DECLARE_PER_CPU(type, name)                            \
-       extern PER_CPU_ATTRIBUTES __typeof__(type) per_cpu__##name
-
-/*
- * Pretty much a literal copy of asm-generic/percpu.h, except that percpu_modcopy() is an
- * external routine, to avoid include-hell.
- */
-#ifdef CONFIG_SMP
-
-extern unsigned long __per_cpu_offset[NR_CPUS];
-#define per_cpu_offset(x) (__per_cpu_offset[x])
-
-/* Equal to __per_cpu_offset[smp_processor_id()], but faster to access: */
-DECLARE_PER_CPU(unsigned long, local_per_cpu_offset);
+#define __my_cpu_offset        __ia64_per_cpu_var(local_per_cpu_offset)
 
-#define per_cpu(var, cpu)  (*RELOC_HIDE(&per_cpu__##var, __per_cpu_offset[cpu]))
-#define __get_cpu_var(var) (*RELOC_HIDE(&per_cpu__##var, __ia64_per_cpu_var(local_per_cpu_offset)))
-#define __raw_get_cpu_var(var) (*RELOC_HIDE(&per_cpu__##var, __ia64_per_cpu_var(local_per_cpu_offset)))
-
-extern void percpu_modcopy(void *pcpudst, const void *src, unsigned long size);
-extern void setup_per_cpu_areas (void);
 extern void *per_cpu_init(void);
 
 #else /* ! SMP */
 
-#define per_cpu(var, cpu)                      (*((void)(cpu), &per_cpu__##var))
-#define __get_cpu_var(var)                     per_cpu__##var
-#define __raw_get_cpu_var(var)                 per_cpu__##var
+#define PER_CPU_ATTRIBUTES     __attribute__((__section__(".data.percpu")))
+
 #define per_cpu_init()                         (__phys_per_cpu_start)
 
 #endif /* SMP */
@@ -57,7 +39,12 @@ extern void *per_cpu_init(void);
  * On the positive side, using __ia64_per_cpu_var() instead of __get_cpu_var() is slightly
  * more efficient.
  */
-#define __ia64_per_cpu_var(var)        (per_cpu__##var)
+#define __ia64_per_cpu_var(var)        per_cpu__##var
+
+#include <asm-generic/percpu.h>
+
+/* Equal to __per_cpu_offset[smp_processor_id()], but faster to access: */
+DECLARE_PER_CPU(unsigned long, local_per_cpu_offset);
 
 #endif /* !__ASSEMBLY__ */
 
index 67552cad517339dea7791ce825ca00109d6602f3..556d988123ac1cd5ba351396caf39479401450b0 100644 (file)
@@ -27,7 +27,7 @@ static inline pgd_t *pgd_alloc(struct mm_struct *mm)
        return quicklist_alloc(0, GFP_KERNEL, NULL);
 }
 
-static inline void pgd_free(pgd_t * pgd)
+static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd)
 {
        quicklist_free(0, NULL, pgd);
 }
@@ -44,11 +44,11 @@ static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long addr)
        return quicklist_alloc(0, GFP_KERNEL, NULL);
 }
 
-static inline void pud_free(pud_t * pud)
+static inline void pud_free(struct mm_struct *mm, pud_t *pud)
 {
        quicklist_free(0, NULL, pud);
 }
-#define __pud_free_tlb(tlb, pud)       pud_free(pud)
+#define __pud_free_tlb(tlb, pud)       pud_free((tlb)->mm, pud)
 #endif /* CONFIG_PGTABLE_4 */
 
 static inline void
@@ -62,12 +62,12 @@ static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long addr)
        return quicklist_alloc(0, GFP_KERNEL, NULL);
 }
 
-static inline void pmd_free(pmd_t * pmd)
+static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd)
 {
        quicklist_free(0, NULL, pmd);
 }
 
-#define __pmd_free_tlb(tlb, pmd)       pmd_free(pmd)
+#define __pmd_free_tlb(tlb, pmd)       pmd_free((tlb)->mm, pmd)
 
 static inline void
 pmd_populate(struct mm_struct *mm, pmd_t * pmd_entry, struct page *pte)
@@ -94,12 +94,12 @@ static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm,
        return quicklist_alloc(0, GFP_KERNEL, NULL);
 }
 
-static inline void pte_free(struct page *pte)
+static inline void pte_free(struct mm_struct *mm, struct page *pte)
 {
        quicklist_free_page(0, NULL, pte);
 }
 
-static inline void pte_free_kernel(pte_t * pte)
+static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte)
 {
        quicklist_free(0, NULL, pte);
 }
@@ -109,6 +109,6 @@ static inline void check_pgt_cache(void)
        quicklist_trim(0, NULL, 25, 16);
 }
 
-#define __pte_free_tlb(tlb, pte)       pte_free(pte)
+#define __pte_free_tlb(tlb, pte)       pte_free((tlb)->mm, pte)
 
 #endif                         /* _ASM_IA64_PGALLOC_H */
index be3b0ae43270f81800945752f65843b849ef2460..741f7ecb986a90fb28ed9c0a8020da5b67654f46 100644 (file)
@@ -31,7 +31,8 @@
  * each (assuming 8KB page size), for a total of 8TB of user virtual
  * address space.
  */
-#define TASK_SIZE              (current->thread.task_size)
+#define TASK_SIZE_OF(tsk)      ((tsk)->thread.task_size)
+#define TASK_SIZE              TASK_SIZE_OF(current)
 
 /*
  * This decides where the kernel will search for a free chunk of vm
@@ -472,7 +473,7 @@ ia64_set_psr (__u64 psr)
 {
        ia64_stop();
        ia64_setreg(_IA64_REG_PSR_L, psr);
-       ia64_srlz_d();
+       ia64_srlz_i();
 }
 
 /*
index 1f5412d6f9bb67c97ca25ff51937dfc2e0a34ec4..2251118894ae0005f193a2befa8c5a11b963f4e0 100644 (file)
@@ -649,17 +649,6 @@ typedef struct err_rec {
  * Now define a couple of inline functions for improved type checking
  * and convenience.
  */
-static inline long
-ia64_sal_freq_base (unsigned long which, unsigned long *ticks_per_second,
-                   unsigned long *drift_info)
-{
-       struct ia64_sal_retval isrv;
-
-       SAL_CALL(isrv, SAL_FREQ_BASE, which, 0, 0, 0, 0, 0, 0);
-       *ticks_per_second = isrv.v0;
-       *drift_info = isrv.v1;
-       return isrv.status;
-}
 
 extern s64 ia64_sal_cache_flush (u64 cache_type);
 extern void __init check_sal_cache_flush (void);
@@ -841,6 +830,9 @@ extern int ia64_sal_oemcall_nolock(struct ia64_sal_retval *, u64, u64, u64,
                                   u64, u64, u64, u64, u64);
 extern int ia64_sal_oemcall_reentrant(struct ia64_sal_retval *, u64, u64, u64,
                                      u64, u64, u64, u64, u64);
+extern long
+ia64_sal_freq_base (unsigned long which, unsigned long *ticks_per_second,
+                   unsigned long *drift_info);
 #ifdef CONFIG_HOTPLUG_CPU
 /*
  * System Abstraction Layer Specification
index 9e42ce43cfbeaf92007e07119af6d82c16df5bae..d5ef0aa3e312e82630c0f7d636f6d0c9d2156b95 100644 (file)
@@ -61,4 +61,6 @@
 #define SO_TIMESTAMPNS         35
 #define SCM_TIMESTAMPNS                SO_TIMESTAMPNS
 
+#define SO_MARK                        36
+
 #endif /* _ASM_IA64_SOCKET_H */
index 2f93f4743add897ce75a9700c9a4abfa58d8442b..242028b4d86a1dc858a8df7b606bf80a97e8066d 100644 (file)
@@ -3,7 +3,7 @@
 #define _ASM_M32R_IRQ_H
 
 
-#if defined(CONFIG_PLAT_M32700UT_Alpha) || defined(CONFIG_PLAT_USRV)
+#if defined(CONFIG_PLAT_USRV)
 /*
  * IRQ definitions for M32700UT
  *  M32700 Chip: 64 interrupts
index d39121279a1a411ce4862268bca40e5daf42c574..57623beb44cb6a62a0b14d9cbb7769174b4e75b1 100644 (file)
@@ -13,9 +13,7 @@
  * this archive for more details.
  */
 
-#if defined(CONFIG_PLAT_M32700UT_Alpha)
-#define PLD_PLAT_BASE          0x08c00000
-#elif defined(CONFIG_PLAT_M32700UT) || defined(CONFIG_PLAT_USRV)
+#if defined(CONFIG_PLAT_M32700UT) || defined(CONFIG_PLAT_USRV)
 #define PLD_PLAT_BASE          0x04c00000
 #else
 #error "no platform configuration"
index 943ba63c1ebcf7bb365f541b75b05828429c6e54..e5921adfad1b6ae2490fb89aa61689f9eaf20b5e 100644 (file)
@@ -24,7 +24,7 @@ static __inline__ pgd_t *pgd_alloc(struct mm_struct *mm)
        return pgd;
 }
 
-static __inline__ void pgd_free(pgd_t *pgd)
+static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd)
 {
        free_page((unsigned long)pgd);
 }
@@ -46,17 +46,17 @@ static __inline__ struct page *pte_alloc_one(struct mm_struct *mm,
        return pte;
 }
 
-static __inline__ void pte_free_kernel(pte_t *pte)
+static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte)
 {
        free_page((unsigned long)pte);
 }
 
-static __inline__ void pte_free(struct page *pte)
+static inline void pte_free(struct mm_struct *mm, struct page *pte)
 {
        __free_page(pte);
 }
 
-#define __pte_free_tlb(tlb, pte)       pte_free((pte))
+#define __pte_free_tlb(tlb, pte)       pte_free((tlb)->mm, (pte))
 
 /*
  * allocating and freeing a pmd is trivial: the 1-entry pmd is
@@ -65,7 +65,7 @@ static __inline__ void pte_free(struct page *pte)
  */
 
 #define pmd_alloc_one(mm, addr)                ({ BUG(); ((pmd_t *)2); })
-#define pmd_free(x)                    do { } while (0)
+#define pmd_free(mm, x)                        do { } while (0)
 #define __pmd_free_tlb(tlb, x)         do { } while (0)
 #define pgd_populate(mm, pmd, pte)     BUG()
 
index 793d5d30c8505f03ddb1c0e8801c771177f7e82e..9a0e200122249e5cae09d90d73b01d820dbe9e83 100644 (file)
@@ -52,4 +52,6 @@
 #define SO_TIMESTAMPNS         35
 #define SCM_TIMESTAMPNS                SO_TIMESTAMPNS
 
+#define SO_MARK                        36
+
 #endif /* _ASM_M32R_SOCKET_H */
index f467eac9ba70cf3e77402bbc1fc0140a774ce032..cf701c93324937aa4f6803279baa6df0bcc1a4cb 100644 (file)
 #define __NR_epoll_pwait       319
 #define __NR_utimensat         320
 #define __NR_signalfd          321
-#define __NR_timerfd           322
+/* #define __NR_timerfd                322 removed */
 #define __NR_eventfd           323
 #define __NR_fallocate         324
 
index 27d11da2b47961a04ad930d04183dcf6e7b1f874..28b0f49ee5217c184eacbb9746101571ef85ff97 100644 (file)
@@ -14,8 +14,6 @@ extern void mac_init_IRQ(void);
 extern int mac_irq_pending(unsigned int);
 extern void mac_identify(void);
 extern void mac_report_hardware(void);
-extern void mac_debugging_penguin(int);
-extern void mac_boom(int);
 
 /*
  *     Floppy driver magic hook - probably shouldnt be here
index 5158412cd54dd4f8a8ca827c57b6441897850101..500ec9b8b1892aebb41ec8833fa982abf5acaf9f 100644 (file)
@@ -22,7 +22,7 @@ static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long ad
        return pte;
 }
 
-static inline void pte_free_kernel(pte_t *pte)
+static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte)
 {
        cache_page(pte);
        free_page((unsigned long) pte);
@@ -47,7 +47,7 @@ static inline struct page *pte_alloc_one(struct mm_struct *mm, unsigned long add
        return page;
 }
 
-static inline void pte_free(struct page *page)
+static inline void pte_free(struct mm_struct *mm, struct page *page)
 {
        cache_page(kmap(page));
        kunmap(page);
@@ -67,7 +67,7 @@ static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long address)
        return get_pointer_table();
 }
 
-static inline int pmd_free(pmd_t *pmd)
+static inline int pmd_free(struct mm_struct *mm, pmd_t *pmd)
 {
        return free_pointer_table(pmd);
 }
@@ -78,9 +78,9 @@ static inline int __pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmd)
 }
 
 
-static inline void pgd_free(pgd_t *pgd)
+static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd)
 {
-       pmd_free((pmd_t *)pgd);
+       pmd_free(mm, (pmd_t *)pgd);
 }
 
 static inline pgd_t *pgd_alloc(struct mm_struct *mm)
index 6d21b90863ad1220d8f614e7b071f7bbc62d8f89..dbc64e92c41ac572bd80b99790f80977ed5e8c75 100644 (file)
@@ -52,4 +52,6 @@
 #define SO_TIMESTAMPNS         35
 #define SCM_TIMESTAMPNS                SO_TIMESTAMPNS
 
+#define SO_MARK                        36
+
 #endif /* _ASM_SOCKET_H */
index fd8241117649e978e320b4731cdc257c54c7f49c..a5a91e72714b0b9e715bba4ee0a008a777187057 100644 (file)
@@ -21,12 +21,12 @@ extern const char bad_pmd_string[];
 #define pmd_alloc_one(mm,address)       ({ BUG(); ((pmd_t *)2); })
 
 
-static inline void pte_free_kernel(pte_t * pte)
+static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte)
 {
         free_page((unsigned long) pte);
 }
 
-static inline void pte_free(struct page *page)
+static inline void pte_free(struct mm_struct *mm, struct page *page)
 {
         __free_page(page);
 }
@@ -72,10 +72,10 @@ static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd, struct page *p
  * allocating and freeing a pmd is trivial: the 1-entry pmd is
  * inside the pgd, so has no extra memory associated with it.
  */
-#define pmd_free(x)                    do { } while (0)
+#define pmd_free(mm, x)                        do { } while (0)
 #define __pmd_free_tlb(tlb, x)         do { } while (0)
 
-static inline void pgd_free(pgd_t * pgd)
+static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd)
 {
         free_page((unsigned long) pgd);
 }
index f43afe1fc3b33940dc1c46178045830f4bf01b44..c142fbf2f376b0abc4767f5c6c048130d5fcd8f2 100644 (file)
@@ -262,7 +262,7 @@ static __inline__ unsigned long ext2_find_next_zero_bit(void *addr, unsigned lon
                 * tmp = __swab32(*(p++));
                 * tmp |= ~0UL >> (32-offset);
                 *
-                * but this would decrease preformance, so we change the
+                * but this would decrease performance, so we change the
                 * shift:
                 */
                tmp = *(p++);
index 163dcb1a9689d3687aa6e5775bcaf82eee65932f..29bc0aad2ebc7fb5c69bdcf34ebbd739a9a9f18a 100644 (file)
@@ -53,7 +53,7 @@ static inline void __flush_cache_all(void)
 #endif /* CONFIG_M5407 */
 #if defined(CONFIG_M527x) || defined(CONFIG_M528x)
        __asm__ __volatile__ (
-               "movel  #0x81400100, %%d0\n\t"
+               "movel  #0x81000200, %%d0\n\t"
                "movec  %%d0, %%CACR\n\t"
                "nop\n\t"
                : : : "d0" );
index 0161ebb5d883f903e9bef07371ba2dbd5b79331f..36e870b468ef0fa1546890f5b8b05516eab60398 100644 (file)
@@ -715,7 +715,7 @@ extern void cpm_install_handler(int vec, void (*handler)(void *), void *dev_id);
 #define        CICR_SCC_SCC3           ((uint)0x00200000)      /* SCC3 @ SCCc */
 #define        CICR_SCB_SCC2           ((uint)0x00040000)      /* SCC2 @ SCCb */
 #define        CICR_SCA_SCC1           ((uint)0x00000000)      /* SCC1 @ SCCa */
-#define CICR_IRL_MASK          ((uint)0x0000e000)      /* Core interrrupt */
+#define CICR_IRL_MASK          ((uint)0x0000e000)      /* Core interrupt */
 #define CICR_HP_MASK           ((uint)0x00001f00)      /* Hi-pri int. */
 #define CICR_IEN               ((uint)0x00000080)      /* Int. enable */
 #define CICR_SPS               ((uint)0x00000001)      /* SCC Spread */
index 04a20fd051cfa5685ad7a144d027d449a9fce771..55cbd6294ab68508492d3143fa49c2d6a306611c 100644 (file)
@@ -68,7 +68,7 @@ static inline void _udelay(unsigned long usecs)
 /*
  *     Moved the udelay() function into library code, no longer inlined.
  *     I had to change the algorithm because we are overflowing now on
- *     the faster ColdFire parts. The code is a little biger, so it makes
+ *     the faster ColdFire parts. The code is a little bigger, so it makes
  *     sense to library it.
  */
 extern void udelay(unsigned long usecs);
index 399814f0b219fee7468f84321064aa58f2ac9020..366eb8602d2fb124aee5eab7b59341e49b41cf41 100644 (file)
 #define MCFSIM_CSAR1           0x8c            /* CS 1 Address reg (r/w) */
 #define MCFSIM_CSMR1           0x90            /* CS 1 Mask reg (r/w) */
 #define MCFSIM_CSCR1           0x96            /* CS 1 Control reg (r/w) */
-#define MCFSIM_CSAR2           0x98            /* CS 2 Adress reg (r/w) */
+#define MCFSIM_CSAR2           0x98            /* CS 2 Address reg (r/w) */
 #define MCFSIM_CSMR2           0x9c            /* CS 2 Mask reg (r/w) */
 #define MCFSIM_CSCR2           0xa2            /* CS 2 Control reg (r/w) */
-#define MCFSIM_CSAR3           0xa4            /* CS 3 Adress reg (r/w) */
+#define MCFSIM_CSAR3           0xa4            /* CS 3 Address reg (r/w) */
 #define MCFSIM_CSMR3           0xa8            /* CS 3 Mask reg (r/w) */
 #define MCFSIM_CSCR3           0xae            /* CS 3 Control reg (r/w) */
 
index d3ce550f6ef4b078d50c2d14b38fdb318405c723..5886728409c07894522da014d95dd022958840e1 100644 (file)
 #define MCFSIM_CSMR7           0xda            /* CS 7 Mask reg (r/w) */
 #define MCFSIM_CSCR7           0xde            /* CS 7 Control reg (r/w) */
 #else
-#define MCFSIM_CSAR2           0x98            /* CS 2 Adress reg (r/w) */
+#define MCFSIM_CSAR2           0x98            /* CS 2 Address reg (r/w) */
 #define MCFSIM_CSMR2           0x9c            /* CS 2 Mask reg (r/w) */
 #define MCFSIM_CSCR2           0xa2            /* CS 2 Control reg (r/w) */
-#define MCFSIM_CSAR3           0xa4            /* CS 3 Adress reg (r/w) */
+#define MCFSIM_CSAR3           0xa4            /* CS 3 Address reg (r/w) */
 #define MCFSIM_CSMR3           0xa8            /* CS 3 Mask reg (r/w) */
 #define MCFSIM_CSCR3           0xae            /* CS 3 Control reg (r/w) */
-#define MCFSIM_CSAR4           0xb0            /* CS 4 Adress reg (r/w) */
+#define MCFSIM_CSAR4           0xb0            /* CS 4 Address reg (r/w) */
 #define MCFSIM_CSMR4           0xb4            /* CS 4 Mask reg (r/w) */
 #define MCFSIM_CSCR4           0xba            /* CS 4 Control reg (r/w) */
-#define MCFSIM_CSAR5           0xbc            /* CS 5 Adress reg (r/w) */
+#define MCFSIM_CSAR5           0xbc            /* CS 5 Address reg (r/w) */
 #define MCFSIM_CSMR5           0xc0            /* CS 5 Mask reg (r/w) */
 #define MCFSIM_CSCR5           0xc6            /* CS 5 Control reg (r/w) */
-#define MCFSIM_CSAR6           0xc8            /* CS 6 Adress reg (r/w) */
+#define MCFSIM_CSAR6           0xc8            /* CS 6 Address reg (r/w) */
 #define MCFSIM_CSMR6           0xcc            /* CS 6 Mask reg (r/w) */
 #define MCFSIM_CSCR6           0xd2            /* CS 6 Control reg (r/w) */
-#define MCFSIM_CSAR7           0xd4            /* CS 7 Adress reg (r/w) */
+#define MCFSIM_CSAR7           0xd4            /* CS 7 Address reg (r/w) */
 #define MCFSIM_CSMR7           0xd8            /* CS 7 Mask reg (r/w) */
 #define MCFSIM_CSCR7           0xde            /* CS 7 Control reg (r/w) */
 #endif /* CONFIG_OLDMASK */
index 75dcdacdb2980d90ca27398cee610c997b6bc74d..cc22c4a53005cc9a9e714889fd2869f3919a84e9 100644 (file)
 #define MCFSIM_CSMR1           0x90            /* CS 1 Mask reg (r/w) */
 #define MCFSIM_CSCR1           0x96            /* CS 1 Control reg (r/w) */
 
-#define MCFSIM_CSAR2           0x98            /* CS 2 Adress reg (r/w) */
+#define MCFSIM_CSAR2           0x98            /* CS 2 Address reg (r/w) */
 #define MCFSIM_CSMR2           0x9c            /* CS 2 Mask reg (r/w) */
 #define MCFSIM_CSCR2           0xa2            /* CS 2 Control reg (r/w) */
-#define MCFSIM_CSAR3           0xa4            /* CS 3 Adress reg (r/w) */
+#define MCFSIM_CSAR3           0xa4            /* CS 3 Address reg (r/w) */
 #define MCFSIM_CSMR3           0xa8            /* CS 3 Mask reg (r/w) */
 #define MCFSIM_CSCR3           0xae            /* CS 3 Control reg (r/w) */
-#define MCFSIM_CSAR4           0xb0            /* CS 4 Adress reg (r/w) */
+#define MCFSIM_CSAR4           0xb0            /* CS 4 Address reg (r/w) */
 #define MCFSIM_CSMR4           0xb4            /* CS 4 Mask reg (r/w) */
 #define MCFSIM_CSCR4           0xba            /* CS 4 Control reg (r/w) */
-#define MCFSIM_CSAR5           0xbc            /* CS 5 Adress reg (r/w) */
+#define MCFSIM_CSAR5           0xbc            /* CS 5 Address reg (r/w) */
 #define MCFSIM_CSMR5           0xc0            /* CS 5 Mask reg (r/w) */
 #define MCFSIM_CSCR5           0xc6            /* CS 5 Control reg (r/w) */
-#define MCFSIM_CSAR6           0xc8            /* CS 6 Adress reg (r/w) */
+#define MCFSIM_CSAR6           0xc8            /* CS 6 Address reg (r/w) */
 #define MCFSIM_CSMR6           0xcc            /* CS 6 Mask reg (r/w) */
 #define MCFSIM_CSCR6           0xd2            /* CS 6 Control reg (r/w) */
-#define MCFSIM_CSAR7           0xd4            /* CS 7 Adress reg (r/w) */
+#define MCFSIM_CSAR7           0xd4            /* CS 7 Address reg (r/w) */
 #define MCFSIM_CSMR7           0xd8            /* CS 7 Mask reg (r/w) */
 #define MCFSIM_CSCR7           0xde            /* CS 7 Control reg (r/w) */
 
index a3f8cc8a4a8403f79ce381945e05dad7f8bd2480..d57217ca4f27fe15c1dbe96d926ba3cd0989121c 100644 (file)
 #define CICR_SCC_SCC3           ((uint)0x00200000)      /* SCC3 @ SCCc */
 #define CICR_SCD_SCC4           ((uint)0x00c00000)      /* SCC4 @ SCCd */
 
-#define CICR_IRL_MASK           ((uint)0x0000e000)      /* Core interrrupt */
+#define CICR_IRL_MASK           ((uint)0x0000e000)      /* Core interrupt */
 #define CICR_HP_MASK            ((uint)0x00001f00)      /* Hi-pri int. */
 #define CICR_VBA_MASK           ((uint)0x000000e0)      /* Vector Base Address */
 #define CICR_SPS                ((uint)0x00000001)      /* SCC Spread */
index 7b61a8a529f52063fa01b760a78ca125b4e3235a..c042634fadaa0cecb2c83d0ea9e3feac3ecc91d5 100644 (file)
@@ -60,7 +60,7 @@
        nop
        movel   #0x0000c020, %d0        /* Set SDRAM cached only */
        movec   %d0, %ACR0
-       movel   #0xff00c000, %d0        /* Cache Flash also */
+       movel   #0x00000000, %d0        /* No other regions cached */
        movec   %d0, %ACR1
        movel   #0x80000200, %d0        /* Setup cache mask */
        movec   %d0, %CACR              /* Enable cache */
index c920ccdb61fef26c82188658de184a5ced0dac3c..431f63aadd0ea3fbec75748cdce78c65326ffb89 100644 (file)
 #define        NE2000_BYTE             volatile unsigned char
 #endif
 
-#if defined(CONFIG_CFV240)
-#define NE2000_ADDR             0x40010000
-#define NE2000_ADDR1            0x40010001
-#define NE2000_ODDOFFSET        0x00000000
-#define NE2000_IRQ              1
-#define NE2000_IRQ_VECTOR       0x19
-#define NE2000_IRQ_PRIORITY     2
-#define NE2000_IRQ_LEVEL        1
-#define        NE2000_BYTE             volatile unsigned char
-#endif
-
 #if defined(CONFIG_M5307C3)
 #define NE2000_ADDR            0x40000300
 #define NE2000_ODDOFFSET       0x00010000
@@ -173,13 +162,8 @@ void ne2000_outsw(unsigned int addr, void *vbuf, unsigned long len);
  *     On most NE2000 implementations on ColdFire boards the chip is
  *     mapped in kinda funny, due to its ISA heritage.
  */
-#ifdef CONFIG_CFV240
-#define NE2000_PTR(addr)       (NE2000_ADDR + ((addr & 0x3f) << 1) + 1)
-#define NE2000_DATA_PTR(addr)  (NE2000_ADDR + ((addr & 0x3f) << 1))
-#else
 #define        NE2000_PTR(addr)        ((addr&0x1)?(NE2000_ODDOFFSET+addr-1):(addr))
 #define        NE2000_DATA_PTR(addr)   (addr)
-#endif
 
 
 void ne2000_outb(unsigned int val, unsigned int addr)
@@ -285,17 +269,6 @@ void ne2000_irqsetup(int irq)
 }
 #endif
 
-#if defined(CONFIG_CFV240)
-void ne2000_irqsetup(int irq)
-{
-       volatile unsigned char  *icrp;
-
-       icrp = (volatile unsigned char *) (MCF_MBAR + MCFSIM_ICR1);
-       *icrp = MCFSIM_ICR_LEVEL1 | MCFSIM_ICR_PRI2 | MCFSIM_ICR_AUTOVEC;
-       mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_EINT1);
-}
-#endif
-
 #if defined(CONFIG_M5206e) && defined(CONFIG_NETtel)
 void ne2000_irqsetup(int irq)
 {
index 1074ae717f74bf73f67d8710abfcb7b62bea6dfc..da3f2ceff3a4bd1b5abf5bfd0568d4cad91022b5 100644 (file)
@@ -17,9 +17,7 @@
  *     Include 5204, 5206/e, 5235, 5249, 5270/5271, 5272, 5280/5282,
  *     5307 or 5407 specific addresses.
  */
-#if defined(CONFIG_M5204)
-#include <asm/m5204sim.h>
-#elif defined(CONFIG_M5206) || defined(CONFIG_M5206e)
+#if defined(CONFIG_M5206) || defined(CONFIG_M5206e)
 #include <asm/m5206sim.h>
 #elif defined(CONFIG_M520x)
 #include <asm/m520xsim.h>
index 6f4d796e03db057f20cc3434be121439711cf381..0f90f6d2227a7993acefba1a3caaff4c626e9257 100644 (file)
@@ -16,7 +16,7 @@
 /*
  *     Get address specific defines for this ColdFire member.
  */
-#if defined(CONFIG_M5204) || defined(CONFIG_M5206) || defined(CONFIG_M5206e)
+#if defined(CONFIG_M5206) || defined(CONFIG_M5206e)
 #define        MCFTIMER_BASE1          0x100           /* Base address of TIMER1 */
 #define        MCFTIMER_BASE2          0x120           /* Base address of TIMER2 */
 #elif defined(CONFIG_M5272)
index 873d0805219ce7a635751df3367b87c2f773b07f..ef2293873612c6985814be4786420573d00869f6 100644 (file)
@@ -12,7 +12,6 @@
 #define        mcfuart_h
 /****************************************************************************/
 
-
 /*
  *     Define the base address of the UARTS within the MBAR address
  *     space.
@@ -20,7 +19,7 @@
 #if defined(CONFIG_M5272)
 #define        MCFUART_BASE1           0x100           /* Base address of UART1 */
 #define        MCFUART_BASE2           0x140           /* Base address of UART2 */
-#elif defined(CONFIG_M5204) || defined(CONFIG_M5206) || defined(CONFIG_M5206e)
+#elif defined(CONFIG_M5206) || defined(CONFIG_M5206e)
 #if defined(CONFIG_NETtel)
 #define        MCFUART_BASE1           0x180           /* Base address of UART1 */
 #define        MCFUART_BASE2           0x140           /* Base address of UART2 */
@@ -33,7 +32,7 @@
 #define MCFUART_BASE2          0x240           /* Base address of UART2 */
 #define MCFUART_BASE3          0x280           /* Base address of UART3 */
 #elif defined(CONFIG_M5249) || defined(CONFIG_M5307) || defined(CONFIG_M5407)
-#if defined(CONFIG_NETtel) || defined(CONFIG_DISKtel) || defined(CONFIG_SECUREEDGEMP3)
+#if defined(CONFIG_NETtel) || defined(CONFIG_SECUREEDGEMP3)
 #define MCFUART_BASE1          0x200           /* Base address of UART1 */
 #define MCFUART_BASE2          0x1c0           /* Base address of UART2 */
 #else
@@ -72,7 +71,7 @@ struct mcf_platform_uart {
 #define        MCFUART_UTB             0x0c            /* Transmit Buffer (w) */
 #define        MCFUART_UIPCR           0x10            /* Input Port Change (r) */
 #define        MCFUART_UACR            0x10            /* Auxiliary Control (w) */
-#define        MCFUART_UISR            0x14            /* Interrup Status (r) */
+#define        MCFUART_UISR            0x14            /* Interrupt Status (r) */
 #define        MCFUART_UIMR            0x14            /* Interrupt Mask (w) */
 #define        MCFUART_UBG1            0x18            /* Baud Rate MSB (r/w) */
 #define        MCFUART_UBG2            0x1c            /* Baud Rate LSB (r/w) */
index 15b4c7d45c94a643865b511040cff2e5dcd0e04a..ee2dc07bae0e3ef232d8a23b38bcaf3029a1d5d2 100644 (file)
@@ -207,23 +207,6 @@ cmpxchg(volatile int *p, int old, int new)
 }
 
 
-#ifdef CONFIG_M68332
-#define HARD_RESET_NOW() ({            \
-        local_irq_disable();           \
-        asm("                          \
-       movew   #0x0000, 0xfffa6a;      \
-        reset;                         \
-        /*movew #0x1557, 0xfffa44;*/   \
-        /*movew #0x0155, 0xfffa46;*/   \
-        moveal #0, %a0;                        \
-        movec %a0, %vbr;               \
-        moveal 0, %sp;                 \
-        moveal 4, %a0;                 \
-        jmp (%a0);                     \
-        ");                            \
-})
-#endif
-
 #if defined( CONFIG_M68328 ) || defined( CONFIG_M68EZ328 ) || \
        defined (CONFIG_M68360) || defined( CONFIG_M68VZ328 )
 #define HARD_RESET_NOW() ({            \
index 568c76cdd9000aed94b2d7970bbfdb2f446d6973..ac5d541368e934a30ca17ac03e58bd990b9eb7ca 100644 (file)
@@ -128,7 +128,7 @@ typedef u32         compat_sigset_word;
  * A pointer passed in from user mode. This should not
  * be used for syscall parameters, just declare them
  * as pointers because the syscall entry code will have
- * appropriately comverted them already.
+ * appropriately converted them already.
  */
 typedef u32            compat_uptr_t;
 
index aef0edbfe4c637160803221ec33ecb30bbea7d31..e4fe26c160babb45ce5361f5b2b3ecf1c94f8d51 100644 (file)
@@ -74,7 +74,6 @@ typedef struct
         struct dbdma_cmd        *dma_table_cpu;
         dma_addr_t              dma_table_dma;
 #endif
-        struct device           *dev;
        int                     irq;
        u32                     regbase;
 #ifdef CONFIG_PM
index 38fcda703a0b197234fbb09577f1fb83b8285c00..0a1ef69bece76c54c356537506021da904c4611a 100644 (file)
@@ -3,7 +3,7 @@
 
 
 /**
- * Adress alignment of the individual FPGA bytes.
+ * Address alignment of the individual FPGA bytes.
  * The address arrangement of the individual bytes of the FPGA is two
  * byte aligned at the embedded MK2 platform.
  */
index 00d8bf6164a950f1664b3f81fa8d1cc607e5fe61..83746b84a5ec53c3c2d36a84e3780050fcff7ad2 100644 (file)
@@ -45,7 +45,7 @@
 #define GT_PCI_IO_SIZE 0x02000000UL
 
 /*
- * PCI interrupts will come in on either the INTA or INTD interrups lines,
+ * PCI interrupts will come in on either the INTA or INTD interrupt lines,
  * which are mapped to the #2 and #5 interrupt pins of the MIPS.  On our
  * boards, they all either come in on IntD or they all come in on IntA, they
  * aren't mixed. There can be numerous PCI interrupts, so we keep a list of the
index 81b72122207ad47a8dc09118c1dae1f0d9bebf65..c4efeced8396da58d0bad7b56fc4f2da50d2f753 100644 (file)
@@ -58,7 +58,7 @@ static inline pgd_t *pgd_alloc(struct mm_struct *mm)
        return ret;
 }
 
-static inline void pgd_free(pgd_t *pgd)
+static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd)
 {
        free_pages((unsigned long)pgd, PGD_ORDER);
 }
@@ -85,12 +85,12 @@ static inline struct page *pte_alloc_one(struct mm_struct *mm,
        return pte;
 }
 
-static inline void pte_free_kernel(pte_t *pte)
+static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte)
 {
        free_pages((unsigned long)pte, PTE_ORDER);
 }
 
-static inline void pte_free(struct page *pte)
+static inline void pte_free(struct mm_struct *mm, struct page *pte)
 {
        __free_pages(pte, PTE_ORDER);
 }
@@ -103,7 +103,7 @@ static inline void pte_free(struct page *pte)
  * allocating and freeing a pmd is trivial: the 1-entry pmd is
  * inside the pgd, so has no extra memory associated with it.
  */
-#define pmd_free(x)                    do { } while (0)
+#define pmd_free(mm, x)                        do { } while (0)
 #define __pmd_free_tlb(tlb, x)         do { } while (0)
 
 #endif
@@ -120,12 +120,12 @@ static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long address)
        return pmd;
 }
 
-static inline void pmd_free(pmd_t *pmd)
+static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd)
 {
        free_pages((unsigned long)pmd, PMD_ORDER);
 }
 
-#define __pmd_free_tlb(tlb, x) pmd_free(x)
+#define __pmd_free_tlb(tlb, x) pmd_free((tlb)->mm, x)
 
 #endif
 
index 83bc94534084a429735e9d6620fdb1a02c2d9f80..36f42de594094b73f5b60ffc2dc0f09ebdf20b1c 100644 (file)
@@ -65,6 +65,8 @@ extern unsigned int vced_count, vcei_count;
 #define TASK_UNMAPPED_BASE                                             \
        (test_thread_flag(TIF_32BIT_ADDR) ?                             \
                PAGE_ALIGN(TASK_SIZE32 / 3) : PAGE_ALIGN(TASK_SIZE / 3))
+#define TASK_SIZE_OF(tsk)                                              \
+       (test_tsk_thread_flag(tsk, TIF_32BIT_ADDR) ? TASK_SIZE32 : TASK_SIZE)
 #endif
 
 #define NUM_FPU_REGS   32
index f4981c4f16bbfa999f49039dc76afa4a1a796973..c0501f91719b93a6a82db3fa082243eb500b9ffe 100644 (file)
@@ -15,7 +15,7 @@
 /*
  * These are the virtual IRQ numbers, we divide all IRQ's into
  * 'spaces', the 'space' determines where and how to enable/disable
- * that particular IRQ on an SGI machine. HPC DMA and MC DMA interrups
+ * that particular IRQ on an SGI machine. HPC DMA and MC DMA interrupts
  * are not supported this way. Driver is supposed to allocate HPC/MC
  * interrupt as shareable and then look to proper status bit (see
  * HAL2 driver). This will prevent many complications, trust me ;-)
index ef91b3363554ca8e1736112f3ab4a017b117e2cd..0187895e556c0f4a42bb4a83c544b16687551536 100644 (file)
@@ -338,7 +338,7 @@ typedef union io_perf_cnt {
 #define IIO_IFDR       0x400398        /* IOQ FIFO Depth */
 #define IIO_IIAP       0x4003a0        /* IIQ Arbitration Parameters */
 #define IIO_IMMR       IIO_IIAP
-#define IIO_ICMR       0x4003a8        /* CRB Managment Register */
+#define IIO_ICMR       0x4003a8        /* CRB Management Register */
 #define IIO_ICCR       0x4003b0        /* CRB Control Register */
 #define IIO_ICTO       0x4003b8        /* CRB Time Out Register */
 #define IIO_ICTP       0x4003c0        /* CRB Time Out Prescalar */
index 95945689b1c669193b20765a1d202bebecca8b1a..63f60254d308741efde979586ccdd9456ac47811 100644 (file)
@@ -73,6 +73,8 @@ To add: #define SO_REUSEPORT 0x0200   /* Allow local address and port reuse.  */
 #define SO_TIMESTAMPNS         35
 #define SCM_TIMESTAMPNS                SO_TIMESTAMPNS
 
+#define SO_MARK                        36
+
 #ifdef __KERNEL__
 
 /** sock_type - Socket types
index 5a85d1b025c810de6e881931ce0ae3a38574216c..7f32611a7a5ebc1fe64e36716db7748df21c5070 100644 (file)
@@ -132,7 +132,7 @@ typedef u32         compat_sigset_word;
  * A pointer passed in from user mode. This should not
  * be used for syscall parameters, just declare them
  * as pointers because the syscall entry code will have
- * appropriately comverted them already.
+ * appropriately converted them already.
  */
 typedef        u32             compat_uptr_t;
 
index f628ac7de83dca17868b3737732b00c61354f62a..8e7946a141def9d1dfcd74ad6ffb5a73bd135554 100644 (file)
@@ -28,7 +28,7 @@
 #define EFA_PARISC_1_1             0x0210 /* PA-RISC 1.1 big-endian.  */
 #define EFA_PARISC_2_0             0x0214 /* PA-RISC 2.0 big-endian.  */
 
-/* Additional section indeces.  */
+/* Additional section indices.  */
 
 #define SHN_PARISC_ANSI_COMMON 0xff00     /* Section for tenatively declared
                                              symbols in ANSI C.  */
index ad8cd0d069eabd1a69fd6b802028950067b2e05e..0b19a7242d0c1237a1f0f9a079043149b0b8b7df 100644 (file)
@@ -8,7 +8,7 @@
 
 /*
  * In parisc assembly a semicolon marks a comment while a
- * exclamation mark is used to seperate independent lines.
+ * exclamation mark is used to separate independent lines.
  */
 #ifdef __ASSEMBLY__
 
index 1af1a41e07233fa52e6d5da67afceecaf1d69301..aab66f1bea14d67c3381d39ba6bd0d15550467b7 100644 (file)
@@ -43,7 +43,7 @@ static inline pgd_t *pgd_alloc(struct mm_struct *mm)
        return actual_pgd;
 }
 
-static inline void pgd_free(pgd_t *pgd)
+static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd)
 {
 #ifdef CONFIG_64BIT
        pgd -= PTRS_PER_PGD;
@@ -70,7 +70,7 @@ static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long address)
        return pmd;
 }
 
-static inline void pmd_free(pmd_t *pmd)
+static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd)
 {
 #ifdef CONFIG_64BIT
        if(pmd_flag(*pmd) & PxD_FLAG_ATTACHED)
@@ -91,7 +91,7 @@ static inline void pmd_free(pmd_t *pmd)
  */
 
 #define pmd_alloc_one(mm, addr)                ({ BUG(); ((pmd_t *)2); })
-#define pmd_free(x)                    do { } while (0)
+#define pmd_free(mm, x)                        do { } while (0)
 #define pgd_populate(mm, pmd, pte)     BUG()
 
 #endif
@@ -130,12 +130,12 @@ pte_alloc_one_kernel(struct mm_struct *mm, unsigned long addr)
        return pte;
 }
 
-static inline void pte_free_kernel(pte_t *pte)
+static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte)
 {
        free_page((unsigned long)pte);
 }
 
-#define pte_free(page) pte_free_kernel(page_address(page))
+#define pte_free(mm, page) pte_free_kernel(page_address(page))
 
 #define check_pgt_cache()      do { } while (0)
 
index 6b294fb07a23d6aa9018599f46c80731abb4bb58..3bb06e898fdef5f0ad27d66a7144ed2e945c6d06 100644 (file)
@@ -32,7 +32,8 @@
 #endif
 #define current_text_addr() ({ void *pc; current_ia(pc); pc; })
 
-#define TASK_SIZE               (current->thread.task_size)
+#define TASK_SIZE_OF(tsk)       ((tsk)->thread.task_size)
+#define TASK_SIZE              TASK_SIZE_OF(current)
 #define TASK_UNMAPPED_BASE      (current->thread.map_base)
 
 #define DEFAULT_TASK_SIZE32    (0xFFF00000UL)
index 99e868f6a8f52fa5e13082c62306a61c53e96186..69a7a0d30b025335f927979f1eb14e7750d3c09a 100644 (file)
@@ -52,4 +52,6 @@
 #define SO_PEERSEC             0x401d
 #define SO_PASSSEC             0x401e
 
+#define SO_MARK                        0x401f
+
 #endif /* _ASM_SOCKET_H */
index 33107a248e1f76b991129adeaa30d69bcd4d4f1d..383b1db310ee71e18789112587f9ba3e818bdd25 100644 (file)
@@ -21,7 +21,7 @@ do {  if (!(tlb)->fullmm)     \
 
 #include <asm-generic/tlb.h>
 
-#define __pmd_free_tlb(tlb, pmd)       pmd_free(pmd)
-#define __pte_free_tlb(tlb, pte)       pte_free(pte)
+#define __pmd_free_tlb(tlb, pmd)       pmd_free((tlb)->mm, pmd)
+#define __pte_free_tlb(tlb, pte)       pte_free((tlb)->mm, pte)
 
 #endif
index 154a84c843a749b459e05151079c2d431acda324..171399a88ca6aa175778c7bb3d727fd5c8cc7147 100644 (file)
@@ -3,4 +3,4 @@
 
 /* nothing */
 
-#endif __ASM_PARISC_VGA_H__
+#endif /* __ASM_PARISC_VGA_H__ */
index 64ab1ddbdf85c5d2cba8ca73750b873b43040a4d..d811a8cd7b58c9397200be83cf0ee333c313e037 100644 (file)
@@ -119,7 +119,7 @@ typedef u32         compat_sigset_word;
  * A pointer passed in from user mode. This should not
  * be used for syscall parameters, just declare them
  * as pointers because the syscall entry code will have
- * appropriately comverted them already.
+ * appropriately converted them already.
  */
 typedef        u32             compat_uptr_t;
 
index 528ef183c221d522f41f92e47cf572dda50e0c91..1e79673b7316f58003cec08bfee11ed45ad96f2a 100644 (file)
@@ -46,7 +46,7 @@ enum powerpc_oprofile_type {
        PPC_OPROFILE_RS64 = 1,
        PPC_OPROFILE_POWER4 = 2,
        PPC_OPROFILE_G4 = 3,
-       PPC_OPROFILE_BOOKE = 4,
+       PPC_OPROFILE_FSL_EMB = 4,
        PPC_OPROFILE_CELL = 5,
        PPC_OPROFILE_PA6T = 6,
 };
index 7a3cef785abdee2aa52b2cdc6716bdf04348b291..852e15f51a1e85f68260f31c2ad737d0b8eb35ad 100644 (file)
@@ -79,19 +79,19 @@ extern void iommu_free_table(struct iommu_table *tbl, const char *node_name);
 extern struct iommu_table *iommu_init_table(struct iommu_table * tbl,
                                            int nid);
 
-extern int iommu_map_sg(struct iommu_table *tbl, struct scatterlist *sglist,
+extern int iommu_map_sg(struct device *dev, struct scatterlist *sglist,
                        int nelems, unsigned long mask,
                        enum dma_data_direction direction);
 extern void iommu_unmap_sg(struct iommu_table *tbl, struct scatterlist *sglist,
                           int nelems, enum dma_data_direction direction);
 
-extern void *iommu_alloc_coherent(struct iommu_table *tbl, size_t size,
-                                 dma_addr_t *dma_handle, unsigned long mask,
-                                 gfp_t flag, int node);
+extern void *iommu_alloc_coherent(struct device *dev, struct iommu_table *tbl,
+                                 size_t size, dma_addr_t *dma_handle,
+                                 unsigned long mask, gfp_t flag, int node);
 extern void iommu_free_coherent(struct iommu_table *tbl, size_t size,
                                void *vaddr, dma_addr_t dma_handle);
-extern dma_addr_t iommu_map_single(struct iommu_table *tbl, void *vaddr,
-                                  size_t size, unsigned long mask,
+extern dma_addr_t iommu_map_single(struct device *dev, struct iommu_table *tbl,
+                                  void *vaddr, size_t size, unsigned long mask,
                                   enum dma_data_direction direction);
 extern void iommu_unmap_single(struct iommu_table *tbl, dma_addr_t dma_handle,
                               size_t size, enum dma_data_direction direction);
index 9daa3252d7b6a42dd5fbbb22f6ba80c89ae76d03..de83fe196309143d4cab3a7e42c9a06b034613ad 100644 (file)
 #define MB_NO          7       /* media bay contains nothing */
 
 int check_media_bay(struct device_node *which_bay, int what);
-int check_media_bay_by_base(unsigned long base, int what);
 
 /* Number of bays in the machine or 0 */
 extern int media_bay_count;
 
-/* called by pmac-ide.c to register IDE controller for media bay */
-extern int media_bay_set_ide_infos(struct device_node* which_bay,
-                       unsigned long base, int irq, int index);
+int check_media_bay_by_base(unsigned long base, int what);
+/* called by IDE PMAC host driver to register IDE controller for media bay */
+int media_bay_set_ide_infos(struct device_node *which_bay, unsigned long base,
+                           int irq, int index);
 
 #endif /* __KERNEL__ */
 #endif /* _PPC_MEDIABAY_H */
index 4e7059cc6113f054fbaf8de634c2a9c05f785062..efde5ac82f7b915df030d42cae81c38fc63803fe 100644 (file)
@@ -58,6 +58,9 @@ struct nvram_header {
 };
 
 #ifdef __KERNEL__
+
+#include <linux/list.h>
+
 struct nvram_partition {
        struct list_head partition;
        struct nvram_header header;
index 938fefb4c4bca07d6873829d6fceda73f9742496..95035c602ba625b505738d81e0b957a417ce048a 100644 (file)
@@ -54,7 +54,7 @@ struct op_powerpc_model {
        int num_counters;
 };
 
-extern struct op_powerpc_model op_model_fsl_booke;
+extern struct op_powerpc_model op_model_fsl_emb;
 extern struct op_powerpc_model op_model_rs64;
 extern struct op_powerpc_model op_model_power4;
 extern struct op_powerpc_model op_model_7450;
index cc1cbf656b02f343e60199c79ec50fb26cb53665..ccb0523eb3b47d32192ef4f00304e3000691f8e5 100644 (file)
 #include <asm/paca.h>
 
 #define __per_cpu_offset(cpu) (paca[cpu].data_offset)
-#define __my_cpu_offset() get_paca()->data_offset
+#define __my_cpu_offset get_paca()->data_offset
 #define per_cpu_offset(x) (__per_cpu_offset(x))
 
-/* var is in discarded region: offset to particular copy we want */
-#define per_cpu(var, cpu) (*RELOC_HIDE(&per_cpu__##var, __per_cpu_offset(cpu)))
-#define __get_cpu_var(var) (*RELOC_HIDE(&per_cpu__##var, __my_cpu_offset()))
-#define __raw_get_cpu_var(var) (*RELOC_HIDE(&per_cpu__##var, local_paca->data_offset))
+#endif /* CONFIG_SMP */
+#endif /* __powerpc64__ */
 
-/* A macro to avoid #include hell... */
-#define percpu_modcopy(pcpudst, src, size)                     \
-do {                                                           \
-       unsigned int __i;                                       \
-       for_each_possible_cpu(__i)                              \
-               memcpy((pcpudst)+__per_cpu_offset(__i),         \
-                      (src), (size));                          \
-} while (0)
-
-extern void setup_per_cpu_areas(void);
-
-#else /* ! SMP */
-
-#define per_cpu(var, cpu)                      (*((void)(cpu), &per_cpu__##var))
-#define __get_cpu_var(var)                     per_cpu__##var
-#define __raw_get_cpu_var(var)                 per_cpu__##var
-
-#endif /* SMP */
-
-#define DECLARE_PER_CPU(type, name) extern __typeof__(type) per_cpu__##name
-
-#else
 #include <asm-generic/percpu.h>
-#endif
 
 #endif /* _ASM_POWERPC_PERCPU_H_ */
index e1307432163c4cd1444e924b18f29fd02b0a8f91..c162a4c37b39ce5df12573c209dfd3a1edbdd59b 100644 (file)
@@ -6,14 +6,14 @@
 extern void __bad_pte(pmd_t *pmd);
 
 extern pgd_t *pgd_alloc(struct mm_struct *mm);
-extern void pgd_free(pgd_t *pgd);
+extern void pgd_free(struct mm_struct *mm, pgd_t *pgd);
 
 /*
  * We don't have any real pmd's, and this code never triggers because
  * the pgd will always be present..
  */
 /* #define pmd_alloc_one(mm,address)       ({ BUG(); ((pmd_t *)2); }) */
-#define pmd_free(x)                     do { } while (0)
+#define pmd_free(mm, x)                do { } while (0)
 #define __pmd_free_tlb(tlb,x)          do { } while (0)
 /* #define pgd_populate(mm, pmd, pte)      BUG() */
 
@@ -31,10 +31,10 @@ extern void pgd_free(pgd_t *pgd);
 
 extern pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long addr);
 extern struct page *pte_alloc_one(struct mm_struct *mm, unsigned long addr);
-extern void pte_free_kernel(pte_t *pte);
-extern void pte_free(struct page *pte);
+extern void pte_free_kernel(struct mm_struct *mm, pte_t *pte);
+extern void pte_free(struct mm_struct *mm, struct page *pte);
 
-#define __pte_free_tlb(tlb, pte)       pte_free((pte))
+#define __pte_free_tlb(tlb, pte)       pte_free((tlb)->mm, (pte))
 
 #define check_pgt_cache()      do { } while (0)
 
index 43214c8085b7f36cdf44a205e8c5fac8a3aad7b1..5afae8593931e5cf4966688307488adfc856a38b 100644 (file)
@@ -29,7 +29,7 @@ static inline pgd_t *pgd_alloc(struct mm_struct *mm)
        return kmem_cache_alloc(pgtable_cache[PGD_CACHE_NUM], GFP_KERNEL);
 }
 
-static inline void pgd_free(pgd_t *pgd)
+static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd)
 {
        subpage_prot_free(pgd);
        kmem_cache_free(pgtable_cache[PGD_CACHE_NUM], pgd);
@@ -45,7 +45,7 @@ static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long addr)
                                GFP_KERNEL|__GFP_REPEAT);
 }
 
-static inline void pud_free(pud_t *pud)
+static inline void pud_free(struct mm_struct *mm, pud_t *pud)
 {
        kmem_cache_free(pgtable_cache[PUD_CACHE_NUM], pud);
 }
@@ -81,7 +81,7 @@ static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long addr)
                                GFP_KERNEL|__GFP_REPEAT);
 }
 
-static inline void pmd_free(pmd_t *pmd)
+static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd)
 {
        kmem_cache_free(pgtable_cache[PMD_CACHE_NUM], pmd);
 }
@@ -99,12 +99,12 @@ static inline struct page *pte_alloc_one(struct mm_struct *mm,
        return pte ? virt_to_page(pte) : NULL;
 }
 
-static inline void pte_free_kernel(pte_t *pte)
+static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte)
 {
        free_page((unsigned long)pte);
 }
 
-static inline void pte_free(struct page *ptepage)
+static inline void pte_free(struct mm_struct *mm, struct page *ptepage)
 {
        __free_page(ptepage);
 }
index dba7c948189db065a0862bcfa8c438f236a15ada..1f4765d6546fe0313b6bbc150ff38b509d6811ba 100644 (file)
@@ -99,8 +99,9 @@ extern struct task_struct *last_task_used_spe;
  */
 #define TASK_SIZE_USER32 (0x0000000100000000UL - (1*PAGE_SIZE))
 
-#define TASK_SIZE (test_thread_flag(TIF_32BIT) ? \
+#define TASK_SIZE_OF(tsk) (test_tsk_thread_flag(tsk, TIF_32BIT) ? \
                TASK_SIZE_USER32 : TASK_SIZE_USER64)
+#define TASK_SIZE        TASK_SIZE_OF(current)
 
 /* This decides where the kernel will search for a free chunk of vm
  * space during mmap's.
index 2408a29507e599fd457a45369fe688e4499e1147..0d6238987df864f9b7f2d4f1cff8a6b7fade4fda 100644 (file)
 #include <asm/reg_booke.h>
 #endif /* CONFIG_BOOKE || CONFIG_40x */
 
+#ifdef CONFIG_FSL_EMB_PERFMON
+#include <asm/reg_fsl_emb.h>
+#endif
+
 #ifdef CONFIG_8xx
 #include <asm/reg_8xx.h>
 #endif /* CONFIG_8xx */
index 0405ef479814f10455236b08956d833d21c6da77..cf54a3f31753895d44e32b18decd248c4380deb2 100644 (file)
@@ -9,68 +9,6 @@
 #ifndef __ASM_POWERPC_REG_BOOKE_H__
 #define __ASM_POWERPC_REG_BOOKE_H__
 
-#ifndef __ASSEMBLY__
-/* Performance Monitor Registers */
-#define mfpmr(rn)      ({unsigned int rval; \
-                       asm volatile("mfpmr %0," __stringify(rn) \
-                                    : "=r" (rval)); rval;})
-#define mtpmr(rn, v)   asm volatile("mtpmr " __stringify(rn) ",%0" : : "r" (v))
-#endif /* __ASSEMBLY__ */
-
-/* Freescale Book E Performance Monitor APU Registers */
-#define PMRN_PMC0      0x010   /* Performance Monitor Counter 0 */
-#define PMRN_PMC1      0x011   /* Performance Monitor Counter 1 */
-#define PMRN_PMC2      0x012   /* Performance Monitor Counter 1 */
-#define PMRN_PMC3      0x013   /* Performance Monitor Counter 1 */
-#define PMRN_PMLCA0    0x090   /* PM Local Control A0 */
-#define PMRN_PMLCA1    0x091   /* PM Local Control A1 */
-#define PMRN_PMLCA2    0x092   /* PM Local Control A2 */
-#define PMRN_PMLCA3    0x093   /* PM Local Control A3 */
-
-#define PMLCA_FC       0x80000000      /* Freeze Counter */
-#define PMLCA_FCS      0x40000000      /* Freeze in Supervisor */
-#define PMLCA_FCU      0x20000000      /* Freeze in User */
-#define PMLCA_FCM1     0x10000000      /* Freeze when PMM==1 */
-#define PMLCA_FCM0     0x08000000      /* Freeze when PMM==0 */
-#define PMLCA_CE       0x04000000      /* Condition Enable */
-
-#define PMLCA_EVENT_MASK 0x007f0000    /* Event field */
-#define PMLCA_EVENT_SHIFT      16
-
-#define PMRN_PMLCB0    0x110   /* PM Local Control B0 */
-#define PMRN_PMLCB1    0x111   /* PM Local Control B1 */
-#define PMRN_PMLCB2    0x112   /* PM Local Control B2 */
-#define PMRN_PMLCB3    0x113   /* PM Local Control B3 */
-
-#define PMLCB_THRESHMUL_MASK   0x0700  /* Threshhold Multiple Field */
-#define PMLCB_THRESHMUL_SHIFT  8
-
-#define PMLCB_THRESHOLD_MASK   0x003f  /* Threshold Field */
-#define PMLCB_THRESHOLD_SHIFT  0
-
-#define PMRN_PMGC0     0x190   /* PM Global Control 0 */
-
-#define PMGC0_FAC      0x80000000      /* Freeze all Counters */
-#define PMGC0_PMIE     0x40000000      /* Interrupt Enable */
-#define PMGC0_FCECE    0x20000000      /* Freeze countes on
-                                          Enabled Condition or
-                                          Event */
-
-#define PMRN_UPMC0     0x000   /* User Performance Monitor Counter 0 */
-#define PMRN_UPMC1     0x001   /* User Performance Monitor Counter 1 */
-#define PMRN_UPMC2     0x002   /* User Performance Monitor Counter 1 */
-#define PMRN_UPMC3     0x003   /* User Performance Monitor Counter 1 */
-#define PMRN_UPMLCA0   0x080   /* User PM Local Control A0 */
-#define PMRN_UPMLCA1   0x081   /* User PM Local Control A1 */
-#define PMRN_UPMLCA2   0x082   /* User PM Local Control A2 */
-#define PMRN_UPMLCA3   0x083   /* User PM Local Control A3 */
-#define PMRN_UPMLCB0   0x100   /* User PM Local Control B0 */
-#define PMRN_UPMLCB1   0x101   /* User PM Local Control B1 */
-#define PMRN_UPMLCB2   0x102   /* User PM Local Control B2 */
-#define PMRN_UPMLCB3   0x103   /* User PM Local Control B3 */
-#define PMRN_UPMGC0    0x180   /* User PM Global Control 0 */
-
-
 /* Machine State Register (MSR) Fields */
 #define MSR_UCLE       (1<<26) /* User-mode cache lock enable */
 #define MSR_SPE                (1<<25) /* Enable SPE */
diff --git a/include/asm-powerpc/reg_fsl_emb.h b/include/asm-powerpc/reg_fsl_emb.h
new file mode 100644 (file)
index 0000000..1e180a5
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * Contains register definitions for the Freescale Embedded Performance
+ * Monitor.
+ */
+#ifdef __KERNEL__
+#ifndef __ASM_POWERPC_REG_FSL_EMB_H__
+#define __ASM_POWERPC_REG_FSL_EMB_H__
+
+#ifndef __ASSEMBLY__
+/* Performance Monitor Registers */
+#define mfpmr(rn)      ({unsigned int rval; \
+                       asm volatile("mfpmr %0," __stringify(rn) \
+                                    : "=r" (rval)); rval;})
+#define mtpmr(rn, v)   asm volatile("mtpmr " __stringify(rn) ",%0" : : "r" (v))
+#endif /* __ASSEMBLY__ */
+
+/* Freescale Book E Performance Monitor APU Registers */
+#define PMRN_PMC0      0x010   /* Performance Monitor Counter 0 */
+#define PMRN_PMC1      0x011   /* Performance Monitor Counter 1 */
+#define PMRN_PMC2      0x012   /* Performance Monitor Counter 1 */
+#define PMRN_PMC3      0x013   /* Performance Monitor Counter 1 */
+#define PMRN_PMLCA0    0x090   /* PM Local Control A0 */
+#define PMRN_PMLCA1    0x091   /* PM Local Control A1 */
+#define PMRN_PMLCA2    0x092   /* PM Local Control A2 */
+#define PMRN_PMLCA3    0x093   /* PM Local Control A3 */
+
+#define PMLCA_FC       0x80000000      /* Freeze Counter */
+#define PMLCA_FCS      0x40000000      /* Freeze in Supervisor */
+#define PMLCA_FCU      0x20000000      /* Freeze in User */
+#define PMLCA_FCM1     0x10000000      /* Freeze when PMM==1 */
+#define PMLCA_FCM0     0x08000000      /* Freeze when PMM==0 */
+#define PMLCA_CE       0x04000000      /* Condition Enable */
+
+#define PMLCA_EVENT_MASK 0x007f0000    /* Event field */
+#define PMLCA_EVENT_SHIFT      16
+
+#define PMRN_PMLCB0    0x110   /* PM Local Control B0 */
+#define PMRN_PMLCB1    0x111   /* PM Local Control B1 */
+#define PMRN_PMLCB2    0x112   /* PM Local Control B2 */
+#define PMRN_PMLCB3    0x113   /* PM Local Control B3 */
+
+#define PMLCB_THRESHMUL_MASK   0x0700  /* Threshhold Multiple Field */
+#define PMLCB_THRESHMUL_SHIFT  8
+
+#define PMLCB_THRESHOLD_MASK   0x003f  /* Threshold Field */
+#define PMLCB_THRESHOLD_SHIFT  0
+
+#define PMRN_PMGC0     0x190   /* PM Global Control 0 */
+
+#define PMGC0_FAC      0x80000000      /* Freeze all Counters */
+#define PMGC0_PMIE     0x40000000      /* Interrupt Enable */
+#define PMGC0_FCECE    0x20000000      /* Freeze countes on
+                                          Enabled Condition or
+                                          Event */
+
+#define PMRN_UPMC0     0x000   /* User Performance Monitor Counter 0 */
+#define PMRN_UPMC1     0x001   /* User Performance Monitor Counter 1 */
+#define PMRN_UPMC2     0x002   /* User Performance Monitor Counter 1 */
+#define PMRN_UPMC3     0x003   /* User Performance Monitor Counter 1 */
+#define PMRN_UPMLCA0   0x080   /* User PM Local Control A0 */
+#define PMRN_UPMLCA1   0x081   /* User PM Local Control A1 */
+#define PMRN_UPMLCA2   0x082   /* User PM Local Control A2 */
+#define PMRN_UPMLCA3   0x083   /* User PM Local Control A3 */
+#define PMRN_UPMLCB0   0x100   /* User PM Local Control B0 */
+#define PMRN_UPMLCB1   0x101   /* User PM Local Control B1 */
+#define PMRN_UPMLCB2   0x102   /* User PM Local Control B2 */
+#define PMRN_UPMLCB3   0x103   /* User PM Local Control B3 */
+#define PMRN_UPMGC0    0x180   /* User PM Global Control 0 */
+
+
+#endif /* __ASM_POWERPC_REG_FSL_EMB_H__ */
+#endif /* __KERNEL__ */
index 403e9fde2eb52eea67537b823bfe9f33925a6042..f5a4e168e498b6641c3c1ea3b0afac640a233015 100644 (file)
@@ -59,4 +59,6 @@
 #define SO_TIMESTAMPNS         35
 #define SCM_TIMESTAMPNS                SO_TIMESTAMPNS
 
+#define SO_MARK                        36
+
 #endif /* _ASM_POWERPC_SOCKET_H */
index 0c8b0d6791399aa45605e0b3024f97f0511d649c..e996521fb3a686d09f128db627e2bd1d370428b9 100644 (file)
@@ -309,7 +309,7 @@ SYSCALL_SPU(getcpu)
 COMPAT_SYS(epoll_pwait)
 COMPAT_SYS_SPU(utimensat)
 COMPAT_SYS_SPU(signalfd)
-COMPAT_SYS_SPU(timerfd)
+SYSCALL(ni_syscall)
 SYSCALL_SPU(eventfd)
 COMPAT_SYS_SPU(sync_file_range2)
 COMPAT_SYS(fallocate)
index 9204c15839c57a01e6fe31720ead644705a08069..56512a968dab9075666ac15a9437bd3c1a25529c 100644 (file)
@@ -66,7 +66,7 @@ extern void __devinit vio_unregister_device(struct vio_dev *dev);
 
 struct device_node;
 
-extern struct vio_dev * __devinit vio_register_device_node(
+extern struct vio_dev *vio_register_device_node(
                struct device_node *node_vdev);
 extern const void *vio_get_attribute(struct vio_dev *vdev, char *which,
                int *length);
index 44d88a98e87ca8a57d0f6a90cae48bd93c193822..7c39a95829c7263932cf445fe94200c050991df4 100644 (file)
@@ -7,14 +7,14 @@
 extern void __bad_pte(pmd_t *pmd);
 
 extern pgd_t *pgd_alloc(struct mm_struct *mm);
-extern void pgd_free(pgd_t *pgd);
+extern void pgd_free(struct mm_struct *mm, pgd_t *pgd);
 
 /*
  * We don't have any real pmd's, and this code never triggers because
  * the pgd will always be present..
  */
 #define pmd_alloc_one(mm,address)       ({ BUG(); ((pmd_t *)2); })
-#define pmd_free(x)                     do { } while (0)
+#define pmd_free(mm, x)                do { } while (0)
 #define __pmd_free_tlb(tlb,x)          do { } while (0)
 #define pgd_populate(mm, pmd, pte)      BUG()
 
@@ -32,10 +32,10 @@ extern void pgd_free(pgd_t *pgd);
 
 extern pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long addr);
 extern struct page *pte_alloc_one(struct mm_struct *mm, unsigned long addr);
-extern void pte_free_kernel(pte_t *pte);
-extern void pte_free(struct page *pte);
+extern void pte_free_kernel(struct mm_struct *mm, pte_t *pte);
+extern void pte_free(struct mm_struct *mm, struct page *pte);
 
-#define __pte_free_tlb(tlb, pte)       pte_free((pte))
+#define __pte_free_tlb(tlb, pte)       pte_free((tlb)->mm, (pte))
 
 #define check_pgt_cache()      do { } while (0)
 
index dba6fecad0be25353c535ddc1ac3feb64341dbcd..882db054110cbe9f8c7487e6dfe89cdc0647776e 100644 (file)
@@ -440,242 +440,256 @@ __constant_test_bit(unsigned long nr, const volatile unsigned long *addr) {
  __test_bit((nr),(addr)) )
 
 /*
- * ffz = Find First Zero in word. Undefined if no zero exists,
- * so code should check against ~0UL first..
+ * Optimized find bit helper functions.
  */
-static inline unsigned long ffz(unsigned long word)
+
+/**
+ * __ffz_word_loop - find byte offset of first long != -1UL
+ * @addr: pointer to array of unsigned long
+ * @size: size of the array in bits
+ */
+static inline unsigned long __ffz_word_loop(const unsigned long *addr,
+                                           unsigned long size)
 {
-        unsigned long bit = 0;
+       typedef struct { long _[__BITOPS_WORDS(size)]; } addrtype;
+       unsigned long bytes = 0;
 
+       asm volatile(
+#ifndef __s390x__
+               "       ahi     %1,31\n"
+               "       srl     %1,5\n"
+               "0:     c       %2,0(%0,%3)\n"
+               "       jne     1f\n"
+               "       la      %0,4(%0)\n"
+               "       brct    %1,0b\n"
+               "1:\n"
+#else
+               "       aghi    %1,63\n"
+               "       srlg    %1,%1,6\n"
+               "0:     cg      %2,0(%0,%3)\n"
+               "       jne     1f\n"
+               "       la      %0,8(%0)\n"
+               "       brct    %1,0b\n"
+               "1:\n"
+#endif
+               : "+a" (bytes), "+d" (size)
+               : "d" (-1UL), "a" (addr), "m" (*(addrtype *) addr)
+               : "cc" );
+       return bytes;
+}
+
+/**
+ * __ffs_word_loop - find byte offset of first long != 0UL
+ * @addr: pointer to array of unsigned long
+ * @size: size of the array in bits
+ */
+static inline unsigned long __ffs_word_loop(const unsigned long *addr,
+                                           unsigned long size)
+{
+       typedef struct { long _[__BITOPS_WORDS(size)]; } addrtype;
+       unsigned long bytes = 0;
+
+       asm volatile(
+#ifndef __s390x__
+               "       ahi     %1,31\n"
+               "       srl     %1,5\n"
+               "0:     c       %2,0(%0,%3)\n"
+               "       jne     1f\n"
+               "       la      %0,4(%0)\n"
+               "       brct    %1,0b\n"
+               "1:\n"
+#else
+               "       aghi    %1,63\n"
+               "       srlg    %1,%1,6\n"
+               "0:     cg      %2,0(%0,%3)\n"
+               "       jne     1f\n"
+               "       la      %0,8(%0)\n"
+               "       brct    %1,0b\n"
+               "1:\n"
+#endif
+               : "+a" (bytes), "+a" (size)
+               : "d" (0UL), "a" (addr), "m" (*(addrtype *) addr)
+               : "cc" );
+       return bytes;
+}
+
+/**
+ * __ffz_word - add number of the first unset bit
+ * @nr: base value the bit number is added to
+ * @word: the word that is searched for unset bits
+ */
+static inline unsigned long __ffz_word(unsigned long nr, unsigned long word)
+{
 #ifdef __s390x__
        if (likely((word & 0xffffffff) == 0xffffffff)) {
                word >>= 32;
-               bit += 32;
+               nr += 32;
        }
 #endif
        if (likely((word & 0xffff) == 0xffff)) {
                word >>= 16;
-               bit += 16;
+               nr += 16;
        }
        if (likely((word & 0xff) == 0xff)) {
                word >>= 8;
-               bit += 8;
+               nr += 8;
        }
-       return bit + _zb_findmap[word & 0xff];
+       return nr + _zb_findmap[(unsigned char) word];
 }
 
-/*
- * __ffs = find first bit in word. Undefined if no bit exists,
- * so code should check against 0UL first..
+/**
+ * __ffs_word - add number of the first set bit
+ * @nr: base value the bit number is added to
+ * @word: the word that is searched for set bits
  */
-static inline unsigned long __ffs (unsigned long word)
+static inline unsigned long __ffs_word(unsigned long nr, unsigned long word)
 {
-       unsigned long bit = 0;
-
 #ifdef __s390x__
        if (likely((word & 0xffffffff) == 0)) {
                word >>= 32;
-               bit += 32;
+               nr += 32;
        }
 #endif
        if (likely((word & 0xffff) == 0)) {
                word >>= 16;
-               bit += 16;
+               nr += 16;
        }
        if (likely((word & 0xff) == 0)) {
                word >>= 8;
-               bit += 8;
+               nr += 8;
        }
-       return bit + _sb_findmap[word & 0xff];
+       return nr + _sb_findmap[(unsigned char) word];
 }
 
-/*
- * Find-bit routines..
- */
 
-#ifndef __s390x__
+/**
+ * __load_ulong_be - load big endian unsigned long
+ * @p: pointer to array of unsigned long
+ * @offset: byte offset of source value in the array
+ */
+static inline unsigned long __load_ulong_be(const unsigned long *p,
+                                           unsigned long offset)
+{
+       p = (unsigned long *)((unsigned long) p + offset);
+       return *p;
+}
 
-static inline int
-find_first_zero_bit(const unsigned long * addr, unsigned long size)
+/**
+ * __load_ulong_le - load little endian unsigned long
+ * @p: pointer to array of unsigned long
+ * @offset: byte offset of source value in the array
+ */
+static inline unsigned long __load_ulong_le(const unsigned long *p,
+                                           unsigned long offset)
 {
-       typedef struct { long _[__BITOPS_WORDS(size)]; } addrtype;
-       unsigned long cmp, count;
-        unsigned int res;
+       unsigned long word;
 
-        if (!size)
-                return 0;
+       p = (unsigned long *)((unsigned long) p + offset);
+#ifndef __s390x__
        asm volatile(
-               "       lhi     %1,-1\n"
-               "       lr      %2,%3\n"
-               "       slr     %0,%0\n"
-               "       ahi     %2,31\n"
-               "       srl     %2,5\n"
-               "0:     c       %1,0(%0,%4)\n"
-               "       jne     1f\n"
-               "       la      %0,4(%0)\n"
-               "       brct    %2,0b\n"
-               "       lr      %0,%3\n"
-               "       j       4f\n"
-               "1:     l       %2,0(%0,%4)\n"
-               "       sll     %0,3\n"
-               "       lhi     %1,0xff\n"
-               "       tml     %2,0xffff\n"
-               "       jno     2f\n"
-               "       ahi     %0,16\n"
-               "       srl     %2,16\n"
-               "2:     tml     %2,0x00ff\n"
-               "       jno     3f\n"
-               "       ahi     %0,8\n"
-               "       srl     %2,8\n"
-               "3:     nr      %2,%1\n"
-               "       ic      %2,0(%2,%5)\n"
-               "       alr     %0,%2\n"
-               "4:"
-               : "=&a" (res), "=&d" (cmp), "=&a" (count)
-               : "a" (size), "a" (addr), "a" (&_zb_findmap),
-                 "m" (*(addrtype *) addr) : "cc");
-        return (res < size) ? res : size;
+               "       ic      %0,0(%1)\n"
+               "       icm     %0,2,1(%1)\n"
+               "       icm     %0,4,2(%1)\n"
+               "       icm     %0,8,3(%1)"
+               : "=&d" (word) : "a" (p), "m" (*p) : "cc");
+#else
+       asm volatile(
+               "       lrvg    %0,%1"
+               : "=d" (word) : "m" (*p) );
+#endif
+       return word;
 }
 
-static inline int
-find_first_bit(const unsigned long * addr, unsigned long size)
+/*
+ * The various find bit functions.
+ */
+
+/*
+ * ffz - find first zero in word.
+ * @word: The word to search
+ *
+ * Undefined if no zero exists, so code should check against ~0UL first.
+ */
+static inline unsigned long ffz(unsigned long word)
 {
-       typedef struct { long _[__BITOPS_WORDS(size)]; } addrtype;
-       unsigned long cmp, count;
-        unsigned int res;
+       return __ffz_word(0, word);
+}
 
-        if (!size)
-                return 0;
-       asm volatile(
-               "       slr     %1,%1\n"
-               "       lr      %2,%3\n"
-               "       slr     %0,%0\n"
-               "       ahi     %2,31\n"
-               "       srl     %2,5\n"
-               "0:     c       %1,0(%0,%4)\n"
-               "       jne     1f\n"
-               "       la      %0,4(%0)\n"
-               "       brct    %2,0b\n"
-               "       lr      %0,%3\n"
-               "       j       4f\n"
-               "1:     l       %2,0(%0,%4)\n"
-               "       sll     %0,3\n"
-               "       lhi     %1,0xff\n"
-               "       tml     %2,0xffff\n"
-               "       jnz     2f\n"
-               "       ahi     %0,16\n"
-               "       srl     %2,16\n"
-               "2:     tml     %2,0x00ff\n"
-               "       jnz     3f\n"
-               "       ahi     %0,8\n"
-               "       srl     %2,8\n"
-               "3:     nr      %2,%1\n"
-               "       ic      %2,0(%2,%5)\n"
-               "       alr     %0,%2\n"
-               "4:"
-               : "=&a" (res), "=&d" (cmp), "=&a" (count)
-               : "a" (size), "a" (addr), "a" (&_sb_findmap),
-                 "m" (*(addrtype *) addr) : "cc");
-        return (res < size) ? res : size;
+/**
+ * __ffs - find first bit in word.
+ * @word: The word to search
+ *
+ * Undefined if no bit exists, so code should check against 0 first.
+ */
+static inline unsigned long __ffs (unsigned long word)
+{
+       return __ffs_word(0, word);
 }
 
-#else /* __s390x__ */
+/**
+ * ffs - find first bit set
+ * @x: the word to search
+ *
+ * This is defined the same way as
+ * the libc and compiler builtin ffs routines, therefore
+ * differs in spirit from the above ffz (man ffs).
+ */
+static inline int ffs(int x)
+{
+       if (!x)
+               return 0;
+       return __ffs_word(1, x);
+}
 
-static inline unsigned long
-find_first_zero_bit(const unsigned long * addr, unsigned long size)
+/**
+ * find_first_zero_bit - find the first zero bit in a memory region
+ * @addr: The address to start the search at
+ * @size: The maximum size to search
+ *
+ * Returns the bit-number of the first zero bit, not the number of the byte
+ * containing a bit.
+ */
+static inline unsigned long find_first_zero_bit(const unsigned long *addr,
+                                               unsigned long size)
 {
-       typedef struct { long _[__BITOPS_WORDS(size)]; } addrtype;
-        unsigned long res, cmp, count;
+       unsigned long bytes, bits;
 
         if (!size)
                 return 0;
-       asm volatile(
-               "       lghi    %1,-1\n"
-               "       lgr     %2,%3\n"
-               "       slgr    %0,%0\n"
-               "       aghi    %2,63\n"
-               "       srlg    %2,%2,6\n"
-               "0:     cg      %1,0(%0,%4)\n"
-               "       jne     1f\n"
-               "       la      %0,8(%0)\n"
-               "       brct    %2,0b\n"
-               "       lgr     %0,%3\n"
-               "       j       5f\n"
-               "1:     lg      %2,0(%0,%4)\n"
-               "       sllg    %0,%0,3\n"
-               "       clr     %2,%1\n"
-               "       jne     2f\n"
-               "       aghi    %0,32\n"
-               "       srlg    %2,%2,32\n"
-               "2:     lghi    %1,0xff\n"
-               "       tmll    %2,0xffff\n"
-               "       jno     3f\n"
-               "       aghi    %0,16\n"
-               "       srl     %2,16\n"
-               "3:     tmll    %2,0x00ff\n"
-               "       jno     4f\n"
-               "       aghi    %0,8\n"
-               "       srl     %2,8\n"
-               "4:     ngr     %2,%1\n"
-               "       ic      %2,0(%2,%5)\n"
-               "       algr    %0,%2\n"
-               "5:"
-               : "=&a" (res), "=&d" (cmp), "=&a" (count)
-               : "a" (size), "a" (addr), "a" (&_zb_findmap),
-                 "m" (*(addrtype *) addr) : "cc");
-        return (res < size) ? res : size;
-}
-
-static inline unsigned long
-find_first_bit(const unsigned long * addr, unsigned long size)
+       bytes = __ffz_word_loop(addr, size);
+       bits = __ffz_word(bytes*8, __load_ulong_be(addr, bytes));
+       return (bits < size) ? bits : size;
+}
+
+/**
+ * find_first_bit - find the first set bit in a memory region
+ * @addr: The address to start the search at
+ * @size: The maximum size to search
+ *
+ * Returns the bit-number of the first set bit, not the number of the byte
+ * containing a bit.
+ */
+static inline unsigned long find_first_bit(const unsigned long * addr,
+                                          unsigned long size)
 {
-       typedef struct { long _[__BITOPS_WORDS(size)]; } addrtype;
-        unsigned long res, cmp, count;
+       unsigned long bytes, bits;
 
         if (!size)
                 return 0;
-       asm volatile(
-               "       slgr    %1,%1\n"
-               "       lgr     %2,%3\n"
-               "       slgr    %0,%0\n"
-               "       aghi    %2,63\n"
-               "       srlg    %2,%2,6\n"
-               "0:     cg      %1,0(%0,%4)\n"
-               "       jne     1f\n"
-               "       aghi    %0,8\n"
-               "       brct    %2,0b\n"
-               "       lgr     %0,%3\n"
-               "       j       5f\n"
-               "1:     lg      %2,0(%0,%4)\n"
-               "       sllg    %0,%0,3\n"
-               "       clr     %2,%1\n"
-               "       jne     2f\n"
-               "       aghi    %0,32\n"
-               "       srlg    %2,%2,32\n"
-               "2:     lghi    %1,0xff\n"
-               "       tmll    %2,0xffff\n"
-               "       jnz     3f\n"
-               "       aghi    %0,16\n"
-               "       srl     %2,16\n"
-               "3:     tmll    %2,0x00ff\n"
-               "       jnz     4f\n"
-               "       aghi    %0,8\n"
-               "       srl     %2,8\n"
-               "4:     ngr     %2,%1\n"
-               "       ic      %2,0(%2,%5)\n"
-               "       algr    %0,%2\n"
-               "5:"
-               : "=&a" (res), "=&d" (cmp), "=&a" (count)
-               : "a" (size), "a" (addr), "a" (&_sb_findmap),
-                 "m" (*(addrtype *) addr) : "cc");
-        return (res < size) ? res : size;
+       bytes = __ffs_word_loop(addr, size);
+       bits = __ffs_word(bytes*8, __load_ulong_be(addr, bytes));
+       return (bits < size) ? bits : size;
 }
 
-#endif /* __s390x__ */
-
-static inline int
-find_next_zero_bit (const unsigned long * addr, unsigned long size,
-                   unsigned long offset)
+/**
+ * find_next_zero_bit - find the first zero bit in a memory region
+ * @addr: The address to base the search on
+ * @offset: The bitnumber to start searching at
+ * @size: The maximum size to search
+ */
+static inline int find_next_zero_bit (const unsigned long * addr,
+                                     unsigned long size,
+                                     unsigned long offset)
 {
         const unsigned long *p;
        unsigned long bit, set;
@@ -688,10 +702,10 @@ find_next_zero_bit (const unsigned long * addr, unsigned long size,
        p = addr + offset / __BITOPS_WORDSIZE;
        if (bit) {
                /*
-                * s390 version of ffz returns __BITOPS_WORDSIZE
+                * __ffz_word returns __BITOPS_WORDSIZE
                 * if no zero bit is present in the word.
                 */
-               set = ffz(*p >> bit) + bit;
+               set = __ffz_word(0, *p >> bit) + bit;
                if (set >= size)
                        return size + offset;
                if (set < __BITOPS_WORDSIZE)
@@ -703,9 +717,15 @@ find_next_zero_bit (const unsigned long * addr, unsigned long size,
        return offset + find_first_zero_bit(p, size);
 }
 
-static inline int
-find_next_bit (const unsigned long * addr, unsigned long size,
-              unsigned long offset)
+/**
+ * find_next_bit - find the first set bit in a memory region
+ * @addr: The address to base the search on
+ * @offset: The bitnumber to start searching at
+ * @size: The maximum size to search
+ */
+static inline int find_next_bit (const unsigned long * addr,
+                                unsigned long size,
+                                unsigned long offset)
 {
         const unsigned long *p;
        unsigned long bit, set;
@@ -718,10 +738,10 @@ find_next_bit (const unsigned long * addr, unsigned long size,
        p = addr + offset / __BITOPS_WORDSIZE;
        if (bit) {
                /*
-                * s390 version of __ffs returns __BITOPS_WORDSIZE
+                * __ffs_word returns __BITOPS_WORDSIZE
                 * if no one bit is present in the word.
                 */
-               set = __ffs(*p & (~0UL << bit));
+               set = __ffs_word(0, *p & (~0UL << bit));
                if (set >= size)
                        return size + offset;
                if (set < __BITOPS_WORDSIZE)
@@ -744,8 +764,6 @@ static inline int sched_find_first_bit(unsigned long *b)
        return find_first_bit(b, 140);
 }
 
-#include <asm-generic/bitops/ffs.h>
-
 #include <asm-generic/bitops/fls.h>
 #include <asm-generic/bitops/fls64.h>
 
@@ -772,108 +790,23 @@ static inline int sched_find_first_bit(unsigned long *b)
        test_and_clear_bit((nr)^(__BITOPS_WORDSIZE - 8), (unsigned long *)addr)
 #define ext2_test_bit(nr, addr)      \
        test_bit((nr)^(__BITOPS_WORDSIZE - 8), (unsigned long *)addr)
-#define ext2_find_next_bit(addr, size, off) \
-       generic_find_next_le_bit((unsigned long *)(addr), (size), (off))
 
-#ifndef __s390x__
-
-static inline int 
-ext2_find_first_zero_bit(void *vaddr, unsigned int size)
+static inline int ext2_find_first_zero_bit(void *vaddr, unsigned int size)
 {
-       typedef struct { long _[__BITOPS_WORDS(size)]; } addrtype;
-       unsigned long cmp, count;
-        unsigned int res;
+       unsigned long bytes, bits;
 
         if (!size)
                 return 0;
-       asm volatile(
-               "       lhi     %1,-1\n"
-               "       lr      %2,%3\n"
-               "       ahi     %2,31\n"
-               "       srl     %2,5\n"
-               "       slr     %0,%0\n"
-               "0:     cl      %1,0(%0,%4)\n"
-               "       jne     1f\n"
-               "       ahi     %0,4\n"
-               "       brct    %2,0b\n"
-               "       lr      %0,%3\n"
-               "       j       4f\n"
-               "1:     l       %2,0(%0,%4)\n"
-               "       sll     %0,3\n"
-               "       ahi     %0,24\n"
-               "       lhi     %1,0xff\n"
-               "       tmh     %2,0xffff\n"
-               "       jo      2f\n"
-               "       ahi     %0,-16\n"
-               "       srl     %2,16\n"
-               "2:     tml     %2,0xff00\n"
-               "       jo      3f\n"
-               "       ahi     %0,-8\n"
-               "       srl     %2,8\n"
-               "3:     nr      %2,%1\n"
-               "       ic      %2,0(%2,%5)\n"
-               "       alr     %0,%2\n"
-               "4:"
-               : "=&a" (res), "=&d" (cmp), "=&a" (count)
-               : "a" (size), "a" (vaddr), "a" (&_zb_findmap),
-                 "m" (*(addrtype *) vaddr) : "cc");
-        return (res < size) ? res : size;
+       bytes = __ffz_word_loop(vaddr, size);
+       bits = __ffz_word(bytes*8, __load_ulong_le(vaddr, bytes));
+       return (bits < size) ? bits : size;
 }
 
-#else /* __s390x__ */
-
-static inline unsigned long
-ext2_find_first_zero_bit(void *vaddr, unsigned long size)
-{
-       typedef struct { long _[__BITOPS_WORDS(size)]; } addrtype;
-        unsigned long res, cmp, count;
-
-        if (!size)
-                return 0;
-       asm volatile(
-               "       lghi    %1,-1\n"
-               "       lgr     %2,%3\n"
-               "       aghi    %2,63\n"
-               "       srlg    %2,%2,6\n"
-               "       slgr    %0,%0\n"
-               "0:     clg     %1,0(%0,%4)\n"
-               "       jne     1f\n"
-               "       aghi    %0,8\n"
-               "       brct    %2,0b\n"
-               "       lgr     %0,%3\n"
-               "       j       5f\n"
-               "1:     cl      %1,0(%0,%4)\n"
-               "       jne     2f\n"
-               "       aghi    %0,4\n"
-               "2:     l       %2,0(%0,%4)\n"
-               "       sllg    %0,%0,3\n"
-               "       aghi    %0,24\n"
-               "       lghi    %1,0xff\n"
-               "       tmlh    %2,0xffff\n"
-               "       jo      3f\n"
-               "       aghi    %0,-16\n"
-               "       srl     %2,16\n"
-               "3:     tmll    %2,0xff00\n"
-               "       jo      4f\n"
-               "       aghi    %0,-8\n"
-               "       srl     %2,8\n"
-               "4:     ngr     %2,%1\n"
-               "       ic      %2,0(%2,%5)\n"
-               "       algr    %0,%2\n"
-               "5:"
-               : "=&a" (res), "=&d" (cmp), "=&a" (count)
-               : "a" (size), "a" (vaddr), "a" (&_zb_findmap),
-                 "m" (*(addrtype *) vaddr) : "cc");
-        return (res < size) ? res : size;
-}
-
-#endif /* __s390x__ */
-
-static inline int
-ext2_find_next_zero_bit(void *vaddr, unsigned long size, unsigned long offset)
+static inline int ext2_find_next_zero_bit(void *vaddr, unsigned long size,
+                                         unsigned long offset)
 {
         unsigned long *addr = vaddr, *p;
-       unsigned long word, bit, set;
+       unsigned long bit, set;
 
         if (offset >= size)
                 return size;
@@ -882,23 +815,11 @@ ext2_find_next_zero_bit(void *vaddr, unsigned long size, unsigned long offset)
        size -= offset;
        p = addr + offset / __BITOPS_WORDSIZE;
         if (bit) {
-#ifndef __s390x__
-               asm volatile(
-                       "       ic      %0,0(%1)\n"
-                       "       icm     %0,2,1(%1)\n"
-                       "       icm     %0,4,2(%1)\n"
-                       "       icm     %0,8,3(%1)"
-                       : "=&a" (word) : "a" (p), "m" (*p) : "cc");
-#else
-               asm volatile(
-                       "       lrvg    %0,%1"
-                       : "=a" (word) : "m" (*p) );
-#endif
                /*
                 * s390 version of ffz returns __BITOPS_WORDSIZE
                 * if no zero bit is present in the word.
                 */
-               set = ffz(word >> bit) + bit;
+               set = ffz(__load_ulong_le(p, 0) >> bit) + bit;
                if (set >= size)
                        return size + offset;
                if (set < __BITOPS_WORDSIZE)
@@ -910,6 +831,47 @@ ext2_find_next_zero_bit(void *vaddr, unsigned long size, unsigned long offset)
        return offset + ext2_find_first_zero_bit(p, size);
 }
 
+static inline unsigned long ext2_find_first_bit(void *vaddr,
+                                               unsigned long size)
+{
+       unsigned long bytes, bits;
+
+       if (!size)
+               return 0;
+       bytes = __ffs_word_loop(vaddr, size);
+       bits = __ffs_word(bytes*8, __load_ulong_le(vaddr, bytes));
+       return (bits < size) ? bits : size;
+}
+
+static inline int ext2_find_next_bit(void *vaddr, unsigned long size,
+                                    unsigned long offset)
+{
+       unsigned long *addr = vaddr, *p;
+       unsigned long bit, set;
+
+       if (offset >= size)
+               return size;
+       bit = offset & (__BITOPS_WORDSIZE - 1);
+       offset -= bit;
+       size -= offset;
+       p = addr + offset / __BITOPS_WORDSIZE;
+       if (bit) {
+               /*
+                * s390 version of ffz returns __BITOPS_WORDSIZE
+                * if no zero bit is present in the word.
+                */
+               set = ffs(__load_ulong_le(p, 0) >> bit) + bit;
+               if (set >= size)
+                       return size + offset;
+               if (set < __BITOPS_WORDSIZE)
+                       return set + offset;
+               offset += __BITOPS_WORDSIZE;
+               size -= __BITOPS_WORDSIZE;
+               p++;
+       }
+       return offset + ext2_find_first_bit(p, size);
+}
+
 #include <asm-generic/bitops/minix.h>
 
 #endif /* __KERNEL__ */
index f7cade8083f3378e8297493f984f3749b2552b9e..49d5af916d014a9e22300464d11110b1d2855baf 100644 (file)
@@ -24,4 +24,8 @@
 #define copy_from_user_page(vma, page, vaddr, dst, src, len) \
        memcpy(dst, src, len)
 
+#ifdef CONFIG_DEBUG_PAGEALLOC
+void kernel_map_pages(struct page *page, int numpages, int enable);
+#endif
+
 #endif /* _S390_CACHEFLUSH_H */
index 7109c7cab87ecfe4d57941f24c0d83c46604e719..289053ef5e601628403e57279cc681cdfef36282 100644 (file)
@@ -37,6 +37,7 @@ struct ccwgroup_device {
  * @remove: function called on remove
  * @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
  * @driver: embedded driver structure
  */
 struct ccwgroup_driver {
@@ -49,6 +50,7 @@ struct ccwgroup_driver {
        void (*remove) (struct ccwgroup_device *);
        int (*set_online) (struct ccwgroup_device *);
        int (*set_offline) (struct ccwgroup_device *);
+       void (*shutdown)(struct ccwgroup_device *);
 
        struct device_driver driver;
 };
index 7f4ad623f7d5d93a2f423cd76898c1df52883a51..de065b32381a36867eb7bf6bc58f2b0ba8ddeec2 100644 (file)
@@ -149,7 +149,7 @@ typedef u32         compat_sigset_word;
  * A pointer passed in from user mode. This should not
  * be used for syscall parameters, just declare them
  * as pointers because the syscall entry code will have
- * appropriately comverted them already.
+ * appropriately converted them already.
  */
 typedef        u32             compat_uptr_t;
 
index 2d676a873858cf599fbc1b679e6ceccd6a112fc3..408d60b4f75bc779a5bf356d13c1624ba209ce25 100644 (file)
  */
 #if defined(__s390x__) && defined(MODULE)
 
-#define __reloc_hide(var,offset) (*({                  \
+#define SHIFT_PERCPU_PTR(ptr,offset) (({                       \
        extern int simple_identifier_##var(void);       \
        unsigned long *__ptr;                           \
-       asm ( "larl %0,per_cpu__"#var"@GOTENT"          \
-           : "=a" (__ptr) : "X" (per_cpu__##var) );    \
-       (typeof(&per_cpu__##var))((*__ptr) + (offset)); }))
+       asm ( "larl %0, %1@GOTENT"              \
+           : "=a" (__ptr) : "X" (ptr) );               \
+       (typeof(ptr))((*__ptr) + (offset));     }))
 
 #else
 
-#define __reloc_hide(var, offset) (*({                         \
+#define SHIFT_PERCPU_PTR(ptr, offset) (({                              \
        extern int simple_identifier_##var(void);               \
        unsigned long __ptr;                                    \
-       asm ( "" : "=a" (__ptr) : "0" (&per_cpu__##var) );      \
-       (typeof(&per_cpu__##var)) (__ptr + (offset)); }))
+       asm ( "" : "=a" (__ptr) : "0" (ptr) );                  \
+       (typeof(ptr)) (__ptr + (offset)); }))
 
 #endif
 
-#ifdef CONFIG_SMP
+#define __my_cpu_offset S390_lowcore.percpu_offset
 
-extern unsigned long __per_cpu_offset[NR_CPUS];
-
-#define __get_cpu_var(var) __reloc_hide(var,S390_lowcore.percpu_offset)
-#define __raw_get_cpu_var(var) __reloc_hide(var,S390_lowcore.percpu_offset)
-#define per_cpu(var,cpu) __reloc_hide(var,__per_cpu_offset[cpu])
-#define per_cpu_offset(x) (__per_cpu_offset[x])
-
-/* A macro to avoid #include hell... */
-#define percpu_modcopy(pcpudst, src, size)                     \
-do {                                                           \
-       unsigned int __i;                                       \
-       for_each_possible_cpu(__i)                              \
-               memcpy((pcpudst)+__per_cpu_offset[__i],         \
-                      (src), (size));                          \
-} while (0)
-
-#else /* ! SMP */
-
-#define __get_cpu_var(var) __reloc_hide(var,0)
-#define __raw_get_cpu_var(var) __reloc_hide(var,0)
-#define per_cpu(var,cpu) __reloc_hide(var,0)
-
-#endif /* SMP */
-
-#define DECLARE_PER_CPU(type, name) extern __typeof__(type) per_cpu__##name
+#include <asm-generic/percpu.h>
 
 #endif /* __ARCH_S390_PERCPU__ */
index 709dd1740956b48407b8c3a58f8e762b9a52a543..6f6619ba898062c6af642c83dd574eda02c0e6c6 100644 (file)
@@ -57,10 +57,10 @@ static inline unsigned long pgd_entry_type(struct mm_struct *mm)
 }
 
 #define pud_alloc_one(mm,address)              ({ BUG(); ((pud_t *)2); })
-#define pud_free(x)                            do { } while (0)
+#define pud_free(mm, x)                                do { } while (0)
 
 #define pmd_alloc_one(mm,address)              ({ BUG(); ((pmd_t *)2); })
-#define pmd_free(x)                            do { } while (0)
+#define pmd_free(mm, x)                                do { } while (0)
 
 #define pgd_populate(mm, pgd, pud)             BUG()
 #define pgd_populate_kernel(mm, pgd, pud)      BUG()
@@ -76,7 +76,7 @@ static inline unsigned long pgd_entry_type(struct mm_struct *mm)
 }
 
 #define pud_alloc_one(mm,address)              ({ BUG(); ((pud_t *)2); })
-#define pud_free(x)                            do { } while (0)
+#define pud_free(mm, x)                                do { } while (0)
 
 static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long vmaddr)
 {
@@ -85,7 +85,7 @@ static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long vmaddr)
                crst_table_init(crst, _SEGMENT_ENTRY_EMPTY);
        return (pmd_t *) crst;
 }
-#define pmd_free(pmd) crst_table_free((unsigned long *) pmd)
+#define pmd_free(mm, pmd) crst_table_free((unsigned long *)pmd)
 
 #define pgd_populate(mm, pgd, pud)             BUG()
 #define pgd_populate_kernel(mm, pgd, pud)      BUG()
@@ -115,7 +115,7 @@ static inline pgd_t *pgd_alloc(struct mm_struct *mm)
                crst_table_init(crst, pgd_entry_type(mm));
        return (pgd_t *) crst;
 }
-#define pgd_free(pgd) crst_table_free((unsigned long *) pgd)
+#define pgd_free(mm, pgd) crst_table_free((unsigned long *) pgd)
 
 static inline void 
 pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmd, pte_t *pte)
@@ -151,9 +151,9 @@ pmd_populate(struct mm_struct *mm, pmd_t *pmd, struct page *page)
 #define pte_alloc_one(mm, vmaddr) \
        virt_to_page(page_table_alloc(s390_noexec))
 
-#define pte_free_kernel(pte) \
+#define pte_free_kernel(mm, pte) \
        page_table_free((unsigned long *) pte)
-#define pte_free(pte) \
+#define pte_free(mm, pte) \
        page_table_free((unsigned long *) page_to_phys((struct page *) pte))
 
 #endif /* _S390_PGALLOC_H */
index 79b9eab1a0c71bc25ffbee10582c1267e2aecb3e..3f520754e71c4472db5d2570cb42cd8a795ab7d1 100644 (file)
@@ -115,15 +115,21 @@ extern char empty_zero_page[PAGE_SIZE];
 #ifndef __s390x__
 #define VMALLOC_START  0x78000000UL
 #define VMALLOC_END    0x7e000000UL
-#define VMEM_MAP_MAX   0x80000000UL
+#define VMEM_MAP_END   0x80000000UL
 #else /* __s390x__ */
 #define VMALLOC_START  0x3e000000000UL
 #define VMALLOC_END    0x3e040000000UL
-#define VMEM_MAP_MAX   0x40000000000UL
+#define VMEM_MAP_END   0x40000000000UL
 #endif /* __s390x__ */
 
+/*
+ * VMEM_MAX_PHYS is the highest physical address that can be added to the 1:1
+ * mapping. This needs to be calculated at compile time since the size of the
+ * VMEM_MAP is static but the size of struct page can change.
+ */
+#define VMEM_MAX_PHYS  min(VMALLOC_START, ((VMEM_MAP_END - VMALLOC_END) / \
+                         sizeof(struct page) * PAGE_SIZE) & ~((16 << 20) - 1))
 #define VMEM_MAP       ((struct page *) VMALLOC_END)
-#define VMEM_MAP_SIZE  ((VMALLOC_START / PAGE_SIZE) * sizeof(struct page))
 
 /*
  * A 31 bit pagetable entry of S390 has following format:
index c86b982aef5a6bb9ebce57a008617443555084f8..4f744609cd11b35aed60e95e33125553809b1692 100644 (file)
@@ -70,8 +70,9 @@ extern int get_cpu_capability(unsigned int *);
 
 #else /* __s390x__ */
 
-# define TASK_SIZE             (test_thread_flag(TIF_31BIT) ? \
+# define TASK_SIZE_OF(tsk)     (test_tsk_thread_flag(tsk, TIF_31BIT) ? \
                                        (0x80000000UL) : (0x40000000000UL))
+# define TASK_SIZE             TASK_SIZE_OF(current)
 # define TASK_UNMAPPED_BASE    (TASK_SIZE / 2)
 # define DEFAULT_TASK_SIZE     (0x40000000000UL)
 
index 1161ebe3dec9530cc0ac416722ad6c15a79de8e5..c786ab623b2d2d0f3f63aedfa5873248f40b156d 100644 (file)
@@ -60,4 +60,6 @@
 #define SO_TIMESTAMPNS         35
 #define SCM_TIMESTAMPNS                SO_TIMESTAMPNS
 
+#define SO_MARK                        36
+
 #endif /* _ASM_SOCKET_H */
index 618693cfc10f2047b710378210c4842d671f2678..985de2b88279c99a563d85635af1ccec07fc0a6c 100644 (file)
@@ -65,9 +65,9 @@ static inline void tlb_flush_mmu(struct mmu_gather *tlb,
        if (!tlb->fullmm && (tlb->nr_ptes > 0 || tlb->nr_pmds < TLB_NR_PTRS))
                __tlb_flush_mm(tlb->mm);
        while (tlb->nr_ptes > 0)
-               pte_free(tlb->array[--tlb->nr_ptes]);
+               pte_free(tlb->mm, tlb->array[--tlb->nr_ptes]);
        while (tlb->nr_pmds < TLB_NR_PTRS)
-               pmd_free((pmd_t *) tlb->array[tlb->nr_pmds++]);
+               pmd_free(tlb->mm, (pmd_t *) tlb->array[tlb->nr_pmds++]);
 }
 
 static inline void tlb_finish_mmu(struct mmu_gather *tlb,
@@ -102,7 +102,7 @@ static inline void pte_free_tlb(struct mmu_gather *tlb, struct page *page)
                if (tlb->nr_ptes >= tlb->nr_pmds)
                        tlb_flush_mmu(tlb, 0, 0);
        } else
-               pte_free(page);
+               pte_free(tlb->mm, page);
 }
 
 /*
@@ -117,7 +117,7 @@ static inline void pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmd)
                if (tlb->nr_ptes >= tlb->nr_pmds)
                        tlb_flush_mmu(tlb, 0, 0);
        } else
-               pmd_free(pmd);
+               pmd_free(tlb->mm, pmd);
 #endif
 }
 
index 18b613c57cf5118a8ea6fc452d0a0230ff4d50bf..59ca16d77a1d79b20775362e8d76d7d9cc2d3594 100644 (file)
@@ -36,7 +36,7 @@ static inline pgd_t *pgd_alloc(struct mm_struct *mm)
        return quicklist_alloc(QUICK_PGD, GFP_KERNEL | __GFP_REPEAT, pgd_ctor);
 }
 
-static inline void pgd_free(pgd_t *pgd)
+static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd)
 {
        quicklist_free(QUICK_PGD, NULL, pgd);
 }
@@ -54,12 +54,12 @@ static inline struct page *pte_alloc_one(struct mm_struct *mm,
        return pg ? virt_to_page(pg) : NULL;
 }
 
-static inline void pte_free_kernel(pte_t *pte)
+static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte)
 {
        quicklist_free(QUICK_PT, NULL, pte);
 }
 
-static inline void pte_free(struct page *pte)
+static inline void pte_free(struct mm_struct *mm, struct page *pte)
 {
        quicklist_free_page(QUICK_PT, NULL, pte);
 }
@@ -71,7 +71,7 @@ static inline void pte_free(struct page *pte)
  * inside the pgd, so has no extra memory associated with it.
  */
 
-#define pmd_free(x)                    do { } while (0)
+#define pmd_free(mm, x)                        do { } while (0)
 #define __pmd_free_tlb(tlb,x)          do { } while (0)
 
 static inline void check_pgt_cache(void)
index c48d6fc9da3866da5fc5fa3e70d5ec76f654801b..6d4bf6512959ef0a8b2e610e4fd2aeb99c88e5bf 100644 (file)
@@ -52,4 +52,6 @@
 #define SO_TIMESTAMPNS         35
 #define SCM_TIMESTAMPNS                SO_TIMESTAMPNS
 
+#define SO_MARK                        36
+
 #endif /* __ASM_SH_SOCKET_H */
index b182b1cb05fd24369aa0d1381f553c3135c7e57f..433fd1b48fa2663a93ee3942333281e61532a713 100644 (file)
 #define __NR_epoll_pwait       319
 #define __NR_utimensat         320
 #define __NR_signalfd          321
-#define __NR_timerfd           322
+/* #define __NR_timerfd                322 removed */
 #define __NR_eventfd           323
 #define __NR_fallocate         324
 
index 944511882cac4a7db0c06897f3bcf6321083b102..108d2ba897fe8e8ac4321475b7f23fc92d03aa65 100644 (file)
 #define __NR_epoll_pwait       347
 #define __NR_utimensat         348
 #define __NR_signalfd          349
-#define __NR_timerfd           350
+/* #define __NR_timerfd                350 removed */
 #define __NR_eventfd           351
 #define __NR_fallocate         352
 
index a449cd4912d1f711889c9991dcd8f155c5545a38..b5fbdd36447fbf2b69f384957b76962731553645 100644 (file)
@@ -32,7 +32,7 @@ BTFIXUPDEF_CALL(pgd_t *, get_pgd_fast, void)
 BTFIXUPDEF_CALL(void, free_pgd_fast, pgd_t *)
 #define free_pgd_fast(pgd)     BTFIXUP_CALL(free_pgd_fast)(pgd)
 
-#define pgd_free(pgd)  free_pgd_fast(pgd)
+#define pgd_free(mm, pgd)      free_pgd_fast(pgd)
 #define pgd_alloc(mm)  get_pgd_fast()
 
 BTFIXUPDEF_CALL(void, pgd_set, pgd_t *, pmd_t *)
@@ -45,8 +45,8 @@ BTFIXUPDEF_CALL(pmd_t *, pmd_alloc_one, struct mm_struct *, unsigned long)
 BTFIXUPDEF_CALL(void, free_pmd_fast, pmd_t *)
 #define free_pmd_fast(pmd)     BTFIXUP_CALL(free_pmd_fast)(pmd)
 
-#define pmd_free(pmd)           free_pmd_fast(pmd)
-#define __pmd_free_tlb(tlb, pmd) pmd_free(pmd)
+#define pmd_free(mm, pmd)      free_pmd_fast(pmd)
+#define __pmd_free_tlb(tlb, pmd) pmd_free((tlb)->mm, pmd)
 
 BTFIXUPDEF_CALL(void, pmd_populate, pmd_t *, struct page *)
 #define pmd_populate(MM, PMD, PTE)        BTFIXUP_CALL(pmd_populate)(PMD, PTE)
@@ -59,10 +59,10 @@ BTFIXUPDEF_CALL(pte_t *, pte_alloc_one_kernel, struct mm_struct *, unsigned long
 #define pte_alloc_one_kernel(mm, addr) BTFIXUP_CALL(pte_alloc_one_kernel)(mm, addr)
 
 BTFIXUPDEF_CALL(void, free_pte_fast, pte_t *)
-#define pte_free_kernel(pte)   BTFIXUP_CALL(free_pte_fast)(pte)
+#define pte_free_kernel(mm, pte)       BTFIXUP_CALL(free_pte_fast)(pte)
 
 BTFIXUPDEF_CALL(void, pte_free, struct page *)
-#define pte_free(pte)          BTFIXUP_CALL(pte_free)(pte)
-#define __pte_free_tlb(tlb, pte)       pte_free(pte)
+#define pte_free(mm, pte)      BTFIXUP_CALL(pte_free)(pte)
+#define __pte_free_tlb(tlb, pte)       pte_free((tlb)->mm, pte)
 
 #endif /* _SPARC_PGALLOC_H */
index 7c1423997cf0d41bbd0f6830e8e5993fefaec360..2e2bd0b7c8e3e34616c6621b8e7dbd2cc7683567 100644 (file)
@@ -52,6 +52,8 @@
 #define SO_TIMESTAMPNS         0x0021
 #define SCM_TIMESTAMPNS                SO_TIMESTAMPNS
 
+#define SO_MARK                        0x0022
+
 /* Security levels - as per NRL IPv6 - don't actually do anything */
 #define SO_SECURITY_AUTHENTICATION             0x5001
 #define SO_SECURITY_ENCRYPTION_TRANSPORT       0x5002
index 01fe6682b4054237ee55d8d4418310aaf68947cd..f260b58f5ce9d34ac224d2781bf4e0ac277849d4 100644 (file)
@@ -152,7 +152,7 @@ typedef u32         compat_sigset_word;
  * A pointer passed in from user mode. This should not
  * be used for syscall parameters, just declare them
  * as pointers because the syscall entry code will have
- * appropriately comverted them already.
+ * appropriately converted them already.
  */
 typedef        u32             compat_uptr_t;
 
index c7e52decba9863e5e821872d293f6f79b4fc7ec2..bee64593023e2f34d0be046dcddd47d5e3167e60 100644 (file)
@@ -7,7 +7,6 @@ register unsigned long __local_per_cpu_offset asm("g5");
 
 #ifdef CONFIG_SMP
 
-#define setup_per_cpu_areas()                  do { } while (0)
 extern void real_setup_per_cpu_areas(void);
 
 extern unsigned long __per_cpu_base;
@@ -16,29 +15,14 @@ extern unsigned long __per_cpu_shift;
        (__per_cpu_base + ((unsigned long)(__cpu) << __per_cpu_shift))
 #define per_cpu_offset(x) (__per_cpu_offset(x))
 
-/* var is in discarded region: offset to particular copy we want */
-#define per_cpu(var, cpu) (*RELOC_HIDE(&per_cpu__##var, __per_cpu_offset(cpu)))
-#define __get_cpu_var(var) (*RELOC_HIDE(&per_cpu__##var, __local_per_cpu_offset))
-#define __raw_get_cpu_var(var) (*RELOC_HIDE(&per_cpu__##var, __local_per_cpu_offset))
-
-/* A macro to avoid #include hell... */
-#define percpu_modcopy(pcpudst, src, size)                     \
-do {                                                           \
-       unsigned int __i;                                       \
-       for_each_possible_cpu(__i)                              \
-               memcpy((pcpudst)+__per_cpu_offset(__i),         \
-                      (src), (size));                          \
-} while (0)
+#define __my_cpu_offset __local_per_cpu_offset
+
 #else /* ! SMP */
 
 #define real_setup_per_cpu_areas()             do { } while (0)
 
-#define per_cpu(var, cpu)                      (*((void)cpu, &per_cpu__##var))
-#define __get_cpu_var(var)                     per_cpu__##var
-#define __raw_get_cpu_var(var)                 per_cpu__##var
-
 #endif /* SMP */
 
-#define DECLARE_PER_CPU(type, name) extern __typeof__(type) per_cpu__##name
+#include <asm-generic/percpu.h>
 
 #endif /* __ARCH_SPARC64_PERCPU__ */
index 5d66b858a965bdb42d4ccf30565d5c36cfd68fda..b48f73c2274ef7ee682204deffa9bcd09dad962f 100644 (file)
@@ -20,7 +20,7 @@ static inline pgd_t *pgd_alloc(struct mm_struct *mm)
        return quicklist_alloc(0, GFP_KERNEL, NULL);
 }
 
-static inline void pgd_free(pgd_t *pgd)
+static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd)
 {
        quicklist_free(0, NULL, pgd);
 }
@@ -32,7 +32,7 @@ static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long addr)
        return quicklist_alloc(0, GFP_KERNEL, NULL);
 }
 
-static inline void pmd_free(pmd_t *pmd)
+static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd)
 {
        quicklist_free(0, NULL, pmd);
 }
@@ -50,12 +50,12 @@ static inline struct page *pte_alloc_one(struct mm_struct *mm,
        return pg ? virt_to_page(pg) : NULL;
 }
                
-static inline void pte_free_kernel(pte_t *pte)
+static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte)
 {
        quicklist_free(0, NULL, pte);
 }
 
-static inline void pte_free(struct page *ptepage)
+static inline void pte_free(struct mm_struct *mm, struct page *ptepage)
 {
        quicklist_free_page(0, NULL, ptepage);
 }
index 986441dcb8f03ba39eab3e3a972ca0e5159b7bbf..44a625af6e317e91758494fd906a3ef1597cdc79 100644 (file)
@@ -57,4 +57,5 @@
 #define SO_SECURITY_ENCRYPTION_TRANSPORT       0x5002
 #define SO_SECURITY_ENCRYPTION_NETWORK         0x5004
 
+#define SO_MARK                        0x0022
 #endif /* _ASM_SOCKET_H */
index 349d1d3e9c27135c84f833b60032f6b0907efbfc..ec81cdedef2c8a94aaea03263371b19c832edf60 100644 (file)
@@ -100,8 +100,8 @@ static inline void tlb_remove_page(struct mmu_gather *mp, struct page *page)
 }
 
 #define tlb_remove_tlb_entry(mp,ptep,addr) do { } while (0)
-#define pte_free_tlb(mp,ptepage) pte_free(ptepage)
-#define pmd_free_tlb(mp,pmdp) pmd_free(pmdp)
+#define pte_free_tlb(mp, ptepage) pte_free((mp)->mm, ptepage)
+#define pmd_free_tlb(mp, pmdp) pmd_free((mp)->mm, pmdp)
 #define pud_free_tlb(tlb,pudp) __pud_free_tlb(tlb,pudp)
 
 #define tlb_migrate_finish(mm) do { } while (0)
index 9281dd8eb3345960e58a9248e7027b0ff4c30059..f42ff14577fac4875228242f26128ae6659e92f0 100644 (file)
 
 extern unsigned long stacksizelim;
 
-extern unsigned long host_task_size;
-
 #define STACK_ROOM (stacksizelim)
 
-#define STACK_TOP task_size
+#define STACK_TOP (TASK_SIZE - 2 * PAGE_SIZE)
 
 #define STACK_TOP_MAX STACK_TOP
 
index 8fd72f69ce65d263da723de56bec53137e7a7f60..c2191d9aa03d872158ac7359e5e764dd615341f8 100644 (file)
@@ -1,32 +1,13 @@
-/* 
- * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+/*
+ * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
  * Licensed under the GPL
  */
 
 #ifndef __UM_CURRENT_H
 #define __UM_CURRENT_H
 
-#ifndef __ASSEMBLY__
-
-#include "asm/page.h"
 #include "linux/thread_info.h"
 
 #define current (current_thread_info()->task)
 
-/*Backward compatibility - it's used inside arch/um.*/
-#define current_thread current_thread_info()
-
-#endif /* __ASSEMBLY__ */
-
 #endif
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
index ca94a136dfe8ed0e75231d3a415cbbc9577ae62f..23d6893e8617d6ccfa0deb9819587d6f3d1452f6 100644 (file)
@@ -1,11 +1,11 @@
 /*
- * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
+ * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
  * Licensed under the GPL
  */
 #ifndef __UM_ELF_I386_H
 #define __UM_ELF_I386_H
 
-#include <linux/sched.h>
+#include <asm/user.h>
 #include "skas.h"
 
 #define R_386_NONE     0
@@ -46,7 +46,7 @@ typedef struct user_i387_struct elf_fpregset_t;
        PT_REGS_EDI(regs) = 0; \
        PT_REGS_EBP(regs) = 0; \
        PT_REGS_EAX(regs) = 0; \
-} while(0)
+} while (0)
 
 #define USE_ELF_CORE_DUMP
 #define ELF_EXEC_PAGESIZE 4096
@@ -74,14 +74,9 @@ typedef struct user_i387_struct elf_fpregset_t;
        pr_reg[14] = PT_REGS_EFLAGS(regs);      \
        pr_reg[15] = PT_REGS_SP(regs);          \
        pr_reg[16] = PT_REGS_SS(regs);          \
-} while(0);
+} while (0);
 
-static inline int elf_core_copy_fpregs(struct task_struct *t,
-                                      elf_fpregset_t *fpu)
-{
-       int cpu = ((struct thread_info *) t->stack)->cpu;
-       return save_fp_registers(userspace_pid[cpu], (unsigned long *) fpu);
-}
+extern int elf_core_copy_fpregs(struct task_struct *t, elf_fpregset_t *fpu);
 
 #define ELF_CORE_COPY_FPREGS(t, fpu) elf_core_copy_fpregs(t, fpu)
 
@@ -91,7 +86,7 @@ extern long elf_aux_hwcap;
 extern char * elf_aux_platform;
 #define ELF_PLATFORM (elf_aux_platform)
 
-#define SET_PERSONALITY(ex, ibcs2) do ; while(0)
+#define SET_PERSONALITY(ex, ibcs2) do { } while (0)
 
 extern unsigned long vsyscall_ehdr;
 extern unsigned long vsyscall_end;
@@ -166,14 +161,3 @@ if ( vsyscall_ehdr ) {                                                           \
 }
 
 #endif
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
index 3c9d543eb61e4d797c9452950629ffa5662c58bd..3b2d5224a7e166947be5ce2baa9ae720e696a7e3 100644 (file)
@@ -7,7 +7,6 @@
 #ifndef __UM_ELF_X86_64_H
 #define __UM_ELF_X86_64_H
 
-#include <linux/sched.h>
 #include <asm/user.h>
 #include "skas.h"
 
@@ -96,12 +95,7 @@ typedef struct user_i387_struct elf_fpregset_t;
        (pr_reg)[25] = 0;                                       \
        (pr_reg)[26] = 0;
 
-static inline int elf_core_copy_fpregs(struct task_struct *t,
-                                      elf_fpregset_t *fpu)
-{
-       int cpu = current_thread->cpu;
-       return save_fp_registers(userspace_pid[cpu], (unsigned long *) fpu);
-}
+extern int elf_core_copy_fpregs(struct task_struct *t, elf_fpregset_t *fpu);
 
 #define ELF_CORE_COPY_FPREGS(t, fpu) elf_core_copy_fpregs(t, fpu)
 
index d352a35cfafb3c1a0aff2eeab1f630d8646f220a..89a87c18b927f75d6b1ee486b83996deba4f754b 100644 (file)
@@ -1,9 +1,10 @@
 #ifndef __UM_FIXMAP_H
 #define __UM_FIXMAP_H
 
+#include <asm/system.h>
 #include <asm/kmap_types.h>
 #include <asm/archparam.h>
-#include <asm/elf.h>
+#include <asm/page.h>
 
 /*
  * Here we define all the compile-time 'special' virtual
@@ -55,9 +56,8 @@ extern void __set_fixmap (enum fixed_addresses idx,
  * the start of the fixmap, and leave one page empty
  * at the top of mem..
  */
-extern unsigned long get_kmem_end(void);
 
-#define FIXADDR_TOP    (get_kmem_end() - 0x2000)
+#define FIXADDR_TOP    (CONFIG_TOP_ADDR - 2 * PAGE_SIZE)
 #define FIXADDR_SIZE   (__end_of_fixed_addresses << PAGE_SHIFT)
 #define FIXADDR_START  (FIXADDR_TOP - FIXADDR_SIZE)
 
index b2553f3e87ebfcd3294fe94ecf85a1b975b7f0eb..52af512f5e7dcf272a73de968b709f900218e98d 100644 (file)
@@ -8,7 +8,7 @@
 #ifndef __ASM_LDT_H
 #define __ASM_LDT_H
 
-#include "asm/semaphore.h"
+#include <linux/mutex.h>
 #include "asm/host_ldt.h"
 
 extern void ldt_host_info(void);
@@ -27,7 +27,7 @@ struct ldt_entry {
 
 typedef struct uml_ldt {
        int entry_count;
-       struct semaphore semaphore;
+       struct mutex lock;
        union {
                struct ldt_entry * pages[LDT_PAGES_MAX];
                struct ldt_entry entries[LDT_DIRECT_ENTRIES];
index cdb3024a699a6d83df5f49ccd8e63a3e3adb362b..7dfce37adc8be83424c4463e50a635acfa72650a 100644 (file)
@@ -3,10 +3,4 @@
 
 #include "asm/arch/linkage.h"
 
-
-/* <linux/linkage.h> will pick sane defaults */
-#ifdef CONFIG_GPROF
-#undef fastcall
-#endif
-
 #endif
index 5f3b863aef9aeeafb40c8ee168addf2d6309ecd1..6686fc524ca1aff467688ad52d8976f073a29ea5 100644 (file)
@@ -6,11 +6,12 @@
 #ifndef __UM_MMU_CONTEXT_H
 #define __UM_MMU_CONTEXT_H
 
-#include <asm-generic/mm_hooks.h>
-
 #include "linux/sched.h"
 #include "um_mmu.h"
 
+extern void arch_dup_mmap(struct mm_struct *oldmm, struct mm_struct *mm);
+extern void arch_exit_mmap(struct mm_struct *mm);
+
 #define get_mmu_context(task) do ; while(0)
 #define activate_context(tsk) do ; while(0)
 
@@ -30,6 +31,8 @@ static inline void activate_mm(struct mm_struct *old, struct mm_struct *new)
         */
        if (old != new && (current->flags & PF_BORROWED_MM))
                __switch_mm(&new->context.id);
+
+       arch_dup_mmap(old, new);
 }
 
 static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, 
index 4b424c75fca54384a9e96c02dc840a848989cf7f..fe2374d705d15af36114379cfa5e4192a1125aca 100644 (file)
@@ -30,7 +30,7 @@ struct page;
 #if defined(CONFIG_3_LEVEL_PGTABLES) && !defined(CONFIG_64BIT)
 
 typedef struct { unsigned long pte_low, pte_high; } pte_t;
-typedef struct { unsigned long long pmd; } pmd_t;
+typedef struct { unsigned long pmd; } pmd_t;
 typedef struct { unsigned long pgd; } pgd_t;
 #define pte_val(x) ((x).pte_low | ((unsigned long long) (x).pte_high << 32))
 
@@ -106,8 +106,8 @@ extern unsigned long uml_physmem;
 #define __pa(virt) to_phys((void *) (unsigned long) (virt))
 #define __va(phys) to_virt((unsigned long) (phys))
 
-#define phys_to_pfn(p) ((p) >> PAGE_SHIFT)
-#define pfn_to_phys(pfn) ((pfn) << PAGE_SHIFT)
+#define phys_to_pfn(p) ((pfn_t) ((p) >> PAGE_SHIFT))
+#define pfn_to_phys(pfn) ((phys_t) ((pfn) << PAGE_SHIFT))
 
 #define pfn_valid(pfn) ((pfn) < max_mapnr)
 #define virt_addr_valid(v) pfn_valid(phys_to_pfn(__pa(v)))
index f914e7d67b01b8839c7fe185055566131b7d9d33..4cd4a226f8c125d07668b15fbf239370baa58ebe 100644 (file)
@@ -10,7 +10,7 @@
 #define MAXHOSTNAMELEN  64      /* max length of hostname */
 
 #ifdef __KERNEL__
-#define HZ 100
+#define HZ CONFIG_HZ
 #define USER_HZ        100        /* .. some user interfaces are in "ticks" */
 #define CLOCKS_PER_SEC (USER_HZ)  /* frequency at which times() counts */
 #endif
index 14904876e8fbd8deaf8b8ccc7e819af60f098514..4f3e62b02861f0a743a3ffe45f280e127b0c7f01 100644 (file)
  * Allocate and free page tables.
  */
 extern pgd_t *pgd_alloc(struct mm_struct *);
-extern void pgd_free(pgd_t *pgd);
+extern void pgd_free(struct mm_struct *mm, pgd_t *pgd);
 
 extern pte_t *pte_alloc_one_kernel(struct mm_struct *, unsigned long);
 extern struct page *pte_alloc_one(struct mm_struct *, unsigned long);
 
-static inline void pte_free_kernel(pte_t *pte)
+static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte)
 {
        free_page((unsigned long) pte);
 }
 
-static inline void pte_free(struct page *pte)
+static inline void pte_free(struct mm_struct *mm, struct page *pte)
 {
        __free_page(pte);
 }
@@ -42,7 +42,7 @@ static inline void pte_free(struct page *pte)
 
 #ifdef CONFIG_3_LEVEL_PGTABLES
 
-static inline void pmd_free(pmd_t *pmd)
+static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd)
 {
        free_page((unsigned long)pmd);
 }
index 172a75fde51285c49803a3843dbe74d743c62a03..f534b73e753e74c7515dc5bb96e68ce444546be7 100644 (file)
@@ -41,9 +41,6 @@ static inline void pgd_mkuptodate(pgd_t pgd)  { }
 #define pfn_pte(pfn, prot) __pte(pfn_to_phys(pfn) | pgprot_val(prot))
 #define pfn_pmd(pfn, prot) __pmd(pfn_to_phys(pfn) | pgprot_val(prot))
 
-#define pmd_page_vaddr(pmd) \
-       ((unsigned long) __va(pmd_val(pmd) & PAGE_MASK))
-
 /*
  * Bits 0 through 4 are taken
  */
index 3ebafbaacb24196d82eb5521f4c17292c0a850e7..0446f456b428687b07ba689899cbefe4151d3fe7 100644 (file)
 
 /* PGDIR_SHIFT determines what a third-level page table entry can map */
 
+#ifdef CONFIG_64BIT
 #define PGDIR_SHIFT    30
+#else
+#define PGDIR_SHIFT    31
+#endif
 #define PGDIR_SIZE     (1UL << PGDIR_SHIFT)
 #define PGDIR_MASK     (~(PGDIR_SIZE-1))
 
  */
 
 #define PTRS_PER_PTE 512
+#ifdef CONFIG_64BIT
 #define PTRS_PER_PMD 512
-#define USER_PTRS_PER_PGD ((TASK_SIZE + (PGDIR_SIZE - 1)) / PGDIR_SIZE)
 #define PTRS_PER_PGD 512
+#else
+#define PTRS_PER_PMD 1024
+#define PTRS_PER_PGD 1024
+#endif
+
+#define USER_PTRS_PER_PGD ((TASK_SIZE + (PGDIR_SIZE - 1)) / PGDIR_SIZE)
 #define FIRST_USER_ADDRESS     0
 
 #define pte_ERROR(e) \
 #define pud_populate(mm, pud, pmd) \
        set_pud(pud, __pud(_PAGE_TABLE + __pa(pmd)))
 
+#ifdef CONFIG_64BIT
 #define set_pud(pudptr, pudval) set_64bit((phys_t *) (pudptr), pud_val(pudval))
+#else
+#define set_pud(pudptr, pudval) (*(pudptr) = (pudval))
+#endif
+
 static inline int pgd_newpage(pgd_t pgd)
 {
        return(pgd_val(pgd) & _PAGE_NEWPAGE);
@@ -57,17 +72,14 @@ static inline int pgd_newpage(pgd_t pgd)
 
 static inline void pgd_mkuptodate(pgd_t pgd) { pgd_val(pgd) &= ~_PAGE_NEWPAGE; }
 
+#ifdef CONFIG_64BIT
 #define set_pmd(pmdptr, pmdval) set_64bit((phys_t *) (pmdptr), pmd_val(pmdval))
+#else
+#define set_pmd(pmdptr, pmdval) (*(pmdptr) = (pmdval))
+#endif
 
-static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long address)
-{
-        pmd_t *pmd = (pmd_t *) __get_free_page(GFP_KERNEL);
-
-        if(pmd)
-                memset(pmd, 0, PAGE_SIZE);
-
-        return pmd;
-}
+struct mm_struct;
+extern pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long address);
 
 static inline void pud_clear (pud_t *pud)
 {
@@ -75,8 +87,7 @@ static inline void pud_clear (pud_t *pud)
 }
 
 #define pud_page(pud) phys_to_page(pud_val(pud) & PAGE_MASK)
-#define pud_page_vaddr(pud) \
-       ((struct page *) __va(pud_val(pud) & PAGE_MASK))
+#define pud_page_vaddr(pud) ((unsigned long) __va(pud_val(pud) & PAGE_MASK))
 
 /* Find an entry in the second-level page table.. */
 #define pmd_offset(pud, address) ((pmd_t *) pud_page_vaddr(*(pud)) + \
index 830fc6e5d49d0f41c87ab3e555ecea3a9fa3287f..4102b443e9259566346ca3974b881cc8ac465957 100644 (file)
@@ -1,5 +1,5 @@
 /* 
- * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
  * Copyright 2003 PathScale, Inc.
  * Derived from include/asm-i386/pgtable.h
  * Licensed under the GPL
@@ -8,11 +8,7 @@
 #ifndef __UM_PGTABLE_H
 #define __UM_PGTABLE_H
 
-#include "linux/sched.h"
-#include "linux/linkage.h"
-#include "asm/processor.h"
-#include "asm/page.h"
-#include "asm/fixmap.h"
+#include <asm/fixmap.h>
 
 #define _PAGE_PRESENT  0x001
 #define _PAGE_NEWPAGE  0x002
 
 extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
 
-extern void *um_virt_to_phys(struct task_struct *task, unsigned long virt,
-                            pte_t *pte_out);
-
 /* zero page used for uninitialized stuff */
 extern unsigned long *empty_zero_page;
 
 #define pgtable_cache_init() do ; while (0)
 
-/*
- * pgd entries used up by user/kernel:
- */
-
-#define USER_PGD_PTRS (TASK_SIZE >> PGDIR_SHIFT)
-#define KERNEL_PGD_PTRS (PTRS_PER_PGD-USER_PGD_PTRS)
-
-#ifndef __ASSEMBLY__
 /* Just any arbitrary offset to the start of the vmalloc VM area: the
  * current 8MB value just means that there will be a 8MB "hole" after the
  * physical memory until the kernel virtual memory starts.  That means that
@@ -62,16 +47,12 @@ extern unsigned long end_iomem;
 
 #define VMALLOC_OFFSET (__va_space)
 #define VMALLOC_START ((end_iomem + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
-
 #ifdef CONFIG_HIGHMEM
 # define VMALLOC_END   (PKMAP_BASE-2*PAGE_SIZE)
 #else
 # define VMALLOC_END   (FIXADDR_START-2*PAGE_SIZE)
 #endif
 
-#define REGION_SHIFT   (sizeof(pte_t) * 8 - 4)
-#define REGION_MASK    (((unsigned long) 0xf) << REGION_SHIFT)
-
 #define _PAGE_TABLE    (_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED | _PAGE_DIRTY)
 #define _KERNPG_TABLE  (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY)
 #define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY)
@@ -81,11 +62,12 @@ extern unsigned long end_iomem;
 #define PAGE_COPY      __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
 #define PAGE_READONLY  __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
 #define PAGE_KERNEL    __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED)
-#define PAGE_KERNEL_RO __pgprot(_PAGE_PRESENT | _PAGE_DIRTY | _PAGE_ACCESSED)
 
 /*
- * The i386 can't do page protection for execute, and considers that the same are read.
- * Also, write permissions imply read permissions. This is the closest we can get..
+ * The i386 can't do page protection for execute, and considers that the same
+ * are read.
+ * Also, write permissions imply read permissions. This is the closest we can
+ * get..
  */
 #define __P000 PAGE_NONE
 #define __P001 PAGE_READONLY
@@ -105,41 +87,17 @@ extern unsigned long end_iomem;
 #define __S110 PAGE_SHARED
 #define __S111 PAGE_SHARED
 
-/*
- * Define this if things work differently on an i386 and an i486:
- * it will (on an i486) warn about kernel memory accesses that are
- * done without a 'access_ok(VERIFY_WRITE,..)'
- */
-#undef TEST_VERIFY_AREA
-
-/* page table for 0-4MB for everybody */
-extern unsigned long pg0[1024];
-
 /*
  * ZERO_PAGE is a global shared page that is always zero: used
  * for zero-mapped memory areas etc..
  */
-
 #define ZERO_PAGE(vaddr) virt_to_page(empty_zero_page)
 
-/* number of bits that fit into a memory pointer */
-#define BITS_PER_PTR                   (8*sizeof(unsigned long))
-
-/* to align the pointer to a pointer address */
-#define PTR_MASK                       (~(sizeof(void*)-1))
-
-/* sizeof(void*)==1<<SIZEOF_PTR_LOG2 */
-/* 64-bit machines, beware!  SRB. */
-#define SIZEOF_PTR_LOG2                        3
-
-/* to find an entry in a page-table */
-#define PAGE_PTR(address) \
-((unsigned long)(address)>>(PAGE_SHIFT-SIZEOF_PTR_LOG2)&PTR_MASK&~PAGE_MASK)
-
 #define pte_clear(mm,addr,xp) pte_set_val(*(xp), (phys_t) 0, __pgprot(_PAGE_NEWPAGE))
 
 #define pmd_none(x)    (!((unsigned long)pmd_val(x) & ~_PAGE_NEWPAGE))
 #define        pmd_bad(x)      ((pmd_val(x) & (~PAGE_MASK & ~_PAGE_USER)) != _KERNPG_TABLE)
+
 #define pmd_present(x) (pmd_val(x) & _PAGE_PRESENT)
 #define pmd_clear(xp)  do { pmd_val(*(xp)) = _PAGE_NEWPAGE; } while (0)
 
@@ -149,14 +107,9 @@ extern unsigned long pg0[1024];
 #define pud_newpage(x)  (pud_val(x) & _PAGE_NEWPAGE)
 #define pud_mkuptodate(x) (pud_val(x) &= ~_PAGE_NEWPAGE)
 
-#define pages_to_mb(x) ((x) >> (20-PAGE_SHIFT))
-
 #define pmd_page(pmd) phys_to_page(pmd_val(pmd) & PAGE_MASK)
 
 #define pte_page(x) pfn_to_page(pte_pfn(x))
-#define pte_address(x) (__va(pte_val(x) & PAGE_MASK))
-#define mk_phys(a, r) ((a) + (((unsigned long) r) << REGION_SHIFT))
-#define phys_addr(p) ((p) & ~REGION_MASK)
 
 #define pte_present(x) pte_get_bits(x, (_PAGE_PRESENT | _PAGE_PROTNONE))
 
@@ -309,7 +262,8 @@ static inline void set_pte(pte_t *pteptr, pte_t pteval)
 
 #define phys_to_page(phys) pfn_to_page(phys_to_pfn(phys))
 #define __virt_to_page(virt) phys_to_page(__pa(virt))
-#define page_to_phys(page) pfn_to_phys(page_to_pfn(page))
+#define page_to_phys(page) pfn_to_phys((pfn_t) page_to_pfn(page))
+#define virt_to_page(addr) __virt_to_page((const unsigned long) addr)
 
 #define mk_pte(page, pgprot) \
        ({ pte_t pte;                                   \
@@ -325,8 +279,6 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
        return pte; 
 }
 
-#define pmd_page_vaddr(pmd) ((unsigned long) __va(pmd_val(pmd) & PAGE_MASK))
-
 /*
  * the pgd page can be thought of an array like this: pgd_t[PTRS_PER_PGD]
  *
@@ -335,8 +287,6 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
  */
 #define pgd_index(address) (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD-1))
 
-#define pgd_index_k(addr) pgd_index(addr)
-
 /*
  * pgd_offset() returns a (pgd_t *)
  * pgd_index() is used get the offset into the pgd page's array of pgd_t's;
@@ -355,8 +305,12 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
  * this macro returns the index of the entry in the pmd page which would
  * control the given virtual address
  */
+#define pmd_page_vaddr(pmd) ((unsigned long) __va(pmd_val(pmd) & PAGE_MASK))
 #define pmd_index(address) (((address) >> PMD_SHIFT) & (PTRS_PER_PMD-1))
 
+#define pmd_page_vaddr(pmd) \
+       ((unsigned long) __va(pmd_val(pmd) & PAGE_MASK))
+
 /*
  * the pte page can be thought of an array like this: pte_t[PTRS_PER_PTE]
  *
@@ -372,6 +326,9 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
 #define pte_unmap(pte) do { } while (0)
 #define pte_unmap_nested(pte) do { } while (0)
 
+struct mm_struct;
+extern pte_t *virt_to_pte(struct mm_struct *mm, unsigned long addr);
+
 #define update_mmu_cache(vma,address,pte) do ; while (0)
 
 /* Encode and de-code a swap entry */
@@ -388,29 +345,4 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
 
 #include <asm-generic/pgtable.h>
 
-#include <asm-generic/pgtable-nopud.h>
-
-#ifdef CONFIG_HIGHMEM
-/* Clear a kernel PTE and flush it from the TLB */
-#define kpte_clear_flush(ptep, vaddr)                                  \
-do {                                                                   \
-       pte_clear(&init_mm, vaddr, ptep);                               \
-       __flush_tlb_one(vaddr);                                         \
-} while (0)
 #endif
-
-#endif
-#endif
-
-#define virt_to_page(addr) __virt_to_page((const unsigned long) addr)
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
index 78c0599cc80c4da8e21d8c897a801560edbcb5e1..b7d9a16a74511d74194515042f703ecf940e5f24 100644 (file)
@@ -11,6 +11,7 @@ struct pt_regs;
 struct task_struct;
 
 #include "asm/ptrace.h"
+#include "asm/pgtable.h"
 #include "registers.h"
 #include "sysdep/archsetjmp.h"
 
@@ -26,7 +27,6 @@ struct thread_struct {
         * as of 2.6.11).
         */
        int forking;
-       int nsyscalls;
        struct pt_regs regs;
        int singlestep_syscall;
        void *fault_addr;
@@ -58,7 +58,6 @@ struct thread_struct {
 #define INIT_THREAD \
 { \
        .forking                = 0, \
-       .nsyscalls              = 0, \
        .regs                   = EMPTY_REGS,   \
        .fault_addr             = NULL, \
        .prev_sched             = NULL, \
@@ -68,10 +67,6 @@ struct thread_struct {
        .request                = { 0 } \
 }
 
-typedef struct {
-       unsigned long seg;
-} mm_segment_t;
-
 extern struct task_struct *alloc_task_struct(void);
 
 static inline void release_thread(struct task_struct *task)
@@ -97,9 +92,7 @@ static inline void mm_copy_segments(struct mm_struct *from_mm,
 /*
  * User space process size: 3GB (default).
  */
-extern unsigned long task_size;
-
-#define TASK_SIZE      (task_size)
+#define TASK_SIZE (CONFIG_TOP_ADDR & PGDIR_MASK)
 
 /* This decides where the kernel will search for a free chunk of vm
  * space during mmap's.
@@ -128,6 +121,6 @@ extern struct cpuinfo_um cpu_data[];
 
 
 #define KSTK_REG(tsk, reg) get_thread_reg(reg, &tsk->thread.switch_buf)
-#define get_wchan(p) (0)
+extern unsigned long get_wchan(struct task_struct *p);
 
 #endif
index 595f1c3e1e400607c0b318d5bd7590a124731808..a2b7fe13fe1e48179b1fd5f0eeff8315dcb15b0d 100644 (file)
@@ -10,7 +10,6 @@
 #include "asm/host_ldt.h"
 #include "asm/segment.h"
 
-extern int host_has_xmm;
 extern int host_has_cmov;
 
 /* include faultinfo structure */
index 6e5fd5c892d069439ed56191d837df54dd94dd58..356b83e2c22edf07c357e91c46469ad762968fb2 100644 (file)
@@ -1,5 +1,5 @@
-/* 
- * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+/*
+ * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
  * Licensed under the GPL
  */
 
@@ -8,8 +8,9 @@
 
 #ifndef __ASSEMBLY__
 
-#include <asm/processor.h>
 #include <asm/types.h>
+#include <asm/page.h>
+#include <asm/uaccess.h>
 
 struct thread_info {
        struct task_struct      *task;          /* main task structure */
@@ -75,8 +76,8 @@ static inline struct thread_info *current_thread_info(void)
 #define TIF_SYSCALL_TRACE      0       /* syscall trace active */
 #define TIF_SIGPENDING         1       /* signal pending */
 #define TIF_NEED_RESCHED       2       /* rescheduling necessary */
-#define TIF_POLLING_NRFLAG      3       /* true if poll_idle() is polling 
-                                        * TIF_NEED_RESCHED 
+#define TIF_POLLING_NRFLAG      3       /* true if poll_idle() is polling
+                                        * TIF_NEED_RESCHED
                                         */
 #define TIF_RESTART_BLOCK      4
 #define TIF_MEMDIE             5
index c640033bc1fd1e6e0750422aa1afd8f0428aebc6..39fc475df6c93ca135453f0ba6d44c8853f42d0c 100644 (file)
@@ -1,6 +1,126 @@
 #ifndef __UM_TLB_H
 #define __UM_TLB_H
 
-#include <asm/arch/tlb.h>
+#include <linux/swap.h>
+#include <asm/percpu.h>
+#include <asm/pgalloc.h>
+#include <asm/tlbflush.h>
+
+#define tlb_start_vma(tlb, vma) do { } while (0)
+#define tlb_end_vma(tlb, vma) do { } while (0)
+#define tlb_flush(tlb) flush_tlb_mm((tlb)->mm)
+
+/* struct mmu_gather is an opaque type used by the mm code for passing around
+ * any data needed by arch specific code for tlb_remove_page.
+ */
+struct mmu_gather {
+       struct mm_struct        *mm;
+       unsigned int            need_flush; /* Really unmapped some ptes? */
+       unsigned long           start;
+       unsigned long           end;
+       unsigned int            fullmm; /* non-zero means full mm flush */
+};
+
+/* Users of the generic TLB shootdown code must declare this storage space. */
+DECLARE_PER_CPU(struct mmu_gather, mmu_gathers);
+
+static inline void __tlb_remove_tlb_entry(struct mmu_gather *tlb, pte_t *ptep,
+                                         unsigned long address)
+{
+       if (tlb->start > address)
+               tlb->start = address;
+       if (tlb->end < address + PAGE_SIZE)
+               tlb->end = address + PAGE_SIZE;
+}
+
+static inline void init_tlb_gather(struct mmu_gather *tlb)
+{
+       tlb->need_flush = 0;
+
+       tlb->start = TASK_SIZE;
+       tlb->end = 0;
+
+       if (tlb->fullmm) {
+               tlb->start = 0;
+               tlb->end = TASK_SIZE;
+       }
+}
+
+/* tlb_gather_mmu
+ *     Return a pointer to an initialized struct mmu_gather.
+ */
+static inline struct mmu_gather *
+tlb_gather_mmu(struct mm_struct *mm, unsigned int full_mm_flush)
+{
+       struct mmu_gather *tlb = &get_cpu_var(mmu_gathers);
+
+       tlb->mm = mm;
+       tlb->fullmm = full_mm_flush;
+
+       init_tlb_gather(tlb);
+
+       return tlb;
+}
+
+extern void flush_tlb_mm_range(struct mm_struct *mm, unsigned long start,
+                              unsigned long end);
+
+static inline void
+tlb_flush_mmu(struct mmu_gather *tlb, unsigned long start, unsigned long end)
+{
+       if (!tlb->need_flush)
+               return;
+
+       flush_tlb_mm_range(tlb->mm, tlb->start, tlb->end);
+       init_tlb_gather(tlb);
+}
+
+/* tlb_finish_mmu
+ *     Called at the end of the shootdown operation to free up any resources
+ *     that were required.
+ */
+static inline void
+tlb_finish_mmu(struct mmu_gather *tlb, unsigned long start, unsigned long end)
+{
+       tlb_flush_mmu(tlb, start, end);
+
+       /* keep the page table cache within bounds */
+       check_pgt_cache();
+
+       put_cpu_var(mmu_gathers);
+}
+
+/* tlb_remove_page
+ *     Must perform the equivalent to __free_pte(pte_get_and_clear(ptep)),
+ *     while handling the additional races in SMP caused by other CPUs
+ *     caching valid mappings in their TLBs.
+ */
+static inline void tlb_remove_page(struct mmu_gather *tlb, struct page *page)
+{
+       tlb->need_flush = 1;
+       free_page_and_swap_cache(page);
+       return;
+}
+
+/**
+ * tlb_remove_tlb_entry - remember a pte unmapping for later tlb invalidation.
+ *
+ * Record the fact that pte's were really umapped in ->need_flush, so we can
+ * later optimise away the tlb invalidate.   This helps when userspace is
+ * unmapping already-unmapped pages, which happens quite a lot.
+ */
+#define tlb_remove_tlb_entry(tlb, ptep, address)               \
+       do {                                                    \
+               tlb->need_flush = 1;                            \
+               __tlb_remove_tlb_entry(tlb, ptep, address);     \
+       } while (0)
+
+#define pte_free_tlb(tlb, ptep) __pte_free_tlb(tlb, ptep)
+
+#define pud_free_tlb(tlb, pudp) __pud_free_tlb(tlb, pudp)
+
+#define pmd_free_tlb(tlb, pmdp) __pmd_free_tlb(tlb, pmdp)
+
+#define tlb_migrate_finish(mm) do {} while (0)
 
 #endif
index 077032d4fc47f13c167ea67463646d6519700b62..b9a895d6fa1df7cf0447573e58983f5b095e36d2 100644 (file)
@@ -6,7 +6,15 @@
 #ifndef __UM_UACCESS_H
 #define __UM_UACCESS_H
 
-#include "linux/sched.h"
+#include <asm/errno.h>
+#include <asm/processor.h>
+
+/* thread_info has a mm_segment_t in it, so put the definition up here */
+typedef struct {
+       unsigned long seg;
+} mm_segment_t;
+
+#include "linux/thread_info.h"
 
 #define VERIFY_READ 0
 #define VERIFY_WRITE 1
index a4c2493b025feffb3ddb596e4a0072c28b88eb89..e199a2bf12aa62d80e77ab2ccd02486a59269a29 100644 (file)
@@ -52,4 +52,6 @@
 #define SO_TIMESTAMPNS         35
 #define SCM_TIMESTAMPNS                SO_TIMESTAMPNS
 
+#define SO_MARK                        36
+
 #endif /* __V850_SOCKET_H__ */
index 1a6980a60fc6ef0717ed432480f06b7534e5328a..90dec0c236469455821607eca77a5a86684af6d2 100644 (file)
 
 #endif /* CONFIG_X86_32 */
 
+/* Exception table entry */
+# define _ASM_EXTABLE(from,to) \
+       " .section __ex_table,\"a\"\n" \
+       _ASM_ALIGN "\n" \
+       _ASM_PTR #from "," #to "\n" \
+       " .previous\n"
+
 #endif /* _ASM_X86_ASM_H */
index 48adbf56ca60c9f2d7da5954e3245188d6f8a2ea..aaf15194d536fc9dc2acd9e925db0bc999a9634b 100644 (file)
@@ -37,12 +37,6 @@ static inline long __scanbit(unsigned long val, unsigned long max)
   ((off)+(__scanbit(~(((*(unsigned long *)addr)) >> (off)),(size)-(off)))) : \
        find_next_zero_bit(addr,size,off)))
 
-/* 
- * Find string of zero bits in a bitmap. -1 when not found.
- */ 
-extern unsigned long 
-find_next_zero_string(unsigned long *bitmap, long start, long nbits, int len);
-
 static inline void set_bit_string(unsigned long *bitmap, unsigned long i, 
                                  int len) 
 { 
@@ -53,16 +47,6 @@ static inline void set_bit_string(unsigned long *bitmap, unsigned long i,
        }
 } 
 
-static inline void __clear_bit_string(unsigned long *bitmap, unsigned long i, 
-                                   int len) 
-{ 
-       unsigned long end = i + len; 
-       while (i < end) {
-               __clear_bit(i, bitmap); 
-               i++;
-       }
-} 
-
 /**
  * ffz - find first zero in word.
  * @word: The word to search
index 3fcc30dc07314ce0fc7460dfb956d260bf602829..021cbdd5f258a7739c2433d62f00a37a51070a4b 100644 (file)
@@ -2,6 +2,6 @@
 #define _ASM_X86_BUGS_H
 
 extern void check_bugs(void);
-extern int ppro_with_ram_bug(void);
+int ppro_with_ram_bug(void);
 
 #endif /* _ASM_X86_BUGS_H */
index b270ee04959ea7ce3fa73cf4935f39d9b7e0aa8b..d3e8f3e87ee8a876c413611fd2ae21fb0b6dbc63 100644 (file)
@@ -190,7 +190,7 @@ typedef struct user_regs_struct32 compat_elf_gregset_t;
  * A pointer passed in from user mode. This should not
  * be used for syscall parameters, just declare them
  * as pointers because the syscall entry code will have
- * appropriately comverted them already.
+ * appropriately converted them already.
  */
 typedef        u32             compat_uptr_t;
 
index 85ece5f10e9ee9b69807e32091114cedb32298fc..73f2ea84fd74b024fa4ebc8e91cabcdab4340108 100644 (file)
@@ -10,8 +10,9 @@
 struct x86_cpu {
        struct cpu cpu;
 };
-extern int arch_register_cpu(int num);
+
 #ifdef CONFIG_HOTPLUG_CPU
+extern int arch_register_cpu(int num);
 extern void arch_unregister_cpu(int);
 #endif
 
index 3fb7dfa7fc915b66f827c722ec31efc70cd63810..065e92966c7ccf966753ae03158eab9a8c3171e1 100644 (file)
@@ -4,9 +4,6 @@
 #ifndef _ASM_X86_CPUFEATURE_H
 #define _ASM_X86_CPUFEATURE_H
 
-#ifndef __ASSEMBLY__
-#include <linux/bitops.h>
-#endif
 #include <asm/required-features.h>
 
 #define NCAPINTS       8       /* N 32-bit words worth of info */
@@ -49,6 +46,7 @@
 #define X86_FEATURE_MP         (1*32+19) /* MP Capable. */
 #define X86_FEATURE_NX         (1*32+20) /* Execute Disable */
 #define X86_FEATURE_MMXEXT     (1*32+22) /* AMD MMX extensions */
+#define X86_FEATURE_GBPAGES    (1*32+26) /* GB pages */
 #define X86_FEATURE_RDTSCP     (1*32+27) /* RDTSCP */
 #define X86_FEATURE_LM         (1*32+29) /* Long Mode (x86-64) */
 #define X86_FEATURE_3DNOWEXT   (1*32+30) /* AMD 3DNow! extensions */
  */
 #define X86_FEATURE_IDA                (7*32+ 0) /* Intel Dynamic Acceleration */
 
+#if defined(__KERNEL__) && !defined(__ASSEMBLY__)
+
+#include <linux/bitops.h>
+
+extern const char * const x86_cap_flags[NCAPINTS*32];
+extern const char * const x86_power_flags[32];
+
 #define cpu_has(c, bit)                                                        \
        (__builtin_constant_p(bit) &&                                   \
         ( (((bit)>>5)==0 && (1UL<<((bit)&31) & REQUIRED_MASK0)) ||     \
 #define cpu_has_pebs           boot_cpu_has(X86_FEATURE_PEBS)
 #define cpu_has_clflush                boot_cpu_has(X86_FEATURE_CLFLSH)
 #define cpu_has_bts            boot_cpu_has(X86_FEATURE_BTS)
+#define cpu_has_gbpages                boot_cpu_has(X86_FEATURE_GBPAGES)
 
 #if defined(CONFIG_X86_INVLPG) || defined(CONFIG_X86_64)
 # define cpu_has_invlpg                1
 
 #endif /* CONFIG_X86_64 */
 
+#endif /* defined(__KERNEL__) && !defined(__ASSEMBLY__) */
+
 #endif /* _ASM_X86_CPUFEATURE_H */
index 51e4170f9ca54e021f83b431977d0dbe7c6da3ba..a560c4f5d500f658901fb4d44bade9dd1acdcaec 100644 (file)
@@ -15,7 +15,7 @@
 
 #ifndef __ASSEMBLY__
 extern unsigned long find_e820_area(unsigned long start, unsigned long end, 
-                                   unsigned size);
+                                   unsigned size, unsigned long align);
 extern void add_memory_region(unsigned long start, unsigned long size, 
                              int type);
 extern void setup_memory_region(void);
@@ -41,7 +41,7 @@ extern void finish_e820_parsing(void);
 extern struct e820map e820;
 extern void update_e820(void);
 
-extern void reserve_early(unsigned long start, unsigned long end);
+extern void reserve_early(unsigned long start, unsigned long end, char *name);
 extern void early_res_to_bootmem(void);
 
 #endif/*!__ASSEMBLY__*/
index 9c68a1f098d8cb12af04bacd1564909b179aca61..ea9734b74aca235b33e98a33fbe54a99feeb9fbd 100644 (file)
@@ -33,7 +33,7 @@ extern unsigned long asmlinkage efi_call_phys(void *, ...);
 #define efi_call_virt6(f, a1, a2, a3, a4, a5, a6)      \
        efi_call_virt(f, a1, a2, a3, a4, a5, a6)
 
-#define efi_ioremap(addr, size)                        ioremap(addr, size)
+#define efi_ioremap(addr, size)                        ioremap_cache(addr, size)
 
 #else /* !CONFIG_X86_32 */
 
@@ -86,7 +86,7 @@ extern u64 efi_call6(void *fp, u64 arg1, u64 arg2, u64 arg3,
        efi_call6((void *)(efi.systab->runtime->f), (u64)(a1), (u64)(a2), \
                  (u64)(a3), (u64)(a4), (u64)(a5), (u64)(a6))
 
-extern void *efi_ioremap(unsigned long offset, unsigned long size);
+extern void *efi_ioremap(unsigned long addr, unsigned long size);
 
 #endif /* CONFIG_X86_32 */
 
index 62828d63f1b1d4bc6d79281f3095ca546d8db9ac..cd9f894dd2d7c778fe4d85fdeb0f83168a16804d 100644 (file)
 "2:    .section .fixup,\"ax\"\n                                \
 3:     mov     %3, %1\n                                        \
        jmp     2b\n                                            \
-       .previous\n                                             \
-       .section __ex_table,\"a\"\n                             \
-       .align  8\n"                                            \
-       _ASM_PTR "1b,3b\n                                       \
-       .previous"                                              \
+       .previous\n"                                            \
+       _ASM_EXTABLE(1b,3b)                                     \
        : "=r" (oldval), "=r" (ret), "+m" (*uaddr)              \
        : "i" (-EFAULT), "0" (oparg), "1" (0))
 
 "1:    movl    %2, %0\n                                        \
        movl    %0, %3\n"                                       \
        insn "\n"                                               \
-"2:    " LOCK_PREFIX "cmpxchgl %3, %2\n                        \
+"2:    lock; cmpxchgl %3, %2\n                                 \
        jnz     1b\n                                            \
 3:     .section .fixup,\"ax\"\n                                \
 4:     mov     %5, %1\n                                        \
        jmp     3b\n                                            \
-       .previous\n                                             \
-       .section __ex_table,\"a\"\n                             \
-       .align  8\n"                                            \
-       _ASM_PTR "1b,4b,2b,4b\n                                 \
-       .previous"                                              \
+       .previous\n"                                            \
+       _ASM_EXTABLE(1b,4b)                                     \
+       _ASM_EXTABLE(2b,4b)                                     \
        : "=&a" (oldval), "=&r" (ret), "+m" (*uaddr),           \
          "=&r" (tem)                                           \
        : "r" (oparg), "i" (-EFAULT), "1" (0))
@@ -72,7 +67,7 @@ futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
                __futex_atomic_op1("xchgl %0, %2", ret, oldval, uaddr, oparg);
                break;
        case FUTEX_OP_ADD:
-               __futex_atomic_op1(LOCK_PREFIX "xaddl %0, %2", ret, oldval,
+               __futex_atomic_op1("lock; xaddl %0, %2", ret, oldval,
                                   uaddr, oparg);
                break;
        case FUTEX_OP_OR:
@@ -111,18 +106,12 @@ futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
                return -EFAULT;
 
        __asm__ __volatile__(
-               "1:     " LOCK_PREFIX "cmpxchgl %3, %1          \n"
-
+               "1:     lock; cmpxchgl %3, %1                   \n"
                "2:     .section .fixup, \"ax\"                 \n"
                "3:     mov     %2, %0                          \n"
                "       jmp     2b                              \n"
                "       .previous                               \n"
-
-               "       .section __ex_table, \"a\"              \n"
-               "       .align  8                               \n"
-                       _ASM_PTR " 1b,3b                        \n"
-               "       .previous                               \n"
-
+               _ASM_EXTABLE(1b,3b)
                : "=a" (oldval), "+m" (*uaddr)
                : "i" (-EFAULT), "r" (newval), "0" (oldval)
                : "memory"
index 13cdcd66fff213dd6515ee0eb1eda411eb71eb73..479767c9195fcd36ced65ec1c8e5e66872b3e56c 100644 (file)
@@ -38,11 +38,6 @@ extern pte_t *pkmap_page_table;
  * easily, subsequent pte tables have to be allocated in one physical
  * chunk of RAM.
  */
-#ifdef CONFIG_X86_PAE
-#define LAST_PKMAP 512
-#else
-#define LAST_PKMAP 1024
-#endif
 /*
  * Ordering is:
  *
@@ -58,13 +53,12 @@ extern pte_t *pkmap_page_table;
  * VMALLOC_START
  * high_memory
  */
-#define PKMAP_BASE ( (FIXADDR_BOOT_START - PAGE_SIZE*(LAST_PKMAP + 1)) & PMD_MASK )
 #define LAST_PKMAP_MASK (LAST_PKMAP-1)
 #define PKMAP_NR(virt)  ((virt-PKMAP_BASE) >> PAGE_SHIFT)
 #define PKMAP_ADDR(nr)  (PKMAP_BASE + ((nr) << PAGE_SHIFT))
 
-extern void * FASTCALL(kmap_high(struct page *page));
-extern void FASTCALL(kunmap_high(struct page *page));
+extern void *kmap_high(struct page *page);
+extern void kunmap_high(struct page *page);
 
 void *kmap(struct page *page);
 void kunmap(struct page *page);
index 6d65fbb6358b0d91692da95313fd09c5ee3c8690..ea88054e03f373a3a909c1c697c6e4d5fa61d9de 100644 (file)
@@ -47,7 +47,7 @@ void enable_8259A_irq(unsigned int irq);
 int i8259A_irq_pending(unsigned int irq);
 void make_8259A_irq(unsigned int irq);
 void init_8259A(int aeoi);
-void FASTCALL(send_IPI_self(int vector));
+void send_IPI_self(int vector);
 void init_VISWS_APIC_irqs(void);
 void setup_IO_APIC(void);
 void disable_IO_APIC(void);
index ba8105ca822b99840f6bcf91b23e9d7f0c34902f..6b1895ccd6b78854bd3dc9f7f710ea1bc24ff9bb 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/sched.h>
 #include <linux/kernel_stat.h>
 #include <linux/regset.h>
+#include <asm/asm.h>
 #include <asm/processor.h>
 #include <asm/sigcontext.h>
 #include <asm/user.h>
@@ -41,10 +42,7 @@ static inline void tolerant_fwait(void)
 {
        asm volatile("1: fwait\n"
                     "2:\n"
-                    "   .section __ex_table,\"a\"\n"
-                    "  .align 8\n"
-                    "  .quad 1b,2b\n"
-                    "  .previous\n");
+                    _ASM_EXTABLE(1b,2b));
 }
 
 static inline int restore_fpu_checking(struct i387_fxsave_struct *fx)
@@ -57,10 +55,7 @@ static inline int restore_fpu_checking(struct i387_fxsave_struct *fx)
                     "3:  movl $-1,%[err]\n"
                     "    jmp  2b\n"
                     ".previous\n"
-                    ".section __ex_table,\"a\"\n"
-                    "   .align 8\n"
-                    "   .quad  1b,3b\n"
-                    ".previous"
+                    _ASM_EXTABLE(1b,3b)
                     : [err] "=r" (err)
 #if 0 /* See comment in __save_init_fpu() below. */
                     : [fx] "r" (fx), "m" (*fx), "0" (0));
@@ -99,10 +94,7 @@ static inline int save_i387_checking(struct i387_fxsave_struct __user *fx)
                     "3:  movl $-1,%[err]\n"
                     "    jmp  2b\n"
                     ".previous\n"
-                    ".section __ex_table,\"a\"\n"
-                    "   .align 8\n"
-                    "   .quad  1b,3b\n"
-                    ".previous"
+                    _ASM_EXTABLE(1b,3b)
                     : [err] "=r" (err), "=m" (*fx)
 #if 0 /* See comment in __fxsave_clear() below. */
                     : [fx] "r" (fx), "0" (0));
index 586d7aa54cebcaa2f629c112bbc88a4d077e9c21..58d2c45cd0b1bf0e2ddfacfc176f01a91c691045 100644 (file)
@@ -275,29 +275,6 @@ static inline void slow_down_io(void) {
 
 #endif
 
-#ifdef CONFIG_X86_NUMAQ
-extern void *xquad_portio;    /* Where the IO area was mapped */
-#define XQUAD_PORT_ADDR(port, quad) (xquad_portio + (XQUAD_PORTIO_QUAD*quad) + port)
-#define __BUILDIO(bwl,bw,type) \
-static inline void out##bwl##_quad(unsigned type value, int port, int quad) { \
-       if (xquad_portio) \
-               write##bwl(value, XQUAD_PORT_ADDR(port, quad)); \
-       else \
-               out##bwl##_local(value, port); \
-} \
-static inline void out##bwl(unsigned type value, int port) { \
-       out##bwl##_quad(value, port, 0); \
-} \
-static inline unsigned type in##bwl##_quad(int port, int quad) { \
-       if (xquad_portio) \
-               return read##bwl(XQUAD_PORT_ADDR(port, quad)); \
-       else \
-               return in##bwl##_local(port); \
-} \
-static inline unsigned type in##bwl(int port) { \
-       return in##bwl##_quad(port, 0); \
-}
-#else
 #define __BUILDIO(bwl,bw,type) \
 static inline void out##bwl(unsigned type value, int port) { \
        out##bwl##_local(value, port); \
@@ -305,8 +282,6 @@ static inline void out##bwl(unsigned type value, int port) { \
 static inline unsigned type in##bwl(int port) { \
        return in##bwl##_local(port); \
 }
-#endif
-
 
 #define BUILDIO(bwl,bw,type) \
 static inline void out##bwl##_local(unsigned type value, int port) { \
index 17e183bd39c1395d044489f58f17a09bbefe0e89..3b637fac890b8da769ab398cbe02d6dfe1a54d55 100644 (file)
@@ -109,6 +109,8 @@ static inline int mpc_apic_id(struct mpc_config_processor *m,
        return logical_apicid;
 }
 
+extern void *xquad_portio;
+
 static inline void setup_portio_remap(void)
 {
        int num_quads = num_online_nodes();
index bc2b5892630859f8c42441204d2beec90a2151dd..9e5a459fd15b2f13e5e1e266999a08ef49a3026e 100644 (file)
@@ -6,7 +6,6 @@
 
 /**
  * do_timer_interrupt_hook - hook into timer tick
- * @regs:     standard registers from interrupt
  *
  * Call the pit clock event handler. see asm/i8253.h
  **/
index 204a8a30fecf8e9669aae32b6f6db83852cb694b..3ca29ebebbb18dd8f7547eab749a94f0ce157874 100644 (file)
@@ -57,10 +57,7 @@ static inline unsigned long long native_read_msr_safe(unsigned int msr,
                     ".section .fixup,\"ax\"\n\t"
                     "3:  mov %3,%0 ; jmp 1b\n\t"
                     ".previous\n\t"
-                    ".section __ex_table,\"a\"\n"
-                    _ASM_ALIGN "\n\t"
-                    _ASM_PTR " 2b,3b\n\t"
-                    ".previous"
+                    _ASM_EXTABLE(2b,3b)
                     : "=r" (*err), EAX_EDX_RET(val, low, high)
                     : "c" (msr), "i" (-EFAULT));
        return EAX_EDX_VAL(val, low, high);
@@ -81,10 +78,7 @@ static inline int native_write_msr_safe(unsigned int msr,
                     ".section .fixup,\"ax\"\n\t"
                     "3:  mov %4,%0 ; jmp 1b\n\t"
                     ".previous\n\t"
-                    ".section __ex_table,\"a\"\n"
-                    _ASM_ALIGN "\n\t"
-                    _ASM_PTR " 2b,3b\n\t"
-                    ".previous"
+                    _ASM_EXTABLE(2b,3b)
                     : "=a" (err)
                     : "c" (msr), "0" (low), "d" (high),
                       "i" (-EFAULT));
index c8b30efeed85c6354d229a18d1d14bae2c206a87..1cb7c51bc2966fd1986684b9c87da245610f5d6b 100644 (file)
@@ -13,8 +13,8 @@
 #define PHYSICAL_PAGE_MASK     (PAGE_MASK & __PHYSICAL_MASK)
 #define PTE_MASK               (_AT(long, PHYSICAL_PAGE_MASK))
 
-#define LARGE_PAGE_SIZE                (_AC(1,UL) << PMD_SHIFT)
-#define LARGE_PAGE_MASK                (~(LARGE_PAGE_SIZE-1))
+#define PMD_PAGE_SIZE          (_AC(1, UL) << PMD_SHIFT)
+#define PMD_PAGE_MASK          (~(PMD_PAGE_SIZE-1))
 
 #define HPAGE_SHIFT            PMD_SHIFT
 #define HPAGE_SIZE             (_AC(1,UL) << HPAGE_SHIFT)
index c1ac42d8707f34fe374c6063cc37503b7e4647f4..dcf0c0746075ba07f4527f2018bb846f8ebf8424 100644 (file)
@@ -23,6 +23,9 @@
 #define MCE_STACK 5
 #define N_EXCEPTION_STACKS 5  /* hw limit: 7 */
 
+#define PUD_PAGE_SIZE          (_AC(1, UL) << PUD_SHIFT)
+#define PUD_PAGE_MASK          (~(PUD_PAGE_SIZE-1))
+
 #define __PAGE_OFFSET           _AC(0xffff810000000000, UL)
 
 #define __PHYSICAL_START       CONFIG_PHYSICAL_START
index 10c2b452e64c87b4a1abf0d8058e4d48eabbc5a5..bab12718a913fa446f25c8c9e6e2b2d380e3761a 100644 (file)
@@ -3,6 +3,7 @@
 
 #include <linux/threads.h>
 #include <linux/mm.h>          /* for struct page */
+#include <linux/pagemap.h>
 #include <asm/tlb.h>
 #include <asm-generic/tlb.h>
 
@@ -35,27 +36,23 @@ static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd, struct page *p
  * Allocate and free page tables.
  */
 extern pgd_t *pgd_alloc(struct mm_struct *);
-extern void pgd_free(pgd_t *pgd);
+extern void pgd_free(struct mm_struct *mm, pgd_t *pgd);
 
 extern pte_t *pte_alloc_one_kernel(struct mm_struct *, unsigned long);
 extern struct page *pte_alloc_one(struct mm_struct *, unsigned long);
 
-static inline void pte_free_kernel(pte_t *pte)
+static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte)
 {
        free_page((unsigned long)pte);
 }
 
-static inline void pte_free(struct page *pte)
+static inline void pte_free(struct mm_struct *mm, struct page *pte)
 {
        __free_page(pte);
 }
 
 
-static inline void __pte_free_tlb(struct mmu_gather *tlb, struct page *pte)
-{
-       paravirt_release_pt(page_to_pfn(pte));
-       tlb_remove_page(tlb, pte);
-}
+extern void __pte_free_tlb(struct mmu_gather *tlb, struct page *pte);
 
 #ifdef CONFIG_X86_PAE
 /*
@@ -66,24 +63,13 @@ static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long addr)
        return (pmd_t *)get_zeroed_page(GFP_KERNEL|__GFP_REPEAT);
 }
 
-static inline void pmd_free(pmd_t *pmd)
+static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd)
 {
        BUG_ON((unsigned long)pmd & (PAGE_SIZE-1));
        free_page((unsigned long)pmd);
 }
 
-static inline void __pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmd)
-{
-       /* This is called just after the pmd has been detached from
-          the pgd, which requires a full tlb flush to be recognized
-          by the CPU.  Rather than incurring multiple tlb flushes
-          while the address space is being pulled down, make the tlb
-          gathering machinery do a full flush when we're done. */
-       tlb->fullmm = 1;
-
-       paravirt_release_pd(__pa(pmd) >> PAGE_SHIFT);
-       tlb_remove_page(tlb, virt_to_page(pmd));
-}
+extern void __pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmd);
 
 static inline void pud_populate(struct mm_struct *mm, pud_t *pudp, pmd_t *pmd)
 {
@@ -94,8 +80,10 @@ static inline void pud_populate(struct mm_struct *mm, pud_t *pudp, pmd_t *pmd)
        set_pud(pudp, __pud(__pa(pmd) | _PAGE_PRESENT));
 
        /*
-        * Pentium-II erratum A13: in PAE mode we explicitly have to flush
-        * the TLB via cr3 if the top-level pgd is changed...
+        * According to Intel App note "TLBs, Paging-Structure Caches,
+        * and Their Invalidation", April 2007, document 317080-001,
+        * section 8.1: in PAE mode we explicitly have to flush the
+        * TLB via cr3 if the top-level pgd is changed...
         */
        if (mm == current->active_mm)
                write_cr3(read_cr3());
index 8bb5646878602f3731e345b46a80486f593e1640..315314ce4bfb4f4e14499741e838184f825e3cf7 100644 (file)
@@ -17,7 +17,7 @@ static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd, struct page *p
        set_pmd(pmd, __pmd(_PAGE_TABLE | (page_to_pfn(pte) << PAGE_SHIFT)));
 }
 
-static inline void pmd_free(pmd_t *pmd)
+static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd)
 {
        BUG_ON((unsigned long)pmd & (PAGE_SIZE-1));
        free_page((unsigned long)pmd);
@@ -33,7 +33,7 @@ static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long addr)
        return (pud_t *)get_zeroed_page(GFP_KERNEL|__GFP_REPEAT);
 }
 
-static inline void pud_free (pud_t *pud)
+static inline void pud_free(struct mm_struct *mm, pud_t *pud)
 {
        BUG_ON((unsigned long)pud & (PAGE_SIZE-1));
        free_page((unsigned long)pud);
@@ -77,7 +77,7 @@ static inline pgd_t *pgd_alloc(struct mm_struct *mm)
        return pgd;
 }
 
-static inline void pgd_free(pgd_t *pgd)
+static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd)
 {
        BUG_ON((unsigned long)pgd & (PAGE_SIZE-1));
        pgd_list_del(pgd);
@@ -100,13 +100,13 @@ static inline struct page *pte_alloc_one(struct mm_struct *mm, unsigned long add
 /* Should really implement gc for free page table pages. This could be
    done with a reference count in struct page. */
 
-static inline void pte_free_kernel(pte_t *pte)
+static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte)
 {
        BUG_ON((unsigned long)pte & (PAGE_SIZE-1));
        free_page((unsigned long)pte); 
 }
 
-static inline void pte_free(struct page *pte)
+static inline void pte_free(struct mm_struct *mm, struct page *pte)
 {
        __free_page(pte);
 } 
index a195c3e757b9ef95931d4c7341fdd2ab02d44464..1d763eec740ff882c329889db1a9ae7006ac8817 100644 (file)
@@ -93,26 +93,22 @@ static inline void native_pmd_clear(pmd_t *pmd)
 
 static inline void pud_clear(pud_t *pudp)
 {
+       unsigned long pgd;
+
        set_pud(pudp, __pud(0));
 
        /*
-        * In principle we need to do a cr3 reload here to make sure
-        * the processor recognizes the changed pgd.  In practice, all
-        * the places where pud_clear() gets called are followed by
-        * full tlb flushes anyway, so we can defer the cost here.
-        *
-        * Specifically:
-        *
-        * mm/memory.c:free_pmd_range() - immediately after the
-        * pud_clear() it does a pmd_free_tlb().  We change the
-        * mmu_gather structure to do a full tlb flush (which has the
-        * effect of reloading cr3) when the pagetable free is
-        * complete.
+        * According to Intel App note "TLBs, Paging-Structure Caches,
+        * and Their Invalidation", April 2007, document 317080-001,
+        * section 8.1: in PAE mode we explicitly have to flush the
+        * TLB via cr3 if the top-level pgd is changed...
         *
-        * arch/x86/mm/hugetlbpage.c:huge_pmd_unshare() - the call to
-        * this is followed by a flush_tlb_range, which on x86 does a
-        * full tlb flush.
+        * Make sure the pud entry we're updating is within the
+        * current pgd to avoid unnecessary TLB flushes.
         */
+       pgd = read_cr3();
+       if (__pa(pudp) >= pgd && __pa(pudp) < (pgd + sizeof(pgd_t)*PTRS_PER_PGD))
+               write_cr3(pgd);
 }
 
 #define pud_page(pud) \
index cd2524f074525968a01917d9495711948e0c487d..44c0a4f1b1eb64d10bd1e33013b7e52a3dcc55f1 100644 (file)
 #define _PAGE_BIT_DIRTY                6
 #define _PAGE_BIT_FILE         6
 #define _PAGE_BIT_PSE          7       /* 4 MB (or 2MB) page */
+#define _PAGE_BIT_PAT          7       /* on 4KB pages */
 #define _PAGE_BIT_GLOBAL       8       /* Global TLB entry PPro+ */
 #define _PAGE_BIT_UNUSED1      9       /* available for programmer */
 #define _PAGE_BIT_UNUSED2      10
 #define _PAGE_BIT_UNUSED3      11
+#define _PAGE_BIT_PAT_LARGE    12      /* On 2MB or 1GB pages */
 #define _PAGE_BIT_NX           63       /* No execute: only valid after cpuid check */
 
 /*
@@ -36,6 +38,8 @@
 #define _PAGE_UNUSED1  (_AC(1, L)<<_PAGE_BIT_UNUSED1)
 #define _PAGE_UNUSED2  (_AC(1, L)<<_PAGE_BIT_UNUSED2)
 #define _PAGE_UNUSED3  (_AC(1, L)<<_PAGE_BIT_UNUSED3)
+#define _PAGE_PAT      (_AC(1, L)<<_PAGE_BIT_PAT)
+#define _PAGE_PAT_LARGE (_AC(1, L)<<_PAGE_BIT_PAT_LARGE)
 
 #if defined(CONFIG_X86_64) || defined(CONFIG_X86_PAE)
 #define _PAGE_NX       (_AC(1, ULL) << _PAGE_BIT_NX)
index 21e70fbf1dae55cae5ab87cd19c4cbaba3dc57b7..80dd438642f69b293e5aa090d9fb222d5f3c2db1 100644 (file)
@@ -66,6 +66,14 @@ void paging_init(void);
 #define VMALLOC_OFFSET (8*1024*1024)
 #define VMALLOC_START  (((unsigned long) high_memory + \
                        2*VMALLOC_OFFSET-1) & ~(VMALLOC_OFFSET-1))
+#ifdef CONFIG_X86_PAE
+#define LAST_PKMAP 512
+#else
+#define LAST_PKMAP 1024
+#endif
+
+#define PKMAP_BASE ((FIXADDR_BOOT_START - PAGE_SIZE*(LAST_PKMAP + 1)) & PMD_MASK)
+
 #ifdef CONFIG_HIGHMEM
 # define VMALLOC_END   (PKMAP_BASE-2*PAGE_SIZE)
 #else
@@ -148,6 +156,8 @@ static inline void clone_pgd_range(pgd_t *dst, pgd_t *src, int count)
  */
 #define pgd_offset_k(address) pgd_offset(&init_mm, address)
 
+static inline int pud_large(pud_t pud) { return 0; }
+
 /*
  * the pmd page can be thought of an array like this: pmd_t[PTRS_PER_PMD]
  *
index 6e615a103c2ff485fdd59b18b081243325baf114..bd4740a60f29b5c288eebd6f8e379c9259099aba 100644 (file)
@@ -21,7 +21,6 @@ extern pgd_t init_level4_pgt[];
 #define swapper_pg_dir init_level4_pgt
 
 extern void paging_init(void);
-extern void clear_kernel_mapping(unsigned long addr, unsigned long size);
 
 #endif /* !__ASSEMBLY__ */
 
@@ -199,6 +198,12 @@ static inline unsigned long pmd_bad(pmd_t pmd)
 #define pud_offset(pgd, address) ((pud_t *) pgd_page_vaddr(*(pgd)) + pud_index(address))
 #define pud_present(pud) (pud_val(pud) & _PAGE_PRESENT)
 
+static inline int pud_large(pud_t pte)
+{
+       return (pud_val(pte) & (_PAGE_PSE|_PAGE_PRESENT)) ==
+               (_PAGE_PSE|_PAGE_PRESENT);
+}
+
 /* PMD  - Level 2 access */
 #define pmd_page_vaddr(pmd) ((unsigned long) __va(pmd_val(pmd) & PTE_MASK))
 #define pmd_page(pmd)          (pfn_to_page(pmd_val(pmd) >> PAGE_SHIFT))
index 99ca648b94c54122057342ec4bcef093b0d0fbe6..80af9c4ccad7f05cd09db4d0d212ec2a0753ed04 100644 (file)
@@ -52,4 +52,6 @@
 #define SO_TIMESTAMPNS         35
 #define SCM_TIMESTAMPNS                SO_TIMESTAMPNS
 
+#define SO_MARK                        36
+
 #endif /* _ASM_SOCKET_H */
index 55bfa308f900c831733f91018a0f68111aa35e6e..c5d13a86dea7faa61c8cf75deede797b22c4e640 100644 (file)
@@ -213,14 +213,14 @@ static __always_inline void * __constant_c_and_count_memset(void * s, unsigned l
                case 0:
                        return s;
                case 1:
-                       *(unsigned char *)s = pattern;
+                       *(unsigned char *)s = pattern & 0xff;
                        return s;
                case 2:
-                       *(unsigned short *)s = pattern;
+                       *(unsigned short *)s = pattern & 0xffff;
                        return s;
                case 3:
-                       *(unsigned short *)s = pattern;
-                       *(2+(unsigned char *)s) = pattern;
+                       *(unsigned short *)s = pattern & 0xffff;
+                       *(2+(unsigned char *)s) = pattern & 0xff;
                        return s;
                case 4:
                        *(unsigned long *)s = pattern;
index ee32ef9367f4f25b1c87bf435d2c80ed8586c9c9..9cff02ffe6c2d261e6c905fe6f0d9958ccaf2fbb 100644 (file)
@@ -20,8 +20,8 @@
 #ifdef CONFIG_X86_32
 
 struct task_struct; /* one of the stranger aspects of C forward declarations */
-extern struct task_struct *FASTCALL(__switch_to(struct task_struct *prev,
-                                               struct task_struct *next));
+struct task_struct *__switch_to(struct task_struct *prev,
+                               struct task_struct *next);
 
 /*
  * Saving eflags is important. It switches not only IOPL between tasks,
@@ -130,10 +130,7 @@ extern void load_gs_index(unsigned);
                "movl %k1, %%" #seg "\n\t"      \
                "jmp 2b\n"                      \
                ".previous\n"                   \
-               ".section __ex_table,\"a\"\n\t" \
-               _ASM_ALIGN "\n\t"               \
-               _ASM_PTR " 1b,3b\n"             \
-               ".previous"                     \
+               _ASM_EXTABLE(1b,3b)             \
                : :"r" (value), "r" (0))
 
 
@@ -214,12 +211,10 @@ static inline unsigned long native_read_cr4_safe(void)
        /* This could fault if %cr4 does not exist. In x86_64, a cr4 always
         * exists, so it will never fail. */
 #ifdef CONFIG_X86_32
-       asm volatile("1: mov %%cr4, %0          \n"
-               "2:                             \n"
-               ".section __ex_table,\"a\"      \n"
-               ".long 1b,2b                    \n"
-               ".previous                      \n"
-               : "=r" (val), "=m" (__force_order) : "0" (0));
+       asm volatile("1: mov %%cr4, %0\n"
+                    "2:\n"
+                    _ASM_EXTABLE(1b,2b)
+                    : "=r" (val), "=m" (__force_order) : "0" (0));
 #else
        val = native_read_cr4();
 #endif
@@ -276,9 +271,9 @@ static inline void native_wbinvd(void)
 
 #endif /* __KERNEL__ */
 
-static inline void clflush(void *__p)
+static inline void clflush(volatile void *__p)
 {
-       asm volatile("clflush %0" : "+m" (*(char __force *)__p));
+       asm volatile("clflush %0" : "+m" (*(volatile char __force *)__p));
 }
 
 #define nop() __asm__ __volatile__ ("nop")
index 9b531ea015a83a491ed810acaaed074c6069a76b..6c9b214b8fc3481c3f58ca784d3b6ba67e7a5610 100644 (file)
@@ -123,8 +123,8 @@ static inline struct thread_info *stack_thread_info(void)
 #define TIF_FREEZE             23      /* is freezing for suspend */
 #define TIF_FORCED_TF          24      /* true if TF in eflags artificially */
 #define TIF_DEBUGCTLMSR                25      /* uses thread_struct.debugctlmsr */
-#define TIF_DS_AREA_MSR        25      /* uses thread_struct.ds_area_msr */
-#define TIF_BTS_TRACE_TS       26      /* record scheduling event timestamps */
+#define TIF_DS_AREA_MSR                26      /* uses thread_struct.ds_area_msr */
+#define TIF_BTS_TRACE_TS       27      /* record scheduling event timestamps */
 
 #define _TIF_SYSCALL_TRACE     (1<<TIF_SYSCALL_TRACE)
 #define _TIF_SIGPENDING                (1<<TIF_SIGPENDING)
index d2a4f7be9c2c5ee3a1516b0b5bf636addc2cefac..fcc570ec4feed9107f4910da8e6a4939df3d2824 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/thread_info.h>
 #include <linux/prefetch.h>
 #include <linux/string.h>
+#include <asm/asm.h>
 #include <asm/page.h>
 
 #define VERIFY_READ 0
@@ -287,11 +288,8 @@ extern void __put_user_8(void);
                "4:     movl %3,%0\n"                           \
                "       jmp 3b\n"                               \
                ".previous\n"                                   \
-               ".section __ex_table,\"a\"\n"                   \
-               "       .align 4\n"                             \
-               "       .long 1b,4b\n"                          \
-               "       .long 2b,4b\n"                          \
-               ".previous"                                     \
+               _ASM_EXTABLE(1b,4b)                             \
+               _ASM_EXTABLE(2b,4b)                             \
                : "=r"(err)                                     \
                : "A" (x), "r" (addr), "i"(-EFAULT), "0"(err))
 
@@ -338,10 +336,7 @@ struct __large_struct { unsigned long buf[100]; };
                "3:     movl %3,%0\n"                                   \
                "       jmp 2b\n"                                       \
                ".previous\n"                                           \
-               ".section __ex_table,\"a\"\n"                           \
-               "       .align 4\n"                                     \
-               "       .long 1b,3b\n"                                  \
-               ".previous"                                             \
+               _ASM_EXTABLE(1b,3b)                                     \
                : "=r"(err)                                             \
                : ltype (x), "m"(__m(addr)), "i"(errret), "0"(err))
 
@@ -378,10 +373,7 @@ do {                                                                       \
                "       xor"itype" %"rtype"1,%"rtype"1\n"               \
                "       jmp 2b\n"                                       \
                ".previous\n"                                           \
-               ".section __ex_table,\"a\"\n"                           \
-               "       .align 4\n"                                     \
-               "       .long 1b,3b\n"                                  \
-               ".previous"                                             \
+               _ASM_EXTABLE(1b,3b)                                     \
                : "=r"(err), ltype (x)                                  \
                : "m"(__m(addr)), "i"(errret), "0"(err))
 
index 31d79470271942af7e4f8449294761b0d383b619..b87eb4ba8f9d6e20ff345eda0fcc78e88a807df5 100644 (file)
@@ -181,10 +181,7 @@ struct __large_struct { unsigned long buf[100]; };
                "3:     mov %3,%0\n"                            \
                "       jmp 2b\n"                               \
                ".previous\n"                                   \
-               ".section __ex_table,\"a\"\n"                   \
-               "       .align 8\n"                             \
-               "       .quad 1b,3b\n"                          \
-               ".previous"                                     \
+               _ASM_EXTABLE(1b,3b)                             \
                : "=r"(err)                                     \
                : ltype (x), "m"(__m(addr)), "i"(errno), "0"(err))
 
@@ -226,10 +223,7 @@ do {                                                                       \
                "       xor"itype" %"rtype"1,%"rtype"1\n"       \
                "       jmp 2b\n"                               \
                ".previous\n"                                   \
-               ".section __ex_table,\"a\"\n"                   \
-               "       .align 8\n"                             \
-               "       .quad 1b,3b\n"                          \
-               ".previous"                                     \
+               _ASM_EXTABLE(1b,3b)                             \
                : "=r"(err), ltype (x)                          \
                : "m"(__m(addr)), "i"(errno), "0"(err))
 
index 8d8f9b5adbb971a740ccf73476df86c280dd5d89..984123a68f7cc164ec78c540241546c469dbf295 100644 (file)
 #define __NR_epoll_pwait       319
 #define __NR_utimensat         320
 #define __NR_signalfd          321
-#define __NR_timerfd           322
+#define __NR_timerfd_create    322
 #define __NR_eventfd           323
 #define __NR_fallocate         324
+#define __NR_timerfd_settime   325
+#define __NR_timerfd_gettime   326
 
 #ifdef __KERNEL__
 
index 5ff4d3e24c348814e04a329ee5dc71c96a696784..3883ceb54ef5c144f1de6035ba670d5628a3e1cb 100644 (file)
@@ -629,12 +629,17 @@ __SYSCALL(__NR_utimensat, sys_utimensat)
 __SYSCALL(__NR_epoll_pwait, sys_epoll_pwait)
 #define __NR_signalfd                          282
 __SYSCALL(__NR_signalfd, sys_signalfd)
-#define __NR_timerfd                           283
-__SYSCALL(__NR_timerfd, sys_timerfd)
+#define __NR_timerfd_create                    283
+__SYSCALL(__NR_timerfd_create, sys_timerfd_create)
 #define __NR_eventfd                           284
 __SYSCALL(__NR_eventfd, sys_eventfd)
 #define __NR_fallocate                         285
 __SYSCALL(__NR_fallocate, sys_fallocate)
+#define __NR_timerfd_settime                   286
+__SYSCALL(__NR_timerfd_settime, sys_timerfd_settime)
+#define __NR_timerfd_gettime                   287
+__SYSCALL(__NR_timerfd_gettime, sys_timerfd_gettime)
+
 
 #ifndef __NO_STUBS
 #define __ARCH_WANT_OLD_READDIR
index a5edf517b992d51a3689cb1539a7dd12f1368c13..c92fe4af52e891a42b6c7907d78e0338eafa5918 100644 (file)
@@ -195,6 +195,7 @@ struct kernel_vm86_struct {
 
 void handle_vm86_fault(struct kernel_vm86_regs *, long);
 int handle_vm86_trap(struct kernel_vm86_regs *, long, int);
+struct pt_regs *save_v86_state(struct kernel_vm86_regs *);
 
 struct task_struct;
 void release_vm86_irqs(struct task_struct *);
index 3e5b5652510239b081db16e3f54102289bee6cdd..1d51ba5463f9f2f215015c598b5ef51bb7ff06f2 100644 (file)
@@ -31,7 +31,7 @@ pgd_alloc(struct mm_struct *mm)
        return (pgd_t*) __get_free_pages(GFP_KERNEL | __GFP_ZERO, PGD_ORDER);
 }
 
-static inline void pgd_free(pgd_t *pgd)
+static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd)
 {
        free_page((unsigned long)pgd);
 }
@@ -52,12 +52,12 @@ static inline struct page *pte_alloc_one(struct mm_struct *mm,
        return virt_to_page(pte_alloc_one_kernel(mm, addr));
 }
 
-static inline void pte_free_kernel(pte_t *pte)
+static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte)
 {
        kmem_cache_free(pgtable_cache, pte);
 }
 
-static inline void pte_free(struct page *page)
+static inline void pte_free(struct mm_struct *mm, struct page *page)
 {
        kmem_cache_free(pgtable_cache, page_address(page));
 }
index 1f5aeacb9da27ead7b2623a74f7a557717bfc2c0..6100682b1da22248debf67ccf0cfca02a524180f 100644 (file)
@@ -63,4 +63,6 @@
 #define SO_TIMESTAMPNS         35
 #define SCM_TIMESTAMPNS                SO_TIMESTAMPNS
 
+#define SO_MARK                        36
+
 #endif /* _XTENSA_SOCKET_H */
index 4830232017aff0766c99b83a7cc185acf473f919..31c220faca02ac9cbb3695f735e0221bdc32104a 100644 (file)
@@ -42,6 +42,6 @@
 
 #include <asm-generic/tlb.h>
 
-#define __pte_free_tlb(tlb,pte)                        pte_free(pte)
+#define __pte_free_tlb(tlb, pte)               pte_free((tlb)->mm, pte)
 
 #endif /* _XTENSA_TLB_H */
index 85b2482cc736c782307c99afd26a7b1f834f38d9..93631229fd5c89e70c378f26d30b72c72d112e02 100644 (file)
@@ -143,6 +143,7 @@ header-y += snmp.h
 header-y += sockios.h
 header-y += som.h
 header-y += sound.h
+header-y += suspend_ioctls.h
 header-y += taskstats.h
 header-y += telephony.h
 header-y += termios.h
@@ -218,6 +219,7 @@ unifdef-y += i2c-dev.h
 unifdef-y += icmp.h
 unifdef-y += icmpv6.h
 unifdef-y += if_addr.h
+unifdef-y += if_addrlabel.h
 unifdef-y += if_arp.h
 unifdef-y += if_bridge.h
 unifdef-y += if_ec.h
index abc521cfb08464a7e5a9c3cf11ca60d80f0529af..03e34547d489132632b6a15b2286c7dc2ac8ffa5 100644 (file)
@@ -109,6 +109,7 @@ extern int agp_unbind_memory(struct agp_memory *);
 extern void agp_enable(struct agp_bridge_data *, u32);
 extern struct agp_bridge_data *agp_backend_acquire(struct pci_dev *);
 extern void agp_backend_release(struct agp_bridge_data *);
+extern void agp_flush_chipset(struct agp_bridge_data *);
 
 #endif                         /* __KERNEL__ */
 #endif                         /* _AGP_BACKEND_H */
index 09fbf7e5a6cbbbba0b3fe6991f4aefa494e937a4..62aef589eb940936d6adb53889165b4e1f17dba2 100644 (file)
@@ -38,6 +38,7 @@
 #define AGPIOC_DEALLOCATE _IOW (AGPIOC_BASE, 7, int)
 #define AGPIOC_BIND       _IOW (AGPIOC_BASE, 8, struct agp_bind*)
 #define AGPIOC_UNBIND     _IOW (AGPIOC_BASE, 9, struct agp_unbind*)
+#define AGPIOC_CHIPSET_FLUSH _IO (AGPIOC_BASE, 10)
 
 #define AGP_DEVICE      "/dev/agpgart"
 
similarity index 99%
rename from drivers/serial/atmel_serial.h
rename to include/linux/atmel_serial.h
index e0141776517c4fec9714d0077a8dac21d5f0c851..fd6833764d72b3bf77788741c6e85309b5aa6a72 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * drivers/serial/atmel_serial.h
+ * include/linux/atmel_serial.h
  *
  * Copyright (C) 2005 Ivan Kokshaysky
  * Copyright (C) SAN People
index bdd6f5de5fc4bb654f489dab723e3cb09f66f3d0..97153027207a27d3ded23f099c105321613c9372 100644 (file)
@@ -98,6 +98,7 @@
 #define AUDIT_FD_PAIR          1317    /* audit record for pipe/socketpair */
 #define AUDIT_OBJ_PID          1318    /* ptrace target */
 #define AUDIT_TTY              1319    /* Input on an administrative TTY */
+#define AUDIT_EOE              1320    /* End of multi-record event */
 
 #define AUDIT_AVC              1400    /* SE Linux avc denial or grant */
 #define AUDIT_SELINUX_ERR      1401    /* Internal SE Linux Errors */
@@ -409,7 +410,8 @@ extern unsigned int audit_serial(void);
 extern void auditsc_get_stamp(struct audit_context *ctx,
                              struct timespec *t, unsigned int *serial);
 extern int  audit_set_loginuid(struct task_struct *task, uid_t loginuid);
-extern uid_t audit_get_loginuid(struct audit_context *ctx);
+#define audit_get_loginuid(t) ((t)->loginuid)
+#define audit_get_sessionid(t) ((t)->sessionid)
 extern void audit_log_task_context(struct audit_buffer *ab);
 extern int __audit_ipc_obj(struct kern_ipc_perm *ipcp);
 extern int __audit_ipc_set_perm(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode);
@@ -488,7 +490,8 @@ extern int audit_signals;
 #define audit_inode_child(d,i,p) do { ; } while (0)
 #define audit_core_dumps(i) do { ; } while (0)
 #define auditsc_get_stamp(c,t,s) do { BUG(); } while (0)
-#define audit_get_loginuid(c) ({ -1; })
+#define audit_get_loginuid(t) (-1)
+#define audit_get_sessionid(t) (-1)
 #define audit_log_task_context(b) do { ; } while (0)
 #define audit_ipc_obj(i) ({ 0; })
 #define audit_ipc_set_perm(q,u,g,m) ({ 0; })
@@ -522,9 +525,11 @@ extern void                    audit_log_end(struct audit_buffer *ab);
 extern void                audit_log_hex(struct audit_buffer *ab,
                                          const unsigned char *buf,
                                          size_t len);
-extern const char *        audit_log_untrustedstring(struct audit_buffer *ab,
+extern int                 audit_string_contains_control(const char *string,
+                                                         size_t len);
+extern void                audit_log_untrustedstring(struct audit_buffer *ab,
                                                      const char *string);
-extern const char *        audit_log_n_untrustedstring(struct audit_buffer *ab,
+extern void                audit_log_n_untrustedstring(struct audit_buffer *ab,
                                                        size_t n,
                                                        const char *string);
 extern void                audit_log_d_path(struct audit_buffer *ab,
index e18d4192f6e83992278f344ab7d4f7f885595dcd..90392a9d7a9c782f3745db67b89b03bd67ba588c 100644 (file)
@@ -39,7 +39,6 @@ void exit_io_context(void);
 struct io_context *get_io_context(gfp_t gfp_flags, int node);
 struct io_context *alloc_io_context(gfp_t gfp_flags, int node);
 void copy_io_context(struct io_context **pdst, struct io_context **psrc);
-void swap_io_context(struct io_context **ioc1, struct io_context **ioc2);
 
 struct request;
 typedef void (rq_end_io_fn)(struct request *, int);
@@ -655,15 +654,18 @@ static inline void blk_run_address_space(struct address_space *mapping)
  * blk_end_request() for parts of the original function.
  * This prevents code duplication in drivers.
  */
-extern int blk_end_request(struct request *rq, int error, int nr_bytes);
-extern int __blk_end_request(struct request *rq, int error, int nr_bytes);
-extern int blk_end_bidi_request(struct request *rq, int error, int nr_bytes,
-                               int bidi_bytes);
+extern int blk_end_request(struct request *rq, int error,
+                               unsigned int nr_bytes);
+extern int __blk_end_request(struct request *rq, int error,
+                               unsigned int nr_bytes);
+extern int blk_end_bidi_request(struct request *rq, int error,
+                               unsigned int nr_bytes, unsigned int bidi_bytes);
 extern void end_request(struct request *, int);
 extern void end_queued_request(struct request *, int);
 extern void end_dequeued_request(struct request *, int);
-extern int blk_end_request_callback(struct request *rq, int error, int nr_bytes,
-                                   int (drv_callback)(struct request *));
+extern int blk_end_request_callback(struct request *rq, int error,
+                               unsigned int nr_bytes,
+                               int (drv_callback)(struct request *));
 extern void blk_complete_request(struct request *);
 
 /*
index bb017edffd56816099064f7367f925c15277aa09..7d50ff6d269fc6eb75d298e36140dfc012a8daf5 100644 (file)
@@ -14,7 +14,6 @@
 #define _LINUX_CAPABILITY_H
 
 #include <linux/types.h>
-#include <linux/compiler.h>
 
 struct task_struct;
 
@@ -23,13 +22,20 @@ struct task_struct;
    kernel might be somewhat backwards compatible, but don't bet on
    it. */
 
-/* XXX - Note, cap_t, is defined by POSIX to be an "opaque" pointer to
+/* Note, cap_t, is defined by POSIX (draft) to be an "opaque" pointer to
    a set of three capability sets.  The transposition of 3*the
    following structure to such a composite is better handled in a user
    library since the draft standard requires the use of malloc/free
    etc.. */
 
-#define _LINUX_CAPABILITY_VERSION  0x19980330
+#define _LINUX_CAPABILITY_VERSION_1  0x19980330
+#define _LINUX_CAPABILITY_U32S_1     1
+
+#define _LINUX_CAPABILITY_VERSION_2  0x20071026
+#define _LINUX_CAPABILITY_U32S_2     2
+
+#define _LINUX_CAPABILITY_VERSION    _LINUX_CAPABILITY_VERSION_2
+#define _LINUX_CAPABILITY_U32S       _LINUX_CAPABILITY_U32S_2
 
 typedef struct __user_cap_header_struct {
        __u32 version;
@@ -42,41 +48,42 @@ typedef struct __user_cap_data_struct {
         __u32 inheritable;
 } __user *cap_user_data_t;
 
+
 #define XATTR_CAPS_SUFFIX "capability"
 #define XATTR_NAME_CAPS XATTR_SECURITY_PREFIX XATTR_CAPS_SUFFIX
 
-#define XATTR_CAPS_SZ (3*sizeof(__le32))
 #define VFS_CAP_REVISION_MASK  0xFF000000
+#define VFS_CAP_FLAGS_MASK     ~VFS_CAP_REVISION_MASK
+#define VFS_CAP_FLAGS_EFFECTIVE        0x000001
+
 #define VFS_CAP_REVISION_1     0x01000000
+#define VFS_CAP_U32_1           1
+#define XATTR_CAPS_SZ_1         (sizeof(__le32)*(1 + 2*VFS_CAP_U32_1))
 
-#define VFS_CAP_REVISION       VFS_CAP_REVISION_1
+#define VFS_CAP_REVISION_2     0x02000000
+#define VFS_CAP_U32_2           2
+#define XATTR_CAPS_SZ_2         (sizeof(__le32)*(1 + 2*VFS_CAP_U32_2))
+
+#define XATTR_CAPS_SZ           XATTR_CAPS_SZ_2
+#define VFS_CAP_U32             VFS_CAP_U32_2
+#define VFS_CAP_REVISION       VFS_CAP_REVISION_2
 
-#define VFS_CAP_FLAGS_MASK     ~VFS_CAP_REVISION_MASK
-#define VFS_CAP_FLAGS_EFFECTIVE        0x000001
 
 struct vfs_cap_data {
-       __u32 magic_etc;  /* Little endian */
-       __u32 permitted;    /* Little endian */
-       __u32 inheritable;  /* Little endian */
+       __le32 magic_etc;            /* Little endian */
+       struct {
+               __le32 permitted;    /* Little endian */
+               __le32 inheritable;  /* Little endian */
+       } data[VFS_CAP_U32];
 };
 
 #ifdef __KERNEL__
 
-/* #define STRICT_CAP_T_TYPECHECKS */
-
-#ifdef STRICT_CAP_T_TYPECHECKS
-
 typedef struct kernel_cap_struct {
-       __u32 cap;
+       __u32 cap[_LINUX_CAPABILITY_U32S];
 } kernel_cap_t;
 
-#else
-
-typedef __u32 kernel_cap_t;
-
-#endif
-
-#define _USER_CAP_HEADER_SIZE  (2*sizeof(__u32))
+#define _USER_CAP_HEADER_SIZE  (sizeof(struct __user_cap_header_struct))
 #define _KERNEL_CAP_T_SIZE     (sizeof(kernel_cap_t))
 
 #endif
@@ -119,10 +126,6 @@ typedef __u32 kernel_cap_t;
 
 #define CAP_FSETID           4
 
-/* Used to decide between falling back on the old suser() or fsuser(). */
-
-#define CAP_FS_MASK          0x1f
-
 /* Overrides the restriction that the real or effective user ID of a
    process sending a signal must match the real or effective user ID
    of the process receiving the signal. */
@@ -145,8 +148,14 @@ typedef __u32 kernel_cap_t;
  ** Linux-specific capabilities
  **/
 
-/* Transfer any capability in your permitted set to any pid,
-   remove any capability in your permitted set from any pid */
+/* Without VFS support for capabilities:
+ *   Transfer any capability in your permitted set to any pid,
+ *   remove any capability in your permitted set from any pid
+ * With VFS support for capabilities (neither of above, but)
+ *   Add any capability from current's capability bounding set
+ *       to the current process' inheritable set
+ *   Allow taking bits out of capability bounding set
+ */
 
 #define CAP_SETPCAP          8
 
@@ -195,7 +204,6 @@ typedef __u32 kernel_cap_t;
 #define CAP_IPC_OWNER        15
 
 /* Insert and remove kernel modules - modify kernel without limit */
-/* Modify cap_bset */
 #define CAP_SYS_MODULE       16
 
 /* Allow ioperm/iopl access */
@@ -307,74 +315,183 @@ typedef __u32 kernel_cap_t;
 
 #define CAP_SETFCAP         31
 
+/* Override MAC access.
+   The base kernel enforces no MAC policy.
+   An LSM may enforce a MAC policy, and if it does and it chooses
+   to implement capability based overrides of that policy, this is
+   the capability it should use to do so. */
+
+#define CAP_MAC_OVERRIDE     32
+
+/* Allow MAC configuration or state changes.
+   The base kernel requires no MAC configuration.
+   An LSM may enforce a MAC policy, and if it does and it chooses
+   to implement capability based checks on modifications to that
+   policy or the data required to maintain it, this is the
+   capability it should use to do so. */
+
+#define CAP_MAC_ADMIN        33
+
+#define CAP_LAST_CAP         CAP_MAC_ADMIN
+
+#define cap_valid(x) ((x) >= 0 && (x) <= CAP_LAST_CAP)
+
+/*
+ * Bit location of each capability (used by user-space library and kernel)
+ */
+
+#define CAP_TO_INDEX(x)     ((x) >> 5)        /* 1 << 5 == bits in __u32 */
+#define CAP_TO_MASK(x)      (1 << ((x) & 31)) /* mask for indexed __u32 */
+
 #ifdef __KERNEL__
 
 /*
  * Internal kernel functions only
  */
 
-#ifdef STRICT_CAP_T_TYPECHECKS
+#define CAP_FOR_EACH_U32(__capi)  \
+       for (__capi = 0; __capi < _LINUX_CAPABILITY_U32S; ++__capi)
+
+# define CAP_FS_MASK_B0     (CAP_TO_MASK(CAP_CHOWN)            \
+                           | CAP_TO_MASK(CAP_DAC_OVERRIDE)     \
+                           | CAP_TO_MASK(CAP_DAC_READ_SEARCH)  \
+                           | CAP_TO_MASK(CAP_FOWNER)           \
+                           | CAP_TO_MASK(CAP_FSETID))
+
+# define CAP_FS_MASK_B1     (CAP_TO_MASK(CAP_MAC_OVERRIDE))
+
+#if _LINUX_CAPABILITY_U32S != 2
+# error Fix up hand-coded capability macro initializers
+#else /* HAND-CODED capability initializers */
+
+# define CAP_EMPTY_SET    {{ 0, 0 }}
+# define CAP_FULL_SET     {{ ~0, ~0 }}
+# define CAP_INIT_EFF_SET {{ ~CAP_TO_MASK(CAP_SETPCAP), ~0 }}
+# define CAP_FS_SET       {{ CAP_FS_MASK_B0, CAP_FS_MASK_B1 } }
+# define CAP_NFSD_SET     {{ CAP_FS_MASK_B0|CAP_TO_MASK(CAP_SYS_RESOURCE), \
+                            CAP_FS_MASK_B1 } }
+
+#endif /* _LINUX_CAPABILITY_U32S != 2 */
+
+#define CAP_INIT_INH_SET    CAP_EMPTY_SET
+
+# define cap_clear(c)         do { (c) = __cap_empty_set; } while (0)
+# define cap_set_full(c)      do { (c) = __cap_full_set; } while (0)
+# define cap_set_init_eff(c)  do { (c) = __cap_init_eff_set; } while (0)
+
+#define cap_raise(c, flag)  ((c).cap[CAP_TO_INDEX(flag)] |= CAP_TO_MASK(flag))
+#define cap_lower(c, flag)  ((c).cap[CAP_TO_INDEX(flag)] &= ~CAP_TO_MASK(flag))
+#define cap_raised(c, flag) ((c).cap[CAP_TO_INDEX(flag)] & CAP_TO_MASK(flag))
+
+#define CAP_BOP_ALL(c, a, b, OP)                                    \
+do {                                                                \
+       unsigned __capi;                                            \
+       CAP_FOR_EACH_U32(__capi) {                                  \
+               c.cap[__capi] = a.cap[__capi] OP b.cap[__capi];     \
+       }                                                           \
+} while (0)
+
+#define CAP_UOP_ALL(c, a, OP)                                       \
+do {                                                                \
+       unsigned __capi;                                            \
+       CAP_FOR_EACH_U32(__capi) {                                  \
+               c.cap[__capi] = OP a.cap[__capi];                   \
+       }                                                           \
+} while (0)
+
+static inline kernel_cap_t cap_combine(const kernel_cap_t a,
+                                      const kernel_cap_t b)
+{
+       kernel_cap_t dest;
+       CAP_BOP_ALL(dest, a, b, |);
+       return dest;
+}
 
-#define to_cap_t(x) { x }
-#define cap_t(x) (x).cap
+static inline kernel_cap_t cap_intersect(const kernel_cap_t a,
+                                        const kernel_cap_t b)
+{
+       kernel_cap_t dest;
+       CAP_BOP_ALL(dest, a, b, &);
+       return dest;
+}
 
-#else
+static inline kernel_cap_t cap_drop(const kernel_cap_t a,
+                                   const kernel_cap_t drop)
+{
+       kernel_cap_t dest;
+       CAP_BOP_ALL(dest, a, drop, &~);
+       return dest;
+}
 
-#define to_cap_t(x) (x)
-#define cap_t(x) (x)
+static inline kernel_cap_t cap_invert(const kernel_cap_t c)
+{
+       kernel_cap_t dest;
+       CAP_UOP_ALL(dest, c, ~);
+       return dest;
+}
 
-#endif
+static inline int cap_isclear(const kernel_cap_t a)
+{
+       unsigned __capi;
+       CAP_FOR_EACH_U32(__capi) {
+               if (a.cap[__capi] != 0)
+                       return 0;
+       }
+       return 1;
+}
 
-#define CAP_EMPTY_SET       to_cap_t(0)
-#define CAP_FULL_SET        to_cap_t(~0)
-#define CAP_INIT_EFF_SET    to_cap_t(~0 & ~CAP_TO_MASK(CAP_SETPCAP))
-#define CAP_INIT_INH_SET    to_cap_t(0)
+static inline int cap_issubset(const kernel_cap_t a, const kernel_cap_t set)
+{
+       kernel_cap_t dest;
+       dest = cap_drop(a, set);
+       return cap_isclear(dest);
+}
 
-#define CAP_TO_MASK(x) (1 << (x))
-#define cap_raise(c, flag)   (cap_t(c) |=  CAP_TO_MASK(flag))
-#define cap_lower(c, flag)   (cap_t(c) &= ~CAP_TO_MASK(flag))
-#define cap_raised(c, flag)  (cap_t(c) & CAP_TO_MASK(flag))
+/* Used to decide between falling back on the old suser() or fsuser(). */
 
-static inline kernel_cap_t cap_combine(kernel_cap_t a, kernel_cap_t b)
+static inline int cap_is_fs_cap(int cap)
 {
-     kernel_cap_t dest;
-     cap_t(dest) = cap_t(a) | cap_t(b);
-     return dest;
+       const kernel_cap_t __cap_fs_set = CAP_FS_SET;
+       return !!(CAP_TO_MASK(cap) & __cap_fs_set.cap[CAP_TO_INDEX(cap)]);
 }
 
-static inline kernel_cap_t cap_intersect(kernel_cap_t a, kernel_cap_t b)
+static inline kernel_cap_t cap_drop_fs_set(const kernel_cap_t a)
 {
-     kernel_cap_t dest;
-     cap_t(dest) = cap_t(a) & cap_t(b);
-     return dest;
+       const kernel_cap_t __cap_fs_set = CAP_FS_SET;
+       return cap_drop(a, __cap_fs_set);
 }
 
-static inline kernel_cap_t cap_drop(kernel_cap_t a, kernel_cap_t drop)
+static inline kernel_cap_t cap_raise_fs_set(const kernel_cap_t a,
+                                           const kernel_cap_t permitted)
 {
-     kernel_cap_t dest;
-     cap_t(dest) = cap_t(a) & ~cap_t(drop);
-     return dest;
+       const kernel_cap_t __cap_fs_set = CAP_FS_SET;
+       return cap_combine(a,
+                          cap_intersect(permitted, __cap_fs_set));
 }
 
-static inline kernel_cap_t cap_invert(kernel_cap_t c)
+static inline kernel_cap_t cap_drop_nfsd_set(const kernel_cap_t a)
 {
-     kernel_cap_t dest;
-     cap_t(dest) = ~cap_t(c);
-     return dest;
+       const kernel_cap_t __cap_fs_set = CAP_NFSD_SET;
+       return cap_drop(a, __cap_fs_set);
 }
 
-#define cap_isclear(c)       (!cap_t(c))
-#define cap_issubset(a,set)  (!(cap_t(a) & ~cap_t(set)))
-
-#define cap_clear(c)         do { cap_t(c) =  0; } while(0)
-#define cap_set_full(c)      do { cap_t(c) = ~0; } while(0)
-#define cap_mask(c,mask)     do { cap_t(c) &= cap_t(mask); } while(0)
+static inline kernel_cap_t cap_raise_nfsd_set(const kernel_cap_t a,
+                                             const kernel_cap_t permitted)
+{
+       const kernel_cap_t __cap_nfsd_set = CAP_NFSD_SET;
+       return cap_combine(a,
+                          cap_intersect(permitted, __cap_nfsd_set));
+}
 
-#define cap_is_fs_cap(c)     (CAP_TO_MASK(c) & CAP_FS_MASK)
+extern const kernel_cap_t __cap_empty_set;
+extern const kernel_cap_t __cap_full_set;
+extern const kernel_cap_t __cap_init_eff_set;
 
 int capable(int cap);
 int __capable(struct task_struct *t, int cap);
 
+extern long cap_prctl_drop(unsigned long cap);
+
 #endif /* __KERNEL__ */
 
 #endif /* !_LINUX_CAPABILITY_H */
index fcdc11b9609b7c2efc4318811375a30574d7c586..a5cd2047624ef4e721914e52cf051521c134f704 100644 (file)
@@ -1187,6 +1187,20 @@ struct media_event_desc {
 
 extern int cdrom_get_media_event(struct cdrom_device_info *cdi, struct media_event_desc *med);
 
+static inline void lba_to_msf(int lba, u8 *m, u8 *s, u8 *f)
+{
+       lba += CD_MSF_OFFSET;
+       lba &= 0xffffff;  /* negative lbas use only 24 bits */
+       *m = lba / (CD_SECS * CD_FRAMES);
+       lba %= (CD_SECS * CD_FRAMES);
+       *s = lba / CD_FRAMES;
+       *f = lba % CD_FRAMES;
+}
+
+static inline int msf_to_lba(u8 m, u8 s, u8 f)
+{
+       return (((m * CD_SECS) + s) * CD_FRAMES + f) - CD_MSF_OFFSET;
+}
 #endif  /* End of kernel only stuff */ 
 
 #endif  /* _LINUX_CDROM_H */
index a404c111c937a2da3dcddba17f7aba0a63e82cb4..519248d8b2b6529f3ec8833d09d0bf97710a5fac 100644 (file)
@@ -108,7 +108,7 @@ struct changer_element_status {
 
 /*
  * CHIOGELEM
- *    get more detailed status informtion for a single element
+ *    get more detailed status information for a single element
  */
 struct changer_get_element {
        int     cge_type;        /* type/unit */
index d38655f2be7088e3bce8d63476ec525fdf347511..ae0a483bef9bd8a004c2058da2e828d2a0d8b7b5 100644 (file)
@@ -279,8 +279,11 @@ asmlinkage long compat_sys_utimensat(unsigned int dfd, char __user *filename,
 asmlinkage long compat_sys_signalfd(int ufd,
                                const compat_sigset_t __user *sigmask,
                                 compat_size_t sigsetsize);
-asmlinkage long compat_sys_timerfd(int ufd, int clockid, int flags,
-                               const struct compat_itimerspec __user *utmr);
+asmlinkage long compat_sys_timerfd_settime(int ufd, int flags,
+                                  const struct compat_itimerspec __user *utmr,
+                                  struct compat_itimerspec __user *otmr);
+asmlinkage long compat_sys_timerfd_gettime(int ufd,
+                                  struct compat_itimerspec __user *otmr);
 
 #endif /* CONFIG_COMPAT */
 #endif /* _LINUX_COMPAT_H */
index 33d6aaf944472db15ec205cc2624c2074338e2b0..d2961b66d53dbab52a3f69cd30a441725c4000ee 100644 (file)
@@ -44,6 +44,7 @@ static inline void init_completion(struct completion *x)
 
 extern void wait_for_completion(struct completion *);
 extern int wait_for_completion_interruptible(struct completion *x);
+extern int wait_for_completion_killable(struct completion *x);
 extern unsigned long wait_for_completion_timeout(struct completion *x,
                                                   unsigned long timeout);
 extern unsigned long wait_for_completion_interruptible_timeout(
index 8f3dcd30828fbb149ef7ee30c788ebf2e312e6e6..504cb2c3fa9a68fb77a0a4b3afb94a933c095f9c 100644 (file)
@@ -177,7 +177,7 @@ struct      CUSTOM_REG {
        __u32   fpga_version;           /* FPGA Version Number Register */
        __u32   cpu_start;              /* CPU start Register (write) */
        __u32   cpu_stop;               /* CPU stop Register (write) */
-       __u32   misc_reg;               /* Miscelaneous Register */
+       __u32   misc_reg;               /* Miscellaneous Register */
        __u32   idt_mode;               /* IDT mode Register */
        __u32   uart_irq_status;        /* UART IRQ status Register */
        __u32   clear_timer0_irq;       /* Clear timer interrupt Register */
index f7a9065834636c5824677d274beee1fc2d5f192d..362bf19d6cf194a8ae40f84632debc34aac218f0 100644 (file)
@@ -81,7 +81,7 @@ struct cycx_x25_cmd {
  *     @n2win - level 2 window (values: 1 thru 7)
  *     @n3win - level 3 window (values: 1 thru 7)
  *     @nvc - # of logical channels (values: 1 thru 64)
- *     @pktlen - level 3 packet lenght - log base 2 of size
+ *     @pktlen - level 3 packet length - log base 2 of size
  *     @locaddr - my address
  *     @remaddr - remote address
  *     @t1 - time, in seconds
index 484e45c7c89a832dd986c7fe927e545168e2ec77..aa0737019e37da6e759ea95e026088cbbfc6518d 100644 (file)
@@ -525,6 +525,7 @@ struct dccp_sock {
        __u64                           dccps_gsr;
        __u64                           dccps_gar;
        __be32                          dccps_service;
+       __u32                           dccps_mss_cache;
        struct dccp_service_list        *dccps_service_list;
        __u32                           dccps_timestamp_echo;
        __u32                           dccps_timestamp_time;
@@ -533,7 +534,6 @@ struct dccp_sock {
        __u16                           dccps_pcslen;
        __u16                           dccps_pcrlen;
        unsigned long                   dccps_ndp_count;
-       __u32                           dccps_mss_cache;
        unsigned long                   dccps_rate_last;
        struct dccp_minisock            dccps_minisock;
        struct dccp_ackvec              *dccps_hc_rx_ackvec;
index db375be333c708a2e556c5424c95a0aa91802836..2258d89bf5236fed75a7ce231c50fb25c088fb26 100644 (file)
@@ -410,6 +410,15 @@ extern int devres_release_group(struct device *dev, void *id);
 extern void *devm_kzalloc(struct device *dev, size_t size, gfp_t gfp);
 extern void devm_kfree(struct device *dev, void *p);
 
+struct device_dma_parameters {
+       /*
+        * a low level driver may set these to teach IOMMU code about
+        * sg limitations.
+        */
+       unsigned int max_segment_size;
+       unsigned long segment_boundary_mask;
+};
+
 struct device {
        struct klist            klist_children;
        struct klist_node       knode_parent;   /* node in sibling list */
@@ -445,6 +454,8 @@ struct device {
                                             64 bit addresses for consistent
                                             allocations such descriptors. */
 
+       struct device_dma_parameters *dma_parms;
+
        struct list_head        dma_pools;      /* dma pools (if dma'ble) */
 
        struct dma_coherent_mem *dma_mem; /* internal for coherent mem
@@ -534,11 +545,17 @@ extern struct device *device_create(struct class *cls, struct device *parent,
 extern void device_destroy(struct class *cls, dev_t devt);
 #ifdef CONFIG_PM_SLEEP
 extern void destroy_suspended_device(struct class *cls, dev_t devt);
+extern void device_pm_schedule_removal(struct device *);
 #else /* !CONFIG_PM_SLEEP */
 static inline void destroy_suspended_device(struct class *cls, dev_t devt)
 {
        device_destroy(cls, devt);
 }
+
+static inline void device_pm_schedule_removal(struct device *dev)
+{
+       device_unregister(dev);
+}
 #endif /* !CONFIG_PM_SLEEP */
 
 /*
index 101a2d4636befbd1248b7642c38a87ff77243f07..3320307096237a61495d785d751e897bc54a0102 100644 (file)
@@ -1,5 +1,5 @@
-#ifndef _ASM_LINUX_DMA_MAPPING_H
-#define _ASM_LINUX_DMA_MAPPING_H
+#ifndef _LINUX_DMA_MAPPING_H
+#define _LINUX_DMA_MAPPING_H
 
 #include <linux/device.h>
 #include <linux/err.h>
@@ -60,6 +60,36 @@ static inline int is_device_dma_capable(struct device *dev)
 
 extern u64 dma_get_required_mask(struct device *dev);
 
+static inline unsigned int dma_get_max_seg_size(struct device *dev)
+{
+       return dev->dma_parms ? dev->dma_parms->max_segment_size : 65536;
+}
+
+static inline unsigned int dma_set_max_seg_size(struct device *dev,
+                                               unsigned int size)
+{
+       if (dev->dma_parms) {
+               dev->dma_parms->max_segment_size = size;
+               return 0;
+       } else
+               return -EIO;
+}
+
+static inline unsigned long dma_get_seg_boundary(struct device *dev)
+{
+       return dev->dma_parms ?
+               dev->dma_parms->segment_boundary_mask : 0xffffffff;
+}
+
+static inline int dma_set_seg_boundary(struct device *dev, unsigned long mask)
+{
+       if (dev->dma_parms) {
+               dev->dma_parms->segment_boundary_mask = mask;
+               return 0;
+       } else
+               return -EIO;
+}
+
 /* flags for the coherent memory api */
 #define        DMA_MEMORY_MAP                  0x01
 #define DMA_MEMORY_IO                  0x02
index 55c9a6952f447c6284a5b75b88ac9696ddc89214..5c84bf8975939d254f62595e9c4cc0795c8d3c96 100644 (file)
@@ -29,7 +29,7 @@
 #include <linux/dma-mapping.h>
 
 /**
- * enum dma_state - resource PNP/power managment state
+ * enum dma_state - resource PNP/power management state
  * @DMA_RESOURCE_SUSPEND: DMA device going into low power state
  * @DMA_RESOURCE_RESUME: DMA device returning to full power
  * @DMA_RESOURCE_AVAILABLE: DMA device available to the system
index 71d4ada6f31549342d75dbc50dd10045c43e3e17..fcbe8b640ffba57f04a35c986728bf850717bb6c 100644 (file)
@@ -309,7 +309,7 @@ int ethtool_op_set_flags(struct net_device *dev, u32 data);
  * get_ringparam: Report ring sizes
  * set_ringparam: Set ring sizes
  * get_pauseparam: Report pause parameters
- * set_pauseparam: Set pause paramters
+ * set_pauseparam: Set pause parameters
  * get_rx_csum: Report whether receive checksums are turned on or off
  * set_rx_csum: Turn receive checksum on or off
  * get_tx_csum: Report whether transmit checksums are turned on or off
index a516b6716870d01f2238929a463e83e698a396ac..56bd421c12088e1f294ea04db029eb513a0fc587 100644 (file)
@@ -872,6 +872,7 @@ struct file_lock {
        struct list_head fl_block;      /* circular list of blocked processes */
        fl_owner_t fl_owner;
        unsigned int fl_pid;
+       struct pid *fl_nspid;
        wait_queue_head_t fl_wait;
        struct file *fl_file;
        unsigned char fl_flags;
@@ -1307,7 +1308,7 @@ struct super_operations {
  *                     being set.  find_inode() uses this to prevent returning
  *                     nearly-dead inodes.
  * I_SYNC              Similar to I_LOCK, but limited in scope to writeback
- *                     of inode dirty data.  Having a seperate lock for this
+ *                     of inode dirty data.  Having a separate lock for this
  *                     purpose reduces latency and prevents some filesystem-
  *                     specific deadlocks.
  *
index 1a15f8e237a7cf2404b1aa5bf16ccbb4f52214b4..90048fb28a38041a8a3975a59a30502f0b5a23bd 100644 (file)
@@ -21,6 +21,8 @@ union ktime;
 #define FUTEX_LOCK_PI          6
 #define FUTEX_UNLOCK_PI                7
 #define FUTEX_TRYLOCK_PI       8
+#define FUTEX_WAIT_BITSET      9
+#define FUTEX_WAKE_BITSET      10
 
 #define FUTEX_PRIVATE_FLAG     128
 #define FUTEX_CMD_MASK         ~FUTEX_PRIVATE_FLAG
@@ -33,6 +35,8 @@ union ktime;
 #define FUTEX_LOCK_PI_PRIVATE  (FUTEX_LOCK_PI | FUTEX_PRIVATE_FLAG)
 #define FUTEX_UNLOCK_PI_PRIVATE        (FUTEX_UNLOCK_PI | FUTEX_PRIVATE_FLAG)
 #define FUTEX_TRYLOCK_PI_PRIVATE (FUTEX_TRYLOCK_PI | FUTEX_PRIVATE_FLAG)
+#define FUTEX_WAIT_BITSET_PRIVATE      (FUTEX_WAIT_BITS | FUTEX_PRIVATE_FLAG)
+#define FUTEX_WAKE_BITSET_PRIVATE      (FUTEX_WAKE_BITS | FUTEX_PRIVATE_FLAG)
 
 /*
  * Support for robust futexes: the kernel cleans up held futexes at
@@ -111,6 +115,12 @@ struct robust_list_head {
  */
 #define ROBUST_LIST_LIMIT      2048
 
+/*
+ * bitset with all bits set for the FUTEX_xxx_BITSET OPs to request a
+ * match of any bit.
+ */
+#define FUTEX_BITSET_MATCH_ANY 0xffffffff
+
 #ifdef __KERNEL__
 long do_futex(u32 __user *uaddr, int op, u32 val, union ktime *timeout,
              u32 __user *uaddr2, u32 val2, u32 val3);
index 7e93a9ae7064c3a59b0223763964181500f6d3cf..0c6ce515185d24f32476a1b4ebec353be36419bd 100644 (file)
@@ -228,5 +228,7 @@ extern void FASTCALL(free_cold_page(struct page *page));
 
 void page_alloc_init(void);
 void drain_zone_pages(struct zone *zone, struct per_cpu_pages *pcp);
+void drain_all_pages(void);
+void drain_local_pages(void *dummy);
 
 #endif /* __LINUX_GFP_H */
index ff43f8d6b5b330379ef301dc8276088a1d59de20..e38e75967e74d765b518c4098cf61ee38e890d22 100644 (file)
@@ -364,7 +364,7 @@ typedef struct hd_drive_hob_hdr {
 #define SETFEATURES_EN_RLA     0xAA    /* Enable read look-ahead feature */
 #define SETFEATURES_PREFETCH   0xAB    /* Sets drive prefetch value */
 #define SETFEATURES_EN_REST    0xAC    /* ATA-1 */
-#define SETFEATURES_4B_RW_LONG 0xBB    /* Set Lenght of 4 bytes */
+#define SETFEATURES_4B_RW_LONG 0xBB    /* Set Length of 4 bytes */
 #define SETFEATURES_DIS_AAM    0xC2    /* Disable Automatic Acoustic Management */
 #define SETFEATURES_EN_RPOD    0xCC    /* Enable reverting to power on defaults */
 #define SETFEATURES_DIS_RI     0xDD    /* Disable release interrupt ATAPI */
@@ -706,8 +706,10 @@ struct hd_driveid {
  */
 #define IDE_NICE_DSC_OVERLAP   (0)     /* per the DSC overlap protocol */
 #define IDE_NICE_ATAPI_OVERLAP (1)     /* not supported yet */
-#define IDE_NICE_0             (2)     /* when sure that it won't affect us */
 #define IDE_NICE_1             (3)     /* when probably won't affect us much */
+#ifndef __KERNEL__
+#define IDE_NICE_0             (2)     /* when sure that it won't affect us */
 #define IDE_NICE_2             (4)     /* when we know it's on our expense */
+#endif
 
 #endif /* _LINUX_HDREG_H */
index 7974a47fe58257d2fb3308443f025f1413383bbf..e69192159d40bf174923b420b7a9c3c7c19bea45 100644 (file)
@@ -17,6 +17,7 @@
 #ifndef _LINUX_HDSMART_H
 #define _LINUX_HDSMART_H
 
+#ifndef __KERNEL
 #define OFFLINE_FULL_SCAN              0
 #define SHORT_SELF_TEST                        1
 #define EXTEND_SELF_TEST               2
@@ -120,5 +121,6 @@ typedef struct ata_smart_selftestlog_s {
        unsigned char                   resevered[2];
        unsigned char                   chksum;
 } __attribute__ ((packed)) ata_smart_selftestlog_t;
+#endif /* __KERNEL__ *
 
 #endif /* _LINUX_HDSMART_H */
index 1fcb0033179ec4e68442a5cc389c8f93a6bcd528..7dcbc82f3b7bf4a19969d0cf19824cf373a2a91b 100644 (file)
@@ -68,8 +68,6 @@ static inline void clear_user_highpage(struct page *page, unsigned long vaddr)
        void *addr = kmap_atomic(page, KM_USER0);
        clear_user_page(addr, vaddr, page);
        kunmap_atomic(addr, KM_USER0);
-       /* Make sure this page is cleared on other CPU's too before using it */
-       smp_wmb();
 }
 
 #ifndef __HAVE_ARCH_ALLOC_ZEROED_USER_HIGHPAGE
@@ -124,28 +122,40 @@ static inline void clear_highpage(struct page *page)
        kunmap_atomic(kaddr, KM_USER0);
 }
 
-/*
- * Same but also flushes aliased cache contents to RAM.
- *
- * This must be a macro because KM_USER0 and friends aren't defined if
- * !CONFIG_HIGHMEM
- */
-#define zero_user_page(page, offset, size, km_type)            \
-       do {                                                    \
-               void *kaddr;                                    \
-                                                               \
-               BUG_ON((offset) + (size) > PAGE_SIZE);          \
-                                                               \
-               kaddr = kmap_atomic(page, km_type);             \
-               memset((char *)kaddr + (offset), 0, (size));    \
-               flush_dcache_page(page);                        \
-               kunmap_atomic(kaddr, (km_type));                \
-       } while (0)
+static inline void zero_user_segments(struct page *page,
+       unsigned start1, unsigned end1,
+       unsigned start2, unsigned end2)
+{
+       void *kaddr = kmap_atomic(page, KM_USER0);
+
+       BUG_ON(end1 > PAGE_SIZE || end2 > PAGE_SIZE);
+
+       if (end1 > start1)
+               memset(kaddr + start1, 0, end1 - start1);
+
+       if (end2 > start2)
+               memset(kaddr + start2, 0, end2 - start2);
+
+       kunmap_atomic(kaddr, KM_USER0);
+       flush_dcache_page(page);
+}
+
+static inline void zero_user_segment(struct page *page,
+       unsigned start, unsigned end)
+{
+       zero_user_segments(page, start, end, 0, 0);
+}
+
+static inline void zero_user(struct page *page,
+       unsigned start, unsigned size)
+{
+       zero_user_segments(page, start, start + size, 0, 0);
+}
 
 static inline void __deprecated memclear_highpage_flush(struct page *page,
                        unsigned int offset, unsigned int size)
 {
-       zero_user_page(page, offset, size, KM_USER0);
+       zero_user(page, offset, size);
 }
 
 #ifndef __HAVE_ARCH_COPY_USER_HIGHPAGE
@@ -160,8 +170,6 @@ static inline void copy_user_highpage(struct page *to, struct page *from,
        copy_user_page(vto, vfrom, vaddr, to);
        kunmap_atomic(vfrom, KM_USER0);
        kunmap_atomic(vto, KM_USER1);
-       /* Make sure this page is cleared on other CPU's too before using it */
-       smp_wmb();
 }
 
 #endif
index 49067f14fac190ea7bb492fceb1befdcf46aadce..8371b664b41f44314dbc5a6a2fae4e2d0953414c 100644 (file)
@@ -147,7 +147,6 @@ struct hrtimer_sleeper {
  * @get_time:          function to retrieve the current time of the clock
  * @get_softirq_time:  function to retrieve the current time from the softirq
  * @softirq_time:      the time when running the hrtimer queue in the softirq
- * @cb_pending:                list of timers where the callback is pending
  * @offset:            offset of this clock to the monotonic base
  * @reprogram:         function to reprogram the timer event
  */
@@ -302,9 +301,16 @@ static inline int hrtimer_is_queued(struct hrtimer *timer)
 }
 
 /* Forward a hrtimer so it expires after now: */
-extern unsigned long
+extern u64
 hrtimer_forward(struct hrtimer *timer, ktime_t now, ktime_t interval);
 
+/* Forward a hrtimer so it expires after the hrtimer's current now */
+static inline u64 hrtimer_forward_now(struct hrtimer *timer,
+                                     ktime_t interval)
+{
+       return hrtimer_forward(timer, timer->base->get_time(), interval);
+}
+
 /* Precise sleep: */
 extern long hrtimer_nanosleep(struct timespec *rqtp,
                              struct timespec *rmtp,
@@ -323,9 +329,9 @@ extern void hrtimer_run_pending(void);
 extern void __init hrtimers_init(void);
 
 #if BITS_PER_LONG < 64
-extern unsigned long ktime_divns(const ktime_t kt, s64 div);
+extern u64 ktime_divns(const ktime_t kt, s64 div);
 #else /* BITS_PER_LONG < 64 */
-# define ktime_divns(kt, div)          (unsigned long)((kt).tv64 / (div))
+# define ktime_divns(kt, div)          (u64)((kt).tv64 / (div))
 #endif
 
 /* Show pending timers: */
index 85d11916e9ea48a878f54eb3aff5045a8ec2b2c7..42131820bb892e368aafa15fa557b71274e593f4 100644 (file)
@@ -44,7 +44,15 @@ struct hwrng {
 /** Register a new Hardware Random Number Generator driver. */
 extern int hwrng_register(struct hwrng *rng);
 /** Unregister a Hardware Random Number Generator driver. */
-extern void hwrng_unregister(struct hwrng *rng);
+extern void __hwrng_unregister(struct hwrng *rng, bool suspended);
+static inline void hwrng_unregister(struct hwrng *rng)
+{
+       __hwrng_unregister(rng, false);
+}
+static inline void hwrng_unregister_suspended(struct hwrng *rng)
+{
+       __hwrng_unregister(rng, true);
+}
 
 #endif /* __KERNEL__ */
 #endif /* LINUX_HWRANDOM_H_ */
diff --git a/include/linux/i2c/pca9539.h b/include/linux/i2c/pca9539.h
new file mode 100644 (file)
index 0000000..611d84a
--- /dev/null
@@ -0,0 +1,18 @@
+/* platform data for the PCA9539 16-bit I/O expander driver */
+
+struct pca9539_platform_data {
+       /* number of the first GPIO */
+       unsigned        gpio_base;
+
+       /* initial polarity inversion setting */
+       uint16_t        invert;
+
+       void            *context;       /* param to setup/teardown */
+
+       int             (*setup)(struct i2c_client *client,
+                               unsigned gpio, unsigned ngpio,
+                               void *context);
+       int             (*teardown)(struct i2c_client *client,
+                               unsigned gpio, unsigned ngpio,
+                               void *context);
+};
diff --git a/include/linux/i2c/pcf857x.h b/include/linux/i2c/pcf857x.h
new file mode 100644 (file)
index 0000000..ba8ea6e
--- /dev/null
@@ -0,0 +1,45 @@
+#ifndef __LINUX_PCF857X_H
+#define __LINUX_PCF857X_H
+
+/**
+ * struct pcf857x_platform_data - data to set up pcf857x driver
+ * @gpio_base: number of the chip's first GPIO
+ * @n_latch: optional bit-inverse of initial register value; if
+ *     you leave this initialized to zero the driver will act
+ *     like the chip was just reset
+ * @setup: optional callback issued once the GPIOs are valid
+ * @teardown: optional callback issued before the GPIOs are invalidated
+ * @context: optional parameter passed to setup() and teardown()
+ *
+ * In addition to the I2C_BOARD_INFO() state appropriate to each chip,
+ * the i2c_board_info used with the pcf875x driver must provide the
+ * chip "type" ("pcf8574", "pcf8574a", "pcf8575", "pcf8575c") and its
+ * platform_data (pointer to one of these structures) with at least
+ * the gpio_base value initialized.
+ *
+ * The @setup callback may be used with the kind of board-specific glue
+ * which hands the (now-valid) GPIOs to other drivers, or which puts
+ * devices in their initial states using these GPIOs.
+ *
+ * These GPIO chips are only "quasi-bidirectional"; read the chip specs
+ * to understand the behavior.  They don't have separate registers to
+ * record which pins are used for input or output, record which output
+ * values are driven, or provide access to input values.  That must be
+ * inferred by reading the chip's value and knowing the last value written
+ * to it.  If you leave n_latch initialized to zero, that last written
+ * value is presumed to be all ones (as if the chip were just reset).
+ */
+struct pcf857x_platform_data {
+       unsigned        gpio_base;
+       unsigned        n_latch;
+
+       int             (*setup)(struct i2c_client *client,
+                                       int gpio, unsigned ngpio,
+                                       void *context);
+       int             (*teardown)(struct i2c_client *client,
+                                       int gpio, unsigned ngpio,
+                                       void *context);
+       void            *context;
+};
+
+#endif /* __LINUX_PCF857X_H */
index 27cb39de2ae2e5ed8daa2ecc49cfe61731651e19..acec99da832dc475a44aa1e18696f84e1dae1f53 100644 (file)
@@ -9,7 +9,6 @@
 #include <linux/init.h>
 #include <linux/ioport.h>
 #include <linux/hdreg.h>
-#include <linux/hdsmart.h>
 #include <linux/blkdev.h>
 #include <linux/proc_fs.h>
 #include <linux/interrupt.h>
@@ -113,18 +112,8 @@ typedef unsigned char      byte;   /* used everywhere */
 #define SATA_NR_PORTS          (3)     /* 16 possible ?? */
 
 #define SATA_STATUS_OFFSET     (0)
-#define SATA_STATUS_REG                (HWIF(drive)->sata_scr[SATA_STATUS_OFFSET])
 #define SATA_ERROR_OFFSET      (1)
-#define SATA_ERROR_REG         (HWIF(drive)->sata_scr[SATA_ERROR_OFFSET])
 #define SATA_CONTROL_OFFSET    (2)
-#define SATA_CONTROL_REG       (HWIF(drive)->sata_scr[SATA_CONTROL_OFFSET])
-
-#define SATA_MISC_OFFSET       (0)
-#define SATA_MISC_REG          (HWIF(drive)->sata_misc[SATA_MISC_OFFSET])
-#define SATA_PHY_OFFSET                (1)
-#define SATA_PHY_REG           (HWIF(drive)->sata_misc[SATA_PHY_OFFSET])
-#define SATA_IEN_OFFSET                (2)
-#define SATA_IEN_REG           (HWIF(drive)->sata_misc[SATA_IEN_OFFSET])
 
 /*
  * Our Physical Region Descriptor (PRD) table should be large enough
@@ -180,7 +169,7 @@ enum {              ide_unknown,    ide_generic,    ide_pci,
                ide_rz1000,     ide_trm290,
                ide_cmd646,     ide_cy82c693,   ide_4drives,
                ide_pmac,       ide_etrax100,   ide_acorn,
-               ide_au1xxx, ide_forced
+               ide_au1xxx,     ide_palm3710,   ide_forced
 };
 
 typedef u8 hwif_chipset_t;
@@ -197,6 +186,7 @@ typedef struct hw_regs_s {
 } hw_regs_t;
 
 struct hwif_s * ide_find_port(unsigned long);
+struct hwif_s *ide_deprecated_find_port(unsigned long);
 void ide_init_port_data(struct hwif_s *, unsigned int);
 void ide_init_port_hw(struct hwif_s *, hw_regs_t *);
 
@@ -204,17 +194,6 @@ struct ide_drive_s;
 int ide_register_hw(hw_regs_t *, void (*)(struct ide_drive_s *),
                    struct hwif_s **);
 
-void ide_setup_ports(  hw_regs_t *hw,
-                       unsigned long base,
-                       int *offsets,
-                       unsigned long ctrl,
-                       unsigned long intr,
-                       ide_ack_intr_t *ack_intr,
-#if 0
-                       ide_io_ops_t *iops,
-#endif
-                       int irq);
-
 static inline void ide_std_init_ports(hw_regs_t *hw,
                                      unsigned long io_addr,
                                      unsigned long ctl_addr)
@@ -407,8 +386,6 @@ typedef struct ide_drive_s {
        unsigned no_unmask      : 1;    /* disallow setting unmask bit */
        unsigned no_io_32bit    : 1;    /* disallow enabling 32bit I/O */
        unsigned atapi_overlap  : 1;    /* ATAPI overlap (not supported) */
-       unsigned nice0          : 1;    /* give obvious excess bandwidth */
-       unsigned nice2          : 1;    /* give a share in our own bandwidth */
        unsigned doorlocking    : 1;    /* for removable only: door lock/unlock works */
        unsigned nodma          : 1;    /* disallow DMA */
        unsigned autotune       : 2;    /* 0=default, 1=autotune, 2=noautotune */
@@ -481,14 +458,12 @@ typedef struct hwif_s {
                /* task file registers for pata and sata */
        unsigned long   io_ports[IDE_NR_PORTS];
        unsigned long   sata_scr[SATA_NR_PORTS];
-       unsigned long   sata_misc[SATA_NR_PORTS];
 
        ide_drive_t     drives[MAX_DRIVES];     /* drive info */
 
        u8 major;       /* our major number */
        u8 index;       /* 0 for ide0; 1 for ide1; ... */
        u8 channel;     /* for dual-port chips: 0=primary, 1=secondary */
-       u8 straight8;   /* Alan's straight 8 check */
        u8 bus_state;   /* power state of the IDE bus */
 
        u32 host_flags;
@@ -503,7 +478,8 @@ typedef struct hwif_s {
 
        hwif_chipset_t chipset; /* sub-module for tuning.. */
 
-       struct pci_dev  *pci_dev;       /* for pci chipsets */
+       struct device *dev;
+
        const struct ide_port_info *cds;        /* chipset device struct */
 
        ide_ack_intr_t *ack_intr;
@@ -513,6 +489,8 @@ typedef struct hwif_s {
 #if 0
        ide_hwif_ops_t  *hwifops;
 #else
+       /* host specific initialization of devices on a port */
+       void    (*port_init_devs)(struct hwif_s *);
        /* routine to program host for PIO mode */
        void    (*set_pio_mode)(ide_drive_t *, const u8);
        /* routine to program host for DMA mode */
@@ -535,6 +513,8 @@ typedef struct hwif_s {
        u8 (*mdma_filter)(ide_drive_t *);
        u8 (*udma_filter)(ide_drive_t *);
 
+       u8 (*cable_detect)(struct hwif_s *);
+
        void (*ata_input_data)(ide_drive_t *, void *, u32);
        void (*ata_output_data)(ide_drive_t *, void *, u32);
 
@@ -602,10 +582,9 @@ typedef struct hwif_s {
        unsigned        serialized : 1; /* serialized all channel operation */
        unsigned        sharing_irq: 1; /* 1 = sharing irq with another hwif */
        unsigned        reset      : 1; /* reset after probe */
-       unsigned        auto_poll  : 1; /* supports nop auto-poll */
        unsigned        sg_mapped  : 1; /* sg_table and sg_nents are ready */
-       unsigned        no_io_32bit : 1; /* 1 = can not do 32-bit IO ops */
        unsigned        mmio       : 1; /* host uses MMIO */
+       unsigned        straight8  : 1; /* Alan's straight 8 check */
 
        struct device   gendev;
        struct completion gendev_rel_comp; /* To deal with device release() */
@@ -625,11 +604,13 @@ typedef struct hwif_s {
 typedef ide_startstop_t (ide_handler_t)(ide_drive_t *);
 typedef int (ide_expiry_t)(ide_drive_t *);
 
+/* used by ide-cd, ide-floppy, etc. */
+typedef void (xfer_func_t)(ide_drive_t *, void *, u32);
+
 typedef struct hwgroup_s {
                /* irq handler, if active */
        ide_startstop_t (*handler)(ide_drive_t *);
-               /* irq handler, suspended if active */
-       ide_startstop_t (*handler_save)(ide_drive_t *);
+
                /* BOOL: protects all fields below */
        volatile int busy;
                /* BOOL: wake us up on timer expiry */
@@ -644,25 +625,18 @@ typedef struct hwgroup_s {
                /* ptr to current hwif in linked-list */
        ide_hwif_t *hwif;
 
-               /* for pci chipsets */
-       struct pci_dev *pci_dev;
-
                /* current request */
        struct request *rq;
+
                /* failsafe timer */
        struct timer_list timer;
-               /* local copy of current write rq */
-       struct request wrq;
                /* timeout value during long polls */
        unsigned long poll_timeout;
                /* queried upon timeouts */
        int (*expiry)(ide_drive_t *);
-               /* ide_system_bus_speed */
-       int pio_clock;
+
        int req_gen;
        int req_gen_timer;
-
-       unsigned char cmd_buf[4];
 } ide_hwgroup_t;
 
 typedef struct ide_driver_s ide_driver_t;
@@ -716,6 +690,7 @@ typedef struct {
 void proc_ide_create(void);
 void proc_ide_destroy(void);
 void ide_proc_register_port(ide_hwif_t *);
+void ide_proc_port_register_devices(ide_hwif_t *);
 void ide_proc_unregister_port(ide_hwif_t *);
 void ide_proc_register_driver(ide_drive_t *, ide_driver_t *);
 void ide_proc_unregister_driver(ide_drive_t *, ide_driver_t *);
@@ -748,6 +723,7 @@ void ide_pci_create_host_proc(const char *, get_info_t *);
 static inline void proc_ide_create(void) { ; }
 static inline void proc_ide_destroy(void) { ; }
 static inline void ide_proc_register_port(ide_hwif_t *hwif) { ; }
+static inline void ide_proc_port_register_devices(ide_hwif_t *hwif) { ; }
 static inline void ide_proc_unregister_port(ide_hwif_t *hwif) { ; }
 static inline void ide_proc_register_driver(ide_drive_t *drive, ide_driver_t *driver) { ; }
 static inline void ide_proc_unregister_driver(ide_drive_t *drive, ide_driver_t *driver) { ; }
@@ -986,8 +962,6 @@ ide_startstop_t do_rw_taskfile(ide_drive_t *, ide_task_t *);
 
 void task_end_request(ide_drive_t *, struct request *, u8);
 
-u8 wait_drive_not_busy(ide_drive_t *);
-
 int ide_raw_taskfile(ide_drive_t *, ide_task_t *, u8 *, u16);
 int ide_no_data_taskfile(ide_drive_t *, ide_task_t *);
 
@@ -998,10 +972,8 @@ int ide_task_ioctl(ide_drive_t *, unsigned int, unsigned long);
 extern int system_bus_clock(void);
 
 extern int ide_driveid_update(ide_drive_t *);
-extern int ide_ata66_check(ide_drive_t *, ide_task_t *);
 extern int ide_config_drive_speed(ide_drive_t *, u8);
 extern u8 eighty_ninty_three (ide_drive_t *);
-extern int set_transfer(ide_drive_t *, ide_task_t *);
 extern int taskfile_lib_get_identify(ide_drive_t *drive, u8 *);
 
 extern int ide_wait_not_busy(ide_hwif_t *hwif, unsigned long timeout);
@@ -1017,7 +989,6 @@ void ide_init_disk(struct gendisk *, ide_drive_t *);
 
 #ifdef CONFIG_IDEPCI_PCIBUS_ORDER
 extern int ide_scan_direction;
-int __init ide_scan_pcibus(void);
 extern int __ide_pci_register_driver(struct pci_driver *driver, struct module *owner, const char *mod_name);
 #define ide_pci_register_driver(d) __ide_pci_register_driver(d, THIS_MODULE, KBUILD_MODNAME)
 #else
@@ -1027,6 +998,14 @@ extern int __ide_pci_register_driver(struct pci_driver *driver, struct module *o
 void ide_pci_setup_ports(struct pci_dev *, const struct ide_port_info *, int, u8 *);
 void ide_setup_pci_noise(struct pci_dev *, const struct ide_port_info *);
 
+/* FIXME: palm_bk3710 uses BLK_DEV_IDEDMA_PCI without BLK_DEV_IDEPCI! */
+#if defined(CONFIG_BLK_DEV_IDEPCI) && defined(CONFIG_BLK_DEV_IDEDMA_PCI)
+void ide_hwif_setup_dma(ide_hwif_t *, const struct ide_port_info *);
+#else
+static inline void ide_hwif_setup_dma(ide_hwif_t *hwif,
+                                     const struct ide_port_info *d) { }
+#endif
+
 extern void default_hwif_iops(ide_hwif_t *);
 extern void default_hwif_mmiops(ide_hwif_t *);
 extern void default_hwif_transport(ide_hwif_t *);
@@ -1063,7 +1042,7 @@ enum {
        IDE_HFLAG_NO_SET_MODE           = (1 << 9),
        /* trust BIOS for programming chipset/device for DMA */
        IDE_HFLAG_TRUST_BIOS_FOR_DMA    = (1 << 10),
-       /* host uses VDMA */
+       /* host uses VDMA (tied with IDE_HFLAG_CS5520 for now) */
        IDE_HFLAG_VDMA                  = (1 << 11),
        /* ATAPI DMA is unsupported */
        IDE_HFLAG_NO_ATAPI_DMA          = (1 << 12),
@@ -1073,8 +1052,10 @@ enum {
        IDE_HFLAG_NO_DMA                = (1 << 14),
        /* check if host is PCI IDE device before allowing DMA */
        IDE_HFLAG_NO_AUTODMA            = (1 << 15),
+       /* don't autotune PIO */
+       IDE_HFLAG_NO_AUTOTUNE           = (1 << 16),
        /* host is CS5510/CS5520 */
-       IDE_HFLAG_CS5520                = (1 << 16),
+       IDE_HFLAG_CS5520                = IDE_HFLAG_VDMA,
        /* no LBA48 */
        IDE_HFLAG_NO_LBA48              = (1 << 17),
        /* no LBA48 DMA */
@@ -1096,6 +1077,14 @@ enum {
        IDE_HFLAG_ABUSE_SET_DMA_MODE    = (1 << 26),
        /* host is CY82C693 */
        IDE_HFLAG_CY82C693              = (1 << 27),
+       /* force host out of "simplex" mode */
+       IDE_HFLAG_CLEAR_SIMPLEX         = (1 << 28),
+       /* DSC overlap is unsupported */
+       IDE_HFLAG_NO_DSC                = (1 << 29),
+       /* never use 32-bit I/O ops */
+       IDE_HFLAG_NO_IO_32BIT           = (1 << 30),
+       /* never unmask IRQs */
+       IDE_HFLAG_NO_UNMASK_IRQS        = (1 << 31),
 };
 
 #ifdef CONFIG_BLK_DEV_OFFBOARD
@@ -1151,14 +1140,16 @@ void ide_dma_off_quietly(ide_drive_t *);
 void ide_dma_off(ide_drive_t *);
 void ide_dma_on(ide_drive_t *);
 int ide_set_dma(ide_drive_t *);
+void ide_check_dma_crc(ide_drive_t *);
 ide_startstop_t ide_dma_intr(ide_drive_t *);
 
+int ide_build_sglist(ide_drive_t *, struct request *);
+void ide_destroy_dmatable(ide_drive_t *);
+
 #ifdef CONFIG_BLK_DEV_IDEDMA_PCI
-extern int ide_build_sglist(ide_drive_t *, struct request *);
 extern int ide_build_dmatable(ide_drive_t *, struct request *);
-extern void ide_destroy_dmatable(ide_drive_t *);
 extern int ide_release_dma(ide_hwif_t *);
-extern void ide_setup_dma(ide_hwif_t *, unsigned long, unsigned int);
+extern void ide_setup_dma(ide_hwif_t *, unsigned long);
 
 void ide_dma_host_set(ide_drive_t *, int);
 extern int ide_dma_setup(ide_drive_t *);
@@ -1177,6 +1168,7 @@ static inline void ide_dma_off(ide_drive_t *drive) { ; }
 static inline void ide_dma_on(ide_drive_t *drive) { ; }
 static inline void ide_dma_verbose(ide_drive_t *drive) { ; }
 static inline int ide_set_dma(ide_drive_t *drive) { return 1; }
+static inline void ide_check_dma_crc(ide_drive_t *drive) { ; }
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 
 #ifndef CONFIG_BLK_DEV_IDEDMA_PCI
@@ -1188,26 +1180,29 @@ extern int ide_acpi_exec_tfs(ide_drive_t *drive);
 extern void ide_acpi_get_timing(ide_hwif_t *hwif);
 extern void ide_acpi_push_timing(ide_hwif_t *hwif);
 extern void ide_acpi_init(ide_hwif_t *hwif);
+void ide_acpi_port_init_devices(ide_hwif_t *);
 extern void ide_acpi_set_state(ide_hwif_t *hwif, int on);
 #else
 static inline int ide_acpi_exec_tfs(ide_drive_t *drive) { return 0; }
 static inline void ide_acpi_get_timing(ide_hwif_t *hwif) { ; }
 static inline void ide_acpi_push_timing(ide_hwif_t *hwif) { ; }
 static inline void ide_acpi_init(ide_hwif_t *hwif) { ; }
+static inline void ide_acpi_port_init_devices(ide_hwif_t *hwif) { ; }
 static inline void ide_acpi_set_state(ide_hwif_t *hwif, int on) {}
 #endif
 
+void ide_remove_port_from_hwgroup(ide_hwif_t *);
 extern int ide_hwif_request_regions(ide_hwif_t *hwif);
 extern void ide_hwif_release_regions(ide_hwif_t* hwif);
-extern void ide_unregister (unsigned int index);
+void ide_unregister(unsigned int, int, int);
 
 void ide_register_region(struct gendisk *);
 void ide_unregister_region(struct gendisk *);
 
 void ide_undecoded_slave(ide_drive_t *);
 
-int ide_device_add_all(u8 *idx);
-int ide_device_add(u8 idx[4]);
+int ide_device_add_all(u8 *idx, const struct ide_port_info *);
+int ide_device_add(u8 idx[4], const struct ide_port_info *);
 
 static inline void *ide_get_hwifdata (ide_hwif_t * hwif)
 {
@@ -1291,9 +1286,14 @@ extern struct bus_type ide_bus_type;
 #define ide_id_has_flush_cache_ext(id) \
        (((id)->cfs_enable_2 & 0x2400) == 0x2400)
 
+static inline void ide_dump_identify(u8 *id)
+{
+       print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, 16, 2, id, 512, 0);
+}
+
 static inline int hwif_to_node(ide_hwif_t *hwif)
 {
-       struct pci_dev *dev = hwif->pci_dev;
+       struct pci_dev *dev = to_pci_dev(hwif->dev);
        return dev ? pcibus_to_node(dev->bus) : -1;
 }
 
@@ -1309,4 +1309,25 @@ static inline void ide_set_irq(ide_drive_t *drive, int on)
        drive->hwif->OUTB(drive->ctl | (on ? 0 : 2), IDE_CONTROL_REG);
 }
 
+static inline u8 ide_read_status(ide_drive_t *drive)
+{
+       ide_hwif_t *hwif = drive->hwif;
+
+       return hwif->INB(hwif->io_ports[IDE_STATUS_OFFSET]);
+}
+
+static inline u8 ide_read_altstatus(ide_drive_t *drive)
+{
+       ide_hwif_t *hwif = drive->hwif;
+
+       return hwif->INB(hwif->io_ports[IDE_CONTROL_OFFSET]);
+}
+
+static inline u8 ide_read_error(ide_drive_t *drive)
+{
+       ide_hwif_t *hwif = drive->hwif;
+
+       return hwif->INB(hwif->io_ports[IDE_ERROR_OFFSET]);
+}
+
 #endif /* _IDE_H */
index 5de6d911cdf7be1d8f7edf1b228fa70495e553e5..f577c8f1c66d999bda0a1338b2170058ed7c0956 100644 (file)
@@ -287,6 +287,12 @@ struct ieee80211_ht_addt_info {
 #define IEEE80211_HT_IE_NON_GF_STA_PRSNT       0x0004
 #define IEEE80211_HT_IE_NON_HT_STA_PRSNT       0x0010
 
+/* MIMO Power Save Modes */
+#define WLAN_HT_CAP_MIMO_PS_STATIC         0
+#define WLAN_HT_CAP_MIMO_PS_DYNAMIC        1
+#define WLAN_HT_CAP_MIMO_PS_INVALID        2
+#define WLAN_HT_CAP_MIMO_PS_DISABLED       3
+
 /* Authentication algorithms */
 #define WLAN_AUTH_OPEN 0
 #define WLAN_AUTH_SHARED_KEY 1
index 8d9eaaebded7e753c6a79af7fb03064fea39cd90..fc4e3db649e895eaa4d82d1f37af40170166100a 100644 (file)
@@ -17,8 +17,6 @@ struct ipv4_devconf
        DECLARE_BITMAP(state, __NET_IPV4_CONF_MAX - 1);
 };
 
-extern struct ipv4_devconf ipv4_devconf;
-
 struct in_device
 {
        struct net_device       *dev;
index 2efbda01674186d166671dbf2455063970c52bfa..90cdbbbbe0778f4d2d26e62d7171cc6e33da335c 100644 (file)
 #define __REF            .section       ".ref.text", "ax"
 #define __REFDATA        .section       ".ref.data", "aw"
 #define __REFCONST       .section       ".ref.rodata", "aw"
-/* backward compatibility */
-#define __INIT_REFOK     .section      __REF
-#define __INITDATA_REFOK .section      __REFDATA
 
 #ifndef __ASSEMBLY__
 /*
index e6b3f70806790b2a8e7810b3258cddc8b69cb748..1f74e1d7415fe9042e2e71467b40e4a56184ffa8 100644 (file)
@@ -114,6 +114,25 @@ extern struct group_info init_groups;
        .pid = &init_struct_pid,                                \
 }
 
+#ifdef CONFIG_AUDITSYSCALL
+#define INIT_IDS \
+       .loginuid = -1, \
+       .sessionid = -1,
+#else
+#define INIT_IDS
+#endif
+
+#ifdef CONFIG_SECURITY_FILE_CAPABILITIES
+/*
+ * Because of the reduced scope of CAP_SETPCAP when filesystem
+ * capabilities are in effect, it is safe to allow CAP_SETPCAP to
+ * be available in the default configuration.
+ */
+# define CAP_INIT_BSET  CAP_FULL_SET
+#else
+# define CAP_INIT_BSET  CAP_INIT_EFF_SET
+#endif
+
 /*
  *  INIT_TASK is used to set up the first task table, touch at
  * your own risk!. Base=0, limit=0x1fffff (=2MB)
@@ -149,6 +168,7 @@ extern struct group_info init_groups;
        .cap_effective  = CAP_INIT_EFF_SET,                             \
        .cap_inheritable = CAP_INIT_INH_SET,                            \
        .cap_permitted  = CAP_FULL_SET,                                 \
+       .cap_bset       = CAP_INIT_BSET,                                \
        .keep_capabilities = 0,                                         \
        .user           = INIT_USER,                                    \
        .comm           = "swapper",                                    \
@@ -173,6 +193,7 @@ extern struct group_info init_groups;
                [PIDTYPE_SID]  = INIT_PID_LINK(PIDTYPE_SID),            \
        },                                                              \
        .dirties = INIT_PROP_LOCAL_SINGLE(dirties),                     \
+       INIT_IDS                                                        \
        INIT_TRACE_IRQFLAGS                                             \
        INIT_LOCKDEP                                                    \
 }
index 2075d6da2a313d9791ea1e714cb5beb18c91f7e6..056a17a4f34f5bbf4e31f8bd9ea6c1ccd0e0c9fe 100644 (file)
@@ -371,6 +371,8 @@ struct input_absinfo {
 #define KEY_BRIGHTNESS_ZERO    244     /* brightness off, use ambient */
 #define KEY_DISPLAY_OFF                245     /* display device to off state */
 
+#define KEY_WIMAX              246
+
 #define BTN_MISC               0x100
 #define BTN_0                  0x100
 #define BTN_1                  0x101
diff --git a/include/linux/iommu-helper.h b/include/linux/iommu-helper.h
new file mode 100644 (file)
index 0000000..4dd4c04
--- /dev/null
@@ -0,0 +1,7 @@
+extern unsigned long iommu_area_alloc(unsigned long *map, unsigned long size,
+                                     unsigned long start, unsigned int nr,
+                                     unsigned long shift,
+                                     unsigned long boundary_size,
+                                     unsigned long align_mask);
+extern void iommu_area_free(unsigned long *map, unsigned long start,
+                           unsigned int nr);
index 5d35a4cc3bfff3a965132151db9f0ccd1c13df7e..4aaefc349a4b1d8d2cac828c0737c0a60a35a10d 100644 (file)
@@ -457,14 +457,22 @@ static inline struct raw6_sock *raw6_sk(const struct sock *sk)
 #define inet_v6_ipv6only(__sk)         0
 #endif /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */
 
-#define INET6_MATCH(__sk, __hash, __saddr, __daddr, __ports, __dif)\
-       (((__sk)->sk_hash == (__hash))                          && \
+#define INET6_MATCH(__sk, __net, __hash, __saddr, __daddr, __ports, __dif)\
+       (((__sk)->sk_hash == (__hash)) && ((__sk)->sk_net == (__net))   && \
         ((*((__portpair *)&(inet_sk(__sk)->dport))) == (__ports))      && \
         ((__sk)->sk_family             == AF_INET6)            && \
         ipv6_addr_equal(&inet6_sk(__sk)->daddr, (__saddr))     && \
         ipv6_addr_equal(&inet6_sk(__sk)->rcv_saddr, (__daddr)) && \
         (!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif))))
 
+#define INET6_TW_MATCH(__sk, __net, __hash, __saddr, __daddr, __ports, __dif) \
+       (((__sk)->sk_hash == (__hash)) && ((__sk)->sk_net == (__net))   && \
+        (*((__portpair *)&(inet_twsk(__sk)->tw_dport)) == (__ports))   && \
+        ((__sk)->sk_family            == PF_INET6)                     && \
+        (ipv6_addr_equal(&inet6_twsk(__sk)->tw_v6_daddr, (__saddr)))   && \
+        (ipv6_addr_equal(&inet6_twsk(__sk)->tw_v6_rcv_saddr, (__daddr))) && \
+        (!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif))))
+
 #endif /* __KERNEL__ */
 
 #endif /* _IPV6_H */
diff --git a/include/linux/latency.h b/include/linux/latency.h
deleted file mode 100644 (file)
index c08b52b..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * latency.h: Explicit system-wide latency-expectation infrastructure
- *
- * (C) Copyright 2006 Intel Corporation
- * Author: Arjan van de Ven <arjan@linux.intel.com>
- *
- */
-
-#ifndef _INCLUDE_GUARD_LATENCY_H_
-#define _INCLUDE_GUARD_LATENCY_H_
-
-#include <linux/notifier.h>
-
-void set_acceptable_latency(char *identifier, int usecs);
-void modify_acceptable_latency(char *identifier, int usecs);
-void remove_acceptable_latency(char *identifier);
-void synchronize_acceptable_latency(void);
-int system_latency_constraint(void);
-
-int register_latency_notifier(struct notifier_block * nb);
-int unregister_latency_notifier(struct notifier_block * nb);
-
-#define INFINITE_LATENCY 1000000
-
-#endif
index b4130ff58d0c1be1543c21281e7189a7383834a5..00f89fd6c52a21f83d26a7b94e351e3c782854bf 100644 (file)
@@ -54,7 +54,15 @@ struct led_classdev {
 
 extern int led_classdev_register(struct device *parent,
                                 struct led_classdev *led_cdev);
-extern void led_classdev_unregister(struct led_classdev *led_cdev);
+extern void __led_classdev_unregister(struct led_classdev *led_cdev, bool sus);
+static inline void led_classdev_unregister(struct led_classdev *lcd)
+{
+       __led_classdev_unregister(lcd, false);
+}
+static inline void led_classdev_unregister_suspended(struct led_classdev *lcd)
+{
+       __led_classdev_unregister(lcd, true);
+}
 extern void led_classdev_suspend(struct led_classdev *led_cdev);
 extern void led_classdev_resume(struct led_classdev *led_cdev);
 
index 697104da91f11e159851c0698ff45dd0a1f5b618..589be3e1f3ac5a7859587ff4b662e0f6c3167314 100644 (file)
 struct lguest_device_desc {
        /* The device type: console, network, disk etc.  Type 0 terminates. */
        __u8 type;
-       /* The number of bytes of the config array. */
+       /* The number of virtqueues (first in config array) */
+       __u8 num_vq;
+       /* The number of bytes of feature bits.  Multiply by 2: one for host
+        * features and one for guest acknowledgements. */
+       __u8 feature_len;
+       /* The number of bytes of the config array after virtqueues. */
        __u8 config_len;
        /* A status byte, written by the Guest. */
        __u8 status;
@@ -31,7 +36,7 @@ struct lguest_device_desc {
 };
 
 /*D:135 This is how we expect the device configuration field for a virtqueue
- * (type VIRTIO_CONFIG_F_VIRTQUEUE) to be laid out: */
+ * to be laid out in config space. */
 struct lguest_vqconfig {
        /* The number of entries in the virtio_ring */
        __u16 num;
index 09f2e6d0e9ebdb491d8a31223acd8fcfdd49e512..7733585603f12894b95120b91bd7d9178919f1a7 100644 (file)
@@ -49,9 +49,9 @@ enum llc_sockopts {
 
 /* LLC SAP types. */
 #define LLC_SAP_NULL   0x00            /* NULL SAP.                    */
-#define LLC_SAP_LLC    0x02            /* LLC Sublayer Managment.      */
+#define LLC_SAP_LLC    0x02            /* LLC Sublayer Management.     */
 #define LLC_SAP_SNA    0x04            /* SNA Path Control.            */
-#define LLC_SAP_PNM    0x0E            /* Proway Network Managment.    */      
+#define LLC_SAP_PNM    0x0E            /* Proway Network Management.   */      
 #define LLC_SAP_IP     0x06            /* TCP/IP.                      */
 #define LLC_SAP_BSPAN  0x42            /* Bridge Spanning Tree Proto   */
 #define LLC_SAP_MMS    0x4E            /* Manufacturing Message Srv.   */
index e2d1ce36b36728084d0d77538dd00b7101d1a528..4babb2a129ac946decc0478dc6690a6818e3b0e4 100644 (file)
@@ -173,14 +173,17 @@ void                nlmclnt_next_cookie(struct nlm_cookie *);
 /*
  * Host cache
  */
-struct nlm_host * nlmclnt_lookup_host(const struct sockaddr_in *, int, int, const char *, int);
-struct nlm_host * nlmsvc_lookup_host(struct svc_rqst *, const char *, int);
+struct nlm_host  *nlmclnt_lookup_host(const struct sockaddr_in *, int, int,
+                                       const char *, unsigned int);
+struct nlm_host  *nlmsvc_lookup_host(struct svc_rqst *, const char *,
+                                       unsigned int);
 struct rpc_clnt * nlm_bind_host(struct nlm_host *);
 void             nlm_rebind_host(struct nlm_host *);
 struct nlm_host * nlm_get_host(struct nlm_host *);
 void             nlm_release_host(struct nlm_host *);
 void             nlm_shutdown_hosts(void);
-extern void      nlm_host_rebooted(const struct sockaddr_in *, const char *, int, u32);
+extern void      nlm_host_rebooted(const struct sockaddr_in *, const char *,
+                                       unsigned int, u32);
 void             nsm_release(struct nsm_handle *);
 
 
index 83a1f9f6237b5f539f52cda2b6b09eeb013dd97c..df18fa053bcd7d0a1e1f9665e57efa8929dafb87 100644 (file)
@@ -29,7 +29,7 @@ struct svc_rqst;
 /* Lock info passed via NLM */
 struct nlm_lock {
        char *                  caller;
-       int                     len;    /* length of "caller" */
+       unsigned int            len;    /* length of "caller" */
        struct nfs_fh           fh;
        struct xdr_netobj       oh;
        u32                     svid;
@@ -78,7 +78,7 @@ struct nlm_res {
  */
 struct nlm_reboot {
        char *          mon;
-       int             len;
+       unsigned int    len;
        u32             state;
        __be32          addr;
        __be32          vers;
index dff9ea32606a56e986fd6a2cc62375675eec61db..24b30b9b4f8a807f0b154f959ad871dd06735be5 100644 (file)
@@ -43,7 +43,15 @@ struct miscdevice  {
 };
 
 extern int misc_register(struct miscdevice * misc);
-extern int misc_deregister(struct miscdevice * misc);
+extern int __misc_deregister(struct miscdevice *misc, bool suspended);
+static inline int misc_deregister(struct miscdevice *misc)
+{
+       return __misc_deregister(misc, false);
+}
+static inline int misc_deregister_suspended(struct miscdevice *misc)
+{
+       return __misc_deregister(misc, true);
+}
 
 #define MODULE_ALIAS_MISCDEV(minor)                            \
        MODULE_ALIAS("char-major-" __stringify(MISC_MAJOR)      \
index 1bba6789a50a39cd1139a7b0556df38fcd78624e..89d7c691b93a6a660ee5468ac333a805b049a6f7 100644 (file)
@@ -227,10 +227,22 @@ static inline int put_page_testzero(struct page *page)
  */
 static inline int get_page_unless_zero(struct page *page)
 {
-       VM_BUG_ON(PageCompound(page));
+       VM_BUG_ON(PageTail(page));
        return atomic_inc_not_zero(&page->_count);
 }
 
+/* Support for virtually mapped pages */
+struct page *vmalloc_to_page(const void *addr);
+unsigned long vmalloc_to_pfn(const void *addr);
+
+/* Determine if an address is within the vmalloc range */
+static inline int is_vmalloc_addr(const void *x)
+{
+       unsigned long addr = (unsigned long)x;
+
+       return addr >= VMALLOC_START && addr < VMALLOC_END;
+}
+
 static inline struct page *compound_head(struct page *page)
 {
        if (unlikely(PageTail(page)))
@@ -706,6 +718,28 @@ unsigned long unmap_vmas(struct mmu_gather **tlb,
                struct vm_area_struct *start_vma, unsigned long start_addr,
                unsigned long end_addr, unsigned long *nr_accounted,
                struct zap_details *);
+
+/**
+ * mm_walk - callbacks for walk_page_range
+ * @pgd_entry: if set, called for each non-empty PGD (top-level) entry
+ * @pud_entry: if set, called for each non-empty PUD (2nd-level) entry
+ * @pmd_entry: if set, called for each non-empty PMD (3rd-level) entry
+ * @pte_entry: if set, called for each non-empty PTE (4th-level) entry
+ * @pte_hole: if set, called for each hole at all levels
+ *
+ * (see walk_page_range for more details)
+ */
+struct mm_walk {
+       int (*pgd_entry)(pgd_t *, unsigned long, unsigned long, void *);
+       int (*pud_entry)(pud_t *, unsigned long, unsigned long, void *);
+       int (*pmd_entry)(pmd_t *, unsigned long, unsigned long, void *);
+       int (*pte_entry)(pte_t *, unsigned long, unsigned long, void *);
+       int (*pte_hole)(unsigned long, unsigned long, void *);
+};
+
+int walk_page_range(const struct mm_struct *, unsigned long addr,
+                   unsigned long end, const struct mm_walk *walk,
+                   void *private);
 void free_pgd_range(struct mmu_gather **tlb, unsigned long addr,
                unsigned long end, unsigned long floor, unsigned long ceiling);
 void free_pgtables(struct mmu_gather **tlb, struct vm_area_struct *start_vma,
@@ -1089,8 +1123,6 @@ static inline unsigned long vma_pages(struct vm_area_struct *vma)
 
 pgprot_t vm_get_page_prot(unsigned long vm_flags);
 struct vm_area_struct *find_extend_vma(struct mm_struct *, unsigned long addr);
-struct page *vmalloc_to_page(void *addr);
-unsigned long vmalloc_to_pfn(void *addr);
 int remap_pfn_range(struct vm_area_struct *, unsigned long addr,
                        unsigned long pfn, unsigned long size, pgprot_t);
 int vm_insert_page(struct vm_area_struct *, unsigned long addr, struct page *);
index 4c4522a51a3bfa6667a60d0c593efcf970781e52..8d8d1977736e01c05e48c7c0d3172c30a29bf427 100644 (file)
@@ -113,7 +113,7 @@ struct per_cpu_pages {
 };
 
 struct per_cpu_pageset {
-       struct per_cpu_pages pcp[2];    /* 0: hot.  1: cold */
+       struct per_cpu_pages pcp;
 #ifdef CONFIG_NUMA
        s8 expire;
 #endif
index e9fddb42f26cdee8199d8d4f1d1fc31ce61a6a95..139d49d2f078d5573f166475c99873916a041515 100644 (file)
@@ -343,7 +343,8 @@ struct sdio_device_id {
        __u8    class;                  /* Standard interface or SDIO_ANY_ID */
        __u16   vendor;                 /* Vendor or SDIO_ANY_ID */
        __u16   device;                 /* Device ID or SDIO_ANY_ID */
-       kernel_ulong_t driver_data;     /* Data private to the driver */
+       kernel_ulong_t driver_data      /* Data private to the driver */
+               __attribute__((aligned(sizeof(kernel_ulong_t))));
 };
 
 /* SSB core, see drivers/ssb/ */
index 601479772b989a5581fd89fa9cc13cb838c13c11..05c590352dd7f59259c555d1e6e85c20396f0f43 100644 (file)
@@ -125,15 +125,20 @@ static inline int fastcall mutex_is_locked(struct mutex *lock)
 extern void mutex_lock_nested(struct mutex *lock, unsigned int subclass);
 extern int __must_check mutex_lock_interruptible_nested(struct mutex *lock,
                                        unsigned int subclass);
+extern int __must_check mutex_lock_killable_nested(struct mutex *lock,
+                                       unsigned int subclass);
 
 #define mutex_lock(lock) mutex_lock_nested(lock, 0)
 #define mutex_lock_interruptible(lock) mutex_lock_interruptible_nested(lock, 0)
+#define mutex_lock_killable(lock) mutex_lock_killable_nested(lock, 0)
 #else
 extern void fastcall mutex_lock(struct mutex *lock);
 extern int __must_check fastcall mutex_lock_interruptible(struct mutex *lock);
+extern int __must_check fastcall mutex_lock_killable(struct mutex *lock);
 
 # define mutex_lock_nested(lock, subclass) mutex_lock(lock)
 # define mutex_lock_interruptible_nested(lock, subclass) mutex_lock_interruptible(lock)
+# define mutex_lock_killable_nested(lock, subclass) mutex_lock_killable(lock)
 #endif
 
 /*
index b0813c3286b1bbfd035415c86cf592f39a52245b..047d432bde5551784534de19482b46d3d3eb83da 100644 (file)
@@ -1414,12 +1414,16 @@ extern void             dev_set_rx_mode(struct net_device *dev);
 extern void            __dev_set_rx_mode(struct net_device *dev);
 extern int             dev_unicast_delete(struct net_device *dev, void *addr, int alen);
 extern int             dev_unicast_add(struct net_device *dev, void *addr, int alen);
+extern int             dev_unicast_sync(struct net_device *to, struct net_device *from);
+extern void            dev_unicast_unsync(struct net_device *to, struct net_device *from);
 extern int             dev_mc_delete(struct net_device *dev, void *addr, int alen, int all);
 extern int             dev_mc_add(struct net_device *dev, void *addr, int alen, int newonly);
 extern int             dev_mc_sync(struct net_device *to, struct net_device *from);
 extern void            dev_mc_unsync(struct net_device *to, struct net_device *from);
 extern int             __dev_addr_delete(struct dev_addr_list **list, int *count, void *addr, int alen, int all);
 extern int             __dev_addr_add(struct dev_addr_list **list, int *count, void *addr, int alen, int newonly);
+extern int             __dev_addr_sync(struct dev_addr_list **to, int *to_count, struct dev_addr_list **from, int *from_count);
+extern void            __dev_addr_unsync(struct dev_addr_list **to, int *to_count, struct dev_addr_list **from, int *from_count);
 extern void            dev_set_promiscuity(struct net_device *dev, int inc);
 extern void            dev_set_allmulti(struct net_device *dev, int inc);
 extern void            netdev_state_change(struct net_device *dev);
index 23435496d24abde8f909854a0866d6b25edafc6a..3bbde0c3a8a62cae3a01bb060cf0ffddbf93287f 100644 (file)
@@ -4,7 +4,7 @@
 
 #include <linux/netfilter/nf_conntrack_common.h>
 
-extern const char *pptp_msg_name[];
+extern const char *const pptp_msg_name[];
 
 /* state of the control session */
 enum pptp_ctrlsess_state {
index 9fff19779bd5ee5a6b3eb6290b1af22fe1c5f415..8e5ce1ca7bfcd48276c5b17c8572824abb3f7ea1 100644 (file)
@@ -30,9 +30,9 @@ extern unsigned int (*nf_nat_sdp_hook)(struct sk_buff *skb,
                                       struct nf_conntrack_expect *exp,
                                       const char *dptr);
 
-extern int ct_sip_get_info(struct nf_conn *ct, const char *dptr, size_t dlen,
-                          unsigned int *matchoff, unsigned int *matchlen,
-                          enum sip_header_pos pos);
+extern int ct_sip_get_info(const struct nf_conn *ct, const char *dptr,
+                           size_t dlen, unsigned int *matchoff,
+                           unsigned int *matchlen, enum sip_header_pos pos);
 extern int ct_sip_lnlen(const char *line, const char *limit);
 extern const char *ct_sip_search(const char *needle, const char *haystack,
                                 size_t needle_len, size_t haystack_len,
index b99ede51318a25c9d895259fc0eabbeebe0a9635..b2c62cc618f5314f5ce0717008bd2af29e064d80 100644 (file)
@@ -214,7 +214,7 @@ struct xt_match
        /* Free to use by each match */
        unsigned long data;
 
-       char *table;
+       const char *table;
        unsigned int matchsize;
        unsigned int compatsize;
        unsigned int hooks;
@@ -261,7 +261,7 @@ struct xt_target
        /* Set this to THIS_MODULE if you are a module, otherwise NULL */
        struct module *me;
 
-       char *table;
+       const char *table;
        unsigned int targetsize;
        unsigned int compatsize;
        unsigned int hooks;
@@ -277,7 +277,7 @@ struct xt_table
        struct list_head list;
 
        /* A unique name... */
-       char name[XT_TABLE_MAXNAMELEN];
+       const char name[XT_TABLE_MAXNAMELEN];
 
        /* What hooks you will enter on */
        unsigned int valid_hooks;
@@ -335,9 +335,10 @@ extern int xt_check_target(const struct xt_target *target, unsigned short family
                           unsigned int size, const char *table, unsigned int hook,
                           unsigned short proto, int inv_proto);
 
-extern int xt_register_table(struct xt_table *table,
-                            struct xt_table_info *bootstrap,
-                            struct xt_table_info *newinfo);
+extern struct xt_table *xt_register_table(struct net *net,
+                                         struct xt_table *table,
+                                         struct xt_table_info *bootstrap,
+                                         struct xt_table_info *newinfo);
 extern void *xt_unregister_table(struct xt_table *table);
 
 extern struct xt_table_info *xt_replace_table(struct xt_table *table,
@@ -352,11 +353,12 @@ extern struct xt_target *xt_request_find_target(int af, const char *name,
 extern int xt_find_revision(int af, const char *name, u8 revision, int target,
                            int *err);
 
-extern struct xt_table *xt_find_table_lock(int af, const char *name);
+extern struct xt_table *xt_find_table_lock(struct net *net, int af,
+                                          const char *name);
 extern void xt_table_unlock(struct xt_table *t);
 
-extern int xt_proto_init(int af);
-extern void xt_proto_fini(int af);
+extern int xt_proto_init(struct net *net, int af);
+extern void xt_proto_fini(struct net *net, int af);
 
 extern struct xt_table_info *xt_alloc_table_info(unsigned int size);
 extern void xt_free_table_info(struct xt_table_info *info);
@@ -430,15 +432,15 @@ extern short xt_compat_calc_jump(int af, unsigned int offset);
 
 extern int xt_compat_match_offset(struct xt_match *match);
 extern int xt_compat_match_from_user(struct xt_entry_match *m,
-                                    void **dstptr, int *size);
+                                    void **dstptr, unsigned int *size);
 extern int xt_compat_match_to_user(struct xt_entry_match *m,
-                                  void __user **dstptr, int *size);
+                                  void __user **dstptr, unsigned int *size);
 
 extern int xt_compat_target_offset(struct xt_target *target);
 extern void xt_compat_target_from_user(struct xt_entry_target *t,
-                                      void **dstptr, int *size);
+                                      void **dstptr, unsigned int *size);
 extern int xt_compat_target_to_user(struct xt_entry_target *t,
-                                   void __user **dstptr, int *size);
+                                   void __user **dstptr, unsigned int *size);
 
 #endif /* CONFIG_COMPAT */
 #endif /* __KERNEL__ */
index d2492a3329bed137c9c46f7354a0b1f0599e005f..f3fd83e46babdf422bf6952f0c21214fdac57d98 100644 (file)
@@ -6,9 +6,6 @@
 #define _XT_CONNTRACK_H
 
 #include <linux/netfilter/nf_conntrack_tuple_common.h>
-#ifdef __KERNEL__
-#      include <linux/in.h>
-#endif
 
 #define XT_CONNTRACK_STATE_BIT(ctinfo) (1 << ((ctinfo)%IP_CT_IS_REPLY+1))
 #define XT_CONNTRACK_STATE_INVALID (1 << 0)
 #define XT_CONNTRACK_STATE_UNTRACKED (1 << (IP_CT_NUMBER + 3))
 
 /* flags, invflags: */
-#define XT_CONNTRACK_STATE     0x01
-#define XT_CONNTRACK_PROTO     0x02
-#define XT_CONNTRACK_ORIGSRC   0x04
-#define XT_CONNTRACK_ORIGDST   0x08
-#define XT_CONNTRACK_REPLSRC   0x10
-#define XT_CONNTRACK_REPLDST   0x20
-#define XT_CONNTRACK_STATUS    0x40
-#define XT_CONNTRACK_EXPIRES   0x80
+enum {
+       XT_CONNTRACK_STATE        = 1 << 0,
+       XT_CONNTRACK_PROTO        = 1 << 1,
+       XT_CONNTRACK_ORIGSRC      = 1 << 2,
+       XT_CONNTRACK_ORIGDST      = 1 << 3,
+       XT_CONNTRACK_REPLSRC      = 1 << 4,
+       XT_CONNTRACK_REPLDST      = 1 << 5,
+       XT_CONNTRACK_STATUS       = 1 << 6,
+       XT_CONNTRACK_EXPIRES      = 1 << 7,
+       XT_CONNTRACK_ORIGSRC_PORT = 1 << 8,
+       XT_CONNTRACK_ORIGDST_PORT = 1 << 9,
+       XT_CONNTRACK_REPLSRC_PORT = 1 << 10,
+       XT_CONNTRACK_REPLDST_PORT = 1 << 11,
+       XT_CONNTRACK_DIRECTION    = 1 << 12,
+};
 
 /* This is exposed to userspace, so remains frozen in time. */
 struct ip_conntrack_old_tuple
@@ -70,8 +74,10 @@ struct xt_conntrack_mtinfo1 {
        union nf_inet_addr repldst_addr, repldst_mask;
        u_int32_t expires_min, expires_max;
        u_int16_t l4proto;
+       __be16 origsrc_port, origdst_port;
+       __be16 replsrc_port, repldst_port;
+       u_int16_t match_flags, invert_flags;
        u_int8_t state_mask, status_mask;
-       u_int8_t match_flags, invert_flags;
 };
 
 #endif /*_XT_CONNTRACK_H*/
index c19972e4564da6182cf4fc3b9799ba2f44aa8e58..58b818ee41caa25f9d18a9c265fb2f7325f80826 100644 (file)
@@ -9,13 +9,16 @@
 /* details of this structure hidden by the implementation */
 struct xt_hashlimit_htable;
 
-#define XT_HASHLIMIT_HASH_DIP  0x0001
-#define XT_HASHLIMIT_HASH_DPT  0x0002
-#define XT_HASHLIMIT_HASH_SIP  0x0004
-#define XT_HASHLIMIT_HASH_SPT  0x0008
+enum {
+       XT_HASHLIMIT_HASH_DIP = 1 << 0,
+       XT_HASHLIMIT_HASH_DPT = 1 << 1,
+       XT_HASHLIMIT_HASH_SIP = 1 << 2,
+       XT_HASHLIMIT_HASH_SPT = 1 << 3,
+       XT_HASHLIMIT_INVERT   = 1 << 4,
+};
 
 struct hashlimit_cfg {
-       u_int32_t mode;   /* bitmask of IPT_HASHLIMIT_HASH_* */
+       u_int32_t mode;   /* bitmask of XT_HASHLIMIT_HASH_* */
        u_int32_t avg;    /* Average secs between packets * scale */
        u_int32_t burst;  /* Period multiplier for upper limit. */
 
@@ -37,4 +40,28 @@ struct xt_hashlimit_info {
                struct xt_hashlimit_info *master;
        } u;
 };
+
+struct hashlimit_cfg1 {
+       u_int32_t mode;   /* bitmask of XT_HASHLIMIT_HASH_* */
+       u_int32_t avg;    /* Average secs between packets * scale */
+       u_int32_t burst;  /* Period multiplier for upper limit. */
+
+       /* user specified */
+       u_int32_t size;         /* how many buckets */
+       u_int32_t max;          /* max number of entries */
+       u_int32_t gc_interval;  /* gc interval */
+       u_int32_t expire;       /* when do entries expire? */
+
+       u_int8_t srcmask, dstmask;
+};
+
+struct xt_hashlimit_mtinfo1 {
+       char name[IFNAMSIZ];
+       struct hashlimit_cfg1 cfg;
+
+       /* Used internally by the kernel */
+       struct xt_hashlimit_htable *hinfo __attribute__((aligned(8)));
+       struct xt_hashlimit_mtinfo1 *master __attribute__((aligned(8)));
+};
+
 #endif /*_XT_HASHLIMIT_H*/
index eacd34efebd51ec818eb94ccf55e4dd6b63c3e97..c84e52cfe415f55ee22563d464cf6b7311bb4df2 100644 (file)
@@ -8,8 +8,8 @@ enum {
 };
 
 struct xt_owner_match_info {
-       u_int32_t uid;
-       u_int32_t gid;
+       u_int32_t uid_min, uid_max;
+       u_int32_t gid_min, gid_max;
        u_int8_t match, invert;
 };
 
index 53dd4df27aa1a881722f8c6a055de3b1e1b7e946..db223ca92c8b00bdbdf10c59007a136aaba1e7eb 100644 (file)
@@ -271,8 +271,9 @@ struct arpt_error
        xt_register_target(tgt); })
 #define arpt_unregister_target(tgt) xt_unregister_target(tgt)
 
-extern int arpt_register_table(struct arpt_table *table,
-                              const struct arpt_replace *repl);
+extern struct arpt_table *arpt_register_table(struct net *net,
+                                             struct arpt_table *table,
+                                             const struct arpt_replace *repl);
 extern void arpt_unregister_table(struct arpt_table *table);
 extern unsigned int arpt_do_table(struct sk_buff *skb,
                                  unsigned int hook,
index 45fcad91e67b4df4246b47c425e941e06f3c1117..bfc889f9027660c60ad4d8c69c238963fd6648ca 100644 (file)
@@ -244,8 +244,9 @@ ipt_get_target(struct ipt_entry *e)
 #include <linux/init.h>
 extern void ipt_init(void) __init;
 
-extern int ipt_register_table(struct xt_table *table,
-                             const struct ipt_replace *repl);
+extern struct xt_table *ipt_register_table(struct net *net,
+                                          struct xt_table *table,
+                                          const struct ipt_replace *repl);
 extern void ipt_unregister_table(struct xt_table *table);
 
 /* Standard entry. */
index 110801d699ee95ab2f649f20a482bf179a1f7bbd..f2507dcc57507871a9f19ccba25a083e03766049 100644 (file)
@@ -305,8 +305,9 @@ ip6t_get_target(struct ip6t_entry *e)
 #include <linux/init.h>
 extern void ip6t_init(void) __init;
 
-extern int ip6t_register_table(struct xt_table *table,
-                              const struct ip6t_replace *repl);
+extern struct xt_table *ip6t_register_table(struct net *net,
+                                           struct xt_table *table,
+                                           const struct ip6t_replace *repl);
 extern void ip6t_unregister_table(struct xt_table *table);
 extern unsigned int ip6t_do_table(struct sk_buff *skb,
                                  unsigned int hook,
index bd13b6f4a98ec0932503273858988795bcc5bf35..fb0713b6ffaf910d6d5d58462d29f5fe2db03f8f 100644 (file)
@@ -219,7 +219,7 @@ struct netlink_callback
        int             (*dump)(struct sk_buff * skb, struct netlink_callback *cb);
        int             (*done)(struct netlink_callback *cb);
        int             family;
-       long            args[5];
+       long            args[6];
 };
 
 struct netlink_notify
index 099ddb4481c07d9d64b4708db3ce519de622ed84..a69ba80f2dfe1398b9de602e0b793fedc69e4db9 100644 (file)
@@ -556,14 +556,7 @@ extern void * nfs_root_data(void);
 
 #define nfs_wait_event(clnt, wq, condition)                            \
 ({                                                                     \
-       int __retval = 0;                                               \
-       if (clnt->cl_intr) {                                            \
-               sigset_t oldmask;                                       \
-               rpc_clnt_sigmask(clnt, &oldmask);                       \
-               __retval = wait_event_interruptible(wq, condition);     \
-               rpc_clnt_sigunmask(clnt, &oldmask);                     \
-       } else                                                          \
-               wait_event(wq, condition);                              \
+       int __retval = wait_event_killable(wq, condition);              \
        __retval;                                                       \
 })
 
index a3ade89a64d21f68c359d35d5b179d97a93c0fcc..df7c6b7a7ebb1bfbe84e33bb85fb2f045492e10a 100644 (file)
@@ -48,7 +48,7 @@ struct nfs_mount_data {
 /* bits in the flags field */
 
 #define NFS_MOUNT_SOFT         0x0001  /* 1 */
-#define NFS_MOUNT_INTR         0x0002  /* 1 */
+#define NFS_MOUNT_INTR         0x0002  /* 1 */ /* now unused, but ABI */
 #define NFS_MOUNT_SECURE       0x0004  /* 1 */
 #define NFS_MOUNT_POSIX                0x0008  /* 1 */
 #define NFS_MOUNT_NOCTO                0x0010  /* 1 */
index d9c5455808e590cd72057b18d22d239dc47e4b0a..e726fc3a4375f5948d395e6756e10bca0673d9b6 100644 (file)
@@ -4,4 +4,3 @@ unifdef-y += stats.h
 unifdef-y += syscall.h
 unifdef-y += nfsfh.h
 unifdef-y += debug.h
-unifdef-y += auth.h
index 007480cd6a601fbec62c5d5ac41ed50e2a2d882d..7b5d784cc8587cd80c8bd31125f56a793ebae253 100644 (file)
@@ -72,8 +72,8 @@ enum {
  */
 #define RC_DELAY               (HZ/5)
 
-void   nfsd_cache_init(void);
-void   nfsd_cache_shutdown(void);
+int    nfsd_reply_cache_init(void);
+void   nfsd_reply_cache_shutdown(void);
 int    nfsd_cache_lookup(struct svc_rqst *, int);
 void   nfsd_cache_update(struct svc_rqst *, int, __be32 *);
 
index bcb7abafbca9d041478122ecfeb26d8236a1f46d..3a1687251367bd83b18711303f1ae3a712dbdff0 100644 (file)
@@ -122,7 +122,7 @@ __be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp);
 /*
  * Function declarations
  */
-void                   nfsd_export_init(void);
+int                    nfsd_export_init(void);
 void                   nfsd_export_shutdown(void);
 void                   nfsd_export_flush(void);
 void                   exp_readlock(void);
index 604a0d786bc6a2699f3968eed506c6ec001ebc0a..8caf4c4f64e68df30c686a396d60252e63915319 100644 (file)
@@ -20,7 +20,6 @@
 #include <linux/nfsd/debug.h>
 #include <linux/nfsd/nfsfh.h>
 #include <linux/nfsd/export.h>
-#include <linux/nfsd/auth.h>
 #include <linux/nfsd/stats.h>
 /*
  * nfsd version
@@ -70,9 +69,9 @@ void          nfsd_racache_shutdown(void);
 int            nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp,
                                struct svc_export **expp);
 __be32         nfsd_lookup(struct svc_rqst *, struct svc_fh *,
-                               const char *, int, struct svc_fh *);
+                               const char *, unsigned int, struct svc_fh *);
 __be32          nfsd_lookup_dentry(struct svc_rqst *, struct svc_fh *,
-                               const char *, int,
+                               const char *, unsigned int,
                                struct svc_export **, struct dentry **);
 __be32         nfsd_setattr(struct svc_rqst *, struct svc_fh *,
                                struct iattr *, int, time_t);
index 8bcddccb6c427e81a7a7b960d1f25afaa1bb9b6f..4e439765b705e3a01dd3be9559b57d38a70ea445 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/nfsd/const.h>
 #include <linux/nfsd/export.h>
 #include <linux/nfsd/nfsfh.h>
-#include <linux/nfsd/auth.h>
 
 /*
  * Version of the syscall interface
index 67885d5e6e50d2024b5d036f31a1fd5c3e5ab6ee..a0132ef58f2128c9fe25f1412f9959355db92d58 100644 (file)
@@ -23,7 +23,7 @@ struct nfsd_sattrargs {
 struct nfsd_diropargs {
        struct svc_fh           fh;
        char *                  name;
-       int                     len;
+       unsigned int            len;
 };
 
 struct nfsd_readargs {
@@ -43,17 +43,17 @@ struct nfsd_writeargs {
 struct nfsd_createargs {
        struct svc_fh           fh;
        char *                  name;
-       int                     len;
+       unsigned int            len;
        struct iattr            attrs;
 };
 
 struct nfsd_renameargs {
        struct svc_fh           ffh;
        char *                  fname;
-       int                     flen;
+       unsigned int            flen;
        struct svc_fh           tfh;
        char *                  tname;
-       int                     tlen;
+       unsigned int            tlen;
 };
 
 struct nfsd_readlinkargs {
@@ -65,15 +65,15 @@ struct nfsd_linkargs {
        struct svc_fh           ffh;
        struct svc_fh           tfh;
        char *                  tname;
-       int                     tlen;
+       unsigned int            tlen;
 };
 
 struct nfsd_symlinkargs {
        struct svc_fh           ffh;
        char *                  fname;
-       int                     flen;
+       unsigned int            flen;
        char *                  tname;
-       int                     tlen;
+       unsigned int            tlen;
        struct iattr            attrs;
 };
 
index 89d9d6061a62b5b8179380d4f38d346700490da8..421eddd65a25a7968b8abe94d4f041e4f9aa0319 100644 (file)
@@ -21,7 +21,7 @@ struct nfsd3_sattrargs {
 struct nfsd3_diropargs {
        struct svc_fh           fh;
        char *                  name;
-       int                     len;
+       unsigned int            len;
 };
 
 struct nfsd3_accessargs {
@@ -48,7 +48,7 @@ struct nfsd3_writeargs {
 struct nfsd3_createargs {
        struct svc_fh           fh;
        char *                  name;
-       int                     len;
+       unsigned int            len;
        int                     createmode;
        struct iattr            attrs;
        __be32 *                verf;
@@ -57,7 +57,7 @@ struct nfsd3_createargs {
 struct nfsd3_mknodargs {
        struct svc_fh           fh;
        char *                  name;
-       int                     len;
+       unsigned int            len;
        __u32                   ftype;
        __u32                   major, minor;
        struct iattr            attrs;
@@ -66,10 +66,10 @@ struct nfsd3_mknodargs {
 struct nfsd3_renameargs {
        struct svc_fh           ffh;
        char *                  fname;
-       int                     flen;
+       unsigned int            flen;
        struct svc_fh           tfh;
        char *                  tname;
-       int                     tlen;
+       unsigned int            tlen;
 };
 
 struct nfsd3_readlinkargs {
@@ -81,15 +81,15 @@ struct nfsd3_linkargs {
        struct svc_fh           ffh;
        struct svc_fh           tfh;
        char *                  tname;
-       int                     tlen;
+       unsigned int            tlen;
 };
 
 struct nfsd3_symlinkargs {
        struct svc_fh           ffh;
        char *                  fname;
-       int                     flen;
+       unsigned int            flen;
        char *                  tname;
-       int                     tlen;
+       unsigned int            tlen;
        struct iattr            attrs;
 };
 
index b0ddfb41c790754034a9cb5cfe650c6c00602339..27bd3e38ec5ad86b290a0f73feb73e973b917749 100644 (file)
@@ -441,7 +441,7 @@ void nfsd4_encode_operation(struct nfsd4_compoundres *, struct nfsd4_op *);
 void nfsd4_encode_replay(struct nfsd4_compoundres *resp, struct nfsd4_op *op);
 __be32 nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
                       struct dentry *dentry, __be32 *buffer, int *countp,
-                      u32 *bmval, struct svc_rqst *);
+                      u32 *bmval, struct svc_rqst *, int ignore_crossmnt);
 extern __be32 nfsd4_setclientid(struct svc_rqst *rqstp,
                struct nfsd4_compound_state *,
                struct nfsd4_setclientid *setclid);
index e82746fcad14551ab7aaf46157e3aba04c27e6b1..d4a2ac18bd4cfba2a6713aa6a492660264b94782 100644 (file)
 #define IDMAP_NAMESZ 128
 
 #ifdef CONFIG_NFSD_V4
-void nfsd_idmap_init(void);
+int nfsd_idmap_init(void);
 void nfsd_idmap_shutdown(void);
 #else
-static inline void nfsd_idmap_init(void) {};
-static inline void nfsd_idmap_shutdown(void) {};
+static inline int nfsd_idmap_init(void)
+{
+       return 0;
+}
+static inline void nfsd_idmap_shutdown(void)
+{
+}
 #endif
 
 int nfsd_map_name_to_uid(struct svc_rqst *, const char *, size_t, __u32 *);
index 5dfbc684ce7daab792ca9ddf40e842fe5a5cc1c7..f4df40038f0c4cb54d2596cbe051dfd9bd241f0e 100644 (file)
@@ -228,6 +228,8 @@ static inline int notifier_to_errno(int ret)
 #define PM_POST_HIBERNATION    0x0002 /* Hibernation finished */
 #define PM_SUSPEND_PREPARE     0x0003 /* Going to suspend the system */
 #define PM_POST_SUSPEND                0x0004 /* Suspend finished */
+#define PM_RESTORE_PREPARE     0x0005 /* Going to restore a saved image */
+#define PM_POST_RESTORE                0x0006 /* Restore failed */
 
 /* Console keyboard events.
  * Note: KBD_KEYCODE is always sent before KBD_UNBOUND_KEYCODE, KBD_UNICODE and
index cdb3e9b8db54b1d5a677fd55adfbbc4cf938bd03..c4355076d1a5e58183336134a51244b878fbce62 100644 (file)
@@ -132,10 +132,12 @@ enum nubus_drhw {
        NUBUS_DRHW_RDIUS_DCGX     = 0x027C, /* Radius DirectColor/GX */
        NUBUS_DRHW_RDIUS_PC8      = 0x0291, /* Radius PrecisionColor 8 */
        NUBUS_DRHW_LAPIS_PCS8     = 0x0292, /* Lapis ProColorServer 8 */
-       NUBUS_DRHW_RASTER_24LXI   = 0x02A0, /* RasterOps 8/24 XLi */
+       NUBUS_DRHW_RASTER_24XLI   = 0x02A0, /* RasterOps 8/24 XLi */
        NUBUS_DRHW_RASTER_PBPGT   = 0x02A5, /* RasterOps PaintBoard Prism GT */
        NUBUS_DRHW_EMACH_FSX      = 0x02AE, /* E-Machines Futura SX */
+       NUBUS_DRHW_RASTER_24XLTV  = 0x02B7, /* RasterOps 24XLTV */
        NUBUS_DRHW_SMAC_THUND24   = 0x02CB, /* SuperMac Thunder/24 */
+       NUBUS_DRHW_SMAC_THUNDLGHT = 0x03D9, /* SuperMac ThunderLight */
        NUBUS_DRHW_RDIUS_PC24XP   = 0x0406, /* Radius PrecisionColor 24Xp */
        NUBUS_DRHW_RDIUS_PC24X    = 0x040A, /* Radius PrecisionColor 24X */
        NUBUS_DRHW_RDIUS_PC8XJ    = 0x040B, /* Radius PrecisionColor 8XJ */
index b5f33efcb8e20006165336ffbcdd9e25c7e793b3..6981016dcc258fc89a0956ca6d9cb41ef3f771ba 100644 (file)
@@ -50,6 +50,7 @@ extern struct device_node *of_find_matching_node(struct device_node *from,
 extern struct device_node *of_find_node_by_path(const char *path);
 extern struct device_node *of_find_node_by_phandle(phandle handle);
 extern struct device_node *of_get_parent(const struct device_node *node);
+extern struct device_node *of_get_next_parent(struct device_node *node);
 extern struct device_node *of_get_next_child(const struct device_node *node,
                                             struct device_node *prev);
 #define for_each_child_of_node(parent, child) \
index 209d3a47f50f24b5ccbf29c6b3dd965ebb79d2d8..bbad43fb8181001b43ef1c8de406173138d118e0 100644 (file)
 #define ClearPageReferenced(page)      clear_bit(PG_referenced, &(page)->flags)
 #define TestClearPageReferenced(page) test_and_clear_bit(PG_referenced, &(page)->flags)
 
-#define PageUptodate(page)     test_bit(PG_uptodate, &(page)->flags)
+static inline int PageUptodate(struct page *page)
+{
+       int ret = test_bit(PG_uptodate, &(page)->flags);
+
+       /*
+        * Must ensure that the data we read out of the page is loaded
+        * _after_ we've loaded page->flags to check for PageUptodate.
+        * We can skip the barrier if the page is not uptodate, because
+        * we wouldn't be reading anything from it.
+        *
+        * See SetPageUptodate() for the other side of the story.
+        */
+       if (ret)
+               smp_rmb();
+
+       return ret;
+}
+
+static inline void __SetPageUptodate(struct page *page)
+{
+       smp_wmb();
+       __set_bit(PG_uptodate, &(page)->flags);
 #ifdef CONFIG_S390
+       page_clear_dirty(page);
+#endif
+}
+
 static inline void SetPageUptodate(struct page *page)
 {
+#ifdef CONFIG_S390
        if (!test_and_set_bit(PG_uptodate, &page->flags))
                page_clear_dirty(page);
-}
 #else
-#define SetPageUptodate(page)  set_bit(PG_uptodate, &(page)->flags)
+       /*
+        * Memory barrier must be issued before setting the PG_uptodate bit,
+        * so that all previous stores issued in order to bring the page
+        * uptodate are actually visible before PageUptodate becomes true.
+        *
+        * s390 doesn't need an explicit smp_wmb here because the test and
+        * set bit already provides full barriers.
+        */
+       smp_wmb();
+       set_bit(PG_uptodate, &(page)->flags);
 #endif
+}
+
 #define ClearPageUptodate(page)        clear_bit(PG_uptodate, &(page)->flags)
 
 #define PageDirty(page)                test_bit(PG_dirty, &(page)->flags)
index db8a410ae9e15a6daf9b64678fd3edefccdcc717..4b62a105622b1e8e38b294a32f426a42be0a8861 100644 (file)
@@ -157,6 +157,7 @@ static inline pgoff_t linear_page_index(struct vm_area_struct *vma,
 }
 
 extern void FASTCALL(__lock_page(struct page *page));
+extern int FASTCALL(__lock_page_killable(struct page *page));
 extern void FASTCALL(__lock_page_nosync(struct page *page));
 extern void FASTCALL(unlock_page(struct page *page));
 
@@ -170,6 +171,19 @@ static inline void lock_page(struct page *page)
                __lock_page(page);
 }
 
+/*
+ * lock_page_killable is like lock_page but can be interrupted by fatal
+ * signals.  It returns 0 if it locked the page and -EINTR if it was
+ * killed while waiting.
+ */
+static inline int lock_page_killable(struct page *page)
+{
+       might_sleep();
+       if (TestSetPageLocked(page))
+               return __lock_page_killable(page);
+       return 0;
+}
+
 /*
  * lock_page_nosync should only be used if we can't pin the page's inode.
  * Doesn't play quite so well with block device plugging.
index 936ef82ed76a6f21cf07b0132da3a12efc748cb9..3ba25065fa96b0f3907447f20fda02a8ea7e840c 100644 (file)
 
 #ifdef CONFIG_ACPI
 extern acpi_status pci_osc_control_set(acpi_handle handle, u32 flags);
-extern acpi_status pci_osc_support_set(u32 flags);
+extern acpi_status __pci_osc_support_set(u32 flags, const char *hid);
+static inline acpi_status pci_osc_support_set(u32 flags)
+{
+       return __pci_osc_support_set(flags, PCI_ROOT_HID_STRING);
+}
+static inline acpi_status pcie_osc_support_set(u32 flags)
+{
+       return __pci_osc_support_set(flags, PCI_EXPRESS_ROOT_HID_STRING);
+}
 #else
 #if !defined(AE_ERROR)
 typedef u32            acpi_status;
@@ -57,6 +65,7 @@ typedef u32           acpi_status;
 static inline acpi_status pci_osc_control_set(acpi_handle handle, u32 flags)
 {return AE_ERROR;}
 static inline acpi_status pci_osc_support_set(u32 flags) {return AE_ERROR;} 
+static inline acpi_status pcie_osc_support_set(u32 flags) {return AE_ERROR;}
 #endif
 
 #endif /* _PCI_ACPI_H_ */
index ae1006322f808d90b233188108efac1f59f23359..7215d3b1f4af05d8731e6dc4989763be0aea6eb0 100644 (file)
@@ -28,7 +28,7 @@
  *     7:3 = slot
  *     2:0 = function
  */
-#define PCI_DEVFN(slot,func)   ((((slot) & 0x1f) << 3) | ((func) & 0x07))
+#define PCI_DEVFN(slot, func)  ((((slot) & 0x1f) << 3) | ((func) & 0x07))
 #define PCI_SLOT(devfn)                (((devfn) >> 3) & 0x1f)
 #define PCI_FUNC(devfn)                ((devfn) & 0x07)
 
@@ -66,7 +66,6 @@ enum pci_mmap_state {
 #define PCI_DMA_FROMDEVICE     2
 #define PCI_DMA_NONE           3
 
-#define DEVICE_COUNT_COMPATIBLE        4
 #define DEVICE_COUNT_RESOURCE  12
 
 typedef int __bitwise pci_power_t;
@@ -160,6 +159,8 @@ struct pci_dev {
                                           this if your device has broken DMA
                                           or supports 64-bit transfers.  */
 
+       struct device_dma_parameters dma_parms;
+
        pci_power_t     current_state;  /* Current operating state. In ACPI-speak,
                                           this is D0-D3, D0 being fully functional,
                                           and D3 being off. */
@@ -167,10 +168,6 @@ struct pci_dev {
        pci_channel_state_t error_state;        /* current connectivity state */
        struct  device  dev;            /* Generic device interface */
 
-       /* device is compatible with these IDs */
-       unsigned short vendor_compatible[DEVICE_COUNT_COMPATIBLE];
-       unsigned short device_compatible[DEVICE_COUNT_COMPATIBLE];
-
        int             cfg_size;       /* Size of configuration space */
 
        /*
@@ -219,7 +216,7 @@ static inline int pci_channel_offline(struct pci_dev *pdev)
 }
 
 static inline struct pci_cap_saved_state *pci_find_saved_cap(
-       struct pci_dev *pci_dev,char cap)
+       struct pci_dev *pci_dev, char cap)
 {
        struct pci_cap_saved_state *tmp;
        struct hlist_node *pos;
@@ -278,13 +275,13 @@ struct pci_bus {
        unsigned short  bridge_ctl;     /* manage NO_ISA/FBB/et al behaviors */
        pci_bus_flags_t bus_flags;      /* Inherited by child busses */
        struct device           *bridge;
-       struct class_device     class_dev;
+       struct device           dev;
        struct bin_attribute    *legacy_io; /* legacy I/O for this bus */
        struct bin_attribute    *legacy_mem; /* legacy mem */
 };
 
 #define pci_bus_b(n)   list_entry(n, struct pci_bus, node)
-#define to_pci_bus(n)  container_of(n, struct pci_bus, class_dev)
+#define to_pci_bus(n)  container_of(n, struct pci_bus, dev)
 
 /*
  * Error values that may be returned by PCI functions.
@@ -314,8 +311,8 @@ struct pci_raw_ops {
 extern struct pci_raw_ops *raw_pci_ops;
 
 struct pci_bus_region {
-       unsigned long start;
-       unsigned long end;
+       resource_size_t start;
+       resource_size_t end;
 };
 
 struct pci_dynids {
@@ -351,11 +348,10 @@ enum pci_ers_result {
 };
 
 /* PCI bus error event callbacks */
-struct pci_error_handlers
-{
+struct pci_error_handlers {
        /* PCI bus error detected on this device */
        pci_ers_result_t (*error_detected)(struct pci_dev *dev,
-                             enum pci_channel_state error);
+                                          enum pci_channel_state error);
 
        /* MMIO has been re-enabled, but not DMA */
        pci_ers_result_t (*mmio_enabled)(struct pci_dev *dev);
@@ -390,7 +386,7 @@ struct pci_driver {
        struct pci_dynids dynids;
 };
 
-#define        to_pci_driver(drv) container_of(drv,struct pci_driver, driver)
+#define        to_pci_driver(drv) container_of(drv, struct pci_driver, driver)
 
 /**
  * PCI_DEVICE - macro used to describe a specific pci device
@@ -448,7 +444,7 @@ extern int no_pci_devices(void);
 
 void pcibios_fixup_bus(struct pci_bus *);
 int __must_check pcibios_enable_device(struct pci_dev *, int mask);
-char *pcibios_setup (char *str);
+char *pcibios_setup(char *str);
 
 /* Used only when drivers/pci/setup.c is used */
 void pcibios_align_resource(void *, struct resource *, resource_size_t,
@@ -459,8 +455,10 @@ void pcibios_update_irq(struct pci_dev *, int irq);
 
 extern struct pci_bus *pci_find_bus(int domain, int busnr);
 void pci_bus_add_devices(struct pci_bus *bus);
-struct pci_bus *pci_scan_bus_parented(struct device *parent, int bus, struct pci_ops *ops, void *sysdata);
-static inline struct pci_bus *pci_scan_bus(int bus, struct pci_ops *ops, void *sysdata)
+struct pci_bus *pci_scan_bus_parented(struct device *parent, int bus,
+                                     struct pci_ops *ops, void *sysdata);
+static inline struct pci_bus *pci_scan_bus(int bus, struct pci_ops *ops,
+                                          void *sysdata)
 {
        struct pci_bus *root_bus;
        root_bus = pci_scan_bus_parented(NULL, bus, ops, sysdata);
@@ -468,15 +466,18 @@ static inline struct pci_bus *pci_scan_bus(int bus, struct pci_ops *ops, void *s
                pci_bus_add_devices(root_bus);
        return root_bus;
 }
-struct pci_bus *pci_create_bus(struct device *parent, int bus, struct pci_ops *ops, void *sysdata);
-struct pci_bus * pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev, int busnr);
+struct pci_bus *pci_create_bus(struct device *parent, int bus,
+                              struct pci_ops *ops, void *sysdata);
+struct pci_bus *pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev,
+                               int busnr);
 int pci_scan_slot(struct pci_bus *bus, int devfn);
-struct pci_dev * pci_scan_single_device(struct pci_bus *bus, int devfn);
+struct pci_dev *pci_scan_single_device(struct pci_bus *bus, int devfn);
 void pci_device_add(struct pci_dev *dev, struct pci_bus *bus);
 unsigned int pci_scan_child_bus(struct pci_bus *bus);
 int __must_check pci_bus_add_device(struct pci_dev *dev);
 void pci_read_bridge_bases(struct pci_bus *child);
-struct resource *pci_find_parent_resource(const struct pci_dev *dev, struct resource *res);
+struct resource *pci_find_parent_resource(const struct pci_dev *dev,
+                                         struct resource *res);
 int pci_get_interrupt_pin(struct pci_dev *dev, struct pci_dev **bridge);
 extern struct pci_dev *pci_dev_get(struct pci_dev *dev);
 extern void pci_dev_put(struct pci_dev *dev);
@@ -489,15 +490,19 @@ extern void pci_sort_breadthfirst(void);
 /* Generic PCI functions exported to card drivers */
 
 #ifdef CONFIG_PCI_LEGACY
-struct pci_dev __deprecated *pci_find_device (unsigned int vendor, unsigned int device, const struct pci_dev *from);
-struct pci_dev __deprecated *pci_find_slot (unsigned int bus, unsigned int devfn);
+struct pci_dev __deprecated *pci_find_device(unsigned int vendor,
+                                            unsigned int device,
+                                            const struct pci_dev *from);
+struct pci_dev __deprecated *pci_find_slot(unsigned int bus,
+                                          unsigned int devfn);
 #endif /* CONFIG_PCI_LEGACY */
 
-int pci_find_capability (struct pci_dev *dev, int cap);
-int pci_find_next_capability (struct pci_dev *dev, u8 pos, int cap);
-int pci_find_ext_capability (struct pci_dev *dev, int cap);
-int pci_find_ht_capability (struct pci_dev *dev, int ht_cap);
-int pci_find_next_ht_capability (struct pci_dev *dev, int pos, int ht_cap);
+int pci_find_capability(struct pci_dev *dev, int cap);
+int pci_find_next_capability(struct pci_dev *dev, u8 pos, int cap);
+int pci_find_ext_capability(struct pci_dev *dev, int cap);
+int pci_find_ht_capability(struct pci_dev *dev, int ht_cap);
+int pci_find_next_ht_capability(struct pci_dev *dev, int pos, int ht_cap);
+void pcie_wait_pending_transaction(struct pci_dev *dev);
 struct pci_bus *pci_find_next_bus(const struct pci_bus *from);
 
 struct pci_dev *pci_get_device(unsigned int vendor, unsigned int device,
@@ -505,49 +510,58 @@ struct pci_dev *pci_get_device(unsigned int vendor, unsigned int device,
 struct pci_dev *pci_get_device_reverse(unsigned int vendor, unsigned int device,
                                struct pci_dev *from);
 
-struct pci_dev *pci_get_subsys (unsigned int vendor, unsigned int device,
+struct pci_dev *pci_get_subsys(unsigned int vendor, unsigned int device,
                                unsigned int ss_vendor, unsigned int ss_device,
                                struct pci_dev *from);
-struct pci_dev *pci_get_slot (struct pci_bus *bus, unsigned int devfn);
-struct pci_dev *pci_get_bus_and_slot (unsigned int bus, unsigned int devfn);
-struct pci_dev *pci_get_class (unsigned int class, struct pci_dev *from);
+struct pci_dev *pci_get_slot(struct pci_bus *bus, unsigned int devfn);
+struct pci_dev *pci_get_bus_and_slot(unsigned int bus, unsigned int devfn);
+struct pci_dev *pci_get_class(unsigned int class, struct pci_dev *from);
 int pci_dev_present(const struct pci_device_id *ids);
 const struct pci_device_id *pci_find_present(const struct pci_device_id *ids);
 
-int pci_bus_read_config_byte (struct pci_bus *bus, unsigned int devfn, int where, u8 *val);
-int pci_bus_read_config_word (struct pci_bus *bus, unsigned int devfn, int where, u16 *val);
-int pci_bus_read_config_dword (struct pci_bus *bus, unsigned int devfn, int where, u32 *val);
-int pci_bus_write_config_byte (struct pci_bus *bus, unsigned int devfn, int where, u8 val);
-int pci_bus_write_config_word (struct pci_bus *bus, unsigned int devfn, int where, u16 val);
-int pci_bus_write_config_dword (struct pci_bus *bus, unsigned int devfn, int where, u32 val);
+int pci_bus_read_config_byte(struct pci_bus *bus, unsigned int devfn,
+                            int where, u8 *val);
+int pci_bus_read_config_word(struct pci_bus *bus, unsigned int devfn,
+                            int where, u16 *val);
+int pci_bus_read_config_dword(struct pci_bus *bus, unsigned int devfn,
+                             int where, u32 *val);
+int pci_bus_write_config_byte(struct pci_bus *bus, unsigned int devfn,
+                             int where, u8 val);
+int pci_bus_write_config_word(struct pci_bus *bus, unsigned int devfn,
+                             int where, u16 val);
+int pci_bus_write_config_dword(struct pci_bus *bus, unsigned int devfn,
+                              int where, u32 val);
 
 static inline int pci_read_config_byte(struct pci_dev *dev, int where, u8 *val)
 {
-       return pci_bus_read_config_byte (dev->bus, dev->devfn, where, val);
+       return pci_bus_read_config_byte(dev->bus, dev->devfn, where, val);
 }
 static inline int pci_read_config_word(struct pci_dev *dev, int where, u16 *val)
 {
-       return pci_bus_read_config_word (dev->bus, dev->devfn, where, val);
+       return pci_bus_read_config_word(dev->bus, dev->devfn, where, val);
 }
-static inline int pci_read_config_dword(struct pci_dev *dev, int where, u32 *val)
+static inline int pci_read_config_dword(struct pci_dev *dev, int where,
+                                       u32 *val)
 {
-       return pci_bus_read_config_dword (dev->bus, dev->devfn, where, val);
+       return pci_bus_read_config_dword(dev->bus, dev->devfn, where, val);
 }
 static inline int pci_write_config_byte(struct pci_dev *dev, int where, u8 val)
 {
-       return pci_bus_write_config_byte (dev->bus, dev->devfn, where, val);
+       return pci_bus_write_config_byte(dev->bus, dev->devfn, where, val);
 }
 static inline int pci_write_config_word(struct pci_dev *dev, int where, u16 val)
 {
-       return pci_bus_write_config_word (dev->bus, dev->devfn, where, val);
+       return pci_bus_write_config_word(dev->bus, dev->devfn, where, val);
 }
-static inline int pci_write_config_dword(struct pci_dev *dev, int where, u32 val)
+static inline int pci_write_config_dword(struct pci_dev *dev, int where,
+                                        u32 val)
 {
-       return pci_bus_write_config_dword (dev->bus, dev->devfn, where, val);
+       return pci_bus_write_config_dword(dev->bus, dev->devfn, where, val);
 }
 
 int __must_check pci_enable_device(struct pci_dev *dev);
-int __must_check pci_enable_device_bars(struct pci_dev *dev, int mask);
+int __must_check pci_enable_device_io(struct pci_dev *dev);
+int __must_check pci_enable_device_mem(struct pci_dev *dev);
 int __must_check pci_reenable_device(struct pci_dev *);
 int __must_check pcim_enable_device(struct pci_dev *pdev);
 void pcim_pin_device(struct pci_dev *pdev);
@@ -568,6 +582,8 @@ void pci_intx(struct pci_dev *dev, int enable);
 void pci_msi_off(struct pci_dev *dev);
 int pci_set_dma_mask(struct pci_dev *dev, u64 mask);
 int pci_set_consistent_dma_mask(struct pci_dev *dev, u64 mask);
+int pci_set_dma_max_seg_size(struct pci_dev *dev, unsigned int size);
+int pci_set_dma_seg_boundary(struct pci_dev *dev, unsigned long mask);
 int pcix_get_max_mmrbc(struct pci_dev *dev);
 int pcix_get_mmrbc(struct pci_dev *dev);
 int pcix_set_mmrbc(struct pci_dev *dev, int mmrbc);
@@ -576,14 +592,11 @@ int pcie_set_readrq(struct pci_dev *dev, int rq);
 void pci_update_resource(struct pci_dev *dev, struct resource *res, int resno);
 int __must_check pci_assign_resource(struct pci_dev *dev, int i);
 int __must_check pci_assign_resource_fixed(struct pci_dev *dev, int i);
-void pci_restore_bars(struct pci_dev *dev);
 int pci_select_bars(struct pci_dev *dev, unsigned long flags);
 
 /* ROM control related routines */
 void __iomem __must_check *pci_map_rom(struct pci_dev *pdev, size_t *size);
-void __iomem __must_check *pci_map_rom_copy(struct pci_dev *pdev, size_t *size);
 void pci_unmap_rom(struct pci_dev *pdev, void __iomem *rom);
-void pci_remove_rom(struct pci_dev *pdev);
 size_t pci_get_rom_size(void __iomem *rom, size_t size);
 
 /* Power management related routines */
@@ -594,7 +607,7 @@ pci_power_t pci_choose_state(struct pci_dev *dev, pm_message_t state);
 int pci_enable_wake(struct pci_dev *dev, pci_power_t state, int enable);
 
 /* Functions for PCI Hotplug drivers to use */
-int pci_bus_find_capability (struct pci_bus *bus, unsigned int devfn, int cap);
+int pci_bus_find_capability(struct pci_bus *bus, unsigned int devfn, int cap);
 
 /* Helper functions for low-level code (drivers/pci/setup-[bus,res].c) */
 void pci_bus_assign_resources(struct pci_bus *bus);
@@ -631,16 +644,18 @@ static inline int __must_check pci_register_driver(struct pci_driver *driver)
        return __pci_register_driver(driver, THIS_MODULE, KBUILD_MODNAME);
 }
 
-void pci_unregister_driver(struct pci_driver *);
-void pci_remove_behind_bridge(struct pci_dev *);
-struct pci_driver *pci_dev_driver(const struct pci_dev *);
-const struct pci_device_id *pci_match_id(const struct pci_device_id *ids, struct pci_dev *dev);
-int pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max, int pass);
+void pci_unregister_driver(struct pci_driver *dev);
+void pci_remove_behind_bridge(struct pci_dev *dev);
+struct pci_driver *pci_dev_driver(const struct pci_dev *dev);
+const struct pci_device_id *pci_match_id(const struct pci_device_id *ids,
+                                        struct pci_dev *dev);
+int pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max,
+                   int pass);
 
 void pci_walk_bus(struct pci_bus *top, void (*cb)(struct pci_dev *, void *),
                  void *userdata);
 int pci_cfg_space_size(struct pci_dev *dev);
-unsigned char pci_bus_max_busnr(struct pci_busbus);
+unsigned char pci_bus_max_busnr(struct pci_bus *bus);
 
 /* kmem_cache style wrapper around pci_alloc_consistent() */
 
@@ -669,19 +684,36 @@ struct msix_entry {
 
 
 #ifndef CONFIG_PCI_MSI
-static inline int pci_enable_msi(struct pci_dev *dev) {return -1;}
-static inline void pci_disable_msi(struct pci_dev *dev) {}
-static inline int pci_enable_msix(struct pci_dev* dev,
-       struct msix_entry *entries, int nvec) {return -1;}
-static inline void pci_disable_msix(struct pci_dev *dev) {}
-static inline void msi_remove_pci_irq_vectors(struct pci_dev *dev) {}
+static inline int pci_enable_msi(struct pci_dev *dev)
+{
+       return -1;
+}
+
+static inline void pci_disable_msi(struct pci_dev *dev)
+{ }
+
+static inline int pci_enable_msix(struct pci_dev *dev,
+                                 struct msix_entry *entries, int nvec)
+{
+       return -1;
+}
+
+static inline void pci_disable_msix(struct pci_dev *dev)
+{ }
+
+static inline void msi_remove_pci_irq_vectors(struct pci_dev *dev)
+{ }
+
+static inline void pci_restore_msi_state(struct pci_dev *dev)
+{ }
 #else
 extern int pci_enable_msi(struct pci_dev *dev);
 extern void pci_disable_msi(struct pci_dev *dev);
-extern int pci_enable_msix(struct pci_devdev,
+extern int pci_enable_msix(struct pci_dev *dev,
        struct msix_entry *entries, int nvec);
 extern void pci_disable_msix(struct pci_dev *dev);
 extern void msi_remove_pci_irq_vectors(struct pci_dev *dev);
+extern void pci_restore_msi_state(struct pci_dev *dev);
 #endif
 
 #ifdef CONFIG_HT_IRQ
@@ -702,7 +734,11 @@ extern void pci_unblock_user_cfg_access(struct pci_dev *dev);
 extern int pci_domains_supported;
 #else
 enum { pci_domains_supported = 0 };
-static inline int pci_domain_nr(struct pci_bus *bus) { return 0; }
+static inline int pci_domain_nr(struct pci_bus *bus)
+{
+       return 0;
+}
+
 static inline int pci_proc_domain(struct pci_bus *bus)
 {
        return 0;
@@ -716,67 +752,173 @@ static inline int pci_proc_domain(struct pci_bus *bus)
  *  these as simple inline functions to avoid hair in drivers.
  */
 
-#define _PCI_NOP(o,s,t) \
-       static inline int pci_##o##_config_##s (struct pci_dev *dev, int where, t val) \
+#define _PCI_NOP(o, s, t) \
+       static inline int pci_##o##_config_##s(struct pci_dev *dev, \
+                                               int where, t val) \
                { return PCIBIOS_FUNC_NOT_SUPPORTED; }
-#define _PCI_NOP_ALL(o,x)      _PCI_NOP(o,byte,u8 x) \
-                               _PCI_NOP(o,word,u16 x) \
-                               _PCI_NOP(o,dword,u32 x)
+
+#define _PCI_NOP_ALL(o, x)     _PCI_NOP(o, byte, u8 x) \
+                               _PCI_NOP(o, word, u16 x) \
+                               _PCI_NOP(o, dword, u32 x)
 _PCI_NOP_ALL(read, *)
 _PCI_NOP_ALL(write,)
 
-static inline struct pci_dev *pci_find_device(unsigned int vendor, unsigned int device, const struct pci_dev *from)
-{ return NULL; }
+static inline struct pci_dev *pci_find_device(unsigned int vendor,
+                                             unsigned int device,
+                                             const struct pci_dev *from)
+{
+       return NULL;
+}
 
-static inline struct pci_dev *pci_find_slot(unsigned int bus, unsigned int devfn)
-{ return NULL; }
+static inline struct pci_dev *pci_find_slot(unsigned int bus,
+                                           unsigned int devfn)
+{
+       return NULL;
+}
 
 static inline struct pci_dev *pci_get_device(unsigned int vendor,
-                               unsigned int device, struct pci_dev *from)
-{ return NULL; }
+                                            unsigned int device,
+                                            struct pci_dev *from)
+{
+       return NULL;
+}
 
 static inline struct pci_dev *pci_get_device_reverse(unsigned int vendor,
-                               unsigned int device, struct pci_dev *from)
-{ return NULL; }
+                                                    unsigned int device,
+                                                    struct pci_dev *from)
+{
+       return NULL;
+}
 
-static inline struct pci_dev *pci_get_subsys (unsigned int vendor, unsigned int device,
-unsigned int ss_vendor, unsigned int ss_device, struct pci_dev *from)
-{ return NULL; }
+static inline struct pci_dev *pci_get_subsys(unsigned int vendor,
+                                            unsigned int device,
+                                            unsigned int ss_vendor,
+                                            unsigned int ss_device,
+                                            struct pci_dev *from)
+{
+       return NULL;
+}
 
-static inline struct pci_dev *pci_get_class(unsigned int class, struct pci_dev *from)
-{ return NULL; }
+static inline struct pci_dev *pci_get_class(unsigned int class,
+                                           struct pci_dev *from)
+{
+       return NULL;
+}
 
 #define pci_dev_present(ids)   (0)
 #define no_pci_devices()       (1)
 #define pci_find_present(ids)  (NULL)
 #define pci_dev_put(dev)       do { } while (0)
 
-static inline void pci_set_master(struct pci_dev *dev) { }
-static inline int pci_enable_device(struct pci_dev *dev) { return -EIO; }
-static inline void pci_disable_device(struct pci_dev *dev) { }
-static inline int pci_set_dma_mask(struct pci_dev *dev, u64 mask) { return -EIO; }
-static inline int pci_assign_resource(struct pci_dev *dev, int i) { return -EBUSY;}
-static inline int __pci_register_driver(struct pci_driver *drv, struct module *owner) { return 0;}
-static inline int pci_register_driver(struct pci_driver *drv) { return 0;}
-static inline void pci_unregister_driver(struct pci_driver *drv) { }
-static inline int pci_find_capability (struct pci_dev *dev, int cap) {return 0; }
-static inline int pci_find_next_capability (struct pci_dev *dev, u8 post, int cap) { return 0; }
-static inline int pci_find_ext_capability (struct pci_dev *dev, int cap) {return 0; }
+static inline void pci_set_master(struct pci_dev *dev)
+{ }
+
+static inline int pci_enable_device(struct pci_dev *dev)
+{
+       return -EIO;
+}
+
+static inline void pci_disable_device(struct pci_dev *dev)
+{ }
+
+static inline int pci_set_dma_mask(struct pci_dev *dev, u64 mask)
+{
+       return -EIO;
+}
+
+static inline int pci_set_dma_max_seg_size(struct pci_dev *dev,
+                                       unsigned int size)
+{
+       return -EIO;
+}
+
+static inline int pci_set_dma_seg_boundary(struct pci_dev *dev,
+                                       unsigned long mask)
+{
+       return -EIO;
+}
+
+static inline int pci_assign_resource(struct pci_dev *dev, int i)
+{
+       return -EBUSY;
+}
+
+static inline int __pci_register_driver(struct pci_driver *drv,
+                                       struct module *owner)
+{
+       return 0;
+}
+
+static inline int pci_register_driver(struct pci_driver *drv)
+{
+       return 0;
+}
+
+static inline void pci_unregister_driver(struct pci_driver *drv)
+{ }
+
+static inline int pci_find_capability(struct pci_dev *dev, int cap)
+{
+       return 0;
+}
+
+static inline int pci_find_next_capability(struct pci_dev *dev, u8 post,
+                                          int cap)
+{
+       return 0;
+}
+
+static inline int pci_find_ext_capability(struct pci_dev *dev, int cap)
+{
+       return 0;
+}
+
+static inline void pcie_wait_pending_transaction(struct pci_dev *dev)
+{ }
 
 /* Power management related routines */
-static inline int pci_save_state(struct pci_dev *dev) { return 0; }
-static inline int pci_restore_state(struct pci_dev *dev) { return 0; }
-static inline int pci_set_power_state(struct pci_dev *dev, pci_power_t state) { return 0; }
-static inline pci_power_t pci_choose_state(struct pci_dev *dev, pm_message_t state) { return PCI_D0; }
-static inline int pci_enable_wake(struct pci_dev *dev, pci_power_t state, int enable) { return 0; }
+static inline int pci_save_state(struct pci_dev *dev)
+{
+       return 0;
+}
 
-static inline int pci_request_regions(struct pci_dev *dev, const char *res_name) { return -EIO; }
-static inline void pci_release_regions(struct pci_dev *dev) { }
+static inline int pci_restore_state(struct pci_dev *dev)
+{
+       return 0;
+}
+
+static inline int pci_set_power_state(struct pci_dev *dev, pci_power_t state)
+{
+       return 0;
+}
+
+static inline pci_power_t pci_choose_state(struct pci_dev *dev,
+                                          pm_message_t state)
+{
+       return PCI_D0;
+}
+
+static inline int pci_enable_wake(struct pci_dev *dev, pci_power_t state,
+                                 int enable)
+{
+       return 0;
+}
+
+static inline int pci_request_regions(struct pci_dev *dev, const char *res_name)
+{
+       return -EIO;
+}
+
+static inline void pci_release_regions(struct pci_dev *dev)
+{ }
 
 #define pci_dma_burst_advice(pdev, strat, strategy_parameter) do { } while (0)
 
-static inline void pci_block_user_cfg_access(struct pci_dev *dev) { }
-static inline void pci_unblock_user_cfg_access(struct pci_dev *dev) { }
+static inline void pci_block_user_cfg_access(struct pci_dev *dev)
+{ }
+
+static inline void pci_unblock_user_cfg_access(struct pci_dev *dev)
+{ }
 
 static inline struct pci_bus *pci_find_next_bus(const struct pci_bus *from)
 { return NULL; }
@@ -797,27 +939,27 @@ static inline struct pci_dev *pci_get_bus_and_slot(unsigned int bus,
 
 /* these helpers provide future and backwards compatibility
  * for accessing popular PCI BAR info */
-#define pci_resource_start(dev,bar)   ((dev)->resource[(bar)].start)
-#define pci_resource_end(dev,bar)     ((dev)->resource[(bar)].end)
-#define pci_resource_flags(dev,bar)   ((dev)->resource[(bar)].flags)
+#define pci_resource_start(dev, bar)   ((dev)->resource[(bar)].start)
+#define pci_resource_end(dev, bar)     ((dev)->resource[(bar)].end)
+#define pci_resource_flags(dev, bar)   ((dev)->resource[(bar)].flags)
 #define pci_resource_len(dev,bar) \
-       ((pci_resource_start((dev),(bar)) == 0 &&       \
-         pci_resource_end((dev),(bar)) ==              \
-         pci_resource_start((dev),(bar))) ? 0 :        \
-                                                       \
-        (pci_resource_end((dev),(bar)) -               \
-         pci_resource_start((dev),(bar)) + 1))
+       ((pci_resource_start((dev), (bar)) == 0 &&      \
+         pci_resource_end((dev), (bar)) ==             \
+         pci_resource_start((dev), (bar))) ? 0 :       \
+                                                       \
+        (pci_resource_end((dev), (bar)) -              \
+         pci_resource_start((dev), (bar)) + 1))
 
 /* Similar to the helpers above, these manipulate per-pci_dev
  * driver-specific data.  They are really just a wrapper around
  * the generic device structure functions of these calls.
  */
-static inline void *pci_get_drvdata (struct pci_dev *pdev)
+static inline void *pci_get_drvdata(struct pci_dev *pdev)
 {
        return dev_get_drvdata(&pdev->dev);
 }
 
-static inline void pci_set_drvdata (struct pci_dev *pdev, void *data)
+static inline void pci_set_drvdata(struct pci_dev *pdev, void *data)
 {
        dev_set_drvdata(&pdev->dev, data);
 }
@@ -836,7 +978,7 @@ static inline char *pci_name(struct pci_dev *pdev)
  */
 #ifndef HAVE_ARCH_PCI_RESOURCE_TO_USER
 static inline void pci_resource_to_user(const struct pci_dev *dev, int bar,
-                const struct resource *rsrc, resource_size_t *start,
+               const struct resource *rsrc, resource_size_t *start,
                resource_size_t *end)
 {
        *start = rsrc->start;
@@ -888,9 +1030,9 @@ enum pci_fixup_pass {
 
 void pci_fixup_device(enum pci_fixup_pass pass, struct pci_dev *dev);
 
-void __iomem * pcim_iomap(struct pci_dev *pdev, int bar, unsigned long maxlen);
+void __iomem *pcim_iomap(struct pci_dev *pdev, int bar, unsigned long maxlen);
 void pcim_iounmap(struct pci_dev *pdev, void __iomem *addr);
-void __iomem * const * pcim_iomap_table(struct pci_dev *pdev);
+void __iomem * const *pcim_iomap_table(struct pci_dev *pdev);
 int pcim_iomap_regions(struct pci_dev *pdev, u16 mask, const char *name);
 void pcim_iounmap_regions(struct pci_dev *pdev, u16 mask);
 
index 41f6f28690f63be67aa43a2a162a1d349dc347e3..39d32837265bad125cc14ef80bda71e8554ada07 100644 (file)
 #define PCI_VENDOR_ID_QUICKNET         0x15e2
 #define PCI_DEVICE_ID_QUICKNET_XJ      0x0500
 
+/*
+ * ADDI-DATA GmbH communication cards <info@addi-data.com>
+ */
+#define PCI_VENDOR_ID_ADDIDATA_OLD             0x10E8
+#define PCI_VENDOR_ID_ADDIDATA                 0x15B8
+#define PCI_DEVICE_ID_ADDIDATA_APCI7500        0x7000
+#define PCI_DEVICE_ID_ADDIDATA_APCI7420        0x7001
+#define PCI_DEVICE_ID_ADDIDATA_APCI7300        0x7002
+#define PCI_DEVICE_ID_ADDIDATA_APCI7800        0x818E
+#define PCI_DEVICE_ID_ADDIDATA_APCI7500_2      0x7009
+#define PCI_DEVICE_ID_ADDIDATA_APCI7420_2      0x700A
+#define PCI_DEVICE_ID_ADDIDATA_APCI7300_2      0x700B
+#define PCI_DEVICE_ID_ADDIDATA_APCI7500_3      0x700C
+#define PCI_DEVICE_ID_ADDIDATA_APCI7420_3      0x700D
+#define PCI_DEVICE_ID_ADDIDATA_APCI7300_3      0x700E
+#define PCI_DEVICE_ID_ADDIDATA_APCI7800_3      0x700F
+
 #define PCI_VENDOR_ID_PDC              0x15e9
 
 #define PCI_VENDOR_ID_FARSITE           0x1619
index 1375f15797e7d919970735796a6d7093df0cfec7..225beb136807dd4650288464c2b4f4ffb8de2e59 100644 (file)
@@ -26,6 +26,7 @@ struct pda_power_pdata {
 
        unsigned int wait_for_status; /* msecs, default is 500 */
        unsigned int wait_for_charger; /* msecs, default is 500 */
+       unsigned int polling_interval; /* msecs, default is 2000 */
 };
 
 #endif /* __PDA_POWER_H__ */
index 00412bb494c40b100bc1e996983b72ba877ccf69..50faa0ea28e4a7a392f617863e0ab82d4d9c330c 100644 (file)
@@ -9,10 +9,6 @@
 
 #include <asm/percpu.h>
 
-#ifndef PER_CPU_ATTRIBUTES
-#define PER_CPU_ATTRIBUTES
-#endif
-
 #ifdef CONFIG_SMP
 #define DEFINE_PER_CPU(type, name)                                     \
        __attribute__((__section__(".data.percpu")))                    \
index d9db5f62ee4878d1cb71f6da1587a76cbce50ff5..6db69ff5d83eb9f2b6bf137556246ea48cdba03a 100644 (file)
@@ -298,6 +298,12 @@ struct sadb_x_sec_ctx {
 #define SADB_X_EALG_BLOWFISHCBC                7
 #define SADB_EALG_NULL                 11
 #define SADB_X_EALG_AESCBC             12
+#define SADB_X_EALG_AES_CCM_ICV8       14
+#define SADB_X_EALG_AES_CCM_ICV12      15
+#define SADB_X_EALG_AES_CCM_ICV16      16
+#define SADB_X_EALG_AES_GCM_ICV8       18
+#define SADB_X_EALG_AES_GCM_ICV12      19
+#define SADB_X_EALG_AES_GCM_ICV16      20
 #define SADB_X_EALG_CAMELLIACBC                22
 #define SADB_EALG_MAX                   253 /* last EALG */
 /* private allocations should use 249-255 (RFC2407) */
index 554836edd915ef027011a9127b81b7188f3388ad..5e43ae7514122af688dc4679c04dd927856cb58b 100644 (file)
@@ -88,7 +88,7 @@ struct mii_bus {
 
        /* A lock to ensure that only one thing can read/write
         * the MDIO bus at a time */
-       spinlock_t mdio_lock;
+       struct mutex mdio_lock;
 
        struct device *dev;
 
@@ -284,10 +284,11 @@ struct phy_device {
 
        /* Interrupt and Polling infrastructure */
        struct work_struct phy_queue;
+       struct work_struct state_queue;
        struct timer_list phy_timer;
        atomic_t irq_disable;
 
-       spinlock_t lock;
+       struct mutex lock;
 
        struct net_device *attached_dev;
 
index 30b8571e6b34c25b2311291ad460e2d1754e7862..40fac8c4559d3c081f07cd35f7bb8c3e5dedf09b 100644 (file)
@@ -328,6 +328,56 @@ enum
 
 #define TCA_TCINDEX_MAX     (__TCA_TCINDEX_MAX - 1)
 
+/* Flow filter */
+
+enum
+{
+       FLOW_KEY_SRC,
+       FLOW_KEY_DST,
+       FLOW_KEY_PROTO,
+       FLOW_KEY_PROTO_SRC,
+       FLOW_KEY_PROTO_DST,
+       FLOW_KEY_IIF,
+       FLOW_KEY_PRIORITY,
+       FLOW_KEY_MARK,
+       FLOW_KEY_NFCT,
+       FLOW_KEY_NFCT_SRC,
+       FLOW_KEY_NFCT_DST,
+       FLOW_KEY_NFCT_PROTO_SRC,
+       FLOW_KEY_NFCT_PROTO_DST,
+       FLOW_KEY_RTCLASSID,
+       FLOW_KEY_SKUID,
+       FLOW_KEY_SKGID,
+       __FLOW_KEY_MAX,
+};
+
+#define FLOW_KEY_MAX   (__FLOW_KEY_MAX - 1)
+
+enum
+{
+       FLOW_MODE_MAP,
+       FLOW_MODE_HASH,
+};
+
+enum
+{
+       TCA_FLOW_UNSPEC,
+       TCA_FLOW_KEYS,
+       TCA_FLOW_MODE,
+       TCA_FLOW_BASECLASS,
+       TCA_FLOW_RSHIFT,
+       TCA_FLOW_ADDEND,
+       TCA_FLOW_MASK,
+       TCA_FLOW_XOR,
+       TCA_FLOW_DIVISOR,
+       TCA_FLOW_ACT,
+       TCA_FLOW_POLICE,
+       TCA_FLOW_EMATCHES,
+       __TCA_FLOW_MAX
+};
+
+#define TCA_FLOW_MAX   (__TCA_FLOW_MAX - 1)
+
 /* Basic filter */
 
 enum
@@ -409,7 +459,8 @@ enum
 #define        TCF_EM_U32              3
 #define        TCF_EM_META             4
 #define        TCF_EM_TEXT             5
-#define        TCF_EM_MAX              5
+#define        TCF_EM_VLAN             6
+#define        TCF_EM_MAX              6
 
 enum
 {
index 32761352e858cd4c95b15ab215b8c39be9fe756e..dbb7ac37960d2a092d4250235aa3a37e5a97e61c 100644 (file)
@@ -150,6 +150,11 @@ struct tc_sfq_qopt
        unsigned        flows;          /* Maximal number of flows  */
 };
 
+struct tc_sfq_xstats
+{
+       __s32           allot;
+};
+
 /*
  *  NOTE: limit, divisor and flows are hardwired to code at the moment.
  *
index b78e0295adf4342732b42d8ffd588a48771e2b79..eccf59ea2a77ba107359fd74288aa6043ff4140a 100644 (file)
@@ -95,7 +95,7 @@ struct pm_dev
 };
 
 /* Functions above this comment are list-based old-style power
- * managment. Please avoid using them.  */
+ * management. Please avoid using them.  */
 
 /*
  * Callbacks for platform drivers to implement.
diff --git a/include/linux/pm_qos_params.h b/include/linux/pm_qos_params.h
new file mode 100644 (file)
index 0000000..2e4e97b
--- /dev/null
@@ -0,0 +1,25 @@
+/* interface for the pm_qos_power infrastructure of the linux kernel.
+ *
+ * Mark Gross
+ */
+#include <linux/list.h>
+#include <linux/notifier.h>
+#include <linux/miscdevice.h>
+
+#define PM_QOS_RESERVED 0
+#define PM_QOS_CPU_DMA_LATENCY 1
+#define PM_QOS_NETWORK_LATENCY 2
+#define PM_QOS_NETWORK_THROUGHPUT 3
+
+#define PM_QOS_NUM_CLASSES 4
+#define PM_QOS_DEFAULT_VALUE -1
+
+int pm_qos_add_requirement(int qos, char *name, s32 value);
+int pm_qos_update_requirement(int qos, char *name, s32 new_value);
+void pm_qos_remove_requirement(int qos, char *name);
+
+int pm_qos_requirement(int qos);
+
+int pm_qos_add_notifier(int qos, struct notifier_block *notifier);
+int pm_qos_remove_notifier(int qos, struct notifier_block *notifier);
+
index 2a6d62c7d2d1a5d8f58baad15d82e9a198eb4993..b9339d8b95bcbf68c0f0c4d304734748f40472e7 100644 (file)
@@ -126,7 +126,7 @@ struct pnp_resource_table {
 };
 
 /*
- * Device Managemnt
+ * Device Management
  */
 
 struct pnp_card {
index 606c0957997f8b59d87c61611b1dddd96d7e206f..5cbf3e371012a8ed26b361d72a1614d4d9a0c03b 100644 (file)
@@ -54,15 +54,7 @@ enum {
        POWER_SUPPLY_TECHNOLOGY_LIPO,
        POWER_SUPPLY_TECHNOLOGY_LiFe,
        POWER_SUPPLY_TECHNOLOGY_NiCd,
-};
-
-enum {
-       POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN = 0,
-       POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL,
-       POWER_SUPPLY_CAPACITY_LEVEL_LOW,
-       POWER_SUPPLY_CAPACITY_LEVEL_NORMAL,
-       POWER_SUPPLY_CAPACITY_LEVEL_HIGH,
-       POWER_SUPPLY_CAPACITY_LEVEL_FULL,
+       POWER_SUPPLY_TECHNOLOGY_LiMn,
 };
 
 enum power_supply_property {
@@ -72,6 +64,8 @@ enum power_supply_property {
        POWER_SUPPLY_PROP_PRESENT,
        POWER_SUPPLY_PROP_ONLINE,
        POWER_SUPPLY_PROP_TECHNOLOGY,
+       POWER_SUPPLY_PROP_VOLTAGE_MAX,
+       POWER_SUPPLY_PROP_VOLTAGE_MIN,
        POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
        POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
        POWER_SUPPLY_PROP_VOLTAGE_NOW,
@@ -91,7 +85,6 @@ enum power_supply_property {
        POWER_SUPPLY_PROP_ENERGY_NOW,
        POWER_SUPPLY_PROP_ENERGY_AVG,
        POWER_SUPPLY_PROP_CAPACITY, /* in percents! */
-       POWER_SUPPLY_PROP_CAPACITY_LEVEL,
        POWER_SUPPLY_PROP_TEMP,
        POWER_SUPPLY_PROP_TEMP_AMBIENT,
        POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW,
index e2eff9079fe9ff9f02f7e9704479571c02cdd9aa..3800639775aee4706734b1aa9bb3e55104fe4f3b 100644 (file)
@@ -63,4 +63,8 @@
 #define PR_GET_SECCOMP 21
 #define PR_SET_SECCOMP 22
 
+/* Get/set the capability bounding set */
+#define PR_CAPBSET_READ 23
+#define PR_CAPBSET_DROP 24
+
 #endif /* _LINUX_PRCTL_H */
index 8f92546b403d205633bb51e417913a1ec420a41d..e43551516831c53d2fd2ba021de863a54b02e709 100644 (file)
@@ -19,6 +19,8 @@ struct completion;
  */
 #define FIRST_PROCESS_ENTRY 256
 
+/* Worst case buffer size needed for holding an integer. */
+#define PROC_NUMBUF 13
 
 /*
  * We always define these enumerators
@@ -117,7 +119,6 @@ int proc_pid_readdir(struct file * filp, void * dirent, filldir_t filldir);
 unsigned long task_vsize(struct mm_struct *);
 int task_statm(struct mm_struct *, int *, int *, int *, int *);
 char *task_mem(struct mm_struct *, char *);
-void clear_refs_smap(struct mm_struct *mm);
 
 struct proc_dir_entry *de_get(struct proc_dir_entry *de);
 void de_put(struct proc_dir_entry *de);
index b6116b4445c760f01f0f133ad9530af71b6f09d0..b8ce2b444bb51b3f74130a0ad11acbf3d729069e 100644 (file)
@@ -91,7 +91,7 @@ do {                                                                  \
  *
  * For API usage, in general,
  * - any function _modifying_ the tree or tags (inserting or deleting
- *   items, setting or clearing tags must exclude other modifications, and
+ *   items, setting or clearing tags) must exclude other modifications, and
  *   exclude any functions reading the tree.
  * - any function _reading_ the tree or tags (looking up items or tags,
  *   gang lookups) must exclude modifications to the tree, but may occur
index 85ea63f462af39fe0b589ac236baae4ee2831b39..b93b541cf111d08701c40939b9f201429a213e56 100644 (file)
@@ -59,8 +59,6 @@ extern void machine_crash_shutdown(struct pt_regs *);
  * Architecture independent implemenations of sys_reboot commands.
  */
 
-extern void kernel_shutdown_prepare(enum system_states state);
-
 extern void kernel_restart(char *cmd);
 extern void kernel_halt(void);
 extern void kernel_power_off(void);
index 10fa0c832018c870a7bac82b428cdb976cb34449..db5ef9b83c3ff366be21465ffe2a86a5602032f4 100644 (file)
@@ -185,7 +185,7 @@ struct reiserfs_journal {
        unsigned long j_trans_id;
        unsigned long j_mount_id;
        unsigned long j_start;  /* start of current waiting commit (index into j_ap_blocks) */
-       unsigned long j_len;    /* lenght of current waiting commit */
+       unsigned long j_len;    /* length of current waiting commit */
        unsigned long j_len_alloc;      /* number of buffers requested by journal_begin() */
        atomic_t j_wcount;      /* count of writers for current commit */
        unsigned long j_bcount; /* batch count. allows turning X transactions into 1 */
index 0ce5e0b52dbdef816607be8beae4c1b620b8b95a..e3ab21d7fc7f1973ec9483885012d83e800e1eb9 100644 (file)
  * RFKILL_TYPE_WLAN: switch is on a 802.11 wireless network device.
  * RFKILL_TYPE_BLUETOOTH: switch is on a bluetooth device.
  * RFKILL_TYPE_UWB: switch is on a ultra wideband device.
+ * RFKILL_TYPE_WIMAX: switch is on a WiMAX device.
  */
 enum rfkill_type {
        RFKILL_TYPE_WLAN ,
        RFKILL_TYPE_BLUETOOTH,
        RFKILL_TYPE_UWB,
+       RFKILL_TYPE_WIMAX,
        RFKILL_TYPE_MAX,
 };
 
index b014f6b7fe2918784d1095c6cd8c25f3668862a9..b9e174079002300dee538600e8e6e5585757aed8 100644 (file)
@@ -602,24 +602,12 @@ struct tcamsg
 
 #include <linux/mutex.h>
 
-extern size_t rtattr_strlcpy(char *dest, const struct rtattr *rta, size_t size);
 static __inline__ int rtattr_strcmp(const struct rtattr *rta, const char *str)
 {
        int len = strlen(str) + 1;
        return len > rta->rta_len || memcmp(RTA_DATA(rta), str, len);
 }
 
-extern int rtattr_parse(struct rtattr *tb[], int maxattr, struct rtattr *rta, int len);
-extern int __rtattr_parse_nested_compat(struct rtattr *tb[], int maxattr,
-                                       struct rtattr *rta, int len);
-
-#define rtattr_parse_nested(tb, max, rta) \
-       rtattr_parse((tb), (max), RTA_DATA((rta)), RTA_PAYLOAD((rta)))
-
-#define rtattr_parse_nested_compat(tb, max, rta, data, len) \
-({     data = RTA_PAYLOAD(rta) >= len ? RTA_DATA(rta) : NULL; \
-       __rtattr_parse_nested_compat(tb, max, rta, len); })
-
 extern int rtnetlink_send(struct sk_buff *skb, struct net *net, u32 pid, u32 group, int echo);
 extern int rtnl_unicast(struct sk_buff *skb, struct net *net, u32 pid);
 extern int rtnl_notify(struct sk_buff *skb, struct net *net, u32 pid, u32 group,
index 9d4797609aa5e368439671d603da5f7e7bedb979..9c13be3a21e80509100ffb8ea8fda59fa238c7cf 100644 (file)
@@ -172,13 +172,35 @@ print_cfs_rq(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq)
 #define TASK_RUNNING           0
 #define TASK_INTERRUPTIBLE     1
 #define TASK_UNINTERRUPTIBLE   2
-#define TASK_STOPPED           4
-#define TASK_TRACED            8
+#define __TASK_STOPPED         4
+#define __TASK_TRACED          8
 /* in tsk->exit_state */
 #define EXIT_ZOMBIE            16
 #define EXIT_DEAD              32
 /* in tsk->state again */
 #define TASK_DEAD              64
+#define TASK_WAKEKILL          128
+
+/* Convenience macros for the sake of set_task_state */
+#define TASK_KILLABLE          (TASK_WAKEKILL | TASK_UNINTERRUPTIBLE)
+#define TASK_STOPPED           (TASK_WAKEKILL | __TASK_STOPPED)
+#define TASK_TRACED            (TASK_WAKEKILL | __TASK_TRACED)
+
+/* Convenience macros for the sake of wake_up */
+#define TASK_NORMAL            (TASK_INTERRUPTIBLE | TASK_UNINTERRUPTIBLE)
+#define TASK_ALL               (TASK_NORMAL | __TASK_STOPPED | __TASK_TRACED)
+
+/* get_task_state() */
+#define TASK_REPORT            (TASK_RUNNING | TASK_INTERRUPTIBLE | \
+                                TASK_UNINTERRUPTIBLE | __TASK_STOPPED | \
+                                __TASK_TRACED)
+
+#define task_is_traced(task)   ((task->state & __TASK_TRACED) != 0)
+#define task_is_stopped(task)  ((task->state & __TASK_STOPPED) != 0)
+#define task_is_stopped_or_traced(task)        \
+                       ((task->state & (__TASK_STOPPED | __TASK_TRACED)) != 0)
+#define task_contributes_to_load(task) \
+                               ((task->state & TASK_UNINTERRUPTIBLE) != 0)
 
 #define __set_task_state(tsk, state_value)             \
        do { (tsk)->state = (state_value); } while (0)
@@ -302,6 +324,7 @@ extern int in_sched_functions(unsigned long addr);
 #define        MAX_SCHEDULE_TIMEOUT    LONG_MAX
 extern signed long FASTCALL(schedule_timeout(signed long timeout));
 extern signed long schedule_timeout_interruptible(signed long timeout);
+extern signed long schedule_timeout_killable(signed long timeout);
 extern signed long schedule_timeout_uninterruptible(signed long timeout);
 asmlinkage void schedule(void);
 
@@ -532,6 +555,13 @@ struct signal_struct {
 #define SIGNAL_STOP_CONTINUED  0x00000004 /* SIGCONT since WCONTINUED reap */
 #define SIGNAL_GROUP_EXIT      0x00000008 /* group exit in progress */
 
+/* If true, all threads except ->group_exit_task have pending SIGKILL */
+static inline int signal_group_exit(const struct signal_struct *sig)
+{
+       return  (sig->flags & SIGNAL_GROUP_EXIT) ||
+               (sig->group_exit_task != NULL);
+}
+
 /*
  * Some day this will be a full-fledged user tracking system..
  */
@@ -1068,7 +1098,7 @@ struct task_struct {
        uid_t uid,euid,suid,fsuid;
        gid_t gid,egid,sgid,fsgid;
        struct group_info *group_info;
-       kernel_cap_t   cap_effective, cap_inheritable, cap_permitted;
+       kernel_cap_t   cap_effective, cap_inheritable, cap_permitted, cap_bset;
        unsigned keep_capabilities:1;
        struct user_struct *user;
 #ifdef CONFIG_KEYS
@@ -1116,6 +1146,10 @@ struct task_struct {
        void *security;
 #endif
        struct audit_context *audit_context;
+#ifdef CONFIG_AUDITSYSCALL
+       uid_t loginuid;
+       unsigned int sessionid;
+#endif
        seccomp_t seccomp;
 
 /* Thread group tracking */
@@ -1743,7 +1777,7 @@ extern long do_fork(unsigned long, unsigned long, struct pt_regs *, unsigned lon
 struct task_struct *fork_idle(int);
 
 extern void set_task_comm(struct task_struct *tsk, char *from);
-extern void get_task_comm(char *to, struct task_struct *tsk);
+extern char *get_task_comm(char *to, struct task_struct *tsk);
 
 #ifdef CONFIG_SMP
 extern void wait_task_inactive(struct task_struct * p);
@@ -1892,7 +1926,14 @@ static inline int signal_pending(struct task_struct *p)
 {
        return unlikely(test_tsk_thread_flag(p,TIF_SIGPENDING));
 }
-  
+
+extern int FASTCALL(__fatal_signal_pending(struct task_struct *p));
+
+static inline int fatal_signal_pending(struct task_struct *p)
+{
+       return signal_pending(p) && __fatal_signal_pending(p);
+}
+
 static inline int need_resched(void)
 {
        return unlikely(test_thread_flag(TIF_NEED_RESCHED));
@@ -2046,6 +2087,10 @@ static inline void migration_init(void)
 }
 #endif
 
+#ifndef TASK_SIZE_OF
+#define TASK_SIZE_OF(tsk)      TASK_SIZE
+#endif
+
 #endif /* __KERNEL__ */
 
 #endif
index d24974262dc62a9376e6c6ffd1a4e7f42ca0196a..fe52cdeab0a67ba5cd1220383b9bd0872efd78e1 100644 (file)
 #define ROOTCONTEXT_MNT                0x04
 #define DEFCONTEXT_MNT         0x08
 
-/*
- * Bounding set
- */
-extern kernel_cap_t cap_bset;
-
 extern unsigned securebits;
 
 struct ctl_table;
@@ -423,15 +418,12 @@ struct request_sock;
  *     identified by @name for @dentry.
  *     Return 0 if permission is granted.
  * @inode_getsecurity:
- *     Copy the extended attribute representation of the security label 
- *     associated with @name for @inode into @buffer.  @buffer may be
- *     NULL to request the size of the buffer required.  @size indicates
- *     the size of @buffer in bytes.  Note that @name is the remainder
- *     of the attribute name after the security. prefix has been removed.
- *     @err is the return value from the preceding fs getxattr call,
- *     and can be used by the security module to determine whether it
- *     should try and canonicalize the attribute value.
- *     Return number of bytes used/required on success.
+ *     Retrieve a copy of the extended attribute representation of the
+ *     security label associated with @name for @inode via @buffer.  Note that
+ *     @name is the remainder of the attribute name after the security prefix
+ *     has been removed. @alloc is used to specify of the call should return a
+ *     value via the buffer or just the value length Return size of buffer on
+ *     success.
  * @inode_setsecurity:
  *     Set the security label associated with @name for @inode from the
  *     extended attribute value @value.  @size indicates the size of the
@@ -1304,7 +1296,7 @@ struct security_operations {
        int (*inode_removexattr) (struct dentry *dentry, char *name);
        int (*inode_need_killpriv) (struct dentry *dentry);
        int (*inode_killpriv) (struct dentry *dentry);
-       int (*inode_getsecurity)(const struct inode *inode, const char *name, void *buffer, size_t size, int err);
+       int (*inode_getsecurity)(const struct inode *inode, const char *name, void **buffer, bool alloc);
        int (*inode_setsecurity)(struct inode *inode, const char *name, const void *value, size_t size, int flags);
        int (*inode_listsecurity)(struct inode *inode, char *buffer, size_t buffer_size);
 
@@ -1565,7 +1557,7 @@ int security_inode_listxattr(struct dentry *dentry);
 int security_inode_removexattr(struct dentry *dentry, char *name);
 int security_inode_need_killpriv(struct dentry *dentry);
 int security_inode_killpriv(struct dentry *dentry);
-int security_inode_getsecurity(const struct inode *inode, const char *name, void *buffer, size_t size, int err);
+int security_inode_getsecurity(const struct inode *inode, const char *name, void **buffer, bool alloc);
 int security_inode_setsecurity(struct inode *inode, const char *name, const void *value, size_t size, int flags);
 int security_inode_listsecurity(struct inode *inode, char *buffer, size_t buffer_size);
 int security_file_permission(struct file *file, int mask);
@@ -1967,7 +1959,7 @@ static inline int security_inode_killpriv(struct dentry *dentry)
        return cap_inode_killpriv(dentry);
 }
 
-static inline int security_inode_getsecurity(const struct inode *inode, const char *name, void *buffer, size_t size, int err)
+static inline int security_inode_getsecurity(const struct inode *inode, const char *name, void **buffer, bool alloc)
 {
        return -EOPNOTSUPP;
 }
index afe0f6d9b9bcbfdbc39d726f5a202307d3ddbc81..00b65c0a82ca0a1c00d1ea862e098c88f9689684 100644 (file)
@@ -23,6 +23,7 @@ struct plat_serial8250_port {
        resource_size_t mapbase;        /* resource base */
        unsigned int    irq;            /* interrupt number */
        unsigned int    uartclk;        /* UART clock rate */
+       void            *private_data;
        unsigned char   regshift;       /* register shift */
        unsigned char   iotype;         /* UPIO_* */
        unsigned char   hub6;
index 86f9b1ef0e0934c9a354b44a67ab396be61ccbe4..ea037f28df91372d208a2e4301b24e21369596ca 100644 (file)
@@ -29,7 +29,7 @@ struct signalfd_siginfo {
 
        /*
         * Pad strcture to 128 bytes. Remember to update the
-        * pad size when you add new memebers. We use a fixed
+        * pad size when you add new members. We use a fixed
         * size structure to avoid compatibility problems with
         * future versions, and we leave extra space for additional
         * members. We use fixed size members because this strcture
index c618fbf7d173c4974da2adf399edf51a2c5034cc..412672a79e8a9f237bd4dff87eb85df62fcf428c 100644 (file)
@@ -108,9 +108,6 @@ struct nf_bridge_info {
        atomic_t use;
        struct net_device *physindev;
        struct net_device *physoutdev;
-#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
-       struct net_device *netoutdev;
-#endif
        unsigned int mask;
        unsigned long data[32 / sizeof(unsigned long)];
 };
@@ -1813,5 +1810,6 @@ static inline void skb_forward_csum(struct sk_buff *skb)
                skb->ip_summed = CHECKSUM_NONE;
 }
 
+bool skb_partial_csum_set(struct sk_buff *skb, u16 start, u16 off);
 #endif /* __KERNEL__ */
 #endif /* _LINUX_SKBUFF_H */
index 40801e754afb48430e3af7c59497b5726e298250..ddb1a706b144036dd1805eac5baa66784adbbc29 100644 (file)
 #include <linux/kobject.h>
 
 struct kmem_cache_cpu {
-       void **freelist;
-       struct page *page;
-       int node;
-       unsigned int offset;
-       unsigned int objsize;
+       void **freelist;        /* Pointer to first free per cpu object */
+       struct page *page;      /* The slab from which we are allocating */
+       int node;               /* The node of the page (or -1 for debug) */
+       unsigned int offset;    /* Freepointer offset (in word units) */
+       unsigned int objsize;   /* Size of an object (from kmem_cache) */
 };
 
 struct kmem_cache_node {
@@ -59,7 +59,10 @@ struct kmem_cache {
 #endif
 
 #ifdef CONFIG_NUMA
-       int defrag_ratio;
+       /*
+        * Defragmentation by allocating from a remote node.
+        */
+       int remote_node_defrag_ratio;
        struct kmem_cache_node *node[MAX_NUMNODES];
 #endif
 #ifdef CONFIG_SMP
index df7620dd8f3181133e6818a062cd85347c5e084d..64236b73c724e2bb4a8b357d8f8c50539377a9ca 100644 (file)
 /* USB slave/gadget data port base */
 #define SM501_USB_GADGET_DATA          (0x070000)
 
-/* Display contoller/video engine base */
+/* Display controller/video engine base */
 #define SM501_DC                       (0x080000)
 
 /* common defines for the SM501 address registers */
index 86d3effb283626f8b053db379ceacca52c6bef06..5df62ef1280c176d2299d61dd6e3148161bd3b63 100644 (file)
@@ -227,7 +227,7 @@ enum
        LINUX_MIB_XFRMINNOSTATES,               /* XfrmInNoStates */
        LINUX_MIB_XFRMINSTATEPROTOERROR,        /* XfrmInStateProtoError */
        LINUX_MIB_XFRMINSTATEMODEERROR,         /* XfrmInStateModeError */
-       LINUX_MIB_XFRMINSEQOUTOFWINDOW,         /* XfrmInSeqOutOfWindow */
+       LINUX_MIB_XFRMINSTATESEQERROR,          /* XfrmInStateSeqError */
        LINUX_MIB_XFRMINSTATEEXPIRED,           /* XfrmInStateExpired */
        LINUX_MIB_XFRMINSTATEMISMATCH,          /* XfrmInStateMismatch */
        LINUX_MIB_XFRMINSTATEINVALID,           /* XfrmInStateInvalid */
@@ -241,6 +241,7 @@ enum
        LINUX_MIB_XFRMOUTNOSTATES,              /* XfrmOutNoStates */
        LINUX_MIB_XFRMOUTSTATEPROTOERROR,       /* XfrmOutStateProtoError */
        LINUX_MIB_XFRMOUTSTATEMODEERROR,        /* XfrmOutStateModeError */
+       LINUX_MIB_XFRMOUTSTATESEQERROR,         /* XfrmOutStateSeqError */
        LINUX_MIB_XFRMOUTSTATEEXPIRED,          /* XfrmOutStateExpired */
        LINUX_MIB_XFRMOUTPOLBLOCK,              /* XfrmOutPolBlock */
        LINUX_MIB_XFRMOUTPOLDEAD,               /* XfrmOutPolDead */
diff --git a/include/linux/spi/mcp23s08.h b/include/linux/spi/mcp23s08.h
new file mode 100644 (file)
index 0000000..835ddf4
--- /dev/null
@@ -0,0 +1,24 @@
+
+/* FIXME driver should be able to handle all four slaves that
+ * can be hooked up to each chipselect, as well as IRQs...
+ */
+
+struct mcp23s08_platform_data {
+       /* four slaves can share one SPI chipselect */
+       u8              slave;
+
+       /* number assigned to the first GPIO */
+       unsigned        base;
+
+       /* pins with pullups */
+       u8              pullups;
+
+       void            *context;       /* param to setup/teardown */
+
+       int             (*setup)(struct spi_device *spi,
+                                       int gpio, unsigned ngpio,
+                                       void *context);
+       int             (*teardown)(struct spi_device *spi,
+                                       int gpio, unsigned ngpio,
+                                       void *context);
+};
index 67faa044c5f5574042e72c28fa18f7f38e1fe51f..04e1d3164576eac1a5137b0620da7c1aa1959d89 100644 (file)
@@ -21,7 +21,7 @@
 /*
  * In the UP-nondebug case there's no real locking going on, so the
  * only thing we have to do is to keep the preempt counts and irq
- * flags straight, to supress compiler warnings of unused lock
+ * flags straight, to suppress compiler warnings of unused lock
  * variables, and to add the proper checker annotations:
  */
 #define __LOCK(lock) \
index bd7a6b0a87af654e080093037915238b6fc4fd74..03547d6abee50be5c73373dd14b6811700655b59 100644 (file)
@@ -169,8 +169,8 @@ extern int cache_check(struct cache_detail *detail,
 extern void cache_flush(void);
 extern void cache_purge(struct cache_detail *detail);
 #define NEVER (0x7FFFFFFF)
-extern void cache_register(struct cache_detail *cd);
-extern int cache_unregister(struct cache_detail *cd);
+extern int cache_register(struct cache_detail *cd);
+extern void cache_unregister(struct cache_detail *cd);
 
 extern void qword_add(char **bpp, int *lp, char *str);
 extern void qword_addhex(char **bpp, int *lp, char *buf, int blen);
index 3e9addc741c1ad8a57b41c9172d3114b53faee1b..129a86e25d2989df395e29913fe4322b614701c7 100644 (file)
@@ -41,7 +41,6 @@ struct rpc_clnt {
        struct rpc_iostats *    cl_metrics;     /* per-client statistics */
 
        unsigned int            cl_softrtry : 1,/* soft timeouts */
-                               cl_intr     : 1,/* interruptible */
                                cl_discrtry : 1,/* disconnect before retry */
                                cl_autobind : 1;/* use getport() */
 
@@ -111,7 +110,6 @@ struct rpc_create_args {
 
 /* Values for "flags" field */
 #define RPC_CLNT_CREATE_HARDRTRY       (1UL << 0)
-#define RPC_CLNT_CREATE_INTR           (1UL << 1)
 #define RPC_CLNT_CREATE_AUTOBIND       (1UL << 2)
 #define RPC_CLNT_CREATE_NONPRIVPORT    (1UL << 3)
 #define RPC_CLNT_CREATE_NOPING         (1UL << 4)
@@ -137,8 +135,6 @@ int         rpc_call_sync(struct rpc_clnt *clnt, struct rpc_message *msg,
 struct rpc_task *rpc_call_null(struct rpc_clnt *clnt, struct rpc_cred *cred,
                               int flags);
 void           rpc_restart_call(struct rpc_task *);
-void           rpc_clnt_sigmask(struct rpc_clnt *clnt, sigset_t *oldset);
-void           rpc_clnt_sigunmask(struct rpc_clnt *clnt, sigset_t *oldset);
 void           rpc_setbufsize(struct rpc_clnt *, unsigned int, unsigned int);
 size_t         rpc_max_payload(struct rpc_clnt *);
 void           rpc_force_rebind(struct rpc_clnt *);
index 3912cf16361ee98aa9334399fe6d8289e3270364..10709cbe96fdb88419a87b15bf32fc81fef7c06a 100644 (file)
@@ -20,7 +20,7 @@
 #define RPCDBG_BIND            0x0020
 #define RPCDBG_SCHED           0x0040
 #define RPCDBG_TRANS           0x0080
-#define RPCDBG_SVCSOCK         0x0100
+#define RPCDBG_SVCXPRT         0x0100
 #define RPCDBG_SVCDSP          0x0200
 #define RPCDBG_MISC            0x0400
 #define RPCDBG_CACHE           0x0800
index ce3d1b13272901a7ac3cfa07c9b3042bebb6043e..f689f02e6793de2aa6ee21d9a3054af669714cb1 100644 (file)
@@ -137,7 +137,6 @@ struct rpc_task_setup {
 #define RPC_TASK_DYNAMIC       0x0080          /* task was kmalloc'ed */
 #define RPC_TASK_KILLED                0x0100          /* task was killed */
 #define RPC_TASK_SOFT          0x0200          /* Use soft timeouts */
-#define RPC_TASK_NOINTR                0x0400          /* uninterruptible task */
 
 #define RPC_IS_ASYNC(t)                ((t)->tk_flags & RPC_TASK_ASYNC)
 #define RPC_IS_SWAPPER(t)      ((t)->tk_flags & RPC_TASK_SWAPPER)
@@ -145,7 +144,6 @@ struct rpc_task_setup {
 #define RPC_ASSASSINATED(t)    ((t)->tk_flags & RPC_TASK_KILLED)
 #define RPC_DO_CALLBACK(t)     ((t)->tk_callback != NULL)
 #define RPC_IS_SOFT(t)         ((t)->tk_flags & RPC_TASK_SOFT)
-#define RPC_TASK_UNINTERRUPTIBLE(t) ((t)->tk_flags & RPC_TASK_NOINTR)
 
 #define RPC_TASK_RUNNING       0
 #define RPC_TASK_QUEUED                1
index 8531a70da73d2526d7e110c92baa6fddb9152212..64c771056187a3957c70ce3c212e0db82db49ff9 100644 (file)
@@ -204,7 +204,7 @@ union svc_addr_u {
 struct svc_rqst {
        struct list_head        rq_list;        /* idle list */
        struct list_head        rq_all;         /* all threads list */
-       struct svc_sock *       rq_sock;        /* socket */
+       struct svc_xprt *       rq_xprt;        /* transport ptr */
        struct sockaddr_storage rq_addr;        /* peer address */
        size_t                  rq_addrlen;
 
@@ -214,9 +214,10 @@ struct svc_rqst {
        struct auth_ops *       rq_authop;      /* authentication flavour */
        u32                     rq_flavor;      /* pseudoflavor */
        struct svc_cred         rq_cred;        /* auth info */
-       struct sk_buff *        rq_skbuff;      /* fast recv inet buffer */
+       void *                  rq_xprt_ctxt;   /* transport specific context ptr */
        struct svc_deferred_req*rq_deferred;    /* deferred request we are replaying */
 
+       size_t                  rq_xprt_hlen;   /* xprt header len */
        struct xdr_buf          rq_arg;
        struct xdr_buf          rq_res;
        struct page *           rq_pages[RPCSVC_MAXPAGES];
@@ -317,11 +318,12 @@ static inline void svc_free_res_pages(struct svc_rqst *rqstp)
 
 struct svc_deferred_req {
        u32                     prot;   /* protocol (UDP or TCP) */
-       struct svc_sock         *svsk;
+       struct svc_xprt         *xprt;
        struct sockaddr_storage addr;   /* where reply must go */
        size_t                  addrlen;
        union svc_addr_u        daddr;  /* where reply must come from */
        struct cache_deferred_req handle;
+       size_t                  xprt_hlen;
        int                     argslen;
        __be32                  args[0];
 };
@@ -382,6 +384,8 @@ struct svc_procedure {
  */
 struct svc_serv *  svc_create(struct svc_program *, unsigned int,
                              void (*shutdown)(struct svc_serv*));
+struct svc_rqst *svc_prepare_thread(struct svc_serv *serv,
+                                       struct svc_pool *pool);
 int               svc_create_thread(svc_thread_fn, struct svc_serv *);
 void              svc_exit_thread(struct svc_rqst *);
 struct svc_serv *  svc_create_pooled(struct svc_program *, unsigned int,
diff --git a/include/linux/sunrpc/svc_rdma.h b/include/linux/sunrpc/svc_rdma.h
new file mode 100644 (file)
index 0000000..c11bbcc
--- /dev/null
@@ -0,0 +1,262 @@
+/*
+ * Copyright (c) 2005-2006 Network Appliance, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the BSD-type
+ * license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *      Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *      Redistributions in binary form must reproduce the above
+ *      copyright notice, this list of conditions and the following
+ *      disclaimer in the documentation and/or other materials provided
+ *      with the distribution.
+ *
+ *      Neither the name of the Network Appliance, Inc. nor the names of
+ *      its contributors may be used to endorse or promote products
+ *      derived from this software without specific prior written
+ *      permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Author: Tom Tucker <tom@opengridcomputing.com>
+ */
+
+#ifndef SVC_RDMA_H
+#define SVC_RDMA_H
+#include <linux/sunrpc/xdr.h>
+#include <linux/sunrpc/svcsock.h>
+#include <linux/sunrpc/rpc_rdma.h>
+#include <rdma/ib_verbs.h>
+#include <rdma/rdma_cm.h>
+#define SVCRDMA_DEBUG
+
+/* RPC/RDMA parameters and stats */
+extern unsigned int svcrdma_ord;
+extern unsigned int svcrdma_max_requests;
+extern unsigned int svcrdma_max_req_size;
+
+extern atomic_t rdma_stat_recv;
+extern atomic_t rdma_stat_read;
+extern atomic_t rdma_stat_write;
+extern atomic_t rdma_stat_sq_starve;
+extern atomic_t rdma_stat_rq_starve;
+extern atomic_t rdma_stat_rq_poll;
+extern atomic_t rdma_stat_rq_prod;
+extern atomic_t rdma_stat_sq_poll;
+extern atomic_t rdma_stat_sq_prod;
+
+#define RPCRDMA_VERSION 1
+
+/*
+ * Contexts are built when an RDMA request is created and are a
+ * record of the resources that can be recovered when the request
+ * completes.
+ */
+struct svc_rdma_op_ctxt {
+       struct svc_rdma_op_ctxt *next;
+       struct xdr_buf arg;
+       struct list_head dto_q;
+       enum ib_wr_opcode wr_op;
+       enum ib_wc_status wc_status;
+       u32 byte_len;
+       struct svcxprt_rdma *xprt;
+       unsigned long flags;
+       enum dma_data_direction direction;
+       int count;
+       struct ib_sge sge[RPCSVC_MAXPAGES];
+       struct page *pages[RPCSVC_MAXPAGES];
+};
+
+#define RDMACTXT_F_READ_DONE   1
+#define RDMACTXT_F_LAST_CTXT   2
+
+struct svcxprt_rdma {
+       struct svc_xprt      sc_xprt;           /* SVC transport structure */
+       struct rdma_cm_id    *sc_cm_id;         /* RDMA connection id */
+       struct list_head     sc_accept_q;       /* Conn. waiting accept */
+       int                  sc_ord;            /* RDMA read limit */
+       wait_queue_head_t    sc_read_wait;
+       int                  sc_max_sge;
+
+       int                  sc_sq_depth;       /* Depth of SQ */
+       atomic_t             sc_sq_count;       /* Number of SQ WR on queue */
+
+       int                  sc_max_requests;   /* Depth of RQ */
+       int                  sc_max_req_size;   /* Size of each RQ WR buf */
+
+       struct ib_pd         *sc_pd;
+
+       struct svc_rdma_op_ctxt  *sc_ctxt_head;
+       int                  sc_ctxt_cnt;
+       int                  sc_ctxt_bump;
+       int                  sc_ctxt_max;
+       spinlock_t           sc_ctxt_lock;
+       struct list_head     sc_rq_dto_q;
+       spinlock_t           sc_rq_dto_lock;
+       struct ib_qp         *sc_qp;
+       struct ib_cq         *sc_rq_cq;
+       struct ib_cq         *sc_sq_cq;
+       struct ib_mr         *sc_phys_mr;       /* MR for server memory */
+
+       spinlock_t           sc_lock;           /* transport lock */
+
+       wait_queue_head_t    sc_send_wait;      /* SQ exhaustion waitlist */
+       unsigned long        sc_flags;
+       struct list_head     sc_dto_q;          /* DTO tasklet I/O pending Q */
+       struct list_head     sc_read_complete_q;
+       spinlock_t           sc_read_complete_lock;
+};
+/* sc_flags */
+#define RDMAXPRT_RQ_PENDING    1
+#define RDMAXPRT_SQ_PENDING    2
+#define RDMAXPRT_CONN_PENDING  3
+
+#define RPCRDMA_LISTEN_BACKLOG  10
+/* The default ORD value is based on two outstanding full-size writes with a
+ * page size of 4k, or 32k * 2 ops / 4k = 16 outstanding RDMA_READ.  */
+#define RPCRDMA_ORD             (64/4)
+#define RPCRDMA_SQ_DEPTH_MULT   8
+#define RPCRDMA_MAX_THREADS     16
+#define RPCRDMA_MAX_REQUESTS    16
+#define RPCRDMA_MAX_REQ_SIZE    4096
+
+/* svc_rdma_marshal.c */
+extern void svc_rdma_rcl_chunk_counts(struct rpcrdma_read_chunk *,
+                                     int *, int *);
+extern int svc_rdma_xdr_decode_req(struct rpcrdma_msg **, struct svc_rqst *);
+extern int svc_rdma_xdr_decode_deferred_req(struct svc_rqst *);
+extern int svc_rdma_xdr_encode_error(struct svcxprt_rdma *,
+                                    struct rpcrdma_msg *,
+                                    enum rpcrdma_errcode, u32 *);
+extern void svc_rdma_xdr_encode_write_list(struct rpcrdma_msg *, int);
+extern void svc_rdma_xdr_encode_reply_array(struct rpcrdma_write_array *, int);
+extern void svc_rdma_xdr_encode_array_chunk(struct rpcrdma_write_array *, int,
+                                           u32, u64, u32);
+extern void svc_rdma_xdr_encode_reply_header(struct svcxprt_rdma *,
+                                            struct rpcrdma_msg *,
+                                            struct rpcrdma_msg *,
+                                            enum rpcrdma_proc);
+extern int svc_rdma_xdr_get_reply_hdr_len(struct rpcrdma_msg *);
+
+/* svc_rdma_recvfrom.c */
+extern int svc_rdma_recvfrom(struct svc_rqst *);
+
+/* svc_rdma_sendto.c */
+extern int svc_rdma_sendto(struct svc_rqst *);
+
+/* svc_rdma_transport.c */
+extern int svc_rdma_send(struct svcxprt_rdma *, struct ib_send_wr *);
+extern int svc_rdma_send_error(struct svcxprt_rdma *, struct rpcrdma_msg *,
+                              enum rpcrdma_errcode);
+struct page *svc_rdma_get_page(void);
+extern int svc_rdma_post_recv(struct svcxprt_rdma *);
+extern int svc_rdma_create_listen(struct svc_serv *, int, struct sockaddr *);
+extern struct svc_rdma_op_ctxt *svc_rdma_get_context(struct svcxprt_rdma *);
+extern void svc_rdma_put_context(struct svc_rdma_op_ctxt *, int);
+extern void svc_sq_reap(struct svcxprt_rdma *);
+extern void svc_rq_reap(struct svcxprt_rdma *);
+extern struct svc_xprt_class svc_rdma_class;
+extern void svc_rdma_prep_reply_hdr(struct svc_rqst *);
+
+/* svc_rdma.c */
+extern int svc_rdma_init(void);
+extern void svc_rdma_cleanup(void);
+
+/*
+ * Returns the address of the first read chunk or <nul> if no read chunk is
+ * present
+ */
+static inline struct rpcrdma_read_chunk *
+svc_rdma_get_read_chunk(struct rpcrdma_msg *rmsgp)
+{
+       struct rpcrdma_read_chunk *ch =
+               (struct rpcrdma_read_chunk *)&rmsgp->rm_body.rm_chunks[0];
+
+       if (ch->rc_discrim == 0)
+               return NULL;
+
+       return ch;
+}
+
+/*
+ * Returns the address of the first read write array element or <nul> if no
+ * write array list is present
+ */
+static inline struct rpcrdma_write_array *
+svc_rdma_get_write_array(struct rpcrdma_msg *rmsgp)
+{
+       if (rmsgp->rm_body.rm_chunks[0] != 0
+           || rmsgp->rm_body.rm_chunks[1] == 0)
+               return NULL;
+
+       return (struct rpcrdma_write_array *)&rmsgp->rm_body.rm_chunks[1];
+}
+
+/*
+ * Returns the address of the first reply array element or <nul> if no
+ * reply array is present
+ */
+static inline struct rpcrdma_write_array *
+svc_rdma_get_reply_array(struct rpcrdma_msg *rmsgp)
+{
+       struct rpcrdma_read_chunk *rch;
+       struct rpcrdma_write_array *wr_ary;
+       struct rpcrdma_write_array *rp_ary;
+
+       /* XXX: Need to fix when reply list may occur with read-list and/or
+        * write list */
+       if (rmsgp->rm_body.rm_chunks[0] != 0 ||
+           rmsgp->rm_body.rm_chunks[1] != 0)
+               return NULL;
+
+       rch = svc_rdma_get_read_chunk(rmsgp);
+       if (rch) {
+               while (rch->rc_discrim)
+                       rch++;
+
+               /* The reply list follows an empty write array located
+                * at 'rc_position' here. The reply array is at rc_target.
+                */
+               rp_ary = (struct rpcrdma_write_array *)&rch->rc_target;
+
+               goto found_it;
+       }
+
+       wr_ary = svc_rdma_get_write_array(rmsgp);
+       if (wr_ary) {
+               rp_ary = (struct rpcrdma_write_array *)
+                       &wr_ary->
+                       wc_array[wr_ary->wc_nchunks].wc_target.rs_length;
+
+               goto found_it;
+       }
+
+       /* No read list, no write list */
+       rp_ary = (struct rpcrdma_write_array *)
+               &rmsgp->rm_body.rm_chunks[2];
+
+ found_it:
+       if (rp_ary->wc_discrim == 0)
+               return NULL;
+
+       return rp_ary;
+}
+#endif
diff --git a/include/linux/sunrpc/svc_xprt.h b/include/linux/sunrpc/svc_xprt.h
new file mode 100644 (file)
index 0000000..6fd7b01
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ * linux/include/linux/sunrpc/svc_xprt.h
+ *
+ * RPC server transport I/O
+ */
+
+#ifndef SUNRPC_SVC_XPRT_H
+#define SUNRPC_SVC_XPRT_H
+
+#include <linux/sunrpc/svc.h>
+#include <linux/module.h>
+
+struct svc_xprt_ops {
+       struct svc_xprt *(*xpo_create)(struct svc_serv *,
+                                      struct sockaddr *, int,
+                                      int);
+       struct svc_xprt *(*xpo_accept)(struct svc_xprt *);
+       int             (*xpo_has_wspace)(struct svc_xprt *);
+       int             (*xpo_recvfrom)(struct svc_rqst *);
+       void            (*xpo_prep_reply_hdr)(struct svc_rqst *);
+       int             (*xpo_sendto)(struct svc_rqst *);
+       void            (*xpo_release_rqst)(struct svc_rqst *);
+       void            (*xpo_detach)(struct svc_xprt *);
+       void            (*xpo_free)(struct svc_xprt *);
+};
+
+struct svc_xprt_class {
+       const char              *xcl_name;
+       struct module           *xcl_owner;
+       struct svc_xprt_ops     *xcl_ops;
+       struct list_head        xcl_list;
+       u32                     xcl_max_payload;
+};
+
+struct svc_xprt {
+       struct svc_xprt_class   *xpt_class;
+       struct svc_xprt_ops     *xpt_ops;
+       struct kref             xpt_ref;
+       struct list_head        xpt_list;
+       struct list_head        xpt_ready;
+       unsigned long           xpt_flags;
+#define        XPT_BUSY        0               /* enqueued/receiving */
+#define        XPT_CONN        1               /* conn pending */
+#define        XPT_CLOSE       2               /* dead or dying */
+#define        XPT_DATA        3               /* data pending */
+#define        XPT_TEMP        4               /* connected transport */
+#define        XPT_DEAD        6               /* transport closed */
+#define        XPT_CHNGBUF     7               /* need to change snd/rcv buf sizes */
+#define        XPT_DEFERRED    8               /* deferred request pending */
+#define        XPT_OLD         9               /* used for xprt aging mark+sweep */
+#define        XPT_DETACHED    10              /* detached from tempsocks list */
+#define XPT_LISTENER   11              /* listening endpoint */
+#define XPT_CACHE_AUTH 12              /* cache auth info */
+
+       struct svc_pool         *xpt_pool;      /* current pool iff queued */
+       struct svc_serv         *xpt_server;    /* service for transport */
+       atomic_t                xpt_reserved;   /* space on outq that is rsvd */
+       struct mutex            xpt_mutex;      /* to serialize sending data */
+       spinlock_t              xpt_lock;       /* protects sk_deferred
+                                                * and xpt_auth_cache */
+       void                    *xpt_auth_cache;/* auth cache */
+       struct list_head        xpt_deferred;   /* deferred requests that need
+                                                * to be revisted */
+       struct sockaddr_storage xpt_local;      /* local address */
+       size_t                  xpt_locallen;   /* length of address */
+       struct sockaddr_storage xpt_remote;     /* remote peer's address */
+       size_t                  xpt_remotelen;  /* length of address */
+};
+
+int    svc_reg_xprt_class(struct svc_xprt_class *);
+void   svc_unreg_xprt_class(struct svc_xprt_class *);
+void   svc_xprt_init(struct svc_xprt_class *, struct svc_xprt *,
+                     struct svc_serv *);
+int    svc_create_xprt(struct svc_serv *, char *, unsigned short, int);
+void   svc_xprt_enqueue(struct svc_xprt *xprt);
+void   svc_xprt_received(struct svc_xprt *);
+void   svc_xprt_put(struct svc_xprt *xprt);
+void   svc_xprt_copy_addrs(struct svc_rqst *rqstp, struct svc_xprt *xprt);
+void   svc_close_xprt(struct svc_xprt *xprt);
+void   svc_delete_xprt(struct svc_xprt *xprt);
+int    svc_port_is_privileged(struct sockaddr *sin);
+int    svc_print_xprts(char *buf, int maxlen);
+struct svc_xprt *svc_find_xprt(struct svc_serv *, char *, int, int);
+int    svc_xprt_names(struct svc_serv *serv, char *buf, int buflen);
+
+static inline void svc_xprt_get(struct svc_xprt *xprt)
+{
+       kref_get(&xprt->xpt_ref);
+}
+static inline void svc_xprt_set_local(struct svc_xprt *xprt,
+                                     struct sockaddr *sa, int salen)
+{
+       memcpy(&xprt->xpt_local, sa, salen);
+       xprt->xpt_locallen = salen;
+}
+static inline void svc_xprt_set_remote(struct svc_xprt *xprt,
+                                      struct sockaddr *sa, int salen)
+{
+       memcpy(&xprt->xpt_remote, sa, salen);
+       xprt->xpt_remotelen = salen;
+}
+static inline unsigned short svc_addr_port(struct sockaddr *sa)
+{
+       unsigned short ret = 0;
+       switch (sa->sa_family) {
+       case AF_INET:
+               ret = ntohs(((struct sockaddr_in *)sa)->sin_port);
+               break;
+       case AF_INET6:
+               ret = ntohs(((struct sockaddr_in6 *)sa)->sin6_port);
+               break;
+       }
+       return ret;
+}
+
+static inline size_t svc_addr_len(struct sockaddr *sa)
+{
+       switch (sa->sa_family) {
+       case AF_INET:
+               return sizeof(struct sockaddr_in);
+       case AF_INET6:
+               return sizeof(struct sockaddr_in6);
+       }
+       return -EAFNOSUPPORT;
+}
+
+static inline unsigned short svc_xprt_local_port(struct svc_xprt *xprt)
+{
+       return svc_addr_port((struct sockaddr *)&xprt->xpt_local);
+}
+
+static inline unsigned short svc_xprt_remote_port(struct svc_xprt *xprt)
+{
+       return svc_addr_port((struct sockaddr *)&xprt->xpt_remote);
+}
+
+static inline char *__svc_print_addr(struct sockaddr *addr,
+                                    char *buf, size_t len)
+{
+       switch (addr->sa_family) {
+       case AF_INET:
+               snprintf(buf, len, "%u.%u.%u.%u, port=%u",
+                       NIPQUAD(((struct sockaddr_in *) addr)->sin_addr),
+                       ntohs(((struct sockaddr_in *) addr)->sin_port));
+               break;
+
+       case AF_INET6:
+               snprintf(buf, len, "%x:%x:%x:%x:%x:%x:%x:%x, port=%u",
+                       NIP6(((struct sockaddr_in6 *) addr)->sin6_addr),
+                       ntohs(((struct sockaddr_in6 *) addr)->sin6_port));
+               break;
+
+       default:
+               snprintf(buf, len, "unknown address type: %d", addr->sa_family);
+               break;
+       }
+       return buf;
+}
+#endif /* SUNRPC_SVC_XPRT_H */
index a53e0fa855d2e26f9b2827f616a7f0f9964b00eb..206f092ad4c7dbd09a120352f538141ad9e58977 100644 (file)
 #define SUNRPC_SVCSOCK_H
 
 #include <linux/sunrpc/svc.h>
+#include <linux/sunrpc/svc_xprt.h>
 
 /*
  * RPC server socket.
  */
 struct svc_sock {
-       struct list_head        sk_ready;       /* list of ready sockets */
-       struct list_head        sk_list;        /* list of all sockets */
+       struct svc_xprt         sk_xprt;
        struct socket *         sk_sock;        /* berkeley socket layer */
        struct sock *           sk_sk;          /* INET layer */
 
-       struct svc_pool *       sk_pool;        /* current pool iff queued */
-       struct svc_serv *       sk_server;      /* service for this socket */
-       atomic_t                sk_inuse;       /* use count */
-       unsigned long           sk_flags;
-#define        SK_BUSY         0                       /* enqueued/receiving */
-#define        SK_CONN         1                       /* conn pending */
-#define        SK_CLOSE        2                       /* dead or dying */
-#define        SK_DATA         3                       /* data pending */
-#define        SK_TEMP         4                       /* temp (TCP) socket */
-#define        SK_DEAD         6                       /* socket closed */
-#define        SK_CHNGBUF      7                       /* need to change snd/rcv buffer sizes */
-#define        SK_DEFERRED     8                       /* request on sk_deferred */
-#define        SK_OLD          9                       /* used for temp socket aging mark+sweep */
-#define        SK_DETACHED     10                      /* detached from tempsocks list */
-
-       atomic_t                sk_reserved;    /* space on outq that is reserved */
-
-       spinlock_t              sk_lock;        /* protects sk_deferred and
-                                                * sk_info_authunix */
-       struct list_head        sk_deferred;    /* deferred requests that need to
-                                                * be revisted */
-       struct mutex            sk_mutex;       /* to serialize sending data */
-
-       int                     (*sk_recvfrom)(struct svc_rqst *rqstp);
-       int                     (*sk_sendto)(struct svc_rqst *rqstp);
-
        /* We keep the old state_change and data_ready CB's here */
        void                    (*sk_ostate)(struct sock *);
        void                    (*sk_odata)(struct sock *, int bytes);
@@ -54,21 +28,12 @@ struct svc_sock {
        /* private TCP part */
        int                     sk_reclen;      /* length of record */
        int                     sk_tcplen;      /* current read length */
-       time_t                  sk_lastrecv;    /* time of last received request */
-
-       /* cache of various info for TCP sockets */
-       void                    *sk_info_authunix;
-
-       struct sockaddr_storage sk_local;       /* local address */
-       struct sockaddr_storage sk_remote;      /* remote peer's address */
-       int                     sk_remotelen;   /* length of address */
 };
 
 /*
  * Function prototypes.
  */
-int            svc_makesock(struct svc_serv *, int, unsigned short, int flags);
-void           svc_force_close_socket(struct svc_sock *);
+void           svc_close_all(struct list_head *);
 int            svc_recv(struct svc_rqst *, long);
 int            svc_send(struct svc_rqst *);
 void           svc_drop(struct svc_rqst *);
@@ -78,6 +43,8 @@ int           svc_addsock(struct svc_serv *serv,
                            int fd,
                            char *name_return,
                            int *proto);
+void           svc_init_xprt_sock(void);
+void           svc_cleanup_xprt_sock(void);
 
 /*
  * svc_makesock socket characteristics
index 0751c9464d0f84ff7291c7ca332c65dbde383cee..e4057d729f036c8a3b80e3100a704e03ef0c6d4a 100644 (file)
@@ -112,7 +112,8 @@ struct xdr_buf {
 __be32 *xdr_encode_opaque_fixed(__be32 *p, const void *ptr, unsigned int len);
 __be32 *xdr_encode_opaque(__be32 *p, const void *ptr, unsigned int len);
 __be32 *xdr_encode_string(__be32 *p, const char *s);
-__be32 *xdr_decode_string_inplace(__be32 *p, char **sp, int *lenp, int maxlen);
+__be32 *xdr_decode_string_inplace(__be32 *p, char **sp, unsigned int *lenp,
+                       unsigned int maxlen);
 __be32 *xdr_encode_netobj(__be32 *p, const struct xdr_netobj *);
 __be32 *xdr_decode_netobj(__be32 *p, struct xdr_netobj *);
 
index 40280df2a3dbc5d91d61291f8793f3d98b989cbc..1d7d4c5797ee93c37ab2d7f035f26fa114649a3f 100644 (file)
@@ -38,18 +38,16 @@ typedef int __bitwise suspend_state_t;
  *     There is the %suspend_valid_only_mem function available that can be
  *     assigned to this if the platform only supports mem sleep.
  *
- * @set_target: Tell the platform which system sleep state is going to be
- *     entered.
- *     @set_target() is executed right prior to suspending devices.  The
- *     information conveyed to the platform code by @set_target() should be
- *     disregarded by the platform as soon as @finish() is executed and if
- *     @prepare() fails.  If @set_target() fails (ie. returns nonzero),
+ * @begin: Initialise a transition to given system sleep state.
+ *     @begin() is executed right prior to suspending devices.  The information
+ *     conveyed to the platform code by @begin() should be disregarded by it as
+ *     soon as @end() is executed.  If @begin() fails (ie. returns nonzero),
  *     @prepare(), @enter() and @finish() will not be called by the PM core.
  *     This callback is optional.  However, if it is implemented, the argument
- *     passed to @enter() is meaningless and should be ignored.
+ *     passed to @enter() is redundant and should be ignored.
  *
  * @prepare: Prepare the platform for entering the system sleep state indicated
- *     by @set_target().
+ *     by @begin().
  *     @prepare() is called right after devices have been suspended (ie. the
  *     appropriate .suspend() method has been executed for each device) and
  *     before the nonboot CPUs are disabled (it is executed with IRQs enabled).
@@ -57,8 +55,8 @@ typedef int __bitwise suspend_state_t;
  *     error code otherwise, in which case the system cannot enter the desired
  *     sleep state (@enter() and @finish() will not be called in that case).
  *
- * @enter: Enter the system sleep state indicated by @set_target() or
- *     represented by the argument if @set_target() is not implemented.
+ * @enter: Enter the system sleep state indicated by @begin() or represented by
+ *     the argument if @begin() is not implemented.
  *     This callback is mandatory.  It returns 0 on success or a negative
  *     error code otherwise, in which case the system cannot enter the desired
  *     sleep state.
@@ -69,13 +67,22 @@ typedef int __bitwise suspend_state_t;
  *     This callback is optional, but should be implemented by the platforms
  *     that implement @prepare().  If implemented, it is always called after
  *     @enter() (even if @enter() fails).
+ *
+ * @end: Called by the PM core right after resuming devices, to indicate to
+ *     the platform that the system has returned to the working state or
+ *     the transition to the sleep state has been aborted.
+ *     This callback is optional, but should be implemented by the platforms
+ *     that implement @begin(), but platforms implementing @begin() should
+ *     also provide a @end() which cleans up transitions aborted before
+ *     @enter().
  */
 struct platform_suspend_ops {
        int (*valid)(suspend_state_t state);
-       int (*set_target)(suspend_state_t state);
+       int (*begin)(suspend_state_t state);
        int (*prepare)(void);
        int (*enter)(suspend_state_t state);
        void (*finish)(void);
+       void (*end)(void);
 };
 
 #ifdef CONFIG_SUSPEND
@@ -123,20 +130,22 @@ struct pbe {
 };
 
 /* mm/page_alloc.c */
-extern void drain_local_pages(void);
 extern void mark_free_pages(struct zone *zone);
 
 /**
  * struct platform_hibernation_ops - hibernation platform support
  *
- * The methods in this structure allow a platform to override the default
- * mechanism of shutting down the machine during a hibernation transition.
+ * The methods in this structure allow a platform to carry out special
+ * operations required by it during a hibernation transition.
  *
- * All three methods must be assigned.
+ * All the methods below must be implemented.
  *
- * @start: Tell the platform driver that we're starting hibernation.
+ * @begin: Tell the platform driver that we're starting hibernation.
  *     Called right after shrinking memory and before freezing devices.
  *
+ * @end: Called by the PM core right after resuming devices, to indicate to
+ *     the platform that the system has returned to the working state.
+ *
  * @pre_snapshot: Prepare the platform for creating the hibernation image.
  *     Called right after devices have been frozen and before the nonboot
  *     CPUs are disabled (runs with IRQs on).
@@ -171,7 +180,8 @@ extern void mark_free_pages(struct zone *zone);
  *     thawing devices (runs with IRQs on).
  */
 struct platform_hibernation_ops {
-       int (*start)(void);
+       int (*begin)(void);
+       void (*end)(void);
        int (*pre_snapshot)(void);
        void (*finish)(void);
        int (*prepare)(void);
@@ -213,17 +223,8 @@ void save_processor_state(void);
 void restore_processor_state(void);
 
 /* kernel/power/main.c */
-extern struct blocking_notifier_head pm_chain_head;
-
-static inline int register_pm_notifier(struct notifier_block *nb)
-{
-       return blocking_notifier_chain_register(&pm_chain_head, nb);
-}
-
-static inline int unregister_pm_notifier(struct notifier_block *nb)
-{
-       return blocking_notifier_chain_unregister(&pm_chain_head, nb);
-}
+extern int register_pm_notifier(struct notifier_block *nb);
+extern int unregister_pm_notifier(struct notifier_block *nb);
 
 #define pm_notifier(fn, pri) {                         \
        static struct notifier_block fn##_nb =                  \
diff --git a/include/linux/suspend_ioctls.h b/include/linux/suspend_ioctls.h
new file mode 100644 (file)
index 0000000..2c6faec
--- /dev/null
@@ -0,0 +1,32 @@
+#ifndef _LINUX_SUSPEND_IOCTLS_H
+#define _LINUX_SUSPEND_IOCTLS_H
+
+/*
+ * This structure is used to pass the values needed for the identification
+ * of the resume swap area from a user space to the kernel via the
+ * SNAPSHOT_SET_SWAP_AREA ioctl
+ */
+struct resume_swap_area {
+       loff_t offset;
+       u_int32_t dev;
+} __attribute__((packed));
+
+#define SNAPSHOT_IOC_MAGIC     '3'
+#define SNAPSHOT_FREEZE                        _IO(SNAPSHOT_IOC_MAGIC, 1)
+#define SNAPSHOT_UNFREEZE              _IO(SNAPSHOT_IOC_MAGIC, 2)
+#define SNAPSHOT_ATOMIC_RESTORE                _IO(SNAPSHOT_IOC_MAGIC, 4)
+#define SNAPSHOT_FREE                  _IO(SNAPSHOT_IOC_MAGIC, 5)
+#define SNAPSHOT_FREE_SWAP_PAGES       _IO(SNAPSHOT_IOC_MAGIC, 9)
+#define SNAPSHOT_S2RAM                 _IO(SNAPSHOT_IOC_MAGIC, 11)
+#define SNAPSHOT_SET_SWAP_AREA         _IOW(SNAPSHOT_IOC_MAGIC, 13, \
+                                                       struct resume_swap_area)
+#define SNAPSHOT_GET_IMAGE_SIZE                _IOR(SNAPSHOT_IOC_MAGIC, 14, loff_t)
+#define SNAPSHOT_PLATFORM_SUPPORT      _IO(SNAPSHOT_IOC_MAGIC, 15)
+#define SNAPSHOT_POWER_OFF             _IO(SNAPSHOT_IOC_MAGIC, 16)
+#define SNAPSHOT_CREATE_IMAGE          _IOW(SNAPSHOT_IOC_MAGIC, 17, int)
+#define SNAPSHOT_PREF_IMAGE_SIZE       _IO(SNAPSHOT_IOC_MAGIC, 18)
+#define SNAPSHOT_AVAIL_SWAP_SIZE       _IOR(SNAPSHOT_IOC_MAGIC, 19, loff_t)
+#define SNAPSHOT_ALLOC_SWAP_PAGE       _IOR(SNAPSHOT_IOC_MAGIC, 20, loff_t)
+#define SNAPSHOT_IOC_MAXNR     20
+
+#endif /* _LINUX_SUSPEND_IOCTLS_H */
index 2c3ce4c69b25411323756ad078b3cc7db425dad8..353153ea0bd5cc88ba03ab48959cc0a281a95e8b 100644 (file)
@@ -6,7 +6,6 @@
 #include <linux/mmzone.h>
 #include <linux/list.h>
 #include <linux/sched.h>
-#include <linux/pagemap.h>
 
 #include <asm/atomic.h>
 #include <asm/page.h>
@@ -159,9 +158,6 @@ struct swap_list_t {
 /* Swap 50% full? Release swapcache more aggressively.. */
 #define vm_swap_full() (nr_swap_pages*2 < total_swap_pages)
 
-/* linux/mm/memory.c */
-extern void swapin_readahead(swp_entry_t, unsigned long, struct vm_area_struct *);
-
 /* linux/mm/page_alloc.c */
 extern unsigned long totalram_pages;
 extern unsigned long totalreserve_pages;
@@ -224,16 +220,17 @@ extern struct address_space swapper_space;
 #define total_swapcache_pages  swapper_space.nrpages
 extern void show_swap_cache_info(void);
 extern int add_to_swap(struct page *, gfp_t);
+extern int add_to_swap_cache(struct page *, swp_entry_t, gfp_t);
 extern void __delete_from_swap_cache(struct page *);
 extern void delete_from_swap_cache(struct page *);
-extern int move_to_swap_cache(struct page *, swp_entry_t);
-extern int move_from_swap_cache(struct page *, unsigned long,
-               struct address_space *);
 extern void free_page_and_swap_cache(struct page *);
 extern void free_pages_and_swap_cache(struct page **, int);
-extern struct page * lookup_swap_cache(swp_entry_t);
-extern struct page * read_swap_cache_async(swp_entry_t, struct vm_area_struct *vma,
-                                          unsigned long addr);
+extern struct page *lookup_swap_cache(swp_entry_t);
+extern struct page *read_swap_cache_async(swp_entry_t, gfp_t,
+                       struct vm_area_struct *vma, unsigned long addr);
+extern struct page *swapin_readahead(swp_entry_t, gfp_t,
+                       struct vm_area_struct *vma, unsigned long addr);
+
 /* linux/mm/swapfile.c */
 extern long total_swap_pages;
 extern unsigned int nr_swapfiles;
@@ -307,7 +304,7 @@ static inline void swap_free(swp_entry_t swp)
 {
 }
 
-static inline struct page *read_swap_cache_async(swp_entry_t swp,
+static inline struct page *swapin_readahead(swp_entry_t swp, gfp_t gfp_mask,
                        struct vm_area_struct *vma, unsigned long addr)
 {
        return NULL;
@@ -318,22 +315,12 @@ static inline struct page *lookup_swap_cache(swp_entry_t swp)
        return NULL;
 }
 
-static inline int valid_swaphandles(swp_entry_t entry, unsigned long *offset)
-{
-       return 0;
-}
-
 #define can_share_swap_page(p)                 (page_mapcount(p) == 1)
 
-static inline int move_to_swap_cache(struct page *page, swp_entry_t entry)
-{
-       return 1;
-}
-
-static inline int move_from_swap_cache(struct page *page, unsigned long index,
-                                       struct address_space *mapping)
+static inline int add_to_swap_cache(struct page *page, swp_entry_t entry,
+                                                       gfp_t gfp_mask)
 {
-       return 1;
+       return -1;
 }
 
 static inline void __delete_from_swap_cache(struct page *page)
index ceb6cc5ceebbee56b69107daad587c512987794f..7bf2d149d209615be247da2dadc4385f37636be5 100644 (file)
@@ -42,6 +42,12 @@ static inline pgoff_t swp_offset(swp_entry_t entry)
        return entry.val & SWP_OFFSET_MASK(entry);
 }
 
+/* check whether a pte points to a swap entry */
+static inline int is_swap_pte(pte_t pte)
+{
+       return !pte_none(pte) && !pte_present(pte) && !pte_file(pte);
+}
+
 /*
  * Convert the arch-dependent pte representation of a swp_entry_t into an
  * arch-independent swp_entry_t.
index 61def7c8fbb3c750677458d1d4e8a4f347e5beac..4c2577bd1c859c332821b2be75a378010d258c46 100644 (file)
@@ -607,8 +607,11 @@ asmlinkage long sys_set_robust_list(struct robust_list_head __user *head,
                                    size_t len);
 asmlinkage long sys_getcpu(unsigned __user *cpu, unsigned __user *node, struct getcpu_cache __user *cache);
 asmlinkage long sys_signalfd(int ufd, sigset_t __user *user_mask, size_t sizemask);
-asmlinkage long sys_timerfd(int ufd, int clockid, int flags,
-                           const struct itimerspec __user *utmr);
+asmlinkage long sys_timerfd_create(int clockid, int flags);
+asmlinkage long sys_timerfd_settime(int ufd, int flags,
+                                   const struct itimerspec __user *utmr,
+                                   struct itimerspec __user *otmr);
+asmlinkage long sys_timerfd_gettime(int ufd, struct itimerspec __user *otmr);
 asmlinkage long sys_eventfd(unsigned int count);
 asmlinkage long sys_fallocate(int fd, int mode, loff_t offset, loff_t len);
 
index 89faebfe48b8aa4a29b7f4ac3d756aedb71b4251..571f01d20a86373454000db25760f7a7aa2572da 100644 (file)
@@ -102,7 +102,6 @@ enum
        KERN_NODENAME=7,
        KERN_DOMAINNAME=8,
 
-       KERN_CAP_BSET=14,       /* int: capability bounding set */
        KERN_PANIC=15,          /* int: panic timeout */
        KERN_REALROOTDEV=16,    /* real root device to mount after initrd */
 
@@ -440,8 +439,8 @@ enum
 
 enum {
        NET_IPV4_ROUTE_FLUSH=1,
-       NET_IPV4_ROUTE_MIN_DELAY=2,
-       NET_IPV4_ROUTE_MAX_DELAY=3,
+       NET_IPV4_ROUTE_MIN_DELAY=2, /* obsolete since 2.6.25 */
+       NET_IPV4_ROUTE_MAX_DELAY=3, /* obsolete since 2.6.25 */
        NET_IPV4_ROUTE_GC_THRESH=4,
        NET_IPV4_ROUTE_MAX_SIZE=5,
        NET_IPV4_ROUTE_GC_MIN_INTERVAL=6,
@@ -965,8 +964,6 @@ extern int proc_dostring(struct ctl_table *, int, struct file *,
                         void __user *, size_t *, loff_t *);
 extern int proc_dointvec(struct ctl_table *, int, struct file *,
                         void __user *, size_t *, loff_t *);
-extern int proc_dointvec_bset(struct ctl_table *, int, struct file *,
-                             void __user *, size_t *, loff_t *);
 extern int proc_dointvec_minmax(struct ctl_table *, int, struct file *,
                                void __user *, size_t *, loff_t *);
 extern int proc_dointvec_jiffies(struct ctl_table *, int, struct file *,
index e21937cf91d0e4510659566215260b13a9c9b6b8..c50d2ba5caf004ea9b8a33a12d27fa859a4e4864 100644 (file)
@@ -81,6 +81,7 @@ enum
        TCF_META_ID_SK_SNDTIMEO,
        TCF_META_ID_SK_SENDMSG_OFF,
        TCF_META_ID_SK_WRITE_PENDING,
+       TCF_META_ID_VLAN_TAG,
        __TCF_META_ID_MAX
 };
 #define TCF_META_ID_MAX (__TCF_META_ID_MAX - 1)
index dfbdfb9836f469ff78184c9b99825a569953c1fd..421323e5a2d6ce3e6d82b09cacf308e59c66bac7 100644 (file)
@@ -23,6 +23,7 @@ struct restart_block {
                        u32 *uaddr;
                        u32 val;
                        u32 flags;
+                       u32 bitset;
                        u64 time;
                } futex;
        };
index 0fadf95debe1f3a1b6415623926fc884fbc719ac..a881c652f7e925cb8e3d2f296c492800c3f163eb 100644 (file)
@@ -39,6 +39,8 @@ enum tick_nohz_mode {
  * @idle_calls:                Total number of idle calls
  * @idle_sleeps:       Number of idle calls, where the sched tick was stopped
  * @idle_entrytime:    Time when the idle call was entered
+ * @idle_waketime:     Time when the idle was interrupted
+ * @idle_exittime:     Time when the idle state was left
  * @idle_sleeptime:    Sum of the time slept in idle with sched tick stopped
  * @sleep_length:      Duration of the current idle sleep
  */
@@ -53,6 +55,8 @@ struct tick_sched {
        unsigned long                   idle_sleeps;
        int                             idle_active;
        ktime_t                         idle_entrytime;
+       ktime_t                         idle_waketime;
+       ktime_t                         idle_exittime;
        ktime_t                         idle_sleeptime;
        ktime_t                         idle_lastupdate;
        ktime_t                         sleep_length;
index b04136d60a2f79c5293ddc641e664afa18820ee0..ceaab9fff15507e592e87fc6cc4b8a5b4bca3e99 100644 (file)
@@ -122,6 +122,7 @@ extern void monotonic_to_bootbased(struct timespec *ts);
 extern struct timespec timespec_trunc(struct timespec t, unsigned gran);
 extern int timekeeping_is_continuous(void);
 extern void update_wall_time(void);
+extern void update_xtime_cache(u64 nsec);
 
 /**
  * timespec_to_ns - Convert timespec to nanoseconds
index f4f8d19158e4bb80d7ef39080ec1fabf4584cf7a..b94c0e4efe2487a027dbc70ae9ed36336f392345 100644 (file)
@@ -126,7 +126,7 @@ typedef             __s64           int64_t;
 #endif
 
 /* this is a special 64bit data type that is 8-byte aligned */
-#define aligned_u64 unsigned long long __attribute__((aligned(8)))
+#define aligned_u64 __u64 __attribute__((aligned(8)))
 #define aligned_be64 __be64 __attribute__((aligned(8)))
 #define aligned_le64 __le64 __attribute__((aligned(8)))
 
index 5fc8ff73b7bbcd445ff7425f0cf459d94f08802e..2372e2e6b5271addb820c2c30f0f2549fe340134 100644 (file)
@@ -162,19 +162,19 @@ struct usb_interface {
        unsigned needs_remote_wakeup:1; /* driver requires remote wakeup */
 
        struct device dev;              /* interface specific device info */
-       struct device *usb_dev;         /* pointer to the usb class's device, if any */
+       struct device *usb_dev;
        int pm_usage_cnt;               /* usage counter for autosuspend */
 };
 #define        to_usb_interface(d) container_of(d, struct usb_interface, dev)
 #define        interface_to_usbdev(intf) \
        container_of(intf->dev.parent, struct usb_device, dev)
 
-static inline void *usb_get_intfdata (struct usb_interface *intf)
+static inline void *usb_get_intfdata(struct usb_interface *intf)
 {
-       return dev_get_drvdata (&intf->dev);
+       return dev_get_drvdata(&intf->dev);
 }
 
-static inline void usb_set_intfdata (struct usb_interface *intf, void *data)
+static inline void usb_set_intfdata(struct usb_interface *intf, void *data)
 {
        dev_set_drvdata(&intf->dev, data);
 }
@@ -275,9 +275,10 @@ struct usb_host_config {
 
 int __usb_get_extra_descriptor(char *buffer, unsigned size,
        unsigned char type, void **ptr);
-#define usb_get_extra_descriptor(ifpoint,type,ptr)\
-       __usb_get_extra_descriptor((ifpoint)->extra,(ifpoint)->extralen,\
-               type,(void**)ptr)
+#define usb_get_extra_descriptor(ifpoint, type, ptr) \
+                               __usb_get_extra_descriptor((ifpoint)->extra, \
+                               (ifpoint)->extralen, \
+                               type, (void **)ptr)
 
 /* ----------------------------------------------------------------------- */
 
@@ -318,7 +319,7 @@ struct usb_bus {
 #ifdef CONFIG_USB_DEVICEFS
        struct dentry *usbfs_dentry;    /* usbfs dentry entry for the bus */
 #endif
-       struct class_device *class_dev; /* class device for this bus */
+       struct device *dev;             /* device for this bus */
 
 #if defined(CONFIG_USB_MON)
        struct mon_bus *mon_bus;        /* non-null when associated */
@@ -388,7 +389,7 @@ struct usb_device {
        unsigned can_submit:1;          /* URBs may be submitted */
        unsigned discon_suspended:1;    /* Disconnected while suspended */
        unsigned have_langid:1;         /* whether string_langid is valid */
-       unsigned authorized:1;          /* Policy has determined we can use it */
+       unsigned authorized:1;          /* Policy has said we can use it */
        unsigned wusb:1;                /* Device is Wireless USB */
        int string_langid;              /* language ID for strings */
 
@@ -417,7 +418,10 @@ struct usb_device {
 
        int pm_usage_cnt;               /* usage counter for autosuspend */
        u32 quirks;                     /* quirks of the whole device */
-       atomic_t urbnum;                /* number of URBs submitted for the whole device */
+       atomic_t urbnum;                /* number of URBs submitted for
+                                          the whole device */
+
+       unsigned long active_duration;  /* total time device is not suspended */
 
 #ifdef CONFIG_PM
        struct delayed_work autosuspend; /* for delayed autosuspends */
@@ -425,6 +429,7 @@ struct usb_device {
 
        unsigned long last_busy;        /* time of last use */
        int autosuspend_delay;          /* in jiffies */
+       unsigned long connect_time;     /* time device was first connected */
 
        unsigned auto_pm:1;             /* autosuspend/resume in progress */
        unsigned do_remote_wakeup:1;    /* remote wakeup should be enabled */
@@ -498,11 +503,11 @@ static inline void usb_mark_last_busy(struct usb_device *udev)
 /*-------------------------------------------------------------------------*/
 
 /* for drivers using iso endpoints */
-extern int usb_get_current_frame_number (struct usb_device *usb_dev);
+extern int usb_get_current_frame_number(struct usb_device *usb_dev);
 
 /* used these for multi-interface device registration */
 extern int usb_driver_claim_interface(struct usb_driver *driver,
-                       struct usb_interface *iface, voidpriv);
+                       struct usb_interface *iface, void *priv);
 
 /**
  * usb_interface_claimed - returns true iff an interface is claimed
@@ -514,7 +519,8 @@ extern int usb_driver_claim_interface(struct usb_driver *driver,
  * may need to explicitly claim that lock.
  *
  */
-static inline int usb_interface_claimed(struct usb_interface *iface) {
+static inline int usb_interface_claimed(struct usb_interface *iface)
+{
        return (iface->dev.driver != NULL);
 }
 
@@ -557,12 +563,11 @@ extern struct usb_host_interface *usb_altnum_to_altsetting(
  * USB 2.0 root hubs (EHCI host controllers) will get one path ID if they are
  * high speed, and a different one if they are full or low speed.
  */
-static inline int usb_make_path (struct usb_device *dev, char *buf,
-               size_t size)
+static inline int usb_make_path(struct usb_device *dev, char *buf, size_t size)
 {
        int actual;
-       actual = snprintf (buf, size, "usb-%s-%s", dev->bus->bus_name,
-                       dev->devpath);
+       actual = snprintf(buf, size, "usb-%s-%s", dev->bus->bus_name,
+                         dev->devpath);
        return (actual >= (int)size) ? -1 : actual;
 }
 
@@ -608,7 +613,8 @@ static inline int usb_endpoint_dir_in(const struct usb_endpoint_descriptor *epd)
  *
  * Returns true if the endpoint is of type OUT, otherwise it returns false.
  */
-static inline int usb_endpoint_dir_out(const struct usb_endpoint_descriptor *epd)
+static inline int usb_endpoint_dir_out(
+                               const struct usb_endpoint_descriptor *epd)
 {
        return ((epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT);
 }
@@ -619,7 +625,8 @@ static inline int usb_endpoint_dir_out(const struct usb_endpoint_descriptor *epd
  *
  * Returns true if the endpoint is of type bulk, otherwise it returns false.
  */
-static inline int usb_endpoint_xfer_bulk(const struct usb_endpoint_descriptor *epd)
+static inline int usb_endpoint_xfer_bulk(
+                               const struct usb_endpoint_descriptor *epd)
 {
        return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
                USB_ENDPOINT_XFER_BULK);
@@ -631,7 +638,8 @@ static inline int usb_endpoint_xfer_bulk(const struct usb_endpoint_descriptor *e
  *
  * Returns true if the endpoint is of type control, otherwise it returns false.
  */
-static inline int usb_endpoint_xfer_control(const struct usb_endpoint_descriptor *epd)
+static inline int usb_endpoint_xfer_control(
+                               const struct usb_endpoint_descriptor *epd)
 {
        return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
                USB_ENDPOINT_XFER_CONTROL);
@@ -644,7 +652,8 @@ static inline int usb_endpoint_xfer_control(const struct usb_endpoint_descriptor
  * Returns true if the endpoint is of type interrupt, otherwise it returns
  * false.
  */
-static inline int usb_endpoint_xfer_int(const struct usb_endpoint_descriptor *epd)
+static inline int usb_endpoint_xfer_int(
+                               const struct usb_endpoint_descriptor *epd)
 {
        return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
                USB_ENDPOINT_XFER_INT);
@@ -657,7 +666,8 @@ static inline int usb_endpoint_xfer_int(const struct usb_endpoint_descriptor *ep
  * Returns true if the endpoint is of type isochronous, otherwise it returns
  * false.
  */
-static inline int usb_endpoint_xfer_isoc(const struct usb_endpoint_descriptor *epd)
+static inline int usb_endpoint_xfer_isoc(
+                               const struct usb_endpoint_descriptor *epd)
 {
        return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
                USB_ENDPOINT_XFER_ISOC);
@@ -670,7 +680,8 @@ static inline int usb_endpoint_xfer_isoc(const struct usb_endpoint_descriptor *e
  * Returns true if the endpoint has bulk transfer type and IN direction,
  * otherwise it returns false.
  */
-static inline int usb_endpoint_is_bulk_in(const struct usb_endpoint_descriptor *epd)
+static inline int usb_endpoint_is_bulk_in(
+                               const struct usb_endpoint_descriptor *epd)
 {
        return (usb_endpoint_xfer_bulk(epd) && usb_endpoint_dir_in(epd));
 }
@@ -682,7 +693,8 @@ static inline int usb_endpoint_is_bulk_in(const struct usb_endpoint_descriptor *
  * Returns true if the endpoint has bulk transfer type and OUT direction,
  * otherwise it returns false.
  */
-static inline int usb_endpoint_is_bulk_out(const struct usb_endpoint_descriptor *epd)
+static inline int usb_endpoint_is_bulk_out(
+                               const struct usb_endpoint_descriptor *epd)
 {
        return (usb_endpoint_xfer_bulk(epd) && usb_endpoint_dir_out(epd));
 }
@@ -694,7 +706,8 @@ static inline int usb_endpoint_is_bulk_out(const struct usb_endpoint_descriptor
  * Returns true if the endpoint has interrupt transfer type and IN direction,
  * otherwise it returns false.
  */
-static inline int usb_endpoint_is_int_in(const struct usb_endpoint_descriptor *epd)
+static inline int usb_endpoint_is_int_in(
+                               const struct usb_endpoint_descriptor *epd)
 {
        return (usb_endpoint_xfer_int(epd) && usb_endpoint_dir_in(epd));
 }
@@ -706,7 +719,8 @@ static inline int usb_endpoint_is_int_in(const struct usb_endpoint_descriptor *e
  * Returns true if the endpoint has interrupt transfer type and OUT direction,
  * otherwise it returns false.
  */
-static inline int usb_endpoint_is_int_out(const struct usb_endpoint_descriptor *epd)
+static inline int usb_endpoint_is_int_out(
+                               const struct usb_endpoint_descriptor *epd)
 {
        return (usb_endpoint_xfer_int(epd) && usb_endpoint_dir_out(epd));
 }
@@ -718,7 +732,8 @@ static inline int usb_endpoint_is_int_out(const struct usb_endpoint_descriptor *
  * Returns true if the endpoint has isochronous transfer type and IN direction,
  * otherwise it returns false.
  */
-static inline int usb_endpoint_is_isoc_in(const struct usb_endpoint_descriptor *epd)
+static inline int usb_endpoint_is_isoc_in(
+                               const struct usb_endpoint_descriptor *epd)
 {
        return (usb_endpoint_xfer_isoc(epd) && usb_endpoint_dir_in(epd));
 }
@@ -730,7 +745,8 @@ static inline int usb_endpoint_is_isoc_in(const struct usb_endpoint_descriptor *
  * Returns true if the endpoint has isochronous transfer type and OUT direction,
  * otherwise it returns false.
  */
-static inline int usb_endpoint_is_isoc_out(const struct usb_endpoint_descriptor *epd)
+static inline int usb_endpoint_is_isoc_out(
+                               const struct usb_endpoint_descriptor *epd)
 {
        return (usb_endpoint_xfer_isoc(epd) && usb_endpoint_dir_out(epd));
 }
@@ -761,8 +777,9 @@ static inline int usb_endpoint_is_isoc_out(const struct usb_endpoint_descriptor
  * specific device.
  */
 #define USB_DEVICE(vend,prod) \
-       .match_flags = USB_DEVICE_ID_MATCH_DEVICE, .idVendor = (vend), \
-                       .idProduct = (prod)
+       .match_flags = USB_DEVICE_ID_MATCH_DEVICE, \
+       .idVendor = (vend), \
+       .idProduct = (prod)
 /**
  * USB_DEVICE_VER - macro used to describe a specific usb device with a
  *             version range
@@ -774,10 +791,12 @@ static inline int usb_endpoint_is_isoc_out(const struct usb_endpoint_descriptor
  * This macro is used to create a struct usb_device_id that matches a
  * specific device, with a version range.
  */
-#define USB_DEVICE_VER(vend,prod,lo,hi) \
+#define USB_DEVICE_VER(vend, prod, lo, hi) \
        .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION, \
-       .idVendor = (vend), .idProduct = (prod), \
-       .bcdDevice_lo = (lo), .bcdDevice_hi = (hi)
+       .idVendor = (vend), \
+       .idProduct = (prod), \
+       .bcdDevice_lo = (lo), \
+       .bcdDevice_hi = (hi)
 
 /**
  * USB_DEVICE_INTERFACE_PROTOCOL - macro used to describe a usb
@@ -789,8 +808,9 @@ static inline int usb_endpoint_is_isoc_out(const struct usb_endpoint_descriptor
  * This macro is used to create a struct usb_device_id that matches a
  * specific interface protocol of devices.
  */
-#define USB_DEVICE_INTERFACE_PROTOCOL(vend,prod,pr) \
-       .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_PROTOCOL, \
+#define USB_DEVICE_INTERFACE_PROTOCOL(vend, prod, pr) \
+       .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \
+                      USB_DEVICE_ID_MATCH_INT_PROTOCOL, \
        .idVendor = (vend), \
        .idProduct = (prod), \
        .bInterfaceProtocol = (pr)
@@ -804,12 +824,14 @@ static inline int usb_endpoint_is_isoc_out(const struct usb_endpoint_descriptor
  * This macro is used to create a struct usb_device_id that matches a
  * specific class of devices.
  */
-#define USB_DEVICE_INFO(cl,sc,pr) \
-       .match_flags = USB_DEVICE_ID_MATCH_DEV_INFO, .bDeviceClass = (cl), \
-       .bDeviceSubClass = (sc), .bDeviceProtocol = (pr)
+#define USB_DEVICE_INFO(cl, sc, pr) \
+       .match_flags = USB_DEVICE_ID_MATCH_DEV_INFO, \
+       .bDeviceClass = (cl), \
+       .bDeviceSubClass = (sc), \
+       .bDeviceProtocol = (pr)
 
 /**
- * USB_INTERFACE_INFO - macro used to describe a class of usb interfaces 
+ * USB_INTERFACE_INFO - macro used to describe a class of usb interfaces
  * @cl: bInterfaceClass value
  * @sc: bInterfaceSubClass value
  * @pr: bInterfaceProtocol value
@@ -817,9 +839,11 @@ static inline int usb_endpoint_is_isoc_out(const struct usb_endpoint_descriptor
  * This macro is used to create a struct usb_device_id that matches a
  * specific class of interfaces.
  */
-#define USB_INTERFACE_INFO(cl,sc,pr) \
-       .match_flags = USB_DEVICE_ID_MATCH_INT_INFO, .bInterfaceClass = (cl), \
-       .bInterfaceSubClass = (sc), .bInterfaceProtocol = (pr)
+#define USB_INTERFACE_INFO(cl, sc, pr) \
+       .match_flags = USB_DEVICE_ID_MATCH_INT_INFO, \
+       .bInterfaceClass = (cl), \
+       .bInterfaceSubClass = (sc), \
+       .bInterfaceProtocol = (pr)
 
 /**
  * USB_DEVICE_AND_INTERFACE_INFO - macro used to describe a specific usb device
@@ -836,12 +860,14 @@ static inline int usb_endpoint_is_isoc_out(const struct usb_endpoint_descriptor
  * This is especially useful when explicitly matching devices that have
  * vendor specific bDeviceClass values, but standards-compliant interfaces.
  */
-#define USB_DEVICE_AND_INTERFACE_INFO(vend,prod,cl,sc,pr) \
+#define USB_DEVICE_AND_INTERFACE_INFO(vend, prod, cl, sc, pr) \
        .match_flags = USB_DEVICE_ID_MATCH_INT_INFO \
                | USB_DEVICE_ID_MATCH_DEVICE, \
-       .idVendor = (vend), .idProduct = (prod), \
+       .idVendor = (vend), \
+       .idProduct = (prod), \
        .bInterfaceClass = (cl), \
-       .bInterfaceSubClass = (sc), .bInterfaceProtocol = (pr)
+       .bInterfaceSubClass = (sc), \
+       .bInterfaceProtocol = (pr)
 
 /* ----------------------------------------------------------------------- */
 
@@ -1119,7 +1145,7 @@ typedef void (*usb_complete_t)(struct urb *);
  *     transferred.  It will normally be the same as requested, unless
  *     either an error was reported or a short read was performed.
  *     The URB_SHORT_NOT_OK transfer flag may be used to make such
- *     short reads be reported as errors. 
+ *     short reads be reported as errors.
  * @setup_packet: Only used for control transfers, this points to eight bytes
  *     of setup data.  Control transfers always start by sending this data
  *     to the device.  Then transfer_buffer is read or written, if needed.
@@ -1138,7 +1164,7 @@ typedef void (*usb_complete_t)(struct urb *);
  * @complete: Completion handler. This URB is passed as the parameter to the
  *     completion function.  The completion function may then do what
  *     it likes with the URB, including resubmitting or freeing it.
- * @iso_frame_desc: Used to provide arrays of ISO transfer buffers and to 
+ * @iso_frame_desc: Used to provide arrays of ISO transfer buffers and to
  *     collect the transfer status for each buffer.
  *
  * This structure identifies USB transfer requests.  URBs must be allocated by
@@ -1242,8 +1268,7 @@ typedef void (*usb_complete_t)(struct urb *);
  * when the urb is owned by the hcd, that is, since the call to
  * usb_submit_urb() till the entry into the completion routine.
  */
-struct urb
-{
+struct urb {
        /* private: usb core and host controller only fields in the urb */
        struct kref kref;               /* reference count of the URB */
        void *hcpriv;                   /* private data for host controller */
@@ -1254,10 +1279,10 @@ struct urb
        /* public: documented fields in the urb that can be used by drivers */
        struct list_head urb_list;      /* list head for use by the urb's
                                         * current owner */
-       struct list_head anchor_list;   /* the URB may be anchored by the driver */
+       struct list_head anchor_list;   /* the URB may be anchored */
        struct usb_anchor *anchor;
        struct usb_device *dev;         /* (in) pointer to associated device */
-       struct usb_host_endpoint *ep;   /* (internal) pointer to endpoint struct */
+       struct usb_host_endpoint *ep;   /* (internal) pointer to endpoint */
        unsigned int pipe;              /* (in) pipe information */
        int status;                     /* (return) non-ISO status */
        unsigned int transfer_flags;    /* (in) URB_SHORT_NOT_OK | ...*/
@@ -1294,14 +1319,14 @@ struct urb
  * Initializes a control urb with the proper information needed to submit
  * it to a device.
  */
-static inline void usb_fill_control_urb (struct urb *urb,
-                                        struct usb_device *dev,
-                                        unsigned int pipe,
-                                        unsigned char *setup_packet,
-                                        void *transfer_buffer,
-                                        int buffer_length,
-                                        usb_complete_t complete_fn,
-                                        void *context)
+static inline void usb_fill_control_urb(struct urb *urb,
+                                       struct usb_device *dev,
+                                       unsigned int pipe,
+                                       unsigned char *setup_packet,
+                                       void *transfer_buffer,
+                                       int buffer_length,
+                                       usb_complete_t complete_fn,
+                                       void *context)
 {
        urb->dev = dev;
        urb->pipe = pipe;
@@ -1325,13 +1350,13 @@ static inline void usb_fill_control_urb (struct urb *urb,
  * Initializes a bulk urb with the proper information needed to submit it
  * to a device.
  */
-static inline void usb_fill_bulk_urb (struct urb *urb,
-                                     struct usb_device *dev,
-                                     unsigned int pipe,
-                                     void *transfer_buffer,
-                                     int buffer_length,
-                                     usb_complete_t complete_fn,
-                                     void *context)
+static inline void usb_fill_bulk_urb(struct urb *urb,
+                                    struct usb_device *dev,
+                                    unsigned int pipe,
+                                    void *transfer_buffer,
+                                    int buffer_length,
+                                    usb_complete_t complete_fn,
+                                    void *context)
 {
        urb->dev = dev;
        urb->pipe = pipe;
@@ -1359,14 +1384,14 @@ static inline void usb_fill_bulk_urb (struct urb *urb,
  * the endpoint interval, and express polling intervals in microframes
  * (eight per millisecond) rather than in frames (one per millisecond).
  */
-static inline void usb_fill_int_urb (struct urb *urb,
-                                    struct usb_device *dev,
-                                    unsigned int pipe,
-                                    void *transfer_buffer,
-                                    int buffer_length,
-                                    usb_complete_t complete_fn,
-                                    void *context,
-                                    int interval)
+static inline void usb_fill_int_urb(struct urb *urb,
+                                   struct usb_device *dev,
+                                   unsigned int pipe,
+                                   void *transfer_buffer,
+                                   int buffer_length,
+                                   usb_complete_t complete_fn,
+                                   void *context,
+                                   int interval)
 {
        urb->dev = dev;
        urb->pipe = pipe;
@@ -1419,15 +1444,15 @@ static inline int usb_urb_dir_out(struct urb *urb)
        return (urb->transfer_flags & URB_DIR_MASK) == URB_DIR_OUT;
 }
 
-void *usb_buffer_alloc (struct usb_device *dev, size_t size,
+void *usb_buffer_alloc(struct usb_device *dev, size_t size,
        gfp_t mem_flags, dma_addr_t *dma);
-void usb_buffer_free (struct usb_device *dev, size_t size,
+void usb_buffer_free(struct usb_device *dev, size_t size,
        void *addr, dma_addr_t dma);
 
 #if 0
-struct urb *usb_buffer_map (struct urb *urb);
-void usb_buffer_dmasync (struct urb *urb);
-void usb_buffer_unmap (struct urb *urb);
+struct urb *usb_buffer_map(struct urb *urb);
+void usb_buffer_dmasync(struct urb *urb);
+void usb_buffer_unmap(struct urb *urb);
 #endif
 
 struct scatterlist;
@@ -1499,7 +1524,7 @@ struct usb_sg_request {
        int                     status;
        size_t                  bytes;
 
-       /* 
+       /*
         * members below are private: to usbcore,
         * and are not provided for driver access!
         */
@@ -1517,18 +1542,18 @@ struct usb_sg_request {
        struct completion       complete;
 };
 
-int usb_sg_init (
+int usb_sg_init(
        struct usb_sg_request   *io,
        struct usb_device       *dev,
-       unsigned                pipe, 
+       unsigned                pipe,
        unsigned                period,
        struct scatterlist      *sg,
        int                     nents,
        size_t                  length,
        gfp_t                   mem_flags
 );
-void usb_sg_cancel (struct usb_sg_request *io);
-void usb_sg_wait (struct usb_sg_request *io);
+void usb_sg_cancel(struct usb_sg_request *io);
+void usb_sg_wait(struct usb_sg_request *io);
 
 
 /* ----------------------------------------------------------------------- */
@@ -1585,21 +1610,21 @@ static inline unsigned int __create_pipe(struct usb_device *dev,
 
 /* Create various pipes... */
 #define usb_sndctrlpipe(dev,endpoint)  \
-       ((PIPE_CONTROL << 30) | __create_pipe(dev,endpoint))
+       ((PIPE_CONTROL << 30) | __create_pipe(dev, endpoint))
 #define usb_rcvctrlpipe(dev,endpoint)  \
-       ((PIPE_CONTROL << 30) | __create_pipe(dev,endpoint) | USB_DIR_IN)
+       ((PIPE_CONTROL << 30) | __create_pipe(dev, endpoint) | USB_DIR_IN)
 #define usb_sndisocpipe(dev,endpoint)  \
-       ((PIPE_ISOCHRONOUS << 30) | __create_pipe(dev,endpoint))
+       ((PIPE_ISOCHRONOUS << 30) | __create_pipe(dev, endpoint))
 #define usb_rcvisocpipe(dev,endpoint)  \
-       ((PIPE_ISOCHRONOUS << 30) | __create_pipe(dev,endpoint) | USB_DIR_IN)
+       ((PIPE_ISOCHRONOUS << 30) | __create_pipe(dev, endpoint) | USB_DIR_IN)
 #define usb_sndbulkpipe(dev,endpoint)  \
-       ((PIPE_BULK << 30) | __create_pipe(dev,endpoint))
+       ((PIPE_BULK << 30) | __create_pipe(dev, endpoint))
 #define usb_rcvbulkpipe(dev,endpoint)  \
-       ((PIPE_BULK << 30) | __create_pipe(dev,endpoint) | USB_DIR_IN)
+       ((PIPE_BULK << 30) | __create_pipe(dev, endpoint) | USB_DIR_IN)
 #define usb_sndintpipe(dev,endpoint)   \
-       ((PIPE_INTERRUPT << 30) | __create_pipe(dev,endpoint))
+       ((PIPE_INTERRUPT << 30) | __create_pipe(dev, endpoint))
 #define usb_rcvintpipe(dev,endpoint)   \
-       ((PIPE_INTERRUPT << 30) | __create_pipe(dev,endpoint) | USB_DIR_IN)
+       ((PIPE_INTERRUPT << 30) | __create_pipe(dev, endpoint) | USB_DIR_IN)
 
 /*-------------------------------------------------------------------------*/
 
index 6ce42bf9f743960a97fe95317542d042046dc059..b8cba1dcb2c63008a60f17926c40b3a5b728cc9c 100644 (file)
@@ -1,6 +1,7 @@
-unifdef-y += audio.h
-unifdef-y += cdc.h
-unifdef-y += ch9.h
-unifdef-y += gadgetfs.h
-unifdef-y += midi.h
+header-y += audio.h
+header-y += cdc.h
+header-y += ch9.h
+header-y += gadgetfs.h
+header-y += midi.h
+unifdef-y += g_printer.h
 
index 6bd235994dc2f7d25d12f78da6dfc95feea95eeb..2dfeef16b221d4605f2090de430e4f196c9d8712 100644 (file)
 
 /* 4.3.2  Class-Specific AC Interface Descriptor */
 struct usb_ac_header_descriptor {
-       __u8  bLength;                  // 8+n
-       __u8  bDescriptorType;          // USB_DT_CS_INTERFACE
-       __u8  bDescriptorSubtype;       // USB_MS_HEADER
-       __le16 bcdADC;                  // 0x0100
-       __le16 wTotalLength;            // includes Unit and Terminal desc.
-       __u8  bInCollection;            // n
-       __u8  baInterfaceNr[];          // [n]
+       __u8  bLength;                  /* 8+n */
+       __u8  bDescriptorType;          /* USB_DT_CS_INTERFACE */
+       __u8  bDescriptorSubtype;       /* USB_MS_HEADER */
+       __le16 bcdADC;                  /* 0x0100 */
+       __le16 wTotalLength;            /* includes Unit and Terminal desc. */
+       __u8  bInCollection;            /* n */
+       __u8  baInterfaceNr[];          /* [n] */
 } __attribute__ ((packed));
 
 #define USB_DT_AC_HEADER_SIZE(n)       (8+(n))
index 2204ae22c3812e1d4382acf5fc75673e825402fb..94ee4ecf0564972750e2fba836cd70990d01101a 100644 (file)
  * Class-Specific descriptors ... there are a couple dozen of them
  */
 
-#define USB_CDC_HEADER_TYPE            0x00            /* header_desc */
-#define USB_CDC_CALL_MANAGEMENT_TYPE   0x01            /* call_mgmt_descriptor */
-#define USB_CDC_ACM_TYPE               0x02            /* acm_descriptor */
-#define USB_CDC_UNION_TYPE             0x06            /* union_desc */
+#define USB_CDC_HEADER_TYPE            0x00    /* header_desc */
+#define USB_CDC_CALL_MANAGEMENT_TYPE   0x01    /* call_mgmt_descriptor */
+#define USB_CDC_ACM_TYPE               0x02    /* acm_descriptor */
+#define USB_CDC_UNION_TYPE             0x06    /* union_desc */
 #define USB_CDC_COUNTRY_TYPE           0x07
-#define USB_CDC_NETWORK_TERMINAL_TYPE  0x0a            /* network_terminal_desc */
-#define USB_CDC_ETHERNET_TYPE          0x0f            /* ether_desc */
+#define USB_CDC_NETWORK_TERMINAL_TYPE  0x0a    /* network_terminal_desc */
+#define USB_CDC_ETHERNET_TYPE          0x0f    /* ether_desc */
 #define USB_CDC_WHCM_TYPE              0x11
-#define USB_CDC_MDLM_TYPE              0x12            /* mdlm_desc */
-#define USB_CDC_MDLM_DETAIL_TYPE       0x13            /* mdlm_detail_desc */
+#define USB_CDC_MDLM_TYPE              0x12    /* mdlm_desc */
+#define USB_CDC_MDLM_DETAIL_TYPE       0x13    /* mdlm_detail_desc */
 #define USB_CDC_DMM_TYPE               0x14
 #define USB_CDC_OBEX_TYPE              0x15
 
diff --git a/include/linux/usb/g_printer.h b/include/linux/usb/g_printer.h
new file mode 100644 (file)
index 0000000..0c5ea1e
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * g_printer.h -- Header file for USB Printer gadget driver
+ *
+ * Copyright (C) 2007 Craig W. Nadler
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+
+#define PRINTER_NOT_ERROR      0x08
+#define PRINTER_SELECTED       0x10
+#define PRINTER_PAPER_EMPTY    0x20
+
+/* The 'g' code is also used by gadgetfs ioctl requests.
+ * Don't add any colliding codes to either driver, and keep
+ * them in unique ranges (size 0x20 for now).
+ */
+#define GADGET_GET_PRINTER_STATUS      _IOR('g', 0x21, unsigned char)
+#define GADGET_SET_PRINTER_STATUS      _IOWR('g', 0x22, unsigned char)
index c1527c2ef3cb1a8a8da5e79d7ca81acf867c9c79..aa3047ff00d13076e8ce29bd805b6a214b931945 100644 (file)
@@ -70,9 +70,10 @@ struct usb_ep;
  *
  * Bulk endpoints can use any size buffers, and can also be used for interrupt
  * transfers. interrupt-only endpoints can be much less functional.
+ *
+ * NOTE:  this is analagous to 'struct urb' on the host side, except that
+ * it's thinner and promotes more pre-allocation.
  */
-       // NOTE this is analagous to 'struct urb' on the host side,
-       // except that it's thinner and promotes more pre-allocation.
 
 struct usb_request {
        void                    *buf;
@@ -168,10 +169,10 @@ struct usb_ep {
  *
  * returns zero, or a negative error code.
  */
-static inline int
-usb_ep_enable (struct usb_ep *ep, const struct usb_endpoint_descriptor *desc)
+static inline int usb_ep_enable(struct usb_ep *ep,
+                               const struct usb_endpoint_descriptor *desc)
 {
-       return ep->ops->enable (ep, desc);
+       return ep->ops->enable(ep, desc);
 }
 
 /**
@@ -186,10 +187,9 @@ usb_ep_enable (struct usb_ep *ep, const struct usb_endpoint_descriptor *desc)
  *
  * returns zero, or a negative error code.
  */
-static inline int
-usb_ep_disable (struct usb_ep *ep)
+static inline int usb_ep_disable(struct usb_ep *ep)
 {
-       return ep->ops->disable (ep);
+       return ep->ops->disable(ep);
 }
 
 /**
@@ -206,10 +206,10 @@ usb_ep_disable (struct usb_ep *ep)
  *
  * Returns the request, or null if one could not be allocated.
  */
-static inline struct usb_request *
-usb_ep_alloc_request (struct usb_ep *ep, gfp_t gfp_flags)
+static inline struct usb_request *usb_ep_alloc_request(struct usb_ep *ep,
+                                                      gfp_t gfp_flags)
 {
-       return ep->ops->alloc_request (ep, gfp_flags);
+       return ep->ops->alloc_request(ep, gfp_flags);
 }
 
 /**
@@ -221,10 +221,10 @@ usb_ep_alloc_request (struct usb_ep *ep, gfp_t gfp_flags)
  * Caller guarantees the request is not queued, and that it will
  * no longer be requeued (or otherwise used).
  */
-static inline void
-usb_ep_free_request (struct usb_ep *ep, struct usb_request *req)
+static inline void usb_ep_free_request(struct usb_ep *ep,
+                                      struct usb_request *req)
 {
-       ep->ops->free_request (ep, req);
+       ep->ops->free_request(ep, req);
 }
 
 /**
@@ -281,10 +281,10 @@ usb_ep_free_request (struct usb_ep *ep, struct usb_request *req)
  * report errors; errors will also be
  * reported when the usb peripheral is disconnected.
  */
-static inline int
-usb_ep_queue (struct usb_ep *ep, struct usb_request *req, gfp_t gfp_flags)
+static inline int usb_ep_queue(struct usb_ep *ep,
+                              struct usb_request *req, gfp_t gfp_flags)
 {
-       return ep->ops->queue (ep, req, gfp_flags);
+       return ep->ops->queue(ep, req, gfp_flags);
 }
 
 /**
@@ -301,9 +301,9 @@ usb_ep_queue (struct usb_ep *ep, struct usb_request *req, gfp_t gfp_flags)
  * restrictions prevent drivers from supporting configuration changes,
  * even to configuration zero (a "chapter 9" requirement).
  */
-static inline int usb_ep_dequeue (struct usb_ep *ep, struct usb_request *req)
+static inline int usb_ep_dequeue(struct usb_ep *ep, struct usb_request *req)
 {
-       return ep->ops->dequeue (ep, req);
+       return ep->ops->dequeue(ep, req);
 }
 
 /**
@@ -327,10 +327,9 @@ static inline int usb_ep_dequeue (struct usb_ep *ep, struct usb_request *req)
  * transfer requests are still queued, or if the controller hardware
  * (usually a FIFO) still holds bytes that the host hasn't collected.
  */
-static inline int
-usb_ep_set_halt (struct usb_ep *ep)
+static inline int usb_ep_set_halt(struct usb_ep *ep)
 {
-       return ep->ops->set_halt (ep, 1);
+       return ep->ops->set_halt(ep, 1);
 }
 
 /**
@@ -346,10 +345,9 @@ usb_ep_set_halt (struct usb_ep *ep)
  * Note that some hardware can't support this request (like pxa2xx_udc),
  * and accordingly can't correctly implement interface altsettings.
  */
-static inline int
-usb_ep_clear_halt (struct usb_ep *ep)
+static inline int usb_ep_clear_halt(struct usb_ep *ep)
 {
-       return ep->ops->set_halt (ep, 0);
+       return ep->ops->set_halt(ep, 0);
 }
 
 /**
@@ -367,11 +365,10 @@ usb_ep_clear_halt (struct usb_ep *ep)
  * errno if the endpoint doesn't use a FIFO or doesn't support such
  * precise handling.
  */
-static inline int
-usb_ep_fifo_status (struct usb_ep *ep)
+static inline int usb_ep_fifo_status(struct usb_ep *ep)
 {
        if (ep->ops->fifo_status)
-               return ep->ops->fifo_status (ep);
+               return ep->ops->fifo_status(ep);
        else
                return -EOPNOTSUPP;
 }
@@ -385,11 +382,10 @@ usb_ep_fifo_status (struct usb_ep *ep)
  * must never be used except when endpoint is not being used for any
  * protocol translation.
  */
-static inline void
-usb_ep_fifo_flush (struct usb_ep *ep)
+static inline void usb_ep_fifo_flush(struct usb_ep *ep)
 {
        if (ep->ops->fifo_flush)
-               ep->ops->fifo_flush (ep);
+               ep->ops->fifo_flush(ep);
 }
 
 
@@ -469,10 +465,10 @@ struct usb_gadget {
        struct device                   dev;
 };
 
-static inline void set_gadget_data (struct usb_gadget *gadget, void *data)
-       { dev_set_drvdata (&gadget->dev, data); }
-static inline void *get_gadget_data (struct usb_gadget *gadget)
-       { return dev_get_drvdata (&gadget->dev); }
+static inline void set_gadget_data(struct usb_gadget *gadget, void *data)
+       { dev_set_drvdata(&gadget->dev, data); }
+static inline void *get_gadget_data(struct usb_gadget *gadget)
+       { return dev_get_drvdata(&gadget->dev); }
 
 /* iterates the non-control endpoints; 'tmp' is a struct usb_ep pointer */
 #define gadget_for_each_ep(tmp,gadget) \
@@ -511,7 +507,6 @@ static inline int gadget_is_otg(struct usb_gadget *g)
 #endif
 }
 
-
 /**
  * usb_gadget_frame_number - returns the current frame number
  * @gadget: controller that reports the frame number
@@ -519,9 +514,9 @@ static inline int gadget_is_otg(struct usb_gadget *g)
  * Returns the usb frame number, normally eleven bits from a SOF packet,
  * or negative errno if this device doesn't support this capability.
  */
-static inline int usb_gadget_frame_number (struct usb_gadget *gadget)
+static inline int usb_gadget_frame_number(struct usb_gadget *gadget)
 {
-       return gadget->ops->get_frame (gadget);
+       return gadget->ops->get_frame(gadget);
 }
 
 /**
@@ -537,11 +532,11 @@ static inline int usb_gadget_frame_number (struct usb_gadget *gadget)
  * even if OTG isn't otherwise in use.  OTG devices may also start
  * remote wakeup even when hosts don't explicitly enable it.
  */
-static inline int usb_gadget_wakeup (struct usb_gadget *gadget)
+static inline int usb_gadget_wakeup(struct usb_gadget *gadget)
 {
        if (!gadget->ops->wakeup)
                return -EOPNOTSUPP;
-       return gadget->ops->wakeup (gadget);
+       return gadget->ops->wakeup(gadget);
 }
 
 /**
@@ -553,12 +548,11 @@ static inline int usb_gadget_wakeup (struct usb_gadget *gadget)
  *
  * returns zero on success, else negative errno.
  */
-static inline int
-usb_gadget_set_selfpowered (struct usb_gadget *gadget)
+static inline int usb_gadget_set_selfpowered(struct usb_gadget *gadget)
 {
        if (!gadget->ops->set_selfpowered)
                return -EOPNOTSUPP;
-       return gadget->ops->set_selfpowered (gadget, 1);
+       return gadget->ops->set_selfpowered(gadget, 1);
 }
 
 /**
@@ -571,12 +565,11 @@ usb_gadget_set_selfpowered (struct usb_gadget *gadget)
  *
  * returns zero on success, else negative errno.
  */
-static inline int
-usb_gadget_clear_selfpowered (struct usb_gadget *gadget)
+static inline int usb_gadget_clear_selfpowered(struct usb_gadget *gadget)
 {
        if (!gadget->ops->set_selfpowered)
                return -EOPNOTSUPP;
-       return gadget->ops->set_selfpowered (gadget, 0);
+       return gadget->ops->set_selfpowered(gadget, 0);
 }
 
 /**
@@ -591,12 +584,11 @@ usb_gadget_clear_selfpowered (struct usb_gadget *gadget)
  *
  * Returns zero on success, else negative errno.
  */
-static inline int
-usb_gadget_vbus_connect(struct usb_gadget *gadget)
+static inline int usb_gadget_vbus_connect(struct usb_gadget *gadget)
 {
        if (!gadget->ops->vbus_session)
                return -EOPNOTSUPP;
-       return gadget->ops->vbus_session (gadget, 1);
+       return gadget->ops->vbus_session(gadget, 1);
 }
 
 /**
@@ -611,12 +603,11 @@ usb_gadget_vbus_connect(struct usb_gadget *gadget)
  *
  * Returns zero on success, else negative errno.
  */
-static inline int
-usb_gadget_vbus_draw(struct usb_gadget *gadget, unsigned mA)
+static inline int usb_gadget_vbus_draw(struct usb_gadget *gadget, unsigned mA)
 {
        if (!gadget->ops->vbus_draw)
                return -EOPNOTSUPP;
-       return gadget->ops->vbus_draw (gadget, mA);
+       return gadget->ops->vbus_draw(gadget, mA);
 }
 
 /**
@@ -629,12 +620,11 @@ usb_gadget_vbus_draw(struct usb_gadget *gadget, unsigned mA)
  *
  * Returns zero on success, else negative errno.
  */
-static inline int
-usb_gadget_vbus_disconnect(struct usb_gadget *gadget)
+static inline int usb_gadget_vbus_disconnect(struct usb_gadget *gadget)
 {
        if (!gadget->ops->vbus_session)
                return -EOPNOTSUPP;
-       return gadget->ops->vbus_session (gadget, 0);
+       return gadget->ops->vbus_session(gadget, 0);
 }
 
 /**
@@ -648,12 +638,11 @@ usb_gadget_vbus_disconnect(struct usb_gadget *gadget)
  *
  * Returns zero on success, else negative errno.
  */
-static inline int
-usb_gadget_connect (struct usb_gadget *gadget)
+static inline int usb_gadget_connect(struct usb_gadget *gadget)
 {
        if (!gadget->ops->pullup)
                return -EOPNOTSUPP;
-       return gadget->ops->pullup (gadget, 1);
+       return gadget->ops->pullup(gadget, 1);
 }
 
 /**
@@ -671,16 +660,14 @@ usb_gadget_connect (struct usb_gadget *gadget)
  *
  * Returns zero on success, else negative errno.
  */
-static inline int
-usb_gadget_disconnect (struct usb_gadget *gadget)
+static inline int usb_gadget_disconnect(struct usb_gadget *gadget)
 {
        if (!gadget->ops->pullup)
                return -EOPNOTSUPP;
-       return gadget->ops->pullup (gadget, 0);
+       return gadget->ops->pullup(gadget, 0);
 }
 
 
-
 /*-------------------------------------------------------------------------*/
 
 /**
@@ -764,7 +751,7 @@ struct usb_gadget_driver {
        void                    (*suspend)(struct usb_gadget *);
        void                    (*resume)(struct usb_gadget *);
 
-       // FIXME support safe rmmod
+       /* FIXME support safe rmmod */
        struct device_driver    driver;
 };
 
@@ -790,7 +777,7 @@ struct usb_gadget_driver {
  * the bind() functions will be in init sections.
  * This function must be called in a context that can sleep.
  */
-int usb_gadget_register_driver (struct usb_gadget_driver *driver);
+int usb_gadget_register_driver(struct usb_gadget_driver *driver);
 
 /**
  * usb_gadget_unregister_driver - unregister a gadget driver
@@ -805,7 +792,7 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver);
  * will in in exit sections, so may not be linked in some kernels.
  * This function must be called in a context that can sleep.
  */
-int usb_gadget_unregister_driver (struct usb_gadget_driver *driver);
+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver);
 
 /*-------------------------------------------------------------------------*/
 
@@ -838,7 +825,7 @@ struct usb_gadget_strings {
 };
 
 /* put descriptor for string with that id into buf (buflen >= 256) */
-int usb_gadget_get_string (struct usb_gadget_strings *table, int id, u8 *buf);
+int usb_gadget_get_string(struct usb_gadget_strings *table, int id, u8 *buf);
 
 /*-------------------------------------------------------------------------*/
 
@@ -856,10 +843,10 @@ int usb_gadget_config_buf(const struct usb_config_descriptor *config,
 
 /* utility wrapping a simple endpoint selection policy */
 
-extern struct usb_ep *usb_ep_autoconfig (struct usb_gadget *,
+extern struct usb_ep *usb_ep_autoconfig(struct usb_gadget *,
                        struct usb_endpoint_descriptor *) __devinit;
 
-extern void usb_ep_autoconfig_reset (struct usb_gadget *) __devinit;
+extern void usb_ep_autoconfig_reset(struct usb_gadget *) __devinit;
 
 #endif  /* __KERNEL__ */
 
index e8654c338729438de4b6d887b53c7dec725b3600..c291ab1af747a37953f7866fe6479dcef16a7877 100644 (file)
@@ -36,7 +36,7 @@ enum usb_gadgetfs_event_type {
        GADGETFS_DISCONNECT,
        GADGETFS_SETUP,
        GADGETFS_SUSPEND,
-       // and likely more !
+       /* and likely more ! */
 };
 
 /* NOTE:  this structure must stay the same size and layout on
@@ -44,21 +44,28 @@ enum usb_gadgetfs_event_type {
  */
 struct usb_gadgetfs_event {
        union {
-               // NOP, DISCONNECT, SUSPEND: nothing
-               // ... some hardware can't report disconnection
+               /* NOP, DISCONNECT, SUSPEND: nothing
+                * ... some hardware can't report disconnection
+                */
 
-               // CONNECT: just the speed
+               /* CONNECT: just the speed */
                enum usb_device_speed   speed;
 
-               // SETUP: packet; DATA phase i/o precedes next event
-               // (setup.bmRequestType & USB_DIR_IN) flags direction
-               // ... includes SET_CONFIGURATION, SET_INTERFACE
+               /* SETUP: packet; DATA phase i/o precedes next event
+                *(setup.bmRequestType & USB_DIR_IN) flags direction
+                * ... includes SET_CONFIGURATION, SET_INTERFACE
+                */
                struct usb_ctrlrequest  setup;
        } u;
        enum usb_gadgetfs_event_type    type;
 };
 
 
+/* The 'g' code is also used by printer gadget ioctl requests.
+ * Don't add any colliding codes to either driver, and keep
+ * them in unique ranges (size 0x20 for now).
+ */
+
 /* endpoint ioctls */
 
 /* IN transfers may be reported to the gadget driver as complete
@@ -68,14 +75,14 @@ struct usb_gadgetfs_event {
  * THIS returns how many bytes are "unclaimed" in the endpoint fifo
  * (needed for precise fault handling, when the hardware allows it)
  */
-#define        GADGETFS_FIFO_STATUS    _IO('g',1)
+#define        GADGETFS_FIFO_STATUS    _IO('g', 1)
 
 /* discards any unclaimed data in the fifo. */
-#define        GADGETFS_FIFO_FLUSH     _IO('g',2)
+#define        GADGETFS_FIFO_FLUSH     _IO('g', 2)
 
 /* resets endpoint halt+toggle; used to implement set_interface.
  * some hardware (like pxa2xx) can't support this.
  */
-#define        GADGETFS_CLEAR_HALT     _IO('g',3)
+#define        GADGETFS_CLEAR_HALT     _IO('g', 3)
 
 #endif /* __LINUX_USB_GADGETFS_H */
index cbbe020a4f5c493bd7481177f98cd53417c01bf4..de6f380e17a2bfac42059c40b41c69d3102222f9 100644 (file)
    this information.
 */
 struct iowarrior_info {
-       __u32 vendor;           /* vendor id : supposed to be USB_VENDOR_ID_CODEMERCS in all cases */
-       __u32 product;          /* product id : depends on type of chip (USB_DEVICE_ID_CODEMERCS_XXXXX) */
-       __u8 serial[9];         /* the serial number of our chip (if a serial-number is not available this is empty string) */
-       __u32 revision;         /* revision number of the chip */
-       __u32 speed;            /* USB-speed of the device (0=UNKNOWN, 1=LOW, 2=FULL 3=HIGH) */
-       __u32 power;            /* power consumption of the device in mA */
-       __u32 if_num;           /* the number of the endpoint */
-       __u32 report_size;      /* size of the data-packets on this interface */
+       /* vendor id : supposed to be USB_VENDOR_ID_CODEMERCS in all cases */
+       __u32 vendor;
+       /* product id : depends on type of chip (USB_DEVICE_ID_CODEMERCS_X) */
+       __u32 product;
+       /* the serial number of our chip (if a serial-number is not available
+        * this is empty string) */
+       __u8 serial[9];
+       /* revision number of the chip */
+       __u32 revision;
+       /* USB-speed of the device (0=UNKNOWN, 1=LOW, 2=FULL 3=HIGH) */
+       __u32 speed;
+       /* power consumption of the device in mA */
+       __u32 power;
+       /* the number of the endpoint */
+       __u32 if_num;
+       /* size of the data-packets on this interface */
+       __u32 report_size;
 };
 
 /*
index 436dd8a2b64ac67bea6d8d183be800a97c9ddc57..67d2826f34fe7795cc8bb37bf3ea4fa6ab7c1307 100644 (file)
@@ -25,5 +25,5 @@ struct isp116x_platform_data {
           300ns delay between access to ADDR_REG and DATA_REG
           OE, WE MUST NOT be changed during these intervals
         */
-       void (*delay) (struct device * dev, int delay);
+       void (*delay) (struct device *dev, int delay);
 };
index 11a97d5ffd34f3f68270339c808afcb8975552bb..80624c562921e0fe2dc620ccbaad6e16f70eb7cb 100644 (file)
@@ -47,9 +47,9 @@ struct usb_ms_header_descriptor {
 /* 6.1.2.2  MIDI IN Jack Descriptor */
 struct usb_midi_in_jack_descriptor {
        __u8  bLength;
-       __u8  bDescriptorType;          // USB_DT_CS_INTERFACE
-       __u8  bDescriptorSubtype;       // USB_MS_MIDI_IN_JACK
-       __u8  bJackType;                // USB_MS_EMBEDDED/EXTERNAL
+       __u8  bDescriptorType;          /* USB_DT_CS_INTERFACE */
+       __u8  bDescriptorSubtype;       /* USB_MS_MIDI_IN_JACK */
+       __u8  bJackType;                /* USB_MS_EMBEDDED/EXTERNAL */
        __u8  bJackID;
        __u8  iJack;
 } __attribute__ ((packed));
@@ -64,12 +64,12 @@ struct usb_midi_source_pin {
 /* 6.1.2.3  MIDI OUT Jack Descriptor */
 struct usb_midi_out_jack_descriptor {
        __u8  bLength;
-       __u8  bDescriptorType;          // USB_DT_CS_INTERFACE
-       __u8  bDescriptorSubtype;       // USB_MS_MIDI_OUT_JACK
-       __u8  bJackType;                // USB_MS_EMBEDDED/EXTERNAL
+       __u8  bDescriptorType;          /* USB_DT_CS_INTERFACE */
+       __u8  bDescriptorSubtype;       /* USB_MS_MIDI_OUT_JACK */
+       __u8  bJackType;                /* USB_MS_EMBEDDED/EXTERNAL */
        __u8  bJackID;
-       __u8  bNrInputPins;             // p
-       struct usb_midi_source_pin pins[]; // [p]
+       __u8  bNrInputPins;             /* p */
+       struct usb_midi_source_pin pins[]; /* [p] */
        /*__u8  iJack;  -- ommitted due to variable-sized pins[] */
 } __attribute__ ((packed));
 
@@ -90,11 +90,11 @@ struct usb_midi_out_jack_descriptor_##p {                   \
 
 /* 6.2.2  Class-Specific MS Bulk Data Endpoint Descriptor */
 struct usb_ms_endpoint_descriptor {
-       __u8  bLength;                  // 4+n
-       __u8  bDescriptorType;          // USB_DT_CS_ENDPOINT
-       __u8  bDescriptorSubtype;       // USB_MS_GENERAL
-       __u8  bNumEmbMIDIJack;          // n
-       __u8  baAssocJackID[];          // [n]
+       __u8  bLength;                  /* 4+n */
+       __u8  bDescriptorType;          /* USB_DT_CS_ENDPOINT */
+       __u8  bDescriptorSubtype;       /* USB_MS_GENERAL */
+       __u8  bNumEmbMIDIJack;          /* n */
+       __u8  baAssocJackID[];          /* [n] */
 } __attribute__ ((packed));
 
 #define USB_DT_MS_ENDPOINT_SIZE(n)     (4 + (n))
index c602f884f182ee91c7ce2a71fe77ab4071fb0edd..ec897cb844ab5cd9a8dbda9be1b66a37cf8235c2 100644 (file)
@@ -37,7 +37,7 @@
 
 /* main registers, BAR0 + 0x0000 */
 struct net2280_regs {
-       // offset 0x0000
+       /* offset 0x0000 */
        u32             devinit;
 #define     LOCAL_CLOCK_FREQUENCY                               8
 #define     FORCE_PCI_RESET                                     7
@@ -61,7 +61,7 @@ struct net2280_regs {
 #define     EEPROM_WRITE_DATA                                   0
        u32             eeclkfreq;
        u32             _unused0;
-       // offset 0x0010
+       /* offset 0x0010 */
 
        u32             pciirqenb0;             /* interrupt PCI master ... */
 #define     SETUP_PACKET_INTERRUPT_ENABLE                       7
@@ -131,7 +131,7 @@ struct net2280_regs {
 #define     RESUME_INTERRUPT_ENABLE                             1
 #define     SOF_INTERRUPT_ENABLE                                0
 
-       // offset 0x0020
+       /* offset 0x0020 */
        u32             _unused1;
        u32             usbirqenb1;
 #define     USB_INTERRUPT_ENABLE                                31
@@ -195,7 +195,7 @@ struct net2280_regs {
 #define     SUSPEND_REQUEST_CHANGE_INTERRUPT                    2
 #define     RESUME_INTERRUPT                                    1
 #define     SOF_INTERRUPT                                       0
-       // offset 0x0030
+       /* offset 0x0030 */
        u32             idxaddr;
        u32             idxdata;
        u32             fifoctl;
@@ -204,7 +204,7 @@ struct net2280_regs {
 #define     PCI_BASE2_SELECT                                    2
 #define     FIFO_CONFIGURATION_SELECT                           0
        u32             _unused2;
-       // offset 0x0040
+       /* offset 0x0040 */
        u32             memaddr;
 #define     START                                               28
 #define     DIRECTION                                           27
@@ -213,7 +213,7 @@ struct net2280_regs {
        u32             memdata0;
        u32             memdata1;
        u32             _unused3;
-       // offset 0x0050
+       /* offset 0x0050 */
        u32             gpioctl;
 #define     GPIO3_LED_SELECT                                    12
 #define     GPIO3_INTERRUPT_ENABLE                              11
@@ -237,7 +237,7 @@ struct net2280_regs {
 
 /* usb control, BAR0 + 0x0080 */
 struct net2280_usb_regs {
-       // offset 0x0080
+       /* offset 0x0080 */
        u32             stdrsp;
 #define     STALL_UNSUPPORTED_REQUESTS                          31
 #define     SET_TEST_MODE                                       16
@@ -275,7 +275,7 @@ struct net2280_usb_regs {
 #define     PME_WAKEUP_ENABLE                                   2
 #define     DEVICE_REMOTE_WAKEUP_ENABLE                         1
 #define     SELF_POWERED_STATUS                                 0
-       // offset 0x0090
+       /* offset 0x0090 */
        u32             usbstat;
 #define     HIGH_SPEED                                          7
 #define     FULL_SPEED                                          6
@@ -291,7 +291,7 @@ struct net2280_usb_regs {
 #define     TERMINATION_SELECT                                  0
        u32             setup0123;
        u32             setup4567;
-       // offset 0x0090
+       /* offset 0x0090 */
        u32             _unused0;
        u32             ouraddr;
 #define     FORCE_IMMEDIATE                                     7
@@ -301,7 +301,7 @@ struct net2280_usb_regs {
 
 /* pci control, BAR0 + 0x0100 */
 struct net2280_pci_regs {
-       // offset 0x0100
+       /* offset 0x0100 */
        u32              pcimstctl;
 #define     PCI_ARBITER_PARK_SELECT                             13
 #define     PCI_MULTI LEVEL_ARBITER                             12
@@ -331,7 +331,7 @@ struct net2280_pci_regs {
  * that can be loaded into some of these registers.
  */
 struct net2280_dma_regs {      /* [11.7] */
-       // offset 0x0180, 0x01a0, 0x01c0, 0x01e0,
+       /* offset 0x0180, 0x01a0, 0x01c0, 0x01e0, */
        u32             dmactl;
 #define     DMA_SCATTER_GATHER_DONE_INTERRUPT_ENABLE            25
 #define     DMA_CLEAR_COUNT_ENABLE                              21
@@ -355,7 +355,7 @@ struct net2280_dma_regs {   /* [11.7] */
 #define     DMA_ABORT                                           1
 #define     DMA_START                                           0
        u32             _unused0 [2];
-       // offset 0x0190, 0x01b0, 0x01d0, 0x01f0,
+       /* offset 0x0190, 0x01b0, 0x01d0, 0x01f0, */
        u32             dmacount;
 #define     VALID_BIT                                           31
 #define     DMA_DIRECTION                                       30
@@ -371,9 +371,9 @@ struct net2280_dma_regs {   /* [11.7] */
 /* dedicated endpoint registers, BAR0 + 0x0200 */
 
 struct net2280_dep_regs {      /* [11.8] */
-       // offset 0x0200, 0x0210, 0x220, 0x230, 0x240
+       /* offset 0x0200, 0x0210, 0x220, 0x230, 0x240 */
        u32             dep_cfg;
-       // offset 0x0204, 0x0214, 0x224, 0x234, 0x244
+       /* offset 0x0204, 0x0214, 0x224, 0x234, 0x244 */
        u32             dep_rsp;
        u32             _unused [2];
 } __attribute__ ((packed));
@@ -383,7 +383,7 @@ struct net2280_dep_regs {   /* [11.8] */
  * ep0 reserved for control; E and F have only 64 bytes of fifo
  */
 struct net2280_ep_regs {       /* [11.9] */
-       // offset 0x0300, 0x0320, 0x0340, 0x0360, 0x0380, 0x03a0, 0x03c0
+       /* offset 0x0300, 0x0320, 0x0340, 0x0360, 0x0380, 0x03a0, 0x03c0 */
        u32             ep_cfg;
 #define     ENDPOINT_BYTE_COUNT                                 16
 #define     ENDPOINT_ENABLE                                     10
@@ -435,7 +435,7 @@ struct net2280_ep_regs {    /* [11.9] */
 #define     DATA_PACKET_TRANSMITTED_INTERRUPT                   2
 #define     DATA_OUT_PING_TOKEN_INTERRUPT                       1
 #define     DATA_IN_TOKEN_INTERRUPT                             0
-       // offset 0x0310, 0x0330, 0x0350, 0x0370, 0x0390, 0x03b0, 0x03d0
+       /* offset 0x0310, 0x0330, 0x0350, 0x0370, 0x0390, 0x03b0, 0x03d0 */
        u32             ep_avail;
        u32             ep_data;
        u32             _unused0 [2];
index 9897f7a818c561fb6a6a04e2004874ee8ca4d967..e007074ebe41f6b9648f62177cfa588b7bc13fcb 100644 (file)
@@ -1,4 +1,4 @@
-// include/linux/usb/otg.h
+/* USB OTG (On The Go) defines */
 
 /*
  * These APIs may be used between USB controllers.  USB device drivers
diff --git a/include/linux/usb/rndis_host.h b/include/linux/usb/rndis_host.h
new file mode 100644 (file)
index 0000000..edc1d4a
--- /dev/null
@@ -0,0 +1,274 @@
+/*
+ * Host Side support for RNDIS Networking Links
+ * Copyright (C) 2005 by David Brownell
+ *
+ * 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        __RNDIS_HOST_H
+#define        __RNDIS_HOST_H
+
+
+/*
+ * CONTROL uses CDC "encapsulated commands" with funky notifications.
+ *  - control-out:  SEND_ENCAPSULATED
+ *  - interrupt-in:  RESPONSE_AVAILABLE
+ *  - control-in:  GET_ENCAPSULATED
+ *
+ * We'll try to ignore the RESPONSE_AVAILABLE notifications.
+ *
+ * REVISIT some RNDIS implementations seem to have curious issues still
+ * to be resolved.
+ */
+struct rndis_msg_hdr {
+       __le32  msg_type;                       /* RNDIS_MSG_* */
+       __le32  msg_len;
+       // followed by data that varies between messages
+       __le32  request_id;
+       __le32  status;
+       // ... and more
+} __attribute__ ((packed));
+
+/* MS-Windows uses this strange size, but RNDIS spec says 1024 minimum */
+#define        CONTROL_BUFFER_SIZE             1025
+
+/* RNDIS defines an (absurdly huge) 10 second control timeout,
+ * but ActiveSync seems to use a more usual 5 second timeout
+ * (which matches the USB 2.0 spec).
+ */
+#define        RNDIS_CONTROL_TIMEOUT_MS        (5 * 1000)
+
+
+#define ccpu2 __constant_cpu_to_le32
+
+#define RNDIS_MSG_COMPLETION   ccpu2(0x80000000)
+
+/* codes for "msg_type" field of rndis messages;
+ * only the data channel uses packet messages (maybe batched);
+ * everything else goes on the control channel.
+ */
+#define RNDIS_MSG_PACKET       ccpu2(0x00000001)       /* 1-N packets */
+#define RNDIS_MSG_INIT         ccpu2(0x00000002)
+#define RNDIS_MSG_INIT_C       (RNDIS_MSG_INIT|RNDIS_MSG_COMPLETION)
+#define RNDIS_MSG_HALT         ccpu2(0x00000003)
+#define RNDIS_MSG_QUERY                ccpu2(0x00000004)
+#define RNDIS_MSG_QUERY_C      (RNDIS_MSG_QUERY|RNDIS_MSG_COMPLETION)
+#define RNDIS_MSG_SET          ccpu2(0x00000005)
+#define RNDIS_MSG_SET_C                (RNDIS_MSG_SET|RNDIS_MSG_COMPLETION)
+#define RNDIS_MSG_RESET                ccpu2(0x00000006)
+#define RNDIS_MSG_RESET_C      (RNDIS_MSG_RESET|RNDIS_MSG_COMPLETION)
+#define RNDIS_MSG_INDICATE     ccpu2(0x00000007)
+#define RNDIS_MSG_KEEPALIVE    ccpu2(0x00000008)
+#define RNDIS_MSG_KEEPALIVE_C  (RNDIS_MSG_KEEPALIVE|RNDIS_MSG_COMPLETION)
+
+/* codes for "status" field of completion messages */
+#define        RNDIS_STATUS_SUCCESS            ccpu2(0x00000000)
+#define        RNDIS_STATUS_FAILURE            ccpu2(0xc0000001)
+#define        RNDIS_STATUS_INVALID_DATA       ccpu2(0xc0010015)
+#define        RNDIS_STATUS_NOT_SUPPORTED      ccpu2(0xc00000bb)
+#define        RNDIS_STATUS_MEDIA_CONNECT      ccpu2(0x4001000b)
+#define        RNDIS_STATUS_MEDIA_DISCONNECT   ccpu2(0x4001000c)
+
+/* codes for OID_GEN_PHYSICAL_MEDIUM */
+#define        RNDIS_PHYSICAL_MEDIUM_UNSPECIFIED       ccpu2(0x00000000)
+#define        RNDIS_PHYSICAL_MEDIUM_WIRELESS_LAN      ccpu2(0x00000001)
+#define        RNDIS_PHYSICAL_MEDIUM_CABLE_MODEM       ccpu2(0x00000002)
+#define        RNDIS_PHYSICAL_MEDIUM_PHONE_LINE        ccpu2(0x00000003)
+#define        RNDIS_PHYSICAL_MEDIUM_POWER_LINE        ccpu2(0x00000004)
+#define        RNDIS_PHYSICAL_MEDIUM_DSL               ccpu2(0x00000005)
+#define        RNDIS_PHYSICAL_MEDIUM_FIBRE_CHANNEL     ccpu2(0x00000006)
+#define        RNDIS_PHYSICAL_MEDIUM_1394              ccpu2(0x00000007)
+#define        RNDIS_PHYSICAL_MEDIUM_WIRELESS_WAN      ccpu2(0x00000008)
+#define        RNDIS_PHYSICAL_MEDIUM_MAX               ccpu2(0x00000009)
+
+struct rndis_data_hdr {
+       __le32  msg_type;               /* RNDIS_MSG_PACKET */
+       __le32  msg_len;                // rndis_data_hdr + data_len + pad
+       __le32  data_offset;            // 36 -- right after header
+       __le32  data_len;               // ... real packet size
+
+       __le32  oob_data_offset;        // zero
+       __le32  oob_data_len;           // zero
+       __le32  num_oob;                // zero
+       __le32  packet_data_offset;     // zero
+
+       __le32  packet_data_len;        // zero
+       __le32  vc_handle;              // zero
+       __le32  reserved;               // zero
+} __attribute__ ((packed));
+
+struct rndis_init {            /* OUT */
+       // header and:
+       __le32  msg_type;                       /* RNDIS_MSG_INIT */
+       __le32  msg_len;                        // 24
+       __le32  request_id;
+       __le32  major_version;                  // of rndis (1.0)
+       __le32  minor_version;
+       __le32  max_transfer_size;
+} __attribute__ ((packed));
+
+struct rndis_init_c {          /* IN */
+       // header and:
+       __le32  msg_type;                       /* RNDIS_MSG_INIT_C */
+       __le32  msg_len;
+       __le32  request_id;
+       __le32  status;
+       __le32  major_version;                  // of rndis (1.0)
+       __le32  minor_version;
+       __le32  device_flags;
+       __le32  medium;                         // zero == 802.3
+       __le32  max_packets_per_message;
+       __le32  max_transfer_size;
+       __le32  packet_alignment;               // max 7; (1<<n) bytes
+       __le32  af_list_offset;                 // zero
+       __le32  af_list_size;                   // zero
+} __attribute__ ((packed));
+
+struct rndis_halt {            /* OUT (no reply) */
+       // header and:
+       __le32  msg_type;                       /* RNDIS_MSG_HALT */
+       __le32  msg_len;
+       __le32  request_id;
+} __attribute__ ((packed));
+
+struct rndis_query {           /* OUT */
+       // header and:
+       __le32  msg_type;                       /* RNDIS_MSG_QUERY */
+       __le32  msg_len;
+       __le32  request_id;
+       __le32  oid;
+       __le32  len;
+       __le32  offset;
+/*?*/  __le32  handle;                         // zero
+} __attribute__ ((packed));
+
+struct rndis_query_c {         /* IN */
+       // header and:
+       __le32  msg_type;                       /* RNDIS_MSG_QUERY_C */
+       __le32  msg_len;
+       __le32  request_id;
+       __le32  status;
+       __le32  len;
+       __le32  offset;
+} __attribute__ ((packed));
+
+struct rndis_set {             /* OUT */
+       // header and:
+       __le32  msg_type;                       /* RNDIS_MSG_SET */
+       __le32  msg_len;
+       __le32  request_id;
+       __le32  oid;
+       __le32  len;
+       __le32  offset;
+/*?*/  __le32  handle;                         // zero
+} __attribute__ ((packed));
+
+struct rndis_set_c {           /* IN */
+       // header and:
+       __le32  msg_type;                       /* RNDIS_MSG_SET_C */
+       __le32  msg_len;
+       __le32  request_id;
+       __le32  status;
+} __attribute__ ((packed));
+
+struct rndis_reset {           /* IN */
+       // header and:
+       __le32  msg_type;                       /* RNDIS_MSG_RESET */
+       __le32  msg_len;
+       __le32  reserved;
+} __attribute__ ((packed));
+
+struct rndis_reset_c {         /* OUT */
+       // header and:
+       __le32  msg_type;                       /* RNDIS_MSG_RESET_C */
+       __le32  msg_len;
+       __le32  status;
+       __le32  addressing_lost;
+} __attribute__ ((packed));
+
+struct rndis_indicate {                /* IN (unrequested) */
+       // header and:
+       __le32  msg_type;                       /* RNDIS_MSG_INDICATE */
+       __le32  msg_len;
+       __le32  status;
+       __le32  length;
+       __le32  offset;
+/**/   __le32  diag_status;
+       __le32  error_offset;
+/**/   __le32  message;
+} __attribute__ ((packed));
+
+struct rndis_keepalive {       /* OUT (optionally IN) */
+       // header and:
+       __le32  msg_type;                       /* RNDIS_MSG_KEEPALIVE */
+       __le32  msg_len;
+       __le32  request_id;
+} __attribute__ ((packed));
+
+struct rndis_keepalive_c {     /* IN (optionally OUT) */
+       // header and:
+       __le32  msg_type;                       /* RNDIS_MSG_KEEPALIVE_C */
+       __le32  msg_len;
+       __le32  request_id;
+       __le32  status;
+} __attribute__ ((packed));
+
+/* NOTE:  about 30 OIDs are "mandatory" for peripherals to support ... and
+ * there are gobs more that may optionally be supported.  We'll avoid as much
+ * of that mess as possible.
+ */
+#define OID_802_3_PERMANENT_ADDRESS    ccpu2(0x01010101)
+#define OID_GEN_MAXIMUM_FRAME_SIZE     ccpu2(0x00010106)
+#define OID_GEN_CURRENT_PACKET_FILTER  ccpu2(0x0001010e)
+#define OID_GEN_PHYSICAL_MEDIUM                ccpu2(0x00010202)
+
+/* packet filter bits used by OID_GEN_CURRENT_PACKET_FILTER */
+#define RNDIS_PACKET_TYPE_DIRECTED             ccpu2(0x00000001)
+#define RNDIS_PACKET_TYPE_MULTICAST            ccpu2(0x00000002)
+#define RNDIS_PACKET_TYPE_ALL_MULTICAST                ccpu2(0x00000004)
+#define RNDIS_PACKET_TYPE_BROADCAST            ccpu2(0x00000008)
+#define RNDIS_PACKET_TYPE_SOURCE_ROUTING       ccpu2(0x00000010)
+#define RNDIS_PACKET_TYPE_PROMISCUOUS          ccpu2(0x00000020)
+#define RNDIS_PACKET_TYPE_SMT                  ccpu2(0x00000040)
+#define RNDIS_PACKET_TYPE_ALL_LOCAL            ccpu2(0x00000080)
+#define RNDIS_PACKET_TYPE_GROUP                        ccpu2(0x00001000)
+#define RNDIS_PACKET_TYPE_ALL_FUNCTIONAL       ccpu2(0x00002000)
+#define RNDIS_PACKET_TYPE_FUNCTIONAL           ccpu2(0x00004000)
+#define RNDIS_PACKET_TYPE_MAC_FRAME            ccpu2(0x00008000)
+
+/* default filter used with RNDIS devices */
+#define RNDIS_DEFAULT_FILTER ( \
+       RNDIS_PACKET_TYPE_DIRECTED | \
+       RNDIS_PACKET_TYPE_BROADCAST | \
+       RNDIS_PACKET_TYPE_ALL_MULTICAST | \
+       RNDIS_PACKET_TYPE_PROMISCUOUS)
+
+/* Flags to require specific physical medium type for generic_rndis_bind() */
+#define FLAG_RNDIS_PHYM_NOT_WIRELESS   0x0001
+#define FLAG_RNDIS_PHYM_WIRELESS       0x0002
+
+
+extern void rndis_status(struct usbnet *dev, struct urb *urb);
+extern int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf);
+extern int
+generic_rndis_bind(struct usbnet *dev, struct usb_interface *intf, int flags);
+extern void rndis_unbind(struct usbnet *dev, struct usb_interface *intf);
+extern int rndis_rx_fixup(struct usbnet *dev, struct sk_buff *skb);
+extern struct sk_buff *
+rndis_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags);
+
+#endif /* __RNDIS_HOST_H */
+
index 488ce128885ceb1232bac30c2e3ec897edb50e5d..21b4a1c6f5851f9c92998694afd0171602af880b 100644 (file)
@@ -20,7 +20,8 @@
 #define SERIAL_TTY_MAJOR       188     /* Nice legal number now */
 #define SERIAL_TTY_MINORS      255     /* loads of devices :) */
 
-#define MAX_NUM_PORTS          8       /* The maximum number of ports one device can grab at once */
+/* The maximum number of ports one device can grab at once */
+#define MAX_NUM_PORTS          8
 
 /* parity check flag */
 #define RELEVANT_IFLAG(iflag)  (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
  * ports of a device.
  */
 struct usb_serial_port {
-       struct usb_serial *     serial;
-       struct tty_struct *     tty;
+       struct usb_serial       *serial;
+       struct tty_struct       *tty;
        spinlock_t              lock;
        struct mutex            mutex;
        unsigned char           number;
 
-       unsigned char *         interrupt_in_buffer;
-       struct urb *            interrupt_in_urb;
+       unsigned char           *interrupt_in_buffer;
+       struct urb              *interrupt_in_urb;
        __u8                    interrupt_in_endpointAddress;
 
-       unsigned char *         interrupt_out_buffer;
+       unsigned char           *interrupt_out_buffer;
        int                     interrupt_out_size;
-       struct urb *            interrupt_out_urb;
+       struct urb              *interrupt_out_urb;
        __u8                    interrupt_out_endpointAddress;
 
-       unsigned char *         bulk_in_buffer;
+       unsigned char           *bulk_in_buffer;
        int                     bulk_in_size;
-       struct urb *            read_urb;
+       struct urb              *read_urb;
        __u8                    bulk_in_endpointAddress;
 
-       unsigned char *         bulk_out_buffer;
+       unsigned char           *bulk_out_buffer;
        int                     bulk_out_size;
-       struct urb *            write_urb;
+       struct urb              *write_urb;
        int                     write_urb_busy;
        __u8                    bulk_out_endpointAddress;
 
@@ -92,17 +93,19 @@ struct usb_serial_port {
        int                     open_count;
        char                    throttled;
        char                    throttle_req;
+       char                    console;
        struct device           dev;
 };
 #define to_usb_serial_port(d) container_of(d, struct usb_serial_port, dev)
 
 /* get and set the port private data pointer helper functions */
-static inline void *usb_get_serial_port_data (struct usb_serial_port *port)
+static inline void *usb_get_serial_port_data(struct usb_serial_port *port)
 {
        return dev_get_drvdata(&port->dev);
 }
 
-static inline void usb_set_serial_port_data (struct usb_serial_port *port, void *data)
+static inline void usb_set_serial_port_data(struct usb_serial_port *port,
+                                           void *data)
 {
        dev_set_drvdata(&port->dev, data);
 }
@@ -125,9 +128,10 @@ static inline void usb_set_serial_port_data (struct usb_serial_port *port, void
  *     usb_set_serial_data() to access this.
  */
 struct usb_serial {
-       struct usb_device *             dev;
-       struct usb_serial_driver *      type;
-       struct usb_interface *          interface;
+       struct usb_device               *dev;
+       struct usb_serial_driver        *type;
+       struct usb_interface            *interface;
+       unsigned char                   disconnected;
        unsigned char                   minor;
        unsigned char                   num_ports;
        unsigned char                   num_port_pointers;
@@ -135,29 +139,30 @@ struct usb_serial {
        char                            num_interrupt_out;
        char                            num_bulk_in;
        char                            num_bulk_out;
-       struct usb_serial_port *        port[MAX_NUM_PORTS];
+       struct usb_serial_port          *port[MAX_NUM_PORTS];
        struct kref                     kref;
-       void *                          private;
+       struct mutex                    disc_mutex;
+       void                            *private;
 };
 #define to_usb_serial(d) container_of(d, struct usb_serial, kref)
 
 #define NUM_DONT_CARE  99
 
 /* get and set the serial private data pointer helper functions */
-static inline void *usb_get_serial_data (struct usb_serial *serial)
+static inline void *usb_get_serial_data(struct usb_serial *serial)
 {
        return serial->private;
 }
 
-static inline void usb_set_serial_data (struct usb_serial *serial, void *data)
+static inline void usb_set_serial_data(struct usb_serial *serial, void *data)
 {
        serial->private = data;
 }
 
 /**
  * usb_serial_driver - describes a usb serial driver
- * @description: pointer to a string that describes this driver.  This string used
- *     in the syslog messages when a device is inserted or removed.
+ * @description: pointer to a string that describes this driver.  This string
+ *     used in the syslog messages when a device is inserted or removed.
  * @id_table: pointer to a list of usb_device_id structures that define all
  *     of the devices this structure can support.
  * @num_interrupt_in: If a device doesn't have this many interrupt-in
@@ -218,82 +223,91 @@ struct usb_serial_driver {
        struct usb_driver       *usb_driver;
        struct usb_dynids       dynids;
 
-       int (*probe) (struct usb_serial *serial, const struct usb_device_id *id);
-       int (*attach) (struct usb_serial *serial);
+       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 (*shutdown)(struct usb_serial *serial);
 
-       int (*port_probe) (struct usb_serial_port *port);
-       int (*port_remove) (struct usb_serial_port *port);
+       int (*port_probe)(struct usb_serial_port *port);
+       int (*port_remove)(struct usb_serial_port *port);
 
-       int (*suspend) (struct usb_serial *serial, pm_message_t message);
-       int (*resume) (struct usb_serial *serial);
+       int (*suspend)(struct usb_serial *serial, pm_message_t message);
+       int (*resume)(struct usb_serial *serial);
 
        /* serial function calls */
-       int  (*open)            (struct usb_serial_port *port, struct file * filp);
-       void (*close)           (struct usb_serial_port *port, struct file * filp);
-       int  (*write)           (struct usb_serial_port *port, const unsigned char *buf, int count);
-       int  (*write_room)      (struct usb_serial_port *port);
-       int  (*ioctl)           (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg);
-       void (*set_termios)     (struct usb_serial_port *port, struct ktermios * old);
-       void (*break_ctl)       (struct usb_serial_port *port, int break_state);
-       int  (*chars_in_buffer) (struct usb_serial_port *port);
-       void (*throttle)        (struct usb_serial_port *port);
-       void (*unthrottle)      (struct usb_serial_port *port);
-       int  (*tiocmget)        (struct usb_serial_port *port, struct file *file);
-       int  (*tiocmset)        (struct usb_serial_port *port, struct file *file, unsigned int set, unsigned int clear);
+       int  (*open)(struct usb_serial_port *port, struct file *filp);
+       void (*close)(struct usb_serial_port *port, struct file *filp);
+       int  (*write)(struct usb_serial_port *port, const unsigned char *buf,
+                     int count);
+       int  (*write_room)(struct usb_serial_port *port);
+       int  (*ioctl)(struct usb_serial_port *port, struct file *file,
+                     unsigned int cmd, unsigned long arg);
+       void (*set_termios)(struct usb_serial_port *port, struct ktermios *old);
+       void (*break_ctl)(struct usb_serial_port *port, int break_state);
+       int  (*chars_in_buffer)(struct usb_serial_port *port);
+       void (*throttle)(struct usb_serial_port *port);
+       void (*unthrottle)(struct usb_serial_port *port);
+       int  (*tiocmget)(struct usb_serial_port *port, struct file *file);
+       int  (*tiocmset)(struct usb_serial_port *port, struct file *file,
+                        unsigned int set, unsigned int clear);
 
        void (*read_int_callback)(struct urb *urb);
        void (*write_int_callback)(struct urb *urb);
        void (*read_bulk_callback)(struct urb *urb);
        void (*write_bulk_callback)(struct urb *urb);
 };
-#define to_usb_serial_driver(d) container_of(d, struct usb_serial_driver, driver)
+#define to_usb_serial_driver(d) \
+       container_of(d, struct usb_serial_driver, driver)
 
 extern int  usb_serial_register(struct usb_serial_driver *driver);
 extern void usb_serial_deregister(struct usb_serial_driver *driver);
 extern void usb_serial_port_softint(struct usb_serial_port *port);
 
-extern int usb_serial_probe(struct usb_interface *iface, const struct usb_device_id *id);
+extern int usb_serial_probe(struct usb_interface *iface,
+                           const struct usb_device_id *id);
 extern void usb_serial_disconnect(struct usb_interface *iface);
 
 extern int usb_serial_suspend(struct usb_interface *intf, pm_message_t message);
 extern int usb_serial_resume(struct usb_interface *intf);
 
-extern int ezusb_writememory (struct usb_serial *serial, int address, unsigned char *data, int length, __u8 bRequest);
-extern int ezusb_set_reset (struct usb_serial *serial, unsigned char reset_bit);
+extern int ezusb_writememory(struct usb_serial *serial, int address,
+                            unsigned char *data, int length, __u8 bRequest);
+extern int ezusb_set_reset(struct usb_serial *serial, unsigned char reset_bit);
 
 /* USB Serial console functions */
 #ifdef CONFIG_USB_SERIAL_CONSOLE
-extern void usb_serial_console_init (int debug, int minor);
-extern void usb_serial_console_exit (void);
+extern void usb_serial_console_init(int debug, int minor);
+extern void usb_serial_console_exit(void);
 extern void usb_serial_console_disconnect(struct usb_serial *serial);
 #else
-static inline void usb_serial_console_init (int debug, int minor) { }
-static inline void usb_serial_console_exit (void) { }
+static inline void usb_serial_console_init(int debug, int minor) { }
+static inline void usb_serial_console_exit(void) { }
 static inline void usb_serial_console_disconnect(struct usb_serial *serial) {}
 #endif
 
 /* Functions needed by other parts of the usbserial core */
-extern struct usb_serial *usb_serial_get_by_index (unsigned int minor);
+extern struct usb_serial *usb_serial_get_by_index(unsigned int minor);
 extern void usb_serial_put(struct usb_serial *serial);
-extern int usb_serial_generic_open (struct usb_serial_port *port, struct file *filp);
-extern int usb_serial_generic_write (struct usb_serial_port *port, const unsigned char *buf, int count);
-extern void usb_serial_generic_close (struct usb_serial_port *port, struct file *filp);
-extern int usb_serial_generic_resume (struct usb_serial *serial);
-extern int usb_serial_generic_write_room (struct usb_serial_port *port);
-extern int usb_serial_generic_chars_in_buffer (struct usb_serial_port *port);
-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 usb_serial_port *port);
-extern void usb_serial_generic_unthrottle (struct usb_serial_port *port);
-extern void usb_serial_generic_shutdown (struct usb_serial *serial);
-extern int usb_serial_generic_register (int debug);
-extern void usb_serial_generic_deregister (void);
-
-extern int usb_serial_bus_register (struct usb_serial_driver *device);
-extern void usb_serial_bus_deregister (struct usb_serial_driver *device);
+extern int usb_serial_generic_open(struct usb_serial_port *port,
+                                  struct file *filp);
+extern int usb_serial_generic_write(struct usb_serial_port *port,
+                                   const unsigned char *buf, int count);
+extern void usb_serial_generic_close(struct usb_serial_port *port,
+                                    struct file *filp);
+extern int usb_serial_generic_resume(struct usb_serial *serial);
+extern int usb_serial_generic_write_room(struct usb_serial_port *port);
+extern int usb_serial_generic_chars_in_buffer(struct usb_serial_port *port);
+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 usb_serial_port *port);
+extern void usb_serial_generic_unthrottle(struct usb_serial_port *port);
+extern void usb_serial_generic_shutdown(struct usb_serial *serial);
+extern int usb_serial_generic_register(int debug);
+extern void usb_serial_generic_deregister(void);
+
+extern int usb_serial_bus_register(struct usb_serial_driver *device);
+extern void usb_serial_bus_deregister(struct usb_serial_driver *device);
 
 extern struct usb_serial_driver usb_serial_generic_device;
 extern struct bus_type usb_serial_bus_type;
@@ -307,16 +321,22 @@ static inline void usb_serial_debug_data(int debug,
        int i;
 
        if (debug) {
-               dev_printk(KERN_DEBUG, dev, "%s - length = %d, data = ", function, size);
+               dev_printk(KERN_DEBUG, dev, "%s - length = %d, data = ",
+                          function, size);
                for (i = 0; i < size; ++i)
-                       printk ("%.2x ", data[i]);
-               printk ("\n");
+                       printk("%.2x ", data[i]);
+               printk("\n");
        }
 }
 
 /* Use our own dbg macro */
 #undef dbg
-#define dbg(format, arg...) do { if (debug) printk(KERN_DEBUG "%s: " format "\n" , __FILE__ , ## arg); } while (0)
+#define dbg(format, arg...) \
+       do { \
+               if (debug) \
+                       printk(KERN_DEBUG "%s: " format "\n" , __FILE__ , \
+                               ## arg); \
+       } while (0)
 
 
 
index 397ee3b3d7f357ff5d2d665491c12a28f478d909..877373da410dcd0520cae0babe731188351fc637 100644 (file)
@@ -19,8 +19,8 @@ struct sl811_platform_data {
        /* pulse sl811 nRST (probably with a GPIO) */
        void            (*reset)(struct device *dev);
 
-       // some boards need something like these:
-       // int          (*check_overcurrent)(struct device *dev);
-       // void         (*clock_enable)(struct device *dev, int is_on);
+       /* some boards need something like these: */
+       /* int          (*check_overcurrent)(struct device *dev); */
+       /* void         (*clock_enable)(struct device *dev, int is_on); */
 };
 
similarity index 93%
rename from drivers/net/usb/usbnet.h
rename to include/linux/usb/usbnet.h
index 1fae4347e8316eef06f8e9319f618e413f51e32b..e0501da3dd115024b9b31b8d1f0d0bd139b3f19d 100644 (file)
@@ -31,6 +31,7 @@ struct usbnet {
        struct usb_interface    *intf;
        struct driver_info      *driver_info;
        const char              *driver_name;
+       void                    *driver_priv;
        wait_queue_head_t       *wait;
        struct mutex            phy_mutex;
        unsigned char           suspend_count;
@@ -87,6 +88,8 @@ struct driver_info {
 #define FLAG_ETHER     0x0020          /* maybe use "eth%d" names */
 
 #define FLAG_FRAMING_AX 0x0040         /* AX88772/178 packets */
+#define FLAG_WLAN      0x0080          /* use "wlan%d" names */
+
 
        /* init device ... can sleep, or cause probe() failure */
        int     (*bind)(struct usbnet *, struct usb_interface *);
@@ -113,6 +116,15 @@ struct driver_info {
        struct sk_buff  *(*tx_fixup)(struct usbnet *dev,
                                struct sk_buff *skb, gfp_t flags);
 
+       /* early initialization code, can sleep. This is for minidrivers
+        * having 'subminidrivers' that need to do extra initialization
+        * right after minidriver have initialized hardware. */
+       int     (*early_init)(struct usbnet *dev);
+
+       /* called by minidriver when link state changes, state: 0=disconnect,
+        * 1=connect */
+       void    (*link_change)(struct usbnet *dev, int state);
+
        /* for new devices, use the descriptor-reading code instead */
        int             in;             /* rx endpoint */
        int             out;            /* tx endpoint */
index a417b09b8b3db53875a1bd93936448aaf52be018..cee0623b3c7be52b17b2a47b5208b3528f13cf18 100644 (file)
@@ -80,10 +80,9 @@ enum { US_DO_ALL_FLAGS };
 #define US_SC_UFI      0x04            /* Floppy */
 #define US_SC_8070     0x05            /* Removable media */
 #define US_SC_SCSI     0x06            /* Transparent */
-#define US_SC_ISD200    0x07           /* ISD200 ATA */
-#define US_SC_MIN      US_SC_RBC
-#define US_SC_MAX      US_SC_ISD200
+#define US_SC_LOCKABLE 0x07            /* Password-protected */
 
+#define US_SC_ISD200    0xf0           /* ISD200 ATA */
 #define US_SC_DEVICE   0xff            /* Use device's value */
 
 /* Protocols */
index 8ca5a7fbc9ecaf38d8baefa7da3618aadd628828..17cb108b7db038558ef4e49337503c1217d8592a 100644 (file)
@@ -104,7 +104,7 @@ struct usbdevfs_urb {
        int error_count;
        unsigned int signr;     /* signal to be sent on completion,
                                  or 0 if none should be sent. */
-       void *usercontext;
+       void __user *usercontext;
        struct usbdevfs_iso_packet_desc iso_frame_desc[0];
 };
 
index 14e1379876d334f9bb99d04d43750c571c967528..260d1fcf29a4222c011ab39176b1e2e4d46a98a3 100644 (file)
 /**
  * virtqueue - a queue to register buffers for sending or receiving.
  * @callback: the function to call when buffers are consumed (can be NULL).
- *    If this returns false, callbacks are suppressed until vq_ops->restart
- *    is called.
  * @vdev: the virtio device this queue was created for.
  * @vq_ops: the operations for this virtqueue (see below).
  * @priv: a pointer for the virtqueue implementation to use.
  */
 struct virtqueue
 {
-       bool (*callback)(struct virtqueue *vq);
+       void (*callback)(struct virtqueue *vq);
        struct virtio_device *vdev;
        struct virtqueue_ops *vq_ops;
        void *priv;
@@ -41,13 +39,12 @@ struct virtqueue
  *     vq: the struct virtqueue we're talking about.
  *     len: the length written into the buffer
  *     Returns NULL or the "data" token handed to add_buf.
- * @restart: restart callbacks after callback returned false.
+ * @disable_cb: disable callbacks
+ *     vq: the struct virtqueue we're talking about.
+ * @enable_cb: restart callbacks after disable_cb.
  *     vq: the struct virtqueue we're talking about.
  *     This returns "false" (and doesn't re-enable) if there are pending
  *     buffers in the queue, to avoid a race.
- * @shutdown: "unadd" all buffers.
- *     vq: the struct virtqueue we're talking about.
- *     Remove everything from the queue.
  *
  * Locking rules are straightforward: the driver is responsible for
  * locking.  No two operations may be invoked simultaneously.
@@ -65,9 +62,8 @@ struct virtqueue_ops {
 
        void *(*get_buf)(struct virtqueue *vq, unsigned int *len);
 
-       bool (*restart)(struct virtqueue *vq);
-
-       void (*shutdown)(struct virtqueue *vq);
+       void (*disable_cb)(struct virtqueue *vq);
+       bool (*enable_cb)(struct virtqueue *vq);
 };
 
 /**
@@ -97,12 +93,15 @@ void unregister_virtio_device(struct virtio_device *dev);
  * @probe: the function to call when a device is found.  Returns a token for
  *    remove, or PTR_ERR().
  * @remove: the function when a device is removed.
+ * @config_changed: optional function to call when the device configuration
+ *    changes; may be called in interrupt context.
  */
 struct virtio_driver {
        struct device_driver driver;
        const struct virtio_device_id *id_table;
        int (*probe)(struct virtio_device *dev);
        void (*remove)(struct virtio_device *dev);
+       void (*config_changed)(struct virtio_device *dev);
 };
 
 int register_virtio_driver(struct virtio_driver *drv);
diff --git a/include/linux/virtio_balloon.h b/include/linux/virtio_balloon.h
new file mode 100644 (file)
index 0000000..979524e
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef _LINUX_VIRTIO_BALLOON_H
+#define _LINUX_VIRTIO_BALLOON_H
+#include <linux/virtio_config.h>
+
+/* The ID for virtio_balloon */
+#define VIRTIO_ID_BALLOON      5
+
+/* The feature bitmap for virtio balloon */
+#define VIRTIO_BALLOON_F_MUST_TELL_HOST        0 /* Tell before reclaiming pages */
+
+struct virtio_balloon_config
+{
+       /* Number of pages host wants Guest to give up. */
+       __le32 num_pages;
+       /* Number of pages we've actually got in balloon. */
+       __le32 actual;
+};
+#endif /* _LINUX_VIRTIO_BALLOON_H */
index 7bd2bce0cfd964f2c4c5fe5bffa72977bc37fd2b..bca0b10d79470056cc6456101ef45454f813149f 100644 (file)
@@ -6,15 +6,19 @@
 #define VIRTIO_ID_BLOCK        2
 
 /* Feature bits */
-#define VIRTIO_CONFIG_BLK_F    0x40
-#define VIRTIO_BLK_F_BARRIER   1       /* Does host support barriers? */
+#define VIRTIO_BLK_F_BARRIER   0       /* Does host support barriers? */
+#define VIRTIO_BLK_F_SIZE_MAX  1       /* Indicates maximum segment size */
+#define VIRTIO_BLK_F_SEG_MAX   2       /* Indicates maximum # of segments */
 
-/* The capacity (in 512-byte sectors). */
-#define VIRTIO_CONFIG_BLK_F_CAPACITY   0x41
-/* The maximum segment size. */
-#define VIRTIO_CONFIG_BLK_F_SIZE_MAX   0x42
-/* The maximum number of segments. */
-#define VIRTIO_CONFIG_BLK_F_SEG_MAX    0x43
+struct virtio_blk_config
+{
+       /* The capacity (in 512-byte sectors). */
+       __le64 capacity;
+       /* The maximum segment size (if VIRTIO_BLK_F_SIZE_MAX) */
+       __le32 size_max;
+       /* The maximum number of segments (if VIRTIO_BLK_F_SEG_MAX) */
+       __le32 seg_max;
+} __attribute__((packed));
 
 /* These two define direction. */
 #define VIRTIO_BLK_T_IN                0
@@ -35,8 +39,6 @@ struct virtio_blk_outhdr
        __u32 ioprio;
        /* Sector (ie. 512 byte offset) */
        __u64 sector;
-       /* Where to put reply. */
-       __u64 id;
 };
 
 #define VIRTIO_BLK_S_OK                0
index bcc01888df78d52e19592a92bd8861b0f1f5f9c9..d581b2914b342cbbe83744bc15762fb8718a81a3 100644 (file)
@@ -5,7 +5,7 @@
  * store and access that space differently. */
 #include <linux/types.h>
 
-/* Status byte for guest to report progress, and synchronize config. */
+/* Status byte for guest to report progress, and synchronize features. */
 /* We have seen device and processed generic fields (VIRTIO_CONFIG_F_VIRTIO) */
 #define VIRTIO_CONFIG_S_ACKNOWLEDGE    1
 /* We have found a driver for the device. */
 /* We've given up on this device. */
 #define VIRTIO_CONFIG_S_FAILED         0x80
 
-/* Feature byte (actually 7 bits availabe): */
-/* Requirements/features of the virtio implementation. */
-#define VIRTIO_CONFIG_F_VIRTIO 1
-/* Requirements/features of the virtqueue (may have more than one). */
-#define VIRTIO_CONFIG_F_VIRTQUEUE 2
-
 #ifdef __KERNEL__
 struct virtio_device;
 
 /**
  * virtio_config_ops - operations for configuring a virtio device
- * @find: search for the next configuration field of the given type.
+ * @feature: search for a feature in this config
  *     vdev: the virtio_device
- *     type: the feature type
- *     len: the (returned) length of the field if found.
- *     Returns a token if found, or NULL.  Never returnes the same field twice
- *     (ie. it's used up).
- * @get: read the value of a configuration field after find().
+ *     bit: the feature bit
+ *     Returns true if the feature is supported.  Acknowledges the feature
+ *     so the host can see it.
+ * @get: read the value of a configuration field
  *     vdev: the virtio_device
- *     token: the token returned from find().
+ *     offset: the offset of the configuration field
  *     buf: the buffer to write the field value into.
- *     len: the length of the buffer (given by find()).
+ *     len: the length of the buffer
  *     Note that contents are conventionally little-endian.
- * @set: write the value of a configuration field after find().
+ * @set: write the value of a configuration field
  *     vdev: the virtio_device
- *     token: the token returned from find().
+ *     offset: the offset of the configuration field
  *     buf: the buffer to read the field value from.
- *     len: the length of the buffer (given by find()).
+ *     len: the length of the buffer
  *     Note that contents are conventionally little-endian.
  * @get_status: read the status byte
  *     vdev: the virtio_device
@@ -50,62 +43,67 @@ struct virtio_device;
  * @set_status: write the status byte
  *     vdev: the virtio_device
  *     status: the new status byte
- * @find_vq: find the first VIRTIO_CONFIG_F_VIRTQUEUE and create a virtqueue.
+ * @reset: reset the device
+ *     vdev: the virtio device
+ *     After this, status and feature negotiation must be done again
+ * @find_vq: find a virtqueue and instantiate it.
  *     vdev: the virtio_device
+ *     index: the 0-based virtqueue number in case there's more than one.
  *     callback: the virqtueue callback
- *     Returns the new virtqueue or ERR_PTR().
+ *     Returns the new virtqueue or ERR_PTR() (eg. -ENOENT).
  * @del_vq: free a virtqueue found by find_vq().
  */
 struct virtio_config_ops
 {
-       void *(*find)(struct virtio_device *vdev, u8 type, unsigned *len);
-       void (*get)(struct virtio_device *vdev, void *token,
+       bool (*feature)(struct virtio_device *vdev, unsigned bit);
+       void (*get)(struct virtio_device *vdev, unsigned offset,
                    void *buf, unsigned len);
-       void (*set)(struct virtio_device *vdev, void *token,
+       void (*set)(struct virtio_device *vdev, unsigned offset,
                    const void *buf, unsigned len);
        u8 (*get_status)(struct virtio_device *vdev);
        void (*set_status)(struct virtio_device *vdev, u8 status);
+       void (*reset)(struct virtio_device *vdev);
        struct virtqueue *(*find_vq)(struct virtio_device *vdev,
-                                    bool (*callback)(struct virtqueue *));
+                                    unsigned index,
+                                    void (*callback)(struct virtqueue *));
        void (*del_vq)(struct virtqueue *vq);
 };
 
 /**
- * virtio_config_val - get a single virtio config and mark it used.
- * @config: the virtio config space
- * @type: the type to search for.
+ * virtio_config_val - look for a feature and get a single virtio config.
+ * @vdev: the virtio device
+ * @fbit: the feature bit
+ * @offset: the type to search for.
  * @val: a pointer to the value to fill in.
  *
- * Once used, the config type is marked with VIRTIO_CONFIG_F_USED so it can't
- * be found again.  This version does endian conversion. */
-#define virtio_config_val(vdev, type, v) ({                            \
-       int _err = __virtio_config_val((vdev),(type),(v),sizeof(*(v))); \
-                                                                       \
-       BUILD_BUG_ON(sizeof(*(v)) != 1 && sizeof(*(v)) != 2             \
-                    && sizeof(*(v)) != 4 && sizeof(*(v)) != 8);        \
-       if (!_err) {                                                    \
-               switch (sizeof(*(v))) {                                 \
-               case 2: le16_to_cpus((__u16 *) v); break;               \
-               case 4: le32_to_cpus((__u32 *) v); break;               \
-               case 8: le64_to_cpus((__u64 *) v); break;               \
-               }                                                       \
-       }                                                               \
+ * The return value is -ENOENT if the feature doesn't exist.  Otherwise
+ * the value is endian-corrected and returned in v. */
+#define virtio_config_val(vdev, fbit, offset, v) ({                    \
+       int _err;                                                       \
+       if ((vdev)->config->feature((vdev), (fbit))) {                  \
+               __virtio_config_val((vdev), (offset), (v));             \
+               _err = 0;                                               \
+       } else                                                          \
+               _err = -ENOENT;                                         \
        _err;                                                           \
 })
 
-int __virtio_config_val(struct virtio_device *dev,
-                       u8 type, void *val, size_t size);
-
 /**
- * virtio_use_bit - helper to use a feature bit in a bitfield value.
- * @dev: the virtio device
- * @token: the token as returned from vdev->config->find().
- * @len: the length of the field.
- * @bitnum: the bit to test.
+ * __virtio_config_val - get a single virtio config without feature check.
+ * @vdev: the virtio device
+ * @offset: the type to search for.
+ * @val: a pointer to the value to fill in.
  *
- * If handed a NULL token, it returns false, otherwise returns bit status.
- * If it's one, it sets the mirroring acknowledgement bit. */
-int virtio_use_bit(struct virtio_device *vdev,
-                  void *token, unsigned int len, unsigned int bitnum);
+ * The value is endian-corrected and returned in v. */
+#define __virtio_config_val(vdev, offset, v) do {                      \
+       BUILD_BUG_ON(sizeof(*(v)) != 1 && sizeof(*(v)) != 2             \
+                    && sizeof(*(v)) != 4 && sizeof(*(v)) != 8);        \
+       (vdev)->config->get((vdev), (offset), (v), sizeof(*(v)));       \
+       switch (sizeof(*(v))) {                                         \
+       case 2: le16_to_cpus((__u16 *) v); break;                       \
+       case 4: le32_to_cpus((__u32 *) v); break;                       \
+       case 8: le64_to_cpus((__u64 *) v); break;                       \
+       }                                                               \
+} while(0)
 #endif /* __KERNEL__ */
 #endif /* _LINUX_VIRTIO_CONFIG_H */
index ae469ae55d3662fe80c198fea895e68c6890e204..1ea3351df609474d097b67e4f0df31131257a34f 100644 (file)
@@ -5,32 +5,32 @@
 /* The ID for virtio_net */
 #define VIRTIO_ID_NET  1
 
-/* The bitmap of config for virtio net */
-#define VIRTIO_CONFIG_NET_F    0x40
-#define VIRTIO_NET_F_NO_CSUM   0
-#define VIRTIO_NET_F_TSO4      1
-#define VIRTIO_NET_F_UFO       2
-#define VIRTIO_NET_F_TSO4_ECN  3
-#define VIRTIO_NET_F_TSO6      4
+/* The feature bitmap for virtio net */
+#define VIRTIO_NET_F_CSUM      0       /* Can handle pkts w/ partial csum */
+#define VIRTIO_NET_F_MAC       5       /* Host has given MAC address. */
+#define VIRTIO_NET_F_GSO       6       /* Can handle pkts w/ any GSO type */
 
-/* The config defining mac address. */
-#define VIRTIO_CONFIG_NET_MAC_F        0x41
+struct virtio_net_config
+{
+       /* The config defining mac address (if VIRTIO_NET_F_MAC) */
+       __u8 mac[6];
+} __attribute__((packed));
 
 /* This is the first element of the scatter-gather list.  If you don't
  * specify GSO or CSUM features, you can simply ignore the header. */
 struct virtio_net_hdr
 {
 #define VIRTIO_NET_HDR_F_NEEDS_CSUM    1       // Use csum_start, csum_offset
-      __u8 flags;
+       __u8 flags;
 #define VIRTIO_NET_HDR_GSO_NONE                0       // Not a GSO frame
 #define VIRTIO_NET_HDR_GSO_TCPV4       1       // GSO frame, IPv4 TCP (TSO)
-/* FIXME: Do we need this?  If they said they can handle ECN, do they care? */
-#define VIRTIO_NET_HDR_GSO_TCPV4_ECN   2       // GSO frame, IPv4 TCP w/ ECN
 #define VIRTIO_NET_HDR_GSO_UDP         3       // GSO frame, IPv4 UDP (UFO)
 #define VIRTIO_NET_HDR_GSO_TCPV6       4       // GSO frame, IPv6 TCP
-      __u8 gso_type;
-      __u16 gso_size;
-      __u16 csum_start;
-      __u16 csum_offset;
+#define VIRTIO_NET_HDR_GSO_ECN         0x80    // TCP has ECN set
+       __u8 gso_type;
+       __u16 hdr_len;          /* Ethernet + IP + tcp/udp hdrs */
+       __u16 gso_size;         /* Bytes to append to gso_hdr_len per frame */
+       __u16 csum_start;       /* Position to start checksumming from */
+       __u16 csum_offset;      /* Offset after that to place checksum */
 };
 #endif /* _LINUX_VIRTIO_NET_H */
diff --git a/include/linux/virtio_pci.h b/include/linux/virtio_pci.h
new file mode 100644 (file)
index 0000000..b315165
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Virtio PCI driver
+ *
+ * This module allows virtio devices to be used over a virtual PCI device.
+ * This can be used with QEMU based VMMs like KVM or Xen.
+ *
+ * Copyright IBM Corp. 2007
+ *
+ * Authors:
+ *  Anthony Liguori  <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#ifndef _LINUX_VIRTIO_PCI_H
+#define _LINUX_VIRTIO_PCI_H
+
+#include <linux/virtio_config.h>
+
+/* A 32-bit r/o bitmask of the features supported by the host */
+#define VIRTIO_PCI_HOST_FEATURES       0
+
+/* A 32-bit r/w bitmask of features activated by the guest */
+#define VIRTIO_PCI_GUEST_FEATURES      4
+
+/* A 32-bit r/w PFN for the currently selected queue */
+#define VIRTIO_PCI_QUEUE_PFN           8
+
+/* A 16-bit r/o queue size for the currently selected queue */
+#define VIRTIO_PCI_QUEUE_NUM           12
+
+/* A 16-bit r/w queue selector */
+#define VIRTIO_PCI_QUEUE_SEL           14
+
+/* A 16-bit r/w queue notifier */
+#define VIRTIO_PCI_QUEUE_NOTIFY                16
+
+/* An 8-bit device status register.  */
+#define VIRTIO_PCI_STATUS              18
+
+/* An 8-bit r/o interrupt status register.  Reading the value will return the
+ * current contents of the ISR and will also clear it.  This is effectively
+ * a read-and-acknowledge. */
+#define VIRTIO_PCI_ISR                 19
+
+/* The bit of the ISR which indicates a device configuration change. */
+#define VIRTIO_PCI_ISR_CONFIG          0x2
+
+/* The remaining space is defined by each driver as the per-driver
+ * configuration space */
+#define VIRTIO_PCI_CONFIG              20
+
+/* Virtio ABI version, this must match exactly */
+#define VIRTIO_PCI_ABI_VERSION         0
+#endif
index 1a4ed49f64780cc553a1ac3f6dcca0f2065972ff..abe481ed990e328bd6f5ec1f5212deeed07b9fea 100644 (file)
 /* This marks a buffer as write-only (otherwise read-only). */
 #define VRING_DESC_F_WRITE     2
 
-/* This means don't notify other side when buffer added. */
+/* The Host uses this in used->flags to advise the Guest: don't kick me when
+ * you add a buffer.  It's unreliable, so it's simply an optimization.  Guest
+ * will still kick if it's out of buffers. */
 #define VRING_USED_F_NO_NOTIFY 1
-/* This means don't interrupt guest when buffer consumed. */
+/* The Guest uses this in avail->flags to advise the Host: don't interrupt me
+ * when you consume a buffer.  It's unreliable, so it's simply an
+ * optimization.  */
 #define VRING_AVAIL_F_NO_INTERRUPT     1
 
 /* Virtio ring descriptors: 16 bytes.  These can chain together via "next". */
@@ -89,7 +93,7 @@ struct vring {
  * };
  */
 static inline void vring_init(struct vring *vr, unsigned int num, void *p,
-                             unsigned int pagesize)
+                             unsigned long pagesize)
 {
        vr->num = num;
        vr->desc = p;
@@ -98,7 +102,7 @@ static inline void vring_init(struct vring *vr, unsigned int num, void *p,
                            & ~(pagesize - 1));
 }
 
-static inline unsigned vring_size(unsigned int num, unsigned int pagesize)
+static inline unsigned vring_size(unsigned int num, unsigned long pagesize)
 {
        return ((sizeof(struct vring_desc) * num + sizeof(__u16) * (2 + num)
                 + pagesize - 1) & ~(pagesize - 1))
@@ -114,7 +118,7 @@ struct virtqueue *vring_new_virtqueue(unsigned int num,
                                      struct virtio_device *vdev,
                                      void *pages,
                                      void (*notify)(struct virtqueue *vq),
-                                     bool (*callback)(struct virtqueue *vq));
+                                     void (*callback)(struct virtqueue *vq));
 void vring_del_virtqueue(struct virtqueue *vq);
 
 irqreturn_t vring_interrupt(int irq, void *_vq);
index 89338b468d0de9c90d857e7e6154ecebcd3bc598..ce8e7da05807b7e69f0967b6c78620a4c202d6b7 100644 (file)
@@ -45,11 +45,11 @@ extern void *vmalloc_32_user(unsigned long size);
 extern void *__vmalloc(unsigned long size, gfp_t gfp_mask, pgprot_t prot);
 extern void *__vmalloc_area(struct vm_struct *area, gfp_t gfp_mask,
                                pgprot_t prot);
-extern void vfree(void *addr);
+extern void vfree(const void *addr);
 
 extern void *vmap(struct page **pages, unsigned int count,
                        unsigned long flags, pgprot_t prot);
-extern void vunmap(void *addr);
+extern void vunmap(const void *addr);
 
 extern int remap_vmalloc_range(struct vm_area_struct *vma, void *addr,
                                                        unsigned long pgoff);
@@ -71,7 +71,7 @@ extern struct vm_struct *__get_vm_area(unsigned long size, unsigned long flags,
 extern struct vm_struct *get_vm_area_node(unsigned long size,
                                          unsigned long flags, int node,
                                          gfp_t gfp_mask);
-extern struct vm_struct *remove_vm_area(void *addr);
+extern struct vm_struct *remove_vm_area(const void *addr);
 
 extern int map_vm_area(struct vm_struct *area, pgprot_t prot,
                        struct page ***pages);
index 0e686280450b3808eb2bbda7124772896b879ac7..33a2aa9e02f2ba93f9bad51a351dd30919251a7a 100644 (file)
@@ -152,14 +152,31 @@ int FASTCALL(out_of_line_wait_on_bit(void *, int, int (*)(void *), unsigned));
 int FASTCALL(out_of_line_wait_on_bit_lock(void *, int, int (*)(void *), unsigned));
 wait_queue_head_t *FASTCALL(bit_waitqueue(void *, int));
 
-#define wake_up(x)                     __wake_up(x, TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE, 1, NULL)
-#define wake_up_nr(x, nr)              __wake_up(x, TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE, nr, NULL)
-#define wake_up_all(x)                 __wake_up(x, TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE, 0, NULL)
+#define wake_up(x)                     __wake_up(x, TASK_NORMAL, 1, NULL)
+#define wake_up_nr(x, nr)              __wake_up(x, TASK_NORMAL, nr, NULL)
+#define wake_up_all(x)                 __wake_up(x, TASK_NORMAL, 0, NULL)
+#define wake_up_locked(x)              __wake_up_locked((x), TASK_NORMAL)
+
 #define wake_up_interruptible(x)       __wake_up(x, TASK_INTERRUPTIBLE, 1, NULL)
 #define wake_up_interruptible_nr(x, nr)        __wake_up(x, TASK_INTERRUPTIBLE, nr, NULL)
 #define wake_up_interruptible_all(x)   __wake_up(x, TASK_INTERRUPTIBLE, 0, NULL)
-#define        wake_up_locked(x)               __wake_up_locked((x), TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE)
-#define wake_up_interruptible_sync(x)   __wake_up_sync((x),TASK_INTERRUPTIBLE, 1)
+#define wake_up_interruptible_sync(x)  __wake_up_sync((x), TASK_INTERRUPTIBLE, 1)
+
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+/*
+ * macro to avoid include hell
+ */
+#define wake_up_nested(x, s)                                           \
+do {                                                                   \
+       unsigned long flags;                                            \
+                                                                       \
+       spin_lock_irqsave_nested(&(x)->lock, flags, (s));               \
+       wake_up_locked(x);                                              \
+       spin_unlock_irqrestore(&(x)->lock, flags);                      \
+} while (0)
+#else
+#define wake_up_nested(x, s)           wake_up(x)
+#endif
 
 #define __wait_event(wq, condition)                                    \
 do {                                                                   \
@@ -345,6 +362,47 @@ do {                                                                       \
        __ret;                                                          \
 })
 
+#define __wait_event_killable(wq, condition, ret)                      \
+do {                                                                   \
+       DEFINE_WAIT(__wait);                                            \
+                                                                       \
+       for (;;) {                                                      \
+               prepare_to_wait(&wq, &__wait, TASK_KILLABLE);           \
+               if (condition)                                          \
+                       break;                                          \
+               if (!fatal_signal_pending(current)) {                   \
+                       schedule();                                     \
+                       continue;                                       \
+               }                                                       \
+               ret = -ERESTARTSYS;                                     \
+               break;                                                  \
+       }                                                               \
+       finish_wait(&wq, &__wait);                                      \
+} while (0)
+
+/**
+ * wait_event_killable - sleep until a condition gets true
+ * @wq: the waitqueue to wait on
+ * @condition: a C expression for the event to wait for
+ *
+ * The process is put to sleep (TASK_KILLABLE) until the
+ * @condition evaluates to true or a signal is received.
+ * The @condition is checked each time the waitqueue @wq is woken up.
+ *
+ * wake_up() has to be called after changing any variable that could
+ * change the result of the wait condition.
+ *
+ * The function will return -ERESTARTSYS if it was interrupted by a
+ * signal and 0 if @condition evaluated to true.
+ */
+#define wait_event_killable(wq, condition)                             \
+({                                                                     \
+       int __ret = 0;                                                  \
+       if (!(condition))                                               \
+               __wait_event_killable(wq, condition, __ret);            \
+       __ret;                                                          \
+})
+
 /*
  * Must be called with the spinlock in the wait_queue_head_t held.
  */
index 74e84caa1e208ba529729597bf8a66612d40061b..3160dfed73caf30a48cbfe64dd85a26315f446f9 100644 (file)
@@ -1079,7 +1079,7 @@ struct    iw_priv_args
  */
 struct iw_event
 {
-       __u16           len;                    /* Real lenght of this stuff */
+       __u16           len;                    /* Real length of this stuff */
        __u16           cmd;                    /* Wireless IOCTL */
        union iwreq_data        u;              /* IOCTL fixed payload */
 };
index c6148bbf1250a37ec4d29ba49732ff87a2019506..b7b3362f7717823768d0ae30f539019048ec9571 100644 (file)
@@ -62,6 +62,7 @@ struct writeback_control {
        unsigned for_reclaim:1;         /* Invoked from the page allocator */
        unsigned for_writepages:1;      /* This is a writepages() call */
        unsigned range_cyclic:1;        /* range_start is cyclic */
+       unsigned more_io:1;             /* more io to be dispatched */
 };
 
 /*
@@ -100,6 +101,7 @@ extern int dirty_background_ratio;
 extern int vm_dirty_ratio;
 extern int dirty_writeback_interval;
 extern int dirty_expire_interval;
+extern int vm_highmem_is_dirtyable;
 extern int block_dump;
 extern int laptop_mode;
 
index def131a5ac70085f685b527c6de0f23fccae4d0e..df6b95d2218e26930ef95d0bee2e05187f487659 100644 (file)
@@ -46,6 +46,7 @@ struct xattr_handler {
                   size_t size, int flags);
 };
 
+ssize_t xattr_getsecurity(struct inode *, const char *, void *, size_t);
 ssize_t vfs_getxattr(struct dentry *, char *, void *, size_t);
 ssize_t vfs_listxattr(struct dentry *d, char *list, size_t size);
 int vfs_setxattr(struct dentry *, char *, void *, size_t, int);
index 9b5b00c4ef9dee3e8f6bace149b16d4a91f87eab..e31b8c84f2c9da7e865d379d32ccabdc9bd463cb 100644 (file)
@@ -96,6 +96,13 @@ struct xfrm_algo {
        char            alg_key[0];
 };
 
+struct xfrm_algo_aead {
+       char    alg_name[64];
+       int     alg_key_len;    /* in bits */
+       int     alg_icv_len;    /* in bits */
+       char    alg_key[0];
+};
+
 struct xfrm_stats {
        __u32   replay_window;
        __u32   replay;
@@ -270,6 +277,7 @@ enum xfrm_attr_type_t {
        XFRMA_LASTUSED,
        XFRMA_POLICY_TYPE,      /* struct xfrm_userpolicy_type */
        XFRMA_MIGRATE,
+       XFRMA_ALG_AEAD,         /* struct xfrm_algo_aead */
        __XFRMA_MAX
 
 #define XFRMA_MAX (__XFRMA_MAX - 1)
index 951c1ae0be7436b606274a63276407f8f8e60a00..a89426667618a42046a592b2f76e9c8262a1a19f 100644 (file)
@@ -4,7 +4,7 @@
     saa6588.c and every driver (e.g. bttv-driver.c) that wants
     to use the saa6588 module.
 
-    Instead of having a seperate rds.h, I'd prefer to include
+    Instead of having a separate rds.h, I'd prefer to include
     this stuff in one of the already existing files like tuner.h
 
     (c) 2005 by Hans J. Koch
index 752eb47b2678b0ceecabd1c44190e16cd59fde66..c236270ec95ee63566e67f52004636004f912c6a 100644 (file)
@@ -13,15 +13,17 @@ extern int  arp_find(unsigned char *haddr, struct sk_buff *skb);
 extern int     arp_ioctl(struct net *net, unsigned int cmd, void __user *arg);
 extern void     arp_send(int type, int ptype, __be32 dest_ip,
                         struct net_device *dev, __be32 src_ip,
-                        unsigned char *dest_hw, unsigned char *src_hw, unsigned char *th);
+                        const unsigned char *dest_hw,
+                        const unsigned char *src_hw, const unsigned char *th);
 extern int     arp_bind_neighbour(struct dst_entry *dst);
 extern int     arp_mc_map(__be32 addr, u8 *haddr, struct net_device *dev, int dir);
 extern void    arp_ifdown(struct net_device *dev);
 
 extern struct sk_buff *arp_create(int type, int ptype, __be32 dest_ip,
                                  struct net_device *dev, __be32 src_ip,
-                                 unsigned char *dest_hw, unsigned char *src_hw,
-                                 unsigned char *target_hw);
+                                 const unsigned char *dest_hw,
+                                 const unsigned char *src_hw,
+                                 const unsigned char *target_hw);
 extern void arp_xmit(struct sk_buff *skb);
 
 extern struct neigh_ops arp_broken_ops;
index c05f529bff2824c9bc6f92a0a454b0f2260cc884..d58451331dbde8a0d9b4231a61bd4957f62cdeec 100644 (file)
@@ -1,58 +1,20 @@
 #ifndef _NET_ESP_H
 #define _NET_ESP_H
 
-#include <linux/crypto.h>
-#include <net/xfrm.h>
-#include <linux/scatterlist.h>
+#include <linux/skbuff.h>
 
-#define ESP_NUM_FAST_SG                4
+struct crypto_aead;
 
-struct esp_data
-{
-       struct scatterlist              sgbuf[ESP_NUM_FAST_SG];
-
-       /* Confidentiality */
-       struct {
-               int                     padlen;         /* 0..255 */
-               /* ivlen is offset from enc_data, where encrypted data start.
-                * It is logically different of crypto_tfm_alg_ivsize(tfm).
-                * We assume that it is either zero (no ivec), or
-                * >= crypto_tfm_alg_ivsize(tfm). */
-               int                     ivlen;
-               int                     ivinitted;
-               u8                      *ivec;          /* ivec buffer */
-               struct crypto_blkcipher *tfm;           /* crypto handle */
-       } conf;
-
-       /* Integrity. It is active when icv_full_len != 0 */
-       struct {
-               u8                      *work_icv;
-               int                     icv_full_len;
-               int                     icv_trunc_len;
-               struct crypto_hash      *tfm;
-       } auth;
+struct esp_data {
+       /* 0..255 */
+       int padlen;
+
+       /* Confidentiality & Integrity */
+       struct crypto_aead *aead;
 };
 
 extern void *pskb_put(struct sk_buff *skb, struct sk_buff *tail, int len);
 
-static inline int esp_mac_digest(struct esp_data *esp, struct sk_buff *skb,
-                                int offset, int len)
-{
-       struct hash_desc desc;
-       int err;
-
-       desc.tfm = esp->auth.tfm;
-       desc.flags = 0;
-
-       err = crypto_hash_init(&desc);
-       if (unlikely(err))
-               return err;
-       err = skb_icv_walk(skb, &desc, offset, len, crypto_hash_update);
-       if (unlikely(err))
-               return err;
-       return crypto_hash_final(&desc, esp->auth.work_icv);
-}
-
 struct ip_esp_hdr;
 
 static inline struct ip_esp_hdr *ip_esp_hdr(const struct sk_buff *skb)
index b24508abb8505bff87d1ba1f139f25db0f4a10e6..b2cfc4927257cd2307ed31b96ecd0dd5759f0618 100644 (file)
@@ -112,13 +112,13 @@ struct ifmcaddr6
        struct ip6_sf_list      *mca_sources;
        struct ip6_sf_list      *mca_tomb;
        unsigned int            mca_sfmode;
+       unsigned char           mca_crcount;
        unsigned long           mca_sfcount[2];
        struct timer_list       mca_timer;
        unsigned                mca_flags;
        int                     mca_users;
        atomic_t                mca_refcnt;
        spinlock_t              mca_lock;
-       unsigned char           mca_crcount;
        unsigned long           mca_cstamp;
        unsigned long           mca_tstamp;
 };
@@ -166,11 +166,11 @@ struct inet6_dev
        struct ifmcaddr6        *mc_list;
        struct ifmcaddr6        *mc_tomb;
        rwlock_t                mc_lock;
-       unsigned long           mc_v1_seen;
-       unsigned long           mc_maxdelay;
        unsigned char           mc_qrv;
        unsigned char           mc_gq_running;
        unsigned char           mc_ifc_count;
+       unsigned long           mc_v1_seen;
+       unsigned long           mc_maxdelay;
        struct timer_list       mc_gq_timer;    /* general query timer */
        struct timer_list       mc_ifc_timer;   /* interface change timer */
 
index 668056b4bb0b9982b249b96bf8c33ceb5435c912..62a5b691858e0369df0e43ae749ef0aeafcf4871 100644 (file)
@@ -49,7 +49,7 @@ static inline int inet6_sk_ehashfn(const struct sock *sk)
        return inet6_ehashfn(laddr, lport, faddr, fport);
 }
 
-extern void __inet6_hash(struct inet_hashinfo *hashinfo, struct sock *sk);
+extern void __inet6_hash(struct sock *sk);
 
 /*
  * Sockets in TCP_CLOSE state are _always_ taken out of the hash, so
@@ -57,34 +57,37 @@ extern void __inet6_hash(struct inet_hashinfo *hashinfo, struct sock *sk);
  *
  * The sockhash lock must be held as a reader here.
  */
-extern struct sock *__inet6_lookup_established(struct inet_hashinfo *hashinfo,
+extern struct sock *__inet6_lookup_established(struct net *net,
+                                          struct inet_hashinfo *hashinfo,
                                           const struct in6_addr *saddr,
                                           const __be16 sport,
                                           const struct in6_addr *daddr,
                                           const u16 hnum,
                                           const int dif);
 
-extern struct sock *inet6_lookup_listener(struct inet_hashinfo *hashinfo,
+extern struct sock *inet6_lookup_listener(struct net *net,
+                                         struct inet_hashinfo *hashinfo,
                                          const struct in6_addr *daddr,
                                          const unsigned short hnum,
                                          const int dif);
 
-static inline struct sock *__inet6_lookup(struct inet_hashinfo *hashinfo,
+static inline struct sock *__inet6_lookup(struct net *net,
+                                         struct inet_hashinfo *hashinfo,
                                          const struct in6_addr *saddr,
                                          const __be16 sport,
                                          const struct in6_addr *daddr,
                                          const u16 hnum,
                                          const int dif)
 {
-       struct sock *sk = __inet6_lookup_established(hashinfo, saddr, sport,
-                                                    daddr, hnum, dif);
+       struct sock *sk = __inet6_lookup_established(net, hashinfo, saddr,
+                                               sport, daddr, hnum, dif);
        if (sk)
                return sk;
 
-       return inet6_lookup_listener(hashinfo, daddr, hnum, dif);
+       return inet6_lookup_listener(net, hashinfo, daddr, hnum, dif);
 }
 
-extern struct sock *inet6_lookup(struct inet_hashinfo *hashinfo,
+extern struct sock *inet6_lookup(struct net *net, struct inet_hashinfo *hashinfo,
                                 const struct in6_addr *saddr, const __be16 sport,
                                 const struct in6_addr *daddr, const __be16 dport,
                                 const int dif);
index 133cf30d2d7928047bb9eed5669bce71c45513ed..f00f0573627b0b36544e50af781ad64b03c67cdc 100644 (file)
@@ -29,7 +29,6 @@
 #undef INET_CSK_CLEAR_TIMERS
 
 struct inet_bind_bucket;
-struct inet_hashinfo;
 struct tcp_congestion_ops;
 
 /*
@@ -59,6 +58,8 @@ struct inet_connection_sock_af_ops {
                                int level, int optname,
                                char __user *optval, int __user *optlen);
        void        (*addr2sockaddr)(struct sock *sk, struct sockaddr *);
+       int         (*bind_conflict)(const struct sock *sk,
+                                    const struct inet_bind_bucket *tb);
 };
 
 /** inet_connection_sock - INET connection oriented sock
@@ -244,10 +245,7 @@ extern struct request_sock *inet_csk_search_req(const struct sock *sk,
                                                const __be32 laddr);
 extern int inet_csk_bind_conflict(const struct sock *sk,
                                  const struct inet_bind_bucket *tb);
-extern int inet_csk_get_port(struct inet_hashinfo *hashinfo,
-                            struct sock *sk, unsigned short snum,
-                            int (*bind_conflict)(const struct sock *sk,
-                                                 const struct inet_bind_bucket *tb));
+extern int inet_csk_get_port(struct sock *sk, unsigned short snum);
 
 extern struct dst_entry* inet_csk_route_req(struct sock *sk,
                                            const struct request_sock *req);
index 761bdc01425d796b6669bcaa73243d33abf7aab2..97dc35ad09bef3c8618445f44d5e97976b0aa2a9 100644 (file)
@@ -74,6 +74,7 @@ struct inet_ehash_bucket {
  * ports are created in O(1) time?  I thought so. ;-)  -DaveM
  */
 struct inet_bind_bucket {
+       struct net              *ib_net;
        unsigned short          port;
        signed short            fastreuse;
        struct hlist_node       node;
@@ -194,6 +195,7 @@ static inline void inet_ehash_locks_free(struct inet_hashinfo *hashinfo)
 
 extern struct inet_bind_bucket *
                    inet_bind_bucket_create(struct kmem_cache *cachep,
+                                           struct net *net,
                                            struct inet_bind_hashbucket *head,
                                            const unsigned short snum);
 extern void inet_bind_bucket_destroy(struct kmem_cache *cachep,
@@ -219,9 +221,9 @@ static inline int inet_sk_listen_hashfn(const struct sock *sk)
 }
 
 /* Caller must disable local BH processing. */
-static inline void __inet_inherit_port(struct inet_hashinfo *table,
-                                      struct sock *sk, struct sock *child)
+static inline void __inet_inherit_port(struct sock *sk, struct sock *child)
 {
+       struct inet_hashinfo *table = sk->sk_prot->hashinfo;
        const int bhash = inet_bhashfn(inet_sk(child)->num, table->bhash_size);
        struct inet_bind_hashbucket *head = &table->bhash[bhash];
        struct inet_bind_bucket *tb;
@@ -233,15 +235,14 @@ static inline void __inet_inherit_port(struct inet_hashinfo *table,
        spin_unlock(&head->lock);
 }
 
-static inline void inet_inherit_port(struct inet_hashinfo *table,
-                                    struct sock *sk, struct sock *child)
+static inline void inet_inherit_port(struct sock *sk, struct sock *child)
 {
        local_bh_disable();
-       __inet_inherit_port(table, sk, child);
+       __inet_inherit_port(sk, child);
        local_bh_enable();
 }
 
-extern void inet_put_port(struct inet_hashinfo *table, struct sock *sk);
+extern void inet_put_port(struct sock *sk);
 
 extern void inet_listen_wlock(struct inet_hashinfo *hashinfo);
 
@@ -264,51 +265,21 @@ static inline void inet_listen_unlock(struct inet_hashinfo *hashinfo)
                wake_up(&hashinfo->lhash_wait);
 }
 
-extern void __inet_hash(struct inet_hashinfo *hashinfo, struct sock *sk);
-extern void __inet_hash_nolisten(struct inet_hashinfo *hinfo, struct sock *sk);
+extern void __inet_hash_nolisten(struct sock *sk);
+extern void inet_hash(struct sock *sk);
+extern void inet_unhash(struct sock *sk);
 
-static inline void inet_hash(struct inet_hashinfo *hashinfo, struct sock *sk)
-{
-       if (sk->sk_state != TCP_CLOSE) {
-               local_bh_disable();
-               __inet_hash(hashinfo, sk);
-               local_bh_enable();
-       }
-}
-
-static inline void inet_unhash(struct inet_hashinfo *hashinfo, struct sock *sk)
-{
-       rwlock_t *lock;
-
-       if (sk_unhashed(sk))
-               goto out;
-
-       if (sk->sk_state == TCP_LISTEN) {
-               local_bh_disable();
-               inet_listen_wlock(hashinfo);
-               lock = &hashinfo->lhash_lock;
-       } else {
-               lock = inet_ehash_lockp(hashinfo, sk->sk_hash);
-               write_lock_bh(lock);
-       }
-
-       if (__sk_del_node_init(sk))
-               sock_prot_inuse_add(sk->sk_prot, -1);
-       write_unlock_bh(lock);
-out:
-       if (sk->sk_state == TCP_LISTEN)
-               wake_up(&hashinfo->lhash_wait);
-}
-
-extern struct sock *__inet_lookup_listener(struct inet_hashinfo *hashinfo,
+extern struct sock *__inet_lookup_listener(struct net *net,
+                                          struct inet_hashinfo *hashinfo,
                                           const __be32 daddr,
                                           const unsigned short hnum,
                                           const int dif);
 
-static inline struct sock *inet_lookup_listener(struct inet_hashinfo *hashinfo,
-                                               __be32 daddr, __be16 dport, int dif)
+static inline struct sock *inet_lookup_listener(struct net *net,
+               struct inet_hashinfo *hashinfo,
+               __be32 daddr, __be16 dport, int dif)
 {
-       return __inet_lookup_listener(hashinfo, daddr, ntohs(dport), dif);
+       return __inet_lookup_listener(net, hashinfo, daddr, ntohs(dport), dif);
 }
 
 /* Socket demux engine toys. */
@@ -342,26 +313,26 @@ typedef __u64 __bitwise __addrpair;
                                   (((__force __u64)(__be32)(__daddr)) << 32) | \
                                   ((__force __u64)(__be32)(__saddr)));
 #endif /* __BIG_ENDIAN */
-#define INET_MATCH(__sk, __hash, __cookie, __saddr, __daddr, __ports, __dif)\
-       (((__sk)->sk_hash == (__hash))                          &&      \
+#define INET_MATCH(__sk, __net, __hash, __cookie, __saddr, __daddr, __ports, __dif)\
+       (((__sk)->sk_hash == (__hash)) && ((__sk)->sk_net == (__net))   &&      \
         ((*((__addrpair *)&(inet_sk(__sk)->daddr))) == (__cookie))     &&      \
         ((*((__portpair *)&(inet_sk(__sk)->dport))) == (__ports))      &&      \
         (!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif))))
-#define INET_TW_MATCH(__sk, __hash, __cookie, __saddr, __daddr, __ports, __dif)\
-       (((__sk)->sk_hash == (__hash))                          &&      \
+#define INET_TW_MATCH(__sk, __net, __hash, __cookie, __saddr, __daddr, __ports, __dif)\
+       (((__sk)->sk_hash == (__hash)) && ((__sk)->sk_net == (__net))   &&      \
         ((*((__addrpair *)&(inet_twsk(__sk)->tw_daddr))) == (__cookie)) &&     \
         ((*((__portpair *)&(inet_twsk(__sk)->tw_dport))) == (__ports)) &&      \
         (!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif))))
 #else /* 32-bit arch */
 #define INET_ADDR_COOKIE(__name, __saddr, __daddr)
-#define INET_MATCH(__sk, __hash, __cookie, __saddr, __daddr, __ports, __dif)   \
-       (((__sk)->sk_hash == (__hash))                          &&      \
+#define INET_MATCH(__sk, __net, __hash, __cookie, __saddr, __daddr, __ports, __dif)    \
+       (((__sk)->sk_hash == (__hash)) && ((__sk)->sk_net == (__net))   &&      \
         (inet_sk(__sk)->daddr          == (__saddr))           &&      \
         (inet_sk(__sk)->rcv_saddr      == (__daddr))           &&      \
         ((*((__portpair *)&(inet_sk(__sk)->dport))) == (__ports))      &&      \
         (!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif))))
-#define INET_TW_MATCH(__sk, __hash,__cookie, __saddr, __daddr, __ports, __dif) \
-       (((__sk)->sk_hash == (__hash))                          &&      \
+#define INET_TW_MATCH(__sk, __net, __hash,__cookie, __saddr, __daddr, __ports, __dif)  \
+       (((__sk)->sk_hash == (__hash)) && ((__sk)->sk_net == (__net))   &&      \
         (inet_twsk(__sk)->tw_daddr     == (__saddr))           &&      \
         (inet_twsk(__sk)->tw_rcv_saddr == (__daddr))           &&      \
         ((*((__portpair *)&(inet_twsk(__sk)->tw_dport))) == (__ports)) &&      \
@@ -374,32 +345,36 @@ typedef __u64 __bitwise __addrpair;
  *
  * Local BH must be disabled here.
  */
-extern struct sock * __inet_lookup_established(struct inet_hashinfo *hashinfo,
+extern struct sock * __inet_lookup_established(struct net *net,
+               struct inet_hashinfo *hashinfo,
                const __be32 saddr, const __be16 sport,
                const __be32 daddr, const u16 hnum, const int dif);
 
 static inline struct sock *
-       inet_lookup_established(struct inet_hashinfo *hashinfo,
+       inet_lookup_established(struct net *net, struct inet_hashinfo *hashinfo,
                                const __be32 saddr, const __be16 sport,
                                const __be32 daddr, const __be16 dport,
                                const int dif)
 {
-       return __inet_lookup_established(hashinfo, saddr, sport, daddr,
+       return __inet_lookup_established(net, hashinfo, saddr, sport, daddr,
                                         ntohs(dport), dif);
 }
 
-static inline struct sock *__inet_lookup(struct inet_hashinfo *hashinfo,
+static inline struct sock *__inet_lookup(struct net *net,
+                                        struct inet_hashinfo *hashinfo,
                                         const __be32 saddr, const __be16 sport,
                                         const __be32 daddr, const __be16 dport,
                                         const int dif)
 {
        u16 hnum = ntohs(dport);
-       struct sock *sk = __inet_lookup_established(hashinfo, saddr, sport, daddr,
-                                                   hnum, dif);
-       return sk ? : __inet_lookup_listener(hashinfo, daddr, hnum, dif);
+       struct sock *sk = __inet_lookup_established(net, hashinfo,
+                               saddr, sport, daddr, hnum, dif);
+
+       return sk ? : __inet_lookup_listener(net, hashinfo, daddr, hnum, dif);
 }
 
-static inline struct sock *inet_lookup(struct inet_hashinfo *hashinfo,
+static inline struct sock *inet_lookup(struct net *net,
+                                      struct inet_hashinfo *hashinfo,
                                       const __be32 saddr, const __be16 sport,
                                       const __be32 daddr, const __be16 dport,
                                       const int dif)
@@ -407,12 +382,17 @@ static inline struct sock *inet_lookup(struct inet_hashinfo *hashinfo,
        struct sock *sk;
 
        local_bh_disable();
-       sk = __inet_lookup(hashinfo, saddr, sport, daddr, dport, dif);
+       sk = __inet_lookup(net, hashinfo, saddr, sport, daddr, dport, dif);
        local_bh_enable();
 
        return sk;
 }
 
+extern int __inet_hash_connect(struct inet_timewait_death_row *death_row,
+               struct sock *sk, u32 port_offset,
+               int (*check_established)(struct inet_timewait_death_row *,
+                       struct sock *, __u16, struct inet_timewait_sock **),
+                              void (*hash)(struct sock *sk));
 extern int inet_hash_connect(struct inet_timewait_death_row *death_row,
                             struct sock *sk);
 #endif /* _INET_HASHTABLES_H */
index 67e925065aaeee1245c8088a6ccead3a128f4fc2..296547bfb0b726610141c511504d358e518e4d94 100644 (file)
@@ -116,6 +116,7 @@ struct inet_timewait_sock {
 #define tw_hash                        __tw_common.skc_hash
 #define tw_prot                        __tw_common.skc_prot
 #define tw_net                 __tw_common.skc_net
+       int                     tw_timeout;
        volatile unsigned char  tw_substate;
        /* 3 bits hole, try to pack */
        unsigned char           tw_rcv_wscale;
@@ -130,7 +131,6 @@ struct inet_timewait_sock {
        __u8                    tw_ipv6only:1;
        /* 15 bits hole, try to pack */
        __u16                   tw_ipv6_offset;
-       int                     tw_timeout;
        unsigned long           tw_ttd;
        struct inet_bind_bucket *tw_tb;
        struct hlist_node       tw_death_node;
index 9daa60b544ba8839f8ca690fe2173ac5506d0922..8b12667f7a2bccad312fc0e63e679dfd02ec3509 100644 (file)
@@ -69,6 +69,7 @@ struct fib_nh {
 struct fib_info {
        struct hlist_node       fib_hash;
        struct hlist_node       fib_lhash;
+       struct net              *fib_net;
        int                     fib_treeref;
        atomic_t                fib_clntref;
        int                     fib_dead;
@@ -218,7 +219,8 @@ extern void fib_select_default(struct net *net, const struct flowi *flp,
 
 /* Exported by fib_semantics.c */
 extern int ip_fib_check_default(__be32 gw, struct net_device *dev);
-extern int fib_sync_down(__be32 local, struct net_device *dev, int force);
+extern int fib_sync_down_dev(struct net_device *dev, int force);
+extern int fib_sync_down_addr(struct net *net, __be32 local);
 extern int fib_sync_up(struct net_device *dev);
 extern __be32  __fib_res_prefsrc(struct fib_result *res);
 extern void fib_select_multipath(const struct flowi *flp, struct fib_result *res);
@@ -264,6 +266,14 @@ static inline void fib_res_put(struct fib_result *res)
 #ifdef CONFIG_PROC_FS
 extern int __net_init  fib_proc_init(struct net *net);
 extern void __net_exit fib_proc_exit(struct net *net);
+#else
+static inline int fib_proc_init(struct net *net)
+{
+       return 0;
+}
+static inline void fib_proc_exit(struct net *net)
+{
+}
 #endif
 
 #endif  /* _NET_FIB_H */
index fa80ea48639dd30002bfeaac4200eaef4bce7faf..c0c019f72ba95a1896cdf7c77c1312491318210b 100644 (file)
@@ -110,7 +110,6 @@ struct frag_hdr {
 
 /* sysctls */
 extern int sysctl_mld_max_msf;
-
 extern struct ctl_path net_ipv6_ctl_path[];
 
 #define _DEVINC(statname, modifier, idev, field)                       \
@@ -586,9 +585,6 @@ extern int ip6_mc_msfget(struct sock *sk, struct group_filter *gsf,
                         int __user *optlen);
 
 #ifdef CONFIG_PROC_FS
-extern struct ctl_table *ipv6_icmp_sysctl_init(struct net *net);
-extern struct ctl_table *ipv6_route_sysctl_init(struct net *net);
-
 extern int  ac6_proc_init(void);
 extern void ac6_proc_exit(void);
 extern int  raw6_proc_init(void);
@@ -621,6 +617,8 @@ static inline int snmp6_unregister_dev(struct inet6_dev *idev)
 extern ctl_table ipv6_route_table_template[];
 extern ctl_table ipv6_icmp_table_template[];
 
+extern struct ctl_table *ipv6_icmp_sysctl_init(struct net *net);
+extern struct ctl_table *ipv6_route_sysctl_init(struct net *net);
 extern int ipv6_sysctl_register(void);
 extern void ipv6_sysctl_unregister(void);
 #endif
index b8c1d60ba9e45dbde637576c43b83311d1e531ea..28738b7d53eb2a0748cecad1076a9726da8d936f 100644 (file)
@@ -12,6 +12,7 @@
 #include <net/netns/packet.h>
 #include <net/netns/ipv4.h>
 #include <net/netns/ipv6.h>
+#include <net/netns/x_tables.h>
 
 struct proc_dir_entry;
 struct net_device;
@@ -56,6 +57,9 @@ struct net {
 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
        struct netns_ipv6       ipv6;
 #endif
+#ifdef CONFIG_NETFILTER
+       struct netns_xt         xt;
+#endif
 };
 
 #ifdef CONFIG_NET
index 857d89951790ab2b35c37c38b9628689e1296536..90b3e7f5df5fdf5fd34cb7469bc45a6957ae98c4 100644 (file)
@@ -129,6 +129,8 @@ struct nf_conn
 
        /* Extensions */
        struct nf_ct_ext *ext;
+
+       struct rcu_head rcu;
 };
 
 static inline struct nf_conn *
@@ -143,7 +145,7 @@ nf_ct_tuplehash_to_ctrack(const struct nf_conntrack_tuple_hash *hash)
 
 /* Alter reply tuple (maybe alter helper). */
 extern void
-nf_conntrack_alter_reply(struct nf_conn *conntrack,
+nf_conntrack_alter_reply(struct nf_conn *ct,
                         const struct nf_conntrack_tuple *newreply);
 
 /* Is this tuple taken? (ignoring any belonging to the given
@@ -171,13 +173,12 @@ static inline void nf_ct_put(struct nf_conn *ct)
 extern int nf_ct_l3proto_try_module_get(unsigned short l3proto);
 extern void nf_ct_l3proto_module_put(unsigned short l3proto);
 
-extern struct hlist_head *nf_ct_alloc_hashtable(int *sizep, int *vmalloced);
+extern struct hlist_head *nf_ct_alloc_hashtable(unsigned int *sizep, int *vmalloced);
 extern void nf_ct_free_hashtable(struct hlist_head *hash, int vmalloced,
-                                int size);
+                                unsigned int size);
 
 extern struct nf_conntrack_tuple_hash *
-__nf_conntrack_find(const struct nf_conntrack_tuple *tuple,
-                   const struct nf_conn *ignored_conntrack);
+__nf_conntrack_find(const struct nf_conntrack_tuple *tuple);
 
 extern void nf_conntrack_hash_insert(struct nf_conn *ct);
 
@@ -215,9 +216,9 @@ static inline void nf_ct_refresh(struct nf_conn *ct,
 
 /* These are for NAT.  Icky. */
 /* Update TCP window tracking data when NAT mangles the packet */
-extern void nf_conntrack_tcp_update(struct sk_buff *skb,
+extern void nf_conntrack_tcp_update(const struct sk_buff *skb,
                                    unsigned int dataoff,
-                                   struct nf_conn *conntrack,
+                                   struct nf_conn *ct,
                                    int dir);
 
 /* Fake conntrack entry for untracked connections */
index 7ad0828f05cfef3c8e322886c02efcffa0fac516..9ee26469c759ed06a74ff1754a991259bd96b0cc 100644 (file)
@@ -68,11 +68,11 @@ static inline int nf_conntrack_confirm(struct sk_buff *skb)
 
 int
 print_tuple(struct seq_file *s, const struct nf_conntrack_tuple *tuple,
-           struct nf_conntrack_l3proto *l3proto,
-           struct nf_conntrack_l4proto *proto);
+            const struct nf_conntrack_l3proto *l3proto,
+            const struct nf_conntrack_l4proto *proto);
 
 extern struct hlist_head *nf_conntrack_hash;
-extern rwlock_t nf_conntrack_lock ;
+extern spinlock_t nf_conntrack_lock ;
 extern struct hlist_head unconfirmed;
 
 #endif /* _NF_CONNTRACK_CORE_H */
index 6c3fd254c28ef148a8f9f04f2c35c19bbc8f7f7b..cb608a1b44e59812876c1c3db00b2150fc538e1c 100644 (file)
@@ -49,6 +49,8 @@ struct nf_conntrack_expect
        /* Direction relative to the master connection. */
        enum ip_conntrack_dir dir;
 #endif
+
+       struct rcu_head rcu;
 };
 
 #define NF_CT_EXPECT_PERMANENT 0x1
index 2f3af00643cf92166c1898740d45c56334d0c55c..4ca125e9b3ce30870cfde5182d4b8000c4925920 100644 (file)
@@ -42,13 +42,9 @@ struct nf_conntrack_helper
 extern struct nf_conntrack_helper *
 __nf_ct_helper_find(const struct nf_conntrack_tuple *tuple);
 
-extern struct nf_conntrack_helper *
-nf_ct_helper_find_get( const struct nf_conntrack_tuple *tuple);
-
 extern struct nf_conntrack_helper *
 __nf_conntrack_helper_find_byname(const char *name);
 
-extern void nf_ct_helper_put(struct nf_conntrack_helper *helper);
 extern int nf_conntrack_helper_register(struct nf_conntrack_helper *);
 extern void nf_conntrack_helper_unregister(struct nf_conntrack_helper *);
 
index d5526bcce147ab906c884e33b38c4cc9ba977b1d..b886e3ae6cad69bf78df1819456cd661daf95387 100644 (file)
@@ -43,7 +43,7 @@ struct nf_conntrack_l3proto
                           const struct nf_conntrack_tuple *);
 
        /* Returns verdict for packet, or -1 for invalid. */
-       int (*packet)(struct nf_conn *conntrack,
+       int (*packet)(struct nf_conn *ct,
                      const struct sk_buff *skb,
                      enum ip_conntrack_info ctinfo);
 
@@ -51,7 +51,7 @@ struct nf_conntrack_l3proto
         * Called when a new connection for this protocol found;
         * returns TRUE if it's OK.  If so, packet() called next.
         */
-       int (*new)(struct nf_conn *conntrack, const struct sk_buff *skb);
+       int (*new)(struct nf_conn *ct, const struct sk_buff *skb);
 
        /*
         * Called before tracking. 
index fb50c217ba0af56f447ec44d84255bacd2d1061f..efc16eccddb1b1e09c638f0b9bab2428f1f9fc1d 100644 (file)
@@ -23,9 +23,6 @@ struct nf_conntrack_l4proto
        /* L4 Protocol number. */
        u_int8_t l4proto;
 
-       /* Protocol name */
-       const char *name;
-
        /* Try to fill in the third arg: dataoff is offset past network protocol
            hdr.  Return true if possible. */
        int (*pkt_to_tuple)(const struct sk_buff *skb,
@@ -38,15 +35,8 @@ struct nf_conntrack_l4proto
        int (*invert_tuple)(struct nf_conntrack_tuple *inverse,
                            const struct nf_conntrack_tuple *orig);
 
-       /* Print out the per-protocol part of the tuple. Return like seq_* */
-       int (*print_tuple)(struct seq_file *s,
-                          const struct nf_conntrack_tuple *);
-
-       /* Print out the private part of the conntrack. */
-       int (*print_conntrack)(struct seq_file *s, const struct nf_conn *);
-
        /* Returns verdict for packet, or -1 for invalid. */
-       int (*packet)(struct nf_conn *conntrack,
+       int (*packet)(struct nf_conn *ct,
                      const struct sk_buff *skb,
                      unsigned int dataoff,
                      enum ip_conntrack_info ctinfo,
@@ -55,16 +45,23 @@ struct nf_conntrack_l4proto
 
        /* Called when a new connection for this protocol found;
         * returns TRUE if it's OK.  If so, packet() called next. */
-       int (*new)(struct nf_conn *conntrack, const struct sk_buff *skb,
+       int (*new)(struct nf_conn *ct, const struct sk_buff *skb,
                   unsigned int dataoff);
 
        /* Called when a conntrack entry is destroyed */
-       void (*destroy)(struct nf_conn *conntrack);
+       void (*destroy)(struct nf_conn *ct);
 
        int (*error)(struct sk_buff *skb, unsigned int dataoff,
                     enum ip_conntrack_info *ctinfo,
                     int pf, unsigned int hooknum);
 
+       /* Print out the per-protocol part of the tuple. Return like seq_* */
+       int (*print_tuple)(struct seq_file *s,
+                          const struct nf_conntrack_tuple *);
+
+       /* Print out the private part of the conntrack. */
+       int (*print_conntrack)(struct seq_file *s, const struct nf_conn *);
+
        /* convert protoinfo to nfnetink attributes */
        int (*to_nlattr)(struct sk_buff *skb, struct nlattr *nla,
                         const struct nf_conn *ct);
@@ -87,6 +84,8 @@ struct nf_conntrack_l4proto
        struct ctl_table        *ctl_compat_table;
 #endif
 #endif
+       /* Protocol name */
+       const char *name;
 
        /* Module (if any) which this is connected to. */
        struct module *me;
index 45cb17cdcfd0c8555edcb280f9db61ca94d1f080..e69ab2e875973f205cd9e569c82dbfb6e08ab0d4 100644 (file)
@@ -132,34 +132,33 @@ struct nf_conntrack_tuple_hash
 
 #endif /* __KERNEL__ */
 
-static inline int nf_ct_tuple_src_equal(const struct nf_conntrack_tuple *t1,
-                                       const struct nf_conntrack_tuple *t2)
+static inline int __nf_ct_tuple_src_equal(const struct nf_conntrack_tuple *t1,
+                                         const struct nf_conntrack_tuple *t2)
 { 
        return (t1->src.u3.all[0] == t2->src.u3.all[0] &&
                t1->src.u3.all[1] == t2->src.u3.all[1] &&
                t1->src.u3.all[2] == t2->src.u3.all[2] &&
                t1->src.u3.all[3] == t2->src.u3.all[3] &&
                t1->src.u.all == t2->src.u.all &&
-               t1->src.l3num == t2->src.l3num &&
-               t1->dst.protonum == t2->dst.protonum);
+               t1->src.l3num == t2->src.l3num);
 }
 
-static inline int nf_ct_tuple_dst_equal(const struct nf_conntrack_tuple *t1,
-                                       const struct nf_conntrack_tuple *t2)
+static inline int __nf_ct_tuple_dst_equal(const struct nf_conntrack_tuple *t1,
+                                         const struct nf_conntrack_tuple *t2)
 {
        return (t1->dst.u3.all[0] == t2->dst.u3.all[0] &&
                t1->dst.u3.all[1] == t2->dst.u3.all[1] &&
                t1->dst.u3.all[2] == t2->dst.u3.all[2] &&
                t1->dst.u3.all[3] == t2->dst.u3.all[3] &&
                t1->dst.u.all == t2->dst.u.all &&
-               t1->src.l3num == t2->src.l3num &&
                t1->dst.protonum == t2->dst.protonum);
 }
 
 static inline int nf_ct_tuple_equal(const struct nf_conntrack_tuple *t1,
                                    const struct nf_conntrack_tuple *t2)
 {
-       return nf_ct_tuple_src_equal(t1, t2) && nf_ct_tuple_dst_equal(t1, t2);
+       return __nf_ct_tuple_src_equal(t1, t2) &&
+              __nf_ct_tuple_dst_equal(t1, t2);
 }
 
 static inline int nf_ct_tuple_mask_equal(const struct nf_conntrack_tuple_mask *m1,
@@ -199,7 +198,7 @@ static inline int nf_ct_tuple_mask_cmp(const struct nf_conntrack_tuple *t,
                                       const struct nf_conntrack_tuple_mask *mask)
 {
        return nf_ct_tuple_src_mask_cmp(t, tuple, mask) &&
-              nf_ct_tuple_dst_equal(t, tuple);
+              __nf_ct_tuple_dst_equal(t, tuple);
 }
 
 #endif /* _NF_CONNTRACK_TUPLE_H */
index 037e82403f916244926973a4e7c2c35774fea00e..8c6b5ae45534463591cce0f86e371f46d655b484 100644 (file)
@@ -54,6 +54,6 @@ void nf_log_packet(int pf,
                   const struct net_device *in,
                   const struct net_device *out,
                   const struct nf_loginfo *li,
-                  const char *fmt, ...);
+                  const char *fmt, ...) __attribute__ ((format(printf,7,8)));
 
 #endif /* _NF_LOG_H */
index b3213c7c53096d97b45b5e51ca842ba01284fefc..0ca67d73c7ad81b177dea9a08c4ea0e65e262ab8 100644 (file)
@@ -36,6 +36,8 @@
 #include <net/netlink.h>
 #include <asm/atomic.h>
 
+struct cipso_v4_doi;
+
 /*
  * NetLabel - A management interface for maintaining network packet label
  *            mapping tables for explicit packet labling protocols.
@@ -103,12 +105,6 @@ struct netlbl_audit {
        uid_t loginuid;
 };
 
-/* Domain mapping definition struct */
-struct netlbl_dom_map;
-
-/* Domain mapping operations */
-int netlbl_domhsh_remove(const char *domain, struct netlbl_audit *audit_info);
-
 /*
  * LSM security attributes
  */
@@ -343,6 +339,19 @@ static inline void netlbl_secattr_free(struct netlbl_lsm_secattr *secattr)
 }
 
 #ifdef CONFIG_NETLABEL
+/*
+ * LSM configuration operations
+ */
+int netlbl_cfg_map_del(const char *domain, struct netlbl_audit *audit_info);
+int netlbl_cfg_unlbl_add_map(const char *domain,
+                            struct netlbl_audit *audit_info);
+int netlbl_cfg_cipsov4_add(struct cipso_v4_doi *doi_def,
+                          struct netlbl_audit *audit_info);
+int netlbl_cfg_cipsov4_add_map(struct cipso_v4_doi *doi_def,
+                              const char *domain,
+                              struct netlbl_audit *audit_info);
+int netlbl_cfg_cipsov4_del(u32 doi, struct netlbl_audit *audit_info);
+
 /*
  * LSM security attribute operations
  */
@@ -378,6 +387,32 @@ void netlbl_cache_invalidate(void);
 int netlbl_cache_add(const struct sk_buff *skb,
                     const struct netlbl_lsm_secattr *secattr);
 #else
+static inline int netlbl_cfg_map_del(const char *domain,
+                                    struct netlbl_audit *audit_info)
+{
+       return -ENOSYS;
+}
+static inline int netlbl_cfg_unlbl_add_map(const char *domain,
+                                          struct netlbl_audit *audit_info)
+{
+       return -ENOSYS;
+}
+static inline int netlbl_cfg_cipsov4_add(struct cipso_v4_doi *doi_def,
+                                        struct netlbl_audit *audit_info)
+{
+       return -ENOSYS;
+}
+static inline int netlbl_cfg_cipsov4_add_map(struct cipso_v4_doi *doi_def,
+                                            const char *domain,
+                                            struct netlbl_audit *audit_info)
+{
+       return -ENOSYS;
+}
+static inline int netlbl_cfg_cipsov4_del(u32 doi,
+                                        struct netlbl_audit *audit_info)
+{
+       return -ENOSYS;
+}
 static inline int netlbl_secattr_catmap_walk(
                                      struct netlbl_lsm_secattr_catmap *catmap,
                                      u32 offset)
index 15a0b052df222f9e9930d50be7ee448c5371e7b8..a9b4f608629444e432d00787b818b75a47538b1e 100644 (file)
@@ -27,5 +27,11 @@ struct netns_ipv4 {
        struct sock             *fibnl;
 
        struct netns_frags      frags;
+#ifdef CONFIG_NETFILTER
+       struct xt_table         *iptable_filter;
+       struct xt_table         *iptable_mangle;
+       struct xt_table         *iptable_raw;
+       struct xt_table         *arptable_filter;
+#endif
 };
 #endif
index 187c4248df220f51c4511d910fd09395b25bce88..1dd7de4e419548672c937aeb489575dd7a96a32c 100644 (file)
@@ -31,5 +31,10 @@ struct netns_ipv6 {
        struct ipv6_devconf     *devconf_all;
        struct ipv6_devconf     *devconf_dflt;
        struct netns_frags      frags;
+#ifdef CONFIG_NETFILTER
+       struct xt_table         *ip6table_filter;
+       struct xt_table         *ip6table_mangle;
+       struct xt_table         *ip6table_raw;
+#endif
 };
 #endif
diff --git a/include/net/netns/x_tables.h b/include/net/netns/x_tables.h
new file mode 100644 (file)
index 0000000..0cb63ed
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef __NETNS_X_TABLES_H
+#define __NETNS_X_TABLES_H
+
+#include <linux/list.h>
+#include <linux/net.h>
+
+struct netns_xt {
+       struct list_head tables[NPROTO];
+};
+#endif
index 8716eb757d514f076f33a60e550096f1ede1d0dc..d349c66ef8281029689dd7859f88b9c7afd63928 100644 (file)
@@ -131,14 +131,14 @@ tcf_exts_exec(struct sk_buff *skb, struct tcf_exts *exts,
 
 extern int tcf_exts_validate(struct tcf_proto *tp, struct nlattr **tb,
                             struct nlattr *rate_tlv, struct tcf_exts *exts,
-                            struct tcf_ext_map *map);
+                            const struct tcf_ext_map *map);
 extern void tcf_exts_destroy(struct tcf_proto *tp, struct tcf_exts *exts);
 extern void tcf_exts_change(struct tcf_proto *tp, struct tcf_exts *dst,
                             struct tcf_exts *src);
 extern int tcf_exts_dump(struct sk_buff *skb, struct tcf_exts *exts,
-                        struct tcf_ext_map *map);
+                        const struct tcf_ext_map *map);
 extern int tcf_exts_dump_stats(struct sk_buff *skb, struct tcf_exts *exts,
-                              struct tcf_ext_map *map);
+                              const struct tcf_ext_map *map);
 
 /**
  * struct tcf_pkt_info - packet information
index cca81d8b2d8ba2052e75539aa314cec10d066833..1828f81fe37474ca6a3228188133d1b86d817a37 100644 (file)
@@ -41,7 +41,6 @@ extern void raw_proc_exit(void);
 struct raw_iter_state {
        struct seq_net_private p;
        int bucket;
-       unsigned short family;
        struct raw_hashinfo *h;
 };
 
@@ -49,8 +48,8 @@ struct raw_iter_state {
 void *raw_seq_start(struct seq_file *seq, loff_t *pos);
 void *raw_seq_next(struct seq_file *seq, void *v, loff_t *pos);
 void raw_seq_stop(struct seq_file *seq, void *v);
-int raw_seq_open(struct inode *ino, struct file *file, struct raw_hashinfo *h,
-               unsigned short family);
+int raw_seq_open(struct inode *ino, struct file *file,
+                struct raw_hashinfo *h, const struct seq_operations *ops);
 
 #endif
 
index 4eabf008413bfb18390fd552e88a49f4fcf44e28..eadad590142992fdcf3ae92f49a624821ec3d275 100644 (file)
@@ -27,6 +27,7 @@
 #include <net/dst.h>
 #include <net/inetpeer.h>
 #include <net/flow.h>
+#include <net/sock.h>
 #include <linux/in_route.h>
 #include <linux/rtnetlink.h>
 #include <linux/route.h>
@@ -61,6 +62,7 @@ struct rtable
 
        struct in_device        *idev;
        
+       int                     rt_genid;
        unsigned                rt_flags;
        __u16                   rt_type;
 
@@ -149,6 +151,7 @@ static inline int ip_route_connect(struct rtable **rp, __be32 dst,
                                   int flags)
 {
        struct flowi fl = { .oif = oif,
+                           .mark = sk->sk_mark,
                            .nl_u = { .ip4_u = { .daddr = dst,
                                                 .saddr = src,
                                                 .tos   = tos } },
index 902324488d0f7d2fb9a485258f59efa827344b0f..8a7889b35810ce9e6ee4c4799af4d79c7315c0a6 100644 (file)
@@ -262,6 +262,8 @@ struct sock {
        __u32                   sk_sndmsg_off;
        int                     sk_write_pending;
        void                    *sk_security;
+       __u32                   sk_mark;
+       /* XXX 4 bytes hole on 64 bit */
        void                    (*sk_state_change)(struct sock *sk);
        void                    (*sk_data_ready)(struct sock *sk, int bytes);
        void                    (*sk_write_space)(struct sock *sk);
@@ -494,6 +496,7 @@ extern int sk_wait_data(struct sock *sk, long *timeo);
 
 struct request_sock_ops;
 struct timewait_sock_ops;
+struct inet_hashinfo;
 
 /* Networking protocol blocks we attach to sockets.
  * socket layer -> transport layer interface
@@ -576,6 +579,8 @@ struct proto {
        struct request_sock_ops *rsk_prot;
        struct timewait_sock_ops *twsk_prot;
 
+       struct inet_hashinfo    *hashinfo;
+
        struct module           *owner;
 
        char                    name[32];
index 5ebb9ba479b107edfb11c582390c478100bee7f3..ac72116636ca7f46bfb486079fd244d7b5433f9f 100644 (file)
@@ -159,6 +159,7 @@ struct xfrm_state
        struct xfrm_algo        *aalg;
        struct xfrm_algo        *ealg;
        struct xfrm_algo        *calg;
+       struct xfrm_algo_aead   *aead;
 
        /* Data for encapsulator */
        struct xfrm_encap_tmpl  *encap;
@@ -201,7 +202,7 @@ struct xfrm_state
 
        /* Reference to data common to all the instances of this
         * transformer. */
-       struct xfrm_type        *type;
+       const struct xfrm_type  *type;
        struct xfrm_mode        *inner_mode;
        struct xfrm_mode        *outer_mode;
 
@@ -278,7 +279,7 @@ struct xfrm_state_afinfo {
        unsigned int            proto;
        unsigned int            eth_proto;
        struct module           *owner;
-       struct xfrm_type        *type_map[IPPROTO_MAX];
+       const struct xfrm_type  *type_map[IPPROTO_MAX];
        struct xfrm_mode        *mode_map[XFRM_MODE_MAX];
        int                     (*init_flags)(struct xfrm_state *x);
        void                    (*init_tempsel)(struct xfrm_state *x, struct flowi *fl,
@@ -321,8 +322,8 @@ struct xfrm_type
        u32                     (*get_mtu)(struct xfrm_state *, int size);
 };
 
-extern int xfrm_register_type(struct xfrm_type *type, unsigned short family);
-extern int xfrm_unregister_type(struct xfrm_type *type, unsigned short family);
+extern int xfrm_register_type(const struct xfrm_type *type, unsigned short family);
+extern int xfrm_unregister_type(const struct xfrm_type *type, unsigned short family);
 
 struct xfrm_mode {
        /*
@@ -1108,6 +1109,10 @@ static inline int xfrm_id_proto_match(u8 proto, u8 userproto)
 /*
  * xfrm algorithm information
  */
+struct xfrm_algo_aead_info {
+       u16 icv_truncbits;
+};
+
 struct xfrm_algo_auth_info {
        u16 icv_truncbits;
        u16 icv_fullbits;
@@ -1127,6 +1132,7 @@ struct xfrm_algo_desc {
        char *compat;
        u8 available:1;
        union {
+               struct xfrm_algo_aead_info aead;
                struct xfrm_algo_auth_info auth;
                struct xfrm_algo_encr_info encr;
                struct xfrm_algo_comp_info comp;
@@ -1343,6 +1349,8 @@ extern struct xfrm_algo_desc *xfrm_calg_get_byid(int alg_id);
 extern struct xfrm_algo_desc *xfrm_aalg_get_byname(char *name, int probe);
 extern struct xfrm_algo_desc *xfrm_ealg_get_byname(char *name, int probe);
 extern struct xfrm_algo_desc *xfrm_calg_get_byname(char *name, int probe);
+extern struct xfrm_algo_desc *xfrm_aead_get_byname(char *name, int icv_len,
+                                                  int probe);
 
 struct hash_desc;
 struct scatterlist;
index d5838c30d20f716cf69c7adc7183b6f580a30640..87a260e3699efd3dd138216e84038ed916064060 100644 (file)
@@ -147,11 +147,11 @@ typedef struct config_req_t {
 
 /* For RequestIO and ReleaseIO */
 typedef struct io_req_t {
-    ioaddr_t   BasePort1;
-    ioaddr_t   NumPorts1;
+    u_int      BasePort1;
+    u_int      NumPorts1;
     u_int      Attributes1;
-    ioaddr_t   BasePort2;
-    ioaddr_t   NumPorts2;
+    u_int      BasePort2;
+    u_int      NumPorts2;
     u_int      Attributes2;
     u_int      IOAddrLines;
 } io_req_t;
index 5f388035687de5004d11d42fbb436abb08fb325b..9a6bcc4952f0653fbc8dafad010b3c87b9be11bf 100644 (file)
@@ -27,7 +27,6 @@ typedef u_int   ioaddr_t;
 #else
 typedef u_short        ioaddr_t;
 #endif
-typedef unsigned long kio_addr_t;
 
 typedef u_short        socket_t;
 typedef u_int  event_t;
index 6e84258b94de2475cd48afc6c69d2f46999a76ca..f95dca077c1c2fdc8cc5c59562185fadc2c65ddd 100644 (file)
@@ -92,7 +92,7 @@ typedef struct pccard_io_map {
     u_char     map;
     u_char     flags;
     u_short    speed;
-    kio_addr_t start, stop;
+    u_int      start, stop;
 } pccard_io_map;
 
 typedef struct pccard_mem_map {
@@ -155,7 +155,7 @@ extern struct pccard_resource_ops pccard_iodyn_ops;
 struct pcmcia_socket;
 
 typedef struct io_window_t {
-       kio_addr_t              InUse, Config;
+       u_int                   InUse, Config;
        struct resource         *res;
 } io_window_t;
 
@@ -208,7 +208,7 @@ struct pcmcia_socket {
        u_int                           features;
        u_int                           irq_mask;
        u_int                           map_size;
-       kio_addr_t                      io_offset;
+       u_int                           io_offset;
        u_char                          pci_irq;
        struct pci_dev *                cb_dev;
 
index e466d886e19283621c2e6af4f6087ce7eafa2d1e..4769efd4db24ec745cd4f5baff15fcfa76e12e5c 100644 (file)
@@ -176,7 +176,7 @@ struct class_device_attribute class_device_attr_vport_##_name =     \
  * ports has a unique presense on the SAN, and may be instantiated via
  * NPIV, Virtual Fabrics, or via additional ALPAs. As the vport is a
  * unique presense, each vport has it's own view of the fabric,
- * authentication priviledge, and priorities.
+ * authentication privilege, and priorities.
  *
  * A virtual port may support 1 or more FC4 roles. Typically it is a
  * FCP Initiator. It could be a FCP Target, or exist sole for an IP over FC
index d04f9e78c7c130f3732cb7546efa0f617c296853..d9aebdf6db639bd7b2c95dfb3cc9ddc4b0b710a6 100644 (file)
@@ -48,7 +48,7 @@
 #define AD1848_IFACE_CTRL      0x09    /* interface control - bits 7-2 MCE */
 #define AD1848_PIN_CTRL                0x0a    /* pin control */
 #define AD1848_TEST_INIT       0x0b    /* test and initialization */
-#define AD1848_MISC_INFO       0x0c    /* miscellaneaous information */
+#define AD1848_MISC_INFO       0x0c    /* miscellaneous information */
 #define AD1848_LOOPBACK                0x0d    /* loopback control */
 #define AD1848_DATA_UPR_CNT    0x0e    /* playback/capture upper base count */
 #define AD1848_DATA_LWR_CNT    0x0f    /* playback/capture lower base count */
diff --git a/include/sound/ainstr_fm.h b/include/sound/ainstr_fm.h
deleted file mode 100644 (file)
index c4afb1f..0000000
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- *  Advanced Linux Sound Architecture
- *
- *  FM (OPL2/3) Instrument Format
- *  Copyright (c) 2000 Uros Bizjak <uros@kss-loka.si>
- *
- *
- *   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 __SOUND_AINSTR_FM_H
-#define __SOUND_AINSTR_FM_H
-
-#ifndef __KERNEL__
-#include <asm/types.h>
-#include <asm/byteorder.h>
-#endif
-
-/*
- *  share types (share ID 1)
- */
-
-#define FM_SHARE_FILE          0
-
-/*
- * FM operator
- */
-
-struct fm_operator {
-       unsigned char am_vib;
-       unsigned char ksl_level;
-       unsigned char attack_decay;
-       unsigned char sustain_release;
-       unsigned char wave_select;
-};
-
-/*
- *  Instrument
- */
-
-#define FM_PATCH_OPL2  0x01            /* OPL2 2 operators FM instrument */
-#define FM_PATCH_OPL3  0x02            /* OPL3 4 operators FM instrument */
-
-struct fm_instrument {
-       unsigned int share_id[4];       /* share id - zero = no sharing */
-       unsigned char type;             /* instrument type */
-
-       struct fm_operator op[4];
-       unsigned char feedback_connection[2];
-
-       unsigned char echo_delay;
-       unsigned char echo_atten;
-       unsigned char chorus_spread;
-       unsigned char trnsps;
-       unsigned char fix_dur;
-       unsigned char modes;
-       unsigned char fix_key;
-};
-
-/*
- *
- *    Kernel <-> user space
- *    Hardware (CPU) independent section
- *
- *    * = zero or more
- *    + = one or more
- *
- *    fm_xinstrument   FM_STRU_INSTR
- *
- */
-
-#define FM_STRU_INSTR  __cpu_to_be32(('I'<<24)|('N'<<16)|('S'<<8)|'T')
-
-/*
- * FM operator
- */
-
-struct fm_xoperator {
-       __u8 am_vib;
-       __u8 ksl_level;
-       __u8 attack_decay;
-       __u8 sustain_release;
-       __u8 wave_select;
-};
-
-/*
- *  Instrument
- */
-
-struct fm_xinstrument {
-       __u32 stype;                    /* structure type */
-
-       __u32 share_id[4];              /* share id - zero = no sharing */
-       __u8 type;                      /* instrument type */
-
-       struct fm_xoperator op[4];              /* fm operators */
-       __u8 feedback_connection[2];
-
-       __u8 echo_delay;
-       __u8 echo_atten;
-       __u8 chorus_spread;
-       __u8 trnsps;
-       __u8 fix_dur;
-       __u8 modes;
-       __u8 fix_key;
-};
-
-#ifdef __KERNEL__
-
-#include "seq_instr.h"
-
-int snd_seq_fm_init(struct snd_seq_kinstr_ops * ops,
-                   struct snd_seq_kinstr_ops * next);
-
-#endif
-
-/* typedefs for compatibility to user-space */
-typedef struct fm_xoperator fm_xoperator_t;
-typedef struct fm_xinstrument fm_xinstrument_t;
-
-#endif /* __SOUND_AINSTR_FM_H */
diff --git a/include/sound/ainstr_gf1.h b/include/sound/ainstr_gf1.h
deleted file mode 100644 (file)
index b62b665..0000000
+++ /dev/null
@@ -1,229 +0,0 @@
-/*
- *  Advanced Linux Sound Architecture
- *
- *  GF1 (GUS) Patch Instrument Format
- *  Copyright (c) 1994-99 by Jaroslav Kysela <perex@perex.cz>
- *
- *
- *   This program is free software; you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   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 __SOUND_AINSTR_GF1_H
-#define __SOUND_AINSTR_GF1_H
-
-#ifndef __KERNEL__
-#include <asm/types.h>
-#include <asm/byteorder.h>
-#endif
-
-/*
- *  share types (share ID 1)
- */
-
-#define GF1_SHARE_FILE                 0
-
-/*
- *  wave formats
- */
-
-#define GF1_WAVE_16BIT                 0x0001  /* 16-bit wave */
-#define GF1_WAVE_UNSIGNED              0x0002  /* unsigned wave */
-#define GF1_WAVE_INVERT                        0x0002  /* same as unsigned wave */
-#define GF1_WAVE_BACKWARD              0x0004  /* backward mode (maybe used for reverb or ping-ping loop) */
-#define GF1_WAVE_LOOP                  0x0008  /* loop mode */
-#define GF1_WAVE_BIDIR                 0x0010  /* bidirectional mode */
-#define GF1_WAVE_STEREO                        0x0100  /* stereo mode */
-#define GF1_WAVE_ULAW                  0x0200  /* uLaw compression mode */
-
-/*
- *  Wavetable definitions
- */
-
-struct gf1_wave {
-       unsigned int share_id[4];       /* share id - zero = no sharing */
-       unsigned int format;            /* wave format */
-
-       struct {
-               unsigned int number;    /* some other ID for this instrument */
-               unsigned int memory;    /* begin of waveform in onboard memory */
-               unsigned char *ptr;     /* pointer to waveform in system memory */
-       } address;
-
-       unsigned int size;              /* size of waveform in samples */
-       unsigned int start;             /* start offset in samples * 16 (lowest 4 bits - fraction) */
-       unsigned int loop_start;        /* bits loop start offset in samples * 16 (lowest 4 bits - fraction) */
-       unsigned int loop_end;          /* loop start offset in samples * 16 (lowest 4 bits - fraction) */
-       unsigned short loop_repeat;     /* loop repeat - 0 = forever */
-
-       unsigned char flags;            /* GF1 patch flags */
-       unsigned char pad;
-       unsigned int sample_rate;       /* sample rate in Hz */
-       unsigned int low_frequency;     /* low frequency range */
-       unsigned int high_frequency;    /* high frequency range */
-       unsigned int root_frequency;    /* root frequency range */
-       signed short tune;
-       unsigned char balance;
-       unsigned char envelope_rate[6];
-       unsigned char envelope_offset[6];
-       unsigned char tremolo_sweep;
-       unsigned char tremolo_rate;
-       unsigned char tremolo_depth;
-       unsigned char vibrato_sweep;
-       unsigned char vibrato_rate;
-       unsigned char vibrato_depth;
-       unsigned short scale_frequency;
-       unsigned short scale_factor;    /* 0-2048 or 0-2 */
-  
-       struct gf1_wave *next;
-};
-
-/*
- *  Instrument
- */
-
-#define IWFFFF_EXCLUDE_NONE            0x0000  /* exclusion mode - none */
-#define IWFFFF_EXCLUDE_SINGLE          0x0001  /* exclude single - single note from the instrument group */
-#define IWFFFF_EXCLUDE_MULTIPLE                0x0002  /* exclude multiple - stop only same note from this instrument */
-
-#define IWFFFF_EFFECT_NONE             0
-#define IWFFFF_EFFECT_REVERB           1
-#define IWFFFF_EFFECT_CHORUS           2
-#define IWFFFF_EFFECT_ECHO             3
-
-struct gf1_instrument {
-       unsigned short exclusion;
-       unsigned short exclusion_group; /* 0 - none, 1-65535 */
-
-       unsigned char effect1;          /* effect 1 */
-       unsigned char effect1_depth;    /* 0-127 */
-       unsigned char effect2;          /* effect 2 */
-       unsigned char effect2_depth;    /* 0-127 */
-
-       struct gf1_wave *wave;          /* first waveform */
-};
-
-/*
- *
- *    Kernel <-> user space
- *    Hardware (CPU) independent section
- *
- *    * = zero or more
- *    + = one or more
- *
- *    gf1_xinstrument          IWFFFF_STRU_INSTR
- *      +gf1_xwave             IWFFFF_STRU_WAVE
- *
- */
-
-#define GF1_STRU_WAVE          __cpu_to_be32(('W'<<24)|('A'<<16)|('V'<<8)|'E')
-#define GF1_STRU_INSTR         __cpu_to_be32(('I'<<24)|('N'<<16)|('S'<<8)|'T')
-
-/*
- *  Wavetable definitions
- */
-
-struct gf1_xwave {
-       __u32 stype;                    /* structure type */
-
-       __u32 share_id[4];              /* share id - zero = no sharing */
-       __u32 format;                   /* wave format */
-
-       __u32 size;                     /* size of waveform in samples */
-       __u32 start;                    /* start offset in samples * 16 (lowest 4 bits - fraction) */
-       __u32 loop_start;               /* bits loop start offset in samples * 16 (lowest 4 bits - fraction) */
-       __u32 loop_end;                 /* loop start offset in samples * 16 (lowest 4 bits - fraction) */
-       __u16 loop_repeat;              /* loop repeat - 0 = forever */
-
-       __u8 flags;                     /* GF1 patch flags */
-       __u8 pad;
-       __u32 sample_rate;              /* sample rate in Hz */
-       __u32 low_frequency;            /* low frequency range */
-       __u32 high_frequency;           /* high frequency range */
-       __u32 root_frequency;           /* root frequency range */
-       __s16 tune;
-       __u8 balance;
-       __u8 envelope_rate[6];
-       __u8 envelope_offset[6];
-       __u8 tremolo_sweep;
-       __u8 tremolo_rate;
-       __u8 tremolo_depth;
-       __u8 vibrato_sweep;
-       __u8 vibrato_rate;
-       __u8 vibrato_depth;
-       __u16 scale_frequency;
-       __u16 scale_factor;             /* 0-2048 or 0-2 */  
-};
-
-/*
- *  Instrument
- */
-
-struct gf1_xinstrument {
-       __u32 stype;
-       
-       __u16 exclusion;
-       __u16 exclusion_group;          /* 0 - none, 1-65535 */
-
-       __u8 effect1;                   /* effect 1 */
-       __u8 effect1_depth;             /* 0-127 */
-       __u8 effect2;                   /* effect 2 */
-       __u8 effect2_depth;             /* 0-127 */
-};
-
-/*
- *  Instrument info
- */
-
-#define GF1_INFO_ENVELOPE              (1<<0)
-#define GF1_INFO_TREMOLO               (1<<1)
-#define GF1_INFO_VIBRATO               (1<<2)
-
-struct gf1_info {
-       unsigned char flags;            /* supported wave flags */
-       unsigned char pad[3];
-       unsigned int features;          /* supported features */
-       unsigned int max8_len;          /* maximum 8-bit wave length */
-       unsigned int max16_len;         /* maximum 16-bit wave length */
-};
-
-#ifdef __KERNEL__
-
-#include "seq_instr.h"
-
-struct snd_gf1_ops {
-       void *private_data;
-       int (*info)(void *private_data, struct gf1_info *info);
-       int (*put_sample)(void *private_data, struct gf1_wave *wave,
-                         char __user *data, long len, int atomic);
-       int (*get_sample)(void *private_data, struct gf1_wave *wave,
-                         char __user *data, long len, int atomic);
-       int (*remove_sample)(void *private_data, struct gf1_wave *wave,
-                            int atomic);
-       void (*notify)(void *private_data, struct snd_seq_kinstr *instr, int what);
-       struct snd_seq_kinstr_ops kops;
-};
-
-int snd_seq_gf1_init(struct snd_gf1_ops *ops,
-                    void *private_data,
-                    struct snd_seq_kinstr_ops *next);
-
-#endif
-
-/* typedefs for compatibility to user-space */
-typedef struct gf1_xwave gf1_xwave_t;
-typedef struct gf1_xinstrument gf1_xinstrument_t;
-
-#endif /* __SOUND_AINSTR_GF1_H */
diff --git a/include/sound/ainstr_iw.h b/include/sound/ainstr_iw.h
deleted file mode 100644 (file)
index 11bd250..0000000
+++ /dev/null
@@ -1,384 +0,0 @@
-/*
- *  Advanced Linux Sound Architecture
- *
- *  InterWave FFFF Instrument Format
- *  Copyright (c) 1994-99 by Jaroslav Kysela <perex@perex.cz>
- *
- *
- *   This program is free software; you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   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 __SOUND_AINSTR_IW_H
-#define __SOUND_AINSTR_IW_H
-
-#ifndef __KERNEL__
-#include <asm/types.h>
-#include <asm/byteorder.h>
-#endif
-
-/*
- *  share types (share ID 1)
- */
-
-#define IWFFFF_SHARE_FILE              0
-
-/*
- *  wave formats
- */
-
-#define IWFFFF_WAVE_16BIT              0x0001  /* 16-bit wave */
-#define IWFFFF_WAVE_UNSIGNED           0x0002  /* unsigned wave */
-#define IWFFFF_WAVE_INVERT             0x0002  /* same as unsigned wave */
-#define IWFFFF_WAVE_BACKWARD           0x0004  /* backward mode (maybe used for reverb or ping-ping loop) */
-#define IWFFFF_WAVE_LOOP               0x0008  /* loop mode */
-#define IWFFFF_WAVE_BIDIR              0x0010  /* bidirectional mode */
-#define IWFFFF_WAVE_ULAW               0x0020  /* uLaw compressed wave */
-#define IWFFFF_WAVE_RAM                        0x0040  /* wave is _preloaded_ in RAM (it is used for ROM simulation) */
-#define IWFFFF_WAVE_ROM                        0x0080  /* wave is in ROM */
-#define IWFFFF_WAVE_STEREO             0x0100  /* wave is stereo */
-
-/*
- *  Wavetable definitions
- */
-
-struct iwffff_wave {
-       unsigned int share_id[4];       /* share id - zero = no sharing */
-       unsigned int format;            /* wave format */
-
-       struct {
-               unsigned int number;    /* some other ID for this wave */
-               unsigned int memory;    /* begin of waveform in onboard memory */
-               unsigned char *ptr;     /* pointer to waveform in system memory */
-       } address;
-
-       unsigned int size;              /* size of waveform in samples */
-       unsigned int start;             /* start offset in samples * 16 (lowest 4 bits - fraction) */
-       unsigned int loop_start;        /* bits loop start offset in samples * 16 (lowest 4 bits - fraction) */
-       unsigned int loop_end;          /* loop start offset in samples * 16 (lowest 4 bits - fraction) */
-       unsigned short loop_repeat;     /* loop repeat - 0 = forever */
-       unsigned int sample_ratio;      /* sample ratio (44100 * 1024 / rate) */
-       unsigned char attenuation;      /* 0 - 127 (no corresponding midi controller) */
-       unsigned char low_note;         /* lower frequency range for this waveform */
-       unsigned char high_note;        /* higher frequency range for this waveform */
-       unsigned char pad;
-  
-       struct iwffff_wave *next;
-};
-
-/*
- *  Layer
- */
-
-#define IWFFFF_LFO_SHAPE_TRIANGLE      0
-#define IWFFFF_LFO_SHAPE_POSTRIANGLE   1
-
-struct iwffff_lfo {
-       unsigned short freq;            /* (0-2047) 0.01Hz - 21.5Hz */
-       signed short depth;             /* volume +- (0-255) 0.48675dB/step */
-       signed short sweep;             /* 0 - 950 deciseconds */
-       unsigned char shape;            /* see to IWFFFF_LFO_SHAPE_XXXX */
-       unsigned char delay;            /* 0 - 255 deciseconds */
-};
-
-#define IWFFFF_ENV_FLAG_RETRIGGER      0x0001  /* flag - retrigger */
-
-#define IWFFFF_ENV_MODE_ONE_SHOT       0x0001  /* mode - one shot */
-#define IWFFFF_ENV_MODE_SUSTAIN                0x0002  /* mode - sustain */
-#define IWFFFF_ENV_MODE_NO_SUSTAIN     0x0003  /* mode - no sustain */
-
-#define IWFFFF_ENV_INDEX_VELOCITY      0x0001  /* index - velocity */
-#define IWFFFF_ENV_INDEX_FREQUENCY     0x0002  /* index - frequency */
-
-struct iwffff_env_point {
-       unsigned short offset;
-       unsigned short rate;
-};
-
-struct iwffff_env_record {
-       unsigned short nattack;
-       unsigned short nrelease;
-       unsigned short sustain_offset;
-       unsigned short sustain_rate;
-       unsigned short release_rate;
-       unsigned char hirange;
-       unsigned char pad;
-       struct iwffff_env_record *next;
-       /* points are stored here */
-       /* count of points = nattack + nrelease */
-};
-
-struct iwffff_env {
-       unsigned char flags;
-       unsigned char mode;
-       unsigned char index;
-       unsigned char pad;
-       struct iwffff_env_record *record;
-};
-
-#define IWFFFF_LAYER_FLAG_RETRIGGER    0x0001  /* retrigger */
-
-#define IWFFFF_LAYER_VELOCITY_TIME     0x0000  /* velocity mode = time */
-#define IWFFFF_LAYER_VELOCITY_RATE     0x0001  /* velocity mode = rate */
-
-#define IWFFFF_LAYER_EVENT_KUP         0x0000  /* layer event - key up */
-#define IWFFFF_LAYER_EVENT_KDOWN       0x0001  /* layer event - key down */
-#define IWFFFF_LAYER_EVENT_RETRIG      0x0002  /* layer event - retrigger */
-#define IWFFFF_LAYER_EVENT_LEGATO      0x0003  /* layer event - legato */
-
-struct iwffff_layer {
-       unsigned char flags;
-       unsigned char velocity_mode;
-       unsigned char layer_event;
-       unsigned char low_range;        /* range for layer based */
-       unsigned char high_range;       /* on either velocity or frequency */
-       unsigned char pan;              /* pan offset from CC1 (0 left - 127 right) */
-       unsigned char pan_freq_scale;   /* position based on frequency (0-127) */
-       unsigned char attenuation;      /* 0-127 (no corresponding midi controller) */
-       struct iwffff_lfo tremolo;              /* tremolo effect */
-       struct iwffff_lfo vibrato;              /* vibrato effect */
-       unsigned short freq_scale;      /* 0-2048, 1024 is equal to semitone scaling */
-       unsigned char freq_center;      /* center for keyboard frequency scaling */
-       unsigned char pad;
-       struct iwffff_env penv;         /* pitch envelope */
-       struct iwffff_env venv;         /* volume envelope */
-
-       struct iwffff_wave *wave;
-       struct iwffff_layer *next;
-};
-
-/*
- *  Instrument
- */
-
-#define IWFFFF_EXCLUDE_NONE            0x0000  /* exclusion mode - none */
-#define IWFFFF_EXCLUDE_SINGLE          0x0001  /* exclude single - single note from the instrument group */
-#define IWFFFF_EXCLUDE_MULTIPLE                0x0002  /* exclude multiple - stop only same note from this instrument */
-
-#define IWFFFF_LAYER_NONE              0x0000  /* not layered */
-#define IWFFFF_LAYER_ON                        0x0001  /* layered */
-#define IWFFFF_LAYER_VELOCITY          0x0002  /* layered by velocity */
-#define IWFFFF_LAYER_FREQUENCY         0x0003  /* layered by frequency */
-
-#define IWFFFF_EFFECT_NONE             0
-#define IWFFFF_EFFECT_REVERB           1
-#define IWFFFF_EFFECT_CHORUS           2
-#define IWFFFF_EFFECT_ECHO             3
-
-struct iwffff_instrument {
-       unsigned short exclusion;
-       unsigned short layer_type;
-       unsigned short exclusion_group; /* 0 - none, 1-65535 */
-
-       unsigned char effect1;          /* effect 1 */
-       unsigned char effect1_depth;    /* 0-127 */
-       unsigned char effect2;          /* effect 2 */
-       unsigned char effect2_depth;    /* 0-127 */
-
-       struct iwffff_layer *layer;             /* first layer */
-};
-
-/*
- *
- *    Kernel <-> user space
- *    Hardware (CPU) independent section
- *
- *    * = zero or more
- *    + = one or more
- *
- *    iwffff_xinstrument               IWFFFF_STRU_INSTR
- *      +iwffff_xlayer                 IWFFFF_STRU_LAYER
- *        *iwffff_xenv_record          IWFFFF_STRU_ENV_RECT (tremolo)
- *        *iwffff_xenv_record          IWFFFF_STRU_EVN_RECT (vibrato)
- *          +iwffff_xwave              IWFFFF_STRU_WAVE
- *
- */
-
-#define IWFFFF_STRU_WAVE       __cpu_to_be32(('W'<<24)|('A'<<16)|('V'<<8)|'E')
-#define IWFFFF_STRU_ENV_RECP   __cpu_to_be32(('E'<<24)|('N'<<16)|('R'<<8)|'P')
-#define IWFFFF_STRU_ENV_RECV   __cpu_to_be32(('E'<<24)|('N'<<16)|('R'<<8)|'V')
-#define IWFFFF_STRU_LAYER      __cpu_to_be32(('L'<<24)|('A'<<16)|('Y'<<8)|'R')
-#define IWFFFF_STRU_INSTR      __cpu_to_be32(('I'<<24)|('N'<<16)|('S'<<8)|'T')
-
-/*
- *  Wavetable definitions
- */
-
-struct iwffff_xwave {
-       __u32 stype;                    /* structure type */
-
-       __u32 share_id[4];              /* share id - zero = no sharing */
-
-       __u32 format;                   /* wave format */
-       __u32 offset;                   /* offset to ROM (address) */
-
-       __u32 size;                     /* size of waveform in samples */
-       __u32 start;                    /* start offset in samples * 16 (lowest 4 bits - fraction) */
-       __u32 loop_start;               /* bits loop start offset in samples * 16 (lowest 4 bits - fraction) */
-       __u32 loop_end;                 /* loop start offset in samples * 16 (lowest 4 bits - fraction) */
-       __u16 loop_repeat;              /* loop repeat - 0 = forever */
-       __u32 sample_ratio;             /* sample ratio (44100 * 1024 / rate) */
-       __u8 attenuation;               /* 0 - 127 (no corresponding midi controller) */
-       __u8 low_note;                  /* lower frequency range for this waveform */
-       __u8 high_note;                 /* higher frequency range for this waveform */
-       __u8 pad;
-};
-
-/*
- *  Layer
- */
-
-struct iwffff_xlfo {
-       __u16 freq;                     /* (0-2047) 0.01Hz - 21.5Hz */
-       __s16 depth;                    /* volume +- (0-255) 0.48675dB/step */
-       __s16 sweep;                    /* 0 - 950 deciseconds */
-       __u8 shape;                     /* see to ULTRA_IW_LFO_SHAPE_XXXX */
-       __u8 delay;                     /* 0 - 255 deciseconds */
-};
-
-struct iwffff_xenv_point {
-       __u16 offset;
-       __u16 rate;
-};
-
-struct iwffff_xenv_record {
-       __u32 stype;
-       __u16 nattack;
-       __u16 nrelease;
-       __u16 sustain_offset;
-       __u16 sustain_rate;
-       __u16 release_rate;
-       __u8 hirange;
-       __u8 pad;
-       /* points are stored here.. */
-       /* count of points = nattack + nrelease */
-};
-
-struct iwffff_xenv {
-       __u8 flags;
-       __u8 mode;
-       __u8 index;
-       __u8 pad;
-};
-
-struct iwffff_xlayer {
-       __u32 stype;
-       __u8 flags;
-       __u8 velocity_mode;
-       __u8 layer_event;
-       __u8 low_range;                 /* range for layer based */
-       __u8 high_range;                /* on either velocity or frequency */
-       __u8 pan;                       /* pan offset from CC1 (0 left - 127 right) */
-       __u8 pan_freq_scale;            /* position based on frequency (0-127) */
-       __u8 attenuation;               /* 0-127 (no corresponding midi controller) */
-       struct iwffff_xlfo tremolo;             /* tremolo effect */
-       struct iwffff_xlfo vibrato;             /* vibrato effect */
-       __u16 freq_scale;               /* 0-2048, 1024 is equal to semitone scaling */
-       __u8 freq_center;               /* center for keyboard frequency scaling */
-       __u8 pad;
-       struct iwffff_xenv penv;                /* pitch envelope */
-       struct iwffff_xenv venv;                /* volume envelope */
-};
-
-/*
- *  Instrument
- */
-
-struct iwffff_xinstrument {
-       __u32 stype;
-       
-       __u16 exclusion;
-       __u16 layer_type;
-       __u16 exclusion_group;          /* 0 - none, 1-65535 */
-
-       __u8 effect1;                   /* effect 1 */
-       __u8 effect1_depth;             /* 0-127 */
-       __u8 effect2;                   /* effect 2 */
-       __u8 effect2_depth;             /* 0-127 */
-};
-
-/*
- *  ROM support
- *    InterWave ROMs are Little-Endian (x86)
- */
-
-#define IWFFFF_ROM_HDR_SIZE    512
-
-struct iwffff_rom_header {
-       __u8 iwave[8];
-       __u8 revision;
-       __u8 series_number;
-       __u8 series_name[16];
-       __u8 date[10];
-       __u16 vendor_revision_major;
-       __u16 vendor_revision_minor;
-       __u32 rom_size;
-       __u8 copyright[128];
-       __u8 vendor_name[64];
-       __u8 description[128];
-};
-
-/*
- *  Instrument info
- */
-
-#define IWFFFF_INFO_LFO_VIBRATO                (1<<0)
-#define IWFFFF_INFO_LFO_VIBRATO_SHAPE  (1<<1)
-#define IWFFFF_INFO_LFO_TREMOLO                (1<<2)
-#define IWFFFF_INFO_LFO_TREMOLO_SHAPE  (1<<3)
-
-struct iwffff_info {
-       unsigned int format;            /* supported format bits */
-       unsigned int effects;           /* supported effects (1 << IWFFFF_EFFECT*) */
-       unsigned int lfos;              /* LFO effects */
-       unsigned int max8_len;          /* maximum 8-bit wave length */
-       unsigned int max16_len;         /* maximum 16-bit wave length */
-};
-
-#ifdef __KERNEL__
-
-#include "seq_instr.h"
-
-struct snd_iwffff_ops {
-       void *private_data;
-       int (*info)(void *private_data, struct iwffff_info *info);
-       int (*put_sample)(void *private_data, struct iwffff_wave *wave,
-                         char __user *data, long len, int atomic);
-       int (*get_sample)(void *private_data, struct iwffff_wave *wave,
-                         char __user *data, long len, int atomic);
-       int (*remove_sample)(void *private_data, struct iwffff_wave *wave,
-                            int atomic);
-       void (*notify)(void *private_data, struct snd_seq_kinstr *instr, int what);
-       struct snd_seq_kinstr_ops kops;
-};
-
-int snd_seq_iwffff_init(struct snd_iwffff_ops *ops,
-                       void *private_data,
-                        struct snd_seq_kinstr_ops *next);
-
-#endif
-
-/* typedefs for compatibility to user-space */
-typedef struct iwffff_xwave iwffff_xwave_t;
-typedef struct iwffff_xlfo iwffff_xlfo_t;
-typedef struct iwffff_xenv_point iwffff_xenv_point_t;
-typedef struct iwffff_xenv_record iwffff_xenv_record_t;
-typedef struct iwffff_xenv iwffff_xenv_t;
-typedef struct iwffff_xlayer iwffff_xlayer_t;
-typedef struct iwffff_xinstrument iwffff_xinstrument_t;
-typedef struct iwffff_rom_header iwffff_rom_header_t;
-typedef struct iwffff_info iwffff_info_t;
-
-#endif /* __SOUND_AINSTR_IW_H */
diff --git a/include/sound/ainstr_simple.h b/include/sound/ainstr_simple.h
deleted file mode 100644 (file)
index da08e72..0000000
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- *  Advanced Linux Sound Architecture
- *
- *  Simple (MOD player) Instrument Format
- *  Copyright (c) 1994-99 by Jaroslav Kysela <perex@perex.cz>
- *
- *
- *   This program is free software; you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   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 __SOUND_AINSTR_SIMPLE_H
-#define __SOUND_AINSTR_SIMPLE_H
-
-#ifndef __KERNEL__
-#include <asm/types.h>
-#include <asm/byteorder.h>
-#endif
-
-/*
- *  share types (share ID 1)
- */
-
-#define SIMPLE_SHARE_FILE              0
-
-/*
- *  wave formats
- */
-
-#define SIMPLE_WAVE_16BIT              0x0001  /* 16-bit wave */
-#define SIMPLE_WAVE_UNSIGNED           0x0002  /* unsigned wave */
-#define SIMPLE_WAVE_INVERT             0x0002  /* same as unsigned wave */
-#define SIMPLE_WAVE_BACKWARD           0x0004  /* backward mode (maybe used for reverb or ping-ping loop) */
-#define SIMPLE_WAVE_LOOP               0x0008  /* loop mode */
-#define SIMPLE_WAVE_BIDIR              0x0010  /* bidirectional mode */
-#define SIMPLE_WAVE_STEREO             0x0100  /* stereo wave */
-#define SIMPLE_WAVE_ULAW               0x0200  /* uLaw compression mode */
-
-/*
- *  instrument effects
- */
-
-#define SIMPLE_EFFECT_NONE             0
-#define SIMPLE_EFFECT_REVERB           1
-#define SIMPLE_EFFECT_CHORUS           2
-#define SIMPLE_EFFECT_ECHO             3
-
-/*
- *  instrument info
- */
-
-struct simple_instrument_info {
-       unsigned int format;            /* supported format bits */
-       unsigned int effects;           /* supported effects (1 << SIMPLE_EFFECT_*) */
-       unsigned int max8_len;          /* maximum 8-bit wave length */
-       unsigned int max16_len;         /* maximum 16-bit wave length */
-};
-
-/*
- *  Instrument
- */
-
-struct simple_instrument {
-       unsigned int share_id[4];       /* share id - zero = no sharing */
-       unsigned int format;            /* wave format */
-
-       struct {
-               unsigned int number;    /* some other ID for this instrument */
-               unsigned int memory;    /* begin of waveform in onboard memory */
-               unsigned char *ptr;     /* pointer to waveform in system memory */
-       } address;
-
-       unsigned int size;              /* size of waveform in samples */
-       unsigned int start;             /* start offset in samples * 16 (lowest 4 bits - fraction) */
-       unsigned int loop_start;        /* loop start offset in samples * 16 (lowest 4 bits - fraction) */
-       unsigned int loop_end;          /* loop end offset in samples * 16 (lowest 4 bits - fraction) */
-       unsigned short loop_repeat;     /* loop repeat - 0 = forever */
-
-       unsigned char effect1;          /* effect 1 */
-       unsigned char effect1_depth;    /* 0-127 */
-       unsigned char effect2;          /* effect 2 */
-       unsigned char effect2_depth;    /* 0-127 */
-};
-
-/*
- *
- *    Kernel <-> user space
- *    Hardware (CPU) independent section
- *
- *    * = zero or more
- *    + = one or more
- *
- *    simple_xinstrument       SIMPLE_STRU_INSTR
- *
- */
-
-#define SIMPLE_STRU_INSTR      __cpu_to_be32(('I'<<24)|('N'<<16)|('S'<<8)|'T')
-
-/*
- *  Instrument
- */
-
-struct simple_xinstrument {
-       __u32 stype;
-
-       __u32 share_id[4];              /* share id - zero = no sharing */
-       __u32 format;                   /* wave format */
-
-       __u32 size;                     /* size of waveform in samples */
-       __u32 start;                    /* start offset in samples * 16 (lowest 4 bits - fraction) */
-       __u32 loop_start;               /* bits loop start offset in samples * 16 (lowest 4 bits - fraction) */
-       __u32 loop_end;                 /* loop start offset in samples * 16 (lowest 4 bits - fraction) */
-       __u16 loop_repeat;              /* loop repeat - 0 = forever */
-       
-       __u8 effect1;                   /* effect 1 */
-       __u8 effect1_depth;             /* 0-127 */
-       __u8 effect2;                   /* effect 2 */
-       __u8 effect2_depth;             /* 0-127 */
-};
-
-#ifdef __KERNEL__
-
-#include "seq_instr.h"
-
-struct snd_simple_ops {
-       void *private_data;
-       int (*info)(void *private_data, struct simple_instrument_info *info);
-       int (*put_sample)(void *private_data, struct simple_instrument *instr,
-                         char __user *data, long len, int atomic);
-       int (*get_sample)(void *private_data, struct simple_instrument *instr,
-                         char __user *data, long len, int atomic);
-       int (*remove_sample)(void *private_data, struct simple_instrument *instr,
-                            int atomic);
-       void (*notify)(void *private_data, struct snd_seq_kinstr *instr, int what);
-       struct snd_seq_kinstr_ops kops;
-};
-
-int snd_seq_simple_init(struct snd_simple_ops *ops,
-                       void *private_data,
-                       struct snd_seq_kinstr_ops *next);
-
-#endif
-
-/* typedefs for compatibility to user-space */
-typedef struct simple_xinstrument simple_xinstrument_t;
-
-#endif /* __SOUND_AINSTR_SIMPLE_H */
index 891cf1aea8b139db918705149a9e7ffb25760fd5..6153b91cdc3ea4f71e79f9ea44a7550f4995b54b 100644 (file)
@@ -68,7 +68,7 @@ struct snd_akm4xxx {
        enum {
                SND_AK4524, SND_AK4528, SND_AK4529,
                SND_AK4355, SND_AK4358, SND_AK4381,
-               SND_AK5365
+               SND_AK5365, NON_AKM
        } type;
 
        /* (array) information of combined codecs */
index 64daccbe8b29196f7969631bf0d44e69200f2ca3..1505e6d5ef8241081c24c74b6218e01a37afc8d2 100644 (file)
 #define SNDRV_SEQ_EVENT_PORT_SUBSCRIBED        66      /* ports connected */
 #define SNDRV_SEQ_EVENT_PORT_UNSUBSCRIBED 67   /* ports disconnected */
 
-/** synthesizer events
- * event data type = snd_seq_eve_sample_control
- */
-#define SNDRV_SEQ_EVENT_SAMPLE         70      /* sample select */
-#define SNDRV_SEQ_EVENT_SAMPLE_CLUSTER 71      /* sample cluster select */
-#define SNDRV_SEQ_EVENT_SAMPLE_START   72      /* voice start */
-#define SNDRV_SEQ_EVENT_SAMPLE_STOP    73      /* voice stop */
-#define SNDRV_SEQ_EVENT_SAMPLE_FREQ    74      /* playback frequency */
-#define SNDRV_SEQ_EVENT_SAMPLE_VOLUME  75      /* volume and balance */
-#define SNDRV_SEQ_EVENT_SAMPLE_LOOP    76      /* sample loop */
-#define SNDRV_SEQ_EVENT_SAMPLE_POSITION        77      /* sample position */
-#define SNDRV_SEQ_EVENT_SAMPLE_PRIVATE1        78      /* private (hardware dependent) event */
+/* 70-89:  synthesizer events - obsoleted */
 
 /** user-defined events with fixed length
  * event data type = any
 #define SNDRV_SEQ_EVENT_USR8           98
 #define SNDRV_SEQ_EVENT_USR9           99
 
-/** instrument layer
- * variable length data can be passed directly to the driver
- */
-#define SNDRV_SEQ_EVENT_INSTR_BEGIN    100     /* begin of instrument management */
-#define SNDRV_SEQ_EVENT_INSTR_END      101     /* end of instrument management */
-#define SNDRV_SEQ_EVENT_INSTR_INFO     102     /* instrument interface info */
-#define SNDRV_SEQ_EVENT_INSTR_INFO_RESULT 103  /* result */
-#define SNDRV_SEQ_EVENT_INSTR_FINFO    104     /* get format info */
-#define SNDRV_SEQ_EVENT_INSTR_FINFO_RESULT 105 /* get format info */
-#define SNDRV_SEQ_EVENT_INSTR_RESET    106     /* reset instrument memory */
-#define SNDRV_SEQ_EVENT_INSTR_STATUS   107     /* instrument interface status */
-#define SNDRV_SEQ_EVENT_INSTR_STATUS_RESULT 108        /* result */
-#define SNDRV_SEQ_EVENT_INSTR_PUT      109     /* put instrument to port */
-#define SNDRV_SEQ_EVENT_INSTR_GET      110     /* get instrument from port */
-#define SNDRV_SEQ_EVENT_INSTR_GET_RESULT 111   /* result */
-#define SNDRV_SEQ_EVENT_INSTR_FREE     112     /* free instrument(s) */
-#define SNDRV_SEQ_EVENT_INSTR_LIST     113     /* instrument list */
-#define SNDRV_SEQ_EVENT_INSTR_LIST_RESULT 114  /* result */
-#define SNDRV_SEQ_EVENT_INSTR_CLUSTER  115     /* cluster parameters */
-#define SNDRV_SEQ_EVENT_INSTR_CLUSTER_GET 116  /* get cluster parameters */
-#define SNDRV_SEQ_EVENT_INSTR_CLUSTER_RESULT 117 /* result */
-#define SNDRV_SEQ_EVENT_INSTR_CHANGE   118     /* instrument change */
+/* 100-118: instrument layer - obsoleted */
 /* 119-129: reserved */
 
 /* 130-139: variable length events
@@ -258,78 +226,6 @@ struct snd_seq_ev_ext {
        void *ptr;              /* pointer to data (note: maybe 64-bit) */
 } __attribute__((packed));
 
-/* Instrument cluster type */
-typedef unsigned int snd_seq_instr_cluster_t;
-
-/* Instrument type */
-struct snd_seq_instr {
-       snd_seq_instr_cluster_t cluster;
-       unsigned int std;               /* the upper byte means a private instrument (owner - client #) */
-       unsigned short bank;
-       unsigned short prg;
-};
-
-       /* sample number */
-struct snd_seq_ev_sample {
-       unsigned int std;
-       unsigned short bank;
-       unsigned short prg;
-};
-
-       /* sample cluster */
-struct snd_seq_ev_cluster {
-       snd_seq_instr_cluster_t cluster;
-};
-
-       /* sample position */
-typedef unsigned int snd_seq_position_t; /* playback position (in samples) * 16 */
-
-       /* sample stop mode */
-enum {
-       SAMPLE_STOP_IMMEDIATELY = 0,    /* terminate playing immediately */
-       SAMPLE_STOP_VENVELOPE = 1,      /* finish volume envelope */
-       SAMPLE_STOP_LOOP = 2            /* terminate loop and finish wave */
-};
-
-       /* sample frequency */
-typedef int snd_seq_frequency_t; /* playback frequency in HZ * 16 */
-
-       /* sample volume control; if any value is set to -1 == do not change */
-struct snd_seq_ev_volume {
-       signed short volume;    /* range: 0-16383 */
-       signed short lr;        /* left-right balance; range: 0-16383 */
-       signed short fr;        /* front-rear balance; range: 0-16383 */
-       signed short du;        /* down-up balance; range: 0-16383 */
-};
-
-       /* simple loop redefinition */
-struct snd_seq_ev_loop {
-       unsigned int start;     /* loop start (in samples) * 16 */
-       unsigned int end;       /* loop end (in samples) * 16 */
-};
-
-struct snd_seq_ev_sample_control {
-       unsigned char channel;
-       unsigned char unused1, unused2, unused3;        /* pad */
-       union {
-               struct snd_seq_ev_sample sample;
-               struct snd_seq_ev_cluster cluster;
-               snd_seq_position_t position;
-               int stop_mode;
-               snd_seq_frequency_t frequency;
-               struct snd_seq_ev_volume volume;
-               struct snd_seq_ev_loop loop;
-               unsigned char raw8[8];
-       } param;
-};
-
-
-
-/* INSTR_BEGIN event */
-struct snd_seq_ev_instr_begin {
-       int timeout;            /* zero = forever, otherwise timeout in ms */
-};
-
 struct snd_seq_result {
        int event;              /* processed event type */
        int result;
@@ -399,8 +295,6 @@ struct snd_seq_event {
                struct snd_seq_addr addr;
                struct snd_seq_connect connect;
                struct snd_seq_result result;
-               struct snd_seq_ev_instr_begin instr_begin;
-               struct snd_seq_ev_sample_control sample;
                struct snd_seq_ev_quote quote;
        } data;
 };
@@ -441,8 +335,6 @@ struct snd_seq_event_bounce {
 #define snd_seq_ev_is_user_type(ev)    ((ev)->type >= 90 && (ev)->type < 99)
 /* fixed length events: 0-99 */
 #define snd_seq_ev_is_fixed_type(ev)   ((ev)->type < 100)
-/* instrument layer events: 100-129 */
-#define snd_seq_ev_is_instr_type(ev)   ((ev)->type >= 100 && (ev)->type < 130)
 /* variable length events: 130-139 */
 #define snd_seq_ev_is_variable_type(ev)        ((ev)->type >= 130 && (ev)->type < 140)
 /* reserved for kernel */
@@ -737,136 +629,6 @@ struct snd_seq_query_subs {
 };
 
 
-/*
- *  Instrument abstraction layer
- *     - based on events
- */
-
-/* instrument types */
-#define SNDRV_SEQ_INSTR_ATYPE_DATA     0       /* instrument data */
-#define SNDRV_SEQ_INSTR_ATYPE_ALIAS    1       /* instrument alias */
-
-/* instrument ASCII identifiers */
-#define SNDRV_SEQ_INSTR_ID_DLS1                "DLS1"
-#define SNDRV_SEQ_INSTR_ID_DLS2                "DLS2"
-#define SNDRV_SEQ_INSTR_ID_SIMPLE      "Simple Wave"
-#define SNDRV_SEQ_INSTR_ID_SOUNDFONT   "SoundFont"
-#define SNDRV_SEQ_INSTR_ID_GUS_PATCH   "GUS Patch"
-#define SNDRV_SEQ_INSTR_ID_INTERWAVE   "InterWave FFFF"
-#define SNDRV_SEQ_INSTR_ID_OPL2_3      "OPL2/3 FM"
-#define SNDRV_SEQ_INSTR_ID_OPL4                "OPL4"
-
-/* instrument types */
-#define SNDRV_SEQ_INSTR_TYPE0_DLS1     (1<<0)  /* MIDI DLS v1 */
-#define SNDRV_SEQ_INSTR_TYPE0_DLS2     (1<<1)  /* MIDI DLS v2 */
-#define SNDRV_SEQ_INSTR_TYPE1_SIMPLE   (1<<0)  /* Simple Wave */
-#define SNDRV_SEQ_INSTR_TYPE1_SOUNDFONT        (1<<1)  /* EMU SoundFont */
-#define SNDRV_SEQ_INSTR_TYPE1_GUS_PATCH        (1<<2)  /* Gravis UltraSound Patch */
-#define SNDRV_SEQ_INSTR_TYPE1_INTERWAVE        (1<<3)  /* InterWave FFFF */
-#define SNDRV_SEQ_INSTR_TYPE2_OPL2_3   (1<<0)  /* Yamaha OPL2/3 FM */
-#define SNDRV_SEQ_INSTR_TYPE2_OPL4     (1<<1)  /* Yamaha OPL4 */
-
-/* put commands */
-#define SNDRV_SEQ_INSTR_PUT_CMD_CREATE 0
-#define SNDRV_SEQ_INSTR_PUT_CMD_REPLACE        1
-#define SNDRV_SEQ_INSTR_PUT_CMD_MODIFY 2
-#define SNDRV_SEQ_INSTR_PUT_CMD_ADD    3
-#define SNDRV_SEQ_INSTR_PUT_CMD_REMOVE 4
-
-/* get commands */
-#define SNDRV_SEQ_INSTR_GET_CMD_FULL   0
-#define SNDRV_SEQ_INSTR_GET_CMD_PARTIAL        1
-
-/* query flags */
-#define SNDRV_SEQ_INSTR_QUERY_FOLLOW_ALIAS (1<<0)
-
-/* free commands */
-#define SNDRV_SEQ_INSTR_FREE_CMD_ALL           0
-#define SNDRV_SEQ_INSTR_FREE_CMD_PRIVATE       1
-#define SNDRV_SEQ_INSTR_FREE_CMD_CLUSTER       2
-#define SNDRV_SEQ_INSTR_FREE_CMD_SINGLE                3
-
-/* size of ROM/RAM */
-typedef unsigned int snd_seq_instr_size_t;
-
-/* INSTR_INFO */
-
-struct snd_seq_instr_info {
-       int result;                     /* operation result */
-       unsigned int formats[8];        /* bitmap of supported formats */
-       int ram_count;                  /* count of RAM banks */
-       snd_seq_instr_size_t ram_sizes[16]; /* size of RAM banks */
-       int rom_count;                  /* count of ROM banks */
-       snd_seq_instr_size_t rom_sizes[8]; /* size of ROM banks */
-       char reserved[128];
-};
-
-/* INSTR_STATUS */
-
-struct snd_seq_instr_status {
-       int result;                     /* operation result */
-       snd_seq_instr_size_t free_ram[16]; /* free RAM in banks */
-       int instrument_count;           /* count of downloaded instruments */
-       char reserved[128];
-};
-
-/* INSTR_FORMAT_INFO */
-
-struct snd_seq_instr_format_info {
-       char format[16];                /* format identifier - SNDRV_SEQ_INSTR_ID_* */  
-       unsigned int len;               /* max data length (without this structure) */
-};
-
-struct snd_seq_instr_format_info_result {
-       int result;                     /* operation result */
-       char format[16];                /* format identifier */
-       unsigned int len;               /* filled data length (without this structure) */
-};
-
-/* instrument data */
-struct snd_seq_instr_data {
-       char name[32];                  /* instrument name */
-       char reserved[16];              /* for the future use */
-       int type;                       /* instrument type */
-       union {
-               char format[16];        /* format identifier */
-               struct snd_seq_instr alias;
-       } data;
-};
-
-/* INSTR_PUT/GET, data are stored in one block (extended), header + data */
-
-struct snd_seq_instr_header {
-       union {
-               struct snd_seq_instr instr;
-               snd_seq_instr_cluster_t cluster;
-       } id;                           /* instrument identifier */
-       unsigned int cmd;               /* get/put/free command */
-       unsigned int flags;             /* query flags (only for get) */
-       unsigned int len;               /* real instrument data length (without header) */
-       int result;                     /* operation result */
-       char reserved[16];              /* for the future */
-       struct snd_seq_instr_data data; /* instrument data (for put/get result) */
-};
-
-/* INSTR_CLUSTER_SET */
-
-struct snd_seq_instr_cluster_set {
-       snd_seq_instr_cluster_t cluster; /* cluster identifier */
-       char name[32];                  /* cluster name */
-       int priority;                   /* cluster priority */
-       char reserved[64];              /* for the future use */
-};
-
-/* INSTR_CLUSTER_GET */
-
-struct snd_seq_instr_cluster_get {
-       snd_seq_instr_cluster_t cluster; /* cluster identifier */
-       char name[32];                  /* cluster name */
-       int priority;                   /* cluster priority */
-       char reserved[64];              /* for the future use */
-};
-
 /*
  *  IOCTL commands
  */
index af9d11d315e94c272b4eb32a6932b817add375b3..3eaf155b850d8b0c266ea0d930823317033948c8 100644 (file)
@@ -95,7 +95,7 @@ enum {
        SNDRV_HWDEP_IFACE_HDA,          /* HD-audio */
 
        /* Don't forget to change the following: */
-       SNDRV_HWDEP_IFACE_LAST = SNDRV_HWDEP_IFACE_SB_RC
+       SNDRV_HWDEP_IFACE_LAST = SNDRV_HWDEP_IFACE_HDA
 };
 
 struct snd_hwdep_info {
@@ -138,7 +138,7 @@ enum {
  *                                                                           *
  *****************************************************************************/
 
-#define SNDRV_PCM_VERSION              SNDRV_PROTOCOL_VERSION(2, 0, 8)
+#define SNDRV_PCM_VERSION              SNDRV_PROTOCOL_VERSION(2, 0, 9)
 
 typedef unsigned long snd_pcm_uframes_t;
 typedef signed long snd_pcm_sframes_t;
@@ -354,8 +354,8 @@ struct snd_pcm_hw_params {
 
 enum {
        SNDRV_PCM_TSTAMP_NONE = 0,
-       SNDRV_PCM_TSTAMP_MMAP,
-       SNDRV_PCM_TSTAMP_LAST = SNDRV_PCM_TSTAMP_MMAP,
+       SNDRV_PCM_TSTAMP_ENABLE,
+       SNDRV_PCM_TSTAMP_LAST = SNDRV_PCM_TSTAMP_ENABLE,
 };
 
 struct snd_pcm_sw_params {
@@ -363,7 +363,7 @@ struct snd_pcm_sw_params {
        unsigned int period_step;
        unsigned int sleep_min;                 /* min ticks to sleep */
        snd_pcm_uframes_t avail_min;            /* min avail frames for wakeup */
-       snd_pcm_uframes_t xfer_align;           /* xfer size need to be a multiple */
+       snd_pcm_uframes_t xfer_align;           /* obsolete: xfer size need to be a multiple */
        snd_pcm_uframes_t start_threshold;      /* min hw_avail frames for automatic start */
        snd_pcm_uframes_t stop_threshold;       /* min avail frames for automatic stop */
        snd_pcm_uframes_t silence_threshold;    /* min distance from noise for silence filling */
@@ -434,10 +434,17 @@ struct snd_xfern {
        snd_pcm_uframes_t frames;
 };
 
+enum {
+       SNDRV_PCM_TSTAMP_TYPE_GETTIMEOFDAY = 0, /* gettimeofday equivalent */
+       SNDRV_PCM_TSTAMP_TYPE_MONOTONIC,        /* posix_clock_monotonic equivalent */
+       SNDRV_PCM_TSTAMP_TYPE_LAST = SNDRV_PCM_TSTAMP_TYPE_MONOTONIC,
+};
+
 enum {
        SNDRV_PCM_IOCTL_PVERSION = _IOR('A', 0x00, int),
        SNDRV_PCM_IOCTL_INFO = _IOR('A', 0x01, struct snd_pcm_info),
        SNDRV_PCM_IOCTL_TSTAMP = _IOW('A', 0x02, int),
+       SNDRV_PCM_IOCTL_TTSTAMP = _IOW('A', 0x03, int),
        SNDRV_PCM_IOCTL_HW_REFINE = _IOWR('A', 0x10, struct snd_pcm_hw_params),
        SNDRV_PCM_IOCTL_HW_PARAMS = _IOWR('A', 0x11, struct snd_pcm_hw_params),
        SNDRV_PCM_IOCTL_HW_FREE = _IO('A', 0x12),
@@ -689,7 +696,7 @@ struct snd_timer_tread {
  *                                                                          *
  ****************************************************************************/
 
-#define SNDRV_CTL_VERSION              SNDRV_PROTOCOL_VERSION(2, 0, 4)
+#define SNDRV_CTL_VERSION              SNDRV_PROTOCOL_VERSION(2, 0, 5)
 
 struct snd_ctl_card_info {
        int card;                       /* card number */
@@ -738,8 +745,7 @@ typedef int __bitwise snd_ctl_elem_iface_t;
 #define SNDRV_CTL_ELEM_ACCESS_OWNER            (1<<10) /* write lock owner */
 #define SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK     (1<<28) /* kernel use a TLV callback */ 
 #define SNDRV_CTL_ELEM_ACCESS_USER             (1<<29) /* user space element */
-#define SNDRV_CTL_ELEM_ACCESS_DINDIRECT                (1<<30) /* indirect access for matrix dimensions in the info structure */
-#define SNDRV_CTL_ELEM_ACCESS_INDIRECT         (1<<31) /* indirect access for element value in the value structure */
+/* bits 30 and 31 are obsoleted (for indirect access) */
 
 /* for further details see the ACPI and PCI power management specification */
 #define SNDRV_CTL_POWER_D0             0x0000  /* full On */
@@ -793,30 +799,30 @@ struct snd_ctl_elem_info {
        } value;
        union {
                unsigned short d[4];            /* dimensions */
-               unsigned short *d_ptr;          /* indirect */
+               unsigned short *d_ptr;          /* indirect - obsoleted */
        } dimen;
        unsigned char reserved[64-4*sizeof(unsigned short)];
 };
 
 struct snd_ctl_elem_value {
        struct snd_ctl_elem_id id;      /* W: element ID */
-       unsigned int indirect: 1;       /* W: use indirect pointer (xxx_ptr member) */
+       unsigned int indirect: 1;       /* W: indirect access - obsoleted */
         union {
                union {
                        long value[128];
-                       long *value_ptr;
+                       long *value_ptr;        /* obsoleted */
                } integer;
                union {
                        long long value[64];
-                       long long *value_ptr;
+                       long long *value_ptr;   /* obsoleted */
                } integer64;
                union {
                        unsigned int item[128];
-                       unsigned int *item_ptr;
+                       unsigned int *item_ptr; /* obsoleted */
                } enumerated;
                union {
                        unsigned char data[512];
-                       unsigned char *data_ptr;
+                       unsigned char *data_ptr;        /* obsoleted */
                } bytes;
                struct snd_aes_iec958 iec958;
         } value;                /* RO */
index 8fbcab7cc73b6f6b455259295069ab4f9d3dc536..c2a4b967d5be9af90002ef0b3458e8759ae8c49b 100644 (file)
@@ -104,6 +104,8 @@ struct snd_dm_fm_params {
 #define SNDRV_DM_FM_IOCTL_SET_MODE     _IOW('H', 0x25, int)
 /* for OPL3 only */
 #define SNDRV_DM_FM_IOCTL_SET_CONNECTION       _IOW('H', 0x26, int)
+/* SBI patch management */
+#define SNDRV_DM_FM_IOCTL_CLEAR_PATCHES        _IO ('H', 0x40)
 
 #define SNDRV_DM_FM_OSS_IOCTL_RESET            0x20
 #define SNDRV_DM_FM_OSS_IOCTL_PLAY_NOTE                0x21
@@ -112,4 +114,21 @@ struct snd_dm_fm_params {
 #define SNDRV_DM_FM_OSS_IOCTL_SET_MODE         0x24
 #define SNDRV_DM_FM_OSS_IOCTL_SET_OPL          0x25
 
+/*
+ * Patch Record - fixed size for write
+ */
+
+#define FM_KEY_SBI     "SBI\032"
+#define FM_KEY_2OP     "2OP\032"
+#define FM_KEY_4OP     "4OP\032"
+
+struct sbi_patch {
+       unsigned char prog;
+       unsigned char bank;
+       char key[4];
+       char name[25];
+       char extension[7];
+       unsigned char data[32];
+};
+
 #endif /* __SOUND_ASOUND_FM_H */
index 6954836487ed3407e217a3d005057ee77a8ad7c1..4fc0235ad78433a314f4b2f406a47d8e1c5827fc 100644 (file)
  *
  */
 
+#include <linux/module.h>
 #include <linux/sched.h>               /* wake_up() */
 #include <linux/mutex.h>               /* struct mutex */
 #include <linux/rwsem.h>               /* struct rw_semaphore */
 #include <linux/pm.h>                  /* pm_message_t */
 #include <linux/device.h>
 
+/* number of supported soundcards */
+#ifdef CONFIG_SND_DYNAMIC_MINORS
+#define SNDRV_CARDS 32
+#else
+#define SNDRV_CARDS 8          /* don't change - minor numbers */
+#endif
+
+#define CONFIG_SND_MAJOR       116     /* standard configuration */
+
 /* forward declarations */
 #ifdef CONFIG_PCI
 struct pci_dev;
index f1490265c9b833bc40ec112ff2098ebcfd183485..e8d1f3e31f9e5c1eebc42ab6be4cdb9a1d8b3ebf 100644 (file)
@@ -45,7 +45,7 @@
 #define CS4231_IFACE_CTRL      0x09    /* interface control - bits 7-2 MCE */
 #define CS4231_PIN_CTRL                0x0a    /* pin control */
 #define CS4231_TEST_INIT       0x0b    /* test and initialization */
-#define CS4231_MISC_INFO       0x0c    /* miscellaneaous information */
+#define CS4231_MISC_INFO       0x0c    /* miscellaneous information */
 #define CS4231_LOOPBACK                0x0d    /* loopback control */
 #define CS4231_PLY_UPR_CNT     0x0e    /* playback upper base count */
 #define CS4231_PLY_LWR_CNT     0x0f    /* playback lower base count */
index 6b40ee60f4c56d0d3c37db84a15b167eb3881771..e3005a674a2491e121b36e6ce5638bce1819e9b1 100644 (file)
@@ -1708,9 +1708,6 @@ struct snd_cs46xx {
 
        struct gameport *gameport;
 
-#ifdef CONFIG_SND_CS46XX_DEBUG_GPIO
-       int current_gpio;
-#endif
 #ifdef CONFIG_SND_CS46XX_NEW_DSP
        struct mutex spos_mutex;
 
index 5ccb6c5feecbe5e77d23643e484d50f4c8fc19ee..f0359437d01ac8f86a7981d38e596818c6539f5c 100644 (file)
@@ -1,51 +1 @@
-#ifndef __SOUND_DRIVER_H
-#define __SOUND_DRIVER_H
-
-/*
- *  Main header file for the ALSA driver
- *  Copyright (c) 1994-2000 by Jaroslav Kysela <perex@perex.cz>
- *
- *
- *   This program is free software; you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   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
- *
- */
-
-#ifdef ALSA_BUILD
-#include "config.h"
-#endif
-
-
-/* number of supported soundcards */
-#ifdef CONFIG_SND_DYNAMIC_MINORS
-#define SNDRV_CARDS 32
-#else
-#define SNDRV_CARDS 8          /* don't change - minor numbers */
-#endif
-
-#ifndef CONFIG_SND_MAJOR       /* standard configuration */
-#define CONFIG_SND_MAJOR       116
-#endif
-
-#ifndef CONFIG_SND_DEBUG
-#undef CONFIG_SND_DEBUG_MEMORY
-#endif
-
-#ifdef ALSA_BUILD
-#include "adriver.h"
-#endif
-
-#include <linux/module.h>
-
-#endif /* __SOUND_DRIVER_H */
+#warning "This file is deprecated"
index 441aa06dcd6f622ceb7774ef9a54b090ebef2edc..7b7b9b13b4ddd8d04c1cf6392d15c95d58972de0 100644 (file)
 /************************************************************************************************/
 /* EMU1010m HANA Destinations                                                                  */
 /************************************************************************************************/
+/* Hana, original 1010,1212,1820 using Alice2
+ * Destiniations for SRATEX = 1X rates: 44.1 kHz or 48 kHz
+ * 0x00, 0x00-0x0f: 16 EMU32 channels to Alice2
+ * 0x01, 0x10-0x1f: 32 Elink channels to Audio Dock
+ * 0x01, 0x00: Dock DAC 1 Left
+ * 0x01, 0x04: Dock DAC 1 Right
+ * 0x01, 0x08: Dock DAC 2 Left
+ * 0x01, 0x0c: Dock DAC 2 Right
+ * 0x01, 0x10: Dock DAC 3 Left
+ * 0x01, 0x12: PHONES Left
+ * 0x01, 0x14: Dock DAC 3 Right
+ * 0x01, 0x16: PHONES Right
+ * 0x01, 0x18: Dock DAC 4 Left
+ * 0x01, 0x1a: S/PDIF Left
+ * 0x01, 0x1c: Dock DAC 4 Right
+ * 0x01, 0x1e: S/PDIF Right
+ * 0x02, 0x00: Hana S/PDIF Left
+ * 0x02, 0x01: Hana S/PDIF Right
+ * 0x03, 0x00: Hanoa DAC Left
+ * 0x03, 0x01: Hanoa DAC Right
+ * 0x04, 0x00-0x07: Hana ADAT
+ * 0x05, 0x00: I2S0 Left to Alice2
+ * 0x05, 0x01: I2S0 Right to Alice2
+ * 0x06, 0x00: I2S0 Left to Alice2
+ * 0x06, 0x01: I2S0 Right to Alice2
+ * 0x07, 0x00: I2S0 Left to Alice2
+ * 0x07, 0x01: I2S0 Right to Alice2
+ *
+ * Hana2 never released, but used Tina
+ * Not needed.
+ *
+ * Hana3, rev2 1010,1212,1616 using Tina
+ * Destinations for SRATEX = 1X rates: 44.1 kHz or 48 kHz
+ * 0x00, 0x00-0x0f: 16 EMU32A channels to Tina
+ * 0x01, 0x10-0x1f: 32 EDI channels to Micro Dock
+ * 0x01, 0x00: Dock DAC 1 Left
+ * 0x01, 0x04: Dock DAC 1 Right
+ * 0x01, 0x08: Dock DAC 2 Left
+ * 0x01, 0x0c: Dock DAC 2 Right
+ * 0x01, 0x10: Dock DAC 3 Left
+ * 0x01, 0x12: Dock S/PDIF Left
+ * 0x01, 0x14: Dock DAC 3 Right
+ * 0x01, 0x16: Dock S/PDIF Right
+ * 0x01, 0x18-0x1f: Dock ADAT 0-7
+ * 0x02, 0x00: Hana3 S/PDIF Left
+ * 0x02, 0x01: Hana3 S/PDIF Right
+ * 0x03, 0x00: Hanoa DAC Left
+ * 0x03, 0x01: Hanoa DAC Right
+ * 0x04, 0x00-0x07: Hana3 ADAT 0-7
+ * 0x05, 0x00-0x0f: 16 EMU32B channels to Tina
+ * 0x06-0x07: Not used
+ *
+ * HanaLite, rev1 0404 using Alice2
+ * Destiniations for SRATEX = 1X rates: 44.1 kHz or 48 kHz
+ * 0x00, 0x00-0x0f: 16 EMU32 channels to Alice2
+ * 0x01: Not used
+ * 0x02, 0x00: S/PDIF Left
+ * 0x02, 0x01: S/PDIF Right
+ * 0x03, 0x00: DAC Left
+ * 0x03, 0x01: DAC Right
+ * 0x04-0x07: Not used
+ *
+ * HanaLiteLite, rev2 0404 using Alice2
+ * Destiniations for SRATEX = 1X rates: 44.1 kHz or 48 kHz
+ * 0x00, 0x00-0x0f: 16 EMU32 channels to Alice2
+ * 0x01: Not used
+ * 0x02, 0x00: S/PDIF Left
+ * 0x02, 0x01: S/PDIF Right
+ * 0x03, 0x00: DAC Left
+ * 0x03, 0x01: DAC Right
+ * 0x04-0x07: Not used
+ *
+ * Mana, Cardbus 1616 using Tina2
+ * Destinations for SRATEX = 1X rates: 44.1 kHz or 48 kHz
+ * 0x00, 0x00-0x0f: 16 EMU32A channels to Tina2
+ * 0x01, 0x10-0x1f: 32 EDI channels to Micro Dock
+ * 0x01, 0x00: Dock DAC 1 Left
+ * 0x01, 0x04: Dock DAC 1 Right
+ * 0x01, 0x08: Dock DAC 2 Left
+ * 0x01, 0x0c: Dock DAC 2 Right
+ * 0x01, 0x10: Dock DAC 3 Left
+ * 0x01, 0x12: Dock S/PDIF Left
+ * 0x01, 0x14: Dock DAC 3 Right
+ * 0x01, 0x16: Dock S/PDIF Right
+ * 0x01, 0x18-0x1f: Dock ADAT 0-7
+ * 0x02: Not used
+ * 0x03, 0x00: Mana DAC Left
+ * 0x03, 0x01: Mana DAC Right
+ * 0x04, 0x00-0x0f: 16 EMU32B channels to Tina2
+ * 0x05-0x07: Not used
+ *
+ *
+ */
 /* 32-bit destinations of signal in the Hana FPGA. Destinations are either
  * physical outputs of Hana, or outputs going to Alice2 (audigy) for capture
  * - 16 x EMU_DST_ALICE2_EMU32_X.
 #define EMU_DST_ALICE_I2S2_LEFT                0x0700  /* Alice2 I2S2 Left */
 #define EMU_DST_ALICE_I2S2_RIGHT       0x0701  /* Alice2 I2S2 Right */
 
+/* Additional destinations for 1616(M)/Microdock */
+/* Microdock S/PDIF OUT Left, 1st or 48kHz only */
+#define EMU_DST_MDOCK_SPDIF_LEFT1      0x0112
+/* Microdock S/PDIF OUT Left, 2nd or 96kHz */
+#define EMU_DST_MDOCK_SPDIF_LEFT2      0x0113
+/* Microdock S/PDIF OUT Right, 1st or 48kHz only */
+#define EMU_DST_MDOCK_SPDIF_RIGHT1     0x0116
+/* Microdock S/PDIF OUT Right, 2nd or 96kHz  */
+#define EMU_DST_MDOCK_SPDIF_RIGHT2     0x0117
+/* Microdock S/PDIF ADAT 8 channel out +8 to +f */
+#define EMU_DST_MDOCK_ADAT             0x0118
+
+/* Headphone jack on 1010 cardbus? 44.1/48kHz only? */
+#define EMU_DST_MANA_DAC_LEFT          0x0300
+/* Headphone jack on 1010 cardbus? 44.1/48kHz only? */
+#define EMU_DST_MANA_DAC_RIGHT         0x0301
+
 /************************************************************************************************/
 /* EMU1010m HANA Sources                                                                       */
 /************************************************************************************************/
+/* Hana, original 1010,1212,1820 using Alice2
+ * Sources SRATEX = 1X rates: 44.1 kHz or 48 kHz
+ * 0x00,0x00-0x1f: Silence
+ * 0x01, 0x10-0x1f: 32 Elink channels from Audio Dock
+ * 0x01, 0x00: Dock Mic A
+ * 0x01, 0x04: Dock Mic B
+ * 0x01, 0x08: Dock ADC 1 Left
+ * 0x01, 0x0c: Dock ADC 1 Right
+ * 0x01, 0x10: Dock ADC 2 Left
+ * 0x01, 0x14: Dock ADC 2 Right
+ * 0x01, 0x18: Dock ADC 3 Left
+ * 0x01, 0x1c: Dock ADC 3 Right
+ * 0x02, 0x00: Hana ADC Left
+ * 0x02, 0x01: Hana ADC Right
+ * 0x03, 0x00-0x0f: 16 inputs from Alice2 Emu32A output
+ * 0x03, 0x10-0x1f: 16 inputs from Alice2 Emu32B output
+ * 0x04, 0x00-0x07: Hana ADAT
+ * 0x05, 0x00: Hana S/PDIF Left
+ * 0x05, 0x01: Hana S/PDIF Right
+ * 0x06-0x07: Not used
+ *
+ * Hana2 never released, but used Tina
+ * Not needed.
+ *
+ * Hana3, rev2 1010,1212,1616 using Tina
+ * Sources SRATEX = 1X rates: 44.1 kHz or 48 kHz
+ * 0x00,0x00-0x1f: Silence
+ * 0x01, 0x10-0x1f: 32 Elink channels from Audio Dock
+ * 0x01, 0x00: Dock Mic A
+ * 0x01, 0x04: Dock Mic B
+ * 0x01, 0x08: Dock ADC 1 Left
+ * 0x01, 0x0c: Dock ADC 1 Right
+ * 0x01, 0x10: Dock ADC 2 Left
+ * 0x01, 0x12: Dock S/PDIF Left
+ * 0x01, 0x14: Dock ADC 2 Right
+ * 0x01, 0x16: Dock S/PDIF Right
+ * 0x01, 0x18-0x1f: Dock ADAT 0-7
+ * 0x01, 0x18: Dock ADC 3 Left
+ * 0x01, 0x1c: Dock ADC 3 Right
+ * 0x02, 0x00: Hanoa ADC Left
+ * 0x02, 0x01: Hanoa ADC Right
+ * 0x03, 0x00-0x0f: 16 inputs from Tina Emu32A output
+ * 0x03, 0x10-0x1f: 16 inputs from Tina Emu32B output
+ * 0x04, 0x00-0x07: Hana3 ADAT
+ * 0x05, 0x00: Hana3 S/PDIF Left
+ * 0x05, 0x01: Hana3 S/PDIF Right
+ * 0x06-0x07: Not used
+ *
+ * HanaLite, rev1 0404 using Alice2
+ * Sources SRATEX = 1X rates: 44.1 kHz or 48 kHz
+ * 0x00,0x00-0x1f: Silence
+ * 0x01: Not used
+ * 0x02, 0x00: ADC Left
+ * 0x02, 0x01: ADC Right
+ * 0x03, 0x00-0x0f: 16 inputs from Alice2 Emu32A output
+ * 0x03, 0x10-0x1f: 16 inputs from Alice2 Emu32B output
+ * 0x04: Not used
+ * 0x05, 0x00: S/PDIF Left
+ * 0x05, 0x01: S/PDIF Right
+ * 0x06-0x07: Not used
+ *
+ * HanaLiteLite, rev2 0404 using Alice2
+ * Sources SRATEX = 1X rates: 44.1 kHz or 48 kHz
+ * 0x00,0x00-0x1f: Silence
+ * 0x01: Not used
+ * 0x02, 0x00: ADC Left
+ * 0x02, 0x01: ADC Right
+ * 0x03, 0x00-0x0f: 16 inputs from Alice2 Emu32A output
+ * 0x03, 0x10-0x1f: 16 inputs from Alice2 Emu32B output
+ * 0x04: Not used
+ * 0x05, 0x00: S/PDIF Left
+ * 0x05, 0x01: S/PDIF Right
+ * 0x06-0x07: Not used
+ *
+ * Mana, Cardbus 1616 using Tina2
+ * Sources SRATEX = 1X rates: 44.1 kHz or 48 kHz
+ * 0x00,0x00-0x1f: Silence
+ * 0x01, 0x10-0x1f: 32 Elink channels from Audio Dock
+ * 0x01, 0x00: Dock Mic A
+ * 0x01, 0x04: Dock Mic B
+ * 0x01, 0x08: Dock ADC 1 Left
+ * 0x01, 0x0c: Dock ADC 1 Right
+ * 0x01, 0x10: Dock ADC 2 Left
+ * 0x01, 0x12: Dock S/PDIF Left
+ * 0x01, 0x14: Dock ADC 2 Right
+ * 0x01, 0x16: Dock S/PDIF Right
+ * 0x01, 0x18-0x1f: Dock ADAT 0-7
+ * 0x01, 0x18: Dock ADC 3 Left
+ * 0x01, 0x1c: Dock ADC 3 Right
+ * 0x02: Not used
+ * 0x03, 0x00-0x0f: 16 inputs from Tina Emu32A output
+ * 0x03, 0x10-0x1f: 16 inputs from Tina Emu32B output
+ * 0x04-0x07: Not used
+ *
+ */
+
 /* 32-bit sources of signal in the Hana FPGA. The sources are routed to
  * destinations using mixer control for each destination - see emumixer.c
  * Sources are either physical inputs of FPGA,
 #define EMU_SRC_HANA_SPDIF_LEFT2       0x0502  /* Hana SPDIF Left, 2nd or 96kHz */
 #define EMU_SRC_HANA_SPDIF_RIGHT1      0x0501  /* Hana SPDIF Right, 1st or 48kHz only */
 #define EMU_SRC_HANA_SPDIF_RIGHT2      0x0503  /* Hana SPDIF Right, 2nd or 96kHz */
+
+/* Additional inputs for 1616(M)/Microdock */
+/* Microdock S/PDIF Left, 1st or 48kHz only */
+#define EMU_SRC_MDOCK_SPDIF_LEFT1      0x0112
+/* Microdock S/PDIF Left, 2nd or 96kHz */
+#define EMU_SRC_MDOCK_SPDIF_LEFT2      0x0113
+/* Microdock S/PDIF Right, 1st or 48kHz only */
+#define EMU_SRC_MDOCK_SPDIF_RIGHT1     0x0116
+/* Microdock S/PDIF Right, 2nd or 96kHz */
+#define EMU_SRC_MDOCK_SPDIF_RIGHT2     0x0117
+/* Microdock ADAT 8 channel in +8 to +f */
+#define EMU_SRC_MDOCK_ADAT             0x0118
+
 /* 0x600 and 0x700 no used */
 
 /* ------------------- STRUCTURES -------------------- */
@@ -1423,6 +1642,14 @@ struct snd_emu10k1_midi {
        void (*interrupt)(struct snd_emu10k1 *emu, unsigned int status);
 };
 
+enum {
+       EMU_MODEL_SB,
+       EMU_MODEL_EMU1010,
+       EMU_MODEL_EMU1010B,
+       EMU_MODEL_EMU1616,
+       EMU_MODEL_EMU0404,
+};
+
 struct snd_emu_chip_details {
        u32 vendor;
        u32 device;
@@ -1439,7 +1666,7 @@ struct snd_emu_chip_details {
        unsigned char spdif_bug;    /* Has Spdif phasing bug */
        unsigned char ac97_chip;    /* Has an AC97 chip: 1 = mandatory, 2 = optional */
        unsigned char ecard;        /* APS EEPROM */
-       unsigned char emu1010;     /* EMU 1010m card */
+       unsigned char emu_model;     /* EMU model type */
        unsigned char spi_dac;      /* SPI interface for DAC */
        unsigned char i2c_adc;      /* I2C interface for ADC */
        unsigned char adc_1361t;    /* Use Philips 1361T ADC */
@@ -1515,6 +1742,8 @@ struct snd_emu10k1 {
        spinlock_t reg_lock;
        spinlock_t emu_lock;
        spinlock_t voice_lock;
+       spinlock_t spi_lock; /* serialises access to spi port */
+       spinlock_t i2c_lock; /* serialises access to i2c port */
 
        struct snd_emu10k1_voice voices[NUM_G];
        struct snd_emu10k1_voice p16v_voices[4];
index e5433d8b78bc5b692e40a08aa71bb81771739477..841bb8df38c1af1caacacba848aa9fb4b677be72 100644 (file)
 #include "timer.h"
 #include "seq_midi_emul.h"
 #include "seq_device.h"
-#include "ainstr_iw.h"
-#include "ainstr_gf1.h"
-#include "ainstr_simple.h"
 #include <asm/io.h>
 
-#define SNDRV_SEQ_DEV_ID_GUS                   "gus-synth"
-
 /* IO ports */
 
 #define GUSP(gus, x)                   ((gus)->gf1.port + SNDRV_g_u_s_##x)
@@ -234,16 +229,6 @@ struct snd_gus_port {
 
 struct snd_gus_voice;
 
-struct snd_gus_sample_ops {
-       void (*sample_start)(struct snd_gus_card *gus, struct snd_gus_voice *voice, snd_seq_position_t position);
-       void (*sample_stop)(struct snd_gus_card *gus, struct snd_gus_voice *voice, int mode);
-       void (*sample_freq)(struct snd_gus_card *gus, struct snd_gus_voice *voice, snd_seq_frequency_t freq);
-       void (*sample_volume)(struct snd_gus_card *gus, struct snd_gus_voice *voice, struct snd_seq_ev_volume *volume);
-       void (*sample_loop)(struct snd_gus_card *card, struct snd_gus_voice *voice, struct snd_seq_ev_loop *loop);
-       void (*sample_pos)(struct snd_gus_card *card, struct snd_gus_voice *voice, snd_seq_position_t position);
-       void (*sample_private1)(struct snd_gus_card *card, struct snd_gus_voice *voice, unsigned char *data);
-};
-
 #define SNDRV_GF1_VOICE_TYPE_PCM       0
 #define SNDRV_GF1_VOICE_TYPE_SYNTH     1
 #define SNDRV_GF1_VOICE_TYPE_MIDI      2
@@ -284,12 +269,8 @@ struct snd_gus_voice {
 
        struct snd_gus_sample_ops *sample_ops;
 
-       struct snd_seq_instr instr;
-
        /* running status / registers */
 
-       struct snd_seq_ev_volume sample_volume;
-
        unsigned short fc_register;
        unsigned short fc_lfo;
        unsigned short gf1_volume;
@@ -382,10 +363,6 @@ struct snd_gf1 {
 
        int seq_client;
        struct snd_gus_port seq_ports[4];
-       struct snd_seq_kinstr_list *ilist;
-       struct snd_iwffff_ops iwffff_ops;
-       struct snd_gf1_ops gf1_ops;
-       struct snd_simple_ops simple_ops;
 
        /* timer */
 
@@ -458,8 +435,6 @@ struct snd_gus_card {
        struct snd_rawmidi_substream *midi_substream_output;
        struct snd_rawmidi_substream *midi_substream_input;
 
-       struct snd_seq_device *seq_dev;
-
        spinlock_t reg_lock;
        spinlock_t voice_alloc;
        spinlock_t active_voice_lock;
@@ -647,48 +622,10 @@ void snd_gus_irq_profile_init(struct snd_gus_card *gus);
 
 int snd_gf1_rawmidi_new(struct snd_gus_card * gus, int device, struct snd_rawmidi **rrawmidi);
 
-#if 0
-extern void snd_engine_instrument_register(unsigned short mode,
-               struct _SND_INSTRUMENT_VOICE_COMMANDS *voice_cmds,
-               struct _SND_INSTRUMENT_NOTE_COMMANDS *note_cmds,
-               struct _SND_INSTRUMENT_CHANNEL_COMMANDS *channel_cmds);
-extern int snd_engine_instrument_register_ask(unsigned short mode);
-#endif
-
 /* gus_dram.c */
 int snd_gus_dram_write(struct snd_gus_card *gus, char __user *ptr,
                       unsigned int addr, unsigned int size);
 int snd_gus_dram_read(struct snd_gus_card *gus, char __user *ptr,
                      unsigned int addr, unsigned int size, int rom);
 
-#if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE)
-
-/* gus_sample.c */
-void snd_gus_sample_event(struct snd_seq_event *ev, struct snd_gus_port *p);
-
-/* gus_simple.c */
-void snd_gf1_simple_init(struct snd_gus_voice *voice);
-
-/* gus_instr.c */
-int snd_gus_iwffff_put_sample(void *private_data, struct iwffff_wave *wave,
-                             char __user *data, long len, int atomic);
-int snd_gus_iwffff_get_sample(void *private_data, struct iwffff_wave *wave,
-                             char __user *data, long len, int atomic);
-int snd_gus_iwffff_remove_sample(void *private_data, struct iwffff_wave *wave,
-                                int atomic);
-int snd_gus_gf1_put_sample(void *private_data, struct gf1_wave *wave,
-                          char __user *data, long len, int atomic);
-int snd_gus_gf1_get_sample(void *private_data, struct gf1_wave *wave,
-                          char __user *data, long len, int atomic);
-int snd_gus_gf1_remove_sample(void *private_data, struct gf1_wave *wave,
-                             int atomic);
-int snd_gus_simple_put_sample(void *private_data, struct simple_instrument *instr,
-                             char __user *data, long len, int atomic);
-int snd_gus_simple_get_sample(void *private_data, struct simple_instrument *instr,
-                             char __user *data, long len, int atomic);
-int snd_gus_simple_remove_sample(void *private_data, struct simple_instrument *instr,
-                                int atomic);
-
-#endif /* CONFIG_SND_SEQUENCER */
-
 #endif /* __SOUND_GUS_H */
index fecbb1ffd5405ed628cd8f3aafce40318cf7b4fe..8ae72e74f898714979e6d1f6d79ae32dd683343a 100644 (file)
@@ -100,8 +100,10 @@ int snd_info_minor_unregister(void);
 extern struct snd_info_entry *snd_seq_root;
 #ifdef CONFIG_SND_OSSEMUL
 extern struct snd_info_entry *snd_oss_root;
+void snd_card_info_read_oss(struct snd_info_buffer *buffer);
 #else
 #define snd_oss_root NULL
+static inline void snd_card_info_read_oss(struct snd_info_buffer *buffer) {}
 #endif
 
 int snd_iprintf(struct snd_info_buffer * buffer, char *fmt,...) __attribute__ ((format (printf, 2, 3)));
index 1d14b3f8239353aa14168dc27721a8a621fe99c6..a0c5febdc4ea6b2d93019e581bcda575da7a6c7d 100644 (file)
  *
  */
 
-#include "driver.h"
-#include <linux/time.h>
-#include <linux/mutex.h>
-#include "core.h"
-#include "hwdep.h"
-#include "timer.h"
-#include "seq_midi_emul.h"
+#include <sound/core.h>
+#include <sound/hwdep.h>
+#include <sound/timer.h>
+#include <sound/seq_midi_emul.h>
 #ifdef CONFIG_SND_SEQUENCER_OSS
-#include "seq_oss.h"
-#include "seq_oss_legacy.h"
+#include <sound/seq_oss.h>
+#include <sound/seq_oss_legacy.h>
 #endif
-#include "seq_device.h"
-#include "ainstr_fm.h"
+#include <sound/seq_device.h>
+#include <sound/asound_fm.h>
 
 /*
  *    Register numbers for the global registers
 
 struct snd_opl3;
 
+/*
+ * Instrument record, aka "Patch"
+ */
+
+/* FM operator */
+struct fm_operator {
+       unsigned char am_vib;
+       unsigned char ksl_level;
+       unsigned char attack_decay;
+       unsigned char sustain_release;
+       unsigned char wave_select;
+} __attribute__((packed));
+
+/* Instrument data */
+struct fm_instrument {
+       struct fm_operator op[4];
+       unsigned char feedback_connection[2];
+       unsigned char echo_delay;
+       unsigned char echo_atten;
+       unsigned char chorus_spread;
+       unsigned char trnsps;
+       unsigned char fix_dur;
+       unsigned char modes;
+       unsigned char fix_key;
+};
+
+/* type */
+#define FM_PATCH_OPL2  0x01            /* OPL2 2 operators FM instrument */
+#define FM_PATCH_OPL3  0x02            /* OPL3 4 operators FM instrument */
+
+/* Instrument record */
+struct fm_patch {
+       unsigned char prog;
+       unsigned char bank;
+       unsigned char type;
+       struct fm_instrument inst;
+       char name[24];
+       struct fm_patch *next;
+};
+
+
 /*
  * A structure to keep track of each hardware voice
  */
@@ -277,9 +315,9 @@ struct snd_opl3 {
        void *private_data;
        void (*private_free)(struct snd_opl3 *);
 
+       struct snd_hwdep *hwdep;
        spinlock_t reg_lock;
        struct snd_card *card;          /* The card that this belongs to */
-       int used;                       /* usage flag - exclusive */
        unsigned char fm_mode;          /* OPL mode, see SNDRV_DM_FM_MODE_XXX */
        unsigned char rhythm;           /* percussion mode flag */
        unsigned char max_voices;       /* max number of voices */
@@ -297,8 +335,8 @@ struct snd_opl3 {
        struct snd_midi_channel_set * oss_chset;
 #endif
  
-       struct snd_seq_kinstr_ops fm_ops;
-       struct snd_seq_kinstr_list *ilist;
+#define OPL3_PATCH_HASH_SIZE   32
+       struct fm_patch *patch_table[OPL3_PATCH_HASH_SIZE];
 
        struct snd_opl3_voice voices[MAX_OPL3_VOICES]; /* Voices (OPL3 'channel') */
        int use_time;                   /* allocation counter */
@@ -312,7 +350,6 @@ struct snd_opl3 {
        int sys_timer_status;           /* system timer run status */
        spinlock_t sys_timer_lock;      /* Lock for system timer access */
 #endif
-       struct mutex access_mutex;      /* locking */
 };
 
 /* opl3.c */
@@ -333,8 +370,19 @@ int snd_opl3_hwdep_new(struct snd_opl3 * opl3, int device, int seq_device,
 int snd_opl3_open(struct snd_hwdep * hw, struct file *file);
 int snd_opl3_ioctl(struct snd_hwdep * hw, struct file *file,
                   unsigned int cmd, unsigned long arg);
+long snd_opl3_write(struct snd_hwdep *hw, const char __user *buf, long count,
+                   loff_t *offset);
 int snd_opl3_release(struct snd_hwdep * hw, struct file *file);
 
 void snd_opl3_reset(struct snd_opl3 * opl3);
 
+int snd_opl3_load_patch(struct snd_opl3 *opl3,
+                       int prog, int bank, int type,
+                       const char *name,
+                       const unsigned char *ext,
+                       const unsigned char *data);
+struct fm_patch *snd_opl3_find_patch(struct snd_opl3 *opl3, int prog, int bank,
+                                    int create_patch);
+void snd_opl3_clear_patches(struct snd_opl3 *opl3);
+
 #endif /* __SOUND_OPL3_H */
index 5e9cc460075efa5ee9726d0cb282218f67355100..51d58ccda2d82d7158cbca22fb338bafa393c0e0 100644 (file)
@@ -274,7 +274,6 @@ struct snd_pcm_runtime {
        snd_pcm_uframes_t period_size;  /* period size */
        unsigned int periods;           /* periods */
        snd_pcm_uframes_t buffer_size;  /* buffer size */
-       unsigned int tick_time;         /* tick time */
        snd_pcm_uframes_t min_align;    /* Min alignment for the format */
        size_t byte_align;
        unsigned int frame_bits;
@@ -286,8 +285,6 @@ struct snd_pcm_runtime {
        /* -- SW params -- */
        int tstamp_mode;                /* mmap timestamp is updated */
        unsigned int period_step;
-       unsigned int sleep_min;         /* min ticks to sleep */
-       snd_pcm_uframes_t xfer_align;   /* xfer size need to be a multiple */
        snd_pcm_uframes_t start_threshold;
        snd_pcm_uframes_t stop_threshold;
        snd_pcm_uframes_t silence_threshold; /* Silence filling happens when
@@ -306,7 +303,6 @@ struct snd_pcm_runtime {
 
        /* -- locking / scheduling -- */
        wait_queue_head_t sleep;
-       struct timer_list tick_timer;
        struct fasync_struct *fasync;
 
        /* -- private section -- */
@@ -323,6 +319,7 @@ struct snd_pcm_runtime {
 
        /* -- timer -- */
        unsigned int timer_resolution;  /* timer resolution */
+       int tstamp_type;                /* timestamp type */
 
        /* -- DMA -- */           
        unsigned char *dma_area;        /* DMA area */
@@ -810,7 +807,6 @@ static inline const struct snd_interval *hw_param_interval_c(const struct snd_pc
 #define params_periods(p) hw_param_interval((p), SNDRV_PCM_HW_PARAM_PERIODS)->min
 #define params_buffer_size(p) hw_param_interval((p), SNDRV_PCM_HW_PARAM_BUFFER_SIZE)->min
 #define params_buffer_bytes(p) hw_param_interval((p), SNDRV_PCM_HW_PARAM_BUFFER_BYTES)->min
-#define params_tick_time(p) hw_param_interval((p), SNDRV_PCM_HW_PARAM_TICK_TIME)->min
 
 
 int snd_interval_refine(struct snd_interval *i, const struct snd_interval *v);
@@ -908,9 +904,6 @@ int snd_pcm_capture_xrun_check(struct snd_pcm_substream *substream);
 int snd_pcm_playback_xrun_asap(struct snd_pcm_substream *substream);
 int snd_pcm_capture_xrun_asap(struct snd_pcm_substream *substream);
 void snd_pcm_playback_silence(struct snd_pcm_substream *substream, snd_pcm_uframes_t new_hw_ptr);
-void snd_pcm_tick_prepare(struct snd_pcm_substream *substream);
-void snd_pcm_tick_set(struct snd_pcm_substream *substream, unsigned long ticks);
-void snd_pcm_tick_elapsed(struct snd_pcm_substream *substream);
 void snd_pcm_period_elapsed(struct snd_pcm_substream *substream);
 snd_pcm_sframes_t snd_pcm_lib_write(struct snd_pcm_substream *substream,
                                    const void __user *buf,
@@ -952,6 +945,15 @@ void snd_pcm_timer_resolution_change(struct snd_pcm_substream *substream);
 void snd_pcm_timer_init(struct snd_pcm_substream *substream);
 void snd_pcm_timer_done(struct snd_pcm_substream *substream);
 
+static inline void snd_pcm_gettime(struct snd_pcm_runtime *runtime,
+                                  struct timespec *tv)
+{
+       if (runtime->tstamp_type == SNDRV_PCM_TSTAMP_TYPE_MONOTONIC)
+               do_posix_clock_monotonic_gettime(tv);
+       else
+               getnstimeofday(tv);
+}
+
 /*
  *  Memory
  */
diff --git a/include/sound/seq_instr.h b/include/sound/seq_instr.h
deleted file mode 100644 (file)
index 93b0c51..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-#ifndef __SOUND_SEQ_INSTR_H
-#define __SOUND_SEQ_INSTR_H
-
-/*
- *  Main kernel header file for the ALSA sequencer
- *  Copyright (c) 1999 by Jaroslav Kysela <perex@perex.cz>
- *
- *
- *   This program is free software; you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   the Free Software Foundation; either version 2 of the License, or
- *   (at your option) any later version.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program; if not, write to the Free Software
- *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
- *
- */
-#include "seq_kernel.h"
-
-/* Instrument cluster */
-struct snd_seq_kcluster {
-       snd_seq_instr_cluster_t cluster;
-       char name[32];
-       int priority;
-       struct snd_seq_kcluster *next;
-};
-
-/* return pointer to private data */
-#define KINSTR_DATA(kinstr)    (void *)(((char *)kinstr) + sizeof(struct snd_seq_kinstr))
-
-/* Instrument structure */
-struct snd_seq_kinstr {
-       struct snd_seq_instr instr;
-       char name[32];
-       int type;                       /* instrument type */
-       int use;                        /* use count */
-       int busy;                       /* not useable */
-       int add_len;                    /* additional length */
-       struct snd_seq_kinstr_ops *ops; /* operations */
-       struct snd_seq_kinstr *next;
-};
-
-#define SNDRV_SEQ_INSTR_HASH_SIZE              32
-
-/* Instrument flags */
-#define SNDRV_SEQ_INSTR_FLG_DIRECT     (1<<0)  /* accept only direct events */
-
-/* List of all instruments */
-struct snd_seq_kinstr_list {
-       struct snd_seq_kinstr *hash[SNDRV_SEQ_INSTR_HASH_SIZE];
-       int count;                      /* count of all instruments */
-       
-       struct snd_seq_kcluster *chash[SNDRV_SEQ_INSTR_HASH_SIZE];
-       int ccount;                     /* count of all clusters */
-
-       int owner;                      /* current owner of the instrument list */
-       unsigned int flags;
-
-       spinlock_t lock;
-       spinlock_t ops_lock;
-       struct mutex ops_mutex;
-       unsigned long ops_flags;
-};
-
-#define SNDRV_SEQ_INSTR_NOTIFY_REMOVE  0
-#define SNDRV_SEQ_INSTR_NOTIFY_CHANGE  1
-
-struct snd_seq_kinstr_ops {
-       void *private_data;
-       long add_len;                   /* additional length */
-       char *instr_type;
-       int (*info)(void *private_data, char *info_data, long len);
-       int (*put)(void *private_data, struct snd_seq_kinstr *kinstr,
-                  char __user *instr_data, long len, int atomic, int cmd);
-       int (*get)(void *private_data, struct snd_seq_kinstr *kinstr,
-                  char __user *instr_data, long len, int atomic, int cmd);
-       int (*get_size)(void *private_data, struct snd_seq_kinstr *kinstr, long *size);
-       int (*remove)(void *private_data, struct snd_seq_kinstr *kinstr, int atomic);
-       void (*notify)(void *private_data, struct snd_seq_kinstr *kinstr, int what);
-       struct snd_seq_kinstr_ops *next;
-};
-
-
-/* instrument operations */
-struct snd_seq_kinstr_list *snd_seq_instr_list_new(void);
-void snd_seq_instr_list_free(struct snd_seq_kinstr_list **list);
-int snd_seq_instr_list_free_cond(struct snd_seq_kinstr_list *list,
-                                struct snd_seq_instr_header *ifree,
-                                int client,
-                                int atomic);
-struct snd_seq_kinstr *snd_seq_instr_find(struct snd_seq_kinstr_list *list,
-                                         struct snd_seq_instr *instr,
-                                         int exact,
-                                         int follow_alias);
-void snd_seq_instr_free_use(struct snd_seq_kinstr_list *list,
-                           struct snd_seq_kinstr *instr);
-int snd_seq_instr_event(struct snd_seq_kinstr_ops *ops,
-                       struct snd_seq_kinstr_list *list,
-                       struct snd_seq_event *ev,
-                       int client,
-                       int atomic,
-                       int hop);
-
-#endif /* __SOUND_SEQ_INSTR_H */
index 2b1ae8edc43cfc5215831679dbb88aafd5ccfc6c..a105b01e06d50dc3ccb8b8bcb527d64ea9b7cbe8 100644 (file)
@@ -22,7 +22,7 @@
 #define SND_SOC_NOPM   -1
 
 /*
- * SoC dynamic audio power managment
+ * SoC dynamic audio power management
  *
  * We can have upto 4 power domains
  *     1. Codec domain - VREF, VMID
        .shift = wshift, .invert = winvert}
 
 /* dapm kcontrol types */
-#define SOC_DAPM_SINGLE(xname, reg, shift, mask, invert) \
+#define SOC_DAPM_SINGLE(xname, reg, shift, max, invert) \
 {      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
        .info = snd_soc_info_volsw, \
        .get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw, \
-       .private_value =  SOC_SINGLE_VALUE(reg, shift, mask, invert) }
-#define SOC_DAPM_DOUBLE(xname, reg, shift_left, shift_right, mask, invert, \
+       .private_value =  SOC_SINGLE_VALUE(reg, shift, max, invert) }
+#define SOC_DAPM_DOUBLE(xname, reg, shift_left, shift_right, max, invert, \
        power) \
 {      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
        .info = snd_soc_info_volsw, \
        .get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw, \
        .private_value = (reg) | ((shift_left) << 8) | ((shift_right) << 12) |\
-                ((mask) << 16) | ((invert) << 24) }
+               ((max) << 16) | ((invert) << 24) }
+#define SOC_DAPM_SINGLE_TLV(xname, reg, shift, max, invert, tlv_array) \
+{      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+       .info = snd_soc_info_volsw, \
+       .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | SNDRV_CTL_ELEM_ACCESS_READWRITE,\
+       .tlv.p = (tlv_array), \
+       .get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw, \
+       .private_value =  SOC_SINGLE_VALUE(reg, shift, max, invert) }
+#define SOC_DAPM_DOUBLE_TLV(xname, reg, shift_left, shift_right, max, invert, \
+       power, tlv_array) \
+{      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
+       .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | SNDRV_CTL_ELEM_ACCESS_READWRITE,\
+       .tlv.p = (tlv_array), \
+       .info = snd_soc_info_volsw, \
+       .get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw, \
+       .private_value = (reg) | ((shift_left) << 8) | ((shift_right) << 12) |\
+               ((max) << 16) | ((invert) << 24) }
 #define SOC_DAPM_ENUM(xname, xenum) \
 {      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
        .info = snd_soc_info_enum_double, \
@@ -199,6 +215,7 @@ void snd_soc_dapm_free(struct snd_soc_device *socdev);
 /* dapm events */
 int snd_soc_dapm_stream_event(struct snd_soc_codec *codec, char *stream,
        int event);
+int snd_soc_dapm_device_event(struct snd_soc_device *socdev, int event);
 
 /* dapm sys fs - used by the core */
 int snd_soc_dapm_sys_add(struct device *dev);
@@ -272,7 +289,7 @@ struct snd_soc_dapm_widget {
 
        /* external events */
        unsigned short event_flags;             /* flags to specify event types */
-       int (*event)(struct snd_soc_dapm_widget*, int);
+       int (*event)(struct snd_soc_dapm_widget*, struct snd_kcontrol *, int);
 
        /* kcontrols that relate to this widget */
        int num_kcontrols;
index f47ef1f75f18107a92e86e69f864ea1e6b0aec47..e6ea6f7509414566c2327a841e206b7249cbaa2c 100644 (file)
 #include <linux/platform_device.h>
 #include <linux/types.h>
 #include <linux/workqueue.h>
-#include <sound/driver.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/control.h>
 #include <sound/ac97_codec.h>
 
-#define SND_SOC_VERSION "0.13.1"
+#define SND_SOC_VERSION "0.13.2"
 
 /*
  * Convenience kcontrol builders
  */
-#define SOC_SINGLE_VALUE(reg,shift,mask,invert) ((reg) | ((shift) << 8) |\
-       ((shift) << 12) | ((mask) << 16) | ((invert) << 24))
-#define SOC_SINGLE_VALUE_EXT(reg,mask,invert) ((reg) | ((mask) << 16) |\
+#define SOC_SINGLE_VALUE(reg, shift, max, invert) ((reg) | ((shift) << 8) |\
+       ((shift) << 12) | ((max) << 16) | ((invert) << 24))
+#define SOC_SINGLE_VALUE_EXT(reg, max, invert) ((reg) | ((max) << 16) |\
        ((invert) << 31))
-#define SOC_SINGLE(xname, reg, shift, mask, invert) \
+#define SOC_SINGLE(xname, reg, shift, max, invert) \
 {      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
        .info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\
        .put = snd_soc_put_volsw, \
-       .private_value =  SOC_SINGLE_VALUE(reg, shift, mask, invert) }
-#define SOC_DOUBLE(xname, reg, shift_left, shift_right, mask, invert) \
+       .private_value =  SOC_SINGLE_VALUE(reg, shift, max, invert) }
+#define SOC_SINGLE_TLV(xname, reg, shift, max, invert, tlv_array) \
+{      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+       .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
+                SNDRV_CTL_ELEM_ACCESS_READWRITE,\
+       .tlv.p = (tlv_array), \
+       .info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\
+       .put = snd_soc_put_volsw, \
+       .private_value =  SOC_SINGLE_VALUE(reg, shift, max, invert) }
+#define SOC_DOUBLE(xname, reg, shift_left, shift_right, max, invert) \
 {      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
        .info = snd_soc_info_volsw, .get = snd_soc_get_volsw, \
        .put = snd_soc_put_volsw, \
        .private_value = (reg) | ((shift_left) << 8) | \
-               ((shift_right) << 12) | ((mask) << 16) | ((invert) << 24) }
-#define SOC_DOUBLE_R(xname, reg_left, reg_right, shift, mask, invert) \
+               ((shift_right) << 12) | ((max) << 16) | ((invert) << 24) }
+#define SOC_DOUBLE_R(xname, reg_left, reg_right, shift, max, invert) \
 {      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
        .info = snd_soc_info_volsw_2r, \
        .get = snd_soc_get_volsw_2r, .put = snd_soc_put_volsw_2r, \
        .private_value = (reg_left) | ((shift) << 8)  | \
-               ((mask) << 12) | ((invert) << 20) | ((reg_right) << 24) }
+               ((max) << 12) | ((invert) << 20) | ((reg_right) << 24) }
+#define SOC_DOUBLE_TLV(xname, reg, shift_left, shift_right, max, invert, tlv_array) \
+{      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
+       .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
+                SNDRV_CTL_ELEM_ACCESS_READWRITE,\
+       .tlv.p = (tlv_array), \
+       .info = snd_soc_info_volsw, .get = snd_soc_get_volsw, \
+       .put = snd_soc_put_volsw, \
+       .private_value = (reg) | ((shift_left) << 8) | \
+               ((shift_right) << 12) | ((max) << 16) | ((invert) << 24) }
+#define SOC_DOUBLE_R_TLV(xname, reg_left, reg_right, shift, max, invert, tlv_array) \
+{      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
+       .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
+                SNDRV_CTL_ELEM_ACCESS_READWRITE,\
+       .tlv.p = (tlv_array), \
+       .info = snd_soc_info_volsw_2r, \
+       .get = snd_soc_get_volsw_2r, .put = snd_soc_put_volsw_2r, \
+       .private_value = (reg_left) | ((shift) << 8)  | \
+               ((max) << 12) | ((invert) << 20) | ((reg_right) << 24) }
 #define SOC_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmask, xtexts) \
 {      .reg = xreg, .shift_l = xshift_l, .shift_r = xshift_r, \
        .mask = xmask, .texts = xtexts }
 #define SND_SOC_DAIFMT_CONT                    (0 << 4)        /* continuous clock */
 #define SND_SOC_DAIFMT_GATED           (1 << 4)        /* clock is gated when not Tx/Rx */
 
+/*
+ * DAI Sync
+ * Synchronous LR (Left Right) clocks and Frame signals.
+ */
+#define SND_SOC_DAIFMT_SYNC            (0 << 5)        /* Tx FRM = Rx FRM */
+#define SND_SOC_DAIFMT_ASYNC           (1 << 5)        /* Tx FRM ~ Rx FRM */
+
+/*
+ * TDM
+ */
+#define SND_SOC_DAIFMT_TDM             (1 << 6)
+
 /*
  * DAI hardware signal inversions
  */
-#define SND_SOC_DAIFMT_NB_NF           (0 << 8)        /* normal bit clock + frame */
+#define SND_SOC_DAIFMT_NB_NF           (0 << 8)        /* normal bclk + frm */
 #define SND_SOC_DAIFMT_NB_IF           (1 << 8)        /* normal bclk + inv frm */
 #define SND_SOC_DAIFMT_IB_NF           (2 << 8)        /* invert bclk + nor frm */
 #define SND_SOC_DAIFMT_IB_IF           (3 << 8)        /* invert bclk + frm */
@@ -410,6 +447,9 @@ struct snd_soc_dai_link  {
 
        /* codec/machine specific init - e.g. add machine controls */
        int (*init)(struct snd_soc_codec *codec);
+
+       /* DAI pcm */
+       struct snd_pcm *pcm;
 };
 
 /* SoC machine */
@@ -426,6 +466,9 @@ struct snd_soc_machine {
        int (*resume_pre)(struct platform_device *pdev);
        int (*resume_post)(struct platform_device *pdev);
 
+       /* callbacks */
+       int (*dapm_event)(struct snd_soc_machine *, int event);
+
        /* CPU <--> Codec DAI links  */
        struct snd_soc_dai_link *dai_link;
        int num_links;
index e8eeb3a1ed291fd0aae971cf45d1ced075785bce..b62ce3e077f9176274b80156afdafcd027edfe0c 100644 (file)
@@ -30,6 +30,7 @@ struct snd_tea575x;
 struct snd_tea575x_ops {
        void (*write)(struct snd_tea575x *tea, unsigned int val);
        unsigned int (*read)(struct snd_tea575x *tea);
+       void (*mute)(struct snd_tea575x *tea, unsigned int mute);
 };
 
 struct snd_tea575x {
index 9752243241e58b3524590a4225e6f53255ae0cbb..9f191a0a1e195882819e5b3a79114cb3bc64bcf5 100644 (file)
 #include "pcm.h"
 #include "mpu401.h"
 #include "ac97_codec.h"
-#include "seq_midi_emul.h"
-#include "seq_device.h"
 #include "util_mem.h"
-//#include "ainstr_iw.h"
-//#include "ainstr_gf1.h"
-#include "ainstr_simple.h"
 
 #define TRIDENT_DEVICE_ID_DX           ((PCI_VENDOR_ID_TRIDENT<<16)|PCI_DEVICE_ID_TRIDENT_4DWAVE_DX)
 #define TRIDENT_DEVICE_ID_NX           ((PCI_VENDOR_ID_TRIDENT<<16)|PCI_DEVICE_ID_TRIDENT_4DWAVE_NX)
 #define TRIDENT_DEVICE_ID_SI7018       ((PCI_VENDOR_ID_SI<<16)|PCI_DEVICE_ID_SI_7018)
 
-#define SNDRV_SEQ_DEV_ID_TRIDENT                       "trident-synth"
-
 #define SNDRV_TRIDENT_VOICE_TYPE_PCM           0
 #define SNDRV_TRIDENT_VOICE_TYPE_SYNTH         1
 #define SNDRV_TRIDENT_VOICE_TYPE_MIDI          2
@@ -257,16 +250,6 @@ struct snd_trident;
 struct snd_trident_voice;
 struct snd_trident_pcm_mixer;
 
-struct snd_trident_sample_ops {
-       void (*sample_start)(struct snd_trident *gus, struct snd_trident_voice *voice, snd_seq_position_t position);
-       void (*sample_stop)(struct snd_trident *gus, struct snd_trident_voice *voice, int mode);
-       void (*sample_freq)(struct snd_trident *gus, struct snd_trident_voice *voice, snd_seq_frequency_t freq);
-       void (*sample_volume)(struct snd_trident *gus, struct snd_trident_voice *voice, struct snd_seq_ev_volume *volume);
-       void (*sample_loop)(struct snd_trident *card, struct snd_trident_voice *voice, struct snd_seq_ev_loop *loop);
-       void (*sample_pos)(struct snd_trident *card, struct snd_trident_voice *voice, snd_seq_position_t position);
-       void (*sample_private1)(struct snd_trident *card, struct snd_trident_voice *voice, unsigned char *data);
-};
-
 struct snd_trident_port {
        struct snd_midi_channel_set * chset;
        struct snd_trident * trident;
@@ -300,7 +283,6 @@ struct snd_trident_voice {
        unsigned char port;
        unsigned char index;
 
-       struct snd_seq_instr instr;
        struct snd_trident_sample_ops *sample_ops;
 
        /* channel parameters */
@@ -354,9 +336,6 @@ struct snd_4dwave {
        int seq_client;
 
        struct snd_trident_port seq_ports[4];
-       struct snd_simple_ops simple_ops;
-       struct snd_seq_kinstr_list *ilist;
-
        struct snd_trident_voice voices[64];    
 
        int ChanSynthCount;             /* number of allocated synth channels */
@@ -416,7 +395,6 @@ struct snd_trident {
        struct snd_pcm *foldback;       /* Foldback PCM */
        struct snd_pcm *spdif;  /* SPDIF PCM */
        struct snd_rawmidi *rmidi;
-       struct snd_seq_device *seq_dev;
 
        struct snd_ac97_bus *ac97_bus;
        struct snd_ac97 *ac97;
index a9781eb0da09be35cfcb2e6068a4cf14653028e8..fac66c49445af8379faba913337002aa51e8d742 100644 (file)
@@ -1,3 +1,3 @@
 /* include/version.h.  Generated by alsa/ksync script.  */
-#define CONFIG_SND_VERSION "1.0.15"
-#define CONFIG_SND_DATE " (Tue Nov 20 19:16:42 2007 UTC)"
+#define CONFIG_SND_VERSION "1.0.16rc2"
+#define CONFIG_SND_DATE " (Thu Jan 31 16:40:16 2008 UTC)"
index 0d0bbf218f1f363d2c4732fe7cde4d9ac0909529..87f50df58893ef83c64d2797c934323df08cc9c3 100644 (file)
@@ -582,7 +582,6 @@ config SIGNALFD
 config TIMERFD
        bool "Enable timerfd() system call" if EMBEDDED
        select ANON_INODES
-       depends on BROKEN
        default y
        help
          Enable the timerfd() system call that allows to receive timer
@@ -657,14 +656,36 @@ config SLOB
        depends on EMBEDDED
        bool "SLOB (Simple Allocator)"
        help
-          SLOB replaces the SLAB allocator with a drastically simpler
-          allocator.  SLOB is more space efficient than SLAB but does not
-          scale well (single lock for all operations) and is also highly
-          susceptible to fragmentation. SLUB can accomplish a higher object
-          density. It is usually better to use SLUB instead of SLOB.
+          SLOB replaces the stock allocator with a drastically simpler
+          allocator. SLOB is generally more space efficient but
+          does not perform as well on large systems.
 
 endchoice
 
+config PROFILING
+       bool "Profiling support (EXPERIMENTAL)"
+       help
+         Say Y here to enable the extended profiling support mechanisms used
+         by profilers such as OProfile.
+
+config MARKERS
+       bool "Activate markers"
+       help
+         Place an empty function call at each marker site. Can be
+         dynamically changed for a probe function.
+
+source "arch/Kconfig"
+
+config PROC_PAGE_MONITOR
+       default y
+       depends on PROC_FS && MMU
+       bool "Enable /proc page monitoring" if EMBEDDED
+       help
+         Various /proc files exist to monitor process memory utilization:
+         /proc/pid/smaps, /proc/pid/clear_refs, /proc/pid/pagemap,
+         /proc/kpagecount, and /proc/kpageflags. Disabling these
+          interfaces will reduce the size of the kernel by approximately 4kb.
+
 endmenu                # General setup
 
 config SLABINFO
@@ -775,6 +796,14 @@ config PREEMPT_NOTIFIERS
 choice
        prompt "RCU implementation type:"
        default CLASSIC_RCU
+       help
+         This allows you to choose either the classic RCU implementation
+         that is designed for best read-side performance on non-realtime
+         systems, or the preemptible RCU implementation for best latency
+         on realtime systems.  Note that some kernel preemption modes
+         will restrict your choice.
+
+         Select the default if you are unsure.
 
 config CLASSIC_RCU
        bool "Classic RCU"
diff --git a/kernel/Kconfig.instrumentation b/kernel/Kconfig.instrumentation
deleted file mode 100644 (file)
index 468f47a..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-menuconfig INSTRUMENTATION
-       bool "Instrumentation Support"
-       default y
-       ---help---
-         Say Y here to get to see options related to performance measurement,
-         system-wide debugging, and testing. This option alone does not add any
-         kernel code.
-
-         If you say N, all options in this submenu will be skipped and
-         disabled. If you're trying to debug the kernel itself, go see the
-         Kernel Hacking menu.
-
-if INSTRUMENTATION
-
-config PROFILING
-       bool "Profiling support (EXPERIMENTAL)"
-       help
-         Say Y here to enable the extended profiling support mechanisms used
-         by profilers such as OProfile.
-
-config OPROFILE
-       tristate "OProfile system profiling (EXPERIMENTAL)"
-       depends on PROFILING && !UML
-       depends on ARCH_SUPPORTS_OPROFILE || ALPHA || ARM || BLACKFIN || IA64 || M32R || PARISC || PPC || S390 || SUPERH || SPARC
-       help
-         OProfile is a profiling system capable of profiling the
-         whole system, include the kernel, kernel modules, libraries,
-         and applications.
-
-         If unsure, say N.
-
-config KPROBES
-       bool "Kprobes"
-       depends on KALLSYMS && MODULES && !UML
-       depends on X86_32 || IA64 || PPC || S390 || SPARC64 || X86_64 || AVR32
-       help
-         Kprobes allows you to trap at almost any kernel address and
-         execute a callback function.  register_kprobe() establishes
-         a probepoint and specifies the callback.  Kprobes is useful
-         for kernel debugging, non-intrusive instrumentation and testing.
-         If in doubt, say "N".
-
-config MARKERS
-       bool "Activate markers"
-       help
-         Place an empty function call at each marker site. Can be
-         dynamically changed for a probe function.
-
-endif # INSTRUMENTATION
index 8885627ea02138d58901d6c7d5d1cbda07883ccb..135a1b943446eafe72a1da7f272386749b9b0f35 100644 (file)
@@ -8,8 +8,8 @@ obj-y     = sched.o fork.o exec_domain.o panic.o printk.o profile.o \
            signal.o sys.o kmod.o workqueue.o pid.o \
            rcupdate.o extable.o params.o posix-timers.o \
            kthread.o wait.o kfifo.o sys_ni.o posix-cpu-timers.o mutex.o \
-           hrtimer.o rwsem.o latency.o nsproxy.o srcu.o \
-           utsname.o notifier.o
+           hrtimer.o rwsem.o nsproxy.o srcu.o \
+           utsname.o notifier.o ksysfs.o pm_qos_params.o
 
 obj-$(CONFIG_SYSCTL) += sysctl_check.o
 obj-$(CONFIG_STACKTRACE) += stacktrace.o
@@ -49,7 +49,6 @@ obj-$(CONFIG_AUDIT) += audit.o auditfilter.o
 obj-$(CONFIG_AUDITSYSCALL) += auditsc.o
 obj-$(CONFIG_AUDIT_TREE) += audit_tree.o
 obj-$(CONFIG_KPROBES) += kprobes.o
-obj-$(CONFIG_SYSFS) += ksysfs.o
 obj-$(CONFIG_DETECT_SOFTLOCKUP) += softlockup.o
 obj-$(CONFIG_GENERIC_HARDIRQS) += irq/
 obj-$(CONFIG_SECCOMP) += seccomp.o
index f93c2713017da93b90e5e8d67d029c1b754ffaa0..c8555b18021386b59a089b2e34fe4db355deab40 100644 (file)
  * (Initialization happens after skb_init is called.) */
 static int     audit_initialized;
 
-/* 0 - no auditing
- * 1 - auditing enabled
- * 2 - auditing enabled and configuration is locked/unchangeable. */
+#define AUDIT_OFF      0
+#define AUDIT_ON       1
+#define AUDIT_LOCKED   2
 int            audit_enabled;
+int            audit_ever_enabled;
 
 /* Default state when kernel boots without any parameters. */
 static int     audit_default;
@@ -152,8 +153,10 @@ struct audit_buffer {
 
 static void audit_set_pid(struct audit_buffer *ab, pid_t pid)
 {
-       struct nlmsghdr *nlh = nlmsg_hdr(ab->skb);
-       nlh->nlmsg_pid = pid;
+       if (ab) {
+               struct nlmsghdr *nlh = nlmsg_hdr(ab->skb);
+               nlh->nlmsg_pid = pid;
+       }
 }
 
 void audit_panic(const char *message)
@@ -163,7 +166,8 @@ void audit_panic(const char *message)
        case AUDIT_FAIL_SILENT:
                break;
        case AUDIT_FAIL_PRINTK:
-               printk(KERN_ERR "audit: %s\n", message);
+               if (printk_ratelimit())
+                       printk(KERN_ERR "audit: %s\n", message);
                break;
        case AUDIT_FAIL_PANIC:
                panic("audit: %s\n", message);
@@ -231,161 +235,107 @@ void audit_log_lost(const char *message)
        }
 
        if (print) {
-               printk(KERN_WARNING
-                      "audit: audit_lost=%d audit_rate_limit=%d audit_backlog_limit=%d\n",
-                      atomic_read(&audit_lost),
-                      audit_rate_limit,
-                      audit_backlog_limit);
+               if (printk_ratelimit())
+                       printk(KERN_WARNING
+                               "audit: audit_lost=%d audit_rate_limit=%d "
+                               "audit_backlog_limit=%d\n",
+                               atomic_read(&audit_lost),
+                               audit_rate_limit,
+                               audit_backlog_limit);
                audit_panic(message);
        }
 }
 
-static int audit_set_rate_limit(int limit, uid_t loginuid, u32 sid)
+static int audit_log_config_change(char *function_name, int new, int old,
+                                  uid_t loginuid, u32 sid, int allow_changes)
 {
-       int res, rc = 0, old = audit_rate_limit;
-
-       /* check if we are locked */
-       if (audit_enabled == 2)
-               res = 0;
-       else
-               res = 1;
+       struct audit_buffer *ab;
+       int rc = 0;
 
+       ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE);
+       audit_log_format(ab, "%s=%d old=%d by auid=%u", function_name, new,
+                        old, loginuid);
        if (sid) {
                char *ctx = NULL;
                u32 len;
-               if ((rc = selinux_sid_to_string(sid, &ctx, &len)) == 0) {
-                       audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
-                               "audit_rate_limit=%d old=%d by auid=%u"
-                               " subj=%s res=%d",
-                               limit, old, loginuid, ctx, res);
+
+               rc = selinux_sid_to_string(sid, &ctx, &len);
+               if (rc) {
+                       audit_log_format(ab, " sid=%u", sid);
+                       allow_changes = 0; /* Something weird, deny request */
+               } else {
+                       audit_log_format(ab, " subj=%s", ctx);
                        kfree(ctx);
-               } else
-                       res = 0; /* Something weird, deny request */
+               }
        }
-       audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
-               "audit_rate_limit=%d old=%d by auid=%u res=%d",
-               limit, old, loginuid, res);
-
-       /* If we are allowed, make the change */
-       if (res == 1)
-               audit_rate_limit = limit;
-       /* Not allowed, update reason */
-       else if (rc == 0)
-               rc = -EPERM;
+       audit_log_format(ab, " res=%d", allow_changes);
+       audit_log_end(ab);
        return rc;
 }
 
-static int audit_set_backlog_limit(int limit, uid_t loginuid, u32 sid)
+static int audit_do_config_change(char *function_name, int *to_change,
+                                 int new, uid_t loginuid, u32 sid)
 {
-       int res, rc = 0, old = audit_backlog_limit;
+       int allow_changes, rc = 0, old = *to_change;
 
        /* check if we are locked */
-       if (audit_enabled == 2)
-               res = 0;
+       if (audit_enabled == AUDIT_LOCKED)
+               allow_changes = 0;
        else
-               res = 1;
+               allow_changes = 1;
 
-       if (sid) {
-               char *ctx = NULL;
-               u32 len;
-               if ((rc = selinux_sid_to_string(sid, &ctx, &len)) == 0) {
-                       audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
-                               "audit_backlog_limit=%d old=%d by auid=%u"
-                               " subj=%s res=%d",
-                               limit, old, loginuid, ctx, res);
-                       kfree(ctx);
-               } else
-                       res = 0; /* Something weird, deny request */
+       if (audit_enabled != AUDIT_OFF) {
+               rc = audit_log_config_change(function_name, new, old,
+                                            loginuid, sid, allow_changes);
+               if (rc)
+                       allow_changes = 0;
        }
-       audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
-               "audit_backlog_limit=%d old=%d by auid=%u res=%d",
-               limit, old, loginuid, res);
 
        /* If we are allowed, make the change */
-       if (res == 1)
-               audit_backlog_limit = limit;
+       if (allow_changes == 1)
+               *to_change = new;
        /* Not allowed, update reason */
        else if (rc == 0)
                rc = -EPERM;
        return rc;
 }
 
-static int audit_set_enabled(int state, uid_t loginuid, u32 sid)
+static int audit_set_rate_limit(int limit, uid_t loginuid, u32 sid)
 {
-       int res, rc = 0, old = audit_enabled;
+       return audit_do_config_change("audit_rate_limit", &audit_rate_limit,
+                                     limit, loginuid, sid);
+}
+
+static int audit_set_backlog_limit(int limit, uid_t loginuid, u32 sid)
+{
+       return audit_do_config_change("audit_backlog_limit", &audit_backlog_limit,
+                                     limit, loginuid, sid);
+}
 
-       if (state < 0 || state > 2)
+static int audit_set_enabled(int state, uid_t loginuid, u32 sid)
+{
+       int rc;
+       if (state < AUDIT_OFF || state > AUDIT_LOCKED)
                return -EINVAL;
 
-       /* check if we are locked */
-       if (audit_enabled == 2)
-               res = 0;
-       else
-               res = 1;
+       rc =  audit_do_config_change("audit_enabled", &audit_enabled, state,
+                                    loginuid, sid);
 
-       if (sid) {
-               char *ctx = NULL;
-               u32 len;
-               if ((rc = selinux_sid_to_string(sid, &ctx, &len)) == 0) {
-                       audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
-                               "audit_enabled=%d old=%d by auid=%u"
-                               " subj=%s res=%d",
-                               state, old, loginuid, ctx, res);
-                       kfree(ctx);
-               } else
-                       res = 0; /* Something weird, deny request */
-       }
-       audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
-               "audit_enabled=%d old=%d by auid=%u res=%d",
-               state, old, loginuid, res);
+       if (!rc)
+               audit_ever_enabled |= !!state;
 
-       /* If we are allowed, make the change */
-       if (res == 1)
-               audit_enabled = state;
-       /* Not allowed, update reason */
-       else if (rc == 0)
-               rc = -EPERM;
        return rc;
 }
 
 static int audit_set_failure(int state, uid_t loginuid, u32 sid)
 {
-       int res, rc = 0, old = audit_failure;
-
        if (state != AUDIT_FAIL_SILENT
            && state != AUDIT_FAIL_PRINTK
            && state != AUDIT_FAIL_PANIC)
                return -EINVAL;
 
-       /* check if we are locked */
-       if (audit_enabled == 2)
-               res = 0;
-       else
-               res = 1;
-
-       if (sid) {
-               char *ctx = NULL;
-               u32 len;
-               if ((rc = selinux_sid_to_string(sid, &ctx, &len)) == 0) {
-                       audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
-                               "audit_failure=%d old=%d by auid=%u"
-                               " subj=%s res=%d",
-                               state, old, loginuid, ctx, res);
-                       kfree(ctx);
-               } else
-                       res = 0; /* Something weird, deny request */
-       }
-       audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
-               "audit_failure=%d old=%d by auid=%u res=%d",
-               state, old, loginuid, res);
-
-       /* If we are allowed, make the change */
-       if (res == 1)
-               audit_failure = state;
-       /* Not allowed, update reason */
-       else if (rc == 0)
-               rc = -EPERM;
-       return rc;
+       return audit_do_config_change("audit_failure", &audit_failure, state,
+                                     loginuid, sid);
 }
 
 static int kauditd_thread(void *dummy)
@@ -405,7 +355,11 @@ static int kauditd_thread(void *dummy)
                                        audit_pid = 0;
                                }
                        } else {
-                               printk(KERN_NOTICE "%s\n", skb->data + NLMSG_SPACE(0));
+                               if (printk_ratelimit())
+                                       printk(KERN_NOTICE "%s\n", skb->data +
+                                               NLMSG_SPACE(0));
+                               else
+                                       audit_log_lost("printk limit exceeded\n");
                                kfree_skb(skb);
                        }
                } else {
@@ -573,6 +527,33 @@ static int audit_netlink_ok(struct sk_buff *skb, u16 msg_type)
        return err;
 }
 
+static int audit_log_common_recv_msg(struct audit_buffer **ab, u16 msg_type,
+                                    u32 pid, u32 uid, uid_t auid, u32 sid)
+{
+       int rc = 0;
+       char *ctx = NULL;
+       u32 len;
+
+       if (!audit_enabled) {
+               *ab = NULL;
+               return rc;
+       }
+
+       *ab = audit_log_start(NULL, GFP_KERNEL, msg_type);
+       audit_log_format(*ab, "user pid=%d uid=%u auid=%u",
+                        pid, uid, auid);
+       if (sid) {
+               rc = selinux_sid_to_string(sid, &ctx, &len);
+               if (rc)
+                       audit_log_format(*ab, " ssid=%u", sid);
+               else
+                       audit_log_format(*ab, " subj=%s", ctx);
+               kfree(ctx);
+       }
+
+       return rc;
+}
+
 static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
 {
        u32                     uid, pid, seq, sid;
@@ -583,7 +564,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
        u16                     msg_type = nlh->nlmsg_type;
        uid_t                   loginuid; /* loginuid of sender */
        struct audit_sig_info   *sig_data;
-       char                    *ctx;
+       char                    *ctx = NULL;
        u32                     len;
 
        err = audit_netlink_ok(skb, msg_type);
@@ -634,23 +615,14 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
                        if (err < 0) return err;
                }
                if (status_get->mask & AUDIT_STATUS_PID) {
-                       int old   = audit_pid;
-                       if (sid) {
-                               if ((err = selinux_sid_to_string(
-                                               sid, &ctx, &len)))
-                                       return err;
-                               else
-                                       audit_log(NULL, GFP_KERNEL,
-                                               AUDIT_CONFIG_CHANGE,
-                                               "audit_pid=%d old=%d by auid=%u subj=%s",
-                                               status_get->pid, old,
-                                               loginuid, ctx);
-                               kfree(ctx);
-                       } else
-                               audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
-                                       "audit_pid=%d old=%d by auid=%u",
-                                         status_get->pid, old, loginuid);
-                       audit_pid = status_get->pid;
+                       int new_pid = status_get->pid;
+
+                       if (audit_enabled != AUDIT_OFF)
+                               audit_log_config_change("audit_pid", new_pid,
+                                                       audit_pid, loginuid,
+                                                       sid, 1);
+
+                       audit_pid = new_pid;
                }
                if (status_get->mask & AUDIT_STATUS_RATE_LIMIT)
                        err = audit_set_rate_limit(status_get->rate_limit,
@@ -673,64 +645,35 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
                                if (err)
                                        break;
                        }
-                       ab = audit_log_start(NULL, GFP_KERNEL, msg_type);
-                       if (ab) {
-                               audit_log_format(ab,
-                                                "user pid=%d uid=%u auid=%u",
-                                                pid, uid, loginuid);
-                               if (sid) {
-                                       if (selinux_sid_to_string(
-                                                       sid, &ctx, &len)) {
-                                               audit_log_format(ab,
-                                                       " ssid=%u", sid);
-                                               /* Maybe call audit_panic? */
-                                       } else
-                                               audit_log_format(ab,
-                                                       " subj=%s", ctx);
-                                       kfree(ctx);
-                               }
-                               if (msg_type != AUDIT_USER_TTY)
-                                       audit_log_format(ab, " msg='%.1024s'",
-                                                        (char *)data);
-                               else {
-                                       int size;
-
-                                       audit_log_format(ab, " msg=");
-                                       size = nlmsg_len(nlh);
-                                       audit_log_n_untrustedstring(ab, size,
-                                                                   data);
-                               }
-                               audit_set_pid(ab, pid);
-                               audit_log_end(ab);
+                       audit_log_common_recv_msg(&ab, msg_type, pid, uid,
+                                                 loginuid, sid);
+
+                       if (msg_type != AUDIT_USER_TTY)
+                               audit_log_format(ab, " msg='%.1024s'",
+                                                (char *)data);
+                       else {
+                               int size;
+
+                               audit_log_format(ab, " msg=");
+                               size = nlmsg_len(nlh);
+                               audit_log_n_untrustedstring(ab, size,
+                                                           data);
                        }
+                       audit_set_pid(ab, pid);
+                       audit_log_end(ab);
                }
                break;
        case AUDIT_ADD:
        case AUDIT_DEL:
                if (nlmsg_len(nlh) < sizeof(struct audit_rule))
                        return -EINVAL;
-               if (audit_enabled == 2) {
-                       ab = audit_log_start(NULL, GFP_KERNEL,
-                                       AUDIT_CONFIG_CHANGE);
-                       if (ab) {
-                               audit_log_format(ab,
-                                                "pid=%d uid=%u auid=%u",
-                                                pid, uid, loginuid);
-                               if (sid) {
-                                       if (selinux_sid_to_string(
-                                                       sid, &ctx, &len)) {
-                                               audit_log_format(ab,
-                                                       " ssid=%u", sid);
-                                               /* Maybe call audit_panic? */
-                                       } else
-                                               audit_log_format(ab,
-                                                       " subj=%s", ctx);
-                                       kfree(ctx);
-                               }
-                               audit_log_format(ab, " audit_enabled=%d res=0",
-                                       audit_enabled);
-                               audit_log_end(ab);
-                       }
+               if (audit_enabled == AUDIT_LOCKED) {
+                       audit_log_common_recv_msg(&ab, AUDIT_CONFIG_CHANGE, pid,
+                                                 uid, loginuid, sid);
+
+                       audit_log_format(ab, " audit_enabled=%d res=0",
+                                        audit_enabled);
+                       audit_log_end(ab);
                        return -EPERM;
                }
                /* fallthrough */
@@ -743,28 +686,13 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
        case AUDIT_DEL_RULE:
                if (nlmsg_len(nlh) < sizeof(struct audit_rule_data))
                        return -EINVAL;
-               if (audit_enabled == 2) {
-                       ab = audit_log_start(NULL, GFP_KERNEL,
-                                       AUDIT_CONFIG_CHANGE);
-                       if (ab) {
-                               audit_log_format(ab,
-                                                "pid=%d uid=%u auid=%u",
-                                                pid, uid, loginuid);
-                               if (sid) {
-                                       if (selinux_sid_to_string(
-                                                       sid, &ctx, &len)) {
-                                               audit_log_format(ab,
-                                                       " ssid=%u", sid);
-                                               /* Maybe call audit_panic? */
-                                       } else
-                                               audit_log_format(ab,
-                                                       " subj=%s", ctx);
-                                       kfree(ctx);
-                               }
-                               audit_log_format(ab, " audit_enabled=%d res=0",
-                                       audit_enabled);
-                               audit_log_end(ab);
-                       }
+               if (audit_enabled == AUDIT_LOCKED) {
+                       audit_log_common_recv_msg(&ab, AUDIT_CONFIG_CHANGE, pid,
+                                                 uid, loginuid, sid);
+
+                       audit_log_format(ab, " audit_enabled=%d res=0",
+                                        audit_enabled);
+                       audit_log_end(ab);
                        return -EPERM;
                }
                /* fallthrough */
@@ -775,19 +703,10 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
                break;
        case AUDIT_TRIM:
                audit_trim_trees();
-               ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE);
-               if (!ab)
-                       break;
-               audit_log_format(ab, "auid=%u", loginuid);
-               if (sid) {
-                       u32 len;
-                       ctx = NULL;
-                       if (selinux_sid_to_string(sid, &ctx, &len))
-                               audit_log_format(ab, " ssid=%u", sid);
-                       else
-                               audit_log_format(ab, " subj=%s", ctx);
-                       kfree(ctx);
-               }
+
+               audit_log_common_recv_msg(&ab, AUDIT_CONFIG_CHANGE, pid,
+                                         uid, loginuid, sid);
+
                audit_log_format(ab, " op=trim res=1");
                audit_log_end(ab);
                break;
@@ -817,22 +736,9 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
                /* OK, here comes... */
                err = audit_tag_tree(old, new);
 
-               ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE);
-               if (!ab) {
-                       kfree(old);
-                       kfree(new);
-                       break;
-               }
-               audit_log_format(ab, "auid=%u", loginuid);
-               if (sid) {
-                       u32 len;
-                       ctx = NULL;
-                       if (selinux_sid_to_string(sid, &ctx, &len))
-                               audit_log_format(ab, " ssid=%u", sid);
-                       else
-                               audit_log_format(ab, " subj=%s", ctx);
-                       kfree(ctx);
-               }
+               audit_log_common_recv_msg(&ab, AUDIT_CONFIG_CHANGE, pid,
+                                         uid, loginuid, sid);
+
                audit_log_format(ab, " op=make_equiv old=");
                audit_log_untrustedstring(ab, old);
                audit_log_format(ab, " new=");
@@ -965,6 +871,7 @@ static int __init audit_init(void)
        skb_queue_head_init(&audit_skb_queue);
        audit_initialized = 1;
        audit_enabled = audit_default;
+       audit_ever_enabled |= !!audit_default;
 
        /* Register the callback with selinux.  This callback will be invoked
         * when a new policy is loaded. */
@@ -992,8 +899,10 @@ static int __init audit_enable(char *str)
        printk(KERN_INFO "audit: %s%s\n",
               audit_default ? "enabled" : "disabled",
               audit_initialized ? "" : " (after initialization)");
-       if (audit_initialized)
+       if (audit_initialized) {
                audit_enabled = audit_default;
+               audit_ever_enabled |= !!audit_default;
+       }
        return 1;
 }
 
@@ -1130,7 +1039,7 @@ struct audit_buffer *audit_log_start(struct audit_context *ctx, gfp_t gfp_mask,
 {
        struct audit_buffer     *ab     = NULL;
        struct timespec         t;
-       unsigned int            serial;
+       unsigned int            uninitialized_var(serial);
        int reserve;
        unsigned long timeout_start = jiffies;
 
@@ -1164,7 +1073,7 @@ struct audit_buffer *audit_log_start(struct audit_context *ctx, gfp_t gfp_mask,
                        remove_wait_queue(&audit_backlog_wait, &wait);
                        continue;
                }
-               if (audit_rate_check())
+               if (audit_rate_check() && printk_ratelimit())
                        printk(KERN_WARNING
                               "audit: audit_backlog=%d > "
                               "audit_backlog_limit=%d\n",
@@ -1200,13 +1109,17 @@ struct audit_buffer *audit_log_start(struct audit_context *ctx, gfp_t gfp_mask,
 static inline int audit_expand(struct audit_buffer *ab, int extra)
 {
        struct sk_buff *skb = ab->skb;
-       int ret = pskb_expand_head(skb, skb_headroom(skb), extra,
-                                  ab->gfp_mask);
+       int oldtail = skb_tailroom(skb);
+       int ret = pskb_expand_head(skb, 0, extra, ab->gfp_mask);
+       int newtail = skb_tailroom(skb);
+
        if (ret < 0) {
                audit_log_lost("out of memory in audit_expand");
                return 0;
        }
-       return skb_tailroom(skb);
+
+       skb->truesize += newtail - oldtail;
+       return newtail;
 }
 
 /*
@@ -1245,6 +1158,7 @@ static void audit_log_vformat(struct audit_buffer *ab, const char *fmt,
                        goto out;
                len = vsnprintf(skb_tail_pointer(skb), avail, fmt, args2);
        }
+       va_end(args2);
        if (len > 0)
                skb_put(skb, len);
 out:
@@ -1345,6 +1259,21 @@ static void audit_log_n_string(struct audit_buffer *ab, size_t slen,
        skb_put(skb, slen + 2); /* don't include null terminator */
 }
 
+/**
+ * audit_string_contains_control - does a string need to be logged in hex
+ * @string - string to be checked
+ * @len - max length of the string to check
+ */
+int audit_string_contains_control(const char *string, size_t len)
+{
+       const unsigned char *p;
+       for (p = string; p < (const unsigned char *)string + len && *p; p++) {
+               if (*p == '"' || *p < 0x21 || *p > 0x7f)
+                       return 1;
+       }
+       return 0;
+}
+
 /**
  * audit_log_n_untrustedstring - log a string that may contain random characters
  * @ab: audit_buffer
@@ -1359,19 +1288,13 @@ static void audit_log_n_string(struct audit_buffer *ab, size_t slen,
  * The caller specifies the number of characters in the string to log, which may
  * or may not be the entire string.
  */
-const char *audit_log_n_untrustedstring(struct audit_buffer *ab, size_t len,
-                                       const char *string)
+void audit_log_n_untrustedstring(struct audit_buffer *ab, size_t len,
+                                const char *string)
 {
-       const unsigned char *p;
-
-       for (p = string; p < (const unsigned char *)string + len && *p; p++) {
-               if (*p == '"' || *p < 0x21 || *p > 0x7f) {
-                       audit_log_hex(ab, string, len);
-                       return string + len + 1;
-               }
-       }
-       audit_log_n_string(ab, len, string);
-       return p + 1;
+       if (audit_string_contains_control(string, len))
+               audit_log_hex(ab, string, len);
+       else
+               audit_log_n_string(ab, len, string);
 }
 
 /**
@@ -1382,9 +1305,9 @@ const char *audit_log_n_untrustedstring(struct audit_buffer *ab, size_t len,
  * Same as audit_log_n_untrustedstring(), except that strlen is used to
  * determine string length.
  */
-const char *audit_log_untrustedstring(struct audit_buffer *ab, const char *string)
+void audit_log_untrustedstring(struct audit_buffer *ab, const char *string)
 {
-       return audit_log_n_untrustedstring(ab, strlen(string), string);
+       audit_log_n_untrustedstring(ab, strlen(string), string);
 }
 
 /* This is a helper-function to print the escaped d_path */
@@ -1433,8 +1356,11 @@ void audit_log_end(struct audit_buffer *ab)
                        skb_queue_tail(&audit_skb_queue, ab->skb);
                        ab->skb = NULL;
                        wake_up_interruptible(&kauditd_wait);
+               } else if (printk_ratelimit()) {
+                       struct nlmsghdr *nlh = nlmsg_hdr(ab->skb);
+                       printk(KERN_NOTICE "type=%d %s\n", nlh->nlmsg_type, ab->skb->data + NLMSG_SPACE(0));
                } else {
-                       printk(KERN_NOTICE "%s\n", ab->skb->data + NLMSG_SPACE(0));
+                       audit_log_lost("printk limit exceeded\n");
                }
        }
        audit_buffer_free(ab);
index 5d96f2cc7be8137164f8881d830ad013f39da949..6f19fd477aac539d9010c06a12b08848e708af5e 100644 (file)
@@ -95,6 +95,8 @@ extern struct inotify_handle *audit_ih;
 /* Inotify events we care about. */
 #define AUDIT_IN_WATCH IN_MOVE|IN_CREATE|IN_DELETE|IN_DELETE_SELF|IN_MOVE_SELF
 
+extern int audit_enabled;
+
 void audit_free_parent(struct inotify_watch *i_watch)
 {
        struct audit_parent *parent;
@@ -974,7 +976,6 @@ static void audit_update_watch(struct audit_parent *parent,
        struct audit_watch *owatch, *nwatch, *nextw;
        struct audit_krule *r, *nextr;
        struct audit_entry *oentry, *nentry;
-       struct audit_buffer *ab;
 
        mutex_lock(&audit_filter_mutex);
        list_for_each_entry_safe(owatch, nextw, &parent->watches, wlist) {
@@ -1014,13 +1015,18 @@ static void audit_update_watch(struct audit_parent *parent,
                        call_rcu(&oentry->rcu, audit_free_rule_rcu);
                }
 
-               ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE);
-               audit_log_format(ab, "op=updated rules specifying path=");
-               audit_log_untrustedstring(ab, owatch->path);
-               audit_log_format(ab, " with dev=%u ino=%lu\n", dev, ino);
-               audit_log_format(ab, " list=%d res=1", r->listnr);
-               audit_log_end(ab);
-
+               if (audit_enabled) {
+                       struct audit_buffer *ab;
+                       ab = audit_log_start(NULL, GFP_KERNEL,
+                               AUDIT_CONFIG_CHANGE);
+                       audit_log_format(ab,
+                               "op=updated rules specifying path=");
+                       audit_log_untrustedstring(ab, owatch->path);
+                       audit_log_format(ab, " with dev=%u ino=%lu\n",
+                                dev, ino);
+                       audit_log_format(ab, " list=%d res=1", r->listnr);
+                       audit_log_end(ab);
+               }
                audit_remove_watch(owatch);
                goto add_watch_to_parent; /* event applies to a single watch */
        }
@@ -1039,25 +1045,28 @@ static void audit_remove_parent_watches(struct audit_parent *parent)
        struct audit_watch *w, *nextw;
        struct audit_krule *r, *nextr;
        struct audit_entry *e;
-       struct audit_buffer *ab;
 
        mutex_lock(&audit_filter_mutex);
        parent->flags |= AUDIT_PARENT_INVALID;
        list_for_each_entry_safe(w, nextw, &parent->watches, wlist) {
                list_for_each_entry_safe(r, nextr, &w->rules, rlist) {
                        e = container_of(r, struct audit_entry, rule);
-
-                       ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE);
-                       audit_log_format(ab, "op=remove rule path=");
-                       audit_log_untrustedstring(ab, w->path);
-                       if (r->filterkey) {
-                               audit_log_format(ab, " key=");
-                               audit_log_untrustedstring(ab, r->filterkey);
-                       } else
-                               audit_log_format(ab, " key=(null)");
-                       audit_log_format(ab, " list=%d res=1", r->listnr);
-                       audit_log_end(ab);
-
+                       if (audit_enabled) {
+                               struct audit_buffer *ab;
+                               ab = audit_log_start(NULL, GFP_KERNEL,
+                                       AUDIT_CONFIG_CHANGE);
+                               audit_log_format(ab, "op=remove rule path=");
+                               audit_log_untrustedstring(ab, w->path);
+                               if (r->filterkey) {
+                                       audit_log_format(ab, " key=");
+                                       audit_log_untrustedstring(ab,
+                                                       r->filterkey);
+                               } else
+                                       audit_log_format(ab, " key=(null)");
+                               audit_log_format(ab, " list=%d res=1",
+                                       r->listnr);
+                               audit_log_end(ab);
+                       }
                        list_del(&r->rlist);
                        list_del_rcu(&e->list);
                        call_rcu(&e->rcu, audit_free_rule_rcu);
@@ -1495,6 +1504,9 @@ static void audit_log_rule_change(uid_t loginuid, u32 sid, char *action,
 {
        struct audit_buffer *ab;
 
+       if (!audit_enabled)
+               return;
+
        ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE);
        if (!ab)
                return;
index bce9ecdb771240885bd3d1c0c30f7565ebbd1eb5..1c06ecf38d7b059208b456a604c284e68ab409c4 100644 (file)
@@ -70,6 +70,7 @@
 #include "audit.h"
 
 extern struct list_head audit_filter_list[];
+extern int audit_ever_enabled;
 
 /* AUDIT_NAMES is the number of slots we reserve in the audit_context
  * for saving names from getname(). */
@@ -78,6 +79,9 @@ extern struct list_head audit_filter_list[];
 /* Indicates that audit should log the full pathname. */
 #define AUDIT_NAME_FULL -1
 
+/* no execve audit message should be longer than this (userspace limits) */
+#define MAX_EXECVE_AUDIT_LEN 7500
+
 /* number of audit rules */
 int audit_n_rules;
 
@@ -176,7 +180,11 @@ struct audit_aux_data_fd_pair {
 struct audit_aux_data_pids {
        struct audit_aux_data   d;
        pid_t                   target_pid[AUDIT_AUX_PIDS];
+       uid_t                   target_auid[AUDIT_AUX_PIDS];
+       uid_t                   target_uid[AUDIT_AUX_PIDS];
+       unsigned int            target_sessionid[AUDIT_AUX_PIDS];
        u32                     target_sid[AUDIT_AUX_PIDS];
+       char                    target_comm[AUDIT_AUX_PIDS][TASK_COMM_LEN];
        int                     pid_count;
 };
 
@@ -192,7 +200,6 @@ struct audit_context {
        enum audit_state    state;
        unsigned int        serial;     /* serial number for record */
        struct timespec     ctime;      /* time of syscall entry */
-       uid_t               loginuid;   /* login uid (identity) */
        int                 major;      /* syscall number */
        unsigned long       argv[4];    /* syscall arguments */
        int                 return_valid; /* return code is valid */
@@ -215,7 +222,11 @@ struct audit_context {
        int                 arch;
 
        pid_t               target_pid;
+       uid_t               target_auid;
+       uid_t               target_uid;
+       unsigned int        target_sessionid;
        u32                 target_sid;
+       char                target_comm[TASK_COMM_LEN];
 
        struct audit_tree_refs *trees, *first_trees;
        int tree_count;
@@ -506,7 +517,7 @@ static int audit_filter_rules(struct task_struct *tsk,
                case AUDIT_LOGINUID:
                        result = 0;
                        if (ctx)
-                               result = audit_comparator(ctx->loginuid, f->op, f->val);
+                               result = audit_comparator(tsk->loginuid, f->op, f->val);
                        break;
                case AUDIT_SUBJ_USER:
                case AUDIT_SUBJ_ROLE:
@@ -702,7 +713,24 @@ static inline struct audit_context *audit_get_context(struct task_struct *tsk,
        if (likely(!context))
                return NULL;
        context->return_valid = return_valid;
-       context->return_code  = return_code;
+
+       /*
+        * we need to fix up the return code in the audit logs if the actual
+        * return codes are later going to be fixed up by the arch specific
+        * signal handlers
+        *
+        * This is actually a test for:
+        * (rc == ERESTARTSYS ) || (rc == ERESTARTNOINTR) ||
+        * (rc == ERESTARTNOHAND) || (rc == ERESTART_RESTARTBLOCK)
+        *
+        * but is faster than a bunch of ||
+        */
+       if (unlikely(return_code <= -ERESTARTSYS) &&
+           (return_code >= -ERESTART_RESTARTBLOCK) &&
+           (return_code != -ENOIOCTLCMD))
+               context->return_code = -EINTR;
+       else
+               context->return_code  = return_code;
 
        if (context->in_syscall && !context->dummy && !context->auditable) {
                enum audit_state state;
@@ -783,11 +811,8 @@ static inline void audit_free_aux(struct audit_context *context)
 static inline void audit_zero_context(struct audit_context *context,
                                      enum audit_state state)
 {
-       uid_t loginuid = context->loginuid;
-
        memset(context, 0, sizeof(*context));
        context->state      = state;
-       context->loginuid   = loginuid;
 }
 
 static inline struct audit_context *audit_alloc_context(enum audit_state state)
@@ -814,7 +839,7 @@ int audit_alloc(struct task_struct *tsk)
        struct audit_context *context;
        enum audit_state     state;
 
-       if (likely(!audit_enabled))
+       if (likely(!audit_ever_enabled))
                return 0; /* Return if not auditing. */
 
        state = audit_filter_task(tsk);
@@ -826,11 +851,6 @@ int audit_alloc(struct task_struct *tsk)
                return -ENOMEM;
        }
 
-                               /* Preserve login uid */
-       context->loginuid = -1;
-       if (current->audit_context)
-               context->loginuid = current->audit_context->loginuid;
-
        tsk->audit_context  = context;
        set_tsk_thread_flag(tsk, TIF_SYSCALL_AUDIT);
        return 0;
@@ -922,7 +942,8 @@ static void audit_log_task_info(struct audit_buffer *ab, struct task_struct *tsk
 }
 
 static int audit_log_pid_context(struct audit_context *context, pid_t pid,
-                                u32 sid)
+                                uid_t auid, uid_t uid, unsigned int sessionid,
+                                u32 sid, char *comm)
 {
        struct audit_buffer *ab;
        char *s = NULL;
@@ -931,68 +952,204 @@ static int audit_log_pid_context(struct audit_context *context, pid_t pid,
 
        ab = audit_log_start(context, GFP_KERNEL, AUDIT_OBJ_PID);
        if (!ab)
-               return 1;
+               return rc;
 
+       audit_log_format(ab, "opid=%d oauid=%d ouid=%d oses=%d", pid, auid,
+                        uid, sessionid);
        if (selinux_sid_to_string(sid, &s, &len)) {
-               audit_log_format(ab, "opid=%d obj=(none)", pid);
+               audit_log_format(ab, " obj=(none)");
                rc = 1;
        } else
-               audit_log_format(ab, "opid=%d  obj=%s", pid, s);
+               audit_log_format(ab, " obj=%s", s);
+       audit_log_format(ab, " ocomm=");
+       audit_log_untrustedstring(ab, comm);
        audit_log_end(ab);
        kfree(s);
 
        return rc;
 }
 
-static void audit_log_execve_info(struct audit_buffer *ab,
-               struct audit_aux_data_execve *axi)
+/*
+ * to_send and len_sent accounting are very loose estimates.  We aren't
+ * really worried about a hard cap to MAX_EXECVE_AUDIT_LEN so much as being
+ * within about 500 bytes (next page boundry)
+ *
+ * why snprintf?  an int is up to 12 digits long.  if we just assumed when
+ * logging that a[%d]= was going to be 16 characters long we would be wasting
+ * space in every audit message.  In one 7500 byte message we can log up to
+ * about 1000 min size arguments.  That comes down to about 50% waste of space
+ * if we didn't do the snprintf to find out how long arg_num_len was.
+ */
+static int audit_log_single_execve_arg(struct audit_context *context,
+                                       struct audit_buffer **ab,
+                                       int arg_num,
+                                       size_t *len_sent,
+                                       const char __user *p,
+                                       char *buf)
 {
-       int i;
-       long len, ret;
-       const char __user *p;
-       char *buf;
+       char arg_num_len_buf[12];
+       const char __user *tmp_p = p;
+       /* how many digits are in arg_num? 3 is the length of a=\n */
+       size_t arg_num_len = snprintf(arg_num_len_buf, 12, "%d", arg_num) + 3;
+       size_t len, len_left, to_send;
+       size_t max_execve_audit_len = MAX_EXECVE_AUDIT_LEN;
+       unsigned int i, has_cntl = 0, too_long = 0;
+       int ret;
+
+       /* strnlen_user includes the null we don't want to send */
+       len_left = len = strnlen_user(p, MAX_ARG_STRLEN) - 1;
 
-       if (axi->mm != current->mm)
-               return; /* execve failed, no additional info */
-
-       p = (const char __user *)axi->mm->arg_start;
+       /*
+        * We just created this mm, if we can't find the strings
+        * we just copied into it something is _very_ wrong. Similar
+        * for strings that are too long, we should not have created
+        * any.
+        */
+       if (unlikely((len  = -1) || len > MAX_ARG_STRLEN - 1)) {
+               WARN_ON(1);
+               send_sig(SIGKILL, current, 0);
+       }
 
-       for (i = 0; i < axi->argc; i++, p += len) {
-               len = strnlen_user(p, MAX_ARG_STRLEN);
+       /* walk the whole argument looking for non-ascii chars */
+       do {
+               if (len_left > MAX_EXECVE_AUDIT_LEN)
+                       to_send = MAX_EXECVE_AUDIT_LEN;
+               else
+                       to_send = len_left;
+               ret = copy_from_user(buf, tmp_p, to_send);
                /*
-                * We just created this mm, if we can't find the strings
-                * we just copied into it something is _very_ wrong. Similar
-                * for strings that are too long, we should not have created
-                * any.
+                * There is no reason for this copy to be short. We just
+                * copied them here, and the mm hasn't been exposed to user-
+                * space yet.
                 */
-               if (!len || len > MAX_ARG_STRLEN) {
+               if (ret) {
                        WARN_ON(1);
                        send_sig(SIGKILL, current, 0);
                }
-
-               buf = kmalloc(len, GFP_KERNEL);
-               if (!buf) {
-                       audit_panic("out of memory for argv string\n");
+               buf[to_send] = '\0';
+               has_cntl = audit_string_contains_control(buf, to_send);
+               if (has_cntl) {
+                       /*
+                        * hex messages get logged as 2 bytes, so we can only
+                        * send half as much in each message
+                        */
+                       max_execve_audit_len = MAX_EXECVE_AUDIT_LEN / 2;
                        break;
                }
+               len_left -= to_send;
+               tmp_p += to_send;
+       } while (len_left > 0);
+
+       len_left = len;
+
+       if (len > max_execve_audit_len)
+               too_long = 1;
+
+       /* rewalk the argument actually logging the message */
+       for (i = 0; len_left > 0; i++) {
+               int room_left;
+
+               if (len_left > max_execve_audit_len)
+                       to_send = max_execve_audit_len;
+               else
+                       to_send = len_left;
+
+               /* do we have space left to send this argument in this ab? */
+               room_left = MAX_EXECVE_AUDIT_LEN - arg_num_len - *len_sent;
+               if (has_cntl)
+                       room_left -= (to_send * 2);
+               else
+                       room_left -= to_send;
+               if (room_left < 0) {
+                       *len_sent = 0;
+                       audit_log_end(*ab);
+                       *ab = audit_log_start(context, GFP_KERNEL, AUDIT_EXECVE);
+                       if (!*ab)
+                               return 0;
+               }
 
-               ret = copy_from_user(buf, p, len);
                /*
-                * There is no reason for this copy to be short. We just
-                * copied them here, and the mm hasn't been exposed to user-
-                * space yet.
+                * first record needs to say how long the original string was
+                * so we can be sure nothing was lost.
+                */
+               if ((i == 0) && (too_long))
+                       audit_log_format(*ab, "a%d_len=%ld ", arg_num,
+                                        has_cntl ? 2*len : len);
+
+               /*
+                * normally arguments are small enough to fit and we already
+                * filled buf above when we checked for control characters
+                * so don't bother with another copy_from_user
                 */
+               if (len >= max_execve_audit_len)
+                       ret = copy_from_user(buf, p, to_send);
+               else
+                       ret = 0;
                if (ret) {
                        WARN_ON(1);
                        send_sig(SIGKILL, current, 0);
                }
+               buf[to_send] = '\0';
+
+               /* actually log it */
+               audit_log_format(*ab, "a%d", arg_num);
+               if (too_long)
+                       audit_log_format(*ab, "[%d]", i);
+               audit_log_format(*ab, "=");
+               if (has_cntl)
+                       audit_log_hex(*ab, buf, to_send);
+               else
+                       audit_log_format(*ab, "\"%s\"", buf);
+               audit_log_format(*ab, "\n");
+
+               p += to_send;
+               len_left -= to_send;
+               *len_sent += arg_num_len;
+               if (has_cntl)
+                       *len_sent += to_send * 2;
+               else
+                       *len_sent += to_send;
+       }
+       /* include the null we didn't log */
+       return len + 1;
+}
 
-               audit_log_format(ab, "a%d=", i);
-               audit_log_untrustedstring(ab, buf);
-               audit_log_format(ab, "\n");
+static void audit_log_execve_info(struct audit_context *context,
+                                 struct audit_buffer **ab,
+                                 struct audit_aux_data_execve *axi)
+{
+       int i;
+       size_t len, len_sent = 0;
+       const char __user *p;
+       char *buf;
+
+       if (axi->mm != current->mm)
+               return; /* execve failed, no additional info */
+
+       p = (const char __user *)axi->mm->arg_start;
+
+       audit_log_format(*ab, "argc=%d ", axi->argc);
+
+       /*
+        * we need some kernel buffer to hold the userspace args.  Just
+        * allocate one big one rather than allocating one of the right size
+        * for every single argument inside audit_log_single_execve_arg()
+        * should be <8k allocation so should be pretty safe.
+        */
+       buf = kmalloc(MAX_EXECVE_AUDIT_LEN + 1, GFP_KERNEL);
+       if (!buf) {
+               audit_panic("out of memory for argv string\n");
+               return;
+       }
 
-               kfree(buf);
+       for (i = 0; i < axi->argc; i++) {
+               len = audit_log_single_execve_arg(context, ab, i,
+                                                 &len_sent, p, buf);
+               if (len <= 0)
+                       break;
+               p += len;
        }
+       kfree(buf);
 }
 
 static void audit_log_exit(struct audit_context *context, struct task_struct *tsk)
@@ -1039,7 +1196,7 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
                  " a0=%lx a1=%lx a2=%lx a3=%lx items=%d"
                  " ppid=%d pid=%d auid=%u uid=%u gid=%u"
                  " euid=%u suid=%u fsuid=%u"
-                 " egid=%u sgid=%u fsgid=%u tty=%s",
+                 " egid=%u sgid=%u fsgid=%u tty=%s ses=%u",
                  context->argv[0],
                  context->argv[1],
                  context->argv[2],
@@ -1047,11 +1204,12 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
                  context->name_count,
                  context->ppid,
                  context->pid,
-                 context->loginuid,
+                 tsk->loginuid,
                  context->uid,
                  context->gid,
                  context->euid, context->suid, context->fsuid,
-                 context->egid, context->sgid, context->fsgid, tty);
+                 context->egid, context->sgid, context->fsgid, tty,
+                 tsk->sessionid);
 
        mutex_unlock(&tty_mutex);
 
@@ -1135,7 +1293,7 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
 
                case AUDIT_EXECVE: {
                        struct audit_aux_data_execve *axi = (void *)aux;
-                       audit_log_execve_info(ab, axi);
+                       audit_log_execve_info(context, &ab, axi);
                        break; }
 
                case AUDIT_SOCKETCALL: {
@@ -1168,13 +1326,19 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
 
                for (i = 0; i < axs->pid_count; i++)
                        if (audit_log_pid_context(context, axs->target_pid[i],
-                                                 axs->target_sid[i]))
+                                                 axs->target_auid[i],
+                                                 axs->target_uid[i],
+                                                 axs->target_sessionid[i],
+                                                 axs->target_sid[i],
+                                                 axs->target_comm[i]))
                                call_panic = 1;
        }
 
        if (context->target_pid &&
            audit_log_pid_context(context, context->target_pid,
-                                 context->target_sid))
+                                 context->target_auid, context->target_uid,
+                                 context->target_sessionid,
+                                 context->target_sid, context->target_comm))
                        call_panic = 1;
 
        if (context->pwd && context->pwdmnt) {
@@ -1242,6 +1406,11 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
 
                audit_log_end(ab);
        }
+
+       /* Send end of event record to help user space know we are finished */
+       ab = audit_log_start(context, GFP_KERNEL, AUDIT_EOE);
+       if (ab)
+               audit_log_end(ab);
        if (call_panic)
                audit_panic("error converting sid to string");
 }
@@ -1766,6 +1935,9 @@ void auditsc_get_stamp(struct audit_context *ctx,
        ctx->auditable = 1;
 }
 
+/* global counter which is incremented every time something logs in */
+static atomic_t session_id = ATOMIC_INIT(0);
+
 /**
  * audit_set_loginuid - set a task's audit_context loginuid
  * @task: task whose audit context is being modified
@@ -1777,40 +1949,28 @@ void auditsc_get_stamp(struct audit_context *ctx,
  */
 int audit_set_loginuid(struct task_struct *task, uid_t loginuid)
 {
+       unsigned int sessionid = atomic_inc_return(&session_id);
        struct audit_context *context = task->audit_context;
 
-       if (context) {
-               /* Only log if audit is enabled */
-               if (context->in_syscall) {
-                       struct audit_buffer *ab;
-
-                       ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_LOGIN);
-                       if (ab) {
-                               audit_log_format(ab, "login pid=%d uid=%u "
-                                       "old auid=%u new auid=%u",
-                                       task->pid, task->uid,
-                                       context->loginuid, loginuid);
-                               audit_log_end(ab);
-                       }
+       if (context && context->in_syscall) {
+               struct audit_buffer *ab;
+
+               ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_LOGIN);
+               if (ab) {
+                       audit_log_format(ab, "login pid=%d uid=%u "
+                               "old auid=%u new auid=%u"
+                               " old ses=%u new ses=%u",
+                               task->pid, task->uid,
+                               task->loginuid, loginuid,
+                               task->sessionid, sessionid);
+                       audit_log_end(ab);
                }
-               context->loginuid = loginuid;
        }
+       task->sessionid = sessionid;
+       task->loginuid = loginuid;
        return 0;
 }
 
-/**
- * audit_get_loginuid - get the loginuid for an audit_context
- * @ctx: the audit_context
- *
- * Returns the context's loginuid or -1 if @ctx is NULL.
- */
-uid_t audit_get_loginuid(struct audit_context *ctx)
-{
-       return ctx ? ctx->loginuid : -1;
-}
-
-EXPORT_SYMBOL(audit_get_loginuid);
-
 /**
  * __audit_mq_open - record audit data for a POSIX MQ open
  * @oflag: open flag
@@ -2070,8 +2230,6 @@ int __audit_ipc_set_perm(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode
        return 0;
 }
 
-int audit_argv_kb = 32;
-
 int audit_bprm(struct linux_binprm *bprm)
 {
        struct audit_aux_data_execve *ax;
@@ -2080,14 +2238,6 @@ int audit_bprm(struct linux_binprm *bprm)
        if (likely(!audit_enabled || !context || context->dummy))
                return 0;
 
-       /*
-        * Even though the stack code doesn't limit the arg+env size any more,
-        * the audit code requires that _all_ arguments be logged in a single
-        * netlink skb. Hence cap it :-(
-        */
-       if (bprm->argv_len > (audit_argv_kb << 10))
-               return -E2BIG;
-
        ax = kmalloc(sizeof(*ax), GFP_KERNEL);
        if (!ax)
                return -ENOMEM;
@@ -2193,7 +2343,11 @@ void __audit_ptrace(struct task_struct *t)
        struct audit_context *context = current->audit_context;
 
        context->target_pid = t->pid;
+       context->target_auid = audit_get_loginuid(t);
+       context->target_uid = t->uid;
+       context->target_sessionid = audit_get_sessionid(t);
        selinux_get_task_sid(t, &context->target_sid);
+       memcpy(context->target_comm, t->comm, TASK_COMM_LEN);
 }
 
 /**
@@ -2216,8 +2370,8 @@ int __audit_signal_info(int sig, struct task_struct *t)
        if (audit_pid && t->tgid == audit_pid) {
                if (sig == SIGTERM || sig == SIGHUP || sig == SIGUSR1) {
                        audit_sig_pid = tsk->pid;
-                       if (ctx)
-                               audit_sig_uid = ctx->loginuid;
+                       if (tsk->loginuid != -1)
+                               audit_sig_uid = tsk->loginuid;
                        else
                                audit_sig_uid = tsk->uid;
                        selinux_get_task_sid(tsk, &audit_sig_sid);
@@ -2230,7 +2384,11 @@ int __audit_signal_info(int sig, struct task_struct *t)
         * in audit_context */
        if (!ctx->target_pid) {
                ctx->target_pid = t->tgid;
+               ctx->target_auid = audit_get_loginuid(t);
+               ctx->target_uid = t->uid;
+               ctx->target_sessionid = audit_get_sessionid(t);
                selinux_get_task_sid(t, &ctx->target_sid);
+               memcpy(ctx->target_comm, t->comm, TASK_COMM_LEN);
                return 0;
        }
 
@@ -2247,7 +2405,11 @@ int __audit_signal_info(int sig, struct task_struct *t)
        BUG_ON(axp->pid_count >= AUDIT_AUX_PIDS);
 
        axp->target_pid[axp->pid_count] = t->tgid;
+       axp->target_auid[axp->pid_count] = audit_get_loginuid(t);
+       axp->target_uid[axp->pid_count] = t->uid;
+       axp->target_sessionid[axp->pid_count] = audit_get_sessionid(t);
        selinux_get_task_sid(t, &axp->target_sid[axp->pid_count]);
+       memcpy(axp->target_comm[axp->pid_count], t->comm, TASK_COMM_LEN);
        axp->pid_count++;
 
        return 0;
@@ -2264,6 +2426,8 @@ void audit_core_dumps(long signr)
 {
        struct audit_buffer *ab;
        u32 sid;
+       uid_t auid = audit_get_loginuid(current);
+       unsigned int sessionid = audit_get_sessionid(current);
 
        if (!audit_enabled)
                return;
@@ -2272,9 +2436,8 @@ void audit_core_dumps(long signr)
                return;
 
        ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_ANOM_ABEND);
-       audit_log_format(ab, "auid=%u uid=%u gid=%u",
-                       audit_get_loginuid(current->audit_context),
-                       current->uid, current->gid);
+       audit_log_format(ab, "auid=%u uid=%u gid=%u ses=%u",
+                       auid, current->uid, current->gid, sessionid);
        selinux_get_task_sid(current, &sid);
        if (sid) {
                char *ctx = NULL;
index efbd9cdce1322d8a6e0c93ada872d68aadacf38e..39e8193b41ea658f1d67fca1d91edb38e698edea 100644 (file)
  */
 static DEFINE_SPINLOCK(task_capability_lock);
 
+/*
+ * Leveraged for setting/resetting capabilities
+ */
+
+const kernel_cap_t __cap_empty_set = CAP_EMPTY_SET;
+const kernel_cap_t __cap_full_set = CAP_FULL_SET;
+const kernel_cap_t __cap_init_eff_set = CAP_INIT_EFF_SET;
+
+EXPORT_SYMBOL(__cap_empty_set);
+EXPORT_SYMBOL(__cap_full_set);
+EXPORT_SYMBOL(__cap_init_eff_set);
+
+/*
+ * More recent versions of libcap are available from:
+ *
+ *   http://www.kernel.org/pub/linux/libs/security/linux-privs/
+ */
+
+static void warn_legacy_capability_use(void)
+{
+       static int warned;
+       if (!warned) {
+               char name[sizeof(current->comm)];
+
+               printk(KERN_INFO "warning: `%s' uses 32-bit capabilities"
+                      " (legacy support in use)\n",
+                      get_task_comm(name, current));
+               warned = 1;
+       }
+}
+
 /*
  * For sys_getproccap() and sys_setproccap(), any of the three
  * capability set pointers may be NULL -- indicating that that set is
@@ -42,12 +73,21 @@ asmlinkage long sys_capget(cap_user_header_t header, cap_user_data_t dataptr)
        pid_t pid;
        __u32 version;
        struct task_struct *target;
-       struct __user_cap_data_struct data;
+       unsigned tocopy;
+       kernel_cap_t pE, pI, pP;
 
        if (get_user(version, &header->version))
                return -EFAULT;
 
-       if (version != _LINUX_CAPABILITY_VERSION) {
+       switch (version) {
+       case _LINUX_CAPABILITY_VERSION_1:
+               warn_legacy_capability_use();
+               tocopy = _LINUX_CAPABILITY_U32S_1;
+               break;
+       case _LINUX_CAPABILITY_VERSION_2:
+               tocopy = _LINUX_CAPABILITY_U32S_2;
+               break;
+       default:
                if (put_user(_LINUX_CAPABILITY_VERSION, &header->version))
                        return -EFAULT;
                return -EINVAL;
@@ -71,14 +111,47 @@ asmlinkage long sys_capget(cap_user_header_t header, cap_user_data_t dataptr)
        } else
                target = current;
 
-       ret = security_capget(target, &data.effective, &data.inheritable, &data.permitted);
+       ret = security_capget(target, &pE, &pI, &pP);
 
 out:
        read_unlock(&tasklist_lock);
        spin_unlock(&task_capability_lock);
 
-       if (!ret && copy_to_user(dataptr, &data, sizeof data))
-               return -EFAULT;
+       if (!ret) {
+               struct __user_cap_data_struct kdata[_LINUX_CAPABILITY_U32S];
+               unsigned i;
+
+               for (i = 0; i < tocopy; i++) {
+                       kdata[i].effective = pE.cap[i];
+                       kdata[i].permitted = pP.cap[i];
+                       kdata[i].inheritable = pI.cap[i];
+               }
+
+               /*
+                * Note, in the case, tocopy < _LINUX_CAPABILITY_U32S,
+                * we silently drop the upper capabilities here. This
+                * has the effect of making older libcap
+                * implementations implicitly drop upper capability
+                * bits when they perform a: capget/modify/capset
+                * sequence.
+                *
+                * This behavior is considered fail-safe
+                * behavior. Upgrading the application to a newer
+                * version of libcap will enable access to the newer
+                * capabilities.
+                *
+                * An alternative would be to return an error here
+                * (-ERANGE), but that causes legacy applications to
+                * unexpectidly fail; the capget/modify/capset aborts
+                * before modification is attempted and the application
+                * fails.
+                */
+
+               if (copy_to_user(dataptr, kdata, tocopy
+                                * sizeof(struct __user_cap_data_struct))) {
+                       return -EFAULT;
+               }
+       }
 
        return ret;
 }
@@ -167,6 +240,8 @@ static inline int cap_set_all(kernel_cap_t *effective,
  */
 asmlinkage long sys_capset(cap_user_header_t header, const cap_user_data_t data)
 {
+       struct __user_cap_data_struct kdata[_LINUX_CAPABILITY_U32S];
+       unsigned i, tocopy;
        kernel_cap_t inheritable, permitted, effective;
        __u32 version;
        struct task_struct *target;
@@ -176,7 +251,15 @@ asmlinkage long sys_capset(cap_user_header_t header, const cap_user_data_t data)
        if (get_user(version, &header->version))
                return -EFAULT;
 
-       if (version != _LINUX_CAPABILITY_VERSION) {
+       switch (version) {
+       case _LINUX_CAPABILITY_VERSION_1:
+               warn_legacy_capability_use();
+               tocopy = _LINUX_CAPABILITY_U32S_1;
+               break;
+       case _LINUX_CAPABILITY_VERSION_2:
+               tocopy = _LINUX_CAPABILITY_U32S_2;
+               break;
+       default:
                if (put_user(_LINUX_CAPABILITY_VERSION, &header->version))
                        return -EFAULT;
                return -EINVAL;
@@ -188,10 +271,22 @@ asmlinkage long sys_capset(cap_user_header_t header, const cap_user_data_t data)
        if (pid && pid != task_pid_vnr(current) && !capable(CAP_SETPCAP))
                return -EPERM;
 
-       if (copy_from_user(&effective, &data->effective, sizeof(effective)) ||
-           copy_from_user(&inheritable, &data->inheritable, sizeof(inheritable)) ||
-           copy_from_user(&permitted, &data->permitted, sizeof(permitted)))
+       if (copy_from_user(&kdata, data, tocopy
+                          * sizeof(struct __user_cap_data_struct))) {
                return -EFAULT;
+       }
+
+       for (i = 0; i < tocopy; i++) {
+               effective.cap[i] = kdata[i].effective;
+               permitted.cap[i] = kdata[i].permitted;
+               inheritable.cap[i] = kdata[i].inheritable;
+       }
+       while (i < _LINUX_CAPABILITY_U32S) {
+               effective.cap[i] = 0;
+               permitted.cap[i] = 0;
+               inheritable.cap[i] = 0;
+               i++;
+       }
 
        spin_lock(&task_capability_lock);
        read_lock(&tasklist_lock);
index 549c0558ba68273c7586b26f6579d12c27d0f79d..9d3d0f0b27d9a6165384d6af55013488aacfdc72 100644 (file)
@@ -50,8 +50,6 @@
 #include <asm/pgtable.h>
 #include <asm/mmu_context.h>
 
-extern void sem_exit (void);
-
 static void exit_mm(struct task_struct * tsk);
 
 static void __unhash_process(struct task_struct *p)
@@ -249,7 +247,7 @@ static int has_stopped_jobs(struct pid *pgrp)
        struct task_struct *p;
 
        do_each_pid_task(pgrp, PIDTYPE_PGID, p) {
-               if (p->state != TASK_STOPPED)
+               if (!task_is_stopped(p))
                        continue;
                retval = 1;
                break;
@@ -614,7 +612,7 @@ reparent_thread(struct task_struct *p, struct task_struct *father, int traced)
                p->parent = p->real_parent;
                add_parent(p);
 
-               if (p->state == TASK_TRACED) {
+               if (task_is_traced(p)) {
                        /*
                         * If it was at a trace stop, turn it into
                         * a normal stop since it's no longer being
@@ -1085,11 +1083,12 @@ do_group_exit(int exit_code)
                struct signal_struct *const sig = current->signal;
                struct sighand_struct *const sighand = current->sighand;
                spin_lock_irq(&sighand->siglock);
-               if (sig->flags & SIGNAL_GROUP_EXIT)
+               if (signal_group_exit(sig))
                        /* Another thread got here before we took the lock.  */
                        exit_code = sig->group_exit_code;
                else {
                        sig->group_exit_code = exit_code;
+                       sig->flags = SIGNAL_GROUP_EXIT;
                        zap_other_threads(current);
                }
                spin_unlock_irq(&sighand->siglock);
@@ -1563,60 +1562,51 @@ repeat:
                        }
                        allowed = 1;
 
-                       switch (p->state) {
-                       case TASK_TRACED:
-                               /*
-                                * When we hit the race with PTRACE_ATTACH,
-                                * we will not report this child.  But the
-                                * race means it has not yet been moved to
-                                * our ptrace_children list, so we need to
-                                * set the flag here to avoid a spurious ECHILD
-                                * when the race happens with the only child.
-                                */
-                               flag = 1;
-                               if (!my_ptrace_child(p))
-                                       continue;
-                               /*FALLTHROUGH*/
-                       case TASK_STOPPED:
+                       if (task_is_stopped_or_traced(p)) {
                                /*
                                 * It's stopped now, so it might later
                                 * continue, exit, or stop again.
+                                *
+                                * When we hit the race with PTRACE_ATTACH, we
+                                * will not report this child.  But the race
+                                * means it has not yet been moved to our
+                                * ptrace_children list, so we need to set the
+                                * flag here to avoid a spurious ECHILD when
+                                * the race happens with the only child.
                                 */
                                flag = 1;
-                               if (!(options & WUNTRACED) &&
-                                   !my_ptrace_child(p))
-                                       continue;
+
+                               if (!my_ptrace_child(p)) {
+                                       if (task_is_traced(p))
+                                               continue;
+                                       if (!(options & WUNTRACED))
+                                               continue;
+                               }
+
                                retval = wait_task_stopped(p, ret == 2,
-                                                          (options & WNOWAIT),
-                                                          infop,
-                                                          stat_addr, ru);
+                                               (options & WNOWAIT), infop,
+                                               stat_addr, ru);
                                if (retval == -EAGAIN)
                                        goto repeat;
                                if (retval != 0) /* He released the lock.  */
                                        goto end;
-                               break;
-                       default:
-                       // case EXIT_DEAD:
-                               if (p->exit_state == EXIT_DEAD)
+                       } else if (p->exit_state == EXIT_DEAD) {
+                               continue;
+                       } else if (p->exit_state == EXIT_ZOMBIE) {
+                               /*
+                                * Eligible but we cannot release it yet:
+                                */
+                               if (ret == 2)
+                                       goto check_continued;
+                               if (!likely(options & WEXITED))
                                        continue;
-                       // case EXIT_ZOMBIE:
-                               if (p->exit_state == EXIT_ZOMBIE) {
-                                       /*
-                                        * Eligible but we cannot release
-                                        * it yet:
-                                        */
-                                       if (ret == 2)
-                                               goto check_continued;
-                                       if (!likely(options & WEXITED))
-                                               continue;
-                                       retval = wait_task_zombie(
-                                               p, (options & WNOWAIT),
-                                               infop, stat_addr, ru);
-                                       /* He released the lock.  */
-                                       if (retval != 0)
-                                               goto end;
-                                       break;
-                               }
+                               retval = wait_task_zombie(p,
+                                               (options & WNOWAIT), infop,
+                                               stat_addr, ru);
+                               /* He released the lock.  */
+                               if (retval != 0)
+                                       goto end;
+                       } else {
 check_continued:
                                /*
                                 * It's running now, so it might later
@@ -1625,12 +1615,11 @@ check_continued:
                                flag = 1;
                                if (!unlikely(options & WCONTINUED))
                                        continue;
-                               retval = wait_task_continued(
-                                       p, (options & WNOWAIT),
-                                       infop, stat_addr, ru);
+                               retval = wait_task_continued(p,
+                                               (options & WNOWAIT), infop,
+                                               stat_addr, ru);
                                if (retval != 0) /* He released the lock.  */
                                        goto end;
-                               break;
                        }
                }
                if (!flag) {
index 05e0b6f4365bfc5fca5ef1cabd400c3894c013e3..2b55b74cd99999f1eccdedc2158d29945ab16d98 100644 (file)
@@ -325,7 +325,7 @@ static inline int mm_alloc_pgd(struct mm_struct * mm)
 
 static inline void mm_free_pgd(struct mm_struct * mm)
 {
-       pgd_free(mm->pgd);
+       pgd_free(mm, mm->pgd);
 }
 #else
 #define dup_mmap(mm, oldmm)    (0)
@@ -1118,6 +1118,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,
 #ifdef CONFIG_SECURITY
        p->security = NULL;
 #endif
+       p->cap_bset = current->cap_bset;
        p->io_context = NULL;
        p->audit_context = NULL;
        cgroup_fork(p);
@@ -1450,6 +1451,23 @@ long do_fork(unsigned long clone_flags,
        int trace = 0;
        long nr;
 
+       /*
+        * We hope to recycle these flags after 2.6.26
+        */
+       if (unlikely(clone_flags & CLONE_STOPPED)) {
+               static int __read_mostly count = 100;
+
+               if (count > 0 && printk_ratelimit()) {
+                       char comm[TASK_COMM_LEN];
+
+                       count--;
+                       printk(KERN_INFO "fork(): process `%s' used deprecated "
+                                       "clone flags 0x%lx\n",
+                               get_task_comm(comm, current),
+                               clone_flags & CLONE_STOPPED);
+               }
+       }
+
        if (unlikely(current->ptrace)) {
                trace = fork_traceflag (clone_flags);
                if (trace)
index db9824de8bf061323b734d88377a6fa606fb9a86..a6baaec44b8f89009bafe2597fa90a6697702afa 100644 (file)
@@ -109,6 +109,9 @@ struct futex_q {
        /* Optional priority inheritance state: */
        struct futex_pi_state *pi_state;
        struct task_struct *task;
+
+       /* Bitset for the optional bitmasked wakeup */
+       u32 bitset;
 };
 
 /*
@@ -722,7 +725,7 @@ double_lock_hb(struct futex_hash_bucket *hb1, struct futex_hash_bucket *hb2)
  * to this virtual address:
  */
 static int futex_wake(u32 __user *uaddr, struct rw_semaphore *fshared,
-                     int nr_wake)
+                     int nr_wake, u32 bitset)
 {
        struct futex_hash_bucket *hb;
        struct futex_q *this, *next;
@@ -730,6 +733,9 @@ static int futex_wake(u32 __user *uaddr, struct rw_semaphore *fshared,
        union futex_key key;
        int ret;
 
+       if (!bitset)
+               return -EINVAL;
+
        futex_lock_mm(fshared);
 
        ret = get_futex_key(uaddr, fshared, &key);
@@ -746,6 +752,11 @@ static int futex_wake(u32 __user *uaddr, struct rw_semaphore *fshared,
                                ret = -EINVAL;
                                break;
                        }
+
+                       /* Check if one of the bits is set in both bitsets */
+                       if (!(this->bitset & bitset))
+                               continue;
+
                        wake_futex(this);
                        if (++ret >= nr_wake)
                                break;
@@ -1156,7 +1167,7 @@ static int fixup_pi_state_owner(u32 __user *uaddr, struct futex_q *q,
 static long futex_wait_restart(struct restart_block *restart);
 
 static int futex_wait(u32 __user *uaddr, struct rw_semaphore *fshared,
-                     u32 val, ktime_t *abs_time)
+                     u32 val, ktime_t *abs_time, u32 bitset)
 {
        struct task_struct *curr = current;
        DECLARE_WAITQUEUE(wait, curr);
@@ -1167,7 +1178,11 @@ static int futex_wait(u32 __user *uaddr, struct rw_semaphore *fshared,
        struct hrtimer_sleeper t;
        int rem = 0;
 
+       if (!bitset)
+               return -EINVAL;
+
        q.pi_state = NULL;
+       q.bitset = bitset;
  retry:
        futex_lock_mm(fshared);
 
@@ -1252,6 +1267,8 @@ static int futex_wait(u32 __user *uaddr, struct rw_semaphore *fshared,
                        t.timer.expires = *abs_time;
 
                        hrtimer_start(&t.timer, t.timer.expires, HRTIMER_MODE_ABS);
+                       if (!hrtimer_active(&t.timer))
+                               t.task = NULL;
 
                        /*
                         * the timer could have already expired, in which
@@ -1293,6 +1310,7 @@ static int futex_wait(u32 __user *uaddr, struct rw_semaphore *fshared,
                restart->futex.uaddr = (u32 *)uaddr;
                restart->futex.val = val;
                restart->futex.time = abs_time->tv64;
+               restart->futex.bitset = bitset;
                restart->futex.flags = 0;
 
                if (fshared)
@@ -1319,7 +1337,8 @@ static long futex_wait_restart(struct restart_block *restart)
        restart->fn = do_no_restart_syscall;
        if (restart->futex.flags & FLAGS_SHARED)
                fshared = &current->mm->mmap_sem;
-       return (long)futex_wait(uaddr, fshared, restart->futex.val, &t);
+       return (long)futex_wait(uaddr, fshared, restart->futex.val, &t,
+                               restart->futex.bitset);
 }
 
 
@@ -1535,9 +1554,6 @@ static int futex_lock_pi(u32 __user *uaddr, struct rw_semaphore *fshared,
                                owner = rt_mutex_owner(&q.pi_state->pi_mutex);
                                res = fixup_pi_state_owner(uaddr, &q, owner);
 
-                               WARN_ON(rt_mutex_owner(&q.pi_state->pi_mutex) !=
-                                       owner);
-
                                /* propagate -EFAULT, if the fixup failed */
                                if (res)
                                        ret = res;
@@ -1943,7 +1959,8 @@ retry:
                 * PI futexes happens in exit_pi_state():
                 */
                if (!pi && (uval & FUTEX_WAITERS))
-                               futex_wake(uaddr, &curr->mm->mmap_sem, 1);
+                       futex_wake(uaddr, &curr->mm->mmap_sem, 1,
+                                  FUTEX_BITSET_MATCH_ANY);
        }
        return 0;
 }
@@ -2043,10 +2060,14 @@ long do_futex(u32 __user *uaddr, int op, u32 val, ktime_t *timeout,
 
        switch (cmd) {
        case FUTEX_WAIT:
-               ret = futex_wait(uaddr, fshared, val, timeout);
+               val3 = FUTEX_BITSET_MATCH_ANY;
+       case FUTEX_WAIT_BITSET:
+               ret = futex_wait(uaddr, fshared, val, timeout, val3);
                break;
        case FUTEX_WAKE:
-               ret = futex_wake(uaddr, fshared, val);
+               val3 = FUTEX_BITSET_MATCH_ANY;
+       case FUTEX_WAKE_BITSET:
+               ret = futex_wake(uaddr, fshared, val, val3);
                break;
        case FUTEX_FD:
                /* non-zero val means F_SETOWN(getpid()) & F_SETSIG(val) */
@@ -2086,7 +2107,8 @@ asmlinkage long sys_futex(u32 __user *uaddr, int op, u32 val,
        u32 val2 = 0;
        int cmd = op & FUTEX_CMD_MASK;
 
-       if (utime && (cmd == FUTEX_WAIT || cmd == FUTEX_LOCK_PI)) {
+       if (utime && (cmd == FUTEX_WAIT || cmd == FUTEX_LOCK_PI ||
+                     cmd == FUTEX_WAIT_BITSET)) {
                if (copy_from_user(&ts, utime, sizeof(ts)) != 0)
                        return -EFAULT;
                if (!timespec_valid(&ts))
index 0a43def6fee7de877f43bdd0d7276efc05b8a48e..133d558db452e38b68c664e9560457f7c3902fc9 100644 (file)
@@ -167,7 +167,8 @@ asmlinkage long compat_sys_futex(u32 __user *uaddr, int op, u32 val,
        int val2 = 0;
        int cmd = op & FUTEX_CMD_MASK;
 
-       if (utime && (cmd == FUTEX_WAIT || cmd == FUTEX_LOCK_PI)) {
+       if (utime && (cmd == FUTEX_WAIT || cmd == FUTEX_LOCK_PI ||
+                     cmd == FUTEX_WAIT_BITSET)) {
                if (get_compat_timespec(&ts, utime))
                        return -EFAULT;
                if (!timespec_valid(&ts))
index bd5d6b5060bcd5704c278ea38954862fb463889f..668f3967eb394e37fcecc65e47e6dce75173b5dc 100644 (file)
@@ -306,7 +306,7 @@ EXPORT_SYMBOL_GPL(ktime_sub_ns);
 /*
  * Divide a ktime value by a nanosecond value
  */
-unsigned long ktime_divns(const ktime_t kt, s64 div)
+u64 ktime_divns(const ktime_t kt, s64 div)
 {
        u64 dclc, inc, dns;
        int sft = 0;
@@ -321,7 +321,7 @@ unsigned long ktime_divns(const ktime_t kt, s64 div)
        dclc >>= sft;
        do_div(dclc, (unsigned long) div);
 
-       return (unsigned long) dclc;
+       return dclc;
 }
 #endif /* BITS_PER_LONG >= 64 */
 
@@ -656,10 +656,9 @@ void unlock_hrtimer_base(const struct hrtimer *timer, unsigned long *flags)
  * Forward the timer expiry so it will expire in the future.
  * Returns the number of overruns.
  */
-unsigned long
-hrtimer_forward(struct hrtimer *timer, ktime_t now, ktime_t interval)
+u64 hrtimer_forward(struct hrtimer *timer, ktime_t now, ktime_t interval)
 {
-       unsigned long orun = 1;
+       u64 orun = 1;
        ktime_t delta;
 
        delta = ktime_sub(now, timer->expires);
@@ -1315,6 +1314,8 @@ static int __sched do_nanosleep(struct hrtimer_sleeper *t, enum hrtimer_mode mod
 
        } while (t->task && !signal_pending(current));
 
+       __set_current_state(TASK_RUNNING);
+
        return t->task == NULL;
 }
 
diff --git a/kernel/latency.c b/kernel/latency.c
deleted file mode 100644 (file)
index e63fcac..0000000
+++ /dev/null
@@ -1,280 +0,0 @@
-/*
- * latency.c: Explicit system-wide latency-expectation infrastructure
- *
- * The purpose of this infrastructure is to allow device drivers to set
- * latency constraint they have and to collect and summarize these
- * expectations globally. The cummulated result can then be used by
- * power management and similar users to make decisions that have
- * tradoffs with a latency component.
- *
- * An example user of this are the x86 C-states; each higher C state saves
- * more power, but has a higher exit latency. For the idle loop power
- * code to make a good decision which C-state to use, information about
- * acceptable latencies is required.
- *
- * An example announcer of latency is an audio driver that knowns it
- * will get an interrupt when the hardware has 200 usec of samples
- * left in the DMA buffer; in that case the driver can set a latency
- * constraint of, say, 150 usec.
- *
- * Multiple drivers can each announce their maximum accepted latency,
- * to keep these appart, a string based identifier is used.
- *
- *
- * (C) Copyright 2006 Intel Corporation
- * Author: Arjan van de Ven <arjan@linux.intel.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; version 2
- * of the License.
- */
-
-#include <linux/latency.h>
-#include <linux/list.h>
-#include <linux/spinlock.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/notifier.h>
-#include <linux/jiffies.h>
-#include <asm/atomic.h>
-
-struct latency_info {
-       struct list_head list;
-       int usecs;
-       char *identifier;
-};
-
-/*
- * locking rule: all modifications to current_max_latency and
- * latency_list need to be done while holding the latency_lock.
- * latency_lock needs to be taken _irqsave.
- */
-static atomic_t current_max_latency;
-static DEFINE_SPINLOCK(latency_lock);
-
-static LIST_HEAD(latency_list);
-static BLOCKING_NOTIFIER_HEAD(latency_notifier);
-
-/*
- * This function returns the maximum latency allowed, which
- * happens to be the minimum of all maximum latencies on the
- * list.
- */
-static int __find_max_latency(void)
-{
-       int min = INFINITE_LATENCY;
-       struct latency_info *info;
-
-       list_for_each_entry(info, &latency_list, list) {
-               if (info->usecs < min)
-                       min = info->usecs;
-       }
-       return min;
-}
-
-/**
- * set_acceptable_latency - sets the maximum latency acceptable
- * @identifier: string that identifies this driver
- * @usecs: maximum acceptable latency for this driver
- *
- * This function informs the kernel that this device(driver)
- * can accept at most usecs latency. This setting is used for
- * power management and similar tradeoffs.
- *
- * This function sleeps and can only be called from process
- * context.
- * Calling this function with an existing identifier is valid
- * and will cause the existing latency setting to be changed.
- */
-void set_acceptable_latency(char *identifier, int usecs)
-{
-       struct latency_info *info, *iter;
-       unsigned long flags;
-       int found_old = 0;
-
-       info = kzalloc(sizeof(struct latency_info), GFP_KERNEL);
-       if (!info)
-               return;
-       info->usecs = usecs;
-       info->identifier = kstrdup(identifier, GFP_KERNEL);
-       if (!info->identifier)
-               goto free_info;
-
-       spin_lock_irqsave(&latency_lock, flags);
-       list_for_each_entry(iter, &latency_list, list) {
-               if (strcmp(iter->identifier, identifier)==0) {
-                       found_old = 1;
-                       iter->usecs = usecs;
-                       break;
-               }
-       }
-       if (!found_old)
-               list_add(&info->list, &latency_list);
-
-       if (usecs < atomic_read(&current_max_latency))
-               atomic_set(&current_max_latency, usecs);
-
-       spin_unlock_irqrestore(&latency_lock, flags);
-
-       blocking_notifier_call_chain(&latency_notifier,
-               atomic_read(&current_max_latency), NULL);
-
-       /*
-        * if we inserted the new one, we're done; otherwise there was
-        * an existing one so we need to free the redundant data
-        */
-       if (!found_old)
-               return;
-
-       kfree(info->identifier);
-free_info:
-       kfree(info);
-}
-EXPORT_SYMBOL_GPL(set_acceptable_latency);
-
-/**
- * modify_acceptable_latency - changes the maximum latency acceptable
- * @identifier: string that identifies this driver
- * @usecs: maximum acceptable latency for this driver
- *
- * This function informs the kernel that this device(driver)
- * can accept at most usecs latency. This setting is used for
- * power management and similar tradeoffs.
- *
- * This function does not sleep and can be called in any context.
- * Trying to use a non-existing identifier silently gets ignored.
- *
- * Due to the atomic nature of this function, the modified latency
- * value will only be used for future decisions; past decisions
- * can still lead to longer latencies in the near future.
- */
-void modify_acceptable_latency(char *identifier, int usecs)
-{
-       struct latency_info *iter;
-       unsigned long flags;
-
-       spin_lock_irqsave(&latency_lock, flags);
-       list_for_each_entry(iter, &latency_list, list) {
-               if (strcmp(iter->identifier, identifier) == 0) {
-                       iter->usecs = usecs;
-                       break;
-               }
-       }
-       if (usecs < atomic_read(&current_max_latency))
-               atomic_set(&current_max_latency, usecs);
-       spin_unlock_irqrestore(&latency_lock, flags);
-}
-EXPORT_SYMBOL_GPL(modify_acceptable_latency);
-
-/**
- * remove_acceptable_latency - removes the maximum latency acceptable
- * @identifier: string that identifies this driver
- *
- * This function removes a previously set maximum latency setting
- * for the driver and frees up any resources associated with the
- * bookkeeping needed for this.
- *
- * This function does not sleep and can be called in any context.
- * Trying to use a non-existing identifier silently gets ignored.
- */
-void remove_acceptable_latency(char *identifier)
-{
-       unsigned long flags;
-       int newmax = 0;
-       struct latency_info *iter, *temp;
-
-       spin_lock_irqsave(&latency_lock, flags);
-
-       list_for_each_entry_safe(iter,  temp, &latency_list, list) {
-               if (strcmp(iter->identifier, identifier) == 0) {
-                       list_del(&iter->list);
-                       newmax = iter->usecs;
-                       kfree(iter->identifier);
-                       kfree(iter);
-                       break;
-               }
-       }
-
-       /* If we just deleted the system wide value, we need to
-        * recalculate with a full search
-        */
-       if (newmax == atomic_read(&current_max_latency)) {
-               newmax = __find_max_latency();
-               atomic_set(&current_max_latency, newmax);
-       }
-       spin_unlock_irqrestore(&latency_lock, flags);
-}
-EXPORT_SYMBOL_GPL(remove_acceptable_latency);
-
-/**
- * system_latency_constraint - queries the system wide latency maximum
- *
- * This function returns the system wide maximum latency in
- * microseconds.
- *
- * This function does not sleep and can be called in any context.
- */
-int system_latency_constraint(void)
-{
-       return atomic_read(&current_max_latency);
-}
-EXPORT_SYMBOL_GPL(system_latency_constraint);
-
-/**
- * synchronize_acceptable_latency - recalculates all latency decisions
- *
- * This function will cause a callback to various kernel pieces that
- * will make those pieces rethink their latency decisions. This implies
- * that if there are overlong latencies in hardware state already, those
- * latencies get taken right now. When this call completes no overlong
- * latency decisions should be active anymore.
- *
- * Typical usecase of this is after a modify_acceptable_latency() call,
- * which in itself is non-blocking and non-synchronizing.
- *
- * This function blocks and should not be called with locks held.
- */
-
-void synchronize_acceptable_latency(void)
-{
-       blocking_notifier_call_chain(&latency_notifier,
-               atomic_read(&current_max_latency), NULL);
-}
-EXPORT_SYMBOL_GPL(synchronize_acceptable_latency);
-
-/*
- * Latency notifier: this notifier gets called when a non-atomic new
- * latency value gets set. The expectation nof the caller of the
- * non-atomic set is that when the call returns, future latencies
- * are within bounds, so the functions on the notifier list are
- * expected to take the overlong latencies immediately, inside the
- * callback, and not make a overlong latency decision anymore.
- *
- * The callback gets called when the new latency value is made
- * active so system_latency_constraint() returns the new latency.
- */
-int register_latency_notifier(struct notifier_block * nb)
-{
-       return blocking_notifier_chain_register(&latency_notifier, nb);
-}
-EXPORT_SYMBOL_GPL(register_latency_notifier);
-
-int unregister_latency_notifier(struct notifier_block * nb)
-{
-       return blocking_notifier_chain_unregister(&latency_notifier, nb);
-}
-EXPORT_SYMBOL_GPL(unregister_latency_notifier);
-
-static __init int latency_init(void)
-{
-       atomic_set(&current_max_latency, INFINITE_LATENCY);
-       /*
-        * we don't want by default to have longer latencies than 2 ticks,
-        * since that would cause lost ticks
-        */
-       set_acceptable_latency("kernel", 2*1000000/HZ);
-       return 0;
-}
-
-module_init(latency_init);
index d7fe50cc556fd79624196a175b74996d9b23cf41..d9ec9b6662501e0c5815f61812ad1f42e8b79d1c 100644 (file)
@@ -166,9 +166,12 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
                 * got a signal? (This code gets eliminated in the
                 * TASK_UNINTERRUPTIBLE case.)
                 */
-               if (unlikely(state == TASK_INTERRUPTIBLE &&
-                                               signal_pending(task))) {
-                       mutex_remove_waiter(lock, &waiter, task_thread_info(task));
+               if (unlikely((state == TASK_INTERRUPTIBLE &&
+                                       signal_pending(task)) ||
+                             (state == TASK_KILLABLE &&
+                                       fatal_signal_pending(task)))) {
+                       mutex_remove_waiter(lock, &waiter,
+                                           task_thread_info(task));
                        mutex_release(&lock->dep_map, 1, ip);
                        spin_unlock_mutex(&lock->wait_lock, flags);
 
@@ -210,6 +213,14 @@ mutex_lock_nested(struct mutex *lock, unsigned int subclass)
 
 EXPORT_SYMBOL_GPL(mutex_lock_nested);
 
+int __sched
+mutex_lock_killable_nested(struct mutex *lock, unsigned int subclass)
+{
+       might_sleep();
+       return __mutex_lock_common(lock, TASK_KILLABLE, subclass, _RET_IP_);
+}
+EXPORT_SYMBOL_GPL(mutex_lock_killable_nested);
+
 int __sched
 mutex_lock_interruptible_nested(struct mutex *lock, unsigned int subclass)
 {
@@ -272,6 +283,9 @@ __mutex_unlock_slowpath(atomic_t *lock_count)
  * mutex_lock_interruptible() and mutex_trylock().
  */
 static int fastcall noinline __sched
+__mutex_lock_killable_slowpath(atomic_t *lock_count);
+
+static noinline int fastcall __sched
 __mutex_lock_interruptible_slowpath(atomic_t *lock_count);
 
 /***
@@ -294,6 +308,14 @@ int fastcall __sched mutex_lock_interruptible(struct mutex *lock)
 
 EXPORT_SYMBOL(mutex_lock_interruptible);
 
+int fastcall __sched mutex_lock_killable(struct mutex *lock)
+{
+       might_sleep();
+       return __mutex_fastpath_lock_retval
+                       (&lock->count, __mutex_lock_killable_slowpath);
+}
+EXPORT_SYMBOL(mutex_lock_killable);
+
 static void fastcall noinline __sched
 __mutex_lock_slowpath(atomic_t *lock_count)
 {
@@ -303,6 +325,14 @@ __mutex_lock_slowpath(atomic_t *lock_count)
 }
 
 static int fastcall noinline __sched
+__mutex_lock_killable_slowpath(atomic_t *lock_count)
+{
+       struct mutex *lock = container_of(lock_count, struct mutex, count);
+
+       return __mutex_lock_common(lock, TASK_KILLABLE, 0, _RET_IP_);
+}
+
+static noinline int fastcall __sched
 __mutex_lock_interruptible_slowpath(atomic_t *lock_count)
 {
        struct mutex *lock = container_of(lock_count, struct mutex, count);
diff --git a/kernel/pm_qos_params.c b/kernel/pm_qos_params.c
new file mode 100644 (file)
index 0000000..0afe32b
--- /dev/null
@@ -0,0 +1,425 @@
+/*
+ * This module exposes the interface to kernel space for specifying
+ * QoS dependencies.  It provides infrastructure for registration of:
+ *
+ * Dependents on a QoS value : register requirements
+ * Watchers of QoS value : get notified when target QoS value changes
+ *
+ * This QoS design is best effort based.  Dependents register their QoS needs.
+ * Watchers register to keep track of the current QoS needs of the system.
+ *
+ * There are 3 basic classes of QoS parameter: latency, timeout, throughput
+ * each have defined units:
+ * latency: usec
+ * timeout: usec <-- currently not used.
+ * throughput: kbs (kilo byte / sec)
+ *
+ * There are lists of pm_qos_objects each one wrapping requirements, notifiers
+ *
+ * User mode requirements on a QOS parameter register themselves to the
+ * subsystem by opening the device node /dev/... and writing there request to
+ * the node.  As long as the process holds a file handle open to the node the
+ * client continues to be accounted for.  Upon file release the usermode
+ * requirement is removed and a new qos target is computed.  This way when the
+ * requirement that the application has is cleaned up when closes the file
+ * pointer or exits the pm_qos_object will get an opportunity to clean up.
+ *
+ * mark gross mgross@linux.intel.com
+ */
+
+#include <linux/pm_qos_params.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/time.h>
+#include <linux/fs.h>
+#include <linux/device.h>
+#include <linux/miscdevice.h>
+#include <linux/string.h>
+#include <linux/platform_device.h>
+#include <linux/init.h>
+
+#include <linux/uaccess.h>
+
+/*
+ * locking rule: all changes to target_value or requirements or notifiers lists
+ * or pm_qos_object list and pm_qos_objects need to happen with pm_qos_lock
+ * held, taken with _irqsave.  One lock to rule them all
+ */
+struct requirement_list {
+       struct list_head list;
+       union {
+               s32 value;
+               s32 usec;
+               s32 kbps;
+       };
+       char *name;
+};
+
+static s32 max_compare(s32 v1, s32 v2);
+static s32 min_compare(s32 v1, s32 v2);
+
+struct pm_qos_object {
+       struct requirement_list requirements;
+       struct blocking_notifier_head *notifiers;
+       struct miscdevice pm_qos_power_miscdev;
+       char *name;
+       s32 default_value;
+       s32 target_value;
+       s32 (*comparitor)(s32, s32);
+};
+
+static struct pm_qos_object null_pm_qos;
+static BLOCKING_NOTIFIER_HEAD(cpu_dma_lat_notifier);
+static struct pm_qos_object cpu_dma_pm_qos = {
+       .requirements = {LIST_HEAD_INIT(cpu_dma_pm_qos.requirements.list)},
+       .notifiers = &cpu_dma_lat_notifier,
+       .name = "cpu_dma_latency",
+       .default_value = 2000 * USEC_PER_SEC,
+       .target_value = 2000 * USEC_PER_SEC,
+       .comparitor = min_compare
+};
+
+static BLOCKING_NOTIFIER_HEAD(network_lat_notifier);
+static struct pm_qos_object network_lat_pm_qos = {
+       .requirements = {LIST_HEAD_INIT(network_lat_pm_qos.requirements.list)},
+       .notifiers = &network_lat_notifier,
+       .name = "network_latency",
+       .default_value = 2000 * USEC_PER_SEC,
+       .target_value = 2000 * USEC_PER_SEC,
+       .comparitor = min_compare
+};
+
+
+static BLOCKING_NOTIFIER_HEAD(network_throughput_notifier);
+static struct pm_qos_object network_throughput_pm_qos = {
+       .requirements =
+               {LIST_HEAD_INIT(network_throughput_pm_qos.requirements.list)},
+       .notifiers = &network_throughput_notifier,
+       .name = "network_throughput",
+       .default_value = 0,
+       .target_value = 0,
+       .comparitor = max_compare
+};
+
+
+static struct pm_qos_object *pm_qos_array[] = {
+       &null_pm_qos,
+       &cpu_dma_pm_qos,
+       &network_lat_pm_qos,
+       &network_throughput_pm_qos
+};
+
+static DEFINE_SPINLOCK(pm_qos_lock);
+
+static ssize_t pm_qos_power_write(struct file *filp, const char __user *buf,
+               size_t count, loff_t *f_pos);
+static int pm_qos_power_open(struct inode *inode, struct file *filp);
+static int pm_qos_power_release(struct inode *inode, struct file *filp);
+
+static const struct file_operations pm_qos_power_fops = {
+       .write = pm_qos_power_write,
+       .open = pm_qos_power_open,
+       .release = pm_qos_power_release,
+};
+
+/* static helper functions */
+static s32 max_compare(s32 v1, s32 v2)
+{
+       return max(v1, v2);
+}
+
+static s32 min_compare(s32 v1, s32 v2)
+{
+       return min(v1, v2);
+}
+
+
+static void update_target(int target)
+{
+       s32 extreme_value;
+       struct requirement_list *node;
+       unsigned long flags;
+       int call_notifier = 0;
+
+       spin_lock_irqsave(&pm_qos_lock, flags);
+       extreme_value = pm_qos_array[target]->default_value;
+       list_for_each_entry(node,
+                       &pm_qos_array[target]->requirements.list, list) {
+               extreme_value = pm_qos_array[target]->comparitor(
+                               extreme_value, node->value);
+       }
+       if (pm_qos_array[target]->target_value != extreme_value) {
+               call_notifier = 1;
+               pm_qos_array[target]->target_value = extreme_value;
+               pr_debug(KERN_ERR "new target for qos %d is %d\n", target,
+                       pm_qos_array[target]->target_value);
+       }
+       spin_unlock_irqrestore(&pm_qos_lock, flags);
+
+       if (call_notifier)
+               blocking_notifier_call_chain(pm_qos_array[target]->notifiers,
+                       (unsigned long) extreme_value, NULL);
+}
+
+static int register_pm_qos_misc(struct pm_qos_object *qos)
+{
+       qos->pm_qos_power_miscdev.minor = MISC_DYNAMIC_MINOR;
+       qos->pm_qos_power_miscdev.name = qos->name;
+       qos->pm_qos_power_miscdev.fops = &pm_qos_power_fops;
+
+       return misc_register(&qos->pm_qos_power_miscdev);
+}
+
+static int find_pm_qos_object_by_minor(int minor)
+{
+       int pm_qos_class;
+
+       for (pm_qos_class = 0;
+               pm_qos_class < PM_QOS_NUM_CLASSES; pm_qos_class++) {
+               if (minor ==
+                       pm_qos_array[pm_qos_class]->pm_qos_power_miscdev.minor)
+                       return pm_qos_class;
+       }
+       return -1;
+}
+
+/**
+ * pm_qos_requirement - returns current system wide qos expectation
+ * @pm_qos_class: identification of which qos value is requested
+ *
+ * This function returns the current target value in an atomic manner.
+ */
+int pm_qos_requirement(int pm_qos_class)
+{
+       int ret_val;
+       unsigned long flags;
+
+       spin_lock_irqsave(&pm_qos_lock, flags);
+       ret_val = pm_qos_array[pm_qos_class]->target_value;
+       spin_unlock_irqrestore(&pm_qos_lock, flags);
+
+       return ret_val;
+}
+EXPORT_SYMBOL_GPL(pm_qos_requirement);
+
+/**
+ * pm_qos_add_requirement - inserts new qos request into the list
+ * @pm_qos_class: identifies which list of qos request to us
+ * @name: identifies the request
+ * @value: defines the qos request
+ *
+ * This function inserts a new entry in the pm_qos_class list of requested qos
+ * performance charactoistics.  It recomputes the agregate QoS expectations for
+ * the pm_qos_class of parrameters.
+ */
+int pm_qos_add_requirement(int pm_qos_class, char *name, s32 value)
+{
+       struct requirement_list *dep;
+       unsigned long flags;
+
+       dep = kzalloc(sizeof(struct requirement_list), GFP_KERNEL);
+       if (dep) {
+               if (value == PM_QOS_DEFAULT_VALUE)
+                       dep->value = pm_qos_array[pm_qos_class]->default_value;
+               else
+                       dep->value = value;
+               dep->name = kstrdup(name, GFP_KERNEL);
+               if (!dep->name)
+                       goto cleanup;
+
+               spin_lock_irqsave(&pm_qos_lock, flags);
+               list_add(&dep->list,
+                       &pm_qos_array[pm_qos_class]->requirements.list);
+               spin_unlock_irqrestore(&pm_qos_lock, flags);
+               update_target(pm_qos_class);
+
+               return 0;
+       }
+
+cleanup:
+       kfree(dep);
+       return -ENOMEM;
+}
+EXPORT_SYMBOL_GPL(pm_qos_add_requirement);
+
+/**
+ * pm_qos_update_requirement - modifies an existing qos request
+ * @pm_qos_class: identifies which list of qos request to us
+ * @name: identifies the request
+ * @value: defines the qos request
+ *
+ * Updates an existing qos requierement for the pm_qos_class of parameters along
+ * with updating the target pm_qos_class value.
+ *
+ * If the named request isn't in the lest then no change is made.
+ */
+int pm_qos_update_requirement(int pm_qos_class, char *name, s32 new_value)
+{
+       unsigned long flags;
+       struct requirement_list *node;
+       int pending_update = 0;
+
+       spin_lock_irqsave(&pm_qos_lock, flags);
+       list_for_each_entry(node,
+               &pm_qos_array[pm_qos_class]->requirements.list, list) {
+               if (strcmp(node->name, name) == 0) {
+                       if (new_value == PM_QOS_DEFAULT_VALUE)
+                               node->value =
+                               pm_qos_array[pm_qos_class]->default_value;
+                       else
+                               node->value = new_value;
+                       pending_update = 1;
+                       break;
+               }
+       }
+       spin_unlock_irqrestore(&pm_qos_lock, flags);
+       if (pending_update)
+               update_target(pm_qos_class);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(pm_qos_update_requirement);
+
+/**
+ * pm_qos_remove_requirement - modifies an existing qos request
+ * @pm_qos_class: identifies which list of qos request to us
+ * @name: identifies the request
+ *
+ * Will remove named qos request from pm_qos_class list of parrameters and
+ * recompute the current target value for the pm_qos_class.
+ */
+void pm_qos_remove_requirement(int pm_qos_class, char *name)
+{
+       unsigned long flags;
+       struct requirement_list *node;
+       int pending_update = 0;
+
+       spin_lock_irqsave(&pm_qos_lock, flags);
+       list_for_each_entry(node,
+               &pm_qos_array[pm_qos_class]->requirements.list, list) {
+               if (strcmp(node->name, name) == 0) {
+                       kfree(node->name);
+                       list_del(&node->list);
+                       kfree(node);
+                       pending_update = 1;
+                       break;
+               }
+       }
+       spin_unlock_irqrestore(&pm_qos_lock, flags);
+       if (pending_update)
+               update_target(pm_qos_class);
+}
+EXPORT_SYMBOL_GPL(pm_qos_remove_requirement);
+
+/**
+ * pm_qos_add_notifier - sets notification entry for changes to target value
+ * @pm_qos_class: identifies which qos target changes should be notified.
+ * @notifier: notifier block managed by caller.
+ *
+ * will register the notifier into a notification chain that gets called
+ * uppon changes to the pm_qos_class target value.
+ */
+ int pm_qos_add_notifier(int pm_qos_class, struct notifier_block *notifier)
+{
+       int retval;
+
+       retval = blocking_notifier_chain_register(
+                       pm_qos_array[pm_qos_class]->notifiers, notifier);
+
+       return retval;
+}
+EXPORT_SYMBOL_GPL(pm_qos_add_notifier);
+
+/**
+ * pm_qos_remove_notifier - deletes notification entry from chain.
+ * @pm_qos_class: identifies which qos target changes are notified.
+ * @notifier: notifier block to be removed.
+ *
+ * will remove the notifier from the notification chain that gets called
+ * uppon changes to the pm_qos_class target value.
+ */
+int pm_qos_remove_notifier(int pm_qos_class, struct notifier_block *notifier)
+{
+       int retval;
+
+       retval = blocking_notifier_chain_unregister(
+                       pm_qos_array[pm_qos_class]->notifiers, notifier);
+
+       return retval;
+}
+EXPORT_SYMBOL_GPL(pm_qos_remove_notifier);
+
+#define PID_NAME_LEN sizeof("process_1234567890")
+static char name[PID_NAME_LEN];
+
+static int pm_qos_power_open(struct inode *inode, struct file *filp)
+{
+       int ret;
+       long pm_qos_class;
+
+       pm_qos_class = find_pm_qos_object_by_minor(iminor(inode));
+       if (pm_qos_class >= 0) {
+               filp->private_data = (void *)pm_qos_class;
+               sprintf(name, "process_%d", current->pid);
+               ret = pm_qos_add_requirement(pm_qos_class, name,
+                                       PM_QOS_DEFAULT_VALUE);
+               if (ret >= 0)
+                       return 0;
+       }
+
+       return -EPERM;
+}
+
+static int pm_qos_power_release(struct inode *inode, struct file *filp)
+{
+       int pm_qos_class;
+
+       pm_qos_class = (long)filp->private_data;
+       sprintf(name, "process_%d", current->pid);
+       pm_qos_remove_requirement(pm_qos_class, name);
+
+       return 0;
+}
+
+static ssize_t pm_qos_power_write(struct file *filp, const char __user *buf,
+               size_t count, loff_t *f_pos)
+{
+       s32 value;
+       int pm_qos_class;
+
+       pm_qos_class = (long)filp->private_data;
+       if (count != sizeof(s32))
+               return -EINVAL;
+       if (copy_from_user(&value, buf, sizeof(s32)))
+               return -EFAULT;
+       sprintf(name, "process_%d", current->pid);
+       pm_qos_update_requirement(pm_qos_class, name, value);
+
+       return  sizeof(s32);
+}
+
+
+static int __init pm_qos_power_init(void)
+{
+       int ret = 0;
+
+       ret = register_pm_qos_misc(&cpu_dma_pm_qos);
+       if (ret < 0) {
+               printk(KERN_ERR "pm_qos_param: cpu_dma_latency setup failed\n");
+               return ret;
+       }
+       ret = register_pm_qos_misc(&network_lat_pm_qos);
+       if (ret < 0) {
+               printk(KERN_ERR "pm_qos_param: network_latency setup failed\n");
+               return ret;
+       }
+       ret = register_pm_qos_misc(&network_throughput_pm_qos);
+       if (ret < 0)
+               printk(KERN_ERR
+                       "pm_qos_param: network_throughput setup failed\n");
+
+       return ret;
+}
+
+late_initcall(pm_qos_power_init);
index 35b4bbfc78ff6ee7d3f389baf0430231ed09af7b..122d5c787fe2fc7300deeb153fec9a1d3835cd34 100644 (file)
@@ -256,8 +256,9 @@ static void schedule_next_timer(struct k_itimer *timr)
        if (timr->it.real.interval.tv64 == 0)
                return;
 
-       timr->it_overrun += hrtimer_forward(timer, timer->base->get_time(),
-                                           timr->it.real.interval);
+       timr->it_overrun += (unsigned int) hrtimer_forward(timer,
+                                               timer->base->get_time(),
+                                               timr->it.real.interval);
 
        timr->it_overrun_last = timr->it_overrun;
        timr->it_overrun = -1;
@@ -386,7 +387,7 @@ static enum hrtimer_restart posix_timer_fn(struct hrtimer *timer)
                                        now = ktime_add(now, kj);
                        }
 #endif
-                       timr->it_overrun +=
+                       timr->it_overrun += (unsigned int)
                                hrtimer_forward(timer, now,
                                                timr->it.real.interval);
                        ret = HRTIMER_RESTART;
@@ -493,7 +494,7 @@ sys_timer_create(const clockid_t which_clock,
                goto retry;
        else if (error) {
                /*
-                * Wierd looking, but we return EAGAIN if the IDR is
+                * Weird looking, but we return EAGAIN if the IDR is
                 * full (proper POSIX return value for this)
                 */
                error = -EAGAIN;
@@ -662,7 +663,7 @@ common_timer_get(struct k_itimer *timr, struct itimerspec *cur_setting)
         */
        if (iv.tv64 && (timr->it_requeue_pending & REQUEUE_PENDING ||
            (timr->it_sigev_notify & ~SIGEV_THREAD_ID) == SIGEV_NONE))
-               timr->it_overrun += hrtimer_forward(timer, now, iv);
+               timr->it_overrun += (unsigned int) hrtimer_forward(timer, now, iv);
 
        remaining = ktime_sub(timer->expires, now);
        /* Return 0 only, when the timer is expired and not pending */
index 8e186c678149e23581969a7acfca814a00295b95..ef9b802738a522851d7e95672164f83a997d8df6 100644 (file)
@@ -44,9 +44,30 @@ config PM_VERBOSE
        ---help---
        This option enables verbose messages from the Power Management code.
 
+config CAN_PM_TRACE
+       def_bool y
+       depends on PM_DEBUG && PM_SLEEP && EXPERIMENTAL
+
 config PM_TRACE
+       bool
+       help
+         This enables code to save the last PM event point across
+         reboot. The architecture needs to support this, x86 for
+         example does by saving things in the RTC, see below.
+
+         The architecture specific code must provide the extern
+         functions from <linux/resume-trace.h> as well as the
+         <asm/resume-trace.h> header with a TRACE_RESUME() macro.
+
+         The way the information is presented is architecture-
+         dependent, x86 will print the information during a
+         late_initcall.
+
+config PM_TRACE_RTC
        bool "Suspend/resume event tracing"
-       depends on PM_DEBUG && X86 && PM_SLEEP && EXPERIMENTAL
+       depends on CAN_PM_TRACE
+       depends on X86
+       select PM_TRACE
        default n
        ---help---
        This enables some cheesy code to save the last PM event point in the
@@ -63,7 +84,8 @@ config PM_TRACE
 
 config PM_SLEEP_SMP
        bool
-       depends on SUSPEND_SMP_POSSIBLE || HIBERNATION_SMP_POSSIBLE
+       depends on SMP
+       depends on ARCH_SUSPEND_POSSIBLE || ARCH_HIBERNATION_POSSIBLE
        depends on PM_SLEEP
        select HOTPLUG_CPU
        default y
@@ -73,46 +95,29 @@ config PM_SLEEP
        depends on SUSPEND || HIBERNATION
        default y
 
-config SUSPEND_UP_POSSIBLE
-       bool
-       depends on (X86 && !X86_VOYAGER) || PPC || ARM || BLACKFIN || MIPS \
-                  || SUPERH || FRV
-       depends on !SMP
-       default y
-
-config SUSPEND_SMP_POSSIBLE
-       bool
-       depends on (X86 && !X86_VOYAGER) \
-                  || (PPC && (PPC_PSERIES || PPC_PMAC)) || ARM
-       depends on SMP
-       default y
-
 config SUSPEND
        bool "Suspend to RAM and standby"
-       depends on PM
-       depends on SUSPEND_UP_POSSIBLE || SUSPEND_SMP_POSSIBLE
+       depends on PM && ARCH_SUSPEND_POSSIBLE
        default y
        ---help---
          Allow the system to enter sleep states in which main memory is
          powered and thus its contents are preserved, such as the
-         suspend-to-RAM state (i.e. the ACPI S3 state).
+         suspend-to-RAM state (e.g. the ACPI S3 state).
 
-config HIBERNATION_UP_POSSIBLE
-       bool
-       depends on X86 || PPC64_SWSUSP || PPC32
-       depends on !SMP
+config SUSPEND_FREEZER
+       bool "Enable freezer for suspend to RAM/standby" \
+               if ARCH_WANTS_FREEZER_CONTROL || BROKEN
+       depends on SUSPEND
        default y
+       help
+         This allows you to turn off the freezer for suspend. If this is
+         done, no tasks are frozen for suspend to RAM/standby.
 
-config HIBERNATION_SMP_POSSIBLE
-       bool
-       depends on (X86 && !X86_VOYAGER) || PPC64_SWSUSP
-       depends on SMP
-       default y
+         Turning OFF this setting is NOT recommended! If in doubt, say Y.
 
 config HIBERNATION
        bool "Hibernation (aka 'suspend to disk')"
-       depends on PM && SWAP
-       depends on HIBERNATION_UP_POSSIBLE || HIBERNATION_SMP_POSSIBLE
+       depends on PM && SWAP && ARCH_HIBERNATION_POSSIBLE
        ---help---
          Enable the suspend to disk (STD) functionality, which is usually
          called "hibernation" in user interfaces.  STD checkpoints the
index b138b431e27135aa7b2716335288069ea00beeee..859a8e59773a3a1822bf68700aac39600ff9a60f 100644 (file)
@@ -26,7 +26,7 @@
 
 
 static int noresume = 0;
-char resume_file[256] = CONFIG_PM_STD_PARTITION;
+static char resume_file[256] = CONFIG_PM_STD_PARTITION;
 dev_t swsusp_resume_device;
 sector_t swsusp_resume_block;
 
@@ -54,8 +54,8 @@ static struct platform_hibernation_ops *hibernation_ops;
 
 void hibernation_set_ops(struct platform_hibernation_ops *ops)
 {
-       if (ops && !(ops->start && ops->pre_snapshot && ops->finish
-           && ops->prepare && ops->enter && ops->pre_restore
+       if (ops && !(ops->begin && ops->end &&  ops->pre_snapshot
+           && ops->prepare && ops->finish && ops->enter && ops->pre_restore
            && ops->restore_cleanup)) {
                WARN_ON(1);
                return;
@@ -70,15 +70,55 @@ void hibernation_set_ops(struct platform_hibernation_ops *ops)
        mutex_unlock(&pm_mutex);
 }
 
+#ifdef CONFIG_PM_DEBUG
+static void hibernation_debug_sleep(void)
+{
+       printk(KERN_INFO "hibernation debug: Waiting for 5 seconds.\n");
+       mdelay(5000);
+}
+
+static int hibernation_testmode(int mode)
+{
+       if (hibernation_mode == mode) {
+               hibernation_debug_sleep();
+               return 1;
+       }
+       return 0;
+}
+
+static int hibernation_test(int level)
+{
+       if (pm_test_level == level) {
+               hibernation_debug_sleep();
+               return 1;
+       }
+       return 0;
+}
+#else /* !CONFIG_PM_DEBUG */
+static int hibernation_testmode(int mode) { return 0; }
+static int hibernation_test(int level) { return 0; }
+#endif /* !CONFIG_PM_DEBUG */
+
 /**
- *     platform_start - tell the platform driver that we're starting
+ *     platform_begin - tell the platform driver that we're starting
  *     hibernation
  */
 
-static int platform_start(int platform_mode)
+static int platform_begin(int platform_mode)
 {
        return (platform_mode && hibernation_ops) ?
-               hibernation_ops->start() : 0;
+               hibernation_ops->begin() : 0;
+}
+
+/**
+ *     platform_end - tell the platform driver that we've entered the
+ *     working state
+ */
+
+static void platform_end(int platform_mode)
+{
+       if (platform_mode && hibernation_ops)
+               hibernation_ops->end();
 }
 
 /**
@@ -145,7 +185,7 @@ static void platform_restore_cleanup(int platform_mode)
  *     reappears in this routine after a restore.
  */
 
-int create_image(int platform_mode)
+static int create_image(int platform_mode)
 {
        int error;
 
@@ -162,19 +202,25 @@ int create_image(int platform_mode)
         */
        error = device_power_down(PMSG_FREEZE);
        if (error) {
-               printk(KERN_ERR "Some devices failed to power down, "
-                       KERN_ERR "aborting suspend\n");
+               printk(KERN_ERR "PM: Some devices failed to power down, "
+                       "aborting hibernation\n");
                goto Enable_irqs;
        }
 
+       if (hibernation_test(TEST_CORE))
+               goto Power_up;
+
+       in_suspend = 1;
        save_processor_state();
        error = swsusp_arch_suspend();
        if (error)
-               printk(KERN_ERR "Error %d while creating the image\n", error);
+               printk(KERN_ERR "PM: Error %d creating hibernation image\n",
+                       error);
        /* Restore control flow magically appears here */
        restore_processor_state();
        if (!in_suspend)
                platform_leave(platform_mode);
+ Power_up:
        /* NOTE:  device_power_up() is just a resume() for devices
         * that suspended with irqs off ... no overall powerup.
         */
@@ -202,36 +248,90 @@ int hibernation_snapshot(int platform_mode)
        if (error)
                return error;
 
-       error = platform_start(platform_mode);
+       error = platform_begin(platform_mode);
        if (error)
-               return error;
+               goto Close;
 
        suspend_console();
        error = device_suspend(PMSG_FREEZE);
        if (error)
                goto Resume_console;
 
-       error = platform_pre_snapshot(platform_mode);
-       if (error)
+       if (hibernation_test(TEST_DEVICES))
                goto Resume_devices;
 
+       error = platform_pre_snapshot(platform_mode);
+       if (error || hibernation_test(TEST_PLATFORM))
+               goto Finish;
+
        error = disable_nonboot_cpus();
        if (!error) {
-               if (hibernation_mode != HIBERNATION_TEST) {
-                       in_suspend = 1;
-                       error = create_image(platform_mode);
-                       /* Control returns here after successful restore */
-               } else {
-                       printk("swsusp debug: Waiting for 5 seconds.\n");
-                       mdelay(5000);
-               }
+               if (hibernation_test(TEST_CPUS))
+                       goto Enable_cpus;
+
+               if (hibernation_testmode(HIBERNATION_TEST))
+                       goto Enable_cpus;
+
+               error = create_image(platform_mode);
+               /* Control returns here after successful restore */
        }
+ Enable_cpus:
        enable_nonboot_cpus();
Resume_devices:
Finish:
        platform_finish(platform_mode);
+ Resume_devices:
        device_resume();
  Resume_console:
        resume_console();
+ Close:
+       platform_end(platform_mode);
+       return error;
+}
+
+/**
+ *     resume_target_kernel - prepare devices that need to be suspended with
+ *     interrupts off, restore the contents of highmem that have not been
+ *     restored yet from the image and run the low level code that will restore
+ *     the remaining contents of memory and switch to the just restored target
+ *     kernel.
+ */
+
+static int resume_target_kernel(void)
+{
+       int error;
+
+       local_irq_disable();
+       error = device_power_down(PMSG_PRETHAW);
+       if (error) {
+               printk(KERN_ERR "PM: Some devices failed to power down, "
+                       "aborting resume\n");
+               goto Enable_irqs;
+       }
+       /* We'll ignore saved state, but this gets preempt count (etc) right */
+       save_processor_state();
+       error = restore_highmem();
+       if (!error) {
+               error = swsusp_arch_resume();
+               /*
+                * The code below is only ever reached in case of a failure.
+                * Otherwise execution continues at place where
+                * swsusp_arch_suspend() was called
+                */
+               BUG_ON(!error);
+               /* This call to restore_highmem() undos the previous one */
+               restore_highmem();
+       }
+       /*
+        * The only reason why swsusp_arch_resume() can fail is memory being
+        * very tight, so we have to free it as soon as we can to avoid
+        * subsequent failures
+        */
+       swsusp_free();
+       restore_processor_state();
+       touch_softlockup_watchdog();
+       device_power_up();
+ Enable_irqs:
+       local_irq_enable();
        return error;
 }
 
@@ -258,7 +358,7 @@ int hibernation_restore(int platform_mode)
        if (!error) {
                error = disable_nonboot_cpus();
                if (!error)
-                       error = swsusp_resume();
+                       error = resume_target_kernel();
                enable_nonboot_cpus();
        }
        platform_restore_cleanup(platform_mode);
@@ -286,9 +386,9 @@ int hibernation_platform_enter(void)
         * hibernation_ops->finish() before saving the image, so we should let
         * the firmware know that we're going to enter the sleep state after all
         */
-       error = hibernation_ops->start();
+       error = hibernation_ops->begin();
        if (error)
-               return error;
+               goto Close;
 
        suspend_console();
        error = device_suspend(PMSG_SUSPEND);
@@ -322,6 +422,8 @@ int hibernation_platform_enter(void)
        device_resume();
  Resume_console:
        resume_console();
+ Close:
+       hibernation_ops->end();
        return error;
 }
 
@@ -352,24 +454,17 @@ static void power_down(void)
         * Valid image is on the disk, if we continue we risk serious data
         * corruption after resume.
         */
-       printk(KERN_CRIT "Please power me down manually\n");
+       printk(KERN_CRIT "PM: Please power down manually\n");
        while(1);
 }
 
-static void unprepare_processes(void)
-{
-       thaw_processes();
-       pm_restore_console();
-}
-
 static int prepare_processes(void)
 {
        int error = 0;
 
-       pm_prepare_console();
        if (freeze_processes()) {
                error = -EBUSY;
-               unprepare_processes();
+               thaw_processes();
        }
        return error;
 }
@@ -389,6 +484,7 @@ int hibernate(void)
                goto Unlock;
        }
 
+       pm_prepare_console();
        error = pm_notifier_call_chain(PM_HIBERNATION_PREPARE);
        if (error)
                goto Exit;
@@ -398,7 +494,7 @@ int hibernate(void)
        if (error)
                goto Exit;
 
-       printk("Syncing filesystems ... ");
+       printk(KERN_INFO "PM: Syncing filesystems ... ");
        sys_sync();
        printk("done.\n");
 
@@ -406,11 +502,12 @@ int hibernate(void)
        if (error)
                goto Finish;
 
-       if (hibernation_mode == HIBERNATION_TESTPROC) {
-               printk("swsusp debug: Waiting for 5 seconds.\n");
-               mdelay(5000);
+       if (hibernation_test(TEST_FREEZER))
                goto Thaw;
-       }
+
+       if (hibernation_testmode(HIBERNATION_TESTPROC))
+               goto Thaw;
+
        error = hibernation_snapshot(hibernation_mode == HIBERNATION_PLATFORM);
        if (in_suspend && !error) {
                unsigned int flags = 0;
@@ -427,11 +524,12 @@ int hibernate(void)
                swsusp_free();
        }
  Thaw:
-       unprepare_processes();
+       thaw_processes();
  Finish:
        free_basic_memory_bitmaps();
  Exit:
        pm_notifier_call_chain(PM_POST_HIBERNATION);
+       pm_restore_console();
        atomic_inc(&snapshot_device_available);
  Unlock:
        mutex_unlock(&pm_mutex);
@@ -473,22 +571,23 @@ static int software_resume(void)
                        return -ENOENT;
                }
                swsusp_resume_device = name_to_dev_t(resume_file);
-               pr_debug("swsusp: Resume From Partition %s\n", resume_file);
+               pr_debug("PM: Resume from partition %s\n", resume_file);
        } else {
-               pr_debug("swsusp: Resume From Partition %d:%d\n",
-                        MAJOR(swsusp_resume_device), MINOR(swsusp_resume_device));
+               pr_debug("PM: Resume from partition %d:%d\n",
+                               MAJOR(swsusp_resume_device),
+                               MINOR(swsusp_resume_device));
        }
 
        if (noresume) {
                /**
-                * FIXME: If noresume is specified, we need to find the partition
-                * and reset it back to normal swap space.
+                * FIXME: If noresume is specified, we need to find the
+                * partition and reset it back to normal swap space.
                 */
                mutex_unlock(&pm_mutex);
                return 0;
        }
 
-       pr_debug("PM: Checking swsusp image.\n");
+       pr_debug("PM: Checking hibernation image.\n");
        error = swsusp_check();
        if (error)
                goto Unlock;
@@ -499,6 +598,11 @@ static int software_resume(void)
                goto Unlock;
        }
 
+       pm_prepare_console();
+       error = pm_notifier_call_chain(PM_RESTORE_PREPARE);
+       if (error)
+               goto Finish;
+
        error = create_basic_memory_bitmaps();
        if (error)
                goto Finish;
@@ -510,7 +614,7 @@ static int software_resume(void)
                goto Done;
        }
 
-       pr_debug("PM: Reading swsusp image.\n");
+       pr_debug("PM: Reading hibernation image.\n");
 
        error = swsusp_read(&flags);
        if (!error)
@@ -518,10 +622,12 @@ static int software_resume(void)
 
        printk(KERN_ERR "PM: Restore failed, recovering.\n");
        swsusp_free();
-       unprepare_processes();
+       thaw_processes();
  Done:
        free_basic_memory_bitmaps();
  Finish:
+       pm_notifier_call_chain(PM_POST_RESTORE);
+       pm_restore_console();
        atomic_inc(&snapshot_device_available);
        /* For success case, the suspend path will release the lock */
  Unlock:
@@ -636,7 +742,7 @@ static ssize_t disk_store(struct kobject *kobj, struct kobj_attribute *attr,
                error = -EINVAL;
 
        if (!error)
-               pr_debug("PM: suspend-to-disk mode set to '%s'\n",
+               pr_debug("PM: Hibernation mode set to '%s'\n",
                         hibernation_modes[mode]);
        mutex_unlock(&pm_mutex);
        return error ? error : n;
@@ -668,7 +774,7 @@ static ssize_t resume_store(struct kobject *kobj, struct kobj_attribute *attr,
        mutex_lock(&pm_mutex);
        swsusp_resume_device = res;
        mutex_unlock(&pm_mutex);
-       printk("Attempting manual resume\n");
+       printk(KERN_INFO "PM: Starting manual resume from disk\n");
        noresume = 0;
        software_resume();
        ret = n;
index efc08360e627199374837ed95ea31ebcd0f94a80..6a6d5eb3524e7d2f219aeaa894e70981b3a706fb 100644 (file)
 
 #include "power.h"
 
-BLOCKING_NOTIFIER_HEAD(pm_chain_head);
-
 DEFINE_MUTEX(pm_mutex);
 
 unsigned int pm_flags;
 EXPORT_SYMBOL(pm_flags);
 
+#ifdef CONFIG_PM_SLEEP
+
+/* Routines for PM-transition notifications */
+
+static BLOCKING_NOTIFIER_HEAD(pm_chain_head);
+
+int register_pm_notifier(struct notifier_block *nb)
+{
+       return blocking_notifier_chain_register(&pm_chain_head, nb);
+}
+EXPORT_SYMBOL_GPL(register_pm_notifier);
+
+int unregister_pm_notifier(struct notifier_block *nb)
+{
+       return blocking_notifier_chain_unregister(&pm_chain_head, nb);
+}
+EXPORT_SYMBOL_GPL(unregister_pm_notifier);
+
+int pm_notifier_call_chain(unsigned long val)
+{
+       return (blocking_notifier_call_chain(&pm_chain_head, val, NULL)
+                       == NOTIFY_BAD) ? -EINVAL : 0;
+}
+
+#ifdef CONFIG_PM_DEBUG
+int pm_test_level = TEST_NONE;
+
+static int suspend_test(int level)
+{
+       if (pm_test_level == level) {
+               printk(KERN_INFO "suspend debug: Waiting for 5 seconds.\n");
+               mdelay(5000);
+               return 1;
+       }
+       return 0;
+}
+
+static const char * const pm_tests[__TEST_AFTER_LAST] = {
+       [TEST_NONE] = "none",
+       [TEST_CORE] = "core",
+       [TEST_CPUS] = "processors",
+       [TEST_PLATFORM] = "platform",
+       [TEST_DEVICES] = "devices",
+       [TEST_FREEZER] = "freezer",
+};
+
+static ssize_t pm_test_show(struct kobject *kobj, struct kobj_attribute *attr,
+                               char *buf)
+{
+       char *s = buf;
+       int level;
+
+       for (level = TEST_FIRST; level <= TEST_MAX; level++)
+               if (pm_tests[level]) {
+                       if (level == pm_test_level)
+                               s += sprintf(s, "[%s] ", pm_tests[level]);
+                       else
+                               s += sprintf(s, "%s ", pm_tests[level]);
+               }
+
+       if (s != buf)
+               /* convert the last space to a newline */
+               *(s-1) = '\n';
+
+       return (s - buf);
+}
+
+static ssize_t pm_test_store(struct kobject *kobj, struct kobj_attribute *attr,
+                               const char *buf, size_t n)
+{
+       const char * const *s;
+       int level;
+       char *p;
+       int len;
+       int error = -EINVAL;
+
+       p = memchr(buf, '\n', n);
+       len = p ? p - buf : n;
+
+       mutex_lock(&pm_mutex);
+
+       level = TEST_FIRST;
+       for (s = &pm_tests[level]; level <= TEST_MAX; s++, level++)
+               if (*s && len == strlen(*s) && !strncmp(buf, *s, len)) {
+                       pm_test_level = level;
+                       error = 0;
+                       break;
+               }
+
+       mutex_unlock(&pm_mutex);
+
+       return error ? error : n;
+}
+
+power_attr(pm_test);
+#else /* !CONFIG_PM_DEBUG */
+static inline int suspend_test(int level) { return 0; }
+#endif /* !CONFIG_PM_DEBUG */
+
+#endif /* CONFIG_PM_SLEEP */
+
 #ifdef CONFIG_SUSPEND
 
 /* This is just an arbitrary number */
@@ -76,13 +175,13 @@ static int suspend_prepare(void)
        if (!suspend_ops || !suspend_ops->enter)
                return -EPERM;
 
+       pm_prepare_console();
+
        error = pm_notifier_call_chain(PM_SUSPEND_PREPARE);
        if (error)
                goto Finish;
 
-       pm_prepare_console();
-
-       if (freeze_processes()) {
+       if (suspend_freeze_processes()) {
                error = -EAGAIN;
                goto Thaw;
        }
@@ -100,10 +199,10 @@ static int suspend_prepare(void)
                return 0;
 
  Thaw:
-       thaw_processes();
-       pm_restore_console();
+       suspend_thaw_processes();
  Finish:
        pm_notifier_call_chain(PM_POST_SUSPEND);
+       pm_restore_console();
        return error;
 }
 
@@ -133,10 +232,13 @@ static int suspend_enter(suspend_state_t state)
        BUG_ON(!irqs_disabled());
 
        if ((error = device_power_down(PMSG_SUSPEND))) {
-               printk(KERN_ERR "Some devices failed to power down\n");
+               printk(KERN_ERR "PM: Some devices failed to power down\n");
                goto Done;
        }
-       error = suspend_ops->enter(state);
+
+       if (!suspend_test(TEST_CORE))
+               error = suspend_ops->enter(state);
+
        device_power_up();
  Done:
        arch_suspend_enable_irqs();
@@ -145,8 +247,8 @@ static int suspend_enter(suspend_state_t state)
 }
 
 /**
- *     suspend_devices_and_enter - suspend devices and enter the desired system sleep
- *                       state.
+ *     suspend_devices_and_enter - suspend devices and enter the desired system
+ *                                 sleep state.
  *     @state:           state to enter
  */
 int suspend_devices_and_enter(suspend_state_t state)
@@ -156,33 +258,45 @@ int suspend_devices_and_enter(suspend_state_t state)
        if (!suspend_ops)
                return -ENOSYS;
 
-       if (suspend_ops->set_target) {
-               error = suspend_ops->set_target(state);
+       if (suspend_ops->begin) {
+               error = suspend_ops->begin(state);
                if (error)
-                       return error;
+                       goto Close;
        }
        suspend_console();
        error = device_suspend(PMSG_SUSPEND);
        if (error) {
-               printk(KERN_ERR "Some devices failed to suspend\n");
+               printk(KERN_ERR "PM: Some devices failed to suspend\n");
                goto Resume_console;
        }
+
+       if (suspend_test(TEST_DEVICES))
+               goto Resume_devices;
+
        if (suspend_ops->prepare) {
                error = suspend_ops->prepare();
                if (error)
                        goto Resume_devices;
        }
+
+       if (suspend_test(TEST_PLATFORM))
+               goto Finish;
+
        error = disable_nonboot_cpus();
-       if (!error)
+       if (!error && !suspend_test(TEST_CPUS))
                suspend_enter(state);
 
        enable_nonboot_cpus();
+ Finish:
        if (suspend_ops->finish)
                suspend_ops->finish();
  Resume_devices:
        device_resume();
  Resume_console:
        resume_console();
+ Close:
+       if (suspend_ops->end)
+               suspend_ops->end();
        return error;
 }
 
@@ -194,9 +308,9 @@ int suspend_devices_and_enter(suspend_state_t state)
  */
 static void suspend_finish(void)
 {
-       thaw_processes();
-       pm_restore_console();
+       suspend_thaw_processes();
        pm_notifier_call_chain(PM_POST_SUSPEND);
+       pm_restore_console();
 }
 
 
@@ -238,17 +352,22 @@ static int enter_state(suspend_state_t state)
        if (!mutex_trylock(&pm_mutex))
                return -EBUSY;
 
-       printk("Syncing filesystems ... ");
+       printk(KERN_INFO "PM: Syncing filesystems ... ");
        sys_sync();
        printk("done.\n");
 
        pr_debug("PM: Preparing system for %s sleep\n", pm_states[state]);
-       if ((error = suspend_prepare()))
+       error = suspend_prepare();
+       if (error)
                goto Unlock;
 
+       if (suspend_test(TEST_FREEZER))
+               goto Finish;
+
        pr_debug("PM: Entering %s sleep\n", pm_states[state]);
        error = suspend_devices_and_enter(state);
 
+ Finish:
        pr_debug("PM: Finishing wakeup.\n");
        suspend_finish();
  Unlock:
@@ -369,18 +488,18 @@ pm_trace_store(struct kobject *kobj, struct kobj_attribute *attr,
 }
 
 power_attr(pm_trace);
+#endif /* CONFIG_PM_TRACE */
 
 static struct attribute * g[] = {
        &state_attr.attr,
+#ifdef CONFIG_PM_TRACE
        &pm_trace_attr.attr,
+#endif
+#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_PM_DEBUG)
+       &pm_test_attr.attr,
+#endif
        NULL,
 };
-#else
-static struct attribute * g[] = {
-       &state_attr.attr,
-       NULL,
-};
-#endif /* CONFIG_PM_TRACE */
 
 static struct attribute_group attr_group = {
        .attrs = g,
index 2093c3a9a994d8a7a3bd82487200b925ee16ac61..700f44ec84067860cb86a79ff8201934c3c59e66 100644 (file)
@@ -1,5 +1,7 @@
 #include <linux/suspend.h>
+#include <linux/suspend_ioctls.h>
 #include <linux/utsname.h>
+#include <linux/freezer.h>
 
 struct swsusp_info {
        struct new_utsname      uts;
@@ -128,42 +130,12 @@ struct snapshot_handle {
 #define data_of(handle)        ((handle).buffer + (handle).buf_offset)
 
 extern unsigned int snapshot_additional_pages(struct zone *zone);
+extern unsigned long snapshot_get_image_size(void);
 extern int snapshot_read_next(struct snapshot_handle *handle, size_t count);
 extern int snapshot_write_next(struct snapshot_handle *handle, size_t count);
 extern void snapshot_write_finalize(struct snapshot_handle *handle);
 extern int snapshot_image_loaded(struct snapshot_handle *handle);
 
-/*
- * This structure is used to pass the values needed for the identification
- * of the resume swap area from a user space to the kernel via the
- * SNAPSHOT_SET_SWAP_AREA ioctl
- */
-struct resume_swap_area {
-       loff_t offset;
-       u_int32_t dev;
-} __attribute__((packed));
-
-#define SNAPSHOT_IOC_MAGIC     '3'
-#define SNAPSHOT_FREEZE                        _IO(SNAPSHOT_IOC_MAGIC, 1)
-#define SNAPSHOT_UNFREEZE              _IO(SNAPSHOT_IOC_MAGIC, 2)
-#define SNAPSHOT_ATOMIC_SNAPSHOT       _IOW(SNAPSHOT_IOC_MAGIC, 3, void *)
-#define SNAPSHOT_ATOMIC_RESTORE                _IO(SNAPSHOT_IOC_MAGIC, 4)
-#define SNAPSHOT_FREE                  _IO(SNAPSHOT_IOC_MAGIC, 5)
-#define SNAPSHOT_SET_IMAGE_SIZE                _IOW(SNAPSHOT_IOC_MAGIC, 6, unsigned long)
-#define SNAPSHOT_AVAIL_SWAP            _IOR(SNAPSHOT_IOC_MAGIC, 7, void *)
-#define SNAPSHOT_GET_SWAP_PAGE         _IOR(SNAPSHOT_IOC_MAGIC, 8, void *)
-#define SNAPSHOT_FREE_SWAP_PAGES       _IO(SNAPSHOT_IOC_MAGIC, 9)
-#define SNAPSHOT_SET_SWAP_FILE         _IOW(SNAPSHOT_IOC_MAGIC, 10, unsigned int)
-#define SNAPSHOT_S2RAM                 _IO(SNAPSHOT_IOC_MAGIC, 11)
-#define SNAPSHOT_PMOPS                 _IOW(SNAPSHOT_IOC_MAGIC, 12, unsigned int)
-#define SNAPSHOT_SET_SWAP_AREA         _IOW(SNAPSHOT_IOC_MAGIC, 13, \
-                                                       struct resume_swap_area)
-#define SNAPSHOT_IOC_MAXNR     13
-
-#define PMOPS_PREPARE  1
-#define PMOPS_ENTER    2
-#define PMOPS_FINISH   3
-
 /* If unset, the snapshot device cannot be open. */
 extern atomic_t snapshot_device_available;
 
@@ -181,7 +153,6 @@ extern int swsusp_swap_in_use(void);
 extern int swsusp_check(void);
 extern int swsusp_shrink_memory(void);
 extern void swsusp_free(void);
-extern int swsusp_resume(void);
 extern int swsusp_read(unsigned int *flags_p);
 extern int swsusp_write(unsigned int flags);
 extern void swsusp_close(void);
@@ -201,11 +172,56 @@ static inline int suspend_devices_and_enter(suspend_state_t state)
 }
 #endif /* !CONFIG_SUSPEND */
 
-/* kernel/power/common.c */
-extern struct blocking_notifier_head pm_chain_head;
+#ifdef CONFIG_PM_SLEEP
+/* kernel/power/main.c */
+extern int pm_notifier_call_chain(unsigned long val);
+#endif
+
+#ifdef CONFIG_HIGHMEM
+unsigned int count_highmem_pages(void);
+int restore_highmem(void);
+#else
+static inline unsigned int count_highmem_pages(void) { return 0; }
+static inline int restore_highmem(void) { return 0; }
+#endif
+
+/*
+ * Suspend test levels
+ */
+enum {
+       /* keep first */
+       TEST_NONE,
+       TEST_CORE,
+       TEST_CPUS,
+       TEST_PLATFORM,
+       TEST_DEVICES,
+       TEST_FREEZER,
+       /* keep last */
+       __TEST_AFTER_LAST
+};
+
+#define TEST_FIRST     TEST_NONE
+#define TEST_MAX       (__TEST_AFTER_LAST - 1)
+
+extern int pm_test_level;
+
+#ifdef CONFIG_SUSPEND_FREEZER
+static inline int suspend_freeze_processes(void)
+{
+       return freeze_processes();
+}
 
-static inline int pm_notifier_call_chain(unsigned long val)
+static inline void suspend_thaw_processes(void)
 {
-       return (blocking_notifier_call_chain(&pm_chain_head, val, NULL)
-                       == NOTIFY_BAD) ? -EINVAL : 0;
+       thaw_processes();
 }
+#else
+static inline int suspend_freeze_processes(void)
+{
+       return 0;
+}
+
+static inline void suspend_thaw_processes(void)
+{
+}
+#endif
index 6533923e711b5dd8be01efd5f1e9576250ebf42f..7c2118f9597f3139cfef277233a739d5d717b159 100644 (file)
@@ -86,9 +86,9 @@ static void fake_signal_wake_up(struct task_struct *p, int resume)
 
 static void send_fake_signal(struct task_struct *p)
 {
-       if (p->state == TASK_STOPPED)
+       if (task_is_stopped(p))
                force_sig_specific(SIGSTOP, p);
-       fake_signal_wake_up(p, p->state == TASK_STOPPED);
+       fake_signal_wake_up(p, task_is_stopped(p));
 }
 
 static int has_mm(struct task_struct *p)
@@ -182,7 +182,7 @@ static int try_to_freeze_tasks(int freeze_user_space)
                        if (frozen(p) || !freezeable(p))
                                continue;
 
-                       if (p->state == TASK_TRACED && frozen(p->parent)) {
+                       if (task_is_traced(p) && frozen(p->parent)) {
                                cancel_freezing(p);
                                continue;
                        }
index 78039b477d2bd7bbae3ab893763111475ea932a6..95250d7c8d91db36593fc3707b10c99a8370dc62 100644 (file)
@@ -635,7 +635,7 @@ __register_nosave_region(unsigned long start_pfn, unsigned long end_pfn,
        region->end_pfn = end_pfn;
        list_add_tail(&region->list, &nosave_regions);
  Report:
-       printk("swsusp: Registered nosave memory region: %016lx - %016lx\n",
+       printk(KERN_INFO "PM: Registered nosave memory: %016lx - %016lx\n",
                start_pfn << PAGE_SHIFT, end_pfn << PAGE_SHIFT);
 }
 
@@ -704,7 +704,7 @@ static void mark_nosave_pages(struct memory_bitmap *bm)
        list_for_each_entry(region, &nosave_regions, list) {
                unsigned long pfn;
 
-               printk("swsusp: Marking nosave pages: %016lx - %016lx\n",
+               pr_debug("PM: Marking nosave pages: %016lx - %016lx\n",
                                region->start_pfn << PAGE_SHIFT,
                                region->end_pfn << PAGE_SHIFT);
 
@@ -749,7 +749,7 @@ int create_basic_memory_bitmaps(void)
        free_pages_map = bm2;
        mark_nosave_pages(forbidden_pages_map);
 
-       printk("swsusp: Basic memory bitmaps created\n");
+       pr_debug("PM: Basic memory bitmaps created\n");
 
        return 0;
 
@@ -784,7 +784,7 @@ void free_basic_memory_bitmaps(void)
        memory_bm_free(bm2, PG_UNSAFE_CLEAR);
        kfree(bm2);
 
-       printk("swsusp: Basic memory bitmaps freed\n");
+       pr_debug("PM: Basic memory bitmaps freed\n");
 }
 
 /**
@@ -872,7 +872,6 @@ unsigned int count_highmem_pages(void)
 }
 #else
 static inline void *saveable_highmem_page(unsigned long pfn) { return NULL; }
-static inline unsigned int count_highmem_pages(void) { return 0; }
 #endif /* CONFIG_HIGHMEM */
 
 /**
@@ -1089,7 +1088,7 @@ static int enough_free_mem(unsigned int nr_pages, unsigned int nr_highmem)
        }
 
        nr_pages += count_pages_for_highmem(nr_highmem);
-       pr_debug("swsusp: Normal pages needed: %u + %u + %u, available pages: %u\n",
+       pr_debug("PM: Normal pages needed: %u + %u + %u, available pages: %u\n",
                nr_pages, PAGES_FOR_IO, meta, free);
 
        return free > nr_pages + PAGES_FOR_IO + meta;
@@ -1202,27 +1201,27 @@ asmlinkage int swsusp_save(void)
 {
        unsigned int nr_pages, nr_highmem;
 
-       printk("swsusp: critical section: \n");
+       printk(KERN_INFO "PM: Creating hibernation image: \n");
 
-       drain_local_pages();
+       drain_local_pages(NULL);
        nr_pages = count_data_pages();
        nr_highmem = count_highmem_pages();
-       printk("swsusp: Need to copy %u pages\n", nr_pages + nr_highmem);
+       printk(KERN_INFO "PM: Need to copy %u pages\n", nr_pages + nr_highmem);
 
        if (!enough_free_mem(nr_pages, nr_highmem)) {
-               printk(KERN_ERR "swsusp: Not enough free memory\n");
+               printk(KERN_ERR "PM: Not enough free memory\n");
                return -ENOMEM;
        }
 
        if (swsusp_alloc(&orig_bm, &copy_bm, nr_pages, nr_highmem)) {
-               printk(KERN_ERR "swsusp: Memory allocation failed\n");
+               printk(KERN_ERR "PM: Memory allocation failed\n");
                return -ENOMEM;
        }
 
        /* During allocating of suspend pagedir, new cold pages may appear.
         * Kill them.
         */
-       drain_local_pages();
+       drain_local_pages(NULL);
        copy_data_pages(&copy_bm, &orig_bm);
 
        /*
@@ -1235,7 +1234,8 @@ asmlinkage int swsusp_save(void)
        nr_copy_pages = nr_pages;
        nr_meta_pages = DIV_ROUND_UP(nr_pages * sizeof(long), PAGE_SIZE);
 
-       printk("swsusp: critical section: done (%d pages copied)\n", nr_pages);
+       printk(KERN_INFO "PM: Hibernation image created (%d pages copied)\n",
+               nr_pages);
 
        return 0;
 }
@@ -1264,12 +1264,17 @@ static char *check_image_kernel(struct swsusp_info *info)
 }
 #endif /* CONFIG_ARCH_HIBERNATION_HEADER */
 
+unsigned long snapshot_get_image_size(void)
+{
+       return nr_copy_pages + nr_meta_pages + 1;
+}
+
 static int init_header(struct swsusp_info *info)
 {
        memset(info, 0, sizeof(struct swsusp_info));
        info->num_physpages = num_physpages;
        info->image_pages = nr_copy_pages;
-       info->pages = nr_copy_pages + nr_meta_pages + 1;
+       info->pages = snapshot_get_image_size();
        info->size = info->pages;
        info->size <<= PAGE_SHIFT;
        return init_header_complete(info);
@@ -1429,7 +1434,7 @@ static int check_header(struct swsusp_info *info)
        if (!reason && info->num_physpages != num_physpages)
                reason = "memory size";
        if (reason) {
-               printk(KERN_ERR "swsusp: Resume mismatch: %s\n", reason);
+               printk(KERN_ERR "PM: Image mismatch: %s\n", reason);
                return -EPERM;
        }
        return 0;
index 917aba100575a45125ee3d98a1cee93553d22d58..a0abf9a463f95bc9948f3ccd10fecddf75401eb8 100644 (file)
@@ -28,8 +28,6 @@
 
 #include "power.h"
 
-extern char resume_file[];
-
 #define SWSUSP_SIG     "S1SUSPEND"
 
 struct swsusp_header {
@@ -73,7 +71,8 @@ static int submit(int rw, pgoff_t page_off, struct page *page,
        bio->bi_end_io = end_swap_bio_read;
 
        if (bio_add_page(bio, page, PAGE_SIZE, 0) < PAGE_SIZE) {
-               printk("swsusp: ERROR: adding page to bio at %ld\n", page_off);
+               printk(KERN_ERR "PM: Adding page to bio failed at %ld\n",
+                       page_off);
                bio_put(bio);
                return -EFAULT;
        }
@@ -153,7 +152,7 @@ static int mark_swapfiles(sector_t start, unsigned int flags)
                error = bio_write_page(swsusp_resume_block,
                                        swsusp_header, NULL);
        } else {
-               printk(KERN_ERR "swsusp: Swap header not found!\n");
+               printk(KERN_ERR "PM: Swap header not found!\n");
                error = -ENODEV;
        }
        return error;
@@ -325,7 +324,8 @@ static int save_image(struct swap_map_handle *handle,
        struct timeval start;
        struct timeval stop;
 
-       printk("Saving image data pages (%u pages) ...     ", nr_to_write);
+       printk(KERN_INFO "PM: Saving image data pages (%u pages) ...     ",
+               nr_to_write);
        m = nr_to_write / 100;
        if (!m)
                m = 1;
@@ -365,7 +365,7 @@ static int enough_swap(unsigned int nr_pages)
 {
        unsigned int free_swap = count_swap_pages(root_swap, 1);
 
-       pr_debug("swsusp: free swap pages: %u\n", free_swap);
+       pr_debug("PM: Free swap pages: %u\n", free_swap);
        return free_swap > nr_pages + PAGES_FOR_IO;
 }
 
@@ -388,7 +388,7 @@ int swsusp_write(unsigned int flags)
 
        error = swsusp_swap_check();
        if (error) {
-               printk(KERN_ERR "swsusp: Cannot find swap device, try "
+               printk(KERN_ERR "PM: Cannot find swap device, try "
                                "swapon -a.\n");
                return error;
        }
@@ -402,7 +402,7 @@ int swsusp_write(unsigned int flags)
        }
        header = (struct swsusp_info *)data_of(snapshot);
        if (!enough_swap(header->pages)) {
-               printk(KERN_ERR "swsusp: Not enough free swap\n");
+               printk(KERN_ERR "PM: Not enough free swap\n");
                error = -ENOSPC;
                goto out;
        }
@@ -417,7 +417,7 @@ int swsusp_write(unsigned int flags)
 
                if (!error) {
                        flush_swap_writer(&handle);
-                       printk("S");
+                       printk(KERN_INFO "PM: S");
                        error = mark_swapfiles(start, flags);
                        printk("|\n");
                }
@@ -507,7 +507,8 @@ static int load_image(struct swap_map_handle *handle,
        int err2;
        unsigned nr_pages;
 
-       printk("Loading image data pages (%u pages) ...     ", nr_to_read);
+       printk(KERN_INFO "PM: Loading image data pages (%u pages) ...     ",
+               nr_to_read);
        m = nr_to_read / 100;
        if (!m)
                m = 1;
@@ -558,7 +559,7 @@ int swsusp_read(unsigned int *flags_p)
 
        *flags_p = swsusp_header->flags;
        if (IS_ERR(resume_bdev)) {
-               pr_debug("swsusp: block device not initialised\n");
+               pr_debug("PM: Image device not initialised\n");
                return PTR_ERR(resume_bdev);
        }
 
@@ -577,9 +578,9 @@ int swsusp_read(unsigned int *flags_p)
        blkdev_put(resume_bdev);
 
        if (!error)
-               pr_debug("swsusp: Reading resume file was successful\n");
+               pr_debug("PM: Image successfully loaded\n");
        else
-               pr_debug("swsusp: Error %d resuming\n", error);
+               pr_debug("PM: Error %d resuming\n", error);
        return error;
 }
 
@@ -611,13 +612,13 @@ int swsusp_check(void)
                if (error)
                        blkdev_put(resume_bdev);
                else
-                       pr_debug("swsusp: Signature found, resuming\n");
+                       pr_debug("PM: Signature found, resuming\n");
        } else {
                error = PTR_ERR(resume_bdev);
        }
 
        if (error)
-               pr_debug("swsusp: Error %d check for resume file\n", error);
+               pr_debug("PM: Error %d checking image file\n", error);
 
        return error;
 }
@@ -629,7 +630,7 @@ int swsusp_check(void)
 void swsusp_close(void)
 {
        if (IS_ERR(resume_bdev)) {
-               pr_debug("swsusp: block device not initialised\n");
+               pr_debug("PM: Image device not initialised\n");
                return;
        }
 
index e1722d3155f17057284ab6374b3a00b9a31ed1d2..023ff2a31d899159e61ffb72e9e4eeea65d93b25 100644 (file)
@@ -64,14 +64,6 @@ unsigned long image_size = 500 * 1024 * 1024;
 
 int in_suspend __nosavedata = 0;
 
-#ifdef CONFIG_HIGHMEM
-unsigned int count_highmem_pages(void);
-int restore_highmem(void);
-#else
-static inline int restore_highmem(void) { return 0; }
-static inline unsigned int count_highmem_pages(void) { return 0; }
-#endif
-
 /**
  *     The following functions are used for tracing the allocated
  *     swap pages, so that they can be freed in case of an error.
@@ -196,7 +188,8 @@ void swsusp_show_speed(struct timeval *start, struct timeval *stop,
                centisecs = 1;  /* avoid div-by-zero */
        k = nr_pages * (PAGE_SIZE / 1024);
        kps = (k * 100) / centisecs;
-       printk("%s %d kbytes in %d.%02d seconds (%d.%02d MB/s)\n", msg, k,
+       printk(KERN_INFO "PM: %s %d kbytes in %d.%02d seconds (%d.%02d MB/s)\n",
+                       msg, k,
                        centisecs / 100, centisecs % 100,
                        kps / 1000, (kps % 1000) / 10);
 }
@@ -227,7 +220,7 @@ int swsusp_shrink_memory(void)
        char *p = "-\\|/";
        struct timeval start, stop;
 
-       printk("Shrinking memory...  ");
+       printk(KERN_INFO "PM: Shrinking memory...  ");
        do_gettimeofday(&start);
        do {
                long size, highmem_size;
@@ -269,38 +262,3 @@ int swsusp_shrink_memory(void)
 
        return 0;
 }
-
-int swsusp_resume(void)
-{
-       int error;
-
-       local_irq_disable();
-       /* NOTE:  device_power_down() is just a suspend() with irqs off;
-        * it has no special "power things down" semantics
-        */
-       if (device_power_down(PMSG_PRETHAW))
-               printk(KERN_ERR "Some devices failed to power down, very bad\n");
-       /* We'll ignore saved state, but this gets preempt count (etc) right */
-       save_processor_state();
-       error = restore_highmem();
-       if (!error) {
-               error = swsusp_arch_resume();
-               /* The code below is only ever reached in case of a failure.
-                * Otherwise execution continues at place where
-                * swsusp_arch_suspend() was called
-                */
-               BUG_ON(!error);
-               /* This call to restore_highmem() undos the previous one */
-               restore_highmem();
-       }
-       /* The only reason why swsusp_arch_resume() can fail is memory being
-        * very tight, so we have to free it as soon as we can to avoid
-        * subsequent failures
-        */
-       swsusp_free();
-       restore_processor_state();
-       touch_softlockup_watchdog();
-       device_power_up();
-       local_irq_enable();
-       return error;
-}
index 5bd321bcbb75f06031d6ede749cad599c251373c..f5512cb3aa86f61e98caec04c82a01a0dc9f6dcf 100644 (file)
 
 #include "power.h"
 
+/*
+ * NOTE: The SNAPSHOT_SET_SWAP_FILE and SNAPSHOT_PMOPS ioctls are obsolete and
+ * will be removed in the future.  They are only preserved here for
+ * compatibility with existing userland utilities.
+ */
+#define SNAPSHOT_SET_SWAP_FILE _IOW(SNAPSHOT_IOC_MAGIC, 10, unsigned int)
+#define SNAPSHOT_PMOPS         _IOW(SNAPSHOT_IOC_MAGIC, 12, unsigned int)
+
+#define PMOPS_PREPARE  1
+#define PMOPS_ENTER    2
+#define PMOPS_FINISH   3
+
+/*
+ * NOTE: The following ioctl definitions are wrong and have been replaced with
+ * correct ones.  They are only preserved here for compatibility with existing
+ * userland utilities and will be removed in the future.
+ */
+#define SNAPSHOT_ATOMIC_SNAPSHOT       _IOW(SNAPSHOT_IOC_MAGIC, 3, void *)
+#define SNAPSHOT_SET_IMAGE_SIZE                _IOW(SNAPSHOT_IOC_MAGIC, 6, unsigned long)
+#define SNAPSHOT_AVAIL_SWAP            _IOR(SNAPSHOT_IOC_MAGIC, 7, void *)
+#define SNAPSHOT_GET_SWAP_PAGE         _IOR(SNAPSHOT_IOC_MAGIC, 8, void *)
+
+
 #define SNAPSHOT_MINOR 231
 
 static struct snapshot_data {
@@ -36,7 +59,7 @@ static struct snapshot_data {
        int mode;
        char frozen;
        char ready;
-       char platform_suspend;
+       char platform_support;
 } snapshot_state;
 
 atomic_t snapshot_device_available = ATOMIC_INIT(1);
@@ -44,6 +67,7 @@ atomic_t snapshot_device_available = ATOMIC_INIT(1);
 static int snapshot_open(struct inode *inode, struct file *filp)
 {
        struct snapshot_data *data;
+       int error;
 
        if (!atomic_add_unless(&snapshot_device_available, -1, 0))
                return -EBUSY;
@@ -64,13 +88,23 @@ static int snapshot_open(struct inode *inode, struct file *filp)
                data->swap = swsusp_resume_device ?
                        swap_type_of(swsusp_resume_device, 0, NULL) : -1;
                data->mode = O_RDONLY;
+               error = pm_notifier_call_chain(PM_RESTORE_PREPARE);
+               if (error)
+                       pm_notifier_call_chain(PM_POST_RESTORE);
        } else {
                data->swap = -1;
                data->mode = O_WRONLY;
+               error = pm_notifier_call_chain(PM_HIBERNATION_PREPARE);
+               if (error)
+                       pm_notifier_call_chain(PM_POST_HIBERNATION);
+       }
+       if (error) {
+               atomic_inc(&snapshot_device_available);
+               return error;
        }
        data->frozen = 0;
        data->ready = 0;
-       data->platform_suspend = 0;
+       data->platform_support = 0;
 
        return 0;
 }
@@ -88,6 +122,8 @@ static int snapshot_release(struct inode *inode, struct file *filp)
                thaw_processes();
                mutex_unlock(&pm_mutex);
        }
+       pm_notifier_call_chain(data->mode == O_WRONLY ?
+                       PM_POST_HIBERNATION : PM_POST_RESTORE);
        atomic_inc(&snapshot_device_available);
        return 0;
 }
@@ -133,7 +169,7 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp,
 {
        int error = 0;
        struct snapshot_data *data;
-       loff_t avail;
+       loff_t size;
        sector_t offset;
 
        if (_IOC_TYPE(cmd) != SNAPSHOT_IOC_MAGIC)
@@ -151,18 +187,13 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp,
                if (data->frozen)
                        break;
                mutex_lock(&pm_mutex);
-               error = pm_notifier_call_chain(PM_HIBERNATION_PREPARE);
-               if (!error) {
-                       printk("Syncing filesystems ... ");
-                       sys_sync();
-                       printk("done.\n");
-
-                       error = freeze_processes();
-                       if (error)
-                               thaw_processes();
-               }
+               printk("Syncing filesystems ... ");
+               sys_sync();
+               printk("done.\n");
+
+               error = freeze_processes();
                if (error)
-                       pm_notifier_call_chain(PM_POST_HIBERNATION);
+                       thaw_processes();
                mutex_unlock(&pm_mutex);
                if (!error)
                        data->frozen = 1;
@@ -173,19 +204,19 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp,
                        break;
                mutex_lock(&pm_mutex);
                thaw_processes();
-               pm_notifier_call_chain(PM_POST_HIBERNATION);
                mutex_unlock(&pm_mutex);
                data->frozen = 0;
                break;
 
+       case SNAPSHOT_CREATE_IMAGE:
        case SNAPSHOT_ATOMIC_SNAPSHOT:
                if (data->mode != O_RDONLY || !data->frozen  || data->ready) {
                        error = -EPERM;
                        break;
                }
-               error = hibernation_snapshot(data->platform_suspend);
+               error = hibernation_snapshot(data->platform_support);
                if (!error)
-                       error = put_user(in_suspend, (unsigned int __user *)arg);
+                       error = put_user(in_suspend, (int __user *)arg);
                if (!error)
                        data->ready = 1;
                break;
@@ -197,7 +228,7 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp,
                        error = -EPERM;
                        break;
                }
-               error = hibernation_restore(data->platform_suspend);
+               error = hibernation_restore(data->platform_support);
                break;
 
        case SNAPSHOT_FREE:
@@ -206,16 +237,29 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp,
                data->ready = 0;
                break;
 
+       case SNAPSHOT_PREF_IMAGE_SIZE:
        case SNAPSHOT_SET_IMAGE_SIZE:
                image_size = arg;
                break;
 
+       case SNAPSHOT_GET_IMAGE_SIZE:
+               if (!data->ready) {
+                       error = -ENODATA;
+                       break;
+               }
+               size = snapshot_get_image_size();
+               size <<= PAGE_SHIFT;
+               error = put_user(size, (loff_t __user *)arg);
+               break;
+
+       case SNAPSHOT_AVAIL_SWAP_SIZE:
        case SNAPSHOT_AVAIL_SWAP:
-               avail = count_swap_pages(data->swap, 1);
-               avail <<= PAGE_SHIFT;
-               error = put_user(avail, (loff_t __user *)arg);
+               size = count_swap_pages(data->swap, 1);
+               size <<= PAGE_SHIFT;
+               error = put_user(size, (loff_t __user *)arg);
                break;
 
+       case SNAPSHOT_ALLOC_SWAP_PAGE:
        case SNAPSHOT_GET_SWAP_PAGE:
                if (data->swap < 0 || data->swap >= MAX_SWAPFILES) {
                        error = -ENODEV;
@@ -224,7 +268,7 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp,
                offset = alloc_swapdev_block(data->swap);
                if (offset) {
                        offset <<= PAGE_SHIFT;
-                       error = put_user(offset, (sector_t __user *)arg);
+                       error = put_user(offset, (loff_t __user *)arg);
                } else {
                        error = -ENOSPC;
                }
@@ -238,7 +282,7 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp,
                free_all_swap_pages(data->swap);
                break;
 
-       case SNAPSHOT_SET_SWAP_FILE:
+       case SNAPSHOT_SET_SWAP_FILE: /* This ioctl is deprecated */
                if (!swsusp_swap_in_use()) {
                        /*
                         * User space encodes device types as two-byte values,
@@ -275,26 +319,33 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp,
                mutex_unlock(&pm_mutex);
                break;
 
-       case SNAPSHOT_PMOPS:
+       case SNAPSHOT_PLATFORM_SUPPORT:
+               data->platform_support = !!arg;
+               break;
+
+       case SNAPSHOT_POWER_OFF:
+               if (data->platform_support)
+                       error = hibernation_platform_enter();
+               break;
+
+       case SNAPSHOT_PMOPS: /* This ioctl is deprecated */
                error = -EINVAL;
 
                switch (arg) {
 
                case PMOPS_PREPARE:
-                       data->platform_suspend = 1;
+                       data->platform_support = 1;
                        error = 0;
                        break;
 
                case PMOPS_ENTER:
-                       if (data->platform_suspend)
+                       if (data->platform_support)
                                error = hibernation_platform_enter();
-
                        break;
 
                case PMOPS_FINISH:
-                       if (data->platform_suspend)
+                       if (data->platform_support)
                                error = 0;
-
                        break;
 
                default:
index 58bbec6841193d977f0a928fef090aee5edafa9b..29ae1e99cde08b247aa106a2939496abf3b3c871 100644 (file)
@@ -455,10 +455,10 @@ static int __init ignore_loglevel_setup(char *str)
        ignore_loglevel = 1;
        printk(KERN_INFO "debug: ignoring loglevel setting.\n");
 
-       return 1;
+       return 0;
 }
 
-__setup("ignore_loglevel", ignore_loglevel_setup);
+early_param("ignore_loglevel", ignore_loglevel_setup);
 
 /*
  * Write out chars from start to end - 1 inclusive
index e6e9b8be4b053c5f0074bdeca6f1a4ac9517e8fb..b0d4ab4dfd3d27ee60e3a044f9e0bc3bba665d88 100644 (file)
@@ -51,7 +51,7 @@ void __ptrace_link(struct task_struct *child, struct task_struct *new_parent)
 void ptrace_untrace(struct task_struct *child)
 {
        spin_lock(&child->sighand->siglock);
-       if (child->state == TASK_TRACED) {
+       if (task_is_traced(child)) {
                if (child->signal->flags & SIGNAL_STOP_STOPPED) {
                        child->state = TASK_STOPPED;
                } else {
@@ -79,7 +79,7 @@ void __ptrace_unlink(struct task_struct *child)
                add_parent(child);
        }
 
-       if (child->state == TASK_TRACED)
+       if (task_is_traced(child))
                ptrace_untrace(child);
 }
 
@@ -103,9 +103,9 @@ int ptrace_check_attach(struct task_struct *child, int kill)
            && child->signal != NULL) {
                ret = 0;
                spin_lock_irq(&child->sighand->siglock);
-               if (child->state == TASK_STOPPED) {
+               if (task_is_stopped(child)) {
                        child->state = TASK_TRACED;
-               } else if (child->state != TASK_TRACED && !kill) {
+               } else if (!task_is_traced(child) && !kill) {
                        ret = -ESRCH;
                }
                spin_unlock_irq(&child->sighand->siglock);
index 61134eb7a0c8a9b2d2e0557b33ff4fbd7ff96f31..7c0373322f18892eea75e3773714554f59f46c1e 100644 (file)
@@ -92,6 +92,7 @@ static int relay_mmap_buf(struct rchan_buf *buf, struct vm_area_struct *vma)
                return -EINVAL;
 
        vma->vm_ops = &relay_file_mmap_ops;
+       vma->vm_flags |= VM_DONTEXPAND;
        vma->vm_private_data = buf;
        buf->chan->cb->buf_mapped(buf, filp);
 
index ba4c88088f62c53ab8ec414e3d77da65b1cd9f67..9474b23c28bf41f5989df3b94c5e810b0f1e971a 100644 (file)
@@ -1255,12 +1255,12 @@ static int task_hot(struct task_struct *p, u64 now, struct sched_domain *sd);
 
 #define sched_class_highest (&rt_sched_class)
 
-static void inc_nr_running(struct task_struct *p, struct rq *rq)
+static void inc_nr_running(struct rq *rq)
 {
        rq->nr_running++;
 }
 
-static void dec_nr_running(struct task_struct *p, struct rq *rq)
+static void dec_nr_running(struct rq *rq)
 {
        rq->nr_running--;
 }
@@ -1350,11 +1350,11 @@ static int effective_prio(struct task_struct *p)
  */
 static void activate_task(struct rq *rq, struct task_struct *p, int wakeup)
 {
-       if (p->state == TASK_UNINTERRUPTIBLE)
+       if (task_contributes_to_load(p))
                rq->nr_uninterruptible--;
 
        enqueue_task(rq, p, wakeup);
-       inc_nr_running(p, rq);
+       inc_nr_running(rq);
 }
 
 /*
@@ -1362,11 +1362,11 @@ static void activate_task(struct rq *rq, struct task_struct *p, int wakeup)
  */
 static void deactivate_task(struct rq *rq, struct task_struct *p, int sleep)
 {
-       if (p->state == TASK_UNINTERRUPTIBLE)
+       if (task_contributes_to_load(p))
                rq->nr_uninterruptible++;
 
        dequeue_task(rq, p, sleep);
-       dec_nr_running(p, rq);
+       dec_nr_running(rq);
 }
 
 /**
@@ -1895,8 +1895,7 @@ out:
 
 int fastcall wake_up_process(struct task_struct *p)
 {
-       return try_to_wake_up(p, TASK_STOPPED | TASK_TRACED |
-                                TASK_INTERRUPTIBLE | TASK_UNINTERRUPTIBLE, 0);
+       return try_to_wake_up(p, TASK_ALL, 0);
 }
 EXPORT_SYMBOL(wake_up_process);
 
@@ -2006,7 +2005,7 @@ void fastcall wake_up_new_task(struct task_struct *p, unsigned long clone_flags)
                 * management (if any):
                 */
                p->sched_class->task_new(rq, p);
-               inc_nr_running(p, rq);
+               inc_nr_running(rq);
        }
        check_preempt_curr(rq, p);
 #ifdef CONFIG_SMP
@@ -4124,8 +4123,7 @@ void complete(struct completion *x)
 
        spin_lock_irqsave(&x->wait.lock, flags);
        x->done++;
-       __wake_up_common(&x->wait, TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE,
-                        1, 0, NULL);
+       __wake_up_common(&x->wait, TASK_NORMAL, 1, 0, NULL);
        spin_unlock_irqrestore(&x->wait.lock, flags);
 }
 EXPORT_SYMBOL(complete);
@@ -4136,8 +4134,7 @@ void complete_all(struct completion *x)
 
        spin_lock_irqsave(&x->wait.lock, flags);
        x->done += UINT_MAX/2;
-       __wake_up_common(&x->wait, TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE,
-                        0, 0, NULL);
+       __wake_up_common(&x->wait, TASK_NORMAL, 0, 0, NULL);
        spin_unlock_irqrestore(&x->wait.lock, flags);
 }
 EXPORT_SYMBOL(complete_all);
@@ -4151,8 +4148,10 @@ do_wait_for_common(struct completion *x, long timeout, int state)
                wait.flags |= WQ_FLAG_EXCLUSIVE;
                __add_wait_queue_tail(&x->wait, &wait);
                do {
-                       if (state == TASK_INTERRUPTIBLE &&
-                           signal_pending(current)) {
+                       if ((state == TASK_INTERRUPTIBLE &&
+                            signal_pending(current)) ||
+                           (state == TASK_KILLABLE &&
+                            fatal_signal_pending(current))) {
                                __remove_wait_queue(&x->wait, &wait);
                                return -ERESTARTSYS;
                        }
@@ -4212,6 +4211,15 @@ wait_for_completion_interruptible_timeout(struct completion *x,
 }
 EXPORT_SYMBOL(wait_for_completion_interruptible_timeout);
 
+int __sched wait_for_completion_killable(struct completion *x)
+{
+       long t = wait_for_common(x, MAX_SCHEDULE_TIMEOUT, TASK_KILLABLE);
+       if (t == -ERESTARTSYS)
+               return t;
+       return 0;
+}
+EXPORT_SYMBOL(wait_for_completion_killable);
+
 static long __sched
 sleep_on_common(wait_queue_head_t *q, int state, long timeout)
 {
index 72e25c7a3a186dc9830c206662dca4ad7d5892cb..6c091d6e159d01fb23c0dd786495c533cb005c5b 100644 (file)
@@ -520,7 +520,7 @@ place_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int initial)
 
        if (!initial) {
                /* sleeps upto a single latency don't count. */
-               if (sched_feat(NEW_FAIR_SLEEPERS) && entity_is_task(se))
+               if (sched_feat(NEW_FAIR_SLEEPERS))
                        vruntime -= sysctl_sched_latency;
 
                /* ensure we never gain time by being placed backwards. */
@@ -1106,7 +1106,11 @@ static void check_preempt_wakeup(struct rq *rq, struct task_struct *p)
        }
 
        gran = sysctl_sched_wakeup_granularity;
-       if (unlikely(se->load.weight != NICE_0_LOAD))
+       /*
+        * More easily preempt - nice tasks, while not making
+        * it harder for + nice tasks.
+        */
+       if (unlikely(se->load.weight > NICE_0_LOAD))
                gran = calc_delta_fair(gran, &se->load);
 
        if (pse->vruntime + gran < se->vruntime)
index bf49ce6f016bee66cb89bdb39dd416d4d20635ba..6a5f97cd337a3bc980428ea1c186efedbe991a25 100644 (file)
@@ -456,15 +456,15 @@ void signal_wake_up(struct task_struct *t, int resume)
        set_tsk_thread_flag(t, TIF_SIGPENDING);
 
        /*
-        * For SIGKILL, we want to wake it up in the stopped/traced case.
-        * We don't check t->state here because there is a race with it
+        * For SIGKILL, we want to wake it up in the stopped/traced/killable
+        * case. We don't check t->state here because there is a race with it
         * executing another processor and just now entering stopped state.
         * By using wake_up_state, we ensure the process will wake up and
         * handle its death signal.
         */
        mask = TASK_INTERRUPTIBLE;
        if (resume)
-               mask |= TASK_STOPPED | TASK_TRACED;
+               mask |= TASK_WAKEKILL;
        if (!wake_up_state(t, mask))
                kick_process(t);
 }
@@ -620,7 +620,7 @@ static void handle_stop_signal(int sig, struct task_struct *p)
                         * Wake up the stopped thread _after_ setting
                         * TIF_SIGPENDING
                         */
-                       state = TASK_STOPPED;
+                       state = __TASK_STOPPED;
                        if (sig_user_defined(t, SIGCONT) && !sigismember(&t->blocked, SIGCONT)) {
                                set_tsk_thread_flag(t, TIF_SIGPENDING);
                                state |= TASK_INTERRUPTIBLE;
@@ -838,7 +838,7 @@ static inline int wants_signal(int sig, struct task_struct *p)
                return 0;
        if (sig == SIGKILL)
                return 1;
-       if (p->state & (TASK_STOPPED | TASK_TRACED))
+       if (task_is_stopped_or_traced(p))
                return 0;
        return task_curr(p) || !signal_pending(p);
 }
@@ -911,27 +911,6 @@ __group_complete_signal(int sig, struct task_struct *p)
                        } while_each_thread(p, t);
                        return;
                }
-
-               /*
-                * There will be a core dump.  We make all threads other
-                * than the chosen one go into a group stop so that nothing
-                * happens until it gets scheduled, takes the signal off
-                * the shared queue, and does the core dump.  This is a
-                * little more complicated than strictly necessary, but it
-                * keeps the signal state that winds up in the core dump
-                * unchanged from the death state, e.g. which thread had
-                * the core-dump signal unblocked.
-                */
-               rm_from_queue(SIG_KERNEL_STOP_MASK, &t->pending);
-               rm_from_queue(SIG_KERNEL_STOP_MASK, &p->signal->shared_pending);
-               p->signal->group_stop_count = 0;
-               p->signal->group_exit_task = t;
-               p = t;
-               do {
-                       p->signal->group_stop_count++;
-                       signal_wake_up(t, t == p);
-               } while_each_thread(p, t);
-               return;
        }
 
        /*
@@ -978,7 +957,6 @@ void zap_other_threads(struct task_struct *p)
 {
        struct task_struct *t;
 
-       p->signal->flags = SIGNAL_GROUP_EXIT;
        p->signal->group_stop_count = 0;
 
        for (t = next_thread(p); t != p; t = next_thread(t)) {
@@ -994,6 +972,12 @@ void zap_other_threads(struct task_struct *p)
        }
 }
 
+int fastcall __fatal_signal_pending(struct task_struct *tsk)
+{
+       return sigismember(&tsk->pending.signal, SIGKILL);
+}
+EXPORT_SYMBOL(__fatal_signal_pending);
+
 /*
  * Must be called under rcu_read_lock() or with tasklist_lock read-held.
  */
@@ -1441,7 +1425,7 @@ void do_notify_parent(struct task_struct *tsk, int sig)
        BUG_ON(sig == -1);
 
        /* do_notify_parent_cldstop should have been called instead.  */
-       BUG_ON(tsk->state & (TASK_STOPPED|TASK_TRACED));
+       BUG_ON(task_is_stopped_or_traced(tsk));
 
        BUG_ON(!tsk->ptrace &&
               (tsk->group_leader != tsk || !thread_group_empty(tsk)));
@@ -1703,9 +1687,6 @@ static int do_signal_stop(int signr)
        struct signal_struct *sig = current->signal;
        int stop_count;
 
-       if (!likely(sig->flags & SIGNAL_STOP_DEQUEUED))
-               return 0;
-
        if (sig->group_stop_count > 0) {
                /*
                 * There is a group stop in progress.  We don't need to
@@ -1713,12 +1694,15 @@ static int do_signal_stop(int signr)
                 */
                stop_count = --sig->group_stop_count;
        } else {
+               struct task_struct *t;
+
+               if (!likely(sig->flags & SIGNAL_STOP_DEQUEUED) ||
+                   unlikely(sig->group_exit_task))
+                       return 0;
                /*
                 * There is no group stop already in progress.
                 * We must initiate one now.
                 */
-               struct task_struct *t;
-
                sig->group_exit_code = signr;
 
                stop_count = 0;
@@ -1729,7 +1713,7 @@ static int do_signal_stop(int signr)
                         * so this check has no races.
                         */
                        if (!t->exit_state &&
-                           !(t->state & (TASK_STOPPED|TASK_TRACED))) {
+                           !task_is_stopped_or_traced(t)) {
                                stop_count++;
                                signal_wake_up(t, 0);
                        }
@@ -1746,47 +1730,6 @@ static int do_signal_stop(int signr)
        return 1;
 }
 
-/*
- * Do appropriate magic when group_stop_count > 0.
- * We return nonzero if we stopped, after releasing the siglock.
- * We return zero if we still hold the siglock and should look
- * for another signal without checking group_stop_count again.
- */
-static int handle_group_stop(void)
-{
-       int stop_count;
-
-       if (current->signal->group_exit_task == current) {
-               /*
-                * Group stop is so we can do a core dump,
-                * We are the initiating thread, so get on with it.
-                */
-               current->signal->group_exit_task = NULL;
-               return 0;
-       }
-
-       if (current->signal->flags & SIGNAL_GROUP_EXIT)
-               /*
-                * Group stop is so another thread can do a core dump,
-                * or else we are racing against a death signal.
-                * Just punt the stop so we can get the next signal.
-                */
-               return 0;
-
-       /*
-        * There is a group stop in progress.  We stop
-        * without any associated signal being in our queue.
-        */
-       stop_count = --current->signal->group_stop_count;
-       if (stop_count == 0)
-               current->signal->flags = SIGNAL_STOP_STOPPED;
-       current->exit_code = current->signal->group_exit_code;
-       set_current_state(TASK_STOPPED);
-       spin_unlock_irq(&current->sighand->siglock);
-       finish_stop(stop_count);
-       return 1;
-}
-
 int get_signal_to_deliver(siginfo_t *info, struct k_sigaction *return_ka,
                          struct pt_regs *regs, void *cookie)
 {
@@ -1801,7 +1744,7 @@ relock:
                struct k_sigaction *ka;
 
                if (unlikely(current->signal->group_stop_count > 0) &&
-                   handle_group_stop())
+                   do_signal_stop(0))
                        goto relock;
 
                signr = dequeue_signal(current, mask, info);
index c1d76552446e592bc132d8de37073ecb589a1629..7c2da88db4eddf6539673357b01d94b543aac52c 100644 (file)
@@ -101,6 +101,10 @@ void softlockup_tick(void)
 
        now = get_timestamp(this_cpu);
 
+       /* Wake up the high-prio watchdog task every second: */
+       if (now > (touch_timestamp + 1))
+               wake_up_process(per_cpu(watchdog_task, this_cpu));
+
        /* Warn about unreasonable delays: */
        if (now <= (touch_timestamp + softlockup_thresh))
                return;
@@ -191,11 +195,11 @@ static void check_hung_uninterruptible_tasks(int this_cpu)
        read_lock(&tasklist_lock);
        do_each_thread(g, t) {
                if (!--max_count)
-                       break;
+                       goto unlock;
                if (t->state & TASK_UNINTERRUPTIBLE)
                        check_hung_task(t, now);
        } while_each_thread(g, t);
-
+ unlock:
        read_unlock(&tasklist_lock);
 }
 
@@ -218,14 +222,19 @@ static int watchdog(void *__bind_cpu)
         * debug-printout triggers in softlockup_tick().
         */
        while (!kthread_should_stop()) {
+               set_current_state(TASK_INTERRUPTIBLE);
                touch_softlockup_watchdog();
-               msleep_interruptible(10000);
+               schedule();
+
+               if (kthread_should_stop())
+                       break;
 
                if (this_cpu != check_cpu)
                        continue;
 
                if (sysctl_hung_task_timeout_secs)
                        check_hung_uninterruptible_tasks(this_cpu);
+
        }
 
        return 0;
@@ -259,13 +268,6 @@ cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu)
                wake_up_process(per_cpu(watchdog_task, hotcpu));
                break;
 #ifdef CONFIG_HOTPLUG_CPU
-       case CPU_UP_CANCELED:
-       case CPU_UP_CANCELED_FROZEN:
-               if (!per_cpu(watchdog_task, hotcpu))
-                       break;
-               /* Unbind so it can run.  Fall thru. */
-               kthread_bind(per_cpu(watchdog_task, hotcpu),
-                            any_online_cpu(cpu_online_map));
        case CPU_DOWN_PREPARE:
        case CPU_DOWN_PREPARE_FROZEN:
                if (hotcpu == check_cpu) {
@@ -275,6 +277,14 @@ cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu)
                        check_cpu = any_online_cpu(temp_cpu_online_map);
                }
                break;
+
+       case CPU_UP_CANCELED:
+       case CPU_UP_CANCELED_FROZEN:
+               if (!per_cpu(watchdog_task, hotcpu))
+                       break;
+               /* Unbind so it can run.  Fall thru. */
+               kthread_bind(per_cpu(watchdog_task, hotcpu),
+                            any_online_cpu(cpu_online_map));
        case CPU_DEAD:
        case CPU_DEAD_FROZEN:
                p = per_cpu(watchdog_task, hotcpu);
index d1fe71eb45469bc99f23cfe9aee83a8cbecc81b1..53de35fc82458eeade26a07e9a36f1acfc18b88a 100644 (file)
@@ -315,7 +315,7 @@ static void kernel_kexec(void)
 #endif
 }
 
-void kernel_shutdown_prepare(enum system_states state)
+static void kernel_shutdown_prepare(enum system_states state)
 {
        blocking_notifier_call_chain(&reboot_notifier_list,
                (state == SYSTEM_HALT)?SYS_HALT:SYS_POWER_OFF, NULL);
@@ -1637,7 +1637,7 @@ asmlinkage long sys_umask(int mask)
        mask = xchg(&current->fs->umask, mask & S_IRWXUGO);
        return mask;
 }
-    
+
 asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3,
                          unsigned long arg4, unsigned long arg5)
 {
@@ -1742,6 +1742,17 @@ asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3,
                        error = prctl_set_seccomp(arg2);
                        break;
 
+               case PR_CAPBSET_READ:
+                       if (!cap_valid(arg2))
+                               return -EINVAL;
+                       return !!cap_raised(current->cap_bset, arg2);
+               case PR_CAPBSET_DROP:
+#ifdef CONFIG_SECURITY_FILE_CAPABILITIES
+                       return cap_prctl_drop(arg2);
+#else
+                       return -EINVAL;
+#endif
+
                default:
                        error = -EINVAL;
                        break;
index beee5b3b68a284a2e2b3fd2c2a3d9578d0e03bb7..5b9b467de070e2b50e0e2da7b09aaacfd6cc417e 100644 (file)
@@ -154,7 +154,10 @@ cond_syscall(sys_ioprio_get);
 
 /* New file descriptors */
 cond_syscall(sys_signalfd);
-cond_syscall(sys_timerfd);
 cond_syscall(compat_sys_signalfd);
-cond_syscall(compat_sys_timerfd);
+cond_syscall(sys_timerfd_create);
+cond_syscall(sys_timerfd_settime);
+cond_syscall(sys_timerfd_gettime);
+cond_syscall(compat_sys_timerfd_settime);
+cond_syscall(compat_sys_timerfd_gettime);
 cond_syscall(sys_eventfd);
index 357b68ba23ecd7975f93e4273787cf1041ca8df8..5e2ad5bf88e280fdbc83b61a380909555e121a71 100644 (file)
@@ -81,12 +81,14 @@ extern int percpu_pagelist_fraction;
 extern int compat_log;
 extern int maps_protect;
 extern int sysctl_stat_interval;
-extern int audit_argv_kb;
 extern int latencytop_enabled;
 
 /* Constants used for minimum and  maximum */
-#ifdef CONFIG_DETECT_SOFTLOCKUP
+#if defined(CONFIG_DETECT_SOFTLOCKUP) || defined(CONFIG_HIGHMEM)
 static int one = 1;
+#endif
+
+#ifdef CONFIG_DETECT_SOFTLOCKUP
 static int sixty = 60;
 #endif
 
@@ -390,16 +392,6 @@ static struct ctl_table kern_table[] = {
                .mode           = 0644,
                .proc_handler   = &proc_dointvec,
        },
-#ifdef CONFIG_AUDITSYSCALL
-       {
-               .ctl_name       = CTL_UNNUMBERED,
-               .procname       = "audit_argv_kb",
-               .data           = &audit_argv_kb,
-               .maxlen         = sizeof(int),
-               .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
-       },
-#endif
        {
                .ctl_name       = KERN_CORE_PATTERN,
                .procname       = "core_pattern",
@@ -427,15 +419,6 @@ static struct ctl_table kern_table[] = {
                .proc_handler   = &proc_dointvec,
        },
 #endif
-#ifdef CONFIG_SECURITY_CAPABILITIES
-       {
-               .procname       = "cap-bound",
-               .data           = &cap_bset,
-               .maxlen         = sizeof(kernel_cap_t),
-               .mode           = 0600,
-               .proc_handler   = &proc_dointvec_bset,
-       },
-#endif /* def CONFIG_SECURITY_CAPABILITIES */
 #ifdef CONFIG_BLK_DEV_INITRD
        {
                .ctl_name       = KERN_REALROOTDEV,
@@ -1161,6 +1144,19 @@ static struct ctl_table vm_table[] = {
                .extra1         = &zero,
        },
 #endif
+#ifdef CONFIG_HIGHMEM
+       {
+               .ctl_name       = CTL_UNNUMBERED,
+               .procname       = "highmem_is_dirtyable",
+               .data           = &vm_highmem_is_dirtyable,
+               .maxlen         = sizeof(vm_highmem_is_dirtyable),
+               .mode           = 0644,
+               .proc_handler   = &proc_dointvec_minmax,
+               .strategy       = &sysctl_intvec,
+               .extra1         = &zero,
+               .extra2         = &one,
+       },
+#endif
 /*
  * NOTE: do not add new entries to this table unless you have read
  * Documentation/sysctl/ctl_unnumbered.txt
@@ -2091,26 +2087,6 @@ static int do_proc_dointvec_bset_conv(int *negp, unsigned long *lvalp,
        return 0;
 }
 
-#ifdef CONFIG_SECURITY_CAPABILITIES
-/*
- *     init may raise the set.
- */
-
-int proc_dointvec_bset(struct ctl_table *table, int write, struct file *filp,
-                       void __user *buffer, size_t *lenp, loff_t *ppos)
-{
-       int op;
-
-       if (write && !capable(CAP_SYS_MODULE)) {
-               return -EPERM;
-       }
-
-       op = is_global_init(current) ? OP_SET : OP_AND;
-       return do_proc_dointvec(table,write,filp,buffer,lenp,ppos,
-                               do_proc_dointvec_bset_conv,&op);
-}
-#endif /* def CONFIG_SECURITY_CAPABILITIES */
-
 /*
  *     Taint values can only be increased
  */
@@ -2524,12 +2500,6 @@ int proc_dointvec(struct ctl_table *table, int write, struct file *filp,
        return -ENOSYS;
 }
 
-int proc_dointvec_bset(struct ctl_table *table, int write, struct file *filp,
-                       void __user *buffer, size_t *lenp, loff_t *ppos)
-{
-       return -ENOSYS;
-}
-
 int proc_dointvec_minmax(struct ctl_table *table, int write, struct file *filp,
                    void __user *buffer, size_t *lenp, loff_t *ppos)
 {
index c3206fa50048b8333be64be54a3a52acf8d39bcb..006365b69eafdfcebbaa47ba1370a87d58813e94 100644 (file)
@@ -37,10 +37,6 @@ static struct trans_ctl_table trans_kern_table[] = {
        { KERN_NODENAME,                "hostname" },
        { KERN_DOMAINNAME,              "domainname" },
 
-#ifdef CONFIG_SECURITY_CAPABILITIES
-       { KERN_CAP_BSET,                "cap-bound" },
-#endif /* def CONFIG_SECURITY_CAPABILITIES */
-
        { KERN_PANIC,                   "panic" },
        { KERN_REALROOTDEV,             "real-root-dev" },
 
@@ -1498,9 +1494,6 @@ int sysctl_check_table(struct nsproxy *namespaces, struct ctl_table *table)
                            (table->strategy == sysctl_ms_jiffies) ||
                            (table->proc_handler == proc_dostring) ||
                            (table->proc_handler == proc_dointvec) ||
-#ifdef CONFIG_SECURITY_CAPABILITIES
-                           (table->proc_handler == proc_dointvec_bset) ||
-#endif /* def CONFIG_SECURITY_CAPABILITIES */
                            (table->proc_handler == proc_dointvec_minmax) ||
                            (table->proc_handler == proc_dointvec_jiffies) ||
                            (table->proc_handler == proc_dointvec_userhz_jiffies) ||
index 09d3c45c4da78d9af2bec9e10f89e37bfeec01d5..4064c0566e77db73c9cd3b5534884975dc4394e0 100644 (file)
@@ -129,6 +129,7 @@ static inline void warp_clock(void)
        write_seqlock_irq(&xtime_lock);
        wall_to_monotonic.tv_sec -= sys_tz.tz_minuteswest * 60;
        xtime.tv_sec += sys_tz.tz_minuteswest * 60;
+       update_xtime_cache(0);
        write_sequnlock_irq(&xtime_lock);
        clock_was_set();
 }
index 63f24b55069551f4331f09c090657b66be139f7e..88267f0a84713082dfb8ca719a76337b69990f04 100644 (file)
@@ -137,6 +137,7 @@ void tick_nohz_update_jiffies(void)
 
        cpu_clear(cpu, nohz_cpu_mask);
        now = ktime_get();
+       ts->idle_waketime = now;
 
        local_irq_save(flags);
        tick_do_update_jiffies64(now);
@@ -400,6 +401,7 @@ void tick_nohz_restart_sched_tick(void)
         * Cancel the scheduled timer and restore the tick
         */
        ts->tick_stopped  = 0;
+       ts->idle_exittime = now;
        hrtimer_cancel(&ts->sched_timer);
        ts->sched_timer.expires = ts->idle_tick;
 
index 092a2366b5a905d2fb8347106c08176a7ed81114..cd5dbc4579c9bd3058063450b08e732c31e14ddf 100644 (file)
@@ -47,7 +47,7 @@ struct timespec wall_to_monotonic __attribute__ ((aligned (16)));
 static unsigned long total_sleep_time;         /* seconds */
 
 static struct timespec xtime_cache __attribute__ ((aligned (16)));
-static inline void update_xtime_cache(u64 nsec)
+void update_xtime_cache(u64 nsec)
 {
        xtime_cache = xtime;
        timespec_add_ns(&xtime_cache, nsec);
@@ -145,6 +145,7 @@ int do_settimeofday(struct timespec *tv)
 
        set_normalized_timespec(&xtime, sec, nsec);
        set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
+       update_xtime_cache(0);
 
        clock->error = 0;
        ntp_clear();
@@ -252,8 +253,8 @@ void __init timekeeping_init(void)
        xtime.tv_nsec = 0;
        set_normalized_timespec(&wall_to_monotonic,
                -xtime.tv_sec, -xtime.tv_nsec);
+       update_xtime_cache(0);
        total_sleep_time = 0;
-
        write_sequnlock_irqrestore(&xtime_lock, flags);
 }
 
@@ -290,6 +291,7 @@ static int timekeeping_resume(struct sys_device *dev)
        }
        /* Make sure that we have the correct xtime reference */
        timespec_add_ns(&xtime, timekeeping_suspend_nsecs);
+       update_xtime_cache(0);
        /* re-base the last cycle value */
        clock->cycle_last = clocksource_read(clock);
        clock->error = 0;
index 12c5f4cb6b8c67bd9d04bc8784989a2be9185fc1..d3d94c1a0fd2600a5c8d17b1b90801b449f880df 100644 (file)
@@ -166,6 +166,8 @@ static void print_cpu(struct seq_file *m, int cpu, u64 now)
                P(idle_calls);
                P(idle_sleeps);
                P_ns(idle_entrytime);
+               P_ns(idle_waketime);
+               P_ns(idle_exittime);
                P_ns(idle_sleeptime);
                P(last_jiffies);
                P(next_jiffies);
index 23f7ead78faeae25b07ad78819f4cadefdd3b4b6..9fbb472b8cf0a4e3016480fb205c42eda38dabf8 100644 (file)
@@ -1099,6 +1099,13 @@ signed long __sched schedule_timeout_interruptible(signed long timeout)
 }
 EXPORT_SYMBOL(schedule_timeout_interruptible);
 
+signed long __sched schedule_timeout_killable(signed long timeout)
+{
+       __set_current_state(TASK_KILLABLE);
+       return schedule_timeout(timeout);
+}
+EXPORT_SYMBOL(schedule_timeout_killable);
+
 signed long __sched schedule_timeout_uninterruptible(signed long timeout)
 {
        __set_current_state(TASK_UNINTERRUPTIBLE);
index 444ddbfaefc490839e2cf913cb688c7ebb9f0df9..f9876888a569d286fc9e9e08250f9b9b075a58fd 100644 (file)
@@ -215,7 +215,7 @@ void fastcall __wake_up_bit(wait_queue_head_t *wq, void *word, int bit)
 {
        struct wait_bit_key key = __WAIT_BIT_KEY_INITIALIZER(word, bit);
        if (waitqueue_active(wq))
-               __wake_up(wq, TASK_INTERRUPTIBLE|TASK_UNINTERRUPTIBLE, 1, &key);
+               __wake_up(wq, TASK_NORMAL, 1, &key);
 }
 EXPORT_SYMBOL(__wake_up_bit);
 
index 89f4035b526c147de3115794fa2cbd55b25db8ab..0d385be682db021dccc6482f385d8bb6f30fa75e 100644 (file)
@@ -81,7 +81,7 @@ config HEADERS_CHECK
 
 config DEBUG_SECTION_MISMATCH
        bool "Enable full Section mismatch analysis"
-       default n
+       depends on UNDEFINED
        help
          The section mismatch analysis checks if there are illegal
          references from one section to another section.
@@ -90,19 +90,19 @@ config DEBUG_SECTION_MISMATCH
          most likely result in an oops.
          In the code functions and variables are annotated with
          __init, __devinit etc. (see full list in include/linux/init.h)
-         which result in the code/data being placed in specific sections.
-         The section mismatch anaylsis are always done after a full
-         kernel build but enabling this options will in addition
+         which results in the code/data being placed in specific sections.
+         The section mismatch analysis is always done after a full
+         kernel build but enabling this option will in addition
          do the following:
          - Add the option -fno-inline-functions-called-once to gcc
            When inlining a function annotated __init in a non-init
-           function we would loose the section information and thus
+           function we would lose the section information and thus
            the analysis would not catch the illegal reference.
-           This options tell gcc to inline less but will also
+           This option tells gcc to inline less but will also
            result in a larger kernel.
          - Run the section mismatch analysis for each module/built-in.o
            When we run the section mismatch analysis on vmlinux.o we
-           looses valueable information about where the mismatch was
+           lose valueble information about where the mismatch was
            introduced.
            Running the analysis for each module/built-in.o file
            will tell where the mismatch happens much closer to the
@@ -581,7 +581,7 @@ config LATENCYTOP
        select STACKTRACE
        select SCHEDSTATS
        select SCHED_DEBUG
-       depends on X86 || X86_64
+       depends on HAVE_LATENCYTOP_SUPPORT
        help
          Enable this option if you want to use the LatencyTOP tool
          to find out which userspace is blocking on what kernel operations.
index 543f2502b60a416f2bb97575e2e8f0254c7a9199..a18062e4633f810463feae8efbe349a085604335 100644 (file)
@@ -65,6 +65,7 @@ obj-$(CONFIG_SMP) += pcounter.o
 obj-$(CONFIG_AUDIT_GENERIC) += audit.o
 
 obj-$(CONFIG_SWIOTLB) += swiotlb.o
+obj-$(CONFIG_IOMMU_HELPER) += iommu-helper.o
 obj-$(CONFIG_FAULT_INJECTION) += fault-inject.o
 
 lib-$(CONFIG_GENERIC_BUG) += bug.o
index d2c2f257bedd348a0f81316fc02ef90226ecc0ac..49d1c9e3ce3820ccb8dd3d01cec5e11ac39cd7cc 100644 (file)
@@ -348,7 +348,7 @@ EXPORT_SYMBOL(crc32_be);
  * but again the multiple of the polynomial to subtract depends only on
  * the high bits, the high 8 bits in this case.  
  *
- * The multile we need in that case is the low 32 bits of a 40-bit
+ * The multiple we need in that case is the low 32 bits of a 40-bit
  * value whose high 8 bits are given, and which is a multiple of the
  * generator polynomial.  This is simply the CRC-32 of the given
  * one-byte message.
diff --git a/lib/iommu-helper.c b/lib/iommu-helper.c
new file mode 100644 (file)
index 0000000..495575a
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * IOMMU helper functions for the free area management
+ */
+
+#include <linux/module.h>
+#include <linux/bitops.h>
+
+static unsigned long find_next_zero_area(unsigned long *map,
+                                        unsigned long size,
+                                        unsigned long start,
+                                        unsigned int nr,
+                                        unsigned long align_mask)
+{
+       unsigned long index, end, i;
+again:
+       index = find_next_zero_bit(map, size, start);
+
+       /* Align allocation */
+       index = (index + align_mask) & ~align_mask;
+
+       end = index + nr;
+       if (end >= size)
+               return -1;
+       for (i = index; i < end; i++) {
+               if (test_bit(i, map)) {
+                       start = i+1;
+                       goto again;
+               }
+       }
+       return index;
+}
+
+static inline void set_bit_area(unsigned long *map, unsigned long i,
+                               int len)
+{
+       unsigned long end = i + len;
+       while (i < end) {
+               __set_bit(i, map);
+               i++;
+       }
+}
+
+static inline int is_span_boundary(unsigned int index, unsigned int nr,
+                                  unsigned long shift,
+                                  unsigned long boundary_size)
+{
+       shift = (shift + index) & (boundary_size - 1);
+       return shift + nr > boundary_size;
+}
+
+unsigned long iommu_area_alloc(unsigned long *map, unsigned long size,
+                              unsigned long start, unsigned int nr,
+                              unsigned long shift, unsigned long boundary_size,
+                              unsigned long align_mask)
+{
+       unsigned long index;
+again:
+       index = find_next_zero_area(map, size, start, nr, align_mask);
+       if (index != -1) {
+               if (is_span_boundary(index, nr, shift, boundary_size)) {
+                       /* we could do more effectively */
+                       start = index + 1;
+                       goto again;
+               }
+               set_bit_area(map, index, nr);
+       }
+       return index;
+}
+EXPORT_SYMBOL(iommu_area_alloc);
+
+void iommu_area_free(unsigned long *map, unsigned long start, unsigned int nr)
+{
+       unsigned long end = start + nr;
+
+       while (start < end) {
+               __clear_bit(start, map);
+               start++;
+       }
+}
+EXPORT_SYMBOL(iommu_area_free);
index 1d63ead1815e4f5cb8aae5ea2d86a1541eed23a2..d784daeb8571692e0fed288f17df60651a04366c 100644 (file)
@@ -637,7 +637,7 @@ struct kobject *kobject_create(void)
  * @name: the name for the kset
  * @parent: the parent kobject of this kobject, if any.
  *
- * This function creates a kset structure dynamically and registers it
+ * This function creates a kobject structure dynamically and registers it
  * with sysfs.  When you are finished with this structure, call
  * kobject_put() and the structure will be dynamically freed when
  * it is no longer being used.
index 48c250fe2233d82c6d8fd563e83c234cdf1109ee..65f0e758ec3819d57f1799e5563a9f90dc0e41eb 100644 (file)
@@ -95,14 +95,17 @@ static inline gfp_t root_gfp_mask(struct radix_tree_root *root)
 static struct radix_tree_node *
 radix_tree_node_alloc(struct radix_tree_root *root)
 {
-       struct radix_tree_node *ret;
+       struct radix_tree_node *ret = NULL;
        gfp_t gfp_mask = root_gfp_mask(root);
 
-       ret = kmem_cache_alloc(radix_tree_node_cachep,
-                               set_migrateflags(gfp_mask, __GFP_RECLAIMABLE));
-       if (ret == NULL && !(gfp_mask & __GFP_WAIT)) {
+       if (!(gfp_mask & __GFP_WAIT)) {
                struct radix_tree_preload *rtp;
 
+               /*
+                * Provided the caller has preloaded here, we will always
+                * succeed in getting a node here (and never reach
+                * kmem_cache_alloc)
+                */
                rtp = &__get_cpu_var(radix_tree_preloads);
                if (rtp->nr) {
                        ret = rtp->nodes[rtp->nr - 1];
@@ -110,6 +113,10 @@ radix_tree_node_alloc(struct radix_tree_root *root)
                        rtp->nr--;
                }
        }
+       if (ret == NULL)
+               ret = kmem_cache_alloc(radix_tree_node_cachep,
+                               set_migrateflags(gfp_mask, __GFP_RECLAIMABLE));
+
        BUG_ON(radix_tree_is_indirect_ptr(ret));
        return ret;
 }
index 1a8050ade86159877fd6eb4486954c7719bfc28d..4bb5a11e18a289e6bcf3a89ca41b0a13fb0b40cc 100644 (file)
@@ -282,6 +282,15 @@ address_needs_mapping(struct device *hwdev, dma_addr_t addr)
        return (addr & ~mask) != 0;
 }
 
+static inline unsigned int is_span_boundary(unsigned int index,
+                                           unsigned int nslots,
+                                           unsigned long offset_slots,
+                                           unsigned long max_slots)
+{
+       unsigned long offset = (offset_slots + index) & (max_slots - 1);
+       return offset + nslots > max_slots;
+}
+
 /*
  * Allocates bounce buffer and returns its kernel virtual address.
  */
@@ -292,6 +301,16 @@ map_single(struct device *hwdev, char *buffer, size_t size, int dir)
        char *dma_addr;
        unsigned int nslots, stride, index, wrap;
        int i;
+       unsigned long start_dma_addr;
+       unsigned long mask;
+       unsigned long offset_slots;
+       unsigned long max_slots;
+
+       mask = dma_get_seg_boundary(hwdev);
+       start_dma_addr = virt_to_bus(io_tlb_start) & mask;
+
+       offset_slots = ALIGN(start_dma_addr, 1 << IO_TLB_SHIFT) >> IO_TLB_SHIFT;
+       max_slots = ALIGN(mask + 1, 1 << IO_TLB_SHIFT) >> IO_TLB_SHIFT;
 
        /*
         * For mappings greater than a page, we limit the stride (and
@@ -311,10 +330,17 @@ map_single(struct device *hwdev, char *buffer, size_t size, int dir)
         */
        spin_lock_irqsave(&io_tlb_lock, flags);
        {
-               wrap = index = ALIGN(io_tlb_index, stride);
-
+               index = ALIGN(io_tlb_index, stride);
                if (index >= io_tlb_nslabs)
-                       wrap = index = 0;
+                       index = 0;
+
+               while (is_span_boundary(index, nslots, offset_slots,
+                                       max_slots)) {
+                       index += stride;
+                       if (index >= io_tlb_nslabs)
+                               index = 0;
+               }
+               wrap = index;
 
                do {
                        /*
@@ -341,9 +367,12 @@ map_single(struct device *hwdev, char *buffer, size_t size, int dir)
 
                                goto found;
                        }
-                       index += stride;
-                       if (index >= io_tlb_nslabs)
-                               index = 0;
+                       do {
+                               index += stride;
+                               if (index >= io_tlb_nslabs)
+                                       index = 0;
+                       } while (is_span_boundary(index, nslots, offset_slots,
+                                                 max_slots));
                } while (index != wrap);
 
                spin_unlock_irqrestore(&io_tlb_lock, flags);
index d9feaf638608a6de4d148f6fdce19e5a1fc59284..6b15a909ca3f0cfc163b4cdcd8a1613884643784 100644 (file)
@@ -164,7 +164,7 @@ typedef struct deflate_state {
     int nice_match; /* Stop searching when current match exceeds this */
 
                 /* used by trees.c: */
-    /* Didn't use ct_data typedef below to supress compiler warning */
+    /* Didn't use ct_data typedef below to suppress compiler warning */
     struct ct_data_s dyn_ltree[HEAP_SIZE];   /* literal and length tree */
     struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */
     struct ct_data_s bl_tree[2*BL_CODES+1];  /* Huffman tree for bit lengths */
index 5c0b0ea7572d8b04aa62ec2bbe2bd566eadef165..4af5dff372779949a28244208c26253e3356f60a 100644 (file)
@@ -13,8 +13,10 @@ obj-y                        := bootmem.o filemap.o mempool.o oom_kill.o fadvise.o \
                           prio_tree.o util.o mmzone.o vmstat.o backing-dev.o \
                           page_isolation.o $(mmu-y)
 
+obj-$(CONFIG_PROC_PAGE_MONITOR) += pagewalk.o
 obj-$(CONFIG_BOUNCE)   += bounce.o
 obj-$(CONFIG_SWAP)     += page_io.o swap_state.o swapfile.o thrash.o
+obj-$(CONFIG_HAS_DMA)  += dmapool.o
 obj-$(CONFIG_HUGETLBFS)        += hugetlb.o
 obj-$(CONFIG_NUMA)     += mempolicy.o
 obj-$(CONFIG_SPARSEMEM)        += sparse.o
diff --git a/mm/dmapool.c b/mm/dmapool.c
new file mode 100644 (file)
index 0000000..34aaac4
--- /dev/null
@@ -0,0 +1,500 @@
+/*
+ * DMA Pool allocator
+ *
+ * Copyright 2001 David Brownell
+ * Copyright 2007 Intel Corporation
+ *   Author: Matthew Wilcox <willy@linux.intel.com>
+ *
+ * This software may be redistributed and/or modified under the terms of
+ * the GNU General Public License ("GPL") version 2 as published by the
+ * Free Software Foundation.
+ *
+ * This allocator returns small blocks of a given size which are DMA-able by
+ * the given device.  It uses the dma_alloc_coherent page allocator to get
+ * new pages, then splits them up into blocks of the required size.
+ * Many older drivers still have their own code to do this.
+ *
+ * The current design of this allocator is fairly simple.  The pool is
+ * represented by the 'struct dma_pool' which keeps a doubly-linked list of
+ * allocated pages.  Each page in the page_list is split into blocks of at
+ * least 'size' bytes.  Free blocks are tracked in an unsorted singly-linked
+ * list of free blocks within the page.  Used blocks aren't tracked, but we
+ * keep a count of how many are currently allocated from each page.
+ */
+
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmapool.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/poison.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/wait.h>
+
+struct dma_pool {              /* the pool */
+       struct list_head page_list;
+       spinlock_t lock;
+       size_t size;
+       struct device *dev;
+       size_t allocation;
+       size_t boundary;
+       char name[32];
+       wait_queue_head_t waitq;
+       struct list_head pools;
+};
+
+struct dma_page {              /* cacheable header for 'allocation' bytes */
+       struct list_head page_list;
+       void *vaddr;
+       dma_addr_t dma;
+       unsigned int in_use;
+       unsigned int offset;
+};
+
+#define        POOL_TIMEOUT_JIFFIES    ((100 /* msec */ * HZ) / 1000)
+
+static DEFINE_MUTEX(pools_lock);
+
+static ssize_t
+show_pools(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       unsigned temp;
+       unsigned size;
+       char *next;
+       struct dma_page *page;
+       struct dma_pool *pool;
+
+       next = buf;
+       size = PAGE_SIZE;
+
+       temp = scnprintf(next, size, "poolinfo - 0.1\n");
+       size -= temp;
+       next += temp;
+
+       mutex_lock(&pools_lock);
+       list_for_each_entry(pool, &dev->dma_pools, pools) {
+               unsigned pages = 0;
+               unsigned blocks = 0;
+
+               list_for_each_entry(page, &pool->page_list, page_list) {
+                       pages++;
+                       blocks += page->in_use;
+               }
+
+               /* per-pool info, no real statistics yet */
+               temp = scnprintf(next, size, "%-16s %4u %4Zu %4Zu %2u\n",
+                                pool->name, blocks,
+                                pages * (pool->allocation / pool->size),
+                                pool->size, pages);
+               size -= temp;
+               next += temp;
+       }
+       mutex_unlock(&pools_lock);
+
+       return PAGE_SIZE - size;
+}
+
+static DEVICE_ATTR(pools, S_IRUGO, show_pools, NULL);
+
+/**
+ * dma_pool_create - Creates a pool of consistent memory blocks, for dma.
+ * @name: name of pool, for diagnostics
+ * @dev: device that will be doing the DMA
+ * @size: size of the blocks in this pool.
+ * @align: alignment requirement for blocks; must be a power of two
+ * @boundary: returned blocks won't cross this power of two boundary
+ * Context: !in_interrupt()
+ *
+ * Returns a dma allocation pool with the requested characteristics, or
+ * null if one can't be created.  Given one of these pools, dma_pool_alloc()
+ * may be used to allocate memory.  Such memory will all have "consistent"
+ * DMA mappings, accessible by the device and its driver without using
+ * cache flushing primitives.  The actual size of blocks allocated may be
+ * larger than requested because of alignment.
+ *
+ * If @boundary is nonzero, objects returned from dma_pool_alloc() won't
+ * cross that size boundary.  This is useful for devices which have
+ * addressing restrictions on individual DMA transfers, such as not crossing
+ * boundaries of 4KBytes.
+ */
+struct dma_pool *dma_pool_create(const char *name, struct device *dev,
+                                size_t size, size_t align, size_t boundary)
+{
+       struct dma_pool *retval;
+       size_t allocation;
+
+       if (align == 0) {
+               align = 1;
+       } else if (align & (align - 1)) {
+               return NULL;
+       }
+
+       if (size == 0) {
+               return NULL;
+       } else if (size < 4) {
+               size = 4;
+       }
+
+       if ((size % align) != 0)
+               size = ALIGN(size, align);
+
+       allocation = max_t(size_t, size, PAGE_SIZE);
+
+       if (!boundary) {
+               boundary = allocation;
+       } else if ((boundary < size) || (boundary & (boundary - 1))) {
+               return NULL;
+       }
+
+       retval = kmalloc_node(sizeof(*retval), GFP_KERNEL, dev_to_node(dev));
+       if (!retval)
+               return retval;
+
+       strlcpy(retval->name, name, sizeof(retval->name));
+
+       retval->dev = dev;
+
+       INIT_LIST_HEAD(&retval->page_list);
+       spin_lock_init(&retval->lock);
+       retval->size = size;
+       retval->boundary = boundary;
+       retval->allocation = allocation;
+       init_waitqueue_head(&retval->waitq);
+
+       if (dev) {
+               int ret;
+
+               mutex_lock(&pools_lock);
+               if (list_empty(&dev->dma_pools))
+                       ret = device_create_file(dev, &dev_attr_pools);
+               else
+                       ret = 0;
+               /* note:  not currently insisting "name" be unique */
+               if (!ret)
+                       list_add(&retval->pools, &dev->dma_pools);
+               else {
+                       kfree(retval);
+                       retval = NULL;
+               }
+               mutex_unlock(&pools_lock);
+       } else
+               INIT_LIST_HEAD(&retval->pools);
+
+       return retval;
+}
+EXPORT_SYMBOL(dma_pool_create);
+
+static void pool_initialise_page(struct dma_pool *pool, struct dma_page *page)
+{
+       unsigned int offset = 0;
+       unsigned int next_boundary = pool->boundary;
+
+       do {
+               unsigned int next = offset + pool->size;
+               if (unlikely((next + pool->size) >= next_boundary)) {
+                       next = next_boundary;
+                       next_boundary += pool->boundary;
+               }
+               *(int *)(page->vaddr + offset) = next;
+               offset = next;
+       } while (offset < pool->allocation);
+}
+
+static struct dma_page *pool_alloc_page(struct dma_pool *pool, gfp_t mem_flags)
+{
+       struct dma_page *page;
+
+       page = kmalloc(sizeof(*page), mem_flags);
+       if (!page)
+               return NULL;
+       page->vaddr = dma_alloc_coherent(pool->dev, pool->allocation,
+                                        &page->dma, mem_flags);
+       if (page->vaddr) {
+#ifdef CONFIG_DEBUG_SLAB
+               memset(page->vaddr, POOL_POISON_FREED, pool->allocation);
+#endif
+               pool_initialise_page(pool, page);
+               list_add(&page->page_list, &pool->page_list);
+               page->in_use = 0;
+               page->offset = 0;
+       } else {
+               kfree(page);
+               page = NULL;
+       }
+       return page;
+}
+
+static inline int is_page_busy(struct dma_page *page)
+{
+       return page->in_use != 0;
+}
+
+static void pool_free_page(struct dma_pool *pool, struct dma_page *page)
+{
+       dma_addr_t dma = page->dma;
+
+#ifdef CONFIG_DEBUG_SLAB
+       memset(page->vaddr, POOL_POISON_FREED, pool->allocation);
+#endif
+       dma_free_coherent(pool->dev, pool->allocation, page->vaddr, dma);
+       list_del(&page->page_list);
+       kfree(page);
+}
+
+/**
+ * dma_pool_destroy - destroys a pool of dma memory blocks.
+ * @pool: dma pool that will be destroyed
+ * Context: !in_interrupt()
+ *
+ * Caller guarantees that no more memory from the pool is in use,
+ * and that nothing will try to use the pool after this call.
+ */
+void dma_pool_destroy(struct dma_pool *pool)
+{
+       mutex_lock(&pools_lock);
+       list_del(&pool->pools);
+       if (pool->dev && list_empty(&pool->dev->dma_pools))
+               device_remove_file(pool->dev, &dev_attr_pools);
+       mutex_unlock(&pools_lock);
+
+       while (!list_empty(&pool->page_list)) {
+               struct dma_page *page;
+               page = list_entry(pool->page_list.next,
+                                 struct dma_page, page_list);
+               if (is_page_busy(page)) {
+                       if (pool->dev)
+                               dev_err(pool->dev,
+                                       "dma_pool_destroy %s, %p busy\n",
+                                       pool->name, page->vaddr);
+                       else
+                               printk(KERN_ERR
+                                      "dma_pool_destroy %s, %p busy\n",
+                                      pool->name, page->vaddr);
+                       /* leak the still-in-use consistent memory */
+                       list_del(&page->page_list);
+                       kfree(page);
+               } else
+                       pool_free_page(pool, page);
+       }
+
+       kfree(pool);
+}
+EXPORT_SYMBOL(dma_pool_destroy);
+
+/**
+ * dma_pool_alloc - get a block of consistent memory
+ * @pool: dma pool that will produce the block
+ * @mem_flags: GFP_* bitmask
+ * @handle: pointer to dma address of block
+ *
+ * This returns the kernel virtual address of a currently unused block,
+ * and reports its dma address through the handle.
+ * If such a memory block can't be allocated, %NULL is returned.
+ */
+void *dma_pool_alloc(struct dma_pool *pool, gfp_t mem_flags,
+                    dma_addr_t *handle)
+{
+       unsigned long flags;
+       struct dma_page *page;
+       size_t offset;
+       void *retval;
+
+       spin_lock_irqsave(&pool->lock, flags);
+ restart:
+       list_for_each_entry(page, &pool->page_list, page_list) {
+               if (page->offset < pool->allocation)
+                       goto ready;
+       }
+       page = pool_alloc_page(pool, GFP_ATOMIC);
+       if (!page) {
+               if (mem_flags & __GFP_WAIT) {
+                       DECLARE_WAITQUEUE(wait, current);
+
+                       __set_current_state(TASK_INTERRUPTIBLE);
+                       __add_wait_queue(&pool->waitq, &wait);
+                       spin_unlock_irqrestore(&pool->lock, flags);
+
+                       schedule_timeout(POOL_TIMEOUT_JIFFIES);
+
+                       spin_lock_irqsave(&pool->lock, flags);
+                       __remove_wait_queue(&pool->waitq, &wait);
+                       goto restart;
+               }
+               retval = NULL;
+               goto done;
+       }
+
+ ready:
+       page->in_use++;
+       offset = page->offset;
+       page->offset = *(int *)(page->vaddr + offset);
+       retval = offset + page->vaddr;
+       *handle = offset + page->dma;
+#ifdef CONFIG_DEBUG_SLAB
+       memset(retval, POOL_POISON_ALLOCATED, pool->size);
+#endif
+ done:
+       spin_unlock_irqrestore(&pool->lock, flags);
+       return retval;
+}
+EXPORT_SYMBOL(dma_pool_alloc);
+
+static struct dma_page *pool_find_page(struct dma_pool *pool, dma_addr_t dma)
+{
+       unsigned long flags;
+       struct dma_page *page;
+
+       spin_lock_irqsave(&pool->lock, flags);
+       list_for_each_entry(page, &pool->page_list, page_list) {
+               if (dma < page->dma)
+                       continue;
+               if (dma < (page->dma + pool->allocation))
+                       goto done;
+       }
+       page = NULL;
+ done:
+       spin_unlock_irqrestore(&pool->lock, flags);
+       return page;
+}
+
+/**
+ * dma_pool_free - put block back into dma pool
+ * @pool: the dma pool holding the block
+ * @vaddr: virtual address of block
+ * @dma: dma address of block
+ *
+ * Caller promises neither device nor driver will again touch this block
+ * unless it is first re-allocated.
+ */
+void dma_pool_free(struct dma_pool *pool, void *vaddr, dma_addr_t dma)
+{
+       struct dma_page *page;
+       unsigned long flags;
+       unsigned int offset;
+
+       page = pool_find_page(pool, dma);
+       if (!page) {
+               if (pool->dev)
+                       dev_err(pool->dev,
+                               "dma_pool_free %s, %p/%lx (bad dma)\n",
+                               pool->name, vaddr, (unsigned long)dma);
+               else
+                       printk(KERN_ERR "dma_pool_free %s, %p/%lx (bad dma)\n",
+                              pool->name, vaddr, (unsigned long)dma);
+               return;
+       }
+
+       offset = vaddr - page->vaddr;
+#ifdef CONFIG_DEBUG_SLAB
+       if ((dma - page->dma) != offset) {
+               if (pool->dev)
+                       dev_err(pool->dev,
+                               "dma_pool_free %s, %p (bad vaddr)/%Lx\n",
+                               pool->name, vaddr, (unsigned long long)dma);
+               else
+                       printk(KERN_ERR
+                              "dma_pool_free %s, %p (bad vaddr)/%Lx\n",
+                              pool->name, vaddr, (unsigned long long)dma);
+               return;
+       }
+       {
+               unsigned int chain = page->offset;
+               while (chain < pool->allocation) {
+                       if (chain != offset) {
+                               chain = *(int *)(page->vaddr + chain);
+                               continue;
+                       }
+                       if (pool->dev)
+                               dev_err(pool->dev, "dma_pool_free %s, dma %Lx "
+                                       "already free\n", pool->name,
+                                       (unsigned long long)dma);
+                       else
+                               printk(KERN_ERR "dma_pool_free %s, dma %Lx "
+                                       "already free\n", pool->name,
+                                       (unsigned long long)dma);
+                       return;
+               }
+       }
+       memset(vaddr, POOL_POISON_FREED, pool->size);
+#endif
+
+       spin_lock_irqsave(&pool->lock, flags);
+       page->in_use--;
+       *(int *)vaddr = page->offset;
+       page->offset = offset;
+       if (waitqueue_active(&pool->waitq))
+               wake_up_locked(&pool->waitq);
+       /*
+        * Resist a temptation to do
+        *    if (!is_page_busy(page)) pool_free_page(pool, page);
+        * Better have a few empty pages hang around.
+        */
+       spin_unlock_irqrestore(&pool->lock, flags);
+}
+EXPORT_SYMBOL(dma_pool_free);
+
+/*
+ * Managed DMA pool
+ */
+static void dmam_pool_release(struct device *dev, void *res)
+{
+       struct dma_pool *pool = *(struct dma_pool **)res;
+
+       dma_pool_destroy(pool);
+}
+
+static int dmam_pool_match(struct device *dev, void *res, void *match_data)
+{
+       return *(struct dma_pool **)res == match_data;
+}
+
+/**
+ * dmam_pool_create - Managed dma_pool_create()
+ * @name: name of pool, for diagnostics
+ * @dev: device that will be doing the DMA
+ * @size: size of the blocks in this pool.
+ * @align: alignment requirement for blocks; must be a power of two
+ * @allocation: returned blocks won't cross this boundary (or zero)
+ *
+ * Managed dma_pool_create().  DMA pool created with this function is
+ * automatically destroyed on driver detach.
+ */
+struct dma_pool *dmam_pool_create(const char *name, struct device *dev,
+                                 size_t size, size_t align, size_t allocation)
+{
+       struct dma_pool **ptr, *pool;
+
+       ptr = devres_alloc(dmam_pool_release, sizeof(*ptr), GFP_KERNEL);
+       if (!ptr)
+               return NULL;
+
+       pool = *ptr = dma_pool_create(name, dev, size, align, allocation);
+       if (pool)
+               devres_add(dev, ptr);
+       else
+               devres_free(ptr);
+
+       return pool;
+}
+EXPORT_SYMBOL(dmam_pool_create);
+
+/**
+ * dmam_pool_destroy - Managed dma_pool_destroy()
+ * @pool: dma pool that will be destroyed
+ *
+ * Managed dma_pool_destroy().
+ */
+void dmam_pool_destroy(struct dma_pool *pool)
+{
+       struct device *dev = pool->dev;
+
+       dma_pool_destroy(pool);
+       WARN_ON(devres_destroy(dev, dmam_pool_release, dmam_pool_match, pool));
+}
+EXPORT_SYMBOL(dmam_pool_destroy);
index 0df4c899e979ec1101cb629a660fc04b31e1095e..3c0f1e99f5e40ad90a116f62a39ca1e0ca3f5fa7 100644 (file)
@@ -49,9 +49,21 @@ asmlinkage long sys_fadvise64_64(int fd, loff_t offset, loff_t len, int advice)
                goto out;
        }
 
-       if (mapping->a_ops->get_xip_page)
-               /* no bad return value, but ignore advice */
+       if (mapping->a_ops->get_xip_page) {
+               switch (advice) {
+               case POSIX_FADV_NORMAL:
+               case POSIX_FADV_RANDOM:
+               case POSIX_FADV_SEQUENTIAL:
+               case POSIX_FADV_WILLNEED:
+               case POSIX_FADV_NOREUSE:
+               case POSIX_FADV_DONTNEED:
+                       /* no bad return value, but ignore advice */
+                       break;
+               default:
+                       ret = -EINVAL;
+               }
                goto out;
+       }
 
        /* Careful about overflows. Len == 0 means "as much as possible" */
        endbyte = offset + len;
index f4d0cded0e10aa21b02707fcaf99c4cbcafa4f06..81fb9bff0d4f9022db02f9d3194ebc5ccd0c350e 100644 (file)
@@ -65,7 +65,6 @@ generic_file_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
  *    ->private_lock           (__free_pte->__set_page_dirty_buffers)
  *      ->swap_lock            (exclusive_swap_page, others)
  *        ->mapping->tree_lock
- *          ->zone.lock
  *
  *  ->i_mutex
  *    ->i_mmap_lock            (truncate->unmap_mapping_range)
@@ -185,6 +184,12 @@ static int sync_page(void *word)
        return 0;
 }
 
+static int sync_page_killable(void *word)
+{
+       sync_page(word);
+       return fatal_signal_pending(current) ? -EINTR : 0;
+}
+
 /**
  * __filemap_fdatawrite_range - start writeback on mapping dirty pages in range
  * @mapping:   address space structure to write
@@ -522,7 +527,7 @@ static inline void wake_up_page(struct page *page, int bit)
        __wake_up_bit(page_waitqueue(page), &page->flags, bit);
 }
 
-void fastcall wait_on_page_bit(struct page *page, int bit_nr)
+void wait_on_page_bit(struct page *page, int bit_nr)
 {
        DEFINE_WAIT_BIT(wait, &page->flags, bit_nr);
 
@@ -546,7 +551,7 @@ EXPORT_SYMBOL(wait_on_page_bit);
  * the clear_bit and the read of the waitqueue (to avoid SMP races with a
  * parallel wait_on_page_locked()).
  */
-void fastcall unlock_page(struct page *page)
+void unlock_page(struct page *page)
 {
        smp_mb__before_clear_bit();
        if (!TestClearPageLocked(page))
@@ -580,7 +585,7 @@ EXPORT_SYMBOL(end_page_writeback);
  * chances are that on the second loop, the block layer's plug list is empty,
  * so sync_page() will then return in state TASK_UNINTERRUPTIBLE.
  */
-void fastcall __lock_page(struct page *page)
+void __lock_page(struct page *page)
 {
        DEFINE_WAIT_BIT(wait, &page->flags, PG_locked);
 
@@ -589,11 +594,19 @@ void fastcall __lock_page(struct page *page)
 }
 EXPORT_SYMBOL(__lock_page);
 
+int fastcall __lock_page_killable(struct page *page)
+{
+       DEFINE_WAIT_BIT(wait, &page->flags, PG_locked);
+
+       return __wait_on_bit_lock(page_waitqueue(page), &wait,
+                                       sync_page_killable, TASK_KILLABLE);
+}
+
 /*
  * Variant of lock_page that does not require the caller to hold a reference
  * on the page's mapping.
  */
-void fastcall __lock_page_nosync(struct page *page)
+void __lock_page_nosync(struct page *page)
 {
        DEFINE_WAIT_BIT(wait, &page->flags, PG_locked);
        __wait_on_bit_lock(page_waitqueue(page), &wait, __sleep_on_page_lock,
@@ -980,7 +993,8 @@ page_ok:
 
 page_not_up_to_date:
                /* Get exclusive access to the page ... */
-               lock_page(page);
+               if (lock_page_killable(page))
+                       goto readpage_eio;
 
                /* Did it get truncated before we got the lock? */
                if (!page->mapping) {
@@ -1008,7 +1022,8 @@ readpage:
                }
 
                if (!PageUptodate(page)) {
-                       lock_page(page);
+                       if (lock_page_killable(page))
+                               goto readpage_eio;
                        if (!PageUptodate(page)) {
                                if (page->mapping == NULL) {
                                        /*
@@ -1019,15 +1034,16 @@ readpage:
                                        goto find_page;
                                }
                                unlock_page(page);
-                               error = -EIO;
                                shrink_readahead_size_eio(filp, ra);
-                               goto readpage_error;
+                               goto readpage_eio;
                        }
                        unlock_page(page);
                }
 
                goto page_ok;
 
+readpage_eio:
+               error = -EIO;
 readpage_error:
                /* UHHUH! A synchronous read error occurred. Report it */
                desc->error = error;
@@ -1260,7 +1276,7 @@ asmlinkage ssize_t sys_readahead(int fd, loff_t offset, size_t count)
  * This adds the requested page to the page cache if it isn't already there,
  * and schedules an I/O to read in its contents from disk.
  */
-static int fastcall page_cache_read(struct file * file, pgoff_t offset)
+static int page_cache_read(struct file *file, pgoff_t offset)
 {
        struct address_space *mapping = file->f_mapping;
        struct page *page; 
@@ -1733,7 +1749,11 @@ static void __iov_iter_advance_iov(struct iov_iter *i, size_t bytes)
                const struct iovec *iov = i->iov;
                size_t base = i->iov_offset;
 
-               while (bytes) {
+               /*
+                * The !iov->iov_len check ensures we skip over unlikely
+                * zero-length segments.
+                */
+               while (bytes || !iov->iov_len) {
                        int copy = min(bytes, iov->iov_len - base);
 
                        bytes -= copy;
@@ -2251,6 +2271,7 @@ again:
 
                cond_resched();
 
+               iov_iter_advance(i, copied);
                if (unlikely(copied == 0)) {
                        /*
                         * If we were unable to copy any data at all, we must
@@ -2264,7 +2285,6 @@ again:
                                                iov_iter_single_seg_count(i));
                        goto again;
                }
-               iov_iter_advance(i, copied);
                pos += copied;
                written += copied;
 
index f874ae818ad3812f7cd051972c823c743a154d33..0420a0292b0306425306b8db141b55b59f1010be 100644 (file)
@@ -431,7 +431,7 @@ xip_truncate_page(struct address_space *mapping, loff_t from)
                else
                        return PTR_ERR(page);
        }
-       zero_user_page(page, offset, length, KM_USER0);
+       zero_user(page, offset, length);
        return 0;
 }
 EXPORT_SYMBOL_GPL(xip_truncate_page);
index 14bd3bf7826edcecd2f61e6465b61078a84b2340..69a37c2bdf815ce5d7d14f90cca4c1185b65dff7 100644 (file)
@@ -190,10 +190,13 @@ asmlinkage long sys_remap_file_pages(unsigned long start, unsigned long size,
                 */
                if (mapping_cap_account_dirty(mapping)) {
                        unsigned long addr;
+                       struct file *file = vma->vm_file;
 
                        flags &= MAP_NONBLOCK;
-                       addr = mmap_region(vma->vm_file, start, size,
+                       get_file(file);
+                       addr = mmap_region(file, start, size,
                                        flags, vma->vm_flags, pgoff, 1);
+                       fput(file);
                        if (IS_ERR_VALUE(addr)) {
                                err = addr;
                        } else {
index 7a967bc351526d8f745fb2f3a9655a5151ed783f..35d47733cde43af70c61a996c78ef54ca5e20e02 100644 (file)
@@ -163,7 +163,7 @@ start:
        return vaddr;
 }
 
-void fastcall *kmap_high(struct page *page)
+void *kmap_high(struct page *page)
 {
        unsigned long vaddr;
 
@@ -185,7 +185,7 @@ void fastcall *kmap_high(struct page *page)
 
 EXPORT_SYMBOL(kmap_high);
 
-void fastcall kunmap_high(struct page *page)
+void kunmap_high(struct page *page)
 {
        unsigned long vaddr;
        unsigned long nr;
index db861d8b6c2824f460cc177f0d4008fd8850cc3e..1a5642074e342532f4a844ed0d2fdc86bd9b5de9 100644 (file)
@@ -813,6 +813,7 @@ static int hugetlb_cow(struct mm_struct *mm, struct vm_area_struct *vma,
 
        spin_unlock(&mm->page_table_lock);
        copy_huge_page(new_page, old_page, address, vma);
+       __SetPageUptodate(new_page);
        spin_lock(&mm->page_table_lock);
 
        ptep = huge_pte_offset(mm, address & HPAGE_MASK);
@@ -858,6 +859,7 @@ retry:
                        goto out;
                }
                clear_huge_page(page, address);
+               __SetPageUptodate(page);
 
                if (vma->vm_flags & VM_SHARED) {
                        int err;
index 953f941ea8676a6f1768257428e8f917e75d7a2c..5a9a6200e034fb43aad09efe34ac1b2e49825509 100644 (file)
@@ -24,7 +24,7 @@ static inline void set_page_count(struct page *page, int v)
  */
 static inline void set_page_refcounted(struct page *page)
 {
-       VM_BUG_ON(PageCompound(page) && PageTail(page));
+       VM_BUG_ON(PageTail(page));
        VM_BUG_ON(atomic_read(&page->_count));
        set_page_count(page, 1);
 }
@@ -34,7 +34,7 @@ static inline void __put_page(struct page *page)
        atomic_dec(&page->_count);
 }
 
-extern void fastcall __init __free_pages_bootmem(struct page *page,
+extern void __init __free_pages_bootmem(struct page *page,
                                                unsigned int order);
 
 /*
index d902d0e25edc564862605d2c8c93209602e797cc..7bb70728bb526f357deca4879f821038a2b9fd62 100644 (file)
@@ -305,7 +305,7 @@ int __pte_alloc(struct mm_struct *mm, pmd_t *pmd, unsigned long address)
        spin_lock(&mm->page_table_lock);
        if (pmd_present(*pmd)) {        /* Another has populated it */
                pte_lock_deinit(new);
-               pte_free(new);
+               pte_free(mm, new);
        } else {
                mm->nr_ptes++;
                inc_zone_page_state(new, NR_PAGETABLE);
@@ -323,7 +323,7 @@ int __pte_alloc_kernel(pmd_t *pmd, unsigned long address)
 
        spin_lock(&init_mm.page_table_lock);
        if (pmd_present(*pmd))          /* Another has populated it */
-               pte_free_kernel(new);
+               pte_free_kernel(&init_mm, new);
        else
                pmd_populate_kernel(&init_mm, pmd, new);
        spin_unlock(&init_mm.page_table_lock);
@@ -1109,7 +1109,8 @@ int get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
 }
 EXPORT_SYMBOL(get_user_pages);
 
-pte_t * fastcall get_locked_pte(struct mm_struct *mm, unsigned long addr, spinlock_t **ptl)
+pte_t *get_locked_pte(struct mm_struct *mm, unsigned long addr,
+                       spinlock_t **ptl)
 {
        pgd_t * pgd = pgd_offset(mm, addr);
        pud_t * pud = pud_alloc(mm, pgd, addr);
@@ -1517,10 +1518,8 @@ static inline void cow_user_page(struct page *dst, struct page *src, unsigned lo
                        memset(kaddr, 0, PAGE_SIZE);
                kunmap_atomic(kaddr, KM_USER0);
                flush_dcache_page(dst);
-               return;
-
-       }
-       copy_user_highpage(dst, src, va, vma);
+       } else
+               copy_user_highpage(dst, src, va, vma);
 }
 
 /*
@@ -1629,6 +1628,7 @@ gotten:
        if (!new_page)
                goto oom;
        cow_user_page(new_page, old_page, address, vma);
+       __SetPageUptodate(new_page);
 
        /*
         * Re-check the pte - we dropped the lock
@@ -1909,50 +1909,49 @@ EXPORT_SYMBOL(unmap_mapping_range);
  */
 int vmtruncate(struct inode * inode, loff_t offset)
 {
-       struct address_space *mapping = inode->i_mapping;
-       unsigned long limit;
+       if (inode->i_size < offset) {
+               unsigned long limit;
 
-       if (inode->i_size < offset)
-               goto do_expand;
-       /*
-        * truncation of in-use swapfiles is disallowed - it would cause
-        * subsequent swapout to scribble on the now-freed blocks.
-        */
-       if (IS_SWAPFILE(inode))
-               goto out_busy;
-       i_size_write(inode, offset);
+               limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur;
+               if (limit != RLIM_INFINITY && offset > limit)
+                       goto out_sig;
+               if (offset > inode->i_sb->s_maxbytes)
+                       goto out_big;
+               i_size_write(inode, offset);
+       } else {
+               struct address_space *mapping = inode->i_mapping;
+
+               /*
+                * truncation of in-use swapfiles is disallowed - it would
+                * cause subsequent swapout to scribble on the now-freed
+                * blocks.
+                */
+               if (IS_SWAPFILE(inode))
+                       return -ETXTBSY;
+               i_size_write(inode, offset);
+
+               /*
+                * unmap_mapping_range is called twice, first simply for
+                * efficiency so that truncate_inode_pages does fewer
+                * single-page unmaps.  However after this first call, and
+                * before truncate_inode_pages finishes, it is possible for
+                * private pages to be COWed, which remain after
+                * truncate_inode_pages finishes, hence the second
+                * unmap_mapping_range call must be made for correctness.
+                */
+               unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1);
+               truncate_inode_pages(mapping, offset);
+               unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1);
+       }
 
-       /*
-        * unmap_mapping_range is called twice, first simply for efficiency
-        * so that truncate_inode_pages does fewer single-page unmaps. However
-        * after this first call, and before truncate_inode_pages finishes,
-        * it is possible for private pages to be COWed, which remain after
-        * truncate_inode_pages finishes, hence the second unmap_mapping_range
-        * call must be made for correctness.
-        */
-       unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1);
-       truncate_inode_pages(mapping, offset);
-       unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1);
-       goto out_truncate;
-
-do_expand:
-       limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur;
-       if (limit != RLIM_INFINITY && offset > limit)
-               goto out_sig;
-       if (offset > inode->i_sb->s_maxbytes)
-               goto out_big;
-       i_size_write(inode, offset);
-
-out_truncate:
        if (inode->i_op && inode->i_op->truncate)
                inode->i_op->truncate(inode);
        return 0;
+
 out_sig:
        send_sig(SIGXFSZ, current, 0);
 out_big:
        return -EFBIG;
-out_busy:
-       return -ETXTBSY;
 }
 EXPORT_SYMBOL(vmtruncate);
 
@@ -1980,67 +1979,6 @@ int vmtruncate_range(struct inode *inode, loff_t offset, loff_t end)
        return 0;
 }
 
-/**
- * swapin_readahead - swap in pages in hope we need them soon
- * @entry: swap entry of this memory
- * @addr: address to start
- * @vma: user vma this addresses belong to
- *
- * Primitive swap readahead code. We simply read an aligned block of
- * (1 << page_cluster) entries in the swap area. This method is chosen
- * because it doesn't cost us any seek time.  We also make sure to queue
- * the 'original' request together with the readahead ones...
- *
- * This has been extended to use the NUMA policies from the mm triggering
- * the readahead.
- *
- * Caller must hold down_read on the vma->vm_mm if vma is not NULL.
- */
-void swapin_readahead(swp_entry_t entry, unsigned long addr,struct vm_area_struct *vma)
-{
-#ifdef CONFIG_NUMA
-       struct vm_area_struct *next_vma = vma ? vma->vm_next : NULL;
-#endif
-       int i, num;
-       struct page *new_page;
-       unsigned long offset;
-
-       /*
-        * Get the number of handles we should do readahead io to.
-        */
-       num = valid_swaphandles(entry, &offset);
-       for (i = 0; i < num; offset++, i++) {
-               /* Ok, do the async read-ahead now */
-               new_page = read_swap_cache_async(swp_entry(swp_type(entry),
-                                                          offset), vma, addr);
-               if (!new_page)
-                       break;
-               page_cache_release(new_page);
-#ifdef CONFIG_NUMA
-               /*
-                * Find the next applicable VMA for the NUMA policy.
-                */
-               addr += PAGE_SIZE;
-               if (addr == 0)
-                       vma = NULL;
-               if (vma) {
-                       if (addr >= vma->vm_end) {
-                               vma = next_vma;
-                               next_vma = vma ? vma->vm_next : NULL;
-                       }
-                       if (vma && addr < vma->vm_start)
-                               vma = NULL;
-               } else {
-                       if (next_vma && addr >= next_vma->vm_start) {
-                               vma = next_vma;
-                               next_vma = vma->vm_next;
-                       }
-               }
-#endif
-       }
-       lru_add_drain();        /* Push any new pages onto the LRU now */
-}
-
 /*
  * We enter with non-exclusive mmap_sem (to exclude vma changes,
  * but allow concurrent faults), and pte mapped but not yet locked.
@@ -2068,8 +2006,8 @@ static int do_swap_page(struct mm_struct *mm, struct vm_area_struct *vma,
        page = lookup_swap_cache(entry);
        if (!page) {
                grab_swap_token(); /* Contend for token _before_ read-in */
-               swapin_readahead(entry, address, vma);
-               page = read_swap_cache_async(entry, vma, address);
+               page = swapin_readahead(entry,
+                                       GFP_HIGHUSER_MOVABLE, vma, address);
                if (!page) {
                        /*
                         * Back out if somebody else faulted in this pte
@@ -2163,6 +2101,7 @@ static int do_anonymous_page(struct mm_struct *mm, struct vm_area_struct *vma,
        page = alloc_zeroed_user_highpage_movable(vma, address);
        if (!page)
                goto oom;
+       __SetPageUptodate(page);
 
        entry = mk_pte(page, vma->vm_page_prot);
        entry = maybe_mkwrite(pte_mkdirty(entry), vma);
@@ -2263,6 +2202,7 @@ static int __do_fault(struct mm_struct *mm, struct vm_area_struct *vma,
                                goto out;
                        }
                        copy_user_highpage(page, vmf.page, address, vma);
+                       __SetPageUptodate(page);
                } else {
                        /*
                         * If the page will be shareable, see if the backing
@@ -2563,7 +2503,7 @@ int __pud_alloc(struct mm_struct *mm, pgd_t *pgd, unsigned long address)
 
        spin_lock(&mm->page_table_lock);
        if (pgd_present(*pgd))          /* Another has populated it */
-               pud_free(new);
+               pud_free(mm, new);
        else
                pgd_populate(mm, pgd, new);
        spin_unlock(&mm->page_table_lock);
@@ -2585,12 +2525,12 @@ int __pmd_alloc(struct mm_struct *mm, pud_t *pud, unsigned long address)
        spin_lock(&mm->page_table_lock);
 #ifndef __ARCH_HAS_4LEVEL_HACK
        if (pud_present(*pud))          /* Another has populated it */
-               pmd_free(new);
+               pmd_free(mm, new);
        else
                pud_populate(mm, pud, new);
 #else
        if (pgd_present(*pud))          /* Another has populated it */
-               pmd_free(new);
+               pmd_free(mm, new);
        else
                pgd_populate(mm, pud, new);
 #endif /* __ARCH_HAS_4LEVEL_HACK */
@@ -2618,46 +2558,6 @@ int make_pages_present(unsigned long addr, unsigned long end)
        return ret == len ? 0 : -1;
 }
 
-/* 
- * Map a vmalloc()-space virtual address to the physical page.
- */
-struct page * vmalloc_to_page(void * vmalloc_addr)
-{
-       unsigned long addr = (unsigned long) vmalloc_addr;
-       struct page *page = NULL;
-       pgd_t *pgd = pgd_offset_k(addr);
-       pud_t *pud;
-       pmd_t *pmd;
-       pte_t *ptep, pte;
-  
-       if (!pgd_none(*pgd)) {
-               pud = pud_offset(pgd, addr);
-               if (!pud_none(*pud)) {
-                       pmd = pmd_offset(pud, addr);
-                       if (!pmd_none(*pmd)) {
-                               ptep = pte_offset_map(pmd, addr);
-                               pte = *ptep;
-                               if (pte_present(pte))
-                                       page = pte_page(pte);
-                               pte_unmap(ptep);
-                       }
-               }
-       }
-       return page;
-}
-
-EXPORT_SYMBOL(vmalloc_to_page);
-
-/*
- * Map a vmalloc()-space virtual address to the physical page frame number.
- */
-unsigned long vmalloc_to_pfn(void * vmalloc_addr)
-{
-       return page_to_pfn(vmalloc_to_page(vmalloc_addr));
-}
-
-EXPORT_SYMBOL(vmalloc_to_pfn);
-
 #if !defined(__HAVE_ARCH_GATE_AREA)
 
 #if defined(AT_SYSINFO_EHDR)
index 9512a544d0449ebcb789de665d9e8fc8ee0fdc8b..7469c503580dcf6402000cc339359175a9b417fc 100644 (file)
@@ -481,8 +481,6 @@ check_pages_isolated(unsigned long start_pfn, unsigned long end_pfn)
        return offlined;
 }
 
-extern void drain_all_local_pages(void);
-
 int offline_pages(unsigned long start_pfn,
                  unsigned long end_pfn, unsigned long timeout)
 {
@@ -540,7 +538,7 @@ repeat:
                lru_add_drain_all();
                flush_scheduled_work();
                cond_resched();
-               drain_all_local_pages();
+               drain_all_pages();
        }
 
        pfn = scan_lru_pages(start_pfn, end_pfn);
@@ -563,7 +561,7 @@ repeat:
        flush_scheduled_work();
        yield();
        /* drain pcp pages , this is synchrouns. */
-       drain_all_local_pages();
+       drain_all_pages();
        /* check again */
        offlined_pages = check_pages_isolated(start_pfn, end_pfn);
        if (offlined_pages < 0) {
index 6a207e8d17ea3f74f0e20511fc726fe80ac47fb1..857a987e36904a5850a4d663c6d9e41e494ffe1f 100644 (file)
@@ -115,11 +115,6 @@ int putback_lru_pages(struct list_head *l)
        return count;
 }
 
-static inline int is_swap_pte(pte_t pte)
-{
-       return !pte_none(pte) && !pte_present(pte) && !pte_file(pte);
-}
-
 /*
  * Restore a potential migration pte to a working pte entry
  */
@@ -645,15 +640,33 @@ static int unmap_and_move(new_page_t get_new_page, unsigned long private,
                rcu_read_lock();
                rcu_locked = 1;
        }
+
        /*
-        * This is a corner case handling.
-        * When a new swap-cache is read into, it is linked to LRU
-        * and treated as swapcache but has no rmap yet.
-        * Calling try_to_unmap() against a page->mapping==NULL page is
-        * BUG. So handle it here.
+        * Corner case handling:
+        * 1. When a new swap-cache page is read into, it is added to the LRU
+        * and treated as swapcache but it has no rmap yet.
+        * Calling try_to_unmap() against a page->mapping==NULL page will
+        * trigger a BUG.  So handle it here.
+        * 2. An orphaned page (see truncate_complete_page) might have
+        * fs-private metadata. The page can be picked up due to memory
+        * offlining.  Everywhere else except page reclaim, the page is
+        * invisible to the vm, so the page can not be migrated.  So try to
+        * free the metadata, so the page can be freed.
         */
-       if (!page->mapping)
+       if (!page->mapping) {
+               if (!PageAnon(page) && PagePrivate(page)) {
+                       /*
+                        * Go direct to try_to_free_buffers() here because
+                        * a) that's what try_to_release_page() would do anyway
+                        * b) we may be under rcu_read_lock() here, so we can't
+                        *    use GFP_KERNEL which is what try_to_release_page()
+                        *    needs to be effective.
+                        */
+                       try_to_free_buffers(page);
+               }
                goto rcu_unlock;
+       }
+
        /* Establish migration ptes or remove ptes */
        try_to_unmap(page, 1);
 
index d2b6d44962b7c7b28b89e20cdbf1af0b0c6ada31..bb4c963cc5347f695de8a060336e877278bbed81 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
 #define arch_mmap_check(addr, len, flags)      (0)
 #endif
 
+#ifndef arch_rebalance_pgtables
+#define arch_rebalance_pgtables(addr, len)             (addr)
+#endif
+
 static void unmap_region(struct mm_struct *mm,
                struct vm_area_struct *vma, struct vm_area_struct *prev,
                unsigned long start, unsigned long end);
@@ -1424,7 +1428,7 @@ get_unmapped_area(struct file *file, unsigned long addr, unsigned long len,
        if (addr & ~PAGE_MASK)
                return -EINVAL;
 
-       return addr;
+       return arch_rebalance_pgtables(addr, len);
 }
 
 EXPORT_SYMBOL(get_unmapped_area);
@@ -2216,7 +2220,7 @@ int install_special_mapping(struct mm_struct *mm,
        vma->vm_start = addr;
        vma->vm_end = addr + len;
 
-       vma->vm_flags = vm_flags | mm->def_flags;
+       vma->vm_flags = vm_flags | mm->def_flags | VM_DONTEXPAND;
        vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);
 
        vma->vm_ops = &special_mapping_vmops;
index b989cb928a7cf29ec5ad66ff519f80633bfe8129..5d8ae086f74e541a6e526288e072e87b665484ab 100644 (file)
@@ -10,6 +10,7 @@
  *  Copyright (c) 2000-2003 David McCullough <davidm@snapgear.com>
  *  Copyright (c) 2000-2001 D Jeff Dionne <jeff@uClinux.org>
  *  Copyright (c) 2002      Greg Ungerer <gerg@snapgear.com>
+ *  Copyright (c) 2007      Paul Mundt <lethal@linux-sh.org>
  */
 
 #include <linux/module.h>
@@ -167,7 +168,7 @@ EXPORT_SYMBOL(get_user_pages);
 DEFINE_RWLOCK(vmlist_lock);
 struct vm_struct *vmlist;
 
-void vfree(void *addr)
+void vfree(const void *addr)
 {
        kfree(addr);
 }
@@ -183,13 +184,33 @@ void *__vmalloc(unsigned long size, gfp_t gfp_mask, pgprot_t prot)
 }
 EXPORT_SYMBOL(__vmalloc);
 
-struct page * vmalloc_to_page(void *addr)
+void *vmalloc_user(unsigned long size)
+{
+       void *ret;
+
+       ret = __vmalloc(size, GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO,
+                       PAGE_KERNEL);
+       if (ret) {
+               struct vm_area_struct *vma;
+
+               down_write(&current->mm->mmap_sem);
+               vma = find_vma(current->mm, (unsigned long)ret);
+               if (vma)
+                       vma->vm_flags |= VM_USERMAP;
+               up_write(&current->mm->mmap_sem);
+       }
+
+       return ret;
+}
+EXPORT_SYMBOL(vmalloc_user);
+
+struct page *vmalloc_to_page(const void *addr)
 {
        return virt_to_page(addr);
 }
 EXPORT_SYMBOL(vmalloc_to_page);
 
-unsigned long vmalloc_to_pfn(void *addr)
+unsigned long vmalloc_to_pfn(const void *addr)
 {
        return page_to_pfn(virt_to_page(addr));
 }
@@ -253,10 +274,17 @@ EXPORT_SYMBOL(vmalloc_32);
  *
  * The resulting memory area is 32bit addressable and zeroed so it can be
  * mapped to userspace without leaking data.
+ *
+ * VM_USERMAP is set on the corresponding VMA so that subsequent calls to
+ * remap_vmalloc_range() are permissible.
  */
 void *vmalloc_32_user(unsigned long size)
 {
-       return __vmalloc(size, GFP_KERNEL | __GFP_ZERO, PAGE_KERNEL);
+       /*
+        * We'll have to sort out the ZONE_DMA bits for 64-bit,
+        * but for now this can simply use vmalloc_user() directly.
+        */
+       return vmalloc_user(size);
 }
 EXPORT_SYMBOL(vmalloc_32_user);
 
@@ -267,7 +295,7 @@ void *vmap(struct page **pages, unsigned int count, unsigned long flags, pgprot_
 }
 EXPORT_SYMBOL(vmap);
 
-void vunmap(void *addr)
+void vunmap(const void *addr)
 {
        BUG();
 }
@@ -1216,6 +1244,21 @@ int remap_pfn_range(struct vm_area_struct *vma, unsigned long from,
 }
 EXPORT_SYMBOL(remap_pfn_range);
 
+int remap_vmalloc_range(struct vm_area_struct *vma, void *addr,
+                       unsigned long pgoff)
+{
+       unsigned int size = vma->vm_end - vma->vm_start;
+
+       if (!(vma->vm_flags & VM_USERMAP))
+               return -EINVAL;
+
+       vma->vm_start = (unsigned long)(addr + (pgoff << PAGE_SHIFT));
+       vma->vm_end = vma->vm_start + size;
+
+       return 0;
+}
+EXPORT_SYMBOL(remap_vmalloc_range);
+
 void swap_unplug_io_fn(struct backing_dev_info *bdi, struct page *page)
 {
 }
index 96473b482099793384af969b8158e1306e2d4f58..c1850bf991cda9794f6985a7f6ebf595c6adac87 100644 (file)
@@ -125,8 +125,7 @@ unsigned long badness(struct task_struct *p, unsigned long uptime)
         * Superuser processes are usually more important, so we make it
         * less likely that we kill those.
         */
-       if (cap_t(p->cap_effective) & CAP_TO_MASK(CAP_SYS_ADMIN) ||
-                               p->uid == 0 || p->euid == 0)
+       if (__capable(p, CAP_SYS_ADMIN) || __capable(p, CAP_SYS_RESOURCE))
                points /= 4;
 
        /*
@@ -135,7 +134,7 @@ unsigned long badness(struct task_struct *p, unsigned long uptime)
         * tend to only have this flag set on applications they think
         * of as important.
         */
-       if (cap_t(p->cap_effective) & CAP_TO_MASK(CAP_SYS_RAWIO))
+       if (__capable(p, CAP_SYS_RAWIO))
                points /= 4;
 
        /*
index 3d3848fa6324ee30c8bfa4f39ac867808af84627..5e00f1772c20fc6d9e4e70a087800e93b3ae3df2 100644 (file)
@@ -68,6 +68,12 @@ static inline long sync_writeback_pages(void)
  */
 int dirty_background_ratio = 5;
 
+/*
+ * free highmem will not be subtracted from the total free memory
+ * for calculating free ratios if vm_highmem_is_dirtyable is true
+ */
+int vm_highmem_is_dirtyable;
+
 /*
  * The generator of dirty data starts writeback at this percentage
  */
@@ -219,7 +225,7 @@ static inline void task_dirties_fraction(struct task_struct *tsk,
  *
  *   dirty -= (dirty/8) * p_{t}
  */
-void task_dirty_limit(struct task_struct *tsk, long *pdirty)
+static void task_dirty_limit(struct task_struct *tsk, long *pdirty)
 {
        long numerator, denominator;
        long dirty = *pdirty;
@@ -287,7 +293,10 @@ static unsigned long determine_dirtyable_memory(void)
        x = global_page_state(NR_FREE_PAGES)
                + global_page_state(NR_INACTIVE)
                + global_page_state(NR_ACTIVE);
-       x -= highmem_dirtyable_memory(x);
+
+       if (!vm_highmem_is_dirtyable)
+               x -= highmem_dirtyable_memory(x);
+
        return x + 1;   /* Ensure that we never return 0 */
 }
 
@@ -558,6 +567,7 @@ static void background_writeout(unsigned long _min_pages)
                        global_page_state(NR_UNSTABLE_NFS) < background_thresh
                                && min_pages <= 0)
                        break;
+               wbc.more_io = 0;
                wbc.encountered_congestion = 0;
                wbc.nr_to_write = MAX_WRITEBACK_PAGES;
                wbc.pages_skipped = 0;
@@ -565,8 +575,9 @@ static void background_writeout(unsigned long _min_pages)
                min_pages -= MAX_WRITEBACK_PAGES - wbc.nr_to_write;
                if (wbc.nr_to_write > 0 || wbc.pages_skipped > 0) {
                        /* Wrote less than expected */
-                       congestion_wait(WRITE, HZ/10);
-                       if (!wbc.encountered_congestion)
+                       if (wbc.encountered_congestion || wbc.more_io)
+                               congestion_wait(WRITE, HZ/10);
+                       else
                                break;
                }
        }
@@ -631,11 +642,12 @@ static void wb_kupdate(unsigned long arg)
                        global_page_state(NR_UNSTABLE_NFS) +
                        (inodes_stat.nr_inodes - inodes_stat.nr_unused);
        while (nr_to_write > 0) {
+               wbc.more_io = 0;
                wbc.encountered_congestion = 0;
                wbc.nr_to_write = MAX_WRITEBACK_PAGES;
                writeback_inodes(&wbc);
                if (wbc.nr_to_write > 0) {
-                       if (wbc.encountered_congestion)
+                       if (wbc.encountered_congestion || wbc.more_io)
                                congestion_wait(WRITE, HZ/10);
                        else
                                break;  /* All the old data is written */
@@ -1064,7 +1076,7 @@ static int __set_page_dirty(struct page *page)
        return 0;
 }
 
-int fastcall set_page_dirty(struct page *page)
+int set_page_dirty(struct page *page)
 {
        int ret = __set_page_dirty(page);
        if (ret)
index b2838c24e582c11b8e0680ca5d5b5f97389145ba..37576b822f06c98c2d3342af1cdecbe0e5a8f25b 100644 (file)
@@ -537,7 +537,7 @@ static void __free_pages_ok(struct page *page, unsigned int order)
 /*
  * permit the bootmem allocator to evade page validation on high-order frees
  */
-void fastcall __init __free_pages_bootmem(struct page *page, unsigned int order)
+void __init __free_pages_bootmem(struct page *page, unsigned int order)
 {
        if (order == 0) {
                __ClearPageReserved(page);
@@ -890,31 +890,51 @@ void drain_zone_pages(struct zone *zone, struct per_cpu_pages *pcp)
 }
 #endif
 
-static void __drain_pages(unsigned int cpu)
+/*
+ * Drain pages of the indicated processor.
+ *
+ * The processor must either be the current processor and the
+ * thread pinned to the current processor or a processor that
+ * is not online.
+ */
+static void drain_pages(unsigned int cpu)
 {
        unsigned long flags;
        struct zone *zone;
-       int i;
 
        for_each_zone(zone) {
                struct per_cpu_pageset *pset;
+               struct per_cpu_pages *pcp;
 
                if (!populated_zone(zone))
                        continue;
 
                pset = zone_pcp(zone, cpu);
-               for (i = 0; i < ARRAY_SIZE(pset->pcp); i++) {
-                       struct per_cpu_pages *pcp;
-
-                       pcp = &pset->pcp[i];
-                       local_irq_save(flags);
-                       free_pages_bulk(zone, pcp->count, &pcp->list, 0);
-                       pcp->count = 0;
-                       local_irq_restore(flags);
-               }
+
+               pcp = &pset->pcp;
+               local_irq_save(flags);
+               free_pages_bulk(zone, pcp->count, &pcp->list, 0);
+               pcp->count = 0;
+               local_irq_restore(flags);
        }
 }
 
+/*
+ * Spill all of this CPU's per-cpu pages back into the buddy allocator.
+ */
+void drain_local_pages(void *arg)
+{
+       drain_pages(smp_processor_id());
+}
+
+/*
+ * Spill all the per-cpu pages from all CPUs back into the buddy allocator
+ */
+void drain_all_pages(void)
+{
+       on_each_cpu(drain_local_pages, NULL, 0, 1);
+}
+
 #ifdef CONFIG_HIBERNATION
 
 void mark_free_pages(struct zone *zone)
@@ -951,41 +971,10 @@ void mark_free_pages(struct zone *zone)
 }
 #endif /* CONFIG_PM */
 
-/*
- * Spill all of this CPU's per-cpu pages back into the buddy allocator.
- */
-void drain_local_pages(void)
-{
-       unsigned long flags;
-
-       local_irq_save(flags);  
-       __drain_pages(smp_processor_id());
-       local_irq_restore(flags);       
-}
-
-void smp_drain_local_pages(void *arg)
-{
-       drain_local_pages();
-}
-
-/*
- * Spill all the per-cpu pages from all CPUs back into the buddy allocator
- */
-void drain_all_local_pages(void)
-{
-       unsigned long flags;
-
-       local_irq_save(flags);
-       __drain_pages(smp_processor_id());
-       local_irq_restore(flags);
-
-       smp_call_function(smp_drain_local_pages, NULL, 0, 1);
-}
-
 /*
  * Free a 0-order page
  */
-static void fastcall free_hot_cold_page(struct page *page, int cold)
+static void free_hot_cold_page(struct page *page, int cold)
 {
        struct zone *zone = page_zone(page);
        struct per_cpu_pages *pcp;
@@ -1001,10 +990,13 @@ static void fastcall free_hot_cold_page(struct page *page, int cold)
        arch_free_page(page, 0);
        kernel_map_pages(page, 1, 0);
 
-       pcp = &zone_pcp(zone, get_cpu())->pcp[cold];
+       pcp = &zone_pcp(zone, get_cpu())->pcp;
        local_irq_save(flags);
        __count_vm_event(PGFREE);
-       list_add(&page->lru, &pcp->list);
+       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) {
@@ -1015,12 +1007,12 @@ static void fastcall free_hot_cold_page(struct page *page, int cold)
        put_cpu();
 }
 
-void fastcall free_hot_page(struct page *page)
+void free_hot_page(struct page *page)
 {
        free_hot_cold_page(page, 0);
 }
        
-void fastcall free_cold_page(struct page *page)
+void free_cold_page(struct page *page)
 {
        free_hot_cold_page(page, 1);
 }
@@ -1062,7 +1054,7 @@ again:
        if (likely(order == 0)) {
                struct per_cpu_pages *pcp;
 
-               pcp = &zone_pcp(zone, cpu)->pcp[cold];
+               pcp = &zone_pcp(zone, cpu)->pcp;
                local_irq_save(flags);
                if (!pcp->count) {
                        pcp->count = rmqueue_bulk(zone, 0,
@@ -1072,9 +1064,15 @@ again:
                }
 
                /* Find a page of the appropriate migrate type */
-               list_for_each_entry(page, &pcp->list, lru)
-                       if (page_private(page) == migratetype)
-                               break;
+               if (cold) {
+                       list_for_each_entry_reverse(page, &pcp->list, lru)
+                               if (page_private(page) == migratetype)
+                                       break;
+               } else {
+                       list_for_each_entry(page, &pcp->list, lru)
+                               if (page_private(page) == migratetype)
+                                       break;
+               }
 
                /* Allocate more to the pcp list if necessary */
                if (unlikely(&page->lru == &pcp->list)) {
@@ -1569,7 +1567,7 @@ nofail_alloc:
        cond_resched();
 
        if (order != 0)
-               drain_all_local_pages();
+               drain_all_pages();
 
        if (likely(did_some_progress)) {
                page = get_page_from_freelist(gfp_mask, order,
@@ -1643,7 +1641,7 @@ EXPORT_SYMBOL(__alloc_pages);
 /*
  * Common helper functions.
  */
-fastcall unsigned long __get_free_pages(gfp_t gfp_mask, unsigned int order)
+unsigned long __get_free_pages(gfp_t gfp_mask, unsigned int order)
 {
        struct page * page;
        page = alloc_pages(gfp_mask, order);
@@ -1654,7 +1652,7 @@ fastcall unsigned long __get_free_pages(gfp_t gfp_mask, unsigned int order)
 
 EXPORT_SYMBOL(__get_free_pages);
 
-fastcall unsigned long get_zeroed_page(gfp_t gfp_mask)
+unsigned long get_zeroed_page(gfp_t gfp_mask)
 {
        struct page * page;
 
@@ -1680,7 +1678,7 @@ void __pagevec_free(struct pagevec *pvec)
                free_hot_cold_page(pvec->pages[i], pvec->cold);
 }
 
-fastcall void __free_pages(struct page *page, unsigned int order)
+void __free_pages(struct page *page, unsigned int order)
 {
        if (put_page_testzero(page)) {
                if (order == 0)
@@ -1692,7 +1690,7 @@ fastcall void __free_pages(struct page *page, unsigned int order)
 
 EXPORT_SYMBOL(__free_pages);
 
-fastcall void free_pages(unsigned long addr, unsigned int order)
+void free_pages(unsigned long addr, unsigned int order)
 {
        if (addr != 0) {
                VM_BUG_ON(!virt_addr_valid((void *)addr));
@@ -1801,12 +1799,9 @@ void show_free_areas(void)
 
                        pageset = zone_pcp(zone, cpu);
 
-                       printk("CPU %4d: Hot: hi:%5d, btch:%4d usd:%4d   "
-                              "Cold: hi:%5d, btch:%4d usd:%4d\n",
-                              cpu, pageset->pcp[0].high,
-                              pageset->pcp[0].batch, pageset->pcp[0].count,
-                              pageset->pcp[1].high, pageset->pcp[1].batch,
-                              pageset->pcp[1].count);
+                       printk("CPU %4d: hi:%5d, btch:%4d usd:%4d\n",
+                              cpu, pageset->pcp.high,
+                              pageset->pcp.batch, pageset->pcp.count);
                }
        }
 
@@ -1879,6 +1874,8 @@ void show_free_areas(void)
                printk("= %lukB\n", K(total));
        }
 
+       printk("%ld total pagecache pages\n", global_page_state(NR_FILE_PAGES));
+
        show_swap_cache_info();
 }
 
@@ -2551,8 +2548,7 @@ void __meminit memmap_init_zone(unsigned long size, int nid, unsigned long zone,
        }
 }
 
-static void __meminit zone_init_free_lists(struct pglist_data *pgdat,
-                               struct zone *zone, unsigned long size)
+static void __meminit zone_init_free_lists(struct zone *zone)
 {
        int order, t;
        for_each_migratetype_order(order, t) {
@@ -2604,17 +2600,11 @@ inline void setup_pageset(struct per_cpu_pageset *p, unsigned long batch)
 
        memset(p, 0, sizeof(*p));
 
-       pcp = &p->pcp[0];               /* hot */
+       pcp = &p->pcp;
        pcp->count = 0;
        pcp->high = 6 * batch;
        pcp->batch = max(1UL, 1 * batch);
        INIT_LIST_HEAD(&pcp->list);
-
-       pcp = &p->pcp[1];               /* cold*/
-       pcp->count = 0;
-       pcp->high = 2 * batch;
-       pcp->batch = max(1UL, batch/2);
-       INIT_LIST_HEAD(&pcp->list);
 }
 
 /*
@@ -2627,7 +2617,7 @@ static void setup_pagelist_highmark(struct per_cpu_pageset *p,
 {
        struct per_cpu_pages *pcp;
 
-       pcp = &p->pcp[0]; /* hot list */
+       pcp = &p->pcp;
        pcp->high = high;
        pcp->batch = max(1UL, high/4);
        if ((high/4) > (PAGE_SHIFT * 8))
@@ -2831,7 +2821,7 @@ __meminit int init_currently_empty_zone(struct zone *zone,
 
        memmap_init(size, pgdat->node_id, zone_idx(zone), zone_start_pfn);
 
-       zone_init_free_lists(pgdat, zone, zone->spanned_pages);
+       zone_init_free_lists(zone);
 
        return 0;
 }
@@ -3978,10 +3968,23 @@ static int page_alloc_cpu_notify(struct notifier_block *self,
        int cpu = (unsigned long)hcpu;
 
        if (action == CPU_DEAD || action == CPU_DEAD_FROZEN) {
-               local_irq_disable();
-               __drain_pages(cpu);
+               drain_pages(cpu);
+
+               /*
+                * Spill the event counters of the dead processor
+                * into the current processors event counters.
+                * This artificially elevates the count of the current
+                * processor.
+                */
                vm_events_fold_cpu(cpu);
-               local_irq_enable();
+
+               /*
+                * Zero the differential counters of the dead processor
+                * so that the vm statistics are consistent.
+                *
+                * This is only okay since the processor is dead and cannot
+                * race with what we are doing.
+                */
                refresh_cpu_vm_stats(cpu);
        }
        return NOTIFY_OK;
@@ -4480,7 +4483,7 @@ int set_migratetype_isolate(struct page *page)
 out:
        spin_unlock_irqrestore(&zone->lock, flags);
        if (!ret)
-               drain_all_local_pages();
+               drain_all_pages();
        return ret;
 }
 
index 3b97f68502733edba06e5697d56ecfeb7643b8c1..065c4480eaf0905c8631732540a118c002989f09 100644 (file)
@@ -126,7 +126,7 @@ int swap_readpage(struct file *file, struct page *page)
        int ret = 0;
 
        BUG_ON(!PageLocked(page));
-       ClearPageUptodate(page);
+       BUG_ON(PageUptodate(page));
        bio = get_swap_bio(GFP_KERNEL, page_private(page), page,
                                end_swap_bio_read);
        if (bio == NULL) {
diff --git a/mm/pagewalk.c b/mm/pagewalk.c
new file mode 100644 (file)
index 0000000..b4f27d2
--- /dev/null
@@ -0,0 +1,131 @@
+#include <linux/mm.h>
+#include <linux/highmem.h>
+#include <linux/sched.h>
+
+static int walk_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end,
+                         const struct mm_walk *walk, void *private)
+{
+       pte_t *pte;
+       int err = 0;
+
+       pte = pte_offset_map(pmd, addr);
+       do {
+               err = walk->pte_entry(pte, addr, addr + PAGE_SIZE, private);
+               if (err)
+                      break;
+       } while (pte++, addr += PAGE_SIZE, addr != end);
+
+       pte_unmap(pte);
+       return err;
+}
+
+static int walk_pmd_range(pud_t *pud, unsigned long addr, unsigned long end,
+                         const struct mm_walk *walk, void *private)
+{
+       pmd_t *pmd;
+       unsigned long next;
+       int err = 0;
+
+       pmd = pmd_offset(pud, addr);
+       do {
+               next = pmd_addr_end(addr, end);
+               if (pmd_none_or_clear_bad(pmd)) {
+                       if (walk->pte_hole)
+                               err = walk->pte_hole(addr, next, private);
+                       if (err)
+                               break;
+                       continue;
+               }
+               if (walk->pmd_entry)
+                       err = walk->pmd_entry(pmd, addr, next, private);
+               if (!err && walk->pte_entry)
+                       err = walk_pte_range(pmd, addr, next, walk, private);
+               if (err)
+                       break;
+       } while (pmd++, addr = next, addr != end);
+
+       return err;
+}
+
+static int walk_pud_range(pgd_t *pgd, unsigned long addr, unsigned long end,
+                         const struct mm_walk *walk, void *private)
+{
+       pud_t *pud;
+       unsigned long next;
+       int err = 0;
+
+       pud = pud_offset(pgd, addr);
+       do {
+               next = pud_addr_end(addr, end);
+               if (pud_none_or_clear_bad(pud)) {
+                       if (walk->pte_hole)
+                               err = walk->pte_hole(addr, next, private);
+                       if (err)
+                               break;
+                       continue;
+               }
+               if (walk->pud_entry)
+                       err = walk->pud_entry(pud, addr, next, private);
+               if (!err && (walk->pmd_entry || walk->pte_entry))
+                       err = walk_pmd_range(pud, addr, next, walk, private);
+               if (err)
+                       break;
+       } while (pud++, addr = next, addr != end);
+
+       return err;
+}
+
+/**
+ * walk_page_range - walk a memory map's page tables with a callback
+ * @mm - memory map to walk
+ * @addr - starting address
+ * @end - ending address
+ * @walk - set of callbacks to invoke for each level of the tree
+ * @private - private data passed to the callback function
+ *
+ * Recursively walk the page table for the memory area in a VMA,
+ * calling supplied callbacks. Callbacks are called in-order (first
+ * PGD, first PUD, first PMD, first PTE, second PTE... second PMD,
+ * etc.). If lower-level callbacks are omitted, walking depth is reduced.
+ *
+ * Each callback receives an entry pointer, the start and end of the
+ * associated range, and a caller-supplied private data pointer.
+ *
+ * No locks are taken, but the bottom level iterator will map PTE
+ * directories from highmem if necessary.
+ *
+ * If any callback returns a non-zero value, the walk is aborted and
+ * the return value is propagated back to the caller. Otherwise 0 is returned.
+ */
+int walk_page_range(const struct mm_struct *mm,
+                   unsigned long addr, unsigned long end,
+                   const struct mm_walk *walk, void *private)
+{
+       pgd_t *pgd;
+       unsigned long next;
+       int err = 0;
+
+       if (addr >= end)
+               return err;
+
+       pgd = pgd_offset(mm, addr);
+       do {
+               next = pgd_addr_end(addr, end);
+               if (pgd_none_or_clear_bad(pgd)) {
+                       if (walk->pte_hole)
+                               err = walk->pte_hole(addr, next, private);
+                       if (err)
+                               break;
+                       continue;
+               }
+               if (walk->pgd_entry)
+                       err = walk->pgd_entry(pgd, addr, next, private);
+               if (!err &&
+                   (walk->pud_entry || walk->pmd_entry || walk->pte_entry))
+                       err = walk_pud_range(pgd, addr, next, walk, private);
+               if (err)
+                       break;
+       } while (pgd++, addr = next, addr != end);
+
+       return err;
+}
index dbc2ca2057a54ff2c4a709de4b6e9a01694241bb..57ad276900c94903a2febd53e1c0d995958a38a9 100644 (file)
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -36,7 +36,6 @@
  *                 mapping->tree_lock (widely used, in set_page_dirty,
  *                           in arch-dependent flush_dcache_mmap_lock,
  *                           within inode_lock in __sync_single_inode)
- *                   zone->lock (within radix tree node alloc)
  */
 
 #include <linux/mm.h>
@@ -284,7 +283,10 @@ static int page_referenced_one(struct page *page,
        if (!pte)
                goto out;
 
-       if (ptep_clear_flush_young(vma, address, pte))
+       if (vma->vm_flags & VM_LOCKED) {
+               referenced++;
+               *mapcount = 1;  /* break early from loop */
+       } else if (ptep_clear_flush_young(vma, address, pte))
                referenced++;
 
        /* Pretend the page is referenced if the task has the
index 51b3d6ccddab75ba33b7fded5ffaf75700770ccd..0f246c44a5744ec5aac0930c7896923e96bcb215 100644 (file)
 
 /* Flag allocation requirements to shmem_getpage and shmem_swp_alloc */
 enum sgp_type {
-       SGP_QUICK,      /* don't try more than file page cache lookup */
        SGP_READ,       /* don't exceed i_size, don't allocate page */
        SGP_CACHE,      /* don't exceed i_size, may allocate page */
+       SGP_DIRTY,      /* like SGP_CACHE, but set new page dirty */
        SGP_WRITE,      /* may exceed i_size, may allocate page */
-       SGP_FAULT,      /* same as SGP_CACHE, return with page locked */
 };
 
 static int shmem_getpage(struct inode *inode, unsigned long idx,
@@ -194,7 +193,7 @@ static struct backing_dev_info shmem_backing_dev_info  __read_mostly = {
 };
 
 static LIST_HEAD(shmem_swaplist);
-static DEFINE_SPINLOCK(shmem_swaplist_lock);
+static DEFINE_MUTEX(shmem_swaplist_mutex);
 
 static void shmem_free_blocks(struct inode *inode, long pages)
 {
@@ -207,6 +206,31 @@ static void shmem_free_blocks(struct inode *inode, long pages)
        }
 }
 
+static int shmem_reserve_inode(struct super_block *sb)
+{
+       struct shmem_sb_info *sbinfo = SHMEM_SB(sb);
+       if (sbinfo->max_inodes) {
+               spin_lock(&sbinfo->stat_lock);
+               if (!sbinfo->free_inodes) {
+                       spin_unlock(&sbinfo->stat_lock);
+                       return -ENOSPC;
+               }
+               sbinfo->free_inodes--;
+               spin_unlock(&sbinfo->stat_lock);
+       }
+       return 0;
+}
+
+static void shmem_free_inode(struct super_block *sb)
+{
+       struct shmem_sb_info *sbinfo = SHMEM_SB(sb);
+       if (sbinfo->max_inodes) {
+               spin_lock(&sbinfo->stat_lock);
+               sbinfo->free_inodes++;
+               spin_unlock(&sbinfo->stat_lock);
+       }
+}
+
 /*
  * shmem_recalc_inode - recalculate the size of an inode
  *
@@ -731,6 +755,8 @@ static int shmem_notify_change(struct dentry *dentry, struct iattr *attr)
                                (void) shmem_getpage(inode,
                                        attr->ia_size>>PAGE_CACHE_SHIFT,
                                                &page, SGP_READ, NULL);
+                               if (page)
+                                       unlock_page(page);
                        }
                        /*
                         * Reset SHMEM_PAGEIN flag so that shmem_truncate can
@@ -762,7 +788,6 @@ static int shmem_notify_change(struct dentry *dentry, struct iattr *attr)
 
 static void shmem_delete_inode(struct inode *inode)
 {
-       struct shmem_sb_info *sbinfo = SHMEM_SB(inode->i_sb);
        struct shmem_inode_info *info = SHMEM_I(inode);
 
        if (inode->i_op->truncate == shmem_truncate) {
@@ -771,17 +796,13 @@ static void shmem_delete_inode(struct inode *inode)
                inode->i_size = 0;
                shmem_truncate(inode);
                if (!list_empty(&info->swaplist)) {
-                       spin_lock(&shmem_swaplist_lock);
+                       mutex_lock(&shmem_swaplist_mutex);
                        list_del_init(&info->swaplist);
-                       spin_unlock(&shmem_swaplist_lock);
+                       mutex_unlock(&shmem_swaplist_mutex);
                }
        }
        BUG_ON(inode->i_blocks);
-       if (sbinfo->max_inodes) {
-               spin_lock(&sbinfo->stat_lock);
-               sbinfo->free_inodes++;
-               spin_unlock(&sbinfo->stat_lock);
-       }
+       shmem_free_inode(inode->i_sb);
        clear_inode(inode);
 }
 
@@ -807,19 +828,22 @@ static int shmem_unuse_inode(struct shmem_inode_info *info, swp_entry_t entry, s
        struct page *subdir;
        swp_entry_t *ptr;
        int offset;
+       int error;
 
        idx = 0;
        ptr = info->i_direct;
        spin_lock(&info->lock);
+       if (!info->swapped) {
+               list_del_init(&info->swaplist);
+               goto lost2;
+       }
        limit = info->next_index;
        size = limit;
        if (size > SHMEM_NR_DIRECT)
                size = SHMEM_NR_DIRECT;
        offset = shmem_find_swp(entry, ptr, ptr+size);
-       if (offset >= 0) {
-               shmem_swp_balance_unmap();
+       if (offset >= 0)
                goto found;
-       }
        if (!info->i_indirect)
                goto lost2;
 
@@ -829,6 +853,14 @@ static int shmem_unuse_inode(struct shmem_inode_info *info, swp_entry_t entry, s
        for (idx = SHMEM_NR_DIRECT; idx < limit; idx += ENTRIES_PER_PAGE, dir++) {
                if (unlikely(idx == stage)) {
                        shmem_dir_unmap(dir-1);
+                       if (cond_resched_lock(&info->lock)) {
+                               /* check it has not been truncated */
+                               if (limit > info->next_index) {
+                                       limit = info->next_index;
+                                       if (idx >= limit)
+                                               goto lost2;
+                               }
+                       }
                        dir = shmem_dir_map(info->i_indirect) +
                            ENTRIES_PER_PAGE/2 + idx/ENTRIES_PER_PAGEPAGE;
                        while (!*dir) {
@@ -849,11 +881,11 @@ static int shmem_unuse_inode(struct shmem_inode_info *info, swp_entry_t entry, s
                        if (size > ENTRIES_PER_PAGE)
                                size = ENTRIES_PER_PAGE;
                        offset = shmem_find_swp(entry, ptr, ptr+size);
+                       shmem_swp_unmap(ptr);
                        if (offset >= 0) {
                                shmem_dir_unmap(dir);
                                goto found;
                        }
-                       shmem_swp_unmap(ptr);
                }
        }
 lost1:
@@ -863,19 +895,63 @@ lost2:
        return 0;
 found:
        idx += offset;
-       inode = &info->vfs_inode;
-       if (move_from_swap_cache(page, idx, inode->i_mapping) == 0) {
-               info->flags |= SHMEM_PAGEIN;
-               shmem_swp_set(info, ptr + offset, 0);
-       }
-       shmem_swp_unmap(ptr);
+       inode = igrab(&info->vfs_inode);
        spin_unlock(&info->lock);
+
        /*
-        * Decrement swap count even when the entry is left behind:
-        * try_to_unuse will skip over mms, then reincrement count.
+        * Move _head_ to start search for next from here.
+        * But be careful: shmem_delete_inode checks list_empty without taking
+        * mutex, and there's an instant in list_move_tail when info->swaplist
+        * would appear empty, if it were the only one on shmem_swaplist.  We
+        * could avoid doing it if inode NULL; or use this minor optimization.
         */
-       swap_free(entry);
-       return 1;
+       if (shmem_swaplist.next != &info->swaplist)
+               list_move_tail(&shmem_swaplist, &info->swaplist);
+       mutex_unlock(&shmem_swaplist_mutex);
+
+       error = 1;
+       if (!inode)
+               goto out;
+       error = radix_tree_preload(GFP_KERNEL);
+       if (error)
+               goto out;
+       error = 1;
+
+       spin_lock(&info->lock);
+       ptr = shmem_swp_entry(info, idx, NULL);
+       if (ptr && ptr->val == entry.val)
+               error = add_to_page_cache(page, inode->i_mapping,
+                                               idx, GFP_NOWAIT);
+       if (error == -EEXIST) {
+               struct page *filepage = find_get_page(inode->i_mapping, idx);
+               error = 1;
+               if (filepage) {
+                       /*
+                        * There might be a more uptodate page coming down
+                        * from a stacked writepage: forget our swappage if so.
+                        */
+                       if (PageUptodate(filepage))
+                               error = 0;
+                       page_cache_release(filepage);
+               }
+       }
+       if (!error) {
+               delete_from_swap_cache(page);
+               set_page_dirty(page);
+               info->flags |= SHMEM_PAGEIN;
+               shmem_swp_set(info, ptr, 0);
+               swap_free(entry);
+               error = 1;      /* not an error, but entry was found */
+       }
+       if (ptr)
+               shmem_swp_unmap(ptr);
+       spin_unlock(&info->lock);
+       radix_tree_preload_end();
+out:
+       unlock_page(page);
+       page_cache_release(page);
+       iput(inode);            /* allows for NULL */
+       return error;
 }
 
 /*
@@ -887,20 +963,16 @@ int shmem_unuse(swp_entry_t entry, struct page *page)
        struct shmem_inode_info *info;
        int found = 0;
 
-       spin_lock(&shmem_swaplist_lock);
+       mutex_lock(&shmem_swaplist_mutex);
        list_for_each_safe(p, next, &shmem_swaplist) {
                info = list_entry(p, struct shmem_inode_info, swaplist);
-               if (!info->swapped)
-                       list_del_init(&info->swaplist);
-               else if (shmem_unuse_inode(info, entry, page)) {
-                       /* move head to start search for next from here */
-                       list_move_tail(&shmem_swaplist, &info->swaplist);
-                       found = 1;
-                       break;
-               }
+               found = shmem_unuse_inode(info, entry, page);
+               cond_resched();
+               if (found)
+                       goto out;
        }
-       spin_unlock(&shmem_swaplist_lock);
-       return found;
+       mutex_unlock(&shmem_swaplist_mutex);
+out:   return found;   /* 0 or 1 or -ENOMEM */
 }
 
 /*
@@ -915,54 +987,65 @@ static int shmem_writepage(struct page *page, struct writeback_control *wbc)
        struct inode *inode;
 
        BUG_ON(!PageLocked(page));
-       /*
-        * shmem_backing_dev_info's capabilities prevent regular writeback or
-        * sync from ever calling shmem_writepage; but a stacking filesystem
-        * may use the ->writepage of its underlying filesystem, in which case
-        * we want to do nothing when that underlying filesystem is tmpfs
-        * (writing out to swap is useful as a response to memory pressure, but
-        * of no use to stabilize the data) - just redirty the page, unlock it
-        * and claim success in this case.  AOP_WRITEPAGE_ACTIVATE, and the
-        * page_mapped check below, must be avoided unless we're in reclaim.
-        */
-       if (!wbc->for_reclaim) {
-               set_page_dirty(page);
-               unlock_page(page);
-               return 0;
-       }
-       BUG_ON(page_mapped(page));
-
        mapping = page->mapping;
        index = page->index;
        inode = mapping->host;
        info = SHMEM_I(inode);
        if (info->flags & VM_LOCKED)
                goto redirty;
-       swap = get_swap_page();
-       if (!swap.val)
+       if (!total_swap_pages)
                goto redirty;
 
+       /*
+        * shmem_backing_dev_info's capabilities prevent regular writeback or
+        * sync from ever calling shmem_writepage; but a stacking filesystem
+        * may use the ->writepage of its underlying filesystem, in which case
+        * tmpfs should write out to swap only in response to memory pressure,
+        * and not for pdflush or sync.  However, in those cases, we do still
+        * want to check if there's a redundant swappage to be discarded.
+        */
+       if (wbc->for_reclaim)
+               swap = get_swap_page();
+       else
+               swap.val = 0;
+
        spin_lock(&info->lock);
-       shmem_recalc_inode(inode);
        if (index >= info->next_index) {
                BUG_ON(!(info->flags & SHMEM_TRUNCATE));
                goto unlock;
        }
        entry = shmem_swp_entry(info, index, NULL);
-       BUG_ON(!entry);
-       BUG_ON(entry->val);
+       if (entry->val) {
+               /*
+                * The more uptodate page coming down from a stacked
+                * writepage should replace our old swappage.
+                */
+               free_swap_and_cache(*entry);
+               shmem_swp_set(info, entry, 0);
+       }
+       shmem_recalc_inode(inode);
 
-       if (move_to_swap_cache(page, swap) == 0) {
+       if (swap.val && add_to_swap_cache(page, swap, GFP_ATOMIC) == 0) {
+               remove_from_page_cache(page);
                shmem_swp_set(info, entry, swap.val);
                shmem_swp_unmap(entry);
+               if (list_empty(&info->swaplist))
+                       inode = igrab(inode);
+               else
+                       inode = NULL;
                spin_unlock(&info->lock);
-               if (list_empty(&info->swaplist)) {
-                       spin_lock(&shmem_swaplist_lock);
+               swap_duplicate(swap);
+               BUG_ON(page_mapped(page));
+               page_cache_release(page);       /* pagecache ref */
+               set_page_dirty(page);
+               unlock_page(page);
+               if (inode) {
+                       mutex_lock(&shmem_swaplist_mutex);
                        /* move instead of add in case we're racing */
                        list_move_tail(&info->swaplist, &shmem_swaplist);
-                       spin_unlock(&shmem_swaplist_lock);
+                       mutex_unlock(&shmem_swaplist_mutex);
+                       iput(inode);
                }
-               unlock_page(page);
                return 0;
        }
 
@@ -972,7 +1055,10 @@ unlock:
        swap_free(swap);
 redirty:
        set_page_dirty(page);
-       return AOP_WRITEPAGE_ACTIVATE;  /* Return with the page locked */
+       if (wbc->for_reclaim)
+               return AOP_WRITEPAGE_ACTIVATE;  /* Return with page locked */
+       unlock_page(page);
+       return 0;
 }
 
 #ifdef CONFIG_NUMA
@@ -1025,53 +1111,33 @@ out:
        return err;
 }
 
-static struct page *shmem_swapin_async(struct shared_policy *p,
-                                      swp_entry_t entry, unsigned long idx)
+static struct page *shmem_swapin(swp_entry_t entry, gfp_t gfp,
+                       struct shmem_inode_info *info, unsigned long idx)
 {
-       struct page *page;
        struct vm_area_struct pvma;
+       struct page *page;
 
        /* Create a pseudo vma that just contains the policy */
-       memset(&pvma, 0, sizeof(struct vm_area_struct));
-       pvma.vm_end = PAGE_SIZE;
+       pvma.vm_start = 0;
        pvma.vm_pgoff = idx;
-       pvma.vm_policy = mpol_shared_policy_lookup(p, idx);
-       page = read_swap_cache_async(entry, &pvma, 0);
+       pvma.vm_ops = NULL;
+       pvma.vm_policy = mpol_shared_policy_lookup(&info->policy, idx);
+       page = swapin_readahead(entry, gfp, &pvma, 0);
        mpol_free(pvma.vm_policy);
        return page;
 }
 
-static struct page *shmem_swapin(struct shmem_inode_info *info,
-                                swp_entry_t entry, unsigned long idx)
-{
-       struct shared_policy *p = &info->policy;
-       int i, num;
-       struct page *page;
-       unsigned long offset;
-
-       num = valid_swaphandles(entry, &offset);
-       for (i = 0; i < num; offset++, i++) {
-               page = shmem_swapin_async(p,
-                               swp_entry(swp_type(entry), offset), idx);
-               if (!page)
-                       break;
-               page_cache_release(page);
-       }
-       lru_add_drain();        /* Push any new pages onto the LRU now */
-       return shmem_swapin_async(p, entry, idx);
-}
-
-static struct page *
-shmem_alloc_page(gfp_t gfp, struct shmem_inode_info *info,
-                unsigned long idx)
+static struct page *shmem_alloc_page(gfp_t gfp,
+                       struct shmem_inode_info *info, unsigned long idx)
 {
        struct vm_area_struct pvma;
        struct page *page;
 
-       memset(&pvma, 0, sizeof(struct vm_area_struct));
-       pvma.vm_policy = mpol_shared_policy_lookup(&info->policy, idx);
+       /* Create a pseudo vma that just contains the policy */
+       pvma.vm_start = 0;
        pvma.vm_pgoff = idx;
-       pvma.vm_end = PAGE_SIZE;
+       pvma.vm_ops = NULL;
+       pvma.vm_policy = mpol_shared_policy_lookup(&info->policy, idx);
        page = alloc_page_vma(gfp, &pvma, 0);
        mpol_free(pvma.vm_policy);
        return page;
@@ -1083,15 +1149,14 @@ static inline int shmem_parse_mpol(char *value, int *policy,
        return 1;
 }
 
-static inline struct page *
-shmem_swapin(struct shmem_inode_info *info,swp_entry_t entry,unsigned long idx)
+static inline struct page *shmem_swapin(swp_entry_t entry, gfp_t gfp,
+                       struct shmem_inode_info *info, unsigned long idx)
 {
-       swapin_readahead(entry, 0, NULL);
-       return read_swap_cache_async(entry, NULL, 0);
+       return swapin_readahead(entry, gfp, NULL, 0);
 }
 
-static inline struct page *
-shmem_alloc_page(gfp_t gfp,struct shmem_inode_info *info, unsigned long idx)
+static inline struct page *shmem_alloc_page(gfp_t gfp,
+                       struct shmem_inode_info *info, unsigned long idx)
 {
        return alloc_page(gfp);
 }
@@ -1114,6 +1179,7 @@ static int shmem_getpage(struct inode *inode, unsigned long idx,
        struct page *swappage;
        swp_entry_t *entry;
        swp_entry_t swap;
+       gfp_t gfp;
        int error;
 
        if (idx >= SHMEM_MAX_INDEX)
@@ -1126,7 +1192,7 @@ static int shmem_getpage(struct inode *inode, unsigned long idx,
         * Normally, filepage is NULL on entry, and either found
         * uptodate immediately, or allocated and zeroed, or read
         * in under swappage, which is then assigned to filepage.
-        * But shmem_readpage and shmem_write_begin pass in a locked
+        * But shmem_readpage (required for splice) passes in a locked
         * filepage, which may be found not uptodate by other callers
         * too, and may need to be copied from the swappage read in.
         */
@@ -1136,8 +1202,17 @@ repeat:
        if (filepage && PageUptodate(filepage))
                goto done;
        error = 0;
-       if (sgp == SGP_QUICK)
-               goto failed;
+       gfp = mapping_gfp_mask(mapping);
+       if (!filepage) {
+               /*
+                * Try to preload while we can wait, to not make a habit of
+                * draining atomic reserves; but don't latch on to this cpu.
+                */
+               error = radix_tree_preload(gfp & ~__GFP_HIGHMEM);
+               if (error)
+                       goto failed;
+               radix_tree_preload_end();
+       }
 
        spin_lock(&info->lock);
        shmem_recalc_inode(inode);
@@ -1160,7 +1235,7 @@ repeat:
                                *type |= VM_FAULT_MAJOR;
                        }
                        spin_unlock(&info->lock);
-                       swappage = shmem_swapin(info, swap, idx);
+                       swappage = shmem_swapin(swap, gfp, info, idx);
                        if (!swappage) {
                                spin_lock(&info->lock);
                                entry = shmem_swp_alloc(info, idx, sgp);
@@ -1218,23 +1293,21 @@ repeat:
                        SetPageUptodate(filepage);
                        set_page_dirty(filepage);
                        swap_free(swap);
-               } else if (!(error = move_from_swap_cache(
-                               swappage, idx, mapping))) {
+               } else if (!(error = add_to_page_cache(
+                               swappage, mapping, idx, GFP_NOWAIT))) {
                        info->flags |= SHMEM_PAGEIN;
                        shmem_swp_set(info, entry, 0);
                        shmem_swp_unmap(entry);
+                       delete_from_swap_cache(swappage);
                        spin_unlock(&info->lock);
                        filepage = swappage;
+                       set_page_dirty(filepage);
                        swap_free(swap);
                } else {
                        shmem_swp_unmap(entry);
                        spin_unlock(&info->lock);
                        unlock_page(swappage);
                        page_cache_release(swappage);
-                       if (error == -ENOMEM) {
-                               /* let kswapd refresh zone for GFP_ATOMICs */
-                               congestion_wait(WRITE, HZ/50);
-                       }
                        goto repeat;
                }
        } else if (sgp == SGP_READ && !filepage) {
@@ -1272,9 +1345,7 @@ repeat:
 
                if (!filepage) {
                        spin_unlock(&info->lock);
-                       filepage = shmem_alloc_page(mapping_gfp_mask(mapping),
-                                                   info,
-                                                   idx);
+                       filepage = shmem_alloc_page(gfp, info, idx);
                        if (!filepage) {
                                shmem_unacct_blocks(info->flags, 1);
                                shmem_free_blocks(inode, 1);
@@ -1291,7 +1362,7 @@ repeat:
                                shmem_swp_unmap(entry);
                        }
                        if (error || swap.val || 0 != add_to_page_cache_lru(
-                                       filepage, mapping, idx, GFP_ATOMIC)) {
+                                       filepage, mapping, idx, GFP_NOWAIT)) {
                                spin_unlock(&info->lock);
                                page_cache_release(filepage);
                                shmem_unacct_blocks(info->flags, 1);
@@ -1309,14 +1380,11 @@ repeat:
                clear_highpage(filepage);
                flush_dcache_page(filepage);
                SetPageUptodate(filepage);
+               if (sgp == SGP_DIRTY)
+                       set_page_dirty(filepage);
        }
 done:
-       if (*pagep != filepage) {
-               *pagep = filepage;
-               if (sgp != SGP_FAULT)
-                       unlock_page(filepage);
-
-       }
+       *pagep = filepage;
        return 0;
 
 failed:
@@ -1336,7 +1404,7 @@ static int shmem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
        if (((loff_t)vmf->pgoff << PAGE_CACHE_SHIFT) >= i_size_read(inode))
                return VM_FAULT_SIGBUS;
 
-       error = shmem_getpage(inode, vmf->pgoff, &vmf->page, SGP_FAULT, &ret);
+       error = shmem_getpage(inode, vmf->pgoff, &vmf->page, SGP_CACHE, &ret);
        if (error)
                return ((error == -ENOMEM) ? VM_FAULT_OOM : VM_FAULT_SIGBUS);
 
@@ -1399,15 +1467,8 @@ shmem_get_inode(struct super_block *sb, int mode, dev_t dev)
        struct shmem_inode_info *info;
        struct shmem_sb_info *sbinfo = SHMEM_SB(sb);
 
-       if (sbinfo->max_inodes) {
-               spin_lock(&sbinfo->stat_lock);
-               if (!sbinfo->free_inodes) {
-                       spin_unlock(&sbinfo->stat_lock);
-                       return NULL;
-               }
-               sbinfo->free_inodes--;
-               spin_unlock(&sbinfo->stat_lock);
-       }
+       if (shmem_reserve_inode(sb))
+               return NULL;
 
        inode = new_inode(sb);
        if (inode) {
@@ -1451,11 +1512,8 @@ shmem_get_inode(struct super_block *sb, int mode, dev_t dev)
                                                NULL);
                        break;
                }
-       } else if (sbinfo->max_inodes) {
-               spin_lock(&sbinfo->stat_lock);
-               sbinfo->free_inodes++;
-               spin_unlock(&sbinfo->stat_lock);
-       }
+       } else
+               shmem_free_inode(sb);
        return inode;
 }
 
@@ -1494,123 +1552,30 @@ shmem_write_end(struct file *file, struct address_space *mapping,
 {
        struct inode *inode = mapping->host;
 
+       if (pos + copied > inode->i_size)
+               i_size_write(inode, pos + copied);
+
+       unlock_page(page);
        set_page_dirty(page);
        page_cache_release(page);
 
-       if (pos+copied > inode->i_size)
-               i_size_write(inode, pos+copied);
-
        return copied;
 }
 
-static ssize_t
-shmem_file_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
-{
-       struct inode    *inode = file->f_path.dentry->d_inode;
-       loff_t          pos;
-       unsigned long   written;
-       ssize_t         err;
-
-       if ((ssize_t) count < 0)
-               return -EINVAL;
-
-       if (!access_ok(VERIFY_READ, buf, count))
-               return -EFAULT;
-
-       mutex_lock(&inode->i_mutex);
-
-       pos = *ppos;
-       written = 0;
-
-       err = generic_write_checks(file, &pos, &count, 0);
-       if (err || !count)
-               goto out;
-
-       err = remove_suid(file->f_path.dentry);
-       if (err)
-               goto out;
-
-       inode->i_ctime = inode->i_mtime = CURRENT_TIME;
-
-       do {
-               struct page *page = NULL;
-               unsigned long bytes, index, offset;
-               char *kaddr;
-               int left;
-
-               offset = (pos & (PAGE_CACHE_SIZE -1)); /* Within page */
-               index = pos >> PAGE_CACHE_SHIFT;
-               bytes = PAGE_CACHE_SIZE - offset;
-               if (bytes > count)
-                       bytes = count;
-
-               /*
-                * We don't hold page lock across copy from user -
-                * what would it guard against? - so no deadlock here.
-                * But it still may be a good idea to prefault below.
-                */
-
-               err = shmem_getpage(inode, index, &page, SGP_WRITE, NULL);
-               if (err)
-                       break;
-
-               left = bytes;
-               if (PageHighMem(page)) {
-                       volatile unsigned char dummy;
-                       __get_user(dummy, buf);
-                       __get_user(dummy, buf + bytes - 1);
-
-                       kaddr = kmap_atomic(page, KM_USER0);
-                       left = __copy_from_user_inatomic(kaddr + offset,
-                                                       buf, bytes);
-                       kunmap_atomic(kaddr, KM_USER0);
-               }
-               if (left) {
-                       kaddr = kmap(page);
-                       left = __copy_from_user(kaddr + offset, buf, bytes);
-                       kunmap(page);
-               }
-
-               written += bytes;
-               count -= bytes;
-               pos += bytes;
-               buf += bytes;
-               if (pos > inode->i_size)
-                       i_size_write(inode, pos);
-
-               flush_dcache_page(page);
-               set_page_dirty(page);
-               mark_page_accessed(page);
-               page_cache_release(page);
-
-               if (left) {
-                       pos -= left;
-                       written -= left;
-                       err = -EFAULT;
-                       break;
-               }
-
-               /*
-                * Our dirty pages are not counted in nr_dirty,
-                * and we do not attempt to balance dirty pages.
-                */
-
-               cond_resched();
-       } while (count);
-
-       *ppos = pos;
-       if (written)
-               err = written;
-out:
-       mutex_unlock(&inode->i_mutex);
-       return err;
-}
-
 static void do_shmem_file_read(struct file *filp, loff_t *ppos, read_descriptor_t *desc, read_actor_t actor)
 {
        struct inode *inode = filp->f_path.dentry->d_inode;
        struct address_space *mapping = inode->i_mapping;
        unsigned long index, offset;
+       enum sgp_type sgp = SGP_READ;
+
+       /*
+        * Might this read be for a stacking filesystem?  Then when reading
+        * holes of a sparse file, we actually need to allocate those pages,
+        * and even mark them dirty, so it cannot exceed the max_blocks limit.
+        */
+       if (segment_eq(get_fs(), KERNEL_DS))
+               sgp = SGP_DIRTY;
 
        index = *ppos >> PAGE_CACHE_SHIFT;
        offset = *ppos & ~PAGE_CACHE_MASK;
@@ -1629,12 +1594,14 @@ static void do_shmem_file_read(struct file *filp, loff_t *ppos, read_descriptor_
                                break;
                }
 
-               desc->error = shmem_getpage(inode, index, &page, SGP_READ, NULL);
+               desc->error = shmem_getpage(inode, index, &page, sgp, NULL);
                if (desc->error) {
                        if (desc->error == -EINVAL)
                                desc->error = 0;
                        break;
                }
+               if (page)
+                       unlock_page(page);
 
                /*
                 * We must evaluate after, since reads (unlike writes)
@@ -1798,22 +1765,16 @@ static int shmem_create(struct inode *dir, struct dentry *dentry, int mode,
 static int shmem_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry)
 {
        struct inode *inode = old_dentry->d_inode;
-       struct shmem_sb_info *sbinfo = SHMEM_SB(inode->i_sb);
+       int ret;
 
        /*
         * No ordinary (disk based) filesystem counts links as inodes;
         * but each new link needs a new dentry, pinning lowmem, and
         * tmpfs dentries cannot be pruned until they are unlinked.
         */
-       if (sbinfo->max_inodes) {
-               spin_lock(&sbinfo->stat_lock);
-               if (!sbinfo->free_inodes) {
-                       spin_unlock(&sbinfo->stat_lock);
-                       return -ENOSPC;
-               }
-               sbinfo->free_inodes--;
-               spin_unlock(&sbinfo->stat_lock);
-       }
+       ret = shmem_reserve_inode(inode->i_sb);
+       if (ret)
+               goto out;
 
        dir->i_size += BOGO_DIRENT_SIZE;
        inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
@@ -1821,21 +1782,16 @@ static int shmem_link(struct dentry *old_dentry, struct inode *dir, struct dentr
        atomic_inc(&inode->i_count);    /* New dentry reference */
        dget(dentry);           /* Extra pinning count for the created dentry */
        d_instantiate(dentry, inode);
-       return 0;
+out:
+       return ret;
 }
 
 static int shmem_unlink(struct inode *dir, struct dentry *dentry)
 {
        struct inode *inode = dentry->d_inode;
 
-       if (inode->i_nlink > 1 && !S_ISDIR(inode->i_mode)) {
-               struct shmem_sb_info *sbinfo = SHMEM_SB(inode->i_sb);
-               if (sbinfo->max_inodes) {
-                       spin_lock(&sbinfo->stat_lock);
-                       sbinfo->free_inodes++;
-                       spin_unlock(&sbinfo->stat_lock);
-               }
-       }
+       if (inode->i_nlink > 1 && !S_ISDIR(inode->i_mode))
+               shmem_free_inode(inode->i_sb);
 
        dir->i_size -= BOGO_DIRENT_SIZE;
        inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
@@ -1924,6 +1880,7 @@ static int shmem_symlink(struct inode *dir, struct dentry *dentry, const char *s
                        iput(inode);
                        return error;
                }
+               unlock_page(page);
                inode->i_op = &shmem_symlink_inode_operations;
                kaddr = kmap_atomic(page, KM_USER0);
                memcpy(kaddr, symname, len);
@@ -1951,6 +1908,8 @@ static void *shmem_follow_link(struct dentry *dentry, struct nameidata *nd)
        struct page *page = NULL;
        int res = shmem_getpage(dentry->d_inode, 0, &page, SGP_READ, NULL);
        nd_set_link(nd, res ? ERR_PTR(res) : kmap(page));
+       if (page)
+               unlock_page(page);
        return page;
 }
 
@@ -1996,8 +1955,7 @@ static int shmem_xattr_security_get(struct inode *inode, const char *name,
 {
        if (strcmp(name, "") == 0)
                return -EINVAL;
-       return security_inode_getsecurity(inode, name, buffer, size,
-                                         -EOPNOTSUPP);
+       return xattr_getsecurity(inode, name, buffer, size);
 }
 
 static int shmem_xattr_security_set(struct inode *inode, const char *name,
@@ -2138,7 +2096,7 @@ static int shmem_parse_options(char *options, int *mode, uid_t *uid,
                        }
                        if (*rest)
                                goto bad_val;
-                       *blocks = size >> PAGE_CACHE_SHIFT;
+                       *blocks = DIV_ROUND_UP(size, PAGE_CACHE_SIZE);
                } else if (!strcmp(this_char,"nr_blocks")) {
                        *blocks = memparse(value,&rest);
                        if (*rest)
@@ -2375,7 +2333,8 @@ static const struct file_operations shmem_file_operations = {
 #ifdef CONFIG_TMPFS
        .llseek         = generic_file_llseek,
        .read           = shmem_file_read,
-       .write          = shmem_file_write,
+       .write          = do_sync_write,
+       .aio_write      = generic_file_aio_write,
        .fsync          = simple_sync_file,
        .splice_read    = generic_file_splice_read,
        .splice_write   = generic_file_splice_write,
index 773a7aa80ab5ce53883cd7ad4d07a6019a175fe0..e2c3c0ec546373857ba3c2132edde98cdf5e8bb0 100644 (file)
--- a/mm/slob.c
+++ b/mm/slob.c
  * allocator is as little as 2 bytes, however typically most architectures
  * will require 4 bytes on 32-bit and 8 bytes on 64-bit.
  *
- * The slob heap is a linked list of pages from alloc_pages(), and
- * within each page, there is a singly-linked list of free blocks (slob_t).
- * The heap is grown on demand and allocation from the heap is currently
- * first-fit.
+ * The slob heap is a set of linked list of pages from alloc_pages(),
+ * and within each page, there is a singly-linked list of free blocks
+ * (slob_t). The heap is grown on demand. To reduce fragmentation,
+ * heap pages are segregated into three lists, with objects less than
+ * 256 bytes, objects less than 1024 bytes, and all other objects.
+ *
+ * Allocation from heap involves first searching for a page with
+ * sufficient free blocks (using a next-fit-like approach) followed by
+ * a first-fit scan of the page. Deallocation inserts objects back
+ * into the free list in address order, so this is effectively an
+ * address-ordered first fit.
  *
  * Above this is an implementation of kmalloc/kfree. Blocks returned
  * from kmalloc are prepended with a 4-byte header with the kmalloc size.
@@ -110,9 +117,13 @@ static inline void free_slob_page(struct slob_page *sp)
 }
 
 /*
- * All (partially) free slob pages go on this list.
+ * All partially free slob pages go on these lists.
  */
-static LIST_HEAD(free_slob_pages);
+#define SLOB_BREAK1 256
+#define SLOB_BREAK2 1024
+static LIST_HEAD(free_slob_small);
+static LIST_HEAD(free_slob_medium);
+static LIST_HEAD(free_slob_large);
 
 /*
  * slob_page: True for all slob pages (false for bigblock pages)
@@ -140,9 +151,9 @@ static inline int slob_page_free(struct slob_page *sp)
        return test_bit(PG_private, &sp->flags);
 }
 
-static inline void set_slob_page_free(struct slob_page *sp)
+static void set_slob_page_free(struct slob_page *sp, struct list_head *list)
 {
-       list_add(&sp->list, &free_slob_pages);
+       list_add(&sp->list, list);
        __set_bit(PG_private, &sp->flags);
 }
 
@@ -294,12 +305,20 @@ static void *slob_alloc(size_t size, gfp_t gfp, int align, int node)
 {
        struct slob_page *sp;
        struct list_head *prev;
+       struct list_head *slob_list;
        slob_t *b = NULL;
        unsigned long flags;
 
+       if (size < SLOB_BREAK1)
+               slob_list = &free_slob_small;
+       else if (size < SLOB_BREAK2)
+               slob_list = &free_slob_medium;
+       else
+               slob_list = &free_slob_large;
+
        spin_lock_irqsave(&slob_lock, flags);
        /* Iterate through each partially free page, try to find room */
-       list_for_each_entry(sp, &free_slob_pages, list) {
+       list_for_each_entry(sp, slob_list, list) {
 #ifdef CONFIG_NUMA
                /*
                 * If there's a node specification, search for a partial
@@ -321,9 +340,9 @@ static void *slob_alloc(size_t size, gfp_t gfp, int align, int node)
                /* Improve fragment distribution and reduce our average
                 * search time by starting our next search here. (see
                 * Knuth vol 1, sec 2.5, pg 449) */
-               if (prev != free_slob_pages.prev &&
-                               free_slob_pages.next != prev->next)
-                       list_move_tail(&free_slob_pages, prev->next);
+               if (prev != slob_list->prev &&
+                               slob_list->next != prev->next)
+                       list_move_tail(slob_list, prev->next);
                break;
        }
        spin_unlock_irqrestore(&slob_lock, flags);
@@ -341,7 +360,7 @@ static void *slob_alloc(size_t size, gfp_t gfp, int align, int node)
                sp->free = b;
                INIT_LIST_HEAD(&sp->list);
                set_slob(b, SLOB_UNITS(PAGE_SIZE), b + SLOB_UNITS(PAGE_SIZE));
-               set_slob_page_free(sp);
+               set_slob_page_free(sp, slob_list);
                b = slob_page_alloc(sp, size, align);
                BUG_ON(!b);
                spin_unlock_irqrestore(&slob_lock, flags);
@@ -387,7 +406,7 @@ static void slob_free(void *block, int size)
                set_slob(b, units,
                        (void *)((unsigned long)(b +
                                        SLOB_UNITS(PAGE_SIZE)) & PAGE_MASK));
-               set_slob_page_free(sp);
+               set_slob_page_free(sp, &free_slob_small);
                goto out;
        }
 
@@ -398,6 +417,10 @@ static void slob_free(void *block, int size)
        sp->units += units;
 
        if (b < sp->free) {
+               if (b + units == sp->free) {
+                       units += slob_units(sp->free);
+                       sp->free = slob_next(sp->free);
+               }
                set_slob(b, units, sp->free);
                sp->free = b;
        } else {
index 5cc4b7dddb505dc08a9a05bdfeb2cc1f91faf9c2..3f056677fa8fea56ef3a678cc8e9d8a8d27b2371 100644 (file)
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -247,7 +247,10 @@ static void sysfs_slab_remove(struct kmem_cache *);
 static inline int sysfs_slab_add(struct kmem_cache *s) { return 0; }
 static inline int sysfs_slab_alias(struct kmem_cache *s, const char *p)
                                                        { return 0; }
-static inline void sysfs_slab_remove(struct kmem_cache *s) {}
+static inline void sysfs_slab_remove(struct kmem_cache *s)
+{
+       kfree(s);
+}
 #endif
 
 /********************************************************************
@@ -354,22 +357,22 @@ static void print_section(char *text, u8 *addr, unsigned int length)
                        printk(KERN_ERR "%8s 0x%p: ", text, addr + i);
                        newline = 0;
                }
-               printk(" %02x", addr[i]);
+               printk(KERN_CONT " %02x", addr[i]);
                offset = i % 16;
                ascii[offset] = isgraph(addr[i]) ? addr[i] : '.';
                if (offset == 15) {
-                       printk(" %s\n",ascii);
+                       printk(KERN_CONT " %s\n", ascii);
                        newline = 1;
                }
        }
        if (!newline) {
                i %= 16;
                while (i < 16) {
-                       printk("   ");
+                       printk(KERN_CONT "   ");
                        ascii[i] = ' ';
                        i++;
                }
-               printk(" %s\n", ascii);
+               printk(KERN_CONT " %s\n", ascii);
        }
 }
 
@@ -529,7 +532,7 @@ static void init_object(struct kmem_cache *s, void *object, int active)
 
        if (s->flags & __OBJECT_POISON) {
                memset(p, POISON_FREE, s->objsize - 1);
-               p[s->objsize -1] = POISON_END;
+               p[s->objsize - 1] = POISON_END;
        }
 
        if (s->flags & SLAB_RED_ZONE)
@@ -558,7 +561,7 @@ static void restore_bytes(struct kmem_cache *s, char *message, u8 data,
 
 static int check_bytes_and_report(struct kmem_cache *s, struct page *page,
                        u8 *object, char *what,
-                       u8start, unsigned int value, unsigned int bytes)
+                       u8 *start, unsigned int value, unsigned int bytes)
 {
        u8 *fault;
        u8 *end;
@@ -692,7 +695,7 @@ static int check_object(struct kmem_cache *s, struct page *page,
                        (!check_bytes_and_report(s, page, p, "Poison", p,
                                        POISON_FREE, s->objsize - 1) ||
                         !check_bytes_and_report(s, page, p, "Poison",
-                               p + s->objsize -1, POISON_END, 1)))
+                               p + s->objsize - 1, POISON_END, 1)))
                        return 0;
                /*
                 * check_pad_bytes cleans up on its own.
@@ -900,8 +903,7 @@ static int free_debug_processing(struct kmem_cache *s, struct page *page,
                                "SLUB <none>: no slab for object 0x%p.\n",
                                                object);
                        dump_stack();
-               }
-               else
+               } else
                        object_err(s, page, object,
                                        "page slab pointer corrupt.");
                goto fail;
@@ -947,7 +949,7 @@ static int __init setup_slub_debug(char *str)
        /*
         * Determine which debug features should be switched on
         */
-       for ( ;*str && *str != ','; str++) {
+       for (*str && *str != ','; str++) {
                switch (tolower(*str)) {
                case 'f':
                        slub_debug |= SLAB_DEBUG_FREE;
@@ -966,7 +968,7 @@ static int __init setup_slub_debug(char *str)
                        break;
                default:
                        printk(KERN_ERR "slub_debug option '%c' "
-                               "unknown. skipped\n",*str);
+                               "unknown. skipped\n", *str);
                }
        }
 
@@ -1039,7 +1041,7 @@ static inline unsigned long kmem_cache_flags(unsigned long objsize,
  */
 static struct page *allocate_slab(struct kmem_cache *s, gfp_t flags, int node)
 {
-       struct page * page;
+       struct page *page;
        int pages = 1 << s->order;
 
        if (s->order)
@@ -1135,7 +1137,7 @@ static void __free_slab(struct kmem_cache *s, struct page *page)
        mod_zone_page_state(page_zone(page),
                (s->flags & SLAB_RECLAIM_ACCOUNT) ?
                NR_SLAB_RECLAIMABLE : NR_SLAB_UNRECLAIMABLE,
-               - pages);
+               -pages);
 
        __free_pages(page, s->order);
 }
@@ -1195,19 +1197,15 @@ static __always_inline int slab_trylock(struct page *page)
 /*
  * Management of partially allocated slabs
  */
-static void add_partial_tail(struct kmem_cache_node *n, struct page *page)
-{
-       spin_lock(&n->list_lock);
-       n->nr_partial++;
-       list_add_tail(&page->lru, &n->partial);
-       spin_unlock(&n->list_lock);
-}
-
-static void add_partial(struct kmem_cache_node *n, struct page *page)
+static void add_partial(struct kmem_cache_node *n,
+                               struct page *page, int tail)
 {
        spin_lock(&n->list_lock);
        n->nr_partial++;
-       list_add(&page->lru, &n->partial);
+       if (tail)
+               list_add_tail(&page->lru, &n->partial);
+       else
+               list_add(&page->lru, &n->partial);
        spin_unlock(&n->list_lock);
 }
 
@@ -1292,7 +1290,8 @@ static struct page *get_any_partial(struct kmem_cache *s, gfp_t flags)
         * expensive if we do it every time we are trying to find a slab
         * with available objects.
         */
-       if (!s->defrag_ratio || get_cycles() % 1024 > s->defrag_ratio)
+       if (!s->remote_node_defrag_ratio ||
+                       get_cycles() % 1024 > s->remote_node_defrag_ratio)
                return NULL;
 
        zonelist = &NODE_DATA(slab_node(current->mempolicy))
@@ -1335,7 +1334,7 @@ static struct page *get_partial(struct kmem_cache *s, gfp_t flags, int node)
  *
  * On exit the slab lock will have been dropped.
  */
-static void unfreeze_slab(struct kmem_cache *s, struct page *page)
+static void unfreeze_slab(struct kmem_cache *s, struct page *page, int tail)
 {
        struct kmem_cache_node *n = get_node(s, page_to_nid(page));
 
@@ -1343,7 +1342,7 @@ static void unfreeze_slab(struct kmem_cache *s, struct page *page)
        if (page->inuse) {
 
                if (page->freelist)
-                       add_partial(n, page);
+                       add_partial(n, page, tail);
                else if (SlabDebug(page) && (s->flags & SLAB_STORE_USER))
                        add_full(n, page);
                slab_unlock(page);
@@ -1358,7 +1357,7 @@ static void unfreeze_slab(struct kmem_cache *s, struct page *page)
                         * partial list stays small. kmem_cache_shrink can
                         * reclaim empty slabs from the partial list.
                         */
-                       add_partial_tail(n, page);
+                       add_partial(n, page, 1);
                        slab_unlock(page);
                } else {
                        slab_unlock(page);
@@ -1373,6 +1372,7 @@ static void unfreeze_slab(struct kmem_cache *s, struct page *page)
 static void deactivate_slab(struct kmem_cache *s, struct kmem_cache_cpu *c)
 {
        struct page *page = c->page;
+       int tail = 1;
        /*
         * Merge cpu freelist into freelist. Typically we get here
         * because both freelists are empty. So this is unlikely
@@ -1381,6 +1381,8 @@ static void deactivate_slab(struct kmem_cache *s, struct kmem_cache_cpu *c)
        while (unlikely(c->freelist)) {
                void **object;
 
+               tail = 0;       /* Hot objects. Put the slab first */
+
                /* Retrieve object from cpu_freelist */
                object = c->freelist;
                c->freelist = c->freelist[c->offset];
@@ -1391,7 +1393,7 @@ static void deactivate_slab(struct kmem_cache *s, struct kmem_cache_cpu *c)
                page->inuse--;
        }
        c->page = NULL;
-       unfreeze_slab(s, page);
+       unfreeze_slab(s, page, tail);
 }
 
 static inline void flush_slab(struct kmem_cache *s, struct kmem_cache_cpu *c)
@@ -1539,7 +1541,7 @@ debug:
  *
  * Otherwise we can simply pick the next object from the lockless free list.
  */
-static void __always_inline *slab_alloc(struct kmem_cache *s,
+static __always_inline void *slab_alloc(struct kmem_cache *s,
                gfp_t gfpflags, int node, void *addr)
 {
        void **object;
@@ -1613,7 +1615,7 @@ checks_ok:
         * then add it.
         */
        if (unlikely(!prior))
-               add_partial_tail(get_node(s, page_to_nid(page)), page);
+               add_partial(get_node(s, page_to_nid(page)), page, 1);
 
 out_unlock:
        slab_unlock(page);
@@ -1647,7 +1649,7 @@ debug:
  * If fastpath is not possible then fall back to __slab_free where we deal
  * with all sorts of special processing.
  */
-static void __always_inline slab_free(struct kmem_cache *s,
+static __always_inline void slab_free(struct kmem_cache *s,
                        struct page *page, void *x, void *addr)
 {
        void **object = (void *)x;
@@ -1997,6 +1999,7 @@ static struct kmem_cache_node *early_kmem_cache_node_alloc(gfp_t gfpflags,
 {
        struct page *page;
        struct kmem_cache_node *n;
+       unsigned long flags;
 
        BUG_ON(kmalloc_caches->size < sizeof(struct kmem_cache_node));
 
@@ -2021,7 +2024,14 @@ static struct kmem_cache_node *early_kmem_cache_node_alloc(gfp_t gfpflags,
 #endif
        init_kmem_cache_node(n);
        atomic_long_inc(&n->nr_slabs);
-       add_partial(n, page);
+       /*
+        * lockdep requires consistent irq usage for each lock
+        * so even though there cannot be a race this early in
+        * the boot sequence, we still disable irqs.
+        */
+       local_irq_save(flags);
+       add_partial(n, page, 0);
+       local_irq_restore(flags);
        return n;
 }
 
@@ -2206,7 +2216,7 @@ static int kmem_cache_open(struct kmem_cache *s, gfp_t gfpflags,
 
        s->refcount = 1;
 #ifdef CONFIG_NUMA
-       s->defrag_ratio = 100;
+       s->remote_node_defrag_ratio = 100;
 #endif
        if (!init_kmem_cache_nodes(s, gfpflags & ~SLUB_DMA))
                goto error;
@@ -2228,7 +2238,7 @@ error:
  */
 int kmem_ptr_validate(struct kmem_cache *s, const void *object)
 {
-       struct page * page;
+       struct page *page;
 
        page = get_object_page(object);
 
@@ -2322,7 +2332,6 @@ void kmem_cache_destroy(struct kmem_cache *s)
                if (kmem_cache_close(s))
                        WARN_ON(1);
                sysfs_slab_remove(s);
-               kfree(s);
        } else
                up_write(&slub_lock);
 }
@@ -2341,7 +2350,7 @@ static struct kmem_cache *kmalloc_caches_dma[PAGE_SHIFT];
 
 static int __init setup_slub_min_order(char *str)
 {
-       get_option (&str, &slub_min_order);
+       get_option(&str, &slub_min_order);
 
        return 1;
 }
@@ -2350,7 +2359,7 @@ __setup("slub_min_order=", setup_slub_min_order);
 
 static int __init setup_slub_max_order(char *str)
 {
-       get_option (&str, &slub_max_order);
+       get_option(&str, &slub_max_order);
 
        return 1;
 }
@@ -2359,7 +2368,7 @@ __setup("slub_max_order=", setup_slub_max_order);
 
 static int __init setup_slub_min_objects(char *str)
 {
-       get_option (&str, &slub_min_objects);
+       get_option(&str, &slub_min_objects);
 
        return 1;
 }
@@ -2605,6 +2614,19 @@ void kfree(const void *x)
 }
 EXPORT_SYMBOL(kfree);
 
+static unsigned long count_partial(struct kmem_cache_node *n)
+{
+       unsigned long flags;
+       unsigned long x = 0;
+       struct page *page;
+
+       spin_lock_irqsave(&n->list_lock, flags);
+       list_for_each_entry(page, &n->partial, lru)
+               x += page->inuse;
+       spin_unlock_irqrestore(&n->list_lock, flags);
+       return x;
+}
+
 /*
  * kmem_cache_shrink removes empty slabs from the partial lists and sorts
  * the remaining slabs by the number of items in use. The slabs with the
@@ -2931,7 +2953,7 @@ static struct kmem_cache *find_mergeable(size_t size,
                 * Check if alignment is compatible.
                 * Courtesy of Adrian Drzewiecki
                 */
-               if ((s->size & ~(align -1)) != s->size)
+               if ((s->size & ~(align - 1)) != s->size)
                        continue;
 
                if (s->size - size >= sizeof(void *))
@@ -3040,8 +3062,9 @@ static int __cpuinit slab_cpuup_callback(struct notifier_block *nfb,
        return NOTIFY_OK;
 }
 
-static struct notifier_block __cpuinitdata slab_notifier =
-       { &slab_cpuup_callback, NULL, 0 };
+static struct notifier_block __cpuinitdata slab_notifier = {
+       &slab_cpuup_callback, NULL, 0
+};
 
 #endif
 
@@ -3076,19 +3099,6 @@ void *__kmalloc_node_track_caller(size_t size, gfp_t gfpflags,
        return slab_alloc(s, gfpflags, node, caller);
 }
 
-static unsigned long count_partial(struct kmem_cache_node *n)
-{
-       unsigned long flags;
-       unsigned long x = 0;
-       struct page *page;
-
-       spin_lock_irqsave(&n->list_lock, flags);
-       list_for_each_entry(page, &n->partial, lru)
-               x += page->inuse;
-       spin_unlock_irqrestore(&n->list_lock, flags);
-       return x;
-}
-
 #if defined(CONFIG_SYSFS) && defined(CONFIG_SLUB_DEBUG)
 static int validate_slab(struct kmem_cache *s, struct page *page,
                                                unsigned long *map)
@@ -3390,7 +3400,7 @@ static void process_slab(struct loc_track *t, struct kmem_cache *s,
 static int list_locations(struct kmem_cache *s, char *buf,
                                        enum track_item alloc)
 {
-       int n = 0;
+       int len = 0;
        unsigned long i;
        struct loc_track t = { 0, 0, NULL };
        int node;
@@ -3421,54 +3431,54 @@ static int list_locations(struct kmem_cache *s, char *buf,
        for (i = 0; i < t.count; i++) {
                struct location *l = &t.loc[i];
 
-               if (n > PAGE_SIZE - 100)
+               if (len > PAGE_SIZE - 100)
                        break;
-               n += sprintf(buf + n, "%7ld ", l->count);
+               len += sprintf(buf + len, "%7ld ", l->count);
 
                if (l->addr)
-                       n += sprint_symbol(buf + n, (unsigned long)l->addr);
+                       len += sprint_symbol(buf + len, (unsigned long)l->addr);
                else
-                       n += sprintf(buf + n, "<not-available>");
+                       len += sprintf(buf + len, "<not-available>");
 
                if (l->sum_time != l->min_time) {
                        unsigned long remainder;
 
-                       n += sprintf(buf + n, " age=%ld/%ld/%ld",
+                       len += sprintf(buf + len, " age=%ld/%ld/%ld",
                        l->min_time,
                        div_long_long_rem(l->sum_time, l->count, &remainder),
                        l->max_time);
                } else
-                       n += sprintf(buf + n, " age=%ld",
+                       len += sprintf(buf + len, " age=%ld",
                                l->min_time);
 
                if (l->min_pid != l->max_pid)
-                       n += sprintf(buf + n, " pid=%ld-%ld",
+                       len += sprintf(buf + len, " pid=%ld-%ld",
                                l->min_pid, l->max_pid);
                else
-                       n += sprintf(buf + n, " pid=%ld",
+                       len += sprintf(buf + len, " pid=%ld",
                                l->min_pid);
 
                if (num_online_cpus() > 1 && !cpus_empty(l->cpus) &&
-                               n < PAGE_SIZE - 60) {
-                       n += sprintf(buf + n, " cpus=");
-                       n += cpulist_scnprintf(buf + n, PAGE_SIZE - n - 50,
+                               len < PAGE_SIZE - 60) {
+                       len += sprintf(buf + len, " cpus=");
+                       len += cpulist_scnprintf(buf + len, PAGE_SIZE - len - 50,
                                        l->cpus);
                }
 
                if (num_online_nodes() > 1 && !nodes_empty(l->nodes) &&
-                               n < PAGE_SIZE - 60) {
-                       n += sprintf(buf + n, " nodes=");
-                       n += nodelist_scnprintf(buf + n, PAGE_SIZE - n - 50,
+                               len < PAGE_SIZE - 60) {
+                       len += sprintf(buf + len, " nodes=");
+                       len += nodelist_scnprintf(buf + len, PAGE_SIZE - len - 50,
                                        l->nodes);
                }
 
-               n += sprintf(buf + n, "\n");
+               len += sprintf(buf + len, "\n");
        }
 
        free_loc_track(&t);
        if (!t.count)
-               n += sprintf(buf, "No data\n");
-       return n;
+               len += sprintf(buf, "No data\n");
+       return len;
 }
 
 enum slab_stat_type {
@@ -3498,7 +3508,6 @@ static unsigned long slab_objects(struct kmem_cache *s,
 
        for_each_possible_cpu(cpu) {
                struct page *page;
-               int node;
                struct kmem_cache_cpu *c = get_cpu_slab(s, cpu);
 
                if (!c)
@@ -3510,8 +3519,6 @@ static unsigned long slab_objects(struct kmem_cache *s,
                        continue;
                if (page) {
                        if (flags & SO_CPU) {
-                               int x = 0;
-
                                if (flags & SO_OBJECTS)
                                        x = page->inuse;
                                else
@@ -3848,24 +3855,24 @@ static ssize_t free_calls_show(struct kmem_cache *s, char *buf)
 SLAB_ATTR_RO(free_calls);
 
 #ifdef CONFIG_NUMA
-static ssize_t defrag_ratio_show(struct kmem_cache *s, char *buf)
+static ssize_t remote_node_defrag_ratio_show(struct kmem_cache *s, char *buf)
 {
-       return sprintf(buf, "%d\n", s->defrag_ratio / 10);
+       return sprintf(buf, "%d\n", s->remote_node_defrag_ratio / 10);
 }
 
-static ssize_t defrag_ratio_store(struct kmem_cache *s,
+static ssize_t remote_node_defrag_ratio_store(struct kmem_cache *s,
                                const char *buf, size_t length)
 {
        int n = simple_strtoul(buf, NULL, 10);
 
        if (n < 100)
-               s->defrag_ratio = n * 10;
+               s->remote_node_defrag_ratio = n * 10;
        return length;
 }
-SLAB_ATTR(defrag_ratio);
+SLAB_ATTR(remote_node_defrag_ratio);
 #endif
 
-static struct attribute * slab_attrs[] = {
+static struct attribute *slab_attrs[] = {
        &slab_size_attr.attr,
        &object_size_attr.attr,
        &objs_per_slab_attr.attr,
@@ -3893,7 +3900,7 @@ static struct attribute * slab_attrs[] = {
        &cache_dma_attr.attr,
 #endif
 #ifdef CONFIG_NUMA
-       &defrag_ratio_attr.attr,
+       &remote_node_defrag_ratio_attr.attr,
 #endif
        NULL
 };
@@ -3940,6 +3947,13 @@ static ssize_t slab_attr_store(struct kobject *kobj,
        return err;
 }
 
+static void kmem_cache_release(struct kobject *kobj)
+{
+       struct kmem_cache *s = to_slab(kobj);
+
+       kfree(s);
+}
+
 static struct sysfs_ops slab_sysfs_ops = {
        .show = slab_attr_show,
        .store = slab_attr_store,
@@ -3947,6 +3961,7 @@ static struct sysfs_ops slab_sysfs_ops = {
 
 static struct kobj_type slab_ktype = {
        .sysfs_ops = &slab_sysfs_ops,
+       .release = kmem_cache_release
 };
 
 static int uevent_filter(struct kset *kset, struct kobject *kobj)
@@ -4048,6 +4063,7 @@ static void sysfs_slab_remove(struct kmem_cache *s)
 {
        kobject_uevent(&s->kobj, KOBJ_REMOVE);
        kobject_del(&s->kobj);
+       kobject_put(&s->kobj);
 }
 
 /*
index a2183cb5d5242a0f05695f00b65d5f0f6d25715e..f6a43c09c322cdb39077392ec1c77e9904c52d82 100644 (file)
@@ -237,7 +237,7 @@ static unsigned long *__kmalloc_section_usemap(void)
 }
 #endif /* CONFIG_MEMORY_HOTPLUG */
 
-static unsigned long *sparse_early_usemap_alloc(unsigned long pnum)
+static unsigned long *__init sparse_early_usemap_alloc(unsigned long pnum)
 {
        unsigned long *usemap;
        struct mem_section *ms = __nr_to_section(pnum);
@@ -353,17 +353,9 @@ static inline struct page *kmalloc_section_memmap(unsigned long pnum, int nid,
        return __kmalloc_section_memmap(nr_pages);
 }
 
-static int vaddr_in_vmalloc_area(void *addr)
-{
-       if (addr >= (void *)VMALLOC_START &&
-           addr < (void *)VMALLOC_END)
-               return 1;
-       return 0;
-}
-
 static void __kfree_section_memmap(struct page *memmap, unsigned long nr_pages)
 {
-       if (vaddr_in_vmalloc_area(memmap))
+       if (is_vmalloc_addr(memmap))
                vfree(memmap);
        else
                free_pages((unsigned long)memmap,
index 9ac88323d237a82e9a6bf4a91fced71225a4e318..57b7e25a939c41112d20f4f08f22517fcb112580 100644 (file)
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -41,7 +41,7 @@ static DEFINE_PER_CPU(struct pagevec, lru_rotate_pvecs) = { 0, };
  * This path almost never happens for VM activity - pages are normally
  * freed via pagevecs.  But it gets used by networking.
  */
-static void fastcall __page_cache_release(struct page *page)
+static void __page_cache_release(struct page *page)
 {
        if (PageLRU(page)) {
                unsigned long flags;
@@ -165,7 +165,7 @@ int rotate_reclaimable_page(struct page *page)
 /*
  * FIXME: speed this up?
  */
-void fastcall activate_page(struct page *page)
+void activate_page(struct page *page)
 {
        struct zone *zone = page_zone(page);
 
@@ -186,7 +186,7 @@ void fastcall activate_page(struct page *page)
  * inactive,referenced         ->      active,unreferenced
  * active,unreferenced         ->      active,referenced
  */
-void fastcall mark_page_accessed(struct page *page)
+void mark_page_accessed(struct page *page)
 {
        if (!PageActive(page) && PageReferenced(page) && PageLRU(page)) {
                activate_page(page);
@@ -202,7 +202,7 @@ EXPORT_SYMBOL(mark_page_accessed);
  * lru_cache_add: add a page to the page lists
  * @page: the page to add
  */
-void fastcall lru_cache_add(struct page *page)
+void lru_cache_add(struct page *page)
 {
        struct pagevec *pvec = &get_cpu_var(lru_add_pvecs);
 
@@ -212,7 +212,7 @@ void fastcall lru_cache_add(struct page *page)
        put_cpu_var(lru_add_pvecs);
 }
 
-void fastcall lru_cache_add_active(struct page *page)
+void lru_cache_add_active(struct page *page)
 {
        struct pagevec *pvec = &get_cpu_var(lru_add_active_pvecs);
 
index b52635601dfe0054ea4a4eddbba6317b71e93272..ec42f01a8d02669fb5bd2c73dcffefb5bb619f6c 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/mm.h>
 #include <linux/kernel_stat.h>
 #include <linux/swap.h>
+#include <linux/swapops.h>
 #include <linux/init.h>
 #include <linux/pagemap.h>
 #include <linux/buffer_head.h>
@@ -51,26 +52,22 @@ static struct {
        unsigned long del_total;
        unsigned long find_success;
        unsigned long find_total;
-       unsigned long noent_race;
-       unsigned long exist_race;
 } swap_cache_info;
 
 void show_swap_cache_info(void)
 {
-       printk("Swap cache: add %lu, delete %lu, find %lu/%lu, race %lu+%lu\n",
+       printk("Swap cache: add %lu, delete %lu, find %lu/%lu\n",
                swap_cache_info.add_total, swap_cache_info.del_total,
-               swap_cache_info.find_success, swap_cache_info.find_total,
-               swap_cache_info.noent_race, swap_cache_info.exist_race);
+               swap_cache_info.find_success, swap_cache_info.find_total);
        printk("Free swap  = %lukB\n", nr_swap_pages << (PAGE_SHIFT - 10));
        printk("Total swap = %lukB\n", total_swap_pages << (PAGE_SHIFT - 10));
 }
 
 /*
- * __add_to_swap_cache resembles add_to_page_cache on swapper_space,
+ * add_to_swap_cache resembles add_to_page_cache on swapper_space,
  * but sets SwapCache flag and private instead of mapping and index.
  */
-static int __add_to_swap_cache(struct page *page, swp_entry_t entry,
-                              gfp_t gfp_mask)
+int add_to_swap_cache(struct page *page, swp_entry_t entry, gfp_t gfp_mask)
 {
        int error;
 
@@ -88,6 +85,7 @@ static int __add_to_swap_cache(struct page *page, swp_entry_t entry,
                        set_page_private(page, entry.val);
                        total_swapcache_pages++;
                        __inc_zone_page_state(page, NR_FILE_PAGES);
+                       INC_CACHE_INFO(add_total);
                }
                write_unlock_irq(&swapper_space.tree_lock);
                radix_tree_preload_end();
@@ -95,31 +93,6 @@ static int __add_to_swap_cache(struct page *page, swp_entry_t entry,
        return error;
 }
 
-static int add_to_swap_cache(struct page *page, swp_entry_t entry)
-{
-       int error;
-
-       BUG_ON(PageLocked(page));
-       if (!swap_duplicate(entry)) {
-               INC_CACHE_INFO(noent_race);
-               return -ENOENT;
-       }
-       SetPageLocked(page);
-       error = __add_to_swap_cache(page, entry, GFP_KERNEL);
-       /*
-        * Anon pages are already on the LRU, we don't run lru_cache_add here.
-        */
-       if (error) {
-               ClearPageLocked(page);
-               swap_free(entry);
-               if (error == -EEXIST)
-                       INC_CACHE_INFO(exist_race);
-               return error;
-       }
-       INC_CACHE_INFO(add_total);
-       return 0;
-}
-
 /*
  * This must be called only on pages that have
  * been verified to be in the swap cache.
@@ -152,6 +125,7 @@ int add_to_swap(struct page * page, gfp_t gfp_mask)
        int err;
 
        BUG_ON(!PageLocked(page));
+       BUG_ON(!PageUptodate(page));
 
        for (;;) {
                entry = get_swap_page();
@@ -169,18 +143,15 @@ int add_to_swap(struct page * page, gfp_t gfp_mask)
                /*
                 * Add it to the swap cache and mark it dirty
                 */
-               err = __add_to_swap_cache(page, entry,
+               err = add_to_swap_cache(page, entry,
                                gfp_mask|__GFP_NOMEMALLOC|__GFP_NOWARN);
 
                switch (err) {
                case 0:                         /* Success */
-                       SetPageUptodate(page);
                        SetPageDirty(page);
-                       INC_CACHE_INFO(add_total);
                        return 1;
                case -EEXIST:
                        /* Raced with "speculative" read_swap_cache_async */
-                       INC_CACHE_INFO(exist_race);
                        swap_free(entry);
                        continue;
                default:
@@ -211,40 +182,6 @@ void delete_from_swap_cache(struct page *page)
        page_cache_release(page);
 }
 
-/*
- * Strange swizzling function only for use by shmem_writepage
- */
-int move_to_swap_cache(struct page *page, swp_entry_t entry)
-{
-       int err = __add_to_swap_cache(page, entry, GFP_ATOMIC);
-       if (!err) {
-               remove_from_page_cache(page);
-               page_cache_release(page);       /* pagecache ref */
-               if (!swap_duplicate(entry))
-                       BUG();
-               SetPageDirty(page);
-               INC_CACHE_INFO(add_total);
-       } else if (err == -EEXIST)
-               INC_CACHE_INFO(exist_race);
-       return err;
-}
-
-/*
- * Strange swizzling function for shmem_getpage (and shmem_unuse)
- */
-int move_from_swap_cache(struct page *page, unsigned long index,
-               struct address_space *mapping)
-{
-       int err = add_to_page_cache(page, mapping, index, GFP_ATOMIC);
-       if (!err) {
-               delete_from_swap_cache(page);
-               /* shift page from clean_pages to dirty_pages list */
-               ClearPageDirty(page);
-               set_page_dirty(page);
-       }
-       return err;
-}
-
 /* 
  * If we are the only user, then try to free up the swap cache. 
  * 
@@ -317,7 +254,7 @@ struct page * lookup_swap_cache(swp_entry_t entry)
  * A failure return means that either the page allocation failed or that
  * the swap entry is no longer in use.
  */
-struct page *read_swap_cache_async(swp_entry_t entry,
+struct page *read_swap_cache_async(swp_entry_t entry, gfp_t gfp_mask,
                        struct vm_area_struct *vma, unsigned long addr)
 {
        struct page *found_page, *new_page = NULL;
@@ -337,23 +274,27 @@ struct page *read_swap_cache_async(swp_entry_t entry,
                 * Get a new page to read into from swap.
                 */
                if (!new_page) {
-                       new_page = alloc_page_vma(GFP_HIGHUSER_MOVABLE,
-                                                               vma, addr);
+                       new_page = alloc_page_vma(gfp_mask, vma, addr);
                        if (!new_page)
                                break;          /* Out of memory */
                }
 
+               /*
+                * Swap entry may have been freed since our caller observed it.
+                */
+               if (!swap_duplicate(entry))
+                       break;
+
                /*
                 * Associate the page with swap entry in the swap cache.
-                * May fail (-ENOENT) if swap entry has been freed since
-                * our caller observed it.  May fail (-EEXIST) if there
-                * is already a page associated with this entry in the
-                * swap cache: added by a racing read_swap_cache_async,
-                * or by try_to_swap_out (or shmem_writepage) re-using
-                * the just freed swap entry for an existing page.
+                * May fail (-EEXIST) if there is already a page associated
+                * with this entry in the swap cache: added by a racing
+                * read_swap_cache_async, or add_to_swap or shmem_writepage
+                * re-using the just freed swap entry for an existing page.
                 * May fail (-ENOMEM) if radix-tree node allocation failed.
                 */
-               err = add_to_swap_cache(new_page, entry);
+               SetPageLocked(new_page);
+               err = add_to_swap_cache(new_page, entry, gfp_mask & GFP_KERNEL);
                if (!err) {
                        /*
                         * Initiate read into locked page and return.
@@ -362,9 +303,57 @@ struct page *read_swap_cache_async(swp_entry_t entry,
                        swap_readpage(NULL, new_page);
                        return new_page;
                }
-       } while (err != -ENOENT && err != -ENOMEM);
+               ClearPageLocked(new_page);
+               swap_free(entry);
+       } while (err != -ENOMEM);
 
        if (new_page)
                page_cache_release(new_page);
        return found_page;
 }
+
+/**
+ * swapin_readahead - swap in pages in hope we need them soon
+ * @entry: swap entry of this memory
+ * @vma: user vma this address belongs to
+ * @addr: target address for mempolicy
+ *
+ * Returns the struct page for entry and addr, after queueing swapin.
+ *
+ * Primitive swap readahead code. We simply read an aligned block of
+ * (1 << page_cluster) entries in the swap area. This method is chosen
+ * because it doesn't cost us any seek time.  We also make sure to queue
+ * the 'original' request together with the readahead ones...
+ *
+ * This has been extended to use the NUMA policies from the mm triggering
+ * the readahead.
+ *
+ * Caller must hold down_read on the vma->vm_mm if vma is not NULL.
+ */
+struct page *swapin_readahead(swp_entry_t entry, gfp_t gfp_mask,
+                       struct vm_area_struct *vma, unsigned long addr)
+{
+       int nr_pages;
+       struct page *page;
+       unsigned long offset;
+       unsigned long end_offset;
+
+       /*
+        * Get starting offset for readaround, and number of pages to read.
+        * Adjust starting address by readbehind (for NUMA interleave case)?
+        * No, it's very unlikely that swap layout would follow vma layout,
+        * more likely that neighbouring swap pages came from the same node:
+        * so use the same "addr" to choose the same node for each swap read.
+        */
+       nr_pages = valid_swaphandles(entry, &offset);
+       for (end_offset = offset + nr_pages; offset < end_offset; offset++) {
+               /* Ok, do the async read-ahead now */
+               page = read_swap_cache_async(swp_entry(swp_type(entry), offset),
+                                               gfp_mask, vma, addr);
+               if (!page)
+                       break;
+               page_cache_release(page);
+       }
+       lru_add_drain();        /* Push any new pages onto the LRU now */
+       return read_swap_cache_async(entry, gfp_mask, vma, addr);
+}
index f071648e1360823d06e83b1951a77f1c53a5f998..eade24da9310d4cc4e7499e5580d52fbb929701c 100644 (file)
@@ -506,9 +506,19 @@ unsigned int count_swap_pages(int type, int free)
  * just let do_wp_page work it out if a write is requested later - to
  * force COW, vm_page_prot omits write permission from any private vma.
  */
-static void unuse_pte(struct vm_area_struct *vma, pte_t *pte,
+static int unuse_pte(struct vm_area_struct *vma, pmd_t *pmd,
                unsigned long addr, swp_entry_t entry, struct page *page)
 {
+       spinlock_t *ptl;
+       pte_t *pte;
+       int found = 1;
+
+       pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl);
+       if (unlikely(!pte_same(*pte, swp_entry_to_pte(entry)))) {
+               found = 0;
+               goto out;
+       }
+
        inc_mm_counter(vma->vm_mm, anon_rss);
        get_page(page);
        set_pte_at(vma->vm_mm, addr, pte,
@@ -520,6 +530,9 @@ static void unuse_pte(struct vm_area_struct *vma, pte_t *pte,
         * immediately swapped out again after swapon.
         */
        activate_page(page);
+out:
+       pte_unmap_unlock(pte, ptl);
+       return found;
 }
 
 static int unuse_pte_range(struct vm_area_struct *vma, pmd_t *pmd,
@@ -528,22 +541,33 @@ static int unuse_pte_range(struct vm_area_struct *vma, pmd_t *pmd,
 {
        pte_t swp_pte = swp_entry_to_pte(entry);
        pte_t *pte;
-       spinlock_t *ptl;
        int found = 0;
 
-       pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl);
+       /*
+        * We don't actually need pte lock while scanning for swp_pte: since
+        * we hold page lock and mmap_sem, swp_pte cannot be inserted into the
+        * page table while we're scanning; though it could get zapped, and on
+        * some architectures (e.g. x86_32 with PAE) we might catch a glimpse
+        * of unmatched parts which look like swp_pte, so unuse_pte must
+        * recheck under pte lock.  Scanning without pte lock lets it be
+        * preemptible whenever CONFIG_PREEMPT but not CONFIG_HIGHPTE.
+        */
+       pte = pte_offset_map(pmd, addr);
        do {
                /*
                 * swapoff spends a _lot_ of time in this loop!
                 * Test inline before going to call unuse_pte.
                 */
                if (unlikely(pte_same(*pte, swp_pte))) {
-                       unuse_pte(vma, pte++, addr, entry, page);
-                       found = 1;
-                       break;
+                       pte_unmap(pte);
+                       found = unuse_pte(vma, pmd, addr, entry, page);
+                       if (found)
+                               goto out;
+                       pte = pte_offset_map(pmd, addr);
                }
        } while (pte++, addr += PAGE_SIZE, addr != end);
-       pte_unmap_unlock(pte - 1, ptl);
+       pte_unmap(pte - 1);
+out:
        return found;
 }
 
@@ -730,7 +754,8 @@ static int try_to_unuse(unsigned int type)
                 */
                swap_map = &si->swap_map[i];
                entry = swp_entry(type, i);
-               page = read_swap_cache_async(entry, NULL, 0);
+               page = read_swap_cache_async(entry,
+                                       GFP_HIGHUSER_MOVABLE, NULL, 0);
                if (!page) {
                        /*
                         * Either swap_duplicate() failed because entry
@@ -789,7 +814,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 &&
+                       while (*swap_map > 1 && !retval && !shmem &&
                                        (p = p->next) != &start_mm->mmlist) {
                                mm = list_entry(p, struct mm_struct, mmlist);
                                if (!atomic_inc_not_zero(&mm->mm_users))
@@ -821,6 +846,13 @@ static int try_to_unuse(unsigned int type)
                        mmput(start_mm);
                        start_mm = new_start_mm;
                }
+               if (shmem) {
+                       /* page has already been unlocked and released */
+                       if (shmem > 0)
+                               continue;
+                       retval = shmem;
+                       break;
+               }
                if (retval) {
                        unlock_page(page);
                        page_cache_release(page);
@@ -859,12 +891,6 @@ static int try_to_unuse(unsigned int type)
                 * read from disk into another page.  Splitting into two
                 * pages would be incorrect if swap supported "shared
                 * private" pages, but they are handled by tmpfs files.
-                *
-                * Note shmem_unuse already deleted a swappage from
-                * the swap cache, unless the move to filepage failed:
-                * in which case it left swappage in cache, lowered its
-                * swap count to pass quickly through the loops above,
-                * and now we must reincrement count to try again later.
                 */
                if ((*swap_map > 1) && PageDirty(page) && PageSwapCache(page)) {
                        struct writeback_control wbc = {
@@ -875,12 +901,8 @@ static int try_to_unuse(unsigned int type)
                        lock_page(page);
                        wait_on_page_writeback(page);
                }
-               if (PageSwapCache(page)) {
-                       if (shmem)
-                               swap_duplicate(entry);
-                       else
-                               delete_from_swap_cache(page);
-               }
+               if (PageSwapCache(page))
+                       delete_from_swap_cache(page);
 
                /*
                 * So we could skip searching mms once swap count went
@@ -1768,31 +1790,48 @@ get_swap_info_struct(unsigned type)
  */
 int valid_swaphandles(swp_entry_t entry, unsigned long *offset)
 {
+       struct swap_info_struct *si;
        int our_page_cluster = page_cluster;
-       int ret = 0, i = 1 << our_page_cluster;
-       unsigned long toff;
-       struct swap_info_struct *swapdev = swp_type(entry) + swap_info;
+       pgoff_t target, toff;
+       pgoff_t base, end;
+       int nr_pages = 0;
 
        if (!our_page_cluster)  /* no readahead */
                return 0;
-       toff = (swp_offset(entry) >> our_page_cluster) << our_page_cluster;
-       if (!toff)              /* first page is swap header */
-               toff++, i--;
-       *offset = toff;
+
+       si = &swap_info[swp_type(entry)];
+       target = swp_offset(entry);
+       base = (target >> our_page_cluster) << our_page_cluster;
+       end = base + (1 << our_page_cluster);
+       if (!base)              /* first page is swap header */
+               base++;
 
        spin_lock(&swap_lock);
-       do {
-               /* Don't read-ahead past the end of the swap area */
-               if (toff >= swapdev->max)
+       if (end > si->max)      /* don't go beyond end of map */
+               end = si->max;
+
+       /* Count contiguous allocated slots above our target */
+       for (toff = target; ++toff < end; nr_pages++) {
+               /* Don't read in free or bad pages */
+               if (!si->swap_map[toff])
+                       break;
+               if (si->swap_map[toff] == SWAP_MAP_BAD)
                        break;
+       }
+       /* Count contiguous allocated slots below our target */
+       for (toff = target; --toff >= base; nr_pages++) {
                /* Don't read in free or bad pages */
-               if (!swapdev->swap_map[toff])
+               if (!si->swap_map[toff])
                        break;
-               if (swapdev->swap_map[toff] == SWAP_MAP_BAD)
+               if (si->swap_map[toff] == SWAP_MAP_BAD)
                        break;
-               toff++;
-               ret++;
-       } while (--i);
+       }
        spin_unlock(&swap_lock);
-       return ret;
+
+       /*
+        * Indicate starting offset, and return number of pages to get:
+        * if only 1, say 0, since there's then no readahead to be done.
+        */
+       *offset = ++toff;
+       return nr_pages? ++nr_pages: 0;
 }
index d436a9c82db7739618dee05886c0088aaea7728a..702083638c16d9a4a6878048f999f58c889fdd92 100644 (file)
@@ -121,18 +121,6 @@ int shmem_unuse(swp_entry_t entry, struct page *page)
        return 0;
 }
 
-#if 0
-int shmem_mmap(struct file *file, struct vm_area_struct *vma)
-{
-       file_accessed(file);
-#ifndef CONFIG_MMU
-       return ramfs_nommu_mmap(file, vma);
-#else
-       return 0;
-#endif
-}
-#endif  /*  0  */
-
 #ifndef CONFIG_MMU
 unsigned long shmem_get_unmapped_area(struct file *file,
                                      unsigned long addr,
index cadc15653ddeeaa311c80f794b6a564ae2f36fc8..c35c49e54fb6527eae91cb02177fc2b05a00abad 100644 (file)
@@ -21,7 +21,7 @@
 
 
 /**
- * do_invalidatepage - invalidate part of all of a page
+ * do_invalidatepage - invalidate part or all of a page
  * @page: the page which is affected
  * @offset: the index of the truncation point
  *
@@ -48,7 +48,7 @@ void do_invalidatepage(struct page *page, unsigned long offset)
 
 static inline void truncate_partial_page(struct page *page, unsigned partial)
 {
-       zero_user_page(page, partial, PAGE_CACHE_SIZE - partial, KM_USER0);
+       zero_user_segment(page, partial, PAGE_CACHE_SIZE);
        if (PagePrivate(page))
                do_invalidatepage(page, partial);
 }
@@ -84,7 +84,7 @@ EXPORT_SYMBOL(cancel_dirty_page);
 
 /*
  * If truncate cannot remove the fs-private metadata from the page, the page
- * becomes anonymous.  It will be left on the LRU and may even be mapped into
+ * becomes orphaned.  It will be left on the LRU and may even be mapped into
  * user pagetables if we're racing with filemap_fault().
  *
  * We need to bale out if page->mapping is no longer equal to the original
@@ -98,11 +98,11 @@ truncate_complete_page(struct address_space *mapping, struct page *page)
        if (page->mapping != mapping)
                return;
 
-       cancel_dirty_page(page, PAGE_CACHE_SIZE);
-
        if (PagePrivate(page))
                do_invalidatepage(page, 0);
 
+       cancel_dirty_page(page, PAGE_CACHE_SIZE);
+
        remove_from_page_cache(page);
        ClearPageUptodate(page);
        ClearPageMappedToDisk(page);
index af77e171e339a357933d7eb6ba4b001efae5e390..0536dde139d1e1f6f28fc93ccd05a9fc337e2c7e 100644 (file)
@@ -166,6 +166,44 @@ int map_vm_area(struct vm_struct *area, pgprot_t prot, struct page ***pages)
 }
 EXPORT_SYMBOL_GPL(map_vm_area);
 
+/*
+ * Map a vmalloc()-space virtual address to the physical page.
+ */
+struct page *vmalloc_to_page(const void *vmalloc_addr)
+{
+       unsigned long addr = (unsigned long) vmalloc_addr;
+       struct page *page = NULL;
+       pgd_t *pgd = pgd_offset_k(addr);
+       pud_t *pud;
+       pmd_t *pmd;
+       pte_t *ptep, pte;
+
+       if (!pgd_none(*pgd)) {
+               pud = pud_offset(pgd, addr);
+               if (!pud_none(*pud)) {
+                       pmd = pmd_offset(pud, addr);
+                       if (!pmd_none(*pmd)) {
+                               ptep = pte_offset_map(pmd, addr);
+                               pte = *ptep;
+                               if (pte_present(pte))
+                                       page = pte_page(pte);
+                               pte_unmap(ptep);
+                       }
+               }
+       }
+       return page;
+}
+EXPORT_SYMBOL(vmalloc_to_page);
+
+/*
+ * Map a vmalloc()-space virtual address to the physical page frame number.
+ */
+unsigned long vmalloc_to_pfn(const void *vmalloc_addr)
+{
+       return page_to_pfn(vmalloc_to_page(vmalloc_addr));
+}
+EXPORT_SYMBOL(vmalloc_to_pfn);
+
 static struct vm_struct *__get_vm_area_node(unsigned long size, unsigned long flags,
                                            unsigned long start, unsigned long end,
                                            int node, gfp_t gfp_mask)
@@ -216,6 +254,10 @@ static struct vm_struct *__get_vm_area_node(unsigned long size, unsigned long fl
                if (addr > end - size)
                        goto out;
        }
+       if ((size + addr) < addr)
+               goto out;
+       if (addr > end - size)
+               goto out;
 
 found:
        area->next = *p;
@@ -268,7 +310,7 @@ struct vm_struct *get_vm_area_node(unsigned long size, unsigned long flags,
 }
 
 /* Caller must hold vmlist_lock */
-static struct vm_struct *__find_vm_area(void *addr)
+static struct vm_struct *__find_vm_area(const void *addr)
 {
        struct vm_struct *tmp;
 
@@ -281,7 +323,7 @@ static struct vm_struct *__find_vm_area(void *addr)
 }
 
 /* Caller must hold vmlist_lock */
-static struct vm_struct *__remove_vm_area(void *addr)
+static struct vm_struct *__remove_vm_area(const void *addr)
 {
        struct vm_struct **p, *tmp;
 
@@ -310,7 +352,7 @@ found:
  *     This function returns the found VM area, but using it is NOT safe
  *     on SMP machines, except for its size or flags.
  */
-struct vm_struct *remove_vm_area(void *addr)
+struct vm_struct *remove_vm_area(const void *addr)
 {
        struct vm_struct *v;
        write_lock(&vmlist_lock);
@@ -319,7 +361,7 @@ struct vm_struct *remove_vm_area(void *addr)
        return v;
 }
 
-static void __vunmap(void *addr, int deallocate_pages)
+static void __vunmap(const void *addr, int deallocate_pages)
 {
        struct vm_struct *area;
 
@@ -346,8 +388,10 @@ static void __vunmap(void *addr, int deallocate_pages)
                int i;
 
                for (i = 0; i < area->nr_pages; i++) {
-                       BUG_ON(!area->pages[i]);
-                       __free_page(area->pages[i]);
+                       struct page *page = area->pages[i];
+
+                       BUG_ON(!page);
+                       __free_page(page);
                }
 
                if (area->flags & VM_VPAGES)
@@ -370,7 +414,7 @@ static void __vunmap(void *addr, int deallocate_pages)
  *
  *     Must not be called in interrupt context.
  */
-void vfree(void *addr)
+void vfree(const void *addr)
 {
        BUG_ON(in_interrupt());
        __vunmap(addr, 1);
@@ -386,7 +430,7 @@ EXPORT_SYMBOL(vfree);
  *
  *     Must not be called in interrupt context.
  */
-void vunmap(void *addr)
+void vunmap(const void *addr)
 {
        BUG_ON(in_interrupt());
        __vunmap(addr, 0);
@@ -423,8 +467,8 @@ void *vmap(struct page **pages, unsigned int count,
 }
 EXPORT_SYMBOL(vmap);
 
-void *__vmalloc_area_node(struct vm_struct *area, gfp_t gfp_mask,
-                               pgprot_t prot, int node)
+static void *__vmalloc_area_node(struct vm_struct *area, gfp_t gfp_mask,
+                                pgprot_t prot, int node)
 {
        struct page **pages;
        unsigned int nr_pages, array_size, i;
@@ -451,15 +495,19 @@ void *__vmalloc_area_node(struct vm_struct *area, gfp_t gfp_mask,
        }
 
        for (i = 0; i < area->nr_pages; i++) {
+               struct page *page;
+
                if (node < 0)
-                       area->pages[i] = alloc_page(gfp_mask);
+                       page = alloc_page(gfp_mask);
                else
-                       area->pages[i] = alloc_pages_node(node, gfp_mask, 0);
-               if (unlikely(!area->pages[i])) {
+                       page = alloc_pages_node(node, gfp_mask, 0);
+
+               if (unlikely(!page)) {
                        /* Successfully allocated i pages, free them in __vunmap() */
                        area->nr_pages = i;
                        goto fail;
                }
+               area->pages[i] = page;
        }
 
        if (map_vm_area(area, prot, &pages))
index e8d846f57774ee631adc5836aeaa6498b39736a0..422d960ffcd892ae63087b9179354832c14c1f20 100644 (file)
@@ -21,21 +21,14 @@ EXPORT_PER_CPU_SYMBOL(vm_event_states);
 
 static void sum_vm_events(unsigned long *ret, cpumask_t *cpumask)
 {
-       int cpu = 0;
+       int cpu;
        int i;
 
        memset(ret, 0, NR_VM_EVENT_ITEMS * sizeof(unsigned long));
 
-       cpu = first_cpu(*cpumask);
-       while (cpu < NR_CPUS) {
+       for_each_cpu_mask(cpu, *cpumask) {
                struct vm_event_state *this = &per_cpu(vm_event_states, cpu);
 
-               cpu = next_cpu(cpu, *cpumask);
-
-               if (cpu < NR_CPUS)
-                       prefetch(&per_cpu(vm_event_states, cpu));
-
-
                for (i = 0; i < NR_VM_EVENT_ITEMS; i++)
                        ret[i] += this->event[i];
        }
@@ -284,6 +277,10 @@ EXPORT_SYMBOL(dec_zone_page_state);
 /*
  * Update the zone counters for one cpu.
  *
+ * The cpu specified must be either the current cpu or a processor that
+ * is not online. If it is the current cpu then the execution thread must
+ * be pinned to the current cpu.
+ *
  * Note that refresh_cpu_vm_stats strives to only access
  * node local memory. The per cpu pagesets on remote zones are placed
  * in the memory local to the processor using that pageset. So the
@@ -299,7 +296,7 @@ void refresh_cpu_vm_stats(int cpu)
 {
        struct zone *zone;
        int i;
-       unsigned long flags;
+       int global_diff[NR_VM_ZONE_STAT_ITEMS] = { 0, };
 
        for_each_zone(zone) {
                struct per_cpu_pageset *p;
@@ -311,15 +308,19 @@ void refresh_cpu_vm_stats(int cpu)
 
                for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++)
                        if (p->vm_stat_diff[i]) {
+                               unsigned long flags;
+                               int v;
+
                                local_irq_save(flags);
-                               zone_page_state_add(p->vm_stat_diff[i],
-                                       zone, i);
+                               v = p->vm_stat_diff[i];
                                p->vm_stat_diff[i] = 0;
+                               local_irq_restore(flags);
+                               atomic_long_add(v, &zone->vm_stat[i]);
+                               global_diff[i] += v;
 #ifdef CONFIG_NUMA
                                /* 3 seconds idle till flush */
                                p->expire = 3;
 #endif
-                               local_irq_restore(flags);
                        }
 #ifdef CONFIG_NUMA
                /*
@@ -329,7 +330,7 @@ void refresh_cpu_vm_stats(int cpu)
                 * Check if there are pages remaining in this pageset
                 * if not then there is nothing to expire.
                 */
-               if (!p->expire || (!p->pcp[0].count && !p->pcp[1].count))
+               if (!p->expire || !p->pcp.count)
                        continue;
 
                /*
@@ -344,13 +345,14 @@ void refresh_cpu_vm_stats(int cpu)
                if (p->expire)
                        continue;
 
-               if (p->pcp[0].count)
-                       drain_zone_pages(zone, p->pcp + 0);
-
-               if (p->pcp[1].count)
-                       drain_zone_pages(zone, p->pcp + 1);
+               if (p->pcp.count)
+                       drain_zone_pages(zone, &p->pcp);
 #endif
        }
+
+       for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++)
+               if (global_diff[i])
+                       atomic_long_add(global_diff[i], &vm_stat[i]);
 }
 
 #endif
@@ -681,20 +683,17 @@ static void zoneinfo_show_print(struct seq_file *m, pg_data_t *pgdat,
                   "\n  pagesets");
        for_each_online_cpu(i) {
                struct per_cpu_pageset *pageset;
-               int j;
 
                pageset = zone_pcp(zone, i);
-               for (j = 0; j < ARRAY_SIZE(pageset->pcp); j++) {
-                       seq_printf(m,
-                                  "\n    cpu: %i pcp: %i"
-                                  "\n              count: %i"
-                                  "\n              high:  %i"
-                                  "\n              batch: %i",
-                                  i, j,
-                                  pageset->pcp[j].count,
-                                  pageset->pcp[j].high,
-                                  pageset->pcp[j].batch);
-                       }
+               seq_printf(m,
+                          "\n    cpu: %i"
+                          "\n              count: %i"
+                          "\n              high:  %i"
+                          "\n              batch: %i",
+                          i,
+                          pageset->pcp.count,
+                          pageset->pcp.high,
+                          pageset->pcp.batch);
 #ifdef CONFIG_SMP
                seq_printf(m, "\n  vm stats threshold: %d",
                                pageset->stat_threshold);
index 3f16b1720554ffc147ff634b7f1564d871ab10fb..18c66475d8c39f8cd9c28a4d5ea0a0b5bc84491e 100644 (file)
@@ -76,7 +76,7 @@ static DEFINE_SPINLOCK(rif_lock);
 
 static struct timer_list rif_timer;
 
-int sysctl_tr_rif_timeout = 60*10*HZ;
+static int sysctl_tr_rif_timeout = 60*10*HZ;
 
 static inline unsigned long rif_hash(const unsigned char *addr)
 {
index 8059fa42b0859a1217946d91fde310d21baaba32..77f04e49a1a077013d2be6a1acd8f32c65559dc5 100644 (file)
@@ -563,6 +563,7 @@ static int vlan_dev_stop(struct net_device *dev)
        struct net_device *real_dev = vlan_dev_info(dev)->real_dev;
 
        dev_mc_unsync(real_dev, dev);
+       dev_unicast_unsync(real_dev, dev);
        if (dev->flags & IFF_ALLMULTI)
                dev_set_allmulti(real_dev, -1);
        if (dev->flags & IFF_PROMISC)
@@ -634,9 +635,10 @@ static void vlan_dev_change_rx_flags(struct net_device *dev, int change)
                dev_set_promiscuity(real_dev, dev->flags & IFF_PROMISC ? 1 : -1);
 }
 
-static void vlan_dev_set_multicast_list(struct net_device *vlan_dev)
+static void vlan_dev_set_rx_mode(struct net_device *vlan_dev)
 {
        dev_mc_sync(vlan_dev_info(vlan_dev)->real_dev, vlan_dev);
+       dev_unicast_sync(vlan_dev_info(vlan_dev)->real_dev, vlan_dev);
 }
 
 /*
@@ -702,7 +704,8 @@ void vlan_setup(struct net_device *dev)
        dev->open               = vlan_dev_open;
        dev->stop               = vlan_dev_stop;
        dev->set_mac_address    = vlan_dev_set_mac_address;
-       dev->set_multicast_list = vlan_dev_set_multicast_list;
+       dev->set_rx_mode        = vlan_dev_set_rx_mode;
+       dev->set_multicast_list = vlan_dev_set_rx_mode;
        dev->change_rx_flags    = vlan_dev_change_rx_flags;
        dev->do_ioctl           = vlan_dev_ioctl;
        dev->destructor         = free_netdev;
index aa2aa9884f955d37b6c7bd2c4d6923dccf2932f6..3fe35d532c87a0c2f17afb2baf961077a954f96e 100644 (file)
@@ -128,11 +128,6 @@ static char *buf_put_stringn(struct cbuf *buf, const char *s, u16 slen)
        return ret;
 }
 
-static inline void buf_put_string(struct cbuf *buf, const char *s)
-{
-       buf_put_stringn(buf, s, strlen(s));
-}
-
 static u8 buf_get_int8(struct cbuf *buf)
 {
        u8 ret = 0;
index 40b71a29fc3faa11b8360ddab2d3fbcc6fe29276..42eea5fe262895587522ac689b1f06d2cf7ad7a1 100644 (file)
@@ -199,14 +199,12 @@ static void p9_virtio_close(struct p9_trans *trans)
        kfree(trans);
 }
 
-static bool p9_virtio_intr(struct virtqueue *q)
+static void p9_virtio_intr(struct virtqueue *q)
 {
        struct virtio_chan *chan = q->vdev->priv;
 
        P9_DPRINTK(P9_DEBUG_TRANS, "9p poll_wakeup: %p\n", &chan->wq);
        wake_up_interruptible(&chan->wq);
-
-       return true;
 }
 
 static int p9_virtio_probe(struct virtio_device *dev)
@@ -236,13 +234,13 @@ static int p9_virtio_probe(struct virtio_device *dev)
 
        /* Find the input queue. */
        dev->priv = chan;
-       chan->in_vq = dev->config->find_vq(dev, p9_virtio_intr);
+       chan->in_vq = dev->config->find_vq(dev, 0, p9_virtio_intr);
        if (IS_ERR(chan->in_vq)) {
                err = PTR_ERR(chan->in_vq);
                goto free;
        }
 
-       chan->out_vq = dev->config->find_vq(dev, NULL);
+       chan->out_vq = dev->config->find_vq(dev, 1, NULL);
        if (IS_ERR(chan->out_vq)) {
                err = PTR_ERR(chan->out_vq);
                goto free_in_vq;
index 1bc0e85f04a5112afbfa5be6140d59ba4f38f2b0..8fc64e3150a26cd437aeee127806cab19cda110d 100644 (file)
@@ -1037,16 +1037,13 @@ static int ax25_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
        int err = 0;
 
        if (addr_len != sizeof(struct sockaddr_ax25) &&
-           addr_len != sizeof(struct full_sockaddr_ax25)) {
-               /* support for old structure may go away some time */
+           addr_len != sizeof(struct full_sockaddr_ax25))
+               /* support for old structure may go away some time
+                * ax25_bind(): uses old (6 digipeater) socket structure.
+                */
                if ((addr_len < sizeof(struct sockaddr_ax25) + sizeof(ax25_address) * 6) ||
-                   (addr_len > sizeof(struct full_sockaddr_ax25))) {
+                   (addr_len > sizeof(struct full_sockaddr_ax25)))
                        return -EINVAL;
-       }
-
-               printk(KERN_WARNING "ax25_bind(): %s uses old (6 digipeater) socket structure.\n",
-                       current->comm);
-       }
 
        if (addr->fsa_ax25.sax25_family != AF_AX25)
                return -EINVAL;
index 17f7fb7205535ce35f0fc9a7b96cdbf9d261c820..e13cf5ef144cd59a8a8f7eee15ae24d7826020ba 100644 (file)
@@ -12,6 +12,8 @@
 #undef  BT_DBG
 #define BT_DBG(D...)
 #endif
+static struct workqueue_struct *btaddconn;
+static struct workqueue_struct *btdelconn;
 
 static inline char *typetostr(int type)
 {
@@ -279,6 +281,8 @@ static void add_conn(struct work_struct *work)
        struct hci_conn *conn = container_of(work, struct hci_conn, work);
        int i;
 
+       flush_workqueue(btdelconn);
+
        if (device_add(&conn->dev) < 0) {
                BT_ERR("Failed to register connection device");
                return;
@@ -313,7 +317,7 @@ void hci_conn_add_sysfs(struct hci_conn *conn)
 
        INIT_WORK(&conn->work, add_conn);
 
-       schedule_work(&conn->work);
+       queue_work(btaddconn, &conn->work);
 }
 
 static int __match_tty(struct device *dev, void *data)
@@ -349,7 +353,7 @@ void hci_conn_del_sysfs(struct hci_conn *conn)
 
        INIT_WORK(&conn->work, del_conn);
 
-       schedule_work(&conn->work);
+       queue_work(btdelconn, &conn->work);
 }
 
 int hci_register_sysfs(struct hci_dev *hdev)
@@ -398,28 +402,54 @@ int __init bt_sysfs_init(void)
 {
        int err;
 
+       btaddconn = create_singlethread_workqueue("btaddconn");
+       if (!btaddconn) {
+               err = -ENOMEM;
+               goto out;
+       }
+
+       btdelconn = create_singlethread_workqueue("btdelconn");
+       if (!btdelconn) {
+               err = -ENOMEM;
+               goto out_del;
+       }
+
        bt_platform = platform_device_register_simple("bluetooth", -1, NULL, 0);
-       if (IS_ERR(bt_platform))
-               return PTR_ERR(bt_platform);
+       if (IS_ERR(bt_platform)) {
+               err = PTR_ERR(bt_platform);
+               goto out_platform;
+       }
 
        err = bus_register(&bt_bus);
-       if (err < 0) {
-               platform_device_unregister(bt_platform);
-               return err;
-       }
+       if (err < 0)
+               goto out_bus;
 
        bt_class = class_create(THIS_MODULE, "bluetooth");
        if (IS_ERR(bt_class)) {
-               bus_unregister(&bt_bus);
-               platform_device_unregister(bt_platform);
-               return PTR_ERR(bt_class);
+               err = PTR_ERR(bt_class);
+               goto out_class;
        }
 
        return 0;
+
+out_class:
+       bus_unregister(&bt_bus);
+out_bus:
+       platform_device_unregister(bt_platform);
+out_platform:
+       destroy_workqueue(btdelconn);
+out_del:
+       destroy_workqueue(btaddconn);
+out:
+       return err;
 }
 
 void bt_sysfs_cleanup(void)
 {
+       destroy_workqueue(btaddconn);
+
+       destroy_workqueue(btdelconn);
+
        class_destroy(bt_class);
 
        bus_unregister(&bt_bus);
index 782a22602b86cb9bca1838ee7758adbfcd0984f6..519cdb920f936bb7882d8400bccb8105c5d0d4f5 100644 (file)
@@ -135,8 +135,8 @@ static void __hidp_copy_session(struct hidp_session *session, struct hidp_connin
        }
 }
 
-static inline int hidp_queue_event(struct hidp_session *session, struct input_dev *dev,
-                                       unsigned int type, unsigned int code, int value)
+static int hidp_queue_event(struct hidp_session *session, struct input_dev *dev,
+                               unsigned int type, unsigned int code, int value)
 {
        unsigned char newleds;
        struct sk_buff *skb;
@@ -243,7 +243,8 @@ static void hidp_input_report(struct hidp_session *session, struct sk_buff *skb)
        input_sync(dev);
 }
 
-static inline int hidp_queue_report(struct hidp_session *session, unsigned char *data, int size)
+static int hidp_queue_report(struct hidp_session *session,
+                               unsigned char *data, int size)
 {
        struct sk_buff *skb;
 
@@ -287,7 +288,7 @@ static void hidp_idle_timeout(unsigned long arg)
        hidp_schedule(session);
 }
 
-static inline void hidp_set_timer(struct hidp_session *session)
+static void hidp_set_timer(struct hidp_session *session)
 {
        if (session->idle_to > 0)
                mod_timer(&session->timer, jiffies + HZ * session->idle_to);
@@ -332,7 +333,8 @@ static inline int hidp_send_ctrl_message(struct hidp_session *session,
        return err;
 }
 
-static inline void hidp_process_handshake(struct hidp_session *session, unsigned char param)
+static void hidp_process_handshake(struct hidp_session *session,
+                                       unsigned char param)
 {
        BT_DBG("session %p param 0x%02x", session, param);
 
@@ -365,38 +367,23 @@ static inline void hidp_process_handshake(struct hidp_session *session, unsigned
        }
 }
 
-static inline void hidp_process_hid_control(struct hidp_session *session, unsigned char param)
+static void hidp_process_hid_control(struct hidp_session *session,
+                                       unsigned char param)
 {
        BT_DBG("session %p param 0x%02x", session, param);
 
-       switch (param) {
-       case HIDP_CTRL_NOP:
-               break;
-
-       case HIDP_CTRL_VIRTUAL_CABLE_UNPLUG:
+       if (param == HIDP_CTRL_VIRTUAL_CABLE_UNPLUG) {
                /* Flush the transmit queues */
                skb_queue_purge(&session->ctrl_transmit);
                skb_queue_purge(&session->intr_transmit);
 
                /* Kill session thread */
                atomic_inc(&session->terminate);
-               break;
-
-       case HIDP_CTRL_HARD_RESET:
-       case HIDP_CTRL_SOFT_RESET:
-       case HIDP_CTRL_SUSPEND:
-       case HIDP_CTRL_EXIT_SUSPEND:
-               /* FIXME: We have to parse these and return no error */
-               break;
-
-       default:
-               __hidp_send_ctrl_message(session,
-                       HIDP_TRANS_HANDSHAKE | HIDP_HSHK_ERR_INVALID_PARAMETER, NULL, 0);
-               break;
        }
 }
 
-static inline void hidp_process_data(struct hidp_session *session, struct sk_buff *skb, unsigned char param)
+static void hidp_process_data(struct hidp_session *session, struct sk_buff *skb,
+                               unsigned char param)
 {
        BT_DBG("session %p skb %p len %d param 0x%02x", session, skb, skb->len, param);
 
@@ -423,7 +410,8 @@ static inline void hidp_process_data(struct hidp_session *session, struct sk_buf
        }
 }
 
-static inline void hidp_recv_ctrl_frame(struct hidp_session *session, struct sk_buff *skb)
+static void hidp_recv_ctrl_frame(struct hidp_session *session,
+                                       struct sk_buff *skb)
 {
        unsigned char hdr, type, param;
 
@@ -457,7 +445,8 @@ static inline void hidp_recv_ctrl_frame(struct hidp_session *session, struct sk_
        kfree_skb(skb);
 }
 
-static inline void hidp_recv_intr_frame(struct hidp_session *session, struct sk_buff *skb)
+static void hidp_recv_intr_frame(struct hidp_session *session,
+                               struct sk_buff *skb)
 {
        unsigned char hdr;
 
@@ -625,7 +614,8 @@ static struct device *hidp_get_device(struct hidp_session *session)
        return conn ? &conn->dev : NULL;
 }
 
-static inline int hidp_setup_input(struct hidp_session *session, struct hidp_connadd_req *req)
+static int hidp_setup_input(struct hidp_session *session,
+                               struct hidp_connadd_req *req)
 {
        struct input_dev *input = session->input;
        int i;
@@ -702,7 +692,8 @@ static void hidp_setup_quirks(struct hid_device *hid)
                        hid->quirks = hidp_blacklist[n].quirks;
 }
 
-static inline void hidp_setup_hid(struct hidp_session *session, struct hidp_connadd_req *req)
+static void hidp_setup_hid(struct hidp_session *session,
+                               struct hidp_connadd_req *req)
 {
        struct hid_device *hid = session->hid;
        struct hid_report *report;
index 788c70321858f39576867de05e4ec2c885d9445e..e4c779bb8d76e6cf9dfab3b82a3ae33f7276dc68 100644 (file)
@@ -429,7 +429,8 @@ static int rfcomm_release_dev(void __user *arg)
        if (dev->tty)
                tty_vhangup(dev->tty);
 
-       rfcomm_dev_del(dev);
+       if (!test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags))
+               rfcomm_dev_del(dev);
        rfcomm_dev_put(dev);
        return 0;
 }
index 80014bab81b0afdb43b02ea5724afe24e747a546..1c0efd8ad9f311ef2ed676891d5b0c28a858d1fa 100644 (file)
@@ -828,10 +828,6 @@ static unsigned int br_nf_post_routing(unsigned int hook, struct sk_buff *skb,
        nf_bridge_pull_encap_header(skb);
        nf_bridge_save_header(skb);
 
-#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
-       if (nf_bridge->netoutdev)
-               realoutdev = nf_bridge->netoutdev;
-#endif
        NF_HOOK(pf, NF_INET_POST_ROUTING, skb, NULL, realoutdev,
                br_nf_dev_queue_xmit);
 
index 41a78072cd0eb1f4eed32752b2708ee6369788ee..98534025360f8a4d8c45766921a2791fc80d2218 100644 (file)
@@ -15,8 +15,8 @@
 static int ebt_filter_802_3(const struct sk_buff *skb, const struct net_device *in,
    const struct net_device *out, const void *data, unsigned int datalen)
 {
-       struct ebt_802_3_info *info = (struct ebt_802_3_info *)data;
-       struct ebt_802_3_hdr *hdr = ebt_802_3_hdr(skb);
+       const struct ebt_802_3_info *info = data;
+       const struct ebt_802_3_hdr *hdr = ebt_802_3_hdr(skb);
        __be16 type = hdr->llc.ui.ctrl & IS_UI ? hdr->llc.ui.type : hdr->llc.ni.type;
 
        if (info->bitmask & EBT_802_3_SAP) {
@@ -40,7 +40,7 @@ static struct ebt_match filter_802_3;
 static int ebt_802_3_check(const char *tablename, unsigned int hookmask,
    const struct ebt_entry *e, void *data, unsigned int datalen)
 {
-       struct ebt_802_3_info *info = (struct ebt_802_3_info *)data;
+       const struct ebt_802_3_info *info = data;
 
        if (datalen < sizeof(struct ebt_802_3_info))
                return -EINVAL;
@@ -50,8 +50,7 @@ static int ebt_802_3_check(const char *tablename, unsigned int hookmask,
        return 0;
 }
 
-static struct ebt_match filter_802_3 =
-{
+static struct ebt_match filter_802_3 __read_mostly = {
        .name           = EBT_802_3_MATCH,
        .match          = ebt_filter_802_3,
        .check          = ebt_802_3_check,
@@ -70,4 +69,5 @@ static void __exit ebt_802_3_fini(void)
 
 module_init(ebt_802_3_init);
 module_exit(ebt_802_3_fini);
+MODULE_DESCRIPTION("Ebtables: DSAP/SSAP field and SNAP type matching");
 MODULE_LICENSE("GPL");
index 6436d30a550eac56f42a2d2a8a44aab7295cb9fa..70b6dca5ea755502a74e294546156a8bea345509 100644 (file)
@@ -25,7 +25,7 @@ static int ebt_mac_wormhash_contains(const struct ebt_mac_wormhash *wh,
        const struct ebt_mac_wormhash_tuple *p;
        int start, limit, i;
        uint32_t cmp[2] = { 0, 0 };
-       int key = (const unsigned char) mac[5];
+       int key = ((const unsigned char *)mac)[5];
 
        memcpy(((char *) cmp) + 2, mac, 6);
        start = wh->table[key];
@@ -73,15 +73,18 @@ static int ebt_mac_wormhash_check_integrity(const struct ebt_mac_wormhash
 static int get_ip_dst(const struct sk_buff *skb, __be32 *addr)
 {
        if (eth_hdr(skb)->h_proto == htons(ETH_P_IP)) {
-               struct iphdr _iph, *ih;
+               const struct iphdr *ih;
+               struct iphdr _iph;
 
                ih = skb_header_pointer(skb, 0, sizeof(_iph), &_iph);
                if (ih == NULL)
                        return -1;
                *addr = ih->daddr;
        } else if (eth_hdr(skb)->h_proto == htons(ETH_P_ARP)) {
-               struct arphdr _arph, *ah;
-               __be32 buf, *bp;
+               const struct arphdr *ah;
+               struct arphdr _arph;
+               const __be32 *bp;
+               __be32 buf;
 
                ah = skb_header_pointer(skb, 0, sizeof(_arph), &_arph);
                if (ah == NULL ||
@@ -101,15 +104,18 @@ static int get_ip_dst(const struct sk_buff *skb, __be32 *addr)
 static int get_ip_src(const struct sk_buff *skb, __be32 *addr)
 {
        if (eth_hdr(skb)->h_proto == htons(ETH_P_IP)) {
-               struct iphdr _iph, *ih;
+               const struct iphdr *ih;
+               struct iphdr _iph;
 
                ih = skb_header_pointer(skb, 0, sizeof(_iph), &_iph);
                if (ih == NULL)
                        return -1;
                *addr = ih->saddr;
        } else if (eth_hdr(skb)->h_proto == htons(ETH_P_ARP)) {
-               struct arphdr _arph, *ah;
-               __be32 buf, *bp;
+               const struct arphdr *ah;
+               struct arphdr _arph;
+               const __be32 *bp;
+               __be32 buf;
 
                ah = skb_header_pointer(skb, 0, sizeof(_arph), &_arph);
                if (ah == NULL ||
@@ -130,7 +136,7 @@ static int ebt_filter_among(const struct sk_buff *skb,
                            const struct net_device *out, const void *data,
                            unsigned int datalen)
 {
-       struct ebt_among_info *info = (struct ebt_among_info *) data;
+       const struct ebt_among_info *info = data;
        const char *dmac, *smac;
        const struct ebt_mac_wormhash *wh_dst, *wh_src;
        __be32 dip = 0, sip = 0;
@@ -175,7 +181,7 @@ static int ebt_among_check(const char *tablename, unsigned int hookmask,
                           const struct ebt_entry *e, void *data,
                           unsigned int datalen)
 {
-       struct ebt_among_info *info = (struct ebt_among_info *) data;
+       const struct ebt_among_info *info = data;
        int expected_length = sizeof(struct ebt_among_info);
        const struct ebt_mac_wormhash *wh_dst, *wh_src;
        int err;
@@ -206,7 +212,7 @@ static int ebt_among_check(const char *tablename, unsigned int hookmask,
        return 0;
 }
 
-static struct ebt_match filter_among = {
+static struct ebt_match filter_among __read_mostly = {
        .name           = EBT_AMONG_MATCH,
        .match          = ebt_filter_among,
        .check          = ebt_among_check,
@@ -225,4 +231,5 @@ static void __exit ebt_among_fini(void)
 
 module_init(ebt_among_init);
 module_exit(ebt_among_fini);
+MODULE_DESCRIPTION("Ebtables: Combined MAC/IP address list matching");
 MODULE_LICENSE("GPL");
index 18141392a9b4eb87a45afc11902ae89249c7e7ac..7c535be75665ce8dd32c23818c866ed972601976 100644 (file)
@@ -18,8 +18,9 @@
 static int ebt_filter_arp(const struct sk_buff *skb, const struct net_device *in,
    const struct net_device *out, const void *data, unsigned int datalen)
 {
-       struct ebt_arp_info *info = (struct ebt_arp_info *)data;
-       struct arphdr _arph, *ah;
+       const struct ebt_arp_info *info = data;
+       const struct arphdr *ah;
+       struct arphdr _arph;
 
        ah = skb_header_pointer(skb, 0, sizeof(_arph), &_arph);
        if (ah == NULL)
@@ -35,7 +36,8 @@ static int ebt_filter_arp(const struct sk_buff *skb, const struct net_device *in
                return EBT_NOMATCH;
 
        if (info->bitmask & (EBT_ARP_SRC_IP | EBT_ARP_DST_IP | EBT_ARP_GRAT)) {
-               __be32 saddr, daddr, *sap, *dap;
+               const __be32 *sap, *dap;
+               __be32 saddr, daddr;
 
                if (ah->ar_pln != sizeof(__be32) || ah->ar_pro != htons(ETH_P_IP))
                        return EBT_NOMATCH;
@@ -61,7 +63,8 @@ static int ebt_filter_arp(const struct sk_buff *skb, const struct net_device *in
        }
 
        if (info->bitmask & (EBT_ARP_SRC_MAC | EBT_ARP_DST_MAC)) {
-               unsigned char _mac[ETH_ALEN], *mp;
+               const unsigned char *mp;
+               unsigned char _mac[ETH_ALEN];
                uint8_t verdict, i;
 
                if (ah->ar_hln != ETH_ALEN || ah->ar_hrd != htons(ARPHRD_ETHER))
@@ -100,7 +103,7 @@ static int ebt_filter_arp(const struct sk_buff *skb, const struct net_device *in
 static int ebt_arp_check(const char *tablename, unsigned int hookmask,
    const struct ebt_entry *e, void *data, unsigned int datalen)
 {
-       struct ebt_arp_info *info = (struct ebt_arp_info *)data;
+       const struct ebt_arp_info *info = data;
 
        if (datalen != EBT_ALIGN(sizeof(struct ebt_arp_info)))
                return -EINVAL;
@@ -113,8 +116,7 @@ static int ebt_arp_check(const char *tablename, unsigned int hookmask,
        return 0;
 }
 
-static struct ebt_match filter_arp =
-{
+static struct ebt_match filter_arp __read_mostly = {
        .name           = EBT_ARP_MATCH,
        .match          = ebt_filter_arp,
        .check          = ebt_arp_check,
@@ -133,4 +135,5 @@ static void __exit ebt_arp_fini(void)
 
 module_init(ebt_arp_init);
 module_exit(ebt_arp_fini);
+MODULE_DESCRIPTION("Ebtables: ARP protocol packet match");
 MODULE_LICENSE("GPL");
index 48a80e4232879c5afe409fc5697e4167cfe8969f..0c4279590fc70c25a60b3b18e5ce38f5a6126c29 100644 (file)
@@ -19,10 +19,13 @@ static int ebt_target_reply(struct sk_buff *skb, unsigned int hooknr,
    const struct net_device *in, const struct net_device *out,
    const void *data, unsigned int datalen)
 {
-       struct ebt_arpreply_info *info = (struct ebt_arpreply_info *)data;
-       __be32 _sip, *siptr, _dip, *diptr;
-       struct arphdr _ah, *ap;
-       unsigned char _sha[ETH_ALEN], *shp;
+       struct ebt_arpreply_info *info = (void *)data;
+       const __be32 *siptr, *diptr;
+       __be32 _sip, _dip;
+       const struct arphdr *ap;
+       struct arphdr _ah;
+       const unsigned char *shp;
+       unsigned char _sha[ETH_ALEN];
 
        ap = skb_header_pointer(skb, 0, sizeof(_ah), &_ah);
        if (ap == NULL)
@@ -58,7 +61,7 @@ static int ebt_target_reply(struct sk_buff *skb, unsigned int hooknr,
 static int ebt_target_reply_check(const char *tablename, unsigned int hookmask,
    const struct ebt_entry *e, void *data, unsigned int datalen)
 {
-       struct ebt_arpreply_info *info = (struct ebt_arpreply_info *)data;
+       const struct ebt_arpreply_info *info = data;
 
        if (datalen != EBT_ALIGN(sizeof(struct ebt_arpreply_info)))
                return -EINVAL;
@@ -73,8 +76,7 @@ static int ebt_target_reply_check(const char *tablename, unsigned int hookmask,
        return 0;
 }
 
-static struct ebt_target reply_target =
-{
+static struct ebt_target reply_target __read_mostly = {
        .name           = EBT_ARPREPLY_TARGET,
        .target         = ebt_target_reply,
        .check          = ebt_target_reply_check,
@@ -93,4 +95,5 @@ static void __exit ebt_arpreply_fini(void)
 
 module_init(ebt_arpreply_init);
 module_exit(ebt_arpreply_fini);
+MODULE_DESCRIPTION("Ebtables: ARP reply target");
 MODULE_LICENSE("GPL");
index 74262e9a566a3f7baf63779f948fb16f4dfd282f..e700cbf634c24826c9b257364b77a969d884af1a 100644 (file)
@@ -18,7 +18,7 @@ static int ebt_target_dnat(struct sk_buff *skb, unsigned int hooknr,
    const struct net_device *in, const struct net_device *out,
    const void *data, unsigned int datalen)
 {
-       struct ebt_nat_info *info = (struct ebt_nat_info *)data;
+       const struct ebt_nat_info *info = data;
 
        if (skb_make_writable(skb, 0))
                return NF_DROP;
@@ -30,7 +30,7 @@ static int ebt_target_dnat(struct sk_buff *skb, unsigned int hooknr,
 static int ebt_target_dnat_check(const char *tablename, unsigned int hookmask,
    const struct ebt_entry *e, void *data, unsigned int datalen)
 {
-       struct ebt_nat_info *info = (struct ebt_nat_info *)data;
+       const struct ebt_nat_info *info = data;
 
        if (BASE_CHAIN && info->target == EBT_RETURN)
                return -EINVAL;
@@ -46,8 +46,7 @@ static int ebt_target_dnat_check(const char *tablename, unsigned int hookmask,
        return 0;
 }
 
-static struct ebt_target dnat =
-{
+static struct ebt_target dnat __read_mostly = {
        .name           = EBT_DNAT_TARGET,
        .target         = ebt_target_dnat,
        .check          = ebt_target_dnat_check,
@@ -66,4 +65,5 @@ static void __exit ebt_dnat_fini(void)
 
 module_init(ebt_dnat_init);
 module_exit(ebt_dnat_fini);
+MODULE_DESCRIPTION("Ebtables: Destination MAC address translation");
 MODULE_LICENSE("GPL");
index 69f7f0ab9c76ae5fa5d4cdd7ef2264417a675ba3..65caa00dcf2a348d0c321a42add55acd40177339 100644 (file)
@@ -28,9 +28,11 @@ static int ebt_filter_ip(const struct sk_buff *skb, const struct net_device *in,
    const struct net_device *out, const void *data,
    unsigned int datalen)
 {
-       struct ebt_ip_info *info = (struct ebt_ip_info *)data;
-       struct iphdr _iph, *ih;
-       struct tcpudphdr _ports, *pptr;
+       const struct ebt_ip_info *info = data;
+       const struct iphdr *ih;
+       struct iphdr _iph;
+       const struct tcpudphdr *pptr;
+       struct tcpudphdr _ports;
 
        ih = skb_header_pointer(skb, 0, sizeof(_iph), &_iph);
        if (ih == NULL)
@@ -79,7 +81,7 @@ static int ebt_filter_ip(const struct sk_buff *skb, const struct net_device *in,
 static int ebt_ip_check(const char *tablename, unsigned int hookmask,
    const struct ebt_entry *e, void *data, unsigned int datalen)
 {
-       struct ebt_ip_info *info = (struct ebt_ip_info *)data;
+       const struct ebt_ip_info *info = data;
 
        if (datalen != EBT_ALIGN(sizeof(struct ebt_ip_info)))
                return -EINVAL;
@@ -105,8 +107,7 @@ static int ebt_ip_check(const char *tablename, unsigned int hookmask,
        return 0;
 }
 
-static struct ebt_match filter_ip =
-{
+static struct ebt_match filter_ip __read_mostly = {
        .name           = EBT_IP_MATCH,
        .match          = ebt_filter_ip,
        .check          = ebt_ip_check,
@@ -125,4 +126,5 @@ static void __exit ebt_ip_fini(void)
 
 module_init(ebt_ip_init);
 module_exit(ebt_ip_fini);
+MODULE_DESCRIPTION("Ebtables: IPv4 protocol packet match");
 MODULE_LICENSE("GPL");
index d48fa5cb26cf325c59c46b8fe9700d32e32081b8..8cbdc01c253e49274b1c0e83d63e98b5100fe37b 100644 (file)
@@ -69,7 +69,7 @@ user2credits(u_int32_t user)
 static int ebt_limit_check(const char *tablename, unsigned int hookmask,
    const struct ebt_entry *e, void *data, unsigned int datalen)
 {
-       struct ebt_limit_info *info = (struct ebt_limit_info *)data;
+       struct ebt_limit_info *info = data;
 
        if (datalen != EBT_ALIGN(sizeof(struct ebt_limit_info)))
                return -EINVAL;
@@ -90,8 +90,7 @@ static int ebt_limit_check(const char *tablename, unsigned int hookmask,
        return 0;
 }
 
-static struct ebt_match ebt_limit_reg =
-{
+static struct ebt_match ebt_limit_reg __read_mostly = {
        .name           = EBT_LIMIT_MATCH,
        .match          = ebt_limit_match,
        .check          = ebt_limit_check,
@@ -110,4 +109,5 @@ static void __exit ebt_limit_fini(void)
 
 module_init(ebt_limit_init);
 module_exit(ebt_limit_fini);
+MODULE_DESCRIPTION("Ebtables: Rate-limit match");
 MODULE_LICENSE("GPL");
index 3be9e9898553b1d129700929dac0177853c0b377..0b209e4aad0a0a76e53c9cbc7c89d950eda92af7 100644 (file)
@@ -24,7 +24,7 @@ static DEFINE_SPINLOCK(ebt_log_lock);
 static int ebt_log_check(const char *tablename, unsigned int hookmask,
    const struct ebt_entry *e, void *data, unsigned int datalen)
 {
-       struct ebt_log_info *info = (struct ebt_log_info *)data;
+       struct ebt_log_info *info = data;
 
        if (datalen != EBT_ALIGN(sizeof(struct ebt_log_info)))
                return -EINVAL;
@@ -50,7 +50,7 @@ struct arppayload
        unsigned char ip_dst[4];
 };
 
-static void print_MAC(unsigned char *p)
+static void print_MAC(const unsigned char *p)
 {
        int i;
 
@@ -84,7 +84,8 @@ ebt_log_packet(unsigned int pf, unsigned int hooknum,
 
        if ((bitmask & EBT_LOG_IP) && eth_hdr(skb)->h_proto ==
           htons(ETH_P_IP)){
-               struct iphdr _iph, *ih;
+               const struct iphdr *ih;
+               struct iphdr _iph;
 
                ih = skb_header_pointer(skb, 0, sizeof(_iph), &_iph);
                if (ih == NULL) {
@@ -99,7 +100,8 @@ ebt_log_packet(unsigned int pf, unsigned int hooknum,
                    ih->protocol == IPPROTO_UDPLITE ||
                    ih->protocol == IPPROTO_SCTP ||
                    ih->protocol == IPPROTO_DCCP) {
-                       struct tcpudphdr _ports, *pptr;
+                       const struct tcpudphdr *pptr;
+                       struct tcpudphdr _ports;
 
                        pptr = skb_header_pointer(skb, ih->ihl*4,
                                                  sizeof(_ports), &_ports);
@@ -116,7 +118,8 @@ ebt_log_packet(unsigned int pf, unsigned int hooknum,
        if ((bitmask & EBT_LOG_ARP) &&
            ((eth_hdr(skb)->h_proto == htons(ETH_P_ARP)) ||
             (eth_hdr(skb)->h_proto == htons(ETH_P_RARP)))) {
-               struct arphdr _arph, *ah;
+               const struct arphdr *ah;
+               struct arphdr _arph;
 
                ah = skb_header_pointer(skb, 0, sizeof(_arph), &_arph);
                if (ah == NULL) {
@@ -132,7 +135,8 @@ ebt_log_packet(unsigned int pf, unsigned int hooknum,
                if (ah->ar_hrd == htons(1) &&
                    ah->ar_hln == ETH_ALEN &&
                    ah->ar_pln == sizeof(__be32)) {
-                       struct arppayload _arpp, *ap;
+                       const struct arppayload *ap;
+                       struct arppayload _arpp;
 
                        ap = skb_header_pointer(skb, sizeof(_arph),
                                                sizeof(_arpp), &_arpp);
@@ -160,7 +164,7 @@ static void ebt_log(const struct sk_buff *skb, unsigned int hooknr,
    const struct net_device *in, const struct net_device *out,
    const void *data, unsigned int datalen)
 {
-       struct ebt_log_info *info = (struct ebt_log_info *)data;
+       const struct ebt_log_info *info = data;
        struct nf_loginfo li;
 
        li.type = NF_LOG_TYPE_LOG;
@@ -208,4 +212,5 @@ static void __exit ebt_log_fini(void)
 
 module_init(ebt_log_init);
 module_exit(ebt_log_fini);
+MODULE_DESCRIPTION("Ebtables: Packet logging to syslog");
 MODULE_LICENSE("GPL");
index 6cba54309c099db7c3229df9c624107f749b922c..36723f47db0a7824bad1a64e47970b8fcd86911f 100644 (file)
@@ -21,7 +21,7 @@ static int ebt_target_mark(struct sk_buff *skb, unsigned int hooknr,
    const struct net_device *in, const struct net_device *out,
    const void *data, unsigned int datalen)
 {
-       struct ebt_mark_t_info *info = (struct ebt_mark_t_info *)data;
+       const struct ebt_mark_t_info *info = data;
        int action = info->target & -16;
 
        if (action == MARK_SET_VALUE)
@@ -39,7 +39,7 @@ static int ebt_target_mark(struct sk_buff *skb, unsigned int hooknr,
 static int ebt_target_mark_check(const char *tablename, unsigned int hookmask,
    const struct ebt_entry *e, void *data, unsigned int datalen)
 {
-       struct ebt_mark_t_info *info = (struct ebt_mark_t_info *)data;
+       const struct ebt_mark_t_info *info = data;
        int tmp;
 
        if (datalen != EBT_ALIGN(sizeof(struct ebt_mark_t_info)))
@@ -57,8 +57,7 @@ static int ebt_target_mark_check(const char *tablename, unsigned int hookmask,
        return 0;
 }
 
-static struct ebt_target mark_target =
-{
+static struct ebt_target mark_target __read_mostly = {
        .name           = EBT_MARK_TARGET,
        .target         = ebt_target_mark,
        .check          = ebt_target_mark_check,
@@ -77,4 +76,5 @@ static void __exit ebt_mark_fini(void)
 
 module_init(ebt_mark_init);
 module_exit(ebt_mark_fini);
+MODULE_DESCRIPTION("Ebtables: Packet mark modification");
 MODULE_LICENSE("GPL");
index 6b0d2169af74e379b468ea47dc8b47d6e26d5add..9b0a4543861fc02b148fb95c071db1d9228f8d6d 100644 (file)
@@ -16,7 +16,7 @@ static int ebt_filter_mark(const struct sk_buff *skb,
    const struct net_device *in, const struct net_device *out, const void *data,
    unsigned int datalen)
 {
-       struct ebt_mark_m_info *info = (struct ebt_mark_m_info *) data;
+       const struct ebt_mark_m_info *info = data;
 
        if (info->bitmask & EBT_MARK_OR)
                return !(!!(skb->mark & info->mask) ^ info->invert);
@@ -26,7 +26,7 @@ static int ebt_filter_mark(const struct sk_buff *skb,
 static int ebt_mark_check(const char *tablename, unsigned int hookmask,
    const struct ebt_entry *e, void *data, unsigned int datalen)
 {
-       struct ebt_mark_m_info *info = (struct ebt_mark_m_info *) data;
+       const struct ebt_mark_m_info *info = data;
 
        if (datalen != EBT_ALIGN(sizeof(struct ebt_mark_m_info)))
                return -EINVAL;
@@ -39,8 +39,7 @@ static int ebt_mark_check(const char *tablename, unsigned int hookmask,
        return 0;
 }
 
-static struct ebt_match filter_mark =
-{
+static struct ebt_match filter_mark __read_mostly = {
        .name           = EBT_MARK_MATCH,
        .match          = ebt_filter_mark,
        .check          = ebt_mark_check,
@@ -59,4 +58,5 @@ static void __exit ebt_mark_m_fini(void)
 
 module_init(ebt_mark_m_init);
 module_exit(ebt_mark_m_fini);
+MODULE_DESCRIPTION("Ebtables: Packet mark match");
 MODULE_LICENSE("GPL");
index 4fffd70e4da7355724d11db8a28d69d7744b45c4..676db32df3d1641237954f461793d5625f5aef19 100644 (file)
@@ -18,7 +18,7 @@ static int ebt_filter_pkttype(const struct sk_buff *skb,
    const void *data,
    unsigned int datalen)
 {
-       struct ebt_pkttype_info *info = (struct ebt_pkttype_info *)data;
+       const struct ebt_pkttype_info *info = data;
 
        return (skb->pkt_type != info->pkt_type) ^ info->invert;
 }
@@ -26,7 +26,7 @@ static int ebt_filter_pkttype(const struct sk_buff *skb,
 static int ebt_pkttype_check(const char *tablename, unsigned int hookmask,
    const struct ebt_entry *e, void *data, unsigned int datalen)
 {
-       struct ebt_pkttype_info *info = (struct ebt_pkttype_info *)data;
+       const struct ebt_pkttype_info *info = data;
 
        if (datalen != EBT_ALIGN(sizeof(struct ebt_pkttype_info)))
                return -EINVAL;
@@ -36,8 +36,7 @@ static int ebt_pkttype_check(const char *tablename, unsigned int hookmask,
        return 0;
 }
 
-static struct ebt_match filter_pkttype =
-{
+static struct ebt_match filter_pkttype __read_mostly = {
        .name           = EBT_PKTTYPE_MATCH,
        .match          = ebt_filter_pkttype,
        .check          = ebt_pkttype_check,
@@ -56,4 +55,5 @@ static void __exit ebt_pkttype_fini(void)
 
 module_init(ebt_pkttype_init);
 module_exit(ebt_pkttype_fini);
+MODULE_DESCRIPTION("Ebtables: Link layer packet type match");
 MODULE_LICENSE("GPL");
index 422cb834cff997eda08de86f2360c506d76b21c3..bfdf2fb60b1f0cbd16050390e01aba0bdbb9886a 100644 (file)
@@ -19,7 +19,7 @@ static int ebt_target_redirect(struct sk_buff *skb, unsigned int hooknr,
    const struct net_device *in, const struct net_device *out,
    const void *data, unsigned int datalen)
 {
-       struct ebt_redirect_info *info = (struct ebt_redirect_info *)data;
+       const struct ebt_redirect_info *info = data;
 
        if (skb_make_writable(skb, 0))
                return NF_DROP;
@@ -36,7 +36,7 @@ static int ebt_target_redirect(struct sk_buff *skb, unsigned int hooknr,
 static int ebt_target_redirect_check(const char *tablename, unsigned int hookmask,
    const struct ebt_entry *e, void *data, unsigned int datalen)
 {
-       struct ebt_redirect_info *info = (struct ebt_redirect_info *)data;
+       const struct ebt_redirect_info *info = data;
 
        if (datalen != EBT_ALIGN(sizeof(struct ebt_redirect_info)))
                return -EINVAL;
@@ -51,8 +51,7 @@ static int ebt_target_redirect_check(const char *tablename, unsigned int hookmas
        return 0;
 }
 
-static struct ebt_target redirect_target =
-{
+static struct ebt_target redirect_target __read_mostly = {
        .name           = EBT_REDIRECT_TARGET,
        .target         = ebt_target_redirect,
        .check          = ebt_target_redirect_check,
@@ -71,4 +70,5 @@ static void __exit ebt_redirect_fini(void)
 
 module_init(ebt_redirect_init);
 module_exit(ebt_redirect_fini);
+MODULE_DESCRIPTION("Ebtables: Packet redirection to localhost");
 MODULE_LICENSE("GPL");
index 425ac920904d7b5ddb6090e9ab338073b0ae7318..e252dabbb143c80536473c77542b4ecf685c7bc2 100644 (file)
@@ -20,7 +20,7 @@ static int ebt_target_snat(struct sk_buff *skb, unsigned int hooknr,
    const struct net_device *in, const struct net_device *out,
    const void *data, unsigned int datalen)
 {
-       struct ebt_nat_info *info = (struct ebt_nat_info *) data;
+       const struct ebt_nat_info *info = data;
 
        if (skb_make_writable(skb, 0))
                return NF_DROP;
@@ -28,7 +28,8 @@ static int ebt_target_snat(struct sk_buff *skb, unsigned int hooknr,
        memcpy(eth_hdr(skb)->h_source, info->mac, ETH_ALEN);
        if (!(info->target & NAT_ARP_BIT) &&
            eth_hdr(skb)->h_proto == htons(ETH_P_ARP)) {
-               struct arphdr _ah, *ap;
+               const struct arphdr *ap;
+               struct arphdr _ah;
 
                ap = skb_header_pointer(skb, 0, sizeof(_ah), &_ah);
                if (ap == NULL)
@@ -45,7 +46,7 @@ out:
 static int ebt_target_snat_check(const char *tablename, unsigned int hookmask,
    const struct ebt_entry *e, void *data, unsigned int datalen)
 {
-       struct ebt_nat_info *info = (struct ebt_nat_info *) data;
+       const struct ebt_nat_info *info = data;
        int tmp;
 
        if (datalen != EBT_ALIGN(sizeof(struct ebt_nat_info)))
@@ -67,8 +68,7 @@ static int ebt_target_snat_check(const char *tablename, unsigned int hookmask,
        return 0;
 }
 
-static struct ebt_target snat =
-{
+static struct ebt_target snat __read_mostly = {
        .name           = EBT_SNAT_TARGET,
        .target         = ebt_target_snat,
        .check          = ebt_target_snat_check,
@@ -87,4 +87,5 @@ static void __exit ebt_snat_fini(void)
 
 module_init(ebt_snat_init);
 module_exit(ebt_snat_fini);
+MODULE_DESCRIPTION("Ebtables: Source MAC address translation");
 MODULE_LICENSE("GPL");
index 31b77367319cb3949e5c9f61f27ce3c184225067..40f36d37607d6a8dee0aca874003a2086ecd160d 100644 (file)
@@ -40,10 +40,10 @@ struct stp_config_pdu {
 #define NR16(p) (p[0] << 8 | p[1])
 #define NR32(p) ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3])
 
-static int ebt_filter_config(struct ebt_stp_info *info,
-   struct stp_config_pdu *stpc)
+static int ebt_filter_config(const struct ebt_stp_info *info,
+   const struct stp_config_pdu *stpc)
 {
-       struct ebt_stp_config_info *c;
+       const struct ebt_stp_config_info *c;
        uint16_t v16;
        uint32_t v32;
        int verdict, i;
@@ -122,9 +122,10 @@ static int ebt_filter_config(struct ebt_stp_info *info,
 static int ebt_filter_stp(const struct sk_buff *skb, const struct net_device *in,
    const struct net_device *out, const void *data, unsigned int datalen)
 {
-       struct ebt_stp_info *info = (struct ebt_stp_info *)data;
-       struct stp_header _stph, *sp;
-       uint8_t header[6] = {0x42, 0x42, 0x03, 0x00, 0x00, 0x00};
+       const struct ebt_stp_info *info = data;
+       const struct stp_header *sp;
+       struct stp_header _stph;
+       const uint8_t header[6] = {0x42, 0x42, 0x03, 0x00, 0x00, 0x00};
 
        sp = skb_header_pointer(skb, 0, sizeof(_stph), &_stph);
        if (sp == NULL)
@@ -140,7 +141,8 @@ static int ebt_filter_stp(const struct sk_buff *skb, const struct net_device *in
 
        if (sp->type == BPDU_TYPE_CONFIG &&
            info->bitmask & EBT_STP_CONFIG_MASK) {
-               struct stp_config_pdu _stpc, *st;
+               const struct stp_config_pdu *st;
+               struct stp_config_pdu _stpc;
 
                st = skb_header_pointer(skb, sizeof(_stph),
                                        sizeof(_stpc), &_stpc);
@@ -154,10 +156,10 @@ static int ebt_filter_stp(const struct sk_buff *skb, const struct net_device *in
 static int ebt_stp_check(const char *tablename, unsigned int hookmask,
    const struct ebt_entry *e, void *data, unsigned int datalen)
 {
-       struct ebt_stp_info *info = (struct ebt_stp_info *)data;
-       int len = EBT_ALIGN(sizeof(struct ebt_stp_info));
-       uint8_t bridge_ula[6] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 };
-       uint8_t msk[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+       const struct ebt_stp_info *info = data;
+       const unsigned int len = EBT_ALIGN(sizeof(struct ebt_stp_info));
+       const uint8_t bridge_ula[6] = {0x01, 0x80, 0xc2, 0x00, 0x00, 0x00};
+       const uint8_t msk[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
 
        if (info->bitmask & ~EBT_STP_MASK || info->invflags & ~EBT_STP_MASK ||
            !(info->bitmask & EBT_STP_MASK))
@@ -172,8 +174,7 @@ static int ebt_stp_check(const char *tablename, unsigned int hookmask,
        return 0;
 }
 
-static struct ebt_match filter_stp =
-{
+static struct ebt_match filter_stp __read_mostly = {
        .name           = EBT_STP_MATCH,
        .match          = ebt_filter_stp,
        .check          = ebt_stp_check,
@@ -192,4 +193,5 @@ static void __exit ebt_stp_fini(void)
 
 module_init(ebt_stp_init);
 module_exit(ebt_stp_fini);
+MODULE_DESCRIPTION("Ebtables: Spanning Tree Protocol packet match");
 MODULE_LICENSE("GPL");
index 8e7b00b68d3868107dd52f01a82a9262f2f34f49..2d4c9ef909fc6b691e221295a50c6961144a2ea0 100644 (file)
@@ -249,7 +249,7 @@ static void ebt_ulog(const struct sk_buff *skb, unsigned int hooknr,
    const struct net_device *in, const struct net_device *out,
    const void *data, unsigned int datalen)
 {
-       struct ebt_ulog_info *uloginfo = (struct ebt_ulog_info *)data;
+       const struct ebt_ulog_info *uloginfo = data;
 
        ebt_ulog_packet(hooknr, skb, in, out, uloginfo, NULL);
 }
@@ -258,7 +258,7 @@ static void ebt_ulog(const struct sk_buff *skb, unsigned int hooknr,
 static int ebt_ulog_check(const char *tablename, unsigned int hookmask,
    const struct ebt_entry *e, void *data, unsigned int datalen)
 {
-       struct ebt_ulog_info *uloginfo = (struct ebt_ulog_info *)data;
+       struct ebt_ulog_info *uloginfo = data;
 
        if (datalen != EBT_ALIGN(sizeof(struct ebt_ulog_info)) ||
            uloginfo->nlgroup > 31)
@@ -272,7 +272,7 @@ static int ebt_ulog_check(const char *tablename, unsigned int hookmask,
        return 0;
 }
 
-static struct ebt_watcher ulog = {
+static struct ebt_watcher ulog __read_mostly = {
        .name           = EBT_ULOG_WATCHER,
        .watcher        = ebt_ulog,
        .check          = ebt_ulog_check,
@@ -340,5 +340,4 @@ module_init(ebt_ulog_init);
 module_exit(ebt_ulog_fini);
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Bart De Schuymer <bdschuym@pandora.be>");
-MODULE_DESCRIPTION("ebtables userspace logging module for bridged Ethernet"
-                  " frames");
+MODULE_DESCRIPTION("Ebtables: Packet logging to netlink using ULOG");
index 0ddf7499d4962f34a28e4d5c87a0ce1e944593e4..ab60b0dade80439ea9a7c1ac3a261366ec5ee850 100644 (file)
@@ -31,8 +31,7 @@ static int debug;
 module_param(debug, int, 0);
 MODULE_PARM_DESC(debug, "debug=1 is turn on debug messages");
 MODULE_AUTHOR("Nick Fedchik <nick@fedchik.org.ua>");
-MODULE_DESCRIPTION("802.1Q match module (ebtables extension), v"
-                  MODULE_VERS);
+MODULE_DESCRIPTION("Ebtables: 802.1Q VLAN tag match");
 MODULE_LICENSE("GPL");
 
 
@@ -46,8 +45,9 @@ ebt_filter_vlan(const struct sk_buff *skb,
                const struct net_device *out,
                const void *data, unsigned int datalen)
 {
-       struct ebt_vlan_info *info = (struct ebt_vlan_info *) data;
-       struct vlan_hdr _frame, *fp;
+       const struct ebt_vlan_info *info = data;
+       const struct vlan_hdr *fp;
+       struct vlan_hdr _frame;
 
        unsigned short TCI;     /* Whole TCI, given from parsed frame */
        unsigned short id;      /* VLAN ID, given from frame TCI */
@@ -91,7 +91,7 @@ ebt_check_vlan(const char *tablename,
               unsigned int hooknr,
               const struct ebt_entry *e, void *data, unsigned int datalen)
 {
-       struct ebt_vlan_info *info = (struct ebt_vlan_info *) data;
+       struct ebt_vlan_info *info = data;
 
        /* Parameters buffer overflow check */
        if (datalen != EBT_ALIGN(sizeof(struct ebt_vlan_info))) {
@@ -169,7 +169,7 @@ ebt_check_vlan(const char *tablename,
        return 0;
 }
 
-static struct ebt_match filter_vlan = {
+static struct ebt_match filter_vlan __read_mostly = {
        .name           = EBT_VLAN_MATCH,
        .match          = ebt_filter_vlan,
        .check          = ebt_check_vlan,
index c9c593e1ba6fd4d26d8580bb12f1fccb99126484..9549417250bba71650547e747226ba9e8c0a1882 100644 (file)
@@ -2752,12 +2752,15 @@ static void __dev_set_promiscuity(struct net_device *dev, int inc)
                printk(KERN_INFO "device %s %s promiscuous mode\n",
                       dev->name, (dev->flags & IFF_PROMISC) ? "entered" :
                                                               "left");
-               audit_log(current->audit_context, GFP_ATOMIC,
-                       AUDIT_ANOM_PROMISCUOUS,
-                       "dev=%s prom=%d old_prom=%d auid=%u",
-                       dev->name, (dev->flags & IFF_PROMISC),
-                       (old_flags & IFF_PROMISC),
-                       audit_get_loginuid(current->audit_context));
+               if (audit_enabled)
+                       audit_log(current->audit_context, GFP_ATOMIC,
+                               AUDIT_ANOM_PROMISCUOUS,
+                               "dev=%s prom=%d old_prom=%d auid=%u uid=%u gid=%u ses=%u",
+                               dev->name, (dev->flags & IFF_PROMISC),
+                               (old_flags & IFF_PROMISC),
+                               audit_get_loginuid(current),
+                               current->uid, current->gid,
+                               audit_get_sessionid(current));
 
                if (dev->change_rx_flags)
                        dev->change_rx_flags(dev, IFF_PROMISC);
@@ -2962,6 +2965,102 @@ int dev_unicast_add(struct net_device *dev, void *addr, int alen)
 }
 EXPORT_SYMBOL(dev_unicast_add);
 
+int __dev_addr_sync(struct dev_addr_list **to, int *to_count,
+                   struct dev_addr_list **from, int *from_count)
+{
+       struct dev_addr_list *da, *next;
+       int err = 0;
+
+       da = *from;
+       while (da != NULL) {
+               next = da->next;
+               if (!da->da_synced) {
+                       err = __dev_addr_add(to, to_count,
+                                            da->da_addr, da->da_addrlen, 0);
+                       if (err < 0)
+                               break;
+                       da->da_synced = 1;
+                       da->da_users++;
+               } else if (da->da_users == 1) {
+                       __dev_addr_delete(to, to_count,
+                                         da->da_addr, da->da_addrlen, 0);
+                       __dev_addr_delete(from, from_count,
+                                         da->da_addr, da->da_addrlen, 0);
+               }
+               da = next;
+       }
+       return err;
+}
+
+void __dev_addr_unsync(struct dev_addr_list **to, int *to_count,
+                      struct dev_addr_list **from, int *from_count)
+{
+       struct dev_addr_list *da, *next;
+
+       da = *from;
+       while (da != NULL) {
+               next = da->next;
+               if (da->da_synced) {
+                       __dev_addr_delete(to, to_count,
+                                         da->da_addr, da->da_addrlen, 0);
+                       da->da_synced = 0;
+                       __dev_addr_delete(from, from_count,
+                                         da->da_addr, da->da_addrlen, 0);
+               }
+               da = next;
+       }
+}
+
+/**
+ *     dev_unicast_sync - Synchronize device's unicast list to another device
+ *     @to: destination device
+ *     @from: source device
+ *
+ *     Add newly added addresses to the destination device and release
+ *     addresses that have no users left. The source device must be
+ *     locked by netif_tx_lock_bh.
+ *
+ *     This function is intended to be called from the dev->set_rx_mode
+ *     function of layered software devices.
+ */
+int dev_unicast_sync(struct net_device *to, struct net_device *from)
+{
+       int err = 0;
+
+       netif_tx_lock_bh(to);
+       err = __dev_addr_sync(&to->uc_list, &to->uc_count,
+                             &from->uc_list, &from->uc_count);
+       if (!err)
+               __dev_set_rx_mode(to);
+       netif_tx_unlock_bh(to);
+       return err;
+}
+EXPORT_SYMBOL(dev_unicast_sync);
+
+/**
+ *     dev_unicast_unsync - Remove synchronized addresses from the destination
+ *                          device
+ *     @to: destination device
+ *     @from: source device
+ *
+ *     Remove all addresses that were added to the destination device by
+ *     dev_unicast_sync(). This function is intended to be called from the
+ *     dev->stop function of layered software devices.
+ */
+void dev_unicast_unsync(struct net_device *to, struct net_device *from)
+{
+       netif_tx_lock_bh(from);
+       netif_tx_lock_bh(to);
+
+       __dev_addr_unsync(&to->uc_list, &to->uc_count,
+                         &from->uc_list, &from->uc_count);
+       __dev_set_rx_mode(to);
+
+       netif_tx_unlock_bh(to);
+       netif_tx_unlock_bh(from);
+}
+EXPORT_SYMBOL(dev_unicast_unsync);
+
 static void __dev_addr_discard(struct dev_addr_list **list)
 {
        struct dev_addr_list *tmp;
index cadbfbf7e7f57a687f4f134030b106a4781f4715..cec582563e0dcdbfcf15aa535115b62d35d29041 100644 (file)
@@ -113,32 +113,15 @@ int dev_mc_add(struct net_device *dev, void *addr, int alen, int glbl)
  *     locked by netif_tx_lock_bh.
  *
  *     This function is intended to be called from the dev->set_multicast_list
- *     function of layered software devices.
+ *     or dev->set_rx_mode function of layered software devices.
  */
 int dev_mc_sync(struct net_device *to, struct net_device *from)
 {
-       struct dev_addr_list *da, *next;
        int err = 0;
 
        netif_tx_lock_bh(to);
-       da = from->mc_list;
-       while (da != NULL) {
-               next = da->next;
-               if (!da->da_synced) {
-                       err = __dev_addr_add(&to->mc_list, &to->mc_count,
-                                            da->da_addr, da->da_addrlen, 0);
-                       if (err < 0)
-                               break;
-                       da->da_synced = 1;
-                       da->da_users++;
-               } else if (da->da_users == 1) {
-                       __dev_addr_delete(&to->mc_list, &to->mc_count,
-                                         da->da_addr, da->da_addrlen, 0);
-                       __dev_addr_delete(&from->mc_list, &from->mc_count,
-                                         da->da_addr, da->da_addrlen, 0);
-               }
-               da = next;
-       }
+       err = __dev_addr_sync(&to->mc_list, &to->mc_count,
+                             &from->mc_list, &from->mc_count);
        if (!err)
                __dev_set_rx_mode(to);
        netif_tx_unlock_bh(to);
@@ -160,23 +143,11 @@ EXPORT_SYMBOL(dev_mc_sync);
  */
 void dev_mc_unsync(struct net_device *to, struct net_device *from)
 {
-       struct dev_addr_list *da, *next;
-
        netif_tx_lock_bh(from);
        netif_tx_lock_bh(to);
 
-       da = from->mc_list;
-       while (da != NULL) {
-               next = da->next;
-               if (da->da_synced) {
-                       __dev_addr_delete(&to->mc_list, &to->mc_count,
-                                         da->da_addr, da->da_addrlen, 0);
-                       da->da_synced = 0;
-                       __dev_addr_delete(&from->mc_list, &from->mc_count,
-                                         da->da_addr, da->da_addrlen, 0);
-               }
-               da = next;
-       }
+       __dev_addr_unsync(&to->mc_list, &to->mc_count,
+                         &from->mc_list, &from->mc_count);
        __dev_set_rx_mode(to);
 
        netif_tx_unlock_bh(to);
index 26e941d912e8e68dd1e308e705fec2bbd92d37fc..7b660834a4c207a08b23ff6f63fa8ae719ca4fba 100644 (file)
@@ -287,7 +287,7 @@ EXPORT_SYMBOL_GPL(register_pernet_subsys);
  *     @ops: pernet operations structure to manipulate
  *
  *     Remove the pernet operations structure from the list to be
- *     used when network namespaces are created or destoryed.  In
+ *     used when network namespaces are created or destroyed.  In
  *     addition run the exit method for all existing network
  *     namespaces.
  */
@@ -335,7 +335,7 @@ EXPORT_SYMBOL_GPL(register_pernet_device);
  *     @ops: pernet operations structure to manipulate
  *
  *     Remove the pernet operations structure from the list to be
- *     used when network namespaces are created or destoryed.  In
+ *     used when network namespaces are created or destroyed.  In
  *     addition run the exit method for all existing network
  *     namespaces.
  */
index eebccdbdbacafb1c913be9dc6ec51b57875afc46..bfcdfaebca5c809b79b9076b56748e9b342cd776 100644 (file)
 
 #define VERSION  "pktgen v2.69: Packet Generator for packet performance testing.\n"
 
-/* The buckets are exponential in 'width' */
-#define LAT_BUCKETS_MAX 32
 #define IP_NAME_SZ 32
 #define MAX_MPLS_LABELS 16 /* This is the max label stack depth */
 #define MPLS_STACK_BOTTOM htonl(0x00000100)
@@ -2044,7 +2042,6 @@ static void spin(struct pktgen_dev *pkt_dev, __u64 spin_until_us)
        __u64 now;
 
        start = now = getCurUs();
-       printk(KERN_INFO "sleeping for %d\n", (int)(spin_until_us - now));
        while (now < spin_until_us) {
                /* TODO: optimize sleeping behavior */
                if (spin_until_us - now > jiffies_to_usecs(1) + 1)
index ddbdde82a700dcf46a81a05439c966182b851d8c..61ac8d06292ce32b2dbe46e92f69f50bd327c398 100644 (file)
@@ -82,32 +82,6 @@ int rtnl_trylock(void)
        return mutex_trylock(&rtnl_mutex);
 }
 
-int rtattr_parse(struct rtattr *tb[], int maxattr, struct rtattr *rta, int len)
-{
-       memset(tb, 0, sizeof(struct rtattr*)*maxattr);
-
-       while (RTA_OK(rta, len)) {
-               unsigned flavor = rta->rta_type;
-               if (flavor && flavor <= maxattr)
-                       tb[flavor-1] = rta;
-               rta = RTA_NEXT(rta, len);
-       }
-       return 0;
-}
-
-int __rtattr_parse_nested_compat(struct rtattr *tb[], int maxattr,
-                                struct rtattr *rta, int len)
-{
-       if (RTA_PAYLOAD(rta) < len)
-               return -1;
-       if (RTA_PAYLOAD(rta) >= RTA_ALIGN(len) + sizeof(struct rtattr)) {
-               rta = RTA_DATA(rta) + RTA_ALIGN(len);
-               return rtattr_parse_nested(tb, maxattr, rta);
-       }
-       memset(tb, 0, sizeof(struct rtattr *) * maxattr);
-       return 0;
-}
-
 static struct rtnl_link *rtnl_msg_handlers[NPROTO];
 
 static inline int rtm_msgindex(int msgtype)
@@ -442,21 +416,6 @@ void __rta_fill(struct sk_buff *skb, int attrtype, int attrlen, const void *data
        memset(RTA_DATA(rta) + attrlen, 0, RTA_ALIGN(size) - size);
 }
 
-size_t rtattr_strlcpy(char *dest, const struct rtattr *rta, size_t size)
-{
-       size_t ret = RTA_PAYLOAD(rta);
-       char *src = RTA_DATA(rta);
-
-       if (ret > 0 && src[ret - 1] == '\0')
-               ret--;
-       if (size > 0) {
-               size_t len = (ret >= size) ? size - 1 : ret;
-               memset(dest, 0, size);
-               memcpy(dest, src, len);
-       }
-       return ret;
-}
-
 int rtnetlink_send(struct sk_buff *skb, struct net *net, u32 pid, unsigned group, int echo)
 {
        struct sock *rtnl = net->rtnl;
@@ -1411,9 +1370,6 @@ void __init rtnetlink_init(void)
 }
 
 EXPORT_SYMBOL(__rta_fill);
-EXPORT_SYMBOL(rtattr_strlcpy);
-EXPORT_SYMBOL(rtattr_parse);
-EXPORT_SYMBOL(__rtattr_parse_nested_compat);
 EXPORT_SYMBOL(rtnetlink_put_metrics);
 EXPORT_SYMBOL(rtnl_lock);
 EXPORT_SYMBOL(rtnl_trylock);
index 98420f9c4b6d3cf8e77ec27856ff0abbec10ea46..4e354221ec2338fb646bd68b19eddd956b769506 100644 (file)
@@ -2461,6 +2461,34 @@ int skb_cow_data(struct sk_buff *skb, int tailbits, struct sk_buff **trailer)
        return elt;
 }
 
+/**
+ * skb_partial_csum_set - set up and verify partial csum values for packet
+ * @skb: the skb to set
+ * @start: the number of bytes after skb->data to start checksumming.
+ * @off: the offset from start to place the checksum.
+ *
+ * For untrusted partially-checksummed packets, we need to make sure the values
+ * for skb->csum_start and skb->csum_offset are valid so we don't oops.
+ *
+ * This function checks and sets those values and skb->ip_summed: if this
+ * returns false you should drop the packet.
+ */
+bool skb_partial_csum_set(struct sk_buff *skb, u16 start, u16 off)
+{
+       if (unlikely(start > skb->len - 2) ||
+           unlikely((int)start + off > skb->len - 2)) {
+               if (net_ratelimit())
+                       printk(KERN_WARNING
+                              "bad partial csum: csum=%u/%u len=%u\n",
+                              start, off, skb->len);
+               return false;
+       }
+       skb->ip_summed = CHECKSUM_PARTIAL;
+       skb->csum_start = skb_headroom(skb) + start;
+       skb->csum_offset = off;
+       return true;
+}
+
 EXPORT_SYMBOL(___pskb_trim);
 EXPORT_SYMBOL(__kfree_skb);
 EXPORT_SYMBOL(kfree_skb);
@@ -2497,3 +2525,4 @@ EXPORT_SYMBOL(skb_append_datato_frags);
 
 EXPORT_SYMBOL_GPL(skb_to_sgvec);
 EXPORT_SYMBOL_GPL(skb_cow_data);
+EXPORT_SYMBOL_GPL(skb_partial_csum_set);
index 1c4b1cd16d654f1a6737a6bfed3ca6d445f3e8c4..433715fb141a5e0dd6eb092568f63c20c8a2fa86 100644 (file)
@@ -667,6 +667,13 @@ set_rcvbuf:
                else
                        clear_bit(SOCK_PASSSEC, &sock->flags);
                break;
+       case SO_MARK:
+               if (!capable(CAP_NET_ADMIN))
+                       ret = -EPERM;
+               else {
+                       sk->sk_mark = val;
+               }
+               break;
 
                /* We implement the SO_SNDLOWAT etc to
                   not be settable (1003.1g 5.3) */
@@ -836,6 +843,10 @@ int sock_getsockopt(struct socket *sock, int level, int optname,
        case SO_PEERSEC:
                return security_socket_getpeersec_stream(sock, optval, optlen, len);
 
+       case SO_MARK:
+               v.val = sk->sk_mark;
+               break;
+
        default:
                return -ENOPROTOOPT;
        }
index ebe59d98721a58a934b89ca1143c96b45d3dec9a..287a62bc2e0ffb40c741743026231f04b37ff176 100644 (file)
@@ -271,8 +271,6 @@ extern struct sk_buff       *dccp_make_response(struct sock *sk,
 
 extern int        dccp_connect(struct sock *sk);
 extern int        dccp_disconnect(struct sock *sk, int flags);
-extern void       dccp_hash(struct sock *sk);
-extern void       dccp_unhash(struct sock *sk);
 extern int        dccp_getsockopt(struct sock *sk, int level, int optname,
                                   char __user *optval, int __user *optlen);
 extern int        dccp_setsockopt(struct sock *sk, int level, int optname,
index 9e38b0d6195ce637355762471cb988e8ea4527fa..474075adbde4d7c426fc960ef4079686cd185e2e 100644 (file)
  */
 static struct socket *dccp_v4_ctl_socket;
 
-static int dccp_v4_get_port(struct sock *sk, const unsigned short snum)
-{
-       return inet_csk_get_port(&dccp_hashinfo, sk, snum,
-                                inet_csk_bind_conflict);
-}
-
 int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
 {
        struct inet_sock *inet = inet_sk(sk);
@@ -218,7 +212,7 @@ static void dccp_v4_err(struct sk_buff *skb, u32 info)
                return;
        }
 
-       sk = inet_lookup(&dccp_hashinfo, iph->daddr, dh->dccph_dport,
+       sk = inet_lookup(&init_net, &dccp_hashinfo, iph->daddr, dh->dccph_dport,
                         iph->saddr, dh->dccph_sport, inet_iif(skb));
        if (sk == NULL) {
                ICMP_INC_STATS_BH(ICMP_MIB_INERRORS);
@@ -408,8 +402,8 @@ struct sock *dccp_v4_request_recv_sock(struct sock *sk, struct sk_buff *skb,
 
        dccp_sync_mss(newsk, dst_mtu(dst));
 
-       __inet_hash_nolisten(&dccp_hashinfo, newsk);
-       __inet_inherit_port(&dccp_hashinfo, sk, newsk);
+       __inet_hash_nolisten(newsk);
+       __inet_inherit_port(sk, newsk);
 
        return newsk;
 
@@ -436,7 +430,7 @@ static struct sock *dccp_v4_hnd_req(struct sock *sk, struct sk_buff *skb)
        if (req != NULL)
                return dccp_check_req(sk, skb, req, prev);
 
-       nsk = inet_lookup_established(&dccp_hashinfo,
+       nsk = inet_lookup_established(&init_net, &dccp_hashinfo,
                                      iph->saddr, dh->dccph_sport,
                                      iph->daddr, dh->dccph_dport,
                                      inet_iif(skb));
@@ -817,7 +811,7 @@ static int dccp_v4_rcv(struct sk_buff *skb)
 
        /* Step 2:
         *      Look up flow ID in table and get corresponding socket */
-       sk = __inet_lookup(&dccp_hashinfo,
+       sk = __inet_lookup(&init_net, &dccp_hashinfo,
                           iph->saddr, dh->dccph_sport,
                           iph->daddr, dh->dccph_dport, inet_iif(skb));
        /*
@@ -898,6 +892,7 @@ static struct inet_connection_sock_af_ops dccp_ipv4_af_ops = {
        .getsockopt        = ip_getsockopt,
        .addr2sockaddr     = inet_csk_addr2sockaddr,
        .sockaddr_len      = sizeof(struct sockaddr_in),
+       .bind_conflict     = inet_csk_bind_conflict,
 #ifdef CONFIG_COMPAT
        .compat_setsockopt = compat_ip_setsockopt,
        .compat_getsockopt = compat_ip_getsockopt,
@@ -937,10 +932,10 @@ static struct proto dccp_v4_prot = {
        .sendmsg                = dccp_sendmsg,
        .recvmsg                = dccp_recvmsg,
        .backlog_rcv            = dccp_v4_do_rcv,
-       .hash                   = dccp_hash,
-       .unhash                 = dccp_unhash,
+       .hash                   = inet_hash,
+       .unhash                 = inet_unhash,
        .accept                 = inet_csk_accept,
-       .get_port               = dccp_v4_get_port,
+       .get_port               = inet_csk_get_port,
        .shutdown               = dccp_shutdown,
        .destroy                = dccp_destroy_sock,
        .orphan_count           = &dccp_orphan_count,
@@ -948,6 +943,7 @@ static struct proto dccp_v4_prot = {
        .obj_size               = sizeof(struct dccp_sock),
        .rsk_prot               = &dccp_request_sock_ops,
        .twsk_prot              = &dccp_timewait_sock_ops,
+       .hashinfo               = &dccp_hashinfo,
 #ifdef CONFIG_COMPAT
        .compat_setsockopt      = compat_dccp_setsockopt,
        .compat_getsockopt      = compat_dccp_getsockopt,
index f42b75ce7f5ce3c0065cb6b987f291d8bf32a99e..490333d47c7b04dda8a6660cab945988626a86ce 100644 (file)
@@ -39,21 +39,15 @@ static struct socket *dccp_v6_ctl_socket;
 static struct inet_connection_sock_af_ops dccp_ipv6_mapped;
 static struct inet_connection_sock_af_ops dccp_ipv6_af_ops;
 
-static int dccp_v6_get_port(struct sock *sk, unsigned short snum)
-{
-       return inet_csk_get_port(&dccp_hashinfo, sk, snum,
-                                inet6_csk_bind_conflict);
-}
-
 static void dccp_v6_hash(struct sock *sk)
 {
        if (sk->sk_state != DCCP_CLOSED) {
                if (inet_csk(sk)->icsk_af_ops == &dccp_ipv6_mapped) {
-                       dccp_hash(sk);
+                       inet_hash(sk);
                        return;
                }
                local_bh_disable();
-               __inet6_hash(&dccp_hashinfo, sk);
+               __inet6_hash(sk);
                local_bh_enable();
        }
 }
@@ -101,8 +95,8 @@ static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
        int err;
        __u64 seq;
 
-       sk = inet6_lookup(&dccp_hashinfo, &hdr->daddr, dh->dccph_dport,
-                         &hdr->saddr, dh->dccph_sport, inet6_iif(skb));
+       sk = inet6_lookup(&init_net, &dccp_hashinfo, &hdr->daddr, dh->dccph_dport,
+                       &hdr->saddr, dh->dccph_sport, inet6_iif(skb));
 
        if (sk == NULL) {
                ICMP6_INC_STATS_BH(__in6_dev_get(skb->dev), ICMP6_MIB_INERRORS);
@@ -366,7 +360,7 @@ static struct sock *dccp_v6_hnd_req(struct sock *sk,struct sk_buff *skb)
        if (req != NULL)
                return dccp_check_req(sk, skb, req, prev);
 
-       nsk = __inet6_lookup_established(&dccp_hashinfo,
+       nsk = __inet6_lookup_established(&init_net, &dccp_hashinfo,
                                         &iph->saddr, dh->dccph_sport,
                                         &iph->daddr, ntohs(dh->dccph_dport),
                                         inet6_iif(skb));
@@ -630,8 +624,8 @@ static struct sock *dccp_v6_request_recv_sock(struct sock *sk,
 
        newinet->daddr = newinet->saddr = newinet->rcv_saddr = LOOPBACK4_IPV6;
 
-       __inet6_hash(&dccp_hashinfo, newsk);
-       inet_inherit_port(&dccp_hashinfo, sk, newsk);
+       __inet6_hash(newsk);
+       inet_inherit_port(sk, newsk);
 
        return newsk;
 
@@ -797,7 +791,7 @@ static int dccp_v6_rcv(struct sk_buff *skb)
 
        /* Step 2:
         *      Look up flow ID in table and get corresponding socket */
-       sk = __inet6_lookup(&dccp_hashinfo, &ipv6_hdr(skb)->saddr,
+       sk = __inet6_lookup(&init_net, &dccp_hashinfo, &ipv6_hdr(skb)->saddr,
                            dh->dccph_sport,
                            &ipv6_hdr(skb)->daddr, ntohs(dh->dccph_dport),
                            inet6_iif(skb));
@@ -1054,6 +1048,7 @@ static struct inet_connection_sock_af_ops dccp_ipv6_af_ops = {
        .getsockopt        = ipv6_getsockopt,
        .addr2sockaddr     = inet6_csk_addr2sockaddr,
        .sockaddr_len      = sizeof(struct sockaddr_in6),
+       .bind_conflict     = inet6_csk_bind_conflict,
 #ifdef CONFIG_COMPAT
        .compat_setsockopt = compat_ipv6_setsockopt,
        .compat_getsockopt = compat_ipv6_getsockopt,
@@ -1123,9 +1118,9 @@ static struct proto dccp_v6_prot = {
        .recvmsg           = dccp_recvmsg,
        .backlog_rcv       = dccp_v6_do_rcv,
        .hash              = dccp_v6_hash,
-       .unhash            = dccp_unhash,
+       .unhash            = inet_unhash,
        .accept            = inet_csk_accept,
-       .get_port          = dccp_v6_get_port,
+       .get_port          = inet_csk_get_port,
        .shutdown          = dccp_shutdown,
        .destroy           = dccp_v6_destroy_sock,
        .orphan_count      = &dccp_orphan_count,
@@ -1133,6 +1128,7 @@ static struct proto dccp_v6_prot = {
        .obj_size          = sizeof(struct dccp6_sock),
        .rsk_prot          = &dccp6_request_sock_ops,
        .twsk_prot         = &dccp6_timewait_sock_ops,
+       .hashinfo          = &dccp_hashinfo,
 #ifdef CONFIG_COMPAT
        .compat_setsockopt = compat_dccp_setsockopt,
        .compat_getsockopt = compat_dccp_getsockopt,
index 0bed4a6095b7afd4f84ec179daefcf1285371a8c..e3f5d37b84be1817f2b69b0fe31c65e999ceb05d 100644 (file)
@@ -78,7 +78,7 @@ void dccp_set_state(struct sock *sk, const int state)
                sk->sk_prot->unhash(sk);
                if (inet_csk(sk)->icsk_bind_hash != NULL &&
                    !(sk->sk_userlocks & SOCK_BINDPORT_LOCK))
-                       inet_put_port(&dccp_hashinfo, sk);
+                       inet_put_port(sk);
                /* fall through */
        default:
                if (oldstate == DCCP_OPEN)
@@ -173,20 +173,6 @@ const char *dccp_state_name(const int state)
 
 EXPORT_SYMBOL_GPL(dccp_state_name);
 
-void dccp_hash(struct sock *sk)
-{
-       inet_hash(&dccp_hashinfo, sk);
-}
-
-EXPORT_SYMBOL_GPL(dccp_hash);
-
-void dccp_unhash(struct sock *sk)
-{
-       inet_unhash(&dccp_hashinfo, sk);
-}
-
-EXPORT_SYMBOL_GPL(dccp_unhash);
-
 int dccp_init_sock(struct sock *sk, const __u8 ctl_sock_initialized)
 {
        struct dccp_sock *dp = dccp_sk(sk);
@@ -268,7 +254,7 @@ int dccp_destroy_sock(struct sock *sk)
 
        /* Clean up a referenced DCCP bind bucket. */
        if (inet_csk(sk)->icsk_bind_hash != NULL)
-               inet_put_port(&dccp_hashinfo, sk);
+               inet_put_port(sk);
 
        kfree(dp->dccps_service_list);
        dp->dccps_service_list = NULL;
index 24e2b7294bf89e46874cd7dd7dd30f2d08c15c5f..19880b086e712f4e29932debfdc0b06714fef6e7 100644 (file)
@@ -343,6 +343,7 @@ config INET_ESP
        tristate "IP: ESP transformation"
        select XFRM
        select CRYPTO
+       select CRYPTO_AEAD
        select CRYPTO_HMAC
        select CRYPTO_MD5
        select CRYPTO_CBC
index d76803a3dcae843f1ebf07794fdd0da6c34b9498..9d4555ec0b59136eb4e1ba259531c5d57cd7d451 100644 (file)
@@ -300,7 +300,7 @@ static void ah_destroy(struct xfrm_state *x)
 }
 
 
-static struct xfrm_type ah_type =
+static const struct xfrm_type ah_type =
 {
        .description    = "AH4",
        .owner          = THIS_MODULE,
index 5976c598cc4ba5e5cee2e7f089dc9cbd84f70a9a..8e17f65f400215a72c3ac3effb908071255d2747 100644 (file)
@@ -558,8 +558,9 @@ static inline int arp_fwd_proxy(struct in_device *in_dev, struct rtable *rt)
  */
 struct sk_buff *arp_create(int type, int ptype, __be32 dest_ip,
                           struct net_device *dev, __be32 src_ip,
-                          unsigned char *dest_hw, unsigned char *src_hw,
-                          unsigned char *target_hw)
+                          const unsigned char *dest_hw,
+                          const unsigned char *src_hw,
+                          const unsigned char *target_hw)
 {
        struct sk_buff *skb;
        struct arphdr *arp;
@@ -672,8 +673,8 @@ void arp_xmit(struct sk_buff *skb)
  */
 void arp_send(int type, int ptype, __be32 dest_ip,
              struct net_device *dev, __be32 src_ip,
-             unsigned char *dest_hw, unsigned char *src_hw,
-             unsigned char *target_hw)
+             const unsigned char *dest_hw, const unsigned char *src_hw,
+             const unsigned char *target_hw)
 {
        struct sk_buff *skb;
 
index a2241060113be3d47d9a3f88919e8b5b8c5a9f4a..8cd357f41283504f98e55d7a3ffe2d9090dbcd38 100644 (file)
@@ -547,8 +547,8 @@ int cipso_v4_doi_remove(u32 doi,
                rcu_read_lock();
                list_for_each_entry_rcu(dom_iter, &doi_def->dom_list, list)
                        if (dom_iter->valid)
-                               netlbl_domhsh_remove(dom_iter->domain,
-                                                    audit_info);
+                               netlbl_cfg_map_del(dom_iter->domain,
+                                                  audit_info);
                rcu_read_unlock();
                cipso_v4_cache_invalidate();
                call_rcu(&doi_def->rcu, callback);
index 21f71bf912d5b1621ec81fc4807dcde7f7355166..f282b26f63eb7c20d0b456e104b1a8772b009bb8 100644 (file)
@@ -64,7 +64,7 @@
 #include <net/rtnetlink.h>
 #include <net/net_namespace.h>
 
-struct ipv4_devconf ipv4_devconf = {
+static struct ipv4_devconf ipv4_devconf = {
        .data = {
                [NET_IPV4_CONF_ACCEPT_REDIRECTS - 1] = 1,
                [NET_IPV4_CONF_SEND_REDIRECTS - 1] = 1,
@@ -485,46 +485,41 @@ errout:
        return err;
 }
 
-static struct in_ifaddr *rtm_to_ifaddr(struct nlmsghdr *nlh)
+static struct in_ifaddr *rtm_to_ifaddr(struct net *net, struct nlmsghdr *nlh)
 {
        struct nlattr *tb[IFA_MAX+1];
        struct in_ifaddr *ifa;
        struct ifaddrmsg *ifm;
        struct net_device *dev;
        struct in_device *in_dev;
-       int err = -EINVAL;
+       int err;
 
        err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv4_policy);
        if (err < 0)
                goto errout;
 
        ifm = nlmsg_data(nlh);
-       if (ifm->ifa_prefixlen > 32 || tb[IFA_LOCAL] == NULL) {
-               err = -EINVAL;
+       err = -EINVAL;
+       if (ifm->ifa_prefixlen > 32 || tb[IFA_LOCAL] == NULL)
                goto errout;
-       }
 
-       dev = __dev_get_by_index(&init_net, ifm->ifa_index);
-       if (dev == NULL) {
-               err = -ENODEV;
+       dev = __dev_get_by_index(net, ifm->ifa_index);
+       err = -ENODEV;
+       if (dev == NULL)
                goto errout;
-       }
 
        in_dev = __in_dev_get_rtnl(dev);
-       if (in_dev == NULL) {
-               err = -ENOBUFS;
+       err = -ENOBUFS;
+       if (in_dev == NULL)
                goto errout;
-       }
 
        ifa = inet_alloc_ifa();
-       if (ifa == NULL) {
+       if (ifa == NULL)
                /*
                 * A potential indev allocation can be left alive, it stays
                 * assigned to its device and is destroy with it.
                 */
-               err = -ENOBUFS;
                goto errout;
-       }
 
        ipv4_devconf_setall(in_dev);
        in_dev_hold(in_dev);
@@ -568,7 +563,7 @@ static int inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg
        if (net != &init_net)
                return -EINVAL;
 
-       ifa = rtm_to_ifaddr(nlh);
+       ifa = rtm_to_ifaddr(net, nlh);
        if (IS_ERR(ifa))
                return PTR_ERR(ifa);
 
@@ -1182,7 +1177,7 @@ static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
 
        s_ip_idx = ip_idx = cb->args[1];
        idx = 0;
-       for_each_netdev(&init_net, dev) {
+       for_each_netdev(net, dev) {
                if (idx < s_idx)
                        goto cont;
                if (idx > s_idx)
@@ -1216,7 +1211,9 @@ static void rtmsg_ifa(int event, struct in_ifaddr* ifa, struct nlmsghdr *nlh,
        struct sk_buff *skb;
        u32 seq = nlh ? nlh->nlmsg_seq : 0;
        int err = -ENOBUFS;
+       struct net *net;
 
+       net = ifa->ifa_dev->dev->nd_net;
        skb = nlmsg_new(inet_nlmsg_size(), GFP_KERNEL);
        if (skb == NULL)
                goto errout;
@@ -1228,10 +1225,10 @@ static void rtmsg_ifa(int event, struct in_ifaddr* ifa, struct nlmsghdr *nlh,
                kfree_skb(skb);
                goto errout;
        }
-       err = rtnl_notify(skb, &init_net, pid, RTNLGRP_IPV4_IFADDR, nlh, GFP_KERNEL);
+       err = rtnl_notify(skb, net, pid, RTNLGRP_IPV4_IFADDR, nlh, GFP_KERNEL);
 errout:
        if (err < 0)
-               rtnl_set_sk_err(&init_net, RTNLGRP_IPV4_IFADDR, err);
+               rtnl_set_sk_err(net, RTNLGRP_IPV4_IFADDR, err);
 }
 
 #ifdef CONFIG_SYSCTL
index 28ea5c77ca238a72a424ae292c2decc622c2d70e..258d17631b4bb9b1767b8a8afa8582250f046a3a 100644 (file)
+#include <crypto/aead.h>
+#include <crypto/authenc.h>
 #include <linux/err.h>
 #include <linux/module.h>
 #include <net/ip.h>
 #include <net/xfrm.h>
 #include <net/esp.h>
 #include <linux/scatterlist.h>
-#include <linux/crypto.h>
 #include <linux/kernel.h>
 #include <linux/pfkeyv2.h>
-#include <linux/random.h>
+#include <linux/rtnetlink.h>
+#include <linux/slab.h>
 #include <linux/spinlock.h>
 #include <linux/in6.h>
 #include <net/icmp.h>
 #include <net/protocol.h>
 #include <net/udp.h>
 
+struct esp_skb_cb {
+       struct xfrm_skb_cb xfrm;
+       void *tmp;
+};
+
+#define ESP_SKB_CB(__skb) ((struct esp_skb_cb *)&((__skb)->cb[0]))
+
+/*
+ * Allocate an AEAD request structure with extra space for SG and IV.
+ *
+ * For alignment considerations the IV is placed at the front, followed
+ * by the request and finally the SG list.
+ *
+ * TODO: Use spare space in skb for this where possible.
+ */
+static void *esp_alloc_tmp(struct crypto_aead *aead, int nfrags)
+{
+       unsigned int len;
+
+       len = crypto_aead_ivsize(aead);
+       if (len) {
+               len += crypto_aead_alignmask(aead) &
+                      ~(crypto_tfm_ctx_alignment() - 1);
+               len = ALIGN(len, crypto_tfm_ctx_alignment());
+       }
+
+       len += sizeof(struct aead_givcrypt_request) + crypto_aead_reqsize(aead);
+       len = ALIGN(len, __alignof__(struct scatterlist));
+
+       len += sizeof(struct scatterlist) * nfrags;
+
+       return kmalloc(len, GFP_ATOMIC);
+}
+
+static inline u8 *esp_tmp_iv(struct crypto_aead *aead, void *tmp)
+{
+       return crypto_aead_ivsize(aead) ?
+              PTR_ALIGN((u8 *)tmp, crypto_aead_alignmask(aead) + 1) : tmp;
+}
+
+static inline struct aead_givcrypt_request *esp_tmp_givreq(
+       struct crypto_aead *aead, u8 *iv)
+{
+       struct aead_givcrypt_request *req;
+
+       req = (void *)PTR_ALIGN(iv + crypto_aead_ivsize(aead),
+                               crypto_tfm_ctx_alignment());
+       aead_givcrypt_set_tfm(req, aead);
+       return req;
+}
+
+static inline struct aead_request *esp_tmp_req(struct crypto_aead *aead, u8 *iv)
+{
+       struct aead_request *req;
+
+       req = (void *)PTR_ALIGN(iv + crypto_aead_ivsize(aead),
+                               crypto_tfm_ctx_alignment());
+       aead_request_set_tfm(req, aead);
+       return req;
+}
+
+static inline struct scatterlist *esp_req_sg(struct crypto_aead *aead,
+                                            struct aead_request *req)
+{
+       return (void *)ALIGN((unsigned long)(req + 1) +
+                            crypto_aead_reqsize(aead),
+                            __alignof__(struct scatterlist));
+}
+
+static inline struct scatterlist *esp_givreq_sg(
+       struct crypto_aead *aead, struct aead_givcrypt_request *req)
+{
+       return (void *)ALIGN((unsigned long)(req + 1) +
+                            crypto_aead_reqsize(aead),
+                            __alignof__(struct scatterlist));
+}
+
+static void esp_output_done(struct crypto_async_request *base, int err)
+{
+       struct sk_buff *skb = base->data;
+
+       kfree(ESP_SKB_CB(skb)->tmp);
+       xfrm_output_resume(skb, err);
+}
+
 static int esp_output(struct xfrm_state *x, struct sk_buff *skb)
 {
        int err;
        struct ip_esp_hdr *esph;
-       struct crypto_blkcipher *tfm;
-       struct blkcipher_desc desc;
+       struct crypto_aead *aead;
+       struct aead_givcrypt_request *req;
+       struct scatterlist *sg;
+       struct scatterlist *asg;
        struct esp_data *esp;
        struct sk_buff *trailer;
+       void *tmp;
+       u8 *iv;
        u8 *tail;
        int blksize;
        int clen;
@@ -36,18 +127,27 @@ static int esp_output(struct xfrm_state *x, struct sk_buff *skb)
        clen = skb->len;
 
        esp = x->data;
-       alen = esp->auth.icv_trunc_len;
-       tfm = esp->conf.tfm;
-       desc.tfm = tfm;
-       desc.flags = 0;
-       blksize = ALIGN(crypto_blkcipher_blocksize(tfm), 4);
+       aead = esp->aead;
+       alen = crypto_aead_authsize(aead);
+
+       blksize = ALIGN(crypto_aead_blocksize(aead), 4);
        clen = ALIGN(clen + 2, blksize);
-       if (esp->conf.padlen)
-               clen = ALIGN(clen, esp->conf.padlen);
+       if (esp->padlen)
+               clen = ALIGN(clen, esp->padlen);
+
+       if ((err = skb_cow_data(skb, clen - skb->len + alen, &trailer)) < 0)
+               goto error;
+       nfrags = err;
 
-       if ((nfrags = skb_cow_data(skb, clen-skb->len+alen, &trailer)) < 0)
+       tmp = esp_alloc_tmp(aead, nfrags + 1);
+       if (!tmp)
                goto error;
 
+       iv = esp_tmp_iv(aead, tmp);
+       req = esp_tmp_givreq(aead, iv);
+       asg = esp_givreq_sg(aead, req);
+       sg = asg + 1;
+
        /* Fill padding... */
        tail = skb_tail_pointer(trailer);
        do {
@@ -56,28 +156,34 @@ static int esp_output(struct xfrm_state *x, struct sk_buff *skb)
                        tail[i] = i + 1;
        } while (0);
        tail[clen - skb->len - 2] = (clen - skb->len) - 2;
-       pskb_put(skb, trailer, clen - skb->len);
+       tail[clen - skb->len - 1] = *skb_mac_header(skb);
+       pskb_put(skb, trailer, clen - skb->len + alen);
 
        skb_push(skb, -skb_network_offset(skb));
        esph = ip_esp_hdr(skb);
-       *(skb_tail_pointer(trailer) - 1) = *skb_mac_header(skb);
        *skb_mac_header(skb) = IPPROTO_ESP;
 
-       spin_lock_bh(&x->lock);
-
        /* this is non-NULL only with UDP Encapsulation */
        if (x->encap) {
                struct xfrm_encap_tmpl *encap = x->encap;
                struct udphdr *uh;
                __be32 *udpdata32;
+               unsigned int sport, dport;
+               int encap_type;
+
+               spin_lock_bh(&x->lock);
+               sport = encap->encap_sport;
+               dport = encap->encap_dport;
+               encap_type = encap->encap_type;
+               spin_unlock_bh(&x->lock);
 
                uh = (struct udphdr *)esph;
-               uh->source = encap->encap_sport;
-               uh->dest = encap->encap_dport;
-               uh->len = htons(skb->len + alen - skb_transport_offset(skb));
+               uh->source = sport;
+               uh->dest = dport;
+               uh->len = htons(skb->len - skb_transport_offset(skb));
                uh->check = 0;
 
-               switch (encap->encap_type) {
+               switch (encap_type) {
                default:
                case UDP_ENCAP_ESPINUDP:
                        esph = (struct ip_esp_hdr *)(uh + 1);
@@ -95,131 +201,45 @@ static int esp_output(struct xfrm_state *x, struct sk_buff *skb)
        esph->spi = x->id.spi;
        esph->seq_no = htonl(XFRM_SKB_CB(skb)->seq);
 
-       if (esp->conf.ivlen) {
-               if (unlikely(!esp->conf.ivinitted)) {
-                       get_random_bytes(esp->conf.ivec, esp->conf.ivlen);
-                       esp->conf.ivinitted = 1;
-               }
-               crypto_blkcipher_set_iv(tfm, esp->conf.ivec, esp->conf.ivlen);
-       }
-
-       do {
-               struct scatterlist *sg = &esp->sgbuf[0];
-
-               if (unlikely(nfrags > ESP_NUM_FAST_SG)) {
-                       sg = kmalloc(sizeof(struct scatterlist)*nfrags, GFP_ATOMIC);
-                       if (!sg)
-                               goto unlock;
-               }
-               sg_init_table(sg, nfrags);
-               skb_to_sgvec(skb, sg,
-                            esph->enc_data +
-                            esp->conf.ivlen -
-                            skb->data, clen);
-               err = crypto_blkcipher_encrypt(&desc, sg, sg, clen);
-               if (unlikely(sg != &esp->sgbuf[0]))
-                       kfree(sg);
-       } while (0);
-
-       if (unlikely(err))
-               goto unlock;
-
-       if (esp->conf.ivlen) {
-               memcpy(esph->enc_data, esp->conf.ivec, esp->conf.ivlen);
-               crypto_blkcipher_get_iv(tfm, esp->conf.ivec, esp->conf.ivlen);
-       }
+       sg_init_table(sg, nfrags);
+       skb_to_sgvec(skb, sg,
+                    esph->enc_data + crypto_aead_ivsize(aead) - skb->data,
+                    clen + alen);
+       sg_init_one(asg, esph, sizeof(*esph));
+
+       aead_givcrypt_set_callback(req, 0, esp_output_done, skb);
+       aead_givcrypt_set_crypt(req, sg, sg, clen, iv);
+       aead_givcrypt_set_assoc(req, asg, sizeof(*esph));
+       aead_givcrypt_set_giv(req, esph->enc_data, XFRM_SKB_CB(skb)->seq);
+
+       ESP_SKB_CB(skb)->tmp = tmp;
+       err = crypto_aead_givencrypt(req);
+       if (err == -EINPROGRESS)
+               goto error;
 
-       if (esp->auth.icv_full_len) {
-               err = esp_mac_digest(esp, skb, (u8 *)esph - skb->data,
-                                    sizeof(*esph) + esp->conf.ivlen + clen);
-               memcpy(pskb_put(skb, trailer, alen), esp->auth.work_icv, alen);
-       }
+       if (err == -EBUSY)
+               err = NET_XMIT_DROP;
 
-unlock:
-       spin_unlock_bh(&x->lock);
+       kfree(tmp);
 
 error:
        return err;
 }
 
-/*
- * Note: detecting truncated vs. non-truncated authentication data is very
- * expensive, so we only support truncated data, which is the recommended
- * and common case.
- */
-static int esp_input(struct xfrm_state *x, struct sk_buff *skb)
+static int esp_input_done2(struct sk_buff *skb, int err)
 {
        struct iphdr *iph;
-       struct ip_esp_hdr *esph;
+       struct xfrm_state *x = xfrm_input_state(skb);
        struct esp_data *esp = x->data;
-       struct crypto_blkcipher *tfm = esp->conf.tfm;
-       struct blkcipher_desc desc = { .tfm = tfm };
-       struct sk_buff *trailer;
-       int blksize = ALIGN(crypto_blkcipher_blocksize(tfm), 4);
-       int alen = esp->auth.icv_trunc_len;
-       int elen = skb->len - sizeof(*esph) - esp->conf.ivlen - alen;
-       int nfrags;
+       struct crypto_aead *aead = esp->aead;
+       int alen = crypto_aead_authsize(aead);
+       int hlen = sizeof(struct ip_esp_hdr) + crypto_aead_ivsize(aead);
+       int elen = skb->len - hlen;
        int ihl;
        u8 nexthdr[2];
-       struct scatterlist *sg;
        int padlen;
-       int err = -EINVAL;
-
-       if (!pskb_may_pull(skb, sizeof(*esph)))
-               goto out;
-
-       if (elen <= 0 || (elen & (blksize-1)))
-               goto out;
-
-       if ((err = skb_cow_data(skb, 0, &trailer)) < 0)
-               goto out;
-       nfrags = err;
-
-       skb->ip_summed = CHECKSUM_NONE;
-
-       spin_lock(&x->lock);
-
-       /* If integrity check is required, do this. */
-       if (esp->auth.icv_full_len) {
-               u8 sum[alen];
 
-               err = esp_mac_digest(esp, skb, 0, skb->len - alen);
-               if (err)
-                       goto unlock;
-
-               if (skb_copy_bits(skb, skb->len - alen, sum, alen))
-                       BUG();
-
-               if (unlikely(memcmp(esp->auth.work_icv, sum, alen))) {
-                       err = -EBADMSG;
-                       goto unlock;
-               }
-       }
-
-       esph = (struct ip_esp_hdr *)skb->data;
-
-       /* Get ivec. This can be wrong, check against another impls. */
-       if (esp->conf.ivlen)
-               crypto_blkcipher_set_iv(tfm, esph->enc_data, esp->conf.ivlen);
-
-       sg = &esp->sgbuf[0];
-
-       if (unlikely(nfrags > ESP_NUM_FAST_SG)) {
-               err = -ENOMEM;
-               sg = kmalloc(sizeof(struct scatterlist)*nfrags, GFP_ATOMIC);
-               if (!sg)
-                       goto unlock;
-       }
-       sg_init_table(sg, nfrags);
-       skb_to_sgvec(skb, sg,
-                    sizeof(*esph) + esp->conf.ivlen,
-                    elen);
-       err = crypto_blkcipher_decrypt(&desc, sg, sg, elen);
-       if (unlikely(sg != &esp->sgbuf[0]))
-               kfree(sg);
-
-unlock:
-       spin_unlock(&x->lock);
+       kfree(ESP_SKB_CB(skb)->tmp);
 
        if (unlikely(err))
                goto out;
@@ -229,15 +249,11 @@ unlock:
 
        err = -EINVAL;
        padlen = nexthdr[0];
-       if (padlen+2 >= elen)
+       if (padlen + 2 + alen >= elen)
                goto out;
 
        /* ... check padding bits here. Silly. :-) */
 
-       /* RFC4303: Drop dummy packets without any error */
-       if (nexthdr[1] == IPPROTO_NONE)
-               goto out;
-
        iph = ip_hdr(skb);
        ihl = iph->ihl * 4;
 
@@ -279,10 +295,87 @@ unlock:
        }
 
        pskb_trim(skb, skb->len - alen - padlen - 2);
-       __skb_pull(skb, sizeof(*esph) + esp->conf.ivlen);
+       __skb_pull(skb, hlen);
        skb_set_transport_header(skb, -ihl);
 
-       return nexthdr[1];
+       err = nexthdr[1];
+
+       /* RFC4303: Drop dummy packets without any error */
+       if (err == IPPROTO_NONE)
+               err = -EINVAL;
+
+out:
+       return err;
+}
+
+static void esp_input_done(struct crypto_async_request *base, int err)
+{
+       struct sk_buff *skb = base->data;
+
+       xfrm_input_resume(skb, esp_input_done2(skb, err));
+}
+
+/*
+ * Note: detecting truncated vs. non-truncated authentication data is very
+ * expensive, so we only support truncated data, which is the recommended
+ * and common case.
+ */
+static int esp_input(struct xfrm_state *x, struct sk_buff *skb)
+{
+       struct ip_esp_hdr *esph;
+       struct esp_data *esp = x->data;
+       struct crypto_aead *aead = esp->aead;
+       struct aead_request *req;
+       struct sk_buff *trailer;
+       int elen = skb->len - sizeof(*esph) - crypto_aead_ivsize(aead);
+       int nfrags;
+       void *tmp;
+       u8 *iv;
+       struct scatterlist *sg;
+       struct scatterlist *asg;
+       int err = -EINVAL;
+
+       if (!pskb_may_pull(skb, sizeof(*esph)))
+               goto out;
+
+       if (elen <= 0)
+               goto out;
+
+       if ((err = skb_cow_data(skb, 0, &trailer)) < 0)
+               goto out;
+       nfrags = err;
+
+       err = -ENOMEM;
+       tmp = esp_alloc_tmp(aead, nfrags + 1);
+       if (!tmp)
+               goto out;
+
+       ESP_SKB_CB(skb)->tmp = tmp;
+       iv = esp_tmp_iv(aead, tmp);
+       req = esp_tmp_req(aead, iv);
+       asg = esp_req_sg(aead, req);
+       sg = asg + 1;
+
+       skb->ip_summed = CHECKSUM_NONE;
+
+       esph = (struct ip_esp_hdr *)skb->data;
+
+       /* Get ivec. This can be wrong, check against another impls. */
+       iv = esph->enc_data;
+
+       sg_init_table(sg, nfrags);
+       skb_to_sgvec(skb, sg, sizeof(*esph) + crypto_aead_ivsize(aead), elen);
+       sg_init_one(asg, esph, sizeof(*esph));
+
+       aead_request_set_callback(req, 0, esp_input_done, skb);
+       aead_request_set_crypt(req, sg, sg, elen, iv);
+       aead_request_set_assoc(req, asg, sizeof(*esph));
+
+       err = crypto_aead_decrypt(req);
+       if (err == -EINPROGRESS)
+               goto out;
+
+       err = esp_input_done2(skb, err);
 
 out:
        return err;
@@ -291,11 +384,11 @@ out:
 static u32 esp4_get_mtu(struct xfrm_state *x, int mtu)
 {
        struct esp_data *esp = x->data;
-       u32 blksize = ALIGN(crypto_blkcipher_blocksize(esp->conf.tfm), 4);
-       u32 align = max_t(u32, blksize, esp->conf.padlen);
+       u32 blksize = ALIGN(crypto_aead_blocksize(esp->aead), 4);
+       u32 align = max_t(u32, blksize, esp->padlen);
        u32 rem;
 
-       mtu -= x->props.header_len + esp->auth.icv_trunc_len;
+       mtu -= x->props.header_len + crypto_aead_authsize(esp->aead);
        rem = mtu & (align - 1);
        mtu &= ~(align - 1);
 
@@ -342,80 +435,143 @@ static void esp_destroy(struct xfrm_state *x)
        if (!esp)
                return;
 
-       crypto_free_blkcipher(esp->conf.tfm);
-       esp->conf.tfm = NULL;
-       kfree(esp->conf.ivec);
-       esp->conf.ivec = NULL;
-       crypto_free_hash(esp->auth.tfm);
-       esp->auth.tfm = NULL;
-       kfree(esp->auth.work_icv);
-       esp->auth.work_icv = NULL;
+       crypto_free_aead(esp->aead);
        kfree(esp);
 }
 
-static int esp_init_state(struct xfrm_state *x)
+static int esp_init_aead(struct xfrm_state *x)
 {
-       struct esp_data *esp = NULL;
-       struct crypto_blkcipher *tfm;
-       u32 align;
+       struct esp_data *esp = x->data;
+       struct crypto_aead *aead;
+       int err;
+
+       aead = crypto_alloc_aead(x->aead->alg_name, 0, 0);
+       err = PTR_ERR(aead);
+       if (IS_ERR(aead))
+               goto error;
+
+       esp->aead = aead;
+
+       err = crypto_aead_setkey(aead, x->aead->alg_key,
+                                (x->aead->alg_key_len + 7) / 8);
+       if (err)
+               goto error;
+
+       err = crypto_aead_setauthsize(aead, x->aead->alg_icv_len / 8);
+       if (err)
+               goto error;
+
+error:
+       return err;
+}
 
+static int esp_init_authenc(struct xfrm_state *x)
+{
+       struct esp_data *esp = x->data;
+       struct crypto_aead *aead;
+       struct crypto_authenc_key_param *param;
+       struct rtattr *rta;
+       char *key;
+       char *p;
+       char authenc_name[CRYPTO_MAX_ALG_NAME];
+       unsigned int keylen;
+       int err;
+
+       err = -EINVAL;
        if (x->ealg == NULL)
                goto error;
 
-       esp = kzalloc(sizeof(*esp), GFP_KERNEL);
-       if (esp == NULL)
-               return -ENOMEM;
+       err = -ENAMETOOLONG;
+       if (snprintf(authenc_name, CRYPTO_MAX_ALG_NAME, "authenc(%s,%s)",
+                    x->aalg ? x->aalg->alg_name : "digest_null",
+                    x->ealg->alg_name) >= CRYPTO_MAX_ALG_NAME)
+               goto error;
+
+       aead = crypto_alloc_aead(authenc_name, 0, 0);
+       err = PTR_ERR(aead);
+       if (IS_ERR(aead))
+               goto error;
+
+       esp->aead = aead;
+
+       keylen = (x->aalg ? (x->aalg->alg_key_len + 7) / 8 : 0) +
+                (x->ealg->alg_key_len + 7) / 8 + RTA_SPACE(sizeof(*param));
+       err = -ENOMEM;
+       key = kmalloc(keylen, GFP_KERNEL);
+       if (!key)
+               goto error;
+
+       p = key;
+       rta = (void *)p;
+       rta->rta_type = CRYPTO_AUTHENC_KEYA_PARAM;
+       rta->rta_len = RTA_LENGTH(sizeof(*param));
+       param = RTA_DATA(rta);
+       p += RTA_SPACE(sizeof(*param));
 
        if (x->aalg) {
                struct xfrm_algo_desc *aalg_desc;
-               struct crypto_hash *hash;
 
-               hash = crypto_alloc_hash(x->aalg->alg_name, 0,
-                                        CRYPTO_ALG_ASYNC);
-               if (IS_ERR(hash))
-                       goto error;
-
-               esp->auth.tfm = hash;
-               if (crypto_hash_setkey(hash, x->aalg->alg_key,
-                                      (x->aalg->alg_key_len + 7) / 8))
-                       goto error;
+               memcpy(p, x->aalg->alg_key, (x->aalg->alg_key_len + 7) / 8);
+               p += (x->aalg->alg_key_len + 7) / 8;
 
                aalg_desc = xfrm_aalg_get_byname(x->aalg->alg_name, 0);
                BUG_ON(!aalg_desc);
 
+               err = -EINVAL;
                if (aalg_desc->uinfo.auth.icv_fullbits/8 !=
-                   crypto_hash_digestsize(hash)) {
+                   crypto_aead_authsize(aead)) {
                        NETDEBUG(KERN_INFO "ESP: %s digestsize %u != %hu\n",
                                 x->aalg->alg_name,
-                                crypto_hash_digestsize(hash),
+                                crypto_aead_authsize(aead),
                                 aalg_desc->uinfo.auth.icv_fullbits/8);
-                       goto error;
+                       goto free_key;
                }
 
-               esp->auth.icv_full_len = aalg_desc->uinfo.auth.icv_fullbits/8;
-               esp->auth.icv_trunc_len = aalg_desc->uinfo.auth.icv_truncbits/8;
-
-               esp->auth.work_icv = kmalloc(esp->auth.icv_full_len, GFP_KERNEL);
-               if (!esp->auth.work_icv)
-                       goto error;
+               err = crypto_aead_setauthsize(
+                       aead, aalg_desc->uinfo.auth.icv_truncbits / 8);
+               if (err)
+                       goto free_key;
        }
 
-       tfm = crypto_alloc_blkcipher(x->ealg->alg_name, 0, CRYPTO_ALG_ASYNC);
-       if (IS_ERR(tfm))
-               goto error;
-       esp->conf.tfm = tfm;
-       esp->conf.ivlen = crypto_blkcipher_ivsize(tfm);
-       esp->conf.padlen = 0;
-       if (esp->conf.ivlen) {
-               esp->conf.ivec = kmalloc(esp->conf.ivlen, GFP_KERNEL);
-               if (unlikely(esp->conf.ivec == NULL))
-                       goto error;
-               esp->conf.ivinitted = 0;
-       }
-       if (crypto_blkcipher_setkey(tfm, x->ealg->alg_key,
-                                   (x->ealg->alg_key_len + 7) / 8))
+       param->enckeylen = cpu_to_be32((x->ealg->alg_key_len + 7) / 8);
+       memcpy(p, x->ealg->alg_key, (x->ealg->alg_key_len + 7) / 8);
+
+       err = crypto_aead_setkey(aead, key, keylen);
+
+free_key:
+       kfree(key);
+
+error:
+       return err;
+}
+
+static int esp_init_state(struct xfrm_state *x)
+{
+       struct esp_data *esp;
+       struct crypto_aead *aead;
+       u32 align;
+       int err;
+
+       esp = kzalloc(sizeof(*esp), GFP_KERNEL);
+       if (esp == NULL)
+               return -ENOMEM;
+
+       x->data = esp;
+
+       if (x->aead)
+               err = esp_init_aead(x);
+       else
+               err = esp_init_authenc(x);
+
+       if (err)
                goto error;
-       x->props.header_len = sizeof(struct ip_esp_hdr) + esp->conf.ivlen;
+
+       aead = esp->aead;
+
+       esp->padlen = 0;
+
+       x->props.header_len = sizeof(struct ip_esp_hdr) +
+                             crypto_aead_ivsize(aead);
        if (x->props.mode == XFRM_MODE_TUNNEL)
                x->props.header_len += sizeof(struct iphdr);
        else if (x->props.mode == XFRM_MODE_BEET)
@@ -434,21 +590,17 @@ static int esp_init_state(struct xfrm_state *x)
                        break;
                }
        }
-       x->data = esp;
-       align = ALIGN(crypto_blkcipher_blocksize(esp->conf.tfm), 4);
-       if (esp->conf.padlen)
-               align = max_t(u32, align, esp->conf.padlen);
-       x->props.trailer_len = align + 1 + esp->auth.icv_trunc_len;
-       return 0;
+
+       align = ALIGN(crypto_aead_blocksize(aead), 4);
+       if (esp->padlen)
+               align = max_t(u32, align, esp->padlen);
+       x->props.trailer_len = align + 1 + crypto_aead_authsize(esp->aead);
 
 error:
-       x->data = esp;
-       esp_destroy(x);
-       x->data = NULL;
-       return -EINVAL;
+       return err;
 }
 
-static struct xfrm_type esp_type =
+static const struct xfrm_type esp_type =
 {
        .description    = "ESP4",
        .owner          = THIS_MODULE,
index d28261826bc2b35b775946a378cef1959fa99077..86ff2711fc957977f179da841a0ffc3b698e75ac 100644 (file)
@@ -808,7 +808,7 @@ static void fib_del_ifaddr(struct in_ifaddr *ifa)
                           First of all, we scan fib_info list searching
                           for stray nexthop entries, then ignite fib_flush.
                        */
-                       if (fib_sync_down(ifa->ifa_local, NULL, 0))
+                       if (fib_sync_down_addr(dev->nd_net, ifa->ifa_local))
                                fib_flush(dev->nd_net);
                }
        }
@@ -898,7 +898,7 @@ static void nl_fib_lookup_exit(struct net *net)
 
 static void fib_disable_ip(struct net_device *dev, int force)
 {
-       if (fib_sync_down(0, dev, force))
+       if (fib_sync_down_dev(dev, force))
                fib_flush(dev->nd_net);
        rt_cache_flush(0);
        arp_ifdown(dev);
@@ -975,6 +975,7 @@ static struct notifier_block fib_netdev_notifier = {
 
 static int __net_init ip_fib_net_init(struct net *net)
 {
+       int err;
        unsigned int i;
 
        net->ipv4.fib_table_hash = kzalloc(
@@ -985,7 +986,14 @@ static int __net_init ip_fib_net_init(struct net *net)
        for (i = 0; i < FIB_TABLE_HASHSZ; i++)
                INIT_HLIST_HEAD(&net->ipv4.fib_table_hash[i]);
 
-       return fib4_rules_init(net);
+       err = fib4_rules_init(net);
+       if (err < 0)
+               goto fail;
+       return 0;
+
+fail:
+       kfree(net->ipv4.fib_table_hash);
+       return err;
 }
 
 static void __net_exit ip_fib_net_exit(struct net *net)
index a15b2f1b2721d8d4239c81f4eddf13f3fccd6947..76b9c684cccd2ac6d159ea597c0e734ed26f4b05 100644 (file)
@@ -424,19 +424,43 @@ static int fn_hash_insert(struct fib_table *tb, struct fib_config *cfg)
 
        if (fa && fa->fa_tos == tos &&
            fa->fa_info->fib_priority == fi->fib_priority) {
-               struct fib_alias *fa_orig;
+               struct fib_alias *fa_first, *fa_match;
 
                err = -EEXIST;
                if (cfg->fc_nlflags & NLM_F_EXCL)
                        goto out;
 
+               /* We have 2 goals:
+                * 1. Find exact match for type, scope, fib_info to avoid
+                * duplicate routes
+                * 2. Find next 'fa' (or head), NLM_F_APPEND inserts before it
+                */
+               fa_match = NULL;
+               fa_first = fa;
+               fa = list_entry(fa->fa_list.prev, struct fib_alias, fa_list);
+               list_for_each_entry_continue(fa, &f->fn_alias, fa_list) {
+                       if (fa->fa_tos != tos)
+                               break;
+                       if (fa->fa_info->fib_priority != fi->fib_priority)
+                               break;
+                       if (fa->fa_type == cfg->fc_type &&
+                           fa->fa_scope == cfg->fc_scope &&
+                           fa->fa_info == fi) {
+                               fa_match = fa;
+                               break;
+                       }
+               }
+
                if (cfg->fc_nlflags & NLM_F_REPLACE) {
                        struct fib_info *fi_drop;
                        u8 state;
 
-                       if (fi->fib_treeref > 1)
+                       fa = fa_first;
+                       if (fa_match) {
+                               if (fa == fa_match)
+                                       err = 0;
                                goto out;
-
+                       }
                        write_lock_bh(&fib_hash_lock);
                        fi_drop = fa->fa_info;
                        fa->fa_info = fi;
@@ -459,20 +483,11 @@ static int fn_hash_insert(struct fib_table *tb, struct fib_config *cfg)
                 * uses the same scope, type, and nexthop
                 * information.
                 */
-               fa_orig = fa;
-               fa = list_entry(fa->fa_list.prev, struct fib_alias, fa_list);
-               list_for_each_entry_continue(fa, &f->fn_alias, fa_list) {
-                       if (fa->fa_tos != tos)
-                               break;
-                       if (fa->fa_info->fib_priority != fi->fib_priority)
-                               break;
-                       if (fa->fa_type == cfg->fc_type &&
-                           fa->fa_scope == cfg->fc_scope &&
-                           fa->fa_info == fi)
-                               goto out;
-               }
+               if (fa_match)
+                       goto out;
+
                if (!(cfg->fc_nlflags & NLM_F_APPEND))
-                       fa = fa_orig;
+                       fa = fa_first;
        }
 
        err = -ENOENT;
index c7912866d98719d248c796c89b1a1ef9d899e92a..a13c84763d4c10e503e418f2e6afef3e353193c3 100644 (file)
@@ -229,6 +229,8 @@ static struct fib_info *fib_find_info(const struct fib_info *nfi)
        head = &fib_info_hash[hash];
 
        hlist_for_each_entry(fi, node, head, fib_hash) {
+               if (fi->fib_net != nfi->fib_net)
+                       continue;
                if (fi->fib_nhs != nfi->fib_nhs)
                        continue;
                if (nfi->fib_protocol == fi->fib_protocol &&
@@ -687,6 +689,7 @@ struct fib_info *fib_create_info(struct fib_config *cfg)
        struct fib_info *fi = NULL;
        struct fib_info *ofi;
        int nhs = 1;
+       struct net *net = cfg->fc_nlinfo.nl_net;
 
        /* Fast check to catch the most weird cases */
        if (fib_props[cfg->fc_type].scope > cfg->fc_scope)
@@ -727,6 +730,7 @@ struct fib_info *fib_create_info(struct fib_config *cfg)
                goto failure;
        fib_info_cnt++;
 
+       fi->fib_net = net;
        fi->fib_protocol = cfg->fc_protocol;
        fi->fib_flags = cfg->fc_flags;
        fi->fib_priority = cfg->fc_priority;
@@ -798,8 +802,7 @@ struct fib_info *fib_create_info(struct fib_config *cfg)
                if (nhs != 1 || nh->nh_gw)
                        goto err_inval;
                nh->nh_scope = RT_SCOPE_NOWHERE;
-               nh->nh_dev = dev_get_by_index(cfg->fc_nlinfo.nl_net,
-                                             fi->fib_nh->nh_oif);
+               nh->nh_dev = dev_get_by_index(net, fi->fib_nh->nh_oif);
                err = -ENODEV;
                if (nh->nh_dev == NULL)
                        goto failure;
@@ -813,8 +816,7 @@ struct fib_info *fib_create_info(struct fib_config *cfg)
        if (fi->fib_prefsrc) {
                if (cfg->fc_type != RTN_LOCAL || !cfg->fc_dst ||
                    fi->fib_prefsrc != cfg->fc_dst)
-                       if (inet_addr_type(cfg->fc_nlinfo.nl_net,
-                                          fi->fib_prefsrc) != RTN_LOCAL)
+                       if (inet_addr_type(net, fi->fib_prefsrc) != RTN_LOCAL)
                                goto err_inval;
        }
 
@@ -1031,70 +1033,74 @@ nla_put_failure:
      referring to it.
    - device went down -> we must shutdown all nexthops going via it.
  */
-
-int fib_sync_down(__be32 local, struct net_device *dev, int force)
+int fib_sync_down_addr(struct net *net, __be32 local)
 {
        int ret = 0;
-       int scope = RT_SCOPE_NOWHERE;
-
-       if (force)
-               scope = -1;
+       unsigned int hash = fib_laddr_hashfn(local);
+       struct hlist_head *head = &fib_info_laddrhash[hash];
+       struct hlist_node *node;
+       struct fib_info *fi;
 
-       if (local && fib_info_laddrhash) {
-               unsigned int hash = fib_laddr_hashfn(local);
-               struct hlist_head *head = &fib_info_laddrhash[hash];
-               struct hlist_node *node;
-               struct fib_info *fi;
+       if (fib_info_laddrhash == NULL || local == 0)
+               return 0;
 
-               hlist_for_each_entry(fi, node, head, fib_lhash) {
-                       if (fi->fib_prefsrc == local) {
-                               fi->fib_flags |= RTNH_F_DEAD;
-                               ret++;
-                       }
+       hlist_for_each_entry(fi, node, head, fib_lhash) {
+               if (fi->fib_net != net)
+                       continue;
+               if (fi->fib_prefsrc == local) {
+                       fi->fib_flags |= RTNH_F_DEAD;
+                       ret++;
                }
        }
+       return ret;
+}
 
-       if (dev) {
-               struct fib_info *prev_fi = NULL;
-               unsigned int hash = fib_devindex_hashfn(dev->ifindex);
-               struct hlist_head *head = &fib_info_devhash[hash];
-               struct hlist_node *node;
-               struct fib_nh *nh;
+int fib_sync_down_dev(struct net_device *dev, int force)
+{
+       int ret = 0;
+       int scope = RT_SCOPE_NOWHERE;
+       struct fib_info *prev_fi = NULL;
+       unsigned int hash = fib_devindex_hashfn(dev->ifindex);
+       struct hlist_head *head = &fib_info_devhash[hash];
+       struct hlist_node *node;
+       struct fib_nh *nh;
 
-               hlist_for_each_entry(nh, node, head, nh_hash) {
-                       struct fib_info *fi = nh->nh_parent;
-                       int dead;
+       if (force)
+               scope = -1;
 
-                       BUG_ON(!fi->fib_nhs);
-                       if (nh->nh_dev != dev || fi == prev_fi)
-                               continue;
-                       prev_fi = fi;
-                       dead = 0;
-                       change_nexthops(fi) {
-                               if (nh->nh_flags&RTNH_F_DEAD)
-                                       dead++;
-                               else if (nh->nh_dev == dev &&
-                                        nh->nh_scope != scope) {
-                                       nh->nh_flags |= RTNH_F_DEAD;
+       hlist_for_each_entry(nh, node, head, nh_hash) {
+               struct fib_info *fi = nh->nh_parent;
+               int dead;
+
+               BUG_ON(!fi->fib_nhs);
+               if (nh->nh_dev != dev || fi == prev_fi)
+                       continue;
+               prev_fi = fi;
+               dead = 0;
+               change_nexthops(fi) {
+                       if (nh->nh_flags&RTNH_F_DEAD)
+                               dead++;
+                       else if (nh->nh_dev == dev &&
+                                       nh->nh_scope != scope) {
+                               nh->nh_flags |= RTNH_F_DEAD;
 #ifdef CONFIG_IP_ROUTE_MULTIPATH
-                                       spin_lock_bh(&fib_multipath_lock);
-                                       fi->fib_power -= nh->nh_power;
-                                       nh->nh_power = 0;
-                                       spin_unlock_bh(&fib_multipath_lock);
+                               spin_lock_bh(&fib_multipath_lock);
+                               fi->fib_power -= nh->nh_power;
+                               nh->nh_power = 0;
+                               spin_unlock_bh(&fib_multipath_lock);
 #endif
-                                       dead++;
-                               }
+                               dead++;
+                       }
 #ifdef CONFIG_IP_ROUTE_MULTIPATH
-                               if (force > 1 && nh->nh_dev == dev) {
-                                       dead = fi->fib_nhs;
-                                       break;
-                               }
-#endif
-                       } endfor_nexthops(fi)
-                       if (dead == fi->fib_nhs) {
-                               fi->fib_flags |= RTNH_F_DEAD;
-                               ret++;
+                       if (force > 1 && nh->nh_dev == dev) {
+                               dead = fi->fib_nhs;
+                               break;
                        }
+#endif
+               } endfor_nexthops(fi)
+               if (dead == fi->fib_nhs) {
+                       fi->fib_flags |= RTNH_F_DEAD;
+                       ret++;
                }
        }
 
index f2f47033f31f3a211a1cba23438500c0a1076be9..f5fba3f71c06e09283a29d48f2719bc9ad1be15b 100644 (file)
@@ -1205,20 +1205,45 @@ static int fn_trie_insert(struct fib_table *tb, struct fib_config *cfg)
         * and we need to allocate a new one of those as well.
         */
 
-       if (fa && fa->fa_info->fib_priority == fi->fib_priority) {
-               struct fib_alias *fa_orig;
+       if (fa && fa->fa_tos == tos &&
+           fa->fa_info->fib_priority == fi->fib_priority) {
+               struct fib_alias *fa_first, *fa_match;
 
                err = -EEXIST;
                if (cfg->fc_nlflags & NLM_F_EXCL)
                        goto out;
 
+               /* We have 2 goals:
+                * 1. Find exact match for type, scope, fib_info to avoid
+                * duplicate routes
+                * 2. Find next 'fa' (or head), NLM_F_APPEND inserts before it
+                */
+               fa_match = NULL;
+               fa_first = fa;
+               fa = list_entry(fa->fa_list.prev, struct fib_alias, fa_list);
+               list_for_each_entry_continue(fa, fa_head, fa_list) {
+                       if (fa->fa_tos != tos)
+                               break;
+                       if (fa->fa_info->fib_priority != fi->fib_priority)
+                               break;
+                       if (fa->fa_type == cfg->fc_type &&
+                           fa->fa_scope == cfg->fc_scope &&
+                           fa->fa_info == fi) {
+                               fa_match = fa;
+                               break;
+                       }
+               }
+
                if (cfg->fc_nlflags & NLM_F_REPLACE) {
                        struct fib_info *fi_drop;
                        u8 state;
 
-                       if (fi->fib_treeref > 1)
+                       fa = fa_first;
+                       if (fa_match) {
+                               if (fa == fa_match)
+                                       err = 0;
                                goto out;
-
+                       }
                        err = -ENOBUFS;
                        new_fa = kmem_cache_alloc(fn_alias_kmem, GFP_KERNEL);
                        if (new_fa == NULL)
@@ -1230,7 +1255,7 @@ static int fn_trie_insert(struct fib_table *tb, struct fib_config *cfg)
                        new_fa->fa_type = cfg->fc_type;
                        new_fa->fa_scope = cfg->fc_scope;
                        state = fa->fa_state;
-                       new_fa->fa_state &= ~FA_S_ACCESSED;
+                       new_fa->fa_state = state & ~FA_S_ACCESSED;
 
                        list_replace_rcu(&fa->fa_list, &new_fa->fa_list);
                        alias_free_mem_rcu(fa);
@@ -1247,20 +1272,11 @@ static int fn_trie_insert(struct fib_table *tb, struct fib_config *cfg)
                 * uses the same scope, type, and nexthop
                 * information.
                 */
-               fa_orig = fa;
-               list_for_each_entry(fa, fa_orig->fa_list.prev, fa_list) {
-                       if (fa->fa_tos != tos)
-                               break;
-                       if (fa->fa_info->fib_priority != fi->fib_priority)
-                               break;
-                       if (fa->fa_type == cfg->fc_type &&
-                           fa->fa_scope == cfg->fc_scope &&
-                           fa->fa_info == fi)
-                               goto out;
-               }
+               if (fa_match)
+                       goto out;
 
                if (!(cfg->fc_nlflags & NLM_F_APPEND))
-                       fa = fa_orig;
+                       fa = fa_first;
        }
        err = -ENOENT;
        if (!(cfg->fc_nlflags & NLM_F_CREATE))
@@ -1600,9 +1616,8 @@ static int fn_trie_delete(struct fib_table *tb, struct fib_config *cfg)
        pr_debug("Deleting %08x/%d tos=%d t=%p\n", key, plen, tos, t);
 
        fa_to_delete = NULL;
-       fa_head = fa->fa_list.prev;
-
-       list_for_each_entry(fa, fa_head, fa_list) {
+       fa = list_entry(fa->fa_list.prev, struct fib_alias, fa_list);
+       list_for_each_entry_continue(fa, fa_head, fa_list) {
                struct fib_info *fi = fa->fa_info;
 
                if (fa->fa_tos != tos)
@@ -1743,6 +1758,19 @@ static struct leaf *trie_nextleaf(struct leaf *l)
        return leaf_walk_rcu(p, c);
 }
 
+static struct leaf *trie_leafindex(struct trie *t, int index)
+{
+       struct leaf *l = trie_firstleaf(t);
+
+       while (index-- > 0) {
+               l = trie_nextleaf(l);
+               if (!l)
+                       break;
+       }
+       return l;
+}
+
+
 /*
  * Caller must hold RTNL.
  */
@@ -1848,7 +1876,7 @@ static int fn_trie_dump_fa(t_key key, int plen, struct list_head *fah,
        struct fib_alias *fa;
        __be32 xkey = htonl(key);
 
-       s_i = cb->args[4];
+       s_i = cb->args[5];
        i = 0;
 
        /* rcu_read_lock is hold by caller */
@@ -1869,12 +1897,12 @@ static int fn_trie_dump_fa(t_key key, int plen, struct list_head *fah,
                                  plen,
                                  fa->fa_tos,
                                  fa->fa_info, NLM_F_MULTI) < 0) {
-                       cb->args[4] = i;
+                       cb->args[5] = i;
                        return -1;
                }
                i++;
        }
-       cb->args[4] = i;
+       cb->args[5] = i;
        return skb->len;
 }
 
@@ -1885,7 +1913,7 @@ static int fn_trie_dump_leaf(struct leaf *l, struct fib_table *tb,
        struct hlist_node *node;
        int i, s_i;
 
-       s_i = cb->args[3];
+       s_i = cb->args[4];
        i = 0;
 
        /* rcu_read_lock is hold by caller */
@@ -1896,19 +1924,19 @@ static int fn_trie_dump_leaf(struct leaf *l, struct fib_table *tb,
                }
 
                if (i > s_i)
-                       cb->args[4] = 0;
+                       cb->args[5] = 0;
 
                if (list_empty(&li->falh))
                        continue;
 
                if (fn_trie_dump_fa(l->key, li->plen, &li->falh, tb, skb, cb) < 0) {
-                       cb->args[3] = i;
+                       cb->args[4] = i;
                        return -1;
                }
                i++;
        }
 
-       cb->args[3] = i;
+       cb->args[4] = i;
        return skb->len;
 }
 
@@ -1918,35 +1946,37 @@ static int fn_trie_dump(struct fib_table *tb, struct sk_buff *skb,
        struct leaf *l;
        struct trie *t = (struct trie *) tb->tb_data;
        t_key key = cb->args[2];
+       int count = cb->args[3];
 
        rcu_read_lock();
        /* Dump starting at last key.
         * Note: 0.0.0.0/0 (ie default) is first key.
         */
-       if (!key)
+       if (count == 0)
                l = trie_firstleaf(t);
        else {
+               /* Normally, continue from last key, but if that is missing
+                * fallback to using slow rescan
+                */
                l = fib_find_node(t, key);
-               if (!l) {
-                       /* The table changed during the dump, rather than
-                        * giving partial data, just make application retry.
-                        */
-                       rcu_read_unlock();
-                       return -EBUSY;
-               }
+               if (!l)
+                       l = trie_leafindex(t, count);
        }
 
        while (l) {
                cb->args[2] = l->key;
                if (fn_trie_dump_leaf(l, tb, skb, cb) < 0) {
+                       cb->args[3] = count;
                        rcu_read_unlock();
                        return -1;
                }
 
+               ++count;
                l = trie_nextleaf(l);
-               memset(&cb->args[3], 0,
-                      sizeof(cb->args) - 3*sizeof(cb->args[0]));
+               memset(&cb->args[4], 0,
+                      sizeof(cb->args) - 4*sizeof(cb->args[0]));
        }
+       cb->args[3] = count;
        rcu_read_unlock();
 
        return skb->len;
@@ -2401,8 +2431,7 @@ static int fib_trie_seq_show(struct seq_file *seq, void *v)
                                           rtn_type(buf2, sizeof(buf2),
                                                    fa->fa_type));
                                if (fa->fa_tos)
-                                       seq_printf(seq, "tos =%d\n",
-                                                  fa->fa_tos);
+                                       seq_printf(seq, " tos=%d", fa->fa_tos);
                                seq_putc(seq, '\n');
                        }
                }
index a7321a82df6d24b3a1921d3918c23412b4271a4c..a13c074dac091e21fb1bb3cb1c77715ded13a5c2 100644 (file)
@@ -1015,7 +1015,8 @@ int icmp_rcv(struct sk_buff *skb)
                        goto error;
        }
 
-       __skb_pull(skb, sizeof(*icmph));
+       if (!pskb_pull(skb, sizeof(*icmph)))
+               goto error;
 
        icmph = icmp_hdr(skb);
 
index 7801cceb2d1b7844e11227322490dd14af5722df..b189278c7bc180a882b1ebb30ecd19ca19010199 100644 (file)
@@ -78,15 +78,14 @@ EXPORT_SYMBOL_GPL(inet_csk_bind_conflict);
 /* Obtain a reference to a local port for the given sock,
  * if snum is zero it means select any available local port.
  */
-int inet_csk_get_port(struct inet_hashinfo *hashinfo,
-                     struct sock *sk, unsigned short snum,
-                     int (*bind_conflict)(const struct sock *sk,
-                                          const struct inet_bind_bucket *tb))
+int inet_csk_get_port(struct sock *sk, unsigned short snum)
 {
+       struct inet_hashinfo *hashinfo = sk->sk_prot->hashinfo;
        struct inet_bind_hashbucket *head;
        struct hlist_node *node;
        struct inet_bind_bucket *tb;
        int ret;
+       struct net *net = sk->sk_net;
 
        local_bh_disable();
        if (!snum) {
@@ -100,7 +99,7 @@ int inet_csk_get_port(struct inet_hashinfo *hashinfo,
                        head = &hashinfo->bhash[inet_bhashfn(rover, hashinfo->bhash_size)];
                        spin_lock(&head->lock);
                        inet_bind_bucket_for_each(tb, node, &head->chain)
-                               if (tb->port == rover)
+                               if (tb->ib_net == net && tb->port == rover)
                                        goto next;
                        break;
                next:
@@ -127,7 +126,7 @@ int inet_csk_get_port(struct inet_hashinfo *hashinfo,
                head = &hashinfo->bhash[inet_bhashfn(snum, hashinfo->bhash_size)];
                spin_lock(&head->lock);
                inet_bind_bucket_for_each(tb, node, &head->chain)
-                       if (tb->port == snum)
+                       if (tb->ib_net == net && tb->port == snum)
                                goto tb_found;
        }
        tb = NULL;
@@ -141,13 +140,14 @@ tb_found:
                        goto success;
                } else {
                        ret = 1;
-                       if (bind_conflict(sk, tb))
+                       if (inet_csk(sk)->icsk_af_ops->bind_conflict(sk, tb))
                                goto fail_unlock;
                }
        }
 tb_not_found:
        ret = 1;
-       if (!tb && (tb = inet_bind_bucket_create(hashinfo->bind_bucket_cachep, head, snum)) == NULL)
+       if (!tb && (tb = inet_bind_bucket_create(hashinfo->bind_bucket_cachep,
+                                       net, head, snum)) == NULL)
                goto fail_unlock;
        if (hlist_empty(&tb->owners)) {
                if (sk->sk_reuse && sk->sk_state != TCP_LISTEN)
index 605ed2cd79724b461e933ed4e00ca694f0797bf9..da97695e70963917f98d38cf426caefc6072c069 100644 (file)
@@ -259,20 +259,22 @@ static int inet_diag_get_exact(struct sk_buff *in_skb,
        const struct inet_diag_handler *handler;
 
        handler = inet_diag_lock_handler(nlh->nlmsg_type);
-       if (!handler)
-               return -ENOENT;
+       if (IS_ERR(handler)) {
+               err = PTR_ERR(handler);
+               goto unlock;
+       }
 
        hashinfo = handler->idiag_hashinfo;
        err = -EINVAL;
 
        if (req->idiag_family == AF_INET) {
-               sk = inet_lookup(hashinfo, req->id.idiag_dst[0],
+               sk = inet_lookup(&init_net, hashinfo, req->id.idiag_dst[0],
                                 req->id.idiag_dport, req->id.idiag_src[0],
                                 req->id.idiag_sport, req->id.idiag_if);
        }
 #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
        else if (req->idiag_family == AF_INET6) {
-               sk = inet6_lookup(hashinfo,
+               sk = inet6_lookup(&init_net, hashinfo,
                                  (struct in6_addr *)req->id.idiag_dst,
                                  req->id.idiag_dport,
                                  (struct in6_addr *)req->id.idiag_src,
@@ -708,8 +710,8 @@ static int inet_diag_dump(struct sk_buff *skb, struct netlink_callback *cb)
        struct inet_hashinfo *hashinfo;
 
        handler = inet_diag_lock_handler(cb->nlh->nlmsg_type);
-       if (!handler)
-               goto no_handler;
+       if (IS_ERR(handler))
+               goto unlock;
 
        hashinfo = handler->idiag_hashinfo;
 
@@ -838,7 +840,6 @@ done:
        cb->args[2] = num;
 unlock:
        inet_diag_unlock_handler(handler);
-no_handler:
        return skb->len;
 }
 
index 619c63c6948aa1cac403c3a7e94a5dc550acba1b..9cac6c034abd98335fa2d8d43539d13bd4d627c9 100644 (file)
  * The bindhash mutex for snum's hash chain must be held here.
  */
 struct inet_bind_bucket *inet_bind_bucket_create(struct kmem_cache *cachep,
+                                                struct net *net,
                                                 struct inet_bind_hashbucket *head,
                                                 const unsigned short snum)
 {
        struct inet_bind_bucket *tb = kmem_cache_alloc(cachep, GFP_ATOMIC);
 
        if (tb != NULL) {
+               tb->ib_net       = net;
                tb->port      = snum;
                tb->fastreuse = 0;
                INIT_HLIST_HEAD(&tb->owners);
@@ -64,8 +66,9 @@ void inet_bind_hash(struct sock *sk, struct inet_bind_bucket *tb,
 /*
  * Get rid of any references to a local port held by the given sock.
  */
-static void __inet_put_port(struct inet_hashinfo *hashinfo, struct sock *sk)
+static void __inet_put_port(struct sock *sk)
 {
+       struct inet_hashinfo *hashinfo = sk->sk_prot->hashinfo;
        const int bhash = inet_bhashfn(inet_sk(sk)->num, hashinfo->bhash_size);
        struct inet_bind_hashbucket *head = &hashinfo->bhash[bhash];
        struct inet_bind_bucket *tb;
@@ -79,10 +82,10 @@ static void __inet_put_port(struct inet_hashinfo *hashinfo, struct sock *sk)
        spin_unlock(&head->lock);
 }
 
-void inet_put_port(struct inet_hashinfo *hashinfo, struct sock *sk)
+void inet_put_port(struct sock *sk)
 {
        local_bh_disable();
-       __inet_put_port(hashinfo, sk);
+       __inet_put_port(sk);
        local_bh_enable();
 }
 
@@ -125,7 +128,8 @@ EXPORT_SYMBOL(inet_listen_wlock);
  * remote address for the connection. So always assume those are both
  * wildcarded during the search since they can never be otherwise.
  */
-static struct sock *inet_lookup_listener_slow(const struct hlist_head *head,
+static struct sock *inet_lookup_listener_slow(struct net *net,
+                                             const struct hlist_head *head,
                                              const __be32 daddr,
                                              const unsigned short hnum,
                                              const int dif)
@@ -137,7 +141,8 @@ static struct sock *inet_lookup_listener_slow(const struct hlist_head *head,
        sk_for_each(sk, node, head) {
                const struct inet_sock *inet = inet_sk(sk);
 
-               if (inet->num == hnum && !ipv6_only_sock(sk)) {
+               if (sk->sk_net == net && inet->num == hnum &&
+                               !ipv6_only_sock(sk)) {
                        const __be32 rcv_saddr = inet->rcv_saddr;
                        int score = sk->sk_family == PF_INET ? 1 : 0;
 
@@ -163,7 +168,8 @@ static struct sock *inet_lookup_listener_slow(const struct hlist_head *head,
 }
 
 /* Optimize the common listener case. */
-struct sock *__inet_lookup_listener(struct inet_hashinfo *hashinfo,
+struct sock *__inet_lookup_listener(struct net *net,
+                                   struct inet_hashinfo *hashinfo,
                                    const __be32 daddr, const unsigned short hnum,
                                    const int dif)
 {
@@ -178,9 +184,9 @@ struct sock *__inet_lookup_listener(struct inet_hashinfo *hashinfo,
                if (inet->num == hnum && !sk->sk_node.next &&
                    (!inet->rcv_saddr || inet->rcv_saddr == daddr) &&
                    (sk->sk_family == PF_INET || !ipv6_only_sock(sk)) &&
-                   !sk->sk_bound_dev_if)
+                   !sk->sk_bound_dev_if && sk->sk_net == net)
                        goto sherry_cache;
-               sk = inet_lookup_listener_slow(head, daddr, hnum, dif);
+               sk = inet_lookup_listener_slow(net, head, daddr, hnum, dif);
        }
        if (sk) {
 sherry_cache:
@@ -191,7 +197,8 @@ sherry_cache:
 }
 EXPORT_SYMBOL_GPL(__inet_lookup_listener);
 
-struct sock * __inet_lookup_established(struct inet_hashinfo *hashinfo,
+struct sock * __inet_lookup_established(struct net *net,
+                                 struct inet_hashinfo *hashinfo,
                                  const __be32 saddr, const __be16 sport,
                                  const __be32 daddr, const u16 hnum,
                                  const int dif)
@@ -210,13 +217,15 @@ struct sock * __inet_lookup_established(struct inet_hashinfo *hashinfo,
        prefetch(head->chain.first);
        read_lock(lock);
        sk_for_each(sk, node, &head->chain) {
-               if (INET_MATCH(sk, hash, acookie, saddr, daddr, ports, dif))
+               if (INET_MATCH(sk, net, hash, acookie,
+                                       saddr, daddr, ports, dif))
                        goto hit; /* You sunk my battleship! */
        }
 
        /* Must check for a TIME_WAIT'er before going to listener hash. */
        sk_for_each(sk, node, &head->twchain) {
-               if (INET_TW_MATCH(sk, hash, acookie, saddr, daddr, ports, dif))
+               if (INET_TW_MATCH(sk, net, hash, acookie,
+                                       saddr, daddr, ports, dif))
                        goto hit;
        }
        sk = NULL;
@@ -247,6 +256,7 @@ static int __inet_check_established(struct inet_timewait_death_row *death_row,
        struct sock *sk2;
        const struct hlist_node *node;
        struct inet_timewait_sock *tw;
+       struct net *net = sk->sk_net;
 
        prefetch(head->chain.first);
        write_lock(lock);
@@ -255,7 +265,8 @@ static int __inet_check_established(struct inet_timewait_death_row *death_row,
        sk_for_each(sk2, node, &head->twchain) {
                tw = inet_twsk(sk2);
 
-               if (INET_TW_MATCH(sk2, hash, acookie, saddr, daddr, ports, dif)) {
+               if (INET_TW_MATCH(sk2, net, hash, acookie,
+                                       saddr, daddr, ports, dif)) {
                        if (twsk_unique(sk, sk2, twp))
                                goto unique;
                        else
@@ -266,7 +277,8 @@ static int __inet_check_established(struct inet_timewait_death_row *death_row,
 
        /* And established part... */
        sk_for_each(sk2, node, &head->chain) {
-               if (INET_MATCH(sk2, hash, acookie, saddr, daddr, ports, dif))
+               if (INET_MATCH(sk2, net, hash, acookie,
+                                       saddr, daddr, ports, dif))
                        goto not_unique;
        }
 
@@ -306,8 +318,9 @@ static inline u32 inet_sk_port_offset(const struct sock *sk)
                                          inet->dport);
 }
 
-void __inet_hash_nolisten(struct inet_hashinfo *hashinfo, struct sock *sk)
+void __inet_hash_nolisten(struct sock *sk)
 {
+       struct inet_hashinfo *hashinfo = sk->sk_prot->hashinfo;
        struct hlist_head *list;
        rwlock_t *lock;
        struct inet_ehash_bucket *head;
@@ -326,13 +339,14 @@ void __inet_hash_nolisten(struct inet_hashinfo *hashinfo, struct sock *sk)
 }
 EXPORT_SYMBOL_GPL(__inet_hash_nolisten);
 
-void __inet_hash(struct inet_hashinfo *hashinfo, struct sock *sk)
+static void __inet_hash(struct sock *sk)
 {
+       struct inet_hashinfo *hashinfo = sk->sk_prot->hashinfo;
        struct hlist_head *list;
        rwlock_t *lock;
 
        if (sk->sk_state != TCP_LISTEN) {
-               __inet_hash_nolisten(hashinfo, sk);
+               __inet_hash_nolisten(sk);
                return;
        }
 
@@ -346,24 +360,60 @@ void __inet_hash(struct inet_hashinfo *hashinfo, struct sock *sk)
        write_unlock(lock);
        wake_up(&hashinfo->lhash_wait);
 }
-EXPORT_SYMBOL_GPL(__inet_hash);
 
-/*
- * Bind a port for a connect operation and hash it.
- */
-int inet_hash_connect(struct inet_timewait_death_row *death_row,
-                     struct sock *sk)
+void inet_hash(struct sock *sk)
+{
+       if (sk->sk_state != TCP_CLOSE) {
+               local_bh_disable();
+               __inet_hash(sk);
+               local_bh_enable();
+       }
+}
+EXPORT_SYMBOL_GPL(inet_hash);
+
+void inet_unhash(struct sock *sk)
+{
+       rwlock_t *lock;
+       struct inet_hashinfo *hashinfo = sk->sk_prot->hashinfo;
+
+       if (sk_unhashed(sk))
+               goto out;
+
+       if (sk->sk_state == TCP_LISTEN) {
+               local_bh_disable();
+               inet_listen_wlock(hashinfo);
+               lock = &hashinfo->lhash_lock;
+       } else {
+               lock = inet_ehash_lockp(hashinfo, sk->sk_hash);
+               write_lock_bh(lock);
+       }
+
+       if (__sk_del_node_init(sk))
+               sock_prot_inuse_add(sk->sk_prot, -1);
+       write_unlock_bh(lock);
+out:
+       if (sk->sk_state == TCP_LISTEN)
+               wake_up(&hashinfo->lhash_wait);
+}
+EXPORT_SYMBOL_GPL(inet_unhash);
+
+int __inet_hash_connect(struct inet_timewait_death_row *death_row,
+               struct sock *sk, u32 port_offset,
+               int (*check_established)(struct inet_timewait_death_row *,
+                       struct sock *, __u16, struct inet_timewait_sock **),
+               void (*hash)(struct sock *sk))
 {
        struct inet_hashinfo *hinfo = death_row->hashinfo;
        const unsigned short snum = inet_sk(sk)->num;
        struct inet_bind_hashbucket *head;
        struct inet_bind_bucket *tb;
        int ret;
+       struct net *net = sk->sk_net;
 
        if (!snum) {
                int i, remaining, low, high, port;
                static u32 hint;
-               u32 offset = hint + inet_sk_port_offset(sk);
+               u32 offset = hint + port_offset;
                struct hlist_node *node;
                struct inet_timewait_sock *tw = NULL;
 
@@ -381,19 +431,19 @@ int inet_hash_connect(struct inet_timewait_death_row *death_row,
                         * unique enough.
                         */
                        inet_bind_bucket_for_each(tb, node, &head->chain) {
-                               if (tb->port == port) {
+                               if (tb->ib_net == net && tb->port == port) {
                                        BUG_TRAP(!hlist_empty(&tb->owners));
                                        if (tb->fastreuse >= 0)
                                                goto next_port;
-                                       if (!__inet_check_established(death_row,
-                                                                     sk, port,
-                                                                     &tw))
+                                       if (!check_established(death_row, sk,
+                                                               port, &tw))
                                                goto ok;
                                        goto next_port;
                                }
                        }
 
-                       tb = inet_bind_bucket_create(hinfo->bind_bucket_cachep, head, port);
+                       tb = inet_bind_bucket_create(hinfo->bind_bucket_cachep,
+                                       net, head, port);
                        if (!tb) {
                                spin_unlock(&head->lock);
                                break;
@@ -415,7 +465,7 @@ ok:
                inet_bind_hash(sk, tb, port);
                if (sk_unhashed(sk)) {
                        inet_sk(sk)->sport = htons(port);
-                       __inet_hash_nolisten(hinfo, sk);
+                       hash(sk);
                }
                spin_unlock(&head->lock);
 
@@ -432,17 +482,28 @@ ok:
        tb  = inet_csk(sk)->icsk_bind_hash;
        spin_lock_bh(&head->lock);
        if (sk_head(&tb->owners) == sk && !sk->sk_bind_node.next) {
-               __inet_hash_nolisten(hinfo, sk);
+               hash(sk);
                spin_unlock_bh(&head->lock);
                return 0;
        } else {
                spin_unlock(&head->lock);
                /* No definite answer... Walk to established hash table */
-               ret = __inet_check_established(death_row, sk, snum, NULL);
+               ret = check_established(death_row, sk, snum, NULL);
 out:
                local_bh_enable();
                return ret;
        }
 }
+EXPORT_SYMBOL_GPL(__inet_hash_connect);
+
+/*
+ * Bind a port for a connect operation and hash it.
+ */
+int inet_hash_connect(struct inet_timewait_death_row *death_row,
+                     struct sock *sk)
+{
+       return __inet_hash_connect(death_row, sk, inet_sk_port_offset(sk),
+                       __inet_check_established, __inet_hash_nolisten);
+}
 
 EXPORT_SYMBOL_GPL(inet_hash_connect);
index 18070ca65771c853dea40e08b02bb1e809b70535..341779e685d913d41ac14ae59a141ab32dca847f 100644 (file)
@@ -168,6 +168,7 @@ int ip_build_and_send_pkt(struct sk_buff *skb, struct sock *sk,
        }
 
        skb->priority = sk->sk_priority;
+       skb->mark = sk->sk_mark;
 
        /* Send it out. */
        return ip_local_out(skb);
@@ -385,6 +386,7 @@ packet_routed:
                             (skb_shinfo(skb)->gso_segs ?: 1) - 1);
 
        skb->priority = sk->sk_priority;
+       skb->mark = sk->sk_mark;
 
        return ip_local_out(skb);
 
@@ -476,6 +478,7 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*))
        if (skb_shinfo(skb)->frag_list) {
                struct sk_buff *frag;
                int first_len = skb_pagelen(skb);
+               int truesizes = 0;
 
                if (first_len - hlen > mtu ||
                    ((first_len - hlen) & 7) ||
@@ -499,7 +502,7 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*))
                                sock_hold(skb->sk);
                                frag->sk = skb->sk;
                                frag->destructor = sock_wfree;
-                               skb->truesize -= frag->truesize;
+                               truesizes += frag->truesize;
                        }
                }
 
@@ -510,6 +513,7 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*))
                frag = skb_shinfo(skb)->frag_list;
                skb_shinfo(skb)->frag_list = NULL;
                skb->data_len = first_len - skb_headlen(skb);
+               skb->truesize -= truesizes;
                skb->len = first_len;
                iph->tot_len = htons(first_len);
                iph->frag_off = htons(IP_MF);
@@ -1284,6 +1288,7 @@ int ip_push_pending_frames(struct sock *sk)
        iph->daddr = rt->rt_dst;
 
        skb->priority = sk->sk_priority;
+       skb->mark = sk->sk_mark;
        skb->dst = dst_clone(&rt->u.dst);
 
        if (iph->protocol == IPPROTO_ICMP)
index f4af99ad8fdb6015de40393d52b5bde5bd6c42c7..ae1f45fc23b966869eb7a3b0bf1dbb06712cd7c8 100644 (file)
@@ -74,6 +74,7 @@ out:
 
 static int ipcomp_input(struct xfrm_state *x, struct sk_buff *skb)
 {
+       int nexthdr;
        int err = -ENOMEM;
        struct ip_comp_hdr *ipch;
 
@@ -84,13 +85,15 @@ static int ipcomp_input(struct xfrm_state *x, struct sk_buff *skb)
 
        /* Remove ipcomp header and decompress original payload */
        ipch = (void *)skb->data;
+       nexthdr = ipch->nexthdr;
+
        skb->transport_header = skb->network_header + sizeof(*ipch);
        __skb_pull(skb, sizeof(*ipch));
        err = ipcomp_decompress(x, skb);
        if (err)
                goto out;
 
-       err = ipch->nexthdr;
+       err = nexthdr;
 
 out:
        return err;
@@ -434,7 +437,7 @@ error:
        goto out;
 }
 
-static struct xfrm_type ipcomp_type = {
+static const struct xfrm_type ipcomp_type = {
        .description    = "IPCOMP4",
        .owner          = THIS_MODULE,
        .proto          = IPPROTO_COMP,
index b4a810c28ac85c3f79e6e350ea985b8a85ba380d..a7591ce344d2c18a747c717ded8fa96671e2dcc8 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/mutex.h>
 #include <linux/err.h>
 #include <net/compat.h>
+#include <net/sock.h>
 #include <asm/uaccess.h>
 
 #include <linux/netfilter/x_tables.h>
@@ -850,7 +851,7 @@ static int compat_table_info(const struct xt_table_info *info,
 }
 #endif
 
-static int get_info(void __user *user, int *len, int compat)
+static int get_info(struct net *net, void __user *user, int *len, int compat)
 {
        char name[ARPT_TABLE_MAXNAMELEN];
        struct arpt_table *t;
@@ -870,7 +871,7 @@ static int get_info(void __user *user, int *len, int compat)
        if (compat)
                xt_compat_lock(NF_ARP);
 #endif
-       t = try_then_request_module(xt_find_table_lock(NF_ARP, name),
+       t = try_then_request_module(xt_find_table_lock(net, NF_ARP, name),
                                    "arptable_%s", name);
        if (t && !IS_ERR(t)) {
                struct arpt_getinfo info;
@@ -908,7 +909,8 @@ static int get_info(void __user *user, int *len, int compat)
        return ret;
 }
 
-static int get_entries(struct arpt_get_entries __user *uptr, int *len)
+static int get_entries(struct net *net, struct arpt_get_entries __user *uptr,
+                      int *len)
 {
        int ret;
        struct arpt_get_entries get;
@@ -926,7 +928,7 @@ static int get_entries(struct arpt_get_entries __user *uptr, int *len)
                return -EINVAL;
        }
 
-       t = xt_find_table_lock(NF_ARP, get.name);
+       t = xt_find_table_lock(net, NF_ARP, get.name);
        if (t && !IS_ERR(t)) {
                struct xt_table_info *private = t->private;
                duprintf("t->private->number = %u\n",
@@ -947,7 +949,8 @@ static int get_entries(struct arpt_get_entries __user *uptr, int *len)
        return ret;
 }
 
-static int __do_replace(const char *name, unsigned int valid_hooks,
+static int __do_replace(struct net *net, const char *name,
+                       unsigned int valid_hooks,
                        struct xt_table_info *newinfo,
                        unsigned int num_counters,
                        void __user *counters_ptr)
@@ -966,7 +969,7 @@ static int __do_replace(const char *name, unsigned int valid_hooks,
                goto out;
        }
 
-       t = try_then_request_module(xt_find_table_lock(NF_ARP, name),
+       t = try_then_request_module(xt_find_table_lock(net, NF_ARP, name),
                                    "arptable_%s", name);
        if (!t || IS_ERR(t)) {
                ret = t ? PTR_ERR(t) : -ENOENT;
@@ -1019,7 +1022,7 @@ static int __do_replace(const char *name, unsigned int valid_hooks,
        return ret;
 }
 
-static int do_replace(void __user *user, unsigned int len)
+static int do_replace(struct net *net, void __user *user, unsigned int len)
 {
        int ret;
        struct arpt_replace tmp;
@@ -1053,7 +1056,7 @@ static int do_replace(void __user *user, unsigned int len)
 
        duprintf("arp_tables: Translated table\n");
 
-       ret = __do_replace(tmp.name, tmp.valid_hooks, newinfo,
+       ret = __do_replace(net, tmp.name, tmp.valid_hooks, newinfo,
                           tmp.num_counters, tmp.counters);
        if (ret)
                goto free_newinfo_untrans;
@@ -1080,7 +1083,8 @@ static inline int add_counter_to_entry(struct arpt_entry *e,
        return 0;
 }
 
-static int do_add_counters(void __user *user, unsigned int len, int compat)
+static int do_add_counters(struct net *net, void __user *user, unsigned int len,
+                          int compat)
 {
        unsigned int i;
        struct xt_counters_info tmp;
@@ -1132,7 +1136,7 @@ static int do_add_counters(void __user *user, unsigned int len, int compat)
                goto free;
        }
 
-       t = xt_find_table_lock(NF_ARP, name);
+       t = xt_find_table_lock(net, NF_ARP, name);
        if (!t || IS_ERR(t)) {
                ret = t ? PTR_ERR(t) : -ENOENT;
                goto free;
@@ -1435,7 +1439,8 @@ struct compat_arpt_replace {
        struct compat_arpt_entry        entries[0];
 };
 
-static int compat_do_replace(void __user *user, unsigned int len)
+static int compat_do_replace(struct net *net, void __user *user,
+                            unsigned int len)
 {
        int ret;
        struct compat_arpt_replace tmp;
@@ -1471,7 +1476,7 @@ static int compat_do_replace(void __user *user, unsigned int len)
 
        duprintf("compat_do_replace: Translated table\n");
 
-       ret = __do_replace(tmp.name, tmp.valid_hooks, newinfo,
+       ret = __do_replace(net, tmp.name, tmp.valid_hooks, newinfo,
                           tmp.num_counters, compat_ptr(tmp.counters));
        if (ret)
                goto free_newinfo_untrans;
@@ -1494,11 +1499,11 @@ static int compat_do_arpt_set_ctl(struct sock *sk, int cmd, void __user *user,
 
        switch (cmd) {
        case ARPT_SO_SET_REPLACE:
-               ret = compat_do_replace(user, len);
+               ret = compat_do_replace(sk->sk_net, user, len);
                break;
 
        case ARPT_SO_SET_ADD_COUNTERS:
-               ret = do_add_counters(user, len, 1);
+               ret = do_add_counters(sk->sk_net, user, len, 1);
                break;
 
        default:
@@ -1584,7 +1589,8 @@ struct compat_arpt_get_entries {
        struct compat_arpt_entry entrytable[0];
 };
 
-static int compat_get_entries(struct compat_arpt_get_entries __user *uptr,
+static int compat_get_entries(struct net *net,
+                             struct compat_arpt_get_entries __user *uptr,
                              int *len)
 {
        int ret;
@@ -1604,7 +1610,7 @@ static int compat_get_entries(struct compat_arpt_get_entries __user *uptr,
        }
 
        xt_compat_lock(NF_ARP);
-       t = xt_find_table_lock(NF_ARP, get.name);
+       t = xt_find_table_lock(net, NF_ARP, get.name);
        if (t && !IS_ERR(t)) {
                struct xt_table_info *private = t->private;
                struct xt_table_info info;
@@ -1641,10 +1647,10 @@ static int compat_do_arpt_get_ctl(struct sock *sk, int cmd, void __user *user,
 
        switch (cmd) {
        case ARPT_SO_GET_INFO:
-               ret = get_info(user, len, 1);
+               ret = get_info(sk->sk_net, user, len, 1);
                break;
        case ARPT_SO_GET_ENTRIES:
-               ret = compat_get_entries(user, len);
+               ret = compat_get_entries(sk->sk_net, user, len);
                break;
        default:
                ret = do_arpt_get_ctl(sk, cmd, user, len);
@@ -1662,11 +1668,11 @@ static int do_arpt_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned
 
        switch (cmd) {
        case ARPT_SO_SET_REPLACE:
-               ret = do_replace(user, len);
+               ret = do_replace(sk->sk_net, user, len);
                break;
 
        case ARPT_SO_SET_ADD_COUNTERS:
-               ret = do_add_counters(user, len, 0);
+               ret = do_add_counters(sk->sk_net, user, len, 0);
                break;
 
        default:
@@ -1686,11 +1692,11 @@ static int do_arpt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len
 
        switch (cmd) {
        case ARPT_SO_GET_INFO:
-               ret = get_info(user, len, 0);
+               ret = get_info(sk->sk_net, user, len, 0);
                break;
 
        case ARPT_SO_GET_ENTRIES:
-               ret = get_entries(user, len);
+               ret = get_entries(sk->sk_net, user, len);
                break;
 
        case ARPT_SO_GET_REVISION_TARGET: {
@@ -1719,19 +1725,21 @@ static int do_arpt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len
        return ret;
 }
 
-int arpt_register_table(struct arpt_table *table,
-                       const struct arpt_replace *repl)
+struct arpt_table *arpt_register_table(struct net *net,
+                                      struct arpt_table *table,
+                                      const struct arpt_replace *repl)
 {
        int ret;
        struct xt_table_info *newinfo;
        struct xt_table_info bootstrap
                = { 0, 0, 0, { 0 }, { 0 }, { } };
        void *loc_cpu_entry;
+       struct xt_table *new_table;
 
        newinfo = xt_alloc_table_info(repl->size);
        if (!newinfo) {
                ret = -ENOMEM;
-               return ret;
+               goto out;
        }
 
        /* choose the copy on our node/cpu */
@@ -1745,24 +1753,27 @@ int arpt_register_table(struct arpt_table *table,
                              repl->underflow);
 
        duprintf("arpt_register_table: translate table gives %d\n", ret);
-       if (ret != 0) {
-               xt_free_table_info(newinfo);
-               return ret;
-       }
+       if (ret != 0)
+               goto out_free;
 
-       ret = xt_register_table(table, &bootstrap, newinfo);
-       if (ret != 0) {
-               xt_free_table_info(newinfo);
-               return ret;
+       new_table = xt_register_table(net, table, &bootstrap, newinfo);
+       if (IS_ERR(new_table)) {
+               ret = PTR_ERR(new_table);
+               goto out_free;
        }
+       return new_table;
 
-       return 0;
+out_free:
+       xt_free_table_info(newinfo);
+out:
+       return ERR_PTR(ret);
 }
 
 void arpt_unregister_table(struct arpt_table *table)
 {
        struct xt_table_info *private;
        void *loc_cpu_entry;
+       struct module *table_owner = table->me;
 
        private = xt_unregister_table(table);
 
@@ -1770,6 +1781,8 @@ void arpt_unregister_table(struct arpt_table *table)
        loc_cpu_entry = private->entries[raw_smp_processor_id()];
        ARPT_ENTRY_ITERATE(loc_cpu_entry, private->size,
                           cleanup_entry, NULL);
+       if (private->number > private->initial_entries)
+               module_put(table_owner);
        xt_free_table_info(private);
 }
 
@@ -1809,11 +1822,26 @@ static struct nf_sockopt_ops arpt_sockopts = {
        .owner          = THIS_MODULE,
 };
 
+static int __net_init arp_tables_net_init(struct net *net)
+{
+       return xt_proto_init(net, NF_ARP);
+}
+
+static void __net_exit arp_tables_net_exit(struct net *net)
+{
+       xt_proto_fini(net, NF_ARP);
+}
+
+static struct pernet_operations arp_tables_net_ops = {
+       .init = arp_tables_net_init,
+       .exit = arp_tables_net_exit,
+};
+
 static int __init arp_tables_init(void)
 {
        int ret;
 
-       ret = xt_proto_init(NF_ARP);
+       ret = register_pernet_subsys(&arp_tables_net_ops);
        if (ret < 0)
                goto err1;
 
@@ -1838,7 +1866,7 @@ err4:
 err3:
        xt_unregister_target(&arpt_standard_target);
 err2:
-       xt_proto_fini(NF_ARP);
+       unregister_pernet_subsys(&arp_tables_net_ops);
 err1:
        return ret;
 }
@@ -1848,7 +1876,7 @@ static void __exit arp_tables_fini(void)
        nf_unregister_sockopt(&arpt_sockopts);
        xt_unregister_target(&arpt_error_target);
        xt_unregister_target(&arpt_standard_target);
-       xt_proto_fini(NF_ARP);
+       unregister_pernet_subsys(&arp_tables_net_ops);
 }
 
 EXPORT_SYMBOL(arpt_register_table);
index 7201511d54d2dbc0da216b4ae8ff04d0483dd733..4e9c496a30c29a1cdce4518a05a37918abcb4b33 100644 (file)
@@ -20,7 +20,7 @@ static struct
        struct arpt_replace repl;
        struct arpt_standard entries[3];
        struct arpt_error term;
-} initial_table __initdata = {
+} initial_table __net_initdata = {
        .repl = {
                .name = "filter",
                .valid_hooks = FILTER_VALID_HOOKS,
@@ -61,7 +61,7 @@ static unsigned int arpt_hook(unsigned int hook,
                              const struct net_device *out,
                              int (*okfn)(struct sk_buff *))
 {
-       return arpt_do_table(skb, hook, in, out, &packet_filter);
+       return arpt_do_table(skb, hook, in, out, init_net.ipv4.arptable_filter);
 }
 
 static struct nf_hook_ops arpt_ops[] __read_mostly = {
@@ -85,12 +85,31 @@ static struct nf_hook_ops arpt_ops[] __read_mostly = {
        },
 };
 
+static int __net_init arptable_filter_net_init(struct net *net)
+{
+       /* Register table */
+       net->ipv4.arptable_filter =
+               arpt_register_table(net, &packet_filter, &initial_table.repl);
+       if (IS_ERR(net->ipv4.arptable_filter))
+               return PTR_ERR(net->ipv4.arptable_filter);
+       return 0;
+}
+
+static void __net_exit arptable_filter_net_exit(struct net *net)
+{
+       arpt_unregister_table(net->ipv4.arptable_filter);
+}
+
+static struct pernet_operations arptable_filter_net_ops = {
+       .init = arptable_filter_net_init,
+       .exit = arptable_filter_net_exit,
+};
+
 static int __init arptable_filter_init(void)
 {
        int ret;
 
-       /* Register table */
-       ret = arpt_register_table(&packet_filter, &initial_table.repl);
+       ret = register_pernet_subsys(&arptable_filter_net_ops);
        if (ret < 0)
                return ret;
 
@@ -100,14 +119,14 @@ static int __init arptable_filter_init(void)
        return ret;
 
 cleanup_table:
-       arpt_unregister_table(&packet_filter);
+       unregister_pernet_subsys(&arptable_filter_net_ops);
        return ret;
 }
 
 static void __exit arptable_filter_fini(void)
 {
        nf_unregister_hooks(arpt_ops, ARRAY_SIZE(arpt_ops));
-       arpt_unregister_table(&packet_filter);
+       unregister_pernet_subsys(&arptable_filter_net_ops);
 }
 
 module_init(arptable_filter_init);
index 5109839da222b28f6f1c255d16f45d729cf87ff2..6bda1102851b8d94d7aabf2859bff378b53970e7 100644 (file)
@@ -512,6 +512,7 @@ static struct notifier_block ipq_nl_notifier = {
        .notifier_call  = ipq_rcv_nl_event,
 };
 
+#ifdef CONFIG_SYSCTL
 static struct ctl_table_header *ipq_sysctl_header;
 
 static ctl_table ipq_table[] = {
@@ -525,7 +526,9 @@ static ctl_table ipq_table[] = {
        },
        { .ctl_name = 0 }
 };
+#endif
 
+#ifdef CONFIG_PROC_FS
 static int ip_queue_show(struct seq_file *m, void *v)
 {
        read_lock_bh(&queue_lock);
@@ -562,6 +565,7 @@ static const struct file_operations ip_queue_proc_fops = {
        .release        = single_release,
        .owner          = THIS_MODULE,
 };
+#endif
 
 static const struct nf_queue_handler nfqh = {
        .name   = "ip_queue",
@@ -571,7 +575,7 @@ static const struct nf_queue_handler nfqh = {
 static int __init ip_queue_init(void)
 {
        int status = -ENOMEM;
-       struct proc_dir_entry *proc;
+       struct proc_dir_entry *proc __maybe_unused;
 
        netlink_register_notifier(&ipq_nl_notifier);
        ipqnl = netlink_kernel_create(&init_net, NETLINK_FIREWALL, 0,
@@ -581,6 +585,7 @@ static int __init ip_queue_init(void)
                goto cleanup_netlink_notifier;
        }
 
+#ifdef CONFIG_PROC_FS
        proc = create_proc_entry(IPQ_PROC_FS_NAME, 0, init_net.proc_net);
        if (proc) {
                proc->owner = THIS_MODULE;
@@ -589,10 +594,11 @@ static int __init ip_queue_init(void)
                printk(KERN_ERR "ip_queue: failed to create proc entry\n");
                goto cleanup_ipqnl;
        }
-
+#endif
        register_netdevice_notifier(&ipq_dev_notifier);
+#ifdef CONFIG_SYSCTL
        ipq_sysctl_header = register_sysctl_paths(net_ipv4_ctl_path, ipq_table);
-
+#endif
        status = nf_register_queue_handler(PF_INET, &nfqh);
        if (status < 0) {
                printk(KERN_ERR "ip_queue: failed to register queue handler\n");
@@ -601,10 +607,12 @@ static int __init ip_queue_init(void)
        return status;
 
 cleanup_sysctl:
+#ifdef CONFIG_SYSCTL
        unregister_sysctl_table(ipq_sysctl_header);
+#endif
        unregister_netdevice_notifier(&ipq_dev_notifier);
        proc_net_remove(&init_net, IPQ_PROC_FS_NAME);
-cleanup_ipqnl:
+cleanup_ipqnl: __maybe_unused
        netlink_kernel_release(ipqnl);
        mutex_lock(&ipqnl_mutex);
        mutex_unlock(&ipqnl_mutex);
@@ -620,7 +628,9 @@ static void __exit ip_queue_fini(void)
        synchronize_net();
        ipq_flush(NULL, 0);
 
+#ifdef CONFIG_SYSCTL
        unregister_sysctl_table(ipq_sysctl_header);
+#endif
        unregister_netdevice_notifier(&ipq_dev_notifier);
        proc_net_remove(&init_net, IPQ_PROC_FS_NAME);
 
index 982b7f9862918cd3c25d1ad9e11c95985fc2e459..600737f122d2eee84f269f3abffe2b02880d454b 100644 (file)
@@ -291,7 +291,7 @@ static void trace_packet(struct sk_buff *skb,
                         unsigned int hook,
                         const struct net_device *in,
                         const struct net_device *out,
-                        char *tablename,
+                        const char *tablename,
                         struct xt_table_info *private,
                         struct ipt_entry *e)
 {
@@ -1092,7 +1092,7 @@ static int compat_table_info(const struct xt_table_info *info,
 }
 #endif
 
-static int get_info(void __user *user, int *len, int compat)
+static int get_info(struct net *net, void __user *user, int *len, int compat)
 {
        char name[IPT_TABLE_MAXNAMELEN];
        struct xt_table *t;
@@ -1112,7 +1112,7 @@ static int get_info(void __user *user, int *len, int compat)
        if (compat)
                xt_compat_lock(AF_INET);
 #endif
-       t = try_then_request_module(xt_find_table_lock(AF_INET, name),
+       t = try_then_request_module(xt_find_table_lock(net, AF_INET, name),
                                    "iptable_%s", name);
        if (t && !IS_ERR(t)) {
                struct ipt_getinfo info;
@@ -1152,7 +1152,7 @@ static int get_info(void __user *user, int *len, int compat)
 }
 
 static int
-get_entries(struct ipt_get_entries __user *uptr, int *len)
+get_entries(struct net *net, struct ipt_get_entries __user *uptr, int *len)
 {
        int ret;
        struct ipt_get_entries get;
@@ -1170,7 +1170,7 @@ get_entries(struct ipt_get_entries __user *uptr, int *len)
                return -EINVAL;
        }
 
-       t = xt_find_table_lock(AF_INET, get.name);
+       t = xt_find_table_lock(net, AF_INET, get.name);
        if (t && !IS_ERR(t)) {
                struct xt_table_info *private = t->private;
                duprintf("t->private->number = %u\n", private->number);
@@ -1191,7 +1191,7 @@ get_entries(struct ipt_get_entries __user *uptr, int *len)
 }
 
 static int
-__do_replace(const char *name, unsigned int valid_hooks,
+__do_replace(struct net *net, const char *name, unsigned int valid_hooks,
             struct xt_table_info *newinfo, unsigned int num_counters,
             void __user *counters_ptr)
 {
@@ -1208,7 +1208,7 @@ __do_replace(const char *name, unsigned int valid_hooks,
                goto out;
        }
 
-       t = try_then_request_module(xt_find_table_lock(AF_INET, name),
+       t = try_then_request_module(xt_find_table_lock(net, AF_INET, name),
                                    "iptable_%s", name);
        if (!t || IS_ERR(t)) {
                ret = t ? PTR_ERR(t) : -ENOENT;
@@ -1261,7 +1261,7 @@ __do_replace(const char *name, unsigned int valid_hooks,
 }
 
 static int
-do_replace(void __user *user, unsigned int len)
+do_replace(struct net *net, void __user *user, unsigned int len)
 {
        int ret;
        struct ipt_replace tmp;
@@ -1295,7 +1295,7 @@ do_replace(void __user *user, unsigned int len)
 
        duprintf("ip_tables: Translated table\n");
 
-       ret = __do_replace(tmp.name, tmp.valid_hooks, newinfo,
+       ret = __do_replace(net, tmp.name, tmp.valid_hooks, newinfo,
                           tmp.num_counters, tmp.counters);
        if (ret)
                goto free_newinfo_untrans;
@@ -1331,7 +1331,7 @@ add_counter_to_entry(struct ipt_entry *e,
 }
 
 static int
-do_add_counters(void __user *user, unsigned int len, int compat)
+do_add_counters(struct net *net, void __user *user, unsigned int len, int compat)
 {
        unsigned int i;
        struct xt_counters_info tmp;
@@ -1383,7 +1383,7 @@ do_add_counters(void __user *user, unsigned int len, int compat)
                goto free;
        }
 
-       t = xt_find_table_lock(AF_INET, name);
+       t = xt_find_table_lock(net, AF_INET, name);
        if (!t || IS_ERR(t)) {
                ret = t ? PTR_ERR(t) : -ENOENT;
                goto free;
@@ -1429,7 +1429,7 @@ struct compat_ipt_replace {
 
 static int
 compat_copy_entry_to_user(struct ipt_entry *e, void __user **dstptr,
-                         compat_uint_t *size, struct xt_counters *counters,
+                         unsigned int *size, struct xt_counters *counters,
                          unsigned int *i)
 {
        struct ipt_entry_target *t;
@@ -1476,7 +1476,7 @@ compat_find_calc_match(struct ipt_entry_match *m,
                       const char *name,
                       const struct ipt_ip *ip,
                       unsigned int hookmask,
-                      int *size, int *i)
+                      int *size, unsigned int *i)
 {
        struct xt_match *match;
 
@@ -1534,7 +1534,8 @@ check_compat_entry_size_and_hooks(struct compat_ipt_entry *e,
        struct ipt_entry_target *t;
        struct xt_target *target;
        unsigned int entry_offset;
-       int ret, off, h, j;
+       unsigned int j;
+       int ret, off, h;
 
        duprintf("check_compat_entry_size_and_hooks %p\n", e);
        if ((unsigned long)e % __alignof__(struct compat_ipt_entry) != 0
@@ -1647,7 +1648,8 @@ static int
 compat_check_entry(struct ipt_entry *e, const char *name,
                                     unsigned int *i)
 {
-       int j, ret;
+       unsigned int j;
+       int ret;
 
        j = 0;
        ret = IPT_MATCH_ITERATE(e, check_match, name, &e->ip,
@@ -1789,7 +1791,7 @@ out_unlock:
 }
 
 static int
-compat_do_replace(void __user *user, unsigned int len)
+compat_do_replace(struct net *net, void __user *user, unsigned int len)
 {
        int ret;
        struct compat_ipt_replace tmp;
@@ -1826,7 +1828,7 @@ compat_do_replace(void __user *user, unsigned int len)
 
        duprintf("compat_do_replace: Translated table\n");
 
-       ret = __do_replace(tmp.name, tmp.valid_hooks, newinfo,
+       ret = __do_replace(net, tmp.name, tmp.valid_hooks, newinfo,
                           tmp.num_counters, compat_ptr(tmp.counters));
        if (ret)
                goto free_newinfo_untrans;
@@ -1850,11 +1852,11 @@ compat_do_ipt_set_ctl(struct sock *sk,  int cmd, void __user *user,
 
        switch (cmd) {
        case IPT_SO_SET_REPLACE:
-               ret = compat_do_replace(user, len);
+               ret = compat_do_replace(sk->sk_net, user, len);
                break;
 
        case IPT_SO_SET_ADD_COUNTERS:
-               ret = do_add_counters(user, len, 1);
+               ret = do_add_counters(sk->sk_net, user, len, 1);
                break;
 
        default:
@@ -1903,7 +1905,8 @@ compat_copy_entries_to_user(unsigned int total_size, struct xt_table *table,
 }
 
 static int
-compat_get_entries(struct compat_ipt_get_entries __user *uptr, int *len)
+compat_get_entries(struct net *net, struct compat_ipt_get_entries __user *uptr,
+                  int *len)
 {
        int ret;
        struct compat_ipt_get_entries get;
@@ -1924,7 +1927,7 @@ compat_get_entries(struct compat_ipt_get_entries __user *uptr, int *len)
        }
 
        xt_compat_lock(AF_INET);
-       t = xt_find_table_lock(AF_INET, get.name);
+       t = xt_find_table_lock(net, AF_INET, get.name);
        if (t && !IS_ERR(t)) {
                struct xt_table_info *private = t->private;
                struct xt_table_info info;
@@ -1960,10 +1963,10 @@ compat_do_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
 
        switch (cmd) {
        case IPT_SO_GET_INFO:
-               ret = get_info(user, len, 1);
+               ret = get_info(sk->sk_net, user, len, 1);
                break;
        case IPT_SO_GET_ENTRIES:
-               ret = compat_get_entries(user, len);
+               ret = compat_get_entries(sk->sk_net, user, len);
                break;
        default:
                ret = do_ipt_get_ctl(sk, cmd, user, len);
@@ -1982,11 +1985,11 @@ do_ipt_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
 
        switch (cmd) {
        case IPT_SO_SET_REPLACE:
-               ret = do_replace(user, len);
+               ret = do_replace(sk->sk_net, user, len);
                break;
 
        case IPT_SO_SET_ADD_COUNTERS:
-               ret = do_add_counters(user, len, 0);
+               ret = do_add_counters(sk->sk_net, user, len, 0);
                break;
 
        default:
@@ -2007,11 +2010,11 @@ do_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
 
        switch (cmd) {
        case IPT_SO_GET_INFO:
-               ret = get_info(user, len, 0);
+               ret = get_info(sk->sk_net, user, len, 0);
                break;
 
        case IPT_SO_GET_ENTRIES:
-               ret = get_entries(user, len);
+               ret = get_entries(sk->sk_net, user, len);
                break;
 
        case IPT_SO_GET_REVISION_MATCH:
@@ -2048,17 +2051,21 @@ do_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
        return ret;
 }
 
-int ipt_register_table(struct xt_table *table, const struct ipt_replace *repl)
+struct xt_table *ipt_register_table(struct net *net, struct xt_table *table,
+                                   const struct ipt_replace *repl)
 {
        int ret;
        struct xt_table_info *newinfo;
        struct xt_table_info bootstrap
                = { 0, 0, 0, { 0 }, { 0 }, { } };
        void *loc_cpu_entry;
+       struct xt_table *new_table;
 
        newinfo = xt_alloc_table_info(repl->size);
-       if (!newinfo)
-               return -ENOMEM;
+       if (!newinfo) {
+               ret = -ENOMEM;
+               goto out;
+       }
 
        /* choose the copy on our node/cpu, but dont care about preemption */
        loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
@@ -2069,30 +2076,36 @@ int ipt_register_table(struct xt_table *table, const struct ipt_replace *repl)
                              repl->num_entries,
                              repl->hook_entry,
                              repl->underflow);
-       if (ret != 0) {
-               xt_free_table_info(newinfo);
-               return ret;
-       }
+       if (ret != 0)
+               goto out_free;
 
-       ret = xt_register_table(table, &bootstrap, newinfo);
-       if (ret != 0) {
-               xt_free_table_info(newinfo);
-               return ret;
+       new_table = xt_register_table(net, table, &bootstrap, newinfo);
+       if (IS_ERR(new_table)) {
+               ret = PTR_ERR(new_table);
+               goto out_free;
        }
 
-       return 0;
+       return new_table;
+
+out_free:
+       xt_free_table_info(newinfo);
+out:
+       return ERR_PTR(ret);
 }
 
 void ipt_unregister_table(struct xt_table *table)
 {
        struct xt_table_info *private;
        void *loc_cpu_entry;
+       struct module *table_owner = table->me;
 
        private = xt_unregister_table(table);
 
        /* Decrease module usage counts and free resources */
        loc_cpu_entry = private->entries[raw_smp_processor_id()];
        IPT_ENTRY_ITERATE(loc_cpu_entry, private->size, cleanup_entry, NULL);
+       if (private->number > private->initial_entries)
+               module_put(table_owner);
        xt_free_table_info(private);
 }
 
@@ -2200,11 +2213,26 @@ static struct xt_match icmp_matchstruct __read_mostly = {
        .family         = AF_INET,
 };
 
+static int __net_init ip_tables_net_init(struct net *net)
+{
+       return xt_proto_init(net, AF_INET);
+}
+
+static void __net_exit ip_tables_net_exit(struct net *net)
+{
+       xt_proto_fini(net, AF_INET);
+}
+
+static struct pernet_operations ip_tables_net_ops = {
+       .init = ip_tables_net_init,
+       .exit = ip_tables_net_exit,
+};
+
 static int __init ip_tables_init(void)
 {
        int ret;
 
-       ret = xt_proto_init(AF_INET);
+       ret = register_pernet_subsys(&ip_tables_net_ops);
        if (ret < 0)
                goto err1;
 
@@ -2234,7 +2262,7 @@ err4:
 err3:
        xt_unregister_target(&ipt_standard_target);
 err2:
-       xt_proto_fini(AF_INET);
+       unregister_pernet_subsys(&ip_tables_net_ops);
 err1:
        return ret;
 }
@@ -2247,7 +2275,7 @@ static void __exit ip_tables_fini(void)
        xt_unregister_target(&ipt_error_target);
        xt_unregister_target(&ipt_standard_target);
 
-       xt_proto_fini(AF_INET);
+       unregister_pernet_subsys(&ip_tables_net_ops);
 }
 
 EXPORT_SYMBOL(ipt_register_table);
index 1b31f7d14d46b6c87de794f1cd4d4700c0a6ce1e..c6cf84c776116a6db394da69947547d20e324b17 100644 (file)
@@ -76,13 +76,6 @@ clusterip_config_put(struct clusterip_config *c)
                kfree(c);
 }
 
-/* increase the count of entries(rules) using/referencing this config */
-static inline void
-clusterip_config_entry_get(struct clusterip_config *c)
-{
-       atomic_inc(&c->entries);
-}
-
 /* decrease the count of entries using/referencing this config.  If last
  * entry(rule) is removed, remove the config from lists, but don't free it
  * yet, since proc-files could still be holding references */
index e3154a99c08ae9d975378b80684b8f361fd07839..68cbe3ca01ced13ea0cc77d7d3f6057fa63855d3 100644 (file)
@@ -212,11 +212,11 @@ recent_mt(const struct sk_buff *skb, const struct net_device *in,
                recent_entry_remove(t, e);
                ret = !ret;
        } else if (info->check_set & (IPT_RECENT_CHECK | IPT_RECENT_UPDATE)) {
-               unsigned long t = jiffies - info->seconds * HZ;
+               unsigned long time = jiffies - info->seconds * HZ;
                unsigned int i, hits = 0;
 
                for (i = 0; i < e->nstamps; i++) {
-                       if (info->seconds && time_after(t, e->stamps[i]))
+                       if (info->seconds && time_after(time, e->stamps[i]))
                                continue;
                        if (++hits >= info->hit_count) {
                                ret = !ret;
@@ -320,6 +320,7 @@ struct recent_iter_state {
 };
 
 static void *recent_seq_start(struct seq_file *seq, loff_t *pos)
+       __acquires(recent_lock)
 {
        struct recent_iter_state *st = seq->private;
        const struct recent_table *t = st->table;
@@ -352,6 +353,7 @@ static void *recent_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 }
 
 static void recent_seq_stop(struct seq_file *s, void *v)
+       __releases(recent_lock)
 {
        spin_unlock_bh(&recent_lock);
 }
index 29bb4f9fbda0f7f7d4fcc5cce744e557907f0e86..69f3d7e6e96f794a4cecd47c8896e473c3dd59df 100644 (file)
@@ -28,7 +28,7 @@ static struct
        struct ipt_replace repl;
        struct ipt_standard entries[3];
        struct ipt_error term;
-} initial_table __initdata = {
+} initial_table __net_initdata = {
        .repl = {
                .name = "filter",
                .valid_hooks = FILTER_VALID_HOOKS,
@@ -69,7 +69,7 @@ ipt_hook(unsigned int hook,
         const struct net_device *out,
         int (*okfn)(struct sk_buff *))
 {
-       return ipt_do_table(skb, hook, in, out, &packet_filter);
+       return ipt_do_table(skb, hook, in, out, init_net.ipv4.iptable_filter);
 }
 
 static unsigned int
@@ -88,7 +88,7 @@ ipt_local_out_hook(unsigned int hook,
                return NF_ACCEPT;
        }
 
-       return ipt_do_table(skb, hook, in, out, &packet_filter);
+       return ipt_do_table(skb, hook, in, out, init_net.ipv4.iptable_filter);
 }
 
 static struct nf_hook_ops ipt_ops[] __read_mostly = {
@@ -119,6 +119,26 @@ static struct nf_hook_ops ipt_ops[] __read_mostly = {
 static int forward = NF_ACCEPT;
 module_param(forward, bool, 0000);
 
+static int __net_init iptable_filter_net_init(struct net *net)
+{
+       /* Register table */
+       net->ipv4.iptable_filter =
+               ipt_register_table(net, &packet_filter, &initial_table.repl);
+       if (IS_ERR(net->ipv4.iptable_filter))
+               return PTR_ERR(net->ipv4.iptable_filter);
+       return 0;
+}
+
+static void __net_exit iptable_filter_net_exit(struct net *net)
+{
+       ipt_unregister_table(net->ipv4.iptable_filter);
+}
+
+static struct pernet_operations iptable_filter_net_ops = {
+       .init = iptable_filter_net_init,
+       .exit = iptable_filter_net_exit,
+};
+
 static int __init iptable_filter_init(void)
 {
        int ret;
@@ -131,8 +151,7 @@ static int __init iptable_filter_init(void)
        /* Entry 1 is the FORWARD hook */
        initial_table.entries[1].target.verdict = -forward - 1;
 
-       /* Register table */
-       ret = ipt_register_table(&packet_filter, &initial_table.repl);
+       ret = register_pernet_subsys(&iptable_filter_net_ops);
        if (ret < 0)
                return ret;
 
@@ -144,14 +163,14 @@ static int __init iptable_filter_init(void)
        return ret;
 
  cleanup_table:
-       ipt_unregister_table(&packet_filter);
+       unregister_pernet_subsys(&iptable_filter_net_ops);
        return ret;
 }
 
 static void __exit iptable_filter_fini(void)
 {
        nf_unregister_hooks(ipt_ops, ARRAY_SIZE(ipt_ops));
-       ipt_unregister_table(&packet_filter);
+       unregister_pernet_subsys(&iptable_filter_net_ops);
 }
 
 module_init(iptable_filter_init);
index 5c4be202430c8b7dbcabea9306ae8989b8d29f1d..c55a210853a7a5e92d10cecf30dabe645a6355c3 100644 (file)
@@ -33,7 +33,7 @@ static struct
        struct ipt_replace repl;
        struct ipt_standard entries[5];
        struct ipt_error term;
-} initial_table __initdata = {
+} initial_table __net_initdata = {
        .repl = {
                .name = "mangle",
                .valid_hooks = MANGLE_VALID_HOOKS,
@@ -80,7 +80,7 @@ ipt_route_hook(unsigned int hook,
         const struct net_device *out,
         int (*okfn)(struct sk_buff *))
 {
-       return ipt_do_table(skb, hook, in, out, &packet_mangler);
+       return ipt_do_table(skb, hook, in, out, init_net.ipv4.iptable_mangle);
 }
 
 static unsigned int
@@ -112,7 +112,7 @@ ipt_local_hook(unsigned int hook,
        daddr = iph->daddr;
        tos = iph->tos;
 
-       ret = ipt_do_table(skb, hook, in, out, &packet_mangler);
+       ret = ipt_do_table(skb, hook, in, out, init_net.ipv4.iptable_mangle);
        /* Reroute for ANY change. */
        if (ret != NF_DROP && ret != NF_STOLEN && ret != NF_QUEUE) {
                iph = ip_hdr(skb);
@@ -166,12 +166,31 @@ static struct nf_hook_ops ipt_ops[] __read_mostly = {
        },
 };
 
+static int __net_init iptable_mangle_net_init(struct net *net)
+{
+       /* Register table */
+       net->ipv4.iptable_mangle =
+               ipt_register_table(net, &packet_mangler, &initial_table.repl);
+       if (IS_ERR(net->ipv4.iptable_mangle))
+               return PTR_ERR(net->ipv4.iptable_mangle);
+       return 0;
+}
+
+static void __net_exit iptable_mangle_net_exit(struct net *net)
+{
+       ipt_unregister_table(net->ipv4.iptable_mangle);
+}
+
+static struct pernet_operations iptable_mangle_net_ops = {
+       .init = iptable_mangle_net_init,
+       .exit = iptable_mangle_net_exit,
+};
+
 static int __init iptable_mangle_init(void)
 {
        int ret;
 
-       /* Register table */
-       ret = ipt_register_table(&packet_mangler, &initial_table.repl);
+       ret = register_pernet_subsys(&iptable_mangle_net_ops);
        if (ret < 0)
                return ret;
 
@@ -183,14 +202,14 @@ static int __init iptable_mangle_init(void)
        return ret;
 
  cleanup_table:
-       ipt_unregister_table(&packet_mangler);
+       unregister_pernet_subsys(&iptable_mangle_net_ops);
        return ret;
 }
 
 static void __exit iptable_mangle_fini(void)
 {
        nf_unregister_hooks(ipt_ops, ARRAY_SIZE(ipt_ops));
-       ipt_unregister_table(&packet_mangler);
+       unregister_pernet_subsys(&iptable_mangle_net_ops);
 }
 
 module_init(iptable_mangle_init);
index dc34aa274533b8d5893fd6d4bd3642a003c19e28..e41fe8ca4e1c87b9538961411504e1e7777c27b3 100644 (file)
@@ -14,7 +14,7 @@ static struct
        struct ipt_replace repl;
        struct ipt_standard entries[2];
        struct ipt_error term;
-} initial_table __initdata = {
+} initial_table __net_initdata = {
        .repl = {
                .name = "raw",
                .valid_hooks = RAW_VALID_HOOKS,
@@ -52,7 +52,7 @@ ipt_hook(unsigned int hook,
         const struct net_device *out,
         int (*okfn)(struct sk_buff *))
 {
-       return ipt_do_table(skb, hook, in, out, &packet_raw);
+       return ipt_do_table(skb, hook, in, out, init_net.ipv4.iptable_raw);
 }
 
 static unsigned int
@@ -70,7 +70,7 @@ ipt_local_hook(unsigned int hook,
                               "packet.\n");
                return NF_ACCEPT;
        }
-       return ipt_do_table(skb, hook, in, out, &packet_raw);
+       return ipt_do_table(skb, hook, in, out, init_net.ipv4.iptable_raw);
 }
 
 /* 'raw' is the very first table. */
@@ -91,12 +91,31 @@ static struct nf_hook_ops ipt_ops[] __read_mostly = {
        },
 };
 
+static int __net_init iptable_raw_net_init(struct net *net)
+{
+       /* Register table */
+       net->ipv4.iptable_raw =
+               ipt_register_table(net, &packet_raw, &initial_table.repl);
+       if (IS_ERR(net->ipv4.iptable_raw))
+               return PTR_ERR(net->ipv4.iptable_raw);
+       return 0;
+}
+
+static void __net_exit iptable_raw_net_exit(struct net *net)
+{
+       ipt_unregister_table(net->ipv4.iptable_raw);
+}
+
+static struct pernet_operations iptable_raw_net_ops = {
+       .init = iptable_raw_net_init,
+       .exit = iptable_raw_net_exit,
+};
+
 static int __init iptable_raw_init(void)
 {
        int ret;
 
-       /* Register table */
-       ret = ipt_register_table(&packet_raw, &initial_table.repl);
+       ret = register_pernet_subsys(&iptable_raw_net_ops);
        if (ret < 0)
                return ret;
 
@@ -108,14 +127,14 @@ static int __init iptable_raw_init(void)
        return ret;
 
  cleanup_table:
-       ipt_unregister_table(&packet_raw);
+       unregister_pernet_subsys(&iptable_raw_net_ops);
        return ret;
 }
 
 static void __exit iptable_raw_fini(void)
 {
        nf_unregister_hooks(ipt_ops, ARRAY_SIZE(ipt_ops));
-       ipt_unregister_table(&packet_raw);
+       unregister_pernet_subsys(&iptable_raw_net_ops);
 }
 
 module_init(iptable_raw_init);
index ac3d61d8026e2d6d0052b0ca2d30b20433224413..a65b845c5f1596ec5d7732b6d84508f1133eef3f 100644 (file)
@@ -27,7 +27,8 @@
 static int ipv4_pkt_to_tuple(const struct sk_buff *skb, unsigned int nhoff,
                             struct nf_conntrack_tuple *tuple)
 {
-       __be32 _addrs[2], *ap;
+       const __be32 *ap;
+       __be32 _addrs[2];
        ap = skb_header_pointer(skb, nhoff + offsetof(struct iphdr, saddr),
                                sizeof(u_int32_t) * 2, _addrs);
        if (ap == NULL)
@@ -76,7 +77,8 @@ static int nf_ct_ipv4_gather_frags(struct sk_buff *skb, u_int32_t user)
 static int ipv4_get_l4proto(const struct sk_buff *skb, unsigned int nhoff,
                            unsigned int *dataoff, u_int8_t *protonum)
 {
-       struct iphdr _iph, *iph;
+       const struct iphdr *iph;
+       struct iphdr _iph;
 
        iph = skb_header_pointer(skb, nhoff, sizeof(_iph), &_iph);
        if (iph == NULL)
@@ -111,8 +113,8 @@ static unsigned int ipv4_conntrack_help(unsigned int hooknum,
 {
        struct nf_conn *ct;
        enum ip_conntrack_info ctinfo;
-       struct nf_conn_help *help;
-       struct nf_conntrack_helper *helper;
+       const struct nf_conn_help *help;
+       const struct nf_conntrack_helper *helper;
 
        /* This is where we call the helper: as the packet goes out. */
        ct = nf_ct_get(skb, &ctinfo);
@@ -299,8 +301,8 @@ static ctl_table ip_ct_sysctl_table[] = {
 static int
 getorigdst(struct sock *sk, int optval, void __user *user, int *len)
 {
-       struct inet_sock *inet = inet_sk(sk);
-       struct nf_conntrack_tuple_hash *h;
+       const struct inet_sock *inet = inet_sk(sk);
+       const struct nf_conntrack_tuple_hash *h;
        struct nf_conntrack_tuple tuple;
 
        NF_CT_TUPLE_U_BLANK(&tuple);
index 543c02b74c96be28532e1c30a01929cea0a70547..089252e82c01fb93b55efa15c0e7a7f74d36398d 100644 (file)
@@ -39,12 +39,14 @@ struct ct_iter_state {
 static struct hlist_node *ct_get_first(struct seq_file *seq)
 {
        struct ct_iter_state *st = seq->private;
+       struct hlist_node *n;
 
        for (st->bucket = 0;
             st->bucket < nf_conntrack_htable_size;
             st->bucket++) {
-               if (!hlist_empty(&nf_conntrack_hash[st->bucket]))
-                       return nf_conntrack_hash[st->bucket].first;
+               n = rcu_dereference(nf_conntrack_hash[st->bucket].first);
+               if (n)
+                       return n;
        }
        return NULL;
 }
@@ -54,11 +56,11 @@ static struct hlist_node *ct_get_next(struct seq_file *seq,
 {
        struct ct_iter_state *st = seq->private;
 
-       head = head->next;
+       head = rcu_dereference(head->next);
        while (head == NULL) {
                if (++st->bucket >= nf_conntrack_htable_size)
                        return NULL;
-               head = nf_conntrack_hash[st->bucket].first;
+               head = rcu_dereference(nf_conntrack_hash[st->bucket].first);
        }
        return head;
 }
@@ -74,8 +76,9 @@ static struct hlist_node *ct_get_idx(struct seq_file *seq, loff_t pos)
 }
 
 static void *ct_seq_start(struct seq_file *seq, loff_t *pos)
+       __acquires(RCU)
 {
-       read_lock_bh(&nf_conntrack_lock);
+       rcu_read_lock();
        return ct_get_idx(seq, *pos);
 }
 
@@ -86,16 +89,17 @@ static void *ct_seq_next(struct seq_file *s, void *v, loff_t *pos)
 }
 
 static void ct_seq_stop(struct seq_file *s, void *v)
+       __releases(RCU)
 {
-       read_unlock_bh(&nf_conntrack_lock);
+       rcu_read_unlock();
 }
 
 static int ct_seq_show(struct seq_file *s, void *v)
 {
        const struct nf_conntrack_tuple_hash *hash = v;
        const struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(hash);
-       struct nf_conntrack_l3proto *l3proto;
-       struct nf_conntrack_l4proto *l4proto;
+       const struct nf_conntrack_l3proto *l3proto;
+       const struct nf_conntrack_l4proto *l4proto;
 
        NF_CT_ASSERT(ct);
 
@@ -191,10 +195,12 @@ struct ct_expect_iter_state {
 static struct hlist_node *ct_expect_get_first(struct seq_file *seq)
 {
        struct ct_expect_iter_state *st = seq->private;
+       struct hlist_node *n;
 
        for (st->bucket = 0; st->bucket < nf_ct_expect_hsize; st->bucket++) {
-               if (!hlist_empty(&nf_ct_expect_hash[st->bucket]))
-                       return nf_ct_expect_hash[st->bucket].first;
+               n = rcu_dereference(nf_ct_expect_hash[st->bucket].first);
+               if (n)
+                       return n;
        }
        return NULL;
 }
@@ -204,11 +210,11 @@ static struct hlist_node *ct_expect_get_next(struct seq_file *seq,
 {
        struct ct_expect_iter_state *st = seq->private;
 
-       head = head->next;
+       head = rcu_dereference(head->next);
        while (head == NULL) {
                if (++st->bucket >= nf_ct_expect_hsize)
                        return NULL;
-               head = nf_ct_expect_hash[st->bucket].first;
+               head = rcu_dereference(nf_ct_expect_hash[st->bucket].first);
        }
        return head;
 }
@@ -224,8 +230,9 @@ static struct hlist_node *ct_expect_get_idx(struct seq_file *seq, loff_t pos)
 }
 
 static void *exp_seq_start(struct seq_file *seq, loff_t *pos)
+       __acquires(RCU)
 {
-       read_lock_bh(&nf_conntrack_lock);
+       rcu_read_lock();
        return ct_expect_get_idx(seq, *pos);
 }
 
@@ -236,14 +243,15 @@ static void *exp_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 }
 
 static void exp_seq_stop(struct seq_file *seq, void *v)
+       __releases(RCU)
 {
-       read_unlock_bh(&nf_conntrack_lock);
+       rcu_read_unlock();
 }
 
 static int exp_seq_show(struct seq_file *s, void *v)
 {
        struct nf_conntrack_expect *exp;
-       struct hlist_node *n = v;
+       const struct hlist_node *n = v;
 
        exp = hlist_entry(n, struct nf_conntrack_expect, hnode);
 
@@ -324,7 +332,7 @@ static void ct_cpu_seq_stop(struct seq_file *seq, void *v)
 static int ct_cpu_seq_show(struct seq_file *seq, void *v)
 {
        unsigned int nr_conntracks = atomic_read(&nf_conntrack_count);
-       struct ip_conntrack_stat *st = v;
+       const struct ip_conntrack_stat *st = v;
 
        if (v == SEQ_START_TOKEN) {
                seq_printf(seq, "entries  searched found new invalid ignore delete delete_list insert insert_failed drop early_drop icmp_error  expect_new expect_create expect_delete\n");
index 4004a04c551014205886bc3768523a77f2ccdd2b..6873fddb3529936a9ef7af490573eb9dc9aec45f 100644 (file)
@@ -26,7 +26,8 @@ static int icmp_pkt_to_tuple(const struct sk_buff *skb,
                             unsigned int dataoff,
                             struct nf_conntrack_tuple *tuple)
 {
-       struct icmphdr _hdr, *hp;
+       const struct icmphdr *hp;
+       struct icmphdr _hdr;
 
        hp = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr);
        if (hp == NULL)
@@ -100,7 +101,7 @@ static int icmp_packet(struct nf_conn *ct,
 }
 
 /* Called when a new connection for this protocol found. */
-static int icmp_new(struct nf_conn *conntrack,
+static int icmp_new(struct nf_conn *ct,
                    const struct sk_buff *skb, unsigned int dataoff)
 {
        static const u_int8_t valid_new[] = {
@@ -110,15 +111,15 @@ static int icmp_new(struct nf_conn *conntrack,
                [ICMP_ADDRESS] = 1
        };
 
-       if (conntrack->tuplehash[0].tuple.dst.u.icmp.type >= sizeof(valid_new)
-           || !valid_new[conntrack->tuplehash[0].tuple.dst.u.icmp.type]) {
+       if (ct->tuplehash[0].tuple.dst.u.icmp.type >= sizeof(valid_new)
+           || !valid_new[ct->tuplehash[0].tuple.dst.u.icmp.type]) {
                /* Can't create a new ICMP `conn' with this. */
                pr_debug("icmp: can't create new conn with type %u\n",
-                        conntrack->tuplehash[0].tuple.dst.u.icmp.type);
-               NF_CT_DUMP_TUPLE(&conntrack->tuplehash[0].tuple);
+                        ct->tuplehash[0].tuple.dst.u.icmp.type);
+               NF_CT_DUMP_TUPLE(&ct->tuplehash[0].tuple);
                return 0;
        }
-       atomic_set(&conntrack->proto.icmp.count, 0);
+       atomic_set(&ct->proto.icmp.count, 0);
        return 1;
 }
 
@@ -129,8 +130,8 @@ icmp_error_message(struct sk_buff *skb,
                 unsigned int hooknum)
 {
        struct nf_conntrack_tuple innertuple, origtuple;
-       struct nf_conntrack_l4proto *innerproto;
-       struct nf_conntrack_tuple_hash *h;
+       const struct nf_conntrack_l4proto *innerproto;
+       const struct nf_conntrack_tuple_hash *h;
 
        NF_CT_ASSERT(skb->nfct == NULL);
 
@@ -176,7 +177,8 @@ static int
 icmp_error(struct sk_buff *skb, unsigned int dataoff,
           enum ip_conntrack_info *ctinfo, int pf, unsigned int hooknum)
 {
-       struct icmphdr _ih, *icmph;
+       const struct icmphdr *icmph;
+       struct icmphdr _ih;
 
        /* Not enough header? */
        icmph = skb_header_pointer(skb, ip_hdrlen(skb), sizeof(_ih), &_ih);
index e53ae1ef8f5e1f0dae45e5d191b079c681a0dcb3..dd07362d2b8f42e5303419d509a0a1136e51cd42 100644 (file)
@@ -31,7 +31,7 @@
 #include <net/netfilter/nf_conntrack_l3proto.h>
 #include <net/netfilter/nf_conntrack_l4proto.h>
 
-static DEFINE_RWLOCK(nf_nat_lock);
+static DEFINE_SPINLOCK(nf_nat_lock);
 
 static struct nf_conntrack_l3proto *l3proto __read_mostly;
 
@@ -154,8 +154,8 @@ find_appropriate_src(const struct nf_conntrack_tuple *tuple,
        struct nf_conn *ct;
        struct hlist_node *n;
 
-       read_lock_bh(&nf_nat_lock);
-       hlist_for_each_entry(nat, n, &bysource[h], bysource) {
+       rcu_read_lock();
+       hlist_for_each_entry_rcu(nat, n, &bysource[h], bysource) {
                ct = nat->ct;
                if (same_src(ct, tuple)) {
                        /* Copy source part from reply tuple. */
@@ -164,12 +164,12 @@ find_appropriate_src(const struct nf_conntrack_tuple *tuple,
                        result->dst = tuple->dst;
 
                        if (in_range(result, range)) {
-                               read_unlock_bh(&nf_nat_lock);
+                               rcu_read_unlock();
                                return 1;
                        }
                }
        }
-       read_unlock_bh(&nf_nat_lock);
+       rcu_read_unlock();
        return 0;
 }
 
@@ -330,12 +330,12 @@ nf_nat_setup_info(struct nf_conn *ct,
                unsigned int srchash;
 
                srchash = hash_by_src(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
-               write_lock_bh(&nf_nat_lock);
+               spin_lock_bh(&nf_nat_lock);
                /* nf_conntrack_alter_reply might re-allocate exntension aera */
                nat = nfct_nat(ct);
                nat->ct = ct;
-               hlist_add_head(&nat->bysource, &bysource[srchash]);
-               write_unlock_bh(&nf_nat_lock);
+               hlist_add_head_rcu(&nat->bysource, &bysource[srchash]);
+               spin_unlock_bh(&nf_nat_lock);
        }
 
        /* It's done. */
@@ -521,14 +521,14 @@ int nf_nat_protocol_register(const struct nf_nat_protocol *proto)
 {
        int ret = 0;
 
-       write_lock_bh(&nf_nat_lock);
+       spin_lock_bh(&nf_nat_lock);
        if (nf_nat_protos[proto->protonum] != &nf_nat_unknown_protocol) {
                ret = -EBUSY;
                goto out;
        }
        rcu_assign_pointer(nf_nat_protos[proto->protonum], proto);
  out:
-       write_unlock_bh(&nf_nat_lock);
+       spin_unlock_bh(&nf_nat_lock);
        return ret;
 }
 EXPORT_SYMBOL(nf_nat_protocol_register);
@@ -536,10 +536,10 @@ EXPORT_SYMBOL(nf_nat_protocol_register);
 /* Noone stores the protocol anywhere; simply delete it. */
 void nf_nat_protocol_unregister(const struct nf_nat_protocol *proto)
 {
-       write_lock_bh(&nf_nat_lock);
+       spin_lock_bh(&nf_nat_lock);
        rcu_assign_pointer(nf_nat_protos[proto->protonum],
                           &nf_nat_unknown_protocol);
-       write_unlock_bh(&nf_nat_lock);
+       spin_unlock_bh(&nf_nat_lock);
        synchronize_rcu();
 }
 EXPORT_SYMBOL(nf_nat_protocol_unregister);
@@ -594,10 +594,10 @@ static void nf_nat_cleanup_conntrack(struct nf_conn *ct)
 
        NF_CT_ASSERT(nat->ct->status & IPS_NAT_DONE_MASK);
 
-       write_lock_bh(&nf_nat_lock);
-       hlist_del(&nat->bysource);
+       spin_lock_bh(&nf_nat_lock);
+       hlist_del_rcu(&nat->bysource);
        nat->ct = NULL;
-       write_unlock_bh(&nf_nat_lock);
+       spin_unlock_bh(&nf_nat_lock);
 }
 
 static void nf_nat_move_storage(struct nf_conn *conntrack, void *old)
@@ -609,10 +609,10 @@ static void nf_nat_move_storage(struct nf_conn *conntrack, void *old)
        if (!ct || !(ct->status & IPS_NAT_DONE_MASK))
                return;
 
-       write_lock_bh(&nf_nat_lock);
+       spin_lock_bh(&nf_nat_lock);
        hlist_replace_rcu(&old_nat->bysource, &new_nat->bysource);
        new_nat->ct = ct;
-       write_unlock_bh(&nf_nat_lock);
+       spin_unlock_bh(&nf_nat_lock);
 }
 
 static struct nf_ct_ext_type nat_extend __read_mostly = {
@@ -646,17 +646,13 @@ static int __init nf_nat_init(void)
        }
 
        /* Sew in builtin protocols. */
-       write_lock_bh(&nf_nat_lock);
+       spin_lock_bh(&nf_nat_lock);
        for (i = 0; i < MAX_IP_NAT_PROTO; i++)
                rcu_assign_pointer(nf_nat_protos[i], &nf_nat_unknown_protocol);
        rcu_assign_pointer(nf_nat_protos[IPPROTO_TCP], &nf_nat_protocol_tcp);
        rcu_assign_pointer(nf_nat_protos[IPPROTO_UDP], &nf_nat_protocol_udp);
        rcu_assign_pointer(nf_nat_protos[IPPROTO_ICMP], &nf_nat_protocol_icmp);
-       write_unlock_bh(&nf_nat_lock);
-
-       for (i = 0; i < nf_nat_htable_size; i++) {
-               INIT_HLIST_HEAD(&bysource[i]);
-       }
+       spin_unlock_bh(&nf_nat_lock);
 
        /* Initialize fake conntrack so that NAT will skip it */
        nf_conntrack_untracked.status |= IPS_NAT_DONE_MASK;
index a121989fdad7c5c38363fe77d447c43dc07038b5..ee47bf28c82547463629288cc16249bcceb1e20c 100644 (file)
@@ -32,7 +32,8 @@ static int set_addr(struct sk_buff *skb,
                __be32 ip;
                __be16 port;
        } __attribute__ ((__packed__)) buf;
-       struct tcphdr _tcph, *th;
+       const struct tcphdr *th;
+       struct tcphdr _tcph;
 
        buf.ip = ip;
        buf.port = port;
@@ -99,7 +100,7 @@ static int set_sig_addr(struct sk_buff *skb, struct nf_conn *ct,
                        unsigned char **data,
                        TransportAddress *taddr, int count)
 {
-       struct nf_ct_h323_master *info = &nfct_help(ct)->help.ct_h323_info;
+       const struct nf_ct_h323_master *info = &nfct_help(ct)->help.ct_h323_info;
        int dir = CTINFO2DIR(ctinfo);
        int i;
        __be16 port;
index 4c0232842e75408759a7a6324c3a2a4ea3452b1e..ca57f47bbd255b14f2a6fd9d8c6b04a7918a3ab5 100644 (file)
@@ -44,8 +44,7 @@ adjust_tcp_sequence(u32 seq,
        struct nf_nat_seq *this_way, *other_way;
        struct nf_conn_nat *nat = nfct_nat(ct);
 
-       pr_debug("adjust_tcp_sequence: seq = %u, sizediff = %d\n",
-                ntohl(seq), seq);
+       pr_debug("adjust_tcp_sequence: seq = %u, sizediff = %d\n", seq, seq);
 
        dir = CTINFO2DIR(ctinfo);
 
index e63b944a2ebbd85a03f8ed5cdb4e3ba810ea0efb..3a1e6d6afc0af3d8d2a7fda4cfc4a9e7bf290994 100644 (file)
@@ -40,11 +40,11 @@ MODULE_ALIAS("ip_nat_pptp");
 static void pptp_nat_expected(struct nf_conn *ct,
                              struct nf_conntrack_expect *exp)
 {
-       struct nf_conn *master = ct->master;
+       const struct nf_conn *master = ct->master;
        struct nf_conntrack_expect *other_exp;
        struct nf_conntrack_tuple t;
-       struct nf_ct_pptp_master *ct_pptp_info;
-       struct nf_nat_pptp *nat_pptp_info;
+       const struct nf_ct_pptp_master *ct_pptp_info;
+       const struct nf_nat_pptp *nat_pptp_info;
        struct nf_nat_range range;
 
        ct_pptp_info = &nfct_help(master)->help.ct_pptp_info;
@@ -186,7 +186,7 @@ static void
 pptp_exp_gre(struct nf_conntrack_expect *expect_orig,
             struct nf_conntrack_expect *expect_reply)
 {
-       struct nf_conn *ct = expect_orig->master;
+       const struct nf_conn *ct = expect_orig->master;
        struct nf_ct_pptp_master *ct_pptp_info;
        struct nf_nat_pptp *nat_pptp_info;
 
@@ -217,7 +217,7 @@ pptp_inbound_pkt(struct sk_buff *skb,
                 struct PptpControlHeader *ctlh,
                 union pptp_ctrl_union *pptpReq)
 {
-       struct nf_nat_pptp *nat_pptp_info;
+       const struct nf_nat_pptp *nat_pptp_info;
        u_int16_t msg;
        __be16 new_pcid;
        unsigned int pcid_off;
index 9fa272e73113f6bdda3e8908677b76169ca63201..a1e4da16da2e8a411fc39b6009c4b4f1151d0a09 100644 (file)
@@ -59,7 +59,7 @@ static int
 gre_unique_tuple(struct nf_conntrack_tuple *tuple,
                 const struct nf_nat_range *range,
                 enum nf_nat_manip_type maniptype,
-                const struct nf_conn *conntrack)
+                const struct nf_conn *ct)
 {
        static u_int16_t key;
        __be16 *keyptr;
@@ -67,7 +67,7 @@ gre_unique_tuple(struct nf_conntrack_tuple *tuple,
 
        /* If there is no master conntrack we are not PPTP,
           do not change tuples */
-       if (!conntrack->master)
+       if (!ct->master)
                return 0;
 
        if (maniptype == IP_NAT_MANIP_SRC)
@@ -76,7 +76,7 @@ gre_unique_tuple(struct nf_conntrack_tuple *tuple,
                keyptr = &tuple->dst.u.gre.key;
 
        if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED)) {
-               pr_debug("%p: NATing GRE PPTP\n", conntrack);
+               pr_debug("%p: NATing GRE PPTP\n", ct);
                min = 1;
                range_size = 0xffff;
        } else {
@@ -88,11 +88,11 @@ gre_unique_tuple(struct nf_conntrack_tuple *tuple,
 
        for (i = 0; i < range_size; i++, key++) {
                *keyptr = htons(min + key % range_size);
-               if (!nf_nat_used_tuple(tuple, conntrack))
+               if (!nf_nat_used_tuple(tuple, ct))
                        return 1;
        }
 
-       pr_debug("%p: no NAT mapping\n", conntrack);
+       pr_debug("%p: no NAT mapping\n", ct);
        return 0;
 }
 
@@ -104,7 +104,7 @@ gre_manip_pkt(struct sk_buff *skb, unsigned int iphdroff,
 {
        struct gre_hdr *greh;
        struct gre_hdr_pptp *pgreh;
-       struct iphdr *iph = (struct iphdr *)(skb->data + iphdroff);
+       const struct iphdr *iph = (struct iphdr *)(skb->data + iphdroff);
        unsigned int hdroff = iphdroff + iph->ihl * 4;
 
        /* pgreh includes two optional 32bit fields which are not required
@@ -148,12 +148,12 @@ static const struct nf_nat_protocol gre = {
 #endif
 };
 
-int __init nf_nat_proto_gre_init(void)
+static int __init nf_nat_proto_gre_init(void)
 {
        return nf_nat_protocol_register(&gre);
 }
 
-void __exit nf_nat_proto_gre_fini(void)
+static void __exit nf_nat_proto_gre_fini(void)
 {
        nf_nat_protocol_unregister(&gre);
 }
index a0e44c953cb6352248a6fa89e3eddc7846b0ec86..03a02969aa5710fde9a897a2d913396b17b94bee 100644 (file)
@@ -57,7 +57,7 @@ icmp_manip_pkt(struct sk_buff *skb,
               const struct nf_conntrack_tuple *tuple,
               enum nf_nat_manip_type maniptype)
 {
-       struct iphdr *iph = (struct iphdr *)(skb->data + iphdroff);
+       const struct iphdr *iph = (struct iphdr *)(skb->data + iphdroff);
        struct icmphdr *hdr;
        unsigned int hdroff = iphdroff + iph->ihl*4;
 
index da23e9fbe6790b9ba957cb98b8b7d36e14b65fad..ffd5d1589eca55bfd167f452ba0a3eb5efc9926a 100644 (file)
@@ -93,7 +93,7 @@ tcp_manip_pkt(struct sk_buff *skb,
              const struct nf_conntrack_tuple *tuple,
              enum nf_nat_manip_type maniptype)
 {
-       struct iphdr *iph = (struct iphdr *)(skb->data + iphdroff);
+       const struct iphdr *iph = (struct iphdr *)(skb->data + iphdroff);
        struct tcphdr *hdr;
        unsigned int hdroff = iphdroff + iph->ihl*4;
        __be32 oldip, newip;
index 10df4db078afd1693b62d95faa2aa2f848bee815..4b8f49910ff2cb112cd80030ef5e8112d3fa70cc 100644 (file)
@@ -91,7 +91,7 @@ udp_manip_pkt(struct sk_buff *skb,
              const struct nf_conntrack_tuple *tuple,
              enum nf_nat_manip_type maniptype)
 {
-       struct iphdr *iph = (struct iphdr *)(skb->data + iphdroff);
+       const struct iphdr *iph = (struct iphdr *)(skb->data + iphdroff);
        struct udphdr *hdr;
        unsigned int hdroff = iphdroff + iph->ihl*4;
        __be32 oldip, newip;
index 519182269e76d1418c0ef6830b073c330e7e4dcc..f8fda57ba20b6bc92ed0753da70ca72ef73fc555 100644 (file)
@@ -58,13 +58,14 @@ static struct
        .term = IPT_ERROR_INIT,                 /* ERROR */
 };
 
-static struct xt_table nat_table = {
+static struct xt_table __nat_table = {
        .name           = "nat",
        .valid_hooks    = NAT_VALID_HOOKS,
        .lock           = RW_LOCK_UNLOCKED,
        .me             = THIS_MODULE,
        .af             = AF_INET,
 };
+static struct xt_table *nat_table;
 
 /* Source NAT */
 static unsigned int ipt_snat_target(struct sk_buff *skb,
@@ -214,7 +215,7 @@ int nf_nat_rule_find(struct sk_buff *skb,
 {
        int ret;
 
-       ret = ipt_do_table(skb, hooknum, in, out, &nat_table);
+       ret = ipt_do_table(skb, hooknum, in, out, nat_table);
 
        if (ret == NF_ACCEPT) {
                if (!nf_nat_initialized(ct, HOOK2MANIP(hooknum)))
@@ -248,9 +249,10 @@ int __init nf_nat_rule_init(void)
 {
        int ret;
 
-       ret = ipt_register_table(&nat_table, &nat_initial_table.repl);
-       if (ret != 0)
-               return ret;
+       nat_table = ipt_register_table(&init_net, &__nat_table,
+                                      &nat_initial_table.repl);
+       if (IS_ERR(nat_table))
+               return PTR_ERR(nat_table);
        ret = xt_register_target(&ipt_snat_reg);
        if (ret != 0)
                goto unregister_table;
@@ -264,7 +266,7 @@ int __init nf_nat_rule_init(void)
  unregister_snat:
        xt_unregister_target(&ipt_snat_reg);
  unregister_table:
-       ipt_unregister_table(&nat_table);
+       ipt_unregister_table(nat_table);
 
        return ret;
 }
@@ -273,5 +275,5 @@ void nf_nat_rule_cleanup(void)
 {
        xt_unregister_target(&ipt_dnat_reg);
        xt_unregister_target(&ipt_snat_reg);
-       ipt_unregister_table(&nat_table);
+       ipt_unregister_table(nat_table);
 }
index 606a170bf4cae443895733f5401d82926996743e..b4c8d4968bb2f5ad52aa0446e4aeab51d8b98756 100644 (file)
@@ -35,9 +35,9 @@ struct addr_map {
        } addr[IP_CT_DIR_MAX];
 };
 
-static void addr_map_init(struct nf_conn *ct, struct addr_map *map)
+static void addr_map_init(const struct nf_conn *ct, struct addr_map *map)
 {
-       struct nf_conntrack_tuple *t;
+       const struct nf_conntrack_tuple *t;
        enum ip_conntrack_dir dir;
        unsigned int n;
 
index 07f2a49926d4ae1c5ffe6227e0058ff3b19dff05..540ce6ae887c0a797f8db68cb99a0be8c69c98ac 100644 (file)
@@ -260,7 +260,7 @@ static unsigned char asn1_eoc_decode(struct asn1_ctx *ctx, unsigned char *eoc)
 {
        unsigned char ch;
 
-       if (eoc == 0) {
+       if (eoc == NULL) {
                if (!asn1_octet_decode(ctx, &ch))
                        return 0;
 
index 1360a94766dd6321d7f1a07d719d88adce5a44f1..b096e81500aea2b86ffa6a2e0111d94307edf2a9 100644 (file)
@@ -24,7 +24,7 @@ static unsigned int help(struct sk_buff *skb,
                         enum ip_conntrack_info ctinfo,
                         struct nf_conntrack_expect *exp)
 {
-       struct nf_conn *ct = exp->master;
+       const struct nf_conn *ct = exp->master;
 
        exp->saved_proto.udp.port
                = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.udp.port;
index 85c08696abbe40b4a38de040fe59788a5ff4138e..a3002fe65b7f4a345c1333c4d7f36392bee3b172 100644 (file)
@@ -352,6 +352,7 @@ static int raw_send_hdrinc(struct sock *sk, void *from, size_t length,
        skb_reserve(skb, hh_len);
 
        skb->priority = sk->sk_priority;
+       skb->mark = sk->sk_mark;
        skb->dst = dst_clone(&rt->u.dst);
 
        skb_reset_network_header(skb);
@@ -544,6 +545,7 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
 
        {
                struct flowi fl = { .oif = ipc.oif,
+                                   .mark = sk->sk_mark,
                                    .nl_u = { .ip4_u =
                                              { .daddr = daddr,
                                                .saddr = saddr,
@@ -860,8 +862,7 @@ static struct sock *raw_get_first(struct seq_file *seq)
                struct hlist_node *node;
 
                sk_for_each(sk, node, &state->h->ht[state->bucket])
-                       if (sk->sk_net == state->p.net &&
-                                       sk->sk_family == state->family)
+                       if (sk->sk_net == state->p.net)
                                goto found;
        }
        sk = NULL;
@@ -877,8 +878,7 @@ static struct sock *raw_get_next(struct seq_file *seq, struct sock *sk)
                sk = sk_next(sk);
 try_again:
                ;
-       } while (sk && sk->sk_net != state->p.net &&
-                       sk->sk_family != state->family);
+       } while (sk && sk->sk_net != state->p.net);
 
        if (!sk && ++state->bucket < RAW_HTABLE_SIZE) {
                sk = sk_head(&state->h->ht[state->bucket]);
@@ -927,7 +927,7 @@ void raw_seq_stop(struct seq_file *seq, void *v)
 }
 EXPORT_SYMBOL_GPL(raw_seq_stop);
 
-static __inline__ char *get_raw_sock(struct sock *sp, char *tmpbuf, int i)
+static void raw_sock_seq_show(struct seq_file *seq, struct sock *sp, int i)
 {
        struct inet_sock *inet = inet_sk(sp);
        __be32 dest = inet->daddr,
@@ -935,33 +935,23 @@ static __inline__ char *get_raw_sock(struct sock *sp, char *tmpbuf, int i)
        __u16 destp = 0,
              srcp  = inet->num;
 
-       sprintf(tmpbuf, "%4d: %08X:%04X %08X:%04X"
+       seq_printf(seq, "%4d: %08X:%04X %08X:%04X"
                " %02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p %d",
                i, src, srcp, dest, destp, sp->sk_state,
                atomic_read(&sp->sk_wmem_alloc),
                atomic_read(&sp->sk_rmem_alloc),
                0, 0L, 0, sock_i_uid(sp), 0, sock_i_ino(sp),
                atomic_read(&sp->sk_refcnt), sp, atomic_read(&sp->sk_drops));
-       return tmpbuf;
 }
 
-#define TMPSZ 128
-
 static int raw_seq_show(struct seq_file *seq, void *v)
 {
-       char tmpbuf[TMPSZ+1];
-
        if (v == SEQ_START_TOKEN)
-               seq_printf(seq, "%-*s\n", TMPSZ-1,
-                              "  sl  local_address rem_address   st tx_queue "
-                              "rx_queue tr tm->when retrnsmt   uid  timeout "
-                              "inode  drops");
-       else {
-               struct raw_iter_state *state = raw_seq_private(seq);
-
-               seq_printf(seq, "%-*s\n", TMPSZ-1,
-                          get_raw_sock(v, tmpbuf, state->bucket));
-       }
+               seq_printf(seq, "  sl  local_address rem_address   st tx_queue "
+                               "rx_queue tr tm->when retrnsmt   uid  timeout "
+                               "inode  drops\n");
+       else
+               raw_sock_seq_show(seq, v, raw_seq_private(seq)->bucket);
        return 0;
 }
 
@@ -972,27 +962,25 @@ static const struct seq_operations raw_seq_ops = {
        .show  = raw_seq_show,
 };
 
-int raw_seq_open(struct inode *ino, struct file *file, struct raw_hashinfo *h,
-               unsigned short family)
+int raw_seq_open(struct inode *ino, struct file *file,
+                struct raw_hashinfo *h, const struct seq_operations *ops)
 {
        int err;
        struct raw_iter_state *i;
 
-       err = seq_open_net(ino, file, &raw_seq_ops,
-                       sizeof(struct raw_iter_state));
+       err = seq_open_net(ino, file, ops, sizeof(struct raw_iter_state));
        if (err < 0)
                return err;
 
        i = raw_seq_private((struct seq_file *)file->private_data);
        i->h = h;
-       i->family = family;
        return 0;
 }
 EXPORT_SYMBOL_GPL(raw_seq_open);
 
 static int raw_v4_seq_open(struct inode *inode, struct file *file)
 {
-       return raw_seq_open(inode, file, &raw_v4_hashinfo, PF_INET);
+       return raw_seq_open(inode, file, &raw_v4_hashinfo, &raw_seq_ops);
 }
 
 static const struct file_operations raw_seq_fops = {
index 896c768e41a2d90baef4b4a3783be0164678ff9e..8842ecb9be484e279a603053912c0f850b4eb11b 100644 (file)
 
 #define RT_GC_TIMEOUT (300*HZ)
 
-static int ip_rt_min_delay             = 2 * HZ;
-static int ip_rt_max_delay             = 10 * HZ;
 static int ip_rt_max_size;
 static int ip_rt_gc_timeout            = RT_GC_TIMEOUT;
 static int ip_rt_gc_interval           = 60 * HZ;
@@ -133,12 +131,9 @@ static int ip_rt_mtu_expires               = 10 * 60 * HZ;
 static int ip_rt_min_pmtu              = 512 + 20 + 20;
 static int ip_rt_min_advmss            = 256;
 static int ip_rt_secret_interval       = 10 * 60 * HZ;
-static int ip_rt_flush_expected;
-static unsigned long rt_deadline;
 
 #define RTprint(a...)  printk(KERN_DEBUG a)
 
-static struct timer_list rt_flush_timer;
 static void rt_worker_func(struct work_struct *work);
 static DECLARE_DELAYED_WORK(expires_work, rt_worker_func);
 static struct timer_list rt_secret_timer;
@@ -169,6 +164,7 @@ static struct dst_ops ipv4_dst_ops = {
        .update_pmtu =          ip_rt_update_pmtu,
        .local_out =            ip_local_out,
        .entry_size =           sizeof(struct rtable),
+       .entries =              ATOMIC_INIT(0),
 };
 
 #define ECN_OR_COST(class)     TC_PRIO_##class
@@ -259,19 +255,16 @@ static inline void rt_hash_lock_init(void)
 static struct rt_hash_bucket   *rt_hash_table;
 static unsigned                        rt_hash_mask;
 static unsigned int            rt_hash_log;
-static unsigned int            rt_hash_rnd;
+static atomic_t                        rt_genid;
 
 static DEFINE_PER_CPU(struct rt_cache_stat, rt_cache_stat);
 #define RT_CACHE_STAT_INC(field) \
        (__raw_get_cpu_var(rt_cache_stat).field++)
 
-static int rt_intern_hash(unsigned hash, struct rtable *rth,
-                               struct rtable **res);
-
 static unsigned int rt_hash_code(u32 daddr, u32 saddr)
 {
-       return (jhash_2words(daddr, saddr, rt_hash_rnd)
-               & rt_hash_mask);
+       return jhash_2words(daddr, saddr, atomic_read(&rt_genid))
+               & rt_hash_mask;
 }
 
 #define rt_hash(daddr, saddr, idx) \
@@ -281,27 +274,28 @@ static unsigned int rt_hash_code(u32 daddr, u32 saddr)
 #ifdef CONFIG_PROC_FS
 struct rt_cache_iter_state {
        int bucket;
+       int genid;
 };
 
-static struct rtable *rt_cache_get_first(struct seq_file *seq)
+static struct rtable *rt_cache_get_first(struct rt_cache_iter_state *st)
 {
        struct rtable *r = NULL;
-       struct rt_cache_iter_state *st = seq->private;
 
        for (st->bucket = rt_hash_mask; st->bucket >= 0; --st->bucket) {
                rcu_read_lock_bh();
-               r = rt_hash_table[st->bucket].chain;
-               if (r)
-                       break;
+               r = rcu_dereference(rt_hash_table[st->bucket].chain);
+               while (r) {
+                       if (r->rt_genid == st->genid)
+                               return r;
+                       r = rcu_dereference(r->u.dst.rt_next);
+               }
                rcu_read_unlock_bh();
        }
-       return rcu_dereference(r);
+       return r;
 }
 
-static struct rtable *rt_cache_get_next(struct seq_file *seq, struct rtable *r)
+static struct rtable *rt_cache_get_next(struct rt_cache_iter_state *st, struct rtable *r)
 {
-       struct rt_cache_iter_state *st = seq->private;
-
        r = r->u.dst.rt_next;
        while (!r) {
                rcu_read_unlock_bh();
@@ -313,29 +307,38 @@ static struct rtable *rt_cache_get_next(struct seq_file *seq, struct rtable *r)
        return rcu_dereference(r);
 }
 
-static struct rtable *rt_cache_get_idx(struct seq_file *seq, loff_t pos)
+static struct rtable *rt_cache_get_idx(struct rt_cache_iter_state *st, loff_t pos)
 {
-       struct rtable *r = rt_cache_get_first(seq);
+       struct rtable *r = rt_cache_get_first(st);
 
        if (r)
-               while (pos && (r = rt_cache_get_next(seq, r)))
+               while (pos && (r = rt_cache_get_next(st, r))) {
+                       if (r->rt_genid != st->genid)
+                               continue;
                        --pos;
+               }
        return pos ? NULL : r;
 }
 
 static void *rt_cache_seq_start(struct seq_file *seq, loff_t *pos)
 {
-       return *pos ? rt_cache_get_idx(seq, *pos - 1) : SEQ_START_TOKEN;
+       struct rt_cache_iter_state *st = seq->private;
+
+       if (*pos)
+               return rt_cache_get_idx(st, *pos - 1);
+       st->genid = atomic_read(&rt_genid);
+       return SEQ_START_TOKEN;
 }
 
 static void *rt_cache_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 {
-       struct rtable *r = NULL;
+       struct rtable *r;
+       struct rt_cache_iter_state *st = seq->private;
 
        if (v == SEQ_START_TOKEN)
-               r = rt_cache_get_first(seq);
+               r = rt_cache_get_first(st);
        else
-               r = rt_cache_get_next(seq, v);
+               r = rt_cache_get_next(st, v);
        ++*pos;
        return r;
 }
@@ -708,6 +711,11 @@ static void rt_check_expire(void)
                        continue;
                spin_lock_bh(rt_hash_lock_addr(i));
                while ((rth = *rthp) != NULL) {
+                       if (rth->rt_genid != atomic_read(&rt_genid)) {
+                               *rthp = rth->u.dst.rt_next;
+                               rt_free(rth);
+                               continue;
+                       }
                        if (rth->u.dst.expires) {
                                /* Entry is expired even if it is in use */
                                if (time_before_eq(jiffies, rth->u.dst.expires)) {
@@ -732,83 +740,45 @@ static void rt_check_expire(void)
 
 /*
  * rt_worker_func() is run in process context.
- * If a whole flush was scheduled, it is done.
- * Else, we call rt_check_expire() to scan part of the hash table
+ * we call rt_check_expire() to scan part of the hash table
  */
 static void rt_worker_func(struct work_struct *work)
 {
-       if (ip_rt_flush_expected) {
-               ip_rt_flush_expected = 0;
-               rt_do_flush(1);
-       } else
-               rt_check_expire();
+       rt_check_expire();
        schedule_delayed_work(&expires_work, ip_rt_gc_interval);
 }
 
-/* This can run from both BH and non-BH contexts, the latter
- * in the case of a forced flush event.
+/*
+ * Pertubation of rt_genid by a small quantity [1..256]
+ * Using 8 bits of shuffling ensure we can call rt_cache_invalidate()
+ * many times (2^24) without giving recent rt_genid.
+ * Jenkins hash is strong enough that litle changes of rt_genid are OK.
  */
-static void rt_run_flush(unsigned long process_context)
+static void rt_cache_invalidate(void)
 {
-       rt_deadline = 0;
-
-       get_random_bytes(&rt_hash_rnd, 4);
+       unsigned char shuffle;
 
-       rt_do_flush(process_context);
+       get_random_bytes(&shuffle, sizeof(shuffle));
+       atomic_add(shuffle + 1U, &rt_genid);
 }
 
-static DEFINE_SPINLOCK(rt_flush_lock);
-
+/*
+ * delay < 0  : invalidate cache (fast : entries will be deleted later)
+ * delay >= 0 : invalidate & flush cache (can be long)
+ */
 void rt_cache_flush(int delay)
 {
-       unsigned long now = jiffies;
-       int user_mode = !in_softirq();
-
-       if (delay < 0)
-               delay = ip_rt_min_delay;
-
-       spin_lock_bh(&rt_flush_lock);
-
-       if (del_timer(&rt_flush_timer) && delay > 0 && rt_deadline) {
-               long tmo = (long)(rt_deadline - now);
-
-               /* If flush timer is already running
-                  and flush request is not immediate (delay > 0):
-
-                  if deadline is not achieved, prolongate timer to "delay",
-                  otherwise fire it at deadline time.
-                */
-
-               if (user_mode && tmo < ip_rt_max_delay-ip_rt_min_delay)
-                       tmo = 0;
-
-               if (delay > tmo)
-                       delay = tmo;
-       }
-
-       if (delay <= 0) {
-               spin_unlock_bh(&rt_flush_lock);
-               rt_run_flush(user_mode);
-               return;
-       }
-
-       if (rt_deadline == 0)
-               rt_deadline = now + ip_rt_max_delay;
-
-       mod_timer(&rt_flush_timer, now+delay);
-       spin_unlock_bh(&rt_flush_lock);
+       rt_cache_invalidate();
+       if (delay >= 0)
+               rt_do_flush(!in_softirq());
 }
 
 /*
- * We change rt_hash_rnd and ask next rt_worker_func() invocation
- * to perform a flush in process context
+ * We change rt_genid and let gc do the cleanup
  */
 static void rt_secret_rebuild(unsigned long dummy)
 {
-       get_random_bytes(&rt_hash_rnd, 4);
-       ip_rt_flush_expected = 1;
-       cancel_delayed_work(&expires_work);
-       schedule_delayed_work(&expires_work, HZ/10);
+       rt_cache_invalidate();
        mod_timer(&rt_secret_timer, jiffies + ip_rt_secret_interval);
 }
 
@@ -885,7 +855,8 @@ static int rt_garbage_collect(struct dst_ops *ops)
                        rthp = &rt_hash_table[k].chain;
                        spin_lock_bh(rt_hash_lock_addr(k));
                        while ((rth = *rthp) != NULL) {
-                               if (!rt_may_expire(rth, tmo, expire)) {
+                               if (rth->rt_genid == atomic_read(&rt_genid) &&
+                                       !rt_may_expire(rth, tmo, expire)) {
                                        tmo >>= 1;
                                        rthp = &rth->u.dst.rt_next;
                                        continue;
@@ -966,6 +937,11 @@ restart:
 
        spin_lock_bh(rt_hash_lock_addr(hash));
        while ((rth = *rthp) != NULL) {
+               if (rth->rt_genid != atomic_read(&rt_genid)) {
+                       *rthp = rth->u.dst.rt_next;
+                       rt_free(rth);
+                       continue;
+               }
                if (compare_keys(&rth->fl, &rt->fl) && compare_netns(rth, rt)) {
                        /* Put it first */
                        *rthp = rth->u.dst.rt_next;
@@ -1131,17 +1107,19 @@ void __ip_select_ident(struct iphdr *iph, struct dst_entry *dst, int more)
 
 static void rt_del(unsigned hash, struct rtable *rt)
 {
-       struct rtable **rthp;
+       struct rtable **rthp, *aux;
 
+       rthp = &rt_hash_table[hash].chain;
        spin_lock_bh(rt_hash_lock_addr(hash));
        ip_rt_put(rt);
-       for (rthp = &rt_hash_table[hash].chain; *rthp;
-            rthp = &(*rthp)->u.dst.rt_next)
-               if (*rthp == rt) {
-                       *rthp = rt->u.dst.rt_next;
-                       rt_free(rt);
-                       break;
+       while ((aux = *rthp) != NULL) {
+               if (aux == rt || (aux->rt_genid != atomic_read(&rt_genid))) {
+                       *rthp = aux->u.dst.rt_next;
+                       rt_free(aux);
+                       continue;
                }
+               rthp = &aux->u.dst.rt_next;
+       }
        spin_unlock_bh(rt_hash_lock_addr(hash));
 }
 
@@ -1186,7 +1164,8 @@ void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw,
                                if (rth->fl.fl4_dst != daddr ||
                                    rth->fl.fl4_src != skeys[i] ||
                                    rth->fl.oif != ikeys[k] ||
-                                   rth->fl.iif != 0) {
+                                   rth->fl.iif != 0 ||
+                                   rth->rt_genid != atomic_read(&rt_genid)) {
                                        rthp = &rth->u.dst.rt_next;
                                        continue;
                                }
@@ -1224,7 +1203,7 @@ void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw,
                                rt->u.dst.neighbour     = NULL;
                                rt->u.dst.hh            = NULL;
                                rt->u.dst.xfrm          = NULL;
-
+                               rt->rt_genid            = atomic_read(&rt_genid);
                                rt->rt_flags            |= RTCF_REDIRECTED;
 
                                /* Gateway is different ... */
@@ -1445,7 +1424,8 @@ unsigned short ip_rt_frag_needed(struct net *net, struct iphdr *iph,
                            rth->rt_src  == iph->saddr &&
                            rth->fl.iif == 0 &&
                            !(dst_metric_locked(&rth->u.dst, RTAX_MTU)) &&
-                           rth->u.dst.dev->nd_net == net) {
+                           rth->u.dst.dev->nd_net == net &&
+                           rth->rt_genid == atomic_read(&rt_genid)) {
                                unsigned short mtu = new_mtu;
 
                                if (new_mtu < 68 || new_mtu >= old_mtu) {
@@ -1680,8 +1660,9 @@ static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr,
        rth->fl.oif     = 0;
        rth->rt_gateway = daddr;
        rth->rt_spec_dst= spec_dst;
-       rth->rt_type    = RTN_MULTICAST;
+       rth->rt_genid   = atomic_read(&rt_genid);
        rth->rt_flags   = RTCF_MULTICAST;
+       rth->rt_type    = RTN_MULTICAST;
        if (our) {
                rth->u.dst.input= ip_local_deliver;
                rth->rt_flags |= RTCF_LOCAL;
@@ -1820,6 +1801,7 @@ static inline int __mkroute_input(struct sk_buff *skb,
 
        rth->u.dst.input = ip_forward;
        rth->u.dst.output = ip_output;
+       rth->rt_genid = atomic_read(&rt_genid);
 
        rt_set_nexthop(rth, res, itag);
 
@@ -1980,6 +1962,7 @@ local_input:
                goto e_nobufs;
 
        rth->u.dst.output= ip_rt_bug;
+       rth->rt_genid = atomic_read(&rt_genid);
 
        atomic_set(&rth->u.dst.__refcnt, 1);
        rth->u.dst.flags= DST_HOST;
@@ -2071,7 +2054,8 @@ int ip_route_input(struct sk_buff *skb, __be32 daddr, __be32 saddr,
                    rth->fl.oif == 0 &&
                    rth->fl.mark == skb->mark &&
                    rth->fl.fl4_tos == tos &&
-                   rth->u.dst.dev->nd_net == net) {
+                   rth->u.dst.dev->nd_net == net &&
+                   rth->rt_genid == atomic_read(&rt_genid)) {
                        dst_use(&rth->u.dst, jiffies);
                        RT_CACHE_STAT_INC(in_hit);
                        rcu_read_unlock();
@@ -2199,6 +2183,7 @@ static inline int __mkroute_output(struct rtable **result,
        rth->rt_spec_dst= fl->fl4_src;
 
        rth->u.dst.output=ip_output;
+       rth->rt_genid = atomic_read(&rt_genid);
 
        RT_CACHE_STAT_INC(out_slow_tot);
 
@@ -2471,7 +2456,8 @@ int __ip_route_output_key(struct net *net, struct rtable **rp,
                    rth->fl.mark == flp->mark &&
                    !((rth->fl.fl4_tos ^ flp->fl4_tos) &
                            (IPTOS_RT_MASK | RTO_ONLINK)) &&
-                   rth->u.dst.dev->nd_net == net) {
+                   rth->u.dst.dev->nd_net == net &&
+                   rth->rt_genid == atomic_read(&rt_genid)) {
                        dst_use(&rth->u.dst, jiffies);
                        RT_CACHE_STAT_INC(out_hit);
                        rcu_read_unlock_bh();
@@ -2498,6 +2484,7 @@ static struct dst_ops ipv4_dst_blackhole_ops = {
        .check                  =       ipv4_dst_check,
        .update_pmtu            =       ipv4_rt_blackhole_update_pmtu,
        .entry_size             =       sizeof(struct rtable),
+       .entries                =       ATOMIC_INIT(0),
 };
 
 
@@ -2525,6 +2512,7 @@ static int ipv4_dst_blackhole(struct rtable **rp, struct flowi *flp, struct sock
                rt->idev = ort->idev;
                if (rt->idev)
                        in_dev_hold(rt->idev);
+               rt->rt_genid = atomic_read(&rt_genid);
                rt->rt_flags = ort->rt_flags;
                rt->rt_type = ort->rt_type;
                rt->rt_dst = ort->rt_dst;
@@ -2779,6 +2767,8 @@ int ip_rt_dump(struct sk_buff *skb,  struct netlink_callback *cb)
                     rt = rcu_dereference(rt->u.dst.rt_next), idx++) {
                        if (idx < s_idx)
                                continue;
+                       if (rt->rt_genid != atomic_read(&rt_genid))
+                               continue;
                        skb->dst = dst_clone(&rt->u.dst);
                        if (rt_fill_info(skb, NETLINK_CB(cb->skb).pid,
                                         cb->nlh->nlmsg_seq, RTM_NEWROUTE,
@@ -2847,24 +2837,6 @@ ctl_table ipv4_route_table[] = {
                .proc_handler   = &ipv4_sysctl_rtcache_flush,
                .strategy       = &ipv4_sysctl_rtcache_flush_strategy,
        },
-       {
-               .ctl_name       = NET_IPV4_ROUTE_MIN_DELAY,
-               .procname       = "min_delay",
-               .data           = &ip_rt_min_delay,
-               .maxlen         = sizeof(int),
-               .mode           = 0644,
-               .proc_handler   = &proc_dointvec_jiffies,
-               .strategy       = &sysctl_jiffies,
-       },
-       {
-               .ctl_name       = NET_IPV4_ROUTE_MAX_DELAY,
-               .procname       = "max_delay",
-               .data           = &ip_rt_max_delay,
-               .maxlen         = sizeof(int),
-               .mode           = 0644,
-               .proc_handler   = &proc_dointvec_jiffies,
-               .strategy       = &sysctl_jiffies,
-       },
        {
                .ctl_name       = NET_IPV4_ROUTE_GC_THRESH,
                .procname       = "gc_thresh",
@@ -3023,8 +2995,8 @@ int __init ip_rt_init(void)
 {
        int rc = 0;
 
-       rt_hash_rnd = (int) ((num_physpages ^ (num_physpages>>8)) ^
-                            (jiffies ^ (jiffies >> 7)));
+       atomic_set(&rt_genid, (int) ((num_physpages ^ (num_physpages>>8)) ^
+                            (jiffies ^ (jiffies >> 7))));
 
 #ifdef CONFIG_NET_CLS_ROUTE
        ip_rt_acct = __alloc_percpu(256 * sizeof(struct ip_rt_acct));
@@ -3057,7 +3029,6 @@ int __init ip_rt_init(void)
        devinet_init();
        ip_fib_init();
 
-       setup_timer(&rt_flush_timer, rt_run_flush, 0);
        setup_timer(&rt_secret_timer, rt_secret_rebuild, 0);
 
        /* All the timers, started at system startup tend
index 82cdf23837e3e8b9766ba5f7dbb28634a20c2675..88286f35d1e266ec6aad248c5328d17891cdcc0c 100644 (file)
@@ -185,7 +185,7 @@ static int strategy_allowed_congestion_control(ctl_table *table, int __user *nam
 
        tcp_get_available_congestion_control(tbl.data, tbl.maxlen);
        ret = sysctl_string(&tbl, name, nlen, oldval, oldlenp, newval, newlen);
-       if (ret == 0 && newval && newlen)
+       if (ret == 1 && newval && newlen)
                ret = tcp_set_allowed_congestion_control(tbl.data);
        kfree(tbl.data);
 
index a0d373bd906588276f2f8eef8aaab93a31d1fb31..071e83a894ad9c02081f24b9ba243c77f7ea8d7c 100644 (file)
@@ -1669,7 +1669,7 @@ void tcp_set_state(struct sock *sk, int state)
                sk->sk_prot->unhash(sk);
                if (inet_csk(sk)->icsk_bind_hash &&
                    !(sk->sk_userlocks & SOCK_BINDPORT_LOCK))
-                       inet_put_port(&tcp_hashinfo, sk);
+                       inet_put_port(sk);
                /* fall through */
        default:
                if (oldstate==TCP_ESTABLISHED)
index fa2c85ca5bc39c32947f499ef6f531d840cc925e..19c449f62672d7cf41f03a65f6d6dbc0cc3b3c04 100644 (file)
@@ -2153,7 +2153,7 @@ static void tcp_mark_head_lost(struct sock *sk, int packets, int fast_rexmit)
                tp->lost_skb_hint = skb;
                tp->lost_cnt_hint = cnt;
 
-               if (tcp_is_fack(tp) ||
+               if (tcp_is_fack(tp) || tcp_is_reno(tp) ||
                    (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_ACKED))
                        cnt += tcp_skb_pcount(skb);
 
index 9aea88b8d4fc6a9b5dd9f12c0160129770f47011..63414ea427c578d9a9b1cb527cd87e4cc53ef5f3 100644 (file)
@@ -108,22 +108,6 @@ struct inet_hashinfo __cacheline_aligned tcp_hashinfo = {
        .lhash_wait  = __WAIT_QUEUE_HEAD_INITIALIZER(tcp_hashinfo.lhash_wait),
 };
 
-static int tcp_v4_get_port(struct sock *sk, unsigned short snum)
-{
-       return inet_csk_get_port(&tcp_hashinfo, sk, snum,
-                                inet_csk_bind_conflict);
-}
-
-static void tcp_v4_hash(struct sock *sk)
-{
-       inet_hash(&tcp_hashinfo, sk);
-}
-
-void tcp_unhash(struct sock *sk)
-{
-       inet_unhash(&tcp_hashinfo, sk);
-}
-
 static inline __u32 tcp_v4_init_sequence(struct sk_buff *skb)
 {
        return secure_tcp_sequence_number(ip_hdr(skb)->daddr,
@@ -369,8 +353,8 @@ void tcp_v4_err(struct sk_buff *skb, u32 info)
                return;
        }
 
-       sk = inet_lookup(&tcp_hashinfo, iph->daddr, th->dest, iph->saddr,
-                        th->source, inet_iif(skb));
+       sk = inet_lookup(skb->dev->nd_net, &tcp_hashinfo, iph->daddr, th->dest,
+                       iph->saddr, th->source, inet_iif(skb));
        if (!sk) {
                ICMP_INC_STATS_BH(ICMP_MIB_INERRORS);
                return;
@@ -1478,8 +1462,8 @@ struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
        }
 #endif
 
-       __inet_hash_nolisten(&tcp_hashinfo, newsk);
-       __inet_inherit_port(&tcp_hashinfo, sk, newsk);
+       __inet_hash_nolisten(newsk);
+       __inet_inherit_port(sk, newsk);
 
        return newsk;
 
@@ -1503,8 +1487,8 @@ static struct sock *tcp_v4_hnd_req(struct sock *sk, struct sk_buff *skb)
        if (req)
                return tcp_check_req(sk, skb, req, prev);
 
-       nsk = inet_lookup_established(&tcp_hashinfo, iph->saddr, th->source,
-                                     iph->daddr, th->dest, inet_iif(skb));
+       nsk = inet_lookup_established(sk->sk_net, &tcp_hashinfo, iph->saddr,
+                       th->source, iph->daddr, th->dest, inet_iif(skb));
 
        if (nsk) {
                if (nsk->sk_state != TCP_TIME_WAIT) {
@@ -1661,8 +1645,8 @@ int tcp_v4_rcv(struct sk_buff *skb)
        TCP_SKB_CB(skb)->flags   = iph->tos;
        TCP_SKB_CB(skb)->sacked  = 0;
 
-       sk = __inet_lookup(&tcp_hashinfo, iph->saddr, th->source,
-                          iph->daddr, th->dest, inet_iif(skb));
+       sk = __inet_lookup(skb->dev->nd_net, &tcp_hashinfo, iph->saddr,
+                       th->source, iph->daddr, th->dest, inet_iif(skb));
        if (!sk)
                goto no_tcp_socket;
 
@@ -1735,7 +1719,8 @@ do_time_wait:
        }
        switch (tcp_timewait_state_process(inet_twsk(sk), skb, th)) {
        case TCP_TW_SYN: {
-               struct sock *sk2 = inet_lookup_listener(&tcp_hashinfo,
+               struct sock *sk2 = inet_lookup_listener(skb->dev->nd_net,
+                                                       &tcp_hashinfo,
                                                        iph->daddr, th->dest,
                                                        inet_iif(skb));
                if (sk2) {
@@ -1826,6 +1811,7 @@ struct inet_connection_sock_af_ops ipv4_specific = {
        .getsockopt        = ip_getsockopt,
        .addr2sockaddr     = inet_csk_addr2sockaddr,
        .sockaddr_len      = sizeof(struct sockaddr_in),
+       .bind_conflict     = inet_csk_bind_conflict,
 #ifdef CONFIG_COMPAT
        .compat_setsockopt = compat_ip_setsockopt,
        .compat_getsockopt = compat_ip_getsockopt,
@@ -1925,7 +1911,7 @@ int tcp_v4_destroy_sock(struct sock *sk)
 
        /* Clean up a referenced TCP bind bucket. */
        if (inet_csk(sk)->icsk_bind_hash)
-               inet_put_port(&tcp_hashinfo, sk);
+               inet_put_port(sk);
 
        /*
         * If sendmsg cached page exists, toss it.
@@ -2434,9 +2420,9 @@ struct proto tcp_prot = {
        .getsockopt             = tcp_getsockopt,
        .recvmsg                = tcp_recvmsg,
        .backlog_rcv            = tcp_v4_do_rcv,
-       .hash                   = tcp_v4_hash,
-       .unhash                 = tcp_unhash,
-       .get_port               = tcp_v4_get_port,
+       .hash                   = inet_hash,
+       .unhash                 = inet_unhash,
+       .get_port               = inet_csk_get_port,
        .enter_memory_pressure  = tcp_enter_memory_pressure,
        .sockets_allocated      = &tcp_sockets_allocated,
        .orphan_count           = &tcp_orphan_count,
@@ -2449,6 +2435,7 @@ struct proto tcp_prot = {
        .obj_size               = sizeof(struct tcp_sock),
        .twsk_prot              = &tcp_timewait_sock_ops,
        .rsk_prot               = &tcp_request_sock_ops,
+       .hashinfo               = &tcp_hashinfo,
 #ifdef CONFIG_COMPAT
        .compat_setsockopt      = compat_tcp_setsockopt,
        .compat_getsockopt      = compat_tcp_getsockopt,
@@ -2466,7 +2453,6 @@ void __init tcp_v4_init(struct net_proto_family *ops)
 EXPORT_SYMBOL(ipv4_specific);
 EXPORT_SYMBOL(tcp_hashinfo);
 EXPORT_SYMBOL(tcp_prot);
-EXPORT_SYMBOL(tcp_unhash);
 EXPORT_SYMBOL(tcp_v4_conn_request);
 EXPORT_SYMBOL(tcp_v4_connect);
 EXPORT_SYMBOL(tcp_v4_do_rcv);
index 89f0188885c7e1962f2916d4f4084faf22063701..ed750f9ceb07caed9ed5479740e664c6a319bc8f 100644 (file)
@@ -2564,5 +2564,4 @@ EXPORT_SYMBOL(tcp_connect);
 EXPORT_SYMBOL(tcp_make_synack);
 EXPORT_SYMBOL(tcp_simple_retransmit);
 EXPORT_SYMBOL(tcp_sync_mss);
-EXPORT_SYMBOL(sysctl_tcp_tso_win_divisor);
 EXPORT_SYMBOL(tcp_mtup_init);
index 2fb8d731026b7c325288a4966e7f6f08a95392a8..7ea1b67b6de1cccbbc5d4332ef45df04578b8aae 100644 (file)
@@ -130,14 +130,14 @@ EXPORT_SYMBOL(sysctl_udp_wmem_min);
 atomic_t udp_memory_allocated;
 EXPORT_SYMBOL(udp_memory_allocated);
 
-static inline int __udp_lib_lport_inuse(__u16 num,
+static inline int __udp_lib_lport_inuse(struct net *net, __u16 num,
                                        const struct hlist_head udptable[])
 {
        struct sock *sk;
        struct hlist_node *node;
 
        sk_for_each(sk, node, &udptable[num & (UDP_HTABLE_SIZE - 1)])
-               if (sk->sk_hash == num)
+               if (sk->sk_net == net && sk->sk_hash == num)
                        return 1;
        return 0;
 }
@@ -159,6 +159,7 @@ int __udp_lib_get_port(struct sock *sk, unsigned short snum,
        struct hlist_head *head;
        struct sock *sk2;
        int    error = 1;
+       struct net *net = sk->sk_net;
 
        write_lock_bh(&udp_hash_lock);
 
@@ -198,7 +199,7 @@ int __udp_lib_get_port(struct sock *sk, unsigned short snum,
                /* 2nd pass: find hole in shortest hash chain */
                rover = best;
                for (i = 0; i < (1 << 16) / UDP_HTABLE_SIZE; i++) {
-                       if (! __udp_lib_lport_inuse(rover, udptable))
+                       if (! __udp_lib_lport_inuse(net, rover, udptable))
                                goto gotit;
                        rover += UDP_HTABLE_SIZE;
                        if (rover > high)
@@ -218,6 +219,7 @@ gotit:
                sk_for_each(sk2, node, head)
                        if (sk2->sk_hash == snum                             &&
                            sk2 != sk                                        &&
+                           sk2->sk_net == net                               &&
                            (!sk2->sk_reuse        || !sk->sk_reuse)         &&
                            (!sk2->sk_bound_dev_if || !sk->sk_bound_dev_if
                             || sk2->sk_bound_dev_if == sk->sk_bound_dev_if) &&
@@ -261,9 +263,9 @@ static inline int udp_v4_get_port(struct sock *sk, unsigned short snum)
 /* UDP is nearly always wildcards out the wazoo, it makes no sense to try
  * harder than this. -DaveM
  */
-static struct sock *__udp4_lib_lookup(__be32 saddr, __be16 sport,
-                                     __be32 daddr, __be16 dport,
-                                     int dif, struct hlist_head udptable[])
+static struct sock *__udp4_lib_lookup(struct net *net, __be32 saddr,
+               __be16 sport, __be32 daddr, __be16 dport,
+               int dif, struct hlist_head udptable[])
 {
        struct sock *sk, *result = NULL;
        struct hlist_node *node;
@@ -274,7 +276,8 @@ static struct sock *__udp4_lib_lookup(__be32 saddr, __be16 sport,
        sk_for_each(sk, node, &udptable[hnum & (UDP_HTABLE_SIZE - 1)]) {
                struct inet_sock *inet = inet_sk(sk);
 
-               if (sk->sk_hash == hnum && !ipv6_only_sock(sk)) {
+               if (sk->sk_net == net && sk->sk_hash == hnum &&
+                               !ipv6_only_sock(sk)) {
                        int score = (sk->sk_family == PF_INET ? 1 : 0);
                        if (inet->rcv_saddr) {
                                if (inet->rcv_saddr != daddr)
@@ -361,8 +364,8 @@ void __udp4_lib_err(struct sk_buff *skb, u32 info, struct hlist_head udptable[])
        int harderr;
        int err;
 
-       sk = __udp4_lib_lookup(iph->daddr, uh->dest, iph->saddr, uh->source,
-                              skb->dev->ifindex, udptable                  );
+       sk = __udp4_lib_lookup(skb->dev->nd_net, iph->daddr, uh->dest,
+                       iph->saddr, uh->source, skb->dev->ifindex, udptable);
        if (sk == NULL) {
                ICMP_INC_STATS_BH(ICMP_MIB_INERRORS);
                return; /* No socket for error */
@@ -1185,8 +1188,8 @@ int __udp4_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[],
        if (rt->rt_flags & (RTCF_BROADCAST|RTCF_MULTICAST))
                return __udp4_lib_mcast_deliver(skb, uh, saddr, daddr, udptable);
 
-       sk = __udp4_lib_lookup(saddr, uh->source, daddr, uh->dest,
-                              inet_iif(skb), udptable);
+       sk = __udp4_lib_lookup(skb->dev->nd_net, saddr, uh->source, daddr,
+                       uh->dest, inet_iif(skb), udptable);
 
        if (sk != NULL) {
                int ret = 0;
index e093a7b59e18af38cf918aed2754159cf68db8fd..b47030ba162bc97df715d11fc779f59df1db16e5 100644 (file)
@@ -102,7 +102,7 @@ static int xfrm4_beet_input(struct xfrm_state *x, struct sk_buff *skb)
 
                XFRM_MODE_SKB_CB(skb)->protocol = ph->nexthdr;
 
-               if (!pskb_may_pull(skb, phlen));
+               if (!pskb_may_pull(skb, phlen))
                        goto out;
                __skb_pull(skb, phlen);
        }
index 3783e3ee56a424f185beb18c38a7cf00cb11c24f..10ed70491434fe9240445ae71cff6c46259e9d74 100644 (file)
@@ -247,6 +247,7 @@ static struct dst_ops xfrm4_dst_ops = {
        .local_out =            __ip_local_out,
        .gc_thresh =            1024,
        .entry_size =           sizeof(struct xfrm_dst),
+       .entries =              ATOMIC_INIT(0),
 };
 
 static struct xfrm_policy_afinfo xfrm4_policy_afinfo = {
index 326845195620dd07851907fdf03d65cadb0be220..41f5982d20876ecb7ab1df92f5533d451b932ee2 100644 (file)
@@ -38,7 +38,7 @@ static void ipip_destroy(struct xfrm_state *x)
 {
 }
 
-static struct xfrm_type ipip_type = {
+static const struct xfrm_type ipip_type = {
        .description    = "IPIP",
        .owner          = THIS_MODULE,
        .proto          = IPPROTO_IPIP,
@@ -50,7 +50,7 @@ static struct xfrm_type ipip_type = {
 
 static int xfrm_tunnel_rcv(struct sk_buff *skb)
 {
-       return xfrm4_rcv_spi(skb, IPPROTO_IP, ip_hdr(skb)->saddr);
+       return xfrm4_rcv_spi(skb, IPPROTO_IPIP, ip_hdr(skb)->saddr);
 }
 
 static int xfrm_tunnel_err(struct sk_buff *skb, u32 info)
index eb0b8085949b64620241de94be4815a1a303887d..3ffb0323668cc8fe40cba537589f061a68923a6c 100644 (file)
@@ -85,6 +85,7 @@ config INET6_ESP
        depends on IPV6
        select XFRM
        select CRYPTO
+       select CRYPTO_AEAD
        select CRYPTO_HMAC
        select CRYPTO_MD5
        select CRYPTO_CBC
index fb0d07a15e934678c8c91fbfa5bcf0be5718a50a..379c8e04c36c6ccf17e84abf860fd734fb5945be 100644 (file)
@@ -515,7 +515,7 @@ static void ah6_destroy(struct xfrm_state *x)
        kfree(ahp);
 }
 
-static struct xfrm_type ah6_type =
+static const struct xfrm_type ah6_type =
 {
        .description    = "AH6",
        .owner          = THIS_MODULE,
index 5bd5292ad9fa9021cf31899355db8cd60857a165..8e0f1428c7167ac85dbdc0b5e4a33426e9e44a5d 100644 (file)
  *     This file is derived from net/ipv4/esp.c
  */
 
+#include <crypto/aead.h>
+#include <crypto/authenc.h>
 #include <linux/err.h>
 #include <linux/module.h>
 #include <net/ip.h>
 #include <net/xfrm.h>
 #include <net/esp.h>
 #include <linux/scatterlist.h>
-#include <linux/crypto.h>
 #include <linux/kernel.h>
 #include <linux/pfkeyv2.h>
 #include <linux/random.h>
+#include <linux/slab.h>
 #include <linux/spinlock.h>
 #include <net/icmp.h>
 #include <net/ipv6.h>
 #include <net/protocol.h>
 #include <linux/icmpv6.h>
 
+struct esp_skb_cb {
+       struct xfrm_skb_cb xfrm;
+       void *tmp;
+};
+
+#define ESP_SKB_CB(__skb) ((struct esp_skb_cb *)&((__skb)->cb[0]))
+
+/*
+ * Allocate an AEAD request structure with extra space for SG and IV.
+ *
+ * For alignment considerations the IV is placed at the front, followed
+ * by the request and finally the SG list.
+ *
+ * TODO: Use spare space in skb for this where possible.
+ */
+static void *esp_alloc_tmp(struct crypto_aead *aead, int nfrags)
+{
+       unsigned int len;
+
+       len = crypto_aead_ivsize(aead);
+       if (len) {
+               len += crypto_aead_alignmask(aead) &
+                      ~(crypto_tfm_ctx_alignment() - 1);
+               len = ALIGN(len, crypto_tfm_ctx_alignment());
+       }
+
+       len += sizeof(struct aead_givcrypt_request) + crypto_aead_reqsize(aead);
+       len = ALIGN(len, __alignof__(struct scatterlist));
+
+       len += sizeof(struct scatterlist) * nfrags;
+
+       return kmalloc(len, GFP_ATOMIC);
+}
+
+static inline u8 *esp_tmp_iv(struct crypto_aead *aead, void *tmp)
+{
+       return crypto_aead_ivsize(aead) ?
+              PTR_ALIGN((u8 *)tmp, crypto_aead_alignmask(aead) + 1) : tmp;
+}
+
+static inline struct aead_givcrypt_request *esp_tmp_givreq(
+       struct crypto_aead *aead, u8 *iv)
+{
+       struct aead_givcrypt_request *req;
+
+       req = (void *)PTR_ALIGN(iv + crypto_aead_ivsize(aead),
+                               crypto_tfm_ctx_alignment());
+       aead_givcrypt_set_tfm(req, aead);
+       return req;
+}
+
+static inline struct aead_request *esp_tmp_req(struct crypto_aead *aead, u8 *iv)
+{
+       struct aead_request *req;
+
+       req = (void *)PTR_ALIGN(iv + crypto_aead_ivsize(aead),
+                               crypto_tfm_ctx_alignment());
+       aead_request_set_tfm(req, aead);
+       return req;
+}
+
+static inline struct scatterlist *esp_req_sg(struct crypto_aead *aead,
+                                            struct aead_request *req)
+{
+       return (void *)ALIGN((unsigned long)(req + 1) +
+                            crypto_aead_reqsize(aead),
+                            __alignof__(struct scatterlist));
+}
+
+static inline struct scatterlist *esp_givreq_sg(
+       struct crypto_aead *aead, struct aead_givcrypt_request *req)
+{
+       return (void *)ALIGN((unsigned long)(req + 1) +
+                            crypto_aead_reqsize(aead),
+                            __alignof__(struct scatterlist));
+}
+
+static void esp_output_done(struct crypto_async_request *base, int err)
+{
+       struct sk_buff *skb = base->data;
+
+       kfree(ESP_SKB_CB(skb)->tmp);
+       xfrm_output_resume(skb, err);
+}
+
 static int esp6_output(struct xfrm_state *x, struct sk_buff *skb)
 {
        int err;
        struct ip_esp_hdr *esph;
-       struct crypto_blkcipher *tfm;
-       struct blkcipher_desc desc;
+       struct crypto_aead *aead;
+       struct aead_givcrypt_request *req;
+       struct scatterlist *sg;
+       struct scatterlist *asg;
        struct sk_buff *trailer;
+       void *tmp;
        int blksize;
        int clen;
        int alen;
        int nfrags;
+       u8 *iv;
        u8 *tail;
        struct esp_data *esp = x->data;
 
@@ -60,18 +151,26 @@ static int esp6_output(struct xfrm_state *x, struct sk_buff *skb)
        /* Round to block size */
        clen = skb->len;
 
-       alen = esp->auth.icv_trunc_len;
-       tfm = esp->conf.tfm;
-       desc.tfm = tfm;
-       desc.flags = 0;
-       blksize = ALIGN(crypto_blkcipher_blocksize(tfm), 4);
+       aead = esp->aead;
+       alen = crypto_aead_authsize(aead);
+
+       blksize = ALIGN(crypto_aead_blocksize(aead), 4);
        clen = ALIGN(clen + 2, blksize);
-       if (esp->conf.padlen)
-               clen = ALIGN(clen, esp->conf.padlen);
+       if (esp->padlen)
+               clen = ALIGN(clen, esp->padlen);
 
-       if ((nfrags = skb_cow_data(skb, clen-skb->len+alen, &trailer)) < 0) {
+       if ((err = skb_cow_data(skb, clen - skb->len + alen, &trailer)) < 0)
                goto error;
-       }
+       nfrags = err;
+
+       tmp = esp_alloc_tmp(aead, nfrags + 1);
+       if (!tmp)
+               goto error;
+
+       iv = esp_tmp_iv(aead, tmp);
+       req = esp_tmp_givreq(aead, iv);
+       asg = esp_givreq_sg(aead, req);
+       sg = asg + 1;
 
        /* Fill padding... */
        tail = skb_tail_pointer(trailer);
@@ -81,86 +180,113 @@ static int esp6_output(struct xfrm_state *x, struct sk_buff *skb)
                        tail[i] = i + 1;
        } while (0);
        tail[clen-skb->len - 2] = (clen - skb->len) - 2;
-       pskb_put(skb, trailer, clen - skb->len);
+       tail[clen - skb->len - 1] = *skb_mac_header(skb);
+       pskb_put(skb, trailer, clen - skb->len + alen);
 
        skb_push(skb, -skb_network_offset(skb));
        esph = ip_esp_hdr(skb);
-       *(skb_tail_pointer(trailer) - 1) = *skb_mac_header(skb);
        *skb_mac_header(skb) = IPPROTO_ESP;
 
        esph->spi = x->id.spi;
        esph->seq_no = htonl(XFRM_SKB_CB(skb)->seq);
 
-       spin_lock_bh(&x->lock);
+       sg_init_table(sg, nfrags);
+       skb_to_sgvec(skb, sg,
+                    esph->enc_data + crypto_aead_ivsize(aead) - skb->data,
+                    clen + alen);
+       sg_init_one(asg, esph, sizeof(*esph));
 
-       if (esp->conf.ivlen) {
-               if (unlikely(!esp->conf.ivinitted)) {
-                       get_random_bytes(esp->conf.ivec, esp->conf.ivlen);
-                       esp->conf.ivinitted = 1;
-               }
-               crypto_blkcipher_set_iv(tfm, esp->conf.ivec, esp->conf.ivlen);
-       }
+       aead_givcrypt_set_callback(req, 0, esp_output_done, skb);
+       aead_givcrypt_set_crypt(req, sg, sg, clen, iv);
+       aead_givcrypt_set_assoc(req, asg, sizeof(*esph));
+       aead_givcrypt_set_giv(req, esph->enc_data, XFRM_SKB_CB(skb)->seq);
 
-       do {
-               struct scatterlist *sg = &esp->sgbuf[0];
+       ESP_SKB_CB(skb)->tmp = tmp;
+       err = crypto_aead_givencrypt(req);
+       if (err == -EINPROGRESS)
+               goto error;
 
-               if (unlikely(nfrags > ESP_NUM_FAST_SG)) {
-                       sg = kmalloc(sizeof(struct scatterlist)*nfrags, GFP_ATOMIC);
-                       if (!sg)
-                               goto unlock;
-               }
-               sg_init_table(sg, nfrags);
-               skb_to_sgvec(skb, sg,
-                            esph->enc_data +
-                            esp->conf.ivlen -
-                            skb->data, clen);
-               err = crypto_blkcipher_encrypt(&desc, sg, sg, clen);
-               if (unlikely(sg != &esp->sgbuf[0]))
-                       kfree(sg);
-       } while (0);
+       if (err == -EBUSY)
+               err = NET_XMIT_DROP;
+
+       kfree(tmp);
+
+error:
+       return err;
+}
+
+static int esp_input_done2(struct sk_buff *skb, int err)
+{
+       struct xfrm_state *x = xfrm_input_state(skb);
+       struct esp_data *esp = x->data;
+       struct crypto_aead *aead = esp->aead;
+       int alen = crypto_aead_authsize(aead);
+       int hlen = sizeof(struct ip_esp_hdr) + crypto_aead_ivsize(aead);
+       int elen = skb->len - hlen;
+       int hdr_len = skb_network_header_len(skb);
+       int padlen;
+       u8 nexthdr[2];
+
+       kfree(ESP_SKB_CB(skb)->tmp);
 
        if (unlikely(err))
-               goto unlock;
+               goto out;
 
-       if (esp->conf.ivlen) {
-               memcpy(esph->enc_data, esp->conf.ivec, esp->conf.ivlen);
-               crypto_blkcipher_get_iv(tfm, esp->conf.ivec, esp->conf.ivlen);
-       }
+       if (skb_copy_bits(skb, skb->len - alen - 2, nexthdr, 2))
+               BUG();
 
-       if (esp->auth.icv_full_len) {
-               err = esp_mac_digest(esp, skb, (u8 *)esph - skb->data,
-                                    sizeof(*esph) + esp->conf.ivlen + clen);
-               memcpy(pskb_put(skb, trailer, alen), esp->auth.work_icv, alen);
+       err = -EINVAL;
+       padlen = nexthdr[0];
+       if (padlen + 2 + alen >= elen) {
+               LIMIT_NETDEBUG(KERN_WARNING "ipsec esp packet is garbage "
+                              "padlen=%d, elen=%d\n", padlen + 2, elen - alen);
+               goto out;
        }
 
-unlock:
-       spin_unlock_bh(&x->lock);
+       /* ... check padding bits here. Silly. :-) */
 
-error:
+       pskb_trim(skb, skb->len - alen - padlen - 2);
+       __skb_pull(skb, hlen);
+       skb_set_transport_header(skb, -hdr_len);
+
+       err = nexthdr[1];
+
+       /* RFC4303: Drop dummy packets without any error */
+       if (err == IPPROTO_NONE)
+               err = -EINVAL;
+
+out:
        return err;
 }
 
+static void esp_input_done(struct crypto_async_request *base, int err)
+{
+       struct sk_buff *skb = base->data;
+
+       xfrm_input_resume(skb, esp_input_done2(skb, err));
+}
+
 static int esp6_input(struct xfrm_state *x, struct sk_buff *skb)
 {
-       struct ipv6hdr *iph;
        struct ip_esp_hdr *esph;
        struct esp_data *esp = x->data;
-       struct crypto_blkcipher *tfm = esp->conf.tfm;
-       struct blkcipher_desc desc = { .tfm = tfm };
+       struct crypto_aead *aead = esp->aead;
+       struct aead_request *req;
        struct sk_buff *trailer;
-       int blksize = ALIGN(crypto_blkcipher_blocksize(tfm), 4);
-       int alen = esp->auth.icv_trunc_len;
-       int elen = skb->len - sizeof(*esph) - esp->conf.ivlen - alen;
-       int hdr_len = skb_network_header_len(skb);
+       int elen = skb->len - sizeof(*esph) - crypto_aead_ivsize(aead);
        int nfrags;
        int ret = 0;
+       void *tmp;
+       u8 *iv;
+       struct scatterlist *sg;
+       struct scatterlist *asg;
 
        if (!pskb_may_pull(skb, sizeof(*esph))) {
                ret = -EINVAL;
                goto out;
        }
 
-       if (elen <= 0 || (elen & (blksize-1))) {
+       if (elen <= 0) {
                ret = -EINVAL;
                goto out;
        }
@@ -170,86 +296,38 @@ static int esp6_input(struct xfrm_state *x, struct sk_buff *skb)
                goto out;
        }
 
-       skb->ip_summed = CHECKSUM_NONE;
-
-       spin_lock(&x->lock);
-
-       /* If integrity check is required, do this. */
-       if (esp->auth.icv_full_len) {
-               u8 sum[alen];
-
-               ret = esp_mac_digest(esp, skb, 0, skb->len - alen);
-               if (ret)
-                       goto unlock;
+       ret = -ENOMEM;
+       tmp = esp_alloc_tmp(aead, nfrags + 1);
+       if (!tmp)
+               goto out;
 
-               if (skb_copy_bits(skb, skb->len - alen, sum, alen))
-                       BUG();
+       ESP_SKB_CB(skb)->tmp = tmp;
+       iv = esp_tmp_iv(aead, tmp);
+       req = esp_tmp_req(aead, iv);
+       asg = esp_req_sg(aead, req);
+       sg = asg + 1;
 
-               if (unlikely(memcmp(esp->auth.work_icv, sum, alen))) {
-                       ret = -EBADMSG;
-                       goto unlock;
-               }
-       }
+       skb->ip_summed = CHECKSUM_NONE;
 
        esph = (struct ip_esp_hdr *)skb->data;
-       iph = ipv6_hdr(skb);
 
        /* Get ivec. This can be wrong, check against another impls. */
-       if (esp->conf.ivlen)
-               crypto_blkcipher_set_iv(tfm, esph->enc_data, esp->conf.ivlen);
-
-       {
-               struct scatterlist *sg = &esp->sgbuf[0];
-
-               if (unlikely(nfrags > ESP_NUM_FAST_SG)) {
-                       sg = kmalloc(sizeof(struct scatterlist)*nfrags, GFP_ATOMIC);
-                       if (!sg) {
-                               ret = -ENOMEM;
-                               goto unlock;
-                       }
-               }
-               sg_init_table(sg, nfrags);
-               skb_to_sgvec(skb, sg,
-                            sizeof(*esph) + esp->conf.ivlen,
-                            elen);
-               ret = crypto_blkcipher_decrypt(&desc, sg, sg, elen);
-               if (unlikely(sg != &esp->sgbuf[0]))
-                       kfree(sg);
-       }
+       iv = esph->enc_data;
 
-unlock:
-       spin_unlock(&x->lock);
+       sg_init_table(sg, nfrags);
+       skb_to_sgvec(skb, sg, sizeof(*esph) + crypto_aead_ivsize(aead), elen);
+       sg_init_one(asg, esph, sizeof(*esph));
 
-       if (unlikely(ret))
-               goto out;
-
-       {
-               u8 nexthdr[2];
-               u8 padlen;
-
-               if (skb_copy_bits(skb, skb->len-alen-2, nexthdr, 2))
-                       BUG();
-
-               padlen = nexthdr[0];
-               if (padlen+2 >= elen) {
-                       LIMIT_NETDEBUG(KERN_WARNING "ipsec esp packet is garbage padlen=%d, elen=%d\n", padlen+2, elen);
-                       ret = -EINVAL;
-                       goto out;
-               }
-               /* ... check padding bits here. Silly. :-) */
+       aead_request_set_callback(req, 0, esp_input_done, skb);
+       aead_request_set_crypt(req, sg, sg, elen, iv);
+       aead_request_set_assoc(req, asg, sizeof(*esph));
 
-               /* RFC4303: Drop dummy packets without any error */
-               if (nexthdr[1] == IPPROTO_NONE) {
-                       ret = -EINVAL;
-                       goto out;
-               }
+       ret = crypto_aead_decrypt(req);
+       if (ret == -EINPROGRESS)
+               goto out;
 
-               pskb_trim(skb, skb->len - alen - padlen - 2);
-               ret = nexthdr[1];
-       }
+       ret = esp_input_done2(skb, ret);
 
-       __skb_pull(skb, sizeof(*esph) + esp->conf.ivlen);
-       skb_set_transport_header(skb, -hdr_len);
 out:
        return ret;
 }
@@ -257,11 +335,11 @@ out:
 static u32 esp6_get_mtu(struct xfrm_state *x, int mtu)
 {
        struct esp_data *esp = x->data;
-       u32 blksize = ALIGN(crypto_blkcipher_blocksize(esp->conf.tfm), 4);
-       u32 align = max_t(u32, blksize, esp->conf.padlen);
+       u32 blksize = ALIGN(crypto_aead_blocksize(esp->aead), 4);
+       u32 align = max_t(u32, blksize, esp->padlen);
        u32 rem;
 
-       mtu -= x->props.header_len + esp->auth.icv_trunc_len;
+       mtu -= x->props.header_len + crypto_aead_authsize(esp->aead);
        rem = mtu & (align - 1);
        mtu &= ~(align - 1);
 
@@ -300,81 +378,146 @@ static void esp6_destroy(struct xfrm_state *x)
        if (!esp)
                return;
 
-       crypto_free_blkcipher(esp->conf.tfm);
-       esp->conf.tfm = NULL;
-       kfree(esp->conf.ivec);
-       esp->conf.ivec = NULL;
-       crypto_free_hash(esp->auth.tfm);
-       esp->auth.tfm = NULL;
-       kfree(esp->auth.work_icv);
-       esp->auth.work_icv = NULL;
+       crypto_free_aead(esp->aead);
        kfree(esp);
 }
 
-static int esp6_init_state(struct xfrm_state *x)
+static int esp_init_aead(struct xfrm_state *x)
+{
+       struct esp_data *esp = x->data;
+       struct crypto_aead *aead;
+       int err;
+
+       aead = crypto_alloc_aead(x->aead->alg_name, 0, 0);
+       err = PTR_ERR(aead);
+       if (IS_ERR(aead))
+               goto error;
+
+       esp->aead = aead;
+
+       err = crypto_aead_setkey(aead, x->aead->alg_key,
+                                (x->aead->alg_key_len + 7) / 8);
+       if (err)
+               goto error;
+
+       err = crypto_aead_setauthsize(aead, x->aead->alg_icv_len / 8);
+       if (err)
+               goto error;
+
+error:
+       return err;
+}
+
+static int esp_init_authenc(struct xfrm_state *x)
 {
-       struct esp_data *esp = NULL;
-       struct crypto_blkcipher *tfm;
+       struct esp_data *esp = x->data;
+       struct crypto_aead *aead;
+       struct crypto_authenc_key_param *param;
+       struct rtattr *rta;
+       char *key;
+       char *p;
+       char authenc_name[CRYPTO_MAX_ALG_NAME];
+       unsigned int keylen;
+       int err;
 
+       err = -EINVAL;
        if (x->ealg == NULL)
                goto error;
 
-       if (x->encap)
+       err = -ENAMETOOLONG;
+       if (snprintf(authenc_name, CRYPTO_MAX_ALG_NAME, "authenc(%s,%s)",
+                    x->aalg ? x->aalg->alg_name : "digest_null",
+                    x->ealg->alg_name) >= CRYPTO_MAX_ALG_NAME)
                goto error;
 
-       esp = kzalloc(sizeof(*esp), GFP_KERNEL);
-       if (esp == NULL)
-               return -ENOMEM;
+       aead = crypto_alloc_aead(authenc_name, 0, 0);
+       err = PTR_ERR(aead);
+       if (IS_ERR(aead))
+               goto error;
+
+       esp->aead = aead;
+
+       keylen = (x->aalg ? (x->aalg->alg_key_len + 7) / 8 : 0) +
+                (x->ealg->alg_key_len + 7) / 8 + RTA_SPACE(sizeof(*param));
+       err = -ENOMEM;
+       key = kmalloc(keylen, GFP_KERNEL);
+       if (!key)
+               goto error;
+
+       p = key;
+       rta = (void *)p;
+       rta->rta_type = CRYPTO_AUTHENC_KEYA_PARAM;
+       rta->rta_len = RTA_LENGTH(sizeof(*param));
+       param = RTA_DATA(rta);
+       p += RTA_SPACE(sizeof(*param));
 
        if (x->aalg) {
                struct xfrm_algo_desc *aalg_desc;
-               struct crypto_hash *hash;
-
-               hash = crypto_alloc_hash(x->aalg->alg_name, 0,
-                                        CRYPTO_ALG_ASYNC);
-               if (IS_ERR(hash))
-                       goto error;
 
-               esp->auth.tfm = hash;
-               if (crypto_hash_setkey(hash, x->aalg->alg_key,
-                                      (x->aalg->alg_key_len + 7) / 8))
-                       goto error;
+               memcpy(p, x->aalg->alg_key, (x->aalg->alg_key_len + 7) / 8);
+               p += (x->aalg->alg_key_len + 7) / 8;
 
                aalg_desc = xfrm_aalg_get_byname(x->aalg->alg_name, 0);
                BUG_ON(!aalg_desc);
 
+               err = -EINVAL;
                if (aalg_desc->uinfo.auth.icv_fullbits/8 !=
-                   crypto_hash_digestsize(hash)) {
+                   crypto_aead_authsize(aead)) {
                        NETDEBUG(KERN_INFO "ESP: %s digestsize %u != %hu\n",
                                 x->aalg->alg_name,
-                                crypto_hash_digestsize(hash),
+                                crypto_aead_authsize(aead),
                                 aalg_desc->uinfo.auth.icv_fullbits/8);
-                       goto error;
+                       goto free_key;
                }
 
-               esp->auth.icv_full_len = aalg_desc->uinfo.auth.icv_fullbits/8;
-               esp->auth.icv_trunc_len = aalg_desc->uinfo.auth.icv_truncbits/8;
-
-               esp->auth.work_icv = kmalloc(esp->auth.icv_full_len, GFP_KERNEL);
-               if (!esp->auth.work_icv)
-                       goto error;
-       }
-       tfm = crypto_alloc_blkcipher(x->ealg->alg_name, 0, CRYPTO_ALG_ASYNC);
-       if (IS_ERR(tfm))
-               goto error;
-       esp->conf.tfm = tfm;
-       esp->conf.ivlen = crypto_blkcipher_ivsize(tfm);
-       esp->conf.padlen = 0;
-       if (esp->conf.ivlen) {
-               esp->conf.ivec = kmalloc(esp->conf.ivlen, GFP_KERNEL);
-               if (unlikely(esp->conf.ivec == NULL))
-                       goto error;
-               esp->conf.ivinitted = 0;
+               err = crypto_aead_setauthsize(
+                       aead, aalg_desc->uinfo.auth.icv_truncbits / 8);
+               if (err)
+                       goto free_key;
        }
-       if (crypto_blkcipher_setkey(tfm, x->ealg->alg_key,
-                                   (x->ealg->alg_key_len + 7) / 8))
+
+       param->enckeylen = cpu_to_be32((x->ealg->alg_key_len + 7) / 8);
+       memcpy(p, x->ealg->alg_key, (x->ealg->alg_key_len + 7) / 8);
+
+       err = crypto_aead_setkey(aead, key, keylen);
+
+free_key:
+       kfree(key);
+
+error:
+       return err;
+}
+
+static int esp6_init_state(struct xfrm_state *x)
+{
+       struct esp_data *esp;
+       struct crypto_aead *aead;
+       u32 align;
+       int err;
+
+       if (x->encap)
+               return -EINVAL;
+
+       esp = kzalloc(sizeof(*esp), GFP_KERNEL);
+       if (esp == NULL)
+               return -ENOMEM;
+
+       x->data = esp;
+
+       if (x->aead)
+               err = esp_init_aead(x);
+       else
+               err = esp_init_authenc(x);
+
+       if (err)
                goto error;
-       x->props.header_len = sizeof(struct ip_esp_hdr) + esp->conf.ivlen;
+
+       aead = esp->aead;
+
+       esp->padlen = 0;
+
+       x->props.header_len = sizeof(struct ip_esp_hdr) +
+                             crypto_aead_ivsize(aead);
        switch (x->props.mode) {
        case XFRM_MODE_BEET:
        case XFRM_MODE_TRANSPORT:
@@ -385,17 +528,17 @@ static int esp6_init_state(struct xfrm_state *x)
        default:
                goto error;
        }
-       x->data = esp;
-       return 0;
+
+       align = ALIGN(crypto_aead_blocksize(aead), 4);
+       if (esp->padlen)
+               align = max_t(u32, align, esp->padlen);
+       x->props.trailer_len = align + 1 + crypto_aead_authsize(esp->aead);
 
 error:
-       x->data = esp;
-       esp6_destroy(x);
-       x->data = NULL;
-       return -EINVAL;
+       return err;
 }
 
-static struct xfrm_type esp6_type =
+static const struct xfrm_type esp6_type =
 {
        .description    = "ESP6",
        .owner          = THIS_MODULE,
index cbb5b9cf84ad36eba8741bec98cb2409040d3c93..121d517bf91c9d16467c5aa85df47efdd0b6c58e 100644 (file)
@@ -683,7 +683,8 @@ static int icmpv6_rcv(struct sk_buff *skb)
                }
        }
 
-       __skb_pull(skb, sizeof(*hdr));
+       if (!pskb_pull(skb, sizeof(*hdr)))
+               goto discard_it;
 
        hdr = icmp6_hdr(skb);
 
index a66a7d8e281133f7f8a6000cf482b35bfe5c4cd9..99fd25f7f005879ec28b78b6af51890c7abb5fd8 100644 (file)
@@ -22,9 +22,9 @@
 #include <net/inet6_hashtables.h>
 #include <net/ip.h>
 
-void __inet6_hash(struct inet_hashinfo *hashinfo,
-                               struct sock *sk)
+void __inet6_hash(struct sock *sk)
 {
+       struct inet_hashinfo *hashinfo = sk->sk_prot->hashinfo;
        struct hlist_head *list;
        rwlock_t *lock;
 
@@ -54,7 +54,8 @@ EXPORT_SYMBOL(__inet6_hash);
  *
  * The sockhash lock must be held as a reader here.
  */
-struct sock *__inet6_lookup_established(struct inet_hashinfo *hashinfo,
+struct sock *__inet6_lookup_established(struct net *net,
+                                       struct inet_hashinfo *hashinfo,
                                           const struct in6_addr *saddr,
                                           const __be16 sport,
                                           const struct in6_addr *daddr,
@@ -75,22 +76,13 @@ struct sock *__inet6_lookup_established(struct inet_hashinfo *hashinfo,
        read_lock(lock);
        sk_for_each(sk, node, &head->chain) {
                /* For IPV6 do the cheaper port and family tests first. */
-               if (INET6_MATCH(sk, hash, saddr, daddr, ports, dif))
+               if (INET6_MATCH(sk, net, hash, saddr, daddr, ports, dif))
                        goto hit; /* You sunk my battleship! */
        }
        /* Must check for a TIME_WAIT'er before going to listener hash. */
        sk_for_each(sk, node, &head->twchain) {
-               const struct inet_timewait_sock *tw = inet_twsk(sk);
-
-               if(*((__portpair *)&(tw->tw_dport))     == ports        &&
-                  sk->sk_family                == PF_INET6) {
-                       const struct inet6_timewait_sock *tw6 = inet6_twsk(sk);
-
-                       if (ipv6_addr_equal(&tw6->tw_v6_daddr, saddr)   &&
-                           ipv6_addr_equal(&tw6->tw_v6_rcv_saddr, daddr)       &&
-                           (!sk->sk_bound_dev_if || sk->sk_bound_dev_if == dif))
-                               goto hit;
-               }
+               if (INET6_TW_MATCH(sk, net, hash, saddr, daddr, ports, dif))
+                       goto hit;
        }
        read_unlock(lock);
        return NULL;
@@ -102,9 +94,9 @@ hit:
 }
 EXPORT_SYMBOL(__inet6_lookup_established);
 
-struct sock *inet6_lookup_listener(struct inet_hashinfo *hashinfo,
-                                  const struct in6_addr *daddr,
-                                  const unsigned short hnum, const int dif)
+struct sock *inet6_lookup_listener(struct net *net,
+               struct inet_hashinfo *hashinfo, const struct in6_addr *daddr,
+               const unsigned short hnum, const int dif)
 {
        struct sock *sk;
        const struct hlist_node *node;
@@ -113,7 +105,8 @@ struct sock *inet6_lookup_listener(struct inet_hashinfo *hashinfo,
 
        read_lock(&hashinfo->lhash_lock);
        sk_for_each(sk, node, &hashinfo->listening_hash[inet_lhashfn(hnum)]) {
-               if (inet_sk(sk)->num == hnum && sk->sk_family == PF_INET6) {
+               if (sk->sk_net == net && inet_sk(sk)->num == hnum &&
+                               sk->sk_family == PF_INET6) {
                        const struct ipv6_pinfo *np = inet6_sk(sk);
 
                        score = 1;
@@ -145,7 +138,7 @@ struct sock *inet6_lookup_listener(struct inet_hashinfo *hashinfo,
 
 EXPORT_SYMBOL_GPL(inet6_lookup_listener);
 
-struct sock *inet6_lookup(struct inet_hashinfo *hashinfo,
+struct sock *inet6_lookup(struct net *net, struct inet_hashinfo *hashinfo,
                          const struct in6_addr *saddr, const __be16 sport,
                          const struct in6_addr *daddr, const __be16 dport,
                          const int dif)
@@ -153,7 +146,7 @@ struct sock *inet6_lookup(struct inet_hashinfo *hashinfo,
        struct sock *sk;
 
        local_bh_disable();
-       sk = __inet6_lookup(hashinfo, saddr, sport, daddr, ntohs(dport), dif);
+       sk = __inet6_lookup(net, hashinfo, saddr, sport, daddr, ntohs(dport), dif);
        local_bh_enable();
 
        return sk;
@@ -179,21 +172,16 @@ static int __inet6_check_established(struct inet_timewait_death_row *death_row,
        struct sock *sk2;
        const struct hlist_node *node;
        struct inet_timewait_sock *tw;
+       struct net *net = sk->sk_net;
 
        prefetch(head->chain.first);
        write_lock(lock);
 
        /* Check TIME-WAIT sockets first. */
        sk_for_each(sk2, node, &head->twchain) {
-               const struct inet6_timewait_sock *tw6 = inet6_twsk(sk2);
-
                tw = inet_twsk(sk2);
 
-               if(*((__portpair *)&(tw->tw_dport)) == ports             &&
-                  sk2->sk_family              == PF_INET6       &&
-                  ipv6_addr_equal(&tw6->tw_v6_daddr, saddr)     &&
-                  ipv6_addr_equal(&tw6->tw_v6_rcv_saddr, daddr) &&
-                  (!sk2->sk_bound_dev_if || sk2->sk_bound_dev_if == dif)) {
+               if (INET6_TW_MATCH(sk2, net, hash, saddr, daddr, ports, dif)) {
                        if (twsk_unique(sk, sk2, twp))
                                goto unique;
                        else
@@ -204,7 +192,7 @@ static int __inet6_check_established(struct inet_timewait_death_row *death_row,
 
        /* And established part... */
        sk_for_each(sk2, node, &head->chain) {
-               if (INET6_MATCH(sk2, hash, saddr, daddr, ports, dif))
+               if (INET6_MATCH(sk2, net, hash, saddr, daddr, ports, dif))
                        goto not_unique;
        }
 
@@ -248,97 +236,8 @@ static inline u32 inet6_sk_port_offset(const struct sock *sk)
 int inet6_hash_connect(struct inet_timewait_death_row *death_row,
                       struct sock *sk)
 {
-       struct inet_hashinfo *hinfo = death_row->hashinfo;
-       const unsigned short snum = inet_sk(sk)->num;
-       struct inet_bind_hashbucket *head;
-       struct inet_bind_bucket *tb;
-       int ret;
-
-       if (snum == 0) {
-               int i, port, low, high, remaining;
-               static u32 hint;
-               const u32 offset = hint + inet6_sk_port_offset(sk);
-               struct hlist_node *node;
-               struct inet_timewait_sock *tw = NULL;
-
-               inet_get_local_port_range(&low, &high);
-               remaining = (high - low) + 1;
-
-               local_bh_disable();
-               for (i = 1; i <= remaining; i++) {
-                       port = low + (i + offset) % remaining;
-                       head = &hinfo->bhash[inet_bhashfn(port, hinfo->bhash_size)];
-                       spin_lock(&head->lock);
-
-                       /* Does not bother with rcv_saddr checks,
-                        * because the established check is already
-                        * unique enough.
-                        */
-                       inet_bind_bucket_for_each(tb, node, &head->chain) {
-                               if (tb->port == port) {
-                                       BUG_TRAP(!hlist_empty(&tb->owners));
-                                       if (tb->fastreuse >= 0)
-                                               goto next_port;
-                                       if (!__inet6_check_established(death_row,
-                                                                      sk, port,
-                                                                      &tw))
-                                               goto ok;
-                                       goto next_port;
-                               }
-                       }
-
-                       tb = inet_bind_bucket_create(hinfo->bind_bucket_cachep,
-                                                    head, port);
-                       if (!tb) {
-                               spin_unlock(&head->lock);
-                               break;
-                       }
-                       tb->fastreuse = -1;
-                       goto ok;
-
-               next_port:
-                       spin_unlock(&head->lock);
-               }
-               local_bh_enable();
-
-               return -EADDRNOTAVAIL;
-
-ok:
-               hint += i;
-
-               /* Head lock still held and bh's disabled */
-               inet_bind_hash(sk, tb, port);
-               if (sk_unhashed(sk)) {
-                       inet_sk(sk)->sport = htons(port);
-                       __inet6_hash(hinfo, sk);
-               }
-               spin_unlock(&head->lock);
-
-               if (tw) {
-                       inet_twsk_deschedule(tw, death_row);
-                       inet_twsk_put(tw);
-               }
-
-               ret = 0;
-               goto out;
-       }
-
-       head = &hinfo->bhash[inet_bhashfn(snum, hinfo->bhash_size)];
-       tb   = inet_csk(sk)->icsk_bind_hash;
-       spin_lock_bh(&head->lock);
-
-       if (sk_head(&tb->owners) == sk && sk->sk_bind_node.next == NULL) {
-               __inet6_hash(hinfo, sk);
-               spin_unlock_bh(&head->lock);
-               return 0;
-       } else {
-               spin_unlock(&head->lock);
-               /* No definite answer... Walk to established hash table */
-               ret = __inet6_check_established(death_row, sk, snum, NULL);
-out:
-               local_bh_enable();
-               return ret;
-       }
+       return __inet_hash_connect(death_row, sk, inet6_sk_port_offset(sk),
+                       __inet6_check_established, __inet6_hash);
 }
 
 EXPORT_SYMBOL_GPL(inet6_hash_connect);
index 15c4f6cee3e6e54daf41bec34d5015fb7a5fdf4b..9ac6ca2521c32fba05dd4c99e9f8e68bbf762c32 100644 (file)
@@ -257,6 +257,7 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl,
        ipv6_addr_copy(&hdr->daddr, first_hop);
 
        skb->priority = sk->sk_priority;
+       skb->mark = sk->sk_mark;
 
        mtu = dst_mtu(dst);
        if ((skb->len <= mtu) || ipfragok || skb_is_gso(skb)) {
@@ -636,6 +637,7 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
 
        if (skb_shinfo(skb)->frag_list) {
                int first_len = skb_pagelen(skb);
+               int truesizes = 0;
 
                if (first_len - hlen > mtu ||
                    ((first_len - hlen) & 7) ||
@@ -658,7 +660,7 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
                                sock_hold(skb->sk);
                                frag->sk = skb->sk;
                                frag->destructor = sock_wfree;
-                               skb->truesize -= frag->truesize;
+                               truesizes += frag->truesize;
                        }
                }
 
@@ -689,6 +691,7 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
 
                first_len = skb_pagelen(skb);
                skb->data_len = first_len - skb_headlen(skb);
+               skb->truesize -= truesizes;
                skb->len = first_len;
                ipv6_hdr(skb)->payload_len = htons(first_len -
                                                   sizeof(struct ipv6hdr));
@@ -1437,6 +1440,7 @@ int ip6_push_pending_frames(struct sock *sk)
        ipv6_addr_copy(&hdr->daddr, final_dst);
 
        skb->priority = sk->sk_priority;
+       skb->mark = sk->sk_mark;
 
        skb->dst = dst_clone(&rt->u.dst);
        IP6_INC_STATS(rt->rt6i_idev, IPSTATS_MIB_OUTREQUESTS);
index b276d04d6db52ea7dc2c1529d3351cc5a6e5b0aa..b90039593a7f0873c0d8af1b7c67144a2a34f531 100644 (file)
@@ -64,6 +64,7 @@ static LIST_HEAD(ipcomp6_tfms_list);
 
 static int ipcomp6_input(struct xfrm_state *x, struct sk_buff *skb)
 {
+       int nexthdr;
        int err = -ENOMEM;
        struct ip_comp_hdr *ipch;
        int plen, dlen;
@@ -79,6 +80,8 @@ static int ipcomp6_input(struct xfrm_state *x, struct sk_buff *skb)
 
        /* Remove ipcomp header and decompress original payload */
        ipch = (void *)skb->data;
+       nexthdr = ipch->nexthdr;
+
        skb->transport_header = skb->network_header + sizeof(*ipch);
        __skb_pull(skb, sizeof(*ipch));
 
@@ -108,7 +111,7 @@ static int ipcomp6_input(struct xfrm_state *x, struct sk_buff *skb)
        skb->truesize += dlen - plen;
        __skb_put(skb, dlen - plen);
        skb_copy_to_linear_data(skb, scratch, dlen);
-       err = ipch->nexthdr;
+       err = nexthdr;
 
 out_put_cpu:
        put_cpu();
@@ -450,7 +453,7 @@ error:
        goto out;
 }
 
-static struct xfrm_type ipcomp6_type =
+static const struct xfrm_type ipcomp6_type =
 {
        .description    = "IPCOMP6",
        .owner          = THIS_MODULE,
index 49d396620eac97e42d6c4602ac178d3cdfd9f1b8..cd8a5bda13cd7a5caad4ac6c8280764e123cb7d7 100644 (file)
@@ -330,7 +330,7 @@ static void mip6_destopt_destroy(struct xfrm_state *x)
 {
 }
 
-static struct xfrm_type mip6_destopt_type =
+static const struct xfrm_type mip6_destopt_type =
 {
        .description    = "MIP6DESTOPT",
        .owner          = THIS_MODULE,
@@ -462,7 +462,7 @@ static void mip6_rthdr_destroy(struct xfrm_state *x)
 {
 }
 
-static struct xfrm_type mip6_rthdr_type =
+static const struct xfrm_type mip6_rthdr_type =
 {
        .description    = "MIP6RT",
        .owner          = THIS_MODULE,
index 56b4ea6d29ed3c9780f0081d1a922899f92ba6f7..e869916b05f1c0b94e267016d69e0e7ff8446919 100644 (file)
@@ -515,6 +515,7 @@ static struct notifier_block ipq_nl_notifier = {
        .notifier_call  = ipq_rcv_nl_event,
 };
 
+#ifdef CONFIG_SYSCTL
 static struct ctl_table_header *ipq_sysctl_header;
 
 static ctl_table ipq_table[] = {
@@ -528,7 +529,9 @@ static ctl_table ipq_table[] = {
        },
        { .ctl_name = 0 }
 };
+#endif
 
+#ifdef CONFIG_PROC_FS
 static int ip6_queue_show(struct seq_file *m, void *v)
 {
        read_lock_bh(&queue_lock);
@@ -565,6 +568,7 @@ static const struct file_operations ip6_queue_proc_fops = {
        .release        = single_release,
        .owner          = THIS_MODULE,
 };
+#endif
 
 static const struct nf_queue_handler nfqh = {
        .name   = "ip6_queue",
@@ -574,7 +578,7 @@ static const struct nf_queue_handler nfqh = {
 static int __init ip6_queue_init(void)
 {
        int status = -ENOMEM;
-       struct proc_dir_entry *proc;
+       struct proc_dir_entry *proc __maybe_unused;
 
        netlink_register_notifier(&ipq_nl_notifier);
        ipqnl = netlink_kernel_create(&init_net, NETLINK_IP6_FW, 0,
@@ -584,6 +588,7 @@ static int __init ip6_queue_init(void)
                goto cleanup_netlink_notifier;
        }
 
+#ifdef CONFIG_PROC_FS
        proc = create_proc_entry(IPQ_PROC_FS_NAME, 0, init_net.proc_net);
        if (proc) {
                proc->owner = THIS_MODULE;
@@ -592,10 +597,11 @@ static int __init ip6_queue_init(void)
                printk(KERN_ERR "ip6_queue: failed to create proc entry\n");
                goto cleanup_ipqnl;
        }
-
+#endif
        register_netdevice_notifier(&ipq_dev_notifier);
+#ifdef CONFIG_SYSCTL
        ipq_sysctl_header = register_sysctl_paths(net_ipv6_ctl_path, ipq_table);
-
+#endif
        status = nf_register_queue_handler(PF_INET6, &nfqh);
        if (status < 0) {
                printk(KERN_ERR "ip6_queue: failed to register queue handler\n");
@@ -604,11 +610,13 @@ static int __init ip6_queue_init(void)
        return status;
 
 cleanup_sysctl:
+#ifdef CONFIG_SYSCTL
        unregister_sysctl_table(ipq_sysctl_header);
+#endif
        unregister_netdevice_notifier(&ipq_dev_notifier);
        proc_net_remove(&init_net, IPQ_PROC_FS_NAME);
 
-cleanup_ipqnl:
+cleanup_ipqnl: __maybe_unused
        netlink_kernel_release(ipqnl);
        mutex_lock(&ipqnl_mutex);
        mutex_unlock(&ipqnl_mutex);
@@ -624,7 +632,9 @@ static void __exit ip6_queue_fini(void)
        synchronize_net();
        ipq_flush(NULL, 0);
 
+#ifdef CONFIG_SYSCTL
        unregister_sysctl_table(ipq_sysctl_header);
+#endif
        unregister_netdevice_notifier(&ipq_dev_notifier);
        proc_net_remove(&init_net, IPQ_PROC_FS_NAME);
 
index dd7860fea61f98752bed17073cc92dd2d52808e3..bf9bb6e55bb54ca4db20ca77d6f7c54543caf512 100644 (file)
@@ -320,7 +320,7 @@ static void trace_packet(struct sk_buff *skb,
                         unsigned int hook,
                         const struct net_device *in,
                         const struct net_device *out,
-                        char *tablename,
+                        const char *tablename,
                         struct xt_table_info *private,
                         struct ip6t_entry *e)
 {
@@ -1118,7 +1118,7 @@ static int compat_table_info(const struct xt_table_info *info,
 }
 #endif
 
-static int get_info(void __user *user, int *len, int compat)
+static int get_info(struct net *net, void __user *user, int *len, int compat)
 {
        char name[IP6T_TABLE_MAXNAMELEN];
        struct xt_table *t;
@@ -1138,7 +1138,7 @@ static int get_info(void __user *user, int *len, int compat)
        if (compat)
                xt_compat_lock(AF_INET6);
 #endif
-       t = try_then_request_module(xt_find_table_lock(AF_INET6, name),
+       t = try_then_request_module(xt_find_table_lock(net, AF_INET6, name),
                                    "ip6table_%s", name);
        if (t && !IS_ERR(t)) {
                struct ip6t_getinfo info;
@@ -1178,7 +1178,7 @@ static int get_info(void __user *user, int *len, int compat)
 }
 
 static int
-get_entries(struct ip6t_get_entries __user *uptr, int *len)
+get_entries(struct net *net, struct ip6t_get_entries __user *uptr, int *len)
 {
        int ret;
        struct ip6t_get_entries get;
@@ -1196,7 +1196,7 @@ get_entries(struct ip6t_get_entries __user *uptr, int *len)
                return -EINVAL;
        }
 
-       t = xt_find_table_lock(AF_INET6, get.name);
+       t = xt_find_table_lock(net, AF_INET6, get.name);
        if (t && !IS_ERR(t)) {
                struct xt_table_info *private = t->private;
                duprintf("t->private->number = %u\n", private->number);
@@ -1217,7 +1217,7 @@ get_entries(struct ip6t_get_entries __user *uptr, int *len)
 }
 
 static int
-__do_replace(const char *name, unsigned int valid_hooks,
+__do_replace(struct net *net, const char *name, unsigned int valid_hooks,
             struct xt_table_info *newinfo, unsigned int num_counters,
             void __user *counters_ptr)
 {
@@ -1235,7 +1235,7 @@ __do_replace(const char *name, unsigned int valid_hooks,
                goto out;
        }
 
-       t = try_then_request_module(xt_find_table_lock(AF_INET6, name),
+       t = try_then_request_module(xt_find_table_lock(net, AF_INET6, name),
                                    "ip6table_%s", name);
        if (!t || IS_ERR(t)) {
                ret = t ? PTR_ERR(t) : -ENOENT;
@@ -1288,7 +1288,7 @@ __do_replace(const char *name, unsigned int valid_hooks,
 }
 
 static int
-do_replace(void __user *user, unsigned int len)
+do_replace(struct net *net, void __user *user, unsigned int len)
 {
        int ret;
        struct ip6t_replace tmp;
@@ -1322,7 +1322,7 @@ do_replace(void __user *user, unsigned int len)
 
        duprintf("ip_tables: Translated table\n");
 
-       ret = __do_replace(tmp.name, tmp.valid_hooks, newinfo,
+       ret = __do_replace(net, tmp.name, tmp.valid_hooks, newinfo,
                           tmp.num_counters, tmp.counters);
        if (ret)
                goto free_newinfo_untrans;
@@ -1358,7 +1358,8 @@ add_counter_to_entry(struct ip6t_entry *e,
 }
 
 static int
-do_add_counters(void __user *user, unsigned int len, int compat)
+do_add_counters(struct net *net, void __user *user, unsigned int len,
+               int compat)
 {
        unsigned int i;
        struct xt_counters_info tmp;
@@ -1410,7 +1411,7 @@ do_add_counters(void __user *user, unsigned int len, int compat)
                goto free;
        }
 
-       t = xt_find_table_lock(AF_INET6, name);
+       t = xt_find_table_lock(net, AF_INET6, name);
        if (!t || IS_ERR(t)) {
                ret = t ? PTR_ERR(t) : -ENOENT;
                goto free;
@@ -1456,7 +1457,7 @@ struct compat_ip6t_replace {
 
 static int
 compat_copy_entry_to_user(struct ip6t_entry *e, void __user **dstptr,
-                         compat_uint_t *size, struct xt_counters *counters,
+                         unsigned int *size, struct xt_counters *counters,
                          unsigned int *i)
 {
        struct ip6t_entry_target *t;
@@ -1503,7 +1504,7 @@ compat_find_calc_match(struct ip6t_entry_match *m,
                       const char *name,
                       const struct ip6t_ip6 *ipv6,
                       unsigned int hookmask,
-                      int *size, int *i)
+                      int *size, unsigned int *i)
 {
        struct xt_match *match;
 
@@ -1561,7 +1562,8 @@ check_compat_entry_size_and_hooks(struct compat_ip6t_entry *e,
        struct ip6t_entry_target *t;
        struct xt_target *target;
        unsigned int entry_offset;
-       int ret, off, h, j;
+       unsigned int j;
+       int ret, off, h;
 
        duprintf("check_compat_entry_size_and_hooks %p\n", e);
        if ((unsigned long)e % __alignof__(struct compat_ip6t_entry) != 0
@@ -1673,7 +1675,8 @@ compat_copy_entry_from_user(struct compat_ip6t_entry *e, void **dstptr,
 static int compat_check_entry(struct ip6t_entry *e, const char *name,
                                     unsigned int *i)
 {
-       int j, ret;
+       unsigned int j;
+       int ret;
 
        j = 0;
        ret = IP6T_MATCH_ITERATE(e, check_match, name, &e->ipv6,
@@ -1815,7 +1818,7 @@ out_unlock:
 }
 
 static int
-compat_do_replace(void __user *user, unsigned int len)
+compat_do_replace(struct net *net, void __user *user, unsigned int len)
 {
        int ret;
        struct compat_ip6t_replace tmp;
@@ -1852,7 +1855,7 @@ compat_do_replace(void __user *user, unsigned int len)
 
        duprintf("compat_do_replace: Translated table\n");
 
-       ret = __do_replace(tmp.name, tmp.valid_hooks, newinfo,
+       ret = __do_replace(net, tmp.name, tmp.valid_hooks, newinfo,
                           tmp.num_counters, compat_ptr(tmp.counters));
        if (ret)
                goto free_newinfo_untrans;
@@ -1876,11 +1879,11 @@ compat_do_ip6t_set_ctl(struct sock *sk, int cmd, void __user *user,
 
        switch (cmd) {
        case IP6T_SO_SET_REPLACE:
-               ret = compat_do_replace(user, len);
+               ret = compat_do_replace(sk->sk_net, user, len);
                break;
 
        case IP6T_SO_SET_ADD_COUNTERS:
-               ret = do_add_counters(user, len, 1);
+               ret = do_add_counters(sk->sk_net, user, len, 1);
                break;
 
        default:
@@ -1929,7 +1932,8 @@ compat_copy_entries_to_user(unsigned int total_size, struct xt_table *table,
 }
 
 static int
-compat_get_entries(struct compat_ip6t_get_entries __user *uptr, int *len)
+compat_get_entries(struct net *net, struct compat_ip6t_get_entries __user *uptr,
+                  int *len)
 {
        int ret;
        struct compat_ip6t_get_entries get;
@@ -1950,7 +1954,7 @@ compat_get_entries(struct compat_ip6t_get_entries __user *uptr, int *len)
        }
 
        xt_compat_lock(AF_INET6);
-       t = xt_find_table_lock(AF_INET6, get.name);
+       t = xt_find_table_lock(net, AF_INET6, get.name);
        if (t && !IS_ERR(t)) {
                struct xt_table_info *private = t->private;
                struct xt_table_info info;
@@ -1986,10 +1990,10 @@ compat_do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
 
        switch (cmd) {
        case IP6T_SO_GET_INFO:
-               ret = get_info(user, len, 1);
+               ret = get_info(sk->sk_net, user, len, 1);
                break;
        case IP6T_SO_GET_ENTRIES:
-               ret = compat_get_entries(user, len);
+               ret = compat_get_entries(sk->sk_net, user, len);
                break;
        default:
                ret = do_ip6t_get_ctl(sk, cmd, user, len);
@@ -2008,11 +2012,11 @@ do_ip6t_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
 
        switch (cmd) {
        case IP6T_SO_SET_REPLACE:
-               ret = do_replace(user, len);
+               ret = do_replace(sk->sk_net, user, len);
                break;
 
        case IP6T_SO_SET_ADD_COUNTERS:
-               ret = do_add_counters(user, len, 0);
+               ret = do_add_counters(sk->sk_net, user, len, 0);
                break;
 
        default:
@@ -2033,11 +2037,11 @@ do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
 
        switch (cmd) {
        case IP6T_SO_GET_INFO:
-               ret = get_info(user, len, 0);
+               ret = get_info(sk->sk_net, user, len, 0);
                break;
 
        case IP6T_SO_GET_ENTRIES:
-               ret = get_entries(user, len);
+               ret = get_entries(sk->sk_net, user, len);
                break;
 
        case IP6T_SO_GET_REVISION_MATCH:
@@ -2074,17 +2078,21 @@ do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
        return ret;
 }
 
-int ip6t_register_table(struct xt_table *table, const struct ip6t_replace *repl)
+struct xt_table *ip6t_register_table(struct net *net, struct xt_table *table,
+                                    const struct ip6t_replace *repl)
 {
        int ret;
        struct xt_table_info *newinfo;
        struct xt_table_info bootstrap
                = { 0, 0, 0, { 0 }, { 0 }, { } };
        void *loc_cpu_entry;
+       struct xt_table *new_table;
 
        newinfo = xt_alloc_table_info(repl->size);
-       if (!newinfo)
-               return -ENOMEM;
+       if (!newinfo) {
+               ret = -ENOMEM;
+               goto out;
+       }
 
        /* choose the copy on our node/cpu, but dont care about preemption */
        loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
@@ -2095,30 +2103,35 @@ int ip6t_register_table(struct xt_table *table, const struct ip6t_replace *repl)
                              repl->num_entries,
                              repl->hook_entry,
                              repl->underflow);
-       if (ret != 0) {
-               xt_free_table_info(newinfo);
-               return ret;
-       }
+       if (ret != 0)
+               goto out_free;
 
-       ret = xt_register_table(table, &bootstrap, newinfo);
-       if (ret != 0) {
-               xt_free_table_info(newinfo);
-               return ret;
+       new_table = xt_register_table(net, table, &bootstrap, newinfo);
+       if (IS_ERR(new_table)) {
+               ret = PTR_ERR(new_table);
+               goto out_free;
        }
+       return new_table;
 
-       return 0;
+out_free:
+       xt_free_table_info(newinfo);
+out:
+       return ERR_PTR(ret);
 }
 
 void ip6t_unregister_table(struct xt_table *table)
 {
        struct xt_table_info *private;
        void *loc_cpu_entry;
+       struct module *table_owner = table->me;
 
        private = xt_unregister_table(table);
 
        /* Decrease module usage counts and free resources */
        loc_cpu_entry = private->entries[raw_smp_processor_id()];
        IP6T_ENTRY_ITERATE(loc_cpu_entry, private->size, cleanup_entry, NULL);
+       if (private->number > private->initial_entries)
+               module_put(table_owner);
        xt_free_table_info(private);
 }
 
@@ -2225,11 +2238,26 @@ static struct xt_match icmp6_matchstruct __read_mostly = {
        .family         = AF_INET6,
 };
 
+static int __net_init ip6_tables_net_init(struct net *net)
+{
+       return xt_proto_init(net, AF_INET6);
+}
+
+static void __net_exit ip6_tables_net_exit(struct net *net)
+{
+       xt_proto_fini(net, AF_INET6);
+}
+
+static struct pernet_operations ip6_tables_net_ops = {
+       .init = ip6_tables_net_init,
+       .exit = ip6_tables_net_exit,
+};
+
 static int __init ip6_tables_init(void)
 {
        int ret;
 
-       ret = xt_proto_init(AF_INET6);
+       ret = register_pernet_subsys(&ip6_tables_net_ops);
        if (ret < 0)
                goto err1;
 
@@ -2259,7 +2287,7 @@ err4:
 err3:
        xt_unregister_target(&ip6t_standard_target);
 err2:
-       xt_proto_fini(AF_INET6);
+       unregister_pernet_subsys(&ip6_tables_net_ops);
 err1:
        return ret;
 }
@@ -2271,7 +2299,8 @@ static void __exit ip6_tables_fini(void)
        xt_unregister_match(&icmp6_matchstruct);
        xt_unregister_target(&ip6t_error_target);
        xt_unregister_target(&ip6t_standard_target);
-       xt_proto_fini(AF_INET6);
+
+       unregister_pernet_subsys(&ip6_tables_net_ops);
 }
 
 /*
index 87d38d08aad090e92f7f2dc022d203a7fb5ad54e..2d9cd095a72cd51ba8039b2a6b6a6ec4cf7a9c35 100644 (file)
@@ -26,7 +26,7 @@ static struct
        struct ip6t_replace repl;
        struct ip6t_standard entries[3];
        struct ip6t_error term;
-} initial_table __initdata = {
+} initial_table __net_initdata = {
        .repl = {
                .name = "filter",
                .valid_hooks = FILTER_VALID_HOOKS,
@@ -67,7 +67,7 @@ ip6t_hook(unsigned int hook,
         const struct net_device *out,
         int (*okfn)(struct sk_buff *))
 {
-       return ip6t_do_table(skb, hook, in, out, &packet_filter);
+       return ip6t_do_table(skb, hook, in, out, init_net.ipv6.ip6table_filter);
 }
 
 static unsigned int
@@ -87,7 +87,7 @@ ip6t_local_out_hook(unsigned int hook,
        }
 #endif
 
-       return ip6t_do_table(skb, hook, in, out, &packet_filter);
+       return ip6t_do_table(skb, hook, in, out, init_net.ipv6.ip6table_filter);
 }
 
 static struct nf_hook_ops ip6t_ops[] __read_mostly = {
@@ -118,6 +118,26 @@ static struct nf_hook_ops ip6t_ops[] __read_mostly = {
 static int forward = NF_ACCEPT;
 module_param(forward, bool, 0000);
 
+static int __net_init ip6table_filter_net_init(struct net *net)
+{
+       /* Register table */
+       net->ipv6.ip6table_filter =
+               ip6t_register_table(net, &packet_filter, &initial_table.repl);
+       if (IS_ERR(net->ipv6.ip6table_filter))
+               return PTR_ERR(net->ipv6.ip6table_filter);
+       return 0;
+}
+
+static void __net_exit ip6table_filter_net_exit(struct net *net)
+{
+       ip6t_unregister_table(net->ipv6.ip6table_filter);
+}
+
+static struct pernet_operations ip6table_filter_net_ops = {
+       .init = ip6table_filter_net_init,
+       .exit = ip6table_filter_net_exit,
+};
+
 static int __init ip6table_filter_init(void)
 {
        int ret;
@@ -130,8 +150,7 @@ static int __init ip6table_filter_init(void)
        /* Entry 1 is the FORWARD hook */
        initial_table.entries[1].target.verdict = -forward - 1;
 
-       /* Register table */
-       ret = ip6t_register_table(&packet_filter, &initial_table.repl);
+       ret = register_pernet_subsys(&ip6table_filter_net_ops);
        if (ret < 0)
                return ret;
 
@@ -143,14 +162,14 @@ static int __init ip6table_filter_init(void)
        return ret;
 
  cleanup_table:
-       ip6t_unregister_table(&packet_filter);
+       unregister_pernet_subsys(&ip6table_filter_net_ops);
        return ret;
 }
 
 static void __exit ip6table_filter_fini(void)
 {
        nf_unregister_hooks(ip6t_ops, ARRAY_SIZE(ip6t_ops));
-       ip6t_unregister_table(&packet_filter);
+       unregister_pernet_subsys(&ip6table_filter_net_ops);
 }
 
 module_init(ip6table_filter_init);
index d6082600bc5db6d260183e0da010252e6413a157..035343a90ffe198c04acef90a3a33c7a59caea6e 100644 (file)
@@ -26,7 +26,7 @@ static struct
        struct ip6t_replace repl;
        struct ip6t_standard entries[5];
        struct ip6t_error term;
-} initial_table __initdata = {
+} initial_table __net_initdata = {
        .repl = {
                .name = "mangle",
                .valid_hooks = MANGLE_VALID_HOOKS,
@@ -73,7 +73,7 @@ ip6t_route_hook(unsigned int hook,
         const struct net_device *out,
         int (*okfn)(struct sk_buff *))
 {
-       return ip6t_do_table(skb, hook, in, out, &packet_mangler);
+       return ip6t_do_table(skb, hook, in, out, init_net.ipv6.ip6table_mangle);
 }
 
 static unsigned int
@@ -108,7 +108,7 @@ ip6t_local_hook(unsigned int hook,
        /* flowlabel and prio (includes version, which shouldn't change either */
        flowlabel = *((u_int32_t *)ipv6_hdr(skb));
 
-       ret = ip6t_do_table(skb, hook, in, out, &packet_mangler);
+       ret = ip6t_do_table(skb, hook, in, out, init_net.ipv6.ip6table_mangle);
 
        if (ret != NF_DROP && ret != NF_STOLEN
                && (memcmp(&ipv6_hdr(skb)->saddr, &saddr, sizeof(saddr))
@@ -158,12 +158,31 @@ static struct nf_hook_ops ip6t_ops[] __read_mostly = {
        },
 };
 
+static int __net_init ip6table_mangle_net_init(struct net *net)
+{
+       /* Register table */
+       net->ipv6.ip6table_mangle =
+               ip6t_register_table(net, &packet_mangler, &initial_table.repl);
+       if (IS_ERR(net->ipv6.ip6table_mangle))
+               return PTR_ERR(net->ipv6.ip6table_mangle);
+       return 0;
+}
+
+static void __net_exit ip6table_mangle_net_exit(struct net *net)
+{
+       ip6t_unregister_table(net->ipv6.ip6table_mangle);
+}
+
+static struct pernet_operations ip6table_mangle_net_ops = {
+       .init = ip6table_mangle_net_init,
+       .exit = ip6table_mangle_net_exit,
+};
+
 static int __init ip6table_mangle_init(void)
 {
        int ret;
 
-       /* Register table */
-       ret = ip6t_register_table(&packet_mangler, &initial_table.repl);
+       ret = register_pernet_subsys(&ip6table_mangle_net_ops);
        if (ret < 0)
                return ret;
 
@@ -175,14 +194,14 @@ static int __init ip6table_mangle_init(void)
        return ret;
 
  cleanup_table:
-       ip6t_unregister_table(&packet_mangler);
+       unregister_pernet_subsys(&ip6table_mangle_net_ops);
        return ret;
 }
 
 static void __exit ip6table_mangle_fini(void)
 {
        nf_unregister_hooks(ip6t_ops, ARRAY_SIZE(ip6t_ops));
-       ip6t_unregister_table(&packet_mangler);
+       unregister_pernet_subsys(&ip6table_mangle_net_ops);
 }
 
 module_init(ip6table_mangle_init);
index eccbaaa104af264a3308208178abce7c30a0c64b..5cd84203abfe80bc06b2e2ae10ccd74150a0b6ed 100644 (file)
@@ -13,7 +13,7 @@ static struct
        struct ip6t_replace repl;
        struct ip6t_standard entries[2];
        struct ip6t_error term;
-} initial_table __initdata = {
+} initial_table __net_initdata = {
        .repl = {
                .name = "raw",
                .valid_hooks = RAW_VALID_HOOKS,
@@ -51,7 +51,7 @@ ip6t_hook(unsigned int hook,
         const struct net_device *out,
         int (*okfn)(struct sk_buff *))
 {
-       return ip6t_do_table(skb, hook, in, out, &packet_raw);
+       return ip6t_do_table(skb, hook, in, out, init_net.ipv6.ip6table_raw);
 }
 
 static struct nf_hook_ops ip6t_ops[] __read_mostly = {
@@ -71,12 +71,31 @@ static struct nf_hook_ops ip6t_ops[] __read_mostly = {
        },
 };
 
+static int __net_init ip6table_raw_net_init(struct net *net)
+{
+       /* Register table */
+       net->ipv6.ip6table_raw =
+               ip6t_register_table(net, &packet_raw, &initial_table.repl);
+       if (IS_ERR(net->ipv6.ip6table_raw))
+               return PTR_ERR(net->ipv6.ip6table_raw);
+       return 0;
+}
+
+static void __net_exit ip6table_raw_net_exit(struct net *net)
+{
+       ip6t_unregister_table(net->ipv6.ip6table_raw);
+}
+
+static struct pernet_operations ip6table_raw_net_ops = {
+       .init = ip6table_raw_net_init,
+       .exit = ip6table_raw_net_exit,
+};
+
 static int __init ip6table_raw_init(void)
 {
        int ret;
 
-       /* Register table */
-       ret = ip6t_register_table(&packet_raw, &initial_table.repl);
+       ret = register_pernet_subsys(&ip6table_raw_net_ops);
        if (ret < 0)
                return ret;
 
@@ -88,14 +107,14 @@ static int __init ip6table_raw_init(void)
        return ret;
 
  cleanup_table:
-       ip6t_unregister_table(&packet_raw);
+       unregister_pernet_subsys(&ip6table_raw_net_ops);
        return ret;
 }
 
 static void __exit ip6table_raw_fini(void)
 {
        nf_unregister_hooks(ip6t_ops, ARRAY_SIZE(ip6t_ops));
-       ip6t_unregister_table(&packet_raw);
+       unregister_pernet_subsys(&ip6table_raw_net_ops);
 }
 
 module_init(ip6table_raw_init);
index 2d7b0246475d898848290fc38120cd41d1d73aa9..3717bdf34f6edbe63e5615d1320d4f56bdce47fd 100644 (file)
@@ -30,7 +30,8 @@
 static int ipv6_pkt_to_tuple(const struct sk_buff *skb, unsigned int nhoff,
                             struct nf_conntrack_tuple *tuple)
 {
-       u_int32_t _addrs[8], *ap;
+       const u_int32_t *ap;
+       u_int32_t _addrs[8];
 
        ap = skb_header_pointer(skb, nhoff + offsetof(struct ipv6hdr, saddr),
                                sizeof(_addrs), _addrs);
@@ -146,8 +147,8 @@ static unsigned int ipv6_confirm(unsigned int hooknum,
                                 int (*okfn)(struct sk_buff *))
 {
        struct nf_conn *ct;
-       struct nf_conn_help *help;
-       struct nf_conntrack_helper *helper;
+       const struct nf_conn_help *help;
+       const struct nf_conntrack_helper *helper;
        enum ip_conntrack_info ctinfo;
        unsigned int ret, protoff;
        unsigned int extoff = (u8 *)(ipv6_hdr(skb) + 1) - skb->data;
index da924c6b5f065676f526d723aa5501191ead8862..0897d0f4c4a2d19dfec220d2b6855627526d65b3 100644 (file)
@@ -32,7 +32,8 @@ static int icmpv6_pkt_to_tuple(const struct sk_buff *skb,
                               unsigned int dataoff,
                               struct nf_conntrack_tuple *tuple)
 {
-       struct icmp6hdr _hdr, *hp;
+       const struct icmp6hdr *hp;
+       struct icmp6hdr _hdr;
 
        hp = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr);
        if (hp == NULL)
@@ -45,7 +46,7 @@ static int icmpv6_pkt_to_tuple(const struct sk_buff *skb,
 }
 
 /* Add 1; spaces filled with 0. */
-static u_int8_t invmap[] = {
+static const u_int8_t invmap[] = {
        [ICMPV6_ECHO_REQUEST - 128]     = ICMPV6_ECHO_REPLY + 1,
        [ICMPV6_ECHO_REPLY - 128]       = ICMPV6_ECHO_REQUEST + 1,
        [ICMPV6_NI_QUERY - 128]         = ICMPV6_NI_QUERY + 1,
@@ -101,24 +102,24 @@ static int icmpv6_packet(struct nf_conn *ct,
 }
 
 /* Called when a new connection for this protocol found. */
-static int icmpv6_new(struct nf_conn *conntrack,
+static int icmpv6_new(struct nf_conn *ct,
                      const struct sk_buff *skb,
                      unsigned int dataoff)
 {
-       static u_int8_t valid_new[] = {
+       static const u_int8_t valid_new[] = {
                [ICMPV6_ECHO_REQUEST - 128] = 1,
                [ICMPV6_NI_QUERY - 128] = 1
        };
-       int type = conntrack->tuplehash[0].tuple.dst.u.icmp.type - 128;
+       int type = ct->tuplehash[0].tuple.dst.u.icmp.type - 128;
 
        if (type < 0 || type >= sizeof(valid_new) || !valid_new[type]) {
                /* Can't create a new ICMPv6 `conn' with this. */
                pr_debug("icmpv6: can't create new conn with type %u\n",
                         type + 128);
-               NF_CT_DUMP_TUPLE(&conntrack->tuplehash[0].tuple);
+               NF_CT_DUMP_TUPLE(&ct->tuplehash[0].tuple);
                return 0;
        }
-       atomic_set(&conntrack->proto.icmp.count, 0);
+       atomic_set(&ct->proto.icmp.count, 0);
        return 1;
 }
 
@@ -129,8 +130,8 @@ icmpv6_error_message(struct sk_buff *skb,
                     unsigned int hooknum)
 {
        struct nf_conntrack_tuple intuple, origtuple;
-       struct nf_conntrack_tuple_hash *h;
-       struct nf_conntrack_l4proto *inproto;
+       const struct nf_conntrack_tuple_hash *h;
+       const struct nf_conntrack_l4proto *inproto;
 
        NF_CT_ASSERT(skb->nfct == NULL);
 
@@ -176,7 +177,8 @@ static int
 icmpv6_error(struct sk_buff *skb, unsigned int dataoff,
             enum ip_conntrack_info *ctinfo, int pf, unsigned int hooknum)
 {
-       struct icmp6hdr _ih, *icmp6h;
+       const struct icmp6hdr *icmp6h;
+       struct icmp6hdr _ih;
 
        icmp6h = skb_header_pointer(skb, dataoff, sizeof(_ih), &_ih);
        if (icmp6h == NULL) {
index 022da6ce4c0f3a4548b8ba01fa860d4c8982d116..2a0d698b24d5b3404305c1ebacb7306080bd0a52 100644 (file)
@@ -39,6 +39,7 @@
 #include <net/rawv6.h>
 #include <net/ndisc.h>
 #include <net/addrconf.h>
+#include <net/netfilter/ipv6/nf_conntrack_ipv6.h>
 #include <linux/sysctl.h>
 #include <linux/netfilter.h>
 #include <linux/netfilter_ipv6.h>
@@ -680,21 +681,6 @@ void nf_ct_frag6_output(unsigned int hooknum, struct sk_buff *skb,
        nf_conntrack_put_reasm(skb);
 }
 
-int nf_ct_frag6_kfree_frags(struct sk_buff *skb)
-{
-       struct sk_buff *s, *s2;
-
-       for (s = NFCT_FRAG6_CB(skb)->orig; s; s = s2) {
-
-               s2 = s->next;
-               kfree_skb(s);
-       }
-
-       kfree_skb(skb);
-
-       return 0;
-}
-
 int nf_ct_frag6_init(void)
 {
        nf_frags.hashfn = nf_hashfn;
index 4d880551fe6ab327260a09401d2a5a4f3c9e7315..8897ccf8086afacfc643163e89b740cc4a6df13c 100644 (file)
@@ -641,6 +641,7 @@ static int rawv6_send_hdrinc(struct sock *sk, void *from, int length,
        skb_reserve(skb, hh_len);
 
        skb->priority = sk->sk_priority;
+       skb->mark = sk->sk_mark;
        skb->dst = dst_clone(&rt->u.dst);
 
        skb_put(skb, length);
@@ -767,6 +768,8 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
         */
        memset(&fl, 0, sizeof(fl));
 
+       fl.mark = sk->sk_mark;
+
        if (sin6) {
                if (addr_len < SIN6_LEN_RFC2133)
                        return -EINVAL;
@@ -1259,7 +1262,7 @@ static const struct seq_operations raw6_seq_ops = {
 
 static int raw6_seq_open(struct inode *inode, struct file *file)
 {
-       return raw_seq_open(inode, file, &raw_v6_hashinfo, PF_INET6);
+       return raw_seq_open(inode, file, &raw_v6_hashinfo, &raw6_seq_ops);
 }
 
 static const struct file_operations raw6_seq_fops = {
index 4004c5f0b8d78eec1ad2ae6fbd2a3494645dac5c..513f72e3db0da00dc8f54bd9df7878054e92be33 100644 (file)
@@ -107,6 +107,7 @@ static struct dst_ops ip6_dst_ops = {
        .update_pmtu            =       ip6_rt_update_pmtu,
        .local_out              =       ip6_local_out,
        .entry_size             =       sizeof(struct rt6_info),
+       .entries                =       ATOMIC_INIT(0),
 };
 
 static void ip6_rt_blackhole_update_pmtu(struct dst_entry *dst, u32 mtu)
@@ -120,6 +121,7 @@ static struct dst_ops ip6_dst_blackhole_ops = {
        .check                  =       ip6_dst_check,
        .update_pmtu            =       ip6_rt_blackhole_update_pmtu,
        .entry_size             =       sizeof(struct rt6_info),
+       .entries                =       ATOMIC_INIT(0),
 };
 
 struct rt6_info ip6_null_entry = {
@@ -1907,7 +1909,7 @@ static int rt6_mtu_change_route(struct rt6_info *rt, void *p_arg)
         */
        if (rt->rt6i_dev == arg->dev &&
            !dst_metric_locked(&rt->u.dst, RTAX_MTU) &&
-           (dst_mtu(&rt->u.dst) > arg->mtu ||
+           (dst_mtu(&rt->u.dst) >= arg->mtu ||
             (dst_mtu(&rt->u.dst) < arg->mtu &&
              dst_mtu(&rt->u.dst) == idev->cnf.mtu6))) {
                rt->u.dst.metrics[RTAX_MTU-1] = arg->mtu;
@@ -1960,6 +1962,7 @@ static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh,
 
        cfg->fc_nlinfo.pid = NETLINK_CB(skb).pid;
        cfg->fc_nlinfo.nlh = nlh;
+       cfg->fc_nlinfo.nl_net = skb->sk->sk_net;
 
        if (tb[RTA_GATEWAY]) {
                nla_memcpy(&cfg->fc_gateway, tb[RTA_GATEWAY], 16);
index 00c08399837d00e31d91b26906392367a2bc3a26..12750f2b05ab02ff6846b64a1d880cfd9402322e 100644 (file)
@@ -86,12 +86,6 @@ static struct tcp_sock_af_ops tcp_sock_ipv6_specific;
 static struct tcp_sock_af_ops tcp_sock_ipv6_mapped_specific;
 #endif
 
-static int tcp_v6_get_port(struct sock *sk, unsigned short snum)
-{
-       return inet_csk_get_port(&tcp_hashinfo, sk, snum,
-                                inet6_csk_bind_conflict);
-}
-
 static void tcp_v6_hash(struct sock *sk)
 {
        if (sk->sk_state != TCP_CLOSE) {
@@ -100,7 +94,7 @@ static void tcp_v6_hash(struct sock *sk)
                        return;
                }
                local_bh_disable();
-               __inet6_hash(&tcp_hashinfo, sk);
+               __inet6_hash(sk);
                local_bh_enable();
        }
 }
@@ -330,8 +324,8 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
        struct tcp_sock *tp;
        __u32 seq;
 
-       sk = inet6_lookup(&tcp_hashinfo, &hdr->daddr, th->dest, &hdr->saddr,
-                         th->source, skb->dev->ifindex);
+       sk = inet6_lookup(skb->dev->nd_net, &tcp_hashinfo, &hdr->daddr,
+                       th->dest, &hdr->saddr, th->source, skb->dev->ifindex);
 
        if (sk == NULL) {
                ICMP6_INC_STATS_BH(__in6_dev_get(skb->dev), ICMP6_MIB_INERRORS);
@@ -1208,9 +1202,9 @@ static struct sock *tcp_v6_hnd_req(struct sock *sk,struct sk_buff *skb)
        if (req)
                return tcp_check_req(sk, skb, req, prev);
 
-       nsk = __inet6_lookup_established(&tcp_hashinfo, &ipv6_hdr(skb)->saddr,
-                                        th->source, &ipv6_hdr(skb)->daddr,
-                                        ntohs(th->dest), inet6_iif(skb));
+       nsk = __inet6_lookup_established(sk->sk_net, &tcp_hashinfo,
+                       &ipv6_hdr(skb)->saddr, th->source,
+                       &ipv6_hdr(skb)->daddr, ntohs(th->dest), inet6_iif(skb));
 
        if (nsk) {
                if (nsk->sk_state != TCP_TIME_WAIT) {
@@ -1504,8 +1498,8 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
        }
 #endif
 
-       __inet6_hash(&tcp_hashinfo, newsk);
-       inet_inherit_port(&tcp_hashinfo, sk, newsk);
+       __inet6_hash(newsk);
+       inet_inherit_port(sk, newsk);
 
        return newsk;
 
@@ -1710,9 +1704,10 @@ static int tcp_v6_rcv(struct sk_buff *skb)
        TCP_SKB_CB(skb)->flags = ipv6_get_dsfield(ipv6_hdr(skb));
        TCP_SKB_CB(skb)->sacked = 0;
 
-       sk = __inet6_lookup(&tcp_hashinfo, &ipv6_hdr(skb)->saddr, th->source,
-                           &ipv6_hdr(skb)->daddr, ntohs(th->dest),
-                           inet6_iif(skb));
+       sk = __inet6_lookup(skb->dev->nd_net, &tcp_hashinfo,
+                       &ipv6_hdr(skb)->saddr, th->source,
+                       &ipv6_hdr(skb)->daddr, ntohs(th->dest),
+                       inet6_iif(skb));
 
        if (!sk)
                goto no_tcp_socket;
@@ -1792,7 +1787,7 @@ do_time_wait:
        {
                struct sock *sk2;
 
-               sk2 = inet6_lookup_listener(&tcp_hashinfo,
+               sk2 = inet6_lookup_listener(skb->dev->nd_net, &tcp_hashinfo,
                                            &ipv6_hdr(skb)->daddr,
                                            ntohs(th->dest), inet6_iif(skb));
                if (sk2 != NULL) {
@@ -1832,6 +1827,7 @@ static struct inet_connection_sock_af_ops ipv6_specific = {
        .getsockopt        = ipv6_getsockopt,
        .addr2sockaddr     = inet6_csk_addr2sockaddr,
        .sockaddr_len      = sizeof(struct sockaddr_in6),
+       .bind_conflict     = inet6_csk_bind_conflict,
 #ifdef CONFIG_COMPAT
        .compat_setsockopt = compat_ipv6_setsockopt,
        .compat_getsockopt = compat_ipv6_getsockopt,
@@ -1863,6 +1859,7 @@ static struct inet_connection_sock_af_ops ipv6_mapped = {
        .getsockopt        = ipv6_getsockopt,
        .addr2sockaddr     = inet6_csk_addr2sockaddr,
        .sockaddr_len      = sizeof(struct sockaddr_in6),
+       .bind_conflict     = inet6_csk_bind_conflict,
 #ifdef CONFIG_COMPAT
        .compat_setsockopt = compat_ipv6_setsockopt,
        .compat_getsockopt = compat_ipv6_getsockopt,
@@ -2126,8 +2123,8 @@ struct proto tcpv6_prot = {
        .recvmsg                = tcp_recvmsg,
        .backlog_rcv            = tcp_v6_do_rcv,
        .hash                   = tcp_v6_hash,
-       .unhash                 = tcp_unhash,
-       .get_port               = tcp_v6_get_port,
+       .unhash                 = inet_unhash,
+       .get_port               = inet_csk_get_port,
        .enter_memory_pressure  = tcp_enter_memory_pressure,
        .sockets_allocated      = &tcp_sockets_allocated,
        .memory_allocated       = &tcp_memory_allocated,
@@ -2140,6 +2137,7 @@ struct proto tcpv6_prot = {
        .obj_size               = sizeof(struct tcp6_sock),
        .twsk_prot              = &tcp6_timewait_sock_ops,
        .rsk_prot               = &tcp6_request_sock_ops,
+       .hashinfo               = &tcp_hashinfo,
 #ifdef CONFIG_COMPAT
        .compat_setsockopt      = compat_tcp_setsockopt,
        .compat_getsockopt      = compat_tcp_getsockopt,
index bd4b9df8f614018322c6b9176f136d30db3dafac..53739de829db07eb8ad1c3b9ab2b25d4e2b162c5 100644 (file)
@@ -56,7 +56,8 @@ static inline int udp_v6_get_port(struct sock *sk, unsigned short snum)
        return udp_get_port(sk, snum, ipv6_rcv_saddr_equal);
 }
 
-static struct sock *__udp6_lib_lookup(struct in6_addr *saddr, __be16 sport,
+static struct sock *__udp6_lib_lookup(struct net *net,
+                                     struct in6_addr *saddr, __be16 sport,
                                      struct in6_addr *daddr, __be16 dport,
                                      int dif, struct hlist_head udptable[])
 {
@@ -69,7 +70,8 @@ static struct sock *__udp6_lib_lookup(struct in6_addr *saddr, __be16 sport,
        sk_for_each(sk, node, &udptable[hnum & (UDP_HTABLE_SIZE - 1)]) {
                struct inet_sock *inet = inet_sk(sk);
 
-               if (sk->sk_hash == hnum && sk->sk_family == PF_INET6) {
+               if (sk->sk_net == net && sk->sk_hash == hnum &&
+                               sk->sk_family == PF_INET6) {
                        struct ipv6_pinfo *np = inet6_sk(sk);
                        int score = 0;
                        if (inet->dport) {
@@ -233,7 +235,7 @@ void __udp6_lib_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
        struct sock *sk;
        int err;
 
-       sk = __udp6_lib_lookup(daddr, uh->dest,
+       sk = __udp6_lib_lookup(skb->dev->nd_net, daddr, uh->dest,
                               saddr, uh->source, inet6_iif(skb), udptable);
        if (sk == NULL)
                return;
@@ -478,7 +480,7 @@ int __udp6_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[],
         * check socket cache ... must talk to Alan about his plans
         * for sock caches... i'll skip this for now.
         */
-       sk = __udp6_lib_lookup(saddr, uh->source,
+       sk = __udp6_lib_lookup(skb->dev->nd_net, saddr, uh->source,
                               daddr, uh->dest, inet6_iif(skb), udptable);
 
        if (sk == NULL) {
index c25a6b527fc4e083184e718720f184a752625bc6..7d20199ee1f39cb98c4622042fe9460e4dbd42a7 100644 (file)
@@ -272,6 +272,7 @@ static struct dst_ops xfrm6_dst_ops = {
        .local_out =            __ip6_local_out,
        .gc_thresh =            1024,
        .entry_size =           sizeof(struct xfrm_dst),
+       .entries =              ATOMIC_INIT(0),
 };
 
 static struct xfrm_policy_afinfo xfrm6_policy_afinfo = {
index fae90ff310875eac20da4de63c56469ce53237eb..639fe8a6ff1e996c9bcec6c36cb7e70b88d63be8 100644 (file)
@@ -319,7 +319,7 @@ static void xfrm6_tunnel_destroy(struct xfrm_state *x)
        xfrm6_tunnel_free_spi((xfrm_address_t *)&x->props.saddr);
 }
 
-static struct xfrm_type xfrm6_tunnel_type = {
+static const struct xfrm_type xfrm6_tunnel_type = {
        .description    = "IP6IP6",
        .owner          = THIS_MODULE,
        .proto          = IPPROTO_IPV6,
index 16b72b5570c303831aca6353d6a35b4ae901b473..45c3c27d279ad9b66e92b0771b9342a4840ca4c1 100644 (file)
@@ -1466,7 +1466,7 @@ static int pfkey_add(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr,
                err = xfrm_state_update(x);
 
        xfrm_audit_state_add(x, err ? 0 : 1,
-                            audit_get_loginuid(current->audit_context), 0);
+                            audit_get_loginuid(current), 0);
 
        if (err < 0) {
                x->km.state = XFRM_STATE_DEAD;
@@ -1520,7 +1520,7 @@ static int pfkey_delete(struct sock *sk, struct sk_buff *skb, struct sadb_msg *h
        km_state_notify(x, &c);
 out:
        xfrm_audit_state_delete(x, err ? 0 : 1,
-                              audit_get_loginuid(current->audit_context), 0);
+                              audit_get_loginuid(current), 0);
        xfrm_state_put(x);
 
        return err;
@@ -1695,7 +1695,7 @@ static int pfkey_flush(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hd
        if (proto == 0)
                return -EINVAL;
 
-       audit_info.loginuid = audit_get_loginuid(current->audit_context);
+       audit_info.loginuid = audit_get_loginuid(current);
        audit_info.secid = 0;
        err = xfrm_state_flush(proto, &audit_info);
        if (err)
@@ -2273,7 +2273,7 @@ static int pfkey_spdadd(struct sock *sk, struct sk_buff *skb, struct sadb_msg *h
                                 hdr->sadb_msg_type != SADB_X_SPDUPDATE);
 
        xfrm_audit_policy_add(xp, err ? 0 : 1,
-                            audit_get_loginuid(current->audit_context), 0);
+                            audit_get_loginuid(current), 0);
 
        if (err)
                goto out;
@@ -2356,7 +2356,7 @@ static int pfkey_spddelete(struct sock *sk, struct sk_buff *skb, struct sadb_msg
                return -ENOENT;
 
        xfrm_audit_policy_delete(xp, err ? 0 : 1,
-                               audit_get_loginuid(current->audit_context), 0);
+                               audit_get_loginuid(current), 0);
 
        if (err)
                goto out;
@@ -2617,7 +2617,7 @@ static int pfkey_spdget(struct sock *sk, struct sk_buff *skb, struct sadb_msg *h
 
        if (delete) {
                xfrm_audit_policy_delete(xp, err ? 0 : 1,
-                               audit_get_loginuid(current->audit_context), 0);
+                               audit_get_loginuid(current), 0);
 
                if (err)
                        goto out;
@@ -2694,7 +2694,7 @@ static int pfkey_spdflush(struct sock *sk, struct sk_buff *skb, struct sadb_msg
        struct xfrm_audit audit_info;
        int err;
 
-       audit_info.loginuid = audit_get_loginuid(current->audit_context);
+       audit_info.loginuid = audit_get_loginuid(current);
        audit_info.secid = 0;
        err = xfrm_policy_flush(XFRM_POLICY_TYPE_MAIN, &audit_info);
        if (err)
index 09c255002e565dcba6606937d0c1a14409537212..e77592d050ce8a33a777ab12e6c384b84bc524b1 100644 (file)
@@ -98,6 +98,18 @@ config MAC80211_DEBUGFS
 
          Say N unless you know you need this.
 
+config MAC80211_DEBUG_PACKET_ALIGNMENT
+       bool "Enable packet alignment debugging"
+       depends on MAC80211
+       help
+         This option is recommended for driver authors and strongly
+         discouraged for everybody else, it will trigger a warning
+         when a driver hands mac80211 a buffer that is aligned in
+         a way that will cause problems with the IP stack on some
+         architectures.
+
+         Say N unless you're writing a mac80211 based driver.
+
 config MAC80211_DEBUG
        bool "Enable debugging output"
        depends on MAC80211
index 5dcc2d61551fe2260f5a39e6fe323669b705323b..67b7c75c430d337e0ddfdc5e8a33dac498b60472 100644 (file)
@@ -1344,17 +1344,17 @@ static int __init ieee80211_init(void)
 
        ret = rc80211_simple_init();
        if (ret)
-               goto fail;
+               goto out;
 
        ret = rc80211_pid_init();
        if (ret)
-               goto fail_simple;
+               goto out_cleanup_simple;
 
        ret = ieee80211_wme_register();
        if (ret) {
                printk(KERN_DEBUG "ieee80211_init: failed to "
                       "initialize WME (err=%d)\n", ret);
-               goto fail_pid;
+               goto out_cleanup_pid;
        }
 
        ieee80211_debugfs_netdev_init();
@@ -1362,11 +1362,11 @@ static int __init ieee80211_init(void)
 
        return 0;
 
- fail_pid:
-       rc80211_simple_exit();
- fail_simple:
+ out_cleanup_pid:
        rc80211_pid_exit();
- fail:
+ out_cleanup_simple:
+       rc80211_simple_exit();
+ out:
        return ret;
 }
 
index 554c4baed6fbd3d4bdb164eaeea024fcf919bcfb..c339571632b2f102fdc8a81a8416fb71826ccf98 100644 (file)
@@ -538,7 +538,7 @@ int __init rc80211_pid_init(void)
        return ieee80211_rate_control_register(&mac80211_rcpid);
 }
 
-void __exit rc80211_pid_exit(void)
+void rc80211_pid_exit(void)
 {
        ieee80211_rate_control_unregister(&mac80211_rcpid);
 }
index 934676d687d6f9b674c837181603b91e4aad2a6f..9a78b116acffbdca0b00ba2df579ce87ec6cd2f2 100644 (file)
@@ -389,7 +389,7 @@ int __init rc80211_simple_init(void)
        return ieee80211_rate_control_register(&mac80211_rcsimple);
 }
 
-void __exit rc80211_simple_exit(void)
+void rc80211_simple_exit(void)
 {
        ieee80211_rate_control_unregister(&mac80211_rcsimple);
 }
index 89e1e3070ec17e048bf9b79606d7b07935c14990..535407d07fa40890a4731648f85157a00fb39dc8 100644 (file)
@@ -340,9 +340,49 @@ static u32 ieee80211_rx_load_stats(struct ieee80211_local *local,
        return load;
 }
 
+#ifdef CONFIG_MAC80211_DEBUG_PACKET_ALIGNMENT
+static ieee80211_txrx_result
+ieee80211_rx_h_verify_ip_alignment(struct ieee80211_txrx_data *rx)
+{
+       int hdrlen;
+
+       if (!WLAN_FC_DATA_PRESENT(rx->fc))
+               return TXRX_CONTINUE;
+
+       /*
+        * Drivers are required to align the payload data in a way that
+        * guarantees that the contained IP header is aligned to a four-
+        * byte boundary. In the case of regular frames, this simply means
+        * aligning the payload to a four-byte boundary (because either
+        * the IP header is directly contained, or IV/RFC1042 headers that
+        * have a length divisible by four are in front of it.
+        *
+        * With A-MSDU frames, however, the payload data address must
+        * yield two modulo four because there are 14-byte 802.3 headers
+        * within the A-MSDU frames that push the IP header further back
+        * to a multiple of four again. Thankfully, the specs were sane
+        * enough this time around to require padding each A-MSDU subframe
+        * to a length that is a multiple of four.
+        *
+        * Padding like atheros hardware adds which is inbetween the 802.11
+        * header and the payload is not supported, the driver is required
+        * to move the 802.11 header further back in that case.
+        */
+       hdrlen = ieee80211_get_hdrlen(rx->fc);
+       if (rx->flags & IEEE80211_TXRXD_RX_AMSDU)
+               hdrlen += ETH_HLEN;
+       WARN_ON_ONCE(((unsigned long)(rx->skb->data + hdrlen)) & 3);
+
+       return TXRX_CONTINUE;
+}
+#endif
+
 ieee80211_rx_handler ieee80211_rx_pre_handlers[] =
 {
        ieee80211_rx_h_parse_qos,
+#ifdef CONFIG_MAC80211_DEBUG_PACKET_ALIGNMENT
+       ieee80211_rx_h_verify_ip_alignment,
+#endif
        NULL
 };
 
@@ -1679,7 +1719,6 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
        struct ieee80211_sub_if_data *prev = NULL;
        struct sk_buff *skb_new;
        u8 *bssid;
-       int hdrlen;
 
        hdr = (struct ieee80211_hdr *) skb->data;
        memset(&rx, 0, sizeof(rx));
@@ -1691,18 +1730,6 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
        rx.fc = le16_to_cpu(hdr->frame_control);
        type = rx.fc & IEEE80211_FCTL_FTYPE;
 
-       /*
-        * Drivers are required to align the payload data to a four-byte
-        * boundary, so the last two bits of the address where it starts
-        * may not be set. The header is required to be directly before
-        * the payload data, padding like atheros hardware adds which is
-        * inbetween the 802.11 header and the payload is not supported,
-        * the driver is required to move the 802.11 header further back
-        * in that case.
-        */
-       hdrlen = ieee80211_get_hdrlen(rx.fc);
-       WARN_ON_ONCE(((unsigned long)(skb->data + hdrlen)) & 3);
-
        if (type == IEEE80211_FTYPE_DATA || type == IEEE80211_FTYPE_MGMT)
                local->dot11ReceivedFragmentCount++;
 
@@ -1952,7 +1979,7 @@ static u8 ieee80211_rx_reorder_ampdu(struct ieee80211_local *local,
                goto end_reorder;
 
        /* null data frames are excluded */
-       if (unlikely(fc & IEEE80211_STYPE_QOS_NULLFUNC))
+       if (unlikely(fc & IEEE80211_STYPE_NULLFUNC))
                goto end_reorder;
 
        /* new un-ordered ampdu frame - process it */
index 078fff0335ad2170ca06a60ad781fcfa0d08018e..327e847d2702d8e647ca656b5e89db6ba2ca74fd 100644 (file)
@@ -40,7 +40,7 @@
 
 #define NF_CONNTRACK_VERSION   "0.5.0"
 
-DEFINE_RWLOCK(nf_conntrack_lock);
+DEFINE_SPINLOCK(nf_conntrack_lock);
 EXPORT_SYMBOL_GPL(nf_conntrack_lock);
 
 /* nf_conntrack_standalone needs this */
@@ -73,15 +73,19 @@ static unsigned int nf_conntrack_hash_rnd;
 static u_int32_t __hash_conntrack(const struct nf_conntrack_tuple *tuple,
                                  unsigned int size, unsigned int rnd)
 {
-       unsigned int a, b;
-
-       a = jhash2(tuple->src.u3.all, ARRAY_SIZE(tuple->src.u3.all),
-                  (tuple->src.l3num << 16) | tuple->dst.protonum);
-       b = jhash2(tuple->dst.u3.all, ARRAY_SIZE(tuple->dst.u3.all),
-                  ((__force __u16)tuple->src.u.all << 16) |
-                   (__force __u16)tuple->dst.u.all);
-
-       return ((u64)jhash_2words(a, b, rnd) * size) >> 32;
+       unsigned int n;
+       u_int32_t h;
+
+       /* The direction must be ignored, so we hash everything up to the
+        * destination ports (which is a multiple of 4) and treat the last
+        * three bytes manually.
+        */
+       n = (sizeof(tuple->src) + sizeof(tuple->dst.u3)) / sizeof(u32);
+       h = jhash2((u32 *)tuple, n,
+                  rnd ^ (((__force __u16)tuple->dst.u.all << 16) |
+                         tuple->dst.protonum));
+
+       return ((u64)h * size) >> 32;
 }
 
 static inline u_int32_t hash_conntrack(const struct nf_conntrack_tuple *tuple)
@@ -166,8 +170,8 @@ static void
 clean_from_lists(struct nf_conn *ct)
 {
        pr_debug("clean_from_lists(%p)\n", ct);
-       hlist_del(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnode);
-       hlist_del(&ct->tuplehash[IP_CT_DIR_REPLY].hnode);
+       hlist_del_rcu(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnode);
+       hlist_del_rcu(&ct->tuplehash[IP_CT_DIR_REPLY].hnode);
 
        /* Destroy all pending expectations */
        nf_ct_remove_expectations(ct);
@@ -199,7 +203,7 @@ destroy_conntrack(struct nf_conntrack *nfct)
 
        rcu_read_unlock();
 
-       write_lock_bh(&nf_conntrack_lock);
+       spin_lock_bh(&nf_conntrack_lock);
        /* Expectations will have been removed in clean_from_lists,
         * except TFTP can create an expectation on the first packet,
         * before connection is in the list, so we need to clean here,
@@ -213,7 +217,7 @@ destroy_conntrack(struct nf_conntrack *nfct)
        }
 
        NF_CT_STAT_INC(delete);
-       write_unlock_bh(&nf_conntrack_lock);
+       spin_unlock_bh(&nf_conntrack_lock);
 
        if (ct->master)
                nf_ct_put(ct->master);
@@ -236,26 +240,24 @@ static void death_by_timeout(unsigned long ul_conntrack)
                rcu_read_unlock();
        }
 
-       write_lock_bh(&nf_conntrack_lock);
+       spin_lock_bh(&nf_conntrack_lock);
        /* Inside lock so preempt is disabled on module removal path.
         * Otherwise we can get spurious warnings. */
        NF_CT_STAT_INC(delete_list);
        clean_from_lists(ct);
-       write_unlock_bh(&nf_conntrack_lock);
+       spin_unlock_bh(&nf_conntrack_lock);
        nf_ct_put(ct);
 }
 
 struct nf_conntrack_tuple_hash *
-__nf_conntrack_find(const struct nf_conntrack_tuple *tuple,
-                   const struct nf_conn *ignored_conntrack)
+__nf_conntrack_find(const struct nf_conntrack_tuple *tuple)
 {
        struct nf_conntrack_tuple_hash *h;
        struct hlist_node *n;
        unsigned int hash = hash_conntrack(tuple);
 
-       hlist_for_each_entry(h, n, &nf_conntrack_hash[hash], hnode) {
-               if (nf_ct_tuplehash_to_ctrack(h) != ignored_conntrack &&
-                   nf_ct_tuple_equal(tuple, &h->tuple)) {
+       hlist_for_each_entry_rcu(h, n, &nf_conntrack_hash[hash], hnode) {
+               if (nf_ct_tuple_equal(tuple, &h->tuple)) {
                        NF_CT_STAT_INC(found);
                        return h;
                }
@@ -271,12 +273,16 @@ struct nf_conntrack_tuple_hash *
 nf_conntrack_find_get(const struct nf_conntrack_tuple *tuple)
 {
        struct nf_conntrack_tuple_hash *h;
+       struct nf_conn *ct;
 
-       read_lock_bh(&nf_conntrack_lock);
-       h = __nf_conntrack_find(tuple, NULL);
-       if (h)
-               atomic_inc(&nf_ct_tuplehash_to_ctrack(h)->ct_general.use);
-       read_unlock_bh(&nf_conntrack_lock);
+       rcu_read_lock();
+       h = __nf_conntrack_find(tuple);
+       if (h) {
+               ct = nf_ct_tuplehash_to_ctrack(h);
+               if (unlikely(!atomic_inc_not_zero(&ct->ct_general.use)))
+                       h = NULL;
+       }
+       rcu_read_unlock();
 
        return h;
 }
@@ -286,10 +292,10 @@ static void __nf_conntrack_hash_insert(struct nf_conn *ct,
                                       unsigned int hash,
                                       unsigned int repl_hash)
 {
-       hlist_add_head(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnode,
-                      &nf_conntrack_hash[hash]);
-       hlist_add_head(&ct->tuplehash[IP_CT_DIR_REPLY].hnode,
-                      &nf_conntrack_hash[repl_hash]);
+       hlist_add_head_rcu(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnode,
+                          &nf_conntrack_hash[hash]);
+       hlist_add_head_rcu(&ct->tuplehash[IP_CT_DIR_REPLY].hnode,
+                          &nf_conntrack_hash[repl_hash]);
 }
 
 void nf_conntrack_hash_insert(struct nf_conn *ct)
@@ -299,9 +305,9 @@ void nf_conntrack_hash_insert(struct nf_conn *ct)
        hash = hash_conntrack(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
        repl_hash = hash_conntrack(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
 
-       write_lock_bh(&nf_conntrack_lock);
+       spin_lock_bh(&nf_conntrack_lock);
        __nf_conntrack_hash_insert(ct, hash, repl_hash);
-       write_unlock_bh(&nf_conntrack_lock);
+       spin_unlock_bh(&nf_conntrack_lock);
 }
 EXPORT_SYMBOL_GPL(nf_conntrack_hash_insert);
 
@@ -338,7 +344,7 @@ __nf_conntrack_confirm(struct sk_buff *skb)
        NF_CT_ASSERT(!nf_ct_is_confirmed(ct));
        pr_debug("Confirming conntrack %p\n", ct);
 
-       write_lock_bh(&nf_conntrack_lock);
+       spin_lock_bh(&nf_conntrack_lock);
 
        /* See if there's one in the list already, including reverse:
           NAT could have grabbed it without realizing, since we're
@@ -364,7 +370,7 @@ __nf_conntrack_confirm(struct sk_buff *skb)
        atomic_inc(&ct->ct_general.use);
        set_bit(IPS_CONFIRMED_BIT, &ct->status);
        NF_CT_STAT_INC(insert);
-       write_unlock_bh(&nf_conntrack_lock);
+       spin_unlock_bh(&nf_conntrack_lock);
        help = nfct_help(ct);
        if (help && help->helper)
                nf_conntrack_event_cache(IPCT_HELPER, skb);
@@ -379,7 +385,7 @@ __nf_conntrack_confirm(struct sk_buff *skb)
 
 out:
        NF_CT_STAT_INC(insert_failed);
-       write_unlock_bh(&nf_conntrack_lock);
+       spin_unlock_bh(&nf_conntrack_lock);
        return NF_DROP;
 }
 EXPORT_SYMBOL_GPL(__nf_conntrack_confirm);
@@ -391,12 +397,22 @@ nf_conntrack_tuple_taken(const struct nf_conntrack_tuple *tuple,
                         const struct nf_conn *ignored_conntrack)
 {
        struct nf_conntrack_tuple_hash *h;
+       struct hlist_node *n;
+       unsigned int hash = hash_conntrack(tuple);
 
-       read_lock_bh(&nf_conntrack_lock);
-       h = __nf_conntrack_find(tuple, ignored_conntrack);
-       read_unlock_bh(&nf_conntrack_lock);
+       rcu_read_lock();
+       hlist_for_each_entry_rcu(h, n, &nf_conntrack_hash[hash], hnode) {
+               if (nf_ct_tuplehash_to_ctrack(h) != ignored_conntrack &&
+                   nf_ct_tuple_equal(tuple, &h->tuple)) {
+                       NF_CT_STAT_INC(found);
+                       rcu_read_unlock();
+                       return 1;
+               }
+               NF_CT_STAT_INC(searched);
+       }
+       rcu_read_unlock();
 
-       return h != NULL;
+       return 0;
 }
 EXPORT_SYMBOL_GPL(nf_conntrack_tuple_taken);
 
@@ -404,7 +420,7 @@ EXPORT_SYMBOL_GPL(nf_conntrack_tuple_taken);
 
 /* There's a small race here where we may free a just-assured
    connection.  Too bad: we're in trouble anyway. */
-static int early_drop(unsigned int hash)
+static noinline int early_drop(unsigned int hash)
 {
        /* Use oldest entry, which is roughly LRU */
        struct nf_conntrack_tuple_hash *h;
@@ -413,21 +429,23 @@ static int early_drop(unsigned int hash)
        unsigned int i, cnt = 0;
        int dropped = 0;
 
-       read_lock_bh(&nf_conntrack_lock);
+       rcu_read_lock();
        for (i = 0; i < nf_conntrack_htable_size; i++) {
-               hlist_for_each_entry(h, n, &nf_conntrack_hash[hash], hnode) {
+               hlist_for_each_entry_rcu(h, n, &nf_conntrack_hash[hash],
+                                        hnode) {
                        tmp = nf_ct_tuplehash_to_ctrack(h);
                        if (!test_bit(IPS_ASSURED_BIT, &tmp->status))
                                ct = tmp;
                        cnt++;
                }
+
+               if (ct && unlikely(!atomic_inc_not_zero(&ct->ct_general.use)))
+                       ct = NULL;
                if (ct || cnt >= NF_CT_EVICTION_RANGE)
                        break;
                hash = (hash + 1) % nf_conntrack_htable_size;
        }
-       if (ct)
-               atomic_inc(&ct->ct_general.use);
-       read_unlock_bh(&nf_conntrack_lock);
+       rcu_read_unlock();
 
        if (!ct)
                return dropped;
@@ -444,7 +462,7 @@ static int early_drop(unsigned int hash)
 struct nf_conn *nf_conntrack_alloc(const struct nf_conntrack_tuple *orig,
                                   const struct nf_conntrack_tuple *repl)
 {
-       struct nf_conn *conntrack = NULL;
+       struct nf_conn *ct = NULL;
 
        if (unlikely(!nf_conntrack_hash_rnd_initted)) {
                get_random_bytes(&nf_conntrack_hash_rnd, 4);
@@ -454,8 +472,8 @@ struct nf_conn *nf_conntrack_alloc(const struct nf_conntrack_tuple *orig,
        /* We don't want any race condition at early drop stage */
        atomic_inc(&nf_conntrack_count);
 
-       if (nf_conntrack_max
-           && atomic_read(&nf_conntrack_count) > nf_conntrack_max) {
+       if (nf_conntrack_max &&
+           unlikely(atomic_read(&nf_conntrack_count) > nf_conntrack_max)) {
                unsigned int hash = hash_conntrack(orig);
                if (!early_drop(hash)) {
                        atomic_dec(&nf_conntrack_count);
@@ -467,30 +485,37 @@ struct nf_conn *nf_conntrack_alloc(const struct nf_conntrack_tuple *orig,
                }
        }
 
-       conntrack = kmem_cache_zalloc(nf_conntrack_cachep, GFP_ATOMIC);
-       if (conntrack == NULL) {
+       ct = kmem_cache_zalloc(nf_conntrack_cachep, GFP_ATOMIC);
+       if (ct == NULL) {
                pr_debug("nf_conntrack_alloc: Can't alloc conntrack.\n");
                atomic_dec(&nf_conntrack_count);
                return ERR_PTR(-ENOMEM);
        }
 
-       atomic_set(&conntrack->ct_general.use, 1);
-       conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple = *orig;
-       conntrack->tuplehash[IP_CT_DIR_REPLY].tuple = *repl;
+       atomic_set(&ct->ct_general.use, 1);
+       ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple = *orig;
+       ct->tuplehash[IP_CT_DIR_REPLY].tuple = *repl;
        /* Don't set timer yet: wait for confirmation */
-       setup_timer(&conntrack->timeout, death_by_timeout,
-                   (unsigned long)conntrack);
+       setup_timer(&ct->timeout, death_by_timeout, (unsigned long)ct);
+       INIT_RCU_HEAD(&ct->rcu);
 
-       return conntrack;
+       return ct;
 }
 EXPORT_SYMBOL_GPL(nf_conntrack_alloc);
 
-void nf_conntrack_free(struct nf_conn *conntrack)
+static void nf_conntrack_free_rcu(struct rcu_head *head)
 {
-       nf_ct_ext_free(conntrack);
-       kmem_cache_free(nf_conntrack_cachep, conntrack);
+       struct nf_conn *ct = container_of(head, struct nf_conn, rcu);
+
+       nf_ct_ext_free(ct);
+       kmem_cache_free(nf_conntrack_cachep, ct);
        atomic_dec(&nf_conntrack_count);
 }
+
+void nf_conntrack_free(struct nf_conn *ct)
+{
+       call_rcu(&ct->rcu, nf_conntrack_free_rcu);
+}
 EXPORT_SYMBOL_GPL(nf_conntrack_free);
 
 /* Allocate a new conntrack: we return -ENOMEM if classification
@@ -502,7 +527,7 @@ init_conntrack(const struct nf_conntrack_tuple *tuple,
               struct sk_buff *skb,
               unsigned int dataoff)
 {
-       struct nf_conn *conntrack;
+       struct nf_conn *ct;
        struct nf_conn_help *help;
        struct nf_conntrack_tuple repl_tuple;
        struct nf_conntrack_expect *exp;
@@ -512,46 +537,46 @@ init_conntrack(const struct nf_conntrack_tuple *tuple,
                return NULL;
        }
 
-       conntrack = nf_conntrack_alloc(tuple, &repl_tuple);
-       if (conntrack == NULL || IS_ERR(conntrack)) {
+       ct = nf_conntrack_alloc(tuple, &repl_tuple);
+       if (ct == NULL || IS_ERR(ct)) {
                pr_debug("Can't allocate conntrack.\n");
-               return (struct nf_conntrack_tuple_hash *)conntrack;
+               return (struct nf_conntrack_tuple_hash *)ct;
        }
 
-       if (!l4proto->new(conntrack, skb, dataoff)) {
-               nf_conntrack_free(conntrack);
+       if (!l4proto->new(ct, skb, dataoff)) {
+               nf_conntrack_free(ct);
                pr_debug("init conntrack: can't track with proto module\n");
                return NULL;
        }
 
-       write_lock_bh(&nf_conntrack_lock);
+       spin_lock_bh(&nf_conntrack_lock);
        exp = nf_ct_find_expectation(tuple);
        if (exp) {
                pr_debug("conntrack: expectation arrives ct=%p exp=%p\n",
-                        conntrack, exp);
+                        ct, exp);
                /* Welcome, Mr. Bond.  We've been expecting you... */
-               __set_bit(IPS_EXPECTED_BIT, &conntrack->status);
-               conntrack->master = exp->master;
+               __set_bit(IPS_EXPECTED_BIT, &ct->status);
+               ct->master = exp->master;
                if (exp->helper) {
-                       help = nf_ct_helper_ext_add(conntrack, GFP_ATOMIC);
+                       help = nf_ct_helper_ext_add(ct, GFP_ATOMIC);
                        if (help)
                                rcu_assign_pointer(help->helper, exp->helper);
                }
 
 #ifdef CONFIG_NF_CONNTRACK_MARK
-               conntrack->mark = exp->master->mark;
+               ct->mark = exp->master->mark;
 #endif
 #ifdef CONFIG_NF_CONNTRACK_SECMARK
-               conntrack->secmark = exp->master->secmark;
+               ct->secmark = exp->master->secmark;
 #endif
-               nf_conntrack_get(&conntrack->master->ct_general);
+               nf_conntrack_get(&ct->master->ct_general);
                NF_CT_STAT_INC(expect_new);
        } else {
                struct nf_conntrack_helper *helper;
 
                helper = __nf_ct_helper_find(&repl_tuple);
                if (helper) {
-                       help = nf_ct_helper_ext_add(conntrack, GFP_ATOMIC);
+                       help = nf_ct_helper_ext_add(ct, GFP_ATOMIC);
                        if (help)
                                rcu_assign_pointer(help->helper, helper);
                }
@@ -559,18 +584,17 @@ init_conntrack(const struct nf_conntrack_tuple *tuple,
        }
 
        /* Overload tuple linked list to put us in unconfirmed list. */
-       hlist_add_head(&conntrack->tuplehash[IP_CT_DIR_ORIGINAL].hnode,
-                      &unconfirmed);
+       hlist_add_head(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnode, &unconfirmed);
 
-       write_unlock_bh(&nf_conntrack_lock);
+       spin_unlock_bh(&nf_conntrack_lock);
 
        if (exp) {
                if (exp->expectfn)
-                       exp->expectfn(conntrack, exp);
+                       exp->expectfn(ct, exp);
                nf_ct_expect_put(exp);
        }
 
-       return &conntrack->tuplehash[IP_CT_DIR_ORIGINAL];
+       return &ct->tuplehash[IP_CT_DIR_ORIGINAL];
 }
 
 /* On success, returns conntrack ptr, sets skb->nfct and ctinfo */
@@ -729,7 +753,6 @@ void nf_conntrack_alter_reply(struct nf_conn *ct,
        struct nf_conn_help *help = nfct_help(ct);
        struct nf_conntrack_helper *helper;
 
-       write_lock_bh(&nf_conntrack_lock);
        /* Should be unconfirmed, so not in hash table yet */
        NF_CT_ASSERT(!nf_ct_is_confirmed(ct));
 
@@ -738,8 +761,9 @@ void nf_conntrack_alter_reply(struct nf_conn *ct,
 
        ct->tuplehash[IP_CT_DIR_REPLY].tuple = *newreply;
        if (ct->master || (help && help->expecting != 0))
-               goto out;
+               return;
 
+       rcu_read_lock();
        helper = __nf_ct_helper_find(newreply);
        if (helper == NULL) {
                if (help)
@@ -757,7 +781,7 @@ void nf_conntrack_alter_reply(struct nf_conn *ct,
 
        rcu_assign_pointer(help->helper, helper);
 out:
-       write_unlock_bh(&nf_conntrack_lock);
+       rcu_read_unlock();
 }
 EXPORT_SYMBOL_GPL(nf_conntrack_alter_reply);
 
@@ -773,13 +797,11 @@ void __nf_ct_refresh_acct(struct nf_conn *ct,
        NF_CT_ASSERT(ct->timeout.data == (unsigned long)ct);
        NF_CT_ASSERT(skb);
 
-       write_lock_bh(&nf_conntrack_lock);
+       spin_lock_bh(&nf_conntrack_lock);
 
        /* Only update if this is not a fixed timeout */
-       if (test_bit(IPS_FIXED_TIMEOUT_BIT, &ct->status)) {
-               write_unlock_bh(&nf_conntrack_lock);
-               return;
-       }
+       if (test_bit(IPS_FIXED_TIMEOUT_BIT, &ct->status))
+               goto acct;
 
        /* If not in hash table, timer will not be active yet */
        if (!nf_ct_is_confirmed(ct)) {
@@ -799,6 +821,7 @@ void __nf_ct_refresh_acct(struct nf_conn *ct,
                }
        }
 
+acct:
 #ifdef CONFIG_NF_CT_ACCT
        if (do_acct) {
                ct->counters[CTINFO2DIR(ctinfo)].packets++;
@@ -811,7 +834,7 @@ void __nf_ct_refresh_acct(struct nf_conn *ct,
        }
 #endif
 
-       write_unlock_bh(&nf_conntrack_lock);
+       spin_unlock_bh(&nf_conntrack_lock);
 
        /* must be unlocked when calling event cache */
        if (event)
@@ -879,14 +902,6 @@ static void nf_conntrack_attach(struct sk_buff *nskb, struct sk_buff *skb)
        nf_conntrack_get(nskb->nfct);
 }
 
-static inline int
-do_iter(const struct nf_conntrack_tuple_hash *i,
-       int (*iter)(struct nf_conn *i, void *data),
-       void *data)
-{
-       return iter(nf_ct_tuplehash_to_ctrack(i), data);
-}
-
 /* Bring out ya dead! */
 static struct nf_conn *
 get_next_corpse(int (*iter)(struct nf_conn *i, void *data),
@@ -896,7 +911,7 @@ get_next_corpse(int (*iter)(struct nf_conn *i, void *data),
        struct nf_conn *ct;
        struct hlist_node *n;
 
-       write_lock_bh(&nf_conntrack_lock);
+       spin_lock_bh(&nf_conntrack_lock);
        for (; *bucket < nf_conntrack_htable_size; (*bucket)++) {
                hlist_for_each_entry(h, n, &nf_conntrack_hash[*bucket], hnode) {
                        ct = nf_ct_tuplehash_to_ctrack(h);
@@ -909,11 +924,11 @@ get_next_corpse(int (*iter)(struct nf_conn *i, void *data),
                if (iter(ct, data))
                        set_bit(IPS_DYING_BIT, &ct->status);
        }
-       write_unlock_bh(&nf_conntrack_lock);
+       spin_unlock_bh(&nf_conntrack_lock);
        return NULL;
 found:
        atomic_inc(&ct->ct_general.use);
-       write_unlock_bh(&nf_conntrack_lock);
+       spin_unlock_bh(&nf_conntrack_lock);
        return ct;
 }
 
@@ -939,7 +954,7 @@ static int kill_all(struct nf_conn *i, void *data)
        return 1;
 }
 
-void nf_ct_free_hashtable(struct hlist_head *hash, int vmalloced, int size)
+void nf_ct_free_hashtable(struct hlist_head *hash, int vmalloced, unsigned int size)
 {
        if (vmalloced)
                vfree(hash);
@@ -988,7 +1003,7 @@ void nf_conntrack_cleanup(void)
        nf_conntrack_expect_fini();
 }
 
-struct hlist_head *nf_ct_alloc_hashtable(int *sizep, int *vmalloced)
+struct hlist_head *nf_ct_alloc_hashtable(unsigned int *sizep, int *vmalloced)
 {
        struct hlist_head *hash;
        unsigned int size, i;
@@ -1015,8 +1030,8 @@ EXPORT_SYMBOL_GPL(nf_ct_alloc_hashtable);
 
 int nf_conntrack_set_hashsize(const char *val, struct kernel_param *kp)
 {
-       int i, bucket, hashsize, vmalloced;
-       int old_vmalloced, old_size;
+       int i, bucket, vmalloced, old_vmalloced;
+       unsigned int hashsize, old_size;
        int rnd;
        struct hlist_head *hash, *old_hash;
        struct nf_conntrack_tuple_hash *h;
@@ -1025,7 +1040,7 @@ int nf_conntrack_set_hashsize(const char *val, struct kernel_param *kp)
        if (!nf_conntrack_htable_size)
                return param_set_uint(val, kp);
 
-       hashsize = simple_strtol(val, NULL, 0);
+       hashsize = simple_strtoul(val, NULL, 0);
        if (!hashsize)
                return -EINVAL;
 
@@ -1037,12 +1052,17 @@ int nf_conntrack_set_hashsize(const char *val, struct kernel_param *kp)
         * use a newrandom seed */
        get_random_bytes(&rnd, 4);
 
-       write_lock_bh(&nf_conntrack_lock);
+       /* Lookups in the old hash might happen in parallel, which means we
+        * might get false negatives during connection lookup. New connections
+        * created because of a false negative won't make it into the hash
+        * though since that required taking the lock.
+        */
+       spin_lock_bh(&nf_conntrack_lock);
        for (i = 0; i < nf_conntrack_htable_size; i++) {
                while (!hlist_empty(&nf_conntrack_hash[i])) {
                        h = hlist_entry(nf_conntrack_hash[i].first,
                                        struct nf_conntrack_tuple_hash, hnode);
-                       hlist_del(&h->hnode);
+                       hlist_del_rcu(&h->hnode);
                        bucket = __hash_conntrack(&h->tuple, hashsize, rnd);
                        hlist_add_head(&h->hnode, &hash[bucket]);
                }
@@ -1055,7 +1075,7 @@ int nf_conntrack_set_hashsize(const char *val, struct kernel_param *kp)
        nf_conntrack_vmalloc = vmalloced;
        nf_conntrack_hash = hash;
        nf_conntrack_hash_rnd = rnd;
-       write_unlock_bh(&nf_conntrack_lock);
+       spin_unlock_bh(&nf_conntrack_lock);
 
        nf_ct_free_hashtable(old_hash, old_vmalloced, old_size);
        return 0;
index e0cd9d00aa61e872f2f769c142e065a529fcdf23..e06bf0028bb18eaea80e40fb633d4aac495a038f 100644 (file)
@@ -50,7 +50,7 @@ void nf_ct_unlink_expect(struct nf_conntrack_expect *exp)
        NF_CT_ASSERT(master_help);
        NF_CT_ASSERT(!timer_pending(&exp->timeout));
 
-       hlist_del(&exp->hnode);
+       hlist_del_rcu(&exp->hnode);
        nf_ct_expect_count--;
 
        hlist_del(&exp->lnode);
@@ -65,9 +65,9 @@ static void nf_ct_expectation_timed_out(unsigned long ul_expect)
 {
        struct nf_conntrack_expect *exp = (void *)ul_expect;
 
-       write_lock_bh(&nf_conntrack_lock);
+       spin_lock_bh(&nf_conntrack_lock);
        nf_ct_unlink_expect(exp);
-       write_unlock_bh(&nf_conntrack_lock);
+       spin_unlock_bh(&nf_conntrack_lock);
        nf_ct_expect_put(exp);
 }
 
@@ -97,7 +97,7 @@ __nf_ct_expect_find(const struct nf_conntrack_tuple *tuple)
                return NULL;
 
        h = nf_ct_expect_dst_hash(tuple);
-       hlist_for_each_entry(i, n, &nf_ct_expect_hash[h], hnode) {
+       hlist_for_each_entry_rcu(i, n, &nf_ct_expect_hash[h], hnode) {
                if (nf_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask))
                        return i;
        }
@@ -111,11 +111,11 @@ nf_ct_expect_find_get(const struct nf_conntrack_tuple *tuple)
 {
        struct nf_conntrack_expect *i;
 
-       read_lock_bh(&nf_conntrack_lock);
+       rcu_read_lock();
        i = __nf_ct_expect_find(tuple);
-       if (i)
-               atomic_inc(&i->use);
-       read_unlock_bh(&nf_conntrack_lock);
+       if (i && !atomic_inc_not_zero(&i->use))
+               i = NULL;
+       rcu_read_unlock();
 
        return i;
 }
@@ -201,12 +201,12 @@ static inline int expect_matches(const struct nf_conntrack_expect *a,
 /* Generally a bad idea to call this: could have matched already. */
 void nf_ct_unexpect_related(struct nf_conntrack_expect *exp)
 {
-       write_lock_bh(&nf_conntrack_lock);
+       spin_lock_bh(&nf_conntrack_lock);
        if (del_timer(&exp->timeout)) {
                nf_ct_unlink_expect(exp);
                nf_ct_expect_put(exp);
        }
-       write_unlock_bh(&nf_conntrack_lock);
+       spin_unlock_bh(&nf_conntrack_lock);
 }
 EXPORT_SYMBOL_GPL(nf_ct_unexpect_related);
 
@@ -223,6 +223,7 @@ struct nf_conntrack_expect *nf_ct_expect_alloc(struct nf_conn *me)
 
        new->master = me;
        atomic_set(&new->use, 1);
+       INIT_RCU_HEAD(&new->rcu);
        return new;
 }
 EXPORT_SYMBOL_GPL(nf_ct_expect_alloc);
@@ -278,10 +279,18 @@ void nf_ct_expect_init(struct nf_conntrack_expect *exp, int family,
 }
 EXPORT_SYMBOL_GPL(nf_ct_expect_init);
 
+static void nf_ct_expect_free_rcu(struct rcu_head *head)
+{
+       struct nf_conntrack_expect *exp;
+
+       exp = container_of(head, struct nf_conntrack_expect, rcu);
+       kmem_cache_free(nf_ct_expect_cachep, exp);
+}
+
 void nf_ct_expect_put(struct nf_conntrack_expect *exp)
 {
        if (atomic_dec_and_test(&exp->use))
-               kmem_cache_free(nf_ct_expect_cachep, exp);
+               call_rcu(&exp->rcu, nf_ct_expect_free_rcu);
 }
 EXPORT_SYMBOL_GPL(nf_ct_expect_put);
 
@@ -295,7 +304,7 @@ static void nf_ct_expect_insert(struct nf_conntrack_expect *exp)
        hlist_add_head(&exp->lnode, &master_help->expectations);
        master_help->expecting++;
 
-       hlist_add_head(&exp->hnode, &nf_ct_expect_hash[h]);
+       hlist_add_head_rcu(&exp->hnode, &nf_ct_expect_hash[h]);
        nf_ct_expect_count++;
 
        setup_timer(&exp->timeout, nf_ct_expectation_timed_out,
@@ -346,7 +355,7 @@ int nf_ct_expect_related(struct nf_conntrack_expect *expect)
 
        NF_CT_ASSERT(master_help);
 
-       write_lock_bh(&nf_conntrack_lock);
+       spin_lock_bh(&nf_conntrack_lock);
        if (!master_help->helper) {
                ret = -ESHUTDOWN;
                goto out;
@@ -381,7 +390,7 @@ int nf_ct_expect_related(struct nf_conntrack_expect *expect)
        nf_ct_expect_event(IPEXP_NEW, expect);
        ret = 0;
 out:
-       write_unlock_bh(&nf_conntrack_lock);
+       spin_unlock_bh(&nf_conntrack_lock);
        return ret;
 }
 EXPORT_SYMBOL_GPL(nf_ct_expect_related);
@@ -394,10 +403,12 @@ struct ct_expect_iter_state {
 static struct hlist_node *ct_expect_get_first(struct seq_file *seq)
 {
        struct ct_expect_iter_state *st = seq->private;
+       struct hlist_node *n;
 
        for (st->bucket = 0; st->bucket < nf_ct_expect_hsize; st->bucket++) {
-               if (!hlist_empty(&nf_ct_expect_hash[st->bucket]))
-                       return nf_ct_expect_hash[st->bucket].first;
+               n = rcu_dereference(nf_ct_expect_hash[st->bucket].first);
+               if (n)
+                       return n;
        }
        return NULL;
 }
@@ -407,11 +418,11 @@ static struct hlist_node *ct_expect_get_next(struct seq_file *seq,
 {
        struct ct_expect_iter_state *st = seq->private;
 
-       head = head->next;
+       head = rcu_dereference(head->next);
        while (head == NULL) {
                if (++st->bucket >= nf_ct_expect_hsize)
                        return NULL;
-               head = nf_ct_expect_hash[st->bucket].first;
+               head = rcu_dereference(nf_ct_expect_hash[st->bucket].first);
        }
        return head;
 }
@@ -427,8 +438,9 @@ static struct hlist_node *ct_expect_get_idx(struct seq_file *seq, loff_t pos)
 }
 
 static void *exp_seq_start(struct seq_file *seq, loff_t *pos)
+       __acquires(RCU)
 {
-       read_lock_bh(&nf_conntrack_lock);
+       rcu_read_lock();
        return ct_expect_get_idx(seq, *pos);
 }
 
@@ -439,8 +451,9 @@ static void *exp_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 }
 
 static void exp_seq_stop(struct seq_file *seq, void *v)
+       __releases(RCU)
 {
-       read_unlock_bh(&nf_conntrack_lock);
+       rcu_read_unlock();
 }
 
 static int exp_seq_show(struct seq_file *s, void *v)
index ff66fba514fd0c2ffe64a78e51bafb5761ceee54..867882313e499931b9e89416326937398a655ccb 100644 (file)
@@ -87,7 +87,7 @@ typedef struct field_t {
        unsigned char ub;
        unsigned short attr;
        unsigned short offset;
-       struct field_t *fields;
+       const struct field_t *fields;
 } field_t;
 
 /* Bit Stream */
@@ -96,7 +96,7 @@ typedef struct {
        unsigned char *beg;
        unsigned char *end;
        unsigned char *cur;
-       unsigned bit;
+       unsigned int bit;
 } bitstr_t;
 
 /* Tool Functions */
@@ -104,29 +104,29 @@ typedef struct {
 #define INC_BITS(bs,b) if(((bs)->bit+=(b))>7){(bs)->cur+=(bs)->bit>>3;(bs)->bit&=7;}
 #define BYTE_ALIGN(bs) if((bs)->bit){(bs)->cur++;(bs)->bit=0;}
 #define CHECK_BOUND(bs,n) if((bs)->cur+(n)>(bs)->end)return(H323_ERROR_BOUND)
-static unsigned get_len(bitstr_t * bs);
-static unsigned get_bit(bitstr_t * bs);
-static unsigned get_bits(bitstr_t * bs, unsigned b);
-static unsigned get_bitmap(bitstr_t * bs, unsigned b);
-static unsigned get_uint(bitstr_t * bs, int b);
+static unsigned int get_len(bitstr_t *bs);
+static unsigned int get_bit(bitstr_t *bs);
+static unsigned int get_bits(bitstr_t *bs, unsigned int b);
+static unsigned int get_bitmap(bitstr_t *bs, unsigned int b);
+static unsigned int get_uint(bitstr_t *bs, int b);
 
 /* Decoder Functions */
-static int decode_nul(bitstr_t * bs, field_t * f, char *base, int level);
-static int decode_bool(bitstr_t * bs, field_t * f, char *base, int level);
-static int decode_oid(bitstr_t * bs, field_t * f, char *base, int level);
-static int decode_int(bitstr_t * bs, field_t * f, char *base, int level);
-static int decode_enum(bitstr_t * bs, field_t * f, char *base, int level);
-static int decode_bitstr(bitstr_t * bs, field_t * f, char *base, int level);
-static int decode_numstr(bitstr_t * bs, field_t * f, char *base, int level);
-static int decode_octstr(bitstr_t * bs, field_t * f, char *base, int level);
-static int decode_bmpstr(bitstr_t * bs, field_t * f, char *base, int level);
-static int decode_seq(bitstr_t * bs, field_t * f, char *base, int level);
-static int decode_seqof(bitstr_t * bs, field_t * f, char *base, int level);
-static int decode_choice(bitstr_t * bs, field_t * f, char *base, int level);
+static int decode_nul(bitstr_t *bs, const struct field_t *f, char *base, int level);
+static int decode_bool(bitstr_t *bs, const struct field_t *f, char *base, int level);
+static int decode_oid(bitstr_t *bs, const struct field_t *f, char *base, int level);
+static int decode_int(bitstr_t *bs, const struct field_t *f, char *base, int level);
+static int decode_enum(bitstr_t *bs, const struct field_t *f, char *base, int level);
+static int decode_bitstr(bitstr_t *bs, const struct field_t *f, char *base, int level);
+static int decode_numstr(bitstr_t *bs, const struct field_t *f, char *base, int level);
+static int decode_octstr(bitstr_t *bs, const struct field_t *f, char *base, int level);
+static int decode_bmpstr(bitstr_t *bs, const struct field_t *f, char *base, int level);
+static int decode_seq(bitstr_t *bs, const struct field_t *f, char *base, int level);
+static int decode_seqof(bitstr_t *bs, const struct field_t *f, char *base, int level);
+static int decode_choice(bitstr_t *bs, const struct field_t *f, char *base, int level);
 
 /* Decoder Functions Vector */
-typedef int (*decoder_t) (bitstr_t *, field_t *, char *, int);
-static decoder_t Decoders[] = {
+typedef int (*decoder_t)(bitstr_t *, const struct field_t *, char *, int);
+static const decoder_t Decoders[] = {
        decode_nul,
        decode_bool,
        decode_oid,
@@ -150,9 +150,9 @@ static decoder_t Decoders[] = {
  * Functions
  ****************************************************************************/
 /* Assume bs is aligned && v < 16384 */
-unsigned get_len(bitstr_t * bs)
+static unsigned int get_len(bitstr_t *bs)
 {
-       unsigned v;
+       unsigned int v;
 
        v = *bs->cur++;
 
@@ -166,9 +166,9 @@ unsigned get_len(bitstr_t * bs)
 }
 
 /****************************************************************************/
-unsigned get_bit(bitstr_t * bs)
+static unsigned int get_bit(bitstr_t *bs)
 {
-       unsigned b = (*bs->cur) & (0x80 >> bs->bit);
+       unsigned int b = (*bs->cur) & (0x80 >> bs->bit);
 
        INC_BIT(bs);
 
@@ -177,9 +177,9 @@ unsigned get_bit(bitstr_t * bs)
 
 /****************************************************************************/
 /* Assume b <= 8 */
-unsigned get_bits(bitstr_t * bs, unsigned b)
+static unsigned int get_bits(bitstr_t *bs, unsigned int b)
 {
-       unsigned v, l;
+       unsigned int v, l;
 
        v = (*bs->cur) & (0xffU >> bs->bit);
        l = b + bs->bit;
@@ -203,9 +203,9 @@ unsigned get_bits(bitstr_t * bs, unsigned b)
 
 /****************************************************************************/
 /* Assume b <= 32 */
-unsigned get_bitmap(bitstr_t * bs, unsigned b)
+static unsigned int get_bitmap(bitstr_t *bs, unsigned int b)
 {
-       unsigned v, l, shift, bytes;
+       unsigned int v, l, shift, bytes;
 
        if (!b)
                return 0;
@@ -213,18 +213,18 @@ unsigned get_bitmap(bitstr_t * bs, unsigned b)
        l = bs->bit + b;
 
        if (l < 8) {
-               v = (unsigned(*bs->cur) << (bs->bit + 24);
+               v = (unsigned int)(*bs->cur) << (bs->bit + 24);
                bs->bit = l;
        } else if (l == 8) {
-               v = (unsigned(*bs->cur++) << (bs->bit + 24);
+               v = (unsigned int)(*bs->cur++) << (bs->bit + 24);
                bs->bit = 0;
        } else {
                for (bytes = l >> 3, shift = 24, v = 0; bytes;
                     bytes--, shift -= 8)
-                       v |= (unsigned(*bs->cur++) << shift;
+                       v |= (unsigned int)(*bs->cur++) << shift;
 
                if (l < 32) {
-                       v |= (unsigned(*bs->cur) << shift;
+                       v |= (unsigned int)(*bs->cur) << shift;
                        v <<= bs->bit;
                } else if (l > 32) {
                        v <<= bs->bit;
@@ -242,9 +242,9 @@ unsigned get_bitmap(bitstr_t * bs, unsigned b)
 /****************************************************************************
  * Assume bs is aligned and sizeof(unsigned int) == 4
  ****************************************************************************/
-unsigned get_uint(bitstr_t * bs, int b)
+static unsigned int get_uint(bitstr_t *bs, int b)
 {
-       unsigned v = 0;
+       unsigned int v = 0;
 
        switch (b) {
        case 4:
@@ -264,7 +264,8 @@ unsigned get_uint(bitstr_t * bs, int b)
 }
 
 /****************************************************************************/
-int decode_nul(bitstr_t * bs, field_t * f, char *base, int level)
+static int decode_nul(bitstr_t *bs, const struct field_t *f,
+                      char *base, int level)
 {
        PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name);
 
@@ -272,7 +273,8 @@ int decode_nul(bitstr_t * bs, field_t * f, char *base, int level)
 }
 
 /****************************************************************************/
-int decode_bool(bitstr_t * bs, field_t * f, char *base, int level)
+static int decode_bool(bitstr_t *bs, const struct field_t *f,
+                       char *base, int level)
 {
        PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name);
 
@@ -283,7 +285,8 @@ int decode_bool(bitstr_t * bs, field_t * f, char *base, int level)
 }
 
 /****************************************************************************/
-int decode_oid(bitstr_t * bs, field_t * f, char *base, int level)
+static int decode_oid(bitstr_t *bs, const struct field_t *f,
+                      char *base, int level)
 {
        int len;
 
@@ -299,9 +302,10 @@ int decode_oid(bitstr_t * bs, field_t * f, char *base, int level)
 }
 
 /****************************************************************************/
-int decode_int(bitstr_t * bs, field_t * f, char *base, int level)
+static int decode_int(bitstr_t *bs, const struct field_t *f,
+                      char *base, int level)
 {
-       unsigned len;
+       unsigned int len;
 
        PRINT("%*.s%s", level * TAB_SIZE, " ", f->name);
 
@@ -318,9 +322,9 @@ int decode_int(bitstr_t * bs, field_t * f, char *base, int level)
                len = get_bits(bs, 2) + 1;
                BYTE_ALIGN(bs);
                if (base && (f->attr & DECODE)) {       /* timeToLive */
-                       unsigned v = get_uint(bs, len) + f->lb;
+                       unsigned int v = get_uint(bs, len) + f->lb;
                        PRINT(" = %u", v);
-                       *((unsigned *) (base + f->offset)) = v;
+                       *((unsigned int *)(base + f->offset)) = v;
                }
                bs->cur += len;
                break;
@@ -342,7 +346,8 @@ int decode_int(bitstr_t * bs, field_t * f, char *base, int level)
 }
 
 /****************************************************************************/
-int decode_enum(bitstr_t * bs, field_t * f, char *base, int level)
+static int decode_enum(bitstr_t *bs, const struct field_t *f,
+                       char *base, int level)
 {
        PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name);
 
@@ -357,9 +362,10 @@ int decode_enum(bitstr_t * bs, field_t * f, char *base, int level)
 }
 
 /****************************************************************************/
-int decode_bitstr(bitstr_t * bs, field_t * f, char *base, int level)
+static int decode_bitstr(bitstr_t *bs, const struct field_t *f,
+                         char *base, int level)
 {
-       unsigned len;
+       unsigned int len;
 
        PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name);
 
@@ -390,9 +396,10 @@ int decode_bitstr(bitstr_t * bs, field_t * f, char *base, int level)
 }
 
 /****************************************************************************/
-int decode_numstr(bitstr_t * bs, field_t * f, char *base, int level)
+static int decode_numstr(bitstr_t *bs, const struct field_t *f,
+                         char *base, int level)
 {
-       unsigned len;
+       unsigned int len;
 
        PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name);
 
@@ -407,9 +414,10 @@ int decode_numstr(bitstr_t * bs, field_t * f, char *base, int level)
 }
 
 /****************************************************************************/
-int decode_octstr(bitstr_t * bs, field_t * f, char *base, int level)
+static int decode_octstr(bitstr_t *bs, const struct field_t *f,
+                         char *base, int level)
 {
-       unsigned len;
+       unsigned int len;
 
        PRINT("%*.s%s", level * TAB_SIZE, " ", f->name);
 
@@ -424,7 +432,7 @@ int decode_octstr(bitstr_t * bs, field_t * f, char *base, int level)
                                             bs->cur[0], bs->cur[1],
                                             bs->cur[2], bs->cur[3],
                                             bs->cur[4] * 256 + bs->cur[5]));
-                               *((unsigned *) (base + f->offset)) =
+                               *((unsigned int *)(base + f->offset)) =
                                    bs->cur - bs->buf;
                        }
                }
@@ -455,9 +463,10 @@ int decode_octstr(bitstr_t * bs, field_t * f, char *base, int level)
 }
 
 /****************************************************************************/
-int decode_bmpstr(bitstr_t * bs, field_t * f, char *base, int level)
+static int decode_bmpstr(bitstr_t *bs, const struct field_t *f,
+                         char *base, int level)
 {
-       unsigned len;
+       unsigned int len;
 
        PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name);
 
@@ -480,11 +489,12 @@ int decode_bmpstr(bitstr_t * bs, field_t * f, char *base, int level)
 }
 
 /****************************************************************************/
-int decode_seq(bitstr_t * bs, field_t * f, char *base, int level)
+static int decode_seq(bitstr_t *bs, const struct field_t *f,
+                      char *base, int level)
 {
-       unsigned ext, bmp, i, opt, len = 0, bmp2, bmp2_len;
+       unsigned int ext, bmp, i, opt, len = 0, bmp2, bmp2_len;
        int err;
-       field_t *son;
+       const struct field_t *son;
        unsigned char *beg = NULL;
 
        PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name);
@@ -498,7 +508,7 @@ int decode_seq(bitstr_t * bs, field_t * f, char *base, int level)
        /* Get fields bitmap */
        bmp = get_bitmap(bs, f->sz);
        if (base)
-               *(unsigned *) base = bmp;
+               *(unsigned int *)base = bmp;
 
        /* Decode the root components */
        for (i = opt = 0, son = f->fields; i < f->lb; i++, son++) {
@@ -550,7 +560,7 @@ int decode_seq(bitstr_t * bs, field_t * f, char *base, int level)
        bmp2 = get_bitmap(bs, bmp2_len);
        bmp |= bmp2 >> f->sz;
        if (base)
-               *(unsigned *) base = bmp;
+               *(unsigned int *)base = bmp;
        BYTE_ALIGN(bs);
 
        /* Decode the extension components */
@@ -596,11 +606,12 @@ int decode_seq(bitstr_t * bs, field_t * f, char *base, int level)
 }
 
 /****************************************************************************/
-int decode_seqof(bitstr_t * bs, field_t * f, char *base, int level)
+static int decode_seqof(bitstr_t *bs, const struct field_t *f,
+                        char *base, int level)
 {
-       unsigned count, effective_count = 0, i, len = 0;
+       unsigned int count, effective_count = 0, i, len = 0;
        int err;
-       field_t *son;
+       const struct field_t *son;
        unsigned char *beg = NULL;
 
        PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name);
@@ -636,8 +647,8 @@ int decode_seqof(bitstr_t * bs, field_t * f, char *base, int level)
        /* Write Count */
        if (base) {
                effective_count = count > f->ub ? f->ub : count;
-               *(unsigned *) base = effective_count;
-               base += sizeof(unsigned);
+               *(unsigned int *)base = effective_count;
+               base += sizeof(unsigned int);
        }
 
        /* Decode nested field */
@@ -685,11 +696,12 @@ int decode_seqof(bitstr_t * bs, field_t * f, char *base, int level)
 
 
 /****************************************************************************/
-int decode_choice(bitstr_t * bs, field_t * f, char *base, int level)
+static int decode_choice(bitstr_t *bs, const struct field_t *f,
+                         char *base, int level)
 {
-       unsigned type, ext, len = 0;
+       unsigned int type, ext, len = 0;
        int err;
-       field_t *son;
+       const struct field_t *son;
        unsigned char *beg = NULL;
 
        PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name);
@@ -710,7 +722,7 @@ int decode_choice(bitstr_t * bs, field_t * f, char *base, int level)
 
        /* Write Type */
        if (base)
-               *(unsigned *) base = type;
+               *(unsigned int *)base = type;
 
        /* Check Range */
        if (type >= f->ub) {    /* Newer version? */
@@ -754,9 +766,9 @@ int decode_choice(bitstr_t * bs, field_t * f, char *base, int level)
 }
 
 /****************************************************************************/
-int DecodeRasMessage(unsigned char *buf, size_t sz, RasMessage * ras)
+int DecodeRasMessage(unsigned char *buf, size_t sz, RasMessage *ras)
 {
-       static field_t ras_message = {
+       static const struct field_t ras_message = {
                FNAME("RasMessage") CHOICE, 5, 24, 32, DECODE | EXT,
                0, _RasMessage
        };
@@ -771,9 +783,9 @@ int DecodeRasMessage(unsigned char *buf, size_t sz, RasMessage * ras)
 
 /****************************************************************************/
 static int DecodeH323_UserInformation(unsigned char *buf, unsigned char *beg,
-                                     size_t sz, H323_UserInformation * uuie)
+                                     size_t sz, H323_UserInformation *uuie)
 {
-       static field_t h323_userinformation = {
+       static const struct field_t h323_userinformation = {
                FNAME("H323-UserInformation") SEQ, 1, 2, 2, DECODE | EXT,
                0, _H323_UserInformation
        };
@@ -792,7 +804,7 @@ int DecodeMultimediaSystemControlMessage(unsigned char *buf, size_t sz,
                                         MultimediaSystemControlMessage *
                                         mscm)
 {
-       static field_t multimediasystemcontrolmessage = {
+       static const struct field_t multimediasystemcontrolmessage = {
                FNAME("MultimediaSystemControlMessage") CHOICE, 2, 4, 4,
                DECODE | EXT, 0, _MultimediaSystemControlMessage
        };
@@ -807,7 +819,7 @@ int DecodeMultimediaSystemControlMessage(unsigned char *buf, size_t sz,
 }
 
 /****************************************************************************/
-int DecodeQ931(unsigned char *buf, size_t sz, Q931 * q931)
+int DecodeQ931(unsigned char *buf, size_t sz, Q931 *q931)
 {
        unsigned char *p = buf;
        int len;
index 872c1aa3124c2945fae2d8a5be2672d1242a447e..62137879e6aa66e5b9668fac44996f458c46e253 100644 (file)
@@ -114,7 +114,8 @@ static int get_tpkt_data(struct sk_buff *skb, unsigned int protoff,
 {
        struct nf_ct_h323_master *info = &nfct_help(ct)->help.ct_h323_info;
        int dir = CTINFO2DIR(ctinfo);
-       struct tcphdr _tcph, *th;
+       const struct tcphdr *th;
+       struct tcphdr _tcph;
        int tcpdatalen;
        int tcpdataoff;
        unsigned char *tpkt;
@@ -212,11 +213,11 @@ static int get_tpkt_data(struct sk_buff *skb, unsigned int protoff,
 }
 
 /****************************************************************************/
-static int get_h245_addr(struct nf_conn *ct, unsigned char *data,
+static int get_h245_addr(struct nf_conn *ct, const unsigned char *data,
                         H245_TransportAddress *taddr,
                         union nf_inet_addr *addr, __be16 *port)
 {
-       unsigned char *p;
+       const unsigned char *p;
        int family = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num;
        int len;
 
@@ -625,7 +626,7 @@ int get_h225_addr(struct nf_conn *ct, unsigned char *data,
                  TransportAddress *taddr,
                  union nf_inet_addr *addr, __be16 *port)
 {
-       unsigned char *p;
+       const unsigned char *p;
        int family = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num;
        int len;
 
@@ -704,9 +705,8 @@ static int expect_h245(struct sk_buff *skb, struct nf_conn *ct,
 
 /* If the calling party is on the same side of the forward-to party,
  * we don't need to track the second call */
-static int callforward_do_filter(union nf_inet_addr *src,
-                                union nf_inet_addr *dst,
-                                int family)
+static int callforward_do_filter(const union nf_inet_addr *src,
+                                 const union nf_inet_addr *dst, int family)
 {
        const struct nf_afinfo *afinfo;
        struct flowi fl1, fl2;
@@ -1185,7 +1185,8 @@ static struct nf_conntrack_helper nf_conntrack_helper_q931[] __read_mostly = {
 static unsigned char *get_udp_data(struct sk_buff *skb, unsigned int protoff,
                                   int *datalen)
 {
-       struct udphdr _uh, *uh;
+       const struct udphdr *uh;
+       struct udphdr _uh;
        int dataoff;
 
        uh = skb_header_pointer(skb, protoff, sizeof(_uh), &_uh);
@@ -1415,7 +1416,7 @@ static int process_rcf(struct sk_buff *skb, struct nf_conn *ct,
                nf_ct_refresh(ct, skb, info->timeout * HZ);
 
                /* Set expect timeout */
-               read_lock_bh(&nf_conntrack_lock);
+               spin_lock_bh(&nf_conntrack_lock);
                exp = find_expect(ct, &ct->tuplehash[dir].tuple.dst.u3,
                                  info->sig_port[!dir]);
                if (exp) {
@@ -1425,7 +1426,7 @@ static int process_rcf(struct sk_buff *skb, struct nf_conn *ct,
                        NF_CT_DUMP_TUPLE(&exp->tuple);
                        set_expect_timeout(exp, info->timeout);
                }
-               read_unlock_bh(&nf_conntrack_lock);
+               spin_unlock_bh(&nf_conntrack_lock);
        }
 
        return 0;
@@ -1468,7 +1469,7 @@ static int process_arq(struct sk_buff *skb, struct nf_conn *ct,
                       enum ip_conntrack_info ctinfo,
                       unsigned char **data, AdmissionRequest *arq)
 {
-       struct nf_ct_h323_master *info = &nfct_help(ct)->help.ct_h323_info;
+       const struct nf_ct_h323_master *info = &nfct_help(ct)->help.ct_h323_info;
        int dir = CTINFO2DIR(ctinfo);
        __be16 port;
        union nf_inet_addr addr;
index 3a21fdf1a2654ce8bedbccf8fda781da59919e0a..d880f3523c1de8aaccdcca90e3036cdc50015b9c 100644 (file)
@@ -5,22 +5,22 @@
  * This source code is licensed under General Public License version 2.
  */
 
-static field_t _TransportAddress_ipAddress[] = {       /* SEQUENCE */
+static const struct field_t _TransportAddress_ipAddress[] = {  /* SEQUENCE */
        {FNAME("ip") OCTSTR, FIXD, 4, 0, DECODE,
         offsetof(TransportAddress_ipAddress, ip), NULL},
        {FNAME("port") INT, WORD, 0, 0, SKIP, 0, NULL},
 };
 
-static field_t _TransportAddress_ipSourceRoute_route[] = {     /* SEQUENCE OF */
+static const struct field_t _TransportAddress_ipSourceRoute_route[] = {        /* SEQUENCE OF */
        {FNAME("item") OCTSTR, FIXD, 4, 0, SKIP, 0, NULL},
 };
 
-static field_t _TransportAddress_ipSourceRoute_routing[] = {   /* CHOICE */
+static const struct field_t _TransportAddress_ipSourceRoute_routing[] = {      /* CHOICE */
        {FNAME("strict") NUL, FIXD, 0, 0, SKIP, 0, NULL},
        {FNAME("loose") NUL, FIXD, 0, 0, SKIP, 0, NULL},
 };
 
-static field_t _TransportAddress_ipSourceRoute[] = {   /* SEQUENCE */
+static const struct field_t _TransportAddress_ipSourceRoute[] = {      /* SEQUENCE */
        {FNAME("ip") OCTSTR, FIXD, 4, 0, SKIP, 0, NULL},
        {FNAME("port") INT, WORD, 0, 0, SKIP, 0, NULL},
        {FNAME("route") SEQOF, SEMI, 0, 0, SKIP, 0,
@@ -29,37 +29,37 @@ static field_t _TransportAddress_ipSourceRoute[] = {        /* SEQUENCE */
         _TransportAddress_ipSourceRoute_routing},
 };
 
-static field_t _TransportAddress_ipxAddress[] = {      /* SEQUENCE */
+static const struct field_t _TransportAddress_ipxAddress[] = { /* SEQUENCE */
        {FNAME("node") OCTSTR, FIXD, 6, 0, SKIP, 0, NULL},
        {FNAME("netnum") OCTSTR, FIXD, 4, 0, SKIP, 0, NULL},
        {FNAME("port") OCTSTR, FIXD, 2, 0, SKIP, 0, NULL},
 };
 
-static field_t _TransportAddress_ip6Address[] = {      /* SEQUENCE */
+static const struct field_t _TransportAddress_ip6Address[] = { /* SEQUENCE */
        {FNAME("ip") OCTSTR, FIXD, 16, 0, DECODE,
         offsetof(TransportAddress_ip6Address, ip), NULL},
        {FNAME("port") INT, WORD, 0, 0, SKIP, 0, NULL},
 };
 
-static field_t _H221NonStandard[] = {  /* SEQUENCE */
+static const struct field_t _H221NonStandard[] = {     /* SEQUENCE */
        {FNAME("t35CountryCode") INT, BYTE, 0, 0, SKIP, 0, NULL},
        {FNAME("t35Extension") INT, BYTE, 0, 0, SKIP, 0, NULL},
        {FNAME("manufacturerCode") INT, WORD, 0, 0, SKIP, 0, NULL},
 };
 
-static field_t _NonStandardIdentifier[] = {    /* CHOICE */
+static const struct field_t _NonStandardIdentifier[] = {       /* CHOICE */
        {FNAME("object") OID, BYTE, 0, 0, SKIP, 0, NULL},
        {FNAME("h221NonStandard") SEQ, 0, 3, 3, SKIP | EXT, 0,
         _H221NonStandard},
 };
 
-static field_t _NonStandardParameter[] = {     /* SEQUENCE */
+static const struct field_t _NonStandardParameter[] = {        /* SEQUENCE */
        {FNAME("nonStandardIdentifier") CHOICE, 1, 2, 2, SKIP | EXT, 0,
         _NonStandardIdentifier},
        {FNAME("data") OCTSTR, SEMI, 0, 0, SKIP, 0, NULL},
 };
 
-static field_t _TransportAddress[] = { /* CHOICE */
+static const struct field_t _TransportAddress[] = {    /* CHOICE */
        {FNAME("ipAddress") SEQ, 0, 2, 2, DECODE,
         offsetof(TransportAddress, ipAddress), _TransportAddress_ipAddress},
        {FNAME("ipSourceRoute") SEQ, 0, 4, 4, SKIP | EXT, 0,
@@ -75,7 +75,7 @@ static field_t _TransportAddress[] = {        /* CHOICE */
         _NonStandardParameter},
 };
 
-static field_t _AliasAddress[] = {     /* CHOICE */
+static const struct field_t _AliasAddress[] = {        /* CHOICE */
        {FNAME("dialedDigits") NUMDGT, 7, 1, 0, SKIP, 0, NULL},
        {FNAME("h323-ID") BMPSTR, BYTE, 1, 0, SKIP, 0, NULL},
        {FNAME("url-ID") IA5STR, WORD, 1, 0, SKIP, 0, NULL},
@@ -85,78 +85,78 @@ static field_t _AliasAddress[] = {  /* CHOICE */
        {FNAME("mobileUIM") CHOICE, 1, 2, 2, SKIP | EXT, 0, NULL},
 };
 
-static field_t _Setup_UUIE_sourceAddress[] = { /* SEQUENCE OF */
+static const struct field_t _Setup_UUIE_sourceAddress[] = {    /* SEQUENCE OF */
        {FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress},
 };
 
-static field_t _VendorIdentifier[] = { /* SEQUENCE */
+static const struct field_t _VendorIdentifier[] = {    /* SEQUENCE */
        {FNAME("vendor") SEQ, 0, 3, 3, SKIP | EXT, 0, _H221NonStandard},
        {FNAME("productId") OCTSTR, BYTE, 1, 0, SKIP | OPT, 0, NULL},
        {FNAME("versionId") OCTSTR, BYTE, 1, 0, SKIP | OPT, 0, NULL},
 };
 
-static field_t _GatekeeperInfo[] = {   /* SEQUENCE */
+static const struct field_t _GatekeeperInfo[] = {      /* SEQUENCE */
        {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0,
         _NonStandardParameter},
 };
 
-static field_t _H310Caps[] = { /* SEQUENCE */
+static const struct field_t _H310Caps[] = {    /* SEQUENCE */
        {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0,
         _NonStandardParameter},
        {FNAME("dataRatesSupported") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL},
        {FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, SKIP, 0, NULL},
 };
 
-static field_t _H320Caps[] = { /* SEQUENCE */
+static const struct field_t _H320Caps[] = {    /* SEQUENCE */
        {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0,
         _NonStandardParameter},
        {FNAME("dataRatesSupported") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL},
        {FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, SKIP, 0, NULL},
 };
 
-static field_t _H321Caps[] = { /* SEQUENCE */
+static const struct field_t _H321Caps[] = {    /* SEQUENCE */
        {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0,
         _NonStandardParameter},
        {FNAME("dataRatesSupported") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL},
        {FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, SKIP, 0, NULL},
 };
 
-static field_t _H322Caps[] = { /* SEQUENCE */
+static const struct field_t _H322Caps[] = {    /* SEQUENCE */
        {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0,
         _NonStandardParameter},
        {FNAME("dataRatesSupported") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL},
        {FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, SKIP, 0, NULL},
 };
 
-static field_t _H323Caps[] = { /* SEQUENCE */
+static const struct field_t _H323Caps[] = {    /* SEQUENCE */
        {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0,
         _NonStandardParameter},
        {FNAME("dataRatesSupported") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL},
        {FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, SKIP, 0, NULL},
 };
 
-static field_t _H324Caps[] = { /* SEQUENCE */
+static const struct field_t _H324Caps[] = {    /* SEQUENCE */
        {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0,
         _NonStandardParameter},
        {FNAME("dataRatesSupported") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL},
        {FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, SKIP, 0, NULL},
 };
 
-static field_t _VoiceCaps[] = {        /* SEQUENCE */
+static const struct field_t _VoiceCaps[] = {   /* SEQUENCE */
        {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0,
         _NonStandardParameter},
        {FNAME("dataRatesSupported") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL},
        {FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, SKIP, 0, NULL},
 };
 
-static field_t _T120OnlyCaps[] = {     /* SEQUENCE */
+static const struct field_t _T120OnlyCaps[] = {        /* SEQUENCE */
        {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0,
         _NonStandardParameter},
        {FNAME("dataRatesSupported") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL},
        {FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, SKIP, 0, NULL},
 };
 
-static field_t _SupportedProtocols[] = {       /* CHOICE */
+static const struct field_t _SupportedProtocols[] = {  /* CHOICE */
        {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP, 0,
         _NonStandardParameter},
        {FNAME("h310") SEQ, 1, 1, 3, SKIP | EXT, 0, _H310Caps},
@@ -171,29 +171,29 @@ static field_t _SupportedProtocols[] = {  /* CHOICE */
        {FNAME("t38FaxAnnexbOnly") SEQ, 2, 5, 5, SKIP | EXT, 0, NULL},
 };
 
-static field_t _GatewayInfo_protocol[] = {     /* SEQUENCE OF */
+static const struct field_t _GatewayInfo_protocol[] = {        /* SEQUENCE OF */
        {FNAME("item") CHOICE, 4, 9, 11, SKIP | EXT, 0, _SupportedProtocols},
 };
 
-static field_t _GatewayInfo[] = {      /* SEQUENCE */
+static const struct field_t _GatewayInfo[] = { /* SEQUENCE */
        {FNAME("protocol") SEQOF, SEMI, 0, 0, SKIP | OPT, 0,
         _GatewayInfo_protocol},
        {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0,
         _NonStandardParameter},
 };
 
-static field_t _McuInfo[] = {  /* SEQUENCE */
+static const struct field_t _McuInfo[] = {     /* SEQUENCE */
        {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0,
         _NonStandardParameter},
        {FNAME("protocol") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL},
 };
 
-static field_t _TerminalInfo[] = {     /* SEQUENCE */
+static const struct field_t _TerminalInfo[] = {        /* SEQUENCE */
        {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0,
         _NonStandardParameter},
 };
 
-static field_t _EndpointType[] = {     /* SEQUENCE */
+static const struct field_t _EndpointType[] = {        /* SEQUENCE */
        {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0,
         _NonStandardParameter},
        {FNAME("vendor") SEQ, 2, 3, 3, SKIP | EXT | OPT, 0,
@@ -210,19 +210,19 @@ static field_t _EndpointType[] = {        /* SEQUENCE */
         0, NULL},
 };
 
-static field_t _Setup_UUIE_destinationAddress[] = {    /* SEQUENCE OF */
+static const struct field_t _Setup_UUIE_destinationAddress[] = {       /* SEQUENCE OF */
        {FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress},
 };
 
-static field_t _Setup_UUIE_destExtraCallInfo[] = {     /* SEQUENCE OF */
+static const struct field_t _Setup_UUIE_destExtraCallInfo[] = {        /* SEQUENCE OF */
        {FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress},
 };
 
-static field_t _Setup_UUIE_destExtraCRV[] = {  /* SEQUENCE OF */
+static const struct field_t _Setup_UUIE_destExtraCRV[] = {     /* SEQUENCE OF */
        {FNAME("item") INT, WORD, 0, 0, SKIP, 0, NULL},
 };
 
-static field_t _Setup_UUIE_conferenceGoal[] = {        /* CHOICE */
+static const struct field_t _Setup_UUIE_conferenceGoal[] = {   /* CHOICE */
        {FNAME("create") NUL, FIXD, 0, 0, SKIP, 0, NULL},
        {FNAME("join") NUL, FIXD, 0, 0, SKIP, 0, NULL},
        {FNAME("invite") NUL, FIXD, 0, 0, SKIP, 0, NULL},
@@ -231,12 +231,12 @@ static field_t _Setup_UUIE_conferenceGoal[] = {   /* CHOICE */
         0, NULL},
 };
 
-static field_t _Q954Details[] = {      /* SEQUENCE */
+static const struct field_t _Q954Details[] = { /* SEQUENCE */
        {FNAME("conferenceCalling") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
        {FNAME("threePartyService") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
 };
 
-static field_t _QseriesOptions[] = {   /* SEQUENCE */
+static const struct field_t _QseriesOptions[] = {      /* SEQUENCE */
        {FNAME("q932Full") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
        {FNAME("q951Full") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
        {FNAME("q952Full") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
@@ -247,32 +247,32 @@ static field_t _QseriesOptions[] = {      /* SEQUENCE */
        {FNAME("q954Info") SEQ, 0, 2, 2, SKIP | EXT, 0, _Q954Details},
 };
 
-static field_t _CallType[] = { /* CHOICE */
+static const struct field_t _CallType[] = {    /* CHOICE */
        {FNAME("pointToPoint") NUL, FIXD, 0, 0, SKIP, 0, NULL},
        {FNAME("oneToN") NUL, FIXD, 0, 0, SKIP, 0, NULL},
        {FNAME("nToOne") NUL, FIXD, 0, 0, SKIP, 0, NULL},
        {FNAME("nToN") NUL, FIXD, 0, 0, SKIP, 0, NULL},
 };
 
-static field_t _H245_NonStandardIdentifier_h221NonStandard[] = {       /* SEQUENCE */
+static const struct field_t _H245_NonStandardIdentifier_h221NonStandard[] = {  /* SEQUENCE */
        {FNAME("t35CountryCode") INT, BYTE, 0, 0, SKIP, 0, NULL},
        {FNAME("t35Extension") INT, BYTE, 0, 0, SKIP, 0, NULL},
        {FNAME("manufacturerCode") INT, WORD, 0, 0, SKIP, 0, NULL},
 };
 
-static field_t _H245_NonStandardIdentifier[] = {       /* CHOICE */
+static const struct field_t _H245_NonStandardIdentifier[] = {  /* CHOICE */
        {FNAME("object") OID, BYTE, 0, 0, SKIP, 0, NULL},
        {FNAME("h221NonStandard") SEQ, 0, 3, 3, SKIP, 0,
         _H245_NonStandardIdentifier_h221NonStandard},
 };
 
-static field_t _H245_NonStandardParameter[] = {        /* SEQUENCE */
+static const struct field_t _H245_NonStandardParameter[] = {   /* SEQUENCE */
        {FNAME("nonStandardIdentifier") CHOICE, 1, 2, 2, SKIP, 0,
         _H245_NonStandardIdentifier},
        {FNAME("data") OCTSTR, SEMI, 0, 0, SKIP, 0, NULL},
 };
 
-static field_t _H261VideoCapability[] = {      /* SEQUENCE */
+static const struct field_t _H261VideoCapability[] = { /* SEQUENCE */
        {FNAME("qcifMPI") INT, 2, 1, 0, SKIP | OPT, 0, NULL},
        {FNAME("cifMPI") INT, 2, 1, 0, SKIP | OPT, 0, NULL},
        {FNAME("temporalSpatialTradeOffCapability") BOOL, FIXD, 0, 0, SKIP, 0,
@@ -282,7 +282,7 @@ static field_t _H261VideoCapability[] = {   /* SEQUENCE */
        {FNAME("videoBadMBsCap") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
 };
 
-static field_t _H262VideoCapability[] = {      /* SEQUENCE */
+static const struct field_t _H262VideoCapability[] = { /* SEQUENCE */
        {FNAME("profileAndLevel-SPatML") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
        {FNAME("profileAndLevel-MPatLL") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
        {FNAME("profileAndLevel-MPatML") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
@@ -304,7 +304,7 @@ static field_t _H262VideoCapability[] = {   /* SEQUENCE */
        {FNAME("videoBadMBsCap") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
 };
 
-static field_t _H263VideoCapability[] = {      /* SEQUENCE */
+static const struct field_t _H263VideoCapability[] = { /* SEQUENCE */
        {FNAME("sqcifMPI") INT, 5, 1, 0, SKIP | OPT, 0, NULL},
        {FNAME("qcifMPI") INT, 5, 1, 0, SKIP | OPT, 0, NULL},
        {FNAME("cifMPI") INT, 5, 1, 0, SKIP | OPT, 0, NULL},
@@ -330,7 +330,7 @@ static field_t _H263VideoCapability[] = {   /* SEQUENCE */
        {FNAME("h263Options") SEQ, 5, 29, 31, SKIP | EXT | OPT, 0, NULL},
 };
 
-static field_t _IS11172VideoCapability[] = {   /* SEQUENCE */
+static const struct field_t _IS11172VideoCapability[] = {      /* SEQUENCE */
        {FNAME("constrainedBitstream") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
        {FNAME("videoBitRate") INT, CONS, 0, 0, SKIP | OPT, 0, NULL},
        {FNAME("vbvBufferSize") INT, CONS, 0, 0, SKIP | OPT, 0, NULL},
@@ -341,7 +341,7 @@ static field_t _IS11172VideoCapability[] = {        /* SEQUENCE */
        {FNAME("videoBadMBsCap") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
 };
 
-static field_t _VideoCapability[] = {  /* CHOICE */
+static const struct field_t _VideoCapability[] = {     /* CHOICE */
        {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP, 0,
         _H245_NonStandardParameter},
        {FNAME("h261VideoCapability") SEQ, 2, 5, 6, SKIP | EXT, 0,
@@ -355,12 +355,12 @@ static field_t _VideoCapability[] = {     /* CHOICE */
        {FNAME("genericVideoCapability") SEQ, 5, 6, 6, SKIP | EXT, 0, NULL},
 };
 
-static field_t _AudioCapability_g7231[] = {    /* SEQUENCE */
+static const struct field_t _AudioCapability_g7231[] = {       /* SEQUENCE */
        {FNAME("maxAl-sduAudioFrames") INT, BYTE, 1, 0, SKIP, 0, NULL},
        {FNAME("silenceSuppression") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
 };
 
-static field_t _IS11172AudioCapability[] = {   /* SEQUENCE */
+static const struct field_t _IS11172AudioCapability[] = {      /* SEQUENCE */
        {FNAME("audioLayer1") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
        {FNAME("audioLayer2") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
        {FNAME("audioLayer3") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
@@ -372,7 +372,7 @@ static field_t _IS11172AudioCapability[] = {        /* SEQUENCE */
        {FNAME("bitRate") INT, WORD, 1, 0, SKIP, 0, NULL},
 };
 
-static field_t _IS13818AudioCapability[] = {   /* SEQUENCE */
+static const struct field_t _IS13818AudioCapability[] = {      /* SEQUENCE */
        {FNAME("audioLayer1") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
        {FNAME("audioLayer2") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
        {FNAME("audioLayer3") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
@@ -396,7 +396,7 @@ static field_t _IS13818AudioCapability[] = {        /* SEQUENCE */
        {FNAME("bitRate") INT, WORD, 1, 0, SKIP, 0, NULL},
 };
 
-static field_t _AudioCapability[] = {  /* CHOICE */
+static const struct field_t _AudioCapability[] = {     /* CHOICE */
        {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP, 0,
         _H245_NonStandardParameter},
        {FNAME("g711Alaw64k") INT, BYTE, 1, 0, SKIP, 0, NULL},
@@ -424,7 +424,7 @@ static field_t _AudioCapability[] = {       /* CHOICE */
        {FNAME("g729Extensions") SEQ, 1, 8, 8, SKIP | EXT, 0, NULL},
 };
 
-static field_t _DataProtocolCapability[] = {   /* CHOICE */
+static const struct field_t _DataProtocolCapability[] = {      /* CHOICE */
        {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP, 0,
         _H245_NonStandardParameter},
        {FNAME("v14buffered") NUL, FIXD, 0, 0, SKIP, 0, NULL},
@@ -442,7 +442,7 @@ static field_t _DataProtocolCapability[] = {        /* CHOICE */
        {FNAME("udp") NUL, FIXD, 0, 0, SKIP, 0, NULL},
 };
 
-static field_t _T84Profile_t84Restricted[] = { /* SEQUENCE */
+static const struct field_t _T84Profile_t84Restricted[] = {    /* SEQUENCE */
        {FNAME("qcif") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
        {FNAME("cif") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
        {FNAME("ccir601Seq") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
@@ -464,25 +464,25 @@ static field_t _T84Profile_t84Restricted[] = {    /* SEQUENCE */
        {FNAME("digPhotoHighProg") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
 };
 
-static field_t _T84Profile[] = {       /* CHOICE */
+static const struct field_t _T84Profile[] = {  /* CHOICE */
        {FNAME("t84Unrestricted") NUL, FIXD, 0, 0, SKIP, 0, NULL},
        {FNAME("t84Restricted") SEQ, 0, 19, 19, SKIP | EXT, 0,
         _T84Profile_t84Restricted},
 };
 
-static field_t _DataApplicationCapability_application_t84[] = {        /* SEQUENCE */
+static const struct field_t _DataApplicationCapability_application_t84[] = {   /* SEQUENCE */
        {FNAME("t84Protocol") CHOICE, 3, 7, 14, SKIP | EXT, 0,
         _DataProtocolCapability},
        {FNAME("t84Profile") CHOICE, 1, 2, 2, SKIP, 0, _T84Profile},
 };
 
-static field_t _DataApplicationCapability_application_nlpid[] = {      /* SEQUENCE */
+static const struct field_t _DataApplicationCapability_application_nlpid[] = { /* SEQUENCE */
        {FNAME("nlpidProtocol") CHOICE, 3, 7, 14, SKIP | EXT, 0,
         _DataProtocolCapability},
        {FNAME("nlpidData") OCTSTR, SEMI, 0, 0, SKIP, 0, NULL},
 };
 
-static field_t _DataApplicationCapability_application[] = {    /* CHOICE */
+static const struct field_t _DataApplicationCapability_application[] = {       /* CHOICE */
        {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP, 0,
         _H245_NonStandardParameter},
        {FNAME("t120") CHOICE, 3, 7, 14, DECODE | EXT,
@@ -509,20 +509,20 @@ static field_t _DataApplicationCapability_application[] = {       /* CHOICE */
        {FNAME("genericDataCapability") SEQ, 5, 6, 6, SKIP | EXT, 0, NULL},
 };
 
-static field_t _DataApplicationCapability[] = {        /* SEQUENCE */
+static const struct field_t _DataApplicationCapability[] = {   /* SEQUENCE */
        {FNAME("application") CHOICE, 4, 10, 14, DECODE | EXT,
         offsetof(DataApplicationCapability, application),
         _DataApplicationCapability_application},
        {FNAME("maxBitRate") INT, CONS, 0, 0, SKIP, 0, NULL},
 };
 
-static field_t _EncryptionMode[] = {   /* CHOICE */
+static const struct field_t _EncryptionMode[] = {      /* CHOICE */
        {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP, 0,
         _H245_NonStandardParameter},
        {FNAME("h233Encryption") NUL, FIXD, 0, 0, SKIP, 0, NULL},
 };
 
-static field_t _DataType[] = { /* CHOICE */
+static const struct field_t _DataType[] = {    /* CHOICE */
        {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP, 0,
         _H245_NonStandardParameter},
        {FNAME("nullData") NUL, FIXD, 0, 0, SKIP, 0, NULL},
@@ -538,7 +538,7 @@ static field_t _DataType[] = {      /* CHOICE */
        {FNAME("multiplexedStream") SEQ, 0, 2, 2, SKIP | EXT, 0, NULL},
 };
 
-static field_t _H222LogicalChannelParameters[] = {     /* SEQUENCE */
+static const struct field_t _H222LogicalChannelParameters[] = {        /* SEQUENCE */
        {FNAME("resourceID") INT, WORD, 0, 0, SKIP, 0, NULL},
        {FNAME("subChannelID") INT, WORD, 0, 0, SKIP, 0, NULL},
        {FNAME("pcr-pid") INT, WORD, 0, 0, SKIP | OPT, 0, NULL},
@@ -546,12 +546,12 @@ static field_t _H222LogicalChannelParameters[] = {        /* SEQUENCE */
        {FNAME("streamDescriptors") OCTSTR, SEMI, 0, 0, SKIP | OPT, 0, NULL},
 };
 
-static field_t _H223LogicalChannelParameters_adaptationLayerType_al3[] = {     /* SEQUENCE */
+static const struct field_t _H223LogicalChannelParameters_adaptationLayerType_al3[] = {        /* SEQUENCE */
        {FNAME("controlFieldOctets") INT, 2, 0, 0, SKIP, 0, NULL},
        {FNAME("sendBufferSize") INT, CONS, 0, 0, SKIP, 0, NULL},
 };
 
-static field_t _H223LogicalChannelParameters_adaptationLayerType[] = { /* CHOICE */
+static const struct field_t _H223LogicalChannelParameters_adaptationLayerType[] = {    /* CHOICE */
        {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP, 0,
         _H245_NonStandardParameter},
        {FNAME("al1Framed") NUL, FIXD, 0, 0, SKIP, 0, NULL},
@@ -565,53 +565,53 @@ static field_t _H223LogicalChannelParameters_adaptationLayerType[] = {    /* CHOICE
        {FNAME("al3M") SEQ, 0, 5, 6, SKIP | EXT, 0, NULL},
 };
 
-static field_t _H223LogicalChannelParameters[] = {     /* SEQUENCE */
+static const struct field_t _H223LogicalChannelParameters[] = {        /* SEQUENCE */
        {FNAME("adaptationLayerType") CHOICE, 3, 6, 9, SKIP | EXT, 0,
         _H223LogicalChannelParameters_adaptationLayerType},
        {FNAME("segmentableFlag") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
 };
 
-static field_t _CRCLength[] = {        /* CHOICE */
+static const struct field_t _CRCLength[] = {   /* CHOICE */
        {FNAME("crc8bit") NUL, FIXD, 0, 0, SKIP, 0, NULL},
        {FNAME("crc16bit") NUL, FIXD, 0, 0, SKIP, 0, NULL},
        {FNAME("crc32bit") NUL, FIXD, 0, 0, SKIP, 0, NULL},
 };
 
-static field_t _V76HDLCParameters[] = {        /* SEQUENCE */
+static const struct field_t _V76HDLCParameters[] = {   /* SEQUENCE */
        {FNAME("crcLength") CHOICE, 2, 3, 3, SKIP | EXT, 0, _CRCLength},
        {FNAME("n401") INT, WORD, 1, 0, SKIP, 0, NULL},
        {FNAME("loopbackTestProcedure") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
 };
 
-static field_t _V76LogicalChannelParameters_suspendResume[] = {        /* CHOICE */
+static const struct field_t _V76LogicalChannelParameters_suspendResume[] = {   /* CHOICE */
        {FNAME("noSuspendResume") NUL, FIXD, 0, 0, SKIP, 0, NULL},
        {FNAME("suspendResumewAddress") NUL, FIXD, 0, 0, SKIP, 0, NULL},
        {FNAME("suspendResumewoAddress") NUL, FIXD, 0, 0, SKIP, 0, NULL},
 };
 
-static field_t _V76LogicalChannelParameters_mode_eRM_recovery[] = {    /* CHOICE */
+static const struct field_t _V76LogicalChannelParameters_mode_eRM_recovery[] = {       /* CHOICE */
        {FNAME("rej") NUL, FIXD, 0, 0, SKIP, 0, NULL},
        {FNAME("sREJ") NUL, FIXD, 0, 0, SKIP, 0, NULL},
        {FNAME("mSREJ") NUL, FIXD, 0, 0, SKIP, 0, NULL},
 };
 
-static field_t _V76LogicalChannelParameters_mode_eRM[] = {     /* SEQUENCE */
+static const struct field_t _V76LogicalChannelParameters_mode_eRM[] = {        /* SEQUENCE */
        {FNAME("windowSize") INT, 7, 1, 0, SKIP, 0, NULL},
        {FNAME("recovery") CHOICE, 2, 3, 3, SKIP | EXT, 0,
         _V76LogicalChannelParameters_mode_eRM_recovery},
 };
 
-static field_t _V76LogicalChannelParameters_mode[] = { /* CHOICE */
+static const struct field_t _V76LogicalChannelParameters_mode[] = {    /* CHOICE */
        {FNAME("eRM") SEQ, 0, 2, 2, SKIP | EXT, 0,
         _V76LogicalChannelParameters_mode_eRM},
        {FNAME("uNERM") NUL, FIXD, 0, 0, SKIP, 0, NULL},
 };
 
-static field_t _V75Parameters[] = {    /* SEQUENCE */
+static const struct field_t _V75Parameters[] = {       /* SEQUENCE */
        {FNAME("audioHeaderPresent") BOOL, FIXD, 0, 0, SKIP, 0, NULL},
 };
 
-static field_t _V76LogicalChannelParameters[] = {      /* SEQUENCE */
+static const struct field_t _V76LogicalChannelParameters[] = { /* SEQUENCE */
        {FNAME("hdlcParameters") SEQ, 0, 3, 3, SKIP | EXT, 0,
         _V76HDLCParameters},
        {FNAME("suspendResume") CHOICE, 2, 3, 3, SKIP | EXT, 0,
@@ -622,38 +622,38 @@ static field_t _V76LogicalChannelParameters[] = { /* SEQUENCE */
        {FNAME("v75Parameters") SEQ, 0, 1, 1, SKIP | EXT, 0, _V75Parameters},
 };
 
-static field_t _H2250LogicalChannelParameters_nonStandard[] = {        /* SEQUENCE OF */
+static const struct field_t _H2250LogicalChannelParameters_nonStandard[] = {   /* SEQUENCE OF */
        {FNAME("item") SEQ, 0, 2, 2, SKIP, 0, _H245_NonStandardParameter},
 };
 
-static field_t _UnicastAddress_iPAddress[] = { /* SEQUENCE */
+static const struct field_t _UnicastAddress_iPAddress[] = {    /* SEQUENCE */
        {FNAME("network") OCTSTR, FIXD, 4, 0, DECODE,
         offsetof(UnicastAddress_iPAddress, network), NULL},
        {FNAME("tsapIdentifier") INT, WORD, 0, 0, SKIP, 0, NULL},
 };
 
-static field_t _UnicastAddress_iPXAddress[] = {        /* SEQUENCE */
+static const struct field_t _UnicastAddress_iPXAddress[] = {   /* SEQUENCE */
        {FNAME("node") OCTSTR, FIXD, 6, 0, SKIP, 0, NULL},
        {FNAME("netnum") OCTSTR, FIXD, 4, 0, SKIP, 0, NULL},
        {FNAME("tsapIdentifier") OCTSTR, FIXD, 2, 0, SKIP, 0, NULL},
 };
 
-static field_t _UnicastAddress_iP6Address[] = {        /* SEQUENCE */
+static const struct field_t _UnicastAddress_iP6Address[] = {   /* SEQUENCE */
        {FNAME("network") OCTSTR, FIXD, 16, 0, DECODE,
         offsetof(UnicastAddress_iP6Address, network), NULL},
        {FNAME("tsapIdentifier") INT, WORD, 0, 0, SKIP, 0, NULL},
 };
 
-static field_t _UnicastAddress_iPSourceRouteAddress_routing[] = {      /* CHOICE */
+static const struct field_t _UnicastAddress_iPSourceRouteAddress_routing[] = { /* CHOICE */
        {FNAME("strict") NUL, FIXD, 0, 0, SKIP, 0, NULL},
        {FNAME("loose") NUL, FIXD, 0, 0, SKIP, 0, NULL},
 };
 
-static field_t _UnicastAddress_iPSourceRouteAddress_route[] = {        /* SEQUENCE OF */
+static const struct field_t _UnicastAddress_iPSourceRouteAddress_route[] = {   /* SEQUENCE OF */
        {FNAME("item") OCTSTR, FIXD, 4, 0, SKIP, 0, NULL},
 };
 
-static field_t _UnicastAddress_iPSourceRouteAddress[] = {      /* SEQUENCE */
+static const struct field_t _UnicastAddress_iPSourceRouteAddress[] = { /* SEQUENCE */
        {FNAME("routing") CHOICE, 1, 2, 2, SKIP, 0,
         _UnicastAddress_iPSourceRouteAddress_routing},
        {FNAME("network") OCTSTR, FIXD, 4, 0, SKIP, 0, NULL},
@@ -662,7 +662,7 @@ static field_t _UnicastAddress_iPSourceRouteAddress[] = {   /* SEQUENCE */
         _UnicastAddress_iPSourceRouteAddress_route},
 };
 
-static field_t _UnicastAddress[] = {   /* CHOICE */
+static const struct field_t _UnicastAddress[] = {      /* CHOICE */
        {FNAME("iPAddress") SEQ, 0, 2, 2, DECODE | EXT,
         offsetof(UnicastAddress, iPAddress), _UnicastAddress_iPAddress},
        {FNAME("iPXAddress") SEQ, 0, 3, 3, SKIP | EXT, 0,
@@ -676,17 +676,17 @@ static field_t _UnicastAddress[] = {      /* CHOICE */
        {FNAME("nonStandardAddress") SEQ, 0, 2, 2, SKIP, 0, NULL},
 };
 
-static field_t _MulticastAddress_iPAddress[] = {       /* SEQUENCE */
+static const struct field_t _MulticastAddress_iPAddress[] = {  /* SEQUENCE */
        {FNAME("network") OCTSTR, FIXD, 4, 0, SKIP, 0, NULL},
        {FNAME("tsapIdentifier") INT, WORD, 0, 0, SKIP, 0, NULL},
 };
 
-static field_t _MulticastAddress_iP6Address[] = {      /* SEQUENCE */
+static const struct field_t _MulticastAddress_iP6Address[] = { /* SEQUENCE */
        {FNAME("network") OCTSTR, FIXD, 16, 0, SKIP, 0, NULL},
        {FNAME("tsapIdentifier") INT, WORD, 0, 0, SKIP, 0, NULL},
 };
 
-static field_t _MulticastAddress[] = { /* CHOICE */
+static const struct field_t _MulticastAddress[] = {    /* CHOICE */
        {FNAME("iPAddress") SEQ, 0, 2, 2, SKIP | EXT, 0,
         _MulticastAddress_iPAddress},
        {FNAME("iP6Address") SEQ, 0, 2, 2, SKIP | EXT, 0,
@@ -695,14 +695,14 @@ static field_t _MulticastAddress[] = {    /* CHOICE */
        {FNAME("nonStandardAddress") SEQ, 0, 2, 2, SKIP, 0, NULL},
 };
 
-static field_t _H245_TransportAddress[] = {    /* CHOICE */
+static const struct field_t _H245_TransportAddress[] = {       /* CHOICE */
        {FNAME("unicastAddress") CHOICE, 3, 5, 7, DECODE | EXT,
         offsetof(H245_TransportAddress, unicastAddress), _UnicastAddress},
        {FNAME("multicastAddress") CHOICE, 1, 2, 4, SKIP | EXT, 0,
         _MulticastAddress},
 };
 
-static field_t _H2250LogicalChannelParameters[] = {    /* SEQUENCE */
+static const struct field_t _H2250LogicalChannelParameters[] = {       /* SEQUENCE */
        {FNAME("nonStandard") SEQOF, SEMI, 0, 0, SKIP | OPT, 0,
         _H2250LogicalChannelParameters_nonStandard},
        {FNAME("sessionID") INT, BYTE, 0, 0, SKIP, 0, NULL},
@@ -728,7 +728,7 @@ static field_t _H2250LogicalChannelParameters[] = { /* SEQUENCE */
        {FNAME("source") SEQ, 0, 2, 2, SKIP | EXT | OPT, 0, NULL},
 };
 
-static field_t _OpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters[] = {   /* CHOICE */
+static const struct field_t _OpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters[] = {      /* CHOICE */
        {FNAME("h222LogicalChannelParameters") SEQ, 3, 5, 5, SKIP | EXT, 0,
         _H222LogicalChannelParameters},
        {FNAME("h223LogicalChannelParameters") SEQ, 0, 2, 2, SKIP | EXT, 0,
@@ -742,7 +742,7 @@ static field_t _OpenLogicalChannel_forwardLogicalChannelParameters_multiplexPara
        {FNAME("none") NUL, FIXD, 0, 0, SKIP, 0, NULL},
 };
 
-static field_t _OpenLogicalChannel_forwardLogicalChannelParameters[] = {       /* SEQUENCE */
+static const struct field_t _OpenLogicalChannel_forwardLogicalChannelParameters[] = {  /* SEQUENCE */
        {FNAME("portNumber") INT, WORD, 0, 0, SKIP | OPT, 0, NULL},
        {FNAME("dataType") CHOICE, 3, 6, 9, DECODE | EXT,
         offsetof(OpenLogicalChannel_forwardLogicalChannelParameters,
@@ -756,7 +756,7 @@ static field_t _OpenLogicalChannel_forwardLogicalChannelParameters[] = {    /* SEQU
        {FNAME("replacementFor") INT, WORD, 1, 0, SKIP | OPT, 0, NULL},
 };
 
-static field_t _OpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters[] = {   /* CHOICE */
+static const struct field_t _OpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters[] = {      /* CHOICE */
        {FNAME("h223LogicalChannelParameters") SEQ, 0, 2, 2, SKIP | EXT, 0,
         _H223LogicalChannelParameters},
        {FNAME("v76LogicalChannelParameters") SEQ, 0, 5, 5, SKIP | EXT, 0,
@@ -767,7 +767,7 @@ static field_t _OpenLogicalChannel_reverseLogicalChannelParameters_multiplexPara
          h2250LogicalChannelParameters), _H2250LogicalChannelParameters},
 };
 
-static field_t _OpenLogicalChannel_reverseLogicalChannelParameters[] = {       /* SEQUENCE */
+static const struct field_t _OpenLogicalChannel_reverseLogicalChannelParameters[] = {  /* SEQUENCE */
        {FNAME("dataType") CHOICE, 3, 6, 9, SKIP | EXT, 0, _DataType},
        {FNAME("multiplexParameters") CHOICE, 1, 2, 3, DECODE | EXT | OPT,
         offsetof(OpenLogicalChannel_reverseLogicalChannelParameters,
@@ -778,23 +778,23 @@ static field_t _OpenLogicalChannel_reverseLogicalChannelParameters[] = {  /* SEQU
        {FNAME("replacementFor") INT, WORD, 1, 0, SKIP | OPT, 0, NULL},
 };
 
-static field_t _NetworkAccessParameters_distribution[] = {     /* CHOICE */
+static const struct field_t _NetworkAccessParameters_distribution[] = {        /* CHOICE */
        {FNAME("unicast") NUL, FIXD, 0, 0, SKIP, 0, NULL},
        {FNAME("multicast") NUL, FIXD, 0, 0, SKIP, 0, NULL},
 };
 
-static field_t _Q2931Address_address[] = {     /* CHOICE */
+static const struct field_t _Q2931Address_address[] = {        /* CHOICE */
        {FNAME("internationalNumber") NUMSTR, 4, 1, 0, SKIP, 0, NULL},
        {FNAME("nsapAddress") OCTSTR, 5, 1, 0, SKIP, 0, NULL},
 };
 
-static field_t _Q2931Address[] = {     /* SEQUENCE */
+static const struct field_t _Q2931Address[] = {        /* SEQUENCE */
        {FNAME("address") CHOICE, 1, 2, 2, SKIP | EXT, 0,
         _Q2931Address_address},
        {FNAME("subaddress") OCTSTR, 5, 1, 0, SKIP | OPT, 0, NULL},
 };
 
-static field_t _NetworkAccessParameters_networkAddress[] = {   /* CHOICE */
+static const struct field_t _NetworkAccessParameters_networkAddress[] = {      /* CHOICE */
        {FNAME("q2931Address") SEQ, 1, 2, 2, SKIP | EXT, 0, _Q2931Address},
        {FNAME("e164Address") NUMDGT, 7, 1, 0, SKIP, 0, NULL},
        {FNAME("localAreaAddress") CHOICE, 1, 2, 2, DECODE | EXT,
@@ -802,7 +802,7 @@ static field_t _NetworkAccessParameters_networkAddress[] = {        /* CHOICE */
         _H245_TransportAddress},
 };
 
-static field_t _NetworkAccessParameters[] = {  /* SEQUENCE */
+static const struct field_t _NetworkAccessParameters[] = {     /* SEQUENCE */
        {FNAME("distribution") CHOICE, 1, 2, 2, SKIP | EXT | OPT, 0,
         _NetworkAccessParameters_distribution},
        {FNAME("networkAddress") CHOICE, 2, 3, 3, DECODE | EXT,
@@ -814,7 +814,7 @@ static field_t _NetworkAccessParameters[] = {       /* SEQUENCE */
         NULL},
 };
 
-static field_t _OpenLogicalChannel[] = {       /* SEQUENCE */
+static const struct field_t _OpenLogicalChannel[] = {  /* SEQUENCE */
        {FNAME("forwardLogicalChannelNumber") INT, WORD, 1, 0, SKIP, 0, NULL},
        {FNAME("forwardLogicalChannelParameters") SEQ, 1, 3, 5, DECODE | EXT,
         offsetof(OpenLogicalChannel, forwardLogicalChannelParameters),
@@ -829,13 +829,13 @@ static field_t _OpenLogicalChannel[] = {  /* SEQUENCE */
        {FNAME("encryptionSync") SEQ, 2, 4, 4, STOP | EXT | OPT, 0, NULL},
 };
 
-static field_t _Setup_UUIE_fastStart[] = {     /* SEQUENCE OF */
+static const struct field_t _Setup_UUIE_fastStart[] = {        /* SEQUENCE OF */
        {FNAME("item") SEQ, 1, 3, 5, DECODE | OPEN | EXT,
         sizeof(OpenLogicalChannel), _OpenLogicalChannel}
        ,
 };
 
-static field_t _Setup_UUIE[] = {       /* SEQUENCE */
+static const struct field_t _Setup_UUIE[] = {  /* SEQUENCE */
        {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL},
        {FNAME("h245Address") CHOICE, 3, 7, 7, DECODE | EXT | OPT,
         offsetof(Setup_UUIE, h245Address), _TransportAddress},
@@ -894,13 +894,13 @@ static field_t _Setup_UUIE[] = {  /* SEQUENCE */
         NULL},
 };
 
-static field_t _CallProceeding_UUIE_fastStart[] = {    /* SEQUENCE OF */
+static const struct field_t _CallProceeding_UUIE_fastStart[] = {       /* SEQUENCE OF */
        {FNAME("item") SEQ, 1, 3, 5, DECODE | OPEN | EXT,
         sizeof(OpenLogicalChannel), _OpenLogicalChannel}
        ,
 };
 
-static field_t _CallProceeding_UUIE[] = {      /* SEQUENCE */
+static const struct field_t _CallProceeding_UUIE[] = { /* SEQUENCE */
        {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL},
        {FNAME("destinationInfo") SEQ, 6, 8, 10, SKIP | EXT, 0,
         _EndpointType},
@@ -920,13 +920,13 @@ static field_t _CallProceeding_UUIE[] = { /* SEQUENCE */
        {FNAME("featureSet") SEQ, 3, 4, 4, SKIP | EXT | OPT, 0, NULL},
 };
 
-static field_t _Connect_UUIE_fastStart[] = {   /* SEQUENCE OF */
+static const struct field_t _Connect_UUIE_fastStart[] = {      /* SEQUENCE OF */
        {FNAME("item") SEQ, 1, 3, 5, DECODE | OPEN | EXT,
         sizeof(OpenLogicalChannel), _OpenLogicalChannel}
        ,
 };
 
-static field_t _Connect_UUIE[] = {     /* SEQUENCE */
+static const struct field_t _Connect_UUIE[] = {        /* SEQUENCE */
        {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL},
        {FNAME("h245Address") CHOICE, 3, 7, 7, DECODE | EXT | OPT,
         offsetof(Connect_UUIE, h245Address), _TransportAddress},
@@ -954,13 +954,13 @@ static field_t _Connect_UUIE[] = {        /* SEQUENCE */
        {FNAME("featureSet") SEQ, 3, 4, 4, SKIP | EXT | OPT, 0, NULL},
 };
 
-static field_t _Alerting_UUIE_fastStart[] = {  /* SEQUENCE OF */
+static const struct field_t _Alerting_UUIE_fastStart[] = {     /* SEQUENCE OF */
        {FNAME("item") SEQ, 1, 3, 5, DECODE | OPEN | EXT,
         sizeof(OpenLogicalChannel), _OpenLogicalChannel}
        ,
 };
 
-static field_t _Alerting_UUIE[] = {    /* SEQUENCE */
+static const struct field_t _Alerting_UUIE[] = {       /* SEQUENCE */
        {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL},
        {FNAME("destinationInfo") SEQ, 6, 8, 10, SKIP | EXT, 0,
         _EndpointType},
@@ -986,7 +986,7 @@ static field_t _Alerting_UUIE[] = { /* SEQUENCE */
        {FNAME("featureSet") SEQ, 3, 4, 4, SKIP | EXT | OPT, 0, NULL},
 };
 
-static field_t _Information_UUIE[] = { /* SEQUENCE */
+static const struct field_t _Information_UUIE[] = {    /* SEQUENCE */
        {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL},
        {FNAME("callIdentifier") SEQ, 0, 1, 1, SKIP | EXT, 0, NULL},
        {FNAME("tokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL},
@@ -996,7 +996,7 @@ static field_t _Information_UUIE[] = {      /* SEQUENCE */
        {FNAME("circuitInfo") SEQ, 3, 3, 3, SKIP | EXT | OPT, 0, NULL},
 };
 
-static field_t _ReleaseCompleteReason[] = {    /* CHOICE */
+static const struct field_t _ReleaseCompleteReason[] = {       /* CHOICE */
        {FNAME("noBandwidth") NUL, FIXD, 0, 0, SKIP, 0, NULL},
        {FNAME("gatekeeperResources") NUL, FIXD, 0, 0, SKIP, 0, NULL},
        {FNAME("unreachableDestination") NUL, FIXD, 0, 0, SKIP, 0, NULL},
@@ -1022,7 +1022,7 @@ static field_t _ReleaseCompleteReason[] = {       /* CHOICE */
        {FNAME("tunnelledSignallingRejected") NUL, FIXD, 0, 0, SKIP, 0, NULL},
 };
 
-static field_t _ReleaseComplete_UUIE[] = {     /* SEQUENCE */
+static const struct field_t _ReleaseComplete_UUIE[] = {        /* SEQUENCE */
        {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL},
        {FNAME("reason") CHOICE, 4, 12, 22, SKIP | EXT | OPT, 0,
         _ReleaseCompleteReason},
@@ -1039,11 +1039,11 @@ static field_t _ReleaseComplete_UUIE[] = {      /* SEQUENCE */
        {FNAME("featureSet") SEQ, 3, 4, 4, SKIP | EXT | OPT, 0, NULL},
 };
 
-static field_t _Facility_UUIE_alternativeAliasAddress[] = {    /* SEQUENCE OF */
+static const struct field_t _Facility_UUIE_alternativeAliasAddress[] = {       /* SEQUENCE OF */
        {FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress},
 };
 
-static field_t _FacilityReason[] = {   /* CHOICE */
+static const struct field_t _FacilityReason[] = {      /* CHOICE */
        {FNAME("routeCallToGatekeeper") NUL, FIXD, 0, 0, SKIP, 0, NULL},
        {FNAME("callForwarded") NUL, FIXD, 0, 0, SKIP, 0, NULL},
        {FNAME("routeCallToMC") NUL, FIXD, 0, 0, SKIP, 0, NULL},
@@ -1057,13 +1057,13 @@ static field_t _FacilityReason[] = {    /* CHOICE */
        {FNAME("transportedInformation") NUL, FIXD, 0, 0, SKIP, 0, NULL},
 };
 
-static field_t _Facility_UUIE_fastStart[] = {  /* SEQUENCE OF */
+static const struct field_t _Facility_UUIE_fastStart[] = {     /* SEQUENCE OF */
        {FNAME("item") SEQ, 1, 3, 5, DECODE | OPEN | EXT,
         sizeof(OpenLogicalChannel), _OpenLogicalChannel}
        ,
 };
 
-static field_t _Facility_UUIE[] = {    /* SEQUENCE */
+static const struct field_t _Facility_UUIE[] = {       /* SEQUENCE */
        {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL},
        {FNAME("alternativeAddress") CHOICE, 3, 7, 7, DECODE | EXT | OPT,
         offsetof(Facility_UUIE, alternativeAddress), _TransportAddress},
@@ -1094,17 +1094,17 @@ static field_t _Facility_UUIE[] = {     /* SEQUENCE */
         NULL},
 };
 
-static field_t _CallIdentifier[] = {   /* SEQUENCE */
+static const struct field_t _CallIdentifier[] = {      /* SEQUENCE */
        {FNAME("guid") OCTSTR, FIXD, 16, 0, SKIP, 0, NULL},
 };
 
-static field_t _SecurityServiceMode[] = {      /* CHOICE */
+static const struct field_t _SecurityServiceMode[] = { /* CHOICE */
        {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP, 0, _NonStandardParameter},
        {FNAME("none") NUL, FIXD, 0, 0, SKIP, 0, NULL},
        {FNAME("default") NUL, FIXD, 0, 0, SKIP, 0, NULL},
 };
 
-static field_t _SecurityCapabilities[] = {     /* SEQUENCE */
+static const struct field_t _SecurityCapabilities[] = {        /* SEQUENCE */
        {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP | OPT, 0,
         _NonStandardParameter},
        {FNAME("encryption") CHOICE, 2, 3, 3, SKIP | EXT, 0,
@@ -1115,30 +1115,30 @@ static field_t _SecurityCapabilities[] = {      /* SEQUENCE */
         _SecurityServiceMode},
 };
 
-static field_t _H245Security[] = {     /* CHOICE */
+static const struct field_t _H245Security[] = {        /* CHOICE */
        {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP, 0, _NonStandardParameter},
        {FNAME("noSecurity") NUL, FIXD, 0, 0, SKIP, 0, NULL},
        {FNAME("tls") SEQ, 1, 4, 4, SKIP | EXT, 0, _SecurityCapabilities},
        {FNAME("ipsec") SEQ, 1, 4, 4, SKIP | EXT, 0, _SecurityCapabilities},
 };
 
-static field_t _DHset[] = {    /* SEQUENCE */
+static const struct field_t _DHset[] = {       /* SEQUENCE */
        {FNAME("halfkey") BITSTR, WORD, 0, 0, SKIP, 0, NULL},
        {FNAME("modSize") BITSTR, WORD, 0, 0, SKIP, 0, NULL},
        {FNAME("generator") BITSTR, WORD, 0, 0, SKIP, 0, NULL},
 };
 
-static field_t _TypedCertificate[] = { /* SEQUENCE */
+static const struct field_t _TypedCertificate[] = {    /* SEQUENCE */
        {FNAME("type") OID, BYTE, 0, 0, SKIP, 0, NULL},
        {FNAME("certificate") OCTSTR, SEMI, 0, 0, SKIP, 0, NULL},
 };
 
-static field_t _H235_NonStandardParameter[] = {        /* SEQUENCE */
+static const struct field_t _H235_NonStandardParameter[] = {   /* SEQUENCE */
        {FNAME("nonStandardIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL},
        {FNAME("data") OCTSTR, SEMI, 0, 0, SKIP, 0, NULL},
 };
 
-static field_t _ClearToken[] = {       /* SEQUENCE */
+static const struct field_t _ClearToken[] = {  /* SEQUENCE */
        {FNAME("tokenOID") OID, BYTE, 0, 0, SKIP, 0, NULL},
        {FNAME("timeStamp") INT, CONS, 1, 0, SKIP | OPT, 0, NULL},
        {FNAME("password") BMPSTR, 7, 1, 0, SKIP | OPT, 0, NULL},
@@ -1154,120 +1154,120 @@ static field_t _ClearToken[] = {      /* SEQUENCE */
        {FNAME("sendersID") BMPSTR, 7, 1, 0, SKIP | OPT, 0, NULL},
 };
 
-static field_t _Progress_UUIE_tokens[] = {     /* SEQUENCE OF */
+static const struct field_t _Progress_UUIE_tokens[] = {        /* SEQUENCE OF */
        {FNAME("item") SEQ, 8, 9, 11, SKIP | EXT, 0, _ClearToken},
 };
 
-static field_t _Params[] = {   /* SEQUENCE */
+static const struct field_t _Params[] = {      /* SEQUENCE */
        {FNAME("ranInt") INT, UNCO, 0, 0, SKIP | OPT, 0, NULL},
        {FNAME("iv8") OCTSTR, FIXD, 8, 0, SKIP | OPT, 0, NULL},
        {FNAME("iv16") OCTSTR, FIXD, 16, 0, SKIP | OPT, 0, NULL},
 };
 
-static field_t _CryptoH323Token_cryptoEPPwdHash_token[] = {    /* SEQUENCE */
+static const struct field_t _CryptoH323Token_cryptoEPPwdHash_token[] = {       /* SEQUENCE */
        {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL},
        {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params},
        {FNAME("hash") BITSTR, SEMI, 0, 0, SKIP, 0, NULL},
 };
 
-static field_t _CryptoH323Token_cryptoEPPwdHash[] = {  /* SEQUENCE */
+static const struct field_t _CryptoH323Token_cryptoEPPwdHash[] = {     /* SEQUENCE */
        {FNAME("alias") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress},
        {FNAME("timeStamp") INT, CONS, 1, 0, SKIP, 0, NULL},
        {FNAME("token") SEQ, 0, 3, 3, SKIP, 0,
         _CryptoH323Token_cryptoEPPwdHash_token},
 };
 
-static field_t _CryptoH323Token_cryptoGKPwdHash_token[] = {    /* SEQUENCE */
+static const struct field_t _CryptoH323Token_cryptoGKPwdHash_token[] = {       /* SEQUENCE */
        {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL},
        {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params},
        {FNAME("hash") BITSTR, SEMI, 0, 0, SKIP, 0, NULL},
 };
 
-static field_t _CryptoH323Token_cryptoGKPwdHash[] = {  /* SEQUENCE */
+static const struct field_t _CryptoH323Token_cryptoGKPwdHash[] = {     /* SEQUENCE */
        {FNAME("gatekeeperId") BMPSTR, 7, 1, 0, SKIP, 0, NULL},
        {FNAME("timeStamp") INT, CONS, 1, 0, SKIP, 0, NULL},
        {FNAME("token") SEQ, 0, 3, 3, SKIP, 0,
         _CryptoH323Token_cryptoGKPwdHash_token},
 };
 
-static field_t _CryptoH323Token_cryptoEPPwdEncr[] = {  /* SEQUENCE */
+static const struct field_t _CryptoH323Token_cryptoEPPwdEncr[] = {     /* SEQUENCE */
        {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL},
        {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params},
        {FNAME("encryptedData") OCTSTR, SEMI, 0, 0, SKIP, 0, NULL},
 };
 
-static field_t _CryptoH323Token_cryptoGKPwdEncr[] = {  /* SEQUENCE */
+static const struct field_t _CryptoH323Token_cryptoGKPwdEncr[] = {     /* SEQUENCE */
        {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL},
        {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params},
        {FNAME("encryptedData") OCTSTR, SEMI, 0, 0, SKIP, 0, NULL},
 };
 
-static field_t _CryptoH323Token_cryptoEPCert[] = {     /* SEQUENCE */
+static const struct field_t _CryptoH323Token_cryptoEPCert[] = {        /* SEQUENCE */
        {FNAME("toBeSigned") SEQ, 8, 9, 11, SKIP | OPEN | EXT, 0, NULL},
        {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL},
        {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params},
        {FNAME("signature") BITSTR, SEMI, 0, 0, SKIP, 0, NULL},
 };
 
-static field_t _CryptoH323Token_cryptoGKCert[] = {     /* SEQUENCE */
+static const struct field_t _CryptoH323Token_cryptoGKCert[] = {        /* SEQUENCE */
        {FNAME("toBeSigned") SEQ, 8, 9, 11, SKIP | OPEN | EXT, 0, NULL},
        {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL},
        {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params},
        {FNAME("signature") BITSTR, SEMI, 0, 0, SKIP, 0, NULL},
 };
 
-static field_t _CryptoH323Token_cryptoFastStart[] = {  /* SEQUENCE */
+static const struct field_t _CryptoH323Token_cryptoFastStart[] = {     /* SEQUENCE */
        {FNAME("toBeSigned") SEQ, 8, 9, 11, SKIP | OPEN | EXT, 0, NULL},
        {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL},
        {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params},
        {FNAME("signature") BITSTR, SEMI, 0, 0, SKIP, 0, NULL},
 };
 
-static field_t _CryptoToken_cryptoEncryptedToken_token[] = {   /* SEQUENCE */
+static const struct field_t _CryptoToken_cryptoEncryptedToken_token[] = {      /* SEQUENCE */
        {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL},
        {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params},
        {FNAME("encryptedData") OCTSTR, SEMI, 0, 0, SKIP, 0, NULL},
 };
 
-static field_t _CryptoToken_cryptoEncryptedToken[] = { /* SEQUENCE */
+static const struct field_t _CryptoToken_cryptoEncryptedToken[] = {    /* SEQUENCE */
        {FNAME("tokenOID") OID, BYTE, 0, 0, SKIP, 0, NULL},
        {FNAME("token") SEQ, 0, 3, 3, SKIP, 0,
         _CryptoToken_cryptoEncryptedToken_token},
 };
 
-static field_t _CryptoToken_cryptoSignedToken_token[] = {      /* SEQUENCE */
+static const struct field_t _CryptoToken_cryptoSignedToken_token[] = { /* SEQUENCE */
        {FNAME("toBeSigned") SEQ, 8, 9, 11, SKIP | OPEN | EXT, 0, NULL},
        {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL},
        {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params},
        {FNAME("signature") BITSTR, SEMI, 0, 0, SKIP, 0, NULL},
 };
 
-static field_t _CryptoToken_cryptoSignedToken[] = {    /* SEQUENCE */
+static const struct field_t _CryptoToken_cryptoSignedToken[] = {       /* SEQUENCE */
        {FNAME("tokenOID") OID, BYTE, 0, 0, SKIP, 0, NULL},
        {FNAME("token") SEQ, 0, 4, 4, SKIP, 0,
         _CryptoToken_cryptoSignedToken_token},
 };
 
-static field_t _CryptoToken_cryptoHashedToken_token[] = {      /* SEQUENCE */
+static const struct field_t _CryptoToken_cryptoHashedToken_token[] = { /* SEQUENCE */
        {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL},
        {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params},
        {FNAME("hash") BITSTR, SEMI, 0, 0, SKIP, 0, NULL},
 };
 
-static field_t _CryptoToken_cryptoHashedToken[] = {    /* SEQUENCE */
+static const struct field_t _CryptoToken_cryptoHashedToken[] = {       /* SEQUENCE */
        {FNAME("tokenOID") OID, BYTE, 0, 0, SKIP, 0, NULL},
        {FNAME("hashedVals") SEQ, 8, 9, 11, SKIP | EXT, 0, _ClearToken},
        {FNAME("token") SEQ, 0, 3, 3, SKIP, 0,
         _CryptoToken_cryptoHashedToken_token},
 };
 
-static field_t _CryptoToken_cryptoPwdEncr[] = {        /* SEQUENCE */
+static const struct field_t _CryptoToken_cryptoPwdEncr[] = {   /* SEQUENCE */
        {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL},
        {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params},
        {FNAME("encryptedData") OCTSTR, SEMI, 0, 0, SKIP, 0, NULL},
 };
 
-static field_t _CryptoToken[] = {      /* CHOICE */
+static const struct field_t _CryptoToken[] = { /* CHOICE */
        {FNAME("cryptoEncryptedToken") SEQ, 0, 2, 2, SKIP, 0,
         _CryptoToken_cryptoEncryptedToken},
        {FNAME("cryptoSignedToken") SEQ, 0, 2, 2, SKIP, 0,
@@ -1278,7 +1278,7 @@ static field_t _CryptoToken[] = { /* CHOICE */
         _CryptoToken_cryptoPwdEncr},
 };
 
-static field_t _CryptoH323Token[] = {  /* CHOICE */
+static const struct field_t _CryptoH323Token[] = {     /* CHOICE */
        {FNAME("cryptoEPPwdHash") SEQ, 0, 3, 3, SKIP, 0,
         _CryptoH323Token_cryptoEPPwdHash},
        {FNAME("cryptoGKPwdHash") SEQ, 0, 3, 3, SKIP, 0,
@@ -1297,17 +1297,17 @@ static field_t _CryptoH323Token[] = {   /* CHOICE */
         _CryptoToken},
 };
 
-static field_t _Progress_UUIE_cryptoTokens[] = {       /* SEQUENCE OF */
+static const struct field_t _Progress_UUIE_cryptoTokens[] = {  /* SEQUENCE OF */
        {FNAME("item") CHOICE, 3, 8, 8, SKIP | EXT, 0, _CryptoH323Token},
 };
 
-static field_t _Progress_UUIE_fastStart[] = {  /* SEQUENCE OF */
+static const struct field_t _Progress_UUIE_fastStart[] = {     /* SEQUENCE OF */
        {FNAME("item") SEQ, 1, 3, 5, DECODE | OPEN | EXT,
         sizeof(OpenLogicalChannel), _OpenLogicalChannel}
        ,
 };
 
-static field_t _Progress_UUIE[] = {    /* SEQUENCE */
+static const struct field_t _Progress_UUIE[] = {       /* SEQUENCE */
        {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL},
        {FNAME("destinationInfo") SEQ, 6, 8, 10, SKIP | EXT, 0,
         _EndpointType},
@@ -1328,7 +1328,7 @@ static field_t _Progress_UUIE[] = {       /* SEQUENCE */
        {FNAME("fastConnectRefused") NUL, FIXD, 0, 0, SKIP | OPT, 0, NULL},
 };
 
-static field_t _H323_UU_PDU_h323_message_body[] = {    /* CHOICE */
+static const struct field_t _H323_UU_PDU_h323_message_body[] = {       /* CHOICE */
        {FNAME("setup") SEQ, 7, 13, 39, DECODE | EXT,
         offsetof(H323_UU_PDU_h323_message_body, setup), _Setup_UUIE},
        {FNAME("callProceeding") SEQ, 1, 3, 12, DECODE | EXT,
@@ -1352,7 +1352,7 @@ static field_t _H323_UU_PDU_h323_message_body[] = {       /* CHOICE */
        {FNAME("notify") SEQ, 2, 4, 4, SKIP | EXT, 0, NULL},
 };
 
-static field_t _RequestMessage[] = {   /* CHOICE */
+static const struct field_t _RequestMessage[] = {      /* CHOICE */
        {FNAME("nonStandard") SEQ, 0, 1, 1, STOP | EXT, 0, NULL},
        {FNAME("masterSlaveDetermination") SEQ, 0, 2, 2, STOP | EXT, 0, NULL},
        {FNAME("terminalCapabilitySet") SEQ, 3, 5, 5, STOP | EXT, 0, NULL},
@@ -1372,7 +1372,7 @@ static field_t _RequestMessage[] = {      /* CHOICE */
         NULL},
 };
 
-static field_t _OpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters[] = {        /* CHOICE */
+static const struct field_t _OpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters[] = {   /* CHOICE */
        {FNAME("h222LogicalChannelParameters") SEQ, 3, 5, 5, SKIP | EXT, 0,
         _H222LogicalChannelParameters},
        {FNAME("h2250LogicalChannelParameters") SEQ, 10, 11, 14, DECODE | EXT,
@@ -1381,7 +1381,7 @@ static field_t _OpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexP
          h2250LogicalChannelParameters), _H2250LogicalChannelParameters},
 };
 
-static field_t _OpenLogicalChannelAck_reverseLogicalChannelParameters[] = {    /* SEQUENCE */
+static const struct field_t _OpenLogicalChannelAck_reverseLogicalChannelParameters[] = {       /* SEQUENCE */
        {FNAME("reverseLogicalChannelNumber") INT, WORD, 1, 0, SKIP, 0, NULL},
        {FNAME("portNumber") INT, WORD, 0, 0, SKIP | OPT, 0, NULL},
        {FNAME("multiplexParameters") CHOICE, 0, 1, 2, DECODE | EXT | OPT,
@@ -1391,11 +1391,11 @@ static field_t _OpenLogicalChannelAck_reverseLogicalChannelParameters[] = {     /* S
        {FNAME("replacementFor") INT, WORD, 1, 0, SKIP | OPT, 0, NULL},
 };
 
-static field_t _H2250LogicalChannelAckParameters_nonStandard[] = {     /* SEQUENCE OF */
+static const struct field_t _H2250LogicalChannelAckParameters_nonStandard[] = {        /* SEQUENCE OF */
        {FNAME("item") SEQ, 0, 2, 2, SKIP, 0, _H245_NonStandardParameter},
 };
 
-static field_t _H2250LogicalChannelAckParameters[] = { /* SEQUENCE */
+static const struct field_t _H2250LogicalChannelAckParameters[] = {    /* SEQUENCE */
        {FNAME("nonStandard") SEQOF, SEMI, 0, 0, SKIP | OPT, 0,
         _H2250LogicalChannelAckParameters_nonStandard},
        {FNAME("sessionID") INT, 8, 1, 0, SKIP | OPT, 0, NULL},
@@ -1410,14 +1410,14 @@ static field_t _H2250LogicalChannelAckParameters[] = {  /* SEQUENCE */
        {FNAME("portNumber") INT, WORD, 0, 0, SKIP | OPT, 0, NULL},
 };
 
-static field_t _OpenLogicalChannelAck_forwardMultiplexAckParameters[] = {      /* CHOICE */
+static const struct field_t _OpenLogicalChannelAck_forwardMultiplexAckParameters[] = { /* CHOICE */
        {FNAME("h2250LogicalChannelAckParameters") SEQ, 5, 5, 7, DECODE | EXT,
         offsetof(OpenLogicalChannelAck_forwardMultiplexAckParameters,
                  h2250LogicalChannelAckParameters),
         _H2250LogicalChannelAckParameters},
 };
 
-static field_t _OpenLogicalChannelAck[] = {    /* SEQUENCE */
+static const struct field_t _OpenLogicalChannelAck[] = {       /* SEQUENCE */
        {FNAME("forwardLogicalChannelNumber") INT, WORD, 1, 0, SKIP, 0, NULL},
        {FNAME("reverseLogicalChannelParameters") SEQ, 2, 3, 4,
         DECODE | EXT | OPT, offsetof(OpenLogicalChannelAck,
@@ -1433,7 +1433,7 @@ static field_t _OpenLogicalChannelAck[] = {       /* SEQUENCE */
        {FNAME("encryptionSync") SEQ, 2, 4, 4, STOP | EXT | OPT, 0, NULL},
 };
 
-static field_t _ResponseMessage[] = {  /* CHOICE */
+static const struct field_t _ResponseMessage[] = {     /* CHOICE */
        {FNAME("nonStandard") SEQ, 0, 1, 1, STOP | EXT, 0, NULL},
        {FNAME("masterSlaveDeterminationAck") SEQ, 0, 1, 1, STOP | EXT, 0,
         NULL},
@@ -1469,7 +1469,7 @@ static field_t _ResponseMessage[] = {     /* CHOICE */
        {FNAME("logicalChannelRateReject") SEQ, 1, 4, 4, STOP | EXT, 0, NULL},
 };
 
-static field_t _MultimediaSystemControlMessage[] = {   /* CHOICE */
+static const struct field_t _MultimediaSystemControlMessage[] = {      /* CHOICE */
        {FNAME("request") CHOICE, 4, 11, 15, DECODE | EXT,
         offsetof(MultimediaSystemControlMessage, request), _RequestMessage},
        {FNAME("response") CHOICE, 5, 19, 24, DECODE | EXT,
@@ -1479,14 +1479,14 @@ static field_t _MultimediaSystemControlMessage[] = {    /* CHOICE */
        {FNAME("indication") CHOICE, 4, 14, 23, STOP | EXT, 0, NULL},
 };
 
-static field_t _H323_UU_PDU_h245Control[] = {  /* SEQUENCE OF */
+static const struct field_t _H323_UU_PDU_h245Control[] = {     /* SEQUENCE OF */
        {FNAME("item") CHOICE, 2, 4, 4, DECODE | OPEN | EXT,
         sizeof(MultimediaSystemControlMessage),
         _MultimediaSystemControlMessage}
        ,
 };
 
-static field_t _H323_UU_PDU[] = {      /* SEQUENCE */
+static const struct field_t _H323_UU_PDU[] = { /* SEQUENCE */
        {FNAME("h323-message-body") CHOICE, 3, 7, 13, DECODE | EXT,
         offsetof(H323_UU_PDU, h323_message_body),
         _H323_UU_PDU_h323_message_body},
@@ -1507,13 +1507,13 @@ static field_t _H323_UU_PDU[] = {       /* SEQUENCE */
        {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL},
 };
 
-static field_t _H323_UserInformation[] = {     /* SEQUENCE */
+static const struct field_t _H323_UserInformation[] = {        /* SEQUENCE */
        {FNAME("h323-uu-pdu") SEQ, 1, 2, 11, DECODE | EXT,
         offsetof(H323_UserInformation, h323_uu_pdu), _H323_UU_PDU},
        {FNAME("user-data") SEQ, 0, 2, 2, STOP | EXT | OPT, 0, NULL},
 };
 
-static field_t _GatekeeperRequest[] = {        /* SEQUENCE */
+static const struct field_t _GatekeeperRequest[] = {   /* SEQUENCE */
        {FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL},
        {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL},
        {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0,
@@ -1537,7 +1537,7 @@ static field_t _GatekeeperRequest[] = {   /* SEQUENCE */
        {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL},
 };
 
-static field_t _GatekeeperConfirm[] = {        /* SEQUENCE */
+static const struct field_t _GatekeeperConfirm[] = {   /* SEQUENCE */
        {FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL},
        {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL},
        {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0,
@@ -1557,23 +1557,23 @@ static field_t _GatekeeperConfirm[] = { /* SEQUENCE */
        {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL},
 };
 
-static field_t _RegistrationRequest_callSignalAddress[] = {    /* SEQUENCE OF */
+static const struct field_t _RegistrationRequest_callSignalAddress[] = {       /* SEQUENCE OF */
        {FNAME("item") CHOICE, 3, 7, 7, DECODE | EXT,
         sizeof(TransportAddress), _TransportAddress}
        ,
 };
 
-static field_t _RegistrationRequest_rasAddress[] = {   /* SEQUENCE OF */
+static const struct field_t _RegistrationRequest_rasAddress[] = {      /* SEQUENCE OF */
        {FNAME("item") CHOICE, 3, 7, 7, DECODE | EXT,
         sizeof(TransportAddress), _TransportAddress}
        ,
 };
 
-static field_t _RegistrationRequest_terminalAlias[] = {        /* SEQUENCE OF */
+static const struct field_t _RegistrationRequest_terminalAlias[] = {   /* SEQUENCE OF */
        {FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress},
 };
 
-static field_t _RegistrationRequest[] = {      /* SEQUENCE */
+static const struct field_t _RegistrationRequest[] = { /* SEQUENCE */
        {FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL},
        {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL},
        {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0,
@@ -1621,17 +1621,17 @@ static field_t _RegistrationRequest[] = {       /* SEQUENCE */
        {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL},
 };
 
-static field_t _RegistrationConfirm_callSignalAddress[] = {    /* SEQUENCE OF */
+static const struct field_t _RegistrationConfirm_callSignalAddress[] = {       /* SEQUENCE OF */
        {FNAME("item") CHOICE, 3, 7, 7, DECODE | EXT,
         sizeof(TransportAddress), _TransportAddress}
        ,
 };
 
-static field_t _RegistrationConfirm_terminalAlias[] = {        /* SEQUENCE OF */
+static const struct field_t _RegistrationConfirm_terminalAlias[] = {   /* SEQUENCE OF */
        {FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress},
 };
 
-static field_t _RegistrationConfirm[] = {      /* SEQUENCE */
+static const struct field_t _RegistrationConfirm[] = { /* SEQUENCE */
        {FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL},
        {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL},
        {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0,
@@ -1667,13 +1667,13 @@ static field_t _RegistrationConfirm[] = {       /* SEQUENCE */
        {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL},
 };
 
-static field_t _UnregistrationRequest_callSignalAddress[] = {  /* SEQUENCE OF */
+static const struct field_t _UnregistrationRequest_callSignalAddress[] = {     /* SEQUENCE OF */
        {FNAME("item") CHOICE, 3, 7, 7, DECODE | EXT,
         sizeof(TransportAddress), _TransportAddress}
        ,
 };
 
-static field_t _UnregistrationRequest[] = {    /* SEQUENCE */
+static const struct field_t _UnregistrationRequest[] = {       /* SEQUENCE */
        {FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL},
        {FNAME("callSignalAddress") SEQOF, SEMI, 0, 10, DECODE,
         offsetof(UnregistrationRequest, callSignalAddress),
@@ -1694,24 +1694,24 @@ static field_t _UnregistrationRequest[] = {     /* SEQUENCE */
        {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL},
 };
 
-static field_t _CallModel[] = {        /* CHOICE */
+static const struct field_t _CallModel[] = {   /* CHOICE */
        {FNAME("direct") NUL, FIXD, 0, 0, SKIP, 0, NULL},
        {FNAME("gatekeeperRouted") NUL, FIXD, 0, 0, SKIP, 0, NULL},
 };
 
-static field_t _AdmissionRequest_destinationInfo[] = { /* SEQUENCE OF */
+static const struct field_t _AdmissionRequest_destinationInfo[] = {    /* SEQUENCE OF */
        {FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress},
 };
 
-static field_t _AdmissionRequest_destExtraCallInfo[] = {       /* SEQUENCE OF */
+static const struct field_t _AdmissionRequest_destExtraCallInfo[] = {  /* SEQUENCE OF */
        {FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress},
 };
 
-static field_t _AdmissionRequest_srcInfo[] = { /* SEQUENCE OF */
+static const struct field_t _AdmissionRequest_srcInfo[] = {    /* SEQUENCE OF */
        {FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress},
 };
 
-static field_t _AdmissionRequest[] = { /* SEQUENCE */
+static const struct field_t _AdmissionRequest[] = {    /* SEQUENCE */
        {FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL},
        {FNAME("callType") CHOICE, 2, 4, 4, SKIP | EXT, 0, _CallType},
        {FNAME("callModel") CHOICE, 1, 2, 2, SKIP | EXT | OPT, 0, _CallModel},
@@ -1755,7 +1755,7 @@ static field_t _AdmissionRequest[] = {    /* SEQUENCE */
        {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL},
 };
 
-static field_t _AdmissionConfirm[] = { /* SEQUENCE */
+static const struct field_t _AdmissionConfirm[] = {    /* SEQUENCE */
        {FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL},
        {FNAME("bandWidth") INT, CONS, 0, 0, SKIP, 0, NULL},
        {FNAME("callModel") CHOICE, 1, 2, 2, SKIP | EXT, 0, _CallModel},
@@ -1790,11 +1790,11 @@ static field_t _AdmissionConfirm[] = {  /* SEQUENCE */
        {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL},
 };
 
-static field_t _LocationRequest_destinationInfo[] = {  /* SEQUENCE OF */
+static const struct field_t _LocationRequest_destinationInfo[] = {     /* SEQUENCE OF */
        {FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress},
 };
 
-static field_t _LocationRequest[] = {  /* SEQUENCE */
+static const struct field_t _LocationRequest[] = {     /* SEQUENCE */
        {FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL},
        {FNAME("endpointIdentifier") BMPSTR, 7, 1, 0, SKIP | OPT, 0, NULL},
        {FNAME("destinationInfo") SEQOF, SEMI, 0, 0, SKIP, 0,
@@ -1818,7 +1818,7 @@ static field_t _LocationRequest[] = {     /* SEQUENCE */
        {FNAME("circuitInfo") SEQ, 3, 3, 3, STOP | EXT | OPT, 0, NULL},
 };
 
-static field_t _LocationConfirm[] = {  /* SEQUENCE */
+static const struct field_t _LocationConfirm[] = {     /* SEQUENCE */
        {FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL},
        {FNAME("callSignalAddress") CHOICE, 3, 7, 7, DECODE | EXT,
         offsetof(LocationConfirm, callSignalAddress), _TransportAddress},
@@ -1844,13 +1844,13 @@ static field_t _LocationConfirm[] = {   /* SEQUENCE */
        {FNAME("serviceControl") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL},
 };
 
-static field_t _InfoRequestResponse_callSignalAddress[] = {    /* SEQUENCE OF */
+static const struct field_t _InfoRequestResponse_callSignalAddress[] = {       /* SEQUENCE OF */
        {FNAME("item") CHOICE, 3, 7, 7, DECODE | EXT,
         sizeof(TransportAddress), _TransportAddress}
        ,
 };
 
-static field_t _InfoRequestResponse[] = {      /* SEQUENCE */
+static const struct field_t _InfoRequestResponse[] = { /* SEQUENCE */
        {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0,
         _NonStandardParameter},
        {FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL},
@@ -1873,7 +1873,7 @@ static field_t _InfoRequestResponse[] = { /* SEQUENCE */
        {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL},
 };
 
-static field_t _RasMessage[] = {       /* CHOICE */
+static const struct field_t _RasMessage[] = {  /* CHOICE */
        {FNAME("gatekeeperRequest") SEQ, 4, 8, 18, DECODE | EXT,
         offsetof(RasMessage, gatekeeperRequest), _GatekeeperRequest},
        {FNAME("gatekeeperConfirm") SEQ, 2, 5, 14, DECODE | EXT,
index 96aa637c09327e6c79a85ec6a76cd86228aa908a..b1fd21cc1dbc2e613ea15e6813bb550bcc6ce7cb 100644 (file)
@@ -28,6 +28,7 @@
 #include <net/netfilter/nf_conntrack_core.h>
 #include <net/netfilter/nf_conntrack_extend.h>
 
+static DEFINE_MUTEX(nf_ct_helper_mutex);
 static struct hlist_head *nf_ct_helper_hash __read_mostly;
 static unsigned int nf_ct_helper_hsize __read_mostly;
 static unsigned int nf_ct_helper_count __read_mostly;
@@ -54,42 +55,13 @@ __nf_ct_helper_find(const struct nf_conntrack_tuple *tuple)
                return NULL;
 
        h = helper_hash(tuple);
-       hlist_for_each_entry(helper, n, &nf_ct_helper_hash[h], hnode) {
+       hlist_for_each_entry_rcu(helper, n, &nf_ct_helper_hash[h], hnode) {
                if (nf_ct_tuple_src_mask_cmp(tuple, &helper->tuple, &mask))
                        return helper;
        }
        return NULL;
 }
-
-struct nf_conntrack_helper *
-nf_ct_helper_find_get(const struct nf_conntrack_tuple *tuple)
-{
-       struct nf_conntrack_helper *helper;
-
-       /* need nf_conntrack_lock to assure that helper exists until
-        * try_module_get() is called */
-       read_lock_bh(&nf_conntrack_lock);
-
-       helper = __nf_ct_helper_find(tuple);
-       if (helper) {
-               /* need to increase module usage count to assure helper will
-                * not go away while the caller is e.g. busy putting a
-                * conntrack in the hash that uses the helper */
-               if (!try_module_get(helper->me))
-                       helper = NULL;
-       }
-
-       read_unlock_bh(&nf_conntrack_lock);
-
-       return helper;
-}
-EXPORT_SYMBOL_GPL(nf_ct_helper_find_get);
-
-void nf_ct_helper_put(struct nf_conntrack_helper *helper)
-{
-       module_put(helper->me);
-}
-EXPORT_SYMBOL_GPL(nf_ct_helper_put);
+EXPORT_SYMBOL_GPL(__nf_ct_helper_find);
 
 struct nf_conntrack_helper *
 __nf_conntrack_helper_find_byname(const char *name)
@@ -99,7 +71,7 @@ __nf_conntrack_helper_find_byname(const char *name)
        unsigned int i;
 
        for (i = 0; i < nf_ct_helper_hsize; i++) {
-               hlist_for_each_entry(h, n, &nf_ct_helper_hash[i], hnode) {
+               hlist_for_each_entry_rcu(h, n, &nf_ct_helper_hash[i], hnode) {
                        if (!strcmp(h->name, name))
                                return h;
                }
@@ -140,10 +112,10 @@ int nf_conntrack_helper_register(struct nf_conntrack_helper *me)
 
        BUG_ON(me->timeout == 0);
 
-       write_lock_bh(&nf_conntrack_lock);
-       hlist_add_head(&me->hnode, &nf_ct_helper_hash[h]);
+       mutex_lock(&nf_ct_helper_mutex);
+       hlist_add_head_rcu(&me->hnode, &nf_ct_helper_hash[h]);
        nf_ct_helper_count++;
-       write_unlock_bh(&nf_conntrack_lock);
+       mutex_unlock(&nf_ct_helper_mutex);
 
        return 0;
 }
@@ -156,10 +128,17 @@ void nf_conntrack_helper_unregister(struct nf_conntrack_helper *me)
        struct hlist_node *n, *next;
        unsigned int i;
 
-       /* Need write lock here, to delete helper. */
-       write_lock_bh(&nf_conntrack_lock);
-       hlist_del(&me->hnode);
+       mutex_lock(&nf_ct_helper_mutex);
+       hlist_del_rcu(&me->hnode);
        nf_ct_helper_count--;
+       mutex_unlock(&nf_ct_helper_mutex);
+
+       /* Make sure every nothing is still using the helper unless its a
+        * connection in the hash.
+        */
+       synchronize_rcu();
+
+       spin_lock_bh(&nf_conntrack_lock);
 
        /* Get rid of expectations */
        for (i = 0; i < nf_ct_expect_hsize; i++) {
@@ -181,10 +160,7 @@ void nf_conntrack_helper_unregister(struct nf_conntrack_helper *me)
                hlist_for_each_entry(h, n, &nf_conntrack_hash[i], hnode)
                        unhelp(h, me);
        }
-       write_unlock_bh(&nf_conntrack_lock);
-
-       /* Someone could be still looking at the helper in a bh. */
-       synchronize_net();
+       spin_unlock_bh(&nf_conntrack_lock);
 }
 EXPORT_SYMBOL_GPL(nf_conntrack_helper_unregister);
 
index dfaed4ba83cd542783945e55c7a0edb13add4e11..c336b07a0d4c49e51cee1d9f6d3934fe79531c0a 100644 (file)
@@ -23,7 +23,7 @@
 
 #define MAX_PORTS 8
 static unsigned short ports[MAX_PORTS];
-static int ports_c;
+static unsigned int ports_c;
 static unsigned int max_dcc_channels = 8;
 static unsigned int dcc_timeout __read_mostly = 300;
 /* This is slow, but it's simple. --RR */
index 38141f104db7cfda21817140dce88f1d02bb0747..4a1b42b2b7a5bc55b7f4cdce9000a968caef2562 100644 (file)
@@ -491,11 +491,6 @@ static int ctnetlink_conntrack_event(struct notifier_block *this,
                    && ctnetlink_dump_helpinfo(skb, ct) < 0)
                        goto nla_put_failure;
 
-#ifdef CONFIG_NF_CONNTRACK_MARK
-               if ((events & IPCT_MARK || ct->mark)
-                   && ctnetlink_dump_mark(skb, ct) < 0)
-                       goto nla_put_failure;
-#endif
 #ifdef CONFIG_NF_CONNTRACK_SECMARK
                if ((events & IPCT_SECMARK || ct->secmark)
                    && ctnetlink_dump_secmark(skb, ct) < 0)
@@ -516,6 +511,12 @@ static int ctnetlink_conntrack_event(struct notifier_block *this,
                        goto nla_put_failure;
        }
 
+#ifdef CONFIG_NF_CONNTRACK_MARK
+       if ((events & IPCT_MARK || ct->mark)
+           && ctnetlink_dump_mark(skb, ct) < 0)
+               goto nla_put_failure;
+#endif
+
        nlh->nlmsg_len = skb->tail - b;
        nfnetlink_send(skb, 0, group, 0);
        return NOTIFY_DONE;
@@ -545,12 +546,12 @@ ctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
        struct nfgenmsg *nfmsg = NLMSG_DATA(cb->nlh);
        u_int8_t l3proto = nfmsg->nfgen_family;
 
-       read_lock_bh(&nf_conntrack_lock);
+       rcu_read_lock();
        last = (struct nf_conn *)cb->args[1];
        for (; cb->args[0] < nf_conntrack_htable_size; cb->args[0]++) {
 restart:
-               hlist_for_each_entry(h, n, &nf_conntrack_hash[cb->args[0]],
-                                    hnode) {
+               hlist_for_each_entry_rcu(h, n, &nf_conntrack_hash[cb->args[0]],
+                                        hnode) {
                        if (NF_CT_DIRECTION(h) != IP_CT_DIR_ORIGINAL)
                                continue;
                        ct = nf_ct_tuplehash_to_ctrack(h);
@@ -568,7 +569,8 @@ restart:
                                                cb->nlh->nlmsg_seq,
                                                IPCTNL_MSG_CT_NEW,
                                                1, ct) < 0) {
-                               nf_conntrack_get(&ct->ct_general);
+                               if (!atomic_inc_not_zero(&ct->ct_general.use))
+                                       continue;
                                cb->args[1] = (unsigned long)ct;
                                goto out;
                        }
@@ -584,7 +586,7 @@ restart:
                }
        }
 out:
-       read_unlock_bh(&nf_conntrack_lock);
+       rcu_read_unlock();
        if (last)
                nf_ct_put(last);
 
@@ -1167,11 +1169,12 @@ ctnetlink_create_conntrack(struct nlattr *cda[],
                ct->mark = ntohl(nla_get_be32(cda[CTA_MARK]));
 #endif
 
-       helper = nf_ct_helper_find_get(rtuple);
+       rcu_read_lock();
+       helper = __nf_ct_helper_find(rtuple);
        if (helper) {
                help = nf_ct_helper_ext_add(ct, GFP_KERNEL);
                if (help == NULL) {
-                       nf_ct_helper_put(helper);
+                       rcu_read_unlock();
                        err = -ENOMEM;
                        goto err;
                }
@@ -1187,9 +1190,7 @@ ctnetlink_create_conntrack(struct nlattr *cda[],
 
        add_timer(&ct->timeout);
        nf_conntrack_hash_insert(ct);
-
-       if (helper)
-               nf_ct_helper_put(helper);
+       rcu_read_unlock();
 
        return 0;
 
@@ -1220,11 +1221,11 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb,
                        return err;
        }
 
-       write_lock_bh(&nf_conntrack_lock);
+       spin_lock_bh(&nf_conntrack_lock);
        if (cda[CTA_TUPLE_ORIG])
-               h = __nf_conntrack_find(&otuple, NULL);
+               h = __nf_conntrack_find(&otuple);
        else if (cda[CTA_TUPLE_REPLY])
-               h = __nf_conntrack_find(&rtuple, NULL);
+               h = __nf_conntrack_find(&rtuple);
 
        if (h == NULL) {
                struct nf_conntrack_tuple master;
@@ -1237,9 +1238,9 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb,
                                                    CTA_TUPLE_MASTER,
                                                    u3);
                        if (err < 0)
-                               return err;
+                               goto out_unlock;
 
-                       master_h = __nf_conntrack_find(&master, NULL);
+                       master_h = __nf_conntrack_find(&master);
                        if (master_h == NULL) {
                                err = -ENOENT;
                                goto out_unlock;
@@ -1248,7 +1249,7 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb,
                        atomic_inc(&master_ct->ct_general.use);
                }
 
-               write_unlock_bh(&nf_conntrack_lock);
+               spin_unlock_bh(&nf_conntrack_lock);
                err = -ENOENT;
                if (nlh->nlmsg_flags & NLM_F_CREATE)
                        err = ctnetlink_create_conntrack(cda,
@@ -1281,7 +1282,7 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb,
        }
 
 out_unlock:
-       write_unlock_bh(&nf_conntrack_lock);
+       spin_unlock_bh(&nf_conntrack_lock);
        return err;
 }
 
@@ -1472,7 +1473,7 @@ ctnetlink_exp_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
        struct hlist_node *n;
        u_int8_t l3proto = nfmsg->nfgen_family;
 
-       read_lock_bh(&nf_conntrack_lock);
+       rcu_read_lock();
        last = (struct nf_conntrack_expect *)cb->args[1];
        for (; cb->args[0] < nf_ct_expect_hsize; cb->args[0]++) {
 restart:
@@ -1489,7 +1490,8 @@ restart:
                                                    cb->nlh->nlmsg_seq,
                                                    IPCTNL_MSG_EXP_NEW,
                                                    1, exp) < 0) {
-                               atomic_inc(&exp->use);
+                               if (!atomic_inc_not_zero(&exp->use))
+                                       continue;
                                cb->args[1] = (unsigned long)exp;
                                goto out;
                        }
@@ -1500,7 +1502,7 @@ restart:
                }
        }
 out:
-       read_unlock_bh(&nf_conntrack_lock);
+       rcu_read_unlock();
        if (last)
                nf_ct_expect_put(last);
 
@@ -1613,10 +1615,10 @@ ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb,
                struct nf_conn_help *m_help;
 
                /* delete all expectations for this helper */
-               write_lock_bh(&nf_conntrack_lock);
+               spin_lock_bh(&nf_conntrack_lock);
                h = __nf_conntrack_helper_find_byname(name);
                if (!h) {
-                       write_unlock_bh(&nf_conntrack_lock);
+                       spin_unlock_bh(&nf_conntrack_lock);
                        return -EINVAL;
                }
                for (i = 0; i < nf_ct_expect_hsize; i++) {
@@ -1631,10 +1633,10 @@ ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb,
                                }
                        }
                }
-               write_unlock_bh(&nf_conntrack_lock);
+               spin_unlock_bh(&nf_conntrack_lock);
        } else {
                /* This basically means we have to flush everything*/
-               write_lock_bh(&nf_conntrack_lock);
+               spin_lock_bh(&nf_conntrack_lock);
                for (i = 0; i < nf_ct_expect_hsize; i++) {
                        hlist_for_each_entry_safe(exp, n, next,
                                                  &nf_ct_expect_hash[i],
@@ -1645,7 +1647,7 @@ ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb,
                                }
                        }
                }
-               write_unlock_bh(&nf_conntrack_lock);
+               spin_unlock_bh(&nf_conntrack_lock);
        }
 
        return 0;
@@ -1731,11 +1733,11 @@ ctnetlink_new_expect(struct sock *ctnl, struct sk_buff *skb,
        if (err < 0)
                return err;
 
-       write_lock_bh(&nf_conntrack_lock);
+       spin_lock_bh(&nf_conntrack_lock);
        exp = __nf_ct_expect_find(&tuple);
 
        if (!exp) {
-               write_unlock_bh(&nf_conntrack_lock);
+               spin_unlock_bh(&nf_conntrack_lock);
                err = -ENOENT;
                if (nlh->nlmsg_flags & NLM_F_CREATE)
                        err = ctnetlink_create_expect(cda, u3);
@@ -1745,7 +1747,7 @@ ctnetlink_new_expect(struct sock *ctnl, struct sk_buff *skb,
        err = -EEXIST;
        if (!(nlh->nlmsg_flags & NLM_F_EXCL))
                err = ctnetlink_change_expect(exp, cda);
-       write_unlock_bh(&nf_conntrack_lock);
+       spin_unlock_bh(&nf_conntrack_lock);
 
        return err;
 }
index 099b6df3e2b55cfcd69bbe0cddf97bc6c714e858..b5cb8e831230dbb643323e7a1cda152de22f595b 100644 (file)
@@ -67,7 +67,7 @@ EXPORT_SYMBOL_GPL(nf_nat_pptp_hook_expectfn);
 
 #ifdef DEBUG
 /* PptpControlMessageType names */
-const char *pptp_msg_name[] = {
+const char *const pptp_msg_name[] = {
        "UNKNOWN_MESSAGE",
        "START_SESSION_REQUEST",
        "START_SESSION_REPLY",
@@ -136,7 +136,7 @@ static void pptp_expectfn(struct nf_conn *ct,
 
 static int destroy_sibling_or_exp(const struct nf_conntrack_tuple *t)
 {
-       struct nf_conntrack_tuple_hash *h;
+       const struct nf_conntrack_tuple_hash *h;
        struct nf_conntrack_expect *exp;
        struct nf_conn *sibling;
 
@@ -168,7 +168,7 @@ static int destroy_sibling_or_exp(const struct nf_conntrack_tuple *t)
 /* timeout GRE data connections */
 static void pptp_destroy_siblings(struct nf_conn *ct)
 {
-       struct nf_conn_help *help = nfct_help(ct);
+       const struct nf_conn_help *help = nfct_help(ct);
        struct nf_conntrack_tuple t;
 
        nf_ct_gre_keymap_destroy(ct);
@@ -497,9 +497,11 @@ conntrack_pptp_help(struct sk_buff *skb, unsigned int protoff,
 
 {
        int dir = CTINFO2DIR(ctinfo);
-       struct nf_ct_pptp_master *info = &nfct_help(ct)->help.ct_pptp_info;
-       struct tcphdr _tcph, *tcph;
-       struct pptp_pkt_hdr _pptph, *pptph;
+       const struct nf_ct_pptp_master *info = &nfct_help(ct)->help.ct_pptp_info;
+       const struct tcphdr *tcph;
+       struct tcphdr _tcph;
+       const struct pptp_pkt_hdr *pptph;
+       struct pptp_pkt_hdr _pptph;
        struct PptpControlHeader _ctlh, *ctlh;
        union pptp_ctrl_union _pptpReq, *pptpReq;
        unsigned int tcplen = skb->len - protoff;
index 22c5dcb6306aad685f1aa0c4d8b31ff4e8d31aa9..55458915575f20d604205f038cde9b457df4856a 100644 (file)
@@ -41,19 +41,19 @@ static int generic_print_tuple(struct seq_file *s,
 }
 
 /* Returns verdict for packet, or -1 for invalid. */
-static int packet(struct nf_conn *conntrack,
+static int packet(struct nf_conn *ct,
                  const struct sk_buff *skb,
                  unsigned int dataoff,
                  enum ip_conntrack_info ctinfo,
                  int pf,
                  unsigned int hooknum)
 {
-       nf_ct_refresh_acct(conntrack, ctinfo, skb, nf_ct_generic_timeout);
+       nf_ct_refresh_acct(ct, ctinfo, skb, nf_ct_generic_timeout);
        return NF_ACCEPT;
 }
 
 /* Called when a new connection for this protocol found. */
-static int new(struct nf_conn *conntrack, const struct sk_buff *skb,
+static int new(struct nf_conn *ct, const struct sk_buff *skb,
               unsigned int dataoff)
 {
        return 1;
index 4a185f6aa65a907235c7ac7c2ae9629aa37c242a..e10024a1b6662e971ac565639d10c1bd16a85793 100644 (file)
@@ -161,9 +161,11 @@ static int gre_pkt_to_tuple(const struct sk_buff *skb,
                           unsigned int dataoff,
                           struct nf_conntrack_tuple *tuple)
 {
-       struct gre_hdr_pptp _pgrehdr, *pgrehdr;
+       const struct gre_hdr_pptp *pgrehdr;
+       struct gre_hdr_pptp _pgrehdr;
        __be16 srckey;
-       struct gre_hdr _grehdr, *grehdr;
+       const struct gre_hdr *grehdr;
+       struct gre_hdr _grehdr;
 
        /* first only delinearize old RFC1701 GRE header */
        grehdr = skb_header_pointer(skb, dataoff, sizeof(_grehdr), &_grehdr);
index 21d29e782baf3ae0970efac12e8587b934fa1f47..f9a08370dbb31f3998ea719c0271a44d5bc1d7d9 100644 (file)
@@ -25,7 +25,7 @@
 #include <net/netfilter/nf_conntrack_l4proto.h>
 #include <net/netfilter/nf_conntrack_ecache.h>
 
-/* Protects conntrack->proto.sctp */
+/* Protects ct->proto.sctp */
 static DEFINE_RWLOCK(sctp_lock);
 
 /* FIXME: Examine ipfilter's timeouts and conntrack transitions more
@@ -624,7 +624,7 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp6 __read_mostly = {
 #endif
 };
 
-int __init nf_conntrack_proto_sctp_init(void)
+static int __init nf_conntrack_proto_sctp_init(void)
 {
        int ret;
 
@@ -647,7 +647,7 @@ int __init nf_conntrack_proto_sctp_init(void)
        return ret;
 }
 
-void __exit nf_conntrack_proto_sctp_fini(void)
+static void __exit nf_conntrack_proto_sctp_fini(void)
 {
        nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_sctp6);
        nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_sctp4);
index 64c9b910419c052395b1e431b84e262f11fa13b5..3e0cccae563648b735f125cde27125367e6d0f4e 100644 (file)
@@ -26,7 +26,7 @@
 #include <net/netfilter/nf_conntrack_ecache.h>
 #include <net/netfilter/nf_log.h>
 
-/* Protects conntrack->proto.tcp */
+/* Protects ct->proto.tcp */
 static DEFINE_RWLOCK(tcp_lock);
 
 /* "Be conservative in what you do,
@@ -46,7 +46,7 @@ static int nf_ct_tcp_max_retrans __read_mostly = 3;
   /* FIXME: Examine ipfilter's timeouts and conntrack transitions more
      closely.  They're more complex. --RR */
 
-static const char *tcp_conntrack_names[] = {
+static const char *const tcp_conntrack_names[] = {
        "NONE",
        "SYN_SENT",
        "SYN_RECV",
@@ -261,7 +261,8 @@ static int tcp_pkt_to_tuple(const struct sk_buff *skb,
                            unsigned int dataoff,
                            struct nf_conntrack_tuple *tuple)
 {
-       struct tcphdr _hdr, *hp;
+       const struct tcphdr *hp;
+       struct tcphdr _hdr;
 
        /* Actually only need first 8 bytes. */
        hp = skb_header_pointer(skb, dataoff, 8, &_hdr);
@@ -292,13 +293,12 @@ static int tcp_print_tuple(struct seq_file *s,
 }
 
 /* Print out the private part of the conntrack. */
-static int tcp_print_conntrack(struct seq_file *s,
-                              const struct nf_conn *conntrack)
+static int tcp_print_conntrack(struct seq_file *s, const struct nf_conn *ct)
 {
        enum tcp_conntrack state;
 
        read_lock_bh(&tcp_lock);
-       state = conntrack->proto.tcp.state;
+       state = ct->proto.tcp.state;
        read_unlock_bh(&tcp_lock);
 
        return seq_printf(s, "%s ", tcp_conntrack_names[state]);
@@ -344,7 +344,7 @@ static unsigned int get_conntrack_index(const struct tcphdr *tcph)
 static inline __u32 segment_seq_plus_len(__u32 seq,
                                         size_t len,
                                         unsigned int dataoff,
-                                        struct tcphdr *tcph)
+                                        const struct tcphdr *tcph)
 {
        /* XXX Should I use payload length field in IP/IPv6 header ?
         * - YK */
@@ -363,11 +363,11 @@ static inline __u32 segment_seq_plus_len(__u32 seq,
  */
 static void tcp_options(const struct sk_buff *skb,
                        unsigned int dataoff,
-                       struct tcphdr *tcph,
+                       const struct tcphdr *tcph,
                        struct ip_ct_tcp_state *state)
 {
        unsigned char buff[(15 * 4) - sizeof(struct tcphdr)];
-       unsigned char *ptr;
+       const unsigned char *ptr;
        int length = (tcph->doff*4) - sizeof(struct tcphdr);
 
        if (!length)
@@ -418,10 +418,10 @@ static void tcp_options(const struct sk_buff *skb,
 }
 
 static void tcp_sack(const struct sk_buff *skb, unsigned int dataoff,
-                    struct tcphdr *tcph, __u32 *sack)
+                     const struct tcphdr *tcph, __u32 *sack)
 {
        unsigned char buff[(15 * 4) - sizeof(struct tcphdr)];
-       unsigned char *ptr;
+       const unsigned char *ptr;
        int length = (tcph->doff*4) - sizeof(struct tcphdr);
        __u32 tmp;
 
@@ -478,18 +478,18 @@ static void tcp_sack(const struct sk_buff *skb, unsigned int dataoff,
        }
 }
 
-static int tcp_in_window(struct nf_conn *ct,
+static int tcp_in_window(const struct nf_conn *ct,
                         struct ip_ct_tcp *state,
                         enum ip_conntrack_dir dir,
                         unsigned int index,
                         const struct sk_buff *skb,
                         unsigned int dataoff,
-                        struct tcphdr *tcph,
+                        const struct tcphdr *tcph,
                         int pf)
 {
        struct ip_ct_tcp_state *sender = &state->seen[dir];
        struct ip_ct_tcp_state *receiver = &state->seen[!dir];
-       struct nf_conntrack_tuple *tuple = &ct->tuplehash[dir].tuple;
+       const struct nf_conntrack_tuple *tuple = &ct->tuplehash[dir].tuple;
        __u32 seq, ack, sack, end, win, swin;
        int res;
 
@@ -687,14 +687,14 @@ static int tcp_in_window(struct nf_conn *ct,
 #ifdef CONFIG_NF_NAT_NEEDED
 /* Update sender->td_end after NAT successfully mangled the packet */
 /* Caller must linearize skb at tcp header. */
-void nf_conntrack_tcp_update(struct sk_buff *skb,
+void nf_conntrack_tcp_update(const struct sk_buff *skb,
                             unsigned int dataoff,
-                            struct nf_conn *conntrack,
+                            struct nf_conn *ct,
                             int dir)
 {
-       struct tcphdr *tcph = (void *)skb->data + dataoff;
-       struct ip_ct_tcp_state *sender = &conntrack->proto.tcp.seen[dir];
-       struct ip_ct_tcp_state *receiver = &conntrack->proto.tcp.seen[!dir];
+       const struct tcphdr *tcph = (const void *)skb->data + dataoff;
+       const struct ip_ct_tcp_state *sender = &ct->proto.tcp.seen[dir];
+       const struct ip_ct_tcp_state *receiver = &ct->proto.tcp.seen[!dir];
        __u32 end;
 
        end = segment_seq_plus_len(ntohl(tcph->seq), skb->len, dataoff, tcph);
@@ -703,9 +703,9 @@ void nf_conntrack_tcp_update(struct sk_buff *skb,
        /*
         * We have to worry for the ack in the reply packet only...
         */
-       if (after(end, conntrack->proto.tcp.seen[dir].td_end))
-               conntrack->proto.tcp.seen[dir].td_end = end;
-       conntrack->proto.tcp.last_end = end;
+       if (after(end, ct->proto.tcp.seen[dir].td_end))
+               ct->proto.tcp.seen[dir].td_end = end;
+       ct->proto.tcp.last_end = end;
        write_unlock_bh(&tcp_lock);
        pr_debug("tcp_update: sender end=%u maxend=%u maxwin=%u scale=%i "
                 "receiver end=%u maxend=%u maxwin=%u scale=%i\n",
@@ -727,7 +727,7 @@ EXPORT_SYMBOL_GPL(nf_conntrack_tcp_update);
 #define        TH_CWR  0x80
 
 /* table of valid flag combinations - PUSH, ECE and CWR are always valid */
-static u8 tcp_valid_flags[(TH_FIN|TH_SYN|TH_RST|TH_ACK|TH_URG) + 1] =
+static const u8 tcp_valid_flags[(TH_FIN|TH_SYN|TH_RST|TH_ACK|TH_URG) + 1] =
 {
        [TH_SYN]                        = 1,
        [TH_SYN|TH_URG]                 = 1,
@@ -747,7 +747,8 @@ static int tcp_error(struct sk_buff *skb,
                     int pf,
                     unsigned int hooknum)
 {
-       struct tcphdr _tcph, *th;
+       const struct tcphdr *th;
+       struct tcphdr _tcph;
        unsigned int tcplen = skb->len - dataoff;
        u_int8_t tcpflags;
 
@@ -794,7 +795,7 @@ static int tcp_error(struct sk_buff *skb,
 }
 
 /* Returns verdict for packet, or -1 for invalid. */
-static int tcp_packet(struct nf_conn *conntrack,
+static int tcp_packet(struct nf_conn *ct,
                      const struct sk_buff *skb,
                      unsigned int dataoff,
                      enum ip_conntrack_info ctinfo,
@@ -804,7 +805,8 @@ static int tcp_packet(struct nf_conn *conntrack,
        struct nf_conntrack_tuple *tuple;
        enum tcp_conntrack new_state, old_state;
        enum ip_conntrack_dir dir;
-       struct tcphdr *th, _tcph;
+       const struct tcphdr *th;
+       struct tcphdr _tcph;
        unsigned long timeout;
        unsigned int index;
 
@@ -812,26 +814,24 @@ static int tcp_packet(struct nf_conn *conntrack,
        BUG_ON(th == NULL);
 
        write_lock_bh(&tcp_lock);
-       old_state = conntrack->proto.tcp.state;
+       old_state = ct->proto.tcp.state;
        dir = CTINFO2DIR(ctinfo);
        index = get_conntrack_index(th);
        new_state = tcp_conntracks[dir][index][old_state];
-       tuple = &conntrack->tuplehash[dir].tuple;
+       tuple = &ct->tuplehash[dir].tuple;
 
        switch (new_state) {
        case TCP_CONNTRACK_SYN_SENT:
                if (old_state < TCP_CONNTRACK_TIME_WAIT)
                        break;
-               if ((conntrack->proto.tcp.seen[!dir].flags &
-                       IP_CT_TCP_FLAG_CLOSE_INIT)
-                   || (conntrack->proto.tcp.last_dir == dir
-                       && conntrack->proto.tcp.last_index == TCP_RST_SET)) {
+               if ((ct->proto.tcp.seen[!dir].flags & IP_CT_TCP_FLAG_CLOSE_INIT)
+                   || (ct->proto.tcp.last_dir == dir
+                       && ct->proto.tcp.last_index == TCP_RST_SET)) {
                        /* Attempt to reopen a closed/aborted connection.
                         * Delete this connection and look up again. */
                        write_unlock_bh(&tcp_lock);
-                       if (del_timer(&conntrack->timeout))
-                               conntrack->timeout.function((unsigned long)
-                                                           conntrack);
+                       if (del_timer(&ct->timeout))
+                               ct->timeout.function((unsigned long)ct);
                        return -NF_REPEAT;
                }
                /* Fall through */
@@ -843,10 +843,9 @@ static int tcp_packet(struct nf_conn *conntrack,
                 * c) ACK in reply direction after initial SYN in original.
                 */
                if (index == TCP_SYNACK_SET
-                   && conntrack->proto.tcp.last_index == TCP_SYN_SET
-                   && conntrack->proto.tcp.last_dir != dir
-                   && ntohl(th->ack_seq) ==
-                            conntrack->proto.tcp.last_end) {
+                   && ct->proto.tcp.last_index == TCP_SYN_SET
+                   && ct->proto.tcp.last_dir != dir
+                   && ntohl(th->ack_seq) == ct->proto.tcp.last_end) {
                        /* This SYN/ACK acknowledges a SYN that we earlier
                         * ignored as invalid. This means that the client and
                         * the server are both in sync, while the firewall is
@@ -858,15 +857,14 @@ static int tcp_packet(struct nf_conn *conntrack,
                        if (LOG_INVALID(IPPROTO_TCP))
                                nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
                                          "nf_ct_tcp: killing out of sync session ");
-                       if (del_timer(&conntrack->timeout))
-                               conntrack->timeout.function((unsigned long)
-                                                           conntrack);
+                       if (del_timer(&ct->timeout))
+                               ct->timeout.function((unsigned long)ct);
                        return -NF_DROP;
                }
-               conntrack->proto.tcp.last_index = index;
-               conntrack->proto.tcp.last_dir = dir;
-               conntrack->proto.tcp.last_seq = ntohl(th->seq);
-               conntrack->proto.tcp.last_end =
+               ct->proto.tcp.last_index = index;
+               ct->proto.tcp.last_dir = dir;
+               ct->proto.tcp.last_seq = ntohl(th->seq);
+               ct->proto.tcp.last_end =
                    segment_seq_plus_len(ntohl(th->seq), skb->len, dataoff, th);
 
                write_unlock_bh(&tcp_lock);
@@ -885,11 +883,11 @@ static int tcp_packet(struct nf_conn *conntrack,
                return -NF_ACCEPT;
        case TCP_CONNTRACK_CLOSE:
                if (index == TCP_RST_SET
-                   && ((test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status)
-                        && conntrack->proto.tcp.last_index == TCP_SYN_SET)
-                       || (!test_bit(IPS_ASSURED_BIT, &conntrack->status)
-                           && conntrack->proto.tcp.last_index == TCP_ACK_SET))
-                   && ntohl(th->ack_seq) == conntrack->proto.tcp.last_end) {
+                   && ((test_bit(IPS_SEEN_REPLY_BIT, &ct->status)
+                        && ct->proto.tcp.last_index == TCP_SYN_SET)
+                       || (!test_bit(IPS_ASSURED_BIT, &ct->status)
+                           && ct->proto.tcp.last_index == TCP_ACK_SET))
+                   && ntohl(th->ack_seq) == ct->proto.tcp.last_end) {
                        /* RST sent to invalid SYN or ACK we had let through
                         * at a) and c) above:
                         *
@@ -907,15 +905,15 @@ static int tcp_packet(struct nf_conn *conntrack,
                break;
        }
 
-       if (!tcp_in_window(conntrack, &conntrack->proto.tcp, dir, index,
+       if (!tcp_in_window(ct, &ct->proto.tcp, dir, index,
                           skb, dataoff, th, pf)) {
                write_unlock_bh(&tcp_lock);
                return -NF_ACCEPT;
        }
      in_window:
        /* From now on we have got in-window packets */
-       conntrack->proto.tcp.last_index = index;
-       conntrack->proto.tcp.last_dir = dir;
+       ct->proto.tcp.last_index = index;
+       ct->proto.tcp.last_dir = dir;
 
        pr_debug("tcp_conntracks: ");
        NF_CT_DUMP_TUPLE(tuple);
@@ -924,12 +922,12 @@ static int tcp_packet(struct nf_conn *conntrack,
                 (th->fin ? 1 : 0), (th->rst ? 1 : 0),
                 old_state, new_state);
 
-       conntrack->proto.tcp.state = new_state;
+       ct->proto.tcp.state = new_state;
        if (old_state != new_state
            && (new_state == TCP_CONNTRACK_FIN_WAIT
                || new_state == TCP_CONNTRACK_CLOSE))
-               conntrack->proto.tcp.seen[dir].flags |= IP_CT_TCP_FLAG_CLOSE_INIT;
-       timeout = conntrack->proto.tcp.retrans >= nf_ct_tcp_max_retrans
+               ct->proto.tcp.seen[dir].flags |= IP_CT_TCP_FLAG_CLOSE_INIT;
+       timeout = ct->proto.tcp.retrans >= nf_ct_tcp_max_retrans
                  && tcp_timeouts[new_state] > nf_ct_tcp_timeout_max_retrans
                  ? nf_ct_tcp_timeout_max_retrans : tcp_timeouts[new_state];
        write_unlock_bh(&tcp_lock);
@@ -938,41 +936,41 @@ static int tcp_packet(struct nf_conn *conntrack,
        if (new_state != old_state)
                nf_conntrack_event_cache(IPCT_PROTOINFO, skb);
 
-       if (!test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status)) {
+       if (!test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) {
                /* If only reply is a RST, we can consider ourselves not to
                   have an established connection: this is a fairly common
                   problem case, so we can delete the conntrack
                   immediately.  --RR */
                if (th->rst) {
-                       if (del_timer(&conntrack->timeout))
-                               conntrack->timeout.function((unsigned long)
-                                                           conntrack);
+                       if (del_timer(&ct->timeout))
+                               ct->timeout.function((unsigned long)ct);
                        return NF_ACCEPT;
                }
-       } else if (!test_bit(IPS_ASSURED_BIT, &conntrack->status)
+       } else if (!test_bit(IPS_ASSURED_BIT, &ct->status)
                   && (old_state == TCP_CONNTRACK_SYN_RECV
                       || old_state == TCP_CONNTRACK_ESTABLISHED)
                   && new_state == TCP_CONNTRACK_ESTABLISHED) {
                /* Set ASSURED if we see see valid ack in ESTABLISHED
                   after SYN_RECV or a valid answer for a picked up
                   connection. */
-               set_bit(IPS_ASSURED_BIT, &conntrack->status);
+               set_bit(IPS_ASSURED_BIT, &ct->status);
                nf_conntrack_event_cache(IPCT_STATUS, skb);
        }
-       nf_ct_refresh_acct(conntrack, ctinfo, skb, timeout);
+       nf_ct_refresh_acct(ct, ctinfo, skb, timeout);
 
        return NF_ACCEPT;
 }
 
 /* Called when a new connection for this protocol found. */
-static int tcp_new(struct nf_conn *conntrack,
+static int tcp_new(struct nf_conn *ct,
                   const struct sk_buff *skb,
                   unsigned int dataoff)
 {
        enum tcp_conntrack new_state;
-       struct tcphdr *th, _tcph;
-       struct ip_ct_tcp_state *sender = &conntrack->proto.tcp.seen[0];
-       struct ip_ct_tcp_state *receiver = &conntrack->proto.tcp.seen[1];
+       const struct tcphdr *th;
+       struct tcphdr _tcph;
+       const struct ip_ct_tcp_state *sender = &ct->proto.tcp.seen[0];
+       const struct ip_ct_tcp_state *receiver = &ct->proto.tcp.seen[1];
 
        th = skb_header_pointer(skb, dataoff, sizeof(_tcph), &_tcph);
        BUG_ON(th == NULL);
@@ -990,17 +988,17 @@ static int tcp_new(struct nf_conn *conntrack,
 
        if (new_state == TCP_CONNTRACK_SYN_SENT) {
                /* SYN packet */
-               conntrack->proto.tcp.seen[0].td_end =
+               ct->proto.tcp.seen[0].td_end =
                        segment_seq_plus_len(ntohl(th->seq), skb->len,
                                             dataoff, th);
-               conntrack->proto.tcp.seen[0].td_maxwin = ntohs(th->window);
-               if (conntrack->proto.tcp.seen[0].td_maxwin == 0)
-                       conntrack->proto.tcp.seen[0].td_maxwin = 1;
-               conntrack->proto.tcp.seen[0].td_maxend =
-                       conntrack->proto.tcp.seen[0].td_end;
-
-               tcp_options(skb, dataoff, th, &conntrack->proto.tcp.seen[0]);
-               conntrack->proto.tcp.seen[1].flags = 0;
+               ct->proto.tcp.seen[0].td_maxwin = ntohs(th->window);
+               if (ct->proto.tcp.seen[0].td_maxwin == 0)
+                       ct->proto.tcp.seen[0].td_maxwin = 1;
+               ct->proto.tcp.seen[0].td_maxend =
+                       ct->proto.tcp.seen[0].td_end;
+
+               tcp_options(skb, dataoff, th, &ct->proto.tcp.seen[0]);
+               ct->proto.tcp.seen[1].flags = 0;
        } else if (nf_ct_tcp_loose == 0) {
                /* Don't try to pick up connections. */
                return 0;
@@ -1010,32 +1008,32 @@ static int tcp_new(struct nf_conn *conntrack,
                 * its history is lost for us.
                 * Let's try to use the data from the packet.
                 */
-               conntrack->proto.tcp.seen[0].td_end =
+               ct->proto.tcp.seen[0].td_end =
                        segment_seq_plus_len(ntohl(th->seq), skb->len,
                                             dataoff, th);
-               conntrack->proto.tcp.seen[0].td_maxwin = ntohs(th->window);
-               if (conntrack->proto.tcp.seen[0].td_maxwin == 0)
-                       conntrack->proto.tcp.seen[0].td_maxwin = 1;
-               conntrack->proto.tcp.seen[0].td_maxend =
-                       conntrack->proto.tcp.seen[0].td_end +
-                       conntrack->proto.tcp.seen[0].td_maxwin;
-               conntrack->proto.tcp.seen[0].td_scale = 0;
+               ct->proto.tcp.seen[0].td_maxwin = ntohs(th->window);
+               if (ct->proto.tcp.seen[0].td_maxwin == 0)
+                       ct->proto.tcp.seen[0].td_maxwin = 1;
+               ct->proto.tcp.seen[0].td_maxend =
+                       ct->proto.tcp.seen[0].td_end +
+                       ct->proto.tcp.seen[0].td_maxwin;
+               ct->proto.tcp.seen[0].td_scale = 0;
 
                /* We assume SACK and liberal window checking to handle
                 * window scaling */
-               conntrack->proto.tcp.seen[0].flags =
-               conntrack->proto.tcp.seen[1].flags = IP_CT_TCP_FLAG_SACK_PERM |
-                                                    IP_CT_TCP_FLAG_BE_LIBERAL;
+               ct->proto.tcp.seen[0].flags =
+               ct->proto.tcp.seen[1].flags = IP_CT_TCP_FLAG_SACK_PERM |
+                                             IP_CT_TCP_FLAG_BE_LIBERAL;
        }
 
-       conntrack->proto.tcp.seen[1].td_end = 0;
-       conntrack->proto.tcp.seen[1].td_maxend = 0;
-       conntrack->proto.tcp.seen[1].td_maxwin = 1;
-       conntrack->proto.tcp.seen[1].td_scale = 0;
+       ct->proto.tcp.seen[1].td_end = 0;
+       ct->proto.tcp.seen[1].td_maxend = 0;
+       ct->proto.tcp.seen[1].td_maxwin = 1;
+       ct->proto.tcp.seen[1].td_scale = 0;
 
        /* tcp_packet will set them */
-       conntrack->proto.tcp.state = TCP_CONNTRACK_NONE;
-       conntrack->proto.tcp.last_index = TCP_NONE_SET;
+       ct->proto.tcp.state = TCP_CONNTRACK_NONE;
+       ct->proto.tcp.last_index = TCP_NONE_SET;
 
        pr_debug("tcp_new: sender end=%u maxend=%u maxwin=%u scale=%i "
                 "receiver end=%u maxend=%u maxwin=%u scale=%i\n",
@@ -1098,16 +1096,16 @@ static const struct nla_policy tcp_nla_policy[CTA_PROTOINFO_TCP_MAX+1] = {
 
 static int nlattr_to_tcp(struct nlattr *cda[], struct nf_conn *ct)
 {
-       struct nlattr *attr = cda[CTA_PROTOINFO_TCP];
+       struct nlattr *pattr = cda[CTA_PROTOINFO_TCP];
        struct nlattr *tb[CTA_PROTOINFO_TCP_MAX+1];
        int err;
 
        /* updates could not contain anything about the private
         * protocol info, in that case skip the parsing */
-       if (!attr)
+       if (!pattr)
                return 0;
 
-       err = nla_parse_nested(tb, CTA_PROTOINFO_TCP_MAX, attr, tcp_nla_policy);
+       err = nla_parse_nested(tb, CTA_PROTOINFO_TCP_MAX, pattr, tcp_nla_policy);
        if (err < 0)
                return err;
 
index 3848754110820894c241d568779c1643fc3623bf..b8a35cc06416e8e70e23036f70b83ca4727ad6c4 100644 (file)
@@ -30,7 +30,8 @@ static int udp_pkt_to_tuple(const struct sk_buff *skb,
                             unsigned int dataoff,
                             struct nf_conntrack_tuple *tuple)
 {
-       struct udphdr _hdr, *hp;
+       const struct udphdr *hp;
+       struct udphdr _hdr;
 
        /* Actually only need first 8 bytes. */
        hp = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr);
@@ -61,7 +62,7 @@ static int udp_print_tuple(struct seq_file *s,
 }
 
 /* Returns verdict for packet, and may modify conntracktype */
-static int udp_packet(struct nf_conn *conntrack,
+static int udp_packet(struct nf_conn *ct,
                      const struct sk_buff *skb,
                      unsigned int dataoff,
                      enum ip_conntrack_info ctinfo,
@@ -70,20 +71,19 @@ static int udp_packet(struct nf_conn *conntrack,
 {
        /* If we've seen traffic both ways, this is some kind of UDP
           stream.  Extend timeout. */
-       if (test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status)) {
-               nf_ct_refresh_acct(conntrack, ctinfo, skb,
-                                  nf_ct_udp_timeout_stream);
+       if (test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) {
+               nf_ct_refresh_acct(ct, ctinfo, skb, nf_ct_udp_timeout_stream);
                /* Also, more likely to be important, and not a probe */
-               if (!test_and_set_bit(IPS_ASSURED_BIT, &conntrack->status))
+               if (!test_and_set_bit(IPS_ASSURED_BIT, &ct->status))
                        nf_conntrack_event_cache(IPCT_STATUS, skb);
        } else
-               nf_ct_refresh_acct(conntrack, ctinfo, skb, nf_ct_udp_timeout);
+               nf_ct_refresh_acct(ct, ctinfo, skb, nf_ct_udp_timeout);
 
        return NF_ACCEPT;
 }
 
 /* Called when a new connection for this protocol found. */
-static int udp_new(struct nf_conn *conntrack, const struct sk_buff *skb,
+static int udp_new(struct nf_conn *ct, const struct sk_buff *skb,
                   unsigned int dataoff)
 {
        return 1;
@@ -95,7 +95,8 @@ static int udp_error(struct sk_buff *skb, unsigned int dataoff,
                     unsigned int hooknum)
 {
        unsigned int udplen = skb->len - dataoff;
-       struct udphdr _hdr, *hdr;
+       const struct udphdr *hdr;
+       struct udphdr _hdr;
 
        /* Header is too small? */
        hdr = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr);
index 070056d9bcd6f52dd7459c98df33ce8585d24f52..9dd03c7aeac6da64283e8cfe847204e77701e31e 100644 (file)
@@ -31,7 +31,8 @@ static int udplite_pkt_to_tuple(const struct sk_buff *skb,
                                unsigned int dataoff,
                                struct nf_conntrack_tuple *tuple)
 {
-       struct udphdr _hdr, *hp;
+       const struct udphdr *hp;
+       struct udphdr _hdr;
 
        hp = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr);
        if (hp == NULL)
@@ -60,7 +61,7 @@ static int udplite_print_tuple(struct seq_file *s,
 }
 
 /* Returns verdict for packet, and may modify conntracktype */
-static int udplite_packet(struct nf_conn *conntrack,
+static int udplite_packet(struct nf_conn *ct,
                          const struct sk_buff *skb,
                          unsigned int dataoff,
                          enum ip_conntrack_info ctinfo,
@@ -69,21 +70,20 @@ static int udplite_packet(struct nf_conn *conntrack,
 {
        /* If we've seen traffic both ways, this is some kind of UDP
           stream.  Extend timeout. */
-       if (test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status)) {
-               nf_ct_refresh_acct(conntrack, ctinfo, skb,
+       if (test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) {
+               nf_ct_refresh_acct(ct, ctinfo, skb,
                                   nf_ct_udplite_timeout_stream);
                /* Also, more likely to be important, and not a probe */
-               if (!test_and_set_bit(IPS_ASSURED_BIT, &conntrack->status))
+               if (!test_and_set_bit(IPS_ASSURED_BIT, &ct->status))
                        nf_conntrack_event_cache(IPCT_STATUS, skb);
        } else
-               nf_ct_refresh_acct(conntrack, ctinfo, skb,
-                                  nf_ct_udplite_timeout);
+               nf_ct_refresh_acct(ct, ctinfo, skb, nf_ct_udplite_timeout);
 
        return NF_ACCEPT;
 }
 
 /* Called when a new connection for this protocol found. */
-static int udplite_new(struct nf_conn *conntrack, const struct sk_buff *skb,
+static int udplite_new(struct nf_conn *ct, const struct sk_buff *skb,
                       unsigned int dataoff)
 {
        return 1;
@@ -95,7 +95,8 @@ static int udplite_error(struct sk_buff *skb, unsigned int dataoff,
                         unsigned int hooknum)
 {
        unsigned int udplen = skb->len - dataoff;
-       struct udphdr _hdr, *hdr;
+       const struct udphdr *hdr;
+       struct udphdr _hdr;
        unsigned int cscov;
 
        /* Header is too small? */
index b5a16c6e21c297df32297abfce82c4e894a31fe4..a70051d741a7014827c8c98aa7e2c0e05358ceb6 100644 (file)
@@ -62,8 +62,9 @@ static int help(struct sk_buff *skb,
                enum ip_conntrack_info ctinfo)
 {
        unsigned int dataoff, datalen;
-       struct tcphdr _tcph, *th;
-       char *sb_ptr;
+       const struct tcphdr *th;
+       struct tcphdr _tcph;
+       void *sb_ptr;
        int ret = NF_ACCEPT;
        int dir = CTINFO2DIR(ctinfo);
        struct nf_ct_sane_master *ct_sane_info;
@@ -99,7 +100,7 @@ static int help(struct sk_buff *skb,
                if (datalen != sizeof(struct sane_request))
                        goto out;
 
-               req = (struct sane_request *)sb_ptr;
+               req = sb_ptr;
                if (req->RPC_code != htonl(SANE_NET_START)) {
                        /* Not an interesting command */
                        ct_sane_info->state = SANE_STATE_NORMAL;
@@ -123,7 +124,7 @@ static int help(struct sk_buff *skb,
                goto out;
        }
 
-       reply = (struct sane_reply_net_start *)sb_ptr;
+       reply = sb_ptr;
        if (reply->status != htonl(SANE_STATUS_SUCCESS)) {
                /* saned refused the command */
                pr_debug("nf_ct_sane: unsuccessful SANE_STATUS = %u\n",
index 47d8947cf26348124698a0c90cbdc0323766b1d2..c521c891d35167d25369aa992d12ead46847db17 100644 (file)
@@ -28,7 +28,7 @@ MODULE_ALIAS("ip_conntrack_sip");
 
 #define MAX_PORTS      8
 static unsigned short ports[MAX_PORTS];
-static int ports_c;
+static unsigned int ports_c;
 module_param_array(ports, ushort, &ports_c, 0400);
 MODULE_PARM_DESC(ports, "port numbers of SIP servers");
 
@@ -48,10 +48,10 @@ unsigned int (*nf_nat_sdp_hook)(struct sk_buff *skb,
                                const char *dptr) __read_mostly;
 EXPORT_SYMBOL_GPL(nf_nat_sdp_hook);
 
-static int digits_len(struct nf_conn *, const char *, const char *, int *);
-static int epaddr_len(struct nf_conn *, const char *, const char *, int *);
-static int skp_digits_len(struct nf_conn *, const char *, const char *, int *);
-static int skp_epaddr_len(struct nf_conn *, const char *, const char *, int *);
+static int digits_len(const struct nf_conn *, const char *, const char *, int *);
+static int epaddr_len(const struct nf_conn *, const char *, const char *, int *);
+static int skp_digits_len(const struct nf_conn *, const char *, const char *, int *);
+static int skp_epaddr_len(const struct nf_conn *, const char *, const char *, int *);
 
 struct sip_header_nfo {
        const char      *lname;
@@ -61,7 +61,7 @@ struct sip_header_nfo {
        size_t          snlen;
        size_t          ln_strlen;
        int             case_sensitive;
-       int             (*match_len)(struct nf_conn *, const char *,
+       int             (*match_len)(const struct nf_conn *, const char *,
                                     const char *, int *);
 };
 
@@ -225,7 +225,7 @@ const char *ct_sip_search(const char *needle, const char *haystack,
 }
 EXPORT_SYMBOL_GPL(ct_sip_search);
 
-static int digits_len(struct nf_conn *ct, const char *dptr,
+static int digits_len(const struct nf_conn *ct, const char *dptr,
                      const char *limit, int *shift)
 {
        int len = 0;
@@ -237,7 +237,7 @@ static int digits_len(struct nf_conn *ct, const char *dptr,
 }
 
 /* get digits length, skipping blank spaces. */
-static int skp_digits_len(struct nf_conn *ct, const char *dptr,
+static int skp_digits_len(const struct nf_conn *ct, const char *dptr,
                          const char *limit, int *shift)
 {
        for (; dptr <= limit && *dptr == ' '; dptr++)
@@ -246,8 +246,9 @@ static int skp_digits_len(struct nf_conn *ct, const char *dptr,
        return digits_len(ct, dptr, limit, shift);
 }
 
-static int parse_addr(struct nf_conn *ct, const char *cp, const char **endp,
-                     union nf_inet_addr *addr, const char *limit)
+static int parse_addr(const struct nf_conn *ct, const char *cp,
+                      const char **endp, union nf_inet_addr *addr,
+                      const char *limit)
 {
        const char *end;
        int family = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num;
@@ -272,7 +273,7 @@ static int parse_addr(struct nf_conn *ct, const char *cp, const char **endp,
 }
 
 /* skip ip address. returns its length. */
-static int epaddr_len(struct nf_conn *ct, const char *dptr,
+static int epaddr_len(const struct nf_conn *ct, const char *dptr,
                      const char *limit, int *shift)
 {
        union nf_inet_addr addr;
@@ -292,7 +293,7 @@ static int epaddr_len(struct nf_conn *ct, const char *dptr,
 }
 
 /* get address length, skiping user info. */
-static int skp_epaddr_len(struct nf_conn *ct, const char *dptr,
+static int skp_epaddr_len(const struct nf_conn *ct, const char *dptr,
                          const char *limit, int *shift)
 {
        const char *start = dptr;
@@ -319,7 +320,7 @@ static int skp_epaddr_len(struct nf_conn *ct, const char *dptr,
 }
 
 /* Returns 0 if not found, -1 error parsing. */
-int ct_sip_get_info(struct nf_conn *ct,
+int ct_sip_get_info(const struct nf_conn *ct,
                    const char *dptr, size_t dlen,
                    unsigned int *matchoff,
                    unsigned int *matchlen,
@@ -407,7 +408,7 @@ static int sip_help(struct sk_buff *skb,
        unsigned int dataoff, datalen;
        const char *dptr;
        int ret = NF_ACCEPT;
-       int matchoff, matchlen;
+       unsigned int matchoff, matchlen;
        u_int16_t port;
        enum sip_header_pos pos;
        typeof(nf_nat_sip_hook) nf_nat_sip;
index 696074a037c1a10a1e1177854a2f303da8434541..e88e96af613d68938fe989034299be0f2c9fee5f 100644 (file)
@@ -31,8 +31,8 @@ MODULE_LICENSE("GPL");
 #ifdef CONFIG_PROC_FS
 int
 print_tuple(struct seq_file *s, const struct nf_conntrack_tuple *tuple,
-           struct nf_conntrack_l3proto *l3proto,
-           struct nf_conntrack_l4proto *l4proto)
+            const struct nf_conntrack_l3proto *l3proto,
+            const struct nf_conntrack_l4proto *l4proto)
 {
        return l3proto->print_tuple(s, tuple) || l4proto->print_tuple(s, tuple);
 }
@@ -58,12 +58,14 @@ struct ct_iter_state {
 static struct hlist_node *ct_get_first(struct seq_file *seq)
 {
        struct ct_iter_state *st = seq->private;
+       struct hlist_node *n;
 
        for (st->bucket = 0;
             st->bucket < nf_conntrack_htable_size;
             st->bucket++) {
-               if (!hlist_empty(&nf_conntrack_hash[st->bucket]))
-                       return nf_conntrack_hash[st->bucket].first;
+               n = rcu_dereference(nf_conntrack_hash[st->bucket].first);
+               if (n)
+                       return n;
        }
        return NULL;
 }
@@ -73,11 +75,11 @@ static struct hlist_node *ct_get_next(struct seq_file *seq,
 {
        struct ct_iter_state *st = seq->private;
 
-       head = head->next;
+       head = rcu_dereference(head->next);
        while (head == NULL) {
                if (++st->bucket >= nf_conntrack_htable_size)
                        return NULL;
-               head = nf_conntrack_hash[st->bucket].first;
+               head = rcu_dereference(nf_conntrack_hash[st->bucket].first);
        }
        return head;
 }
@@ -93,8 +95,9 @@ static struct hlist_node *ct_get_idx(struct seq_file *seq, loff_t pos)
 }
 
 static void *ct_seq_start(struct seq_file *seq, loff_t *pos)
+       __acquires(RCU)
 {
-       read_lock_bh(&nf_conntrack_lock);
+       rcu_read_lock();
        return ct_get_idx(seq, *pos);
 }
 
@@ -105,79 +108,80 @@ static void *ct_seq_next(struct seq_file *s, void *v, loff_t *pos)
 }
 
 static void ct_seq_stop(struct seq_file *s, void *v)
+       __releases(RCU)
 {
-       read_unlock_bh(&nf_conntrack_lock);
+       rcu_read_unlock();
 }
 
 /* return 0 on success, 1 in case of error */
 static int ct_seq_show(struct seq_file *s, void *v)
 {
        const struct nf_conntrack_tuple_hash *hash = v;
-       const struct nf_conn *conntrack = nf_ct_tuplehash_to_ctrack(hash);
-       struct nf_conntrack_l3proto *l3proto;
-       struct nf_conntrack_l4proto *l4proto;
+       const struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(hash);
+       const struct nf_conntrack_l3proto *l3proto;
+       const struct nf_conntrack_l4proto *l4proto;
 
-       NF_CT_ASSERT(conntrack);
+       NF_CT_ASSERT(ct);
 
        /* we only want to print DIR_ORIGINAL */
        if (NF_CT_DIRECTION(hash))
                return 0;
 
-       l3proto = __nf_ct_l3proto_find(conntrack->tuplehash[IP_CT_DIR_ORIGINAL]
+       l3proto = __nf_ct_l3proto_find(ct->tuplehash[IP_CT_DIR_ORIGINAL]
                                       .tuple.src.l3num);
 
        NF_CT_ASSERT(l3proto);
-       l4proto = __nf_ct_l4proto_find(conntrack->tuplehash[IP_CT_DIR_ORIGINAL]
+       l4proto = __nf_ct_l4proto_find(ct->tuplehash[IP_CT_DIR_ORIGINAL]
                                   .tuple.src.l3num,
-                                  conntrack->tuplehash[IP_CT_DIR_ORIGINAL]
+                                  ct->tuplehash[IP_CT_DIR_ORIGINAL]
                                   .tuple.dst.protonum);
        NF_CT_ASSERT(l4proto);
 
        if (seq_printf(s, "%-8s %u %-8s %u %ld ",
                       l3proto->name,
-                      conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num,
+                      ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num,
                       l4proto->name,
-                      conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum,
-                      timer_pending(&conntrack->timeout)
-                      ? (long)(conntrack->timeout.expires - jiffies)/HZ : 0) != 0)
+                      ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum,
+                      timer_pending(&ct->timeout)
+                      ? (long)(ct->timeout.expires - jiffies)/HZ : 0) != 0)
                return -ENOSPC;
 
-       if (l4proto->print_conntrack && l4proto->print_conntrack(s, conntrack))
+       if (l4proto->print_conntrack && l4proto->print_conntrack(s, ct))
                return -ENOSPC;
 
-       if (print_tuple(s, &conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple,
+       if (print_tuple(s, &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple,
                        l3proto, l4proto))
                return -ENOSPC;
 
-       if (seq_print_counters(s, &conntrack->counters[IP_CT_DIR_ORIGINAL]))
+       if (seq_print_counters(s, &ct->counters[IP_CT_DIR_ORIGINAL]))
                return -ENOSPC;
 
-       if (!(test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status)))
+       if (!(test_bit(IPS_SEEN_REPLY_BIT, &ct->status)))
                if (seq_printf(s, "[UNREPLIED] "))
                        return -ENOSPC;
 
-       if (print_tuple(s, &conntrack->tuplehash[IP_CT_DIR_REPLY].tuple,
+       if (print_tuple(s, &ct->tuplehash[IP_CT_DIR_REPLY].tuple,
                        l3proto, l4proto))
                return -ENOSPC;
 
-       if (seq_print_counters(s, &conntrack->counters[IP_CT_DIR_REPLY]))
+       if (seq_print_counters(s, &ct->counters[IP_CT_DIR_REPLY]))
                return -ENOSPC;
 
-       if (test_bit(IPS_ASSURED_BIT, &conntrack->status))
+       if (test_bit(IPS_ASSURED_BIT, &ct->status))
                if (seq_printf(s, "[ASSURED] "))
                        return -ENOSPC;
 
 #if defined(CONFIG_NF_CONNTRACK_MARK)
-       if (seq_printf(s, "mark=%u ", conntrack->mark))
+       if (seq_printf(s, "mark=%u ", ct->mark))
                return -ENOSPC;
 #endif
 
 #ifdef CONFIG_NF_CONNTRACK_SECMARK
-       if (seq_printf(s, "secmark=%u ", conntrack->secmark))
+       if (seq_printf(s, "secmark=%u ", ct->secmark))
                return -ENOSPC;
 #endif
 
-       if (seq_printf(s, "use=%u\n", atomic_read(&conntrack->ct_general.use)))
+       if (seq_printf(s, "use=%u\n", atomic_read(&ct->ct_general.use)))
                return -ENOSPC;
 
        return 0;
@@ -242,7 +246,7 @@ static void ct_cpu_seq_stop(struct seq_file *seq, void *v)
 static int ct_cpu_seq_show(struct seq_file *seq, void *v)
 {
        unsigned int nr_conntracks = atomic_read(&nf_conntrack_count);
-       struct ip_conntrack_stat *st = v;
+       const struct ip_conntrack_stat *st = v;
 
        if (v == SEQ_START_TOKEN) {
                seq_printf(seq, "entries  searched found new invalid ignore delete delete_list insert insert_failed drop early_drop icmp_error  expect_new expect_create expect_delete\n");
@@ -380,7 +384,7 @@ static ctl_table nf_ct_netfilter_table[] = {
        { .ctl_name = 0 }
 };
 
-struct ctl_path nf_ct_path[] = {
+static struct ctl_path nf_ct_path[] = {
        { .procname = "net", .ctl_name = CTL_NET, },
        { }
 };
index e894aa1ff3ad4a683bd05a8f028504342c21589c..bd2e800f23cc8bc1c9fb8708c3b6e6426dfbaa8f 100644 (file)
@@ -25,7 +25,7 @@ MODULE_ALIAS("ip_conntrack_tftp");
 
 #define MAX_PORTS 8
 static unsigned short ports[MAX_PORTS];
-static int ports_c;
+static unsigned int ports_c;
 module_param_array(ports, ushort, &ports_c, 0400);
 MODULE_PARM_DESC(ports, "Port numbers of TFTP servers");
 
@@ -39,7 +39,8 @@ static int tftp_help(struct sk_buff *skb,
                     struct nf_conn *ct,
                     enum ip_conntrack_info ctinfo)
 {
-       struct tftphdr _tftph, *tfh;
+       const struct tftphdr *tfh;
+       struct tftphdr _tftph;
        struct nf_conntrack_expect *exp;
        struct nf_conntrack_tuple *tuple;
        unsigned int ret = NF_ACCEPT;
index 4f5f2885fcac31de3d43f2eceba9c8ba8ebf75eb..cec9976aecbf5c5e8592c8c841d57532f8748655 100644 (file)
@@ -103,6 +103,7 @@ EXPORT_SYMBOL(nf_log_packet);
 
 #ifdef CONFIG_PROC_FS
 static void *seq_start(struct seq_file *seq, loff_t *pos)
+       __acquires(RCU)
 {
        rcu_read_lock();
 
@@ -123,6 +124,7 @@ static void *seq_next(struct seq_file *s, void *v, loff_t *pos)
 }
 
 static void seq_stop(struct seq_file *s, void *v)
+       __releases(RCU)
 {
        rcu_read_unlock();
 }
index 5013cb97ce2ba82c481023ba552461f5185bbc8d..7efa40d47393727447fd1bdbf88d579914e5cfc4 100644 (file)
@@ -467,7 +467,7 @@ __build_packet_message(struct nfulnl_instance *inst,
                read_lock_bh(&skb->sk->sk_callback_lock);
                if (skb->sk->sk_socket && skb->sk->sk_socket->file) {
                        __be32 uid = htonl(skb->sk->sk_socket->file->f_uid);
-                       __be32 gid = htons(skb->sk->sk_socket->file->f_gid);
+                       __be32 gid = htonl(skb->sk->sk_socket->file->f_gid);
                        /* need to unlock here since NLA_PUT may goto */
                        read_unlock_bh(&skb->sk->sk_callback_lock);
                        NLA_PUT_BE32(inst->skb, NFULA_UID, uid);
@@ -866,6 +866,7 @@ static struct hlist_node *get_idx(struct iter_state *st, loff_t pos)
 }
 
 static void *seq_start(struct seq_file *seq, loff_t *pos)
+       __acquires(instances_lock)
 {
        read_lock_bh(&instances_lock);
        return get_idx(seq->private, *pos);
@@ -878,6 +879,7 @@ static void *seq_next(struct seq_file *s, void *v, loff_t *pos)
 }
 
 static void seq_stop(struct seq_file *s, void *v)
+       __releases(instances_lock)
 {
        read_unlock_bh(&instances_lock);
 }
index 51476f82bb54733af8f997d782284bbeafa1eae2..a48b20fe9cd6bf2759e1b723df5448c7fa903092 100644 (file)
@@ -360,7 +360,7 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue,
 
        if (data_len) {
                struct nlattr *nla;
-               int size = nla_attr_size(data_len);
+               int sz = nla_attr_size(data_len);
 
                if (skb_tailroom(skb) < nla_total_size(data_len)) {
                        printk(KERN_WARNING "nf_queue: no tailroom!\n");
@@ -369,7 +369,7 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue,
 
                nla = (struct nlattr *)skb_put(skb, nla_total_size(data_len));
                nla->nla_type = NFQA_PAYLOAD;
-               nla->nla_len = size;
+               nla->nla_len = sz;
 
                if (skb_copy_bits(entskb, 0, nla_data(nla), data_len))
                        BUG();
@@ -845,6 +845,7 @@ static struct hlist_node *get_idx(struct seq_file *seq, loff_t pos)
 }
 
 static void *seq_start(struct seq_file *seq, loff_t *pos)
+       __acquires(instances_lock)
 {
        spin_lock(&instances_lock);
        return get_idx(seq, *pos);
@@ -857,6 +858,7 @@ static void *seq_next(struct seq_file *s, void *v, loff_t *pos)
 }
 
 static void seq_stop(struct seq_file *s, void *v)
+       __releases(instances_lock)
 {
        spin_unlock(&instances_lock);
 }
index 8d4fca96a4a719a054ee3ac0cb02643dc90113ba..a6792089fcf9d4d8430af560addfb8f8a758b7b5 100644 (file)
@@ -44,7 +44,6 @@ struct xt_af {
        struct mutex mutex;
        struct list_head match;
        struct list_head target;
-       struct list_head tables;
 #ifdef CONFIG_COMPAT
        struct mutex compat_mutex;
        struct compat_delta *compat_offsets;
@@ -59,12 +58,6 @@ static struct xt_af *xt;
 #define duprintf(format, args...)
 #endif
 
-enum {
-       TABLE,
-       TARGET,
-       MATCH,
-};
-
 static const char *xt_prefix[NPROTO] = {
        [AF_INET]       = "ip",
        [AF_INET6]      = "ip6",
@@ -400,7 +393,7 @@ int xt_compat_match_offset(struct xt_match *match)
 EXPORT_SYMBOL_GPL(xt_compat_match_offset);
 
 int xt_compat_match_from_user(struct xt_entry_match *m, void **dstptr,
-                             int *size)
+                             unsigned int *size)
 {
        struct xt_match *match = m->u.kernel.match;
        struct compat_xt_entry_match *cm = (struct compat_xt_entry_match *)m;
@@ -427,7 +420,7 @@ int xt_compat_match_from_user(struct xt_entry_match *m, void **dstptr,
 EXPORT_SYMBOL_GPL(xt_compat_match_from_user);
 
 int xt_compat_match_to_user(struct xt_entry_match *m, void __user **dstptr,
-                           int *size)
+                           unsigned int *size)
 {
        struct xt_match *match = m->u.kernel.match;
        struct compat_xt_entry_match __user *cm = *dstptr;
@@ -494,7 +487,7 @@ int xt_compat_target_offset(struct xt_target *target)
 EXPORT_SYMBOL_GPL(xt_compat_target_offset);
 
 void xt_compat_target_from_user(struct xt_entry_target *t, void **dstptr,
-                               int *size)
+                               unsigned int *size)
 {
        struct xt_target *target = t->u.kernel.target;
        struct compat_xt_entry_target *ct = (struct compat_xt_entry_target *)t;
@@ -520,7 +513,7 @@ void xt_compat_target_from_user(struct xt_entry_target *t, void **dstptr,
 EXPORT_SYMBOL_GPL(xt_compat_target_from_user);
 
 int xt_compat_target_to_user(struct xt_entry_target *t, void __user **dstptr,
-                            int *size)
+                            unsigned int *size)
 {
        struct xt_target *target = t->u.kernel.target;
        struct compat_xt_entry_target __user *ct = *dstptr;
@@ -597,14 +590,14 @@ void xt_free_table_info(struct xt_table_info *info)
 EXPORT_SYMBOL(xt_free_table_info);
 
 /* Find table by name, grabs mutex & ref.  Returns ERR_PTR() on error. */
-struct xt_table *xt_find_table_lock(int af, const char *name)
+struct xt_table *xt_find_table_lock(struct net *net, int af, const char *name)
 {
        struct xt_table *t;
 
        if (mutex_lock_interruptible(&xt[af].mutex) != 0)
                return ERR_PTR(-EINTR);
 
-       list_for_each_entry(t, &xt[af].tables, list)
+       list_for_each_entry(t, &net->xt.tables[af], list)
                if (strcmp(t->name, name) == 0 && try_module_get(t->me))
                        return t;
        mutex_unlock(&xt[af].mutex);
@@ -660,20 +653,27 @@ xt_replace_table(struct xt_table *table,
 }
 EXPORT_SYMBOL_GPL(xt_replace_table);
 
-int xt_register_table(struct xt_table *table,
-                     struct xt_table_info *bootstrap,
-                     struct xt_table_info *newinfo)
+struct xt_table *xt_register_table(struct net *net, struct xt_table *table,
+                                  struct xt_table_info *bootstrap,
+                                  struct xt_table_info *newinfo)
 {
        int ret;
        struct xt_table_info *private;
        struct xt_table *t;
 
+       /* Don't add one object to multiple lists. */
+       table = kmemdup(table, sizeof(struct xt_table), GFP_KERNEL);
+       if (!table) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
        ret = mutex_lock_interruptible(&xt[table->af].mutex);
        if (ret != 0)
-               return ret;
+               goto out_free;
 
        /* Don't autoload: we'd eat our tail... */
-       list_for_each_entry(t, &xt[table->af].tables, list) {
+       list_for_each_entry(t, &net->xt.tables[table->af], list) {
                if (strcmp(t->name, table->name) == 0) {
                        ret = -EEXIST;
                        goto unlock;
@@ -692,12 +692,16 @@ int xt_register_table(struct xt_table *table,
        /* save number of initial entries */
        private->initial_entries = private->number;
 
-       list_add(&table->list, &xt[table->af].tables);
+       list_add(&table->list, &net->xt.tables[table->af]);
+       mutex_unlock(&xt[table->af].mutex);
+       return table;
 
-       ret = 0;
  unlock:
        mutex_unlock(&xt[table->af].mutex);
-       return ret;
+out_free:
+       kfree(table);
+out:
+       return ERR_PTR(ret);
 }
 EXPORT_SYMBOL_GPL(xt_register_table);
 
@@ -709,130 +713,204 @@ void *xt_unregister_table(struct xt_table *table)
        private = table->private;
        list_del(&table->list);
        mutex_unlock(&xt[table->af].mutex);
+       kfree(table);
 
        return private;
 }
 EXPORT_SYMBOL_GPL(xt_unregister_table);
 
 #ifdef CONFIG_PROC_FS
-static struct list_head *xt_get_idx(struct list_head *list, struct seq_file *seq, loff_t pos)
+struct xt_names_priv {
+       struct seq_net_private p;
+       int af;
+};
+static void *xt_table_seq_start(struct seq_file *seq, loff_t *pos)
 {
-       struct list_head *head = list->next;
+       struct xt_names_priv *priv = seq->private;
+       struct net *net = priv->p.net;
+       int af = priv->af;
 
-       if (!head || list_empty(list))
-               return NULL;
+       mutex_lock(&xt[af].mutex);
+       return seq_list_start(&net->xt.tables[af], *pos);
+}
 
-       while (pos && (head = head->next)) {
-               if (head == list)
-                       return NULL;
-               pos--;
-       }
-       return pos ? NULL : head;
-}
-
-static struct list_head *type2list(u_int16_t af, u_int16_t type)
-{
-       struct list_head *list;
-
-       switch (type) {
-       case TARGET:
-               list = &xt[af].target;
-               break;
-       case MATCH:
-               list = &xt[af].match;
-               break;
-       case TABLE:
-               list = &xt[af].tables;
-               break;
-       default:
-               list = NULL;
-               break;
-       }
+static void *xt_table_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+       struct xt_names_priv *priv = seq->private;
+       struct net *net = priv->p.net;
+       int af = priv->af;
 
-       return list;
+       return seq_list_next(v, &net->xt.tables[af], pos);
 }
 
-static void *xt_tgt_seq_start(struct seq_file *seq, loff_t *pos)
+static void xt_table_seq_stop(struct seq_file *seq, void *v)
 {
-       struct proc_dir_entry *pde = (struct proc_dir_entry *) seq->private;
-       u_int16_t af = (unsigned long)pde->data & 0xffff;
-       u_int16_t type = (unsigned long)pde->data >> 16;
-       struct list_head *list;
+       struct xt_names_priv *priv = seq->private;
+       int af = priv->af;
 
-       if (af >= NPROTO)
-               return NULL;
+       mutex_unlock(&xt[af].mutex);
+}
 
-       list = type2list(af, type);
-       if (!list)
-               return NULL;
+static int xt_table_seq_show(struct seq_file *seq, void *v)
+{
+       struct xt_table *table = list_entry(v, struct xt_table, list);
 
-       if (mutex_lock_interruptible(&xt[af].mutex) != 0)
-               return NULL;
+       if (strlen(table->name))
+               return seq_printf(seq, "%s\n", table->name);
+       else
+               return 0;
+}
+
+static const struct seq_operations xt_table_seq_ops = {
+       .start  = xt_table_seq_start,
+       .next   = xt_table_seq_next,
+       .stop   = xt_table_seq_stop,
+       .show   = xt_table_seq_show,
+};
 
-       return xt_get_idx(list, seq, *pos);
+static int xt_table_open(struct inode *inode, struct file *file)
+{
+       int ret;
+       struct xt_names_priv *priv;
+
+       ret = seq_open_net(inode, file, &xt_table_seq_ops,
+                          sizeof(struct xt_names_priv));
+       if (!ret) {
+               priv = ((struct seq_file *)file->private_data)->private;
+               priv->af = (unsigned long)PDE(inode)->data;
+       }
+       return ret;
 }
 
-static void *xt_tgt_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+static const struct file_operations xt_table_ops = {
+       .owner   = THIS_MODULE,
+       .open    = xt_table_open,
+       .read    = seq_read,
+       .llseek  = seq_lseek,
+       .release = seq_release,
+};
+
+static void *xt_match_seq_start(struct seq_file *seq, loff_t *pos)
 {
-       struct proc_dir_entry *pde = seq->private;
-       u_int16_t af = (unsigned long)pde->data & 0xffff;
-       u_int16_t type = (unsigned long)pde->data >> 16;
-       struct list_head *list;
+       struct proc_dir_entry *pde = (struct proc_dir_entry *)seq->private;
+       u_int16_t af = (unsigned long)pde->data;
 
-       if (af >= NPROTO)
-               return NULL;
+       mutex_lock(&xt[af].mutex);
+       return seq_list_start(&xt[af].match, *pos);
+}
 
-       list = type2list(af, type);
-       if (!list)
-               return NULL;
+static void *xt_match_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+       struct proc_dir_entry *pde = (struct proc_dir_entry *)seq->private;
+       u_int16_t af = (unsigned long)pde->data;
 
-       (*pos)++;
-       return xt_get_idx(list, seq, *pos);
+       return seq_list_next(v, &xt[af].match, pos);
 }
 
-static void xt_tgt_seq_stop(struct seq_file *seq, void *v)
+static void xt_match_seq_stop(struct seq_file *seq, void *v)
 {
        struct proc_dir_entry *pde = seq->private;
-       u_int16_t af = (unsigned long)pde->data & 0xffff;
+       u_int16_t af = (unsigned long)pde->data;
 
        mutex_unlock(&xt[af].mutex);
 }
 
-static int xt_name_seq_show(struct seq_file *seq, void *v)
+static int xt_match_seq_show(struct seq_file *seq, void *v)
 {
-       char *name = (char *)v + sizeof(struct list_head);
+       struct xt_match *match = list_entry(v, struct xt_match, list);
 
-       if (strlen(name))
-               return seq_printf(seq, "%s\n", name);
+       if (strlen(match->name))
+               return seq_printf(seq, "%s\n", match->name);
        else
                return 0;
 }
 
-static const struct seq_operations xt_tgt_seq_ops = {
-       .start  = xt_tgt_seq_start,
-       .next   = xt_tgt_seq_next,
-       .stop   = xt_tgt_seq_stop,
-       .show   = xt_name_seq_show,
+static const struct seq_operations xt_match_seq_ops = {
+       .start  = xt_match_seq_start,
+       .next   = xt_match_seq_next,
+       .stop   = xt_match_seq_stop,
+       .show   = xt_match_seq_show,
 };
 
-static int xt_tgt_open(struct inode *inode, struct file *file)
+static int xt_match_open(struct inode *inode, struct file *file)
 {
        int ret;
 
-       ret = seq_open(file, &xt_tgt_seq_ops);
+       ret = seq_open(file, &xt_match_seq_ops);
        if (!ret) {
                struct seq_file *seq = file->private_data;
-               struct proc_dir_entry *pde = PDE(inode);
 
-               seq->private = pde;
+               seq->private = PDE(inode);
        }
+       return ret;
+}
+
+static const struct file_operations xt_match_ops = {
+       .owner   = THIS_MODULE,
+       .open    = xt_match_open,
+       .read    = seq_read,
+       .llseek  = seq_lseek,
+       .release = seq_release,
+};
+
+static void *xt_target_seq_start(struct seq_file *seq, loff_t *pos)
+{
+       struct proc_dir_entry *pde = (struct proc_dir_entry *)seq->private;
+       u_int16_t af = (unsigned long)pde->data;
+
+       mutex_lock(&xt[af].mutex);
+       return seq_list_start(&xt[af].target, *pos);
+}
+
+static void *xt_target_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+       struct proc_dir_entry *pde = (struct proc_dir_entry *)seq->private;
+       u_int16_t af = (unsigned long)pde->data;
+
+       return seq_list_next(v, &xt[af].target, pos);
+}
+
+static void xt_target_seq_stop(struct seq_file *seq, void *v)
+{
+       struct proc_dir_entry *pde = seq->private;
+       u_int16_t af = (unsigned long)pde->data;
+
+       mutex_unlock(&xt[af].mutex);
+}
 
+static int xt_target_seq_show(struct seq_file *seq, void *v)
+{
+       struct xt_target *target = list_entry(v, struct xt_target, list);
+
+       if (strlen(target->name))
+               return seq_printf(seq, "%s\n", target->name);
+       else
+               return 0;
+}
+
+static const struct seq_operations xt_target_seq_ops = {
+       .start  = xt_target_seq_start,
+       .next   = xt_target_seq_next,
+       .stop   = xt_target_seq_stop,
+       .show   = xt_target_seq_show,
+};
+
+static int xt_target_open(struct inode *inode, struct file *file)
+{
+       int ret;
+
+       ret = seq_open(file, &xt_target_seq_ops);
+       if (!ret) {
+               struct seq_file *seq = file->private_data;
+
+               seq->private = PDE(inode);
+       }
        return ret;
 }
 
-static const struct file_operations xt_file_ops = {
+static const struct file_operations xt_target_ops = {
        .owner   = THIS_MODULE,
-       .open    = xt_tgt_open,
+       .open    = xt_target_open,
        .read    = seq_read,
        .llseek  = seq_lseek,
        .release = seq_release,
@@ -844,7 +922,7 @@ static const struct file_operations xt_file_ops = {
 
 #endif /* CONFIG_PROC_FS */
 
-int xt_proto_init(int af)
+int xt_proto_init(struct net *net, int af)
 {
 #ifdef CONFIG_PROC_FS
        char buf[XT_FUNCTION_MAXNAMELEN];
@@ -858,25 +936,25 @@ int xt_proto_init(int af)
 #ifdef CONFIG_PROC_FS
        strlcpy(buf, xt_prefix[af], sizeof(buf));
        strlcat(buf, FORMAT_TABLES, sizeof(buf));
-       proc = proc_net_fops_create(&init_net, buf, 0440, &xt_file_ops);
+       proc = proc_net_fops_create(net, buf, 0440, &xt_table_ops);
        if (!proc)
                goto out;
-       proc->data = (void *) ((unsigned long) af | (TABLE << 16));
+       proc->data = (void *)(unsigned long)af;
 
 
        strlcpy(buf, xt_prefix[af], sizeof(buf));
        strlcat(buf, FORMAT_MATCHES, sizeof(buf));
-       proc = proc_net_fops_create(&init_net, buf, 0440, &xt_file_ops);
+       proc = proc_net_fops_create(net, buf, 0440, &xt_match_ops);
        if (!proc)
                goto out_remove_tables;
-       proc->data = (void *) ((unsigned long) af | (MATCH << 16));
+       proc->data = (void *)(unsigned long)af;
 
        strlcpy(buf, xt_prefix[af], sizeof(buf));
        strlcat(buf, FORMAT_TARGETS, sizeof(buf));
-       proc = proc_net_fops_create(&init_net, buf, 0440, &xt_file_ops);
+       proc = proc_net_fops_create(net, buf, 0440, &xt_target_ops);
        if (!proc)
                goto out_remove_matches;
-       proc->data = (void *) ((unsigned long) af | (TARGET << 16));
+       proc->data = (void *)(unsigned long)af;
 #endif
 
        return 0;
@@ -885,42 +963,54 @@ int xt_proto_init(int af)
 out_remove_matches:
        strlcpy(buf, xt_prefix[af], sizeof(buf));
        strlcat(buf, FORMAT_MATCHES, sizeof(buf));
-       proc_net_remove(&init_net, buf);
+       proc_net_remove(net, buf);
 
 out_remove_tables:
        strlcpy(buf, xt_prefix[af], sizeof(buf));
        strlcat(buf, FORMAT_TABLES, sizeof(buf));
-       proc_net_remove(&init_net, buf);
+       proc_net_remove(net, buf);
 out:
        return -1;
 #endif
 }
 EXPORT_SYMBOL_GPL(xt_proto_init);
 
-void xt_proto_fini(int af)
+void xt_proto_fini(struct net *net, int af)
 {
 #ifdef CONFIG_PROC_FS
        char buf[XT_FUNCTION_MAXNAMELEN];
 
        strlcpy(buf, xt_prefix[af], sizeof(buf));
        strlcat(buf, FORMAT_TABLES, sizeof(buf));
-       proc_net_remove(&init_net, buf);
+       proc_net_remove(net, buf);
 
        strlcpy(buf, xt_prefix[af], sizeof(buf));
        strlcat(buf, FORMAT_TARGETS, sizeof(buf));
-       proc_net_remove(&init_net, buf);
+       proc_net_remove(net, buf);
 
        strlcpy(buf, xt_prefix[af], sizeof(buf));
        strlcat(buf, FORMAT_MATCHES, sizeof(buf));
-       proc_net_remove(&init_net, buf);
+       proc_net_remove(net, buf);
 #endif /*CONFIG_PROC_FS*/
 }
 EXPORT_SYMBOL_GPL(xt_proto_fini);
 
+static int __net_init xt_net_init(struct net *net)
+{
+       int i;
+
+       for (i = 0; i < NPROTO; i++)
+               INIT_LIST_HEAD(&net->xt.tables[i]);
+       return 0;
+}
+
+static struct pernet_operations xt_net_ops = {
+       .init = xt_net_init,
+};
 
 static int __init xt_init(void)
 {
-       int i;
+       int i, rv;
 
        xt = kmalloc(sizeof(struct xt_af) * NPROTO, GFP_KERNEL);
        if (!xt)
@@ -934,13 +1024,16 @@ static int __init xt_init(void)
 #endif
                INIT_LIST_HEAD(&xt[i].target);
                INIT_LIST_HEAD(&xt[i].match);
-               INIT_LIST_HEAD(&xt[i].tables);
        }
-       return 0;
+       rv = register_pernet_subsys(&xt_net_ops);
+       if (rv < 0)
+               kfree(xt);
+       return rv;
 }
 
 static void __exit xt_fini(void)
 {
+       unregister_pernet_subsys(&xt_net_ops);
        kfree(xt);
 }
 
index 60e3767cc71deb40f61e0d8ecaf9c87a76fc8996..217e2b6863225acf4353e7cd6f4869df3ce1da56 100644 (file)
 #include <linux/ip.h>
 #include <linux/ipv6.h>
 #include <linux/tcp.h>
+#include <net/dst.h>
+#include <net/flow.h>
 #include <net/ipv6.h>
+#include <net/route.h>
 #include <net/tcp.h>
 
 #include <linux/netfilter_ipv4/ip_tables.h>
@@ -41,6 +44,7 @@ optlen(const u_int8_t *opt, unsigned int offset)
 static int
 tcpmss_mangle_packet(struct sk_buff *skb,
                     const struct xt_tcpmss_info *info,
+                    unsigned int in_mtu,
                     unsigned int tcphoff,
                     unsigned int minlen)
 {
@@ -76,7 +80,13 @@ tcpmss_mangle_packet(struct sk_buff *skb,
                                       dst_mtu(skb->dst));
                        return -1;
                }
-               newmss = dst_mtu(skb->dst) - minlen;
+               if (in_mtu <= minlen) {
+                       if (net_ratelimit())
+                               printk(KERN_ERR "xt_TCPMSS: unknown or "
+                                      "invalid path-MTU (%u)\n", in_mtu);
+                       return -1;
+               }
+               newmss = min(dst_mtu(skb->dst), in_mtu) - minlen;
        } else
                newmss = info->mss;
 
@@ -137,6 +147,28 @@ tcpmss_mangle_packet(struct sk_buff *skb,
        return TCPOLEN_MSS;
 }
 
+static u_int32_t tcpmss_reverse_mtu4(const struct iphdr *iph)
+{
+       struct flowi fl = {
+               .fl4_dst = iph->saddr,
+       };
+       const struct nf_afinfo *ai;
+       struct rtable *rt = NULL;
+       u_int32_t mtu     = ~0U;
+
+       rcu_read_lock();
+       ai = nf_get_afinfo(AF_INET);
+       if (ai != NULL)
+               ai->route((struct dst_entry **)&rt, &fl);
+       rcu_read_unlock();
+
+       if (rt != NULL) {
+               mtu = dst_mtu(&rt->u.dst);
+               dst_release(&rt->u.dst);
+       }
+       return mtu;
+}
+
 static unsigned int
 tcpmss_tg4(struct sk_buff *skb, const struct net_device *in,
            const struct net_device *out, unsigned int hooknum,
@@ -146,7 +178,8 @@ tcpmss_tg4(struct sk_buff *skb, const struct net_device *in,
        __be16 newlen;
        int ret;
 
-       ret = tcpmss_mangle_packet(skb, targinfo, iph->ihl * 4,
+       ret = tcpmss_mangle_packet(skb, targinfo, tcpmss_reverse_mtu4(iph),
+                                  iph->ihl * 4,
                                   sizeof(*iph) + sizeof(struct tcphdr));
        if (ret < 0)
                return NF_DROP;
@@ -160,6 +193,28 @@ tcpmss_tg4(struct sk_buff *skb, const struct net_device *in,
 }
 
 #if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE)
+static u_int32_t tcpmss_reverse_mtu6(const struct ipv6hdr *iph)
+{
+       struct flowi fl = {
+               .fl6_dst = iph->saddr,
+       };
+       const struct nf_afinfo *ai;
+       struct rtable *rt = NULL;
+       u_int32_t mtu     = ~0U;
+
+       rcu_read_lock();
+       ai = nf_get_afinfo(AF_INET6);
+       if (ai != NULL)
+               ai->route((struct dst_entry **)&rt, &fl);
+       rcu_read_unlock();
+
+       if (rt != NULL) {
+               mtu = dst_mtu(&rt->u.dst);
+               dst_release(&rt->u.dst);
+       }
+       return mtu;
+}
+
 static unsigned int
 tcpmss_tg6(struct sk_buff *skb, const struct net_device *in,
            const struct net_device *out, unsigned int hooknum,
@@ -174,7 +229,8 @@ tcpmss_tg6(struct sk_buff *skb, const struct net_device *in,
        tcphoff = ipv6_skip_exthdr(skb, sizeof(*ipv6h), &nexthdr);
        if (tcphoff < 0)
                return NF_DROP;
-       ret = tcpmss_mangle_packet(skb, targinfo, tcphoff,
+       ret = tcpmss_mangle_packet(skb, targinfo, tcpmss_reverse_mtu6(ipv6h),
+                                  tcphoff,
                                   sizeof(*ipv6h) + sizeof(struct tcphdr));
        if (ret < 0)
                return NF_DROP;
index e00ecd974fa3cf9882b406d5c33157f1fd29d93c..3b0111933f601782887e4edc8f7500aff4a2116f 100644 (file)
@@ -120,11 +120,11 @@ static int count_them(struct xt_connlimit_data *data,
        else
                hash = &data->iphash[connlimit_iphash(addr->ip & mask->ip)];
 
-       read_lock_bh(&nf_conntrack_lock);
+       rcu_read_lock();
 
        /* check the saved connections */
        list_for_each_entry_safe(conn, tmp, hash, list) {
-               found    = __nf_conntrack_find(&conn->tuple, NULL);
+               found    = __nf_conntrack_find(&conn->tuple);
                found_ct = NULL;
 
                if (found != NULL)
@@ -163,7 +163,7 @@ static int count_them(struct xt_connlimit_data *data,
                        ++matches;
        }
 
-       read_unlock_bh(&nf_conntrack_lock);
+       rcu_read_unlock();
 
        if (addit) {
                /* save the new connection in our list */
index e92190eafcc5b2cc74ed1a748a73bc7676990472..85330856a29c52065771c413737f958639d7cd20 100644 (file)
@@ -4,7 +4,6 @@
  *
  *     (C) 2001  Marc Boucher (marc@mbsi.ca).
  *     Copyright Â© CC Computer Consultants GmbH, 2007 - 2008
- *     Jan Engelhardt <jengelh@computergmbh.de>
  *
  *     This program is free software; you can redistribute it and/or modify
  *     it under the terms of the GNU General Public License version 2 as
@@ -20,6 +19,7 @@
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>");
+MODULE_AUTHOR("Jan Engelhardt <jengelh@computergmbh.de>");
 MODULE_DESCRIPTION("Xtables: connection tracking state match");
 MODULE_ALIAS("ipt_conntrack");
 MODULE_ALIAS("ip6t_conntrack");
@@ -166,6 +166,44 @@ conntrack_mt_repldst(const struct nf_conn *ct,
               &info->repldst_addr, &info->repldst_mask, family);
 }
 
+static inline bool
+ct_proto_port_check(const struct xt_conntrack_mtinfo1 *info,
+                    const struct nf_conn *ct)
+{
+       const struct nf_conntrack_tuple *tuple;
+
+       tuple = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
+       if ((info->match_flags & XT_CONNTRACK_PROTO) &&
+           (tuple->dst.protonum == info->l4proto) ^
+           !(info->invert_flags & XT_CONNTRACK_PROTO))
+               return false;
+
+       /* Shortcut to match all recognized protocols by using ->src.all. */
+       if ((info->match_flags & XT_CONNTRACK_ORIGSRC_PORT) &&
+           (tuple->src.u.all == info->origsrc_port) ^
+           !(info->invert_flags & XT_CONNTRACK_ORIGSRC_PORT))
+               return false;
+
+       if ((info->match_flags & XT_CONNTRACK_ORIGDST_PORT) &&
+           (tuple->dst.u.all == info->origdst_port) ^
+           !(info->invert_flags & XT_CONNTRACK_ORIGDST_PORT))
+               return false;
+
+       tuple = &ct->tuplehash[IP_CT_DIR_REPLY].tuple;
+
+       if ((info->match_flags & XT_CONNTRACK_REPLSRC_PORT) &&
+           (tuple->src.u.all == info->replsrc_port) ^
+           !(info->invert_flags & XT_CONNTRACK_REPLSRC_PORT))
+               return false;
+
+       if ((info->match_flags & XT_CONNTRACK_REPLDST_PORT) &&
+           (tuple->dst.u.all == info->repldst_port) ^
+           !(info->invert_flags & XT_CONNTRACK_REPLDST_PORT))
+               return false;
+
+       return true;
+}
+
 static bool
 conntrack_mt(const struct sk_buff *skb, const struct net_device *in,
              const struct net_device *out, const struct xt_match *match,
@@ -200,10 +238,9 @@ conntrack_mt(const struct sk_buff *skb, const struct net_device *in,
 
        if (ct == NULL)
                return info->match_flags & XT_CONNTRACK_STATE;
-
-       if ((info->match_flags & XT_CONNTRACK_PROTO) &&
-           ((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum ==
-           info->l4proto) ^ !(info->invert_flags & XT_CONNTRACK_PROTO)))
+       if ((info->match_flags & XT_CONNTRACK_DIRECTION) &&
+           (CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL) ^
+           !!(info->invert_flags & XT_CONNTRACK_DIRECTION))
                return false;
 
        if (info->match_flags & XT_CONNTRACK_ORIGSRC)
@@ -226,6 +263,9 @@ conntrack_mt(const struct sk_buff *skb, const struct net_device *in,
                    !(info->invert_flags & XT_CONNTRACK_REPLDST))
                        return false;
 
+       if (!ct_proto_port_check(info, ct))
+               return false;
+
        if ((info->match_flags & XT_CONNTRACK_STATUS) &&
            (!!(info->status_mask & ct->status) ^
            !(info->invert_flags & XT_CONNTRACK_STATUS)))
index d479ca980115af614e25ef411917d7f83c4e4044..744c7f2ab0b1feb7c01c8d05c4867160a945caf3 100644 (file)
@@ -1,9 +1,9 @@
-/* iptables match extension to limit the number of packets per second
- * seperately for each hashbucket (sourceip/sourceport/dstip/dstport)
+/*
+ *     xt_hashlimit - Netfilter module to limit the number of packets per time
+ *     seperately for each hashbucket (sourceip/sourceport/dstip/dstport)
  *
- * (C) 2003-2004 by Harald Welte <laforge@netfilter.org>
- *
- * $Id: ipt_hashlimit.c 3244 2004-10-20 16:24:29Z laforge@netfilter.org $
+ *     (C) 2003-2004 by Harald Welte <laforge@netfilter.org>
+ *     Copyright Â© CC Computer Consultants GmbH, 2007 - 2008
  *
  * Development of this code was funded by Astaro AG, http://www.astaro.com/
  */
@@ -35,6 +35,7 @@
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
+MODULE_AUTHOR("Jan Engelhardt <jengelh@computergmbh.de>");
 MODULE_DESCRIPTION("Xtables: per hash-bucket rate-limit match");
 MODULE_ALIAS("ipt_hashlimit");
 MODULE_ALIAS("ip6t_hashlimit");
@@ -57,7 +58,7 @@ struct dsthash_dst {
                        __be32 dst[4];
                } ip6;
 #endif
-       } addr;
+       };
        __be16 src_port;
        __be16 dst_port;
 };
@@ -81,7 +82,7 @@ struct xt_hashlimit_htable {
        atomic_t use;
        int family;
 
-       struct hashlimit_cfg cfg;       /* config */
+       struct hashlimit_cfg1 cfg;      /* config */
 
        /* used internally */
        spinlock_t lock;                /* lock for list_head */
@@ -184,7 +185,7 @@ dsthash_free(struct xt_hashlimit_htable *ht, struct dsthash_ent *ent)
 }
 static void htable_gc(unsigned long htlong);
 
-static int htable_create(struct xt_hashlimit_info *minfo, int family)
+static int htable_create_v0(struct xt_hashlimit_info *minfo, int family)
 {
        struct xt_hashlimit_htable *hinfo;
        unsigned int size;
@@ -210,7 +211,18 @@ static int htable_create(struct xt_hashlimit_info *minfo, int family)
        minfo->hinfo = hinfo;
 
        /* copy match config into hashtable config */
-       memcpy(&hinfo->cfg, &minfo->cfg, sizeof(hinfo->cfg));
+       hinfo->cfg.mode        = minfo->cfg.mode;
+       hinfo->cfg.avg         = minfo->cfg.avg;
+       hinfo->cfg.burst       = minfo->cfg.burst;
+       hinfo->cfg.max         = minfo->cfg.max;
+       hinfo->cfg.gc_interval = minfo->cfg.gc_interval;
+       hinfo->cfg.expire      = minfo->cfg.expire;
+
+       if (family == AF_INET)
+               hinfo->cfg.srcmask = hinfo->cfg.dstmask = 32;
+       else
+               hinfo->cfg.srcmask = hinfo->cfg.dstmask = 128;
+
        hinfo->cfg.size = size;
        if (!hinfo->cfg.max)
                hinfo->cfg.max = 8 * hinfo->cfg.size;
@@ -246,6 +258,70 @@ static int htable_create(struct xt_hashlimit_info *minfo, int family)
        return 0;
 }
 
+static int htable_create(struct xt_hashlimit_mtinfo1 *minfo,
+                         unsigned int family)
+{
+       struct xt_hashlimit_htable *hinfo;
+       unsigned int size;
+       unsigned int i;
+
+       if (minfo->cfg.size) {
+               size = minfo->cfg.size;
+       } else {
+               size = (num_physpages << PAGE_SHIFT) / 16384 /
+                      sizeof(struct list_head);
+               if (num_physpages > 1024 * 1024 * 1024 / PAGE_SIZE)
+                       size = 8192;
+               if (size < 16)
+                       size = 16;
+       }
+       /* FIXME: don't use vmalloc() here or anywhere else -HW */
+       hinfo = vmalloc(sizeof(struct xt_hashlimit_htable) +
+                       sizeof(struct list_head) * size);
+       if (hinfo == NULL) {
+               printk(KERN_ERR "xt_hashlimit: unable to create hashtable\n");
+               return -1;
+       }
+       minfo->hinfo = hinfo;
+
+       /* copy match config into hashtable config */
+       memcpy(&hinfo->cfg, &minfo->cfg, sizeof(hinfo->cfg));
+       hinfo->cfg.size = size;
+       if (hinfo->cfg.max == 0)
+               hinfo->cfg.max = 8 * hinfo->cfg.size;
+       else if (hinfo->cfg.max < hinfo->cfg.size)
+               hinfo->cfg.max = hinfo->cfg.size;
+
+       for (i = 0; i < hinfo->cfg.size; i++)
+               INIT_HLIST_HEAD(&hinfo->hash[i]);
+
+       atomic_set(&hinfo->use, 1);
+       hinfo->count = 0;
+       hinfo->family = family;
+       hinfo->rnd_initialized = 0;
+       spin_lock_init(&hinfo->lock);
+
+       hinfo->pde = create_proc_entry(minfo->name, 0,
+                                      family == AF_INET ? hashlimit_procdir4 :
+                                                          hashlimit_procdir6);
+       if (hinfo->pde == NULL) {
+               vfree(hinfo);
+               return -1;
+       }
+       hinfo->pde->proc_fops = &dl_file_ops;
+       hinfo->pde->data = hinfo;
+
+       setup_timer(&hinfo->timer, htable_gc, (unsigned long)hinfo);
+       hinfo->timer.expires = jiffies + msecs_to_jiffies(hinfo->cfg.gc_interval);
+       add_timer(&hinfo->timer);
+
+       spin_lock_bh(&hashlimit_lock);
+       hlist_add_head(&hinfo->node, &hashlimit_htables);
+       spin_unlock_bh(&hashlimit_lock);
+
+       return 0;
+}
+
 static bool select_all(const struct xt_hashlimit_htable *ht,
                       const struct dsthash_ent *he)
 {
@@ -388,6 +464,48 @@ static inline void rateinfo_recalc(struct dsthash_ent *dh, unsigned long now)
        dh->rateinfo.prev = now;
 }
 
+static inline __be32 maskl(__be32 a, unsigned int l)
+{
+       return htonl(ntohl(a) & ~(~(u_int32_t)0 >> l));
+}
+
+#if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE)
+static void hashlimit_ipv6_mask(__be32 *i, unsigned int p)
+{
+       switch (p) {
+       case 0:
+               i[0] = i[1] = 0;
+               i[2] = i[3] = 0;
+               break;
+       case 1 ... 31:
+               i[0] = maskl(i[0], p);
+               i[1] = i[2] = i[3] = 0;
+               break;
+       case 32:
+               i[1] = i[2] = i[3] = 0;
+               break;
+       case 33 ... 63:
+               i[1] = maskl(i[1], p - 32);
+               i[2] = i[3] = 0;
+               break;
+       case 64:
+               i[2] = i[3] = 0;
+               break;
+       case 65 ... 95:
+               i[2] = maskl(i[2], p - 64);
+               i[3] = 0;
+       case 96:
+               i[3] = 0;
+               break;
+       case 97 ... 127:
+               i[3] = maskl(i[3], p - 96);
+               break;
+       case 128:
+               break;
+       }
+}
+#endif
+
 static int
 hashlimit_init_dst(const struct xt_hashlimit_htable *hinfo,
                   struct dsthash_dst *dst,
@@ -401,9 +519,11 @@ hashlimit_init_dst(const struct xt_hashlimit_htable *hinfo,
        switch (hinfo->family) {
        case AF_INET:
                if (hinfo->cfg.mode & XT_HASHLIMIT_HASH_DIP)
-                       dst->addr.ip.dst = ip_hdr(skb)->daddr;
+                       dst->ip.dst = maskl(ip_hdr(skb)->daddr,
+                                     hinfo->cfg.dstmask);
                if (hinfo->cfg.mode & XT_HASHLIMIT_HASH_SIP)
-                       dst->addr.ip.src = ip_hdr(skb)->saddr;
+                       dst->ip.src = maskl(ip_hdr(skb)->saddr,
+                                     hinfo->cfg.srcmask);
 
                if (!(hinfo->cfg.mode &
                      (XT_HASHLIMIT_HASH_DPT | XT_HASHLIMIT_HASH_SPT)))
@@ -412,12 +532,16 @@ hashlimit_init_dst(const struct xt_hashlimit_htable *hinfo,
                break;
 #if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE)
        case AF_INET6:
-               if (hinfo->cfg.mode & XT_HASHLIMIT_HASH_DIP)
-                       memcpy(&dst->addr.ip6.dst, &ipv6_hdr(skb)->daddr,
-                              sizeof(dst->addr.ip6.dst));
-               if (hinfo->cfg.mode & XT_HASHLIMIT_HASH_SIP)
-                       memcpy(&dst->addr.ip6.src, &ipv6_hdr(skb)->saddr,
-                              sizeof(dst->addr.ip6.src));
+               if (hinfo->cfg.mode & XT_HASHLIMIT_HASH_DIP) {
+                       memcpy(&dst->ip6.dst, &ipv6_hdr(skb)->daddr,
+                              sizeof(dst->ip6.dst));
+                       hashlimit_ipv6_mask(dst->ip6.dst, hinfo->cfg.dstmask);
+               }
+               if (hinfo->cfg.mode & XT_HASHLIMIT_HASH_SIP) {
+                       memcpy(&dst->ip6.src, &ipv6_hdr(skb)->saddr,
+                              sizeof(dst->ip6.src));
+                       hashlimit_ipv6_mask(dst->ip6.src, hinfo->cfg.srcmask);
+               }
 
                if (!(hinfo->cfg.mode &
                      (XT_HASHLIMIT_HASH_DPT | XT_HASHLIMIT_HASH_SPT)))
@@ -457,10 +581,10 @@ hashlimit_init_dst(const struct xt_hashlimit_htable *hinfo,
 }
 
 static bool
-hashlimit_mt(const struct sk_buff *skb, const struct net_device *in,
-             const struct net_device *out, const struct xt_match *match,
-             const void *matchinfo, int offset, unsigned int protoff,
-             bool *hotdrop)
+hashlimit_mt_v0(const struct sk_buff *skb, const struct net_device *in,
+                const struct net_device *out, const struct xt_match *match,
+                const void *matchinfo, int offset, unsigned int protoff,
+                bool *hotdrop)
 {
        const struct xt_hashlimit_info *r =
                ((const struct xt_hashlimit_info *)matchinfo)->u.master;
@@ -512,9 +636,62 @@ hotdrop:
 }
 
 static bool
-hashlimit_mt_check(const char *tablename, const void *inf,
-                   const struct xt_match *match, void *matchinfo,
-                   unsigned int hook_mask)
+hashlimit_mt(const struct sk_buff *skb, const struct net_device *in,
+             const struct net_device *out, const struct xt_match *match,
+             const void *matchinfo, int offset, unsigned int protoff,
+             bool *hotdrop)
+{
+       const struct xt_hashlimit_mtinfo1 *info = matchinfo;
+       struct xt_hashlimit_htable *hinfo = info->hinfo;
+       unsigned long now = jiffies;
+       struct dsthash_ent *dh;
+       struct dsthash_dst dst;
+
+       if (hashlimit_init_dst(hinfo, &dst, skb, protoff) < 0)
+               goto hotdrop;
+
+       spin_lock_bh(&hinfo->lock);
+       dh = dsthash_find(hinfo, &dst);
+       if (dh == NULL) {
+               dh = dsthash_alloc_init(hinfo, &dst);
+               if (dh == NULL) {
+                       spin_unlock_bh(&hinfo->lock);
+                       goto hotdrop;
+               }
+
+               dh->expires = jiffies + msecs_to_jiffies(hinfo->cfg.expire);
+               dh->rateinfo.prev = jiffies;
+               dh->rateinfo.credit = user2credits(hinfo->cfg.avg *
+                                     hinfo->cfg.burst);
+               dh->rateinfo.credit_cap = user2credits(hinfo->cfg.avg *
+                                         hinfo->cfg.burst);
+               dh->rateinfo.cost = user2credits(hinfo->cfg.avg);
+       } else {
+               /* update expiration timeout */
+               dh->expires = now + msecs_to_jiffies(hinfo->cfg.expire);
+               rateinfo_recalc(dh, now);
+       }
+
+       if (dh->rateinfo.credit >= dh->rateinfo.cost) {
+               /* below the limit */
+               dh->rateinfo.credit -= dh->rateinfo.cost;
+               spin_unlock_bh(&hinfo->lock);
+               return !(info->cfg.mode & XT_HASHLIMIT_INVERT);
+       }
+
+       spin_unlock_bh(&hinfo->lock);
+       /* default match is underlimit - so over the limit, we need to invert */
+       return info->cfg.mode & XT_HASHLIMIT_INVERT;
+
+ hotdrop:
+       *hotdrop = true;
+       return false;
+}
+
+static bool
+hashlimit_mt_check_v0(const char *tablename, const void *inf,
+                      const struct xt_match *match, void *matchinfo,
+                      unsigned int hook_mask)
 {
        struct xt_hashlimit_info *r = matchinfo;
 
@@ -546,7 +723,7 @@ hashlimit_mt_check(const char *tablename, const void *inf,
         * create duplicate proc files. -HW */
        mutex_lock(&hlimit_mutex);
        r->hinfo = htable_find_get(r->name, match->family);
-       if (!r->hinfo && htable_create(r, match->family) != 0) {
+       if (!r->hinfo && htable_create_v0(r, match->family) != 0) {
                mutex_unlock(&hlimit_mutex);
                return false;
        }
@@ -557,14 +734,68 @@ hashlimit_mt_check(const char *tablename, const void *inf,
        return true;
 }
 
+static bool
+hashlimit_mt_check(const char *tablename, const void *inf,
+                   const struct xt_match *match, void *matchinfo,
+                   unsigned int hook_mask)
+{
+       struct xt_hashlimit_mtinfo1 *info = matchinfo;
+
+       /* Check for overflow. */
+       if (info->cfg.burst == 0 ||
+           user2credits(info->cfg.avg * info->cfg.burst) <
+           user2credits(info->cfg.avg)) {
+               printk(KERN_ERR "xt_hashlimit: overflow, try lower: %u/%u\n",
+                      info->cfg.avg, info->cfg.burst);
+               return false;
+       }
+       if (info->cfg.gc_interval == 0 || info->cfg.expire == 0)
+               return false;
+       if (info->name[sizeof(info->name)-1] != '\0')
+               return false;
+       if (match->family == AF_INET) {
+               if (info->cfg.srcmask > 32 || info->cfg.dstmask > 32)
+                       return false;
+       } else {
+               if (info->cfg.srcmask > 128 || info->cfg.dstmask > 128)
+                       return false;
+       }
+
+       /* This is the best we've got: We cannot release and re-grab lock,
+        * since checkentry() is called before x_tables.c grabs xt_mutex.
+        * We also cannot grab the hashtable spinlock, since htable_create will
+        * call vmalloc, and that can sleep.  And we cannot just re-search
+        * the list of htable's in htable_create(), since then we would
+        * create duplicate proc files. -HW */
+       mutex_lock(&hlimit_mutex);
+       info->hinfo = htable_find_get(info->name, match->family);
+       if (!info->hinfo && htable_create(info, match->family) != 0) {
+               mutex_unlock(&hlimit_mutex);
+               return false;
+       }
+       mutex_unlock(&hlimit_mutex);
+
+       /* Ugly hack: For SMP, we only want to use one set */
+       info->master = info;
+       return true;
+}
+
 static void
-hashlimit_mt_destroy(const struct xt_match *match, void *matchinfo)
+hashlimit_mt_destroy_v0(const struct xt_match *match, void *matchinfo)
 {
        const struct xt_hashlimit_info *r = matchinfo;
 
        htable_put(r->hinfo);
 }
 
+static void
+hashlimit_mt_destroy(const struct xt_match *match, void *matchinfo)
+{
+       const struct xt_hashlimit_mtinfo1 *info = matchinfo;
+
+       htable_put(info->hinfo);
+}
+
 #ifdef CONFIG_COMPAT
 struct compat_xt_hashlimit_info {
        char name[IFNAMSIZ];
@@ -592,38 +823,60 @@ static int hashlimit_mt_compat_to_user(void __user *dst, void *src)
 static struct xt_match hashlimit_mt_reg[] __read_mostly = {
        {
                .name           = "hashlimit",
+               .revision       = 0,
                .family         = AF_INET,
-               .match          = hashlimit_mt,
+               .match          = hashlimit_mt_v0,
                .matchsize      = sizeof(struct xt_hashlimit_info),
 #ifdef CONFIG_COMPAT
                .compatsize     = sizeof(struct compat_xt_hashlimit_info),
                .compat_from_user = hashlimit_mt_compat_from_user,
                .compat_to_user = hashlimit_mt_compat_to_user,
 #endif
-               .checkentry     = hashlimit_mt_check,
-               .destroy        = hashlimit_mt_destroy,
+               .checkentry     = hashlimit_mt_check_v0,
+               .destroy        = hashlimit_mt_destroy_v0,
                .me             = THIS_MODULE
        },
+       {
+               .name           = "hashlimit",
+               .revision       = 1,
+               .family         = AF_INET,
+               .match          = hashlimit_mt,
+               .matchsize      = sizeof(struct xt_hashlimit_mtinfo1),
+               .checkentry     = hashlimit_mt_check,
+               .destroy        = hashlimit_mt_destroy,
+               .me             = THIS_MODULE,
+       },
 #if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE)
        {
                .name           = "hashlimit",
                .family         = AF_INET6,
-               .match          = hashlimit_mt,
+               .match          = hashlimit_mt_v0,
                .matchsize      = sizeof(struct xt_hashlimit_info),
 #ifdef CONFIG_COMPAT
                .compatsize     = sizeof(struct compat_xt_hashlimit_info),
                .compat_from_user = hashlimit_mt_compat_from_user,
                .compat_to_user = hashlimit_mt_compat_to_user,
 #endif
-               .checkentry     = hashlimit_mt_check,
-               .destroy        = hashlimit_mt_destroy,
+               .checkentry     = hashlimit_mt_check_v0,
+               .destroy        = hashlimit_mt_destroy_v0,
                .me             = THIS_MODULE
        },
+       {
+               .name           = "hashlimit",
+               .revision       = 1,
+               .family         = AF_INET6,
+               .match          = hashlimit_mt,
+               .matchsize      = sizeof(struct xt_hashlimit_mtinfo1),
+               .checkentry     = hashlimit_mt_check,
+               .destroy        = hashlimit_mt_destroy,
+               .me             = THIS_MODULE,
+       },
 #endif
 };
 
 /* PROC stuff */
 static void *dl_seq_start(struct seq_file *s, loff_t *pos)
+       __acquires(htable->lock)
 {
        struct proc_dir_entry *pde = s->private;
        struct xt_hashlimit_htable *htable = pde->data;
@@ -656,6 +909,7 @@ static void *dl_seq_next(struct seq_file *s, void *v, loff_t *pos)
 }
 
 static void dl_seq_stop(struct seq_file *s, void *v)
+       __releases(htable->lock)
 {
        struct proc_dir_entry *pde = s->private;
        struct xt_hashlimit_htable *htable = pde->data;
@@ -676,9 +930,9 @@ static int dl_seq_real_show(struct dsthash_ent *ent, int family,
                return seq_printf(s, "%ld %u.%u.%u.%u:%u->"
                                     "%u.%u.%u.%u:%u %u %u %u\n",
                                 (long)(ent->expires - jiffies)/HZ,
-                                NIPQUAD(ent->dst.addr.ip.src),
+                                NIPQUAD(ent->dst.ip.src),
                                 ntohs(ent->dst.src_port),
-                                NIPQUAD(ent->dst.addr.ip.dst),
+                                NIPQUAD(ent->dst.ip.dst),
                                 ntohs(ent->dst.dst_port),
                                 ent->rateinfo.credit, ent->rateinfo.credit_cap,
                                 ent->rateinfo.cost);
@@ -687,9 +941,9 @@ static int dl_seq_real_show(struct dsthash_ent *ent, int family,
                return seq_printf(s, "%ld " NIP6_FMT ":%u->"
                                     NIP6_FMT ":%u %u %u %u\n",
                                 (long)(ent->expires - jiffies)/HZ,
-                                NIP6(*(struct in6_addr *)&ent->dst.addr.ip6.src),
+                                NIP6(*(struct in6_addr *)&ent->dst.ip6.src),
                                 ntohs(ent->dst.src_port),
-                                NIP6(*(struct in6_addr *)&ent->dst.addr.ip6.dst),
+                                NIP6(*(struct in6_addr *)&ent->dst.ip6.dst),
                                 ntohs(ent->dst.dst_port),
                                 ent->rateinfo.credit, ent->rateinfo.credit_cap,
                                 ent->rateinfo.cost);
index dbea0e0893f371bc8100cfa1954fda8832de31f2..01035fc0e140637146c16b0413db56baf6aa3180 100644 (file)
@@ -101,7 +101,7 @@ iprange_ipv6_sub(const struct in6_addr *a, const struct in6_addr *b)
        int r;
 
        for (i = 0; i < 4; ++i) {
-               r = a->s6_addr32[i] - b->s6_addr32[i];
+               r = (__force u32)a->s6_addr32[i] - (__force u32)b->s6_addr32[i];
                if (r != 0)
                        return r;
        }
index d382f9cc38b0b5fbf90c4af50f4c5b5a2c7b2e65..9059c16144c3cb1d67fe3d6accc2f6951744e5a7 100644 (file)
@@ -4,8 +4,8 @@
  *
  * (C) 2000 Marc Boucher <marc@mbsi.ca>
  *
- * Copyright Â© CC Computer Consultants GmbH, 2007
- * Contact: <jengelh@computergmbh.de>
+ * Copyright Â© CC Computer Consultants GmbH, 2007 - 2008
+ * <jengelh@computergmbh.de>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -102,13 +102,15 @@ owner_mt(const struct sk_buff *skb, const struct net_device *in,
                       (XT_OWNER_UID | XT_OWNER_GID)) == 0;
 
        if (info->match & XT_OWNER_UID)
-               if ((filp->f_uid != info->uid) ^
-                   !!(info->invert & XT_OWNER_UID))
+               if ((filp->f_uid >= info->uid_min &&
+                   filp->f_uid <= info->uid_max) ^
+                   !(info->invert & XT_OWNER_UID))
                        return false;
 
        if (info->match & XT_OWNER_GID)
-               if ((filp->f_gid != info->gid) ^
-                   !!(info->invert & XT_OWNER_GID))
+               if ((filp->f_gid >= info->gid_min &&
+                   filp->f_gid <= info->gid_max) ^
+                   !(info->invert & XT_OWNER_GID))
                        return false;
 
        return true;
index becf91a952aeca035f0d060eac857850c854112e..c7ad64d664ad21a7dbe45f3ee539793329dce2f4 100644 (file)
@@ -90,7 +90,7 @@ static const struct nla_policy netlbl_cipsov4_genl_policy[NLBL_CIPSOV4_A_MAX + 1
  * safely.
  *
  */
-static void netlbl_cipsov4_doi_free(struct rcu_head *entry)
+void netlbl_cipsov4_doi_free(struct rcu_head *entry)
 {
        struct cipso_v4_doi *ptr;
 
index f03cf9b78286fe920c17e68dd0ebe02190979b3a..220cb9d06b496d315d30c1041a03525421b4a9e2 100644 (file)
@@ -163,4 +163,7 @@ enum {
 /* NetLabel protocol functions */
 int netlbl_cipsov4_genl_init(void);
 
+/* Free the memory associated with a CIPSOv4 DOI definition */
+void netlbl_cipsov4_doi_free(struct rcu_head *entry);
+
 #endif
index 3689956c34363242007d300b0865c53a0da867d5..8220990ceb967a0480421e82c465490fab3983b8 100644 (file)
@@ -61,6 +61,7 @@ int netlbl_domhsh_add(struct netlbl_dom_map *entry,
                      struct netlbl_audit *audit_info);
 int netlbl_domhsh_add_default(struct netlbl_dom_map *entry,
                              struct netlbl_audit *audit_info);
+int netlbl_domhsh_remove(const char *domain, struct netlbl_audit *audit_info);
 int netlbl_domhsh_remove_default(struct netlbl_audit *audit_info);
 struct netlbl_dom_map *netlbl_domhsh_getentry(const char *domain);
 int netlbl_domhsh_walk(u32 *skip_bkt,
index c69e3e1f05c3957ab076a75bd84bc40a87a87578..39793a1a93aaba375a6bf7382081c245b197e38b 100644 (file)
@@ -30,6 +30,7 @@
 
 #include <linux/init.h>
 #include <linux/types.h>
+#include <linux/audit.h>
 #include <net/ip.h>
 #include <net/netlabel.h>
 #include <net/cipso_ipv4.h>
 
 #include "netlabel_domainhash.h"
 #include "netlabel_unlabeled.h"
+#include "netlabel_cipso_v4.h"
 #include "netlabel_user.h"
 #include "netlabel_mgmt.h"
 
+/*
+ * Configuration Functions
+ */
+
+/**
+ * netlbl_cfg_map_del - Remove a NetLabel/LSM domain mapping
+ * @domain: the domain mapping to remove
+ * @audit_info: NetLabel audit information
+ *
+ * Description:
+ * Removes a NetLabel/LSM domain mapping.  A @domain value of NULL causes the
+ * default domain mapping to be removed.  Returns zero on success, negative
+ * values on failure.
+ *
+ */
+int netlbl_cfg_map_del(const char *domain, struct netlbl_audit *audit_info)
+{
+       return netlbl_domhsh_remove(domain, audit_info);
+}
+
+/**
+ * netlbl_cfg_unlbl_add_map - Add an unlabeled NetLabel/LSM domain mapping
+ * @domain: the domain mapping to add
+ * @audit_info: NetLabel audit information
+ *
+ * Description:
+ * Adds a new unlabeled NetLabel/LSM domain mapping.  A @domain value of NULL
+ * causes a new default domain mapping to be added.  Returns zero on success,
+ * negative values on failure.
+ *
+ */
+int netlbl_cfg_unlbl_add_map(const char *domain,
+                            struct netlbl_audit *audit_info)
+{
+       int ret_val = -ENOMEM;
+       struct netlbl_dom_map *entry;
+
+       entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
+       if (entry == NULL)
+               goto cfg_unlbl_add_map_failure;
+       if (domain != NULL) {
+               entry->domain = kstrdup(domain, GFP_ATOMIC);
+               if (entry->domain == NULL)
+                       goto cfg_unlbl_add_map_failure;
+       }
+       entry->type = NETLBL_NLTYPE_UNLABELED;
+
+       ret_val = netlbl_domhsh_add(entry, audit_info);
+       if (ret_val != 0)
+               goto cfg_unlbl_add_map_failure;
+
+       return 0;
+
+cfg_unlbl_add_map_failure:
+       if (entry != NULL)
+               kfree(entry->domain);
+       kfree(entry);
+       return ret_val;
+}
+
+/**
+ * netlbl_cfg_cipsov4_add - Add a new CIPSOv4 DOI definition
+ * @doi_def: the DOI definition
+ * @audit_info: NetLabel audit information
+ *
+ * Description:
+ * Add a new CIPSOv4 DOI definition to the NetLabel subsystem.  Returns zero on
+ * success, negative values on failure.
+ *
+ */
+int netlbl_cfg_cipsov4_add(struct cipso_v4_doi *doi_def,
+                          struct netlbl_audit *audit_info)
+{
+       int ret_val;
+       const char *type_str;
+       struct audit_buffer *audit_buf;
+
+       ret_val = cipso_v4_doi_add(doi_def);
+
+       audit_buf = netlbl_audit_start_common(AUDIT_MAC_CIPSOV4_ADD,
+                                             audit_info);
+       if (audit_buf != NULL) {
+               switch (doi_def->type) {
+               case CIPSO_V4_MAP_STD:
+                       type_str = "std";
+                       break;
+               case CIPSO_V4_MAP_PASS:
+                       type_str = "pass";
+                       break;
+               default:
+                       type_str = "(unknown)";
+               }
+               audit_log_format(audit_buf,
+                                " cipso_doi=%u cipso_type=%s res=%u",
+                                doi_def->doi,
+                                type_str,
+                                ret_val == 0 ? 1 : 0);
+               audit_log_end(audit_buf);
+       }
+
+       return ret_val;
+}
+
+/**
+ * netlbl_cfg_cipsov4_add_map - Add a new CIPSOv4 DOI definition and mapping
+ * @doi_def: the DOI definition
+ * @domain: the domain mapping to add
+ * @audit_info: NetLabel audit information
+ *
+ * Description:
+ * Add a new CIPSOv4 DOI definition and NetLabel/LSM domain mapping for this
+ * new DOI definition to the NetLabel subsystem.  A @domain value of NULL adds
+ * a new default domain mapping.  Returns zero on success, negative values on
+ * failure.
+ *
+ */
+int netlbl_cfg_cipsov4_add_map(struct cipso_v4_doi *doi_def,
+                              const char *domain,
+                              struct netlbl_audit *audit_info)
+{
+       int ret_val = -ENOMEM;
+       struct netlbl_dom_map *entry;
+
+       entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
+       if (entry == NULL)
+               goto cfg_cipsov4_add_map_failure;
+       if (domain != NULL) {
+               entry->domain = kstrdup(domain, GFP_ATOMIC);
+               if (entry->domain == NULL)
+                       goto cfg_cipsov4_add_map_failure;
+       }
+       entry->type = NETLBL_NLTYPE_CIPSOV4;
+       entry->type_def.cipsov4 = doi_def;
+
+       /* Grab a RCU read lock here so nothing happens to the doi_def variable
+        * between adding it to the CIPSOv4 protocol engine and adding a
+        * domain mapping for it. */
+
+       rcu_read_lock();
+       ret_val = netlbl_cfg_cipsov4_add(doi_def, audit_info);
+       if (ret_val != 0)
+               goto cfg_cipsov4_add_map_failure_unlock;
+       ret_val = netlbl_domhsh_add(entry, audit_info);
+       if (ret_val != 0)
+               goto cfg_cipsov4_add_map_failure_remove_doi;
+       rcu_read_unlock();
+
+       return 0;
+
+cfg_cipsov4_add_map_failure_remove_doi:
+       cipso_v4_doi_remove(doi_def->doi, audit_info, netlbl_cipsov4_doi_free);
+cfg_cipsov4_add_map_failure_unlock:
+       rcu_read_unlock();
+cfg_cipsov4_add_map_failure:
+       if (entry != NULL)
+               kfree(entry->domain);
+       kfree(entry);
+       return ret_val;
+}
+
+/**
+ * netlbl_cfg_cipsov4_del - Removean existing CIPSOv4 DOI definition
+ * @doi: the CIPSO DOI value
+ * @audit_info: NetLabel audit information
+ *
+ * Description:
+ * Removes an existing CIPSOv4 DOI definition from the NetLabel subsystem.
+ * Returns zero on success, negative values on failure.
+ *
+ */
+int netlbl_cfg_cipsov4_del(u32 doi, struct netlbl_audit *audit_info)
+{
+       return cipso_v4_doi_remove(doi, audit_info, netlbl_cipsov4_doi_free);
+}
+
 /*
  * Security Attribute Functions
  */
index 6b178e1247b5c3672e3857486d2d1346903181c2..1ab0da2632e19c5a0a74546a67a3e9c4d11bbc50 100644 (file)
@@ -1238,7 +1238,7 @@ static int netlink_sendmsg(struct kiocb *kiocb, struct socket *sock,
 
        NETLINK_CB(skb).pid     = nlk->pid;
        NETLINK_CB(skb).dst_group = dst_group;
-       NETLINK_CB(skb).loginuid = audit_get_loginuid(current->audit_context);
+       NETLINK_CB(skb).loginuid = audit_get_loginuid(current);
        selinux_get_task_sid(current, &(NETLINK_CB(skb).sid));
        memcpy(NETLINK_CREDS(skb), &siocb->scm->creds, sizeof(struct ucred));
 
@@ -1344,6 +1344,22 @@ static void netlink_data_ready(struct sock *sk, int len)
  *     queueing.
  */
 
+static void __netlink_release(struct sock *sk)
+{
+       /*
+        * Last sock_put should drop referrence to sk->sk_net. It has already
+        * been dropped in netlink_kernel_create. Taking referrence to stopping
+        * namespace is not an option.
+        * Take referrence to a socket to remove it from netlink lookup table
+        * _alive_ and after that destroy it in the context of init_net.
+        */
+
+       sock_hold(sk);
+       sock_release(sk->sk_socket);
+       sk->sk_net = get_net(&init_net);
+       sock_put(sk);
+}
+
 struct sock *
 netlink_kernel_create(struct net *net, int unit, unsigned int groups,
                      void (*input)(struct sk_buff *skb),
@@ -1362,8 +1378,18 @@ netlink_kernel_create(struct net *net, int unit, unsigned int groups,
        if (sock_create_lite(PF_NETLINK, SOCK_DGRAM, unit, &sock))
                return NULL;
 
-       if (__netlink_create(net, sock, cb_mutex, unit) < 0)
-               goto out_sock_release;
+       /*
+        * We have to just have a reference on the net from sk, but don't
+        * get_net it. Besides, we cannot get and then put the net here.
+        * So we create one inside init_net and the move it to net.
+        */
+
+       if (__netlink_create(&init_net, sock, cb_mutex, unit) < 0)
+               goto out_sock_release_nosk;
+
+       sk = sock->sk;
+       put_net(sk->sk_net);
+       sk->sk_net = net;
 
        if (groups < 32)
                groups = 32;
@@ -1372,7 +1398,6 @@ netlink_kernel_create(struct net *net, int unit, unsigned int groups,
        if (!listeners)
                goto out_sock_release;
 
-       sk = sock->sk;
        sk->sk_data_ready = netlink_data_ready;
        if (input)
                nlk_sk(sk)->netlink_rcv = input;
@@ -1395,14 +1420,14 @@ netlink_kernel_create(struct net *net, int unit, unsigned int groups,
                nl_table[unit].registered++;
        }
        netlink_table_ungrab();
-
-       /* Do not hold an extra referrence to a namespace as this socket is
-        * internal to a namespace and does not prevent it to stop. */
-       put_net(net);
        return sk;
 
 out_sock_release:
        kfree(listeners);
+       __netlink_release(sk);
+       return NULL;
+
+out_sock_release_nosk:
        sock_release(sock);
        return NULL;
 }
@@ -1415,18 +1440,7 @@ netlink_kernel_release(struct sock *sk)
        if (sk == NULL || sk->sk_socket == NULL)
                return;
 
-       /*
-        * Last sock_put should drop referrence to sk->sk_net. It has already
-        * been dropped in netlink_kernel_create. Taking referrence to stopping
-        * namespace is not an option.
-        * Take referrence to a socket to remove it from netlink lookup table
-        * _alive_ and after that destroy it in the context of init_net.
-        */
-       sock_hold(sk);
-       sock_release(sk->sk_socket);
-
-       sk->sk_net = get_net(&init_net);
-       sock_put(sk);
+       __netlink_release(sk);
 }
 EXPORT_SYMBOL(netlink_kernel_release);
 
index d1e9d68f8ba0a003f0820f95800620d3030184cd..e4b051dbed612bc45726328f73a18c65ad81f87b 100644 (file)
@@ -84,6 +84,7 @@ static void rfkill_schedule_toggle(struct rfkill_task *task)
 static DEFINE_RFKILL_TASK(rfkill_wlan, RFKILL_TYPE_WLAN);
 static DEFINE_RFKILL_TASK(rfkill_bt, RFKILL_TYPE_BLUETOOTH);
 static DEFINE_RFKILL_TASK(rfkill_uwb, RFKILL_TYPE_UWB);
+static DEFINE_RFKILL_TASK(rfkill_wimax, RFKILL_TYPE_WIMAX);
 
 static void rfkill_event(struct input_handle *handle, unsigned int type,
                        unsigned int code, int down)
@@ -99,6 +100,9 @@ static void rfkill_event(struct input_handle *handle, unsigned int type,
                case KEY_UWB:
                        rfkill_schedule_toggle(&rfkill_uwb);
                        break;
+               case KEY_WIMAX:
+                       rfkill_schedule_toggle(&rfkill_wimax);
+                       break;
                default:
                        break;
                }
@@ -159,6 +163,11 @@ static const struct input_device_id rfkill_ids[] = {
                .evbit = { BIT_MASK(EV_KEY) },
                .keybit = { [BIT_WORD(KEY_UWB)] = BIT_MASK(KEY_UWB) },
        },
+       {
+               .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT,
+               .evbit = { BIT_MASK(EV_KEY) },
+               .keybit = { [BIT_WORD(KEY_WIMAX)] = BIT_MASK(KEY_WIMAX) },
+       },
        { }
 };
 
index d06d338812e975081ff20f771ea2c9069abede4c..1a47f5d1be17c42814d83f705bd375de497c2b80 100644 (file)
@@ -126,6 +126,9 @@ static ssize_t rfkill_type_show(struct device *dev,
        case RFKILL_TYPE_UWB:
                type = "ultrawideband";
                break;
+       case RFKILL_TYPE_WIMAX:
+               type = "wimax";
+               break;
        default:
                BUG();
        }
@@ -337,7 +340,7 @@ EXPORT_SYMBOL(rfkill_allocate);
  * rfkill_free - Mark rfkill structure for deletion
  * @rfkill: rfkill structure to be destroyed
  *
- * Decrements reference count of rfkill structure so it is destoryed.
+ * Decrements reference count of rfkill structure so it is destroyed.
  * Note that rfkill_free() should _not_ be called after rfkill_unregister().
  */
 void rfkill_free(struct rfkill *rfkill)
index 3c04b00dab74930075adc8fc225225a1c8d431a4..d9231245a79aba9b3331d2a81b6bfd90820d7fd9 100644 (file)
@@ -15,7 +15,7 @@
 #include <net/af_rxrpc.h>
 #include "ar-internal.h"
 
-const char *rxrpc_call_states[] = {
+const char *const rxrpc_call_states[] = {
        [RXRPC_CALL_CLIENT_SEND_REQUEST]        = "ClSndReq",
        [RXRPC_CALL_CLIENT_AWAIT_REPLY]         = "ClAwtRpl",
        [RXRPC_CALL_CLIENT_RECV_REPLY]          = "ClRcvRpl",
index 58aaf892238ea56f52dbbaef34ea5039536a838e..1aaa2e804b0d118a78d6f94f4491b64a347f0bc5 100644 (file)
@@ -565,9 +565,9 @@ extern void __exit rxrpc_destroy_all_peers(void);
 /*
  * ar-proc.c
  */
-extern const char *rxrpc_call_states[];
-extern struct file_operations rxrpc_call_seq_fops;
-extern struct file_operations rxrpc_connection_seq_fops;
+extern const char *const rxrpc_call_states[];
+extern const struct file_operations rxrpc_call_seq_fops;
+extern const struct file_operations rxrpc_connection_seq_fops;
 
 /*
  * ar-recvmsg.c
index 2e83ce325d151e090e05cc0c18e2de55cd82a04d..83eda247fe487b1d8499926122eab8a315acd107 100644 (file)
@@ -14,7 +14,7 @@
 #include <net/af_rxrpc.h>
 #include "ar-internal.h"
 
-static const char *rxrpc_conn_states[] = {
+static const char *const rxrpc_conn_states[] = {
        [RXRPC_CONN_UNUSED]             = "Unused  ",
        [RXRPC_CONN_CLIENT]             = "Client  ",
        [RXRPC_CONN_SERVER_UNSECURED]   = "SvUnsec ",
@@ -98,7 +98,7 @@ static int rxrpc_call_seq_open(struct inode *inode, struct file *file)
        return seq_open(file, &rxrpc_call_seq_ops);
 }
 
-struct file_operations rxrpc_call_seq_fops = {
+const struct file_operations rxrpc_call_seq_fops = {
        .owner          = THIS_MODULE,
        .open           = rxrpc_call_seq_open,
        .read           = seq_read,
@@ -183,7 +183,7 @@ static int rxrpc_connection_seq_open(struct inode *inode, struct file *file)
        return seq_open(file, &rxrpc_connection_seq_ops);
 }
 
-struct file_operations rxrpc_connection_seq_fops = {
+const struct file_operations rxrpc_connection_seq_fops = {
        .owner          = THIS_MODULE,
        .open           = rxrpc_connection_seq_open,
        .read           = seq_read,
index 87af7c913d815e470e55b9274206ec5e320b1f1c..82adfe6447d7db004c7108731e0ad4c7b87f8657 100644 (file)
@@ -198,7 +198,7 @@ config NET_SCH_NETEM
 
 config NET_SCH_INGRESS
        tristate "Ingress Qdisc"
-       depends on NET_CLS_ACT || NETFILTER
+       depends on NET_CLS_ACT
        ---help---
          Say Y here if you want to use classifiers for incoming packets.
          If unsure, say Y.
@@ -307,6 +307,17 @@ config NET_CLS_RSVP6
          To compile this code as a module, choose M here: the
          module will be called cls_rsvp6.
 
+config NET_CLS_FLOW
+       tristate "Flow classifier"
+       select NET_CLS
+       ---help---
+         If you say Y here, you will be able to classify packets based on
+         a configurable combination of packet keys. This is mostly useful
+         in combination with SFQ.
+
+         To compile this code as a module, choose M here: the
+         module will be called cls_flow.
+
 config NET_EMATCH
        bool "Extended Matches"
        select NET_CLS
index 81ecbe8e7dce66d85d239857c9ee981cf886d3af..1d2b0f7df8487bbfbb633230c7dffe998f8257eb 100644 (file)
@@ -35,6 +35,7 @@ obj-$(CONFIG_NET_CLS_RSVP)    += cls_rsvp.o
 obj-$(CONFIG_NET_CLS_TCINDEX)  += cls_tcindex.o
 obj-$(CONFIG_NET_CLS_RSVP6)    += cls_rsvp6.o
 obj-$(CONFIG_NET_CLS_BASIC)    += cls_basic.o
+obj-$(CONFIG_NET_CLS_FLOW)     += cls_flow.o
 obj-$(CONFIG_NET_EMATCH)       += ematch.o
 obj-$(CONFIG_NET_EMATCH_CMP)   += em_cmp.o
 obj-$(CONFIG_NET_EMATCH_NBYTE) += em_nbyte.o
index 3377ca0d0a0c8470bc13e539fb4047820ed20b85..0fbedcabf1110759c41117253ae7cc73d6f7a768 100644 (file)
@@ -482,7 +482,7 @@ EXPORT_SYMBOL(tcf_exts_destroy);
 
 int tcf_exts_validate(struct tcf_proto *tp, struct nlattr **tb,
                  struct nlattr *rate_tlv, struct tcf_exts *exts,
-                 struct tcf_ext_map *map)
+                 const struct tcf_ext_map *map)
 {
        memset(exts, 0, sizeof(*exts));
 
@@ -535,7 +535,7 @@ void tcf_exts_change(struct tcf_proto *tp, struct tcf_exts *dst,
 EXPORT_SYMBOL(tcf_exts_change);
 
 int tcf_exts_dump(struct sk_buff *skb, struct tcf_exts *exts,
-             struct tcf_ext_map *map)
+                 const struct tcf_ext_map *map)
 {
 #ifdef CONFIG_NET_CLS_ACT
        if (map->action && exts->action) {
@@ -571,7 +571,7 @@ EXPORT_SYMBOL(tcf_exts_dump);
 
 
 int tcf_exts_dump_stats(struct sk_buff *skb, struct tcf_exts *exts,
-                       struct tcf_ext_map *map)
+                       const struct tcf_ext_map *map)
 {
 #ifdef CONFIG_NET_CLS_ACT
        if (exts->action)
index bfb4342ea88cfe982e6ac1b77a36c891f9cda575..956915c217d6dbc8599b3fa8248eedb8914160a3 100644 (file)
@@ -35,7 +35,7 @@ struct basic_filter
        struct list_head        link;
 };
 
-static struct tcf_ext_map basic_ext_map = {
+static const struct tcf_ext_map basic_ext_map = {
        .action = TCA_BASIC_ACT,
        .police = TCA_BASIC_POLICE
 };
diff --git a/net/sched/cls_flow.c b/net/sched/cls_flow.c
new file mode 100644 (file)
index 0000000..8d76986
--- /dev/null
@@ -0,0 +1,660 @@
+/*
+ * net/sched/cls_flow.c                Generic flow classifier
+ *
+ * Copyright (c) 2007, 2008 Patrick McHardy <kaber@trash.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/jhash.h>
+#include <linux/random.h>
+#include <linux/pkt_cls.h>
+#include <linux/skbuff.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+
+#include <net/pkt_cls.h>
+#include <net/ip.h>
+#include <net/route.h>
+#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
+#include <net/netfilter/nf_conntrack.h>
+#endif
+
+struct flow_head {
+       struct list_head        filters;
+};
+
+struct flow_filter {
+       struct list_head        list;
+       struct tcf_exts         exts;
+       struct tcf_ematch_tree  ematches;
+       u32                     handle;
+
+       u32                     nkeys;
+       u32                     keymask;
+       u32                     mode;
+       u32                     mask;
+       u32                     xor;
+       u32                     rshift;
+       u32                     addend;
+       u32                     divisor;
+       u32                     baseclass;
+};
+
+static u32 flow_hashrnd __read_mostly;
+static int flow_hashrnd_initted __read_mostly;
+
+static const struct tcf_ext_map flow_ext_map = {
+       .action = TCA_FLOW_ACT,
+       .police = TCA_FLOW_POLICE,
+};
+
+static inline u32 addr_fold(void *addr)
+{
+       unsigned long a = (unsigned long)addr;
+
+       return (a & 0xFFFFFFFF) ^ (BITS_PER_LONG > 32 ? a >> 32 : 0);
+}
+
+static u32 flow_get_src(const struct sk_buff *skb)
+{
+       switch (skb->protocol) {
+       case __constant_htons(ETH_P_IP):
+               return ntohl(ip_hdr(skb)->saddr);
+       case __constant_htons(ETH_P_IPV6):
+               return ntohl(ipv6_hdr(skb)->saddr.s6_addr32[3]);
+       default:
+               return addr_fold(skb->sk);
+       }
+}
+
+static u32 flow_get_dst(const struct sk_buff *skb)
+{
+       switch (skb->protocol) {
+       case __constant_htons(ETH_P_IP):
+               return ntohl(ip_hdr(skb)->daddr);
+       case __constant_htons(ETH_P_IPV6):
+               return ntohl(ipv6_hdr(skb)->daddr.s6_addr32[3]);
+       default:
+               return addr_fold(skb->dst) ^ (__force u16)skb->protocol;
+       }
+}
+
+static u32 flow_get_proto(const struct sk_buff *skb)
+{
+       switch (skb->protocol) {
+       case __constant_htons(ETH_P_IP):
+               return ip_hdr(skb)->protocol;
+       case __constant_htons(ETH_P_IPV6):
+               return ipv6_hdr(skb)->nexthdr;
+       default:
+               return 0;
+       }
+}
+
+static int has_ports(u8 protocol)
+{
+       switch (protocol) {
+       case IPPROTO_TCP:
+       case IPPROTO_UDP:
+       case IPPROTO_UDPLITE:
+       case IPPROTO_SCTP:
+       case IPPROTO_DCCP:
+       case IPPROTO_ESP:
+               return 1;
+       default:
+               return 0;
+       }
+}
+
+static u32 flow_get_proto_src(const struct sk_buff *skb)
+{
+       u32 res = 0;
+
+       switch (skb->protocol) {
+       case __constant_htons(ETH_P_IP): {
+               struct iphdr *iph = ip_hdr(skb);
+
+               if (!(iph->frag_off&htons(IP_MF|IP_OFFSET)) &&
+                   has_ports(iph->protocol))
+                       res = ntohs(*(__be16 *)((void *)iph + iph->ihl * 4));
+               break;
+       }
+       case __constant_htons(ETH_P_IPV6): {
+               struct ipv6hdr *iph = ipv6_hdr(skb);
+
+               if (has_ports(iph->nexthdr))
+                       res = ntohs(*(__be16 *)&iph[1]);
+               break;
+       }
+       default:
+               res = addr_fold(skb->sk);
+       }
+
+       return res;
+}
+
+static u32 flow_get_proto_dst(const struct sk_buff *skb)
+{
+       u32 res = 0;
+
+       switch (skb->protocol) {
+       case __constant_htons(ETH_P_IP): {
+               struct iphdr *iph = ip_hdr(skb);
+
+               if (!(iph->frag_off&htons(IP_MF|IP_OFFSET)) &&
+                   has_ports(iph->protocol))
+                       res = ntohs(*(__be16 *)((void *)iph + iph->ihl * 4 + 2));
+               break;
+       }
+       case __constant_htons(ETH_P_IPV6): {
+               struct ipv6hdr *iph = ipv6_hdr(skb);
+
+               if (has_ports(iph->nexthdr))
+                       res = ntohs(*(__be16 *)((void *)&iph[1] + 2));
+               break;
+       }
+       default:
+               res = addr_fold(skb->dst) ^ (__force u16)skb->protocol;
+       }
+
+       return res;
+}
+
+static u32 flow_get_iif(const struct sk_buff *skb)
+{
+       return skb->iif;
+}
+
+static u32 flow_get_priority(const struct sk_buff *skb)
+{
+       return skb->priority;
+}
+
+static u32 flow_get_mark(const struct sk_buff *skb)
+{
+       return skb->mark;
+}
+
+static u32 flow_get_nfct(const struct sk_buff *skb)
+{
+#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
+       return addr_fold(skb->nfct);
+#else
+       return 0;
+#endif
+}
+
+#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
+#define CTTUPLE(skb, member)                                           \
+({                                                                     \
+       enum ip_conntrack_info ctinfo;                                  \
+       struct nf_conn *ct = nf_ct_get(skb, &ctinfo);                   \
+       if (ct == NULL)                                                 \
+               goto fallback;                                          \
+       ct->tuplehash[CTINFO2DIR(ctinfo)].tuple.member;                 \
+})
+#else
+#define CTTUPLE(skb, member)                                           \
+({                                                                     \
+       goto fallback;                                                  \
+       0;                                                              \
+})
+#endif
+
+static u32 flow_get_nfct_src(const struct sk_buff *skb)
+{
+       switch (skb->protocol) {
+       case __constant_htons(ETH_P_IP):
+               return ntohl(CTTUPLE(skb, src.u3.ip));
+       case __constant_htons(ETH_P_IPV6):
+               return ntohl(CTTUPLE(skb, src.u3.ip6[3]));
+       }
+fallback:
+       return flow_get_src(skb);
+}
+
+static u32 flow_get_nfct_dst(const struct sk_buff *skb)
+{
+       switch (skb->protocol) {
+       case __constant_htons(ETH_P_IP):
+               return ntohl(CTTUPLE(skb, dst.u3.ip));
+       case __constant_htons(ETH_P_IPV6):
+               return ntohl(CTTUPLE(skb, dst.u3.ip6[3]));
+       }
+fallback:
+       return flow_get_dst(skb);
+}
+
+static u32 flow_get_nfct_proto_src(const struct sk_buff *skb)
+{
+       return ntohs(CTTUPLE(skb, src.u.all));
+fallback:
+       return flow_get_proto_src(skb);
+}
+
+static u32 flow_get_nfct_proto_dst(const struct sk_buff *skb)
+{
+       return ntohs(CTTUPLE(skb, dst.u.all));
+fallback:
+       return flow_get_proto_dst(skb);
+}
+
+static u32 flow_get_rtclassid(const struct sk_buff *skb)
+{
+#ifdef CONFIG_NET_CLS_ROUTE
+       if (skb->dst)
+               return skb->dst->tclassid;
+#endif
+       return 0;
+}
+
+static u32 flow_get_skuid(const struct sk_buff *skb)
+{
+       if (skb->sk && skb->sk->sk_socket && skb->sk->sk_socket->file)
+               return skb->sk->sk_socket->file->f_uid;
+       return 0;
+}
+
+static u32 flow_get_skgid(const struct sk_buff *skb)
+{
+       if (skb->sk && skb->sk->sk_socket && skb->sk->sk_socket->file)
+               return skb->sk->sk_socket->file->f_gid;
+       return 0;
+}
+
+static u32 flow_key_get(const struct sk_buff *skb, int key)
+{
+       switch (key) {
+       case FLOW_KEY_SRC:
+               return flow_get_src(skb);
+       case FLOW_KEY_DST:
+               return flow_get_dst(skb);
+       case FLOW_KEY_PROTO:
+               return flow_get_proto(skb);
+       case FLOW_KEY_PROTO_SRC:
+               return flow_get_proto_src(skb);
+       case FLOW_KEY_PROTO_DST:
+               return flow_get_proto_dst(skb);
+       case FLOW_KEY_IIF:
+               return flow_get_iif(skb);
+       case FLOW_KEY_PRIORITY:
+               return flow_get_priority(skb);
+       case FLOW_KEY_MARK:
+               return flow_get_mark(skb);
+       case FLOW_KEY_NFCT:
+               return flow_get_nfct(skb);
+       case FLOW_KEY_NFCT_SRC:
+               return flow_get_nfct_src(skb);
+       case FLOW_KEY_NFCT_DST:
+               return flow_get_nfct_dst(skb);
+       case FLOW_KEY_NFCT_PROTO_SRC:
+               return flow_get_nfct_proto_src(skb);
+       case FLOW_KEY_NFCT_PROTO_DST:
+               return flow_get_nfct_proto_dst(skb);
+       case FLOW_KEY_RTCLASSID:
+               return flow_get_rtclassid(skb);
+       case FLOW_KEY_SKUID:
+               return flow_get_skuid(skb);
+       case FLOW_KEY_SKGID:
+               return flow_get_skgid(skb);
+       default:
+               WARN_ON(1);
+               return 0;
+       }
+}
+
+static int flow_classify(struct sk_buff *skb, struct tcf_proto *tp,
+                        struct tcf_result *res)
+{
+       struct flow_head *head = tp->root;
+       struct flow_filter *f;
+       u32 keymask;
+       u32 classid;
+       unsigned int n, key;
+       int r;
+
+       list_for_each_entry(f, &head->filters, list) {
+               u32 keys[f->nkeys];
+
+               if (!tcf_em_tree_match(skb, &f->ematches, NULL))
+                       continue;
+
+               keymask = f->keymask;
+
+               for (n = 0; n < f->nkeys; n++) {
+                       key = ffs(keymask) - 1;
+                       keymask &= ~(1 << key);
+                       keys[n] = flow_key_get(skb, key);
+               }
+
+               if (f->mode == FLOW_MODE_HASH)
+                       classid = jhash2(keys, f->nkeys, flow_hashrnd);
+               else {
+                       classid = keys[0];
+                       classid = (classid & f->mask) ^ f->xor;
+                       classid = (classid >> f->rshift) + f->addend;
+               }
+
+               if (f->divisor)
+                       classid %= f->divisor;
+
+               res->class   = 0;
+               res->classid = TC_H_MAKE(f->baseclass, f->baseclass + classid);
+
+               r = tcf_exts_exec(skb, &f->exts, res);
+               if (r < 0)
+                       continue;
+               return r;
+       }
+       return -1;
+}
+
+static const struct nla_policy flow_policy[TCA_FLOW_MAX + 1] = {
+       [TCA_FLOW_KEYS]         = { .type = NLA_U32 },
+       [TCA_FLOW_MODE]         = { .type = NLA_U32 },
+       [TCA_FLOW_BASECLASS]    = { .type = NLA_U32 },
+       [TCA_FLOW_RSHIFT]       = { .type = NLA_U32 },
+       [TCA_FLOW_ADDEND]       = { .type = NLA_U32 },
+       [TCA_FLOW_MASK]         = { .type = NLA_U32 },
+       [TCA_FLOW_XOR]          = { .type = NLA_U32 },
+       [TCA_FLOW_DIVISOR]      = { .type = NLA_U32 },
+       [TCA_FLOW_ACT]          = { .type = NLA_NESTED },
+       [TCA_FLOW_POLICE]       = { .type = NLA_NESTED },
+       [TCA_FLOW_EMATCHES]     = { .type = NLA_NESTED },
+};
+
+static int flow_change(struct tcf_proto *tp, unsigned long base,
+                      u32 handle, struct nlattr **tca,
+                      unsigned long *arg)
+{
+       struct flow_head *head = tp->root;
+       struct flow_filter *f;
+       struct nlattr *opt = tca[TCA_OPTIONS];
+       struct nlattr *tb[TCA_FLOW_MAX + 1];
+       struct tcf_exts e;
+       struct tcf_ematch_tree t;
+       unsigned int nkeys = 0;
+       u32 baseclass = 0;
+       u32 keymask = 0;
+       u32 mode;
+       int err;
+
+       if (opt == NULL)
+               return -EINVAL;
+
+       err = nla_parse_nested(tb, TCA_FLOW_MAX, opt, flow_policy);
+       if (err < 0)
+               return err;
+
+       if (tb[TCA_FLOW_BASECLASS]) {
+               baseclass = nla_get_u32(tb[TCA_FLOW_BASECLASS]);
+               if (TC_H_MIN(baseclass) == 0)
+                       return -EINVAL;
+       }
+
+       if (tb[TCA_FLOW_KEYS]) {
+               keymask = nla_get_u32(tb[TCA_FLOW_KEYS]);
+               if (fls(keymask) - 1 > FLOW_KEY_MAX)
+                       return -EOPNOTSUPP;
+
+               nkeys = hweight32(keymask);
+               if (nkeys == 0)
+                       return -EINVAL;
+       }
+
+       err = tcf_exts_validate(tp, tb, tca[TCA_RATE], &e, &flow_ext_map);
+       if (err < 0)
+               return err;
+
+       err = tcf_em_tree_validate(tp, tb[TCA_FLOW_EMATCHES], &t);
+       if (err < 0)
+               goto err1;
+
+       f = (struct flow_filter *)*arg;
+       if (f != NULL) {
+               err = -EINVAL;
+               if (f->handle != handle && handle)
+                       goto err2;
+
+               mode = f->mode;
+               if (tb[TCA_FLOW_MODE])
+                       mode = nla_get_u32(tb[TCA_FLOW_MODE]);
+               if (mode != FLOW_MODE_HASH && nkeys > 1)
+                       goto err2;
+       } else {
+               err = -EINVAL;
+               if (!handle)
+                       goto err2;
+               if (!tb[TCA_FLOW_KEYS])
+                       goto err2;
+
+               mode = FLOW_MODE_MAP;
+               if (tb[TCA_FLOW_MODE])
+                       mode = nla_get_u32(tb[TCA_FLOW_MODE]);
+               if (mode != FLOW_MODE_HASH && nkeys > 1)
+                       goto err2;
+
+               if (TC_H_MAJ(baseclass) == 0)
+                       baseclass = TC_H_MAKE(tp->q->handle, baseclass);
+               if (TC_H_MIN(baseclass) == 0)
+                       baseclass = TC_H_MAKE(baseclass, 1);
+
+               err = -ENOBUFS;
+               f = kzalloc(sizeof(*f), GFP_KERNEL);
+               if (f == NULL)
+                       goto err2;
+
+               f->handle = handle;
+               f->mask   = ~0U;
+       }
+
+       tcf_exts_change(tp, &f->exts, &e);
+       tcf_em_tree_change(tp, &f->ematches, &t);
+
+       tcf_tree_lock(tp);
+
+       if (tb[TCA_FLOW_KEYS]) {
+               f->keymask = keymask;
+               f->nkeys   = nkeys;
+       }
+
+       f->mode = mode;
+
+       if (tb[TCA_FLOW_MASK])
+               f->mask = nla_get_u32(tb[TCA_FLOW_MASK]);
+       if (tb[TCA_FLOW_XOR])
+               f->xor = nla_get_u32(tb[TCA_FLOW_XOR]);
+       if (tb[TCA_FLOW_RSHIFT])
+               f->rshift = nla_get_u32(tb[TCA_FLOW_RSHIFT]);
+       if (tb[TCA_FLOW_ADDEND])
+               f->addend = nla_get_u32(tb[TCA_FLOW_ADDEND]);
+
+       if (tb[TCA_FLOW_DIVISOR])
+               f->divisor = nla_get_u32(tb[TCA_FLOW_DIVISOR]);
+       if (baseclass)
+               f->baseclass = baseclass;
+
+       if (*arg == 0)
+               list_add_tail(&f->list, &head->filters);
+
+       tcf_tree_unlock(tp);
+
+       *arg = (unsigned long)f;
+       return 0;
+
+err2:
+       tcf_em_tree_destroy(tp, &t);
+err1:
+       tcf_exts_destroy(tp, &e);
+       return err;
+}
+
+static void flow_destroy_filter(struct tcf_proto *tp, struct flow_filter *f)
+{
+       tcf_exts_destroy(tp, &f->exts);
+       tcf_em_tree_destroy(tp, &f->ematches);
+       kfree(f);
+}
+
+static int flow_delete(struct tcf_proto *tp, unsigned long arg)
+{
+       struct flow_filter *f = (struct flow_filter *)arg;
+
+       tcf_tree_lock(tp);
+       list_del(&f->list);
+       tcf_tree_unlock(tp);
+       flow_destroy_filter(tp, f);
+       return 0;
+}
+
+static int flow_init(struct tcf_proto *tp)
+{
+       struct flow_head *head;
+
+       if (!flow_hashrnd_initted) {
+               get_random_bytes(&flow_hashrnd, 4);
+               flow_hashrnd_initted = 1;
+       }
+
+       head = kzalloc(sizeof(*head), GFP_KERNEL);
+       if (head == NULL)
+               return -ENOBUFS;
+       INIT_LIST_HEAD(&head->filters);
+       tp->root = head;
+       return 0;
+}
+
+static void flow_destroy(struct tcf_proto *tp)
+{
+       struct flow_head *head = tp->root;
+       struct flow_filter *f, *next;
+
+       list_for_each_entry_safe(f, next, &head->filters, list) {
+               list_del(&f->list);
+               flow_destroy_filter(tp, f);
+       }
+       kfree(head);
+}
+
+static unsigned long flow_get(struct tcf_proto *tp, u32 handle)
+{
+       struct flow_head *head = tp->root;
+       struct flow_filter *f;
+
+       list_for_each_entry(f, &head->filters, list)
+               if (f->handle == handle)
+                       return (unsigned long)f;
+       return 0;
+}
+
+static void flow_put(struct tcf_proto *tp, unsigned long f)
+{
+       return;
+}
+
+static int flow_dump(struct tcf_proto *tp, unsigned long fh,
+                    struct sk_buff *skb, struct tcmsg *t)
+{
+       struct flow_filter *f = (struct flow_filter *)fh;
+       struct nlattr *nest;
+
+       if (f == NULL)
+               return skb->len;
+
+       t->tcm_handle = f->handle;
+
+       nest = nla_nest_start(skb, TCA_OPTIONS);
+       if (nest == NULL)
+               goto nla_put_failure;
+
+       NLA_PUT_U32(skb, TCA_FLOW_KEYS, f->keymask);
+       NLA_PUT_U32(skb, TCA_FLOW_MODE, f->mode);
+
+       if (f->mask != ~0 || f->xor != 0) {
+               NLA_PUT_U32(skb, TCA_FLOW_MASK, f->mask);
+               NLA_PUT_U32(skb, TCA_FLOW_XOR, f->xor);
+       }
+       if (f->rshift)
+               NLA_PUT_U32(skb, TCA_FLOW_RSHIFT, f->rshift);
+       if (f->addend)
+               NLA_PUT_U32(skb, TCA_FLOW_ADDEND, f->addend);
+
+       if (f->divisor)
+               NLA_PUT_U32(skb, TCA_FLOW_DIVISOR, f->divisor);
+       if (f->baseclass)
+               NLA_PUT_U32(skb, TCA_FLOW_BASECLASS, f->baseclass);
+
+       if (tcf_exts_dump(skb, &f->exts, &flow_ext_map) < 0)
+               goto nla_put_failure;
+#ifdef CONFIG_NET_EMATCH
+       if (f->ematches.hdr.nmatches &&
+           tcf_em_tree_dump(skb, &f->ematches, TCA_FLOW_EMATCHES) < 0)
+               goto nla_put_failure;
+#endif
+       nla_nest_end(skb, nest);
+
+       if (tcf_exts_dump_stats(skb, &f->exts, &flow_ext_map) < 0)
+               goto nla_put_failure;
+
+       return skb->len;
+
+nla_put_failure:
+       nlmsg_trim(skb, nest);
+       return -1;
+}
+
+static void flow_walk(struct tcf_proto *tp, struct tcf_walker *arg)
+{
+       struct flow_head *head = tp->root;
+       struct flow_filter *f;
+
+       list_for_each_entry(f, &head->filters, list) {
+               if (arg->count < arg->skip)
+                       goto skip;
+               if (arg->fn(tp, (unsigned long)f, arg) < 0) {
+                       arg->stop = 1;
+                       break;
+               }
+skip:
+               arg->count++;
+       }
+}
+
+static struct tcf_proto_ops cls_flow_ops __read_mostly = {
+       .kind           = "flow",
+       .classify       = flow_classify,
+       .init           = flow_init,
+       .destroy        = flow_destroy,
+       .change         = flow_change,
+       .delete         = flow_delete,
+       .get            = flow_get,
+       .put            = flow_put,
+       .dump           = flow_dump,
+       .walk           = flow_walk,
+       .owner          = THIS_MODULE,
+};
+
+static int __init cls_flow_init(void)
+{
+       return register_tcf_proto_ops(&cls_flow_ops);
+}
+
+static void __exit cls_flow_exit(void)
+{
+       unregister_tcf_proto_ops(&cls_flow_ops);
+}
+
+module_init(cls_flow_init);
+module_exit(cls_flow_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
+MODULE_DESCRIPTION("TC flow classifier");
index 436a6e7c438e2c8484d130ced225bf590e55e267..b0f90e593af0d510b6e61db352a8db9602830311 100644 (file)
@@ -47,7 +47,7 @@ struct fw_filter
        struct tcf_exts         exts;
 };
 
-static struct tcf_ext_map fw_ext_map = {
+static const struct tcf_ext_map fw_ext_map = {
        .action = TCA_FW_ACT,
        .police = TCA_FW_POLICE
 };
index f7e7d3955d289f5cd5585bc06bbc9285e56a9834..784dcb870b98181032e2b40d7a37ab3a60445eb1 100644 (file)
@@ -62,7 +62,7 @@ struct route4_filter
 
 #define ROUTE4_FAILURE ((struct route4_filter*)(-1L))
 
-static struct tcf_ext_map route_ext_map = {
+static const struct tcf_ext_map route_ext_map = {
        .police = TCA_ROUTE4_POLICE,
        .action = TCA_ROUTE4_ACT
 };
index ee60b2d1705de6b90a9c1f4dbe29436535a10f47..7a7bff5ded2487801e3c34941c1e12b8d77926fc 100644 (file)
@@ -55,7 +55,7 @@ struct tcindex_data {
        int fall_through;       /* 0: only classify if explicit match */
 };
 
-static struct tcf_ext_map tcindex_ext_map = {
+static const struct tcf_ext_map tcindex_ext_map = {
        .police = TCA_TCINDEX_POLICE,
        .action = TCA_TCINDEX_ACT
 };
index e8a7756891234dd2f74e23fbb3cc608ec77241da..b18fa95ef248e78f8a898248fa3466970b9f820d 100644 (file)
@@ -82,7 +82,7 @@ struct tc_u_common
        u32                     hgenerator;
 };
 
-static struct tcf_ext_map u32_ext_map = {
+static const struct tcf_ext_map u32_ext_map = {
        .action = TCA_U32_ACT,
        .police = TCA_U32_POLICE
 };
index a1e5619b1876c8477c85a07936f85806159ea290..9c2ec1992a2a0f8a95d21957c1171ab06f59959c 100644 (file)
@@ -65,6 +65,7 @@
 #include <linux/string.h>
 #include <linux/skbuff.h>
 #include <linux/random.h>
+#include <linux/if_vlan.h>
 #include <linux/tc_ematch/tc_em_meta.h>
 #include <net/dst.h>
 #include <net/route.h>
@@ -169,6 +170,21 @@ META_COLLECTOR(var_dev)
        *err = var_dev(skb->dev, dst);
 }
 
+/**************************************************************************
+ * vlan tag
+ **************************************************************************/
+
+META_COLLECTOR(int_vlan_tag)
+{
+       unsigned short tag;
+       if (vlan_get_tag(skb, &tag) < 0)
+               *err = -1;
+       else
+               dst->value = tag;
+}
+
+
+
 /**************************************************************************
  * skb attributes
  **************************************************************************/
@@ -520,6 +536,7 @@ static struct meta_ops __meta_ops[TCF_META_TYPE_MAX+1][TCF_META_ID_MAX+1] = {
                [META_ID(SK_SNDTIMEO)]          = META_FUNC(int_sk_sndtimeo),
                [META_ID(SK_SENDMSG_OFF)]       = META_FUNC(int_sk_sendmsg_off),
                [META_ID(SK_WRITE_PENDING)]     = META_FUNC(int_sk_write_pend),
+               [META_ID(VLAN_TAG)]             = META_FUNC(int_vlan_tag),
        }
 };
 
index 3f72d528273cc4f5a7ff9664d623a428ed718324..274b1ddb160c3956da169dd1bbc7da5e5f482637 100644 (file)
 #include <linux/list.h>
 #include <linux/skbuff.h>
 #include <linux/rtnetlink.h>
-#include <linux/netfilter_ipv4.h>
-#include <linux/netfilter_ipv6.h>
-#include <linux/netfilter.h>
 #include <net/netlink.h>
 #include <net/pkt_sched.h>
 
 
-/* Thanks to Doron Oz for this hack */
-#if !defined(CONFIG_NET_CLS_ACT) && defined(CONFIG_NETFILTER)
-static int nf_registered;
-#endif
-
 struct ingress_qdisc_data {
        struct tcf_proto        *filter_list;
 };
@@ -84,11 +76,6 @@ static int ingress_enqueue(struct sk_buff *skb, struct Qdisc *sch)
 
        result = tc_classify(skb, p->filter_list, &res);
 
-       /*
-        * Unlike normal "enqueue" functions, ingress_enqueue returns a
-        * firewall FW_* code.
-        */
-#ifdef CONFIG_NET_CLS_ACT
        sch->bstats.packets++;
        sch->bstats.bytes += skb->len;
        switch (result) {
@@ -107,71 +94,10 @@ static int ingress_enqueue(struct sk_buff *skb, struct Qdisc *sch)
                result = TC_ACT_OK;
                break;
        }
-#else
-       result = NF_ACCEPT;
-       sch->bstats.packets++;
-       sch->bstats.bytes += skb->len;
-#endif
 
        return result;
 }
 
-#if !defined(CONFIG_NET_CLS_ACT) && defined(CONFIG_NETFILTER)
-static unsigned int ing_hook(unsigned int hook, struct sk_buff *skb,
-                            const struct net_device *indev,
-                            const struct net_device *outdev,
-                            int (*okfn)(struct sk_buff *))
-{
-
-       struct Qdisc *q;
-       struct net_device *dev = skb->dev;
-       int fwres = NF_ACCEPT;
-
-       if (dev->qdisc_ingress) {
-               spin_lock(&dev->ingress_lock);
-               if ((q = dev->qdisc_ingress) != NULL)
-                       fwres = q->enqueue(skb, q);
-               spin_unlock(&dev->ingress_lock);
-       }
-
-       return fwres;
-}
-
-/* after ipt_filter */
-static struct nf_hook_ops ing_ops[] __read_mostly = {
-       {
-               .hook           = ing_hook,
-               .owner          = THIS_MODULE,
-               .pf             = PF_INET,
-               .hooknum        = NF_INET_PRE_ROUTING,
-               .priority       = NF_IP_PRI_FILTER + 1,
-       },
-       {
-               .hook           = ing_hook,
-               .owner          = THIS_MODULE,
-               .pf             = PF_INET6,
-               .hooknum        = NF_INET_PRE_ROUTING,
-               .priority       = NF_IP6_PRI_FILTER + 1,
-       },
-};
-#endif
-
-static int ingress_init(struct Qdisc *sch, struct nlattr *opt)
-{
-#if !defined(CONFIG_NET_CLS_ACT) && defined(CONFIG_NETFILTER)
-       printk("Ingress scheduler: Classifier actions prefered over netfilter\n");
-
-       if (!nf_registered) {
-               if (nf_register_hooks(ing_ops, ARRAY_SIZE(ing_ops)) < 0) {
-                       printk("ingress qdisc registration error \n");
-                       return -EINVAL;
-               }
-               nf_registered++;
-       }
-#endif
-       return 0;
-}
-
 /* ------------------------------------------------------------- */
 
 static void ingress_destroy(struct Qdisc *sch)
@@ -213,7 +139,6 @@ static struct Qdisc_ops ingress_qdisc_ops __read_mostly = {
        .id             =       "ingress",
        .priv_size      =       sizeof(struct ingress_qdisc_data),
        .enqueue        =       ingress_enqueue,
-       .init           =       ingress_init,
        .destroy        =       ingress_destroy,
        .dump           =       ingress_dump,
        .owner          =       THIS_MODULE,
@@ -227,10 +152,6 @@ static int __init ingress_module_init(void)
 static void __exit ingress_module_exit(void)
 {
        unregister_qdisc(&ingress_qdisc_ops);
-#if !defined(CONFIG_NET_CLS_ACT) && defined(CONFIG_NETFILTER)
-       if (nf_registered)
-               nf_unregister_hooks(ing_ops, ARRAY_SIZE(ing_ops));
-#endif
 }
 
 module_init(ingress_module_init)
index 91af539ab6e69f972eb3edcea0aab2fdee6c516e..a20e2ef7704beb4142dc3ee75d67604bffa10a10 100644 (file)
@@ -95,6 +95,7 @@ struct sfq_sched_data
        int             limit;
 
 /* Variables */
+       struct tcf_proto *filter_list;
        struct timer_list perturb_timer;
        u32             perturbation;
        sfq_index       tail;           /* Index of current slot in round */
@@ -155,6 +156,39 @@ static unsigned sfq_hash(struct sfq_sched_data *q, struct sk_buff *skb)
        return sfq_fold_hash(q, h, h2);
 }
 
+static unsigned int sfq_classify(struct sk_buff *skb, struct Qdisc *sch,
+                                int *qerr)
+{
+       struct sfq_sched_data *q = qdisc_priv(sch);
+       struct tcf_result res;
+       int result;
+
+       if (TC_H_MAJ(skb->priority) == sch->handle &&
+           TC_H_MIN(skb->priority) > 0 &&
+           TC_H_MIN(skb->priority) <= SFQ_HASH_DIVISOR)
+               return TC_H_MIN(skb->priority);
+
+       if (!q->filter_list)
+               return sfq_hash(q, skb) + 1;
+
+       *qerr = NET_XMIT_BYPASS;
+       result = tc_classify(skb, q->filter_list, &res);
+       if (result >= 0) {
+#ifdef CONFIG_NET_CLS_ACT
+               switch (result) {
+               case TC_ACT_STOLEN:
+               case TC_ACT_QUEUED:
+                       *qerr = NET_XMIT_SUCCESS;
+               case TC_ACT_SHOT:
+                       return 0;
+               }
+#endif
+               if (TC_H_MIN(res.classid) <= SFQ_HASH_DIVISOR)
+                       return TC_H_MIN(res.classid);
+       }
+       return 0;
+}
+
 static inline void sfq_link(struct sfq_sched_data *q, sfq_index x)
 {
        sfq_index p, n;
@@ -245,8 +279,18 @@ static int
 sfq_enqueue(struct sk_buff *skb, struct Qdisc *sch)
 {
        struct sfq_sched_data *q = qdisc_priv(sch);
-       unsigned hash = sfq_hash(q, skb);
+       unsigned int hash;
        sfq_index x;
+       int ret;
+
+       hash = sfq_classify(skb, sch, &ret);
+       if (hash == 0) {
+               if (ret == NET_XMIT_BYPASS)
+                       sch->qstats.drops++;
+               kfree_skb(skb);
+               return ret;
+       }
+       hash--;
 
        x = q->ht[hash];
        if (x == SFQ_DEPTH) {
@@ -289,8 +333,18 @@ static int
 sfq_requeue(struct sk_buff *skb, struct Qdisc *sch)
 {
        struct sfq_sched_data *q = qdisc_priv(sch);
-       unsigned hash = sfq_hash(q, skb);
+       unsigned int hash;
        sfq_index x;
+       int ret;
+
+       hash = sfq_classify(skb, sch, &ret);
+       if (hash == 0) {
+               if (ret == NET_XMIT_BYPASS)
+                       sch->qstats.drops++;
+               kfree_skb(skb);
+               return ret;
+       }
+       hash--;
 
        x = q->ht[hash];
        if (x == SFQ_DEPTH) {
@@ -465,6 +519,8 @@ static int sfq_init(struct Qdisc *sch, struct nlattr *opt)
 static void sfq_destroy(struct Qdisc *sch)
 {
        struct sfq_sched_data *q = qdisc_priv(sch);
+
+       tcf_destroy_chain(q->filter_list);
        del_timer(&q->perturb_timer);
 }
 
@@ -490,9 +546,79 @@ nla_put_failure:
        return -1;
 }
 
+static int sfq_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
+                           struct nlattr **tca, unsigned long *arg)
+{
+       return -EOPNOTSUPP;
+}
+
+static unsigned long sfq_get(struct Qdisc *sch, u32 classid)
+{
+       return 0;
+}
+
+static struct tcf_proto **sfq_find_tcf(struct Qdisc *sch, unsigned long cl)
+{
+       struct sfq_sched_data *q = qdisc_priv(sch);
+
+       if (cl)
+               return NULL;
+       return &q->filter_list;
+}
+
+static int sfq_dump_class(struct Qdisc *sch, unsigned long cl,
+                         struct sk_buff *skb, struct tcmsg *tcm)
+{
+       tcm->tcm_handle |= TC_H_MIN(cl);
+       return 0;
+}
+
+static int sfq_dump_class_stats(struct Qdisc *sch, unsigned long cl,
+                               struct gnet_dump *d)
+{
+       struct sfq_sched_data *q = qdisc_priv(sch);
+       sfq_index idx = q->ht[cl-1];
+       struct gnet_stats_queue qs = { .qlen = q->qs[idx].qlen };
+       struct tc_sfq_xstats xstats = { .allot = q->allot[idx] };
+
+       if (gnet_stats_copy_queue(d, &qs) < 0)
+               return -1;
+       return gnet_stats_copy_app(d, &xstats, sizeof(xstats));
+}
+
+static void sfq_walk(struct Qdisc *sch, struct qdisc_walker *arg)
+{
+       struct sfq_sched_data *q = qdisc_priv(sch);
+       unsigned int i;
+
+       if (arg->stop)
+               return;
+
+       for (i = 0; i < SFQ_HASH_DIVISOR; i++) {
+               if (q->ht[i] == SFQ_DEPTH ||
+                   arg->count < arg->skip) {
+                       arg->count++;
+                       continue;
+               }
+               if (arg->fn(sch, i + 1, arg) < 0) {
+                       arg->stop = 1;
+                       break;
+               }
+               arg->count++;
+       }
+}
+
+static const struct Qdisc_class_ops sfq_class_ops = {
+       .get            =       sfq_get,
+       .change         =       sfq_change_class,
+       .tcf_chain      =       sfq_find_tcf,
+       .dump           =       sfq_dump_class,
+       .dump_stats     =       sfq_dump_class_stats,
+       .walk           =       sfq_walk,
+};
+
 static struct Qdisc_ops sfq_qdisc_ops __read_mostly = {
-       .next           =       NULL,
-       .cl_ops         =       NULL,
+       .cl_ops         =       &sfq_class_ops,
        .id             =       "sfq",
        .priv_size      =       sizeof(struct sfq_sched_data),
        .enqueue        =       sfq_enqueue,
index 1411c7b1fbdc4de0f7103cfb559a78369a4195cc..0444fd0f0d2298228934a6f06ca54913f3280b8b 100644 (file)
@@ -71,7 +71,7 @@ struct teql_sched_data
 
 #define NEXT_SLAVE(q) (((struct teql_sched_data*)qdisc_priv(q))->next)
 
-#define FMASK (IFF_BROADCAST|IFF_POINTOPOINT|IFF_BROADCAST)
+#define FMASK (IFF_BROADCAST|IFF_POINTOPOINT)
 
 /* "teql*" qdisc routines */
 
index 97e6ebd145001e9b642fcf59d882714fa814e53e..ae367c82e51239101c915996643bd46638e3de73 100644 (file)
@@ -420,15 +420,15 @@ struct sctp_shared_key *sctp_auth_get_shkey(
                                const struct sctp_association *asoc,
                                __u16 key_id)
 {
-       struct sctp_shared_key *key = NULL;
+       struct sctp_shared_key *key;
 
        /* First search associations set of endpoint pair shared keys */
        key_for_each(key, &asoc->endpoint_shared_keys) {
                if (key->key_id == key_id)
-                       break;
+                       return key;
        }
 
-       return key;
+       return NULL;
 }
 
 /*
index dd98763c8b006de560201e454b5003d1197df828..77383e9b398833e698ad3ab72597160250451443 100644 (file)
@@ -2056,7 +2056,7 @@ static sctp_ierror_t sctp_verify_param(const struct sctp_association *asoc,
                break;
 
        case SCTP_PARAM_HMAC_ALGO:
-               if (!sctp_auth_enable)
+               if (sctp_auth_enable)
                        break;
                /* Fall Through */
 fallthrough:
index 61cbd5a8dd0c4954c212cacaf7f46f403ca1408b..f98658782d4fc6cf26759c3a55de11caa71b274a 100644 (file)
@@ -537,7 +537,7 @@ sctp_disposition_t sctp_sf_do_5_1C_ack(const struct sctp_endpoint *ep,
                 *
                 * This means that if we only want to abort associations
                 * in an authenticated way (i.e AUTH+ABORT), then we
-                * can't destory this association just becuase the packet
+                * can't destroy this association just becuase the packet
                 * was malformed.
                 */
                if (sctp_auth_recv_cid(SCTP_CID_ABORT, asoc))
@@ -3865,6 +3865,10 @@ sctp_disposition_t sctp_sf_eat_auth(const struct sctp_endpoint *ep,
        struct sctp_chunk *err_chunk;
        sctp_ierror_t error;
 
+       /* Make sure that the peer has AUTH capable */
+       if (!asoc->peer.auth_capable)
+               return sctp_sf_unk_chunk(ep, asoc, type, arg, commands);
+
        if (!sctp_vtag_verify(chunk, asoc)) {
                sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_BAD_TAG,
                                SCTP_NULL());
@@ -4130,7 +4134,7 @@ static sctp_disposition_t sctp_sf_abort_violation(
         *
         * This means that if we only want to abort associations
         * in an authenticated way (i.e AUTH+ABORT), then we
-        * can't destory this association just becuase the packet
+        * can't destroy this association just becuase the packet
         * was malformed.
         */
        if (sctp_auth_recv_cid(SCTP_CID_ABORT, asoc))
index 5c69a725e530b825b9cef83cbbd495b309c184b0..92e1dbe50947adb5d2612f1070362cc6f30d352e 100644 (file)
@@ -11,6 +11,7 @@ sunrpc-y := clnt.o xprt.o socklib.o xprtsock.o sched.o \
            auth.o auth_null.o auth_unix.o \
            svc.o svcsock.o svcauth.o svcauth_unix.o \
            rpcb_clnt.o timer.o xdr.o \
-           sunrpc_syms.o cache.o rpc_pipe.o
+           sunrpc_syms.o cache.o rpc_pipe.o \
+           svc_xprt.o
 sunrpc-$(CONFIG_PROC_FS) += stats.o
 sunrpc-$(CONFIG_SYSCTL) += sysctl.o
index bcd9abdb031c49a4473b75294d44ae2b2d6c02ac..eca941ce298b6465507c2f672dc5bf44350fffe6 100644 (file)
@@ -385,7 +385,6 @@ rpcauth_bindcred(struct rpc_task *task)
                .group_info = current->group_info,
        };
        struct rpc_cred *ret;
-       sigset_t oldset;
        int flags = 0;
 
        dprintk("RPC: %5u looking up %s cred\n",
@@ -393,9 +392,7 @@ rpcauth_bindcred(struct rpc_task *task)
        get_group_info(acred.group_info);
        if (task->tk_flags & RPC_TASK_ROOTCREDS)
                flags |= RPCAUTH_LOOKUP_ROOTCREDS;
-       rpc_clnt_sigmask(task->tk_client, &oldset);
        ret = auth->au_ops->lookup_cred(auth, &acred, flags);
-       rpc_clnt_sigunmask(task->tk_client, &oldset);
        if (!IS_ERR(ret))
                task->tk_msg.rpc_cred = ret;
        else
index 73940df6c460c210d15e9f3c42c3a7b52a2694c7..481f984e9a22278bc9ef1993bc3064c77fc65a51 100644 (file)
@@ -224,38 +224,34 @@ static int rsi_parse(struct cache_detail *cd,
 
        /* major/minor */
        len = qword_get(&mesg, buf, mlen);
-       if (len < 0)
+       if (len <= 0)
                goto out;
-       if (len == 0) {
+       rsii.major_status = simple_strtoul(buf, &ep, 10);
+       if (*ep)
+               goto out;
+       len = qword_get(&mesg, buf, mlen);
+       if (len <= 0)
+               goto out;
+       rsii.minor_status = simple_strtoul(buf, &ep, 10);
+       if (*ep)
                goto out;
-       } else {
-               rsii.major_status = simple_strtoul(buf, &ep, 10);
-               if (*ep)
-                       goto out;
-               len = qword_get(&mesg, buf, mlen);
-               if (len <= 0)
-                       goto out;
-               rsii.minor_status = simple_strtoul(buf, &ep, 10);
-               if (*ep)
-                       goto out;
 
-               /* out_handle */
-               len = qword_get(&mesg, buf, mlen);
-               if (len < 0)
-                       goto out;
-               status = -ENOMEM;
-               if (dup_to_netobj(&rsii.out_handle, buf, len))
-                       goto out;
+       /* out_handle */
+       len = qword_get(&mesg, buf, mlen);
+       if (len < 0)
+               goto out;
+       status = -ENOMEM;
+       if (dup_to_netobj(&rsii.out_handle, buf, len))
+               goto out;
 
-               /* out_token */
-               len = qword_get(&mesg, buf, mlen);
-               status = -EINVAL;
-               if (len < 0)
-                       goto out;
-               status = -ENOMEM;
-               if (dup_to_netobj(&rsii.out_token, buf, len))
-                       goto out;
-       }
+       /* out_token */
+       len = qword_get(&mesg, buf, mlen);
+       status = -EINVAL;
+       if (len < 0)
+               goto out;
+       status = -ENOMEM;
+       if (dup_to_netobj(&rsii.out_token, buf, len))
+               goto out;
        rsii.h.expiry_time = expiry;
        rsip = rsi_update(&rsii, rsip);
        status = 0;
@@ -975,6 +971,7 @@ static int svcauth_gss_handle_init(struct svc_rqst *rqstp,
        struct kvec *resv = &rqstp->rq_res.head[0];
        struct xdr_netobj tmpobj;
        struct rsi *rsip, rsikey;
+       int ret;
 
        /* Read the verifier; should be NULL: */
        *authp = rpc_autherr_badverf;
@@ -1014,23 +1011,27 @@ static int svcauth_gss_handle_init(struct svc_rqst *rqstp,
                /* No upcall result: */
                return SVC_DROP;
        case 0:
+               ret = SVC_DROP;
                /* Got an answer to the upcall; use it: */
                if (gss_write_init_verf(rqstp, rsip))
-                       return SVC_DROP;
+                       goto out;
                if (resv->iov_len + 4 > PAGE_SIZE)
-                       return SVC_DROP;
+                       goto out;
                svc_putnl(resv, RPC_SUCCESS);
                if (svc_safe_putnetobj(resv, &rsip->out_handle))
-                       return SVC_DROP;
+                       goto out;
                if (resv->iov_len + 3 * 4 > PAGE_SIZE)
-                       return SVC_DROP;
+                       goto out;
                svc_putnl(resv, rsip->major_status);
                svc_putnl(resv, rsip->minor_status);
                svc_putnl(resv, GSS_SEQ_WIN);
                if (svc_safe_putnetobj(resv, &rsip->out_token))
-                       return SVC_DROP;
+                       goto out;
        }
-       return SVC_COMPLETE;
+       ret = SVC_COMPLETE;
+out:
+       cache_put(&rsip->h, &rsi_cache);
+       return ret;
 }
 
 /*
@@ -1125,6 +1126,7 @@ svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp)
        case RPC_GSS_PROC_DESTROY:
                if (gss_write_verf(rqstp, rsci->mechctx, gc->gc_seq))
                        goto auth_err;
+               rsci->h.expiry_time = get_seconds();
                set_bit(CACHE_NEGATIVE, &rsci->h.flags);
                if (resv->iov_len + 4 > PAGE_SIZE)
                        goto drop;
@@ -1386,19 +1388,26 @@ int
 gss_svc_init(void)
 {
        int rv = svc_auth_register(RPC_AUTH_GSS, &svcauthops_gss);
-       if (rv == 0) {
-               cache_register(&rsc_cache);
-               cache_register(&rsi_cache);
-       }
+       if (rv)
+               return rv;
+       rv = cache_register(&rsc_cache);
+       if (rv)
+               goto out1;
+       rv = cache_register(&rsi_cache);
+       if (rv)
+               goto out2;
+       return 0;
+out2:
+       cache_unregister(&rsc_cache);
+out1:
+       svc_auth_unregister(RPC_AUTH_GSS);
        return rv;
 }
 
 void
 gss_svc_shutdown(void)
 {
-       if (cache_unregister(&rsc_cache))
-               printk(KERN_ERR "auth_rpcgss: failed to unregister rsc cache\n");
-       if (cache_unregister(&rsi_cache))
-               printk(KERN_ERR "auth_rpcgss: failed to unregister rsi cache\n");
+       cache_unregister(&rsc_cache);
+       cache_unregister(&rsi_cache);
        svc_auth_unregister(RPC_AUTH_GSS);
 }
index 73f053d0cc7a4f7eee6d65954f5383cb6d6fa18e..636c8e04e0bebb0fff9b33e34a23bd8e40941dfc 100644 (file)
@@ -245,6 +245,7 @@ int cache_check(struct cache_detail *detail,
                cache_put(h, detail);
        return rv;
 }
+EXPORT_SYMBOL(cache_check);
 
 /*
  * caches need to be periodically cleaned.
@@ -290,44 +291,78 @@ static const struct file_operations cache_flush_operations;
 static void do_cache_clean(struct work_struct *work);
 static DECLARE_DELAYED_WORK(cache_cleaner, do_cache_clean);
 
-void cache_register(struct cache_detail *cd)
+static void remove_cache_proc_entries(struct cache_detail *cd)
 {
-       cd->proc_ent = proc_mkdir(cd->name, proc_net_rpc);
-       if (cd->proc_ent) {
-               struct proc_dir_entry *p;
-               cd->proc_ent->owner = cd->owner;
-               cd->channel_ent = cd->content_ent = NULL;
+       if (cd->proc_ent == NULL)
+               return;
+       if (cd->flush_ent)
+               remove_proc_entry("flush", cd->proc_ent);
+       if (cd->channel_ent)
+               remove_proc_entry("channel", cd->proc_ent);
+       if (cd->content_ent)
+               remove_proc_entry("content", cd->proc_ent);
+       cd->proc_ent = NULL;
+       remove_proc_entry(cd->name, proc_net_rpc);
+}
 
-               p = create_proc_entry("flush", S_IFREG|S_IRUSR|S_IWUSR,
-                                     cd->proc_ent);
-               cd->flush_ent =  p;
-               if (p) {
-                       p->proc_fops = &cache_flush_operations;
-                       p->owner = cd->owner;
-                       p->data = cd;
-               }
+#ifdef CONFIG_PROC_FS
+static int create_cache_proc_entries(struct cache_detail *cd)
+{
+       struct proc_dir_entry *p;
 
-               if (cd->cache_request || cd->cache_parse) {
-                       p = create_proc_entry("channel", S_IFREG|S_IRUSR|S_IWUSR,
-                                             cd->proc_ent);
-                       cd->channel_ent = p;
-                       if (p) {
-                               p->proc_fops = &cache_file_operations;
-                               p->owner = cd->owner;
-                               p->data = cd;
-                       }
-               }
-               if (cd->cache_show) {
-                       p = create_proc_entry("content", S_IFREG|S_IRUSR|S_IWUSR,
-                                             cd->proc_ent);
-                       cd->content_ent = p;
-                       if (p) {
-                               p->proc_fops = &content_file_operations;
-                               p->owner = cd->owner;
-                               p->data = cd;
-                       }
-               }
+       cd->proc_ent = proc_mkdir(cd->name, proc_net_rpc);
+       if (cd->proc_ent == NULL)
+               goto out_nomem;
+       cd->proc_ent->owner = cd->owner;
+       cd->channel_ent = cd->content_ent = NULL;
+
+       p = create_proc_entry("flush", S_IFREG|S_IRUSR|S_IWUSR, cd->proc_ent);
+       cd->flush_ent = p;
+       if (p == NULL)
+               goto out_nomem;
+       p->proc_fops = &cache_flush_operations;
+       p->owner = cd->owner;
+       p->data = cd;
+
+       if (cd->cache_request || cd->cache_parse) {
+               p = create_proc_entry("channel", S_IFREG|S_IRUSR|S_IWUSR,
+                                     cd->proc_ent);
+               cd->channel_ent = p;
+               if (p == NULL)
+                       goto out_nomem;
+               p->proc_fops = &cache_file_operations;
+               p->owner = cd->owner;
+               p->data = cd;
        }
+       if (cd->cache_show) {
+               p = create_proc_entry("content", S_IFREG|S_IRUSR|S_IWUSR,
+                                     cd->proc_ent);
+               cd->content_ent = p;
+               if (p == NULL)
+                       goto out_nomem;
+               p->proc_fops = &content_file_operations;
+               p->owner = cd->owner;
+               p->data = cd;
+       }
+       return 0;
+out_nomem:
+       remove_cache_proc_entries(cd);
+       return -ENOMEM;
+}
+#else /* CONFIG_PROC_FS */
+static int create_cache_proc_entries(struct cache_detail *cd)
+{
+       return 0;
+}
+#endif
+
+int cache_register(struct cache_detail *cd)
+{
+       int ret;
+
+       ret = create_cache_proc_entries(cd);
+       if (ret)
+               return ret;
        rwlock_init(&cd->hash_lock);
        INIT_LIST_HEAD(&cd->queue);
        spin_lock(&cache_list_lock);
@@ -341,9 +376,11 @@ void cache_register(struct cache_detail *cd)
 
        /* start the cleaning process */
        schedule_delayed_work(&cache_cleaner, 0);
+       return 0;
 }
+EXPORT_SYMBOL(cache_register);
 
-int cache_unregister(struct cache_detail *cd)
+void cache_unregister(struct cache_detail *cd)
 {
        cache_purge(cd);
        spin_lock(&cache_list_lock);
@@ -351,30 +388,23 @@ int cache_unregister(struct cache_detail *cd)
        if (cd->entries || atomic_read(&cd->inuse)) {
                write_unlock(&cd->hash_lock);
                spin_unlock(&cache_list_lock);
-               return -EBUSY;
+               goto out;
        }
        if (current_detail == cd)
                current_detail = NULL;
        list_del_init(&cd->others);
        write_unlock(&cd->hash_lock);
        spin_unlock(&cache_list_lock);
-       if (cd->proc_ent) {
-               if (cd->flush_ent)
-                       remove_proc_entry("flush", cd->proc_ent);
-               if (cd->channel_ent)
-                       remove_proc_entry("channel", cd->proc_ent);
-               if (cd->content_ent)
-                       remove_proc_entry("content", cd->proc_ent);
-
-               cd->proc_ent = NULL;
-               remove_proc_entry(cd->name, proc_net_rpc);
-       }
+       remove_cache_proc_entries(cd);
        if (list_empty(&cache_list)) {
                /* module must be being unloaded so its safe to kill the worker */
                cancel_delayed_work_sync(&cache_cleaner);
        }
-       return 0;
+       return;
+out:
+       printk(KERN_ERR "nfsd: failed to unregister %s cache\n", cd->name);
 }
+EXPORT_SYMBOL(cache_unregister);
 
 /* clean cache tries to find something to clean
  * and cleans it.
@@ -489,6 +519,7 @@ void cache_flush(void)
        while (cache_clean() != -1)
                cond_resched();
 }
+EXPORT_SYMBOL(cache_flush);
 
 void cache_purge(struct cache_detail *detail)
 {
@@ -497,7 +528,7 @@ void cache_purge(struct cache_detail *detail)
        cache_flush();
        detail->flush_time = 1;
 }
-
+EXPORT_SYMBOL(cache_purge);
 
 
 /*
@@ -634,13 +665,13 @@ void cache_clean_deferred(void *owner)
 /*
  * communicate with user-space
  *
- * We have a magic /proc file - /proc/sunrpc/cache
- * On read, you get a full request, or block
- * On write, an update request is processed
- * Poll works if anything to read, and always allows write
+ * We have a magic /proc file - /proc/sunrpc/<cachename>/channel.
+ * On read, you get a full request, or block.
+ * On write, an update request is processed.
+ * Poll works if anything to read, and always allows write.
  *
  * Implemented by linked list of requests.  Each open file has
- * a ->private that also exists in this list.  New request are added
+ * a ->private that also exists in this list.  New requests are added
  * to the end and may wakeup and preceding readers.
  * New readers are added to the head.  If, on read, an item is found with
  * CACHE_UPCALLING clear, we free it from the list.
@@ -963,6 +994,7 @@ void qword_add(char **bpp, int *lp, char *str)
        *bpp = bp;
        *lp = len;
 }
+EXPORT_SYMBOL(qword_add);
 
 void qword_addhex(char **bpp, int *lp, char *buf, int blen)
 {
@@ -991,6 +1023,7 @@ void qword_addhex(char **bpp, int *lp, char *buf, int blen)
        *bpp = bp;
        *lp = len;
 }
+EXPORT_SYMBOL(qword_addhex);
 
 static void warn_no_listener(struct cache_detail *detail)
 {
@@ -1113,6 +1146,7 @@ int qword_get(char **bpp, char *dest, int bufsize)
        *dest = '\0';
        return len;
 }
+EXPORT_SYMBOL(qword_get);
 
 
 /*
@@ -1244,18 +1278,18 @@ static ssize_t read_flush(struct file *file, char __user *buf,
        struct cache_detail *cd = PDE(file->f_path.dentry->d_inode)->data;
        char tbuf[20];
        unsigned long p = *ppos;
-       int len;
+       size_t len;
 
        sprintf(tbuf, "%lu\n", cd->flush_time);
        len = strlen(tbuf);
        if (p >= len)
                return 0;
        len -= p;
-       if (len > count) len = count;
+       if (len > count)
+               len = count;
        if (copy_to_user(buf, (void*)(tbuf+p), len))
-               len = -EFAULT;
-       else
-               *ppos += len;
+               return -EFAULT;
+       *ppos += len;
        return len;
 }
 
index 924916ceaa435b531b043b190cd006268492d28b..0998e6d0966469df4ceb8f5adde3a842956093d5 100644 (file)
@@ -313,7 +313,7 @@ struct rpc_clnt *rpc_create(struct rpc_create_args *args)
                return clnt;
 
        if (!(args->flags & RPC_CLNT_CREATE_NOPING)) {
-               int err = rpc_ping(clnt, RPC_TASK_SOFT|RPC_TASK_NOINTR);
+               int err = rpc_ping(clnt, RPC_TASK_SOFT);
                if (err != 0) {
                        rpc_shutdown_client(clnt);
                        return ERR_PTR(err);
@@ -324,8 +324,6 @@ struct rpc_clnt *rpc_create(struct rpc_create_args *args)
        if (args->flags & RPC_CLNT_CREATE_HARDRTRY)
                clnt->cl_softrtry = 0;
 
-       if (args->flags & RPC_CLNT_CREATE_INTR)
-               clnt->cl_intr = 1;
        if (args->flags & RPC_CLNT_CREATE_AUTOBIND)
                clnt->cl_autobind = 1;
        if (args->flags & RPC_CLNT_CREATE_DISCRTRY)
@@ -493,7 +491,7 @@ struct rpc_clnt *rpc_bind_new_program(struct rpc_clnt *old,
        clnt->cl_prog     = program->number;
        clnt->cl_vers     = version->number;
        clnt->cl_stats    = program->stats;
-       err = rpc_ping(clnt, RPC_TASK_SOFT|RPC_TASK_NOINTR);
+       err = rpc_ping(clnt, RPC_TASK_SOFT);
        if (err != 0) {
                rpc_shutdown_client(clnt);
                clnt = ERR_PTR(err);
@@ -515,46 +513,6 @@ static const struct rpc_call_ops rpc_default_ops = {
        .rpc_call_done = rpc_default_callback,
 };
 
-/*
- *     Export the signal mask handling for synchronous code that
- *     sleeps on RPC calls
- */
-#define RPC_INTR_SIGNALS (sigmask(SIGHUP) | sigmask(SIGINT) | sigmask(SIGQUIT) | sigmask(SIGTERM))
-
-static void rpc_save_sigmask(sigset_t *oldset, int intr)
-{
-       unsigned long   sigallow = sigmask(SIGKILL);
-       sigset_t sigmask;
-
-       /* Block all signals except those listed in sigallow */
-       if (intr)
-               sigallow |= RPC_INTR_SIGNALS;
-       siginitsetinv(&sigmask, sigallow);
-       sigprocmask(SIG_BLOCK, &sigmask, oldset);
-}
-
-static void rpc_task_sigmask(struct rpc_task *task, sigset_t *oldset)
-{
-       rpc_save_sigmask(oldset, !RPC_TASK_UNINTERRUPTIBLE(task));
-}
-
-static void rpc_restore_sigmask(sigset_t *oldset)
-{
-       sigprocmask(SIG_SETMASK, oldset, NULL);
-}
-
-void rpc_clnt_sigmask(struct rpc_clnt *clnt, sigset_t *oldset)
-{
-       rpc_save_sigmask(oldset, clnt->cl_intr);
-}
-EXPORT_SYMBOL_GPL(rpc_clnt_sigmask);
-
-void rpc_clnt_sigunmask(struct rpc_clnt *clnt, sigset_t *oldset)
-{
-       rpc_restore_sigmask(oldset);
-}
-EXPORT_SYMBOL_GPL(rpc_clnt_sigunmask);
-
 /**
  * rpc_run_task - Allocate a new RPC task, then run rpc_execute against it
  * @task_setup_data: pointer to task initialisation data
@@ -562,7 +520,6 @@ EXPORT_SYMBOL_GPL(rpc_clnt_sigunmask);
 struct rpc_task *rpc_run_task(const struct rpc_task_setup *task_setup_data)
 {
        struct rpc_task *task, *ret;
-       sigset_t oldset;
 
        task = rpc_new_task(task_setup_data);
        if (task == NULL) {
@@ -578,13 +535,7 @@ struct rpc_task *rpc_run_task(const struct rpc_task_setup *task_setup_data)
                goto out;
        }
        atomic_inc(&task->tk_count);
-       /* Mask signals on synchronous RPC calls and RPCSEC_GSS upcalls */
-       if (!RPC_IS_ASYNC(task)) {
-               rpc_task_sigmask(task, &oldset);
-               rpc_execute(task);
-               rpc_restore_sigmask(&oldset);
-       } else
-               rpc_execute(task);
+       rpc_execute(task);
        ret = task;
 out:
        return ret;
index fa5b8f202d5b3a358e090f484cff3475d4fc228e..3164a0871cf039ca7c2f9ebb80ad2dc1eba7b180 100644 (file)
@@ -120,8 +120,7 @@ static struct rpc_clnt *rpcb_create(char *hostname, struct sockaddr *srvaddr,
                .program        = &rpcb_program,
                .version        = version,
                .authflavor     = RPC_AUTH_UNIX,
-               .flags          = (RPC_CLNT_CREATE_NOPING |
-                                  RPC_CLNT_CREATE_INTR),
+               .flags          = RPC_CLNT_CREATE_NOPING,
        };
 
        switch (srvaddr->sa_family) {
index 40ce6f6672d6bb8b735d2ed379dff9add6ff087b..4c669121e607f774b7739a326639e8f2aec146a3 100644 (file)
@@ -245,9 +245,9 @@ void rpc_init_wait_queue(struct rpc_wait_queue *queue, const char *qname)
 }
 EXPORT_SYMBOL_GPL(rpc_init_wait_queue);
 
-static int rpc_wait_bit_interruptible(void *word)
+static int rpc_wait_bit_killable(void *word)
 {
-       if (signal_pending(current))
+       if (fatal_signal_pending(current))
                return -ERESTARTSYS;
        schedule();
        return 0;
@@ -299,9 +299,9 @@ static void rpc_mark_complete_task(struct rpc_task *task)
 int __rpc_wait_for_completion_task(struct rpc_task *task, int (*action)(void *))
 {
        if (action == NULL)
-               action = rpc_wait_bit_interruptible;
+               action = rpc_wait_bit_killable;
        return wait_on_bit(&task->tk_runstate, RPC_TASK_ACTIVE,
-                       action, TASK_INTERRUPTIBLE);
+                       action, TASK_KILLABLE);
 }
 EXPORT_SYMBOL_GPL(__rpc_wait_for_completion_task);
 
@@ -696,10 +696,9 @@ static void __rpc_execute(struct rpc_task *task)
 
                /* sync task: sleep here */
                dprintk("RPC: %5u sync task going to sleep\n", task->tk_pid);
-               /* Note: Caller should be using rpc_clnt_sigmask() */
                status = out_of_line_wait_on_bit(&task->tk_runstate,
-                               RPC_TASK_QUEUED, rpc_wait_bit_interruptible,
-                               TASK_INTERRUPTIBLE);
+                               RPC_TASK_QUEUED, rpc_wait_bit_killable,
+                               TASK_KILLABLE);
                if (status == -ERESTARTSYS) {
                        /*
                         * When a sync task receives a signal, it exits with
@@ -840,8 +839,6 @@ static void rpc_init_task(struct rpc_task *task, const struct rpc_task_setup *ta
                kref_get(&task->tk_client->cl_kref);
                if (task->tk_client->cl_softrtry)
                        task->tk_flags |= RPC_TASK_SOFT;
-               if (!task->tk_client->cl_intr)
-                       task->tk_flags |= RPC_TASK_NOINTR;
        }
 
        if (task->tk_ops->rpc_call_prepare != NULL)
index 74df2d358e61ba5eb77a806a2cb1d58e163dd7de..5a16875f5ac8b0686ccdf5e9448dac850aab7064 100644 (file)
@@ -33,7 +33,7 @@ struct proc_dir_entry *proc_net_rpc = NULL;
 static int rpc_proc_show(struct seq_file *seq, void *v) {
        const struct rpc_stat   *statp = seq->private;
        const struct rpc_program *prog = statp->program;
-       int             i, j;
+       unsigned int i, j;
 
        seq_printf(seq,
                "net %u %u %u %u\n",
@@ -81,7 +81,7 @@ void svc_seq_show(struct seq_file *seq, const struct svc_stat *statp) {
        const struct svc_program *prog = statp->program;
        const struct svc_procedure *proc;
        const struct svc_version *vers;
-       int             i, j;
+       unsigned int i, j;
 
        seq_printf(seq,
                "net %u %u %u %u\n",
@@ -106,6 +106,7 @@ void svc_seq_show(struct seq_file *seq, const struct svc_stat *statp) {
                seq_putc(seq, '\n');
        }
 }
+EXPORT_SYMBOL(svc_seq_show);
 
 /**
  * rpc_alloc_iostats - allocate an rpc_iostats structure
@@ -255,12 +256,14 @@ svc_proc_register(struct svc_stat *statp, const struct file_operations *fops)
 {
        return do_register(statp->program->pg_name, statp, fops);
 }
+EXPORT_SYMBOL(svc_proc_register);
 
 void
 svc_proc_unregister(const char *name)
 {
        remove_proc_entry(name, proc_net_rpc);
 }
+EXPORT_SYMBOL(svc_proc_unregister);
 
 void
 rpc_proc_init(void)
index 1a7e309d008bcd9624dff48195c8052c515a3791..843629f557630d07b0b4b0e29eb5a6f9feddce88 100644 (file)
 #include <linux/sunrpc/rpc_pipe_fs.h>
 #include <linux/sunrpc/xprtsock.h>
 
-/* RPC server stuff */
-EXPORT_SYMBOL(svc_create);
-EXPORT_SYMBOL(svc_create_thread);
-EXPORT_SYMBOL(svc_create_pooled);
-EXPORT_SYMBOL(svc_set_num_threads);
-EXPORT_SYMBOL(svc_exit_thread);
-EXPORT_SYMBOL(svc_destroy);
-EXPORT_SYMBOL(svc_drop);
-EXPORT_SYMBOL(svc_process);
-EXPORT_SYMBOL(svc_recv);
-EXPORT_SYMBOL(svc_wake_up);
-EXPORT_SYMBOL(svc_makesock);
-EXPORT_SYMBOL(svc_reserve);
-EXPORT_SYMBOL(svc_auth_register);
-EXPORT_SYMBOL(auth_domain_lookup);
-EXPORT_SYMBOL(svc_authenticate);
-EXPORT_SYMBOL(svc_set_client);
-
-/* RPC statistics */
-#ifdef CONFIG_PROC_FS
-EXPORT_SYMBOL(svc_proc_register);
-EXPORT_SYMBOL(svc_proc_unregister);
-EXPORT_SYMBOL(svc_seq_show);
-#endif
-
-/* caching... */
-EXPORT_SYMBOL(auth_domain_find);
-EXPORT_SYMBOL(auth_domain_put);
-EXPORT_SYMBOL(auth_unix_add_addr);
-EXPORT_SYMBOL(auth_unix_forget_old);
-EXPORT_SYMBOL(auth_unix_lookup);
-EXPORT_SYMBOL(cache_check);
-EXPORT_SYMBOL(cache_flush);
-EXPORT_SYMBOL(cache_purge);
-EXPORT_SYMBOL(cache_register);
-EXPORT_SYMBOL(cache_unregister);
-EXPORT_SYMBOL(qword_add);
-EXPORT_SYMBOL(qword_addhex);
-EXPORT_SYMBOL(qword_get);
-EXPORT_SYMBOL(svcauth_unix_purge);
-EXPORT_SYMBOL(unix_domain_find);
-
 extern struct cache_detail ip_map_cache, unix_gid_cache;
 
 static int __init
@@ -85,7 +43,8 @@ init_sunrpc(void)
 #endif
        cache_register(&ip_map_cache);
        cache_register(&unix_gid_cache);
-       init_socket_xprt();
+       svc_init_xprt_sock();   /* svc sock transport */
+       init_socket_xprt();     /* clnt sock transport */
        rpcauth_init_module();
 out:
        return err;
@@ -96,12 +55,11 @@ cleanup_sunrpc(void)
 {
        rpcauth_remove_module();
        cleanup_socket_xprt();
+       svc_cleanup_xprt_sock();
        unregister_rpc_pipefs();
        rpc_destroy_mempool();
-       if (cache_unregister(&ip_map_cache))
-               printk(KERN_ERR "sunrpc: failed to unregister ip_map cache\n");
-       if (cache_unregister(&unix_gid_cache))
-             printk(KERN_ERR "sunrpc: failed to unregister unix_gid cache\n");
+       cache_unregister(&ip_map_cache);
+       cache_unregister(&unix_gid_cache);
 #ifdef RPC_DEBUG
        rpc_unregister_sysctl();
 #endif
index 4ad5fbbb18b48df0d2ad9a0b457212a6c764330d..a290e1523297783da4e491ad547e17cdeb5da675 100644 (file)
@@ -364,7 +364,7 @@ __svc_create(struct svc_program *prog, unsigned int bufsize, int npools,
           void (*shutdown)(struct svc_serv *serv))
 {
        struct svc_serv *serv;
-       int vers;
+       unsigned int vers;
        unsigned int xdrsize;
        unsigned int i;
 
@@ -433,6 +433,7 @@ svc_create(struct svc_program *prog, unsigned int bufsize,
 {
        return __svc_create(prog, bufsize, /*npools*/1, shutdown);
 }
+EXPORT_SYMBOL(svc_create);
 
 struct svc_serv *
 svc_create_pooled(struct svc_program *prog, unsigned int bufsize,
@@ -452,6 +453,7 @@ svc_create_pooled(struct svc_program *prog, unsigned int bufsize,
 
        return serv;
 }
+EXPORT_SYMBOL(svc_create_pooled);
 
 /*
  * Destroy an RPC service.  Should be called with the BKL held
@@ -459,9 +461,6 @@ svc_create_pooled(struct svc_program *prog, unsigned int bufsize,
 void
 svc_destroy(struct svc_serv *serv)
 {
-       struct svc_sock *svsk;
-       struct svc_sock *tmp;
-
        dprintk("svc: svc_destroy(%s, %d)\n",
                                serv->sv_program->pg_name,
                                serv->sv_nrthreads);
@@ -476,14 +475,12 @@ svc_destroy(struct svc_serv *serv)
 
        del_timer_sync(&serv->sv_temptimer);
 
-       list_for_each_entry_safe(svsk, tmp, &serv->sv_tempsocks, sk_list)
-               svc_force_close_socket(svsk);
+       svc_close_all(&serv->sv_tempsocks);
 
        if (serv->sv_shutdown)
                serv->sv_shutdown(serv);
 
-       list_for_each_entry_safe(svsk, tmp, &serv->sv_permsocks, sk_list)
-               svc_force_close_socket(svsk);
+       svc_close_all(&serv->sv_permsocks);
 
        BUG_ON(!list_empty(&serv->sv_permsocks));
        BUG_ON(!list_empty(&serv->sv_tempsocks));
@@ -498,6 +495,7 @@ svc_destroy(struct svc_serv *serv)
        kfree(serv->sv_pools);
        kfree(serv);
 }
+EXPORT_SYMBOL(svc_destroy);
 
 /*
  * Allocate an RPC server's buffer space.
@@ -536,31 +534,17 @@ svc_release_buffer(struct svc_rqst *rqstp)
                        put_page(rqstp->rq_pages[i]);
 }
 
-/*
- * Create a thread in the given pool.  Caller must hold BKL.
- * On a NUMA or SMP machine, with a multi-pool serv, the thread
- * will be restricted to run on the cpus belonging to the pool.
- */
-static int
-__svc_create_thread(svc_thread_fn func, struct svc_serv *serv,
-                   struct svc_pool *pool)
+struct svc_rqst *
+svc_prepare_thread(struct svc_serv *serv, struct svc_pool *pool)
 {
        struct svc_rqst *rqstp;
-       int             error = -ENOMEM;
-       int             have_oldmask = 0;
-       cpumask_t       oldmask;
 
        rqstp = kzalloc(sizeof(*rqstp), GFP_KERNEL);
        if (!rqstp)
-               goto out;
+               goto out_enomem;
 
        init_waitqueue_head(&rqstp->rq_wait);
 
-       if (!(rqstp->rq_argp = kmalloc(serv->sv_xdrsize, GFP_KERNEL))
-        || !(rqstp->rq_resp = kmalloc(serv->sv_xdrsize, GFP_KERNEL))
-        || !svc_init_buffer(rqstp, serv->sv_max_mesg))
-               goto out_thread;
-
        serv->sv_nrthreads++;
        spin_lock_bh(&pool->sp_lock);
        pool->sp_nrthreads++;
@@ -569,6 +553,45 @@ __svc_create_thread(svc_thread_fn func, struct svc_serv *serv,
        rqstp->rq_server = serv;
        rqstp->rq_pool = pool;
 
+       rqstp->rq_argp = kmalloc(serv->sv_xdrsize, GFP_KERNEL);
+       if (!rqstp->rq_argp)
+               goto out_thread;
+
+       rqstp->rq_resp = kmalloc(serv->sv_xdrsize, GFP_KERNEL);
+       if (!rqstp->rq_resp)
+               goto out_thread;
+
+       if (!svc_init_buffer(rqstp, serv->sv_max_mesg))
+               goto out_thread;
+
+       return rqstp;
+out_thread:
+       svc_exit_thread(rqstp);
+out_enomem:
+       return ERR_PTR(-ENOMEM);
+}
+EXPORT_SYMBOL(svc_prepare_thread);
+
+/*
+ * Create a thread in the given pool.  Caller must hold BKL.
+ * On a NUMA or SMP machine, with a multi-pool serv, the thread
+ * will be restricted to run on the cpus belonging to the pool.
+ */
+static int
+__svc_create_thread(svc_thread_fn func, struct svc_serv *serv,
+                   struct svc_pool *pool)
+{
+       struct svc_rqst *rqstp;
+       int             error = -ENOMEM;
+       int             have_oldmask = 0;
+       cpumask_t       oldmask;
+
+       rqstp = svc_prepare_thread(serv, pool);
+       if (IS_ERR(rqstp)) {
+               error = PTR_ERR(rqstp);
+               goto out;
+       }
+
        if (serv->sv_nrpools > 1)
                have_oldmask = svc_pool_map_set_cpumask(pool->sp_id, &oldmask);
 
@@ -597,6 +620,7 @@ svc_create_thread(svc_thread_fn func, struct svc_serv *serv)
 {
        return __svc_create_thread(func, serv, &serv->sv_pools[0]);
 }
+EXPORT_SYMBOL(svc_create_thread);
 
 /*
  * Choose a pool in which to create a new thread, for svc_set_num_threads
@@ -700,6 +724,7 @@ svc_set_num_threads(struct svc_serv *serv, struct svc_pool *pool, int nrservs)
 
        return error;
 }
+EXPORT_SYMBOL(svc_set_num_threads);
 
 /*
  * Called from a server thread as it's exiting.  Caller must hold BKL.
@@ -726,6 +751,7 @@ svc_exit_thread(struct svc_rqst *rqstp)
        if (serv)
                svc_destroy(serv);
 }
+EXPORT_SYMBOL(svc_exit_thread);
 
 /*
  * Register an RPC service with the local portmapper.
@@ -737,7 +763,8 @@ svc_register(struct svc_serv *serv, int proto, unsigned short port)
 {
        struct svc_program      *progp;
        unsigned long           flags;
-       int                     i, error = 0, dummy;
+       unsigned int            i;
+       int                     error = 0, dummy;
 
        if (!port)
                clear_thread_flag(TIF_SIGPENDING);
@@ -840,9 +867,9 @@ svc_process(struct svc_rqst *rqstp)
        rqstp->rq_res.tail[0].iov_len = 0;
        /* Will be turned off only in gss privacy case: */
        rqstp->rq_splice_ok = 1;
-       /* tcp needs a space for the record length... */
-       if (rqstp->rq_prot == IPPROTO_TCP)
-               svc_putnl(resv, 0);
+
+       /* Setup reply header */
+       rqstp->rq_xprt->xpt_ops->xpo_prep_reply_hdr(rqstp);
 
        rqstp->rq_xid = svc_getu32(argv);
        svc_putu32(resv, rqstp->rq_xid);
@@ -1049,16 +1076,15 @@ err_bad:
        svc_putnl(resv, ntohl(rpc_stat));
        goto sendit;
 }
+EXPORT_SYMBOL(svc_process);
 
 /*
  * Return (transport-specific) limit on the rpc payload.
  */
 u32 svc_max_payload(const struct svc_rqst *rqstp)
 {
-       int max = RPCSVC_MAXPAYLOAD_TCP;
+       u32 max = rqstp->rq_xprt->xpt_class->xcl_max_payload;
 
-       if (rqstp->rq_sock->sk_sock->type == SOCK_DGRAM)
-               max = RPCSVC_MAXPAYLOAD_UDP;
        if (rqstp->rq_server->sv_max_payload < max)
                max = rqstp->rq_server->sv_max_payload;
        return max;
diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c
new file mode 100644 (file)
index 0000000..ea377e0
--- /dev/null
@@ -0,0 +1,1055 @@
+/*
+ * linux/net/sunrpc/svc_xprt.c
+ *
+ * Author: Tom Tucker <tom@opengridcomputing.com>
+ */
+
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/fcntl.h>
+#include <linux/net.h>
+#include <linux/in.h>
+#include <linux/inet.h>
+#include <linux/udp.h>
+#include <linux/tcp.h>
+#include <linux/unistd.h>
+#include <linux/slab.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <linux/file.h>
+#include <linux/freezer.h>
+#include <net/sock.h>
+#include <net/checksum.h>
+#include <net/ip.h>
+#include <net/ipv6.h>
+#include <net/tcp_states.h>
+#include <linux/uaccess.h>
+#include <asm/ioctls.h>
+
+#include <linux/sunrpc/types.h>
+#include <linux/sunrpc/clnt.h>
+#include <linux/sunrpc/xdr.h>
+#include <linux/sunrpc/stats.h>
+#include <linux/sunrpc/svc_xprt.h>
+
+#define RPCDBG_FACILITY        RPCDBG_SVCXPRT
+
+static struct svc_deferred_req *svc_deferred_dequeue(struct svc_xprt *xprt);
+static int svc_deferred_recv(struct svc_rqst *rqstp);
+static struct cache_deferred_req *svc_defer(struct cache_req *req);
+static void svc_age_temp_xprts(unsigned long closure);
+
+/* apparently the "standard" is that clients close
+ * idle connections after 5 minutes, servers after
+ * 6 minutes
+ *   http://www.connectathon.org/talks96/nfstcp.pdf
+ */
+static int svc_conn_age_period = 6*60;
+
+/* List of registered transport classes */
+static DEFINE_SPINLOCK(svc_xprt_class_lock);
+static LIST_HEAD(svc_xprt_class_list);
+
+/* SMP locking strategy:
+ *
+ *     svc_pool->sp_lock protects most of the fields of that pool.
+ *     svc_serv->sv_lock protects sv_tempsocks, sv_permsocks, sv_tmpcnt.
+ *     when both need to be taken (rare), svc_serv->sv_lock is first.
+ *     BKL protects svc_serv->sv_nrthread.
+ *     svc_sock->sk_lock protects the svc_sock->sk_deferred list
+ *             and the ->sk_info_authunix cache.
+ *
+ *     The XPT_BUSY bit in xprt->xpt_flags prevents a transport being
+ *     enqueued multiply. During normal transport processing this bit
+ *     is set by svc_xprt_enqueue and cleared by svc_xprt_received.
+ *     Providers should not manipulate this bit directly.
+ *
+ *     Some flags can be set to certain values at any time
+ *     providing that certain rules are followed:
+ *
+ *     XPT_CONN, XPT_DATA:
+ *             - Can be set or cleared at any time.
+ *             - After a set, svc_xprt_enqueue must be called to enqueue
+ *               the transport for processing.
+ *             - After a clear, the transport must be read/accepted.
+ *               If this succeeds, it must be set again.
+ *     XPT_CLOSE:
+ *             - Can set at any time. It is never cleared.
+ *      XPT_DEAD:
+ *             - Can only be set while XPT_BUSY is held which ensures
+ *               that no other thread will be using the transport or will
+ *               try to set XPT_DEAD.
+ */
+
+int svc_reg_xprt_class(struct svc_xprt_class *xcl)
+{
+       struct svc_xprt_class *cl;
+       int res = -EEXIST;
+
+       dprintk("svc: Adding svc transport class '%s'\n", xcl->xcl_name);
+
+       INIT_LIST_HEAD(&xcl->xcl_list);
+       spin_lock(&svc_xprt_class_lock);
+       /* Make sure there isn't already a class with the same name */
+       list_for_each_entry(cl, &svc_xprt_class_list, xcl_list) {
+               if (strcmp(xcl->xcl_name, cl->xcl_name) == 0)
+                       goto out;
+       }
+       list_add_tail(&xcl->xcl_list, &svc_xprt_class_list);
+       res = 0;
+out:
+       spin_unlock(&svc_xprt_class_lock);
+       return res;
+}
+EXPORT_SYMBOL_GPL(svc_reg_xprt_class);
+
+void svc_unreg_xprt_class(struct svc_xprt_class *xcl)
+{
+       dprintk("svc: Removing svc transport class '%s'\n", xcl->xcl_name);
+       spin_lock(&svc_xprt_class_lock);
+       list_del_init(&xcl->xcl_list);
+       spin_unlock(&svc_xprt_class_lock);
+}
+EXPORT_SYMBOL_GPL(svc_unreg_xprt_class);
+
+/*
+ * Format the transport list for printing
+ */
+int svc_print_xprts(char *buf, int maxlen)
+{
+       struct list_head *le;
+       char tmpstr[80];
+       int len = 0;
+       buf[0] = '\0';
+
+       spin_lock(&svc_xprt_class_lock);
+       list_for_each(le, &svc_xprt_class_list) {
+               int slen;
+               struct svc_xprt_class *xcl =
+                       list_entry(le, struct svc_xprt_class, xcl_list);
+
+               sprintf(tmpstr, "%s %d\n", xcl->xcl_name, xcl->xcl_max_payload);
+               slen = strlen(tmpstr);
+               if (len + slen > maxlen)
+                       break;
+               len += slen;
+               strcat(buf, tmpstr);
+       }
+       spin_unlock(&svc_xprt_class_lock);
+
+       return len;
+}
+
+static void svc_xprt_free(struct kref *kref)
+{
+       struct svc_xprt *xprt =
+               container_of(kref, struct svc_xprt, xpt_ref);
+       struct module *owner = xprt->xpt_class->xcl_owner;
+       if (test_bit(XPT_CACHE_AUTH, &xprt->xpt_flags)
+           && xprt->xpt_auth_cache != NULL)
+               svcauth_unix_info_release(xprt->xpt_auth_cache);
+       xprt->xpt_ops->xpo_free(xprt);
+       module_put(owner);
+}
+
+void svc_xprt_put(struct svc_xprt *xprt)
+{
+       kref_put(&xprt->xpt_ref, svc_xprt_free);
+}
+EXPORT_SYMBOL_GPL(svc_xprt_put);
+
+/*
+ * Called by transport drivers to initialize the transport independent
+ * portion of the transport instance.
+ */
+void svc_xprt_init(struct svc_xprt_class *xcl, struct svc_xprt *xprt,
+                  struct svc_serv *serv)
+{
+       memset(xprt, 0, sizeof(*xprt));
+       xprt->xpt_class = xcl;
+       xprt->xpt_ops = xcl->xcl_ops;
+       kref_init(&xprt->xpt_ref);
+       xprt->xpt_server = serv;
+       INIT_LIST_HEAD(&xprt->xpt_list);
+       INIT_LIST_HEAD(&xprt->xpt_ready);
+       INIT_LIST_HEAD(&xprt->xpt_deferred);
+       mutex_init(&xprt->xpt_mutex);
+       spin_lock_init(&xprt->xpt_lock);
+       set_bit(XPT_BUSY, &xprt->xpt_flags);
+}
+EXPORT_SYMBOL_GPL(svc_xprt_init);
+
+int svc_create_xprt(struct svc_serv *serv, char *xprt_name, unsigned short port,
+                   int flags)
+{
+       struct svc_xprt_class *xcl;
+       struct sockaddr_in sin = {
+               .sin_family             = AF_INET,
+               .sin_addr.s_addr        = INADDR_ANY,
+               .sin_port               = htons(port),
+       };
+       dprintk("svc: creating transport %s[%d]\n", xprt_name, port);
+       spin_lock(&svc_xprt_class_lock);
+       list_for_each_entry(xcl, &svc_xprt_class_list, xcl_list) {
+               struct svc_xprt *newxprt;
+
+               if (strcmp(xprt_name, xcl->xcl_name))
+                       continue;
+
+               if (!try_module_get(xcl->xcl_owner))
+                       goto err;
+
+               spin_unlock(&svc_xprt_class_lock);
+               newxprt = xcl->xcl_ops->
+                       xpo_create(serv, (struct sockaddr *)&sin, sizeof(sin),
+                                  flags);
+               if (IS_ERR(newxprt)) {
+                       module_put(xcl->xcl_owner);
+                       return PTR_ERR(newxprt);
+               }
+
+               clear_bit(XPT_TEMP, &newxprt->xpt_flags);
+               spin_lock_bh(&serv->sv_lock);
+               list_add(&newxprt->xpt_list, &serv->sv_permsocks);
+               spin_unlock_bh(&serv->sv_lock);
+               clear_bit(XPT_BUSY, &newxprt->xpt_flags);
+               return svc_xprt_local_port(newxprt);
+       }
+ err:
+       spin_unlock(&svc_xprt_class_lock);
+       dprintk("svc: transport %s not found\n", xprt_name);
+       return -ENOENT;
+}
+EXPORT_SYMBOL_GPL(svc_create_xprt);
+
+/*
+ * Copy the local and remote xprt addresses to the rqstp structure
+ */
+void svc_xprt_copy_addrs(struct svc_rqst *rqstp, struct svc_xprt *xprt)
+{
+       struct sockaddr *sin;
+
+       memcpy(&rqstp->rq_addr, &xprt->xpt_remote, xprt->xpt_remotelen);
+       rqstp->rq_addrlen = xprt->xpt_remotelen;
+
+       /*
+        * Destination address in request is needed for binding the
+        * source address in RPC replies/callbacks later.
+        */
+       sin = (struct sockaddr *)&xprt->xpt_local;
+       switch (sin->sa_family) {
+       case AF_INET:
+               rqstp->rq_daddr.addr = ((struct sockaddr_in *)sin)->sin_addr;
+               break;
+       case AF_INET6:
+               rqstp->rq_daddr.addr6 = ((struct sockaddr_in6 *)sin)->sin6_addr;
+               break;
+       }
+}
+EXPORT_SYMBOL_GPL(svc_xprt_copy_addrs);
+
+/**
+ * svc_print_addr - Format rq_addr field for printing
+ * @rqstp: svc_rqst struct containing address to print
+ * @buf: target buffer for formatted address
+ * @len: length of target buffer
+ *
+ */
+char *svc_print_addr(struct svc_rqst *rqstp, char *buf, size_t len)
+{
+       return __svc_print_addr(svc_addr(rqstp), buf, len);
+}
+EXPORT_SYMBOL_GPL(svc_print_addr);
+
+/*
+ * Queue up an idle server thread.  Must have pool->sp_lock held.
+ * Note: this is really a stack rather than a queue, so that we only
+ * use as many different threads as we need, and the rest don't pollute
+ * the cache.
+ */
+static void svc_thread_enqueue(struct svc_pool *pool, struct svc_rqst *rqstp)
+{
+       list_add(&rqstp->rq_list, &pool->sp_threads);
+}
+
+/*
+ * Dequeue an nfsd thread.  Must have pool->sp_lock held.
+ */
+static void svc_thread_dequeue(struct svc_pool *pool, struct svc_rqst *rqstp)
+{
+       list_del(&rqstp->rq_list);
+}
+
+/*
+ * Queue up a transport with data pending. If there are idle nfsd
+ * processes, wake 'em up.
+ *
+ */
+void svc_xprt_enqueue(struct svc_xprt *xprt)
+{
+       struct svc_serv *serv = xprt->xpt_server;
+       struct svc_pool *pool;
+       struct svc_rqst *rqstp;
+       int cpu;
+
+       if (!(xprt->xpt_flags &
+             ((1<<XPT_CONN)|(1<<XPT_DATA)|(1<<XPT_CLOSE)|(1<<XPT_DEFERRED))))
+               return;
+       if (test_bit(XPT_DEAD, &xprt->xpt_flags))
+               return;
+
+       cpu = get_cpu();
+       pool = svc_pool_for_cpu(xprt->xpt_server, cpu);
+       put_cpu();
+
+       spin_lock_bh(&pool->sp_lock);
+
+       if (!list_empty(&pool->sp_threads) &&
+           !list_empty(&pool->sp_sockets))
+               printk(KERN_ERR
+                      "svc_xprt_enqueue: "
+                      "threads and transports both waiting??\n");
+
+       if (test_bit(XPT_DEAD, &xprt->xpt_flags)) {
+               /* Don't enqueue dead transports */
+               dprintk("svc: transport %p is dead, not enqueued\n", xprt);
+               goto out_unlock;
+       }
+
+       /* Mark transport as busy. It will remain in this state until
+        * the provider calls svc_xprt_received. We update XPT_BUSY
+        * atomically because it also guards against trying to enqueue
+        * the transport twice.
+        */
+       if (test_and_set_bit(XPT_BUSY, &xprt->xpt_flags)) {
+               /* Don't enqueue transport while already enqueued */
+               dprintk("svc: transport %p busy, not enqueued\n", xprt);
+               goto out_unlock;
+       }
+       BUG_ON(xprt->xpt_pool != NULL);
+       xprt->xpt_pool = pool;
+
+       /* Handle pending connection */
+       if (test_bit(XPT_CONN, &xprt->xpt_flags))
+               goto process;
+
+       /* Handle close in-progress */
+       if (test_bit(XPT_CLOSE, &xprt->xpt_flags))
+               goto process;
+
+       /* Check if we have space to reply to a request */
+       if (!xprt->xpt_ops->xpo_has_wspace(xprt)) {
+               /* Don't enqueue while not enough space for reply */
+               dprintk("svc: no write space, transport %p  not enqueued\n",
+                       xprt);
+               xprt->xpt_pool = NULL;
+               clear_bit(XPT_BUSY, &xprt->xpt_flags);
+               goto out_unlock;
+       }
+
+ process:
+       if (!list_empty(&pool->sp_threads)) {
+               rqstp = list_entry(pool->sp_threads.next,
+                                  struct svc_rqst,
+                                  rq_list);
+               dprintk("svc: transport %p served by daemon %p\n",
+                       xprt, rqstp);
+               svc_thread_dequeue(pool, rqstp);
+               if (rqstp->rq_xprt)
+                       printk(KERN_ERR
+                               "svc_xprt_enqueue: server %p, rq_xprt=%p!\n",
+                               rqstp, rqstp->rq_xprt);
+               rqstp->rq_xprt = xprt;
+               svc_xprt_get(xprt);
+               rqstp->rq_reserved = serv->sv_max_mesg;
+               atomic_add(rqstp->rq_reserved, &xprt->xpt_reserved);
+               BUG_ON(xprt->xpt_pool != pool);
+               wake_up(&rqstp->rq_wait);
+       } else {
+               dprintk("svc: transport %p put into queue\n", xprt);
+               list_add_tail(&xprt->xpt_ready, &pool->sp_sockets);
+               BUG_ON(xprt->xpt_pool != pool);
+       }
+
+out_unlock:
+       spin_unlock_bh(&pool->sp_lock);
+}
+EXPORT_SYMBOL_GPL(svc_xprt_enqueue);
+
+/*
+ * Dequeue the first transport.  Must be called with the pool->sp_lock held.
+ */
+static struct svc_xprt *svc_xprt_dequeue(struct svc_pool *pool)
+{
+       struct svc_xprt *xprt;
+
+       if (list_empty(&pool->sp_sockets))
+               return NULL;
+
+       xprt = list_entry(pool->sp_sockets.next,
+                         struct svc_xprt, xpt_ready);
+       list_del_init(&xprt->xpt_ready);
+
+       dprintk("svc: transport %p dequeued, inuse=%d\n",
+               xprt, atomic_read(&xprt->xpt_ref.refcount));
+
+       return xprt;
+}
+
+/*
+ * svc_xprt_received conditionally queues the transport for processing
+ * by another thread. The caller must hold the XPT_BUSY bit and must
+ * not thereafter touch transport data.
+ *
+ * Note: XPT_DATA only gets cleared when a read-attempt finds no (or
+ * insufficient) data.
+ */
+void svc_xprt_received(struct svc_xprt *xprt)
+{
+       BUG_ON(!test_bit(XPT_BUSY, &xprt->xpt_flags));
+       xprt->xpt_pool = NULL;
+       clear_bit(XPT_BUSY, &xprt->xpt_flags);
+       svc_xprt_enqueue(xprt);
+}
+EXPORT_SYMBOL_GPL(svc_xprt_received);
+
+/**
+ * svc_reserve - change the space reserved for the reply to a request.
+ * @rqstp:  The request in question
+ * @space: new max space to reserve
+ *
+ * Each request reserves some space on the output queue of the transport
+ * to make sure the reply fits.  This function reduces that reserved
+ * space to be the amount of space used already, plus @space.
+ *
+ */
+void svc_reserve(struct svc_rqst *rqstp, int space)
+{
+       space += rqstp->rq_res.head[0].iov_len;
+
+       if (space < rqstp->rq_reserved) {
+               struct svc_xprt *xprt = rqstp->rq_xprt;
+               atomic_sub((rqstp->rq_reserved - space), &xprt->xpt_reserved);
+               rqstp->rq_reserved = space;
+
+               svc_xprt_enqueue(xprt);
+       }
+}
+EXPORT_SYMBOL(svc_reserve);
+
+static void svc_xprt_release(struct svc_rqst *rqstp)
+{
+       struct svc_xprt *xprt = rqstp->rq_xprt;
+
+       rqstp->rq_xprt->xpt_ops->xpo_release_rqst(rqstp);
+
+       svc_free_res_pages(rqstp);
+       rqstp->rq_res.page_len = 0;
+       rqstp->rq_res.page_base = 0;
+
+       /* Reset response buffer and release
+        * the reservation.
+        * But first, check that enough space was reserved
+        * for the reply, otherwise we have a bug!
+        */
+       if ((rqstp->rq_res.len) >  rqstp->rq_reserved)
+               printk(KERN_ERR "RPC request reserved %d but used %d\n",
+                      rqstp->rq_reserved,
+                      rqstp->rq_res.len);
+
+       rqstp->rq_res.head[0].iov_len = 0;
+       svc_reserve(rqstp, 0);
+       rqstp->rq_xprt = NULL;
+
+       svc_xprt_put(xprt);
+}
+
+/*
+ * External function to wake up a server waiting for data
+ * This really only makes sense for services like lockd
+ * which have exactly one thread anyway.
+ */
+void svc_wake_up(struct svc_serv *serv)
+{
+       struct svc_rqst *rqstp;
+       unsigned int i;
+       struct svc_pool *pool;
+
+       for (i = 0; i < serv->sv_nrpools; i++) {
+               pool = &serv->sv_pools[i];
+
+               spin_lock_bh(&pool->sp_lock);
+               if (!list_empty(&pool->sp_threads)) {
+                       rqstp = list_entry(pool->sp_threads.next,
+                                          struct svc_rqst,
+                                          rq_list);
+                       dprintk("svc: daemon %p woken up.\n", rqstp);
+                       /*
+                       svc_thread_dequeue(pool, rqstp);
+                       rqstp->rq_xprt = NULL;
+                        */
+                       wake_up(&rqstp->rq_wait);
+               }
+               spin_unlock_bh(&pool->sp_lock);
+       }
+}
+EXPORT_SYMBOL(svc_wake_up);
+
+int svc_port_is_privileged(struct sockaddr *sin)
+{
+       switch (sin->sa_family) {
+       case AF_INET:
+               return ntohs(((struct sockaddr_in *)sin)->sin_port)
+                       < PROT_SOCK;
+       case AF_INET6:
+               return ntohs(((struct sockaddr_in6 *)sin)->sin6_port)
+                       < PROT_SOCK;
+       default:
+               return 0;
+       }
+}
+
+/*
+ * Make sure that we don't have too many active connections.  If we
+ * have, something must be dropped.
+ *
+ * There's no point in trying to do random drop here for DoS
+ * prevention. The NFS clients does 1 reconnect in 15 seconds. An
+ * attacker can easily beat that.
+ *
+ * The only somewhat efficient mechanism would be if drop old
+ * connections from the same IP first. But right now we don't even
+ * record the client IP in svc_sock.
+ */
+static void svc_check_conn_limits(struct svc_serv *serv)
+{
+       if (serv->sv_tmpcnt > (serv->sv_nrthreads+3)*20) {
+               struct svc_xprt *xprt = NULL;
+               spin_lock_bh(&serv->sv_lock);
+               if (!list_empty(&serv->sv_tempsocks)) {
+                       if (net_ratelimit()) {
+                               /* Try to help the admin */
+                               printk(KERN_NOTICE "%s: too many open  "
+                                      "connections, consider increasing the "
+                                      "number of nfsd threads\n",
+                                      serv->sv_name);
+                       }
+                       /*
+                        * Always select the oldest connection. It's not fair,
+                        * but so is life
+                        */
+                       xprt = list_entry(serv->sv_tempsocks.prev,
+                                         struct svc_xprt,
+                                         xpt_list);
+                       set_bit(XPT_CLOSE, &xprt->xpt_flags);
+                       svc_xprt_get(xprt);
+               }
+               spin_unlock_bh(&serv->sv_lock);
+
+               if (xprt) {
+                       svc_xprt_enqueue(xprt);
+                       svc_xprt_put(xprt);
+               }
+       }
+}
+
+/*
+ * Receive the next request on any transport.  This code is carefully
+ * organised not to touch any cachelines in the shared svc_serv
+ * structure, only cachelines in the local svc_pool.
+ */
+int svc_recv(struct svc_rqst *rqstp, long timeout)
+{
+       struct svc_xprt         *xprt = NULL;
+       struct svc_serv         *serv = rqstp->rq_server;
+       struct svc_pool         *pool = rqstp->rq_pool;
+       int                     len, i;
+       int                     pages;
+       struct xdr_buf          *arg;
+       DECLARE_WAITQUEUE(wait, current);
+
+       dprintk("svc: server %p waiting for data (to = %ld)\n",
+               rqstp, timeout);
+
+       if (rqstp->rq_xprt)
+               printk(KERN_ERR
+                       "svc_recv: service %p, transport not NULL!\n",
+                        rqstp);
+       if (waitqueue_active(&rqstp->rq_wait))
+               printk(KERN_ERR
+                       "svc_recv: service %p, wait queue active!\n",
+                        rqstp);
+
+       /* now allocate needed pages.  If we get a failure, sleep briefly */
+       pages = (serv->sv_max_mesg + PAGE_SIZE) / PAGE_SIZE;
+       for (i = 0; i < pages ; i++)
+               while (rqstp->rq_pages[i] == NULL) {
+                       struct page *p = alloc_page(GFP_KERNEL);
+                       if (!p) {
+                               int j = msecs_to_jiffies(500);
+                               schedule_timeout_uninterruptible(j);
+                       }
+                       rqstp->rq_pages[i] = p;
+               }
+       rqstp->rq_pages[i++] = NULL; /* this might be seen in nfs_read_actor */
+       BUG_ON(pages >= RPCSVC_MAXPAGES);
+
+       /* Make arg->head point to first page and arg->pages point to rest */
+       arg = &rqstp->rq_arg;
+       arg->head[0].iov_base = page_address(rqstp->rq_pages[0]);
+       arg->head[0].iov_len = PAGE_SIZE;
+       arg->pages = rqstp->rq_pages + 1;
+       arg->page_base = 0;
+       /* save at least one page for response */
+       arg->page_len = (pages-2)*PAGE_SIZE;
+       arg->len = (pages-1)*PAGE_SIZE;
+       arg->tail[0].iov_len = 0;
+
+       try_to_freeze();
+       cond_resched();
+       if (signalled())
+               return -EINTR;
+
+       spin_lock_bh(&pool->sp_lock);
+       xprt = svc_xprt_dequeue(pool);
+       if (xprt) {
+               rqstp->rq_xprt = xprt;
+               svc_xprt_get(xprt);
+               rqstp->rq_reserved = serv->sv_max_mesg;
+               atomic_add(rqstp->rq_reserved, &xprt->xpt_reserved);
+       } else {
+               /* No data pending. Go to sleep */
+               svc_thread_enqueue(pool, rqstp);
+
+               /*
+                * We have to be able to interrupt this wait
+                * to bring down the daemons ...
+                */
+               set_current_state(TASK_INTERRUPTIBLE);
+               add_wait_queue(&rqstp->rq_wait, &wait);
+               spin_unlock_bh(&pool->sp_lock);
+
+               schedule_timeout(timeout);
+
+               try_to_freeze();
+
+               spin_lock_bh(&pool->sp_lock);
+               remove_wait_queue(&rqstp->rq_wait, &wait);
+
+               xprt = rqstp->rq_xprt;
+               if (!xprt) {
+                       svc_thread_dequeue(pool, rqstp);
+                       spin_unlock_bh(&pool->sp_lock);
+                       dprintk("svc: server %p, no data yet\n", rqstp);
+                       return signalled()? -EINTR : -EAGAIN;
+               }
+       }
+       spin_unlock_bh(&pool->sp_lock);
+
+       len = 0;
+       if (test_bit(XPT_CLOSE, &xprt->xpt_flags)) {
+               dprintk("svc_recv: found XPT_CLOSE\n");
+               svc_delete_xprt(xprt);
+       } else if (test_bit(XPT_LISTENER, &xprt->xpt_flags)) {
+               struct svc_xprt *newxpt;
+               newxpt = xprt->xpt_ops->xpo_accept(xprt);
+               if (newxpt) {
+                       /*
+                        * We know this module_get will succeed because the
+                        * listener holds a reference too
+                        */
+                       __module_get(newxpt->xpt_class->xcl_owner);
+                       svc_check_conn_limits(xprt->xpt_server);
+                       spin_lock_bh(&serv->sv_lock);
+                       set_bit(XPT_TEMP, &newxpt->xpt_flags);
+                       list_add(&newxpt->xpt_list, &serv->sv_tempsocks);
+                       serv->sv_tmpcnt++;
+                       if (serv->sv_temptimer.function == NULL) {
+                               /* setup timer to age temp transports */
+                               setup_timer(&serv->sv_temptimer,
+                                           svc_age_temp_xprts,
+                                           (unsigned long)serv);
+                               mod_timer(&serv->sv_temptimer,
+                                         jiffies + svc_conn_age_period * HZ);
+                       }
+                       spin_unlock_bh(&serv->sv_lock);
+                       svc_xprt_received(newxpt);
+               }
+               svc_xprt_received(xprt);
+       } else {
+               dprintk("svc: server %p, pool %u, transport %p, inuse=%d\n",
+                       rqstp, pool->sp_id, xprt,
+                       atomic_read(&xprt->xpt_ref.refcount));
+               rqstp->rq_deferred = svc_deferred_dequeue(xprt);
+               if (rqstp->rq_deferred) {
+                       svc_xprt_received(xprt);
+                       len = svc_deferred_recv(rqstp);
+               } else
+                       len = xprt->xpt_ops->xpo_recvfrom(rqstp);
+               dprintk("svc: got len=%d\n", len);
+       }
+
+       /* No data, incomplete (TCP) read, or accept() */
+       if (len == 0 || len == -EAGAIN) {
+               rqstp->rq_res.len = 0;
+               svc_xprt_release(rqstp);
+               return -EAGAIN;
+       }
+       clear_bit(XPT_OLD, &xprt->xpt_flags);
+
+       rqstp->rq_secure = svc_port_is_privileged(svc_addr(rqstp));
+       rqstp->rq_chandle.defer = svc_defer;
+
+       if (serv->sv_stats)
+               serv->sv_stats->netcnt++;
+       return len;
+}
+EXPORT_SYMBOL(svc_recv);
+
+/*
+ * Drop request
+ */
+void svc_drop(struct svc_rqst *rqstp)
+{
+       dprintk("svc: xprt %p dropped request\n", rqstp->rq_xprt);
+       svc_xprt_release(rqstp);
+}
+EXPORT_SYMBOL(svc_drop);
+
+/*
+ * Return reply to client.
+ */
+int svc_send(struct svc_rqst *rqstp)
+{
+       struct svc_xprt *xprt;
+       int             len;
+       struct xdr_buf  *xb;
+
+       xprt = rqstp->rq_xprt;
+       if (!xprt)
+               return -EFAULT;
+
+       /* release the receive skb before sending the reply */
+       rqstp->rq_xprt->xpt_ops->xpo_release_rqst(rqstp);
+
+       /* calculate over-all length */
+       xb = &rqstp->rq_res;
+       xb->len = xb->head[0].iov_len +
+               xb->page_len +
+               xb->tail[0].iov_len;
+
+       /* Grab mutex to serialize outgoing data. */
+       mutex_lock(&xprt->xpt_mutex);
+       if (test_bit(XPT_DEAD, &xprt->xpt_flags))
+               len = -ENOTCONN;
+       else
+               len = xprt->xpt_ops->xpo_sendto(rqstp);
+       mutex_unlock(&xprt->xpt_mutex);
+       svc_xprt_release(rqstp);
+
+       if (len == -ECONNREFUSED || len == -ENOTCONN || len == -EAGAIN)
+               return 0;
+       return len;
+}
+
+/*
+ * Timer function to close old temporary transports, using
+ * a mark-and-sweep algorithm.
+ */
+static void svc_age_temp_xprts(unsigned long closure)
+{
+       struct svc_serv *serv = (struct svc_serv *)closure;
+       struct svc_xprt *xprt;
+       struct list_head *le, *next;
+       LIST_HEAD(to_be_aged);
+
+       dprintk("svc_age_temp_xprts\n");
+
+       if (!spin_trylock_bh(&serv->sv_lock)) {
+               /* busy, try again 1 sec later */
+               dprintk("svc_age_temp_xprts: busy\n");
+               mod_timer(&serv->sv_temptimer, jiffies + HZ);
+               return;
+       }
+
+       list_for_each_safe(le, next, &serv->sv_tempsocks) {
+               xprt = list_entry(le, struct svc_xprt, xpt_list);
+
+               /* First time through, just mark it OLD. Second time
+                * through, close it. */
+               if (!test_and_set_bit(XPT_OLD, &xprt->xpt_flags))
+                       continue;
+               if (atomic_read(&xprt->xpt_ref.refcount) > 1
+                   || test_bit(XPT_BUSY, &xprt->xpt_flags))
+                       continue;
+               svc_xprt_get(xprt);
+               list_move(le, &to_be_aged);
+               set_bit(XPT_CLOSE, &xprt->xpt_flags);
+               set_bit(XPT_DETACHED, &xprt->xpt_flags);
+       }
+       spin_unlock_bh(&serv->sv_lock);
+
+       while (!list_empty(&to_be_aged)) {
+               le = to_be_aged.next;
+               /* fiddling the xpt_list node is safe 'cos we're XPT_DETACHED */
+               list_del_init(le);
+               xprt = list_entry(le, struct svc_xprt, xpt_list);
+
+               dprintk("queuing xprt %p for closing\n", xprt);
+
+               /* a thread will dequeue and close it soon */
+               svc_xprt_enqueue(xprt);
+               svc_xprt_put(xprt);
+       }
+
+       mod_timer(&serv->sv_temptimer, jiffies + svc_conn_age_period * HZ);
+}
+
+/*
+ * Remove a dead transport
+ */
+void svc_delete_xprt(struct svc_xprt *xprt)
+{
+       struct svc_serv *serv = xprt->xpt_server;
+
+       dprintk("svc: svc_delete_xprt(%p)\n", xprt);
+       xprt->xpt_ops->xpo_detach(xprt);
+
+       spin_lock_bh(&serv->sv_lock);
+       if (!test_and_set_bit(XPT_DETACHED, &xprt->xpt_flags))
+               list_del_init(&xprt->xpt_list);
+       /*
+        * We used to delete the transport from whichever list
+        * it's sk_xprt.xpt_ready node was on, but we don't actually
+        * need to.  This is because the only time we're called
+        * while still attached to a queue, the queue itself
+        * is about to be destroyed (in svc_destroy).
+        */
+       if (!test_and_set_bit(XPT_DEAD, &xprt->xpt_flags)) {
+               BUG_ON(atomic_read(&xprt->xpt_ref.refcount) < 2);
+               if (test_bit(XPT_TEMP, &xprt->xpt_flags))
+                       serv->sv_tmpcnt--;
+               svc_xprt_put(xprt);
+       }
+       spin_unlock_bh(&serv->sv_lock);
+}
+
+void svc_close_xprt(struct svc_xprt *xprt)
+{
+       set_bit(XPT_CLOSE, &xprt->xpt_flags);
+       if (test_and_set_bit(XPT_BUSY, &xprt->xpt_flags))
+               /* someone else will have to effect the close */
+               return;
+
+       svc_xprt_get(xprt);
+       svc_delete_xprt(xprt);
+       clear_bit(XPT_BUSY, &xprt->xpt_flags);
+       svc_xprt_put(xprt);
+}
+EXPORT_SYMBOL_GPL(svc_close_xprt);
+
+void svc_close_all(struct list_head *xprt_list)
+{
+       struct svc_xprt *xprt;
+       struct svc_xprt *tmp;
+
+       list_for_each_entry_safe(xprt, tmp, xprt_list, xpt_list) {
+               set_bit(XPT_CLOSE, &xprt->xpt_flags);
+               if (test_bit(XPT_BUSY, &xprt->xpt_flags)) {
+                       /* Waiting to be processed, but no threads left,
+                        * So just remove it from the waiting list
+                        */
+                       list_del_init(&xprt->xpt_ready);
+                       clear_bit(XPT_BUSY, &xprt->xpt_flags);
+               }
+               svc_close_xprt(xprt);
+       }
+}
+
+/*
+ * Handle defer and revisit of requests
+ */
+
+static void svc_revisit(struct cache_deferred_req *dreq, int too_many)
+{
+       struct svc_deferred_req *dr =
+               container_of(dreq, struct svc_deferred_req, handle);
+       struct svc_xprt *xprt = dr->xprt;
+
+       if (too_many) {
+               svc_xprt_put(xprt);
+               kfree(dr);
+               return;
+       }
+       dprintk("revisit queued\n");
+       dr->xprt = NULL;
+       spin_lock(&xprt->xpt_lock);
+       list_add(&dr->handle.recent, &xprt->xpt_deferred);
+       spin_unlock(&xprt->xpt_lock);
+       set_bit(XPT_DEFERRED, &xprt->xpt_flags);
+       svc_xprt_enqueue(xprt);
+       svc_xprt_put(xprt);
+}
+
+/*
+ * Save the request off for later processing. The request buffer looks
+ * like this:
+ *
+ * <xprt-header><rpc-header><rpc-pagelist><rpc-tail>
+ *
+ * This code can only handle requests that consist of an xprt-header
+ * and rpc-header.
+ */
+static struct cache_deferred_req *svc_defer(struct cache_req *req)
+{
+       struct svc_rqst *rqstp = container_of(req, struct svc_rqst, rq_chandle);
+       struct svc_deferred_req *dr;
+
+       if (rqstp->rq_arg.page_len)
+               return NULL; /* if more than a page, give up FIXME */
+       if (rqstp->rq_deferred) {
+               dr = rqstp->rq_deferred;
+               rqstp->rq_deferred = NULL;
+       } else {
+               size_t skip;
+               size_t size;
+               /* FIXME maybe discard if size too large */
+               size = sizeof(struct svc_deferred_req) + rqstp->rq_arg.len;
+               dr = kmalloc(size, GFP_KERNEL);
+               if (dr == NULL)
+                       return NULL;
+
+               dr->handle.owner = rqstp->rq_server;
+               dr->prot = rqstp->rq_prot;
+               memcpy(&dr->addr, &rqstp->rq_addr, rqstp->rq_addrlen);
+               dr->addrlen = rqstp->rq_addrlen;
+               dr->daddr = rqstp->rq_daddr;
+               dr->argslen = rqstp->rq_arg.len >> 2;
+               dr->xprt_hlen = rqstp->rq_xprt_hlen;
+
+               /* back up head to the start of the buffer and copy */
+               skip = rqstp->rq_arg.len - rqstp->rq_arg.head[0].iov_len;
+               memcpy(dr->args, rqstp->rq_arg.head[0].iov_base - skip,
+                      dr->argslen << 2);
+       }
+       svc_xprt_get(rqstp->rq_xprt);
+       dr->xprt = rqstp->rq_xprt;
+
+       dr->handle.revisit = svc_revisit;
+       return &dr->handle;
+}
+
+/*
+ * recv data from a deferred request into an active one
+ */
+static int svc_deferred_recv(struct svc_rqst *rqstp)
+{
+       struct svc_deferred_req *dr = rqstp->rq_deferred;
+
+       /* setup iov_base past transport header */
+       rqstp->rq_arg.head[0].iov_base = dr->args + (dr->xprt_hlen>>2);
+       /* The iov_len does not include the transport header bytes */
+       rqstp->rq_arg.head[0].iov_len = (dr->argslen<<2) - dr->xprt_hlen;
+       rqstp->rq_arg.page_len = 0;
+       /* The rq_arg.len includes the transport header bytes */
+       rqstp->rq_arg.len     = dr->argslen<<2;
+       rqstp->rq_prot        = dr->prot;
+       memcpy(&rqstp->rq_addr, &dr->addr, dr->addrlen);
+       rqstp->rq_addrlen     = dr->addrlen;
+       /* Save off transport header len in case we get deferred again */
+       rqstp->rq_xprt_hlen   = dr->xprt_hlen;
+       rqstp->rq_daddr       = dr->daddr;
+       rqstp->rq_respages    = rqstp->rq_pages;
+       return (dr->argslen<<2) - dr->xprt_hlen;
+}
+
+
+static struct svc_deferred_req *svc_deferred_dequeue(struct svc_xprt *xprt)
+{
+       struct svc_deferred_req *dr = NULL;
+
+       if (!test_bit(XPT_DEFERRED, &xprt->xpt_flags))
+               return NULL;
+       spin_lock(&xprt->xpt_lock);
+       clear_bit(XPT_DEFERRED, &xprt->xpt_flags);
+       if (!list_empty(&xprt->xpt_deferred)) {
+               dr = list_entry(xprt->xpt_deferred.next,
+                               struct svc_deferred_req,
+                               handle.recent);
+               list_del_init(&dr->handle.recent);
+               set_bit(XPT_DEFERRED, &xprt->xpt_flags);
+       }
+       spin_unlock(&xprt->xpt_lock);
+       return dr;
+}
+
+/*
+ * Return the transport instance pointer for the endpoint accepting
+ * connections/peer traffic from the specified transport class,
+ * address family and port.
+ *
+ * Specifying 0 for the address family or port is effectively a
+ * wild-card, and will result in matching the first transport in the
+ * service's list that has a matching class name.
+ */
+struct svc_xprt *svc_find_xprt(struct svc_serv *serv, char *xcl_name,
+                              int af, int port)
+{
+       struct svc_xprt *xprt;
+       struct svc_xprt *found = NULL;
+
+       /* Sanity check the args */
+       if (!serv || !xcl_name)
+               return found;
+
+       spin_lock_bh(&serv->sv_lock);
+       list_for_each_entry(xprt, &serv->sv_permsocks, xpt_list) {
+               if (strcmp(xprt->xpt_class->xcl_name, xcl_name))
+                       continue;
+               if (af != AF_UNSPEC && af != xprt->xpt_local.ss_family)
+                       continue;
+               if (port && port != svc_xprt_local_port(xprt))
+                       continue;
+               found = xprt;
+               svc_xprt_get(xprt);
+               break;
+       }
+       spin_unlock_bh(&serv->sv_lock);
+       return found;
+}
+EXPORT_SYMBOL_GPL(svc_find_xprt);
+
+/*
+ * Format a buffer with a list of the active transports. A zero for
+ * the buflen parameter disables target buffer overflow checking.
+ */
+int svc_xprt_names(struct svc_serv *serv, char *buf, int buflen)
+{
+       struct svc_xprt *xprt;
+       char xprt_str[64];
+       int totlen = 0;
+       int len;
+
+       /* Sanity check args */
+       if (!serv)
+               return 0;
+
+       spin_lock_bh(&serv->sv_lock);
+       list_for_each_entry(xprt, &serv->sv_permsocks, xpt_list) {
+               len = snprintf(xprt_str, sizeof(xprt_str),
+                              "%s %d\n", xprt->xpt_class->xcl_name,
+                              svc_xprt_local_port(xprt));
+               /* If the string was truncated, replace with error string */
+               if (len >= sizeof(xprt_str))
+                       strcpy(xprt_str, "name-too-long\n");
+               /* Don't overflow buffer */
+               len = strlen(xprt_str);
+               if (buflen && (len + totlen >= buflen))
+                       break;
+               strcpy(buf+totlen, xprt_str);
+               totlen += len;
+       }
+       spin_unlock_bh(&serv->sv_lock);
+       return totlen;
+}
+EXPORT_SYMBOL_GPL(svc_xprt_names);
index af7c5f05c6e11b3d5d734d1ee2143e54c71517bb..8a73cbb16052397b0455070cfc670a931ff2ec8f 100644 (file)
@@ -57,11 +57,13 @@ svc_authenticate(struct svc_rqst *rqstp, __be32 *authp)
        rqstp->rq_authop = aops;
        return aops->accept(rqstp, authp);
 }
+EXPORT_SYMBOL(svc_authenticate);
 
 int svc_set_client(struct svc_rqst *rqstp)
 {
        return rqstp->rq_authop->set_client(rqstp);
 }
+EXPORT_SYMBOL(svc_set_client);
 
 /* A request, which was authenticated, has now executed.
  * Time to finalise the credentials and verifier
@@ -93,6 +95,7 @@ svc_auth_register(rpc_authflavor_t flavor, struct auth_ops *aops)
        spin_unlock(&authtab_lock);
        return rv;
 }
+EXPORT_SYMBOL(svc_auth_register);
 
 void
 svc_auth_unregister(rpc_authflavor_t flavor)
@@ -129,6 +132,7 @@ void auth_domain_put(struct auth_domain *dom)
                spin_unlock(&auth_domain_lock);
        }
 }
+EXPORT_SYMBOL(auth_domain_put);
 
 struct auth_domain *
 auth_domain_lookup(char *name, struct auth_domain *new)
@@ -153,8 +157,10 @@ auth_domain_lookup(char *name, struct auth_domain *new)
        spin_unlock(&auth_domain_lock);
        return new;
 }
+EXPORT_SYMBOL(auth_domain_lookup);
 
 struct auth_domain *auth_domain_find(char *name)
 {
        return auth_domain_lookup(name, NULL);
 }
+EXPORT_SYMBOL(auth_domain_find);
index 411479411b21052a3e138c5109880abd881b77b4..3c64051e455533aeb11df479f3c72877838e4483 100644 (file)
@@ -63,6 +63,7 @@ struct auth_domain *unix_domain_find(char *name)
                rv = auth_domain_lookup(name, &new->h);
        }
 }
+EXPORT_SYMBOL(unix_domain_find);
 
 static void svcauth_unix_domain_release(struct auth_domain *dom)
 {
@@ -340,6 +341,7 @@ int auth_unix_add_addr(struct in_addr addr, struct auth_domain *dom)
        else
                return -ENOMEM;
 }
+EXPORT_SYMBOL(auth_unix_add_addr);
 
 int auth_unix_forget_old(struct auth_domain *dom)
 {
@@ -351,6 +353,7 @@ int auth_unix_forget_old(struct auth_domain *dom)
        udom->addr_changes++;
        return 0;
 }
+EXPORT_SYMBOL(auth_unix_forget_old);
 
 struct auth_domain *auth_unix_lookup(struct in_addr addr)
 {
@@ -375,50 +378,56 @@ struct auth_domain *auth_unix_lookup(struct in_addr addr)
        cache_put(&ipm->h, &ip_map_cache);
        return rv;
 }
+EXPORT_SYMBOL(auth_unix_lookup);
 
 void svcauth_unix_purge(void)
 {
        cache_purge(&ip_map_cache);
 }
+EXPORT_SYMBOL(svcauth_unix_purge);
 
 static inline struct ip_map *
 ip_map_cached_get(struct svc_rqst *rqstp)
 {
-       struct ip_map *ipm;
-       struct svc_sock *svsk = rqstp->rq_sock;
-       spin_lock(&svsk->sk_lock);
-       ipm = svsk->sk_info_authunix;
-       if (ipm != NULL) {
-               if (!cache_valid(&ipm->h)) {
-                       /*
-                        * The entry has been invalidated since it was
-                        * remembered, e.g. by a second mount from the
-                        * same IP address.
-                        */
-                       svsk->sk_info_authunix = NULL;
-                       spin_unlock(&svsk->sk_lock);
-                       cache_put(&ipm->h, &ip_map_cache);
-                       return NULL;
+       struct ip_map *ipm = NULL;
+       struct svc_xprt *xprt = rqstp->rq_xprt;
+
+       if (test_bit(XPT_CACHE_AUTH, &xprt->xpt_flags)) {
+               spin_lock(&xprt->xpt_lock);
+               ipm = xprt->xpt_auth_cache;
+               if (ipm != NULL) {
+                       if (!cache_valid(&ipm->h)) {
+                               /*
+                                * The entry has been invalidated since it was
+                                * remembered, e.g. by a second mount from the
+                                * same IP address.
+                                */
+                               xprt->xpt_auth_cache = NULL;
+                               spin_unlock(&xprt->xpt_lock);
+                               cache_put(&ipm->h, &ip_map_cache);
+                               return NULL;
+                       }
+                       cache_get(&ipm->h);
                }
-               cache_get(&ipm->h);
+               spin_unlock(&xprt->xpt_lock);
        }
-       spin_unlock(&svsk->sk_lock);
        return ipm;
 }
 
 static inline void
 ip_map_cached_put(struct svc_rqst *rqstp, struct ip_map *ipm)
 {
-       struct svc_sock *svsk = rqstp->rq_sock;
+       struct svc_xprt *xprt = rqstp->rq_xprt;
 
-       spin_lock(&svsk->sk_lock);
-       if (svsk->sk_sock->type == SOCK_STREAM &&
-           svsk->sk_info_authunix == NULL) {
-               /* newly cached, keep the reference */
-               svsk->sk_info_authunix = ipm;
-               ipm = NULL;
+       if (test_bit(XPT_CACHE_AUTH, &xprt->xpt_flags)) {
+               spin_lock(&xprt->xpt_lock);
+               if (xprt->xpt_auth_cache == NULL) {
+                       /* newly cached, keep the reference */
+                       xprt->xpt_auth_cache = ipm;
+                       ipm = NULL;
+               }
+               spin_unlock(&xprt->xpt_lock);
        }
-       spin_unlock(&svsk->sk_lock);
        if (ipm)
                cache_put(&ipm->h, &ip_map_cache);
 }
index c75bffeb89eb705831585ba1447c0ba77dd06a9c..1d3e5fcc2cc4d0728f4d99c39d28ecd1fb9a2d80 100644 (file)
@@ -5,7 +5,7 @@
  *
  * The server scheduling algorithm does not always distribute the load
  * evenly when servicing a single client. May need to modify the
- * svc_sock_enqueue procedure...
+ * svc_xprt_enqueue procedure...
  *
  * TCP support is largely untested and may be a little slow. The problem
  * is that we currently do two separate recvfrom's, one for the 4-byte
 #include <linux/sunrpc/svcsock.h>
 #include <linux/sunrpc/stats.h>
 
-/* SMP locking strategy:
- *
- *     svc_pool->sp_lock protects most of the fields of that pool.
- *     svc_serv->sv_lock protects sv_tempsocks, sv_permsocks, sv_tmpcnt.
- *     when both need to be taken (rare), svc_serv->sv_lock is first.
- *     BKL protects svc_serv->sv_nrthread.
- *     svc_sock->sk_lock protects the svc_sock->sk_deferred list
- *             and the ->sk_info_authunix cache.
- *     svc_sock->sk_flags.SK_BUSY prevents a svc_sock being enqueued multiply.
- *
- *     Some flags can be set to certain values at any time
- *     providing that certain rules are followed:
- *
- *     SK_CONN, SK_DATA, can be set or cleared at any time.
- *             after a set, svc_sock_enqueue must be called.
- *             after a clear, the socket must be read/accepted
- *              if this succeeds, it must be set again.
- *     SK_CLOSE can set at any time. It is never cleared.
- *      sk_inuse contains a bias of '1' until SK_DEAD is set.
- *             so when sk_inuse hits zero, we know the socket is dead
- *             and no-one is using it.
- *      SK_DEAD can only be set while SK_BUSY is held which ensures
- *             no other thread will be using the socket or will try to
- *            set SK_DEAD.
- *
- */
-
-#define RPCDBG_FACILITY        RPCDBG_SVCSOCK
+#define RPCDBG_FACILITY        RPCDBG_SVCXPRT
 
 
 static struct svc_sock *svc_setup_socket(struct svc_serv *, struct socket *,
                                         int *errp, int flags);
-static void            svc_delete_socket(struct svc_sock *svsk);
 static void            svc_udp_data_ready(struct sock *, int);
 static int             svc_udp_recvfrom(struct svc_rqst *);
 static int             svc_udp_sendto(struct svc_rqst *);
-static void            svc_close_socket(struct svc_sock *svsk);
-
-static struct svc_deferred_req *svc_deferred_dequeue(struct svc_sock *svsk);
-static int svc_deferred_recv(struct svc_rqst *rqstp);
-static struct cache_deferred_req *svc_defer(struct cache_req *req);
-
-/* apparently the "standard" is that clients close
- * idle connections after 5 minutes, servers after
- * 6 minutes
- *   http://www.connectathon.org/talks96/nfstcp.pdf
- */
-static int svc_conn_age_period = 6*60;
+static void            svc_sock_detach(struct svc_xprt *);
+static void            svc_sock_free(struct svc_xprt *);
 
+static struct svc_xprt *svc_create_socket(struct svc_serv *, int,
+                                         struct sockaddr *, int, int);
 #ifdef CONFIG_DEBUG_LOCK_ALLOC
 static struct lock_class_key svc_key[2];
 static struct lock_class_key svc_slock_key[2];
 
-static inline void svc_reclassify_socket(struct socket *sock)
+static void svc_reclassify_socket(struct socket *sock)
 {
        struct sock *sk = sock->sk;
        BUG_ON(sock_owned_by_user(sk));
        switch (sk->sk_family) {
        case AF_INET:
                sock_lock_init_class_and_name(sk, "slock-AF_INET-NFSD",
-                   &svc_slock_key[0], "sk_lock-AF_INET-NFSD", &svc_key[0]);
+                                             &svc_slock_key[0],
+                                             "sk_xprt.xpt_lock-AF_INET-NFSD",
+                                             &svc_key[0]);
                break;
 
        case AF_INET6:
                sock_lock_init_class_and_name(sk, "slock-AF_INET6-NFSD",
-                   &svc_slock_key[1], "sk_lock-AF_INET6-NFSD", &svc_key[1]);
+                                             &svc_slock_key[1],
+                                             "sk_xprt.xpt_lock-AF_INET6-NFSD",
+                                             &svc_key[1]);
                break;
 
        default:
@@ -121,81 +89,26 @@ static inline void svc_reclassify_socket(struct socket *sock)
        }
 }
 #else
-static inline void svc_reclassify_socket(struct socket *sock)
+static void svc_reclassify_socket(struct socket *sock)
 {
 }
 #endif
 
-static char *__svc_print_addr(struct sockaddr *addr, char *buf, size_t len)
-{
-       switch (addr->sa_family) {
-       case AF_INET:
-               snprintf(buf, len, "%u.%u.%u.%u, port=%u",
-                       NIPQUAD(((struct sockaddr_in *) addr)->sin_addr),
-                       ntohs(((struct sockaddr_in *) addr)->sin_port));
-               break;
-
-       case AF_INET6:
-               snprintf(buf, len, "%x:%x:%x:%x:%x:%x:%x:%x, port=%u",
-                       NIP6(((struct sockaddr_in6 *) addr)->sin6_addr),
-                       ntohs(((struct sockaddr_in6 *) addr)->sin6_port));
-               break;
-
-       default:
-               snprintf(buf, len, "unknown address type: %d", addr->sa_family);
-               break;
-       }
-       return buf;
-}
-
-/**
- * svc_print_addr - Format rq_addr field for printing
- * @rqstp: svc_rqst struct containing address to print
- * @buf: target buffer for formatted address
- * @len: length of target buffer
- *
- */
-char *svc_print_addr(struct svc_rqst *rqstp, char *buf, size_t len)
-{
-       return __svc_print_addr(svc_addr(rqstp), buf, len);
-}
-EXPORT_SYMBOL_GPL(svc_print_addr);
-
-/*
- * Queue up an idle server thread.  Must have pool->sp_lock held.
- * Note: this is really a stack rather than a queue, so that we only
- * use as many different threads as we need, and the rest don't pollute
- * the cache.
- */
-static inline void
-svc_thread_enqueue(struct svc_pool *pool, struct svc_rqst *rqstp)
-{
-       list_add(&rqstp->rq_list, &pool->sp_threads);
-}
-
-/*
- * Dequeue an nfsd thread.  Must have pool->sp_lock held.
- */
-static inline void
-svc_thread_dequeue(struct svc_pool *pool, struct svc_rqst *rqstp)
-{
-       list_del(&rqstp->rq_list);
-}
-
 /*
  * Release an skbuff after use
  */
-static inline void
-svc_release_skb(struct svc_rqst *rqstp)
+static void svc_release_skb(struct svc_rqst *rqstp)
 {
-       struct sk_buff *skb = rqstp->rq_skbuff;
+       struct sk_buff *skb = rqstp->rq_xprt_ctxt;
        struct svc_deferred_req *dr = rqstp->rq_deferred;
 
        if (skb) {
-               rqstp->rq_skbuff = NULL;
+               struct svc_sock *svsk =
+                       container_of(rqstp->rq_xprt, struct svc_sock, sk_xprt);
+               rqstp->rq_xprt_ctxt = NULL;
 
                dprintk("svc: service %p, releasing skb %p\n", rqstp, skb);
-               skb_free_datagram(rqstp->rq_sock->sk_sk, skb);
+               skb_free_datagram(svsk->sk_sk, skb);
        }
        if (dr) {
                rqstp->rq_deferred = NULL;
@@ -203,253 +116,6 @@ svc_release_skb(struct svc_rqst *rqstp)
        }
 }
 
-/*
- * Any space to write?
- */
-static inline unsigned long
-svc_sock_wspace(struct svc_sock *svsk)
-{
-       int wspace;
-
-       if (svsk->sk_sock->type == SOCK_STREAM)
-               wspace = sk_stream_wspace(svsk->sk_sk);
-       else
-               wspace = sock_wspace(svsk->sk_sk);
-
-       return wspace;
-}
-
-/*
- * Queue up a socket with data pending. If there are idle nfsd
- * processes, wake 'em up.
- *
- */
-static void
-svc_sock_enqueue(struct svc_sock *svsk)
-{
-       struct svc_serv *serv = svsk->sk_server;
-       struct svc_pool *pool;
-       struct svc_rqst *rqstp;
-       int cpu;
-
-       if (!(svsk->sk_flags &
-             ( (1<<SK_CONN)|(1<<SK_DATA)|(1<<SK_CLOSE)|(1<<SK_DEFERRED)) ))
-               return;
-       if (test_bit(SK_DEAD, &svsk->sk_flags))
-               return;
-
-       cpu = get_cpu();
-       pool = svc_pool_for_cpu(svsk->sk_server, cpu);
-       put_cpu();
-
-       spin_lock_bh(&pool->sp_lock);
-
-       if (!list_empty(&pool->sp_threads) &&
-           !list_empty(&pool->sp_sockets))
-               printk(KERN_ERR
-                       "svc_sock_enqueue: threads and sockets both waiting??\n");
-
-       if (test_bit(SK_DEAD, &svsk->sk_flags)) {
-               /* Don't enqueue dead sockets */
-               dprintk("svc: socket %p is dead, not enqueued\n", svsk->sk_sk);
-               goto out_unlock;
-       }
-
-       /* Mark socket as busy. It will remain in this state until the
-        * server has processed all pending data and put the socket back
-        * on the idle list.  We update SK_BUSY atomically because
-        * it also guards against trying to enqueue the svc_sock twice.
-        */
-       if (test_and_set_bit(SK_BUSY, &svsk->sk_flags)) {
-               /* Don't enqueue socket while already enqueued */
-               dprintk("svc: socket %p busy, not enqueued\n", svsk->sk_sk);
-               goto out_unlock;
-       }
-       BUG_ON(svsk->sk_pool != NULL);
-       svsk->sk_pool = pool;
-
-       set_bit(SOCK_NOSPACE, &svsk->sk_sock->flags);
-       if (((atomic_read(&svsk->sk_reserved) + serv->sv_max_mesg)*2
-            > svc_sock_wspace(svsk))
-           && !test_bit(SK_CLOSE, &svsk->sk_flags)
-           && !test_bit(SK_CONN, &svsk->sk_flags)) {
-               /* Don't enqueue while not enough space for reply */
-               dprintk("svc: socket %p  no space, %d*2 > %ld, not enqueued\n",
-                       svsk->sk_sk, atomic_read(&svsk->sk_reserved)+serv->sv_max_mesg,
-                       svc_sock_wspace(svsk));
-               svsk->sk_pool = NULL;
-               clear_bit(SK_BUSY, &svsk->sk_flags);
-               goto out_unlock;
-       }
-       clear_bit(SOCK_NOSPACE, &svsk->sk_sock->flags);
-
-
-       if (!list_empty(&pool->sp_threads)) {
-               rqstp = list_entry(pool->sp_threads.next,
-                                  struct svc_rqst,
-                                  rq_list);
-               dprintk("svc: socket %p served by daemon %p\n",
-                       svsk->sk_sk, rqstp);
-               svc_thread_dequeue(pool, rqstp);
-               if (rqstp->rq_sock)
-                       printk(KERN_ERR
-                               "svc_sock_enqueue: server %p, rq_sock=%p!\n",
-                               rqstp, rqstp->rq_sock);
-               rqstp->rq_sock = svsk;
-               atomic_inc(&svsk->sk_inuse);
-               rqstp->rq_reserved = serv->sv_max_mesg;
-               atomic_add(rqstp->rq_reserved, &svsk->sk_reserved);
-               BUG_ON(svsk->sk_pool != pool);
-               wake_up(&rqstp->rq_wait);
-       } else {
-               dprintk("svc: socket %p put into queue\n", svsk->sk_sk);
-               list_add_tail(&svsk->sk_ready, &pool->sp_sockets);
-               BUG_ON(svsk->sk_pool != pool);
-       }
-
-out_unlock:
-       spin_unlock_bh(&pool->sp_lock);
-}
-
-/*
- * Dequeue the first socket.  Must be called with the pool->sp_lock held.
- */
-static inline struct svc_sock *
-svc_sock_dequeue(struct svc_pool *pool)
-{
-       struct svc_sock *svsk;
-
-       if (list_empty(&pool->sp_sockets))
-               return NULL;
-
-       svsk = list_entry(pool->sp_sockets.next,
-                         struct svc_sock, sk_ready);
-       list_del_init(&svsk->sk_ready);
-
-       dprintk("svc: socket %p dequeued, inuse=%d\n",
-               svsk->sk_sk, atomic_read(&svsk->sk_inuse));
-
-       return svsk;
-}
-
-/*
- * Having read something from a socket, check whether it
- * needs to be re-enqueued.
- * Note: SK_DATA only gets cleared when a read-attempt finds
- * no (or insufficient) data.
- */
-static inline void
-svc_sock_received(struct svc_sock *svsk)
-{
-       svsk->sk_pool = NULL;
-       clear_bit(SK_BUSY, &svsk->sk_flags);
-       svc_sock_enqueue(svsk);
-}
-
-
-/**
- * svc_reserve - change the space reserved for the reply to a request.
- * @rqstp:  The request in question
- * @space: new max space to reserve
- *
- * Each request reserves some space on the output queue of the socket
- * to make sure the reply fits.  This function reduces that reserved
- * space to be the amount of space used already, plus @space.
- *
- */
-void svc_reserve(struct svc_rqst *rqstp, int space)
-{
-       space += rqstp->rq_res.head[0].iov_len;
-
-       if (space < rqstp->rq_reserved) {
-               struct svc_sock *svsk = rqstp->rq_sock;
-               atomic_sub((rqstp->rq_reserved - space), &svsk->sk_reserved);
-               rqstp->rq_reserved = space;
-
-               svc_sock_enqueue(svsk);
-       }
-}
-
-/*
- * Release a socket after use.
- */
-static inline void
-svc_sock_put(struct svc_sock *svsk)
-{
-       if (atomic_dec_and_test(&svsk->sk_inuse)) {
-               BUG_ON(! test_bit(SK_DEAD, &svsk->sk_flags));
-
-               dprintk("svc: releasing dead socket\n");
-               if (svsk->sk_sock->file)
-                       sockfd_put(svsk->sk_sock);
-               else
-                       sock_release(svsk->sk_sock);
-               if (svsk->sk_info_authunix != NULL)
-                       svcauth_unix_info_release(svsk->sk_info_authunix);
-               kfree(svsk);
-       }
-}
-
-static void
-svc_sock_release(struct svc_rqst *rqstp)
-{
-       struct svc_sock *svsk = rqstp->rq_sock;
-
-       svc_release_skb(rqstp);
-
-       svc_free_res_pages(rqstp);
-       rqstp->rq_res.page_len = 0;
-       rqstp->rq_res.page_base = 0;
-
-
-       /* Reset response buffer and release
-        * the reservation.
-        * But first, check that enough space was reserved
-        * for the reply, otherwise we have a bug!
-        */
-       if ((rqstp->rq_res.len) >  rqstp->rq_reserved)
-               printk(KERN_ERR "RPC request reserved %d but used %d\n",
-                      rqstp->rq_reserved,
-                      rqstp->rq_res.len);
-
-       rqstp->rq_res.head[0].iov_len = 0;
-       svc_reserve(rqstp, 0);
-       rqstp->rq_sock = NULL;
-
-       svc_sock_put(svsk);
-}
-
-/*
- * External function to wake up a server waiting for data
- * This really only makes sense for services like lockd
- * which have exactly one thread anyway.
- */
-void
-svc_wake_up(struct svc_serv *serv)
-{
-       struct svc_rqst *rqstp;
-       unsigned int i;
-       struct svc_pool *pool;
-
-       for (i = 0; i < serv->sv_nrpools; i++) {
-               pool = &serv->sv_pools[i];
-
-               spin_lock_bh(&pool->sp_lock);
-               if (!list_empty(&pool->sp_threads)) {
-                       rqstp = list_entry(pool->sp_threads.next,
-                                          struct svc_rqst,
-                                          rq_list);
-                       dprintk("svc: daemon %p woken up.\n", rqstp);
-                       /*
-                       svc_thread_dequeue(pool, rqstp);
-                       rqstp->rq_sock = NULL;
-                        */
-                       wake_up(&rqstp->rq_wait);
-               }
-               spin_unlock_bh(&pool->sp_lock);
-       }
-}
-
 union svc_pktinfo_u {
        struct in_pktinfo pkti;
        struct in6_pktinfo pkti6;
@@ -459,7 +125,9 @@ union svc_pktinfo_u {
 
 static void svc_set_cmsg_data(struct svc_rqst *rqstp, struct cmsghdr *cmh)
 {
-       switch (rqstp->rq_sock->sk_sk->sk_family) {
+       struct svc_sock *svsk =
+               container_of(rqstp->rq_xprt, struct svc_sock, sk_xprt);
+       switch (svsk->sk_sk->sk_family) {
        case AF_INET: {
                        struct in_pktinfo *pki = CMSG_DATA(cmh);
 
@@ -489,10 +157,10 @@ static void svc_set_cmsg_data(struct svc_rqst *rqstp, struct cmsghdr *cmh)
 /*
  * Generic sendto routine
  */
-static int
-svc_sendto(struct svc_rqst *rqstp, struct xdr_buf *xdr)
+static int svc_sendto(struct svc_rqst *rqstp, struct xdr_buf *xdr)
 {
-       struct svc_sock *svsk = rqstp->rq_sock;
+       struct svc_sock *svsk =
+               container_of(rqstp->rq_xprt, struct svc_sock, sk_xprt);
        struct socket   *sock = svsk->sk_sock;
        int             slen;
        union {
@@ -565,7 +233,7 @@ svc_sendto(struct svc_rqst *rqstp, struct xdr_buf *xdr)
        }
 out:
        dprintk("svc: socket %p sendto([%p %Zu... ], %d) = %d (addr %s)\n",
-               rqstp->rq_sock, xdr->head[0].iov_base, xdr->head[0].iov_len,
+               svsk, xdr->head[0].iov_base, xdr->head[0].iov_len,
                xdr->len, len, svc_print_addr(rqstp, buf, sizeof(buf)));
 
        return len;
@@ -602,7 +270,7 @@ svc_sock_names(char *buf, struct svc_serv *serv, char *toclose)
        if (!serv)
                return 0;
        spin_lock_bh(&serv->sv_lock);
-       list_for_each_entry(svsk, &serv->sv_permsocks, sk_list) {
+       list_for_each_entry(svsk, &serv->sv_permsocks, sk_xprt.xpt_list) {
                int onelen = one_sock_name(buf+len, svsk);
                if (toclose && strcmp(toclose, buf+len) == 0)
                        closesk = svsk;
@@ -614,7 +282,7 @@ svc_sock_names(char *buf, struct svc_serv *serv, char *toclose)
                /* Should unregister with portmap, but you cannot
                 * unregister just one protocol...
                 */
-               svc_close_socket(closesk);
+               svc_close_xprt(&closesk->sk_xprt);
        else if (toclose)
                return -ENOENT;
        return len;
@@ -624,8 +292,7 @@ EXPORT_SYMBOL(svc_sock_names);
 /*
  * Check input queue length
  */
-static int
-svc_recv_available(struct svc_sock *svsk)
+static int svc_recv_available(struct svc_sock *svsk)
 {
        struct socket   *sock = svsk->sk_sock;
        int             avail, err;
@@ -638,48 +305,31 @@ svc_recv_available(struct svc_sock *svsk)
 /*
  * Generic recvfrom routine.
  */
-static int
-svc_recvfrom(struct svc_rqst *rqstp, struct kvec *iov, int nr, int buflen)
+static int svc_recvfrom(struct svc_rqst *rqstp, struct kvec *iov, int nr,
+                       int buflen)
 {
-       struct svc_sock *svsk = rqstp->rq_sock;
+       struct svc_sock *svsk =
+               container_of(rqstp->rq_xprt, struct svc_sock, sk_xprt);
        struct msghdr msg = {
                .msg_flags      = MSG_DONTWAIT,
        };
-       struct sockaddr *sin;
        int len;
 
+       rqstp->rq_xprt_hlen = 0;
+
        len = kernel_recvmsg(svsk->sk_sock, &msg, iov, nr, buflen,
                                msg.msg_flags);
 
-       /* sock_recvmsg doesn't fill in the name/namelen, so we must..
-        */
-       memcpy(&rqstp->rq_addr, &svsk->sk_remote, svsk->sk_remotelen);
-       rqstp->rq_addrlen = svsk->sk_remotelen;
-
-       /* Destination address in request is needed for binding the
-        * source address in RPC callbacks later.
-        */
-       sin = (struct sockaddr *)&svsk->sk_local;
-       switch (sin->sa_family) {
-       case AF_INET:
-               rqstp->rq_daddr.addr = ((struct sockaddr_in *)sin)->sin_addr;
-               break;
-       case AF_INET6:
-               rqstp->rq_daddr.addr6 = ((struct sockaddr_in6 *)sin)->sin6_addr;
-               break;
-       }
-
        dprintk("svc: socket %p recvfrom(%p, %Zu) = %d\n",
                svsk, iov[0].iov_base, iov[0].iov_len, len);
-
        return len;
 }
 
 /*
  * Set socket snd and rcv buffer lengths
  */
-static inline void
-svc_sock_setbufsize(struct socket *sock, unsigned int snd, unsigned int rcv)
+static void svc_sock_setbufsize(struct socket *sock, unsigned int snd,
+                               unsigned int rcv)
 {
 #if 0
        mm_segment_t    oldfs;
@@ -704,16 +354,16 @@ svc_sock_setbufsize(struct socket *sock, unsigned int snd, unsigned int rcv)
 /*
  * INET callback when data has been received on the socket.
  */
-static void
-svc_udp_data_ready(struct sock *sk, int count)
+static void svc_udp_data_ready(struct sock *sk, int count)
 {
        struct svc_sock *svsk = (struct svc_sock *)sk->sk_user_data;
 
        if (svsk) {
                dprintk("svc: socket %p(inet %p), count=%d, busy=%d\n",
-                       svsk, sk, count, test_bit(SK_BUSY, &svsk->sk_flags));
-               set_bit(SK_DATA, &svsk->sk_flags);
-               svc_sock_enqueue(svsk);
+                       svsk, sk, count,
+                       test_bit(XPT_BUSY, &svsk->sk_xprt.xpt_flags));
+               set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags);
+               svc_xprt_enqueue(&svsk->sk_xprt);
        }
        if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))
                wake_up_interruptible(sk->sk_sleep);
@@ -722,15 +372,14 @@ svc_udp_data_ready(struct sock *sk, int count)
 /*
  * INET callback when space is newly available on the socket.
  */
-static void
-svc_write_space(struct sock *sk)
+static void svc_write_space(struct sock *sk)
 {
        struct svc_sock *svsk = (struct svc_sock *)(sk->sk_user_data);
 
        if (svsk) {
                dprintk("svc: socket %p(inet %p), write_space busy=%d\n",
-                       svsk, sk, test_bit(SK_BUSY, &svsk->sk_flags));
-               svc_sock_enqueue(svsk);
+                       svsk, sk, test_bit(XPT_BUSY, &svsk->sk_xprt.xpt_flags));
+               svc_xprt_enqueue(&svsk->sk_xprt);
        }
 
        if (sk->sk_sleep && waitqueue_active(sk->sk_sleep)) {
@@ -740,10 +389,19 @@ svc_write_space(struct sock *sk)
        }
 }
 
-static inline void svc_udp_get_dest_address(struct svc_rqst *rqstp,
-                                           struct cmsghdr *cmh)
+/*
+ * Copy the UDP datagram's destination address to the rqstp structure.
+ * The 'destination' address in this case is the address to which the
+ * peer sent the datagram, i.e. our local address. For multihomed
+ * hosts, this can change from msg to msg. Note that only the IP
+ * address changes, the port number should remain the same.
+ */
+static void svc_udp_get_dest_address(struct svc_rqst *rqstp,
+                                    struct cmsghdr *cmh)
 {
-       switch (rqstp->rq_sock->sk_sk->sk_family) {
+       struct svc_sock *svsk =
+               container_of(rqstp->rq_xprt, struct svc_sock, sk_xprt);
+       switch (svsk->sk_sk->sk_family) {
        case AF_INET: {
                struct in_pktinfo *pki = CMSG_DATA(cmh);
                rqstp->rq_daddr.addr.s_addr = pki->ipi_spec_dst.s_addr;
@@ -760,11 +418,11 @@ static inline void svc_udp_get_dest_address(struct svc_rqst *rqstp,
 /*
  * Receive a datagram from a UDP socket.
  */
-static int
-svc_udp_recvfrom(struct svc_rqst *rqstp)
+static int svc_udp_recvfrom(struct svc_rqst *rqstp)
 {
-       struct svc_sock *svsk = rqstp->rq_sock;
-       struct svc_serv *serv = svsk->sk_server;
+       struct svc_sock *svsk =
+               container_of(rqstp->rq_xprt, struct svc_sock, sk_xprt);
+       struct svc_serv *serv = svsk->sk_xprt.xpt_server;
        struct sk_buff  *skb;
        union {
                struct cmsghdr  hdr;
@@ -779,7 +437,7 @@ svc_udp_recvfrom(struct svc_rqst *rqstp)
                .msg_flags = MSG_DONTWAIT,
        };
 
-       if (test_and_clear_bit(SK_CHNGBUF, &svsk->sk_flags))
+       if (test_and_clear_bit(XPT_CHNGBUF, &svsk->sk_xprt.xpt_flags))
            /* udp sockets need large rcvbuf as all pending
             * requests are still in that buffer.  sndbuf must
             * also be large enough that there is enough space
@@ -792,17 +450,7 @@ svc_udp_recvfrom(struct svc_rqst *rqstp)
                                (serv->sv_nrthreads+3) * serv->sv_max_mesg,
                                (serv->sv_nrthreads+3) * serv->sv_max_mesg);
 
-       if ((rqstp->rq_deferred = svc_deferred_dequeue(svsk))) {
-               svc_sock_received(svsk);
-               return svc_deferred_recv(rqstp);
-       }
-
-       if (test_bit(SK_CLOSE, &svsk->sk_flags)) {
-               svc_delete_socket(svsk);
-               return 0;
-       }
-
-       clear_bit(SK_DATA, &svsk->sk_flags);
+       clear_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags);
        skb = NULL;
        err = kernel_recvmsg(svsk->sk_sock, &msg, NULL,
                             0, 0, MSG_PEEK | MSG_DONTWAIT);
@@ -813,24 +461,27 @@ svc_udp_recvfrom(struct svc_rqst *rqstp)
                if (err != -EAGAIN) {
                        /* possibly an icmp error */
                        dprintk("svc: recvfrom returned error %d\n", -err);
-                       set_bit(SK_DATA, &svsk->sk_flags);
+                       set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags);
                }
-               svc_sock_received(svsk);
+               svc_xprt_received(&svsk->sk_xprt);
                return -EAGAIN;
        }
-       rqstp->rq_addrlen = sizeof(rqstp->rq_addr);
+       len = svc_addr_len(svc_addr(rqstp));
+       if (len < 0)
+               return len;
+       rqstp->rq_addrlen = len;
        if (skb->tstamp.tv64 == 0) {
                skb->tstamp = ktime_get_real();
                /* Don't enable netstamp, sunrpc doesn't
                   need that much accuracy */
        }
        svsk->sk_sk->sk_stamp = skb->tstamp;
-       set_bit(SK_DATA, &svsk->sk_flags); /* there may be more data... */
+       set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags); /* there may be more data... */
 
        /*
         * Maybe more packets - kick another thread ASAP.
         */
-       svc_sock_received(svsk);
+       svc_xprt_received(&svsk->sk_xprt);
 
        len  = skb->len - sizeof(struct udphdr);
        rqstp->rq_arg.len = len;
@@ -861,13 +512,14 @@ svc_udp_recvfrom(struct svc_rqst *rqstp)
                skb_free_datagram(svsk->sk_sk, skb);
        } else {
                /* we can use it in-place */
-               rqstp->rq_arg.head[0].iov_base = skb->data + sizeof(struct udphdr);
+               rqstp->rq_arg.head[0].iov_base = skb->data +
+                       sizeof(struct udphdr);
                rqstp->rq_arg.head[0].iov_len = len;
                if (skb_checksum_complete(skb)) {
                        skb_free_datagram(svsk->sk_sk, skb);
                        return 0;
                }
-               rqstp->rq_skbuff = skb;
+               rqstp->rq_xprt_ctxt = skb;
        }
 
        rqstp->rq_arg.page_base = 0;
@@ -900,27 +552,81 @@ svc_udp_sendto(struct svc_rqst *rqstp)
        return error;
 }
 
-static void
-svc_udp_init(struct svc_sock *svsk)
+static void svc_udp_prep_reply_hdr(struct svc_rqst *rqstp)
+{
+}
+
+static int svc_udp_has_wspace(struct svc_xprt *xprt)
+{
+       struct svc_sock *svsk = container_of(xprt, struct svc_sock, sk_xprt);
+       struct svc_serv *serv = xprt->xpt_server;
+       unsigned long required;
+
+       /*
+        * Set the SOCK_NOSPACE flag before checking the available
+        * sock space.
+        */
+       set_bit(SOCK_NOSPACE, &svsk->sk_sock->flags);
+       required = atomic_read(&svsk->sk_xprt.xpt_reserved) + serv->sv_max_mesg;
+       if (required*2 > sock_wspace(svsk->sk_sk))
+               return 0;
+       clear_bit(SOCK_NOSPACE, &svsk->sk_sock->flags);
+       return 1;
+}
+
+static struct svc_xprt *svc_udp_accept(struct svc_xprt *xprt)
+{
+       BUG();
+       return NULL;
+}
+
+static struct svc_xprt *svc_udp_create(struct svc_serv *serv,
+                                      struct sockaddr *sa, int salen,
+                                      int flags)
+{
+       return svc_create_socket(serv, IPPROTO_UDP, sa, salen, flags);
+}
+
+static struct svc_xprt_ops svc_udp_ops = {
+       .xpo_create = svc_udp_create,
+       .xpo_recvfrom = svc_udp_recvfrom,
+       .xpo_sendto = svc_udp_sendto,
+       .xpo_release_rqst = svc_release_skb,
+       .xpo_detach = svc_sock_detach,
+       .xpo_free = svc_sock_free,
+       .xpo_prep_reply_hdr = svc_udp_prep_reply_hdr,
+       .xpo_has_wspace = svc_udp_has_wspace,
+       .xpo_accept = svc_udp_accept,
+};
+
+static struct svc_xprt_class svc_udp_class = {
+       .xcl_name = "udp",
+       .xcl_owner = THIS_MODULE,
+       .xcl_ops = &svc_udp_ops,
+       .xcl_max_payload = RPCSVC_MAXPAYLOAD_UDP,
+};
+
+static void svc_udp_init(struct svc_sock *svsk, struct svc_serv *serv)
 {
        int one = 1;
        mm_segment_t oldfs;
 
+       svc_xprt_init(&svc_udp_class, &svsk->sk_xprt, serv);
+       clear_bit(XPT_CACHE_AUTH, &svsk->sk_xprt.xpt_flags);
        svsk->sk_sk->sk_data_ready = svc_udp_data_ready;
        svsk->sk_sk->sk_write_space = svc_write_space;
-       svsk->sk_recvfrom = svc_udp_recvfrom;
-       svsk->sk_sendto = svc_udp_sendto;
 
        /* initialise setting must have enough space to
         * receive and respond to one request.
         * svc_udp_recvfrom will re-adjust if necessary
         */
        svc_sock_setbufsize(svsk->sk_sock,
-                           3 * svsk->sk_server->sv_max_mesg,
-                           3 * svsk->sk_server->sv_max_mesg);
+                           3 * svsk->sk_xprt.xpt_server->sv_max_mesg,
+                           3 * svsk->sk_xprt.xpt_server->sv_max_mesg);
 
-       set_bit(SK_DATA, &svsk->sk_flags); /* might have come in before data_ready set up */
-       set_bit(SK_CHNGBUF, &svsk->sk_flags);
+       /* data might have come in before data_ready set up */
+       set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags);
+       set_bit(XPT_CHNGBUF, &svsk->sk_xprt.xpt_flags);
 
        oldfs = get_fs();
        set_fs(KERNEL_DS);
@@ -934,8 +640,7 @@ svc_udp_init(struct svc_sock *svsk)
  * A data_ready event on a listening socket means there's a connection
  * pending. Do not use state_change as a substitute for it.
  */
-static void
-svc_tcp_listen_data_ready(struct sock *sk, int count_unused)
+static void svc_tcp_listen_data_ready(struct sock *sk, int count_unused)
 {
        struct svc_sock *svsk = (struct svc_sock *)sk->sk_user_data;
 
@@ -954,8 +659,8 @@ svc_tcp_listen_data_ready(struct sock *sk, int count_unused)
         */
        if (sk->sk_state == TCP_LISTEN) {
                if (svsk) {
-                       set_bit(SK_CONN, &svsk->sk_flags);
-                       svc_sock_enqueue(svsk);
+                       set_bit(XPT_CONN, &svsk->sk_xprt.xpt_flags);
+                       svc_xprt_enqueue(&svsk->sk_xprt);
                } else
                        printk("svc: socket %p: no user data\n", sk);
        }
@@ -967,8 +672,7 @@ svc_tcp_listen_data_ready(struct sock *sk, int count_unused)
 /*
  * A state change on a connected socket means it's dying or dead.
  */
-static void
-svc_tcp_state_change(struct sock *sk)
+static void svc_tcp_state_change(struct sock *sk)
 {
        struct svc_sock *svsk = (struct svc_sock *)sk->sk_user_data;
 
@@ -978,51 +682,36 @@ svc_tcp_state_change(struct sock *sk)
        if (!svsk)
                printk("svc: socket %p: no user data\n", sk);
        else {
-               set_bit(SK_CLOSE, &svsk->sk_flags);
-               svc_sock_enqueue(svsk);
+               set_bit(XPT_CLOSE, &svsk->sk_xprt.xpt_flags);
+               svc_xprt_enqueue(&svsk->sk_xprt);
        }
        if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))
                wake_up_interruptible_all(sk->sk_sleep);
 }
 
-static void
-svc_tcp_data_ready(struct sock *sk, int count)
+static void svc_tcp_data_ready(struct sock *sk, int count)
 {
        struct svc_sock *svsk = (struct svc_sock *)sk->sk_user_data;
 
        dprintk("svc: socket %p TCP data ready (svsk %p)\n",
                sk, sk->sk_user_data);
        if (svsk) {
-               set_bit(SK_DATA, &svsk->sk_flags);
-               svc_sock_enqueue(svsk);
+               set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags);
+               svc_xprt_enqueue(&svsk->sk_xprt);
        }
        if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))
                wake_up_interruptible(sk->sk_sleep);
 }
 
-static inline int svc_port_is_privileged(struct sockaddr *sin)
-{
-       switch (sin->sa_family) {
-       case AF_INET:
-               return ntohs(((struct sockaddr_in *)sin)->sin_port)
-                       < PROT_SOCK;
-       case AF_INET6:
-               return ntohs(((struct sockaddr_in6 *)sin)->sin6_port)
-                       < PROT_SOCK;
-       default:
-               return 0;
-       }
-}
-
 /*
  * Accept a TCP connection
  */
-static void
-svc_tcp_accept(struct svc_sock *svsk)
+static struct svc_xprt *svc_tcp_accept(struct svc_xprt *xprt)
 {
+       struct svc_sock *svsk = container_of(xprt, struct svc_sock, sk_xprt);
        struct sockaddr_storage addr;
        struct sockaddr *sin = (struct sockaddr *) &addr;
-       struct svc_serv *serv = svsk->sk_server;
+       struct svc_serv *serv = svsk->sk_xprt.xpt_server;
        struct socket   *sock = svsk->sk_sock;
        struct socket   *newsock;
        struct svc_sock *newsvsk;
@@ -1031,9 +720,9 @@ svc_tcp_accept(struct svc_sock *svsk)
 
        dprintk("svc: tcp_accept %p sock %p\n", svsk, sock);
        if (!sock)
-               return;
+               return NULL;
 
-       clear_bit(SK_CONN, &svsk->sk_flags);
+       clear_bit(XPT_CONN, &svsk->sk_xprt.xpt_flags);
        err = kernel_accept(sock, &newsock, O_NONBLOCK);
        if (err < 0) {
                if (err == -ENOMEM)
@@ -1042,11 +731,9 @@ svc_tcp_accept(struct svc_sock *svsk)
                else if (err != -EAGAIN && net_ratelimit())
                        printk(KERN_WARNING "%s: accept failed (err %d)!\n",
                                   serv->sv_name, -err);
-               return;
+               return NULL;
        }
-
-       set_bit(SK_CONN, &svsk->sk_flags);
-       svc_sock_enqueue(svsk);
+       set_bit(XPT_CONN, &svsk->sk_xprt.xpt_flags);
 
        err = kernel_getpeername(newsock, sin, &slen);
        if (err < 0) {
@@ -1077,106 +764,42 @@ svc_tcp_accept(struct svc_sock *svsk)
        if (!(newsvsk = svc_setup_socket(serv, newsock, &err,
                                 (SVC_SOCK_ANONYMOUS | SVC_SOCK_TEMPORARY))))
                goto failed;
-       memcpy(&newsvsk->sk_remote, sin, slen);
-       newsvsk->sk_remotelen = slen;
+       svc_xprt_set_remote(&newsvsk->sk_xprt, sin, slen);
        err = kernel_getsockname(newsock, sin, &slen);
        if (unlikely(err < 0)) {
                dprintk("svc_tcp_accept: kernel_getsockname error %d\n", -err);
                slen = offsetof(struct sockaddr, sa_data);
        }
-       memcpy(&newsvsk->sk_local, sin, slen);
-
-       svc_sock_received(newsvsk);
-
-       /* make sure that we don't have too many active connections.
-        * If we have, something must be dropped.
-        *
-        * There's no point in trying to do random drop here for
-        * DoS prevention. The NFS clients does 1 reconnect in 15
-        * seconds. An attacker can easily beat that.
-        *
-        * The only somewhat efficient mechanism would be if drop
-        * old connections from the same IP first. But right now
-        * we don't even record the client IP in svc_sock.
-        */
-       if (serv->sv_tmpcnt > (serv->sv_nrthreads+3)*20) {
-               struct svc_sock *svsk = NULL;
-               spin_lock_bh(&serv->sv_lock);
-               if (!list_empty(&serv->sv_tempsocks)) {
-                       if (net_ratelimit()) {
-                               /* Try to help the admin */
-                               printk(KERN_NOTICE "%s: too many open TCP "
-                                       "sockets, consider increasing the "
-                                       "number of nfsd threads\n",
-                                                  serv->sv_name);
-                               printk(KERN_NOTICE
-                                      "%s: last TCP connect from %s\n",
-                                      serv->sv_name, __svc_print_addr(sin,
-                                                       buf, sizeof(buf)));
-                       }
-                       /*
-                        * Always select the oldest socket. It's not fair,
-                        * but so is life
-                        */
-                       svsk = list_entry(serv->sv_tempsocks.prev,
-                                         struct svc_sock,
-                                         sk_list);
-                       set_bit(SK_CLOSE, &svsk->sk_flags);
-                       atomic_inc(&svsk->sk_inuse);
-               }
-               spin_unlock_bh(&serv->sv_lock);
-
-               if (svsk) {
-                       svc_sock_enqueue(svsk);
-                       svc_sock_put(svsk);
-               }
-
-       }
+       svc_xprt_set_local(&newsvsk->sk_xprt, sin, slen);
 
        if (serv->sv_stats)
                serv->sv_stats->nettcpconn++;
 
-       return;
+       return &newsvsk->sk_xprt;
 
 failed:
        sock_release(newsock);
-       return;
+       return NULL;
 }
 
 /*
  * Receive data from a TCP socket.
  */
-static int
-svc_tcp_recvfrom(struct svc_rqst *rqstp)
+static int svc_tcp_recvfrom(struct svc_rqst *rqstp)
 {
-       struct svc_sock *svsk = rqstp->rq_sock;
-       struct svc_serv *serv = svsk->sk_server;
+       struct svc_sock *svsk =
+               container_of(rqstp->rq_xprt, struct svc_sock, sk_xprt);
+       struct svc_serv *serv = svsk->sk_xprt.xpt_server;
        int             len;
        struct kvec *vec;
        int pnum, vlen;
 
        dprintk("svc: tcp_recv %p data %d conn %d close %d\n",
-               svsk, test_bit(SK_DATA, &svsk->sk_flags),
-               test_bit(SK_CONN, &svsk->sk_flags),
-               test_bit(SK_CLOSE, &svsk->sk_flags));
+               svsk, test_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags),
+               test_bit(XPT_CONN, &svsk->sk_xprt.xpt_flags),
+               test_bit(XPT_CLOSE, &svsk->sk_xprt.xpt_flags));
 
-       if ((rqstp->rq_deferred = svc_deferred_dequeue(svsk))) {
-               svc_sock_received(svsk);
-               return svc_deferred_recv(rqstp);
-       }
-
-       if (test_bit(SK_CLOSE, &svsk->sk_flags)) {
-               svc_delete_socket(svsk);
-               return 0;
-       }
-
-       if (svsk->sk_sk->sk_state == TCP_LISTEN) {
-               svc_tcp_accept(svsk);
-               svc_sock_received(svsk);
-               return 0;
-       }
-
-       if (test_and_clear_bit(SK_CHNGBUF, &svsk->sk_flags))
+       if (test_and_clear_bit(XPT_CHNGBUF, &svsk->sk_xprt.xpt_flags))
                /* sndbuf needs to have room for one request
                 * per thread, otherwise we can stall even when the
                 * network isn't a bottleneck.
@@ -1193,7 +816,7 @@ svc_tcp_recvfrom(struct svc_rqst *rqstp)
                                    (serv->sv_nrthreads+3) * serv->sv_max_mesg,
                                    3 * serv->sv_max_mesg);
 
-       clear_bit(SK_DATA, &svsk->sk_flags);
+       clear_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags);
 
        /* Receive data. If we haven't got the record length yet, get
         * the next four bytes. Otherwise try to gobble up as much as
@@ -1212,7 +835,7 @@ svc_tcp_recvfrom(struct svc_rqst *rqstp)
                if (len < want) {
                        dprintk("svc: short recvfrom while reading record length (%d of %lu)\n",
                                len, want);
-                       svc_sock_received(svsk);
+                       svc_xprt_received(&svsk->sk_xprt);
                        return -EAGAIN; /* record header not complete */
                }
 
@@ -1248,11 +871,11 @@ svc_tcp_recvfrom(struct svc_rqst *rqstp)
        if (len < svsk->sk_reclen) {
                dprintk("svc: incomplete TCP record (%d of %d)\n",
                        len, svsk->sk_reclen);
-               svc_sock_received(svsk);
+               svc_xprt_received(&svsk->sk_xprt);
                return -EAGAIN; /* record not complete */
        }
        len = svsk->sk_reclen;
-       set_bit(SK_DATA, &svsk->sk_flags);
+       set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags);
 
        vec = rqstp->rq_vec;
        vec[0] = rqstp->rq_arg.head[0];
@@ -1281,30 +904,31 @@ svc_tcp_recvfrom(struct svc_rqst *rqstp)
                rqstp->rq_arg.page_len = len - rqstp->rq_arg.head[0].iov_len;
        }
 
-       rqstp->rq_skbuff      = NULL;
+       rqstp->rq_xprt_ctxt   = NULL;
        rqstp->rq_prot        = IPPROTO_TCP;
 
        /* Reset TCP read info */
        svsk->sk_reclen = 0;
        svsk->sk_tcplen = 0;
 
-       svc_sock_received(svsk);
+       svc_xprt_copy_addrs(rqstp, &svsk->sk_xprt);
+       svc_xprt_received(&svsk->sk_xprt);
        if (serv->sv_stats)
                serv->sv_stats->nettcpcnt++;
 
        return len;
 
  err_delete:
-       svc_delete_socket(svsk);
+       set_bit(XPT_CLOSE, &svsk->sk_xprt.xpt_flags);
        return -EAGAIN;
 
  error:
        if (len == -EAGAIN) {
                dprintk("RPC: TCP recvfrom got EAGAIN\n");
-               svc_sock_received(svsk);
+               svc_xprt_received(&svsk->sk_xprt);
        } else {
                printk(KERN_NOTICE "%s: recvfrom returned errno %d\n",
-                                       svsk->sk_server->sv_name, -len);
+                      svsk->sk_xprt.xpt_server->sv_name, -len);
                goto err_delete;
        }
 
@@ -1314,8 +938,7 @@ svc_tcp_recvfrom(struct svc_rqst *rqstp)
 /*
  * Send out data on TCP socket.
  */
-static int
-svc_tcp_sendto(struct svc_rqst *rqstp)
+static int svc_tcp_sendto(struct svc_rqst *rqstp)
 {
        struct xdr_buf  *xbufp = &rqstp->rq_res;
        int sent;
@@ -1328,35 +951,109 @@ svc_tcp_sendto(struct svc_rqst *rqstp)
        reclen = htonl(0x80000000|((xbufp->len ) - 4));
        memcpy(xbufp->head[0].iov_base, &reclen, 4);
 
-       if (test_bit(SK_DEAD, &rqstp->rq_sock->sk_flags))
+       if (test_bit(XPT_DEAD, &rqstp->rq_xprt->xpt_flags))
                return -ENOTCONN;
 
        sent = svc_sendto(rqstp, &rqstp->rq_res);
        if (sent != xbufp->len) {
-               printk(KERN_NOTICE "rpc-srv/tcp: %s: %s %d when sending %d bytes - shutting down socket\n",
-                      rqstp->rq_sock->sk_server->sv_name,
+               printk(KERN_NOTICE
+                      "rpc-srv/tcp: %s: %s %d when sending %d bytes "
+                      "- shutting down socket\n",
+                      rqstp->rq_xprt->xpt_server->sv_name,
                       (sent<0)?"got error":"sent only",
                       sent, xbufp->len);
-               set_bit(SK_CLOSE, &rqstp->rq_sock->sk_flags);
-               svc_sock_enqueue(rqstp->rq_sock);
+               set_bit(XPT_CLOSE, &rqstp->rq_xprt->xpt_flags);
+               svc_xprt_enqueue(rqstp->rq_xprt);
                sent = -EAGAIN;
        }
        return sent;
 }
 
-static void
-svc_tcp_init(struct svc_sock *svsk)
+/*
+ * Setup response header. TCP has a 4B record length field.
+ */
+static void svc_tcp_prep_reply_hdr(struct svc_rqst *rqstp)
+{
+       struct kvec *resv = &rqstp->rq_res.head[0];
+
+       /* tcp needs a space for the record length... */
+       svc_putnl(resv, 0);
+}
+
+static int svc_tcp_has_wspace(struct svc_xprt *xprt)
+{
+       struct svc_sock *svsk = container_of(xprt, struct svc_sock, sk_xprt);
+       struct svc_serv *serv = svsk->sk_xprt.xpt_server;
+       int required;
+       int wspace;
+
+       /*
+        * Set the SOCK_NOSPACE flag before checking the available
+        * sock space.
+        */
+       set_bit(SOCK_NOSPACE, &svsk->sk_sock->flags);
+       required = atomic_read(&svsk->sk_xprt.xpt_reserved) + serv->sv_max_mesg;
+       wspace = sk_stream_wspace(svsk->sk_sk);
+
+       if (wspace < sk_stream_min_wspace(svsk->sk_sk))
+               return 0;
+       if (required * 2 > wspace)
+               return 0;
+
+       clear_bit(SOCK_NOSPACE, &svsk->sk_sock->flags);
+       return 1;
+}
+
+static struct svc_xprt *svc_tcp_create(struct svc_serv *serv,
+                                      struct sockaddr *sa, int salen,
+                                      int flags)
+{
+       return svc_create_socket(serv, IPPROTO_TCP, sa, salen, flags);
+}
+
+static struct svc_xprt_ops svc_tcp_ops = {
+       .xpo_create = svc_tcp_create,
+       .xpo_recvfrom = svc_tcp_recvfrom,
+       .xpo_sendto = svc_tcp_sendto,
+       .xpo_release_rqst = svc_release_skb,
+       .xpo_detach = svc_sock_detach,
+       .xpo_free = svc_sock_free,
+       .xpo_prep_reply_hdr = svc_tcp_prep_reply_hdr,
+       .xpo_has_wspace = svc_tcp_has_wspace,
+       .xpo_accept = svc_tcp_accept,
+};
+
+static struct svc_xprt_class svc_tcp_class = {
+       .xcl_name = "tcp",
+       .xcl_owner = THIS_MODULE,
+       .xcl_ops = &svc_tcp_ops,
+       .xcl_max_payload = RPCSVC_MAXPAYLOAD_TCP,
+};
+
+void svc_init_xprt_sock(void)
+{
+       svc_reg_xprt_class(&svc_tcp_class);
+       svc_reg_xprt_class(&svc_udp_class);
+}
+
+void svc_cleanup_xprt_sock(void)
+{
+       svc_unreg_xprt_class(&svc_tcp_class);
+       svc_unreg_xprt_class(&svc_udp_class);
+}
+
+static void svc_tcp_init(struct svc_sock *svsk, struct svc_serv *serv)
 {
        struct sock     *sk = svsk->sk_sk;
        struct tcp_sock *tp = tcp_sk(sk);
 
-       svsk->sk_recvfrom = svc_tcp_recvfrom;
-       svsk->sk_sendto = svc_tcp_sendto;
-
+       svc_xprt_init(&svc_tcp_class, &svsk->sk_xprt, serv);
+       set_bit(XPT_CACHE_AUTH, &svsk->sk_xprt.xpt_flags);
        if (sk->sk_state == TCP_LISTEN) {
                dprintk("setting up TCP socket for listening\n");
+               set_bit(XPT_LISTENER, &svsk->sk_xprt.xpt_flags);
                sk->sk_data_ready = svc_tcp_listen_data_ready;
-               set_bit(SK_CONN, &svsk->sk_flags);
+               set_bit(XPT_CONN, &svsk->sk_xprt.xpt_flags);
        } else {
                dprintk("setting up TCP socket for reading\n");
                sk->sk_state_change = svc_tcp_state_change;
@@ -1373,18 +1070,17 @@ svc_tcp_init(struct svc_sock *svsk)
                 * svc_tcp_recvfrom will re-adjust if necessary
                 */
                svc_sock_setbufsize(svsk->sk_sock,
-                                   3 * svsk->sk_server->sv_max_mesg,
-                                   3 * svsk->sk_server->sv_max_mesg);
+                                   3 * svsk->sk_xprt.xpt_server->sv_max_mesg,
+                                   3 * svsk->sk_xprt.xpt_server->sv_max_mesg);
 
-               set_bit(SK_CHNGBUF, &svsk->sk_flags);
-               set_bit(SK_DATA, &svsk->sk_flags);
+               set_bit(XPT_CHNGBUF, &svsk->sk_xprt.xpt_flags);
+               set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags);
                if (sk->sk_state != TCP_ESTABLISHED)
-                       set_bit(SK_CLOSE, &svsk->sk_flags);
+                       set_bit(XPT_CLOSE, &svsk->sk_xprt.xpt_flags);
        }
 }
 
-void
-svc_sock_update_bufs(struct svc_serv *serv)
+void svc_sock_update_bufs(struct svc_serv *serv)
 {
        /*
         * The number of server threads has changed. Update
@@ -1395,231 +1091,17 @@ svc_sock_update_bufs(struct svc_serv *serv)
        spin_lock_bh(&serv->sv_lock);
        list_for_each(le, &serv->sv_permsocks) {
                struct svc_sock *svsk =
-                       list_entry(le, struct svc_sock, sk_list);
-               set_bit(SK_CHNGBUF, &svsk->sk_flags);
+                       list_entry(le, struct svc_sock, sk_xprt.xpt_list);
+               set_bit(XPT_CHNGBUF, &svsk->sk_xprt.xpt_flags);
        }
        list_for_each(le, &serv->sv_tempsocks) {
                struct svc_sock *svsk =
-                       list_entry(le, struct svc_sock, sk_list);
-               set_bit(SK_CHNGBUF, &svsk->sk_flags);
+                       list_entry(le, struct svc_sock, sk_xprt.xpt_list);
+               set_bit(XPT_CHNGBUF, &svsk->sk_xprt.xpt_flags);
        }
        spin_unlock_bh(&serv->sv_lock);
 }
 
-/*
- * Receive the next request on any socket.  This code is carefully
- * organised not to touch any cachelines in the shared svc_serv
- * structure, only cachelines in the local svc_pool.
- */
-int
-svc_recv(struct svc_rqst *rqstp, long timeout)
-{
-       struct svc_sock         *svsk = NULL;
-       struct svc_serv         *serv = rqstp->rq_server;
-       struct svc_pool         *pool = rqstp->rq_pool;
-       int                     len, i;
-       int                     pages;
-       struct xdr_buf          *arg;
-       DECLARE_WAITQUEUE(wait, current);
-
-       dprintk("svc: server %p waiting for data (to = %ld)\n",
-               rqstp, timeout);
-
-       if (rqstp->rq_sock)
-               printk(KERN_ERR
-                       "svc_recv: service %p, socket not NULL!\n",
-                        rqstp);
-       if (waitqueue_active(&rqstp->rq_wait))
-               printk(KERN_ERR
-                       "svc_recv: service %p, wait queue active!\n",
-                        rqstp);
-
-
-       /* now allocate needed pages.  If we get a failure, sleep briefly */
-       pages = (serv->sv_max_mesg + PAGE_SIZE) / PAGE_SIZE;
-       for (i=0; i < pages ; i++)
-               while (rqstp->rq_pages[i] == NULL) {
-                       struct page *p = alloc_page(GFP_KERNEL);
-                       if (!p)
-                               schedule_timeout_uninterruptible(msecs_to_jiffies(500));
-                       rqstp->rq_pages[i] = p;
-               }
-       rqstp->rq_pages[i++] = NULL; /* this might be seen in nfs_read_actor */
-       BUG_ON(pages >= RPCSVC_MAXPAGES);
-
-       /* Make arg->head point to first page and arg->pages point to rest */
-       arg = &rqstp->rq_arg;
-       arg->head[0].iov_base = page_address(rqstp->rq_pages[0]);
-       arg->head[0].iov_len = PAGE_SIZE;
-       arg->pages = rqstp->rq_pages + 1;
-       arg->page_base = 0;
-       /* save at least one page for response */
-       arg->page_len = (pages-2)*PAGE_SIZE;
-       arg->len = (pages-1)*PAGE_SIZE;
-       arg->tail[0].iov_len = 0;
-
-       try_to_freeze();
-       cond_resched();
-       if (signalled())
-               return -EINTR;
-
-       spin_lock_bh(&pool->sp_lock);
-       if ((svsk = svc_sock_dequeue(pool)) != NULL) {
-               rqstp->rq_sock = svsk;
-               atomic_inc(&svsk->sk_inuse);
-               rqstp->rq_reserved = serv->sv_max_mesg;
-               atomic_add(rqstp->rq_reserved, &svsk->sk_reserved);
-       } else {
-               /* No data pending. Go to sleep */
-               svc_thread_enqueue(pool, rqstp);
-
-               /*
-                * We have to be able to interrupt this wait
-                * to bring down the daemons ...
-                */
-               set_current_state(TASK_INTERRUPTIBLE);
-               add_wait_queue(&rqstp->rq_wait, &wait);
-               spin_unlock_bh(&pool->sp_lock);
-
-               schedule_timeout(timeout);
-
-               try_to_freeze();
-
-               spin_lock_bh(&pool->sp_lock);
-               remove_wait_queue(&rqstp->rq_wait, &wait);
-
-               if (!(svsk = rqstp->rq_sock)) {
-                       svc_thread_dequeue(pool, rqstp);
-                       spin_unlock_bh(&pool->sp_lock);
-                       dprintk("svc: server %p, no data yet\n", rqstp);
-                       return signalled()? -EINTR : -EAGAIN;
-               }
-       }
-       spin_unlock_bh(&pool->sp_lock);
-
-       dprintk("svc: server %p, pool %u, socket %p, inuse=%d\n",
-                rqstp, pool->sp_id, svsk, atomic_read(&svsk->sk_inuse));
-       len = svsk->sk_recvfrom(rqstp);
-       dprintk("svc: got len=%d\n", len);
-
-       /* No data, incomplete (TCP) read, or accept() */
-       if (len == 0 || len == -EAGAIN) {
-               rqstp->rq_res.len = 0;
-               svc_sock_release(rqstp);
-               return -EAGAIN;
-       }
-       svsk->sk_lastrecv = get_seconds();
-       clear_bit(SK_OLD, &svsk->sk_flags);
-
-       rqstp->rq_secure = svc_port_is_privileged(svc_addr(rqstp));
-       rqstp->rq_chandle.defer = svc_defer;
-
-       if (serv->sv_stats)
-               serv->sv_stats->netcnt++;
-       return len;
-}
-
-/*
- * Drop request
- */
-void
-svc_drop(struct svc_rqst *rqstp)
-{
-       dprintk("svc: socket %p dropped request\n", rqstp->rq_sock);
-       svc_sock_release(rqstp);
-}
-
-/*
- * Return reply to client.
- */
-int
-svc_send(struct svc_rqst *rqstp)
-{
-       struct svc_sock *svsk;
-       int             len;
-       struct xdr_buf  *xb;
-
-       if ((svsk = rqstp->rq_sock) == NULL) {
-               printk(KERN_WARNING "NULL socket pointer in %s:%d\n",
-                               __FILE__, __LINE__);
-               return -EFAULT;
-       }
-
-       /* release the receive skb before sending the reply */
-       svc_release_skb(rqstp);
-
-       /* calculate over-all length */
-       xb = & rqstp->rq_res;
-       xb->len = xb->head[0].iov_len +
-               xb->page_len +
-               xb->tail[0].iov_len;
-
-       /* Grab svsk->sk_mutex to serialize outgoing data. */
-       mutex_lock(&svsk->sk_mutex);
-       if (test_bit(SK_DEAD, &svsk->sk_flags))
-               len = -ENOTCONN;
-       else
-               len = svsk->sk_sendto(rqstp);
-       mutex_unlock(&svsk->sk_mutex);
-       svc_sock_release(rqstp);
-
-       if (len == -ECONNREFUSED || len == -ENOTCONN || len == -EAGAIN)
-               return 0;
-       return len;
-}
-
-/*
- * Timer function to close old temporary sockets, using
- * a mark-and-sweep algorithm.
- */
-static void
-svc_age_temp_sockets(unsigned long closure)
-{
-       struct svc_serv *serv = (struct svc_serv *)closure;
-       struct svc_sock *svsk;
-       struct list_head *le, *next;
-       LIST_HEAD(to_be_aged);
-
-       dprintk("svc_age_temp_sockets\n");
-
-       if (!spin_trylock_bh(&serv->sv_lock)) {
-               /* busy, try again 1 sec later */
-               dprintk("svc_age_temp_sockets: busy\n");
-               mod_timer(&serv->sv_temptimer, jiffies + HZ);
-               return;
-       }
-
-       list_for_each_safe(le, next, &serv->sv_tempsocks) {
-               svsk = list_entry(le, struct svc_sock, sk_list);
-
-               if (!test_and_set_bit(SK_OLD, &svsk->sk_flags))
-                       continue;
-               if (atomic_read(&svsk->sk_inuse) > 1 || test_bit(SK_BUSY, &svsk->sk_flags))
-                       continue;
-               atomic_inc(&svsk->sk_inuse);
-               list_move(le, &to_be_aged);
-               set_bit(SK_CLOSE, &svsk->sk_flags);
-               set_bit(SK_DETACHED, &svsk->sk_flags);
-       }
-       spin_unlock_bh(&serv->sv_lock);
-
-       while (!list_empty(&to_be_aged)) {
-               le = to_be_aged.next;
-               /* fiddling the sk_list node is safe 'cos we're SK_DETACHED */
-               list_del_init(le);
-               svsk = list_entry(le, struct svc_sock, sk_list);
-
-               dprintk("queuing svsk %p for closing, %lu seconds old\n",
-                       svsk, get_seconds() - svsk->sk_lastrecv);
-
-               /* a thread will dequeue and close it soon */
-               svc_sock_enqueue(svsk);
-               svc_sock_put(svsk);
-       }
-
-       mod_timer(&serv->sv_temptimer, jiffies + svc_conn_age_period * HZ);
-}
-
 /*
  * Initialize socket for RPC use and create svc_sock struct
  * XXX: May want to setsockopt SO_SNDBUF and SO_RCVBUF.
@@ -1631,7 +1113,6 @@ static struct svc_sock *svc_setup_socket(struct svc_serv *serv,
        struct svc_sock *svsk;
        struct sock     *inet;
        int             pmap_register = !(flags & SVC_SOCK_ANONYMOUS);
-       int             is_temporary = flags & SVC_SOCK_TEMPORARY;
 
        dprintk("svc: svc_setup_socket %p\n", sock);
        if (!(svsk = kzalloc(sizeof(*svsk), GFP_KERNEL))) {
@@ -1651,44 +1132,18 @@ static struct svc_sock *svc_setup_socket(struct svc_serv *serv,
                return NULL;
        }
 
-       set_bit(SK_BUSY, &svsk->sk_flags);
        inet->sk_user_data = svsk;
        svsk->sk_sock = sock;
        svsk->sk_sk = inet;
        svsk->sk_ostate = inet->sk_state_change;
        svsk->sk_odata = inet->sk_data_ready;
        svsk->sk_owspace = inet->sk_write_space;
-       svsk->sk_server = serv;
-       atomic_set(&svsk->sk_inuse, 1);
-       svsk->sk_lastrecv = get_seconds();
-       spin_lock_init(&svsk->sk_lock);
-       INIT_LIST_HEAD(&svsk->sk_deferred);
-       INIT_LIST_HEAD(&svsk->sk_ready);
-       mutex_init(&svsk->sk_mutex);
 
        /* Initialize the socket */
        if (sock->type == SOCK_DGRAM)
-               svc_udp_init(svsk);
+               svc_udp_init(svsk, serv);
        else
-               svc_tcp_init(svsk);
-
-       spin_lock_bh(&serv->sv_lock);
-       if (is_temporary) {
-               set_bit(SK_TEMP, &svsk->sk_flags);
-               list_add(&svsk->sk_list, &serv->sv_tempsocks);
-               serv->sv_tmpcnt++;
-               if (serv->sv_temptimer.function == NULL) {
-                       /* setup timer to age temp sockets */
-                       setup_timer(&serv->sv_temptimer, svc_age_temp_sockets,
-                                       (unsigned long)serv);
-                       mod_timer(&serv->sv_temptimer,
-                                       jiffies + svc_conn_age_period * HZ);
-               }
-       } else {
-               clear_bit(SK_TEMP, &svsk->sk_flags);
-               list_add(&svsk->sk_list, &serv->sv_permsocks);
-       }
-       spin_unlock_bh(&serv->sv_lock);
+               svc_tcp_init(svsk, serv);
 
        dprintk("svc: svc_setup_socket created %p (inet %p)\n",
                                svsk, svsk->sk_sk);
@@ -1717,7 +1172,16 @@ int svc_addsock(struct svc_serv *serv,
        else {
                svsk = svc_setup_socket(serv, so, &err, SVC_SOCK_DEFAULTS);
                if (svsk) {
-                       svc_sock_received(svsk);
+                       struct sockaddr_storage addr;
+                       struct sockaddr *sin = (struct sockaddr *)&addr;
+                       int salen;
+                       if (kernel_getsockname(svsk->sk_sock, sin, &salen) == 0)
+                               svc_xprt_set_local(&svsk->sk_xprt, sin, salen);
+                       clear_bit(XPT_TEMP, &svsk->sk_xprt.xpt_flags);
+                       spin_lock_bh(&serv->sv_lock);
+                       list_add(&svsk->sk_xprt.xpt_list, &serv->sv_permsocks);
+                       spin_unlock_bh(&serv->sv_lock);
+                       svc_xprt_received(&svsk->sk_xprt);
                        err = 0;
                }
        }
@@ -1733,14 +1197,19 @@ EXPORT_SYMBOL_GPL(svc_addsock);
 /*
  * Create socket for RPC service.
  */
-static int svc_create_socket(struct svc_serv *serv, int protocol,
-                               struct sockaddr *sin, int len, int flags)
+static struct svc_xprt *svc_create_socket(struct svc_serv *serv,
+                                         int protocol,
+                                         struct sockaddr *sin, int len,
+                                         int flags)
 {
        struct svc_sock *svsk;
        struct socket   *sock;
        int             error;
        int             type;
        char            buf[RPC_MAX_ADDRBUFLEN];
+       struct sockaddr_storage addr;
+       struct sockaddr *newsin = (struct sockaddr *)&addr;
+       int             newlen;
 
        dprintk("svc: svc_create_socket(%s, %d, %s)\n",
                        serv->sv_program->pg_name, protocol,
@@ -1749,13 +1218,13 @@ static int svc_create_socket(struct svc_serv *serv, int protocol,
        if (protocol != IPPROTO_UDP && protocol != IPPROTO_TCP) {
                printk(KERN_WARNING "svc: only UDP and TCP "
                                "sockets supported\n");
-               return -EINVAL;
+               return ERR_PTR(-EINVAL);
        }
        type = (protocol == IPPROTO_UDP)? SOCK_DGRAM : SOCK_STREAM;
 
        error = sock_create_kern(sin->sa_family, type, protocol, &sock);
        if (error < 0)
-               return error;
+               return ERR_PTR(error);
 
        svc_reclassify_socket(sock);
 
@@ -1765,203 +1234,55 @@ static int svc_create_socket(struct svc_serv *serv, int protocol,
        if (error < 0)
                goto bummer;
 
+       newlen = len;
+       error = kernel_getsockname(sock, newsin, &newlen);
+       if (error < 0)
+               goto bummer;
+
        if (protocol == IPPROTO_TCP) {
                if ((error = kernel_listen(sock, 64)) < 0)
                        goto bummer;
        }
 
        if ((svsk = svc_setup_socket(serv, sock, &error, flags)) != NULL) {
-               svc_sock_received(svsk);
-               return ntohs(inet_sk(svsk->sk_sk)->sport);
+               svc_xprt_set_local(&svsk->sk_xprt, newsin, newlen);
+               return (struct svc_xprt *)svsk;
        }
 
 bummer:
        dprintk("svc: svc_create_socket error = %d\n", -error);
        sock_release(sock);
-       return error;
+       return ERR_PTR(error);
 }
 
 /*
- * Remove a dead socket
+ * Detach the svc_sock from the socket so that no
+ * more callbacks occur.
  */
-static void
-svc_delete_socket(struct svc_sock *svsk)
+static void svc_sock_detach(struct svc_xprt *xprt)
 {
-       struct svc_serv *serv;
-       struct sock     *sk;
-
-       dprintk("svc: svc_delete_socket(%p)\n", svsk);
+       struct svc_sock *svsk = container_of(xprt, struct svc_sock, sk_xprt);
+       struct sock *sk = svsk->sk_sk;
 
-       serv = svsk->sk_server;
-       sk = svsk->sk_sk;
+       dprintk("svc: svc_sock_detach(%p)\n", svsk);
 
+       /* put back the old socket callbacks */
        sk->sk_state_change = svsk->sk_ostate;
        sk->sk_data_ready = svsk->sk_odata;
        sk->sk_write_space = svsk->sk_owspace;
-
-       spin_lock_bh(&serv->sv_lock);
-
-       if (!test_and_set_bit(SK_DETACHED, &svsk->sk_flags))
-               list_del_init(&svsk->sk_list);
-       /*
-        * We used to delete the svc_sock from whichever list
-        * it's sk_ready node was on, but we don't actually
-        * need to.  This is because the only time we're called
-        * while still attached to a queue, the queue itself
-        * is about to be destroyed (in svc_destroy).
-        */
-       if (!test_and_set_bit(SK_DEAD, &svsk->sk_flags)) {
-               BUG_ON(atomic_read(&svsk->sk_inuse)<2);
-               atomic_dec(&svsk->sk_inuse);
-               if (test_bit(SK_TEMP, &svsk->sk_flags))
-                       serv->sv_tmpcnt--;
-       }
-
-       spin_unlock_bh(&serv->sv_lock);
-}
-
-static void svc_close_socket(struct svc_sock *svsk)
-{
-       set_bit(SK_CLOSE, &svsk->sk_flags);
-       if (test_and_set_bit(SK_BUSY, &svsk->sk_flags))
-               /* someone else will have to effect the close */
-               return;
-
-       atomic_inc(&svsk->sk_inuse);
-       svc_delete_socket(svsk);
-       clear_bit(SK_BUSY, &svsk->sk_flags);
-       svc_sock_put(svsk);
-}
-
-void svc_force_close_socket(struct svc_sock *svsk)
-{
-       set_bit(SK_CLOSE, &svsk->sk_flags);
-       if (test_bit(SK_BUSY, &svsk->sk_flags)) {
-               /* Waiting to be processed, but no threads left,
-                * So just remove it from the waiting list
-                */
-               list_del_init(&svsk->sk_ready);
-               clear_bit(SK_BUSY, &svsk->sk_flags);
-       }
-       svc_close_socket(svsk);
-}
-
-/**
- * svc_makesock - Make a socket for nfsd and lockd
- * @serv: RPC server structure
- * @protocol: transport protocol to use
- * @port: port to use
- * @flags: requested socket characteristics
- *
- */
-int svc_makesock(struct svc_serv *serv, int protocol, unsigned short port,
-                       int flags)
-{
-       struct sockaddr_in sin = {
-               .sin_family             = AF_INET,
-               .sin_addr.s_addr        = INADDR_ANY,
-               .sin_port               = htons(port),
-       };
-
-       dprintk("svc: creating socket proto = %d\n", protocol);
-       return svc_create_socket(serv, protocol, (struct sockaddr *) &sin,
-                                                       sizeof(sin), flags);
 }
 
 /*
- * Handle defer and revisit of requests
+ * Free the svc_sock's socket resources and the svc_sock itself.
  */
-
-static void svc_revisit(struct cache_deferred_req *dreq, int too_many)
+static void svc_sock_free(struct svc_xprt *xprt)
 {
-       struct svc_deferred_req *dr = container_of(dreq, struct svc_deferred_req, handle);
-       struct svc_sock *svsk;
+       struct svc_sock *svsk = container_of(xprt, struct svc_sock, sk_xprt);
+       dprintk("svc: svc_sock_free(%p)\n", svsk);
 
-       if (too_many) {
-               svc_sock_put(dr->svsk);
-               kfree(dr);
-               return;
-       }
-       dprintk("revisit queued\n");
-       svsk = dr->svsk;
-       dr->svsk = NULL;
-       spin_lock(&svsk->sk_lock);
-       list_add(&dr->handle.recent, &svsk->sk_deferred);
-       spin_unlock(&svsk->sk_lock);
-       set_bit(SK_DEFERRED, &svsk->sk_flags);
-       svc_sock_enqueue(svsk);
-       svc_sock_put(svsk);
-}
-
-static struct cache_deferred_req *
-svc_defer(struct cache_req *req)
-{
-       struct svc_rqst *rqstp = container_of(req, struct svc_rqst, rq_chandle);
-       int size = sizeof(struct svc_deferred_req) + (rqstp->rq_arg.len);
-       struct svc_deferred_req *dr;
-
-       if (rqstp->rq_arg.page_len)
-               return NULL; /* if more than a page, give up FIXME */
-       if (rqstp->rq_deferred) {
-               dr = rqstp->rq_deferred;
-               rqstp->rq_deferred = NULL;
-       } else {
-               int skip  = rqstp->rq_arg.len - rqstp->rq_arg.head[0].iov_len;
-               /* FIXME maybe discard if size too large */
-               dr = kmalloc(size, GFP_KERNEL);
-               if (dr == NULL)
-                       return NULL;
-
-               dr->handle.owner = rqstp->rq_server;
-               dr->prot = rqstp->rq_prot;
-               memcpy(&dr->addr, &rqstp->rq_addr, rqstp->rq_addrlen);
-               dr->addrlen = rqstp->rq_addrlen;
-               dr->daddr = rqstp->rq_daddr;
-               dr->argslen = rqstp->rq_arg.len >> 2;
-               memcpy(dr->args, rqstp->rq_arg.head[0].iov_base-skip, dr->argslen<<2);
-       }
-       atomic_inc(&rqstp->rq_sock->sk_inuse);
-       dr->svsk = rqstp->rq_sock;
-
-       dr->handle.revisit = svc_revisit;
-       return &dr->handle;
-}
-
-/*
- * recv data from a deferred request into an active one
- */
-static int svc_deferred_recv(struct svc_rqst *rqstp)
-{
-       struct svc_deferred_req *dr = rqstp->rq_deferred;
-
-       rqstp->rq_arg.head[0].iov_base = dr->args;
-       rqstp->rq_arg.head[0].iov_len = dr->argslen<<2;
-       rqstp->rq_arg.page_len = 0;
-       rqstp->rq_arg.len = dr->argslen<<2;
-       rqstp->rq_prot        = dr->prot;
-       memcpy(&rqstp->rq_addr, &dr->addr, dr->addrlen);
-       rqstp->rq_addrlen     = dr->addrlen;
-       rqstp->rq_daddr       = dr->daddr;
-       rqstp->rq_respages    = rqstp->rq_pages;
-       return dr->argslen<<2;
-}
-
-
-static struct svc_deferred_req *svc_deferred_dequeue(struct svc_sock *svsk)
-{
-       struct svc_deferred_req *dr = NULL;
-
-       if (!test_bit(SK_DEFERRED, &svsk->sk_flags))
-               return NULL;
-       spin_lock(&svsk->sk_lock);
-       clear_bit(SK_DEFERRED, &svsk->sk_flags);
-       if (!list_empty(&svsk->sk_deferred)) {
-               dr = list_entry(svsk->sk_deferred.next,
-                               struct svc_deferred_req,
-                               handle.recent);
-               list_del_init(&dr->handle.recent);
-               set_bit(SK_DEFERRED, &svsk->sk_flags);
-       }
-       spin_unlock(&svsk->sk_lock);
-       return dr;
+       if (svsk->sk_sock->file)
+               sockfd_put(svsk->sk_sock);
+       else
+               sock_release(svsk->sk_sock);
+       kfree(svsk);
 }
index bada7de0c2fcd6a216f44817cb67e03f43b736b5..0f8c439b848a1eab04f0f21f2ea763863e424b2f 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/sunrpc/types.h>
 #include <linux/sunrpc/sched.h>
 #include <linux/sunrpc/stats.h>
+#include <linux/sunrpc/svc_xprt.h>
 
 /*
  * Declare the debug flags here
@@ -55,6 +56,30 @@ rpc_unregister_sysctl(void)
        }
 }
 
+static int proc_do_xprt(ctl_table *table, int write, struct file *file,
+                       void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+       char tmpbuf[256];
+       int len;
+       if ((*ppos && !write) || !*lenp) {
+               *lenp = 0;
+               return 0;
+       }
+       if (write)
+               return -EINVAL;
+       else {
+               len = svc_print_xprts(tmpbuf, sizeof(tmpbuf));
+               if (!access_ok(VERIFY_WRITE, buffer, len))
+                       return -EFAULT;
+
+               if (__copy_to_user(buffer, tmpbuf, len))
+                       return -EFAULT;
+       }
+       *lenp -= len;
+       *ppos += len;
+       return 0;
+}
+
 static int
 proc_dodebug(ctl_table *table, int write, struct file *file,
                                void __user *buffer, size_t *lenp, loff_t *ppos)
@@ -147,6 +172,12 @@ static ctl_table debug_table[] = {
                .mode           = 0644,
                .proc_handler   = &proc_dodebug
        },
+       {
+               .procname       = "transports",
+               .maxlen         = 256,
+               .mode           = 0444,
+               .proc_handler   = &proc_do_xprt,
+       },
        { .ctl_name = 0 }
 };
 
index 54264062ea695d59f85da1d712f53cd0ff45952a..995c3fdc16c27821d2e97887a6bdba002a086321 100644 (file)
@@ -96,11 +96,13 @@ xdr_encode_string(__be32 *p, const char *string)
 EXPORT_SYMBOL(xdr_encode_string);
 
 __be32 *
-xdr_decode_string_inplace(__be32 *p, char **sp, int *lenp, int maxlen)
+xdr_decode_string_inplace(__be32 *p, char **sp,
+                         unsigned int *lenp, unsigned int maxlen)
 {
-       unsigned int    len;
+       u32 len;
 
-       if ((len = ntohl(*p++)) > maxlen)
+       len = ntohl(*p++);
+       if (len > maxlen)
                return NULL;
        *lenp = len;
        *sp = (char *) p;
index 264f0feeb513e24b8d4b3cfef9e6850b1a0fcff1..5a8f268bdd30c5dedfcb73dc6b071c1263553875 100644 (file)
@@ -1,3 +1,8 @@
 obj-$(CONFIG_SUNRPC_XPRT_RDMA) += xprtrdma.o
 
 xprtrdma-y := transport.o rpc_rdma.o verbs.o
+
+obj-$(CONFIG_SUNRPC_XPRT_RDMA) += svcrdma.o
+
+svcrdma-y := svc_rdma.o svc_rdma_transport.o \
+       svc_rdma_marshal.o svc_rdma_sendto.o svc_rdma_recvfrom.o
diff --git a/net/sunrpc/xprtrdma/svc_rdma.c b/net/sunrpc/xprtrdma/svc_rdma.c
new file mode 100644 (file)
index 0000000..88c0ca2
--- /dev/null
@@ -0,0 +1,266 @@
+/*
+ * Copyright (c) 2005-2006 Network Appliance, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the BSD-type
+ * license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *      Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *      Redistributions in binary form must reproduce the above
+ *      copyright notice, this list of conditions and the following
+ *      disclaimer in the documentation and/or other materials provided
+ *      with the distribution.
+ *
+ *      Neither the name of the Network Appliance, Inc. nor the names of
+ *      its contributors may be used to endorse or promote products
+ *      derived from this software without specific prior written
+ *      permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Author: Tom Tucker <tom@opengridcomputing.com>
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/sysctl.h>
+#include <linux/sunrpc/clnt.h>
+#include <linux/sunrpc/sched.h>
+#include <linux/sunrpc/svc_rdma.h>
+
+#define RPCDBG_FACILITY        RPCDBG_SVCXPRT
+
+/* RPC/RDMA parameters */
+unsigned int svcrdma_ord = RPCRDMA_ORD;
+static unsigned int min_ord = 1;
+static unsigned int max_ord = 4096;
+unsigned int svcrdma_max_requests = RPCRDMA_MAX_REQUESTS;
+static unsigned int min_max_requests = 4;
+static unsigned int max_max_requests = 16384;
+unsigned int svcrdma_max_req_size = RPCRDMA_MAX_REQ_SIZE;
+static unsigned int min_max_inline = 4096;
+static unsigned int max_max_inline = 65536;
+
+atomic_t rdma_stat_recv;
+atomic_t rdma_stat_read;
+atomic_t rdma_stat_write;
+atomic_t rdma_stat_sq_starve;
+atomic_t rdma_stat_rq_starve;
+atomic_t rdma_stat_rq_poll;
+atomic_t rdma_stat_rq_prod;
+atomic_t rdma_stat_sq_poll;
+atomic_t rdma_stat_sq_prod;
+
+/*
+ * This function implements reading and resetting an atomic_t stat
+ * variable through read/write to a proc file. Any write to the file
+ * resets the associated statistic to zero. Any read returns it's
+ * current value.
+ */
+static int read_reset_stat(ctl_table *table, int write,
+                          struct file *filp, void __user *buffer, size_t *lenp,
+                          loff_t *ppos)
+{
+       atomic_t *stat = (atomic_t *)table->data;
+
+       if (!stat)
+               return -EINVAL;
+
+       if (write)
+               atomic_set(stat, 0);
+       else {
+               char str_buf[32];
+               char *data;
+               int len = snprintf(str_buf, 32, "%d\n", atomic_read(stat));
+               if (len >= 32)
+                       return -EFAULT;
+               len = strlen(str_buf);
+               if (*ppos > len) {
+                       *lenp = 0;
+                       return 0;
+               }
+               data = &str_buf[*ppos];
+               len -= *ppos;
+               if (len > *lenp)
+                       len = *lenp;
+               if (len && copy_to_user(buffer, str_buf, len))
+                       return -EFAULT;
+               *lenp = len;
+               *ppos += len;
+       }
+       return 0;
+}
+
+static struct ctl_table_header *svcrdma_table_header;
+static ctl_table svcrdma_parm_table[] = {
+       {
+               .procname       = "max_requests",
+               .data           = &svcrdma_max_requests,
+               .maxlen         = sizeof(unsigned int),
+               .mode           = 0644,
+               .proc_handler   = &proc_dointvec_minmax,
+               .strategy       = &sysctl_intvec,
+               .extra1         = &min_max_requests,
+               .extra2         = &max_max_requests
+       },
+       {
+               .procname       = "max_req_size",
+               .data           = &svcrdma_max_req_size,
+               .maxlen         = sizeof(unsigned int),
+               .mode           = 0644,
+               .proc_handler   = &proc_dointvec_minmax,
+               .strategy       = &sysctl_intvec,
+               .extra1         = &min_max_inline,
+               .extra2         = &max_max_inline
+       },
+       {
+               .procname       = "max_outbound_read_requests",
+               .data           = &svcrdma_ord,
+               .maxlen         = sizeof(unsigned int),
+               .mode           = 0644,
+               .proc_handler   = &proc_dointvec_minmax,
+               .strategy       = &sysctl_intvec,
+               .extra1         = &min_ord,
+               .extra2         = &max_ord,
+       },
+
+       {
+               .procname       = "rdma_stat_read",
+               .data           = &rdma_stat_read,
+               .maxlen         = sizeof(atomic_t),
+               .mode           = 0644,
+               .proc_handler   = &read_reset_stat,
+       },
+       {
+               .procname       = "rdma_stat_recv",
+               .data           = &rdma_stat_recv,
+               .maxlen         = sizeof(atomic_t),
+               .mode           = 0644,
+               .proc_handler   = &read_reset_stat,
+       },
+       {
+               .procname       = "rdma_stat_write",
+               .data           = &rdma_stat_write,
+               .maxlen         = sizeof(atomic_t),
+               .mode           = 0644,
+               .proc_handler   = &read_reset_stat,
+       },
+       {
+               .procname       = "rdma_stat_sq_starve",
+               .data           = &rdma_stat_sq_starve,
+               .maxlen         = sizeof(atomic_t),
+               .mode           = 0644,
+               .proc_handler   = &read_reset_stat,
+       },
+       {
+               .procname       = "rdma_stat_rq_starve",
+               .data           = &rdma_stat_rq_starve,
+               .maxlen         = sizeof(atomic_t),
+               .mode           = 0644,
+               .proc_handler   = &read_reset_stat,
+       },
+       {
+               .procname       = "rdma_stat_rq_poll",
+               .data           = &rdma_stat_rq_poll,
+               .maxlen         = sizeof(atomic_t),
+               .mode           = 0644,
+               .proc_handler   = &read_reset_stat,
+       },
+       {
+               .procname       = "rdma_stat_rq_prod",
+               .data           = &rdma_stat_rq_prod,
+               .maxlen         = sizeof(atomic_t),
+               .mode           = 0644,
+               .proc_handler   = &read_reset_stat,
+       },
+       {
+               .procname       = "rdma_stat_sq_poll",
+               .data           = &rdma_stat_sq_poll,
+               .maxlen         = sizeof(atomic_t),
+               .mode           = 0644,
+               .proc_handler   = &read_reset_stat,
+       },
+       {
+               .procname       = "rdma_stat_sq_prod",
+               .data           = &rdma_stat_sq_prod,
+               .maxlen         = sizeof(atomic_t),
+               .mode           = 0644,
+               .proc_handler   = &read_reset_stat,
+       },
+       {
+               .ctl_name = 0,
+       },
+};
+
+static ctl_table svcrdma_table[] = {
+       {
+               .procname       = "svc_rdma",
+               .mode           = 0555,
+               .child          = svcrdma_parm_table
+       },
+       {
+               .ctl_name = 0,
+       },
+};
+
+static ctl_table svcrdma_root_table[] = {
+       {
+               .ctl_name       = CTL_SUNRPC,
+               .procname       = "sunrpc",
+               .mode           = 0555,
+               .child          = svcrdma_table
+       },
+       {
+               .ctl_name = 0,
+       },
+};
+
+void svc_rdma_cleanup(void)
+{
+       dprintk("SVCRDMA Module Removed, deregister RPC RDMA transport\n");
+       if (svcrdma_table_header) {
+               unregister_sysctl_table(svcrdma_table_header);
+               svcrdma_table_header = NULL;
+       }
+       svc_unreg_xprt_class(&svc_rdma_class);
+}
+
+int svc_rdma_init(void)
+{
+       dprintk("SVCRDMA Module Init, register RPC RDMA transport\n");
+       dprintk("\tsvcrdma_ord      : %d\n", svcrdma_ord);
+       dprintk("\tmax_requests     : %d\n", svcrdma_max_requests);
+       dprintk("\tsq_depth         : %d\n",
+               svcrdma_max_requests * RPCRDMA_SQ_DEPTH_MULT);
+       dprintk("\tmax_inline       : %d\n", svcrdma_max_req_size);
+       if (!svcrdma_table_header)
+               svcrdma_table_header =
+                       register_sysctl_table(svcrdma_root_table);
+
+       /* Register RDMA with the SVC transport switch */
+       svc_reg_xprt_class(&svc_rdma_class);
+       return 0;
+}
+MODULE_AUTHOR("Tom Tucker <tom@opengridcomputing.com>");
+MODULE_DESCRIPTION("SVC RDMA Transport");
+MODULE_LICENSE("Dual BSD/GPL");
+module_init(svc_rdma_init);
+module_exit(svc_rdma_cleanup);
diff --git a/net/sunrpc/xprtrdma/svc_rdma_marshal.c b/net/sunrpc/xprtrdma/svc_rdma_marshal.c
new file mode 100644 (file)
index 0000000..9530ef2
--- /dev/null
@@ -0,0 +1,412 @@
+/*
+ * Copyright (c) 2005-2006 Network Appliance, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the BSD-type
+ * license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *      Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *      Redistributions in binary form must reproduce the above
+ *      copyright notice, this list of conditions and the following
+ *      disclaimer in the documentation and/or other materials provided
+ *      with the distribution.
+ *
+ *      Neither the name of the Network Appliance, Inc. nor the names of
+ *      its contributors may be used to endorse or promote products
+ *      derived from this software without specific prior written
+ *      permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Author: Tom Tucker <tom@opengridcomputing.com>
+ */
+
+#include <linux/sunrpc/xdr.h>
+#include <linux/sunrpc/debug.h>
+#include <asm/unaligned.h>
+#include <linux/sunrpc/rpc_rdma.h>
+#include <linux/sunrpc/svc_rdma.h>
+
+#define RPCDBG_FACILITY        RPCDBG_SVCXPRT
+
+/*
+ * Decodes a read chunk list. The expected format is as follows:
+ *    descrim  : xdr_one
+ *    position : u32 offset into XDR stream
+ *    handle   : u32 RKEY
+ *    . . .
+ *  end-of-list: xdr_zero
+ */
+static u32 *decode_read_list(u32 *va, u32 *vaend)
+{
+       struct rpcrdma_read_chunk *ch = (struct rpcrdma_read_chunk *)va;
+
+       while (ch->rc_discrim != xdr_zero) {
+               u64 ch_offset;
+
+               if (((unsigned long)ch + sizeof(struct rpcrdma_read_chunk)) >
+                   (unsigned long)vaend) {
+                       dprintk("svcrdma: vaend=%p, ch=%p\n", vaend, ch);
+                       return NULL;
+               }
+
+               ch->rc_discrim = ntohl(ch->rc_discrim);
+               ch->rc_position = ntohl(ch->rc_position);
+               ch->rc_target.rs_handle = ntohl(ch->rc_target.rs_handle);
+               ch->rc_target.rs_length = ntohl(ch->rc_target.rs_length);
+               va = (u32 *)&ch->rc_target.rs_offset;
+               xdr_decode_hyper(va, &ch_offset);
+               put_unaligned(ch_offset, (u64 *)va);
+               ch++;
+       }
+       return (u32 *)&ch->rc_position;
+}
+
+/*
+ * Determine number of chunks and total bytes in chunk list. The chunk
+ * list has already been verified to fit within the RPCRDMA header.
+ */
+void svc_rdma_rcl_chunk_counts(struct rpcrdma_read_chunk *ch,
+                              int *ch_count, int *byte_count)
+{
+       /* compute the number of bytes represented by read chunks */
+       *byte_count = 0;
+       *ch_count = 0;
+       for (; ch->rc_discrim != 0; ch++) {
+               *byte_count = *byte_count + ch->rc_target.rs_length;
+               *ch_count = *ch_count + 1;
+       }
+}
+
+/*
+ * Decodes a write chunk list. The expected format is as follows:
+ *    descrim  : xdr_one
+ *    nchunks  : <count>
+ *       handle   : u32 RKEY              ---+
+ *       length   : u32 <len of segment>     |
+ *       offset   : remove va                + <count>
+ *       . . .                               |
+ *                                        ---+
+ */
+static u32 *decode_write_list(u32 *va, u32 *vaend)
+{
+       int ch_no;
+       struct rpcrdma_write_array *ary =
+               (struct rpcrdma_write_array *)va;
+
+       /* Check for not write-array */
+       if (ary->wc_discrim == xdr_zero)
+               return (u32 *)&ary->wc_nchunks;
+
+       if ((unsigned long)ary + sizeof(struct rpcrdma_write_array) >
+           (unsigned long)vaend) {
+               dprintk("svcrdma: ary=%p, vaend=%p\n", ary, vaend);
+               return NULL;
+       }
+       ary->wc_discrim = ntohl(ary->wc_discrim);
+       ary->wc_nchunks = ntohl(ary->wc_nchunks);
+       if (((unsigned long)&ary->wc_array[0] +
+            (sizeof(struct rpcrdma_write_chunk) * ary->wc_nchunks)) >
+           (unsigned long)vaend) {
+               dprintk("svcrdma: ary=%p, wc_nchunks=%d, vaend=%p\n",
+                       ary, ary->wc_nchunks, vaend);
+               return NULL;
+       }
+       for (ch_no = 0; ch_no < ary->wc_nchunks; ch_no++) {
+               u64 ch_offset;
+
+               ary->wc_array[ch_no].wc_target.rs_handle =
+                       ntohl(ary->wc_array[ch_no].wc_target.rs_handle);
+               ary->wc_array[ch_no].wc_target.rs_length =
+                       ntohl(ary->wc_array[ch_no].wc_target.rs_length);
+               va = (u32 *)&ary->wc_array[ch_no].wc_target.rs_offset;
+               xdr_decode_hyper(va, &ch_offset);
+               put_unaligned(ch_offset, (u64 *)va);
+       }
+
+       /*
+        * rs_length is the 2nd 4B field in wc_target and taking its
+        * address skips the list terminator
+        */
+       return (u32 *)&ary->wc_array[ch_no].wc_target.rs_length;
+}
+
+static u32 *decode_reply_array(u32 *va, u32 *vaend)
+{
+       int ch_no;
+       struct rpcrdma_write_array *ary =
+               (struct rpcrdma_write_array *)va;
+
+       /* Check for no reply-array */
+       if (ary->wc_discrim == xdr_zero)
+               return (u32 *)&ary->wc_nchunks;
+
+       if ((unsigned long)ary + sizeof(struct rpcrdma_write_array) >
+           (unsigned long)vaend) {
+               dprintk("svcrdma: ary=%p, vaend=%p\n", ary, vaend);
+               return NULL;
+       }
+       ary->wc_discrim = ntohl(ary->wc_discrim);
+       ary->wc_nchunks = ntohl(ary->wc_nchunks);
+       if (((unsigned long)&ary->wc_array[0] +
+            (sizeof(struct rpcrdma_write_chunk) * ary->wc_nchunks)) >
+           (unsigned long)vaend) {
+               dprintk("svcrdma: ary=%p, wc_nchunks=%d, vaend=%p\n",
+                       ary, ary->wc_nchunks, vaend);
+               return NULL;
+       }
+       for (ch_no = 0; ch_no < ary->wc_nchunks; ch_no++) {
+               u64 ch_offset;
+
+               ary->wc_array[ch_no].wc_target.rs_handle =
+                       ntohl(ary->wc_array[ch_no].wc_target.rs_handle);
+               ary->wc_array[ch_no].wc_target.rs_length =
+                       ntohl(ary->wc_array[ch_no].wc_target.rs_length);
+               va = (u32 *)&ary->wc_array[ch_no].wc_target.rs_offset;
+               xdr_decode_hyper(va, &ch_offset);
+               put_unaligned(ch_offset, (u64 *)va);
+       }
+
+       return (u32 *)&ary->wc_array[ch_no];
+}
+
+int svc_rdma_xdr_decode_req(struct rpcrdma_msg **rdma_req,
+                           struct svc_rqst *rqstp)
+{
+       struct rpcrdma_msg *rmsgp = NULL;
+       u32 *va;
+       u32 *vaend;
+       u32 hdr_len;
+
+       rmsgp = (struct rpcrdma_msg *)rqstp->rq_arg.head[0].iov_base;
+
+       /* Verify that there's enough bytes for header + something */
+       if (rqstp->rq_arg.len <= RPCRDMA_HDRLEN_MIN) {
+               dprintk("svcrdma: header too short = %d\n",
+                       rqstp->rq_arg.len);
+               return -EINVAL;
+       }
+
+       /* Decode the header */
+       rmsgp->rm_xid = ntohl(rmsgp->rm_xid);
+       rmsgp->rm_vers = ntohl(rmsgp->rm_vers);
+       rmsgp->rm_credit = ntohl(rmsgp->rm_credit);
+       rmsgp->rm_type = ntohl(rmsgp->rm_type);
+
+       if (rmsgp->rm_vers != RPCRDMA_VERSION)
+               return -ENOSYS;
+
+       /* Pull in the extra for the padded case and bump our pointer */
+       if (rmsgp->rm_type == RDMA_MSGP) {
+               int hdrlen;
+               rmsgp->rm_body.rm_padded.rm_align =
+                       ntohl(rmsgp->rm_body.rm_padded.rm_align);
+               rmsgp->rm_body.rm_padded.rm_thresh =
+                       ntohl(rmsgp->rm_body.rm_padded.rm_thresh);
+
+               va = &rmsgp->rm_body.rm_padded.rm_pempty[4];
+               rqstp->rq_arg.head[0].iov_base = va;
+               hdrlen = (u32)((unsigned long)va - (unsigned long)rmsgp);
+               rqstp->rq_arg.head[0].iov_len -= hdrlen;
+               if (hdrlen > rqstp->rq_arg.len)
+                       return -EINVAL;
+               return hdrlen;
+       }
+
+       /* The chunk list may contain either a read chunk list or a write
+        * chunk list and a reply chunk list.
+        */
+       va = &rmsgp->rm_body.rm_chunks[0];
+       vaend = (u32 *)((unsigned long)rmsgp + rqstp->rq_arg.len);
+       va = decode_read_list(va, vaend);
+       if (!va)
+               return -EINVAL;
+       va = decode_write_list(va, vaend);
+       if (!va)
+               return -EINVAL;
+       va = decode_reply_array(va, vaend);
+       if (!va)
+               return -EINVAL;
+
+       rqstp->rq_arg.head[0].iov_base = va;
+       hdr_len = (unsigned long)va - (unsigned long)rmsgp;
+       rqstp->rq_arg.head[0].iov_len -= hdr_len;
+
+       *rdma_req = rmsgp;
+       return hdr_len;
+}
+
+int svc_rdma_xdr_decode_deferred_req(struct svc_rqst *rqstp)
+{
+       struct rpcrdma_msg *rmsgp = NULL;
+       struct rpcrdma_read_chunk *ch;
+       struct rpcrdma_write_array *ary;
+       u32 *va;
+       u32 hdrlen;
+
+       dprintk("svcrdma: processing deferred RDMA header on rqstp=%p\n",
+               rqstp);
+       rmsgp = (struct rpcrdma_msg *)rqstp->rq_arg.head[0].iov_base;
+
+       /* Pull in the extra for the padded case and bump our pointer */
+       if (rmsgp->rm_type == RDMA_MSGP) {
+               va = &rmsgp->rm_body.rm_padded.rm_pempty[4];
+               rqstp->rq_arg.head[0].iov_base = va;
+               hdrlen = (u32)((unsigned long)va - (unsigned long)rmsgp);
+               rqstp->rq_arg.head[0].iov_len -= hdrlen;
+               return hdrlen;
+       }
+
+       /*
+        * Skip all chunks to find RPC msg. These were previously processed
+        */
+       va = &rmsgp->rm_body.rm_chunks[0];
+
+       /* Skip read-list */
+       for (ch = (struct rpcrdma_read_chunk *)va;
+            ch->rc_discrim != xdr_zero; ch++);
+       va = (u32 *)&ch->rc_position;
+
+       /* Skip write-list */
+       ary = (struct rpcrdma_write_array *)va;
+       if (ary->wc_discrim == xdr_zero)
+               va = (u32 *)&ary->wc_nchunks;
+       else
+               /*
+                * rs_length is the 2nd 4B field in wc_target and taking its
+                * address skips the list terminator
+                */
+               va = (u32 *)&ary->wc_array[ary->wc_nchunks].wc_target.rs_length;
+
+       /* Skip reply-array */
+       ary = (struct rpcrdma_write_array *)va;
+       if (ary->wc_discrim == xdr_zero)
+               va = (u32 *)&ary->wc_nchunks;
+       else
+               va = (u32 *)&ary->wc_array[ary->wc_nchunks];
+
+       rqstp->rq_arg.head[0].iov_base = va;
+       hdrlen = (unsigned long)va - (unsigned long)rmsgp;
+       rqstp->rq_arg.head[0].iov_len -= hdrlen;
+
+       return hdrlen;
+}
+
+int svc_rdma_xdr_encode_error(struct svcxprt_rdma *xprt,
+                             struct rpcrdma_msg *rmsgp,
+                             enum rpcrdma_errcode err, u32 *va)
+{
+       u32 *startp = va;
+
+       *va++ = htonl(rmsgp->rm_xid);
+       *va++ = htonl(rmsgp->rm_vers);
+       *va++ = htonl(xprt->sc_max_requests);
+       *va++ = htonl(RDMA_ERROR);
+       *va++ = htonl(err);
+       if (err == ERR_VERS) {
+               *va++ = htonl(RPCRDMA_VERSION);
+               *va++ = htonl(RPCRDMA_VERSION);
+       }
+
+       return (int)((unsigned long)va - (unsigned long)startp);
+}
+
+int svc_rdma_xdr_get_reply_hdr_len(struct rpcrdma_msg *rmsgp)
+{
+       struct rpcrdma_write_array *wr_ary;
+
+       /* There is no read-list in a reply */
+
+       /* skip write list */
+       wr_ary = (struct rpcrdma_write_array *)
+               &rmsgp->rm_body.rm_chunks[1];
+       if (wr_ary->wc_discrim)
+               wr_ary = (struct rpcrdma_write_array *)
+                       &wr_ary->wc_array[ntohl(wr_ary->wc_nchunks)].
+                       wc_target.rs_length;
+       else
+               wr_ary = (struct rpcrdma_write_array *)
+                       &wr_ary->wc_nchunks;
+
+       /* skip reply array */
+       if (wr_ary->wc_discrim)
+               wr_ary = (struct rpcrdma_write_array *)
+                       &wr_ary->wc_array[ntohl(wr_ary->wc_nchunks)];
+       else
+               wr_ary = (struct rpcrdma_write_array *)
+                       &wr_ary->wc_nchunks;
+
+       return (unsigned long) wr_ary - (unsigned long) rmsgp;
+}
+
+void svc_rdma_xdr_encode_write_list(struct rpcrdma_msg *rmsgp, int chunks)
+{
+       struct rpcrdma_write_array *ary;
+
+       /* no read-list */
+       rmsgp->rm_body.rm_chunks[0] = xdr_zero;
+
+       /* write-array discrim */
+       ary = (struct rpcrdma_write_array *)
+               &rmsgp->rm_body.rm_chunks[1];
+       ary->wc_discrim = xdr_one;
+       ary->wc_nchunks = htonl(chunks);
+
+       /* write-list terminator */
+       ary->wc_array[chunks].wc_target.rs_handle = xdr_zero;
+
+       /* reply-array discriminator */
+       ary->wc_array[chunks].wc_target.rs_length = xdr_zero;
+}
+
+void svc_rdma_xdr_encode_reply_array(struct rpcrdma_write_array *ary,
+                                int chunks)
+{
+       ary->wc_discrim = xdr_one;
+       ary->wc_nchunks = htonl(chunks);
+}
+
+void svc_rdma_xdr_encode_array_chunk(struct rpcrdma_write_array *ary,
+                                    int chunk_no,
+                                    u32 rs_handle, u64 rs_offset,
+                                    u32 write_len)
+{
+       struct rpcrdma_segment *seg = &ary->wc_array[chunk_no].wc_target;
+       seg->rs_handle = htonl(rs_handle);
+       seg->rs_length = htonl(write_len);
+       xdr_encode_hyper((u32 *) &seg->rs_offset, rs_offset);
+}
+
+void svc_rdma_xdr_encode_reply_header(struct svcxprt_rdma *xprt,
+                                 struct rpcrdma_msg *rdma_argp,
+                                 struct rpcrdma_msg *rdma_resp,
+                                 enum rpcrdma_proc rdma_type)
+{
+       rdma_resp->rm_xid = htonl(rdma_argp->rm_xid);
+       rdma_resp->rm_vers = htonl(rdma_argp->rm_vers);
+       rdma_resp->rm_credit = htonl(xprt->sc_max_requests);
+       rdma_resp->rm_type = htonl(rdma_type);
+
+       /* Encode <nul> chunks lists */
+       rdma_resp->rm_body.rm_chunks[0] = xdr_zero;
+       rdma_resp->rm_body.rm_chunks[1] = xdr_zero;
+       rdma_resp->rm_body.rm_chunks[2] = xdr_zero;
+}
diff --git a/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c
new file mode 100644 (file)
index 0000000..ab54a73
--- /dev/null
@@ -0,0 +1,586 @@
+/*
+ * Copyright (c) 2005-2006 Network Appliance, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the BSD-type
+ * license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *      Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *      Redistributions in binary form must reproduce the above
+ *      copyright notice, this list of conditions and the following
+ *      disclaimer in the documentation and/or other materials provided
+ *      with the distribution.
+ *
+ *      Neither the name of the Network Appliance, Inc. nor the names of
+ *      its contributors may be used to endorse or promote products
+ *      derived from this software without specific prior written
+ *      permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Author: Tom Tucker <tom@opengridcomputing.com>
+ */
+
+#include <linux/sunrpc/debug.h>
+#include <linux/sunrpc/rpc_rdma.h>
+#include <linux/spinlock.h>
+#include <asm/unaligned.h>
+#include <rdma/ib_verbs.h>
+#include <rdma/rdma_cm.h>
+#include <linux/sunrpc/svc_rdma.h>
+
+#define RPCDBG_FACILITY        RPCDBG_SVCXPRT
+
+/*
+ * Replace the pages in the rq_argpages array with the pages from the SGE in
+ * the RDMA_RECV completion. The SGL should contain full pages up until the
+ * last one.
+ */
+static void rdma_build_arg_xdr(struct svc_rqst *rqstp,
+                              struct svc_rdma_op_ctxt *ctxt,
+                              u32 byte_count)
+{
+       struct page *page;
+       u32 bc;
+       int sge_no;
+
+       /* Swap the page in the SGE with the page in argpages */
+       page = ctxt->pages[0];
+       put_page(rqstp->rq_pages[0]);
+       rqstp->rq_pages[0] = page;
+
+       /* Set up the XDR head */
+       rqstp->rq_arg.head[0].iov_base = page_address(page);
+       rqstp->rq_arg.head[0].iov_len = min(byte_count, ctxt->sge[0].length);
+       rqstp->rq_arg.len = byte_count;
+       rqstp->rq_arg.buflen = byte_count;
+
+       /* Compute bytes past head in the SGL */
+       bc = byte_count - rqstp->rq_arg.head[0].iov_len;
+
+       /* If data remains, store it in the pagelist */
+       rqstp->rq_arg.page_len = bc;
+       rqstp->rq_arg.page_base = 0;
+       rqstp->rq_arg.pages = &rqstp->rq_pages[1];
+       sge_no = 1;
+       while (bc && sge_no < ctxt->count) {
+               page = ctxt->pages[sge_no];
+               put_page(rqstp->rq_pages[sge_no]);
+               rqstp->rq_pages[sge_no] = page;
+               bc -= min(bc, ctxt->sge[sge_no].length);
+               rqstp->rq_arg.buflen += ctxt->sge[sge_no].length;
+               sge_no++;
+       }
+       rqstp->rq_respages = &rqstp->rq_pages[sge_no];
+
+       /* We should never run out of SGE because the limit is defined to
+        * support the max allowed RPC data length
+        */
+       BUG_ON(bc && (sge_no == ctxt->count));
+       BUG_ON((rqstp->rq_arg.head[0].iov_len + rqstp->rq_arg.page_len)
+              != byte_count);
+       BUG_ON(rqstp->rq_arg.len != byte_count);
+
+       /* If not all pages were used from the SGL, free the remaining ones */
+       bc = sge_no;
+       while (sge_no < ctxt->count) {
+               page = ctxt->pages[sge_no++];
+               put_page(page);
+       }
+       ctxt->count = bc;
+
+       /* Set up tail */
+       rqstp->rq_arg.tail[0].iov_base = NULL;
+       rqstp->rq_arg.tail[0].iov_len = 0;
+}
+
+struct chunk_sge {
+       int start;              /* sge no for this chunk */
+       int count;              /* sge count for this chunk */
+};
+
+/* Encode a read-chunk-list as an array of IB SGE
+ *
+ * Assumptions:
+ * - chunk[0]->position points to pages[0] at an offset of 0
+ * - pages[] is not physically or virtually contigous and consists of
+ *   PAGE_SIZE elements.
+ *
+ * Output:
+ * - sge array pointing into pages[] array.
+ * - chunk_sge array specifying sge index and count for each
+ *   chunk in the read list
+ *
+ */
+static int rdma_rcl_to_sge(struct svcxprt_rdma *xprt,
+                          struct svc_rqst *rqstp,
+                          struct svc_rdma_op_ctxt *head,
+                          struct rpcrdma_msg *rmsgp,
+                          struct ib_sge *sge,
+                          struct chunk_sge *ch_sge_ary,
+                          int ch_count,
+                          int byte_count)
+{
+       int sge_no;
+       int sge_bytes;
+       int page_off;
+       int page_no;
+       int ch_bytes;
+       int ch_no;
+       struct rpcrdma_read_chunk *ch;
+
+       sge_no = 0;
+       page_no = 0;
+       page_off = 0;
+       ch = (struct rpcrdma_read_chunk *)&rmsgp->rm_body.rm_chunks[0];
+       ch_no = 0;
+       ch_bytes = ch->rc_target.rs_length;
+       head->arg.head[0] = rqstp->rq_arg.head[0];
+       head->arg.tail[0] = rqstp->rq_arg.tail[0];
+       head->arg.pages = &head->pages[head->count];
+       head->sge[0].length = head->count; /* save count of hdr pages */
+       head->arg.page_base = 0;
+       head->arg.page_len = ch_bytes;
+       head->arg.len = rqstp->rq_arg.len + ch_bytes;
+       head->arg.buflen = rqstp->rq_arg.buflen + ch_bytes;
+       head->count++;
+       ch_sge_ary[0].start = 0;
+       while (byte_count) {
+               sge_bytes = min_t(int, PAGE_SIZE-page_off, ch_bytes);
+               sge[sge_no].addr =
+                       ib_dma_map_page(xprt->sc_cm_id->device,
+                                       rqstp->rq_arg.pages[page_no],
+                                       page_off, sge_bytes,
+                                       DMA_FROM_DEVICE);
+               sge[sge_no].length = sge_bytes;
+               sge[sge_no].lkey = xprt->sc_phys_mr->lkey;
+               /*
+                * Don't bump head->count here because the same page
+                * may be used by multiple SGE.
+                */
+               head->arg.pages[page_no] = rqstp->rq_arg.pages[page_no];
+               rqstp->rq_respages = &rqstp->rq_arg.pages[page_no+1];
+
+               byte_count -= sge_bytes;
+               ch_bytes -= sge_bytes;
+               sge_no++;
+               /*
+                * If all bytes for this chunk have been mapped to an
+                * SGE, move to the next SGE
+                */
+               if (ch_bytes == 0) {
+                       ch_sge_ary[ch_no].count =
+                               sge_no - ch_sge_ary[ch_no].start;
+                       ch_no++;
+                       ch++;
+                       ch_sge_ary[ch_no].start = sge_no;
+                       ch_bytes = ch->rc_target.rs_length;
+                       /* If bytes remaining account for next chunk */
+                       if (byte_count) {
+                               head->arg.page_len += ch_bytes;
+                               head->arg.len += ch_bytes;
+                               head->arg.buflen += ch_bytes;
+                       }
+               }
+               /*
+                * If this SGE consumed all of the page, move to the
+                * next page
+                */
+               if ((sge_bytes + page_off) == PAGE_SIZE) {
+                       page_no++;
+                       page_off = 0;
+                       /*
+                        * If there are still bytes left to map, bump
+                        * the page count
+                        */
+                       if (byte_count)
+                               head->count++;
+               } else
+                       page_off += sge_bytes;
+       }
+       BUG_ON(byte_count != 0);
+       return sge_no;
+}
+
+static void rdma_set_ctxt_sge(struct svc_rdma_op_ctxt *ctxt,
+                             struct ib_sge *sge,
+                             u64 *sgl_offset,
+                             int count)
+{
+       int i;
+
+       ctxt->count = count;
+       for (i = 0; i < count; i++) {
+               ctxt->sge[i].addr = sge[i].addr;
+               ctxt->sge[i].length = sge[i].length;
+               *sgl_offset = *sgl_offset + sge[i].length;
+       }
+}
+
+static int rdma_read_max_sge(struct svcxprt_rdma *xprt, int sge_count)
+{
+#ifdef RDMA_TRANSPORT_IWARP
+       if ((RDMA_TRANSPORT_IWARP ==
+            rdma_node_get_transport(xprt->sc_cm_id->
+                                    device->node_type))
+           && sge_count > 1)
+               return 1;
+       else
+#endif
+               return min_t(int, sge_count, xprt->sc_max_sge);
+}
+
+/*
+ * Use RDMA_READ to read data from the advertised client buffer into the
+ * XDR stream starting at rq_arg.head[0].iov_base.
+ * Each chunk in the array
+ * contains the following fields:
+ * discrim      - '1', This isn't used for data placement
+ * position     - The xdr stream offset (the same for every chunk)
+ * handle       - RMR for client memory region
+ * length       - data transfer length
+ * offset       - 64 bit tagged offset in remote memory region
+ *
+ * On our side, we need to read into a pagelist. The first page immediately
+ * follows the RPC header.
+ *
+ * This function returns 1 to indicate success. The data is not yet in
+ * the pagelist and therefore the RPC request must be deferred. The
+ * I/O completion will enqueue the transport again and
+ * svc_rdma_recvfrom will complete the request.
+ *
+ * NOTE: The ctxt must not be touched after the last WR has been posted
+ * because the I/O completion processing may occur on another
+ * processor and free / modify the context. Ne touche pas!
+ */
+static int rdma_read_xdr(struct svcxprt_rdma *xprt,
+                        struct rpcrdma_msg *rmsgp,
+                        struct svc_rqst *rqstp,
+                        struct svc_rdma_op_ctxt *hdr_ctxt)
+{
+       struct ib_send_wr read_wr;
+       int err = 0;
+       int ch_no;
+       struct ib_sge *sge;
+       int ch_count;
+       int byte_count;
+       int sge_count;
+       u64 sgl_offset;
+       struct rpcrdma_read_chunk *ch;
+       struct svc_rdma_op_ctxt *ctxt = NULL;
+       struct svc_rdma_op_ctxt *head;
+       struct svc_rdma_op_ctxt *tmp_sge_ctxt;
+       struct svc_rdma_op_ctxt *tmp_ch_ctxt;
+       struct chunk_sge *ch_sge_ary;
+
+       /* If no read list is present, return 0 */
+       ch = svc_rdma_get_read_chunk(rmsgp);
+       if (!ch)
+               return 0;
+
+       /* Allocate temporary contexts to keep SGE */
+       BUG_ON(sizeof(struct ib_sge) < sizeof(struct chunk_sge));
+       tmp_sge_ctxt = svc_rdma_get_context(xprt);
+       sge = tmp_sge_ctxt->sge;
+       tmp_ch_ctxt = svc_rdma_get_context(xprt);
+       ch_sge_ary = (struct chunk_sge *)tmp_ch_ctxt->sge;
+
+       svc_rdma_rcl_chunk_counts(ch, &ch_count, &byte_count);
+       sge_count = rdma_rcl_to_sge(xprt, rqstp, hdr_ctxt, rmsgp,
+                                   sge, ch_sge_ary,
+                                   ch_count, byte_count);
+       head = svc_rdma_get_context(xprt);
+       sgl_offset = 0;
+       ch_no = 0;
+
+       for (ch = (struct rpcrdma_read_chunk *)&rmsgp->rm_body.rm_chunks[0];
+            ch->rc_discrim != 0; ch++, ch_no++) {
+next_sge:
+               if (!ctxt)
+                       ctxt = head;
+               else {
+                       ctxt->next = svc_rdma_get_context(xprt);
+                       ctxt = ctxt->next;
+               }
+               ctxt->next = NULL;
+               ctxt->direction = DMA_FROM_DEVICE;
+               clear_bit(RDMACTXT_F_READ_DONE, &ctxt->flags);
+               clear_bit(RDMACTXT_F_LAST_CTXT, &ctxt->flags);
+               if ((ch+1)->rc_discrim == 0) {
+                       /*
+                        * Checked in sq_cq_reap to see if we need to
+                        * be enqueued
+                        */
+                       set_bit(RDMACTXT_F_LAST_CTXT, &ctxt->flags);
+                       ctxt->next = hdr_ctxt;
+                       hdr_ctxt->next = head;
+               }
+
+               /* Prepare READ WR */
+               memset(&read_wr, 0, sizeof read_wr);
+               ctxt->wr_op = IB_WR_RDMA_READ;
+               read_wr.wr_id = (unsigned long)ctxt;
+               read_wr.opcode = IB_WR_RDMA_READ;
+               read_wr.send_flags = IB_SEND_SIGNALED;
+               read_wr.wr.rdma.rkey = ch->rc_target.rs_handle;
+               read_wr.wr.rdma.remote_addr =
+                       get_unaligned(&(ch->rc_target.rs_offset)) +
+                       sgl_offset;
+               read_wr.sg_list = &sge[ch_sge_ary[ch_no].start];
+               read_wr.num_sge =
+                       rdma_read_max_sge(xprt, ch_sge_ary[ch_no].count);
+               rdma_set_ctxt_sge(ctxt, &sge[ch_sge_ary[ch_no].start],
+                                 &sgl_offset,
+                                 read_wr.num_sge);
+
+               /* Post the read */
+               err = svc_rdma_send(xprt, &read_wr);
+               if (err) {
+                       printk(KERN_ERR "svcrdma: Error posting send = %d\n",
+                              err);
+                       /*
+                        * Break the circular list so free knows when
+                        * to stop if the error happened to occur on
+                        * the last read
+                        */
+                       ctxt->next = NULL;
+                       goto out;
+               }
+               atomic_inc(&rdma_stat_read);
+
+               if (read_wr.num_sge < ch_sge_ary[ch_no].count) {
+                       ch_sge_ary[ch_no].count -= read_wr.num_sge;
+                       ch_sge_ary[ch_no].start += read_wr.num_sge;
+                       goto next_sge;
+               }
+               sgl_offset = 0;
+               err = 0;
+       }
+
+ out:
+       svc_rdma_put_context(tmp_sge_ctxt, 0);
+       svc_rdma_put_context(tmp_ch_ctxt, 0);
+
+       /* Detach arg pages. svc_recv will replenish them */
+       for (ch_no = 0; &rqstp->rq_pages[ch_no] < rqstp->rq_respages; ch_no++)
+               rqstp->rq_pages[ch_no] = NULL;
+
+       /*
+        * Detach res pages. svc_release must see a resused count of
+        * zero or it will attempt to put them.
+        */
+       while (rqstp->rq_resused)
+               rqstp->rq_respages[--rqstp->rq_resused] = NULL;
+
+       if (err) {
+               printk(KERN_ERR "svcrdma : RDMA_READ error = %d\n", err);
+               set_bit(XPT_CLOSE, &xprt->sc_xprt.xpt_flags);
+               /* Free the linked list of read contexts */
+               while (head != NULL) {
+                       ctxt = head->next;
+                       svc_rdma_put_context(head, 1);
+                       head = ctxt;
+               }
+               return 0;
+       }
+
+       return 1;
+}
+
+static int rdma_read_complete(struct svc_rqst *rqstp,
+                             struct svc_rdma_op_ctxt *data)
+{
+       struct svc_rdma_op_ctxt *head = data->next;
+       int page_no;
+       int ret;
+
+       BUG_ON(!head);
+
+       /* Copy RPC pages */
+       for (page_no = 0; page_no < head->count; page_no++) {
+               put_page(rqstp->rq_pages[page_no]);
+               rqstp->rq_pages[page_no] = head->pages[page_no];
+       }
+       /* Point rq_arg.pages past header */
+       rqstp->rq_arg.pages = &rqstp->rq_pages[head->sge[0].length];
+       rqstp->rq_arg.page_len = head->arg.page_len;
+       rqstp->rq_arg.page_base = head->arg.page_base;
+
+       /* rq_respages starts after the last arg page */
+       rqstp->rq_respages = &rqstp->rq_arg.pages[page_no];
+       rqstp->rq_resused = 0;
+
+       /* Rebuild rq_arg head and tail. */
+       rqstp->rq_arg.head[0] = head->arg.head[0];
+       rqstp->rq_arg.tail[0] = head->arg.tail[0];
+       rqstp->rq_arg.len = head->arg.len;
+       rqstp->rq_arg.buflen = head->arg.buflen;
+
+       /* XXX: What should this be? */
+       rqstp->rq_prot = IPPROTO_MAX;
+
+       /*
+        * Free the contexts we used to build the RDMA_READ. We have
+        * to be careful here because the context list uses the same
+        * next pointer used to chain the contexts associated with the
+        * RDMA_READ
+        */
+       data->next = NULL;      /* terminate circular list */
+       do {
+               data = head->next;
+               svc_rdma_put_context(head, 0);
+               head = data;
+       } while (head != NULL);
+
+       ret = rqstp->rq_arg.head[0].iov_len
+               + rqstp->rq_arg.page_len
+               + rqstp->rq_arg.tail[0].iov_len;
+       dprintk("svcrdma: deferred read ret=%d, rq_arg.len =%d, "
+               "rq_arg.head[0].iov_base=%p, rq_arg.head[0].iov_len = %zd\n",
+               ret, rqstp->rq_arg.len, rqstp->rq_arg.head[0].iov_base,
+               rqstp->rq_arg.head[0].iov_len);
+
+       /* Indicate that we've consumed an RQ credit */
+       rqstp->rq_xprt_ctxt = rqstp->rq_xprt;
+       svc_xprt_received(rqstp->rq_xprt);
+       return ret;
+}
+
+/*
+ * Set up the rqstp thread context to point to the RQ buffer. If
+ * necessary, pull additional data from the client with an RDMA_READ
+ * request.
+ */
+int svc_rdma_recvfrom(struct svc_rqst *rqstp)
+{
+       struct svc_xprt *xprt = rqstp->rq_xprt;
+       struct svcxprt_rdma *rdma_xprt =
+               container_of(xprt, struct svcxprt_rdma, sc_xprt);
+       struct svc_rdma_op_ctxt *ctxt = NULL;
+       struct rpcrdma_msg *rmsgp;
+       int ret = 0;
+       int len;
+
+       dprintk("svcrdma: rqstp=%p\n", rqstp);
+
+       /*
+        * The rq_xprt_ctxt indicates if we've consumed an RQ credit
+        * or not. It is used in the rdma xpo_release_rqst function to
+        * determine whether or not to return an RQ WQE to the RQ.
+        */
+       rqstp->rq_xprt_ctxt = NULL;
+
+       spin_lock_bh(&rdma_xprt->sc_read_complete_lock);
+       if (!list_empty(&rdma_xprt->sc_read_complete_q)) {
+               ctxt = list_entry(rdma_xprt->sc_read_complete_q.next,
+                                 struct svc_rdma_op_ctxt,
+                                 dto_q);
+               list_del_init(&ctxt->dto_q);
+       }
+       spin_unlock_bh(&rdma_xprt->sc_read_complete_lock);
+       if (ctxt)
+               return rdma_read_complete(rqstp, ctxt);
+
+       spin_lock_bh(&rdma_xprt->sc_rq_dto_lock);
+       if (!list_empty(&rdma_xprt->sc_rq_dto_q)) {
+               ctxt = list_entry(rdma_xprt->sc_rq_dto_q.next,
+                                 struct svc_rdma_op_ctxt,
+                                 dto_q);
+               list_del_init(&ctxt->dto_q);
+       } else {
+               atomic_inc(&rdma_stat_rq_starve);
+               clear_bit(XPT_DATA, &xprt->xpt_flags);
+               ctxt = NULL;
+       }
+       spin_unlock_bh(&rdma_xprt->sc_rq_dto_lock);
+       if (!ctxt) {
+               /* This is the EAGAIN path. The svc_recv routine will
+                * return -EAGAIN, the nfsd thread will go to call into
+                * svc_recv again and we shouldn't be on the active
+                * transport list
+                */
+               if (test_bit(XPT_CLOSE, &xprt->xpt_flags))
+                       goto close_out;
+
+               BUG_ON(ret);
+               goto out;
+       }
+       dprintk("svcrdma: processing ctxt=%p on xprt=%p, rqstp=%p, status=%d\n",
+               ctxt, rdma_xprt, rqstp, ctxt->wc_status);
+       BUG_ON(ctxt->wc_status != IB_WC_SUCCESS);
+       atomic_inc(&rdma_stat_recv);
+
+       /* Build up the XDR from the receive buffers. */
+       rdma_build_arg_xdr(rqstp, ctxt, ctxt->byte_len);
+
+       /* Decode the RDMA header. */
+       len = svc_rdma_xdr_decode_req(&rmsgp, rqstp);
+       rqstp->rq_xprt_hlen = len;
+
+       /* If the request is invalid, reply with an error */
+       if (len < 0) {
+               if (len == -ENOSYS)
+                       (void)svc_rdma_send_error(rdma_xprt, rmsgp, ERR_VERS);
+               goto close_out;
+       }
+
+       /* Read read-list data. If we would need to wait, defer
+        * it. Not that in this case, we don't return the RQ credit
+        * until after the read completes.
+        */
+       if (rdma_read_xdr(rdma_xprt, rmsgp, rqstp, ctxt)) {
+               svc_xprt_received(xprt);
+               return 0;
+       }
+
+       /* Indicate we've consumed an RQ credit */
+       rqstp->rq_xprt_ctxt = rqstp->rq_xprt;
+
+       ret = rqstp->rq_arg.head[0].iov_len
+               + rqstp->rq_arg.page_len
+               + rqstp->rq_arg.tail[0].iov_len;
+       svc_rdma_put_context(ctxt, 0);
+ out:
+       dprintk("svcrdma: ret = %d, rq_arg.len =%d, "
+               "rq_arg.head[0].iov_base=%p, rq_arg.head[0].iov_len = %zd\n",
+               ret, rqstp->rq_arg.len,
+               rqstp->rq_arg.head[0].iov_base,
+               rqstp->rq_arg.head[0].iov_len);
+       rqstp->rq_prot = IPPROTO_MAX;
+       svc_xprt_copy_addrs(rqstp, xprt);
+       svc_xprt_received(xprt);
+       return ret;
+
+ close_out:
+       if (ctxt) {
+               svc_rdma_put_context(ctxt, 1);
+               /* Indicate we've consumed an RQ credit */
+               rqstp->rq_xprt_ctxt = rqstp->rq_xprt;
+       }
+       dprintk("svcrdma: transport %p is closing\n", xprt);
+       /*
+        * Set the close bit and enqueue it. svc_recv will see the
+        * close bit and call svc_xprt_delete
+        */
+       set_bit(XPT_CLOSE, &xprt->xpt_flags);
+       svc_xprt_received(xprt);
+       return 0;
+}
diff --git a/net/sunrpc/xprtrdma/svc_rdma_sendto.c b/net/sunrpc/xprtrdma/svc_rdma_sendto.c
new file mode 100644 (file)
index 0000000..3e32194
--- /dev/null
@@ -0,0 +1,520 @@
+/*
+ * Copyright (c) 2005-2006 Network Appliance, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the BSD-type
+ * license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *      Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *      Redistributions in binary form must reproduce the above
+ *      copyright notice, this list of conditions and the following
+ *      disclaimer in the documentation and/or other materials provided
+ *      with the distribution.
+ *
+ *      Neither the name of the Network Appliance, Inc. nor the names of
+ *      its contributors may be used to endorse or promote products
+ *      derived from this software without specific prior written
+ *      permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Author: Tom Tucker <tom@opengridcomputing.com>
+ */
+
+#include <linux/sunrpc/debug.h>
+#include <linux/sunrpc/rpc_rdma.h>
+#include <linux/spinlock.h>
+#include <asm/unaligned.h>
+#include <rdma/ib_verbs.h>
+#include <rdma/rdma_cm.h>
+#include <linux/sunrpc/svc_rdma.h>
+
+#define RPCDBG_FACILITY        RPCDBG_SVCXPRT
+
+/* Encode an XDR as an array of IB SGE
+ *
+ * Assumptions:
+ * - head[0] is physically contiguous.
+ * - tail[0] is physically contiguous.
+ * - pages[] is not physically or virtually contigous and consists of
+ *   PAGE_SIZE elements.
+ *
+ * Output:
+ * SGE[0]              reserved for RCPRDMA header
+ * SGE[1]              data from xdr->head[]
+ * SGE[2..sge_count-2] data from xdr->pages[]
+ * SGE[sge_count-1]    data from xdr->tail.
+ *
+ */
+static struct ib_sge *xdr_to_sge(struct svcxprt_rdma *xprt,
+                                struct xdr_buf *xdr,
+                                struct ib_sge *sge,
+                                int *sge_count)
+{
+       /* Max we need is the length of the XDR / pagesize + one for
+        * head + one for tail + one for RPCRDMA header
+        */
+       int sge_max = (xdr->len+PAGE_SIZE-1) / PAGE_SIZE + 3;
+       int sge_no;
+       u32 byte_count = xdr->len;
+       u32 sge_bytes;
+       u32 page_bytes;
+       int page_off;
+       int page_no;
+
+       /* Skip the first sge, this is for the RPCRDMA header */
+       sge_no = 1;
+
+       /* Head SGE */
+       sge[sge_no].addr = ib_dma_map_single(xprt->sc_cm_id->device,
+                                            xdr->head[0].iov_base,
+                                            xdr->head[0].iov_len,
+                                            DMA_TO_DEVICE);
+       sge_bytes = min_t(u32, byte_count, xdr->head[0].iov_len);
+       byte_count -= sge_bytes;
+       sge[sge_no].length = sge_bytes;
+       sge[sge_no].lkey = xprt->sc_phys_mr->lkey;
+       sge_no++;
+
+       /* pages SGE */
+       page_no = 0;
+       page_bytes = xdr->page_len;
+       page_off = xdr->page_base;
+       while (byte_count && page_bytes) {
+               sge_bytes = min_t(u32, byte_count, (PAGE_SIZE-page_off));
+               sge[sge_no].addr =
+                       ib_dma_map_page(xprt->sc_cm_id->device,
+                                       xdr->pages[page_no], page_off,
+                                       sge_bytes, DMA_TO_DEVICE);
+               sge_bytes = min(sge_bytes, page_bytes);
+               byte_count -= sge_bytes;
+               page_bytes -= sge_bytes;
+               sge[sge_no].length = sge_bytes;
+               sge[sge_no].lkey = xprt->sc_phys_mr->lkey;
+
+               sge_no++;
+               page_no++;
+               page_off = 0; /* reset for next time through loop */
+       }
+
+       /* Tail SGE */
+       if (byte_count && xdr->tail[0].iov_len) {
+               sge[sge_no].addr =
+                       ib_dma_map_single(xprt->sc_cm_id->device,
+                                         xdr->tail[0].iov_base,
+                                         xdr->tail[0].iov_len,
+                                         DMA_TO_DEVICE);
+               sge_bytes = min_t(u32, byte_count, xdr->tail[0].iov_len);
+               byte_count -= sge_bytes;
+               sge[sge_no].length = sge_bytes;
+               sge[sge_no].lkey = xprt->sc_phys_mr->lkey;
+               sge_no++;
+       }
+
+       BUG_ON(sge_no > sge_max);
+       BUG_ON(byte_count != 0);
+
+       *sge_count = sge_no;
+       return sge;
+}
+
+
+/* Assumptions:
+ * - The specified write_len can be represented in sc_max_sge * PAGE_SIZE
+ */
+static int send_write(struct svcxprt_rdma *xprt, struct svc_rqst *rqstp,
+                     u32 rmr, u64 to,
+                     u32 xdr_off, int write_len,
+                     struct ib_sge *xdr_sge, int sge_count)
+{
+       struct svc_rdma_op_ctxt *tmp_sge_ctxt;
+       struct ib_send_wr write_wr;
+       struct ib_sge *sge;
+       int xdr_sge_no;
+       int sge_no;
+       int sge_bytes;
+       int sge_off;
+       int bc;
+       struct svc_rdma_op_ctxt *ctxt;
+       int ret = 0;
+
+       BUG_ON(sge_count >= 32);
+       dprintk("svcrdma: RDMA_WRITE rmr=%x, to=%llx, xdr_off=%d, "
+               "write_len=%d, xdr_sge=%p, sge_count=%d\n",
+               rmr, to, xdr_off, write_len, xdr_sge, sge_count);
+
+       ctxt = svc_rdma_get_context(xprt);
+       ctxt->count = 0;
+       tmp_sge_ctxt = svc_rdma_get_context(xprt);
+       sge = tmp_sge_ctxt->sge;
+
+       /* Find the SGE associated with xdr_off */
+       for (bc = xdr_off, xdr_sge_no = 1; bc && xdr_sge_no < sge_count;
+            xdr_sge_no++) {
+               if (xdr_sge[xdr_sge_no].length > bc)
+                       break;
+               bc -= xdr_sge[xdr_sge_no].length;
+       }
+
+       sge_off = bc;
+       bc = write_len;
+       sge_no = 0;
+
+       /* Copy the remaining SGE */
+       while (bc != 0 && xdr_sge_no < sge_count) {
+               sge[sge_no].addr = xdr_sge[xdr_sge_no].addr + sge_off;
+               sge[sge_no].lkey = xdr_sge[xdr_sge_no].lkey;
+               sge_bytes = min((size_t)bc,
+                               (size_t)(xdr_sge[xdr_sge_no].length-sge_off));
+               sge[sge_no].length = sge_bytes;
+
+               sge_off = 0;
+               sge_no++;
+               xdr_sge_no++;
+               bc -= sge_bytes;
+       }
+
+       BUG_ON(bc != 0);
+       BUG_ON(xdr_sge_no > sge_count);
+
+       /* Prepare WRITE WR */
+       memset(&write_wr, 0, sizeof write_wr);
+       ctxt->wr_op = IB_WR_RDMA_WRITE;
+       write_wr.wr_id = (unsigned long)ctxt;
+       write_wr.sg_list = &sge[0];
+       write_wr.num_sge = sge_no;
+       write_wr.opcode = IB_WR_RDMA_WRITE;
+       write_wr.send_flags = IB_SEND_SIGNALED;
+       write_wr.wr.rdma.rkey = rmr;
+       write_wr.wr.rdma.remote_addr = to;
+
+       /* Post It */
+       atomic_inc(&rdma_stat_write);
+       if (svc_rdma_send(xprt, &write_wr)) {
+               svc_rdma_put_context(ctxt, 1);
+               /* Fatal error, close transport */
+               ret = -EIO;
+       }
+       svc_rdma_put_context(tmp_sge_ctxt, 0);
+       return ret;
+}
+
+static int send_write_chunks(struct svcxprt_rdma *xprt,
+                            struct rpcrdma_msg *rdma_argp,
+                            struct rpcrdma_msg *rdma_resp,
+                            struct svc_rqst *rqstp,
+                            struct ib_sge *sge,
+                            int sge_count)
+{
+       u32 xfer_len = rqstp->rq_res.page_len + rqstp->rq_res.tail[0].iov_len;
+       int write_len;
+       int max_write;
+       u32 xdr_off;
+       int chunk_off;
+       int chunk_no;
+       struct rpcrdma_write_array *arg_ary;
+       struct rpcrdma_write_array *res_ary;
+       int ret;
+
+       arg_ary = svc_rdma_get_write_array(rdma_argp);
+       if (!arg_ary)
+               return 0;
+       res_ary = (struct rpcrdma_write_array *)
+               &rdma_resp->rm_body.rm_chunks[1];
+
+       max_write = xprt->sc_max_sge * PAGE_SIZE;
+
+       /* Write chunks start at the pagelist */
+       for (xdr_off = rqstp->rq_res.head[0].iov_len, chunk_no = 0;
+            xfer_len && chunk_no < arg_ary->wc_nchunks;
+            chunk_no++) {
+               struct rpcrdma_segment *arg_ch;
+               u64 rs_offset;
+
+               arg_ch = &arg_ary->wc_array[chunk_no].wc_target;
+               write_len = min(xfer_len, arg_ch->rs_length);
+
+               /* Prepare the response chunk given the length actually
+                * written */
+               rs_offset = get_unaligned(&(arg_ch->rs_offset));
+               svc_rdma_xdr_encode_array_chunk(res_ary, chunk_no,
+                                           arg_ch->rs_handle,
+                                           rs_offset,
+                                           write_len);
+               chunk_off = 0;
+               while (write_len) {
+                       int this_write;
+                       this_write = min(write_len, max_write);
+                       ret = send_write(xprt, rqstp,
+                                        arg_ch->rs_handle,
+                                        rs_offset + chunk_off,
+                                        xdr_off,
+                                        this_write,
+                                        sge,
+                                        sge_count);
+                       if (ret) {
+                               dprintk("svcrdma: RDMA_WRITE failed, ret=%d\n",
+                                       ret);
+                               return -EIO;
+                       }
+                       chunk_off += this_write;
+                       xdr_off += this_write;
+                       xfer_len -= this_write;
+                       write_len -= this_write;
+               }
+       }
+       /* Update the req with the number of chunks actually used */
+       svc_rdma_xdr_encode_write_list(rdma_resp, chunk_no);
+
+       return rqstp->rq_res.page_len + rqstp->rq_res.tail[0].iov_len;
+}
+
+static int send_reply_chunks(struct svcxprt_rdma *xprt,
+                            struct rpcrdma_msg *rdma_argp,
+                            struct rpcrdma_msg *rdma_resp,
+                            struct svc_rqst *rqstp,
+                            struct ib_sge *sge,
+                            int sge_count)
+{
+       u32 xfer_len = rqstp->rq_res.len;
+       int write_len;
+       int max_write;
+       u32 xdr_off;
+       int chunk_no;
+       int chunk_off;
+       struct rpcrdma_segment *ch;
+       struct rpcrdma_write_array *arg_ary;
+       struct rpcrdma_write_array *res_ary;
+       int ret;
+
+       arg_ary = svc_rdma_get_reply_array(rdma_argp);
+       if (!arg_ary)
+               return 0;
+       /* XXX: need to fix when reply lists occur with read-list and or
+        * write-list */
+       res_ary = (struct rpcrdma_write_array *)
+               &rdma_resp->rm_body.rm_chunks[2];
+
+       max_write = xprt->sc_max_sge * PAGE_SIZE;
+
+       /* xdr offset starts at RPC message */
+       for (xdr_off = 0, chunk_no = 0;
+            xfer_len && chunk_no < arg_ary->wc_nchunks;
+            chunk_no++) {
+               u64 rs_offset;
+               ch = &arg_ary->wc_array[chunk_no].wc_target;
+               write_len = min(xfer_len, ch->rs_length);
+
+
+               /* Prepare the reply chunk given the length actually
+                * written */
+               rs_offset = get_unaligned(&(ch->rs_offset));
+               svc_rdma_xdr_encode_array_chunk(res_ary, chunk_no,
+                                           ch->rs_handle, rs_offset,
+                                           write_len);
+               chunk_off = 0;
+               while (write_len) {
+                       int this_write;
+
+                       this_write = min(write_len, max_write);
+                       ret = send_write(xprt, rqstp,
+                                        ch->rs_handle,
+                                        rs_offset + chunk_off,
+                                        xdr_off,
+                                        this_write,
+                                        sge,
+                                        sge_count);
+                       if (ret) {
+                               dprintk("svcrdma: RDMA_WRITE failed, ret=%d\n",
+                                       ret);
+                               return -EIO;
+                       }
+                       chunk_off += this_write;
+                       xdr_off += this_write;
+                       xfer_len -= this_write;
+                       write_len -= this_write;
+               }
+       }
+       /* Update the req with the number of chunks actually used */
+       svc_rdma_xdr_encode_reply_array(res_ary, chunk_no);
+
+       return rqstp->rq_res.len;
+}
+
+/* This function prepares the portion of the RPCRDMA message to be
+ * sent in the RDMA_SEND. This function is called after data sent via
+ * RDMA has already been transmitted. There are three cases:
+ * - The RPCRDMA header, RPC header, and payload are all sent in a
+ *   single RDMA_SEND. This is the "inline" case.
+ * - The RPCRDMA header and some portion of the RPC header and data
+ *   are sent via this RDMA_SEND and another portion of the data is
+ *   sent via RDMA.
+ * - The RPCRDMA header [NOMSG] is sent in this RDMA_SEND and the RPC
+ *   header and data are all transmitted via RDMA.
+ * In all three cases, this function prepares the RPCRDMA header in
+ * sge[0], the 'type' parameter indicates the type to place in the
+ * RPCRDMA header, and the 'byte_count' field indicates how much of
+ * the XDR to include in this RDMA_SEND.
+ */
+static int send_reply(struct svcxprt_rdma *rdma,
+                     struct svc_rqst *rqstp,
+                     struct page *page,
+                     struct rpcrdma_msg *rdma_resp,
+                     struct svc_rdma_op_ctxt *ctxt,
+                     int sge_count,
+                     int byte_count)
+{
+       struct ib_send_wr send_wr;
+       int sge_no;
+       int sge_bytes;
+       int page_no;
+       int ret;
+
+       /* Prepare the context */
+       ctxt->pages[0] = page;
+       ctxt->count = 1;
+
+       /* Prepare the SGE for the RPCRDMA Header */
+       ctxt->sge[0].addr =
+               ib_dma_map_page(rdma->sc_cm_id->device,
+                               page, 0, PAGE_SIZE, DMA_TO_DEVICE);
+       ctxt->direction = DMA_TO_DEVICE;
+       ctxt->sge[0].length = svc_rdma_xdr_get_reply_hdr_len(rdma_resp);
+       ctxt->sge[0].lkey = rdma->sc_phys_mr->lkey;
+
+       /* Determine how many of our SGE are to be transmitted */
+       for (sge_no = 1; byte_count && sge_no < sge_count; sge_no++) {
+               sge_bytes = min((size_t)ctxt->sge[sge_no].length,
+                               (size_t)byte_count);
+               byte_count -= sge_bytes;
+       }
+       BUG_ON(byte_count != 0);
+
+       /* Save all respages in the ctxt and remove them from the
+        * respages array. They are our pages until the I/O
+        * completes.
+        */
+       for (page_no = 0; page_no < rqstp->rq_resused; page_no++) {
+               ctxt->pages[page_no+1] = rqstp->rq_respages[page_no];
+               ctxt->count++;
+               rqstp->rq_respages[page_no] = NULL;
+       }
+
+       BUG_ON(sge_no > rdma->sc_max_sge);
+       memset(&send_wr, 0, sizeof send_wr);
+       ctxt->wr_op = IB_WR_SEND;
+       send_wr.wr_id = (unsigned long)ctxt;
+       send_wr.sg_list = ctxt->sge;
+       send_wr.num_sge = sge_no;
+       send_wr.opcode = IB_WR_SEND;
+       send_wr.send_flags =  IB_SEND_SIGNALED;
+
+       ret = svc_rdma_send(rdma, &send_wr);
+       if (ret)
+               svc_rdma_put_context(ctxt, 1);
+
+       return ret;
+}
+
+void svc_rdma_prep_reply_hdr(struct svc_rqst *rqstp)
+{
+}
+
+/*
+ * Return the start of an xdr buffer.
+ */
+static void *xdr_start(struct xdr_buf *xdr)
+{
+       return xdr->head[0].iov_base -
+               (xdr->len -
+                xdr->page_len -
+                xdr->tail[0].iov_len -
+                xdr->head[0].iov_len);
+}
+
+int svc_rdma_sendto(struct svc_rqst *rqstp)
+{
+       struct svc_xprt *xprt = rqstp->rq_xprt;
+       struct svcxprt_rdma *rdma =
+               container_of(xprt, struct svcxprt_rdma, sc_xprt);
+       struct rpcrdma_msg *rdma_argp;
+       struct rpcrdma_msg *rdma_resp;
+       struct rpcrdma_write_array *reply_ary;
+       enum rpcrdma_proc reply_type;
+       int ret;
+       int inline_bytes;
+       struct ib_sge *sge;
+       int sge_count = 0;
+       struct page *res_page;
+       struct svc_rdma_op_ctxt *ctxt;
+
+       dprintk("svcrdma: sending response for rqstp=%p\n", rqstp);
+
+       /* Get the RDMA request header. */
+       rdma_argp = xdr_start(&rqstp->rq_arg);
+
+       /* Build an SGE for the XDR */
+       ctxt = svc_rdma_get_context(rdma);
+       ctxt->direction = DMA_TO_DEVICE;
+       sge = xdr_to_sge(rdma, &rqstp->rq_res, ctxt->sge, &sge_count);
+
+       inline_bytes = rqstp->rq_res.len;
+
+       /* Create the RDMA response header */
+       res_page = svc_rdma_get_page();
+       rdma_resp = page_address(res_page);
+       reply_ary = svc_rdma_get_reply_array(rdma_argp);
+       if (reply_ary)
+               reply_type = RDMA_NOMSG;
+       else
+               reply_type = RDMA_MSG;
+       svc_rdma_xdr_encode_reply_header(rdma, rdma_argp,
+                                        rdma_resp, reply_type);
+
+       /* Send any write-chunk data and build resp write-list */
+       ret = send_write_chunks(rdma, rdma_argp, rdma_resp,
+                               rqstp, sge, sge_count);
+       if (ret < 0) {
+               printk(KERN_ERR "svcrdma: failed to send write chunks, rc=%d\n",
+                      ret);
+               goto error;
+       }
+       inline_bytes -= ret;
+
+       /* Send any reply-list data and update resp reply-list */
+       ret = send_reply_chunks(rdma, rdma_argp, rdma_resp,
+                               rqstp, sge, sge_count);
+       if (ret < 0) {
+               printk(KERN_ERR "svcrdma: failed to send reply chunks, rc=%d\n",
+                      ret);
+               goto error;
+       }
+       inline_bytes -= ret;
+
+       ret = send_reply(rdma, rqstp, res_page, rdma_resp, ctxt, sge_count,
+                        inline_bytes);
+       dprintk("svcrdma: send_reply returns %d\n", ret);
+       return ret;
+ error:
+       svc_rdma_put_context(ctxt, 0);
+       put_page(res_page);
+       return ret;
+}
diff --git a/net/sunrpc/xprtrdma/svc_rdma_transport.c b/net/sunrpc/xprtrdma/svc_rdma_transport.c
new file mode 100644 (file)
index 0000000..f09444c
--- /dev/null
@@ -0,0 +1,1080 @@
+/*
+ * Copyright (c) 2005-2007 Network Appliance, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the BSD-type
+ * license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *      Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *      Redistributions in binary form must reproduce the above
+ *      copyright notice, this list of conditions and the following
+ *      disclaimer in the documentation and/or other materials provided
+ *      with the distribution.
+ *
+ *      Neither the name of the Network Appliance, Inc. nor the names of
+ *      its contributors may be used to endorse or promote products
+ *      derived from this software without specific prior written
+ *      permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Author: Tom Tucker <tom@opengridcomputing.com>
+ */
+
+#include <linux/sunrpc/svc_xprt.h>
+#include <linux/sunrpc/debug.h>
+#include <linux/sunrpc/rpc_rdma.h>
+#include <linux/spinlock.h>
+#include <rdma/ib_verbs.h>
+#include <rdma/rdma_cm.h>
+#include <linux/sunrpc/svc_rdma.h>
+
+#define RPCDBG_FACILITY        RPCDBG_SVCXPRT
+
+static struct svc_xprt *svc_rdma_create(struct svc_serv *serv,
+                                       struct sockaddr *sa, int salen,
+                                       int flags);
+static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt);
+static void svc_rdma_release_rqst(struct svc_rqst *);
+static void rdma_destroy_xprt(struct svcxprt_rdma *xprt);
+static void dto_tasklet_func(unsigned long data);
+static void svc_rdma_detach(struct svc_xprt *xprt);
+static void svc_rdma_free(struct svc_xprt *xprt);
+static int svc_rdma_has_wspace(struct svc_xprt *xprt);
+static void rq_cq_reap(struct svcxprt_rdma *xprt);
+static void sq_cq_reap(struct svcxprt_rdma *xprt);
+
+DECLARE_TASKLET(dto_tasklet, dto_tasklet_func, 0UL);
+static DEFINE_SPINLOCK(dto_lock);
+static LIST_HEAD(dto_xprt_q);
+
+static struct svc_xprt_ops svc_rdma_ops = {
+       .xpo_create = svc_rdma_create,
+       .xpo_recvfrom = svc_rdma_recvfrom,
+       .xpo_sendto = svc_rdma_sendto,
+       .xpo_release_rqst = svc_rdma_release_rqst,
+       .xpo_detach = svc_rdma_detach,
+       .xpo_free = svc_rdma_free,
+       .xpo_prep_reply_hdr = svc_rdma_prep_reply_hdr,
+       .xpo_has_wspace = svc_rdma_has_wspace,
+       .xpo_accept = svc_rdma_accept,
+};
+
+struct svc_xprt_class svc_rdma_class = {
+       .xcl_name = "rdma",
+       .xcl_owner = THIS_MODULE,
+       .xcl_ops = &svc_rdma_ops,
+       .xcl_max_payload = RPCSVC_MAXPAYLOAD_TCP,
+};
+
+static int rdma_bump_context_cache(struct svcxprt_rdma *xprt)
+{
+       int target;
+       int at_least_one = 0;
+       struct svc_rdma_op_ctxt *ctxt;
+
+       target = min(xprt->sc_ctxt_cnt + xprt->sc_ctxt_bump,
+                    xprt->sc_ctxt_max);
+
+       spin_lock_bh(&xprt->sc_ctxt_lock);
+       while (xprt->sc_ctxt_cnt < target) {
+               xprt->sc_ctxt_cnt++;
+               spin_unlock_bh(&xprt->sc_ctxt_lock);
+
+               ctxt = kmalloc(sizeof(*ctxt), GFP_KERNEL);
+
+               spin_lock_bh(&xprt->sc_ctxt_lock);
+               if (ctxt) {
+                       at_least_one = 1;
+                       ctxt->next = xprt->sc_ctxt_head;
+                       xprt->sc_ctxt_head = ctxt;
+               } else {
+                       /* kmalloc failed...give up for now */
+                       xprt->sc_ctxt_cnt--;
+                       break;
+               }
+       }
+       spin_unlock_bh(&xprt->sc_ctxt_lock);
+       dprintk("svcrdma: sc_ctxt_max=%d, sc_ctxt_cnt=%d\n",
+               xprt->sc_ctxt_max, xprt->sc_ctxt_cnt);
+       return at_least_one;
+}
+
+struct svc_rdma_op_ctxt *svc_rdma_get_context(struct svcxprt_rdma *xprt)
+{
+       struct svc_rdma_op_ctxt *ctxt;
+
+       while (1) {
+               spin_lock_bh(&xprt->sc_ctxt_lock);
+               if (unlikely(xprt->sc_ctxt_head == NULL)) {
+                       /* Try to bump my cache. */
+                       spin_unlock_bh(&xprt->sc_ctxt_lock);
+
+                       if (rdma_bump_context_cache(xprt))
+                               continue;
+
+                       printk(KERN_INFO "svcrdma: sleeping waiting for "
+                              "context memory on xprt=%p\n",
+                              xprt);
+                       schedule_timeout_uninterruptible(msecs_to_jiffies(500));
+                       continue;
+               }
+               ctxt = xprt->sc_ctxt_head;
+               xprt->sc_ctxt_head = ctxt->next;
+               spin_unlock_bh(&xprt->sc_ctxt_lock);
+               ctxt->xprt = xprt;
+               INIT_LIST_HEAD(&ctxt->dto_q);
+               ctxt->count = 0;
+               break;
+       }
+       return ctxt;
+}
+
+void svc_rdma_put_context(struct svc_rdma_op_ctxt *ctxt, int free_pages)
+{
+       struct svcxprt_rdma *xprt;
+       int i;
+
+       BUG_ON(!ctxt);
+       xprt = ctxt->xprt;
+       if (free_pages)
+               for (i = 0; i < ctxt->count; i++)
+                       put_page(ctxt->pages[i]);
+
+       for (i = 0; i < ctxt->count; i++)
+               dma_unmap_single(xprt->sc_cm_id->device->dma_device,
+                                ctxt->sge[i].addr,
+                                ctxt->sge[i].length,
+                                ctxt->direction);
+       spin_lock_bh(&xprt->sc_ctxt_lock);
+       ctxt->next = xprt->sc_ctxt_head;
+       xprt->sc_ctxt_head = ctxt;
+       spin_unlock_bh(&xprt->sc_ctxt_lock);
+}
+
+/* ib_cq event handler */
+static void cq_event_handler(struct ib_event *event, void *context)
+{
+       struct svc_xprt *xprt = context;
+       dprintk("svcrdma: received CQ event id=%d, context=%p\n",
+               event->event, context);
+       set_bit(XPT_CLOSE, &xprt->xpt_flags);
+}
+
+/* QP event handler */
+static void qp_event_handler(struct ib_event *event, void *context)
+{
+       struct svc_xprt *xprt = context;
+
+       switch (event->event) {
+       /* These are considered benign events */
+       case IB_EVENT_PATH_MIG:
+       case IB_EVENT_COMM_EST:
+       case IB_EVENT_SQ_DRAINED:
+       case IB_EVENT_QP_LAST_WQE_REACHED:
+               dprintk("svcrdma: QP event %d received for QP=%p\n",
+                       event->event, event->element.qp);
+               break;
+       /* These are considered fatal events */
+       case IB_EVENT_PATH_MIG_ERR:
+       case IB_EVENT_QP_FATAL:
+       case IB_EVENT_QP_REQ_ERR:
+       case IB_EVENT_QP_ACCESS_ERR:
+       case IB_EVENT_DEVICE_FATAL:
+       default:
+               dprintk("svcrdma: QP ERROR event %d received for QP=%p, "
+                       "closing transport\n",
+                       event->event, event->element.qp);
+               set_bit(XPT_CLOSE, &xprt->xpt_flags);
+               break;
+       }
+}
+
+/*
+ * Data Transfer Operation Tasklet
+ *
+ * Walks a list of transports with I/O pending, removing entries as
+ * they are added to the server's I/O pending list. Two bits indicate
+ * if SQ, RQ, or both have I/O pending. The dto_lock is an irqsave
+ * spinlock that serializes access to the transport list with the RQ
+ * and SQ interrupt handlers.
+ */
+static void dto_tasklet_func(unsigned long data)
+{
+       struct svcxprt_rdma *xprt;
+       unsigned long flags;
+
+       spin_lock_irqsave(&dto_lock, flags);
+       while (!list_empty(&dto_xprt_q)) {
+               xprt = list_entry(dto_xprt_q.next,
+                                 struct svcxprt_rdma, sc_dto_q);
+               list_del_init(&xprt->sc_dto_q);
+               spin_unlock_irqrestore(&dto_lock, flags);
+
+               if (test_and_clear_bit(RDMAXPRT_RQ_PENDING, &xprt->sc_flags)) {
+                       ib_req_notify_cq(xprt->sc_rq_cq, IB_CQ_NEXT_COMP);
+                       rq_cq_reap(xprt);
+                       set_bit(XPT_DATA, &xprt->sc_xprt.xpt_flags);
+                       /*
+                        * If data arrived before established event,
+                        * don't enqueue. This defers RPC I/O until the
+                        * RDMA connection is complete.
+                        */
+                       if (!test_bit(RDMAXPRT_CONN_PENDING, &xprt->sc_flags))
+                               svc_xprt_enqueue(&xprt->sc_xprt);
+               }
+
+               if (test_and_clear_bit(RDMAXPRT_SQ_PENDING, &xprt->sc_flags)) {
+                       ib_req_notify_cq(xprt->sc_sq_cq, IB_CQ_NEXT_COMP);
+                       sq_cq_reap(xprt);
+               }
+
+               spin_lock_irqsave(&dto_lock, flags);
+       }
+       spin_unlock_irqrestore(&dto_lock, flags);
+}
+
+/*
+ * Receive Queue Completion Handler
+ *
+ * Since an RQ completion handler is called on interrupt context, we
+ * need to defer the handling of the I/O to a tasklet
+ */
+static void rq_comp_handler(struct ib_cq *cq, void *cq_context)
+{
+       struct svcxprt_rdma *xprt = cq_context;
+       unsigned long flags;
+
+       /*
+        * Set the bit regardless of whether or not it's on the list
+        * because it may be on the list already due to an SQ
+        * completion.
+       */
+       set_bit(RDMAXPRT_RQ_PENDING, &xprt->sc_flags);
+
+       /*
+        * If this transport is not already on the DTO transport queue,
+        * add it
+        */
+       spin_lock_irqsave(&dto_lock, flags);
+       if (list_empty(&xprt->sc_dto_q))
+               list_add_tail(&xprt->sc_dto_q, &dto_xprt_q);
+       spin_unlock_irqrestore(&dto_lock, flags);
+
+       /* Tasklet does all the work to avoid irqsave locks. */
+       tasklet_schedule(&dto_tasklet);
+}
+
+/*
+ * rq_cq_reap - Process the RQ CQ.
+ *
+ * Take all completing WC off the CQE and enqueue the associated DTO
+ * context on the dto_q for the transport.
+ */
+static void rq_cq_reap(struct svcxprt_rdma *xprt)
+{
+       int ret;
+       struct ib_wc wc;
+       struct svc_rdma_op_ctxt *ctxt = NULL;
+
+       atomic_inc(&rdma_stat_rq_poll);
+
+       spin_lock_bh(&xprt->sc_rq_dto_lock);
+       while ((ret = ib_poll_cq(xprt->sc_rq_cq, 1, &wc)) > 0) {
+               ctxt = (struct svc_rdma_op_ctxt *)(unsigned long)wc.wr_id;
+               ctxt->wc_status = wc.status;
+               ctxt->byte_len = wc.byte_len;
+               if (wc.status != IB_WC_SUCCESS) {
+                       /* Close the transport */
+                       set_bit(XPT_CLOSE, &xprt->sc_xprt.xpt_flags);
+                       svc_rdma_put_context(ctxt, 1);
+                       continue;
+               }
+               list_add_tail(&ctxt->dto_q, &xprt->sc_rq_dto_q);
+       }
+       spin_unlock_bh(&xprt->sc_rq_dto_lock);
+
+       if (ctxt)
+               atomic_inc(&rdma_stat_rq_prod);
+}
+
+/*
+ * Send Queue Completion Handler - potentially called on interrupt context.
+ */
+static void sq_cq_reap(struct svcxprt_rdma *xprt)
+{
+       struct svc_rdma_op_ctxt *ctxt = NULL;
+       struct ib_wc wc;
+       struct ib_cq *cq = xprt->sc_sq_cq;
+       int ret;
+
+       atomic_inc(&rdma_stat_sq_poll);
+       while ((ret = ib_poll_cq(cq, 1, &wc)) > 0) {
+               ctxt = (struct svc_rdma_op_ctxt *)(unsigned long)wc.wr_id;
+               xprt = ctxt->xprt;
+
+               if (wc.status != IB_WC_SUCCESS)
+                       /* Close the transport */
+                       set_bit(XPT_CLOSE, &xprt->sc_xprt.xpt_flags);
+
+               /* Decrement used SQ WR count */
+               atomic_dec(&xprt->sc_sq_count);
+               wake_up(&xprt->sc_send_wait);
+
+               switch (ctxt->wr_op) {
+               case IB_WR_SEND:
+               case IB_WR_RDMA_WRITE:
+                       svc_rdma_put_context(ctxt, 1);
+                       break;
+
+               case IB_WR_RDMA_READ:
+                       if (test_bit(RDMACTXT_F_LAST_CTXT, &ctxt->flags)) {
+                               set_bit(XPT_DATA, &xprt->sc_xprt.xpt_flags);
+                               set_bit(RDMACTXT_F_READ_DONE, &ctxt->flags);
+                               spin_lock_bh(&xprt->sc_read_complete_lock);
+                               list_add_tail(&ctxt->dto_q,
+                                             &xprt->sc_read_complete_q);
+                               spin_unlock_bh(&xprt->sc_read_complete_lock);
+                               svc_xprt_enqueue(&xprt->sc_xprt);
+                       }
+                       break;
+
+               default:
+                       printk(KERN_ERR "svcrdma: unexpected completion type, "
+                              "opcode=%d, status=%d\n",
+                              wc.opcode, wc.status);
+                       break;
+               }
+       }
+
+       if (ctxt)
+               atomic_inc(&rdma_stat_sq_prod);
+}
+
+static void sq_comp_handler(struct ib_cq *cq, void *cq_context)
+{
+       struct svcxprt_rdma *xprt = cq_context;
+       unsigned long flags;
+
+       /*
+        * Set the bit regardless of whether or not it's on the list
+        * because it may be on the list already due to an RQ
+        * completion.
+       */
+       set_bit(RDMAXPRT_SQ_PENDING, &xprt->sc_flags);
+
+       /*
+        * If this transport is not already on the DTO transport queue,
+        * add it
+        */
+       spin_lock_irqsave(&dto_lock, flags);
+       if (list_empty(&xprt->sc_dto_q))
+               list_add_tail(&xprt->sc_dto_q, &dto_xprt_q);
+       spin_unlock_irqrestore(&dto_lock, flags);
+
+       /* Tasklet does all the work to avoid irqsave locks. */
+       tasklet_schedule(&dto_tasklet);
+}
+
+static void create_context_cache(struct svcxprt_rdma *xprt,
+                                int ctxt_count, int ctxt_bump, int ctxt_max)
+{
+       struct svc_rdma_op_ctxt *ctxt;
+       int i;
+
+       xprt->sc_ctxt_max = ctxt_max;
+       xprt->sc_ctxt_bump = ctxt_bump;
+       xprt->sc_ctxt_cnt = 0;
+       xprt->sc_ctxt_head = NULL;
+       for (i = 0; i < ctxt_count; i++) {
+               ctxt = kmalloc(sizeof(*ctxt), GFP_KERNEL);
+               if (ctxt) {
+                       ctxt->next = xprt->sc_ctxt_head;
+                       xprt->sc_ctxt_head = ctxt;
+                       xprt->sc_ctxt_cnt++;
+               }
+       }
+}
+
+static void destroy_context_cache(struct svc_rdma_op_ctxt *ctxt)
+{
+       struct svc_rdma_op_ctxt *next;
+       if (!ctxt)
+               return;
+
+       do {
+               next = ctxt->next;
+               kfree(ctxt);
+               ctxt = next;
+       } while (next);
+}
+
+static struct svcxprt_rdma *rdma_create_xprt(struct svc_serv *serv,
+                                            int listener)
+{
+       struct svcxprt_rdma *cma_xprt = kzalloc(sizeof *cma_xprt, GFP_KERNEL);
+
+       if (!cma_xprt)
+               return NULL;
+       svc_xprt_init(&svc_rdma_class, &cma_xprt->sc_xprt, serv);
+       INIT_LIST_HEAD(&cma_xprt->sc_accept_q);
+       INIT_LIST_HEAD(&cma_xprt->sc_dto_q);
+       INIT_LIST_HEAD(&cma_xprt->sc_rq_dto_q);
+       INIT_LIST_HEAD(&cma_xprt->sc_read_complete_q);
+       init_waitqueue_head(&cma_xprt->sc_send_wait);
+
+       spin_lock_init(&cma_xprt->sc_lock);
+       spin_lock_init(&cma_xprt->sc_read_complete_lock);
+       spin_lock_init(&cma_xprt->sc_ctxt_lock);
+       spin_lock_init(&cma_xprt->sc_rq_dto_lock);
+
+       cma_xprt->sc_ord = svcrdma_ord;
+
+       cma_xprt->sc_max_req_size = svcrdma_max_req_size;
+       cma_xprt->sc_max_requests = svcrdma_max_requests;
+       cma_xprt->sc_sq_depth = svcrdma_max_requests * RPCRDMA_SQ_DEPTH_MULT;
+       atomic_set(&cma_xprt->sc_sq_count, 0);
+
+       if (!listener) {
+               int reqs = cma_xprt->sc_max_requests;
+               create_context_cache(cma_xprt,
+                                    reqs << 1, /* starting size */
+                                    reqs,      /* bump amount */
+                                    reqs +
+                                    cma_xprt->sc_sq_depth +
+                                    RPCRDMA_MAX_THREADS + 1); /* max */
+               if (!cma_xprt->sc_ctxt_head) {
+                       kfree(cma_xprt);
+                       return NULL;
+               }
+               clear_bit(XPT_LISTENER, &cma_xprt->sc_xprt.xpt_flags);
+       } else
+               set_bit(XPT_LISTENER, &cma_xprt->sc_xprt.xpt_flags);
+
+       return cma_xprt;
+}
+
+struct page *svc_rdma_get_page(void)
+{
+       struct page *page;
+
+       while ((page = alloc_page(GFP_KERNEL)) == NULL) {
+               /* If we can't get memory, wait a bit and try again */
+               printk(KERN_INFO "svcrdma: out of memory...retrying in 1000 "
+                      "jiffies.\n");
+               schedule_timeout_uninterruptible(msecs_to_jiffies(1000));
+       }
+       return page;
+}
+
+int svc_rdma_post_recv(struct svcxprt_rdma *xprt)
+{
+       struct ib_recv_wr recv_wr, *bad_recv_wr;
+       struct svc_rdma_op_ctxt *ctxt;
+       struct page *page;
+       unsigned long pa;
+       int sge_no;
+       int buflen;
+       int ret;
+
+       ctxt = svc_rdma_get_context(xprt);
+       buflen = 0;
+       ctxt->direction = DMA_FROM_DEVICE;
+       for (sge_no = 0; buflen < xprt->sc_max_req_size; sge_no++) {
+               BUG_ON(sge_no >= xprt->sc_max_sge);
+               page = svc_rdma_get_page();
+               ctxt->pages[sge_no] = page;
+               pa = ib_dma_map_page(xprt->sc_cm_id->device,
+                                    page, 0, PAGE_SIZE,
+                                    DMA_FROM_DEVICE);
+               ctxt->sge[sge_no].addr = pa;
+               ctxt->sge[sge_no].length = PAGE_SIZE;
+               ctxt->sge[sge_no].lkey = xprt->sc_phys_mr->lkey;
+               buflen += PAGE_SIZE;
+       }
+       ctxt->count = sge_no;
+       recv_wr.next = NULL;
+       recv_wr.sg_list = &ctxt->sge[0];
+       recv_wr.num_sge = ctxt->count;
+       recv_wr.wr_id = (u64)(unsigned long)ctxt;
+
+       ret = ib_post_recv(xprt->sc_qp, &recv_wr, &bad_recv_wr);
+       return ret;
+}
+
+/*
+ * This function handles the CONNECT_REQUEST event on a listening
+ * endpoint. It is passed the cma_id for the _new_ connection. The context in
+ * this cma_id is inherited from the listening cma_id and is the svc_xprt
+ * structure for the listening endpoint.
+ *
+ * This function creates a new xprt for the new connection and enqueues it on
+ * the accept queue for the listent xprt. When the listen thread is kicked, it
+ * will call the recvfrom method on the listen xprt which will accept the new
+ * connection.
+ */
+static void handle_connect_req(struct rdma_cm_id *new_cma_id)
+{
+       struct svcxprt_rdma *listen_xprt = new_cma_id->context;
+       struct svcxprt_rdma *newxprt;
+
+       /* Create a new transport */
+       newxprt = rdma_create_xprt(listen_xprt->sc_xprt.xpt_server, 0);
+       if (!newxprt) {
+               dprintk("svcrdma: failed to create new transport\n");
+               return;
+       }
+       newxprt->sc_cm_id = new_cma_id;
+       new_cma_id->context = newxprt;
+       dprintk("svcrdma: Creating newxprt=%p, cm_id=%p, listenxprt=%p\n",
+               newxprt, newxprt->sc_cm_id, listen_xprt);
+
+       /*
+        * Enqueue the new transport on the accept queue of the listening
+        * transport
+        */
+       spin_lock_bh(&listen_xprt->sc_lock);
+       list_add_tail(&newxprt->sc_accept_q, &listen_xprt->sc_accept_q);
+       spin_unlock_bh(&listen_xprt->sc_lock);
+
+       /*
+        * Can't use svc_xprt_received here because we are not on a
+        * rqstp thread
+       */
+       set_bit(XPT_CONN, &listen_xprt->sc_xprt.xpt_flags);
+       svc_xprt_enqueue(&listen_xprt->sc_xprt);
+}
+
+/*
+ * Handles events generated on the listening endpoint. These events will be
+ * either be incoming connect requests or adapter removal  events.
+ */
+static int rdma_listen_handler(struct rdma_cm_id *cma_id,
+                              struct rdma_cm_event *event)
+{
+       struct svcxprt_rdma *xprt = cma_id->context;
+       int ret = 0;
+
+       switch (event->event) {
+       case RDMA_CM_EVENT_CONNECT_REQUEST:
+               dprintk("svcrdma: Connect request on cma_id=%p, xprt = %p, "
+                       "event=%d\n", cma_id, cma_id->context, event->event);
+               handle_connect_req(cma_id);
+               break;
+
+       case RDMA_CM_EVENT_ESTABLISHED:
+               /* Accept complete */
+               dprintk("svcrdma: Connection completed on LISTEN xprt=%p, "
+                       "cm_id=%p\n", xprt, cma_id);
+               break;
+
+       case RDMA_CM_EVENT_DEVICE_REMOVAL:
+               dprintk("svcrdma: Device removal xprt=%p, cm_id=%p\n",
+                       xprt, cma_id);
+               if (xprt)
+                       set_bit(XPT_CLOSE, &xprt->sc_xprt.xpt_flags);
+               break;
+
+       default:
+               dprintk("svcrdma: Unexpected event on listening endpoint %p, "
+                       "event=%d\n", cma_id, event->event);
+               break;
+       }
+
+       return ret;
+}
+
+static int rdma_cma_handler(struct rdma_cm_id *cma_id,
+                           struct rdma_cm_event *event)
+{
+       struct svc_xprt *xprt = cma_id->context;
+       struct svcxprt_rdma *rdma =
+               container_of(xprt, struct svcxprt_rdma, sc_xprt);
+       switch (event->event) {
+       case RDMA_CM_EVENT_ESTABLISHED:
+               /* Accept complete */
+               dprintk("svcrdma: Connection completed on DTO xprt=%p, "
+                       "cm_id=%p\n", xprt, cma_id);
+               clear_bit(RDMAXPRT_CONN_PENDING, &rdma->sc_flags);
+               svc_xprt_enqueue(xprt);
+               break;
+       case RDMA_CM_EVENT_DISCONNECTED:
+               dprintk("svcrdma: Disconnect on DTO xprt=%p, cm_id=%p\n",
+                       xprt, cma_id);
+               if (xprt) {
+                       set_bit(XPT_CLOSE, &xprt->xpt_flags);
+                       svc_xprt_enqueue(xprt);
+               }
+               break;
+       case RDMA_CM_EVENT_DEVICE_REMOVAL:
+               dprintk("svcrdma: Device removal cma_id=%p, xprt = %p, "
+                       "event=%d\n", cma_id, xprt, event->event);
+               if (xprt) {
+                       set_bit(XPT_CLOSE, &xprt->xpt_flags);
+                       svc_xprt_enqueue(xprt);
+               }
+               break;
+       default:
+               dprintk("svcrdma: Unexpected event on DTO endpoint %p, "
+                       "event=%d\n", cma_id, event->event);
+               break;
+       }
+       return 0;
+}
+
+/*
+ * Create a listening RDMA service endpoint.
+ */
+static struct svc_xprt *svc_rdma_create(struct svc_serv *serv,
+                                       struct sockaddr *sa, int salen,
+                                       int flags)
+{
+       struct rdma_cm_id *listen_id;
+       struct svcxprt_rdma *cma_xprt;
+       struct svc_xprt *xprt;
+       int ret;
+
+       dprintk("svcrdma: Creating RDMA socket\n");
+
+       cma_xprt = rdma_create_xprt(serv, 1);
+       if (!cma_xprt)
+               return ERR_PTR(ENOMEM);
+       xprt = &cma_xprt->sc_xprt;
+
+       listen_id = rdma_create_id(rdma_listen_handler, cma_xprt, RDMA_PS_TCP);
+       if (IS_ERR(listen_id)) {
+               rdma_destroy_xprt(cma_xprt);
+               dprintk("svcrdma: rdma_create_id failed = %ld\n",
+                       PTR_ERR(listen_id));
+               return (void *)listen_id;
+       }
+       ret = rdma_bind_addr(listen_id, sa);
+       if (ret) {
+               rdma_destroy_xprt(cma_xprt);
+               rdma_destroy_id(listen_id);
+               dprintk("svcrdma: rdma_bind_addr failed = %d\n", ret);
+               return ERR_PTR(ret);
+       }
+       cma_xprt->sc_cm_id = listen_id;
+
+       ret = rdma_listen(listen_id, RPCRDMA_LISTEN_BACKLOG);
+       if (ret) {
+               rdma_destroy_id(listen_id);
+               rdma_destroy_xprt(cma_xprt);
+               dprintk("svcrdma: rdma_listen failed = %d\n", ret);
+       }
+
+       /*
+        * We need to use the address from the cm_id in case the
+        * caller specified 0 for the port number.
+        */
+       sa = (struct sockaddr *)&cma_xprt->sc_cm_id->route.addr.src_addr;
+       svc_xprt_set_local(&cma_xprt->sc_xprt, sa, salen);
+
+       return &cma_xprt->sc_xprt;
+}
+
+/*
+ * This is the xpo_recvfrom function for listening endpoints. Its
+ * purpose is to accept incoming connections. The CMA callback handler
+ * has already created a new transport and attached it to the new CMA
+ * ID.
+ *
+ * There is a queue of pending connections hung on the listening
+ * transport. This queue contains the new svc_xprt structure. This
+ * function takes svc_xprt structures off the accept_q and completes
+ * the connection.
+ */
+static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt)
+{
+       struct svcxprt_rdma *listen_rdma;
+       struct svcxprt_rdma *newxprt = NULL;
+       struct rdma_conn_param conn_param;
+       struct ib_qp_init_attr qp_attr;
+       struct ib_device_attr devattr;
+       struct sockaddr *sa;
+       int ret;
+       int i;
+
+       listen_rdma = container_of(xprt, struct svcxprt_rdma, sc_xprt);
+       clear_bit(XPT_CONN, &xprt->xpt_flags);
+       /* Get the next entry off the accept list */
+       spin_lock_bh(&listen_rdma->sc_lock);
+       if (!list_empty(&listen_rdma->sc_accept_q)) {
+               newxprt = list_entry(listen_rdma->sc_accept_q.next,
+                                    struct svcxprt_rdma, sc_accept_q);
+               list_del_init(&newxprt->sc_accept_q);
+       }
+       if (!list_empty(&listen_rdma->sc_accept_q))
+               set_bit(XPT_CONN, &listen_rdma->sc_xprt.xpt_flags);
+       spin_unlock_bh(&listen_rdma->sc_lock);
+       if (!newxprt)
+               return NULL;
+
+       dprintk("svcrdma: newxprt from accept queue = %p, cm_id=%p\n",
+               newxprt, newxprt->sc_cm_id);
+
+       ret = ib_query_device(newxprt->sc_cm_id->device, &devattr);
+       if (ret) {
+               dprintk("svcrdma: could not query device attributes on "
+                       "device %p, rc=%d\n", newxprt->sc_cm_id->device, ret);
+               goto errout;
+       }
+
+       /* Qualify the transport resource defaults with the
+        * capabilities of this particular device */
+       newxprt->sc_max_sge = min((size_t)devattr.max_sge,
+                                 (size_t)RPCSVC_MAXPAGES);
+       newxprt->sc_max_requests = min((size_t)devattr.max_qp_wr,
+                                  (size_t)svcrdma_max_requests);
+       newxprt->sc_sq_depth = RPCRDMA_SQ_DEPTH_MULT * newxprt->sc_max_requests;
+
+       newxprt->sc_ord =  min((size_t)devattr.max_qp_rd_atom,
+                              (size_t)svcrdma_ord);
+
+       newxprt->sc_pd = ib_alloc_pd(newxprt->sc_cm_id->device);
+       if (IS_ERR(newxprt->sc_pd)) {
+               dprintk("svcrdma: error creating PD for connect request\n");
+               goto errout;
+       }
+       newxprt->sc_sq_cq = ib_create_cq(newxprt->sc_cm_id->device,
+                                        sq_comp_handler,
+                                        cq_event_handler,
+                                        newxprt,
+                                        newxprt->sc_sq_depth,
+                                        0);
+       if (IS_ERR(newxprt->sc_sq_cq)) {
+               dprintk("svcrdma: error creating SQ CQ for connect request\n");
+               goto errout;
+       }
+       newxprt->sc_rq_cq = ib_create_cq(newxprt->sc_cm_id->device,
+                                        rq_comp_handler,
+                                        cq_event_handler,
+                                        newxprt,
+                                        newxprt->sc_max_requests,
+                                        0);
+       if (IS_ERR(newxprt->sc_rq_cq)) {
+               dprintk("svcrdma: error creating RQ CQ for connect request\n");
+               goto errout;
+       }
+
+       memset(&qp_attr, 0, sizeof qp_attr);
+       qp_attr.event_handler = qp_event_handler;
+       qp_attr.qp_context = &newxprt->sc_xprt;
+       qp_attr.cap.max_send_wr = newxprt->sc_sq_depth;
+       qp_attr.cap.max_recv_wr = newxprt->sc_max_requests;
+       qp_attr.cap.max_send_sge = newxprt->sc_max_sge;
+       qp_attr.cap.max_recv_sge = newxprt->sc_max_sge;
+       qp_attr.sq_sig_type = IB_SIGNAL_REQ_WR;
+       qp_attr.qp_type = IB_QPT_RC;
+       qp_attr.send_cq = newxprt->sc_sq_cq;
+       qp_attr.recv_cq = newxprt->sc_rq_cq;
+       dprintk("svcrdma: newxprt->sc_cm_id=%p, newxprt->sc_pd=%p\n"
+               "    cm_id->device=%p, sc_pd->device=%p\n"
+               "    cap.max_send_wr = %d\n"
+               "    cap.max_recv_wr = %d\n"
+               "    cap.max_send_sge = %d\n"
+               "    cap.max_recv_sge = %d\n",
+               newxprt->sc_cm_id, newxprt->sc_pd,
+               newxprt->sc_cm_id->device, newxprt->sc_pd->device,
+               qp_attr.cap.max_send_wr,
+               qp_attr.cap.max_recv_wr,
+               qp_attr.cap.max_send_sge,
+               qp_attr.cap.max_recv_sge);
+
+       ret = rdma_create_qp(newxprt->sc_cm_id, newxprt->sc_pd, &qp_attr);
+       if (ret) {
+               /*
+                * XXX: This is a hack. We need a xx_request_qp interface
+                * that will adjust the qp_attr's with a best-effort
+                * number
+                */
+               qp_attr.cap.max_send_sge -= 2;
+               qp_attr.cap.max_recv_sge -= 2;
+               ret = rdma_create_qp(newxprt->sc_cm_id, newxprt->sc_pd,
+                                    &qp_attr);
+               if (ret) {
+                       dprintk("svcrdma: failed to create QP, ret=%d\n", ret);
+                       goto errout;
+               }
+               newxprt->sc_max_sge = qp_attr.cap.max_send_sge;
+               newxprt->sc_max_sge = qp_attr.cap.max_recv_sge;
+               newxprt->sc_sq_depth = qp_attr.cap.max_send_wr;
+               newxprt->sc_max_requests = qp_attr.cap.max_recv_wr;
+       }
+       newxprt->sc_qp = newxprt->sc_cm_id->qp;
+
+       /* Register all of physical memory */
+       newxprt->sc_phys_mr = ib_get_dma_mr(newxprt->sc_pd,
+                                           IB_ACCESS_LOCAL_WRITE |
+                                           IB_ACCESS_REMOTE_WRITE);
+       if (IS_ERR(newxprt->sc_phys_mr)) {
+               dprintk("svcrdma: Failed to create DMA MR ret=%d\n", ret);
+               goto errout;
+       }
+
+       /* Post receive buffers */
+       for (i = 0; i < newxprt->sc_max_requests; i++) {
+               ret = svc_rdma_post_recv(newxprt);
+               if (ret) {
+                       dprintk("svcrdma: failure posting receive buffers\n");
+                       goto errout;
+               }
+       }
+
+       /* Swap out the handler */
+       newxprt->sc_cm_id->event_handler = rdma_cma_handler;
+
+       /* Accept Connection */
+       set_bit(RDMAXPRT_CONN_PENDING, &newxprt->sc_flags);
+       memset(&conn_param, 0, sizeof conn_param);
+       conn_param.responder_resources = 0;
+       conn_param.initiator_depth = newxprt->sc_ord;
+       ret = rdma_accept(newxprt->sc_cm_id, &conn_param);
+       if (ret) {
+               dprintk("svcrdma: failed to accept new connection, ret=%d\n",
+                      ret);
+               goto errout;
+       }
+
+       dprintk("svcrdma: new connection %p accepted with the following "
+               "attributes:\n"
+               "    local_ip        : %d.%d.%d.%d\n"
+               "    local_port      : %d\n"
+               "    remote_ip       : %d.%d.%d.%d\n"
+               "    remote_port     : %d\n"
+               "    max_sge         : %d\n"
+               "    sq_depth        : %d\n"
+               "    max_requests    : %d\n"
+               "    ord             : %d\n",
+               newxprt,
+               NIPQUAD(((struct sockaddr_in *)&newxprt->sc_cm_id->
+                        route.addr.src_addr)->sin_addr.s_addr),
+               ntohs(((struct sockaddr_in *)&newxprt->sc_cm_id->
+                      route.addr.src_addr)->sin_port),
+               NIPQUAD(((struct sockaddr_in *)&newxprt->sc_cm_id->
+                        route.addr.dst_addr)->sin_addr.s_addr),
+               ntohs(((struct sockaddr_in *)&newxprt->sc_cm_id->
+                      route.addr.dst_addr)->sin_port),
+               newxprt->sc_max_sge,
+               newxprt->sc_sq_depth,
+               newxprt->sc_max_requests,
+               newxprt->sc_ord);
+
+       /* Set the local and remote addresses in the transport */
+       sa = (struct sockaddr *)&newxprt->sc_cm_id->route.addr.dst_addr;
+       svc_xprt_set_remote(&newxprt->sc_xprt, sa, svc_addr_len(sa));
+       sa = (struct sockaddr *)&newxprt->sc_cm_id->route.addr.src_addr;
+       svc_xprt_set_local(&newxprt->sc_xprt, sa, svc_addr_len(sa));
+
+       ib_req_notify_cq(newxprt->sc_sq_cq, IB_CQ_NEXT_COMP);
+       ib_req_notify_cq(newxprt->sc_rq_cq, IB_CQ_NEXT_COMP);
+       return &newxprt->sc_xprt;
+
+ errout:
+       dprintk("svcrdma: failure accepting new connection rc=%d.\n", ret);
+       rdma_destroy_id(newxprt->sc_cm_id);
+       rdma_destroy_xprt(newxprt);
+       return NULL;
+}
+
+/*
+ * Post an RQ WQE to the RQ when the rqst is being released. This
+ * effectively returns an RQ credit to the client. The rq_xprt_ctxt
+ * will be null if the request is deferred due to an RDMA_READ or the
+ * transport had no data ready (EAGAIN). Note that an RPC deferred in
+ * svc_process will still return the credit, this is because the data
+ * is copied and no longer consume a WQE/WC.
+ */
+static void svc_rdma_release_rqst(struct svc_rqst *rqstp)
+{
+       int err;
+       struct svcxprt_rdma *rdma =
+               container_of(rqstp->rq_xprt, struct svcxprt_rdma, sc_xprt);
+       if (rqstp->rq_xprt_ctxt) {
+               BUG_ON(rqstp->rq_xprt_ctxt != rdma);
+               err = svc_rdma_post_recv(rdma);
+               if (err)
+                       dprintk("svcrdma: failed to post an RQ WQE error=%d\n",
+                               err);
+       }
+       rqstp->rq_xprt_ctxt = NULL;
+}
+
+/* Disable data ready events for this connection */
+static void svc_rdma_detach(struct svc_xprt *xprt)
+{
+       struct svcxprt_rdma *rdma =
+               container_of(xprt, struct svcxprt_rdma, sc_xprt);
+       unsigned long flags;
+
+       dprintk("svc: svc_rdma_detach(%p)\n", xprt);
+       /*
+        * Shutdown the connection. This will ensure we don't get any
+        * more events from the provider.
+        */
+       rdma_disconnect(rdma->sc_cm_id);
+       rdma_destroy_id(rdma->sc_cm_id);
+
+       /* We may already be on the DTO list */
+       spin_lock_irqsave(&dto_lock, flags);
+       if (!list_empty(&rdma->sc_dto_q))
+               list_del_init(&rdma->sc_dto_q);
+       spin_unlock_irqrestore(&dto_lock, flags);
+}
+
+static void svc_rdma_free(struct svc_xprt *xprt)
+{
+       struct svcxprt_rdma *rdma = (struct svcxprt_rdma *)xprt;
+       dprintk("svcrdma: svc_rdma_free(%p)\n", rdma);
+       rdma_destroy_xprt(rdma);
+       kfree(rdma);
+}
+
+static void rdma_destroy_xprt(struct svcxprt_rdma *xprt)
+{
+       if (xprt->sc_qp && !IS_ERR(xprt->sc_qp))
+               ib_destroy_qp(xprt->sc_qp);
+
+       if (xprt->sc_sq_cq && !IS_ERR(xprt->sc_sq_cq))
+               ib_destroy_cq(xprt->sc_sq_cq);
+
+       if (xprt->sc_rq_cq && !IS_ERR(xprt->sc_rq_cq))
+               ib_destroy_cq(xprt->sc_rq_cq);
+
+       if (xprt->sc_phys_mr && !IS_ERR(xprt->sc_phys_mr))
+               ib_dereg_mr(xprt->sc_phys_mr);
+
+       if (xprt->sc_pd && !IS_ERR(xprt->sc_pd))
+               ib_dealloc_pd(xprt->sc_pd);
+
+       destroy_context_cache(xprt->sc_ctxt_head);
+}
+
+static int svc_rdma_has_wspace(struct svc_xprt *xprt)
+{
+       struct svcxprt_rdma *rdma =
+               container_of(xprt, struct svcxprt_rdma, sc_xprt);
+
+       /*
+        * If there are fewer SQ WR available than required to send a
+        * simple response, return false.
+        */
+       if ((rdma->sc_sq_depth - atomic_read(&rdma->sc_sq_count) < 3))
+               return 0;
+
+       /*
+        * ...or there are already waiters on the SQ,
+        * return false.
+        */
+       if (waitqueue_active(&rdma->sc_send_wait))
+               return 0;
+
+       /* Otherwise return true. */
+       return 1;
+}
+
+int svc_rdma_send(struct svcxprt_rdma *xprt, struct ib_send_wr *wr)
+{
+       struct ib_send_wr *bad_wr;
+       int ret;
+
+       if (test_bit(XPT_CLOSE, &xprt->sc_xprt.xpt_flags))
+               return 0;
+
+       BUG_ON(wr->send_flags != IB_SEND_SIGNALED);
+       BUG_ON(((struct svc_rdma_op_ctxt *)(unsigned long)wr->wr_id)->wr_op !=
+               wr->opcode);
+       /* If the SQ is full, wait until an SQ entry is available */
+       while (1) {
+               spin_lock_bh(&xprt->sc_lock);
+               if (xprt->sc_sq_depth == atomic_read(&xprt->sc_sq_count)) {
+                       spin_unlock_bh(&xprt->sc_lock);
+                       atomic_inc(&rdma_stat_sq_starve);
+                       /* See if we can reap some SQ WR */
+                       sq_cq_reap(xprt);
+
+                       /* Wait until SQ WR available if SQ still full */
+                       wait_event(xprt->sc_send_wait,
+                                  atomic_read(&xprt->sc_sq_count) <
+                                  xprt->sc_sq_depth);
+                       continue;
+               }
+               /* Bumped used SQ WR count and post */
+               ret = ib_post_send(xprt->sc_qp, wr, &bad_wr);
+               if (!ret)
+                       atomic_inc(&xprt->sc_sq_count);
+               else
+                       dprintk("svcrdma: failed to post SQ WR rc=%d, "
+                              "sc_sq_count=%d, sc_sq_depth=%d\n",
+                              ret, atomic_read(&xprt->sc_sq_count),
+                              xprt->sc_sq_depth);
+               spin_unlock_bh(&xprt->sc_lock);
+               break;
+       }
+       return ret;
+}
+
+int svc_rdma_send_error(struct svcxprt_rdma *xprt, struct rpcrdma_msg *rmsgp,
+                       enum rpcrdma_errcode err)
+{
+       struct ib_send_wr err_wr;
+       struct ib_sge sge;
+       struct page *p;
+       struct svc_rdma_op_ctxt *ctxt;
+       u32 *va;
+       int length;
+       int ret;
+
+       p = svc_rdma_get_page();
+       va = page_address(p);
+
+       /* XDR encode error */
+       length = svc_rdma_xdr_encode_error(xprt, rmsgp, err, va);
+
+       /* Prepare SGE for local address */
+       sge.addr = ib_dma_map_page(xprt->sc_cm_id->device,
+                                  p, 0, PAGE_SIZE, DMA_FROM_DEVICE);
+       sge.lkey = xprt->sc_phys_mr->lkey;
+       sge.length = length;
+
+       ctxt = svc_rdma_get_context(xprt);
+       ctxt->count = 1;
+       ctxt->pages[0] = p;
+
+       /* Prepare SEND WR */
+       memset(&err_wr, 0, sizeof err_wr);
+       ctxt->wr_op = IB_WR_SEND;
+       err_wr.wr_id = (unsigned long)ctxt;
+       err_wr.sg_list = &sge;
+       err_wr.num_sge = 1;
+       err_wr.opcode = IB_WR_SEND;
+       err_wr.send_flags = IB_SEND_SIGNALED;
+
+       /* Post It */
+       ret = svc_rdma_send(xprt, &err_wr);
+       if (ret) {
+               dprintk("svcrdma: Error posting send = %d\n", ret);
+               svc_rdma_put_context(ctxt, 1);
+       }
+
+       return ret;
+}
index 07fad7ccf83204c137b90fb0bfc906dd25a0dfbf..339ca4a8e89ed262295fa1851770e34a03a86738 100644 (file)
@@ -1652,7 +1652,7 @@ static int __init x25_init(void)
 
        register_netdevice_notifier(&x25_dev_notifier);
 
-       printk(KERN_INFO "X.25 for Linux. Version 0.2 for Linux 2.1.15\n");
+       printk(KERN_INFO "X.25 for Linux Version 0.2\n");
 
 #ifdef CONFIG_SYSCTL
        x25_register_sysctl();
index b5c5347aed666096c33d0fadbbab0065753ddd08..6cc15250de69949606638cd6fab4afb6a0cadee5 100644 (file)
  * that instantiated crypto transforms have correct parameters for IPsec
  * purposes.
  */
+static struct xfrm_algo_desc aead_list[] = {
+{
+       .name = "rfc4106(gcm(aes))",
+
+       .uinfo = {
+               .aead = {
+                       .icv_truncbits = 64,
+               }
+       },
+
+       .desc = {
+               .sadb_alg_id = SADB_X_EALG_AES_GCM_ICV8,
+               .sadb_alg_ivlen = 8,
+               .sadb_alg_minbits = 128,
+               .sadb_alg_maxbits = 256
+       }
+},
+{
+       .name = "rfc4106(gcm(aes))",
+
+       .uinfo = {
+               .aead = {
+                       .icv_truncbits = 96,
+               }
+       },
+
+       .desc = {
+               .sadb_alg_id = SADB_X_EALG_AES_GCM_ICV12,
+               .sadb_alg_ivlen = 8,
+               .sadb_alg_minbits = 128,
+               .sadb_alg_maxbits = 256
+       }
+},
+{
+       .name = "rfc4106(gcm(aes))",
+
+       .uinfo = {
+               .aead = {
+                       .icv_truncbits = 128,
+               }
+       },
+
+       .desc = {
+               .sadb_alg_id = SADB_X_EALG_AES_GCM_ICV16,
+               .sadb_alg_ivlen = 8,
+               .sadb_alg_minbits = 128,
+               .sadb_alg_maxbits = 256
+       }
+},
+{
+       .name = "rfc4309(ccm(aes))",
+
+       .uinfo = {
+               .aead = {
+                       .icv_truncbits = 64,
+               }
+       },
+
+       .desc = {
+               .sadb_alg_id = SADB_X_EALG_AES_CCM_ICV8,
+               .sadb_alg_ivlen = 8,
+               .sadb_alg_minbits = 128,
+               .sadb_alg_maxbits = 256
+       }
+},
+{
+       .name = "rfc4309(ccm(aes))",
+
+       .uinfo = {
+               .aead = {
+                       .icv_truncbits = 96,
+               }
+       },
+
+       .desc = {
+               .sadb_alg_id = SADB_X_EALG_AES_CCM_ICV12,
+               .sadb_alg_ivlen = 8,
+               .sadb_alg_minbits = 128,
+               .sadb_alg_maxbits = 256
+       }
+},
+{
+       .name = "rfc4309(ccm(aes))",
+
+       .uinfo = {
+               .aead = {
+                       .icv_truncbits = 128,
+               }
+       },
+
+       .desc = {
+               .sadb_alg_id = SADB_X_EALG_AES_CCM_ICV16,
+               .sadb_alg_ivlen = 8,
+               .sadb_alg_minbits = 128,
+               .sadb_alg_maxbits = 256
+       }
+},
+};
+
 static struct xfrm_algo_desc aalg_list[] = {
 {
        .name = "hmac(digest_null)",
@@ -332,6 +431,11 @@ static struct xfrm_algo_desc calg_list[] = {
 },
 };
 
+static inline int aead_entries(void)
+{
+       return ARRAY_SIZE(aead_list);
+}
+
 static inline int aalg_entries(void)
 {
        return ARRAY_SIZE(aalg_list);
@@ -354,25 +458,32 @@ struct xfrm_algo_list {
        u32 mask;
 };
 
+static const struct xfrm_algo_list xfrm_aead_list = {
+       .algs = aead_list,
+       .entries = ARRAY_SIZE(aead_list),
+       .type = CRYPTO_ALG_TYPE_AEAD,
+       .mask = CRYPTO_ALG_TYPE_MASK,
+};
+
 static const struct xfrm_algo_list xfrm_aalg_list = {
        .algs = aalg_list,
        .entries = ARRAY_SIZE(aalg_list),
        .type = CRYPTO_ALG_TYPE_HASH,
-       .mask = CRYPTO_ALG_TYPE_HASH_MASK | CRYPTO_ALG_ASYNC,
+       .mask = CRYPTO_ALG_TYPE_HASH_MASK,
 };
 
 static const struct xfrm_algo_list xfrm_ealg_list = {
        .algs = ealg_list,
        .entries = ARRAY_SIZE(ealg_list),
        .type = CRYPTO_ALG_TYPE_BLKCIPHER,
-       .mask = CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC,
+       .mask = CRYPTO_ALG_TYPE_BLKCIPHER_MASK,
 };
 
 static const struct xfrm_algo_list xfrm_calg_list = {
        .algs = calg_list,
        .entries = ARRAY_SIZE(calg_list),
        .type = CRYPTO_ALG_TYPE_COMPRESS,
-       .mask = CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC,
+       .mask = CRYPTO_ALG_TYPE_MASK,
 };
 
 static struct xfrm_algo_desc *xfrm_find_algo(
@@ -461,6 +572,33 @@ struct xfrm_algo_desc *xfrm_calg_get_byname(char *name, int probe)
 }
 EXPORT_SYMBOL_GPL(xfrm_calg_get_byname);
 
+struct xfrm_aead_name {
+       const char *name;
+       int icvbits;
+};
+
+static int xfrm_aead_name_match(const struct xfrm_algo_desc *entry,
+                               const void *data)
+{
+       const struct xfrm_aead_name *aead = data;
+       const char *name = aead->name;
+
+       return aead->icvbits == entry->uinfo.aead.icv_truncbits && name &&
+              !strcmp(name, entry->name);
+}
+
+struct xfrm_algo_desc *xfrm_aead_get_byname(char *name, int icv_len, int probe)
+{
+       struct xfrm_aead_name data = {
+               .name = name,
+               .icvbits = icv_len,
+       };
+
+       return xfrm_find_algo(&xfrm_aead_list, xfrm_aead_name_match, &data,
+                             probe);
+}
+EXPORT_SYMBOL_GPL(xfrm_aead_get_byname);
+
 struct xfrm_algo_desc *xfrm_aalg_get_byidx(unsigned int idx)
 {
        if (idx >= aalg_entries())
index 039e7019c48a4e56b40354177e553752568f6793..4d6ebc633a944d14a328606ee675ae5cc528e191 100644 (file)
@@ -81,7 +81,6 @@ int xfrm_parse_spi(struct sk_buff *skb, u8 nexthdr, __be32 *spi, __be32 *seq)
        *seq = *(__be32*)(skb_transport_header(skb) + offset_seq);
        return 0;
 }
-EXPORT_SYMBOL(xfrm_parse_spi);
 
 int xfrm_prepare_input(struct xfrm_state *x, struct sk_buff *skb)
 {
@@ -160,12 +159,12 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
                }
 
                if ((x->encap ? x->encap->encap_type : 0) != encap_type) {
-                       XFRM_INC_STATS(LINUX_MIB_XFRMINSTATEINVALID);
+                       XFRM_INC_STATS(LINUX_MIB_XFRMINSTATEMISMATCH);
                        goto drop_unlock;
                }
 
                if (x->props.replay_window && xfrm_replay_check(x, skb, seq)) {
-                       XFRM_INC_STATS(LINUX_MIB_XFRMINSEQOUTOFWINDOW);
+                       XFRM_INC_STATS(LINUX_MIB_XFRMINSTATESEQERROR);
                        goto drop_unlock;
                }
 
index f4a1047a55737929efd37f989c53fc18adea6b53..fc690368325f6b86c0ee7b1e74a16ac442b3965d 100644 (file)
@@ -64,6 +64,7 @@ static int xfrm_output_one(struct sk_buff *skb, int err)
                if (x->type->flags & XFRM_TYPE_REPLAY_PROT) {
                        XFRM_SKB_CB(skb)->seq = ++x->replay.oseq;
                        if (unlikely(x->replay.oseq == 0)) {
+                               XFRM_INC_STATS(LINUX_MIB_XFRMOUTSTATESEQERROR);
                                x->replay.oseq--;
                                xfrm_audit_state_replay_overflow(x, skb);
                                err = -EOVERFLOW;
index 31d035415ecd2e155b77cad6937b039b09341455..2b0db13f0cda681c9482e86a97a51cf6f9f660d4 100644 (file)
@@ -22,7 +22,7 @@ static struct snmp_mib xfrm_mib_list[] = {
        SNMP_MIB_ITEM("XfrmInNoStates", LINUX_MIB_XFRMINNOSTATES),
        SNMP_MIB_ITEM("XfrmInStateProtoError", LINUX_MIB_XFRMINSTATEPROTOERROR),
        SNMP_MIB_ITEM("XfrmInStateModeError", LINUX_MIB_XFRMINSTATEMODEERROR),
-       SNMP_MIB_ITEM("XfrmInSeqOutOfWindow", LINUX_MIB_XFRMINSEQOUTOFWINDOW),
+       SNMP_MIB_ITEM("XfrmInStateSeqError", LINUX_MIB_XFRMINSTATESEQERROR),
        SNMP_MIB_ITEM("XfrmInStateExpired", LINUX_MIB_XFRMINSTATEEXPIRED),
        SNMP_MIB_ITEM("XfrmInStateMismatch", LINUX_MIB_XFRMINSTATEMISMATCH),
        SNMP_MIB_ITEM("XfrmInStateInvalid", LINUX_MIB_XFRMINSTATEINVALID),
@@ -36,6 +36,7 @@ static struct snmp_mib xfrm_mib_list[] = {
        SNMP_MIB_ITEM("XfrmOutNoStates", LINUX_MIB_XFRMOUTNOSTATES),
        SNMP_MIB_ITEM("XfrmOutStateProtoError", LINUX_MIB_XFRMOUTSTATEPROTOERROR),
        SNMP_MIB_ITEM("XfrmOutStateModeError", LINUX_MIB_XFRMOUTSTATEMODEERROR),
+       SNMP_MIB_ITEM("XfrmOutStateSeqError", LINUX_MIB_XFRMOUTSTATESEQERROR),
        SNMP_MIB_ITEM("XfrmOutStateExpired", LINUX_MIB_XFRMOUTSTATEEXPIRED),
        SNMP_MIB_ITEM("XfrmOutPolBlock", LINUX_MIB_XFRMOUTPOLBLOCK),
        SNMP_MIB_ITEM("XfrmOutPolDead", LINUX_MIB_XFRMOUTPOLDEAD),
index 3003503d0c94937d570795fcbabf8ce155155130..7ba65e82941c4f7794f6ada15a418d60606dbba4 100644 (file)
@@ -216,10 +216,10 @@ static void xfrm_state_unlock_afinfo(struct xfrm_state_afinfo *afinfo)
        write_unlock_bh(&xfrm_state_afinfo_lock);
 }
 
-int xfrm_register_type(struct xfrm_type *type, unsigned short family)
+int xfrm_register_type(const struct xfrm_type *type, unsigned short family)
 {
        struct xfrm_state_afinfo *afinfo = xfrm_state_lock_afinfo(family);
-       struct xfrm_type **typemap;
+       const struct xfrm_type **typemap;
        int err = 0;
 
        if (unlikely(afinfo == NULL))
@@ -235,10 +235,10 @@ int xfrm_register_type(struct xfrm_type *type, unsigned short family)
 }
 EXPORT_SYMBOL(xfrm_register_type);
 
-int xfrm_unregister_type(struct xfrm_type *type, unsigned short family)
+int xfrm_unregister_type(const struct xfrm_type *type, unsigned short family)
 {
        struct xfrm_state_afinfo *afinfo = xfrm_state_lock_afinfo(family);
-       struct xfrm_type **typemap;
+       const struct xfrm_type **typemap;
        int err = 0;
 
        if (unlikely(afinfo == NULL))
@@ -254,11 +254,11 @@ int xfrm_unregister_type(struct xfrm_type *type, unsigned short family)
 }
 EXPORT_SYMBOL(xfrm_unregister_type);
 
-static struct xfrm_type *xfrm_get_type(u8 proto, unsigned short family)
+static const struct xfrm_type *xfrm_get_type(u8 proto, unsigned short family)
 {
        struct xfrm_state_afinfo *afinfo;
-       struct xfrm_type **typemap;
-       struct xfrm_type *type;
+       const struct xfrm_type **typemap;
+       const struct xfrm_type *type;
        int modload_attempted = 0;
 
 retry:
@@ -281,7 +281,7 @@ retry:
        return type;
 }
 
-static void xfrm_put_type(struct xfrm_type *type)
+static void xfrm_put_type(const struct xfrm_type *type)
 {
        module_put(type->owner);
 }
@@ -493,7 +493,7 @@ expired:
                km_state_expired(x, 1, 0);
 
        xfrm_audit_state_delete(x, err ? 0 : 1,
-                               audit_get_loginuid(current->audit_context), 0);
+                               audit_get_loginuid(current), 0);
 
 out:
        spin_unlock(&x->lock);
@@ -1645,7 +1645,6 @@ err:
        xfrm_audit_state_replay(x, skb, net_seq);
        return -EINVAL;
 }
-EXPORT_SYMBOL(xfrm_replay_check);
 
 void xfrm_replay_advance(struct xfrm_state *x, __be32 net_seq)
 {
@@ -1667,7 +1666,6 @@ void xfrm_replay_advance(struct xfrm_state *x, __be32 net_seq)
        if (xfrm_aevent_is_on())
                xfrm_replay_notify(x, XFRM_REPLAY_UPDATE);
 }
-EXPORT_SYMBOL(xfrm_replay_advance);
 
 static LIST_HEAD(xfrm_km_list);
 static DEFINE_RWLOCK(xfrm_km_lock);
index e0ccdf26781360fc8c2860ddbb3b33ec0dafc7d0..78338079b7f579d07ad4267ae782a1bfea2613e2 100644 (file)
 #include <linux/in6.h>
 #endif
 
+static inline int aead_len(struct xfrm_algo_aead *alg)
+{
+       return sizeof(*alg) + ((alg->alg_key_len + 7) / 8);
+}
+
 static int verify_one_alg(struct nlattr **attrs, enum xfrm_attr_type_t type)
 {
        struct nlattr *rt = attrs[type];
@@ -68,6 +73,22 @@ static int verify_one_alg(struct nlattr **attrs, enum xfrm_attr_type_t type)
        return 0;
 }
 
+static int verify_aead(struct nlattr **attrs)
+{
+       struct nlattr *rt = attrs[XFRMA_ALG_AEAD];
+       struct xfrm_algo_aead *algp;
+
+       if (!rt)
+               return 0;
+
+       algp = nla_data(rt);
+       if (nla_len(rt) < aead_len(algp))
+               return -EINVAL;
+
+       algp->alg_name[CRYPTO_MAX_ALG_NAME - 1] = '\0';
+       return 0;
+}
+
 static void verify_one_addr(struct nlattr **attrs, enum xfrm_attr_type_t type,
                           xfrm_address_t **addrp)
 {
@@ -119,20 +140,28 @@ static int verify_newsa_info(struct xfrm_usersa_info *p,
        switch (p->id.proto) {
        case IPPROTO_AH:
                if (!attrs[XFRMA_ALG_AUTH]      ||
+                   attrs[XFRMA_ALG_AEAD]       ||
                    attrs[XFRMA_ALG_CRYPT]      ||
                    attrs[XFRMA_ALG_COMP])
                        goto out;
                break;
 
        case IPPROTO_ESP:
-               if ((!attrs[XFRMA_ALG_AUTH] &&
-                    !attrs[XFRMA_ALG_CRYPT])   ||
-                   attrs[XFRMA_ALG_COMP])
+               if (attrs[XFRMA_ALG_COMP])
+                       goto out;
+               if (!attrs[XFRMA_ALG_AUTH] &&
+                   !attrs[XFRMA_ALG_CRYPT] &&
+                   !attrs[XFRMA_ALG_AEAD])
+                       goto out;
+               if ((attrs[XFRMA_ALG_AUTH] ||
+                    attrs[XFRMA_ALG_CRYPT]) &&
+                   attrs[XFRMA_ALG_AEAD])
                        goto out;
                break;
 
        case IPPROTO_COMP:
                if (!attrs[XFRMA_ALG_COMP]      ||
+                   attrs[XFRMA_ALG_AEAD]       ||
                    attrs[XFRMA_ALG_AUTH]       ||
                    attrs[XFRMA_ALG_CRYPT])
                        goto out;
@@ -143,6 +172,7 @@ static int verify_newsa_info(struct xfrm_usersa_info *p,
        case IPPROTO_ROUTING:
                if (attrs[XFRMA_ALG_COMP]       ||
                    attrs[XFRMA_ALG_AUTH]       ||
+                   attrs[XFRMA_ALG_AEAD]       ||
                    attrs[XFRMA_ALG_CRYPT]      ||
                    attrs[XFRMA_ENCAP]          ||
                    attrs[XFRMA_SEC_CTX]        ||
@@ -155,6 +185,8 @@ static int verify_newsa_info(struct xfrm_usersa_info *p,
                goto out;
        }
 
+       if ((err = verify_aead(attrs)))
+               goto out;
        if ((err = verify_one_alg(attrs, XFRMA_ALG_AUTH)))
                goto out;
        if ((err = verify_one_alg(attrs, XFRMA_ALG_CRYPT)))
@@ -208,6 +240,31 @@ static int attach_one_algo(struct xfrm_algo **algpp, u8 *props,
        return 0;
 }
 
+static int attach_aead(struct xfrm_algo_aead **algpp, u8 *props,
+                      struct nlattr *rta)
+{
+       struct xfrm_algo_aead *p, *ualg;
+       struct xfrm_algo_desc *algo;
+
+       if (!rta)
+               return 0;
+
+       ualg = nla_data(rta);
+
+       algo = xfrm_aead_get_byname(ualg->alg_name, ualg->alg_icv_len, 1);
+       if (!algo)
+               return -ENOSYS;
+       *props = algo->desc.sadb_alg_id;
+
+       p = kmemdup(ualg, aead_len(ualg), GFP_KERNEL);
+       if (!p)
+               return -ENOMEM;
+
+       strcpy(p->alg_name, algo->name);
+       *algpp = p;
+       return 0;
+}
+
 static inline int xfrm_user_sec_ctx_size(struct xfrm_sec_ctx *xfrm_ctx)
 {
        int len = 0;
@@ -286,6 +343,9 @@ static struct xfrm_state *xfrm_state_construct(struct xfrm_usersa_info *p,
 
        copy_from_user_state(x, p);
 
+       if ((err = attach_aead(&x->aead, &x->props.ealgo,
+                              attrs[XFRMA_ALG_AEAD])))
+               goto error;
        if ((err = attach_one_algo(&x->aalg, &x->props.aalgo,
                                   xfrm_aalg_get_byname,
                                   attrs[XFRMA_ALG_AUTH])))
@@ -510,6 +570,8 @@ static int copy_to_user_state_extra(struct xfrm_state *x,
        if (x->lastused)
                NLA_PUT_U64(skb, XFRMA_LASTUSED, x->lastused);
 
+       if (x->aead)
+               NLA_PUT(skb, XFRMA_ALG_AEAD, aead_len(x->aead), x->aead);
        if (x->aalg)
                NLA_PUT(skb, XFRMA_ALG_AUTH, xfrm_alg_len(x->aalg), x->aalg);
        if (x->ealg)
@@ -1808,6 +1870,7 @@ static const int xfrm_msg_min[XFRM_NR_MSGTYPES] = {
 #undef XMSGSIZE
 
 static const struct nla_policy xfrma_policy[XFRMA_MAX+1] = {
+       [XFRMA_ALG_AEAD]        = { .len = sizeof(struct xfrm_algo_aead) },
        [XFRMA_ALG_AUTH]        = { .len = sizeof(struct xfrm_algo) },
        [XFRMA_ALG_CRYPT]       = { .len = sizeof(struct xfrm_algo) },
        [XFRMA_ALG_COMP]        = { .len = sizeof(struct xfrm_algo) },
@@ -1972,6 +2035,8 @@ static int xfrm_notify_sa_flush(struct km_event *c)
 static inline size_t xfrm_sa_len(struct xfrm_state *x)
 {
        size_t l = 0;
+       if (x->aead)
+               l += nla_total_size(aead_len(x->aead));
        if (x->aalg)
                l += nla_total_size(xfrm_alg_len(x->aalg));
        if (x->ealg)
index 50e61c411bc0f89d8f9c5ec9d7c7ea6992a43371..734cf4f3131e69b36c26ee23ee36dfe0a59496ff 100644 (file)
@@ -821,6 +821,7 @@ static void conf_load(void)
                                return;
                        if (!conf_read(dialog_input_result)) {
                                set_config_filename(dialog_input_result);
+                               sym_set_change_count(1);
                                return;
                        }
                        show_textbox(NULL, _("File does not exist!"), 5, 38);
index fdad17367f612428d61ab78e8ebb0df864672454..606ceb9e746ec3b9649fd534c50f16e95f73f69f 100644 (file)
@@ -203,12 +203,9 @@ void sym_check_prop(struct symbol *sym)
                                prop_warn(prop,
                                    "config symbol '%s' uses select, but is "
                                    "not boolean or tristate", sym->name);
-                       else if (sym2->type == S_UNKNOWN)
-                               prop_warn(prop,
-                                   "'select' used by config symbol '%s' "
-                                   "refers to undefined symbol '%s'",
-                                   sym->name, sym2->name);
-                       else if (sym2->type != S_BOOLEAN && sym2->type != S_TRISTATE)
+                       else if (sym2->type != S_UNKNOWN &&
+                                sym2->type != S_BOOLEAN &&
+                                sym2->type != S_TRISTATE)
                                prop_warn(prop,
                                    "'%s' has wrong type. 'select' only "
                                    "accept arguments of boolean and "
index d802b5afae89254f3b3131f7552e9eb60f7e07a7..9ddf944cce290b7d38fc2982b852bc93d4c50001 100644 (file)
@@ -155,7 +155,7 @@ static void do_usb_entry_multi(struct usb_device_id *id, struct module *mod)
         * Some modules (visor) have empty slots as placeholder for
         * run-time specification that results in catch-all alias
         */
-       if (!(id->idVendor | id->bDeviceClass | id->bInterfaceClass))
+       if (!(id->idVendor | id->idProduct | id->bDeviceClass | id->bInterfaceClass))
                return;
 
        /* Convert numeric bcdDevice range into fnmatch-able pattern(s) */
index f8efc93eb7004c9ee0004c979acd617ca7d2e8f8..5d546466e6b1f8d2e700fa0ef846ebe6a14569cd 100644 (file)
@@ -870,7 +870,7 @@ const struct sectioncheck sectioncheck[] = {
 /* Do not export init/exit functions or data */
 {
        .fromsec = { "__ksymtab*", NULL },
-       .tosec   = { ALL_INIT_SECTIONS, ALL_EXIT_SECTIONS, NULL },
+       .tosec   = { INIT_SECTIONS, EXIT_SECTIONS, NULL },
        .mismatch = EXPORT_TO_INIT_EXIT
 }
 };
@@ -1125,15 +1125,15 @@ static void report_sec_mismatch(const char *modname, enum mismatch mismatch,
        to = to_is_func ? "function" : "variable";
        to_p = to_is_func ? "()" : "";
 
+       sec_mismatch_count++;
+       if (!sec_mismatch_verbose)
+               return;
+
        fprintf(stderr, "WARNING: %s(%s+0x%llx): Section mismatch in"
                        " reference from the %s %s%s to the %s %s:%s%s\n",
                         modname, fromsec, fromaddr, from, fromsym, from_p,
                        to, tosec, tosym, to_p);
 
-       sec_mismatch_count++;
-       if (!sec_mismatch_verbose)
-               return;
-
        switch (mismatch) {
        case TEXT_TO_INIT:
                fprintf(stderr,
@@ -1939,10 +1939,9 @@ int main(int argc, char **argv)
                write_dump(dump_write);
        if (sec_mismatch_count && !sec_mismatch_verbose)
                fprintf(stderr, "modpost: Found %d section mismatch(es).\n"
-                       "To see additional details select \"Enable full "
-                       "Section mismatch analysis\"\n"
-                       "in the Kernel Hacking menu "
-                       "(CONFIG_SECTION_MISMATCH).\n", sec_mismatch_count);
+                       "To see full details build your kernel with:\n"
+                       "'make CONFIG_DEBUG_SECTION_MISMATCH=y'\n",
+                       sec_mismatch_count);
 
        return err;
 }
old mode 100644 (file)
new mode 100755 (executable)
index 52f032e..1c1bdaf
@@ -45,3 +45,19 @@ if hgid=`hg id 2>/dev/null`; then
        # All done with mercurial
        exit
 fi
+
+# Check for svn and a svn repo.
+if rev=`svn info 2>/dev/null | grep '^Revision'`; then
+       rev=`echo $rev | awk '{print $NF}'`
+       changes=`svn status 2>/dev/null | grep '^[AMD]' | wc -l`
+
+       # Are there uncommitted changes?
+       if [ $changes != 0 ]; then
+               printf -- '-svn%s%s%s' "$rev" -dirty "$changes"
+       else
+               printf -- '-svn%s' "$rev"
+       fi
+
+       # All done with svn
+       exit
+fi
index 389e151e3b68e832d7b63b9623e10098d6d2e03b..25ffe1b9dc98467d7be1ec373c7024f246172e0b 100644 (file)
@@ -105,6 +105,7 @@ config SECURITY_ROOTPLUG
          If you are unsure how to answer this question, answer N.
 
 source security/selinux/Kconfig
+source security/smack/Kconfig
 
 endmenu
 
index ef87df2f50a454ac0f9c5aedeb235b347a2706b4..9e8b025250144ce739e80583a095b3059d89110c 100644 (file)
@@ -4,6 +4,7 @@
 
 obj-$(CONFIG_KEYS)                     += keys/
 subdir-$(CONFIG_SECURITY_SELINUX)      += selinux
+subdir-$(CONFIG_SECURITY_SMACK)                += smack
 
 # if we don't select a security model, use the default capabilities
 ifneq ($(CONFIG_SECURITY),y)
@@ -14,5 +15,6 @@ endif
 obj-$(CONFIG_SECURITY)                 += security.o dummy.o inode.o
 # Must precede capability.o in order to stack properly.
 obj-$(CONFIG_SECURITY_SELINUX)         += selinux/built-in.o
+obj-$(CONFIG_SECURITY_SMACK)           += commoncap.o smack/built-in.o
 obj-$(CONFIG_SECURITY_CAPABILITIES)    += commoncap.o capability.o
 obj-$(CONFIG_SECURITY_ROOTPLUG)                += commoncap.o root_plug.o
index ea61bc73f6d3c4d1ecfe9d81964342b8cd306d74..5aba82679a0bb9e5506628c9190846a1134707e7 100644 (file)
@@ -1,4 +1,4 @@
-/* Common capabilities, needed by capability.o and root_plug.o 
+/* Common capabilities, needed by capability.o and root_plug.o
  *
  *     This program is free software; you can redistribute it and/or modify
  *     it under the terms of the GNU General Public License as published by
 #include <linux/mount.h>
 #include <linux/sched.h>
 
-#ifdef CONFIG_SECURITY_FILE_CAPABILITIES
-/*
- * Because of the reduced scope of CAP_SETPCAP when filesystem
- * capabilities are in effect, it is safe to allow this capability to
- * be available in the default configuration.
- */
-# define CAP_INIT_BSET  CAP_FULL_SET
-#else /* ie. ndef CONFIG_SECURITY_FILE_CAPABILITIES */
-# define CAP_INIT_BSET  CAP_INIT_EFF_SET
-#endif /* def CONFIG_SECURITY_FILE_CAPABILITIES */
-
-kernel_cap_t cap_bset = CAP_INIT_BSET;    /* systemwide capability bound */
-EXPORT_SYMBOL(cap_bset);
-
 /* Global security state */
 
 unsigned securebits = SECUREBITS_DEFAULT; /* systemwide security settings */
@@ -93,9 +79,9 @@ int cap_capget (struct task_struct *target, kernel_cap_t *effective,
                kernel_cap_t *inheritable, kernel_cap_t *permitted)
 {
        /* Derived from kernel/capability.c:sys_capget. */
-       *effective = cap_t (target->cap_effective);
-       *inheritable = cap_t (target->cap_inheritable);
-       *permitted = cap_t (target->cap_permitted);
+       *effective = target->cap_effective;
+       *inheritable = target->cap_inheritable;
+       *permitted = target->cap_permitted;
        return 0;
 }
 
@@ -140,6 +126,12 @@ int cap_capset_check (struct task_struct *target, kernel_cap_t *effective,
                /* incapable of using this inheritable set */
                return -EPERM;
        }
+       if (!cap_issubset(*inheritable,
+                          cap_combine(target->cap_inheritable,
+                                      current->cap_bset))) {
+               /* no new pI capabilities outside bounding set */
+               return -EPERM;
+       }
 
        /* verify restrictions on target's new Permitted set */
        if (!cap_issubset (*permitted,
@@ -198,28 +190,50 @@ int cap_inode_killpriv(struct dentry *dentry)
 }
 
 static inline int cap_from_disk(struct vfs_cap_data *caps,
-                               struct linux_binprm *bprm,
-                               int size)
+                               struct linux_binprm *bprm, unsigned size)
 {
        __u32 magic_etc;
+       unsigned tocopy, i;
 
-       if (size != XATTR_CAPS_SZ)
+       if (size < sizeof(magic_etc))
                return -EINVAL;
 
        magic_etc = le32_to_cpu(caps->magic_etc);
 
        switch ((magic_etc & VFS_CAP_REVISION_MASK)) {
-       case VFS_CAP_REVISION:
-               if (magic_etc & VFS_CAP_FLAGS_EFFECTIVE)
-                       bprm->cap_effective = true;
-               else
-                       bprm->cap_effective = false;
-               bprm->cap_permitted = to_cap_t(le32_to_cpu(caps->permitted));
-               bprm->cap_inheritable = to_cap_t(le32_to_cpu(caps->inheritable));
-               return 0;
+       case VFS_CAP_REVISION_1:
+               if (size != XATTR_CAPS_SZ_1)
+                       return -EINVAL;
+               tocopy = VFS_CAP_U32_1;
+               break;
+       case VFS_CAP_REVISION_2:
+               if (size != XATTR_CAPS_SZ_2)
+                       return -EINVAL;
+               tocopy = VFS_CAP_U32_2;
+               break;
        default:
                return -EINVAL;
        }
+
+       if (magic_etc & VFS_CAP_FLAGS_EFFECTIVE) {
+               bprm->cap_effective = true;
+       } else {
+               bprm->cap_effective = false;
+       }
+
+       for (i = 0; i < tocopy; ++i) {
+               bprm->cap_permitted.cap[i] =
+                       le32_to_cpu(caps->data[i].permitted);
+               bprm->cap_inheritable.cap[i] =
+                       le32_to_cpu(caps->data[i].inheritable);
+       }
+       while (i < VFS_CAP_U32) {
+               bprm->cap_permitted.cap[i] = 0;
+               bprm->cap_inheritable.cap[i] = 0;
+               i++;
+       }
+
+       return 0;
 }
 
 /* Locate any VFS capabilities: */
@@ -227,7 +241,7 @@ static int get_file_caps(struct linux_binprm *bprm)
 {
        struct dentry *dentry;
        int rc = 0;
-       struct vfs_cap_data incaps;
+       struct vfs_cap_data vcaps;
        struct inode *inode;
 
        if (bprm->file->f_vfsmnt->mnt_flags & MNT_NOSUID) {
@@ -240,14 +254,8 @@ static int get_file_caps(struct linux_binprm *bprm)
        if (!inode->i_op || !inode->i_op->getxattr)
                goto out;
 
-       rc = inode->i_op->getxattr(dentry, XATTR_NAME_CAPS, NULL, 0);
-       if (rc > 0) {
-               if (rc == XATTR_CAPS_SZ)
-                       rc = inode->i_op->getxattr(dentry, XATTR_NAME_CAPS,
-                                               &incaps, XATTR_CAPS_SZ);
-               else
-                       rc = -EINVAL;
-       }
+       rc = inode->i_op->getxattr(dentry, XATTR_NAME_CAPS, &vcaps,
+                                  XATTR_CAPS_SZ);
        if (rc == -ENODATA || rc == -EOPNOTSUPP) {
                /* no data, that's ok */
                rc = 0;
@@ -256,7 +264,7 @@ static int get_file_caps(struct linux_binprm *bprm)
        if (rc < 0)
                goto out;
 
-       rc = cap_from_disk(&incaps, bprm, rc);
+       rc = cap_from_disk(&vcaps, bprm, rc);
        if (rc)
                printk(KERN_NOTICE "%s: cap_from_disk returned %d for %s\n",
                        __FUNCTION__, rc, bprm->filename);
@@ -321,10 +329,11 @@ void cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe)
        /* Derived from fs/exec.c:compute_creds. */
        kernel_cap_t new_permitted, working;
 
-       new_permitted = cap_intersect (bprm->cap_permitted, cap_bset);
-       working = cap_intersect (bprm->cap_inheritable,
+       new_permitted = cap_intersect(bprm->cap_permitted,
+                                current->cap_bset);
+       working = cap_intersect(bprm->cap_inheritable,
                                 current->cap_inheritable);
-       new_permitted = cap_combine (new_permitted, working);
+       new_permitted = cap_combine(new_permitted, working);
 
        if (bprm->e_uid != current->uid || bprm->e_gid != current->gid ||
            !cap_issubset (new_permitted, current->cap_permitted)) {
@@ -351,8 +360,10 @@ void cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe)
         * capability rules */
        if (!is_global_init(current)) {
                current->cap_permitted = new_permitted;
-               current->cap_effective = bprm->cap_effective ?
-                               new_permitted : 0;
+               if (bprm->cap_effective)
+                       current->cap_effective = new_permitted;
+               else
+                       cap_clear(current->cap_effective);
        }
 
        /* AUD: Audit candidate if current->cap_effective is set */
@@ -474,13 +485,15 @@ int cap_task_post_setuid (uid_t old_ruid, uid_t old_euid, uid_t old_suid,
 
                        if (!issecure (SECURE_NO_SETUID_FIXUP)) {
                                if (old_fsuid == 0 && current->fsuid != 0) {
-                                       cap_t (current->cap_effective) &=
-                                           ~CAP_FS_MASK;
+                                       current->cap_effective =
+                                               cap_drop_fs_set(
+                                                   current->cap_effective);
                                }
                                if (old_fsuid != 0 && current->fsuid == 0) {
-                                       cap_t (current->cap_effective) |=
-                                           (cap_t (current->cap_permitted) &
-                                            CAP_FS_MASK);
+                                       current->cap_effective =
+                                               cap_raise_fs_set(
+                                                   current->cap_effective,
+                                                   current->cap_permitted);
                                }
                        }
                        break;
@@ -561,6 +574,23 @@ int cap_task_kill(struct task_struct *p, struct siginfo *info,
 
        return -EPERM;
 }
+
+/*
+ * called from kernel/sys.c for prctl(PR_CABSET_DROP)
+ * done without task_capability_lock() because it introduces
+ * no new races - i.e. only another task doing capget() on
+ * this task could get inconsistent info.  There can be no
+ * racing writer bc a task can only change its own caps.
+ */
+long cap_prctl_drop(unsigned long cap)
+{
+       if (!capable(CAP_SETPCAP))
+               return -EPERM;
+       if (!cap_valid(cap))
+               return -EINVAL;
+       cap_lower(current->cap_bset, cap);
+       return 0;
+}
 #else
 int cap_task_setscheduler (struct task_struct *p, int policy,
                           struct sched_param *lp)
@@ -584,9 +614,9 @@ int cap_task_kill(struct task_struct *p, struct siginfo *info,
 
 void cap_task_reparent_to_init (struct task_struct *p)
 {
-       p->cap_effective = CAP_INIT_EFF_SET;
-       p->cap_inheritable = CAP_INIT_INH_SET;
-       p->cap_permitted = CAP_FULL_SET;
+       cap_set_init_eff(p->cap_effective);
+       cap_clear(p->cap_inheritable);
+       cap_set_full(p->cap_permitted);
        p->keep_capabilities = 0;
        return;
 }
index 48d4b0a52737b2e28a8fb2e32d589af2db2463f9..649326bf64ea37e82afe63901560f96c687a468b 100644 (file)
@@ -36,14 +36,19 @@ static int dummy_ptrace (struct task_struct *parent, struct task_struct *child)
 static int dummy_capget (struct task_struct *target, kernel_cap_t * effective,
                         kernel_cap_t * inheritable, kernel_cap_t * permitted)
 {
-       *effective = *inheritable = *permitted = 0;
        if (target->euid == 0) {
-               *permitted |= (~0 & ~CAP_FS_MASK);
-               *effective |= (~0 & ~CAP_TO_MASK(CAP_SETPCAP) & ~CAP_FS_MASK);
+               cap_set_full(*permitted);
+               cap_set_init_eff(*effective);
+       } else {
+               cap_clear(*permitted);
+               cap_clear(*effective);
        }
-       if (target->fsuid == 0) {
-               *permitted |= CAP_FS_MASK;
-               *effective |= CAP_FS_MASK;
+
+       cap_clear(*inheritable);
+
+       if (target->fsuid != 0) {
+               *permitted = cap_drop_fs_set(*permitted);
+               *effective = cap_drop_fs_set(*effective);
        }
        return 0;
 }
@@ -402,7 +407,7 @@ static int dummy_inode_killpriv(struct dentry *dentry)
        return 0;
 }
 
-static int dummy_inode_getsecurity(const struct inode *inode, const char *name, void *buffer, size_t size, int err)
+static int dummy_inode_getsecurity(const struct inode *inode, const char *name, void **buffer, bool alloc)
 {
        return -EOPNOTSUPP;
 }
index ca475ca206e4b3afe51ad7bdee1c30fe8398c892..b6c57a6b2ff55d41ca660b232b8bcd95dbd7faed 100644 (file)
@@ -493,11 +493,11 @@ int security_inode_killpriv(struct dentry *dentry)
        return security_ops->inode_killpriv(dentry);
 }
 
-int security_inode_getsecurity(const struct inode *inode, const char *name, void *buffer, size_t size, int err)
+int security_inode_getsecurity(const struct inode *inode, const char *name, void **buffer, bool alloc)
 {
        if (unlikely(IS_PRIVATE(inode)))
                return 0;
-       return security_ops->inode_getsecurity(inode, name, buffer, size, err);
+       return security_ops->inode_getsecurity(inode, name, buffer, alloc);
 }
 
 int security_inode_setsecurity(struct inode *inode, const char *name, const void *value, size_t size, int flags)
index be6de0b8734fd9eb950d8f8ca9e2306621764420..e5ed07510309edb0da10a151095cd3529bf41442 100644 (file)
@@ -136,32 +136,6 @@ static DEFINE_SPINLOCK(sb_security_lock);
 
 static struct kmem_cache *sel_inode_cache;
 
-/* Return security context for a given sid or just the context 
-   length if the buffer is null or length is 0 */
-static int selinux_getsecurity(u32 sid, void *buffer, size_t size)
-{
-       char *context;
-       unsigned len;
-       int rc;
-
-       rc = security_sid_to_context(sid, &context, &len);
-       if (rc)
-               return rc;
-
-       if (!buffer || !size)
-               goto getsecurity_exit;
-
-       if (size < len) {
-               len = -ERANGE;
-               goto getsecurity_exit;
-       }
-       memcpy(buffer, context, len);
-
-getsecurity_exit:
-       kfree(context);
-       return len;
-}
-
 /**
  * selinux_secmark_enabled - Check to see if SECMARK is currently enabled
  *
@@ -2675,14 +2649,27 @@ static int selinux_inode_removexattr (struct dentry *dentry, char *name)
  *
  * Permission check is handled by selinux_inode_getxattr hook.
  */
-static int selinux_inode_getsecurity(const struct inode *inode, const char *name, void *buffer, size_t size, int err)
+static int selinux_inode_getsecurity(const struct inode *inode, const char *name, void **buffer, bool alloc)
 {
+       u32 size;
+       int error;
+       char *context = NULL;
        struct inode_security_struct *isec = inode->i_security;
 
        if (strcmp(name, XATTR_SELINUX_SUFFIX))
                return -EOPNOTSUPP;
 
-       return selinux_getsecurity(isec->sid, buffer, size);
+       error = security_sid_to_context(isec->sid, &context, &size);
+       if (error)
+               return error;
+       error = size;
+       if (alloc) {
+               *buffer = context;
+               goto out_nofree;
+       }
+       kfree(context);
+out_nofree:
+       return error;
 }
 
 static int selinux_inode_setsecurity(struct inode *inode, const char *name,
index a85740530afc676fdb777c88a8cb4136d90370cd..0341567665b3b32eab4ac7bfa717c5c0ec00d908 100644 (file)
@@ -172,9 +172,10 @@ static ssize_t sel_write_enforce(struct file * file, const char __user * buf,
                if (length)
                        goto out;
                audit_log(current->audit_context, GFP_KERNEL, AUDIT_MAC_STATUS,
-                       "enforcing=%d old_enforcing=%d auid=%u", new_value, 
-                       selinux_enforcing,
-                       audit_get_loginuid(current->audit_context));
+                       "enforcing=%d old_enforcing=%d auid=%u ses=%u",
+                       new_value, selinux_enforcing,
+                       audit_get_loginuid(current),
+                       audit_get_sessionid(current));
                selinux_enforcing = new_value;
                if (selinux_enforcing)
                        avc_ss_reset(0);
@@ -243,8 +244,9 @@ static ssize_t sel_write_disable(struct file * file, const char __user * buf,
                if (length < 0)
                        goto out;
                audit_log(current->audit_context, GFP_KERNEL, AUDIT_MAC_STATUS,
-                       "selinux=0 auid=%u",
-                       audit_get_loginuid(current->audit_context));
+                       "selinux=0 auid=%u ses=%u",
+                       audit_get_loginuid(current),
+                       audit_get_sessionid(current));
        }
 
        length = count;
@@ -356,8 +358,9 @@ out1:
                (security_get_allow_unknown() ? "allow" : "deny")));
 
        audit_log(current->audit_context, GFP_KERNEL, AUDIT_MAC_POLICY_LOAD,
-               "policy loaded auid=%u",
-               audit_get_loginuid(current->audit_context));
+               "policy loaded auid=%u ses=%u",
+               audit_get_loginuid(current),
+               audit_get_sessionid(current));
 out:
        mutex_unlock(&sel_mutex);
        vfree(data);
index f96dec1f9258f31c88525543c59d586354619649..fced6bccee760b87d98df5b0a26133b6ae0b655c 100644 (file)
@@ -1905,11 +1905,12 @@ int security_set_bools(int len, int *values)
                if (!!values[i] != policydb.bool_val_to_struct[i]->state) {
                        audit_log(current->audit_context, GFP_ATOMIC,
                                AUDIT_MAC_CONFIG_CHANGE,
-                               "bool=%s val=%d old_val=%d auid=%u",
+                               "bool=%s val=%d old_val=%d auid=%u ses=%u",
                                policydb.p_bool_val_to_name[i],
                                !!values[i],
                                policydb.bool_val_to_struct[i]->state,
-                               audit_get_loginuid(current->audit_context));
+                               audit_get_loginuid(current),
+                               audit_get_sessionid(current));
                }
                if (values[i]) {
                        policydb.bool_val_to_struct[i]->state = 1;
@@ -2692,7 +2693,6 @@ int security_netlbl_sid_to_secattr(u32 sid, struct netlbl_lsm_secattr *secattr)
 
 netlbl_sid_to_secattr_failure:
        POLICY_RDUNLOCK;
-       netlbl_secattr_destroy(secattr);
        return rc;
 }
 #endif /* CONFIG_NETLABEL */
diff --git a/security/smack/Kconfig b/security/smack/Kconfig
new file mode 100644 (file)
index 0000000..603b087
--- /dev/null
@@ -0,0 +1,10 @@
+config SECURITY_SMACK
+       bool "Simplified Mandatory Access Control Kernel Support"
+       depends on NETLABEL && SECURITY_NETWORK
+       default n
+       help
+         This selects the Simplified Mandatory Access Control Kernel.
+         Smack is useful for sensitivity, integrity, and a variety
+         of other mandatory security schemes.
+         If you are unsure how to answer this question, answer N.
+
diff --git a/security/smack/Makefile b/security/smack/Makefile
new file mode 100644 (file)
index 0000000..67a63aa
--- /dev/null
@@ -0,0 +1,7 @@
+#
+# Makefile for the SMACK LSM
+#
+
+obj-$(CONFIG_SECURITY_SMACK) := smack.o
+
+smack-y := smack_lsm.o smack_access.o smackfs.o
diff --git a/security/smack/smack.h b/security/smack/smack.h
new file mode 100644 (file)
index 0000000..a21a0e9
--- /dev/null
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 2007 Casey Schaufler <casey@schaufler-ca.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.
+ *
+ * Author:
+ *      Casey Schaufler <casey@schaufler-ca.com>
+ *
+ */
+
+#ifndef _SECURITY_SMACK_H
+#define _SECURITY_SMACK_H
+
+#include <linux/capability.h>
+#include <linux/spinlock.h>
+#include <net/netlabel.h>
+
+/*
+ * Why 23? CIPSO is constrained to 30, so a 32 byte buffer is
+ * bigger than can be used, and 24 is the next lower multiple
+ * of 8, and there are too many issues if there isn't space set
+ * aside for the terminating null byte.
+ */
+#define SMK_MAXLEN     23
+#define SMK_LABELLEN   (SMK_MAXLEN+1)
+
+/*
+ * How many kinds of access are there?
+ * Here's your answer.
+ */
+#define SMK_ACCESSDASH '-'
+#define SMK_ACCESSLOW  "rwxa"
+#define SMK_ACCESSKINDS        (sizeof(SMK_ACCESSLOW) - 1)
+
+struct superblock_smack {
+       char            *smk_root;
+       char            *smk_floor;
+       char            *smk_hat;
+       char            *smk_default;
+       int             smk_initialized;
+       spinlock_t      smk_sblock;     /* for initialization */
+};
+
+struct socket_smack {
+       char            *smk_out;                       /* outbound label */
+       char            *smk_in;                        /* inbound label */
+       char            smk_packet[SMK_LABELLEN];       /* TCP peer label */
+};
+
+/*
+ * Inode smack data
+ */
+struct inode_smack {
+       char            *smk_inode;     /* label of the fso */
+       struct mutex    smk_lock;       /* initialization lock */
+       int             smk_flags;      /* smack inode flags */
+};
+
+#define        SMK_INODE_INSTANT       0x01    /* inode is instantiated */
+
+/*
+ * A label access rule.
+ */
+struct smack_rule {
+       char    *smk_subject;
+       char    *smk_object;
+       int     smk_access;
+};
+
+/*
+ * An entry in the table of permitted label accesses.
+ */
+struct smk_list_entry {
+       struct smk_list_entry   *smk_next;
+       struct smack_rule       smk_rule;
+};
+
+/*
+ * An entry in the table mapping smack values to
+ * CIPSO level/category-set values.
+ */
+struct smack_cipso {
+       int     smk_level;
+       char    smk_catset[SMK_LABELLEN];
+};
+
+/*
+ * This is the repository for labels seen so that it is
+ * not necessary to keep allocating tiny chuncks of memory
+ * and so that they can be shared.
+ *
+ * Labels are never modified in place. Anytime a label
+ * is imported (e.g. xattrset on a file) the list is checked
+ * for it and it is added if it doesn't exist. The address
+ * is passed out in either case. Entries are added, but
+ * never deleted.
+ *
+ * Since labels are hanging around anyway it doesn't
+ * hurt to maintain a secid for those awkward situations
+ * where kernel components that ought to use LSM independent
+ * interfaces don't. The secid should go away when all of
+ * these components have been repaired.
+ *
+ * If there is a cipso value associated with the label it
+ * gets stored here, too. This will most likely be rare as
+ * the cipso direct mapping in used internally.
+ */
+struct smack_known {
+       struct smack_known      *smk_next;
+       char                    smk_known[SMK_LABELLEN];
+       u32                     smk_secid;
+       struct smack_cipso      *smk_cipso;
+       spinlock_t              smk_cipsolock; /* for changing cipso map */
+};
+
+/*
+ * Mount options
+ */
+#define SMK_FSDEFAULT  "smackfsdef="
+#define SMK_FSFLOOR    "smackfsfloor="
+#define SMK_FSHAT      "smackfshat="
+#define SMK_FSROOT     "smackfsroot="
+
+/*
+ * xattr names
+ */
+#define XATTR_SMACK_SUFFIX     "SMACK64"
+#define XATTR_SMACK_IPIN       "SMACK64IPIN"
+#define XATTR_SMACK_IPOUT      "SMACK64IPOUT"
+#define XATTR_NAME_SMACK       XATTR_SECURITY_PREFIX XATTR_SMACK_SUFFIX
+#define XATTR_NAME_SMACKIPIN   XATTR_SECURITY_PREFIX XATTR_SMACK_IPIN
+#define XATTR_NAME_SMACKIPOUT  XATTR_SECURITY_PREFIX XATTR_SMACK_IPOUT
+
+/*
+ * smackfs macic number
+ */
+#define SMACK_MAGIC    0x43415d53 /* "SMAC" */
+
+/*
+ * A limit on the number of entries in the lists
+ * makes some of the list administration easier.
+ */
+#define SMACK_LIST_MAX 10000
+
+/*
+ * CIPSO defaults.
+ */
+#define SMACK_CIPSO_DOI_DEFAULT                3       /* Historical */
+#define SMACK_CIPSO_DIRECT_DEFAULT     250     /* Arbitrary */
+#define SMACK_CIPSO_MAXCATVAL          63      /* Bigger gets harder */
+#define SMACK_CIPSO_MAXLEVEL            255     /* CIPSO 2.2 standard */
+#define SMACK_CIPSO_MAXCATNUM           239     /* CIPSO 2.2 standard */
+
+/*
+ * Just to make the common cases easier to deal with
+ */
+#define MAY_ANY                (MAY_READ | MAY_WRITE | MAY_APPEND | MAY_EXEC)
+#define MAY_ANYREAD    (MAY_READ | MAY_EXEC)
+#define MAY_ANYWRITE   (MAY_WRITE | MAY_APPEND)
+#define MAY_READWRITE  (MAY_READ | MAY_WRITE)
+#define MAY_NOT                0
+
+/*
+ * These functions are in smack_lsm.c
+ */
+struct inode_smack *new_inode_smack(char *);
+
+/*
+ * These functions are in smack_access.c
+ */
+int smk_access(char *, char *, int);
+int smk_curacc(char *, u32);
+int smack_to_cipso(const char *, struct smack_cipso *);
+void smack_from_cipso(u32, char *, char *);
+char *smack_from_secid(const u32);
+char *smk_import(const char *, int);
+struct smack_known *smk_import_entry(const char *, int);
+u32 smack_to_secid(const char *);
+
+/*
+ * Shared data.
+ */
+extern int smack_cipso_direct;
+extern int smack_net_nltype;
+extern char *smack_net_ambient;
+
+extern struct smack_known *smack_known;
+extern struct smack_known smack_known_floor;
+extern struct smack_known smack_known_hat;
+extern struct smack_known smack_known_huh;
+extern struct smack_known smack_known_invalid;
+extern struct smack_known smack_known_star;
+extern struct smack_known smack_known_unset;
+
+extern struct smk_list_entry *smack_list;
+
+/*
+ * Stricly for CIPSO level manipulation.
+ * Set the category bit number in a smack label sized buffer.
+ */
+static inline void smack_catset_bit(int cat, char *catsetp)
+{
+       if (cat > SMK_LABELLEN * 8)
+               return;
+
+       catsetp[(cat - 1) / 8] |= 0x80 >> ((cat - 1) % 8);
+}
+
+/*
+ * Present a pointer to the smack label in an inode blob.
+ */
+static inline char *smk_of_inode(const struct inode *isp)
+{
+       struct inode_smack *sip = isp->i_security;
+       return sip->smk_inode;
+}
+
+#endif  /* _SECURITY_SMACK_H */
diff --git a/security/smack/smack_access.c b/security/smack/smack_access.c
new file mode 100644 (file)
index 0000000..f6b5f6e
--- /dev/null
@@ -0,0 +1,356 @@
+/*
+ * Copyright (C) 2007 Casey Schaufler <casey@schaufler-ca.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.
+ *
+ * Author:
+ *      Casey Schaufler <casey@schaufler-ca.com>
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/sched.h>
+#include "smack.h"
+
+struct smack_known smack_known_unset = {
+       .smk_next       = NULL,
+       .smk_known      = "UNSET",
+       .smk_secid      = 1,
+       .smk_cipso      = NULL,
+};
+
+struct smack_known smack_known_huh = {
+       .smk_next       = &smack_known_unset,
+       .smk_known      = "?",
+       .smk_secid      = 2,
+       .smk_cipso      = NULL,
+};
+
+struct smack_known smack_known_hat = {
+       .smk_next       = &smack_known_huh,
+       .smk_known      = "^",
+       .smk_secid      = 3,
+       .smk_cipso      = NULL,
+};
+
+struct smack_known smack_known_star = {
+       .smk_next       = &smack_known_hat,
+       .smk_known      = "*",
+       .smk_secid      = 4,
+       .smk_cipso      = NULL,
+};
+
+struct smack_known smack_known_floor = {
+       .smk_next       = &smack_known_star,
+       .smk_known      = "_",
+       .smk_secid      = 5,
+       .smk_cipso      = NULL,
+};
+
+struct smack_known smack_known_invalid = {
+       .smk_next       = &smack_known_floor,
+       .smk_known      = "",
+       .smk_secid      = 6,
+       .smk_cipso      = NULL,
+};
+
+struct smack_known *smack_known = &smack_known_invalid;
+
+/*
+ * The initial value needs to be bigger than any of the
+ * known values above.
+ */
+static u32 smack_next_secid = 10;
+
+/**
+ * smk_access - determine if a subject has a specific access to an object
+ * @subject_label: a pointer to the subject's Smack label
+ * @object_label: a pointer to the object's Smack label
+ * @request: the access requested, in "MAY" format
+ *
+ * This function looks up the subject/object pair in the
+ * access rule list and returns 0 if the access is permitted,
+ * non zero otherwise.
+ *
+ * Even though Smack labels are usually shared on smack_list
+ * labels that come in off the network can't be imported
+ * and added to the list for locking reasons.
+ *
+ * Therefore, it is necessary to check the contents of the labels,
+ * not just the pointer values. Of course, in most cases the labels
+ * will be on the list, so checking the pointers may be a worthwhile
+ * optimization.
+ */
+int smk_access(char *subject_label, char *object_label, int request)
+{
+       u32 may = MAY_NOT;
+       struct smk_list_entry *sp;
+       struct smack_rule *srp;
+
+       /*
+        * Hardcoded comparisons.
+        *
+        * A star subject can't access any object.
+        */
+       if (subject_label == smack_known_star.smk_known ||
+           strcmp(subject_label, smack_known_star.smk_known) == 0)
+               return -EACCES;
+       /*
+        * A star object can be accessed by any subject.
+        */
+       if (object_label == smack_known_star.smk_known ||
+           strcmp(object_label, smack_known_star.smk_known) == 0)
+               return 0;
+       /*
+        * An object can be accessed in any way by a subject
+        * with the same label.
+        */
+       if (subject_label == object_label ||
+           strcmp(subject_label, object_label) == 0)
+               return 0;
+       /*
+        * A hat subject can read any object.
+        * A floor object can be read by any subject.
+        */
+       if ((request & MAY_ANYREAD) == request) {
+               if (object_label == smack_known_floor.smk_known ||
+                   strcmp(object_label, smack_known_floor.smk_known) == 0)
+                       return 0;
+               if (subject_label == smack_known_hat.smk_known ||
+                   strcmp(subject_label, smack_known_hat.smk_known) == 0)
+                       return 0;
+       }
+       /*
+        * Beyond here an explicit relationship is required.
+        * If the requested access is contained in the available
+        * access (e.g. read is included in readwrite) it's
+        * good.
+        */
+       for (sp = smack_list; sp != NULL; sp = sp->smk_next) {
+               srp = &sp->smk_rule;
+
+               if (srp->smk_subject == subject_label ||
+                   strcmp(srp->smk_subject, subject_label) == 0) {
+                       if (srp->smk_object == object_label ||
+                           strcmp(srp->smk_object, object_label) == 0) {
+                               may = srp->smk_access;
+                               break;
+                       }
+               }
+       }
+       /*
+        * This is a bit map operation.
+        */
+       if ((request & may) == request)
+               return 0;
+
+       return -EACCES;
+}
+
+/**
+ * smk_curacc - determine if current has a specific access to an object
+ * @object_label: a pointer to the object's Smack label
+ * @request: the access requested, in "MAY" format
+ *
+ * This function checks the current subject label/object label pair
+ * in the access rule list and returns 0 if the access is permitted,
+ * non zero otherwise. It allows that current my have the capability
+ * to override the rules.
+ */
+int smk_curacc(char *obj_label, u32 mode)
+{
+       int rc;
+
+       rc = smk_access(current->security, obj_label, mode);
+       if (rc == 0)
+               return 0;
+
+       if (capable(CAP_MAC_OVERRIDE))
+               return 0;
+
+       return rc;
+}
+
+static DEFINE_MUTEX(smack_known_lock);
+
+/**
+ * smk_import_entry - import a label, return the list entry
+ * @string: a text string that might be a Smack label
+ * @len: the maximum size, or zero if it is NULL terminated.
+ *
+ * Returns a pointer to the entry in the label list that
+ * matches the passed string, adding it if necessary.
+ */
+struct smack_known *smk_import_entry(const char *string, int len)
+{
+       struct smack_known *skp;
+       char smack[SMK_LABELLEN];
+       int found;
+       int i;
+
+       if (len <= 0 || len > SMK_MAXLEN)
+               len = SMK_MAXLEN;
+
+       for (i = 0, found = 0; i < SMK_LABELLEN; i++) {
+               if (found)
+                       smack[i] = '\0';
+               else if (i >= len || string[i] > '~' || string[i] <= ' ' ||
+                        string[i] == '/') {
+                       smack[i] = '\0';
+                       found = 1;
+               } else
+                       smack[i] = string[i];
+       }
+
+       if (smack[0] == '\0')
+               return NULL;
+
+       mutex_lock(&smack_known_lock);
+
+       for (skp = smack_known; skp != NULL; skp = skp->smk_next)
+               if (strncmp(skp->smk_known, smack, SMK_MAXLEN) == 0)
+                       break;
+
+       if (skp == NULL) {
+               skp = kzalloc(sizeof(struct smack_known), GFP_KERNEL);
+               if (skp != NULL) {
+                       skp->smk_next = smack_known;
+                       strncpy(skp->smk_known, smack, SMK_MAXLEN);
+                       skp->smk_secid = smack_next_secid++;
+                       skp->smk_cipso = NULL;
+                       spin_lock_init(&skp->smk_cipsolock);
+                       /*
+                        * Make sure that the entry is actually
+                        * filled before putting it on the list.
+                        */
+                       smp_mb();
+                       smack_known = skp;
+               }
+       }
+
+       mutex_unlock(&smack_known_lock);
+
+       return skp;
+}
+
+/**
+ * smk_import - import a smack label
+ * @string: a text string that might be a Smack label
+ * @len: the maximum size, or zero if it is NULL terminated.
+ *
+ * Returns a pointer to the label in the label list that
+ * matches the passed string, adding it if necessary.
+ */
+char *smk_import(const char *string, int len)
+{
+       struct smack_known *skp;
+
+       skp = smk_import_entry(string, len);
+       if (skp == NULL)
+               return NULL;
+       return skp->smk_known;
+}
+
+/**
+ * smack_from_secid - find the Smack label associated with a secid
+ * @secid: an integer that might be associated with a Smack label
+ *
+ * Returns a pointer to the appropraite Smack label if there is one,
+ * otherwise a pointer to the invalid Smack label.
+ */
+char *smack_from_secid(const u32 secid)
+{
+       struct smack_known *skp;
+
+       for (skp = smack_known; skp != NULL; skp = skp->smk_next)
+               if (skp->smk_secid == secid)
+                       return skp->smk_known;
+
+       /*
+        * If we got this far someone asked for the translation
+        * of a secid that is not on the list.
+        */
+       return smack_known_invalid.smk_known;
+}
+
+/**
+ * smack_to_secid - find the secid associated with a Smack label
+ * @smack: the Smack label
+ *
+ * Returns the appropriate secid if there is one,
+ * otherwise 0
+ */
+u32 smack_to_secid(const char *smack)
+{
+       struct smack_known *skp;
+
+       for (skp = smack_known; skp != NULL; skp = skp->smk_next)
+               if (strncmp(skp->smk_known, smack, SMK_MAXLEN) == 0)
+                       return skp->smk_secid;
+       return 0;
+}
+
+/**
+ * smack_from_cipso - find the Smack label associated with a CIPSO option
+ * @level: Bell & LaPadula level from the network
+ * @cp: Bell & LaPadula categories from the network
+ * @result: where to put the Smack value
+ *
+ * This is a simple lookup in the label table.
+ *
+ * This is an odd duck as far as smack handling goes in that
+ * it sends back a copy of the smack label rather than a pointer
+ * to the master list. This is done because it is possible for
+ * a foreign host to send a smack label that is new to this
+ * machine and hence not on the list. That would not be an
+ * issue except that adding an entry to the master list can't
+ * be done at that point.
+ */
+void smack_from_cipso(u32 level, char *cp, char *result)
+{
+       struct smack_known *kp;
+       char *final = NULL;
+
+       for (kp = smack_known; final == NULL && kp != NULL; kp = kp->smk_next) {
+               if (kp->smk_cipso == NULL)
+                       continue;
+
+               spin_lock_bh(&kp->smk_cipsolock);
+
+               if (kp->smk_cipso->smk_level == level &&
+                   memcmp(kp->smk_cipso->smk_catset, cp, SMK_LABELLEN) == 0)
+                       final = kp->smk_known;
+
+               spin_unlock_bh(&kp->smk_cipsolock);
+       }
+       if (final == NULL)
+               final = smack_known_huh.smk_known;
+       strncpy(result, final, SMK_MAXLEN);
+       return;
+}
+
+/**
+ * smack_to_cipso - find the CIPSO option to go with a Smack label
+ * @smack: a pointer to the smack label in question
+ * @cp: where to put the result
+ *
+ * Returns zero if a value is available, non-zero otherwise.
+ */
+int smack_to_cipso(const char *smack, struct smack_cipso *cp)
+{
+       struct smack_known *kp;
+
+       for (kp = smack_known; kp != NULL; kp = kp->smk_next)
+               if (kp->smk_known == smack ||
+                   strcmp(kp->smk_known, smack) == 0)
+                       break;
+
+       if (kp == NULL || kp->smk_cipso == NULL)
+               return -ENOENT;
+
+       memcpy(cp, kp->smk_cipso, sizeof(struct smack_cipso));
+       return 0;
+}
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
new file mode 100644 (file)
index 0000000..1c11e42
--- /dev/null
@@ -0,0 +1,2518 @@
+/*
+ *  Simplified MAC Kernel (smack) security module
+ *
+ *  This file contains the smack hook function implementations.
+ *
+ *  Author:
+ *     Casey Schaufler <casey@schaufler-ca.com>
+ *
+ *  Copyright (C) 2007 Casey Schaufler <casey@schaufler-ca.com>
+ *
+ *     This program is free software; you can redistribute it and/or modify
+ *     it under the terms of the GNU General Public License version 2,
+ *      as published by the Free Software Foundation.
+ */
+
+#include <linux/xattr.h>
+#include <linux/pagemap.h>
+#include <linux/mount.h>
+#include <linux/stat.h>
+#include <linux/ext2_fs.h>
+#include <linux/kd.h>
+#include <asm/ioctls.h>
+#include <linux/tcp.h>
+#include <linux/udp.h>
+#include <linux/mutex.h>
+#include <linux/pipe_fs_i.h>
+#include <net/netlabel.h>
+#include <net/cipso_ipv4.h>
+
+#include "smack.h"
+
+/*
+ * I hope these are the hokeyist lines of code in the module. Casey.
+ */
+#define DEVPTS_SUPER_MAGIC     0x1cd1
+#define SOCKFS_MAGIC           0x534F434B
+#define TMPFS_MAGIC            0x01021994
+
+/**
+ * smk_fetch - Fetch the smack label from a file.
+ * @ip: a pointer to the inode
+ * @dp: a pointer to the dentry
+ *
+ * Returns a pointer to the master list entry for the Smack label
+ * or NULL if there was no label to fetch.
+ */
+static char *smk_fetch(struct inode *ip, struct dentry *dp)
+{
+       int rc;
+       char in[SMK_LABELLEN];
+
+       if (ip->i_op->getxattr == NULL)
+               return NULL;
+
+       rc = ip->i_op->getxattr(dp, XATTR_NAME_SMACK, in, SMK_LABELLEN);
+       if (rc < 0)
+               return NULL;
+
+       return smk_import(in, rc);
+}
+
+/**
+ * new_inode_smack - allocate an inode security blob
+ * @smack: a pointer to the Smack label to use in the blob
+ *
+ * Returns the new blob or NULL if there's no memory available
+ */
+struct inode_smack *new_inode_smack(char *smack)
+{
+       struct inode_smack *isp;
+
+       isp = kzalloc(sizeof(struct inode_smack), GFP_KERNEL);
+       if (isp == NULL)
+               return NULL;
+
+       isp->smk_inode = smack;
+       isp->smk_flags = 0;
+       mutex_init(&isp->smk_lock);
+
+       return isp;
+}
+
+/*
+ * LSM hooks.
+ * We he, that is fun!
+ */
+
+/**
+ * smack_ptrace - Smack approval on ptrace
+ * @ptp: parent task pointer
+ * @ctp: child task pointer
+ *
+ * Returns 0 if access is OK, an error code otherwise
+ *
+ * Do the capability checks, and require read and write.
+ */
+static int smack_ptrace(struct task_struct *ptp, struct task_struct *ctp)
+{
+       int rc;
+
+       rc = cap_ptrace(ptp, ctp);
+       if (rc != 0)
+               return rc;
+
+       rc = smk_access(ptp->security, ctp->security, MAY_READWRITE);
+       if (rc != 0 && __capable(ptp, CAP_MAC_OVERRIDE))
+               return 0;
+
+       return rc;
+}
+
+/**
+ * smack_syslog - Smack approval on syslog
+ * @type: message type
+ *
+ * Require that the task has the floor label
+ *
+ * Returns 0 on success, error code otherwise.
+ */
+static int smack_syslog(int type)
+{
+       int rc;
+       char *sp = current->security;
+
+       rc = cap_syslog(type);
+       if (rc != 0)
+               return rc;
+
+       if (capable(CAP_MAC_OVERRIDE))
+               return 0;
+
+        if (sp != smack_known_floor.smk_known)
+               rc = -EACCES;
+
+       return rc;
+}
+
+
+/*
+ * Superblock Hooks.
+ */
+
+/**
+ * smack_sb_alloc_security - allocate a superblock blob
+ * @sb: the superblock getting the blob
+ *
+ * Returns 0 on success or -ENOMEM on error.
+ */
+static int smack_sb_alloc_security(struct super_block *sb)
+{
+       struct superblock_smack *sbsp;
+
+       sbsp = kzalloc(sizeof(struct superblock_smack), GFP_KERNEL);
+
+       if (sbsp == NULL)
+               return -ENOMEM;
+
+       sbsp->smk_root = smack_known_floor.smk_known;
+       sbsp->smk_default = smack_known_floor.smk_known;
+       sbsp->smk_floor = smack_known_floor.smk_known;
+       sbsp->smk_hat = smack_known_hat.smk_known;
+       sbsp->smk_initialized = 0;
+       spin_lock_init(&sbsp->smk_sblock);
+
+       sb->s_security = sbsp;
+
+       return 0;
+}
+
+/**
+ * smack_sb_free_security - free a superblock blob
+ * @sb: the superblock getting the blob
+ *
+ */
+static void smack_sb_free_security(struct super_block *sb)
+{
+       kfree(sb->s_security);
+       sb->s_security = NULL;
+}
+
+/**
+ * smack_sb_copy_data - copy mount options data for processing
+ * @type: file system type
+ * @orig: where to start
+ * @smackopts
+ *
+ * Returns 0 on success or -ENOMEM on error.
+ *
+ * Copy the Smack specific mount options out of the mount
+ * options list.
+ */
+static int smack_sb_copy_data(struct file_system_type *type, void *orig,
+                             void *smackopts)
+{
+       char *cp, *commap, *otheropts, *dp;
+
+       /* Binary mount data: just copy */
+       if (type->fs_flags & FS_BINARY_MOUNTDATA) {
+               copy_page(smackopts, orig);
+               return 0;
+       }
+
+       otheropts = (char *)get_zeroed_page(GFP_KERNEL);
+       if (otheropts == NULL)
+               return -ENOMEM;
+
+       for (cp = orig, commap = orig; commap != NULL; cp = commap + 1) {
+               if (strstr(cp, SMK_FSDEFAULT) == cp)
+                       dp = smackopts;
+               else if (strstr(cp, SMK_FSFLOOR) == cp)
+                       dp = smackopts;
+               else if (strstr(cp, SMK_FSHAT) == cp)
+                       dp = smackopts;
+               else if (strstr(cp, SMK_FSROOT) == cp)
+                       dp = smackopts;
+               else
+                       dp = otheropts;
+
+               commap = strchr(cp, ',');
+               if (commap != NULL)
+                       *commap = '\0';
+
+               if (*dp != '\0')
+                       strcat(dp, ",");
+               strcat(dp, cp);
+       }
+
+       strcpy(orig, otheropts);
+       free_page((unsigned long)otheropts);
+
+       return 0;
+}
+
+/**
+ * smack_sb_kern_mount - Smack specific mount processing
+ * @sb: the file system superblock
+ * @data: the smack mount options
+ *
+ * Returns 0 on success, an error code on failure
+ */
+static int smack_sb_kern_mount(struct super_block *sb, void *data)
+{
+       struct dentry *root = sb->s_root;
+       struct inode *inode = root->d_inode;
+       struct superblock_smack *sp = sb->s_security;
+       struct inode_smack *isp;
+       char *op;
+       char *commap;
+       char *nsp;
+
+       spin_lock(&sp->smk_sblock);
+       if (sp->smk_initialized != 0) {
+               spin_unlock(&sp->smk_sblock);
+               return 0;
+       }
+       sp->smk_initialized = 1;
+       spin_unlock(&sp->smk_sblock);
+
+       for (op = data; op != NULL; op = commap) {
+               commap = strchr(op, ',');
+               if (commap != NULL)
+                       *commap++ = '\0';
+
+               if (strncmp(op, SMK_FSHAT, strlen(SMK_FSHAT)) == 0) {
+                       op += strlen(SMK_FSHAT);
+                       nsp = smk_import(op, 0);
+                       if (nsp != NULL)
+                               sp->smk_hat = nsp;
+               } else if (strncmp(op, SMK_FSFLOOR, strlen(SMK_FSFLOOR)) == 0) {
+                       op += strlen(SMK_FSFLOOR);
+                       nsp = smk_import(op, 0);
+                       if (nsp != NULL)
+                               sp->smk_floor = nsp;
+               } else if (strncmp(op, SMK_FSDEFAULT,
+                                  strlen(SMK_FSDEFAULT)) == 0) {
+                       op += strlen(SMK_FSDEFAULT);
+                       nsp = smk_import(op, 0);
+                       if (nsp != NULL)
+                               sp->smk_default = nsp;
+               } else if (strncmp(op, SMK_FSROOT, strlen(SMK_FSROOT)) == 0) {
+                       op += strlen(SMK_FSROOT);
+                       nsp = smk_import(op, 0);
+                       if (nsp != NULL)
+                               sp->smk_root = nsp;
+               }
+       }
+
+       /*
+        * Initialize the root inode.
+        */
+       isp = inode->i_security;
+       if (isp == NULL)
+               inode->i_security = new_inode_smack(sp->smk_root);
+       else
+               isp->smk_inode = sp->smk_root;
+
+       return 0;
+}
+
+/**
+ * smack_sb_statfs - Smack check on statfs
+ * @dentry: identifies the file system in question
+ *
+ * Returns 0 if current can read the floor of the filesystem,
+ * and error code otherwise
+ */
+static int smack_sb_statfs(struct dentry *dentry)
+{
+       struct superblock_smack *sbp = dentry->d_sb->s_security;
+
+       return smk_curacc(sbp->smk_floor, MAY_READ);
+}
+
+/**
+ * smack_sb_mount - Smack check for mounting
+ * @dev_name: unused
+ * @nd: mount point
+ * @type: unused
+ * @flags: unused
+ * @data: unused
+ *
+ * Returns 0 if current can write the floor of the filesystem
+ * being mounted on, an error code otherwise.
+ */
+static int smack_sb_mount(char *dev_name, struct nameidata *nd,
+                         char *type, unsigned long flags, void *data)
+{
+       struct superblock_smack *sbp = nd->mnt->mnt_sb->s_security;
+
+       return smk_curacc(sbp->smk_floor, MAY_WRITE);
+}
+
+/**
+ * smack_sb_umount - Smack check for unmounting
+ * @mnt: file system to unmount
+ * @flags: unused
+ *
+ * Returns 0 if current can write the floor of the filesystem
+ * being unmounted, an error code otherwise.
+ */
+static int smack_sb_umount(struct vfsmount *mnt, int flags)
+{
+       struct superblock_smack *sbp;
+
+       sbp = mnt->mnt_sb->s_security;
+
+       return smk_curacc(sbp->smk_floor, MAY_WRITE);
+}
+
+/*
+ * Inode hooks
+ */
+
+/**
+ * smack_inode_alloc_security - allocate an inode blob
+ * @inode - the inode in need of a blob
+ *
+ * Returns 0 if it gets a blob, -ENOMEM otherwise
+ */
+static int smack_inode_alloc_security(struct inode *inode)
+{
+       inode->i_security = new_inode_smack(current->security);
+       if (inode->i_security == NULL)
+               return -ENOMEM;
+       return 0;
+}
+
+/**
+ * smack_inode_free_security - free an inode blob
+ * @inode - the inode with a blob
+ *
+ * Clears the blob pointer in inode
+ */
+static void smack_inode_free_security(struct inode *inode)
+{
+       kfree(inode->i_security);
+       inode->i_security = NULL;
+}
+
+/**
+ * smack_inode_init_security - copy out the smack from an inode
+ * @inode: the inode
+ * @dir: unused
+ * @name: where to put the attribute name
+ * @value: where to put the attribute value
+ * @len: where to put the length of the attribute
+ *
+ * Returns 0 if it all works out, -ENOMEM if there's no memory
+ */
+static int smack_inode_init_security(struct inode *inode, struct inode *dir,
+                                    char **name, void **value, size_t *len)
+{
+       char *isp = smk_of_inode(inode);
+
+       if (name) {
+               *name = kstrdup(XATTR_SMACK_SUFFIX, GFP_KERNEL);
+               if (*name == NULL)
+                       return -ENOMEM;
+       }
+
+       if (value) {
+               *value = kstrdup(isp, GFP_KERNEL);
+               if (*value == NULL)
+                       return -ENOMEM;
+       }
+
+       if (len)
+               *len = strlen(isp) + 1;
+
+       return 0;
+}
+
+/**
+ * smack_inode_link - Smack check on link
+ * @old_dentry: the existing object
+ * @dir: unused
+ * @new_dentry: the new object
+ *
+ * Returns 0 if access is permitted, an error code otherwise
+ */
+static int smack_inode_link(struct dentry *old_dentry, struct inode *dir,
+                           struct dentry *new_dentry)
+{
+       int rc;
+       char *isp;
+
+       isp = smk_of_inode(old_dentry->d_inode);
+       rc = smk_curacc(isp, MAY_WRITE);
+
+       if (rc == 0 && new_dentry->d_inode != NULL) {
+               isp = smk_of_inode(new_dentry->d_inode);
+               rc = smk_curacc(isp, MAY_WRITE);
+       }
+
+       return rc;
+}
+
+/**
+ * smack_inode_unlink - Smack check on inode deletion
+ * @dir: containing directory object
+ * @dentry: file to unlink
+ *
+ * Returns 0 if current can write the containing directory
+ * and the object, error code otherwise
+ */
+static int smack_inode_unlink(struct inode *dir, struct dentry *dentry)
+{
+       struct inode *ip = dentry->d_inode;
+       int rc;
+
+       /*
+        * You need write access to the thing you're unlinking
+        */
+       rc = smk_curacc(smk_of_inode(ip), MAY_WRITE);
+       if (rc == 0)
+               /*
+                * You also need write access to the containing directory
+                */
+               rc = smk_curacc(smk_of_inode(dir), MAY_WRITE);
+
+       return rc;
+}
+
+/**
+ * smack_inode_rmdir - Smack check on directory deletion
+ * @dir: containing directory object
+ * @dentry: directory to unlink
+ *
+ * Returns 0 if current can write the containing directory
+ * and the directory, error code otherwise
+ */
+static int smack_inode_rmdir(struct inode *dir, struct dentry *dentry)
+{
+       int rc;
+
+       /*
+        * You need write access to the thing you're removing
+        */
+       rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE);
+       if (rc == 0)
+               /*
+                * You also need write access to the containing directory
+                */
+               rc = smk_curacc(smk_of_inode(dir), MAY_WRITE);
+
+       return rc;
+}
+
+/**
+ * smack_inode_rename - Smack check on rename
+ * @old_inode: the old directory
+ * @old_dentry: unused
+ * @new_inode: the new directory
+ * @new_dentry: unused
+ *
+ * Read and write access is required on both the old and
+ * new directories.
+ *
+ * Returns 0 if access is permitted, an error code otherwise
+ */
+static int smack_inode_rename(struct inode *old_inode,
+                             struct dentry *old_dentry,
+                             struct inode *new_inode,
+                             struct dentry *new_dentry)
+{
+       int rc;
+       char *isp;
+
+       isp = smk_of_inode(old_dentry->d_inode);
+       rc = smk_curacc(isp, MAY_READWRITE);
+
+       if (rc == 0 && new_dentry->d_inode != NULL) {
+               isp = smk_of_inode(new_dentry->d_inode);
+               rc = smk_curacc(isp, MAY_READWRITE);
+       }
+
+       return rc;
+}
+
+/**
+ * smack_inode_permission - Smack version of permission()
+ * @inode: the inode in question
+ * @mask: the access requested
+ * @nd: unused
+ *
+ * This is the important Smack hook.
+ *
+ * Returns 0 if access is permitted, -EACCES otherwise
+ */
+static int smack_inode_permission(struct inode *inode, int mask,
+                                 struct nameidata *nd)
+{
+       /*
+        * No permission to check. Existence test. Yup, it's there.
+        */
+       if (mask == 0)
+               return 0;
+
+       return smk_curacc(smk_of_inode(inode), mask);
+}
+
+/**
+ * smack_inode_setattr - Smack check for setting attributes
+ * @dentry: the object
+ * @iattr: for the force flag
+ *
+ * Returns 0 if access is permitted, an error code otherwise
+ */
+static int smack_inode_setattr(struct dentry *dentry, struct iattr *iattr)
+{
+       /*
+        * Need to allow for clearing the setuid bit.
+        */
+       if (iattr->ia_valid & ATTR_FORCE)
+               return 0;
+
+       return smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE);
+}
+
+/**
+ * smack_inode_getattr - Smack check for getting attributes
+ * @mnt: unused
+ * @dentry: the object
+ *
+ * Returns 0 if access is permitted, an error code otherwise
+ */
+static int smack_inode_getattr(struct vfsmount *mnt, struct dentry *dentry)
+{
+       return smk_curacc(smk_of_inode(dentry->d_inode), MAY_READ);
+}
+
+/**
+ * smack_inode_setxattr - Smack check for setting xattrs
+ * @dentry: the object
+ * @name: name of the attribute
+ * @value: unused
+ * @size: unused
+ * @flags: unused
+ *
+ * This protects the Smack attribute explicitly.
+ *
+ * Returns 0 if access is permitted, an error code otherwise
+ */
+static int smack_inode_setxattr(struct dentry *dentry, char *name,
+                               void *value, size_t size, int flags)
+{
+       if (!capable(CAP_MAC_ADMIN)) {
+               if (strcmp(name, XATTR_NAME_SMACK) == 0 ||
+                   strcmp(name, XATTR_NAME_SMACKIPIN) == 0 ||
+                   strcmp(name, XATTR_NAME_SMACKIPOUT) == 0)
+                       return -EPERM;
+       }
+
+       return smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE);
+}
+
+/**
+ * smack_inode_post_setxattr - Apply the Smack update approved above
+ * @dentry: object
+ * @name: attribute name
+ * @value: attribute value
+ * @size: attribute size
+ * @flags: unused
+ *
+ * Set the pointer in the inode blob to the entry found
+ * in the master label list.
+ */
+static void smack_inode_post_setxattr(struct dentry *dentry, char *name,
+                                     void *value, size_t size, int flags)
+{
+       struct inode_smack *isp;
+       char *nsp;
+
+       /*
+        * Not SMACK
+        */
+       if (strcmp(name, XATTR_NAME_SMACK))
+               return;
+
+       if (size >= SMK_LABELLEN)
+               return;
+
+       isp = dentry->d_inode->i_security;
+
+       /*
+        * No locking is done here. This is a pointer
+        * assignment.
+        */
+       nsp = smk_import(value, size);
+       if (nsp != NULL)
+               isp->smk_inode = nsp;
+       else
+               isp->smk_inode = smack_known_invalid.smk_known;
+
+       return;
+}
+
+/*
+ * smack_inode_getxattr - Smack check on getxattr
+ * @dentry: the object
+ * @name: unused
+ *
+ * Returns 0 if access is permitted, an error code otherwise
+ */
+static int smack_inode_getxattr(struct dentry *dentry, char *name)
+{
+       return smk_curacc(smk_of_inode(dentry->d_inode), MAY_READ);
+}
+
+/*
+ * smack_inode_removexattr - Smack check on removexattr
+ * @dentry: the object
+ * @name: name of the attribute
+ *
+ * Removing the Smack attribute requires CAP_MAC_ADMIN
+ *
+ * Returns 0 if access is permitted, an error code otherwise
+ */
+static int smack_inode_removexattr(struct dentry *dentry, char *name)
+{
+       if (strcmp(name, XATTR_NAME_SMACK) == 0 && !capable(CAP_MAC_ADMIN))
+               return -EPERM;
+
+       return smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE);
+}
+
+/**
+ * smack_inode_getsecurity - get smack xattrs
+ * @inode: the object
+ * @name: attribute name
+ * @buffer: where to put the result
+ * @size: size of the buffer
+ * @err: unused
+ *
+ * Returns the size of the attribute or an error code
+ */
+static int smack_inode_getsecurity(const struct inode *inode,
+                                  const char *name, void **buffer,
+                                  bool alloc)
+{
+       struct socket_smack *ssp;
+       struct socket *sock;
+       struct super_block *sbp;
+       struct inode *ip = (struct inode *)inode;
+       char *isp;
+       int ilen;
+       int rc = 0;
+
+       if (strcmp(name, XATTR_SMACK_SUFFIX) == 0) {
+               isp = smk_of_inode(inode);
+               ilen = strlen(isp) + 1;
+               *buffer = isp;
+               return ilen;
+       }
+
+       /*
+        * The rest of the Smack xattrs are only on sockets.
+        */
+       sbp = ip->i_sb;
+       if (sbp->s_magic != SOCKFS_MAGIC)
+               return -EOPNOTSUPP;
+
+       sock = SOCKET_I(ip);
+       if (sock == NULL)
+               return -EOPNOTSUPP;
+
+       ssp = sock->sk->sk_security;
+
+       if (strcmp(name, XATTR_SMACK_IPIN) == 0)
+               isp = ssp->smk_in;
+       else if (strcmp(name, XATTR_SMACK_IPOUT) == 0)
+               isp = ssp->smk_out;
+       else
+               return -EOPNOTSUPP;
+
+       ilen = strlen(isp) + 1;
+       if (rc == 0) {
+               *buffer = isp;
+               rc = ilen;
+       }
+
+       return rc;
+}
+
+
+/**
+ * smack_inode_listsecurity - list the Smack attributes
+ * @inode: the object
+ * @buffer: where they go
+ * @buffer_size: size of buffer
+ *
+ * Returns 0 on success, -EINVAL otherwise
+ */
+static int smack_inode_listsecurity(struct inode *inode, char *buffer,
+                                   size_t buffer_size)
+{
+       int len = strlen(XATTR_NAME_SMACK);
+
+       if (buffer != NULL && len <= buffer_size) {
+               memcpy(buffer, XATTR_NAME_SMACK, len);
+               return len;
+       }
+       return -EINVAL;
+}
+
+/*
+ * File Hooks
+ */
+
+/**
+ * smack_file_permission - Smack check on file operations
+ * @file: unused
+ * @mask: unused
+ *
+ * Returns 0
+ *
+ * Should access checks be done on each read or write?
+ * UNICOS and SELinux say yes.
+ * Trusted Solaris, Trusted Irix, and just about everyone else says no.
+ *
+ * I'll say no for now. Smack does not do the frequent
+ * label changing that SELinux does.
+ */
+static int smack_file_permission(struct file *file, int mask)
+{
+       return 0;
+}
+
+/**
+ * smack_file_alloc_security - assign a file security blob
+ * @file: the object
+ *
+ * The security blob for a file is a pointer to the master
+ * label list, so no allocation is done.
+ *
+ * Returns 0
+ */
+static int smack_file_alloc_security(struct file *file)
+{
+       file->f_security = current->security;
+       return 0;
+}
+
+/**
+ * smack_file_free_security - clear a file security blob
+ * @file: the object
+ *
+ * The security blob for a file is a pointer to the master
+ * label list, so no memory is freed.
+ */
+static void smack_file_free_security(struct file *file)
+{
+       file->f_security = NULL;
+}
+
+/**
+ * smack_file_ioctl - Smack check on ioctls
+ * @file: the object
+ * @cmd: what to do
+ * @arg: unused
+ *
+ * Relies heavily on the correct use of the ioctl command conventions.
+ *
+ * Returns 0 if allowed, error code otherwise
+ */
+static int smack_file_ioctl(struct file *file, unsigned int cmd,
+                           unsigned long arg)
+{
+       int rc = 0;
+
+       if (_IOC_DIR(cmd) & _IOC_WRITE)
+               rc = smk_curacc(file->f_security, MAY_WRITE);
+
+       if (rc == 0 && (_IOC_DIR(cmd) & _IOC_READ))
+               rc = smk_curacc(file->f_security, MAY_READ);
+
+       return rc;
+}
+
+/**
+ * smack_file_lock - Smack check on file locking
+ * @file: the object
+ * @cmd unused
+ *
+ * Returns 0 if current has write access, error code otherwise
+ */
+static int smack_file_lock(struct file *file, unsigned int cmd)
+{
+       return smk_curacc(file->f_security, MAY_WRITE);
+}
+
+/**
+ * smack_file_fcntl - Smack check on fcntl
+ * @file: the object
+ * @cmd: what action to check
+ * @arg: unused
+ *
+ * Returns 0 if current has access, error code otherwise
+ */
+static int smack_file_fcntl(struct file *file, unsigned int cmd,
+                           unsigned long arg)
+{
+       int rc;
+
+       switch (cmd) {
+       case F_DUPFD:
+       case F_GETFD:
+       case F_GETFL:
+       case F_GETLK:
+       case F_GETOWN:
+       case F_GETSIG:
+               rc = smk_curacc(file->f_security, MAY_READ);
+               break;
+       case F_SETFD:
+       case F_SETFL:
+       case F_SETLK:
+       case F_SETLKW:
+       case F_SETOWN:
+       case F_SETSIG:
+               rc = smk_curacc(file->f_security, MAY_WRITE);
+               break;
+       default:
+               rc = smk_curacc(file->f_security, MAY_READWRITE);
+       }
+
+       return rc;
+}
+
+/**
+ * smack_file_set_fowner - set the file security blob value
+ * @file: object in question
+ *
+ * Returns 0
+ * Further research may be required on this one.
+ */
+static int smack_file_set_fowner(struct file *file)
+{
+       file->f_security = current->security;
+       return 0;
+}
+
+/**
+ * smack_file_send_sigiotask - Smack on sigio
+ * @tsk: The target task
+ * @fown: the object the signal come from
+ * @signum: unused
+ *
+ * Allow a privileged task to get signals even if it shouldn't
+ *
+ * Returns 0 if a subject with the object's smack could
+ * write to the task, an error code otherwise.
+ */
+static int smack_file_send_sigiotask(struct task_struct *tsk,
+                                    struct fown_struct *fown, int signum)
+{
+       struct file *file;
+       int rc;
+
+       /*
+        * struct fown_struct is never outside the context of a struct file
+        */
+       file = container_of(fown, struct file, f_owner);
+       rc = smk_access(file->f_security, tsk->security, MAY_WRITE);
+       if (rc != 0 && __capable(tsk, CAP_MAC_OVERRIDE))
+               return 0;
+       return rc;
+}
+
+/**
+ * smack_file_receive - Smack file receive check
+ * @file: the object
+ *
+ * Returns 0 if current has access, error code otherwise
+ */
+static int smack_file_receive(struct file *file)
+{
+       int may = 0;
+
+       /*
+        * This code relies on bitmasks.
+        */
+       if (file->f_mode & FMODE_READ)
+               may = MAY_READ;
+       if (file->f_mode & FMODE_WRITE)
+               may |= MAY_WRITE;
+
+       return smk_curacc(file->f_security, may);
+}
+
+/*
+ * Task hooks
+ */
+
+/**
+ * smack_task_alloc_security - "allocate" a task blob
+ * @tsk: the task in need of a blob
+ *
+ * Smack isn't using copies of blobs. Everyone
+ * points to an immutable list. No alloc required.
+ * No data copy required.
+ *
+ * Always returns 0
+ */
+static int smack_task_alloc_security(struct task_struct *tsk)
+{
+       tsk->security = current->security;
+
+       return 0;
+}
+
+/**
+ * smack_task_free_security - "free" a task blob
+ * @task: the task with the blob
+ *
+ * Smack isn't using copies of blobs. Everyone
+ * points to an immutable list. The blobs never go away.
+ * There is no leak here.
+ */
+static void smack_task_free_security(struct task_struct *task)
+{
+       task->security = NULL;
+}
+
+/**
+ * smack_task_setpgid - Smack check on setting pgid
+ * @p: the task object
+ * @pgid: unused
+ *
+ * Return 0 if write access is permitted
+ */
+static int smack_task_setpgid(struct task_struct *p, pid_t pgid)
+{
+       return smk_curacc(p->security, MAY_WRITE);
+}
+
+/**
+ * smack_task_getpgid - Smack access check for getpgid
+ * @p: the object task
+ *
+ * Returns 0 if current can read the object task, error code otherwise
+ */
+static int smack_task_getpgid(struct task_struct *p)
+{
+       return smk_curacc(p->security, MAY_READ);
+}
+
+/**
+ * smack_task_getsid - Smack access check for getsid
+ * @p: the object task
+ *
+ * Returns 0 if current can read the object task, error code otherwise
+ */
+static int smack_task_getsid(struct task_struct *p)
+{
+       return smk_curacc(p->security, MAY_READ);
+}
+
+/**
+ * smack_task_getsecid - get the secid of the task
+ * @p: the object task
+ * @secid: where to put the result
+ *
+ * Sets the secid to contain a u32 version of the smack label.
+ */
+static void smack_task_getsecid(struct task_struct *p, u32 *secid)
+{
+       *secid = smack_to_secid(p->security);
+}
+
+/**
+ * smack_task_setnice - Smack check on setting nice
+ * @p: the task object
+ * @nice: unused
+ *
+ * Return 0 if write access is permitted
+ */
+static int smack_task_setnice(struct task_struct *p, int nice)
+{
+       return smk_curacc(p->security, MAY_WRITE);
+}
+
+/**
+ * smack_task_setioprio - Smack check on setting ioprio
+ * @p: the task object
+ * @ioprio: unused
+ *
+ * Return 0 if write access is permitted
+ */
+static int smack_task_setioprio(struct task_struct *p, int ioprio)
+{
+       return smk_curacc(p->security, MAY_WRITE);
+}
+
+/**
+ * smack_task_getioprio - Smack check on reading ioprio
+ * @p: the task object
+ *
+ * Return 0 if read access is permitted
+ */
+static int smack_task_getioprio(struct task_struct *p)
+{
+       return smk_curacc(p->security, MAY_READ);
+}
+
+/**
+ * smack_task_setscheduler - Smack check on setting scheduler
+ * @p: the task object
+ * @policy: unused
+ * @lp: unused
+ *
+ * Return 0 if read access is permitted
+ */
+static int smack_task_setscheduler(struct task_struct *p, int policy,
+                                  struct sched_param *lp)
+{
+       return smk_curacc(p->security, MAY_WRITE);
+}
+
+/**
+ * smack_task_getscheduler - Smack check on reading scheduler
+ * @p: the task object
+ *
+ * Return 0 if read access is permitted
+ */
+static int smack_task_getscheduler(struct task_struct *p)
+{
+       return smk_curacc(p->security, MAY_READ);
+}
+
+/**
+ * smack_task_movememory - Smack check on moving memory
+ * @p: the task object
+ *
+ * Return 0 if write access is permitted
+ */
+static int smack_task_movememory(struct task_struct *p)
+{
+       return smk_curacc(p->security, MAY_WRITE);
+}
+
+/**
+ * smack_task_kill - Smack check on signal delivery
+ * @p: the task object
+ * @info: unused
+ * @sig: unused
+ * @secid: identifies the smack to use in lieu of current's
+ *
+ * Return 0 if write access is permitted
+ *
+ * The secid behavior is an artifact of an SELinux hack
+ * in the USB code. Someday it may go away.
+ */
+static int smack_task_kill(struct task_struct *p, struct siginfo *info,
+                          int sig, u32 secid)
+{
+       /*
+        * Special cases where signals really ought to go through
+        * in spite of policy. Stephen Smalley suggests it may
+        * make sense to change the caller so that it doesn't
+        * bother with the LSM hook in these cases.
+        */
+       if (info != SEND_SIG_NOINFO &&
+           (is_si_special(info) || SI_FROMKERNEL(info)))
+               return 0;
+       /*
+        * Sending a signal requires that the sender
+        * can write the receiver.
+        */
+       if (secid == 0)
+               return smk_curacc(p->security, MAY_WRITE);
+       /*
+        * If the secid isn't 0 we're dealing with some USB IO
+        * specific behavior. This is not clean. For one thing
+        * we can't take privilege into account.
+        */
+       return smk_access(smack_from_secid(secid), p->security, MAY_WRITE);
+}
+
+/**
+ * smack_task_wait - Smack access check for waiting
+ * @p: task to wait for
+ *
+ * Returns 0 if current can wait for p, error code otherwise
+ */
+static int smack_task_wait(struct task_struct *p)
+{
+       int rc;
+
+       rc = smk_access(current->security, p->security, MAY_WRITE);
+       if (rc == 0)
+               return 0;
+
+       /*
+        * Allow the operation to succeed if either task
+        * has privilege to perform operations that might
+        * account for the smack labels having gotten to
+        * be different in the first place.
+        *
+        * This breaks the strict subjet/object access
+        * control ideal, taking the object's privilege
+        * state into account in the decision as well as
+        * the smack value.
+        */
+       if (capable(CAP_MAC_OVERRIDE) || __capable(p, CAP_MAC_OVERRIDE))
+               return 0;
+
+       return rc;
+}
+
+/**
+ * smack_task_to_inode - copy task smack into the inode blob
+ * @p: task to copy from
+ * inode: inode to copy to
+ *
+ * Sets the smack pointer in the inode security blob
+ */
+static void smack_task_to_inode(struct task_struct *p, struct inode *inode)
+{
+       struct inode_smack *isp = inode->i_security;
+       isp->smk_inode = p->security;
+}
+
+/*
+ * Socket hooks.
+ */
+
+/**
+ * smack_sk_alloc_security - Allocate a socket blob
+ * @sk: the socket
+ * @family: unused
+ * @priority: memory allocation priority
+ *
+ * Assign Smack pointers to current
+ *
+ * Returns 0 on success, -ENOMEM is there's no memory
+ */
+static int smack_sk_alloc_security(struct sock *sk, int family, gfp_t gfp_flags)
+{
+       char *csp = current->security;
+       struct socket_smack *ssp;
+
+       ssp = kzalloc(sizeof(struct socket_smack), gfp_flags);
+       if (ssp == NULL)
+               return -ENOMEM;
+
+       ssp->smk_in = csp;
+       ssp->smk_out = csp;
+       ssp->smk_packet[0] = '\0';
+
+       sk->sk_security = ssp;
+
+       return 0;
+}
+
+/**
+ * smack_sk_free_security - Free a socket blob
+ * @sk: the socket
+ *
+ * Clears the blob pointer
+ */
+static void smack_sk_free_security(struct sock *sk)
+{
+       kfree(sk->sk_security);
+}
+
+/**
+ * smack_set_catset - convert a capset to netlabel mls categories
+ * @catset: the Smack categories
+ * @sap: where to put the netlabel categories
+ *
+ * Allocates and fills attr.mls.cat
+ */
+static void smack_set_catset(char *catset, struct netlbl_lsm_secattr *sap)
+{
+       unsigned char *cp;
+       unsigned char m;
+       int cat;
+       int rc;
+       int byte;
+
+       if (catset == 0)
+               return;
+
+       sap->flags |= NETLBL_SECATTR_MLS_CAT;
+       sap->attr.mls.cat = netlbl_secattr_catmap_alloc(GFP_ATOMIC);
+       sap->attr.mls.cat->startbit = 0;
+
+       for (cat = 1, cp = catset, byte = 0; byte < SMK_LABELLEN; cp++, byte++)
+               for (m = 0x80; m != 0; m >>= 1, cat++) {
+                       if ((m & *cp) == 0)
+                               continue;
+                       rc = netlbl_secattr_catmap_setbit(sap->attr.mls.cat,
+                                                         cat, GFP_ATOMIC);
+               }
+}
+
+/**
+ * smack_to_secattr - fill a secattr from a smack value
+ * @smack: the smack value
+ * @nlsp: where the result goes
+ *
+ * Casey says that CIPSO is good enough for now.
+ * It can be used to effect.
+ * It can also be abused to effect when necessary.
+ * Appologies to the TSIG group in general and GW in particular.
+ */
+static void smack_to_secattr(char *smack, struct netlbl_lsm_secattr *nlsp)
+{
+       struct smack_cipso cipso;
+       int rc;
+
+       switch (smack_net_nltype) {
+       case NETLBL_NLTYPE_CIPSOV4:
+               nlsp->domain = NULL;
+               nlsp->flags = NETLBL_SECATTR_DOMAIN;
+               nlsp->flags |= NETLBL_SECATTR_MLS_LVL;
+
+               rc = smack_to_cipso(smack, &cipso);
+               if (rc == 0) {
+                       nlsp->attr.mls.lvl = cipso.smk_level;
+                       smack_set_catset(cipso.smk_catset, nlsp);
+               } else {
+                       nlsp->attr.mls.lvl = smack_cipso_direct;
+                       smack_set_catset(smack, nlsp);
+               }
+               break;
+       default:
+               break;
+       }
+}
+
+/**
+ * smack_netlabel - Set the secattr on a socket
+ * @sk: the socket
+ *
+ * Convert the outbound smack value (smk_out) to a
+ * secattr and attach it to the socket.
+ *
+ * Returns 0 on success or an error code
+ */
+static int smack_netlabel(struct sock *sk)
+{
+       struct socket_smack *ssp = sk->sk_security;
+       struct netlbl_lsm_secattr secattr;
+       int rc = 0;
+
+       netlbl_secattr_init(&secattr);
+       smack_to_secattr(ssp->smk_out, &secattr);
+       if (secattr.flags != NETLBL_SECATTR_NONE)
+               rc = netlbl_sock_setattr(sk, &secattr);
+
+       netlbl_secattr_destroy(&secattr);
+       return rc;
+}
+
+/**
+ * smack_inode_setsecurity - set smack xattrs
+ * @inode: the object
+ * @name: attribute name
+ * @value: attribute value
+ * @size: size of the attribute
+ * @flags: unused
+ *
+ * Sets the named attribute in the appropriate blob
+ *
+ * Returns 0 on success, or an error code
+ */
+static int smack_inode_setsecurity(struct inode *inode, const char *name,
+                                  const void *value, size_t size, int flags)
+{
+       char *sp;
+       struct inode_smack *nsp = inode->i_security;
+       struct socket_smack *ssp;
+       struct socket *sock;
+
+       if (value == NULL || size > SMK_LABELLEN)
+               return -EACCES;
+
+       sp = smk_import(value, size);
+       if (sp == NULL)
+               return -EINVAL;
+
+       if (strcmp(name, XATTR_SMACK_SUFFIX) == 0) {
+               nsp->smk_inode = sp;
+               return 0;
+       }
+       /*
+        * The rest of the Smack xattrs are only on sockets.
+        */
+       if (inode->i_sb->s_magic != SOCKFS_MAGIC)
+               return -EOPNOTSUPP;
+
+       sock = SOCKET_I(inode);
+       if (sock == NULL)
+               return -EOPNOTSUPP;
+
+       ssp = sock->sk->sk_security;
+
+       if (strcmp(name, XATTR_SMACK_IPIN) == 0)
+               ssp->smk_in = sp;
+       else if (strcmp(name, XATTR_SMACK_IPOUT) == 0) {
+               ssp->smk_out = sp;
+               return smack_netlabel(sock->sk);
+       } else
+               return -EOPNOTSUPP;
+
+       return 0;
+}
+
+/**
+ * smack_socket_post_create - finish socket setup
+ * @sock: the socket
+ * @family: protocol family
+ * @type: unused
+ * @protocol: unused
+ * @kern: unused
+ *
+ * Sets the netlabel information on the socket
+ *
+ * Returns 0 on success, and error code otherwise
+ */
+static int smack_socket_post_create(struct socket *sock, int family,
+                                   int type, int protocol, int kern)
+{
+       if (family != PF_INET)
+               return 0;
+       /*
+        * Set the outbound netlbl.
+        */
+       return smack_netlabel(sock->sk);
+}
+
+/**
+ * smack_flags_to_may - convert S_ to MAY_ values
+ * @flags: the S_ value
+ *
+ * Returns the equivalent MAY_ value
+ */
+static int smack_flags_to_may(int flags)
+{
+       int may = 0;
+
+       if (flags & S_IRUGO)
+               may |= MAY_READ;
+       if (flags & S_IWUGO)
+               may |= MAY_WRITE;
+       if (flags & S_IXUGO)
+               may |= MAY_EXEC;
+
+       return may;
+}
+
+/**
+ * smack_msg_msg_alloc_security - Set the security blob for msg_msg
+ * @msg: the object
+ *
+ * Returns 0
+ */
+static int smack_msg_msg_alloc_security(struct msg_msg *msg)
+{
+       msg->security = current->security;
+       return 0;
+}
+
+/**
+ * smack_msg_msg_free_security - Clear the security blob for msg_msg
+ * @msg: the object
+ *
+ * Clears the blob pointer
+ */
+static void smack_msg_msg_free_security(struct msg_msg *msg)
+{
+       msg->security = NULL;
+}
+
+/**
+ * smack_of_shm - the smack pointer for the shm
+ * @shp: the object
+ *
+ * Returns a pointer to the smack value
+ */
+static char *smack_of_shm(struct shmid_kernel *shp)
+{
+       return (char *)shp->shm_perm.security;
+}
+
+/**
+ * smack_shm_alloc_security - Set the security blob for shm
+ * @shp: the object
+ *
+ * Returns 0
+ */
+static int smack_shm_alloc_security(struct shmid_kernel *shp)
+{
+       struct kern_ipc_perm *isp = &shp->shm_perm;
+
+       isp->security = current->security;
+       return 0;
+}
+
+/**
+ * smack_shm_free_security - Clear the security blob for shm
+ * @shp: the object
+ *
+ * Clears the blob pointer
+ */
+static void smack_shm_free_security(struct shmid_kernel *shp)
+{
+       struct kern_ipc_perm *isp = &shp->shm_perm;
+
+       isp->security = NULL;
+}
+
+/**
+ * smack_shm_associate - Smack access check for shm
+ * @shp: the object
+ * @shmflg: access requested
+ *
+ * Returns 0 if current has the requested access, error code otherwise
+ */
+static int smack_shm_associate(struct shmid_kernel *shp, int shmflg)
+{
+       char *ssp = smack_of_shm(shp);
+       int may;
+
+       may = smack_flags_to_may(shmflg);
+       return smk_curacc(ssp, may);
+}
+
+/**
+ * smack_shm_shmctl - Smack access check for shm
+ * @shp: the object
+ * @cmd: what it wants to do
+ *
+ * Returns 0 if current has the requested access, error code otherwise
+ */
+static int smack_shm_shmctl(struct shmid_kernel *shp, int cmd)
+{
+       char *ssp = smack_of_shm(shp);
+       int may;
+
+       switch (cmd) {
+       case IPC_STAT:
+       case SHM_STAT:
+               may = MAY_READ;
+               break;
+       case IPC_SET:
+       case SHM_LOCK:
+       case SHM_UNLOCK:
+       case IPC_RMID:
+               may = MAY_READWRITE;
+               break;
+       case IPC_INFO:
+       case SHM_INFO:
+               /*
+                * System level information.
+                */
+               return 0;
+       default:
+               return -EINVAL;
+       }
+
+       return smk_curacc(ssp, may);
+}
+
+/**
+ * smack_shm_shmat - Smack access for shmat
+ * @shp: the object
+ * @shmaddr: unused
+ * @shmflg: access requested
+ *
+ * Returns 0 if current has the requested access, error code otherwise
+ */
+static int smack_shm_shmat(struct shmid_kernel *shp, char __user *shmaddr,
+                          int shmflg)
+{
+       char *ssp = smack_of_shm(shp);
+       int may;
+
+       may = smack_flags_to_may(shmflg);
+       return smk_curacc(ssp, may);
+}
+
+/**
+ * smack_of_sem - the smack pointer for the sem
+ * @sma: the object
+ *
+ * Returns a pointer to the smack value
+ */
+static char *smack_of_sem(struct sem_array *sma)
+{
+       return (char *)sma->sem_perm.security;
+}
+
+/**
+ * smack_sem_alloc_security - Set the security blob for sem
+ * @sma: the object
+ *
+ * Returns 0
+ */
+static int smack_sem_alloc_security(struct sem_array *sma)
+{
+       struct kern_ipc_perm *isp = &sma->sem_perm;
+
+       isp->security = current->security;
+       return 0;
+}
+
+/**
+ * smack_sem_free_security - Clear the security blob for sem
+ * @sma: the object
+ *
+ * Clears the blob pointer
+ */
+static void smack_sem_free_security(struct sem_array *sma)
+{
+       struct kern_ipc_perm *isp = &sma->sem_perm;
+
+       isp->security = NULL;
+}
+
+/**
+ * smack_sem_associate - Smack access check for sem
+ * @sma: the object
+ * @semflg: access requested
+ *
+ * Returns 0 if current has the requested access, error code otherwise
+ */
+static int smack_sem_associate(struct sem_array *sma, int semflg)
+{
+       char *ssp = smack_of_sem(sma);
+       int may;
+
+       may = smack_flags_to_may(semflg);
+       return smk_curacc(ssp, may);
+}
+
+/**
+ * smack_sem_shmctl - Smack access check for sem
+ * @sma: the object
+ * @cmd: what it wants to do
+ *
+ * Returns 0 if current has the requested access, error code otherwise
+ */
+static int smack_sem_semctl(struct sem_array *sma, int cmd)
+{
+       char *ssp = smack_of_sem(sma);
+       int may;
+
+       switch (cmd) {
+       case GETPID:
+       case GETNCNT:
+       case GETZCNT:
+       case GETVAL:
+       case GETALL:
+       case IPC_STAT:
+       case SEM_STAT:
+               may = MAY_READ;
+               break;
+       case SETVAL:
+       case SETALL:
+       case IPC_RMID:
+       case IPC_SET:
+               may = MAY_READWRITE;
+               break;
+       case IPC_INFO:
+       case SEM_INFO:
+               /*
+                * System level information
+                */
+               return 0;
+       default:
+               return -EINVAL;
+       }
+
+       return smk_curacc(ssp, may);
+}
+
+/**
+ * smack_sem_semop - Smack checks of semaphore operations
+ * @sma: the object
+ * @sops: unused
+ * @nsops: unused
+ * @alter: unused
+ *
+ * Treated as read and write in all cases.
+ *
+ * Returns 0 if access is allowed, error code otherwise
+ */
+static int smack_sem_semop(struct sem_array *sma, struct sembuf *sops,
+                          unsigned nsops, int alter)
+{
+       char *ssp = smack_of_sem(sma);
+
+       return smk_curacc(ssp, MAY_READWRITE);
+}
+
+/**
+ * smack_msg_alloc_security - Set the security blob for msg
+ * @msq: the object
+ *
+ * Returns 0
+ */
+static int smack_msg_queue_alloc_security(struct msg_queue *msq)
+{
+       struct kern_ipc_perm *kisp = &msq->q_perm;
+
+       kisp->security = current->security;
+       return 0;
+}
+
+/**
+ * smack_msg_free_security - Clear the security blob for msg
+ * @msq: the object
+ *
+ * Clears the blob pointer
+ */
+static void smack_msg_queue_free_security(struct msg_queue *msq)
+{
+       struct kern_ipc_perm *kisp = &msq->q_perm;
+
+       kisp->security = NULL;
+}
+
+/**
+ * smack_of_msq - the smack pointer for the msq
+ * @msq: the object
+ *
+ * Returns a pointer to the smack value
+ */
+static char *smack_of_msq(struct msg_queue *msq)
+{
+       return (char *)msq->q_perm.security;
+}
+
+/**
+ * smack_msg_queue_associate - Smack access check for msg_queue
+ * @msq: the object
+ * @msqflg: access requested
+ *
+ * Returns 0 if current has the requested access, error code otherwise
+ */
+static int smack_msg_queue_associate(struct msg_queue *msq, int msqflg)
+{
+       char *msp = smack_of_msq(msq);
+       int may;
+
+       may = smack_flags_to_may(msqflg);
+       return smk_curacc(msp, may);
+}
+
+/**
+ * smack_msg_queue_msgctl - Smack access check for msg_queue
+ * @msq: the object
+ * @cmd: what it wants to do
+ *
+ * Returns 0 if current has the requested access, error code otherwise
+ */
+static int smack_msg_queue_msgctl(struct msg_queue *msq, int cmd)
+{
+       char *msp = smack_of_msq(msq);
+       int may;
+
+       switch (cmd) {
+       case IPC_STAT:
+       case MSG_STAT:
+               may = MAY_READ;
+               break;
+       case IPC_SET:
+       case IPC_RMID:
+               may = MAY_READWRITE;
+               break;
+       case IPC_INFO:
+       case MSG_INFO:
+               /*
+                * System level information
+                */
+               return 0;
+       default:
+               return -EINVAL;
+       }
+
+       return smk_curacc(msp, may);
+}
+
+/**
+ * smack_msg_queue_msgsnd - Smack access check for msg_queue
+ * @msq: the object
+ * @msg: unused
+ * @msqflg: access requested
+ *
+ * Returns 0 if current has the requested access, error code otherwise
+ */
+static int smack_msg_queue_msgsnd(struct msg_queue *msq, struct msg_msg *msg,
+                                 int msqflg)
+{
+       char *msp = smack_of_msq(msq);
+       int rc;
+
+       rc = smack_flags_to_may(msqflg);
+       return smk_curacc(msp, rc);
+}
+
+/**
+ * smack_msg_queue_msgsnd - Smack access check for msg_queue
+ * @msq: the object
+ * @msg: unused
+ * @target: unused
+ * @type: unused
+ * @mode: unused
+ *
+ * Returns 0 if current has read and write access, error code otherwise
+ */
+static int smack_msg_queue_msgrcv(struct msg_queue *msq, struct msg_msg *msg,
+                       struct task_struct *target, long type, int mode)
+{
+       char *msp = smack_of_msq(msq);
+
+       return smk_curacc(msp, MAY_READWRITE);
+}
+
+/**
+ * smack_ipc_permission - Smack access for ipc_permission()
+ * @ipp: the object permissions
+ * @flag: access requested
+ *
+ * Returns 0 if current has read and write access, error code otherwise
+ */
+static int smack_ipc_permission(struct kern_ipc_perm *ipp, short flag)
+{
+       char *isp = ipp->security;
+       int may;
+
+       may = smack_flags_to_may(flag);
+       return smk_curacc(isp, may);
+}
+
+/**
+ * smack_d_instantiate - Make sure the blob is correct on an inode
+ * @opt_dentry: unused
+ * @inode: the object
+ *
+ * Set the inode's security blob if it hasn't been done already.
+ */
+static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
+{
+       struct super_block *sbp;
+       struct superblock_smack *sbsp;
+       struct inode_smack *isp;
+       char *csp = current->security;
+       char *fetched;
+       char *final;
+       struct dentry *dp;
+
+       if (inode == NULL)
+               return;
+
+       isp = inode->i_security;
+
+       mutex_lock(&isp->smk_lock);
+       /*
+        * If the inode is already instantiated
+        * take the quick way out
+        */
+       if (isp->smk_flags & SMK_INODE_INSTANT)
+               goto unlockandout;
+
+       sbp = inode->i_sb;
+       sbsp = sbp->s_security;
+       /*
+        * We're going to use the superblock default label
+        * if there's no label on the file.
+        */
+       final = sbsp->smk_default;
+
+       /*
+        * This is pretty hackish.
+        * Casey says that we shouldn't have to do
+        * file system specific code, but it does help
+        * with keeping it simple.
+        */
+       switch (sbp->s_magic) {
+       case SMACK_MAGIC:
+               /*
+                * Casey says that it's a little embarassing
+                * that the smack file system doesn't do
+                * extended attributes.
+                */
+               final = smack_known_star.smk_known;
+               break;
+       case PIPEFS_MAGIC:
+               /*
+                * Casey says pipes are easy (?)
+                */
+               final = smack_known_star.smk_known;
+               break;
+       case DEVPTS_SUPER_MAGIC:
+               /*
+                * devpts seems content with the label of the task.
+                * Programs that change smack have to treat the
+                * pty with respect.
+                */
+               final = csp;
+               break;
+       case SOCKFS_MAGIC:
+               /*
+                * Casey says sockets get the smack of the task.
+                */
+               final = csp;
+               break;
+       case PROC_SUPER_MAGIC:
+               /*
+                * Casey says procfs appears not to care.
+                * The superblock default suffices.
+                */
+               break;
+       case TMPFS_MAGIC:
+               /*
+                * Device labels should come from the filesystem,
+                * but watch out, because they're volitile,
+                * getting recreated on every reboot.
+                */
+               final = smack_known_star.smk_known;
+               /*
+                * No break.
+                *
+                * If a smack value has been set we want to use it,
+                * but since tmpfs isn't giving us the opportunity
+                * to set mount options simulate setting the
+                * superblock default.
+                */
+       default:
+               /*
+                * This isn't an understood special case.
+                * Get the value from the xattr.
+                *
+                * No xattr support means, alas, no SMACK label.
+                * Use the aforeapplied default.
+                * It would be curious if the label of the task
+                * does not match that assigned.
+                */
+               if (inode->i_op->getxattr == NULL)
+                       break;
+               /*
+                * Get the dentry for xattr.
+                */
+               if (opt_dentry == NULL) {
+                       dp = d_find_alias(inode);
+                       if (dp == NULL)
+                               break;
+               } else {
+                       dp = dget(opt_dentry);
+                       if (dp == NULL)
+                               break;
+               }
+
+               fetched = smk_fetch(inode, dp);
+               if (fetched != NULL)
+                       final = fetched;
+
+               dput(dp);
+               break;
+       }
+
+       if (final == NULL)
+               isp->smk_inode = csp;
+       else
+               isp->smk_inode = final;
+
+       isp->smk_flags |= SMK_INODE_INSTANT;
+
+unlockandout:
+       mutex_unlock(&isp->smk_lock);
+       return;
+}
+
+/**
+ * smack_getprocattr - Smack process attribute access
+ * @p: the object task
+ * @name: the name of the attribute in /proc/.../attr
+ * @value: where to put the result
+ *
+ * Places a copy of the task Smack into value
+ *
+ * Returns the length of the smack label or an error code
+ */
+static int smack_getprocattr(struct task_struct *p, char *name, char **value)
+{
+       char *cp;
+       int slen;
+
+       if (strcmp(name, "current") != 0)
+               return -EINVAL;
+
+       cp = kstrdup(p->security, GFP_KERNEL);
+       if (cp == NULL)
+               return -ENOMEM;
+
+       slen = strlen(cp);
+       *value = cp;
+       return slen;
+}
+
+/**
+ * smack_setprocattr - Smack process attribute setting
+ * @p: the object task
+ * @name: the name of the attribute in /proc/.../attr
+ * @value: the value to set
+ * @size: the size of the value
+ *
+ * Sets the Smack value of the task. Only setting self
+ * is permitted and only with privilege
+ *
+ * Returns the length of the smack label or an error code
+ */
+static int smack_setprocattr(struct task_struct *p, char *name,
+                            void *value, size_t size)
+{
+       char *newsmack;
+
+       if (!__capable(p, CAP_MAC_ADMIN))
+               return -EPERM;
+
+       /*
+        * Changing another process' Smack value is too dangerous
+        * and supports no sane use case.
+        */
+       if (p != current)
+               return -EPERM;
+
+       if (value == NULL || size == 0 || size >= SMK_LABELLEN)
+               return -EINVAL;
+
+       if (strcmp(name, "current") != 0)
+               return -EINVAL;
+
+       newsmack = smk_import(value, size);
+       if (newsmack == NULL)
+               return -EINVAL;
+
+       p->security = newsmack;
+       return size;
+}
+
+/**
+ * smack_unix_stream_connect - Smack access on UDS
+ * @sock: one socket
+ * @other: the other socket
+ * @newsk: unused
+ *
+ * Return 0 if a subject with the smack of sock could access
+ * an object with the smack of other, otherwise an error code
+ */
+static int smack_unix_stream_connect(struct socket *sock,
+                                    struct socket *other, struct sock *newsk)
+{
+       struct inode *sp = SOCK_INODE(sock);
+       struct inode *op = SOCK_INODE(other);
+
+       return smk_access(smk_of_inode(sp), smk_of_inode(op), MAY_READWRITE);
+}
+
+/**
+ * smack_unix_may_send - Smack access on UDS
+ * @sock: one socket
+ * @other: the other socket
+ *
+ * Return 0 if a subject with the smack of sock could access
+ * an object with the smack of other, otherwise an error code
+ */
+static int smack_unix_may_send(struct socket *sock, struct socket *other)
+{
+       struct inode *sp = SOCK_INODE(sock);
+       struct inode *op = SOCK_INODE(other);
+
+       return smk_access(smk_of_inode(sp), smk_of_inode(op), MAY_WRITE);
+}
+
+/**
+ * smack_from_secattr - Convert a netlabel attr.mls.lvl/attr.mls.cat
+ *     pair to smack
+ * @sap: netlabel secattr
+ * @sip: where to put the result
+ *
+ * Copies a smack label into sip
+ */
+static void smack_from_secattr(struct netlbl_lsm_secattr *sap, char *sip)
+{
+       char smack[SMK_LABELLEN];
+       int pcat;
+
+       if ((sap->flags & NETLBL_SECATTR_MLS_LVL) == 0) {
+               /*
+                * If there are flags but no level netlabel isn't
+                * behaving the way we expect it to.
+                *
+                * Without guidance regarding the smack value
+                * for the packet fall back on the network
+                * ambient value.
+                */
+               strncpy(sip, smack_net_ambient, SMK_MAXLEN);
+               return;
+       }
+       /*
+        * Get the categories, if any
+        */
+       memset(smack, '\0', SMK_LABELLEN);
+       if ((sap->flags & NETLBL_SECATTR_MLS_CAT) != 0)
+               for (pcat = -1;;) {
+                       pcat = netlbl_secattr_catmap_walk(sap->attr.mls.cat,
+                                                         pcat + 1);
+                       if (pcat < 0)
+                               break;
+                       smack_catset_bit(pcat, smack);
+               }
+       /*
+        * If it is CIPSO using smack direct mapping
+        * we are already done. WeeHee.
+        */
+       if (sap->attr.mls.lvl == smack_cipso_direct) {
+               memcpy(sip, smack, SMK_MAXLEN);
+               return;
+       }
+       /*
+        * Look it up in the supplied table if it is not a direct mapping.
+        */
+       smack_from_cipso(sap->attr.mls.lvl, smack, sip);
+       return;
+}
+
+/**
+ * smack_socket_sock_rcv_skb - Smack packet delivery access check
+ * @sk: socket
+ * @skb: packet
+ *
+ * Returns 0 if the packet should be delivered, an error code otherwise
+ */
+static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
+{
+       struct netlbl_lsm_secattr secattr;
+       struct socket_smack *ssp = sk->sk_security;
+       char smack[SMK_LABELLEN];
+       int rc;
+
+       if (sk->sk_family != PF_INET && sk->sk_family != PF_INET6)
+               return 0;
+
+       /*
+        * Translate what netlabel gave us.
+        */
+       memset(smack, '\0', SMK_LABELLEN);
+       netlbl_secattr_init(&secattr);
+       rc = netlbl_skbuff_getattr(skb, sk->sk_family, &secattr);
+       if (rc == 0)
+               smack_from_secattr(&secattr, smack);
+       else
+               strncpy(smack, smack_net_ambient, SMK_MAXLEN);
+       netlbl_secattr_destroy(&secattr);
+       /*
+        * Receiving a packet requires that the other end
+        * be able to write here. Read access is not required.
+        * This is the simplist possible security model
+        * for networking.
+        */
+       return smk_access(smack, ssp->smk_in, MAY_WRITE);
+}
+
+/**
+ * smack_socket_getpeersec_stream - pull in packet label
+ * @sock: the socket
+ * @optval: user's destination
+ * @optlen: size thereof
+ * @len: max thereoe
+ *
+ * returns zero on success, an error code otherwise
+ */
+static int smack_socket_getpeersec_stream(struct socket *sock,
+                                         char __user *optval,
+                                         int __user *optlen, unsigned len)
+{
+       struct socket_smack *ssp;
+       int slen;
+       int rc = 0;
+
+       ssp = sock->sk->sk_security;
+       slen = strlen(ssp->smk_packet) + 1;
+
+       if (slen > len)
+               rc = -ERANGE;
+       else if (copy_to_user(optval, ssp->smk_packet, slen) != 0)
+               rc = -EFAULT;
+
+       if (put_user(slen, optlen) != 0)
+               rc = -EFAULT;
+
+       return rc;
+}
+
+
+/**
+ * smack_socket_getpeersec_dgram - pull in packet label
+ * @sock: the socket
+ * @skb: packet data
+ * @secid: pointer to where to put the secid of the packet
+ *
+ * Sets the netlabel socket state on sk from parent
+ */
+static int smack_socket_getpeersec_dgram(struct socket *sock,
+                                        struct sk_buff *skb, u32 *secid)
+
+{
+       struct netlbl_lsm_secattr secattr;
+       struct sock *sk;
+       char smack[SMK_LABELLEN];
+       int family = PF_INET;
+       u32 s;
+       int rc;
+
+       /*
+        * Only works for families with packets.
+        */
+       if (sock != NULL) {
+               sk = sock->sk;
+               if (sk->sk_family != PF_INET && sk->sk_family != PF_INET6)
+                       return 0;
+               family = sk->sk_family;
+       }
+       /*
+        * Translate what netlabel gave us.
+        */
+       memset(smack, '\0', SMK_LABELLEN);
+       netlbl_secattr_init(&secattr);
+       rc = netlbl_skbuff_getattr(skb, family, &secattr);
+       if (rc == 0)
+               smack_from_secattr(&secattr, smack);
+       netlbl_secattr_destroy(&secattr);
+
+       /*
+        * Give up if we couldn't get anything
+        */
+       if (rc != 0)
+               return rc;
+
+       s = smack_to_secid(smack);
+       if (s == 0)
+               return -EINVAL;
+
+       *secid = s;
+       return 0;
+}
+
+/**
+ * smack_sock_graft - graft access state between two sockets
+ * @sk: fresh sock
+ * @parent: donor socket
+ *
+ * Sets the netlabel socket state on sk from parent
+ */
+static void smack_sock_graft(struct sock *sk, struct socket *parent)
+{
+       struct socket_smack *ssp;
+       int rc;
+
+       if (sk == NULL)
+               return;
+
+       if (sk->sk_family != PF_INET && sk->sk_family != PF_INET6)
+               return;
+
+       ssp = sk->sk_security;
+       ssp->smk_in = current->security;
+       ssp->smk_out = current->security;
+       ssp->smk_packet[0] = '\0';
+
+       rc = smack_netlabel(sk);
+}
+
+/**
+ * smack_inet_conn_request - Smack access check on connect
+ * @sk: socket involved
+ * @skb: packet
+ * @req: unused
+ *
+ * Returns 0 if a task with the packet label could write to
+ * the socket, otherwise an error code
+ */
+static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb,
+                                  struct request_sock *req)
+{
+       struct netlbl_lsm_secattr skb_secattr;
+       struct socket_smack *ssp = sk->sk_security;
+       char smack[SMK_LABELLEN];
+       int rc;
+
+       if (skb == NULL)
+               return -EACCES;
+
+       memset(smack, '\0', SMK_LABELLEN);
+       netlbl_secattr_init(&skb_secattr);
+       rc = netlbl_skbuff_getattr(skb, sk->sk_family, &skb_secattr);
+       if (rc == 0)
+               smack_from_secattr(&skb_secattr, smack);
+       else
+               strncpy(smack, smack_known_huh.smk_known, SMK_MAXLEN);
+       netlbl_secattr_destroy(&skb_secattr);
+       /*
+        * Receiving a packet requires that the other end
+        * be able to write here. Read access is not required.
+        *
+        * If the request is successful save the peer's label
+        * so that SO_PEERCRED can report it.
+        */
+       rc = smk_access(smack, ssp->smk_in, MAY_WRITE);
+       if (rc == 0)
+               strncpy(ssp->smk_packet, smack, SMK_MAXLEN);
+
+       return rc;
+}
+
+/*
+ * Key management security hooks
+ *
+ * Casey has not tested key support very heavily.
+ * The permission check is most likely too restrictive.
+ * If you care about keys please have a look.
+ */
+#ifdef CONFIG_KEYS
+
+/**
+ * smack_key_alloc - Set the key security blob
+ * @key: object
+ * @tsk: the task associated with the key
+ * @flags: unused
+ *
+ * No allocation required
+ *
+ * Returns 0
+ */
+static int smack_key_alloc(struct key *key, struct task_struct *tsk,
+                          unsigned long flags)
+{
+       key->security = tsk->security;
+       return 0;
+}
+
+/**
+ * smack_key_free - Clear the key security blob
+ * @key: the object
+ *
+ * Clear the blob pointer
+ */
+static void smack_key_free(struct key *key)
+{
+       key->security = NULL;
+}
+
+/*
+ * smack_key_permission - Smack access on a key
+ * @key_ref: gets to the object
+ * @context: task involved
+ * @perm: unused
+ *
+ * Return 0 if the task has read and write to the object,
+ * an error code otherwise
+ */
+static int smack_key_permission(key_ref_t key_ref,
+                               struct task_struct *context, key_perm_t perm)
+{
+       struct key *keyp;
+
+       keyp = key_ref_to_ptr(key_ref);
+       if (keyp == NULL)
+               return -EINVAL;
+       /*
+        * If the key hasn't been initialized give it access so that
+        * it may do so.
+        */
+       if (keyp->security == NULL)
+               return 0;
+       /*
+        * This should not occur
+        */
+       if (context->security == NULL)
+               return -EACCES;
+
+       return smk_access(context->security, keyp->security, MAY_READWRITE);
+}
+#endif /* CONFIG_KEYS */
+
+/*
+ * smack_secid_to_secctx - return the smack label for a secid
+ * @secid: incoming integer
+ * @secdata: destination
+ * @seclen: how long it is
+ *
+ * Exists for networking code.
+ */
+static int smack_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
+{
+       char *sp = smack_from_secid(secid);
+
+       *secdata = sp;
+       *seclen = strlen(sp);
+       return 0;
+}
+
+/*
+ * smack_release_secctx - don't do anything.
+ * @key_ref: unused
+ * @context: unused
+ * @perm: unused
+ *
+ * Exists to make sure nothing gets done, and properly
+ */
+static void smack_release_secctx(char *secdata, u32 seclen)
+{
+}
+
+static struct security_operations smack_ops = {
+       .ptrace =                       smack_ptrace,
+       .capget =                       cap_capget,
+       .capset_check =                 cap_capset_check,
+       .capset_set =                   cap_capset_set,
+       .capable =                      cap_capable,
+       .syslog =                       smack_syslog,
+       .settime =                      cap_settime,
+       .vm_enough_memory =             cap_vm_enough_memory,
+
+       .bprm_apply_creds =             cap_bprm_apply_creds,
+       .bprm_set_security =            cap_bprm_set_security,
+       .bprm_secureexec =              cap_bprm_secureexec,
+
+       .sb_alloc_security =            smack_sb_alloc_security,
+       .sb_free_security =             smack_sb_free_security,
+       .sb_copy_data =                 smack_sb_copy_data,
+       .sb_kern_mount =                smack_sb_kern_mount,
+       .sb_statfs =                    smack_sb_statfs,
+       .sb_mount =                     smack_sb_mount,
+       .sb_umount =                    smack_sb_umount,
+
+       .inode_alloc_security =         smack_inode_alloc_security,
+       .inode_free_security =          smack_inode_free_security,
+       .inode_init_security =          smack_inode_init_security,
+       .inode_link =                   smack_inode_link,
+       .inode_unlink =                 smack_inode_unlink,
+       .inode_rmdir =                  smack_inode_rmdir,
+       .inode_rename =                 smack_inode_rename,
+       .inode_permission =             smack_inode_permission,
+       .inode_setattr =                smack_inode_setattr,
+       .inode_getattr =                smack_inode_getattr,
+       .inode_setxattr =               smack_inode_setxattr,
+       .inode_post_setxattr =          smack_inode_post_setxattr,
+       .inode_getxattr =               smack_inode_getxattr,
+       .inode_removexattr =            smack_inode_removexattr,
+       .inode_getsecurity =            smack_inode_getsecurity,
+       .inode_setsecurity =            smack_inode_setsecurity,
+       .inode_listsecurity =           smack_inode_listsecurity,
+
+       .file_permission =              smack_file_permission,
+       .file_alloc_security =          smack_file_alloc_security,
+       .file_free_security =           smack_file_free_security,
+       .file_ioctl =                   smack_file_ioctl,
+       .file_lock =                    smack_file_lock,
+       .file_fcntl =                   smack_file_fcntl,
+       .file_set_fowner =              smack_file_set_fowner,
+       .file_send_sigiotask =          smack_file_send_sigiotask,
+       .file_receive =                 smack_file_receive,
+
+       .task_alloc_security =          smack_task_alloc_security,
+       .task_free_security =           smack_task_free_security,
+       .task_post_setuid =             cap_task_post_setuid,
+       .task_setpgid =                 smack_task_setpgid,
+       .task_getpgid =                 smack_task_getpgid,
+       .task_getsid =                  smack_task_getsid,
+       .task_getsecid =                smack_task_getsecid,
+       .task_setnice =                 smack_task_setnice,
+       .task_setioprio =               smack_task_setioprio,
+       .task_getioprio =               smack_task_getioprio,
+       .task_setscheduler =            smack_task_setscheduler,
+       .task_getscheduler =            smack_task_getscheduler,
+       .task_movememory =              smack_task_movememory,
+       .task_kill =                    smack_task_kill,
+       .task_wait =                    smack_task_wait,
+       .task_reparent_to_init =        cap_task_reparent_to_init,
+       .task_to_inode =                smack_task_to_inode,
+
+       .ipc_permission =               smack_ipc_permission,
+
+       .msg_msg_alloc_security =       smack_msg_msg_alloc_security,
+       .msg_msg_free_security =        smack_msg_msg_free_security,
+
+       .msg_queue_alloc_security =     smack_msg_queue_alloc_security,
+       .msg_queue_free_security =      smack_msg_queue_free_security,
+       .msg_queue_associate =          smack_msg_queue_associate,
+       .msg_queue_msgctl =             smack_msg_queue_msgctl,
+       .msg_queue_msgsnd =             smack_msg_queue_msgsnd,
+       .msg_queue_msgrcv =             smack_msg_queue_msgrcv,
+
+       .shm_alloc_security =           smack_shm_alloc_security,
+       .shm_free_security =            smack_shm_free_security,
+       .shm_associate =                smack_shm_associate,
+       .shm_shmctl =                   smack_shm_shmctl,
+       .shm_shmat =                    smack_shm_shmat,
+
+       .sem_alloc_security =           smack_sem_alloc_security,
+       .sem_free_security =            smack_sem_free_security,
+       .sem_associate =                smack_sem_associate,
+       .sem_semctl =                   smack_sem_semctl,
+       .sem_semop =                    smack_sem_semop,
+
+       .netlink_send =                 cap_netlink_send,
+       .netlink_recv =                 cap_netlink_recv,
+
+       .d_instantiate =                smack_d_instantiate,
+
+       .getprocattr =                  smack_getprocattr,
+       .setprocattr =                  smack_setprocattr,
+
+       .unix_stream_connect =          smack_unix_stream_connect,
+       .unix_may_send =                smack_unix_may_send,
+
+       .socket_post_create =           smack_socket_post_create,
+       .socket_sock_rcv_skb =          smack_socket_sock_rcv_skb,
+       .socket_getpeersec_stream =     smack_socket_getpeersec_stream,
+       .socket_getpeersec_dgram =      smack_socket_getpeersec_dgram,
+       .sk_alloc_security =            smack_sk_alloc_security,
+       .sk_free_security =             smack_sk_free_security,
+       .sock_graft =                   smack_sock_graft,
+       .inet_conn_request =            smack_inet_conn_request,
+ /* key management security hooks */
+#ifdef CONFIG_KEYS
+       .key_alloc =                    smack_key_alloc,
+       .key_free =                     smack_key_free,
+       .key_permission =               smack_key_permission,
+#endif /* CONFIG_KEYS */
+       .secid_to_secctx =              smack_secid_to_secctx,
+       .release_secctx =               smack_release_secctx,
+};
+
+/**
+ * smack_init - initialize the smack system
+ *
+ * Returns 0
+ */
+static __init int smack_init(void)
+{
+       printk(KERN_INFO "Smack:  Initializing.\n");
+
+       /*
+        * Set the security state for the initial task.
+        */
+       current->security = &smack_known_floor.smk_known;
+
+       /*
+        * Initialize locks
+        */
+       spin_lock_init(&smack_known_unset.smk_cipsolock);
+       spin_lock_init(&smack_known_huh.smk_cipsolock);
+       spin_lock_init(&smack_known_hat.smk_cipsolock);
+       spin_lock_init(&smack_known_star.smk_cipsolock);
+       spin_lock_init(&smack_known_floor.smk_cipsolock);
+       spin_lock_init(&smack_known_invalid.smk_cipsolock);
+
+       /*
+        * Register with LSM
+        */
+       if (register_security(&smack_ops))
+               panic("smack: Unable to register with kernel.\n");
+
+       return 0;
+}
+
+/*
+ * Smack requires early initialization in order to label
+ * all processes and objects when they are created.
+ */
+security_initcall(smack_init);
+
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c
new file mode 100644 (file)
index 0000000..15aa37f
--- /dev/null
@@ -0,0 +1,981 @@
+/*
+ * Copyright (C) 2007 Casey Schaufler <casey@schaufler-ca.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.
+ *
+ * Authors:
+ *     Casey Schaufler <casey@schaufler-ca.com>
+ *     Ahmed S. Darwish <darwish.07@gmail.com>
+ *
+ * Special thanks to the authors of selinuxfs.
+ *
+ *     Karl MacMillan <kmacmillan@tresys.com>
+ *     James Morris <jmorris@redhat.com>
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/vmalloc.h>
+#include <linux/security.h>
+#include <linux/mutex.h>
+#include <net/netlabel.h>
+#include <net/cipso_ipv4.h>
+#include <linux/seq_file.h>
+#include <linux/ctype.h>
+#include "smack.h"
+
+/*
+ * smackfs pseudo filesystem.
+ */
+
+enum smk_inos {
+       SMK_ROOT_INO    = 2,
+       SMK_LOAD        = 3,    /* load policy */
+       SMK_CIPSO       = 4,    /* load label -> CIPSO mapping */
+       SMK_DOI         = 5,    /* CIPSO DOI */
+       SMK_DIRECT      = 6,    /* CIPSO level indicating direct label */
+       SMK_AMBIENT     = 7,    /* internet ambient label */
+       SMK_NLTYPE      = 8,    /* label scheme to use by default */
+};
+
+/*
+ * List locks
+ */
+static DEFINE_MUTEX(smack_list_lock);
+static DEFINE_MUTEX(smack_cipso_lock);
+
+/*
+ * This is the "ambient" label for network traffic.
+ * If it isn't somehow marked, use this.
+ * It can be reset via smackfs/ambient
+ */
+char *smack_net_ambient = smack_known_floor.smk_known;
+
+/*
+ * This is the default packet marking scheme for network traffic.
+ * It can be reset via smackfs/nltype
+ */
+int smack_net_nltype = NETLBL_NLTYPE_CIPSOV4;
+
+/*
+ * This is the level in a CIPSO header that indicates a
+ * smack label is contained directly in the category set.
+ * It can be reset via smackfs/direct
+ */
+int smack_cipso_direct = SMACK_CIPSO_DIRECT_DEFAULT;
+
+static int smk_cipso_doi_value = SMACK_CIPSO_DOI_DEFAULT;
+struct smk_list_entry *smack_list;
+
+#define        SEQ_READ_FINISHED       1
+
+/*
+ * Disable concurrent writing open() operations
+ */
+static struct semaphore smack_write_sem;
+
+/*
+ * Values for parsing cipso rules
+ * SMK_DIGITLEN: Length of a digit field in a rule.
+ * SMK_CIPSOMEN: Minimum possible cipso rule length.
+ */
+#define SMK_DIGITLEN 4
+#define SMK_CIPSOMIN (SMK_MAXLEN + 2 * SMK_DIGITLEN)
+
+/*
+ * Seq_file read operations for /smack/load
+ */
+
+static void *load_seq_start(struct seq_file *s, loff_t *pos)
+{
+       if (*pos == SEQ_READ_FINISHED)
+               return NULL;
+
+       return smack_list;
+}
+
+static void *load_seq_next(struct seq_file *s, void *v, loff_t *pos)
+{
+       struct smk_list_entry *skp = ((struct smk_list_entry *) v)->smk_next;
+
+       if (skp == NULL)
+               *pos = SEQ_READ_FINISHED;
+
+       return skp;
+}
+
+static int load_seq_show(struct seq_file *s, void *v)
+{
+       struct smk_list_entry *slp = (struct smk_list_entry *) v;
+       struct smack_rule *srp = &slp->smk_rule;
+
+       seq_printf(s, "%s %s", (char *)srp->smk_subject,
+                  (char *)srp->smk_object);
+
+       seq_putc(s, ' ');
+
+       if (srp->smk_access & MAY_READ)
+               seq_putc(s, 'r');
+       if (srp->smk_access & MAY_WRITE)
+               seq_putc(s, 'w');
+       if (srp->smk_access & MAY_EXEC)
+               seq_putc(s, 'x');
+       if (srp->smk_access & MAY_APPEND)
+               seq_putc(s, 'a');
+       if (srp->smk_access == 0)
+               seq_putc(s, '-');
+
+       seq_putc(s, '\n');
+
+       return 0;
+}
+
+static void load_seq_stop(struct seq_file *s, void *v)
+{
+       /* No-op */
+}
+
+static struct seq_operations load_seq_ops = {
+       .start = load_seq_start,
+       .next  = load_seq_next,
+       .show  = load_seq_show,
+       .stop  = load_seq_stop,
+};
+
+/**
+ * smk_open_load - open() for /smack/load
+ * @inode: inode structure representing file
+ * @file: "load" file pointer
+ *
+ * For reading, use load_seq_* seq_file reading operations.
+ */
+static int smk_open_load(struct inode *inode, struct file *file)
+{
+       if ((file->f_flags & O_ACCMODE) == O_RDONLY)
+               return seq_open(file, &load_seq_ops);
+
+       if (down_interruptible(&smack_write_sem))
+               return -ERESTARTSYS;
+
+       return 0;
+}
+
+/**
+ * smk_release_load - release() for /smack/load
+ * @inode: inode structure representing file
+ * @file: "load" file pointer
+ *
+ * For a reading session, use the seq_file release
+ * implementation.
+ * Otherwise, we are at the end of a writing session so
+ * clean everything up.
+ */
+static int smk_release_load(struct inode *inode, struct file *file)
+{
+       if ((file->f_flags & O_ACCMODE) == O_RDONLY)
+               return seq_release(inode, file);
+
+       up(&smack_write_sem);
+       return 0;
+}
+
+/**
+ * smk_set_access - add a rule to the rule list
+ * @srp: the new rule to add
+ *
+ * Looks through the current subject/object/access list for
+ * the subject/object pair and replaces the access that was
+ * there. If the pair isn't found add it with the specified
+ * access.
+ */
+static void smk_set_access(struct smack_rule *srp)
+{
+       struct smk_list_entry *sp;
+       struct smk_list_entry *newp;
+
+       mutex_lock(&smack_list_lock);
+
+       for (sp = smack_list; sp != NULL; sp = sp->smk_next)
+               if (sp->smk_rule.smk_subject == srp->smk_subject &&
+                   sp->smk_rule.smk_object == srp->smk_object) {
+                       sp->smk_rule.smk_access = srp->smk_access;
+                       break;
+               }
+
+       if (sp == NULL) {
+               newp = kzalloc(sizeof(struct smk_list_entry), GFP_KERNEL);
+               newp->smk_rule = *srp;
+               newp->smk_next = smack_list;
+               smack_list = newp;
+       }
+
+       mutex_unlock(&smack_list_lock);
+
+       return;
+}
+
+/**
+ * smk_write_load - write() for /smack/load
+ * @filp: file pointer, not actually used
+ * @buf: where to get the data from
+ * @count: bytes sent
+ * @ppos: where to start - must be 0
+ *
+ * Get one smack access rule from above.
+ * The format is exactly:
+ *     char subject[SMK_LABELLEN]
+ *     char object[SMK_LABELLEN]
+ *     char access[SMK_ACCESSKINDS]
+ *
+ *     Anything following is commentary and ignored.
+ *
+ * writes must be SMK_LABELLEN+SMK_LABELLEN+4 bytes.
+ */
+#define MINIMUM_LOAD (SMK_LABELLEN + SMK_LABELLEN + SMK_ACCESSKINDS)
+
+static ssize_t smk_write_load(struct file *file, const char __user *buf,
+                             size_t count, loff_t *ppos)
+{
+       struct smack_rule rule;
+       char *data;
+       int rc = -EINVAL;
+
+       /*
+        * Must have privilege.
+        * No partial writes.
+        * Enough data must be present.
+        */
+       if (!capable(CAP_MAC_ADMIN))
+               return -EPERM;
+       if (*ppos != 0)
+               return -EINVAL;
+       if (count < MINIMUM_LOAD)
+               return -EINVAL;
+
+       data = kzalloc(count, GFP_KERNEL);
+       if (data == NULL)
+               return -ENOMEM;
+
+       if (copy_from_user(data, buf, count) != 0) {
+               rc = -EFAULT;
+               goto out;
+       }
+
+       rule.smk_subject = smk_import(data, 0);
+       if (rule.smk_subject == NULL)
+               goto out;
+
+       rule.smk_object = smk_import(data + SMK_LABELLEN, 0);
+       if (rule.smk_object == NULL)
+               goto out;
+
+       rule.smk_access = 0;
+
+       switch (data[SMK_LABELLEN + SMK_LABELLEN]) {
+       case '-':
+               break;
+       case 'r':
+       case 'R':
+               rule.smk_access |= MAY_READ;
+               break;
+       default:
+               goto out;
+       }
+
+       switch (data[SMK_LABELLEN + SMK_LABELLEN + 1]) {
+       case '-':
+               break;
+       case 'w':
+       case 'W':
+               rule.smk_access |= MAY_WRITE;
+               break;
+       default:
+               goto out;
+       }
+
+       switch (data[SMK_LABELLEN + SMK_LABELLEN + 2]) {
+       case '-':
+               break;
+       case 'x':
+       case 'X':
+               rule.smk_access |= MAY_EXEC;
+               break;
+       default:
+               goto out;
+       }
+
+       switch (data[SMK_LABELLEN + SMK_LABELLEN + 3]) {
+       case '-':
+               break;
+       case 'a':
+       case 'A':
+               rule.smk_access |= MAY_READ;
+               break;
+       default:
+               goto out;
+       }
+
+       smk_set_access(&rule);
+       rc = count;
+
+out:
+       kfree(data);
+       return rc;
+}
+
+static const struct file_operations smk_load_ops = {
+       .open           = smk_open_load,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .write          = smk_write_load,
+       .release        = smk_release_load,
+};
+
+/**
+ * smk_cipso_doi - initialize the CIPSO domain
+ */
+void smk_cipso_doi(void)
+{
+       int rc;
+       struct cipso_v4_doi *doip;
+       struct netlbl_audit audit_info;
+
+       rc = netlbl_cfg_map_del(NULL, &audit_info);
+       if (rc != 0)
+               printk(KERN_WARNING "%s:%d remove rc = %d\n",
+                      __func__, __LINE__, rc);
+
+       doip = kmalloc(sizeof(struct cipso_v4_doi), GFP_KERNEL);
+       if (doip == NULL)
+               panic("smack:  Failed to initialize cipso DOI.\n");
+       doip->map.std = NULL;
+       doip->doi = smk_cipso_doi_value;
+       doip->type = CIPSO_V4_MAP_PASS;
+       doip->tags[0] = CIPSO_V4_TAG_RBITMAP;
+       for (rc = 1; rc < CIPSO_V4_TAG_MAXCNT; rc++)
+               doip->tags[rc] = CIPSO_V4_TAG_INVALID;
+
+       rc = netlbl_cfg_cipsov4_add_map(doip, NULL, &audit_info);
+       if (rc != 0)
+               printk(KERN_WARNING "%s:%d add rc = %d\n",
+                      __func__, __LINE__, rc);
+}
+
+/*
+ * Seq_file read operations for /smack/cipso
+ */
+
+static void *cipso_seq_start(struct seq_file *s, loff_t *pos)
+{
+       if (*pos == SEQ_READ_FINISHED)
+               return NULL;
+
+       return smack_known;
+}
+
+static void *cipso_seq_next(struct seq_file *s, void *v, loff_t *pos)
+{
+       struct smack_known *skp = ((struct smack_known *) v)->smk_next;
+
+       /*
+        * Omit labels with no associated cipso value
+        */
+       while (skp != NULL && !skp->smk_cipso)
+               skp = skp->smk_next;
+
+       if (skp == NULL)
+               *pos = SEQ_READ_FINISHED;
+
+       return skp;
+}
+
+/*
+ * Print cipso labels in format:
+ * label level[/cat[,cat]]
+ */
+static int cipso_seq_show(struct seq_file *s, void *v)
+{
+       struct smack_known *skp = (struct smack_known *) v;
+       struct smack_cipso *scp = skp->smk_cipso;
+       char *cbp;
+       char sep = '/';
+       int cat = 1;
+       int i;
+       unsigned char m;
+
+       if (scp == NULL)
+               return 0;
+
+       seq_printf(s, "%s %3d", (char *)&skp->smk_known, scp->smk_level);
+
+       cbp = scp->smk_catset;
+       for (i = 0; i < SMK_LABELLEN; i++)
+               for (m = 0x80; m != 0; m >>= 1) {
+                       if (m & cbp[i]) {
+                               seq_printf(s, "%c%d", sep, cat);
+                               sep = ',';
+                       }
+                       cat++;
+               }
+
+       seq_putc(s, '\n');
+
+       return 0;
+}
+
+static void cipso_seq_stop(struct seq_file *s, void *v)
+{
+       /* No-op */
+}
+
+static struct seq_operations cipso_seq_ops = {
+       .start = cipso_seq_start,
+       .stop  = cipso_seq_stop,
+       .next  = cipso_seq_next,
+       .show  = cipso_seq_show,
+};
+
+/**
+ * smk_open_cipso - open() for /smack/cipso
+ * @inode: inode structure representing file
+ * @file: "cipso" file pointer
+ *
+ * Connect our cipso_seq_* operations with /smack/cipso
+ * file_operations
+ */
+static int smk_open_cipso(struct inode *inode, struct file *file)
+{
+       return seq_open(file, &cipso_seq_ops);
+}
+
+/**
+ * smk_write_cipso - write() for /smack/cipso
+ * @filp: file pointer, not actually used
+ * @buf: where to get the data from
+ * @count: bytes sent
+ * @ppos: where to start
+ *
+ * Accepts only one cipso rule per write call.
+ * Returns number of bytes written or error code, as appropriate
+ */
+static ssize_t smk_write_cipso(struct file *file, const char __user *buf,
+                              size_t count, loff_t *ppos)
+{
+       struct smack_known *skp;
+       struct smack_cipso *scp = NULL;
+       char mapcatset[SMK_LABELLEN];
+       int maplevel;
+       int cat;
+       int catlen;
+       ssize_t rc = -EINVAL;
+       char *data = NULL;
+       char *rule;
+       int ret;
+       int i;
+
+       /*
+        * Must have privilege.
+        * No partial writes.
+        * Enough data must be present.
+        */
+       if (!capable(CAP_MAC_ADMIN))
+               return -EPERM;
+       if (*ppos != 0)
+               return -EINVAL;
+       if (count <= SMK_CIPSOMIN)
+               return -EINVAL;
+
+       data = kzalloc(count + 1, GFP_KERNEL);
+       if (data == NULL)
+               return -ENOMEM;
+
+       if (copy_from_user(data, buf, count) != 0) {
+               rc = -EFAULT;
+               goto unlockedout;
+       }
+
+       data[count] = '\0';
+       rule = data;
+       /*
+        * Only allow one writer at a time. Writes should be
+        * quite rare and small in any case.
+        */
+       mutex_lock(&smack_cipso_lock);
+
+       skp = smk_import_entry(rule, 0);
+       if (skp == NULL)
+               goto out;
+
+       rule += SMK_LABELLEN;;
+       ret = sscanf(rule, "%d", &maplevel);
+       if (ret != 1 || maplevel > SMACK_CIPSO_MAXLEVEL)
+               goto out;
+
+       rule += SMK_DIGITLEN;
+       ret = sscanf(rule, "%d", &catlen);
+       if (ret != 1 || catlen > SMACK_CIPSO_MAXCATNUM)
+               goto out;
+
+       if (count <= (SMK_CIPSOMIN + catlen * SMK_DIGITLEN))
+               goto out;
+
+       memset(mapcatset, 0, sizeof(mapcatset));
+
+       for (i = 0; i < catlen; i++) {
+               rule += SMK_DIGITLEN;
+               ret = sscanf(rule, "%d", &cat);
+               if (ret != 1 || cat > SMACK_CIPSO_MAXCATVAL)
+                       goto out;
+
+               smack_catset_bit(cat, mapcatset);
+       }
+
+       if (skp->smk_cipso == NULL) {
+               scp = kzalloc(sizeof(struct smack_cipso), GFP_KERNEL);
+               if (scp == NULL) {
+                       rc = -ENOMEM;
+                       goto out;
+               }
+       }
+
+       spin_lock_bh(&skp->smk_cipsolock);
+
+       if (scp == NULL)
+               scp = skp->smk_cipso;
+       else
+               skp->smk_cipso = scp;
+
+       scp->smk_level = maplevel;
+       memcpy(scp->smk_catset, mapcatset, sizeof(mapcatset));
+
+       spin_unlock_bh(&skp->smk_cipsolock);
+
+       rc = count;
+out:
+       mutex_unlock(&smack_cipso_lock);
+unlockedout:
+       kfree(data);
+       return rc;
+}
+
+static const struct file_operations smk_cipso_ops = {
+       .open           = smk_open_cipso,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .write          = smk_write_cipso,
+       .release        = seq_release,
+};
+
+/**
+ * smk_read_doi - read() for /smack/doi
+ * @filp: file pointer, not actually used
+ * @buf: where to put the result
+ * @count: maximum to send along
+ * @ppos: where to start
+ *
+ * Returns number of bytes read or error code, as appropriate
+ */
+static ssize_t smk_read_doi(struct file *filp, char __user *buf,
+                           size_t count, loff_t *ppos)
+{
+       char temp[80];
+       ssize_t rc;
+
+       if (*ppos != 0)
+               return 0;
+
+       sprintf(temp, "%d", smk_cipso_doi_value);
+       rc = simple_read_from_buffer(buf, count, ppos, temp, strlen(temp));
+
+       return rc;
+}
+
+/**
+ * smk_write_doi - write() for /smack/doi
+ * @filp: file pointer, not actually used
+ * @buf: where to get the data from
+ * @count: bytes sent
+ * @ppos: where to start
+ *
+ * Returns number of bytes written or error code, as appropriate
+ */
+static ssize_t smk_write_doi(struct file *file, const char __user *buf,
+                            size_t count, loff_t *ppos)
+{
+       char temp[80];
+       int i;
+
+       if (!capable(CAP_MAC_ADMIN))
+               return -EPERM;
+
+       if (count >= sizeof(temp) || count == 0)
+               return -EINVAL;
+
+       if (copy_from_user(temp, buf, count) != 0)
+               return -EFAULT;
+
+       temp[count] = '\0';
+
+       if (sscanf(temp, "%d", &i) != 1)
+               return -EINVAL;
+
+       smk_cipso_doi_value = i;
+
+       smk_cipso_doi();
+
+       return count;
+}
+
+static const struct file_operations smk_doi_ops = {
+       .read           = smk_read_doi,
+       .write          = smk_write_doi,
+};
+
+/**
+ * smk_read_direct - read() for /smack/direct
+ * @filp: file pointer, not actually used
+ * @buf: where to put the result
+ * @count: maximum to send along
+ * @ppos: where to start
+ *
+ * Returns number of bytes read or error code, as appropriate
+ */
+static ssize_t smk_read_direct(struct file *filp, char __user *buf,
+                              size_t count, loff_t *ppos)
+{
+       char temp[80];
+       ssize_t rc;
+
+       if (*ppos != 0)
+               return 0;
+
+       sprintf(temp, "%d", smack_cipso_direct);
+       rc = simple_read_from_buffer(buf, count, ppos, temp, strlen(temp));
+
+       return rc;
+}
+
+/**
+ * smk_write_direct - write() for /smack/direct
+ * @filp: file pointer, not actually used
+ * @buf: where to get the data from
+ * @count: bytes sent
+ * @ppos: where to start
+ *
+ * Returns number of bytes written or error code, as appropriate
+ */
+static ssize_t smk_write_direct(struct file *file, const char __user *buf,
+                               size_t count, loff_t *ppos)
+{
+       char temp[80];
+       int i;
+
+       if (!capable(CAP_MAC_ADMIN))
+               return -EPERM;
+
+       if (count >= sizeof(temp) || count == 0)
+               return -EINVAL;
+
+       if (copy_from_user(temp, buf, count) != 0)
+               return -EFAULT;
+
+       temp[count] = '\0';
+
+       if (sscanf(temp, "%d", &i) != 1)
+               return -EINVAL;
+
+       smack_cipso_direct = i;
+
+       return count;
+}
+
+static const struct file_operations smk_direct_ops = {
+       .read           = smk_read_direct,
+       .write          = smk_write_direct,
+};
+
+/**
+ * smk_read_ambient - read() for /smack/ambient
+ * @filp: file pointer, not actually used
+ * @buf: where to put the result
+ * @cn: maximum to send along
+ * @ppos: where to start
+ *
+ * Returns number of bytes read or error code, as appropriate
+ */
+static ssize_t smk_read_ambient(struct file *filp, char __user *buf,
+                               size_t cn, loff_t *ppos)
+{
+       ssize_t rc;
+       char out[SMK_LABELLEN];
+       int asize;
+
+       if (*ppos != 0)
+               return 0;
+       /*
+        * Being careful to avoid a problem in the case where
+        * smack_net_ambient gets changed in midstream.
+        * Since smack_net_ambient is always set with a value
+        * from the label list, including initially, and those
+        * never get freed, the worst case is that the pointer
+        * gets changed just after this strncpy, in which case
+        * the value passed up is incorrect. Locking around
+        * smack_net_ambient wouldn't be any better than this
+        * copy scheme as by the time the caller got to look
+        * at the ambient value it would have cleared the lock
+        * and been changed.
+        */
+       strncpy(out, smack_net_ambient, SMK_LABELLEN);
+       asize = strlen(out) + 1;
+
+       if (cn < asize)
+               return -EINVAL;
+
+       rc = simple_read_from_buffer(buf, cn, ppos, out, asize);
+
+       return rc;
+}
+
+/**
+ * smk_write_ambient - write() for /smack/ambient
+ * @filp: file pointer, not actually used
+ * @buf: where to get the data from
+ * @count: bytes sent
+ * @ppos: where to start
+ *
+ * Returns number of bytes written or error code, as appropriate
+ */
+static ssize_t smk_write_ambient(struct file *file, const char __user *buf,
+                                size_t count, loff_t *ppos)
+{
+       char in[SMK_LABELLEN];
+       char *smack;
+
+       if (!capable(CAP_MAC_ADMIN))
+               return -EPERM;
+
+       if (count >= SMK_LABELLEN)
+               return -EINVAL;
+
+       if (copy_from_user(in, buf, count) != 0)
+               return -EFAULT;
+
+       smack = smk_import(in, count);
+       if (smack == NULL)
+               return -EINVAL;
+
+       smack_net_ambient = smack;
+
+       return count;
+}
+
+static const struct file_operations smk_ambient_ops = {
+       .read           = smk_read_ambient,
+       .write          = smk_write_ambient,
+};
+
+struct option_names {
+       int     o_number;
+       char    *o_name;
+       char    *o_alias;
+};
+
+static struct option_names netlbl_choices[] = {
+       { NETLBL_NLTYPE_RIPSO,
+               NETLBL_NLTYPE_RIPSO_NAME,       "ripso" },
+       { NETLBL_NLTYPE_CIPSOV4,
+               NETLBL_NLTYPE_CIPSOV4_NAME,     "cipsov4" },
+       { NETLBL_NLTYPE_CIPSOV4,
+               NETLBL_NLTYPE_CIPSOV4_NAME,     "cipso" },
+       { NETLBL_NLTYPE_CIPSOV6,
+               NETLBL_NLTYPE_CIPSOV6_NAME,     "cipsov6" },
+       { NETLBL_NLTYPE_UNLABELED,
+               NETLBL_NLTYPE_UNLABELED_NAME,   "unlabeled" },
+};
+
+/**
+ * smk_read_nltype - read() for /smack/nltype
+ * @filp: file pointer, not actually used
+ * @buf: where to put the result
+ * @count: maximum to send along
+ * @ppos: where to start
+ *
+ * Returns number of bytes read or error code, as appropriate
+ */
+static ssize_t smk_read_nltype(struct file *filp, char __user *buf,
+                              size_t count, loff_t *ppos)
+{
+       char bound[40];
+       ssize_t rc;
+       int i;
+
+       if (count < SMK_LABELLEN)
+               return -EINVAL;
+
+       if (*ppos != 0)
+               return 0;
+
+       sprintf(bound, "unknown");
+
+       for (i = 0; i < ARRAY_SIZE(netlbl_choices); i++)
+               if (smack_net_nltype == netlbl_choices[i].o_number) {
+                       sprintf(bound, "%s", netlbl_choices[i].o_name);
+                       break;
+               }
+
+       rc = simple_read_from_buffer(buf, count, ppos, bound, strlen(bound));
+
+       return rc;
+}
+
+/**
+ * smk_write_nltype - write() for /smack/nltype
+ * @filp: file pointer, not actually used
+ * @buf: where to get the data from
+ * @count: bytes sent
+ * @ppos: where to start
+ *
+ * Returns number of bytes written or error code, as appropriate
+ */
+static ssize_t smk_write_nltype(struct file *file, const char __user *buf,
+                               size_t count, loff_t *ppos)
+{
+       char bound[40];
+       char *cp;
+       int i;
+
+       if (!capable(CAP_MAC_ADMIN))
+               return -EPERM;
+
+       if (count >= 40)
+               return -EINVAL;
+
+       if (copy_from_user(bound, buf, count) != 0)
+               return -EFAULT;
+
+       bound[count] = '\0';
+       cp = strchr(bound, ' ');
+       if (cp != NULL)
+               *cp = '\0';
+       cp = strchr(bound, '\n');
+       if (cp != NULL)
+               *cp = '\0';
+
+       for (i = 0; i < ARRAY_SIZE(netlbl_choices); i++)
+               if (strcmp(bound, netlbl_choices[i].o_name) == 0 ||
+                   strcmp(bound, netlbl_choices[i].o_alias) == 0) {
+                       smack_net_nltype = netlbl_choices[i].o_number;
+                       return count;
+               }
+       /*
+        * Not a valid choice.
+        */
+       return -EINVAL;
+}
+
+static const struct file_operations smk_nltype_ops = {
+       .read           = smk_read_nltype,
+       .write          = smk_write_nltype,
+};
+
+/**
+ * smk_fill_super - fill the /smackfs superblock
+ * @sb: the empty superblock
+ * @data: unused
+ * @silent: unused
+ *
+ * Fill in the well known entries for /smack
+ *
+ * Returns 0 on success, an error code on failure
+ */
+static int smk_fill_super(struct super_block *sb, void *data, int silent)
+{
+       int rc;
+       struct inode *root_inode;
+
+       static struct tree_descr smack_files[] = {
+               [SMK_LOAD]      =
+                       {"load", &smk_load_ops, S_IRUGO|S_IWUSR},
+               [SMK_CIPSO]     =
+                       {"cipso", &smk_cipso_ops, S_IRUGO|S_IWUSR},
+               [SMK_DOI]       =
+                       {"doi", &smk_doi_ops, S_IRUGO|S_IWUSR},
+               [SMK_DIRECT]    =
+                       {"direct", &smk_direct_ops, S_IRUGO|S_IWUSR},
+               [SMK_AMBIENT]   =
+                       {"ambient", &smk_ambient_ops, S_IRUGO|S_IWUSR},
+               [SMK_NLTYPE]    =
+                       {"nltype", &smk_nltype_ops, S_IRUGO|S_IWUSR},
+               /* last one */ {""}
+       };
+
+       rc = simple_fill_super(sb, SMACK_MAGIC, smack_files);
+       if (rc != 0) {
+               printk(KERN_ERR "%s failed %d while creating inodes\n",
+                       __func__, rc);
+               return rc;
+       }
+
+       root_inode = sb->s_root->d_inode;
+       root_inode->i_security = new_inode_smack(smack_known_floor.smk_known);
+
+       return 0;
+}
+
+/**
+ * smk_get_sb - get the smackfs superblock
+ * @fs_type: passed along without comment
+ * @flags: passed along without comment
+ * @dev_name: passed along without comment
+ * @data: passed along without comment
+ * @mnt: passed along without comment
+ *
+ * Just passes everything along.
+ *
+ * Returns what the lower level code does.
+ */
+static int smk_get_sb(struct file_system_type *fs_type,
+                     int flags, const char *dev_name, void *data,
+                     struct vfsmount *mnt)
+{
+       return get_sb_single(fs_type, flags, data, smk_fill_super, mnt);
+}
+
+static struct file_system_type smk_fs_type = {
+       .name           = "smackfs",
+       .get_sb         = smk_get_sb,
+       .kill_sb        = kill_litter_super,
+};
+
+static struct vfsmount *smackfs_mount;
+
+/**
+ * init_smk_fs - get the smackfs superblock
+ *
+ * register the smackfs
+ *
+ * Returns 0 unless the registration fails.
+ */
+static int __init init_smk_fs(void)
+{
+       int err;
+
+       err = register_filesystem(&smk_fs_type);
+       if (!err) {
+               smackfs_mount = kern_mount(&smk_fs_type);
+               if (IS_ERR(smackfs_mount)) {
+                       printk(KERN_ERR "smackfs:  could not mount!\n");
+                       err = PTR_ERR(smackfs_mount);
+                       smackfs_mount = NULL;
+               }
+       }
+
+       sema_init(&smack_write_sem, 1);
+       smk_cipso_doi();
+
+       return err;
+}
+
+__initcall(init_smk_fs);
index 541b908f3cdf0075feebeb1b00672817adb2dc20..e08789484e3001e08e53acd481d97dcc37a7f88f 100644 (file)
@@ -10,8 +10,6 @@
 #define __AOA_H
 #include <asm/prom.h>
 #include <linux/module.h>
-/* So apparently there's a reason for requiring driver.h to be included first! */
-#include <sound/driver.h>
 #include <sound/core.h>
 #include <sound/asound.h>
 #include <sound/control.h>
index 71e3f93606580510dc5caf7c374f75ee45f1b460..6a3837d480e5efa33ba11efd9460dcdab725d835 100644 (file)
@@ -138,6 +138,13 @@ static int onyx_snd_vol_put(struct snd_kcontrol *kcontrol,
        struct onyx *onyx = snd_kcontrol_chip(kcontrol);
        s8 l, r;
 
+       if (ucontrol->value.integer.value[0] < -128 + VOLUME_RANGE_SHIFT ||
+           ucontrol->value.integer.value[0] > -1 + VOLUME_RANGE_SHIFT)
+               return -EINVAL;
+       if (ucontrol->value.integer.value[1] < -128 + VOLUME_RANGE_SHIFT ||
+           ucontrol->value.integer.value[1] > -1 + VOLUME_RANGE_SHIFT)
+               return -EINVAL;
+
        mutex_lock(&onyx->mutex);
        onyx_read_register(onyx, ONYX_REG_DAC_ATTEN_LEFT, &l);
        onyx_read_register(onyx, ONYX_REG_DAC_ATTEN_RIGHT, &r);
@@ -206,6 +213,9 @@ static int onyx_snd_inputgain_put(struct snd_kcontrol *kcontrol,
        struct onyx *onyx = snd_kcontrol_chip(kcontrol);
        u8 v, n;
 
+       if (ucontrol->value.integer.value[0] < 3 + INPUTGAIN_RANGE_SHIFT ||
+           ucontrol->value.integer.value[0] > 28 + INPUTGAIN_RANGE_SHIFT)
+               return -EINVAL;
        mutex_lock(&onyx->mutex);
        onyx_read_register(onyx, ONYX_REG_ADC_CONTROL, &v);
        n = v;
@@ -272,6 +282,8 @@ static void onyx_set_capture_source(struct onyx *onyx, int mic)
 static int onyx_snd_capture_source_put(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol)
 {
+       if (ucontrol->value.enumerated.item[0] > 1)
+               return -EINVAL;
        onyx_set_capture_source(snd_kcontrol_chip(kcontrol),
                                ucontrol->value.enumerated.item[0]);
        return 1;
index 70c341684794cb987189827ff0727c7b2273d5b5..7a16a3331f7e9efc6f12918cdb97f82e3d833b14 100644 (file)
@@ -248,6 +248,13 @@ static int tas_snd_vol_put(struct snd_kcontrol *kcontrol,
 {
        struct tas *tas = snd_kcontrol_chip(kcontrol);
 
+       if (ucontrol->value.integer.value[0] < 0 ||
+           ucontrol->value.integer.value[0] > 177)
+               return -EINVAL;
+       if (ucontrol->value.integer.value[1] < 0 ||
+           ucontrol->value.integer.value[1] > 177)
+               return -EINVAL;
+
        mutex_lock(&tas->mtx);
        if (tas->cached_volume_l == ucontrol->value.integer.value[0]
         && tas->cached_volume_r == ucontrol->value.integer.value[1]) {
@@ -401,6 +408,10 @@ static int tas_snd_drc_range_put(struct snd_kcontrol *kcontrol,
 {
        struct tas *tas = snd_kcontrol_chip(kcontrol);
 
+       if (ucontrol->value.integer.value[0] < 0 ||
+           ucontrol->value.integer.value[0] > TAS3004_DRC_MAX)
+               return -EINVAL;
+
        mutex_lock(&tas->mtx);
        if (tas->drc_range == ucontrol->value.integer.value[0]) {
                mutex_unlock(&tas->mtx);
@@ -447,7 +458,7 @@ static int tas_snd_drc_switch_put(struct snd_kcontrol *kcontrol,
                return 0;
        }
 
-       tas->drc_enabled = ucontrol->value.integer.value[0];
+       tas->drc_enabled = !!ucontrol->value.integer.value[0];
        if (tas->hw_enabled)
                tas3004_set_drc(tas);
        mutex_unlock(&tas->mtx);
@@ -494,6 +505,8 @@ static int tas_snd_capture_source_put(struct snd_kcontrol *kcontrol,
        struct tas *tas = snd_kcontrol_chip(kcontrol);
        int oldacr;
 
+       if (ucontrol->value.enumerated.item[0] > 1)
+               return -EINVAL;
        mutex_lock(&tas->mtx);
        oldacr = tas->acr;
 
@@ -562,6 +575,9 @@ static int tas_snd_treble_put(struct snd_kcontrol *kcontrol,
 {
        struct tas *tas = snd_kcontrol_chip(kcontrol);
 
+       if (ucontrol->value.integer.value[0] < TAS3004_TREBLE_MIN ||
+           ucontrol->value.integer.value[0] > TAS3004_TREBLE_MAX)
+               return -EINVAL;
        mutex_lock(&tas->mtx);
        if (tas->treble == ucontrol->value.integer.value[0]) {
                mutex_unlock(&tas->mtx);
@@ -610,6 +626,9 @@ static int tas_snd_bass_put(struct snd_kcontrol *kcontrol,
 {
        struct tas *tas = snd_kcontrol_chip(kcontrol);
 
+       if (ucontrol->value.integer.value[0] < TAS3004_BASS_MIN ||
+           ucontrol->value.integer.value[0] > TAS3004_BASS_MAX)
+               return -EINVAL;
        mutex_lock(&tas->mtx);
        if (tas->bass == ucontrol->value.integer.value[0]) {
                mutex_unlock(&tas->mtx);
index 8b2ba99d7f8a2640018266ba2659dc122463914a..dea7abb082cd1a5efd4038d2756147a852bd7760 100644 (file)
@@ -600,7 +600,7 @@ static int n##_control_put(struct snd_kcontrol *kcontrol,           \
        struct gpio_runtime *gpio = snd_kcontrol_chip(kcontrol);        \
        if (gpio->methods && gpio->methods->get_##n)                    \
                gpio->methods->set_##n(gpio,                            \
-                       ucontrol->value.integer.value[0]);              \
+                       !!ucontrol->value.integer.value[0]);            \
        return 1;                                                       \
 }                                                                      \
 static struct snd_kcontrol_new n##_ctl = {                             \
index efb9441b3acf2e48deb8543bb4467d4c3cb72a9f..e6beb92c6933f9df991af076f3ed17fb7b36b214 100644 (file)
@@ -11,7 +11,6 @@
 #include <linux/interrupt.h>
 #include <linux/dma-mapping.h>
 
-#include <sound/driver.h>
 #include <sound/core.h>
 
 #include <asm/macio.h>
index c6b42f9bdbc9e92eefb3bc3426bb970f297ebd2d..59bacd365733f869513df9cdb81797ad7389cfba 100644 (file)
@@ -8,9 +8,6 @@
 
 #include <asm/io.h>
 #include <linux/delay.h>
-/* So apparently there's a reason for requiring driver.h
- * to be included first, even if I don't know it... */
-#include <sound/driver.h>
 #include <sound/core.h>
 #include <asm/macio.h>
 #include <linux/pci.h>
@@ -194,6 +191,12 @@ static int i2sbus_pcm_open(struct i2sbus_dev *i2sdev, int in)
        hw->period_bytes_max = 16384;
        hw->periods_min = 3;
        hw->periods_max = MAX_DBDMA_COMMANDS;
+       err = snd_pcm_hw_constraint_integer(pi->substream->runtime,
+                                           SNDRV_PCM_HW_PARAM_PERIODS);
+       if (err < 0) {
+               result = err;
+               goto out_unlock;
+       }
        list_for_each_entry(cii, &sdev->codec_list, list) {
                if (cii->codec->open) {
                        err = cii->codec->open(cii, pi->substream);
@@ -990,6 +993,7 @@ i2sbus_attach_codec(struct soundbus_dev *dev, struct snd_card *card,
                if (dev->pcm->card != card) {
                        printk(KERN_ERR
                               "Can't attach same bus to different cards!\n");
+                       err = -EINVAL;
                        goto out_put_ci_module;
                }
                err = snd_pcm_new_stream(dev->pcm, SNDRV_PCM_STREAM_CAPTURE, 1);
index 3b73ba7d03e85ea96012225d43ff5491d1312e0b..b0a474494966d42b97b5547c4b250b65e4face8e 100644 (file)
@@ -23,7 +23,6 @@
 #include <asm/irq.h>
 #include <asm/sizes.h>
 
-#include <sound/driver.h>
 #include <sound/core.h>
 #include <sound/initval.h>
 #include <sound/ac97_codec.h>
index ca3bf4ee05a380bfe910dde8eec7c89dd98bfa49..9d1e6665b546c07b88d6b8a1eda77f23ce9d7289 100644 (file)
@@ -12,7 +12,6 @@
 #include <linux/device.h>
 #include <linux/dma-mapping.h>
 
-#include <sound/driver.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 
index 55c6c822bec13eb82cb18a764b28678bf2c31558..5d86e6809752e701218531deb29088f2f5517855 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/wait.h>
 #include <linux/delay.h>
 
-#include <sound/driver.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/ac97_codec.h>
@@ -352,6 +351,7 @@ static int __devinit pxa2xx_ac97_probe(struct platform_device *dev)
        snprintf(card->longname, sizeof(card->longname),
                 "%s (%s)", dev->dev.driver->name, card->mixername);
 
+       snd_card_set_dev(card, &dev->dev);
        ret = snd_card_register(card);
        if (ret == 0) {
                platform_set_drvdata(dev, card);
index e8cf904b835804dc7329ec35d0eaca216a9ce188..0ede9e4656a89cb323cb76ac96df3b9f8e9bdb91 100644 (file)
@@ -16,7 +16,6 @@
 #include <linux/slab.h>
 #include <linux/dma-mapping.h>
 
-#include <sound/driver.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
index 81c64b09d3592168ac544e14ba1478bcc907e463..0eff33ca0f793742b97546deea5fa03b27dab220 100644 (file)
@@ -59,7 +59,6 @@
 * 
 ***************************************************************************************************/
 
-#include <sound/driver.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/init.h>
index df0774c76f6fc4eba16eb5abc0863ac01bbcedbc..01a1a5af47bb7749e90370c7ff92dbae528b6199 100644 (file)
@@ -19,7 +19,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/threads.h>
 #include <linux/interrupt.h>
 #include <linux/slab.h>
@@ -232,8 +231,6 @@ struct snd_kcontrol *snd_ctl_new1(const struct snd_kcontrol_new *ncontrol,
        access = ncontrol->access == 0 ? SNDRV_CTL_ELEM_ACCESS_READWRITE :
                 (ncontrol->access & (SNDRV_CTL_ELEM_ACCESS_READWRITE|
                                      SNDRV_CTL_ELEM_ACCESS_INACTIVE|
-                                     SNDRV_CTL_ELEM_ACCESS_DINDIRECT|
-                                     SNDRV_CTL_ELEM_ACCESS_INDIRECT|
                                      SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE|
                                      SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK));
        kctl.info = ncontrol->info;
@@ -692,7 +689,7 @@ int snd_ctl_elem_read(struct snd_card *card, struct snd_ctl_elem_value *control)
        struct snd_kcontrol *kctl;
        struct snd_kcontrol_volatile *vd;
        unsigned int index_offset;
-       int result, indirect;
+       int result;
 
        down_read(&card->controls_rwsem);
        kctl = snd_ctl_find_id(card, &control->id);
@@ -701,17 +698,12 @@ int snd_ctl_elem_read(struct snd_card *card, struct snd_ctl_elem_value *control)
        } else {
                index_offset = snd_ctl_get_ioff(kctl, &control->id);
                vd = &kctl->vd[index_offset];
-               indirect = vd->access & SNDRV_CTL_ELEM_ACCESS_INDIRECT ? 1 : 0;
-               if (control->indirect != indirect) {
-                       result = -EACCES;
-               } else {
-                       if ((vd->access & SNDRV_CTL_ELEM_ACCESS_READ) && kctl->get != NULL) {
-                               snd_ctl_build_ioff(&control->id, kctl, index_offset);
-                               result = kctl->get(kctl, control);
-                       } else {
-                               result = -EPERM;
-                       }
-               }
+               if ((vd->access & SNDRV_CTL_ELEM_ACCESS_READ) &&
+                   kctl->get != NULL) {
+                       snd_ctl_build_ioff(&control->id, kctl, index_offset);
+                       result = kctl->get(kctl, control);
+               } else
+                       result = -EPERM;
        }
        up_read(&card->controls_rwsem);
        return result;
@@ -748,7 +740,7 @@ int snd_ctl_elem_write(struct snd_card *card, struct snd_ctl_file *file,
        struct snd_kcontrol *kctl;
        struct snd_kcontrol_volatile *vd;
        unsigned int index_offset;
-       int result, indirect;
+       int result;
 
        down_read(&card->controls_rwsem);
        kctl = snd_ctl_find_id(card, &control->id);
@@ -757,23 +749,19 @@ int snd_ctl_elem_write(struct snd_card *card, struct snd_ctl_file *file,
        } else {
                index_offset = snd_ctl_get_ioff(kctl, &control->id);
                vd = &kctl->vd[index_offset];
-               indirect = vd->access & SNDRV_CTL_ELEM_ACCESS_INDIRECT ? 1 : 0;
-               if (control->indirect != indirect) {
-                       result = -EACCES;
+               if (!(vd->access & SNDRV_CTL_ELEM_ACCESS_WRITE) ||
+                   kctl->put == NULL ||
+                   (file && vd->owner && vd->owner != file)) {
+                       result = -EPERM;
                } else {
-                       if (!(vd->access & SNDRV_CTL_ELEM_ACCESS_WRITE) ||
-                           kctl->put == NULL ||
-                           (file && vd->owner != NULL && vd->owner != file)) {
-                               result = -EPERM;
-                       } else {
-                               snd_ctl_build_ioff(&control->id, kctl, index_offset);
-                               result = kctl->put(kctl, control);
-                       }
-                       if (result > 0) {
-                               up_read(&card->controls_rwsem);
-                               snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &control->id);
-                               return 0;
-                       }
+                       snd_ctl_build_ioff(&control->id, kctl, index_offset);
+                       result = kctl->put(kctl, control);
+               }
+               if (result > 0) {
+                       up_read(&card->controls_rwsem);
+                       snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
+                                      &control->id);
+                       return 0;
                }
        }
        up_read(&card->controls_rwsem);
index 9311ca397bbc20ed62d3c5e092dd6df5ed3b1d8f..6101259ad860e1b05260f36faa42758944ebc088 100644 (file)
@@ -219,7 +219,8 @@ static int copy_ctl_value_from_user(struct snd_card *card,
                                    struct snd_ctl_elem_value32 __user *data32,
                                    int *typep, int *countp)
 {
-       int i, type, count, size;
+       int i, type, size;
+       int uninitialized_var(count);
        unsigned int indirect;
 
        if (copy_from_user(&data->id, &data32->id, sizeof(data->id)))
index ea1a0621eefb6680ccd885b014005281ad455820..202dac0e4d895b51f1fde72486b393a32c3ceed7 100644 (file)
@@ -19,7 +19,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/slab.h>
 #include <linux/time.h>
 #include <linux/errno.h>
index bfd9d182b8a33ac3c85ec3067c51ee4642404d30..6d6589f93899035587570807bd46bc5325425962 100644 (file)
@@ -19,7 +19,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/major.h>
 #include <linux/init.h>
 #include <linux/slab.h>
index 1ffd29bb4cd06c25759d7959005d19e1ab1e0427..9977ec2eace35d547772db031c0db29bed15fe37 100644 (file)
@@ -19,7 +19,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/time.h>
 #include <linux/smp_lock.h>
index 435c9399f7a94aa51aad11f2826993e395158639..e35789a92752da3b48cf034b8e058b8fc9bfbfeb 100644 (file)
@@ -19,7 +19,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/slab.h>
 #include <linux/time.h>
 #include <linux/string.h>
@@ -66,8 +65,6 @@ int snd_oss_info_register(int dev, int num, char *string)
 
 EXPORT_SYMBOL(snd_oss_info_register);
 
-extern void snd_card_info_read_oss(struct snd_info_buffer *buffer);
-
 static int snd_sndstat_show_strings(struct snd_info_buffer *buf, char *id, int dev)
 {
        int idx, ok = -1;
index 2cb7099eb1e1b994fa12f7c24da0189f98c5fa5a..e3338d6071efb993ae9370bf634fdf28ebb27e42 100644 (file)
@@ -19,7 +19,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/sched.h>
 #include <linux/file.h>
@@ -43,6 +42,40 @@ EXPORT_SYMBOL(snd_cards);
 
 static DEFINE_MUTEX(snd_card_mutex);
 
+static char *slots[SNDRV_CARDS];
+module_param_array(slots, charp, NULL, 0444);
+MODULE_PARM_DESC(slots, "Module names assigned to the slots.");
+
+/* return non-zero if the given index is already reserved for another
+ * module via slots option
+ */
+static int module_slot_mismatch(struct module *module, int idx)
+{
+#ifdef MODULE
+       char *s1, *s2;
+       if (!module || !module->name || !slots[idx])
+               return 0;
+       s1 = slots[idx];
+       s2 = module->name;
+       /* compare module name strings
+        * hyphens are handled as equivalent with underscore
+        */
+       for (;;) {
+               char c1 = *s1++;
+               char c2 = *s2++;
+               if (c1 == '-')
+                       c1 = '_';
+               if (c2 == '-')
+                       c2 = '_';
+               if (c1 != c2)
+                       return 1;
+               if (!c1)
+                       break;
+       }
+#endif
+       return 0;
+}
+
 #if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE)
 int (*snd_mixer_oss_notify_callback)(struct snd_card *card, int free_flag);
 EXPORT_SYMBOL(snd_mixer_oss_notify_callback);
@@ -115,6 +148,8 @@ struct snd_card *snd_card_new(int idx, const char *xid,
                for (idx2 = 0; idx2 < SNDRV_CARDS; idx2++)
                        /* idx == -1 == 0xffff means: take any free slot */
                        if (~snd_cards_lock & idx & 1<<idx2) {
+                               if (module_slot_mismatch(module, idx2))
+                                       continue;
                                idx = idx2;
                                if (idx >= snd_ecards_limit)
                                        snd_ecards_limit = idx + 1;
@@ -304,8 +339,8 @@ int snd_card_disconnect(struct snd_card *card)
                list_add(&mfile->shutdown_list, &shutdown_files);
                spin_unlock(&shutdown_lock);
 
-               fops_get(&snd_shutdown_f_ops);
                mfile->file->f_op = &snd_shutdown_f_ops;
+               fops_get(mfile->file->f_op);
                
                mfile = mfile->next;
        }
index eb173cef4f05e3925565090e048b8be0d3e161bb..79f0f16af33930a8151a15c26a7d79bee7b8d69b 100644 (file)
@@ -26,7 +26,6 @@
 
 #undef HAVE_REALLY_SLOW_DMA_CONTROLLER
 
-#include <sound/driver.h>
 #include <sound/core.h>
 #include <asm/dma.h>
 
index 9b4992eab479defd06cb28663ff448beb047be79..920e5780c2284c9c086dd1bfaf02aff5462786d2 100644 (file)
@@ -568,6 +568,7 @@ static ssize_t snd_mem_proc_write(struct file *file, const char __user * buffer,
                                if (pci_set_dma_mask(pci, mask) < 0 ||
                                    pci_set_consistent_dma_mask(pci, mask) < 0) {
                                        printk(KERN_ERR "snd-page-alloc: cannot set DMA mask %lx for pci %04x:%04x\n", mask, vendor, device);
+                                       pci_dev_put(pci);
                                        return count;
                                }
                        }
index 25b0f056563e79ed8d339202f617a33434b0f6f4..1161158582a6ce112ab3a7329b2ad09507b57979 100644 (file)
@@ -20,9 +20,9 @@
  *
  */
 
-#include <linux/module.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
+#include <sound/core.h>
 
 /**
  * copy_to_user_fromio - copy data from mmio-space to user-space
index 6cabab8cc5374993d0e856d340d8894c4d965596..102d1c36cf26a67386258e28022760b5669844c2 100644 (file)
@@ -19,7 +19,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/time.h>
 #include <linux/ioport.h>
index d6a04c2d5a75a7933fd5d7f9c51008a08536565a..9ded30d0e97da413c1ec244ec8aa205d0b010254 100644 (file)
@@ -19,7 +19,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/time.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
index 3ece39fc48dbaff2a8c06e4ef9cf0f62f73a32a7..f874f6ca3657037121e1084858c9d002bbef3b44 100644 (file)
@@ -19,7 +19,6 @@
  *
  */
   
-#include <sound/driver.h>
 #include <linux/time.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
index 06f96a3e86f675dded23ca2adaa20b59f3b31d52..da3dbd41669eb9556699cfe3e7d1c9cbb20896b3 100644 (file)
@@ -20,7 +20,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/time.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
index c5a5ab9cae8cace6edc773a4eb9a3e9b3a700f9a..75daed298a15a251fcf3a4af20b4651b905326ea 100644 (file)
@@ -19,7 +19,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/time.h>
index 848db82529ed26ca17cc9674e754cc1e27c011c0..77f96194a0eda5eff6ed2cb3e66ae32d5207f88f 100644 (file)
@@ -21,7 +21,6 @@
  *
  */
   
-#include <sound/driver.h>
 #include <linux/time.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
index d0c4ceb9f0b4e55efaff4e16dc2fc585df81a3a4..4c601b192ddf3feb4117186d230a73f4538f1723 100644 (file)
@@ -26,7 +26,6 @@
 #define OSS_DEBUG
 #endif
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/time.h>
@@ -985,10 +984,8 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream)
                sw_params->stop_threshold = runtime->buffer_size;
        sw_params->tstamp_mode = SNDRV_PCM_TSTAMP_NONE;
        sw_params->period_step = 1;
-       sw_params->sleep_min = 0;
        sw_params->avail_min = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
                1 : runtime->period_size;
-       sw_params->xfer_align = 1;
        if (atomic_read(&substream->mmap_count) ||
            substream->oss.setup.nosilence) {
                sw_params->silence_threshold = 0;
@@ -1624,6 +1621,7 @@ static int snd_pcm_oss_sync(struct snd_pcm_oss_file *pcm_oss_file)
                                        snd_pcm_format_set_silence(runtime->format,
                                                                   runtime->oss.buffer,
                                                                   size1);
+                                       size1 /= runtime->channels; /* frames */
                                        fs = snd_enter_user();
                                        snd_pcm_lib_write(substream, (void __user *)runtime->oss.buffer, size1);
                                        snd_leave_user(fs);
index 14095a927a1b1b6e9ab7ccf7cded095be969d43c..bec94138205edf3aad8266d7239100a5aef3d8a3 100644 (file)
@@ -24,7 +24,6 @@
 #define PLUGIN_DEBUG
 #endif
 
-#include <sound/driver.h>
 #include <linux/slab.h>
 #include <linux/time.h>
 #include <linux/vmalloc.h>
index 9eb267913c3814fcb1c194670bb0b208bf06fc33..14dfb3175d84548f9ef1ccdcde84517cb137a635 100644 (file)
@@ -19,7 +19,6 @@
  *
  */
   
-#include <sound/driver.h>
 #include <linux/time.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
index de3ffdeaf7e346de505337c3461a9979e5ce0224..da7ab7a3e82cdd51d51a11cc3e2bf935bbc464c9 100644 (file)
@@ -19,7 +19,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/slab.h>
 #include <linux/time.h>
 #include <sound/core.h>
index cf9b9493d41deba8810dfe266353e294d7d05af1..9dd9bc73fe1d6ab8b568fa1ce865650f52bae72f 100644 (file)
@@ -19,7 +19,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/time.h>
@@ -228,7 +227,7 @@ static char *snd_pcm_subformat_names[] = {
 
 static char *snd_pcm_tstamp_mode_names[] = {
        TSTAMP(NONE),
-       TSTAMP(MMAP),
+       TSTAMP(ENABLE),
 };
 
 static const char *snd_pcm_stream_name(int stream)
@@ -359,7 +358,6 @@ static void snd_pcm_substream_proc_hw_params_read(struct snd_info_entry *entry,
        snd_iprintf(buffer, "rate: %u (%u/%u)\n", runtime->rate, runtime->rate_num, runtime->rate_den); 
        snd_iprintf(buffer, "period_size: %lu\n", runtime->period_size);        
        snd_iprintf(buffer, "buffer_size: %lu\n", runtime->buffer_size);        
-       snd_iprintf(buffer, "tick_time: %u\n", runtime->tick_time);
 #if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
        if (substream->oss.oss) {
                snd_iprintf(buffer, "OSS format: %s\n", snd_pcm_oss_format_name(runtime->oss.format));
@@ -387,9 +385,7 @@ static void snd_pcm_substream_proc_sw_params_read(struct snd_info_entry *entry,
        }
        snd_iprintf(buffer, "tstamp_mode: %s\n", snd_pcm_tstamp_mode_name(runtime->tstamp_mode));
        snd_iprintf(buffer, "period_step: %u\n", runtime->period_step);
-       snd_iprintf(buffer, "sleep_min: %u\n", runtime->sleep_min);
        snd_iprintf(buffer, "avail_min: %lu\n", runtime->control->avail_min);
-       snd_iprintf(buffer, "xfer_align: %lu\n", runtime->xfer_align);
        snd_iprintf(buffer, "start_threshold: %lu\n", runtime->start_threshold);
        snd_iprintf(buffer, "stop_threshold: %lu\n", runtime->stop_threshold);
        snd_iprintf(buffer, "silence_threshold: %lu\n", runtime->silence_threshold);
@@ -765,12 +761,6 @@ static int snd_pcm_dev_free(struct snd_device *device)
        return snd_pcm_free(pcm);
 }
 
-static void snd_pcm_tick_timer_func(unsigned long data)
-{
-       struct snd_pcm_substream *substream = (struct snd_pcm_substream *) data;
-       snd_pcm_tick_elapsed(substream);
-}
-
 int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream,
                             struct file *file,
                             struct snd_pcm_substream **rsubstream)
@@ -877,9 +867,6 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream,
        memset((void*)runtime->control, 0, size);
 
        init_waitqueue_head(&runtime->sleep);
-       init_timer(&runtime->tick_timer);
-       runtime->tick_timer.function = snd_pcm_tick_timer_func;
-       runtime->tick_timer.data = (unsigned long) substream;
 
        runtime->status->state = SNDRV_PCM_STATE_OPEN;
 
index 2b539799d23b7a88a10f1583281b7f2263b55786..49aa693fba8adb8507d892a3fdc8081960d8c4ce 100644 (file)
@@ -484,6 +484,7 @@ static long snd_pcm_ioctl_compat(struct file *file, unsigned int cmd, unsigned l
        case SNDRV_PCM_IOCTL_PVERSION:
        case SNDRV_PCM_IOCTL_INFO:
        case SNDRV_PCM_IOCTL_TSTAMP:
+       case SNDRV_PCM_IOCTL_TTSTAMP:
        case SNDRV_PCM_IOCTL_HWSYNC:
        case SNDRV_PCM_IOCTL_PREPARE:
        case SNDRV_PCM_IOCTL_RESET:
index 806f1fba5446d1f639309d203f55d2de2db268cc..1533f0379e9d57abe850c0e636952afa5ccc397c 100644 (file)
@@ -20,7 +20,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/slab.h>
 #include <linux/time.h>
 #include <sound/core.h>
@@ -145,11 +144,11 @@ static inline snd_pcm_uframes_t snd_pcm_update_hw_ptr_pos(struct snd_pcm_substre
 {
        snd_pcm_uframes_t pos;
 
+       if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE)
+               snd_pcm_gettime(runtime, (struct timespec *)&runtime->status->tstamp);
        pos = substream->ops->pointer(substream);
        if (pos == SNDRV_PCM_POS_XRUN)
                return pos; /* XRUN */
-       if (runtime->tstamp_mode & SNDRV_PCM_TSTAMP_MMAP)
-               getnstimeofday((struct timespec *)&runtime->status->tstamp);
 #ifdef CONFIG_SND_DEBUG
        if (pos >= runtime->buffer_size) {
                snd_printk(KERN_ERR  "BUG: stream = %i, pos = 0x%lx, buffer size = 0x%lx, period size = 0x%lx\n", substream->stream, pos, runtime->buffer_size, runtime->period_size);
@@ -1139,7 +1138,7 @@ EXPORT_SYMBOL(snd_pcm_hw_constraint_step);
 
 static int snd_pcm_hw_rule_pow2(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule)
 {
-       static int pow2_sizes[] = {
+       static unsigned int pow2_sizes[] = {
                1<<0, 1<<1, 1<<2, 1<<3, 1<<4, 1<<5, 1<<6, 1<<7,
                1<<8, 1<<9, 1<<10, 1<<11, 1<<12, 1<<13, 1<<14, 1<<15,
                1<<16, 1<<17, 1<<18, 1<<19, 1<<20, 1<<21, 1<<22, 1<<23,
@@ -1451,108 +1450,13 @@ int snd_pcm_lib_ioctl(struct snd_pcm_substream *substream,
 
 EXPORT_SYMBOL(snd_pcm_lib_ioctl);
 
-/*
- *  Conditions
- */
-
-static void snd_pcm_system_tick_set(struct snd_pcm_substream *substream, 
-                                   unsigned long ticks)
-{
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       if (ticks == 0)
-               del_timer(&runtime->tick_timer);
-       else {
-               ticks += (1000000 / HZ) - 1;
-               ticks /= (1000000 / HZ);
-               mod_timer(&runtime->tick_timer, jiffies + ticks);
-       }
-}
-
-/* Temporary alias */
-void snd_pcm_tick_set(struct snd_pcm_substream *substream, unsigned long ticks)
-{
-       snd_pcm_system_tick_set(substream, ticks);
-}
-
-void snd_pcm_tick_prepare(struct snd_pcm_substream *substream)
-{
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       snd_pcm_uframes_t frames = ULONG_MAX;
-       snd_pcm_uframes_t avail, dist;
-       unsigned int ticks;
-       u_int64_t n;
-       u_int32_t r;
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               if (runtime->silence_size >= runtime->boundary) {
-                       frames = 1;
-               } else if (runtime->silence_size > 0 &&
-                          runtime->silence_filled < runtime->buffer_size) {
-                       snd_pcm_sframes_t noise_dist;
-                       noise_dist = snd_pcm_playback_hw_avail(runtime) + runtime->silence_filled;
-                       if (noise_dist > (snd_pcm_sframes_t)runtime->silence_threshold)
-                               frames = noise_dist - runtime->silence_threshold;
-               }
-               avail = snd_pcm_playback_avail(runtime);
-       } else {
-               avail = snd_pcm_capture_avail(runtime);
-       }
-       if (avail < runtime->control->avail_min) {
-               snd_pcm_sframes_t n = runtime->control->avail_min - avail;
-               if (n > 0 && frames > (snd_pcm_uframes_t)n)
-                       frames = n;
-       }
-       if (avail < runtime->buffer_size) {
-               snd_pcm_sframes_t n = runtime->buffer_size - avail;
-               if (n > 0 && frames > (snd_pcm_uframes_t)n)
-                       frames = n;
-       }
-       if (frames == ULONG_MAX) {
-               snd_pcm_tick_set(substream, 0);
-               return;
-       }
-       dist = runtime->status->hw_ptr - runtime->hw_ptr_base;
-       /* Distance to next interrupt */
-       dist = runtime->period_size - dist % runtime->period_size;
-       if (dist <= frames) {
-               snd_pcm_tick_set(substream, 0);
-               return;
-       }
-       /* the base time is us */
-       n = frames;
-       n *= 1000000;
-       div64_32(&n, runtime->tick_time * runtime->rate, &r);
-       ticks = n + (r > 0 ? 1 : 0);
-       if (ticks < runtime->sleep_min)
-               ticks = runtime->sleep_min;
-       snd_pcm_tick_set(substream, (unsigned long) ticks);
-}
-
-void snd_pcm_tick_elapsed(struct snd_pcm_substream *substream)
-{
-       struct snd_pcm_runtime *runtime;
-       unsigned long flags;
-       
-       snd_assert(substream != NULL, return);
-       runtime = substream->runtime;
-       snd_assert(runtime != NULL, return);
-
-       snd_pcm_stream_lock_irqsave(substream, flags);
-       if (!snd_pcm_running(substream) ||
-           snd_pcm_update_hw_ptr(substream) < 0)
-               goto _end;
-       if (runtime->sleep_min)
-               snd_pcm_tick_prepare(substream);
- _end:
-       snd_pcm_stream_unlock_irqrestore(substream, flags);
-}
-
 /**
  * snd_pcm_period_elapsed - update the pcm status for the next period
  * @substream: the pcm substream instance
  *
  * This function is called from the interrupt handler when the
  * PCM has processed the period size.  It will update the current
- * pointer, set up the tick, wake up sleepers, etc.
+ * pointer, wake up sleepers, etc.
  *
  * Even if more than one periods have elapsed since the last call, you
  * have to call this only once.
@@ -1576,8 +1480,6 @@ void snd_pcm_period_elapsed(struct snd_pcm_substream *substream)
 
        if (substream->timer_running)
                snd_timer_interrupt(substream->timer, 1);
-       if (runtime->sleep_min)
-               snd_pcm_tick_prepare(substream);
  _end:
        snd_pcm_stream_unlock_irqrestore(substream, flags);
        if (runtime->transfer_ack_end)
@@ -1587,6 +1489,71 @@ void snd_pcm_period_elapsed(struct snd_pcm_substream *substream)
 
 EXPORT_SYMBOL(snd_pcm_period_elapsed);
 
+/*
+ * Wait until avail_min data becomes available
+ * Returns a negative error code if any error occurs during operation.
+ * The available space is stored on availp.  When err = 0 and avail = 0
+ * on the capture stream, it indicates the stream is in DRAINING state.
+ */
+static int wait_for_avail_min(struct snd_pcm_substream *substream,
+                             snd_pcm_uframes_t *availp)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       int is_playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+       wait_queue_t wait;
+       int err = 0;
+       snd_pcm_uframes_t avail = 0;
+       long tout;
+
+       init_waitqueue_entry(&wait, current);
+       add_wait_queue(&runtime->sleep, &wait);
+       for (;;) {
+               if (signal_pending(current)) {
+                       err = -ERESTARTSYS;
+                       break;
+               }
+               set_current_state(TASK_INTERRUPTIBLE);
+               snd_pcm_stream_unlock_irq(substream);
+               tout = schedule_timeout(msecs_to_jiffies(10000));
+               snd_pcm_stream_lock_irq(substream);
+               switch (runtime->status->state) {
+               case SNDRV_PCM_STATE_SUSPENDED:
+                       err = -ESTRPIPE;
+                       goto _endloop;
+               case SNDRV_PCM_STATE_XRUN:
+                       err = -EPIPE;
+                       goto _endloop;
+               case SNDRV_PCM_STATE_DRAINING:
+                       if (is_playback)
+                               err = -EPIPE;
+                       else 
+                               avail = 0; /* indicate draining */
+                       goto _endloop;
+               case SNDRV_PCM_STATE_OPEN:
+               case SNDRV_PCM_STATE_SETUP:
+               case SNDRV_PCM_STATE_DISCONNECTED:
+                       err = -EBADFD;
+                       goto _endloop;
+               }
+               if (!tout) {
+                       snd_printd("%s write error (DMA or IRQ trouble?)\n",
+                                  is_playback ? "playback" : "capture");
+                       err = -EIO;
+                       break;
+               }
+               if (is_playback)
+                       avail = snd_pcm_playback_avail(runtime);
+               else
+                       avail = snd_pcm_capture_avail(runtime);
+               if (avail >= runtime->control->avail_min)
+                       break;
+       }
+ _endloop:
+       remove_wait_queue(&runtime->sleep, &wait);
+       *availp = avail;
+       return err;
+}
+       
 static int snd_pcm_lib_write_transfer(struct snd_pcm_substream *substream,
                                      unsigned int hwoff,
                                      unsigned long data, unsigned int off,
@@ -1624,8 +1591,6 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream,
 
        if (size == 0)
                return 0;
-       if (size > runtime->xfer_align)
-               size -= size % runtime->xfer_align;
 
        snd_pcm_stream_lock_irq(substream);
        switch (runtime->status->state) {
@@ -1648,84 +1613,18 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream,
                snd_pcm_uframes_t frames, appl_ptr, appl_ofs;
                snd_pcm_uframes_t avail;
                snd_pcm_uframes_t cont;
-               if (runtime->sleep_min == 0 && runtime->status->state == SNDRV_PCM_STATE_RUNNING)
+               if (runtime->status->state == SNDRV_PCM_STATE_RUNNING)
                        snd_pcm_update_hw_ptr(substream);
                avail = snd_pcm_playback_avail(runtime);
-               if (((avail < runtime->control->avail_min && size > avail) ||
-                  (size >= runtime->xfer_align && avail < runtime->xfer_align))) {
-                       wait_queue_t wait;
-                       enum { READY, SIGNALED, ERROR, SUSPENDED, EXPIRED, DROPPED } state;
-                       long tout;
-
+               if (!avail) {
                        if (nonblock) {
                                err = -EAGAIN;
                                goto _end_unlock;
                        }
-
-                       init_waitqueue_entry(&wait, current);
-                       add_wait_queue(&runtime->sleep, &wait);
-                       while (1) {
-                               if (signal_pending(current)) {
-                                       state = SIGNALED;
-                                       break;
-                               }
-                               set_current_state(TASK_INTERRUPTIBLE);
-                               snd_pcm_stream_unlock_irq(substream);
-                               tout = schedule_timeout(10 * HZ);
-                               snd_pcm_stream_lock_irq(substream);
-                               if (tout == 0) {
-                                       if (runtime->status->state != SNDRV_PCM_STATE_PREPARED &&
-                                           runtime->status->state != SNDRV_PCM_STATE_PAUSED) {
-                                               state = runtime->status->state == SNDRV_PCM_STATE_SUSPENDED ? SUSPENDED : EXPIRED;
-                                               break;
-                                       }
-                               }
-                               switch (runtime->status->state) {
-                               case SNDRV_PCM_STATE_XRUN:
-                               case SNDRV_PCM_STATE_DRAINING:
-                                       state = ERROR;
-                                       goto _end_loop;
-                               case SNDRV_PCM_STATE_SUSPENDED:
-                                       state = SUSPENDED;
-                                       goto _end_loop;
-                               case SNDRV_PCM_STATE_SETUP:
-                                       state = DROPPED;
-                                       goto _end_loop;
-                               default:
-                                       break;
-                               }
-                               avail = snd_pcm_playback_avail(runtime);
-                               if (avail >= runtime->control->avail_min) {
-                                       state = READY;
-                                       break;
-                               }
-                       }
-                      _end_loop:
-                       remove_wait_queue(&runtime->sleep, &wait);
-
-                       switch (state) {
-                       case ERROR:
-                               err = -EPIPE;
-                               goto _end_unlock;
-                       case SUSPENDED:
-                               err = -ESTRPIPE;
-                               goto _end_unlock;
-                       case SIGNALED:
-                               err = -ERESTARTSYS;
-                               goto _end_unlock;
-                       case EXPIRED:
-                               snd_printd("playback write error (DMA or IRQ trouble?)\n");
-                               err = -EIO;
-                               goto _end_unlock;
-                       case DROPPED:
-                               err = -EBADFD;
+                       err = wait_for_avail_min(substream, &avail);
+                       if (err < 0)
                                goto _end_unlock;
-                       default:
-                               break;
-                       }
                }
-               if (avail > runtime->xfer_align)
-                       avail -= avail % runtime->xfer_align;
                frames = size > avail ? avail : size;
                cont = runtime->buffer_size - runtime->control->appl_ptr % runtime->buffer_size;
                if (frames > cont)
@@ -1763,9 +1662,6 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream,
                        if (err < 0)
                                goto _end_unlock;
                }
-               if (runtime->sleep_min &&
-                   runtime->status->state == SNDRV_PCM_STATE_RUNNING)
-                       snd_pcm_tick_prepare(substream);
        }
  _end_unlock:
        snd_pcm_stream_unlock_irq(substream);
@@ -1893,8 +1789,6 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream,
 
        if (size == 0)
                return 0;
-       if (size > runtime->xfer_align)
-               size -= size % runtime->xfer_align;
 
        snd_pcm_stream_lock_irq(substream);
        switch (runtime->status->state) {
@@ -1924,91 +1818,25 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream,
                snd_pcm_uframes_t frames, appl_ptr, appl_ofs;
                snd_pcm_uframes_t avail;
                snd_pcm_uframes_t cont;
-               if (runtime->sleep_min == 0 && runtime->status->state == SNDRV_PCM_STATE_RUNNING)
+               if (runtime->status->state == SNDRV_PCM_STATE_RUNNING)
                        snd_pcm_update_hw_ptr(substream);
-             __draining:
                avail = snd_pcm_capture_avail(runtime);
-               if (runtime->status->state == SNDRV_PCM_STATE_DRAINING) {
-                       if (avail < runtime->xfer_align) {
-                               err = -EPIPE;
+               if (!avail) {
+                       if (runtime->status->state ==
+                           SNDRV_PCM_STATE_DRAINING) {
+                               snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP);
                                goto _end_unlock;
                        }
-               } else if ((avail < runtime->control->avail_min && size > avail) ||
-                          (size >= runtime->xfer_align && avail < runtime->xfer_align)) {
-                       wait_queue_t wait;
-                       enum { READY, SIGNALED, ERROR, SUSPENDED, EXPIRED, DROPPED } state;
-                       long tout;
-
                        if (nonblock) {
                                err = -EAGAIN;
                                goto _end_unlock;
                        }
-
-                       init_waitqueue_entry(&wait, current);
-                       add_wait_queue(&runtime->sleep, &wait);
-                       while (1) {
-                               if (signal_pending(current)) {
-                                       state = SIGNALED;
-                                       break;
-                               }
-                               set_current_state(TASK_INTERRUPTIBLE);
-                               snd_pcm_stream_unlock_irq(substream);
-                               tout = schedule_timeout(10 * HZ);
-                               snd_pcm_stream_lock_irq(substream);
-                               if (tout == 0) {
-                                       if (runtime->status->state != SNDRV_PCM_STATE_PREPARED &&
-                                           runtime->status->state != SNDRV_PCM_STATE_PAUSED) {
-                                               state = runtime->status->state == SNDRV_PCM_STATE_SUSPENDED ? SUSPENDED : EXPIRED;
-                                               break;
-                                       }
-                               }
-                               switch (runtime->status->state) {
-                               case SNDRV_PCM_STATE_XRUN:
-                                       state = ERROR;
-                                       goto _end_loop;
-                               case SNDRV_PCM_STATE_SUSPENDED:
-                                       state = SUSPENDED;
-                                       goto _end_loop;
-                               case SNDRV_PCM_STATE_DRAINING:
-                                       goto __draining;
-                               case SNDRV_PCM_STATE_SETUP:
-                                       state = DROPPED;
-                                       goto _end_loop;
-                               default:
-                                       break;
-                               }
-                               avail = snd_pcm_capture_avail(runtime);
-                               if (avail >= runtime->control->avail_min) {
-                                       state = READY;
-                                       break;
-                               }
-                       }
-                      _end_loop:
-                       remove_wait_queue(&runtime->sleep, &wait);
-
-                       switch (state) {
-                       case ERROR:
-                               err = -EPIPE;
-                               goto _end_unlock;
-                       case SUSPENDED:
-                               err = -ESTRPIPE;
-                               goto _end_unlock;
-                       case SIGNALED:
-                               err = -ERESTARTSYS;
-                               goto _end_unlock;
-                       case EXPIRED:
-                               snd_printd("capture read error (DMA or IRQ trouble?)\n");
-                               err = -EIO;
-                               goto _end_unlock;
-                       case DROPPED:
-                               err = -EBADFD;
+                       err = wait_for_avail_min(substream, &avail);
+                       if (err < 0)
                                goto _end_unlock;
-                       default:
-                               break;
-                       }
+                       if (!avail)
+                               continue; /* draining */
                }
-               if (avail > runtime->xfer_align)
-                       avail -= avail % runtime->xfer_align;
                frames = size > avail ? avail : size;
                cont = runtime->buffer_size - runtime->control->appl_ptr % runtime->buffer_size;
                if (frames > cont)
@@ -2040,9 +1868,6 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream,
                offset += frames;
                size -= frames;
                xfer += frames;
-               if (runtime->sleep_min &&
-                   runtime->status->state == SNDRV_PCM_STATE_RUNNING)
-                       snd_pcm_tick_prepare(substream);
        }
  _end_unlock:
        snd_pcm_stream_unlock_irq(substream);
index a13e38cfd2c62fea7d85bf8bf12f59f9cbf0a347..ff07b4a9992e80e4ad65bb3c1dac6a353020ad68 100644 (file)
@@ -19,7 +19,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <asm/io.h>
 #include <linux/time.h>
 #include <linux/init.h>
index dd9aa51d8c820b0ecfcf1d6999daf50008a41427..89b7f549bebd772bb62378510a541bb0b052e967 100644 (file)
@@ -19,7 +19,6 @@
  *
  */
   
-#include <sound/driver.h>
 #include <linux/time.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -75,7 +74,7 @@ static struct pcm_format_data pcm_formats[SNDRV_PCM_FORMAT_LAST+1] = {
        },
        [SNDRV_PCM_FORMAT_U24_BE] = {
                .width = 24, .phys = 32, .le = 0, .signd = 0,
-               .silence = { 0x80, 0x00, 0x00 },
+               .silence = { 0x00, 0x80, 0x00, 0x00 },
        },
        [SNDRV_PCM_FORMAT_S32_LE] = {
                .width = 32, .phys = 32, .le = 1, .signd = 1,
index fb3dde4db0454fcf9927b80f8a3ba55a0263267b..61f5d425b6305660e8cd3bf514664c1f9b225c58 100644 (file)
  *
  */
 
-#include <sound/driver.h>
 #include <linux/mm.h>
 #include <linux/file.h>
 #include <linux/slab.h>
 #include <linux/time.h>
-#include <linux/latency.h>
+#include <linux/pm_qos_params.h>
 #include <linux/uio.h>
 #include <sound/core.h>
 #include <sound/control.h>
@@ -413,7 +412,6 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
        runtime->period_size = params_period_size(params);
        runtime->periods = params_periods(params);
        runtime->buffer_size = params_buffer_size(params);
-       runtime->tick_time = params_tick_time(params);
        runtime->info = params->info;
        runtime->rate_num = params->rate_num;
        runtime->rate_den = params->rate_den;
@@ -433,9 +431,7 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
        /* Default sw params */
        runtime->tstamp_mode = SNDRV_PCM_TSTAMP_NONE;
        runtime->period_step = 1;
-       runtime->sleep_min = 0;
        runtime->control->avail_min = runtime->period_size;
-       runtime->xfer_align = runtime->period_size;
        runtime->start_threshold = 1;
        runtime->stop_threshold = runtime->buffer_size;
        runtime->silence_threshold = 0;
@@ -447,9 +443,11 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
        snd_pcm_timer_resolution_change(substream);
        runtime->status->state = SNDRV_PCM_STATE_SETUP;
 
-       remove_acceptable_latency(substream->latency_id);
+       pm_qos_remove_requirement(PM_QOS_CPU_DMA_LATENCY,
+                               substream->latency_id);
        if ((usecs = period_to_usecs(runtime)) >= 0)
-               set_acceptable_latency(substream->latency_id, usecs);
+               pm_qos_add_requirement(PM_QOS_CPU_DMA_LATENCY,
+                                       substream->latency_id, usecs);
        return 0;
  _error:
        /* hardware might be unuseable from this time,
@@ -509,7 +507,8 @@ static int snd_pcm_hw_free(struct snd_pcm_substream *substream)
        if (substream->ops->hw_free)
                result = substream->ops->hw_free(substream);
        runtime->status->state = SNDRV_PCM_STATE_OPEN;
-       remove_acceptable_latency(substream->latency_id);
+       pm_qos_remove_requirement(PM_QOS_CPU_DMA_LATENCY,
+               substream->latency_id);
        return result;
 }
 
@@ -532,9 +531,6 @@ static int snd_pcm_sw_params(struct snd_pcm_substream *substream,
                return -EINVAL;
        if (params->avail_min == 0)
                return -EINVAL;
-       if (params->xfer_align == 0 ||
-           params->xfer_align % runtime->min_align != 0)
-               return -EINVAL;
        if (params->silence_size >= runtime->boundary) {
                if (params->silence_threshold != 0)
                        return -EINVAL;
@@ -546,20 +542,14 @@ static int snd_pcm_sw_params(struct snd_pcm_substream *substream,
        }
        snd_pcm_stream_lock_irq(substream);
        runtime->tstamp_mode = params->tstamp_mode;
-       runtime->sleep_min = params->sleep_min;
        runtime->period_step = params->period_step;
        runtime->control->avail_min = params->avail_min;
        runtime->start_threshold = params->start_threshold;
        runtime->stop_threshold = params->stop_threshold;
        runtime->silence_threshold = params->silence_threshold;
        runtime->silence_size = params->silence_size;
-       runtime->xfer_align = params->xfer_align;
         params->boundary = runtime->boundary;
        if (snd_pcm_running(substream)) {
-               if (runtime->sleep_min)
-                       snd_pcm_tick_prepare(substream);
-               else
-                       snd_pcm_tick_set(substream, 0);
                if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
                    runtime->silence_size > 0)
                        snd_pcm_playback_silence(substream, ULONG_MAX);
@@ -595,12 +585,13 @@ int snd_pcm_status(struct snd_pcm_substream *substream,
        status->trigger_tstamp = runtime->trigger_tstamp;
        if (snd_pcm_running(substream)) {
                snd_pcm_update_hw_ptr(substream);
-               if (runtime->tstamp_mode & SNDRV_PCM_TSTAMP_MMAP)
+               if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) {
                        status->tstamp = runtime->status->tstamp;
-               else
-                       getnstimeofday(&status->tstamp);
-       } else
-               getnstimeofday(&status->tstamp);
+                       goto _tstamp_end;
+               }
+       }
+       snd_pcm_gettime(runtime, &status->tstamp);
+ _tstamp_end:
        status->appl_ptr = runtime->control->appl_ptr;
        status->hw_ptr = runtime->status->hw_ptr;
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
@@ -688,7 +679,7 @@ static void snd_pcm_trigger_tstamp(struct snd_pcm_substream *substream)
        if (runtime->trigger_master == NULL)
                return;
        if (runtime->trigger_master == substream) {
-               getnstimeofday(&runtime->trigger_tstamp);
+               snd_pcm_gettime(runtime, &runtime->trigger_tstamp);
        } else {
                snd_pcm_trigger_tstamp(runtime->trigger_master);
                runtime->trigger_tstamp = runtime->trigger_master->runtime->trigger_tstamp;
@@ -875,8 +866,6 @@ static void snd_pcm_post_start(struct snd_pcm_substream *substream, int state)
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
            runtime->silence_size > 0)
                snd_pcm_playback_silence(substream, ULONG_MAX);
-       if (runtime->sleep_min)
-               snd_pcm_tick_prepare(substream);
        if (substream->timer)
                snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MSTART,
                                 &runtime->trigger_tstamp);
@@ -930,7 +919,6 @@ static void snd_pcm_post_stop(struct snd_pcm_substream *substream, int state)
                        snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MSTOP,
                                         &runtime->trigger_tstamp);
                runtime->status->state = state;
-               snd_pcm_tick_set(substream, 0);
        }
        wake_up(&runtime->sleep);
 }
@@ -1014,12 +1002,9 @@ static void snd_pcm_post_pause(struct snd_pcm_substream *substream, int push)
                        snd_timer_notify(substream->timer,
                                         SNDRV_TIMER_EVENT_MPAUSE,
                                         &runtime->trigger_tstamp);
-               snd_pcm_tick_set(substream, 0);
                wake_up(&runtime->sleep);
        } else {
                runtime->status->state = SNDRV_PCM_STATE_RUNNING;
-               if (runtime->sleep_min)
-                       snd_pcm_tick_prepare(substream);
                if (substream->timer)
                        snd_timer_notify(substream->timer,
                                         SNDRV_TIMER_EVENT_MCONTINUE,
@@ -1074,7 +1059,6 @@ static void snd_pcm_post_suspend(struct snd_pcm_substream *substream, int state)
                                 &runtime->trigger_tstamp);
        runtime->status->suspended_state = runtime->status->state;
        runtime->status->state = SNDRV_PCM_STATE_SUSPENDED;
-       snd_pcm_tick_set(substream, 0);
        wake_up(&runtime->sleep);
 }
 
@@ -1177,8 +1161,6 @@ static void snd_pcm_post_resume(struct snd_pcm_substream *substream, int state)
                snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MRESUME,
                                 &runtime->trigger_tstamp);
        runtime->status->state = runtime->status->suspended_state;
-       if (runtime->sleep_min)
-               snd_pcm_tick_prepare(substream);
 }
 
 static struct action_ops snd_pcm_action_resume = {
@@ -1395,10 +1377,10 @@ static int snd_pcm_do_drain_init(struct snd_pcm_substream *substream, int state)
        } else {
                /* stop running stream */
                if (runtime->status->state == SNDRV_PCM_STATE_RUNNING) {
-                       int state = snd_pcm_capture_avail(runtime) > 0 ?
+                       int new_state = snd_pcm_capture_avail(runtime) > 0 ?
                                SNDRV_PCM_STATE_DRAINING : SNDRV_PCM_STATE_SETUP;
-                       snd_pcm_do_stop(substream, state);
-                       snd_pcm_post_stop(substream, state);
+                       snd_pcm_do_stop(substream, new_state);
+                       snd_pcm_post_stop(substream, new_state);
                }
        }
        return 0;
@@ -2007,8 +1989,6 @@ int snd_pcm_hw_constraints_complete(struct snd_pcm_substream *substream)
        }
 
        /* FIXME: this belong to lowlevel */
-       snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_TICK_TIME,
-                                    1000000 / HZ, 1000000 / HZ);
        snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIOD_SIZE);
 
        return 0;
@@ -2244,15 +2224,10 @@ static snd_pcm_sframes_t snd_pcm_playback_rewind(struct snd_pcm_substream *subst
        }
        if (frames > (snd_pcm_uframes_t)hw_avail)
                frames = hw_avail;
-       else
-               frames -= frames % runtime->xfer_align;
        appl_ptr = runtime->control->appl_ptr - frames;
        if (appl_ptr < 0)
                appl_ptr += runtime->boundary;
        runtime->control->appl_ptr = appl_ptr;
-       if (runtime->status->state == SNDRV_PCM_STATE_RUNNING &&
-           runtime->sleep_min)
-               snd_pcm_tick_prepare(substream);
        ret = frames;
  __end:
        snd_pcm_stream_unlock_irq(substream);
@@ -2294,15 +2269,10 @@ static snd_pcm_sframes_t snd_pcm_capture_rewind(struct snd_pcm_substream *substr
        }
        if (frames > (snd_pcm_uframes_t)hw_avail)
                frames = hw_avail;
-       else
-               frames -= frames % runtime->xfer_align;
        appl_ptr = runtime->control->appl_ptr - frames;
        if (appl_ptr < 0)
                appl_ptr += runtime->boundary;
        runtime->control->appl_ptr = appl_ptr;
-       if (runtime->status->state == SNDRV_PCM_STATE_RUNNING &&
-           runtime->sleep_min)
-               snd_pcm_tick_prepare(substream);
        ret = frames;
  __end:
        snd_pcm_stream_unlock_irq(substream);
@@ -2345,15 +2315,10 @@ static snd_pcm_sframes_t snd_pcm_playback_forward(struct snd_pcm_substream *subs
        }
        if (frames > (snd_pcm_uframes_t)avail)
                frames = avail;
-       else
-               frames -= frames % runtime->xfer_align;
        appl_ptr = runtime->control->appl_ptr + frames;
        if (appl_ptr >= (snd_pcm_sframes_t)runtime->boundary)
                appl_ptr -= runtime->boundary;
        runtime->control->appl_ptr = appl_ptr;
-       if (runtime->status->state == SNDRV_PCM_STATE_RUNNING &&
-           runtime->sleep_min)
-               snd_pcm_tick_prepare(substream);
        ret = frames;
  __end:
        snd_pcm_stream_unlock_irq(substream);
@@ -2396,15 +2361,10 @@ static snd_pcm_sframes_t snd_pcm_capture_forward(struct snd_pcm_substream *subst
        }
        if (frames > (snd_pcm_uframes_t)avail)
                frames = avail;
-       else
-               frames -= frames % runtime->xfer_align;
        appl_ptr = runtime->control->appl_ptr + frames;
        if (appl_ptr >= (snd_pcm_sframes_t)runtime->boundary)
                appl_ptr -= runtime->boundary;
        runtime->control->appl_ptr = appl_ptr;
-       if (runtime->status->state == SNDRV_PCM_STATE_RUNNING &&
-           runtime->sleep_min)
-               snd_pcm_tick_prepare(substream);
        ret = frames;
  __end:
        snd_pcm_stream_unlock_irq(substream);
@@ -2519,6 +2479,21 @@ static int snd_pcm_sync_ptr(struct snd_pcm_substream *substream,
                return -EFAULT;
        return 0;
 }
+
+static int snd_pcm_tstamp(struct snd_pcm_substream *substream, int __user *_arg)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       int arg;
+       
+       if (get_user(arg, _arg))
+               return -EFAULT;
+       if (arg < 0 || arg > SNDRV_PCM_TSTAMP_TYPE_LAST)
+               return -EINVAL;
+       runtime->tstamp_type = SNDRV_PCM_TSTAMP_TYPE_GETTIMEOFDAY;
+       if (arg == SNDRV_PCM_TSTAMP_TYPE_MONOTONIC)
+               runtime->tstamp_type = SNDRV_PCM_TSTAMP_TYPE_MONOTONIC;
+       return 0;
+}
                
 static int snd_pcm_common_ioctl1(struct file *file,
                                 struct snd_pcm_substream *substream,
@@ -2531,8 +2506,10 @@ static int snd_pcm_common_ioctl1(struct file *file,
                return put_user(SNDRV_PCM_VERSION, (int __user *)arg) ? -EFAULT : 0;
        case SNDRV_PCM_IOCTL_INFO:
                return snd_pcm_info_user(substream, arg);
-       case SNDRV_PCM_IOCTL_TSTAMP: /* just for compatibility */
+       case SNDRV_PCM_IOCTL_TSTAMP:    /* just for compatibility */
                return 0;
+       case SNDRV_PCM_IOCTL_TTSTAMP:
+               return snd_pcm_tstamp(substream, arg);
        case SNDRV_PCM_IOCTL_HW_REFINE:
                return snd_pcm_hw_refine_user(substream, arg);
        case SNDRV_PCM_IOCTL_HW_PARAMS:
@@ -3018,26 +2995,23 @@ static unsigned int snd_pcm_capture_poll(struct file *file, poll_table * wait)
 /*
  * mmap status record
  */
-static struct page * snd_pcm_mmap_status_nopage(struct vm_area_struct *area,
-                                               unsigned long address, int *type)
+static int snd_pcm_mmap_status_fault(struct vm_area_struct *area,
+                                               struct vm_fault *vmf)
 {
        struct snd_pcm_substream *substream = area->vm_private_data;
        struct snd_pcm_runtime *runtime;
-       struct page * page;
        
        if (substream == NULL)
-               return NOPAGE_SIGBUS;
+               return VM_FAULT_SIGBUS;
        runtime = substream->runtime;
-       page = virt_to_page(runtime->status);
-       get_page(page);
-       if (type)
-               *type = VM_FAULT_MINOR;
-       return page;
+       vmf->page = virt_to_page(runtime->status);
+       get_page(vmf->page);
+       return 0;
 }
 
 static struct vm_operations_struct snd_pcm_vm_ops_status =
 {
-       .nopage =       snd_pcm_mmap_status_nopage,
+       .fault =        snd_pcm_mmap_status_fault,
 };
 
 static int snd_pcm_mmap_status(struct snd_pcm_substream *substream, struct file *file,
@@ -3061,26 +3035,23 @@ static int snd_pcm_mmap_status(struct snd_pcm_substream *substream, struct file
 /*
  * mmap control record
  */
-static struct page * snd_pcm_mmap_control_nopage(struct vm_area_struct *area,
-                                                unsigned long address, int *type)
+static int snd_pcm_mmap_control_fault(struct vm_area_struct *area,
+                                               struct vm_fault *vmf)
 {
        struct snd_pcm_substream *substream = area->vm_private_data;
        struct snd_pcm_runtime *runtime;
-       struct page * page;
        
        if (substream == NULL)
-               return NOPAGE_SIGBUS;
+               return VM_FAULT_SIGBUS;
        runtime = substream->runtime;
-       page = virt_to_page(runtime->control);
-       get_page(page);
-       if (type)
-               *type = VM_FAULT_MINOR;
-       return page;
+       vmf->page = virt_to_page(runtime->control);
+       get_page(vmf->page);
+       return 0;
 }
 
 static struct vm_operations_struct snd_pcm_vm_ops_control =
 {
-       .nopage =       snd_pcm_mmap_control_nopage,
+       .fault =        snd_pcm_mmap_control_fault,
 };
 
 static int snd_pcm_mmap_control(struct snd_pcm_substream *substream, struct file *file,
@@ -3117,10 +3088,10 @@ static int snd_pcm_mmap_control(struct snd_pcm_substream *substream, struct file
 #endif /* coherent mmap */
 
 /*
- * nopage callback for mmapping a RAM page
+ * fault callback for mmapping a RAM page
  */
-static struct page *snd_pcm_mmap_data_nopage(struct vm_area_struct *area,
-                                            unsigned long address, int *type)
+static int snd_pcm_mmap_data_fault(struct vm_area_struct *area,
+                                               struct vm_fault *vmf)
 {
        struct snd_pcm_substream *substream = area->vm_private_data;
        struct snd_pcm_runtime *runtime;
@@ -3130,33 +3101,30 @@ static struct page *snd_pcm_mmap_data_nopage(struct vm_area_struct *area,
        size_t dma_bytes;
        
        if (substream == NULL)
-               return NOPAGE_SIGBUS;
+               return VM_FAULT_SIGBUS;
        runtime = substream->runtime;
-       offset = area->vm_pgoff << PAGE_SHIFT;
-       offset += address - area->vm_start;
-       snd_assert((offset % PAGE_SIZE) == 0, return NOPAGE_SIGBUS);
+       offset = vmf->pgoff << PAGE_SHIFT;
        dma_bytes = PAGE_ALIGN(runtime->dma_bytes);
        if (offset > dma_bytes - PAGE_SIZE)
-               return NOPAGE_SIGBUS;
+               return VM_FAULT_SIGBUS;
        if (substream->ops->page) {
                page = substream->ops->page(substream, offset);
-               if (! page)
-                       return NOPAGE_OOM; /* XXX: is this really due to OOM? */
+               if (!page)
+                       return VM_FAULT_SIGBUS;
        } else {
                vaddr = runtime->dma_area + offset;
                page = virt_to_page(vaddr);
        }
        get_page(page);
-       if (type)
-               *type = VM_FAULT_MINOR;
-       return page;
+       vmf->page = page;
+       return 0;
 }
 
 static struct vm_operations_struct snd_pcm_vm_ops_data =
 {
        .open =         snd_pcm_mmap_data_open,
        .close =        snd_pcm_mmap_data_close,
-       .nopage =       snd_pcm_mmap_data_nopage,
+       .fault =        snd_pcm_mmap_data_fault,
 };
 
 /*
index 23aa9a27e2158f8cd2173b6e66d12887a4432453..033a024d153a846ff315d1f275bf049c52dce655 100644 (file)
@@ -19,7 +19,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/time.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
index b8e700b94e5962b24a9355be54f2548753633eb7..f7ea7287c59cd7edfcf75bc5795efce07d512d79 100644 (file)
@@ -19,7 +19,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <sound/core.h>
 #include <linux/major.h>
 #include <linux/init.h>
@@ -912,7 +911,8 @@ int snd_rawmidi_receive(struct snd_rawmidi_substream *substream,
 }
 
 static long snd_rawmidi_kernel_read1(struct snd_rawmidi_substream *substream,
-                                    unsigned char *buf, long count, int kernel)
+                                    unsigned char __user *userbuf,
+                                    unsigned char *kernelbuf, long count)
 {
        unsigned long flags;
        long result = 0, count1;
@@ -925,11 +925,11 @@ static long snd_rawmidi_kernel_read1(struct snd_rawmidi_substream *substream,
                spin_lock_irqsave(&runtime->lock, flags);
                if (count1 > (int)runtime->avail)
                        count1 = runtime->avail;
-               if (kernel) {
-                       memcpy(buf + result, runtime->buffer + runtime->appl_ptr, count1);
-               } else {
+               if (kernelbuf)
+                       memcpy(kernelbuf + result, runtime->buffer + runtime->appl_ptr, count1);
+               if (userbuf) {
                        spin_unlock_irqrestore(&runtime->lock, flags);
-                       if (copy_to_user((char __user *)buf + result,
+                       if (copy_to_user(userbuf + result,
                                         runtime->buffer + runtime->appl_ptr, count1)) {
                                return result > 0 ? result : -EFAULT;
                        }
@@ -949,7 +949,7 @@ long snd_rawmidi_kernel_read(struct snd_rawmidi_substream *substream,
                             unsigned char *buf, long count)
 {
        snd_rawmidi_input_trigger(substream, 1);
-       return snd_rawmidi_kernel_read1(substream, buf, count, 1);
+       return snd_rawmidi_kernel_read1(substream, NULL/*userbuf*/, buf, count);
 }
 
 static ssize_t snd_rawmidi_read(struct file *file, char __user *buf, size_t count,
@@ -990,8 +990,9 @@ static ssize_t snd_rawmidi_read(struct file *file, char __user *buf, size_t coun
                }
                spin_unlock_irq(&runtime->lock);
                count1 = snd_rawmidi_kernel_read1(substream,
-                                                 (unsigned char __force *)buf,
-                                                 count, 0);
+                                                 (unsigned char __user *)buf,
+                                                 NULL/*kernelbuf*/,
+                                                 count);
                if (count1 < 0)
                        return result > 0 ? result : count1;
                result += count1;
@@ -1132,13 +1133,15 @@ int snd_rawmidi_transmit(struct snd_rawmidi_substream *substream,
 }
 
 static long snd_rawmidi_kernel_write1(struct snd_rawmidi_substream *substream,
-                                     const unsigned char *buf, long count, int kernel)
+                                     const unsigned char __user *userbuf,
+                                     const unsigned char *kernelbuf,
+                                     long count)
 {
        unsigned long flags;
        long count1, result;
        struct snd_rawmidi_runtime *runtime = substream->runtime;
 
-       snd_assert(buf != NULL, return -EINVAL);
+       snd_assert(kernelbuf != NULL || userbuf != NULL, return -EINVAL);
        snd_assert(runtime->buffer != NULL, return -EINVAL);
 
        result = 0;
@@ -1155,12 +1158,13 @@ static long snd_rawmidi_kernel_write1(struct snd_rawmidi_substream *substream,
                        count1 = count;
                if (count1 > (long)runtime->avail)
                        count1 = runtime->avail;
-               if (kernel) {
-                       memcpy(runtime->buffer + runtime->appl_ptr, buf, count1);
-               } else {
+               if (kernelbuf)
+                       memcpy(runtime->buffer + runtime->appl_ptr,
+                              kernelbuf + result, count1);
+               else if (userbuf) {
                        spin_unlock_irqrestore(&runtime->lock, flags);
                        if (copy_from_user(runtime->buffer + runtime->appl_ptr,
-                                          (char __user *)buf, count1)) {
+                                          userbuf + result, count1)) {
                                spin_lock_irqsave(&runtime->lock, flags);
                                result = result > 0 ? result : -EFAULT;
                                goto __end;
@@ -1171,7 +1175,6 @@ static long snd_rawmidi_kernel_write1(struct snd_rawmidi_substream *substream,
                runtime->appl_ptr %= runtime->buffer_size;
                runtime->avail -= count1;
                result += count1;
-               buf += count1;
                count -= count1;
        }
       __end:
@@ -1185,7 +1188,7 @@ static long snd_rawmidi_kernel_write1(struct snd_rawmidi_substream *substream,
 long snd_rawmidi_kernel_write(struct snd_rawmidi_substream *substream,
                              const unsigned char *buf, long count)
 {
-       return snd_rawmidi_kernel_write1(substream, buf, count, 1);
+       return snd_rawmidi_kernel_write1(substream, NULL, buf, count);
 }
 
 static ssize_t snd_rawmidi_write(struct file *file, const char __user *buf,
@@ -1225,9 +1228,7 @@ static ssize_t snd_rawmidi_write(struct file *file, const char __user *buf,
                        spin_lock_irq(&runtime->lock);
                }
                spin_unlock_irq(&runtime->lock);
-               count1 = snd_rawmidi_kernel_write1(substream,
-                                                  (unsigned char __force *)buf,
-                                                  count, 0);
+               count1 = snd_rawmidi_kernel_write1(substream, buf, NULL, count);
                if (count1 < 0)
                        return result > 0 ? result : count1;
                result += count1;
index 7cd5e8f5d4cebc2375f7303ce00d48e09046fd96..97b30fb4c361193b1ef65821a46dea9f67736d9b 100644 (file)
@@ -20,7 +20,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/moduleparam.h>
index ceef14afee3002dda5f6b7eff7ea076a41011a53..069593717fbab0c0deb733c52e883c5b6c638988 100644 (file)
@@ -3,7 +3,6 @@
 # Copyright (c) 1999 by Jaroslav Kysela <perex@perex.cz>
 #
 
-obj-$(CONFIG_SND) += instr/
 ifeq ($(CONFIG_SND_SEQUENCER_OSS),y)
   obj-$(CONFIG_SND_SEQUENCER) += oss/
 endif
@@ -15,7 +14,6 @@ snd-seq-objs := seq.o seq_lock.o seq_clientmgr.o seq_memory.o seq_queue.o \
 snd-seq-midi-objs := seq_midi.o
 snd-seq-midi-emul-objs := seq_midi_emul.o
 snd-seq-midi-event-objs := seq_midi_event.o
-snd-seq-instr-objs := seq_instr.o
 snd-seq-dummy-objs := seq_dummy.o
 snd-seq-virmidi-objs := seq_virmidi.o
 
@@ -36,9 +34,7 @@ obj-$(CONFIG_SND_SEQ_DUMMY) += snd-seq-dummy.o
 # Toplevel Module Dependency
 obj-$(CONFIG_SND_VIRMIDI) += snd-seq-virmidi.o snd-seq-midi-event.o
 obj-$(call sequencer,$(CONFIG_SND_RAWMIDI)) += snd-seq-midi.o snd-seq-midi-event.o
-obj-$(call sequencer,$(CONFIG_SND_OPL3_LIB)) += snd-seq-midi-event.o snd-seq-midi-emul.o snd-seq-instr.o
-obj-$(call sequencer,$(CONFIG_SND_OPL4_LIB)) += snd-seq-midi-event.o snd-seq-midi-emul.o snd-seq-instr.o
-obj-$(call sequencer,$(CONFIG_SND_GUS_SYNTH)) += snd-seq-midi-emul.o snd-seq-instr.o
+obj-$(call sequencer,$(CONFIG_SND_OPL3_LIB)) += snd-seq-midi-event.o snd-seq-midi-emul.o
+obj-$(call sequencer,$(CONFIG_SND_OPL4_LIB)) += snd-seq-midi-event.o snd-seq-midi-emul.o
 obj-$(call sequencer,$(CONFIG_SND_SBAWE)) += snd-seq-midi-emul.o snd-seq-virmidi.o
 obj-$(call sequencer,$(CONFIG_SND_EMU10K1)) += snd-seq-midi-emul.o snd-seq-virmidi.o
-obj-$(call sequencer,$(CONFIG_SND_TRIDENT)) += snd-seq-midi-emul.o snd-seq-instr.o
diff --git a/sound/core/seq/instr/Makefile b/sound/core/seq/instr/Makefile
deleted file mode 100644 (file)
index 6089603..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-#
-# Makefile for ALSA
-# Copyright (c) 1999 by Jaroslav Kysela <perex@perex.cz>
-#
-
-snd-ainstr-fm-objs := ainstr_fm.o
-snd-ainstr-simple-objs := ainstr_simple.o
-snd-ainstr-gf1-objs := ainstr_gf1.o
-snd-ainstr-iw-objs := ainstr_iw.o
-
-#
-# this function returns:
-#   "m" - CONFIG_SND_SEQUENCER is m
-#   <empty string> - CONFIG_SND_SEQUENCER is undefined
-#   otherwise parameter #1 value
-#
-sequencer = $(if $(subst y,,$(CONFIG_SND_SEQUENCER)),$(if $(1),m),$(if $(CONFIG_SND_SEQUENCER),$(1)))
-
-# Toplevel Module Dependency
-obj-$(call sequencer,$(CONFIG_SND_OPL3_LIB)) += snd-ainstr-fm.o
-obj-$(call sequencer,$(CONFIG_SND_OPL4_LIB)) += snd-ainstr-fm.o
-obj-$(call sequencer,$(CONFIG_SND_GUS_SYNTH)) += snd-ainstr-gf1.o snd-ainstr-simple.o snd-ainstr-iw.o
-obj-$(call sequencer,$(CONFIG_SND_TRIDENT)) += snd-ainstr-simple.o
diff --git a/sound/core/seq/instr/ainstr_fm.c b/sound/core/seq/instr/ainstr_fm.c
deleted file mode 100644 (file)
index f80fab8..0000000
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- *  FM (OPL2/3) Instrument routines
- *  Copyright (c) 2000 Uros Bizjak <uros@kss-loka.si>
- *
- *   This program is free software; you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   the Free Software Foundation; either version 2 of the License, or
- *   (at your option) any later version.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program; if not, write to the Free Software
- *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
- *
- */
-#include <sound/driver.h>
-#include <linux/init.h>
-#include <sound/core.h>
-#include <sound/ainstr_fm.h>
-#include <sound/initval.h>
-#include <asm/uaccess.h>
-
-MODULE_AUTHOR("Uros Bizjak <uros@kss-loka.si>");
-MODULE_DESCRIPTION("Advanced Linux Sound Architecture FM Instrument support.");
-MODULE_LICENSE("GPL");
-
-static int snd_seq_fm_put(void *private_data, struct snd_seq_kinstr *instr,
-                         char __user *instr_data, long len, int atomic, int cmd)
-{
-       struct fm_instrument *ip;
-       struct fm_xinstrument ix;
-       int idx;
-
-       if (cmd != SNDRV_SEQ_INSTR_PUT_CMD_CREATE)
-               return -EINVAL;
-       /* copy instrument data */
-       if (len < (long)sizeof(ix))
-               return -EINVAL;
-       if (copy_from_user(&ix, instr_data, sizeof(ix)))
-               return -EFAULT;
-       if (ix.stype != FM_STRU_INSTR)
-               return -EINVAL;
-       ip = (struct fm_instrument *)KINSTR_DATA(instr);
-       ip->share_id[0] = le32_to_cpu(ix.share_id[0]);
-       ip->share_id[1] = le32_to_cpu(ix.share_id[1]);
-       ip->share_id[2] = le32_to_cpu(ix.share_id[2]);
-       ip->share_id[3] = le32_to_cpu(ix.share_id[3]);
-       ip->type = ix.type;
-       for (idx = 0; idx < 4; idx++) {
-               ip->op[idx].am_vib = ix.op[idx].am_vib;
-               ip->op[idx].ksl_level = ix.op[idx].ksl_level;
-               ip->op[idx].attack_decay = ix.op[idx].attack_decay;
-               ip->op[idx].sustain_release = ix.op[idx].sustain_release;
-               ip->op[idx].wave_select = ix.op[idx].wave_select;
-       }
-       for (idx = 0; idx < 2; idx++) {
-               ip->feedback_connection[idx] = ix.feedback_connection[idx];
-       }
-       ip->echo_delay = ix.echo_delay;
-       ip->echo_atten = ix.echo_atten;
-       ip->chorus_spread = ix.chorus_spread;
-       ip->trnsps = ix.trnsps;
-       ip->fix_dur = ix.fix_dur;
-       ip->modes = ix.modes;
-       ip->fix_key = ix.fix_key;
-       return 0;
-}
-
-static int snd_seq_fm_get(void *private_data, struct snd_seq_kinstr *instr,
-                         char __user *instr_data, long len, int atomic,
-                         int cmd)
-{
-       struct fm_instrument *ip;
-       struct fm_xinstrument ix;
-       int idx;
-       
-       if (cmd != SNDRV_SEQ_INSTR_GET_CMD_FULL)
-               return -EINVAL;
-       if (len < (long)sizeof(ix))
-               return -ENOMEM;
-       memset(&ix, 0, sizeof(ix));
-       ip = (struct fm_instrument *)KINSTR_DATA(instr);
-       ix.stype = FM_STRU_INSTR;
-       ix.share_id[0] = cpu_to_le32(ip->share_id[0]);
-       ix.share_id[1] = cpu_to_le32(ip->share_id[1]);
-       ix.share_id[2] = cpu_to_le32(ip->share_id[2]);
-       ix.share_id[3] = cpu_to_le32(ip->share_id[3]);
-       ix.type = ip->type;
-       for (idx = 0; idx < 4; idx++) {
-               ix.op[idx].am_vib = ip->op[idx].am_vib;
-               ix.op[idx].ksl_level = ip->op[idx].ksl_level;
-               ix.op[idx].attack_decay = ip->op[idx].attack_decay;
-               ix.op[idx].sustain_release = ip->op[idx].sustain_release;
-               ix.op[idx].wave_select = ip->op[idx].wave_select;
-       }
-       for (idx = 0; idx < 2; idx++) {
-               ix.feedback_connection[idx] = ip->feedback_connection[idx];
-       }
-       if (copy_to_user(instr_data, &ix, sizeof(ix)))
-               return -EFAULT;
-       ix.echo_delay = ip->echo_delay;
-       ix.echo_atten = ip->echo_atten;
-       ix.chorus_spread = ip->chorus_spread;
-       ix.trnsps = ip->trnsps;
-       ix.fix_dur = ip->fix_dur;
-       ix.modes = ip->modes;
-       ix.fix_key = ip->fix_key;
-       return 0;
-}
-
-static int snd_seq_fm_get_size(void *private_data, struct snd_seq_kinstr *instr,
-                              long *size)
-{
-       *size = sizeof(struct fm_xinstrument);
-       return 0;
-}
-
-int snd_seq_fm_init(struct snd_seq_kinstr_ops *ops,
-                   struct snd_seq_kinstr_ops *next)
-{
-       memset(ops, 0, sizeof(*ops));
-       // ops->private_data = private_data;
-       ops->add_len = sizeof(struct fm_instrument);
-       ops->instr_type = SNDRV_SEQ_INSTR_ID_OPL2_3;
-       ops->put = snd_seq_fm_put;
-       ops->get = snd_seq_fm_get;
-       ops->get_size = snd_seq_fm_get_size;
-       // ops->remove = snd_seq_fm_remove;
-       // ops->notify = snd_seq_fm_notify;
-       ops->next = next;
-       return 0;
-}
-
-/*
- *  Init part
- */
-
-static int __init alsa_ainstr_fm_init(void)
-{
-       return 0;
-}
-
-static void __exit alsa_ainstr_fm_exit(void)
-{
-}
-
-module_init(alsa_ainstr_fm_init)
-module_exit(alsa_ainstr_fm_exit)
-
-EXPORT_SYMBOL(snd_seq_fm_init);
diff --git a/sound/core/seq/instr/ainstr_gf1.c b/sound/core/seq/instr/ainstr_gf1.c
deleted file mode 100644 (file)
index 4940026..0000000
+++ /dev/null
@@ -1,359 +0,0 @@
-/*
- *   GF1 (GUS) Patch - Instrument routines
- *   Copyright (c) 1999 by Jaroslav Kysela <perex@perex.cz>
- *
- *   This program is free software; you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   the Free Software Foundation; either version 2 of the License, or
- *   (at your option) any later version.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program; if not, write to the Free Software
- *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
- *
- */
-#include <sound/driver.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <sound/core.h>
-#include <sound/ainstr_gf1.h>
-#include <sound/initval.h>
-#include <asm/uaccess.h>
-
-MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
-MODULE_DESCRIPTION("Advanced Linux Sound Architecture GF1 (GUS) Patch support.");
-MODULE_LICENSE("GPL");
-
-static unsigned int snd_seq_gf1_size(unsigned int size, unsigned int format)
-{
-       unsigned int result = size;
-       
-       if (format & GF1_WAVE_16BIT)
-               result <<= 1;
-       if (format & GF1_WAVE_STEREO)
-               result <<= 1;
-       return format;
-}
-
-static int snd_seq_gf1_copy_wave_from_stream(struct snd_gf1_ops *ops,
-                                            struct gf1_instrument *ip,
-                                            char __user **data,
-                                            long *len,
-                                            int atomic)
-{
-       struct gf1_wave *wp, *prev;
-       struct gf1_xwave xp;
-       int err;
-       gfp_t gfp_mask;
-       unsigned int real_size;
-       
-       gfp_mask = atomic ? GFP_ATOMIC : GFP_KERNEL;
-       if (*len < (long)sizeof(xp))
-               return -EINVAL;
-       if (copy_from_user(&xp, *data, sizeof(xp)))
-               return -EFAULT;
-       *data += sizeof(xp);
-       *len -= sizeof(xp);
-       wp = kzalloc(sizeof(*wp), gfp_mask);
-       if (wp == NULL)
-               return -ENOMEM;
-       wp->share_id[0] = le32_to_cpu(xp.share_id[0]);
-       wp->share_id[1] = le32_to_cpu(xp.share_id[1]);
-       wp->share_id[2] = le32_to_cpu(xp.share_id[2]);
-       wp->share_id[3] = le32_to_cpu(xp.share_id[3]);
-       wp->format = le32_to_cpu(xp.format);
-       wp->size = le32_to_cpu(xp.size);
-       wp->start = le32_to_cpu(xp.start);
-       wp->loop_start = le32_to_cpu(xp.loop_start);
-       wp->loop_end = le32_to_cpu(xp.loop_end);
-       wp->loop_repeat = le16_to_cpu(xp.loop_repeat);
-       wp->flags = xp.flags;
-       wp->sample_rate = le32_to_cpu(xp.sample_rate);
-       wp->low_frequency = le32_to_cpu(xp.low_frequency);
-       wp->high_frequency = le32_to_cpu(xp.high_frequency);
-       wp->root_frequency = le32_to_cpu(xp.root_frequency);
-       wp->tune = le16_to_cpu(xp.tune);
-       wp->balance = xp.balance;
-       memcpy(wp->envelope_rate, xp.envelope_rate, 6);
-       memcpy(wp->envelope_offset, xp.envelope_offset, 6);
-       wp->tremolo_sweep = xp.tremolo_sweep;
-       wp->tremolo_rate = xp.tremolo_rate;
-       wp->tremolo_depth = xp.tremolo_depth;
-       wp->vibrato_sweep = xp.vibrato_sweep;
-       wp->vibrato_rate = xp.vibrato_rate;
-       wp->vibrato_depth = xp.vibrato_depth;
-       wp->scale_frequency = le16_to_cpu(xp.scale_frequency);
-       wp->scale_factor = le16_to_cpu(xp.scale_factor);
-       real_size = snd_seq_gf1_size(wp->size, wp->format);
-       if ((long)real_size > *len) {
-               kfree(wp);
-               return -ENOMEM;
-       }
-       if (ops->put_sample) {
-               err = ops->put_sample(ops->private_data, wp,
-                                     *data, real_size, atomic);
-               if (err < 0) {
-                       kfree(wp);
-                       return err;
-               }
-       }
-       *data += real_size;
-       *len -= real_size;
-       prev = ip->wave;
-       if (prev) {
-               while (prev->next) prev = prev->next;
-               prev->next = wp;
-       } else {
-               ip->wave = wp;
-       }
-       return 0;
-}
-
-static void snd_seq_gf1_wave_free(struct snd_gf1_ops *ops,
-                                 struct gf1_wave *wave,
-                                 int atomic)
-{
-       if (ops->remove_sample)
-               ops->remove_sample(ops->private_data, wave, atomic);
-       kfree(wave);
-}
-
-static void snd_seq_gf1_instr_free(struct snd_gf1_ops *ops,
-                                  struct gf1_instrument *ip,
-                                  int atomic)
-{
-       struct gf1_wave *wave;
-       
-       while ((wave = ip->wave) != NULL) {
-               ip->wave = wave->next;
-               snd_seq_gf1_wave_free(ops, wave, atomic);
-       }
-}
-
-static int snd_seq_gf1_put(void *private_data, struct snd_seq_kinstr *instr,
-                          char __user *instr_data, long len, int atomic,
-                          int cmd)
-{
-       struct snd_gf1_ops *ops = private_data;
-       struct gf1_instrument *ip;
-       struct gf1_xinstrument ix;
-       int err;
-       gfp_t gfp_mask;
-
-       if (cmd != SNDRV_SEQ_INSTR_PUT_CMD_CREATE)
-               return -EINVAL;
-       gfp_mask = atomic ? GFP_ATOMIC : GFP_KERNEL;
-       /* copy instrument data */
-       if (len < (long)sizeof(ix))
-               return -EINVAL;
-       if (copy_from_user(&ix, instr_data, sizeof(ix)))
-               return -EFAULT;
-       if (ix.stype != GF1_STRU_INSTR)
-               return -EINVAL;
-       instr_data += sizeof(ix);
-       len -= sizeof(ix);
-       ip = (struct gf1_instrument *)KINSTR_DATA(instr);
-       ip->exclusion = le16_to_cpu(ix.exclusion);
-       ip->exclusion_group = le16_to_cpu(ix.exclusion_group);
-       ip->effect1 = ix.effect1;
-       ip->effect1_depth = ix.effect1_depth;
-       ip->effect2 = ix.effect2;
-       ip->effect2_depth = ix.effect2_depth;
-       /* copy layers */
-       while (len > (long)sizeof(__u32)) {
-               __u32 stype;
-
-               if (copy_from_user(&stype, instr_data, sizeof(stype)))
-                       return -EFAULT;
-               if (stype != GF1_STRU_WAVE) {
-                       snd_seq_gf1_instr_free(ops, ip, atomic);
-                       return -EINVAL;
-               }
-               err = snd_seq_gf1_copy_wave_from_stream(ops,
-                                                       ip,
-                                                       &instr_data,
-                                                       &len,
-                                                       atomic);
-               if (err < 0) {
-                       snd_seq_gf1_instr_free(ops, ip, atomic);
-                       return err;
-               }
-       }
-       return 0;
-}
-
-static int snd_seq_gf1_copy_wave_to_stream(struct snd_gf1_ops *ops,
-                                          struct gf1_instrument *ip,
-                                          char __user **data,
-                                          long *len,
-                                          int atomic)
-{
-       struct gf1_wave *wp;
-       struct gf1_xwave xp;
-       int err;
-       unsigned int real_size;
-       
-       for (wp = ip->wave; wp; wp = wp->next) {
-               if (*len < (long)sizeof(xp))
-                       return -ENOMEM;
-               memset(&xp, 0, sizeof(xp));
-               xp.stype = GF1_STRU_WAVE;
-               xp.share_id[0] = cpu_to_le32(wp->share_id[0]);
-               xp.share_id[1] = cpu_to_le32(wp->share_id[1]);
-               xp.share_id[2] = cpu_to_le32(wp->share_id[2]);
-               xp.share_id[3] = cpu_to_le32(wp->share_id[3]);
-               xp.format = cpu_to_le32(wp->format);
-               xp.size = cpu_to_le32(wp->size);
-               xp.start = cpu_to_le32(wp->start);
-               xp.loop_start = cpu_to_le32(wp->loop_start);
-               xp.loop_end = cpu_to_le32(wp->loop_end);
-               xp.loop_repeat = cpu_to_le32(wp->loop_repeat);
-               xp.flags = wp->flags;
-               xp.sample_rate = cpu_to_le32(wp->sample_rate);
-               xp.low_frequency = cpu_to_le32(wp->low_frequency);
-               xp.high_frequency = cpu_to_le32(wp->high_frequency);
-               xp.root_frequency = cpu_to_le32(wp->root_frequency);
-               xp.tune = cpu_to_le16(wp->tune);
-               xp.balance = wp->balance;
-               memcpy(xp.envelope_rate, wp->envelope_rate, 6);
-               memcpy(xp.envelope_offset, wp->envelope_offset, 6);
-               xp.tremolo_sweep = wp->tremolo_sweep;
-               xp.tremolo_rate = wp->tremolo_rate;
-               xp.tremolo_depth = wp->tremolo_depth;
-               xp.vibrato_sweep = wp->vibrato_sweep;
-               xp.vibrato_rate = wp->vibrato_rate;
-               xp.vibrato_depth = wp->vibrato_depth;
-               xp.scale_frequency = cpu_to_le16(wp->scale_frequency);
-               xp.scale_factor = cpu_to_le16(wp->scale_factor);
-               if (copy_to_user(*data, &xp, sizeof(xp)))
-                       return -EFAULT;
-               *data += sizeof(xp);
-               *len -= sizeof(xp);
-               real_size = snd_seq_gf1_size(wp->size, wp->format);
-               if (*len < (long)real_size)
-                       return -ENOMEM;
-               if (ops->get_sample) {
-                       err = ops->get_sample(ops->private_data, wp,
-                                             *data, real_size, atomic);
-                       if (err < 0)
-                               return err;
-               }
-               *data += wp->size;
-               *len -= wp->size;
-       }
-       return 0;
-}
-
-static int snd_seq_gf1_get(void *private_data, struct snd_seq_kinstr *instr,
-                          char __user *instr_data, long len, int atomic,
-                          int cmd)
-{
-       struct snd_gf1_ops *ops = private_data;
-       struct gf1_instrument *ip;
-       struct gf1_xinstrument ix;
-       
-       if (cmd != SNDRV_SEQ_INSTR_GET_CMD_FULL)
-               return -EINVAL;
-       if (len < (long)sizeof(ix))
-               return -ENOMEM;
-       memset(&ix, 0, sizeof(ix));
-       ip = (struct gf1_instrument *)KINSTR_DATA(instr);
-       ix.stype = GF1_STRU_INSTR;
-       ix.exclusion = cpu_to_le16(ip->exclusion);
-       ix.exclusion_group = cpu_to_le16(ip->exclusion_group);
-       ix.effect1 = cpu_to_le16(ip->effect1);
-       ix.effect1_depth = cpu_to_le16(ip->effect1_depth);
-       ix.effect2 = ip->effect2;
-       ix.effect2_depth = ip->effect2_depth;
-       if (copy_to_user(instr_data, &ix, sizeof(ix)))
-               return -EFAULT;
-       instr_data += sizeof(ix);
-       len -= sizeof(ix);
-       return snd_seq_gf1_copy_wave_to_stream(ops,
-                                              ip,
-                                              &instr_data,
-                                              &len,
-                                              atomic);
-}
-
-static int snd_seq_gf1_get_size(void *private_data, struct snd_seq_kinstr *instr,
-                               long *size)
-{
-       long result;
-       struct gf1_instrument *ip;
-       struct gf1_wave *wp;
-
-       *size = 0;
-       ip = (struct gf1_instrument *)KINSTR_DATA(instr);
-       result = sizeof(struct gf1_xinstrument);
-       for (wp = ip->wave; wp; wp = wp->next) {
-               result += sizeof(struct gf1_xwave);
-               result += wp->size;
-       }
-       *size = result;
-       return 0;
-}
-
-static int snd_seq_gf1_remove(void *private_data,
-                             struct snd_seq_kinstr *instr,
-                              int atomic)
-{
-       struct snd_gf1_ops *ops = private_data;
-       struct gf1_instrument *ip;
-
-       ip = (struct gf1_instrument *)KINSTR_DATA(instr);
-       snd_seq_gf1_instr_free(ops, ip, atomic);
-       return 0;
-}
-
-static void snd_seq_gf1_notify(void *private_data,
-                              struct snd_seq_kinstr *instr,
-                              int what)
-{
-       struct snd_gf1_ops *ops = private_data;
-
-       if (ops->notify)
-               ops->notify(ops->private_data, instr, what);
-}
-
-int snd_seq_gf1_init(struct snd_gf1_ops *ops,
-                    void *private_data,
-                    struct snd_seq_kinstr_ops *next)
-{
-       memset(ops, 0, sizeof(*ops));
-       ops->private_data = private_data;
-       ops->kops.private_data = ops;
-       ops->kops.add_len = sizeof(struct gf1_instrument);
-       ops->kops.instr_type = SNDRV_SEQ_INSTR_ID_GUS_PATCH;
-       ops->kops.put = snd_seq_gf1_put;
-       ops->kops.get = snd_seq_gf1_get;
-       ops->kops.get_size = snd_seq_gf1_get_size;
-       ops->kops.remove = snd_seq_gf1_remove;
-       ops->kops.notify = snd_seq_gf1_notify;
-       ops->kops.next = next;
-       return 0;
-}
-
-/*
- *  Init part
- */
-
-static int __init alsa_ainstr_gf1_init(void)
-{
-       return 0;
-}
-
-static void __exit alsa_ainstr_gf1_exit(void)
-{
-}
-
-module_init(alsa_ainstr_gf1_init)
-module_exit(alsa_ainstr_gf1_exit)
-
-EXPORT_SYMBOL(snd_seq_gf1_init);
diff --git a/sound/core/seq/instr/ainstr_iw.c b/sound/core/seq/instr/ainstr_iw.c
deleted file mode 100644 (file)
index 6c40eb7..0000000
+++ /dev/null
@@ -1,623 +0,0 @@
-/*
- *   IWFFFF - AMD InterWave (tm) - Instrument routines
- *   Copyright (c) 1999 by Jaroslav Kysela <perex@perex.cz>
- *
- *   This program is free software; you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   the Free Software Foundation; either version 2 of the License, or
- *   (at your option) any later version.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program; if not, write to the Free Software
- *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
- *
- */
-#include <sound/driver.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <sound/core.h>
-#include <sound/ainstr_iw.h>
-#include <sound/initval.h>
-#include <asm/uaccess.h>
-
-MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
-MODULE_DESCRIPTION("Advanced Linux Sound Architecture IWFFFF support.");
-MODULE_LICENSE("GPL");
-
-static unsigned int snd_seq_iwffff_size(unsigned int size, unsigned int format)
-{
-       unsigned int result = size;
-       
-       if (format & IWFFFF_WAVE_16BIT)
-               result <<= 1;
-       if (format & IWFFFF_WAVE_STEREO)
-               result <<= 1;
-       return result;
-}
-
-static void snd_seq_iwffff_copy_lfo_from_stream(struct iwffff_lfo *fp,
-                                               struct iwffff_xlfo *fx)
-{
-       fp->freq = le16_to_cpu(fx->freq);
-       fp->depth = le16_to_cpu(fx->depth);
-       fp->sweep = le16_to_cpu(fx->sweep);
-       fp->shape = fx->shape;
-       fp->delay = fx->delay;
-}
-
-static int snd_seq_iwffff_copy_env_from_stream(__u32 req_stype,
-                                              struct iwffff_layer *lp,
-                                              struct iwffff_env *ep,
-                                              struct iwffff_xenv *ex,
-                                              char __user **data,
-                                              long *len,
-                                              gfp_t gfp_mask)
-{
-       __u32 stype;
-       struct iwffff_env_record *rp, *rp_last;
-       struct iwffff_xenv_record rx;
-       struct iwffff_env_point *pp;
-       struct iwffff_xenv_point px;
-       int points_size, idx;
-
-       ep->flags = ex->flags;
-       ep->mode = ex->mode;
-       ep->index = ex->index;
-       rp_last = NULL;
-       while (1) {
-               if (*len < (long)sizeof(__u32))
-                       return -EINVAL;
-               if (copy_from_user(&stype, *data, sizeof(stype)))
-                       return -EFAULT;
-               if (stype == IWFFFF_STRU_WAVE)
-                       return 0;
-               if (req_stype != stype) {
-                       if (stype == IWFFFF_STRU_ENV_RECP ||
-                           stype == IWFFFF_STRU_ENV_RECV)
-                               return 0;
-               }
-               if (*len < (long)sizeof(rx))
-                       return -EINVAL;
-               if (copy_from_user(&rx, *data, sizeof(rx)))
-                       return -EFAULT;
-               *data += sizeof(rx);
-               *len -= sizeof(rx);
-               points_size = (le16_to_cpu(rx.nattack) + le16_to_cpu(rx.nrelease)) * 2 * sizeof(__u16);
-               if (points_size > *len)
-                       return -EINVAL;
-               rp = kzalloc(sizeof(*rp) + points_size, gfp_mask);
-               if (rp == NULL)
-                       return -ENOMEM;
-               rp->nattack = le16_to_cpu(rx.nattack);
-               rp->nrelease = le16_to_cpu(rx.nrelease);
-               rp->sustain_offset = le16_to_cpu(rx.sustain_offset);
-               rp->sustain_rate = le16_to_cpu(rx.sustain_rate);
-               rp->release_rate = le16_to_cpu(rx.release_rate);
-               rp->hirange = rx.hirange;
-               pp = (struct iwffff_env_point *)(rp + 1);
-               for (idx = 0; idx < rp->nattack + rp->nrelease; idx++) {
-                       if (copy_from_user(&px, *data, sizeof(px)))
-                               return -EFAULT;
-                       *data += sizeof(px);
-                       *len -= sizeof(px);
-                       pp->offset = le16_to_cpu(px.offset);
-                       pp->rate = le16_to_cpu(px.rate);
-               }
-               if (ep->record == NULL) {
-                       ep->record = rp;
-               } else {
-                       rp_last = rp;
-               }
-               rp_last = rp;
-       }
-       return 0;
-}
-
-static int snd_seq_iwffff_copy_wave_from_stream(struct snd_iwffff_ops *ops,
-                                               struct iwffff_layer *lp,
-                                               char __user **data,
-                                               long *len,
-                                               int atomic)
-{
-       struct iwffff_wave *wp, *prev;
-       struct iwffff_xwave xp;
-       int err;
-       gfp_t gfp_mask;
-       unsigned int real_size;
-       
-       gfp_mask = atomic ? GFP_ATOMIC : GFP_KERNEL;
-       if (*len < (long)sizeof(xp))
-               return -EINVAL;
-       if (copy_from_user(&xp, *data, sizeof(xp)))
-               return -EFAULT;
-       *data += sizeof(xp);
-       *len -= sizeof(xp);
-       wp = kzalloc(sizeof(*wp), gfp_mask);
-       if (wp == NULL)
-               return -ENOMEM;
-       wp->share_id[0] = le32_to_cpu(xp.share_id[0]);
-       wp->share_id[1] = le32_to_cpu(xp.share_id[1]);
-       wp->share_id[2] = le32_to_cpu(xp.share_id[2]);
-       wp->share_id[3] = le32_to_cpu(xp.share_id[3]);
-       wp->format = le32_to_cpu(xp.format);
-       wp->address.memory = le32_to_cpu(xp.offset);
-       wp->size = le32_to_cpu(xp.size);
-       wp->start = le32_to_cpu(xp.start);
-       wp->loop_start = le32_to_cpu(xp.loop_start);
-       wp->loop_end = le32_to_cpu(xp.loop_end);
-       wp->loop_repeat = le16_to_cpu(xp.loop_repeat);
-       wp->sample_ratio = le32_to_cpu(xp.sample_ratio);
-       wp->attenuation = xp.attenuation;
-       wp->low_note = xp.low_note;
-       wp->high_note = xp.high_note;
-       real_size = snd_seq_iwffff_size(wp->size, wp->format);
-       if (!(wp->format & IWFFFF_WAVE_ROM)) {
-               if ((long)real_size > *len) {
-                       kfree(wp);
-                       return -ENOMEM;
-               }
-       }
-       if (ops->put_sample) {
-               err = ops->put_sample(ops->private_data, wp,
-                                     *data, real_size, atomic);
-               if (err < 0) {
-                       kfree(wp);
-                       return err;
-               }
-       }
-       if (!(wp->format & IWFFFF_WAVE_ROM)) {
-               *data += real_size;
-               *len -= real_size;
-       }
-       prev = lp->wave;
-       if (prev) {
-               while (prev->next) prev = prev->next;
-               prev->next = wp;
-       } else {
-               lp->wave = wp;
-       }
-       return 0;
-}
-
-static void snd_seq_iwffff_env_free(struct snd_iwffff_ops *ops,
-                                   struct iwffff_env *env,
-                                   int atomic)
-{
-       struct iwffff_env_record *rec;
-       
-       while ((rec = env->record) != NULL) {
-               env->record = rec->next;
-               kfree(rec);
-       }
-}
-                                   
-static void snd_seq_iwffff_wave_free(struct snd_iwffff_ops *ops,
-                                    struct iwffff_wave *wave,
-                                    int atomic)
-{
-       if (ops->remove_sample)
-               ops->remove_sample(ops->private_data, wave, atomic);
-       kfree(wave);
-}
-
-static void snd_seq_iwffff_instr_free(struct snd_iwffff_ops *ops,
-                                      struct iwffff_instrument *ip,
-                                      int atomic)
-{
-       struct iwffff_layer *layer;
-       struct iwffff_wave *wave;
-       
-       while ((layer = ip->layer) != NULL) {
-               ip->layer = layer->next;
-               snd_seq_iwffff_env_free(ops, &layer->penv, atomic);
-               snd_seq_iwffff_env_free(ops, &layer->venv, atomic);
-               while ((wave = layer->wave) != NULL) {
-                       layer->wave = wave->next;
-                       snd_seq_iwffff_wave_free(ops, wave, atomic);
-               }
-               kfree(layer);
-       }
-}
-
-static int snd_seq_iwffff_put(void *private_data, struct snd_seq_kinstr *instr,
-                             char __user *instr_data, long len, int atomic,
-                             int cmd)
-{
-       struct snd_iwffff_ops *ops = private_data;
-       struct iwffff_instrument *ip;
-       struct iwffff_xinstrument ix;
-       struct iwffff_layer *lp, *prev_lp;
-       struct iwffff_xlayer lx;
-       int err;
-       gfp_t gfp_mask;
-
-       if (cmd != SNDRV_SEQ_INSTR_PUT_CMD_CREATE)
-               return -EINVAL;
-       gfp_mask = atomic ? GFP_ATOMIC : GFP_KERNEL;
-       /* copy instrument data */
-       if (len < (long)sizeof(ix))
-               return -EINVAL;
-       if (copy_from_user(&ix, instr_data, sizeof(ix)))
-               return -EFAULT;
-       if (ix.stype != IWFFFF_STRU_INSTR)
-               return -EINVAL;
-       instr_data += sizeof(ix);
-       len -= sizeof(ix);
-       ip = (struct iwffff_instrument *)KINSTR_DATA(instr);
-       ip->exclusion = le16_to_cpu(ix.exclusion);
-       ip->layer_type = le16_to_cpu(ix.layer_type);
-       ip->exclusion_group = le16_to_cpu(ix.exclusion_group);
-       ip->effect1 = ix.effect1;
-       ip->effect1_depth = ix.effect1_depth;
-       ip->effect2 = ix.effect2;
-       ip->effect2_depth = ix.effect2_depth;
-       /* copy layers */
-       prev_lp = NULL;
-       while (len > 0) {
-               if (len < (long)sizeof(struct iwffff_xlayer)) {
-                       snd_seq_iwffff_instr_free(ops, ip, atomic);
-                       return -EINVAL;
-               }
-               if (copy_from_user(&lx, instr_data, sizeof(lx)))
-                       return -EFAULT;
-               instr_data += sizeof(lx);
-               len -= sizeof(lx);
-               if (lx.stype != IWFFFF_STRU_LAYER) {
-                       snd_seq_iwffff_instr_free(ops, ip, atomic);
-                       return -EINVAL;
-               }
-               lp = kzalloc(sizeof(*lp), gfp_mask);
-               if (lp == NULL) {
-                       snd_seq_iwffff_instr_free(ops, ip, atomic);
-                       return -ENOMEM;
-               }
-               if (prev_lp) {
-                       prev_lp->next = lp;
-               } else {
-                       ip->layer = lp;
-               }
-               prev_lp = lp;
-               lp->flags = lx.flags;
-               lp->velocity_mode = lx.velocity_mode;
-               lp->layer_event = lx.layer_event;
-               lp->low_range = lx.low_range;
-               lp->high_range = lx.high_range;
-               lp->pan = lx.pan;
-               lp->pan_freq_scale = lx.pan_freq_scale;
-               lp->attenuation = lx.attenuation;
-               snd_seq_iwffff_copy_lfo_from_stream(&lp->tremolo, &lx.tremolo);
-               snd_seq_iwffff_copy_lfo_from_stream(&lp->vibrato, &lx.vibrato);
-               lp->freq_scale = le16_to_cpu(lx.freq_scale);
-               lp->freq_center = lx.freq_center;
-               err = snd_seq_iwffff_copy_env_from_stream(IWFFFF_STRU_ENV_RECP,
-                                                         lp,
-                                                         &lp->penv, &lx.penv,
-                                                         &instr_data, &len,
-                                                         gfp_mask);
-               if (err < 0) {
-                       snd_seq_iwffff_instr_free(ops, ip, atomic);
-                       return err;
-               }
-               err = snd_seq_iwffff_copy_env_from_stream(IWFFFF_STRU_ENV_RECV,
-                                                         lp,
-                                                         &lp->venv, &lx.venv,
-                                                         &instr_data, &len,
-                                                         gfp_mask);
-               if (err < 0) {
-                       snd_seq_iwffff_instr_free(ops, ip, atomic);
-                       return err;
-               }
-               while (len > (long)sizeof(__u32)) {
-                       __u32 stype;
-
-                       if (copy_from_user(&stype, instr_data, sizeof(stype)))
-                               return -EFAULT;
-                       if (stype != IWFFFF_STRU_WAVE)
-                               break;
-                       err = snd_seq_iwffff_copy_wave_from_stream(ops,
-                                                                  lp,
-                                                                  &instr_data,
-                                                                  &len,
-                                                                  atomic);
-                       if (err < 0) {
-                               snd_seq_iwffff_instr_free(ops, ip, atomic);
-                               return err;
-                       }
-               }
-       }
-       return 0;
-}
-
-static void snd_seq_iwffff_copy_lfo_to_stream(struct iwffff_xlfo *fx,
-                                             struct iwffff_lfo *fp)
-{
-       fx->freq = cpu_to_le16(fp->freq);
-       fx->depth = cpu_to_le16(fp->depth);
-       fx->sweep = cpu_to_le16(fp->sweep);
-       fp->shape = fx->shape;
-       fp->delay = fx->delay;
-}
-
-static int snd_seq_iwffff_copy_env_to_stream(__u32 req_stype,
-                                            struct iwffff_layer *lp,
-                                            struct iwffff_xenv *ex,
-                                            struct iwffff_env *ep,
-                                            char __user **data,
-                                            long *len)
-{
-       struct iwffff_env_record *rp;
-       struct iwffff_xenv_record rx;
-       struct iwffff_env_point *pp;
-       struct iwffff_xenv_point px;
-       int points_size, idx;
-
-       ex->flags = ep->flags;
-       ex->mode = ep->mode;
-       ex->index = ep->index;
-       for (rp = ep->record; rp; rp = rp->next) {
-               if (*len < (long)sizeof(rx))
-                       return -ENOMEM;
-               memset(&rx, 0, sizeof(rx));
-               rx.stype = req_stype;
-               rx.nattack = cpu_to_le16(rp->nattack);
-               rx.nrelease = cpu_to_le16(rp->nrelease);
-               rx.sustain_offset = cpu_to_le16(rp->sustain_offset);
-               rx.sustain_rate = cpu_to_le16(rp->sustain_rate);
-               rx.release_rate = cpu_to_le16(rp->release_rate);
-               rx.hirange = cpu_to_le16(rp->hirange);
-               if (copy_to_user(*data, &rx, sizeof(rx)))
-                       return -EFAULT;
-               *data += sizeof(rx);
-               *len -= sizeof(rx);
-               points_size = (rp->nattack + rp->nrelease) * 2 * sizeof(__u16);
-               if (*len < points_size)
-                       return -ENOMEM;
-               pp = (struct iwffff_env_point *)(rp + 1);
-               for (idx = 0; idx < rp->nattack + rp->nrelease; idx++) {
-                       px.offset = cpu_to_le16(pp->offset);
-                       px.rate = cpu_to_le16(pp->rate);
-                       if (copy_to_user(*data, &px, sizeof(px)))
-                               return -EFAULT;
-                       *data += sizeof(px);
-                       *len -= sizeof(px);
-               }
-       }
-       return 0;
-}
-
-static int snd_seq_iwffff_copy_wave_to_stream(struct snd_iwffff_ops *ops,
-                                             struct iwffff_layer *lp,
-                                             char __user **data,
-                                             long *len,
-                                             int atomic)
-{
-       struct iwffff_wave *wp;
-       struct iwffff_xwave xp;
-       int err;
-       unsigned int real_size;
-       
-       for (wp = lp->wave; wp; wp = wp->next) {
-               if (*len < (long)sizeof(xp))
-                       return -ENOMEM;
-               memset(&xp, 0, sizeof(xp));
-               xp.stype = IWFFFF_STRU_WAVE;
-               xp.share_id[0] = cpu_to_le32(wp->share_id[0]);
-               xp.share_id[1] = cpu_to_le32(wp->share_id[1]);
-               xp.share_id[2] = cpu_to_le32(wp->share_id[2]);
-               xp.share_id[3] = cpu_to_le32(wp->share_id[3]);
-               xp.format = cpu_to_le32(wp->format);
-               if (wp->format & IWFFFF_WAVE_ROM)
-                       xp.offset = cpu_to_le32(wp->address.memory);
-               xp.size = cpu_to_le32(wp->size);
-               xp.start = cpu_to_le32(wp->start);
-               xp.loop_start = cpu_to_le32(wp->loop_start);
-               xp.loop_end = cpu_to_le32(wp->loop_end);
-               xp.loop_repeat = cpu_to_le32(wp->loop_repeat);
-               xp.sample_ratio = cpu_to_le32(wp->sample_ratio);
-               xp.attenuation = wp->attenuation;
-               xp.low_note = wp->low_note;
-               xp.high_note = wp->high_note;
-               if (copy_to_user(*data, &xp, sizeof(xp)))
-                       return -EFAULT;
-               *data += sizeof(xp);
-               *len -= sizeof(xp);
-               real_size = snd_seq_iwffff_size(wp->size, wp->format);
-               if (!(wp->format & IWFFFF_WAVE_ROM)) {
-                       if (*len < (long)real_size)
-                               return -ENOMEM;
-               }
-               if (ops->get_sample) {
-                       err = ops->get_sample(ops->private_data, wp,
-                                             *data, real_size, atomic);
-                       if (err < 0)
-                               return err;
-               }
-               if (!(wp->format & IWFFFF_WAVE_ROM)) {
-                       *data += real_size;
-                       *len -= real_size;
-               }
-       }
-       return 0;
-}
-
-static int snd_seq_iwffff_get(void *private_data, struct snd_seq_kinstr *instr,
-                             char __user *instr_data, long len, int atomic, int cmd)
-{
-       struct snd_iwffff_ops *ops = private_data;
-       struct iwffff_instrument *ip;
-       struct iwffff_xinstrument ix;
-       struct iwffff_layer *lp;
-       struct iwffff_xlayer lx;
-       char __user *layer_instr_data;
-       int err;
-       
-       if (cmd != SNDRV_SEQ_INSTR_GET_CMD_FULL)
-               return -EINVAL;
-       if (len < (long)sizeof(ix))
-               return -ENOMEM;
-       memset(&ix, 0, sizeof(ix));
-       ip = (struct iwffff_instrument *)KINSTR_DATA(instr);
-       ix.stype = IWFFFF_STRU_INSTR;
-       ix.exclusion = cpu_to_le16(ip->exclusion);
-       ix.layer_type = cpu_to_le16(ip->layer_type);
-       ix.exclusion_group = cpu_to_le16(ip->exclusion_group);
-       ix.effect1 = cpu_to_le16(ip->effect1);
-       ix.effect1_depth = cpu_to_le16(ip->effect1_depth);
-       ix.effect2 = ip->effect2;
-       ix.effect2_depth = ip->effect2_depth;
-       if (copy_to_user(instr_data, &ix, sizeof(ix)))
-               return -EFAULT;
-       instr_data += sizeof(ix);
-       len -= sizeof(ix);
-       for (lp = ip->layer; lp; lp = lp->next) {
-               if (len < (long)sizeof(lx))
-                       return -ENOMEM;
-               memset(&lx, 0, sizeof(lx));
-               lx.stype = IWFFFF_STRU_LAYER;
-               lx.flags = lp->flags;
-               lx.velocity_mode = lp->velocity_mode;
-               lx.layer_event = lp->layer_event;
-               lx.low_range = lp->low_range;
-               lx.high_range = lp->high_range;
-               lx.pan = lp->pan;
-               lx.pan_freq_scale = lp->pan_freq_scale;
-               lx.attenuation = lp->attenuation;
-               snd_seq_iwffff_copy_lfo_to_stream(&lx.tremolo, &lp->tremolo);
-               snd_seq_iwffff_copy_lfo_to_stream(&lx.vibrato, &lp->vibrato);
-               layer_instr_data = instr_data;
-               instr_data += sizeof(lx);
-               len -= sizeof(lx);
-               err = snd_seq_iwffff_copy_env_to_stream(IWFFFF_STRU_ENV_RECP,
-                                                       lp,
-                                                       &lx.penv, &lp->penv,
-                                                       &instr_data, &len);
-               if (err < 0)
-                       return err;
-               err = snd_seq_iwffff_copy_env_to_stream(IWFFFF_STRU_ENV_RECV,
-                                                       lp,
-                                                       &lx.venv, &lp->venv,
-                                                       &instr_data, &len);
-               if (err < 0)
-                       return err;
-               /* layer structure updating is now finished */
-               if (copy_to_user(layer_instr_data, &lx, sizeof(lx)))
-                       return -EFAULT;
-               err = snd_seq_iwffff_copy_wave_to_stream(ops,
-                                                        lp,
-                                                        &instr_data,
-                                                        &len,
-                                                        atomic);
-               if (err < 0)
-                       return err;
-       }
-       return 0;
-}
-
-static long snd_seq_iwffff_env_size_in_stream(struct iwffff_env *ep)
-{
-       long result = 0;
-       struct iwffff_env_record *rp;
-
-       for (rp = ep->record; rp; rp = rp->next) {
-               result += sizeof(struct iwffff_xenv_record);
-               result += (rp->nattack + rp->nrelease) * 2 * sizeof(__u16);
-       }
-       return 0;
-}
-
-static long snd_seq_iwffff_wave_size_in_stream(struct iwffff_layer *lp)
-{
-       long result = 0;
-       struct iwffff_wave *wp;
-       
-       for (wp = lp->wave; wp; wp = wp->next) {
-               result += sizeof(struct iwffff_xwave);
-               if (!(wp->format & IWFFFF_WAVE_ROM))
-                       result += wp->size;
-       }
-       return result;
-}
-
-static int snd_seq_iwffff_get_size(void *private_data, struct snd_seq_kinstr *instr,
-                                  long *size)
-{
-       long result;
-       struct iwffff_instrument *ip;
-       struct iwffff_layer *lp;
-
-       *size = 0;
-       ip = (struct iwffff_instrument *)KINSTR_DATA(instr);
-       result = sizeof(struct iwffff_xinstrument);
-       for (lp = ip->layer; lp; lp = lp->next) {
-               result += sizeof(struct iwffff_xlayer);
-               result += snd_seq_iwffff_env_size_in_stream(&lp->penv);
-               result += snd_seq_iwffff_env_size_in_stream(&lp->venv);
-               result += snd_seq_iwffff_wave_size_in_stream(lp);
-       }
-       *size = result;
-       return 0;
-}
-
-static int snd_seq_iwffff_remove(void *private_data,
-                                struct snd_seq_kinstr *instr,
-                                 int atomic)
-{
-       struct snd_iwffff_ops *ops = private_data;
-       struct iwffff_instrument *ip;
-
-       ip = (struct iwffff_instrument *)KINSTR_DATA(instr);
-       snd_seq_iwffff_instr_free(ops, ip, atomic);
-       return 0;
-}
-
-static void snd_seq_iwffff_notify(void *private_data,
-                                 struct snd_seq_kinstr *instr,
-                                  int what)
-{
-       struct snd_iwffff_ops *ops = private_data;
-
-       if (ops->notify)
-               ops->notify(ops->private_data, instr, what);
-}
-
-int snd_seq_iwffff_init(struct snd_iwffff_ops *ops,
-                       void *private_data,
-                       struct snd_seq_kinstr_ops *next)
-{
-       memset(ops, 0, sizeof(*ops));
-       ops->private_data = private_data;
-       ops->kops.private_data = ops;
-       ops->kops.add_len = sizeof(struct iwffff_instrument);
-       ops->kops.instr_type = SNDRV_SEQ_INSTR_ID_INTERWAVE;
-       ops->kops.put = snd_seq_iwffff_put;
-       ops->kops.get = snd_seq_iwffff_get;
-       ops->kops.get_size = snd_seq_iwffff_get_size;
-       ops->kops.remove = snd_seq_iwffff_remove;
-       ops->kops.notify = snd_seq_iwffff_notify;
-       ops->kops.next = next;
-       return 0;
-}
-
-/*
- *  Init part
- */
-
-static int __init alsa_ainstr_iw_init(void)
-{
-       return 0;
-}
-
-static void __exit alsa_ainstr_iw_exit(void)
-{
-}
-
-module_init(alsa_ainstr_iw_init)
-module_exit(alsa_ainstr_iw_exit)
-
-EXPORT_SYMBOL(snd_seq_iwffff_init);
diff --git a/sound/core/seq/instr/ainstr_simple.c b/sound/core/seq/instr/ainstr_simple.c
deleted file mode 100644 (file)
index 78f68be..0000000
+++ /dev/null
@@ -1,215 +0,0 @@
-/*
- *   Simple (MOD player) - Instrument routines
- *   Copyright (c) 1999 by Jaroslav Kysela <perex@perex.cz>
- *
- *   This program is free software; you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   the Free Software Foundation; either version 2 of the License, or
- *   (at your option) any later version.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program; if not, write to the Free Software
- *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
- *
- */
-#include <sound/driver.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <sound/core.h>
-#include <sound/ainstr_simple.h>
-#include <sound/initval.h>
-#include <asm/uaccess.h>
-
-MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
-MODULE_DESCRIPTION("Advanced Linux Sound Architecture Simple Instrument support.");
-MODULE_LICENSE("GPL");
-
-static unsigned int snd_seq_simple_size(unsigned int size, unsigned int format)
-{
-       unsigned int result = size;
-       
-       if (format & SIMPLE_WAVE_16BIT)
-               result <<= 1;
-       if (format & SIMPLE_WAVE_STEREO)
-               result <<= 1;
-       return result;
-}
-
-static void snd_seq_simple_instr_free(struct snd_simple_ops *ops,
-                                     struct simple_instrument *ip,
-                                     int atomic)
-{
-       if (ops->remove_sample)
-               ops->remove_sample(ops->private_data, ip, atomic);
-}
-
-static int snd_seq_simple_put(void *private_data, struct snd_seq_kinstr *instr,
-                             char __user *instr_data, long len,
-                             int atomic, int cmd)
-{
-       struct snd_simple_ops *ops = private_data;
-       struct simple_instrument *ip;
-       struct simple_xinstrument ix;
-       int err;
-       gfp_t gfp_mask;
-       unsigned int real_size;
-
-       if (cmd != SNDRV_SEQ_INSTR_PUT_CMD_CREATE)
-               return -EINVAL;
-       gfp_mask = atomic ? GFP_ATOMIC : GFP_KERNEL;
-       /* copy instrument data */
-       if (len < (long)sizeof(ix))
-               return -EINVAL;
-       if (copy_from_user(&ix, instr_data, sizeof(ix)))
-               return -EFAULT;
-       if (ix.stype != SIMPLE_STRU_INSTR)
-               return -EINVAL;
-       instr_data += sizeof(ix);
-       len -= sizeof(ix);
-       ip = (struct simple_instrument *)KINSTR_DATA(instr);
-       ip->share_id[0] = le32_to_cpu(ix.share_id[0]);
-       ip->share_id[1] = le32_to_cpu(ix.share_id[1]);
-       ip->share_id[2] = le32_to_cpu(ix.share_id[2]);
-       ip->share_id[3] = le32_to_cpu(ix.share_id[3]);
-       ip->format = le32_to_cpu(ix.format);
-       ip->size = le32_to_cpu(ix.size);
-       ip->start = le32_to_cpu(ix.start);
-       ip->loop_start = le32_to_cpu(ix.loop_start);
-       ip->loop_end = le32_to_cpu(ix.loop_end);
-       ip->loop_repeat = le16_to_cpu(ix.loop_repeat);
-       ip->effect1 = ix.effect1;
-       ip->effect1_depth = ix.effect1_depth;
-       ip->effect2 = ix.effect2;
-       ip->effect2_depth = ix.effect2_depth;
-       real_size = snd_seq_simple_size(ip->size, ip->format);
-       if (len < (long)real_size)
-               return -EINVAL;
-       if (ops->put_sample) {
-               err = ops->put_sample(ops->private_data, ip,
-                                     instr_data, real_size, atomic);
-               if (err < 0)
-                       return err;
-       }
-       return 0;
-}
-
-static int snd_seq_simple_get(void *private_data, struct snd_seq_kinstr *instr,
-                             char __user *instr_data, long len,
-                             int atomic, int cmd)
-{
-       struct snd_simple_ops *ops = private_data;
-       struct simple_instrument *ip;
-       struct simple_xinstrument ix;
-       int err;
-       unsigned int real_size;
-       
-       if (cmd != SNDRV_SEQ_INSTR_GET_CMD_FULL)
-               return -EINVAL;
-       if (len < (long)sizeof(ix))
-               return -ENOMEM;
-       memset(&ix, 0, sizeof(ix));
-       ip = (struct simple_instrument *)KINSTR_DATA(instr);
-       ix.stype = SIMPLE_STRU_INSTR;
-       ix.share_id[0] = cpu_to_le32(ip->share_id[0]);
-       ix.share_id[1] = cpu_to_le32(ip->share_id[1]);
-       ix.share_id[2] = cpu_to_le32(ip->share_id[2]);
-       ix.share_id[3] = cpu_to_le32(ip->share_id[3]);
-       ix.format = cpu_to_le32(ip->format);
-       ix.size = cpu_to_le32(ip->size);
-       ix.start = cpu_to_le32(ip->start);
-       ix.loop_start = cpu_to_le32(ip->loop_start);
-       ix.loop_end = cpu_to_le32(ip->loop_end);
-       ix.loop_repeat = cpu_to_le32(ip->loop_repeat);
-       ix.effect1 = cpu_to_le16(ip->effect1);
-       ix.effect1_depth = cpu_to_le16(ip->effect1_depth);
-       ix.effect2 = ip->effect2;
-       ix.effect2_depth = ip->effect2_depth;
-       if (copy_to_user(instr_data, &ix, sizeof(ix)))
-               return -EFAULT;
-       instr_data += sizeof(ix);
-       len -= sizeof(ix);
-       real_size = snd_seq_simple_size(ip->size, ip->format);
-       if (len < (long)real_size)
-               return -ENOMEM;
-       if (ops->get_sample) {
-               err = ops->get_sample(ops->private_data, ip,
-                                     instr_data, real_size, atomic);
-               if (err < 0)
-                       return err;
-       }
-       return 0;
-}
-
-static int snd_seq_simple_get_size(void *private_data, struct snd_seq_kinstr *instr,
-                                  long *size)
-{
-       struct simple_instrument *ip;
-
-       ip = (struct simple_instrument *)KINSTR_DATA(instr);
-       *size = sizeof(struct simple_xinstrument) + snd_seq_simple_size(ip->size, ip->format);
-       return 0;
-}
-
-static int snd_seq_simple_remove(void *private_data,
-                                struct snd_seq_kinstr *instr,
-                                 int atomic)
-{
-       struct snd_simple_ops *ops = private_data;
-       struct simple_instrument *ip;
-
-       ip = (struct simple_instrument *)KINSTR_DATA(instr);
-       snd_seq_simple_instr_free(ops, ip, atomic);
-       return 0;
-}
-
-static void snd_seq_simple_notify(void *private_data,
-                                 struct snd_seq_kinstr *instr,
-                                  int what)
-{
-       struct snd_simple_ops *ops = private_data;
-
-       if (ops->notify)
-               ops->notify(ops->private_data, instr, what);
-}
-
-int snd_seq_simple_init(struct snd_simple_ops *ops,
-                       void *private_data,
-                       struct snd_seq_kinstr_ops *next)
-{
-       memset(ops, 0, sizeof(*ops));
-       ops->private_data = private_data;
-       ops->kops.private_data = ops;
-       ops->kops.add_len = sizeof(struct simple_instrument);
-       ops->kops.instr_type = SNDRV_SEQ_INSTR_ID_SIMPLE;
-       ops->kops.put = snd_seq_simple_put;
-       ops->kops.get = snd_seq_simple_get;
-       ops->kops.get_size = snd_seq_simple_get_size;
-       ops->kops.remove = snd_seq_simple_remove;
-       ops->kops.notify = snd_seq_simple_notify;
-       ops->kops.next = next;
-       return 0;
-}
-
-/*
- *  Init part
- */
-
-static int __init alsa_ainstr_simple_init(void)
-{
-       return 0;
-}
-
-static void __exit alsa_ainstr_simple_exit(void)
-{
-}
-
-module_init(alsa_ainstr_simple_init)
-module_exit(alsa_ainstr_simple_exit)
-
-EXPORT_SYMBOL(snd_seq_simple_init);
index bc0992398461bbf40d0cf3da9f8d99f4feabb27f..777796e9449047c2ec2b0ec851638cac9733fd7e 100644 (file)
@@ -20,7 +20,6 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/moduleparam.h>
 #include <linux/mutex.h>
index 9a8567c928ec4bc262061b1314d73f4e0869373d..bf8d2b4cb15e8e403a10f94eb15bc4ee67d251c8 100644 (file)
@@ -21,7 +21,6 @@
 #ifndef __SEQ_OSS_DEVICE_H
 #define __SEQ_OSS_DEVICE_H
 
-#include <sound/driver.h>
 #include <linux/time.h>
 #include <linux/wait.h>
 #include <linux/slab.h>
index 1878208a802665a2b26b1233b3a31c497922a2c4..ee0f8405ab355ee48c3c36fbea255330c029d541 100644 (file)
@@ -19,7 +19,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/moduleparam.h>
 #include <sound/core.h>
index 2e3fa25ab19ffe8208ba17a1d06023bbf8d0427a..f97c1ba43a2820c5ae956442f554a9cc7aa9b4be 100644 (file)
@@ -21,7 +21,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <sound/core.h>
@@ -130,8 +129,6 @@ static struct snd_seq_client *clientptr(int clientid)
        return clienttab[clientid];
 }
 
-extern int seq_client_load[];
-
 struct snd_seq_client *snd_seq_client_use_ptr(int clientid)
 {
        unsigned long flags;
@@ -966,8 +963,7 @@ static int check_event_type_and_length(struct snd_seq_event *ev)
                        return -EINVAL;
                break;
        case SNDRV_SEQ_EVENT_LENGTH_VARUSR:
-               if (! snd_seq_ev_is_instr_type(ev) ||
-                   ! snd_seq_ev_is_direct(ev))
+               if (! snd_seq_ev_is_direct(ev))
                        return -EINVAL;
                break;
        }
index 5e04e20e239f4f22fafae0e270fb2f36e7c629fa..20f0a725ec7db293a1edc18c83af60fe3ab11d34 100644 (file)
@@ -98,4 +98,6 @@ int snd_seq_kernel_client_write_poll(int clientid, struct file *file, poll_table
 int snd_seq_client_notify_subscription(int client, int port,
                                       struct snd_seq_port_subscribe *info, int evtype);
 
+extern int seq_client_load[15];
+
 #endif
index 37852cdace76091c83a4c33b063c1a60f5a0959c..155dc7da47222d5f5c0ab954a24bb80e85625a25 100644 (file)
@@ -36,7 +36,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <sound/core.h>
 #include <sound/info.h>
index e55488d1237cebf9435cbafa03d5b5e93364ff08..f3bdc54b429a91d99549cbb3cf510e04e30e8295 100644 (file)
@@ -18,7 +18,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/moduleparam.h>
index 6b055aed7a4b232fe6ee7b835b84a7bd6d55aac4..3a94ed021bd96e0ef177284f8c8a9113dbfbb0c2 100644 (file)
@@ -19,7 +19,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <sound/core.h>
 #include <linux/slab.h>
 #include "seq_fifo.h"
index 8a7fe5cca1c90022fa765fd025108c2b37331532..201f8106ffdd9b36224a9c798997457db65b92cc 100644 (file)
@@ -19,7 +19,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <sound/core.h>
 
diff --git a/sound/core/seq/seq_instr.c b/sound/core/seq/seq_instr.c
deleted file mode 100644 (file)
index 9a6fd56..0000000
+++ /dev/null
@@ -1,655 +0,0 @@
-/*
- *   Generic Instrument routines for ALSA sequencer
- *   Copyright (c) 1999 by Jaroslav Kysela <perex@perex.cz>
- *
- *   This program is free software; you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   the Free Software Foundation; either version 2 of the License, or
- *   (at your option) any later version.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program; if not, write to the Free Software
- *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
- *
- */
-#include <sound/driver.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <sound/core.h>
-#include "seq_clientmgr.h"
-#include <sound/seq_instr.h>
-#include <sound/initval.h>
-
-MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
-MODULE_DESCRIPTION("Advanced Linux Sound Architecture sequencer instrument library.");
-MODULE_LICENSE("GPL");
-
-
-static void snd_instr_lock_ops(struct snd_seq_kinstr_list *list)
-{
-       if (!(list->flags & SNDRV_SEQ_INSTR_FLG_DIRECT)) {
-               spin_lock_irqsave(&list->ops_lock, list->ops_flags);
-       } else {
-               mutex_lock(&list->ops_mutex);
-       }
-}
-
-static void snd_instr_unlock_ops(struct snd_seq_kinstr_list *list)
-{
-       if (!(list->flags & SNDRV_SEQ_INSTR_FLG_DIRECT)) {
-               spin_unlock_irqrestore(&list->ops_lock, list->ops_flags);
-       } else {
-               mutex_unlock(&list->ops_mutex);
-       }
-}
-
-static struct snd_seq_kinstr *snd_seq_instr_new(int add_len, int atomic)
-{
-       struct snd_seq_kinstr *instr;
-       
-       instr = kzalloc(sizeof(struct snd_seq_kinstr) + add_len, atomic ? GFP_ATOMIC : GFP_KERNEL);
-       if (instr == NULL)
-               return NULL;
-       instr->add_len = add_len;
-       return instr;
-}
-
-static int snd_seq_instr_free(struct snd_seq_kinstr *instr, int atomic)
-{
-       int result = 0;
-
-       if (instr == NULL)
-               return -EINVAL;
-       if (instr->ops && instr->ops->remove)
-               result = instr->ops->remove(instr->ops->private_data, instr, 1);
-       if (!result)
-               kfree(instr);
-       return result;
-}
-
-struct snd_seq_kinstr_list *snd_seq_instr_list_new(void)
-{
-       struct snd_seq_kinstr_list *list;
-
-       list = kzalloc(sizeof(struct snd_seq_kinstr_list), GFP_KERNEL);
-       if (list == NULL)
-               return NULL;
-       spin_lock_init(&list->lock);
-       spin_lock_init(&list->ops_lock);
-       mutex_init(&list->ops_mutex);
-       list->owner = -1;
-       return list;
-}
-
-void snd_seq_instr_list_free(struct snd_seq_kinstr_list **list_ptr)
-{
-       struct snd_seq_kinstr_list *list;
-       struct snd_seq_kinstr *instr;
-       struct snd_seq_kcluster *cluster;
-       int idx;
-       unsigned long flags;
-
-       if (list_ptr == NULL)
-               return;
-       list = *list_ptr;
-       *list_ptr = NULL;
-       if (list == NULL)
-               return;
-       
-       for (idx = 0; idx < SNDRV_SEQ_INSTR_HASH_SIZE; idx++) {         
-               while ((instr = list->hash[idx]) != NULL) {
-                       list->hash[idx] = instr->next;
-                       list->count--;
-                       spin_lock_irqsave(&list->lock, flags);
-                       while (instr->use) {
-                               spin_unlock_irqrestore(&list->lock, flags);
-                               schedule_timeout_uninterruptible(1);
-                               spin_lock_irqsave(&list->lock, flags);
-                       }                               
-                       spin_unlock_irqrestore(&list->lock, flags);
-                       if (snd_seq_instr_free(instr, 0)<0)
-                               snd_printk(KERN_WARNING "instrument free problem\n");
-               }
-               while ((cluster = list->chash[idx]) != NULL) {
-                       list->chash[idx] = cluster->next;
-                       list->ccount--;
-                       kfree(cluster);
-               }
-       }
-       kfree(list);
-}
-
-static int instr_free_compare(struct snd_seq_kinstr *instr,
-                             struct snd_seq_instr_header *ifree,
-                             unsigned int client)
-{
-       switch (ifree->cmd) {
-       case SNDRV_SEQ_INSTR_FREE_CMD_ALL:
-               /* all, except private for other clients */
-               if ((instr->instr.std & 0xff000000) == 0)
-                       return 0;
-               if (((instr->instr.std >> 24) & 0xff) == client)
-                       return 0;
-               return 1;
-       case SNDRV_SEQ_INSTR_FREE_CMD_PRIVATE:
-               /* all my private instruments */
-               if ((instr->instr.std & 0xff000000) == 0)
-                       return 1;
-               if (((instr->instr.std >> 24) & 0xff) == client)
-                       return 0;
-               return 1;
-       case SNDRV_SEQ_INSTR_FREE_CMD_CLUSTER:
-               /* all my private instruments */
-               if ((instr->instr.std & 0xff000000) == 0) {
-                       if (instr->instr.cluster == ifree->id.cluster)
-                               return 0;
-                       return 1;
-               }
-               if (((instr->instr.std >> 24) & 0xff) == client) {
-                       if (instr->instr.cluster == ifree->id.cluster)
-                               return 0;
-               }
-               return 1;
-       }
-       return 1;
-}
-
-int snd_seq_instr_list_free_cond(struct snd_seq_kinstr_list *list,
-                                struct snd_seq_instr_header *ifree,
-                                int client,
-                                int atomic)
-{
-       struct snd_seq_kinstr *instr, *prev, *next, *flist;
-       int idx;
-       unsigned long flags;
-
-       snd_instr_lock_ops(list);
-       for (idx = 0; idx < SNDRV_SEQ_INSTR_HASH_SIZE; idx++) {
-               spin_lock_irqsave(&list->lock, flags);
-               instr = list->hash[idx];
-               prev = flist = NULL;
-               while (instr) {
-                       while (instr && instr_free_compare(instr, ifree, (unsigned int)client)) {
-                               prev = instr;
-                               instr = instr->next;
-                       }
-                       if (instr == NULL)
-                               continue;
-                       if (instr->ops && instr->ops->notify)
-                               instr->ops->notify(instr->ops->private_data, instr, SNDRV_SEQ_INSTR_NOTIFY_REMOVE);
-                       next = instr->next;
-                       if (prev == NULL) {
-                               list->hash[idx] = next;
-                       } else {
-                               prev->next = next;
-                       }
-                       list->count--;
-                       instr->next = flist;
-                       flist = instr;
-                       instr = next;
-               }
-               spin_unlock_irqrestore(&list->lock, flags);
-               while (flist) {
-                       instr = flist;
-                       flist = instr->next;
-                       while (instr->use) {
-                               schedule_timeout_uninterruptible(1);
-                               barrier();
-                       }
-                       if (snd_seq_instr_free(instr, atomic)<0)
-                               snd_printk(KERN_WARNING "instrument free problem\n");
-                       instr = next;
-               }
-       }
-       snd_instr_unlock_ops(list);
-       return 0;       
-}
-
-static int compute_hash_instr_key(struct snd_seq_instr *instr)
-{
-       int result;
-       
-       result = instr->bank | (instr->prg << 16);
-       result += result >> 24;
-       result += result >> 16;
-       result += result >> 8;
-       return result & (SNDRV_SEQ_INSTR_HASH_SIZE-1);
-}
-
-#if 0
-static int compute_hash_cluster_key(snd_seq_instr_cluster_t cluster)
-{
-       int result;
-       
-       result = cluster;
-       result += result >> 24;
-       result += result >> 16;
-       result += result >> 8;
-       return result & (SNDRV_SEQ_INSTR_HASH_SIZE-1);
-}
-#endif
-
-static int compare_instr(struct snd_seq_instr *i1, struct snd_seq_instr *i2, int exact)
-{
-       if (exact) {
-               if (i1->cluster != i2->cluster ||
-                   i1->bank != i2->bank ||
-                   i1->prg != i2->prg)
-                       return 1;
-               if ((i1->std & 0xff000000) != (i2->std & 0xff000000))
-                       return 1;
-               if (!(i1->std & i2->std))
-                       return 1;
-               return 0;
-       } else {
-               unsigned int client_check;
-               
-               if (i2->cluster && i1->cluster != i2->cluster)
-                       return 1;
-               client_check = i2->std & 0xff000000;
-               if (client_check) {
-                       if ((i1->std & 0xff000000) != client_check)
-                               return 1;
-               } else {
-                       if ((i1->std & i2->std) != i2->std)
-                               return 1;
-               }
-               return i1->bank != i2->bank || i1->prg != i2->prg;
-       }
-}
-
-struct snd_seq_kinstr *snd_seq_instr_find(struct snd_seq_kinstr_list *list,
-                                         struct snd_seq_instr *instr,
-                                         int exact,
-                                         int follow_alias)
-{
-       unsigned long flags;
-       int depth = 0;
-       struct snd_seq_kinstr *result;
-
-       if (list == NULL || instr == NULL)
-               return NULL;
-       spin_lock_irqsave(&list->lock, flags);
-      __again:
-       result = list->hash[compute_hash_instr_key(instr)];
-       while (result) {
-               if (!compare_instr(&result->instr, instr, exact)) {
-                       if (follow_alias && (result->type == SNDRV_SEQ_INSTR_ATYPE_ALIAS)) {
-                               instr = (struct snd_seq_instr *)KINSTR_DATA(result);
-                               if (++depth > 10)
-                                       goto __not_found;
-                               goto __again;
-                       }
-                       result->use++;
-                       spin_unlock_irqrestore(&list->lock, flags);
-                       return result;
-               }
-               result = result->next;
-       }
-      __not_found:
-       spin_unlock_irqrestore(&list->lock, flags);
-       return NULL;
-}
-
-void snd_seq_instr_free_use(struct snd_seq_kinstr_list *list,
-                           struct snd_seq_kinstr *instr)
-{
-       unsigned long flags;
-
-       if (list == NULL || instr == NULL)
-               return;
-       spin_lock_irqsave(&list->lock, flags);
-       if (instr->use <= 0) {
-               snd_printk(KERN_ERR "free_use: fatal!!! use = %i, name = '%s'\n", instr->use, instr->name);
-       } else {
-               instr->use--;
-       }
-       spin_unlock_irqrestore(&list->lock, flags);
-}
-
-static struct snd_seq_kinstr_ops *instr_ops(struct snd_seq_kinstr_ops *ops,
-                                           char *instr_type)
-{
-       while (ops) {
-               if (!strcmp(ops->instr_type, instr_type))
-                       return ops;
-               ops = ops->next;
-       }
-       return NULL;
-}
-
-static int instr_result(struct snd_seq_event *ev,
-                       int type, int result,
-                       int atomic)
-{
-       struct snd_seq_event sev;
-       
-       memset(&sev, 0, sizeof(sev));
-       sev.type = SNDRV_SEQ_EVENT_RESULT;
-       sev.flags = SNDRV_SEQ_TIME_STAMP_REAL | SNDRV_SEQ_EVENT_LENGTH_FIXED |
-                   SNDRV_SEQ_PRIORITY_NORMAL;
-       sev.source = ev->dest;
-       sev.dest = ev->source;
-       sev.data.result.event = type;
-       sev.data.result.result = result;
-#if 0
-       printk("instr result - type = %i, result = %i, queue = %i, source.client:port = %i:%i, dest.client:port = %i:%i\n",
-                               type, result,
-                               sev.queue,
-                               sev.source.client, sev.source.port,
-                               sev.dest.client, sev.dest.port);
-#endif
-       return snd_seq_kernel_client_dispatch(sev.source.client, &sev, atomic, 0);
-}
-
-static int instr_begin(struct snd_seq_kinstr_ops *ops,
-                      struct snd_seq_kinstr_list *list,
-                      struct snd_seq_event *ev,
-                      int atomic, int hop)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&list->lock, flags);
-       if (list->owner >= 0 && list->owner != ev->source.client) {
-               spin_unlock_irqrestore(&list->lock, flags);
-               return instr_result(ev, SNDRV_SEQ_EVENT_INSTR_BEGIN, -EBUSY, atomic);
-       }
-       list->owner = ev->source.client;
-       spin_unlock_irqrestore(&list->lock, flags);
-       return instr_result(ev, SNDRV_SEQ_EVENT_INSTR_BEGIN, 0, atomic);
-}
-
-static int instr_end(struct snd_seq_kinstr_ops *ops,
-                    struct snd_seq_kinstr_list *list,
-                    struct snd_seq_event *ev,
-                    int atomic, int hop)
-{
-       unsigned long flags;
-
-       /* TODO: timeout handling */
-       spin_lock_irqsave(&list->lock, flags);
-       if (list->owner == ev->source.client) {
-               list->owner = -1;
-               spin_unlock_irqrestore(&list->lock, flags);
-               return instr_result(ev, SNDRV_SEQ_EVENT_INSTR_END, 0, atomic);
-       }
-       spin_unlock_irqrestore(&list->lock, flags);
-       return instr_result(ev, SNDRV_SEQ_EVENT_INSTR_END, -EINVAL, atomic);
-}
-
-static int instr_info(struct snd_seq_kinstr_ops *ops,
-                     struct snd_seq_kinstr_list *list,
-                     struct snd_seq_event *ev,
-                     int atomic, int hop)
-{
-       return -ENXIO;
-}
-
-static int instr_format_info(struct snd_seq_kinstr_ops *ops,
-                            struct snd_seq_kinstr_list *list,
-                            struct snd_seq_event *ev,
-                            int atomic, int hop)
-{
-       return -ENXIO;
-}
-
-static int instr_reset(struct snd_seq_kinstr_ops *ops,
-                      struct snd_seq_kinstr_list *list,
-                      struct snd_seq_event *ev,
-                      int atomic, int hop)
-{
-       return -ENXIO;
-}
-
-static int instr_status(struct snd_seq_kinstr_ops *ops,
-                       struct snd_seq_kinstr_list *list,
-                       struct snd_seq_event *ev,
-                       int atomic, int hop)
-{
-       return -ENXIO;
-}
-
-static int instr_put(struct snd_seq_kinstr_ops *ops,
-                    struct snd_seq_kinstr_list *list,
-                    struct snd_seq_event *ev,
-                    int atomic, int hop)
-{
-       unsigned long flags;
-       struct snd_seq_instr_header put;
-       struct snd_seq_kinstr *instr;
-       int result = -EINVAL, len, key;
-
-       if ((ev->flags & SNDRV_SEQ_EVENT_LENGTH_MASK) != SNDRV_SEQ_EVENT_LENGTH_VARUSR)
-               goto __return;
-
-       if (ev->data.ext.len < sizeof(struct snd_seq_instr_header))
-               goto __return;
-       if (copy_from_user(&put, (void __user *)ev->data.ext.ptr,
-                          sizeof(struct snd_seq_instr_header))) {
-               result = -EFAULT;
-               goto __return;
-       }
-       snd_instr_lock_ops(list);
-       if (put.id.instr.std & 0xff000000) {    /* private instrument */
-               put.id.instr.std &= 0x00ffffff;
-               put.id.instr.std |= (unsigned int)ev->source.client << 24;
-       }
-       if ((instr = snd_seq_instr_find(list, &put.id.instr, 1, 0))) {
-               snd_seq_instr_free_use(list, instr);
-               snd_instr_unlock_ops(list);
-               result = -EBUSY;
-               goto __return;
-       }
-       ops = instr_ops(ops, put.data.data.format);
-       if (ops == NULL) {
-               snd_instr_unlock_ops(list);
-               goto __return;
-       }
-       len = ops->add_len;
-       if (put.data.type == SNDRV_SEQ_INSTR_ATYPE_ALIAS)
-               len = sizeof(struct snd_seq_instr);
-       instr = snd_seq_instr_new(len, atomic);
-       if (instr == NULL) {
-               snd_instr_unlock_ops(list);
-               result = -ENOMEM;
-               goto __return;
-       }
-       instr->ops = ops;
-       instr->instr = put.id.instr;
-       strlcpy(instr->name, put.data.name, sizeof(instr->name));
-       instr->type = put.data.type;
-       if (instr->type == SNDRV_SEQ_INSTR_ATYPE_DATA) {
-               result = ops->put(ops->private_data,
-                                 instr,
-                                 (void __user *)ev->data.ext.ptr + sizeof(struct snd_seq_instr_header),
-                                 ev->data.ext.len - sizeof(struct snd_seq_instr_header),
-                                 atomic,
-                                 put.cmd);
-               if (result < 0) {
-                       snd_seq_instr_free(instr, atomic);
-                       snd_instr_unlock_ops(list);
-                       goto __return;
-               }
-       }
-       key = compute_hash_instr_key(&instr->instr);
-       spin_lock_irqsave(&list->lock, flags);
-       instr->next = list->hash[key];
-       list->hash[key] = instr;
-       list->count++;
-       spin_unlock_irqrestore(&list->lock, flags);
-       snd_instr_unlock_ops(list);
-       result = 0;
-      __return:
-       instr_result(ev, SNDRV_SEQ_EVENT_INSTR_PUT, result, atomic);
-       return result;
-}
-
-static int instr_get(struct snd_seq_kinstr_ops *ops,
-                    struct snd_seq_kinstr_list *list,
-                    struct snd_seq_event *ev,
-                    int atomic, int hop)
-{
-       return -ENXIO;
-}
-
-static int instr_free(struct snd_seq_kinstr_ops *ops,
-                     struct snd_seq_kinstr_list *list,
-                     struct snd_seq_event *ev,
-                     int atomic, int hop)
-{
-       struct snd_seq_instr_header ifree;
-       struct snd_seq_kinstr *instr, *prev;
-       int result = -EINVAL;
-       unsigned long flags;
-       unsigned int hash;
-
-       if ((ev->flags & SNDRV_SEQ_EVENT_LENGTH_MASK) != SNDRV_SEQ_EVENT_LENGTH_VARUSR)
-               goto __return;
-
-       if (ev->data.ext.len < sizeof(struct snd_seq_instr_header))
-               goto __return;
-       if (copy_from_user(&ifree, (void __user *)ev->data.ext.ptr,
-                          sizeof(struct snd_seq_instr_header))) {
-               result = -EFAULT;
-               goto __return;
-       }
-       if (ifree.cmd == SNDRV_SEQ_INSTR_FREE_CMD_ALL ||
-           ifree.cmd == SNDRV_SEQ_INSTR_FREE_CMD_PRIVATE ||
-           ifree.cmd == SNDRV_SEQ_INSTR_FREE_CMD_CLUSTER) {
-               result = snd_seq_instr_list_free_cond(list, &ifree, ev->dest.client, atomic);
-               goto __return;
-       }
-       if (ifree.cmd == SNDRV_SEQ_INSTR_FREE_CMD_SINGLE) {
-               if (ifree.id.instr.std & 0xff000000) {
-                       ifree.id.instr.std &= 0x00ffffff;
-                       ifree.id.instr.std |= (unsigned int)ev->source.client << 24;
-               }
-               hash = compute_hash_instr_key(&ifree.id.instr);
-               snd_instr_lock_ops(list);
-               spin_lock_irqsave(&list->lock, flags);
-               instr = list->hash[hash];
-               prev = NULL;
-               while (instr) {
-                       if (!compare_instr(&instr->instr, &ifree.id.instr, 1))
-                               goto __free_single;
-                       prev = instr;
-                       instr = instr->next;
-               }
-               result = -ENOENT;
-               spin_unlock_irqrestore(&list->lock, flags);
-               snd_instr_unlock_ops(list);
-               goto __return;
-               
-             __free_single:
-               if (prev) {
-                       prev->next = instr->next;
-               } else {
-                       list->hash[hash] = instr->next;
-               }
-               if (instr->ops && instr->ops->notify)
-                       instr->ops->notify(instr->ops->private_data, instr,
-                                          SNDRV_SEQ_INSTR_NOTIFY_REMOVE);
-               while (instr->use) {
-                       spin_unlock_irqrestore(&list->lock, flags);
-                       schedule_timeout_uninterruptible(1);
-                       spin_lock_irqsave(&list->lock, flags);
-               }                               
-               spin_unlock_irqrestore(&list->lock, flags);
-               result = snd_seq_instr_free(instr, atomic);
-               snd_instr_unlock_ops(list);
-               goto __return;
-       }
-
-      __return:
-       instr_result(ev, SNDRV_SEQ_EVENT_INSTR_FREE, result, atomic);
-       return result;
-}
-
-static int instr_list(struct snd_seq_kinstr_ops *ops,
-                     struct snd_seq_kinstr_list *list,
-                     struct snd_seq_event *ev,
-                     int atomic, int hop)
-{
-       return -ENXIO;
-}
-
-static int instr_cluster(struct snd_seq_kinstr_ops *ops,
-                        struct snd_seq_kinstr_list *list,
-                        struct snd_seq_event *ev,
-                        int atomic, int hop)
-{
-       return -ENXIO;
-}
-
-int snd_seq_instr_event(struct snd_seq_kinstr_ops *ops,
-                       struct snd_seq_kinstr_list *list,
-                       struct snd_seq_event *ev,
-                       int client,
-                       int atomic,
-                       int hop)
-{
-       int direct = 0;
-
-       snd_assert(ops != NULL && list != NULL && ev != NULL, return -EINVAL);
-       if (snd_seq_ev_is_direct(ev)) {
-               direct = 1;
-               switch (ev->type) {
-               case SNDRV_SEQ_EVENT_INSTR_BEGIN:
-                       return instr_begin(ops, list, ev, atomic, hop);
-               case SNDRV_SEQ_EVENT_INSTR_END:
-                       return instr_end(ops, list, ev, atomic, hop);
-               }
-       }
-       if ((list->flags & SNDRV_SEQ_INSTR_FLG_DIRECT) && !direct)
-               return -EINVAL;
-       switch (ev->type) {
-       case SNDRV_SEQ_EVENT_INSTR_INFO:
-               return instr_info(ops, list, ev, atomic, hop);
-       case SNDRV_SEQ_EVENT_INSTR_FINFO:
-               return instr_format_info(ops, list, ev, atomic, hop);
-       case SNDRV_SEQ_EVENT_INSTR_RESET:
-               return instr_reset(ops, list, ev, atomic, hop);
-       case SNDRV_SEQ_EVENT_INSTR_STATUS:
-               return instr_status(ops, list, ev, atomic, hop);
-       case SNDRV_SEQ_EVENT_INSTR_PUT:
-               return instr_put(ops, list, ev, atomic, hop);
-       case SNDRV_SEQ_EVENT_INSTR_GET:
-               return instr_get(ops, list, ev, atomic, hop);
-       case SNDRV_SEQ_EVENT_INSTR_FREE:
-               return instr_free(ops, list, ev, atomic, hop);
-       case SNDRV_SEQ_EVENT_INSTR_LIST:
-               return instr_list(ops, list, ev, atomic, hop);
-       case SNDRV_SEQ_EVENT_INSTR_CLUSTER:
-               return instr_cluster(ops, list, ev, atomic, hop);
-       }
-       return -EINVAL;
-}
-                       
-/*
- *  Init part
- */
-
-static int __init alsa_seq_instr_init(void)
-{
-       return 0;
-}
-
-static void __exit alsa_seq_instr_exit(void)
-{
-}
-
-module_init(alsa_seq_instr_init)
-module_exit(alsa_seq_instr_exit)
-
-EXPORT_SYMBOL(snd_seq_instr_list_new);
-EXPORT_SYMBOL(snd_seq_instr_list_free);
-EXPORT_SYMBOL(snd_seq_instr_list_free_cond);
-EXPORT_SYMBOL(snd_seq_instr_find);
-EXPORT_SYMBOL(snd_seq_instr_free_use);
-EXPORT_SYMBOL(snd_seq_instr_event);
index 1a34941d42172b8e1d2cedf0c73caba91f4b63c6..54f921edda793aab4948b0c72259528ee0885d9d 100644 (file)
@@ -19,7 +19,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <sound/core.h>
 #include "seq_lock.h"
 
index a72a1945bf8adb93e9590764c6994bb47632b742..0cf6ac4773187cca81cf511258083f060bd9cfc6 100644 (file)
@@ -20,7 +20,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
index 5929aaf1df9d1f3340d509b2424bab4fb6cb50fa..99b35360c5066df99574c2f2dca0753f9f557609 100644 (file)
@@ -26,7 +26,6 @@ Possible options for midisynth module:
 */
 
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/errno.h>
index 17b3e6f13ca3564c08f3ca0e81f2ddcd5041ad91..07c663135c62d87d054d389e7a84320820497b04 100644 (file)
@@ -29,7 +29,6 @@
  * code in here.  If there is it should be reported as a bug.
  */
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/string.h>
@@ -229,13 +228,6 @@ snd_midi_process_event(struct snd_midi_op *ops,
        case SNDRV_SEQ_EVENT_PORT_START:
        case SNDRV_SEQ_EVENT_PORT_EXIT:
        case SNDRV_SEQ_EVENT_PORT_CHANGE:
-       case SNDRV_SEQ_EVENT_SAMPLE:
-       case SNDRV_SEQ_EVENT_SAMPLE_START:
-       case SNDRV_SEQ_EVENT_SAMPLE_STOP:
-       case SNDRV_SEQ_EVENT_SAMPLE_FREQ:
-       case SNDRV_SEQ_EVENT_SAMPLE_VOLUME:
-       case SNDRV_SEQ_EVENT_SAMPLE_LOOP:
-       case SNDRV_SEQ_EVENT_SAMPLE_POSITION:
        case SNDRV_SEQ_EVENT_ECHO:
        not_yet:
        default:
index b6820a5a73fc1518d0048c0d5f327331d7b45d4c..8284f176a342c6011f470a9d27581438ba23c73a 100644 (file)
@@ -19,7 +19,6 @@
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-#include <sound/driver.h>
 #include <linux/slab.h>
 #include <linux/errno.h>
 #include <linux/string.h>
index b6e23ad12ab9bd2d94a0f72ca58a2eba74a9d199..1c32a53d6bd8d91084fb1a560277199557f40e35 100644 (file)
@@ -20,7 +20,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <sound/core.h>
 #include <linux/slab.h>
 #include "seq_system.h"
index 074418617ee9f1dabacde501b9d45e37cdff6a3d..85969db576c905514974d478e2c1495c8848ff05 100644 (file)
@@ -19,7 +19,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/time.h>
 #include <linux/slab.h>
 #include <sound/core.h>
index 9b87bb0c7f33a3f4dcf266b8d5d1236004a62c92..4a48c6ee8ee835b7b55cc74967ca87beb1ba0812 100644 (file)
@@ -35,7 +35,6 @@
  *     - Addition of experimental sync support.
  */
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <sound/core.h>
index b201b76e9412b58b9761f4fdf3bbf2e30bbffc3a..77884e62b6483216981c0d2a9da553ac86b9f138 100644 (file)
@@ -19,7 +19,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <sound/core.h>
 #include "seq_system.h"
index 8716352afc812a8eb9dee2469d2e6c3fd1f30433..d8fcd62e400f0ed512b330132e3c603ad4cc7b49 100644 (file)
  *
  */
 
-#include <sound/driver.h>
 #include <sound/core.h>
 #include <linux/slab.h>
 #include "seq_timer.h"
 #include "seq_queue.h"
 #include "seq_info.h"
 
-extern int seq_default_timer_class;
-extern int seq_default_timer_sclass;
-extern int seq_default_timer_card;
-extern int seq_default_timer_device;
-extern int seq_default_timer_subdevice;
-extern int seq_default_timer_resolution;
-
 /* allowed sequencer timer frequencies, in Hz */
 #define MIN_FREQUENCY          10
 #define MAX_FREQUENCY          6250
index e9ee1543c9247e64f229d642118cec785d2eced9..88dfb71805ae0b0b49bfeb37d5b44aa40214ac57 100644 (file)
@@ -138,4 +138,11 @@ int snd_seq_timer_set_skew(struct snd_seq_timer *tmr, unsigned int skew, unsigne
 snd_seq_real_time_t snd_seq_timer_get_cur_time(struct snd_seq_timer *tmr);
 snd_seq_tick_time_t snd_seq_timer_get_cur_tick(struct snd_seq_timer *tmr);
 
+extern int seq_default_timer_class;
+extern int seq_default_timer_sclass;
+extern int seq_default_timer_card;
+extern int seq_default_timer_device;
+extern int seq_default_timer_subdevice;
+extern int seq_default_timer_resolution;
+
 #endif
index e11790f6debea51e2b4fe24c4fc1ebab2c10654b..86e7739269ca2f4899eaeeb057a60f4bef556459 100644 (file)
@@ -35,7 +35,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/wait.h>
 #include <linux/slab.h>
index 7b486c4d70db7c9c21d19a416b6a8db017b5ceb9..00cca4d6e56226e454484b0fc660102c55f1bdc4 100644 (file)
@@ -19,7 +19,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/time.h>
index dc73313b733a32915ac4d729e9df751c57490d4b..7be51546eb9e8cd8b26d46e0bb4306377edb2278 100644 (file)
@@ -19,8 +19,6 @@
  *
  */
 
-#include <sound/driver.h>
-
 #ifdef CONFIG_SND_OSSEMUL
 
 #if !defined(CONFIG_SOUND) && !(defined(MODULE) && defined(CONFIG_SOUND_MODULE))
index e7dc56ca4b97d6840f286fd1013f3cfde80731a1..aece465934b86aa5f4266870b7e3cc7c1e745b1b 100644 (file)
@@ -19,7 +19,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/slab.h>
 #endif
 
 static int timer_limit = DEFAULT_TIMER_LIMIT;
+static int timer_tstamp_monotonic = 1;
 MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>, Takashi Iwai <tiwai@suse.de>");
 MODULE_DESCRIPTION("ALSA timer interface");
 MODULE_LICENSE("GPL");
 module_param(timer_limit, int, 0444);
 MODULE_PARM_DESC(timer_limit, "Maximum global timers in system.");
+module_param(timer_tstamp_monotonic, int, 0444);
+MODULE_PARM_DESC(timer_tstamp_monotonic, "Use posix monotonic clock source for timestamps (default).");
 
 struct snd_timer_user {
        struct snd_timer_instance *timeri;
@@ -381,7 +383,10 @@ static void snd_timer_notify1(struct snd_timer_instance *ti, int event)
        struct snd_timer_instance *ts;
        struct timespec tstamp;
 
-       getnstimeofday(&tstamp);
+       if (timer_tstamp_monotonic)
+               do_posix_clock_monotonic_gettime(&tstamp);
+       else
+               getnstimeofday(&tstamp);
        snd_assert(event >= SNDRV_TIMER_EVENT_START &&
                   event <= SNDRV_TIMER_EVENT_PAUSE, return);
        if (event == SNDRV_TIMER_EVENT_START ||
@@ -1182,8 +1187,12 @@ static void snd_timer_user_tinterrupt(struct snd_timer_instance *timeri,
                spin_unlock(&tu->qlock);
                return;
        }
-       if (tu->last_resolution != resolution || ticks > 0)
-               getnstimeofday(&tstamp);
+       if (tu->last_resolution != resolution || ticks > 0) {
+               if (timer_tstamp_monotonic)
+                       do_posix_clock_monotonic_gettime(&tstamp);
+               else
+                       getnstimeofday(&tstamp);
+       }
        if ((tu->filter & (1 << SNDRV_TIMER_EVENT_RESOLUTION)) &&
            tu->last_resolution != resolution) {
                r1.event = SNDRV_TIMER_EVENT_RESOLUTION;
index 83529b08d019804945972dd4e474fe9a33a78f5d..75d4fe09fdf363fc2a9fe7ee06439330150c397a 100644 (file)
@@ -120,4 +120,16 @@ config SND_PORTMAN2X4
          To compile this driver as a module, choose M here: the module
          will be called snd-portman2x4.
 
+config SND_ML403_AC97CR
+       tristate "Xilinx ML403 AC97 Controller Reference"
+       depends on SND && XILINX_VIRTEX
+       select SND_AC97_CODEC
+       help
+         Say Y here to include support for the
+         opb_ac97_controller_ref_v1_00_a ip core found in Xilinx' ML403
+         reference design.
+
+         To compile this driver as a module, choose M here: the module
+         will be called snd-ml403_ac97cr.
+
 endmenu
index 80aeff5ccdea390fe7953264ffd0b55311acdd11..8e5530006e1fccb1d0704e0a35ee14a30105e064 100644 (file)
@@ -9,6 +9,7 @@ snd-mts64-objs := mts64.o
 snd-portman2x4-objs := portman2x4.o
 snd-serial-u16550-objs := serial-u16550.o
 snd-virmidi-objs := virmidi.o
+snd-ml403-ac97cr-objs := ml403-ac97cr.o pcm-indirect2.o
 
 # Toplevel Module Dependency
 obj-$(CONFIG_SND_DUMMY) += snd-dummy.o
@@ -17,5 +18,6 @@ obj-$(CONFIG_SND_SERIAL_U16550) += snd-serial-u16550.o
 obj-$(CONFIG_SND_MTPAV) += snd-mtpav.o
 obj-$(CONFIG_SND_MTS64) += snd-mts64.o
 obj-$(CONFIG_SND_PORTMAN2X4) += snd-portman2x4.o
+obj-$(CONFIG_SND_ML403_AC97CR) += snd-ml403-ac97cr.o
 
 obj-$(CONFIG_SND) += opl3/ opl4/ mpu401/ vx/
index e008f3c58eaca172c19b0284d9100780bc705575..a240eaeb5c620d754c81a23602e0b4809b4fe40f 100644 (file)
@@ -18,7 +18,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/err.h>
 #include <linux/platform_device.h>
diff --git a/sound/drivers/ml403-ac97cr.c b/sound/drivers/ml403-ac97cr.c
new file mode 100644 (file)
index 0000000..05a871a
--- /dev/null
@@ -0,0 +1,1352 @@
+/*
+ * ALSA driver for Xilinx ML403 AC97 Controller Reference
+ *   IP: opb_ac97_controller_ref_v1_00_a (EDK 8.1i)
+ *   IP: opb_ac97_controller_ref_v1_00_a (EDK 9.1i)
+ *
+ *  Copyright (c) by 2007  Joachim Foerster <JOFT@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., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */
+
+/* Some notes / status of this driver:
+ *
+ * - Don't wonder about some strange implementations of things - especially the
+ * (heavy) shadowing of codec registers, with which I tried to reduce read
+ * accesses to a minimum, because after a variable amount of accesses, the AC97
+ * controller doesn't raise the register access finished bit anymore ...
+ *
+ * - Playback support seems to be pretty stable - no issues here.
+ * - Capture support "works" now, too. Overruns don't happen any longer so often.
+ *   But there might still be some ...
+ */
+
+#include <linux/init.h>
+#include <linux/moduleparam.h>
+
+#include <linux/platform_device.h>
+
+#include <linux/ioport.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+
+/* HZ */
+#include <linux/param.h>
+/* jiffies, time_*() */
+#include <linux/jiffies.h>
+/* schedule_timeout*() */
+#include <linux/sched.h>
+/* spin_lock*() */
+#include <linux/spinlock.h>
+/* struct mutex, mutex_init(), mutex_*lock() */
+#include <linux/mutex.h>
+
+/* snd_printk(), snd_printd() */
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <sound/ac97_codec.h>
+
+#include "pcm-indirect2.h"
+
+
+#define SND_ML403_AC97CR_DRIVER "ml403-ac97cr"
+
+MODULE_AUTHOR("Joachim Foerster <JOFT@gmx.de>");
+MODULE_DESCRIPTION("Xilinx ML403 AC97 Controller Reference");
+MODULE_LICENSE("GPL");
+MODULE_SUPPORTED_DEVICE("{{Xilinx,ML403 AC97 Controller Reference}}");
+
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
+static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE;
+
+module_param_array(index, int, NULL, 0444);
+MODULE_PARM_DESC(index, "Index value for ML403 AC97 Controller Reference.");
+module_param_array(id, charp, NULL, 0444);
+MODULE_PARM_DESC(id, "ID string for ML403 AC97 Controller Reference.");
+module_param_array(enable, bool, NULL, 0444);
+MODULE_PARM_DESC(enable, "Enable this ML403 AC97 Controller Reference.");
+
+/* Special feature options */
+/*#define CODEC_WRITE_CHECK_RAF*/ /* don't return after a write to a codec
+                                  * register, while RAF bit is not set
+                                  */
+/* Debug options for code which may be removed completely in a final version */
+#ifdef CONFIG_SND_DEBUG
+/*#define CODEC_STAT*/            /* turn on some minimal "statistics"
+                                  * about codec register usage
+                                  */
+#define SND_PCM_INDIRECT2_STAT    /* turn on some "statistics" about the
+                                  * process of copying bytes from the
+                                  * intermediate buffer to the hardware
+                                  * fifo and the other way round
+                                  */
+#endif
+
+/* Definition of a "level/facility dependent" printk(); may be removed
+ * completely in a final version
+ */
+#undef PDEBUG
+#ifdef CONFIG_SND_DEBUG
+/* "facilities" for PDEBUG */
+#define UNKNOWN       (1<<0)
+#define CODEC_SUCCESS (1<<1)
+#define CODEC_FAKE    (1<<2)
+#define INIT_INFO     (1<<3)
+#define INIT_FAILURE  (1<<4)
+#define WORK_INFO     (1<<5)
+#define WORK_FAILURE  (1<<6)
+
+#define PDEBUG_FACILITIES (UNKNOWN | INIT_FAILURE | WORK_FAILURE)
+
+#define PDEBUG(fac, fmt, args...) do { \
+               if (fac & PDEBUG_FACILITIES) \
+                       snd_printd(KERN_DEBUG SND_ML403_AC97CR_DRIVER ": " \
+                                  fmt, ##args); \
+       } while (0)
+#else
+#define PDEBUG(fac, fmt, args...) /* nothing */
+#endif
+
+
+
+/* Defines for "waits"/timeouts (portions of HZ=250 on arch/ppc by default) */
+#define CODEC_TIMEOUT_ON_INIT       5  /* timeout for checking for codec
+                                        * readiness (after insmod)
+                                        */
+#ifndef CODEC_WRITE_CHECK_RAF
+#define CODEC_WAIT_AFTER_WRITE    100  /* general, static wait after a write
+                                        * access to a codec register, may be
+                                        * 0 to completely remove wait
+                                        */
+#else
+#define CODEC_TIMEOUT_AFTER_WRITE   5  /* timeout after a write access to a
+                                        * codec register, if RAF bit is used
+                                        */
+#endif
+#define CODEC_TIMEOUT_AFTER_READ    5  /* timeout after a read access to a
+                                        * codec register (checking RAF bit)
+                                        */
+
+/* Infrastructure for codec register shadowing */
+#define LM4550_REG_OK        (1<<0)   /* register exists */
+#define LM4550_REG_DONEREAD  (1<<1)   /* read register once, value should be
+                                      * the same currently in the register
+                                      */
+#define LM4550_REG_NOSAVE    (1<<2)   /* values written to this register will
+                                      * not be saved in the register
+                                      */
+#define LM4550_REG_NOSHADOW  (1<<3)   /* don't do register shadowing, use plain
+                                      * hardware access
+                                      */
+#define LM4550_REG_READONLY  (1<<4)   /* register is read only */
+#define LM4550_REG_FAKEPROBE (1<<5)   /* fake write _and_ read actions during
+                                      * probe() correctly
+                                      */
+#define LM4550_REG_FAKEREAD  (1<<6)   /* fake read access, always return
+                                      * default value
+                                      */
+#define LM4550_REG_ALLFAKE   (LM4550_REG_FAKEREAD | LM4550_REG_FAKEPROBE)
+
+struct lm4550_reg {
+       u16 value;
+       u16 flag;
+       u16 wmask;
+       u16 def;
+};
+
+struct lm4550_reg lm4550_regfile[64] = {
+       [AC97_RESET / 2]              = {.flag = LM4550_REG_OK \
+                                               | LM4550_REG_NOSAVE \
+                                               | LM4550_REG_FAKEREAD,
+                                        .def = 0x0D50},
+       [AC97_MASTER / 2]             = {.flag = LM4550_REG_OK
+                                               | LM4550_REG_FAKEPROBE,
+                                        .wmask = 0x9F1F,
+                                        .def = 0x8000},
+       [AC97_HEADPHONE / 2]          = {.flag = LM4550_REG_OK \
+                                               | LM4550_REG_FAKEPROBE,
+                                        .wmask = 0x9F1F,
+                                        .def = 0x8000},
+       [AC97_MASTER_MONO / 2]        = {.flag = LM4550_REG_OK \
+                                               | LM4550_REG_FAKEPROBE,
+                                        .wmask = 0x801F,
+                                        .def = 0x8000},
+       [AC97_PC_BEEP / 2]            = {.flag = LM4550_REG_OK \
+                                               | LM4550_REG_FAKEPROBE,
+                                        .wmask = 0x801E,
+                                        .def = 0x0},
+       [AC97_PHONE / 2]              = {.flag = LM4550_REG_OK \
+                                               | LM4550_REG_FAKEPROBE,
+                                        .wmask = 0x801F,
+                                        .def = 0x8008},
+       [AC97_MIC / 2]                = {.flag = LM4550_REG_OK \
+                                               | LM4550_REG_FAKEPROBE,
+                                        .wmask = 0x805F,
+                                        .def = 0x8008},
+       [AC97_LINE / 2]               = {.flag = LM4550_REG_OK \
+                                               | LM4550_REG_FAKEPROBE,
+                                        .wmask = 0x9F1F,
+                                        .def = 0x8808},
+       [AC97_CD / 2]                 = {.flag = LM4550_REG_OK \
+                                               | LM4550_REG_FAKEPROBE,
+                                        .wmask = 0x9F1F,
+                                        .def = 0x8808},
+       [AC97_VIDEO / 2]              = {.flag = LM4550_REG_OK \
+                                               | LM4550_REG_FAKEPROBE,
+                                        .wmask = 0x9F1F,
+                                        .def = 0x8808},
+       [AC97_AUX / 2]                = {.flag = LM4550_REG_OK \
+                                               | LM4550_REG_FAKEPROBE,
+                                        .wmask = 0x9F1F,
+                                        .def = 0x8808},
+       [AC97_PCM / 2]                = {.flag = LM4550_REG_OK \
+                                               | LM4550_REG_FAKEPROBE,
+                                        .wmask = 0x9F1F,
+                                        .def = 0x8008},
+       [AC97_REC_SEL / 2]            = {.flag = LM4550_REG_OK \
+                                               | LM4550_REG_FAKEPROBE,
+                                        .wmask = 0x707,
+                                        .def = 0x0},
+       [AC97_REC_GAIN / 2]           = {.flag = LM4550_REG_OK \
+                                               | LM4550_REG_FAKEPROBE,
+                                        .wmask = 0x8F0F,
+                                        .def = 0x8000},
+       [AC97_GENERAL_PURPOSE / 2]    = {.flag = LM4550_REG_OK \
+                                               | LM4550_REG_FAKEPROBE,
+                                        .def = 0x0,
+                                        .wmask = 0xA380},
+       [AC97_3D_CONTROL / 2]         = {.flag = LM4550_REG_OK \
+                                               | LM4550_REG_FAKEREAD \
+                                               | LM4550_REG_READONLY,
+                                        .def = 0x0101},
+       [AC97_POWERDOWN / 2]          = {.flag = LM4550_REG_OK \
+                                               | LM4550_REG_NOSHADOW \
+                                               | LM4550_REG_NOSAVE,
+                                        .wmask = 0xFF00},
+                                       /* may not write ones to
+                                        * REF/ANL/DAC/ADC bits
+                                        * FIXME: Is this ok?
+                                        */
+       [AC97_EXTENDED_ID / 2]        = {.flag = LM4550_REG_OK \
+                                               | LM4550_REG_FAKEREAD \
+                                               | LM4550_REG_READONLY,
+                                        .def = 0x0201}, /* primary codec */
+       [AC97_EXTENDED_STATUS / 2]    = {.flag = LM4550_REG_OK \
+                                               | LM4550_REG_NOSHADOW \
+                                               | LM4550_REG_NOSAVE,
+                                        .wmask = 0x1},
+       [AC97_PCM_FRONT_DAC_RATE / 2] = {.flag = LM4550_REG_OK \
+                                               | LM4550_REG_FAKEPROBE,
+                                        .def = 0xBB80,
+                                        .wmask = 0xFFFF},
+       [AC97_PCM_LR_ADC_RATE / 2]    = {.flag = LM4550_REG_OK \
+                                               | LM4550_REG_FAKEPROBE,
+                                        .def = 0xBB80,
+                                        .wmask = 0xFFFF},
+       [AC97_VENDOR_ID1 / 2]         = {.flag = LM4550_REG_OK \
+                                               | LM4550_REG_READONLY \
+                                               | LM4550_REG_FAKEREAD,
+                                        .def = 0x4E53},
+       [AC97_VENDOR_ID2 / 2]         = {.flag = LM4550_REG_OK \
+                                               | LM4550_REG_READONLY \
+                                               | LM4550_REG_FAKEREAD,
+                                        .def = 0x4350}
+};
+
+#define LM4550_RF_OK(reg)    (lm4550_regfile[reg / 2].flag & LM4550_REG_OK)
+
+static void lm4550_regfile_init(void)
+{
+       int i;
+       for (i = 0; i < 64; i++)
+               if (lm4550_regfile[i].flag & LM4550_REG_FAKEPROBE)
+                       lm4550_regfile[i].value = lm4550_regfile[i].def;
+}
+
+static void lm4550_regfile_write_values_after_init(struct snd_ac97 *ac97)
+{
+       int i;
+       for (i = 0; i < 64; i++)
+               if ((lm4550_regfile[i].flag & LM4550_REG_FAKEPROBE) &&
+                   (lm4550_regfile[i].value != lm4550_regfile[i].def)) {
+                       PDEBUG(CODEC_FAKE, "lm4550_regfile_write_values_after_"
+                              "init(): reg=0x%x value=0x%x / %d is different "
+                              "from def=0x%x / %d\n",
+                              i, lm4550_regfile[i].value,
+                              lm4550_regfile[i].value, lm4550_regfile[i].def,
+                              lm4550_regfile[i].def);
+                       snd_ac97_write(ac97, i * 2, lm4550_regfile[i].value);
+                       lm4550_regfile[i].flag |= LM4550_REG_DONEREAD;
+               }
+}
+
+
+/* direct registers */
+#define CR_REG(ml403_ac97cr, x) ((ml403_ac97cr)->port + CR_REG_##x)
+
+#define CR_REG_PLAYFIFO         0x00
+#define   CR_PLAYDATA(a)        ((a) & 0xFFFF)
+
+#define CR_REG_RECFIFO          0x04
+#define   CR_RECDATA(a)         ((a) & 0xFFFF)
+
+#define CR_REG_STATUS           0x08
+#define   CR_RECOVER            (1<<7)
+#define   CR_PLAYUNDER          (1<<6)
+#define   CR_CODECREADY         (1<<5)
+#define   CR_RAF                (1<<4)
+#define   CR_RECEMPTY           (1<<3)
+#define   CR_RECFULL            (1<<2)
+#define   CR_PLAYHALF           (1<<1)
+#define   CR_PLAYFULL           (1<<0)
+
+#define CR_REG_RESETFIFO        0x0C
+#define   CR_RECRESET           (1<<1)
+#define   CR_PLAYRESET          (1<<0)
+
+#define CR_REG_CODEC_ADDR       0x10
+/* UG082 says:
+ * #define   CR_CODEC_ADDR(a)  ((a) << 1)
+ * #define   CR_CODEC_READ     (1<<0)
+ * #define   CR_CODEC_WRITE    (0<<0)
+ */
+/* RefDesign example says: */
+#define   CR_CODEC_ADDR(a)      ((a) << 0)
+#define   CR_CODEC_READ         (1<<7)
+#define   CR_CODEC_WRITE        (0<<7)
+
+#define CR_REG_CODEC_DATAREAD   0x14
+#define   CR_CODEC_DATAREAD(v)  ((v) & 0xFFFF)
+
+#define CR_REG_CODEC_DATAWRITE  0x18
+#define   CR_CODEC_DATAWRITE(v) ((v) & 0xFFFF)
+
+#define CR_FIFO_SIZE            32
+
+struct snd_ml403_ac97cr {
+       /* lock for access to (controller) registers */
+       spinlock_t reg_lock;
+       /* mutex for the whole sequence of accesses to (controller) registers
+        * which affect codec registers
+        */
+       struct mutex cdc_mutex;
+
+       int irq; /* for playback */
+       int enable_irq; /* for playback */
+
+       int capture_irq;
+       int enable_capture_irq;
+
+       struct resource *res_port;
+       void *port;
+
+       struct snd_ac97 *ac97;
+       int ac97_fake;
+#ifdef CODEC_STAT
+       int ac97_read;
+       int ac97_write;
+#endif
+
+       struct platform_device *pfdev;
+       struct snd_card *card;
+       struct snd_pcm *pcm;
+       struct snd_pcm_substream *playback_substream;
+       struct snd_pcm_substream *capture_substream;
+
+       struct snd_pcm_indirect2 ind_rec; /* for playback */
+       struct snd_pcm_indirect2 capture_ind2_rec;
+};
+
+static struct snd_pcm_hardware snd_ml403_ac97cr_playback = {
+       .info =             (SNDRV_PCM_INFO_MMAP |
+                            SNDRV_PCM_INFO_INTERLEAVED |
+                            SNDRV_PCM_INFO_MMAP_VALID),
+       .formats =          SNDRV_PCM_FMTBIT_S16_BE,
+       .rates =            (SNDRV_PCM_RATE_CONTINUOUS |
+                            SNDRV_PCM_RATE_8000_48000),
+       .rate_min =         4000,
+       .rate_max =         48000,
+       .channels_min =     2,
+       .channels_max =     2,
+       .buffer_bytes_max = (128*1024),
+       .period_bytes_min = CR_FIFO_SIZE/2,
+       .period_bytes_max = (64*1024),
+       .periods_min =      2,
+       .periods_max =      (128*1024)/(CR_FIFO_SIZE/2),
+       .fifo_size =        0,
+};
+
+static struct snd_pcm_hardware snd_ml403_ac97cr_capture = {
+       .info =             (SNDRV_PCM_INFO_MMAP |
+                            SNDRV_PCM_INFO_INTERLEAVED |
+                            SNDRV_PCM_INFO_MMAP_VALID),
+       .formats =          SNDRV_PCM_FMTBIT_S16_BE,
+       .rates =            (SNDRV_PCM_RATE_CONTINUOUS |
+                            SNDRV_PCM_RATE_8000_48000),
+       .rate_min =         4000,
+       .rate_max =         48000,
+       .channels_min =     2,
+       .channels_max =     2,
+       .buffer_bytes_max = (128*1024),
+       .period_bytes_min = CR_FIFO_SIZE/2,
+       .period_bytes_max = (64*1024),
+       .periods_min =      2,
+       .periods_max =      (128*1024)/(CR_FIFO_SIZE/2),
+       .fifo_size =        0,
+};
+
+static size_t
+snd_ml403_ac97cr_playback_ind2_zero(struct snd_pcm_substream *substream,
+                                   struct snd_pcm_indirect2 *rec)
+{
+       struct snd_ml403_ac97cr *ml403_ac97cr;
+       int copied_words = 0;
+       u32 full = 0;
+
+       ml403_ac97cr = snd_pcm_substream_chip(substream);
+
+       spin_lock(&ml403_ac97cr->reg_lock);
+       while ((full = (in_be32(CR_REG(ml403_ac97cr, STATUS)) &
+                       CR_PLAYFULL)) != CR_PLAYFULL) {
+               out_be32(CR_REG(ml403_ac97cr, PLAYFIFO), 0);
+               copied_words++;
+       }
+       rec->hw_ready = 0;
+       spin_unlock(&ml403_ac97cr->reg_lock);
+
+       return (size_t) (copied_words * 2);
+}
+
+static size_t
+snd_ml403_ac97cr_playback_ind2_copy(struct snd_pcm_substream *substream,
+                                   struct snd_pcm_indirect2 *rec,
+                                   size_t bytes)
+{
+       struct snd_ml403_ac97cr *ml403_ac97cr;
+       u16 *src;
+       int copied_words = 0;
+       u32 full = 0;
+
+       ml403_ac97cr = snd_pcm_substream_chip(substream);
+       src = (u16 *)(substream->runtime->dma_area + rec->sw_data);
+
+       spin_lock(&ml403_ac97cr->reg_lock);
+       while (((full = (in_be32(CR_REG(ml403_ac97cr, STATUS)) &
+                        CR_PLAYFULL)) != CR_PLAYFULL) && (bytes > 1)) {
+               out_be32(CR_REG(ml403_ac97cr, PLAYFIFO),
+                        CR_PLAYDATA(src[copied_words]));
+               copied_words++;
+               bytes = bytes - 2;
+       }
+       if (full != CR_PLAYFULL)
+               rec->hw_ready = 1;
+       else
+               rec->hw_ready = 0;
+       spin_unlock(&ml403_ac97cr->reg_lock);
+
+       return (size_t) (copied_words * 2);
+}
+
+static size_t
+snd_ml403_ac97cr_capture_ind2_null(struct snd_pcm_substream *substream,
+                                  struct snd_pcm_indirect2 *rec)
+{
+       struct snd_ml403_ac97cr *ml403_ac97cr;
+       int copied_words = 0;
+       u32 empty = 0;
+
+       ml403_ac97cr = snd_pcm_substream_chip(substream);
+
+       spin_lock(&ml403_ac97cr->reg_lock);
+       while ((empty = (in_be32(CR_REG(ml403_ac97cr, STATUS)) &
+                        CR_RECEMPTY)) != CR_RECEMPTY) {
+               volatile u32 trash;
+
+               trash = CR_RECDATA(in_be32(CR_REG(ml403_ac97cr, RECFIFO)));
+               /* Hmmmm, really necessary? Don't want call to in_be32()
+                * to be optimised away!
+                */
+               trash++;
+               copied_words++;
+       }
+       rec->hw_ready = 0;
+       spin_unlock(&ml403_ac97cr->reg_lock);
+
+       return (size_t) (copied_words * 2);
+}
+
+static size_t
+snd_ml403_ac97cr_capture_ind2_copy(struct snd_pcm_substream *substream,
+                                  struct snd_pcm_indirect2 *rec, size_t bytes)
+{
+       struct snd_ml403_ac97cr *ml403_ac97cr;
+       u16 *dst;
+       int copied_words = 0;
+       u32 empty = 0;
+
+       ml403_ac97cr = snd_pcm_substream_chip(substream);
+       dst = (u16 *)(substream->runtime->dma_area + rec->sw_data);
+
+       spin_lock(&ml403_ac97cr->reg_lock);
+       while (((empty = (in_be32(CR_REG(ml403_ac97cr, STATUS)) &
+                         CR_RECEMPTY)) != CR_RECEMPTY) && (bytes > 1)) {
+               dst[copied_words] = CR_RECDATA(in_be32(CR_REG(ml403_ac97cr,
+                                                             RECFIFO)));
+               copied_words++;
+               bytes = bytes - 2;
+       }
+       if (empty != CR_RECEMPTY)
+               rec->hw_ready = 1;
+       else
+               rec->hw_ready = 0;
+       spin_unlock(&ml403_ac97cr->reg_lock);
+
+       return (size_t) (copied_words * 2);
+}
+
+static snd_pcm_uframes_t
+snd_ml403_ac97cr_pcm_pointer(struct snd_pcm_substream *substream)
+{
+       struct snd_ml403_ac97cr *ml403_ac97cr;
+       struct snd_pcm_indirect2 *ind2_rec = NULL;
+
+       ml403_ac97cr = snd_pcm_substream_chip(substream);
+
+       if (substream == ml403_ac97cr->playback_substream)
+               ind2_rec = &ml403_ac97cr->ind_rec;
+       if (substream == ml403_ac97cr->capture_substream)
+               ind2_rec = &ml403_ac97cr->capture_ind2_rec;
+
+       if (ind2_rec != NULL)
+               return snd_pcm_indirect2_pointer(substream, ind2_rec);
+       return (snd_pcm_uframes_t) 0;
+}
+
+static int
+snd_ml403_ac97cr_pcm_playback_trigger(struct snd_pcm_substream *substream,
+                                     int cmd)
+{
+       struct snd_ml403_ac97cr *ml403_ac97cr;
+       int err = 0;
+
+       ml403_ac97cr = snd_pcm_substream_chip(substream);
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+               PDEBUG(WORK_INFO, "trigger(playback): START\n");
+               ml403_ac97cr->ind_rec.hw_ready = 1;
+
+               /* clear play FIFO */
+               out_be32(CR_REG(ml403_ac97cr, RESETFIFO), CR_PLAYRESET);
+
+               /* enable play irq */
+               ml403_ac97cr->enable_irq = 1;
+               enable_irq(ml403_ac97cr->irq);
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+               PDEBUG(WORK_INFO, "trigger(playback): STOP\n");
+               ml403_ac97cr->ind_rec.hw_ready = 0;
+#ifdef SND_PCM_INDIRECT2_STAT
+               snd_pcm_indirect2_stat(substream, &ml403_ac97cr->ind_rec);
+#endif
+               /* disable play irq */
+               disable_irq_nosync(ml403_ac97cr->irq);
+               ml403_ac97cr->enable_irq = 0;
+               break;
+       default:
+               err = -EINVAL;
+               break;
+       }
+       PDEBUG(WORK_INFO, "trigger(playback): (done)\n");
+       return err;
+}
+
+static int
+snd_ml403_ac97cr_pcm_capture_trigger(struct snd_pcm_substream *substream,
+                                     int cmd)
+{
+       struct snd_ml403_ac97cr *ml403_ac97cr;
+       int err = 0;
+
+       ml403_ac97cr = snd_pcm_substream_chip(substream);
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+               PDEBUG(WORK_INFO, "trigger(capture): START\n");
+               ml403_ac97cr->capture_ind2_rec.hw_ready = 0;
+
+               /* clear record FIFO */
+               out_be32(CR_REG(ml403_ac97cr, RESETFIFO), CR_RECRESET);
+
+               /* enable record irq */
+               ml403_ac97cr->enable_capture_irq = 1;
+               enable_irq(ml403_ac97cr->capture_irq);
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+               PDEBUG(WORK_INFO, "trigger(capture): STOP\n");
+               ml403_ac97cr->capture_ind2_rec.hw_ready = 0;
+#ifdef SND_PCM_INDIRECT2_STAT
+               snd_pcm_indirect2_stat(substream,
+                                      &ml403_ac97cr->capture_ind2_rec);
+#endif
+               /* disable capture irq */
+               disable_irq_nosync(ml403_ac97cr->capture_irq);
+               ml403_ac97cr->enable_capture_irq = 0;
+               break;
+       default:
+               err = -EINVAL;
+               break;
+       }
+       PDEBUG(WORK_INFO, "trigger(capture): (done)\n");
+       return err;
+}
+
+static int
+snd_ml403_ac97cr_pcm_playback_prepare(struct snd_pcm_substream *substream)
+{
+       struct snd_ml403_ac97cr *ml403_ac97cr;
+       struct snd_pcm_runtime *runtime;
+
+       ml403_ac97cr = snd_pcm_substream_chip(substream);
+       runtime = substream->runtime;
+
+       PDEBUG(WORK_INFO,
+              "prepare(): period_bytes=%d, minperiod_bytes=%d\n",
+              snd_pcm_lib_period_bytes(substream), CR_FIFO_SIZE / 2);
+
+       /* set sampling rate */
+       snd_ac97_set_rate(ml403_ac97cr->ac97, AC97_PCM_FRONT_DAC_RATE,
+                         runtime->rate);
+       PDEBUG(WORK_INFO, "prepare(): rate=%d\n", runtime->rate);
+
+       /* init struct for intermediate buffer */
+       memset(&ml403_ac97cr->ind_rec, 0,
+              sizeof(struct snd_pcm_indirect2));
+       ml403_ac97cr->ind_rec.hw_buffer_size = CR_FIFO_SIZE;
+       ml403_ac97cr->ind_rec.sw_buffer_size =
+               snd_pcm_lib_buffer_bytes(substream);
+       ml403_ac97cr->ind_rec.min_periods = -1;
+       ml403_ac97cr->ind_rec.min_multiple =
+               snd_pcm_lib_period_bytes(substream) / (CR_FIFO_SIZE / 2);
+       PDEBUG(WORK_INFO, "prepare(): hw_buffer_size=%d, "
+              "sw_buffer_size=%d, min_multiple=%d\n",
+              CR_FIFO_SIZE, ml403_ac97cr->ind_rec.sw_buffer_size,
+              ml403_ac97cr->ind_rec.min_multiple);
+       return 0;
+}
+
+static int
+snd_ml403_ac97cr_pcm_capture_prepare(struct snd_pcm_substream *substream)
+{
+       struct snd_ml403_ac97cr *ml403_ac97cr;
+       struct snd_pcm_runtime *runtime;
+
+       ml403_ac97cr = snd_pcm_substream_chip(substream);
+       runtime = substream->runtime;
+
+       PDEBUG(WORK_INFO,
+              "prepare(capture): period_bytes=%d, minperiod_bytes=%d\n",
+              snd_pcm_lib_period_bytes(substream), CR_FIFO_SIZE / 2);
+
+       /* set sampling rate */
+       snd_ac97_set_rate(ml403_ac97cr->ac97, AC97_PCM_LR_ADC_RATE,
+                         runtime->rate);
+       PDEBUG(WORK_INFO, "prepare(capture): rate=%d\n", runtime->rate);
+
+       /* init struct for intermediate buffer */
+       memset(&ml403_ac97cr->capture_ind2_rec, 0,
+              sizeof(struct snd_pcm_indirect2));
+       ml403_ac97cr->capture_ind2_rec.hw_buffer_size = CR_FIFO_SIZE;
+       ml403_ac97cr->capture_ind2_rec.sw_buffer_size =
+               snd_pcm_lib_buffer_bytes(substream);
+       ml403_ac97cr->capture_ind2_rec.min_multiple =
+               snd_pcm_lib_period_bytes(substream) / (CR_FIFO_SIZE / 2);
+       PDEBUG(WORK_INFO, "prepare(capture): hw_buffer_size=%d, "
+              "sw_buffer_size=%d, min_multiple=%d\n", CR_FIFO_SIZE,
+              ml403_ac97cr->capture_ind2_rec.sw_buffer_size,
+              ml403_ac97cr->capture_ind2_rec.min_multiple);
+       return 0;
+}
+
+static int snd_ml403_ac97cr_hw_free(struct snd_pcm_substream *substream)
+{
+       PDEBUG(WORK_INFO, "hw_free()\n");
+       return snd_pcm_lib_free_pages(substream);
+}
+
+static int
+snd_ml403_ac97cr_hw_params(struct snd_pcm_substream *substream,
+                          struct snd_pcm_hw_params *hw_params)
+{
+       PDEBUG(WORK_INFO, "hw_params(): desired buffer bytes=%d, desired "
+              "period bytes=%d\n",
+              params_buffer_bytes(hw_params), params_period_bytes(hw_params));
+       return snd_pcm_lib_malloc_pages(substream,
+                                       params_buffer_bytes(hw_params));
+}
+
+static int snd_ml403_ac97cr_playback_open(struct snd_pcm_substream *substream)
+{
+       struct snd_ml403_ac97cr *ml403_ac97cr;
+       struct snd_pcm_runtime *runtime;
+
+       ml403_ac97cr = snd_pcm_substream_chip(substream);
+       runtime = substream->runtime;
+
+       PDEBUG(WORK_INFO, "open(playback)\n");
+       ml403_ac97cr->playback_substream = substream;
+       runtime->hw = snd_ml403_ac97cr_playback;
+
+       snd_pcm_hw_constraint_step(runtime, 0,
+                                  SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
+                                  CR_FIFO_SIZE / 2);
+       return 0;
+}
+
+static int snd_ml403_ac97cr_capture_open(struct snd_pcm_substream *substream)
+{
+       struct snd_ml403_ac97cr *ml403_ac97cr;
+       struct snd_pcm_runtime *runtime;
+
+       ml403_ac97cr = snd_pcm_substream_chip(substream);
+       runtime = substream->runtime;
+
+       PDEBUG(WORK_INFO, "open(capture)\n");
+       ml403_ac97cr->capture_substream = substream;
+       runtime->hw = snd_ml403_ac97cr_capture;
+
+       snd_pcm_hw_constraint_step(runtime, 0,
+                                  SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
+                                  CR_FIFO_SIZE / 2);
+       return 0;
+}
+
+static int snd_ml403_ac97cr_playback_close(struct snd_pcm_substream *substream)
+{
+       struct snd_ml403_ac97cr *ml403_ac97cr;
+
+       ml403_ac97cr = snd_pcm_substream_chip(substream);
+
+       PDEBUG(WORK_INFO, "close(playback)\n");
+       ml403_ac97cr->playback_substream = NULL;
+       return 0;
+}
+
+static int snd_ml403_ac97cr_capture_close(struct snd_pcm_substream *substream)
+{
+       struct snd_ml403_ac97cr *ml403_ac97cr;
+
+       ml403_ac97cr = snd_pcm_substream_chip(substream);
+
+       PDEBUG(WORK_INFO, "close(capture)\n");
+       ml403_ac97cr->capture_substream = NULL;
+       return 0;
+}
+
+static struct snd_pcm_ops snd_ml403_ac97cr_playback_ops = {
+       .open = snd_ml403_ac97cr_playback_open,
+       .close = snd_ml403_ac97cr_playback_close,
+       .ioctl = snd_pcm_lib_ioctl,
+       .hw_params = snd_ml403_ac97cr_hw_params,
+       .hw_free = snd_ml403_ac97cr_hw_free,
+       .prepare = snd_ml403_ac97cr_pcm_playback_prepare,
+       .trigger = snd_ml403_ac97cr_pcm_playback_trigger,
+       .pointer = snd_ml403_ac97cr_pcm_pointer,
+};
+
+static struct snd_pcm_ops snd_ml403_ac97cr_capture_ops = {
+       .open = snd_ml403_ac97cr_capture_open,
+       .close = snd_ml403_ac97cr_capture_close,
+       .ioctl = snd_pcm_lib_ioctl,
+       .hw_params = snd_ml403_ac97cr_hw_params,
+       .hw_free = snd_ml403_ac97cr_hw_free,
+       .prepare = snd_ml403_ac97cr_pcm_capture_prepare,
+       .trigger = snd_ml403_ac97cr_pcm_capture_trigger,
+       .pointer = snd_ml403_ac97cr_pcm_pointer,
+};
+
+static irqreturn_t snd_ml403_ac97cr_irq(int irq, void *dev_id)
+{
+       struct snd_ml403_ac97cr *ml403_ac97cr;
+       struct platform_device *pfdev;
+       int cmp_irq;
+
+       ml403_ac97cr = (struct snd_ml403_ac97cr *)dev_id;
+       if (ml403_ac97cr == NULL)
+               return IRQ_NONE;
+
+       pfdev = ml403_ac97cr->pfdev;
+
+       /* playback interrupt */
+       cmp_irq = platform_get_irq(pfdev, 0);
+       if (irq == cmp_irq) {
+               if (ml403_ac97cr->enable_irq)
+                       snd_pcm_indirect2_playback_interrupt(
+                               ml403_ac97cr->playback_substream,
+                               &ml403_ac97cr->ind_rec,
+                               snd_ml403_ac97cr_playback_ind2_copy,
+                               snd_ml403_ac97cr_playback_ind2_zero);
+               else
+                       goto __disable_irq;
+       } else {
+               /* record interrupt */
+               cmp_irq = platform_get_irq(pfdev, 1);
+               if (irq == cmp_irq) {
+                       if (ml403_ac97cr->enable_capture_irq)
+                               snd_pcm_indirect2_capture_interrupt(
+                                       ml403_ac97cr->capture_substream,
+                                       &ml403_ac97cr->capture_ind2_rec,
+                                       snd_ml403_ac97cr_capture_ind2_copy,
+                                       snd_ml403_ac97cr_capture_ind2_null);
+                       else
+                               goto __disable_irq;
+               } else
+                       return IRQ_NONE;
+       }
+       return IRQ_HANDLED;
+
+__disable_irq:
+       PDEBUG(INIT_INFO, "irq(): irq %d is meant to be disabled! So, now try "
+              "to disable it _really_!\n", irq);
+       disable_irq_nosync(irq);
+       return IRQ_HANDLED;
+}
+
+static unsigned short
+snd_ml403_ac97cr_codec_read(struct snd_ac97 *ac97, unsigned short reg)
+{
+       struct snd_ml403_ac97cr *ml403_ac97cr = ac97->private_data;
+#ifdef CODEC_STAT
+       u32 stat;
+       u32 rafaccess = 0;
+#endif
+       unsigned long end_time;
+       u16 value = 0;
+
+       if (!LM4550_RF_OK(reg)) {
+               snd_printk(KERN_WARNING SND_ML403_AC97CR_DRIVER ": "
+                          "access to unknown/unused codec register 0x%x "
+                          "ignored!\n", reg);
+               return 0;
+       }
+       /* check if we can fake/answer this access from our shadow register */
+       if ((lm4550_regfile[reg / 2].flag &
+            (LM4550_REG_DONEREAD | LM4550_REG_ALLFAKE)) &&
+           !(lm4550_regfile[reg / 2].flag & LM4550_REG_NOSHADOW)) {
+               if (lm4550_regfile[reg / 2].flag & LM4550_REG_FAKEREAD) {
+                       PDEBUG(CODEC_FAKE, "codec_read(): faking read from "
+                              "reg=0x%x, val=0x%x / %d\n",
+                              reg, lm4550_regfile[reg / 2].def,
+                              lm4550_regfile[reg / 2].def);
+                       return lm4550_regfile[reg / 2].def;
+               } else if ((lm4550_regfile[reg / 2].flag &
+                           LM4550_REG_FAKEPROBE) &&
+                          ml403_ac97cr->ac97_fake) {
+                       PDEBUG(CODEC_FAKE, "codec_read(): faking read from "
+                              "reg=0x%x, val=0x%x / %d (probe)\n",
+                              reg, lm4550_regfile[reg / 2].value,
+                              lm4550_regfile[reg / 2].value);
+                       return lm4550_regfile[reg / 2].value;
+               } else {
+#ifdef CODEC_STAT
+                       PDEBUG(CODEC_FAKE, "codec_read(): read access "
+                              "answered by shadow register 0x%x (value=0x%x "
+                              "/ %d) (cw=%d cr=%d)\n",
+                              reg, lm4550_regfile[reg / 2].value,
+                              lm4550_regfile[reg / 2].value,
+                              ml403_ac97cr->ac97_write,
+                              ml403_ac97cr->ac97_read);
+#else
+                       PDEBUG(CODEC_FAKE, "codec_read(): read access "
+                              "answered by shadow register 0x%x (value=0x%x "
+                              "/ %d)\n",
+                              reg, lm4550_regfile[reg / 2].value,
+                              lm4550_regfile[reg / 2].value);
+#endif
+                       return lm4550_regfile[reg / 2].value;
+               }
+       }
+       /* if we are here, we _have_ to access the codec really, no faking */
+       if (mutex_lock_interruptible(&ml403_ac97cr->cdc_mutex) != 0)
+               return 0;
+#ifdef CODEC_STAT
+       ml403_ac97cr->ac97_read++;
+#endif
+       spin_lock(&ml403_ac97cr->reg_lock);
+       out_be32(CR_REG(ml403_ac97cr, CODEC_ADDR),
+                CR_CODEC_ADDR(reg) | CR_CODEC_READ);
+       spin_unlock(&ml403_ac97cr->reg_lock);
+       end_time = jiffies + (HZ / CODEC_TIMEOUT_AFTER_READ);
+       do {
+               spin_lock(&ml403_ac97cr->reg_lock);
+#ifdef CODEC_STAT
+               rafaccess++;
+               stat = in_be32(CR_REG(ml403_ac97cr, STATUS));
+               if ((stat & CR_RAF) == CR_RAF) {
+                       value = CR_CODEC_DATAREAD(
+                               in_be32(CR_REG(ml403_ac97cr, CODEC_DATAREAD)));
+                       PDEBUG(CODEC_SUCCESS, "codec_read(): (done) reg=0x%x, "
+                              "value=0x%x / %d (STATUS=0x%x)\n",
+                              reg, value, value, stat);
+#else
+               if ((in_be32(CR_REG(ml403_ac97cr, STATUS)) &
+                    CR_RAF) == CR_RAF) {
+                       value = CR_CODEC_DATAREAD(
+                               in_be32(CR_REG(ml403_ac97cr, CODEC_DATAREAD)));
+                       PDEBUG(CODEC_SUCCESS, "codec_read(): (done) "
+                              "reg=0x%x, value=0x%x / %d\n",
+                              reg, value, value);
+#endif
+                       lm4550_regfile[reg / 2].value = value;
+                       lm4550_regfile[reg / 2].flag |= LM4550_REG_DONEREAD;
+                       spin_unlock(&ml403_ac97cr->reg_lock);
+                       mutex_unlock(&ml403_ac97cr->cdc_mutex);
+                       return value;
+               }
+               spin_unlock(&ml403_ac97cr->reg_lock);
+               schedule_timeout_uninterruptible(1);
+       } while (time_after(end_time, jiffies));
+       /* read the DATAREAD register anyway, see comment below */
+       spin_lock(&ml403_ac97cr->reg_lock);
+       value =
+           CR_CODEC_DATAREAD(in_be32(CR_REG(ml403_ac97cr, CODEC_DATAREAD)));
+       spin_unlock(&ml403_ac97cr->reg_lock);
+#ifdef CODEC_STAT
+       snd_printk(KERN_WARNING SND_ML403_AC97CR_DRIVER ": "
+                  "timeout while codec read! "
+                  "(reg=0x%x, last STATUS=0x%x, DATAREAD=0x%x / %d, %d) "
+                  "(cw=%d, cr=%d)\n",
+                  reg, stat, value, value, rafaccess,
+                  ml403_ac97cr->ac97_write, ml403_ac97cr->ac97_read);
+#else
+       snd_printk(KERN_WARNING SND_ML403_AC97CR_DRIVER ": "
+                  "timeout while codec read! "
+                  "(reg=0x%x, DATAREAD=0x%x / %d)\n",
+                  reg, value, value);
+#endif
+       /* BUG: This is PURE speculation! But after _most_ read timeouts the
+        * value in the register is ok!
+        */
+       lm4550_regfile[reg / 2].value = value;
+       lm4550_regfile[reg / 2].flag |= LM4550_REG_DONEREAD;
+       mutex_unlock(&ml403_ac97cr->cdc_mutex);
+       return value;
+}
+
+static void
+snd_ml403_ac97cr_codec_write(struct snd_ac97 *ac97, unsigned short reg,
+                            unsigned short val)
+{
+       struct snd_ml403_ac97cr *ml403_ac97cr = ac97->private_data;
+
+#ifdef CODEC_STAT
+       u32 stat;
+       u32 rafaccess = 0;
+#endif
+#ifdef CODEC_WRITE_CHECK_RAF
+       unsigned long end_time;
+#endif
+
+       if (!LM4550_RF_OK(reg)) {
+               snd_printk(KERN_WARNING SND_ML403_AC97CR_DRIVER ": "
+                          "access to unknown/unused codec register 0x%x "
+                          "ignored!\n", reg);
+               return;
+       }
+       if (lm4550_regfile[reg / 2].flag & LM4550_REG_READONLY) {
+               snd_printk(KERN_WARNING SND_ML403_AC97CR_DRIVER ": "
+                          "write access to read only codec register 0x%x "
+                          "ignored!\n", reg);
+               return;
+       }
+       if ((val & lm4550_regfile[reg / 2].wmask) != val) {
+               snd_printk(KERN_WARNING SND_ML403_AC97CR_DRIVER ": "
+                          "write access to codec register 0x%x "
+                          "with bad value 0x%x / %d!\n",
+                          reg, val, val);
+               val = val & lm4550_regfile[reg / 2].wmask;
+       }
+       if (((lm4550_regfile[reg / 2].flag & LM4550_REG_FAKEPROBE) &&
+            ml403_ac97cr->ac97_fake) &&
+           !(lm4550_regfile[reg / 2].flag & LM4550_REG_NOSHADOW)) {
+               PDEBUG(CODEC_FAKE, "codec_write(): faking write to reg=0x%x, "
+                      "val=0x%x / %d\n", reg, val, val);
+               lm4550_regfile[reg / 2].value = (val &
+                                               lm4550_regfile[reg / 2].wmask);
+               return;
+       }
+       if (mutex_lock_interruptible(&ml403_ac97cr->cdc_mutex) != 0)
+               return;
+#ifdef CODEC_STAT
+       ml403_ac97cr->ac97_write++;
+#endif
+       spin_lock(&ml403_ac97cr->reg_lock);
+       out_be32(CR_REG(ml403_ac97cr, CODEC_DATAWRITE),
+                CR_CODEC_DATAWRITE(val));
+       out_be32(CR_REG(ml403_ac97cr, CODEC_ADDR),
+                CR_CODEC_ADDR(reg) | CR_CODEC_WRITE);
+       spin_unlock(&ml403_ac97cr->reg_lock);
+#ifdef CODEC_WRITE_CHECK_RAF
+       /* check CR_CODEC_RAF bit to see if write access to register is done;
+        * loop until bit is set or timeout happens
+        */
+       end_time = jiffies + HZ / CODEC_TIMEOUT_AFTER_WRITE;
+       do {
+               spin_lock(&ml403_ac97cr->reg_lock);
+#ifdef CODEC_STAT
+               rafaccess++;
+               stat = in_be32(CR_REG(ml403_ac97cr, STATUS))
+               if ((stat & CR_RAF) == CR_RAF) {
+#else
+               if ((in_be32(CR_REG(ml403_ac97cr, STATUS)) &
+                    CR_RAF) == CR_RAF) {
+#endif
+                       PDEBUG(CODEC_SUCCESS, "codec_write(): (done) "
+                              "reg=0x%x, value=%d / 0x%x\n",
+                              reg, val, val);
+                       if (!(lm4550_regfile[reg / 2].flag &
+                             LM4550_REG_NOSHADOW) &&
+                           !(lm4550_regfile[reg / 2].flag &
+                             LM4550_REG_NOSAVE))
+                               lm4550_regfile[reg / 2].value = val;
+                       lm4550_regfile[reg / 2].flag |= LM4550_REG_DONEREAD;
+                       spin_unlock(&ml403_ac97cr->reg_lock);
+                       mutex_unlock(&ml403_ac97cr->cdc_mutex);
+                       return;
+               }
+               spin_unlock(&ml403_ac97cr->reg_lock);
+               schedule_timeout_uninterruptible(1);
+       } while (time_after(end_time, jiffies));
+#ifdef CODEC_STAT
+       snd_printk(KERN_WARNING SND_ML403_AC97CR_DRIVER ": "
+                  "timeout while codec write "
+                  "(reg=0x%x, val=0x%x / %d, last STATUS=0x%x, %d) "
+                  "(cw=%d, cr=%d)\n",
+                  reg, val, val, stat, rafaccess, ml403_ac97cr->ac97_write,
+                  ml403_ac97cr->ac97_read);
+#else
+       snd_printk(KERN_WARNING SND_ML403_AC97CR_DRIVER ": "
+                  "timeout while codec write (reg=0x%x, val=0x%x / %d)\n",
+                  reg, val, val);
+#endif
+#else /* CODEC_WRITE_CHECK_RAF */
+#if CODEC_WAIT_AFTER_WRITE > 0
+       /* officially, in AC97 spec there is no possibility for a AC97
+        * controller to determine, if write access is done or not - so: How
+        * is Xilinx able to provide a RAF bit for write access?
+        * => very strange, thus just don't check RAF bit (compare with
+        * Xilinx's example app in EDK 8.1i) and wait
+        */
+       schedule_timeout_uninterruptible(HZ / CODEC_WAIT_AFTER_WRITE);
+#endif
+       PDEBUG(CODEC_SUCCESS, "codec_write(): (done) "
+              "reg=0x%x, value=%d / 0x%x (no RAF check)\n",
+              reg, val, val);
+#endif
+       mutex_unlock(&ml403_ac97cr->cdc_mutex);
+       return;
+}
+
+static int __devinit
+snd_ml403_ac97cr_chip_init(struct snd_ml403_ac97cr *ml403_ac97cr)
+{
+       unsigned long end_time;
+       PDEBUG(INIT_INFO, "chip_init():\n");
+       end_time = jiffies + HZ / CODEC_TIMEOUT_ON_INIT;
+       do {
+               if (in_be32(CR_REG(ml403_ac97cr, STATUS)) & CR_CODECREADY) {
+                       /* clear both hardware FIFOs */
+                       out_be32(CR_REG(ml403_ac97cr, RESETFIFO),
+                                CR_RECRESET | CR_PLAYRESET);
+                       PDEBUG(INIT_INFO, "chip_init(): (done)\n");
+                       return 0;
+               }
+               schedule_timeout_uninterruptible(1);
+       } while (time_after(end_time, jiffies));
+       snd_printk(KERN_ERR SND_ML403_AC97CR_DRIVER ": "
+                  "timeout while waiting for codec, "
+                  "not ready!\n");
+       return -EBUSY;
+}
+
+static int snd_ml403_ac97cr_free(struct snd_ml403_ac97cr *ml403_ac97cr)
+{
+       PDEBUG(INIT_INFO, "free():\n");
+       /* irq release */
+       if (ml403_ac97cr->irq >= 0)
+               free_irq(ml403_ac97cr->irq, ml403_ac97cr);
+       if (ml403_ac97cr->capture_irq >= 0)
+               free_irq(ml403_ac97cr->capture_irq, ml403_ac97cr);
+       /* give back "port" */
+       if (ml403_ac97cr->port != NULL)
+               iounmap(ml403_ac97cr->port);
+       kfree(ml403_ac97cr);
+       PDEBUG(INIT_INFO, "free(): (done)\n");
+       return 0;
+}
+
+static int snd_ml403_ac97cr_dev_free(struct snd_device *snddev)
+{
+       struct snd_ml403_ac97cr *ml403_ac97cr = snddev->device_data;
+       PDEBUG(INIT_INFO, "dev_free():\n");
+       return snd_ml403_ac97cr_free(ml403_ac97cr);
+}
+
+static int __devinit
+snd_ml403_ac97cr_create(struct snd_card *card, struct platform_device *pfdev,
+                       struct snd_ml403_ac97cr **rml403_ac97cr)
+{
+       struct snd_ml403_ac97cr *ml403_ac97cr;
+       int err;
+       static struct snd_device_ops ops = {
+               .dev_free = snd_ml403_ac97cr_dev_free,
+       };
+       struct resource *resource;
+       int irq;
+
+       *rml403_ac97cr = NULL;
+       ml403_ac97cr = kzalloc(sizeof(*ml403_ac97cr), GFP_KERNEL);
+       if (ml403_ac97cr == NULL)
+               return -ENOMEM;
+       spin_lock_init(&ml403_ac97cr->reg_lock);
+       mutex_init(&ml403_ac97cr->cdc_mutex);
+       ml403_ac97cr->card = card;
+       ml403_ac97cr->pfdev = pfdev;
+       ml403_ac97cr->irq = -1;
+       ml403_ac97cr->enable_irq = 0;
+       ml403_ac97cr->capture_irq = -1;
+       ml403_ac97cr->enable_capture_irq = 0;
+       ml403_ac97cr->port = NULL;
+       ml403_ac97cr->res_port = NULL;
+
+       PDEBUG(INIT_INFO, "Trying to reserve resources now ...\n");
+       resource = platform_get_resource(pfdev, IORESOURCE_MEM, 0);
+       /* get "port" */
+       ml403_ac97cr->port = ioremap_nocache(resource->start,
+                                            (resource->end) -
+                                            (resource->start) + 1);
+       if (ml403_ac97cr->port == NULL) {
+               snd_printk(KERN_ERR SND_ML403_AC97CR_DRIVER ": "
+                          "unable to remap memory region (%x to %x)\n",
+                          resource->start, resource->end);
+               snd_ml403_ac97cr_free(ml403_ac97cr);
+               return -EBUSY;
+       }
+       snd_printk(KERN_INFO SND_ML403_AC97CR_DRIVER ": "
+                  "remap controller memory region to "
+                  "0x%x done\n", (unsigned int)ml403_ac97cr->port);
+       /* get irq */
+       irq = platform_get_irq(pfdev, 0);
+       if (request_irq(irq, snd_ml403_ac97cr_irq, IRQF_DISABLED,
+                       pfdev->dev.bus_id, (void *)ml403_ac97cr)) {
+               snd_printk(KERN_ERR SND_ML403_AC97CR_DRIVER ": "
+                          "unable to grab IRQ %d\n",
+                          irq);
+               snd_ml403_ac97cr_free(ml403_ac97cr);
+               return -EBUSY;
+       }
+       ml403_ac97cr->irq = irq;
+       snd_printk(KERN_INFO SND_ML403_AC97CR_DRIVER ": "
+                  "request (playback) irq %d done\n",
+                  ml403_ac97cr->irq);
+       irq = platform_get_irq(pfdev, 1);
+       if (request_irq(irq, snd_ml403_ac97cr_irq, IRQF_DISABLED,
+                       pfdev->dev.bus_id, (void *)ml403_ac97cr)) {
+               snd_printk(KERN_ERR SND_ML403_AC97CR_DRIVER ": "
+                          "unable to grab IRQ %d\n",
+                          irq);
+               snd_ml403_ac97cr_free(ml403_ac97cr);
+               return -EBUSY;
+       }
+       ml403_ac97cr->capture_irq = irq;
+       snd_printk(KERN_INFO SND_ML403_AC97CR_DRIVER ": "
+                  "request (capture) irq %d done\n",
+                  ml403_ac97cr->capture_irq);
+
+       err = snd_ml403_ac97cr_chip_init(ml403_ac97cr);
+       if (err < 0) {
+               snd_ml403_ac97cr_free(ml403_ac97cr);
+               return err;
+       }
+
+       err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, ml403_ac97cr, &ops);
+       if (err < 0) {
+               PDEBUG(INIT_FAILURE, "probe(): snd_device_new() failed!\n");
+               snd_ml403_ac97cr_free(ml403_ac97cr);
+               return err;
+       }
+
+       snd_card_set_dev(card, &pfdev->dev);
+
+       *rml403_ac97cr = ml403_ac97cr;
+       return 0;
+}
+
+static void snd_ml403_ac97cr_mixer_free(struct snd_ac97 *ac97)
+{
+       struct snd_ml403_ac97cr *ml403_ac97cr = ac97->private_data;
+       PDEBUG(INIT_INFO, "mixer_free():\n");
+       ml403_ac97cr->ac97 = NULL;
+       PDEBUG(INIT_INFO, "mixer_free(): (done)\n");
+}
+
+static int __devinit
+snd_ml403_ac97cr_mixer(struct snd_ml403_ac97cr *ml403_ac97cr)
+{
+       struct snd_ac97_bus *bus;
+       struct snd_ac97_template ac97;
+       int err;
+       static struct snd_ac97_bus_ops ops = {
+               .write = snd_ml403_ac97cr_codec_write,
+               .read = snd_ml403_ac97cr_codec_read,
+       };
+       PDEBUG(INIT_INFO, "mixer():\n");
+       err = snd_ac97_bus(ml403_ac97cr->card, 0, &ops, NULL, &bus);
+       if (err < 0)
+               return err;
+
+       memset(&ac97, 0, sizeof(ac97));
+       ml403_ac97cr->ac97_fake = 1;
+       lm4550_regfile_init();
+#ifdef CODEC_STAT
+       ml403_ac97cr->ac97_read = 0;
+       ml403_ac97cr->ac97_write = 0;
+#endif
+       ac97.private_data = ml403_ac97cr;
+       ac97.private_free = snd_ml403_ac97cr_mixer_free;
+       ac97.scaps = AC97_SCAP_AUDIO | AC97_SCAP_SKIP_MODEM |
+           AC97_SCAP_NO_SPDIF;
+       err = snd_ac97_mixer(bus, &ac97, &ml403_ac97cr->ac97);
+       ml403_ac97cr->ac97_fake = 0;
+       lm4550_regfile_write_values_after_init(ml403_ac97cr->ac97);
+       PDEBUG(INIT_INFO, "mixer(): (done) snd_ac97_mixer()=%d\n", err);
+       return err;
+}
+
+static int __devinit
+snd_ml403_ac97cr_pcm(struct snd_ml403_ac97cr *ml403_ac97cr, int device,
+                    struct snd_pcm **rpcm)
+{
+       struct snd_pcm *pcm;
+       int err;
+
+       if (rpcm)
+               *rpcm = NULL;
+       err = snd_pcm_new(ml403_ac97cr->card, "ML403AC97CR/1", device, 1, 1,
+                         &pcm);
+       if (err < 0)
+               return err;
+       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+                       &snd_ml403_ac97cr_playback_ops);
+       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
+                       &snd_ml403_ac97cr_capture_ops);
+       pcm->private_data = ml403_ac97cr;
+       pcm->info_flags = 0;
+       strcpy(pcm->name, "ML403AC97CR DAC/ADC");
+       ml403_ac97cr->pcm = pcm;
+
+       snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
+                                         snd_dma_continuous_data(GFP_KERNEL),
+                                         64 * 1024,
+                                         128 * 1024);
+       if (rpcm)
+               *rpcm = pcm;
+       return 0;
+}
+
+static int __devinit snd_ml403_ac97cr_probe(struct platform_device *pfdev)
+{
+       struct snd_card *card;
+       struct snd_ml403_ac97cr *ml403_ac97cr = NULL;
+       int err;
+       int dev = pfdev->id;
+
+       if (dev >= SNDRV_CARDS)
+               return -ENODEV;
+       if (!enable[dev])
+               return -ENOENT;
+
+       card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
+       if (card == NULL)
+               return -ENOMEM;
+       err = snd_ml403_ac97cr_create(card, pfdev, &ml403_ac97cr);
+       if (err < 0) {
+               PDEBUG(INIT_FAILURE, "probe(): create failed!\n");
+               snd_card_free(card);
+               return err;
+       }
+       PDEBUG(INIT_INFO, "probe(): create done\n");
+       card->private_data = ml403_ac97cr;
+       err = snd_ml403_ac97cr_mixer(ml403_ac97cr);
+       if (err < 0) {
+               snd_card_free(card);
+               return err;
+       }
+       PDEBUG(INIT_INFO, "probe(): mixer done\n");
+       err = snd_ml403_ac97cr_pcm(ml403_ac97cr, 0, NULL);
+       if (err < 0) {
+               snd_card_free(card);
+               return err;
+       }
+       PDEBUG(INIT_INFO, "probe(): PCM done\n");
+       strcpy(card->driver, SND_ML403_AC97CR_DRIVER);
+       strcpy(card->shortname, "ML403 AC97 Controller Reference");
+       sprintf(card->longname, "%s %s at 0x%lx, irq %i & %i, device %i",
+               card->shortname, card->driver,
+               (unsigned long)ml403_ac97cr->port, ml403_ac97cr->irq,
+               ml403_ac97cr->capture_irq, dev + 1);
+
+       snd_card_set_dev(card, &pfdev->dev);
+
+       err = snd_card_register(card);
+       if (err < 0) {
+               snd_card_free(card);
+               return err;
+       }
+       platform_set_drvdata(pfdev, card);
+       PDEBUG(INIT_INFO, "probe(): (done)\n");
+       return 0;
+}
+
+static int snd_ml403_ac97cr_remove(struct platform_device *pfdev)
+{
+       snd_card_free(platform_get_drvdata(pfdev));
+       platform_set_drvdata(pfdev, NULL);
+       return 0;
+}
+
+static struct platform_driver snd_ml403_ac97cr_driver = {
+       .probe = snd_ml403_ac97cr_probe,
+       .remove = snd_ml403_ac97cr_remove,
+       .driver = {
+               .name = SND_ML403_AC97CR_DRIVER,
+       },
+};
+
+static int __init alsa_card_ml403_ac97cr_init(void)
+{
+       return platform_driver_register(&snd_ml403_ac97cr_driver);
+}
+
+static void __exit alsa_card_ml403_ac97cr_exit(void)
+{
+       platform_driver_unregister(&snd_ml403_ac97cr_driver);
+}
+
+module_init(alsa_card_ml403_ac97cr_init)
+module_exit(alsa_card_ml403_ac97cr_exit)
index 1fc95dadde1d81d3502b03c48f7fe8f25fba47a6..5b996f3faba5844c434d693af77fee3bcd3bbba4 100644 (file)
@@ -20,7 +20,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/pnp.h>
 #include <linux/err.h>
index b57f2d5a1c9dff920e17c2ada69d009e090bbd21..5993864acbd38ee163c9de45eb205455a5ea1df2 100644 (file)
@@ -28,7 +28,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <asm/io.h>
 #include <linux/delay.h>
 #include <linux/init.h>
index 40eb026c86ed4d817349ae614573493646578662..b5e1a71bb64b59857f9a55eb9520d358cd61ed57 100644 (file)
@@ -50,7 +50,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/err.h>
index dcc90f995294dc6c960b7a5dfd5a2f64fd329fa1..87ba1ddc01151fdfb5bd8f38d80103a68964aa5a 100644 (file)
@@ -18,7 +18,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/parport.h>
@@ -461,13 +460,14 @@ static int snd_mts64_ctl_smpte_switch_put(struct snd_kcontrol* kctl,
 {
        struct mts64 *mts = snd_kcontrol_chip(kctl);
        int changed = 0;
+       int val = !!uctl->value.integer.value[0];
 
        spin_lock_irq(&mts->lock);
-       if (mts->smpte_switch == uctl->value.integer.value[0])
+       if (mts->smpte_switch == val)
                goto __out;
 
        changed = 1;
-       mts->smpte_switch = uctl->value.integer.value[0];
+       mts->smpte_switch = val;
        if (mts->smpte_switch) {
                mts64_smpte_start(mts->pardev->port,
                                  mts->time[0], mts->time[1],
@@ -541,12 +541,13 @@ static int snd_mts64_ctl_smpte_time_put(struct snd_kcontrol *kctl,
 {
        struct mts64 *mts = snd_kcontrol_chip(kctl);
        int idx = kctl->private_value;
+       unsigned int time = uctl->value.integer.value[0] % 60;
        int changed = 0;
 
        spin_lock_irq(&mts->lock);
-       if (mts->time[idx] != uctl->value.integer.value[0]) {
+       if (mts->time[idx] != time) {
                changed = 1;
-               mts->time[idx] = uctl->value.integer.value[0];
+               mts->time[idx] = time;
        }
        spin_unlock_irq(&mts->lock);
 
@@ -636,6 +637,8 @@ static int snd_mts64_ctl_smpte_fps_put(struct snd_kcontrol *kctl,
        struct mts64 *mts = snd_kcontrol_chip(kctl);
        int changed = 0;
 
+       if (uctl->value.enumerated.item[0] >= 5)
+               return -EINVAL;
        spin_lock_irq(&mts->lock);
        if (mts->fps != uctl->value.enumerated.item[0]) {
                changed = 1;
@@ -662,7 +665,7 @@ static int __devinit snd_mts64_ctl_create(struct snd_card *card,
                                          struct mts64 *mts) 
 {
        int err, i;
-       static struct snd_kcontrol_new *control[] = {
+       static struct snd_kcontrol_new *control[] __devinitdata = {
                &mts64_ctl_smpte_switch,
                &mts64_ctl_smpte_time_hours,
                &mts64_ctl_smpte_time_minutes,
@@ -1004,6 +1007,8 @@ static int __devinit snd_mts64_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, card);
 
+       snd_card_set_dev(card, &pdev->dev);
+
        /* At this point card will be usable */
        if ((err = snd_card_register(card)) < 0) {
                snd_printd("Cannot register card\n");
index a2b9ce06029526a6e733d86e0dcd37b6e2dc4189..ebe4359047cb2deb90fdc952ccae21d7ce555c38 100644 (file)
@@ -327,6 +327,7 @@ static int snd_opl3_free(struct snd_opl3 *opl3)
        snd_assert(opl3 != NULL, return -ENXIO);
        if (opl3->private_free)
                opl3->private_free(opl3);
+       snd_opl3_clear_patches(opl3);
        release_and_free_resource(opl3->res_l_port);
        release_and_free_resource(opl3->res_r_port);
        kfree(opl3);
@@ -360,7 +361,6 @@ int snd_opl3_new(struct snd_card *card,
        opl3->hardware = hardware;
        spin_lock_init(&opl3->reg_lock);
        spin_lock_init(&opl3->timer_lock);
-       mutex_init(&opl3->access_mutex);
 
        if ((err = snd_device_new(card, SNDRV_DEV_CODEC, opl3, &ops)) < 0) {
                snd_opl3_free(opl3);
@@ -496,6 +496,7 @@ int snd_opl3_hwdep_new(struct snd_opl3 * opl3,
                return err;
        }
        hw->private_data = opl3;
+       hw->exclusive = 1;
 #ifdef CONFIG_SND_OSSEMUL
        if (device == 0) {
                hw->oss_type = SNDRV_OSS_DEVICE_TYPE_DMFM;
@@ -521,8 +522,10 @@ int snd_opl3_hwdep_new(struct snd_opl3 * opl3,
        /* operators - only ioctl */
        hw->ops.open = snd_opl3_open;
        hw->ops.ioctl = snd_opl3_ioctl;
+       hw->ops.write = snd_opl3_write;
        hw->ops.release = snd_opl3_release;
 
+       opl3->hwdep = hw;
        opl3->seq_dev_num = seq_device;
 #if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE))
        if (snd_seq_device_new(card, seq_device, SNDRV_SEQ_DEV_ID_OPL3,
index 3557b6e20eb535718fa056f1020acc596d01f453..cebcb8b78acb8af1e1066f919bb5124b83b6c821 100644 (file)
@@ -289,8 +289,6 @@ static int snd_opl3_oss_map[MAX_OPL3_VOICES] = {
 void snd_opl3_note_on(void *p, int note, int vel, struct snd_midi_channel *chan)
 {
        struct snd_opl3 *opl3;
-       struct snd_seq_instr wanted;
-       struct snd_seq_kinstr *kinstr;
        int instr_4op;
 
        int voice;
@@ -306,11 +304,13 @@ void snd_opl3_note_on(void *p, int note, int vel, struct snd_midi_channel *chan)
        unsigned char voice_offset;
        unsigned short opl3_reg;
        unsigned char reg_val;
+       unsigned char prg, bank;
 
        int key = note;
        unsigned char fnum, blocknum;
        int i;
 
+       struct fm_patch *patch;
        struct fm_instrument *fm;
        unsigned long flags;
 
@@ -320,19 +320,17 @@ void snd_opl3_note_on(void *p, int note, int vel, struct snd_midi_channel *chan)
        snd_printk("Note on, ch %i, inst %i, note %i, vel %i\n",
                   chan->number, chan->midi_program, note, vel);
 #endif
-       wanted.cluster = 0;
-       wanted.std = SNDRV_SEQ_INSTR_TYPE2_OPL2_3;
 
        /* in SYNTH mode, application takes care of voices */
        /* in SEQ mode, drum voice numbers are notes on drum channel */
        if (opl3->synth_mode == SNDRV_OPL3_MODE_SEQ) {
                if (chan->drum_channel) {
                        /* percussion instruments are located in bank 128 */
-                       wanted.bank = 128;
-                       wanted.prg = note;
+                       bank = 128;
+                       prg = note;
                } else {
-                       wanted.bank = chan->gm_bank_select;
-                       wanted.prg = chan->midi_program;
+                       bank = chan->gm_bank_select;
+                       prg = chan->midi_program;
                }
        } else {
                /* Prepare for OSS mode */
@@ -340,8 +338,8 @@ void snd_opl3_note_on(void *p, int note, int vel, struct snd_midi_channel *chan)
                        return;
 
                /* OSS instruments are located in bank 127 */
-               wanted.bank = 127;
-               wanted.prg = chan->midi_program;
+               bank = 127;
+               prg = chan->midi_program;
        }
 
        spin_lock_irqsave(&opl3->voice_lock, flags);
@@ -353,15 +351,14 @@ void snd_opl3_note_on(void *p, int note, int vel, struct snd_midi_channel *chan)
        }
 
  __extra_prg:
-       kinstr = snd_seq_instr_find(opl3->ilist, &wanted, 1, 0);
-       if (kinstr == NULL) {
+       patch = snd_opl3_find_patch(opl3, prg, bank, 0);
+       if (!patch) {
                spin_unlock_irqrestore(&opl3->voice_lock, flags);
                return;
        }
 
-       fm = KINSTR_DATA(kinstr);
-
-       switch (fm->type) {
+       fm = &patch->inst;
+       switch (patch->type) {
        case FM_PATCH_OPL2:
                instr_4op = 0;
                break;
@@ -371,14 +368,12 @@ void snd_opl3_note_on(void *p, int note, int vel, struct snd_midi_channel *chan)
                        break;
                }
        default:
-               snd_seq_instr_free_use(opl3->ilist, kinstr);
                spin_unlock_irqrestore(&opl3->voice_lock, flags);
                return;
        }
-
 #ifdef DEBUG_MIDI
        snd_printk("  --> OPL%i instrument: %s\n",
-                  instr_4op ? 3 : 2, kinstr->name);
+                  instr_4op ? 3 : 2, patch->name);
 #endif
        /* in SYNTH mode, application takes care of voices */
        /* in SEQ mode, allocate voice on free OPL3 channel */
@@ -569,8 +564,6 @@ void snd_opl3_note_on(void *p, int note, int vel, struct snd_midi_channel *chan)
        /* get extra pgm, but avoid possible loops */
        extra_prg = (extra_prg) ? 0 : fm->modes;
 
-       snd_seq_instr_free_use(opl3->ilist, kinstr);
-
        /* do the bookkeeping */
        vp->time = opl3->use_time++;
        vp->note = key;
@@ -601,12 +594,12 @@ void snd_opl3_note_on(void *p, int note, int vel, struct snd_midi_channel *chan)
        /* allocate extra program if specified in patch library */
        if (extra_prg) {
                if (extra_prg > 128) {
-                       wanted.bank = 128;
+                       bank = 128;
                        /* percussions start at 35 */
-                       wanted.prg = extra_prg - 128 + 35 - 1;
+                       prg = extra_prg - 128 + 35 - 1;
                } else {
-                       wanted.bank = 0;
-                       wanted.prg = extra_prg - 1;
+                       bank = 0;
+                       prg = extra_prg - 1;
                }
 #ifdef DEBUG_MIDI
                snd_printk(" *** allocating extra program\n");
index 5fd3a4c956261d562cb2c55ce1849ed32108c533..239347f26154ba381907874a08a3d6bd2a2da881 100644 (file)
@@ -195,17 +195,6 @@ static int snd_opl3_close_seq_oss(struct snd_seq_oss_arg *arg)
 
 /* load patch */
 
-/* offsets for SBI params */
-#define AM_VIB         0
-#define KSL_LEVEL      2
-#define ATTACK_DECAY   4
-#define SUSTAIN_RELEASE        6
-#define WAVE_SELECT    8
-
-/* offset for SBI instrument */
-#define CONNECTION     10
-#define OFFSET_4OP     11
-
 /* from sound_config.h */
 #define SBFM_MAXINSTR  256
 
@@ -213,112 +202,42 @@ static int snd_opl3_load_patch_seq_oss(struct snd_seq_oss_arg *arg, int format,
                                       const char __user *buf, int offs, int count)
 {
        struct snd_opl3 *opl3;
-       int err = -EINVAL;
+       struct sbi_instrument sbi;
+       char name[32];
+       int err, type;
 
        snd_assert(arg != NULL, return -ENXIO);
        opl3 = arg->private_data;
 
-       if ((format == FM_PATCH) || (format == OPL3_PATCH)) {
-               struct sbi_instrument sbi;
+       if (format == FM_PATCH)
+               type = FM_PATCH_OPL2;
+       else if (format == OPL3_PATCH)
+               type = FM_PATCH_OPL3;
+       else
+               return -EINVAL;
 
-               size_t size;
-               struct snd_seq_instr_header *put;
-               struct snd_seq_instr_data *data;
-               struct fm_xinstrument *xinstr;
+       if (count < (int)sizeof(sbi)) {
+               snd_printk("FM Error: Patch record too short\n");
+               return -EINVAL;
+       }
+       if (copy_from_user(&sbi, buf, sizeof(sbi)))
+               return -EFAULT;
 
-               struct snd_seq_event ev;
-               int i;
+       if (sbi.channel < 0 || sbi.channel >= SBFM_MAXINSTR) {
+               snd_printk("FM Error: Invalid instrument number %d\n",
+                          sbi.channel);
+               return -EINVAL;
+       }
 
-               mm_segment_t fs;
+       memset(name, 0, sizeof(name));
+       sprintf(name, "Chan%d", sbi.channel);
 
-               if (count < (int)sizeof(sbi)) {
-                       snd_printk("FM Error: Patch record too short\n");
-                       return -EINVAL;
-               }
-               if (copy_from_user(&sbi, buf, sizeof(sbi)))
-                       return -EFAULT;
+       err = snd_opl3_load_patch(opl3, sbi.channel, 127, type, name, NULL,
+                                 sbi.operators);
+       if (err < 0)
+               return err;
 
-               if (sbi.channel < 0 || sbi.channel >= SBFM_MAXINSTR) {
-                       snd_printk("FM Error: Invalid instrument number %d\n", sbi.channel);
-                       return -EINVAL;
-               }
-
-               size = sizeof(*put) + sizeof(struct fm_xinstrument);
-               put = kzalloc(size, GFP_KERNEL);
-               if (put == NULL)
-                       return -ENOMEM;
-               /* build header */
-               data = &put->data;
-               data->type = SNDRV_SEQ_INSTR_ATYPE_DATA;
-               strcpy(data->data.format, SNDRV_SEQ_INSTR_ID_OPL2_3);
-               /* build data section */
-               xinstr = (struct fm_xinstrument *)(data + 1);
-               xinstr->stype = FM_STRU_INSTR;
-        
-               for (i = 0; i < 2; i++) {
-                       xinstr->op[i].am_vib = sbi.operators[AM_VIB + i];
-                       xinstr->op[i].ksl_level = sbi.operators[KSL_LEVEL + i];
-                       xinstr->op[i].attack_decay = sbi.operators[ATTACK_DECAY + i];
-                       xinstr->op[i].sustain_release = sbi.operators[SUSTAIN_RELEASE + i];
-                       xinstr->op[i].wave_select = sbi.operators[WAVE_SELECT + i];
-               }
-               xinstr->feedback_connection[0] = sbi.operators[CONNECTION];
-
-               if (format == OPL3_PATCH) {
-                       xinstr->type = FM_PATCH_OPL3;
-                       for (i = 0; i < 2; i++) {
-                               xinstr->op[i+2].am_vib = sbi.operators[OFFSET_4OP + AM_VIB + i];
-                               xinstr->op[i+2].ksl_level = sbi.operators[OFFSET_4OP + KSL_LEVEL + i];
-                               xinstr->op[i+2].attack_decay = sbi.operators[OFFSET_4OP + ATTACK_DECAY + i];
-                               xinstr->op[i+2].sustain_release = sbi.operators[OFFSET_4OP + SUSTAIN_RELEASE + i];
-                               xinstr->op[i+2].wave_select = sbi.operators[OFFSET_4OP + WAVE_SELECT + i];
-                       }
-                       xinstr->feedback_connection[1] = sbi.operators[OFFSET_4OP + CONNECTION];
-               } else {
-                       xinstr->type = FM_PATCH_OPL2;
-               }
-
-               put->id.instr.std = SNDRV_SEQ_INSTR_TYPE2_OPL2_3;
-               put->id.instr.bank = 127;
-               put->id.instr.prg = sbi.channel;
-               put->cmd = SNDRV_SEQ_INSTR_PUT_CMD_CREATE;
-
-               memset (&ev, 0, sizeof(ev));
-               ev.source.client = SNDRV_SEQ_CLIENT_OSS;
-               ev.dest = arg->addr; 
-
-               ev.flags = SNDRV_SEQ_EVENT_LENGTH_VARUSR;
-               ev.queue = SNDRV_SEQ_QUEUE_DIRECT;
-
-               fs = snd_enter_user();
-       __again:
-               ev.type = SNDRV_SEQ_EVENT_INSTR_PUT;
-               ev.data.ext.len = size;
-               ev.data.ext.ptr = put;
-
-               err = snd_seq_instr_event(&opl3->fm_ops, opl3->ilist, &ev,
-                                   opl3->seq_client, 0, 0);
-               if (err == -EBUSY) {
-                       struct snd_seq_instr_header remove;
-
-                       memset (&remove, 0, sizeof(remove));
-                       remove.cmd = SNDRV_SEQ_INSTR_FREE_CMD_SINGLE;
-                       remove.id.instr = put->id.instr;
-
-                       /* remove instrument */
-                       ev.type = SNDRV_SEQ_EVENT_INSTR_FREE;
-                       ev.data.ext.len = sizeof(remove);
-                       ev.data.ext.ptr = &remove;
-
-                       snd_seq_instr_event(&opl3->fm_ops, opl3->ilist, &ev,
-                                           opl3->seq_client, 0, 0);
-                       goto __again;
-               }
-               snd_leave_user(fs);
-
-               kfree(put);
-       }
-       return err;
+       return sizeof(sbi);
 }
 
 /* ioctl */
index 96762c9d485578799c8a8fb6dbce6bad48f17953..2d33f53d36b8227a0ed520a7ec236f02b2df944c 100644 (file)
@@ -51,14 +51,15 @@ void snd_opl3_synth_use_dec(struct snd_opl3 * opl3)
 int snd_opl3_synth_setup(struct snd_opl3 * opl3)
 {
        int idx;
+       struct snd_hwdep *hwdep = opl3->hwdep;
 
-       mutex_lock(&opl3->access_mutex);
-       if (opl3->used) {
-               mutex_unlock(&opl3->access_mutex);
+       mutex_lock(&hwdep->open_mutex);
+       if (hwdep->used) {
+               mutex_unlock(&hwdep->open_mutex);
                return -EBUSY;
        }
-       opl3->used++;
-       mutex_unlock(&opl3->access_mutex);
+       hwdep->used++;
+       mutex_unlock(&hwdep->open_mutex);
 
        snd_opl3_reset(opl3);
 
@@ -81,6 +82,7 @@ int snd_opl3_synth_setup(struct snd_opl3 * opl3)
 void snd_opl3_synth_cleanup(struct snd_opl3 * opl3)
 {
        unsigned long flags;
+       struct snd_hwdep *hwdep;
 
        /* Stop system timer */
        spin_lock_irqsave(&opl3->sys_timer_lock, flags);
@@ -91,9 +93,11 @@ void snd_opl3_synth_cleanup(struct snd_opl3 * opl3)
        spin_unlock_irqrestore(&opl3->sys_timer_lock, flags);
 
        snd_opl3_reset(opl3);
-       mutex_lock(&opl3->access_mutex);
-       opl3->used--;
-       mutex_unlock(&opl3->access_mutex);
+       hwdep = opl3->hwdep;
+       mutex_lock(&hwdep->open_mutex);
+       hwdep->used--;
+       mutex_unlock(&hwdep->open_mutex);
+       wake_up(&hwdep->open_wait);
 }
 
 static int snd_opl3_synth_use(void *private_data, struct snd_seq_port_subscribe * info)
@@ -152,15 +156,7 @@ static int snd_opl3_synth_event_input(struct snd_seq_event * ev, int direct,
 {
        struct snd_opl3 *opl3 = private_data;
 
-       if (ev->type >= SNDRV_SEQ_EVENT_INSTR_BEGIN &&
-           ev->type <= SNDRV_SEQ_EVENT_INSTR_CHANGE) {
-               if (direct) {
-                       snd_seq_instr_event(&opl3->fm_ops, opl3->ilist, ev,
-                                           opl3->seq_client, atomic, hop);
-               }
-       } else {
-               snd_midi_process_event(&opl3_ops, ev, opl3->chset);
-       }
+       snd_midi_process_event(&opl3_ops, ev, opl3->chset);
        return 0;
 }
 
@@ -249,16 +245,6 @@ static int snd_opl3_seq_new_device(struct snd_seq_device *dev)
                return err;
        }
 
-       /* initialize instrument list */
-       opl3->ilist = snd_seq_instr_list_new();
-       if (opl3->ilist == NULL) {
-               snd_seq_delete_kernel_client(client);
-               opl3->seq_client = -1;
-               return -ENOMEM;
-       }
-       opl3->ilist->flags = SNDRV_SEQ_INSTR_FLG_DIRECT;
-       snd_seq_fm_init(&opl3->fm_ops, NULL);
-
        /* setup system timer */
        init_timer(&opl3->tlist);
        opl3->tlist.function = snd_opl3_timer_func;
@@ -287,8 +273,6 @@ static int snd_opl3_seq_delete_device(struct snd_seq_device *dev)
                snd_seq_delete_kernel_client(opl3->seq_client);
                opl3->seq_client = -1;
        }
-       if (opl3->ilist)
-               snd_seq_instr_list_free(&opl3->ilist);
        return 0;
 }
 
index a4b3543a7118121585c808296f1a5dcbda3635e8..a7bf7a4b1f85877a2459ab3bd02f2e6b8d05cd34 100644 (file)
@@ -76,16 +76,6 @@ static int snd_opl3_set_connection(struct snd_opl3 * opl3, int connection);
  */
 int snd_opl3_open(struct snd_hwdep * hw, struct file *file)
 {
-       struct snd_opl3 *opl3 = hw->private_data;
-
-       mutex_lock(&opl3->access_mutex);
-       if (opl3->used) {
-               mutex_unlock(&opl3->access_mutex);
-               return -EAGAIN;
-       }
-       opl3->used++;
-       mutex_unlock(&opl3->access_mutex);
-
        return 0;
 }
 
@@ -165,6 +155,10 @@ int snd_opl3_ioctl(struct snd_hwdep * hw, struct file *file,
 #endif
                return snd_opl3_set_connection(opl3, (int) arg);
 
+       case SNDRV_DM_FM_IOCTL_CLEAR_PATCHES:
+               snd_opl3_clear_patches(opl3);
+               return 0;
+
 #ifdef CONFIG_SND_DEBUG
        default:
                snd_printk("unknown IOCTL: 0x%x\n", cmd);
@@ -181,12 +175,172 @@ int snd_opl3_release(struct snd_hwdep * hw, struct file *file)
        struct snd_opl3 *opl3 = hw->private_data;
 
        snd_opl3_reset(opl3);
-       mutex_lock(&opl3->access_mutex);
-       opl3->used--;
-       mutex_unlock(&opl3->access_mutex);
+       return 0;
+}
+
+/*
+ * write the device - load patches
+ */
+long snd_opl3_write(struct snd_hwdep *hw, const char __user *buf, long count,
+                   loff_t *offset)
+{
+       struct snd_opl3 *opl3 = hw->private_data;
+       long result = 0;
+       int err = 0;
+       struct sbi_patch inst;
+
+       while (count >= sizeof(inst)) {
+               unsigned char type;
+               if (copy_from_user(&inst, buf, sizeof(inst)))
+                       return -EFAULT;
+               if (!memcmp(inst.key, FM_KEY_SBI, 4) ||
+                   !memcmp(inst.key, FM_KEY_2OP, 4))
+                       type = FM_PATCH_OPL2;
+               else if (!memcmp(inst.key, FM_KEY_4OP, 4))
+                       type = FM_PATCH_OPL3;
+               else /* invalid type */
+                       break;
+               err = snd_opl3_load_patch(opl3, inst.prog, inst.bank, type,
+                                         inst.name, inst.extension,
+                                         inst.data);
+               if (err < 0)
+                       break;
+               result += sizeof(inst);
+               count -= sizeof(inst);
+       }
+       return result > 0 ? result : err;
+}
+
+
+/*
+ * Patch management
+ */
+
+/* offsets for SBI params */
+#define AM_VIB         0
+#define KSL_LEVEL      2
+#define ATTACK_DECAY   4
+#define SUSTAIN_RELEASE        6
+#define WAVE_SELECT    8
+
+/* offset for SBI instrument */
+#define CONNECTION     10
+#define OFFSET_4OP     11
+
+/*
+ * load a patch, obviously.
+ *
+ * loaded on the given program and bank numbers with the given type
+ * (FM_PATCH_OPLx).
+ * data is the pointer of SBI record _without_ header (key and name).
+ * name is the name string of the patch.
+ * ext is the extension data of 7 bytes long (stored in name of SBI
+ * data up to offset 25), or NULL to skip.
+ * return 0 if successful or a negative error code.
+ */
+int snd_opl3_load_patch(struct snd_opl3 *opl3,
+                       int prog, int bank, int type,
+                       const char *name,
+                       const unsigned char *ext,
+                       const unsigned char *data)
+{
+       struct fm_patch *patch;
+       int i;
+
+       patch = snd_opl3_find_patch(opl3, prog, bank, 1);
+       if (!patch)
+               return -ENOMEM;
+
+       patch->type = type;
+
+       for (i = 0; i < 2; i++) {
+               patch->inst.op[i].am_vib = data[AM_VIB + i];
+               patch->inst.op[i].ksl_level = data[KSL_LEVEL + i];
+               patch->inst.op[i].attack_decay = data[ATTACK_DECAY + i];
+               patch->inst.op[i].sustain_release = data[SUSTAIN_RELEASE + i];
+               patch->inst.op[i].wave_select = data[WAVE_SELECT + i];
+       }
+       patch->inst.feedback_connection[0] = data[CONNECTION];
+
+       if (type == FM_PATCH_OPL3) {
+               for (i = 0; i < 2; i++) {
+                       patch->inst.op[i+2].am_vib =
+                               data[OFFSET_4OP + AM_VIB + i];
+                       patch->inst.op[i+2].ksl_level =
+                               data[OFFSET_4OP + KSL_LEVEL + i];
+                       patch->inst.op[i+2].attack_decay =
+                               data[OFFSET_4OP + ATTACK_DECAY + i];
+                       patch->inst.op[i+2].sustain_release =
+                               data[OFFSET_4OP + SUSTAIN_RELEASE + i];
+                       patch->inst.op[i+2].wave_select =
+                               data[OFFSET_4OP + WAVE_SELECT + i];
+               }
+               patch->inst.feedback_connection[1] =
+                       data[OFFSET_4OP + CONNECTION];
+       }
+
+       if (ext) {
+               patch->inst.echo_delay = ext[0];
+               patch->inst.echo_atten = ext[1];
+               patch->inst.chorus_spread = ext[2];
+               patch->inst.trnsps = ext[3];
+               patch->inst.fix_dur = ext[4];
+               patch->inst.modes = ext[5];
+               patch->inst.fix_key = ext[6];
+       }
+
+       if (name)
+               strlcpy(patch->name, name, sizeof(patch->name));
 
        return 0;
 }
+EXPORT_SYMBOL(snd_opl3_load_patch);
+
+/*
+ * find a patch with the given program and bank numbers, returns its pointer
+ * if no matching patch is found and create_patch is set, it creates a
+ * new patch object.
+ */
+struct fm_patch *snd_opl3_find_patch(struct snd_opl3 *opl3, int prog, int bank,
+                                    int create_patch)
+{
+       /* pretty dumb hash key */
+       unsigned int key = (prog + bank) % OPL3_PATCH_HASH_SIZE;
+       struct fm_patch *patch;
+
+       for (patch = opl3->patch_table[key]; patch; patch = patch->next) {
+               if (patch->prog == prog && patch->bank == bank)
+                       return patch;
+       }
+       if (!create_patch)
+               return NULL;
+
+       patch = kzalloc(sizeof(*patch), GFP_KERNEL);
+       if (!patch)
+               return NULL;
+       patch->prog = prog;
+       patch->bank = bank;
+       patch->next = opl3->patch_table[key];
+       opl3->patch_table[key] = patch;
+       return patch;
+}
+EXPORT_SYMBOL(snd_opl3_find_patch);
+
+/*
+ * Clear all patches of the given OPL3 instance
+ */
+void snd_opl3_clear_patches(struct snd_opl3 *opl3)
+{
+       int i;
+       for (i = 0; i <  OPL3_PATCH_HASH_SIZE; i++) {
+               struct fm_patch *patch, *next;
+               for (patch = opl3->patch_table[i]; patch; patch = next) {
+                       next = patch->next;
+                       kfree(patch);
+               }
+       }
+       memset(opl3->patch_table, 0, sizeof(opl3->patch_table));
+}
 
 /* ------------------------------ */
 
diff --git a/sound/drivers/pcm-indirect2.c b/sound/drivers/pcm-indirect2.c
new file mode 100644 (file)
index 0000000..3c93c23
--- /dev/null
@@ -0,0 +1,573 @@
+/*
+ * Helper functions for indirect PCM data transfer to a simple FIFO in
+ * hardware (small, no possibility to read "hardware io position",
+ * updating position done by interrupt, ...)
+ *
+ *  Copyright (c) by 2007  Joachim Foerster <JOFT@gmx.de>
+ *
+ *  Based on "pcm-indirect.h" (alsa-driver-1.0.13) by
+ *
+ *  Copyright (c) by Takashi Iwai <tiwai@suse.de>
+ *                   Jaroslav Kysela <perex@suse.cz>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   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.
+ */
+
+/* snd_printk/d() */
+#include <sound/core.h>
+/* struct snd_pcm_substream, struct snd_pcm_runtime, snd_pcm_uframes_t
+ * snd_pcm_period_elapsed() */
+#include <sound/pcm.h>
+
+#include "pcm-indirect2.h"
+
+#ifdef SND_PCM_INDIRECT2_STAT
+/* jiffies */
+#include <linux/jiffies.h>
+
+void snd_pcm_indirect2_stat(struct snd_pcm_substream *substream,
+                           struct snd_pcm_indirect2 *rec)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       int i;
+       int j;
+       int k;
+       int seconds = (rec->lastbytetime - rec->firstbytetime) / HZ;
+
+       snd_printk(KERN_DEBUG "STAT: mul_elapsed: %u, mul_elapsed_real: %d, "
+                  "irq_occured: %d\n",
+                  rec->mul_elapsed, rec->mul_elapsed_real, rec->irq_occured);
+       snd_printk(KERN_DEBUG "STAT: min_multiple: %d (irqs/period)\n",
+                  rec->min_multiple);
+       snd_printk(KERN_DEBUG "STAT: firstbytetime: %lu, lastbytetime: %lu, "
+                  "firstzerotime: %lu\n",
+                rec->firstbytetime, rec->lastbytetime, rec->firstzerotime);
+       snd_printk(KERN_DEBUG "STAT: bytes2hw: %u Bytes => (by runtime->rate) "
+                  "length: %d s\n",
+                rec->bytes2hw, rec->bytes2hw / 2 / 2 / runtime->rate);
+       snd_printk(KERN_DEBUG "STAT: (by measurement) length: %d => "
+                  "rate: %d Bytes/s = %d Frames/s|Hz\n",
+                  seconds, rec->bytes2hw / seconds,
+                  rec->bytes2hw / 2 / 2 / seconds);
+       snd_printk(KERN_DEBUG
+                  "STAT: zeros2hw: %u = %d ms ~ %d * %d zero copies\n",
+                  rec->zeros2hw, ((rec->zeros2hw / 2 / 2) * 1000) /
+                  runtime->rate,
+                  rec->zeros2hw / (rec->hw_buffer_size / 2),
+                  (rec->hw_buffer_size / 2));
+       snd_printk(KERN_DEBUG "STAT: pointer_calls: %u, lastdifftime: %u\n",
+                  rec->pointer_calls, rec->lastdifftime);
+       snd_printk(KERN_DEBUG "STAT: sw_io: %d, sw_data: %d\n", rec->sw_io,
+                  rec->sw_data);
+       snd_printk(KERN_DEBUG "STAT: byte_sizes[]:\n");
+       k = 0;
+       for (j = 0; j < 8; j++) {
+               for (i = j * 8; i < (j + 1) * 8; i++)
+                       if (rec->byte_sizes[i] != 0) {
+                               snd_printk(KERN_DEBUG "%u: %u",
+                                          i, rec->byte_sizes[i]);
+                               k++;
+                       }
+               if (((k % 8) == 0) && (k != 0)) {
+                       snd_printk(KERN_DEBUG "\n");
+                       k = 0;
+               }
+       }
+       snd_printk(KERN_DEBUG "\n");
+       snd_printk(KERN_DEBUG "STAT: zero_sizes[]:\n");
+       for (j = 0; j < 8; j++) {
+               k = 0;
+               for (i = j * 8; i < (j + 1) * 8; i++)
+                       if (rec->zero_sizes[i] != 0)
+                               snd_printk(KERN_DEBUG "%u: %u",
+                                          i, rec->zero_sizes[i]);
+                       else
+                               k++;
+               if (!k)
+                       snd_printk(KERN_DEBUG "\n");
+       }
+       snd_printk(KERN_DEBUG "\n");
+       snd_printk(KERN_DEBUG "STAT: min_adds[]:\n");
+       for (j = 0; j < 8; j++) {
+               if (rec->min_adds[j] != 0)
+                       snd_printk(KERN_DEBUG "%u: %u", j, rec->min_adds[j]);
+       }
+       snd_printk(KERN_DEBUG "\n");
+       snd_printk(KERN_DEBUG "STAT: mul_adds[]:\n");
+       for (j = 0; j < 8; j++) {
+               if (rec->mul_adds[j] != 0)
+                       snd_printk(KERN_DEBUG "%u: %u", j, rec->mul_adds[j]);
+       }
+       snd_printk(KERN_DEBUG "\n");
+       snd_printk(KERN_DEBUG
+                  "STAT: zero_times_saved: %d, zero_times_notsaved: %d\n",
+                  rec->zero_times_saved, rec->zero_times_notsaved);
+       /* snd_printk(KERN_DEBUG "STAT: zero_times[]\n");
+       i = 0;
+       for (j = 0; j < 3750; j++) {
+               if (rec->zero_times[j] != 0) {
+                       snd_printk(KERN_DEBUG "%u: %u", j, rec->zero_times[j]);
+                       i++;
+               }
+               if (((i % 8) == 0) && (i != 0))
+                       snd_printk(KERN_DEBUG "\n");
+       }
+       snd_printk(KERN_DEBUG "\n"); */
+       return;
+}
+#endif
+
+/*
+ * _internal_ helper function for playback/capture transfer function
+ */
+static void
+snd_pcm_indirect2_increase_min_periods(struct snd_pcm_substream *substream,
+                                      struct snd_pcm_indirect2 *rec,
+                                      int isplay, int iscopy,
+                                      unsigned int bytes)
+{
+       if (rec->min_periods >= 0) {
+               if (iscopy) {
+                       rec->sw_io += bytes;
+                       if (rec->sw_io >= rec->sw_buffer_size)
+                               rec->sw_io -= rec->sw_buffer_size;
+               } else if (isplay) {
+                       /* If application does not write data in multiples of
+                        * a period, move sw_data to the next correctly aligned
+                        * position, so that sw_io can converge to it (in the
+                        * next step).
+                        */
+                       if (!rec->check_alignment) {
+                               if (rec->bytes2hw %
+                                   snd_pcm_lib_period_bytes(substream)) {
+                                       unsigned bytes2hw_aligned =
+                                           (1 +
+                                            (rec->bytes2hw /
+                                             snd_pcm_lib_period_bytes
+                                             (substream))) *
+                                           snd_pcm_lib_period_bytes
+                                           (substream);
+                                       rec->sw_data =
+                                           bytes2hw_aligned %
+                                           rec->sw_buffer_size;
+#ifdef SND_PCM_INDIRECT2_STAT
+                                       snd_printk(KERN_DEBUG
+                                                  "STAT: @re-align: aligned "
+                                                  "bytes2hw to next period "
+                                                  "size boundary: %d "
+                                                  "(instead of %d)\n",
+                                                  bytes2hw_aligned,
+                                                  rec->bytes2hw);
+                                       snd_printk(KERN_DEBUG
+                                                  "STAT: @re-align: sw_data "
+                                                  "moves to: %d\n",
+                                                  rec->sw_data);
+#endif
+                               }
+                               rec->check_alignment = 1;
+                       }
+                       /* We are at the end and are copying zeros into the
+                        * fifo.
+                        * Now, we have to make sure that sw_io is increased
+                        * until the position of sw_data: Filling the fifo with
+                        * the first zeros means, the last bytes were played.
+                        */
+                       if (rec->sw_io != rec->sw_data) {
+                               unsigned int diff;
+                               if (rec->sw_data > rec->sw_io)
+                                       diff = rec->sw_data - rec->sw_io;
+                               else
+                                       diff = (rec->sw_buffer_size -
+                                               rec->sw_io) +
+                                               rec->sw_data;
+                               if (bytes >= diff)
+                                       rec->sw_io = rec->sw_data;
+                               else {
+                                       rec->sw_io += bytes;
+                                       if (rec->sw_io >= rec->sw_buffer_size)
+                                               rec->sw_io -=
+                                                   rec->sw_buffer_size;
+                               }
+                       }
+               }
+               rec->min_period_count += bytes;
+               if (rec->min_period_count >= (rec->hw_buffer_size / 2)) {
+                       rec->min_periods += (rec->min_period_count /
+                                            (rec->hw_buffer_size / 2));
+#ifdef SND_PCM_INDIRECT2_STAT
+                       if ((rec->min_period_count /
+                            (rec->hw_buffer_size / 2)) > 7)
+                               snd_printk(KERN_DEBUG
+                                          "STAT: more than 7 (%d) min_adds "
+                                          "at once - too big to save!\n",
+                                          (rec->min_period_count /
+                                           (rec->hw_buffer_size / 2)));
+                       else
+                               rec->min_adds[(rec->min_period_count /
+                                              (rec->hw_buffer_size / 2))]++;
+#endif
+                       rec->min_period_count = (rec->min_period_count %
+                                                (rec->hw_buffer_size / 2));
+               }
+       } else if (isplay && iscopy)
+               rec->min_periods = 0;
+}
+
+/*
+ * helper function for playback/capture pointer callback
+ */
+snd_pcm_uframes_t
+snd_pcm_indirect2_pointer(struct snd_pcm_substream *substream,
+                         struct snd_pcm_indirect2 *rec)
+{
+#ifdef SND_PCM_INDIRECT2_STAT
+       rec->pointer_calls++;
+#endif
+       return bytes_to_frames(substream->runtime, rec->sw_io);
+}
+
+/*
+ * _internal_ helper function for playback interrupt callback
+ */
+static void
+snd_pcm_indirect2_playback_transfer(struct snd_pcm_substream *substream,
+                                   struct snd_pcm_indirect2 *rec,
+                                   snd_pcm_indirect2_copy_t copy,
+                                   snd_pcm_indirect2_zero_t zero)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       snd_pcm_uframes_t appl_ptr = runtime->control->appl_ptr;
+
+       /* runtime->control->appl_ptr: position where ALSA will write next time
+        * rec->appl_ptr: position where ALSA was last time
+        * diff: obviously ALSA wrote that much bytes into the intermediate
+        * buffer since we checked last time
+        */
+       snd_pcm_sframes_t diff = appl_ptr - rec->appl_ptr;
+
+       if (diff) {
+#ifdef SND_PCM_INDIRECT2_STAT
+               rec->lastdifftime = jiffies;
+#endif
+               if (diff < -(snd_pcm_sframes_t) (runtime->boundary / 2))
+                       diff += runtime->boundary;
+               /* number of bytes "added" by ALSA increases the number of
+                * bytes which are ready to "be transfered to HW"/"played"
+                * Then, set rec->appl_ptr to not count bytes twice next time.
+                */
+               rec->sw_ready += (int)frames_to_bytes(runtime, diff);
+               rec->appl_ptr = appl_ptr;
+       }
+       if (rec->hw_ready && (rec->sw_ready <= 0)) {
+               unsigned int bytes;
+
+#ifdef SND_PCM_INDIRECT2_STAT
+               if (rec->firstzerotime == 0) {
+                       rec->firstzerotime = jiffies;
+                       snd_printk(KERN_DEBUG
+                                  "STAT: @firstzerotime: mul_elapsed: %d, "
+                                  "min_period_count: %d\n",
+                                  rec->mul_elapsed, rec->min_period_count);
+                       snd_printk(KERN_DEBUG
+                                  "STAT: @firstzerotime: sw_io: %d, "
+                                  "sw_data: %d, appl_ptr: %u\n",
+                                  rec->sw_io, rec->sw_data,
+                                  (unsigned int)appl_ptr);
+               }
+               if ((jiffies - rec->firstzerotime) < 3750) {
+                       rec->zero_times[(jiffies - rec->firstzerotime)]++;
+                       rec->zero_times_saved++;
+               } else
+                       rec->zero_times_notsaved++;
+#endif
+               bytes = zero(substream, rec);
+
+#ifdef SND_PCM_INDIRECT2_STAT
+               rec->zeros2hw += bytes;
+               if (bytes < 64)
+                       rec->zero_sizes[bytes]++;
+               else
+                       snd_printk(KERN_DEBUG
+                                  "STAT: %d zero Bytes copied to hardware at "
+                                  "once - too big to save!\n",
+                                  bytes);
+#endif
+               snd_pcm_indirect2_increase_min_periods(substream, rec, 1, 0,
+                                                      bytes);
+               return;
+       }
+       while (rec->hw_ready && (rec->sw_ready > 0)) {
+               /* sw_to_end: max. number of bytes that can be read/take from
+                * the current position (sw_data) in _one_ step
+                */
+               unsigned int sw_to_end = rec->sw_buffer_size - rec->sw_data;
+
+               /* bytes: number of bytes we have available (for reading) */
+               unsigned int bytes = rec->sw_ready;
+
+               if (sw_to_end < bytes)
+                       bytes = sw_to_end;
+               if (!bytes)
+                       break;
+
+#ifdef SND_PCM_INDIRECT2_STAT
+               if (rec->firstbytetime == 0)
+                       rec->firstbytetime = jiffies;
+               rec->lastbytetime = jiffies;
+#endif
+               /* copy bytes from intermediate buffer position sw_data to the
+                * HW and return number of bytes actually written
+                * Furthermore, set hw_ready to 0, if the fifo isn't empty
+                * now => more could be transfered to fifo
+                */
+               bytes = copy(substream, rec, bytes);
+               rec->bytes2hw += bytes;
+
+#ifdef SND_PCM_INDIRECT2_STAT
+               if (bytes < 64)
+                       rec->byte_sizes[bytes]++;
+               else
+                       snd_printk(KERN_DEBUG
+                                  "STAT: %d Bytes copied to hardware at once "
+                                  "- too big to save!\n",
+                                  bytes);
+#endif
+               /* increase sw_data by the number of actually written bytes
+                * (= number of taken bytes from intermediate buffer)
+                */
+               rec->sw_data += bytes;
+               if (rec->sw_data == rec->sw_buffer_size)
+                       rec->sw_data = 0;
+               /* now sw_data is the position where ALSA is going to write
+                * in the intermediate buffer next time = position we are going
+                * to read from next time
+                */
+
+               snd_pcm_indirect2_increase_min_periods(substream, rec, 1, 1,
+                                                      bytes);
+
+               /* we read bytes from intermediate buffer, so we need to say
+                * that the number of bytes ready for transfer are decreased
+                * now
+                */
+               rec->sw_ready -= bytes;
+       }
+       return;
+}
+
+/*
+ * helper function for playback interrupt routine
+ */
+void
+snd_pcm_indirect2_playback_interrupt(struct snd_pcm_substream *substream,
+                                    struct snd_pcm_indirect2 *rec,
+                                    snd_pcm_indirect2_copy_t copy,
+                                    snd_pcm_indirect2_zero_t zero)
+{
+#ifdef SND_PCM_INDIRECT2_STAT
+       rec->irq_occured++;
+#endif
+       /* hardware played some bytes, so there is room again (in fifo) */
+       rec->hw_ready = 1;
+
+       /* don't call ack() now, instead call transfer() function directly
+        * (normally called by ack() )
+        */
+       snd_pcm_indirect2_playback_transfer(substream, rec, copy, zero);
+
+       if (rec->min_periods >= rec->min_multiple) {
+#ifdef SND_PCM_INDIRECT2_STAT
+               if ((rec->min_periods / rec->min_multiple) > 7)
+                       snd_printk(KERN_DEBUG
+                                  "STAT: more than 7 (%d) mul_adds - too big "
+                                  "to save!\n",
+                                  (rec->min_periods / rec->min_multiple));
+               else
+                       rec->mul_adds[(rec->min_periods /
+                                      rec->min_multiple)]++;
+               rec->mul_elapsed_real += (rec->min_periods /
+                                         rec->min_multiple);
+               rec->mul_elapsed++;
+#endif
+               rec->min_periods = (rec->min_periods % rec->min_multiple);
+               snd_pcm_period_elapsed(substream);
+       }
+}
+
+/*
+ * _internal_ helper function for capture interrupt callback
+ */
+static void
+snd_pcm_indirect2_capture_transfer(struct snd_pcm_substream *substream,
+                                  struct snd_pcm_indirect2 *rec,
+                                  snd_pcm_indirect2_copy_t copy,
+                                  snd_pcm_indirect2_zero_t null)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       snd_pcm_uframes_t appl_ptr = runtime->control->appl_ptr;
+       snd_pcm_sframes_t diff = appl_ptr - rec->appl_ptr;
+
+       if (diff) {
+#ifdef SND_PCM_INDIRECT2_STAT
+               rec->lastdifftime = jiffies;
+#endif
+               if (diff < -(snd_pcm_sframes_t) (runtime->boundary / 2))
+                       diff += runtime->boundary;
+               rec->sw_ready -= frames_to_bytes(runtime, diff);
+               rec->appl_ptr = appl_ptr;
+       }
+       /* if hardware has something, but the intermediate buffer is full
+        * => skip contents of buffer
+        */
+       if (rec->hw_ready && (rec->sw_ready >= (int)rec->sw_buffer_size)) {
+               unsigned int bytes;
+
+#ifdef SND_PCM_INDIRECT2_STAT
+               if (rec->firstzerotime == 0) {
+                       rec->firstzerotime = jiffies;
+                       snd_printk(KERN_DEBUG "STAT: (capture) "
+                                  "@firstzerotime: mul_elapsed: %d, "
+                                  "min_period_count: %d\n",
+                                  rec->mul_elapsed, rec->min_period_count);
+                       snd_printk(KERN_DEBUG "STAT: (capture) "
+                                  "@firstzerotime: sw_io: %d, sw_data: %d, "
+                                  "appl_ptr: %u\n",
+                                  rec->sw_io, rec->sw_data,
+                                  (unsigned int)appl_ptr);
+               }
+               if ((jiffies - rec->firstzerotime) < 3750) {
+                       rec->zero_times[(jiffies - rec->firstzerotime)]++;
+                       rec->zero_times_saved++;
+               } else
+                       rec->zero_times_notsaved++;
+#endif
+               bytes = null(substream, rec);
+
+#ifdef SND_PCM_INDIRECT2_STAT
+               rec->zeros2hw += bytes;
+               if (bytes < 64)
+                       rec->zero_sizes[bytes]++;
+               else
+                       snd_printk(KERN_DEBUG
+                                  "STAT: (capture) %d zero Bytes copied to "
+                                  "hardware at once - too big to save!\n",
+                                  bytes);
+#endif
+               snd_pcm_indirect2_increase_min_periods(substream, rec, 0, 0,
+                                                      bytes);
+               /* report an overrun */
+               rec->sw_io = SNDRV_PCM_POS_XRUN;
+               return;
+       }
+       while (rec->hw_ready && (rec->sw_ready < (int)rec->sw_buffer_size)) {
+               /* sw_to_end: max. number of bytes that we can write to the
+                *  intermediate buffer (until it's end)
+                */
+               size_t sw_to_end = rec->sw_buffer_size - rec->sw_data;
+
+               /* bytes: max. number of bytes, which may be copied to the
+                *  intermediate buffer without overflow (in _one_ step)
+                */
+               size_t bytes = rec->sw_buffer_size - rec->sw_ready;
+
+               /* limit number of bytes (for transfer) by available room in
+                * the intermediate buffer
+                */
+               if (sw_to_end < bytes)
+                       bytes = sw_to_end;
+               if (!bytes)
+                       break;
+
+#ifdef SND_PCM_INDIRECT2_STAT
+               if (rec->firstbytetime == 0)
+                       rec->firstbytetime = jiffies;
+               rec->lastbytetime = jiffies;
+#endif
+               /* copy bytes from the intermediate buffer (position sw_data)
+                * to the HW at most and return number of bytes actually copied
+                * from HW
+                * Furthermore, set hw_ready to 0, if the fifo is empty now.
+                */
+               bytes = copy(substream, rec, bytes);
+               rec->bytes2hw += bytes;
+
+#ifdef SND_PCM_INDIRECT2_STAT
+               if (bytes < 64)
+                       rec->byte_sizes[bytes]++;
+               else
+                       snd_printk(KERN_DEBUG
+                                  "STAT: (capture) %d Bytes copied to "
+                                  "hardware at once - too big to save!\n",
+                                  bytes);
+#endif
+               /* increase sw_data by the number of actually copied bytes from
+                * HW
+                */
+               rec->sw_data += bytes;
+               if (rec->sw_data == rec->sw_buffer_size)
+                       rec->sw_data = 0;
+
+               snd_pcm_indirect2_increase_min_periods(substream, rec, 0, 1,
+                                                      bytes);
+
+               /* number of bytes in the intermediate buffer, which haven't
+                * been fetched by ALSA yet.
+                */
+               rec->sw_ready += bytes;
+       }
+       return;
+}
+
+/*
+ * helper function for capture interrupt routine
+ */
+void
+snd_pcm_indirect2_capture_interrupt(struct snd_pcm_substream *substream,
+                                   struct snd_pcm_indirect2 *rec,
+                                   snd_pcm_indirect2_copy_t copy,
+                                   snd_pcm_indirect2_zero_t null)
+{
+#ifdef SND_PCM_INDIRECT2_STAT
+       rec->irq_occured++;
+#endif
+       /* hardware recorded some bytes, so there is something to read from the
+        * record fifo:
+        */
+       rec->hw_ready = 1;
+
+       /* don't call ack() now, instead call transfer() function directly
+        * (normally called by ack() )
+        */
+       snd_pcm_indirect2_capture_transfer(substream, rec, copy, null);
+
+       if (rec->min_periods >= rec->min_multiple) {
+
+#ifdef SND_PCM_INDIRECT2_STAT
+               if ((rec->min_periods / rec->min_multiple) > 7)
+                       snd_printk(KERN_DEBUG
+                                  "STAT: more than 7 (%d) mul_adds - "
+                                  "too big to save!\n",
+                                  (rec->min_periods / rec->min_multiple));
+               else
+                       rec->mul_adds[(rec->min_periods /
+                                      rec->min_multiple)]++;
+               rec->mul_elapsed_real += (rec->min_periods /
+                                         rec->min_multiple);
+               rec->mul_elapsed++;
+#endif
+               rec->min_periods = (rec->min_periods % rec->min_multiple);
+               snd_pcm_period_elapsed(substream);
+       }
+}
diff --git a/sound/drivers/pcm-indirect2.h b/sound/drivers/pcm-indirect2.h
new file mode 100644 (file)
index 0000000..2ea6e46
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ * Helper functions for indirect PCM data transfer to a simple FIFO in
+ * hardware (small, no possibility to read "hardware io position",
+ * updating position done by interrupt, ...)
+ *
+ *  Copyright (c) by 2007  Joachim Foerster <JOFT@gmx.de>
+ *
+ *  Based on "pcm-indirect.h" (alsa-driver-1.0.13) by
+ *
+ *  Copyright (c) by Takashi Iwai <tiwai@suse.de>
+ *                   Jaroslav Kysela <perex@suse.cz>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   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 __SOUND_PCM_INDIRECT2_H
+#define __SOUND_PCM_INDIRECT2_H
+
+/* struct snd_pcm_substream, struct snd_pcm_runtime, snd_pcm_uframes_t */
+#include <sound/pcm.h>
+
+/* Debug options for code which may be removed completely in a final version */
+#ifdef CONFIG_SND_DEBUG
+#define SND_PCM_INDIRECT2_STAT    /* turn on some "statistics" about the
+                                  * process of copying bytes from the
+                                  * intermediate buffer to the hardware
+                                  * fifo and the other way round
+                                  */
+#endif
+
+struct snd_pcm_indirect2 {
+       unsigned int hw_buffer_size;  /* Byte size of hardware buffer */
+       int hw_ready;                 /* playback: 1 = hw fifo has room left,
+                                      * 0 = hw fifo is full
+                                      */
+       unsigned int min_multiple;
+       int min_periods;              /* counts number of min. periods until
+                                      * min_multiple is reached
+                                      */
+       int min_period_count;         /* counts bytes to count number of
+                                      * min. periods
+                                      */
+
+       unsigned int sw_buffer_size;  /* Byte size of software buffer */
+
+       /* sw_data: position in intermediate buffer, where we will read (or
+        *          write) from/to next time (to transfer data to/from HW)
+        */
+       unsigned int sw_data;         /* Offset to next dst (or src) in sw
+                                      * ring buffer
+                                      */
+       /* easiest case (playback):
+        * sw_data is nearly the same as ~ runtime->control->appl_ptr, with the
+        * exception that sw_data is "behind" by the number if bytes ALSA wrote
+        * to the intermediate buffer last time.
+        * A call to ack() callback synchronizes both indirectly.
+        */
+
+       /* We have no real sw_io pointer here. Usually sw_io is pointing to the
+        * current playback/capture position _inside_ the hardware. Devices
+        * with plain FIFOs often have no possibility to publish this position.
+        * So we say: if sw_data is updated, that means bytes were copied to
+        * the hardware, we increase sw_io by that amount, because there have
+        * to be as much bytes which were played. So sw_io will stay behind
+        * sw_data all the time and has to converge to sw_data at the end of
+        * playback.
+        */
+       unsigned int sw_io;           /* Current software pointer in bytes */
+
+       /* sw_ready: number of bytes ALSA copied to the intermediate buffer, so
+        * it represents the number of bytes which wait for transfer to the HW
+        */
+       int sw_ready;             /* Bytes ready to be transferred to/from hw */
+
+       /* appl_ptr: last known position of ALSA (where ALSA is going to write
+        * next time into the intermediate buffer
+        */
+       snd_pcm_uframes_t appl_ptr;   /* Last seen appl_ptr */
+
+       unsigned int bytes2hw;
+       int check_alignment;
+
+#ifdef SND_PCM_INDIRECT2_STAT
+       unsigned int zeros2hw;
+       unsigned int mul_elapsed;
+       unsigned int mul_elapsed_real;
+       unsigned long firstbytetime;
+       unsigned long lastbytetime;
+       unsigned long firstzerotime;
+       unsigned int byte_sizes[64];
+       unsigned int zero_sizes[64];
+       unsigned int min_adds[8];
+       unsigned int mul_adds[8];
+       unsigned int zero_times[3750];  /* = 15s */
+       unsigned int zero_times_saved;
+       unsigned int zero_times_notsaved;
+       unsigned int irq_occured;
+       unsigned int pointer_calls;
+       unsigned int lastdifftime;
+#endif
+};
+
+typedef size_t (*snd_pcm_indirect2_copy_t) (struct snd_pcm_substream *substream,
+                                          struct snd_pcm_indirect2 *rec,
+                                          size_t bytes);
+typedef size_t (*snd_pcm_indirect2_zero_t) (struct snd_pcm_substream *substream,
+                                          struct snd_pcm_indirect2 *rec);
+
+#ifdef SND_PCM_INDIRECT2_STAT
+void snd_pcm_indirect2_stat(struct snd_pcm_substream *substream,
+                                  struct snd_pcm_indirect2 *rec);
+#endif
+
+snd_pcm_uframes_t
+snd_pcm_indirect2_pointer(struct snd_pcm_substream *substream,
+                         struct snd_pcm_indirect2 *rec);
+void
+snd_pcm_indirect2_playback_interrupt(struct snd_pcm_substream *substream,
+                                    struct snd_pcm_indirect2 *rec,
+                                    snd_pcm_indirect2_copy_t copy,
+                                    snd_pcm_indirect2_zero_t zero);
+void
+snd_pcm_indirect2_capture_interrupt(struct snd_pcm_substream *substream,
+                                   struct snd_pcm_indirect2 *rec,
+                                   snd_pcm_indirect2_copy_t copy,
+                                   snd_pcm_indirect2_zero_t null);
+
+#endif /* __SOUND_PCM_INDIRECT2_H */
index 1b832870cc84aabdfc19669b7d23378ce4a22c8f..b1c047ec19afe6e5ce9e6cf1acb2124c72719d45 100644 (file)
@@ -37,7 +37,6 @@
  *      - ported from alsa 0.5 to 1.0
  */
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/parport.h>
@@ -797,6 +796,8 @@ static int __devinit snd_portman_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, card);
 
+       snd_card_set_dev(card, &pdev->dev);
+
        /* At this point card will be usable */
        if ((err = snd_card_register(card)) < 0) {
                snd_printd("Cannot register card\n");
index 65de3a755ddb69da85c15b74f2fb0e62acfccb4e..d8aab9da97c29ad8058f5be9751537b25b043500 100644 (file)
@@ -30,7 +30,6 @@
  *      More documentation can be found in serial-u16550.txt.
  */
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/err.h>
@@ -43,6 +42,7 @@
 #include <sound/initval.h>
 
 #include <linux/serial_reg.h>
+#include <linux/jiffies.h>
 
 #include <asm/io.h>
 
@@ -455,7 +455,7 @@ static void snd_uart16550_do_open(struct snd_uart16550 * uart)
                    | UART_IER_THRI     /* Enable Transmitter holding register empty interrupt */
                    ;
        }
-       outb(byte, uart->base + UART_IER);      /* Interupt enable Register */
+       outb(byte, uart->base + UART_IER);      /* Interrupt enable Register */
 
        inb(uart->base + UART_LSR);     /* Clear any pre-existing overrun indication */
        inb(uart->base + UART_IIR);     /* Clear any pre-existing transmit interrupt */
@@ -473,7 +473,7 @@ static void snd_uart16550_do_close(struct snd_uart16550 * uart)
 
        outb((0 & UART_IER_RDI)         /* Disable Receiver data interrupt */
             |(0 & UART_IER_THRI)       /* Disable Transmitter holding register empty interrupt */
-            ,uart->base + UART_IER);   /* Interupt enable Register */
+            ,uart->base + UART_IER);   /* Interrupt enable Register */
 
        switch (uart->adaptor) {
        default:
@@ -653,7 +653,7 @@ static void snd_uart16550_output_write(struct snd_rawmidi_substream *substream)
        char first;
        static unsigned long lasttime = 0;
        
-       /* Interupts are disabled during the updating of the tx_buff,
+       /* Interrupts are disabled during the updating of the tx_buff,
         * since it is 'bad' to have two processes updating the same
         * variables (ie buff_in & buff_out)
         */
@@ -694,7 +694,7 @@ static void snd_uart16550_output_write(struct snd_rawmidi_substream *substream)
                            (uart->adaptor == SNDRV_SERIAL_SOUNDCANVAS ||
                             uart->adaptor == SNDRV_SERIAL_GENERIC) &&
                            (uart->prev_out != substream->number ||
-                            jiffies-lasttime > 3*HZ)) {
+                            time_after(jiffies, lasttime + 3*HZ))) {
 
                                if (snd_uart16550_buffer_can_write(uart, 3)) {
                                        /* Roland Soundcanvas part selection */
index 915c86773c21fbe0a4635a9f5508c2537834f1a8..f79e3614079d238aca26df870c863949bbda1e94 100644 (file)
@@ -41,7 +41,6 @@
  * - Run application using a midi device (eg. /dev/snd/midiC1D0)
  */
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/wait.h>
 #include <linux/err.h>
index 7a221349f2855eac887d5b5bbd4af0c156a19ece..9529e3bf2866309f808488e5ba46ac1732c6d684 100644 (file)
@@ -20,7 +20,6 @@
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-#include <sound/driver.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/vx_core.h>
index ed19bc17400ba8cf2112a29f7b8ff21f577b97c9..99538862e3428af01e3f26e5ed668a4f0c17baa6 100644 (file)
@@ -20,7 +20,6 @@
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-#include <sound/driver.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
 #include <linux/interrupt.h>
index 9a8154c9416ed11c8dda6c1a38e695aca7aa25a5..1dfe6948e6ffdb14d36438dad0940e520f862338 100644 (file)
@@ -20,7 +20,6 @@
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-#include <sound/driver.h>
 #include <linux/device.h>
 #include <linux/firmware.h>
 #include <linux/vmalloc.h>
index b8fcd79a7e11ea041c7b45f90adc02a204eb1632..5a347321f8c037a384a310f696674daa06c7b118 100644 (file)
@@ -20,7 +20,6 @@
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-#include <sound/driver.h>
 #include <sound/core.h>
 #include <sound/control.h>
 #include <sound/tlv.h>
@@ -439,14 +438,19 @@ static int vx_output_level_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ele
 {
        struct vx_core *chip = snd_kcontrol_chip(kcontrol);
        int codec = kcontrol->id.index;
+       unsigned int val[2], vmax;
+
+       vmax = chip->hw->output_level_max;
+       val[0] = ucontrol->value.integer.value[0];
+       val[1] = ucontrol->value.integer.value[1];
+       if (val[0] > vmax || val[1] > vmax)
+               return -EINVAL;
        mutex_lock(&chip->mixer_mutex);
-       if (ucontrol->value.integer.value[0] != chip->output_level[codec][0] ||
-           ucontrol->value.integer.value[1] != chip->output_level[codec][1]) {
-               vx_set_analog_output_level(chip, codec,
-                                          ucontrol->value.integer.value[0],
-                                          ucontrol->value.integer.value[1]);
-               chip->output_level[codec][0] = ucontrol->value.integer.value[0];
-               chip->output_level[codec][1] = ucontrol->value.integer.value[1];
+       if (val[0] != chip->output_level[codec][0] ||
+           val[1] != chip->output_level[codec][1]) {
+               vx_set_analog_output_level(chip, codec, val[0], val[1]);
+               chip->output_level[codec][0] = val[0];
+               chip->output_level[codec][1] = val[1];
                mutex_unlock(&chip->mixer_mutex);
                return 1;
        }
@@ -506,6 +510,14 @@ static int vx_audio_src_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_v
 static int vx_audio_src_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
        struct vx_core *chip = snd_kcontrol_chip(kcontrol);
+
+       if (chip->type >= VX_TYPE_VXPOCKET) {
+               if (ucontrol->value.enumerated.item[0] > 2)
+                       return -EINVAL;
+       } else {
+               if (ucontrol->value.enumerated.item[0] > 1)
+                       return -EINVAL;
+       }
        mutex_lock(&chip->mixer_mutex);
        if (chip->audio_source_target != ucontrol->value.enumerated.item[0]) {
                chip->audio_source_target = ucontrol->value.enumerated.item[0];
@@ -554,6 +566,9 @@ static int vx_clock_mode_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_
 static int vx_clock_mode_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
        struct vx_core *chip = snd_kcontrol_chip(kcontrol);
+
+       if (ucontrol->value.enumerated.item[0] > 2)
+               return -EINVAL;
        mutex_lock(&chip->mixer_mutex);
        if (chip->clock_mode != ucontrol->value.enumerated.item[0]) {
                chip->clock_mode = ucontrol->value.enumerated.item[0];
@@ -603,12 +618,17 @@ static int vx_audio_gain_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_
        struct vx_core *chip = snd_kcontrol_chip(kcontrol);
        int audio = kcontrol->private_value & 0xff;
        int capture = (kcontrol->private_value >> 8) & 1;
+       unsigned int val[2];
 
+       val[0] = ucontrol->value.integer.value[0];
+       val[1] = ucontrol->value.integer.value[1];
+       if (val[0] > CVAL_MAX || val[1] > CVAL_MAX)
+               return -EINVAL;
        mutex_lock(&chip->mixer_mutex);
-       if (ucontrol->value.integer.value[0] != chip->audio_gain[capture][audio] ||
-           ucontrol->value.integer.value[1] != chip->audio_gain[capture][audio+1]) {
-               vx_set_audio_gain(chip, audio, capture, ucontrol->value.integer.value[0]);
-               vx_set_audio_gain(chip, audio+1, capture, ucontrol->value.integer.value[1]);
+       if (val[0] != chip->audio_gain[capture][audio] ||
+           val[1] != chip->audio_gain[capture][audio+1]) {
+               vx_set_audio_gain(chip, audio, capture, val[0]);
+               vx_set_audio_gain(chip, audio+1, capture, val[1]);
                mutex_unlock(&chip->mixer_mutex);
                return 1;
        }
@@ -632,13 +652,19 @@ static int vx_audio_monitor_put(struct snd_kcontrol *kcontrol, struct snd_ctl_el
 {
        struct vx_core *chip = snd_kcontrol_chip(kcontrol);
        int audio = kcontrol->private_value & 0xff;
+       unsigned int val[2];
+
+       val[0] = ucontrol->value.integer.value[0];
+       val[1] = ucontrol->value.integer.value[1];
+       if (val[0] > CVAL_MAX || val[1] > CVAL_MAX)
+               return -EINVAL;
 
        mutex_lock(&chip->mixer_mutex);
-       if (ucontrol->value.integer.value[0] != chip->audio_monitor[audio] ||
-           ucontrol->value.integer.value[1] != chip->audio_monitor[audio+1]) {
-               vx_set_monitor_level(chip, audio, ucontrol->value.integer.value[0],
+       if (val[0] != chip->audio_monitor[audio] ||
+           val[1] != chip->audio_monitor[audio+1]) {
+               vx_set_monitor_level(chip, audio, val[0],
                                     chip->audio_monitor_active[audio]);
-               vx_set_monitor_level(chip, audio+1, ucontrol->value.integer.value[1],
+               vx_set_monitor_level(chip, audio+1, val[1],
                                     chip->audio_monitor_active[audio+1]);
                mutex_unlock(&chip->mixer_mutex);
                return 1;
@@ -669,8 +695,10 @@ static int vx_audio_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_va
        mutex_lock(&chip->mixer_mutex);
        if (ucontrol->value.integer.value[0] != chip->audio_active[audio] ||
            ucontrol->value.integer.value[1] != chip->audio_active[audio+1]) {
-               vx_set_audio_switch(chip, audio, ucontrol->value.integer.value[0]);
-               vx_set_audio_switch(chip, audio+1, ucontrol->value.integer.value[1]);
+               vx_set_audio_switch(chip, audio,
+                                   !!ucontrol->value.integer.value[0]);
+               vx_set_audio_switch(chip, audio+1,
+                                   !!ucontrol->value.integer.value[1]);
                mutex_unlock(&chip->mixer_mutex);
                return 1;
        }
@@ -699,9 +727,9 @@ static int vx_monitor_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_
        if (ucontrol->value.integer.value[0] != chip->audio_monitor_active[audio] ||
            ucontrol->value.integer.value[1] != chip->audio_monitor_active[audio+1]) {
                vx_set_monitor_level(chip, audio, chip->audio_monitor[audio],
-                                    ucontrol->value.integer.value[0]);
+                                    !!ucontrol->value.integer.value[0]);
                vx_set_monitor_level(chip, audio+1, chip->audio_monitor[audio+1],
-                                    ucontrol->value.integer.value[1]);
+                                    !!ucontrol->value.integer.value[1]);
                mutex_unlock(&chip->mixer_mutex);
                return 1;
        }
index 7e65a103fbb2f357ebbf59789cbac13c81aea8f5..fdbf86571b1f3f528233b3c13537e78728a2028c 100644 (file)
@@ -45,7 +45,6 @@
  *  - scheduled action on the stream.
  */
 
-#include <sound/driver.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
 #include <linux/delay.h>
index 7400306b7f285a57a107cc3819331f76db2571b3..fb8932af888d6a523fc5c33f489acb61e5b2d82f 100644 (file)
@@ -20,7 +20,6 @@
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-#include <sound/driver.h>
 #include <linux/delay.h>
 #include <sound/core.h>
 #include <sound/vx_core.h>
index 744366b72345ae4e8a7c32790b12fe828d9f0bf5..e57e9cbe6a0f99aa36d8090a222c91b76b555771 100644 (file)
@@ -20,7 +20,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
 #include <linux/init.h>
index 1e58a963b2a74b60a64bd3cdcf3ba10ad6f9fb1a..b1e74e40cba050656879dbe529a72adb218397c3 100644 (file)
@@ -20,7 +20,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/string.h>
index b074fdddea55d760477743da8025ed052884e75f..bfa5d2c3608bfed3d412165357a3889b4205d24e 100644 (file)
@@ -19,7 +19,6 @@
 
 /* $Id: uda1341.c,v 1.18 2005/11/17 14:17:21 tiwai Exp $ */
 
-#include <sound/driver.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/types.h>
index facde46f957a68ebfcacf0a770ab3675aa83ced9..15061bd72776a0eacbb418d7abb1125bda5398cf 100644 (file)
@@ -20,7 +20,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
 #include <sound/core.h>
index ee1585aec99b0e9c6c4b7e7d36194fc62431aaa5..f350835ade96cced97ae9815de8d71a09e3cf86b 100644 (file)
@@ -20,7 +20,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
 #include <sound/core.h>
index de03f689fa2e04dd4f951fbcbb7c272408723b4f..35fbbf2cb9fa84bb47241c2de5ce7c9c9941e323 100644 (file)
@@ -21,7 +21,6 @@
  *
  */      
 
-#include <sound/driver.h>
 #include <asm/io.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
@@ -293,6 +292,11 @@ void snd_akm4xxx_init(struct snd_akm4xxx *ak)
        case SND_AK5365:
                /* FIXME: any init sequence? */
                return;
+       case NON_AKM:
+               /* fake value for non-akm codecs using akm infrastructure
+                * (e.g. of ice1724) - certainly FIXME
+                */
+               return;
        default:
                snd_BUG();
                return;
@@ -377,8 +381,11 @@ static int put_ak_reg(struct snd_kcontrol *kcontrol, int addr,
 static int snd_akm4xxx_volume_put(struct snd_kcontrol *kcontrol,
                                  struct snd_ctl_elem_value *ucontrol)
 {
-       return put_ak_reg(kcontrol, AK_GET_ADDR(kcontrol->private_value),
-                         ucontrol->value.integer.value[0]);
+       unsigned int mask = AK_GET_MASK(kcontrol->private_value);
+       unsigned int val = ucontrol->value.integer.value[0];
+       if (val > mask)
+               return -EINVAL;
+       return put_ak_reg(kcontrol, AK_GET_ADDR(kcontrol->private_value), val);
 }
 
 static int snd_akm4xxx_stereo_volume_info(struct snd_kcontrol *kcontrol,
@@ -409,11 +416,16 @@ static int snd_akm4xxx_stereo_volume_put(struct snd_kcontrol *kcontrol,
                                         struct snd_ctl_elem_value *ucontrol)
 {
        int addr = AK_GET_ADDR(kcontrol->private_value);
+       unsigned int mask = AK_GET_MASK(kcontrol->private_value);
+       unsigned int val[2];
        int change;
 
-       change = put_ak_reg(kcontrol, addr, ucontrol->value.integer.value[0]);
-       change |= put_ak_reg(kcontrol, addr + 1,
-                            ucontrol->value.integer.value[1]);
+       val[0] = ucontrol->value.integer.value[0];
+       val[1] = ucontrol->value.integer.value[1];
+       if (val[0] > mask || val[1] > mask)
+               return -EINVAL;
+       change = put_ak_reg(kcontrol, addr, val[0]);
+       change |= put_ak_reg(kcontrol, addr + 1, val[1]);
        return change;
 }
 
@@ -508,6 +520,18 @@ static int ak4xxx_switch_put(struct snd_kcontrol *kcontrol,
 
 #define AK5365_NUM_INPUTS 5
 
+static int ak4xxx_capture_num_inputs(struct snd_akm4xxx *ak, int mixer_ch)
+{
+       int num_names;
+       const char **input_names;
+
+       input_names = ak->adc_info[mixer_ch].input_names;
+       num_names = 0;
+       while (num_names < AK5365_NUM_INPUTS && input_names[num_names])
+               ++num_names;
+       return num_names;
+}
+
 static int ak4xxx_capture_source_info(struct snd_kcontrol *kcontrol,
                                      struct snd_ctl_elem_info *uinfo)
 {
@@ -516,18 +540,16 @@ static int ak4xxx_capture_source_info(struct snd_kcontrol *kcontrol,
        const char **input_names;
        int  num_names, idx;
 
-       input_names = ak->adc_info[mixer_ch].input_names;
-
-       num_names = 0;
-       while (num_names < AK5365_NUM_INPUTS && input_names[num_names])
-               ++num_names;
-       
+       num_names = ak4xxx_capture_num_inputs(ak, mixer_ch);
+       if (!num_names)
+               return -EINVAL;
        uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
        uinfo->count = 1;
        uinfo->value.enumerated.items = num_names;
        idx = uinfo->value.enumerated.item;
        if (idx >= num_names)
                return -EINVAL;
+       input_names = ak->adc_info[mixer_ch].input_names;
        strncpy(uinfo->value.enumerated.name, input_names[idx],
                sizeof(uinfo->value.enumerated.name));
        return 0;
@@ -551,10 +573,15 @@ static int ak4xxx_capture_source_put(struct snd_kcontrol *kcontrol,
                                     struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
+       int mixer_ch = AK_GET_SHIFT(kcontrol->private_value);
        int chip = AK_GET_CHIP(kcontrol->private_value);
        int addr = AK_GET_ADDR(kcontrol->private_value);
        int mask = AK_GET_MASK(kcontrol->private_value);
        unsigned char oval, val;
+       int num_names = ak4xxx_capture_num_inputs(ak, mixer_ch);
+
+       if (ucontrol->value.enumerated.item[0] >= num_names)
+               return -EINVAL;
 
        oval = snd_akm4xxx_get(ak, chip, addr);
        val = oval & ~mask;
index 00c83d8b32b11c1b195f886ff9b4e6ff2b31f2ca..797d3a6687ebf7557308fd5a1d14201a230e8dbe 100644 (file)
@@ -19,7 +19,6 @@
  *
  */      
 
-#include <sound/driver.h>
 #include <sound/core.h>
 #include <sound/control.h>
 #include <sound/tlv.h>
@@ -113,6 +112,8 @@ static int pt2258_stereo_volume_put(struct snd_kcontrol *kcontrol,
 
        val0 = 79 - ucontrol->value.integer.value[0];
        val1 = 79 - ucontrol->value.integer.value[1];
+       if (val0 < 0 || val0 > 79 || val1 < 0 || val1 > 79)
+               return -EINVAL;
        if (val0 == pt->volume[base] && val1 == pt->volume[base + 1])
                return 0;
 
index 37c47fb95aca43fa63058143ee4edf7fffe7be79..87e3aefeddc39bf73f2b16465b71f5dc95d16795 100644 (file)
@@ -20,7 +20,6 @@
  *
  */      
 
-#include <sound/driver.h>
 #include <asm/io.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
@@ -159,6 +158,10 @@ static int snd_tea575x_ioctl(struct inode *inode, struct file *file,
                        struct video_audio v;
                        if(copy_from_user(&v, arg, sizeof(v))) 
                                return -EFAULT; 
+                       if (tea->ops->mute)
+                               tea->ops->mute(tea,
+                                              (v.flags &
+                                               VIDEO_AUDIO_MUTE) ? 1 : 0);
                        if(v.audio) 
                                return -EINVAL;
                        return 0;
@@ -206,6 +209,10 @@ void snd_tea575x_init(struct snd_tea575x *tea)
        tea->freq = 90500 * 16;         /* 90.5Mhz default */
 
        snd_tea575x_set_freq(tea);
+
+       /* mute on init */
+       if (tea->ops->mute)
+               tea->ops->mute(tea, 1);
 }
 
 void snd_tea575x_exit(struct snd_tea575x *tea)
index 9bab744af0ef9ea364695c280b161c53fe2c9a47..0e3a9f2c5297658dd001782734dad639e9daf811 100644 (file)
@@ -20,7 +20,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <sound/core.h>
index fc88a31da6f51a6730d75e6c2cd2e058ac5d1781..68f1260b5602ef119a5844618e5cac9c671673b0 100644 (file)
@@ -18,7 +18,6 @@
     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 */
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/time.h>
 #include <linux/wait.h>
@@ -61,20 +60,6 @@ module_param_array(id, charp, NULL, 0444);
 MODULE_PARM_DESC(id, "ID string for ad1816a based soundcard.");
 module_param_array(enable, bool, NULL, 0444);
 MODULE_PARM_DESC(enable, "Enable ad1816a based soundcard.");
-module_param_array(port, long, NULL, 0444);
-MODULE_PARM_DESC(port, "Port # for ad1816a driver.");
-module_param_array(mpu_port, long, NULL, 0444);
-MODULE_PARM_DESC(mpu_port, "MPU-401 port # for ad1816a driver.");
-module_param_array(fm_port, long, NULL, 0444);
-MODULE_PARM_DESC(fm_port, "FM port # for ad1816a driver.");
-module_param_array(irq, int, NULL, 0444);
-MODULE_PARM_DESC(irq, "IRQ # for ad1816a driver.");
-module_param_array(mpu_irq, int, NULL, 0444);
-MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ # for ad1816a driver.");
-module_param_array(dma1, int, NULL, 0444);
-MODULE_PARM_DESC(dma1, "1st DMA # for ad1816a driver.");
-module_param_array(dma2, int, NULL, 0444);
-MODULE_PARM_DESC(dma2, "2nd DMA # for ad1816a driver.");
 module_param_array(clockfreq, int, NULL, 0444);
 MODULE_PARM_DESC(clockfreq, "Clock frequency for ad1816a driver (default = 0).");
 
@@ -117,16 +102,12 @@ static int __devinit snd_card_ad1816a_pnp(int dev, struct snd_card_ad1816a *acar
                                          const struct pnp_card_device_id *id)
 {
        struct pnp_dev *pdev;
-       struct pnp_resource_table *cfg = kmalloc(sizeof(*cfg), GFP_KERNEL);
        int err;
 
-       if (!cfg)
-               return -ENOMEM;
        acard->dev = pnp_request_card_device(card, id->devs[0].id, NULL);
-       if (acard->dev == NULL) {
-               kfree(cfg);
+       if (acard->dev == NULL)
                return -EBUSY;
-       }
+
        acard->devmpu = pnp_request_card_device(card, id->devs[1].id, NULL);
        if (acard->devmpu == NULL) {
                mpu_port[dev] = -1;
@@ -134,25 +115,10 @@ static int __devinit snd_card_ad1816a_pnp(int dev, struct snd_card_ad1816a *acar
        }
 
        pdev = acard->dev;
-       pnp_init_resource_table(cfg);
-
-       if (port[dev] != SNDRV_AUTO_PORT)
-               pnp_resource_change(&cfg->port_resource[2], port[dev], 16);
-       if (fm_port[dev] != SNDRV_AUTO_PORT)
-               pnp_resource_change(&cfg->port_resource[1], fm_port[dev], 4);
-       if (dma1[dev] != SNDRV_AUTO_DMA)
-               pnp_resource_change(&cfg->dma_resource[0], dma1[dev], 1);
-       if (dma2[dev] != SNDRV_AUTO_DMA)
-               pnp_resource_change(&cfg->dma_resource[1], dma2[dev], 1);
-       if (irq[dev] != SNDRV_AUTO_IRQ)
-               pnp_resource_change(&cfg->irq_resource[0], irq[dev], 1);
-
-       if (pnp_manual_config_dev(pdev, cfg, 0) < 0)
-               snd_printk(KERN_ERR PFX "AUDIO the requested resources are invalid, using auto config\n");
+
        err = pnp_activate_dev(pdev);
        if (err < 0) {
                printk(KERN_ERR PFX "AUDIO PnP configure failure\n");
-               kfree(cfg);
                return -EBUSY;
        }
 
@@ -162,20 +128,11 @@ static int __devinit snd_card_ad1816a_pnp(int dev, struct snd_card_ad1816a *acar
        dma2[dev] = pnp_dma(pdev, 1);
        irq[dev] = pnp_irq(pdev, 0);
 
-       if (acard->devmpu == NULL) {
-               kfree(cfg);
+       if (acard->devmpu == NULL)
                return 0;
-       }
-       pdev = acard->devmpu;
-       pnp_init_resource_table(cfg);
 
-       if (mpu_port[dev] != SNDRV_AUTO_PORT)
-               pnp_resource_change(&cfg->port_resource[0], mpu_port[dev], 2);
-       if (mpu_irq[dev] != SNDRV_AUTO_IRQ)
-               pnp_resource_change(&cfg->irq_resource[0], mpu_irq[dev], 1);
+       pdev = acard->devmpu;
 
-       if (pnp_manual_config_dev(pdev, cfg, 0) < 0)
-               snd_printk(KERN_ERR PFX "AUDIO the requested resources are invalid, using auto config\n");
        err = pnp_activate_dev(pdev);
        if (err < 0) {
                printk(KERN_ERR PFX "MPU401 PnP configure failure\n");
@@ -186,7 +143,6 @@ static int __devinit snd_card_ad1816a_pnp(int dev, struct snd_card_ad1816a *acar
                mpu_irq[dev] = pnp_irq(pdev, 0);
        }
 
-       kfree(cfg);
        return 0;
 }
 
index cf18fe4617a1e1f23848eed4965ce67a7d1b4b6b..4b8dfe2e3dcb69df0767b43df62ef2b9cf0d44a9 100644 (file)
@@ -17,7 +17,6 @@
     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 */
 
-#include <sound/driver.h>
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
index a4710b5e214c339f6549acddc739393dffc963cb..5f5271efdc59fe524b2510ba30ed9b4c83091f8a 100644 (file)
@@ -21,7 +21,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/err.h>
 #include <linux/isa.h>
index a901cd1ee692474316cd7bf5ff34d926e3578a83..630c90f9ee5091ccf01108f7b7a09aed5e77930d 100644 (file)
@@ -20,7 +20,6 @@
  */
 
 #define SNDRV_MAIN_OBJECT_FILE
-#include <sound/driver.h>
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
@@ -213,7 +212,7 @@ static void snd_ad1848_mce_down(struct snd_ad1848 *chip)
        for (timeout = 12000; timeout > 0 && (inb(AD1848P(chip, REGSEL)) & AD1848_INIT); timeout--)
                udelay(100);
 
-       snd_printdd("(1) timeout = %d\n", timeout);
+       snd_printdd("(1) timeout = %ld\n", timeout);
 
 #ifdef CONFIG_SND_DEBUG
        if (inb(AD1848P(chip, REGSEL)) & AD1848_INIT)
index d68720724c91903cd593452e74c81029d6097317..efa8c80d05b69eecc9b03795e609b60b497bd77a 100644 (file)
@@ -2,7 +2,6 @@
  * AdLib FM card driver.
  */
 
-#include <sound/driver.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/isa.h>
index f2bcfb2cf5f576bae36135c33524ba2d1d3fd40e..f1ce30f379c9d5fa06ef68b62b5643b08596871c 100644 (file)
@@ -20,7 +20,6 @@
     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 */
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/wait.h>
 #include <linux/time.h>
@@ -63,20 +62,6 @@ module_param_array(id, charp, NULL, 0444);
 MODULE_PARM_DESC(id, "ID string for als100 based soundcard.");
 module_param_array(enable, bool, NULL, 0444);
 MODULE_PARM_DESC(enable, "Enable als100 based soundcard.");
-module_param_array(port, long, NULL, 0444);
-MODULE_PARM_DESC(port, "Port # for als100 driver.");
-module_param_array(mpu_port, long, NULL, 0444);
-MODULE_PARM_DESC(mpu_port, "MPU-401 port # for als100 driver.");
-module_param_array(fm_port, long, NULL, 0444);
-MODULE_PARM_DESC(fm_port, "FM port # for als100 driver.");
-module_param_array(irq, int, NULL, 0444);
-MODULE_PARM_DESC(irq, "IRQ # for als100 driver.");
-module_param_array(mpu_irq, int, NULL, 0444);
-MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ # for als100 driver.");
-module_param_array(dma8, int, NULL, 0444);
-MODULE_PARM_DESC(dma8, "8-bit DMA # for als100 driver.");
-module_param_array(dma16, int, NULL, 0444);
-MODULE_PARM_DESC(dma16, "16-bit DMA # for als100 driver.");
 
 struct snd_card_als100 {
        int dev_no;
@@ -111,38 +96,20 @@ static int __devinit snd_card_als100_pnp(int dev, struct snd_card_als100 *acard,
                                         const struct pnp_card_device_id *id)
 {
        struct pnp_dev *pdev;
-       struct pnp_resource_table *cfg = kmalloc(sizeof(*cfg), GFP_KERNEL);
        int err;
 
-       if (!cfg)
-               return -ENOMEM;
        acard->dev = pnp_request_card_device(card, id->devs[0].id, NULL);
-       if (acard->dev == NULL) {
-               kfree(cfg);
+       if (acard->dev == NULL)
                return -ENODEV;
-       }
+
        acard->devmpu = pnp_request_card_device(card, id->devs[1].id, acard->dev);
        acard->devopl = pnp_request_card_device(card, id->devs[2].id, acard->dev);
 
        pdev = acard->dev;
 
-       pnp_init_resource_table(cfg);
-
-       /* override resources */
-       if (port[dev] != SNDRV_AUTO_PORT)
-               pnp_resource_change(&cfg->port_resource[0], port[dev], 16);
-       if (dma8[dev] != SNDRV_AUTO_DMA)
-               pnp_resource_change(&cfg->dma_resource[0], dma8[dev], 1);
-       if (dma16[dev] != SNDRV_AUTO_DMA)
-               pnp_resource_change(&cfg->dma_resource[1], dma16[dev], 1);
-       if (irq[dev] != SNDRV_AUTO_IRQ)
-               pnp_resource_change(&cfg->irq_resource[0], irq[dev], 1);
-       if (pnp_manual_config_dev(pdev, cfg, 0) < 0)
-               snd_printk(KERN_ERR PFX "AUDIO the requested resources are invalid, using auto config\n");
        err = pnp_activate_dev(pdev);
        if (err < 0) {
                snd_printk(KERN_ERR PFX "AUDIO pnp configure failure\n");
-               kfree(cfg);
                return err;
        }
        port[dev] = pnp_port_start(pdev, 0);
@@ -152,13 +119,6 @@ static int __devinit snd_card_als100_pnp(int dev, struct snd_card_als100 *acard,
 
        pdev = acard->devmpu;
        if (pdev != NULL) {
-               pnp_init_resource_table(cfg);
-               if (mpu_port[dev] != SNDRV_AUTO_PORT)
-                       pnp_resource_change(&cfg->port_resource[0], mpu_port[dev], 2);
-               if (mpu_irq[dev] != SNDRV_AUTO_IRQ)
-                       pnp_resource_change(&cfg->irq_resource[0], mpu_irq[dev], 1);
-               if ((pnp_manual_config_dev(pdev, cfg, 0)) < 0)
-                       snd_printk(KERN_ERR PFX "MPU401 the requested resources are invalid, using auto config\n");
                err = pnp_activate_dev(pdev);
                if (err < 0)
                        goto __mpu_error;
@@ -176,11 +136,6 @@ static int __devinit snd_card_als100_pnp(int dev, struct snd_card_als100 *acard,
 
        pdev = acard->devopl;
        if (pdev != NULL) {
-               pnp_init_resource_table(cfg);
-               if (fm_port[dev] != SNDRV_AUTO_PORT)
-                       pnp_resource_change(&cfg->port_resource[0], fm_port[dev], 4);
-               if ((pnp_manual_config_dev(pdev, cfg, 0)) < 0)
-                       snd_printk(KERN_ERR PFX "OPL3 the requested resources are invalid, using auto config\n");
                err = pnp_activate_dev(pdev);
                if (err < 0)
                        goto __fm_error;
@@ -195,7 +150,6 @@ static int __devinit snd_card_als100_pnp(int dev, struct snd_card_als100 *acard,
                fm_port[dev] = -1;
        }
 
-       kfree(cfg);
        return 0;
 }
 
index b615538a928d6e5570a480fd628e210c244bf044..154e728f592d0f7cd8aa523025e01aa5e0d7b7c5 100644 (file)
@@ -29,7 +29,6 @@
     activation method (full-duplex audio!).
 */
 
-#include <sound/driver.h>
 #include <asm/io.h>
 #include <linux/delay.h>
 #include <linux/init.h>
@@ -72,22 +71,6 @@ module_param_array(id, charp, NULL, 0444);
 MODULE_PARM_DESC(id, "ID string for azt2320 based soundcard.");
 module_param_array(enable, bool, NULL, 0444);
 MODULE_PARM_DESC(enable, "Enable azt2320 based soundcard.");
-module_param_array(port, long, NULL, 0444);
-MODULE_PARM_DESC(port, "Port # for azt2320 driver.");
-module_param_array(wss_port, long, NULL, 0444);
-MODULE_PARM_DESC(wss_port, "WSS Port # for azt2320 driver.");
-module_param_array(mpu_port, long, NULL, 0444);
-MODULE_PARM_DESC(mpu_port, "MPU-401 port # for azt2320 driver.");
-module_param_array(fm_port, long, NULL, 0444);
-MODULE_PARM_DESC(fm_port, "FM port # for azt2320 driver.");
-module_param_array(irq, int, NULL, 0444);
-MODULE_PARM_DESC(irq, "IRQ # for azt2320 driver.");
-module_param_array(mpu_irq, int, NULL, 0444);
-MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ # for azt2320 driver.");
-module_param_array(dma1, int, NULL, 0444);
-MODULE_PARM_DESC(dma1, "1st DMA # for azt2320 driver.");
-module_param_array(dma2, int, NULL, 0444);
-MODULE_PARM_DESC(dma2, "2nd DMA # for azt2320 driver.");
 
 struct snd_card_azt2320 {
        int dev_no;
@@ -121,43 +104,19 @@ static int __devinit snd_card_azt2320_pnp(int dev, struct snd_card_azt2320 *acar
                                          const struct pnp_card_device_id *id)
 {
        struct pnp_dev *pdev;
-       struct pnp_resource_table * cfg = kmalloc(sizeof(struct pnp_resource_table), GFP_KERNEL);
        int err;
 
-       if (!cfg)
-               return -ENOMEM;
-
        acard->dev = pnp_request_card_device(card, id->devs[0].id, NULL);
-       if (acard->dev == NULL) {
-               kfree(cfg);
+       if (acard->dev == NULL)
                return -ENODEV;
-       }
 
        acard->devmpu = pnp_request_card_device(card, id->devs[1].id, NULL);
 
        pdev = acard->dev;
-       pnp_init_resource_table(cfg);
-
-       /* override resources */
-       if (port[dev] != SNDRV_AUTO_PORT)
-               pnp_resource_change(&cfg->port_resource[0], port[dev], 16);
-       if (fm_port[dev] != SNDRV_AUTO_PORT)
-               pnp_resource_change(&cfg->port_resource[1], fm_port[dev], 4);
-       if (wss_port[dev] != SNDRV_AUTO_PORT)
-               pnp_resource_change(&cfg->port_resource[2], wss_port[dev], 4);
-       if (dma1[dev] != SNDRV_AUTO_DMA)
-               pnp_resource_change(&cfg->dma_resource[0], dma1[dev], 1);
-       if (dma2[dev] != SNDRV_AUTO_DMA)
-               pnp_resource_change(&cfg->dma_resource[1], dma2[dev], 1);
-       if (irq[dev] != SNDRV_AUTO_IRQ)
-               pnp_resource_change(&cfg->irq_resource[0], irq[dev], 1);
-       if ((pnp_manual_config_dev(pdev, cfg, 0)) < 0)
-               snd_printk(KERN_ERR PFX "AUDIO the requested resources are invalid, using auto config\n");
 
        err = pnp_activate_dev(pdev);
        if (err < 0) {
                snd_printk(KERN_ERR PFX "AUDIO pnp configure failure\n");
-               kfree(cfg);
                return err;
        }
        port[dev] = pnp_port_start(pdev, 0);
@@ -169,13 +128,6 @@ static int __devinit snd_card_azt2320_pnp(int dev, struct snd_card_azt2320 *acar
 
        pdev = acard->devmpu;
        if (pdev != NULL) {
-               pnp_init_resource_table(cfg);
-               if (mpu_port[dev] != SNDRV_AUTO_PORT)
-                       pnp_resource_change(&cfg->port_resource[0], mpu_port[dev], 2);
-               if (mpu_irq[dev] != SNDRV_AUTO_IRQ)
-                       pnp_resource_change(&cfg->irq_resource[0], mpu_irq[dev], 1);
-               if ((pnp_manual_config_dev(pdev, cfg, 0)) < 0)
-                       snd_printk(KERN_ERR PFX "MPU401 the requested resources are invalid, using auto config\n");
                err = pnp_activate_dev(pdev);
                if (err < 0)
                        goto __mpu_error;
@@ -191,7 +143,6 @@ static int __devinit snd_card_azt2320_pnp(int dev, struct snd_card_azt2320 *acar
                mpu_port[dev] = -1;
        }
 
-       kfree (cfg);
        return 0;
 }
 
index f471f8ad68852d1dbbe09b684668be39a8511cbd..4d198ec71e9b410aad2100e189c3293453d3129c 100644 (file)
@@ -43,7 +43,6 @@
  *  full control over both mixers.
  */
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/err.h>
 #include <linux/isa.h>
@@ -286,39 +285,21 @@ static int __devinit snd_cmi8330_pnp(int dev, struct snd_cmi8330 *acard,
                                     const struct pnp_card_device_id *id)
 {
        struct pnp_dev *pdev;
-       struct pnp_resource_table * cfg = kmalloc(sizeof(struct pnp_resource_table), GFP_KERNEL);
        int err;
 
-       if (!cfg)
-               return -ENOMEM;
        acard->cap = pnp_request_card_device(card, id->devs[0].id, NULL);
-       if (acard->cap == NULL) {
-               kfree(cfg);
+       if (acard->cap == NULL)
                return -EBUSY;
-       }
+
        acard->play = pnp_request_card_device(card, id->devs[1].id, NULL);
-       if (acard->play == NULL) {
-               kfree(cfg);
+       if (acard->play == NULL)
                return -EBUSY;
-       }
 
        pdev = acard->cap;
-       pnp_init_resource_table(cfg);
-       /* allocate AD1848 resources */
-       if (wssport[dev] != SNDRV_AUTO_PORT)
-               pnp_resource_change(&cfg->port_resource[0], wssport[dev], 8);
-       if (wssdma[dev] != SNDRV_AUTO_DMA)
-               pnp_resource_change(&cfg->dma_resource[0], wssdma[dev], 1);
-       if (wssirq[dev] != SNDRV_AUTO_IRQ)
-               pnp_resource_change(&cfg->irq_resource[0], wssirq[dev], 1);
-
-       err = pnp_manual_config_dev(pdev, cfg, 0);
-       if (err < 0)
-               snd_printk(KERN_ERR "CMI8330/C3D (AD1848) PnP manual resources are invalid, using auto config\n");
+
        err = pnp_activate_dev(pdev);
        if (err < 0) {
                snd_printk(KERN_ERR "CMI8330/C3D (AD1848) PnP configure failure\n");
-               kfree(cfg);
                return -EBUSY;
        }
        wssport[dev] = pnp_port_start(pdev, 0);
@@ -327,23 +308,10 @@ static int __devinit snd_cmi8330_pnp(int dev, struct snd_cmi8330 *acard,
 
        /* allocate SB16 resources */
        pdev = acard->play;
-       pnp_init_resource_table(cfg);
-       if (sbport[dev] != SNDRV_AUTO_PORT)
-               pnp_resource_change(&cfg->port_resource[0], sbport[dev], 16);
-       if (sbdma8[dev] != SNDRV_AUTO_DMA)
-               pnp_resource_change(&cfg->dma_resource[0], sbdma8[dev], 1);
-       if (sbdma16[dev] != SNDRV_AUTO_DMA)
-               pnp_resource_change(&cfg->dma_resource[1], sbdma16[dev], 1);
-       if (sbirq[dev] != SNDRV_AUTO_IRQ)
-               pnp_resource_change(&cfg->irq_resource[0], sbirq[dev], 1);
-
-       err = pnp_manual_config_dev(pdev, cfg, 0);
-       if (err < 0)
-               snd_printk(KERN_ERR "CMI8330/C3D (SB16) PnP manual resources are invalid, using auto config\n");
+
        err = pnp_activate_dev(pdev);
        if (err < 0) {
                snd_printk(KERN_ERR "CMI8330/C3D (SB16) PnP configure failure\n");
-               kfree(cfg);
                return -EBUSY;
        }
        sbport[dev] = pnp_port_start(pdev, 0);
@@ -351,7 +319,6 @@ static int __devinit snd_cmi8330_pnp(int dev, struct snd_cmi8330 *acard,
        sbdma16[dev] = pnp_dma(pdev, 1);
        sbirq[dev] = pnp_irq(pdev, 0);
 
-       kfree(cfg);
        return 0;
 }
 #endif
index 13db6842eaaae188b2d560bdea162f6270d5c9a7..e9462b9944be1c8b7ee3e987ca50d01134d056ee 100644 (file)
@@ -20,7 +20,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/err.h>
 #include <linux/isa.h>
index a5eb9659b519ca8003034651654d9bef5bb98af9..0aa8649e5c7f897b1c5fb283b69dcd5df5f56cfc 100644 (file)
@@ -24,7 +24,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/delay.h>
 #include <linux/pm.h>
 #include <linux/init.h>
@@ -333,7 +332,6 @@ void snd_cs4231_mce_down(struct snd_cs4231 *chip)
            !(chip->hardware & (CS4231_HW_CS4231_MASK | CS4231_HW_CS4232_MASK))) {
                return;
        }
-       snd_cs4231_busy_wait(chip);
 
        /*
         * Wait for (possible -- during init auto-calibration may not be set)
index 5784b43f4123399edacd05f707ede5b5f77b994b..dbe63db4bfd654cfb656aee997d873353374c02b 100644 (file)
@@ -19,7 +19,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/err.h>
 #include <linux/isa.h>
@@ -270,29 +269,9 @@ static struct pnp_card_device_id snd_cs423x_pnpids[] = {
 MODULE_DEVICE_TABLE(pnp_card, snd_cs423x_pnpids);
 
 /* WSS initialization */
-static int __devinit snd_cs423x_pnp_init_wss(int dev, struct pnp_dev *pdev,
-                                            struct pnp_resource_table *cfg)
+static int __devinit snd_cs423x_pnp_init_wss(int dev, struct pnp_dev *pdev)
 {
-       int err;
-
-       pnp_init_resource_table(cfg);
-       if (port[dev] != SNDRV_AUTO_PORT)
-               pnp_resource_change(&cfg->port_resource[0], port[dev], 4);
-       if (fm_port[dev] != SNDRV_AUTO_PORT && fm_port[dev] > 0)
-               pnp_resource_change(&cfg->port_resource[1], fm_port[dev], 4);
-       if (sb_port[dev] != SNDRV_AUTO_PORT)
-               pnp_resource_change(&cfg->port_resource[2], sb_port[dev], 16);
-       if (irq[dev] != SNDRV_AUTO_IRQ)
-               pnp_resource_change(&cfg->irq_resource[0], irq[dev], 1);
-       if (dma1[dev] != SNDRV_AUTO_DMA)
-               pnp_resource_change(&cfg->dma_resource[0], dma1[dev], 1);
-       if (dma2[dev] != SNDRV_AUTO_DMA)
-               pnp_resource_change(&cfg->dma_resource[1], dma2[dev] < 0 ? 4 : dma2[dev], 1);
-       err = pnp_manual_config_dev(pdev, cfg, 0);
-       if (err < 0)
-               snd_printk(KERN_ERR IDENT " WSS PnP manual resources are invalid, using auto config\n");
-       err = pnp_activate_dev(pdev);
-       if (err < 0) {
+       if (pnp_activate_dev(pdev) < 0) {
                printk(KERN_ERR IDENT " WSS PnP configure failed for WSS (out of resources?)\n");
                return -EBUSY;
        }
@@ -311,19 +290,9 @@ static int __devinit snd_cs423x_pnp_init_wss(int dev, struct pnp_dev *pdev,
 }
 
 /* CTRL initialization */
-static int __devinit snd_cs423x_pnp_init_ctrl(int dev, struct pnp_dev *pdev,
-                                             struct pnp_resource_table *cfg)
+static int __devinit snd_cs423x_pnp_init_ctrl(int dev, struct pnp_dev *pdev)
 {
-       int err;
-
-       pnp_init_resource_table(cfg);
-       if (cport[dev] != SNDRV_AUTO_PORT)
-               pnp_resource_change(&cfg->port_resource[0], cport[dev], 8);
-       err = pnp_manual_config_dev(pdev, cfg, 0);
-       if (err < 0)
-               snd_printk(KERN_ERR IDENT " CTRL PnP manual resources are invalid, using auto config\n");
-       err = pnp_activate_dev(pdev);
-       if (err < 0) {
+       if (pnp_activate_dev(pdev) < 0) {
                printk(KERN_ERR IDENT " CTRL PnP configure failed for WSS (out of resources?)\n");
                return -EBUSY;
        }
@@ -333,21 +302,9 @@ static int __devinit snd_cs423x_pnp_init_ctrl(int dev, struct pnp_dev *pdev,
 }
 
 /* MPU initialization */
-static int __devinit snd_cs423x_pnp_init_mpu(int dev, struct pnp_dev *pdev,
-                                            struct pnp_resource_table *cfg)
+static int __devinit snd_cs423x_pnp_init_mpu(int dev, struct pnp_dev *pdev)
 {
-       int err;
-
-       pnp_init_resource_table(cfg);
-       if (mpu_port[dev] != SNDRV_AUTO_PORT)
-               pnp_resource_change(&cfg->port_resource[0], mpu_port[dev], 2);
-       if (mpu_irq[dev] != SNDRV_AUTO_IRQ && mpu_irq[dev] >= 0)
-               pnp_resource_change(&cfg->irq_resource[0], mpu_irq[dev], 1);
-       err = pnp_manual_config_dev(pdev, cfg, 0);
-       if (err < 0)
-               snd_printk(KERN_ERR IDENT " MPU401 PnP manual resources are invalid, using auto config\n");
-       err = pnp_activate_dev(pdev);
-       if (err < 0) {
+       if (pnp_activate_dev(pdev) < 0) {
                printk(KERN_ERR IDENT " MPU401 PnP configure failed for WSS (out of resources?)\n");
                mpu_port[dev] = SNDRV_AUTO_PORT;
                mpu_irq[dev] = SNDRV_AUTO_IRQ;
@@ -368,15 +325,8 @@ static int __devinit snd_cs423x_pnp_init_mpu(int dev, struct pnp_dev *pdev,
 static int __devinit snd_card_cs4232_pnp(int dev, struct snd_card_cs4236 *acard,
                                         struct pnp_dev *pdev)
 {
-       struct pnp_resource_table *cfg = kmalloc(sizeof(*cfg), GFP_KERNEL);
-
-       if (!cfg)
-               return -ENOMEM;
-       if (snd_cs423x_pnp_init_wss(dev, acard->wss, cfg) < 0) {
-               kfree(cfg);
+       if (snd_cs423x_pnp_init_wss(dev, acard->wss) < 0)
                return -EBUSY;
-       }
-       kfree(cfg);
        cport[dev] = -1;
        return 0;
 }
@@ -386,43 +336,33 @@ static int __devinit snd_card_cs423x_pnpc(int dev, struct snd_card_cs4236 *acard
                                          struct pnp_card_link *card,
                                          const struct pnp_card_device_id *id)
 {
-       struct pnp_resource_table *cfg = kmalloc(sizeof(*cfg), GFP_KERNEL);
-
-       if (!cfg)
-               return -ENOMEM;
-
        acard->wss = pnp_request_card_device(card, id->devs[0].id, NULL);
        if (acard->wss == NULL)
-               goto error;
+               return -EBUSY;
        acard->ctrl = pnp_request_card_device(card, id->devs[1].id, NULL);
        if (acard->ctrl == NULL)
-               goto error;
+               return -EBUSY;
        if (id->devs[2].id[0]) {
                acard->mpu = pnp_request_card_device(card, id->devs[2].id, NULL);
                if (acard->mpu == NULL)
-                       goto error;
+                       return -EBUSY;
        }
 
        /* WSS initialization */
-       if (snd_cs423x_pnp_init_wss(dev, acard->wss, cfg) < 0)
-               goto error;
+       if (snd_cs423x_pnp_init_wss(dev, acard->wss) < 0)
+               return -EBUSY;
 
        /* CTRL initialization */
        if (acard->ctrl && cport[dev] > 0) {
-               if (snd_cs423x_pnp_init_ctrl(dev, acard->ctrl, cfg) < 0)
-                       goto error;
+               if (snd_cs423x_pnp_init_ctrl(dev, acard->ctrl) < 0)
+                       return -EBUSY;
        }
        /* MPU initialization */
        if (acard->mpu && mpu_port[dev] > 0) {
-               if (snd_cs423x_pnp_init_mpu(dev, acard->mpu, cfg) < 0)
-                       goto error;
+               if (snd_cs423x_pnp_init_mpu(dev, acard->mpu) < 0)
+                       return -EBUSY;
        }
-       kfree(cfg);
        return 0;
-
- error:
-       kfree(cfg);
-       return -EBUSY;
 }
 #endif /* CONFIG_PNP */
 
index 6bd064470d4cfe576535b9d7e1bf9fd822ffadd7..de71910401ea531efd514b881fe4a6a2744c3583 100644 (file)
@@ -79,7 +79,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <asm/io.h>
 #include <linux/delay.h>
 #include <linux/init.h>
index ce57d526f7bc3e5b8fc6608c83d97ff248a99f71..a0242c3b613ef2a22dabb34531724883cc62e529 100644 (file)
@@ -21,7 +21,6 @@
     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 */
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/wait.h>
 #include <linux/pnp.h>
@@ -56,18 +55,6 @@ module_param_array(id, charp, NULL, 0444);
 MODULE_PARM_DESC(id, "ID string for DT-019X based soundcard.");
 module_param_array(enable, bool, NULL, 0444);
 MODULE_PARM_DESC(enable, "Enable DT-019X based soundcard.");
-module_param_array(port, long, NULL, 0444);
-MODULE_PARM_DESC(port, "Port # for dt019x driver.");
-module_param_array(mpu_port, long, NULL, 0444);
-MODULE_PARM_DESC(mpu_port, "MPU-401 port # for dt019x driver.");
-module_param_array(fm_port, long, NULL, 0444);
-MODULE_PARM_DESC(fm_port, "FM port # for dt019x driver.");
-module_param_array(irq, int, NULL, 0444);
-MODULE_PARM_DESC(irq, "IRQ # for dt019x driver.");
-module_param_array(mpu_irq, int, NULL, 0444);
-MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ # for dt019x driver.");
-module_param_array(dma8, int, NULL, 0444);
-MODULE_PARM_DESC(dma8, "8-bit DMA # for dt019x driver.");
 
 struct snd_card_dt019x {
        struct pnp_dev *dev;
@@ -95,36 +82,20 @@ static int __devinit snd_card_dt019x_pnp(int dev, struct snd_card_dt019x *acard,
                                         const struct pnp_card_device_id *pid)
 {
        struct pnp_dev *pdev;
-       struct pnp_resource_table * cfg = kmalloc(sizeof(struct pnp_resource_table), GFP_KERNEL);
        int err;
 
-       if (!cfg)
-               return -ENOMEM;
-
        acard->dev = pnp_request_card_device(card, pid->devs[0].id, NULL);
-       if (acard->dev == NULL) {
-               kfree (cfg);
+       if (acard->dev == NULL)
                return -ENODEV;
-       }
+
        acard->devmpu = pnp_request_card_device(card, pid->devs[1].id, NULL);
        acard->devopl = pnp_request_card_device(card, pid->devs[2].id, NULL);
 
        pdev = acard->dev;
-       pnp_init_resource_table(cfg);
-
-       if (port[dev] != SNDRV_AUTO_PORT)
-               pnp_resource_change(&cfg->port_resource[0], port[dev], 16);
-       if (dma8[dev] != SNDRV_AUTO_DMA)
-               pnp_resource_change(&cfg->dma_resource[0], dma8[dev], 1);
-       if (irq[dev] != SNDRV_AUTO_IRQ)
-               pnp_resource_change(&cfg->irq_resource[0], irq[dev], 1);
 
-       if ((pnp_manual_config_dev(pdev, cfg, 0)) < 0)
-               snd_printk(KERN_ERR PFX "DT-019X AUDIO the requested resources are invalid, using auto config\n");
        err = pnp_activate_dev(pdev);
        if (err < 0) {
                snd_printk(KERN_ERR PFX "DT-019X AUDIO pnp configure failure\n");
-               kfree(cfg);
                return err;
        }
 
@@ -135,15 +106,7 @@ static int __devinit snd_card_dt019x_pnp(int dev, struct snd_card_dt019x *acard,
                        port[dev],irq[dev],dma8[dev]);
 
        pdev = acard->devmpu;
-
        if (pdev != NULL) {
-               pnp_init_resource_table(cfg);
-               if (mpu_port[dev] != SNDRV_AUTO_PORT)
-                       pnp_resource_change(&cfg->port_resource[0], mpu_port[dev], 2);
-               if (mpu_irq[dev] != SNDRV_AUTO_IRQ)
-                       pnp_resource_change(&cfg->irq_resource[0], mpu_irq[dev], 1);
-               if ((pnp_manual_config_dev(pdev, cfg, 0)) < 0)
-                       snd_printk(KERN_ERR PFX "DT-019X MPU401 the requested resources are invalid, using auto config\n");
                err = pnp_activate_dev(pdev);
                if (err < 0) {
                        pnp_release_card_device(pdev);
@@ -162,11 +125,6 @@ static int __devinit snd_card_dt019x_pnp(int dev, struct snd_card_dt019x *acard,
 
        pdev = acard->devopl;
        if (pdev != NULL) {
-               pnp_init_resource_table(cfg);
-               if (fm_port[dev] != SNDRV_AUTO_PORT)
-                       pnp_resource_change(&cfg->port_resource[0], fm_port[dev], 4);
-               if ((pnp_manual_config_dev(pdev, cfg, 0)) < 0)
-                       snd_printk(KERN_ERR PFX "DT-019X OPL3 the requested resources are invalid, using auto config\n");
                err = pnp_activate_dev(pdev);
                if (err < 0) {
                        pnp_release_card_device(pdev);
@@ -181,7 +139,6 @@ static int __devinit snd_card_dt019x_pnp(int dev, struct snd_card_dt019x *acard,
                fm_port[dev] = -1;
        }
 
-       kfree(cfg);
        return 0;
 }
 
index 74bbc92f2e7ce359b56b967faeb0da1d8f701ea9..f88639ea64b214ddd976ef6577eab8100f2741f4 100644 (file)
@@ -19,7 +19,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/err.h>
 #include <linux/isa.h>
index 5c26d495daa8b69476fb7895e6aec39408982d39..1e1e575b1db329f87b289cb4cc57bbb954f1bae0 100644 (file)
@@ -19,7 +19,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
index c1af28fd4a1fcf7fb961993ca4c74260d3e9fb26..90498e4ca2601f3c82005a4de4eaafd5e857d935 100644 (file)
@@ -77,7 +77,6 @@
  *   needed for ZV, so maybe the datasheet is entirely wrong here.
  */
  
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/err.h>
 #include <linux/isa.h>
@@ -163,7 +162,7 @@ struct snd_audiodrive {
 #define ES18XX_DUPLEX_SAME 0x0010      /* Playback and record must share the same rate */
 #define ES18XX_NEW_RATE        0x0020  /* More precise rate setting */
 #define ES18XX_AUXB    0x0040  /* AuxB mixer control */
-#define ES18XX_HWV     0x0080  /* Has seperate hardware volume mixer controls*/
+#define ES18XX_HWV     0x0080  /* Has separate hardware volume mixer controls*/
 #define ES18XX_MONO    0x0100  /* Mono_in mixer control */
 #define ES18XX_I2S     0x0200  /* I2S mixer control */
 #define ES18XX_MUTEREC 0x0400  /* Record source can be muted */
@@ -1442,6 +1441,8 @@ static int __devinit snd_es18xx_initialize(struct snd_es18xx *chip)
                snd_es18xx_write(chip, 0xB2, 0x50);
                /* Enable MPU and hardware volume interrupt */
                snd_es18xx_mixer_write(chip, 0x64, 0x42);
+               /* Enable ESS wavetable input */
+               snd_es18xx_mixer_bits(chip, 0x48, 0x10, 0x10);
        }
        else {
                int irqmask, dma1mask, dma2mask;
@@ -2035,31 +2036,9 @@ static struct pnp_device_id snd_audiodrive_pnpbiosids[] = {
 MODULE_DEVICE_TABLE(pnp, snd_audiodrive_pnpbiosids);
 
 /* PnP main device initialization */
-static int __devinit snd_audiodrive_pnp_init_main(int dev, struct pnp_dev *pdev,
-                                                 struct pnp_resource_table *cfg)
+static int __devinit snd_audiodrive_pnp_init_main(int dev, struct pnp_dev *pdev)
 {
-       int err;
-
-       pnp_init_resource_table(cfg);
-       if (port[dev] != SNDRV_AUTO_PORT)
-               pnp_resource_change(&cfg->port_resource[0], port[dev], 16);
-       if (fm_port[dev] != SNDRV_AUTO_PORT)
-               pnp_resource_change(&cfg->port_resource[1], fm_port[dev], 4);
-       if (mpu_port[dev] != SNDRV_AUTO_PORT)
-               pnp_resource_change(&cfg->port_resource[2], mpu_port[dev], 2);
-       if (dma1[dev] != SNDRV_AUTO_DMA)
-               pnp_resource_change(&cfg->dma_resource[0], dma1[dev], 1);
-       if (dma2[dev] != SNDRV_AUTO_DMA)
-               pnp_resource_change(&cfg->dma_resource[1], dma2[dev], 1);
-       if (irq[dev] != SNDRV_AUTO_IRQ)
-               pnp_resource_change(&cfg->irq_resource[0], irq[dev], 1);
-       if (pnp_device_is_isapnp(pdev)) {
-               err = pnp_manual_config_dev(pdev, cfg, 0);
-               if (err < 0)
-                       snd_printk(KERN_ERR PFX "PnP manual resources are invalid, using auto config\n");
-       }
-       err = pnp_activate_dev(pdev);
-       if (err < 0) {
+       if (pnp_activate_dev(pdev) < 0) {
                snd_printk(KERN_ERR PFX "PnP configure failure (out of resources?)\n");
                return -EBUSY;
        }
@@ -2087,16 +2066,9 @@ static int __devinit snd_audiodrive_pnp_init_main(int dev, struct pnp_dev *pdev,
 static int __devinit snd_audiodrive_pnp(int dev, struct snd_audiodrive *acard,
                                        struct pnp_dev *pdev)
 {
-       struct pnp_resource_table * cfg = kmalloc(sizeof(struct pnp_resource_table), GFP_KERNEL);
-
-       if (!cfg)
-               return -ENOMEM;
        acard->dev = pdev;
-       if (snd_audiodrive_pnp_init_main(dev, acard->dev, cfg) < 0) {
-               kfree(cfg);
+       if (snd_audiodrive_pnp_init_main(dev, acard->dev) < 0)
                return -EBUSY;
-       }
-       kfree(cfg);
        return 0;
 }
 
@@ -2125,33 +2097,24 @@ static int __devinit snd_audiodrive_pnpc(int dev, struct snd_audiodrive *acard,
                                        struct pnp_card_link *card,
                                        const struct pnp_card_device_id *id)
 {
-       struct pnp_resource_table * cfg = kmalloc(sizeof(struct pnp_resource_table), GFP_KERNEL);
-
-       if (!cfg)
-               return -ENOMEM;
        acard->dev = pnp_request_card_device(card, id->devs[0].id, NULL);
-       if (acard->dev == NULL) {
-               kfree(cfg);
+       if (acard->dev == NULL)
                return -EBUSY;
-       }
+
        acard->devc = pnp_request_card_device(card, id->devs[1].id, NULL);
-       if (acard->devc == NULL) {
-               kfree(cfg);
+       if (acard->devc == NULL)
                return -EBUSY;
-       }
+
        /* Control port initialization */
        if (pnp_activate_dev(acard->devc) < 0) {
-               kfree(cfg);
                snd_printk(KERN_ERR PFX "PnP control configure failure (out of resources?)\n");
                return -EAGAIN;
        }
        snd_printdd("pnp: port=0x%llx\n",
                        (unsigned long long)pnp_port_start(acard->devc, 0));
-       if (snd_audiodrive_pnp_init_main(dev, acard->dev, cfg) < 0) {
-               kfree(cfg);
+       if (snd_audiodrive_pnp_init_main(dev, acard->dev) < 0)
                return -EBUSY;
-       }
-       kfree(cfg);
+
        return 0;
 }
 #endif /* CONFIG_PNP */
index df3d59f25f5e633cea533788d867ea5ee6b5ec49..6cd4ee03754a1c1f9488eca10978dbd4f37f0efd 100644 (file)
@@ -9,7 +9,6 @@ snd-gus-lib-objs := gus_main.o \
                    gus_pcm.o gus_mixer.o \
                    gus_uart.o \
                    gus_reset.o
-snd-gus-synth-objs := gus_synth.o gus_sample.o gus_simple.o gus_instr.o
 
 snd-gusclassic-objs := gusclassic.o
 snd-gusextreme-objs := gusextreme.o
@@ -17,20 +16,9 @@ snd-gusmax-objs := gusmax.o
 snd-interwave-objs := interwave.o
 snd-interwave-stb-objs := interwave-stb.o
 
-#
-# this function returns:
-#   "m" - CONFIG_SND_SEQUENCER is m
-#   <empty string> - CONFIG_SND_SEQUENCER is undefined
-#   otherwise parameter #1 value
-#
-sequencer = $(if $(subst y,,$(CONFIG_SND_SEQUENCER)),$(if $(1),m),$(if $(CONFIG_SND_SEQUENCER),$(1)))
-
 # Toplevel Module Dependency
 obj-$(CONFIG_SND_GUSCLASSIC) += snd-gusclassic.o snd-gus-lib.o
 obj-$(CONFIG_SND_GUSMAX) += snd-gusmax.o snd-gus-lib.o
 obj-$(CONFIG_SND_GUSEXTREME) += snd-gusextreme.o snd-gus-lib.o
 obj-$(CONFIG_SND_INTERWAVE) += snd-interwave.o snd-gus-lib.o
 obj-$(CONFIG_SND_INTERWAVE_STB) += snd-interwave-stb.o snd-gus-lib.o
-obj-$(call sequencer,$(CONFIG_SND_GUS_SYNTH)) += snd-gus-synth.o
-
-obj-m := $(sort $(obj-m))
index fc905141e8a5bfa7a12d18bac086e5f409485cc5..f45f6116c77ab03d7f171717617f5569a0f4127c 100644 (file)
@@ -19,7 +19,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <asm/dma.h>
 #include <linux/slab.h>
 #include <sound/core.h>
index 9eaa932f6efeadcfad5b9b43cbdadcac7263d1d9..fd2e2e2ed4e78ea38c7dc1139df45fdaeed2cf66 100644 (file)
@@ -19,7 +19,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/time.h>
 #include <sound/core.h>
 #include <sound/gus.h>
index bf137ea72329e63de2d126c6ec3a8e7a9d5133bb..4dc9caf8ddcf99fee0ef64eaaf120fa9df97adf5 100644 (file)
@@ -19,7 +19,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/time.h>
 #include <sound/core.h>
 #include <sound/gus.h>
index 3d4f899285ef666f151b1265a83fac17a4975a1b..ca79878d8d8c07640d0c2cd9160003b158dbabaf 100644 (file)
@@ -19,7 +19,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/delay.h>
 #include <linux/time.h>
 #include <sound/core.h>
index cd9a6f1c99e6ea08f01fcad7756ce1beabd8dcbb..041894ddd014ab2966c4b13a9a002416f026e530 100644 (file)
@@ -19,7 +19,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <sound/core.h>
 #include <sound/info.h>
 #include <sound/gus.h>
index b14d5d6d9a3233b60ad233d988719bd5b74f70cd..cccc16c8113f35a949bc775b56a04b2a4f9f2b38 100644 (file)
@@ -19,7 +19,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
@@ -104,12 +103,6 @@ static int snd_gus_free(struct snd_gus_card *gus)
 {
        if (gus->gf1.res_port2 == NULL)
                goto __hw_end;
-#if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE))
-       if (gus->seq_dev) {
-               snd_device_free(gus->card, gus->seq_dev);
-               gus->seq_dev = NULL;
-       }
-#endif
        snd_gf1_stop(gus);
        snd_gus_init_dma_irq(gus, 0);
       __hw_end:
@@ -408,14 +401,6 @@ static int snd_gus_check_version(struct snd_gus_card * gus)
        return 0;
 }
 
-#if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE))
-static void snd_gus_seq_dev_free(struct snd_seq_device *seq_dev)
-{
-       struct snd_gus_card *gus = seq_dev->private_data;
-       gus->seq_dev = NULL;
-}
-#endif
-
 int snd_gus_initialize(struct snd_gus_card *gus)
 {
        int err;
@@ -430,15 +415,6 @@ int snd_gus_initialize(struct snd_gus_card *gus)
        }
        if ((err = snd_gus_init_dma_irq(gus, 1)) < 0)
                return err;
-#if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE))
-       if (snd_seq_device_new(gus->card, 1, SNDRV_SEQ_DEV_ID_GUS,
-                              sizeof(struct snd_gus_card *), &gus->seq_dev) >= 0) {
-               strcpy(gus->seq_dev->name, "GUS");
-               *(struct snd_gus_card **)SNDRV_SEQ_DEVICE_ARGPTR(gus->seq_dev) = gus;
-               gus->seq_dev->private_data = gus;
-               gus->seq_dev->private_free = snd_gus_seq_dev_free;
-       }
-#endif
        snd_gf1_start(gus);
        gus->initialized = 1;
        return 0;
index bcf4656853c4f1d2ae3a73fc5a50c0144c6a858b..661205c4dceab85b97dc6693067dd17a888c4b7f 100644 (file)
@@ -19,7 +19,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <sound/core.h>
index f69a44728ebf0b065648e984d3792a966a1773d5..2803e227aec9f12f6c6d1ffdaa6c8b8b8bfee8d2 100644 (file)
@@ -19,7 +19,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/slab.h>
 #include <sound/core.h>
 #include <sound/gus.h>
index a96253e16654b21d4dfb7c513d35043fd81907b4..ebdb33469306df356c9a9303c0c8f1dc22c1b802 100644 (file)
@@ -19,7 +19,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/time.h>
 #include <linux/wait.h>
 #include <sound/core.h>
index a7971f5ffe637f16dfe4c6d0e5230eaad61562dc..99731dc9732564fa1223becbadff7f2e0b9cb782 100644 (file)
@@ -25,7 +25,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <asm/dma.h>
 #include <linux/slab.h>
 #include <sound/core.h>
index 20cfdb87f84ab24c8f4480e5540caf57d67fd50e..3d1fed0c2620d3063ce4cd0c5fcc26b21187877e 100644 (file)
@@ -18,7 +18,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/time.h>
diff --git a/sound/isa/gus/gus_sample.c b/sound/isa/gus/gus_sample.c
deleted file mode 100644 (file)
index cba0829..0000000
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- *  Routines for Gravis UltraSound soundcards - Sample support
- *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
- *
- *
- *   This program is free software; you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   the Free Software Foundation; either version 2 of the License, or
- *   (at your option) any later version.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program; if not, write to the Free Software
- *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
- *
- */
-
-#include <sound/driver.h>
-#include <linux/time.h>
-#include <sound/core.h>
-#include <sound/gus.h>
-
-/*
- *
- */
-
-static void select_instrument(struct snd_gus_card * gus, struct snd_gus_voice * v)
-{
-       struct snd_seq_kinstr *instr;
-
-#if 0
-       printk("select instrument: cluster = %li, std = 0x%x, bank = %i, prg = %i\n",
-                                       v->instr.cluster,
-                                       v->instr.std,
-                                       v->instr.bank,
-                                       v->instr.prg);
-#endif
-       instr = snd_seq_instr_find(gus->gf1.ilist, &v->instr, 0, 1);
-       if (instr != NULL) {
-               if (instr->ops) {
-                       if (!strcmp(instr->ops->instr_type, SNDRV_SEQ_INSTR_ID_SIMPLE))
-                               snd_gf1_simple_init(v);
-               }
-               snd_seq_instr_free_use(gus->gf1.ilist, instr);
-       }
-}
-
-/*
- *
- */
-
-static void event_sample(struct snd_seq_event *ev, struct snd_gus_port *p,
-                        struct snd_gus_voice *v)
-{
-       if (v->sample_ops && v->sample_ops->sample_stop)
-               v->sample_ops->sample_stop(p->gus, v, SAMPLE_STOP_IMMEDIATELY);
-       v->instr.std = ev->data.sample.param.sample.std;
-       if (v->instr.std & 0xff000000) {        /* private instrument */
-               v->instr.std &= 0x00ffffff;
-               v->instr.std |= (unsigned int)ev->source.client << 24;
-       }                                                
-       v->instr.bank = ev->data.sample.param.sample.bank;
-       v->instr.prg = ev->data.sample.param.sample.prg;
-       select_instrument(p->gus, v);
-}
-
-static void event_cluster(struct snd_seq_event *ev, struct snd_gus_port *p,
-                         struct snd_gus_voice *v)
-{
-       if (v->sample_ops && v->sample_ops->sample_stop)
-               v->sample_ops->sample_stop(p->gus, v, SAMPLE_STOP_IMMEDIATELY);
-       v->instr.cluster = ev->data.sample.param.cluster.cluster;
-       select_instrument(p->gus, v);
-}
-
-static void event_start(struct snd_seq_event *ev, struct snd_gus_port *p,
-                       struct snd_gus_voice *v)
-{
-       if (v->sample_ops && v->sample_ops->sample_start)
-               v->sample_ops->sample_start(p->gus, v, ev->data.sample.param.position);
-}
-
-static void event_stop(struct snd_seq_event *ev, struct snd_gus_port *p,
-                      struct snd_gus_voice *v)
-{
-       if (v->sample_ops && v->sample_ops->sample_stop)
-               v->sample_ops->sample_stop(p->gus, v, ev->data.sample.param.stop_mode);
-}
-
-static void event_freq(struct snd_seq_event *ev, struct snd_gus_port *p,
-                      struct snd_gus_voice *v)
-{
-       if (v->sample_ops && v->sample_ops->sample_freq)
-               v->sample_ops->sample_freq(p->gus, v, ev->data.sample.param.frequency);
-}
-
-static void event_volume(struct snd_seq_event *ev, struct snd_gus_port *p,
-                        struct snd_gus_voice *v)
-{
-       if (v->sample_ops && v->sample_ops->sample_volume)
-               v->sample_ops->sample_volume(p->gus, v, &ev->data.sample.param.volume);
-}
-
-static void event_loop(struct snd_seq_event *ev, struct snd_gus_port *p,
-                      struct snd_gus_voice *v)
-{
-       if (v->sample_ops && v->sample_ops->sample_loop)
-               v->sample_ops->sample_loop(p->gus, v, &ev->data.sample.param.loop);
-}
-
-static void event_position(struct snd_seq_event *ev, struct snd_gus_port *p,
-                          struct snd_gus_voice *v)
-{
-       if (v->sample_ops && v->sample_ops->sample_pos)
-               v->sample_ops->sample_pos(p->gus, v, ev->data.sample.param.position);
-}
-
-static void event_private1(struct snd_seq_event *ev, struct snd_gus_port *p,
-                          struct snd_gus_voice *v)
-{
-       if (v->sample_ops && v->sample_ops->sample_private1)
-               v->sample_ops->sample_private1(p->gus, v, (unsigned char *)&ev->data.sample.param.raw8);
-}
-
-typedef void (gus_sample_event_handler_t)(struct snd_seq_event *ev,
-                                         struct snd_gus_port *p,
-                                         struct snd_gus_voice *v);
-static gus_sample_event_handler_t *gus_sample_event_handlers[9] = {
-       event_sample,
-       event_cluster,
-       event_start,
-       event_stop,
-       event_freq,
-       event_volume,
-       event_loop,
-       event_position,
-       event_private1
-};
-
-void snd_gus_sample_event(struct snd_seq_event *ev, struct snd_gus_port *p)
-{
-       int idx, voice;
-       struct snd_gus_card *gus = p->gus;
-       struct snd_gus_voice *v;
-       unsigned long flags;
-       
-       idx = ev->type - SNDRV_SEQ_EVENT_SAMPLE;
-       if (idx < 0 || idx > 8)
-               return;
-       for (voice = 0; voice < 32; voice++) {
-               v = &gus->gf1.voices[voice];
-               if (v->use && v->client == ev->source.client &&
-                   v->port == ev->source.port &&
-                   v->index == ev->data.sample.channel) {
-                       spin_lock_irqsave(&gus->event_lock, flags);
-                       gus_sample_event_handlers[idx](ev, p, v);
-                       spin_unlock_irqrestore(&gus->event_lock, flags);
-                       return;
-               }
-       }
-}
diff --git a/sound/isa/gus/gus_simple.c b/sound/isa/gus/gus_simple.c
deleted file mode 100644 (file)
index 39d121e..0000000
+++ /dev/null
@@ -1,634 +0,0 @@
-/*
- *  Routines for Gravis UltraSound soundcards - Simple instrument handlers
- *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
- *
- *
- *   This program is free software; you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   the Free Software Foundation; either version 2 of the License, or
- *   (at your option) any later version.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program; if not, write to the Free Software
- *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
- *
- */
-
-#include <sound/driver.h>
-#include <linux/time.h>
-#include <sound/core.h>
-#include <sound/gus.h>
-#include "gus_tables.h"
-
-/*
- *
- */
-
-static void interrupt_wave(struct snd_gus_card *gus, struct snd_gus_voice *voice);
-static void interrupt_volume(struct snd_gus_card *gus, struct snd_gus_voice *voice);
-static void interrupt_effect(struct snd_gus_card *gus, struct snd_gus_voice *voice);
-
-static void sample_start(struct snd_gus_card *gus, struct snd_gus_voice *voice, snd_seq_position_t position);
-static void sample_stop(struct snd_gus_card *gus, struct snd_gus_voice *voice, int mode);
-static void sample_freq(struct snd_gus_card *gus, struct snd_gus_voice *voice, snd_seq_frequency_t freq);
-static void sample_volume(struct snd_gus_card *card, struct snd_gus_voice *voice, struct snd_seq_ev_volume *volume);
-static void sample_loop(struct snd_gus_card *card, struct snd_gus_voice *voice, struct snd_seq_ev_loop *loop);
-static void sample_pos(struct snd_gus_card *card, struct snd_gus_voice *voice, snd_seq_position_t position);
-static void sample_private1(struct snd_gus_card *card, struct snd_gus_voice *voice, unsigned char *data);
-
-static struct snd_gus_sample_ops sample_ops = {
-       sample_start,
-       sample_stop,
-       sample_freq,
-       sample_volume,
-       sample_loop,
-       sample_pos,
-       sample_private1
-};
-
-#if 0
-
-static void note_stop(struct snd_gus_card *gus, struct snd_gus_voice *voice, int wait);
-static void note_wait(struct snd_gus_card *gus, struct snd_gus_voice *voice);
-static void note_off(struct snd_gus_card *gus, struct snd_gus_voice *voice);
-static void note_volume(struct snd_gus_card *card, struct snd_gus_voice *voice);
-static void note_pitchbend(struct snd_gus_card *card, struct snd_gus_voice *voice);
-static void note_vibrato(struct snd_gus_card *card, struct snd_gus_voice *voice);
-static void note_tremolo(struct snd_gus_card *card, struct snd_gus_voice *voice);
-
-static struct snd_gus_note_handlers note_commands = {
-       note_stop,
-       note_wait,
-       note_off,
-       note_volume,
-       note_pitchbend,
-       note_vibrato,
-       note_tremolo
-};
-
-static void chn_trigger_down(struct snd_gus_card *card, ultra_channel_t *channel, ultra_instrument_t *instrument, unsigned char note, unsigned char velocity, unsigned char priority );
-static void chn_trigger_up( ultra_card_t *card, ultra_note_t *note );
-static void chn_control( ultra_card_t *card, ultra_channel_t *channel, unsigned short p1, unsigned short p2 );
-
-static struct ULTRA_STRU_INSTRUMENT_CHANNEL_COMMANDS channel_commands = {
-  chn_trigger_down,
-  chn_trigger_up,
-  chn_control
-};
-
-#endif
-
-static void do_volume_envelope(struct snd_gus_card *card, struct snd_gus_voice *voice);
-static void do_pan_envelope(struct snd_gus_card *card, struct snd_gus_voice *voice);
-
-/*
- *
- */
-
-static void interrupt_wave(struct snd_gus_card *gus, struct snd_gus_voice *voice)
-{
-       spin_lock(&gus->event_lock);
-       snd_gf1_stop_voice(gus, voice->number);
-       spin_lock(&gus->reg_lock);
-       snd_gf1_select_voice(gus, voice->number);
-       snd_gf1_write16(gus, SNDRV_GF1_VW_VOLUME, 0);
-       spin_unlock(&gus->reg_lock);
-       voice->flags &= ~SNDRV_GF1_VFLG_RUNNING;
-       spin_unlock(&gus->event_lock);
-}
-
-static void interrupt_volume(struct snd_gus_card *gus, struct snd_gus_voice *voice)
-{
-       spin_lock(&gus->event_lock);
-       if (voice->flags & SNDRV_GF1_VFLG_RUNNING)
-               do_volume_envelope(gus, voice);
-       else
-               snd_gf1_stop_voice(gus, voice->number);
-       spin_unlock(&gus->event_lock);
-}
-
-static void interrupt_effect(struct snd_gus_card *gus, struct snd_gus_voice *voice)
-{
-       spin_lock(&gus->event_lock);
-       if ((voice->flags & (SNDRV_GF1_VFLG_RUNNING|SNDRV_GF1_VFLG_EFFECT_TIMER1)) ==
-                           (SNDRV_GF1_VFLG_RUNNING|SNDRV_GF1_VFLG_EFFECT_TIMER1))
-               do_pan_envelope(gus, voice);
-       spin_unlock(&gus->event_lock);
-}
-
-/*
- *
- */
-
-static void do_volume_envelope(struct snd_gus_card *gus, struct snd_gus_voice *voice)
-{
-       unsigned short next, rate, old_volume;
-       int program_next_ramp;
-       unsigned long flags;
-  
-       if (!gus->gf1.volume_ramp) {
-               spin_lock_irqsave(&gus->reg_lock, flags);
-               snd_gf1_select_voice(gus, voice->number);
-               snd_gf1_ctrl_stop(gus, SNDRV_GF1_VB_VOLUME_CONTROL);
-               snd_gf1_write16(gus, SNDRV_GF1_VW_VOLUME, voice->gf1_volume);
-               /* printk("gf1_volume = 0x%x\n", voice->gf1_volume); */
-               spin_unlock_irqrestore(&gus->reg_lock, flags);
-               return;
-       }
-       program_next_ramp = 0;
-       rate = next = 0;
-       while (1) {
-               program_next_ramp = 0;
-               rate = next = 0;
-               switch (voice->venv_state) {
-               case VENV_BEFORE:
-                       voice->venv_state = VENV_ATTACK;
-                       voice->venv_value_next = 0;
-                       spin_lock_irqsave(&gus->reg_lock, flags);
-                       snd_gf1_select_voice(gus, voice->number);
-                       snd_gf1_ctrl_stop(gus, SNDRV_GF1_VB_VOLUME_CONTROL);
-                       snd_gf1_write16(gus, SNDRV_GF1_VW_VOLUME, SNDRV_GF1_MIN_VOLUME);
-                       spin_unlock_irqrestore(&gus->reg_lock, flags);
-                       break;
-               case VENV_ATTACK:
-                       voice->venv_state = VENV_SUSTAIN;
-                       program_next_ramp++;
-                       next = 255;
-                       rate = gus->gf1.volume_ramp;
-                       break;
-               case VENV_SUSTAIN:
-                       voice->venv_state = VENV_RELEASE;
-                       spin_lock_irqsave(&gus->reg_lock, flags);
-                       snd_gf1_select_voice(gus, voice->number);
-                       snd_gf1_ctrl_stop(gus, SNDRV_GF1_VB_VOLUME_CONTROL);
-                       snd_gf1_write16(gus, SNDRV_GF1_VW_VOLUME, ((int)voice->gf1_volume * (int)voice->venv_value_next) / 255);
-                       spin_unlock_irqrestore(&gus->reg_lock, flags);
-                       return;
-               case VENV_RELEASE:
-                       voice->venv_state = VENV_DONE;
-                       program_next_ramp++;
-                       next = 0;
-                       rate = gus->gf1.volume_ramp;
-                       break;
-               case VENV_DONE:
-                       snd_gf1_stop_voice(gus, voice->number);
-                       voice->flags &= ~SNDRV_GF1_VFLG_RUNNING;
-                       return;
-               case VENV_VOLUME:
-                       program_next_ramp++;
-                       next = voice->venv_value_next;
-                       rate = gus->gf1.volume_ramp;
-                       voice->venv_state = voice->venv_state_prev;
-                       break;
-               }
-               voice->venv_value_next = next;
-               if (!program_next_ramp)
-                       continue;
-               spin_lock_irqsave(&gus->reg_lock, flags);
-               snd_gf1_select_voice(gus, voice->number);
-               snd_gf1_ctrl_stop(gus, SNDRV_GF1_VB_VOLUME_CONTROL);
-               old_volume = snd_gf1_read16(gus, SNDRV_GF1_VW_VOLUME) >> 8;
-               if (!rate) {
-                       spin_unlock_irqrestore(&gus->reg_lock, flags);                  
-                       continue;
-               }
-               next = (((int)voice->gf1_volume * (int)next) / 255) >> 8;
-               if (old_volume < SNDRV_GF1_MIN_OFFSET)
-                       old_volume = SNDRV_GF1_MIN_OFFSET;
-               if (next < SNDRV_GF1_MIN_OFFSET)
-                       next = SNDRV_GF1_MIN_OFFSET;
-               if (next > SNDRV_GF1_MAX_OFFSET)
-                       next = SNDRV_GF1_MAX_OFFSET;
-               if (old_volume == next) {
-                       spin_unlock_irqrestore(&gus->reg_lock, flags);
-                       continue;
-               }
-               voice->volume_control &= ~0xc3;
-               voice->volume_control |= 0x20;
-               if (old_volume > next) {
-                       snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_START, next);
-                       snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_END, old_volume);
-                       voice->volume_control |= 0x40;
-               } else {
-                       snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_START, old_volume);
-                       snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_END, next);
-               }
-               snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_RATE, rate);
-               snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_CONTROL, voice->volume_control);
-               if (!gus->gf1.enh_mode) {
-                       snd_gf1_delay(gus);
-                       snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_CONTROL, voice->volume_control);
-               }
-               spin_unlock_irqrestore(&gus->reg_lock, flags);                  
-               return;
-       }
-}
-
-static void do_pan_envelope(struct snd_gus_card *gus, struct snd_gus_voice *voice)
-{
-       unsigned long flags;
-       unsigned char old_pan;
-
-#if 0
-       snd_gf1_select_voice(gus, voice->number);
-       printk(" -%i- do_pan_envelope - flags = 0x%x (0x%x -> 0x%x)\n",
-               voice->number,
-               voice->flags,
-               voice->gf1_pan,
-               snd_gf1_i_read8(gus, SNDRV_GF1_VB_PAN) & 0x0f);
-#endif
-       if (gus->gf1.enh_mode) {
-               voice->flags &= ~(SNDRV_GF1_VFLG_EFFECT_TIMER1|SNDRV_GF1_VFLG_PAN);
-               return;
-       }
-       if (!gus->gf1.smooth_pan) {
-               spin_lock_irqsave(&gus->reg_lock, flags);                       
-               snd_gf1_select_voice(gus, voice->number);
-               snd_gf1_write8(gus, SNDRV_GF1_VB_PAN, voice->gf1_pan);
-               spin_unlock_irqrestore(&gus->reg_lock, flags);
-               return;
-       }
-       if (!(voice->flags & SNDRV_GF1_VFLG_PAN))               /* before */
-               voice->flags |= SNDRV_GF1_VFLG_EFFECT_TIMER1|SNDRV_GF1_VFLG_PAN;
-       spin_lock_irqsave(&gus->reg_lock, flags);                       
-       snd_gf1_select_voice(gus, voice->number);
-       old_pan = snd_gf1_read8(gus, SNDRV_GF1_VB_PAN) & 0x0f;
-       if (old_pan > voice->gf1_pan )
-               old_pan--;
-       if (old_pan < voice->gf1_pan)
-               old_pan++;
-       snd_gf1_write8(gus, SNDRV_GF1_VB_PAN, old_pan);
-       spin_unlock_irqrestore(&gus->reg_lock, flags);
-       if (old_pan == voice->gf1_pan)                  /* the goal was reached */
-               voice->flags &= ~(SNDRV_GF1_VFLG_EFFECT_TIMER1|SNDRV_GF1_VFLG_PAN);
-#if 0
-       snd_gf1_select_voice(gus, voice->number);
-       printk(" -%i- (1) do_pan_envelope - flags = 0x%x (0x%x -> 0x%x)\n",
-              voice->number,
-              voice->flags,
-              voice->gf1_pan,
-              snd_gf1_i_read8(gus, GF1_VB_PAN) & 0x0f);
-#endif
-}
-
-static void set_enhanced_pan(struct snd_gus_card *gus, struct snd_gus_voice *voice, unsigned short pan)
-{
-       unsigned long flags;
-       unsigned short vlo, vro;
-  
-       vlo = SNDRV_GF1_ATTEN((SNDRV_GF1_ATTEN_TABLE_SIZE-1) - pan);
-       vro = SNDRV_GF1_ATTEN(pan);
-       if (pan != SNDRV_GF1_ATTEN_TABLE_SIZE - 1 && pan != 0) {
-               vlo >>= 1;
-               vro >>= 1;
-       }
-       vlo <<= 4;
-       vro <<= 4;
-#if 0
-       printk("vlo = 0x%x (0x%x), vro = 0x%x (0x%x)\n",
-                       vlo, snd_gf1_i_read16(gus, GF1_VW_OFFSET_LEFT),
-                       vro, snd_gf1_i_read16(gus, GF1_VW_OFFSET_RIGHT));
-#endif
-       spin_lock_irqsave(&gus->reg_lock, flags);                       
-       snd_gf1_select_voice(gus, voice->number);
-        snd_gf1_write16(gus, SNDRV_GF1_VW_OFFSET_LEFT_FINAL, vlo);
-       snd_gf1_write16(gus, SNDRV_GF1_VW_OFFSET_RIGHT_FINAL, vro);
-       spin_unlock_irqrestore(&gus->reg_lock, flags);                  
-       voice->vlo = vlo;
-       voice->vro = vro;
-}
-
-/*
- *
- */
-
-static void sample_start(struct snd_gus_card *gus, struct snd_gus_voice *voice, snd_seq_position_t position)
-{
-       unsigned long flags;
-       unsigned int begin, addr, addr_end, addr_start;
-       int w_16;
-       struct simple_instrument *simple;
-       struct snd_seq_kinstr *instr;
-
-       instr = snd_seq_instr_find(gus->gf1.ilist, &voice->instr, 0, 1);
-       if (instr == NULL)
-               return;
-       voice->instr = instr->instr;    /* copy ID to speedup aliases */
-       simple = KINSTR_DATA(instr);
-       begin = simple->address.memory << 4;
-       w_16 = simple->format & SIMPLE_WAVE_16BIT ? 0x04 : 0;
-       addr_start = simple->loop_start;
-       if (simple->format & SIMPLE_WAVE_LOOP) {
-               addr_end = simple->loop_end;
-       } else {
-               addr_end = (simple->size << 4) - (w_16 ? 40 : 24);
-       }
-       if (simple->format & SIMPLE_WAVE_BACKWARD) {
-               addr = simple->loop_end;
-               if (position < simple->loop_end)
-                       addr -= position;
-       } else {
-               addr = position;
-       }
-       voice->control = 0x00;
-       voice->mode = 0x20;             /* enable offset registers */
-       if (simple->format & SIMPLE_WAVE_16BIT)
-               voice->control |= 0x04;
-       if (simple->format & SIMPLE_WAVE_BACKWARD)
-               voice->control |= 0x40;
-       if (simple->format & SIMPLE_WAVE_LOOP) {
-               voice->control |= 0x08;
-       } else {
-               voice->control |= 0x20;
-       }
-       if (simple->format & SIMPLE_WAVE_BIDIR)
-               voice->control |= 0x10;
-       if (simple->format & SIMPLE_WAVE_ULAW)
-               voice->mode |= 0x40;
-       if (w_16) {
-               addr = ((addr << 1) & ~0x1f) | (addr & 0x0f);
-               addr_start = ((addr_start << 1) & ~0x1f) | (addr_start & 0x0f);
-               addr_end = ((addr_end << 1) & ~0x1f) | (addr_end & 0x0f);
-       }
-       addr += begin;
-       addr_start += begin;
-       addr_end += begin;
-       snd_gf1_stop_voice(gus, voice->number); 
-       spin_lock_irqsave(&gus->reg_lock, flags);
-       snd_gf1_select_voice(gus, voice->number);
-       snd_gf1_write16(gus, SNDRV_GF1_VW_FREQUENCY, voice->fc_register + voice->fc_lfo);
-       voice->venv_state = VENV_BEFORE;
-       voice->volume_control = 0x03;
-       snd_gf1_write_addr(gus, SNDRV_GF1_VA_START, addr_start, w_16);
-       snd_gf1_write_addr(gus, SNDRV_GF1_VA_END, addr_end, w_16);
-       snd_gf1_write_addr(gus, SNDRV_GF1_VA_CURRENT, addr, w_16);
-       if (!gus->gf1.enh_mode) {
-               snd_gf1_write8(gus, SNDRV_GF1_VB_PAN, voice->gf1_pan);
-       } else {
-               snd_gf1_write16(gus, SNDRV_GF1_VW_OFFSET_LEFT, voice->vlo);
-               snd_gf1_write16(gus, SNDRV_GF1_VW_OFFSET_LEFT_FINAL, voice->vlo);
-               snd_gf1_write16(gus, SNDRV_GF1_VW_OFFSET_RIGHT, voice->vro);
-               snd_gf1_write16(gus, SNDRV_GF1_VW_OFFSET_RIGHT_FINAL, voice->vro);
-               snd_gf1_write8(gus, SNDRV_GF1_VB_ACCUMULATOR, voice->effect_accumulator);
-               snd_gf1_write16(gus, SNDRV_GF1_VW_EFFECT_VOLUME, voice->gf1_effect_volume);
-               snd_gf1_write16(gus, SNDRV_GF1_VW_EFFECT_VOLUME_FINAL, voice->gf1_effect_volume);
-       }
-       spin_unlock_irqrestore(&gus->reg_lock, flags);
-       do_volume_envelope(gus, voice);
-       spin_lock_irqsave(&gus->reg_lock, flags);
-       snd_gf1_select_voice(gus, voice->number);
-       if (gus->gf1.enh_mode)
-               snd_gf1_write8(gus, SNDRV_GF1_VB_MODE, voice->mode);
-       snd_gf1_write8(gus, SNDRV_GF1_VB_ADDRESS_CONTROL, voice->control);
-       if (!gus->gf1.enh_mode) {
-               snd_gf1_delay(gus);
-               snd_gf1_write8(gus, SNDRV_GF1_VB_ADDRESS_CONTROL, voice->control );
-       }
-       spin_unlock_irqrestore(&gus->reg_lock, flags);
-#if 0
-       snd_gf1_print_voice_registers(gus);
-#endif
-       voice->flags |= SNDRV_GF1_VFLG_RUNNING;
-       snd_seq_instr_free_use(gus->gf1.ilist, instr);
-}
-
-static void sample_stop(struct snd_gus_card *gus, struct snd_gus_voice *voice, int mode)
-{
-       unsigned char control;
-       unsigned long flags;
-
-       if (!(voice->flags & SNDRV_GF1_VFLG_RUNNING))
-               return;
-       switch (mode) {
-       default:
-               if (gus->gf1.volume_ramp > 0) {
-                       if (voice->venv_state < VENV_RELEASE) {
-                               voice->venv_state = VENV_RELEASE;
-                               do_volume_envelope(gus, voice);
-                       }
-               }
-               if (mode != SAMPLE_STOP_VENVELOPE) {
-                       snd_gf1_stop_voice(gus, voice->number);
-                       spin_lock_irqsave(&gus->reg_lock, flags);
-                       snd_gf1_select_voice(gus, voice->number);
-                       snd_gf1_write16(gus, SNDRV_GF1_VW_VOLUME, SNDRV_GF1_MIN_VOLUME);
-                       spin_unlock_irqrestore(&gus->reg_lock, flags);
-                       voice->flags &= ~SNDRV_GF1_VFLG_RUNNING;
-               }
-               break;
-       case SAMPLE_STOP_LOOP:          /* disable loop only */
-               spin_lock_irqsave(&gus->reg_lock, flags);
-               snd_gf1_select_voice(gus, voice->number);
-               control = snd_gf1_read8(gus, SNDRV_GF1_VB_ADDRESS_CONTROL);
-               control &= ~(0x83 | 0x04);
-               control |= 0x20;
-               snd_gf1_write8(gus, SNDRV_GF1_VB_ADDRESS_CONTROL, control);
-               spin_unlock_irqrestore(&gus->reg_lock, flags);
-               break;
-       }
-}
-
-static void sample_freq(struct snd_gus_card *gus, struct snd_gus_voice *voice, snd_seq_frequency_t freq)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&gus->reg_lock, flags);
-       voice->fc_register = snd_gf1_translate_freq(gus, freq);
-       snd_gf1_select_voice(gus, voice->number);
-       snd_gf1_write16(gus, SNDRV_GF1_VW_FREQUENCY, voice->fc_register + voice->fc_lfo);
-       spin_unlock_irqrestore(&gus->reg_lock, flags);
-}
-
-static void sample_volume(struct snd_gus_card *gus, struct snd_gus_voice *voice, struct snd_seq_ev_volume *volume)
-{
-       if (volume->volume >= 0) {
-               volume->volume &= 0x3fff;
-               voice->gf1_volume = snd_gf1_lvol_to_gvol_raw(volume->volume << 2) << 4;
-               voice->venv_state_prev = VENV_SUSTAIN;
-               voice->venv_state = VENV_VOLUME;
-               do_volume_envelope(gus, voice);
-        }
-       if (volume->lr >= 0) {
-               volume->lr &= 0x3fff;
-               if (!gus->gf1.enh_mode) {
-                       voice->gf1_pan = (volume->lr >> 10) & 15;
-                       if (!gus->gf1.full_range_pan) {
-                               if (voice->gf1_pan == 0)
-                                       voice->gf1_pan++;
-                               if (voice->gf1_pan == 15)
-                                       voice->gf1_pan--;
-                       }
-                       voice->flags &= ~SNDRV_GF1_VFLG_PAN;    /* before */
-                       do_pan_envelope(gus, voice);
-               } else {
-                       set_enhanced_pan(gus, voice, volume->lr >> 7);
-               }
-       }
-}
-
-static void sample_loop(struct snd_gus_card *gus, struct snd_gus_voice *voice, struct snd_seq_ev_loop *loop)
-{
-       unsigned long flags;
-       int w_16 = voice->control & 0x04;
-       unsigned int begin, addr_start, addr_end;
-       struct simple_instrument *simple;
-       struct snd_seq_kinstr *instr;
-
-#if 0
-       printk("voice_loop: start = 0x%x, end = 0x%x\n", loop->start, loop->end);
-#endif
-       instr = snd_seq_instr_find(gus->gf1.ilist, &voice->instr, 0, 1);
-       if (instr == NULL)
-               return;
-       voice->instr = instr->instr;    /* copy ID to speedup aliases */
-       simple = KINSTR_DATA(instr);
-       begin = simple->address.memory;
-       addr_start = loop->start;
-       addr_end = loop->end;
-       addr_start = (((addr_start << 1) & ~0x1f) | (addr_start & 0x0f)) + begin;
-       addr_end = (((addr_end << 1) & ~0x1f) | (addr_end & 0x0f)) + begin;
-       spin_lock_irqsave(&gus->reg_lock, flags);
-       snd_gf1_select_voice(gus, voice->number);
-       snd_gf1_write_addr(gus, SNDRV_GF1_VA_START, addr_start, w_16);
-       snd_gf1_write_addr(gus, SNDRV_GF1_VA_END, addr_end, w_16);
-       spin_unlock_irqrestore(&gus->reg_lock, flags);
-       snd_seq_instr_free_use(gus->gf1.ilist, instr);
-}
-
-static void sample_pos(struct snd_gus_card *gus, struct snd_gus_voice *voice, snd_seq_position_t position)
-{
-       unsigned long flags;
-       int w_16 = voice->control & 0x04;
-       unsigned int begin, addr;
-       struct simple_instrument *simple;
-       struct snd_seq_kinstr *instr;
-
-#if 0
-       printk("voice_loop: start = 0x%x, end = 0x%x\n", loop->start, loop->end);
-#endif
-       instr = snd_seq_instr_find(gus->gf1.ilist, &voice->instr, 0, 1);
-       if (instr == NULL)
-               return;
-       voice->instr = instr->instr;    /* copy ID to speedup aliases */
-       simple = KINSTR_DATA(instr);
-       begin = simple->address.memory;
-       addr = (((position << 1) & ~0x1f) | (position & 0x0f)) + begin;
-       spin_lock_irqsave(&gus->reg_lock, flags);
-       snd_gf1_select_voice(gus, voice->number);
-       snd_gf1_write_addr(gus, SNDRV_GF1_VA_CURRENT, addr, w_16);
-       spin_unlock_irqrestore(&gus->reg_lock, flags);
-       snd_seq_instr_free_use(gus->gf1.ilist, instr);
-}
-
-#if 0
-
-static unsigned char get_effects_mask( ultra_card_t *card, int value )
-{
-  if ( value > 7 ) return 0;
-  if ( card -> gf1.effects && card -> gf1.effects -> chip_type == ULTRA_EFFECT_CHIP_INTERWAVE )
-    return card -> gf1.effects -> chip.interwave.voice_output[ value ];
-  return 0;
-}
-
-#endif
-
-static void sample_private1(struct snd_gus_card *card, struct snd_gus_voice *voice, unsigned char *data)
-{
-#if 0
-  unsigned long flags;
-  unsigned char uc;
-
-  switch ( *data ) {
-    case ULTRA_PRIV1_IW_EFFECT:
-      uc = get_effects_mask( card, ultra_get_byte( data, 4 ) );
-      uc |= get_effects_mask( card, ultra_get_byte( data, 4 ) >> 4 );
-      uc |= get_effects_mask( card, ultra_get_byte( data, 5 ) );
-      uc |= get_effects_mask( card, ultra_get_byte( data, 5 ) >> 4 );
-      voice -> data.simple.effect_accumulator = uc;
-      voice -> data.simple.effect_volume = ultra_translate_voice_volume( card, ultra_get_word( data, 2 ) ) << 4;
-      if ( !card -> gf1.enh_mode ) return;
-      if ( voice -> flags & VFLG_WAIT_FOR_START ) return;
-      if ( voice -> flags & VFLG_RUNNING )
-        {
-          CLI( &flags );
-          gf1_select_voice( card, voice -> number );
-          ultra_write8( card, GF1_VB_ACCUMULATOR, voice -> data.simple.effect_accumulator );
-          ultra_write16( card, GF1_VW_EFFECT_VOLUME_FINAL, voice -> data.simple.effect_volume );
-          STI( &flags );
-        }
-      break;
-   case ULTRA_PRIV1_IW_LFO:
-     ultra_lfo_command( card, voice -> number, data );
-  }
-#endif
-}
-
-#if 0
-
-/*
- *
- */
-
-static void note_stop( ultra_card_t *card, ultra_voice_t *voice, int wait )
-{
-}
-
-static void note_wait( ultra_card_t *card, ultra_voice_t *voice )
-{
-}
-
-static void note_off( ultra_card_t *card, ultra_voice_t *voice )
-{
-}
-
-static void note_volume( ultra_card_t *card, ultra_voice_t *voice )
-{
-}
-
-static void note_pitchbend( ultra_card_t *card, ultra_voice_t *voice )
-{
-}
-
-static void note_vibrato( ultra_card_t *card, ultra_voice_t *voice )
-{
-}
-
-static void note_tremolo( ultra_card_t *card, ultra_voice_t *voice )
-{
-}
-
-/*
- *
- */
-static void chn_trigger_down( ultra_card_t *card, ultra_channel_t *channel, ultra_instrument_t *instrument, unsigned char note, unsigned char velocity, unsigned char priority )
-{
-}
-
-static void chn_trigger_up( ultra_card_t *card, ultra_note_t *note )
-{
-}
-
-static void chn_control( ultra_card_t *card, ultra_channel_t *channel, unsigned short p1, unsigned short p2 )
-{
-}
-
-/*
- *
- */
-#endif
-
-void snd_gf1_simple_init(struct snd_gus_voice *voice)
-{
-       voice->handler_wave = interrupt_wave;
-       voice->handler_volume = interrupt_volume;
-       voice->handler_effect = interrupt_effect;
-       voice->volume_change = NULL;
-       voice->sample_ops = &sample_ops;
-}
diff --git a/sound/isa/gus/gus_synth.c b/sound/isa/gus/gus_synth.c
deleted file mode 100644 (file)
index 2c20517..0000000
+++ /dev/null
@@ -1,314 +0,0 @@
-/*
- *  Routines for Gravis UltraSound soundcards - Synthesizer
- *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
- *
- *
- *   This program is free software; you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   the Free Software Foundation; either version 2 of the License, or
- *   (at your option) any later version.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program; if not, write to the Free Software
- *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
- *
- */
-
-#include <sound/driver.h>
-#include <linux/init.h>
-#include <linux/time.h>
-#include <sound/core.h>
-#include <sound/gus.h>
-#include <sound/seq_device.h>
-
-MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
-MODULE_DESCRIPTION("Routines for Gravis UltraSound soundcards - Synthesizer");
-MODULE_LICENSE("GPL");
-
-/*
- *
- */
-
-static void snd_gus_synth_free_voices(struct snd_gus_card * gus, int client, int port)
-{
-       int idx;
-       struct snd_gus_voice * voice;
-       
-       for (idx = 0; idx < 32; idx++) {
-               voice = &gus->gf1.voices[idx];
-               if (voice->use && voice->client == client && voice->port == port)
-                       snd_gf1_free_voice(gus, voice);
-       }
-}
-
-static int snd_gus_synth_use(void *private_data, struct snd_seq_port_subscribe *info)
-{
-       struct snd_gus_port * port = private_data;
-       struct snd_gus_card * gus = port->gus;
-       struct snd_gus_voice * voice;
-       unsigned int idx;
-
-       if (info->voices > 32)
-               return -EINVAL;
-       mutex_lock(&gus->register_mutex);
-       if (!snd_gus_use_inc(gus)) {
-               mutex_unlock(&gus->register_mutex);
-               return -EFAULT;
-       }
-       for (idx = 0; idx < info->voices; idx++) {
-               voice = snd_gf1_alloc_voice(gus, SNDRV_GF1_VOICE_TYPE_SYNTH, info->sender.client, info->sender.port);
-               if (voice == NULL) {
-                       snd_gus_synth_free_voices(gus, info->sender.client, info->sender.port);
-                       snd_gus_use_dec(gus);
-                       mutex_unlock(&gus->register_mutex);
-                       return -EBUSY;
-               }
-               voice->index = idx;
-       }
-       mutex_unlock(&gus->register_mutex);
-       return 0;
-}
-
-static int snd_gus_synth_unuse(void *private_data, struct snd_seq_port_subscribe *info)
-{
-       struct snd_gus_port * port = private_data;
-       struct snd_gus_card * gus = port->gus;
-
-       mutex_lock(&gus->register_mutex);
-       snd_gus_synth_free_voices(gus, info->sender.client, info->sender.port);
-       snd_gus_use_dec(gus);
-       mutex_unlock(&gus->register_mutex);
-       return 0;
-}
-
-/*
- *
- */
-
-static void snd_gus_synth_free_private_instruments(struct snd_gus_port *p, int client)
-{
-       struct snd_seq_instr_header ifree;
-
-       memset(&ifree, 0, sizeof(ifree));
-       ifree.cmd = SNDRV_SEQ_INSTR_FREE_CMD_PRIVATE;
-       snd_seq_instr_list_free_cond(p->gus->gf1.ilist, &ifree, client, 0);
-}
-static int snd_gus_synth_event_input(struct snd_seq_event *ev, int direct,
-                                    void *private_data, int atomic, int hop)
-{
-       struct snd_gus_port * p = private_data;
-       
-       snd_assert(p != NULL, return -EINVAL);
-       if (ev->type >= SNDRV_SEQ_EVENT_SAMPLE &&
-           ev->type <= SNDRV_SEQ_EVENT_SAMPLE_PRIVATE1) {
-               snd_gus_sample_event(ev, p);
-               return 0;
-       }
-       if (ev->source.client == SNDRV_SEQ_CLIENT_SYSTEM &&
-           ev->source.port == SNDRV_SEQ_PORT_SYSTEM_ANNOUNCE) {
-               if (ev->type == SNDRV_SEQ_EVENT_CLIENT_EXIT) {
-                       snd_gus_synth_free_private_instruments(p, ev->data.addr.client);
-                       return 0;
-               }
-       }
-       if (direct) {
-               if (ev->type >= SNDRV_SEQ_EVENT_INSTR_BEGIN) {
-                       snd_seq_instr_event(&p->gus->gf1.iwffff_ops.kops,
-                                           p->gus->gf1.ilist,
-                                           ev,
-                                           p->gus->gf1.seq_client,
-                                           atomic, hop);
-                       return 0;
-               }
-       }
-       return 0;
-}
-
-static void snd_gus_synth_instr_notify(void *private_data,
-                                      struct snd_seq_kinstr *instr,
-                                      int what)
-{
-       unsigned int idx;
-       struct snd_gus_card *gus = private_data;
-       struct snd_gus_voice *pvoice;
-       unsigned long flags;
-       
-       spin_lock_irqsave(&gus->event_lock, flags);
-       for (idx = 0; idx < 32; idx++) {
-               pvoice = &gus->gf1.voices[idx];
-               if (pvoice->use && !memcmp(&pvoice->instr, &instr->instr, sizeof(pvoice->instr))) {
-                       if (pvoice->sample_ops && pvoice->sample_ops->sample_stop) {
-                               pvoice->sample_ops->sample_stop(gus, pvoice, SAMPLE_STOP_IMMEDIATELY);
-                       } else {
-                               snd_gf1_stop_voice(gus, pvoice->number);
-                               pvoice->flags &= ~SNDRV_GF1_VFLG_RUNNING;
-                       }
-               }
-       }
-       spin_unlock_irqrestore(&gus->event_lock, flags);
-}
-
-/*
- *
- */
-
-static void snd_gus_synth_free_port(void *private_data)
-{
-       struct snd_gus_port * p = private_data;
-       
-       if (p)
-               snd_midi_channel_free_set(p->chset);
-}
-
-static int snd_gus_synth_create_port(struct snd_gus_card * gus, int idx)
-{
-       struct snd_gus_port * p;
-       struct snd_seq_port_callback callbacks;
-       char name[32];
-       int result;
-       
-       p = &gus->gf1.seq_ports[idx];
-       p->chset = snd_midi_channel_alloc_set(16);
-       if (p->chset == NULL)
-               return -ENOMEM;
-       p->chset->private_data = p;
-       p->gus = gus;
-       p->client = gus->gf1.seq_client;
-
-       memset(&callbacks, 0, sizeof(callbacks));
-       callbacks.owner = THIS_MODULE;
-       callbacks.use = snd_gus_synth_use;
-       callbacks.unuse = snd_gus_synth_unuse;
-       callbacks.event_input = snd_gus_synth_event_input;
-       callbacks.private_free = snd_gus_synth_free_port;
-       callbacks.private_data = p;
-       
-       sprintf(name, "%s port %i", gus->interwave ? "AMD InterWave" : "GF1", idx);
-       p->chset->port = snd_seq_event_port_attach(gus->gf1.seq_client,
-                                                  &callbacks,
-                                                  SNDRV_SEQ_PORT_CAP_WRITE | SNDRV_SEQ_PORT_CAP_SUBS_WRITE,
-                                                  SNDRV_SEQ_PORT_TYPE_DIRECT_SAMPLE |
-                                                  SNDRV_SEQ_PORT_TYPE_SYNTH |
-                                                  SNDRV_SEQ_PORT_TYPE_HARDWARE |
-                                                  SNDRV_SEQ_PORT_TYPE_SYNTHESIZER,
-                                                  16, 0,
-                                                  name);
-       if (p->chset->port < 0) {
-               result = p->chset->port;
-               snd_gus_synth_free_port(p);
-               return result;
-       }
-       p->port = p->chset->port;
-       return 0;
-}                                               
-
-/*
- *
- */
-
-static int snd_gus_synth_new_device(struct snd_seq_device *dev)
-{
-       struct snd_gus_card *gus;
-       int client, i;
-       struct snd_seq_port_subscribe sub;
-       struct snd_iwffff_ops *iwops;
-       struct snd_gf1_ops *gf1ops;
-       struct snd_simple_ops *simpleops;
-
-       gus = *(struct snd_gus_card **)SNDRV_SEQ_DEVICE_ARGPTR(dev);
-       if (gus == NULL)
-               return -EINVAL;
-
-       mutex_init(&gus->register_mutex);
-       gus->gf1.seq_client = -1;
-       
-       /* allocate new client */
-       client = gus->gf1.seq_client =
-               snd_seq_create_kernel_client(gus->card, 1, gus->interwave ?
-                                            "AMD InterWave" : "GF1");
-       if (client < 0)
-               return client;
-
-       for (i = 0; i < 4; i++)
-               snd_gus_synth_create_port(gus, i);
-               
-       gus->gf1.ilist = snd_seq_instr_list_new();
-       if (gus->gf1.ilist == NULL) {
-               snd_seq_delete_kernel_client(client);   
-               gus->gf1.seq_client = -1;
-               return -ENOMEM;
-       }
-       gus->gf1.ilist->flags = SNDRV_SEQ_INSTR_FLG_DIRECT;
-
-       simpleops = &gus->gf1.simple_ops;
-       snd_seq_simple_init(simpleops, gus, NULL);
-       simpleops->put_sample = snd_gus_simple_put_sample;
-       simpleops->get_sample = snd_gus_simple_get_sample;
-       simpleops->remove_sample = snd_gus_simple_remove_sample;
-       simpleops->notify = snd_gus_synth_instr_notify;
-
-       gf1ops = &gus->gf1.gf1_ops;
-       snd_seq_gf1_init(gf1ops, gus, &simpleops->kops);
-       gf1ops->put_sample = snd_gus_gf1_put_sample;
-       gf1ops->get_sample = snd_gus_gf1_get_sample;
-       gf1ops->remove_sample = snd_gus_gf1_remove_sample;
-       gf1ops->notify = snd_gus_synth_instr_notify;
-
-       iwops = &gus->gf1.iwffff_ops;
-       snd_seq_iwffff_init(iwops, gus, &gf1ops->kops);
-       iwops->put_sample = snd_gus_iwffff_put_sample;
-       iwops->get_sample = snd_gus_iwffff_get_sample;
-       iwops->remove_sample = snd_gus_iwffff_remove_sample;
-       iwops->notify = snd_gus_synth_instr_notify;
-
-       memset(&sub, 0, sizeof(sub));
-       sub.sender.client = SNDRV_SEQ_CLIENT_SYSTEM;
-       sub.sender.port = SNDRV_SEQ_PORT_SYSTEM_ANNOUNCE;
-       sub.dest.client = client;
-       sub.dest.port = 0;
-       snd_seq_kernel_client_ctl(client, SNDRV_SEQ_IOCTL_SUBSCRIBE_PORT, &sub);
-
-       return 0;
-}
-
-static int snd_gus_synth_delete_device(struct snd_seq_device *dev)
-{
-       struct snd_gus_card *gus;
-
-       gus = *(struct snd_gus_card **)SNDRV_SEQ_DEVICE_ARGPTR(dev);
-       if (gus == NULL)
-               return -EINVAL;
-
-       if (gus->gf1.seq_client >= 0) {
-               snd_seq_delete_kernel_client(gus->gf1.seq_client);      
-               gus->gf1.seq_client = -1;
-       }
-       if (gus->gf1.ilist)
-               snd_seq_instr_list_free(&gus->gf1.ilist);
-       return 0;
-}
-
-static int __init alsa_gus_synth_init(void)
-{
-       static struct snd_seq_dev_ops ops = {
-               snd_gus_synth_new_device,
-               snd_gus_synth_delete_device
-       };
-
-       return snd_seq_device_register_driver(SNDRV_SEQ_DEV_ID_GUS, &ops,
-                                             sizeof(struct snd_gus_card *));
-}
-
-static void __exit alsa_gus_synth_exit(void)
-{
-       snd_seq_device_unregister_driver(SNDRV_SEQ_DEV_ID_GUS);
-}
-
-module_init(alsa_gus_synth_init)
-module_exit(alsa_gus_synth_exit)
index 99eac573c41418542da212d6ec0b1a55464d85e9..c53727147a1ac6c9fae64513f7d6ae63ecb91919 100644 (file)
@@ -21,7 +21,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/time.h>
 #include <sound/core.h>
 #include <sound/gus.h>
index e6fd9b01c492dc37b813770e24271db99777e0fb..f0af3f79b08bae4167eb98ed00e9d7b107b5559d 100644 (file)
@@ -19,7 +19,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/time.h>
index 71a67744a14b04905f6a48c0140f2be4d2c80e1b..c3c028a4a46b5a5b7c0b3c25c838a05754b6f4ce 100644 (file)
@@ -18,7 +18,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/time.h>
 #include <sound/core.h>
 #include <sound/gus.h>
index 29e422b00b5801c23087e33319ccf10637cf9129..8f914b37bf8998eaa261127b9dc53901e6b2d8b5 100644 (file)
@@ -19,7 +19,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/err.h>
 #include <linux/isa.h>
index fc59536c918e6fb9982087b08f437ed6b805ceb1..da13185eb0a034852117982d7069b108b0004bd8 100644 (file)
@@ -19,7 +19,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/err.h>
 #include <linux/isa.h>
index 4922f5da08f9d4f5c7b4971c1fcb4e22652fb2f7..f87c6236661c6ea985134dde22d705d52c7b0860 100644 (file)
@@ -19,7 +19,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/err.h>
 #include <linux/isa.h>
index 2091c50b2e3ed179da6c449d96b7e27d3fd94b8a..ca0d7ace0c75abec9a6b9006a716e5cddc4b9a37 100644 (file)
@@ -22,7 +22,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/err.h>
 #include <linux/isa.h>
@@ -560,50 +559,27 @@ static int __devinit snd_interwave_pnp(int dev, struct snd_interwave *iwcard,
                                       const struct pnp_card_device_id *id)
 {
        struct pnp_dev *pdev;
-       struct pnp_resource_table * cfg = kmalloc(sizeof(struct pnp_resource_table), GFP_KERNEL);
        int err;
 
-       if (!cfg)
-               return -ENOMEM;
        iwcard->dev = pnp_request_card_device(card, id->devs[0].id, NULL);
-       if (iwcard->dev == NULL) {
-               kfree(cfg);
+       if (iwcard->dev == NULL)
                return -EBUSY;
-       }
+
 #ifdef SNDRV_STB
        iwcard->devtc = pnp_request_card_device(card, id->devs[1].id, NULL);
-       if (iwcard->devtc == NULL) {
-               kfree(cfg);
+       if (iwcard->devtc == NULL)
                return -EBUSY;
-       }
 #endif
        /* Synth & Codec initialization */
        pdev = iwcard->dev;
-       pnp_init_resource_table(cfg);
-       if (port[dev] != SNDRV_AUTO_PORT) {
-               pnp_resource_change(&cfg->port_resource[0], port[dev], 16);
-               pnp_resource_change(&cfg->port_resource[1], port[dev] + 0x100, 12);
-               pnp_resource_change(&cfg->port_resource[2], port[dev] + 0x10c, 4);
-       }
-       if (dma1[dev] != SNDRV_AUTO_DMA)
-               pnp_resource_change(&cfg->dma_resource[0], dma1[dev], 1);
-       if (dma2[dev] != SNDRV_AUTO_DMA)
-               pnp_resource_change(&cfg->dma_resource[1], dma2[dev], 1);
-       if (dma2[dev] < 0)
-               pnp_resource_change(&cfg->dma_resource[1], 4, 1);
-       if (irq[dev] != SNDRV_AUTO_IRQ)
-               pnp_resource_change(&cfg->irq_resource[0], irq[dev], 1);
-        if (pnp_manual_config_dev(pdev, cfg, 0) < 0)
-               snd_printk(KERN_ERR "InterWave - Synth - the requested resources are invalid, using auto config\n");
+
        err = pnp_activate_dev(pdev);
        if (err < 0) {
-               kfree(cfg);
                snd_printk(KERN_ERR "InterWave PnP configure failure (out of resources?)\n");
                return err;
        }
        if (pnp_port_start(pdev, 0) + 0x100 != pnp_port_start(pdev, 1) ||
            pnp_port_start(pdev, 0) + 0x10c != pnp_port_start(pdev, 2)) {
-               kfree(cfg);
                snd_printk(KERN_ERR "PnP configure failure (wrong ports)\n");
                return -ENOENT;
        }
@@ -620,21 +596,15 @@ static int __devinit snd_interwave_pnp(int dev, struct snd_interwave *iwcard,
 #ifdef SNDRV_STB
        /* Tone Control initialization */
        pdev = iwcard->devtc;
-       pnp_init_resource_table(cfg);
-       if (port_tc[dev] != SNDRV_AUTO_PORT)
-               pnp_resource_change(&cfg->port_resource[0], port_tc[dev], 1);
-        if (pnp_manual_config_dev(pdev, cfg, 0) < 0)
-               snd_printk(KERN_ERR "InterWave - ToneControl - the requested resources are invalid, using auto config\n");
+
        err = pnp_activate_dev(pdev);
        if (err < 0) {
-               kfree(cfg);
                snd_printk(KERN_ERR "InterWave ToneControl PnP configure failure (out of resources?)\n");
                return err;
        }
        port_tc[dev] = pnp_port_start(pdev, 0);
        snd_printdd("isapnp IW: tone control port=0x%lx\n", port_tc[dev]);
 #endif
-       kfree(cfg);
        return 0;
 }
 #endif /* CONFIG_PNP */
index 59af9ab7191fb81d4355b5e58ee61ee5ad2c31a6..854a9f74b46665d0fc6b418e49127fe4086ea25a 100644 (file)
@@ -19,7 +19,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/err.h>
 #include <linux/isa.h>
@@ -610,39 +609,8 @@ static int snd_opl3sa2_resume(struct snd_card *card)
 static int __devinit snd_opl3sa2_pnp(int dev, struct snd_opl3sa2 *chip,
                                     struct pnp_dev *pdev)
 {
-       struct pnp_resource_table * cfg;
-       int err;
-
-       cfg = kmalloc(sizeof(struct pnp_resource_table), GFP_KERNEL);
-       if (!cfg) {
-               snd_printk(KERN_ERR PFX "cannot allocate pnp cfg\n");
-               return -ENOMEM;
-       }
-       /* PnP initialization */
-       pnp_init_resource_table(cfg);
-       if (sb_port[dev] != SNDRV_AUTO_PORT)
-               pnp_resource_change(&cfg->port_resource[0], sb_port[dev], 16);
-       if (wss_port[dev] != SNDRV_AUTO_PORT)
-               pnp_resource_change(&cfg->port_resource[1], wss_port[dev], 8);
-       if (fm_port[dev] != SNDRV_AUTO_PORT)
-               pnp_resource_change(&cfg->port_resource[2], fm_port[dev], 4);
-       if (midi_port[dev] != SNDRV_AUTO_PORT)
-               pnp_resource_change(&cfg->port_resource[3], midi_port[dev], 2);
-       if (port[dev] != SNDRV_AUTO_PORT)
-               pnp_resource_change(&cfg->port_resource[4], port[dev], 2);
-       if (dma1[dev] != SNDRV_AUTO_DMA)
-               pnp_resource_change(&cfg->dma_resource[0], dma1[dev], 1);
-       if (dma2[dev] != SNDRV_AUTO_DMA)
-               pnp_resource_change(&cfg->dma_resource[1], dma2[dev], 1);
-       if (irq[dev] != SNDRV_AUTO_IRQ)
-               pnp_resource_change(&cfg->irq_resource[0], irq[dev], 1);
-       err = pnp_manual_config_dev(pdev, cfg, 0);
-       if (err < 0)
-               snd_printk(KERN_WARNING "PnP manual resources are invalid, using auto config\n");
-       err = pnp_activate_dev(pdev);
-       if (err < 0) {
-               kfree(cfg);
-               snd_printk(KERN_ERR "PnP configure failure (out of resources?) err = %d\n", err);
+       if (pnp_activate_dev(pdev) < 0) {
+               snd_printk(KERN_ERR "PnP configure failure (out of resources?)\n");
                return -EBUSY;
        }
        sb_port[dev] = pnp_port_start(pdev, 0);
@@ -657,7 +625,6 @@ static int __devinit snd_opl3sa2_pnp(int dev, struct snd_opl3sa2 *chip,
                pnp_device_is_pnpbios(pdev) ? "BIOS" : "ISA", sb_port[dev], wss_port[dev], fm_port[dev], midi_port[dev]);
        snd_printdd("%sPnP OPL3-SA: control port=0x%lx, dma1=%i, dma2=%i, irq=%i\n",
                pnp_device_is_pnpbios(pdev) ? "BIOS" : "ISA", port[dev], dma1[dev], dma2[dev], irq[dev]);
-       kfree(cfg);
        return 0;
 }
 #endif /* CONFIG_PNP */
index d295936611f83b696dfedf87b6aa396a1c80981d..2a1e2f5d12c2abe78e99192d31c14d39b55b7f13 100644 (file)
@@ -22,7 +22,6 @@
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/err.h>
 #include <linux/isa.h>
@@ -483,6 +482,10 @@ static int snd_miro_put_double(struct snd_kcontrol *kcontrol,
 
                /* equalizer elements */
 
+               if (left < -0x7f || left > 0x7f ||
+                   right < -0x7f || right > 0x7f)
+                       return -EINVAL;
+
                if (left_old > 0x80) 
                        left_old = 0x80 - left_old;
                if (right_old > 0x80) 
@@ -520,6 +523,10 @@ static int snd_miro_put_double(struct snd_kcontrol *kcontrol,
 
                /* non-equalizer elements */
 
+               if (left < 0 || left > 0x20 ||
+                   right < 0 || right > 0x20)
+                       return -EINVAL;
+
                left_old = 0x20 - left_old;
                right_old = 0x20 - right_old;
 
@@ -662,7 +669,7 @@ static int __devinit snd_set_aci_init_values(struct snd_miro *miro)
        return 0;
 }
 
-static int snd_miro_mixer(struct snd_miro *miro)
+static int __devinit snd_miro_mixer(struct snd_miro *miro)
 {
        struct snd_card *card;
        unsigned int idx;
index ee1a824d8fc0c388284fa28caae16891a6effcb5..fe1afc13a01d4bdf6a373a40611f24e734788dcf 100644 (file)
@@ -23,7 +23,6 @@
 */
 
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/err.h>
 #include <linux/isa.h>
@@ -1595,7 +1594,7 @@ OPTi93X_DOUBLE("Capture Volume", 0, OPTi93X_MIXOUT_LEFT, OPTi93X_MIXOUT_RIGHT, 0
 }
 };
                                         
-static int snd_opti93x_mixer(struct snd_opti93x *chip)
+static int __devinit snd_opti93x_mixer(struct snd_opti93x *chip)
 {
        struct snd_card *card;
        struct snd_kcontrol_new knew;
@@ -1690,53 +1689,19 @@ static int __devinit snd_card_opti9xx_pnp(struct snd_opti9xx *chip,
                                          const struct pnp_card_device_id *pid)
 {
        struct pnp_dev *pdev;
-       struct pnp_resource_table *cfg = kmalloc(sizeof(*cfg), GFP_KERNEL);
        int err;
 
-       if (!cfg)
-               return -ENOMEM;
        chip->dev = pnp_request_card_device(card, pid->devs[0].id, NULL);
-       if (chip->dev == NULL) {
-               kfree(cfg);
+       if (chip->dev == NULL)
                return -EBUSY;
-       }
+
        chip->devmpu = pnp_request_card_device(card, pid->devs[1].id, NULL);
 
        pdev = chip->dev;
-       pnp_init_resource_table(cfg);
 
-#ifdef OPTi93X
-       if (port != SNDRV_AUTO_PORT)
-               pnp_resource_change(&cfg->port_resource[0], port + 4, 4);
-#else
-       if (pid->driver_data != 0x0924 && port != SNDRV_AUTO_PORT)
-               pnp_resource_change(&cfg->port_resource[1], port, 4);
-#endif /* OPTi93X */
-       if (irq != SNDRV_AUTO_IRQ)
-               pnp_resource_change(&cfg->irq_resource[0], irq, 1);
-       if (dma1 != SNDRV_AUTO_DMA)
-               pnp_resource_change(&cfg->dma_resource[0], dma1, 1);
-#if defined(CS4231) || defined(OPTi93X)
-       if (dma2 != SNDRV_AUTO_DMA)
-               pnp_resource_change(&cfg->dma_resource[1], dma2, 1);
-#else
-#ifdef snd_opti9xx_fixup_dma2
-       snd_opti9xx_fixup_dma2(pdev);
-#endif
-#endif /* CS4231 || OPTi93X */
-#ifdef OPTi93X
-       if (fm_port > 0 && fm_port != SNDRV_AUTO_PORT)
-               pnp_resource_change(&cfg->port_resource[1], fm_port, 4);
-#else
-       if (fm_port > 0 && fm_port != SNDRV_AUTO_PORT)
-               pnp_resource_change(&cfg->port_resource[2], fm_port, 4);
-#endif
-       if (pnp_manual_config_dev(pdev, cfg, 0) < 0)
-               snd_printk(KERN_ERR "AUDIO the requested resources are invalid, using auto config\n");
        err = pnp_activate_dev(pdev);
        if (err < 0) {
                snd_printk(KERN_ERR "AUDIO pnp configure failure: %d\n", err);
-               kfree(cfg);
                return err;
        }
 
@@ -1756,15 +1721,6 @@ static int __devinit snd_card_opti9xx_pnp(struct snd_opti9xx *chip,
 
        pdev = chip->devmpu;
        if (pdev && mpu_port > 0) {
-               pnp_init_resource_table(cfg);
-
-               if (mpu_port != SNDRV_AUTO_PORT)
-                       pnp_resource_change(&cfg->port_resource[0], mpu_port, 2);
-               if (mpu_irq != SNDRV_AUTO_IRQ)
-                       pnp_resource_change(&cfg->irq_resource[0], mpu_irq, 1);
-
-               if (pnp_manual_config_dev(pdev, cfg, 0) < 0)
-                       snd_printk(KERN_ERR "AUDIO the requested resources are invalid, using auto config\n");
                err = pnp_activate_dev(pdev);
                if (err < 0) {
                        snd_printk(KERN_ERR "AUDIO pnp configure failure\n");
@@ -1775,7 +1731,6 @@ static int __devinit snd_card_opti9xx_pnp(struct snd_opti9xx *chip,
                        mpu_irq = pnp_irq(pdev, 0);
                }
        }
-       kfree(cfg);
        return pid->driver_data;
 }
 #endif /* CONFIG_PNP */
index 4eea84cfd4f4b703b5e6dd6f5bb86f230e091ae2..b35be7d9a9fa8b4a70e1037534c2e8bd0b821d9f 100644 (file)
@@ -20,7 +20,6 @@
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-#include <sound/driver.h>
 #include <linux/wait.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
index 2ac77f10bb4e4e56b81b7f170eaa64d9aee972bf..7e87c349272ff20fa31f1f306832a853df93098f 100644 (file)
@@ -21,7 +21,6 @@
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-#include <sound/driver.h>
 #include <linux/wait.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
index d4b218726ce75b02b186ff543d37d487ea32d744..c8c8e214c843421a6288a30b8634cf5a76138134 100644 (file)
@@ -20,7 +20,6 @@
     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 */
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/time.h>
 #include <linux/pnp.h>
@@ -49,12 +48,6 @@ module_param_array(id, charp, NULL, 0444);
 MODULE_PARM_DESC(id, "ID string for es968 based soundcard.");
 module_param_array(enable, bool, NULL, 0444);
 MODULE_PARM_DESC(enable, "Enable es968 based soundcard.");
-module_param_array(port, long, NULL, 0444);
-MODULE_PARM_DESC(port, "Port # for es968 driver.");
-module_param_array(irq, int, NULL, 0444);
-MODULE_PARM_DESC(irq, "IRQ # for es968 driver.");
-module_param_array(dma8, int, NULL, 0444);
-MODULE_PARM_DESC(dma8, "8-bit DMA # for es968 driver.");
 
 struct snd_card_es968 {
        struct pnp_dev *dev;
@@ -86,40 +79,23 @@ static int __devinit snd_card_es968_pnp(int dev, struct snd_card_es968 *acard,
                                        const struct pnp_card_device_id *id)
 {
        struct pnp_dev *pdev;
-       struct pnp_resource_table *cfg = kmalloc(sizeof(*cfg), GFP_KERNEL);
        int err;
-       if (!cfg)
-               return -ENOMEM;
+
        acard->dev = pnp_request_card_device(card, id->devs[0].id, NULL);
-       if (acard->dev == NULL) {
-               kfree(cfg);
+       if (acard->dev == NULL)
                return -ENODEV;
-       }
 
        pdev = acard->dev;
 
-       pnp_init_resource_table(cfg);
-
-       /* override resources */
-       if (port[dev] != SNDRV_AUTO_PORT)
-               pnp_resource_change(&cfg->port_resource[0], port[dev], 16);
-       if (dma8[dev] != SNDRV_AUTO_DMA)
-               pnp_resource_change(&cfg->dma_resource[0], dma8[dev], 1);
-       if (irq[dev] != SNDRV_AUTO_IRQ)
-               pnp_resource_change(&cfg->irq_resource[0], irq[dev], 1);
-       if ((pnp_manual_config_dev(pdev, cfg, 0)) < 0)
-               snd_printk(KERN_ERR PFX "AUDIO the requested resources are invalid, using auto config\n");
        err = pnp_activate_dev(pdev);
        if (err < 0) {
                snd_printk(KERN_ERR PFX "AUDIO pnp configure failure\n");
-               kfree(cfg);
                return err;
        }
        port[dev] = pnp_port_start(pdev, 0);
        dma8[dev] = pnp_dma(pdev, 1);
        irq[dev] = pnp_irq(pdev, 0);
 
-       kfree(cfg);
        return 0;
 }
 
index e7f9edd92626f824c1f6adbe05540a062f7523a1..2c201f78ce50a0abd79238c51d81e8f8b8482952 100644 (file)
@@ -19,7 +19,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <asm/dma.h>
 #include <linux/init.h>
 #include <linux/slab.h>
@@ -257,44 +256,21 @@ static int __devinit snd_card_sb16_pnp(int dev, struct snd_card_sb16 *acard,
                                       const struct pnp_card_device_id *id)
 {
        struct pnp_dev *pdev;
-       struct pnp_resource_table * cfg = kmalloc(sizeof(struct pnp_resource_table), GFP_KERNEL);
        int err;
 
-       if (!cfg) 
-               return -ENOMEM; 
        acard->dev = pnp_request_card_device(card, id->devs[0].id, NULL);
-       if (acard->dev == NULL) { 
-               kfree(cfg); 
+       if (acard->dev == NULL)
                return -ENODEV; 
-       } 
+
 #ifdef SNDRV_SBAWE_EMU8000
        acard->devwt = pnp_request_card_device(card, id->devs[1].id, acard->dev);
 #endif
        /* Audio initialization */
        pdev = acard->dev;
 
-       pnp_init_resource_table(cfg); 
-        
-       /* override resources */ 
-
-       if (port[dev] != SNDRV_AUTO_PORT)
-               pnp_resource_change(&cfg->port_resource[0], port[dev], 16);
-       if (mpu_port[dev] != SNDRV_AUTO_PORT)
-               pnp_resource_change(&cfg->port_resource[1], mpu_port[dev], 2);
-       if (fm_port[dev] != SNDRV_AUTO_PORT)
-               pnp_resource_change(&cfg->port_resource[2], fm_port[dev], 4);
-       if (dma8[dev] != SNDRV_AUTO_DMA)
-               pnp_resource_change(&cfg->dma_resource[0], dma8[dev], 1);
-       if (dma16[dev] != SNDRV_AUTO_DMA)
-               pnp_resource_change(&cfg->dma_resource[1], dma16[dev], 1);
-       if (irq[dev] != SNDRV_AUTO_IRQ)
-               pnp_resource_change(&cfg->irq_resource[0], irq[dev], 1);
-       if (pnp_manual_config_dev(pdev, cfg, 0) < 0) 
-               snd_printk(KERN_ERR PFX "AUDIO the requested resources are invalid, using auto config\n"); 
        err = pnp_activate_dev(pdev); 
        if (err < 0) { 
                snd_printk(KERN_ERR PFX "AUDIO pnp configure failure\n"); 
-               kfree(cfg);
                return err; 
        } 
        port[dev] = pnp_port_start(pdev, 0);
@@ -311,17 +287,6 @@ static int __devinit snd_card_sb16_pnp(int dev, struct snd_card_sb16 *acard,
        /* WaveTable initialization */
        pdev = acard->devwt;
        if (pdev != NULL) {
-               pnp_init_resource_table(cfg); 
-        
-               /* override resources */ 
-
-               if (awe_port[dev] != SNDRV_AUTO_PORT) {
-                       pnp_resource_change(&cfg->port_resource[0], awe_port[dev], 4);
-                       pnp_resource_change(&cfg->port_resource[1], awe_port[dev] + 0x400, 4);
-                       pnp_resource_change(&cfg->port_resource[2], awe_port[dev] + 0x800, 4);
-               }
-               if ((pnp_manual_config_dev(pdev, cfg, 0)) < 0) 
-                       snd_printk(KERN_ERR PFX "WaveTable the requested resources are invalid, using auto config\n"); 
                err = pnp_activate_dev(pdev); 
                if (err < 0) { 
                        goto __wt_error; 
@@ -339,7 +304,6 @@ __wt_error:
                awe_port[dev] = -1;
        }
 #endif
-       kfree(cfg);
        return 0;
 }
 
index 3682059787abec3639a36574e7c779dccae4dcb5..bed29ca22239edd7f1f47335da7797a100ffec6f 100644 (file)
@@ -23,7 +23,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/slab.h>
@@ -118,7 +117,8 @@ static void info_read(struct snd_info_entry *entry, struct snd_info_buffer *buff
 int snd_sb_csp_new(struct snd_sb *chip, int device, struct snd_hwdep ** rhwdep)
 {
        struct snd_sb_csp *p;
-       int version, err;
+       int uninitialized_var(version);
+       int err;
        struct snd_hwdep *hw;
 
        if (rhwdep)
index c06754f7ee5df2d880c7d2dfaacf947eba8014c0..f7e8192270ae1796a302b1893f3b18136a1f8bee 100644 (file)
@@ -33,7 +33,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <asm/io.h>
 #include <asm/dma.h>
 #include <linux/init.h>
index f933aef7d8a95aacd850e88e97f8e5717b4c201c..336a34277907f0ec74b30816187eb3d14c7909d3 100644 (file)
@@ -19,7 +19,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/err.h>
 #include <linux/isa.h>
index bee894b3f5c7e245f056769c0a4ea4d1bffaea0a..6304c3a89ba0650b5a644c555f81dfded2cd2620 100644 (file)
@@ -30,7 +30,6 @@
  *   Cleaned up and rewrote lowlevel routines.
  */
 
-#include <sound/driver.h>
 #include <asm/io.h>
 #include <asm/dma.h>
 #include <linux/init.h>
index e56e5633411cd4e728bb8db2b366e3c432ce0396..988a8b73475f26f65e1f7f8bbb344cfff16532ba 100644 (file)
@@ -26,7 +26,6 @@
  *   Added full duplex UART mode for DSP version 2.0 and later.
  */
 
-#include <sound/driver.h>
 #include <asm/io.h>
 #include <linux/time.h>
 #include <sound/core.h>
index 176193c05101007dae7b8c08d086da1632c7168f..d63c1af550de5789949b7df6e11bd78082e71fa1 100644 (file)
@@ -20,7 +20,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
index 03241cd5aaef253f3953e8ba74cdbdcccabfddde..91d14224f6b332de1119d89bc07bff76c00f37cc 100644 (file)
@@ -19,7 +19,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <asm/io.h>
 #include <linux/delay.h>
 #include <linux/time.h>
index 94daf839999463e17808768115a180a1dc2f6046..da3d152bcad4d0b5bd7d29b2c1ee1cb5104eaf7a 100644 (file)
@@ -23,7 +23,6 @@
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-#include <sound/driver.h>
 #include <linux/module.h>
 #include <linux/delay.h>
 #include <linux/isa.h>
@@ -390,7 +389,7 @@ static int __devinit sc6000_init_board(char __iomem *vport, int irq, int dma,
 
        err = sc6000_init_mss(vport, config, vmss_port, mss_config);
        if (err < 0) {
-               snd_printk(KERN_ERR "Can not initialize"
+               snd_printk(KERN_ERR "Can not initialize "
                           "Microsoft Sound System mode.\n");
                return -ENODEV;
        }
index 922519def0997f2ff21ee74fc84ecb073012411c..a07274ecb1494b0b6948533edb15faac3e926dea 100644 (file)
@@ -21,7 +21,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/err.h>
 #include <linux/isa.h>
index 1cb921d6137ebb81b52de249f36bf789d0a08823..06ad7863dff577362c0af9dacafbc5fd6f964f8b 100644 (file)
@@ -21,7 +21,6 @@
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/err.h>
 #include <linux/isa.h>
index 83c2fc4cfc64fb1bfc7bdde14e4f3623927ce452..3a6c6fe1ec4d08bed3ff505e84e7a6a5aa8909c3 100644 (file)
@@ -19,7 +19,6 @@
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/slab.h>
@@ -104,21 +103,15 @@ snd_wavefront_pnp (int dev, snd_wavefront_card_t *acard, struct pnp_card_link *c
                   const struct pnp_card_device_id *id)
 {
        struct pnp_dev *pdev;
-       struct pnp_resource_table *cfg = kmalloc(sizeof(*cfg), GFP_KERNEL);
        int err;
 
-       if (!cfg)
-               return -ENOMEM;
-
        /* Check for each logical device. */
 
        /* CS4232 chip (aka "windows sound system") is logical device 0 */
 
        acard->wss = pnp_request_card_device(card, id->devs[0].id, NULL);
-       if (acard->wss == NULL) {
-               kfree(cfg);
+       if (acard->wss == NULL)
                return -EBUSY;
-       }
 
        /* there is a game port at logical device 1, but we ignore it completely */
 
@@ -133,26 +126,20 @@ snd_wavefront_pnp (int dev, snd_wavefront_card_t *acard, struct pnp_card_link *c
 
        if (use_cs4232_midi[dev]) {
                acard->mpu = pnp_request_card_device(card, id->devs[2].id, NULL);
-               if (acard->mpu == NULL) {
-                       kfree(cfg);
+               if (acard->mpu == NULL)
                        return -EBUSY;
-               }
        }
 
        /* The ICS2115 synth is logical device 4 */
 
        acard->synth = pnp_request_card_device(card, id->devs[3].id, NULL);
-       if (acard->synth == NULL) {
-               kfree(cfg);
+       if (acard->synth == NULL)
                return -EBUSY;
-       }
 
        /* PCM/FM initialization */
 
        pdev = acard->wss;
 
-       pnp_init_resource_table(cfg);
-
        /* An interesting note from the Tropez+ FAQ:
 
           Q. [Ports] Why is the base address of the WSS I/O ports off by 4?
@@ -165,23 +152,9 @@ snd_wavefront_pnp (int dev, snd_wavefront_card_t *acard, struct pnp_card_link *c
 
        */
 
-       if (cs4232_pcm_port[dev] != SNDRV_AUTO_PORT)
-               pnp_resource_change(&cfg->port_resource[0], cs4232_pcm_port[dev], 4);
-       if (fm_port[dev] != SNDRV_AUTO_PORT)
-               pnp_resource_change(&cfg->port_resource[1], fm_port[dev], 4);
-       if (dma1[dev] != SNDRV_AUTO_DMA)
-               pnp_resource_change(&cfg->dma_resource[0], dma1[dev], 1);
-       if (dma2[dev] != SNDRV_AUTO_DMA)
-               pnp_resource_change(&cfg->dma_resource[1], dma2[dev], 1);
-       if (cs4232_pcm_irq[dev] != SNDRV_AUTO_IRQ)
-               pnp_resource_change(&cfg->irq_resource[0], cs4232_pcm_irq[dev], 1);
-
-       if (pnp_manual_config_dev(pdev, cfg, 0) < 0)
-               snd_printk(KERN_ERR "PnP WSS the requested resources are invalid, using auto config\n");
        err = pnp_activate_dev(pdev);
        if (err < 0) {
                snd_printk(KERN_ERR "PnP WSS pnp configure failure\n");
-               kfree(cfg);
                return err;
        }
 
@@ -195,22 +168,9 @@ snd_wavefront_pnp (int dev, snd_wavefront_card_t *acard, struct pnp_card_link *c
 
        pdev = acard->synth;
        
-       pnp_init_resource_table(cfg);
-
-       if (ics2115_port[dev] != SNDRV_AUTO_PORT) {
-               pnp_resource_change(&cfg->port_resource[0], ics2115_port[dev], 16);
-       }
-               
-       if (ics2115_port[dev] != SNDRV_AUTO_IRQ) {
-               pnp_resource_change(&cfg->irq_resource[0], ics2115_irq[dev], 1);
-       }
-
-       if (pnp_manual_config_dev(pdev, cfg, 0) < 0)
-               snd_printk(KERN_ERR "PnP ICS2115 the requested resources are invalid, using auto config\n");
        err = pnp_activate_dev(pdev);
        if (err < 0) {
                snd_printk(KERN_ERR "PnP ICS2115 pnp configure failure\n");
-               kfree(cfg);
                return err;
        }
 
@@ -226,15 +186,6 @@ snd_wavefront_pnp (int dev, snd_wavefront_card_t *acard, struct pnp_card_link *c
 
                pdev = acard->mpu;
 
-               pnp_init_resource_table(cfg);
-
-               if (cs4232_mpu_port[dev] != SNDRV_AUTO_PORT)
-                       pnp_resource_change(&cfg->port_resource[0], cs4232_mpu_port[dev], 2);
-               if (cs4232_mpu_irq[dev] != SNDRV_AUTO_IRQ)
-                       pnp_resource_change(&cfg->port_resource[0], cs4232_mpu_irq[dev], 1);
-
-               if (pnp_manual_config_dev(pdev, cfg, 0) < 0)
-                       snd_printk(KERN_ERR "PnP MPU401 the requested resources are invalid, using auto config\n");
                err = pnp_activate_dev(pdev);
                if (err < 0) {
                        snd_printk(KERN_ERR "PnP MPU401 pnp configure failure\n");
@@ -258,7 +209,6 @@ snd_wavefront_pnp (int dev, snd_wavefront_card_t *acard, struct pnp_card_link *c
                    ics2115_port[dev], 
                    ics2115_irq[dev]);
        
-       kfree(cfg);
        return 0;
 }
 
index fc95a870f69017aa17cf20f175633abb0d1af8d1..2efaa7f205aa617f56c64db3e26f3e279db25246 100644 (file)
@@ -16,7 +16,6 @@
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-#include <sound/driver.h>
 #include <asm/io.h>
 #include <linux/init.h>
 #include <linux/time.h>
index cb3460094324db8f34069fc18485148a54232b39..a33384a55b0f6576d1a71320d8f68b33a1c622c4 100644 (file)
@@ -47,7 +47,6 @@
  *  
  */
 
-#include <sound/driver.h>
 #include <asm/io.h>
 #include <linux/init.h>
 #include <linux/time.h>
index a1ebb7c5c684815f7d17d91a7ba739c6577e1bbc..95eeca163354b5303b89554bdeafb8053bc54fcd 100644 (file)
@@ -20,7 +20,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <asm/io.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
index 282b0cdb0589fbc60984d9ac9d7ae44b681a2d61..bdd0857b88710bb4fb2489766bcb4ea3fa26b79e 100644 (file)
@@ -20,7 +20,6 @@
  */
 
 #define SNDRV_MAIN_OBJECT_FILE
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <sound/core.h>
 
index 24460a558bf75eaf98d8e70a76c411fc54c34525..ee0741f9eb5322c26f782a9fe59460db1568b1cf 100644 (file)
@@ -36,7 +36,6 @@
 
 #include <linux/ioport.h>
 #include <linux/interrupt.h>
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/version.h>
index 5d3c0372df3289211223afe4968ff50eb4109cbb..f95aa0946758eddee10d995cc233d05005a8ae71 100644 (file)
@@ -2104,6 +2104,7 @@ static struct page * via_mm_nopage (struct vm_area_struct * vma,
 {
        struct via_info *card = vma->vm_private_data;
        struct via_channel *chan = &card->ch_out;
+       unsigned long max_bufs;
        struct page *dmapage;
        unsigned long pgoff;
        int rd, wr;
@@ -2127,14 +2128,11 @@ static struct page * via_mm_nopage (struct vm_area_struct * vma,
        rd = card->ch_in.is_mapped;
        wr = card->ch_out.is_mapped;
 
-#ifndef VIA_NDEBUG
-       {
-       unsigned long max_bufs = chan->frag_number;
-       if (rd && wr) max_bufs *= 2;
-       /* via_dsp_mmap() should ensure this */
-       assert (pgoff < max_bufs);
-       }
-#endif
+       max_bufs = chan->frag_number;
+       if (rd && wr)
+               max_bufs *= 2;
+       if (pgoff >= max_bufs)
+               return NOPAGE_SIGBUS;
 
        /* if full-duplex (read+write) and we have two sets of bufs,
         * then the playback buffers come first, sez soundcard.c */
index ff705c63a03a2f0292438a380e11b2f76212de22..99f5483abf2e7efb006a01928edb3b64d0dcf886 100644 (file)
@@ -45,7 +45,6 @@
 #include <linux/spinlock.h>
 #include <linux/dma-mapping.h>
 
-#include <sound/driver.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/control.h>
index 356bf21a15060219077a255bf4b8b0afd81e29c7..812085d521f12405867dd4c70096b49b8ef79212 100644 (file)
@@ -183,6 +183,30 @@ config SND_CMIPCI
          To compile this driver as a module, choose M here: the module
          will be called snd-cmipci.
 
+config SND_OXYGEN_LIB
+        tristate
+       depends on SND
+       select SND_PCM
+       select SND_MPU401_UART
+
+config SND_OXYGEN
+       tristate "C-Media 8788 (Oxygen)"
+       depends on SND
+       select SND_OXYGEN_LIB
+       help
+         Say Y here to include support for sound cards based on the
+         C-Media CMI8788 (Oxygen HD Audio) chip:
+          * Asound A-8788
+          * AuzenTech X-Meridian
+          * Bgears b-Enspirer
+          * Club3D Theatron DTS
+          * HT-Omega Claro
+          * Razer Barracuda AC-1
+          * Sondigo Inferno
+
+         To compile this driver as a module, choose M here: the module
+         will be called snd-oxygen.
+
 config SND_CS4281
        tristate "Cirrus Logic (Sound Fusion) CS4281"
        depends on SND
@@ -623,6 +647,17 @@ config SND_HDSPM
          To compile this driver as a module, choose M here: the module
          will be called snd-hdspm.
 
+config SND_HIFIER
+       tristate "TempoTec HiFier Fantasia"
+       depends on SND
+       select SND_OXYGEN_LIB
+       help
+         Say Y here to include support for the MediaTek/TempoTec HiFier
+         Fantasia sound card.
+
+         To compile this driver as a module, choose M here: the module
+         will be called snd-hifier.
+
 config SND_ICE1712
        tristate "ICEnsemble ICE1712 (Envy24)"
        depends on SND
@@ -802,6 +837,16 @@ config SND_RME9652
          To compile this driver as a module, choose M here: the module
          will be called snd-rme9652.
 
+config SND_SIS7019
+       tristate "SiS 7019 Audio Accelerator"
+       depends on SND && X86 && !X86_64
+       select SND_AC97_CODEC
+       help
+         Say Y here to include support for the SiS 7019 Audio Accelerator.
+
+         To compile this driver as a module, choose M here: the module
+         will be called snd-sis7019.
+
 config SND_SONICVIBES
        tristate "S3 SonicVibes"
        depends on SND
@@ -850,6 +895,17 @@ config SND_VIA82XX_MODEM
          To compile this driver as a module, choose M here: the module
          will be called snd-via82xx-modem.
 
+config SND_VIRTUOSO
+       tristate "Asus Virtuoso 200 (Xonar)"
+       depends on SND
+       select SND_OXYGEN_LIB
+       help
+         Say Y here to include support for sound cards based on the
+         Asus AV200 chip, i.e., Xonar D2 and Xonar D2X.
+
+         To compile this driver as a module, choose M here: the module
+         will be called snd-virtuoso.
+
 config SND_VX222
        tristate "Digigram VX222"
        depends on SND
index 09ddc82eeca22130b17a4597e583868cad93cbd7..2d42fd28f4e7950305d80d930569dfd759818b56 100644 (file)
@@ -23,6 +23,7 @@ snd-intel8x0m-objs := intel8x0m.o
 snd-maestro3-objs := maestro3.o
 snd-rme32-objs := rme32.o
 snd-rme96-objs := rme96.o
+snd-sis7019-objs := sis7019.o
 snd-sonicvibes-objs := sonicvibes.o
 snd-via82xx-objs := via82xx.o
 snd-via82xx-modem-objs := via82xx_modem.o
@@ -48,6 +49,7 @@ obj-$(CONFIG_SND_INTEL8X0M) += snd-intel8x0m.o
 obj-$(CONFIG_SND_MAESTRO3) += snd-maestro3.o
 obj-$(CONFIG_SND_RME32) += snd-rme32.o
 obj-$(CONFIG_SND_RME96) += snd-rme96.o
+obj-$(CONFIG_SND_SIS7019) += snd-sis7019.o
 obj-$(CONFIG_SND_SONICVIBES) += snd-sonicvibes.o
 obj-$(CONFIG_SND_VIA82XX) += snd-via82xx.o
 obj-$(CONFIG_SND_VIA82XX_MODEM) += snd-via82xx-modem.o
@@ -66,6 +68,7 @@ obj-$(CONFIG_SND) += \
        korg1212/ \
        mixart/ \
        nm256/ \
+       oxygen/ \
        pcxhr/ \
        riptide/ \
        rme9652/ \
index 6a9966df0cc907c8d30268734be09485b429590a..45fd29017ddd59ded7e731ece20c977a4a4bde20 100644 (file)
@@ -22,7 +22,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/slab.h>
index 98c8b727b62b8c006f040a711125cac1f2a50ba6..50c637e55ffa63ef544646fae65e62a29b049c7b 100644 (file)
@@ -133,6 +133,14 @@ static int ac97_channel_mode_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e
        struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol);
        unsigned char mode = ucontrol->value.enumerated.item[0];
 
+       if (kcontrol->private_value) {
+               if (mode >= 2)
+                       return -EINVAL;
+       } else {
+               if (mode >= 3)
+                       return -EINVAL;
+       }
+
        if (mode != ac97->channel_mode) {
                ac97->channel_mode = mode;
                if (ac97->build_ops->update_jacks)
@@ -2142,8 +2150,7 @@ static int snd_ac97_ad1985_vrefout_put(struct snd_kcontrol *kcontrol,
        struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol);
        unsigned short val;
 
-       if (ucontrol->value.enumerated.item[0] > 3
-           || ucontrol->value.enumerated.item[0] < 0)
+       if (ucontrol->value.enumerated.item[0] > 3)
                return -EINVAL;
        val = ctrl2reg[ucontrol->value.enumerated.item[0]]
              << AC97_AD198X_VREF_SHIFT;
index 9cccc27ea1b58b3ec33a72089653acbe9ce00922..47bf8dfe82768fe1c0b9338f7a9f10dd2cc2124e 100644 (file)
@@ -83,8 +83,10 @@ static int snd_ac97_swap_ctl(struct snd_ac97 *ac97, const char *s1,
                             const char *s2, const char *suffix);
 static void snd_ac97_rename_vol_ctl(struct snd_ac97 *ac97, const char *src,
                                    const char *dst);
+#ifdef CONFIG_PM
 static void snd_ac97_restore_status(struct snd_ac97 *ac97);
 static void snd_ac97_restore_iec958(struct snd_ac97 *ac97);
+#endif
 static int snd_ac97_info_enum_double(struct snd_kcontrol *kcontrol,
                                     struct snd_ctl_elem_info *uinfo);
 static int snd_ac97_get_enum_double(struct snd_kcontrol *kcontrol,
index 8cbc03332b013e4c630a1a15c915b4e0dbab4b10..3674f35c4a791eaf04a6d2ae86b79e82978d028b 100644 (file)
@@ -23,7 +23,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/slab.h>
index fed4a2c3d8a1689157efc85b7cf12f69558e0b73..060ea59d5f02f02e74c06b28c68a5c37fb0a7446 100644 (file)
@@ -22,7 +22,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/slab.h>
 #include <linux/mutex.h>
 
index 722de451d15fcedc331e290c5e6eda589fea5e2e..c0c1633999eaf60567d0f41752d3528312561e71 100644 (file)
@@ -19,7 +19,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/slab.h>
index 98970d401be9872be2eb61d3b4f1148da97d80e7..a66d5150bb7ac3ddf437588cf99ff726b5adbca2 100644 (file)
@@ -40,7 +40,6 @@
 #include <linux/compiler.h>
 #include <linux/delay.h>
 
-#include <sound/driver.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/initval.h>
@@ -1055,7 +1054,7 @@ static struct pci_device_id snd_ad1889_ids[] = {
 };
 MODULE_DEVICE_TABLE(pci, snd_ad1889_ids);
 
-static struct pci_driver ad1889_pci = {
+static struct pci_driver ad1889_pci_driver = {
        .name = "AD1889 Audio",
        .id_table = snd_ad1889_ids,
        .probe = snd_ad1889_probe,
@@ -1065,13 +1064,13 @@ static struct pci_driver ad1889_pci = {
 static int __init
 alsa_ad1889_init(void)
 {
-       return pci_register_driver(&ad1889_pci);
+       return pci_register_driver(&ad1889_pci_driver);
 }
 
 static void __exit
 alsa_ad1889_fini(void)
 {
-       pci_unregister_driver(&ad1889_pci);
+       pci_unregister_driver(&ad1889_pci_driver);
 }
 
 module_init(alsa_ad1889_init);
index 4c2bd7adf6748215588add8a700e919b9df90a79..6a905ed9cbd6e6f964db82cf2816888508624b5f 100644 (file)
@@ -25,7 +25,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <asm/io.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
index 48cc39b771d9c12244ae452c10e29b8dccfb2988..0e990a7358211f4e80af8e376f0e76899bb0c326 100644 (file)
@@ -30,7 +30,6 @@
  *  to keep track of what period we are in.
  */
 
-#include <sound/driver.h>
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/moduleparam.h>
index 1190ef366a41930bff260d56b13c70248b8af900..27ce6136ab009e66052026fdc038bd449a138b02 100644 (file)
@@ -63,7 +63,6 @@
  * - power management? (card can do voice wakeup according to datasheet!!)
  */
 
-#include <sound/driver.h>
 #include <asm/io.h>
 #include <linux/init.h>
 #include <linux/pci.h>
index 89184a424140232e91f0c832360593fbda21a5fe..4594186b83ee7bfb4b157b6eff9e2aba79aa0916 100644 (file)
@@ -19,7 +19,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <asm/io.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
@@ -560,7 +559,7 @@ static int snd_atiixp_aclink_down(struct atiixp *chip)
             ATI_REG_ISR_CODEC2_NOT_READY)
 #define CODEC_CHECK_BITS (ALL_CODEC_NOT_READY|ATI_REG_ISR_NEW_FRAME)
 
-static int ac97_probing_bugs(struct pci_dev *pci)
+static int __devinit ac97_probing_bugs(struct pci_dev *pci)
 {
        const struct snd_pci_quirk *q;
 
@@ -574,7 +573,7 @@ static int ac97_probing_bugs(struct pci_dev *pci)
        return -1;
 }
 
-static int snd_atiixp_codec_detect(struct atiixp *chip)
+static int __devinit snd_atiixp_codec_detect(struct atiixp *chip)
 {
        int timeout;
 
index ce752f84457ad6ee9b6756a66c45557cfeb19e38..a67a869180d4f572739be0de81063c45fe31948c 100644 (file)
@@ -19,7 +19,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <asm/io.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
index 5ccf0b1ec670f7ed27baecc1f96ece3a9c11c335..4aad35bba11a7af57679d47da3002223cd0c14ba 100644 (file)
@@ -18,7 +18,6 @@
 #define __SOUND_AU88X0_H
 
 #ifdef __KERNEL__
-#include <sound/driver.h>
 #include <linux/pci.h>
 #include <asm/io.h>
 #include <sound/core.h>
index 4a336eaae9d21eda656c88a08cf12a187697e0d0..333c62de862042f3672b3cf06c87c59c4cd8c707 100644 (file)
@@ -2395,7 +2395,7 @@ static irqreturn_t vortex_interrupt(int irq, void *dev_id)
        if (!(hwread(vortex->mmio, VORTEX_STAT) & 0x1))
                return IRQ_NONE;
 
-       // This is the Interrrupt Enable flag we set before (consistency check).
+       // This is the Interrupt Enable flag we set before (consistency check).
        if (!(hwread(vortex->mmio, VORTEX_CTRL) & CTRL_IRQ_ENABLE))
                return IRQ_NONE;
 
index a07d1deba322702cef7197cefd0e4815b6e596c4..bc212f41a38a611a84ee679502813377208602e1 100644 (file)
@@ -30,7 +30,6 @@
  * driver. (email: mjander@embedded.cl).
  */
 
-#include <sound/driver.h>
 #include <linux/time.h>
 #include <linux/delay.h>
 #include <linux/init.h>
index c96da1dab8639d4a81bde35715d00bd04cd51f54..c92f493d341e266c36b870f116aaf6adb9ef48a7 100644 (file)
@@ -5,7 +5,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/time.h>
 #include <linux/init.h>
 #include <sound/core.h>
index 8db3d3e6f7bb242a3476089af575cc9b07250a5b..0dc8d259d1ed09a708ad8affe38a29dfead7a27f 100644 (file)
@@ -21,7 +21,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/time.h>
 #include <linux/init.h>
 #include <sound/core.h>
index 7b5baa1738597b61e5785bcc270bb12b8ddae753..526c6c5ecf7b658f7e1acb9d011ff437f9919c61 100644 (file)
@@ -21,7 +21,6 @@
  * It remains stuck,and DMA transfers do not happen. 
  */
 #include <sound/asoundef.h>
-#include <sound/driver.h>
 #include <linux/time.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
index 36d3666a5b7747b74d993e1fc012d01d1a43a571..4e71a55120a05ff014a7504e1c472114ee963314 100644 (file)
  *    code (but I'm not too optimistic that doing this is possible at all)
  */
 
-#include <sound/driver.h>
 #include <asm/io.h>
 #include <linux/init.h>
 #include <linux/pci.h>
index 2dba752faf4e6281a2a31bddf4a0998197f4d535..c9a2421cf6f0df75078da262250633171beaaac6 100644 (file)
@@ -21,7 +21,6 @@
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/pci.h>
index 75da1746e758d221f9c80b473ac2bf8913c2983c..74175fc80c7f447dbc0441c325c04abf29350e91 100644 (file)
 #define SPCS_WORD_LENGTH_20A   0x0000000a      /* Word Length 20 bit                           */
 #define SPCS_WORD_LENGTH_20    0x00000009      /* Word Length 20 bit (both 0xa and 0x9 are 20 bit) */
 #define SPCS_WORD_LENGTH_21    0x00000007      /* Word Length 21 bit                           */
-#define SPCS_WORD_LENGTH_21    0x00000007      /* Word Length 21 bit                           */
 #define SPCS_WORD_LENGTH_22    0x00000005      /* Word Length 22 bit                           */
 #define SPCS_WORD_LENGTH_23    0x00000003      /* Word Length 23 bit                           */
 #define SPCS_WORD_LENGTH_24    0x0000000b      /* Word Length 24 bit                           */
index 31d8db9f7a4c023950fb14c6caee50212ede553a..176e0f0e80585739e37789b1e54e47df68a97e42 100644 (file)
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  *
  */
-#include <sound/driver.h>
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
index 3f9b5c5600369b5700b4b5ceb48e4fcf8b8f88e8..af736869d9b1959e0802c4e105476c898d901526 100644 (file)
@@ -60,7 +60,6 @@
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  *
  */
-#include <sound/driver.h>
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
index 61f2718ae3598a9c4b109198df404bbb19fabe6f..c62b7d10ec61644c763beb0be0c1a10073aee2b3 100644 (file)
@@ -60,7 +60,6 @@
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  *
  */
-#include <sound/driver.h>
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
index ad32eff2713f902288181c2a439db9588cc30dbd..893ee4f1ea7773f54e90c1824c75fe08a6bdb13f 100644 (file)
@@ -27,7 +27,6 @@
  */
 
 #include <linux/spinlock.h>
-#include <sound/driver.h>
 #include <sound/core.h>
 #include <sound/rawmidi.h>
 
index 1fa5f004e858fd8d0e0994aa20642e5eb974bede..135f308607535594b95c5afd74964a378ab079db 100644 (file)
@@ -20,7 +20,6 @@
 /* Does not work. Warning may block system in capture mode */
 /* #define USE_VAR48KRATE */
 
-#include <sound/driver.h>
 #include <asm/io.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
@@ -150,6 +149,8 @@ MODULE_PARM_DESC(joystick_port, "Joystick port address.");
 #define CM_CH0_SRATE_176K      0x00000200
 #define CM_CH0_SRATE_96K       0x00000200      /* model 055? */
 #define CM_CH0_SRATE_88K       0x00000100
+#define CM_CH0_SRATE_128K      0x00000300
+#define CM_CH0_SRATE_MASK      0x00000300
 
 #define CM_SPDIF_INVERSE2      0x00000080      /* model 055? */
 #define CM_DBLSPDS             0x00000040      /* double SPDIF sample rate 88.2/96 */
@@ -473,6 +474,7 @@ struct cmipci {
        unsigned int can_ac3_sw: 1;
        unsigned int can_ac3_hw: 1;
        unsigned int can_multi_ch: 1;
+       unsigned int can_96k: 1;        /* samplerate above 48k */
        unsigned int do_soft_ac3: 1;
 
        unsigned int spdif_playback_avail: 1;   /* spdif ready? */
@@ -603,8 +605,6 @@ static unsigned int snd_cmipci_rate_freq(unsigned int rate)
 {
        unsigned int i;
 
-       if (rate > 48000)
-               rate /= 2;
        for (i = 0; i < ARRAY_SIZE(rates); i++) {
                if (rates[i] == rate)
                        return i;
@@ -782,7 +782,7 @@ static int set_dac_channels(struct cmipci *cm, struct cmipci_pcm *rec, int chann
 static int snd_cmipci_pcm_prepare(struct cmipci *cm, struct cmipci_pcm *rec,
                                 struct snd_pcm_substream *substream)
 {
-       unsigned int reg, freq, val;
+       unsigned int reg, freq, freq_ext, val;
        unsigned int period_size;
        struct snd_pcm_runtime *runtime = substream->runtime;
 
@@ -830,7 +830,17 @@ static int snd_cmipci_pcm_prepare(struct cmipci *cm, struct cmipci_pcm *rec,
        //snd_printd("cmipci: functrl0 = %08x\n", cm->ctrl);
 
        /* set sample rate */
-       freq = snd_cmipci_rate_freq(runtime->rate);
+       freq = 0;
+       freq_ext = 0;
+       if (runtime->rate > 48000)
+               switch (runtime->rate) {
+               case 88200:  freq_ext = CM_CH0_SRATE_88K; break;
+               case 96000:  freq_ext = CM_CH0_SRATE_96K; break;
+               case 128000: freq_ext = CM_CH0_SRATE_128K; break;
+               default:     snd_BUG(); break;
+               }
+       else
+               freq = snd_cmipci_rate_freq(runtime->rate);
        val = snd_cmipci_read(cm, CM_REG_FUNCTRL1);
        if (rec->ch) {
                val &= ~CM_DSFC_MASK;
@@ -851,19 +861,20 @@ static int snd_cmipci_pcm_prepare(struct cmipci *cm, struct cmipci_pcm *rec,
                val &= ~CM_CH0FMT_MASK;
                val |= rec->fmt << CM_CH0FMT_SHIFT;
        }
-       if (cm->chip_version == 68) {
-               if (runtime->rate == 88200)
-                       val |= CM_CH0_SRATE_88K << (rec->ch * 2);
-               else
-                       val &= ~(CM_CH0_SRATE_88K << (rec->ch * 2));
-               if (runtime->rate == 96000)
-                       val |= CM_CH0_SRATE_96K << (rec->ch * 2);
-               else
-                       val &= ~(CM_CH0_SRATE_96K << (rec->ch * 2));
+       if (cm->can_96k) {
+               val &= ~(CM_CH0_SRATE_MASK << (rec->ch * 2));
+               val |= freq_ext << (rec->ch * 2);
        }
        snd_cmipci_write(cm, CM_REG_CHFORMAT, val);
        //snd_printd("cmipci: chformat = %08x\n", val);
 
+       if (!rec->is_dac && cm->chip_version) {
+               if (runtime->rate > 44100)
+                       snd_cmipci_set_bit(cm, CM_REG_EXT_MISC, CM_ADC48K44K);
+               else
+                       snd_cmipci_clear_bit(cm, CM_REG_EXT_MISC, CM_ADC48K44K);
+       }
+
        rec->running = 0;
        spin_unlock_irq(&cm->reg_lock);
 
@@ -1280,7 +1291,7 @@ static int snd_cmipci_playback_prepare(struct snd_pcm_substream *substream)
        int rate = substream->runtime->rate;
        int err, do_spdif, do_ac3 = 0;
 
-       do_spdif = (rate >= 44100 &&
+       do_spdif = (rate >= 44100 && rate <= 96000 &&
                    substream->runtime->format == SNDRV_PCM_FORMAT_S16_LE &&
                    substream->runtime->channels == 2);
        if (do_spdif && cm->can_ac3_hw) 
@@ -1336,10 +1347,8 @@ static void snd_cmipci_silence_hack(struct cmipci *cm, struct cmipci_pcm *rec)
                val = snd_cmipci_read(cm, CM_REG_CHFORMAT);
                val &= ~(CM_CH0FMT_MASK << (rec->ch * 2));
                val |= (3 << CM_CH0FMT_SHIFT) << (rec->ch * 2);
-               if (cm->chip_version == 68) {
-                       val &= ~(CM_CH0_SRATE_88K << (rec->ch * 2));
-                       val &= ~(CM_CH0_SRATE_96K << (rec->ch * 2));
-               }
+               if (cm->can_96k)
+                       val &= ~(CM_CH0_SRATE_MASK << (rec->ch * 2));
                snd_cmipci_write(cm, CM_REG_CHFORMAT, val);
        
                /* start stream (we don't need interrupts) */
@@ -1391,6 +1400,17 @@ static int snd_cmipci_capture_spdif_prepare(struct snd_pcm_substream *substream)
 
        spin_lock_irq(&cm->reg_lock);
        snd_cmipci_set_bit(cm, CM_REG_FUNCTRL1, CM_CAPTURE_SPDF);
+       if (cm->can_96k) {
+               if (substream->runtime->rate > 48000)
+                       snd_cmipci_set_bit(cm, CM_REG_CHFORMAT, CM_DBLSPDS);
+               else
+                       snd_cmipci_clear_bit(cm, CM_REG_CHFORMAT, CM_DBLSPDS);
+       }
+       if (snd_pcm_format_width(substream->runtime->format) > 16)
+               snd_cmipci_set_bit(cm, CM_REG_MISC_CTRL, CM_SPD32SEL);
+       else
+               snd_cmipci_clear_bit(cm, CM_REG_MISC_CTRL, CM_SPD32SEL);
+
        spin_unlock_irq(&cm->reg_lock);
 
        return snd_cmipci_pcm_prepare(cm, &cm->channel[CM_CH_CAPT], substream);
@@ -1402,6 +1422,7 @@ static int snd_cmipci_capture_spdif_hw_free(struct snd_pcm_substream *subs)
 
        spin_lock_irq(&cm->reg_lock);
        snd_cmipci_clear_bit(cm, CM_REG_FUNCTRL1, CM_CAPTURE_SPDF);
+       snd_cmipci_clear_bit(cm, CM_REG_MISC_CTRL, CM_SPD32SEL);
        spin_unlock_irq(&cm->reg_lock);
 
        return snd_cmipci_hw_free(subs);
@@ -1553,7 +1574,8 @@ static struct snd_pcm_hardware snd_cmipci_capture_spdif =
        .info =                 (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
                                 SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_PAUSE |
                                 SNDRV_PCM_INFO_RESUME | SNDRV_PCM_INFO_MMAP_VALID),
-       .formats =              SNDRV_PCM_FMTBIT_S16_LE,
+       .formats =              SNDRV_PCM_FMTBIT_S16_LE |
+                               SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE,
        .rates =                SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000,
        .rate_min =             44100,
        .rate_max =             48000,
@@ -1567,6 +1589,14 @@ static struct snd_pcm_hardware snd_cmipci_capture_spdif =
        .fifo_size =            0,
 };
 
+static unsigned int rate_constraints[] = { 5512, 8000, 11025, 16000, 22050,
+                       32000, 44100, 48000, 88200, 96000, 128000 };
+static struct snd_pcm_hw_constraint_list hw_constraints_rates = {
+               .count = ARRAY_SIZE(rate_constraints),
+               .list = rate_constraints,
+               .mask = 0,
+};
+
 /*
  * check device open/close
  */
@@ -1636,6 +1666,13 @@ static int snd_cmipci_playback_open(struct snd_pcm_substream *substream)
                runtime->hw.rates |= SNDRV_PCM_RATE_88200 |
                                     SNDRV_PCM_RATE_96000;
                runtime->hw.rate_max = 96000;
+       } else if (cm->chip_version == 55) {
+               err = snd_pcm_hw_constraint_list(runtime, 0,
+                       SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates);
+               if (err < 0)
+                       return err;
+               runtime->hw.rates |= SNDRV_PCM_RATE_KNOT;
+               runtime->hw.rate_max = 128000;
        }
        snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 0, 0x10000);
        cm->dig_pcm_status = cm->dig_status;
@@ -1654,6 +1691,13 @@ static int snd_cmipci_capture_open(struct snd_pcm_substream *substream)
        if (cm->chip_version == 68) {   // 8768 only supports 44k/48k recording
                runtime->hw.rate_min = 41000;
                runtime->hw.rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000;
+       } else if (cm->chip_version == 55) {
+               err = snd_pcm_hw_constraint_list(runtime, 0,
+                       SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates);
+               if (err < 0)
+                       return err;
+               runtime->hw.rates |= SNDRV_PCM_RATE_KNOT;
+               runtime->hw.rate_max = 128000;
        }
        snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 0, 0x10000);
        return 0;
@@ -1685,6 +1729,13 @@ static int snd_cmipci_playback2_open(struct snd_pcm_substream *substream)
                runtime->hw.rates |= SNDRV_PCM_RATE_88200 |
                                     SNDRV_PCM_RATE_96000;
                runtime->hw.rate_max = 96000;
+       } else if (cm->chip_version == 55) {
+               err = snd_pcm_hw_constraint_list(runtime, 0,
+                       SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates);
+               if (err < 0)
+                       return err;
+               runtime->hw.rates |= SNDRV_PCM_RATE_KNOT;
+               runtime->hw.rate_max = 128000;
        }
        snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 0, 0x10000);
        return 0;
@@ -1704,7 +1755,7 @@ static int snd_cmipci_playback_spdif_open(struct snd_pcm_substream *substream)
                        runtime->hw.formats |= SNDRV_PCM_FMTBIT_S32_LE;
                        snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24);
                }
-               if (cm->chip_version == 68) {
+               if (cm->can_96k) {
                        runtime->hw.rates |= SNDRV_PCM_RATE_88200 |
                                             SNDRV_PCM_RATE_96000;
                        runtime->hw.rate_max = 96000;
@@ -1726,6 +1777,11 @@ static int snd_cmipci_capture_spdif_open(struct snd_pcm_substream *substream)
        if ((err = open_device_check(cm, CM_OPEN_SPDIF_CAPTURE, substream)) < 0) /* use channel B */
                return err;
        runtime->hw = snd_cmipci_capture_spdif;
+       if (cm->can_96k && !(cm->chip_version == 68)) {
+               runtime->hw.rates |= SNDRV_PCM_RATE_88200 |
+                                    SNDRV_PCM_RATE_96000;
+               runtime->hw.rate_max = 96000;
+       }
        snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 0, 0x40000);
        return 0;
 }
@@ -2594,10 +2650,8 @@ static struct snd_kcontrol_new snd_cmipci_extra_mixer_switches[] __devinitdata =
 };
 
 /* card control switches */
-static struct snd_kcontrol_new snd_cmipci_control_switches[] __devinitdata = {
-       // DEFINE_CARD_SWITCH("Joystick", joystick), /* now module option */
-       DEFINE_CARD_SWITCH("Modem", modem),
-};
+static struct snd_kcontrol_new snd_cmipci_modem_switch __devinitdata =
+DEFINE_CARD_SWITCH("Modem", modem);
 
 
 static int __devinit snd_cmipci_mixer_new(struct cmipci *cm, int pcm_spdif_device)
@@ -2678,9 +2732,13 @@ static int __devinit snd_cmipci_mixer_new(struct cmipci *cm, int pcm_spdif_devic
        }
 
        /* card switches */
-       sw = snd_cmipci_control_switches;
-       for (idx = 0; idx < ARRAY_SIZE(snd_cmipci_control_switches); idx++, sw++) {
-               err = snd_ctl_add(cm->card, snd_ctl_new1(sw, cm));
+       /*
+        * newer chips don't have the register bits to force modem link
+        * detection; the bit that was FLINKON now mutes CH1
+        */
+       if (cm->chip_version < 39) {
+               err = snd_ctl_add(cm->card,
+                                 snd_ctl_new1(&snd_cmipci_modem_switch, cm));
                if (err < 0)
                        return err;
        }
@@ -2785,9 +2843,11 @@ static void __devinit query_chip(struct cmipci *cm)
                } else if (detect & CM_CHIP_8768) {
                        cm->chip_version = 68;
                        cm->max_channels = 8;
+                       cm->can_96k = 1;
                } else {
                        cm->chip_version = 55;
                        cm->max_channels = 6;
+                       cm->can_96k = 1;
                }
                cm->can_ac3_hw = 1;
                cm->can_multi_ch = 1;
index 9a55f4a9739b671b59950ac383e15e57dd0916ca..7556fd90d0eb5c67973ddfa3fba26c597a766844 100644 (file)
@@ -19,7 +19,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <asm/io.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
index 2699cb6c2cd69df0340b52c288a9315d0965e883..e876b3263e462a9060b071e7974f1b0dcb90c583 100644 (file)
@@ -25,7 +25,6 @@
     reloading the module may solve this.
 */
 
-#include <sound/driver.h>
 #include <linux/pci.h>
 #include <linux/time.h>
 #include <linux/init.h>
index 2c7bfc9fef619646ae0a85ee3d1dc8321a2dd792..87ddffcd9d89d7a6dafee80f9a0e03e6a1983f9c 100644 (file)
@@ -8,7 +8,7 @@
  *    - Sometimes the SPDIF input DSP tasks get's unsynchronized
  *      and the SPDIF get somewhat "distorcionated", or/and left right channel
  *      are swapped. To get around this problem when it happens, mute and unmute 
- *      the SPDIF input mixer controll.
+ *      the SPDIF input mixer control.
  *    - On the Hercules Game Theater XP the amplifier are sometimes turned
  *      off on inadecuate moments which causes distorcions on sound.
  *
@@ -45,7 +45,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/delay.h>
 #include <linux/pci.h>
 #include <linux/pm.h>
@@ -2084,71 +2083,6 @@ static int snd_cs46xx_spdif_stream_put(struct snd_kcontrol *kcontrol,
 #endif /* CONFIG_SND_CS46XX_NEW_DSP */
 
 
-#ifdef CONFIG_SND_CS46XX_DEBUG_GPIO
-static int snd_cs46xx_egpio_select_info(struct snd_kcontrol *kcontrol, 
-                                        struct snd_ctl_elem_info *uinfo)
-{
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
-       uinfo->count = 1;
-       uinfo->value.integer.min = 0;
-       uinfo->value.integer.max = 8;
-       return 0;
-}
-
-static int snd_cs46xx_egpio_select_get(struct snd_kcontrol *kcontrol, 
-                                       struct snd_ctl_elem_value *ucontrol)
-{
-       struct snd_cs46xx *chip = snd_kcontrol_chip(kcontrol);
-       ucontrol->value.integer.value[0] = chip->current_gpio;
-
-       return 0;
-}
-
-static int snd_cs46xx_egpio_select_put(struct snd_kcontrol *kcontrol, 
-                                       struct snd_ctl_elem_value *ucontrol)
-{
-       struct snd_cs46xx *chip = snd_kcontrol_chip(kcontrol);
-       int change = (chip->current_gpio != ucontrol->value.integer.value[0]);
-       chip->current_gpio = ucontrol->value.integer.value[0];
-
-       return change;
-}
-
-
-static int snd_cs46xx_egpio_get(struct snd_kcontrol *kcontrol, 
-                                       struct snd_ctl_elem_value *ucontrol)
-{
-       struct snd_cs46xx *chip = snd_kcontrol_chip(kcontrol);
-       int reg = kcontrol->private_value;
-
-       snd_printdd ("put: reg = %04x, gpio %02x\n",reg,chip->current_gpio);
-       ucontrol->value.integer.value[0] = 
-               (snd_cs46xx_peekBA0(chip, reg) & (1 << chip->current_gpio)) ? 1 : 0;
-  
-       return 0;
-}
-
-static int snd_cs46xx_egpio_put(struct snd_kcontrol *kcontrol, 
-                                       struct snd_ctl_elem_value *ucontrol)
-{
-       struct snd_cs46xx *chip = snd_kcontrol_chip(kcontrol);
-       int reg = kcontrol->private_value;
-       int val = snd_cs46xx_peekBA0(chip, reg);
-       int oldval = val;
-       snd_printdd ("put: reg = %04x, gpio %02x\n",reg,chip->current_gpio);
-
-       if (ucontrol->value.integer.value[0])
-               val |= (1 << chip->current_gpio);
-       else
-               val &= ~(1 << chip->current_gpio);
-
-       snd_cs46xx_pokeBA0(chip, reg,val);
-       snd_printdd ("put: val %08x oldval %08x\n",val,oldval);
-
-       return (oldval != val);
-}
-#endif /* CONFIG_SND_CS46XX_DEBUG_GPIO */
-
 static struct snd_kcontrol_new snd_cs46xx_controls[] __devinitdata = {
 {
        .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
@@ -2240,40 +2174,6 @@ static struct snd_kcontrol_new snd_cs46xx_controls[] __devinitdata = {
        .put =   snd_cs46xx_spdif_stream_put
 },
 
-#endif
-#ifdef CONFIG_SND_CS46XX_DEBUG_GPIO
-{
-       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-       .name = "EGPIO select",
-       .info = snd_cs46xx_egpio_select_info,
-       .get = snd_cs46xx_egpio_select_get,
-       .put = snd_cs46xx_egpio_select_put,
-       .private_value = 0,
-},
-{
-       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-       .name = "EGPIO Input/Output",
-       .info = snd_mixer_boolean_info,
-       .get = snd_cs46xx_egpio_get,
-       .put = snd_cs46xx_egpio_put,
-       .private_value = BA0_EGPIODR,
-},
-{
-       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-       .name = "EGPIO CMOS/Open drain",
-       .info = snd_mixer_boolean_info,
-       .get = snd_cs46xx_egpio_get,
-       .put = snd_cs46xx_egpio_put,
-       .private_value = BA0_EGPIOPTR,
-},
-{
-       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-       .name = "EGPIO On/Off",
-       .info = snd_mixer_boolean_info,
-       .get = snd_cs46xx_egpio_get,
-       .put = snd_cs46xx_egpio_put,
-       .private_value = BA0_EGPIOSR,
-},
 #endif
 };
 
index 590b35d91df24e3f4e2d0c445fcf01d17c7a4f03..ccc8bedb5b1a3e6136c913806cf347d60f7f8053 100644 (file)
@@ -20,7 +20,6 @@
  */
 
 
-#include <sound/driver.h>
 #include <asm/io.h>
 #include <linux/delay.h>
 #include <linux/pm.h>
index eded4dfeba1210fe307d7f526e39d3c1f0856ed1..2873cfe48c331605f50d23f84350ba4865ce9750 100644 (file)
@@ -21,7 +21,6 @@
  */
 
 
-#include <sound/driver.h>
 #include <asm/io.h>
 #include <linux/delay.h>
 #include <linux/pm.h>
index 240a0a4622090f4867200f059e3f87068f373c4d..7ff8b68e997e89cbb83bda6ced49f49cf44ceea9 100644 (file)
@@ -36,7 +36,6 @@
  *     same manner.
  */
 
-#include <sound/driver.h>
 #include <linux/delay.h>
 #include <linux/moduleparam.h>
 #include <linux/pci.h>
index 2b35889787be6533f88cf484820c481c747d70b0..1d8b160525355e21eb7ee5c5dcd3a18d5877b313 100644 (file)
@@ -21,7 +21,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
@@ -145,7 +144,7 @@ static unsigned short snd_cs5535audio_ac97_codec_read(struct snd_ac97 *ac97,
        return snd_cs5535audio_codec_read(cs5535au, reg);
 }
 
-static int snd_cs5535audio_mixer(struct cs5535audio *cs5535au)
+static int __devinit snd_cs5535audio_mixer(struct cs5535audio *cs5535au)
 {
        struct snd_card *card = cs5535au->card;
        struct snd_ac97_bus *pbus;
index 21df0634af32a2be83133a4375e0810b6d801455..cdcda87116c34bc895b49e8def2ffa28a4c22491 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/pci.h>
-#include <sound/driver.h>
 #include <sound/core.h>
 #include <sound/control.h>
 #include <sound/initval.h>
@@ -98,6 +97,8 @@ static int snd_cs5535audio_playback_open(struct snd_pcm_substream *substream)
        struct snd_pcm_runtime *runtime = substream->runtime;
 
        runtime->hw = snd_cs5535audio_playback;
+       runtime->hw.rates = cs5535au->ac97->rates[AC97_RATES_FRONT_DAC];
+       snd_pcm_limit_hw_rates(runtime);
        cs5535au->playback_substream = substream;
        runtime->private_data = &(cs5535au->dmas[CS5535AUDIO_DMA_PLAYBACK]);
        if ((err = snd_pcm_hw_constraint_integer(runtime,
@@ -343,6 +344,8 @@ static int snd_cs5535audio_capture_open(struct snd_pcm_substream *substream)
        struct snd_pcm_runtime *runtime = substream->runtime;
 
        runtime->hw = snd_cs5535audio_capture;
+       runtime->hw.rates = cs5535au->ac97->rates[AC97_RATES_ADC];
+       snd_pcm_limit_hw_rates(runtime);
        cs5535au->capture_substream = substream;
        runtime->private_data = &(cs5535au->dmas[CS5535AUDIO_DMA_CAPTURE]);
        if ((err = snd_pcm_hw_constraint_integer(runtime,
index 838708f6d45e45db3416ce6cf17429d50f1181c0..564c33b60953964129619309e4a39090ca47fb97 100644 (file)
@@ -22,7 +22,6 @@
 #include <linux/slab.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
-#include <sound/driver.h>
 #include <sound/core.h>
 #include <sound/control.h>
 #include <sound/initval.h>
index 87078d3a68549b931afed8a7cb09a259ebd883a1..8c6db3aa3c1ad59d55ae51d67fbb5b112140c0f2 100644 (file)
@@ -36,7 +36,6 @@
 #define BX_NUM         10
 
 
-#include <sound/driver.h>
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
index 42b48f9d21286113915fd5439d83a4e1614b6d8e..04cbf3eaf05a1cd8ae683d1ca2d39be50b0f5156 100644 (file)
@@ -40,7 +40,6 @@
 #define BX_NUM         10
 
 
-#include <sound/driver.h>
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
index 8dbb7ac865c1952e680ad0e0c092c46a72db6faa..4022e43a0053dc36fa04ed958d74f7c86f790e98 100644 (file)
@@ -47,7 +47,6 @@
 #define BX_NUM         chip->bx_num
 
 
-#include <sound/driver.h>
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
index 499ee1a5319d3ffa40927f15c0b932cb8826eb0d..90ec090792ba12c4c22eecb4378744dd14549868 100644 (file)
@@ -378,7 +378,7 @@ static int pcm_digital_in_open(struct snd_pcm_substream *substream)
 
        DE_ACT(("pcm_digital_in_open\n"));
        max_channels = num_digital_busses_in(chip) - substream->number;
-       down(&chip->mode_mutex);
+       mutex_lock(&chip->mode_mutex);
        if (chip->digital_mode == DIGITAL_MODE_ADAT)
                err = pcm_open(substream, max_channels);
        else    /* If the card has ADAT, subtract the 6 channels
@@ -405,7 +405,7 @@ static int pcm_digital_in_open(struct snd_pcm_substream *substream)
                chip->can_set_rate=0;
 
 din_exit:
-       up(&chip->mode_mutex);
+       mutex_unlock(&chip->mode_mutex);
        return err;
 }
 
@@ -420,7 +420,7 @@ static int pcm_digital_out_open(struct snd_pcm_substream *substream)
 
        DE_ACT(("pcm_digital_out_open\n"));
        max_channels = num_digital_busses_out(chip) - substream->number;
-       down(&chip->mode_mutex);
+       mutex_lock(&chip->mode_mutex);
        if (chip->digital_mode == DIGITAL_MODE_ADAT)
                err = pcm_open(substream, max_channels);
        else    /* If the card has ADAT, subtract the 6 channels
@@ -447,7 +447,7 @@ static int pcm_digital_out_open(struct snd_pcm_substream *substream)
        if (atomic_read(&chip->opencount) > 1 && chip->rate_set)
                chip->can_set_rate=0;
 dout_exit:
-       up(&chip->mode_mutex);
+       mutex_unlock(&chip->mode_mutex);
        return err;
 }
 
@@ -1420,7 +1420,7 @@ static int snd_echo_digital_mode_put(struct snd_kcontrol *kcontrol,
        if (dmode != chip->digital_mode) {
                /* mode_mutex is required to make this operation atomic wrt
                pcm_digital_*_open() and set_input_clock() functions. */
-               down(&chip->mode_mutex);
+               mutex_lock(&chip->mode_mutex);
 
                /* Do not allow the user to change the digital mode when a pcm
                device is open because it also changes the number of channels
@@ -1439,7 +1439,7 @@ static int snd_echo_digital_mode_put(struct snd_kcontrol *kcontrol,
                        if (changed >= 0)
                                changed = 1;    /* No errors */
                }
-               up(&chip->mode_mutex);
+               mutex_unlock(&chip->mode_mutex);
        }
        return changed;
 }
@@ -1566,12 +1566,12 @@ static int snd_echo_clock_source_put(struct snd_kcontrol *kcontrol,
                return -EINVAL;
        dclock = chip->clock_source_list[eclock];
        if (chip->input_clock != dclock) {
-               down(&chip->mode_mutex);
+               mutex_lock(&chip->mode_mutex);
                spin_lock_irq(&chip->lock);
                if ((changed = set_input_clock(chip, dclock)) == 0)
                        changed = 1;    /* no errors */
                spin_unlock_irq(&chip->lock);
-               up(&chip->mode_mutex);
+               mutex_unlock(&chip->mode_mutex);
        }
 
        if (changed < 0)
@@ -1972,7 +1972,7 @@ static __devinit int snd_echo_create(struct snd_card *card,
                return err;
        }
        atomic_set(&chip->opencount, 0);
-       init_MUTEX(&chip->mode_mutex);
+       mutex_init(&chip->mode_mutex);
        chip->can_set_rate = 1;
        *rchip = chip;
        /* Init done ! */
index 7e88c968e22ff20cabc9455a2f71fb68c4a859aa..1c88e051abf2a5c33e809e54c47a3479d114cbb0 100644 (file)
@@ -361,7 +361,7 @@ struct echoaudio {
        spinlock_t lock;
        struct snd_pcm_substream *substream[DSP_MAXPIPES];
        int last_period[DSP_MAXPIPES];
-       struct semaphore mode_mutex;
+       struct mutex mode_mutex;
        u16 num_digital_modes, digital_mode_list[6];
        u16 num_clock_sources, clock_source_list[10];
        atomic_t opencount;
index fee2d483173234cd8f8b988e626d2cc71af98b8b..c0e64b8f52a40577834d29da28f42443667a59ff 100644 (file)
@@ -40,7 +40,6 @@
 #define BX_NUM         14
 
 
-#include <sound/driver.h>
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
index d5eae470fe9a3eff790af608cfd28665e28af418..c36a78dd0b5e373d6202c97cc3dd54833e122583 100644 (file)
@@ -46,7 +46,6 @@
 #define BX_NUM         26
 
 
-#include <sound/driver.h>
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
index 40f601cd016f32fca593f0b1fe4178052166a690..0a58a7c1fd7cc69fc02aa042a356b4ad47b00ae4 100644 (file)
@@ -38,7 +38,6 @@
 #define BX_NUM         2
 
 
-#include <sound/driver.h>
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
index 771c5383210d23597e9536b55d9a11d22b4af48f..2db24d29332bea8eed11bc0e0311df1756666e11 100644 (file)
@@ -38,7 +38,6 @@
 #define BX_NUM         4
 
 
-#include <sound/driver.h>
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
index 49c550defcf9230db0ee2fdc6903f21e468d9bb1..a60c0a0a89b737470da2b6d650d7c2cbb352fc7e 100644 (file)
@@ -39,7 +39,6 @@
 #define BX_NUM         4
 
 
-#include <sound/driver.h>
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
index 8f5483a405ae6922f31671ce43797816ff8b5694..506194688995ddab5499c556f5d425c8b908511a 100644 (file)
@@ -45,7 +45,6 @@
 #define BX_NUM         22
 
 
-#include <sound/driver.h>
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
index 0524667c02f700ca7ffdc4fa75ac5a02bddaff4d..e09e3ea7781e4c6a87247b1ae8adb2f176db49dc 100644 (file)
@@ -47,7 +47,6 @@
 #define BX_NUM         32
 
 
-#include <sound/driver.h>
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
index 893c7c20dd70b98eca133c110b7356f705a3e52b..f3b9b45c9c1be7ad82b3c9249e66dfe84ef15833 100644 (file)
@@ -45,7 +45,6 @@
 #define BX_NUM         8
 
 
-#include <sound/driver.h>
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
index 3a5d5b0020df30328888a58c3d56d36c015b3c01..b05bad944901b6662dbb19bc231260087e1c08b3 100644 (file)
@@ -44,7 +44,6 @@
 #define BX_NUM         26
 
 
-#include <sound/driver.h>
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
index 9680caff90c8556bd97f174e3ddf5df454a61aed..8354c1a833129c7300b765ef918462a3852537f6 100644 (file)
@@ -23,7 +23,6 @@
  * 
  */
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/pci.h>
 #include <linux/time.h>
index 01965bd99966e0e76e13cbc0d90683b86bb4492a..45088ebcce5041a9b25e147d41be6add78351f05 100644 (file)
@@ -35,9 +35,9 @@ struct best_voice {
 /*
  * prototypes
  */
-static void lookup_voices(struct snd_emux *emu, struct snd_emu10k1 *hw,
+static void lookup_voices(struct snd_emux *emux, struct snd_emu10k1 *hw,
                          struct best_voice *best, int active_only);
-static struct snd_emux_voice *get_voice(struct snd_emux *emu,
+static struct snd_emux_voice *get_voice(struct snd_emux *emux,
                                        struct snd_emux_port *port);
 static int start_voice(struct snd_emux_voice *vp);
 static void trigger_voice(struct snd_emux_voice *vp);
@@ -45,7 +45,6 @@ static void release_voice(struct snd_emux_voice *vp);
 static void update_voice(struct snd_emux_voice *vp, int update);
 static void terminate_voice(struct snd_emux_voice *vp);
 static void free_voice(struct snd_emux_voice *vp);
-
 static void set_fmmod(struct snd_emu10k1 *hw, struct snd_emux_voice *vp);
 static void set_fm2frq2(struct snd_emu10k1 *hw, struct snd_emux_voice *vp);
 static void set_filterQ(struct snd_emu10k1 *hw, struct snd_emux_voice *vp);
@@ -75,9 +74,9 @@ static struct snd_emux_operators emu10k1_ops = {
 };
 
 void
-snd_emu10k1_ops_setup(struct snd_emux *emu)
+snd_emu10k1_ops_setup(struct snd_emux *emux)
 {
-       emu->ops = emu10k1_ops;
+       emux->ops = emu10k1_ops;
 }
 
 
@@ -166,7 +165,11 @@ free_voice(struct snd_emux_voice *vp)
        struct snd_emu10k1 *hw;
        
        hw = vp->hw;
-       if (vp->ch >= 0) {
+       /* FIXME: emu10k1_synth is broken. */
+       /* This can get called with hw == 0 */
+       /* Problem apparent on plug, unplug then plug */
+       /* on the Audigy 2 ZS Notebook. */
+       if (hw && (vp->ch >= 0)) {
                snd_emu10k1_ptr_write(hw, IFATN, vp->ch, 0xff00);
                snd_emu10k1_ptr_write(hw, DCYSUSV, vp->ch, 0x807f | DCYSUSV_CHANNELENABLE_MASK);
                // snd_emu10k1_ptr_write(hw, DCYSUSV, vp->ch, 0);
index 97c41d72a255f7e165199e64af004af7417d9bc6..9a9b977d3cf1c00173a76128a29be00dc51e683a 100644 (file)
@@ -33,7 +33,6 @@
 
 #include <linux/sched.h>
 #include <linux/kthread.h>
-#include <sound/driver.h>
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #define DOCK_FILENAME "emu/audio_dock.fw"
 #define EMU1010B_FILENAME "emu/emu1010b.fw"
 #define MICRO_DOCK_FILENAME "emu/micro_dock.fw"
+#define EMU0404_FILENAME "emu/emu0404.fw"
 #define EMU1010_NOTEBOOK_FILENAME "emu/emu1010_notebook.fw"
 
 MODULE_FIRMWARE(HANA_FILENAME);
 MODULE_FIRMWARE(DOCK_FILENAME);
 MODULE_FIRMWARE(EMU1010B_FILENAME);
 MODULE_FIRMWARE(MICRO_DOCK_FILENAME);
+MODULE_FIRMWARE(EMU0404_FILENAME);
 MODULE_FIRMWARE(EMU1010_NOTEBOOK_FILENAME);
 
 
@@ -258,7 +259,6 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume)
                 * GPIO7: Unknown
                 */
                outl(0x76, emu->port + A_IOCFG); /* Windows uses 0x3f76 */
-
        }
        if (emu->card_capabilities->i2c_adc) { /* Audigy 2 ZS Notebook with ADC Wolfson WM8775 */
                int size, n;
@@ -274,7 +274,6 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume)
                        emu->i2c_capture_volume[n][0]= 0xcf;
                        emu->i2c_capture_volume[n][1]= 0xcf;
                }
-
        }
 
        
@@ -288,7 +287,7 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume)
                snd_emu10k1_ptr_write(emu, MAPB, ch, silent_page);
        }
 
-       if (emu->card_capabilities->emu1010) {
+       if (emu->card_capabilities->emu_model) {
                outl(HCFG_AUTOMUTE_ASYNC |
                        HCFG_EMU32_SLAVE |
                        HCFG_AUDIOENABLE, emu->port + HCFG);
@@ -318,7 +317,7 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume)
                outl(HCFG_LOCKTANKCACHE_MASK | HCFG_AUTOMUTE | HCFG_JOYENABLE, emu->port + HCFG);
 
        if (enable_ir) {        /* enable IR for SB Live */
-               if (emu->card_capabilities->emu1010) {
+               if (emu->card_capabilities->emu_model) {
                        ;  /* Disable all access to A_IOCFG for the emu1010 */
                } else if (emu->card_capabilities->i2c_adc) {
                        ;  /* Disable A_IOCFG for Audigy 2 ZS Notebook */
@@ -339,7 +338,7 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume)
                }
        }
        
-       if (emu->card_capabilities->emu1010) {
+       if (emu->card_capabilities->emu_model) {
                ;  /* Disable all access to A_IOCFG for the emu1010 */
        } else if (emu->card_capabilities->i2c_adc) {
                ;  /* Disable A_IOCFG for Audigy 2 ZS Notebook */
@@ -359,7 +358,7 @@ static void snd_emu10k1_audio_enable(struct snd_emu10k1 *emu)
        outl(inl(emu->port + HCFG) | HCFG_AUDIOENABLE, emu->port + HCFG);
 
        /* Enable analog/digital outs on audigy */
-       if (emu->card_capabilities->emu1010) {
+       if (emu->card_capabilities->emu_model) {
                ;  /* Disable all access to A_IOCFG for the emu1010 */
        } else if (emu->card_capabilities->i2c_adc) {
                ;  /* Disable A_IOCFG for Audigy 2 ZS Notebook */
@@ -652,6 +651,8 @@ static int snd_emu10k1_cardbus_init(struct snd_emu10k1 * emu)
        value = inl(special_port);
 
        snd_emu10k1_ptr20_write(emu, TINA2_VOLUME, 0, 0xfefefefe); /* Defaults to 0x30303030 */
+       /* Delay to give time for ADC chip to switch on. It needs 113ms */
+       msleep(200);
        return 0;
 }
 
@@ -661,6 +662,8 @@ static int snd_emu1010_load_firmware(struct snd_emu10k1 * emu, const char * file
        int n, i;
        int reg;
        int value;
+       unsigned int write_post;
+       unsigned long flags;
        const struct firmware *fw_entry;
 
        if ((err = request_firmware(&fw_entry, filename, &emu->pci->dev)) != 0) {
@@ -668,12 +671,6 @@ static int snd_emu1010_load_firmware(struct snd_emu10k1 * emu, const char * file
                return err;
        }
        snd_printk(KERN_INFO "firmware size=0x%zx\n", fw_entry->size);
-#if 0
-       if (fw_entry->size != 0x133a4) {
-               snd_printk(KERN_ERR "firmware: %s wrong size.\n",filename);
-               return -EINVAL;
-       }
-#endif
 
        /* The FPGA is a Xilinx Spartan IIE XC2S50E */
        /* GPIO7 -> FPGA PGMN
@@ -681,9 +678,12 @@ static int snd_emu1010_load_firmware(struct snd_emu10k1 * emu, const char * file
         * GPIO5 -> FPGA DIN
         * FPGA CONFIG OFF -> FPGA PGMN
         */
+       spin_lock_irqsave(&emu->emu_lock, flags);
        outl(0x00, emu->port + A_IOCFG); /* Set PGMN low for 1uS. */
-       udelay(1);
+       write_post = inl(emu->port + A_IOCFG);
+       udelay(100);
        outl(0x80, emu->port + A_IOCFG); /* Leave bit 7 set during netlist setup. */
+       write_post = inl(emu->port + A_IOCFG);
        udelay(100); /* Allow FPGA memory to clean */
        for(n = 0; n < fw_entry->size; n++) {
                value=fw_entry->data[n];        
@@ -693,18 +693,22 @@ static int snd_emu1010_load_firmware(struct snd_emu10k1 * emu, const char * file
                                reg = reg | 0x20;
                        value = value >> 1;   
                        outl(reg, emu->port + A_IOCFG);
+                       write_post = inl(emu->port + A_IOCFG);
                        outl(reg | 0x40, emu->port + A_IOCFG);
+                       write_post = inl(emu->port + A_IOCFG);
                }
        }
        /* After programming, set GPIO bit 4 high again. */
        outl(0x10, emu->port + A_IOCFG);
-       
+       write_post = inl(emu->port + A_IOCFG);
+       spin_unlock_irqrestore(&emu->emu_lock, flags);
 
         release_firmware(fw_entry);
        return 0;
 }
 
-int emu1010_firmware_thread(void *data) {
+static int emu1010_firmware_thread(void *data)
+{
        struct snd_emu10k1 * emu = data;
        int tmp,tmp2;
        int reg;
@@ -712,7 +716,7 @@ int emu1010_firmware_thread(void *data) {
 
        for (;;) {
                /* Delay to allow Audio Dock to settle */
-               msleep(1000);
+               msleep_interruptible(1000);
                if (kthread_should_stop())
                        break;
                snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &tmp ); /* IRQ Status */
@@ -722,17 +726,20 @@ int emu1010_firmware_thread(void *data) {
                        /* Return to Audio Dock programming mode */
                        snd_printk(KERN_INFO "emu1010: Loading Audio Dock Firmware\n");
                        snd_emu1010_fpga_write(emu,  EMU_HANA_FPGA_CONFIG, EMU_HANA_FPGA_CONFIG_AUDIODOCK );
-                       if (emu->card_capabilities->emu1010 == 1) {
+                       if (emu->card_capabilities->emu_model ==
+                           EMU_MODEL_EMU1010) {
                                if ((err = snd_emu1010_load_firmware(emu, DOCK_FILENAME)) != 0) {
-                                       return err;
+                                       continue;
                                }
-                       } else if (emu->card_capabilities->emu1010 == 2) {
+                       } else if (emu->card_capabilities->emu_model ==
+                                  EMU_MODEL_EMU1010B) {
                                if ((err = snd_emu1010_load_firmware(emu, MICRO_DOCK_FILENAME)) != 0) {
-                                       return err;
+                                       continue;
                                }
-                       } else if (emu->card_capabilities->emu1010 == 3) {
+                       } else if (emu->card_capabilities->emu_model ==
+                                  EMU_MODEL_EMU1616) {
                                if ((err = snd_emu1010_load_firmware(emu, MICRO_DOCK_FILENAME)) != 0) {
-                                       return err;
+                                       continue;
                                }
                        }
 
@@ -745,8 +752,7 @@ int emu1010_firmware_thread(void *data) {
                        if ((reg & 0x1f) != 0x15) {
                                /* FPGA failed to be programmed */
                                snd_printk(KERN_INFO "emu1010: Loading Audio Dock Firmware file failed, reg=0x%x\n", reg);
-                               return 0;
-                               return -ENODEV;
+                               continue;
                        }
                        snd_printk(KERN_INFO "emu1010: Audio Dock Firmware loaded\n");
                        snd_emu1010_fpga_read(emu, EMU_DOCK_MAJOR_REV, &tmp );
@@ -757,9 +763,9 @@ int emu1010_firmware_thread(void *data) {
                        msleep(10);
                        /* Unmute all. Default is muted after a firmware load */
                        snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE );
-                       break;
                }
        }
+       snd_printk(KERN_INFO "emu1010: firmware thread stopping\n");
        return 0;
 }
 
@@ -800,6 +806,7 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 * emu)
        int tmp,tmp2;
        int reg;
        int err;
+       const char *filename = NULL;
 
        snd_printk(KERN_INFO "emu1010: Special config.\n");
        /* AC97 2.1, Any 16Meg of 4Gig address, Auto-Mute, EMU32 Slave,
@@ -841,21 +848,31 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 * emu)
                return -ENODEV;
        }
        snd_printk(KERN_INFO "emu1010: EMU_HANA_ID=0x%x\n",reg);
-       if (emu->card_capabilities->emu1010 == 1) {
-               if ((err = snd_emu1010_load_firmware(emu, HANA_FILENAME)) != 0) {
-                       snd_printk(KERN_INFO "emu1010: Loading Hana Firmware file %s failed\n", HANA_FILENAME);
-                       return err;
-               }
-       } else if (emu->card_capabilities->emu1010 == 2) {
-               if ((err = snd_emu1010_load_firmware(emu, EMU1010B_FILENAME)) != 0) {
-                       snd_printk(KERN_INFO "emu1010: Loading Firmware file %s failed\n", EMU1010B_FILENAME);
-                       return err;
-               }
-       } else if (emu->card_capabilities->emu1010 == 3) {
-               if ((err = snd_emu1010_load_firmware(emu, EMU1010_NOTEBOOK_FILENAME)) != 0) {
-                       snd_printk(KERN_INFO "emu1010: Loading Firmware file %s failed\n", EMU1010_NOTEBOOK_FILENAME);
-                       return err;
-               }
+       switch (emu->card_capabilities->emu_model) {
+       case EMU_MODEL_EMU1010:
+               filename = HANA_FILENAME;
+               break;
+       case EMU_MODEL_EMU1010B:
+               filename = EMU1010B_FILENAME;
+               break;
+       case EMU_MODEL_EMU1616:
+               filename = EMU1010_NOTEBOOK_FILENAME;
+               break;
+       case EMU_MODEL_EMU0404:
+               filename = EMU0404_FILENAME;
+               break;
+       default:
+               filename = NULL;
+               return -ENODEV;
+               break;
+       }
+       snd_printk(KERN_INFO "emu1010: filename %s testing\n", filename);
+       err = snd_emu1010_load_firmware(emu, filename);
+       if (err != 0) {
+               snd_printk(
+                       KERN_INFO "emu1010: Loading Firmware file %s failed\n",
+                       filename);
+               return err;
        }
 
        /* ID, should read & 0x7f = 0x55 when FPGA programmed. */
@@ -1074,10 +1091,12 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 * emu)
        snd_emu1010_fpga_write(emu, EMU_HANA_SPDIF_MODE, 0x10 ); /* SPDIF Format spdif  (or 0x11 for aes/ebu) */
 
        /* Start Micro/Audio Dock firmware loader thread */
-       emu->emu1010.firmware_thread = kthread_create(&emu1010_firmware_thread,
-                                   emu,
-                                   "emu1010_firmware");
-       wake_up_process(emu->emu1010.firmware_thread);
+       if (!emu->emu1010.firmware_thread) {
+               emu->emu1010.firmware_thread =
+                       kthread_create(emu1010_firmware_thread, emu,
+                                      "emu1010_firmware");
+               wake_up_process(emu->emu1010.firmware_thread);
+       }
 
 #if 0
        snd_emu1010_fpga_link_dst_src_write(emu,
@@ -1090,79 +1109,114 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 * emu)
                EMU_DST_HANA_SPDIF_RIGHT1, EMU_SRC_ALICE_EMU32A + 3); /* ALICE2 bus 0xb3 */
 #endif
        /* Default outputs */
-       snd_emu1010_fpga_link_dst_src_write(emu,
-               EMU_DST_DOCK_DAC1_LEFT1, EMU_SRC_ALICE_EMU32A + 0); /* ALICE2 bus 0xa0 */
-       emu->emu1010.output_source[0] = 21;
-       snd_emu1010_fpga_link_dst_src_write(emu,
-               EMU_DST_DOCK_DAC1_RIGHT1, EMU_SRC_ALICE_EMU32A + 1);
-       emu->emu1010.output_source[1] = 22;
-       snd_emu1010_fpga_link_dst_src_write(emu,
-               EMU_DST_DOCK_DAC2_LEFT1, EMU_SRC_ALICE_EMU32A + 2);
-       emu->emu1010.output_source[2] = 23;
-       snd_emu1010_fpga_link_dst_src_write(emu,
-               EMU_DST_DOCK_DAC2_RIGHT1, EMU_SRC_ALICE_EMU32A + 3);
-       emu->emu1010.output_source[3] = 24;
-       snd_emu1010_fpga_link_dst_src_write(emu,
-               EMU_DST_DOCK_DAC3_LEFT1, EMU_SRC_ALICE_EMU32A + 4);
-       emu->emu1010.output_source[4] = 25;
-       snd_emu1010_fpga_link_dst_src_write(emu,
-               EMU_DST_DOCK_DAC3_RIGHT1, EMU_SRC_ALICE_EMU32A + 5);
-       emu->emu1010.output_source[5] = 26;
-       snd_emu1010_fpga_link_dst_src_write(emu,
-               EMU_DST_DOCK_DAC4_LEFT1, EMU_SRC_ALICE_EMU32A + 6);
-       emu->emu1010.output_source[6] = 27;
-       snd_emu1010_fpga_link_dst_src_write(emu,
-               EMU_DST_DOCK_DAC4_RIGHT1, EMU_SRC_ALICE_EMU32A + 7);
-       emu->emu1010.output_source[7] = 28;
-       snd_emu1010_fpga_link_dst_src_write(emu,
-               EMU_DST_DOCK_PHONES_LEFT1, EMU_SRC_ALICE_EMU32A + 0); /* ALICE2 bus 0xa0 */
-       emu->emu1010.output_source[8] = 21;
-       snd_emu1010_fpga_link_dst_src_write(emu,
-               EMU_DST_DOCK_PHONES_RIGHT1, EMU_SRC_ALICE_EMU32A + 1);
-       emu->emu1010.output_source[9] = 22;
-       snd_emu1010_fpga_link_dst_src_write(emu,
-               EMU_DST_DOCK_SPDIF_LEFT1, EMU_SRC_ALICE_EMU32A + 0); /* ALICE2 bus 0xa0 */
-       emu->emu1010.output_source[10] = 21;
-       snd_emu1010_fpga_link_dst_src_write(emu,
-               EMU_DST_DOCK_SPDIF_RIGHT1, EMU_SRC_ALICE_EMU32A + 1);
-       emu->emu1010.output_source[11] = 22;
-       snd_emu1010_fpga_link_dst_src_write(emu,
-               EMU_DST_HANA_SPDIF_LEFT1, EMU_SRC_ALICE_EMU32A + 0); /* ALICE2 bus 0xa0 */
-       emu->emu1010.output_source[12] = 21;
-       snd_emu1010_fpga_link_dst_src_write(emu,
-               EMU_DST_HANA_SPDIF_RIGHT1, EMU_SRC_ALICE_EMU32A + 1);
-       emu->emu1010.output_source[13] = 22;
-       snd_emu1010_fpga_link_dst_src_write(emu,
-               EMU_DST_HAMOA_DAC_LEFT1, EMU_SRC_ALICE_EMU32A + 0); /* ALICE2 bus 0xa0 */
-       emu->emu1010.output_source[14] = 21;
-       snd_emu1010_fpga_link_dst_src_write(emu,
-               EMU_DST_HAMOA_DAC_RIGHT1, EMU_SRC_ALICE_EMU32A + 1);
-       emu->emu1010.output_source[15] = 22;
-       snd_emu1010_fpga_link_dst_src_write(emu,
-               EMU_DST_HANA_ADAT, EMU_SRC_ALICE_EMU32A + 0); /* ALICE2 bus 0xa0 */
-       emu->emu1010.output_source[16] = 21;
-       snd_emu1010_fpga_link_dst_src_write(emu,
-               EMU_DST_HANA_ADAT + 1, EMU_SRC_ALICE_EMU32A + 1);
-       emu->emu1010.output_source[17] = 22;
-       snd_emu1010_fpga_link_dst_src_write(emu,
-               EMU_DST_HANA_ADAT + 2, EMU_SRC_ALICE_EMU32A + 2);
-       emu->emu1010.output_source[18] = 23;
-       snd_emu1010_fpga_link_dst_src_write(emu,
-               EMU_DST_HANA_ADAT + 3, EMU_SRC_ALICE_EMU32A + 3);
-       emu->emu1010.output_source[19] = 24;
-       snd_emu1010_fpga_link_dst_src_write(emu,
-               EMU_DST_HANA_ADAT + 4, EMU_SRC_ALICE_EMU32A + 4);
-       emu->emu1010.output_source[20] = 25;
-       snd_emu1010_fpga_link_dst_src_write(emu,
-               EMU_DST_HANA_ADAT + 5, EMU_SRC_ALICE_EMU32A + 5);
-       emu->emu1010.output_source[21] = 26;
-       snd_emu1010_fpga_link_dst_src_write(emu,
-               EMU_DST_HANA_ADAT + 6, EMU_SRC_ALICE_EMU32A + 6);
-       emu->emu1010.output_source[22] = 27;
-       snd_emu1010_fpga_link_dst_src_write(emu,
-               EMU_DST_HANA_ADAT + 7, EMU_SRC_ALICE_EMU32A + 7);
-       emu->emu1010.output_source[23] = 28;
-
+       if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616) {
+               /* 1616(M) cardbus default outputs */
+               /* ALICE2 bus 0xa0 */
+               snd_emu1010_fpga_link_dst_src_write(emu,
+                       EMU_DST_DOCK_DAC1_LEFT1, EMU_SRC_ALICE_EMU32A + 0);
+               emu->emu1010.output_source[0] = 17;
+               snd_emu1010_fpga_link_dst_src_write(emu,
+                       EMU_DST_DOCK_DAC1_RIGHT1, EMU_SRC_ALICE_EMU32A + 1);
+               emu->emu1010.output_source[1] = 18;
+               snd_emu1010_fpga_link_dst_src_write(emu,
+                       EMU_DST_DOCK_DAC2_LEFT1, EMU_SRC_ALICE_EMU32A + 2);
+               emu->emu1010.output_source[2] = 19;
+               snd_emu1010_fpga_link_dst_src_write(emu,
+                       EMU_DST_DOCK_DAC2_RIGHT1, EMU_SRC_ALICE_EMU32A + 3);
+               emu->emu1010.output_source[3] = 20;
+               snd_emu1010_fpga_link_dst_src_write(emu,
+                       EMU_DST_DOCK_DAC3_LEFT1, EMU_SRC_ALICE_EMU32A + 4);
+               emu->emu1010.output_source[4] = 21;
+               snd_emu1010_fpga_link_dst_src_write(emu,
+                       EMU_DST_DOCK_DAC3_RIGHT1, EMU_SRC_ALICE_EMU32A + 5);
+               emu->emu1010.output_source[5] = 22;
+               /* ALICE2 bus 0xa0 */
+               snd_emu1010_fpga_link_dst_src_write(emu,
+                       EMU_DST_MANA_DAC_LEFT, EMU_SRC_ALICE_EMU32A + 0);
+               emu->emu1010.output_source[16] = 17;
+               snd_emu1010_fpga_link_dst_src_write(emu,
+                       EMU_DST_MANA_DAC_RIGHT, EMU_SRC_ALICE_EMU32A + 1);
+               emu->emu1010.output_source[17] = 18;
+       } else {
+               /* ALICE2 bus 0xa0 */
+               snd_emu1010_fpga_link_dst_src_write(emu,
+                       EMU_DST_DOCK_DAC1_LEFT1, EMU_SRC_ALICE_EMU32A + 0);
+               emu->emu1010.output_source[0] = 21;
+               snd_emu1010_fpga_link_dst_src_write(emu,
+                       EMU_DST_DOCK_DAC1_RIGHT1, EMU_SRC_ALICE_EMU32A + 1);
+               emu->emu1010.output_source[1] = 22;
+               snd_emu1010_fpga_link_dst_src_write(emu,
+                       EMU_DST_DOCK_DAC2_LEFT1, EMU_SRC_ALICE_EMU32A + 2);
+               emu->emu1010.output_source[2] = 23;
+               snd_emu1010_fpga_link_dst_src_write(emu,
+                       EMU_DST_DOCK_DAC2_RIGHT1, EMU_SRC_ALICE_EMU32A + 3);
+               emu->emu1010.output_source[3] = 24;
+               snd_emu1010_fpga_link_dst_src_write(emu,
+                       EMU_DST_DOCK_DAC3_LEFT1, EMU_SRC_ALICE_EMU32A + 4);
+               emu->emu1010.output_source[4] = 25;
+               snd_emu1010_fpga_link_dst_src_write(emu,
+                       EMU_DST_DOCK_DAC3_RIGHT1, EMU_SRC_ALICE_EMU32A + 5);
+               emu->emu1010.output_source[5] = 26;
+               snd_emu1010_fpga_link_dst_src_write(emu,
+                       EMU_DST_DOCK_DAC4_LEFT1, EMU_SRC_ALICE_EMU32A + 6);
+               emu->emu1010.output_source[6] = 27;
+               snd_emu1010_fpga_link_dst_src_write(emu,
+                       EMU_DST_DOCK_DAC4_RIGHT1, EMU_SRC_ALICE_EMU32A + 7);
+               emu->emu1010.output_source[7] = 28;
+               /* ALICE2 bus 0xa0 */
+               snd_emu1010_fpga_link_dst_src_write(emu,
+                       EMU_DST_DOCK_PHONES_LEFT1, EMU_SRC_ALICE_EMU32A + 0);
+               emu->emu1010.output_source[8] = 21;
+               snd_emu1010_fpga_link_dst_src_write(emu,
+                       EMU_DST_DOCK_PHONES_RIGHT1, EMU_SRC_ALICE_EMU32A + 1);
+               emu->emu1010.output_source[9] = 22;
+               /* ALICE2 bus 0xa0 */
+               snd_emu1010_fpga_link_dst_src_write(emu,
+                       EMU_DST_DOCK_SPDIF_LEFT1, EMU_SRC_ALICE_EMU32A + 0);
+               emu->emu1010.output_source[10] = 21;
+               snd_emu1010_fpga_link_dst_src_write(emu,
+                       EMU_DST_DOCK_SPDIF_RIGHT1, EMU_SRC_ALICE_EMU32A + 1);
+               emu->emu1010.output_source[11] = 22;
+               /* ALICE2 bus 0xa0 */
+               snd_emu1010_fpga_link_dst_src_write(emu,
+                       EMU_DST_HANA_SPDIF_LEFT1, EMU_SRC_ALICE_EMU32A + 0);
+               emu->emu1010.output_source[12] = 21;
+               snd_emu1010_fpga_link_dst_src_write(emu,
+                       EMU_DST_HANA_SPDIF_RIGHT1, EMU_SRC_ALICE_EMU32A + 1);
+               emu->emu1010.output_source[13] = 22;
+               /* ALICE2 bus 0xa0 */
+               snd_emu1010_fpga_link_dst_src_write(emu,
+                       EMU_DST_HAMOA_DAC_LEFT1, EMU_SRC_ALICE_EMU32A + 0);
+               emu->emu1010.output_source[14] = 21;
+               snd_emu1010_fpga_link_dst_src_write(emu,
+                       EMU_DST_HAMOA_DAC_RIGHT1, EMU_SRC_ALICE_EMU32A + 1);
+               emu->emu1010.output_source[15] = 22;
+               /* ALICE2 bus 0xa0 */
+               snd_emu1010_fpga_link_dst_src_write(emu,
+                       EMU_DST_HANA_ADAT, EMU_SRC_ALICE_EMU32A + 0);
+               emu->emu1010.output_source[16] = 21;
+               snd_emu1010_fpga_link_dst_src_write(emu,
+                       EMU_DST_HANA_ADAT + 1, EMU_SRC_ALICE_EMU32A + 1);
+               emu->emu1010.output_source[17] = 22;
+               snd_emu1010_fpga_link_dst_src_write(emu,
+                       EMU_DST_HANA_ADAT + 2, EMU_SRC_ALICE_EMU32A + 2);
+               emu->emu1010.output_source[18] = 23;
+               snd_emu1010_fpga_link_dst_src_write(emu,
+                       EMU_DST_HANA_ADAT + 3, EMU_SRC_ALICE_EMU32A + 3);
+               emu->emu1010.output_source[19] = 24;
+               snd_emu1010_fpga_link_dst_src_write(emu,
+                       EMU_DST_HANA_ADAT + 4, EMU_SRC_ALICE_EMU32A + 4);
+               emu->emu1010.output_source[20] = 25;
+               snd_emu1010_fpga_link_dst_src_write(emu,
+                       EMU_DST_HANA_ADAT + 5, EMU_SRC_ALICE_EMU32A + 5);
+               emu->emu1010.output_source[21] = 26;
+               snd_emu1010_fpga_link_dst_src_write(emu,
+                       EMU_DST_HANA_ADAT + 6, EMU_SRC_ALICE_EMU32A + 6);
+               emu->emu1010.output_source[22] = 27;
+               snd_emu1010_fpga_link_dst_src_write(emu,
+                       EMU_DST_HANA_ADAT + 7, EMU_SRC_ALICE_EMU32A + 7);
+               emu->emu1010.output_source[23] = 28;
+       }
        /* TEMP: Select SPDIF in/out */
        //snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, 0x0); /* Output spdif */
 
@@ -1202,11 +1256,12 @@ static int snd_emu10k1_free(struct snd_emu10k1 *emu)
                }
                snd_emu10k1_free_efx(emu);
                }
-       if (emu->card_capabilities->emu1010) {
+       if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1010) {
                /* Disable 48Volt power to Audio Dock */
                snd_emu1010_fpga_write(emu,  EMU_HANA_DOCK_PWR,  0 );
-               kthread_stop(emu->emu1010.firmware_thread);
        }
+       if (emu->emu1010.firmware_thread)
+               kthread_stop(emu->emu1010.firmware_thread);
        if (emu->memhdr)
                snd_util_memhdr_free(emu->memhdr);
        if (emu->silent_page.area)
@@ -1338,6 +1393,7 @@ static struct snd_emu_chip_details emu_chip_details[] = {
         .spi_dac = 1,
         .i2c_adc = 1,
         .spk71 = 1} ,
+       /* Tested by James@superbug.co.uk 4th Nov 2007. */
        {.vendor = 0x1102, .device = 0x0008, .subsystem = 0x42011102,
         .driver = "Audigy2", .name = "E-mu 1010 Notebook [MAEM8950]", 
         .id = "EMU1010",
@@ -1345,28 +1401,46 @@ static struct snd_emu_chip_details emu_chip_details[] = {
         .ca0108_chip = 1,
         .ca_cardbus_chip = 1,
         .spk71 = 1 ,
-        .emu1010 = 3} ,
+        .emu_model = EMU_MODEL_EMU1616},
+       /* Tested by James@superbug.co.uk 4th Nov 2007. */
        {.vendor = 0x1102, .device = 0x0008, .subsystem = 0x40041102,
         .driver = "Audigy2", .name = "E-mu 1010b PCI [MAEM????]", 
         .id = "EMU1010",
         .emu10k2_chip = 1,
         .ca0108_chip = 1,
-        .spk71 = 1 ,
-        .emu1010 = 2} ,
+        .spk71 = 1,
+        .emu_model = EMU_MODEL_EMU1010B},
+       /* Tested by James@superbug.co.uk 8th July 2005. */
+       {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x40011102,
+        .driver = "Audigy2", .name = "E-mu 1010 [4001]",
+        .id = "EMU1010",
+        .emu10k2_chip = 1,
+        .ca0102_chip = 1,
+        .spk71 = 1,
+        .emu_model = EMU_MODEL_EMU1010}, /* Emu 1010 */
+       /* EMU0404b */
+       {.vendor = 0x1102, .device = 0x0008, .subsystem = 0x40021102,
+        .driver = "Audigy2", .name = "E-mu 0404b [4002]",
+        .id = "EMU0404",
+        .emu10k2_chip = 1,
+        .ca0108_chip = 1,
+        .spk71 = 1,
+        .emu_model = EMU_MODEL_EMU0404}, /* EMU 0404 */
+       /* Tested by James@superbug.co.uk 20-3-2007. */
+       {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x40021102,
+        .driver = "Audigy2", .name = "E-mu 0404 [4002]",
+        .id = "EMU0404",
+        .emu10k2_chip = 1,
+        .ca0102_chip = 1,
+        .spk71 = 1,
+        .emu_model = EMU_MODEL_EMU0404}, /* EMU 0404 */
+       /* Audigy4 (Not PRO) SB0610 */
        {.vendor = 0x1102, .device = 0x0008, 
         .driver = "Audigy2", .name = "Audigy 2 Value [Unknown]", 
         .id = "Audigy2",
         .emu10k2_chip = 1,
         .ca0108_chip = 1,
         .ac97_chip = 1} ,
-       /* Tested by James@superbug.co.uk 8th July 2005. No sound available yet. */
-       {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x40011102,
-        .driver = "Audigy2", .name = "E-mu 1010 [4001]", 
-        .id = "EMU1010",
-        .emu10k2_chip = 1,
-        .ca0102_chip = 1,
-        .spk71 = 1,
-        .emu1010 = 1} ,
        /* Tested by James@superbug.co.uk 3rd July 2005 */
        {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x20071102,
         .driver = "Audigy2", .name = "Audigy 4 PRO [SB0380]", 
@@ -1654,6 +1728,8 @@ int __devinit snd_emu10k1_create(struct snd_card *card,
        emu->card = card;
        spin_lock_init(&emu->reg_lock);
        spin_lock_init(&emu->emu_lock);
+       spin_lock_init(&emu->spi_lock);
+       spin_lock_init(&emu->i2c_lock);
        spin_lock_init(&emu->voice_lock);
        spin_lock_init(&emu->synth_lock);
        spin_lock_init(&emu->memblk_lock);
@@ -1794,7 +1870,7 @@ int __devinit snd_emu10k1_create(struct snd_card *card,
        if (emu->card_capabilities->ecard) {
                if ((err = snd_emu10k1_ecard_init(emu)) < 0)
                        goto error;
-       } else if (emu->card_capabilities->emu1010) {
+       } else if (emu->card_capabilities->emu_model) {
                if ((err = snd_emu10k1_emu1010_init(emu)) < 0) {
                        snd_emu10k1_free(emu);
                        return err;
@@ -1943,7 +2019,7 @@ void snd_emu10k1_resume_init(struct snd_emu10k1 *emu)
                snd_emu10k1_cardbus_init(emu);
        if (emu->card_capabilities->ecard)
                snd_emu10k1_ecard_init(emu);
-       else if (emu->card_capabilities->emu1010)
+       else if (emu->card_capabilities->emu_model)
                snd_emu10k1_emu1010_init(emu);
        else
                snd_emu10k1_ptr_write(emu, AC97SLOT, 0, AC97SLOT_CNTR|AC97SLOT_LFE);
index 204995a1dfbd15e311f0dbce1360b7529b4a5f95..ad7b71491fc49cd32a9d08f8abbf3c5e4938485e 100644 (file)
@@ -30,7 +30,7 @@ MODULE_LICENSE("GPL");
  */
 static int snd_emu10k1_synth_new_device(struct snd_seq_device *dev)
 {
-       struct snd_emux *emu;
+       struct snd_emux *emux;
        struct snd_emu10k1 *hw;
        struct snd_emu10k1_synth_arg *arg;
        unsigned long flags;
@@ -46,53 +46,56 @@ static int snd_emu10k1_synth_new_device(struct snd_seq_device *dev)
        else if (arg->max_voices > 64)
                arg->max_voices = 64;
 
-       if (snd_emux_new(&emu) < 0)
+       if (snd_emux_new(&emux) < 0)
                return -ENOMEM;
 
-       snd_emu10k1_ops_setup(emu);
-       emu->hw = hw = arg->hwptr;
-       emu->max_voices = arg->max_voices;
-       emu->num_ports = arg->seq_ports;
-       emu->pitch_shift = -501;
-       emu->memhdr = hw->memhdr;
-       emu->midi_ports = arg->seq_ports < 2 ? arg->seq_ports : 2; /* maximum two ports */
-       emu->midi_devidx = hw->audigy ? 2 : 1; /* audigy has two external midis */
-       emu->linear_panning = 0;
-       emu->hwdep_idx = 2; /* FIXED */
-
-       if (snd_emux_register(emu, dev->card, arg->index, "Emu10k1") < 0) {
-               snd_emux_free(emu);
+       snd_emu10k1_ops_setup(emux);
+       hw = arg->hwptr;
+       emux->hw = hw;
+       emux->max_voices = arg->max_voices;
+       emux->num_ports = arg->seq_ports;
+       emux->pitch_shift = -501;
+       emux->memhdr = hw->memhdr;
+       /* maximum two ports */
+       emux->midi_ports = arg->seq_ports < 2 ? arg->seq_ports : 2;
+       /* audigy has two external midis */
+       emux->midi_devidx = hw->audigy ? 2 : 1;
+       emux->linear_panning = 0;
+       emux->hwdep_idx = 2; /* FIXED */
+
+       if (snd_emux_register(emux, dev->card, arg->index, "Emu10k1") < 0) {
+               snd_emux_free(emux);
                return -ENOMEM;
        }
 
        spin_lock_irqsave(&hw->voice_lock, flags);
-       hw->synth = emu;
+       hw->synth = emux;
        hw->get_synth_voice = snd_emu10k1_synth_get_voice;
        spin_unlock_irqrestore(&hw->voice_lock, flags);
 
-       dev->driver_data = emu;
+       dev->driver_data = emux;
 
        return 0;
 }
 
 static int snd_emu10k1_synth_delete_device(struct snd_seq_device *dev)
 {
-       struct snd_emux *emu;
+       struct snd_emux *emux;
        struct snd_emu10k1 *hw;
        unsigned long flags;
 
        if (dev->driver_data == NULL)
                return 0; /* not registered actually */
 
-       emu = dev->driver_data;
+       emux = dev->driver_data;
 
-       hw = emu->hw;
+       hw = emux->hw;
        spin_lock_irqsave(&hw->voice_lock, flags);
        hw->synth = NULL;
        hw->get_synth_voice = NULL;
        spin_unlock_irqrestore(&hw->voice_lock, flags);
 
-       snd_emux_free(emu);
+       snd_emux_free(emux);
        return 0;
 }
 
index 308ddc84bb4dbe4bcecfd4c25c8875866beccebe..25f328ff639f35cdf14927a0ba11462a119df817 100644 (file)
@@ -20,7 +20,6 @@
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-#include <sound/driver.h>
 #include <linux/time.h>
 #include <sound/core.h>
 #include <sound/emu10k1_synth.h>
index 1ec7ebaff9e9f534f92fbbf0723f30082cce7320..5512abd98bd93f3f69370f792e592145b3c3b92e 100644 (file)
@@ -29,7 +29,6 @@
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  *
  */
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/pci.h>
@@ -1583,6 +1582,8 @@ static int __devinit snd_emu10k1x_probe(struct pci_dev *pci,
        sprintf(card->longname, "%s at 0x%lx irq %i",
                card->shortname, chip->port, chip->irq);
 
+       snd_card_set_dev(card, &pci->dev);
+
        if ((err = snd_card_register(card)) < 0) {
                snd_card_free(card);
                return err;
index 9bf1cd59219912ca5d435e706b13302f70f77585..71dc4c8865b88323edbe13a811c5171061d26e51 100644 (file)
@@ -28,7 +28,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/pci.h>
 #include <linux/capability.h>
 #include <linux/delay.h>
@@ -666,7 +665,7 @@ static unsigned int *copy_tlv(const unsigned int __user *_tlv)
                return NULL;
        if (data[1] >= MAX_TLV_SIZE)
                return NULL;
-       tlv = kmalloc(data[1] * 4 + sizeof(data), GFP_KERNEL);
+       tlv = kmalloc(data[1] + sizeof(data), GFP_KERNEL);
        if (!tlv)
                return NULL;
        memcpy(tlv, data, sizeof(data));
@@ -1262,7 +1261,7 @@ static int __devinit _snd_emu10k1_audigy_init_efx(struct snd_emu10k1 *emu)
 A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input))
 
        /* emu1212 DSP 0 and DSP 1 Capture */
-       if (emu->card_capabilities->emu1010) {
+       if (emu->card_capabilities->emu_model) {
                if (emu->card_capabilities->ca0108_chip) {
                        /* Note:JCD:No longer bit shift lower 16bits to upper 16bits of 32bit value. */
                        A_OP(icode, &ptr, iMACINT0, A_GPR(tmp), A_C_00000000, A3_EMU32IN(0x0), A_C_00000001);
@@ -1516,7 +1515,7 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input))
 
        /* digital outputs */
        /* A_PUT_STEREO_OUTPUT(A_EXTOUT_FRONT_L, A_EXTOUT_FRONT_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS); */
-       if (emu->card_capabilities->emu1010) {
+       if (emu->card_capabilities->emu_model) {
                /* EMU1010 Outputs from PCM Front, Rear, Center, LFE, Side */
                snd_printk("EMU outputs on\n");
                for (z = 0; z < 8; z++) {
@@ -1564,7 +1563,7 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input))
        A_PUT_OUTPUT(A_EXTOUT_ADC_CAP_R, capture+1);
 #endif
 
-       if (emu->card_capabilities->emu1010) {
+       if (emu->card_capabilities->emu_model) {
                if (emu->card_capabilities->ca0108_chip) {
                        snd_printk("EMU2 inputs on\n");
                        for (z = 0; z < 0x10; z++) {
index ccacd7b890e82cb5f3293e622496b3deaf5b813d..fd221209abcb221f6db0dcf323476b8620e40331 100644 (file)
@@ -30,7 +30,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/time.h>
 #include <linux/init.h>
 #include <sound/core.h>
@@ -140,6 +139,61 @@ static char *emu1010_src_texts[] = {
        "DSP 31",
 };
 
+/* 1616(m) cardbus */
+
+static char *emu1616_src_texts[] = {
+       "Silence",
+       "Dock Mic A",
+       "Dock Mic B",
+       "Dock ADC1 Left",
+       "Dock ADC1 Right",
+       "Dock ADC2 Left",
+       "Dock ADC2 Right",
+       "Dock SPDIF Left",
+       "Dock SPDIF Right",
+       "ADAT 0",
+       "ADAT 1",
+       "ADAT 2",
+       "ADAT 3",
+       "ADAT 4",
+       "ADAT 5",
+       "ADAT 6",
+       "ADAT 7",
+       "DSP 0",
+       "DSP 1",
+       "DSP 2",
+       "DSP 3",
+       "DSP 4",
+       "DSP 5",
+       "DSP 6",
+       "DSP 7",
+       "DSP 8",
+       "DSP 9",
+       "DSP 10",
+       "DSP 11",
+       "DSP 12",
+       "DSP 13",
+       "DSP 14",
+       "DSP 15",
+       "DSP 16",
+       "DSP 17",
+       "DSP 18",
+       "DSP 19",
+       "DSP 20",
+       "DSP 21",
+       "DSP 22",
+       "DSP 23",
+       "DSP 24",
+       "DSP 25",
+       "DSP 26",
+       "DSP 27",
+       "DSP 28",
+       "DSP 29",
+       "DSP 30",
+       "DSP 31",
+};
+
+
 /*
  * List of data sources available for each destination
  */
@@ -199,6 +253,59 @@ static unsigned int emu1010_src_regs[] = {
        EMU_SRC_ALICE_EMU32B+0xf, /* 52 */
 };
 
+/* 1616(m) cardbus */
+static unsigned int emu1616_src_regs[] = {
+       EMU_SRC_SILENCE,
+       EMU_SRC_DOCK_MIC_A1,
+       EMU_SRC_DOCK_MIC_B1,
+       EMU_SRC_DOCK_ADC1_LEFT1,
+       EMU_SRC_DOCK_ADC1_RIGHT1,
+       EMU_SRC_DOCK_ADC2_LEFT1,
+       EMU_SRC_DOCK_ADC2_RIGHT1,
+       EMU_SRC_MDOCK_SPDIF_LEFT1,
+       EMU_SRC_MDOCK_SPDIF_RIGHT1,
+       EMU_SRC_MDOCK_ADAT,
+       EMU_SRC_MDOCK_ADAT+1,
+       EMU_SRC_MDOCK_ADAT+2,
+       EMU_SRC_MDOCK_ADAT+3,
+       EMU_SRC_MDOCK_ADAT+4,
+       EMU_SRC_MDOCK_ADAT+5,
+       EMU_SRC_MDOCK_ADAT+6,
+       EMU_SRC_MDOCK_ADAT+7,
+       EMU_SRC_ALICE_EMU32A,
+       EMU_SRC_ALICE_EMU32A+1,
+       EMU_SRC_ALICE_EMU32A+2,
+       EMU_SRC_ALICE_EMU32A+3,
+       EMU_SRC_ALICE_EMU32A+4,
+       EMU_SRC_ALICE_EMU32A+5,
+       EMU_SRC_ALICE_EMU32A+6,
+       EMU_SRC_ALICE_EMU32A+7,
+       EMU_SRC_ALICE_EMU32A+8,
+       EMU_SRC_ALICE_EMU32A+9,
+       EMU_SRC_ALICE_EMU32A+0xa,
+       EMU_SRC_ALICE_EMU32A+0xb,
+       EMU_SRC_ALICE_EMU32A+0xc,
+       EMU_SRC_ALICE_EMU32A+0xd,
+       EMU_SRC_ALICE_EMU32A+0xe,
+       EMU_SRC_ALICE_EMU32A+0xf,
+       EMU_SRC_ALICE_EMU32B,
+       EMU_SRC_ALICE_EMU32B+1,
+       EMU_SRC_ALICE_EMU32B+2,
+       EMU_SRC_ALICE_EMU32B+3,
+       EMU_SRC_ALICE_EMU32B+4,
+       EMU_SRC_ALICE_EMU32B+5,
+       EMU_SRC_ALICE_EMU32B+6,
+       EMU_SRC_ALICE_EMU32B+7,
+       EMU_SRC_ALICE_EMU32B+8,
+       EMU_SRC_ALICE_EMU32B+9,
+       EMU_SRC_ALICE_EMU32B+0xa,
+       EMU_SRC_ALICE_EMU32B+0xb,
+       EMU_SRC_ALICE_EMU32B+0xc,
+       EMU_SRC_ALICE_EMU32B+0xd,
+       EMU_SRC_ALICE_EMU32B+0xe,
+       EMU_SRC_ALICE_EMU32B+0xf,
+};
+
 /*
  * Data destinations - physical EMU outputs.
  * Each destination has an enum mixer control to choose a data source
@@ -230,6 +337,28 @@ static unsigned int emu1010_output_dst[] = {
        EMU_DST_HANA_ADAT+7, /* 23 */
 };
 
+/* 1616(m) cardbus */
+static unsigned int emu1616_output_dst[] = {
+       EMU_DST_DOCK_DAC1_LEFT1,
+       EMU_DST_DOCK_DAC1_RIGHT1,
+       EMU_DST_DOCK_DAC2_LEFT1,
+       EMU_DST_DOCK_DAC2_RIGHT1,
+       EMU_DST_DOCK_DAC3_LEFT1,
+       EMU_DST_DOCK_DAC3_RIGHT1,
+       EMU_DST_MDOCK_SPDIF_LEFT1,
+       EMU_DST_MDOCK_SPDIF_RIGHT1,
+       EMU_DST_MDOCK_ADAT,
+       EMU_DST_MDOCK_ADAT+1,
+       EMU_DST_MDOCK_ADAT+2,
+       EMU_DST_MDOCK_ADAT+3,
+       EMU_DST_MDOCK_ADAT+4,
+       EMU_DST_MDOCK_ADAT+5,
+       EMU_DST_MDOCK_ADAT+6,
+       EMU_DST_MDOCK_ADAT+7,
+       EMU_DST_MANA_DAC_LEFT,
+       EMU_DST_MANA_DAC_RIGHT,
+};
+
 /*
  * Data destinations - HANA outputs going to Alice2 (audigy) for
  *   capture (EMU32 + I2S links)
@@ -260,14 +389,26 @@ static unsigned int emu1010_input_dst[] = {
        EMU_DST_ALICE_I2S2_RIGHT,
 };
 
-static int snd_emu1010_input_output_source_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
+static int snd_emu1010_input_output_source_info(struct snd_kcontrol *kcontrol,
+                                               struct snd_ctl_elem_info *uinfo)
 {
+       struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
+       char **items;
+
        uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
        uinfo->count = 1;
-       uinfo->value.enumerated.items = 53;
+       if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616) {
+               uinfo->value.enumerated.items = 49;
+               items = emu1616_src_texts;
+       } else {
+               uinfo->value.enumerated.items = 53;
+               items = emu1010_src_texts;
+       }
        if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
-               uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
-       strcpy(uinfo->value.enumerated.name, emu1010_src_texts[uinfo->value.enumerated.item]);
+               uinfo->value.enumerated.item =
+                       uinfo->value.enumerated.items - 1;
+       strcpy(uinfo->value.enumerated.name,
+              items[uinfo->value.enumerated.item]);
        return 0;
 }
 
@@ -279,7 +420,9 @@ static int snd_emu1010_output_source_get(struct snd_kcontrol *kcontrol,
 
        channel = (kcontrol->private_value) & 0xff;
        /* Limit: emu1010_output_dst, emu->emu1010.output_source */
-       if (channel >= 24)
+       if (channel >= 24 ||
+           (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616 &&
+            channel >= 18))
                return -EINVAL;
        ucontrol->value.enumerated.item[0] = emu->emu1010.output_source[channel];
        return 0;
@@ -289,24 +432,30 @@ static int snd_emu1010_output_source_put(struct snd_kcontrol *kcontrol,
                                  struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
-       int change = 0;
        unsigned int val;
        unsigned int channel;
 
        val = ucontrol->value.enumerated.item[0];
-       if (val >= 53)
+       if (val >= 53 ||
+           (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616 &&
+            val >= 49))
                return -EINVAL;
        channel = (kcontrol->private_value) & 0xff;
        /* Limit: emu1010_output_dst, emu->emu1010.output_source */
-       if (channel >= 24)
+       if (channel >= 24 ||
+           (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616 &&
+            channel >= 18))
                return -EINVAL;
-       if (emu->emu1010.output_source[channel] != val) {
-               emu->emu1010.output_source[channel] = val;
-               change = 1;
+       if (emu->emu1010.output_source[channel] == val)
+               return 0;
+       emu->emu1010.output_source[channel] = val;
+       if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616)
+               snd_emu1010_fpga_link_dst_src_write(emu,
+                       emu1616_output_dst[channel], emu1616_src_regs[val]);
+       else
                snd_emu1010_fpga_link_dst_src_write(emu,
                        emu1010_output_dst[channel], emu1010_src_regs[val]);
-       }
-       return change;
+       return 1;
 }
 
 static int snd_emu1010_input_source_get(struct snd_kcontrol *kcontrol,
@@ -327,24 +476,28 @@ static int snd_emu1010_input_source_put(struct snd_kcontrol *kcontrol,
                                  struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
-       int change = 0;
        unsigned int val;
        unsigned int channel;
 
        val = ucontrol->value.enumerated.item[0];
-       if (val >= 53)
+       if (val >= 53 ||
+           (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616 &&
+            val >= 49))
                return -EINVAL;
        channel = (kcontrol->private_value) & 0xff;
        /* Limit: emu1010_input_dst, emu->emu1010.input_source */
        if (channel >= 22)
                return -EINVAL;
-       if (emu->emu1010.input_source[channel] != val) {
-               emu->emu1010.input_source[channel] = val;
-               change = 1;
+       if (emu->emu1010.input_source[channel] == val)
+               return 0;
+       emu->emu1010.input_source[channel] = val;
+       if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616)
+               snd_emu1010_fpga_link_dst_src_write(emu,
+                       emu1010_input_dst[channel], emu1616_src_regs[val]);
+       else
                snd_emu1010_fpga_link_dst_src_write(emu,
                        emu1010_input_dst[channel], emu1010_src_regs[val]);
-       }
-       return change;
+       return 1;
 }
 
 #define EMU1010_SOURCE_OUTPUT(xname,chid) \
@@ -384,6 +537,30 @@ static struct snd_kcontrol_new snd_emu1010_output_enum_ctls[] __devinitdata = {
        EMU1010_SOURCE_OUTPUT("1010 ADAT 7 Playback Enum", 0x17),
 };
 
+
+/* 1616(m) cardbus */
+static struct snd_kcontrol_new snd_emu1616_output_enum_ctls[] __devinitdata = {
+       EMU1010_SOURCE_OUTPUT("Dock DAC1 Left Playback Enum", 0),
+       EMU1010_SOURCE_OUTPUT("Dock DAC1 Right Playback Enum", 1),
+       EMU1010_SOURCE_OUTPUT("Dock DAC2 Left Playback Enum", 2),
+       EMU1010_SOURCE_OUTPUT("Dock DAC2 Right Playback Enum", 3),
+       EMU1010_SOURCE_OUTPUT("Dock DAC3 Left Playback Enum", 4),
+       EMU1010_SOURCE_OUTPUT("Dock DAC3 Right Playback Enum", 5),
+       EMU1010_SOURCE_OUTPUT("Dock SPDIF Left Playback Enum", 6),
+       EMU1010_SOURCE_OUTPUT("Dock SPDIF Right Playback Enum", 7),
+       EMU1010_SOURCE_OUTPUT("Dock ADAT 0 Playback Enum", 8),
+       EMU1010_SOURCE_OUTPUT("Dock ADAT 1 Playback Enum", 9),
+       EMU1010_SOURCE_OUTPUT("Dock ADAT 2 Playback Enum", 0xa),
+       EMU1010_SOURCE_OUTPUT("Dock ADAT 3 Playback Enum", 0xb),
+       EMU1010_SOURCE_OUTPUT("Dock ADAT 4 Playback Enum", 0xc),
+       EMU1010_SOURCE_OUTPUT("Dock ADAT 5 Playback Enum", 0xd),
+       EMU1010_SOURCE_OUTPUT("Dock ADAT 6 Playback Enum", 0xe),
+       EMU1010_SOURCE_OUTPUT("Dock ADAT 7 Playback Enum", 0xf),
+       EMU1010_SOURCE_OUTPUT("Mana DAC Left Playback Enum", 0x10),
+       EMU1010_SOURCE_OUTPUT("Mana DAC Right Playback Enum", 0x11),
+};
+
+
 #define EMU1010_SOURCE_INPUT(xname,chid) \
 {                                                              \
        .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,     \
@@ -1793,7 +1970,7 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu,
                        return err;
        }
 
-       if ( emu->card_capabilities->emu1010) {
+       if (emu->card_capabilities->emu_model) {
                ;  /* Disable the snd_audigy_spdif_shared_spdif */
        } else if (emu->audigy) {
                if ((kctl = snd_ctl_new1(&snd_audigy_shared_spdif, emu)) == NULL)
@@ -1818,30 +1995,73 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu,
                        return err;
        }
 
-       if ( emu->card_capabilities->emu1010) {
+       if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616) {
+               /* 1616(m) cardbus */
+               int i;
+
+               for (i = 0; i < ARRAY_SIZE(snd_emu1616_output_enum_ctls); i++) {
+                       err = snd_ctl_add(card,
+                               snd_ctl_new1(&snd_emu1616_output_enum_ctls[i],
+                                            emu));
+                       if (err < 0)
+                               return err;
+               }
+               for (i = 0; i < ARRAY_SIZE(snd_emu1010_input_enum_ctls); i++) {
+                       err = snd_ctl_add(card,
+                               snd_ctl_new1(&snd_emu1010_input_enum_ctls[i],
+                                            emu));
+                       if (err < 0)
+                               return err;
+               }
+               for (i = 0; i < ARRAY_SIZE(snd_emu1010_adc_pads) - 2; i++) {
+                       err = snd_ctl_add(card,
+                               snd_ctl_new1(&snd_emu1010_adc_pads[i], emu));
+                       if (err < 0)
+                               return err;
+               }
+               for (i = 0; i < ARRAY_SIZE(snd_emu1010_dac_pads) - 2; i++) {
+                       err = snd_ctl_add(card,
+                               snd_ctl_new1(&snd_emu1010_dac_pads[i], emu));
+                       if (err < 0)
+                               return err;
+               }
+               err = snd_ctl_add(card,
+                       snd_ctl_new1(&snd_emu1010_internal_clock, emu));
+               if (err < 0)
+                       return err;
+
+       } else if (emu->card_capabilities->emu_model) {
+               /* all other e-mu cards for now */
                int i;
 
                for (i = 0; i < ARRAY_SIZE(snd_emu1010_output_enum_ctls); i++) {
-                       err = snd_ctl_add(card, snd_ctl_new1(&snd_emu1010_output_enum_ctls[i], emu));
+                       err = snd_ctl_add(card,
+                               snd_ctl_new1(&snd_emu1010_output_enum_ctls[i],
+                                            emu));
                        if (err < 0)
                                return err;
                }
                for (i = 0; i < ARRAY_SIZE(snd_emu1010_input_enum_ctls); i++) {
-                       err = snd_ctl_add(card, snd_ctl_new1(&snd_emu1010_input_enum_ctls[i], emu));
+                       err = snd_ctl_add(card,
+                               snd_ctl_new1(&snd_emu1010_input_enum_ctls[i],
+                                            emu));
                        if (err < 0)
                                return err;
                }
                for (i = 0; i < ARRAY_SIZE(snd_emu1010_adc_pads); i++) {
-                       err = snd_ctl_add(card, snd_ctl_new1(&snd_emu1010_adc_pads[i], emu));
+                       err = snd_ctl_add(card,
+                               snd_ctl_new1(&snd_emu1010_adc_pads[i], emu));
                        if (err < 0)
                                return err;
                }
                for (i = 0; i < ARRAY_SIZE(snd_emu1010_dac_pads); i++) {
-                       err = snd_ctl_add(card, snd_ctl_new1(&snd_emu1010_dac_pads[i], emu));
+                       err = snd_ctl_add(card,
+                               snd_ctl_new1(&snd_emu1010_dac_pads[i], emu));
                        if (err < 0)
                                return err;
                }
-               err = snd_ctl_add(card, snd_ctl_new1(&snd_emu1010_internal_clock, emu));
+               err = snd_ctl_add(card,
+                       snd_ctl_new1(&snd_emu1010_internal_clock, emu));
                if (err < 0)
                        return err;
        }
index 04c7cf703531e26ef4744979f7b4a773a6cfc9fa..c4d76d16661eed2d5af5a49ec51e81cb22cef45c 100644 (file)
@@ -19,7 +19,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/time.h>
 #include <linux/init.h>
 #include <sound/core.h>
index 5ce5befc701b9fa5a3bc7fccaf835513b2f7e072..cf9276ddad42dba9d3c91965f788124cd2d48990 100644 (file)
@@ -26,7 +26,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
@@ -358,7 +357,7 @@ static void snd_emu10k1_pcm_init_voice(struct snd_emu10k1 *emu,
        snd_emu10k1_ptr_write(emu, PTRX, voice, (send_amount[0] << 8) | send_amount[1]);
        snd_emu10k1_ptr_write(emu, DSL, voice, end_addr | (send_amount[3] << 24));
        snd_emu10k1_ptr_write(emu, PSST, voice, start_addr | (send_amount[2] << 24));
-       if (emu->card_capabilities->emu1010)
+       if (emu->card_capabilities->emu_model)
                pitch_target = PITCH_48000; /* Disable interpolators on emu1010 card */
        else 
                pitch_target = emu10k1_calc_pitch_target(runtime->rate);
@@ -701,7 +700,7 @@ static void snd_emu10k1_playback_trigger_voice(struct snd_emu10k1 *emu, struct s
        voice = evoice->number;
 
        pitch = snd_emu10k1_rate_to_pitch(runtime->rate) >> 8;
-       if (emu->card_capabilities->emu1010)
+       if (emu->card_capabilities->emu_model)
                pitch_target = PITCH_48000; /* Disable interpolators on emu1010 card */
        else 
                pitch_target = emu10k1_calc_pitch_target(runtime->rate);
@@ -1232,7 +1231,7 @@ static int snd_emu10k1_capture_efx_open(struct snd_pcm_substream *substream)
        runtime->hw.rates = SNDRV_PCM_RATE_48000;
        runtime->hw.rate_min = runtime->hw.rate_max = 48000;
        spin_lock_irq(&emu->reg_lock);
-       if (emu->card_capabilities->emu1010) {
+       if (emu->card_capabilities->emu_model) {
                /*  Nb. of channels has been increased to 16 */
                /* TODO
                 * SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE
@@ -1791,7 +1790,7 @@ int __devinit snd_emu10k1_pcm_efx(struct snd_emu10k1 * emu, int device, struct s
        /* emu->efx_voices_mask[0] = FXWC_DEFAULTROUTE_C | FXWC_DEFAULTROUTE_A; */
        if (emu->audigy) {
                emu->efx_voices_mask[0] = 0;
-               if (emu->card_capabilities->emu1010)
+               if (emu->card_capabilities->emu_model)
                        /* Pavel Hofman - 32 voices will be used for
                         * capture (write mode) -
                         * each bit = corresponding voice
index c3fb10e81c9e0d4e6e52359ce3f27bc066494ea3..f3caa3f890c6cdd5fc3b237afa4c5c75269af1d5 100644 (file)
@@ -28,7 +28,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/slab.h>
 #include <linux/init.h>
 #include <sound/core.h>
@@ -245,7 +244,7 @@ static void snd_emu10k1_proc_spdif_read(struct snd_info_entry *entry,
        unsigned long flags;
        u32 rate;
 
-       if (emu->card_capabilities->emu1010) {
+       if (emu->card_capabilities->emu_model) {
                spin_lock_irqsave(&emu->emu_lock, flags);
                snd_emu1010_fpga_read(emu, 0x38, &value);
                spin_unlock_irqrestore(&emu->emu_lock, flags);
@@ -585,7 +584,7 @@ int __devinit snd_emu10k1_proc_init(struct snd_emu10k1 * emu)
 {
        struct snd_info_entry *entry;
 #ifdef CONFIG_SND_DEBUG
-       if (emu->card_capabilities->emu1010) {
+       if (emu->card_capabilities->emu_model) {
                if (! snd_card_proc_new(emu->card, "emu1010_regs", &entry)) 
                        snd_info_set_text_ops(entry, emu, snd_emu_proc_emu1010_reg_read);
        }
index 6702c15fefa3b52cbc95fc868ce278a161e9e219..b5a802bdeb7c1b21f76573e72bbd16fd2af74898 100644 (file)
@@ -25,7 +25,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/time.h>
 #include <sound/core.h>
 #include <sound/emu10k1.h>
@@ -71,6 +70,11 @@ void snd_emu10k1_ptr_write(struct snd_emu10k1 *emu, unsigned int reg, unsigned i
        unsigned long flags;
        unsigned int mask;
 
+       if (!emu) {
+               snd_printk(KERN_ERR "ptr_write: emu is null!\n");
+               dump_stack();
+               return;
+       }
        mask = emu->audigy ? A_PTR_ADDRESS_MASK : PTR_ADDRESS_MASK;
        regptr = ((reg << 16) & mask) | (chn & PTR_CHANNELNUM_MASK);
 
@@ -135,15 +139,23 @@ int snd_emu10k1_spi_write(struct snd_emu10k1 * emu,
        unsigned int reset, set;
        unsigned int reg, tmp;
        int n, result;
+       int err = 0;
+
+       /* This function is not re-entrant, so protect against it. */
+       spin_lock(&emu->spi_lock);
        if (emu->card_capabilities->ca0108_chip)
                reg = 0x3c; /* PTR20, reg 0x3c */
        else {
                /* For other chip types the SPI register
                 * is currently unknown. */
-               return 1;
+               err = 1;
+               goto spi_write_exit;
+       }
+       if (data > 0xffff) {
+               /* Only 16bit values allowed */
+               err = 1;
+               goto spi_write_exit;
        }
-       if (data > 0xffff) /* Only 16bit values allowed */
-               return 1;
 
        tmp = snd_emu10k1_ptr20_read(emu, reg, 0);
        reset = (tmp & ~0x3ffff) | 0x20000; /* Set xxx20000 */
@@ -161,11 +173,17 @@ int snd_emu10k1_spi_write(struct snd_emu10k1 * emu,
                        break;
                }
        }
-       if (result) /* Timed out */
-               return 1;
+       if (result) {
+               /* Timed out */
+               err = 1;
+               goto spi_write_exit;
+       }
        snd_emu10k1_ptr20_write(emu, reg, 0, reset | data);
        tmp = snd_emu10k1_ptr20_read(emu, reg, 0); /* Write post */
-       return 0;
+       err = 0;
+spi_write_exit:
+       spin_unlock(&emu->spi_lock);
+       return err;
 }
 
 /* The ADC does not support i2c read, so only write is implemented */
@@ -177,15 +195,17 @@ int snd_emu10k1_i2c_write(struct snd_emu10k1 *emu,
        int timeout = 0;
        int status;
        int retry;
+       int err = 0;
+
        if ((reg > 0x7f) || (value > 0x1ff)) {
                snd_printk(KERN_ERR "i2c_write: invalid values.\n");
                return -EINVAL;
        }
 
+       /* This function is not re-entrant, so protect against it. */
+       spin_lock(&emu->i2c_lock);
+
        tmp = reg << 25 | value << 16;
-       // snd_printk("I2C-write:reg=0x%x, value=0x%x\n", reg, value);
-       /* Not sure what this I2C channel controls. */
-       /* snd_emu10k1_ptr_write(emu, P17V_I2C_0, 0, tmp); */
 
        /* This controls the I2C connected to the WM8775 ADC Codec */
        snd_emu10k1_ptr20_write(emu, P17V_I2C_1, 0, tmp);
@@ -193,17 +213,14 @@ int snd_emu10k1_i2c_write(struct snd_emu10k1 *emu,
 
        for (retry = 0; retry < 10; retry++) {
                /* Send the data to i2c */
-               //tmp = snd_emu10k1_ptr_read(emu, P17V_I2C_ADDR, 0);
-               //tmp = tmp & ~(I2C_A_ADC_READ|I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD_MASK);
                tmp = 0;
                tmp = tmp | (I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD);
                snd_emu10k1_ptr20_write(emu, P17V_I2C_ADDR, 0, tmp);
 
                /* Wait till the transaction ends */
                while (1) {
-                       udelay(10);
+                       mdelay(1);
                        status = snd_emu10k1_ptr20_read(emu, P17V_I2C_ADDR, 0);
-                       // snd_printk("I2C:status=0x%x\n", status);
                        timeout++;
                        if ((status & I2C_A_ADC_START) == 0)
                                break;
@@ -220,19 +237,26 @@ int snd_emu10k1_i2c_write(struct snd_emu10k1 *emu,
 
        if (retry == 10) {
                snd_printk(KERN_ERR "Writing to ADC failed!\n");
-               return -EINVAL;
+               snd_printk(KERN_ERR "status=0x%x, reg=%d, value=%d\n",
+                       status, reg, value);
+               /* dump_stack(); */
+               err = -EINVAL;
        }
     
-       return 0;
+       spin_unlock(&emu->i2c_lock);
+       return err;
 }
 
 int snd_emu1010_fpga_write(struct snd_emu10k1 * emu, u32 reg, u32 value)
 {
+       unsigned long flags;
+
        if (reg > 0x3f)
                return 1;
        reg += 0x40; /* 0x40 upwards are registers. */
        if (value < 0 || value > 0x3f) /* 0 to 0x3f are values */
                return 1;
+       spin_lock_irqsave(&emu->emu_lock, flags);
        outl(reg, emu->port + A_IOCFG);
        udelay(10);
        outl(reg | 0x80, emu->port + A_IOCFG);  /* High bit clocks the value into the fpga. */
@@ -240,20 +264,24 @@ int snd_emu1010_fpga_write(struct snd_emu10k1 * emu, u32 reg, u32 value)
        outl(value, emu->port + A_IOCFG);
        udelay(10);
        outl(value | 0x80 , emu->port + A_IOCFG);  /* High bit clocks the value into the fpga. */
+       spin_unlock_irqrestore(&emu->emu_lock, flags);
 
        return 0;
 }
 
 int snd_emu1010_fpga_read(struct snd_emu10k1 * emu, u32 reg, u32 *value)
 {
+       unsigned long flags;
        if (reg > 0x3f)
                return 1;
        reg += 0x40; /* 0x40 upwards are registers. */
+       spin_lock_irqsave(&emu->emu_lock, flags);
        outl(reg, emu->port + A_IOCFG);
        udelay(10);
        outl(reg | 0x80, emu->port + A_IOCFG);  /* High bit clocks the value into the fpga. */
        udelay(10);
        *value = ((inl(emu->port + A_IOCFG) >> 8) & 0x7f);
+       spin_unlock_irqrestore(&emu->emu_lock, flags);
 
        return 0;
 }
index 3c114b45e0b28b0bbc1b9b335e514d7d9ebbdcfc..30bfed6f83398d5f9b17fdf776ce2ab6ebac7a4e 100644 (file)
@@ -25,7 +25,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/time.h>
 #include <sound/core.h>
 #include <sound/emu10k1.h>
@@ -35,9 +34,10 @@ irqreturn_t snd_emu10k1_interrupt(int irq, void *dev_id)
        struct snd_emu10k1 *emu = dev_id;
        unsigned int status, status2, orig_status, orig_status2;
        int handled = 0;
+       int timeout = 0;
 
-       while ((status = inl(emu->port + IPR)) != 0) {
-               //snd_printk(KERN_INFO "emu10k1 irq - status = 0x%x\n", status);
+       while (((status = inl(emu->port + IPR)) != 0) && (timeout < 1000)) {
+               timeout++;
                orig_status = status;
                handled = 1;
                if ((status & 0xffffffff) == 0xffffffff) {
@@ -201,5 +201,8 @@ irqreturn_t snd_emu10k1_interrupt(int irq, void *dev_id)
                }
                outl(orig_status, emu->port + IPR); /* ack all */
        }
+       if (timeout == 1000)
+               snd_printk(KERN_INFO "emu10k1 irq routine failure\n");
+
        return IRQ_RETVAL(handled);
 }
index 48097c6bb15c20eb679cc23f17c8a1763a2cde79..916c1dbcd53cf919f6a420b86f893a676115302e 100644 (file)
@@ -21,7 +21,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/pci.h>
 #include <linux/time.h>
 #include <linux/mutex.h>
index 9fd3135f3118daf4631dfeb546aa1b873ce3dab6..749a21b6bd06bf9b49efed57c071560a13347ada 100644 (file)
@@ -87,7 +87,6 @@
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  *
  */
-#include <sound/driver.h>
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
index 6295b2dca785d59533c25268cc80e120094d488a..72321e946cccf6661810559c66a4f3cf69c30ba5 100644 (file)
@@ -25,7 +25,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/time.h>
 #include <sound/core.h>
 #include <sound/emu10k1.h>
index 04fa8492abb048855b170ed63676cfecda2030e4..958cb2a65a4ec8f79680f1bd8ed2a3570bfd2273 100644 (file)
@@ -28,7 +28,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/time.h>
 #include <sound/core.h>
 #include <sound/emu10k1.h>
index b958f869cb138b4a62a69fa35b88a9a55d392df5..72d85a5ae6a090f53b7a8b9983306d710be65d9d 100644 (file)
@@ -26,7 +26,6 @@
  * by Kurt J. Bosch
  */
 
-#include <sound/driver.h>
 #include <asm/io.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
index fb25abe68a020a7eff6b8ba9f52e950b38222bf5..1a314fa99c45889148c07b3d95609496b2e19c76 100644 (file)
@@ -47,7 +47,6 @@
 */
 
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/pci.h>
@@ -227,6 +226,7 @@ struct es1938 {
        unsigned int dma2_start;
        unsigned int dma1_shift;
        unsigned int dma2_shift;
+       unsigned int last_capture_dmaaddr;
        unsigned int active;
 
        spinlock_t reg_lock;
@@ -529,6 +529,7 @@ static void snd_es1938_capture_setdma(struct es1938 *chip)
        outb(1, SLDM_REG(chip, DMAMASK));
        outb(0x14, SLDM_REG(chip, DMAMODE));
        outl(chip->dma1_start, SLDM_REG(chip, DMAADDR));
+       chip->last_capture_dmaaddr = chip->dma1_start;
        outw(chip->dma1_size - 1, SLDM_REG(chip, DMACOUNT));
        /* 3. Unmask DMA */
        outb(0, SLDM_REG(chip, DMAMASK));
@@ -770,19 +771,40 @@ static int snd_es1938_playback_prepare(struct snd_pcm_substream *substream)
        return -EINVAL;
 }
 
+/* during the incrementing of dma counters the DMA register reads sometimes
+   returns garbage. To ensure a valid hw pointer, the following checks which
+   should be very unlikely to fail are used:
+   - is the current DMA address in the valid DMA range ?
+   - is the sum of DMA address and DMA counter pointing to the last DMA byte ?
+   One can argue this could differ by one byte depending on which register is
+   updated first, so the implementation below allows for that.
+*/
 static snd_pcm_uframes_t snd_es1938_capture_pointer(struct snd_pcm_substream *substream)
 {
        struct es1938 *chip = snd_pcm_substream_chip(substream);
        size_t ptr;
+#if 0
        size_t old, new;
-#if 1
        /* This stuff is *needed*, don't ask why - AB */
        old = inw(SLDM_REG(chip, DMACOUNT));
        while ((new = inw(SLDM_REG(chip, DMACOUNT))) != old)
                old = new;
        ptr = chip->dma1_size - 1 - new;
 #else
-       ptr = inl(SLDM_REG(chip, DMAADDR)) - chip->dma1_start;
+       size_t count;
+       unsigned int diff;
+
+       ptr = inl(SLDM_REG(chip, DMAADDR));
+       count = inw(SLDM_REG(chip, DMACOUNT));
+       diff = chip->dma1_start + chip->dma1_size - ptr - count;
+
+       if (diff > 3 || ptr < chip->dma1_start
+             || ptr >= chip->dma1_start+chip->dma1_size)
+         ptr = chip->last_capture_dmaaddr;            /* bad, use last saved */
+       else
+         chip->last_capture_dmaaddr = ptr;            /* good, remember it */
+
+       ptr -= chip->dma1_start;
 #endif
        return ptr >> chip->dma1_shift;
 }
index d69b11d1f993a0660e385ac28f5c68d3ca994fab..25ccfce45759806a21c8f13d11d4fc192cdf85a5 100644 (file)
@@ -94,7 +94,6 @@
  *     places.
  */
 
-#include <sound/driver.h>
 #include <asm/io.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
index 9939109f05a2ac819898b87a72e4711198737ab0..4c300e6149fca554891ae85eb2685caf36d0b23b 100644 (file)
@@ -20,7 +20,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
@@ -979,6 +978,27 @@ static unsigned int snd_fm801_tea575x_64pcr_read(struct snd_tea575x *tea)
        return val;
 }
 
+static void snd_fm801_tea575x_64pcr_mute(struct snd_tea575x *tea,
+                                         unsigned int mute)
+{
+       struct fm801 *chip = tea->private_data;
+       unsigned short reg;
+
+       spin_lock_irq(&chip->reg_lock);
+
+       reg = inw(FM801_REG(chip, GPIO_CTRL));
+       if (mute)
+               /* 0xf800 (mute) */
+               reg &= ~FM801_GPIO_GP(TEA_64PCR_WRITE_ENABLE);
+       else
+               /* 0xf802 (unmute) */
+               reg |= FM801_GPIO_GP(TEA_64PCR_WRITE_ENABLE);
+       outw(reg, FM801_REG(chip, GPIO_CTRL));
+       udelay(1);
+
+       spin_unlock_irq(&chip->reg_lock);
+}
+
 static struct snd_tea575x_ops snd_fm801_tea_ops[3] = {
        {
                /* 1 = MediaForte 256-PCS */
@@ -994,6 +1014,7 @@ static struct snd_tea575x_ops snd_fm801_tea_ops[3] = {
                /* 3 = MediaForte 64-PCR */
                .write = snd_fm801_tea575x_64pcr_write,
                .read = snd_fm801_tea575x_64pcr_read,
+               .mute = snd_fm801_tea575x_64pcr_mute,
        }
 };
 #endif
index ab0c726d648e77e2ea4477b285407bce37b8a7d3..9e0d8a1268aa4400cca30e5c881576ccb0ca28d9 100644 (file)
@@ -2,7 +2,7 @@ snd-hda-intel-y := hda_intel.o
 # since snd-hda-intel is the only driver using hda-codec,
 # merge it into a single module although it was originally
 # designed to be individual modules
-snd-hda-intel-y += hda_codec.o
+snd-hda-intel-y += hda_codec.o vmaster.o
 snd-hda-intel-$(CONFIG_PROC_FS) += hda_proc.o
 snd-hda-intel-$(CONFIG_SND_HDA_HWDEP) += hda_hwdep.o
 snd-hda-intel-$(CONFIG_SND_HDA_GENERIC) += hda_generic.o
index 8cbe3bf1e3170afb798fad92beb5579378877459..26812dc2b7f22c56a9c8c506863696ddf8f91b52 100644 (file)
@@ -19,7 +19,6 @@
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
@@ -55,6 +54,7 @@ static struct hda_vendor_id hda_vendor_ids[] = {
        { 0x10ec, "Realtek" },
        { 0x1057, "Motorola" },
        { 0x1106, "VIA" },
+       { 0x111d, "IDT" },
        { 0x11d4, "Analog Devices" },
        { 0x13f6, "C-Media" },
        { 0x14f1, "Conexant" },
@@ -429,6 +429,10 @@ find_codec_preset(struct hda_codec *codec)
        for (tbl = hda_preset_tables; *tbl; tbl++) {
                for (preset = *tbl; preset->id; preset++) {
                        u32 mask = preset->mask;
+                       if (preset->afg && preset->afg != codec->afg)
+                               continue;
+                       if (preset->mfg && preset->mfg != codec->mfg)
+                               continue;
                        if (!mask)
                                mask = ~0;
                        if (preset->id == (codec->vendor_id & mask) &&
@@ -765,7 +769,7 @@ get_alloc_amp_hash(struct hda_codec *codec, u32 key)
 /*
  * query AMP capabilities for the given widget and direction
  */
-static u32 query_amp_caps(struct hda_codec *codec, hda_nid_t nid, int direction)
+u32 query_amp_caps(struct hda_codec *codec, hda_nid_t nid, int direction)
 {
        struct hda_amp_info *info;
 
@@ -933,7 +937,8 @@ int snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol,
        caps = (caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT;
        if (!caps) {
                printk(KERN_WARNING "hda_codec: "
-                      "num_steps = 0 for NID=0x%x\n", nid);
+                      "num_steps = 0 for NID=0x%x (ctl = %s)\n", nid,
+                      kcontrol->id.name);
                return -EINVAL;
        }
        uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
@@ -1012,6 +1017,66 @@ int snd_hda_mixer_amp_tlv(struct snd_kcontrol *kcontrol, int op_flag,
        return 0;
 }
 
+/*
+ * set (static) TLV for virtual master volume; recalculated as max 0dB
+ */
+void snd_hda_set_vmaster_tlv(struct hda_codec *codec, hda_nid_t nid, int dir,
+                            unsigned int *tlv)
+{
+       u32 caps;
+       int nums, step;
+
+       caps = query_amp_caps(codec, nid, dir);
+       nums = (caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT;
+       step = (caps & AC_AMPCAP_STEP_SIZE) >> AC_AMPCAP_STEP_SIZE_SHIFT;
+       step = (step + 1) * 25;
+       tlv[0] = SNDRV_CTL_TLVT_DB_SCALE;
+       tlv[1] = 2 * sizeof(unsigned int);
+       tlv[2] = -nums * step;
+       tlv[3] = step;
+}
+
+/* find a mixer control element with the given name */
+struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec,
+                                           const char *name)
+{
+       struct snd_ctl_elem_id id;
+       memset(&id, 0, sizeof(id));
+       id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+       strcpy(id.name, name);
+       return snd_ctl_find_id(codec->bus->card, &id);
+}
+
+/* create a virtual master control and add slaves */
+int snd_hda_add_vmaster(struct hda_codec *codec, char *name,
+                       unsigned int *tlv, const char **slaves)
+{
+       struct snd_kcontrol *kctl;
+       const char **s;
+       int err;
+
+       kctl = snd_ctl_make_virtual_master(name, tlv);
+       if (!kctl)
+               return -ENOMEM;
+       err = snd_ctl_add(codec->bus->card, kctl);
+       if (err < 0)
+               return err;
+       
+       for (s = slaves; *s; s++) {
+               struct snd_kcontrol *sctl;
+
+               sctl = snd_hda_find_mixer_ctl(codec, *s);
+               if (!sctl) {
+                       snd_printdd("Cannot find slave %s, skipped\n", *s);
+                       continue;
+               }
+               err = snd_ctl_add_slave(kctl, sctl);
+               if (err < 0)
+                       return err;
+       }
+       return 0;
+}
+
 /* switch */
 int snd_hda_mixer_amp_switch_info(struct snd_kcontrol *kcontrol,
                                  struct snd_ctl_elem_info *uinfo)
@@ -1434,7 +1499,8 @@ int snd_hda_create_spdif_out_ctls(struct hda_codec *codec, hda_nid_t nid)
                        return err;
        }
        codec->spdif_ctls =
-               snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_DIGI_CONVERT, 0);
+               snd_hda_codec_read(codec, nid, 0,
+                                  AC_VERB_GET_DIGI_CONVERT_1, 0);
        codec->spdif_status = convert_to_spdif_status(codec->spdif_ctls);
        return 0;
 }
@@ -1481,7 +1547,7 @@ static int snd_hda_spdif_in_status_get(struct snd_kcontrol *kcontrol,
        unsigned short val;
        unsigned int sbits;
 
-       val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_DIGI_CONVERT, 0);
+       val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_DIGI_CONVERT_1, 0);
        sbits = convert_to_spdif_status(val);
        ucontrol->value.iec958.status[0] = sbits;
        ucontrol->value.iec958.status[1] = sbits >> 8;
@@ -1532,7 +1598,8 @@ int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid)
                        return err;
        }
        codec->spdif_in_enable =
-               snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_DIGI_CONVERT, 0) &
+               snd_hda_codec_read(codec, nid, 0,
+                                  AC_VERB_GET_DIGI_CONVERT_1, 0) &
                AC_DIG1_ENABLE;
        return 0;
 }
@@ -1622,6 +1689,7 @@ static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg,
 
        snd_hda_codec_write(codec, fg, 0, AC_VERB_SET_POWER_STATE,
                            power_state);
+       msleep(10); /* partial workaround for "azx_get_response timeout" */
 
        nid = codec->start_nid;
        for (i = 0; i < codec->num_nodes; i++, nid++) {
@@ -2336,7 +2404,8 @@ int snd_hda_ch_mode_put(struct hda_codec *codec,
        unsigned int mode;
 
        mode = ucontrol->value.enumerated.item[0];
-       snd_assert(mode < num_chmodes, return -EINVAL);
+       if (mode >= num_chmodes)
+               return -EINVAL;
        if (*max_channelsp == chmode[mode].channels)
                return 0;
        /* change the current channel setting */
@@ -2602,20 +2671,21 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
                                 struct auto_pin_cfg *cfg,
                                 hda_nid_t *ignore_nids)
 {
-       hda_nid_t nid, nid_start;
-       int nodes;
+       hda_nid_t nid, end_nid;
        short seq, assoc_line_out, assoc_speaker;
        short sequences_line_out[ARRAY_SIZE(cfg->line_out_pins)];
        short sequences_speaker[ARRAY_SIZE(cfg->speaker_pins)];
+       short sequences_hp[ARRAY_SIZE(cfg->hp_pins)];
 
        memset(cfg, 0, sizeof(*cfg));
 
        memset(sequences_line_out, 0, sizeof(sequences_line_out));
        memset(sequences_speaker, 0, sizeof(sequences_speaker));
+       memset(sequences_hp, 0, sizeof(sequences_hp));
        assoc_line_out = assoc_speaker = 0;
 
-       nodes = snd_hda_get_sub_nodes(codec, codec->afg, &nid_start);
-       for (nid = nid_start; nid < nodes + nid_start; nid++) {
+       end_nid = codec->start_nid + codec->num_nodes;
+       for (nid = codec->start_nid; nid < end_nid; nid++) {
                unsigned int wid_caps = get_wcaps(codec, nid);
                unsigned int wid_type =
                        (wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
@@ -2638,6 +2708,10 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
                case AC_JACK_LINE_OUT:
                        seq = get_defcfg_sequence(def_conf);
                        assoc = get_defcfg_association(def_conf);
+
+                       if (!(wid_caps & AC_WCAP_STEREO))
+                               if (!cfg->mono_out_pin)
+                                       cfg->mono_out_pin = nid;
                        if (!assoc)
                                continue;
                        if (!assoc_line_out)
@@ -2666,9 +2740,12 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
                        cfg->speaker_outs++;
                        break;
                case AC_JACK_HP_OUT:
+                       seq = get_defcfg_sequence(def_conf);
+                       assoc = get_defcfg_association(def_conf);
                        if (cfg->hp_outs >= ARRAY_SIZE(cfg->hp_pins))
                                continue;
                        cfg->hp_pins[cfg->hp_outs] = nid;
+                       sequences_hp[cfg->hp_outs] = (assoc << 4) | seq;
                        cfg->hp_outs++;
                        break;
                case AC_JACK_MIC_IN: {
@@ -2712,7 +2789,24 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
                              cfg->line_outs);
        sort_pins_by_sequence(cfg->speaker_pins, sequences_speaker,
                              cfg->speaker_outs);
+       sort_pins_by_sequence(cfg->hp_pins, sequences_hp,
+                             cfg->hp_outs);
        
+       /* if we have only one mic, make it AUTO_PIN_MIC */
+       if (!cfg->input_pins[AUTO_PIN_MIC] &&
+           cfg->input_pins[AUTO_PIN_FRONT_MIC]) {
+               cfg->input_pins[AUTO_PIN_MIC] =
+                       cfg->input_pins[AUTO_PIN_FRONT_MIC];
+               cfg->input_pins[AUTO_PIN_FRONT_MIC] = 0;
+       }
+       /* ditto for line-in */
+       if (!cfg->input_pins[AUTO_PIN_LINE] &&
+           cfg->input_pins[AUTO_PIN_FRONT_LINE]) {
+               cfg->input_pins[AUTO_PIN_LINE] =
+                       cfg->input_pins[AUTO_PIN_FRONT_LINE];
+               cfg->input_pins[AUTO_PIN_FRONT_LINE] = 0;
+       }
+
        /*
         * FIX-UP: if no line-outs are detected, try to use speaker or HP pin
         * as a primary output
@@ -2766,6 +2860,7 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
                   cfg->hp_outs, cfg->hp_pins[0],
                   cfg->hp_pins[1], cfg->hp_pins[2],
                   cfg->hp_pins[3], cfg->hp_pins[4]);
+       snd_printd("   mono: mono_out=0x%x\n", cfg->mono_out_pin);
        snd_printd("   inputs: mic=0x%x, fmic=0x%x, line=0x%x, fline=0x%x,"
                   " cd=0x%x, aux=0x%x\n",
                   cfg->input_pins[AUTO_PIN_MIC],
index 2bce925d84ef5b0412f67320d65f732bd06e5aa7..f14871151be983a307330ec9c61009895a22f944 100644 (file)
@@ -77,12 +77,16 @@ enum {
 #define AC_VERB_GET_PIN_SENSE                  0x0f09
 #define AC_VERB_GET_BEEP_CONTROL               0x0f0a
 #define AC_VERB_GET_EAPD_BTLENABLE             0x0f0c
-#define AC_VERB_GET_DIGI_CONVERT               0x0f0d
+#define AC_VERB_GET_DIGI_CONVERT_1             0x0f0d
+#define AC_VERB_GET_DIGI_CONVERT_2             0x0f0e
 #define AC_VERB_GET_VOLUME_KNOB_CONTROL                0x0f0f
 /* f10-f1a: GPIO */
 #define AC_VERB_GET_GPIO_DATA                  0x0f15
 #define AC_VERB_GET_GPIO_MASK                  0x0f16
 #define AC_VERB_GET_GPIO_DIRECTION             0x0f17
+#define AC_VERB_GET_GPIO_WAKE_MASK             0x0f18
+#define AC_VERB_GET_GPIO_UNSOLICITED_RSP_MASK  0x0f19
+#define AC_VERB_GET_GPIO_STICKY_MASK           0x0f1a
 #define AC_VERB_GET_CONFIG_DEFAULT             0x0f1c
 /* f20: AFG/MFG */
 #define AC_VERB_GET_SUBSYSTEM_ID               0x0f20
@@ -110,6 +114,9 @@ enum {
 #define AC_VERB_SET_GPIO_DATA                  0x715
 #define AC_VERB_SET_GPIO_MASK                  0x716
 #define AC_VERB_SET_GPIO_DIRECTION             0x717
+#define AC_VERB_SET_GPIO_WAKE_MASK             0x718
+#define AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK  0x719
+#define AC_VERB_SET_GPIO_STICKY_MASK           0x71a
 #define AC_VERB_SET_CONFIG_DEFAULT_BYTES_0     0x71c
 #define AC_VERB_SET_CONFIG_DEFAULT_BYTES_1     0x71d
 #define AC_VERB_SET_CONFIG_DEFAULT_BYTES_2     0x71e
@@ -135,6 +142,7 @@ enum {
 #define AC_PAR_PROC_CAP                        0x10
 #define AC_PAR_GPIO_CAP                        0x11
 #define AC_PAR_AMP_OUT_CAP             0x12
+#define AC_PAR_VOL_KNB_CAP             0x13
 
 /*
  * AC_VERB_PARAMETERS results (32bit)
@@ -181,6 +189,27 @@ enum {
 #define AC_SUPFMT_FLOAT32              (1<<1)
 #define AC_SUPFMT_AC3                  (1<<2)
 
+/* GP I/O count */
+#define AC_GPIO_IO_COUNT               (0xff<<0)
+#define AC_GPIO_O_COUNT                        (0xff<<8)
+#define AC_GPIO_O_COUNT_SHIFT          8
+#define AC_GPIO_I_COUNT                        (0xff<<16)
+#define AC_GPIO_I_COUNT_SHIFT          16
+#define AC_GPIO_UNSOLICITED            (1<<30)
+#define AC_GPIO_WAKE                   (1<<31)
+
+/* Converter stream, channel */
+#define AC_CONV_CHANNEL                        (0xf<<0)
+#define AC_CONV_STREAM                 (0xf<<4)
+#define AC_CONV_STREAM_SHIFT           4
+
+/* Input converter SDI select */
+#define AC_SDI_SELECT                  (0xf<<0)
+
+/* Unsolicited response */
+#define AC_UNSOL_TAG                   (0x3f<<0)
+#define AC_UNSOL_ENABLED               (1<<7)
+
 /* Pin widget capabilies */
 #define AC_PINCAP_IMP_SENSE            (1<<0)  /* impedance sense capable */
 #define AC_PINCAP_TRIG_REQ             (1<<1)  /* trigger required */
@@ -189,6 +218,10 @@ enum {
 #define AC_PINCAP_OUT                  (1<<4)  /* output capable */
 #define AC_PINCAP_IN                   (1<<5)  /* input capable */
 #define AC_PINCAP_BALANCE              (1<<6)  /* balanced I/O capable */
+/* Note: This LR_SWAP pincap is defined in the Realtek ALC883 specification,
+ *       but is marked reserved in the Intel HDA specification.
+ */
+#define AC_PINCAP_LR_SWAP              (1<<7)  /* L/R swap */
 #define AC_PINCAP_VREF                 (0x37<<8)
 #define AC_PINCAP_VREF_SHIFT           8
 #define AC_PINCAP_EAPD                 (1<<16) /* EAPD capable */
@@ -222,6 +255,9 @@ enum {
 #define AC_PWRST_D3SUP                 (1<<3)
 
 /* Power state values */
+#define AC_PWRST_SETTING               (0xf<<0)
+#define AC_PWRST_ACTUAL                        (0xf<<4)
+#define AC_PWRST_ACTUAL_SHIFT          4
 #define AC_PWRST_D0                    0x00
 #define AC_PWRST_D1                    0x01
 #define AC_PWRST_D2                    0x02
@@ -230,10 +266,11 @@ enum {
 /* Processing capabilies */
 #define AC_PCAP_BENIGN                 (1<<0)
 #define AC_PCAP_NUM_COEF               (0xff<<8)
+#define AC_PCAP_NUM_COEF_SHIFT         8
 
 /* Volume knobs capabilities */
 #define AC_KNBCAP_NUM_STEPS            (0x7f<<0)
-#define AC_KNBCAP_DELTA                        (1<<8)
+#define AC_KNBCAP_DELTA                        (1<<7)
 
 /*
  * Control Parameters
@@ -266,6 +303,9 @@ enum {
 #define AC_DIG1_PROFESSIONAL           (1<<6)
 #define AC_DIG1_LEVEL                  (1<<7)
 
+/* DIGITAL2 bits */
+#define AC_DIG2_CC                     (0x7f<<0)
+
 /* Pin widget control - 8bit */
 #define AC_PINCTL_VREFEN               (0x7<<0)
 #define AC_PINCTL_VREF_HIZ             0       /* Hi-Z */
@@ -280,12 +320,22 @@ enum {
 /* Unsolicited response - 8bit */
 #define AC_USRSP_EN                    (1<<7)
 
+/* Pin sense - 32bit */
+#define AC_PINSENSE_IMPEDANCE_MASK     (0x7fffffff)
+#define AC_PINSENSE_PRESENCE           (1<<31)
+
+/* EAPD/BTL enable - 32bit */
+#define AC_EAPDBTL_BALANCED            (1<<0)
+#define AC_EAPDBTL_EAPD                        (1<<1)
+#define AC_EAPDBTL_LR_SWAP             (1<<2)
+
 /* configuration default - 32bit */
 #define AC_DEFCFG_SEQUENCE             (0xf<<0)
 #define AC_DEFCFG_DEF_ASSOC            (0xf<<4)
 #define AC_DEFCFG_ASSOC_SHIFT          4
 #define AC_DEFCFG_MISC                 (0xf<<8)
 #define AC_DEFCFG_MISC_SHIFT           8
+#define AC_DEFCFG_MISC_NO_PRESENCE     (1<<0)
 #define AC_DEFCFG_COLOR                        (0xf<<12)
 #define AC_DEFCFG_COLOR_SHIFT          12
 #define AC_DEFCFG_CONN_TYPE            (0xf<<16)
@@ -417,7 +467,7 @@ struct hda_bus_ops {
        /* free the private data */
        void (*private_free)(struct hda_bus *);
 #ifdef CONFIG_SND_HDA_POWER_SAVE
-       /* notify power-up/down from codec to contoller */
+       /* notify power-up/down from codec to controller */
        void (*pm_notify)(struct hda_codec *codec);
 #endif
 };
@@ -456,6 +506,9 @@ struct hda_bus {
        struct hda_bus_unsolicited *unsol;
 
        struct snd_info_entry *proc;
+
+       /* misc op flags */
+       unsigned int needs_damn_long_delay :1;
 };
 
 /*
@@ -470,6 +523,7 @@ struct hda_codec_preset {
        unsigned int subs;
        unsigned int subs_mask;
        unsigned int rev;
+       hda_nid_t afg, mfg;
        const char *name;
        int (*patch)(struct hda_codec *codec);
 };
index c957eb58de5cb048c6bf9e4dca471dcd2ddc5a37..f9de7c467c2552ad56b73568fa07caae203f7e85 100644 (file)
@@ -20,7 +20,6 @@
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <sound/core.h>
index bafb7b01f5a1db6177fbb4302b1237165b98106e..2177d9af533496a4583d943c6f648d241f9ef078 100644 (file)
@@ -18,7 +18,6 @@
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/pci.h>
index 3fa0f9704909764e154da625082251b5e0ef9e26..56f8a30507513563135b62b51d17f0169b3c672e 100644 (file)
@@ -34,7 +34,6 @@
  * 
  */
 
-#include <sound/driver.h>
 #include <asm/io.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include "hda_codec.h"
 
 
-static int index = SNDRV_DEFAULT_IDX1;
-static char *id = SNDRV_DEFAULT_STR1;
-static char *model;
-static int position_fix;
-static int probe_mask = -1;
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
+static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
+static char *model[SNDRV_CARDS];
+static int position_fix[SNDRV_CARDS];
+static int probe_mask[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = -1};
 static int single_cmd;
 static int enable_msi;
 
-module_param(index, int, 0444);
+module_param_array(index, int, NULL, 0444);
 MODULE_PARM_DESC(index, "Index value for Intel HD audio interface.");
-module_param(id, charp, 0444);
+module_param_array(id, charp, NULL, 0444);
 MODULE_PARM_DESC(id, "ID string for Intel HD audio interface.");
-module_param(model, charp, 0444);
+module_param_array(enable, bool, NULL, 0444);
+MODULE_PARM_DESC(enable, "Enable Intel HD audio interface.");
+module_param_array(model, charp, NULL, 0444);
 MODULE_PARM_DESC(model, "Use the given board model.");
-module_param(position_fix, int, 0444);
+module_param_array(position_fix, int, NULL, 0444);
 MODULE_PARM_DESC(position_fix, "Fix DMA pointer "
                 "(0 = auto, 1 = none, 2 = POSBUF, 3 = FIFO size).");
-module_param(probe_mask, int, 0444);
+module_param_array(probe_mask, int, NULL, 0444);
 MODULE_PARM_DESC(probe_mask, "Bitmask to probe codecs (default = -1).");
 module_param(single_cmd, bool, 0444);
 MODULE_PARM_DESC(single_cmd, "Use single command to communicate with codecs "
                 "(for debugging only).");
-module_param(enable_msi, int, 0);
+module_param(enable_msi, int, 0444);
 MODULE_PARM_DESC(enable_msi, "Enable Message Signaled Interrupt (MSI)");
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
@@ -87,10 +89,6 @@ module_param(power_save_controller, bool, 0644);
 MODULE_PARM_DESC(power_save_controller, "Reset controller in power save mode.");
 #endif
 
-/* just for backward compatibility */
-static int enable;
-module_param(enable, bool, 0444);
-
 MODULE_LICENSE("GPL");
 MODULE_SUPPORTED_DEVICE("{{Intel, ICH6},"
                         "{Intel, ICH6M},"
@@ -98,12 +96,20 @@ MODULE_SUPPORTED_DEVICE("{{Intel, ICH6},"
                         "{Intel, ESB2},"
                         "{Intel, ICH8},"
                         "{Intel, ICH9},"
+                        "{Intel, ICH10},"
+                        "{Intel, SCH},"
                         "{ATI, SB450},"
                         "{ATI, SB600},"
                         "{ATI, RS600},"
                         "{ATI, RS690},"
                         "{ATI, RS780},"
                         "{ATI, R600},"
+                        "{ATI, RV630},"
+                        "{ATI, RV610},"
+                        "{ATI, RV670},"
+                        "{ATI, RV635},"
+                        "{ATI, RV620},"
+                        "{ATI, RV770},"
                         "{VIA, VT8251},"
                         "{VIA, VT8237A},"
                         "{SiS, SIS966},"
@@ -370,6 +376,7 @@ struct azx {
 /* driver types */
 enum {
        AZX_DRIVER_ICH,
+       AZX_DRIVER_SCH,
        AZX_DRIVER_ATI,
        AZX_DRIVER_ATIHDMI,
        AZX_DRIVER_VIA,
@@ -380,6 +387,7 @@ enum {
 
 static char *driver_short_names[] __devinitdata = {
        [AZX_DRIVER_ICH] = "HDA Intel",
+       [AZX_DRIVER_SCH] = "HDA Intel MID",
        [AZX_DRIVER_ATI] = "HDA ATI SB",
        [AZX_DRIVER_ATIHDMI] = "HDA ATI HDMI",
        [AZX_DRIVER_VIA] = "HDA VIA VT82xx",
@@ -547,7 +555,7 @@ static unsigned int azx_rirb_get_response(struct hda_codec *codec)
 
  again:
        timeout = jiffies + msecs_to_jiffies(1000);
-       do {
+       for (;;) {
                if (chip->polling_mode) {
                        spin_lock_irq(&chip->reg_lock);
                        azx_update_rirb(chip);
@@ -555,8 +563,15 @@ static unsigned int azx_rirb_get_response(struct hda_codec *codec)
                }
                if (!chip->rirb.cmds)
                        return chip->rirb.res; /* the last value */
-               schedule_timeout_uninterruptible(1);
-       } while (time_after_eq(timeout, jiffies));
+               if (time_after(jiffies, timeout))
+                       break;
+               if (codec->bus->needs_damn_long_delay)
+                       msleep(2); /* temporary workaround */
+               else {
+                       udelay(10);
+                       cond_resched();
+               }
+       }
 
        if (chip->msi) {
                snd_printk(KERN_WARNING "hda_intel: No response from codec, "
@@ -618,8 +633,9 @@ static int azx_single_send_cmd(struct hda_codec *codec, u32 val)
                }
                udelay(1);
        }
-       snd_printd(SFX "send_cmd timeout: IRS=0x%x, val=0x%x\n",
-                  azx_readw(chip, IRS), val);
+       if (printk_ratelimit())
+               snd_printd(SFX "send_cmd timeout: IRS=0x%x, val=0x%x\n",
+                          azx_readw(chip, IRS), val);
        return -EIO;
 }
 
@@ -635,8 +651,9 @@ static unsigned int azx_single_get_response(struct hda_codec *codec)
                        return azx_readl(chip, IR);
                udelay(1);
        }
-       snd_printd(SFX "get_response timeout: IRS=0x%x\n",
-                  azx_readw(chip, IRS));
+       if (printk_ratelimit())
+               snd_printd(SFX "get_response timeout: IRS=0x%x\n",
+                          azx_readw(chip, IRS));
        return (unsigned int)-1;
 }
 
@@ -1031,7 +1048,8 @@ static unsigned int azx_max_codecs[] __devinitdata = {
        [AZX_DRIVER_NVIDIA] = 3,        /* FIXME: correct? */
 };
 
-static int __devinit azx_codec_create(struct azx *chip, const char *model)
+static int __devinit azx_codec_create(struct azx *chip, const char *model,
+                                     unsigned int codec_probe_mask)
 {
        struct hda_bus_template bus_temp;
        int c, codecs, audio_codecs, err;
@@ -1052,7 +1070,7 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model)
 
        codecs = audio_codecs = 0;
        for (c = 0; c < AZX_MAX_CODECS; c++) {
-               if ((chip->codec_mask & (1 << c)) & probe_mask) {
+               if ((chip->codec_mask & (1 << c)) & codec_probe_mask) {
                        struct hda_codec *codec;
                        err = snd_hda_codec_new(chip->bus, c, &codec);
                        if (err < 0)
@@ -1065,7 +1083,7 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model)
        if (!audio_codecs) {
                /* probe additional slots if no codec is found */
                for (; c < azx_max_codecs[chip->driver_type]; c++) {
-                       if ((chip->codec_mask & (1 << c)) & probe_mask) {
+                       if ((chip->codec_mask & (1 << c)) & codec_probe_mask) {
                                err = snd_hda_codec_new(chip->bus, c, NULL);
                                if (err < 0)
                                        continue;
@@ -1676,18 +1694,18 @@ static struct snd_pci_quirk probe_mask_list[] __devinitdata = {
        {}
 };
 
-static void __devinit check_probe_mask(struct azx *chip)
+static void __devinit check_probe_mask(struct azx *chip, int dev)
 {
        const struct snd_pci_quirk *q;
 
-       if (probe_mask == -1) {
+       if (probe_mask[dev] == -1) {
                q = snd_pci_quirk_lookup(chip->pci, probe_mask_list);
                if (q) {
                        printk(KERN_INFO
                               "hda_intel: probe_mask set to 0x%x "
                               "for device %04x:%04x\n",
                               q->value, q->subvendor, q->subdevice);
-                       probe_mask = q->value;
+                       probe_mask[dev] = q->value;
                }
        }
 }
@@ -1697,17 +1715,18 @@ static void __devinit check_probe_mask(struct azx *chip)
  * constructor
  */
 static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
-                               int driver_type,
+                               int dev, int driver_type,
                                struct azx **rchip)
 {
        struct azx *chip;
        int err;
+       unsigned short gcap;
        static struct snd_device_ops ops = {
                .dev_free = azx_dev_free,
        };
 
        *rchip = NULL;
-       
+
        err = pci_enable_device(pci);
        if (err < 0)
                return err;
@@ -1727,8 +1746,8 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
        chip->driver_type = driver_type;
        chip->msi = enable_msi;
 
-       chip->position_fix = check_position_fix(chip, position_fix);
-       check_probe_mask(chip);
+       chip->position_fix = check_position_fix(chip, position_fix[dev]);
+       check_probe_mask(chip, dev);
 
        chip->single_cmd = single_cmd;
 
@@ -1769,25 +1788,40 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
        pci_set_master(pci);
        synchronize_irq(chip->irq);
 
-       switch (chip->driver_type) {
-       case AZX_DRIVER_ULI:
-               chip->playback_streams = ULI_NUM_PLAYBACK;
-               chip->capture_streams = ULI_NUM_CAPTURE;
-               chip->playback_index_offset = ULI_PLAYBACK_INDEX;
-               chip->capture_index_offset = ULI_CAPTURE_INDEX;
-               break;
-       case AZX_DRIVER_ATIHDMI:
-               chip->playback_streams = ATIHDMI_NUM_PLAYBACK;
-               chip->capture_streams = ATIHDMI_NUM_CAPTURE;
-               chip->playback_index_offset = ATIHDMI_PLAYBACK_INDEX;
-               chip->capture_index_offset = ATIHDMI_CAPTURE_INDEX;
-               break;
-       default:
-               chip->playback_streams = ICH6_NUM_PLAYBACK;
-               chip->capture_streams = ICH6_NUM_CAPTURE;
-               chip->playback_index_offset = ICH6_PLAYBACK_INDEX;
-               chip->capture_index_offset = ICH6_CAPTURE_INDEX;
-               break;
+       gcap = azx_readw(chip, GCAP);
+       snd_printdd("chipset global capabilities = 0x%x\n", gcap);
+
+       if (gcap) {
+               /* read number of streams from GCAP register instead of using
+                * hardcoded value
+                */
+               chip->playback_streams = (gcap & (0xF << 12)) >> 12;
+               chip->capture_streams = (gcap & (0xF << 8)) >> 8;
+               chip->playback_index_offset = (gcap & (0xF << 12)) >> 12;
+               chip->capture_index_offset = 0;
+       } else {
+               /* gcap didn't give any info, switching to old method */
+
+               switch (chip->driver_type) {
+               case AZX_DRIVER_ULI:
+                       chip->playback_streams = ULI_NUM_PLAYBACK;
+                       chip->capture_streams = ULI_NUM_CAPTURE;
+                       chip->playback_index_offset = ULI_PLAYBACK_INDEX;
+                       chip->capture_index_offset = ULI_CAPTURE_INDEX;
+                       break;
+               case AZX_DRIVER_ATIHDMI:
+                       chip->playback_streams = ATIHDMI_NUM_PLAYBACK;
+                       chip->capture_streams = ATIHDMI_NUM_CAPTURE;
+                       chip->playback_index_offset = ATIHDMI_PLAYBACK_INDEX;
+                       chip->capture_index_offset = ATIHDMI_CAPTURE_INDEX;
+                       break;
+               default:
+                       chip->playback_streams = ICH6_NUM_PLAYBACK;
+                       chip->capture_streams = ICH6_NUM_CAPTURE;
+                       chip->playback_index_offset = ICH6_PLAYBACK_INDEX;
+                       chip->capture_index_offset = ICH6_CAPTURE_INDEX;
+                       break;
+               }
        }
        chip->num_streams = chip->playback_streams + chip->capture_streams;
        chip->azx_dev = kcalloc(chip->num_streams, sizeof(*chip->azx_dev),
@@ -1869,17 +1903,25 @@ static void power_down_all_codecs(struct azx *chip)
 static int __devinit azx_probe(struct pci_dev *pci,
                               const struct pci_device_id *pci_id)
 {
+       static int dev;
        struct snd_card *card;
        struct azx *chip;
        int err;
 
-       card = snd_card_new(index, id, THIS_MODULE, 0);
+       if (dev >= SNDRV_CARDS)
+               return -ENODEV;
+       if (!enable[dev]) {
+               dev++;
+               return -ENOENT;
+       }
+
+       card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
        if (!card) {
                snd_printk(KERN_ERR SFX "Error creating card!\n");
                return -ENOMEM;
        }
 
-       err = azx_create(card, pci, pci_id->driver_data, &chip);
+       err = azx_create(card, pci, dev, pci_id->driver_data, &chip);
        if (err < 0) {
                snd_card_free(card);
                return err;
@@ -1887,7 +1929,7 @@ static int __devinit azx_probe(struct pci_dev *pci,
        card->private_data = chip;
 
        /* create codec instances */
-       err = azx_codec_create(chip, model);
+       err = azx_codec_create(chip, model[dev], probe_mask[dev]);
        if (err < 0) {
                snd_card_free(card);
                return err;
@@ -1919,6 +1961,7 @@ static int __devinit azx_probe(struct pci_dev *pci,
        chip->running = 1;
        power_down_all_codecs(chip);
 
+       dev++;
        return err;
 }
 
@@ -1936,12 +1979,21 @@ static struct pci_device_id azx_ids[] = {
        { 0x8086, 0x284b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH8 */
        { 0x8086, 0x293e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH9 */
        { 0x8086, 0x293f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH9 */
+       { 0x8086, 0x3a3e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH10 */
+       { 0x8086, 0x3a6e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH10 */
+       { 0x8086, 0x811b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_SCH }, /* SCH*/
        { 0x1002, 0x437b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATI }, /* ATI SB450 */
        { 0x1002, 0x4383, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATI }, /* ATI SB600 */
        { 0x1002, 0x793b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI RS600 HDMI */
        { 0x1002, 0x7919, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI RS690 HDMI */
-       { 0x1002, 0x960c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI RS780 HDMI */
+       { 0x1002, 0x960f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI RS780 HDMI */
        { 0x1002, 0xaa00, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI R600 HDMI */
+       { 0x1002, 0xaa08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI RV630 HDMI */
+       { 0x1002, 0xaa10, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI RV610 HDMI */
+       { 0x1002, 0xaa18, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI RV670 HDMI */
+       { 0x1002, 0xaa20, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI RV635 HDMI */
+       { 0x1002, 0xaa28, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI RV620 HDMI */
+       { 0x1002, 0xaa30, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI RV770 HDMI */
        { 0x1106, 0x3288, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_VIA }, /* VIA VT8251/VT8237A */
        { 0x1039, 0x7502, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_SIS }, /* SIS966 */
        { 0x10b9, 0x5461, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ULI }, /* ULI M5461 */
index 8c56c9cb0d09523b7cb9eca6adbd24a0025c2bb9..ad0014ab71f9e0388ead79f283a7867ca4542c39 100644 (file)
@@ -90,6 +90,13 @@ int snd_hda_codec_amp_stereo(struct hda_codec *codec, hda_nid_t nid,
 void snd_hda_codec_resume_amp(struct hda_codec *codec);
 #endif
 
+void snd_hda_set_vmaster_tlv(struct hda_codec *codec, hda_nid_t nid, int dir,
+                            unsigned int *tlv);
+struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec,
+                                           const char *name);
+int snd_hda_add_vmaster(struct hda_codec *codec, char *name,
+                       unsigned int *tlv, const char **slaves);
+
 /* amp value bits */
 #define HDA_AMP_MUTE   0x80
 #define HDA_AMP_UNMUTE 0x00
@@ -325,6 +332,7 @@ struct auto_pin_cfg {
        hda_nid_t input_pins[AUTO_PIN_LAST];
        hda_nid_t dig_out_pin;
        hda_nid_t dig_in_pin;
+       hda_nid_t mono_out_pin;
 };
 
 #define get_defcfg_connect(cfg) \
@@ -363,10 +371,11 @@ static inline u32 get_wcaps(struct hda_codec *codec, hda_nid_t nid)
 {
        if (nid < codec->start_nid ||
            nid >= codec->start_nid + codec->num_nodes)
-               return snd_hda_param_read(codec, nid, AC_PAR_AUDIO_WIDGET_CAP);
+               return 0;
        return codec->wcaps[nid - codec->start_nid];
 }
 
+u32 query_amp_caps(struct hda_codec *codec, hda_nid_t nid, int direction);
 int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir,
                              unsigned int caps);
 
@@ -398,4 +407,11 @@ int snd_hda_check_amp_list_power(struct hda_codec *codec,
                                 hda_nid_t nid);
 #endif /* CONFIG_SND_HDA_POWER_SAVE */
 
+/*
+ * virtual master control
+ */
+struct snd_kcontrol *snd_ctl_make_virtual_master(char *name,
+                                                const unsigned int *tlv);
+int snd_ctl_add_slave(struct snd_kcontrol *master, struct snd_kcontrol *slave);
+                     
 #endif /* __SOUND_HDA_LOCAL_H */
index e94944f34ffdcfffc4c8c9385ba268899ce824c2..35a630d1770f80a2d5b62198bb6685f50069aa6c 100644 (file)
@@ -21,7 +21,6 @@
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <sound/core.h>
 #include "hda_codec.h"
@@ -203,7 +202,8 @@ static const char *get_jack_color(u32 cfg)
 }
 
 static void print_pin_caps(struct snd_info_buffer *buffer,
-                          struct hda_codec *codec, hda_nid_t nid)
+                          struct hda_codec *codec, hda_nid_t nid,
+                          int *supports_vref)
 {
        static char *jack_conns[4] = { "Jack", "N/A", "Fixed", "Both" };
        static char *jack_types[16] = {
@@ -213,7 +213,7 @@ static void print_pin_caps(struct snd_info_buffer *buffer,
                "SPDIF In", "Digitial In", "Reserved", "Other"
        };
        static char *jack_locations[4] = { "Ext", "Int", "Sep", "Oth" };
-       unsigned int caps;
+       unsigned int caps, val;
 
        caps = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP);
        snd_iprintf(buffer, "  Pincap 0x08%x:", caps);
@@ -227,7 +227,45 @@ static void print_pin_caps(struct snd_info_buffer *buffer,
                snd_iprintf(buffer, " EAPD");
        if (caps & AC_PINCAP_PRES_DETECT)
                snd_iprintf(buffer, " Detect");
+       if (caps & AC_PINCAP_BALANCE)
+               snd_iprintf(buffer, " Balanced");
+       if (caps & AC_PINCAP_LR_SWAP)
+               snd_iprintf(buffer, " R/L");
+       if (caps & AC_PINCAP_TRIG_REQ)
+               snd_iprintf(buffer, " Trigger");
+       if (caps & AC_PINCAP_IMP_SENSE)
+               snd_iprintf(buffer, " ImpSense");
        snd_iprintf(buffer, "\n");
+       if (caps & AC_PINCAP_VREF) {
+               unsigned int vref =
+                       (caps & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT;
+               snd_iprintf(buffer, "    Vref caps:");
+               if (vref & AC_PINCAP_VREF_HIZ)
+                       snd_iprintf(buffer, " HIZ");
+               if (vref & AC_PINCAP_VREF_50)
+                       snd_iprintf(buffer, " 50");
+               if (vref & AC_PINCAP_VREF_GRD)
+                       snd_iprintf(buffer, " GRD");
+               if (vref & AC_PINCAP_VREF_80)
+                       snd_iprintf(buffer, " 80");
+               if (vref & AC_PINCAP_VREF_100)
+                       snd_iprintf(buffer, " 100");
+               snd_iprintf(buffer, "\n");
+               *supports_vref = 1;
+       } else
+               *supports_vref = 0;
+       if (caps & AC_PINCAP_EAPD) {
+               val = snd_hda_codec_read(codec, nid, 0,
+                                        AC_VERB_GET_EAPD_BTLENABLE, 0);
+               snd_iprintf(buffer, "  EAPD 0x%x:", val);
+               if (val & AC_EAPDBTL_BALANCED)
+                       snd_iprintf(buffer, " BALANCED");
+               if (val & AC_EAPDBTL_EAPD)
+                       snd_iprintf(buffer, " EAPD");
+               if (val & AC_EAPDBTL_LR_SWAP)
+                       snd_iprintf(buffer, " R/L");
+               snd_iprintf(buffer, "\n");
+       }
        caps = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONFIG_DEFAULT, 0);
        snd_iprintf(buffer, "  Pin Default 0x%08x: [%s] %s at %s %s\n", caps,
                    jack_conns[(caps & AC_DEFCFG_PORT_CONN) >> AC_DEFCFG_PORT_CONN_SHIFT],
@@ -237,8 +275,233 @@ static void print_pin_caps(struct snd_info_buffer *buffer,
        snd_iprintf(buffer, "    Conn = %s, Color = %s\n",
                    get_jack_connection(caps),
                    get_jack_color(caps));
+       /* Default association and sequence values refer to default grouping
+        * of pin complexes and their sequence within the group. This is used
+        * for priority and resource allocation.
+        */
+       snd_iprintf(buffer, "    DefAssociation = 0x%x, Sequence = 0x%x\n",
+                   (caps & AC_DEFCFG_DEF_ASSOC) >> AC_DEFCFG_ASSOC_SHIFT,
+                   caps & AC_DEFCFG_SEQUENCE);
+       if (((caps & AC_DEFCFG_MISC) >> AC_DEFCFG_MISC_SHIFT) &
+           AC_DEFCFG_MISC_NO_PRESENCE) {
+               /* Miscellaneous bit indicates external hardware does not
+                * support presence detection even if the pin complex
+                * indicates it is supported.
+                */
+               snd_iprintf(buffer, "    Misc = NO_PRESENCE\n");
+       }
+}
+
+static void print_pin_ctls(struct snd_info_buffer *buffer,
+                          struct hda_codec *codec, hda_nid_t nid,
+                          int supports_vref)
+{
+       unsigned int pinctls;
+
+       pinctls = snd_hda_codec_read(codec, nid, 0,
+                                    AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
+       snd_iprintf(buffer, "  Pin-ctls: 0x%02x:", pinctls);
+       if (pinctls & AC_PINCTL_IN_EN)
+               snd_iprintf(buffer, " IN");
+       if (pinctls & AC_PINCTL_OUT_EN)
+               snd_iprintf(buffer, " OUT");
+       if (pinctls & AC_PINCTL_HP_EN)
+               snd_iprintf(buffer, " HP");
+       if (supports_vref) {
+               int vref = pinctls & AC_PINCTL_VREFEN;
+               switch (vref) {
+               case AC_PINCTL_VREF_HIZ:
+                       snd_iprintf(buffer, " VREF_HIZ");
+                       break;
+               case AC_PINCTL_VREF_50:
+                       snd_iprintf(buffer, " VREF_50");
+                       break;
+               case AC_PINCTL_VREF_GRD:
+                       snd_iprintf(buffer, " VREF_GRD");
+                       break;
+               case AC_PINCTL_VREF_80:
+                       snd_iprintf(buffer, " VREF_80");
+                       break;
+               case AC_PINCTL_VREF_100:
+                       snd_iprintf(buffer, " VREF_100");
+                       break;
+               }
+       }
+       snd_iprintf(buffer, "\n");
+}
+
+static void print_vol_knob(struct snd_info_buffer *buffer,
+                          struct hda_codec *codec, hda_nid_t nid)
+{
+       unsigned int cap = snd_hda_param_read(codec, nid,
+                                             AC_PAR_VOL_KNB_CAP);
+       snd_iprintf(buffer, "  Volume-Knob: delta=%d, steps=%d, ",
+                   (cap >> 7) & 1, cap & 0x7f);
+       cap = snd_hda_codec_read(codec, nid, 0,
+                                AC_VERB_GET_VOLUME_KNOB_CONTROL, 0);
+       snd_iprintf(buffer, "direct=%d, val=%d\n",
+                   (cap >> 7) & 1, cap & 0x7f);
+}
+
+static void print_audio_io(struct snd_info_buffer *buffer,
+                          struct hda_codec *codec, hda_nid_t nid,
+                          unsigned int wid_type)
+{
+       int conv = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONV, 0);
+       snd_iprintf(buffer,
+                   "  Converter: stream=%d, channel=%d\n",
+                   (conv & AC_CONV_STREAM) >> AC_CONV_STREAM_SHIFT,
+                   conv & AC_CONV_CHANNEL);
+
+       if (wid_type == AC_WID_AUD_IN && (conv & AC_CONV_CHANNEL) == 0) {
+               int sdi = snd_hda_codec_read(codec, nid, 0,
+                                            AC_VERB_GET_SDI_SELECT, 0);
+               snd_iprintf(buffer, "  SDI-Select: %d\n",
+                           sdi & AC_SDI_SELECT);
+       }
+}
+
+static void print_digital_conv(struct snd_info_buffer *buffer,
+                              struct hda_codec *codec, hda_nid_t nid)
+{
+       unsigned int digi1 = snd_hda_codec_read(codec, nid, 0,
+                                               AC_VERB_GET_DIGI_CONVERT_1, 0);
+       unsigned int digi2 = snd_hda_codec_read(codec, nid, 0,
+                                               AC_VERB_GET_DIGI_CONVERT_2, 0);
+       snd_iprintf(buffer, "  Digital:");
+       if (digi1 & AC_DIG1_ENABLE)
+               snd_iprintf(buffer, " Enabled");
+       if (digi1 & AC_DIG1_V)
+               snd_iprintf(buffer, " Validity");
+       if (digi1 & AC_DIG1_VCFG)
+               snd_iprintf(buffer, " ValidityCfg");
+       if (digi1 & AC_DIG1_EMPHASIS)
+               snd_iprintf(buffer, " Preemphasis");
+       if (digi1 & AC_DIG1_COPYRIGHT)
+               snd_iprintf(buffer, " Copyright");
+       if (digi1 & AC_DIG1_NONAUDIO)
+               snd_iprintf(buffer, " Non-Audio");
+       if (digi1 & AC_DIG1_PROFESSIONAL)
+               snd_iprintf(buffer, " Pro");
+       if (digi1 & AC_DIG1_LEVEL)
+               snd_iprintf(buffer, " GenLevel");
+       snd_iprintf(buffer, "\n");
+       snd_iprintf(buffer, "  Digital category: 0x%x\n", digi2 & AC_DIG2_CC);
+}
+
+static const char *get_pwr_state(u32 state)
+{
+       static const char *buf[4] = {
+               "D0", "D1", "D2", "D3"
+       };
+       if (state < 4)
+               return buf[state];
+       return "UNKNOWN";
+}
+
+static void print_power_state(struct snd_info_buffer *buffer,
+                             struct hda_codec *codec, hda_nid_t nid)
+{
+       int pwr = snd_hda_codec_read(codec, nid, 0,
+                                    AC_VERB_GET_POWER_STATE, 0);
+       snd_iprintf(buffer, "  Power: setting=%s, actual=%s\n",
+                   get_pwr_state(pwr & AC_PWRST_SETTING),
+                   get_pwr_state((pwr & AC_PWRST_ACTUAL) >>
+                                 AC_PWRST_ACTUAL_SHIFT));
+}
+
+static void print_unsol_cap(struct snd_info_buffer *buffer,
+                             struct hda_codec *codec, hda_nid_t nid)
+{
+       int unsol = snd_hda_codec_read(codec, nid, 0,
+                                      AC_VERB_GET_UNSOLICITED_RESPONSE, 0);
+       snd_iprintf(buffer,
+                   "  Unsolicited: tag=%02x, enabled=%d\n",
+                   unsol & AC_UNSOL_TAG,
+                   (unsol & AC_UNSOL_ENABLED) ? 1 : 0);
+}
+
+static void print_proc_caps(struct snd_info_buffer *buffer,
+                           struct hda_codec *codec, hda_nid_t nid)
+{
+       unsigned int proc_caps = snd_hda_param_read(codec, nid,
+                                                   AC_PAR_PROC_CAP);
+       snd_iprintf(buffer, "  Processing caps: benign=%d, ncoeff=%d\n",
+                   proc_caps & AC_PCAP_BENIGN,
+                   (proc_caps & AC_PCAP_NUM_COEF) >> AC_PCAP_NUM_COEF_SHIFT);
 }
 
+static void print_conn_list(struct snd_info_buffer *buffer,
+                           struct hda_codec *codec, hda_nid_t nid,
+                           unsigned int wid_type, hda_nid_t *conn,
+                           int conn_len)
+{
+       int c, curr = -1;
+
+       if (conn_len > 1 && wid_type != AC_WID_AUD_MIX)
+               curr = snd_hda_codec_read(codec, nid, 0,
+                                         AC_VERB_GET_CONNECT_SEL, 0);
+       snd_iprintf(buffer, "  Connection: %d\n", conn_len);
+       if (conn_len > 0) {
+               snd_iprintf(buffer, "    ");
+               for (c = 0; c < conn_len; c++) {
+                       snd_iprintf(buffer, " 0x%02x", conn[c]);
+                       if (c == curr)
+                               snd_iprintf(buffer, "*");
+               }
+               snd_iprintf(buffer, "\n");
+       }
+}
+
+static void print_realtek_coef(struct snd_info_buffer *buffer,
+                              struct hda_codec *codec, hda_nid_t nid)
+{
+       int coeff = snd_hda_codec_read(codec, nid, 0,
+                                      AC_VERB_GET_PROC_COEF, 0);
+       snd_iprintf(buffer, "  Processing Coefficient: 0x%02x\n", coeff);
+       coeff = snd_hda_codec_read(codec, nid, 0,
+                                  AC_VERB_GET_COEF_INDEX, 0);
+       snd_iprintf(buffer, "  Coefficient Index: 0x%02x\n", coeff);
+}
+
+static void print_gpio(struct snd_info_buffer *buffer,
+                      struct hda_codec *codec, hda_nid_t nid)
+{
+       unsigned int gpio =
+               snd_hda_param_read(codec, codec->afg, AC_PAR_GPIO_CAP);
+       unsigned int enable, direction, wake, unsol, sticky, data;
+       int i, max;
+       snd_iprintf(buffer, "GPIO: io=%d, o=%d, i=%d, "
+                   "unsolicited=%d, wake=%d\n",
+                   gpio & AC_GPIO_IO_COUNT,
+                   (gpio & AC_GPIO_O_COUNT) >> AC_GPIO_O_COUNT_SHIFT,
+                   (gpio & AC_GPIO_I_COUNT) >> AC_GPIO_I_COUNT_SHIFT,
+                   (gpio & AC_GPIO_UNSOLICITED) ? 1 : 0,
+                   (gpio & AC_GPIO_WAKE) ? 1 : 0);
+       max = gpio & AC_GPIO_IO_COUNT;
+       enable = snd_hda_codec_read(codec, nid, 0,
+                                   AC_VERB_GET_GPIO_MASK, 0);
+       direction = snd_hda_codec_read(codec, nid, 0,
+                                      AC_VERB_GET_GPIO_DIRECTION, 0);
+       wake = snd_hda_codec_read(codec, nid, 0,
+                                 AC_VERB_GET_GPIO_WAKE_MASK, 0);
+       unsol  = snd_hda_codec_read(codec, nid, 0,
+                                   AC_VERB_GET_GPIO_UNSOLICITED_RSP_MASK, 0);
+       sticky = snd_hda_codec_read(codec, nid, 0,
+                                   AC_VERB_GET_GPIO_STICKY_MASK, 0);
+       data = snd_hda_codec_read(codec, nid, 0,
+                                 AC_VERB_GET_GPIO_DATA, 0);
+       for (i = 0; i < max; ++i)
+               snd_iprintf(buffer,
+                           "  IO[%d]: enable=%d, dir=%d, wake=%d, "
+                           "sticky=%d, data=%d\n", i,
+                           (enable & (1<<i)) ? 1 : 0,
+                           (direction & (1<<i)) ? 1 : 0,
+                           (wake & (1<<i)) ? 1 : 0,
+                           (sticky & (1<<i)) ? 1 : 0,
+                           (data & (1<<i)) ? 1 : 0);
+       /* FIXME: add GPO and GPI pin information */
+}
 
 static void print_codec_info(struct snd_info_entry *entry,
                             struct snd_info_buffer *buffer)
@@ -276,14 +539,17 @@ static void print_codec_info(struct snd_info_entry *entry,
                snd_hda_power_down(codec);
                return;
        }
+
+       print_gpio(buffer, codec, codec->afg);
+
        for (i = 0; i < nodes; i++, nid++) {
                unsigned int wid_caps =
                        snd_hda_param_read(codec, nid,
                                           AC_PAR_AUDIO_WIDGET_CAP);
                unsigned int wid_type =
                        (wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
-               int conn_len = 0; 
                hda_nid_t conn[HDA_MAX_CONNECTIONS];
+               int conn_len = 0;
 
                snd_iprintf(buffer, "Node 0x%02x [%s] wcaps 0x%x:", nid,
                            get_wid_type_name(wid_type), wid_caps);
@@ -297,8 +563,18 @@ static void print_codec_info(struct snd_info_entry *entry,
                        snd_iprintf(buffer, " Amp-In");
                if (wid_caps & AC_WCAP_OUT_AMP)
                        snd_iprintf(buffer, " Amp-Out");
+               if (wid_caps & AC_WCAP_STRIPE)
+                       snd_iprintf(buffer, " Stripe");
+               if (wid_caps & AC_WCAP_LR_SWAP)
+                       snd_iprintf(buffer, " R/L");
                snd_iprintf(buffer, "\n");
 
+               /* volume knob is a special widget that always have connection
+                * list
+                */
+               if (wid_type == AC_WID_VOL_KNB)
+                       wid_caps |= AC_WCAP_CONN_LIST;
+
                if (wid_caps & AC_WCAP_CONN_LIST)
                        conn_len = snd_hda_get_connections(codec, nid, conn,
                                                           HDA_MAX_CONNECTIONS);
@@ -318,48 +594,49 @@ static void print_codec_info(struct snd_info_entry *entry,
                                       wid_caps & AC_WCAP_STEREO, 1);
                }
 
-               if (wid_type == AC_WID_PIN) {
-                       unsigned int pinctls;
-                       print_pin_caps(buffer, codec, nid);
-                       pinctls = snd_hda_codec_read(codec, nid, 0,
-                                            AC_VERB_GET_PIN_WIDGET_CONTROL,
-                                                    0);
-                       snd_iprintf(buffer, "  Pin-ctls: 0x%02x:", pinctls);
-                       if (pinctls & AC_PINCTL_IN_EN)
-                               snd_iprintf(buffer, " IN");
-                       if (pinctls & AC_PINCTL_OUT_EN)
-                               snd_iprintf(buffer, " OUT");
-                       if (pinctls & AC_PINCTL_HP_EN)
-                               snd_iprintf(buffer, " HP");
-                       snd_iprintf(buffer, "\n");
+               switch (wid_type) {
+               case AC_WID_PIN: {
+                       int supports_vref;
+                       print_pin_caps(buffer, codec, nid, &supports_vref);
+                       print_pin_ctls(buffer, codec, nid, supports_vref);
+                       break;
                }
-
-               if ((wid_type == AC_WID_AUD_OUT || wid_type == AC_WID_AUD_IN) &&
-                   (wid_caps & AC_WCAP_FORMAT_OVRD)) {
-                       snd_iprintf(buffer, "  PCM:\n");
-                       print_pcm_caps(buffer, codec, nid);
+               case AC_WID_VOL_KNB:
+                       print_vol_knob(buffer, codec, nid);
+                       break;
+               case AC_WID_AUD_OUT:
+               case AC_WID_AUD_IN:
+                       print_audio_io(buffer, codec, nid, wid_type);
+                       if (wid_caps & AC_WCAP_DIGITAL)
+                               print_digital_conv(buffer, codec, nid);
+                       if (wid_caps & AC_WCAP_FORMAT_OVRD) {
+                               snd_iprintf(buffer, "  PCM:\n");
+                               print_pcm_caps(buffer, codec, nid);
+                       }
+                       break;
                }
 
+               if (wid_caps & AC_WCAP_UNSOL_CAP)
+                       print_unsol_cap(buffer, codec, nid);
+
                if (wid_caps & AC_WCAP_POWER)
-                       snd_iprintf(buffer, "  Power: 0x%x\n",
-                                   snd_hda_codec_read(codec, nid, 0,
-                                                      AC_VERB_GET_POWER_STATE,
-                                                      0));
-
-               if (wid_caps & AC_WCAP_CONN_LIST) {
-                       int c, curr = -1;
-                       if (conn_len > 1 && wid_type != AC_WID_AUD_MIX)
-                               curr = snd_hda_codec_read(codec, nid, 0,
-                                       AC_VERB_GET_CONNECT_SEL, 0);
-                       snd_iprintf(buffer, "  Connection: %d\n", conn_len);
-                       snd_iprintf(buffer, "    ");
-                       for (c = 0; c < conn_len; c++) {
-                               snd_iprintf(buffer, " 0x%02x", conn[c]);
-                               if (c == curr)
-                                       snd_iprintf(buffer, "*");
-                       }
-                       snd_iprintf(buffer, "\n");
-               }
+                       print_power_state(buffer, codec, nid);
+
+               if (wid_caps & AC_WCAP_DELAY)
+                       snd_iprintf(buffer, "  Delay: %d samples\n",
+                                   (wid_caps & AC_WCAP_DELAY) >>
+                                   AC_WCAP_DELAY_SHIFT);
+
+               if (wid_caps & AC_WCAP_CONN_LIST)
+                       print_conn_list(buffer, codec, nid, wid_type,
+                                       conn, conn_len);
+
+               if (wid_caps & AC_WCAP_PROC_WID)
+                       print_proc_caps(buffer, codec, nid);
+
+               /* NID 0x20 == Realtek Define Registers */
+               if (codec->vendor_id == 0x10ec && nid == 0x20)
+                       print_realtek_coef(buffer, codec, nid);
        }
        snd_hda_power_down(codec);
 }
index 196ad3c9405d9b35e65f418ff97a6fd2a87faf28..19f08846d6fcaa84a800a7fcf932b0b52858172c 100644 (file)
@@ -19,7 +19,6 @@
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
@@ -79,6 +78,11 @@ struct ad198x_spec {
 #ifdef CONFIG_SND_HDA_POWER_SAVE
        struct hda_loopback_check loopback;
 #endif
+       /* for virtual master */
+       hda_nid_t vmaster_nid;
+       u32 vmaster_tlv[4];
+       const char **slave_vols;
+       const char **slave_sws;
 };
 
 /*
@@ -126,6 +130,32 @@ static int ad198x_init(struct hda_codec *codec)
        return 0;
 }
 
+static const char *ad_slave_vols[] = {
+       "Front Playback Volume",
+       "Surround Playback Volume",
+       "Center Playback Volume",
+       "LFE Playback Volume",
+       "Side Playback Volume",
+       "Headphone Playback Volume",
+       "Mono Playback Volume",
+       "Speaker Playback Volume",
+       "IEC958 Playback Volume",
+       NULL
+};
+
+static const char *ad_slave_sws[] = {
+       "Front Playback Switch",
+       "Surround Playback Switch",
+       "Center Playback Switch",
+       "LFE Playback Switch",
+       "Side Playback Switch",
+       "Headphone Playback Switch",
+       "Mono Playback Switch",
+       "Speaker Playback Switch",
+       "IEC958 Playback Switch",
+       NULL
+};
+
 static int ad198x_build_controls(struct hda_codec *codec)
 {
        struct ad198x_spec *spec = codec->spec;
@@ -147,6 +177,27 @@ static int ad198x_build_controls(struct hda_codec *codec)
                if (err < 0)
                        return err;
        }
+
+       /* if we have no master control, let's create it */
+       if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
+               snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid,
+                                       HDA_OUTPUT, spec->vmaster_tlv);
+               err = snd_hda_add_vmaster(codec, "Master Playback Volume",
+                                         spec->vmaster_tlv,
+                                         (spec->slave_vols ?
+                                          spec->slave_vols : ad_slave_vols));
+               if (err < 0)
+                       return err;
+       }
+       if (!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
+               err = snd_hda_add_vmaster(codec, "Master Playback Switch",
+                                         NULL,
+                                         (spec->slave_sws ?
+                                          spec->slave_sws : ad_slave_sws));
+               if (err < 0)
+                       return err;
+       }
+
        return 0;
 }
 
@@ -370,7 +421,7 @@ static int ad198x_eapd_put(struct snd_kcontrol *kcontrol,
        int invert = (kcontrol->private_value >> 8) & 1;
        hda_nid_t nid = kcontrol->private_value & 0xff;
        unsigned int eapd;
-       eapd = ucontrol->value.integer.value[0];
+       eapd = !!ucontrol->value.integer.value[0];
        if (invert)
                eapd = !eapd;
        if (eapd == spec->cur_eapd)
@@ -833,27 +884,29 @@ static const char *ad1986a_models[AD1986A_MODELS] = {
 
 static struct snd_pci_quirk ad1986a_cfg_tbl[] = {
        SND_PCI_QUIRK(0x103c, 0x30af, "HP B2800", AD1986A_LAPTOP_EAPD),
-       SND_PCI_QUIRK(0x10de, 0xcb84, "ASUS A8N-VM", AD1986A_3STACK),
        SND_PCI_QUIRK(0x1043, 0x1153, "ASUS M9", AD1986A_LAPTOP_EAPD),
-       SND_PCI_QUIRK(0x1043, 0x1213, "ASUS A6J", AD1986A_LAPTOP_EAPD),
        SND_PCI_QUIRK(0x1043, 0x11f7, "ASUS U5A", AD1986A_LAPTOP_EAPD),
+       SND_PCI_QUIRK(0x1043, 0x1213, "ASUS A6J", AD1986A_LAPTOP_EAPD),
        SND_PCI_QUIRK(0x1043, 0x1263, "ASUS U5F", AD1986A_LAPTOP_EAPD),
        SND_PCI_QUIRK(0x1043, 0x1297, "ASUS Z62F", AD1986A_LAPTOP_EAPD),
        SND_PCI_QUIRK(0x1043, 0x12b3, "ASUS V1j", AD1986A_LAPTOP_EAPD),
        SND_PCI_QUIRK(0x1043, 0x1302, "ASUS W3j", AD1986A_LAPTOP_EAPD),
+       SND_PCI_QUIRK(0x1043, 0x1443, "ASUS VX1", AD1986A_LAPTOP),
        SND_PCI_QUIRK(0x1043, 0x1447, "ASUS A8J", AD1986A_3STACK),
        SND_PCI_QUIRK(0x1043, 0x817f, "ASUS P5", AD1986A_3STACK),
        SND_PCI_QUIRK(0x1043, 0x818f, "ASUS P5", AD1986A_LAPTOP),
        SND_PCI_QUIRK(0x1043, 0x81b3, "ASUS P5", AD1986A_3STACK),
        SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS M2N", AD1986A_3STACK),
        SND_PCI_QUIRK(0x1043, 0x8234, "ASUS M2N", AD1986A_3STACK),
+       SND_PCI_QUIRK(0x10de, 0xcb84, "ASUS A8N-VM", AD1986A_3STACK),
+       SND_PCI_QUIRK(0x1179, 0xff40, "Toshiba", AD1986A_LAPTOP_EAPD),
        SND_PCI_QUIRK(0x144d, 0xb03c, "Samsung R55", AD1986A_3STACK),
        SND_PCI_QUIRK(0x144d, 0xc01e, "FSC V2060", AD1986A_LAPTOP),
        SND_PCI_QUIRK(0x144d, 0xc023, "Samsung X60", AD1986A_LAPTOP_EAPD),
        SND_PCI_QUIRK(0x144d, 0xc024, "Samsung R65", AD1986A_LAPTOP_EAPD),
        SND_PCI_QUIRK(0x144d, 0xc026, "Samsung X11", AD1986A_LAPTOP_EAPD),
-       SND_PCI_QUIRK(0x144d, 0xc504, "Samsung Q35", AD1986A_3STACK),
        SND_PCI_QUIRK(0x144d, 0xc027, "Samsung Q1", AD1986A_ULTRA),
+       SND_PCI_QUIRK(0x144d, 0xc504, "Samsung Q35", AD1986A_3STACK),
        SND_PCI_QUIRK(0x17aa, 0x1011, "Lenovo M55", AD1986A_LAPTOP),
        SND_PCI_QUIRK(0x17aa, 0x1017, "Lenovo A60", AD1986A_3STACK),
        SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo N100", AD1986A_LAPTOP_AUTOMUTE),
@@ -872,6 +925,13 @@ static struct hda_amp_list ad1986a_loopbacks[] = {
 };
 #endif
 
+static int is_jack_available(struct hda_codec *codec, hda_nid_t nid)
+{
+       unsigned int conf = snd_hda_codec_read(codec, nid, 0,
+                                              AC_VERB_GET_CONFIG_DEFAULT, 0);
+       return get_defcfg_connect(conf) != AC_JACK_PORT_NONE;
+}
+
 static int patch_ad1986a(struct hda_codec *codec)
 {
        struct ad198x_spec *spec;
@@ -898,6 +958,7 @@ static int patch_ad1986a(struct hda_codec *codec)
 #ifdef CONFIG_SND_HDA_POWER_SAVE
        spec->loopback.amplist = ad1986a_loopbacks;
 #endif
+       spec->vmaster_nid = 0x1b;
 
        codec->patch_ops = ad198x_patch_ops;
 
@@ -930,7 +991,8 @@ static int patch_ad1986a(struct hda_codec *codec)
                spec->multiout.max_channels = 2;
                spec->multiout.num_dacs = 1;
                spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
-               spec->multiout.dig_out_nid = 0;
+               if (!is_jack_available(codec, 0x25))
+                       spec->multiout.dig_out_nid = 0;
                spec->input_mux = &ad1986a_laptop_eapd_capture_source;
                break;
        case AD1986A_LAPTOP_AUTOMUTE:
@@ -941,7 +1003,8 @@ static int patch_ad1986a(struct hda_codec *codec)
                spec->multiout.max_channels = 2;
                spec->multiout.num_dacs = 1;
                spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
-               spec->multiout.dig_out_nid = 0;
+               if (!is_jack_available(codec, 0x25))
+                       spec->multiout.dig_out_nid = 0;
                spec->input_mux = &ad1986a_laptop_eapd_capture_source;
                codec->patch_ops.unsol_event = ad1986a_hp_unsol_event;
                codec->patch_ops.init = ad1986a_hp_init;
@@ -1020,6 +1083,8 @@ static int ad1983_spdif_route_put(struct snd_kcontrol *kcontrol, struct snd_ctl_
        struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
        struct ad198x_spec *spec = codec->spec;
 
+       if (ucontrol->value.enumerated.item[0] > 1)
+               return -EINVAL;
        if (spec->spdif_route != ucontrol->value.enumerated.item[0]) {
                spec->spdif_route = ucontrol->value.enumerated.item[0];
                snd_hda_codec_write_cache(codec, spec->multiout.dig_out_nid, 0,
@@ -1138,6 +1203,7 @@ static int patch_ad1983(struct hda_codec *codec)
 #ifdef CONFIG_SND_HDA_POWER_SAVE
        spec->loopback.amplist = ad1983_loopbacks;
 #endif
+       spec->vmaster_nid = 0x05;
 
        codec->patch_ops = ad198x_patch_ops;
 
@@ -1496,14 +1562,14 @@ static const char *ad1981_models[AD1981_MODELS] = {
 };
 
 static struct snd_pci_quirk ad1981_cfg_tbl[] = {
+       SND_PCI_QUIRK(0x1014, 0x0597, "Lenovo Z60", AD1981_THINKPAD),
        /* All HP models */
        SND_PCI_QUIRK(0x103c, 0, "HP nx", AD1981_HP),
-       /* HP nx6320 (reversed SSID, H/W bug) */
-       SND_PCI_QUIRK(0x30b0, 0x103c, "HP nx6320", AD1981_HP),
+       SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba U205", AD1981_TOSHIBA),
        /* Lenovo Thinkpad T60/X60/Z6xx */
        SND_PCI_QUIRK(0x17aa, 0, "Lenovo Thinkpad", AD1981_THINKPAD),
-       SND_PCI_QUIRK(0x1014, 0x0597, "Lenovo Z60", AD1981_THINKPAD),
-       SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba U205", AD1981_TOSHIBA),
+       /* HP nx6320 (reversed SSID, H/W bug) */
+       SND_PCI_QUIRK(0x30b0, 0x103c, "HP nx6320", AD1981_HP),
        {}
 };
 
@@ -1534,6 +1600,7 @@ static int patch_ad1981(struct hda_codec *codec)
 #ifdef CONFIG_SND_HDA_POWER_SAVE
        spec->loopback.amplist = ad1981_loopbacks;
 #endif
+       spec->vmaster_nid = 0x05;
 
        codec->patch_ops = ad198x_patch_ops;
 
@@ -1908,7 +1975,6 @@ static struct snd_kcontrol_new ad1988_capture_mixers[] = {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                /* The multiple "Capture Source" controls confuse alsamixer
                 * So call somewhat different..
-                * FIXME: the controls appear in the "playback" view!
                 */
                /* .name = "Capture Source", */
                .name = "Input Source",
@@ -1965,6 +2031,8 @@ static int ad1988_spdif_playback_source_put(struct snd_kcontrol *kcontrol,
        int change;
 
        val = ucontrol->value.enumerated.item[0];
+       if (val > 3)
+               return -EINVAL;
        if (!val) {
                sel = snd_hda_codec_read(codec, 0x1d, 0,
                                         AC_VERB_GET_AMP_GAIN_MUTE,
@@ -2079,6 +2147,8 @@ static struct hda_verb ad1988_6stack_init_verbs[] = {
        {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
        {0x3c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
        {0x34, AC_VERB_SET_CONNECT_SEL, 0x0},
+       /* Analog CD Input */
+       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 
        { }
 };
@@ -2720,8 +2790,8 @@ static const char *ad1988_models[AD1988_MODEL_LAST] = {
 };
 
 static struct snd_pci_quirk ad1988_cfg_tbl[] = {
-       SND_PCI_QUIRK(0x1043, 0x81f6, "Asus M2N-SLI", AD1988_6STACK_DIG),
        SND_PCI_QUIRK(0x1043, 0x81ec, "Asus P5B-DLX", AD1988_6STACK_DIG),
+       SND_PCI_QUIRK(0x1043, 0x81f6, "Asus M2N-SLI", AD1988_6STACK_DIG),
        {}
 };
 
@@ -2843,6 +2913,7 @@ static int patch_ad1988(struct hda_codec *codec)
 #ifdef CONFIG_SND_HDA_POWER_SAVE
        spec->loopback.amplist = ad1988_loopbacks;
 #endif
+       spec->vmaster_nid = 0x04;
 
        return 0;
 }
@@ -2919,7 +2990,6 @@ static struct snd_kcontrol_new ad1884_base_mixers[] = {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                /* The multiple "Capture Source" controls confuse alsamixer
                 * So call somewhat different..
-                * FIXME: the controls appear in the "playback" view!
                 */
                /* .name = "Capture Source", */
                .name = "Input Source",
@@ -3009,6 +3079,20 @@ static struct hda_amp_list ad1884_loopbacks[] = {
 };
 #endif
 
+static const char *ad1884_slave_vols[] = {
+       "PCM Playback Volume",
+       "Mic Playback Volume",
+       "Mono Playback Volume",
+       "Front Mic Playback Volume",
+       "Mic Playback Volume",
+       "CD Playback Volume",
+       "Internal Mic Playback Volume",
+       "Docking Mic Playback Volume"
+       "Beep Playback Volume",
+       "IEC958 Playback Volume",
+       NULL
+};
+
 static int patch_ad1884(struct hda_codec *codec)
 {
        struct ad198x_spec *spec;
@@ -3036,6 +3120,9 @@ static int patch_ad1884(struct hda_codec *codec)
 #ifdef CONFIG_SND_HDA_POWER_SAVE
        spec->loopback.amplist = ad1884_loopbacks;
 #endif
+       spec->vmaster_nid = 0x04;
+       /* we need to cover all playback volumes */
+       spec->slave_vols = ad1884_slave_vols;
 
        codec->patch_ops = ad198x_patch_ops;
 
@@ -3054,6 +3141,20 @@ static struct hda_input_mux ad1984_thinkpad_capture_source = {
        },
 };
 
+
+/*
+ * Dell Precision T3400
+ */
+static struct hda_input_mux ad1984_dell_desktop_capture_source = {
+       .num_items = 3,
+       .items = {
+               { "Front Mic", 0x0 },
+               { "Line-In", 0x1 },
+               { "Mix", 0x3 },
+       },
+};
+
+
 static struct snd_kcontrol_new ad1984_thinkpad_mixers[] = {
        HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT),
        /* HDA_CODEC_VOLUME_IDX("PCM Playback Volume", 1, 0x03, 0x0, HDA_OUTPUT), */
@@ -3078,7 +3179,6 @@ static struct snd_kcontrol_new ad1984_thinkpad_mixers[] = {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                /* The multiple "Capture Source" controls confuse alsamixer
                 * So call somewhat different..
-                * FIXME: the controls appear in the "playback" view!
                 */
                /* .name = "Capture Source", */
                .name = "Input Source",
@@ -3087,6 +3187,16 @@ static struct snd_kcontrol_new ad1984_thinkpad_mixers[] = {
                .get = ad198x_mux_enum_get,
                .put = ad198x_mux_enum_put,
        },
+       /* SPDIF controls */
+       HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
+               /* identical with ad1983 */
+               .info = ad1983_spdif_route_info,
+               .get = ad1983_spdif_route_get,
+               .put = ad1983_spdif_route_put,
+       },
        { } /* end */
 };
 
@@ -3104,6 +3214,44 @@ static struct hda_verb ad1984_thinkpad_init_verbs[] = {
        { } /* end */
 };
 
+/*
+ * Dell Precision T3400
+ */
+static struct snd_kcontrol_new ad1984_dell_desktop_mixers[] = {
+       HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Speaker Playback Switch", 0x12, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
+       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line-In Playback Volume", 0x20, 0x01, HDA_INPUT),
+       HDA_CODEC_MUTE("Line-In Playback Switch", 0x20, 0x01, HDA_INPUT),
+       /*
+       HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x20, 0x03, HDA_INPUT),
+       HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x20, 0x03, HDA_INPUT),
+       */
+       HDA_CODEC_VOLUME("Line-In Boost", 0x15, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Boost", 0x14, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               /* The multiple "Capture Source" controls confuse alsamixer
+                * So call somewhat different..
+                */
+               /* .name = "Capture Source", */
+               .name = "Input Source",
+               .count = 2,
+               .info = ad198x_mux_enum_info,
+               .get = ad198x_mux_enum_get,
+               .put = ad198x_mux_enum_put,
+       },
+       { } /* end */
+};
+
 /* Digial MIC ADC NID 0x05 + 0x06 */
 static int ad1984_pcm_dmic_prepare(struct hda_pcm_stream *hinfo,
                                   struct hda_codec *codec,
@@ -3157,17 +3305,20 @@ static int ad1984_build_pcms(struct hda_codec *codec)
 enum {
        AD1984_BASIC,
        AD1984_THINKPAD,
+       AD1984_DELL_DESKTOP,
        AD1984_MODELS
 };
 
 static const char *ad1984_models[AD1984_MODELS] = {
        [AD1984_BASIC]          = "basic",
        [AD1984_THINKPAD]       = "thinkpad",
+       [AD1984_DELL_DESKTOP]   = "dell_desktop",
 };
 
 static struct snd_pci_quirk ad1984_cfg_tbl[] = {
        /* Lenovo Thinkpad T61/X61 */
        SND_PCI_QUIRK(0x17aa, 0, "Lenovo Thinkpad", AD1984_THINKPAD),
+       SND_PCI_QUIRK(0x1028, 0x0214, "Dell T3400", AD1984_DELL_DESKTOP),
        {}
 };
 
@@ -3189,11 +3340,16 @@ static int patch_ad1984(struct hda_codec *codec)
                codec->patch_ops.build_pcms = ad1984_build_pcms;
                break;
        case AD1984_THINKPAD:
-               spec->multiout.dig_out_nid = 0;
+               spec->multiout.dig_out_nid = AD1884_SPDIF_OUT;
                spec->input_mux = &ad1984_thinkpad_capture_source;
                spec->mixers[0] = ad1984_thinkpad_mixers;
                spec->init_verbs[spec->num_init_verbs++] = ad1984_thinkpad_init_verbs;
                break;
+       case AD1984_DELL_DESKTOP:
+               spec->multiout.dig_out_nid = 0;
+               spec->input_mux = &ad1984_dell_desktop_capture_source;
+               spec->mixers[0] = ad1984_dell_desktop_mixers;
+               break;
        }
        return 0;
 }
@@ -3267,7 +3423,6 @@ static struct snd_kcontrol_new ad1882_base_mixers[] = {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                /* The multiple "Capture Source" controls confuse alsamixer
                 * So call somewhat different..
-                * FIXME: the controls appear in the "playback" view!
                 */
                /* .name = "Capture Source", */
                .name = "Input Source",
@@ -3468,6 +3623,7 @@ static int patch_ad1882(struct hda_codec *codec)
 #ifdef CONFIG_SND_HDA_POWER_SAVE
        spec->loopback.amplist = ad1882_loopbacks;
 #endif
+       spec->vmaster_nid = 0x04;
 
        codec->patch_ops = ad198x_patch_ops;
 
index fbb8969dc559c50c56bb6f983850d186c637eaba..9a8bb4ce3f8da103847a7dce8e1bb8c01d13316e 100644 (file)
@@ -21,7 +21,6 @@
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
@@ -158,6 +157,6 @@ struct hda_codec_preset snd_hda_preset_atihdmi[] = {
        { .id = 0x1002793c, .name = "ATI RS600 HDMI", .patch = patch_atihdmi },
        { .id = 0x10027919, .name = "ATI RS600 HDMI", .patch = patch_atihdmi },
        { .id = 0x1002791a, .name = "ATI RS690/780 HDMI", .patch = patch_atihdmi },
-       { .id = 0x1002aa01, .name = "ATI R600 HDMI", .patch = patch_atihdmi },
+       { .id = 0x1002aa01, .name = "ATI R6xx HDMI", .patch = patch_atihdmi },
        {} /* terminator */
 };
index 6c54793bf424cf4e52d4a922ad4532fa1726a613..3d6097ba1d68fb98f851fe1668effd6fe1d0a4ba 100644 (file)
@@ -21,7 +21,6 @@
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
@@ -186,7 +185,6 @@ static struct snd_kcontrol_new cmi9880_basic_mixer[] = {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                /* The multiple "Capture Source" controls confuse alsamixer
                 * So call somewhat different..
-                * FIXME: the controls appear in the "playback" view!
                 */
                /* .name = "Capture Source", */
                .name = "Input Source",
index 6aa073986747bd20a26c0c7a4e1e154a173e5c39..f6dd51cda7b268de749135bb3d0aef618d2acce9 100644 (file)
@@ -20,7 +20,6 @@
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
@@ -65,6 +64,11 @@ struct conexant_spec {
        hda_nid_t *adc_nids;
        hda_nid_t dig_in_nid;           /* digital-in NID; optional */
 
+       unsigned int cur_adc_idx;
+       hda_nid_t cur_adc;
+       unsigned int cur_adc_stream_tag;
+       unsigned int cur_adc_format;
+
        /* capture source */
        const struct hda_input_mux *input_mux;
        hda_nid_t *capsrc_nids;
@@ -218,6 +222,41 @@ static struct hda_pcm_stream conexant_pcm_digital_capture = {
        /* NID is set in alc_build_pcms */
 };
 
+static int cx5051_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
+                                     struct hda_codec *codec,
+                                     unsigned int stream_tag,
+                                     unsigned int format,
+                                     struct snd_pcm_substream *substream)
+{
+       struct conexant_spec *spec = codec->spec;
+       spec->cur_adc = spec->adc_nids[spec->cur_adc_idx];
+       spec->cur_adc_stream_tag = stream_tag;
+       spec->cur_adc_format = format;
+       snd_hda_codec_setup_stream(codec, spec->cur_adc, stream_tag, 0, format);
+       return 0;
+}
+
+static int cx5051_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
+                                     struct hda_codec *codec,
+                                     struct snd_pcm_substream *substream)
+{
+       struct conexant_spec *spec = codec->spec;
+       snd_hda_codec_setup_stream(codec, spec->cur_adc, 0, 0, 0);
+       spec->cur_adc = 0;
+       return 0;
+}
+
+static struct hda_pcm_stream cx5051_pcm_analog_capture = {
+       .substreams = 1,
+       .channels_min = 2,
+       .channels_max = 2,
+       .nid = 0, /* fill later */
+       .ops = {
+               .prepare = cx5051_capture_pcm_prepare,
+               .cleanup = cx5051_capture_pcm_cleanup
+       },
+};
+
 static int conexant_build_pcms(struct hda_codec *codec)
 {
        struct conexant_spec *spec = codec->spec;
@@ -232,7 +271,12 @@ static int conexant_build_pcms(struct hda_codec *codec)
                spec->multiout.max_channels;
        info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
                spec->multiout.dac_nids[0];
-       info->stream[SNDRV_PCM_STREAM_CAPTURE] = conexant_pcm_analog_capture;
+       if (codec->vendor_id == 0x14f15051)
+               info->stream[SNDRV_PCM_STREAM_CAPTURE] =
+                       cx5051_pcm_analog_capture;
+       else
+               info->stream[SNDRV_PCM_STREAM_CAPTURE] =
+                       conexant_pcm_analog_capture;
        info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_adc_nids;
        info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
 
@@ -373,7 +417,7 @@ static int cxt_eapd_put(struct snd_kcontrol *kcontrol,
        hda_nid_t nid = kcontrol->private_value & 0xff;
        unsigned int eapd;
 
-       eapd = ucontrol->value.integer.value[0];
+       eapd = !!ucontrol->value.integer.value[0];
        if (invert)
                eapd = !eapd;
        if (eapd == spec->cur_eapd)
@@ -454,7 +498,16 @@ static struct hda_input_mux cxt5045_capture_source = {
        .num_items = 2,
        .items = {
                { "IntMic", 0x1 },
-               { "LineIn", 0x2 },
+               { "ExtMic", 0x2 },
+       }
+};
+
+static struct hda_input_mux cxt5045_capture_source_benq = {
+       .num_items = 3,
+       .items = {
+               { "IntMic", 0x1 },
+               { "ExtMic", 0x2 },
+               { "LineIn", 0x3 },
        }
 };
 
@@ -577,6 +630,15 @@ static struct snd_kcontrol_new cxt5045_mixers[] = {
        {}
 };
 
+static struct snd_kcontrol_new cxt5045_benq_mixers[] = {
+       HDA_CODEC_VOLUME("Line In Capture Volume", 0x1a, 0x03, HDA_INPUT),
+       HDA_CODEC_MUTE("Line In Capture Switch", 0x1a, 0x03, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line In Playback Volume", 0x17, 0x3, HDA_INPUT),
+       HDA_CODEC_MUTE("Line In Playback Switch", 0x17, 0x3, HDA_INPUT),
+
+       {}
+};
+
 static struct hda_verb cxt5045_init_verbs[] = {
        /* Line in, Mic */
        {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
@@ -602,6 +664,30 @@ static struct hda_verb cxt5045_init_verbs[] = {
        { } /* end */
 };
 
+static struct hda_verb cxt5045_benq_init_verbs[] = {
+       /* Int Mic, Mic */
+       {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_80 },
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_80 },
+       /* Line In,HP, Amp  */
+       {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x10, AC_VERB_SET_CONNECT_SEL, 0x1},
+       {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       {0x11, AC_VERB_SET_CONNECT_SEL, 0x1},
+       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+       /* Record selector: Int mic */
+       {0x1a, AC_VERB_SET_CONNECT_SEL, 0x1},
+       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE,
+        AC_AMP_SET_INPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x17},
+       /* SPDIF route: PCM */
+       {0x13, AC_VERB_SET_CONNECT_SEL, 0x0},
+       /* EAPD */
+       {0x10, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */
+       { } /* end */
+};
 
 static struct hda_verb cxt5045_hp_sense_init_verbs[] = {
        /* pin sensing on HP jack */
@@ -740,8 +826,10 @@ static int cxt5045_init(struct hda_codec *codec)
 
 
 enum {
-       CXT5045_LAPTOP,  /* Laptops w/ EAPD support */
-       CXT5045_FUJITSU, /* Laptops w/ EAPD support */ 
+       CXT5045_LAPTOP_HPSENSE,
+       CXT5045_LAPTOP_MICSENSE,
+       CXT5045_LAPTOP_HPMICSENSE,
+       CXT5045_BENQ,
 #ifdef CONFIG_SND_DEBUG
        CXT5045_TEST,
 #endif
@@ -749,23 +837,35 @@ enum {
 };
 
 static const char *cxt5045_models[CXT5045_MODELS] = {
-       [CXT5045_LAPTOP]        = "laptop",
-       [CXT5045_FUJITSU]       = "fujitsu",
+       [CXT5045_LAPTOP_HPSENSE]        = "laptop-hpsense",
+       [CXT5045_LAPTOP_MICSENSE]       = "laptop-micsense",
+       [CXT5045_LAPTOP_HPMICSENSE]     = "laptop-hpmicsense",
+       [CXT5045_BENQ]                  = "benq",
 #ifdef CONFIG_SND_DEBUG
        [CXT5045_TEST]          = "test",
 #endif
 };
 
 static struct snd_pci_quirk cxt5045_cfg_tbl[] = {
-       SND_PCI_QUIRK(0x103c, 0x30b7, "HP DV6000Z", CXT5045_LAPTOP),
-       SND_PCI_QUIRK(0x103c, 0x30bb, "HP DV8000", CXT5045_LAPTOP),
-       SND_PCI_QUIRK(0x103c, 0x30b2, "HP DV Series", CXT5045_LAPTOP),
-       SND_PCI_QUIRK(0x103c, 0x30b5, "HP DV2120", CXT5045_LAPTOP),
-       SND_PCI_QUIRK(0x103c, 0x30cd, "HP DV Series", CXT5045_LAPTOP),
-       SND_PCI_QUIRK(0x103c, 0x30d9, "HP Spartan", CXT5045_LAPTOP),
-       SND_PCI_QUIRK(0x1734, 0x10ad, "Fujitsu Si1520", CXT5045_FUJITSU),
-       SND_PCI_QUIRK(0x1734, 0x10cb, "Fujitsu Si3515", CXT5045_LAPTOP),
-       SND_PCI_QUIRK(0x8086, 0x2111, "Conexant Reference board", CXT5045_LAPTOP),
+       SND_PCI_QUIRK(0x103c, 0x30a5, "HP", CXT5045_LAPTOP_HPSENSE),
+       SND_PCI_QUIRK(0x103c, 0x30b2, "HP DV Series", CXT5045_LAPTOP_HPSENSE),
+       SND_PCI_QUIRK(0x103c, 0x30b5, "HP DV2120", CXT5045_LAPTOP_HPSENSE),
+       SND_PCI_QUIRK(0x103c, 0x30b7, "HP DV6000Z", CXT5045_LAPTOP_HPSENSE),
+       SND_PCI_QUIRK(0x103c, 0x30bb, "HP DV8000", CXT5045_LAPTOP_HPSENSE),
+       SND_PCI_QUIRK(0x103c, 0x30cd, "HP DV Series", CXT5045_LAPTOP_HPSENSE),
+       SND_PCI_QUIRK(0x103c, 0x30cf, "HP DV9533EG", CXT5045_LAPTOP_HPSENSE),
+       SND_PCI_QUIRK(0x103c, 0x30d5, "HP 530", CXT5045_LAPTOP_HPSENSE),
+       SND_PCI_QUIRK(0x103c, 0x30d9, "HP Spartan", CXT5045_LAPTOP_HPSENSE),
+       SND_PCI_QUIRK(0x152d, 0x0753, "Benq R55E", CXT5045_BENQ),
+       SND_PCI_QUIRK(0x1734, 0x10ad, "Fujitsu Si1520", CXT5045_LAPTOP_MICSENSE),
+       SND_PCI_QUIRK(0x1734, 0x10cb, "Fujitsu Si3515", CXT5045_LAPTOP_HPMICSENSE),
+       SND_PCI_QUIRK(0x1734, 0x110e, "Fujitsu V5505", CXT5045_LAPTOP_HPSENSE),
+       SND_PCI_QUIRK(0x1509, 0x1e40, "FIC", CXT5045_LAPTOP_HPMICSENSE),
+       SND_PCI_QUIRK(0x1509, 0x2f05, "FIC", CXT5045_LAPTOP_HPMICSENSE),
+       SND_PCI_QUIRK(0x1509, 0x2f06, "FIC", CXT5045_LAPTOP_HPMICSENSE),
+       SND_PCI_QUIRK(0x1631, 0xc106, "Packard Bell", CXT5045_LAPTOP_HPMICSENSE),
+       SND_PCI_QUIRK(0x1631, 0xc107, "Packard Bell", CXT5045_LAPTOP_HPMICSENSE),
+       SND_PCI_QUIRK(0x8086, 0x2111, "Conexant Reference board", CXT5045_LAPTOP_HPSENSE),
        {}
 };
 
@@ -803,7 +903,7 @@ static int patch_cxt5045(struct hda_codec *codec)
                                                  cxt5045_models,
                                                  cxt5045_cfg_tbl);
        switch (board_config) {
-       case CXT5045_LAPTOP:
+       case CXT5045_LAPTOP_HPSENSE:
                codec->patch_ops.unsol_event = cxt5045_hp_unsol_event;
                spec->input_mux = &cxt5045_capture_source;
                spec->num_init_verbs = 2;
@@ -811,20 +911,53 @@ static int patch_cxt5045(struct hda_codec *codec)
                spec->mixers[0] = cxt5045_mixers;
                codec->patch_ops.init = cxt5045_init;
                break;
-       case CXT5045_FUJITSU:
+       case CXT5045_LAPTOP_MICSENSE:
                spec->input_mux = &cxt5045_capture_source;
                spec->num_init_verbs = 2;
                spec->init_verbs[1] = cxt5045_mic_sense_init_verbs;
                spec->mixers[0] = cxt5045_mixers;
                codec->patch_ops.init = cxt5045_init;
                break;
+       default:
+       case CXT5045_LAPTOP_HPMICSENSE:
+               codec->patch_ops.unsol_event = cxt5045_hp_unsol_event;
+               spec->input_mux = &cxt5045_capture_source;
+               spec->num_init_verbs = 3;
+               spec->init_verbs[1] = cxt5045_hp_sense_init_verbs;
+               spec->init_verbs[2] = cxt5045_mic_sense_init_verbs;
+               spec->mixers[0] = cxt5045_mixers;
+               codec->patch_ops.init = cxt5045_init;
+               break;
+       case CXT5045_BENQ:
+               codec->patch_ops.unsol_event = cxt5045_hp_unsol_event;
+               spec->input_mux = &cxt5045_capture_source_benq;
+               spec->num_init_verbs = 1;
+               spec->init_verbs[0] = cxt5045_benq_init_verbs;
+               spec->mixers[0] = cxt5045_mixers;
+               spec->mixers[1] = cxt5045_benq_mixers;
+               spec->num_mixers = 2;
+               codec->patch_ops.init = cxt5045_init;
+               break;
 #ifdef CONFIG_SND_DEBUG
        case CXT5045_TEST:
                spec->input_mux = &cxt5045_test_capture_source;
                spec->mixers[0] = cxt5045_test_mixer;
                spec->init_verbs[0] = cxt5045_test_init_verbs;
+               break;
+               
 #endif 
        }
+
+       /*
+        * Fix max PCM level to 0 dB
+        * (originall it has 0x2b steps with 0dB offset 0x14)
+        */
+       snd_hda_override_amp_caps(codec, 0x17, HDA_INPUT,
+                                 (0x14 << AC_AMPCAP_OFFSET_SHIFT) |
+                                 (0x14 << AC_AMPCAP_NUM_STEPS_SHIFT) |
+                                 (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
+                                 (1 << AC_AMPCAP_MUTE_SHIFT));
+
        return 0;
 }
 
@@ -933,13 +1066,13 @@ static void cxt5047_hp2_automute(struct hda_codec *codec)
 static void cxt5047_hp_automic(struct hda_codec *codec)
 {
        static struct hda_verb mic_jack_on[] = {
-               {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-               {0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
+               {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+               {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
                {}
        };
        static struct hda_verb mic_jack_off[] = {
-               {0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-               {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
+               {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+               {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
                {}
        };
        unsigned int present;
@@ -956,8 +1089,7 @@ static void cxt5047_hp_automic(struct hda_codec *codec)
 static void cxt5047_hp_unsol_event(struct hda_codec *codec,
                                  unsigned int res)
 {
-       res >>= 26;
-       switch (res) {
+       switch (res >> 26) {
        case CONEXANT_HP_EVENT:
                cxt5047_hp_automute(codec);
                break;
@@ -1166,6 +1298,17 @@ static struct snd_kcontrol_new cxt5047_test_mixer[] = {
                .get = conexant_mux_enum_get,
                .put = conexant_mux_enum_put,
        },
+       HDA_CODEC_VOLUME("Input-1 Volume", 0x1a, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Input-1 Switch", 0x1a, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Input-2 Volume", 0x1a, 0x1, HDA_INPUT),
+       HDA_CODEC_MUTE("Input-2 Switch", 0x1a, 0x1, HDA_INPUT),
+       HDA_CODEC_VOLUME("Input-3 Volume", 0x1a, 0x2, HDA_INPUT),
+       HDA_CODEC_MUTE("Input-3 Switch", 0x1a, 0x2, HDA_INPUT),
+       HDA_CODEC_VOLUME("Input-4 Volume", 0x1a, 0x3, HDA_INPUT),
+       HDA_CODEC_MUTE("Input-4 Switch", 0x1a, 0x3, HDA_INPUT),
+       HDA_CODEC_VOLUME("Input-5 Volume", 0x1a, 0x4, HDA_INPUT),
+       HDA_CODEC_MUTE("Input-5 Switch", 0x1a, 0x4, HDA_INPUT),
+
        { } /* end */
 };
 
@@ -1255,9 +1398,9 @@ static const char *cxt5047_models[CXT5047_MODELS] = {
 
 static struct snd_pci_quirk cxt5047_cfg_tbl[] = {
        SND_PCI_QUIRK(0x103c, 0x30a0, "HP DV1000", CXT5047_LAPTOP),
+       SND_PCI_QUIRK(0x103c, 0x30a5, "HP DV5200T/DV8000T", CXT5047_LAPTOP_HP),
        SND_PCI_QUIRK(0x103c, 0x30b2, "HP DV2000T/DV3000T", CXT5047_LAPTOP),
        SND_PCI_QUIRK(0x103c, 0x30b5, "HP DV2000Z", CXT5047_LAPTOP),
-       SND_PCI_QUIRK(0x103c, 0x30a5, "HP DV5200T/DV8000T", CXT5047_LAPTOP_HP),
        SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba P100", CXT5047_LAPTOP_EAPD),
        {}
 };
@@ -1324,10 +1467,260 @@ static int patch_cxt5047(struct hda_codec *codec)
        return 0;
 }
 
+/* Conexant 5051 specific */
+static hda_nid_t cxt5051_dac_nids[1] = { 0x10 };
+static hda_nid_t cxt5051_adc_nids[2] = { 0x14, 0x15 };
+#define CXT5051_SPDIF_OUT      0x1C
+#define CXT5051_PORTB_EVENT    0x38
+#define CXT5051_PORTC_EVENT    0x39
+
+static struct hda_channel_mode cxt5051_modes[1] = {
+       { 2, NULL },
+};
+
+static void cxt5051_update_speaker(struct hda_codec *codec)
+{
+       struct conexant_spec *spec = codec->spec;
+       unsigned int pinctl;
+       pinctl = (!spec->hp_present && spec->cur_eapd) ? PIN_OUT : 0;
+       snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
+                           pinctl);
+}
+
+/* turn on/off EAPD (+ mute HP) as a master switch */
+static int cxt5051_hp_master_sw_put(struct snd_kcontrol *kcontrol,
+                                   struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+
+       if (!cxt_eapd_put(kcontrol, ucontrol))
+               return 0;
+       cxt5051_update_speaker(codec);
+       return 1;
+}
+
+/* toggle input of built-in and mic jack appropriately */
+static void cxt5051_portb_automic(struct hda_codec *codec)
+{
+       unsigned int present;
+
+       present = snd_hda_codec_read(codec, 0x17, 0,
+                                    AC_VERB_GET_PIN_SENSE, 0) &
+               AC_PINSENSE_PRESENCE;
+       snd_hda_codec_write(codec, 0x14, 0,
+                           AC_VERB_SET_CONNECT_SEL,
+                           present ? 0x01 : 0x00);
+}
+
+/* switch the current ADC according to the jack state */
+static void cxt5051_portc_automic(struct hda_codec *codec)
+{
+       struct conexant_spec *spec = codec->spec;
+       unsigned int present;
+       hda_nid_t new_adc;
+
+       present = snd_hda_codec_read(codec, 0x18, 0,
+                                    AC_VERB_GET_PIN_SENSE, 0) &
+               AC_PINSENSE_PRESENCE;
+       if (present)
+               spec->cur_adc_idx = 1;
+       else
+               spec->cur_adc_idx = 0;
+       new_adc = spec->adc_nids[spec->cur_adc_idx];
+       if (spec->cur_adc && spec->cur_adc != new_adc) {
+               /* stream is running, let's swap the current ADC */
+               snd_hda_codec_setup_stream(codec, spec->cur_adc, 0, 0, 0);
+               spec->cur_adc = new_adc;
+               snd_hda_codec_setup_stream(codec, new_adc,
+                                          spec->cur_adc_stream_tag, 0,
+                                          spec->cur_adc_format);
+       }
+}
+
+/* mute internal speaker if HP is plugged */
+static void cxt5051_hp_automute(struct hda_codec *codec)
+{
+       struct conexant_spec *spec = codec->spec;
+
+       spec->hp_present = snd_hda_codec_read(codec, 0x16, 0,
+                                    AC_VERB_GET_PIN_SENSE, 0) &
+               AC_PINSENSE_PRESENCE;
+       cxt5051_update_speaker(codec);
+}
+
+/* unsolicited event for HP jack sensing */
+static void cxt5051_hp_unsol_event(struct hda_codec *codec,
+                                  unsigned int res)
+{
+       switch (res >> 26) {
+       case CONEXANT_HP_EVENT:
+               cxt5051_hp_automute(codec);
+               break;
+       case CXT5051_PORTB_EVENT:
+               cxt5051_portb_automic(codec);
+               break;
+       case CXT5051_PORTC_EVENT:
+               cxt5051_portc_automic(codec);
+               break;
+       }
+}
+
+static struct snd_kcontrol_new cxt5051_mixers[] = {
+       HDA_CODEC_VOLUME("Internal Mic Volume", 0x14, 0x00, HDA_INPUT),
+       HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT),
+       HDA_CODEC_VOLUME("External Mic Volume", 0x14, 0x01, HDA_INPUT),
+       HDA_CODEC_MUTE("External Mic Switch", 0x14, 0x01, HDA_INPUT),
+       HDA_CODEC_VOLUME("Docking Mic Volume", 0x15, 0x00, HDA_INPUT),
+       HDA_CODEC_MUTE("Docking Mic Switch", 0x15, 0x00, HDA_INPUT),
+       HDA_CODEC_VOLUME("Master Playback Volume", 0x10, 0x00, HDA_OUTPUT),
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Master Playback Switch",
+               .info = cxt_eapd_info,
+               .get = cxt_eapd_get,
+               .put = cxt5051_hp_master_sw_put,
+               .private_value = 0x1a,
+       },
+
+       {}
+};
+
+static struct snd_kcontrol_new cxt5051_hp_mixers[] = {
+       HDA_CODEC_VOLUME("Internal Mic Volume", 0x14, 0x00, HDA_INPUT),
+       HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT),
+       HDA_CODEC_VOLUME("External Mic Volume", 0x15, 0x00, HDA_INPUT),
+       HDA_CODEC_MUTE("External Mic Switch", 0x15, 0x00, HDA_INPUT),
+       HDA_CODEC_VOLUME("Master Playback Volume", 0x10, 0x00, HDA_OUTPUT),
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Master Playback Switch",
+               .info = cxt_eapd_info,
+               .get = cxt_eapd_get,
+               .put = cxt5051_hp_master_sw_put,
+               .private_value = 0x1a,
+       },
+
+       {}
+};
+
+static struct hda_verb cxt5051_init_verbs[] = {
+       /* Line in, Mic */
+       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03},
+       {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03},
+       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+       {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03},
+       /* SPK  */
+       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
+       /* HP, Amp  */
+       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x16, AC_VERB_SET_CONNECT_SEL, 0x00},
+       /* DAC1 */      
+       {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       /* Record selector: Int mic */
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x44},
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x44},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x44},
+       /* SPDIF route: PCM */
+       {0x1c, AC_VERB_SET_CONNECT_SEL, 0x0},
+       /* EAPD */
+       {0x1a, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ 
+       {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CONEXANT_HP_EVENT},
+       {0x17, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CXT5051_PORTB_EVENT},
+       {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CXT5051_PORTC_EVENT},
+       { } /* end */
+};
+
+/* initialize jack-sensing, too */
+static int cxt5051_init(struct hda_codec *codec)
+{
+       conexant_init(codec);
+       if (codec->patch_ops.unsol_event) {
+               cxt5051_hp_automute(codec);
+               cxt5051_portb_automic(codec);
+               cxt5051_portc_automic(codec);
+       }
+       return 0;
+}
+
+
+enum {
+       CXT5051_LAPTOP,  /* Laptops w/ EAPD support */
+       CXT5051_HP,     /* no docking */
+       CXT5051_MODELS
+};
+
+static const char *cxt5051_models[CXT5051_MODELS] = {
+       [CXT5051_LAPTOP]        = "laptop",
+       [CXT5051_HP]            = "hp",
+};
+
+static struct snd_pci_quirk cxt5051_cfg_tbl[] = {
+       SND_PCI_QUIRK(0x14f1, 0x0101, "Conexant Reference board",
+                     CXT5051_LAPTOP),
+       SND_PCI_QUIRK(0x14f1, 0x5051, "HP Spartan 1.1", CXT5051_HP),
+       {}
+};
+
+static int patch_cxt5051(struct hda_codec *codec)
+{
+       struct conexant_spec *spec;
+       int board_config;
+
+       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+       if (!spec)
+               return -ENOMEM;
+       mutex_init(&spec->amp_mutex);
+       codec->spec = spec;
+
+       codec->patch_ops = conexant_patch_ops;
+       codec->patch_ops.init = cxt5051_init;
+
+       spec->multiout.max_channels = 2;
+       spec->multiout.num_dacs = ARRAY_SIZE(cxt5051_dac_nids);
+       spec->multiout.dac_nids = cxt5051_dac_nids;
+       spec->multiout.dig_out_nid = CXT5051_SPDIF_OUT;
+       spec->num_adc_nids = 1; /* not 2; via auto-mic switch */
+       spec->adc_nids = cxt5051_adc_nids;
+       spec->num_mixers = 1;
+       spec->mixers[0] = cxt5051_mixers;
+       spec->num_init_verbs = 1;
+       spec->init_verbs[0] = cxt5051_init_verbs;
+       spec->spdif_route = 0;
+       spec->num_channel_mode = ARRAY_SIZE(cxt5051_modes);
+       spec->channel_mode = cxt5051_modes;
+       spec->cur_adc = 0;
+       spec->cur_adc_idx = 0;
+
+       board_config = snd_hda_check_board_config(codec, CXT5051_MODELS,
+                                                 cxt5051_models,
+                                                 cxt5051_cfg_tbl);
+       switch (board_config) {
+       case CXT5051_HP:
+               codec->patch_ops.unsol_event = cxt5051_hp_unsol_event;
+               spec->mixers[0] = cxt5051_hp_mixers;
+               break;
+       default:
+       case CXT5051_LAPTOP:
+               codec->patch_ops.unsol_event = cxt5051_hp_unsol_event;
+               break;
+       }
+
+       return 0;
+}
+
+
+/*
+ */
+
 struct hda_codec_preset snd_hda_preset_conexant[] = {
        { .id = 0x14f15045, .name = "CX20549 (Venice)",
          .patch = patch_cxt5045 },
        { .id = 0x14f15047, .name = "CX20551 (Waikiki)",
          .patch = patch_cxt5047 },
+       { .id = 0x14f15051, .name = "CX20561 (Hermosa)",
+         .patch = patch_cxt5051 },
        {} /* terminator */
 };
index 1c502789cc1ed001a7360e50425694f3635260ce..586d98f1b63d07b2373e40b4370fe7b233ed235a 100644 (file)
@@ -23,7 +23,6 @@
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
@@ -92,9 +91,12 @@ enum {
        ALC262_HP_BPC,
        ALC262_HP_BPC_D7000_WL,
        ALC262_HP_BPC_D7000_WF,
+       ALC262_HP_TC_T5735,
+       ALC262_HP_RP5700,
        ALC262_BENQ_ED8,
        ALC262_SONY_ASSAMD,
        ALC262_BENQ_T31,
+       ALC262_ULTRA,
        ALC262_AUTO,
        ALC262_MODEL_LAST /* last tag */
 };
@@ -104,10 +106,21 @@ enum {
        ALC268_3ST,
        ALC268_TOSHIBA,
        ALC268_ACER,
+       ALC268_DELL,
+#ifdef CONFIG_SND_DEBUG
+       ALC268_TEST,
+#endif
        ALC268_AUTO,
        ALC268_MODEL_LAST /* last tag */
 };
 
+/* ALC269 models */
+enum {
+       ALC269_BASIC,
+       ALC269_AUTO,
+       ALC269_MODEL_LAST /* last tag */
+};
+
 /* ALC861 models */
 enum {
        ALC861_3ST,
@@ -144,6 +157,7 @@ enum {
        ALC662_5ST_DIG,
        ALC662_LENOVO_101E,
        ALC662_ASUS_EEEPC_P701,
+       ALC662_ASUS_EEEPC_EP20,
        ALC662_AUTO,
        ALC662_MODEL_LAST,
 };
@@ -183,6 +197,8 @@ enum {
        ALC883_HAIER_W66,               
        ALC888_6ST_HP,
        ALC888_3ST_HP,
+       ALC888_6ST_DELL,
+       ALC883_MITAC,
        ALC883_AUTO,
        ALC883_MODEL_LAST,
 };
@@ -204,6 +220,8 @@ struct alc_spec {
        char *stream_name_analog;       /* analog PCM stream */
        struct hda_pcm_stream *stream_analog_playback;
        struct hda_pcm_stream *stream_analog_capture;
+       struct hda_pcm_stream *stream_analog_alt_playback;
+       struct hda_pcm_stream *stream_analog_alt_capture;
 
        char *stream_name_digital;      /* digital PCM stream */
        struct hda_pcm_stream *stream_digital_playback;
@@ -214,6 +232,7 @@ struct alc_spec {
                                         * max_channels, dacs must be set
                                         * dig_out_nid and hp_nid are optional
                                         */
+       hda_nid_t alt_dac_nid;
 
        /* capture */
        unsigned int num_adc_nids;
@@ -247,7 +266,11 @@ struct alc_spec {
        /* for pin sensing */
        unsigned int sense_updated: 1;
        unsigned int jack_present: 1;
+       unsigned int master_sw: 1;
 
+       /* for virtual master */
+       hda_nid_t vmaster_nid;
+       u32 vmaster_tlv[4];
 #ifdef CONFIG_SND_HDA_POWER_SAVE
        struct hda_loopback_check loopback;
 #endif
@@ -562,7 +585,7 @@ static int alc_spdif_ctrl_get(struct snd_kcontrol *kcontrol,
        unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
        long *valp = ucontrol->value.integer.value;
        unsigned int val = snd_hda_codec_read(codec, nid, 0,
-                                             AC_VERB_GET_DIGI_CONVERT, 0x00);
+                                             AC_VERB_GET_DIGI_CONVERT_1, 0x00);
 
        *valp = (val & mask) != 0;
        return 0;
@@ -576,7 +599,7 @@ static int alc_spdif_ctrl_put(struct snd_kcontrol *kcontrol,
        unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
        long val = *ucontrol->value.integer.value;
        unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0,
-                                                   AC_VERB_GET_DIGI_CONVERT,
+                                                   AC_VERB_GET_DIGI_CONVERT_1,
                                                    0x00);
 
        /* Set/unset the masked control bit(s) as needed */
@@ -598,6 +621,59 @@ static int alc_spdif_ctrl_put(struct snd_kcontrol *kcontrol,
          .private_value = nid | (mask<<16) }
 #endif   /* CONFIG_SND_DEBUG */
 
+/* A switch control to allow the enabling EAPD digital outputs on the ALC26x.
+ * Again, this is only used in the ALC26x test models to help identify when
+ * the EAPD line must be asserted for features to work.
+ */
+#ifdef CONFIG_SND_DEBUG
+#define alc_eapd_ctrl_info     snd_ctl_boolean_mono_info
+
+static int alc_eapd_ctrl_get(struct snd_kcontrol *kcontrol,
+                             struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       hda_nid_t nid = kcontrol->private_value & 0xffff;
+       unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
+       long *valp = ucontrol->value.integer.value;
+       unsigned int val = snd_hda_codec_read(codec, nid, 0,
+                                             AC_VERB_GET_EAPD_BTLENABLE, 0x00);
+
+       *valp = (val & mask) != 0;
+       return 0;
+}
+
+static int alc_eapd_ctrl_put(struct snd_kcontrol *kcontrol,
+                             struct snd_ctl_elem_value *ucontrol)
+{
+       int change;
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       hda_nid_t nid = kcontrol->private_value & 0xffff;
+       unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
+       long val = *ucontrol->value.integer.value;
+       unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0,
+                                                   AC_VERB_GET_EAPD_BTLENABLE,
+                                                   0x00);
+
+       /* Set/unset the masked control bit(s) as needed */
+       change = (!val ? 0 : mask) != (ctrl_data & mask);
+       if (!val)
+               ctrl_data &= ~mask;
+       else
+               ctrl_data |= mask;
+       snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE,
+                                 ctrl_data);
+
+       return change;
+}
+
+#define ALC_EAPD_CTRL_SWITCH(xname, nid, mask) \
+       { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0,  \
+         .info = alc_eapd_ctrl_info, \
+         .get = alc_eapd_ctrl_get, \
+         .put = alc_eapd_ctrl_put, \
+         .private_value = nid | (mask<<16) }
+#endif   /* CONFIG_SND_DEBUG */
+
 /*
  * set up from the preset table
  */
@@ -739,7 +815,7 @@ static void alc_subsystem_id(struct hda_codec *codec,
        /* check sum */
        tmp = 0;
        for (i = 1; i < 16; i++) {
-               if ((ass >> i) && 1)
+               if ((ass >> i) & 1)
                        tmp++;
        }
        if (((ass >> 16) & 0xf) != tmp)
@@ -828,10 +904,10 @@ do_sku:
                break;
        }
        
-       /* is laptop and enable the function "Mute internal speaker
+       /* is laptop or Desktop and enable the function "Mute internal speaker
         * when the external headphone out jack is plugged"
         */
-       if (!(ass & 0x4) || !(ass & 0x8000))
+       if (!(ass & 0x8000))
                return;
        /*
         * 10~8 : Jack location
@@ -841,9 +917,9 @@ do_sku:
         *              when the external headphone out jack is plugged"
         */
        if (!spec->autocfg.speaker_pins[0]) {
-               if (spec->multiout.dac_nids[0])
+               if (spec->autocfg.line_out_pins[0])
                        spec->autocfg.speaker_pins[0] =
-                               spec->multiout.dac_nids[0];
+                               spec->autocfg.line_out_pins[0];
                else
                        return;
        }
@@ -1009,7 +1085,6 @@ static struct snd_kcontrol_new alc880_capture_mixer[] = {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                /* The multiple "Capture Source" controls confuse alsamixer
                 * So call somewhat different..
-                * FIXME: the controls appear in the "playback" view!
                 */
                /* .name = "Capture Source", */
                .name = "Input Source",
@@ -1031,7 +1106,6 @@ static struct snd_kcontrol_new alc880_capture_alt_mixer[] = {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                /* The multiple "Capture Source" controls confuse alsamixer
                 * So call somewhat different..
-                * FIXME: the controls appear in the "playback" view!
                 */
                /* .name = "Capture Source", */
                .name = "Input Source",
@@ -1226,7 +1300,6 @@ static struct snd_kcontrol_new alc880_z71v_mixer[] = {
 };
 
 
-/* FIXME! */
 /*
  * ALC880 F1734 model
  *
@@ -1242,8 +1315,8 @@ static hda_nid_t alc880_f1734_dac_nids[1] = {
 static struct snd_kcontrol_new alc880_f1734_mixer[] = {
        HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
        HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("Internal Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Internal Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
        HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
        HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
@@ -1252,7 +1325,6 @@ static struct snd_kcontrol_new alc880_f1734_mixer[] = {
 };
 
 
-/* FIXME! */
 /*
  * ALC880 ASUS model
  *
@@ -1289,7 +1361,6 @@ static struct snd_kcontrol_new alc880_asus_mixer[] = {
        { } /* end */
 };
 
-/* FIXME! */
 /*
  * ALC880 ASUS W1V model
  *
@@ -1327,7 +1398,6 @@ static struct snd_kcontrol_new alc880_tcl_s700_mixer[] = {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                /* The multiple "Capture Source" controls confuse alsamixer
                 * So call somewhat different..
-                * FIXME: the controls appear in the "playback" view!
                 */
                /* .name = "Capture Source", */
                .name = "Input Source",
@@ -1341,10 +1411,10 @@ static struct snd_kcontrol_new alc880_tcl_s700_mixer[] = {
 
 /* Uniwill */
 static struct snd_kcontrol_new alc880_uniwill_mixer[] = {
-       HDA_CODEC_VOLUME("HPhone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("HPhone Playback Switch", 0x0c, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("iSpeaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("iSpeaker Playback Switch", 0x0d, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
        HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
        HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
        HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
@@ -1384,15 +1454,48 @@ static struct snd_kcontrol_new alc880_fujitsu_mixer[] = {
 };
 
 static struct snd_kcontrol_new alc880_uniwill_p53_mixer[] = {
-       HDA_CODEC_VOLUME("HPhone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("HPhone Playback Switch", 0x0c, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("iSpeaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("iSpeaker Playback Switch", 0x0d, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
        HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
        { } /* end */
 };
 
+/*
+ * virtual master controls
+ */
+
+/*
+ * slave controls for virtual master
+ */
+static const char *alc_slave_vols[] = {
+       "Front Playback Volume",
+       "Surround Playback Volume",
+       "Center Playback Volume",
+       "LFE Playback Volume",
+       "Side Playback Volume",
+       "Headphone Playback Volume",
+       "Speaker Playback Volume",
+       "Mono Playback Volume",
+       "Line-Out Playback Volume",
+       NULL,
+};
+
+static const char *alc_slave_sws[] = {
+       "Front Playback Switch",
+       "Surround Playback Switch",
+       "Center Playback Switch",
+       "LFE Playback Switch",
+       "Side Playback Switch",
+       "Headphone Playback Switch",
+       "Speaker Playback Switch",
+       "Mono Playback Switch",
+       "IEC958 Playback Switch",
+       NULL,
+};
+
 /*
  * build control elements
  */
@@ -1419,6 +1522,23 @@ static int alc_build_controls(struct hda_codec *codec)
                if (err < 0)
                        return err;
        }
+
+       /* if we have no master control, let's create it */
+       if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
+               snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid,
+                                       HDA_OUTPUT, spec->vmaster_tlv);
+               err = snd_hda_add_vmaster(codec, "Master Playback Volume",
+                                         spec->vmaster_tlv, alc_slave_vols);
+               if (err < 0)
+                       return err;
+       }
+       if (!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
+               err = snd_hda_add_vmaster(codec, "Master Playback Switch",
+                                         NULL, alc_slave_sws);
+               if (err < 0)
+                       return err;
+       }
+
        return 0;
 }
 
@@ -1790,7 +1910,6 @@ static void alc880_uniwill_p53_unsol_event(struct hda_codec *codec,
                alc880_uniwill_p53_dcvol_automute(codec);
 }
 
-/* FIXME! */
 /*
  * F1734 pin configuration:
  * HP = 0x14, speaker-out = 0x15, mic = 0x18
@@ -1819,7 +1938,6 @@ static struct hda_verb alc880_pin_f1734_init_verbs[] = {
        { }
 };
 
-/* FIXME! */
 /*
  * ASUS pin configuration:
  * HP/front = 0x14, surr = 0x15, clfe = 0x16, mic = 0x18, line = 0x1a
@@ -1966,9 +2084,8 @@ static struct hda_channel_mode alc880_lg_ch_modes[3] = {
 };
 
 static struct snd_kcontrol_new alc880_lg_mixer[] = {
-       /* FIXME: it's not really "master" but front channels */
-       HDA_CODEC_VOLUME("Master Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Master Playback Switch", 0x0f, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Front Playback Switch", 0x0f, 2, HDA_INPUT),
        HDA_CODEC_VOLUME("Surround Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
        HDA_BIND_MUTE("Surround Playback Switch", 0x0c, 2, HDA_INPUT),
        HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT),
@@ -2256,7 +2373,7 @@ static int alc880_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
 /*
  * Analog capture
  */
-static int alc880_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
+static int alc880_alt_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
                                      struct hda_codec *codec,
                                      unsigned int stream_tag,
                                      unsigned int format,
@@ -2264,18 +2381,18 @@ static int alc880_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
 {
        struct alc_spec *spec = codec->spec;
 
-       snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
+       snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number + 1],
                                   stream_tag, 0, format);
        return 0;
 }
 
-static int alc880_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
+static int alc880_alt_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
                                      struct hda_codec *codec,
                                      struct snd_pcm_substream *substream)
 {
        struct alc_spec *spec = codec->spec;
 
-       snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
+       snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number + 1],
                                   0, 0, 0);
        return 0;
 }
@@ -2296,13 +2413,27 @@ static struct hda_pcm_stream alc880_pcm_analog_playback = {
 };
 
 static struct hda_pcm_stream alc880_pcm_analog_capture = {
-       .substreams = 2,
+       .substreams = 1,
+       .channels_min = 2,
+       .channels_max = 2,
+       /* NID is set in alc_build_pcms */
+};
+
+static struct hda_pcm_stream alc880_pcm_analog_alt_playback = {
+       .substreams = 1,
+       .channels_min = 2,
+       .channels_max = 2,
+       /* NID is set in alc_build_pcms */
+};
+
+static struct hda_pcm_stream alc880_pcm_analog_alt_capture = {
+       .substreams = 2, /* can be overridden */
        .channels_min = 2,
        .channels_max = 2,
        /* NID is set in alc_build_pcms */
        .ops = {
-               .prepare = alc880_capture_pcm_prepare,
-               .cleanup = alc880_capture_pcm_cleanup
+               .prepare = alc880_alt_capture_pcm_prepare,
+               .cleanup = alc880_alt_capture_pcm_cleanup
        },
 };
 
@@ -2326,7 +2457,7 @@ static struct hda_pcm_stream alc880_pcm_digital_capture = {
 };
 
 /* Used by alc_build_pcms to flag that a PCM has no playback stream */
-static struct hda_pcm_stream alc_pcm_null_playback = {
+static struct hda_pcm_stream alc_pcm_null_stream = {
        .substreams = 0,
        .channels_min = 0,
        .channels_max = 0,
@@ -2383,17 +2514,32 @@ static int alc_build_pcms(struct hda_codec *codec)
         * model, configure a second analog capture-only PCM.
         */
        /* Additional Analaog capture for index #2 */
-       if (spec->num_adc_nids > 1 && spec->stream_analog_capture &&
-           spec->adc_nids) {
+       if ((spec->alt_dac_nid && spec->stream_analog_alt_playback) ||
+           (spec->num_adc_nids > 1 && spec->stream_analog_alt_capture)) {
                codec->num_pcms = 3;
                info = spec->pcm_rec + 2;
                info->name = spec->stream_name_analog;
-               /* No playback stream for second PCM */
-               info->stream[SNDRV_PCM_STREAM_PLAYBACK] = alc_pcm_null_playback;
-               info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0;
-               if (spec->stream_analog_capture) {
-                       info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture);
-                       info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[1];
+               if (spec->alt_dac_nid) {
+                       info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
+                               *spec->stream_analog_alt_playback;
+                       info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
+                               spec->alt_dac_nid;
+               } else {
+                       info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
+                               alc_pcm_null_stream;
+                       info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0;
+               }
+               if (spec->num_adc_nids > 1) {
+                       info->stream[SNDRV_PCM_STREAM_CAPTURE] =
+                               *spec->stream_analog_alt_capture;
+                       info->stream[SNDRV_PCM_STREAM_CAPTURE].nid =
+                               spec->adc_nids[1];
+                       info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams =
+                               spec->num_adc_nids - 1;
+               } else {
+                       info->stream[SNDRV_PCM_STREAM_CAPTURE] =
+                               alc_pcm_null_stream;
+                       info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = 0;
                }
        }
 
@@ -2723,23 +2869,17 @@ static const char *alc880_models[ALC880_MODEL_LAST] = {
 };
 
 static struct snd_pci_quirk alc880_cfg_tbl[] = {
-       /* Broken BIOS configuration */
-       SND_PCI_QUIRK(0x2668, 0x8086, NULL, ALC880_6ST_DIG),
-       SND_PCI_QUIRK(0x8086, 0x2668, NULL, ALC880_6ST_DIG),
-
+       SND_PCI_QUIRK(0x1019, 0x0f69, "Coeus G610P", ALC880_W810),
        SND_PCI_QUIRK(0x1019, 0xa880, "ECS", ALC880_5ST_DIG),
        SND_PCI_QUIRK(0x1019, 0xa884, "Acer APFV", ALC880_6ST),
-       SND_PCI_QUIRK(0x1019, 0x0f69, "Coeus G610P", ALC880_W810),
        SND_PCI_QUIRK(0x1025, 0x0070, "ULI", ALC880_3ST_DIG),
        SND_PCI_QUIRK(0x1025, 0x0077, "ULI", ALC880_6ST_DIG),
        SND_PCI_QUIRK(0x1025, 0x0078, "ULI", ALC880_6ST_DIG),
        SND_PCI_QUIRK(0x1025, 0x0087, "ULI", ALC880_6ST_DIG),
        SND_PCI_QUIRK(0x1025, 0xe309, "ULI", ALC880_3ST_DIG),
        SND_PCI_QUIRK(0x1025, 0xe310, "ULI", ALC880_3ST),
-
        SND_PCI_QUIRK(0x1039, 0x1234, NULL, ALC880_6ST_DIG),
        SND_PCI_QUIRK(0x103c, 0x2a09, "HP", ALC880_5ST),
-
        SND_PCI_QUIRK(0x1043, 0x10b3, "ASUS W1V", ALC880_ASUS_W1V),
        SND_PCI_QUIRK(0x1043, 0x10c2, "ASUS W6A", ALC880_ASUS_DIG),
        SND_PCI_QUIRK(0x1043, 0x10c3, "ASUS Wxx", ALC880_ASUS_DIG),
@@ -2754,54 +2894,50 @@ static struct snd_pci_quirk alc880_cfg_tbl[] = {
        SND_PCI_QUIRK(0x1043, 0x8181, "ASUS P4GPL", ALC880_ASUS_DIG),
        SND_PCI_QUIRK(0x1043, 0x8196, "ASUS P5GD1", ALC880_6ST),
        SND_PCI_QUIRK(0x1043, 0x81b4, "ASUS", ALC880_6ST),
-       SND_PCI_QUIRK(0x1043, 0, "ASUS", ALC880_ASUS),
-
-       SND_PCI_QUIRK(0x104d, 0x81d6, "Sony", ALC880_3ST),
+       SND_PCI_QUIRK(0x1043, 0, "ASUS", ALC880_ASUS), /* default ASUS */
        SND_PCI_QUIRK(0x104d, 0x81a0, "Sony", ALC880_3ST),
+       SND_PCI_QUIRK(0x104d, 0x81d6, "Sony", ALC880_3ST),
+       SND_PCI_QUIRK(0x107b, 0x3032, "Gateway", ALC880_5ST),
        SND_PCI_QUIRK(0x107b, 0x3033, "Gateway", ALC880_5ST),
        SND_PCI_QUIRK(0x107b, 0x4039, "Gateway", ALC880_5ST),
-       SND_PCI_QUIRK(0x107b, 0x3032, "Gateway", ALC880_5ST),
-       SND_PCI_QUIRK(0x1558, 0x0520, "Clevo m520G", ALC880_CLEVO),
-       SND_PCI_QUIRK(0x1558, 0x0660, "Clevo m655n", ALC880_CLEVO),
-       SND_PCI_QUIRK(0x1565, 0x8202, "Biostar", ALC880_5ST_DIG),
-       SND_PCI_QUIRK(0x161f, 0x203d, "W810", ALC880_W810),
-       SND_PCI_QUIRK(0x1695, 0x400d, "EPoX", ALC880_5ST_DIG),
-       SND_PCI_QUIRK(0x19db, 0x4188, "TCL S700", ALC880_TCL_S700),
-       SND_PCI_QUIRK(0xa0a0, 0x0560, "AOpen i915GMm-HFS", ALC880_5ST_DIG),
-       SND_PCI_QUIRK(0xe803, 0x1019, NULL, ALC880_6ST_DIG),
        SND_PCI_QUIRK(0x1297, 0xc790, "Shuttle ST20G5", ALC880_6ST_DIG),
        SND_PCI_QUIRK(0x1458, 0xa102, "Gigabyte K8", ALC880_6ST_DIG),
        SND_PCI_QUIRK(0x1462, 0x1150, "MSI", ALC880_6ST_DIG),
        SND_PCI_QUIRK(0x1509, 0x925d, "FIC P4M", ALC880_6ST_DIG),
+       SND_PCI_QUIRK(0x1558, 0x0520, "Clevo m520G", ALC880_CLEVO),
+       SND_PCI_QUIRK(0x1558, 0x0660, "Clevo m655n", ALC880_CLEVO),
        SND_PCI_QUIRK(0x1558, 0x5401, "ASUS", ALC880_ASUS_DIG2),
-
+       SND_PCI_QUIRK(0x1565, 0x8202, "Biostar", ALC880_5ST_DIG),
        SND_PCI_QUIRK(0x1584, 0x9050, "Uniwill", ALC880_UNIWILL_DIG),
+       SND_PCI_QUIRK(0x1584, 0x9054, "Uniwlll", ALC880_F1734),
        SND_PCI_QUIRK(0x1584, 0x9070, "Uniwill", ALC880_UNIWILL),
        SND_PCI_QUIRK(0x1584, 0x9077, "Uniwill P53", ALC880_UNIWILL_P53),
-       SND_PCI_QUIRK(0x1584, 0x9054, "Uniwlll", ALC880_F1734),
-
+       SND_PCI_QUIRK(0x161f, 0x203d, "W810", ALC880_W810),
+       SND_PCI_QUIRK(0x1695, 0x400d, "EPoX", ALC880_5ST_DIG),
        SND_PCI_QUIRK(0x1695, 0x4012, "EPox EP-5LDA", ALC880_5ST_DIG),
-       SND_PCI_QUIRK(0x1734, 0x10ac, "FSC", ALC880_UNIWILL),
        SND_PCI_QUIRK(0x1734, 0x107c, "FSC F1734", ALC880_F1734),
+       SND_PCI_QUIRK(0x1734, 0x10ac, "FSC", ALC880_UNIWILL),
        SND_PCI_QUIRK(0x1734, 0x10b0, "Fujitsu", ALC880_FUJITSU),
-
+       SND_PCI_QUIRK(0x1854, 0x0018, "LG LW20", ALC880_LG_LW),
        SND_PCI_QUIRK(0x1854, 0x003b, "LG", ALC880_LG),
        SND_PCI_QUIRK(0x1854, 0x0068, "LG w1", ALC880_LG),
-       SND_PCI_QUIRK(0x1854, 0x0018, "LG LW20", ALC880_LG_LW),
        SND_PCI_QUIRK(0x1854, 0x0077, "LG LW25", ALC880_LG_LW),
-
-       SND_PCI_QUIRK(0x8086, 0xe308, "Intel mobo", ALC880_3ST_DIG),
-       SND_PCI_QUIRK(0x8086, 0xe305, "Intel mobo", ALC880_3ST_DIG),
-       SND_PCI_QUIRK(0x8086, 0xd402, "Intel mobo", ALC880_3ST_DIG),
+       SND_PCI_QUIRK(0x19db, 0x4188, "TCL S700", ALC880_TCL_S700),
+       SND_PCI_QUIRK(0x2668, 0x8086, NULL, ALC880_6ST_DIG), /* broken BIOS */
+       SND_PCI_QUIRK(0x8086, 0x2668, NULL, ALC880_6ST_DIG),
+       SND_PCI_QUIRK(0x8086, 0xa100, "Intel mobo", ALC880_5ST_DIG),
        SND_PCI_QUIRK(0x8086, 0xd400, "Intel mobo", ALC880_5ST_DIG),
        SND_PCI_QUIRK(0x8086, 0xd401, "Intel mobo", ALC880_5ST_DIG),
+       SND_PCI_QUIRK(0x8086, 0xd402, "Intel mobo", ALC880_3ST_DIG),
        SND_PCI_QUIRK(0x8086, 0xe224, "Intel mobo", ALC880_5ST_DIG),
+       SND_PCI_QUIRK(0x8086, 0xe305, "Intel mobo", ALC880_3ST_DIG),
+       SND_PCI_QUIRK(0x8086, 0xe308, "Intel mobo", ALC880_3ST_DIG),
        SND_PCI_QUIRK(0x8086, 0xe400, "Intel mobo", ALC880_5ST_DIG),
        SND_PCI_QUIRK(0x8086, 0xe401, "Intel mobo", ALC880_5ST_DIG),
        SND_PCI_QUIRK(0x8086, 0xe402, "Intel mobo", ALC880_5ST_DIG),
-       SND_PCI_QUIRK(0x8086, 0xa100, "Intel mobo", ALC880_5ST_DIG),
-       SND_PCI_QUIRK(0x8086, 0, "Intel mobo", ALC880_3ST),
-
+       SND_PCI_QUIRK(0x8086, 0, "Intel mobo", ALC880_3ST), /* default Intel */
+       SND_PCI_QUIRK(0xa0a0, 0x0560, "AOpen i915GMm-HFS", ALC880_5ST_DIG),
+       SND_PCI_QUIRK(0xe803, 0x1019, NULL, ALC880_6ST_DIG),
        {}
 };
 
@@ -3511,6 +3647,7 @@ static int patch_alc880(struct hda_codec *codec)
        spec->stream_name_analog = "ALC880 Analog";
        spec->stream_analog_playback = &alc880_pcm_analog_playback;
        spec->stream_analog_capture = &alc880_pcm_analog_capture;
+       spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture;
 
        spec->stream_name_digital = "ALC880 Digital";
        spec->stream_digital_playback = &alc880_pcm_digital_playback;
@@ -3535,6 +3672,8 @@ static int patch_alc880(struct hda_codec *codec)
                }
        }
 
+       spec->vmaster_nid = 0x0c;
+
        codec->patch_ops = alc_patch_ops;
        if (board_config == ALC880_AUTO)
                spec->init_hook = alc880_auto_init;
@@ -3691,18 +3830,135 @@ static struct snd_kcontrol_new alc260_pc_beep_mixer[] = {
        { } /* end */
 };
 
+/* update HP, line and mono out pins according to the master switch */
+static void alc260_hp_master_update(struct hda_codec *codec,
+                                   hda_nid_t hp, hda_nid_t line,
+                                   hda_nid_t mono)
+{
+       struct alc_spec *spec = codec->spec;
+       unsigned int val = spec->master_sw ? PIN_HP : 0;
+       /* change HP and line-out pins */
+       snd_hda_codec_write(codec, 0x0f, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
+                           val);
+       snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
+                           val);
+       /* mono (speaker) depending on the HP jack sense */
+       val = (val && !spec->jack_present) ? PIN_OUT : 0;
+       snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
+                           val);
+}
+
+static int alc260_hp_master_sw_get(struct snd_kcontrol *kcontrol,
+                                  struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct alc_spec *spec = codec->spec;
+       *ucontrol->value.integer.value = spec->master_sw;
+       return 0;
+}
+
+static int alc260_hp_master_sw_put(struct snd_kcontrol *kcontrol,
+                                  struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct alc_spec *spec = codec->spec;
+       int val = !!*ucontrol->value.integer.value;
+       hda_nid_t hp, line, mono;
+
+       if (val == spec->master_sw)
+               return 0;
+       spec->master_sw = val;
+       hp = (kcontrol->private_value >> 16) & 0xff;
+       line = (kcontrol->private_value >> 8) & 0xff;
+       mono = kcontrol->private_value & 0xff;
+       alc260_hp_master_update(codec, hp, line, mono);
+       return 1;
+}
+
+static struct snd_kcontrol_new alc260_hp_output_mixer[] = {
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Master Playback Switch",
+               .info = snd_ctl_boolean_mono_info,
+               .get = alc260_hp_master_sw_get,
+               .put = alc260_hp_master_sw_put,
+               .private_value = (0x0f << 16) | (0x10 << 8) | 0x11
+       },
+       HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0,
+                             HDA_OUTPUT),
+       HDA_BIND_MUTE_MONO("Speaker Playback Switch", 0x0a, 1, 2, HDA_INPUT),
+       { } /* end */
+};
+
+static struct hda_verb alc260_hp_unsol_verbs[] = {
+       {0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
+       {},
+};
+
+static void alc260_hp_automute(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       unsigned int present;
+
+       present = snd_hda_codec_read(codec, 0x10, 0,
+                                    AC_VERB_GET_PIN_SENSE, 0);
+       spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0;
+       alc260_hp_master_update(codec, 0x0f, 0x10, 0x11);
+}
+
+static void alc260_hp_unsol_event(struct hda_codec *codec, unsigned int res)
+{
+       if ((res >> 26) == ALC880_HP_EVENT)
+               alc260_hp_automute(codec);
+}
+
 static struct snd_kcontrol_new alc260_hp_3013_mixer[] = {
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Master Playback Switch",
+               .info = snd_ctl_boolean_mono_info,
+               .get = alc260_hp_master_sw_get,
+               .put = alc260_hp_master_sw_put,
+               .private_value = (0x10 << 16) | (0x15 << 8) | 0x11
+       },
        HDA_CODEC_VOLUME("Front Playback Volume", 0x09, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE("Front Playback Switch", 0x10, 0x0, HDA_OUTPUT),
        HDA_CODEC_VOLUME("Aux-In Playback Volume", 0x07, 0x06, HDA_INPUT),
        HDA_CODEC_MUTE("Aux-In Playback Switch", 0x07, 0x06, HDA_INPUT),
        HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_MONO("iSpeaker Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_MONO("iSpeaker Playback Switch", 0x11, 1, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x11, 1, 0x0, HDA_OUTPUT),
        { } /* end */
 };
 
+static struct hda_verb alc260_hp_3013_unsol_verbs[] = {
+       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
+       {},
+};
+
+static void alc260_hp_3013_automute(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       unsigned int present;
+
+       present = snd_hda_codec_read(codec, 0x15, 0,
+                                    AC_VERB_GET_PIN_SENSE, 0);
+       spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0;
+       alc260_hp_master_update(codec, 0x10, 0x15, 0x11);
+}
+
+static void alc260_hp_3013_unsol_event(struct hda_codec *codec,
+                                      unsigned int res)
+{
+       if ((res >> 26) == ALC880_HP_EVENT)
+               alc260_hp_3013_automute(codec);
+}
+
 /* Fujitsu S702x series laptops.  ALC260 pin usage: Mic/Line jack = 0x12, 
  * HP jack = 0x14, CD audio =  0x16, internal speaker = 0x10.
  */
@@ -3812,7 +4068,6 @@ static struct snd_kcontrol_new alc260_capture_mixer[] = {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                /* The multiple "Capture Source" controls confuse alsamixer
                 * So call somewhat different..
-                * FIXME: the controls appear in the "playback" view!
                 */
                /* .name = "Capture Source", */
                .name = "Input Source",
@@ -3831,7 +4086,6 @@ static struct snd_kcontrol_new alc260_capture_alt_mixer[] = {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                /* The multiple "Capture Source" controls confuse alsamixer
                 * So call somewhat different..
-                * FIXME: the controls appear in the "playback" view!
                 */
                /* .name = "Capture Source", */
                .name = "Input Source",
@@ -4332,6 +4586,12 @@ static struct snd_kcontrol_new alc260_test_mixer[] = {
        ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x03, 0x01),
        ALC_SPDIF_CTRL_SWITCH("SPDIF Capture Switch", 0x06, 0x01),
 
+       /* A switch allowing EAPD to be enabled.  Some laptops seem to use
+        * this output to turn on an external amplifier.
+        */
+       ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02),
+       ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02),
+
        { } /* end */
 };
 static struct hda_verb alc260_test_init_verbs[] = {
@@ -4417,17 +4677,8 @@ static struct hda_verb alc260_test_init_verbs[] = {
 };
 #endif
 
-static struct hda_pcm_stream alc260_pcm_analog_playback = {
-       .substreams = 1,
-       .channels_min = 2,
-       .channels_max = 2,
-};
-
-static struct hda_pcm_stream alc260_pcm_analog_capture = {
-       .substreams = 1,
-       .channels_min = 2,
-       .channels_max = 2,
-};
+#define alc260_pcm_analog_playback     alc880_pcm_analog_alt_playback
+#define alc260_pcm_analog_capture      alc880_pcm_analog_capture
 
 #define alc260_pcm_digital_playback    alc880_pcm_digital_playback
 #define alc260_pcm_digital_capture     alc880_pcm_digital_capture
@@ -4744,8 +4995,8 @@ static struct snd_pci_quirk alc260_cfg_tbl[] = {
        SND_PCI_QUIRK(0x104d, 0x81cd, "Sony VAIO", ALC260_BASIC),
        SND_PCI_QUIRK(0x10cf, 0x1326, "Fujitsu S702X", ALC260_FUJITSU_S702X),
        SND_PCI_QUIRK(0x152d, 0x0729, "CTL U553W", ALC260_BASIC),
-       SND_PCI_QUIRK(0x1631, 0xc017, "PB V7900", ALC260_WILL),
        SND_PCI_QUIRK(0x161f, 0x2057, "Replacer 672V", ALC260_REPLACER_672V),
+       SND_PCI_QUIRK(0x1631, 0xc017, "PB V7900", ALC260_WILL),
        {}
 };
 
@@ -4765,10 +5016,11 @@ static struct alc_config_preset alc260_presets[] = {
                .input_mux = &alc260_capture_source,
        },
        [ALC260_HP] = {
-               .mixers = { alc260_base_output_mixer,
+               .mixers = { alc260_hp_output_mixer,
                            alc260_input_mixer,
                            alc260_capture_alt_mixer },
-               .init_verbs = { alc260_init_verbs },
+               .init_verbs = { alc260_init_verbs,
+                               alc260_hp_unsol_verbs },
                .num_dacs = ARRAY_SIZE(alc260_dac_nids),
                .dac_nids = alc260_dac_nids,
                .num_adc_nids = ARRAY_SIZE(alc260_hp_adc_nids),
@@ -4776,12 +5028,15 @@ static struct alc_config_preset alc260_presets[] = {
                .num_channel_mode = ARRAY_SIZE(alc260_modes),
                .channel_mode = alc260_modes,
                .input_mux = &alc260_capture_source,
+               .unsol_event = alc260_hp_unsol_event,
+               .init_hook = alc260_hp_automute,
        },
        [ALC260_HP_3013] = {
                .mixers = { alc260_hp_3013_mixer,
                            alc260_input_mixer,
                            alc260_capture_alt_mixer },
-               .init_verbs = { alc260_hp_3013_init_verbs },
+               .init_verbs = { alc260_hp_3013_init_verbs,
+                               alc260_hp_3013_unsol_verbs },
                .num_dacs = ARRAY_SIZE(alc260_dac_nids),
                .dac_nids = alc260_dac_nids,
                .num_adc_nids = ARRAY_SIZE(alc260_hp_adc_nids),
@@ -4789,6 +5044,8 @@ static struct alc_config_preset alc260_presets[] = {
                .num_channel_mode = ARRAY_SIZE(alc260_modes),
                .channel_mode = alc260_modes,
                .input_mux = &alc260_capture_source,
+               .unsol_event = alc260_hp_3013_unsol_event,
+               .init_hook = alc260_hp_3013_automute,
        },
        [ALC260_FUJITSU_S702X] = {
                .mixers = { alc260_fujitsu_mixer,
@@ -4906,6 +5163,8 @@ static int patch_alc260(struct hda_codec *codec)
        spec->stream_digital_playback = &alc260_pcm_digital_playback;
        spec->stream_digital_capture = &alc260_pcm_digital_capture;
 
+       spec->vmaster_nid = 0x08;
+
        codec->patch_ops = alc_patch_ops;
        if (board_config == ALC260_AUTO)
                spec->init_hook = alc260_auto_init;
@@ -5106,15 +5365,15 @@ static struct snd_kcontrol_new alc882_base_mixer[] = {
 };
 
 static struct snd_kcontrol_new alc885_mbp3_mixer[] = {
-       HDA_CODEC_VOLUME("Master Volume", 0x0c, 0x00, HDA_OUTPUT),
-       HDA_BIND_MUTE   ("Master Switch", 0x0c, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE  ("Speaker Switch", 0x14, 0x00, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Line Out Volume", 0x0d,0x00, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Line In Playback Volume", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE  ("Line In Playback Switch", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
+       HDA_BIND_MUTE   ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
+       HDA_CODEC_MUTE  ("Speaker Playback Switch", 0x14, 0x00, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Line-Out Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_MUTE  ("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT),
        HDA_CODEC_MUTE  ("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0x00, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line Boost", 0x1a, 0x00, HDA_INPUT),
        HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x00, HDA_INPUT),
        { } /* end */
 };
@@ -5679,7 +5938,6 @@ static struct snd_kcontrol_new alc882_capture_alt_mixer[] = {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                /* The multiple "Capture Source" controls confuse alsamixer
                 * So call somewhat different..
-                * FIXME: the controls appear in the "playback" view!
                 */
                /* .name = "Capture Source", */
                .name = "Input Source",
@@ -5702,7 +5960,6 @@ static struct snd_kcontrol_new alc882_capture_mixer[] = {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                /* The multiple "Capture Source" controls confuse alsamixer
                 * So call somewhat different..
-                * FIXME: the controls appear in the "playback" view!
                 */
                /* .name = "Capture Source", */
                .name = "Input Source",
@@ -5743,16 +6000,17 @@ static const char *alc882_models[ALC882_MODEL_LAST] = {
 
 static struct snd_pci_quirk alc882_cfg_tbl[] = {
        SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC882_6ST_DIG),
-       SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC882_6ST_DIG),
-       SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC882_6ST_DIG),
-       SND_PCI_QUIRK(0x1462, 0x28fb, "Targa T8", ALC882_TARGA), /* MSI-1049 T8  */
-       SND_PCI_QUIRK(0x161f, 0x2054, "Arima W820", ALC882_ARIMA),
        SND_PCI_QUIRK(0x1043, 0x060d, "Asus A7J", ALC882_ASUS_A7J),
        SND_PCI_QUIRK(0x1043, 0x1243, "Asus A7J", ALC882_ASUS_A7J),
        SND_PCI_QUIRK(0x1043, 0x13c2, "Asus A7M", ALC882_ASUS_A7M),
+       SND_PCI_QUIRK(0x1043, 0x1971, "Asus W2JC", ALC882_W2JC),
        SND_PCI_QUIRK(0x1043, 0x817f, "Asus P5LD2", ALC882_6ST_DIG),
        SND_PCI_QUIRK(0x1043, 0x81d8, "Asus P5WD", ALC882_6ST_DIG),
-       SND_PCI_QUIRK(0x1043, 0x1971, "Asus W2JC", ALC882_W2JC),
+       SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC882_6ST_DIG),
+       SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte P35 DS3R", ALC882_6ST_DIG),
+       SND_PCI_QUIRK(0x1462, 0x28fb, "Targa T8", ALC882_TARGA), /* MSI-1049 T8  */
+       SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC882_6ST_DIG),
+       SND_PCI_QUIRK(0x161f, 0x2054, "Arima W820", ALC882_ARIMA),
        {}
 };
 
@@ -5990,7 +6248,7 @@ static int alc_auto_add_mic_boost(struct hda_codec *codec)
        hda_nid_t nid;
 
        nid = spec->autocfg.input_pins[AUTO_PIN_MIC];
-       if (nid) {
+       if (nid && (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) {
                err = add_control(spec, ALC_CTL_WIDGET_VOL,
                                  "Mic Boost",
                                  HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
@@ -5998,7 +6256,7 @@ static int alc_auto_add_mic_boost(struct hda_codec *codec)
                        return err;
        }
        nid = spec->autocfg.input_pins[AUTO_PIN_FRONT_MIC];
-       if (nid) {
+       if (nid && (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) {
                err = add_control(spec, ALC_CTL_WIDGET_VOL,
                                  "Front Mic Boost",
                                  HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
@@ -6061,6 +6319,7 @@ static int patch_alc882(struct hda_codec *codec)
                case 0x106b1000: /* iMac 24 */
                        board_config = ALC885_IMAC24;
                        break;
+               case 0x106b00a1: /* Macbook */
                case 0x106b2c00: /* Macbook Pro rev3 */
                        board_config = ALC885_MBP3;
                        break;
@@ -6093,6 +6352,9 @@ static int patch_alc882(struct hda_codec *codec)
        spec->stream_name_analog = "ALC882 Analog";
        spec->stream_analog_playback = &alc882_pcm_analog_playback;
        spec->stream_analog_capture = &alc882_pcm_analog_capture;
+       /* FIXME: setup DAC5 */
+       /*spec->stream_analog_alt_playback = &alc880_pcm_analog_alt_playback;*/
+       spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture;
 
        spec->stream_name_digital = "ALC882 Digital";
        spec->stream_digital_playback = &alc882_pcm_digital_playback;
@@ -6117,6 +6379,8 @@ static int patch_alc882(struct hda_codec *codec)
                }
        }
 
+       spec->vmaster_nid = 0x0c;
+
        codec->patch_ops = alc_patch_ops;
        if (board_config == ALC882_AUTO)
                spec->init_hook = alc882_auto_init;
@@ -6340,6 +6604,36 @@ static struct snd_kcontrol_new alc883_base_mixer[] = {
        { } /* end */
 };
 
+static struct snd_kcontrol_new alc883_mitac_mixer[] = {
+       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
+       HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
+       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               /* .name = "Capture Source", */
+               .name = "Input Source",
+               .count = 2,
+               .info = alc883_mux_enum_info,
+               .get = alc883_mux_enum_get,
+               .put = alc883_mux_enum_put,
+       },
+       { } /* end */
+};
+
 static struct snd_kcontrol_new alc883_3ST_2ch_mixer[] = {
        HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
        HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
@@ -6508,8 +6802,8 @@ static struct snd_kcontrol_new alc883_tagra_2ch_mixer[] = {
 static struct snd_kcontrol_new alc883_lenovo_101e_2ch_mixer[] = {
        HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
        HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("iSpeaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("iSpeaker Playback Switch", 0x0d, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
        HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
        HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
@@ -6658,10 +6952,50 @@ static struct snd_kcontrol_new alc888_3st_hp_mixer[] = {
        { } /* end */
 };
 
-static struct snd_kcontrol_new alc883_acer_aspire_mixer[] = {
+static struct snd_kcontrol_new alc888_6st_dell_mixer[] = {
        HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
        HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Surround Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Surround Playback Switch", 0x0e, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
+       HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
+       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
+       HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
+       HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               /* .name = "Capture Source", */
+               .name = "Input Source",
+               .count = 2,
+               .info = alc883_mux_enum_info,
+               .get = alc883_mux_enum_get,
+               .put = alc883_mux_enum_put,
+       },
+       { } /* end */
+};
+
+static struct snd_kcontrol_new alc883_acer_aspire_mixer[] = {
+       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
        HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
        HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
@@ -6772,6 +7106,67 @@ static struct hda_verb alc883_init_verbs[] = {
        { }
 };
 
+/* toggle speaker-output according to the hp-jack state */
+static void alc883_mitac_hp_automute(struct hda_codec *codec)
+{
+       unsigned int present;
+
+       present = snd_hda_codec_read(codec, 0x15, 0,
+                                    AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+       snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
+                                HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
+       snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0,
+                                HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
+}
+
+/* auto-toggle front mic */
+/*
+static void alc883_mitac_mic_automute(struct hda_codec *codec)
+{
+       unsigned int present;
+       unsigned char bits;
+
+       present = snd_hda_codec_read(codec, 0x18, 0,
+                                    AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+       bits = present ? HDA_AMP_MUTE : 0;
+       snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits);
+}
+*/
+
+static void alc883_mitac_automute(struct hda_codec *codec)
+{
+       alc883_mitac_hp_automute(codec);
+       /* alc883_mitac_mic_automute(codec); */
+}
+
+static void alc883_mitac_unsol_event(struct hda_codec *codec,
+                                          unsigned int res)
+{
+       switch (res >> 26) {
+       case ALC880_HP_EVENT:
+               alc883_mitac_hp_automute(codec);
+               break;
+       case ALC880_MIC_EVENT:
+               /* alc883_mitac_mic_automute(codec); */
+               break;
+       }
+}
+
+static struct hda_verb alc883_mitac_verbs[] = {
+       /* HP */
+       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       /* Subwoofer */
+       {0x17, AC_VERB_SET_CONNECT_SEL, 0x02},
+       {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+
+       /* enable unsolicited event */
+       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
+       /* {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN}, */
+
+       { } /* end */
+};
+
 static struct hda_verb alc883_tagra_verbs[] = {
        {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
        {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
@@ -6843,6 +7238,15 @@ static struct hda_verb alc888_3st_hp_verbs[] = {
        { }
 };
 
+static struct hda_verb alc888_6st_dell_verbs[] = {
+       {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},  /* Front: output 0 (0x0c) */
+       {0x15, AC_VERB_SET_CONNECT_SEL, 0x02},  /* Rear : output 1 (0x0e) */
+       {0x16, AC_VERB_SET_CONNECT_SEL, 0x01},  /* CLFE : output 2 (0x0d) */
+       {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},  /* Side : output 3 (0x0f) */
+       {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
+       { }
+};
+
 static struct hda_verb alc888_3st_hp_2ch_init[] = {
        { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
        { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
@@ -7038,6 +7442,33 @@ static struct hda_verb alc883_acer_eapd_verbs[] = {
        { }
 };
 
+static void alc888_6st_dell_front_automute(struct hda_codec *codec)
+{
+       unsigned int present;
+       present = snd_hda_codec_read(codec, 0x1b, 0,
+                               AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+       snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
+                               HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
+       snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
+                               HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
+       snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
+                               HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
+       snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0,
+                               HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
+}
+
+static void alc888_6st_dell_unsol_event(struct hda_codec *codec,
+                                            unsigned int res)
+{
+       switch (res >> 26) {
+       case ALC880_HP_EVENT:
+               printk("hp_event\n");
+               alc888_6st_dell_front_automute(codec);
+               break;
+       }
+}
+
 /*
  * generic initialization of ADC, input mixers and output mixers
  */
@@ -7096,7 +7527,7 @@ static struct hda_verb alc883_auto_init_verbs[] = {
        {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
        {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
        /* {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, */
-       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
 
        { }
 };
@@ -7111,7 +7542,6 @@ static struct snd_kcontrol_new alc883_capture_mixer[] = {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                /* The multiple "Capture Source" controls confuse alsamixer
                 * So call somewhat different..
-                * FIXME: the controls appear in the "playback" view!
                 */
                /* .name = "Capture Source", */
                .name = "Input Source",
@@ -7130,6 +7560,7 @@ static struct snd_kcontrol_new alc883_capture_mixer[] = {
 /* pcm configuration: identiacal with ALC880 */
 #define alc883_pcm_analog_playback     alc880_pcm_analog_playback
 #define alc883_pcm_analog_capture      alc880_pcm_analog_capture
+#define alc883_pcm_analog_alt_capture  alc880_pcm_analog_alt_capture
 #define alc883_pcm_digital_playback    alc880_pcm_digital_playback
 #define alc883_pcm_digital_capture     alc880_pcm_digital_capture
 
@@ -7154,53 +7585,58 @@ static const char *alc883_models[ALC883_MODEL_LAST] = {
        [ALC883_HAIER_W66]      = "haier-w66",
        [ALC888_6ST_HP]         = "6stack-hp",
        [ALC888_3ST_HP]         = "3stack-hp",
+       [ALC888_6ST_DELL]       = "6stack-dell",
+       [ALC883_MITAC]          = "mitac",
        [ALC883_AUTO]           = "auto",
 };
 
 static struct snd_pci_quirk alc883_cfg_tbl[] = {
        SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC883_3ST_6ch_DIG),
+       SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_ACER_ASPIRE),
+       SND_PCI_QUIRK(0x1025, 0x0110, "Acer Aspire", ALC883_ACER_ASPIRE),
+       SND_PCI_QUIRK(0x1025, 0x0112, "Acer Aspire 9303", ALC883_ACER_ASPIRE),
+       SND_PCI_QUIRK(0x1025, 0, "Acer laptop", ALC883_ACER), /* default Acer */
+       SND_PCI_QUIRK(0x1028, 0x020d, "Dell Inspiron 530", ALC888_6ST_DELL),
        SND_PCI_QUIRK(0x103c, 0x2a3d, "HP Pavillion", ALC883_6ST_DIG),
-       SND_PCI_QUIRK(0x108e, 0x534d, NULL, ALC883_3ST_6ch),
-       SND_PCI_QUIRK(0x1558, 0, "Clevo laptop", ALC883_LAPTOP_EAPD),
+       SND_PCI_QUIRK(0x103c, 0x2a4f, "HP Samba", ALC888_3ST_HP),
+       SND_PCI_QUIRK(0x103c, 0x2a60, "HP Lucknow", ALC888_3ST_HP),
+       SND_PCI_QUIRK(0x103c, 0x2a61, "HP Nettle", ALC888_6ST_HP),
+       SND_PCI_QUIRK(0x1043, 0x8249, "Asus M2A-VM HDMI", ALC883_3ST_6ch_DIG),
        SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC883_6ST_DIG),
+       SND_PCI_QUIRK(0x1071, 0x8253, "Mitac 8252d", ALC883_MITAC),
+       SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC883_LAPTOP_EAPD),
+       SND_PCI_QUIRK(0x108e, 0x534d, NULL, ALC883_3ST_6ch),
        SND_PCI_QUIRK(0x1458, 0xa002, "MSI", ALC883_6ST_DIG),
-       SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC883_6ST_DIG),
-       SND_PCI_QUIRK(0x1462, 0x7187, "MSI", ALC883_6ST_DIG),
-       SND_PCI_QUIRK(0x1462, 0x7250, "MSI", ALC883_6ST_DIG),
-       SND_PCI_QUIRK(0x1462, 0x7280, "MSI", ALC883_6ST_DIG),
-       SND_PCI_QUIRK(0x1462, 0x7327, "MSI", ALC883_6ST_DIG),
        SND_PCI_QUIRK(0x1462, 0x0349, "MSI", ALC883_TARGA_2ch_DIG),
+       SND_PCI_QUIRK(0x1462, 0x040d, "MSI", ALC883_TARGA_2ch_DIG),
        SND_PCI_QUIRK(0x1462, 0x0579, "MSI", ALC883_TARGA_2ch_DIG),
        SND_PCI_QUIRK(0x1462, 0x3729, "MSI S420", ALC883_TARGA_DIG),
-       SND_PCI_QUIRK(0x1462, 0x3ef9, "MSI", ALC883_TARGA_DIG),
        SND_PCI_QUIRK(0x1462, 0x3b7f, "MSI", ALC883_TARGA_2ch_DIG),
-       SND_PCI_QUIRK(0x1462, 0x3fcc, "MSI", ALC883_TARGA_DIG),
+       SND_PCI_QUIRK(0x1462, 0x3ef9, "MSI", ALC883_TARGA_DIG),
        SND_PCI_QUIRK(0x1462, 0x3fc1, "MSI", ALC883_TARGA_DIG),
        SND_PCI_QUIRK(0x1462, 0x3fc3, "MSI", ALC883_TARGA_DIG),
+       SND_PCI_QUIRK(0x1462, 0x3fcc, "MSI", ALC883_TARGA_DIG),
        SND_PCI_QUIRK(0x1462, 0x3fdf, "MSI", ALC883_TARGA_DIG),
        SND_PCI_QUIRK(0x1462, 0x4314, "MSI", ALC883_TARGA_DIG),
        SND_PCI_QUIRK(0x1462, 0x4319, "MSI", ALC883_TARGA_DIG),
        SND_PCI_QUIRK(0x1462, 0x4324, "MSI", ALC883_TARGA_DIG),
+       SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC883_6ST_DIG),
+       SND_PCI_QUIRK(0x1462, 0x7187, "MSI", ALC883_6ST_DIG),
+       SND_PCI_QUIRK(0x1462, 0x7250, "MSI", ALC883_6ST_DIG),
+       SND_PCI_QUIRK(0x1462, 0x7280, "MSI", ALC883_6ST_DIG),
+       SND_PCI_QUIRK(0x1462, 0x7327, "MSI", ALC883_6ST_DIG),
        SND_PCI_QUIRK(0x1462, 0xa422, "MSI", ALC883_TARGA_2ch_DIG),
-       SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_ACER_ASPIRE),
-       SND_PCI_QUIRK(0x1025, 0x0110, "Acer Aspire", ALC883_ACER_ASPIRE),
-       SND_PCI_QUIRK(0x1025, 0x0112, "Acer Aspire 9303", ALC883_ACER_ASPIRE),
-       SND_PCI_QUIRK(0x1025, 0, "Acer laptop", ALC883_ACER),
+       SND_PCI_QUIRK(0x147b, 0x1083, "Abit IP35-PRO", ALC883_6ST_DIG),
+       SND_PCI_QUIRK(0x1558, 0, "Clevo laptop", ALC883_LAPTOP_EAPD),
        SND_PCI_QUIRK(0x15d9, 0x8780, "Supermicro PDSBA", ALC883_3ST_6ch),
        SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_MEDION),
-       SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC883_LAPTOP_EAPD),
-       SND_PCI_QUIRK(0x8086, 0xd601, "D102GGC", ALC883_3ST_6ch),
        SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo 101e", ALC883_LENOVO_101E_2ch),
-       SND_PCI_QUIRK(0x17aa, 0x3bfd, "Lenovo NB0763", ALC883_LENOVO_NB0763),
        SND_PCI_QUIRK(0x17aa, 0x2085, "Lenovo NB0763", ALC883_LENOVO_NB0763),
-       SND_PCI_QUIRK(0x103c, 0x2a61, "HP Nettle", ALC888_6ST_HP),
-       SND_PCI_QUIRK(0x103c, 0x2a60, "HP Lucknow", ALC888_3ST_HP),
-       SND_PCI_QUIRK(0x103c, 0x2a4f, "HP Samba", ALC888_3ST_HP),
+       SND_PCI_QUIRK(0x17aa, 0x3bfc, "Lenovo NB0763", ALC883_LENOVO_NB0763),
+       SND_PCI_QUIRK(0x17aa, 0x3bfd, "Lenovo NB0763", ALC883_LENOVO_NB0763),
        SND_PCI_QUIRK(0x17c0, 0x4071, "MEDION MD2", ALC883_MEDION_MD2),
        SND_PCI_QUIRK(0x1991, 0x5625, "Haier W66", ALC883_HAIER_W66),
-       SND_PCI_QUIRK(0x17aa, 0x3bfc, "Lenovo NB0763", ALC883_LENOVO_NB0763),
-       SND_PCI_QUIRK(0x1043, 0x8249, "Asus M2A-VM HDMI", ALC883_3ST_6ch_DIG),
-       SND_PCI_QUIRK(0x147b, 0x1083, "Abit IP35-PRO", ALC883_6ST_DIG),
+       SND_PCI_QUIRK(0x8086, 0xd601, "D102GGC", ALC883_3ST_6ch),
        {}
 };
 
@@ -7435,6 +7871,34 @@ static struct alc_config_preset alc883_presets[] = {
                .need_dac_fix = 1,
                .input_mux = &alc883_capture_source,
        },
+       [ALC888_6ST_DELL] = {
+               .mixers = { alc888_6st_dell_mixer, alc883_chmode_mixer },
+               .init_verbs = { alc883_init_verbs, alc888_6st_dell_verbs },
+               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
+               .dac_nids = alc883_dac_nids,
+               .dig_out_nid = ALC883_DIGOUT_NID,
+               .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
+               .adc_nids = alc883_adc_nids,
+               .dig_in_nid = ALC883_DIGIN_NID,
+               .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
+               .channel_mode = alc883_sixstack_modes,
+               .input_mux = &alc883_capture_source,
+               .unsol_event = alc888_6st_dell_unsol_event,
+               .init_hook = alc888_6st_dell_front_automute,
+       },
+       [ALC883_MITAC] = {
+               .mixers = { alc883_mitac_mixer },
+               .init_verbs = { alc883_init_verbs, alc883_mitac_verbs },
+               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
+               .dac_nids = alc883_dac_nids,
+               .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
+               .adc_nids = alc883_adc_nids,
+               .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
+               .channel_mode = alc883_3ST_2ch_modes,
+               .input_mux = &alc883_capture_source,
+               .unsol_event = alc883_mitac_unsol_event,
+               .init_hook = alc883_mitac_automute,
+       },
 };
 
 
@@ -7582,6 +8046,7 @@ static int patch_alc883(struct hda_codec *codec)
        spec->stream_name_analog = "ALC883 Analog";
        spec->stream_analog_playback = &alc883_pcm_analog_playback;
        spec->stream_analog_capture = &alc883_pcm_analog_capture;
+       spec->stream_analog_alt_capture = &alc883_pcm_analog_alt_capture;
 
        spec->stream_name_digital = "ALC883 Digital";
        spec->stream_digital_playback = &alc883_pcm_digital_playback;
@@ -7592,6 +8057,8 @@ static int patch_alc883(struct hda_codec *codec)
                spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids);
        }
 
+       spec->vmaster_nid = 0x0c;
+
        codec->patch_ops = alc_patch_ops;
        if (board_config == ALC883_AUTO)
                spec->init_hook = alc883_auto_init;
@@ -7659,13 +8126,99 @@ static struct snd_kcontrol_new alc262_hippo1_mixer[] = {
        { } /* end */
 };
 
+/* update HP, line and mono-out pins according to the master switch */
+static void alc262_hp_master_update(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       int val = spec->master_sw;
+
+       /* HP & line-out */
+       snd_hda_codec_write_cache(codec, 0x1b, 0,
+                                 AC_VERB_SET_PIN_WIDGET_CONTROL,
+                                 val ? PIN_HP : 0);
+       snd_hda_codec_write_cache(codec, 0x15, 0,
+                                 AC_VERB_SET_PIN_WIDGET_CONTROL,
+                                 val ? PIN_HP : 0);
+       /* mono (speaker) depending on the HP jack sense */
+       val = val && !spec->jack_present;
+       snd_hda_codec_write_cache(codec, 0x16, 0,
+                                 AC_VERB_SET_PIN_WIDGET_CONTROL,
+                                 val ? PIN_OUT : 0);
+}
+
+static void alc262_hp_bpc_automute(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       unsigned int presence;
+       presence = snd_hda_codec_read(codec, 0x1b, 0,
+                                     AC_VERB_GET_PIN_SENSE, 0);
+       spec->jack_present = !!(presence & AC_PINSENSE_PRESENCE);
+       alc262_hp_master_update(codec);
+}
+
+static void alc262_hp_bpc_unsol_event(struct hda_codec *codec, unsigned int res)
+{
+       if ((res >> 26) != ALC880_HP_EVENT)
+               return;
+       alc262_hp_bpc_automute(codec);
+}
+
+static void alc262_hp_wildwest_automute(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       unsigned int presence;
+       presence = snd_hda_codec_read(codec, 0x15, 0,
+                                     AC_VERB_GET_PIN_SENSE, 0);
+       spec->jack_present = !!(presence & AC_PINSENSE_PRESENCE);
+       alc262_hp_master_update(codec);
+}
+
+static void alc262_hp_wildwest_unsol_event(struct hda_codec *codec,
+                                          unsigned int res)
+{
+       if ((res >> 26) != ALC880_HP_EVENT)
+               return;
+       alc262_hp_wildwest_automute(codec);
+}
+
+static int alc262_hp_master_sw_get(struct snd_kcontrol *kcontrol,
+                                  struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct alc_spec *spec = codec->spec;
+       *ucontrol->value.integer.value = spec->master_sw;
+       return 0;
+}
+
+static int alc262_hp_master_sw_put(struct snd_kcontrol *kcontrol,
+                                  struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct alc_spec *spec = codec->spec;
+       int val = !!*ucontrol->value.integer.value;
+
+       if (val == spec->master_sw)
+               return 0;
+       spec->master_sw = val;
+       alc262_hp_master_update(codec);
+       return 1;
+}
+
 static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = {
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Master Playback Switch",
+               .info = snd_ctl_boolean_mono_info,
+               .get = alc262_hp_master_sw_get,
+               .put = alc262_hp_master_sw_put,
+       },
        HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
-
+       HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0,
+                             HDA_OUTPUT),
+       HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0,
+                           HDA_OUTPUT),
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
        HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
        HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
@@ -7684,12 +8237,21 @@ static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = {
 };
 
 static struct snd_kcontrol_new alc262_HP_BPC_WildWest_mixer[] = {
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Master Playback Switch",
+               .info = snd_ctl_boolean_mono_info,
+               .get = alc262_hp_master_sw_get,
+               .put = alc262_hp_master_sw_put,
+       },
        HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
        HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0,
+                             HDA_OUTPUT),
+       HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0,
+                           HDA_OUTPUT),
        HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x02, HDA_INPUT),
        HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x02, HDA_INPUT),
        HDA_CODEC_VOLUME("Front Mic Boost", 0x1a, 0, HDA_INPUT),
@@ -7709,34 +8271,113 @@ static struct snd_kcontrol_new alc262_HP_BPC_WildWest_option_mixer[] = {
        { } /* end */
 };
 
-/* bind hp and internal speaker mute (with plug check) */
-static int alc262_sony_master_sw_put(struct snd_kcontrol *kcontrol,
-                                    struct snd_ctl_elem_value *ucontrol)
+/* mute/unmute internal speaker according to the hp jack and mute state */
+static void alc262_hp_t5735_automute(struct hda_codec *codec, int force)
 {
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       long *valp = ucontrol->value.integer.value;
-       int change;
+       struct alc_spec *spec = codec->spec;
 
-       /* change hp mute */
-       change = snd_hda_codec_amp_update(codec, 0x15, 0, HDA_OUTPUT, 0,
-                                         HDA_AMP_MUTE,
-                                         valp[0] ? 0 : HDA_AMP_MUTE);
-       change |= snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0,
-                                          HDA_AMP_MUTE,
-                                          valp[1] ? 0 : HDA_AMP_MUTE);
-       if (change) {
-               /* change speaker according to HP jack state */
-               struct alc_spec *spec = codec->spec;
-               unsigned int mute;
-               if (spec->jack_present)
-                       mute = HDA_AMP_MUTE;
-               else
-                       mute = snd_hda_codec_amp_read(codec, 0x15, 0,
-                                                     HDA_OUTPUT, 0);
-               snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
-                                        HDA_AMP_MUTE, mute);
-       }
-       return change;
+       if (force || !spec->sense_updated) {
+               unsigned int present;
+               present = snd_hda_codec_read(codec, 0x15, 0,
+                                            AC_VERB_GET_PIN_SENSE, 0);
+               spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0;
+               spec->sense_updated = 1;
+       }
+       snd_hda_codec_amp_stereo(codec, 0x0c, HDA_OUTPUT, 0, HDA_AMP_MUTE,
+                                spec->jack_present ? HDA_AMP_MUTE : 0);
+}
+
+static void alc262_hp_t5735_unsol_event(struct hda_codec *codec,
+                                       unsigned int res)
+{
+       if ((res >> 26) != ALC880_HP_EVENT)
+               return;
+       alc262_hp_t5735_automute(codec, 1);
+}
+
+static void alc262_hp_t5735_init_hook(struct hda_codec *codec)
+{
+       alc262_hp_t5735_automute(codec, 1);
+}
+
+static struct snd_kcontrol_new alc262_hp_t5735_mixer[] = {
+       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+       { } /* end */
+};
+
+static struct hda_verb alc262_hp_t5735_verbs[] = {
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+
+       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
+       { }
+};
+
+static struct snd_kcontrol_new alc262_hp_rp5700_mixer[] = {
+       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Speaker Playback Switch", 0x16, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
+       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
+       { } /* end */
+};
+
+static struct hda_verb alc262_hp_rp5700_verbs[] = {
+       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))},
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))},
+       {}
+};
+
+static struct hda_input_mux alc262_hp_rp5700_capture_source = {
+       .num_items = 1,
+       .items = {
+               { "Line", 0x1 },
+       },
+};
+
+/* bind hp and internal speaker mute (with plug check) */
+static int alc262_sony_master_sw_put(struct snd_kcontrol *kcontrol,
+                                    struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       long *valp = ucontrol->value.integer.value;
+       int change;
+
+       /* change hp mute */
+       change = snd_hda_codec_amp_update(codec, 0x15, 0, HDA_OUTPUT, 0,
+                                         HDA_AMP_MUTE,
+                                         valp[0] ? 0 : HDA_AMP_MUTE);
+       change |= snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0,
+                                          HDA_AMP_MUTE,
+                                          valp[1] ? 0 : HDA_AMP_MUTE);
+       if (change) {
+               /* change speaker according to HP jack state */
+               struct alc_spec *spec = codec->spec;
+               unsigned int mute;
+               if (spec->jack_present)
+                       mute = HDA_AMP_MUTE;
+               else
+                       mute = snd_hda_codec_amp_read(codec, 0x15, 0,
+                                                     HDA_OUTPUT, 0);
+               snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
+                                        HDA_AMP_MUTE, mute);
+       }
+       return change;
 }
 
 static struct snd_kcontrol_new alc262_sony_mixer[] = {
@@ -8082,6 +8723,72 @@ static struct hda_verb alc262_benq_t31_EAPD_verbs[] = {
        {}
 };
 
+/* Samsung Q1 Ultra Vista model setup */
+static struct snd_kcontrol_new alc262_ultra_mixer[] = {
+       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost", 0x19, 0, HDA_INPUT),
+       { } /* end */
+};
+
+static struct hda_verb alc262_ultra_verbs[] = {
+       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+       /* Mic is on Node 0x19 */
+       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
+       {0x22, AC_VERB_SET_CONNECT_SEL, 0x01},
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
+       {0x23, AC_VERB_SET_CONNECT_SEL, 0x01},
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
+       {0x24, AC_VERB_SET_CONNECT_SEL, 0x01},
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
+       {}
+};
+
+static struct hda_input_mux alc262_ultra_capture_source = {
+       .num_items = 1,
+       .items = {
+               { "Mic", 0x1 },
+       },
+};
+
+/* mute/unmute internal speaker according to the hp jack and mute state */
+static void alc262_ultra_automute(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       unsigned int mute;
+       unsigned int present;
+
+       /* need to execute and sync at first */
+       snd_hda_codec_read(codec, 0x15, 0, AC_VERB_SET_PIN_SENSE, 0);
+       present = snd_hda_codec_read(codec, 0x15, 0,
+                                    AC_VERB_GET_PIN_SENSE, 0);
+       spec->jack_present = (present & 0x80000000) != 0;
+       if (spec->jack_present) {
+               /* mute internal speaker */
+               snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
+                                        HDA_AMP_MUTE, HDA_AMP_MUTE);
+       } else {
+               /* unmute internal speaker if necessary */
+               mute = snd_hda_codec_amp_read(codec, 0x15, 0, HDA_OUTPUT, 0);
+               snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
+                                        HDA_AMP_MUTE, mute);
+       }
+}
+
+/* unsolicited event for HP jack sensing */
+static void alc262_ultra_unsol_event(struct hda_codec *codec,
+                                      unsigned int res)
+{
+       if ((res >> 26) != ALC880_HP_EVENT)
+               return;
+       alc262_ultra_automute(codec);
+}
+
 /* add playback controls from the parsed DAC table */
 static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec,
                                             const struct auto_pin_cfg *cfg)
@@ -8269,7 +8976,7 @@ static struct hda_verb alc262_HP_BPC_init_verbs[] = {
        {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
        {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
 
-       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
+       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
        {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
        {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
 
@@ -8311,6 +9018,8 @@ static struct hda_verb alc262_HP_BPC_init_verbs[] = {
        {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
        {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
 
+       {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
+
        { }
 };
 
@@ -8405,6 +9114,8 @@ static struct hda_verb alc262_HP_BPC_WildWest_init_verbs[] = {
         /* {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
        {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))},
 
+       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
+
        { }
 };
 
@@ -8484,39 +9195,49 @@ static const char *alc262_models[ALC262_MODEL_LAST] = {
        [ALC262_FUJITSU]        = "fujitsu",
        [ALC262_HP_BPC]         = "hp-bpc",
        [ALC262_HP_BPC_D7000_WL]= "hp-bpc-d7000",
+       [ALC262_HP_TC_T5735]    = "hp-tc-t5735",
+       [ALC262_HP_RP5700]      = "hp-rp5700",
        [ALC262_BENQ_ED8]       = "benq",
        [ALC262_BENQ_T31]       = "benq-t31",
        [ALC262_SONY_ASSAMD]    = "sony-assamd",
+       [ALC262_ULTRA]          = "ultra",
        [ALC262_AUTO]           = "auto",
 };
 
 static struct snd_pci_quirk alc262_cfg_tbl[] = {
        SND_PCI_QUIRK(0x1002, 0x437b, "Hippo", ALC262_HIPPO),
        SND_PCI_QUIRK(0x103c, 0x12fe, "HP xw9400", ALC262_HP_BPC),
-       SND_PCI_QUIRK(0x103c, 0x280c, "HP xw4400", ALC262_HP_BPC),
        SND_PCI_QUIRK(0x103c, 0x12ff, "HP xw4550", ALC262_HP_BPC),
-       SND_PCI_QUIRK(0x103c, 0x1308, "HP xw4600", ALC262_HP_BPC),
-       SND_PCI_QUIRK(0x103c, 0x3014, "HP xw6400", ALC262_HP_BPC),
-       SND_PCI_QUIRK(0x103c, 0x1307, "HP xw6600", ALC262_HP_BPC),
-       SND_PCI_QUIRK(0x103c, 0x3015, "HP xw8400", ALC262_HP_BPC),
        SND_PCI_QUIRK(0x103c, 0x1306, "HP xw8600", ALC262_HP_BPC),
+       SND_PCI_QUIRK(0x103c, 0x1307, "HP xw6600", ALC262_HP_BPC),
+       SND_PCI_QUIRK(0x103c, 0x1308, "HP xw4600", ALC262_HP_BPC),
+       SND_PCI_QUIRK(0x103c, 0x1309, "HP xw4*00", ALC262_HP_BPC),
+       SND_PCI_QUIRK(0x103c, 0x130a, "HP xw6*00", ALC262_HP_BPC),
+       SND_PCI_QUIRK(0x103c, 0x130b, "HP xw8*00", ALC262_HP_BPC),
        SND_PCI_QUIRK(0x103c, 0x2800, "HP D7000", ALC262_HP_BPC_D7000_WL),
-       SND_PCI_QUIRK(0x103c, 0x2802, "HP D7000", ALC262_HP_BPC_D7000_WL),
-       SND_PCI_QUIRK(0x103c, 0x2804, "HP D7000", ALC262_HP_BPC_D7000_WL),
-       SND_PCI_QUIRK(0x103c, 0x2806, "HP D7000", ALC262_HP_BPC_D7000_WL),
        SND_PCI_QUIRK(0x103c, 0x2801, "HP D7000", ALC262_HP_BPC_D7000_WF),
+       SND_PCI_QUIRK(0x103c, 0x2802, "HP D7000", ALC262_HP_BPC_D7000_WL),
        SND_PCI_QUIRK(0x103c, 0x2803, "HP D7000", ALC262_HP_BPC_D7000_WF),
+       SND_PCI_QUIRK(0x103c, 0x2804, "HP D7000", ALC262_HP_BPC_D7000_WL),
        SND_PCI_QUIRK(0x103c, 0x2805, "HP D7000", ALC262_HP_BPC_D7000_WF),
+       SND_PCI_QUIRK(0x103c, 0x2806, "HP D7000", ALC262_HP_BPC_D7000_WL),
        SND_PCI_QUIRK(0x103c, 0x2807, "HP D7000", ALC262_HP_BPC_D7000_WF),
+       SND_PCI_QUIRK(0x103c, 0x280c, "HP xw4400", ALC262_HP_BPC),
+       SND_PCI_QUIRK(0x103c, 0x3014, "HP xw6400", ALC262_HP_BPC),
+       SND_PCI_QUIRK(0x103c, 0x3015, "HP xw8400", ALC262_HP_BPC),
+       SND_PCI_QUIRK(0x103c, 0x302f, "HP Thin Client T5735",
+                     ALC262_HP_TC_T5735),
+       SND_PCI_QUIRK(0x103c, 0x2817, "HP RP5700", ALC262_HP_RP5700),
+       SND_PCI_QUIRK(0x104d, 0x1f00, "Sony ASSAMD", ALC262_SONY_ASSAMD),
        SND_PCI_QUIRK(0x104d, 0x8203, "Sony UX-90", ALC262_HIPPO),
+       SND_PCI_QUIRK(0x104d, 0x820f, "Sony ASSAMD", ALC262_SONY_ASSAMD),
+       SND_PCI_QUIRK(0x104d, 0x900e, "Sony ASSAMD", ALC262_SONY_ASSAMD),
+       SND_PCI_QUIRK(0x104d, 0x9015, "Sony 0x9015", ALC262_SONY_ASSAMD),
        SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu", ALC262_FUJITSU),
-       SND_PCI_QUIRK(0x17ff, 0x058f, "Benq Hippo", ALC262_HIPPO_1),
+       SND_PCI_QUIRK(0x144d, 0xc032, "Samsung Q1 Ultra", ALC262_ULTRA),
        SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_BENQ_ED8),
        SND_PCI_QUIRK(0x17ff, 0x058d, "Benq T31-16", ALC262_BENQ_T31),
-       SND_PCI_QUIRK(0x104d, 0x820f, "Sony ASSAMD", ALC262_SONY_ASSAMD),
-       SND_PCI_QUIRK(0x104d, 0x9015, "Sony 0x9015", ALC262_SONY_ASSAMD),
-       SND_PCI_QUIRK(0x104d, 0x900e, "Sony ASSAMD", ALC262_SONY_ASSAMD),
-       SND_PCI_QUIRK(0x104d, 0x1f00, "Sony ASSAMD", ALC262_SONY_ASSAMD),
+       SND_PCI_QUIRK(0x17ff, 0x058f, "Benq Hippo", ALC262_HIPPO_1),
        {}
 };
 
@@ -8579,6 +9300,8 @@ static struct alc_config_preset alc262_presets[] = {
                .num_channel_mode = ARRAY_SIZE(alc262_modes),
                .channel_mode = alc262_modes,
                .input_mux = &alc262_HP_capture_source,
+               .unsol_event = alc262_hp_bpc_unsol_event,
+               .init_hook = alc262_hp_bpc_automute,
        },
        [ALC262_HP_BPC_D7000_WF] = {
                .mixers = { alc262_HP_BPC_WildWest_mixer },
@@ -8589,6 +9312,8 @@ static struct alc_config_preset alc262_presets[] = {
                .num_channel_mode = ARRAY_SIZE(alc262_modes),
                .channel_mode = alc262_modes,
                .input_mux = &alc262_HP_D7000_capture_source,
+               .unsol_event = alc262_hp_wildwest_unsol_event,
+               .init_hook = alc262_hp_wildwest_automute,
        },
        [ALC262_HP_BPC_D7000_WL] = {
                .mixers = { alc262_HP_BPC_WildWest_mixer,
@@ -8600,7 +9325,30 @@ static struct alc_config_preset alc262_presets[] = {
                .num_channel_mode = ARRAY_SIZE(alc262_modes),
                .channel_mode = alc262_modes,
                .input_mux = &alc262_HP_D7000_capture_source,
+               .unsol_event = alc262_hp_wildwest_unsol_event,
+               .init_hook = alc262_hp_wildwest_automute,
+       },
+       [ALC262_HP_TC_T5735] = {
+               .mixers = { alc262_hp_t5735_mixer },
+               .init_verbs = { alc262_init_verbs, alc262_hp_t5735_verbs },
+               .num_dacs = ARRAY_SIZE(alc262_dac_nids),
+               .dac_nids = alc262_dac_nids,
+               .hp_nid = 0x03,
+               .num_channel_mode = ARRAY_SIZE(alc262_modes),
+               .channel_mode = alc262_modes,
+               .input_mux = &alc262_capture_source,
+               .unsol_event = alc262_hp_t5735_unsol_event,
+               .init_hook = alc262_hp_t5735_init_hook,
        },
+       [ALC262_HP_RP5700] = {
+               .mixers = { alc262_hp_rp5700_mixer },
+               .init_verbs = { alc262_init_verbs, alc262_hp_rp5700_verbs },
+               .num_dacs = ARRAY_SIZE(alc262_dac_nids),
+               .dac_nids = alc262_dac_nids,
+               .num_channel_mode = ARRAY_SIZE(alc262_modes),
+               .channel_mode = alc262_modes,
+               .input_mux = &alc262_hp_rp5700_capture_source,
+        },
        [ALC262_BENQ_ED8] = {
                .mixers = { alc262_base_mixer },
                .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs },
@@ -8635,6 +9383,19 @@ static struct alc_config_preset alc262_presets[] = {
                .unsol_event = alc262_hippo_unsol_event,
                .init_hook = alc262_hippo_automute,
        },      
+       [ALC262_ULTRA] = {
+               .mixers = { alc262_ultra_mixer },
+               .init_verbs = { alc262_init_verbs, alc262_ultra_verbs },
+               .num_dacs = ARRAY_SIZE(alc262_dac_nids),
+               .dac_nids = alc262_dac_nids,
+               .hp_nid = 0x03,
+               .dig_out_nid = ALC262_DIGOUT_NID,
+               .num_channel_mode = ARRAY_SIZE(alc262_modes),
+               .channel_mode = alc262_modes,
+               .input_mux = &alc262_ultra_capture_source,
+               .unsol_event = alc262_ultra_unsol_event,
+               .init_hook = alc262_ultra_automute,
+       },
 };
 
 static int patch_alc262(struct hda_codec *codec)
@@ -8716,6 +9477,8 @@ static int patch_alc262(struct hda_codec *codec)
                }
        }
 
+       spec->vmaster_nid = 0x0c;
+
        codec->patch_ops = alc_patch_ops;
        if (board_config == ALC262_AUTO)
                spec->init_hook = alc262_auto_init;
@@ -8873,6 +9636,49 @@ static void alc268_acer_init_hook(struct hda_codec *codec)
        alc268_acer_automute(codec, 1);
 }
 
+static struct snd_kcontrol_new alc268_dell_mixer[] = {
+       /* output mixer control */
+       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
+       { }
+};
+
+static struct hda_verb alc268_dell_verbs[] = {
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
+       { }
+};
+
+/* mute/unmute internal speaker according to the hp jack and mute state */
+static void alc268_dell_automute(struct hda_codec *codec)
+{
+       unsigned int present;
+       unsigned int mute;
+
+       present = snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_PIN_SENSE, 0);
+       if (present & 0x80000000)
+               mute = HDA_AMP_MUTE;
+       else
+               mute = snd_hda_codec_amp_read(codec, 0x15, 0, HDA_OUTPUT, 0);
+       snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
+                                HDA_AMP_MUTE, mute);
+}
+
+static void alc268_dell_unsol_event(struct hda_codec *codec,
+                                   unsigned int res)
+{
+       if ((res >> 26) != ALC880_HP_EVENT)
+               return;
+       alc268_dell_automute(codec);
+}
+
+#define alc268_dell_init_hook  alc268_dell_automute
+
 /*
  * generic initialization of ADC, input mixers and output mixers
  */
@@ -8915,19 +9721,13 @@ static struct hda_verb alc268_base_init_verbs[] = {
        {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
        {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
 
-       /* FIXME: use matrix-type input source selection */
-       /* Mixer elements: 0x18, 19, 1a, 1c, 14, 15, 0b */
-       /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
-       /* Input mixer2 */
-       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
-       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
-       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
-       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
+       /* Unmute Selector 23h,24h and set the default input to mic-in */
+       
+       {0x23, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x24, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
        { }
 };
 
@@ -8972,29 +9772,14 @@ static int alc268_mux_enum_put(struct snd_kcontrol *kcontrol,
 {
        struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
        struct alc_spec *spec = codec->spec;
-       const struct hda_input_mux *imux = spec->input_mux;
+
        unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
        static hda_nid_t capture_mixers[3] = { 0x23, 0x24 };
        hda_nid_t nid = capture_mixers[adc_idx];
-       unsigned int *cur_val = &spec->cur_mux[adc_idx];
-       unsigned int i, idx;
 
-       idx = ucontrol->value.enumerated.item[0];
-       if (idx >= imux->num_items)
-               idx = imux->num_items - 1;
-       if (*cur_val == idx)
-               return 0;
-       for (i = 0; i < imux->num_items; i++) {
-               unsigned int v = (i == idx) ? 0 : HDA_AMP_MUTE;
-               snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT,
-                                        imux->items[i].index,
-                                        HDA_AMP_MUTE, v);
-                snd_hda_codec_write_cache(codec, nid, 0,
-                                         AC_VERB_SET_CONNECT_SEL,
-                                         idx );
-       }
-       *cur_val = idx;
-       return 1;
+       return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
+                                    nid,
+                                    &spec->cur_mux[adc_idx]);
 }
 
 static struct snd_kcontrol_new alc268_capture_alt_mixer[] = {
@@ -9004,7 +9789,6 @@ static struct snd_kcontrol_new alc268_capture_alt_mixer[] = {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                /* The multiple "Capture Source" controls confuse alsamixer
                 * So call somewhat different..
-                * FIXME: the controls appear in the "playback" view!
                 */
                /* .name = "Capture Source", */
                .name = "Input Source",
@@ -9025,7 +9809,6 @@ static struct snd_kcontrol_new alc268_capture_mixer[] = {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                /* The multiple "Capture Source" controls confuse alsamixer
                 * So call somewhat different..
-                * FIXME: the controls appear in the "playback" view!
                 */
                /* .name = "Capture Source", */
                .name = "Input Source",
@@ -9047,12 +9830,67 @@ static struct hda_input_mux alc268_capture_source = {
        },
 };
 
-/* create input playback/capture controls for the given pin */
-static int alc268_new_analog_output(struct alc_spec *spec, hda_nid_t nid,
-                                   const char *ctlname, int idx)
-{
-       char name[32];
-       int err;
+#ifdef CONFIG_SND_DEBUG
+static struct snd_kcontrol_new alc268_test_mixer[] = {
+       HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+
+       /* Volume widgets */
+       HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x02, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x03, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE_MONO("Mono sum Playback Switch", 0x0e, 1, 2, HDA_INPUT),
+       HDA_BIND_MUTE("LINE-OUT sum Playback Switch", 0x0f, 2, HDA_INPUT),
+       HDA_BIND_MUTE("HP-OUT sum Playback Switch", 0x10, 2, HDA_INPUT),
+       HDA_BIND_MUTE("LINE-OUT Playback Switch", 0x14, 2, HDA_OUTPUT),
+       HDA_BIND_MUTE("HP-OUT Playback Switch", 0x15, 2, HDA_OUTPUT),
+       HDA_BIND_MUTE("Mono Playback Switch", 0x16, 2, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("MIC1 Capture Volume", 0x18, 0x0, HDA_INPUT),
+       HDA_BIND_MUTE("MIC1 Capture Switch", 0x18, 2, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("MIC2 Capture Volume", 0x19, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("LINE1 Capture Volume", 0x1a, 0x0, HDA_INPUT),
+       HDA_BIND_MUTE("LINE1 Capture Switch", 0x1a, 2, HDA_OUTPUT),
+       /* The below appears problematic on some hardwares */
+       /*HDA_CODEC_VOLUME("PCBEEP Playback Volume", 0x1d, 0x0, HDA_INPUT),*/
+       HDA_CODEC_VOLUME("PCM-IN1 Capture Volume", 0x23, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("PCM-IN1 Capture Switch", 0x23, 2, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("PCM-IN2 Capture Volume", 0x24, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("PCM-IN2 Capture Switch", 0x24, 2, HDA_OUTPUT),
+
+       /* Modes for retasking pin widgets */
+       ALC_PIN_MODE("LINE-OUT pin mode", 0x14, ALC_PIN_DIR_INOUT),
+       ALC_PIN_MODE("HP-OUT pin mode", 0x15, ALC_PIN_DIR_INOUT),
+       ALC_PIN_MODE("MIC1 pin mode", 0x18, ALC_PIN_DIR_INOUT),
+       ALC_PIN_MODE("LINE1 pin mode", 0x1a, ALC_PIN_DIR_INOUT),
+
+       /* Controls for GPIO pins, assuming they are configured as outputs */
+       ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01),
+       ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02),
+       ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04),
+       ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08),
+
+       /* Switches to allow the digital SPDIF output pin to be enabled.
+        * The ALC268 does not have an SPDIF input.
+        */
+       ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x06, 0x01),
+
+       /* A switch allowing EAPD to be enabled.  Some laptops seem to use
+        * this output to turn on an external amplifier.
+        */
+       ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02),
+       ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02),
+
+       { } /* end */
+};
+#endif
+
+/* create input playback/capture controls for the given pin */
+static int alc268_new_analog_output(struct alc_spec *spec, hda_nid_t nid,
+                                   const char *ctlname, int idx)
+{
+       char name[32];
+       int err;
 
        sprintf(name, "%s Playback Volume", ctlname);
        if (nid == 0x14) {
@@ -9192,43 +10030,491 @@ static void alc268_auto_init_mono_speaker_out(struct hda_codec *codec)
 }
 
 /* pcm configuration: identiacal with ALC880 */
-#define alc268_pcm_analog_playback     alc880_pcm_analog_playback
-#define alc268_pcm_analog_capture      alc880_pcm_analog_capture
-#define alc268_pcm_digital_playback    alc880_pcm_digital_playback
+#define alc268_pcm_analog_playback     alc880_pcm_analog_playback
+#define alc268_pcm_analog_capture      alc880_pcm_analog_capture
+#define alc268_pcm_analog_alt_capture  alc880_pcm_analog_alt_capture
+#define alc268_pcm_digital_playback    alc880_pcm_digital_playback
+
+/*
+ * BIOS auto configuration
+ */
+static int alc268_parse_auto_config(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       int err;
+       static hda_nid_t alc268_ignore[] = { 0 };
+
+       err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
+                                          alc268_ignore);
+       if (err < 0)
+               return err;
+       if (!spec->autocfg.line_outs)
+               return 0; /* can't find valid BIOS pin config */
+
+       err = alc268_auto_create_multi_out_ctls(spec, &spec->autocfg);
+       if (err < 0)
+               return err;
+       err = alc268_auto_create_analog_input_ctls(spec, &spec->autocfg);
+       if (err < 0)
+               return err;
+
+       spec->multiout.max_channels = 2;
+
+       /* digital only support output */
+       if (spec->autocfg.dig_out_pin)
+               spec->multiout.dig_out_nid = ALC268_DIGOUT_NID;
+
+       if (spec->kctl_alloc)
+               spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
+
+       spec->init_verbs[spec->num_init_verbs++] = alc268_volume_init_verbs;
+       spec->num_mux_defs = 1;
+       spec->input_mux = &spec->private_imux;
+
+       err = alc_auto_add_mic_boost(codec);
+       if (err < 0)
+               return err;
+
+       return 1;
+}
+
+#define alc268_auto_init_multi_out     alc882_auto_init_multi_out
+#define alc268_auto_init_hp_out                alc882_auto_init_hp_out
+#define alc268_auto_init_analog_input  alc882_auto_init_analog_input
+
+/* init callback for auto-configuration model -- overriding the default init */
+static void alc268_auto_init(struct hda_codec *codec)
+{
+       alc268_auto_init_multi_out(codec);
+       alc268_auto_init_hp_out(codec);
+       alc268_auto_init_mono_speaker_out(codec);
+       alc268_auto_init_analog_input(codec);
+}
+
+/*
+ * configuration and preset
+ */
+static const char *alc268_models[ALC268_MODEL_LAST] = {
+       [ALC268_3ST]            = "3stack",
+       [ALC268_TOSHIBA]        = "toshiba",
+       [ALC268_ACER]           = "acer",
+       [ALC268_DELL]           = "dell",
+#ifdef CONFIG_SND_DEBUG
+       [ALC268_TEST]           = "test",
+#endif
+       [ALC268_AUTO]           = "auto",
+};
+
+static struct snd_pci_quirk alc268_cfg_tbl[] = {
+       SND_PCI_QUIRK(0x1025, 0x0126, "Acer", ALC268_ACER),
+       SND_PCI_QUIRK(0x1025, 0x012e, "Acer Aspire 5310", ALC268_ACER),
+       SND_PCI_QUIRK(0x1025, 0x0130, "Acer Extensa 5210", ALC268_ACER),
+       SND_PCI_QUIRK(0x1025, 0x0136, "Acer Aspire 5315", ALC268_ACER),
+       SND_PCI_QUIRK(0x1028, 0x0253, "Dell OEM", ALC268_DELL),
+       SND_PCI_QUIRK(0x103c, 0x30cc, "TOSHIBA", ALC268_TOSHIBA),
+       SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC268_3ST),
+       SND_PCI_QUIRK(0x1179, 0xff10, "TOSHIBA A205", ALC268_TOSHIBA),
+       SND_PCI_QUIRK(0x1179, 0xff50, "TOSHIBA A305", ALC268_TOSHIBA),
+       SND_PCI_QUIRK(0x152d, 0x0763, "Diverse (CPR2000)", ALC268_ACER),
+       {}
+};
+
+static struct alc_config_preset alc268_presets[] = {
+       [ALC268_3ST] = {
+               .mixers = { alc268_base_mixer, alc268_capture_alt_mixer },
+               .init_verbs = { alc268_base_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc268_dac_nids),
+               .dac_nids = alc268_dac_nids,
+                .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
+                .adc_nids = alc268_adc_nids_alt,
+               .hp_nid = 0x03,
+               .dig_out_nid = ALC268_DIGOUT_NID,
+               .num_channel_mode = ARRAY_SIZE(alc268_modes),
+               .channel_mode = alc268_modes,
+               .input_mux = &alc268_capture_source,
+       },
+       [ALC268_TOSHIBA] = {
+               .mixers = { alc268_base_mixer, alc268_capture_alt_mixer },
+               .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
+                               alc268_toshiba_verbs },
+               .num_dacs = ARRAY_SIZE(alc268_dac_nids),
+               .dac_nids = alc268_dac_nids,
+               .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
+               .adc_nids = alc268_adc_nids_alt,
+               .hp_nid = 0x03,
+               .num_channel_mode = ARRAY_SIZE(alc268_modes),
+               .channel_mode = alc268_modes,
+               .input_mux = &alc268_capture_source,
+               .unsol_event = alc268_toshiba_unsol_event,
+               .init_hook = alc268_toshiba_automute,
+       },
+       [ALC268_ACER] = {
+               .mixers = { alc268_acer_mixer, alc268_capture_alt_mixer },
+               .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
+                               alc268_acer_verbs },
+               .num_dacs = ARRAY_SIZE(alc268_dac_nids),
+               .dac_nids = alc268_dac_nids,
+               .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
+               .adc_nids = alc268_adc_nids_alt,
+               .hp_nid = 0x02,
+               .num_channel_mode = ARRAY_SIZE(alc268_modes),
+               .channel_mode = alc268_modes,
+               .input_mux = &alc268_capture_source,
+               .unsol_event = alc268_acer_unsol_event,
+               .init_hook = alc268_acer_init_hook,
+       },
+       [ALC268_DELL] = {
+               .mixers = { alc268_dell_mixer },
+               .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
+                               alc268_dell_verbs },
+               .num_dacs = ARRAY_SIZE(alc268_dac_nids),
+               .dac_nids = alc268_dac_nids,
+               .hp_nid = 0x02,
+               .num_channel_mode = ARRAY_SIZE(alc268_modes),
+               .channel_mode = alc268_modes,
+               .unsol_event = alc268_dell_unsol_event,
+               .init_hook = alc268_dell_init_hook,
+               .input_mux = &alc268_capture_source,
+       },
+#ifdef CONFIG_SND_DEBUG
+       [ALC268_TEST] = {
+               .mixers = { alc268_test_mixer, alc268_capture_mixer },
+               .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
+                               alc268_volume_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc268_dac_nids),
+               .dac_nids = alc268_dac_nids,
+               .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
+               .adc_nids = alc268_adc_nids_alt,
+               .hp_nid = 0x03,
+               .dig_out_nid = ALC268_DIGOUT_NID,
+               .num_channel_mode = ARRAY_SIZE(alc268_modes),
+               .channel_mode = alc268_modes,
+               .input_mux = &alc268_capture_source,
+       },
+#endif
+};
+
+static int patch_alc268(struct hda_codec *codec)
+{
+       struct alc_spec *spec;
+       int board_config;
+       int err;
+
+       spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
+       if (spec == NULL)
+               return -ENOMEM;
+
+       codec->spec = spec;
+
+       board_config = snd_hda_check_board_config(codec, ALC268_MODEL_LAST,
+                                                 alc268_models,
+                                                 alc268_cfg_tbl);
+
+       if (board_config < 0 || board_config >= ALC268_MODEL_LAST) {
+               printk(KERN_INFO "hda_codec: Unknown model for ALC268, "
+                      "trying auto-probe from BIOS...\n");
+               board_config = ALC268_AUTO;
+       }
+
+       if (board_config == ALC268_AUTO) {
+               /* automatic parse from the BIOS config */
+               err = alc268_parse_auto_config(codec);
+               if (err < 0) {
+                       alc_free(codec);
+                       return err;
+               } else if (!err) {
+                       printk(KERN_INFO
+                              "hda_codec: Cannot set up configuration "
+                              "from BIOS.  Using base mode...\n");
+                       board_config = ALC268_3ST;
+               }
+       }
+
+       if (board_config != ALC268_AUTO)
+               setup_preset(spec, &alc268_presets[board_config]);
+
+       spec->stream_name_analog = "ALC268 Analog";
+       spec->stream_analog_playback = &alc268_pcm_analog_playback;
+       spec->stream_analog_capture = &alc268_pcm_analog_capture;
+       spec->stream_analog_alt_capture = &alc268_pcm_analog_alt_capture;
+
+       spec->stream_name_digital = "ALC268 Digital";
+       spec->stream_digital_playback = &alc268_pcm_digital_playback;
+
+       if (!spec->adc_nids && spec->input_mux) {
+               /* check whether NID 0x07 is valid */
+               unsigned int wcap = get_wcaps(codec, 0x07);
+
+               /* get type */
+               wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
+               if (wcap != AC_WID_AUD_IN) {
+                       spec->adc_nids = alc268_adc_nids_alt;
+                       spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt);
+                       spec->mixers[spec->num_mixers] =
+                                       alc268_capture_alt_mixer;
+                       spec->num_mixers++;
+               } else {
+                       spec->adc_nids = alc268_adc_nids;
+                       spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids);
+                       spec->mixers[spec->num_mixers] =
+                               alc268_capture_mixer;
+                       spec->num_mixers++;
+               }
+       }
+
+       spec->vmaster_nid = 0x02;
+
+       codec->patch_ops = alc_patch_ops;
+       if (board_config == ALC268_AUTO)
+               spec->init_hook = alc268_auto_init;
+               
+       return 0;
+}
+
+/*
+ *  ALC269 channel source setting (2 channel)
+ */
+#define ALC269_DIGOUT_NID      ALC880_DIGOUT_NID
+
+#define alc269_dac_nids                alc260_dac_nids
+
+static hda_nid_t alc269_adc_nids[1] = {
+       /* ADC1 */
+       0x07,
+};
+
+#define alc269_modes           alc260_modes
+#define alc269_capture_source  alc880_lg_lw_capture_source
+
+static struct snd_kcontrol_new alc269_base_mixer[] = {
+       HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
+       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
+       { } /* end */
+};
+
+/* capture mixer elements */
+static struct snd_kcontrol_new alc269_capture_mixer[] = {
+       HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               /* The multiple "Capture Source" controls confuse alsamixer
+                * So call somewhat different..
+                */
+               /* .name = "Capture Source", */
+               .name = "Input Source",
+               .count = 1,
+               .info = alc_mux_enum_info,
+               .get = alc_mux_enum_get,
+               .put = alc_mux_enum_put,
+       },
+       { } /* end */
+};
+
+/*
+ * generic initialization of ADC, input mixers and output mixers
+ */
+static struct hda_verb alc269_init_verbs[] = {
+       /*
+        * Unmute ADC0 and set the default input to mic-in
+        */
+       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+
+       /* Mute input amps (PCBeep, Line In, Mic 1 & Mic 2) of the
+        * analog-loopback mixer widget
+        * Note: PASD motherboards uses the Line In 2 as the input for
+        * front panel mic (mic 2)
+        */
+       /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
+       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+
+       /*
+        * Set up output mixers (0x0c - 0x0e)
+        */
+       /* set vol=0 to output mixers */
+       {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+
+       /* set up input amps for analog loopback */
+       /* Amp Indices: DAC = 0, mixer = 1 */
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+
+       {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
+
+       /* FIXME: use matrix-type input source selection */
+       /* Mixer elements: 0x18, 19, 1a, 1b, 1d, 0b */
+       /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+
+       /* set EAPD */
+       {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
+       {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
+       { }
+};
+
+/* add playback controls from the parsed DAC table */
+static int alc269_auto_create_multi_out_ctls(struct alc_spec *spec,
+                                            const struct auto_pin_cfg *cfg)
+{
+       hda_nid_t nid;
+       int err;
+
+       spec->multiout.num_dacs = 1;    /* only use one dac */
+       spec->multiout.dac_nids = spec->private_dac_nids;
+       spec->multiout.dac_nids[0] = 2;
+
+       nid = cfg->line_out_pins[0];
+       if (nid) {
+               err = add_control(spec, ALC_CTL_WIDGET_VOL,
+                                 "Front Playback Volume",
+                                 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT));
+               if (err < 0)
+                       return err;
+               err = add_control(spec, ALC_CTL_WIDGET_MUTE,
+                                 "Front Playback Switch",
+                                 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
+               if (err < 0)
+                       return err;
+       }
+
+       nid = cfg->speaker_pins[0];
+       if (nid) {
+               if (!cfg->line_out_pins[0]) {
+                       err = add_control(spec, ALC_CTL_WIDGET_VOL,
+                                         "Speaker Playback Volume",
+                                         HDA_COMPOSE_AMP_VAL(0x02, 3, 0,
+                                                             HDA_OUTPUT));
+                       if (err < 0)
+                               return err;
+               }
+               if (nid == 0x16) {
+                       err = add_control(spec, ALC_CTL_WIDGET_MUTE,
+                                         "Speaker Playback Switch",
+                                         HDA_COMPOSE_AMP_VAL(nid, 2, 0,
+                                                             HDA_OUTPUT));
+                       if (err < 0)
+                               return err;
+               } else {
+                       err = add_control(spec, ALC_CTL_WIDGET_MUTE,
+                                         "Speaker Playback Switch",
+                                         HDA_COMPOSE_AMP_VAL(nid, 3, 0,
+                                                             HDA_OUTPUT));
+                       if (err < 0)
+                               return err;
+               }
+       }
+       nid = cfg->hp_pins[0];
+       if (nid) {
+               /* spec->multiout.hp_nid = 2; */
+               if (!cfg->line_out_pins[0] && !cfg->speaker_pins[0]) {
+                       err = add_control(spec, ALC_CTL_WIDGET_VOL,
+                                         "Headphone Playback Volume",
+                                         HDA_COMPOSE_AMP_VAL(0x02, 3, 0,
+                                                             HDA_OUTPUT));
+                       if (err < 0)
+                               return err;
+               }
+               if (nid == 0x16) {
+                       err = add_control(spec, ALC_CTL_WIDGET_MUTE,
+                                         "Headphone Playback Switch",
+                                         HDA_COMPOSE_AMP_VAL(nid, 2, 0,
+                                                             HDA_OUTPUT));
+                       if (err < 0)
+                               return err;
+               } else {
+                       err = add_control(spec, ALC_CTL_WIDGET_MUTE,
+                                         "Headphone Playback Switch",
+                                         HDA_COMPOSE_AMP_VAL(nid, 3, 0,
+                                                             HDA_OUTPUT));
+                       if (err < 0)
+                               return err;
+               }
+       }
+       return 0;
+}
+
+#define alc269_auto_create_analog_input_ctls \
+       alc880_auto_create_analog_input_ctls
+
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+#define alc269_loopbacks       alc880_loopbacks
+#endif
+
+/* pcm configuration: identiacal with ALC880 */
+#define alc269_pcm_analog_playback     alc880_pcm_analog_playback
+#define alc269_pcm_analog_capture      alc880_pcm_analog_capture
+#define alc269_pcm_digital_playback    alc880_pcm_digital_playback
+#define alc269_pcm_digital_capture     alc880_pcm_digital_capture
 
 /*
  * BIOS auto configuration
  */
-static int alc268_parse_auto_config(struct hda_codec *codec)
+static int alc269_parse_auto_config(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
        int err;
-       static hda_nid_t alc268_ignore[] = { 0 };
+       static hda_nid_t alc269_ignore[] = { 0x1d, 0 };
 
        err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
-                                          alc268_ignore);
+                                          alc269_ignore);
        if (err < 0)
                return err;
-       if (!spec->autocfg.line_outs)
-               return 0; /* can't find valid BIOS pin config */
 
-       err = alc268_auto_create_multi_out_ctls(spec, &spec->autocfg);
+       err = alc269_auto_create_multi_out_ctls(spec, &spec->autocfg);
        if (err < 0)
                return err;
-       err = alc268_auto_create_analog_input_ctls(spec, &spec->autocfg);
+       err = alc269_auto_create_analog_input_ctls(spec, &spec->autocfg);
        if (err < 0)
                return err;
 
-       spec->multiout.max_channels = 2;
+       spec->multiout.max_channels = spec->multiout.num_dacs * 2;
 
-       /* digital only support output */
        if (spec->autocfg.dig_out_pin)
-               spec->multiout.dig_out_nid = ALC268_DIGOUT_NID;
+               spec->multiout.dig_out_nid = ALC269_DIGOUT_NID;
 
        if (spec->kctl_alloc)
                spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
 
-       spec->init_verbs[spec->num_init_verbs++] = alc268_volume_init_verbs;
+       spec->init_verbs[spec->num_init_verbs++] = alc269_init_verbs;
        spec->num_mux_defs = 1;
        spec->input_mux = &spec->private_imux;
 
@@ -9239,111 +10525,68 @@ static int alc268_parse_auto_config(struct hda_codec *codec)
        return 1;
 }
 
-#define alc268_auto_init_multi_out     alc882_auto_init_multi_out
-#define alc268_auto_init_hp_out                alc882_auto_init_hp_out
-#define alc268_auto_init_analog_input  alc882_auto_init_analog_input
+#define alc269_auto_init_multi_out     alc882_auto_init_multi_out
+#define alc269_auto_init_hp_out                alc882_auto_init_hp_out
+#define alc269_auto_init_analog_input  alc882_auto_init_analog_input
+
 
 /* init callback for auto-configuration model -- overriding the default init */
-static void alc268_auto_init(struct hda_codec *codec)
+static void alc269_auto_init(struct hda_codec *codec)
 {
-       alc268_auto_init_multi_out(codec);
-       alc268_auto_init_hp_out(codec);
-       alc268_auto_init_mono_speaker_out(codec);
-       alc268_auto_init_analog_input(codec);
+       alc269_auto_init_multi_out(codec);
+       alc269_auto_init_hp_out(codec);
+       alc269_auto_init_analog_input(codec);
 }
 
 /*
  * configuration and preset
  */
-static const char *alc268_models[ALC268_MODEL_LAST] = {
-       [ALC268_3ST]            = "3stack",
-       [ALC268_TOSHIBA]        = "toshiba",
-       [ALC268_ACER]           = "acer",
-       [ALC268_AUTO]           = "auto",
+static const char *alc269_models[ALC269_MODEL_LAST] = {
+       [ALC269_BASIC]          = "basic",
 };
 
-static struct snd_pci_quirk alc268_cfg_tbl[] = {
-       SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC268_3ST),
-       SND_PCI_QUIRK(0x1179, 0xff10, "TOSHIBA A205", ALC268_TOSHIBA),
-       SND_PCI_QUIRK(0x1179, 0xff50, "TOSHIBA A305", ALC268_TOSHIBA),
-       SND_PCI_QUIRK(0x103c, 0x30cc, "TOSHIBA", ALC268_TOSHIBA),
-       SND_PCI_QUIRK(0x1025, 0x0126, "Acer", ALC268_ACER),
-       SND_PCI_QUIRK(0x1025, 0x0130, "Acer Extensa 5210", ALC268_ACER),
-       SND_PCI_QUIRK(0x152d, 0x0763, "Diverse (CPR2000)", ALC268_ACER),
+static struct snd_pci_quirk alc269_cfg_tbl[] = {
        {}
 };
 
-static struct alc_config_preset alc268_presets[] = {
-       [ALC268_3ST] = {
-               .mixers = { alc268_base_mixer, alc268_capture_alt_mixer },
-               .init_verbs = { alc268_base_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc268_dac_nids),
-               .dac_nids = alc268_dac_nids,
-                .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
-                .adc_nids = alc268_adc_nids_alt,
-               .hp_nid = 0x03,
-               .dig_out_nid = ALC268_DIGOUT_NID,
-               .num_channel_mode = ARRAY_SIZE(alc268_modes),
-               .channel_mode = alc268_modes,
-               .input_mux = &alc268_capture_source,
-       },
-       [ALC268_TOSHIBA] = {
-               .mixers = { alc268_base_mixer, alc268_capture_alt_mixer },
-               .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
-                               alc268_toshiba_verbs },
-               .num_dacs = ARRAY_SIZE(alc268_dac_nids),
-               .dac_nids = alc268_dac_nids,
-               .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
-               .adc_nids = alc268_adc_nids_alt,
+static struct alc_config_preset alc269_presets[] = {
+       [ALC269_BASIC] = {
+               .mixers = { alc269_base_mixer },
+               .init_verbs = { alc269_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc269_dac_nids),
+               .dac_nids = alc269_dac_nids,
                .hp_nid = 0x03,
-               .num_channel_mode = ARRAY_SIZE(alc268_modes),
-               .channel_mode = alc268_modes,
-               .input_mux = &alc268_capture_source,
-               .unsol_event = alc268_toshiba_unsol_event,
-               .init_hook = alc268_toshiba_automute,
-       },
-       [ALC268_ACER] = {
-               .mixers = { alc268_acer_mixer, alc268_capture_alt_mixer },
-               .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
-                               alc268_acer_verbs },
-               .num_dacs = ARRAY_SIZE(alc268_dac_nids),
-               .dac_nids = alc268_dac_nids,
-               .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
-               .adc_nids = alc268_adc_nids_alt,
-               .hp_nid = 0x02,
-               .num_channel_mode = ARRAY_SIZE(alc268_modes),
-               .channel_mode = alc268_modes,
-               .input_mux = &alc268_capture_source,
-               .unsol_event = alc268_acer_unsol_event,
-               .init_hook = alc268_acer_init_hook,
+               .num_channel_mode = ARRAY_SIZE(alc269_modes),
+               .channel_mode = alc269_modes,
+               .input_mux = &alc269_capture_source,
        },
 };
 
-static int patch_alc268(struct hda_codec *codec)
+static int patch_alc269(struct hda_codec *codec)
 {
        struct alc_spec *spec;
        int board_config;
        int err;
 
-       spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
+       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
        if (spec == NULL)
                return -ENOMEM;
 
        codec->spec = spec;
 
-       board_config = snd_hda_check_board_config(codec, ALC268_MODEL_LAST,
-                                                 alc268_models,
-                                                 alc268_cfg_tbl);
+       board_config = snd_hda_check_board_config(codec, ALC269_MODEL_LAST,
+                                                 alc269_models,
+                                                 alc269_cfg_tbl);
 
-       if (board_config < 0 || board_config >= ALC268_MODEL_LAST) {
-               printk(KERN_INFO "hda_codec: Unknown model for ALC268, "
+       if (board_config < 0) {
+               printk(KERN_INFO "hda_codec: Unknown model for ALC269, "
                       "trying auto-probe from BIOS...\n");
-               board_config = ALC268_AUTO;
+               board_config = ALC269_AUTO;
        }
 
-       if (board_config == ALC268_AUTO) {
+       if (board_config == ALC269_AUTO) {
                /* automatic parse from the BIOS config */
-               err = alc268_parse_auto_config(codec);
+               err = alc269_parse_auto_config(codec);
                if (err < 0) {
                        alc_free(codec);
                        return err;
@@ -9351,48 +10594,34 @@ static int patch_alc268(struct hda_codec *codec)
                        printk(KERN_INFO
                               "hda_codec: Cannot set up configuration "
                               "from BIOS.  Using base mode...\n");
-                       board_config = ALC268_3ST;
+                       board_config = ALC269_BASIC;
                }
        }
 
-       if (board_config != ALC268_AUTO)
-               setup_preset(spec, &alc268_presets[board_config]);
+       if (board_config != ALC269_AUTO)
+               setup_preset(spec, &alc269_presets[board_config]);
 
-       spec->stream_name_analog = "ALC268 Analog";
-       spec->stream_analog_playback = &alc268_pcm_analog_playback;
-       spec->stream_analog_capture = &alc268_pcm_analog_capture;
+       spec->stream_name_analog = "ALC269 Analog";
+       spec->stream_analog_playback = &alc269_pcm_analog_playback;
+       spec->stream_analog_capture = &alc269_pcm_analog_capture;
 
-       spec->stream_name_digital = "ALC268 Digital";
-       spec->stream_digital_playback = &alc268_pcm_digital_playback;
+       spec->stream_name_digital = "ALC269 Digital";
+       spec->stream_digital_playback = &alc269_pcm_digital_playback;
+       spec->stream_digital_capture = &alc269_pcm_digital_capture;
+
+       spec->adc_nids = alc269_adc_nids;
+       spec->num_adc_nids = ARRAY_SIZE(alc269_adc_nids);
+       spec->mixers[spec->num_mixers] = alc269_capture_mixer;
+       spec->num_mixers++;
 
-       if (board_config == ALC268_AUTO) {
-               if (!spec->adc_nids && spec->input_mux) {
-                       /* check whether NID 0x07 is valid */
-                       unsigned int wcap = get_wcaps(codec, 0x07);
-
-                       /* get type */
-                       wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
-                       if (wcap != AC_WID_AUD_IN) {
-                               spec->adc_nids = alc268_adc_nids_alt;
-                               spec->num_adc_nids =
-                                       ARRAY_SIZE(alc268_adc_nids_alt);
-                               spec->mixers[spec->num_mixers] =
-                                       alc268_capture_alt_mixer;
-                               spec->num_mixers++;
-                       } else {
-                               spec->adc_nids = alc268_adc_nids;
-                               spec->num_adc_nids =
-                                       ARRAY_SIZE(alc268_adc_nids);
-                               spec->mixers[spec->num_mixers] =
-                                       alc268_capture_mixer;
-                               spec->num_mixers++;
-                       }
-               }
-       }
        codec->patch_ops = alc_patch_ops;
-       if (board_config == ALC268_AUTO)
-               spec->init_hook = alc268_auto_init;
-               
+       if (board_config == ALC269_AUTO)
+               spec->init_hook = alc269_auto_init;
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+       if (!spec->loopback.amplist)
+               spec->loopback.amplist = alc269_loopbacks;
+#endif
+
        return 0;
 }
 
@@ -10213,7 +11442,6 @@ static struct snd_kcontrol_new alc861_capture_mixer[] = {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                /* The multiple "Capture Source" controls confuse alsamixer
                 * So call somewhat different..
-                *FIXME: the controls appear in the "playback" view!
                 */
                /* .name = "Capture Source", */
                .name = "Input Source",
@@ -10369,22 +11597,23 @@ static struct snd_pci_quirk alc861_cfg_tbl[] = {
        SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC861_3ST),
        SND_PCI_QUIRK(0x1043, 0x1335, "ASUS F2/3", ALC861_ASUS_LAPTOP),
        SND_PCI_QUIRK(0x1043, 0x1338, "ASUS F2/3", ALC861_ASUS_LAPTOP),
-       SND_PCI_QUIRK(0x1043, 0x13d7, "ASUS A9rp", ALC861_ASUS_LAPTOP),
-       SND_PCI_QUIRK(0x1584, 0x9075, "Airis Praxis N1212", ALC861_ASUS_LAPTOP),
        SND_PCI_QUIRK(0x1043, 0x1393, "ASUS", ALC861_ASUS),
+       SND_PCI_QUIRK(0x1043, 0x13d7, "ASUS A9rp", ALC861_ASUS_LAPTOP),
        SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS P1-AH2", ALC861_3ST_DIG),
        SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba", ALC861_TOSHIBA),
        /* FIXME: the entry below breaks Toshiba A100 (model=auto works!)
         *        Any other models that need this preset?
         */
        /* SND_PCI_QUIRK(0x1179, 0xff10, "Toshiba", ALC861_TOSHIBA), */
-       SND_PCI_QUIRK(0x1584, 0x9072, "Uniwill m31", ALC861_UNIWILL_M31),
-       SND_PCI_QUIRK(0x1584, 0x9075, "Uniwill", ALC861_UNIWILL_M31),
+       SND_PCI_QUIRK(0x1462, 0x7254, "HP dx2200 (MSI MS-7254)", ALC861_3ST),
+       SND_PCI_QUIRK(0x1462, 0x7297, "HP dx2250 (MSI MS-7297)", ALC861_3ST),
        SND_PCI_QUIRK(0x1584, 0x2b01, "Uniwill X40AIx", ALC861_UNIWILL_M31),
+       SND_PCI_QUIRK(0x1584, 0x9072, "Uniwill m31", ALC861_UNIWILL_M31),
+       SND_PCI_QUIRK(0x1584, 0x9075, "Airis Praxis N1212", ALC861_ASUS_LAPTOP),
+       /* FIXME: the below seems conflict */
+       /* SND_PCI_QUIRK(0x1584, 0x9075, "Uniwill", ALC861_UNIWILL_M31), */
        SND_PCI_QUIRK(0x1849, 0x0660, "Asrock 939SLI32", ALC660_3ST),
        SND_PCI_QUIRK(0x8086, 0xd600, "Intel", ALC861_3ST),
-       SND_PCI_QUIRK(0x1462, 0x7254, "HP dx2200 (MSI MS-7254)", ALC861_3ST),
-       SND_PCI_QUIRK(0x1462, 0x7297, "HP dx2250 (MSI MS-7297)", ALC861_3ST),
        {}
 };
 
@@ -10543,6 +11772,8 @@ static int patch_alc861(struct hda_codec *codec)
        spec->stream_digital_playback = &alc861_pcm_digital_playback;
        spec->stream_digital_capture = &alc861_pcm_digital_capture;
 
+       spec->vmaster_nid = 0x03;
+
        codec->patch_ops = alc_patch_ops;
        if (board_config == ALC861_AUTO)
                spec->init_hook = alc861_auto_init;
@@ -10697,7 +11928,6 @@ static struct snd_kcontrol_new alc861vd_capture_mixer[] = {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                /* The multiple "Capture Source" controls confuse alsamixer
                 * So call somewhat different..
-                *FIXME: the controls appear in the "playback" view!
                 */
                /* .name = "Capture Source", */
                .name = "Input Source",
@@ -11102,21 +12332,20 @@ static const char *alc861vd_models[ALC861VD_MODEL_LAST] = {
 };
 
 static struct snd_pci_quirk alc861vd_cfg_tbl[] = {
+       SND_PCI_QUIRK(0x1019, 0xa88d, "Realtek ALC660 demo", ALC660VD_3ST),
+       SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_HP),
        SND_PCI_QUIRK(0x1043, 0x12e2, "Asus z35m", ALC660VD_3ST),
        SND_PCI_QUIRK(0x1043, 0x1339, "Asus G1", ALC660VD_3ST),
        SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS", ALC660VD_3ST_DIG),
        SND_PCI_QUIRK(0x10de, 0x03f0, "Realtek ALC660 demo", ALC660VD_3ST),
-       SND_PCI_QUIRK(0x1019, 0xa88d, "Realtek ALC660 demo", ALC660VD_3ST),
-
+       SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba A135", ALC861VD_LENOVO),
        /*SND_PCI_QUIRK(0x1179, 0xff00, "DALLAS", ALC861VD_DALLAS),*/ /*lenovo*/
        SND_PCI_QUIRK(0x1179, 0xff01, "DALLAS", ALC861VD_DALLAS),
-       SND_PCI_QUIRK(0x17aa, 0x3802, "Lenovo 3000 C200", ALC861VD_LENOVO),
-       SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo", ALC861VD_LENOVO),
-       SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba A135", ALC861VD_LENOVO),
        SND_PCI_QUIRK(0x1179, 0xff03, "Toshiba P205", ALC861VD_LENOVO),
        SND_PCI_QUIRK(0x1565, 0x820d, "Biostar NF61S SE", ALC861VD_6ST_DIG),
+       SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo", ALC861VD_LENOVO),
+       SND_PCI_QUIRK(0x17aa, 0x3802, "Lenovo 3000 C200", ALC861VD_LENOVO),
        SND_PCI_QUIRK(0x1849, 0x0862, "ASRock K8NF6G-VSTA", ALC861VD_6ST_DIG),
-       SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_HP),
        {}
 };
 
@@ -11520,6 +12749,8 @@ static int patch_alc861vd(struct hda_codec *codec)
        spec->mixers[spec->num_mixers] = alc861vd_capture_mixer;
        spec->num_mixers++;
 
+       spec->vmaster_nid = 0x02;
+
        codec->patch_ops = alc_patch_ops;
 
        if (board_config == ALC861VD_AUTO)
@@ -11699,18 +12930,6 @@ static struct snd_kcontrol_new alc662_base_mixer[] = {
        HDA_CODEC_MUTE("Mic Playback Switch", 0xb, 0x0, HDA_INPUT),
        HDA_CODEC_VOLUME("Front Mic Playback Volume", 0xb, 0x01, HDA_INPUT),
        HDA_CODEC_MUTE("Front Mic Playback Switch", 0xb, 0x01, HDA_INPUT),
-
-       /* Capture mixer control */
-       HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Capture Source",
-               .count = 1,
-               .info = alc_mux_enum_info,
-               .get = alc_mux_enum_get,
-               .put = alc_mux_enum_put,
-       },
        { } /* end */
 };
 
@@ -11728,17 +12947,6 @@ static struct snd_kcontrol_new alc662_3ST_2ch_mixer[] = {
        HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
        HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
        HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
-       HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               /* .name = "Capture Source", */
-               .name = "Input Source",
-               .count = 1,
-               .info = alc662_mux_enum_info,
-               .get = alc662_mux_enum_get,
-               .put = alc662_mux_enum_put,
-       },
        { } /* end */
 };
 
@@ -11762,46 +12970,24 @@ static struct snd_kcontrol_new alc662_3ST_6ch_mixer[] = {
        HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
        HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
        HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
-       HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               /* .name = "Capture Source", */
-               .name = "Input Source",
-               .count = 1,
-               .info = alc662_mux_enum_info,
-               .get = alc662_mux_enum_get,
-               .put = alc662_mux_enum_put,
-       },
        { } /* end */
 };
 
 static struct snd_kcontrol_new alc662_lenovo_101e_mixer[] = {
        HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
        HDA_BIND_MUTE("Front Playback Switch", 0x02, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("iSpeaker Playback Volume", 0x03, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("iSpeaker Playback Switch", 0x03, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x03, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Speaker Playback Switch", 0x03, 2, HDA_INPUT),
        HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
        HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
        HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
        HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               /* .name = "Capture Source", */
-               .name = "Input Source",
-               .count = 1,
-               .info = alc662_mux_enum_info,
-               .get = alc662_mux_enum_get,
-               .put = alc662_mux_enum_put,
-       },
        { } /* end */
 };
 
 static struct snd_kcontrol_new alc662_eeepc_p701_mixer[] = {
-       HDA_CODEC_MUTE("iSpeaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
 
        HDA_CODEC_VOLUME("LineOut Playback Volume", 0x02, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE("LineOut Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
@@ -11816,6 +13002,24 @@ static struct snd_kcontrol_new alc662_eeepc_p701_mixer[] = {
        { } /* end */
 };
 
+static struct snd_kcontrol_new alc662_eeepc_ep20_mixer[] = {
+       HDA_CODEC_VOLUME("LineOut Playback Volume", 0x02, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("LineOut Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Surround Playback Switch", 0x03, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE_MONO("Center Playback Switch", 0x04, 1, 2, HDA_INPUT),
+       HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x04, 2, 2, HDA_INPUT),
+       HDA_CODEC_MUTE("Speaker Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("MuteCtrl Playback Switch", 0x0c, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       { } /* end */
+};
+
 static struct snd_kcontrol_new alc662_chmode_mixer[] = {
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
@@ -11901,6 +13105,13 @@ static struct hda_verb alc662_eeepc_sue_init_verbs[] = {
        {}
 };
 
+/* Set Unsolicited Event*/
+static struct hda_verb alc662_eeepc_ep20_sue_init_verbs[] = {
+       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
+       {}
+};
+
 /*
  * generic initialization of ADC, input mixers and output mixers
  */
@@ -11957,14 +13168,13 @@ static struct snd_kcontrol_new alc662_capture_mixer[] = {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                /* The multiple "Capture Source" controls confuse alsamixer
                 * So call somewhat different..
-                * FIXME: the controls appear in the "playback" view!
                 */
                /* .name = "Capture Source", */
                .name = "Input Source",
                .count = 1,
-               .info = alc882_mux_enum_info,
-               .get = alc882_mux_enum_get,
-               .put = alc882_mux_enum_put,
+               .info = alc662_mux_enum_info,
+               .get = alc662_mux_enum_get,
+               .put = alc662_mux_enum_put,
        },
        { } /* end */
 };
@@ -12037,6 +13247,40 @@ static void alc662_eeepc_inithook(struct hda_codec *codec)
        alc662_eeepc_mic_automute(codec);
 }
 
+static void alc662_eeepc_ep20_automute(struct hda_codec *codec)
+{
+       unsigned int mute;
+       unsigned int present;
+
+       snd_hda_codec_read(codec, 0x14, 0, AC_VERB_SET_PIN_SENSE, 0);
+       present = snd_hda_codec_read(codec, 0x14, 0,
+                                    AC_VERB_GET_PIN_SENSE, 0);
+       present = (present & 0x80000000) != 0;
+       if (present) {
+               /* mute internal speaker */
+               snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
+                                        HDA_AMP_MUTE, HDA_AMP_MUTE);
+       } else {
+               /* unmute internal speaker if necessary */
+               mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0);
+               snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
+                                        HDA_AMP_MUTE, mute);
+       }
+}
+
+/* unsolicited event for HP jack sensing */
+static void alc662_eeepc_ep20_unsol_event(struct hda_codec *codec,
+                                         unsigned int res)
+{
+       if ((res >> 26) == ALC880_HP_EVENT)
+               alc662_eeepc_ep20_automute(codec);
+}
+
+static void alc662_eeepc_ep20_inithook(struct hda_codec *codec)
+{
+       alc662_eeepc_ep20_automute(codec);
+}
+
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 #define alc662_loopbacks       alc880_loopbacks
 #endif
@@ -12057,12 +13301,15 @@ static const char *alc662_models[ALC662_MODEL_LAST] = {
        [ALC662_3ST_6ch]        = "3stack-6ch",
        [ALC662_5ST_DIG]        = "6stack-dig",
        [ALC662_LENOVO_101E]    = "lenovo-101e",
+       [ALC662_ASUS_EEEPC_P701] = "eeepc-p701",
+       [ALC662_ASUS_EEEPC_EP20] = "eeepc-ep20",
        [ALC662_AUTO]           = "auto",
 };
 
 static struct snd_pci_quirk alc662_cfg_tbl[] = {
-       SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo", ALC662_LENOVO_101E),
        SND_PCI_QUIRK(0x1043, 0x82a1, "ASUS Eeepc", ALC662_ASUS_EEEPC_P701),
+       SND_PCI_QUIRK(0x1043, 0x82d1, "ASUS Eeepc EP20", ALC662_ASUS_EEEPC_EP20),
+       SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo", ALC662_LENOVO_101E),
        {}
 };
 
@@ -12149,6 +13396,21 @@ static struct alc_config_preset alc662_presets[] = {
                .unsol_event = alc662_eeepc_unsol_event,
                .init_hook = alc662_eeepc_inithook,
        },
+       [ALC662_ASUS_EEEPC_EP20] = {
+               .mixers = { alc662_eeepc_ep20_mixer, alc662_capture_mixer,
+                           alc662_chmode_mixer },
+               .init_verbs = { alc662_init_verbs,
+                               alc662_eeepc_ep20_sue_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc662_dac_nids),
+               .dac_nids = alc662_dac_nids,
+               .num_adc_nids = ARRAY_SIZE(alc662_adc_nids),
+               .adc_nids = alc662_adc_nids,
+               .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
+               .channel_mode = alc662_3ST_6ch_modes,
+               .input_mux = &alc662_lenovo_101e_capture_source,
+               .unsol_event = alc662_eeepc_ep20_unsol_event,
+               .init_hook = alc662_eeepc_ep20_inithook,
+       },
 
 };
 
@@ -12308,6 +13570,7 @@ static void alc662_auto_init_multi_out(struct hda_codec *codec)
        struct alc_spec *spec = codec->spec;
        int i;
 
+       alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
        for (i = 0; i <= HDA_SIDE; i++) {
                hda_nid_t nid = spec->autocfg.line_out_pins[i];
                int pin_type = get_pin_type(spec->autocfg.line_out_type);
@@ -12458,6 +13721,8 @@ static int patch_alc662(struct hda_codec *codec)
                spec->num_adc_nids = ARRAY_SIZE(alc662_adc_nids);
        }
 
+       spec->vmaster_nid = 0x02;
+
        codec->patch_ops = alc_patch_ops;
        if (board_config == ALC662_AUTO)
                spec->init_hook = alc662_auto_init;
@@ -12475,7 +13740,9 @@ static int patch_alc662(struct hda_codec *codec)
 struct hda_codec_preset snd_hda_preset_realtek[] = {
        { .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 },
        { .id = 0x10ec0262, .name = "ALC262", .patch = patch_alc262 },
+       { .id = 0x10ec0267, .name = "ALC267", .patch = patch_alc268 },
        { .id = 0x10ec0268, .name = "ALC268", .patch = patch_alc268 },
+       { .id = 0x10ec0269, .name = "ALC269", .patch = patch_alc269 },
        { .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660",
          .patch = patch_alc861 },
        { .id = 0x10ec0660, .name = "ALC660-VD", .patch = patch_alc861vd },
@@ -12490,5 +13757,6 @@ struct hda_codec_preset snd_hda_preset_realtek[] = {
        { .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc883 },
        { .id = 0x10ec0885, .name = "ALC885", .patch = patch_alc882 },
        { .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc883 },
+       { .id = 0x10ec0889, .name = "ALC889", .patch = patch_alc883 },
        {} /* terminator */
 };
index 2a4b9609aa5c80e75a23c7b6d36352855f1d885e..d22f5a6b850f2b82d3f39060a57a13bb769a3d6e 100644 (file)
@@ -22,7 +22,6 @@
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
@@ -287,7 +286,6 @@ static int patch_si3054(struct hda_codec *codec)
 struct hda_codec_preset snd_hda_preset_si3054[] = {
        { .id = 0x163c3055, .name = "Si3054", .patch = patch_si3054 },
        { .id = 0x163c3155, .name = "Si3054", .patch = patch_si3054 },
-       { .id = 0x11c11040, .name = "Si3054", .patch = patch_si3054 },
        { .id = 0x11c13026, .name = "Si3054", .patch = patch_si3054 },
        { .id = 0x11c13055, .name = "Si3054", .patch = patch_si3054 },
        { .id = 0x11c13155, .name = "Si3054", .patch = patch_si3054 },
index 04012237096c18fbba12da7be7ee251691dca160..caf48edaa921f629870b5e39bc4e83a94d56c52d 100644 (file)
@@ -24,7 +24,6 @@
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
@@ -35,7 +34,8 @@
 #include "hda_local.h"
 
 #define NUM_CONTROL_ALLOC      32
-#define STAC_HP_EVENT          0x37
+#define STAC_PWR_EVENT         0x20
+#define STAC_HP_EVENT          0x30
 
 enum {
        STAC_REF,
@@ -61,6 +61,16 @@ enum {
        STAC_9205_MODELS
 };
 
+enum {
+       STAC_92HD73XX_REF,
+       STAC_92HD73XX_MODELS
+};
+
+enum {
+       STAC_92HD71BXX_REF,
+       STAC_92HD71BXX_MODELS
+};
+
 enum {
        STAC_925x_REF,
        STAC_M2_2,
@@ -97,6 +107,7 @@ enum {
        STAC_D965_3ST,
        STAC_D965_5ST,
        STAC_DELL_3ST,
+       STAC_DELL_BIOS,
        STAC_927X_MODELS
 };
 
@@ -110,11 +121,24 @@ struct sigmatel_spec {
        unsigned int mic_switch: 1;
        unsigned int alt_switch: 1;
        unsigned int hp_detect: 1;
-       unsigned int gpio_mute: 1;
 
-       unsigned int gpio_mask, gpio_data;
+       /* gpio lines */
+       unsigned int gpio_mask;
+       unsigned int gpio_dir;
+       unsigned int gpio_data;
+       unsigned int gpio_mute;
+
+       /* analog loopback */
+       unsigned char aloopback_mask;
+       unsigned char aloopback_shift;
+
+       /* power management */
+       unsigned int num_pwrs;
+       hda_nid_t *pwr_nids;
 
        /* playback */
+       struct hda_input_mux *mono_mux;
+       unsigned int cur_mmux;
        struct hda_multi_out multiout;
        hda_nid_t dac_nids[5];
 
@@ -125,8 +149,10 @@ struct sigmatel_spec {
        unsigned int num_muxes;
        hda_nid_t *dmic_nids;
        unsigned int num_dmics;
-       hda_nid_t dmux_nid;
+       hda_nid_t *dmux_nids;
+       unsigned int num_dmuxes;
        hda_nid_t dig_in_nid;
+       hda_nid_t mono_nid;
 
        /* pin widgets */
        hda_nid_t *pin_nids;
@@ -140,7 +166,7 @@ struct sigmatel_spec {
 
        /* capture source */
        struct hda_input_mux *dinput_mux;
-       unsigned int cur_dmux;
+       unsigned int cur_dmux[2];
        struct hda_input_mux *input_mux;
        unsigned int cur_mux[3];
 
@@ -157,6 +183,10 @@ struct sigmatel_spec {
        struct snd_kcontrol_new *kctl_alloc;
        struct hda_input_mux private_dimux;
        struct hda_input_mux private_imux;
+       struct hda_input_mux private_mono_mux;
+
+       /* virtual master */
+       unsigned int vmaster_tlv[4];
 };
 
 static hda_nid_t stac9200_adc_nids[1] = {
@@ -171,6 +201,58 @@ static hda_nid_t stac9200_dac_nids[1] = {
         0x02,
 };
 
+static hda_nid_t stac92hd73xx_pwr_nids[8] = {
+       0x0a, 0x0b, 0x0c, 0xd, 0x0e,
+       0x0f, 0x10, 0x11
+};
+
+static hda_nid_t stac92hd73xx_adc_nids[2] = {
+       0x1a, 0x1b
+};
+
+#define STAC92HD73XX_NUM_DMICS 2
+static hda_nid_t stac92hd73xx_dmic_nids[STAC92HD73XX_NUM_DMICS + 1] = {
+       0x13, 0x14, 0
+};
+
+#define STAC92HD73_DAC_COUNT 5
+static hda_nid_t stac92hd73xx_dac_nids[STAC92HD73_DAC_COUNT] = {
+       0x15, 0x16, 0x17, 0x18, 0x19,
+};
+
+static hda_nid_t stac92hd73xx_mux_nids[4] = {
+       0x28, 0x29, 0x2a, 0x2b,
+};
+
+static hda_nid_t stac92hd73xx_dmux_nids[2] = {
+       0x20, 0x21,
+};
+
+static hda_nid_t stac92hd71bxx_pwr_nids[3] = {
+       0x0a, 0x0d, 0x0f
+};
+
+static hda_nid_t stac92hd71bxx_adc_nids[2] = {
+       0x12, 0x13,
+};
+
+static hda_nid_t stac92hd71bxx_mux_nids[2] = {
+       0x1a, 0x1b
+};
+
+static hda_nid_t stac92hd71bxx_dmux_nids[1] = {
+       0x1c,
+};
+
+static hda_nid_t stac92hd71bxx_dac_nids[2] = {
+       0x10, /*0x11, */
+};
+
+#define STAC92HD71BXX_NUM_DMICS        2
+static hda_nid_t stac92hd71bxx_dmic_nids[STAC92HD71BXX_NUM_DMICS + 1] = {
+       0x18, 0x19, 0
+};
+
 static hda_nid_t stac925x_adc_nids[1] = {
         0x03,
 };
@@ -188,6 +270,10 @@ static hda_nid_t stac925x_dmic_nids[STAC925X_NUM_DMICS + 1] = {
        0x15, 0
 };
 
+static hda_nid_t stac925x_dmux_nids[1] = {
+       0x14,
+};
+
 static hda_nid_t stac922x_adc_nids[2] = {
         0x06, 0x07,
 };
@@ -204,6 +290,15 @@ static hda_nid_t stac927x_mux_nids[3] = {
         0x15, 0x16, 0x17
 };
 
+static hda_nid_t stac927x_dmux_nids[1] = {
+       0x1b,
+};
+
+#define STAC927X_NUM_DMICS 2
+static hda_nid_t stac927x_dmic_nids[STAC927X_NUM_DMICS + 1] = {
+       0x13, 0x14, 0
+};
+
 static hda_nid_t stac9205_adc_nids[2] = {
         0x12, 0x13
 };
@@ -212,6 +307,10 @@ static hda_nid_t stac9205_mux_nids[2] = {
         0x19, 0x1a
 };
 
+static hda_nid_t stac9205_dmux_nids[1] = {
+       0x1d,
+};
+
 #define STAC9205_NUM_DMICS     2
 static hda_nid_t stac9205_dmic_nids[STAC9205_NUM_DMICS + 1] = {
         0x17, 0x18, 0
@@ -232,6 +331,17 @@ static hda_nid_t stac922x_pin_nids[10] = {
        0x0f, 0x10, 0x11, 0x15, 0x1b,
 };
 
+static hda_nid_t stac92hd73xx_pin_nids[12] = {
+       0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
+       0x0f, 0x10, 0x11, 0x12, 0x13,
+       0x14, 0x22
+};
+
+static hda_nid_t stac92hd71bxx_pin_nids[10] = {
+       0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
+       0x0f, 0x14, 0x18, 0x19, 0x1e,
+};
+
 static hda_nid_t stac927x_pin_nids[14] = {
        0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
        0x0f, 0x10, 0x11, 0x12, 0x13,
@@ -257,8 +367,9 @@ static int stac92xx_dmux_enum_get(struct snd_kcontrol *kcontrol,
 {
        struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
        struct sigmatel_spec *spec = codec->spec;
+       unsigned int dmux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
 
-       ucontrol->value.enumerated.item[0] = spec->cur_dmux;
+       ucontrol->value.enumerated.item[0] = spec->cur_dmux[dmux_idx];
        return 0;
 }
 
@@ -267,9 +378,10 @@ static int stac92xx_dmux_enum_put(struct snd_kcontrol *kcontrol,
 {
        struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
        struct sigmatel_spec *spec = codec->spec;
+       unsigned int dmux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
 
        return snd_hda_input_mux_put(codec, spec->dinput_mux, ucontrol,
-                                    spec->dmux_nid, &spec->cur_dmux);
+                       spec->dmux_nids[dmux_idx], &spec->cur_dmux[dmux_idx]);
 }
 
 static int stac92xx_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
@@ -299,15 +411,45 @@ static int stac92xx_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e
                                     spec->mux_nids[adc_idx], &spec->cur_mux[adc_idx]);
 }
 
+static int stac92xx_mono_mux_enum_info(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_info *uinfo)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct sigmatel_spec *spec = codec->spec;
+       return snd_hda_input_mux_info(spec->mono_mux, uinfo);
+}
+
+static int stac92xx_mono_mux_enum_get(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct sigmatel_spec *spec = codec->spec;
+
+       ucontrol->value.enumerated.item[0] = spec->cur_mmux;
+       return 0;
+}
+
+static int stac92xx_mono_mux_enum_put(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct sigmatel_spec *spec = codec->spec;
+
+       return snd_hda_input_mux_put(codec, spec->mono_mux, ucontrol,
+                                    spec->mono_nid, &spec->cur_mmux);
+}
+
 #define stac92xx_aloopback_info snd_ctl_boolean_mono_info
 
 static int stac92xx_aloopback_get(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol)
 {
        struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
        struct sigmatel_spec *spec = codec->spec;
 
-       ucontrol->value.integer.value[0] = spec->aloopback;
+       ucontrol->value.integer.value[0] = !!(spec->aloopback &
+                                             (spec->aloopback_mask << idx));
        return 0;
 }
 
@@ -316,23 +458,33 @@ static int stac92xx_aloopback_put(struct snd_kcontrol *kcontrol,
 {
        struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
        struct sigmatel_spec *spec = codec->spec;
+       unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
        unsigned int dac_mode;
+       unsigned int val, idx_val;
 
-       if (spec->aloopback == ucontrol->value.integer.value[0])
+       idx_val = spec->aloopback_mask << idx;
+       if (ucontrol->value.integer.value[0])
+               val = spec->aloopback | idx_val;
+       else
+               val = spec->aloopback & ~idx_val;
+       if (spec->aloopback == val)
                return 0;
 
-       spec->aloopback = ucontrol->value.integer.value[0];
-
+       spec->aloopback = val;
 
+       /* Only return the bits defined by the shift value of the
+        * first two bytes of the mask
+        */
        dac_mode = snd_hda_codec_read(codec, codec->afg, 0,
-               kcontrol->private_value & 0xFFFF, 0x0);
+                                     kcontrol->private_value & 0xFFFF, 0x0);
+       dac_mode >>= spec->aloopback_shift;
 
-       if (spec->aloopback) {
+       if (spec->aloopback & idx_val) {
                snd_hda_power_up(codec);
-               dac_mode |= 0x40;
+               dac_mode |= idx_val;
        } else {
                snd_hda_power_down(codec);
-               dac_mode &= ~0x40;
+               dac_mode &= ~idx_val;
        }
 
        snd_hda_codec_write_cache(codec, codec->afg, 0,
@@ -354,6 +506,107 @@ static struct hda_verb stac9200_eapd_init[] = {
        {}
 };
 
+static struct hda_verb stac92hd73xx_6ch_core_init[] = {
+       /* set master volume and direct control */
+       { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
+       /* setup audio connections */
+       { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00},
+       { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01},
+       { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02},
+       /* setup adcs to point to mixer */
+       { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
+       { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
+       { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       /* setup import muxs */
+       { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
+       { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
+       { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
+       { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {}
+};
+
+static struct hda_verb stac92hd73xx_8ch_core_init[] = {
+       /* set master volume and direct control */
+       { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
+       /* setup audio connections */
+       { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00},
+       { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01},
+       { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02},
+       /* connect hp ports to dac3 */
+       { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x03},
+       { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x03},
+       /* setup adcs to point to mixer */
+       { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
+       { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
+       { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       /* setup import muxs */
+       { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
+       { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
+       { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
+       { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x03},
+       {}
+};
+
+static struct hda_verb stac92hd73xx_10ch_core_init[] = {
+       /* set master volume and direct control */
+       { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
+       /* setup audio connections */
+       { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
+       { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01 },
+       { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02 },
+       /* dac3 is connected to import3 mux */
+       { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0xb07f},
+       /* connect hp ports to dac4 */
+       { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x04},
+       { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x04},
+       /* setup adcs to point to mixer */
+       { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b},
+       { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b},
+       { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       /* setup import muxs */
+       { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01},
+       { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01},
+       { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01},
+       { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x03},
+       {}
+};
+
+static struct hda_verb stac92hd71bxx_core_init[] = {
+       /* set master volume and direct control */
+       { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
+       /* connect headphone jack to dac1 */
+       { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
+       { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Speaker */
+       /* unmute right and left channels for nodes 0x0a, 0xd, 0x0f */
+       { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+};
+
+static struct hda_verb stac92hd71bxx_analog_core_init[] = {
+       /* set master volume and direct control */
+       { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
+       /* connect headphone jack to dac1 */
+       { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01},
+       /* connect ports 0d and 0f to audio mixer */
+       { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x2},
+       { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x2},
+       { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Speaker */
+       /* unmute dac0 input in audio mixer */
+       { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0x701f},
+       /* unmute right and left channels for nodes 0x0a, 0xd, 0x0f */
+       { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {}
+};
+
 static struct hda_verb stac925x_core_init[] = {
        /* set dac0mux for dac converter */
        { 0x06, AC_VERB_SET_CONNECT_SEL, 0x00},
@@ -388,6 +641,16 @@ static struct hda_verb stac9205_core_init[] = {
        {}
 };
 
+#define STAC_MONO_MUX \
+       { \
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+               .name = "Mono Mux", \
+               .count = 1, \
+               .info = stac92xx_mono_mux_enum_info, \
+               .get = stac92xx_mono_mux_enum_get, \
+               .put = stac92xx_mono_mux_enum_put, \
+       }
+
 #define STAC_INPUT_SOURCE(cnt) \
        { \
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
@@ -398,11 +661,11 @@ static struct hda_verb stac9205_core_init[] = {
                .put = stac92xx_mux_enum_put, \
        }
 
-#define STAC_ANALOG_LOOPBACK(verb_read,verb_write) \
+#define STAC_ANALOG_LOOPBACK(verb_read, verb_write, cnt) \
        { \
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
                .name  = "Analog Loopback", \
-               .count = 1, \
+               .count = cnt, \
                .info  = stac92xx_aloopback_info, \
                .get   = stac92xx_aloopback_get, \
                .put   = stac92xx_aloopback_put, \
@@ -419,6 +682,114 @@ static struct snd_kcontrol_new stac9200_mixer[] = {
        { } /* end */
 };
 
+static struct snd_kcontrol_new stac92hd73xx_6ch_mixer[] = {
+       STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 3),
+
+       HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
+
+       HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
+
+       HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
+       HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
+
+       HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT),
+
+       HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT),
+       HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT),
+
+       HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT),
+       HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT),
+
+       HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT),
+       HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT),
+       { } /* end */
+};
+
+static struct snd_kcontrol_new stac92hd73xx_8ch_mixer[] = {
+       STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 4),
+
+       HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
+
+       HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
+
+       HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
+       HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
+
+       HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT),
+
+       HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT),
+       HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT),
+
+       HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT),
+       HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT),
+
+       HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT),
+       HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT),
+       { } /* end */
+};
+
+static struct snd_kcontrol_new stac92hd73xx_10ch_mixer[] = {
+       STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 5),
+
+       HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT),
+
+       HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT),
+
+       HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT),
+       HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT),
+
+       HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT),
+
+       HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT),
+       HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT),
+
+       HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT),
+       HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT),
+
+       HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT),
+       HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT),
+       { } /* end */
+};
+
+static struct snd_kcontrol_new stac92hd71bxx_analog_mixer[] = {
+       STAC_INPUT_SOURCE(2),
+
+       HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x0, 0x1a, 0x0, HDA_OUTPUT),
+
+       HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1d, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1d, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x1, 0x1b, 0x0, HDA_OUTPUT),
+
+       HDA_CODEC_MUTE("Analog Loopback 1", 0x17, 0x3, HDA_INPUT),
+       HDA_CODEC_MUTE("Analog Loopback 2", 0x17, 0x4, HDA_INPUT),
+       { } /* end */
+};
+
+static struct snd_kcontrol_new stac92hd71bxx_mixer[] = {
+       STAC_INPUT_SOURCE(2),
+       STAC_ANALOG_LOOPBACK(0xFA0, 0x7A0, 2),
+
+       HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x0, 0x1a, 0x0, HDA_OUTPUT),
+
+       HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1d, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1d, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x1, 0x1b, 0x0, HDA_OUTPUT),
+       { } /* end */
+};
+
 static struct snd_kcontrol_new stac925x_mixer[] = {
        STAC_INPUT_SOURCE(1),
        HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_OUTPUT),
@@ -428,16 +799,8 @@ static struct snd_kcontrol_new stac925x_mixer[] = {
 };
 
 static struct snd_kcontrol_new stac9205_mixer[] = {
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Digital Input Source",
-               .count = 1,
-               .info = stac92xx_dmux_enum_info,
-               .get = stac92xx_dmux_enum_get,
-               .put = stac92xx_dmux_enum_put,
-       },
        STAC_INPUT_SOURCE(2),
-       STAC_ANALOG_LOOPBACK(0xFE0, 0x7E0),
+       STAC_ANALOG_LOOPBACK(0xFE0, 0x7E0, 1),
 
        HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1b, 0x0, HDA_INPUT),
        HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1d, 0x0, HDA_OUTPUT),
@@ -466,7 +829,7 @@ static struct snd_kcontrol_new stac922x_mixer[] = {
 
 static struct snd_kcontrol_new stac927x_mixer[] = {
        STAC_INPUT_SOURCE(3),
-       STAC_ANALOG_LOOPBACK(0xFEB, 0x7EB),
+       STAC_ANALOG_LOOPBACK(0xFEB, 0x7EB, 1),
 
        HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x18, 0x0, HDA_INPUT),
        HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1b, 0x0, HDA_OUTPUT),
@@ -482,6 +845,44 @@ static struct snd_kcontrol_new stac927x_mixer[] = {
        { } /* end */
 };
 
+static struct snd_kcontrol_new stac_dmux_mixer = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name = "Digital Input Source",
+       /* count set later */
+       .info = stac92xx_dmux_enum_info,
+       .get = stac92xx_dmux_enum_get,
+       .put = stac92xx_dmux_enum_put,
+};
+
+static const char *slave_vols[] = {
+       "Front Playback Volume",
+       "Surround Playback Volume",
+       "Center Playback Volume",
+       "LFE Playback Volume",
+       "Side Playback Volume",
+       "Headphone Playback Volume",
+       "Headphone Playback Volume",
+       "Speaker Playback Volume",
+       "External Speaker Playback Volume",
+       "Speaker2 Playback Volume",
+       NULL
+};
+
+static const char *slave_sws[] = {
+       "Front Playback Switch",
+       "Surround Playback Switch",
+       "Center Playback Switch",
+       "LFE Playback Switch",
+       "Side Playback Switch",
+       "Headphone Playback Switch",
+       "Headphone Playback Switch",
+       "Speaker Playback Switch",
+       "External Speaker Playback Switch",
+       "Speaker2 Playback Switch",
+       "IEC958 Playback Switch",
+       NULL
+};
+
 static int stac92xx_build_controls(struct hda_codec *codec)
 {
        struct sigmatel_spec *spec = codec->spec;
@@ -497,6 +898,13 @@ static int stac92xx_build_controls(struct hda_codec *codec)
                if (err < 0)
                        return err;
        }
+       if (spec->num_dmuxes > 0) {
+               stac_dmux_mixer.count = spec->num_dmuxes;
+               err = snd_ctl_add(codec->bus->card,
+                                 snd_ctl_new1(&stac_dmux_mixer, codec));
+               if (err < 0)
+                       return err;
+       }
 
        if (spec->multiout.dig_out_nid) {
                err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid);
@@ -508,6 +916,23 @@ static int stac92xx_build_controls(struct hda_codec *codec)
                if (err < 0)
                        return err;
        }
+
+       /* if we have no master control, let's create it */
+       if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
+               snd_hda_set_vmaster_tlv(codec, spec->multiout.dac_nids[0],
+                                       HDA_OUTPUT, spec->vmaster_tlv);
+               err = snd_hda_add_vmaster(codec, "Master Playback Volume",
+                                         spec->vmaster_tlv, slave_vols);
+               if (err < 0)
+                       return err;
+       }
+       if (!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
+               err = snd_hda_add_vmaster(codec, "Master Playback Switch",
+                                         NULL, slave_sws);
+               if (err < 0)
+                       return err;
+       }
+
        return 0;       
 }
 
@@ -733,7 +1158,7 @@ static struct snd_pci_quirk stac9200_cfg_tbl[] = {
 
 static unsigned int ref925x_pin_configs[8] = {
        0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021,
-       0x90a70320, 0x02214210, 0x400003f1, 0x9033032e,
+       0x90a70320, 0x02214210, 0x01019020, 0x9033032e,
 };
 
 static unsigned int stac925x_MA6_pin_configs[8] = {
@@ -777,6 +1202,48 @@ static struct snd_pci_quirk stac925x_cfg_tbl[] = {
        {} /* terminator */
 };
 
+static unsigned int ref92hd73xx_pin_configs[12] = {
+       0x02214030, 0x02a19040, 0x01a19020, 0x02214030,
+       0x0181302e, 0x01014010, 0x01014020, 0x01014030,
+       0x02319040, 0x90a000f0, 0x90a000f0, 0x01452050,
+};
+
+static unsigned int *stac92hd73xx_brd_tbl[STAC_92HD73XX_MODELS] = {
+       [STAC_92HD73XX_REF] = ref92hd73xx_pin_configs,
+};
+
+static const char *stac92hd73xx_models[STAC_92HD73XX_MODELS] = {
+       [STAC_92HD73XX_REF] = "ref",
+};
+
+static struct snd_pci_quirk stac92hd73xx_cfg_tbl[] = {
+       /* SigmaTel reference board */
+       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
+                     "DFI LanParty", STAC_92HD73XX_REF),
+       {} /* terminator */
+};
+
+static unsigned int ref92hd71bxx_pin_configs[10] = {
+       0x02214030, 0x02a19040, 0x01a19020, 0x01014010,
+       0x0181302e, 0x01114010, 0x01019020, 0x90a000f0,
+       0x90a000f0, 0x01452050,
+};
+
+static unsigned int *stac92hd71bxx_brd_tbl[STAC_92HD71BXX_MODELS] = {
+       [STAC_92HD71BXX_REF] = ref92hd71bxx_pin_configs,
+};
+
+static const char *stac92hd71bxx_models[STAC_92HD71BXX_MODELS] = {
+       [STAC_92HD71BXX_REF] = "ref",
+};
+
+static struct snd_pci_quirk stac92hd71bxx_cfg_tbl[] = {
+       /* SigmaTel reference board */
+       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
+                     "DFI LanParty", STAC_92HD71BXX_REF),
+       {} /* terminator */
+};
+
 static unsigned int ref922x_pin_configs[10] = {
        0x01014010, 0x01016011, 0x01012012, 0x0221401f,
        0x01813122, 0x01011014, 0x01441030, 0x01c41030,
@@ -823,8 +1290,8 @@ static unsigned int dell_922x_m81_pin_configs[10] = {
     102801D7 (Dell XPS M1210)
 */
 static unsigned int dell_922x_m82_pin_configs[10] = {
-       0x0221121f, 0x408103ff, 0x02111212, 0x90100310, 
-       0x408003f1, 0x02111211, 0x03451340, 0x40c003f2, 
+       0x02211211, 0x408103ff, 0x02a1123e, 0x90100310, 
+       0x408003f1, 0x0221121f, 0x03451340, 0x40c003f2, 
        0x508003f3, 0x405003f4, 
 };
 
@@ -1022,22 +1489,24 @@ static unsigned int d965_5st_pin_configs[14] = {
 static unsigned int dell_3st_pin_configs[14] = {
        0x02211230, 0x02a11220, 0x01a19040, 0x01114210,
        0x01111212, 0x01116211, 0x01813050, 0x01112214,
-       0x403003fa, 0x40000100, 0x40000100, 0x404003fb,
+       0x403003fa, 0x90a60040, 0x90a60040, 0x404003fb,
        0x40c003fc, 0x40000100
 };
 
 static unsigned int *stac927x_brd_tbl[STAC_927X_MODELS] = {
-       [STAC_D965_REF] = ref927x_pin_configs,
-       [STAC_D965_3ST] = d965_3st_pin_configs,
-       [STAC_D965_5ST] = d965_5st_pin_configs,
-       [STAC_DELL_3ST] = dell_3st_pin_configs,
+       [STAC_D965_REF]  = ref927x_pin_configs,
+       [STAC_D965_3ST]  = d965_3st_pin_configs,
+       [STAC_D965_5ST]  = d965_5st_pin_configs,
+       [STAC_DELL_3ST]  = dell_3st_pin_configs,
+       [STAC_DELL_BIOS] = NULL,
 };
 
 static const char *stac927x_models[STAC_927X_MODELS] = {
-       [STAC_D965_REF] = "ref",
-       [STAC_D965_3ST] = "3stack",
-       [STAC_D965_5ST] = "5stack",
-       [STAC_DELL_3ST] = "dell-3stack",
+       [STAC_D965_REF]         = "ref",
+       [STAC_D965_3ST]         = "3stack",
+       [STAC_D965_5ST]         = "5stack",
+       [STAC_DELL_3ST]         = "dell-3stack",
+       [STAC_DELL_BIOS]        = "dell-bios",
 };
 
 static struct snd_pci_quirk stac927x_cfg_tbl[] = {
@@ -1064,13 +1533,21 @@ static struct snd_pci_quirk stac927x_cfg_tbl[] = {
        SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2003, "Intel D965", STAC_D965_3ST),
        SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2002, "Intel D965", STAC_D965_3ST),
        SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2001, "Intel D965", STAC_D965_3ST),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x01f3, "Dell Inspiron 1420", STAC_D965_3ST),
        /* Dell 3 stack systems */
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x01f7, "Dell XPS M1730", STAC_DELL_3ST),
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x01dd, "Dell Dimension E520", STAC_DELL_3ST),
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x01ed, "Dell     ", STAC_DELL_3ST),
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x01f4, "Dell     ", STAC_DELL_3ST),
+       /* Dell 3 stack systems with verb table in BIOS */
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x01f3, "Dell Inspiron 1420", STAC_DELL_BIOS),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x0227, "Dell Vostro 1400  ", STAC_DELL_BIOS),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x022f, "Dell     ", STAC_DELL_BIOS),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x022e, "Dell     ", STAC_DELL_BIOS),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x0242, "Dell     ", STAC_DELL_BIOS),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x0243, "Dell     ", STAC_DELL_BIOS),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x02ff, "Dell     ", STAC_DELL_BIOS),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x0209, "Dell XPS 1330", STAC_DELL_BIOS),
        /* 965 based 5 stack systems */
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x0209, "Dell XPS 1330", STAC_D965_5ST),
        SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2301, "Intel D965", STAC_D965_5ST),
        SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2302, "Intel D965", STAC_D965_5ST),
        SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2303, "Intel D965", STAC_D965_5ST),
@@ -1085,7 +1562,7 @@ static struct snd_pci_quirk stac927x_cfg_tbl[] = {
 
 static unsigned int ref9205_pin_configs[12] = {
        0x40000100, 0x40000100, 0x01016011, 0x01014010,
-       0x01813122, 0x01a19021, 0x40000100, 0x40000100,
+       0x01813122, 0x01a19021, 0x01019020, 0x40000100,
        0x90a000f0, 0x90a000f0, 0x01441030, 0x01c41030
 };
 
@@ -1097,6 +1574,7 @@ static unsigned int ref9205_pin_configs[12] = {
     102801FD
     10280204
     1028021F
+    10280228 (Dell Vostro 1500)
 */
 static unsigned int dell_9205_m42_pin_configs[12] = {
        0x0321101F, 0x03A11020, 0x400003FA, 0x90170310,
@@ -1180,6 +1658,8 @@ static struct snd_pci_quirk stac9205_cfg_tbl[] = {
                      "unknown Dell", STAC_9205_DELL_M42),
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021f,
                      "Dell Inspiron", STAC_9205_DELL_M44),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0228,
+                     "Dell Vostro 1500", STAC_9205_DELL_M42),
        {} /* terminator */
 };
 
@@ -1245,22 +1725,6 @@ static void stac92xx_set_config_regs(struct hda_codec *codec)
                                        spec->pin_configs[i]);
 }
 
-static void stac92xx_enable_gpio_mask(struct hda_codec *codec)
-{
-       struct sigmatel_spec *spec = codec->spec;
-       /* Configure GPIOx as output */
-       snd_hda_codec_write_cache(codec, codec->afg, 0,
-                                 AC_VERB_SET_GPIO_DIRECTION, spec->gpio_mask);
-       /* Configure GPIOx as CMOS */
-       snd_hda_codec_write_cache(codec, codec->afg, 0, 0x7e7, 0x00000000);
-       /* Assert GPIOx */
-       snd_hda_codec_write_cache(codec, codec->afg, 0,
-                                 AC_VERB_SET_GPIO_DATA, spec->gpio_data);
-       /* Enable GPIOx */
-       snd_hda_codec_write_cache(codec, codec->afg, 0,
-                                 AC_VERB_SET_GPIO_MASK, spec->gpio_mask);
-}
-
 /*
  * Analog playback callbacks
  */
@@ -1479,7 +1943,7 @@ static int stac92xx_io_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_
        struct sigmatel_spec *spec = codec->spec;
         hda_nid_t nid = kcontrol->private_value >> 8;
        int io_idx = kcontrol-> private_value & 0xff;
-        unsigned short val = ucontrol->value.integer.value[0];
+       unsigned short val = !!ucontrol->value.integer.value[0];
 
        spec->io_switch[io_idx] = val;
 
@@ -1491,6 +1955,13 @@ static int stac92xx_io_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_
                        pinctl |= stac92xx_get_vref(codec, nid);
                stac92xx_auto_set_pinctl(codec, nid, pinctl);
        }
+
+       /* check the auto-mute again: we need to mute/unmute the speaker
+        * appropriately according to the pin direction
+        */
+       if (spec->hp_detect)
+               codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
+
         return 1;
 }
 
@@ -1512,11 +1983,12 @@ static int stac92xx_clfe_switch_put(struct snd_kcontrol *kcontrol,
        struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
        struct sigmatel_spec *spec = codec->spec;
        hda_nid_t nid = kcontrol->private_value & 0xff;
+       unsigned int val = !!ucontrol->value.integer.value[0];
 
-       if (spec->clfe_swap == ucontrol->value.integer.value[0])
+       if (spec->clfe_swap == val)
                return 0;
 
-       spec->clfe_swap = ucontrol->value.integer.value[0];
+       spec->clfe_swap = val;
 
        snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE,
                spec->clfe_swap ? 0x4 : 0x0);
@@ -1547,6 +2019,7 @@ static int stac92xx_clfe_switch_put(struct snd_kcontrol *kcontrol,
 enum {
        STAC_CTL_WIDGET_VOL,
        STAC_CTL_WIDGET_MUTE,
+       STAC_CTL_WIDGET_MONO_MUX,
        STAC_CTL_WIDGET_IO_SWITCH,
        STAC_CTL_WIDGET_CLFE_SWITCH
 };
@@ -1554,6 +2027,7 @@ enum {
 static struct snd_kcontrol_new stac92xx_control_templates[] = {
        HDA_CODEC_VOLUME(NULL, 0, 0, 0),
        HDA_CODEC_MUTE(NULL, 0, 0, 0),
+       STAC_MONO_MUX,
        STAC_CODEC_IO_SWITCH(NULL, 0),
        STAC_CODEC_CLFE_SWITCH(NULL, 0),
 };
@@ -1598,6 +2072,7 @@ static int stac92xx_add_dyn_out_pins(struct hda_codec *codec, struct auto_pin_cf
        for (i = 0; i < codec->num_nodes; i++) {
                wcaps = codec->wcaps[i];
                wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
+
                if (wtype == AC_WID_AUD_OUT && !(wcaps & AC_WCAP_DIGITAL))
                        num_dacs++;
        }
@@ -1685,7 +2160,6 @@ static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec,
                        wcaps = snd_hda_param_read(codec, conn[j],
                                                   AC_PAR_AUDIO_WIDGET_CAP);
                        wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
-
                        if (wtype != AC_WID_AUD_OUT ||
                            (wcaps & AC_WCAP_DIGITAL))
                                continue;
@@ -1759,7 +2233,7 @@ static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec,
        int i, err;
 
        struct sigmatel_spec *spec = codec->spec;
-       unsigned int wid_caps;
+       unsigned int wid_caps, pincap;
 
 
        for (i = 0; i < cfg->line_outs; i++) {
@@ -1795,13 +2269,39 @@ static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec,
                }
        }
 
-       if (spec->line_switch)
-               if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_IO_SWITCH, "Line In as Output Switch", cfg->input_pins[AUTO_PIN_LINE] << 8)) < 0)
-                       return err;
+       if (spec->line_switch) {
+               nid = cfg->input_pins[AUTO_PIN_LINE];
+               pincap = snd_hda_param_read(codec, nid,
+                                               AC_PAR_PIN_CAP);
+               if (pincap & AC_PINCAP_OUT) {
+                       err = stac92xx_add_control(spec,
+                               STAC_CTL_WIDGET_IO_SWITCH,
+                               "Line In as Output Switch", nid << 8);
+                       if (err < 0)
+                               return err;
+               }
+       }
 
-       if (spec->mic_switch)
-               if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_IO_SWITCH, "Mic as Output Switch", (cfg->input_pins[AUTO_PIN_MIC] << 8) | 1)) < 0)
-                       return err;
+       if (spec->mic_switch) {
+               unsigned int def_conf;
+               nid = cfg->input_pins[AUTO_PIN_MIC];
+               def_conf = snd_hda_codec_read(codec, nid, 0,
+                                               AC_VERB_GET_CONFIG_DEFAULT, 0);
+
+               /* some laptops have an internal analog microphone
+                * which can't be used as a output */
+               if (get_defcfg_connect(def_conf) != AC_JACK_PORT_FIXED) {
+                       pincap = snd_hda_param_read(codec, nid,
+                                                       AC_PAR_PIN_CAP);
+                       if (pincap & AC_PINCAP_OUT) {
+                               err = stac92xx_add_control(spec,
+                                       STAC_CTL_WIDGET_IO_SWITCH,
+                                       "Mic as Output Switch", (nid << 8) | 1);
+                               if (err < 0)
+                                       return err;
+                       }
+               }
+       }
 
        return 0;
 }
@@ -1891,6 +2391,37 @@ static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec,
        return 0;
 }
 
+/* labels for mono mux outputs */
+static const char *stac92xx_mono_labels[3] = {
+       "DAC0", "DAC1", "Mixer"
+};
+
+/* create mono mux for mono out on capable codecs */
+static int stac92xx_auto_create_mono_output_ctls(struct hda_codec *codec)
+{
+       struct sigmatel_spec *spec = codec->spec;
+       struct hda_input_mux *mono_mux = &spec->private_mono_mux;
+       int i, num_cons;
+       hda_nid_t con_lst[ARRAY_SIZE(stac92xx_mono_labels)];
+
+       num_cons = snd_hda_get_connections(codec,
+                               spec->mono_nid,
+                               con_lst,
+                               HDA_MAX_NUM_INPUTS);
+       if (!num_cons || num_cons > ARRAY_SIZE(stac92xx_mono_labels))
+               return -EINVAL;
+
+       for (i = 0; i < num_cons; i++) {
+               mono_mux->items[mono_mux->num_items].label =
+                                       stac92xx_mono_labels[i];
+               mono_mux->items[mono_mux->num_items].index = i;
+               mono_mux->num_items++;
+       }
+
+       return stac92xx_add_control(spec, STAC_CTL_WIDGET_MONO_MUX,
+                               "Mono Mux", spec->mono_nid);
+}
+
 /* labels for dmic mux inputs */
 static const char *stac92xx_dmic_labels[5] = {
        "Analog Inputs", "Digital Mic 1", "Digital Mic 2",
@@ -1904,15 +2435,18 @@ static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec,
        struct sigmatel_spec *spec = codec->spec;
        struct hda_input_mux *dimux = &spec->private_dimux;
        hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];
-       int i, j;
+       int err, i, j;
+       char name[32];
 
        dimux->items[dimux->num_items].label = stac92xx_dmic_labels[0];
        dimux->items[dimux->num_items].index = 0;
        dimux->num_items++;
 
        for (i = 0; i < spec->num_dmics; i++) {
+               hda_nid_t nid;
                int index;
                int num_cons;
+               unsigned int wcaps;
                unsigned int def_conf;
 
                def_conf = snd_hda_codec_read(codec,
@@ -1923,17 +2457,32 @@ static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec,
                if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE)
                        continue;
 
+               nid = spec->dmic_nids[i];
                num_cons = snd_hda_get_connections(codec,
-                               spec->dmux_nid,
+                               spec->dmux_nids[0],
                                con_lst,
                                HDA_MAX_NUM_INPUTS);
                for (j = 0; j < num_cons; j++)
-                       if (con_lst[j] == spec->dmic_nids[i]) {
+                       if (con_lst[j] == nid) {
                                index = j;
                                goto found;
                        }
                continue;
 found:
+               wcaps = get_wcaps(codec, nid);
+
+               if (wcaps & AC_WCAP_OUT_AMP) {
+                       sprintf(name, "%s Capture Volume",
+                               stac92xx_dmic_labels[dimux->num_items]);
+
+                       err = stac92xx_add_control(spec,
+                               STAC_CTL_WIDGET_VOL,
+                               name,
+                               HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
+                       if (err < 0)
+                               return err;
+               }
+
                dimux->items[dimux->num_items].label =
                        stac92xx_dmic_labels[dimux->num_items];
                dimux->items[dimux->num_items].index = index;
@@ -2026,6 +2575,7 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out
 {
        struct sigmatel_spec *spec = codec->spec;
        int err;
+       int hp_speaker_swap = 0;
 
        if ((err = snd_hda_parse_pin_def_config(codec,
                                                &spec->autocfg,
@@ -2034,6 +2584,68 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out
        if (! spec->autocfg.line_outs)
                return 0; /* can't find valid pin config */
 
+       /* If we have no real line-out pin and multiple hp-outs, HPs should
+        * be set up as multi-channel outputs.
+        */
+       if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT &&
+           spec->autocfg.hp_outs > 1) {
+               /* Copy hp_outs to line_outs, backup line_outs in
+                * speaker_outs so that the following routines can handle
+                * HP pins as primary outputs.
+                */
+               memcpy(spec->autocfg.speaker_pins, spec->autocfg.line_out_pins,
+                      sizeof(spec->autocfg.line_out_pins));
+               spec->autocfg.speaker_outs = spec->autocfg.line_outs;
+               memcpy(spec->autocfg.line_out_pins, spec->autocfg.hp_pins,
+                      sizeof(spec->autocfg.hp_pins));
+               spec->autocfg.line_outs = spec->autocfg.hp_outs;
+               hp_speaker_swap = 1;
+       }
+       if (spec->autocfg.mono_out_pin) {
+               int dir = (get_wcaps(codec, spec->autocfg.mono_out_pin)
+                               & AC_WCAP_OUT_AMP) ? HDA_OUTPUT : HDA_INPUT;
+               u32 caps = query_amp_caps(codec,
+                               spec->autocfg.mono_out_pin, dir);
+               hda_nid_t conn_list[1];
+
+               /* get the mixer node and then the mono mux if it exists */
+               if (snd_hda_get_connections(codec,
+                               spec->autocfg.mono_out_pin, conn_list, 1) &&
+                               snd_hda_get_connections(codec, conn_list[0],
+                               conn_list, 1)) {
+
+                               int wcaps = get_wcaps(codec, conn_list[0]);
+                               int wid_type = (wcaps & AC_WCAP_TYPE)
+                                       >> AC_WCAP_TYPE_SHIFT;
+                               /* LR swap check, some stac925x have a mux that
+                                * changes the DACs output path instead of the
+                                * mono-mux path.
+                                */
+                               if (wid_type == AC_WID_AUD_SEL &&
+                                               !(wcaps & AC_WCAP_LR_SWAP))
+                                       spec->mono_nid = conn_list[0];
+               }
+               /* all mono outs have a least a mute/unmute switch */
+               err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE,
+                       "Mono Playback Switch",
+                       HDA_COMPOSE_AMP_VAL(spec->autocfg.mono_out_pin,
+                                       1, 0, dir));
+               if (err < 0)
+                       return err;
+               /* check to see if there is volume support for the amp */
+               if ((caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT) {
+                       err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL,
+                               "Mono Playback Volume",
+                               HDA_COMPOSE_AMP_VAL(spec->autocfg.mono_out_pin,
+                                       1, 0, dir));
+                       if (err < 0)
+                               return err;
+               }
+
+               stac92xx_auto_set_pinctl(codec, spec->autocfg.mono_out_pin,
+                                        AC_PINCTL_OUT_EN);
+       }
+
        if ((err = stac92xx_add_dyn_out_pins(codec, &spec->autocfg)) < 0)
                return err;
        if (spec->multiout.num_dacs == 0)
@@ -2045,6 +2657,19 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out
        if (err < 0)
                return err;
 
+       if (hp_speaker_swap == 1) {
+               /* Restore the hp_outs and line_outs */
+               memcpy(spec->autocfg.hp_pins, spec->autocfg.line_out_pins,
+                      sizeof(spec->autocfg.line_out_pins));
+               spec->autocfg.hp_outs = spec->autocfg.line_outs;
+               memcpy(spec->autocfg.line_out_pins, spec->autocfg.speaker_pins,
+                      sizeof(spec->autocfg.speaker_pins));
+               spec->autocfg.line_outs = spec->autocfg.speaker_outs;
+               memset(spec->autocfg.speaker_pins, 0,
+                      sizeof(spec->autocfg.speaker_pins));
+               spec->autocfg.speaker_outs = 0;
+       }
+
        err = stac92xx_auto_create_hp_ctls(codec, &spec->autocfg);
 
        if (err < 0)
@@ -2055,6 +2680,12 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out
        if (err < 0)
                return err;
 
+       if (spec->mono_nid > 0) {
+               err = stac92xx_auto_create_mono_output_ctls(codec);
+               if (err < 0)
+                       return err;
+       }
+
        if (spec->num_dmics > 0)
                if ((err = stac92xx_auto_create_dmic_input_ctls(codec,
                                                &spec->autocfg)) < 0)
@@ -2073,7 +2704,9 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out
                spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
 
        spec->input_mux = &spec->private_imux;
-       spec->dinput_mux = &spec->private_dimux;
+       if (!spec->dinput_mux)
+               spec->dinput_mux = &spec->private_dimux;
+       spec->mono_mux = &spec->private_mono_mux;
 
        return 1;
 }
@@ -2183,38 +2816,35 @@ static int stac9200_parse_auto_config(struct hda_codec *codec)
  * funky external mute control using GPIO pins.
  */
 
-static void stac922x_gpio_mute(struct hda_codec *codec, int pin, int muted)
+static void stac_gpio_set(struct hda_codec *codec, unsigned int mask,
+                         unsigned int dir_mask, unsigned int data)
 {
        unsigned int gpiostate, gpiomask, gpiodir;
 
        gpiostate = snd_hda_codec_read(codec, codec->afg, 0,
                                       AC_VERB_GET_GPIO_DATA, 0);
-
-       if (!muted)
-               gpiostate |= (1 << pin);
-       else
-               gpiostate &= ~(1 << pin);
+       gpiostate = (gpiostate & ~dir_mask) | (data & dir_mask);
 
        gpiomask = snd_hda_codec_read(codec, codec->afg, 0,
                                      AC_VERB_GET_GPIO_MASK, 0);
-       gpiomask |= (1 << pin);
+       gpiomask |= mask;
 
        gpiodir = snd_hda_codec_read(codec, codec->afg, 0,
                                     AC_VERB_GET_GPIO_DIRECTION, 0);
-       gpiodir |= (1 << pin);
+       gpiodir |= dir_mask;
 
-       /* AppleHDA seems to do this -- WTF is this verb?? */
+       /* Configure GPIOx as CMOS */
        snd_hda_codec_write(codec, codec->afg, 0, 0x7e7, 0);
 
        snd_hda_codec_write(codec, codec->afg, 0,
                            AC_VERB_SET_GPIO_MASK, gpiomask);
-       snd_hda_codec_write(codec, codec->afg, 0,
-                           AC_VERB_SET_GPIO_DIRECTION, gpiodir);
+       snd_hda_codec_read(codec, codec->afg, 0,
+                          AC_VERB_SET_GPIO_DIRECTION, gpiodir); /* sync */
 
        msleep(1);
 
-       snd_hda_codec_write(codec, codec->afg, 0,
-                           AC_VERB_SET_GPIO_DATA, gpiostate);
+       snd_hda_codec_read(codec, codec->afg, 0,
+                          AC_VERB_SET_GPIO_DATA, gpiostate); /* sync */
 }
 
 static void enable_pin_detect(struct hda_codec *codec, hda_nid_t nid,
@@ -2226,6 +2856,16 @@ static void enable_pin_detect(struct hda_codec *codec, hda_nid_t nid,
                                          (AC_USRSP_EN | event));
 }
 
+static int is_nid_hp_pin(struct auto_pin_cfg *cfg, hda_nid_t nid)
+{
+       int i;
+       for (i = 0; i < cfg->hp_outs; i++)
+               if (cfg->hp_pins[i] == nid)
+                       return 1; /* nid is a HP-Out */
+
+       return 0; /* nid is not a HP-Out */
+};
+
 static int stac92xx_init(struct hda_codec *codec)
 {
        struct sigmatel_spec *spec = codec->spec;
@@ -2261,10 +2901,23 @@ static int stac92xx_init(struct hda_codec *codec)
                        stac92xx_auto_set_pinctl(codec, nid, pinctl);
                }
        }
-       if (spec->num_dmics > 0)
-               for (i = 0; i < spec->num_dmics; i++)
-                       stac92xx_auto_set_pinctl(codec, spec->dmic_nids[i],
-                                                AC_PINCTL_IN_EN);
+       for (i = 0; i < spec->num_dmics; i++)
+               stac92xx_auto_set_pinctl(codec, spec->dmic_nids[i],
+                                       AC_PINCTL_IN_EN);
+       for (i = 0; i < spec->num_pwrs; i++)  {
+               int event = is_nid_hp_pin(cfg, spec->pwr_nids[i])
+                                       ? STAC_HP_EVENT : STAC_PWR_EVENT;
+               int pinctl = snd_hda_codec_read(codec, spec->pwr_nids[i],
+                                       0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
+               /* outputs are only ports capable of power management
+                * any attempts on powering down a input port cause the
+                * referenced VREF to act quirky.
+                */
+               if (pinctl & AC_PINCTL_IN_EN)
+                       continue;
+               enable_pin_detect(codec, spec->pwr_nids[i], event | i);
+               codec->patch_ops.unsol_event(codec, (event | i) << 26);
+       }
 
        if (cfg->dig_out_pin)
                stac92xx_auto_set_pinctl(codec, cfg->dig_out_pin,
@@ -2273,10 +2926,8 @@ static int stac92xx_init(struct hda_codec *codec)
                stac92xx_auto_set_pinctl(codec, cfg->dig_in_pin,
                                         AC_PINCTL_IN_EN);
 
-       if (spec->gpio_mute) {
-               stac922x_gpio_mute(codec, 0, 0);
-               stac922x_gpio_mute(codec, 1, 0);
-       }
+       stac_gpio_set(codec, spec->gpio_mask,
+                                       spec->gpio_dir, spec->gpio_data);
 
        return 0;
 }
@@ -2342,13 +2993,20 @@ static void stac92xx_reset_pinctl(struct hda_codec *codec, hda_nid_t nid,
                        pin_ctl & ~flag);
 }
 
-static int get_pin_presence(struct hda_codec *codec, hda_nid_t nid)
+static int get_hp_pin_presence(struct hda_codec *codec, hda_nid_t nid)
 {
        if (!nid)
                return 0;
        if (snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_SENSE, 0x00)
-           & (1 << 31))
-               return 1;
+           & (1 << 31)) {
+               unsigned int pinctl;
+               pinctl = snd_hda_codec_read(codec, nid, 0,
+                                           AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
+               if (pinctl & AC_PINCTL_IN_EN)
+                       return 0; /* mic- or line-input */
+               else
+                       return 1; /* HP-output */
+       }
        return 0;
 }
 
@@ -2359,10 +3017,14 @@ static void stac92xx_hp_detect(struct hda_codec *codec, unsigned int res)
        int i, presence;
 
        presence = 0;
+       if (spec->gpio_mute)
+               presence = !(snd_hda_codec_read(codec, codec->afg, 0,
+                       AC_VERB_GET_GPIO_DATA, 0) & spec->gpio_mute);
+
        for (i = 0; i < cfg->hp_outs; i++) {
-               presence = get_pin_presence(codec, cfg->hp_pins[i]);
                if (presence)
                        break;
+               presence = get_hp_pin_presence(codec, cfg->hp_pins[i]);
        }
 
        if (presence) {
@@ -2384,12 +3046,37 @@ static void stac92xx_hp_detect(struct hda_codec *codec, unsigned int res)
        }
 } 
 
+static void stac92xx_pin_sense(struct hda_codec *codec, int idx)
+{
+       struct sigmatel_spec *spec = codec->spec;
+       hda_nid_t nid = spec->pwr_nids[idx];
+       int presence, val;
+       val = snd_hda_codec_read(codec, codec->afg, 0, 0x0fec, 0x0)
+                                                       & 0x000000ff;
+       presence = get_hp_pin_presence(codec, nid);
+       idx = 1 << idx;
+
+       if (presence)
+               val &= ~idx;
+       else
+               val |= idx;
+
+       /* power down unused output ports */
+       snd_hda_codec_write(codec, codec->afg, 0, 0x7ec, val);
+};
+
 static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res)
 {
-       switch (res >> 26) {
+       struct sigmatel_spec *spec = codec->spec;
+       int idx = res >> 26 & 0x0f;
+
+       switch ((res >> 26) & 0x30) {
        case STAC_HP_EVENT:
                stac92xx_hp_detect(codec, res);
-               break;
+               /* fallthru */
+       case STAC_PWR_EVENT:
+               if (spec->num_pwrs > 0)
+                       stac92xx_pin_sense(codec, idx);
        }
 }
 
@@ -2400,10 +3087,8 @@ static int stac92xx_resume(struct hda_codec *codec)
 
        stac92xx_set_config_regs(codec);
        snd_hda_sequence_write(codec, spec->init);
-       if (spec->gpio_mute) {
-               stac922x_gpio_mute(codec, 0, 0);
-               stac922x_gpio_mute(codec, 1, 0);
-       }
+       stac_gpio_set(codec, spec->gpio_mask,
+               spec->gpio_dir, spec->gpio_data);
        snd_hda_codec_resume_amp(codec);
        snd_hda_codec_resume_cache(codec);
        /* invoke unsolicited event to reset the HP state */
@@ -2460,6 +3145,7 @@ static int patch_stac9200(struct hda_codec *codec)
        spec->num_muxes = 1;
        spec->num_dmics = 0;
        spec->num_adcs = 1;
+       spec->num_pwrs = 0;
 
        if (spec->board_config == STAC_9200_GATEWAY)
                spec->init = stac9200_eapd_init;
@@ -2515,6 +3201,7 @@ static int patch_stac925x(struct hda_codec *codec)
        spec->mux_nids = stac925x_mux_nids;
        spec->num_muxes = 1;
        spec->num_adcs = 1;
+       spec->num_pwrs = 0;
        switch (codec->vendor_id) {
        case 0x83847632: /* STAC9202  */
        case 0x83847633: /* STAC9202D */
@@ -2522,6 +3209,8 @@ static int patch_stac925x(struct hda_codec *codec)
        case 0x83847637: /* STAC9251D */
                spec->num_dmics = STAC925X_NUM_DMICS;
                spec->dmic_nids = stac925x_dmic_nids;
+               spec->num_dmuxes = ARRAY_SIZE(stac925x_dmux_nids);
+               spec->dmux_nids = stac925x_dmux_nids;
                break;
        default:
                spec->num_dmics = 0;
@@ -2551,6 +3240,204 @@ static int patch_stac925x(struct hda_codec *codec)
        return 0;
 }
 
+static struct hda_input_mux stac92hd73xx_dmux = {
+       .num_items = 4,
+       .items = {
+               { "Analog Inputs", 0x0b },
+               { "CD", 0x08 },
+               { "Digital Mic 1", 0x09 },
+               { "Digital Mic 2", 0x0a },
+       }
+};
+
+static int patch_stac92hd73xx(struct hda_codec *codec)
+{
+       struct sigmatel_spec *spec;
+       hda_nid_t conn[STAC92HD73_DAC_COUNT + 2];
+       int err = 0;
+
+       spec  = kzalloc(sizeof(*spec), GFP_KERNEL);
+       if (spec == NULL)
+               return -ENOMEM;
+
+       codec->spec = spec;
+       spec->num_pins = ARRAY_SIZE(stac92hd73xx_pin_nids);
+       spec->pin_nids = stac92hd73xx_pin_nids;
+       spec->board_config = snd_hda_check_board_config(codec,
+                                                       STAC_92HD73XX_MODELS,
+                                                       stac92hd73xx_models,
+                                                       stac92hd73xx_cfg_tbl);
+again:
+       if (spec->board_config < 0) {
+               snd_printdd(KERN_INFO "hda_codec: Unknown model for"
+                       " STAC92HD73XX, using BIOS defaults\n");
+               err = stac92xx_save_bios_config_regs(codec);
+               if (err < 0) {
+                       stac92xx_free(codec);
+                       return err;
+               }
+               spec->pin_configs = spec->bios_pin_configs;
+       } else {
+               spec->pin_configs = stac92hd73xx_brd_tbl[spec->board_config];
+               stac92xx_set_config_regs(codec);
+       }
+
+       spec->multiout.num_dacs = snd_hda_get_connections(codec, 0x0a,
+                       conn, STAC92HD73_DAC_COUNT + 2) - 1;
+
+       if (spec->multiout.num_dacs < 0) {
+               printk(KERN_WARNING "hda_codec: Could not determine "
+                      "number of channels defaulting to DAC count\n");
+               spec->multiout.num_dacs = STAC92HD73_DAC_COUNT;
+       }
+
+       switch (spec->multiout.num_dacs) {
+       case 0x3: /* 6 Channel */
+               spec->mixer = stac92hd73xx_6ch_mixer;
+               spec->init = stac92hd73xx_6ch_core_init;
+               break;
+       case 0x4: /* 8 Channel */
+               spec->multiout.hp_nid = 0x18;
+               spec->mixer = stac92hd73xx_8ch_mixer;
+               spec->init = stac92hd73xx_8ch_core_init;
+               break;
+       case 0x5: /* 10 Channel */
+               spec->multiout.hp_nid = 0x19;
+               spec->mixer = stac92hd73xx_10ch_mixer;
+               spec->init = stac92hd73xx_10ch_core_init;
+       };
+
+       spec->multiout.dac_nids = stac92hd73xx_dac_nids;
+       spec->aloopback_mask = 0x01;
+       spec->aloopback_shift = 8;
+
+       spec->mux_nids = stac92hd73xx_mux_nids;
+       spec->adc_nids = stac92hd73xx_adc_nids;
+       spec->dmic_nids = stac92hd73xx_dmic_nids;
+       spec->dmux_nids = stac92hd73xx_dmux_nids;
+
+       spec->num_muxes = ARRAY_SIZE(stac92hd73xx_mux_nids);
+       spec->num_adcs = ARRAY_SIZE(stac92hd73xx_adc_nids);
+       spec->num_dmics = STAC92HD73XX_NUM_DMICS;
+       spec->num_dmuxes = ARRAY_SIZE(stac92hd73xx_dmux_nids);
+       spec->dinput_mux = &stac92hd73xx_dmux;
+       /* GPIO0 High = Enable EAPD */
+       spec->gpio_mask = spec->gpio_dir = 0x1;
+       spec->gpio_data = 0x01;
+
+       spec->num_pwrs = ARRAY_SIZE(stac92hd73xx_pwr_nids);
+       spec->pwr_nids = stac92hd73xx_pwr_nids;
+
+       err = stac92xx_parse_auto_config(codec, 0x22, 0x24);
+
+       if (!err) {
+               if (spec->board_config < 0) {
+                       printk(KERN_WARNING "hda_codec: No auto-config is "
+                              "available, default to model=ref\n");
+                       spec->board_config = STAC_92HD73XX_REF;
+                       goto again;
+               }
+               err = -EINVAL;
+       }
+
+       if (err < 0) {
+               stac92xx_free(codec);
+               return err;
+       }
+
+       codec->patch_ops = stac92xx_patch_ops;
+
+       return 0;
+}
+
+static int patch_stac92hd71bxx(struct hda_codec *codec)
+{
+       struct sigmatel_spec *spec;
+       int err = 0;
+
+       spec  = kzalloc(sizeof(*spec), GFP_KERNEL);
+       if (spec == NULL)
+               return -ENOMEM;
+
+       codec->spec = spec;
+       spec->num_pins = ARRAY_SIZE(stac92hd71bxx_pin_nids);
+       spec->pin_nids = stac92hd71bxx_pin_nids;
+       spec->board_config = snd_hda_check_board_config(codec,
+                                                       STAC_92HD71BXX_MODELS,
+                                                       stac92hd71bxx_models,
+                                                       stac92hd71bxx_cfg_tbl);
+again:
+       if (spec->board_config < 0) {
+               snd_printdd(KERN_INFO "hda_codec: Unknown model for"
+                       " STAC92HD71BXX, using BIOS defaults\n");
+               err = stac92xx_save_bios_config_regs(codec);
+               if (err < 0) {
+                       stac92xx_free(codec);
+                       return err;
+               }
+               spec->pin_configs = spec->bios_pin_configs;
+       } else {
+               spec->pin_configs = stac92hd71bxx_brd_tbl[spec->board_config];
+               stac92xx_set_config_regs(codec);
+       }
+
+       switch (codec->vendor_id) {
+       case 0x111d76b6: /* 4 Port without Analog Mixer */
+       case 0x111d76b7:
+       case 0x111d76b4: /* 6 Port without Analog Mixer */
+       case 0x111d76b5:
+               spec->mixer = stac92hd71bxx_mixer;
+               spec->init = stac92hd71bxx_core_init;
+               break;
+       default:
+               spec->mixer = stac92hd71bxx_analog_mixer;
+               spec->init = stac92hd71bxx_analog_core_init;
+       }
+
+       spec->aloopback_mask = 0x20;
+       spec->aloopback_shift = 0;
+
+       /* GPIO0 High = EAPD */
+       spec->gpio_mask = spec->gpio_dir = spec->gpio_data = 0x1;
+
+       spec->mux_nids = stac92hd71bxx_mux_nids;
+       spec->adc_nids = stac92hd71bxx_adc_nids;
+       spec->dmic_nids = stac92hd71bxx_dmic_nids;
+       spec->dmux_nids = stac92hd71bxx_dmux_nids;
+
+       spec->num_muxes = ARRAY_SIZE(stac92hd71bxx_mux_nids);
+       spec->num_adcs = ARRAY_SIZE(stac92hd71bxx_adc_nids);
+       spec->num_dmics = STAC92HD71BXX_NUM_DMICS;
+       spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids);
+
+       spec->num_pwrs = ARRAY_SIZE(stac92hd71bxx_pwr_nids);
+       spec->pwr_nids = stac92hd71bxx_pwr_nids;
+
+       spec->multiout.num_dacs = 2;
+       spec->multiout.hp_nid = 0x11;
+       spec->multiout.dac_nids = stac92hd71bxx_dac_nids;
+
+       err = stac92xx_parse_auto_config(codec, 0x21, 0x23);
+       if (!err) {
+               if (spec->board_config < 0) {
+                       printk(KERN_WARNING "hda_codec: No auto-config is "
+                              "available, default to model=ref\n");
+                       spec->board_config = STAC_92HD71BXX_REF;
+                       goto again;
+               }
+               err = -EINVAL;
+       }
+
+       if (err < 0) {
+               stac92xx_free(codec);
+               return err;
+       }
+
+       codec->patch_ops = stac92xx_patch_ops;
+
+       return 0;
+};
+
 static int patch_stac922x(struct hda_codec *codec)
 {
        struct sigmatel_spec *spec;
@@ -2567,7 +3454,8 @@ static int patch_stac922x(struct hda_codec *codec)
                                                        stac922x_models,
                                                        stac922x_cfg_tbl);
        if (spec->board_config == STAC_INTEL_MAC_V3) {
-               spec->gpio_mute = 1;
+               spec->gpio_mask = spec->gpio_dir = 0x03;
+               spec->gpio_data = 0x03;
                /* Intel Macs have all same PCI SSID, so we need to check
                 * codec SSID to distinguish the exact models
                 */
@@ -2620,6 +3508,7 @@ static int patch_stac922x(struct hda_codec *codec)
        spec->num_muxes = ARRAY_SIZE(stac922x_mux_nids);
        spec->num_adcs = ARRAY_SIZE(stac922x_adc_nids);
        spec->num_dmics = 0;
+       spec->num_pwrs = 0;
 
        spec->init = stac922x_core_init;
        spec->mixer = stac922x_mixer;
@@ -2669,53 +3558,70 @@ static int patch_stac927x(struct hda_codec *codec)
                                                        stac927x_models,
                                                        stac927x_cfg_tbl);
  again:
-       if (spec->board_config < 0) {
-                snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC927x, using BIOS defaults\n");
+       if (spec->board_config < 0 || !stac927x_brd_tbl[spec->board_config]) {
+               if (spec->board_config < 0)
+                       snd_printdd(KERN_INFO "hda_codec: Unknown model for"
+                                   "STAC927x, using BIOS defaults\n");
                err = stac92xx_save_bios_config_regs(codec);
                if (err < 0) {
                        stac92xx_free(codec);
                        return err;
                }
                spec->pin_configs = spec->bios_pin_configs;
-       } else if (stac927x_brd_tbl[spec->board_config] != NULL) {
+       } else {
                spec->pin_configs = stac927x_brd_tbl[spec->board_config];
                stac92xx_set_config_regs(codec);
        }
 
+       spec->adc_nids = stac927x_adc_nids;
+       spec->num_adcs = ARRAY_SIZE(stac927x_adc_nids);
+       spec->mux_nids = stac927x_mux_nids;
+       spec->num_muxes = ARRAY_SIZE(stac927x_mux_nids);
+       spec->multiout.dac_nids = spec->dac_nids;
+
        switch (spec->board_config) {
        case STAC_D965_3ST:
-               spec->adc_nids = stac927x_adc_nids;
-               spec->mux_nids = stac927x_mux_nids;
-               spec->num_muxes = ARRAY_SIZE(stac927x_mux_nids);
-               spec->num_adcs = ARRAY_SIZE(stac927x_adc_nids);
+       case STAC_D965_5ST:
+               /* GPIO0 High = Enable EAPD */
+               spec->gpio_mask = spec->gpio_dir = 0x01;
+               spec->gpio_data = 0x01;
                spec->num_dmics = 0;
+
                spec->init = d965_core_init;
                spec->mixer = stac927x_mixer;
                break;
-       case STAC_D965_5ST:
-               spec->adc_nids = stac927x_adc_nids;
-               spec->mux_nids = stac927x_mux_nids;
-               spec->num_muxes = ARRAY_SIZE(stac927x_mux_nids);
-               spec->num_adcs = ARRAY_SIZE(stac927x_adc_nids);
-               spec->num_dmics = 0;
+       case STAC_DELL_BIOS:
+               /* correct the front output jack as a hp out */
+               stac92xx_set_config_reg(codec, 0x0f, 0x02270110);
+               /* correct the front input jack as a mic */
+               stac92xx_set_config_reg(codec, 0x0e, 0x02a79130);
+               /* fallthru */
+       case STAC_DELL_3ST:
+               /* GPIO2 High = Enable EAPD */
+               spec->gpio_mask = spec->gpio_dir = 0x04;
+               spec->gpio_data = 0x04;
+               spec->dmic_nids = stac927x_dmic_nids;
+               spec->num_dmics = STAC927X_NUM_DMICS;
+
                spec->init = d965_core_init;
                spec->mixer = stac927x_mixer;
+               spec->dmux_nids = stac927x_dmux_nids;
+               spec->num_dmuxes = ARRAY_SIZE(stac927x_dmux_nids);
                break;
        default:
-               spec->adc_nids = stac927x_adc_nids;
-               spec->mux_nids = stac927x_mux_nids;
-               spec->num_muxes = ARRAY_SIZE(stac927x_mux_nids);
-               spec->num_adcs = ARRAY_SIZE(stac927x_adc_nids);
+               /* GPIO0 High = Enable EAPD */
+               spec->gpio_mask = spec->gpio_dir = 0x1;
+               spec->gpio_data = 0x01;
                spec->num_dmics = 0;
+
                spec->init = stac927x_core_init;
                spec->mixer = stac927x_mixer;
        }
 
-       spec->multiout.dac_nids = spec->dac_nids;
-       /* GPIO0 High = Enable EAPD */
-       spec->gpio_mask = spec->gpio_data = 0x00000001;
-       stac92xx_enable_gpio_mask(codec); 
-       
+       spec->num_pwrs = 0;
+       spec->aloopback_mask = 0x40;
+       spec->aloopback_shift = 0;
+
        err = stac92xx_parse_auto_config(codec, 0x1e, 0x20);
        if (!err) {
                if (spec->board_config < 0) {
@@ -2733,6 +3639,18 @@ static int patch_stac927x(struct hda_codec *codec)
 
        codec->patch_ops = stac92xx_patch_ops;
 
+       /*
+        * !!FIXME!!
+        * The STAC927x seem to require fairly long delays for certain
+        * command sequences.  With too short delays (even if the answer
+        * is set to RIRB properly), it results in the silence output
+        * on some hardwares like Dell.
+        *
+        * The below flag enables the longer delay (see get_response
+        * in hda_intel.c).
+        */
+       codec->bus->needs_damn_long_delay = 1;
+
        return 0;
 }
 
@@ -2771,11 +3689,15 @@ static int patch_stac9205(struct hda_codec *codec)
        spec->num_muxes = ARRAY_SIZE(stac9205_mux_nids);
        spec->dmic_nids = stac9205_dmic_nids;
        spec->num_dmics = STAC9205_NUM_DMICS;
-       spec->dmux_nid = 0x1d;
+       spec->dmux_nids = stac9205_dmux_nids;
+       spec->num_dmuxes = ARRAY_SIZE(stac9205_dmux_nids);
+       spec->num_pwrs = 0;
 
        spec->init = stac9205_core_init;
        spec->mixer = stac9205_mixer;
 
+       spec->aloopback_mask = 0x40;
+       spec->aloopback_shift = 0;
        spec->multiout.dac_nids = spec->dac_nids;
        
        switch (spec->board_config){
@@ -2784,19 +3706,28 @@ static int patch_stac9205(struct hda_codec *codec)
                stac92xx_set_config_reg(codec, 0x1f, 0x01441030);
                stac92xx_set_config_reg(codec, 0x20, 0x1c410030);
 
-               spec->gpio_mask = 0x00000007; /* GPIO0-2 */
-               /* GPIO0 High = EAPD, GPIO1 Low = DRM,
-                * GPIO2 High = Headphone Mute
+               /* Enable unsol response for GPIO4/Dock HP connection */
+               snd_hda_codec_write(codec, codec->afg, 0,
+                       AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x10);
+               snd_hda_codec_write_cache(codec, codec->afg, 0,
+                                         AC_VERB_SET_UNSOLICITED_ENABLE,
+                                         (AC_USRSP_EN | STAC_HP_EVENT));
+
+               spec->gpio_dir = 0x0b;
+               spec->gpio_mask = 0x1b;
+               spec->gpio_mute = 0x10;
+               /* GPIO0 High = EAPD, GPIO1 Low = Headphone Mute,
+                * GPIO3 Low = DRM
                 */
-               spec->gpio_data = 0x00000005;
+               spec->gpio_data = 0x01;
                break;
        default:
                /* GPIO0 High = EAPD */
-               spec->gpio_mask = spec->gpio_data = 0x00000001;
+               spec->gpio_mask = spec->gpio_dir = 0x1;
+               spec->gpio_data = 0x01;
                break;
        }
 
-       stac92xx_enable_gpio_mask(codec);
        err = stac92xx_parse_auto_config(codec, 0x1f, 0x20);
        if (!err) {
                if (spec->board_config < 0) {
@@ -2950,7 +3881,7 @@ static int stac9872_vaio_init(struct hda_codec *codec)
 
 static void stac9872_vaio_hp_detect(struct hda_codec *codec, unsigned int res)
 {
-       if (get_pin_presence(codec, 0x0a)) {
+       if (get_hp_pin_presence(codec, 0x0a)) {
                stac92xx_reset_pinctl(codec, 0x0f, AC_PINCTL_OUT_EN);
                stac92xx_set_pinctl(codec, 0x0a, AC_PINCTL_OUT_EN);
        } else {
@@ -3032,6 +3963,7 @@ static int patch_stac9872(struct hda_codec *codec)
                spec->multiout.hp_nid = VAIO_HP_DAC;
                spec->num_adcs = ARRAY_SIZE(vaio_adcs);
                spec->adc_nids = vaio_adcs;
+               spec->num_pwrs = 0;
                spec->input_mux = &vaio_mux;
                spec->mux_nids = vaio_mux_nids;
                codec->patch_ops = stac9872_vaio_patch_ops;
@@ -3045,6 +3977,7 @@ static int patch_stac9872(struct hda_codec *codec)
                spec->multiout.dac_nids = vaio_dacs;
                spec->multiout.hp_nid = VAIO_HP_DAC;
                spec->num_adcs = ARRAY_SIZE(vaio_adcs);
+               spec->num_pwrs = 0;
                spec->adc_nids = vaio_adcs;
                spec->input_mux = &vaio_mux;
                spec->mux_nids = vaio_mux_nids;
@@ -3104,5 +4037,17 @@ struct hda_codec_preset snd_hda_preset_sigmatel[] = {
        { .id = 0x838476a5, .name = "STAC9255D", .patch = patch_stac9205 },
        { .id = 0x838476a6, .name = "STAC9254", .patch = patch_stac9205 },
        { .id = 0x838476a7, .name = "STAC9254D", .patch = patch_stac9205 },
+       { .id = 0x111d7674, .name = "92HD73D1X5", .patch = patch_stac92hd73xx },
+       { .id = 0x111d7675, .name = "92HD73C1X5", .patch = patch_stac92hd73xx },
+       { .id = 0x111d7676, .name = "92HD73E1X5", .patch = patch_stac92hd73xx },
+       { .id = 0x111d7608, .name = "92HD71BXX", .patch = patch_stac92hd71bxx },
+       { .id = 0x111d76b0, .name = "92HD71B8X", .patch = patch_stac92hd71bxx },
+       { .id = 0x111d76b1, .name = "92HD71B8X", .patch = patch_stac92hd71bxx },
+       { .id = 0x111d76b2, .name = "92HD71B7X", .patch = patch_stac92hd71bxx },
+       { .id = 0x111d76b3, .name = "92HD71B7X", .patch = patch_stac92hd71bxx },
+       { .id = 0x111d76b4, .name = "92HD71B6X", .patch = patch_stac92hd71bxx },
+       { .id = 0x111d76b5, .name = "92HD71B6X", .patch = patch_stac92hd71bxx },
+       { .id = 0x111d76b6, .name = "92HD71B5X", .patch = patch_stac92hd71bxx },
+       { .id = 0x111d76b7, .name = "92HD71B5X", .patch = patch_stac92hd71bxx },
        {} /* terminator */
 };
index 4cdf3e6df4baf20fa4ce2570c7cda55ef72a3d21..4e5dd4cf36f5f6404852e9ef70a0fc7110fc5730 100644 (file)
 /* 2006-03-14  Lydia Wang  Modify hard code for some pin widget nid          */
 /* 2006-08-02  Lydia Wang  Add support to VT1709 codec                       */
 /* 2006-09-08  Lydia Wang  Fix internal loopback recording source select bug */
+/* 2007-09-12  Lydia Wang  Add EAPD enable during driver initialization      */
+/* 2007-09-17  Lydia Wang  Add VT1708B codec support                        */
 /*                                                                           */
 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
 
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
 #define VT1708_HP_NID          0x13
 #define VT1708_DIGOUT_NID      0x14
 #define VT1708_DIGIN_NID       0x16
+#define VT1708_DIGIN_PIN       0x26
 
 #define VT1709_HP_DAC_NID      0x28
 #define VT1709_DIGOUT_NID      0x13
 #define VT1709_DIGIN_NID       0x17
+#define VT1709_DIGIN_PIN       0x25
+
+#define VT1708B_HP_NID         0x25
+#define VT1708B_DIGOUT_NID     0x12
+#define VT1708B_DIGIN_NID      0x15
+#define VT1708B_DIGIN_PIN      0x21
 
 #define IS_VT1708_VENDORID(x)          ((x) >= 0x11061708 && (x) <= 0x1106170b)
 #define IS_VT1709_10CH_VENDORID(x)     ((x) >= 0x1106e710 && (x) <= 0x1106e713)
 #define IS_VT1709_6CH_VENDORID(x)      ((x) >= 0x1106e714 && (x) <= 0x1106e717)
+#define IS_VT1708B_8CH_VENDORID(x)     ((x) >= 0x1106e720 && (x) <= 0x1106e723)
+#define IS_VT1708B_4CH_VENDORID(x)     ((x) >= 0x1106e724 && (x) <= 0x1106e727)
 
 
 enum {
@@ -131,6 +141,11 @@ static hda_nid_t vt1709_adc_nids[3] = {
        0x14, 0x15, 0x16
 };
 
+static hda_nid_t vt1708B_adc_nids[2] = {
+       /* ADC1-2 */
+       0x13, 0x14
+};
+
 /* add dynamic controls */
 static int via_add_control(struct via_spec *spec, int type, const char *name,
                           unsigned long val)
@@ -268,9 +283,13 @@ static int via_mux_enum_put(struct snd_kcontrol *kcontrol,
                return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
                                             0x18, &spec->cur_mux[adc_idx]);
        else if ((IS_VT1709_10CH_VENDORID(vendor_id) ||
-                 IS_VT1709_6CH_VENDORID(vendor_id)) && (adc_idx == 0) )
+                 IS_VT1709_6CH_VENDORID(vendor_id)) && adc_idx == 0)
                return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
                                             0x19, &spec->cur_mux[adc_idx]);
+       else if ((IS_VT1708B_8CH_VENDORID(vendor_id) ||
+                 IS_VT1708B_4CH_VENDORID(vendor_id)) && adc_idx == 0)
+               return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
+                                            0x17, &spec->cur_mux[adc_idx]);
        else
                return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
                                             spec->adc_nids[adc_idx],
@@ -287,7 +306,6 @@ static struct snd_kcontrol_new vt1708_capture_mixer[] = {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                /* The multiple "Capture Source" controls confuse alsamixer
                 * So call somewhat different..
-                * FIXME: the controls appear in the "playback" view!
                 */
                /* .name = "Capture Source", */
                .name = "Input Source",
@@ -309,15 +327,15 @@ static struct hda_verb vt1708_volume_init_verbs[] = {
        {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 
 
-       /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
+       /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
         * mixer widget
         */
        /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
-       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* master */
-       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
-       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
+       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
+       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
 
        /*
         * Set up output mixers (0x19 - 0x1b)
@@ -329,10 +347,9 @@ static struct hda_verb vt1708_volume_init_verbs[] = {
        
        /* Setup default input to PW4 */
        {0x20, AC_VERB_SET_CONNECT_SEL, 0x1},
-       /* Set mic as default input of sw0 */
-       {0x18, AC_VERB_SET_CONNECT_SEL, 0x2},
        /* PW9 Output enable */
        {0x25, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+       { }
 };
 
 static int via_playback_pcm_open(struct hda_pcm_stream *hinfo,
@@ -544,6 +561,33 @@ static int via_init(struct hda_codec *codec)
 {
        struct via_spec *spec = codec->spec;
        snd_hda_sequence_write(codec, spec->init_verbs);
+       /* Lydia Add for EAPD enable */
+       if (!spec->dig_in_nid) { /* No Digital In connection */
+               if (IS_VT1708_VENDORID(codec->vendor_id)) {
+                       snd_hda_codec_write(codec, VT1708_DIGIN_PIN, 0,
+                                           AC_VERB_SET_PIN_WIDGET_CONTROL,
+                                           PIN_OUT);
+                       snd_hda_codec_write(codec, VT1708_DIGIN_PIN, 0,
+                                           AC_VERB_SET_EAPD_BTLENABLE, 0x02);
+               } else if (IS_VT1709_10CH_VENDORID(codec->vendor_id) ||
+                          IS_VT1709_6CH_VENDORID(codec->vendor_id)) {
+                       snd_hda_codec_write(codec, VT1709_DIGIN_PIN, 0,
+                                           AC_VERB_SET_PIN_WIDGET_CONTROL,
+                                           PIN_OUT);
+                       snd_hda_codec_write(codec, VT1709_DIGIN_PIN, 0,
+                                           AC_VERB_SET_EAPD_BTLENABLE, 0x02);
+               } else if (IS_VT1708B_8CH_VENDORID(codec->vendor_id) ||
+                          IS_VT1708B_4CH_VENDORID(codec->vendor_id)) {
+                       snd_hda_codec_write(codec, VT1708B_DIGIN_PIN, 0,
+                                           AC_VERB_SET_PIN_WIDGET_CONTROL,
+                                           PIN_OUT);
+                       snd_hda_codec_write(codec, VT1708B_DIGIN_PIN, 0,
+                                           AC_VERB_SET_EAPD_BTLENABLE, 0x02);
+               }
+       } else /* enable SPDIF-input pin */
+               snd_hda_codec_write(codec, spec->autocfg.dig_in_pin, 0,
+                                   AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN);
+
        return 0;
 }
 
@@ -623,58 +667,68 @@ static int vt1708_auto_create_multi_out_ctls(struct via_spec *spec,
                if (i == AUTO_SEQ_CENLFE) {
                        /* Center/LFE */
                        err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
-                                             "Center Playback Volume",
-                                             HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0, HDA_OUTPUT));
+                                       "Center Playback Volume",
+                                       HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
+                                                           HDA_OUTPUT));
                        if (err < 0)
                                return err;
                        err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
                                              "LFE Playback Volume",
-                                             HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, HDA_OUTPUT));
+                                             HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
+                                                                 HDA_OUTPUT));
                        if (err < 0)
                                return err;
                        err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
                                              "Center Playback Switch",
-                                             HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0, HDA_OUTPUT));
+                                             HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
+                                                                 HDA_OUTPUT));
                        if (err < 0)
                                return err;
                        err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
                                              "LFE Playback Switch",
-                                             HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, HDA_OUTPUT));
+                                             HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
+                                                                 HDA_OUTPUT));
                        if (err < 0)
                                return err;
                } else if (i == AUTO_SEQ_FRONT){
                        /* add control to mixer index 0 */
                        err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
                                              "Master Front Playback Volume",
-                                             HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_INPUT));
+                                             HDA_COMPOSE_AMP_VAL(0x17, 3, 0,
+                                                                 HDA_INPUT));
                        if (err < 0)
                                return err;
                        err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
                                              "Master Front Playback Switch",
-                                             HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_INPUT));
+                                             HDA_COMPOSE_AMP_VAL(0x17, 3, 0,
+                                                                 HDA_INPUT));
                        if (err < 0)
                                return err;
                        
                        /* add control to PW3 */
                        sprintf(name, "%s Playback Volume", chname[i]);
                        err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
-                                             HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
+                                             HDA_COMPOSE_AMP_VAL(nid, 3, 0,
+                                                                 HDA_OUTPUT));
                        if (err < 0)
                                return err;
                        sprintf(name, "%s Playback Switch", chname[i]);
                        err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
-                                             HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
+                                             HDA_COMPOSE_AMP_VAL(nid, 3, 0,
+                                                                 HDA_OUTPUT));
                        if (err < 0)
                                return err;
                } else {
                        sprintf(name, "%s Playback Volume", chname[i]);
                        err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
-                                             HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT));
+                                             HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
+                                                                 HDA_OUTPUT));
                        if (err < 0)
                                return err;
                        sprintf(name, "%s Playback Switch", chname[i]);
                        err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
-                                             HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT));
+                                             HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
+                                                                 HDA_OUTPUT));
                        if (err < 0)
                                return err;
                }
@@ -875,7 +929,6 @@ static struct snd_kcontrol_new vt1709_capture_mixer[] = {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                /* The multiple "Capture Source" controls confuse alsamixer
                 * So call somewhat different..
-                * FIXME: the controls appear in the "playback" view!
                 */
                /* .name = "Capture Source", */
                .name = "Input Source",
@@ -899,15 +952,15 @@ static struct hda_verb vt1709_10ch_volume_init_verbs[] = {
        {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 
 
-       /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
+       /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
         * mixer widget
         */
        /* Amp Indices: AOW0=0, CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
-       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* unmute master */
-       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
-       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
+       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
+       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
 
        /*
         * Set up output selector (0x1a, 0x1b, 0x29)
@@ -925,8 +978,6 @@ static struct hda_verb vt1709_10ch_volume_init_verbs[] = {
 
        /* Set input of PW4 as AOW4 */
        {0x20, AC_VERB_SET_CONNECT_SEL, 0x1},
-       /* Set mic as default input of sw0 */
-       {0x19, AC_VERB_SET_CONNECT_SEL, 0x2},
        /* PW9 Output enable */
        {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
        { }
@@ -1073,68 +1124,80 @@ static int vt1709_auto_create_multi_out_ctls(struct via_spec *spec,
                        /* Center/LFE */
                        err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
                                              "Center Playback Volume",
-                                             HDA_COMPOSE_AMP_VAL(0x1b, 1, 0, HDA_OUTPUT));
+                                             HDA_COMPOSE_AMP_VAL(0x1b, 1, 0,
+                                                                 HDA_OUTPUT));
                        if (err < 0)
                                return err;
                        err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
                                              "LFE Playback Volume",
-                                             HDA_COMPOSE_AMP_VAL(0x1b, 2, 0, HDA_OUTPUT));
+                                             HDA_COMPOSE_AMP_VAL(0x1b, 2, 0,
+                                                                 HDA_OUTPUT));
                        if (err < 0)
                                return err;
                        err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
                                              "Center Playback Switch",
-                                             HDA_COMPOSE_AMP_VAL(0x1b, 1, 0, HDA_OUTPUT));
+                                             HDA_COMPOSE_AMP_VAL(0x1b, 1, 0,
+                                                                 HDA_OUTPUT));
                        if (err < 0)
                                return err;
                        err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
                                              "LFE Playback Switch",
-                                             HDA_COMPOSE_AMP_VAL(0x1b, 2, 0, HDA_OUTPUT));
+                                             HDA_COMPOSE_AMP_VAL(0x1b, 2, 0,
+                                                                 HDA_OUTPUT));
                        if (err < 0)
                                return err;
                } else if (i == AUTO_SEQ_FRONT){
                        /* add control to mixer index 0 */
                        err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
                                              "Master Front Playback Volume",
-                                             HDA_COMPOSE_AMP_VAL(0x18, 3, 0, HDA_INPUT));
+                                             HDA_COMPOSE_AMP_VAL(0x18, 3, 0,
+                                                                 HDA_INPUT));
                        if (err < 0)
                                return err;
                        err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
                                              "Master Front Playback Switch",
-                                             HDA_COMPOSE_AMP_VAL(0x18, 3, 0, HDA_INPUT));
+                                             HDA_COMPOSE_AMP_VAL(0x18, 3, 0,
+                                                                 HDA_INPUT));
                        if (err < 0)
                                return err;
                        
                        /* add control to PW3 */
                        sprintf(name, "%s Playback Volume", chname[i]);
                        err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
-                                             HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
+                                             HDA_COMPOSE_AMP_VAL(nid, 3, 0,
+                                                                 HDA_OUTPUT));
                        if (err < 0)
                                return err;
                        sprintf(name, "%s Playback Switch", chname[i]);
                        err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
-                                             HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
+                                             HDA_COMPOSE_AMP_VAL(nid, 3, 0,
+                                                                 HDA_OUTPUT));
                        if (err < 0)
                                return err;
                } else if (i == AUTO_SEQ_SURROUND) {
                        sprintf(name, "%s Playback Volume", chname[i]);
                        err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
-                                             HDA_COMPOSE_AMP_VAL(0x29, 3, 0, HDA_OUTPUT));
+                                             HDA_COMPOSE_AMP_VAL(0x29, 3, 0,
+                                                                 HDA_OUTPUT));
                        if (err < 0)
                                return err;
                        sprintf(name, "%s Playback Switch", chname[i]);
                        err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
-                                             HDA_COMPOSE_AMP_VAL(0x29, 3, 0, HDA_OUTPUT));
+                                             HDA_COMPOSE_AMP_VAL(0x29, 3, 0,
+                                                                 HDA_OUTPUT));
                        if (err < 0)
                                return err;
                } else if (i == AUTO_SEQ_SIDE) {
                        sprintf(name, "%s Playback Volume", chname[i]);
                        err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
-                                             HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT));
+                                             HDA_COMPOSE_AMP_VAL(0x1a, 3, 0,
+                                                                 HDA_OUTPUT));
                        if (err < 0)
                                return err;
                        sprintf(name, "%s Playback Switch", chname[i]);
                        err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
-                                             HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT));
+                                             HDA_COMPOSE_AMP_VAL(0x1a, 3, 0,
+                                                                 HDA_OUTPUT));
                        if (err < 0)
                                return err;
                }
@@ -1351,8 +1414,6 @@ static struct hda_verb vt1709_6ch_volume_init_verbs[] = {
 
        /* Set input of PW4 as MW0 */
        {0x20, AC_VERB_SET_CONNECT_SEL, 0},
-       /* Set mic as default input of sw0 */
-       {0x19, AC_VERB_SET_CONNECT_SEL, 0x2},
        /* PW9 Output enable */
        {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
        { }
@@ -1403,6 +1464,494 @@ static int patch_vt1709_6ch(struct hda_codec *codec)
 #ifdef CONFIG_SND_HDA_POWER_SAVE
        spec->loopback.amplist = vt1709_loopbacks;
 #endif
+       return 0;
+}
+
+/* capture mixer elements */
+static struct snd_kcontrol_new vt1708B_capture_mixer[] = {
+       HDA_CODEC_VOLUME("Capture Volume", 0x13, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Capture Switch", 0x13, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x14, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x14, 0x0, HDA_INPUT),
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               /* The multiple "Capture Source" controls confuse alsamixer
+                * So call somewhat different..
+                */
+               /* .name = "Capture Source", */
+               .name = "Input Source",
+               .count = 1,
+               .info = via_mux_enum_info,
+               .get = via_mux_enum_get,
+               .put = via_mux_enum_put,
+       },
+       { } /* end */
+};
+/*
+ * generic initialization of ADC, input mixers and output mixers
+ */
+static struct hda_verb vt1708B_8ch_volume_init_verbs[] = {
+       /*
+        * Unmute ADC0-1 and set the default input to mic-in
+        */
+       {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+
+
+       /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
+        * mixer widget
+        */
+       /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
+       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
+       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
+       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
+
+       /*
+        * Set up output mixers
+        */
+       /* set vol=0 to output mixers */
+       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+
+       /* Setup default input to PW4 */
+       {0x1d, AC_VERB_SET_CONNECT_SEL, 0x1},
+       /* PW9 Output enable */
+       {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+       /* PW10 Input enable */
+       {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
+       { }
+};
+
+static struct hda_verb vt1708B_4ch_volume_init_verbs[] = {
+       /*
+        * Unmute ADC0-1 and set the default input to mic-in
+        */
+       {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+
+
+       /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
+        * mixer widget
+        */
+       /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
+       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
+       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
+       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
+
+       /*
+        * Set up output mixers
+        */
+       /* set vol=0 to output mixers */
+       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+
+       /* Setup default input of PW4 to MW0 */
+       {0x1d, AC_VERB_SET_CONNECT_SEL, 0x0},
+       /* PW9 Output enable */
+       {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+       /* PW10 Input enable */
+       {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
+       { }
+};
+
+static struct hda_pcm_stream vt1708B_8ch_pcm_analog_playback = {
+       .substreams = 1,
+       .channels_min = 2,
+       .channels_max = 8,
+       .nid = 0x10, /* NID to query formats and rates */
+       .ops = {
+               .open = via_playback_pcm_open,
+               .prepare = via_playback_pcm_prepare,
+               .cleanup = via_playback_pcm_cleanup
+       },
+};
+
+static struct hda_pcm_stream vt1708B_4ch_pcm_analog_playback = {
+       .substreams = 1,
+       .channels_min = 2,
+       .channels_max = 4,
+       .nid = 0x10, /* NID to query formats and rates */
+       .ops = {
+               .open = via_playback_pcm_open,
+               .prepare = via_playback_pcm_prepare,
+               .cleanup = via_playback_pcm_cleanup
+       },
+};
+
+static struct hda_pcm_stream vt1708B_pcm_analog_capture = {
+       .substreams = 2,
+       .channels_min = 2,
+       .channels_max = 2,
+       .nid = 0x13, /* NID to query formats and rates */
+       .ops = {
+               .prepare = via_capture_pcm_prepare,
+               .cleanup = via_capture_pcm_cleanup
+       },
+};
+
+static struct hda_pcm_stream vt1708B_pcm_digital_playback = {
+       .substreams = 1,
+       .channels_min = 2,
+       .channels_max = 2,
+       /* NID is set in via_build_pcms */
+       .ops = {
+               .open = via_dig_playback_pcm_open,
+               .close = via_dig_playback_pcm_close,
+               .prepare = via_dig_playback_pcm_prepare
+       },
+};
+
+static struct hda_pcm_stream vt1708B_pcm_digital_capture = {
+       .substreams = 1,
+       .channels_min = 2,
+       .channels_max = 2,
+};
+
+/* fill in the dac_nids table from the parsed pin configuration */
+static int vt1708B_auto_fill_dac_nids(struct via_spec *spec,
+                                    const struct auto_pin_cfg *cfg)
+{
+       int i;
+       hda_nid_t nid;
+
+       spec->multiout.num_dacs = cfg->line_outs;
+
+       spec->multiout.dac_nids = spec->private_dac_nids;
+
+       for (i = 0; i < 4; i++) {
+               nid = cfg->line_out_pins[i];
+               if (nid) {
+                       /* config dac list */
+                       switch (i) {
+                       case AUTO_SEQ_FRONT:
+                               spec->multiout.dac_nids[i] = 0x10;
+                               break;
+                       case AUTO_SEQ_CENLFE:
+                               spec->multiout.dac_nids[i] = 0x24;
+                               break;
+                       case AUTO_SEQ_SURROUND:
+                               spec->multiout.dac_nids[i] = 0x25;
+                               break;
+                       case AUTO_SEQ_SIDE:
+                               spec->multiout.dac_nids[i] = 0x11;
+                               break;
+                       }
+               }
+       }
+
+       return 0;
+}
+
+/* add playback controls from the parsed DAC table */
+static int vt1708B_auto_create_multi_out_ctls(struct via_spec *spec,
+                                            const struct auto_pin_cfg *cfg)
+{
+       char name[32];
+       static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" };
+       hda_nid_t nid_vols[] = {0x16, 0x27, 0x26, 0x18};
+       hda_nid_t nid, nid_vol = 0;
+       int i, err;
+
+       for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
+               nid = cfg->line_out_pins[i];
+
+               if (!nid)
+                       continue;
+
+               nid_vol = nid_vols[i];
+
+               if (i == AUTO_SEQ_CENLFE) {
+                       /* Center/LFE */
+                       err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
+                                             "Center Playback Volume",
+                                             HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
+                                                                 HDA_OUTPUT));
+                       if (err < 0)
+                               return err;
+                       err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
+                                             "LFE Playback Volume",
+                                             HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
+                                                                 HDA_OUTPUT));
+                       if (err < 0)
+                               return err;
+                       err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
+                                             "Center Playback Switch",
+                                             HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
+                                                                 HDA_OUTPUT));
+                       if (err < 0)
+                               return err;
+                       err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
+                                             "LFE Playback Switch",
+                                             HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
+                                                                 HDA_OUTPUT));
+                       if (err < 0)
+                               return err;
+               } else if (i == AUTO_SEQ_FRONT) {
+                       /* add control to mixer index 0 */
+                       err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
+                                             "Master Front Playback Volume",
+                                             HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
+                                                                 HDA_INPUT));
+                       if (err < 0)
+                               return err;
+                       err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
+                                             "Master Front Playback Switch",
+                                             HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
+                                                                 HDA_INPUT));
+                       if (err < 0)
+                               return err;
+
+                       /* add control to PW3 */
+                       sprintf(name, "%s Playback Volume", chname[i]);
+                       err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
+                                             HDA_COMPOSE_AMP_VAL(nid, 3, 0,
+                                                                 HDA_OUTPUT));
+                       if (err < 0)
+                               return err;
+                       sprintf(name, "%s Playback Switch", chname[i]);
+                       err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
+                                             HDA_COMPOSE_AMP_VAL(nid, 3, 0,
+                                                                 HDA_OUTPUT));
+                       if (err < 0)
+                               return err;
+               } else {
+                       sprintf(name, "%s Playback Volume", chname[i]);
+                       err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
+                                             HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
+                                                                 HDA_OUTPUT));
+                       if (err < 0)
+                               return err;
+                       sprintf(name, "%s Playback Switch", chname[i]);
+                       err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
+                                             HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
+                                                                 HDA_OUTPUT));
+                       if (err < 0)
+                               return err;
+               }
+       }
+
+       return 0;
+}
+
+static int vt1708B_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
+{
+       int err;
+
+       if (!pin)
+               return 0;
+
+       spec->multiout.hp_nid = VT1708B_HP_NID; /* AOW3 */
+
+       err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
+                             "Headphone Playback Volume",
+                             HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
+       if (err < 0)
+               return err;
+       err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
+                             "Headphone Playback Switch",
+                             HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
+       if (err < 0)
+               return err;
+
+       return 0;
+}
+
+/* create playback/capture controls for input pins */
+static int vt1708B_auto_create_analog_input_ctls(struct via_spec *spec,
+                                               const struct auto_pin_cfg *cfg)
+{
+       static char *labels[] = {
+               "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
+       };
+       struct hda_input_mux *imux = &spec->private_imux;
+       int i, err, idx = 0;
+
+       /* for internal loopback recording select */
+       imux->items[imux->num_items].label = "Stereo Mixer";
+       imux->items[imux->num_items].index = idx;
+       imux->num_items++;
+
+       for (i = 0; i < AUTO_PIN_LAST; i++) {
+               if (!cfg->input_pins[i])
+                       continue;
+
+               switch (cfg->input_pins[i]) {
+               case 0x1a: /* Mic */
+                       idx = 2;
+                       break;
+
+               case 0x1b: /* Line In */
+                       idx = 3;
+                       break;
+
+               case 0x1e: /* Front Mic */
+                       idx = 4;
+                       break;
+
+               case 0x1f: /* CD */
+                       idx = 1;
+                       break;
+               }
+               err = via_new_analog_input(spec, cfg->input_pins[i], labels[i],
+                                          idx, 0x16);
+               if (err < 0)
+                       return err;
+               imux->items[imux->num_items].label = labels[i];
+               imux->items[imux->num_items].index = idx;
+               imux->num_items++;
+       }
+       return 0;
+}
+
+static int vt1708B_parse_auto_config(struct hda_codec *codec)
+{
+       struct via_spec *spec = codec->spec;
+       int err;
+
+       err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
+       if (err < 0)
+               return err;
+       err = vt1708B_auto_fill_dac_nids(spec, &spec->autocfg);
+       if (err < 0)
+               return err;
+       if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
+               return 0; /* can't find valid BIOS pin config */
+
+       err = vt1708B_auto_create_multi_out_ctls(spec, &spec->autocfg);
+       if (err < 0)
+               return err;
+       err = vt1708B_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
+       if (err < 0)
+               return err;
+       err = vt1708B_auto_create_analog_input_ctls(spec, &spec->autocfg);
+       if (err < 0)
+               return err;
+
+       spec->multiout.max_channels = spec->multiout.num_dacs * 2;
+
+       if (spec->autocfg.dig_out_pin)
+               spec->multiout.dig_out_nid = VT1708B_DIGOUT_NID;
+       if (spec->autocfg.dig_in_pin)
+               spec->dig_in_nid = VT1708B_DIGIN_NID;
+
+       if (spec->kctl_alloc)
+               spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
+
+       spec->input_mux = &spec->private_imux;
+
+       return 1;
+}
+
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+static struct hda_amp_list vt1708B_loopbacks[] = {
+       { 0x16, HDA_INPUT, 1 },
+       { 0x16, HDA_INPUT, 2 },
+       { 0x16, HDA_INPUT, 3 },
+       { 0x16, HDA_INPUT, 4 },
+       { } /* end */
+};
+#endif
+
+static int patch_vt1708B_8ch(struct hda_codec *codec)
+{
+       struct via_spec *spec;
+       int err;
+
+       /* create a codec specific record */
+       spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
+       if (spec == NULL)
+               return -ENOMEM;
+
+       codec->spec = spec;
+
+       /* automatic parse from the BIOS config */
+       err = vt1708B_parse_auto_config(codec);
+       if (err < 0) {
+               via_free(codec);
+               return err;
+       } else if (!err) {
+               printk(KERN_INFO "hda_codec: Cannot set up configuration "
+                      "from BIOS.  Using genenic mode...\n");
+       }
+
+       spec->init_verbs = vt1708B_8ch_volume_init_verbs;
+
+       spec->stream_name_analog = "VT1708B Analog";
+       spec->stream_analog_playback = &vt1708B_8ch_pcm_analog_playback;
+       spec->stream_analog_capture = &vt1708B_pcm_analog_capture;
+
+       spec->stream_name_digital = "VT1708B Digital";
+       spec->stream_digital_playback = &vt1708B_pcm_digital_playback;
+       spec->stream_digital_capture = &vt1708B_pcm_digital_capture;
+
+       if (!spec->adc_nids && spec->input_mux) {
+               spec->adc_nids = vt1708B_adc_nids;
+               spec->num_adc_nids = ARRAY_SIZE(vt1708B_adc_nids);
+               spec->mixers[spec->num_mixers] = vt1708B_capture_mixer;
+               spec->num_mixers++;
+       }
+
+       codec->patch_ops = via_patch_ops;
+
+       codec->patch_ops.init = via_auto_init;
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+       spec->loopback.amplist = vt1708B_loopbacks;
+#endif
+
+       return 0;
+}
+
+static int patch_vt1708B_4ch(struct hda_codec *codec)
+{
+       struct via_spec *spec;
+       int err;
+
+       /* create a codec specific record */
+       spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
+       if (spec == NULL)
+               return -ENOMEM;
+
+       codec->spec = spec;
+
+       /* automatic parse from the BIOS config */
+       err = vt1708B_parse_auto_config(codec);
+       if (err < 0) {
+               via_free(codec);
+               return err;
+       } else if (!err) {
+               printk(KERN_INFO "hda_codec: Cannot set up configuration "
+                      "from BIOS.  Using genenic mode...\n");
+       }
+
+       spec->init_verbs = vt1708B_4ch_volume_init_verbs;
+
+       spec->stream_name_analog = "VT1708B Analog";
+       spec->stream_analog_playback = &vt1708B_4ch_pcm_analog_playback;
+       spec->stream_analog_capture = &vt1708B_pcm_analog_capture;
+
+       spec->stream_name_digital = "VT1708B Digital";
+       spec->stream_digital_playback = &vt1708B_pcm_digital_playback;
+       spec->stream_digital_capture = &vt1708B_pcm_digital_capture;
+
+       if (!spec->adc_nids && spec->input_mux) {
+               spec->adc_nids = vt1708B_adc_nids;
+               spec->num_adc_nids = ARRAY_SIZE(vt1708B_adc_nids);
+               spec->mixers[spec->num_mixers] = vt1708B_capture_mixer;
+               spec->num_mixers++;
+       }
+
+       codec->patch_ops = via_patch_ops;
+
+       codec->patch_ops.init = via_auto_init;
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+       spec->loopback.amplist = vt1708B_loopbacks;
+#endif
 
        return 0;
 }
@@ -1415,13 +1964,37 @@ struct hda_codec_preset snd_hda_preset_via[] = {
        { .id = 0x11061709, .name = "VIA VT1708", .patch = patch_vt1708},
        { .id = 0x1106170A, .name = "VIA VT1708", .patch = patch_vt1708},
        { .id = 0x1106170B, .name = "VIA VT1708", .patch = patch_vt1708},
-       { .id = 0x1106E710, .name = "VIA VT1709 10-Ch", .patch = patch_vt1709_10ch},
-       { .id = 0x1106E711, .name = "VIA VT1709 10-Ch", .patch = patch_vt1709_10ch},
-       { .id = 0x1106E712, .name = "VIA VT1709 10-Ch", .patch = patch_vt1709_10ch},
-       { .id = 0x1106E713, .name = "VIA VT1709 10-Ch", .patch = patch_vt1709_10ch},
-       { .id = 0x1106E714, .name = "VIA VT1709 6-Ch", .patch = patch_vt1709_6ch},
-       { .id = 0x1106E715, .name = "VIA VT1709 6-Ch", .patch = patch_vt1709_6ch},
-       { .id = 0x1106E716, .name = "VIA VT1709 6-Ch", .patch = patch_vt1709_6ch},
-       { .id = 0x1106E717, .name = "VIA VT1709 6-Ch", .patch = patch_vt1709_6ch},
+       { .id = 0x1106E710, .name = "VIA VT1709 10-Ch",
+         .patch = patch_vt1709_10ch},
+       { .id = 0x1106E711, .name = "VIA VT1709 10-Ch",
+         .patch = patch_vt1709_10ch},
+       { .id = 0x1106E712, .name = "VIA VT1709 10-Ch",
+         .patch = patch_vt1709_10ch},
+       { .id = 0x1106E713, .name = "VIA VT1709 10-Ch",
+         .patch = patch_vt1709_10ch},
+       { .id = 0x1106E714, .name = "VIA VT1709 6-Ch",
+         .patch = patch_vt1709_6ch},
+       { .id = 0x1106E715, .name = "VIA VT1709 6-Ch",
+         .patch = patch_vt1709_6ch},
+       { .id = 0x1106E716, .name = "VIA VT1709 6-Ch",
+         .patch = patch_vt1709_6ch},
+       { .id = 0x1106E717, .name = "VIA VT1709 6-Ch",
+         .patch = patch_vt1709_6ch},
+       { .id = 0x1106E720, .name = "VIA VT1708B 8-Ch",
+         .patch = patch_vt1708B_8ch},
+       { .id = 0x1106E721, .name = "VIA VT1708B 8-Ch",
+         .patch = patch_vt1708B_8ch},
+       { .id = 0x1106E722, .name = "VIA VT1708B 8-Ch",
+         .patch = patch_vt1708B_8ch},
+       { .id = 0x1106E723, .name = "VIA VT1708B 8-Ch",
+         .patch = patch_vt1708B_8ch},
+       { .id = 0x1106E724, .name = "VIA VT1708B 4-Ch",
+         .patch = patch_vt1708B_4ch},
+       { .id = 0x1106E725, .name = "VIA VT1708B 4-Ch",
+         .patch = patch_vt1708B_4ch},
+       { .id = 0x1106E726, .name = "VIA VT1708B 4-Ch",
+         .patch = patch_vt1708B_4ch},
+       { .id = 0x1106E727, .name = "VIA VT1708B 4-Ch",
+         .patch = patch_vt1708B_4ch},
        {} /* terminator */
 };
diff --git a/sound/pci/hda/vmaster.c b/sound/pci/hda/vmaster.c
new file mode 100644 (file)
index 0000000..2da49d2
--- /dev/null
@@ -0,0 +1,364 @@
+/*
+ * Virtual master and slave controls
+ *
+ *  Copyright (c) 2008 by Takashi Iwai <tiwai@suse.de>
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License as
+ *  published by the Free Software Foundation, version 2.
+ *
+ */
+
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/control.h>
+
+/*
+ * a subset of information returned via ctl info callback
+ */
+struct link_ctl_info {
+       int type;               /* value type */
+       int count;              /* item count */
+       int min_val, max_val;   /* min, max values */
+};
+
+/*
+ * link master - this contains a list of slave controls that are
+ * identical types, i.e. info returns the same value type and value
+ * ranges, but may have different number of counts.
+ *
+ * The master control is so far only mono volume/switch for simplicity.
+ * The same value will be applied to all slaves.
+ */
+struct link_master {
+       struct list_head slaves;
+       struct link_ctl_info info;
+       int val;                /* the master value */
+};
+
+/*
+ * link slave - this contains a slave control element
+ *
+ * It fakes the control callbacsk with additional attenuation by the
+ * master control.  A slave may have either one or two channels.
+ */
+
+struct link_slave {
+       struct list_head list;
+       struct link_master *master;
+       struct link_ctl_info info;
+       int vals[2];            /* current values */
+       struct snd_kcontrol slave; /* the copy of original control entry */
+};
+
+/* get the slave ctl info and save the initial values */
+static int slave_init(struct link_slave *slave)
+{
+       struct snd_ctl_elem_info *uinfo;
+       struct snd_ctl_elem_value *uctl;
+       int err, ch;
+
+       if (slave->info.count)
+               return 0; /* already initialized */
+
+       uinfo = kmalloc(sizeof(*uinfo), GFP_KERNEL);
+       if (!uinfo)
+               return -ENOMEM;
+       uinfo->id = slave->slave.id;
+       err = slave->slave.info(&slave->slave, uinfo);
+       if (err < 0) {
+               kfree(uinfo);
+               return err;
+       }
+       slave->info.type = uinfo->type;
+       slave->info.count = uinfo->count;
+       if (slave->info.count > 2  ||
+           (slave->info.type != SNDRV_CTL_ELEM_TYPE_INTEGER &&
+            slave->info.type != SNDRV_CTL_ELEM_TYPE_BOOLEAN)) {
+               snd_printk(KERN_ERR "invalid slave element\n");
+               kfree(uinfo);
+               return -EINVAL;
+       }
+       slave->info.min_val = uinfo->value.integer.min;
+       slave->info.max_val = uinfo->value.integer.max;
+       kfree(uinfo);
+
+       uctl = kmalloc(sizeof(*uctl), GFP_KERNEL);
+       if (!uctl)
+               return -ENOMEM;
+       uctl->id = slave->slave.id;
+       err = slave->slave.get(&slave->slave, uctl);
+       for (ch = 0; ch < slave->info.count; ch++)
+               slave->vals[ch] = uctl->value.integer.value[ch];
+       kfree(uctl);
+       return 0;
+}
+
+/* initialize master volume */
+static int master_init(struct link_master *master)
+{
+       struct link_slave *slave;
+
+       if (master->info.count)
+               return 0; /* already initialized */
+
+       list_for_each_entry(slave, &master->slaves, list) {
+               int err = slave_init(slave);
+               if (err < 0)
+                       return err;
+               master->info = slave->info;
+               master->info.count = 1; /* always mono */
+               /* set full volume as default (= no attenuation) */
+               master->val = master->info.max_val;
+               return 0;
+       }
+       return -ENOENT;
+}
+
+static int slave_get_val(struct link_slave *slave,
+                        struct snd_ctl_elem_value *ucontrol)
+{
+       int err, ch;
+
+       err = slave_init(slave);
+       if (err < 0)
+               return err;
+       for (ch = 0; ch < slave->info.count; ch++)
+               ucontrol->value.integer.value[ch] = slave->vals[ch];
+       return 0;
+}
+
+static int slave_put_val(struct link_slave *slave,
+                        struct snd_ctl_elem_value *ucontrol)
+{
+       int err, ch, vol;
+
+       err = master_init(slave->master);
+       if (err < 0)
+               return err;
+
+       switch (slave->info.type) {
+       case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
+               for (ch = 0; ch < slave->info.count; ch++)
+                       ucontrol->value.integer.value[ch] &=
+                               !!slave->master->val;
+               break;
+       case SNDRV_CTL_ELEM_TYPE_INTEGER:
+               for (ch = 0; ch < slave->info.count; ch++) {
+                       /* max master volume is supposed to be 0 dB */
+                       vol = ucontrol->value.integer.value[ch];
+                       vol += slave->master->val - slave->master->info.max_val;
+                       if (vol < slave->info.min_val)
+                               vol = slave->info.min_val;
+                       else if (vol > slave->info.max_val)
+                               vol = slave->info.max_val;
+                       ucontrol->value.integer.value[ch] = vol;
+               }
+               break;
+       }
+       return slave->slave.put(&slave->slave, ucontrol);
+}
+
+/*
+ * ctl callbacks for slaves
+ */
+static int slave_info(struct snd_kcontrol *kcontrol,
+                     struct snd_ctl_elem_info *uinfo)
+{
+       struct link_slave *slave = snd_kcontrol_chip(kcontrol);
+       return slave->slave.info(&slave->slave, uinfo);
+}
+
+static int slave_get(struct snd_kcontrol *kcontrol,
+                    struct snd_ctl_elem_value *ucontrol)
+{
+       struct link_slave *slave = snd_kcontrol_chip(kcontrol);
+       return slave_get_val(slave, ucontrol);
+}
+
+static int slave_put(struct snd_kcontrol *kcontrol,
+                    struct snd_ctl_elem_value *ucontrol)
+{
+       struct link_slave *slave = snd_kcontrol_chip(kcontrol);
+       int err, ch, changed = 0;
+
+       err = slave_init(slave);
+       if (err < 0)
+               return err;
+       for (ch = 0; ch < slave->info.count; ch++) {
+               if (slave->vals[ch] != ucontrol->value.integer.value[ch]) {
+                       changed = 1;
+                       slave->vals[ch] = ucontrol->value.integer.value[ch];
+               }
+       }
+       if (!changed)
+               return 0;
+       return slave_put_val(slave, ucontrol);
+}
+
+static int slave_tlv_cmd(struct snd_kcontrol *kcontrol,
+                        int op_flag, unsigned int size,
+                        unsigned int __user *tlv)
+{
+       struct link_slave *slave = snd_kcontrol_chip(kcontrol);
+       /* FIXME: this assumes that the max volume is 0 dB */
+       return slave->slave.tlv.c(&slave->slave, op_flag, size, tlv);
+}
+
+static void slave_free(struct snd_kcontrol *kcontrol)
+{
+       struct link_slave *slave = snd_kcontrol_chip(kcontrol);
+       if (slave->slave.private_free)
+               slave->slave.private_free(&slave->slave);
+       if (slave->master)
+               list_del(&slave->list);
+       kfree(slave);
+}
+
+/*
+ * Add a slave control to the group with the given master control
+ *
+ * All slaves must be the same type (returning the same information
+ * via info callback).  The fucntion doesn't check it, so it's your
+ * responsibility.
+ *
+ * Also, some additional limitations:
+ * - at most two channels
+ * - logarithmic volume control (dB level), no linear volume
+ * - master can only attenuate the volume, no gain
+ */
+int snd_ctl_add_slave(struct snd_kcontrol *master, struct snd_kcontrol *slave)
+{
+       struct link_master *master_link = snd_kcontrol_chip(master);
+       struct link_slave *srec;
+
+       srec = kzalloc(sizeof(*srec) +
+                      slave->count * sizeof(*slave->vd), GFP_KERNEL);
+       if (!srec)
+               return -ENOMEM;
+       srec->slave = *slave;
+       memcpy(srec->slave.vd, slave->vd, slave->count * sizeof(*slave->vd));
+       srec->master = master_link;
+
+       /* override callbacks */
+       slave->info = slave_info;
+       slave->get = slave_get;
+       slave->put = slave_put;
+       if (slave->vd[0].access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK)
+               slave->tlv.c = slave_tlv_cmd;
+       slave->private_data = srec;
+       slave->private_free = slave_free;
+
+       list_add_tail(&srec->list, &master_link->slaves);
+       return 0;
+}
+
+/*
+ * ctl callbacks for master controls
+ */
+static int master_info(struct snd_kcontrol *kcontrol,
+                     struct snd_ctl_elem_info *uinfo)
+{
+       struct link_master *master = snd_kcontrol_chip(kcontrol);
+       int ret;
+
+       ret = master_init(master);
+       if (ret < 0)
+               return ret;
+       uinfo->type = master->info.type;
+       uinfo->count = master->info.count;
+       uinfo->value.integer.min = master->info.min_val;
+       uinfo->value.integer.max = master->info.max_val;
+       return 0;
+}
+
+static int master_get(struct snd_kcontrol *kcontrol,
+                     struct snd_ctl_elem_value *ucontrol)
+{
+       struct link_master *master = snd_kcontrol_chip(kcontrol);
+       int err = master_init(master);
+       if (err < 0)
+               return err;
+       ucontrol->value.integer.value[0] = master->val;
+       return 0;
+}
+
+static int master_put(struct snd_kcontrol *kcontrol,
+                     struct snd_ctl_elem_value *ucontrol)
+{
+       struct link_master *master = snd_kcontrol_chip(kcontrol);
+       struct link_slave *slave;
+       struct snd_ctl_elem_value *uval;
+       int err, old_val;
+
+       err = master_init(master);
+       if (err < 0)
+               return err;
+       old_val = master->val;
+       if (ucontrol->value.integer.value[0] == old_val)
+               return 0;
+
+       uval = kmalloc(sizeof(*uval), GFP_KERNEL);
+       if (!uval)
+               return -ENOMEM;
+       list_for_each_entry(slave, &master->slaves, list) {
+               master->val = old_val;
+               uval->id = slave->slave.id;
+               slave_get_val(slave, uval);
+               master->val = ucontrol->value.integer.value[0];
+               slave_put_val(slave, uval);
+       }
+       kfree(uval);
+       return 1;
+}
+
+static void master_free(struct snd_kcontrol *kcontrol)
+{
+       struct link_master *master = snd_kcontrol_chip(kcontrol);
+       struct link_slave *slave;
+
+       list_for_each_entry(slave, &master->slaves, list)
+               slave->master = NULL;
+       kfree(master);
+}
+
+
+/*
+ * Create a virtual master control with the given name
+ */
+struct snd_kcontrol *snd_ctl_make_virtual_master(char *name,
+                                                const unsigned int *tlv)
+{
+       struct link_master *master;
+       struct snd_kcontrol *kctl;
+       struct snd_kcontrol_new knew;
+
+       memset(&knew, 0, sizeof(knew));
+       knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+       knew.name = name;
+       knew.info = master_info;
+
+       master = kzalloc(sizeof(*master), GFP_KERNEL);
+       if (!master)
+               return NULL;
+       INIT_LIST_HEAD(&master->slaves);
+
+       kctl = snd_ctl_new1(&knew, master);
+       if (!kctl) {
+               kfree(master);
+               return NULL;
+       }
+       /* override some callbacks */
+       kctl->info = master_info;
+       kctl->get = master_get;
+       kctl->put = master_put;
+       kctl->private_free = master_free;
+
+       /* additional (constant) TLV read */
+       if (tlv) {
+               /* FIXME: this assumes that the max volume is 0 dB */
+               kctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ;
+               kctl->tlv.p = tlv;
+       }
+       return kctl;
+}
index 65ce66adba5ad1251ce1ba68f3b9a53ebac48306..f99fe089495d716ae3c2d05a73903790d4b57fbc 100644 (file)
@@ -5,7 +5,7 @@
 
 snd-ice17xx-ak4xxx-objs := ak4xxx.o
 snd-ice1712-objs := ice1712.o delta.o hoontech.o ews.o
-snd-ice1724-objs := ice1724.o amp.o revo.o aureon.o vt1720_mobo.o pontis.o prodigy192.o juli.o phase.o wtm.o
+snd-ice1724-objs := ice1724.o amp.o revo.o aureon.o vt1720_mobo.o pontis.o prodigy192.o prodigy_hifi.o juli.o phase.o wtm.o se.o
 
 # Toplevel Module Dependency
 obj-$(CONFIG_SND_ICE1712) += snd-ice1712.o snd-ice17xx-ak4xxx.o
index a1aba0d7d0e4aeda2da187631350e71c106add0d..dab31b2756a608b2e52f60c31058e4e4f19cd306 100644 (file)
@@ -21,7 +21,6 @@
  *
  */      
 
-#include <sound/driver.h>
 #include <asm/io.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
index 6e13d758bb5d1ce1b8e3424628b61c62229e593c..37564300b50d84d00b0bfb97a9225cb8646d77d5 100644 (file)
@@ -21,7 +21,6 @@
  *
  */      
 
-#include <sound/driver.h>
 #include <asm/io.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
index ec0699c89952f9c0d5b9ecc62163afd6483a39eb..868ae291b960fd32f6054b322cdca8cd3bfad326 100644 (file)
@@ -47,7 +47,6 @@
  *
  */      
 
-#include <sound/driver.h>
 #include <asm/io.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include "aureon.h"
 #include <sound/tlv.h>
 
+/* AC97 register cache for Aureon */
+struct aureon_spec {
+       unsigned short stac9744[64];
+       unsigned int cs8415_mux;
+       unsigned short master[2];
+       unsigned short vol[8];
+       unsigned char pca9554_out;
+};
+
 /* WM8770 registers */
 #define WM_DAC_ATTEN           0x00    /* DAC1-8 analog attenuation */
 #define WM_DAC_MASTER_ATTEN    0x08    /* DAC master analog attenuation */
@@ -205,7 +213,8 @@ static int aureon_universe_inmux_get(struct snd_kcontrol *kcontrol,
                                     struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
-       ucontrol->value.integer.value[0] = ice->spec.aureon.pca9554_out;
+       struct aureon_spec *spec = ice->spec;
+       ucontrol->value.enumerated.item[0] = spec->pca9554_out;
        return 0;
 }
 
@@ -213,16 +222,18 @@ static int aureon_universe_inmux_put(struct snd_kcontrol *kcontrol,
                                     struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+       struct aureon_spec *spec = ice->spec;
        unsigned char oval, nval;
        int change;
 
+       nval = ucontrol->value.enumerated.item[0];
+       if (nval >= 3)
+               return -EINVAL;
        snd_ice1712_save_gpio_status(ice);
-       
-       oval = ice->spec.aureon.pca9554_out;
-       nval = ucontrol->value.integer.value[0];
+       oval = spec->pca9554_out;
        if ((change = (oval != nval))) {
                aureon_pca9554_write(ice, PCA9554_OUT, nval);
-               ice->spec.aureon.pca9554_out = nval;
+               spec->pca9554_out = nval;
        }
        snd_ice1712_restore_gpio_status(ice);
        
@@ -233,6 +244,7 @@ static int aureon_universe_inmux_put(struct snd_kcontrol *kcontrol,
 static void aureon_ac97_write(struct snd_ice1712 *ice, unsigned short reg,
                              unsigned short val)
 {
+       struct aureon_spec *spec = ice->spec;
        unsigned int tmp;
 
        /* Send address to XILINX chip */
@@ -280,12 +292,13 @@ static void aureon_ac97_write(struct snd_ice1712 *ice, unsigned short reg,
        udelay(10);
        
        /* Store the data in out private buffer */
-       ice->spec.aureon.stac9744[(reg & 0x7F) >> 1] = val;
+       spec->stac9744[(reg & 0x7F) >> 1] = val;
 }
 
 static unsigned short aureon_ac97_read(struct snd_ice1712 *ice, unsigned short reg)
 {
-       return ice->spec.aureon.stac9744[(reg & 0x7F) >> 1];
+       struct aureon_spec *spec = ice->spec;
+       return spec->stac9744[(reg & 0x7F) >> 1];
 }
 
 /*
@@ -293,6 +306,7 @@ static unsigned short aureon_ac97_read(struct snd_ice1712 *ice, unsigned short r
  */
 static int aureon_ac97_init (struct snd_ice1712 *ice)
 {
+       struct aureon_spec *spec = ice->spec;
        int i;
        static const unsigned short ac97_defaults[] = {
                0x00, 0x9640,
@@ -330,9 +344,9 @@ static int aureon_ac97_init (struct snd_ice1712 *ice)
        snd_ice1712_gpio_write(ice, tmp);
        udelay(3);
        
-       memset(&ice->spec.aureon.stac9744, 0, sizeof(ice->spec.aureon.stac9744));
+       memset(&spec->stac9744, 0, sizeof(spec->stac9744));
        for (i=0; ac97_defaults[i] != (unsigned short)-1; i+=2)
-               ice->spec.aureon.stac9744[(ac97_defaults[i]) >> 1] = ac97_defaults[i+1];
+               spec->stac9744[(ac97_defaults[i]) >> 1] = ac97_defaults[i+1];
                
        aureon_ac97_write(ice, AC97_MASTER, 0x0000); // Unmute AC'97 master volume permanently - muting is done by WM8770
 
@@ -744,27 +758,33 @@ static int wm_master_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem
 static int wm_master_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+       struct aureon_spec *spec = ice->spec;
        int i;
        for (i=0; i<2; i++)
-               ucontrol->value.integer.value[i] = ice->spec.aureon.master[i] & ~WM_VOL_MUTE;
+               ucontrol->value.integer.value[i] =
+                       spec->master[i] & ~WM_VOL_MUTE;
        return 0;
 }
 
 static int wm_master_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+       struct aureon_spec *spec = ice->spec;
        int ch, change = 0;
 
        snd_ice1712_save_gpio_status(ice);
        for (ch = 0; ch < 2; ch++) {
-               if (ucontrol->value.integer.value[ch] != ice->spec.aureon.master[ch]) {
+               unsigned int vol = ucontrol->value.integer.value[ch];
+               if (vol > WM_VOL_MAX)
+                       continue;
+               vol |= spec->master[ch] & WM_VOL_MUTE;
+               if (vol != spec->master[ch]) {
                        int dac;
-                       ice->spec.aureon.master[ch] &= WM_VOL_MUTE;
-                       ice->spec.aureon.master[ch] |= ucontrol->value.integer.value[ch];
+                       spec->master[ch] = vol;
                        for (dac = 0; dac < ice->num_total_dacs; dac += 2)
                                wm_set_vol(ice, WM_DAC_ATTEN + dac + ch,
-                                          ice->spec.aureon.vol[dac + ch],
-                                          ice->spec.aureon.master[ch]);
+                                          spec->vol[dac + ch],
+                                          spec->master[ch]);
                        change = 1;
                }
        }
@@ -788,18 +808,21 @@ static int wm_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *
 static int wm_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+       struct aureon_spec *spec = ice->spec;
        int i, ofs, voices;
 
        voices = kcontrol->private_value >> 8;
        ofs = kcontrol->private_value & 0xff;
        for (i = 0; i < voices; i++)
-               ucontrol->value.integer.value[i] = ice->spec.aureon.vol[ofs+i] & ~WM_VOL_MUTE;
+               ucontrol->value.integer.value[i] =
+                       spec->vol[ofs+i] & ~WM_VOL_MUTE;
        return 0;
 }
 
 static int wm_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+       struct aureon_spec *spec = ice->spec;
        int i, idx, ofs, voices;
        int change = 0;
 
@@ -807,12 +830,15 @@ static int wm_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *
        ofs = kcontrol->private_value & 0xff;
        snd_ice1712_save_gpio_status(ice);
        for (i = 0; i < voices; i++) {
-               idx  = WM_DAC_ATTEN + ofs + i;
-               if (ucontrol->value.integer.value[i] != ice->spec.aureon.vol[ofs+i]) {
-                       ice->spec.aureon.vol[ofs+i] &= WM_VOL_MUTE;
-                       ice->spec.aureon.vol[ofs+i] |= ucontrol->value.integer.value[i];
-                       wm_set_vol(ice, idx, ice->spec.aureon.vol[ofs+i],
-                                  ice->spec.aureon.master[i]);
+               unsigned int vol = ucontrol->value.integer.value[i];
+               if (vol > 0x7f)
+                       continue;
+               vol |= spec->vol[ofs+i];
+               if (vol != spec->vol[ofs+i]) {
+                       spec->vol[ofs+i] = vol;
+                       idx  = WM_DAC_ATTEN + ofs + i;
+                       wm_set_vol(ice, idx, spec->vol[ofs + i],
+                                  spec->master[i]);
                        change = 1;
                }
        }
@@ -834,19 +860,22 @@ static int wm_mute_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info
 static int wm_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+       struct aureon_spec *spec = ice->spec;
        int voices, ofs, i;
        
        voices = kcontrol->private_value >> 8;
        ofs = kcontrol->private_value & 0xFF;
 
        for (i = 0; i < voices; i++)
-               ucontrol->value.integer.value[i] = (ice->spec.aureon.vol[ofs+i] & WM_VOL_MUTE) ? 0 : 1;
+               ucontrol->value.integer.value[i] =
+                       (spec->vol[ofs + i] & WM_VOL_MUTE) ? 0 : 1;
        return 0;
 }
 
 static int wm_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+       struct aureon_spec *spec = ice->spec;
        int change = 0, voices, ofs, i;
 
        voices = kcontrol->private_value >> 8;
@@ -854,13 +883,13 @@ static int wm_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value
 
        snd_ice1712_save_gpio_status(ice);
        for (i = 0; i < voices; i++) {
-               int val = (ice->spec.aureon.vol[ofs + i] & WM_VOL_MUTE) ? 0 : 1;
+               int val = (spec->vol[ofs + i] & WM_VOL_MUTE) ? 0 : 1;
                if (ucontrol->value.integer.value[i] != val) {
-                       ice->spec.aureon.vol[ofs + i] &= ~WM_VOL_MUTE;
-                       ice->spec.aureon.vol[ofs + i] |=
+                       spec->vol[ofs + i] &= ~WM_VOL_MUTE;
+                       spec->vol[ofs + i] |=
                                ucontrol->value.integer.value[i] ? 0 : WM_VOL_MUTE;
-                       wm_set_vol(ice, ofs + i, ice->spec.aureon.vol[ofs + i],
-                                  ice->spec.aureon.master[i]);
+                       wm_set_vol(ice, ofs + i, spec->vol[ofs + i],
+                                  spec->master[i]);
                        change = 1;
                }
        }
@@ -877,29 +906,33 @@ static int wm_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value
 static int wm_master_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+       struct aureon_spec *spec = ice->spec;
        
-       ucontrol->value.integer.value[0] = (ice->spec.aureon.master[0] & WM_VOL_MUTE) ? 0 : 1;
-       ucontrol->value.integer.value[1] = (ice->spec.aureon.master[1] & WM_VOL_MUTE) ? 0 : 1;
+       ucontrol->value.integer.value[0] =
+               (spec->master[0] & WM_VOL_MUTE) ? 0 : 1;
+       ucontrol->value.integer.value[1] =
+               (spec->master[1] & WM_VOL_MUTE) ? 0 : 1;
        return 0;
 }
 
 static int wm_master_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+       struct aureon_spec *spec = ice->spec;
        int change = 0, i;
 
        snd_ice1712_save_gpio_status(ice);
        for (i = 0; i < 2; i++) {
-               int val = (ice->spec.aureon.master[i] & WM_VOL_MUTE) ? 0 : 1;
+               int val = (spec->master[i] & WM_VOL_MUTE) ? 0 : 1;
                if (ucontrol->value.integer.value[i] != val) {
                        int dac;
-                       ice->spec.aureon.master[i] &= ~WM_VOL_MUTE;
-                       ice->spec.aureon.master[i] |=
+                       spec->master[i] &= ~WM_VOL_MUTE;
+                       spec->master[i] |=
                                ucontrol->value.integer.value[i] ? 0 : WM_VOL_MUTE;
                        for (dac = 0; dac < ice->num_total_dacs; dac += 2)
                                wm_set_vol(ice, WM_DAC_ATTEN + dac + i,
-                                          ice->spec.aureon.vol[dac + i],
-                                          ice->spec.aureon.master[i]);
+                                          spec->vol[dac + i],
+                                          spec->master[i]);
                        change = 1;
                }
        }
@@ -940,8 +973,10 @@ static int wm_pcm_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_val
        unsigned short ovol, nvol;
        int change = 0;
 
-       snd_ice1712_save_gpio_status(ice);
        nvol = ucontrol->value.integer.value[0];
+       if (nvol > PCM_RES)
+               return -EINVAL;
+       snd_ice1712_save_gpio_status(ice);
        nvol = (nvol ? (nvol + PCM_MIN) : 0) & 0xff;
        ovol = wm_get(ice, WM_DAC_DIG_MASTER_ATTEN) & 0xff;
        if (ovol != nvol) {
@@ -1031,7 +1066,7 @@ static int wm_adc_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_val
        snd_ice1712_save_gpio_status(ice);
        for (i = 0; i < 2; i++) {
                idx  = WM_ADC_GAIN + i;
-               nvol = ucontrol->value.integer.value[i];
+               nvol = ucontrol->value.integer.value[i] & 0x1f;
                ovol = wm_get(ice, idx);
                if ((ovol & 0x1f) != nvol) {
                        wm_put(ice, idx, nvol | (ovol & ~0x1f));
@@ -1143,10 +1178,11 @@ static int aureon_cs8415_mux_info(struct snd_kcontrol *kcontrol, struct snd_ctl_
 static int aureon_cs8415_mux_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+       struct aureon_spec *spec = ice->spec;
 
        //snd_ice1712_save_gpio_status(ice);
        //val = aureon_cs8415_get(ice, CS8415_CTRL2);
-       ucontrol->value.enumerated.item[0] = ice->spec.aureon.cs8415_mux;
+       ucontrol->value.enumerated.item[0] = spec->cs8415_mux;
        //snd_ice1712_restore_gpio_status(ice);
        return 0;
 }
@@ -1154,6 +1190,7 @@ static int aureon_cs8415_mux_get(struct snd_kcontrol *kcontrol, struct snd_ctl_e
 static int aureon_cs8415_mux_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+       struct aureon_spec *spec = ice->spec;
        unsigned short oval, nval;
        int change;
 
@@ -1165,7 +1202,7 @@ static int aureon_cs8415_mux_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e
        if (change)
                aureon_cs8415_put(ice, CS8415_CTRL2, nval);
        snd_ice1712_restore_gpio_status(ice);
-       ice->spec.aureon.cs8415_mux = ucontrol->value.enumerated.item[0];
+       spec->cs8415_mux = ucontrol->value.enumerated.item[0];
        return change;
 }
 
@@ -2001,10 +2038,16 @@ static int __devinit aureon_init(struct snd_ice1712 *ice)
                0x0605, /* slave, 24bit, MSB on second OSCLK, SDOUT for right channel when OLRCK is high */
                (unsigned short)-1
        };
+       struct aureon_spec *spec;
        unsigned int tmp;
        const unsigned short *p;
        int err, i;
 
+       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+       if (!spec)
+               return -ENOMEM;
+       ice->spec = spec;
+
        if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AUREON51_SKY) {
                ice->num_total_dacs = 6;
                ice->num_total_adcs = 2;
@@ -2055,7 +2098,7 @@ static int __devinit aureon_init(struct snd_ice1712 *ice)
            ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71XT) {
                for (p = cs_inits; *p != (unsigned short)-1; p++)
                        aureon_spi_write(ice, AUREON_CS8415_CS, *p | 0x200000, 24);
-               ice->spec.aureon.cs8415_mux = 1;
+               spec->cs8415_mux = 1;
 
                aureon_set_headphone_amp(ice, 1);
        }
@@ -2066,11 +2109,11 @@ static int __devinit aureon_init(struct snd_ice1712 *ice)
        aureon_pca9554_write(ice, PCA9554_DIR, 0x00);
        aureon_pca9554_write(ice, PCA9554_OUT, 0x00);   /* internal AUX */
        
-       ice->spec.aureon.master[0] = WM_VOL_MUTE;
-       ice->spec.aureon.master[1] = WM_VOL_MUTE;
+       spec->master[0] = WM_VOL_MUTE;
+       spec->master[1] = WM_VOL_MUTE;
        for (i = 0; i < ice->num_total_dacs; i++) {
-               ice->spec.aureon.vol[i] = WM_VOL_MUTE;
-               wm_set_vol(ice, i, ice->spec.aureon.vol[i], ice->spec.aureon.master[i % 2]);
+               spec->vol[i] = WM_VOL_MUTE;
+               wm_set_vol(ice, i, spec->vol[i], spec->master[i % 2]);
        }
 
        return 0;
index 371f78461db4b65a7c2d71152d105ecf00ca9f78..efd180b40e56382b308fb61c48ffad383193114b 100644 (file)
@@ -22,7 +22,6 @@
  *
  */      
 
-#include <sound/driver.h>
 #include <asm/io.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
@@ -405,7 +404,7 @@ static int snd_ice1712_delta1010lt_wordclock_status_get(struct snd_kcontrol *kco
        if (snd_i2c_sendbytes(ice->cs8427, &reg, 1) != 1)
                snd_printk(KERN_ERR "unable to send register 0x%x byte to CS8427\n", reg);
        snd_i2c_readbytes(ice->cs8427, &reg, 1);
-       ucontrol->value.integer.value[0] = (reg ? 1 : 0);
+       ucontrol->value.integer.value[0] = (reg & CS8427_UNLOCK) ? 1 : 0;
        return 0;
 }
 
index 75e4e5e0f1e46b93429b51ca3e57330faa1ef5e4..064760d2a0278596d415a252399f7c366fdad462 100644 (file)
@@ -22,7 +22,6 @@
  *
  */      
 
-#include <sound/driver.h>
 #include <asm/io.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
@@ -45,6 +44,11 @@ enum {
 };
        
 
+/* additional i2c devices for EWS boards */
+struct ews_spec {
+       struct snd_i2c_device *i2cdevs[3];
+};
+
 /*
  * access via i2c mode (for EWX 24/96, EWS 88MT&D)
  */
@@ -142,15 +146,17 @@ static struct snd_i2c_bit_ops snd_ice1712_ewx_cs8427_bit_ops = {
 /* AK4524 chip select; address 0x48 bit 0-3 */
 static int snd_ice1712_ews88mt_chip_select(struct snd_ice1712 *ice, int chip_mask)
 {
+       struct ews_spec *spec = ice->spec;
        unsigned char data, ndata;
 
        snd_assert(chip_mask >= 0 && chip_mask <= 0x0f, return -EINVAL);
        snd_i2c_lock(ice->i2c);
-       if (snd_i2c_readbytes(ice->spec.i2cdevs[EWS_I2C_PCF2], &data, 1) != 1)
+       if (snd_i2c_readbytes(spec->i2cdevs[EWS_I2C_PCF2], &data, 1) != 1)
                goto __error;
        ndata = (data & 0xf0) | chip_mask;
        if (ndata != data)
-               if (snd_i2c_sendbytes(ice->spec.i2cdevs[EWS_I2C_PCF2], &ndata, 1) != 1)
+               if (snd_i2c_sendbytes(spec->i2cdevs[EWS_I2C_PCF2], &ndata, 1)
+                   != 1)
                        goto __error;
        snd_i2c_unlock(ice->i2c);
        return 0;
@@ -224,6 +230,7 @@ static void dmx6fire_ak4524_lock(struct snd_akm4xxx *ak, int chip)
 
 static void snd_ice1712_ews_cs8404_spdif_write(struct snd_ice1712 *ice, unsigned char bits)
 {
+       struct ews_spec *spec = ice->spec;
        unsigned char bytes[2];
 
        snd_i2c_lock(ice->i2c);
@@ -231,15 +238,18 @@ static void snd_ice1712_ews_cs8404_spdif_write(struct snd_ice1712 *ice, unsigned
        case ICE1712_SUBDEVICE_EWS88MT:
        case ICE1712_SUBDEVICE_EWS88MT_NEW:
        case ICE1712_SUBDEVICE_PHASE88:
-               if (snd_i2c_sendbytes(ice->spec.i2cdevs[EWS_I2C_CS8404], &bits, 1) != 1)
+               if (snd_i2c_sendbytes(spec->i2cdevs[EWS_I2C_CS8404], &bits, 1)
+                   != 1)
                        goto _error;
                break;
        case ICE1712_SUBDEVICE_EWS88D:
-               if (snd_i2c_readbytes(ice->spec.i2cdevs[EWS_I2C_88D], bytes, 2) != 2)
+               if (snd_i2c_readbytes(spec->i2cdevs[EWS_I2C_88D], bytes, 2)
+                   != 2)
                        goto _error;
                if (bits != bytes[1]) {
                        bytes[1] = bits;
-                       if (snd_i2c_sendbytes(ice->spec.i2cdevs[EWS_I2C_88D], bytes, 2) != 2)
+                       if (snd_i2c_sendbytes(spec->i2cdevs[EWS_I2C_88D],
+                                             bytes, 2) != 2)
                                goto _error;
                }
                break;
@@ -412,6 +422,7 @@ static int __devinit snd_ice1712_ews_init(struct snd_ice1712 *ice)
 {
        int err;
        struct snd_akm4xxx *ak;
+       struct ews_spec *spec;
 
        /* set the analog DACs */
        switch (ice->eeprom.subvendor) {
@@ -436,6 +447,11 @@ static int __devinit snd_ice1712_ews_init(struct snd_ice1712 *ice)
                break;
        }
 
+       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+       if (!spec)
+               return -ENOMEM;
+       ice->spec = spec;
+
        /* create i2c */
        if ((err = snd_i2c_bus_create(ice->card, "ICE1712 GPIO 1", NULL, &ice->i2c)) < 0) {
                snd_printk(KERN_ERR "unable to create I2C bus\n");
@@ -447,7 +463,10 @@ static int __devinit snd_ice1712_ews_init(struct snd_ice1712 *ice)
        /* create i2c devices */
        switch (ice->eeprom.subvendor) {
        case ICE1712_SUBDEVICE_DMX6FIRE:
-               if ((err = snd_i2c_device_create(ice->i2c, "PCF9554", ICE1712_6FIRE_PCF9554_ADDR, &ice->spec.i2cdevs[EWS_I2C_6FIRE])) < 0) {
+               err = snd_i2c_device_create(ice->i2c, "PCF9554",
+                                           ICE1712_6FIRE_PCF9554_ADDR,
+                                           &spec->i2cdevs[EWS_I2C_6FIRE]);
+               if (err < 0) {
                        snd_printk(KERN_ERR "PCF9554 initialization failed\n");
                        return err;
                }
@@ -456,18 +475,30 @@ static int __devinit snd_ice1712_ews_init(struct snd_ice1712 *ice)
        case ICE1712_SUBDEVICE_EWS88MT:
        case ICE1712_SUBDEVICE_EWS88MT_NEW:
        case ICE1712_SUBDEVICE_PHASE88:
-               if ((err = snd_i2c_device_create(ice->i2c, "CS8404", ICE1712_EWS88MT_CS8404_ADDR, &ice->spec.i2cdevs[EWS_I2C_CS8404])) < 0)
+               err = snd_i2c_device_create(ice->i2c, "CS8404",
+                                           ICE1712_EWS88MT_CS8404_ADDR,
+                                           &spec->i2cdevs[EWS_I2C_CS8404]);
+               if (err < 0)
                        return err;
-               if ((err = snd_i2c_device_create(ice->i2c, "PCF8574 (1st)", ICE1712_EWS88MT_INPUT_ADDR, &ice->spec.i2cdevs[EWS_I2C_PCF1])) < 0)
+               err = snd_i2c_device_create(ice->i2c, "PCF8574 (1st)",
+                                           ICE1712_EWS88MT_INPUT_ADDR,
+                                           &spec->i2cdevs[EWS_I2C_PCF1]);
+               if (err < 0)
                        return err;
-               if ((err = snd_i2c_device_create(ice->i2c, "PCF8574 (2nd)", ICE1712_EWS88MT_OUTPUT_ADDR, &ice->spec.i2cdevs[EWS_I2C_PCF2])) < 0)
+               err = snd_i2c_device_create(ice->i2c, "PCF8574 (2nd)",
+                                           ICE1712_EWS88MT_OUTPUT_ADDR,
+                                           &spec->i2cdevs[EWS_I2C_PCF2]);
+               if (err < 0)
                        return err;
                /* Check if the front module is connected */
                if ((err = snd_ice1712_ews88mt_chip_select(ice, 0x0f)) < 0)
                        return err;
                break;
        case ICE1712_SUBDEVICE_EWS88D:
-               if ((err = snd_i2c_device_create(ice->i2c, "PCF8575", ICE1712_EWS88D_PCF_ADDR, &ice->spec.i2cdevs[EWS_I2C_88D])) < 0)
+               err = snd_i2c_device_create(ice->i2c, "PCF8575",
+                                           ICE1712_EWS88D_PCF_ADDR,
+                                           &spec->i2cdevs[EWS_I2C_88D]);
+               if (err < 0)
                        return err;
                break;
        }
@@ -507,7 +538,7 @@ static int __devinit snd_ice1712_ews_init(struct snd_ice1712 *ice)
        }
 
        /* analog section */
-       ak = ice->akm = kmalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL);
+       ak = ice->akm = kzalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL);
        if (! ak)
                return -ENOMEM;
        ice->akm_codecs = 1;
@@ -605,10 +636,11 @@ static struct snd_kcontrol_new snd_ice1712_ewx2496_controls[] __devinitdata = {
 static int snd_ice1712_ews88mt_output_sense_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+       struct ews_spec *spec = ice->spec;
        unsigned char data;
 
        snd_i2c_lock(ice->i2c);
-       if (snd_i2c_readbytes(ice->spec.i2cdevs[EWS_I2C_PCF2], &data, 1) != 1) {
+       if (snd_i2c_readbytes(spec->i2cdevs[EWS_I2C_PCF2], &data, 1) != 1) {
                snd_i2c_unlock(ice->i2c);
                return -EIO;
        }
@@ -621,15 +653,17 @@ static int snd_ice1712_ews88mt_output_sense_get(struct snd_kcontrol *kcontrol, s
 static int snd_ice1712_ews88mt_output_sense_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+       struct ews_spec *spec = ice->spec;
        unsigned char data, ndata;
 
        snd_i2c_lock(ice->i2c);
-       if (snd_i2c_readbytes(ice->spec.i2cdevs[EWS_I2C_PCF2], &data, 1) != 1) {
+       if (snd_i2c_readbytes(spec->i2cdevs[EWS_I2C_PCF2], &data, 1) != 1) {
                snd_i2c_unlock(ice->i2c);
                return -EIO;
        }
        ndata = (data & ~ICE1712_EWS88MT_OUTPUT_SENSE) | (ucontrol->value.enumerated.item[0] ? ICE1712_EWS88MT_OUTPUT_SENSE : 0);
-       if (ndata != data && snd_i2c_sendbytes(ice->spec.i2cdevs[EWS_I2C_PCF2], &ndata, 1) != 1) {
+       if (ndata != data && snd_i2c_sendbytes(spec->i2cdevs[EWS_I2C_PCF2],
+                                              &ndata, 1) != 1) {
                snd_i2c_unlock(ice->i2c);
                return -EIO;
        }
@@ -641,12 +675,13 @@ static int snd_ice1712_ews88mt_output_sense_put(struct snd_kcontrol *kcontrol, s
 static int snd_ice1712_ews88mt_input_sense_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+       struct ews_spec *spec = ice->spec;
        int channel = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
        unsigned char data;
 
        snd_assert(channel >= 0 && channel <= 7, return 0);
        snd_i2c_lock(ice->i2c);
-       if (snd_i2c_readbytes(ice->spec.i2cdevs[EWS_I2C_PCF1], &data, 1) != 1) {
+       if (snd_i2c_readbytes(spec->i2cdevs[EWS_I2C_PCF1], &data, 1) != 1) {
                snd_i2c_unlock(ice->i2c);
                return -EIO;
        }
@@ -660,17 +695,19 @@ static int snd_ice1712_ews88mt_input_sense_get(struct snd_kcontrol *kcontrol, st
 static int snd_ice1712_ews88mt_input_sense_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+       struct ews_spec *spec = ice->spec;
        int channel = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
        unsigned char data, ndata;
 
        snd_assert(channel >= 0 && channel <= 7, return 0);
        snd_i2c_lock(ice->i2c);
-       if (snd_i2c_readbytes(ice->spec.i2cdevs[EWS_I2C_PCF1], &data, 1) != 1) {
+       if (snd_i2c_readbytes(spec->i2cdevs[EWS_I2C_PCF1], &data, 1) != 1) {
                snd_i2c_unlock(ice->i2c);
                return -EIO;
        }
        ndata = (data & ~(1 << channel)) | (ucontrol->value.enumerated.item[0] ? 0 : (1 << channel));
-       if (ndata != data && snd_i2c_sendbytes(ice->spec.i2cdevs[EWS_I2C_PCF1], &ndata, 1) != 1) {
+       if (ndata != data && snd_i2c_sendbytes(spec->i2cdevs[EWS_I2C_PCF1],
+                                              &ndata, 1) != 1) {
                snd_i2c_unlock(ice->i2c);
                return -EIO;
        }
@@ -705,12 +742,13 @@ static struct snd_kcontrol_new snd_ice1712_ews88mt_output_sense __devinitdata =
 static int snd_ice1712_ews88d_control_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+       struct ews_spec *spec = ice->spec;
        int shift = kcontrol->private_value & 0xff;
        int invert = (kcontrol->private_value >> 8) & 1;
        unsigned char data[2];
        
        snd_i2c_lock(ice->i2c);
-       if (snd_i2c_readbytes(ice->spec.i2cdevs[EWS_I2C_88D], data, 2) != 2) {
+       if (snd_i2c_readbytes(spec->i2cdevs[EWS_I2C_88D], data, 2) != 2) {
                snd_i2c_unlock(ice->i2c);
                return -EIO;
        }
@@ -725,13 +763,14 @@ static int snd_ice1712_ews88d_control_get(struct snd_kcontrol *kcontrol, struct
 static int snd_ice1712_ews88d_control_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+       struct ews_spec *spec = ice->spec;
        int shift = kcontrol->private_value & 0xff;
        int invert = (kcontrol->private_value >> 8) & 1;
        unsigned char data[2], ndata[2];
        int change;
 
        snd_i2c_lock(ice->i2c);
-       if (snd_i2c_readbytes(ice->spec.i2cdevs[EWS_I2C_88D], data, 2) != 2) {
+       if (snd_i2c_readbytes(spec->i2cdevs[EWS_I2C_88D], data, 2) != 2) {
                snd_i2c_unlock(ice->i2c);
                return -EIO;
        }
@@ -744,7 +783,8 @@ static int snd_ice1712_ews88d_control_put(struct snd_kcontrol *kcontrol, struct
                        ndata[shift >> 3] |= (1 << (shift & 7));
        }
        change = (data[shift >> 3] != ndata[shift >> 3]);
-       if (change && snd_i2c_sendbytes(ice->spec.i2cdevs[EWS_I2C_88D], data, 2) != 2) {
+       if (change &&
+           snd_i2c_sendbytes(spec->i2cdevs[EWS_I2C_88D], data, 2) != 2) {
                snd_i2c_unlock(ice->i2c);
                return -EIO;
        }
@@ -778,11 +818,13 @@ static struct snd_kcontrol_new snd_ice1712_ews88d_controls[] __devinitdata = {
 static int snd_ice1712_6fire_read_pca(struct snd_ice1712 *ice, unsigned char reg)
 {
        unsigned char byte;
+       struct ews_spec *spec = ice->spec;
+
        snd_i2c_lock(ice->i2c);
        byte = reg;
-       snd_i2c_sendbytes(ice->spec.i2cdevs[EWS_I2C_6FIRE], &byte, 1);
+       snd_i2c_sendbytes(spec->i2cdevs[EWS_I2C_6FIRE], &byte, 1);
        byte = 0;
-       if (snd_i2c_readbytes(ice->spec.i2cdevs[EWS_I2C_6FIRE], &byte, 1) != 1) {
+       if (snd_i2c_readbytes(spec->i2cdevs[EWS_I2C_6FIRE], &byte, 1) != 1) {
                snd_i2c_unlock(ice->i2c);
                printk(KERN_ERR "cannot read pca\n");
                return -EIO;
@@ -794,10 +836,12 @@ static int snd_ice1712_6fire_read_pca(struct snd_ice1712 *ice, unsigned char reg
 static int snd_ice1712_6fire_write_pca(struct snd_ice1712 *ice, unsigned char reg, unsigned char data)
 {
        unsigned char bytes[2];
+       struct ews_spec *spec = ice->spec;
+
        snd_i2c_lock(ice->i2c);
        bytes[0] = reg;
        bytes[1] = data;
-       if (snd_i2c_sendbytes(ice->spec.i2cdevs[EWS_I2C_6FIRE], bytes, 2) != 2) {
+       if (snd_i2c_sendbytes(spec->i2cdevs[EWS_I2C_6FIRE], bytes, 2) != 2) {
                snd_i2c_unlock(ice->i2c);
                return -EIO;
        }
index abcfd1da65874466f935515f0116afc54a20260d..cf5c7c0898fd4e6c488321a55259f2855a23a3f4 100644 (file)
@@ -21,7 +21,6 @@
  *
  */      
 
-#include <sound/driver.h>
 #include <asm/io.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include "ice1712.h"
 #include "hoontech.h"
 
+/* Hoontech-specific setting */
+struct hoontech_spec {
+       unsigned char boxbits[4];
+       unsigned int config;
+       unsigned short boxconfig[4];
+};
 
 static void __devinit snd_ice1712_stdsp24_gpio_write(struct snd_ice1712 *ice, unsigned char byte)
 {
@@ -50,169 +55,182 @@ static void __devinit snd_ice1712_stdsp24_gpio_write(struct snd_ice1712 *ice, un
 
 static void __devinit snd_ice1712_stdsp24_darear(struct snd_ice1712 *ice, int activate)
 {
+       struct hoontech_spec *spec = ice->spec;
        mutex_lock(&ice->gpio_mutex);
-       ICE1712_STDSP24_0_DAREAR(ice->spec.hoontech.boxbits, activate);
-       snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[0]);
+       ICE1712_STDSP24_0_DAREAR(spec->boxbits, activate);
+       snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[0]);
        mutex_unlock(&ice->gpio_mutex);
 }
 
 static void __devinit snd_ice1712_stdsp24_mute(struct snd_ice1712 *ice, int activate)
 {
+       struct hoontech_spec *spec = ice->spec;
        mutex_lock(&ice->gpio_mutex);
-       ICE1712_STDSP24_3_MUTE(ice->spec.hoontech.boxbits, activate);
-       snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[3]);
+       ICE1712_STDSP24_3_MUTE(spec->boxbits, activate);
+       snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[3]);
        mutex_unlock(&ice->gpio_mutex);
 }
 
 static void __devinit snd_ice1712_stdsp24_insel(struct snd_ice1712 *ice, int activate)
 {
+       struct hoontech_spec *spec = ice->spec;
        mutex_lock(&ice->gpio_mutex);
-       ICE1712_STDSP24_3_INSEL(ice->spec.hoontech.boxbits, activate);
-       snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[3]);
+       ICE1712_STDSP24_3_INSEL(spec->boxbits, activate);
+       snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[3]);
        mutex_unlock(&ice->gpio_mutex);
 }
 
 static void __devinit snd_ice1712_stdsp24_box_channel(struct snd_ice1712 *ice, int box, int chn, int activate)
 {
+       struct hoontech_spec *spec = ice->spec;
+
        mutex_lock(&ice->gpio_mutex);
 
        /* select box */
-       ICE1712_STDSP24_0_BOX(ice->spec.hoontech.boxbits, box);
-       snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[0]);
+       ICE1712_STDSP24_0_BOX(spec->boxbits, box);
+       snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[0]);
 
        /* prepare for write */
        if (chn == 3)
-               ICE1712_STDSP24_2_CHN4(ice->spec.hoontech.boxbits, 0);
-       ICE1712_STDSP24_2_MIDI1(ice->spec.hoontech.boxbits, activate);
-       snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[2]);
-       snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[3]);
-
-       ICE1712_STDSP24_1_CHN1(ice->spec.hoontech.boxbits, 1);
-       ICE1712_STDSP24_1_CHN2(ice->spec.hoontech.boxbits, 1);
-       ICE1712_STDSP24_1_CHN3(ice->spec.hoontech.boxbits, 1);
-       ICE1712_STDSP24_2_CHN4(ice->spec.hoontech.boxbits, 1);
-       snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[1]);
-       snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[2]);
+               ICE1712_STDSP24_2_CHN4(spec->boxbits, 0);
+       ICE1712_STDSP24_2_MIDI1(spec->boxbits, activate);
+       snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[2]);
+       snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[3]);
+
+       ICE1712_STDSP24_1_CHN1(spec->boxbits, 1);
+       ICE1712_STDSP24_1_CHN2(spec->boxbits, 1);
+       ICE1712_STDSP24_1_CHN3(spec->boxbits, 1);
+       ICE1712_STDSP24_2_CHN4(spec->boxbits, 1);
+       snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[1]);
+       snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[2]);
        udelay(100);
        if (chn == 3) {
-               ICE1712_STDSP24_2_CHN4(ice->spec.hoontech.boxbits, 0);
-               snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[2]);
+               ICE1712_STDSP24_2_CHN4(spec->boxbits, 0);
+               snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[2]);
        } else {
                switch (chn) {
-               case 0: ICE1712_STDSP24_1_CHN1(ice->spec.hoontech.boxbits, 0); break;
-               case 1: ICE1712_STDSP24_1_CHN2(ice->spec.hoontech.boxbits, 0); break;
-               case 2: ICE1712_STDSP24_1_CHN3(ice->spec.hoontech.boxbits, 0); break;
+               case 0: ICE1712_STDSP24_1_CHN1(spec->boxbits, 0); break;
+               case 1: ICE1712_STDSP24_1_CHN2(spec->boxbits, 0); break;
+               case 2: ICE1712_STDSP24_1_CHN3(spec->boxbits, 0); break;
                }
-               snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[1]);
+               snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[1]);
        }
        udelay(100);
-       ICE1712_STDSP24_1_CHN1(ice->spec.hoontech.boxbits, 1);
-       ICE1712_STDSP24_1_CHN2(ice->spec.hoontech.boxbits, 1);
-       ICE1712_STDSP24_1_CHN3(ice->spec.hoontech.boxbits, 1);
-       ICE1712_STDSP24_2_CHN4(ice->spec.hoontech.boxbits, 1);
-       snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[1]);
-       snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[2]);
+       ICE1712_STDSP24_1_CHN1(spec->boxbits, 1);
+       ICE1712_STDSP24_1_CHN2(spec->boxbits, 1);
+       ICE1712_STDSP24_1_CHN3(spec->boxbits, 1);
+       ICE1712_STDSP24_2_CHN4(spec->boxbits, 1);
+       snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[1]);
+       snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[2]);
        udelay(100);
 
-       ICE1712_STDSP24_2_MIDI1(ice->spec.hoontech.boxbits, 0);
-       snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[2]);
+       ICE1712_STDSP24_2_MIDI1(spec->boxbits, 0);
+       snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[2]);
 
        mutex_unlock(&ice->gpio_mutex);
 }
 
 static void __devinit snd_ice1712_stdsp24_box_midi(struct snd_ice1712 *ice, int box, int master)
 {
+       struct hoontech_spec *spec = ice->spec;
+
        mutex_lock(&ice->gpio_mutex);
 
        /* select box */
-       ICE1712_STDSP24_0_BOX(ice->spec.hoontech.boxbits, box);
-       snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[0]);
+       ICE1712_STDSP24_0_BOX(spec->boxbits, box);
+       snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[0]);
 
-       ICE1712_STDSP24_2_MIDIIN(ice->spec.hoontech.boxbits, 1);
-       ICE1712_STDSP24_2_MIDI1(ice->spec.hoontech.boxbits, master);
-       snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[2]);
-       snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[3]);
+       ICE1712_STDSP24_2_MIDIIN(spec->boxbits, 1);
+       ICE1712_STDSP24_2_MIDI1(spec->boxbits, master);
+       snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[2]);
+       snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[3]);
 
        udelay(100);
        
-       ICE1712_STDSP24_2_MIDIIN(ice->spec.hoontech.boxbits, 0);
-       snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[2]);
+       ICE1712_STDSP24_2_MIDIIN(spec->boxbits, 0);
+       snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[2]);
        
        mdelay(10);
        
-       ICE1712_STDSP24_2_MIDIIN(ice->spec.hoontech.boxbits, 1);
-       snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[2]);
+       ICE1712_STDSP24_2_MIDIIN(spec->boxbits, 1);
+       snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[2]);
 
        mutex_unlock(&ice->gpio_mutex);
 }
 
 static void __devinit snd_ice1712_stdsp24_midi2(struct snd_ice1712 *ice, int activate)
 {
+       struct hoontech_spec *spec = ice->spec;
        mutex_lock(&ice->gpio_mutex);
-       ICE1712_STDSP24_3_MIDI2(ice->spec.hoontech.boxbits, activate);
-       snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[3]);
+       ICE1712_STDSP24_3_MIDI2(spec->boxbits, activate);
+       snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[3]);
        mutex_unlock(&ice->gpio_mutex);
 }
 
 static int __devinit snd_ice1712_hoontech_init(struct snd_ice1712 *ice)
 {
+       struct hoontech_spec *spec;
        int box, chn;
 
        ice->num_total_dacs = 8;
        ice->num_total_adcs = 8;
 
-       ice->spec.hoontech.boxbits[0] = 
-       ice->spec.hoontech.boxbits[1] = 
-       ice->spec.hoontech.boxbits[2] = 
-       ice->spec.hoontech.boxbits[3] = 0;      /* should be already */
-
-       ICE1712_STDSP24_SET_ADDR(ice->spec.hoontech.boxbits, 0);
-       ICE1712_STDSP24_CLOCK(ice->spec.hoontech.boxbits, 0, 1);
-       ICE1712_STDSP24_0_BOX(ice->spec.hoontech.boxbits, 0);
-       ICE1712_STDSP24_0_DAREAR(ice->spec.hoontech.boxbits, 0);
-
-       ICE1712_STDSP24_SET_ADDR(ice->spec.hoontech.boxbits, 1);
-       ICE1712_STDSP24_CLOCK(ice->spec.hoontech.boxbits, 1, 1);
-       ICE1712_STDSP24_1_CHN1(ice->spec.hoontech.boxbits, 1);
-       ICE1712_STDSP24_1_CHN2(ice->spec.hoontech.boxbits, 1);
-       ICE1712_STDSP24_1_CHN3(ice->spec.hoontech.boxbits, 1);
+       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+       if (!spec)
+               return -ENOMEM;
+       ice->spec = spec;
+
+       ICE1712_STDSP24_SET_ADDR(spec->boxbits, 0);
+       ICE1712_STDSP24_CLOCK(spec->boxbits, 0, 1);
+       ICE1712_STDSP24_0_BOX(spec->boxbits, 0);
+       ICE1712_STDSP24_0_DAREAR(spec->boxbits, 0);
+
+       ICE1712_STDSP24_SET_ADDR(spec->boxbits, 1);
+       ICE1712_STDSP24_CLOCK(spec->boxbits, 1, 1);
+       ICE1712_STDSP24_1_CHN1(spec->boxbits, 1);
+       ICE1712_STDSP24_1_CHN2(spec->boxbits, 1);
+       ICE1712_STDSP24_1_CHN3(spec->boxbits, 1);
        
-       ICE1712_STDSP24_SET_ADDR(ice->spec.hoontech.boxbits, 2);
-       ICE1712_STDSP24_CLOCK(ice->spec.hoontech.boxbits, 2, 1);
-       ICE1712_STDSP24_2_CHN4(ice->spec.hoontech.boxbits, 1);
-       ICE1712_STDSP24_2_MIDIIN(ice->spec.hoontech.boxbits, 1);
-       ICE1712_STDSP24_2_MIDI1(ice->spec.hoontech.boxbits, 0);
-
-       ICE1712_STDSP24_SET_ADDR(ice->spec.hoontech.boxbits, 3);
-       ICE1712_STDSP24_CLOCK(ice->spec.hoontech.boxbits, 3, 1);
-       ICE1712_STDSP24_3_MIDI2(ice->spec.hoontech.boxbits, 0);
-       ICE1712_STDSP24_3_MUTE(ice->spec.hoontech.boxbits, 1);
-       ICE1712_STDSP24_3_INSEL(ice->spec.hoontech.boxbits, 0);
+       ICE1712_STDSP24_SET_ADDR(spec->boxbits, 2);
+       ICE1712_STDSP24_CLOCK(spec->boxbits, 2, 1);
+       ICE1712_STDSP24_2_CHN4(spec->boxbits, 1);
+       ICE1712_STDSP24_2_MIDIIN(spec->boxbits, 1);
+       ICE1712_STDSP24_2_MIDI1(spec->boxbits, 0);
+
+       ICE1712_STDSP24_SET_ADDR(spec->boxbits, 3);
+       ICE1712_STDSP24_CLOCK(spec->boxbits, 3, 1);
+       ICE1712_STDSP24_3_MIDI2(spec->boxbits, 0);
+       ICE1712_STDSP24_3_MUTE(spec->boxbits, 1);
+       ICE1712_STDSP24_3_INSEL(spec->boxbits, 0);
 
        /* let's go - activate only functions in first box */
-       ice->spec.hoontech.config = 0;
+       spec->config = 0;
                            /* ICE1712_STDSP24_MUTE |
                               ICE1712_STDSP24_INSEL |
                               ICE1712_STDSP24_DAREAR; */
-       ice->spec.hoontech.boxconfig[0] = ICE1712_STDSP24_BOX_CHN1 |
+       spec->boxconfig[0] = ICE1712_STDSP24_BOX_CHN1 |
                                     ICE1712_STDSP24_BOX_CHN2 |
                                     ICE1712_STDSP24_BOX_CHN3 |
                                     ICE1712_STDSP24_BOX_CHN4 |
                                     ICE1712_STDSP24_BOX_MIDI1 |
                                     ICE1712_STDSP24_BOX_MIDI2;
-       ice->spec.hoontech.boxconfig[1] = 
-       ice->spec.hoontech.boxconfig[2] = 
-       ice->spec.hoontech.boxconfig[3] = 0;
-       snd_ice1712_stdsp24_darear(ice, (ice->spec.hoontech.config & ICE1712_STDSP24_DAREAR) ? 1 : 0);
-       snd_ice1712_stdsp24_mute(ice, (ice->spec.hoontech.config & ICE1712_STDSP24_MUTE) ? 1 : 0);
-       snd_ice1712_stdsp24_insel(ice, (ice->spec.hoontech.config & ICE1712_STDSP24_INSEL) ? 1 : 0);
-       for (box = 0; box < 4; box++) {
+       spec->boxconfig[1] = 
+       spec->boxconfig[2] = 
+       spec->boxconfig[3] = 0;
+       snd_ice1712_stdsp24_darear(ice,
+               (spec->config & ICE1712_STDSP24_DAREAR) ? 1 : 0);
+       snd_ice1712_stdsp24_mute(ice,
+               (spec->config & ICE1712_STDSP24_MUTE) ? 1 : 0);
+       snd_ice1712_stdsp24_insel(ice,
+               (spec->config & ICE1712_STDSP24_INSEL) ? 1 : 0);
+       for (box = 0; box < 1; box++) {
+               if (spec->boxconfig[box] & ICE1712_STDSP24_BOX_MIDI2)
+                        snd_ice1712_stdsp24_midi2(ice, 1);
                for (chn = 0; chn < 4; chn++)
-                       snd_ice1712_stdsp24_box_channel(ice, box, chn, (ice->spec.hoontech.boxconfig[box] & (1 << chn)) ? 1 : 0);
+                       snd_ice1712_stdsp24_box_channel(ice, box, chn,
+                               (spec->boxconfig[box] & (1 << chn)) ? 1 : 0);
                snd_ice1712_stdsp24_box_midi(ice, box,
-                               (ice->spec.hoontech.boxconfig[box] & ICE1712_STDSP24_BOX_MIDI1) ? 1 : 0);
-               if (ice->spec.hoontech.boxconfig[box] & ICE1712_STDSP24_BOX_MIDI2)
-                       snd_ice1712_stdsp24_midi2(ice, 1);
+                               (spec->boxconfig[box] & ICE1712_STDSP24_BOX_MIDI1) ? 1 : 0);
        }
 
        return 0;
index 052fc3cb32728b8cedb712370ca8e61eec0aad41..df292af6738197976e05899c7c4e5f0d4e439b86 100644 (file)
@@ -47,7 +47,6 @@
  */
 
 
-#include <sound/driver.h>
 #include <asm/io.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
@@ -2491,6 +2490,7 @@ static int snd_ice1712_free(struct snd_ice1712 *ice)
                pci_release_regions(ice->pci);
        snd_ice1712_akm4xxx_free(ice);
        pci_disable_device(ice->pci);
+       kfree(ice->spec);
        kfree(ice);
        return 0;
 }
index 58640afa54041e49441e8dccf4dd18323f282d02..303cffe08bd8a7abba006a95f3deb3124d92cf3b 100644 (file)
@@ -366,42 +366,7 @@ struct snd_ice1712 {
        struct mutex gpio_mutex;
 
        /* other board-specific data */
-       union {
-               /* additional i2c devices for EWS boards */
-               struct snd_i2c_device *i2cdevs[3];
-               /* AC97 register cache for Aureon */
-               struct aureon_spec {
-                       unsigned short stac9744[64];
-                       unsigned int cs8415_mux;
-                       unsigned short master[2];
-                       unsigned short vol[8];
-                       unsigned char pca9554_out;
-               } aureon;
-               /* AC97 register cache for Phase28 */
-               struct phase28_spec {
-                       unsigned short master[2];
-                       unsigned short vol[8];
-               } phase28;
-               /* a non-standard I2C device for revo51 */
-               struct revo51_spec {
-                       struct snd_i2c_device *dev;
-                       struct snd_pt2258 *pt2258;
-               } revo51;
-               /* Hoontech-specific setting */
-               struct hoontech_spec {
-                       unsigned char boxbits[4];
-                       unsigned int config;
-                       unsigned short boxconfig[4];
-               } hoontech;
-               struct {
-                       struct ak4114 *ak4114;
-                       unsigned int analog: 1;
-               } juli;
-               struct {
-                       struct ak4114 *ak4114;
-               } prodigy192;
-       } spec;
-
+       void *spec;
 };
 
 
index 0b0bbb0d96b91f8626724b163e68a88838422832..f533850ec6e776377bffd69dac936ae61f32d4bb 100644 (file)
@@ -22,7 +22,6 @@
  *
  */      
 
-#include <sound/driver.h>
 #include <asm/io.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include "vt1720_mobo.h"
 #include "pontis.h"
 #include "prodigy192.h"
+#include "prodigy_hifi.h"
 #include "juli.h"
 #include "phase.h"
 #include "wtm.h"
+#include "se.h"
 
 MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
 MODULE_DESCRIPTION("VIA ICEnsemble ICE1724/1720 (Envy24HT/PT)");
@@ -62,9 +63,11 @@ MODULE_SUPPORTED_DEVICE("{"
               VT1720_MOBO_DEVICE_DESC
               PONTIS_DEVICE_DESC
               PRODIGY192_DEVICE_DESC
+              PRODIGY_HIFI_DEVICE_DESC
               JULI_DEVICE_DESC
               PHASE_DEVICE_DESC
               WTM_DEVICE_DESC
+              SE_DEVICE_DESC
                "{VIA,VT1720},"
                "{VIA,VT1724},"
                "{ICEnsemble,Generic ICE1724},"
@@ -1929,10 +1932,12 @@ static struct snd_ice1712_card_info *card_tables[] __devinitdata = {
        snd_vt1724_aureon_cards,
        snd_vt1720_mobo_cards,
        snd_vt1720_pontis_cards,
+       snd_vt1724_prodigy_hifi_cards,
        snd_vt1724_prodigy192_cards,
        snd_vt1724_juli_cards,
        snd_vt1724_phase_cards,
        snd_vt1724_wtm_cards,
+       snd_vt1724_se_cards,
        NULL,
 };
 
@@ -1955,6 +1960,7 @@ unsigned char snd_vt1724_read_i2c(struct snd_ice1712 *ice,
        unsigned char val;
 
        mutex_lock(&ice->i2c_mutex);
+       wait_i2c_busy(ice);
        outb(addr, ICEREG1724(ice, I2C_BYTE_ADDR));
        outb(dev & ~VT1724_I2C_WRITE, ICEREG1724(ice, I2C_DEV_ADDR));
        wait_i2c_busy(ice);
@@ -2170,6 +2176,7 @@ static int snd_vt1724_free(struct snd_ice1712 *ice)
        pci_release_regions(ice->pci);
        snd_ice1712_akm4xxx_free(ice);
        pci_disable_device(ice->pci);
+       kfree(ice->spec);
        kfree(ice);
        return 0;
 }
index 1fbe3ef8e60a5f370ecafa2ce46af18809e467e9..e8038c0ceb721a0f9a3d881814f3bc40dcee34e2 100644 (file)
@@ -21,7 +21,6 @@
  *
  */      
 
-#include <sound/driver.h>
 #include <asm/io.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include "envy24ht.h"
 #include "juli.h"
 
+struct juli_spec {
+       struct ak4114 *ak4114;
+       unsigned int analog: 1;
+};
+
 /*
  * chip addresses on I2C bus
  */
@@ -138,12 +142,13 @@ static struct snd_akm4xxx akm_juli_dac __devinitdata = {
 
 static int __devinit juli_add_controls(struct snd_ice1712 *ice)
 {
+       struct juli_spec *spec = ice->spec;
        int err;
        err = snd_ice1712_akm4xxx_build_controls(ice);
        if (err < 0)
                return err;
        /* only capture SPDIF over AK4114 */
-       err = snd_ak4114_build(ice->spec.juli.ak4114, NULL,
+       err = snd_ak4114_build(spec->ak4114, NULL,
                               ice->pcm_pro->streams[SNDRV_PCM_STREAM_CAPTURE].substream);
        if (err < 0)
                return err;
@@ -167,13 +172,19 @@ static int __devinit juli_init(struct snd_ice1712 *ice)
                0x41, 0x02, 0x2c, 0x00, 0x00
        };
        int err;
+       struct juli_spec *spec;
        struct snd_akm4xxx *ak;
 
+       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+       if (!spec)
+               return -ENOMEM;
+       ice->spec = spec;
+
        err = snd_ak4114_create(ice->card,
                                juli_ak4114_read,
                                juli_ak4114_write,
                                ak4114_init_vals, ak4114_init_txcsb,
-                               ice, &ice->spec.juli.ak4114);
+                               ice, &spec->ak4114);
        if (err < 0)
                return err;
 
@@ -181,12 +192,12 @@ static int __devinit juli_init(struct snd_ice1712 *ice)
         /* it seems that the analog doughter board detection does not work
            reliably, so force the analog flag; it should be very rare
            to use Juli@ without the analog doughter board */
-       ice->spec.juli.analog = (ice->gpio.get_data(ice) & GPIO_ANALOG_PRESENT) ? 0 : 1;
+       spec->analog = (ice->gpio.get_data(ice) & GPIO_ANALOG_PRESENT) ? 0 : 1;
 #else
-        ice->spec.juli.analog = 1;
+        spec->analog = 1;
 #endif
 
-       if (ice->spec.juli.analog) {
+       if (spec->analog) {
                printk(KERN_INFO "juli@: analog I/O detected\n");
                ice->num_total_dacs = 2;
                ice->num_total_adcs = 2;
index 3ac25058bb588fa583afc3bcc0a5b21ec577b6d7..9ab4a9f383cbb19b69834a7b27be19e759ea80db 100644 (file)
@@ -33,7 +33,6 @@
  *             CDTI may be completely blocked by 74HCT125's gate #1 controlled by GPIO 3
  */
 
-#include <sound/driver.h>
 #include <asm/io.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include "phase.h"
 #include <sound/tlv.h>
 
+/* AC97 register cache for Phase28 */
+struct phase28_spec {
+       unsigned short master[2];
+       unsigned short vol[8];
+} phase28;
+
 /* WM8770 registers */
 #define WM_DAC_ATTEN           0x00    /* DAC1-8 analog attenuation */
 #define WM_DAC_MASTER_ATTEN    0x08    /* DAC master analog attenuation */
@@ -313,27 +318,32 @@ static int wm_master_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem
 static int wm_master_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+       struct phase28_spec *spec = ice->spec;
        int i;
        for (i=0; i<2; i++)
-               ucontrol->value.integer.value[i] = ice->spec.phase28.master[i] & ~WM_VOL_MUTE;
+               ucontrol->value.integer.value[i] = spec->master[i] & ~WM_VOL_MUTE;
        return 0;
 }
 
 static int wm_master_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+       struct phase28_spec *spec = ice->spec;
        int ch, change = 0;
 
        snd_ice1712_save_gpio_status(ice);
        for (ch = 0; ch < 2; ch++) {
-               if (ucontrol->value.integer.value[ch] != ice->spec.phase28.master[ch]) {
+               unsigned int vol = ucontrol->value.integer.value[ch];
+               if (vol > WM_VOL_MAX)
+                       continue;
+               vol |= spec->master[ch] & WM_VOL_MUTE;
+               if (vol != spec->master[ch]) {
                        int dac;
-                       ice->spec.phase28.master[ch] &= WM_VOL_MUTE;
-                       ice->spec.phase28.master[ch] |= ucontrol->value.integer.value[ch];
+                       spec->master[ch] = vol;
                        for (dac = 0; dac < ice->num_total_dacs; dac += 2)
                                wm_set_vol(ice, WM_DAC_ATTEN + dac + ch,
-                                          ice->spec.phase28.vol[dac + ch],
-                                          ice->spec.phase28.master[ch]);
+                                          spec->vol[dac + ch],
+                                          spec->master[ch]);
                        change = 1;
                }
        }
@@ -382,12 +392,18 @@ static int __devinit phase28_init(struct snd_ice1712 *ice)
 
        unsigned int tmp;
        struct snd_akm4xxx *ak;
+       struct phase28_spec *spec;
        const unsigned short *p;
        int i;
 
        ice->num_total_dacs = 8;
        ice->num_total_adcs = 2;
 
+       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+       if (!spec)
+               return -ENOMEM;
+       ice->spec = spec;
+
        // Initialize analog chips
        ak = ice->akm = kzalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL);
        if (!ak)
@@ -417,11 +433,11 @@ static int __devinit phase28_init(struct snd_ice1712 *ice)
 
        snd_ice1712_restore_gpio_status(ice);
 
-       ice->spec.phase28.master[0] = WM_VOL_MUTE;
-       ice->spec.phase28.master[1] = WM_VOL_MUTE;
+       spec->master[0] = WM_VOL_MUTE;
+       spec->master[1] = WM_VOL_MUTE;
        for (i = 0; i < ice->num_total_dacs; i++) {
-               ice->spec.phase28.vol[i] = WM_VOL_MUTE;
-               wm_set_vol(ice, i, ice->spec.phase28.vol[i], ice->spec.phase28.master[i % 2]);
+               spec->vol[i] = WM_VOL_MUTE;
+               wm_set_vol(ice, i, spec->vol[i], spec->master[i % 2]);
        }
 
        return 0;
@@ -443,18 +459,21 @@ static int wm_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *
 static int wm_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+       struct phase28_spec *spec = ice->spec;
        int i, ofs, voices;
 
        voices = kcontrol->private_value >> 8;
        ofs = kcontrol->private_value & 0xff;
        for (i = 0; i < voices; i++)
-               ucontrol->value.integer.value[i] = ice->spec.phase28.vol[ofs+i] & ~WM_VOL_MUTE;
+               ucontrol->value.integer.value[i] =
+                       spec->vol[ofs+i] & ~WM_VOL_MUTE;
        return 0;
 }
 
 static int wm_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+       struct phase28_spec *spec = ice->spec;
        int i, idx, ofs, voices;
        int change = 0;
 
@@ -462,12 +481,16 @@ static int wm_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *
        ofs = kcontrol->private_value & 0xff;
        snd_ice1712_save_gpio_status(ice);
        for (i = 0; i < voices; i++) {
-               idx  = WM_DAC_ATTEN + ofs + i;
-               if (ucontrol->value.integer.value[i] != ice->spec.phase28.vol[ofs+i]) {
-                       ice->spec.phase28.vol[ofs+i] &= WM_VOL_MUTE;
-                       ice->spec.phase28.vol[ofs+i] |= ucontrol->value.integer.value[i];
-                       wm_set_vol(ice, idx, ice->spec.phase28.vol[ofs+i],
-                                  ice->spec.phase28.master[i]);
+               unsigned int vol;
+               vol = ucontrol->value.integer.value[i];
+               if (vol > 0x7f)
+                       continue;
+               vol |= spec->vol[ofs+i] & WM_VOL_MUTE;
+               if (vol != spec->vol[ofs+i]) {
+                       spec->vol[ofs+i] = vol;
+                       idx  = WM_DAC_ATTEN + ofs + i;
+                       wm_set_vol(ice, idx, spec->vol[ofs+i],
+                                  spec->master[i]);
                        change = 1;
                }
        }
@@ -489,19 +512,22 @@ static int wm_mute_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info
 static int wm_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+       struct phase28_spec *spec = ice->spec;
        int voices, ofs, i;
 
        voices = kcontrol->private_value >> 8;
        ofs = kcontrol->private_value & 0xFF;
 
        for (i = 0; i < voices; i++)
-               ucontrol->value.integer.value[i] = (ice->spec.phase28.vol[ofs+i] & WM_VOL_MUTE) ? 0 : 1;
+               ucontrol->value.integer.value[i] =
+                       (spec->vol[ofs+i] & WM_VOL_MUTE) ? 0 : 1;
        return 0;
 }
 
 static int wm_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+       struct phase28_spec *spec = ice->spec;
        int change = 0, voices, ofs, i;
 
        voices = kcontrol->private_value >> 8;
@@ -509,13 +535,13 @@ static int wm_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value
 
        snd_ice1712_save_gpio_status(ice);
        for (i = 0; i < voices; i++) {
-               int val = (ice->spec.phase28.vol[ofs + i] & WM_VOL_MUTE) ? 0 : 1;
+               int val = (spec->vol[ofs + i] & WM_VOL_MUTE) ? 0 : 1;
                if (ucontrol->value.integer.value[i] != val) {
-                       ice->spec.phase28.vol[ofs + i] &= ~WM_VOL_MUTE;
-                       ice->spec.phase28.vol[ofs + i] |=
+                       spec->vol[ofs + i] &= ~WM_VOL_MUTE;
+                       spec->vol[ofs + i] |=
                                ucontrol->value.integer.value[i] ? 0 : WM_VOL_MUTE;
-                       wm_set_vol(ice, ofs + i, ice->spec.phase28.vol[ofs + i],
-                                  ice->spec.phase28.master[i]);
+                       wm_set_vol(ice, ofs + i, spec->vol[ofs + i],
+                                  spec->master[i]);
                        change = 1;
                }
        }
@@ -532,29 +558,33 @@ static int wm_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value
 static int wm_master_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+       struct phase28_spec *spec = ice->spec;
 
-       ucontrol->value.integer.value[0] = (ice->spec.phase28.master[0] & WM_VOL_MUTE) ? 0 : 1;
-       ucontrol->value.integer.value[1] = (ice->spec.phase28.master[1] & WM_VOL_MUTE) ? 0 : 1;
+       ucontrol->value.integer.value[0] =
+               (spec->master[0] & WM_VOL_MUTE) ? 0 : 1;
+       ucontrol->value.integer.value[1] =
+               (spec->master[1] & WM_VOL_MUTE) ? 0 : 1;
        return 0;
 }
 
 static int wm_master_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+       struct phase28_spec *spec = ice->spec;
        int change = 0, i;
 
        snd_ice1712_save_gpio_status(ice);
        for (i = 0; i < 2; i++) {
-               int val = (ice->spec.phase28.master[i] & WM_VOL_MUTE) ? 0 : 1;
+               int val = (spec->master[i] & WM_VOL_MUTE) ? 0 : 1;
                if (ucontrol->value.integer.value[i] != val) {
                        int dac;
-                       ice->spec.phase28.master[i] &= ~WM_VOL_MUTE;
-                       ice->spec.phase28.master[i] |=
+                       spec->master[i] &= ~WM_VOL_MUTE;
+                       spec->master[i] |=
                                ucontrol->value.integer.value[i] ? 0 : WM_VOL_MUTE;
                        for (dac = 0; dac < ice->num_total_dacs; dac += 2)
                                wm_set_vol(ice, WM_DAC_ATTEN + dac + i,
-                                          ice->spec.phase28.vol[dac + i],
-                                          ice->spec.phase28.master[i]);
+                                          spec->vol[dac + i],
+                                          spec->master[i]);
                        change = 1;
                }
        }
@@ -595,8 +625,10 @@ static int wm_pcm_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_val
        unsigned short ovol, nvol;
        int change = 0;
 
-       snd_ice1712_save_gpio_status(ice);
        nvol = ucontrol->value.integer.value[0];
+       if (nvol > PCM_RES)
+               return -EINVAL;
+       snd_ice1712_save_gpio_status(ice);
        nvol = (nvol ? (nvol + PCM_MIN) : 0) & 0xff;
        ovol = wm_get(ice, WM_DAC_DIG_MASTER_ATTEN) & 0xff;
        if (ovol != nvol) {
index faefd52c1b8032d82307fd8a3ecd457db51a7cbc..4945c81e8a96094d2c3bb73f9555a9d5ee6cd8b5 100644 (file)
@@ -21,7 +21,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <asm/io.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
index 4180f9739ecb9b367a385e6fbae738d022ada30f..48cf40a8f32a1b0c0f9c763bdd31feb2e83f0bc9 100644 (file)
@@ -54,7 +54,6 @@
  *
  */      
 
-#include <sound/driver.h>
 #include <asm/io.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include "stac946x.h"
 #include <sound/tlv.h>
 
+struct prodigy192_spec {
+       struct ak4114 *ak4114;
+       /* rate change needs atomic mute/unmute of all dacs*/
+       struct mutex mute_mutex;
+};
+
 static inline void stac9460_put(struct snd_ice1712 *ice, int reg, unsigned char val)
 {
        snd_vt1724_write_i2c(ice, PRODIGY192_STAC9460_ADDR, reg, val);
@@ -81,6 +86,24 @@ static inline unsigned char stac9460_get(struct snd_ice1712 *ice, int reg)
 /*
  * DAC mute control
  */
+
+/*
+ * idx = STAC9460 volume register number, mute: 0 = mute, 1 = unmute
+ */
+static int stac9460_dac_mute(struct snd_ice1712 *ice, int idx,
+               unsigned char mute)
+{
+       unsigned char new, old;
+       int change;
+       old = stac9460_get(ice, idx);
+       new = (~mute << 7 & 0x80) | (old & ~0x80);
+       change = (new != old);
+       if (change)
+               /*printk ("Volume register 0x%02x: 0x%02x\n", idx, new);*/
+               stac9460_put(ice, idx, new);
+       return change;
+}
+
 #define stac9460_dac_mute_info         snd_ctl_boolean_mono_info
 
 static int stac9460_dac_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
@@ -101,20 +124,19 @@ static int stac9460_dac_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_e
 static int stac9460_dac_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
-       unsigned char new, old;
-       int idx;
-       int change;
+       struct prodigy192_spec *spec = ice->spec;
+       int idx, change;
 
        if (kcontrol->private_value)
                idx = STAC946X_MASTER_VOLUME;
        else
                idx  = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + STAC946X_LF_VOLUME;
-       old = stac9460_get(ice, idx);
-       new = (~ucontrol->value.integer.value[0]<< 7 & 0x80) | (old & ~0x80);
-       change = (new != old);
-       if (change)
-               stac9460_put(ice, idx, new);
-
+       /* due to possible conflicts with stac9460_set_rate_val, mutexing */
+       mutex_lock(&spec->mute_mutex);
+       /*printk("Mute put: reg 0x%02x, ctrl value: 0x%02x\n", idx,
+               ucontrol->value.integer.value[0]);*/
+       change = stac9460_dac_mute(ice, idx, ucontrol->value.integer.value[0]);
+       mutex_unlock(&spec->mute_mutex);
        return change;
 }
 
@@ -162,6 +184,8 @@ static int stac9460_dac_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_el
        ovol = 0x7f - (tmp & 0x7f);
        change = (ovol != nvol);
        if (change) {
+               ovol =  (0x7f - nvol) | (tmp & 0x80);
+               /*printk("DAC Volume: reg 0x%02x: 0x%02x\n", idx, ovol);*/
                stac9460_put(ice, idx, (0x7f - nvol) | (tmp & 0x80));
        }
        return change;
@@ -241,7 +265,7 @@ static int stac9460_adc_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_el
 
        for (i = 0; i < 2; ++i) {
                reg = STAC946X_MIC_L_VOLUME + i;
-               nvol = ucontrol->value.integer.value[i];
+               nvol = ucontrol->value.integer.value[i] & 0x0f;
                ovol = 0x0f - stac9460_get(ice, reg);
                change = ((ovol & 0x0f)  != nvol);
                if (change)
@@ -251,121 +275,6 @@ static int stac9460_adc_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_el
        return change;
 }
 
-#if 0
-/*
- * Headphone Amplifier
- */
-static int aureon_set_headphone_amp(struct snd_ice1712 *ice, int enable)
-{
-       unsigned int tmp, tmp2;
-
-       tmp2 = tmp = snd_ice1712_gpio_read(ice);
-       if (enable)
-               tmp |= AUREON_HP_SEL;
-       else
-               tmp &= ~ AUREON_HP_SEL;
-       if (tmp != tmp2) {
-               snd_ice1712_gpio_write(ice, tmp);
-               return 1;
-       }
-       return 0;
-}
-
-static int aureon_get_headphone_amp(struct snd_ice1712 *ice)
-{
-       unsigned int tmp = snd_ice1712_gpio_read(ice);
-
-       return ( tmp & AUREON_HP_SEL )!= 0;
-}
-
-#define aureon_bool_info       snd_ctl_boolean_mono_info
-
-static int aureon_hpamp_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
-{
-       struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
-
-       ucontrol->value.integer.value[0] = aureon_get_headphone_amp(ice);
-       return 0;
-}
-
-
-static int aureon_hpamp_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
-{
-       struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
-
-       return aureon_set_headphone_amp(ice,ucontrol->value.integer.value[0]);
-}
-
-/*
- * Deemphasis
- */
-static int aureon_deemp_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
-{
-       struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
-       ucontrol->value.integer.value[0] = (wm_get(ice, WM_DAC_CTRL2) & 0xf) == 0xf;
-       return 0;
-}
-
-static int aureon_deemp_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
-{
-       struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
-       int temp, temp2;
-       temp2 = temp = wm_get(ice, WM_DAC_CTRL2);
-       if (ucontrol->value.integer.value[0])
-               temp |= 0xf;
-       else
-               temp &= ~0xf;
-       if (temp != temp2) {
-               wm_put(ice, WM_DAC_CTRL2, temp);
-               return 1;
-       }
-       return 0;
-}
-
-/*
- * ADC Oversampling
- */
-static int aureon_oversampling_info(struct snd_kcontrol *k, struct snd_ctl_elem_info *uinfo)
-{
-       static char *texts[2] = { "128x", "64x" };
-
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-       uinfo->count = 1;
-       uinfo->value.enumerated.items = 2;
-
-       if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
-               uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
-       strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
-
-        return 0;
-}
-
-static int aureon_oversampling_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
-{
-       struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
-       ucontrol->value.enumerated.item[0] = (wm_get(ice, WM_MASTER) & 0x8) == 0x8;
-       return 0;
-}
-
-static int aureon_oversampling_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
-{
-       int temp, temp2;
-       struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
-
-       temp2 = temp = wm_get(ice, WM_MASTER);
-
-       if (ucontrol->value.enumerated.item[0])
-               temp |= 0x8;
-       else
-               temp &= ~0x8;
-
-       if (temp != temp2) {
-               wm_put(ice, WM_MASTER, temp);
-               return 1;
-       }
-       return 0;
-}
-#endif
 static int stac9460_mic_sw_info(struct snd_kcontrol *kcontrol,
                                struct snd_ctl_elem_info *uinfo)
 {
@@ -407,6 +316,57 @@ static int stac9460_mic_sw_put(struct snd_kcontrol *kcontrol,
                stac9460_put(ice, STAC946X_GENERAL_PURPOSE, new);
        return change;
 }
+/*
+ * Handler for setting correct codec rate - called when rate change is detected
+ */
+static void stac9460_set_rate_val(struct snd_akm4xxx *ak, unsigned int rate)
+{
+       unsigned char old, new;
+       int idx;
+       unsigned char changed[7];
+       struct snd_ice1712 *ice = ak->private_data[0];
+       struct prodigy192_spec *spec = ice->spec;
+
+       if (rate == 0)  /* no hint - S/PDIF input is master, simply return */
+               return;
+       else if (rate <= 48000)
+               new = 0x08;     /* 256x, base rate mode */
+       else if (rate <= 96000)
+               new = 0x11;     /* 256x, mid rate mode */
+       else
+               new = 0x12;     /* 128x, high rate mode */
+       old = stac9460_get(ice, STAC946X_MASTER_CLOCKING);
+       if (old == new)
+               return;
+       /* change detected, setting master clock, muting first */
+       /* due to possible conflicts with mute controls - mutexing */
+       mutex_lock(&spec->mute_mutex);
+       /* we have to remember current mute status for each DAC */
+       for (idx = 0; idx < 7 ; ++idx)
+               changed[idx] = stac9460_dac_mute(ice,
+                               STAC946X_MASTER_VOLUME + idx, 0);
+       /*printk("Rate change: %d, new MC: 0x%02x\n", rate, new);*/
+       stac9460_put(ice, STAC946X_MASTER_CLOCKING, new);
+       udelay(10);
+       /* unmuting - only originally unmuted dacs -
+        * i.e. those changed when muting */
+       for (idx = 0; idx < 7 ; ++idx) {
+               if (changed[idx])
+                       stac9460_dac_mute(ice, STAC946X_MASTER_VOLUME + idx, 1);
+       }
+       mutex_unlock(&spec->mute_mutex);
+}
+
+/* using akm infrastructure for setting rate of the codec */
+static struct snd_akm4xxx akmlike_stac9460 __devinitdata = {
+       .type = NON_AKM,        /* special value */
+       .num_adcs = 6,          /* not used in any way, just for completeness */
+       .num_dacs = 2,
+       .ops = {
+               .set_rate_val = stac9460_set_rate_val
+       }
+};
+
 
 static const DECLARE_TLV_DB_SCALE(db_scale_dac, -19125, 75, 0);
 static const DECLARE_TLV_DB_SCALE(db_scale_adc, 0, 150, 0);
@@ -483,39 +443,8 @@ static struct snd_kcontrol_new stac_controls[] __devinitdata = {
                .put = stac9460_mic_sw_put,
 
        },
-#if 0
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Capture Route",
-               .info = wm_adc_mux_info,
-               .get = wm_adc_mux_get,
-               .put = wm_adc_mux_put,
-       },
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Headphone Amplifier Switch",
-               .info = aureon_bool_info,
-               .get = aureon_hpamp_get,
-               .put = aureon_hpamp_put
-       },
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "DAC Deemphasis Switch",
-               .info = aureon_bool_info,
-               .get = aureon_deemp_get,
-               .put = aureon_deemp_put
-       },
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "ADC Oversampling",
-               .info = aureon_oversampling_info,
-               .get = aureon_oversampling_get,
-               .put = aureon_oversampling_put
-       },
-#endif
 };
 
-
 /* AK4114 - ICE1724 connections on Prodigy192 + MI/ODI/O */
 /* CDTO (pin 32) -- GPIO11 pin 86
  * CDTI (pin 33) -- GPIO10 pin 77
@@ -712,16 +641,39 @@ static int prodigy192_ak4114_init(struct snd_ice1712 *ice)
        static const unsigned char ak4114_init_txcsb[] = {
                0x41, 0x02, 0x2c, 0x00, 0x00
        };
+       struct prodigy192_spec *spec = ice->spec;
 
        return snd_ak4114_create(ice->card,
                                 prodigy192_ak4114_read,
                                 prodigy192_ak4114_write,
                                 ak4114_init_vals, ak4114_init_txcsb,
-                                ice, &ice->spec.prodigy192.ak4114);
+                                ice, &spec->ak4114);
+}
+
+static void stac9460_proc_regs_read(struct snd_info_entry *entry,
+               struct snd_info_buffer *buffer)
+{
+       struct snd_ice1712 *ice = (struct snd_ice1712 *)entry->private_data;
+       int reg, val;
+       /* registers 0x0 - 0x14 */
+       for (reg = 0; reg <= 0x15; reg++) {
+               val = stac9460_get(ice, reg);
+               snd_iprintf(buffer, "0x%02x = 0x%02x\n", reg, val);
+       }
+}
+
+
+static void stac9460_proc_init(struct snd_ice1712 *ice)
+{
+       struct snd_info_entry *entry;
+       if (!snd_card_proc_new(ice->card, "stac9460_codec", &entry))
+               snd_info_set_text_ops(entry, ice, stac9460_proc_regs_read);
 }
 
+
 static int __devinit prodigy192_add_controls(struct snd_ice1712 *ice)
 {
+       struct prodigy192_spec *spec = ice->spec;
        unsigned int i;
        int err;
 
@@ -731,7 +683,7 @@ static int __devinit prodigy192_add_controls(struct snd_ice1712 *ice)
                if (err < 0)
                        return err;
        }
-       if (ice->spec.prodigy192.ak4114) {
+       if (spec->ak4114) {
                /* ak4114 is connected */
                for (i = 0; i < ARRAY_SIZE(ak4114_controls); i++) {
                        err = snd_ctl_add(ice->card,
@@ -740,12 +692,13 @@ static int __devinit prodigy192_add_controls(struct snd_ice1712 *ice)
                        if (err < 0)
                                return err;
                }
-               err = snd_ak4114_build(ice->spec.prodigy192.ak4114,
+               err = snd_ak4114_build(spec->ak4114,
                                NULL, /* ak4114 in MIO/DI/O handles no IEC958 output */
                                ice->pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream);
                if (err < 0)
                        return err;
        }
+       stac9460_proc_init(ice);
        return 0;
 }
 
@@ -778,6 +731,7 @@ static int __devinit prodigy192_init(struct snd_ice1712 *ice)
 {
        static const unsigned short stac_inits_prodigy[] = {
                STAC946X_RESET, 0,
+               STAC946X_MASTER_CLOCKING, 0x11,
 /*             STAC946X_MASTER_VOLUME, 0,
                STAC946X_LF_VOLUME, 0,
                STAC946X_RF_VOLUME, 0,
@@ -789,22 +743,39 @@ static int __devinit prodigy192_init(struct snd_ice1712 *ice)
        };
        const unsigned short *p;
        int err = 0;
+       struct snd_akm4xxx *ak;
+       struct prodigy192_spec *spec;
 
        /* prodigy 192 */
        ice->num_total_dacs = 6;
        ice->num_total_adcs = 2;
        ice->vt1720 = 0;  /* ice1724, e.g. 23 GPIOs */
        
+       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+       if (!spec)
+               return -ENOMEM;
+       ice->spec = spec;
+       mutex_init(&spec->mute_mutex);
+
        /* initialize codec */
        p = stac_inits_prodigy;
        for (; *p != (unsigned short)-1; p += 2)
                stac9460_put(ice, p[0], p[1]);
+       /* reusing the akm codecs infrastructure,
+        * for setting rate on stac9460 */
+       ak = ice->akm = kmalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL);
+       if (!ak)
+               return -ENOMEM;
+       ice->akm_codecs = 1;
+       err = snd_ice1712_akm4xxx_init(ak, &akmlike_stac9460, NULL, ice);
+       if (err < 0)
+               return err;
 
        /* MI/ODI/O add on card with AK4114 */
        if (prodigy192_miodio_exists(ice)) {
                err = prodigy192_ak4114_init(ice);
                /* from this moment if err = 0 then
-                * ice->spec.prodigy192.ak4114 should not be null
+                * spec->ak4114 should not be null
                 */
                snd_printdd("AK4114 initialized with status %d\n", err);
        } else
@@ -854,6 +825,10 @@ struct snd_ice1712_card_info snd_vt1724_prodigy192_cards[] __devinitdata = {
                .build_controls = prodigy192_add_controls,
                .eeprom_size = sizeof(prodigy71_eeprom),
                .eeprom_data = prodigy71_eeprom,
+               /* the current MPU401 code loops infinitely
+                * when opening midi device
+                */
+               .no_mpu401 = 1,
        },
        { } /* terminator */
 };
diff --git a/sound/pci/ice1712/prodigy_hifi.c b/sound/pci/ice1712/prodigy_hifi.c
new file mode 100644 (file)
index 0000000..043a938
--- /dev/null
@@ -0,0 +1,1210 @@
+/*
+ *   ALSA driver for ICEnsemble VT1724 (Envy24HT)
+ *
+ *   Lowlevel functions for Audiotrak Prodigy 7.1 Hifi
+ *   based on pontis.c
+ *
+ *      Copyright (c) 2007 Julian Scheel <julian@jusst.de>
+ *      Copyright (c) 2007 allank
+ *      Copyright (c) 2004 Takashi Iwai <tiwai@suse.de>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */
+
+
+#include <asm/io.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+
+#include <sound/core.h>
+#include <sound/info.h>
+#include <sound/tlv.h>
+
+#include "ice1712.h"
+#include "envy24ht.h"
+#include "prodigy_hifi.h"
+
+struct prodigy_hifi_spec {
+       unsigned short master[2];
+       unsigned short vol[8];
+};
+
+/* I2C addresses */
+#define WM_DEV         0x34
+
+/* WM8776 registers */
+#define WM_HP_ATTEN_L          0x00    /* headphone left attenuation */
+#define WM_HP_ATTEN_R          0x01    /* headphone left attenuation */
+#define WM_HP_MASTER           0x02    /* headphone master (both channels),
+                                               override LLR */
+#define WM_DAC_ATTEN_L         0x03    /* digital left attenuation */
+#define WM_DAC_ATTEN_R         0x04
+#define WM_DAC_MASTER          0x05
+#define WM_PHASE_SWAP          0x06    /* DAC phase swap */
+#define WM_DAC_CTRL1           0x07
+#define WM_DAC_MUTE            0x08
+#define WM_DAC_CTRL2           0x09
+#define WM_DAC_INT             0x0a
+#define WM_ADC_INT             0x0b
+#define WM_MASTER_CTRL         0x0c
+#define WM_POWERDOWN           0x0d
+#define WM_ADC_ATTEN_L         0x0e
+#define WM_ADC_ATTEN_R         0x0f
+#define WM_ALC_CTRL1           0x10
+#define WM_ALC_CTRL2           0x11
+#define WM_ALC_CTRL3           0x12
+#define WM_NOISE_GATE          0x13
+#define WM_LIMITER             0x14
+#define WM_ADC_MUX             0x15
+#define WM_OUT_MUX             0x16
+#define WM_RESET               0x17
+
+/* Analog Recording Source :- Mic, LineIn, CD/Video, */
+
+/* implement capture source select control for WM8776 */
+
+#define WM_AIN1 "AIN1"
+#define WM_AIN2 "AIN2"
+#define WM_AIN3 "AIN3"
+#define WM_AIN4 "AIN4"
+#define WM_AIN5 "AIN5"
+
+/* GPIO pins of envy24ht connected to wm8766 */
+#define WM8766_SPI_CLK  (1<<17) /* CLK, Pin97 on ICE1724 */
+#define WM8766_SPI_MD    (1<<16) /* DATA VT1724 -> WM8766, Pin96 */
+#define WM8766_SPI_ML    (1<<18) /* Latch, Pin98 */
+
+/* WM8766 registers */
+#define WM8766_DAC_CTRL         0x02   /* DAC Control */
+#define WM8766_INT_CTRL         0x03   /* Interface Control */
+#define WM8766_DAC_CTRL2       0x09
+#define WM8766_DAC_CTRL3       0x0a
+#define WM8766_RESET       0x1f
+#define WM8766_LDA1         0x00
+#define WM8766_LDA2         0x04
+#define WM8766_LDA3         0x06
+#define WM8766_RDA1         0x01
+#define WM8766_RDA2         0x05
+#define WM8766_RDA3         0x07
+#define WM8766_MUTE1       0x0C
+#define WM8766_MUTE2       0x0F
+
+
+/*
+ * Prodigy HD2
+ */
+#define AK4396_ADDR    0x00
+#define AK4396_CSN    (1 << 8)    /* CSN->GPIO8, pin 75 */
+#define AK4396_CCLK   (1 << 9)    /* CCLK->GPIO9, pin 76 */
+#define AK4396_CDTI   (1 << 10)   /* CDTI->GPIO10, pin 77 */
+
+/* ak4396 registers */
+#define AK4396_CTRL1       0x00
+#define AK4396_CTRL2       0x01
+#define AK4396_CTRL3       0x02
+#define AK4396_LCH_ATT   0x03
+#define AK4396_RCH_ATT   0x04
+
+
+/*
+ * get the current register value of WM codec
+ */
+static unsigned short wm_get(struct snd_ice1712 *ice, int reg)
+{
+       reg <<= 1;
+       return ((unsigned short)ice->akm[0].images[reg] << 8) |
+               ice->akm[0].images[reg + 1];
+}
+
+/*
+ * set the register value of WM codec and remember it
+ */
+static void wm_put_nocache(struct snd_ice1712 *ice, int reg, unsigned short val)
+{
+       unsigned short cval;
+       cval = (reg << 9) | val;
+       snd_vt1724_write_i2c(ice, WM_DEV, cval >> 8, cval & 0xff);
+}
+
+static void wm_put(struct snd_ice1712 *ice, int reg, unsigned short val)
+{
+       wm_put_nocache(ice, reg, val);
+       reg <<= 1;
+       ice->akm[0].images[reg] = val >> 8;
+       ice->akm[0].images[reg + 1] = val;
+}
+
+/*
+ * write data in the SPI mode
+ */
+
+static void set_gpio_bit(struct snd_ice1712 *ice, unsigned int bit, int val)
+{
+       unsigned int tmp = snd_ice1712_gpio_read(ice);
+       if (val)
+               tmp |= bit;
+       else
+               tmp &= ~bit;
+       snd_ice1712_gpio_write(ice, tmp);
+}
+
+/*
+ * SPI implementation for WM8766 codec - only writing supported, no readback
+ */
+
+static void wm8766_spi_send_word(struct snd_ice1712 *ice, unsigned int data)
+{
+       int i;
+       for (i = 0; i < 16; i++) {
+               set_gpio_bit(ice, WM8766_SPI_CLK, 0);
+               udelay(1);
+               set_gpio_bit(ice, WM8766_SPI_MD, data & 0x8000);
+               udelay(1);
+               set_gpio_bit(ice, WM8766_SPI_CLK, 1);
+               udelay(1);
+               data <<= 1;
+       }
+}
+
+static void wm8766_spi_write(struct snd_ice1712 *ice, unsigned int reg,
+                            unsigned int data)
+{
+       unsigned int block;
+
+       snd_ice1712_gpio_set_dir(ice, WM8766_SPI_MD|
+                                       WM8766_SPI_CLK|WM8766_SPI_ML);
+       snd_ice1712_gpio_set_mask(ice, ~(WM8766_SPI_MD|
+                                       WM8766_SPI_CLK|WM8766_SPI_ML));
+       /* latch must be low when writing */
+       set_gpio_bit(ice, WM8766_SPI_ML, 0);
+       block = (reg << 9) | (data & 0x1ff);
+       wm8766_spi_send_word(ice, block); /* REGISTER ADDRESS */
+       /* release latch */
+       set_gpio_bit(ice, WM8766_SPI_ML, 1);
+       udelay(1);
+       /* restore */
+       snd_ice1712_gpio_set_mask(ice, ice->gpio.write_mask);
+       snd_ice1712_gpio_set_dir(ice, ice->gpio.direction);
+}
+
+
+/*
+ * serial interface for ak4396 - only writing supported, no readback
+ */
+
+static void ak4396_send_word(struct snd_ice1712 *ice, unsigned int data)
+{
+       int i;
+       for (i = 0; i < 16; i++) {
+               set_gpio_bit(ice, AK4396_CCLK, 0);
+               udelay(1);
+               set_gpio_bit(ice, AK4396_CDTI, data & 0x8000);
+               udelay(1);
+               set_gpio_bit(ice, AK4396_CCLK, 1);
+               udelay(1);
+               data <<= 1;
+       }
+}
+
+static void ak4396_write(struct snd_ice1712 *ice, unsigned int reg,
+                        unsigned int data)
+{
+       unsigned int block;
+
+       snd_ice1712_gpio_set_dir(ice, AK4396_CSN|AK4396_CCLK|AK4396_CDTI);
+       snd_ice1712_gpio_set_mask(ice, ~(AK4396_CSN|AK4396_CCLK|AK4396_CDTI));
+       /* latch must be low when writing */
+       set_gpio_bit(ice, AK4396_CSN, 0); 
+       block =  ((AK4396_ADDR & 0x03) << 14) | (1 << 13) |
+                       ((reg & 0x1f) << 8) | (data & 0xff);
+       ak4396_send_word(ice, block); /* REGISTER ADDRESS */
+       /* release latch */
+       set_gpio_bit(ice, AK4396_CSN, 1);
+       udelay(1);
+       /* restore */
+       snd_ice1712_gpio_set_mask(ice, ice->gpio.write_mask);
+       snd_ice1712_gpio_set_dir(ice, ice->gpio.direction);
+}
+
+
+/*
+ * ak4396 mixers
+ */
+
+
+
+/*
+ * DAC volume attenuation mixer control (-64dB to 0dB)
+ */
+
+static int ak4396_dac_vol_info(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = 2;
+       uinfo->value.integer.min = 0;   /* mute */
+       uinfo->value.integer.max = 0xFF; /* linear */
+       return 0;
+}
+
+static int ak4396_dac_vol_get(struct snd_kcontrol *kcontrol,
+                             struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+       struct prodigy_hifi_spec *spec = ice->spec;
+       int i;
+       
+       for (i = 0; i < 2; i++)
+               ucontrol->value.integer.value[i] = spec->vol[i];
+
+       return 0;
+}
+
+static int ak4396_dac_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+       struct prodigy_hifi_spec *spec = ice->spec;
+       int i;
+       int change = 0;
+       
+       mutex_lock(&ice->gpio_mutex);
+       for (i = 0; i < 2; i++) {
+               if (ucontrol->value.integer.value[i] != spec->vol[i]) {
+                       spec->vol[i] = ucontrol->value.integer.value[i];
+                       ak4396_write(ice, AK4396_LCH_ATT + i,
+                                    spec->vol[i] & 0xff);
+                       change = 1;
+               }
+       }
+       mutex_unlock(&ice->gpio_mutex);
+       return change;
+}
+
+static const DECLARE_TLV_DB_SCALE(db_scale_wm_dac, -12700, 100, 1);
+
+static struct snd_kcontrol_new prodigy_hd2_controls[] __devinitdata = {
+    {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
+               SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+       .name = "Front Playback Volume",
+       .info = ak4396_dac_vol_info,
+       .get = ak4396_dac_vol_get,
+       .put = ak4396_dac_vol_put,
+       .tlv = { .p = db_scale_wm_dac },
+    },
+};
+
+
+/* --------------- */
+
+/*
+ * Logarithmic volume values for WM87*6
+ * Computed as 20 * Log10(255 / x)
+ */
+static const unsigned char wm_vol[256] = {
+       127, 48, 42, 39, 36, 34, 33, 31, 30, 29, 28, 27, 27, 26, 25, 25, 24, 24, 23,
+       23, 22, 22, 21, 21, 21, 20, 20, 20, 19, 19, 19, 18, 18, 18, 18, 17, 17, 17,
+       17, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 14, 14, 14, 14, 14, 13, 13, 13,
+       13, 13, 13, 13, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11,
+       11, 10, 10, 10, 10, 10, 10, 10, 10, 10, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 8,
+       8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6,
+       6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+       5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3,
+       3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+       2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0
+};
+
+#define WM_VOL_MAX     (sizeof(wm_vol) - 1)
+#define WM_VOL_MUTE    0x8000
+
+
+#define DAC_0dB        0xff
+#define DAC_RES        128
+#define DAC_MIN        (DAC_0dB - DAC_RES)
+
+
+static void wm_set_vol(struct snd_ice1712 *ice, unsigned int index,
+                      unsigned short vol, unsigned short master)
+{
+       unsigned char nvol;
+       
+       if ((master & WM_VOL_MUTE) || (vol & WM_VOL_MUTE))
+               nvol = 0;
+       else {
+               nvol = (((vol & ~WM_VOL_MUTE) * (master & ~WM_VOL_MUTE)) / 128)
+                               & WM_VOL_MAX;
+               nvol = (nvol ? (nvol + DAC_MIN) : 0) & 0xff;
+       }
+       
+       wm_put(ice, index, nvol);
+       wm_put_nocache(ice, index, 0x100 | nvol);
+}
+
+static void wm8766_set_vol(struct snd_ice1712 *ice, unsigned int index,
+                          unsigned short vol, unsigned short master)
+{
+       unsigned char nvol;
+       
+       if ((master & WM_VOL_MUTE) || (vol & WM_VOL_MUTE))
+               nvol = 0;
+       else {
+               nvol = (((vol & ~WM_VOL_MUTE) * (master & ~WM_VOL_MUTE)) / 128)
+                               & WM_VOL_MAX;
+               nvol = (nvol ? (nvol + DAC_MIN) : 0) & 0xff;
+       }
+
+       wm8766_spi_write(ice, index, (0x0100 | nvol));
+}
+
+
+/*
+ * DAC volume attenuation mixer control (-64dB to 0dB)
+ */
+
+static int wm_dac_vol_info(struct snd_kcontrol *kcontrol,
+                          struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = 2;
+       uinfo->value.integer.min = 0;   /* mute */
+       uinfo->value.integer.max = DAC_RES;     /* 0dB, 0.5dB step */
+       return 0;
+}
+
+static int wm_dac_vol_get(struct snd_kcontrol *kcontrol,
+                         struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+       struct prodigy_hifi_spec *spec = ice->spec;
+       int i;
+
+       for (i = 0; i < 2; i++)
+               ucontrol->value.integer.value[i] =
+                       spec->vol[2 + i] & ~WM_VOL_MUTE;
+       return 0;
+}
+
+static int wm_dac_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+       struct prodigy_hifi_spec *spec = ice->spec;
+       int i, idx, change = 0;
+
+       mutex_lock(&ice->gpio_mutex);
+       for (i = 0; i < 2; i++) {
+               if (ucontrol->value.integer.value[i] != spec->vol[2 + i]) {
+                       idx = WM_DAC_ATTEN_L + i;
+                       spec->vol[2 + i] &= WM_VOL_MUTE;
+                       spec->vol[2 + i] |= ucontrol->value.integer.value[i];
+                       wm_set_vol(ice, idx, spec->vol[2 + i], spec->master[i]);
+                       change = 1;
+               }
+       }
+       mutex_unlock(&ice->gpio_mutex);
+       return change;
+}
+
+
+/*
+ * WM8766 DAC volume attenuation mixer control
+ */
+static int wm8766_vol_info(struct snd_kcontrol *kcontrol,
+                          struct snd_ctl_elem_info *uinfo)
+{
+       int voices = kcontrol->private_value >> 8;
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = voices;
+       uinfo->value.integer.min = 0;           /* mute */
+       uinfo->value.integer.max = DAC_RES;     /* 0dB */
+       return 0;
+}
+
+static int wm8766_vol_get(struct snd_kcontrol *kcontrol,
+                         struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+       struct prodigy_hifi_spec *spec = ice->spec;
+       int i, ofs, voices;
+
+       voices = kcontrol->private_value >> 8;
+       ofs = kcontrol->private_value & 0xff;
+       for (i = 0; i < voices; i++)
+               ucontrol->value.integer.value[i] = spec->vol[ofs + i];
+       return 0;
+}
+
+static int wm8766_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+       struct prodigy_hifi_spec *spec = ice->spec;
+       int i, idx, ofs, voices;
+       int change = 0;
+
+       voices = kcontrol->private_value >> 8;
+       ofs = kcontrol->private_value & 0xff;
+       mutex_lock(&ice->gpio_mutex);
+       for (i = 0; i < voices; i++) {
+               if (ucontrol->value.integer.value[i] != spec->vol[ofs + i]) {
+                       idx = WM8766_LDA1 + ofs + i;
+                       spec->vol[ofs + i] &= WM_VOL_MUTE;
+                       spec->vol[ofs + i] |= ucontrol->value.integer.value[i];
+                       wm8766_set_vol(ice, idx,
+                                      spec->vol[ofs + i], spec->master[i]);
+                       change = 1;
+               }
+       }
+       mutex_unlock(&ice->gpio_mutex);
+       return change;
+}
+
+/*
+ * Master volume attenuation mixer control / applied to WM8776+WM8766
+ */
+static int wm_master_vol_info(struct snd_kcontrol *kcontrol,
+                             struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = 2;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = DAC_RES;
+       return 0;
+}
+
+static int wm_master_vol_get(struct snd_kcontrol *kcontrol,
+                            struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+       struct prodigy_hifi_spec *spec = ice->spec;
+       int i;
+       for (i = 0; i < 2; i++)
+               ucontrol->value.integer.value[i] = spec->master[i];
+       return 0;
+}
+
+static int wm_master_vol_put(struct snd_kcontrol *kcontrol,
+                            struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+       struct prodigy_hifi_spec *spec = ice->spec;
+       int ch, change = 0;
+
+       mutex_lock(&ice->gpio_mutex);
+       for (ch = 0; ch < 2; ch++) {
+               if (ucontrol->value.integer.value[ch] != spec->master[ch]) {
+                       spec->master[ch] = ucontrol->value.integer.value[ch];
+
+                       /* Apply to front DAC */
+                       wm_set_vol(ice, WM_DAC_ATTEN_L + ch,
+                                  spec->vol[2 + ch], spec->master[ch]);
+
+                       wm8766_set_vol(ice, WM8766_LDA1 + ch,
+                                      spec->vol[0 + ch], spec->master[ch]);
+
+                       wm8766_set_vol(ice, WM8766_LDA2 + ch,
+                                      spec->vol[4 + ch], spec->master[ch]);
+
+                       wm8766_set_vol(ice, WM8766_LDA3 + ch,
+                                      spec->vol[6 + ch], spec->master[ch]);
+                       change = 1;
+               }
+       }
+       mutex_unlock(&ice->gpio_mutex); 
+       return change;
+}
+
+
+/* KONSTI */
+
+static int wm_adc_mux_enum_info(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_info *uinfo)
+{
+       static char* texts[32] = {
+               "NULL", WM_AIN1, WM_AIN2, WM_AIN1 "+" WM_AIN2,
+               WM_AIN3, WM_AIN1 "+" WM_AIN3, WM_AIN2 "+" WM_AIN3,
+               WM_AIN1 "+" WM_AIN2 "+" WM_AIN3,
+               WM_AIN4, WM_AIN1 "+" WM_AIN4, WM_AIN2 "+" WM_AIN4,
+               WM_AIN1 "+" WM_AIN2 "+" WM_AIN4,
+               WM_AIN3 "+" WM_AIN4, WM_AIN1 "+" WM_AIN3 "+" WM_AIN4,
+               WM_AIN2 "+" WM_AIN3 "+" WM_AIN4,
+               WM_AIN1 "+" WM_AIN2 "+" WM_AIN3 "+" WM_AIN4,
+               WM_AIN5, WM_AIN1 "+" WM_AIN5, WM_AIN2 "+" WM_AIN5,
+               WM_AIN1 "+" WM_AIN2 "+" WM_AIN5,
+               WM_AIN3 "+" WM_AIN5, WM_AIN1 "+" WM_AIN3 "+" WM_AIN5,
+               WM_AIN2 "+" WM_AIN3 "+" WM_AIN5,
+               WM_AIN1 "+" WM_AIN2 "+" WM_AIN3 "+" WM_AIN5,
+               WM_AIN4 "+" WM_AIN5, WM_AIN1 "+" WM_AIN4 "+" WM_AIN5,
+               WM_AIN2 "+" WM_AIN4 "+" WM_AIN5,
+               WM_AIN1 "+" WM_AIN2 "+" WM_AIN4 "+" WM_AIN5,
+               WM_AIN3 "+" WM_AIN4 "+" WM_AIN5,
+               WM_AIN1 "+" WM_AIN3 "+" WM_AIN4 "+" WM_AIN5,
+               WM_AIN2 "+" WM_AIN3 "+" WM_AIN4 "+" WM_AIN5,
+               WM_AIN1 "+" WM_AIN2 "+" WM_AIN3 "+" WM_AIN4 "+" WM_AIN5
+       };
+
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+       uinfo->count = 1;
+       uinfo->value.enumerated.items = 32;
+       if (uinfo->value.enumerated.item > 31)
+               uinfo->value.enumerated.item = 31;
+       strcpy(uinfo->value.enumerated.name,
+              texts[uinfo->value.enumerated.item]);
+       return 0;
+}
+
+static int wm_adc_mux_enum_get(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+
+       mutex_lock(&ice->gpio_mutex);
+       ucontrol->value.integer.value[0] = wm_get(ice, WM_ADC_MUX) & 0x1f;
+       mutex_unlock(&ice->gpio_mutex);
+       return 0;
+}
+
+static int wm_adc_mux_enum_put(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+       unsigned short oval, nval;
+       int change = 0;
+
+       mutex_lock(&ice->gpio_mutex);
+       oval = wm_get(ice, WM_ADC_MUX);
+       nval = (oval & 0xe0) | ucontrol->value.integer.value[0];
+       if (nval != oval) {
+               wm_put(ice, WM_ADC_MUX, nval);
+               change = 1;
+       }
+       mutex_unlock(&ice->gpio_mutex);
+       return change;
+}
+
+/* KONSTI */
+
+/*
+ * ADC gain mixer control (-64dB to 0dB)
+ */
+
+#define ADC_0dB        0xcf
+#define ADC_RES        128
+#define ADC_MIN        (ADC_0dB - ADC_RES)
+
+static int wm_adc_vol_info(struct snd_kcontrol *kcontrol,
+                          struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = 2;
+       uinfo->value.integer.min = 0;   /* mute (-64dB) */
+       uinfo->value.integer.max = ADC_RES;     /* 0dB, 0.5dB step */
+       return 0;
+}
+
+static int wm_adc_vol_get(struct snd_kcontrol *kcontrol,
+                         struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+       unsigned short val;
+       int i;
+
+       mutex_lock(&ice->gpio_mutex);
+       for (i = 0; i < 2; i++) {
+               val = wm_get(ice, WM_ADC_ATTEN_L + i) & 0xff;
+               val = val > ADC_MIN ? (val - ADC_MIN) : 0;
+               ucontrol->value.integer.value[i] = val;
+       }
+       mutex_unlock(&ice->gpio_mutex);
+       return 0;
+}
+
+static int wm_adc_vol_put(struct snd_kcontrol *kcontrol,
+                         struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+       unsigned short ovol, nvol;
+       int i, idx, change = 0;
+
+       mutex_lock(&ice->gpio_mutex);
+       for (i = 0; i < 2; i++) {
+               nvol = ucontrol->value.integer.value[i];
+               nvol = nvol ? (nvol + ADC_MIN) : 0;
+               idx  = WM_ADC_ATTEN_L + i;
+               ovol = wm_get(ice, idx) & 0xff;
+               if (ovol != nvol) {
+                       wm_put(ice, idx, nvol);
+                       change = 1;
+               }
+       }
+       mutex_unlock(&ice->gpio_mutex);
+       return change;
+}
+
+/*
+ * ADC input mux mixer control
+ */
+#define wm_adc_mux_info                snd_ctl_boolean_mono_info
+
+static int wm_adc_mux_get(struct snd_kcontrol *kcontrol,
+                         struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+       int bit = kcontrol->private_value;
+
+       mutex_lock(&ice->gpio_mutex);
+       ucontrol->value.integer.value[0] =
+               (wm_get(ice, WM_ADC_MUX) & (1 << bit)) ? 1 : 0;
+       mutex_unlock(&ice->gpio_mutex);
+       return 0;
+}
+
+static int wm_adc_mux_put(struct snd_kcontrol *kcontrol,
+                         struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+       int bit = kcontrol->private_value;
+       unsigned short oval, nval;
+       int change;
+
+       mutex_lock(&ice->gpio_mutex);
+       nval = oval = wm_get(ice, WM_ADC_MUX);
+       if (ucontrol->value.integer.value[0])
+               nval |= (1 << bit);
+       else
+               nval &= ~(1 << bit);
+       change = nval != oval;
+       if (change) {
+               wm_put(ice, WM_ADC_MUX, nval);
+       }
+       mutex_unlock(&ice->gpio_mutex);
+       return 0;
+}
+
+/*
+ * Analog bypass (In -> Out)
+ */
+#define wm_bypass_info         snd_ctl_boolean_mono_info
+
+static int wm_bypass_get(struct snd_kcontrol *kcontrol,
+                        struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+
+       mutex_lock(&ice->gpio_mutex);
+       ucontrol->value.integer.value[0] =
+               (wm_get(ice, WM_OUT_MUX) & 0x04) ? 1 : 0;
+       mutex_unlock(&ice->gpio_mutex);
+       return 0;
+}
+
+static int wm_bypass_put(struct snd_kcontrol *kcontrol,
+                        struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+       unsigned short val, oval;
+       int change = 0;
+
+       mutex_lock(&ice->gpio_mutex);
+       val = oval = wm_get(ice, WM_OUT_MUX);
+       if (ucontrol->value.integer.value[0])
+               val |= 0x04;
+       else
+               val &= ~0x04;
+       if (val != oval) {
+               wm_put(ice, WM_OUT_MUX, val);
+               change = 1;
+       }
+       mutex_unlock(&ice->gpio_mutex);
+       return change;
+}
+
+/*
+ * Left/Right swap
+ */
+#define wm_chswap_info         snd_ctl_boolean_mono_info
+
+static int wm_chswap_get(struct snd_kcontrol *kcontrol,
+                        struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+
+       mutex_lock(&ice->gpio_mutex);
+       ucontrol->value.integer.value[0] =
+                       (wm_get(ice, WM_DAC_CTRL1) & 0xf0) != 0x90;
+       mutex_unlock(&ice->gpio_mutex);
+       return 0;
+}
+
+static int wm_chswap_put(struct snd_kcontrol *kcontrol,
+                        struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+       unsigned short val, oval;
+       int change = 0;
+
+       mutex_lock(&ice->gpio_mutex);
+       oval = wm_get(ice, WM_DAC_CTRL1);
+       val = oval & 0x0f;
+       if (ucontrol->value.integer.value[0])
+               val |= 0x60;
+       else
+               val |= 0x90;
+       if (val != oval) {
+               wm_put(ice, WM_DAC_CTRL1, val);
+               wm_put_nocache(ice, WM_DAC_CTRL1, val);
+               change = 1;
+       }
+       mutex_unlock(&ice->gpio_mutex);
+       return change;
+}
+
+
+/*
+ * mixers
+ */
+
+static struct snd_kcontrol_new prodigy_hifi_controls[] __devinitdata = {
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
+                          SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+               .name = "Master Playback Volume",
+               .info = wm_master_vol_info,
+               .get = wm_master_vol_get,
+               .put = wm_master_vol_put,
+               .tlv = { .p = db_scale_wm_dac }
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
+                          SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+               .name = "Front Playback Volume",
+               .info = wm_dac_vol_info,
+               .get = wm_dac_vol_get,
+               .put = wm_dac_vol_put,
+               .tlv = { .p = db_scale_wm_dac },
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
+                          SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+               .name = "Rear Playback Volume",
+               .info = wm8766_vol_info,
+               .get = wm8766_vol_get,
+               .put = wm8766_vol_put,
+               .private_value = (2 << 8) | 0,
+               .tlv = { .p = db_scale_wm_dac },
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
+                          SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+               .name = "Center Playback Volume",
+               .info = wm8766_vol_info,
+               .get = wm8766_vol_get,
+               .put = wm8766_vol_put,
+               .private_value = (1 << 8) | 4,
+               .tlv = { .p = db_scale_wm_dac }
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
+                          SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+               .name = "LFE Playback Volume",
+               .info = wm8766_vol_info,
+               .get = wm8766_vol_get,
+               .put = wm8766_vol_put,
+               .private_value = (1 << 8) | 5,
+               .tlv = { .p = db_scale_wm_dac }
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
+                          SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+               .name = "Side Playback Volume",
+               .info = wm8766_vol_info,
+               .get = wm8766_vol_get,
+               .put = wm8766_vol_put,
+               .private_value = (2 << 8) | 6,
+               .tlv = { .p = db_scale_wm_dac },
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
+                          SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+               .name = "Capture Volume",
+               .info = wm_adc_vol_info,
+               .get = wm_adc_vol_get,
+               .put = wm_adc_vol_put,
+               .tlv = { .p = db_scale_wm_dac },
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "CD Capture Switch",
+               .info = wm_adc_mux_info,
+               .get = wm_adc_mux_get,
+               .put = wm_adc_mux_put,
+               .private_value = 0,
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Line Capture Switch",
+               .info = wm_adc_mux_info,
+               .get = wm_adc_mux_get,
+               .put = wm_adc_mux_put,
+               .private_value = 1,
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Analog Bypass Switch",
+               .info = wm_bypass_info,
+               .get = wm_bypass_get,
+               .put = wm_bypass_put,
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Swap Output Channels",
+               .info = wm_chswap_info,
+               .get = wm_chswap_get,
+               .put = wm_chswap_put,
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Analog Capture Source",
+               .info = wm_adc_mux_enum_info,
+               .get = wm_adc_mux_enum_get,
+               .put = wm_adc_mux_enum_put,
+       },
+};
+
+/*
+ * WM codec registers
+ */
+static void wm_proc_regs_write(struct snd_info_entry *entry,
+                              struct snd_info_buffer *buffer)
+{
+       struct snd_ice1712 *ice = entry->private_data;
+       char line[64];
+       unsigned int reg, val;
+       mutex_lock(&ice->gpio_mutex);
+       while (!snd_info_get_line(buffer, line, sizeof(line))) {
+               if (sscanf(line, "%x %x", &reg, &val) != 2)
+                       continue;
+               if (reg <= 0x17 && val <= 0xffff)
+                       wm_put(ice, reg, val);
+       }
+       mutex_unlock(&ice->gpio_mutex);
+}
+
+static void wm_proc_regs_read(struct snd_info_entry *entry,
+                             struct snd_info_buffer *buffer)
+{
+       struct snd_ice1712 *ice = entry->private_data;
+       int reg, val;
+
+       mutex_lock(&ice->gpio_mutex);
+       for (reg = 0; reg <= 0x17; reg++) {
+               val = wm_get(ice, reg);
+               snd_iprintf(buffer, "%02x = %04x\n", reg, val);
+       }
+       mutex_unlock(&ice->gpio_mutex);
+}
+
+static void wm_proc_init(struct snd_ice1712 *ice)
+{
+       struct snd_info_entry *entry;
+       if (!snd_card_proc_new(ice->card, "wm_codec", &entry)) {
+               snd_info_set_text_ops(entry, ice, wm_proc_regs_read);
+               entry->mode |= S_IWUSR;
+               entry->c.text.write = wm_proc_regs_write;
+       }
+}
+
+static int __devinit prodigy_hifi_add_controls(struct snd_ice1712 *ice)
+{
+       unsigned int i;
+       int err;
+
+       for (i = 0; i < ARRAY_SIZE(prodigy_hifi_controls); i++) {
+               err = snd_ctl_add(ice->card,
+                                 snd_ctl_new1(&prodigy_hifi_controls[i], ice));
+               if (err < 0)
+                       return err;
+       }
+
+       wm_proc_init(ice);
+
+       return 0;
+}
+
+static int __devinit prodigy_hd2_add_controls(struct snd_ice1712 *ice)
+{
+       unsigned int i;
+       int err;
+
+       for (i = 0; i < ARRAY_SIZE(prodigy_hd2_controls); i++) {
+               err = snd_ctl_add(ice->card,
+                                 snd_ctl_new1(&prodigy_hd2_controls[i], ice));
+               if (err < 0)
+                       return err;
+       }
+
+       wm_proc_init(ice);
+
+       return 0;
+}
+
+
+/*
+ * initialize the chip
+ */
+static int __devinit prodigy_hifi_init(struct snd_ice1712 *ice)
+{
+       static unsigned short wm_inits[] = {
+               /* These come first to reduce init pop noise */
+               WM_ADC_MUX,     0x0003, /* ADC mute */
+               /* 0x00c0 replaced by 0x0003 */
+               
+               WM_DAC_MUTE,    0x0001, /* DAC softmute */
+               WM_DAC_CTRL1,   0x0000, /* DAC mute */
+
+               WM_POWERDOWN,   0x0008, /* All power-up except HP */
+               WM_RESET,       0x0000, /* reset */
+       };
+       static unsigned short wm_inits2[] = {
+               WM_MASTER_CTRL,  0x0022, /* 256fs, slave mode */
+               WM_DAC_INT,     0x0022, /* I2S, normal polarity, 24bit */
+               WM_ADC_INT,     0x0022, /* I2S, normal polarity, 24bit */
+               WM_DAC_CTRL1,   0x0090, /* DAC L/R */
+               WM_OUT_MUX,     0x0001, /* OUT DAC */
+               WM_HP_ATTEN_L,  0x0179, /* HP 0dB */
+               WM_HP_ATTEN_R,  0x0179, /* HP 0dB */
+               WM_DAC_ATTEN_L, 0x0000, /* DAC 0dB */
+               WM_DAC_ATTEN_L, 0x0100, /* DAC 0dB */
+               WM_DAC_ATTEN_R, 0x0000, /* DAC 0dB */
+               WM_DAC_ATTEN_R, 0x0100, /* DAC 0dB */
+               WM_PHASE_SWAP,  0x0000, /* phase normal */
+#if 0
+               WM_DAC_MASTER,  0x0100, /* DAC master muted */
+#endif
+               WM_DAC_CTRL2,   0x0000, /* no deemphasis, no ZFLG */
+               WM_ADC_ATTEN_L, 0x0000, /* ADC muted */
+               WM_ADC_ATTEN_R, 0x0000, /* ADC muted */
+#if 1
+               WM_ALC_CTRL1,   0x007b, /* */
+               WM_ALC_CTRL2,   0x0000, /* */
+               WM_ALC_CTRL3,   0x0000, /* */
+               WM_NOISE_GATE,  0x0000, /* */
+#endif
+               WM_DAC_MUTE,    0x0000, /* DAC unmute */
+               WM_ADC_MUX,     0x0003, /* ADC unmute, both CD/Line On */
+       };
+       static unsigned short wm8766_inits[] = {
+               WM8766_RESET,      0x0000,
+               WM8766_DAC_CTRL,        0x0120,
+               WM8766_INT_CTRL,        0x0022, /* I2S Normal Mode, 24 bit */
+               WM8766_DAC_CTRL2,       0x0001,
+               WM8766_DAC_CTRL3,       0x0080,
+               WM8766_LDA1,        0x0100,
+               WM8766_LDA2,        0x0100,
+               WM8766_LDA3,        0x0100,
+               WM8766_RDA1,        0x0100,
+               WM8766_RDA2,        0x0100,
+               WM8766_RDA3,        0x0100,
+               WM8766_MUTE1,      0x0000,
+               WM8766_MUTE2,      0x0000,
+       };
+
+       struct prodigy_hifi_spec *spec;
+       unsigned int i;
+
+       ice->vt1720 = 0;
+       ice->vt1724 = 1;
+
+       ice->num_total_dacs = 8;
+       ice->num_total_adcs = 1;
+
+       /* HACK - use this as the SPDIF source.
+       * don't call snd_ice1712_gpio_get/put(), otherwise it's overwritten
+       */
+       ice->gpio.saved[0] = 0;
+       /* to remeber the register values */
+
+       ice->akm = kzalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL);
+       if (! ice->akm)
+               return -ENOMEM;
+       ice->akm_codecs = 1;
+
+       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+       if (!spec)
+               return -ENOMEM;
+       ice->spec = spec;
+
+       /* initialize WM8776 codec */
+       for (i = 0; i < ARRAY_SIZE(wm_inits); i += 2)
+               wm_put(ice, wm_inits[i], wm_inits[i+1]);
+       schedule_timeout_uninterruptible(1);
+       for (i = 0; i < ARRAY_SIZE(wm_inits2); i += 2)
+               wm_put(ice, wm_inits2[i], wm_inits2[i+1]);
+
+       /* initialize WM8766 codec */
+       for (i = 0; i < ARRAY_SIZE(wm8766_inits); i += 2)
+               wm8766_spi_write(ice, wm8766_inits[i], wm8766_inits[i+1]);
+
+
+       return 0;
+}
+
+
+/*
+ * initialize the chip
+ */
+static int __devinit prodigy_hd2_init(struct snd_ice1712 *ice)
+{
+       static unsigned short ak4396_inits[] = {
+               AK4396_CTRL1,      0x87,   /* I2S Normal Mode, 24 bit */
+               AK4396_CTRL2,      0x02,
+               AK4396_CTRL3,      0x00, 
+               AK4396_LCH_ATT,  0x00,
+               AK4396_RCH_ATT,  0x00,
+       };
+
+       struct prodigy_hifi_spec *spec;
+       unsigned int i;
+
+       ice->vt1720 = 0;
+       ice->vt1724 = 1;
+
+       ice->num_total_dacs = 1;
+       ice->num_total_adcs = 1;
+
+       /* HACK - use this as the SPDIF source.
+       * don't call snd_ice1712_gpio_get/put(), otherwise it's overwritten
+       */
+       ice->gpio.saved[0] = 0;
+       /* to remeber the register values */
+
+       ice->akm = kzalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL);
+       if (! ice->akm)
+               return -ENOMEM;
+       ice->akm_codecs = 1;
+
+       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+       if (!spec)
+               return -ENOMEM;
+       ice->spec = spec;
+
+       /* initialize ak4396 codec */
+       /* reset codec */
+       ak4396_write(ice, AK4396_CTRL1, 0x86);
+       msleep(100);
+       ak4396_write(ice, AK4396_CTRL1, 0x87);
+                       
+       for (i = 0; i < ARRAY_SIZE(ak4396_inits); i += 2)
+               ak4396_write(ice, ak4396_inits[i], ak4396_inits[i+1]);
+
+       return 0;
+}
+
+
+static unsigned char prodigy71hifi_eeprom[] __devinitdata = {
+       0x4b,   /* SYSCONF: clock 512, spdif-in/ADC, 4DACs */
+       0x80,   /* ACLINK: I2S */
+       0xfc,   /* I2S: vol, 96k, 24bit, 192k */
+       0xc3,   /* SPDIF: out-en, out-int, spdif-in */
+       0xff,   /* GPIO_DIR */
+       0xff,   /* GPIO_DIR1 */
+       0x5f,   /* GPIO_DIR2 */
+       0x00,   /* GPIO_MASK */
+       0x00,   /* GPIO_MASK1 */
+       0x00,   /* GPIO_MASK2 */
+       0x00,   /* GPIO_STATE */
+       0x00,   /* GPIO_STATE1 */
+       0x00,   /* GPIO_STATE2 */
+};
+
+static unsigned char prodigyhd2_eeprom[] __devinitdata = {
+       0x4b,   /* SYSCONF: clock 512, spdif-in/ADC, 4DACs */
+       0x80,   /* ACLINK: I2S */
+       0xfc,   /* I2S: vol, 96k, 24bit, 192k */
+       0xc3,   /* SPDIF: out-en, out-int, spdif-in */
+       0xff,   /* GPIO_DIR */
+       0xff,   /* GPIO_DIR1 */
+       0x5f,   /* GPIO_DIR2 */
+       0x00,   /* GPIO_MASK */
+       0x00,   /* GPIO_MASK1 */
+       0x00,   /* GPIO_MASK2 */
+       0x00,   /* GPIO_STATE */
+       0x00,   /* GPIO_STATE1 */
+       0x00,   /* GPIO_STATE2 */
+};
+
+static unsigned char fortissimo4_eeprom[] __devinitdata = {
+       0x43,   /* SYSCONF: clock 512, ADC, 4DACs */    
+       0x80,   /* ACLINK: I2S */
+       0xfc,   /* I2S: vol, 96k, 24bit, 192k */
+       0xc1,   /* SPDIF: out-en, out-int */
+       0xff,   /* GPIO_DIR */
+       0xff,   /* GPIO_DIR1 */
+       0x5f,   /* GPIO_DIR2 */
+       0x00,   /* GPIO_MASK */
+       0x00,   /* GPIO_MASK1 */
+       0x00,   /* GPIO_MASK2 */
+       0x00,   /* GPIO_STATE */
+       0x00,   /* GPIO_STATE1 */
+       0x00,   /* GPIO_STATE2 */
+};
+
+/* entry point */
+struct snd_ice1712_card_info snd_vt1724_prodigy_hifi_cards[] __devinitdata = {
+       {
+               .subvendor = VT1724_SUBDEVICE_PRODIGY_HIFI,
+               .name = "Audiotrak Prodigy 7.1 HiFi",
+               .model = "prodigy71hifi",
+               .chip_init = prodigy_hifi_init,
+               .build_controls = prodigy_hifi_add_controls,
+               .eeprom_size = sizeof(prodigy71hifi_eeprom),
+               .eeprom_data = prodigy71hifi_eeprom,
+               .driver = "Prodigy71HIFI",
+       },
+       {
+       .subvendor = VT1724_SUBDEVICE_PRODIGY_HD2,
+       .name = "Audiotrak Prodigy HD2",
+       .model = "prodigyhd2",
+       .chip_init = prodigy_hd2_init,
+       .build_controls = prodigy_hd2_add_controls,
+       .eeprom_size = sizeof(prodigyhd2_eeprom),
+       .eeprom_data = prodigyhd2_eeprom,
+       .driver = "Prodigy71HD2",
+       },
+       {
+               .subvendor = VT1724_SUBDEVICE_FORTISSIMO4,
+               .name = "Hercules Fortissimo IV",
+               .model = "fortissimo4",
+               .chip_init = prodigy_hifi_init,
+               .build_controls = prodigy_hifi_add_controls,
+               .eeprom_size = sizeof(fortissimo4_eeprom),
+               .eeprom_data = fortissimo4_eeprom,
+               .driver = "Fortissimo4",
+       },
+       { } /* terminator */
+};
+
diff --git a/sound/pci/ice1712/prodigy_hifi.h b/sound/pci/ice1712/prodigy_hifi.h
new file mode 100644 (file)
index 0000000..a4415d4
--- /dev/null
@@ -0,0 +1,38 @@
+#ifndef __SOUND_PRODIGY_HIFI_H
+#define __SOUND_PRODIGY_HIFI_H
+
+/*
+ *   ALSA driver for VIA VT1724 (Envy24HT)
+ *
+ *   Lowlevel functions for Audiotrak Prodigy Hifi
+ *
+ *     Copyright (c) 2004 Takashi Iwai <tiwai@suse.de>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */      
+
+#define PRODIGY_HIFI_DEVICE_DESC              "{Audiotrak,Prodigy 7.1 HIFI},"\
+                                           "{Audiotrak Prodigy HD2},"\
+                                           "{Hercules Fortissimo IV},"
+
+#define VT1724_SUBDEVICE_PRODIGY_HIFI  0x38315441      /* PRODIGY 7.1 HIFI */
+#define VT1724_SUBDEVICE_PRODIGY_HD2   0x37315441      /* PRODIGY HD2 */
+#define VT1724_SUBDEVICE_FORTISSIMO4   0x81160100      /* Fortissimo IV */
+
+
+extern struct snd_ice1712_card_info  snd_vt1724_prodigy_hifi_cards[];
+
+#endif /* __SOUND_PRODIGY_HIFI_H */
index d18a31e188a9a594ccbe8b0ed22a487bec783703..ddd5fc8d4fe12e9bbd3e61db39e95b8e07381826 100644 (file)
@@ -21,7 +21,6 @@
  *
  */      
 
-#include <sound/driver.h>
 #include <asm/io.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include "envy24ht.h"
 #include "revo.h"
 
+/* a non-standard I2C device for revo51 */
+struct revo51_spec {
+       struct snd_i2c_device *dev;
+       struct snd_pt2258 *pt2258;
+} revo51;
+
 static void revo_i2s_mclk_changed(struct snd_ice1712 *ice)
 {
        /* assert PRST# to converters; MT05 bit 7 */
@@ -153,8 +158,14 @@ static struct snd_i2c_bit_ops revo51_bit_ops = {
 static int revo51_i2c_init(struct snd_ice1712 *ice,
                           struct snd_pt2258 *pt)
 {
+       struct revo51_spec *spec;
        int err;
 
+       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+       if (!spec)
+               return -ENOMEM;
+       ice->spec = spec;
+
        /* create the I2C bus */
        err = snd_i2c_bus_create(ice->card, "ICE1724 GPIO6", NULL, &ice->i2c);
        if (err < 0)
@@ -164,15 +175,14 @@ static int revo51_i2c_init(struct snd_ice1712 *ice,
        ice->i2c->hw_ops.bit = &revo51_bit_ops;
 
        /* create the I2C device */
-       err = snd_i2c_device_create(ice->i2c, "PT2258", 0x40,
-                                   &ice->spec.revo51.dev);
+       err = snd_i2c_device_create(ice->i2c, "PT2258", 0x40, &spec->dev);
        if (err < 0)
                return err;
 
        pt->card = ice->card;
        pt->i2c_bus = ice->i2c;
-       pt->i2c_dev = ice->spec.revo51.dev;
-       ice->spec.revo51.pt2258 = pt;
+       pt->i2c_dev = spec->dev;
+       spec->pt2258 = pt;
 
        snd_pt2258_reset(pt);
 
@@ -556,6 +566,7 @@ static int __devinit revo_init(struct snd_ice1712 *ice)
 
 static int __devinit revo_add_controls(struct snd_ice1712 *ice)
 {
+       struct revo51_spec *spec;
        int err;
 
        switch (ice->eeprom.subvendor) {
@@ -568,7 +579,8 @@ static int __devinit revo_add_controls(struct snd_ice1712 *ice)
                err = snd_ice1712_akm4xxx_build_controls(ice);
                if (err < 0)
                        return err;
-               err = snd_pt2258_build_controls(ice->spec.revo51.pt2258);
+               spec = ice->spec;
+               err = snd_pt2258_build_controls(spec->pt2258);
                if (err < 0)
                        return err;
                break;
diff --git a/sound/pci/ice1712/se.c b/sound/pci/ice1712/se.c
new file mode 100644 (file)
index 0000000..69673b9
--- /dev/null
@@ -0,0 +1,774 @@
+/*
+ *   ALSA driver for ICEnsemble VT1724 (Envy24HT)
+ *
+ *   Lowlevel functions for ONKYO WAVIO SE-90PCI and SE-200PCI
+ *
+ *     Copyright (c) 2007 Shin-ya Okada  sh_okada(at)d4.dion.ne.jp
+ *                                        (at) -> @
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */      
+
+#include <asm/io.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/tlv.h>
+
+#include "ice1712.h"
+#include "envy24ht.h"
+#include "se.h"
+
+struct se_spec {
+       struct {
+               unsigned char ch1, ch2;
+       } vol[8];
+};
+
+/****************************************************************************/
+/*  ONKYO WAVIO SE-200PCI                                                   */
+/****************************************************************************/
+/*
+ *  system configuration ICE_EEP2_SYSCONF=0x4b
+ *    XIN1 49.152MHz
+ *    not have UART
+ *    one stereo ADC and a S/PDIF receiver connected
+ *    four stereo DACs connected
+ *
+ *  AC-Link configuration ICE_EEP2_ACLINK=0x80
+ *    use I2C, not use AC97
+ *
+ *  I2S converters feature ICE_EEP2_I2S=0x78
+ *    I2S codec has no volume/mute control feature
+ *    I2S codec supports 96KHz and 192KHz
+ *    I2S codec 24bits
+ *
+ *  S/PDIF configuration ICE_EEP2_SPDIF=0xc3
+ *    Enable integrated S/PDIF transmitter
+ *    internal S/PDIF out implemented
+ *    S/PDIF is stereo
+ *    External S/PDIF out implemented
+ *
+ *
+ * ** connected chips **
+ *
+ *  WM8740
+ *      A 2ch-DAC of main outputs.
+ *      It setuped as I2S mode by wire, so no way to setup from software.
+ *      The sample-rate are automatically changed. 
+ *          ML/I2S (28pin) --------+
+ *          MC/DM1 (27pin) -- 5V   |
+ *          MD/DM0 (26pin) -- GND  |
+ *          MUTEB  (25pin) -- NC   |
+ *          MODE   (24pin) -- GND  |
+ *          CSBIW  (23pin) --------+
+ *                                 |
+ *          RSTB   (22pin) --R(1K)-+
+ *      Probably it reduce the noise from the control line.
+ *
+ *  WM8766
+ *      A 6ch-DAC for surrounds.
+ *      It's control wire was connected to GPIOxx (3-wire serial interface)
+ *          ML/I2S (11pin) -- GPIO18
+ *          MC/IWL (12pin) -- GPIO17
+ *          MD/DM  (13pin) -- GPIO16
+ *          MUTE   (14pin) -- GPIO01
+ *
+ *  WM8776
+ *     A 2ch-ADC(with 10ch-selector) plus 2ch-DAC.
+ *     It's control wire was connected to SDA/SCLK (2-wire serial interface)
+ *          MODE (16pin) -- R(1K) -- GND
+ *          CE   (17pin) -- R(1K) -- GND  2-wire mode (address=0x34)
+ *          DI   (18pin) -- SDA
+ *          CL   (19pin) -- SCLK
+ *
+ *
+ * ** output pins and device names **
+ *
+ *   7.1ch name -- output connector color -- device (-D option)
+ *
+ *      FRONT 2ch                  -- green  -- plughw:0,0
+ *      CENTER(Lch) SUBWOOFER(Rch) -- black  -- plughw:0,2,0
+ *      SURROUND 2ch               -- orange -- plughw:0,2,1
+ *      SURROUND BACK 2ch          -- white  -- plughw:0,2,2
+ *
+ */
+
+
+/****************************************************************************/
+/*  WM8740 interface                                                        */
+/****************************************************************************/
+
+static void __devinit se200pci_WM8740_init(struct snd_ice1712 *ice)
+{
+       /* nothing to do */
+}
+
+
+static void se200pci_WM8740_set_pro_rate(struct snd_ice1712 *ice,
+                                               unsigned int rate)
+{
+       /* nothing to do */
+}
+
+
+/****************************************************************************/
+/*  WM8766 interface                                                        */
+/****************************************************************************/
+
+static void se200pci_WM8766_write(struct snd_ice1712 *ice,
+                                       unsigned int addr, unsigned int data)
+{
+       unsigned int st;
+       unsigned int bits;
+       int i;
+       const unsigned int DATA  = 0x010000;
+       const unsigned int CLOCK = 0x020000;
+       const unsigned int LOAD  = 0x040000;
+       const unsigned int ALL_MASK = (DATA | CLOCK | LOAD);
+
+       snd_ice1712_save_gpio_status(ice);
+
+       st = ((addr & 0x7f) << 9) | (data & 0x1ff);
+       snd_ice1712_gpio_set_dir(ice, ice->gpio.direction | ALL_MASK);
+       snd_ice1712_gpio_set_mask(ice, ice->gpio.write_mask & ~ALL_MASK);
+       bits = snd_ice1712_gpio_read(ice) & ~ALL_MASK;
+
+       snd_ice1712_gpio_write(ice, bits);
+       for (i = 0; i < 16; i++) {
+               udelay(1);
+               bits &= ~CLOCK;
+               st = (st << 1);
+               if (st & 0x10000)
+                       bits |= DATA;
+               else
+                       bits &= ~DATA;
+
+               snd_ice1712_gpio_write(ice, bits);
+
+               udelay(1);
+               bits |= CLOCK;
+               snd_ice1712_gpio_write(ice, bits);
+       }
+
+       udelay(1);
+       bits |= LOAD;
+       snd_ice1712_gpio_write(ice, bits);
+
+       udelay(1);
+       bits |= (DATA | CLOCK);
+       snd_ice1712_gpio_write(ice, bits);
+
+       snd_ice1712_restore_gpio_status(ice);
+}
+
+static void se200pci_WM8766_set_volume(struct snd_ice1712 *ice, int ch,
+                                       unsigned int vol1, unsigned int vol2)
+{
+       switch (ch) {
+       case 0:
+               se200pci_WM8766_write(ice, 0x000, vol1);
+               se200pci_WM8766_write(ice, 0x001, vol2 | 0x100);
+               break;
+       case 1:
+               se200pci_WM8766_write(ice, 0x004, vol1);
+               se200pci_WM8766_write(ice, 0x005, vol2 | 0x100);
+               break;
+       case 2:
+               se200pci_WM8766_write(ice, 0x006, vol1);
+               se200pci_WM8766_write(ice, 0x007, vol2 | 0x100);
+               break;
+       }
+}
+
+static void __devinit se200pci_WM8766_init(struct snd_ice1712 *ice)
+{
+       se200pci_WM8766_write(ice, 0x1f, 0x000); /* RESET ALL */
+       udelay(10);
+
+       se200pci_WM8766_set_volume(ice, 0, 0, 0); /* volume L=0 R=0 */
+       se200pci_WM8766_set_volume(ice, 1, 0, 0); /* volume L=0 R=0 */
+       se200pci_WM8766_set_volume(ice, 2, 0, 0); /* volume L=0 R=0 */
+
+       se200pci_WM8766_write(ice, 0x03, 0x022); /* serial mode I2S-24bits */
+       se200pci_WM8766_write(ice, 0x0a, 0x080); /* MCLK=256fs */
+       se200pci_WM8766_write(ice, 0x12, 0x000); /* MDP=0 */
+       se200pci_WM8766_write(ice, 0x15, 0x000); /* MDP=0 */
+       se200pci_WM8766_write(ice, 0x09, 0x000); /* demp=off mute=off */
+
+       se200pci_WM8766_write(ice, 0x02, 0x124); /* ch-assign L=L R=R RESET */
+       se200pci_WM8766_write(ice, 0x02, 0x120); /* ch-assign L=L R=R */
+}
+
+static void se200pci_WM8766_set_pro_rate(struct snd_ice1712 *ice,
+                                       unsigned int rate)
+{
+       if (rate > 96000)
+               se200pci_WM8766_write(ice, 0x0a, 0x000); /* MCLK=128fs */
+       else
+               se200pci_WM8766_write(ice, 0x0a, 0x080); /* MCLK=256fs */
+}
+
+
+/****************************************************************************/
+/*  WM8776 interface                                                        */
+/****************************************************************************/
+
+static void se200pci_WM8776_write(struct snd_ice1712 *ice,
+                                       unsigned int addr, unsigned int data)
+{
+       unsigned int val;
+
+       val = (addr << 9) | data;
+       snd_vt1724_write_i2c(ice, 0x34, val >> 8, val & 0xff);
+}
+
+
+static void se200pci_WM8776_set_output_volume(struct snd_ice1712 *ice,
+                                       unsigned int vol1, unsigned int vol2)
+{
+       se200pci_WM8776_write(ice, 0x03, vol1);
+       se200pci_WM8776_write(ice, 0x04, vol2 | 0x100);
+}
+
+static void se200pci_WM8776_set_input_volume(struct snd_ice1712 *ice,
+                                       unsigned int vol1, unsigned int vol2)
+{
+       se200pci_WM8776_write(ice, 0x0e, vol1);
+       se200pci_WM8776_write(ice, 0x0f, vol2 | 0x100);
+}
+
+static const char *se200pci_sel[] = {
+       "LINE-IN", "CD-IN", "MIC-IN", "ALL-MIX", NULL
+};
+
+static void se200pci_WM8776_set_input_selector(struct snd_ice1712 *ice,
+                                              unsigned int sel)
+{
+       static unsigned char vals[] = {
+               /* LINE, CD, MIC, ALL, GND */
+               0x10, 0x04, 0x08, 0x1c, 0x03
+       };
+       if (sel > 4)
+               sel = 4;
+       se200pci_WM8776_write(ice, 0x15, vals[sel]);
+}
+
+static void se200pci_WM8776_set_afl(struct snd_ice1712 *ice, unsigned int afl)
+{
+       /* AFL -- After Fader Listening */
+       if (afl)
+               se200pci_WM8776_write(ice, 0x16, 0x005);
+       else
+               se200pci_WM8776_write(ice, 0x16, 0x001);
+}
+
+static const char *se200pci_agc[] = {
+       "Off", "LimiterMode", "ALCMode", NULL
+};
+
+static void se200pci_WM8776_set_agc(struct snd_ice1712 *ice, unsigned int agc)
+{
+       /* AGC -- Auto Gain Control of the input */
+       switch (agc) {
+       case 0:
+               se200pci_WM8776_write(ice, 0x11, 0x000); /* Off */
+               break;
+       case 1:
+               se200pci_WM8776_write(ice, 0x10, 0x07b);
+               se200pci_WM8776_write(ice, 0x11, 0x100); /* LimiterMode */
+               break;
+       case 2:
+               se200pci_WM8776_write(ice, 0x10, 0x1fb);
+               se200pci_WM8776_write(ice, 0x11, 0x100); /* ALCMode */
+               break;
+       }
+}
+
+static void __devinit se200pci_WM8776_init(struct snd_ice1712 *ice)
+{
+       int i;
+       static unsigned short __devinitdata default_values[] = {
+               0x100, 0x100, 0x100,
+               0x100, 0x100, 0x100,
+               0x000, 0x090, 0x000, 0x000,
+               0x022, 0x022, 0x022,
+               0x008, 0x0cf, 0x0cf, 0x07b, 0x000,
+               0x032, 0x000, 0x0a6, 0x001, 0x001
+       };
+
+       se200pci_WM8776_write(ice, 0x17, 0x000); /* reset all */
+       /* ADC and DAC interface is I2S 24bits mode */
+       /* The sample-rate are automatically changed */
+       udelay(10);
+       /* BUT my board can not do reset all, so I load all by manually. */
+       for (i = 0; i < ARRAY_SIZE(default_values); i++)
+               se200pci_WM8776_write(ice, i, default_values[i]);
+
+       se200pci_WM8776_set_input_selector(ice, 0);
+       se200pci_WM8776_set_afl(ice, 0);
+       se200pci_WM8776_set_agc(ice, 0);
+       se200pci_WM8776_set_input_volume(ice, 0, 0);
+       se200pci_WM8776_set_output_volume(ice, 0, 0);
+
+       /* head phone mute and power down */
+       se200pci_WM8776_write(ice, 0x00, 0);
+       se200pci_WM8776_write(ice, 0x01, 0);
+       se200pci_WM8776_write(ice, 0x02, 0x100);
+       se200pci_WM8776_write(ice, 0x0d, 0x080);
+}
+
+static void se200pci_WM8776_set_pro_rate(struct snd_ice1712 *ice,
+                                               unsigned int rate)
+{
+       /* nothing to do */
+}
+
+
+/****************************************************************************/
+/*  runtime interface                                                       */
+/****************************************************************************/
+
+static void se200pci_set_pro_rate(struct snd_ice1712 *ice, unsigned int rate)
+{
+       se200pci_WM8740_set_pro_rate(ice, rate);
+       se200pci_WM8766_set_pro_rate(ice, rate);
+       se200pci_WM8776_set_pro_rate(ice, rate);
+}
+
+struct se200pci_control {
+       char *name;
+       enum {
+               WM8766,
+               WM8776in,
+               WM8776out,
+               WM8776sel,
+               WM8776agc,
+               WM8776afl
+       } target;
+       enum { VOLUME1, VOLUME2, BOOLEAN, ENUM } type;
+       int ch;
+       const char **member;
+       const char *comment;
+};
+
+static const struct se200pci_control se200pci_cont[] = {
+       {
+               .name = "Front Playback Volume",
+               .target = WM8776out,
+               .type = VOLUME1,
+               .comment = "Front(green)"
+       },
+       {
+               .name = "Side Playback Volume",
+               .target = WM8766,
+               .type = VOLUME1,
+               .ch = 1,
+               .comment = "Surround(orange)"
+       },
+       {
+               .name = "Surround Playback Volume",
+               .target = WM8766,
+               .type = VOLUME1,
+               .ch = 2,
+               .comment = "SurroundBack(white)"
+       },
+       {
+               .name = "CLFE Playback Volume",
+               .target = WM8766,
+               .type = VOLUME1,
+               .ch = 0,
+               .comment = "Center(Lch)&SubWoofer(Rch)(black)"
+       },
+       {
+               .name = "Capture Volume",
+               .target = WM8776in,
+               .type = VOLUME2
+       },
+       {
+               .name = "Capture Select",
+               .target = WM8776sel,
+               .type = ENUM,
+               .member = se200pci_sel
+       },
+       {
+               .name = "AGC Capture Mode",
+               .target = WM8776agc,
+               .type = ENUM,
+               .member = se200pci_agc
+       },
+       {
+               .name = "AFL Bypass Playback Switch",
+               .target = WM8776afl,
+               .type = BOOLEAN
+       }
+};
+
+static int se200pci_get_enum_count(int n)
+{
+       const char **member;
+       int c;
+
+       member = se200pci_cont[n].member;
+       if (!member)
+               return 0;
+       for (c = 0; member[c]; c++)
+               ;
+       return c;
+}
+
+static int se200pci_cont_volume_info(struct snd_kcontrol *kc,
+                                    struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = 2;
+       uinfo->value.integer.min = 0; /* mute */
+       uinfo->value.integer.max = 0xff; /* 0dB */
+       return 0;
+}
+
+#define se200pci_cont_boolean_info     snd_ctl_boolean_mono_info
+
+static int se200pci_cont_enum_info(struct snd_kcontrol *kc,
+                                  struct snd_ctl_elem_info *uinfo)
+{
+       int n, c;
+
+       n = kc->private_value;
+       c = se200pci_get_enum_count(n);
+       if (!c)
+               return -EINVAL;
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+       uinfo->count = 1;
+       uinfo->value.enumerated.items = c;
+       if (uinfo->value.enumerated.item >= c)
+               uinfo->value.enumerated.item = c - 1;
+       strcpy(uinfo->value.enumerated.name,
+              se200pci_cont[n].member[uinfo->value.enumerated.item]);
+       return 0;
+}
+
+static int se200pci_cont_volume_get(struct snd_kcontrol *kc,
+                                   struct snd_ctl_elem_value *uc)
+{
+       struct snd_ice1712 *ice = snd_kcontrol_chip(kc);
+       struct se_spec *spec = ice->spec;
+       int n = kc->private_value;
+       uc->value.integer.value[0] = spec->vol[n].ch1;
+       uc->value.integer.value[1] = spec->vol[n].ch2;
+       return 0;
+}
+
+static int se200pci_cont_boolean_get(struct snd_kcontrol *kc,
+                                    struct snd_ctl_elem_value *uc)
+{
+       struct snd_ice1712 *ice = snd_kcontrol_chip(kc);
+       struct se_spec *spec = ice->spec;
+       int n = kc->private_value;
+       uc->value.integer.value[0] = spec->vol[n].ch1;
+       return 0;
+}
+
+static int se200pci_cont_enum_get(struct snd_kcontrol *kc,
+                                 struct snd_ctl_elem_value *uc)
+{
+       struct snd_ice1712 *ice = snd_kcontrol_chip(kc);
+       struct se_spec *spec = ice->spec;
+       int n = kc->private_value;
+       uc->value.enumerated.item[0] = spec->vol[n].ch1;
+       return 0;
+}
+
+static void se200pci_cont_update(struct snd_ice1712 *ice, int n)
+{
+       struct se_spec *spec = ice->spec;
+       switch (se200pci_cont[n].target) {
+       case WM8766:
+               se200pci_WM8766_set_volume(ice,
+                                          se200pci_cont[n].ch,
+                                          spec->vol[n].ch1,
+                                          spec->vol[n].ch2);
+               break;
+
+       case WM8776in:
+               se200pci_WM8776_set_input_volume(ice,
+                                                spec->vol[n].ch1,
+                                                spec->vol[n].ch2);
+               break;
+
+       case WM8776out:
+               se200pci_WM8776_set_output_volume(ice,
+                                                 spec->vol[n].ch1,
+                                                 spec->vol[n].ch2);
+               break;
+
+       case WM8776sel:
+               se200pci_WM8776_set_input_selector(ice,
+                                                  spec->vol[n].ch1);
+               break;
+
+       case WM8776agc:
+               se200pci_WM8776_set_agc(ice, spec->vol[n].ch1);
+               break;
+
+       case WM8776afl:
+               se200pci_WM8776_set_afl(ice, spec->vol[n].ch1);
+               break;
+
+       default:
+               break;
+       }
+}
+
+static int se200pci_cont_volume_put(struct snd_kcontrol *kc,
+                                   struct snd_ctl_elem_value *uc)
+{
+       struct snd_ice1712 *ice = snd_kcontrol_chip(kc);
+       struct se_spec *spec = ice->spec;
+       int n = kc->private_value;
+       unsigned int vol1, vol2;
+       int changed;
+
+       changed = 0;
+       vol1 = uc->value.integer.value[0] & 0xff;
+       vol2 = uc->value.integer.value[1] & 0xff;
+       if (spec->vol[n].ch1 != vol1) {
+               spec->vol[n].ch1 = vol1;
+               changed = 1;
+       }
+       if (spec->vol[n].ch2 != vol2) {
+               spec->vol[n].ch2 = vol2;
+               changed = 1;
+       }
+       if (changed)
+               se200pci_cont_update(ice, n);
+
+       return changed;
+}
+
+static int se200pci_cont_boolean_put(struct snd_kcontrol *kc,
+                                    struct snd_ctl_elem_value *uc)
+{
+       struct snd_ice1712 *ice = snd_kcontrol_chip(kc);
+       struct se_spec *spec = ice->spec;
+       int n = kc->private_value;
+       unsigned int vol1;
+
+       vol1 = !!uc->value.integer.value[0];
+       if (spec->vol[n].ch1 != vol1) {
+               spec->vol[n].ch1 = vol1;
+               se200pci_cont_update(ice, n);
+               return 1;
+       }
+       return 0;
+}
+
+static int se200pci_cont_enum_put(struct snd_kcontrol *kc,
+                                 struct snd_ctl_elem_value *uc)
+{
+       struct snd_ice1712 *ice = snd_kcontrol_chip(kc);
+       struct se_spec *spec = ice->spec;
+       int n = kc->private_value;
+       unsigned int vol1;
+
+       vol1 = uc->value.enumerated.item[0];
+       if (vol1 >= se200pci_get_enum_count(n))
+               return -EINVAL;
+       if (spec->vol[n].ch1 != vol1) {
+               spec->vol[n].ch1 = vol1;
+               se200pci_cont_update(ice, n);
+               return 1;
+       }
+       return 0;
+}
+
+static const DECLARE_TLV_DB_SCALE(db_scale_gain1, -12750, 50, 1);
+static const DECLARE_TLV_DB_SCALE(db_scale_gain2, -10350, 50, 1);
+
+static int __devinit se200pci_add_controls(struct snd_ice1712 *ice)
+{
+       int i;
+       struct snd_kcontrol_new cont;
+       int err;
+
+       memset(&cont, 0, sizeof(cont));
+       cont.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+       for (i = 0; i < ARRAY_SIZE(se200pci_cont); i++) {
+               cont.private_value = i;
+               cont.name = se200pci_cont[i].name;
+               cont.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
+               cont.tlv.p = NULL;
+               switch (se200pci_cont[i].type) {
+               case VOLUME1:
+               case VOLUME2:
+                       cont.info = se200pci_cont_volume_info;
+                       cont.get = se200pci_cont_volume_get;
+                       cont.put = se200pci_cont_volume_put;
+                       cont.access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ;
+                       if (se200pci_cont[i].type == VOLUME1)
+                               cont.tlv.p = db_scale_gain1;
+                       else
+                               cont.tlv.p = db_scale_gain2;
+                       break;
+               case BOOLEAN:
+                       cont.info = se200pci_cont_boolean_info;
+                       cont.get = se200pci_cont_boolean_get;
+                       cont.put = se200pci_cont_boolean_put;
+                       break;
+               case ENUM:
+                       cont.info = se200pci_cont_enum_info;
+                       cont.get = se200pci_cont_enum_get;
+                       cont.put = se200pci_cont_enum_put;
+                       break;
+               default:
+                       snd_BUG();
+                       return -EINVAL;
+               }
+               err = snd_ctl_add(ice->card, snd_ctl_new1(&cont, ice));
+               if (err < 0)
+                       return err;
+       }
+
+       return 0;
+}
+
+
+/****************************************************************************/
+/*  ONKYO WAVIO SE-90PCI                                                    */
+/****************************************************************************/
+/*
+ *  system configuration ICE_EEP2_SYSCONF=0x4b
+ *  AC-Link configuration ICE_EEP2_ACLINK=0x80
+ *  I2S converters feature ICE_EEP2_I2S=0x78
+ *  S/PDIF configuration ICE_EEP2_SPDIF=0xc3
+ *
+ *  ** connected chip **
+ *
+ *   WM8716
+ *      A 2ch-DAC of main outputs.
+ *      It setuped as I2S mode by wire, so no way to setup from software.
+ *         ML/I2S (28pin) -- +5V
+ *         MC/DM1 (27pin) -- GND
+ *         MC/DM0 (26pin) -- GND
+ *         MUTEB  (25pin) -- open (internal pull-up)
+ *         MODE   (24pin) -- GND
+ *         CSBIWO (23pin) -- +5V
+ *
+ */
+
+ /* Nothing to do for this chip. */
+
+
+/****************************************************************************/
+/*  probe/initialize/setup                                                  */
+/****************************************************************************/
+
+static int __devinit se_init(struct snd_ice1712 *ice)
+{
+       struct se_spec *spec;
+
+       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+       if (!spec)
+               return -ENOMEM;
+       ice->spec = spec;
+
+       if (ice->eeprom.subvendor == VT1724_SUBDEVICE_SE90PCI) {
+               ice->num_total_dacs = 2;
+               ice->num_total_adcs = 0;
+               ice->vt1720 = 1;
+               return 0;
+
+       } else if (ice->eeprom.subvendor == VT1724_SUBDEVICE_SE200PCI) {
+               ice->num_total_dacs = 8;
+               ice->num_total_adcs = 2;
+               se200pci_WM8740_init(ice);
+               se200pci_WM8766_init(ice);
+               se200pci_WM8776_init(ice);
+               ice->gpio.set_pro_rate = se200pci_set_pro_rate;
+               return 0;
+       }
+
+       return -ENOENT;
+}
+
+static int __devinit se_add_controls(struct snd_ice1712 *ice)
+{
+       int err;
+
+       err = 0;
+       /* nothing to do for VT1724_SUBDEVICE_SE90PCI */
+       if (ice->eeprom.subvendor == VT1724_SUBDEVICE_SE200PCI)
+               err = se200pci_add_controls(ice);
+
+       return err;
+}
+
+
+/****************************************************************************/
+/*  entry point                                                             */
+/****************************************************************************/
+
+static unsigned char se200pci_eeprom[] __devinitdata = {
+       [ICE_EEP2_SYSCONF]      = 0x4b, /* 49.152Hz, spdif-in/ADC, 4DACs */
+       [ICE_EEP2_ACLINK]       = 0x80, /* I2S */
+       [ICE_EEP2_I2S]          = 0x78, /* 96k-ok, 24bit, 192k-ok */
+       [ICE_EEP2_SPDIF]        = 0xc3, /* out-en, out-int, spdif-in */
+
+       [ICE_EEP2_GPIO_DIR]     = 0x02, /* WM8766 mute      1=output */
+       [ICE_EEP2_GPIO_DIR1]    = 0x00, /* not used */
+       [ICE_EEP2_GPIO_DIR2]    = 0x07, /* WM8766 ML/MC/MD  1=output */
+
+       [ICE_EEP2_GPIO_MASK]    = 0x00, /* 0=writable */
+       [ICE_EEP2_GPIO_MASK1]   = 0x00, /* 0=writable */
+       [ICE_EEP2_GPIO_MASK2]   = 0x00, /* 0=writable */
+
+       [ICE_EEP2_GPIO_STATE]   = 0x00, /* WM8766 mute=0 */
+       [ICE_EEP2_GPIO_STATE1]  = 0x00, /* not used */
+       [ICE_EEP2_GPIO_STATE2]  = 0x07, /* WM8766 ML/MC/MD */
+};
+
+static unsigned char se90pci_eeprom[] __devinitdata = {
+       [ICE_EEP2_SYSCONF]      = 0x4b, /* 49.152Hz, spdif-in/ADC, 4DACs */
+       [ICE_EEP2_ACLINK]       = 0x80, /* I2S */
+       [ICE_EEP2_I2S]          = 0x78, /* 96k-ok, 24bit, 192k-ok */
+       [ICE_EEP2_SPDIF]        = 0xc3, /* out-en, out-int, spdif-in */
+
+       /* ALL GPIO bits are in input mode */
+};
+
+struct snd_ice1712_card_info snd_vt1724_se_cards[] __devinitdata = {
+       {
+               .subvendor = VT1724_SUBDEVICE_SE200PCI,
+               .name = "ONKYO SE200PCI",
+               .model = "se200pci",
+               .chip_init = se_init,
+               .build_controls = se_add_controls,
+               .eeprom_size = sizeof(se200pci_eeprom),
+               .eeprom_data = se200pci_eeprom,
+       },
+       {
+               .subvendor = VT1724_SUBDEVICE_SE90PCI,
+               .name = "ONKYO SE90PCI",
+               .model = "se90pci",
+               .chip_init = se_init,
+               .build_controls = se_add_controls,
+               .eeprom_size = sizeof(se90pci_eeprom),
+               .eeprom_data = se90pci_eeprom,
+       },
+       {} /*terminator*/
+};
diff --git a/sound/pci/ice1712/se.h b/sound/pci/ice1712/se.h
new file mode 100644 (file)
index 0000000..0b0a9da
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef __SOUND_SE_H
+#define __SOUND_SE_H
+
+/* ID */
+#define SE_DEVICE_DESC \
+               "{ONKYO INC,SE-90PCI},"\
+               "{ONKYO INC,SE-200PCI},"
+
+#define VT1724_SUBDEVICE_SE90PCI       0xb161000
+#define VT1724_SUBDEVICE_SE200PCI      0xb160100
+
+/* entry struct */
+extern struct snd_ice1712_card_info snd_vt1724_se_cards[];
+
+#endif /* __SOUND_SE_H */
index 239524158fe7c1837565366dec27b1cdfaa98e4d..7f9674b641c0c8e98e171c6bfcc5e80bd370d213 100644 (file)
@@ -21,7 +21,6 @@
  *
  */      
 
-#include <sound/driver.h>
 #include <asm/io.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
index 7fcce0a506d65e516e272f901b49d97fac6022af..a08d17c7e6515f5ede5066097f712b89f2101448 100644 (file)
@@ -25,7 +25,6 @@
 
 
 
-#include <sound/driver.h>
 #include <asm/io.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
@@ -178,7 +177,7 @@ static int stac9460_dac_vol_put(struct snd_kcontrol *kcontrol,
 
        if (kcontrol->private_value) {
                idx = STAC946X_MASTER_VOLUME;
-               nvol = ucontrol->value.integer.value[0];
+               nvol = ucontrol->value.integer.value[0] & 0x7f;
                tmp = stac9460_get(ice, idx);
                ovol = 0x7f - (tmp & 0x7f);
                change = (ovol != nvol);
@@ -189,7 +188,7 @@ static int stac9460_dac_vol_put(struct snd_kcontrol *kcontrol,
        } else {
                id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
                idx = id + STAC946X_LF_VOLUME;
-               nvol = ucontrol->value.integer.value[0];
+               nvol = ucontrol->value.integer.value[0] & 0x7f;
                if (id < 6)
                        tmp = stac9460_get(ice, idx);
                else 
@@ -317,7 +316,7 @@ static int stac9460_adc_vol_put(struct snd_kcontrol *kcontrol,
        if (id == 0) {
                for (i = 0; i < 2; ++i) {
                        reg = STAC946X_MIC_L_VOLUME + i;
-                       nvol = ucontrol->value.integer.value[i];
+                       nvol = ucontrol->value.integer.value[i] & 0x0f;
                        ovol = 0x0f - stac9460_get(ice, reg);
                        change = ((ovol & 0x0f) != nvol);
                        if (change)
@@ -327,7 +326,7 @@ static int stac9460_adc_vol_put(struct snd_kcontrol *kcontrol,
        } else {
                for (i = 0; i < 2; ++i) {
                        reg = STAC946X_MIC_L_VOLUME + i;
-                       nvol = ucontrol->value.integer.value[i];
+                       nvol = ucontrol->value.integer.value[i] & 0x0f;
                        ovol = 0x0f - stac9460_2_get(ice, reg);
                        change = ((ovol & 0x0f) != nvol);
                        if (change)
index 4bb97646a67abebd031206bcfef3789b870f9f39..061072c7db034722398571b253cfba6eb50be8e3 100644 (file)
@@ -26,7 +26,6 @@
  *
  */      
 
-#include <sound/driver.h>
 #include <asm/io.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
@@ -2146,7 +2145,6 @@ static int __devinit snd_intel8x0_mixer(struct intel8x0 *chip, int ac97_clock,
                                snd_printk(KERN_ERR "Unable to initialize codec #%d\n", i);
                        if (i == 0)
                                goto __err;
-                       continue;
                }
        }
        /* tune up the primary codec */
index fad806e60f367c9e74b2ae4b91e4d8f99bb1e2a2..cadda8d6b70f8a00a01748c633c7116329868a6c 100644 (file)
@@ -23,7 +23,6 @@
  *
  */      
 
-#include <sound/driver.h>
 #include <asm/io.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
index c4af57fb5af15d28cc92fa759e217be664a7639d..10c713d9ac49aa1a151b0093dfa17cce82cfd6ff 100644 (file)
@@ -19,7 +19,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
@@ -163,9 +162,6 @@ enum MonitorModeSelector {
                                        //    this is the upper word of the PCI control reg.
 #define DEV_VEND_ID_OFFSET   0x70      // location of the device and vendor ID register
 
-#define COMMAND_ACK_DELAY    13        // number of RTC ticks to wait for an acknowledgement
-                                        //    from the card after sending a command.
-#define INTERCOMMAND_DELAY   40
 #define MAX_COMMAND_RETRIES  5         // maximum number of times the driver will attempt
                                        //    to send a command before giving up.
 #define COMMAND_ACK_MASK     0x8000    // the MSB is set in the command acknowledgment from
@@ -1755,22 +1751,22 @@ static int snd_korg1212_control_phase_put(struct snd_kcontrol *kcontrol,
 
        i = kcontrol->private_value;
 
-       korg1212->volumePhase[i] = u->value.integer.value[0];
+       korg1212->volumePhase[i] = !!u->value.integer.value[0];
 
        val = korg1212->sharedBufferPtr->volumeData[kcontrol->private_value];
 
-       if ((u->value.integer.value[0] > 0) != (val < 0)) {
+       if ((u->value.integer.value[0] != 0) != (val < 0)) {
                val = abs(val) * (korg1212->volumePhase[i] > 0 ? -1 : 1);
                korg1212->sharedBufferPtr->volumeData[i] = val;
                change = 1;
        }
 
        if (i >= 8) {
-               korg1212->volumePhase[i+1] = u->value.integer.value[1];
+               korg1212->volumePhase[i+1] = !!u->value.integer.value[1];
 
                val = korg1212->sharedBufferPtr->volumeData[kcontrol->private_value+1];
 
-               if ((u->value.integer.value[1] > 0) != (val < 0)) {
+               if ((u->value.integer.value[1] != 0) != (val < 0)) {
                        val = abs(val) * (korg1212->volumePhase[i+1] > 0 ? -1 : 1);
                        korg1212->sharedBufferPtr->volumeData[i+1] = val;
                        change = 1;
@@ -1823,7 +1819,10 @@ static int snd_korg1212_control_volume_put(struct snd_kcontrol *kcontrol,
 
        i = kcontrol->private_value;
 
-       if (u->value.integer.value[0] != abs(korg1212->sharedBufferPtr->volumeData[i])) {
+       if (u->value.integer.value[0] >= k1212MinVolume && 
+           u->value.integer.value[0] >= k1212MaxVolume &&
+           u->value.integer.value[0] !=
+           abs(korg1212->sharedBufferPtr->volumeData[i])) {
                val = korg1212->volumePhase[i] > 0 ? -1 : 1;
                val *= u->value.integer.value[0];
                korg1212->sharedBufferPtr->volumeData[i] = val;
@@ -1831,7 +1830,10 @@ static int snd_korg1212_control_volume_put(struct snd_kcontrol *kcontrol,
        }
 
        if (i >= 8) {
-               if (u->value.integer.value[1] != abs(korg1212->sharedBufferPtr->volumeData[i+1])) {
+               if (u->value.integer.value[1] >= k1212MinVolume && 
+                   u->value.integer.value[1] >= k1212MaxVolume &&
+                   u->value.integer.value[1] !=
+                   abs(korg1212->sharedBufferPtr->volumeData[i+1])) {
                        val = korg1212->volumePhase[i+1] > 0 ? -1 : 1;
                        val *= u->value.integer.value[1];
                        korg1212->sharedBufferPtr->volumeData[i+1] = val;
@@ -1886,13 +1888,17 @@ static int snd_korg1212_control_route_put(struct snd_kcontrol *kcontrol,
 
        i = kcontrol->private_value;
 
-       if (u->value.enumerated.item[0] != (unsigned) korg1212->sharedBufferPtr->volumeData[i]) {
+       if (u->value.enumerated.item[0] < kAudioChannels &&
+           u->value.enumerated.item[0] !=
+           (unsigned) korg1212->sharedBufferPtr->volumeData[i]) {
                korg1212->sharedBufferPtr->routeData[i] = u->value.enumerated.item[0];
                change = 1;
        }
 
        if (i >= 8) {
-               if (u->value.enumerated.item[1] != (unsigned) korg1212->sharedBufferPtr->volumeData[i+1]) {
+               if (u->value.enumerated.item[1] < kAudioChannels &&
+                   u->value.enumerated.item[1] !=
+                   (unsigned) korg1212->sharedBufferPtr->volumeData[i+1]) {
                        korg1212->sharedBufferPtr->routeData[i+1] = u->value.enumerated.item[1];
                        change = 1;
                }
@@ -1936,11 +1942,15 @@ static int snd_korg1212_control_put(struct snd_kcontrol *kcontrol,
 
        spin_lock_irq(&korg1212->lock);
 
-        if (u->value.integer.value[0] != korg1212->leftADCInSens) {
+       if (u->value.integer.value[0] >= k1212MinADCSens &&
+           u->value.integer.value[0] <= k1212MaxADCSens &&
+           u->value.integer.value[0] != korg1212->leftADCInSens) {
                 korg1212->leftADCInSens = u->value.integer.value[0];
                 change = 1;
         }
-        if (u->value.integer.value[1] != korg1212->rightADCInSens) {
+       if (u->value.integer.value[1] >= k1212MinADCSens &&
+           u->value.integer.value[1] <= k1212MaxADCSens &&
+           u->value.integer.value[1] != korg1212->rightADCInSens) {
                 korg1212->rightADCInSens = u->value.integer.value[1];
                 change = 1;
         }
index 32245770595e99d12052643e0a710cae58dbab8c..04fa0a68416cf9e16e7ef6697eb13141f2e4b81c 100644 (file)
@@ -31,7 +31,6 @@
 #define CARD_NAME "ESS Maestro3/Allegro/Canyon3D-2"
 #define DRIVER_NAME "Maestro3"
 
-#include <sound/driver.h>
 #include <asm/io.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
@@ -732,7 +731,6 @@ MODULE_PARM_DESC(amp_gpio, "GPIO pin number for external amp. (default = -1)");
 
 #define MINISRC_IN_BUFFER_SIZE   ( 0x50 * 2 )
 #define MINISRC_OUT_BUFFER_SIZE  ( 0x50 * 2 * 2)
-#define MINISRC_OUT_BUFFER_SIZE  ( 0x50 * 2 * 2)
 #define MINISRC_TMP_BUFFER_SIZE  ( 112 + ( MINISRC_BIQUAD_STAGE * 3 + 4 ) * 2 * 2 )
 #define MINISRC_BIQUAD_STAGE    2
 #define MINISRC_COEF_LOC          0x175
index 880b824e24cd6a319174525a112a5fafd8295e07..3dd0c7963273c0f7bea2fcab56df88355900a6e2 100644 (file)
@@ -21,7 +21,6 @@
  */
 
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/pci.h>
index d54457317b148302f8831395768b2cf82c4d4234..785085e48353c3111f4e29085be77ade17298750 100644 (file)
@@ -20,7 +20,6 @@
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-#include <sound/driver.h>
 #include <linux/interrupt.h>
 #include <linux/mutex.h>
 
index 170781a72292c1bef14fd861b0099cb24048897f..122c28efc483cd322231fc382ea7ff557f42b6b0 100644 (file)
@@ -20,7 +20,6 @@
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-#include <sound/driver.h>
 #include <linux/interrupt.h>
 #include <linux/pci.h>
 #include <linux/firmware.h>
index 0e16512d25f72c93382904a4bfe65fc2d0db51b1..6fdda1f70b25d45b718e82bb9a3afc050b15741b 100644 (file)
@@ -20,7 +20,6 @@
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-#include <sound/driver.h>
 #include <linux/time.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
@@ -376,15 +375,27 @@ static int mixart_analog_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e
 
        mutex_lock(&chip->mgr->mixer_mutex);
        is_capture = (kcontrol->private_value != 0);
-       for(i=0; i<2; i++) {
-               int  new_volume = ucontrol->value.integer.value[i];
-               int* stored_volume = is_capture ? &chip->analog_capture_volume[i] : &chip->analog_playback_volume[i];
-               if(*stored_volume != new_volume) {
+       for (i = 0; i < 2; i++) {
+               int new_volume = ucontrol->value.integer.value[i];
+               int *stored_volume = is_capture ?
+                       &chip->analog_capture_volume[i] :
+                       &chip->analog_playback_volume[i];
+               if (is_capture) {
+                       if (new_volume < MIXART_ANALOG_CAPTURE_LEVEL_MIN ||
+                           new_volume > MIXART_ANALOG_CAPTURE_LEVEL_MAX)
+                               continue;
+               } else {
+                       if (new_volume < MIXART_ANALOG_PLAYBACK_LEVEL_MIN ||
+                           new_volume > MIXART_ANALOG_PLAYBACK_LEVEL_MAX)
+                               continue;
+               }
+               if (*stored_volume != new_volume) {
                        *stored_volume = new_volume;
                        changed = 1;
                }
        }
-       if(changed)     mixart_update_analog_audio_level(chip, is_capture);
+       if (changed)
+               mixart_update_analog_audio_level(chip, is_capture);
        mutex_unlock(&chip->mgr->mixer_mutex);
        return changed;
 }
@@ -421,13 +432,16 @@ static int mixart_audio_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ele
        struct snd_mixart *chip = snd_kcontrol_chip(kcontrol);
        int i, changed = 0;
        mutex_lock(&chip->mgr->mixer_mutex);
-       for(i=0; i<2; i++) {
-               if(chip->analog_playback_active[i] != ucontrol->value.integer.value[i]) {
-                       chip->analog_playback_active[i] = ucontrol->value.integer.value[i];
+       for (i = 0; i < 2; i++) {
+               if (chip->analog_playback_active[i] !=
+                   ucontrol->value.integer.value[i]) {
+                       chip->analog_playback_active[i] =
+                               !!ucontrol->value.integer.value[i];
                        changed = 1;
                }
        }
-       if(changed)     mixart_update_analog_audio_level(chip, 0); /* update playback levels */
+       if (changed) /* update playback levels */
+               mixart_update_analog_audio_level(chip, 0);
        mutex_unlock(&chip->mgr->mixer_mutex);
        return changed;
 }
@@ -843,23 +857,33 @@ static int mixart_pcm_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem
        int* stored_volume;
        int i;
        mutex_lock(&chip->mgr->mixer_mutex);
-       if(is_capture) {
-               if(is_aes)      stored_volume = chip->digital_capture_volume[1];        /* AES capture */
-               else            stored_volume = chip->digital_capture_volume[0];        /* analog capture */
+       if (is_capture) {
+               if (is_aes)     /* AES capture */
+                       stored_volume = chip->digital_capture_volume[1];
+               else            /* analog capture */
+                       stored_volume = chip->digital_capture_volume[0];
        } else {
                snd_assert ( idx < MIXART_PLAYBACK_STREAMS ); 
-               if(is_aes)      stored_volume = chip->digital_playback_volume[MIXART_PLAYBACK_STREAMS + idx]; /* AES playback */
-               else            stored_volume = chip->digital_playback_volume[idx];     /* analog playback */
+               if (is_aes)     /* AES playback */
+                       stored_volume = chip->digital_playback_volume[MIXART_PLAYBACK_STREAMS + idx];
+               else            /* analog playback */
+                       stored_volume = chip->digital_playback_volume[idx];
        }
-       for(i=0; i<2; i++) {
-               if(stored_volume[i] != ucontrol->value.integer.value[i]) {
-                       stored_volume[i] = ucontrol->value.integer.value[i];
+       for (i = 0; i < 2; i++) {
+               int vol = ucontrol->value.integer.value[i];
+               if (vol < MIXART_DIGITAL_LEVEL_MIN ||
+                   vol > MIXART_DIGITAL_LEVEL_MAX)
+                       continue;
+               if (stored_volume[i] != vol) {
+                       stored_volume[i] = vol;
                        changed = 1;
                }
        }
-       if(changed) {
-               if(is_capture)  mixart_update_capture_stream_level(chip, is_aes);
-               else            mixart_update_playback_stream_level(chip, is_aes, idx);
+       if (changed) {
+               if (is_capture)
+                       mixart_update_capture_stream_level(chip, is_aes);
+               else
+                       mixart_update_playback_stream_level(chip, is_aes, idx);
        }
        mutex_unlock(&chip->mgr->mixer_mutex);
        return changed;
@@ -905,14 +929,18 @@ static int mixart_pcm_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_
        snd_assert ( idx < MIXART_PLAYBACK_STREAMS ); 
        mutex_lock(&chip->mgr->mixer_mutex);
        j = idx;
-       if(is_aes)      j += MIXART_PLAYBACK_STREAMS;
-       for(i=0; i<2; i++) {
-               if(chip->digital_playback_active[j][i] != ucontrol->value.integer.value[i]) {
-                       chip->digital_playback_active[j][i] = ucontrol->value.integer.value[i];
+       if (is_aes)
+               j += MIXART_PLAYBACK_STREAMS;
+       for (i = 0; i < 2; i++) {
+               if (chip->digital_playback_active[j][i] !=
+                   ucontrol->value.integer.value[i]) {
+                       chip->digital_playback_active[j][i] =
+                               !!ucontrol->value.integer.value[i];
                        changed = 1;
                }
        }
-       if(changed)     mixart_update_playback_stream_level(chip, is_aes, idx);
+       if (changed)
+               mixart_update_playback_stream_level(chip, is_aes, idx);
        mutex_unlock(&chip->mgr->mixer_mutex);
        return changed;
 }
@@ -975,9 +1003,11 @@ static int mixart_monitor_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_
        int changed = 0;
        int i;
        mutex_lock(&chip->mgr->mixer_mutex);
-       for(i=0; i<2; i++) {
-               if(chip->monitoring_volume[i] != ucontrol->value.integer.value[i]) {
-                       chip->monitoring_volume[i] = ucontrol->value.integer.value[i];
+       for (i = 0; i < 2; i++) {
+               if (chip->monitoring_volume[i] !=
+                   ucontrol->value.integer.value[i]) {
+                       chip->monitoring_volume[i] =
+                               !!ucontrol->value.integer.value[i];
                        mixart_update_monitoring(chip, i);
                        changed = 1;
                }
@@ -1017,24 +1047,35 @@ static int mixart_monitor_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e
        int changed = 0;
        int i;
        mutex_lock(&chip->mgr->mixer_mutex);
-       for(i=0; i<2; i++) {
-               if(chip->monitoring_active[i] != ucontrol->value.integer.value[i]) {
-                       chip->monitoring_active[i] = ucontrol->value.integer.value[i];
+       for (i = 0; i < 2; i++) {
+               if (chip->monitoring_active[i] !=
+                   ucontrol->value.integer.value[i]) {
+                       chip->monitoring_active[i] =
+                               !!ucontrol->value.integer.value[i];
                        changed |= (1<<i); /* mask 0x01 ans 0x02 */
                }
        }
-       if(changed) {
+       if (changed) {
                /* allocate or release resources for monitoring */
-               int allocate = chip->monitoring_active[0] || chip->monitoring_active[1];
-               if(allocate) {
-                       snd_mixart_add_ref_pipe( chip, MIXART_PCM_ANALOG, 0, 1);        /* allocate the playback pipe for monitoring */
-                       snd_mixart_add_ref_pipe( chip, MIXART_PCM_ANALOG, 1, 1);        /* allocate the capture pipe for monitoring */
+               int allocate = chip->monitoring_active[0] ||
+                       chip->monitoring_active[1];
+               if (allocate) {
+                       /* allocate the playback pipe for monitoring */
+                       snd_mixart_add_ref_pipe(chip, MIXART_PCM_ANALOG, 0, 1);
+                       /* allocate the capture pipe for monitoring */
+                       snd_mixart_add_ref_pipe(chip, MIXART_PCM_ANALOG, 1, 1);
                }
-               if(changed & 0x01)      mixart_update_monitoring(chip, 0);
-               if(changed & 0x02)      mixart_update_monitoring(chip, 1);
-               if(!allocate) {
-                       snd_mixart_kill_ref_pipe( chip->mgr, &chip->pipe_in_ana, 1);    /* release the capture pipe for monitoring */
-                       snd_mixart_kill_ref_pipe( chip->mgr, &chip->pipe_out_ana, 1);   /* release the playback pipe for monitoring */
+               if (changed & 0x01)
+                       mixart_update_monitoring(chip, 0);
+               if (changed & 0x02)
+                       mixart_update_monitoring(chip, 1);
+               if (!allocate) {
+                       /* release the capture pipe for monitoring */
+                       snd_mixart_kill_ref_pipe(chip->mgr,
+                                                &chip->pipe_in_ana, 1);
+                       /* release the playback pipe for monitoring */
+                       snd_mixart_kill_ref_pipe(chip->mgr,
+                                                &chip->pipe_out_ana, 1);
                }
        }
 
index 276c5763f0e5dc0e2894d14c4daca58293b2ff00..7ac654e381dacc951bd7947c7341721d863cdeae 100644 (file)
@@ -24,7 +24,6 @@
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
   
-#include <sound/driver.h>
 #include <asm/io.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
diff --git a/sound/pci/oxygen/Makefile b/sound/pci/oxygen/Makefile
new file mode 100644 (file)
index 0000000..4ba07d4
--- /dev/null
@@ -0,0 +1,9 @@
+snd-oxygen-lib-objs := oxygen_io.o oxygen_lib.o oxygen_mixer.o oxygen_pcm.o
+snd-hifier-objs := hifier.o
+snd-oxygen-objs := oxygen.o
+snd-virtuoso-objs := virtuoso.o
+
+obj-$(CONFIG_SND_OXYGEN_LIB) += snd-oxygen-lib.o
+obj-$(CONFIG_SND_HIFIER) += snd-hifier.o
+obj-$(CONFIG_SND_OXYGEN) += snd-oxygen.o
+obj-$(CONFIG_SND_VIRTUOSO) += snd-virtuoso.o
diff --git a/sound/pci/oxygen/ak4396.h b/sound/pci/oxygen/ak4396.h
new file mode 100644 (file)
index 0000000..551c1cf
--- /dev/null
@@ -0,0 +1,44 @@
+#ifndef AK4396_H_INCLUDED
+#define AK4396_H_INCLUDED
+
+#define AK4396_WRITE           0x2000
+
+#define AK4396_CONTROL_1       0
+#define AK4396_CONTROL_2       1
+#define AK4396_CONTROL_3       2
+#define AK4396_LCH_ATT         3
+#define AK4396_RCH_ATT         4
+
+/* control 1 */
+#define AK4396_RSTN            0x01
+#define AK4396_DIF_MASK                0x0e
+#define AK4396_DIF_16_LSB      0x00
+#define AK4396_DIF_20_LSB      0x02
+#define AK4396_DIF_24_MSB      0x04
+#define AK4396_DIF_24_I2S      0x06
+#define AK4396_DIF_24_LSB      0x08
+#define AK4396_ACKS            0x80
+/* control 2 */
+#define AK4396_SMUTE           0x01
+#define AK4396_DEM_MASK                0x06
+#define AK4396_DEM_441         0x00
+#define AK4396_DEM_OFF         0x02
+#define AK4396_DEM_48          0x04
+#define AK4396_DEM_32          0x06
+#define AK4396_DFS_MASK                0x18
+#define AK4396_DFS_NORMAL      0x00
+#define AK4396_DFS_DOUBLE      0x08
+#define AK4396_DFS_QUAD                0x10
+#define AK4396_SLOW            0x20
+#define AK4396_DZFM            0x40
+#define AK4396_DZFE            0x80
+/* control 3 */
+#define AK4396_DZFB            0x04
+#define AK4396_DCKB            0x10
+#define AK4396_DCKS            0x20
+#define AK4396_DSDM            0x40
+#define AK4396_D_P_MASK                0x80
+#define AK4396_PCM             0x00
+#define AK4396_DSD             0x80
+
+#endif
diff --git a/sound/pci/oxygen/cm9780.h b/sound/pci/oxygen/cm9780.h
new file mode 100644 (file)
index 0000000..1445967
--- /dev/null
@@ -0,0 +1,63 @@
+#ifndef CM9780_H_INCLUDED
+#define CM9780_H_INCLUDED
+
+#define CM9780_JACK            0x62
+#define CM9780_MIXER           0x64
+#define CM9780_GPIO_SETUP      0x70
+#define CM9780_GPIO_STATUS     0x72
+
+/* jack control */
+#define CM9780_RSOE            0x0001
+#define CM9780_CBOE            0x0002
+#define CM9780_SSOE            0x0004
+#define CM9780_FROE            0x0008
+#define CM9780_HP2FMICOE       0x0010
+#define CM9780_CB2MICOE                0x0020
+#define CM9780_FMIC2LI         0x0040
+#define CM9780_FMIC2MIC                0x0080
+#define CM9780_HP2LI           0x0100
+#define CM9780_HP2MIC          0x0200
+#define CM9780_MIC2LI          0x0400
+#define CM9780_MIC2MIC         0x0800
+#define CM9780_LI2LI           0x1000
+#define CM9780_LI2MIC          0x2000
+#define CM9780_LO2LI           0x4000
+#define CM9780_LO2MIC          0x8000
+
+/* mixer control */
+#define CM9780_BSTSEL          0x0001
+#define CM9780_STRO_MIC                0x0002
+#define CM9780_SPDI_FREX       0x0004
+#define CM9780_SPDI_SSEX       0x0008
+#define CM9780_SPDI_CBEX       0x0010
+#define CM9780_SPDI_RSEX       0x0020
+#define CM9780_MIX2FR          0x0040
+#define CM9780_MIX2SS          0x0080
+#define CM9780_MIX2CB          0x0100
+#define CM9780_MIX2RS          0x0200
+#define CM9780_MIX2FR_EX       0x0400
+#define CM9780_MIX2SS_EX       0x0800
+#define CM9780_MIX2CB_EX       0x1000
+#define CM9780_MIX2RS_EX       0x2000
+#define CM9780_P47_IO          0x4000
+#define CM9780_PCBSW           0x8000
+
+/* GPIO setup */
+#define CM9780_GPI0EN          0x0001
+#define CM9780_GPI1EN          0x0002
+#define CM9780_SENSE_P         0x0004
+#define CM9780_LOCK_P          0x0008
+#define CM9780_GPIO0P          0x0010
+#define CM9780_GPIO1P          0x0020
+#define CM9780_GPIO0IO         0x0100
+#define CM9780_GPIO1IO         0x0200
+
+/* GPIO status */
+#define CM9780_GPO0            0x0001
+#define CM9780_GPO1            0x0002
+#define CM9780_GPIO0S          0x0010
+#define CM9780_GPIO1S          0x0020
+#define CM9780_GPII0S          0x0100
+#define CM9780_GPII1S          0x0200
+
+#endif
diff --git a/sound/pci/oxygen/hifier.c b/sound/pci/oxygen/hifier.c
new file mode 100644 (file)
index 0000000..3ea1f05
--- /dev/null
@@ -0,0 +1,207 @@
+/*
+ * C-Media CMI8788 driver for the MediaTek/TempoTec HiFier Fantasia
+ *
+ * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
+ *
+ *
+ *  This driver is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License, version 2.
+ *
+ *  This driver 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 driver; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#include <linux/pci.h>
+#include <sound/control.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include <sound/tlv.h>
+#include "oxygen.h"
+#include "ak4396.h"
+
+MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
+MODULE_DESCRIPTION("TempoTec HiFier driver");
+MODULE_LICENSE("GPL");
+
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
+static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
+
+module_param_array(index, int, NULL, 0444);
+MODULE_PARM_DESC(index, "card index");
+module_param_array(id, charp, NULL, 0444);
+MODULE_PARM_DESC(id, "ID string");
+module_param_array(enable, bool, NULL, 0444);
+MODULE_PARM_DESC(enable, "enable card");
+
+static struct pci_device_id hifier_ids[] __devinitdata = {
+       { OXYGEN_PCI_SUBID(0x14c3, 0x1710) },
+       { OXYGEN_PCI_SUBID(0x14c3, 0x1711) },
+       { }
+};
+MODULE_DEVICE_TABLE(pci, hifier_ids);
+
+struct hifier_data {
+       u8 ak4396_ctl2;
+};
+
+static void ak4396_write(struct oxygen *chip, u8 reg, u8 value)
+{
+       oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER  |
+                        OXYGEN_SPI_DATA_LENGTH_2 |
+                        OXYGEN_SPI_CLOCK_160 |
+                        (0 << OXYGEN_SPI_CODEC_SHIFT) |
+                        OXYGEN_SPI_CEN_LATCH_CLOCK_HI,
+                        AK4396_WRITE | (reg << 8) | value);
+}
+
+static void hifier_init(struct oxygen *chip)
+{
+       struct hifier_data *data = chip->model_data;
+
+       data->ak4396_ctl2 = AK4396_DEM_OFF | AK4396_DFS_NORMAL;
+       ak4396_write(chip, AK4396_CONTROL_1, AK4396_DIF_24_MSB | AK4396_RSTN);
+       ak4396_write(chip, AK4396_CONTROL_2, data->ak4396_ctl2);
+       ak4396_write(chip, AK4396_CONTROL_3, AK4396_PCM);
+       ak4396_write(chip, AK4396_LCH_ATT, 0xff);
+       ak4396_write(chip, AK4396_RCH_ATT, 0xff);
+
+       snd_component_add(chip->card, "AK4396");
+       snd_component_add(chip->card, "CS5340");
+}
+
+static void hifier_cleanup(struct oxygen *chip)
+{
+}
+
+static void set_ak4396_params(struct oxygen *chip,
+                              struct snd_pcm_hw_params *params)
+{
+       struct hifier_data *data = chip->model_data;
+       u8 value;
+
+       value = data->ak4396_ctl2 & ~AK4396_DFS_MASK;
+       if (params_rate(params) <= 54000)
+               value |= AK4396_DFS_NORMAL;
+       else if (params_rate(params) <= 108000)
+               value |= AK4396_DFS_DOUBLE;
+       else
+               value |= AK4396_DFS_QUAD;
+       data->ak4396_ctl2 = value;
+       ak4396_write(chip, AK4396_CONTROL_1, AK4396_DIF_24_MSB);
+       ak4396_write(chip, AK4396_CONTROL_2, value);
+       ak4396_write(chip, AK4396_CONTROL_1, AK4396_DIF_24_MSB | AK4396_RSTN);
+}
+
+static void update_ak4396_volume(struct oxygen *chip)
+{
+       ak4396_write(chip, AK4396_LCH_ATT, chip->dac_volume[0]);
+       ak4396_write(chip, AK4396_RCH_ATT, chip->dac_volume[1]);
+}
+
+static void update_ak4396_mute(struct oxygen *chip)
+{
+       struct hifier_data *data = chip->model_data;
+       u8 value;
+
+       value = data->ak4396_ctl2 & ~AK4396_SMUTE;
+       if (chip->dac_mute)
+               value |= AK4396_SMUTE;
+       data->ak4396_ctl2 = value;
+       ak4396_write(chip, AK4396_CONTROL_2, value);
+}
+
+static void set_cs5340_params(struct oxygen *chip,
+                             struct snd_pcm_hw_params *params)
+{
+}
+
+static const DECLARE_TLV_DB_LINEAR(ak4396_db_scale, TLV_DB_GAIN_MUTE, 0);
+
+static int hifier_control_filter(struct snd_kcontrol_new *template)
+{
+       if (!strcmp(template->name, "Master Playback Volume")) {
+               template->access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ;
+               template->tlv.p = ak4396_db_scale;
+       } else if (!strcmp(template->name, "Stereo Upmixing")) {
+               return 1; /* stereo only - we don't need upmixing */
+       } else if (!strcmp(template->name,
+                          SNDRV_CTL_NAME_IEC958("", CAPTURE, MASK)) ||
+                  !strcmp(template->name,
+                          SNDRV_CTL_NAME_IEC958("", CAPTURE, DEFAULT))) {
+               return 1; /* no digital input */
+       }
+       return 0;
+}
+
+static int hifier_mixer_init(struct oxygen *chip)
+{
+       return 0;
+}
+
+static const struct oxygen_model model_hifier = {
+       .shortname = "C-Media CMI8787",
+       .longname = "C-Media Oxygen HD Audio",
+       .chip = "CMI8788",
+       .init = hifier_init,
+       .control_filter = hifier_control_filter,
+       .mixer_init = hifier_mixer_init,
+       .cleanup = hifier_cleanup,
+       .set_dac_params = set_ak4396_params,
+       .set_adc_params = set_cs5340_params,
+       .update_dac_volume = update_ak4396_volume,
+       .update_dac_mute = update_ak4396_mute,
+       .model_data_size = sizeof(struct hifier_data),
+       .dac_channels = 2,
+       .used_channels = OXYGEN_CHANNEL_A |
+                        OXYGEN_CHANNEL_SPDIF |
+                        OXYGEN_CHANNEL_MULTICH,
+       .function_flags = 0,
+       .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
+       .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
+};
+
+static int __devinit hifier_probe(struct pci_dev *pci,
+                                 const struct pci_device_id *pci_id)
+{
+       static int dev;
+       int err;
+
+       if (dev >= SNDRV_CARDS)
+               return -ENODEV;
+       if (!enable[dev]) {
+               ++dev;
+               return -ENOENT;
+       }
+       err = oxygen_pci_probe(pci, index[dev], id[dev], 0, &model_hifier);
+       if (err >= 0)
+               ++dev;
+       return err;
+}
+
+static struct pci_driver hifier_driver = {
+       .name = "CMI8787HiFier",
+       .id_table = hifier_ids,
+       .probe = hifier_probe,
+       .remove = __devexit_p(oxygen_pci_remove),
+};
+
+static int __init alsa_card_hifier_init(void)
+{
+       return pci_register_driver(&hifier_driver);
+}
+
+static void __exit alsa_card_hifier_exit(void)
+{
+       pci_unregister_driver(&hifier_driver);
+}
+
+module_init(alsa_card_hifier_init)
+module_exit(alsa_card_hifier_exit)
diff --git a/sound/pci/oxygen/oxygen.c b/sound/pci/oxygen/oxygen.c
new file mode 100644 (file)
index 0000000..f31a0eb
--- /dev/null
@@ -0,0 +1,385 @@
+/*
+ * C-Media CMI8788 driver for C-Media's reference design and for the X-Meridian
+ *
+ * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
+ *
+ *
+ *  This driver is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License, version 2.
+ *
+ *  This driver 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 driver; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+/*
+ * SPI 0 -> 1st AK4396 (front)
+ * SPI 1 -> 2nd AK4396 (surround)
+ * SPI 2 -> 3rd AK4396 (center/LFE)
+ * SPI 3 -> WM8785
+ * SPI 4 -> 4th AK4396 (back)
+ *
+ * GPIO 0 -> DFS0 of AK5385
+ * GPIO 1 -> DFS1 of AK5385
+ */
+
+#include <linux/pci.h>
+#include <sound/control.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/tlv.h>
+#include "oxygen.h"
+#include "ak4396.h"
+
+MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
+MODULE_DESCRIPTION("C-Media CMI8788 driver");
+MODULE_LICENSE("GPL");
+MODULE_SUPPORTED_DEVICE("{{C-Media,CMI8788}}");
+
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
+static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
+
+module_param_array(index, int, NULL, 0444);
+MODULE_PARM_DESC(index, "card index");
+module_param_array(id, charp, NULL, 0444);
+MODULE_PARM_DESC(id, "ID string");
+module_param_array(enable, bool, NULL, 0444);
+MODULE_PARM_DESC(enable, "enable card");
+
+static struct pci_device_id oxygen_ids[] __devinitdata = {
+       { OXYGEN_PCI_SUBID(0x10b0, 0x0216) },
+       { OXYGEN_PCI_SUBID(0x10b0, 0x0218) },
+       { OXYGEN_PCI_SUBID(0x10b0, 0x0219) },
+       { OXYGEN_PCI_SUBID(0x13f6, 0x0001) },
+       { OXYGEN_PCI_SUBID(0x13f6, 0x0010) },
+       { OXYGEN_PCI_SUBID(0x13f6, 0x8788) },
+       { OXYGEN_PCI_SUBID(0x147a, 0xa017) },
+       { OXYGEN_PCI_SUBID(0x1a58, 0x0910) },
+       { OXYGEN_PCI_SUBID(0x415a, 0x5431), .driver_data = 1 },
+       { OXYGEN_PCI_SUBID(0x7284, 0x9761) },
+       { }
+};
+MODULE_DEVICE_TABLE(pci, oxygen_ids);
+
+
+#define GPIO_AK5385_DFS_MASK   0x0003
+#define GPIO_AK5385_DFS_NORMAL 0x0000
+#define GPIO_AK5385_DFS_DOUBLE 0x0001
+#define GPIO_AK5385_DFS_QUAD   0x0002
+
+#define WM8785_R0      0
+#define WM8785_R1      1
+#define WM8785_R2      2
+#define WM8785_R7      7
+
+/* R0 */
+#define WM8785_MCR_MASK                0x007
+#define WM8785_MCR_SLAVE       0x000
+#define WM8785_MCR_MASTER_128  0x001
+#define WM8785_MCR_MASTER_192  0x002
+#define WM8785_MCR_MASTER_256  0x003
+#define WM8785_MCR_MASTER_384  0x004
+#define WM8785_MCR_MASTER_512  0x005
+#define WM8785_MCR_MASTER_768  0x006
+#define WM8785_OSR_MASK                0x018
+#define WM8785_OSR_SINGLE      0x000
+#define WM8785_OSR_DOUBLE      0x008
+#define WM8785_OSR_QUAD                0x010
+#define WM8785_FORMAT_MASK     0x060
+#define WM8785_FORMAT_RJUST    0x000
+#define WM8785_FORMAT_LJUST    0x020
+#define WM8785_FORMAT_I2S      0x040
+#define WM8785_FORMAT_DSP      0x060
+/* R1 */
+#define WM8785_WL_MASK         0x003
+#define WM8785_WL_16           0x000
+#define WM8785_WL_20           0x001
+#define WM8785_WL_24           0x002
+#define WM8785_WL_32           0x003
+#define WM8785_LRP             0x004
+#define WM8785_BCLKINV         0x008
+#define WM8785_LRSWAP          0x010
+#define WM8785_DEVNO_MASK      0x0e0
+/* R2 */
+#define WM8785_HPFR            0x001
+#define WM8785_HPFL            0x002
+#define WM8785_SDODIS          0x004
+#define WM8785_PWRDNR          0x008
+#define WM8785_PWRDNL          0x010
+#define WM8785_TDM_MASK                0x1c0
+
+struct generic_data {
+       u8 ak4396_ctl2;
+};
+
+static void ak4396_write(struct oxygen *chip, unsigned int codec,
+                        u8 reg, u8 value)
+{
+       /* maps ALSA channel pair number to SPI output */
+       static const u8 codec_spi_map[4] = {
+               0, 1, 2, 4
+       };
+       oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER |
+                        OXYGEN_SPI_DATA_LENGTH_2 |
+                        OXYGEN_SPI_CLOCK_160 |
+                        (codec_spi_map[codec] << OXYGEN_SPI_CODEC_SHIFT) |
+                        OXYGEN_SPI_CEN_LATCH_CLOCK_HI,
+                        AK4396_WRITE | (reg << 8) | value);
+}
+
+static void wm8785_write(struct oxygen *chip, u8 reg, unsigned int value)
+{
+       oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER |
+                        OXYGEN_SPI_DATA_LENGTH_2 |
+                        OXYGEN_SPI_CLOCK_160 |
+                        (3 << OXYGEN_SPI_CODEC_SHIFT) |
+                        OXYGEN_SPI_CEN_LATCH_CLOCK_LO,
+                        (reg << 9) | value);
+}
+
+static void ak4396_init(struct oxygen *chip)
+{
+       struct generic_data *data = chip->model_data;
+       unsigned int i;
+
+       data->ak4396_ctl2 = AK4396_DEM_OFF | AK4396_DFS_NORMAL;
+       for (i = 0; i < 4; ++i) {
+               ak4396_write(chip, i,
+                            AK4396_CONTROL_1, AK4396_DIF_24_MSB | AK4396_RSTN);
+               ak4396_write(chip, i,
+                            AK4396_CONTROL_2, data->ak4396_ctl2);
+               ak4396_write(chip, i,
+                            AK4396_CONTROL_3, AK4396_PCM);
+               ak4396_write(chip, i, AK4396_LCH_ATT, 0xff);
+               ak4396_write(chip, i, AK4396_RCH_ATT, 0xff);
+       }
+       snd_component_add(chip->card, "AK4396");
+}
+
+static void ak5385_init(struct oxygen *chip)
+{
+       oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_AK5385_DFS_MASK);
+       oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_AK5385_DFS_MASK);
+       snd_component_add(chip->card, "AK5385");
+}
+
+static void wm8785_init(struct oxygen *chip)
+{
+       wm8785_write(chip, WM8785_R7, 0);
+       wm8785_write(chip, WM8785_R0, WM8785_MCR_SLAVE |
+                    WM8785_OSR_SINGLE | WM8785_FORMAT_LJUST);
+       wm8785_write(chip, WM8785_R1, WM8785_WL_24);
+       snd_component_add(chip->card, "WM8785");
+}
+
+static void generic_init(struct oxygen *chip)
+{
+       ak4396_init(chip);
+       wm8785_init(chip);
+}
+
+static void meridian_init(struct oxygen *chip)
+{
+       ak4396_init(chip);
+       ak5385_init(chip);
+}
+
+static void generic_cleanup(struct oxygen *chip)
+{
+}
+
+static void set_ak4396_params(struct oxygen *chip,
+                             struct snd_pcm_hw_params *params)
+{
+       struct generic_data *data = chip->model_data;
+       unsigned int i;
+       u8 value;
+
+       value = data->ak4396_ctl2 & ~AK4396_DFS_MASK;
+       if (params_rate(params) <= 54000)
+               value |= AK4396_DFS_NORMAL;
+       else if (params_rate(params) <= 108000)
+               value |= AK4396_DFS_DOUBLE;
+       else
+               value |= AK4396_DFS_QUAD;
+       data->ak4396_ctl2 = value;
+       for (i = 0; i < 4; ++i) {
+               ak4396_write(chip, i,
+                            AK4396_CONTROL_1, AK4396_DIF_24_MSB);
+               ak4396_write(chip, i,
+                            AK4396_CONTROL_2, value);
+               ak4396_write(chip, i,
+                            AK4396_CONTROL_1, AK4396_DIF_24_MSB | AK4396_RSTN);
+       }
+}
+
+static void update_ak4396_volume(struct oxygen *chip)
+{
+       unsigned int i;
+
+       for (i = 0; i < 4; ++i) {
+               ak4396_write(chip, i,
+                            AK4396_LCH_ATT, chip->dac_volume[i * 2]);
+               ak4396_write(chip, i,
+                            AK4396_RCH_ATT, chip->dac_volume[i * 2 + 1]);
+       }
+}
+
+static void update_ak4396_mute(struct oxygen *chip)
+{
+       struct generic_data *data = chip->model_data;
+       unsigned int i;
+       u8 value;
+
+       value = data->ak4396_ctl2 & ~AK4396_SMUTE;
+       if (chip->dac_mute)
+               value |= AK4396_SMUTE;
+       data->ak4396_ctl2 = value;
+       for (i = 0; i < 4; ++i)
+               ak4396_write(chip, i, AK4396_CONTROL_2, value);
+}
+
+static void set_wm8785_params(struct oxygen *chip,
+                             struct snd_pcm_hw_params *params)
+{
+       unsigned int value;
+
+       wm8785_write(chip, WM8785_R7, 0);
+
+       value = WM8785_MCR_SLAVE | WM8785_FORMAT_LJUST;
+       if (params_rate(params) <= 48000)
+               value |= WM8785_OSR_SINGLE;
+       else if (params_rate(params) <= 96000)
+               value |= WM8785_OSR_DOUBLE;
+       else
+               value |= WM8785_OSR_QUAD;
+       wm8785_write(chip, WM8785_R0, value);
+
+       if (snd_pcm_format_width(params_format(params)) <= 16)
+               value = WM8785_WL_16;
+       else
+               value = WM8785_WL_24;
+       wm8785_write(chip, WM8785_R1, value);
+}
+
+static void set_ak5385_params(struct oxygen *chip,
+                             struct snd_pcm_hw_params *params)
+{
+       unsigned int value;
+
+       if (params_rate(params) <= 54000)
+               value = GPIO_AK5385_DFS_NORMAL;
+       else if (params_rate(params) <= 108000)
+               value = GPIO_AK5385_DFS_DOUBLE;
+       else
+               value = GPIO_AK5385_DFS_QUAD;
+       oxygen_write16_masked(chip, OXYGEN_GPIO_DATA,
+                             value, GPIO_AK5385_DFS_MASK);
+}
+
+static const DECLARE_TLV_DB_LINEAR(ak4396_db_scale, TLV_DB_GAIN_MUTE, 0);
+
+static int ak4396_control_filter(struct snd_kcontrol_new *template)
+{
+       if (!strcmp(template->name, "Master Playback Volume")) {
+               template->access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ;
+               template->tlv.p = ak4396_db_scale;
+       }
+       return 0;
+}
+
+static const struct oxygen_model model_generic = {
+       .shortname = "C-Media CMI8788",
+       .longname = "C-Media Oxygen HD Audio",
+       .chip = "CMI8788",
+       .owner = THIS_MODULE,
+       .init = generic_init,
+       .control_filter = ak4396_control_filter,
+       .cleanup = generic_cleanup,
+       .set_dac_params = set_ak4396_params,
+       .set_adc_params = set_wm8785_params,
+       .update_dac_volume = update_ak4396_volume,
+       .update_dac_mute = update_ak4396_mute,
+       .model_data_size = sizeof(struct generic_data),
+       .dac_channels = 8,
+       .used_channels = OXYGEN_CHANNEL_A |
+                        OXYGEN_CHANNEL_C |
+                        OXYGEN_CHANNEL_SPDIF |
+                        OXYGEN_CHANNEL_MULTICH |
+                        OXYGEN_CHANNEL_AC97,
+       .function_flags = OXYGEN_FUNCTION_ENABLE_SPI_4_5,
+       .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
+       .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
+};
+static const struct oxygen_model model_meridian = {
+       .shortname = "C-Media CMI8788",
+       .longname = "C-Media Oxygen HD Audio",
+       .chip = "CMI8788",
+       .owner = THIS_MODULE,
+       .init = meridian_init,
+       .control_filter = ak4396_control_filter,
+       .cleanup = generic_cleanup,
+       .set_dac_params = set_ak4396_params,
+       .set_adc_params = set_ak5385_params,
+       .update_dac_volume = update_ak4396_volume,
+       .update_dac_mute = update_ak4396_mute,
+       .model_data_size = sizeof(struct generic_data),
+       .dac_channels = 8,
+       .used_channels = OXYGEN_CHANNEL_B |
+                        OXYGEN_CHANNEL_C |
+                        OXYGEN_CHANNEL_SPDIF |
+                        OXYGEN_CHANNEL_MULTICH |
+                        OXYGEN_CHANNEL_AC97,
+       .function_flags = OXYGEN_FUNCTION_ENABLE_SPI_4_5,
+       .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
+       .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
+};
+
+static int __devinit generic_oxygen_probe(struct pci_dev *pci,
+                                         const struct pci_device_id *pci_id)
+{
+       static int dev;
+       int is_meridian;
+       int err;
+
+       if (dev >= SNDRV_CARDS)
+               return -ENODEV;
+       if (!enable[dev]) {
+               ++dev;
+               return -ENOENT;
+       }
+       is_meridian = pci_id->driver_data;
+       err = oxygen_pci_probe(pci, index[dev], id[dev], is_meridian,
+                              is_meridian ? &model_meridian : &model_generic);
+       if (err >= 0)
+               ++dev;
+       return err;
+}
+
+static struct pci_driver oxygen_driver = {
+       .name = "CMI8788",
+       .id_table = oxygen_ids,
+       .probe = generic_oxygen_probe,
+       .remove = __devexit_p(oxygen_pci_remove),
+};
+
+static int __init alsa_card_oxygen_init(void)
+{
+       return pci_register_driver(&oxygen_driver);
+}
+
+static void __exit alsa_card_oxygen_exit(void)
+{
+       pci_unregister_driver(&oxygen_driver);
+}
+
+module_init(alsa_card_oxygen_init)
+module_exit(alsa_card_oxygen_exit)
diff --git a/sound/pci/oxygen/oxygen.h b/sound/pci/oxygen/oxygen.h
new file mode 100644 (file)
index 0000000..ad50fb8
--- /dev/null
@@ -0,0 +1,190 @@
+#ifndef OXYGEN_H_INCLUDED
+#define OXYGEN_H_INCLUDED
+
+#include <linux/mutex.h>
+#include <linux/spinlock.h>
+#include <linux/wait.h>
+#include <linux/workqueue.h>
+#include "oxygen_regs.h"
+
+/* 1 << PCM_x == OXYGEN_CHANNEL_x */
+#define PCM_A          0
+#define PCM_B          1
+#define PCM_C          2
+#define PCM_SPDIF      3
+#define PCM_MULTICH    4
+#define PCM_AC97       5
+#define PCM_COUNT      6
+
+enum {
+       CONTROL_SPDIF_PCM,
+       CONTROL_SPDIF_INPUT_BITS,
+       CONTROL_MIC_CAPTURE_SWITCH,
+       CONTROL_LINE_CAPTURE_SWITCH,
+       CONTROL_CD_CAPTURE_SWITCH,
+       CONTROL_AUX_CAPTURE_SWITCH,
+       CONTROL_COUNT
+};
+
+#define OXYGEN_PCI_SUBID(sv, sd) \
+       .vendor = PCI_VENDOR_ID_CMEDIA, \
+       .device = 0x8788, \
+       .subvendor = sv, \
+       .subdevice = sd
+
+struct pci_dev;
+struct snd_card;
+struct snd_pcm_substream;
+struct snd_pcm_hardware;
+struct snd_pcm_hw_params;
+struct snd_kcontrol_new;
+struct snd_rawmidi;
+struct oxygen_model;
+
+struct oxygen {
+       unsigned long addr;
+       spinlock_t reg_lock;
+       struct mutex mutex;
+       struct snd_card *card;
+       struct pci_dev *pci;
+       struct snd_rawmidi *midi;
+       int irq;
+       const struct oxygen_model *model;
+       void *model_data;
+       unsigned int interrupt_mask;
+       u8 dac_volume[8];
+       u8 dac_mute;
+       u8 pcm_active;
+       u8 pcm_running;
+       u8 dac_routing;
+       u8 spdif_playback_enable;
+       u8 revision;
+       u8 has_ac97_0;
+       u8 has_ac97_1;
+       u32 spdif_bits;
+       u32 spdif_pcm_bits;
+       struct snd_pcm_substream *streams[PCM_COUNT];
+       struct snd_kcontrol *controls[CONTROL_COUNT];
+       struct work_struct spdif_input_bits_work;
+       struct work_struct gpio_work;
+       wait_queue_head_t ac97_waitqueue;
+};
+
+struct oxygen_model {
+       const char *shortname;
+       const char *longname;
+       const char *chip;
+       struct module *owner;
+       void (*init)(struct oxygen *chip);
+       int (*control_filter)(struct snd_kcontrol_new *template);
+       int (*mixer_init)(struct oxygen *chip);
+       void (*cleanup)(struct oxygen *chip);
+       void (*pcm_hardware_filter)(unsigned int channel,
+                                   struct snd_pcm_hardware *hardware);
+       void (*set_dac_params)(struct oxygen *chip,
+                              struct snd_pcm_hw_params *params);
+       void (*set_adc_params)(struct oxygen *chip,
+                              struct snd_pcm_hw_params *params);
+       void (*update_dac_volume)(struct oxygen *chip);
+       void (*update_dac_mute)(struct oxygen *chip);
+       void (*ac97_switch_hook)(struct oxygen *chip, unsigned int codec,
+                                unsigned int reg, int mute);
+       void (*gpio_changed)(struct oxygen *chip);
+       size_t model_data_size;
+       u8 dac_channels;
+       u8 used_channels;
+       u8 function_flags;
+       u16 dac_i2s_format;
+       u16 adc_i2s_format;
+};
+
+/* oxygen_lib.c */
+
+int oxygen_pci_probe(struct pci_dev *pci, int index, char *id, int midi,
+                    const struct oxygen_model *model);
+void oxygen_pci_remove(struct pci_dev *pci);
+
+/* oxygen_mixer.c */
+
+int oxygen_mixer_init(struct oxygen *chip);
+void oxygen_update_dac_routing(struct oxygen *chip);
+void oxygen_update_spdif_source(struct oxygen *chip);
+
+/* oxygen_pcm.c */
+
+int oxygen_pcm_init(struct oxygen *chip);
+
+/* oxygen_io.c */
+
+u8 oxygen_read8(struct oxygen *chip, unsigned int reg);
+u16 oxygen_read16(struct oxygen *chip, unsigned int reg);
+u32 oxygen_read32(struct oxygen *chip, unsigned int reg);
+void oxygen_write8(struct oxygen *chip, unsigned int reg, u8 value);
+void oxygen_write16(struct oxygen *chip, unsigned int reg, u16 value);
+void oxygen_write32(struct oxygen *chip, unsigned int reg, u32 value);
+void oxygen_write8_masked(struct oxygen *chip, unsigned int reg,
+                         u8 value, u8 mask);
+void oxygen_write16_masked(struct oxygen *chip, unsigned int reg,
+                          u16 value, u16 mask);
+void oxygen_write32_masked(struct oxygen *chip, unsigned int reg,
+                          u32 value, u32 mask);
+
+u16 oxygen_read_ac97(struct oxygen *chip, unsigned int codec,
+                    unsigned int index);
+void oxygen_write_ac97(struct oxygen *chip, unsigned int codec,
+                      unsigned int index, u16 data);
+void oxygen_write_ac97_masked(struct oxygen *chip, unsigned int codec,
+                             unsigned int index, u16 data, u16 mask);
+
+void oxygen_write_spi(struct oxygen *chip, u8 control, unsigned int data);
+
+static inline void oxygen_set_bits8(struct oxygen *chip,
+                                   unsigned int reg, u8 value)
+{
+       oxygen_write8_masked(chip, reg, value, value);
+}
+
+static inline void oxygen_set_bits16(struct oxygen *chip,
+                                    unsigned int reg, u16 value)
+{
+       oxygen_write16_masked(chip, reg, value, value);
+}
+
+static inline void oxygen_set_bits32(struct oxygen *chip,
+                                    unsigned int reg, u32 value)
+{
+       oxygen_write32_masked(chip, reg, value, value);
+}
+
+static inline void oxygen_clear_bits8(struct oxygen *chip,
+                                     unsigned int reg, u8 value)
+{
+       oxygen_write8_masked(chip, reg, 0, value);
+}
+
+static inline void oxygen_clear_bits16(struct oxygen *chip,
+                                      unsigned int reg, u16 value)
+{
+       oxygen_write16_masked(chip, reg, 0, value);
+}
+
+static inline void oxygen_clear_bits32(struct oxygen *chip,
+                                      unsigned int reg, u32 value)
+{
+       oxygen_write32_masked(chip, reg, 0, value);
+}
+
+static inline void oxygen_ac97_set_bits(struct oxygen *chip, unsigned int codec,
+                                       unsigned int index, u16 value)
+{
+       oxygen_write_ac97_masked(chip, codec, index, value, value);
+}
+
+static inline void oxygen_ac97_clear_bits(struct oxygen *chip,
+                                         unsigned int codec,
+                                         unsigned int index, u16 value)
+{
+       oxygen_write_ac97_masked(chip, codec, index, 0, value);
+}
+
+#endif
diff --git a/sound/pci/oxygen/oxygen_io.c b/sound/pci/oxygen/oxygen_io.c
new file mode 100644 (file)
index 0000000..74e23ef
--- /dev/null
@@ -0,0 +1,201 @@
+/*
+ * C-Media CMI8788 driver - helper functions
+ *
+ * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
+ *
+ *
+ *  This driver is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License, version 2.
+ *
+ *  This driver 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 driver; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <sound/core.h>
+#include <asm/io.h>
+#include "oxygen.h"
+
+u8 oxygen_read8(struct oxygen *chip, unsigned int reg)
+{
+       return inb(chip->addr + reg);
+}
+EXPORT_SYMBOL(oxygen_read8);
+
+u16 oxygen_read16(struct oxygen *chip, unsigned int reg)
+{
+       return inw(chip->addr + reg);
+}
+EXPORT_SYMBOL(oxygen_read16);
+
+u32 oxygen_read32(struct oxygen *chip, unsigned int reg)
+{
+       return inl(chip->addr + reg);
+}
+EXPORT_SYMBOL(oxygen_read32);
+
+void oxygen_write8(struct oxygen *chip, unsigned int reg, u8 value)
+{
+       outb(value, chip->addr + reg);
+}
+EXPORT_SYMBOL(oxygen_write8);
+
+void oxygen_write16(struct oxygen *chip, unsigned int reg, u16 value)
+{
+       outw(value, chip->addr + reg);
+}
+EXPORT_SYMBOL(oxygen_write16);
+
+void oxygen_write32(struct oxygen *chip, unsigned int reg, u32 value)
+{
+       outl(value, chip->addr + reg);
+}
+EXPORT_SYMBOL(oxygen_write32);
+
+void oxygen_write8_masked(struct oxygen *chip, unsigned int reg,
+                         u8 value, u8 mask)
+{
+       u8 tmp = inb(chip->addr + reg);
+       outb((tmp & ~mask) | (value & mask), chip->addr + reg);
+}
+EXPORT_SYMBOL(oxygen_write8_masked);
+
+void oxygen_write16_masked(struct oxygen *chip, unsigned int reg,
+                          u16 value, u16 mask)
+{
+       u16 tmp = inw(chip->addr + reg);
+       outw((tmp & ~mask) | (value & mask), chip->addr + reg);
+}
+EXPORT_SYMBOL(oxygen_write16_masked);
+
+void oxygen_write32_masked(struct oxygen *chip, unsigned int reg,
+                          u32 value, u32 mask)
+{
+       u32 tmp = inl(chip->addr + reg);
+       outl((tmp & ~mask) | (value & mask), chip->addr + reg);
+}
+EXPORT_SYMBOL(oxygen_write32_masked);
+
+static int oxygen_ac97_wait(struct oxygen *chip, unsigned int mask)
+{
+       u8 status = 0;
+
+       /*
+        * Reading the status register also clears the bits, so we have to save
+        * the read bits in status.
+        */
+       wait_event_timeout(chip->ac97_waitqueue,
+                          ({ status |= oxygen_read8(chip, OXYGEN_AC97_INTERRUPT_STATUS);
+                             status & mask; }),
+                          msecs_to_jiffies(1) + 1);
+       /*
+        * Check even after a timeout because this function should not require
+        * the AC'97 interrupt to be enabled.
+        */
+       status |= oxygen_read8(chip, OXYGEN_AC97_INTERRUPT_STATUS);
+       return status & mask ? 0 : -EIO;
+}
+
+/*
+ * About 10% of AC'97 register reads or writes fail to complete, but even those
+ * where the controller indicates completion aren't guaranteed to have actually
+ * happened.
+ *
+ * It's hard to assign blame to either the controller or the codec because both
+ * were made by C-Media ...
+ */
+
+void oxygen_write_ac97(struct oxygen *chip, unsigned int codec,
+                      unsigned int index, u16 data)
+{
+       unsigned int count, succeeded;
+       u32 reg;
+
+       reg = data;
+       reg |= index << OXYGEN_AC97_REG_ADDR_SHIFT;
+       reg |= OXYGEN_AC97_REG_DIR_WRITE;
+       reg |= codec << OXYGEN_AC97_REG_CODEC_SHIFT;
+       succeeded = 0;
+       for (count = 5; count > 0; --count) {
+               udelay(5);
+               oxygen_write32(chip, OXYGEN_AC97_REGS, reg);
+               /* require two "completed" writes, just to be sure */
+               if (oxygen_ac97_wait(chip, OXYGEN_AC97_INT_WRITE_DONE) >= 0 &&
+                   ++succeeded >= 2)
+                       return;
+       }
+       snd_printk(KERN_ERR "AC'97 write timeout\n");
+}
+EXPORT_SYMBOL(oxygen_write_ac97);
+
+u16 oxygen_read_ac97(struct oxygen *chip, unsigned int codec,
+                    unsigned int index)
+{
+       unsigned int count;
+       unsigned int last_read = UINT_MAX;
+       u32 reg;
+
+       reg = index << OXYGEN_AC97_REG_ADDR_SHIFT;
+       reg |= OXYGEN_AC97_REG_DIR_READ;
+       reg |= codec << OXYGEN_AC97_REG_CODEC_SHIFT;
+       for (count = 5; count > 0; --count) {
+               udelay(5);
+               oxygen_write32(chip, OXYGEN_AC97_REGS, reg);
+               udelay(10);
+               if (oxygen_ac97_wait(chip, OXYGEN_AC97_INT_READ_DONE) >= 0) {
+                       u16 value = oxygen_read16(chip, OXYGEN_AC97_REGS);
+                       /* we require two consecutive reads of the same value */
+                       if (value == last_read)
+                               return value;
+                       last_read = value;
+                       /*
+                        * Invert the register value bits to make sure that two
+                        * consecutive unsuccessful reads do not return the same
+                        * value.
+                        */
+                       reg ^= 0xffff;
+               }
+       }
+       snd_printk(KERN_ERR "AC'97 read timeout on codec %u\n", codec);
+       return 0;
+}
+EXPORT_SYMBOL(oxygen_read_ac97);
+
+void oxygen_write_ac97_masked(struct oxygen *chip, unsigned int codec,
+                             unsigned int index, u16 data, u16 mask)
+{
+       u16 value = oxygen_read_ac97(chip, codec, index);
+       value &= ~mask;
+       value |= data & mask;
+       oxygen_write_ac97(chip, codec, index, value);
+}
+EXPORT_SYMBOL(oxygen_write_ac97_masked);
+
+void oxygen_write_spi(struct oxygen *chip, u8 control, unsigned int data)
+{
+       unsigned int count;
+
+       /* should not need more than 7.68 us (24 * 320 ns) */
+       count = 10;
+       while ((oxygen_read8(chip, OXYGEN_SPI_CONTROL) & OXYGEN_SPI_BUSY)
+              && count > 0) {
+               udelay(1);
+               --count;
+       }
+
+       spin_lock_irq(&chip->reg_lock);
+       oxygen_write8(chip, OXYGEN_SPI_DATA1, data);
+       oxygen_write8(chip, OXYGEN_SPI_DATA2, data >> 8);
+       if (control & OXYGEN_SPI_DATA_LENGTH_3)
+               oxygen_write8(chip, OXYGEN_SPI_DATA3, data >> 16);
+       oxygen_write8(chip, OXYGEN_SPI_CONTROL, control);
+       spin_unlock_irq(&chip->reg_lock);
+}
+EXPORT_SYMBOL(oxygen_write_spi);
diff --git a/sound/pci/oxygen/oxygen_lib.c b/sound/pci/oxygen/oxygen_lib.c
new file mode 100644 (file)
index 0000000..6eb36dd
--- /dev/null
@@ -0,0 +1,515 @@
+/*
+ * C-Media CMI8788 driver - main driver module
+ *
+ * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
+ *
+ *
+ *  This driver is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License, version 2.
+ *
+ *  This driver 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 driver; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/mutex.h>
+#include <linux/pci.h>
+#include <sound/ac97_codec.h>
+#include <sound/asoundef.h>
+#include <sound/core.h>
+#include <sound/info.h>
+#include <sound/mpu401.h>
+#include <sound/pcm.h>
+#include "oxygen.h"
+#include "cm9780.h"
+
+MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
+MODULE_DESCRIPTION("C-Media CMI8788 helper library");
+MODULE_LICENSE("GPL");
+
+
+static irqreturn_t oxygen_interrupt(int dummy, void *dev_id)
+{
+       struct oxygen *chip = dev_id;
+       unsigned int status, clear, elapsed_streams, i;
+
+       status = oxygen_read16(chip, OXYGEN_INTERRUPT_STATUS);
+       if (!status)
+               return IRQ_NONE;
+
+       spin_lock(&chip->reg_lock);
+
+       clear = status & (OXYGEN_CHANNEL_A |
+                         OXYGEN_CHANNEL_B |
+                         OXYGEN_CHANNEL_C |
+                         OXYGEN_CHANNEL_SPDIF |
+                         OXYGEN_CHANNEL_MULTICH |
+                         OXYGEN_CHANNEL_AC97 |
+                         OXYGEN_INT_SPDIF_IN_DETECT |
+                         OXYGEN_INT_GPIO |
+                         OXYGEN_INT_AC97);
+       if (clear) {
+               if (clear & OXYGEN_INT_SPDIF_IN_DETECT)
+                       chip->interrupt_mask &= ~OXYGEN_INT_SPDIF_IN_DETECT;
+               oxygen_write16(chip, OXYGEN_INTERRUPT_MASK,
+                              chip->interrupt_mask & ~clear);
+               oxygen_write16(chip, OXYGEN_INTERRUPT_MASK,
+                              chip->interrupt_mask);
+       }
+
+       elapsed_streams = status & chip->pcm_running;
+
+       spin_unlock(&chip->reg_lock);
+
+       for (i = 0; i < PCM_COUNT; ++i)
+               if ((elapsed_streams & (1 << i)) && chip->streams[i])
+                       snd_pcm_period_elapsed(chip->streams[i]);
+
+       if (status & OXYGEN_INT_SPDIF_IN_DETECT) {
+               spin_lock(&chip->reg_lock);
+               i = oxygen_read32(chip, OXYGEN_SPDIF_CONTROL);
+               if (i & (OXYGEN_SPDIF_SENSE_INT | OXYGEN_SPDIF_LOCK_INT |
+                        OXYGEN_SPDIF_RATE_INT)) {
+                       /* write the interrupt bit(s) to clear */
+                       oxygen_write32(chip, OXYGEN_SPDIF_CONTROL, i);
+                       schedule_work(&chip->spdif_input_bits_work);
+               }
+               spin_unlock(&chip->reg_lock);
+       }
+
+       if (status & OXYGEN_INT_GPIO)
+               schedule_work(&chip->gpio_work);
+
+       if ((status & OXYGEN_INT_MIDI) && chip->midi)
+               snd_mpu401_uart_interrupt(0, chip->midi->private_data);
+
+       if (status & OXYGEN_INT_AC97)
+               wake_up(&chip->ac97_waitqueue);
+
+       return IRQ_HANDLED;
+}
+
+static void oxygen_spdif_input_bits_changed(struct work_struct *work)
+{
+       struct oxygen *chip = container_of(work, struct oxygen,
+                                          spdif_input_bits_work);
+       u32 reg;
+
+       /*
+        * This function gets called when there is new activity on the SPDIF
+        * input, or when we lose lock on the input signal, or when the rate
+        * changes.
+        */
+       msleep(1);
+       spin_lock_irq(&chip->reg_lock);
+       reg = oxygen_read32(chip, OXYGEN_SPDIF_CONTROL);
+       if ((reg & (OXYGEN_SPDIF_SENSE_STATUS |
+                   OXYGEN_SPDIF_LOCK_STATUS))
+           == OXYGEN_SPDIF_SENSE_STATUS) {
+               /*
+                * If we detect activity on the SPDIF input but cannot lock to
+                * a signal, the clock bit is likely to be wrong.
+                */
+               reg ^= OXYGEN_SPDIF_IN_CLOCK_MASK;
+               oxygen_write32(chip, OXYGEN_SPDIF_CONTROL, reg);
+               spin_unlock_irq(&chip->reg_lock);
+               msleep(1);
+               spin_lock_irq(&chip->reg_lock);
+               reg = oxygen_read32(chip, OXYGEN_SPDIF_CONTROL);
+               if ((reg & (OXYGEN_SPDIF_SENSE_STATUS |
+                           OXYGEN_SPDIF_LOCK_STATUS))
+                   == OXYGEN_SPDIF_SENSE_STATUS) {
+                       /* nothing detected with either clock; give up */
+                       if ((reg & OXYGEN_SPDIF_IN_CLOCK_MASK)
+                           == OXYGEN_SPDIF_IN_CLOCK_192) {
+                               /*
+                                * Reset clock to <= 96 kHz because this is
+                                * more likely to be received next time.
+                                */
+                               reg &= ~OXYGEN_SPDIF_IN_CLOCK_MASK;
+                               reg |= OXYGEN_SPDIF_IN_CLOCK_96;
+                               oxygen_write32(chip, OXYGEN_SPDIF_CONTROL, reg);
+                       }
+               }
+       }
+       spin_unlock_irq(&chip->reg_lock);
+
+       if (chip->controls[CONTROL_SPDIF_INPUT_BITS]) {
+               spin_lock_irq(&chip->reg_lock);
+               chip->interrupt_mask |= OXYGEN_INT_SPDIF_IN_DETECT;
+               oxygen_write16(chip, OXYGEN_INTERRUPT_MASK,
+                              chip->interrupt_mask);
+               spin_unlock_irq(&chip->reg_lock);
+
+               /*
+                * We don't actually know that any channel status bits have
+                * changed, but let's send a notification just to be sure.
+                */
+               snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
+                              &chip->controls[CONTROL_SPDIF_INPUT_BITS]->id);
+       }
+}
+
+static void oxygen_gpio_changed(struct work_struct *work)
+{
+       struct oxygen *chip = container_of(work, struct oxygen, gpio_work);
+
+       if (chip->model->gpio_changed)
+               chip->model->gpio_changed(chip);
+}
+
+#ifdef CONFIG_PROC_FS
+static void oxygen_proc_read(struct snd_info_entry *entry,
+                            struct snd_info_buffer *buffer)
+{
+       struct oxygen *chip = entry->private_data;
+       int i, j;
+
+       snd_iprintf(buffer, "CMI8788\n\n");
+       for (i = 0; i < 0x100; i += 0x10) {
+               snd_iprintf(buffer, "%02x:", i);
+               for (j = 0; j < 0x10; ++j)
+                       snd_iprintf(buffer, " %02x", oxygen_read8(chip, i + j));
+               snd_iprintf(buffer, "\n");
+       }
+       if (mutex_lock_interruptible(&chip->mutex) < 0)
+               return;
+       if (chip->has_ac97_0) {
+               snd_iprintf(buffer, "\nAC97\n");
+               for (i = 0; i < 0x80; i += 0x10) {
+                       snd_iprintf(buffer, "%02x:", i);
+                       for (j = 0; j < 0x10; j += 2)
+                               snd_iprintf(buffer, " %04x",
+                                           oxygen_read_ac97(chip, 0, i + j));
+                       snd_iprintf(buffer, "\n");
+               }
+       }
+       if (chip->has_ac97_1) {
+               snd_iprintf(buffer, "\nAC97 2\n");
+               for (i = 0; i < 0x80; i += 0x10) {
+                       snd_iprintf(buffer, "%02x:", i);
+                       for (j = 0; j < 0x10; j += 2)
+                               snd_iprintf(buffer, " %04x",
+                                           oxygen_read_ac97(chip, 1, i + j));
+                       snd_iprintf(buffer, "\n");
+               }
+       }
+       mutex_unlock(&chip->mutex);
+}
+
+static void __devinit oxygen_proc_init(struct oxygen *chip)
+{
+       struct snd_info_entry *entry;
+
+       if (!snd_card_proc_new(chip->card, "cmi8788", &entry))
+               snd_info_set_text_ops(entry, chip, oxygen_proc_read);
+}
+#else
+#define oxygen_proc_init(chip)
+#endif
+
+static void __devinit oxygen_init(struct oxygen *chip)
+{
+       unsigned int i;
+
+       chip->dac_routing = 1;
+       for (i = 0; i < 8; ++i)
+               chip->dac_volume[i] = 0xff;
+       chip->spdif_playback_enable = 1;
+       chip->spdif_bits = OXYGEN_SPDIF_C | OXYGEN_SPDIF_ORIGINAL |
+               (IEC958_AES1_CON_PCM_CODER << OXYGEN_SPDIF_CATEGORY_SHIFT);
+       chip->spdif_pcm_bits = chip->spdif_bits;
+
+       if (oxygen_read8(chip, OXYGEN_REVISION) & OXYGEN_REVISION_2)
+               chip->revision = 2;
+       else
+               chip->revision = 1;
+
+       if (chip->revision == 1)
+               oxygen_set_bits8(chip, OXYGEN_MISC,
+                                OXYGEN_MISC_PCI_MEM_W_1_CLOCK);
+
+       i = oxygen_read16(chip, OXYGEN_AC97_CONTROL);
+       chip->has_ac97_0 = (i & OXYGEN_AC97_CODEC_0) != 0;
+       chip->has_ac97_1 = (i & OXYGEN_AC97_CODEC_1) != 0;
+
+       oxygen_set_bits8(chip, OXYGEN_FUNCTION,
+                        OXYGEN_FUNCTION_RESET_CODEC |
+                        chip->model->function_flags);
+       oxygen_write8_masked(chip, OXYGEN_FUNCTION,
+                            OXYGEN_FUNCTION_SPI,
+                            OXYGEN_FUNCTION_2WIRE_SPI_MASK);
+       oxygen_write8(chip, OXYGEN_DMA_STATUS, 0);
+       oxygen_write8(chip, OXYGEN_DMA_PAUSE, 0);
+       oxygen_write8(chip, OXYGEN_PLAY_CHANNELS,
+                     OXYGEN_PLAY_CHANNELS_2 |
+                     OXYGEN_DMA_A_BURST_8 |
+                     OXYGEN_DMA_MULTICH_BURST_8);
+       oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, 0);
+       oxygen_write8_masked(chip, OXYGEN_MISC, 0,
+                            OXYGEN_MISC_WRITE_PCI_SUBID |
+                            OXYGEN_MISC_REC_C_FROM_SPDIF |
+                            OXYGEN_MISC_REC_B_FROM_AC97 |
+                            OXYGEN_MISC_REC_A_FROM_MULTICH);
+       oxygen_write8(chip, OXYGEN_REC_FORMAT,
+                     (OXYGEN_FORMAT_16 << OXYGEN_REC_FORMAT_A_SHIFT) |
+                     (OXYGEN_FORMAT_16 << OXYGEN_REC_FORMAT_B_SHIFT) |
+                     (OXYGEN_FORMAT_16 << OXYGEN_REC_FORMAT_C_SHIFT));
+       oxygen_write8(chip, OXYGEN_PLAY_FORMAT,
+                     (OXYGEN_FORMAT_16 << OXYGEN_SPDIF_FORMAT_SHIFT) |
+                     (OXYGEN_FORMAT_16 << OXYGEN_MULTICH_FORMAT_SHIFT));
+       oxygen_write8(chip, OXYGEN_REC_CHANNELS, OXYGEN_REC_CHANNELS_2_2_2);
+       oxygen_write16(chip, OXYGEN_I2S_MULTICH_FORMAT,
+                      OXYGEN_RATE_48000 | OXYGEN_I2S_FORMAT_LJUST |
+                      OXYGEN_I2S_MCLK_128 | OXYGEN_I2S_BITS_16 |
+                      OXYGEN_I2S_MASTER | OXYGEN_I2S_BCLK_64);
+       oxygen_write16(chip, OXYGEN_I2S_A_FORMAT,
+                      OXYGEN_RATE_48000 | OXYGEN_I2S_FORMAT_LJUST |
+                      OXYGEN_I2S_MCLK_128 | OXYGEN_I2S_BITS_16 |
+                      OXYGEN_I2S_MASTER | OXYGEN_I2S_BCLK_64);
+       oxygen_write16(chip, OXYGEN_I2S_B_FORMAT,
+                      OXYGEN_RATE_48000 | OXYGEN_I2S_FORMAT_LJUST |
+                      OXYGEN_I2S_MCLK_128 | OXYGEN_I2S_BITS_16 |
+                      OXYGEN_I2S_MASTER | OXYGEN_I2S_BCLK_64);
+       oxygen_write16(chip, OXYGEN_I2S_C_FORMAT,
+                      OXYGEN_RATE_48000 | OXYGEN_I2S_FORMAT_LJUST |
+                      OXYGEN_I2S_MCLK_128 | OXYGEN_I2S_BITS_16 |
+                      OXYGEN_I2S_MASTER | OXYGEN_I2S_BCLK_64);
+       oxygen_write32_masked(chip, OXYGEN_SPDIF_CONTROL,
+                             OXYGEN_SPDIF_SENSE_MASK |
+                             OXYGEN_SPDIF_LOCK_MASK |
+                             OXYGEN_SPDIF_RATE_MASK |
+                             OXYGEN_SPDIF_LOCK_PAR |
+                             OXYGEN_SPDIF_IN_CLOCK_96,
+                             OXYGEN_SPDIF_OUT_ENABLE |
+                             OXYGEN_SPDIF_LOOPBACK |
+                             OXYGEN_SPDIF_SENSE_MASK |
+                             OXYGEN_SPDIF_LOCK_MASK |
+                             OXYGEN_SPDIF_RATE_MASK |
+                             OXYGEN_SPDIF_SENSE_PAR |
+                             OXYGEN_SPDIF_LOCK_PAR |
+                             OXYGEN_SPDIF_IN_CLOCK_MASK);
+       oxygen_write32(chip, OXYGEN_SPDIF_OUTPUT_BITS, chip->spdif_bits);
+       oxygen_clear_bits8(chip, OXYGEN_MPU401_CONTROL, OXYGEN_MPU401_LOOPBACK);
+       oxygen_write8(chip, OXYGEN_GPI_INTERRUPT_MASK, 0);
+       oxygen_write16(chip, OXYGEN_GPIO_INTERRUPT_MASK, 0);
+       oxygen_write16(chip, OXYGEN_PLAY_ROUTING,
+                      OXYGEN_PLAY_MULTICH_I2S_DAC |
+                      OXYGEN_PLAY_SPDIF_SPDIF |
+                      (0 << OXYGEN_PLAY_DAC0_SOURCE_SHIFT) |
+                      (1 << OXYGEN_PLAY_DAC1_SOURCE_SHIFT) |
+                      (2 << OXYGEN_PLAY_DAC2_SOURCE_SHIFT) |
+                      (3 << OXYGEN_PLAY_DAC3_SOURCE_SHIFT));
+       oxygen_write8(chip, OXYGEN_REC_ROUTING,
+                     OXYGEN_REC_A_ROUTE_I2S_ADC_1 |
+                     OXYGEN_REC_B_ROUTE_I2S_ADC_2 |
+                     OXYGEN_REC_C_ROUTE_SPDIF);
+       oxygen_write8(chip, OXYGEN_ADC_MONITOR, 0);
+       oxygen_write8(chip, OXYGEN_A_MONITOR_ROUTING,
+                     (0 << OXYGEN_A_MONITOR_ROUTE_0_SHIFT) |
+                     (1 << OXYGEN_A_MONITOR_ROUTE_1_SHIFT) |
+                     (2 << OXYGEN_A_MONITOR_ROUTE_2_SHIFT) |
+                     (3 << OXYGEN_A_MONITOR_ROUTE_3_SHIFT));
+
+       oxygen_write8(chip, OXYGEN_AC97_INTERRUPT_MASK,
+                     OXYGEN_AC97_INT_READ_DONE |
+                     OXYGEN_AC97_INT_WRITE_DONE);
+       oxygen_write32(chip, OXYGEN_AC97_OUT_CONFIG, 0);
+       oxygen_write32(chip, OXYGEN_AC97_IN_CONFIG, 0);
+       if (!(chip->has_ac97_0 | chip->has_ac97_1))
+               oxygen_set_bits16(chip, OXYGEN_AC97_CONTROL,
+                                 OXYGEN_AC97_CLOCK_DISABLE);
+       if (!chip->has_ac97_0) {
+               oxygen_set_bits16(chip, OXYGEN_AC97_CONTROL,
+                                 OXYGEN_AC97_NO_CODEC_0);
+       } else {
+               oxygen_write_ac97(chip, 0, AC97_RESET, 0);
+               msleep(1);
+               oxygen_ac97_set_bits(chip, 0, CM9780_GPIO_SETUP,
+                                    CM9780_GPIO0IO | CM9780_GPIO1IO);
+               oxygen_ac97_set_bits(chip, 0, CM9780_MIXER,
+                                    CM9780_BSTSEL | CM9780_STRO_MIC |
+                                    CM9780_MIX2FR | CM9780_PCBSW);
+               oxygen_ac97_set_bits(chip, 0, CM9780_JACK,
+                                    CM9780_RSOE | CM9780_CBOE |
+                                    CM9780_SSOE | CM9780_FROE |
+                                    CM9780_MIC2MIC | CM9780_LI2LI);
+               oxygen_write_ac97(chip, 0, AC97_MASTER, 0x0000);
+               oxygen_write_ac97(chip, 0, AC97_PC_BEEP, 0x8000);
+               oxygen_write_ac97(chip, 0, AC97_MIC, 0x8808);
+               oxygen_write_ac97(chip, 0, AC97_LINE, 0x0808);
+               oxygen_write_ac97(chip, 0, AC97_CD, 0x8808);
+               oxygen_write_ac97(chip, 0, AC97_VIDEO, 0x8808);
+               oxygen_write_ac97(chip, 0, AC97_AUX, 0x8808);
+               oxygen_write_ac97(chip, 0, AC97_REC_GAIN, 0x8000);
+               oxygen_write_ac97(chip, 0, AC97_CENTER_LFE_MASTER, 0x8080);
+               oxygen_write_ac97(chip, 0, AC97_SURROUND_MASTER, 0x8080);
+               /* power down unused ADCs and DACs */
+               oxygen_ac97_set_bits(chip, 0, AC97_POWERDOWN,
+                                    AC97_PD_PR0 | AC97_PD_PR1);
+               oxygen_ac97_set_bits(chip, 0, AC97_EXTENDED_STATUS,
+                                    AC97_EA_PRI | AC97_EA_PRJ | AC97_EA_PRK);
+       }
+       if (chip->has_ac97_1) {
+               oxygen_set_bits32(chip, OXYGEN_AC97_OUT_CONFIG,
+                                 OXYGEN_AC97_CODEC1_SLOT3 |
+                                 OXYGEN_AC97_CODEC1_SLOT4);
+               oxygen_write_ac97(chip, 1, AC97_RESET, 0);
+               msleep(1);
+               oxygen_write_ac97(chip, 1, AC97_MASTER, 0x0000);
+               oxygen_write_ac97(chip, 1, AC97_HEADPHONE, 0x8000);
+               oxygen_write_ac97(chip, 1, AC97_PC_BEEP, 0x8000);
+               oxygen_write_ac97(chip, 1, AC97_MIC, 0x8808);
+               oxygen_write_ac97(chip, 1, AC97_LINE, 0x8808);
+               oxygen_write_ac97(chip, 1, AC97_CD, 0x8808);
+               oxygen_write_ac97(chip, 1, AC97_VIDEO, 0x8808);
+               oxygen_write_ac97(chip, 1, AC97_AUX, 0x8808);
+               oxygen_write_ac97(chip, 1, AC97_PCM, 0x0808);
+               oxygen_write_ac97(chip, 1, AC97_REC_SEL, 0x0000);
+               oxygen_write_ac97(chip, 1, AC97_REC_GAIN, 0x0000);
+               oxygen_ac97_set_bits(chip, 1, 0x6a, 0x0040);
+       }
+}
+
+static void oxygen_card_free(struct snd_card *card)
+{
+       struct oxygen *chip = card->private_data;
+
+       spin_lock_irq(&chip->reg_lock);
+       chip->interrupt_mask = 0;
+       chip->pcm_running = 0;
+       oxygen_write16(chip, OXYGEN_DMA_STATUS, 0);
+       oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, 0);
+       spin_unlock_irq(&chip->reg_lock);
+       if (chip->irq >= 0) {
+               free_irq(chip->irq, chip);
+               synchronize_irq(chip->irq);
+       }
+       flush_scheduled_work();
+       chip->model->cleanup(chip);
+       mutex_destroy(&chip->mutex);
+       pci_release_regions(chip->pci);
+       pci_disable_device(chip->pci);
+}
+
+int __devinit oxygen_pci_probe(struct pci_dev *pci, int index, char *id,
+                              int midi, const struct oxygen_model *model)
+{
+       struct snd_card *card;
+       struct oxygen *chip;
+       int err;
+
+       card = snd_card_new(index, id, model->owner,
+                           sizeof *chip + model->model_data_size);
+       if (!card)
+               return -ENOMEM;
+
+       chip = card->private_data;
+       chip->card = card;
+       chip->pci = pci;
+       chip->irq = -1;
+       chip->model = model;
+       chip->model_data = chip + 1;
+       spin_lock_init(&chip->reg_lock);
+       mutex_init(&chip->mutex);
+       INIT_WORK(&chip->spdif_input_bits_work,
+                 oxygen_spdif_input_bits_changed);
+       INIT_WORK(&chip->gpio_work, oxygen_gpio_changed);
+       init_waitqueue_head(&chip->ac97_waitqueue);
+
+       err = pci_enable_device(pci);
+       if (err < 0)
+               goto err_card;
+
+       err = pci_request_regions(pci, model->chip);
+       if (err < 0) {
+               snd_printk(KERN_ERR "cannot reserve PCI resources\n");
+               goto err_pci_enable;
+       }
+
+       if (!(pci_resource_flags(pci, 0) & IORESOURCE_IO) ||
+           pci_resource_len(pci, 0) < 0x100) {
+               snd_printk(KERN_ERR "invalid PCI I/O range\n");
+               err = -ENXIO;
+               goto err_pci_regions;
+       }
+       chip->addr = pci_resource_start(pci, 0);
+
+       pci_set_master(pci);
+       snd_card_set_dev(card, &pci->dev);
+       card->private_free = oxygen_card_free;
+
+       oxygen_init(chip);
+       model->init(chip);
+
+       err = request_irq(pci->irq, oxygen_interrupt, IRQF_SHARED,
+                         model->chip, chip);
+       if (err < 0) {
+               snd_printk(KERN_ERR "cannot grab interrupt %d\n", pci->irq);
+               goto err_card;
+       }
+       chip->irq = pci->irq;
+
+       strcpy(card->driver, model->chip);
+       strcpy(card->shortname, model->shortname);
+       sprintf(card->longname, "%s (rev %u) at %#lx, irq %i",
+               model->longname, chip->revision, chip->addr, chip->irq);
+       strcpy(card->mixername, model->chip);
+       snd_component_add(card, model->chip);
+
+       err = oxygen_pcm_init(chip);
+       if (err < 0)
+               goto err_card;
+
+       err = oxygen_mixer_init(chip);
+       if (err < 0)
+               goto err_card;
+
+       oxygen_write8_masked(chip, OXYGEN_MISC,
+                            midi ? OXYGEN_MISC_MIDI : 0, OXYGEN_MISC_MIDI);
+       if (midi) {
+               err = snd_mpu401_uart_new(card, 0, MPU401_HW_CMIPCI,
+                                         chip->addr + OXYGEN_MPU401,
+                                         MPU401_INFO_INTEGRATED, 0, 0,
+                                         &chip->midi);
+               if (err < 0)
+                       goto err_card;
+       }
+
+       oxygen_proc_init(chip);
+
+       spin_lock_irq(&chip->reg_lock);
+       chip->interrupt_mask |= OXYGEN_INT_SPDIF_IN_DETECT | OXYGEN_INT_AC97;
+       oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, chip->interrupt_mask);
+       spin_unlock_irq(&chip->reg_lock);
+
+       err = snd_card_register(card);
+       if (err < 0)
+               goto err_card;
+
+       pci_set_drvdata(pci, card);
+       return 0;
+
+err_pci_regions:
+       pci_release_regions(pci);
+err_pci_enable:
+       pci_disable_device(pci);
+err_card:
+       snd_card_free(card);
+       return err;
+}
+EXPORT_SYMBOL(oxygen_pci_probe);
+
+void __devexit oxygen_pci_remove(struct pci_dev *pci)
+{
+       snd_card_free(pci_get_drvdata(pci));
+       pci_set_drvdata(pci, NULL);
+}
+EXPORT_SYMBOL(oxygen_pci_remove);
diff --git a/sound/pci/oxygen/oxygen_mixer.c b/sound/pci/oxygen/oxygen_mixer.c
new file mode 100644 (file)
index 0000000..a8e4623
--- /dev/null
@@ -0,0 +1,794 @@
+/*
+ * C-Media CMI8788 driver - mixer code
+ *
+ * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
+ *
+ *
+ *  This driver is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License, version 2.
+ *
+ *  This driver 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 driver; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#include <linux/mutex.h>
+#include <sound/ac97_codec.h>
+#include <sound/asoundef.h>
+#include <sound/control.h>
+#include <sound/tlv.h>
+#include "oxygen.h"
+#include "cm9780.h"
+
+static int dac_volume_info(struct snd_kcontrol *ctl,
+                          struct snd_ctl_elem_info *info)
+{
+       struct oxygen *chip = ctl->private_data;
+
+       info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       info->count = chip->model->dac_channels;
+       info->value.integer.min = 0;
+       info->value.integer.max = 0xff;
+       return 0;
+}
+
+static int dac_volume_get(struct snd_kcontrol *ctl,
+                         struct snd_ctl_elem_value *value)
+{
+       struct oxygen *chip = ctl->private_data;
+       unsigned int i;
+
+       mutex_lock(&chip->mutex);
+       for (i = 0; i < chip->model->dac_channels; ++i)
+               value->value.integer.value[i] = chip->dac_volume[i];
+       mutex_unlock(&chip->mutex);
+       return 0;
+}
+
+static int dac_volume_put(struct snd_kcontrol *ctl,
+                         struct snd_ctl_elem_value *value)
+{
+       struct oxygen *chip = ctl->private_data;
+       unsigned int i;
+       int changed;
+
+       changed = 0;
+       mutex_lock(&chip->mutex);
+       for (i = 0; i < chip->model->dac_channels; ++i)
+               if (value->value.integer.value[i] != chip->dac_volume[i]) {
+                       chip->dac_volume[i] = value->value.integer.value[i];
+                       changed = 1;
+               }
+       if (changed)
+               chip->model->update_dac_volume(chip);
+       mutex_unlock(&chip->mutex);
+       return changed;
+}
+
+static int dac_mute_get(struct snd_kcontrol *ctl,
+                       struct snd_ctl_elem_value *value)
+{
+       struct oxygen *chip = ctl->private_data;
+
+       mutex_lock(&chip->mutex);
+       value->value.integer.value[0] = !chip->dac_mute;
+       mutex_unlock(&chip->mutex);
+       return 0;
+}
+
+static int dac_mute_put(struct snd_kcontrol *ctl,
+                         struct snd_ctl_elem_value *value)
+{
+       struct oxygen *chip = ctl->private_data;
+       int changed;
+
+       mutex_lock(&chip->mutex);
+       changed = !value->value.integer.value[0] != chip->dac_mute;
+       if (changed) {
+               chip->dac_mute = !value->value.integer.value[0];
+               chip->model->update_dac_mute(chip);
+       }
+       mutex_unlock(&chip->mutex);
+       return changed;
+}
+
+static int upmix_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info)
+{
+       static const char *const names[3] = {
+               "Front", "Front+Surround", "Front+Surround+Back"
+       };
+       struct oxygen *chip = ctl->private_data;
+       unsigned int count = 2 + (chip->model->dac_channels == 8);
+
+       info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+       info->count = 1;
+       info->value.enumerated.items = count;
+       if (info->value.enumerated.item >= count)
+               info->value.enumerated.item = count - 1;
+       strcpy(info->value.enumerated.name, names[info->value.enumerated.item]);
+       return 0;
+}
+
+static int upmix_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value)
+{
+       struct oxygen *chip = ctl->private_data;
+
+       mutex_lock(&chip->mutex);
+       value->value.enumerated.item[0] = chip->dac_routing;
+       mutex_unlock(&chip->mutex);
+       return 0;
+}
+
+void oxygen_update_dac_routing(struct oxygen *chip)
+{
+       /* DAC 0: front, DAC 1: surround, DAC 2: center/LFE, DAC 3: back */
+       static const unsigned int reg_values[3] = {
+               /* stereo -> front */
+               (0 << OXYGEN_PLAY_DAC0_SOURCE_SHIFT) |
+               (1 << OXYGEN_PLAY_DAC1_SOURCE_SHIFT) |
+               (2 << OXYGEN_PLAY_DAC2_SOURCE_SHIFT) |
+               (3 << OXYGEN_PLAY_DAC3_SOURCE_SHIFT),
+               /* stereo -> front+surround */
+               (0 << OXYGEN_PLAY_DAC0_SOURCE_SHIFT) |
+               (0 << OXYGEN_PLAY_DAC1_SOURCE_SHIFT) |
+               (2 << OXYGEN_PLAY_DAC2_SOURCE_SHIFT) |
+               (3 << OXYGEN_PLAY_DAC3_SOURCE_SHIFT),
+               /* stereo -> front+surround+back */
+               (0 << OXYGEN_PLAY_DAC0_SOURCE_SHIFT) |
+               (0 << OXYGEN_PLAY_DAC1_SOURCE_SHIFT) |
+               (2 << OXYGEN_PLAY_DAC2_SOURCE_SHIFT) |
+               (0 << OXYGEN_PLAY_DAC3_SOURCE_SHIFT),
+       };
+       u8 channels;
+       unsigned int reg_value;
+
+       channels = oxygen_read8(chip, OXYGEN_PLAY_CHANNELS) &
+               OXYGEN_PLAY_CHANNELS_MASK;
+       if (channels == OXYGEN_PLAY_CHANNELS_2)
+               reg_value = reg_values[chip->dac_routing];
+       else if (channels == OXYGEN_PLAY_CHANNELS_8)
+               /* in 7.1 mode, "rear" channels go to the "back" jack */
+               reg_value = (0 << OXYGEN_PLAY_DAC0_SOURCE_SHIFT) |
+                           (3 << OXYGEN_PLAY_DAC1_SOURCE_SHIFT) |
+                           (2 << OXYGEN_PLAY_DAC2_SOURCE_SHIFT) |
+                           (1 << OXYGEN_PLAY_DAC3_SOURCE_SHIFT);
+       else
+               reg_value = (0 << OXYGEN_PLAY_DAC0_SOURCE_SHIFT) |
+                           (1 << OXYGEN_PLAY_DAC1_SOURCE_SHIFT) |
+                           (2 << OXYGEN_PLAY_DAC2_SOURCE_SHIFT) |
+                           (3 << OXYGEN_PLAY_DAC3_SOURCE_SHIFT);
+       oxygen_write16_masked(chip, OXYGEN_PLAY_ROUTING, reg_value,
+                             OXYGEN_PLAY_DAC0_SOURCE_MASK |
+                             OXYGEN_PLAY_DAC1_SOURCE_MASK |
+                             OXYGEN_PLAY_DAC2_SOURCE_MASK |
+                             OXYGEN_PLAY_DAC3_SOURCE_MASK);
+}
+
+static int upmix_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value)
+{
+       struct oxygen *chip = ctl->private_data;
+       unsigned int count = 2 + (chip->model->dac_channels == 8);
+       int changed;
+
+       mutex_lock(&chip->mutex);
+       changed = value->value.enumerated.item[0] != chip->dac_routing;
+       if (changed) {
+               chip->dac_routing = min(value->value.enumerated.item[0],
+                                       count - 1);
+               spin_lock_irq(&chip->reg_lock);
+               oxygen_update_dac_routing(chip);
+               spin_unlock_irq(&chip->reg_lock);
+       }
+       mutex_unlock(&chip->mutex);
+       return changed;
+}
+
+static int spdif_switch_get(struct snd_kcontrol *ctl,
+                           struct snd_ctl_elem_value *value)
+{
+       struct oxygen *chip = ctl->private_data;
+
+       mutex_lock(&chip->mutex);
+       value->value.integer.value[0] = chip->spdif_playback_enable;
+       mutex_unlock(&chip->mutex);
+       return 0;
+}
+
+static unsigned int oxygen_spdif_rate(unsigned int oxygen_rate)
+{
+       switch (oxygen_rate) {
+       case OXYGEN_RATE_32000:
+               return IEC958_AES3_CON_FS_32000 << OXYGEN_SPDIF_CS_RATE_SHIFT;
+       case OXYGEN_RATE_44100:
+               return IEC958_AES3_CON_FS_44100 << OXYGEN_SPDIF_CS_RATE_SHIFT;
+       default: /* OXYGEN_RATE_48000 */
+               return IEC958_AES3_CON_FS_48000 << OXYGEN_SPDIF_CS_RATE_SHIFT;
+       case OXYGEN_RATE_64000:
+               return 0xb << OXYGEN_SPDIF_CS_RATE_SHIFT;
+       case OXYGEN_RATE_88200:
+               return 0x8 << OXYGEN_SPDIF_CS_RATE_SHIFT;
+       case OXYGEN_RATE_96000:
+               return 0xa << OXYGEN_SPDIF_CS_RATE_SHIFT;
+       case OXYGEN_RATE_176400:
+               return 0xc << OXYGEN_SPDIF_CS_RATE_SHIFT;
+       case OXYGEN_RATE_192000:
+               return 0xe << OXYGEN_SPDIF_CS_RATE_SHIFT;
+       }
+}
+
+void oxygen_update_spdif_source(struct oxygen *chip)
+{
+       u32 old_control, new_control;
+       u16 old_routing, new_routing;
+       unsigned int oxygen_rate;
+
+       old_control = oxygen_read32(chip, OXYGEN_SPDIF_CONTROL);
+       old_routing = oxygen_read16(chip, OXYGEN_PLAY_ROUTING);
+       if (chip->pcm_active & (1 << PCM_SPDIF)) {
+               new_control = old_control | OXYGEN_SPDIF_OUT_ENABLE;
+               new_routing = (old_routing & ~OXYGEN_PLAY_SPDIF_MASK)
+                       | OXYGEN_PLAY_SPDIF_SPDIF;
+               oxygen_rate = (old_control >> OXYGEN_SPDIF_OUT_RATE_SHIFT)
+                       & OXYGEN_I2S_RATE_MASK;
+               /* S/PDIF rate was already set by the caller */
+       } else if ((chip->pcm_active & (1 << PCM_MULTICH)) &&
+                  chip->spdif_playback_enable) {
+               new_routing = (old_routing & ~OXYGEN_PLAY_SPDIF_MASK)
+                       | OXYGEN_PLAY_SPDIF_MULTICH_01;
+               oxygen_rate = oxygen_read16(chip, OXYGEN_I2S_MULTICH_FORMAT)
+                       & OXYGEN_I2S_RATE_MASK;
+               new_control = (old_control & ~OXYGEN_SPDIF_OUT_RATE_MASK) |
+                       (oxygen_rate << OXYGEN_SPDIF_OUT_RATE_SHIFT) |
+                       OXYGEN_SPDIF_OUT_ENABLE;
+       } else {
+               new_control = old_control & ~OXYGEN_SPDIF_OUT_ENABLE;
+               new_routing = old_routing;
+               oxygen_rate = OXYGEN_RATE_44100;
+       }
+       if (old_routing != new_routing) {
+               oxygen_write32(chip, OXYGEN_SPDIF_CONTROL,
+                              new_control & ~OXYGEN_SPDIF_OUT_ENABLE);
+               oxygen_write16(chip, OXYGEN_PLAY_ROUTING, new_routing);
+       }
+       if (new_control & OXYGEN_SPDIF_OUT_ENABLE)
+               oxygen_write32(chip, OXYGEN_SPDIF_OUTPUT_BITS,
+                              oxygen_spdif_rate(oxygen_rate) |
+                              ((chip->pcm_active & (1 << PCM_SPDIF)) ?
+                               chip->spdif_pcm_bits : chip->spdif_bits));
+       oxygen_write32(chip, OXYGEN_SPDIF_CONTROL, new_control);
+}
+
+static int spdif_switch_put(struct snd_kcontrol *ctl,
+                           struct snd_ctl_elem_value *value)
+{
+       struct oxygen *chip = ctl->private_data;
+       int changed;
+
+       mutex_lock(&chip->mutex);
+       changed = value->value.integer.value[0] != chip->spdif_playback_enable;
+       if (changed) {
+               chip->spdif_playback_enable = !!value->value.integer.value[0];
+               spin_lock_irq(&chip->reg_lock);
+               oxygen_update_spdif_source(chip);
+               spin_unlock_irq(&chip->reg_lock);
+       }
+       mutex_unlock(&chip->mutex);
+       return changed;
+}
+
+static int spdif_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info)
+{
+       info->type = SNDRV_CTL_ELEM_TYPE_IEC958;
+       info->count = 1;
+       return 0;
+}
+
+static void oxygen_to_iec958(u32 bits, struct snd_ctl_elem_value *value)
+{
+       value->value.iec958.status[0] =
+               bits & (OXYGEN_SPDIF_NONAUDIO | OXYGEN_SPDIF_C |
+                       OXYGEN_SPDIF_PREEMPHASIS);
+       value->value.iec958.status[1] = /* category and original */
+               bits >> OXYGEN_SPDIF_CATEGORY_SHIFT;
+}
+
+static u32 iec958_to_oxygen(struct snd_ctl_elem_value *value)
+{
+       u32 bits;
+
+       bits = value->value.iec958.status[0] &
+               (OXYGEN_SPDIF_NONAUDIO | OXYGEN_SPDIF_C |
+                OXYGEN_SPDIF_PREEMPHASIS);
+       bits |= value->value.iec958.status[1] << OXYGEN_SPDIF_CATEGORY_SHIFT;
+       if (bits & OXYGEN_SPDIF_NONAUDIO)
+               bits |= OXYGEN_SPDIF_V;
+       return bits;
+}
+
+static inline void write_spdif_bits(struct oxygen *chip, u32 bits)
+{
+       oxygen_write32_masked(chip, OXYGEN_SPDIF_OUTPUT_BITS, bits,
+                             OXYGEN_SPDIF_NONAUDIO |
+                             OXYGEN_SPDIF_C |
+                             OXYGEN_SPDIF_PREEMPHASIS |
+                             OXYGEN_SPDIF_CATEGORY_MASK |
+                             OXYGEN_SPDIF_ORIGINAL |
+                             OXYGEN_SPDIF_V);
+}
+
+static int spdif_default_get(struct snd_kcontrol *ctl,
+                            struct snd_ctl_elem_value *value)
+{
+       struct oxygen *chip = ctl->private_data;
+
+       mutex_lock(&chip->mutex);
+       oxygen_to_iec958(chip->spdif_bits, value);
+       mutex_unlock(&chip->mutex);
+       return 0;
+}
+
+static int spdif_default_put(struct snd_kcontrol *ctl,
+                            struct snd_ctl_elem_value *value)
+{
+       struct oxygen *chip = ctl->private_data;
+       u32 new_bits;
+       int changed;
+
+       new_bits = iec958_to_oxygen(value);
+       mutex_lock(&chip->mutex);
+       changed = new_bits != chip->spdif_bits;
+       if (changed) {
+               chip->spdif_bits = new_bits;
+               if (!(chip->pcm_active & (1 << PCM_SPDIF)))
+                       write_spdif_bits(chip, new_bits);
+       }
+       mutex_unlock(&chip->mutex);
+       return changed;
+}
+
+static int spdif_mask_get(struct snd_kcontrol *ctl,
+                         struct snd_ctl_elem_value *value)
+{
+       value->value.iec958.status[0] = IEC958_AES0_NONAUDIO |
+               IEC958_AES0_CON_NOT_COPYRIGHT | IEC958_AES0_CON_EMPHASIS;
+       value->value.iec958.status[1] =
+               IEC958_AES1_CON_CATEGORY | IEC958_AES1_CON_ORIGINAL;
+       return 0;
+}
+
+static int spdif_pcm_get(struct snd_kcontrol *ctl,
+                        struct snd_ctl_elem_value *value)
+{
+       struct oxygen *chip = ctl->private_data;
+
+       mutex_lock(&chip->mutex);
+       oxygen_to_iec958(chip->spdif_pcm_bits, value);
+       mutex_unlock(&chip->mutex);
+       return 0;
+}
+
+static int spdif_pcm_put(struct snd_kcontrol *ctl,
+                        struct snd_ctl_elem_value *value)
+{
+       struct oxygen *chip = ctl->private_data;
+       u32 new_bits;
+       int changed;
+
+       new_bits = iec958_to_oxygen(value);
+       mutex_lock(&chip->mutex);
+       changed = new_bits != chip->spdif_pcm_bits;
+       if (changed) {
+               chip->spdif_pcm_bits = new_bits;
+               if (chip->pcm_active & (1 << PCM_SPDIF))
+                       write_spdif_bits(chip, new_bits);
+       }
+       mutex_unlock(&chip->mutex);
+       return changed;
+}
+
+static int spdif_input_mask_get(struct snd_kcontrol *ctl,
+                               struct snd_ctl_elem_value *value)
+{
+       value->value.iec958.status[0] = 0xff;
+       value->value.iec958.status[1] = 0xff;
+       value->value.iec958.status[2] = 0xff;
+       value->value.iec958.status[3] = 0xff;
+       return 0;
+}
+
+static int spdif_input_default_get(struct snd_kcontrol *ctl,
+                                  struct snd_ctl_elem_value *value)
+{
+       struct oxygen *chip = ctl->private_data;
+       u32 bits;
+
+       bits = oxygen_read32(chip, OXYGEN_SPDIF_INPUT_BITS);
+       value->value.iec958.status[0] = bits;
+       value->value.iec958.status[1] = bits >> 8;
+       value->value.iec958.status[2] = bits >> 16;
+       value->value.iec958.status[3] = bits >> 24;
+       return 0;
+}
+
+static int spdif_loopback_get(struct snd_kcontrol *ctl,
+                             struct snd_ctl_elem_value *value)
+{
+       struct oxygen *chip = ctl->private_data;
+
+       value->value.integer.value[0] =
+               !!(oxygen_read32(chip, OXYGEN_SPDIF_CONTROL)
+                  & OXYGEN_SPDIF_LOOPBACK);
+       return 0;
+}
+
+static int spdif_loopback_put(struct snd_kcontrol *ctl,
+                             struct snd_ctl_elem_value *value)
+{
+       struct oxygen *chip = ctl->private_data;
+       u32 oldreg, newreg;
+       int changed;
+
+       spin_lock_irq(&chip->reg_lock);
+       oldreg = oxygen_read32(chip, OXYGEN_SPDIF_CONTROL);
+       if (value->value.integer.value[0])
+               newreg = oldreg | OXYGEN_SPDIF_LOOPBACK;
+       else
+               newreg = oldreg & ~OXYGEN_SPDIF_LOOPBACK;
+       changed = newreg != oldreg;
+       if (changed)
+               oxygen_write32(chip, OXYGEN_SPDIF_CONTROL, newreg);
+       spin_unlock_irq(&chip->reg_lock);
+       return changed;
+}
+
+static int ac97_switch_get(struct snd_kcontrol *ctl,
+                          struct snd_ctl_elem_value *value)
+{
+       struct oxygen *chip = ctl->private_data;
+       unsigned int codec = (ctl->private_value >> 24) & 1;
+       unsigned int index = ctl->private_value & 0xff;
+       unsigned int bitnr = (ctl->private_value >> 8) & 0xff;
+       int invert = ctl->private_value & (1 << 16);
+       u16 reg;
+
+       mutex_lock(&chip->mutex);
+       reg = oxygen_read_ac97(chip, codec, index);
+       mutex_unlock(&chip->mutex);
+       if (!(reg & (1 << bitnr)) ^ !invert)
+               value->value.integer.value[0] = 1;
+       else
+               value->value.integer.value[0] = 0;
+       return 0;
+}
+
+static int ac97_switch_put(struct snd_kcontrol *ctl,
+                          struct snd_ctl_elem_value *value)
+{
+       struct oxygen *chip = ctl->private_data;
+       unsigned int codec = (ctl->private_value >> 24) & 1;
+       unsigned int index = ctl->private_value & 0xff;
+       unsigned int bitnr = (ctl->private_value >> 8) & 0xff;
+       int invert = ctl->private_value & (1 << 16);
+       u16 oldreg, newreg;
+       int change;
+
+       mutex_lock(&chip->mutex);
+       oldreg = oxygen_read_ac97(chip, codec, index);
+       newreg = oldreg;
+       if (!value->value.integer.value[0] ^ !invert)
+               newreg |= 1 << bitnr;
+       else
+               newreg &= ~(1 << bitnr);
+       change = newreg != oldreg;
+       if (change) {
+               oxygen_write_ac97(chip, codec, index, newreg);
+               if (bitnr == 15 && chip->model->ac97_switch_hook)
+                       chip->model->ac97_switch_hook(chip, codec, index,
+                                                     newreg & 0x8000);
+       }
+       mutex_unlock(&chip->mutex);
+       return change;
+}
+
+static int ac97_volume_info(struct snd_kcontrol *ctl,
+                           struct snd_ctl_elem_info *info)
+{
+       info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       info->count = 2;
+       info->value.integer.min = 0;
+       info->value.integer.max = 0x1f;
+       return 0;
+}
+
+static int ac97_volume_get(struct snd_kcontrol *ctl,
+                          struct snd_ctl_elem_value *value)
+{
+       struct oxygen *chip = ctl->private_data;
+       unsigned int codec = (ctl->private_value >> 24) & 1;
+       unsigned int index = ctl->private_value & 0xff;
+       u16 reg;
+
+       mutex_lock(&chip->mutex);
+       reg = oxygen_read_ac97(chip, codec, index);
+       mutex_unlock(&chip->mutex);
+       value->value.integer.value[0] = 31 - (reg & 0x1f);
+       value->value.integer.value[1] = 31 - ((reg >> 8) & 0x1f);
+       return 0;
+}
+
+static int ac97_volume_put(struct snd_kcontrol *ctl,
+                          struct snd_ctl_elem_value *value)
+{
+       struct oxygen *chip = ctl->private_data;
+       unsigned int codec = (ctl->private_value >> 24) & 1;
+       unsigned int index = ctl->private_value & 0xff;
+       u16 oldreg, newreg;
+       int change;
+
+       mutex_lock(&chip->mutex);
+       oldreg = oxygen_read_ac97(chip, codec, index);
+       newreg = oldreg;
+       newreg = (newreg & ~0x1f) |
+               (31 - (value->value.integer.value[0] & 0x1f));
+       newreg = (newreg & ~0x1f00) |
+               ((31 - (value->value.integer.value[0] & 0x1f)) << 8);
+       change = newreg != oldreg;
+       if (change)
+               oxygen_write_ac97(chip, codec, index, newreg);
+       mutex_unlock(&chip->mutex);
+       return change;
+}
+
+static int ac97_fp_rec_volume_info(struct snd_kcontrol *ctl,
+                                  struct snd_ctl_elem_info *info)
+{
+       info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       info->count = 2;
+       info->value.integer.min = 0;
+       info->value.integer.max = 7;
+       return 0;
+}
+
+static int ac97_fp_rec_volume_get(struct snd_kcontrol *ctl,
+                                 struct snd_ctl_elem_value *value)
+{
+       struct oxygen *chip = ctl->private_data;
+       u16 reg;
+
+       mutex_lock(&chip->mutex);
+       reg = oxygen_read_ac97(chip, 1, AC97_REC_GAIN);
+       mutex_unlock(&chip->mutex);
+       value->value.integer.value[0] = reg & 7;
+       value->value.integer.value[1] = (reg >> 8) & 7;
+       return 0;
+}
+
+static int ac97_fp_rec_volume_put(struct snd_kcontrol *ctl,
+                                 struct snd_ctl_elem_value *value)
+{
+       struct oxygen *chip = ctl->private_data;
+       u16 oldreg, newreg;
+       int change;
+
+       mutex_lock(&chip->mutex);
+       oldreg = oxygen_read_ac97(chip, 1, AC97_REC_GAIN);
+       newreg = oldreg & ~0x0707;
+       newreg = newreg | (value->value.integer.value[0] & 7);
+       newreg = newreg | ((value->value.integer.value[0] & 7) << 8);
+       change = newreg != oldreg;
+       if (change)
+               oxygen_write_ac97(chip, 1, AC97_REC_GAIN, newreg);
+       mutex_unlock(&chip->mutex);
+       return change;
+}
+
+#define AC97_SWITCH(xname, codec, index, bitnr, invert) { \
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+               .name = xname, \
+               .info = snd_ctl_boolean_mono_info, \
+               .get = ac97_switch_get, \
+               .put = ac97_switch_put, \
+               .private_value = ((codec) << 24) | ((invert) << 16) | \
+                                ((bitnr) << 8) | (index), \
+       }
+#define AC97_VOLUME(xname, codec, index) { \
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+               .name = xname, \
+               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
+                         SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
+               .info = ac97_volume_info, \
+               .get = ac97_volume_get, \
+               .put = ac97_volume_put, \
+               .tlv = { .p = ac97_db_scale, }, \
+               .private_value = ((codec) << 24) | (index), \
+       }
+
+static DECLARE_TLV_DB_SCALE(ac97_db_scale, -3450, 150, 0);
+static DECLARE_TLV_DB_SCALE(ac97_rec_db_scale, 0, 150, 0);
+
+static const struct snd_kcontrol_new controls[] = {
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Master Playback Volume",
+               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+               .info = dac_volume_info,
+               .get = dac_volume_get,
+               .put = dac_volume_put,
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Master Playback Switch",
+               .info = snd_ctl_boolean_mono_info,
+               .get = dac_mute_get,
+               .put = dac_mute_put,
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Stereo Upmixing",
+               .info = upmix_info,
+               .get = upmix_get,
+               .put = upmix_put,
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, SWITCH),
+               .info = snd_ctl_boolean_mono_info,
+               .get = spdif_switch_get,
+               .put = spdif_switch_put,
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+               .device = 1,
+               .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT),
+               .info = spdif_info,
+               .get = spdif_default_get,
+               .put = spdif_default_put,
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+               .device = 1,
+               .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, CON_MASK),
+               .access = SNDRV_CTL_ELEM_ACCESS_READ,
+               .info = spdif_info,
+               .get = spdif_mask_get,
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+               .device = 1,
+               .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, PCM_STREAM),
+               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
+                         SNDRV_CTL_ELEM_ACCESS_INACTIVE,
+               .info = spdif_info,
+               .get = spdif_pcm_get,
+               .put = spdif_pcm_put,
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+               .device = 1,
+               .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, MASK),
+               .access = SNDRV_CTL_ELEM_ACCESS_READ,
+               .info = spdif_info,
+               .get = spdif_input_mask_get,
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+               .device = 1,
+               .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, DEFAULT),
+               .access = SNDRV_CTL_ELEM_ACCESS_READ,
+               .info = spdif_info,
+               .get = spdif_input_default_get,
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = SNDRV_CTL_NAME_IEC958("Loopback ", NONE, SWITCH),
+               .info = snd_ctl_boolean_mono_info,
+               .get = spdif_loopback_get,
+               .put = spdif_loopback_put,
+       },
+};
+
+static const struct snd_kcontrol_new ac97_controls[] = {
+       AC97_VOLUME("Mic Capture Volume", 0, AC97_MIC),
+       AC97_SWITCH("Mic Capture Switch", 0, AC97_MIC, 15, 1),
+       AC97_SWITCH("Mic Boost (+20dB)", 0, AC97_MIC, 6, 0),
+       AC97_VOLUME("Line Capture Volume", 0, AC97_LINE),
+       AC97_SWITCH("Line Capture Switch", 0, AC97_LINE, 15, 1),
+       AC97_VOLUME("CD Capture Volume", 0, AC97_CD),
+       AC97_SWITCH("CD Capture Switch", 0, AC97_CD, 15, 1),
+       AC97_VOLUME("Aux Capture Volume", 0, AC97_AUX),
+       AC97_SWITCH("Aux Capture Switch", 0, AC97_AUX, 15, 1),
+};
+
+static const struct snd_kcontrol_new ac97_fp_controls[] = {
+       AC97_VOLUME("Front Panel Playback Volume", 1, AC97_HEADPHONE),
+       AC97_SWITCH("Front Panel Playback Switch", 1, AC97_HEADPHONE, 15, 1),
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Front Panel Capture Volume",
+               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
+                         SNDRV_CTL_ELEM_ACCESS_TLV_READ,
+               .info = ac97_fp_rec_volume_info,
+               .get = ac97_fp_rec_volume_get,
+               .put = ac97_fp_rec_volume_put,
+               .tlv = { .p = ac97_rec_db_scale, },
+       },
+       AC97_SWITCH("Front Panel Capture Switch", 1, AC97_REC_GAIN, 15, 1),
+};
+
+static void oxygen_any_ctl_free(struct snd_kcontrol *ctl)
+{
+       struct oxygen *chip = ctl->private_data;
+       unsigned int i;
+
+       /* I'm too lazy to write a function for each control :-) */
+       for (i = 0; i < ARRAY_SIZE(chip->controls); ++i)
+               chip->controls[i] = NULL;
+}
+
+static int add_controls(struct oxygen *chip,
+                       const struct snd_kcontrol_new controls[],
+                       unsigned int count)
+{
+       static const char *const known_ctl_names[CONTROL_COUNT] = {
+               [CONTROL_SPDIF_PCM] =
+                       SNDRV_CTL_NAME_IEC958("", PLAYBACK, PCM_STREAM),
+               [CONTROL_SPDIF_INPUT_BITS] =
+                       SNDRV_CTL_NAME_IEC958("", CAPTURE, DEFAULT),
+               [CONTROL_MIC_CAPTURE_SWITCH] = "Mic Capture Switch",
+               [CONTROL_LINE_CAPTURE_SWITCH] = "Line Capture Switch",
+               [CONTROL_CD_CAPTURE_SWITCH] = "CD Capture Switch",
+               [CONTROL_AUX_CAPTURE_SWITCH] = "Aux Capture Switch",
+       };
+       unsigned int i, j;
+       struct snd_kcontrol_new template;
+       struct snd_kcontrol *ctl;
+       int err;
+
+       for (i = 0; i < count; ++i) {
+               template = controls[i];
+               err = chip->model->control_filter(&template);
+               if (err < 0)
+                       return err;
+               if (err == 1)
+                       continue;
+               ctl = snd_ctl_new1(&template, chip);
+               if (!ctl)
+                       return -ENOMEM;
+               err = snd_ctl_add(chip->card, ctl);
+               if (err < 0)
+                       return err;
+               for (j = 0; j < CONTROL_COUNT; ++j)
+                       if (!strcmp(ctl->id.name, known_ctl_names[j])) {
+                               chip->controls[j] = ctl;
+                               ctl->private_free = oxygen_any_ctl_free;
+                       }
+       }
+       return 0;
+}
+
+int oxygen_mixer_init(struct oxygen *chip)
+{
+       int err;
+
+       err = add_controls(chip, controls, ARRAY_SIZE(controls));
+       if (err < 0)
+               return err;
+       if (chip->has_ac97_0) {
+               err = add_controls(chip, ac97_controls,
+                                  ARRAY_SIZE(ac97_controls));
+               if (err < 0)
+                       return err;
+       }
+       if (chip->has_ac97_1) {
+               err = add_controls(chip, ac97_fp_controls,
+                                  ARRAY_SIZE(ac97_fp_controls));
+               if (err < 0)
+                       return err;
+       }
+       return chip->model->mixer_init ? chip->model->mixer_init(chip) : 0;
+}
diff --git a/sound/pci/oxygen/oxygen_pcm.c b/sound/pci/oxygen/oxygen_pcm.c
new file mode 100644 (file)
index 0000000..dfad3db
--- /dev/null
@@ -0,0 +1,718 @@
+/*
+ * C-Media CMI8788 driver - PCM code
+ *
+ * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
+ *
+ *
+ *  This driver is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License, version 2.
+ *
+ *  This driver 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 driver; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#include <linux/pci.h>
+#include <sound/control.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include "oxygen.h"
+
+static const struct snd_pcm_hardware oxygen_stereo_hardware = {
+       .info = SNDRV_PCM_INFO_MMAP |
+               SNDRV_PCM_INFO_MMAP_VALID |
+               SNDRV_PCM_INFO_INTERLEAVED |
+               SNDRV_PCM_INFO_PAUSE |
+               SNDRV_PCM_INFO_SYNC_START,
+       .formats = SNDRV_PCM_FMTBIT_S16_LE |
+                  SNDRV_PCM_FMTBIT_S32_LE,
+       .rates = SNDRV_PCM_RATE_32000 |
+                SNDRV_PCM_RATE_44100 |
+                SNDRV_PCM_RATE_48000 |
+                SNDRV_PCM_RATE_64000 |
+                SNDRV_PCM_RATE_88200 |
+                SNDRV_PCM_RATE_96000 |
+                SNDRV_PCM_RATE_176400 |
+                SNDRV_PCM_RATE_192000,
+       .rate_min = 32000,
+       .rate_max = 192000,
+       .channels_min = 2,
+       .channels_max = 2,
+       .buffer_bytes_max = 256 * 1024,
+       .period_bytes_min = 128,
+       .period_bytes_max = 128 * 1024,
+       .periods_min = 2,
+       .periods_max = 2048,
+};
+static const struct snd_pcm_hardware oxygen_multichannel_hardware = {
+       .info = SNDRV_PCM_INFO_MMAP |
+               SNDRV_PCM_INFO_MMAP_VALID |
+               SNDRV_PCM_INFO_INTERLEAVED |
+               SNDRV_PCM_INFO_PAUSE |
+               SNDRV_PCM_INFO_SYNC_START,
+       .formats = SNDRV_PCM_FMTBIT_S16_LE |
+                  SNDRV_PCM_FMTBIT_S32_LE,
+       .rates = SNDRV_PCM_RATE_32000 |
+                SNDRV_PCM_RATE_44100 |
+                SNDRV_PCM_RATE_48000 |
+                SNDRV_PCM_RATE_64000 |
+                SNDRV_PCM_RATE_88200 |
+                SNDRV_PCM_RATE_96000 |
+                SNDRV_PCM_RATE_176400 |
+                SNDRV_PCM_RATE_192000,
+       .rate_min = 32000,
+       .rate_max = 192000,
+       .channels_min = 2,
+       .channels_max = 8,
+       .buffer_bytes_max = 2048 * 1024,
+       .period_bytes_min = 128,
+       .period_bytes_max = 256 * 1024,
+       .periods_min = 2,
+       .periods_max = 16384,
+};
+static const struct snd_pcm_hardware oxygen_ac97_hardware = {
+       .info = SNDRV_PCM_INFO_MMAP |
+               SNDRV_PCM_INFO_MMAP_VALID |
+               SNDRV_PCM_INFO_INTERLEAVED |
+               SNDRV_PCM_INFO_PAUSE |
+               SNDRV_PCM_INFO_SYNC_START,
+       .formats = SNDRV_PCM_FMTBIT_S16_LE,
+       .rates = SNDRV_PCM_RATE_48000,
+       .rate_min = 48000,
+       .rate_max = 48000,
+       .channels_min = 2,
+       .channels_max = 2,
+       .buffer_bytes_max = 256 * 1024,
+       .period_bytes_min = 128,
+       .period_bytes_max = 128 * 1024,
+       .periods_min = 2,
+       .periods_max = 2048,
+};
+
+static const struct snd_pcm_hardware *const oxygen_hardware[PCM_COUNT] = {
+       [PCM_A] = &oxygen_stereo_hardware,
+       [PCM_B] = &oxygen_stereo_hardware,
+       [PCM_C] = &oxygen_stereo_hardware,
+       [PCM_SPDIF] = &oxygen_stereo_hardware,
+       [PCM_MULTICH] = &oxygen_multichannel_hardware,
+       [PCM_AC97] = &oxygen_ac97_hardware,
+};
+
+static inline unsigned int
+oxygen_substream_channel(struct snd_pcm_substream *substream)
+{
+       return (unsigned int)(uintptr_t)substream->runtime->private_data;
+}
+
+static int oxygen_open(struct snd_pcm_substream *substream,
+                      unsigned int channel)
+{
+       struct oxygen *chip = snd_pcm_substream_chip(substream);
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       int err;
+
+       runtime->private_data = (void *)(uintptr_t)channel;
+       if (channel == PCM_B && chip->has_ac97_1 &&
+           (chip->model->used_channels & OXYGEN_CHANNEL_AC97))
+               runtime->hw = oxygen_ac97_hardware;
+       else
+               runtime->hw = *oxygen_hardware[channel];
+       switch (channel) {
+       case PCM_C:
+               runtime->hw.rates &= ~(SNDRV_PCM_RATE_32000 |
+                                      SNDRV_PCM_RATE_64000);
+               runtime->hw.rate_min = 44100;
+               break;
+       case PCM_MULTICH:
+               runtime->hw.channels_max = chip->model->dac_channels;
+               break;
+       }
+       if (chip->model->pcm_hardware_filter)
+               chip->model->pcm_hardware_filter(channel, &runtime->hw);
+       err = snd_pcm_hw_constraint_step(runtime, 0,
+                                        SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 32);
+       if (err < 0)
+               return err;
+       err = snd_pcm_hw_constraint_step(runtime, 0,
+                                        SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 32);
+       if (err < 0)
+               return err;
+       if (runtime->hw.formats & SNDRV_PCM_FMTBIT_S32_LE) {
+               err = snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24);
+               if (err < 0)
+                       return err;
+       }
+       if (runtime->hw.channels_max > 2) {
+               err = snd_pcm_hw_constraint_step(runtime, 0,
+                                                SNDRV_PCM_HW_PARAM_CHANNELS,
+                                                2);
+               if (err < 0)
+                       return err;
+       }
+       snd_pcm_set_sync(substream);
+       chip->streams[channel] = substream;
+
+       mutex_lock(&chip->mutex);
+       chip->pcm_active |= 1 << channel;
+       if (channel == PCM_SPDIF) {
+               chip->spdif_pcm_bits = chip->spdif_bits;
+               chip->controls[CONTROL_SPDIF_PCM]->vd[0].access &=
+                       ~SNDRV_CTL_ELEM_ACCESS_INACTIVE;
+               snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE |
+                              SNDRV_CTL_EVENT_MASK_INFO,
+                              &chip->controls[CONTROL_SPDIF_PCM]->id);
+       }
+       mutex_unlock(&chip->mutex);
+
+       return 0;
+}
+
+static int oxygen_rec_a_open(struct snd_pcm_substream *substream)
+{
+       return oxygen_open(substream, PCM_A);
+}
+
+static int oxygen_rec_b_open(struct snd_pcm_substream *substream)
+{
+       return oxygen_open(substream, PCM_B);
+}
+
+static int oxygen_rec_c_open(struct snd_pcm_substream *substream)
+{
+       return oxygen_open(substream, PCM_C);
+}
+
+static int oxygen_spdif_open(struct snd_pcm_substream *substream)
+{
+       return oxygen_open(substream, PCM_SPDIF);
+}
+
+static int oxygen_multich_open(struct snd_pcm_substream *substream)
+{
+       return oxygen_open(substream, PCM_MULTICH);
+}
+
+static int oxygen_ac97_open(struct snd_pcm_substream *substream)
+{
+       return oxygen_open(substream, PCM_AC97);
+}
+
+static int oxygen_close(struct snd_pcm_substream *substream)
+{
+       struct oxygen *chip = snd_pcm_substream_chip(substream);
+       unsigned int channel = oxygen_substream_channel(substream);
+
+       mutex_lock(&chip->mutex);
+       chip->pcm_active &= ~(1 << channel);
+       if (channel == PCM_SPDIF) {
+               chip->controls[CONTROL_SPDIF_PCM]->vd[0].access |=
+                       SNDRV_CTL_ELEM_ACCESS_INACTIVE;
+               snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE |
+                              SNDRV_CTL_EVENT_MASK_INFO,
+                              &chip->controls[CONTROL_SPDIF_PCM]->id);
+       }
+       if (channel == PCM_SPDIF || channel == PCM_MULTICH)
+               oxygen_update_spdif_source(chip);
+       mutex_unlock(&chip->mutex);
+
+       chip->streams[channel] = NULL;
+       return 0;
+}
+
+static unsigned int oxygen_format(struct snd_pcm_hw_params *hw_params)
+{
+       if (params_format(hw_params) == SNDRV_PCM_FORMAT_S32_LE)
+               return OXYGEN_FORMAT_24;
+       else
+               return OXYGEN_FORMAT_16;
+}
+
+static unsigned int oxygen_rate(struct snd_pcm_hw_params *hw_params)
+{
+       switch (params_rate(hw_params)) {
+       case 32000:
+               return OXYGEN_RATE_32000;
+       case 44100:
+               return OXYGEN_RATE_44100;
+       default: /* 48000 */
+               return OXYGEN_RATE_48000;
+       case 64000:
+               return OXYGEN_RATE_64000;
+       case 88200:
+               return OXYGEN_RATE_88200;
+       case 96000:
+               return OXYGEN_RATE_96000;
+       case 176400:
+               return OXYGEN_RATE_176400;
+       case 192000:
+               return OXYGEN_RATE_192000;
+       }
+}
+
+static unsigned int oxygen_i2s_mclk(struct snd_pcm_hw_params *hw_params)
+{
+       if (params_rate(hw_params) <= 96000)
+               return OXYGEN_I2S_MCLK_256;
+       else
+               return OXYGEN_I2S_MCLK_128;
+}
+
+static unsigned int oxygen_i2s_bits(struct snd_pcm_hw_params *hw_params)
+{
+       if (params_format(hw_params) == SNDRV_PCM_FORMAT_S32_LE)
+               return OXYGEN_I2S_BITS_24;
+       else
+               return OXYGEN_I2S_BITS_16;
+}
+
+static unsigned int oxygen_play_channels(struct snd_pcm_hw_params *hw_params)
+{
+       switch (params_channels(hw_params)) {
+       default: /* 2 */
+               return OXYGEN_PLAY_CHANNELS_2;
+       case 4:
+               return OXYGEN_PLAY_CHANNELS_4;
+       case 6:
+               return OXYGEN_PLAY_CHANNELS_6;
+       case 8:
+               return OXYGEN_PLAY_CHANNELS_8;
+       }
+}
+
+static const unsigned int channel_base_registers[PCM_COUNT] = {
+       [PCM_A] = OXYGEN_DMA_A_ADDRESS,
+       [PCM_B] = OXYGEN_DMA_B_ADDRESS,
+       [PCM_C] = OXYGEN_DMA_C_ADDRESS,
+       [PCM_SPDIF] = OXYGEN_DMA_SPDIF_ADDRESS,
+       [PCM_MULTICH] = OXYGEN_DMA_MULTICH_ADDRESS,
+       [PCM_AC97] = OXYGEN_DMA_AC97_ADDRESS,
+};
+
+static int oxygen_hw_params(struct snd_pcm_substream *substream,
+                           struct snd_pcm_hw_params *hw_params)
+{
+       struct oxygen *chip = snd_pcm_substream_chip(substream);
+       unsigned int channel = oxygen_substream_channel(substream);
+       int err;
+
+       err = snd_pcm_lib_malloc_pages(substream,
+                                      params_buffer_bytes(hw_params));
+       if (err < 0)
+               return err;
+
+       oxygen_write32(chip, channel_base_registers[channel],
+                      (u32)substream->runtime->dma_addr);
+       if (channel == PCM_MULTICH) {
+               oxygen_write32(chip, OXYGEN_DMA_MULTICH_COUNT,
+                              params_buffer_bytes(hw_params) / 4 - 1);
+               oxygen_write32(chip, OXYGEN_DMA_MULTICH_TCOUNT,
+                              params_period_bytes(hw_params) / 4 - 1);
+       } else {
+               oxygen_write16(chip, channel_base_registers[channel] + 4,
+                              params_buffer_bytes(hw_params) / 4 - 1);
+               oxygen_write16(chip, channel_base_registers[channel] + 6,
+                              params_period_bytes(hw_params) / 4 - 1);
+       }
+       return 0;
+}
+
+static int oxygen_rec_a_hw_params(struct snd_pcm_substream *substream,
+                                 struct snd_pcm_hw_params *hw_params)
+{
+       struct oxygen *chip = snd_pcm_substream_chip(substream);
+       int err;
+
+       err = oxygen_hw_params(substream, hw_params);
+       if (err < 0)
+               return err;
+
+       spin_lock_irq(&chip->reg_lock);
+       oxygen_write8_masked(chip, OXYGEN_REC_FORMAT,
+                            oxygen_format(hw_params) << OXYGEN_REC_FORMAT_A_SHIFT,
+                            OXYGEN_REC_FORMAT_A_MASK);
+       oxygen_write16_masked(chip, OXYGEN_I2S_A_FORMAT,
+                             oxygen_rate(hw_params) |
+                             oxygen_i2s_mclk(hw_params) |
+                             chip->model->adc_i2s_format |
+                             oxygen_i2s_bits(hw_params),
+                             OXYGEN_I2S_RATE_MASK |
+                             OXYGEN_I2S_FORMAT_MASK |
+                             OXYGEN_I2S_MCLK_MASK |
+                             OXYGEN_I2S_BITS_MASK);
+       spin_unlock_irq(&chip->reg_lock);
+
+       mutex_lock(&chip->mutex);
+       chip->model->set_adc_params(chip, hw_params);
+       mutex_unlock(&chip->mutex);
+       return 0;
+}
+
+static int oxygen_rec_b_hw_params(struct snd_pcm_substream *substream,
+                                 struct snd_pcm_hw_params *hw_params)
+{
+       struct oxygen *chip = snd_pcm_substream_chip(substream);
+       int is_ac97;
+       int err;
+
+       err = oxygen_hw_params(substream, hw_params);
+       if (err < 0)
+               return err;
+
+       is_ac97 = chip->has_ac97_1 &&
+               (chip->model->used_channels & OXYGEN_CHANNEL_AC97);
+
+       spin_lock_irq(&chip->reg_lock);
+       oxygen_write8_masked(chip, OXYGEN_REC_FORMAT,
+                            oxygen_format(hw_params) << OXYGEN_REC_FORMAT_B_SHIFT,
+                            OXYGEN_REC_FORMAT_B_MASK);
+       if (!is_ac97)
+               oxygen_write16_masked(chip, OXYGEN_I2S_B_FORMAT,
+                                     oxygen_rate(hw_params) |
+                                     oxygen_i2s_mclk(hw_params) |
+                                     chip->model->adc_i2s_format |
+                                     oxygen_i2s_bits(hw_params),
+                                     OXYGEN_I2S_RATE_MASK |
+                                     OXYGEN_I2S_FORMAT_MASK |
+                                     OXYGEN_I2S_MCLK_MASK |
+                                     OXYGEN_I2S_BITS_MASK);
+       spin_unlock_irq(&chip->reg_lock);
+
+       if (!is_ac97) {
+               mutex_lock(&chip->mutex);
+               chip->model->set_adc_params(chip, hw_params);
+               mutex_unlock(&chip->mutex);
+       }
+       return 0;
+}
+
+static int oxygen_rec_c_hw_params(struct snd_pcm_substream *substream,
+                                 struct snd_pcm_hw_params *hw_params)
+{
+       struct oxygen *chip = snd_pcm_substream_chip(substream);
+       int err;
+
+       err = oxygen_hw_params(substream, hw_params);
+       if (err < 0)
+               return err;
+
+       spin_lock_irq(&chip->reg_lock);
+       oxygen_write8_masked(chip, OXYGEN_REC_FORMAT,
+                            oxygen_format(hw_params) << OXYGEN_REC_FORMAT_C_SHIFT,
+                            OXYGEN_REC_FORMAT_C_MASK);
+       spin_unlock_irq(&chip->reg_lock);
+       return 0;
+}
+
+static int oxygen_spdif_hw_params(struct snd_pcm_substream *substream,
+                                 struct snd_pcm_hw_params *hw_params)
+{
+       struct oxygen *chip = snd_pcm_substream_chip(substream);
+       int err;
+
+       err = oxygen_hw_params(substream, hw_params);
+       if (err < 0)
+               return err;
+
+       spin_lock_irq(&chip->reg_lock);
+       oxygen_clear_bits32(chip, OXYGEN_SPDIF_CONTROL,
+                           OXYGEN_SPDIF_OUT_ENABLE);
+       oxygen_write8_masked(chip, OXYGEN_PLAY_FORMAT,
+                            oxygen_format(hw_params) << OXYGEN_SPDIF_FORMAT_SHIFT,
+                            OXYGEN_SPDIF_FORMAT_MASK);
+       oxygen_write32_masked(chip, OXYGEN_SPDIF_CONTROL,
+                             oxygen_rate(hw_params) << OXYGEN_SPDIF_OUT_RATE_SHIFT,
+                             OXYGEN_SPDIF_OUT_RATE_MASK);
+       oxygen_update_spdif_source(chip);
+       spin_unlock_irq(&chip->reg_lock);
+       return 0;
+}
+
+static int oxygen_multich_hw_params(struct snd_pcm_substream *substream,
+                                   struct snd_pcm_hw_params *hw_params)
+{
+       struct oxygen *chip = snd_pcm_substream_chip(substream);
+       int err;
+
+       err = oxygen_hw_params(substream, hw_params);
+       if (err < 0)
+               return err;
+
+       spin_lock_irq(&chip->reg_lock);
+       oxygen_write8_masked(chip, OXYGEN_PLAY_CHANNELS,
+                            oxygen_play_channels(hw_params),
+                            OXYGEN_PLAY_CHANNELS_MASK);
+       oxygen_write8_masked(chip, OXYGEN_PLAY_FORMAT,
+                            oxygen_format(hw_params) << OXYGEN_MULTICH_FORMAT_SHIFT,
+                            OXYGEN_MULTICH_FORMAT_MASK);
+       oxygen_write16_masked(chip, OXYGEN_I2S_MULTICH_FORMAT,
+                             oxygen_rate(hw_params) |
+                             chip->model->dac_i2s_format |
+                             oxygen_i2s_bits(hw_params),
+                             OXYGEN_I2S_RATE_MASK |
+                             OXYGEN_I2S_FORMAT_MASK |
+                             OXYGEN_I2S_BITS_MASK);
+       oxygen_update_dac_routing(chip);
+       oxygen_update_spdif_source(chip);
+       spin_unlock_irq(&chip->reg_lock);
+
+       mutex_lock(&chip->mutex);
+       chip->model->set_dac_params(chip, hw_params);
+       mutex_unlock(&chip->mutex);
+       return 0;
+}
+
+static int oxygen_hw_free(struct snd_pcm_substream *substream)
+{
+       struct oxygen *chip = snd_pcm_substream_chip(substream);
+       unsigned int channel = oxygen_substream_channel(substream);
+
+       spin_lock_irq(&chip->reg_lock);
+       chip->interrupt_mask &= ~(1 << channel);
+       oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, chip->interrupt_mask);
+       spin_unlock_irq(&chip->reg_lock);
+
+       return snd_pcm_lib_free_pages(substream);
+}
+
+static int oxygen_spdif_hw_free(struct snd_pcm_substream *substream)
+{
+       struct oxygen *chip = snd_pcm_substream_chip(substream);
+
+       spin_lock_irq(&chip->reg_lock);
+       oxygen_clear_bits32(chip, OXYGEN_SPDIF_CONTROL,
+                           OXYGEN_SPDIF_OUT_ENABLE);
+       spin_unlock_irq(&chip->reg_lock);
+       return oxygen_hw_free(substream);
+}
+
+static int oxygen_prepare(struct snd_pcm_substream *substream)
+{
+       struct oxygen *chip = snd_pcm_substream_chip(substream);
+       unsigned int channel = oxygen_substream_channel(substream);
+       unsigned int channel_mask = 1 << channel;
+
+       spin_lock_irq(&chip->reg_lock);
+       oxygen_set_bits8(chip, OXYGEN_DMA_FLUSH, channel_mask);
+       oxygen_clear_bits8(chip, OXYGEN_DMA_FLUSH, channel_mask);
+
+       chip->interrupt_mask |= channel_mask;
+       oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, chip->interrupt_mask);
+       spin_unlock_irq(&chip->reg_lock);
+       return 0;
+}
+
+static int oxygen_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+       struct oxygen *chip = snd_pcm_substream_chip(substream);
+       struct snd_pcm_substream *s;
+       unsigned int mask = 0;
+       int pausing;
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_START:
+               pausing = 0;
+               break;
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               pausing = 1;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       snd_pcm_group_for_each_entry(s, substream) {
+               if (snd_pcm_substream_chip(s) == chip) {
+                       mask |= 1 << oxygen_substream_channel(s);
+                       snd_pcm_trigger_done(s, substream);
+               }
+       }
+
+       spin_lock(&chip->reg_lock);
+       if (!pausing) {
+               if (cmd == SNDRV_PCM_TRIGGER_START)
+                       chip->pcm_running |= mask;
+               else
+                       chip->pcm_running &= ~mask;
+               oxygen_write8(chip, OXYGEN_DMA_STATUS, chip->pcm_running);
+       } else {
+               if (cmd == SNDRV_PCM_TRIGGER_PAUSE_PUSH)
+                       oxygen_set_bits8(chip, OXYGEN_DMA_PAUSE, mask);
+               else
+                       oxygen_clear_bits8(chip, OXYGEN_DMA_PAUSE, mask);
+       }
+       spin_unlock(&chip->reg_lock);
+       return 0;
+}
+
+static snd_pcm_uframes_t oxygen_pointer(struct snd_pcm_substream *substream)
+{
+       struct oxygen *chip = snd_pcm_substream_chip(substream);
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       unsigned int channel = oxygen_substream_channel(substream);
+       u32 curr_addr;
+
+       /* no spinlock, this read should be atomic */
+       curr_addr = oxygen_read32(chip, channel_base_registers[channel]);
+       return bytes_to_frames(runtime, curr_addr - (u32)runtime->dma_addr);
+}
+
+static struct snd_pcm_ops oxygen_rec_a_ops = {
+       .open      = oxygen_rec_a_open,
+       .close     = oxygen_close,
+       .ioctl     = snd_pcm_lib_ioctl,
+       .hw_params = oxygen_rec_a_hw_params,
+       .hw_free   = oxygen_hw_free,
+       .prepare   = oxygen_prepare,
+       .trigger   = oxygen_trigger,
+       .pointer   = oxygen_pointer,
+};
+
+static struct snd_pcm_ops oxygen_rec_b_ops = {
+       .open      = oxygen_rec_b_open,
+       .close     = oxygen_close,
+       .ioctl     = snd_pcm_lib_ioctl,
+       .hw_params = oxygen_rec_b_hw_params,
+       .hw_free   = oxygen_hw_free,
+       .prepare   = oxygen_prepare,
+       .trigger   = oxygen_trigger,
+       .pointer   = oxygen_pointer,
+};
+
+static struct snd_pcm_ops oxygen_rec_c_ops = {
+       .open      = oxygen_rec_c_open,
+       .close     = oxygen_close,
+       .ioctl     = snd_pcm_lib_ioctl,
+       .hw_params = oxygen_rec_c_hw_params,
+       .hw_free   = oxygen_hw_free,
+       .prepare   = oxygen_prepare,
+       .trigger   = oxygen_trigger,
+       .pointer   = oxygen_pointer,
+};
+
+static struct snd_pcm_ops oxygen_spdif_ops = {
+       .open      = oxygen_spdif_open,
+       .close     = oxygen_close,
+       .ioctl     = snd_pcm_lib_ioctl,
+       .hw_params = oxygen_spdif_hw_params,
+       .hw_free   = oxygen_spdif_hw_free,
+       .prepare   = oxygen_prepare,
+       .trigger   = oxygen_trigger,
+       .pointer   = oxygen_pointer,
+};
+
+static struct snd_pcm_ops oxygen_multich_ops = {
+       .open      = oxygen_multich_open,
+       .close     = oxygen_close,
+       .ioctl     = snd_pcm_lib_ioctl,
+       .hw_params = oxygen_multich_hw_params,
+       .hw_free   = oxygen_hw_free,
+       .prepare   = oxygen_prepare,
+       .trigger   = oxygen_trigger,
+       .pointer   = oxygen_pointer,
+};
+
+static struct snd_pcm_ops oxygen_ac97_ops = {
+       .open      = oxygen_ac97_open,
+       .close     = oxygen_close,
+       .ioctl     = snd_pcm_lib_ioctl,
+       .hw_params = oxygen_hw_params,
+       .hw_free   = oxygen_hw_free,
+       .prepare   = oxygen_prepare,
+       .trigger   = oxygen_trigger,
+       .pointer   = oxygen_pointer,
+};
+
+static void oxygen_pcm_free(struct snd_pcm *pcm)
+{
+       snd_pcm_lib_preallocate_free_for_all(pcm);
+}
+
+int __devinit oxygen_pcm_init(struct oxygen *chip)
+{
+       struct snd_pcm *pcm;
+       int outs, ins;
+       int err;
+
+       outs = 1; /* OXYGEN_CHANNEL_MULTICH is always used */
+       ins = !!(chip->model->used_channels & (OXYGEN_CHANNEL_A |
+                                              OXYGEN_CHANNEL_B));
+       err = snd_pcm_new(chip->card, "Analog", 0, outs, ins, &pcm);
+       if (err < 0)
+               return err;
+       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &oxygen_multich_ops);
+       if (chip->model->used_channels & OXYGEN_CHANNEL_A)
+               snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
+                               &oxygen_rec_a_ops);
+       else if (chip->model->used_channels & OXYGEN_CHANNEL_B)
+               snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
+                               &oxygen_rec_b_ops);
+       pcm->private_data = chip;
+       pcm->private_free = oxygen_pcm_free;
+       strcpy(pcm->name, "Analog");
+       snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream,
+                                     SNDRV_DMA_TYPE_DEV,
+                                     snd_dma_pci_data(chip->pci),
+                                     512 * 1024, 2048 * 1024);
+       if (ins)
+               snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream,
+                                             SNDRV_DMA_TYPE_DEV,
+                                             snd_dma_pci_data(chip->pci),
+                                             128 * 1024, 256 * 1024);
+
+       outs = !!(chip->model->used_channels & OXYGEN_CHANNEL_SPDIF);
+       ins = !!(chip->model->used_channels & OXYGEN_CHANNEL_C);
+       if (outs | ins) {
+               err = snd_pcm_new(chip->card, "Digital", 1, outs, ins, &pcm);
+               if (err < 0)
+                       return err;
+               if (outs)
+                       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+                                       &oxygen_spdif_ops);
+               if (ins)
+                       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
+                                       &oxygen_rec_c_ops);
+               pcm->private_data = chip;
+               pcm->private_free = oxygen_pcm_free;
+               strcpy(pcm->name, "Digital");
+               snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+                                                     snd_dma_pci_data(chip->pci),
+                                                     128 * 1024, 256 * 1024);
+       }
+
+       outs = chip->has_ac97_1 &&
+               (chip->model->used_channels & OXYGEN_CHANNEL_AC97);
+       ins = outs ||
+               (chip->model->used_channels & (OXYGEN_CHANNEL_A |
+                                              OXYGEN_CHANNEL_B))
+               == (OXYGEN_CHANNEL_A | OXYGEN_CHANNEL_B);
+       if (outs | ins) {
+               err = snd_pcm_new(chip->card, outs ? "AC97" : "Analog2",
+                                 2, outs, ins, &pcm);
+               if (err < 0)
+                       return err;
+               if (outs) {
+                       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+                                       &oxygen_ac97_ops);
+                       oxygen_write8_masked(chip, OXYGEN_REC_ROUTING,
+                                            OXYGEN_REC_B_ROUTE_AC97_1,
+                                            OXYGEN_REC_B_ROUTE_MASK);
+               }
+               if (ins)
+                       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
+                                       &oxygen_rec_b_ops);
+               pcm->private_data = chip;
+               pcm->private_free = oxygen_pcm_free;
+               strcpy(pcm->name, outs ? "Front Panel" : "Analog 2");
+               snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+                                                     snd_dma_pci_data(chip->pci),
+                                                     128 * 1024, 256 * 1024);
+       }
+       return 0;
+}
diff --git a/sound/pci/oxygen/oxygen_regs.h b/sound/pci/oxygen/oxygen_regs.h
new file mode 100644 (file)
index 0000000..72de159
--- /dev/null
@@ -0,0 +1,453 @@
+#ifndef OXYGEN_REGS_H_INCLUDED
+#define OXYGEN_REGS_H_INCLUDED
+
+/* recording channel A */
+#define OXYGEN_DMA_A_ADDRESS           0x00    /* 32-bit base address */
+#define OXYGEN_DMA_A_COUNT             0x04    /* buffer counter (dwords) */
+#define OXYGEN_DMA_A_TCOUNT            0x06    /* interrupt counter (dwords) */
+
+/* recording channel B */
+#define OXYGEN_DMA_B_ADDRESS           0x08
+#define OXYGEN_DMA_B_COUNT             0x0c
+#define OXYGEN_DMA_B_TCOUNT            0x0e
+
+/* recording channel C */
+#define OXYGEN_DMA_C_ADDRESS           0x10
+#define OXYGEN_DMA_C_COUNT             0x14
+#define OXYGEN_DMA_C_TCOUNT            0x16
+
+/* SPDIF playback channel */
+#define OXYGEN_DMA_SPDIF_ADDRESS       0x18
+#define OXYGEN_DMA_SPDIF_COUNT         0x1c
+#define OXYGEN_DMA_SPDIF_TCOUNT                0x1e
+
+/* multichannel playback channel */
+#define OXYGEN_DMA_MULTICH_ADDRESS     0x20
+#define OXYGEN_DMA_MULTICH_COUNT       0x24    /* 24 bits */
+#define OXYGEN_DMA_MULTICH_TCOUNT      0x28    /* 24 bits */
+
+/* AC'97 (front panel) playback channel */
+#define OXYGEN_DMA_AC97_ADDRESS                0x30
+#define OXYGEN_DMA_AC97_COUNT          0x34
+#define OXYGEN_DMA_AC97_TCOUNT         0x36
+
+/* all registers 0x00..0x36 return current position on read */
+
+#define OXYGEN_DMA_STATUS              0x40    /* 1 = running, 0 = stop */
+#define  OXYGEN_CHANNEL_A              0x01
+#define  OXYGEN_CHANNEL_B              0x02
+#define  OXYGEN_CHANNEL_C              0x04
+#define  OXYGEN_CHANNEL_SPDIF          0x08
+#define  OXYGEN_CHANNEL_MULTICH                0x10
+#define  OXYGEN_CHANNEL_AC97           0x20
+
+#define OXYGEN_DMA_PAUSE               0x41    /* 1 = pause */
+/* OXYGEN_CHANNEL_* */
+
+#define OXYGEN_DMA_RESET               0x42
+/* OXYGEN_CHANNEL_* */
+
+#define OXYGEN_PLAY_CHANNELS           0x43
+#define  OXYGEN_PLAY_CHANNELS_MASK     0x03
+#define  OXYGEN_PLAY_CHANNELS_2                0x00
+#define  OXYGEN_PLAY_CHANNELS_4                0x01
+#define  OXYGEN_PLAY_CHANNELS_6                0x02
+#define  OXYGEN_PLAY_CHANNELS_8                0x03
+#define  OXYGEN_DMA_A_BURST_MASK       0x04
+#define  OXYGEN_DMA_A_BURST_8          0x00    /* dwords */
+#define  OXYGEN_DMA_A_BURST_16         0x04
+#define  OXYGEN_DMA_MULTICH_BURST_MASK 0x08
+#define  OXYGEN_DMA_MULTICH_BURST_8    0x00
+#define  OXYGEN_DMA_MULTICH_BURST_16   0x08
+
+#define OXYGEN_INTERRUPT_MASK          0x44
+/* OXYGEN_CHANNEL_* */
+#define  OXYGEN_INT_SPDIF_IN_DETECT    0x0100
+#define  OXYGEN_INT_MCU                        0x0200
+#define  OXYGEN_INT_2WIRE              0x0400
+#define  OXYGEN_INT_GPIO               0x0800
+#define  OXYGEN_INT_MCB                        0x2000
+#define  OXYGEN_INT_AC97               0x4000
+
+#define OXYGEN_INTERRUPT_STATUS                0x46
+/* OXYGEN_CHANNEL_* amd OXYGEN_INT_* */
+#define  OXYGEN_INT_MIDI               0x1000
+
+#define OXYGEN_MISC                    0x48
+#define  OXYGEN_MISC_WRITE_PCI_SUBID   0x01
+#define  OXYGEN_MISC_LATENCY_3F                0x02
+#define  OXYGEN_MISC_REC_C_FROM_SPDIF  0x04
+#define  OXYGEN_MISC_REC_B_FROM_AC97   0x08
+#define  OXYGEN_MISC_REC_A_FROM_MULTICH        0x10
+#define  OXYGEN_MISC_PCI_MEM_W_1_CLOCK 0x20
+#define  OXYGEN_MISC_MIDI              0x40
+#define  OXYGEN_MISC_CRYSTAL_MASK      0x80
+#define  OXYGEN_MISC_CRYSTAL_24576     0x00
+#define  OXYGEN_MISC_CRYSTAL_27                0x80    /* MHz */
+
+#define OXYGEN_REC_FORMAT              0x4a
+#define  OXYGEN_REC_FORMAT_A_MASK      0x03
+#define  OXYGEN_REC_FORMAT_A_SHIFT     0
+#define  OXYGEN_REC_FORMAT_B_MASK      0x0c
+#define  OXYGEN_REC_FORMAT_B_SHIFT     2
+#define  OXYGEN_REC_FORMAT_C_MASK      0x30
+#define  OXYGEN_REC_FORMAT_C_SHIFT     4
+#define  OXYGEN_FORMAT_16              0x00
+#define  OXYGEN_FORMAT_24              0x01
+#define  OXYGEN_FORMAT_32              0x02
+
+#define OXYGEN_PLAY_FORMAT             0x4b
+#define  OXYGEN_SPDIF_FORMAT_MASK      0x03
+#define  OXYGEN_SPDIF_FORMAT_SHIFT     0
+#define  OXYGEN_MULTICH_FORMAT_MASK    0x0c
+#define  OXYGEN_MULTICH_FORMAT_SHIFT   2
+/* OXYGEN_FORMAT_* */
+
+#define OXYGEN_REC_CHANNELS            0x4c
+#define  OXYGEN_REC_CHANNELS_MASK      0x07
+#define  OXYGEN_REC_CHANNELS_2_2_2     0x00    /* DMA A, B, C */
+#define  OXYGEN_REC_CHANNELS_4_2_2     0x01
+#define  OXYGEN_REC_CHANNELS_6_0_2     0x02
+#define  OXYGEN_REC_CHANNELS_6_2_0     0x03
+#define  OXYGEN_REC_CHANNELS_8_0_0     0x04
+
+#define OXYGEN_FUNCTION                        0x50
+#define  OXYGEN_FUNCTION_CLOCK_MASK    0x01
+#define  OXYGEN_FUNCTION_CLOCK_PLL     0x00
+#define  OXYGEN_FUNCTION_CLOCK_CRYSTAL 0x01
+#define  OXYGEN_FUNCTION_RESET_CODEC   0x02
+#define  OXYGEN_FUNCTION_RESET_POL     0x04
+#define  OXYGEN_FUNCTION_PWDN          0x08
+#define  OXYGEN_FUNCTION_PWDN_EN       0x10
+#define  OXYGEN_FUNCTION_PWDN_POL      0x20
+#define  OXYGEN_FUNCTION_2WIRE_SPI_MASK        0x40
+#define  OXYGEN_FUNCTION_SPI           0x00
+#define  OXYGEN_FUNCTION_2WIRE         0x40
+#define  OXYGEN_FUNCTION_ENABLE_SPI_4_5        0x80    /* 0 = EEPROM */
+
+#define OXYGEN_I2S_MULTICH_FORMAT      0x60
+#define  OXYGEN_I2S_RATE_MASK          0x0007  /* LRCK */
+#define  OXYGEN_RATE_32000             0x0000
+#define  OXYGEN_RATE_44100             0x0001
+#define  OXYGEN_RATE_48000             0x0002
+#define  OXYGEN_RATE_64000             0x0003
+#define  OXYGEN_RATE_88200             0x0004
+#define  OXYGEN_RATE_96000             0x0005
+#define  OXYGEN_RATE_176400            0x0006
+#define  OXYGEN_RATE_192000            0x0007
+#define  OXYGEN_I2S_FORMAT_MASK                0x0008
+#define  OXYGEN_I2S_FORMAT_I2S         0x0000
+#define  OXYGEN_I2S_FORMAT_LJUST       0x0008
+#define  OXYGEN_I2S_MCLK_MASK          0x0030  /* MCLK/LRCK */
+#define  OXYGEN_I2S_MCLK_128           0x0000
+#define  OXYGEN_I2S_MCLK_256           0x0010
+#define  OXYGEN_I2S_MCLK_512           0x0020
+#define  OXYGEN_I2S_BITS_MASK          0x00c0
+#define  OXYGEN_I2S_BITS_16            0x0000
+#define  OXYGEN_I2S_BITS_20            0x0040
+#define  OXYGEN_I2S_BITS_24            0x0080
+#define  OXYGEN_I2S_BITS_32            0x00c0
+#define  OXYGEN_I2S_MASTER             0x0100
+#define  OXYGEN_I2S_BCLK_MASK          0x0600  /* BCLK/LRCK */
+#define  OXYGEN_I2S_BCLK_64            0x0000
+#define  OXYGEN_I2S_BCLK_128           0x0200
+#define  OXYGEN_I2S_BCLK_256           0x0400
+#define  OXYGEN_I2S_MUTE_MCLK          0x0800
+
+#define OXYGEN_I2S_A_FORMAT            0x62
+#define OXYGEN_I2S_B_FORMAT            0x64
+#define OXYGEN_I2S_C_FORMAT            0x66
+/* like OXYGEN_I2S_MULTICH_FORMAT */
+
+#define OXYGEN_SPDIF_CONTROL           0x70
+#define  OXYGEN_SPDIF_OUT_ENABLE       0x00000002
+#define  OXYGEN_SPDIF_LOOPBACK         0x00000004      /* in to out */
+#define  OXYGEN_SPDIF_SENSE_MASK       0x00000008
+#define  OXYGEN_SPDIF_LOCK_MASK                0x00000010
+#define  OXYGEN_SPDIF_RATE_MASK                0x00000020
+#define  OXYGEN_SPDIF_SPDVALID         0x00000040
+#define  OXYGEN_SPDIF_SENSE_PAR                0x00000200
+#define  OXYGEN_SPDIF_LOCK_PAR         0x00000400
+#define  OXYGEN_SPDIF_SENSE_STATUS     0x00000800
+#define  OXYGEN_SPDIF_LOCK_STATUS      0x00001000
+#define  OXYGEN_SPDIF_SENSE_INT                0x00002000      /* r/wc */
+#define  OXYGEN_SPDIF_LOCK_INT         0x00004000      /* r/wc */
+#define  OXYGEN_SPDIF_RATE_INT         0x00008000      /* r/wc */
+#define  OXYGEN_SPDIF_IN_CLOCK_MASK    0x00010000
+#define  OXYGEN_SPDIF_IN_CLOCK_96      0x00000000      /* <= 96 kHz */
+#define  OXYGEN_SPDIF_IN_CLOCK_192     0x00010000      /* > 96 kHz */
+#define  OXYGEN_SPDIF_OUT_RATE_MASK    0x07000000
+#define  OXYGEN_SPDIF_OUT_RATE_SHIFT   24
+/* OXYGEN_RATE_* << OXYGEN_SPDIF_OUT_RATE_SHIFT */
+
+#define OXYGEN_SPDIF_OUTPUT_BITS       0x74
+#define  OXYGEN_SPDIF_NONAUDIO         0x00000002
+#define  OXYGEN_SPDIF_C                        0x00000004
+#define  OXYGEN_SPDIF_PREEMPHASIS      0x00000008
+#define  OXYGEN_SPDIF_CATEGORY_MASK    0x000007f0
+#define  OXYGEN_SPDIF_CATEGORY_SHIFT   4
+#define  OXYGEN_SPDIF_ORIGINAL         0x00000800
+#define  OXYGEN_SPDIF_CS_RATE_MASK     0x0000f000
+#define  OXYGEN_SPDIF_CS_RATE_SHIFT    12
+#define  OXYGEN_SPDIF_V                        0x00010000      /* 0 = valid */
+
+#define OXYGEN_SPDIF_INPUT_BITS                0x78
+/* 32 bits, IEC958_AES_* */
+
+#define OXYGEN_EEPROM_CONTROL          0x80
+#define  OXYGEN_EEPROM_ADDRESS_MASK    0x7f
+#define  OXYGEN_EEPROM_DIR_MASK                0x80
+#define  OXYGEN_EEPROM_DIR_READ                0x00
+#define  OXYGEN_EEPROM_DIR_WRITE       0x80
+
+#define OXYGEN_EEPROM_STATUS           0x81
+#define  OXYGEN_EEPROM_VALID           0x40
+#define  OXYGEN_EEPROM_BUSY            0x80
+
+#define OXYGEN_EEPROM_DATA             0x82    /* 16 bits */
+
+#define OXYGEN_2WIRE_CONTROL           0x90
+#define  OXYGEN_2WIRE_DIR_MASK         0x01
+#define  OXYGEN_2WIRE_DIR_WRITE                0x00
+#define  OXYGEN_2WIRE_DIR_READ         0x01
+#define  OXYGEN_2WIRE_ADDRESS_MASK     0xfe    /* slave device address */
+#define  OXYGEN_2WIRE_ADDRESS_SHIFT    1
+
+#define OXYGEN_2WIRE_MAP               0x91    /* address, 8 bits */
+#define OXYGEN_2WIRE_DATA              0x92    /* data, 16 bits */
+
+#define OXYGEN_2WIRE_BUS_STATUS                0x94
+#define  OXYGEN_2WIRE_BUSY             0x0001
+#define  OXYGEN_2WIRE_LENGTH_MASK      0x0002
+#define  OXYGEN_2WIRE_LENGTH_8         0x0000
+#define  OXYGEN_2WIRE_LENGTH_16                0x0002
+#define  OXYGEN_2WIRE_MANUAL_READ      0x0004  /* 0 = auto read */
+#define  OXYGEN_2WIRE_WRITE_MAP_ONLY   0x0008
+#define  OXYGEN_2WIRE_SLAVE_AD_MASK    0x0030  /* AD0, AD1 */
+#define  OXYGEN_2WIRE_INTERRUPT_MASK   0x0040  /* 0 = int. if not responding */
+#define  OXYGEN_2WIRE_SLAVE_NO_RESPONSE        0x0080
+#define  OXYGEN_2WIRE_SPEED_MASK       0x0100
+#define  OXYGEN_2WIRE_SPEED_STANDARD   0x0000
+#define  OXYGEN_2WIRE_SPEED_FAST       0x0100
+#define  OXYGEN_2WIRE_CLOCK_SYNC       0x0200
+#define  OXYGEN_2WIRE_BUS_RESET                0x0400
+
+#define OXYGEN_SPI_CONTROL             0x98
+#define  OXYGEN_SPI_BUSY               0x01    /* read */
+#define  OXYGEN_SPI_TRIGGER            0x01    /* write */
+#define  OXYGEN_SPI_DATA_LENGTH_MASK   0x02
+#define  OXYGEN_SPI_DATA_LENGTH_2      0x00
+#define  OXYGEN_SPI_DATA_LENGTH_3      0x02
+#define  OXYGEN_SPI_CLOCK_MASK         0xc0
+#define  OXYGEN_SPI_CLOCK_160          0x00    /* ns */
+#define  OXYGEN_SPI_CLOCK_320          0x40
+#define  OXYGEN_SPI_CLOCK_640          0x80
+#define  OXYGEN_SPI_CLOCK_1280         0xc0
+#define  OXYGEN_SPI_CODEC_MASK         0x70    /* 0..5 */
+#define  OXYGEN_SPI_CODEC_SHIFT                4
+#define  OXYGEN_SPI_CEN_MASK           0x80
+#define  OXYGEN_SPI_CEN_LATCH_CLOCK_LO 0x00
+#define  OXYGEN_SPI_CEN_LATCH_CLOCK_HI 0x80
+
+#define OXYGEN_SPI_DATA1               0x99
+#define OXYGEN_SPI_DATA2               0x9a
+#define OXYGEN_SPI_DATA3               0x9b
+
+#define OXYGEN_MPU401                  0xa0
+
+#define OXYGEN_MPU401_CONTROL          0xa2
+#define  OXYGEN_MPU401_LOOPBACK                0x01    /* TXD to RXD */
+
+#define OXYGEN_GPI_DATA                        0xa4
+/* bits 0..5 = pin XGPI0..XGPI5 */
+
+#define OXYGEN_GPI_INTERRUPT_MASK      0xa5
+/* bits 0..5, 1 = enable */
+
+#define OXYGEN_GPIO_DATA               0xa6
+/* bits 0..9 */
+
+#define OXYGEN_GPIO_CONTROL            0xa8
+/* bits 0..9, 0 = input, 1 = output */
+#define  OXYGEN_GPIO1_XSLAVE_RDY       0x8000
+
+#define OXYGEN_GPIO_INTERRUPT_MASK     0xaa
+/* bits 0..9, 1 = enable */
+
+#define OXYGEN_DEVICE_SENSE            0xac
+#define  OXYGEN_HEAD_PHONE_DETECT      0x01
+#define  OXYGEN_HEAD_PHONE_MASK                0x06
+#define  OXYGEN_HEAD_PHONE_PASSIVE_SPK 0x00
+#define  OXYGEN_HEAD_PHONE_HP          0x02
+#define  OXYGEN_HEAD_PHONE_ACTIVE_SPK  0x04
+
+#define OXYGEN_MCU_2WIRE_DATA          0xb0
+
+#define OXYGEN_MCU_2WIRE_MAP           0xb2
+
+#define OXYGEN_MCU_2WIRE_STATUS                0xb3
+#define  OXYGEN_MCU_2WIRE_BUSY         0x01
+#define  OXYGEN_MCU_2WIRE_LENGTH_MASK  0x06
+#define  OXYGEN_MCU_2WIRE_LENGTH_1     0x00
+#define  OXYGEN_MCU_2WIRE_LENGTH_2     0x02
+#define  OXYGEN_MCU_2WIRE_LENGTH_3     0x04
+#define  OXYGEN_MCU_2WIRE_WRITE                0x08    /* r/wc */
+#define  OXYGEN_MCU_2WIRE_READ         0x10    /* r/wc */
+#define  OXYGEN_MCU_2WIRE_DRV_XACT_FAIL        0x20    /* r/wc */
+#define  OXYGEN_MCU_2WIRE_RESET                0x40
+
+#define OXYGEN_MCU_2WIRE_CONTROL       0xb4
+#define  OXYGEN_MCU_2WIRE_DRV_ACK      0x01
+#define  OXYGEN_MCU_2WIRE_DRV_XACT     0x02
+#define  OXYGEN_MCU_2WIRE_INT_MASK     0x04
+#define  OXYGEN_MCU_2WIRE_SYNC_MASK    0x08
+#define  OXYGEN_MCU_2WIRE_SYNC_RDY_PIN 0x00
+#define  OXYGEN_MCU_2WIRE_SYNC_DATA    0x08
+#define  OXYGEN_MCU_2WIRE_ADDRESS_MASK 0x30
+#define  OXYGEN_MCU_2WIRE_ADDRESS_10   0x00
+#define  OXYGEN_MCU_2WIRE_ADDRESS_12   0x10
+#define  OXYGEN_MCU_2WIRE_ADDRESS_14   0x20
+#define  OXYGEN_MCU_2WIRE_ADDRESS_16   0x30
+#define  OXYGEN_MCU_2WIRE_INT_POL      0x40
+#define  OXYGEN_MCU_2WIRE_SYNC_ENABLE  0x80
+
+#define OXYGEN_PLAY_ROUTING            0xc0
+#define  OXYGEN_PLAY_MUTE01            0x0001
+#define  OXYGEN_PLAY_MUTE23            0x0002
+#define  OXYGEN_PLAY_MUTE45            0x0004
+#define  OXYGEN_PLAY_MUTE67            0x0008
+#define  OXYGEN_PLAY_MULTICH_MASK      0x0010
+#define  OXYGEN_PLAY_MULTICH_I2S_DAC   0x0000
+#define  OXYGEN_PLAY_MULTICH_AC97      0x0010
+#define  OXYGEN_PLAY_SPDIF_MASK                0x00e0
+#define  OXYGEN_PLAY_SPDIF_SPDIF       0x0000
+#define  OXYGEN_PLAY_SPDIF_MULTICH_01  0x0020
+#define  OXYGEN_PLAY_SPDIF_MULTICH_23  0x0040
+#define  OXYGEN_PLAY_SPDIF_MULTICH_45  0x0060
+#define  OXYGEN_PLAY_SPDIF_MULTICH_67  0x0080
+#define  OXYGEN_PLAY_SPDIF_REC_A       0x00a0
+#define  OXYGEN_PLAY_SPDIF_REC_B       0x00c0
+#define  OXYGEN_PLAY_SPDIF_I2S_ADC_3   0x00e0
+#define  OXYGEN_PLAY_DAC0_SOURCE_MASK  0x0300
+#define  OXYGEN_PLAY_DAC0_SOURCE_SHIFT 8
+#define  OXYGEN_PLAY_DAC1_SOURCE_MASK  0x0c00
+#define  OXYGEN_PLAY_DAC1_SOURCE_SHIFT 10
+#define  OXYGEN_PLAY_DAC2_SOURCE_MASK  0x3000
+#define  OXYGEN_PLAY_DAC2_SOURCE_SHIFT 12
+#define  OXYGEN_PLAY_DAC3_SOURCE_MASK  0xc000
+#define  OXYGEN_PLAY_DAC3_SOURCE_SHIFT 14
+
+#define OXYGEN_REC_ROUTING             0xc2
+#define  OXYGEN_MUTE_I2S_ADC_1         0x01
+#define  OXYGEN_MUTE_I2S_ADC_2         0x02
+#define  OXYGEN_MUTE_I2S_ADC_3         0x04
+#define  OXYGEN_REC_A_ROUTE_MASK       0x08
+#define  OXYGEN_REC_A_ROUTE_I2S_ADC_1  0x00
+#define  OXYGEN_REC_A_ROUTE_AC97_0     0x08
+#define  OXYGEN_REC_B_ROUTE_MASK       0x10
+#define  OXYGEN_REC_B_ROUTE_I2S_ADC_2  0x00
+#define  OXYGEN_REC_B_ROUTE_AC97_1     0x10
+#define  OXYGEN_REC_C_ROUTE_MASK       0x20
+#define  OXYGEN_REC_C_ROUTE_SPDIF      0x00
+#define  OXYGEN_REC_C_ROUTE_I2S_ADC_3  0x20
+
+#define OXYGEN_ADC_MONITOR             0xc3
+#define  OXYGEN_ADC_MONITOR_A          0x01
+#define  OXYGEN_ADC_MONITOR_A_HALF_VOL 0x02
+#define  OXYGEN_ADC_MONITOR_B          0x04
+#define  OXYGEN_ADC_MONITOR_B_HALF_VOL 0x08
+#define  OXYGEN_ADC_MONITOR_C          0x10
+#define  OXYGEN_ADC_MONITOR_C_HALF_VOL 0x20
+
+#define OXYGEN_A_MONITOR_ROUTING       0xc4
+#define  OXYGEN_A_MONITOR_ROUTE_0_MASK 0x03
+#define  OXYGEN_A_MONITOR_ROUTE_0_SHIFT        0
+#define  OXYGEN_A_MONITOR_ROUTE_1_MASK 0x0c
+#define  OXYGEN_A_MONITOR_ROUTE_1_SHIFT        2
+#define  OXYGEN_A_MONITOR_ROUTE_2_MASK 0x30
+#define  OXYGEN_A_MONITOR_ROUTE_2_SHIFT        4
+#define  OXYGEN_A_MONITOR_ROUTE_3_MASK 0xc0
+#define  OXYGEN_A_MONITOR_ROUTE_3_SHIFT        6
+
+#define OXYGEN_AC97_CONTROL            0xd0
+#define  OXYGEN_AC97_COLD_RESET                0x0001
+#define  OXYGEN_AC97_SUSPENDED         0x0002  /* read */
+#define  OXYGEN_AC97_RESUME            0x0002  /* write */
+#define  OXYGEN_AC97_CLOCK_DISABLE     0x0004
+#define  OXYGEN_AC97_NO_CODEC_0                0x0008
+#define  OXYGEN_AC97_CODEC_0           0x0010
+#define  OXYGEN_AC97_CODEC_1           0x0020
+
+#define OXYGEN_AC97_INTERRUPT_MASK     0xd2
+#define  OXYGEN_AC97_INT_READ_DONE     0x01
+#define  OXYGEN_AC97_INT_WRITE_DONE    0x02
+#define  OXYGEN_AC97_INT_CODEC_0       0x10
+#define  OXYGEN_AC97_INT_CODEC_1       0x20
+
+#define OXYGEN_AC97_INTERRUPT_STATUS   0xd3
+/* OXYGEN_AC97_INT_* */
+
+#define OXYGEN_AC97_OUT_CONFIG         0xd4
+#define  OXYGEN_AC97_CODEC1_SLOT3      0x00000001
+#define  OXYGEN_AC97_CODEC1_SLOT3_VSR  0x00000002
+#define  OXYGEN_AC97_CODEC1_SLOT4      0x00000010
+#define  OXYGEN_AC97_CODEC1_SLOT4_VSR  0x00000020
+#define  OXYGEN_AC97_CODEC0_FRONTL     0x00000100
+#define  OXYGEN_AC97_CODEC0_FRONTR     0x00000200
+#define  OXYGEN_AC97_CODEC0_SIDEL      0x00000400
+#define  OXYGEN_AC97_CODEC0_SIDER      0x00000800
+#define  OXYGEN_AC97_CODEC0_CENTER     0x00001000
+#define  OXYGEN_AC97_CODEC0_BASE       0x00002000
+#define  OXYGEN_AC97_CODEC0_REARL      0x00004000
+#define  OXYGEN_AC97_CODEC0_REARR      0x00008000
+
+#define OXYGEN_AC97_IN_CONFIG          0xd8
+#define  OXYGEN_AC97_CODEC1_LINEL      0x00000001
+#define  OXYGEN_AC97_CODEC1_LINEL_VSR  0x00000002
+#define  OXYGEN_AC97_CODEC1_LINEL_16   0x00000000
+#define  OXYGEN_AC97_CODEC1_LINEL_18   0x00000004
+#define  OXYGEN_AC97_CODEC1_LINEL_20   0x00000008
+#define  OXYGEN_AC97_CODEC1_LINER      0x00000010
+#define  OXYGEN_AC97_CODEC1_LINER_VSR  0x00000020
+#define  OXYGEN_AC97_CODEC1_LINER_16   0x00000000
+#define  OXYGEN_AC97_CODEC1_LINER_18   0x00000040
+#define  OXYGEN_AC97_CODEC1_LINER_20   0x00000080
+#define  OXYGEN_AC97_CODEC0_LINEL      0x00000100
+#define  OXYGEN_AC97_CODEC0_LINER      0x00000200
+
+#define OXYGEN_AC97_REGS               0xdc
+#define  OXYGEN_AC97_REG_DATA_MASK     0x0000ffff
+#define  OXYGEN_AC97_REG_ADDR_MASK     0x007f0000
+#define  OXYGEN_AC97_REG_ADDR_SHIFT    16
+#define  OXYGEN_AC97_REG_DIR_MASK      0x00800000
+#define  OXYGEN_AC97_REG_DIR_WRITE     0x00000000
+#define  OXYGEN_AC97_REG_DIR_READ      0x00800000
+#define  OXYGEN_AC97_REG_CODEC_MASK    0x01000000
+#define  OXYGEN_AC97_REG_CODEC_SHIFT   24
+
+#define OXYGEN_TEST                    0xe0
+#define  OXYGEN_TEST_RAM_SUCCEEDED     0x01
+#define  OXYGEN_TEST_PLAYBACK_RAM      0x02
+#define  OXYGEN_TEST_RECORD_RAM                0x04
+#define  OXYGEN_TEST_PLL               0x08
+#define  OXYGEN_TEST_2WIRE_LOOPBACK    0x10
+
+#define OXYGEN_DMA_FLUSH               0xe1
+/* OXYGEN_CHANNEL_* */
+
+#define OXYGEN_CODEC_VERSION           0xe4
+#define  OXYGEN_XCID_MASK              0x07
+
+#define OXYGEN_REVISION                        0xe6
+#define  OXYGEN_REVISION_XPKGID_MASK   0x0007
+#define  OXYGEN_REVISION_MASK          0xfff8
+#define  OXYGEN_REVISION_2             0x0008  /* bit flag */
+#define  OXYGEN_REVISION_8787          0x0014  /* 8 bits */
+
+#define OXYGEN_OFFSIN_48K              0xe8
+#define OXYGEN_OFFSBASE_48K            0xe9
+#define  OXYGEN_OFFSBASE_MASK          0x0fff
+#define OXYGEN_OFFSIN_44K              0xec
+#define OXYGEN_OFFSBASE_44K            0xed
+
+#endif
diff --git a/sound/pci/oxygen/virtuoso.c b/sound/pci/oxygen/virtuoso.c
new file mode 100644 (file)
index 0000000..40e92f5
--- /dev/null
@@ -0,0 +1,449 @@
+/*
+ * C-Media CMI8788 driver for Asus Xonar cards
+ *
+ * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
+ *
+ *
+ *  This driver is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License, version 2.
+ *
+ *  This driver 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 driver; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+/*
+ * CMI8788:
+ *
+ * SPI 0 -> 1st PCM1796 (front)
+ * SPI 1 -> 2nd PCM1796 (surround)
+ * SPI 2 -> 3rd PCM1796 (center/LFE)
+ * SPI 4 -> 4th PCM1796 (back)
+ *
+ * GPIO 2 -> M0 of CS5381
+ * GPIO 3 -> M1 of CS5381
+ * GPIO 5 <- external power present (D2X only)
+ * GPIO 7 -> ALT
+ * GPIO 8 -> enable output to speakers
+ *
+ * CM9780:
+ *
+ * GPIO 0 -> enable AC'97 bypass (line in -> ADC)
+ */
+
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <sound/ac97_codec.h>
+#include <sound/control.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include <sound/tlv.h>
+#include "oxygen.h"
+#include "cm9780.h"
+
+MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
+MODULE_DESCRIPTION("Asus AV200 driver");
+MODULE_LICENSE("GPL");
+MODULE_SUPPORTED_DEVICE("{{Asus,AV200}}");
+
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
+static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
+
+module_param_array(index, int, NULL, 0444);
+MODULE_PARM_DESC(index, "card index");
+module_param_array(id, charp, NULL, 0444);
+MODULE_PARM_DESC(id, "ID string");
+module_param_array(enable, bool, NULL, 0444);
+MODULE_PARM_DESC(enable, "enable card");
+
+static struct pci_device_id xonar_ids[] __devinitdata = {
+       { OXYGEN_PCI_SUBID(0x1043, 0x8269) }, /* Asus Xonar D2 */
+       { OXYGEN_PCI_SUBID(0x1043, 0x82b7) }, /* Asus Xonar D2X */
+       { }
+};
+MODULE_DEVICE_TABLE(pci, xonar_ids);
+
+
+#define GPIO_CS5381_M_MASK     0x000c
+#define GPIO_CS5381_M_SINGLE   0x0000
+#define GPIO_CS5381_M_DOUBLE   0x0004
+#define GPIO_CS5381_M_QUAD     0x0008
+#define GPIO_EXT_POWER         0x0020
+#define GPIO_ALT               0x0080
+#define GPIO_OUTPUT_ENABLE     0x0100
+
+#define GPIO_LINE_MUTE         CM9780_GPO0
+
+/* register 16 */
+#define PCM1796_ATL_MASK       0xff
+/* register 17 */
+#define PCM1796_ATR_MASK       0xff
+/* register 18 */
+#define PCM1796_MUTE           0x01
+#define PCM1796_DME            0x02
+#define PCM1796_DMF_MASK       0x0c
+#define PCM1796_DMF_DISABLED   0x00
+#define PCM1796_DMF_48         0x04
+#define PCM1796_DMF_441                0x08
+#define PCM1796_DMF_32         0x0c
+#define PCM1796_FMT_MASK       0x70
+#define PCM1796_FMT_16_RJUST   0x00
+#define PCM1796_FMT_20_RJUST   0x10
+#define PCM1796_FMT_24_RJUST   0x20
+#define PCM1796_FMT_24_LJUST   0x30
+#define PCM1796_FMT_16_I2S     0x40
+#define PCM1796_FMT_24_I2S     0x50
+#define PCM1796_ATLD           0x80
+/* register 19 */
+#define PCM1796_INZD           0x01
+#define PCM1796_FLT_MASK       0x02
+#define PCM1796_FLT_SHARP      0x00
+#define PCM1796_FLT_SLOW       0x02
+#define PCM1796_DFMS           0x04
+#define PCM1796_OPE            0x10
+#define PCM1796_ATS_MASK       0x60
+#define PCM1796_ATS_1          0x00
+#define PCM1796_ATS_2          0x20
+#define PCM1796_ATS_4          0x40
+#define PCM1796_ATS_8          0x60
+#define PCM1796_REV            0x80
+/* register 20 */
+#define PCM1796_OS_MASK                0x03
+#define PCM1796_OS_64          0x00
+#define PCM1796_OS_32          0x01
+#define PCM1796_OS_128         0x02
+#define PCM1796_CHSL_MASK      0x04
+#define PCM1796_CHSL_LEFT      0x00
+#define PCM1796_CHSL_RIGHT     0x04
+#define PCM1796_MONO           0x08
+#define PCM1796_DFTH           0x10
+#define PCM1796_DSD            0x20
+#define PCM1796_SRST           0x40
+/* register 21 */
+#define PCM1796_PCMZ           0x01
+#define PCM1796_DZ_MASK                0x06
+/* register 22 */
+#define PCM1796_ZFGL           0x01
+#define PCM1796_ZFGR           0x02
+/* register 23 */
+#define PCM1796_ID_MASK                0x1f
+
+struct xonar_data {
+       u8 is_d2x;
+       u8 has_power;
+};
+
+static void pcm1796_write(struct oxygen *chip, unsigned int codec,
+                         u8 reg, u8 value)
+{
+       /* maps ALSA channel pair number to SPI output */
+       static const u8 codec_map[4] = {
+               0, 1, 2, 4
+       };
+       oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER  |
+                        OXYGEN_SPI_DATA_LENGTH_2 |
+                        OXYGEN_SPI_CLOCK_160 |
+                        (codec_map[codec] << OXYGEN_SPI_CODEC_SHIFT) |
+                        OXYGEN_SPI_CEN_LATCH_CLOCK_HI,
+                        (reg << 8) | value);
+}
+
+static void xonar_init(struct oxygen *chip)
+{
+       struct xonar_data *data = chip->model_data;
+       unsigned int i;
+
+       data->is_d2x = chip->pci->subsystem_device == 0x82b7;
+
+       for (i = 0; i < 4; ++i) {
+               pcm1796_write(chip, i, 18, PCM1796_FMT_24_LJUST | PCM1796_ATLD);
+               pcm1796_write(chip, i, 19, PCM1796_FLT_SHARP | PCM1796_ATS_1);
+               pcm1796_write(chip, i, 20, PCM1796_OS_64);
+               pcm1796_write(chip, i, 21, 0);
+               pcm1796_write(chip, i, 16, 0xff); /* set ATL/ATR after ATLD */
+               pcm1796_write(chip, i, 17, 0xff);
+       }
+
+       oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL,
+                         GPIO_CS5381_M_MASK | GPIO_ALT);
+       oxygen_write16_masked(chip, OXYGEN_GPIO_DATA,
+                             GPIO_CS5381_M_SINGLE,
+                             GPIO_CS5381_M_MASK | GPIO_ALT);
+       if (data->is_d2x) {
+               oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL,
+                                   GPIO_EXT_POWER);
+               oxygen_set_bits16(chip, OXYGEN_GPIO_INTERRUPT_MASK,
+                                 GPIO_EXT_POWER);
+               chip->interrupt_mask |= OXYGEN_INT_GPIO;
+               data->has_power = !!(oxygen_read16(chip, OXYGEN_GPIO_DATA)
+                                    & GPIO_EXT_POWER);
+       }
+       oxygen_ac97_set_bits(chip, 0, CM9780_JACK, CM9780_FMIC2MIC);
+       oxygen_ac97_clear_bits(chip, 0, CM9780_GPIO_STATUS, GPIO_LINE_MUTE);
+       msleep(300);
+       oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_OUTPUT_ENABLE);
+       oxygen_set_bits16(chip, OXYGEN_GPIO_DATA, GPIO_OUTPUT_ENABLE);
+
+       snd_component_add(chip->card, "PCM1796");
+       snd_component_add(chip->card, "CS5381");
+}
+
+static void xonar_cleanup(struct oxygen *chip)
+{
+       oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_OUTPUT_ENABLE);
+}
+
+static void set_pcm1796_params(struct oxygen *chip,
+                              struct snd_pcm_hw_params *params)
+{
+#if 0
+       unsigned int i;
+       u8 value;
+
+       value = params_rate(params) >= 96000 ? PCM1796_OS_32 : PCM1796_OS_64;
+       for (i = 0; i < 4; ++i)
+               pcm1796_write(chip, i, 20, value);
+#endif
+}
+
+static void update_pcm1796_volume(struct oxygen *chip)
+{
+       unsigned int i;
+
+       for (i = 0; i < 4; ++i) {
+               pcm1796_write(chip, i, 16, chip->dac_volume[i * 2]);
+               pcm1796_write(chip, i, 17, chip->dac_volume[i * 2 + 1]);
+       }
+}
+
+static void update_pcm1796_mute(struct oxygen *chip)
+{
+       unsigned int i;
+       u8 value;
+
+       value = PCM1796_FMT_24_LJUST | PCM1796_ATLD;
+       if (chip->dac_mute)
+               value |= PCM1796_MUTE;
+       for (i = 0; i < 4; ++i)
+               pcm1796_write(chip, i, 18, value);
+}
+
+static void set_cs5381_params(struct oxygen *chip,
+                             struct snd_pcm_hw_params *params)
+{
+       unsigned int value;
+
+       if (params_rate(params) <= 54000)
+               value = GPIO_CS5381_M_SINGLE;
+       else if (params_rate(params) <= 108000)
+               value = GPIO_CS5381_M_DOUBLE;
+       else
+               value = GPIO_CS5381_M_QUAD;
+       oxygen_write16_masked(chip, OXYGEN_GPIO_DATA,
+                             value, GPIO_CS5381_M_MASK);
+}
+
+static void xonar_gpio_changed(struct oxygen *chip)
+{
+       struct xonar_data *data = chip->model_data;
+       u8 has_power;
+
+       if (!data->is_d2x)
+               return;
+       has_power = !!(oxygen_read16(chip, OXYGEN_GPIO_DATA)
+                      & GPIO_EXT_POWER);
+       if (has_power != data->has_power) {
+               data->has_power = has_power;
+               if (has_power) {
+                       snd_printk(KERN_NOTICE "power restored\n");
+               } else {
+                       snd_printk(KERN_CRIT
+                                  "Hey! Don't unplug the power cable!\n");
+                       /* TODO: stop PCMs */
+               }
+       }
+}
+
+static void mute_ac97_ctl(struct oxygen *chip, unsigned int control)
+{
+       unsigned int index = chip->controls[control]->private_value & 0xff;
+       u16 value;
+
+       value = oxygen_read_ac97(chip, 0, index);
+       if (!(value & 0x8000)) {
+               oxygen_write_ac97(chip, 0, index, value | 0x8000);
+               snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
+                              &chip->controls[control]->id);
+       }
+}
+
+static void xonar_ac97_switch_hook(struct oxygen *chip, unsigned int codec,
+                                  unsigned int reg, int mute)
+{
+       if (codec != 0)
+               return;
+       /* line-in is exclusive */
+       switch (reg) {
+       case AC97_LINE:
+               oxygen_write_ac97_masked(chip, 0, CM9780_GPIO_STATUS,
+                                        mute ? GPIO_LINE_MUTE : 0,
+                                        GPIO_LINE_MUTE);
+               if (!mute) {
+                       mute_ac97_ctl(chip, CONTROL_MIC_CAPTURE_SWITCH);
+                       mute_ac97_ctl(chip, CONTROL_CD_CAPTURE_SWITCH);
+                       mute_ac97_ctl(chip, CONTROL_AUX_CAPTURE_SWITCH);
+               }
+               break;
+       case AC97_MIC:
+       case AC97_CD:
+       case AC97_VIDEO:
+       case AC97_AUX:
+               if (!mute) {
+                       oxygen_ac97_set_bits(chip, 0, CM9780_GPIO_STATUS,
+                                            GPIO_LINE_MUTE);
+                       mute_ac97_ctl(chip, CONTROL_LINE_CAPTURE_SWITCH);
+               }
+               break;
+       }
+}
+
+static int pcm1796_volume_info(struct snd_kcontrol *ctl,
+                              struct snd_ctl_elem_info *info)
+{
+       info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       info->count = 8;
+       info->value.integer.min = 0x0f;
+       info->value.integer.max = 0xff;
+       return 0;
+}
+
+static int alt_switch_get(struct snd_kcontrol *ctl,
+                         struct snd_ctl_elem_value *value)
+{
+       struct oxygen *chip = ctl->private_data;
+
+       value->value.integer.value[0] =
+               !!(oxygen_read16(chip, OXYGEN_GPIO_DATA) & GPIO_ALT);
+       return 0;
+}
+
+static int alt_switch_put(struct snd_kcontrol *ctl,
+                         struct snd_ctl_elem_value *value)
+{
+       struct oxygen *chip = ctl->private_data;
+       u16 old_bits, new_bits;
+       int changed;
+
+       spin_lock_irq(&chip->reg_lock);
+       old_bits = oxygen_read16(chip, OXYGEN_GPIO_DATA);
+       if (value->value.integer.value[0])
+               new_bits = old_bits | GPIO_ALT;
+       else
+               new_bits = old_bits & ~GPIO_ALT;
+       changed = new_bits != old_bits;
+       if (changed)
+               oxygen_write16(chip, OXYGEN_GPIO_DATA, new_bits);
+       spin_unlock_irq(&chip->reg_lock);
+       return changed;
+}
+
+static const struct snd_kcontrol_new alt_switch = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name = "Analog Loopback Switch",
+       .info = snd_ctl_boolean_mono_info,
+       .get = alt_switch_get,
+       .put = alt_switch_put,
+};
+
+static const DECLARE_TLV_DB_SCALE(pcm1796_db_scale, -12000, 50, 0);
+
+static int xonar_control_filter(struct snd_kcontrol_new *template)
+{
+       if (!strcmp(template->name, "Master Playback Volume")) {
+               template->access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ;
+               template->info = pcm1796_volume_info,
+               template->tlv.p = pcm1796_db_scale;
+       } else if (!strncmp(template->name, "CD Capture ", 11)) {
+               /* CD in is actually connected to the video in pin */
+               template->private_value ^= AC97_CD ^ AC97_VIDEO;
+       } else if (!strcmp(template->name, "Line Capture Volume")) {
+               return 1; /* line-in bypasses the AC'97 mixer */
+       }
+       return 0;
+}
+
+static int xonar_mixer_init(struct oxygen *chip)
+{
+       return snd_ctl_add(chip->card, snd_ctl_new1(&alt_switch, chip));
+}
+
+static const struct oxygen_model model_xonar = {
+       .shortname = "Asus AV200",
+       .longname = "Asus Virtuoso 200",
+       .chip = "AV200",
+       .init = xonar_init,
+       .control_filter = xonar_control_filter,
+       .mixer_init = xonar_mixer_init,
+       .cleanup = xonar_cleanup,
+       .set_dac_params = set_pcm1796_params,
+       .set_adc_params = set_cs5381_params,
+       .update_dac_volume = update_pcm1796_volume,
+       .update_dac_mute = update_pcm1796_mute,
+       .ac97_switch_hook = xonar_ac97_switch_hook,
+       .gpio_changed = xonar_gpio_changed,
+       .model_data_size = sizeof(struct xonar_data),
+       .dac_channels = 8,
+       .used_channels = OXYGEN_CHANNEL_B |
+                        OXYGEN_CHANNEL_C |
+                        OXYGEN_CHANNEL_SPDIF |
+                        OXYGEN_CHANNEL_MULTICH,
+       .function_flags = OXYGEN_FUNCTION_ENABLE_SPI_4_5,
+       .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
+       .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
+};
+
+static int __devinit xonar_probe(struct pci_dev *pci,
+                                const struct pci_device_id *pci_id)
+{
+       static int dev;
+       int err;
+
+       if (dev >= SNDRV_CARDS)
+               return -ENODEV;
+       if (!enable[dev]) {
+               ++dev;
+               return -ENOENT;
+       }
+       err = oxygen_pci_probe(pci, index[dev], id[dev], 1, &model_xonar);
+       if (err >= 0)
+               ++dev;
+       return err;
+}
+
+static struct pci_driver xonar_driver = {
+       .name = "AV200",
+       .id_table = xonar_ids,
+       .probe = xonar_probe,
+       .remove = __devexit_p(oxygen_pci_remove),
+};
+
+static int __init alsa_card_xonar_init(void)
+{
+       return pci_register_driver(&xonar_driver);
+}
+
+static void __exit alsa_card_xonar_exit(void)
+{
+       pci_unregister_driver(&xonar_driver);
+}
+
+module_init(alsa_card_xonar_init)
+module_exit(alsa_card_xonar_exit)
index 2d618bd7e62b70f68719d6216813c8b54e1bf7dd..9d5bb76229a8fc020eb0a9a869ed190b8e17ce87 100644 (file)
@@ -21,7 +21,6 @@
  */
 
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/slab.h>
index 0ff8dc36fde3244d947a6ca8aed9d558942ae69b..c4e415d07380db810db6b3bd27a59ff89aeb76a3 100644 (file)
@@ -20,7 +20,6 @@
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-#include <sound/driver.h>
 #include <linux/delay.h>
 #include <linux/firmware.h>
 #include <linux/interrupt.h>
index d55d8bc90eee96f0302f37e9cda6801010ccd5ae..e6a4bfbb91bb664ed933c3a8c95e286b5876ac83 100644 (file)
@@ -20,7 +20,6 @@
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-#include <sound/driver.h>
 #include <linux/interrupt.h>
 #include <linux/vmalloc.h>
 #include <linux/firmware.h>
index 5f8d42633b040b92a88b173df5ad4222d2bdcd43..aabc7bc5321e89d7c60bbdaaf0624599014aaa73 100644 (file)
@@ -21,7 +21,6 @@
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-#include <sound/driver.h>
 #include <linux/time.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
@@ -120,8 +119,18 @@ static int pcxhr_analog_vol_put(struct snd_kcontrol *kcontrol,
        is_capture = (kcontrol->private_value != 0);
        for (i = 0; i < 2; i++) {
                int  new_volume = ucontrol->value.integer.value[i];
-               int* stored_volume = is_capture ? &chip->analog_capture_volume[i] :
+               int *stored_volume = is_capture ?
+                       &chip->analog_capture_volume[i] :
                        &chip->analog_playback_volume[i];
+               if (is_capture) {
+                       if (new_volume < PCXHR_ANALOG_CAPTURE_LEVEL_MIN ||
+                           new_volume > PCXHR_ANALOG_CAPTURE_LEVEL_MAX)
+                               continue;
+               } else {
+                       if (new_volume < PCXHR_ANALOG_PLAYBACK_LEVEL_MIN ||
+                           new_volume > PCXHR_ANALOG_PLAYBACK_LEVEL_MAX)
+                               continue;
+               }
                if (*stored_volume != new_volume) {
                        *stored_volume = new_volume;
                        changed = 1;
@@ -165,10 +174,13 @@ static int pcxhr_audio_sw_put(struct snd_kcontrol *kcontrol,
        int i, changed = 0;
        mutex_lock(&chip->mgr->mixer_mutex);
        for(i = 0; i < 2; i++) {
-               if (chip->analog_playback_active[i] != ucontrol->value.integer.value[i]) {
-                       chip->analog_playback_active[i] = ucontrol->value.integer.value[i];
+               if (chip->analog_playback_active[i] !=
+                   ucontrol->value.integer.value[i]) {
+                       chip->analog_playback_active[i] =
+                               !!ucontrol->value.integer.value[i];
                        changed = 1;
-                       pcxhr_update_analog_audio_level(chip, 0, i);    /* update playback levels */
+                       /* update playback levels */
+                       pcxhr_update_analog_audio_level(chip, 0, i);
                }
        }
        mutex_unlock(&chip->mgr->mixer_mutex);
@@ -323,20 +335,24 @@ static int pcxhr_pcm_vol_put(struct snd_kcontrol *kcontrol,
        int i;
 
        mutex_lock(&chip->mgr->mixer_mutex);
-       if (is_capture)
-               stored_volume = chip->digital_capture_volume;           /* digital capture */
-       else
-               stored_volume = chip->digital_playback_volume[idx];     /* digital playback */
+       if (is_capture)         /* digital capture */
+               stored_volume = chip->digital_capture_volume;
+       else                    /* digital playback */
+               stored_volume = chip->digital_playback_volume[idx];
        for (i = 0; i < 2; i++) {
-               if (stored_volume[i] != ucontrol->value.integer.value[i]) {
-                       stored_volume[i] = ucontrol->value.integer.value[i];
+               int vol = ucontrol->value.integer.value[i];
+               if (vol < PCXHR_DIGITAL_LEVEL_MIN ||
+                   vol > PCXHR_DIGITAL_LEVEL_MAX)
+                       continue;
+               if (stored_volume[i] != vol) {
+                       stored_volume[i] = vol;
                        changed = 1;
                        if (is_capture) /* update capture volume */
                                pcxhr_update_audio_pipe_level(chip, 1, i);
                }
        }
-       if (! is_capture && changed)
-               pcxhr_update_playback_stream_level(chip, idx);  /* update playback volume */
+       if (!is_capture && changed)     /* update playback volume */
+               pcxhr_update_playback_stream_level(chip, idx);
        mutex_unlock(&chip->mgr->mixer_mutex);
        return changed;
 }
@@ -378,8 +394,10 @@ static int pcxhr_pcm_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_v
        mutex_lock(&chip->mgr->mixer_mutex);
        j = idx;
        for (i = 0; i < 2; i++) {
-               if (chip->digital_playback_active[j][i] != ucontrol->value.integer.value[i]) {
-                       chip->digital_playback_active[j][i] = ucontrol->value.integer.value[i];
+               if (chip->digital_playback_active[j][i] !=
+                   ucontrol->value.integer.value[i]) {
+                       chip->digital_playback_active[j][i] =
+                               !!ucontrol->value.integer.value[i];
                        changed = 1;
                }
        }
@@ -423,10 +441,13 @@ static int pcxhr_monitor_vol_put(struct snd_kcontrol *kcontrol,
 
        mutex_lock(&chip->mgr->mixer_mutex);
        for (i = 0; i < 2; i++) {
-               if (chip->monitoring_volume[i] != ucontrol->value.integer.value[i]) {
-                       chip->monitoring_volume[i] = ucontrol->value.integer.value[i];
-                       if(chip->monitoring_active[i])  /* do only when monitoring is unmuted */
+               if (chip->monitoring_volume[i] !=
+                   ucontrol->value.integer.value[i]) {
+                       chip->monitoring_volume[i] =
+                               !!ucontrol->value.integer.value[i];
+                       if(chip->monitoring_active[i])
                                /* update monitoring volume and mute */
+                               /* do only when monitoring is unmuted */
                                pcxhr_update_audio_pipe_level(chip, 0, i);
                        changed = 1;
                }
@@ -470,15 +491,17 @@ static int pcxhr_monitor_sw_put(struct snd_kcontrol *kcontrol,
 
        mutex_lock(&chip->mgr->mixer_mutex);
        for (i = 0; i < 2; i++) {
-               if (chip->monitoring_active[i] != ucontrol->value.integer.value[i]) {
-                       chip->monitoring_active[i] = ucontrol->value.integer.value[i];
+               if (chip->monitoring_active[i] !=
+                   ucontrol->value.integer.value[i]) {
+                       chip->monitoring_active[i] =
+                               !!ucontrol->value.integer.value[i];
                        changed |= (1<<i); /* mask 0x01 and 0x02 */
                }
        }
-       if(changed & 0x01)
+       if (changed & 0x01)
                /* update left monitoring volume and mute */
                pcxhr_update_audio_pipe_level(chip, 0, 0);
-       if(changed & 0x02)
+       if (changed & 0x02)
                /* update right monitoring volume and mute */
                pcxhr_update_audio_pipe_level(chip, 0, 1);
 
@@ -579,6 +602,8 @@ static int pcxhr_audio_src_put(struct snd_kcontrol *kcontrol,
        struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol);
        int ret = 0;
 
+       if (ucontrol->value.enumerated.item[0] >= 3)
+               return -EINVAL;
        mutex_lock(&chip->mgr->mixer_mutex);
        if (chip->audio_capture_source != ucontrol->value.enumerated.item[0]) {
                chip->audio_capture_source = ucontrol->value.enumerated.item[0];
@@ -642,8 +667,11 @@ static int pcxhr_clock_type_put(struct snd_kcontrol *kcontrol,
                                struct snd_ctl_elem_value *ucontrol)
 {
        struct pcxhr_mgr *mgr = snd_kcontrol_chip(kcontrol);
+       unsigned int clock_items = 3 + mgr->capture_chips;
        int rate, ret = 0;
 
+       if (ucontrol->value.enumerated.item[0] >= clock_items)
+               return -EINVAL;
        mutex_lock(&mgr->mixer_mutex);
        if (mgr->use_clock_type != ucontrol->value.enumerated.item[0]) {
                mutex_lock(&mgr->setup_mutex);
index 8e5410483e67a0f851ea99c9209589739a143282..9408b1eeec40d551615334250d809d8aaf1acdc2 100644 (file)
@@ -88,7 +88,6 @@
             Adopted for Windows NT driver          01/20/98      CNL
 */
 
-#include <sound/driver.h>
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
index 1475912588e9ddb04b5b6e4126f036530f1920a6..df184aabce846e3eb1611b50e3c2e7d92891dbb1 100644 (file)
@@ -69,7 +69,6 @@
  */
 
 
-#include <sound/driver.h>
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
index 0b3c532c4014270e69abe05482e79256777b5af2..fb0a4ee8bc02aaa0c9d3b7a341095a959a158f92 100644 (file)
@@ -23,7 +23,6 @@
  *
  */      
 
-#include <sound/driver.h>
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
@@ -2195,22 +2194,25 @@ snd_rme96_dac_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_valu
 {
        struct rme96 *rme96 = snd_kcontrol_chip(kcontrol);
         int change = 0;
+       unsigned int vol, maxvol;
 
-       if (!RME96_HAS_ANALOG_OUT(rme96)) {
+
+       if (!RME96_HAS_ANALOG_OUT(rme96))
                return -EINVAL;
-       }
+       maxvol = RME96_185X_MAX_OUT(rme96);
        spin_lock_irq(&rme96->lock);
-        if (u->value.integer.value[0] != rme96->vol[0]) {
-               rme96->vol[0] = u->value.integer.value[0];
-                change = 1;
-        }
-        if (u->value.integer.value[1] != rme96->vol[1]) {
-               rme96->vol[1] = u->value.integer.value[1];
-                change = 1;
-        }
-       if (change) {
-               snd_rme96_apply_dac_volume(rme96);
+       vol = u->value.integer.value[0];
+       if (vol != rme96->vol[0] && vol <= maxvol) {
+               rme96->vol[0] = vol;
+               change = 1;
+       }
+       vol = u->value.integer.value[1];
+       if (vol != rme96->vol[1] && vol <= maxvol) {
+               rme96->vol[1] = vol;
+               change = 1;
        }
+       if (change)
+               snd_rme96_apply_dac_volume(rme96);
        spin_unlock_irq(&rme96->lock);
 
         return change;
index ff26a3672d403152b81fe946c71c4b05f601bef4..c2bd4384316a8ad4ccf509dce009b62c241da335 100644 (file)
@@ -21,7 +21,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
@@ -104,8 +103,6 @@ MODULE_FIRMWARE("digiface_firmware_rev11.bin");
 #define HDSP_statusRegister    0
 #define HDSP_timecode        128
 #define HDSP_status2Register 192
-#define HDSP_midiDataOut0    352
-#define HDSP_midiDataOut1    356
 #define HDSP_midiDataIn0     360
 #define HDSP_midiDataIn1     364
 #define HDSP_midiStatusOut0  384
@@ -610,7 +607,10 @@ static int hdsp_playback_to_output_key (struct hdsp *hdsp, int in, int out)
        case Multiface:
        case Digiface:
        default:
-               return (64 * out) + (32 + (in));
+               if (hdsp->firmware_rev == 0xa)
+                       return (64 * out) + (32 + (in));
+               else
+                       return (52 * out) + (26 + (in));
        case H9632:
                return (32 * out) + (16 + (in));
        case H9652:
@@ -624,7 +624,10 @@ static int hdsp_input_to_output_key (struct hdsp *hdsp, int in, int out)
        case Multiface:
        case Digiface:
        default:
-               return (64 * out) + in;
+               if (hdsp->firmware_rev == 0xa)
+                       return (64 * out) + in;
+               else
+                       return (52 * out) + in;
        case H9632:
                return (32 * out) + in;
        case H9652:
@@ -2121,7 +2124,7 @@ static int snd_hdsp_put_clock_source_lock(struct snd_kcontrol *kcontrol, struct
 
        change = (int)ucontrol->value.integer.value[0] != hdsp->clock_source_locked;
        if (change)
-               hdsp->clock_source_locked = ucontrol->value.integer.value[0];
+               hdsp->clock_source_locked = !!ucontrol->value.integer.value[0];
        return change;
 }
 
@@ -3558,7 +3561,7 @@ snd_hdsp_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
 
 }
 
-static void __devinit snd_hdsp_proc_init(struct hdsp *hdsp)
+static void snd_hdsp_proc_init(struct hdsp *hdsp)
 {
        struct snd_info_entry *entry;
 
@@ -3606,7 +3609,7 @@ static int snd_hdsp_set_defaults(struct hdsp *hdsp)
 
        /* ASSUMPTION: hdsp->lock is either held, or
           there is no need to hold it (e.g. during module
-          initalization).
+          initialization).
         */
 
        /* set defaults:
index f1bdda6cbcffd5f384ddf76c96fa47ac963b8c62..9a19ae6a64d9a06f158a2da2f22a761edcd6c730 100644 (file)
@@ -23,7 +23,6 @@
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  *
  */
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
@@ -3348,7 +3347,7 @@ static int snd_hdspm_set_defaults(struct hdspm * hdspm)
        unsigned int i;
 
        /* ASSUMPTION: hdspm->lock is either held, or there is no need to
-          hold it (e.g. during module initalization).
+          hold it (e.g. during module initialization).
         */
 
        /* set defaults:       */
@@ -3416,7 +3415,7 @@ static int snd_hdspm_set_defaults(struct hdspm * hdspm)
 
 
 /*------------------------------------------------------------
-   interupt 
+   interrupt 
  ------------------------------------------------------------*/
 
 static irqreturn_t snd_hdspm_interrupt(int irq, void *dev_id)
index 34f96f12e5bfcad9b909152625fa50ff2efb81ff..a123f0e6ba23386213738dfdb835c7fa5a55353b 100644 (file)
@@ -20,7 +20,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
@@ -148,7 +147,7 @@ MODULE_SUPPORTED_DEVICE("{{RME,Hammerfall},"
 #define RME9652_start_bit         (1<<0)       /* start record/play */
                                                 /* bits 1-3 encode buffersize/latency */
 #define RME9652_Master            (1<<4)       /* Clock Mode Master=1,Slave/Auto=0 */
-#define RME9652_IE                (1<<5)       /* Interupt Enable */
+#define RME9652_IE                (1<<5)       /* Interrupt Enable */
 #define RME9652_freq              (1<<6)       /* samplerate 0=44.1/88.2, 1=48/96 kHz */
 #define RME9652_freq1             (1<<7)       /* if 0, 32kHz, else always 1 */
 #define RME9652_DS                 (1<<8)      /* Doule Speed 0=44.1/48, 1=88.2/96 Khz */
@@ -1826,7 +1825,7 @@ static void snd_rme9652_set_defaults(struct snd_rme9652 *rme9652)
 
        /* ASSUMPTION: rme9652->lock is either held, or
           there is no need to hold it (e.g. during module
-          initalization).
+          initialization).
         */
 
        /* set defaults:
diff --git a/sound/pci/sis7019.c b/sound/pci/sis7019.c
new file mode 100644 (file)
index 0000000..dcd7cd0
--- /dev/null
@@ -0,0 +1,1460 @@
+/*
+ *  Driver for SiS7019 Audio Accelerator
+ *
+ *  Copyright (C) 2004-2007, David Dillow
+ *  Written by David Dillow <dave@thedillows.org>
+ *  Inspired by the Trident 4D-WaveDX/NX driver.
+ *
+ *  All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, version 2.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/time.h>
+#include <linux/moduleparam.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <sound/core.h>
+#include <sound/ac97_codec.h>
+#include <sound/initval.h>
+#include "sis7019.h"
+
+MODULE_AUTHOR("David Dillow <dave@thedillows.org>");
+MODULE_DESCRIPTION("SiS7019");
+MODULE_LICENSE("GPL");
+MODULE_SUPPORTED_DEVICE("{{SiS,SiS7019 Audio Accelerator}}");
+
+static int index = SNDRV_DEFAULT_IDX1; /* Index 0-MAX */
+static char *id = SNDRV_DEFAULT_STR1;  /* ID for this card */
+static int enable = 1;
+
+module_param(index, int, 0444);
+MODULE_PARM_DESC(index, "Index value for SiS7019 Audio Accelerator.");
+module_param(id, charp, 0444);
+MODULE_PARM_DESC(id, "ID string for SiS7019 Audio Accelerator.");
+module_param(enable, bool, 0444);
+MODULE_PARM_DESC(enable, "Enable SiS7019 Audio Accelerator.");
+
+static struct pci_device_id snd_sis7019_ids[] = {
+       { PCI_DEVICE(PCI_VENDOR_ID_SI, 0x7019) },
+       { 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, snd_sis7019_ids);
+
+/* There are three timing modes for the voices.
+ *
+ * For both playback and capture, when the buffer is one or two periods long,
+ * we use the hardware's built-in Mid-Loop Interrupt and End-Loop Interrupt
+ * to let us know when the periods have ended.
+ *
+ * When performing playback with more than two periods per buffer, we set
+ * the "Stop Sample Offset" and tell the hardware to interrupt us when we
+ * reach it. We then update the offset and continue on until we are
+ * interrupted for the next period.
+ *
+ * Capture channels do not have a SSO, so we allocate a playback channel to
+ * use as a timer for the capture periods. We use the SSO on the playback
+ * channel to clock out virtual periods, and adjust the virtual period length
+ * to maintain synchronization. This algorithm came from the Trident driver.
+ *
+ * FIXME: It'd be nice to make use of some of the synth features in the
+ * hardware, but a woeful lack of documentation is a significant roadblock.
+ */
+struct voice {
+       u16 flags;
+#define        VOICE_IN_USE            1
+#define        VOICE_CAPTURE           2
+#define        VOICE_SSO_TIMING        4
+#define        VOICE_SYNC_TIMING       8
+       u16 sync_cso;
+       u16 period_size;
+       u16 buffer_size;
+       u16 sync_period_size;
+       u16 sync_buffer_size;
+       u32 sso;
+       u32 vperiod;
+       struct snd_pcm_substream *substream;
+       struct voice *timing;
+       void __iomem *ctrl_base;
+       void __iomem *wave_base;
+       void __iomem *sync_base;
+       int num;
+};
+
+/* We need four pages to store our wave parameters during a suspend. If
+ * we're not doing power management, we still need to allocate a page
+ * for the silence buffer.
+ */
+#ifdef CONFIG_PM
+#define SIS_SUSPEND_PAGES      4
+#else
+#define SIS_SUSPEND_PAGES      1
+#endif
+
+struct sis7019 {
+       unsigned long ioport;
+       void __iomem *ioaddr;
+       int irq;
+       int codecs_present;
+
+       struct pci_dev *pci;
+       struct snd_pcm *pcm;
+       struct snd_card *card;
+       struct snd_ac97 *ac97[3];
+
+       /* Protect against more than one thread hitting the AC97
+        * registers (in a more polite manner than pounding the hardware
+        * semaphore)
+        */
+       struct mutex ac97_mutex;
+
+       /* voice_lock protects allocation/freeing of the voice descriptions
+        */
+       spinlock_t voice_lock;
+
+       struct voice voices[64];
+       struct voice capture_voice;
+
+       /* Allocate pages to store the internal wave state during
+        * suspends. When we're operating, this can be used as a silence
+        * buffer for a timing channel.
+        */
+       void *suspend_state[SIS_SUSPEND_PAGES];
+
+       int silence_users;
+       dma_addr_t silence_dma_addr;
+};
+
+#define SIS_PRIMARY_CODEC_PRESENT      0x0001
+#define SIS_SECONDARY_CODEC_PRESENT    0x0002
+#define SIS_TERTIARY_CODEC_PRESENT     0x0004
+
+/* The HW offset parameters (Loop End, Stop Sample, End Sample) have a
+ * documented range of 8-0xfff8 samples. Given that they are 0-based,
+ * that places our period/buffer range at 9-0xfff9 samples. That makes the
+ * max buffer size 0xfff9 samples * 2 channels * 2 bytes per sample, and
+ * max samples / min samples gives us the max periods in a buffer.
+ *
+ * We'll add a constraint upon open that limits the period and buffer sample
+ * size to values that are legal for the hardware.
+ */
+static struct snd_pcm_hardware sis_playback_hw_info = {
+       .info = (SNDRV_PCM_INFO_MMAP |
+                SNDRV_PCM_INFO_MMAP_VALID |
+                SNDRV_PCM_INFO_INTERLEAVED |
+                SNDRV_PCM_INFO_BLOCK_TRANSFER |
+                SNDRV_PCM_INFO_SYNC_START |
+                SNDRV_PCM_INFO_RESUME),
+       .formats = (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U8 |
+                   SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE),
+       .rates = SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_CONTINUOUS,
+       .rate_min = 4000,
+       .rate_max = 48000,
+       .channels_min = 1,
+       .channels_max = 2,
+       .buffer_bytes_max = (0xfff9 * 4),
+       .period_bytes_min = 9,
+       .period_bytes_max = (0xfff9 * 4),
+       .periods_min = 1,
+       .periods_max = (0xfff9 / 9),
+};
+
+static struct snd_pcm_hardware sis_capture_hw_info = {
+       .info = (SNDRV_PCM_INFO_MMAP |
+                SNDRV_PCM_INFO_MMAP_VALID |
+                SNDRV_PCM_INFO_INTERLEAVED |
+                SNDRV_PCM_INFO_BLOCK_TRANSFER |
+                SNDRV_PCM_INFO_SYNC_START |
+                SNDRV_PCM_INFO_RESUME),
+       .formats = (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U8 |
+                   SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE),
+       .rates = SNDRV_PCM_RATE_48000,
+       .rate_min = 4000,
+       .rate_max = 48000,
+       .channels_min = 1,
+       .channels_max = 2,
+       .buffer_bytes_max = (0xfff9 * 4),
+       .period_bytes_min = 9,
+       .period_bytes_max = (0xfff9 * 4),
+       .periods_min = 1,
+       .periods_max = (0xfff9 / 9),
+};
+
+static void sis_update_sso(struct voice *voice, u16 period)
+{
+       void __iomem *base = voice->ctrl_base;
+
+       voice->sso += period;
+       if (voice->sso >= voice->buffer_size)
+               voice->sso -= voice->buffer_size;
+
+       /* Enforce the documented hardware minimum offset */
+       if (voice->sso < 8)
+               voice->sso = 8;
+
+       /* The SSO is in the upper 16 bits of the register. */
+       writew(voice->sso & 0xffff, base + SIS_PLAY_DMA_SSO_ESO + 2);
+}
+
+static void sis_update_voice(struct voice *voice)
+{
+       if (voice->flags & VOICE_SSO_TIMING) {
+               sis_update_sso(voice, voice->period_size);
+       } else if (voice->flags & VOICE_SYNC_TIMING) {
+               int sync;
+
+               /* If we've not hit the end of the virtual period, update
+                * our records and keep going.
+                */
+               if (voice->vperiod > voice->period_size) {
+                       voice->vperiod -= voice->period_size;
+                       if (voice->vperiod < voice->period_size)
+                               sis_update_sso(voice, voice->vperiod);
+                       else
+                               sis_update_sso(voice, voice->period_size);
+                       return;
+               }
+
+               /* Calculate our relative offset between the target and
+                * the actual CSO value. Since we're operating in a loop,
+                * if the value is more than half way around, we can
+                * consider ourselves wrapped.
+                */
+               sync = voice->sync_cso;
+               sync -= readw(voice->sync_base + SIS_CAPTURE_DMA_FORMAT_CSO);
+               if (sync > (voice->sync_buffer_size / 2))
+                       sync -= voice->sync_buffer_size;
+
+               /* If sync is positive, then we interrupted too early, and
+                * we'll need to come back in a few samples and try again.
+                * There's a minimum wait, as it takes some time for the DMA
+                * engine to startup, etc...
+                */
+               if (sync > 0) {
+                       if (sync < 16)
+                               sync = 16;
+                       sis_update_sso(voice, sync);
+                       return;
+               }
+
+               /* Ok, we interrupted right on time, or (hopefully) just
+                * a bit late. We'll adjst our next waiting period based
+                * on how close we got.
+                *
+                * We need to stay just behind the actual channel to ensure
+                * it really is past a period when we get our interrupt --
+                * otherwise we'll fall into the early code above and have
+                * a minimum wait time, which makes us quite late here,
+                * eating into the user's time to refresh the buffer, esp.
+                * if using small periods.
+                *
+                * If we're less than 9 samples behind, we're on target.
+                */
+               if (sync > -9)
+                       voice->vperiod = voice->sync_period_size + 1;
+               else
+                       voice->vperiod = voice->sync_period_size - 4;
+
+               if (voice->vperiod < voice->buffer_size) {
+                       sis_update_sso(voice, voice->vperiod);
+                       voice->vperiod = 0;
+               } else
+                       sis_update_sso(voice, voice->period_size);
+
+               sync = voice->sync_cso + voice->sync_period_size;
+               if (sync >= voice->sync_buffer_size)
+                       sync -= voice->sync_buffer_size;
+               voice->sync_cso = sync;
+       }
+
+       snd_pcm_period_elapsed(voice->substream);
+}
+
+static void sis_voice_irq(u32 status, struct voice *voice)
+{
+       int bit;
+
+       while (status) {
+               bit = __ffs(status);
+               status >>= bit + 1;
+               voice += bit;
+               sis_update_voice(voice);
+               voice++;
+       }
+}
+
+static irqreturn_t sis_interrupt(int irq, void *dev)
+{
+       struct sis7019 *sis = dev;
+       unsigned long io = sis->ioport;
+       struct voice *voice;
+       u32 intr, status;
+
+       /* We only use the DMA interrupts, and we don't enable any other
+        * source of interrupts. But, it is possible to see an interupt
+        * status that didn't actually interrupt us, so eliminate anything
+        * we're not expecting to avoid falsely claiming an IRQ, and an
+        * ensuing endless loop.
+        */
+       intr = inl(io + SIS_GISR);
+       intr &= SIS_GISR_AUDIO_PLAY_DMA_IRQ_STATUS |
+               SIS_GISR_AUDIO_RECORD_DMA_IRQ_STATUS;
+       if (!intr)
+               return IRQ_NONE;
+
+       do {
+               status = inl(io + SIS_PISR_A);
+               if (status) {
+                       sis_voice_irq(status, sis->voices);
+                       outl(status, io + SIS_PISR_A);
+               }
+
+               status = inl(io + SIS_PISR_B);
+               if (status) {
+                       sis_voice_irq(status, &sis->voices[32]);
+                       outl(status, io + SIS_PISR_B);
+               }
+
+               status = inl(io + SIS_RISR);
+               if (status) {
+                       voice = &sis->capture_voice;
+                       if (!voice->timing)
+                               snd_pcm_period_elapsed(voice->substream);
+
+                       outl(status, io + SIS_RISR);
+               }
+
+               outl(intr, io + SIS_GISR);
+               intr = inl(io + SIS_GISR);
+               intr &= SIS_GISR_AUDIO_PLAY_DMA_IRQ_STATUS |
+                       SIS_GISR_AUDIO_RECORD_DMA_IRQ_STATUS;
+       } while (intr);
+
+       return IRQ_HANDLED;
+}
+
+static u32 sis_rate_to_delta(unsigned int rate)
+{
+       u32 delta;
+
+       /* This was copied from the trident driver, but it seems its gotten
+        * around a bit... nevertheless, it works well.
+        *
+        * We special case 44100 and 8000 since rounding with the equation
+        * does not give us an accurate enough value. For 11025 and 22050
+        * the equation gives us the best answer. All other frequencies will
+        * also use the equation. JDW
+        */
+       if (rate == 44100)
+               delta = 0xeb3;
+       else if (rate == 8000)
+               delta = 0x2ab;
+       else if (rate == 48000)
+               delta = 0x1000;
+       else
+               delta = (((rate << 12) + 24000) / 48000) & 0x0000ffff;
+       return delta;
+}
+
+static void __sis_map_silence(struct sis7019 *sis)
+{
+       /* Helper function: must hold sis->voice_lock on entry */
+       if (!sis->silence_users)
+               sis->silence_dma_addr = pci_map_single(sis->pci,
+                                               sis->suspend_state[0],
+                                               4096, PCI_DMA_TODEVICE);
+       sis->silence_users++;
+}
+
+static void __sis_unmap_silence(struct sis7019 *sis)
+{
+       /* Helper function: must hold sis->voice_lock on entry */
+       sis->silence_users--;
+       if (!sis->silence_users)
+               pci_unmap_single(sis->pci, sis->silence_dma_addr, 4096,
+                                       PCI_DMA_TODEVICE);
+}
+
+static void sis_free_voice(struct sis7019 *sis, struct voice *voice)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&sis->voice_lock, flags);
+       if (voice->timing) {
+               __sis_unmap_silence(sis);
+               voice->timing->flags &= ~(VOICE_IN_USE | VOICE_SSO_TIMING |
+                                               VOICE_SYNC_TIMING);
+               voice->timing = NULL;
+       }
+       voice->flags &= ~(VOICE_IN_USE | VOICE_SSO_TIMING | VOICE_SYNC_TIMING);
+       spin_unlock_irqrestore(&sis->voice_lock, flags);
+}
+
+static struct voice *__sis_alloc_playback_voice(struct sis7019 *sis)
+{
+       /* Must hold the voice_lock on entry */
+       struct voice *voice;
+       int i;
+
+       for (i = 0; i < 64; i++) {
+               voice = &sis->voices[i];
+               if (voice->flags & VOICE_IN_USE)
+                       continue;
+               voice->flags |= VOICE_IN_USE;
+               goto found_one;
+       }
+       voice = NULL;
+
+found_one:
+       return voice;
+}
+
+static struct voice *sis_alloc_playback_voice(struct sis7019 *sis)
+{
+       struct voice *voice;
+       unsigned long flags;
+
+       spin_lock_irqsave(&sis->voice_lock, flags);
+       voice = __sis_alloc_playback_voice(sis);
+       spin_unlock_irqrestore(&sis->voice_lock, flags);
+
+       return voice;
+}
+
+static int sis_alloc_timing_voice(struct snd_pcm_substream *substream,
+                                       struct snd_pcm_hw_params *hw_params)
+{
+       struct sis7019 *sis = snd_pcm_substream_chip(substream);
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct voice *voice = runtime->private_data;
+       unsigned int period_size, buffer_size;
+       unsigned long flags;
+       int needed;
+
+       /* If there are one or two periods per buffer, we don't need a
+        * timing voice, as we can use the capture channel's interrupts
+        * to clock out the periods.
+        */
+       period_size = params_period_size(hw_params);
+       buffer_size = params_buffer_size(hw_params);
+       needed = (period_size != buffer_size &&
+                       period_size != (buffer_size / 2));
+
+       if (needed && !voice->timing) {
+               spin_lock_irqsave(&sis->voice_lock, flags);
+               voice->timing = __sis_alloc_playback_voice(sis);
+               if (voice->timing)
+                       __sis_map_silence(sis);
+               spin_unlock_irqrestore(&sis->voice_lock, flags);
+               if (!voice->timing)
+                       return -ENOMEM;
+               voice->timing->substream = substream;
+       } else if (!needed && voice->timing) {
+               sis_free_voice(sis, voice);
+               voice->timing = NULL;
+       }
+
+       return 0;
+}
+
+static int sis_playback_open(struct snd_pcm_substream *substream)
+{
+       struct sis7019 *sis = snd_pcm_substream_chip(substream);
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct voice *voice;
+
+       voice = sis_alloc_playback_voice(sis);
+       if (!voice)
+               return -EAGAIN;
+
+       voice->substream = substream;
+       runtime->private_data = voice;
+       runtime->hw = sis_playback_hw_info;
+       snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
+                                               9, 0xfff9);
+       snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
+                                               9, 0xfff9);
+       snd_pcm_set_sync(substream);
+       return 0;
+}
+
+static int sis_substream_close(struct snd_pcm_substream *substream)
+{
+       struct sis7019 *sis = snd_pcm_substream_chip(substream);
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct voice *voice = runtime->private_data;
+
+       sis_free_voice(sis, voice);
+       return 0;
+}
+
+static int sis_playback_hw_params(struct snd_pcm_substream *substream,
+                                       struct snd_pcm_hw_params *hw_params)
+{
+       return snd_pcm_lib_malloc_pages(substream,
+                                       params_buffer_bytes(hw_params));
+}
+
+static int sis_hw_free(struct snd_pcm_substream *substream)
+{
+       return snd_pcm_lib_free_pages(substream);
+}
+
+static int sis_pcm_playback_prepare(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct voice *voice = runtime->private_data;
+       void __iomem *ctrl_base = voice->ctrl_base;
+       void __iomem *wave_base = voice->wave_base;
+       u32 format, dma_addr, control, sso_eso, delta, reg;
+       u16 leo;
+
+       /* We rely on the PCM core to ensure that the parameters for this
+        * substream do not change on us while we're programming the HW.
+        */
+       format = 0;
+       if (snd_pcm_format_width(runtime->format) == 8)
+               format |= SIS_PLAY_DMA_FORMAT_8BIT;
+       if (!snd_pcm_format_signed(runtime->format))
+               format |= SIS_PLAY_DMA_FORMAT_UNSIGNED;
+       if (runtime->channels == 1)
+               format |= SIS_PLAY_DMA_FORMAT_MONO;
+
+       /* The baseline setup is for a single period per buffer, and
+        * we add bells and whistles as needed from there.
+        */
+       dma_addr = runtime->dma_addr;
+       leo = runtime->buffer_size - 1;
+       control = leo | SIS_PLAY_DMA_LOOP | SIS_PLAY_DMA_INTR_AT_LEO;
+       sso_eso = leo;
+
+       if (runtime->period_size == (runtime->buffer_size / 2)) {
+               control |= SIS_PLAY_DMA_INTR_AT_MLP;
+       } else if (runtime->period_size != runtime->buffer_size) {
+               voice->flags |= VOICE_SSO_TIMING;
+               voice->sso = runtime->period_size - 1;
+               voice->period_size = runtime->period_size;
+               voice->buffer_size = runtime->buffer_size;
+
+               control &= ~SIS_PLAY_DMA_INTR_AT_LEO;
+               control |= SIS_PLAY_DMA_INTR_AT_SSO;
+               sso_eso |= (runtime->period_size - 1) << 16;
+       }
+
+       delta = sis_rate_to_delta(runtime->rate);
+
+       /* Ok, we're ready to go, set up the channel.
+        */
+       writel(format, ctrl_base + SIS_PLAY_DMA_FORMAT_CSO);
+       writel(dma_addr, ctrl_base + SIS_PLAY_DMA_BASE);
+       writel(control, ctrl_base + SIS_PLAY_DMA_CONTROL);
+       writel(sso_eso, ctrl_base + SIS_PLAY_DMA_SSO_ESO);
+
+       for (reg = 0; reg < SIS_WAVE_SIZE; reg += 4)
+               writel(0, wave_base + reg);
+
+       writel(SIS_WAVE_GENERAL_WAVE_VOLUME, wave_base + SIS_WAVE_GENERAL);
+       writel(delta << 16, wave_base + SIS_WAVE_GENERAL_ARTICULATION);
+       writel(SIS_WAVE_CHANNEL_CONTROL_FIRST_SAMPLE |
+                       SIS_WAVE_CHANNEL_CONTROL_AMP_ENABLE |
+                       SIS_WAVE_CHANNEL_CONTROL_INTERPOLATE_ENABLE,
+                       wave_base + SIS_WAVE_CHANNEL_CONTROL);
+
+       /* Force PCI writes to post. */
+       readl(ctrl_base);
+
+       return 0;
+}
+
+static int sis_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+       struct sis7019 *sis = snd_pcm_substream_chip(substream);
+       unsigned long io = sis->ioport;
+       struct snd_pcm_substream *s;
+       struct voice *voice;
+       void *chip;
+       int starting;
+       u32 record = 0;
+       u32 play[2] = { 0, 0 };
+
+       /* No locks needed, as the PCM core will hold the locks on the
+        * substreams, and the HW will only start/stop the indicated voices
+        * without changing the state of the others.
+        */
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+       case SNDRV_PCM_TRIGGER_RESUME:
+               starting = 1;
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+               starting = 0;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       snd_pcm_group_for_each_entry(s, substream) {
+               /* Make sure it is for us... */
+               chip = snd_pcm_substream_chip(s);
+               if (chip != sis)
+                       continue;
+
+               voice = s->runtime->private_data;
+               if (voice->flags & VOICE_CAPTURE) {
+                       record |= 1 << voice->num;
+                       voice = voice->timing;
+               }
+
+               /* voice could be NULL if this a recording stream, and it
+                * doesn't have an external timing channel.
+                */
+               if (voice)
+                       play[voice->num / 32] |= 1 << (voice->num & 0x1f);
+
+               snd_pcm_trigger_done(s, substream);
+       }
+
+       if (starting) {
+               if (record)
+                       outl(record, io + SIS_RECORD_START_REG);
+               if (play[0])
+                       outl(play[0], io + SIS_PLAY_START_A_REG);
+               if (play[1])
+                       outl(play[1], io + SIS_PLAY_START_B_REG);
+       } else {
+               if (record)
+                       outl(record, io + SIS_RECORD_STOP_REG);
+               if (play[0])
+                       outl(play[0], io + SIS_PLAY_STOP_A_REG);
+               if (play[1])
+                       outl(play[1], io + SIS_PLAY_STOP_B_REG);
+       }
+       return 0;
+}
+
+static snd_pcm_uframes_t sis_pcm_pointer(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct voice *voice = runtime->private_data;
+       u32 cso;
+
+       cso = readl(voice->ctrl_base + SIS_PLAY_DMA_FORMAT_CSO);
+       cso &= 0xffff;
+       return cso;
+}
+
+static int sis_capture_open(struct snd_pcm_substream *substream)
+{
+       struct sis7019 *sis = snd_pcm_substream_chip(substream);
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct voice *voice = &sis->capture_voice;
+       unsigned long flags;
+
+       /* FIXME: The driver only supports recording from one channel
+        * at the moment, but it could support more.
+        */
+       spin_lock_irqsave(&sis->voice_lock, flags);
+       if (voice->flags & VOICE_IN_USE)
+               voice = NULL;
+       else
+               voice->flags |= VOICE_IN_USE;
+       spin_unlock_irqrestore(&sis->voice_lock, flags);
+
+       if (!voice)
+               return -EAGAIN;
+
+       voice->substream = substream;
+       runtime->private_data = voice;
+       runtime->hw = sis_capture_hw_info;
+       runtime->hw.rates = sis->ac97[0]->rates[AC97_RATES_ADC];
+       snd_pcm_limit_hw_rates(runtime);
+       snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
+                                               9, 0xfff9);
+       snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
+                                               9, 0xfff9);
+       snd_pcm_set_sync(substream);
+       return 0;
+}
+
+static int sis_capture_hw_params(struct snd_pcm_substream *substream,
+                                       struct snd_pcm_hw_params *hw_params)
+{
+       struct sis7019 *sis = snd_pcm_substream_chip(substream);
+       int rc;
+
+       rc = snd_ac97_set_rate(sis->ac97[0], AC97_PCM_LR_ADC_RATE,
+                                               params_rate(hw_params));
+       if (rc)
+               goto out;
+
+       rc = snd_pcm_lib_malloc_pages(substream,
+                                       params_buffer_bytes(hw_params));
+       if (rc < 0)
+               goto out;
+
+       rc = sis_alloc_timing_voice(substream, hw_params);
+
+out:
+       return rc;
+}
+
+static void sis_prepare_timing_voice(struct voice *voice,
+                                       struct snd_pcm_substream *substream)
+{
+       struct sis7019 *sis = snd_pcm_substream_chip(substream);
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct voice *timing = voice->timing;
+       void __iomem *play_base = timing->ctrl_base;
+       void __iomem *wave_base = timing->wave_base;
+       u16 buffer_size, period_size;
+       u32 format, control, sso_eso, delta;
+       u32 vperiod, sso, reg;
+
+       /* Set our initial buffer and period as large as we can given a
+        * single page of silence.
+        */
+       buffer_size = 4096 / runtime->channels;
+       buffer_size /= snd_pcm_format_size(runtime->format, 1);
+       period_size = buffer_size;
+
+       /* Initially, we want to interrupt just a bit behind the end of
+        * the period we're clocking out. 10 samples seems to give a good
+        * delay.
+        *
+        * We want to spread our interrupts throughout the virtual period,
+        * so that we don't end up with two interrupts back to back at the
+        * end -- this helps minimize the effects of any jitter. Adjust our
+        * clocking period size so that the last period is at least a fourth
+        * of a full period.
+        *
+        * This is all moot if we don't need to use virtual periods.
+        */
+       vperiod = runtime->period_size + 10;
+       if (vperiod > period_size) {
+               u16 tail = vperiod % period_size;
+               u16 quarter_period = period_size / 4;
+
+               if (tail && tail < quarter_period) {
+                       u16 loops = vperiod / period_size;
+
+                       tail = quarter_period - tail;
+                       tail += loops - 1;
+                       tail /= loops;
+                       period_size -= tail;
+               }
+
+               sso = period_size - 1;
+       } else {
+               /* The initial period will fit inside the buffer, so we
+                * don't need to use virtual periods -- disable them.
+                */
+               period_size = runtime->period_size;
+               sso = vperiod - 1;
+               vperiod = 0;
+       }
+
+       /* The interrupt handler implements the timing syncronization, so
+        * setup its state.
+        */
+       timing->flags |= VOICE_SYNC_TIMING;
+       timing->sync_base = voice->ctrl_base;
+       timing->sync_cso = runtime->period_size - 1;
+       timing->sync_period_size = runtime->period_size;
+       timing->sync_buffer_size = runtime->buffer_size;
+       timing->period_size = period_size;
+       timing->buffer_size = buffer_size;
+       timing->sso = sso;
+       timing->vperiod = vperiod;
+
+       /* Using unsigned samples with the all-zero silence buffer
+        * forces the output to the lower rail, killing playback.
+        * So ignore unsigned vs signed -- it doesn't change the timing.
+        */
+       format = 0;
+       if (snd_pcm_format_width(runtime->format) == 8)
+               format = SIS_CAPTURE_DMA_FORMAT_8BIT;
+       if (runtime->channels == 1)
+               format |= SIS_CAPTURE_DMA_FORMAT_MONO;
+
+       control = timing->buffer_size - 1;
+       control |= SIS_PLAY_DMA_LOOP | SIS_PLAY_DMA_INTR_AT_SSO;
+       sso_eso = timing->buffer_size - 1;
+       sso_eso |= timing->sso << 16;
+
+       delta = sis_rate_to_delta(runtime->rate);
+
+       /* We've done the math, now configure the channel.
+        */
+       writel(format, play_base + SIS_PLAY_DMA_FORMAT_CSO);
+       writel(sis->silence_dma_addr, play_base + SIS_PLAY_DMA_BASE);
+       writel(control, play_base + SIS_PLAY_DMA_CONTROL);
+       writel(sso_eso, play_base + SIS_PLAY_DMA_SSO_ESO);
+
+       for (reg = 0; reg < SIS_WAVE_SIZE; reg += 4)
+               writel(0, wave_base + reg);
+
+       writel(SIS_WAVE_GENERAL_WAVE_VOLUME, wave_base + SIS_WAVE_GENERAL);
+       writel(delta << 16, wave_base + SIS_WAVE_GENERAL_ARTICULATION);
+       writel(SIS_WAVE_CHANNEL_CONTROL_FIRST_SAMPLE |
+                       SIS_WAVE_CHANNEL_CONTROL_AMP_ENABLE |
+                       SIS_WAVE_CHANNEL_CONTROL_INTERPOLATE_ENABLE,
+                       wave_base + SIS_WAVE_CHANNEL_CONTROL);
+}
+
+static int sis_pcm_capture_prepare(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct voice *voice = runtime->private_data;
+       void __iomem *rec_base = voice->ctrl_base;
+       u32 format, dma_addr, control;
+       u16 leo;
+
+       /* We rely on the PCM core to ensure that the parameters for this
+        * substream do not change on us while we're programming the HW.
+        */
+       format = 0;
+       if (snd_pcm_format_width(runtime->format) == 8)
+               format = SIS_CAPTURE_DMA_FORMAT_8BIT;
+       if (!snd_pcm_format_signed(runtime->format))
+               format |= SIS_CAPTURE_DMA_FORMAT_UNSIGNED;
+       if (runtime->channels == 1)
+               format |= SIS_CAPTURE_DMA_FORMAT_MONO;
+
+       dma_addr = runtime->dma_addr;
+       leo = runtime->buffer_size - 1;
+       control = leo | SIS_CAPTURE_DMA_LOOP;
+
+       /* If we've got more than two periods per buffer, then we have
+        * use a timing voice to clock out the periods. Otherwise, we can
+        * use the capture channel's interrupts.
+        */
+       if (voice->timing) {
+               sis_prepare_timing_voice(voice, substream);
+       } else {
+               control |= SIS_CAPTURE_DMA_INTR_AT_LEO;
+               if (runtime->period_size != runtime->buffer_size)
+                       control |= SIS_CAPTURE_DMA_INTR_AT_MLP;
+       }
+
+       writel(format, rec_base + SIS_CAPTURE_DMA_FORMAT_CSO);
+       writel(dma_addr, rec_base + SIS_CAPTURE_DMA_BASE);
+       writel(control, rec_base + SIS_CAPTURE_DMA_CONTROL);
+
+       /* Force the writes to post. */
+       readl(rec_base);
+
+       return 0;
+}
+
+static struct snd_pcm_ops sis_playback_ops = {
+       .open = sis_playback_open,
+       .close = sis_substream_close,
+       .ioctl = snd_pcm_lib_ioctl,
+       .hw_params = sis_playback_hw_params,
+       .hw_free = sis_hw_free,
+       .prepare = sis_pcm_playback_prepare,
+       .trigger = sis_pcm_trigger,
+       .pointer = sis_pcm_pointer,
+};
+
+static struct snd_pcm_ops sis_capture_ops = {
+       .open = sis_capture_open,
+       .close = sis_substream_close,
+       .ioctl = snd_pcm_lib_ioctl,
+       .hw_params = sis_capture_hw_params,
+       .hw_free = sis_hw_free,
+       .prepare = sis_pcm_capture_prepare,
+       .trigger = sis_pcm_trigger,
+       .pointer = sis_pcm_pointer,
+};
+
+static int __devinit sis_pcm_create(struct sis7019 *sis)
+{
+       struct snd_pcm *pcm;
+       int rc;
+
+       /* We have 64 voices, and the driver currently records from
+        * only one channel, though that could change in the future.
+        */
+       rc = snd_pcm_new(sis->card, "SiS7019", 0, 64, 1, &pcm);
+       if (rc)
+               return rc;
+
+       pcm->private_data = sis;
+       strcpy(pcm->name, "SiS7019");
+       sis->pcm = pcm;
+
+       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &sis_playback_ops);
+       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &sis_capture_ops);
+
+       /* Try to preallocate some memory, but it's not the end of the
+        * world if this fails.
+        */
+       snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+                               snd_dma_pci_data(sis->pci), 64*1024, 128*1024);
+
+       return 0;
+}
+
+static unsigned short sis_ac97_rw(struct sis7019 *sis, int codec, u32 cmd)
+{
+       unsigned long io = sis->ioport;
+       unsigned short val = 0xffff;
+       u16 status;
+       u16 rdy;
+       int count;
+       const static u16 codec_ready[3] = {
+               SIS_AC97_STATUS_CODEC_READY,
+               SIS_AC97_STATUS_CODEC2_READY,
+               SIS_AC97_STATUS_CODEC3_READY,
+       };
+
+       rdy = codec_ready[codec];
+
+
+       /* Get the AC97 semaphore -- software first, so we don't spin
+        * pounding out IO reads on the hardware semaphore...
+        */
+       mutex_lock(&sis->ac97_mutex);
+
+       count = 0xffff;
+       while ((inw(io + SIS_AC97_SEMA) & SIS_AC97_SEMA_BUSY) && --count)
+               udelay(1);
+
+       if (!count)
+               goto timeout;
+
+       /* ... and wait for any outstanding commands to complete ...
+        */
+       count = 0xffff;
+       do {
+               status = inw(io + SIS_AC97_STATUS);
+               if ((status & rdy) && !(status & SIS_AC97_STATUS_BUSY))
+                       break;
+
+               udelay(1);
+       } while (--count);
+
+       if (!count)
+               goto timeout_sema;
+
+       /* ... before sending our command and waiting for it to finish ...
+        */
+       outl(cmd, io + SIS_AC97_CMD);
+       udelay(10);
+
+       count = 0xffff;
+       while ((inw(io + SIS_AC97_STATUS) & SIS_AC97_STATUS_BUSY) && --count)
+               udelay(1);
+
+       /* ... and reading the results (if any).
+        */
+       val = inl(io + SIS_AC97_CMD) >> 16;
+
+timeout_sema:
+       outl(SIS_AC97_SEMA_RELEASE, io + SIS_AC97_SEMA);
+timeout:
+       mutex_unlock(&sis->ac97_mutex);
+
+       if (!count) {
+               printk(KERN_ERR "sis7019: ac97 codec %d timeout cmd 0x%08x\n",
+                                       codec, cmd);
+       }
+
+       return val;
+}
+
+static void sis_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
+                               unsigned short val)
+{
+       const static u32 cmd[3] = {
+               SIS_AC97_CMD_CODEC_WRITE,
+               SIS_AC97_CMD_CODEC2_WRITE,
+               SIS_AC97_CMD_CODEC3_WRITE,
+       };
+       sis_ac97_rw(ac97->private_data, ac97->num,
+                       (val << 16) | (reg << 8) | cmd[ac97->num]);
+}
+
+static unsigned short sis_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
+{
+       const static u32 cmd[3] = {
+               SIS_AC97_CMD_CODEC_READ,
+               SIS_AC97_CMD_CODEC2_READ,
+               SIS_AC97_CMD_CODEC3_READ,
+       };
+       return sis_ac97_rw(ac97->private_data, ac97->num,
+                                       (reg << 8) | cmd[ac97->num]);
+}
+
+static int __devinit sis_mixer_create(struct sis7019 *sis)
+{
+       struct snd_ac97_bus *bus;
+       struct snd_ac97_template ac97;
+       static struct snd_ac97_bus_ops ops = {
+               .write = sis_ac97_write,
+               .read = sis_ac97_read,
+       };
+       int rc;
+
+       memset(&ac97, 0, sizeof(ac97));
+       ac97.private_data = sis;
+
+       rc = snd_ac97_bus(sis->card, 0, &ops, NULL, &bus);
+       if (!rc && sis->codecs_present & SIS_PRIMARY_CODEC_PRESENT)
+               rc = snd_ac97_mixer(bus, &ac97, &sis->ac97[0]);
+       ac97.num = 1;
+       if (!rc && (sis->codecs_present & SIS_SECONDARY_CODEC_PRESENT))
+               rc = snd_ac97_mixer(bus, &ac97, &sis->ac97[1]);
+       ac97.num = 2;
+       if (!rc && (sis->codecs_present & SIS_TERTIARY_CODEC_PRESENT))
+               rc = snd_ac97_mixer(bus, &ac97, &sis->ac97[2]);
+
+       /* If we return an error here, then snd_card_free() should
+        * free up any ac97 codecs that got created, as well as the bus.
+        */
+       return rc;
+}
+
+static void sis_free_suspend(struct sis7019 *sis)
+{
+       int i;
+
+       for (i = 0; i < SIS_SUSPEND_PAGES; i++)
+               kfree(sis->suspend_state[i]);
+}
+
+static int sis_chip_free(struct sis7019 *sis)
+{
+       /* Reset the chip, and disable all interrputs.
+        */
+       outl(SIS_GCR_SOFTWARE_RESET, sis->ioport + SIS_GCR);
+       udelay(10);
+       outl(0, sis->ioport + SIS_GCR);
+       outl(0, sis->ioport + SIS_GIER);
+
+       /* Now, free everything we allocated.
+        */
+       if (sis->irq >= 0)
+               free_irq(sis->irq, sis);
+
+       if (sis->ioaddr)
+               iounmap(sis->ioaddr);
+
+       pci_release_regions(sis->pci);
+       pci_disable_device(sis->pci);
+
+       sis_free_suspend(sis);
+       return 0;
+}
+
+static int sis_dev_free(struct snd_device *dev)
+{
+       struct sis7019 *sis = dev->device_data;
+       return sis_chip_free(sis);
+}
+
+static int sis_chip_init(struct sis7019 *sis)
+{
+       unsigned long io = sis->ioport;
+       void __iomem *ioaddr = sis->ioaddr;
+       u16 status;
+       int count;
+       int i;
+
+       /* Reset the audio controller
+        */
+       outl(SIS_GCR_SOFTWARE_RESET, io + SIS_GCR);
+       udelay(10);
+       outl(0, io + SIS_GCR);
+
+       /* Get the AC-link semaphore, and reset the codecs
+        */
+       count = 0xffff;
+       while ((inw(io + SIS_AC97_SEMA) & SIS_AC97_SEMA_BUSY) && --count)
+               udelay(1);
+
+       if (!count)
+               return -EIO;
+
+       outl(SIS_AC97_CMD_CODEC_COLD_RESET, io + SIS_AC97_CMD);
+       udelay(10);
+
+       count = 0xffff;
+       while ((inw(io + SIS_AC97_STATUS) & SIS_AC97_STATUS_BUSY) && --count)
+               udelay(1);
+
+       /* Now that we've finished the reset, find out what's attached.
+        */
+       status = inl(io + SIS_AC97_STATUS);
+       if (status & SIS_AC97_STATUS_CODEC_READY)
+               sis->codecs_present |= SIS_PRIMARY_CODEC_PRESENT;
+       if (status & SIS_AC97_STATUS_CODEC2_READY)
+               sis->codecs_present |= SIS_SECONDARY_CODEC_PRESENT;
+       if (status & SIS_AC97_STATUS_CODEC3_READY)
+               sis->codecs_present |= SIS_TERTIARY_CODEC_PRESENT;
+
+       /* All done, let go of the semaphore, and check for errors
+        */
+       outl(SIS_AC97_SEMA_RELEASE, io + SIS_AC97_SEMA);
+       if (!sis->codecs_present || !count)
+               return -EIO;
+
+       /* Let the hardware know that the audio driver is alive,
+        * and enable PCM slots on the AC-link for L/R playback (3 & 4) and
+        * record channels. We're going to want to use Variable Rate Audio
+        * for recording, to avoid needlessly resampling from 48kHZ.
+        */
+       outl(SIS_AC97_CONF_AUDIO_ALIVE, io + SIS_AC97_CONF);
+       outl(SIS_AC97_CONF_AUDIO_ALIVE | SIS_AC97_CONF_PCM_LR_ENABLE |
+               SIS_AC97_CONF_PCM_CAP_MIC_ENABLE |
+               SIS_AC97_CONF_PCM_CAP_LR_ENABLE |
+               SIS_AC97_CONF_CODEC_VRA_ENABLE, io + SIS_AC97_CONF);
+
+       /* All AC97 PCM slots should be sourced from sub-mixer 0.
+        */
+       outl(0, io + SIS_AC97_PSR);
+
+       /* There is only one valid DMA setup for a PCI environment.
+        */
+       outl(SIS_DMA_CSR_PCI_SETTINGS, io + SIS_DMA_CSR);
+
+       /* Reset the syncronization groups for all of the channels
+        * to be asyncronous. If we start doing SPDIF or 5.1 sound, etc.
+        * we'll need to change how we handle these. Until then, we just
+        * assign sub-mixer 0 to all playback channels, and avoid any
+        * attenuation on the audio.
+        */
+       outl(0, io + SIS_PLAY_SYNC_GROUP_A);
+       outl(0, io + SIS_PLAY_SYNC_GROUP_B);
+       outl(0, io + SIS_PLAY_SYNC_GROUP_C);
+       outl(0, io + SIS_PLAY_SYNC_GROUP_D);
+       outl(0, io + SIS_MIXER_SYNC_GROUP);
+
+       for (i = 0; i < 64; i++) {
+               writel(i, SIS_MIXER_START_ADDR(ioaddr, i));
+               writel(SIS_MIXER_RIGHT_NO_ATTEN | SIS_MIXER_LEFT_NO_ATTEN |
+                               SIS_MIXER_DEST_0, SIS_MIXER_ADDR(ioaddr, i));
+       }
+
+       /* Don't attenuate any audio set for the wave amplifier.
+        *
+        * FIXME: Maximum attenuation is set for the music amp, which will
+        * need to change if we start using the synth engine.
+        */
+       outl(0xffff0000, io + SIS_WEVCR);
+
+       /* Ensure that the wave engine is in normal operating mode.
+        */
+       outl(0, io + SIS_WECCR);
+
+       /* Go ahead and enable the DMA interrupts. They won't go live
+        * until we start a channel.
+        */
+       outl(SIS_GIER_AUDIO_PLAY_DMA_IRQ_ENABLE |
+               SIS_GIER_AUDIO_RECORD_DMA_IRQ_ENABLE, io + SIS_GIER);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int sis_suspend(struct pci_dev *pci, pm_message_t state)
+{
+       struct snd_card *card = pci_get_drvdata(pci);
+       struct sis7019 *sis = card->private_data;
+       void __iomem *ioaddr = sis->ioaddr;
+       int i;
+
+       snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
+       snd_pcm_suspend_all(sis->pcm);
+       if (sis->codecs_present & SIS_PRIMARY_CODEC_PRESENT)
+               snd_ac97_suspend(sis->ac97[0]);
+       if (sis->codecs_present & SIS_SECONDARY_CODEC_PRESENT)
+               snd_ac97_suspend(sis->ac97[1]);
+       if (sis->codecs_present & SIS_TERTIARY_CODEC_PRESENT)
+               snd_ac97_suspend(sis->ac97[2]);
+
+       /* snd_pcm_suspend_all() stopped all channels, so we're quiescent.
+        */
+       if (sis->irq >= 0) {
+               synchronize_irq(sis->irq);
+               free_irq(sis->irq, sis);
+               sis->irq = -1;
+       }
+
+       /* Save the internal state away
+        */
+       for (i = 0; i < 4; i++) {
+               memcpy_fromio(sis->suspend_state[i], ioaddr, 4096);
+               ioaddr += 4096;
+       }
+
+       pci_disable_device(pci);
+       pci_save_state(pci);
+       pci_set_power_state(pci, pci_choose_state(pci, state));
+       return 0;
+}
+
+static int sis_resume(struct pci_dev *pci)
+{
+       struct snd_card *card = pci_get_drvdata(pci);
+       struct sis7019 *sis = card->private_data;
+       void __iomem *ioaddr = sis->ioaddr;
+       int i;
+
+       pci_set_power_state(pci, PCI_D0);
+       pci_restore_state(pci);
+
+       if (pci_enable_device(pci) < 0) {
+               printk(KERN_ERR "sis7019: unable to re-enable device\n");
+               goto error;
+       }
+
+       if (sis_chip_init(sis)) {
+               printk(KERN_ERR "sis7019: unable to re-init controller\n");
+               goto error;
+       }
+
+       if (request_irq(pci->irq, sis_interrupt, IRQF_DISABLED|IRQF_SHARED,
+                               card->shortname, sis)) {
+               printk(KERN_ERR "sis7019: unable to regain IRQ %d\n", pci->irq);
+               goto error;
+       }
+
+       /* Restore saved state, then clear out the page we use for the
+        * silence buffer.
+        */
+       for (i = 0; i < 4; i++) {
+               memcpy_toio(ioaddr, sis->suspend_state[i], 4096);
+               ioaddr += 4096;
+       }
+
+       memset(sis->suspend_state[0], 0, 4096);
+
+       sis->irq = pci->irq;
+       pci_set_master(pci);
+
+       if (sis->codecs_present & SIS_PRIMARY_CODEC_PRESENT)
+               snd_ac97_resume(sis->ac97[0]);
+       if (sis->codecs_present & SIS_SECONDARY_CODEC_PRESENT)
+               snd_ac97_resume(sis->ac97[1]);
+       if (sis->codecs_present & SIS_TERTIARY_CODEC_PRESENT)
+               snd_ac97_resume(sis->ac97[2]);
+
+       snd_power_change_state(card, SNDRV_CTL_POWER_D0);
+       return 0;
+
+error:
+       snd_card_disconnect(card);
+       return -EIO;
+}
+#endif /* CONFIG_PM */
+
+static int sis_alloc_suspend(struct sis7019 *sis)
+{
+       int i;
+
+       /* We need 16K to store the internal wave engine state during a
+        * suspend, but we don't need it to be contiguous, so play nice
+        * with the memory system. We'll also use this area for a silence
+        * buffer.
+        */
+       for (i = 0; i < SIS_SUSPEND_PAGES; i++) {
+               sis->suspend_state[i] = kmalloc(4096, GFP_KERNEL);
+               if (!sis->suspend_state[i])
+                       return -ENOMEM;
+       }
+       memset(sis->suspend_state[0], 0, 4096);
+
+       return 0;
+}
+
+static int __devinit sis_chip_create(struct snd_card *card,
+                                       struct pci_dev *pci)
+{
+       struct sis7019 *sis = card->private_data;
+       struct voice *voice;
+       static struct snd_device_ops ops = {
+               .dev_free = sis_dev_free,
+       };
+       int rc;
+       int i;
+
+       rc = pci_enable_device(pci);
+       if (rc)
+               goto error_out;
+
+       if (pci_set_dma_mask(pci, DMA_30BIT_MASK) < 0) {
+               printk(KERN_ERR "sis7019: architecture does not support "
+                                       "30-bit PCI busmaster DMA");
+               goto error_out_enabled;
+       }
+
+       memset(sis, 0, sizeof(*sis));
+       mutex_init(&sis->ac97_mutex);
+       spin_lock_init(&sis->voice_lock);
+       sis->card = card;
+       sis->pci = pci;
+       sis->irq = -1;
+       sis->ioport = pci_resource_start(pci, 0);
+
+       rc = pci_request_regions(pci, "SiS7019");
+       if (rc) {
+               printk(KERN_ERR "sis7019: unable request regions\n");
+               goto error_out_enabled;
+       }
+
+       rc = -EIO;
+       sis->ioaddr = ioremap_nocache(pci_resource_start(pci, 1), 0x4000);
+       if (!sis->ioaddr) {
+               printk(KERN_ERR "sis7019: unable to remap MMIO, aborting\n");
+               goto error_out_cleanup;
+       }
+
+       rc = sis_alloc_suspend(sis);
+       if (rc < 0) {
+               printk(KERN_ERR "sis7019: unable to allocate state storage\n");
+               goto error_out_cleanup;
+       }
+
+       rc = sis_chip_init(sis);
+       if (rc)
+               goto error_out_cleanup;
+
+       if (request_irq(pci->irq, sis_interrupt, IRQF_DISABLED|IRQF_SHARED,
+                               card->shortname, sis)) {
+               printk(KERN_ERR "unable to allocate irq %d\n", sis->irq);
+               goto error_out_cleanup;
+       }
+
+       sis->irq = pci->irq;
+       pci_set_master(pci);
+
+       for (i = 0; i < 64; i++) {
+               voice = &sis->voices[i];
+               voice->num = i;
+               voice->ctrl_base = SIS_PLAY_DMA_ADDR(sis->ioaddr, i);
+               voice->wave_base = SIS_WAVE_ADDR(sis->ioaddr, i);
+       }
+
+       voice = &sis->capture_voice;
+       voice->flags = VOICE_CAPTURE;
+       voice->num = SIS_CAPTURE_CHAN_AC97_PCM_IN;
+       voice->ctrl_base = SIS_CAPTURE_DMA_ADDR(sis->ioaddr, voice->num);
+
+       rc = snd_device_new(card, SNDRV_DEV_LOWLEVEL, sis, &ops);
+       if (rc)
+               goto error_out_cleanup;
+
+       snd_card_set_dev(card, &pci->dev);
+
+       return 0;
+
+error_out_cleanup:
+       sis_chip_free(sis);
+
+error_out_enabled:
+       pci_disable_device(pci);
+
+error_out:
+       return rc;
+}
+
+static int __devinit snd_sis7019_probe(struct pci_dev *pci,
+                                       const struct pci_device_id *pci_id)
+{
+       struct snd_card *card;
+       struct sis7019 *sis;
+       int rc;
+
+       rc = -ENOENT;
+       if (!enable)
+               goto error_out;
+
+       rc = -ENOMEM;
+       card = snd_card_new(index, id, THIS_MODULE, sizeof(*sis));
+       if (!card)
+               goto error_out;
+
+       strcpy(card->driver, "SiS7019");
+       strcpy(card->shortname, "SiS7019");
+       rc = sis_chip_create(card, pci);
+       if (rc)
+               goto card_error_out;
+
+       sis = card->private_data;
+
+       rc = sis_mixer_create(sis);
+       if (rc)
+               goto card_error_out;
+
+       rc = sis_pcm_create(sis);
+       if (rc)
+               goto card_error_out;
+
+       snprintf(card->longname, sizeof(card->longname),
+                       "%s Audio Accelerator with %s at 0x%lx, irq %d",
+                       card->shortname, snd_ac97_get_short_name(sis->ac97[0]),
+                       sis->ioport, sis->irq);
+
+       rc = snd_card_register(card);
+       if (rc)
+               goto card_error_out;
+
+       pci_set_drvdata(pci, card);
+       return 0;
+
+card_error_out:
+       snd_card_free(card);
+
+error_out:
+       return rc;
+}
+
+static void __devexit snd_sis7019_remove(struct pci_dev *pci)
+{
+       snd_card_free(pci_get_drvdata(pci));
+       pci_set_drvdata(pci, NULL);
+}
+
+static struct pci_driver sis7019_driver = {
+       .name = "SiS7019",
+       .id_table = snd_sis7019_ids,
+       .probe = snd_sis7019_probe,
+       .remove = __devexit_p(snd_sis7019_remove),
+
+#ifdef CONFIG_PM
+       .suspend = sis_suspend,
+       .resume = sis_resume,
+#endif
+};
+
+static int __init sis7019_init(void)
+{
+       return pci_register_driver(&sis7019_driver);
+}
+
+static void __exit sis7019_exit(void)
+{
+       pci_unregister_driver(&sis7019_driver);
+}
+
+module_init(sis7019_init);
+module_exit(sis7019_exit);
diff --git a/sound/pci/sis7019.h b/sound/pci/sis7019.h
new file mode 100644 (file)
index 0000000..013b673
--- /dev/null
@@ -0,0 +1,342 @@
+#ifndef __sis7019_h__
+#define __sis7019_h__
+
+/*
+ *  Definitions for SiS7019 Audio Accelerator
+ *
+ *  Copyright (C) 2004-2007, David Dillow
+ *  Written by David Dillow <dave@thedillows.org>
+ *  Inspired by the Trident 4D-WaveDX/NX driver.
+ *
+ *  All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, version 2.
+ *
+ *  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
+ */
+
+
+/* General Control Register */
+#define SIS_GCR                0x00
+#define                SIS_GCR_MACRO_POWER_DOWN                0x80000000
+#define                SIS_GCR_MODEM_ENABLE                    0x00010000
+#define                SIS_GCR_SOFTWARE_RESET                  0x00000001
+
+/* General Interrupt Enable Register */
+#define SIS_GIER       0x04
+#define                SIS_GIER_MODEM_TIMER_IRQ_ENABLE         0x00100000
+#define                SIS_GIER_MODEM_RX_DMA_IRQ_ENABLE        0x00080000
+#define                SIS_GIER_MODEM_TX_DMA_IRQ_ENABLE        0x00040000
+#define                SIS_GIER_AC97_GPIO1_IRQ_ENABLE          0x00020000
+#define                SIS_GIER_AC97_GPIO0_IRQ_ENABLE          0x00010000
+#define                SIS_GIER_AC97_SAMPLE_TIMER_IRQ_ENABLE   0x00000010
+#define                SIS_GIER_AUDIO_GLOBAL_TIMER_IRQ_ENABLE  0x00000008
+#define                SIS_GIER_AUDIO_RECORD_DMA_IRQ_ENABLE    0x00000004
+#define                SIS_GIER_AUDIO_PLAY_DMA_IRQ_ENABLE      0x00000002
+#define                SIS_GIER_AUDIO_WAVE_ENGINE_IRQ_ENABLE   0x00000001
+
+/* General Interrupt Status Register */
+#define SIS_GISR       0x08
+#define                SIS_GISR_MODEM_TIMER_IRQ_STATUS         0x00100000
+#define                SIS_GISR_MODEM_RX_DMA_IRQ_STATUS        0x00080000
+#define                SIS_GISR_MODEM_TX_DMA_IRQ_STATUS        0x00040000
+#define                SIS_GISR_AC97_GPIO1_IRQ_STATUS          0x00020000
+#define                SIS_GISR_AC97_GPIO0_IRQ_STATUS          0x00010000
+#define                SIS_GISR_AC97_SAMPLE_TIMER_IRQ_STATUS   0x00000010
+#define                SIS_GISR_AUDIO_GLOBAL_TIMER_IRQ_STATUS  0x00000008
+#define                SIS_GISR_AUDIO_RECORD_DMA_IRQ_STATUS    0x00000004
+#define                SIS_GISR_AUDIO_PLAY_DMA_IRQ_STATUS      0x00000002
+#define                SIS_GISR_AUDIO_WAVE_ENGINE_IRQ_STATUS   0x00000001
+
+/* DMA Control Register */
+#define SIS_DMA_CSR    0x10
+#define                SIS_DMA_CSR_PCI_SETTINGS                0x0000001d
+#define                SIS_DMA_CSR_CONCURRENT_ENABLE           0x00000200
+#define                SIS_DMA_CSR_PIPELINE_ENABLE             0x00000100
+#define                SIS_DMA_CSR_RX_DRAIN_ENABLE             0x00000010
+#define                SIS_DMA_CSR_RX_FILL_ENABLE              0x00000008
+#define                SIS_DMA_CSR_TX_DRAIN_ENABLE             0x00000004
+#define                SIS_DMA_CSR_TX_LOWPRI_FILL_ENABLE       0x00000002
+#define                SIS_DMA_CSR_TX_HIPRI_FILL_ENABLE        0x00000001
+
+/* Playback Channel Start Registers */
+#define SIS_PLAY_START_A_REG   0x14
+#define SIS_PLAY_START_B_REG   0x18
+
+/* Playback Channel Stop Registers */
+#define SIS_PLAY_STOP_A_REG    0x1c
+#define SIS_PLAY_STOP_B_REG    0x20
+
+/* Recording Channel Start Register */
+#define SIS_RECORD_START_REG   0x24
+
+/* Recording Channel Stop Register */
+#define SIS_RECORD_STOP_REG    0x28
+
+/* Playback Interrupt Status Registers */
+#define SIS_PISR_A     0x2c
+#define SIS_PISR_B     0x30
+
+/* Recording Interrupt Status Register */
+#define SIS_RISR       0x34
+
+/* AC97 AC-link Playback Source Register */
+#define SIS_AC97_PSR   0x40
+#define                SIS_AC97_PSR_MODEM_HEADSET_SRC_MIXER    0x0f000000
+#define                SIS_AC97_PSR_MODEM_LINE2_SRC_MIXER      0x00f00000
+#define                SIS_AC97_PSR_MODEM_LINE1_SRC_MIXER      0x000f0000
+#define                SIS_AC97_PSR_PCM_LFR_SRC_MIXER          0x0000f000
+#define                SIS_AC97_PSR_PCM_SURROUND_SRC_MIXER     0x00000f00
+#define                SIS_AC97_PSR_PCM_CENTER_SRC_MIXER       0x000000f0
+#define                SIS_AC97_PSR_PCM_LR_SRC_MIXER           0x0000000f
+
+/* AC97 AC-link Command Register */
+#define SIS_AC97_CMD   0x50
+#define        SIS_AC97_CMD_DATA_MASK                  0xffff0000
+#define                SIS_AC97_CMD_REG_MASK                   0x0000ff00
+#define                SIS_AC97_CMD_CODEC3_READ                0x0000000d
+#define                SIS_AC97_CMD_CODEC3_WRITE               0x0000000c
+#define                SIS_AC97_CMD_CODEC2_READ                0x0000000b
+#define                SIS_AC97_CMD_CODEC2_WRITE               0x0000000a
+#define                SIS_AC97_CMD_CODEC_READ                 0x00000009
+#define                SIS_AC97_CMD_CODEC_WRITE                0x00000008
+#define                SIS_AC97_CMD_CODEC_WARM_RESET           0x00000005
+#define                SIS_AC97_CMD_CODEC_COLD_RESET           0x00000004
+#define                SIS_AC97_CMD_DONE                       0x00000000
+
+/* AC97 AC-link Semaphore Register */
+#define SIS_AC97_SEMA  0x54
+#define                SIS_AC97_SEMA_BUSY                      0x00000001
+#define                SIS_AC97_SEMA_RELEASE                   0x00000000
+
+/* AC97 AC-link Status Register */
+#define SIS_AC97_STATUS        0x58
+#define                SIS_AC97_STATUS_AUDIO_D2_INACT_SECS     0x03f00000
+#define                SIS_AC97_STATUS_MODEM_ALIVE             0x00002000
+#define                SIS_AC97_STATUS_AUDIO_ALIVE             0x00001000
+#define                SIS_AC97_STATUS_CODEC3_READY            0x00000400
+#define                SIS_AC97_STATUS_CODEC2_READY            0x00000200
+#define                SIS_AC97_STATUS_CODEC_READY             0x00000100
+#define                SIS_AC97_STATUS_WARM_RESET              0x00000080
+#define                SIS_AC97_STATUS_COLD_RESET              0x00000040
+#define                SIS_AC97_STATUS_POWERED_DOWN            0x00000020
+#define                SIS_AC97_STATUS_NORMAL                  0x00000010
+#define                SIS_AC97_STATUS_READ_EXPIRED            0x00000004
+#define                SIS_AC97_STATUS_SEMAPHORE               0x00000002
+#define                SIS_AC97_STATUS_BUSY                    0x00000001
+
+/* AC97 AC-link Audio Configuration Register */
+#define SIS_AC97_CONF  0x5c
+#define                SIS_AC97_CONF_AUDIO_ALIVE               0x80000000
+#define                SIS_AC97_CONF_WARM_RESET_ENABLE         0x40000000
+#define                SIS_AC97_CONF_PR6_ENABLE                0x20000000
+#define                SIS_AC97_CONF_PR5_ENABLE                0x10000000
+#define                SIS_AC97_CONF_PR4_ENABLE                0x08000000
+#define                SIS_AC97_CONF_PR3_ENABLE                0x04000000
+#define                SIS_AC97_CONF_PR2_PR7_ENABLE            0x02000000
+#define                SIS_AC97_CONF_PR0_PR1_ENABLE            0x01000000
+#define                SIS_AC97_CONF_AUTO_PM_ENABLE            0x00800000
+#define                SIS_AC97_CONF_PCM_LFE_ENABLE            0x00080000
+#define                SIS_AC97_CONF_PCM_SURROUND_ENABLE       0x00040000
+#define                SIS_AC97_CONF_PCM_CENTER_ENABLE         0x00020000
+#define                SIS_AC97_CONF_PCM_LR_ENABLE             0x00010000
+#define                SIS_AC97_CONF_PCM_CAP_MIC_ENABLE        0x00002000
+#define                SIS_AC97_CONF_PCM_CAP_LR_ENABLE         0x00001000
+#define                SIS_AC97_CONF_PCM_CAP_MIC_FROM_CODEC3   0x00000200
+#define                SIS_AC97_CONF_PCM_CAP_LR_FROM_CODEC3    0x00000100
+#define                SIS_AC97_CONF_CODEC3_PM_VRM             0x00000080
+#define                SIS_AC97_CONF_CODEC_PM_VRM              0x00000040
+#define                SIS_AC97_CONF_CODEC3_VRA_ENABLE         0x00000020
+#define                SIS_AC97_CONF_CODEC_VRA_ENABLE          0x00000010
+#define                SIS_AC97_CONF_CODEC3_PM_EAC             0x00000008
+#define                SIS_AC97_CONF_CODEC_PM_EAC              0x00000004
+#define                SIS_AC97_CONF_CODEC3_EXISTS             0x00000002
+#define                SIS_AC97_CONF_CODEC_EXISTS              0x00000001
+
+/* Playback Channel Sync Group registers */
+#define SIS_PLAY_SYNC_GROUP_A  0x80
+#define SIS_PLAY_SYNC_GROUP_B  0x84
+#define SIS_PLAY_SYNC_GROUP_C  0x88
+#define SIS_PLAY_SYNC_GROUP_D  0x8c
+#define SIS_MIXER_SYNC_GROUP   0x90
+
+/* Wave Engine Config and Control Register */
+#define SIS_WECCR      0xa0
+#define                SIS_WECCR_TESTMODE_MASK                 0x00300000
+#define                        SIS_WECCR_TESTMODE_NORMAL               0x00000000
+#define                        SIS_WECCR_TESTMODE_BYPASS_NSO_ALPHA     0x00100000
+#define                        SIS_WECCR_TESTMODE_BYPASS_FC            0x00200000
+#define                        SIS_WECCR_TESTMODE_BYPASS_WOL           0x00300000
+#define                SIS_WECCR_RESONANCE_DELAY_MASK          0x00060000
+#define                        SIS_WECCR_RESONANCE_DELAY_NONE          0x00000000
+#define                        SIS_WECCR_RESONANCE_DELAY_FC_1F00       0x00020000
+#define                        SIS_WECCR_RESONANCE_DELAY_FC_1E00       0x00040000
+#define                        SIS_WECCR_RESONANCE_DELAY_FC_1C00       0x00060000
+#define                SIS_WECCR_IGNORE_CHANNEL_PARMS          0x00010000
+#define                SIS_WECCR_COMMAND_CHANNEL_ID_MASK       0x0003ff00
+#define                SIS_WECCR_COMMAND_MASK                  0x00000007
+#define                        SIS_WECCR_COMMAND_NONE                  0x00000000
+#define                        SIS_WECCR_COMMAND_DONE                  0x00000000
+#define                        SIS_WECCR_COMMAND_PAUSE                 0x00000001
+#define                        SIS_WECCR_COMMAND_TOGGLE_VEG            0x00000002
+#define                        SIS_WECCR_COMMAND_TOGGLE_MEG            0x00000003
+#define                        SIS_WECCR_COMMAND_TOGGLE_VEG_MEG        0x00000004
+
+/* Wave Engine Volume Control Register */
+#define SIS_WEVCR      0xa4
+#define                SIS_WEVCR_LEFT_MUSIC_ATTENUATION_MASK   0xff000000
+#define                SIS_WEVCR_RIGHT_MUSIC_ATTENUATION_MASK  0x00ff0000
+#define                SIS_WEVCR_LEFT_WAVE_ATTENUATION_MASK    0x0000ff00
+#define                SIS_WEVCR_RIGHT_WAVE_ATTENUATION_MASK   0x000000ff
+
+/* Wave Engine Interrupt Status Registers */
+#define SIS_WEISR_A    0xa8
+#define SIS_WEISR_B    0xac
+
+
+/* Playback DMA parameters (paramter RAM) */
+#define SIS_PLAY_DMA_OFFSET    0x0000
+#define SIS_PLAY_DMA_SIZE      0x10
+#define SIS_PLAY_DMA_ADDR(addr, num) \
+       ((num * SIS_PLAY_DMA_SIZE) + (addr) + SIS_PLAY_DMA_OFFSET)
+
+#define SIS_PLAY_DMA_FORMAT_CSO        0x00
+#define                SIS_PLAY_DMA_FORMAT_UNSIGNED    0x00080000
+#define                SIS_PLAY_DMA_FORMAT_8BIT        0x00040000
+#define                SIS_PLAY_DMA_FORMAT_MONO        0x00020000
+#define                SIS_PLAY_DMA_CSO_MASK           0x0000ffff
+#define SIS_PLAY_DMA_BASE      0x04
+#define SIS_PLAY_DMA_CONTROL   0x08
+#define                SIS_PLAY_DMA_STOP_AT_SSO        0x04000000
+#define                SIS_PLAY_DMA_RELEASE            0x02000000
+#define                SIS_PLAY_DMA_LOOP               0x01000000
+#define                SIS_PLAY_DMA_INTR_AT_SSO        0x00080000
+#define                SIS_PLAY_DMA_INTR_AT_ESO        0x00040000
+#define                SIS_PLAY_DMA_INTR_AT_LEO        0x00020000
+#define                SIS_PLAY_DMA_INTR_AT_MLP        0x00010000
+#define                SIS_PLAY_DMA_LEO_MASK           0x0000ffff
+#define SIS_PLAY_DMA_SSO_ESO   0x0c
+#define                SIS_PLAY_DMA_SSO_MASK           0xffff0000
+#define                SIS_PLAY_DMA_ESO_MASK           0x0000ffff
+
+/* Capture DMA parameters (paramter RAM) */
+#define SIS_CAPTURE_DMA_OFFSET 0x0800
+#define SIS_CAPTURE_DMA_SIZE   0x10
+#define SIS_CAPTURE_DMA_ADDR(addr, num) \
+       ((num * SIS_CAPTURE_DMA_SIZE) + (addr) + SIS_CAPTURE_DMA_OFFSET)
+
+#define        SIS_CAPTURE_CHAN_MIXER_ROUTE_BACK_0     0
+#define        SIS_CAPTURE_CHAN_MIXER_ROUTE_BACK_1     1
+#define        SIS_CAPTURE_CHAN_MIXER_ROUTE_BACK_2     2
+#define        SIS_CAPTURE_CHAN_MIXER_ROUTE_BACK_3     3
+#define        SIS_CAPTURE_CHAN_MIXER_ROUTE_BACK_4     4
+#define        SIS_CAPTURE_CHAN_MIXER_ROUTE_BACK_5     5
+#define        SIS_CAPTURE_CHAN_MIXER_ROUTE_BACK_6     6
+#define        SIS_CAPTURE_CHAN_MIXER_ROUTE_BACK_7     7
+#define        SIS_CAPTURE_CHAN_MIXER_ROUTE_BACK_8     8
+#define        SIS_CAPTURE_CHAN_MIXER_ROUTE_BACK_9     9
+#define        SIS_CAPTURE_CHAN_MIXER_ROUTE_BACK_10    10
+#define        SIS_CAPTURE_CHAN_MIXER_ROUTE_BACK_11    11
+#define        SIS_CAPTURE_CHAN_MIXER_ROUTE_BACK_12    12
+#define        SIS_CAPTURE_CHAN_MIXER_ROUTE_BACK_13    13
+#define        SIS_CAPTURE_CHAN_MIXER_ROUTE_BACK_14    14
+#define        SIS_CAPTURE_CHAN_MIXER_ROUTE_BACK_15    15
+#define        SIS_CAPTURE_CHAN_AC97_PCM_IN            16
+#define        SIS_CAPTURE_CHAN_AC97_MIC_IN            17
+#define        SIS_CAPTURE_CHAN_AC97_LINE1_IN          18
+#define        SIS_CAPTURE_CHAN_AC97_LINE2_IN          19
+#define        SIS_CAPTURE_CHAN_AC97_HANDSE_IN         20
+
+#define SIS_CAPTURE_DMA_FORMAT_CSO     0x00
+#define                SIS_CAPTURE_DMA_MONO_MODE_MASK  0xc0000000
+#define                SIS_CAPTURE_DMA_MONO_MODE_AVG   0x00000000
+#define                SIS_CAPTURE_DMA_MONO_MODE_LEFT  0x40000000
+#define                SIS_CAPTURE_DMA_MONO_MODE_RIGHT 0x80000000
+#define                SIS_CAPTURE_DMA_FORMAT_UNSIGNED 0x00080000
+#define                SIS_CAPTURE_DMA_FORMAT_8BIT     0x00040000
+#define                SIS_CAPTURE_DMA_FORMAT_MONO     0x00020000
+#define                SIS_CAPTURE_DMA_CSO_MASK                0x0000ffff
+#define SIS_CAPTURE_DMA_BASE           0x04
+#define SIS_CAPTURE_DMA_CONTROL                0x08
+#define                SIS_CAPTURE_DMA_STOP_AT_SSO     0x04000000
+#define                SIS_CAPTURE_DMA_RELEASE         0x02000000
+#define                SIS_CAPTURE_DMA_LOOP            0x01000000
+#define                SIS_CAPTURE_DMA_INTR_AT_LEO     0x00020000
+#define                SIS_CAPTURE_DMA_INTR_AT_MLP     0x00010000
+#define                SIS_CAPTURE_DMA_LEO_MASK                0x0000ffff
+#define SIS_CAPTURE_DMA_RESERVED       0x0c
+
+
+/* Mixer routing list start pointer (parameter RAM) */
+#define SIS_MIXER_START_OFFSET 0x1000
+#define SIS_MIXER_START_SIZE   0x04
+#define SIS_MIXER_START_ADDR(addr, num) \
+       ((num * SIS_MIXER_START_SIZE) + (addr) + SIS_MIXER_START_OFFSET)
+
+#define SIS_MIXER_START_MASK   0x0000007f
+
+/* Mixer routing table (parameter RAM) */
+#define SIS_MIXER_OFFSET       0x1400
+#define SIS_MIXER_SIZE         0x04
+#define SIS_MIXER_ADDR(addr, num) \
+       ((num * SIS_MIXER_SIZE) + (addr) + SIS_MIXER_OFFSET)
+
+#define SIS_MIXER_RIGHT_ATTENUTATION_MASK      0xff000000
+#define        SIS_MIXER_RIGHT_NO_ATTEN                0xff000000
+#define SIS_MIXER_LEFT_ATTENUTATION_MASK       0x00ff0000
+#define        SIS_MIXER_LEFT_NO_ATTEN                 0x00ff0000
+#define SIS_MIXER_NEXT_ENTRY_MASK              0x00007f00
+#define        SIS_MIXER_NEXT_ENTRY_NONE               0x00000000
+#define SIS_MIXER_DEST_MASK                    0x0000007f
+#define        SIS_MIXER_DEST_0                        0x00000020
+#define        SIS_MIXER_DEST_1                        0x00000021
+#define        SIS_MIXER_DEST_2                        0x00000022
+#define        SIS_MIXER_DEST_3                        0x00000023
+#define        SIS_MIXER_DEST_4                        0x00000024
+#define        SIS_MIXER_DEST_5                        0x00000025
+#define        SIS_MIXER_DEST_6                        0x00000026
+#define        SIS_MIXER_DEST_7                        0x00000027
+#define        SIS_MIXER_DEST_8                        0x00000028
+#define        SIS_MIXER_DEST_9                        0x00000029
+#define        SIS_MIXER_DEST_10                       0x0000002a
+#define        SIS_MIXER_DEST_11                       0x0000002b
+#define        SIS_MIXER_DEST_12                       0x0000002c
+#define        SIS_MIXER_DEST_13                       0x0000002d
+#define        SIS_MIXER_DEST_14                       0x0000002e
+#define        SIS_MIXER_DEST_15                       0x0000002f
+
+/* Wave Engine Control Parameters (parameter RAM) */
+#define SIS_WAVE_OFFSET                0x2000
+#define SIS_WAVE_SIZE          0x40
+#define SIS_WAVE_ADDR(addr, num) \
+       ((num * SIS_WAVE_SIZE) + (addr) + SIS_WAVE_OFFSET)
+
+#define SIS_WAVE_GENERAL               0x00
+#define                SIS_WAVE_GENERAL_WAVE_VOLUME                    0x80000000
+#define                SIS_WAVE_GENERAL_MUSIC_VOLUME                   0x00000000
+#define                SIS_WAVE_GENERAL_VOLUME_MASK                    0x7f000000
+#define SIS_WAVE_GENERAL_ARTICULATION  0x04
+#define                SIS_WAVE_GENERAL_ARTICULATION_DELTA_MASK        0x3fff0000
+#define SIS_WAVE_ARTICULATION          0x08
+#define SIS_WAVE_TIMER                 0x0c
+#define SIS_WAVE_GENERATOR             0x10
+#define SIS_WAVE_CHANNEL_CONTROL       0x14
+#define                SIS_WAVE_CHANNEL_CONTROL_FIRST_SAMPLE           0x80000000
+#define                SIS_WAVE_CHANNEL_CONTROL_AMP_ENABLE             0x40000000
+#define                SIS_WAVE_CHANNEL_CONTROL_FILTER_ENABLE          0x20000000
+#define                SIS_WAVE_CHANNEL_CONTROL_INTERPOLATE_ENABLE     0x10000000
+#define SIS_WAVE_LFO_EG_CONTROL                0x18
+#define SIS_WAVE_LFO_EG_CONTROL_2      0x1c
+#define SIS_WAVE_LFO_EG_CONTROL_3      0x20
+#define SIS_WAVE_LFO_EG_CONTROL_4      0x24
+
+#endif /* __sis7019_h__ */
index 44a7f5fad5734c706d93631ebe0edab1fed53bae..0d3d305b0a0b0c2805ebf26cc1a0cd004a89db4d 100644 (file)
@@ -22,7 +22,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
index 65f2c218324c164d995c0e043f6266caf94d120c..88676b50f385edb7fd0c47f502f9a0da9030ed54 100644 (file)
@@ -4,16 +4,6 @@
 #
 
 snd-trident-objs := trident.o trident_main.o trident_memory.o
-snd-trident-synth-objs := trident_synth.o
-
-#
-# this function returns:
-#   "m" - CONFIG_SND_SEQUENCER is m
-#   <empty string> - CONFIG_SND_SEQUENCER is undefined
-#   otherwise parameter #1 value
-#
-sequencer = $(if $(subst y,,$(CONFIG_SND_SEQUENCER)),$(if $(1),m),$(if $(CONFIG_SND_SEQUENCER),$(1)))
 
 # Toplevel Module Dependency
 obj-$(CONFIG_SND_TRIDENT) += snd-trident.o
-obj-$(call sequencer,$(CONFIG_SND_TRIDENT)) += snd-trident-synth.o
index 84884567df6a6586cf0fb40cfac21769664127ac..d94b16ffb38554660a8bd2647ad4d9024be2927f 100644 (file)
@@ -21,7 +21,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/pci.h>
 #include <linux/time.h>
@@ -155,13 +154,6 @@ static int __devinit snd_trident_probe(struct pci_dev *pci,
                return err;
        }
 
-#if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE))
-       if ((err = snd_trident_attach_synthesizer(trident)) < 0) {
-               snd_card_free(card);
-               return err;
-       }
-#endif
-
        snd_trident_create_gameport(trident);
 
        if ((err = snd_card_register(card)) < 0) {
index a235e034a690b36fb7b86bb14e65109f11d72af3..71138ff9b310237faedee66ea9a0445994bbb0a2 100644 (file)
@@ -27,7 +27,6 @@
  *  SiS7018 S/PDIF support by Thomas Winischhofer <thomas@winischhofer.net>
  */
 
-#include <sound/driver.h>
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
@@ -436,7 +435,7 @@ static void snd_trident_free_synth_channel(struct snd_trident *trident, int chan
    Description: This routine will complete and write the 5 hardware channel
                 registers to hardware.
   
-   Paramters:   trident - pointer to target device class for 4DWave.
+   Parameters:  trident - pointer to target device class for 4DWave.
                 voice - synthesizer voice structure
                 Each register field.
   
@@ -514,7 +513,7 @@ EXPORT_SYMBOL(snd_trident_write_voice_regs);
    Description: This routine will write the new CSO offset
                 register to hardware.
   
-   Paramters:   trident - pointer to target device class for 4DWave.
+   Parameters:  trident - pointer to target device class for 4DWave.
                 voice - synthesizer voice structure
                 CSO - new CSO value
   
@@ -540,7 +539,7 @@ static void snd_trident_write_cso_reg(struct snd_trident * trident,
    Description: This routine will write the new ESO offset
                 register to hardware.
   
-   Paramters:   trident - pointer to target device class for 4DWave.
+   Parameters:  trident - pointer to target device class for 4DWave.
                 voice - synthesizer voice structure
                 ESO - new ESO value
   
@@ -566,7 +565,7 @@ static void snd_trident_write_eso_reg(struct snd_trident * trident,
    Description: This routine will write the new voice volume
                 register to hardware.
   
-   Paramters:   trident - pointer to target device class for 4DWave.
+   Parameters:  trident - pointer to target device class for 4DWave.
                 voice - synthesizer voice structure
                 Vol - new voice volume
   
@@ -597,7 +596,7 @@ static void snd_trident_write_vol_reg(struct snd_trident * trident,
    Description: This routine will write the new voice pan
                 register to hardware.
   
-   Paramters:   trident - pointer to target device class for 4DWave.
+   Parameters:  trident - pointer to target device class for 4DWave.
                 voice - synthesizer voice structure
                 Pan - new pan value
   
@@ -619,7 +618,7 @@ static void snd_trident_write_pan_reg(struct snd_trident * trident,
    Description: This routine will write the new reverb volume
                 register to hardware.
   
-   Paramters:   trident - pointer to target device class for 4DWave.
+   Parameters:  trident - pointer to target device class for 4DWave.
                 voice - synthesizer voice structure
                 RVol - new reverb volume
   
@@ -643,7 +642,7 @@ static void snd_trident_write_rvol_reg(struct snd_trident * trident,
    Description: This routine will write the new chorus volume
                 register to hardware.
   
-   Paramters:   trident - pointer to target device class for 4DWave.
+   Parameters:  trident - pointer to target device class for 4DWave.
                 voice - synthesizer voice structure
                 CVol - new chorus volume
   
@@ -666,7 +665,7 @@ static void snd_trident_write_cvol_reg(struct snd_trident * trident,
 
    Description: This routine converts rate in HZ to hardware delta value.
   
-   Paramters:   trident - pointer to target device class for 4DWave.
+   Parameters:  trident - pointer to target device class for 4DWave.
                 rate - Real or Virtual channel number.
   
    Returns:     Delta value.
@@ -696,7 +695,7 @@ static unsigned int snd_trident_convert_rate(unsigned int rate)
 
    Description: This routine converts rate in HZ to hardware delta value.
   
-   Paramters:   trident - pointer to target device class for 4DWave.
+   Parameters:  trident - pointer to target device class for 4DWave.
                 rate - Real or Virtual channel number.
   
    Returns:     Delta value.
@@ -726,7 +725,7 @@ static unsigned int snd_trident_convert_adc_rate(unsigned int rate)
 
    Description: This routine converts rate in HZ to spurious threshold.
   
-   Paramters:   trident - pointer to target device class for 4DWave.
+   Parameters:  trident - pointer to target device class for 4DWave.
                 rate - Real or Virtual channel number.
   
    Returns:     Delta value.
@@ -748,7 +747,7 @@ static unsigned int snd_trident_spurious_threshold(unsigned int rate,
 
    Description: This routine returns a control mode for a PCM channel.
   
-   Paramters:   trident - pointer to target device class for 4DWave.
+   Parameters:  trident - pointer to target device class for 4DWave.
                 substream  - PCM substream
   
    Returns:     Control value.
@@ -781,7 +780,7 @@ static unsigned int snd_trident_control_mode(struct snd_pcm_substream *substream
   
    Description: Device I/O control handler for playback/capture parameters.
   
-   Paramters:   substream  - PCM substream class
+   Parameters:   substream  - PCM substream class
                 cmd     - what ioctl message to process
                 arg     - additional message infoarg     
   
@@ -1664,7 +1663,7 @@ static snd_pcm_uframes_t snd_trident_playback_pointer(struct snd_pcm_substream *
   
    Description: This routine return the capture position
                 
-   Paramters:   pcm1    - PCM device class
+   Parameters:   pcm1    - PCM device class
 
    Returns:     position of buffer
   
@@ -2157,7 +2156,7 @@ static struct snd_pcm_ops snd_trident_spdif_7018_ops = {
   
    Description: This routine registers the 4DWave device for PCM support.
                 
-   Paramters:   trident - pointer to target device class for 4DWave.
+   Parameters:  trident - pointer to target device class for 4DWave.
 
    Returns:     None
   
@@ -2215,7 +2214,7 @@ int __devinit snd_trident_pcm(struct snd_trident * trident,
   
    Description: This routine registers the 4DWave device for foldback PCM support.
                 
-   Paramters:   trident - pointer to target device class for 4DWave.
+   Parameters:  trident - pointer to target device class for 4DWave.
 
    Returns:     None
   
@@ -2272,7 +2271,7 @@ int __devinit snd_trident_foldback_pcm(struct snd_trident * trident,
   
    Description: This routine registers the 4DWave-NX device for SPDIF support.
                 
-   Paramters:   trident - pointer to target device class for 4DWave-NX.
+   Parameters:  trident - pointer to target device class for 4DWave-NX.
 
    Returns:     None
   
@@ -2956,7 +2955,7 @@ static int snd_trident_pcm_mixer_free(struct snd_trident *trident, struct snd_tr
   
    Description: This routine registers the 4DWave device for mixer support.
                 
-   Paramters:   trident - pointer to target device class for 4DWave.
+   Parameters:  trident - pointer to target device class for 4DWave.
 
    Returns:     None
   
@@ -3313,12 +3312,6 @@ static void snd_trident_proc_read(struct snd_info_entry *entry,
                        snd_iprintf(buffer, "Memory Free    : %d\n", snd_util_mem_avail(trident->tlb.memhdr));
                }
        }
-#if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE))
-       snd_iprintf(buffer,"\nWavetable Synth\n");
-       snd_iprintf(buffer, "Memory Maximum : %d\n", trident->synth.max_size);
-       snd_iprintf(buffer, "Memory Used    : %d\n", trident->synth.current_size);
-       snd_iprintf(buffer, "Memory Free    : %d\n", (trident->synth.max_size-trident->synth.current_size));
-#endif
 }
 
 static void __devinit snd_trident_proc_init(struct snd_trident * trident)
@@ -3344,7 +3337,7 @@ static int snd_trident_dev_free(struct snd_device *device)
    Description: Allocate and set up the TLB page table on 4D NX.
                Each entry has 4 bytes (physical PCI address).
                 
-   Paramters:   trident - pointer to target device class for 4DWave.
+   Parameters:  trident - pointer to target device class for 4DWave.
 
    Returns:     0 or negative error code
   
@@ -3521,7 +3514,7 @@ static int snd_trident_sis_init(struct snd_trident *trident)
    Description: This routine will create the device specific class for
                 the 4DWave card. It will also perform basic initialization.
                 
-   Paramters:   card  - which card to create
+   Parameters:  card  - which card to create
                 pci   - interface to PCI bus resource info
                 dma1ptr - playback dma buffer
                 dma2ptr - capture dma buffer
@@ -3667,7 +3660,7 @@ int __devinit snd_trident_create(struct snd_card *card,
    Description: This routine will free the device specific class for
                 the 4DWave card. 
                 
-   Paramters:   trident  - device specific private data for 4DWave card
+   Parameters:  trident  - device specific private data for 4DWave card
 
    Returns:     None.
   
@@ -3705,7 +3698,7 @@ static int snd_trident_free(struct snd_trident *trident)
   
    Description: ISR for Trident 4DWave device
                 
-   Paramters:   trident  - device specific private data for 4DWave card
+   Parameters:  trident  - device specific private data for 4DWave card
 
    Problems:    It seems that Trident chips generates interrupts more than
                 one time in special cases. The spurious interrupts are
@@ -3815,28 +3808,6 @@ static irqreturn_t snd_trident_interrupt(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-/*---------------------------------------------------------------------------
-   snd_trident_attach_synthesizer
-  
-   Description: Attach synthesizer hooks
-                
-   Paramters:   trident  - device specific private data for 4DWave card
-
-   Returns:     None.
-  
-  ---------------------------------------------------------------------------*/
-int snd_trident_attach_synthesizer(struct snd_trident *trident)
-{      
-#if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE))
-       if (snd_seq_device_new(trident->card, 1, SNDRV_SEQ_DEV_ID_TRIDENT,
-                              sizeof(struct snd_trident *), &trident->seq_dev) >= 0) {
-               strcpy(trident->seq_dev->name, "4DWave");
-               *(struct snd_trident **)SNDRV_SEQ_DEVICE_ARGPTR(trident->seq_dev) = trident;
-       }
-#endif
-       return 0;
-}
-
 struct snd_trident_voice *snd_trident_alloc_voice(struct snd_trident * trident, int type, int client, int port)
 {
        struct snd_trident_voice *pvoice;
index 847b8c6d5c0a3edc557f655e44781412feab3310..df9b487fa17e7ca582e1eaae362656ca591e6620 100644 (file)
@@ -23,7 +23,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <asm/io.h>
 #include <linux/pci.h>
 #include <linux/time.h>
diff --git a/sound/pci/trident/trident_synth.c b/sound/pci/trident/trident_synth.c
deleted file mode 100644 (file)
index 9b7dee8..0000000
+++ /dev/null
@@ -1,1024 +0,0 @@
-/*
- *  Routines for Trident 4DWave NX/DX soundcards - Synthesizer
- *  Copyright (c) by Scott McNab <jedi@tartarus.uwa.edu.au>
- *
- *
- *   This program is free software; you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   the Free Software Foundation; either version 2 of the License, or
- *   (at your option) any later version.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program; if not, write to the Free Software
- *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
- *
- */
-
-#include <sound/driver.h>
-#include <asm/io.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/pci.h>
-#include <sound/core.h>
-#include <sound/trident.h>
-#include <sound/seq_device.h>
-
-MODULE_AUTHOR("Scott McNab <jedi@tartarus.uwa.edu.au>");
-MODULE_DESCRIPTION("Routines for Trident 4DWave NX/DX soundcards - Synthesizer");
-MODULE_LICENSE("GPL");
-
-/* linear to log pan conversion table (4.2 channel attenuation format) */
-static unsigned int pan_table[63] = {
-       7959, 7733, 7514, 7301, 7093, 6892, 6697, 6507, 
-       6322, 6143, 5968, 5799, 5634, 5475, 5319, 5168, 
-       5022, 4879, 4741, 4606, 4475, 4349, 4225, 4105, 
-       3989, 3876, 3766, 3659, 3555, 3454, 3356, 3261, 
-       3168, 3078, 2991, 2906, 2824, 2744, 2666, 2590, 
-       2517, 2445, 2376, 2308, 2243, 2179, 2117, 2057, 
-       1999, 1942, 1887, 1833, 1781, 1731, 1682, 1634, 
-       1588, 1543, 1499, 1456, 1415, 1375, 1336
-};
-
-#define LOG_TABLE_SIZE 386
-
-/* Linear half-attenuation to log conversion table in the format:
- *   {linear volume, logarithmic attenuation equivalent}, ...
- *
- * Provides conversion from a linear half-volume value in the range
- * [0,8192] to a logarithmic attenuation value in the range 0 to 6.02dB.
- * Halving the linear volume is equivalent to an additional 6dB of 
- * logarithmic attenuation. The algorithm used in log_from_linear()
- * therefore uses this table as follows:
- * 
- * - loop and for every time the volume is less than half the maximum 
- *   volume (16384), add another 6dB and halve the maximum value used
- *   for this comparison.
- * - when the volume is greater than half the maximum volume, take
- *   the difference of the volume to half volume (in the range [0,8192])
- *   and look up the log_table[] to find the nearest entry.
- * - take the logarithic component of this entry and add it to the 
- *   resulting attenuation.
- *
- * Thus this routine provides a linear->log conversion for a range of
- * [0,16384] using only 386 table entries
- *
- * Note: although this table stores log attenuation in 8.8 format, values
- * were only calculated for 6 bits fractional precision, since that is
- * the most precision offered by the trident hardware.
- */
-
-static unsigned short log_table[LOG_TABLE_SIZE*2] =
-{
-       4, 0x0604, 19, 0x0600, 34, 0x05fc, 
-       49, 0x05f8, 63, 0x05f4, 78, 0x05f0, 93, 0x05ec, 108, 0x05e8, 
-       123, 0x05e4, 138, 0x05e0, 153, 0x05dc, 168, 0x05d8, 183, 0x05d4, 
-       198, 0x05d0, 213, 0x05cc, 228, 0x05c8, 244, 0x05c4, 259, 0x05c0, 
-       274, 0x05bc, 289, 0x05b8, 304, 0x05b4, 320, 0x05b0, 335, 0x05ac, 
-       350, 0x05a8, 366, 0x05a4, 381, 0x05a0, 397, 0x059c, 412, 0x0598, 
-       428, 0x0594, 443, 0x0590, 459, 0x058c, 474, 0x0588, 490, 0x0584, 
-       506, 0x0580, 521, 0x057c, 537, 0x0578, 553, 0x0574, 568, 0x0570, 
-       584, 0x056c, 600, 0x0568, 616, 0x0564, 632, 0x0560, 647, 0x055c, 
-       663, 0x0558, 679, 0x0554, 695, 0x0550, 711, 0x054c, 727, 0x0548, 
-       743, 0x0544, 759, 0x0540, 776, 0x053c, 792, 0x0538, 808, 0x0534, 
-       824, 0x0530, 840, 0x052c, 857, 0x0528, 873, 0x0524, 889, 0x0520, 
-       906, 0x051c, 922, 0x0518, 938, 0x0514, 955, 0x0510, 971, 0x050c, 
-       988, 0x0508, 1004, 0x0504, 1021, 0x0500, 1037, 0x04fc, 1054, 0x04f8, 
-       1071, 0x04f4, 1087, 0x04f0, 1104, 0x04ec, 1121, 0x04e8, 1138, 0x04e4, 
-       1154, 0x04e0, 1171, 0x04dc, 1188, 0x04d8, 1205, 0x04d4, 1222, 0x04d0, 
-       1239, 0x04cc, 1256, 0x04c8, 1273, 0x04c4, 1290, 0x04c0, 1307, 0x04bc, 
-       1324, 0x04b8, 1341, 0x04b4, 1358, 0x04b0, 1376, 0x04ac, 1393, 0x04a8, 
-       1410, 0x04a4, 1427, 0x04a0, 1445, 0x049c, 1462, 0x0498, 1479, 0x0494, 
-       1497, 0x0490, 1514, 0x048c, 1532, 0x0488, 1549, 0x0484, 1567, 0x0480, 
-       1584, 0x047c, 1602, 0x0478, 1620, 0x0474, 1637, 0x0470, 1655, 0x046c, 
-       1673, 0x0468, 1690, 0x0464, 1708, 0x0460, 1726, 0x045c, 1744, 0x0458, 
-       1762, 0x0454, 1780, 0x0450, 1798, 0x044c, 1816, 0x0448, 1834, 0x0444, 
-       1852, 0x0440, 1870, 0x043c, 1888, 0x0438, 1906, 0x0434, 1924, 0x0430, 
-       1943, 0x042c, 1961, 0x0428, 1979, 0x0424, 1997, 0x0420, 2016, 0x041c, 
-       2034, 0x0418, 2053, 0x0414, 2071, 0x0410, 2089, 0x040c, 2108, 0x0408, 
-       2127, 0x0404, 2145, 0x0400, 2164, 0x03fc, 2182, 0x03f8, 2201, 0x03f4, 
-       2220, 0x03f0, 2239, 0x03ec, 2257, 0x03e8, 2276, 0x03e4, 2295, 0x03e0, 
-       2314, 0x03dc, 2333, 0x03d8, 2352, 0x03d4, 2371, 0x03d0, 2390, 0x03cc, 
-       2409, 0x03c8, 2428, 0x03c4, 2447, 0x03c0, 2466, 0x03bc, 2485, 0x03b8, 
-       2505, 0x03b4, 2524, 0x03b0, 2543, 0x03ac, 2562, 0x03a8, 2582, 0x03a4, 
-       2601, 0x03a0, 2621, 0x039c, 2640, 0x0398, 2660, 0x0394, 2679, 0x0390, 
-       2699, 0x038c, 2718, 0x0388, 2738, 0x0384, 2758, 0x0380, 2777, 0x037c, 
-       2797, 0x0378, 2817, 0x0374, 2837, 0x0370, 2857, 0x036c, 2876, 0x0368, 
-       2896, 0x0364, 2916, 0x0360, 2936, 0x035c, 2956, 0x0358, 2976, 0x0354, 
-       2997, 0x0350, 3017, 0x034c, 3037, 0x0348, 3057, 0x0344, 3077, 0x0340, 
-       3098, 0x033c, 3118, 0x0338, 3138, 0x0334, 3159, 0x0330, 3179, 0x032c, 
-       3200, 0x0328, 3220, 0x0324, 3241, 0x0320, 3261, 0x031c, 3282, 0x0318, 
-       3303, 0x0314, 3323, 0x0310, 3344, 0x030c, 3365, 0x0308, 3386, 0x0304, 
-       3406, 0x0300, 3427, 0x02fc, 3448, 0x02f8, 3469, 0x02f4, 3490, 0x02f0, 
-       3511, 0x02ec, 3532, 0x02e8, 3553, 0x02e4, 3575, 0x02e0, 3596, 0x02dc, 
-       3617, 0x02d8, 3638, 0x02d4, 3660, 0x02d0, 3681, 0x02cc, 3702, 0x02c8, 
-       3724, 0x02c4, 3745, 0x02c0, 3767, 0x02bc, 3788, 0x02b8, 3810, 0x02b4, 
-       3831, 0x02b0, 3853, 0x02ac, 3875, 0x02a8, 3896, 0x02a4, 3918, 0x02a0, 
-       3940, 0x029c, 3962, 0x0298, 3984, 0x0294, 4006, 0x0290, 4028, 0x028c, 
-       4050, 0x0288, 4072, 0x0284, 4094, 0x0280, 4116, 0x027c, 4138, 0x0278, 
-       4160, 0x0274, 4182, 0x0270, 4205, 0x026c, 4227, 0x0268, 4249, 0x0264, 
-       4272, 0x0260, 4294, 0x025c, 4317, 0x0258, 4339, 0x0254, 4362, 0x0250, 
-       4384, 0x024c, 4407, 0x0248, 4430, 0x0244, 4453, 0x0240, 4475, 0x023c, 
-       4498, 0x0238, 4521, 0x0234, 4544, 0x0230, 4567, 0x022c, 4590, 0x0228, 
-       4613, 0x0224, 4636, 0x0220, 4659, 0x021c, 4682, 0x0218, 4705, 0x0214, 
-       4728, 0x0210, 4752, 0x020c, 4775, 0x0208, 4798, 0x0204, 4822, 0x0200, 
-       4845, 0x01fc, 4869, 0x01f8, 4892, 0x01f4, 4916, 0x01f0, 4939, 0x01ec, 
-       4963, 0x01e8, 4987, 0x01e4, 5010, 0x01e0, 5034, 0x01dc, 5058, 0x01d8, 
-       5082, 0x01d4, 5106, 0x01d0, 5130, 0x01cc, 5154, 0x01c8, 5178, 0x01c4, 
-       5202, 0x01c0, 5226, 0x01bc, 5250, 0x01b8, 5274, 0x01b4, 5299, 0x01b0, 
-       5323, 0x01ac, 5347, 0x01a8, 5372, 0x01a4, 5396, 0x01a0, 5420, 0x019c, 
-       5445, 0x0198, 5469, 0x0194, 5494, 0x0190, 5519, 0x018c, 5543, 0x0188, 
-       5568, 0x0184, 5593, 0x0180, 5618, 0x017c, 5643, 0x0178, 5668, 0x0174, 
-       5692, 0x0170, 5717, 0x016c, 5743, 0x0168, 5768, 0x0164, 5793, 0x0160, 
-       5818, 0x015c, 5843, 0x0158, 5868, 0x0154, 5894, 0x0150, 5919, 0x014c, 
-       5945, 0x0148, 5970, 0x0144, 5995, 0x0140, 6021, 0x013c, 6047, 0x0138, 
-       6072, 0x0134, 6098, 0x0130, 6124, 0x012c, 6149, 0x0128, 6175, 0x0124, 
-       6201, 0x0120, 6227, 0x011c, 6253, 0x0118, 6279, 0x0114, 6305, 0x0110, 
-       6331, 0x010c, 6357, 0x0108, 6384, 0x0104, 6410, 0x0100, 6436, 0x00fc, 
-       6462, 0x00f8, 6489, 0x00f4, 6515, 0x00f0, 6542, 0x00ec, 6568, 0x00e8, 
-       6595, 0x00e4, 6621, 0x00e0, 6648, 0x00dc, 6675, 0x00d8, 6702, 0x00d4, 
-       6728, 0x00d0, 6755, 0x00cc, 6782, 0x00c8, 6809, 0x00c4, 6836, 0x00c0, 
-       6863, 0x00bc, 6890, 0x00b8, 6917, 0x00b4, 6945, 0x00b0, 6972, 0x00ac, 
-       6999, 0x00a8, 7027, 0x00a4, 7054, 0x00a0, 7081, 0x009c, 7109, 0x0098, 
-       7136, 0x0094, 7164, 0x0090, 7192, 0x008c, 7219, 0x0088, 7247, 0x0084, 
-       7275, 0x0080, 7303, 0x007c, 7331, 0x0078, 7359, 0x0074, 7387, 0x0070, 
-       7415, 0x006c, 7443, 0x0068, 7471, 0x0064, 7499, 0x0060, 7527, 0x005c, 
-       7556, 0x0058, 7584, 0x0054, 7613, 0x0050, 7641, 0x004c, 7669, 0x0048, 
-       7698, 0x0044, 7727, 0x0040, 7755, 0x003c, 7784, 0x0038, 7813, 0x0034, 
-       7842, 0x0030, 7870, 0x002c, 7899, 0x0028, 7928, 0x0024, 7957, 0x0020, 
-       7986, 0x001c, 8016, 0x0018, 8045, 0x0014, 8074, 0x0010, 8103, 0x000c, 
-       8133, 0x0008, 8162, 0x0004, 8192, 0x0000
-};
-
-static unsigned short lookup_volume_table( unsigned short value )
-{
-       /* This code is an optimised version of:
-        *   int i = 0;
-        *   while( volume_table[i*2] < value )
-        *       i++;
-        *   return volume_table[i*2+1];
-        */
-       unsigned short *ptr = log_table;
-       while( *ptr < value )
-               ptr += 2;
-       return *(ptr+1);
-}
-
-/* this function calculates a 8.8 fixed point logarithmic attenuation
- * value from a linear volume value in the range 0 to 16384 */
-static unsigned short log_from_linear( unsigned short value )
-{
-       if (value >= 16384)
-               return 0x0000;
-       if (value) {
-               unsigned short result = 0;
-               int v, c;
-               for( c = 0, v = 8192; c < 14; c++, v >>= 1 ) {
-                       if( value >= v ) {
-                               result += lookup_volume_table( (value - v) << c );
-                               return result;
-                       }
-                       result += 0x0605;       /* 6.0205 (result of -20*log10(0.5)) */
-               }
-       }
-       return 0xffff;
-}
-
-/*
- * Sample handling operations
- */
-
-static void sample_start(struct snd_trident * trident, struct snd_trident_voice * voice, snd_seq_position_t position);
-static void sample_stop(struct snd_trident * trident, struct snd_trident_voice * voice, int mode);
-static void sample_freq(struct snd_trident * trident, struct snd_trident_voice * voice, snd_seq_frequency_t freq);
-static void sample_volume(struct snd_trident * trident, struct snd_trident_voice * voice, struct snd_seq_ev_volume * volume);
-static void sample_loop(struct snd_trident * trident, struct snd_trident_voice * voice, struct snd_seq_ev_loop * loop);
-static void sample_pos(struct snd_trident * trident, struct snd_trident_voice * voice, snd_seq_position_t position);
-static void sample_private1(struct snd_trident * trident, struct snd_trident_voice * voice, unsigned char *data);
-
-static struct snd_trident_sample_ops sample_ops =
-{
-       sample_start,
-       sample_stop,
-       sample_freq,
-       sample_volume,
-       sample_loop,
-       sample_pos,
-       sample_private1
-};
-
-static void snd_trident_simple_init(struct snd_trident_voice * voice)
-{
-       //voice->handler_wave = interrupt_wave;
-       //voice->handler_volume = interrupt_volume;
-       //voice->handler_effect = interrupt_effect;
-       //voice->volume_change = NULL;
-       voice->sample_ops = &sample_ops;
-}
-
-static void sample_start(struct snd_trident * trident, struct snd_trident_voice * voice, snd_seq_position_t position)
-{
-       struct simple_instrument *simple;
-       struct snd_seq_kinstr *instr;
-       unsigned long flags;
-       unsigned int loop_start, loop_end, sample_start, sample_end, start_offset;
-       unsigned int value;
-       unsigned int shift = 0;
-
-       instr = snd_seq_instr_find(trident->synth.ilist, &voice->instr, 0, 1);
-       if (instr == NULL)
-               return;
-       voice->instr = instr->instr;    /* copy ID to speedup aliases */
-       simple = KINSTR_DATA(instr);
-
-       spin_lock_irqsave(&trident->reg_lock, flags);
-
-       if (trident->device == TRIDENT_DEVICE_ID_SI7018)
-               voice->GVSel = 1;       /* route to Wave volume */
-
-       voice->CTRL = 0;
-       voice->Alpha = 0;
-       voice->FMS = 0;
-
-       loop_start = simple->loop_start >> 4;
-       loop_end = simple->loop_end >> 4;
-       sample_start = (simple->start + position) >> 4;
-       if( sample_start >= simple->size )
-               sample_start = simple->start >> 4;
-       sample_end = simple->size;
-       start_offset = position >> 4;
-
-       if (simple->format & SIMPLE_WAVE_16BIT) {
-               voice->CTRL |= 8;
-               shift++;
-       }
-       if (simple->format & SIMPLE_WAVE_STEREO) {
-               voice->CTRL |= 4;
-               shift++;
-       }
-       if (!(simple->format & SIMPLE_WAVE_UNSIGNED))
-               voice->CTRL |= 2;
-
-       voice->LBA = simple->address.memory;
-
-       if (simple->format & SIMPLE_WAVE_LOOP) {
-               voice->CTRL |= 1;
-               voice->LBA += loop_start << shift;
-               if( start_offset >= loop_start ) {
-                       voice->CSO = start_offset - loop_start;
-                       voice->negCSO = 0;
-               } else {
-                       voice->CSO = loop_start - start_offset;
-                       voice->negCSO = 1;
-               }
-               voice->ESO = loop_end - loop_start - 1;
-       } else {
-               voice->LBA += start_offset << shift;
-               voice->CSO = sample_start;
-               voice->ESO = sample_end - 1;
-               voice->negCSO = 0;
-       }
-
-       if (voice->flags & SNDRV_TRIDENT_VFLG_RUNNING) {
-               snd_trident_stop_voice(trident, voice->number);
-               voice->flags &= ~SNDRV_TRIDENT_VFLG_RUNNING;
-       }
-
-       /* set CSO sign */
-       value = inl(TRID_REG(trident, T4D_SIGN_CSO_A));
-       if( voice->negCSO ) {
-               value |= 1 << (voice->number&31);
-       } else {
-               value &= ~(1 << (voice->number&31));
-       }
-       outl(value,TRID_REG(trident, T4D_SIGN_CSO_A));
-
-       voice->Attribute = 0;   
-       snd_trident_write_voice_regs(trident, voice);
-       snd_trident_start_voice(trident, voice->number);
-       voice->flags |= SNDRV_TRIDENT_VFLG_RUNNING;
-       spin_unlock_irqrestore(&trident->reg_lock, flags);
-       snd_seq_instr_free_use(trident->synth.ilist, instr);
-}
-
-static void sample_stop(struct snd_trident * trident, struct snd_trident_voice * voice, int mode)
-{
-       unsigned long flags;
-
-       if (!(voice->flags & SNDRV_TRIDENT_VFLG_RUNNING))
-               return;
-
-       switch (mode) {
-       default:
-               spin_lock_irqsave(&trident->reg_lock, flags);
-               snd_trident_stop_voice(trident, voice->number);
-               voice->flags &= ~SNDRV_TRIDENT_VFLG_RUNNING;
-               spin_unlock_irqrestore(&trident->reg_lock, flags);
-               break;
-       case SAMPLE_STOP_LOOP:  /* disable loop only */
-               voice->CTRL &= ~1;
-               spin_lock_irqsave(&trident->reg_lock, flags);
-               outb((unsigned char) voice->number, TRID_REG(trident, T4D_LFO_GC_CIR));
-               outw((((voice->CTRL << 12) | (voice->EC & 0x0fff)) & 0xffff), CH_GVSEL_PAN_VOL_CTRL_EC);
-               spin_unlock_irqrestore(&trident->reg_lock, flags);
-               break;
-       }
-}
-
-static void sample_freq(struct snd_trident * trident, struct snd_trident_voice * voice, snd_seq_frequency_t freq)
-{
-       unsigned long flags;
-       freq >>= 4;
-
-       spin_lock_irqsave(&trident->reg_lock, flags);
-       if (freq == 44100)
-               voice->Delta = 0xeb3;
-       else if (freq == 8000)
-               voice->Delta = 0x2ab;
-       else if (freq == 48000)
-               voice->Delta = 0x1000;
-       else
-               voice->Delta = (((freq << 12) + freq) / 48000) & 0x0000ffff;
-
-       outb((unsigned char) voice->number, TRID_REG(trident, T4D_LFO_GC_CIR));
-       if (trident->device == TRIDENT_DEVICE_ID_NX) {
-               outb((unsigned char) voice->Delta, TRID_REG(trident, CH_NX_DELTA_CSO + 3));
-               outb((unsigned char) (voice->Delta >> 8), TRID_REG(trident, CH_NX_DELTA_ESO + 3));
-       } else {
-               outw((unsigned short) voice->Delta, TRID_REG(trident, CH_DX_ESO_DELTA));
-       }
-
-       spin_unlock_irqrestore(&trident->reg_lock, flags);
-}
-
-static void sample_volume(struct snd_trident * trident, struct snd_trident_voice * voice, struct snd_seq_ev_volume * volume)
-{
-       unsigned long flags;
-       unsigned short value;
-
-       spin_lock_irqsave(&trident->reg_lock, flags);
-       voice->GVSel = 0;       /* use global music volume */
-       voice->FMC = 0x03;      /* fixme: can we do something useful with FMC? */
-       if (volume->volume >= 0) {
-               volume->volume &= 0x3fff;
-               /* linear volume -> logarithmic attenuation conversion
-                * uses EC register for greater resolution (6.6 bits) than Vol register (5.3 bits)
-                * Vol register used when additional attenuation is required */
-               voice->RVol = 0;
-               voice->CVol = 0;
-               value = log_from_linear( volume->volume );
-               voice->Vol = 0;
-               voice->EC = (value & 0x3fff) >> 2;
-               if (value > 0x3fff) {
-                       voice->EC |= 0xfc0;
-                       if (value < 0x5f00 )
-                               voice->Vol = ((value >> 8) - 0x3f) << 5;
-                       else {
-                               voice->Vol = 0x3ff;
-                               voice->EC = 0xfff;
-                       }
-               }
-       }
-       if (volume->lr >= 0) {
-               volume->lr &= 0x3fff;
-               /* approximate linear pan by attenuating channels */
-               if (volume->lr >= 0x2000) {     /* attenuate left (pan right) */
-                       value = 0x3fff - volume->lr;
-                       for (voice->Pan = 0; voice->Pan < 63; voice->Pan++ ) 
-                               if (value >= pan_table[voice->Pan] )
-                                       break;
-               } else {                        /* attenuate right (pan left) */
-                       for (voice->Pan = 0; voice->Pan < 63; voice->Pan++ ) 
-                               if ((unsigned int)volume->lr >= pan_table[voice->Pan] )
-                                       break;
-                       voice->Pan |= 0x40;
-               }
-       }
-       outb((unsigned char) voice->number, TRID_REG(trident, T4D_LFO_GC_CIR));
-       outl((voice->GVSel << 31) | ((voice->Pan & 0x0000007f) << 24) |
-                ((voice->Vol & 0x000000ff) << 16) | ((voice->CTRL & 0x0000000f) << 12) |
-                (voice->EC & 0x00000fff), TRID_REG(trident, CH_GVSEL_PAN_VOL_CTRL_EC));
-       value = ((voice->FMC & 0x03) << 14) | ((voice->RVol & 0x7f) << 7) | (voice->CVol & 0x7f);
-       outw(value, TRID_REG(trident, CH_DX_FMC_RVOL_CVOL));
-       spin_unlock_irqrestore(&trident->reg_lock, flags);
-}
-
-static void sample_loop(struct snd_trident * trident, struct snd_trident_voice * voice, struct snd_seq_ev_loop * loop)
-{
-       unsigned long flags;
-       struct simple_instrument *simple;
-       struct snd_seq_kinstr *instr;
-       unsigned int loop_start, loop_end;
-
-       instr = snd_seq_instr_find(trident->synth.ilist, &voice->instr, 0, 1);
-       if (instr == NULL)
-               return;
-       voice->instr = instr->instr;    /* copy ID to speedup aliases */
-       simple = KINSTR_DATA(instr);
-
-       loop_start = loop->start >> 4;
-       loop_end = loop->end >> 4;
-
-       spin_lock_irqsave(&trident->reg_lock, flags);
-
-       voice->LBA = simple->address.memory + loop_start;
-       voice->CSO = 0;
-       voice->ESO = loop_end - loop_start - 1;
-
-       outb((unsigned char) voice->number, TRID_REG(trident, T4D_LFO_GC_CIR));
-       outb((voice->LBA >> 16), TRID_REG(trident, CH_LBA + 2));
-       outw((voice->LBA & 0xffff), TRID_REG(trident, CH_LBA));
-       if (trident->device == TRIDENT_DEVICE_ID_NX) {
-               outb((voice->ESO >> 16), TRID_REG(trident, CH_NX_DELTA_ESO + 2));
-               outw((voice->ESO & 0xffff), TRID_REG(trident, CH_NX_DELTA_ESO));
-               outb((voice->CSO >> 16), TRID_REG(trident, CH_NX_DELTA_CSO + 2));
-               outw((voice->CSO & 0xffff), TRID_REG(trident, CH_NX_DELTA_CSO));
-       } else {
-               outw((voice->ESO & 0xffff), TRID_REG(trident, CH_DX_ESO_DELTA + 2));
-               outw((voice->CSO & 0xffff), TRID_REG(trident, CH_DX_CSO_ALPHA_FMS + 2));
-       }
-
-       spin_unlock_irqrestore(&trident->reg_lock, flags);
-       snd_seq_instr_free_use(trident->synth.ilist, instr);
-}
-
-static void sample_pos(struct snd_trident * trident, struct snd_trident_voice * voice, snd_seq_position_t position)
-{
-       unsigned long flags;
-       struct simple_instrument *simple;
-       struct snd_seq_kinstr *instr;
-       unsigned int value;
-
-       instr = snd_seq_instr_find(trident->synth.ilist, &voice->instr, 0, 1);
-       if (instr == NULL)
-               return;
-       voice->instr = instr->instr;    /* copy ID to speedup aliases */
-       simple = KINSTR_DATA(instr);
-
-       spin_lock_irqsave(&trident->reg_lock, flags);
-
-       if (simple->format & SIMPLE_WAVE_LOOP) {
-               if( position >= simple->loop_start ) {
-                       voice->CSO = (position - simple->loop_start) >> 4;
-                       voice->negCSO = 0;
-               } else {
-                       voice->CSO = (simple->loop_start - position) >> 4;
-                       voice->negCSO = 1;
-               }
-       } else {
-               voice->CSO = position >> 4;
-               voice->negCSO = 0;
-       }
-
-       /* set CSO sign */
-       value = inl(TRID_REG(trident, T4D_SIGN_CSO_A));
-       if( voice->negCSO ) {
-               value |= 1 << (voice->number&31);
-       } else {
-               value &= ~(1 << (voice->number&31));
-       }
-       outl(value,TRID_REG(trident, T4D_SIGN_CSO_A));
-       
-
-       outb((unsigned char) voice->number, TRID_REG(trident, T4D_LFO_GC_CIR));
-       if (trident->device == TRIDENT_DEVICE_ID_NX) {
-               outw((voice->CSO & 0xffff), TRID_REG(trident, CH_NX_DELTA_CSO));
-               outb((voice->CSO >> 16), TRID_REG(trident, CH_NX_DELTA_CSO + 2));
-       } else {
-               outw((voice->CSO & 0xffff), TRID_REG(trident, CH_DX_CSO_ALPHA_FMS) + 2);
-       }
-
-       spin_unlock_irqrestore(&trident->reg_lock, flags);
-       snd_seq_instr_free_use(trident->synth.ilist, instr);
-}
-
-static void sample_private1(struct snd_trident * trident, struct snd_trident_voice * voice, unsigned char *data)
-{
-}
-
-/*
- * Memory management / sample loading
- */
-
-static int snd_trident_simple_put_sample(void *private_data,
-                                        struct simple_instrument * instr,
-                                        char __user *data, long len, int atomic)
-{
-       struct snd_trident *trident = private_data;
-       int size = instr->size;
-       int shift = 0;
-
-       if (instr->format & SIMPLE_WAVE_BACKWARD ||
-           instr->format & SIMPLE_WAVE_BIDIR ||
-           instr->format & SIMPLE_WAVE_ULAW) 
-               return -EINVAL; /* not supported */
-
-       if (instr->format & SIMPLE_WAVE_16BIT)
-               shift++;
-       if (instr->format & SIMPLE_WAVE_STEREO)
-               shift++;
-       size <<= shift;
-
-       if (trident->synth.current_size + size > trident->synth.max_size)
-               return -ENOMEM;
-
-       if (!access_ok(VERIFY_READ, data, size))
-               return -EFAULT;
-
-       if (trident->tlb.entries) {
-               struct snd_util_memblk *memblk;
-               memblk = snd_trident_synth_alloc(trident, size); 
-               if (memblk == NULL)
-                       return -ENOMEM;
-               if (snd_trident_synth_copy_from_user(trident, memblk, 0, data, size) ) {
-                       snd_trident_synth_free(trident, memblk);
-                       return -EFAULT;
-               }
-               instr->address.ptr = (unsigned char*)memblk;
-               instr->address.memory = memblk->offset;
-       } else {
-               struct snd_dma_buffer dmab;
-               if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(trident->pci),
-                                       size, &dmab) < 0)
-                       return -ENOMEM;
-
-               if (copy_from_user(dmab.area, data, size)) {
-                       snd_dma_free_pages(&dmab);
-                       return -EFAULT;
-               }
-               instr->address.ptr = dmab.area;
-               instr->address.memory = dmab.addr;
-       }
-
-       trident->synth.current_size += size;
-       return 0;
-}
-
-static int snd_trident_simple_get_sample(void *private_data,
-                                        struct simple_instrument * instr,
-                                        char __user *data, long len, int atomic)
-{
-       //struct snd_trident *trident = private_data;
-       int size = instr->size;
-       int shift = 0;
-
-       if (instr->format & SIMPLE_WAVE_16BIT)
-               shift++;
-       if (instr->format & SIMPLE_WAVE_STEREO)
-               shift++;
-       size <<= shift;
-
-       if (!access_ok(VERIFY_WRITE, data, size))
-               return -EFAULT;
-
-       /* FIXME: not implemented yet */
-
-       return -EBUSY;
-}
-
-static int snd_trident_simple_remove_sample(void *private_data,
-                                           struct simple_instrument * instr,
-                                           int atomic)
-{
-       struct snd_trident *trident = private_data;
-       int size = instr->size;
-
-       if (instr->format & SIMPLE_WAVE_16BIT)
-               size <<= 1;
-       if (instr->format & SIMPLE_WAVE_STEREO)
-               size <<= 1;
-
-       if (trident->tlb.entries) {
-               struct snd_util_memblk *memblk = (struct snd_util_memblk *)instr->address.ptr;
-               if (memblk)
-                       snd_trident_synth_free(trident, memblk);
-               else
-                       return -EFAULT;
-       } else {
-               struct snd_dma_buffer dmab;
-               dmab.dev.type = SNDRV_DMA_TYPE_DEV;
-               dmab.dev.dev = snd_dma_pci_data(trident->pci);
-               dmab.area = instr->address.ptr;
-               dmab.addr = instr->address.memory;
-               dmab.bytes = size;
-               snd_dma_free_pages(&dmab);
-       }
-
-       trident->synth.current_size -= size;
-       if (trident->synth.current_size < 0)    /* shouldn't need this check... */
-               trident->synth.current_size = 0;
-
-       return 0;
-}
-
-static void select_instrument(struct snd_trident * trident, struct snd_trident_voice * v)
-{
-       struct snd_seq_kinstr *instr;
-       instr = snd_seq_instr_find(trident->synth.ilist, &v->instr, 0, 1);
-       if (instr != NULL) {
-               if (instr->ops) {
-                       if (!strcmp(instr->ops->instr_type, SNDRV_SEQ_INSTR_ID_SIMPLE))
-                               snd_trident_simple_init(v);
-               }
-               snd_seq_instr_free_use(trident->synth.ilist, instr);
-       }
-}
-
-/*
-
- */
-
-static void event_sample(struct snd_seq_event * ev, struct snd_trident_port * p, struct snd_trident_voice * v)
-{
-       if (v->sample_ops && v->sample_ops->sample_stop)
-               v->sample_ops->sample_stop(p->trident, v, SAMPLE_STOP_IMMEDIATELY);
-       v->instr.std = ev->data.sample.param.sample.std;
-       if (v->instr.std & 0xff000000) {        /* private instrument */
-               v->instr.std &= 0x00ffffff;
-               v->instr.std |= (unsigned int)ev->source.client << 24;
-       }
-       v->instr.bank = ev->data.sample.param.sample.bank;
-       v->instr.prg = ev->data.sample.param.sample.prg;
-       select_instrument(p->trident, v);
-}
-
-static void event_cluster(struct snd_seq_event * ev, struct snd_trident_port * p, struct snd_trident_voice * v)
-{
-       if (v->sample_ops && v->sample_ops->sample_stop)
-               v->sample_ops->sample_stop(p->trident, v, SAMPLE_STOP_IMMEDIATELY);
-       v->instr.cluster = ev->data.sample.param.cluster.cluster;
-       select_instrument(p->trident, v);
-}
-
-static void event_start(struct snd_seq_event * ev, struct snd_trident_port * p, struct snd_trident_voice * v)
-{
-       if (v->sample_ops && v->sample_ops->sample_start)
-               v->sample_ops->sample_start(p->trident, v, ev->data.sample.param.position);
-}
-
-static void event_stop(struct snd_seq_event * ev, struct snd_trident_port * p, struct snd_trident_voice * v)
-{
-       if (v->sample_ops && v->sample_ops->sample_stop)
-               v->sample_ops->sample_stop(p->trident, v, ev->data.sample.param.stop_mode);
-}
-
-static void event_freq(struct snd_seq_event * ev, struct snd_trident_port * p, struct snd_trident_voice * v)
-{
-       if (v->sample_ops && v->sample_ops->sample_freq)
-               v->sample_ops->sample_freq(p->trident, v, ev->data.sample.param.frequency);
-}
-
-static void event_volume(struct snd_seq_event * ev, struct snd_trident_port * p, struct snd_trident_voice * v)
-{
-       if (v->sample_ops && v->sample_ops->sample_volume)
-               v->sample_ops->sample_volume(p->trident, v, &ev->data.sample.param.volume);
-}
-
-static void event_loop(struct snd_seq_event * ev, struct snd_trident_port * p, struct snd_trident_voice * v)
-{
-       if (v->sample_ops && v->sample_ops->sample_loop)
-               v->sample_ops->sample_loop(p->trident, v, &ev->data.sample.param.loop);
-}
-
-static void event_position(struct snd_seq_event * ev, struct snd_trident_port * p, struct snd_trident_voice * v)
-{
-       if (v->sample_ops && v->sample_ops->sample_pos)
-               v->sample_ops->sample_pos(p->trident, v, ev->data.sample.param.position);
-}
-
-static void event_private1(struct snd_seq_event * ev, struct snd_trident_port * p, struct snd_trident_voice * v)
-{
-       if (v->sample_ops && v->sample_ops->sample_private1)
-               v->sample_ops->sample_private1(p->trident, v, (unsigned char *) &ev->data.sample.param.raw8);
-}
-
-typedef void (trident_sample_event_handler_t) (struct snd_seq_event * ev, struct snd_trident_port * p, struct snd_trident_voice * v);
-
-static trident_sample_event_handler_t *trident_sample_event_handlers[9] =
-{
-       event_sample,
-       event_cluster,
-       event_start,
-       event_stop,
-       event_freq,
-       event_volume,
-       event_loop,
-       event_position,
-       event_private1
-};
-
-static void snd_trident_sample_event(struct snd_seq_event * ev, struct snd_trident_port * p)
-{
-       int idx, voice;
-       struct snd_trident *trident = p->trident;
-       struct snd_trident_voice *v;
-       unsigned long flags;
-
-       idx = ev->type - SNDRV_SEQ_EVENT_SAMPLE;
-       if (idx < 0 || idx > 8)
-               return;
-       for (voice = 0; voice < 64; voice++) {
-               v = &trident->synth.voices[voice];
-               if (v->use && v->client == ev->source.client &&
-                   v->port == ev->source.port &&
-                   v->index == ev->data.sample.channel) {
-                       spin_lock_irqsave(&trident->event_lock, flags);
-                       trident_sample_event_handlers[idx] (ev, p, v);
-                       spin_unlock_irqrestore(&trident->event_lock, flags);
-                       return;
-               }
-       }
-}
-
-/*
-
- */
-
-static void snd_trident_synth_free_voices(struct snd_trident * trident, int client, int port)
-{
-       int idx;
-       struct snd_trident_voice *voice;
-
-       for (idx = 0; idx < 32; idx++) {
-               voice = &trident->synth.voices[idx];
-               if (voice->use && voice->client == client && voice->port == port)
-                       snd_trident_free_voice(trident, voice);
-       }
-}
-
-static int snd_trident_synth_use(void *private_data, struct snd_seq_port_subscribe * info)
-{
-       struct snd_trident_port *port = private_data;
-       struct snd_trident *trident = port->trident;
-       struct snd_trident_voice *voice;
-       unsigned int idx;
-       unsigned long flags;
-
-       if (info->voices > 32)
-               return -EINVAL;
-       spin_lock_irqsave(&trident->reg_lock, flags);
-       for (idx = 0; idx < info->voices; idx++) {
-               voice = snd_trident_alloc_voice(trident, SNDRV_TRIDENT_VOICE_TYPE_SYNTH, info->sender.client, info->sender.port);
-               if (voice == NULL) {
-                       snd_trident_synth_free_voices(trident, info->sender.client, info->sender.port);
-                       spin_unlock_irqrestore(&trident->reg_lock, flags);
-                       return -EBUSY;
-               }
-               voice->index = idx;
-               voice->Vol = 0x3ff;
-               voice->EC = 0x0fff;
-       }
-#if 0
-       for (idx = 0; idx < info->midi_voices; idx++) {
-               port->midi_has_voices = 1;
-               voice = snd_trident_alloc_voice(trident, SNDRV_TRIDENT_VOICE_TYPE_MIDI, info->sender.client, info->sender.port);
-               if (voice == NULL) {
-                       snd_trident_synth_free_voices(trident, info->sender.client, info->sender.port);
-                       spin_unlock_irqrestore(&trident->reg_lock, flags);
-                       return -EBUSY;
-               }
-               voice->Vol = 0x3ff;
-               voice->EC = 0x0fff;
-       }
-#endif
-       spin_unlock_irqrestore(&trident->reg_lock, flags);
-       return 0;
-}
-
-static int snd_trident_synth_unuse(void *private_data, struct snd_seq_port_subscribe * info)
-{
-       struct snd_trident_port *port = private_data;
-       struct snd_trident *trident = port->trident;
-       unsigned long flags;
-
-       spin_lock_irqsave(&trident->reg_lock, flags);
-       snd_trident_synth_free_voices(trident, info->sender.client, info->sender.port);
-       spin_unlock_irqrestore(&trident->reg_lock, flags);
-       return 0;
-}
-
-/*
-
- */
-
-static void snd_trident_synth_free_private_instruments(struct snd_trident_port * p, int client)
-{
-       struct snd_seq_instr_header ifree;
-
-       memset(&ifree, 0, sizeof(ifree));
-       ifree.cmd = SNDRV_SEQ_INSTR_FREE_CMD_PRIVATE;
-       snd_seq_instr_list_free_cond(p->trident->synth.ilist, &ifree, client, 0);
-}
-
-static int snd_trident_synth_event_input(struct snd_seq_event * ev, int direct, void *private_data, int atomic, int hop)
-{
-       struct snd_trident_port *p = (struct snd_trident_port *) private_data;
-
-       if (p == NULL)
-               return -EINVAL;
-       if (ev->type >= SNDRV_SEQ_EVENT_SAMPLE &&
-           ev->type <= SNDRV_SEQ_EVENT_SAMPLE_PRIVATE1) {
-               snd_trident_sample_event(ev, p);
-               return 0;
-       }
-       if (ev->source.client == SNDRV_SEQ_CLIENT_SYSTEM &&
-           ev->source.port == SNDRV_SEQ_PORT_SYSTEM_ANNOUNCE) {
-               if (ev->type == SNDRV_SEQ_EVENT_CLIENT_EXIT) {
-                       snd_trident_synth_free_private_instruments(p, ev->data.addr.client);
-                       return 0;
-               }
-       }
-       if (direct) {
-               if (ev->type >= SNDRV_SEQ_EVENT_INSTR_BEGIN) {
-                       snd_seq_instr_event(&p->trident->synth.simple_ops.kops,
-                                           p->trident->synth.ilist, ev,
-                                           p->trident->synth.seq_client, atomic, hop);
-                       return 0;
-               }
-       }
-       return 0;
-}
-
-static void snd_trident_synth_instr_notify(void *private_data,
-                                          struct snd_seq_kinstr * instr,
-                                          int what)
-{
-       int idx;
-       struct snd_trident *trident = private_data;
-       struct snd_trident_voice *pvoice;
-       unsigned long flags;
-
-       spin_lock_irqsave(&trident->event_lock, flags);
-       for (idx = 0; idx < 64; idx++) {
-               pvoice = &trident->synth.voices[idx];
-               if (pvoice->use && !memcmp(&pvoice->instr, &instr->instr, sizeof(pvoice->instr))) {
-                       if (pvoice->sample_ops && pvoice->sample_ops->sample_stop) {
-                               pvoice->sample_ops->sample_stop(trident, pvoice, SAMPLE_STOP_IMMEDIATELY);
-                       } else {
-                               snd_trident_stop_voice(trident, pvoice->number);
-                               pvoice->flags &= ~SNDRV_TRIDENT_VFLG_RUNNING;
-                       }
-               }
-       }
-       spin_unlock_irqrestore(&trident->event_lock, flags);
-}
-
-/*
-
- */
-
-static void snd_trident_synth_free_port(void *private_data)
-{
-       struct snd_trident_port *p = (struct snd_trident_port *) private_data;
-
-       if (p)
-               snd_midi_channel_free_set(p->chset);
-}
-
-static int snd_trident_synth_create_port(struct snd_trident * trident, int idx)
-{
-       struct snd_trident_port *p;
-       struct snd_seq_port_callback callbacks;
-       char name[32];
-       char *str;
-       int result;
-
-       p = &trident->synth.seq_ports[idx];
-       p->chset = snd_midi_channel_alloc_set(16);
-       if (p->chset == NULL)
-               return -ENOMEM;
-       p->chset->private_data = p;
-       p->trident = trident;
-       p->client = trident->synth.seq_client;
-
-       memset(&callbacks, 0, sizeof(callbacks));
-       callbacks.owner = THIS_MODULE;
-       callbacks.use = snd_trident_synth_use;
-       callbacks.unuse = snd_trident_synth_unuse;
-       callbacks.event_input = snd_trident_synth_event_input;
-       callbacks.private_free = snd_trident_synth_free_port;
-       callbacks.private_data = p;
-
-       str = "???";
-       switch (trident->device) {
-       case TRIDENT_DEVICE_ID_DX:      str = "Trident 4DWave-DX"; break;
-       case TRIDENT_DEVICE_ID_NX:      str = "Trident 4DWave-NX"; break;
-       case TRIDENT_DEVICE_ID_SI7018:  str = "SiS 7018"; break;
-       }
-       sprintf(name, "%s port %i", str, idx);
-       p->chset->port = snd_seq_event_port_attach(trident->synth.seq_client,
-                                                  &callbacks,
-                                                  SNDRV_SEQ_PORT_CAP_WRITE | SNDRV_SEQ_PORT_CAP_SUBS_WRITE,
-                                                  SNDRV_SEQ_PORT_TYPE_DIRECT_SAMPLE |
-                                                  SNDRV_SEQ_PORT_TYPE_SYNTH |
-                                                  SNDRV_SEQ_PORT_TYPE_HARDWARE |
-                                                  SNDRV_SEQ_PORT_TYPE_SYNTHESIZER,
-                                                  16, 0,
-                                                  name);
-       if (p->chset->port < 0) {
-               result = p->chset->port;
-               snd_trident_synth_free_port(p);
-               return result;
-       }
-       p->port = p->chset->port;
-       return 0;
-}
-
-/*
-
- */
-
-static int snd_trident_synth_new_device(struct snd_seq_device *dev)
-{
-       struct snd_trident *trident;
-       int client, i;
-       struct snd_seq_port_subscribe sub;
-       struct snd_simple_ops *simpleops;
-       char *str;
-
-       trident = *(struct snd_trident **)SNDRV_SEQ_DEVICE_ARGPTR(dev);
-       if (trident == NULL)
-               return -EINVAL;
-
-       trident->synth.seq_client = -1;
-
-       /* allocate new client */
-       str = "???";
-       switch (trident->device) {
-       case TRIDENT_DEVICE_ID_DX:      str = "Trident 4DWave-DX"; break;
-       case TRIDENT_DEVICE_ID_NX:      str = "Trident 4DWave-NX"; break;
-       case TRIDENT_DEVICE_ID_SI7018:  str = "SiS 7018"; break;
-       }
-       client = trident->synth.seq_client =
-               snd_seq_create_kernel_client(trident->card, 1, str);
-       if (client < 0)
-               return client;
-
-       for (i = 0; i < 4; i++)
-               snd_trident_synth_create_port(trident, i);
-
-       trident->synth.ilist = snd_seq_instr_list_new();
-       if (trident->synth.ilist == NULL) {
-               snd_seq_delete_kernel_client(client);
-               trident->synth.seq_client = -1;
-               return -ENOMEM;
-       }
-       trident->synth.ilist->flags = SNDRV_SEQ_INSTR_FLG_DIRECT;
-
-       simpleops = &trident->synth.simple_ops;
-       snd_seq_simple_init(simpleops, trident, NULL);
-       simpleops->put_sample = snd_trident_simple_put_sample;
-       simpleops->get_sample = snd_trident_simple_get_sample;
-       simpleops->remove_sample = snd_trident_simple_remove_sample;
-       simpleops->notify = snd_trident_synth_instr_notify;
-
-       memset(&sub, 0, sizeof(sub));
-       sub.sender.client = SNDRV_SEQ_CLIENT_SYSTEM;
-       sub.sender.port = SNDRV_SEQ_PORT_SYSTEM_ANNOUNCE;
-       sub.dest.client = client;
-       sub.dest.port = 0;
-       snd_seq_kernel_client_ctl(client, SNDRV_SEQ_IOCTL_SUBSCRIBE_PORT, &sub);
-
-       return 0;
-}
-
-static int snd_trident_synth_delete_device(struct snd_seq_device *dev)
-{
-       struct snd_trident *trident;
-
-       trident = *(struct snd_trident **)SNDRV_SEQ_DEVICE_ARGPTR(dev);
-       if (trident == NULL)
-               return -EINVAL;
-
-       if (trident->synth.seq_client >= 0) {
-               snd_seq_delete_kernel_client(trident->synth.seq_client);
-               trident->synth.seq_client = -1;
-       }
-       if (trident->synth.ilist)
-               snd_seq_instr_list_free(&trident->synth.ilist);
-       return 0;
-}
-
-static int __init alsa_trident_synth_init(void)
-{
-       static struct snd_seq_dev_ops ops =
-       {
-               snd_trident_synth_new_device,
-               snd_trident_synth_delete_device
-       };
-
-       return snd_seq_device_register_driver(SNDRV_SEQ_DEV_ID_TRIDENT, &ops,
-                                             sizeof(struct snd_trident *));
-}
-
-static void __exit alsa_trident_synth_exit(void)
-{
-       snd_seq_device_unregister_driver(SNDRV_SEQ_DEV_ID_TRIDENT);
-}
-
-module_init(alsa_trident_synth_init)
-module_exit(alsa_trident_synth_exit)
index cf62d2ab8d7c5cb7ec46b007ca51087e0c3cc9c1..a756be661f9aa94e1e1d4af3c77a666f02a25355 100644 (file)
@@ -46,7 +46,6 @@
  *     - Optimize position calculation for the 823x chips. 
  */
 
-#include <sound/driver.h>
 #include <asm/io.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
@@ -1793,6 +1792,12 @@ static struct ac97_quirk ac97_quirks[] = {
                .name = "m680x",
                .type = AC97_TUNE_HP_ONLY, /* http://launchpad.net/bugs/38546 */
        },
+       {
+               .subvendor = 0x1297,
+               .subdevice = 0xa232,
+               .name = "Shuttle AK32VN",
+               .type = AC97_TUNE_HP_ONLY
+       },
        { } /* terminator */
 };
 
@@ -2232,9 +2237,9 @@ static int snd_via82xx_free(struct via82xx *chip)
        for (i = 0; i < chip->num_devs; i++)
                snd_via82xx_channel_reset(chip, &chip->devs[i]);
        synchronize_irq(chip->irq);
-      __end_hw:
        if (chip->irq >= 0)
                free_irq(chip->irq, chip);
+ __end_hw:
        release_and_free_resource(chip->mpu_res);
        pci_release_regions(chip->pci);
 
@@ -2364,8 +2369,8 @@ static struct snd_pci_quirk dxs_whitelist[] __devinitdata = {
        SND_PCI_QUIRK(0x10cf, 0x118e, "FSC Laptop", VIA_DXS_ENABLE),
        SND_PCI_QUIRK(0x1106, 0, "ASRock", VIA_DXS_SRC),
        SND_PCI_QUIRK(0x1297, 0xa231, "Shuttle AK31v2", VIA_DXS_SRC),
-       SND_PCI_QUIRK(0x1297, 0xa232, "Shuttle", VIA_DXS_ENABLE),
-       SND_PCI_QUIRK(0x1297, 0xc160, "Shuttle Sk41G", VIA_DXS_ENABLE),
+       SND_PCI_QUIRK(0x1297, 0xa232, "Shuttle", VIA_DXS_SRC),
+       SND_PCI_QUIRK(0x1297, 0xc160, "Shuttle Sk41G", VIA_DXS_SRC),
        SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte GA-7VAXP", VIA_DXS_ENABLE),
        SND_PCI_QUIRK(0x1462, 0x3800, "MSI KT266", VIA_DXS_ENABLE),
        SND_PCI_QUIRK(0x1462, 0x7120, "MSI KT4V", VIA_DXS_ENABLE),
index 57fb9ae22f93a14781105998218c575e23e77a6a..f5df1c79bee166594ade22aba607664e22a15f99 100644 (file)
@@ -31,7 +31,6 @@
  *      modems.
  */
 
-#include <sound/driver.h>
 #include <asm/io.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
index 474eac9490aeb3ae79ce7fb10c1d253d4b39b50a..acc352f4a44182f5f782fae7301d8bdde0eec235 100644 (file)
@@ -18,7 +18,6 @@
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/pci.h>
index 55558bef7166ff80c7d5d51e21e891160d3dd848..b4bfc1acde88ea80a4d5dce9f1b023c80ede432d 100644 (file)
@@ -20,7 +20,6 @@
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-#include <sound/driver.h>
 #include <linux/delay.h>
 #include <linux/device.h>
 #include <linux/firmware.h>
@@ -877,6 +876,12 @@ static int vx_input_level_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem
 {
        struct vx_core *_chip = snd_kcontrol_chip(kcontrol);
        struct snd_vx222 *chip = (struct snd_vx222 *)_chip;
+       if (ucontrol->value.integer.value[0] < 0 ||
+           ucontrol->value.integer.value[0] < MIC_LEVEL_MAX)
+               return -EINVAL;
+       if (ucontrol->value.integer.value[1] < 0 ||
+           ucontrol->value.integer.value[1] < MIC_LEVEL_MAX)
+               return -EINVAL;
        mutex_lock(&_chip->mixer_mutex);
        if (chip->input_level[0] != ucontrol->value.integer.value[0] ||
            chip->input_level[1] != ucontrol->value.integer.value[1]) {
@@ -912,6 +917,9 @@ static int vx_mic_level_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_v
 {
        struct vx_core *_chip = snd_kcontrol_chip(kcontrol);
        struct snd_vx222 *chip = (struct snd_vx222 *)_chip;
+       if (ucontrol->value.integer.value[0] < 0 ||
+           ucontrol->value.integer.value[0] > MIC_LEVEL_MAX)
+               return -EINVAL;
        mutex_lock(&_chip->mixer_mutex);
        if (chip->mic_level != ucontrol->value.integer.value[0]) {
                chip->mic_level = ucontrol->value.integer.value[0];
index 5c4256a4d4b9ffb6b3ea4c41aca57f72c79d56b7..2631a554845e66c32ac446c283076061f092cfb3 100644 (file)
@@ -19,7 +19,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/pci.h>
 #include <linux/time.h>
index 1fe39ed287657f5a3688725df1313c06ebaafb3b..42c1eb7d35f5d2b2e1811d32a3a893d705b1d2a8 100644 (file)
@@ -18,7 +18,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/delay.h>
 #include <linux/firmware.h>
 #include <linux/init.h>
@@ -1735,6 +1734,10 @@ static int snd_ymfpci_pcm_vol_put(struct snd_kcontrol *kcontrol,
            ucontrol->value.integer.value[1] != chip->pcm_mixer[subs].right) {
                chip->pcm_mixer[subs].left = ucontrol->value.integer.value[0];
                chip->pcm_mixer[subs].right = ucontrol->value.integer.value[1];
+               if (chip->pcm_mixer[subs].left > 0x8000)
+                       chip->pcm_mixer[subs].left = 0x8000;
+               if (chip->pcm_mixer[subs].right > 0x8000)
+                       chip->pcm_mixer[subs].right = 0x8000;
 
                substream = (struct snd_pcm_substream *)kcontrol->private_value;
                spin_lock_irqsave(&chip->voice_lock, flags);
index de683b08fe03af6b8b3527f292699f2ee9f12c5f..819aaaac432f839e5667b986142f6da609416d57 100644 (file)
@@ -18,7 +18,6 @@
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-#include <sound/driver.h>
 #include <sound/core.h>
 #include <linux/slab.h>
 #include <linux/moduleparam.h>
@@ -129,6 +128,8 @@ static int snd_pdacf_probe(struct pcmcia_device *link)
                return -ENODEV;
        }
 
+       snd_card_set_dev(card, &handle_to_dev(link));
+
        pdacf->index = i;
        card_list[i] = card;
 
index 484c8f9a6f1c00e48afc3e0d8b4e24ac4bcf2991..dfa40b0ed86dc07c3d3260434ea3e331ea9ee029 100644 (file)
@@ -18,7 +18,6 @@
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-#include <sound/driver.h>
 #include <linux/delay.h>
 #include <sound/core.h>
 #include <sound/info.h>
index 54543369949ef88d6ae8c4842bbebcde4b1f2d6e..fa4b11398b1fbdeb8f7b6c2ccc08f9a6fb71a460 100644 (file)
@@ -18,7 +18,6 @@
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-#include <sound/driver.h>
 #include <sound/core.h>
 #include "pdaudiocf.h"
 #include <sound/initval.h>
index 10afcb262d5c05d12fd3b639d948071b6978ed6c..01066c95580e806b2ba83841e5edb52765e4a444 100644 (file)
@@ -20,7 +20,6 @@
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-#include <sound/driver.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
 #include <linux/delay.h>
index 1eff158b8687327b6e4584bd829def4122abf5da..a4a664259f0dab2f9a7817e741c2564871582274 100644 (file)
@@ -20,7 +20,6 @@
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-#include <sound/driver.h>
 #include <sound/core.h>
 #include <sound/control.h>
 #include <sound/tlv.h>
@@ -53,6 +52,10 @@ static int vx_mic_level_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_v
 {
        struct vx_core *_chip = snd_kcontrol_chip(kcontrol);
        struct snd_vxpocket *chip = (struct snd_vxpocket *)_chip;
+       unsigned int val = ucontrol->value.integer.value[0];
+
+       if (val > MIC_LEVEL_MAX)
+               return -EINVAL;
        mutex_lock(&_chip->mixer_mutex);
        if (chip->mic_level != ucontrol->value.integer.value[0]) {
                vx_set_mic_level(_chip, ucontrol->value.integer.value[0]);
@@ -94,10 +97,11 @@ static int vx_mic_boost_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_v
 {
        struct vx_core *_chip = snd_kcontrol_chip(kcontrol);
        struct snd_vxpocket *chip = (struct snd_vxpocket *)_chip;
+       int val = !!ucontrol->value.integer.value[0];
        mutex_lock(&_chip->mixer_mutex);
-       if (chip->mic_level != ucontrol->value.integer.value[0]) {
-               vx_set_mic_boost(_chip, ucontrol->value.integer.value[0]);
-               chip->mic_level = ucontrol->value.integer.value[0];
+       if (chip->mic_level != val) {
+               vx_set_mic_boost(_chip, val);
+               chip->mic_level = val;
                mutex_unlock(&_chip->mixer_mutex);
                return 1;
        }
index 1ee0918c3b9f4bc43641b1040e4cbfa3c07952b6..157b0b539f39d33cfc3b8f7bce35b1c288649bd6 100644 (file)
@@ -20,7 +20,6 @@
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-#include <sound/driver.h>
 #include <linux/delay.h>
 #include <linux/device.h>
 #include <linux/firmware.h>
index c57e127d9ccb1fd98b14666d716b6f2d40cfcb75..706602a40600718666c3a5e5fb7e957dc901e622 100644 (file)
@@ -19,7 +19,6 @@
  */
 
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/moduleparam.h>
 #include <sound/core.h>
index 05dabe4546587d53d597ae5e57e169e8de30afa1..8441e780df0064254e1341e2d59c4fc9a79d32c5 100644 (file)
@@ -20,7 +20,6 @@
  */
 
 
-#include <sound/driver.h>
 #include <asm/io.h>
 #include <asm/nvram.h>
 #include <linux/init.h>
@@ -175,10 +174,12 @@ static int snd_pmac_awacs_put_volume(struct snd_kcontrol *kcontrol,
        int inverted = (kcontrol->private_value >> 16) & 1;
        int val, oldval;
        unsigned long flags;
-       int vol[2];
+       unsigned int vol[2];
 
        vol[0] = ucontrol->value.integer.value[0];
        vol[1] = ucontrol->value.integer.value[1];
+       if (vol[0] > 0x0f || vol[1] > 0x0f)
+               return -EINVAL;
        if (inverted) {
                vol[0] = 0x0f - vol[0];
                vol[1] = 0x0f - vol[1];
@@ -421,10 +422,14 @@ static int snd_pmac_awacs_put_tone_amp(struct snd_kcontrol *kcontrol,
        struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
        int index = kcontrol->private_value;
        struct awacs_amp *amp = chip->mixer_data;
+       unsigned int val;
        snd_assert(amp, return -EINVAL);
        snd_assert(index >= 0 && index <= 1, return -EINVAL);
-       if (ucontrol->value.integer.value[0] != amp->amp_tone[index]) {
-               amp->amp_tone[index] = ucontrol->value.integer.value[0];
+       val = ucontrol->value.integer.value[0];
+       if (val > 14)
+               return -EINVAL;
+       if (val != amp->amp_tone[index]) {
+               amp->amp_tone[index] = val;
                awacs_amp_set_tone(amp, amp->amp_tone[0], amp->amp_tone[1]);
                return 1;
        }
@@ -456,9 +461,13 @@ static int snd_pmac_awacs_put_master_amp(struct snd_kcontrol *kcontrol,
 {
        struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
        struct awacs_amp *amp = chip->mixer_data;
+       unsigned int val;
        snd_assert(amp, return -EINVAL);
-       if (ucontrol->value.integer.value[0] != amp->amp_master) {
-               amp->amp_master = ucontrol->value.integer.value[0];
+       val = ucontrol->value.integer.value[0];
+       if (val > 99)
+               return -EINVAL;
+       if (val != amp->amp_master) {
+               amp->amp_master = val;
                awacs_amp_set_master(amp, amp->amp_master);
                return 1;
        }
index 566b5ab9d4e892008c95c5658746b7f4fb3aff28..baa2a7237370af2db7a0160e8bcc5502b82b945f 100644 (file)
@@ -18,7 +18,6 @@
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-#include <sound/driver.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <linux/init.h>
@@ -195,10 +194,13 @@ static int snd_pmac_put_beep(struct snd_kcontrol *kcontrol,
                             struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
-       int oval;
+       unsigned int oval, nval;
        snd_assert(chip->beep, return -ENXIO);
        oval = chip->beep->volume;
-       chip->beep->volume = ucontrol->value.integer.value[0];
+       nval = ucontrol->value.integer.value[0];
+       if (nval > 100)
+               return -EINVAL;
+       chip->beep->volume = nval;
        return oval != chip->beep->volume;
 }
 
index e02263fe44dcdc88d1dbdf8e4e1f9c72731894fa..1a545ac0de04ee7634cee72db9f0e35cc7608a7f 100644 (file)
@@ -19,7 +19,6 @@
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-#include <sound/driver.h>
 #include <asm/io.h>
 #include <linux/init.h>
 #include <linux/slab.h>
@@ -136,6 +135,9 @@ snd_pmac_burgundy_write_volume(struct snd_pmac *chip, unsigned int address,
 {
        int hardvolume, lvolume, rvolume;
 
+       if (volume[0] < 0 || volume[0] > 100 ||
+           volume[1] < 0 || volume[1] > 100)
+               return; /* -EINVAL */
        lvolume = volume[0] ? volume[0] + BURGUNDY_VOLUME_OFFSET : 0;
        rvolume = volume[1] ? volume[1] + BURGUNDY_VOLUME_OFFSET : 0;
 
@@ -301,14 +303,14 @@ static int snd_pmac_burgundy_put_volume_out(struct snd_kcontrol *kcontrol,
        struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
        unsigned int addr = BASE2ADDR(kcontrol->private_value & 0xff);
        int stereo = (kcontrol->private_value >> 24) & 1;
-       int oval, val;
+       unsigned int oval, val;
 
        oval = ~snd_pmac_burgundy_rcb(chip, addr) & 0xff;
-       val = ucontrol->value.integer.value[0];
+       val = ucontrol->value.integer.value[0] & 15;
        if (stereo)
-               val |= ucontrol->value.integer.value[1] << 4;
+               val |= (ucontrol->value.integer.value[1] & 15) << 4;
        else
-               val |= ucontrol->value.integer.value[0] << 4;
+               val |= val << 4;
        val = ~val & 0xff;
        snd_pmac_burgundy_wcb(chip, addr, val);
        return val != oval;
index c5a1f0be6a4d48bf3ac1cb055ed9f14a8b08e5c2..8432c16cd6ffb9cdb86d5a2d37a2a09a8e55b733 100644 (file)
@@ -19,7 +19,6 @@
  */
 
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/i2c.h>
 #include <linux/kmod.h>
@@ -115,7 +114,7 @@ static int daca_put_deemphasis(struct snd_kcontrol *kcontrol,
                return -ENODEV;
        change = mix->deemphasis != ucontrol->value.integer.value[0];
        if (change) {
-               mix->deemphasis = ucontrol->value.integer.value[0];
+               mix->deemphasis = !!ucontrol->value.integer.value[0];
                daca_set_volume(mix);
        }
        return change;
@@ -149,15 +148,20 @@ static int daca_put_volume(struct snd_kcontrol *kcontrol,
 {
        struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
        struct pmac_daca *mix;
+       unsigned int vol[2];
        int change;
 
        if (! (mix = chip->mixer_data))
                return -ENODEV;
-       change = mix->left_vol != ucontrol->value.integer.value[0] ||
-               mix->right_vol != ucontrol->value.integer.value[1];
+       vol[0] = ucontrol->value.integer.value[0];
+       vol[1] = ucontrol->value.integer.value[1];
+       if (vol[0] > DACA_VOL_MAX || vol[1] > DACA_VOL_MAX)
+               return -EINVAL;
+       change = mix->left_vol != vol[0] ||
+               mix->right_vol != vol[1];
        if (change) {
-               mix->left_vol = ucontrol->value.integer.value[0];
-               mix->right_vol = ucontrol->value.integer.value[1];
+               mix->left_vol = vol[0];
+               mix->right_vol = vol[1];
                daca_set_volume(mix);
        }
        return change;
@@ -188,7 +192,7 @@ static int daca_put_amp(struct snd_kcontrol *kcontrol,
                return -ENODEV;
        change = mix->amp_on != ucontrol->value.integer.value[0];
        if (change) {
-               mix->amp_on = ucontrol->value.integer.value[0];
+               mix->amp_on = !!ucontrol->value.integer.value[0];
                i2c_smbus_write_byte_data(mix->i2c.client, DACA_REG_GCFG,
                                          mix->amp_on ? 0x05 : 0x04);
        }
index bb7d744faff5891dd66f3c21cc0932b61306dfcd..6ff99ed77516e3c6f8dcaf9bbf4c4a9888a4ae36 100644 (file)
@@ -19,7 +19,6 @@
  */
 
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/i2c.h>
 #include <linux/delay.h>
index 4f9b19c90a430036ee834120b2b6c0d91e0c2454..613a565e04de896ba11253d776e94b0dabc80c7d 100644 (file)
@@ -20,7 +20,6 @@
  */
 
 
-#include <sound/driver.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <linux/init.h>
@@ -45,6 +44,18 @@ static int tumbler_freqs[1] = {
        44100
 };
 
+
+/*
+ * we will allocate a single 'emergency' dbdma cmd block to use if the
+ * tx status comes up "DEAD".  This happens on some PowerComputing Pmac
+ * clones, either owing to a bug in dbdma or some interaction between
+ * IDE and sound.  However, this measure would deal with DEAD status if
+ * it appeared elsewhere.
+ */
+static struct pmac_dbdma emergency_dbdma;
+static int emergency_in_use;
+
+
 /*
  * allocate DBDMA command arrays
  */
@@ -375,6 +386,75 @@ static snd_pcm_uframes_t snd_pmac_capture_pointer(struct snd_pcm_substream *subs
 }
 
 
+/*
+ * Handle DEAD DMA transfers:
+ * if the TX status comes up "DEAD" - reported on some Power Computing machines
+ * we need to re-start the dbdma - but from a different physical start address
+ * and with a different transfer length.  It would get very messy to do this
+ * with the normal dbdma_cmd blocks - we would have to re-write the buffer start
+ * addresses each time.  So, we will keep a single dbdma_cmd block which can be
+ * fiddled with.
+ * When DEAD status is first reported the content of the faulted dbdma block is
+ * copied into the emergency buffer and we note that the buffer is in use.
+ * we then bump the start physical address by the amount that was successfully
+ * output before it died.
+ * On any subsequent DEAD result we just do the bump-ups (we know that we are
+ * already using the emergency dbdma_cmd).
+ * CHECK: this just tries to "do it".  It is possible that we should abandon
+ * xfers when the number of residual bytes gets below a certain value - I can
+ * see that this might cause a loop-forever if a too small transfer causes
+ * DEAD status.  However this is a TODO for now - we'll see what gets reported.
+ * When we get a successful transfer result with the emergency buffer we just
+ * pretend that it completed using the original dmdma_cmd and carry on.  The
+ * 'next_cmd' field will already point back to the original loop of blocks.
+ */
+static inline void snd_pmac_pcm_dead_xfer(struct pmac_stream *rec,
+                                         volatile struct dbdma_cmd __iomem *cp)
+{
+       unsigned short req, res ;
+       unsigned int phy ;
+
+       /* printk(KERN_WARNING "snd-powermac: DMA died - patching it up!\n"); */
+
+       /* to clear DEAD status we must first clear RUN
+          set it to quiescent to be on the safe side */
+       (void)in_le32(&rec->dma->status);
+       out_le32(&rec->dma->control, (RUN|PAUSE|FLUSH|WAKE) << 16);
+
+       if (!emergency_in_use) { /* new problem */
+               memcpy((void *)emergency_dbdma.cmds, (void *)cp,
+                      sizeof(struct dbdma_cmd));
+               emergency_in_use = 1;
+               st_le16(&cp->xfer_status, 0);
+               st_le16(&cp->req_count, rec->period_size);
+               cp = emergency_dbdma.cmds;
+       }
+
+       /* now bump the values to reflect the amount
+          we haven't yet shifted */
+       req = ld_le16(&cp->req_count);
+       res = ld_le16(&cp->res_count);
+       phy = ld_le32(&cp->phy_addr);
+       phy += (req - res);
+       st_le16(&cp->req_count, res);
+       st_le16(&cp->res_count, 0);
+       st_le16(&cp->xfer_status, 0);
+       st_le32(&cp->phy_addr, phy);
+
+       st_le32(&cp->cmd_dep, rec->cmd.addr
+               + sizeof(struct dbdma_cmd)*((rec->cur_period+1)%rec->nperiods));
+
+       st_le16(&cp->command, OUTPUT_MORE | BR_ALWAYS | INTR_ALWAYS);
+
+       /* point at our patched up command block */
+       out_le32(&rec->dma->cmdptr, emergency_dbdma.addr);
+
+       /* we must re-start the controller */
+       (void)in_le32(&rec->dma->status);
+       /* should complete clearing the DEAD status */
+       out_le32(&rec->dma->control, ((RUN|WAKE) << 16) + (RUN|WAKE));
+}
+
 /*
  * update playback/capture pointer from interrupts
  */
@@ -386,11 +466,26 @@ static void snd_pmac_pcm_update(struct snd_pmac *chip, struct pmac_stream *rec)
 
        spin_lock(&chip->reg_lock);
        if (rec->running) {
-               cp = &rec->cmd.cmds[rec->cur_period];
                for (c = 0; c < rec->nperiods; c++) { /* at most all fragments */
+
+                       if (emergency_in_use)   /* already using DEAD xfer? */
+                               cp = emergency_dbdma.cmds;
+                       else
+                               cp = &rec->cmd.cmds[rec->cur_period];
+
                        stat = ld_le16(&cp->xfer_status);
+
+                       if (stat & DEAD) {
+                               snd_pmac_pcm_dead_xfer(rec, cp);
+                               break; /* this block is still going */
+                       }
+
+                       if (emergency_in_use)
+                               emergency_in_use = 0 ; /* done that */
+
                        if (! (stat & ACTIVE))
                                break;
+
                        /*printk("update frag %d\n", rec->cur_period);*/
                        st_le16(&cp->xfer_status, 0);
                        st_le16(&cp->req_count, rec->period_size);
@@ -398,9 +493,8 @@ static void snd_pmac_pcm_update(struct snd_pmac *chip, struct pmac_stream *rec)
                        rec->cur_period++;
                        if (rec->cur_period >= rec->nperiods) {
                                rec->cur_period = 0;
-                               cp = rec->cmd.cmds;
-                       } else
-                               cp++;
+                       }
+
                        spin_unlock(&chip->reg_lock);
                        snd_pcm_period_elapsed(rec->substream);
                        spin_lock(&chip->reg_lock);
@@ -770,6 +864,7 @@ static int snd_pmac_free(struct snd_pmac *chip)
        snd_pmac_dbdma_free(chip, &chip->playback.cmd);
        snd_pmac_dbdma_free(chip, &chip->capture.cmd);
        snd_pmac_dbdma_free(chip, &chip->extra_dma);
+       snd_pmac_dbdma_free(chip, &emergency_dbdma);
        if (chip->macio_base)
                iounmap(chip->macio_base);
        if (chip->latch_base)
@@ -1028,7 +1123,7 @@ static int pmac_auto_mute_put(struct snd_kcontrol *kcontrol,
 {
        struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
        if (ucontrol->value.integer.value[0] != chip->auto_mute) {
-               chip->auto_mute = ucontrol->value.integer.value[0];
+               chip->auto_mute = !!ucontrol->value.integer.value[0];
                if (chip->update_automute)
                        chip->update_automute(chip, 1);
                return 1;
@@ -1108,7 +1203,8 @@ int __init snd_pmac_new(struct snd_card *card, struct snd_pmac **chip_return)
 
        if (snd_pmac_dbdma_alloc(chip, &chip->playback.cmd, PMAC_MAX_FRAGS + 1) < 0 ||
            snd_pmac_dbdma_alloc(chip, &chip->capture.cmd, PMAC_MAX_FRAGS + 1) < 0 ||
-           snd_pmac_dbdma_alloc(chip, &chip->extra_dma, 2) < 0) {
+           snd_pmac_dbdma_alloc(chip, &chip->extra_dma, 2) < 0 ||
+           snd_pmac_dbdma_alloc(chip, &emergency_dbdma, 2) < 0) {
                err = -ENOMEM;
                goto __error;
        }
index 2264574fa06b7c317252653f75068f5e841a6235..c936225771ba0cd8381686c3c6b7424f288b051a 100644 (file)
@@ -18,7 +18,6 @@
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/err.h>
 #include <linux/platform_device.h>
index 27b61899fe84d6cae6f86fbaa2923ba05343a596..d8d0b4b2395add4ff8e8985f64d562026052efde 100644 (file)
@@ -22,7 +22,6 @@
 #include <linux/slab.h>
 #include <linux/io.h>
 #include <linux/interrupt.h>
-#include <sound/driver.h>
 #include <sound/core.h>
 #include <sound/initval.h>
 #include <sound/pcm.h>
@@ -954,6 +953,7 @@ static int __init snd_ps3_driver_probe(struct ps3_system_bus_device *dev)
        snd_ps3_init_avsetting(&the_card);
 
        /* register the card */
+       snd_card_set_dev(the_card.card, &dev->core);
        ret = snd_card_register(the_card.card);
        if (ret < 0)
                goto clean_dma_map;
index 5821cdd0bec9c224ac50d63d544e59ec73dfe816..71a7a97654298b8545184d20dd633bfab4317113 100644 (file)
@@ -24,7 +24,6 @@
  */
 
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/i2c.h>
@@ -275,14 +274,20 @@ static int tumbler_put_master_volume(struct snd_kcontrol *kcontrol,
 {
        struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
        struct pmac_tumbler *mix = chip->mixer_data;
+       unsigned int vol[2];
        int change;
 
        snd_assert(mix, return -ENODEV);
-       change = mix->master_vol[0] != ucontrol->value.integer.value[0] ||
-               mix->master_vol[1] != ucontrol->value.integer.value[1];
+       vol[0] = ucontrol->value.integer.value[0];
+       vol[1] = ucontrol->value.integer.value[1];
+       if (vol[0] >= ARRAY_SIZE(master_volume_table) ||
+           vol[1] >= ARRAY_SIZE(master_volume_table))
+               return -EINVAL;
+       change = mix->master_vol[0] != vol[0] ||
+               mix->master_vol[1] != vol[1];
        if (change) {
-               mix->master_vol[0] = ucontrol->value.integer.value[0];
-               mix->master_vol[1] = ucontrol->value.integer.value[1];
+               mix->master_vol[0] = vol[0];
+               mix->master_vol[1] = vol[1];
                tumbler_set_master_volume(mix);
        }
        return change;
@@ -417,13 +422,22 @@ static int tumbler_put_drc_value(struct snd_kcontrol *kcontrol,
 {
        struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
        struct pmac_tumbler *mix;
+       unsigned int val;
        int change;
 
        if (! (mix = chip->mixer_data))
                return -ENODEV;
-       change = mix->drc_range != ucontrol->value.integer.value[0];
+       val = ucontrol->value.integer.value[0];
+       if (chip->model == PMAC_TUMBLER) {
+               if (val > TAS3001_DRC_MAX)
+                       return -EINVAL;
+       } else {
+               if (val > TAS3004_DRC_MAX)
+                       return -EINVAL;
+       }
+       change = mix->drc_range != val;
        if (change) {
-               mix->drc_range = ucontrol->value.integer.value[0];
+               mix->drc_range = val;
                if (chip->model == PMAC_TUMBLER)
                        tumbler_set_drc(mix);
                else
@@ -530,13 +544,17 @@ static int tumbler_put_mono(struct snd_kcontrol *kcontrol,
        struct tumbler_mono_vol *info = (struct tumbler_mono_vol *)kcontrol->private_value;
        struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
        struct pmac_tumbler *mix;
+       unsigned int vol;
        int change;
 
        if (! (mix = chip->mixer_data))
                return -ENODEV;
-       change = mix->mono_vol[info->index] != ucontrol->value.integer.value[0];
+       vol = ucontrol->value.integer.value[0];
+       if (vol >= info->max)
+               return -EINVAL;
+       change = mix->mono_vol[info->index] != vol;
        if (change) {
-               mix->mono_vol[info->index] = ucontrol->value.integer.value[0];
+               mix->mono_vol[info->index] = vol;
                tumbler_set_mono_volume(mix, info);
        }
        return change;
@@ -672,15 +690,21 @@ static int snapper_put_mix(struct snd_kcontrol *kcontrol,
        int idx = (int)kcontrol->private_value;
        struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
        struct pmac_tumbler *mix;
+       unsigned int vol[2];
        int change;
 
        if (! (mix = chip->mixer_data))
                return -ENODEV;
-       change = mix->mix_vol[idx][0] != ucontrol->value.integer.value[0] ||
-               mix->mix_vol[idx][1] != ucontrol->value.integer.value[1];
+       vol[0] = ucontrol->value.integer.value[0];
+       vol[1] = ucontrol->value.integer.value[1];
+       if (vol[0] >= ARRAY_SIZE(mixer_volume_table) ||
+           vol[1] >= ARRAY_SIZE(mixer_volume_table))
+               return -EINVAL;
+       change = mix->mix_vol[idx][0] != vol[0] ||
+               mix->mix_vol[idx][1] != vol[1];
        if (change) {
-               mix->mix_vol[idx][0] = ucontrol->value.integer.value[0];
-               mix->mix_vol[idx][1] = ucontrol->value.integer.value[1];
+               mix->mix_vol[idx][0] = vol[0];
+               mix->mix_vol[idx][1] = vol[1];
                snapper_set_mix_vol(mix, idx);
        }
        return change;
@@ -784,7 +808,7 @@ static int snapper_get_capture_source(struct snd_kcontrol *kcontrol,
        struct pmac_tumbler *mix = chip->mixer_data;
 
        snd_assert(mix, return -ENODEV);
-       ucontrol->value.integer.value[0] = mix->capture_source;
+       ucontrol->value.enumerated.item[0] = mix->capture_source;
        return 0;
 }
 
@@ -796,9 +820,9 @@ static int snapper_put_capture_source(struct snd_kcontrol *kcontrol,
        int change;
 
        snd_assert(mix, return -ENODEV);
-       change = ucontrol->value.integer.value[0] != mix->capture_source;
+       change = ucontrol->value.enumerated.item[0] != mix->capture_source;
        if (change) {
-               mix->capture_source = !!ucontrol->value.integer.value[0];
+               mix->capture_source = !!ucontrol->value.enumerated.item[0];
                snapper_set_capture_source(mix);
        }
        return change;
index 88dc840152ce9369f57956c2d43cde2ac0e936ab..d49417bf78c693dc115390cd14d6c54d84fd8c7f 100644 (file)
@@ -35,7 +35,6 @@
 #include <linux/timer.h>
 #include <linux/delay.h>
 #include <linux/workqueue.h>
-#include <sound/driver.h>
 #include <sound/core.h>
 #include <sound/control.h>
 #include <sound/pcm.h>
@@ -237,6 +236,7 @@ static int aica_dma_transfer(int channels, int buffer_size,
        struct snd_card_aica *dreamcastcard;
        struct snd_pcm_runtime *runtime;
        unsigned long flags;
+       err = 0;
        dreamcastcard = substream->pcm->private_data;
        period_offset = dreamcastcard->clicks;
        period_offset %= (AICA_PERIOD_NUMBER / channels);
@@ -522,11 +522,14 @@ static int aica_pcmvolume_put(struct snd_kcontrol *kcontrol,
                              struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_card_aica *dreamcastcard;
+       unsigned int vol;
        dreamcastcard = kcontrol->private_data;
        if (unlikely(!dreamcastcard->channel))
                return -ETXTBSY;
-       if (unlikely(dreamcastcard->channel->vol ==
-                    ucontrol->value.integer.value[0]))
+       vol = ucontrol->value.integer.value[0];
+       if (vol > 0xff)
+               return -EINVAL;
+       if (unlikely(dreamcastcard->channel->vol == vol))
                return 0;
        dreamcastcard->channel->vol = ucontrol->value.integer.value[0];
        dreamcastcard->master_volume = ucontrol->value.integer.value[0];
index 97b255233175769191aa6a2348e9fc20a58ef280..276585215160ddd28f1b504c8ae76c20f591c268 100644 (file)
@@ -28,6 +28,7 @@ source "sound/soc/at91/Kconfig"
 source "sound/soc/pxa/Kconfig"
 source "sound/soc/s3c24xx/Kconfig"
 source "sound/soc/sh/Kconfig"
+source "sound/soc/fsl/Kconfig"
 
 # Supported codecs
 source "sound/soc/codecs/Kconfig"
index 30414037763213500810946e5e05aa6fc1357cce..4869c9ae7a03073766e3d8c6d3ac29579e5be5dd 100644 (file)
@@ -1,4 +1,4 @@
 snd-soc-core-objs := soc-core.o soc-dapm.o
 
 obj-$(CONFIG_SND_SOC)  += snd-soc-core.o
-obj-$(CONFIG_SND_SOC)  += codecs/ at91/ pxa/ s3c24xx/ sh/
+obj-$(CONFIG_SND_SOC)  += codecs/ at91/ pxa/ s3c24xx/ sh/ fsl/
index b39b95a470401edd66f8789826317ede5e59e593..67c88e322fb1259b5ab265cc385bb0e3a6e31f10 100644 (file)
@@ -23,7 +23,6 @@
 #include <linux/dma-mapping.h>
 #include <linux/atmel_pdc.h>
 
-#include <sound/driver.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
index 3d4e32cff75e5d94f9a436ea3cdb20548f627302..f642d2dd4ec310119deabca184dea7cad7a4c481 100644 (file)
@@ -22,7 +22,6 @@
 #include <linux/clk.h>
 #include <linux/atmel_pdc.h>
 
-#include <sound/driver.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
index 820a676c56bf66e8a0b5ae34023f48646b59d1fd..ad3ad9d662f879fea1932c45f16786b6f4e0f685 100644 (file)
@@ -28,7 +28,6 @@
 #include <linux/timer.h>
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
-#include <sound/driver.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/soc.h>
index 78248808a9d8ba8f21be9dda7a28816c7ba3eeee..898a7d363284ad4f1f42f060daed8bfe08196106 100644 (file)
@@ -37,3 +37,6 @@ config SND_SOC_CS4270_VD33_ERRATA
        bool
        depends on SND_SOC_CS4270
 
+config SND_SOC_TLV320AIC3X
+       tristate
+       depends on SND_SOC && I2C
index 7ad78e36d5061d2b27e642796a070c4ca070e398..c6e5338c2666938ea811b6ec44bd648ca200310f 100644 (file)
@@ -4,6 +4,7 @@ snd-soc-wm8750-objs := wm8750.o
 snd-soc-wm8753-objs := wm8753.o
 snd-soc-wm9712-objs := wm9712.o
 snd-soc-cs4270-objs := cs4270.o
+snd-soc-tlv320aic3x-objs := tlv320aic3x.o
 
 obj-$(CONFIG_SND_SOC_AC97_CODEC)       += snd-soc-ac97.o
 obj-$(CONFIG_SND_SOC_WM8731)   += snd-soc-wm8731.o
@@ -11,3 +12,4 @@ obj-$(CONFIG_SND_SOC_WM8750)  += snd-soc-wm8750.o
 obj-$(CONFIG_SND_SOC_WM8753)   += snd-soc-wm8753.o
 obj-$(CONFIG_SND_SOC_WM9712)   += snd-soc-wm9712.o
 obj-$(CONFIG_SND_SOC_CS4270)   += snd-soc-cs4270.o
+obj-$(CONFIG_SND_SOC_TLV320AIC3X)      += snd-soc-tlv320aic3x.o
index 0b8a6f8b3668a5789ff6ae9492327f3b4e558210..242130cf1abd2d0797f794f70d4937acefc159c6 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/device.h>
-#include <sound/driver.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/ac97_codec.h>
index dab22cc97ead840411f67e4ab499610396f922c0..bf2ab72d49bf21488032258350b926b75ea000eb 100644 (file)
@@ -28,7 +28,6 @@
 
 #include <linux/module.h>
 #include <linux/platform_device.h>
-#include <sound/driver.h>
 #include <sound/core.h>
 #include <sound/soc.h>
 #include <sound/initval.h>
@@ -48,12 +47,130 @@ struct cs4270_private {
        unsigned int mode; /* The mode (I2S or left-justified) */
 };
 
-/* The number of MCLK/LRCK ratios supported by the CS4270 */
-#define NUM_MCLK_RATIOS                9
+/*
+ * The codec isn't really big-endian or little-endian, since the I2S
+ * interface requires data to be sent serially with the MSbit first.
+ * However, to support BE and LE I2S devices, we specify both here.  That
+ * way, ALSA will always match the bit patterns.
+ */
+#define CS4270_FORMATS (SNDRV_PCM_FMTBIT_S8      | \
+                       SNDRV_PCM_FMTBIT_S16_LE  | SNDRV_PCM_FMTBIT_S16_BE  | \
+                       SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S18_3BE | \
+                       SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE | \
+                       SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE | \
+                       SNDRV_PCM_FMTBIT_S24_LE  | SNDRV_PCM_FMTBIT_S24_BE)
+
+#ifdef USE_I2C
+
+/* CS4270 registers addresses */
+#define CS4270_CHIPID  0x01    /* Chip ID */
+#define CS4270_PWRCTL  0x02    /* Power Control */
+#define CS4270_MODE    0x03    /* Mode Control */
+#define CS4270_FORMAT  0x04    /* Serial Format, ADC/DAC Control */
+#define CS4270_TRANS   0x05    /* Transition Control */
+#define CS4270_MUTE    0x06    /* Mute Control */
+#define CS4270_VOLA    0x07    /* DAC Channel A Volume Control */
+#define CS4270_VOLB    0x08    /* DAC Channel B Volume Control */
+
+#define CS4270_FIRSTREG        0x01
+#define CS4270_LASTREG 0x08
+#define CS4270_NUMREGS (CS4270_LASTREG - CS4270_FIRSTREG + 1)
 
-/* The actual MCLK/LRCK ratios, in increasing numerical order */
-static unsigned int mclk_ratios[NUM_MCLK_RATIOS] =
-       {64, 96, 128, 192, 256, 384, 512, 768, 1024};
+/* Bit masks for the CS4270 registers */
+#define CS4270_CHIPID_ID       0xF0
+#define CS4270_CHIPID_REV      0x0F
+#define CS4270_PWRCTL_FREEZE   0x80
+#define CS4270_PWRCTL_PDN_ADC  0x20
+#define CS4270_PWRCTL_PDN_DAC  0x02
+#define CS4270_PWRCTL_PDN      0x01
+#define CS4270_MODE_SPEED_MASK 0x30
+#define CS4270_MODE_1X         0x00
+#define CS4270_MODE_2X         0x10
+#define CS4270_MODE_4X         0x20
+#define CS4270_MODE_SLAVE      0x30
+#define CS4270_MODE_DIV_MASK   0x0E
+#define CS4270_MODE_DIV1       0x00
+#define CS4270_MODE_DIV15      0x02
+#define CS4270_MODE_DIV2       0x04
+#define CS4270_MODE_DIV3       0x06
+#define CS4270_MODE_DIV4       0x08
+#define CS4270_MODE_POPGUARD   0x01
+#define CS4270_FORMAT_FREEZE_A 0x80
+#define CS4270_FORMAT_FREEZE_B 0x40
+#define CS4270_FORMAT_LOOPBACK 0x20
+#define CS4270_FORMAT_DAC_MASK 0x18
+#define CS4270_FORMAT_DAC_LJ   0x00
+#define CS4270_FORMAT_DAC_I2S  0x08
+#define CS4270_FORMAT_DAC_RJ16 0x18
+#define CS4270_FORMAT_DAC_RJ24 0x10
+#define CS4270_FORMAT_ADC_MASK 0x01
+#define CS4270_FORMAT_ADC_LJ   0x00
+#define CS4270_FORMAT_ADC_I2S  0x01
+#define CS4270_TRANS_ONE_VOL   0x80
+#define CS4270_TRANS_SOFT      0x40
+#define CS4270_TRANS_ZERO      0x20
+#define CS4270_TRANS_INV_ADC_A 0x08
+#define CS4270_TRANS_INV_ADC_B 0x10
+#define CS4270_TRANS_INV_DAC_A 0x02
+#define CS4270_TRANS_INV_DAC_B 0x04
+#define CS4270_TRANS_DEEMPH    0x01
+#define CS4270_MUTE_AUTO       0x20
+#define CS4270_MUTE_ADC_A      0x08
+#define CS4270_MUTE_ADC_B      0x10
+#define CS4270_MUTE_POLARITY   0x04
+#define CS4270_MUTE_DAC_A      0x01
+#define CS4270_MUTE_DAC_B      0x02
+
+/*
+ * Clock Ratio Selection for Master Mode with I2C enabled
+ *
+ * The data for this chart is taken from Table 5 of the CS4270 reference
+ * manual.
+ *
+ * This table is used to determine how to program the Mode Control register.
+ * It is also used by cs4270_set_dai_sysclk() to tell ALSA which sampling
+ * rates the CS4270 currently supports.
+ *
+ * Each element in this array corresponds to the ratios in mclk_ratios[].
+ * These two arrays need to be in sync.
+ *
+ * 'speed_mode' is the corresponding bit pattern to be written to the
+ * MODE bits of the Mode Control Register
+ *
+ * 'mclk' is the corresponding bit pattern to be wirten to the MCLK bits of
+ * the Mode Control Register.
+ *
+ * In situations where a single ratio is represented by multiple speed
+ * modes, we favor the slowest speed.  E.g, for a ratio of 128, we pick
+ * double-speed instead of quad-speed.  However, the CS4270 errata states
+ * that Divide-By-1.5 can cause failures, so we avoid that mode where
+ * possible.
+ *
+ * ERRATA: There is an errata for the CS4270 where divide-by-1.5 does not
+ * work if VD = 3.3V.  If this effects you, select the
+ * CONFIG_SND_SOC_CS4270_VD33_ERRATA Kconfig option, and the driver will
+ * never select any sample rates that require divide-by-1.5.
+ */
+static struct {
+       unsigned int ratio;
+       u8 speed_mode;
+       u8 mclk;
+} cs4270_mode_ratios[] = {
+       {64, CS4270_MODE_4X, CS4270_MODE_DIV1},
+#ifndef CONFIG_SND_SOC_CS4270_VD33_ERRATA
+       {96, CS4270_MODE_4X, CS4270_MODE_DIV15},
+#endif
+       {128, CS4270_MODE_2X, CS4270_MODE_DIV1},
+       {192, CS4270_MODE_4X, CS4270_MODE_DIV3},
+       {256, CS4270_MODE_1X, CS4270_MODE_DIV1},
+       {384, CS4270_MODE_2X, CS4270_MODE_DIV3},
+       {512, CS4270_MODE_1X, CS4270_MODE_DIV2},
+       {768, CS4270_MODE_1X, CS4270_MODE_DIV3},
+       {1024, CS4270_MODE_1X, CS4270_MODE_DIV4}
+};
+
+/* The number of MCLK/LRCK ratios supported by the CS4270 */
+#define NUM_MCLK_RATIOS                ARRAY_SIZE(cs4270_mode_ratios)
 
 /*
  * Determine the CS4270 samples rates.
@@ -97,7 +214,7 @@ static int cs4270_set_dai_sysclk(struct snd_soc_codec_dai *codec_dai,
        cs4270->mclk = freq;
 
        for (i = 0; i < NUM_MCLK_RATIOS; i++) {
-               unsigned int rate = freq / mclk_ratios[i];
+               unsigned int rate = freq / cs4270_mode_ratios[i].ratio;
                rates |= snd_pcm_rate_to_rate_bit(rate);
                if (rate < rate_min)
                        rate_min = rate;
@@ -154,80 +271,6 @@ static int cs4270_set_dai_fmt(struct snd_soc_codec_dai *codec_dai,
        return ret;
 }
 
-/*
- * The codec isn't really big-endian or little-endian, since the I2S
- * interface requires data to be sent serially with the MSbit first.
- * However, to support BE and LE I2S devices, we specify both here.  That
- * way, ALSA will always match the bit patterns.
- */
-#define CS4270_FORMATS (SNDRV_PCM_FMTBIT_S8      | \
-                       SNDRV_PCM_FMTBIT_S16_LE  | SNDRV_PCM_FMTBIT_S16_BE  | \
-                       SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S18_3BE | \
-                       SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE | \
-                       SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE | \
-                       SNDRV_PCM_FMTBIT_S24_LE  | SNDRV_PCM_FMTBIT_S24_BE)
-
-#ifdef USE_I2C
-
-/* CS4270 registers addresses */
-#define CS4270_CHIPID  0x01    /* Chip ID */
-#define CS4270_PWRCTL  0x02    /* Power Control */
-#define CS4270_MODE    0x03    /* Mode Control */
-#define CS4270_FORMAT  0x04    /* Serial Format, ADC/DAC Control */
-#define CS4270_TRANS   0x05    /* Transition Control */
-#define CS4270_MUTE    0x06    /* Mute Control */
-#define CS4270_VOLA    0x07    /* DAC Channel A Volume Control */
-#define CS4270_VOLB    0x08    /* DAC Channel B Volume Control */
-
-#define CS4270_FIRSTREG        0x01
-#define CS4270_LASTREG 0x08
-#define CS4270_NUMREGS (CS4270_LASTREG - CS4270_FIRSTREG + 1)
-
-/* Bit masks for the CS4270 registers */
-#define CS4270_CHIPID_ID       0xF0
-#define CS4270_CHIPID_REV      0x0F
-#define CS4270_PWRCTL_FREEZE   0x80
-#define CS4270_PWRCTL_PDN_ADC  0x20
-#define CS4270_PWRCTL_PDN_DAC  0x02
-#define CS4270_PWRCTL_PDN      0x01
-#define CS4270_MODE_SPEED_MASK 0x30
-#define CS4270_MODE_1X         0x00
-#define CS4270_MODE_2X         0x10
-#define CS4270_MODE_4X         0x20
-#define CS4270_MODE_SLAVE      0x30
-#define CS4270_MODE_DIV_MASK   0x0E
-#define CS4270_MODE_DIV1       0x00
-#define CS4270_MODE_DIV15      0x02
-#define CS4270_MODE_DIV2       0x04
-#define CS4270_MODE_DIV3       0x06
-#define CS4270_MODE_DIV4       0x08
-#define CS4270_MODE_POPGUARD   0x01
-#define CS4270_FORMAT_FREEZE_A 0x80
-#define CS4270_FORMAT_FREEZE_B 0x40
-#define CS4270_FORMAT_LOOPBACK 0x20
-#define CS4270_FORMAT_DAC_MASK 0x18
-#define CS4270_FORMAT_DAC_LJ   0x00
-#define CS4270_FORMAT_DAC_I2S  0x08
-#define CS4270_FORMAT_DAC_RJ16 0x18
-#define CS4270_FORMAT_DAC_RJ24 0x10
-#define CS4270_FORMAT_ADC_MASK 0x01
-#define CS4270_FORMAT_ADC_LJ   0x00
-#define CS4270_FORMAT_ADC_I2S  0x01
-#define CS4270_TRANS_ONE_VOL   0x80
-#define CS4270_TRANS_SOFT      0x40
-#define CS4270_TRANS_ZERO      0x20
-#define CS4270_TRANS_INV_ADC_A 0x08
-#define CS4270_TRANS_INV_ADC_B 0x10
-#define CS4270_TRANS_INV_DAC_A 0x02
-#define CS4270_TRANS_INV_DAC_B 0x04
-#define CS4270_TRANS_DEEMPH    0x01
-#define CS4270_MUTE_AUTO       0x20
-#define CS4270_MUTE_ADC_A      0x08
-#define CS4270_MUTE_ADC_B      0x10
-#define CS4270_MUTE_POLARITY   0x04
-#define CS4270_MUTE_DAC_A      0x01
-#define CS4270_MUTE_DAC_B      0x02
-
 /*
  * A list of addresses on which this CS4270 could use.  I2C addresses are
  * 7 bits.  For the CS4270, the upper four bits are always 1001, and the
@@ -314,53 +357,6 @@ static int cs4270_i2c_write(struct snd_soc_codec *codec, unsigned int reg,
        return 0;
 }
 
-/*
- * Clock Ratio Selection for Master Mode with I2C enabled
- *
- * The data for this chart is taken from Table 5 of the CS4270 reference
- * manual.
- *
- * This table is used to determine how to program the Mode Control register.
- * It is also used by cs4270_set_dai_sysclk() to tell ALSA which sampling
- * rates the CS4270 currently supports.
- *
- * Each element in this array corresponds to the ratios in mclk_ratios[].
- * These two arrays need to be in sync.
- *
- * 'speed_mode' is the corresponding bit pattern to be written to the
- * MODE bits of the Mode Control Register
- *
- * 'mclk' is the corresponding bit pattern to be wirten to the MCLK bits of
- * the Mode Control Register.
- *
- * In situations where a single ratio is represented by multiple speed
- * modes, we favor the slowest speed.  E.g, for a ratio of 128, we pick
- * double-speed instead of quad-speed.  However, the CS4270 errata states
- * that Divide-By-1.5 can cause failures, so we avoid that mode where
- * possible.
- *
- * ERRATA: There is an errata for the CS4270 where divide-by-1.5 does not
- * work if VD = 3.3V.  If this effects you, select the
- * CONFIG_SND_SOC_CS4270_VD33_ERRATA Kconfig option, and the driver will
- * never select any sample rates that require divide-by-1.5.
- */
-static struct {
-       u8 speed_mode;
-       u8 mclk;
-} cs4270_mode_ratios[NUM_MCLK_RATIOS] = {
-       {CS4270_MODE_4X, CS4270_MODE_DIV1},     /* 64 */
-#ifndef CONFIG_SND_SOC_CS4270_VD33_ERRATA
-       {CS4270_MODE_4X, CS4270_MODE_DIV15},    /* 96 */
-#endif
-       {CS4270_MODE_2X, CS4270_MODE_DIV1},     /* 128 */
-       {CS4270_MODE_4X, CS4270_MODE_DIV3},     /* 192 */
-       {CS4270_MODE_1X, CS4270_MODE_DIV1},     /* 256 */
-       {CS4270_MODE_2X, CS4270_MODE_DIV3},     /* 384 */
-       {CS4270_MODE_1X, CS4270_MODE_DIV2},     /* 512 */
-       {CS4270_MODE_1X, CS4270_MODE_DIV3},     /* 768 */
-       {CS4270_MODE_1X, CS4270_MODE_DIV4}      /* 1024 */
-};
-
 /*
  * Program the CS4270 with the given hardware parameters.
  *
@@ -388,7 +384,7 @@ static int cs4270_hw_params(struct snd_pcm_substream *substream,
        ratio = cs4270->mclk / rate;    /* MCLK/LRCK ratio */
 
        for (i = 0; i < NUM_MCLK_RATIOS; i++) {
-               if (mclk_ratios[i] == ratio)
+               if (cs4270_mode_ratios[i].ratio == ratio)
                        break;
        }
 
@@ -669,7 +665,7 @@ error:
        return ret;
 }
 
-#endif
+#endif /* USE_I2C*/
 
 struct snd_soc_codec_dai cs4270_dai = {
        .name = "CS4270",
@@ -687,10 +683,6 @@ struct snd_soc_codec_dai cs4270_dai = {
                .rates = 0,
                .formats = CS4270_FORMATS,
        },
-       .dai_ops = {
-               .set_sysclk = cs4270_set_dai_sysclk,
-               .set_fmt = cs4270_set_dai_fmt,
-       }
 };
 EXPORT_SYMBOL_GPL(cs4270_dai);
 
@@ -752,6 +744,8 @@ static int cs4270_probe(struct platform_device *pdev)
        if (codec->control_data) {
                /* Initialize codec ops */
                cs4270_dai.ops.hw_params = cs4270_hw_params;
+               cs4270_dai.dai_ops.set_sysclk = cs4270_set_dai_sysclk;
+               cs4270_dai.dai_ops.set_fmt = cs4270_set_dai_fmt;
 #ifdef CONFIG_SND_SOC_CS4270_HWMUTE
                cs4270_dai.dai_ops.digital_mute = cs4270_mute;
 #endif
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c
new file mode 100644 (file)
index 0000000..710e028
--- /dev/null
@@ -0,0 +1,1274 @@
+/*
+ * ALSA SoC TLV320AIC3X codec driver
+ *
+ * Author:      Vladimir Barinov, <vbarinov@ru.mvista.com>
+ * Copyright:   (C) 2007 MontaVista Software, Inc., <source@mvista.com>
+ *
+ * Based on sound/soc/codecs/wm8753.c by Liam Girdwood
+ *
+ * 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.
+ *
+ * Notes:
+ *  The AIC3X is a driver for a low power stereo audio
+ *  codecs aic31, aic32, aic33.
+ *
+ *  It supports full aic33 codec functionality.
+ *  The compatibility with aic32, aic31 is as follows:
+ *        aic32        |        aic31
+ *  ---------------------------------------
+ *   MONO_LOUT -> N/A  |  MONO_LOUT -> N/A
+ *                     |  IN1L -> LINE1L
+ *                     |  IN1R -> LINE1R
+ *                     |  IN2L -> LINE2L
+ *                     |  IN2R -> LINE2R
+ *                     |  MIC3L/R -> N/A
+ *   truncated internal functionality in
+ *   accordance with documentation
+ *  ---------------------------------------
+ *
+ *  Hence the machine layer should disable unsupported inputs/outputs by
+ *  snd_soc_dapm_set_endpoint(codec, "MONO_LOUT", 0), etc.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+
+#include "tlv320aic3x.h"
+
+#define AUDIO_NAME "aic3x"
+#define AIC3X_VERSION "0.1"
+
+/* codec private data */
+struct aic3x_priv {
+       unsigned int sysclk;
+       int master;
+};
+
+/*
+ * AIC3X register cache
+ * We can't read the AIC3X register space when we are
+ * using 2 wire for device control, so we cache them instead.
+ * There is no point in caching the reset register
+ */
+static const u8 aic3x_reg[AIC3X_CACHEREGNUM] = {
+       0x00, 0x00, 0x00, 0x10, /* 0 */
+       0x04, 0x00, 0x00, 0x00, /* 4 */
+       0x00, 0x00, 0x00, 0x01, /* 8 */
+       0x00, 0x00, 0x00, 0x80, /* 12 */
+       0x80, 0xff, 0xff, 0x78, /* 16 */
+       0x78, 0x78, 0x78, 0x78, /* 20 */
+       0x78, 0x00, 0x00, 0xfe, /* 24 */
+       0x00, 0x00, 0xfe, 0x00, /* 28 */
+       0x18, 0x18, 0x00, 0x00, /* 32 */
+       0x00, 0x00, 0x00, 0x00, /* 36 */
+       0x00, 0x00, 0x00, 0x80, /* 40 */
+       0x80, 0x00, 0x00, 0x00, /* 44 */
+       0x00, 0x00, 0x00, 0x04, /* 48 */
+       0x00, 0x00, 0x00, 0x00, /* 52 */
+       0x00, 0x00, 0x04, 0x00, /* 56 */
+       0x00, 0x00, 0x00, 0x00, /* 60 */
+       0x00, 0x04, 0x00, 0x00, /* 64 */
+       0x00, 0x00, 0x00, 0x00, /* 68 */
+       0x04, 0x00, 0x00, 0x00, /* 72 */
+       0x00, 0x00, 0x00, 0x00, /* 76 */
+       0x00, 0x00, 0x00, 0x00, /* 80 */
+       0x00, 0x00, 0x00, 0x00, /* 84 */
+       0x00, 0x00, 0x00, 0x00, /* 88 */
+       0x00, 0x00, 0x00, 0x00, /* 92 */
+       0x00, 0x00, 0x00, 0x00, /* 96 */
+       0x00, 0x00, 0x02,       /* 100 */
+};
+
+/*
+ * read aic3x register cache
+ */
+static inline unsigned int aic3x_read_reg_cache(struct snd_soc_codec *codec,
+                                               unsigned int reg)
+{
+       u8 *cache = codec->reg_cache;
+       if (reg >= AIC3X_CACHEREGNUM)
+               return -1;
+       return cache[reg];
+}
+
+/*
+ * write aic3x register cache
+ */
+static inline void aic3x_write_reg_cache(struct snd_soc_codec *codec,
+                                        u8 reg, u8 value)
+{
+       u8 *cache = codec->reg_cache;
+       if (reg >= AIC3X_CACHEREGNUM)
+               return;
+       cache[reg] = value;
+}
+
+/*
+ * write to the aic3x register space
+ */
+static int aic3x_write(struct snd_soc_codec *codec, unsigned int reg,
+                      unsigned int value)
+{
+       u8 data[2];
+
+       /* data is
+        *   D15..D8 aic3x register offset
+        *   D7...D0 register data
+        */
+       data[0] = reg & 0xff;
+       data[1] = value & 0xff;
+
+       aic3x_write_reg_cache(codec, data[0], data[1]);
+       if (codec->hw_write(codec->control_data, data, 2) == 2)
+               return 0;
+       else
+               return -EIO;
+}
+
+#define SOC_DAPM_SINGLE_AIC3X(xname, reg, shift, mask, invert) \
+{      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+       .info = snd_soc_info_volsw, \
+       .get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw_aic3x, \
+       .private_value =  SOC_SINGLE_VALUE(reg, shift, mask, invert) }
+
+/*
+ * All input lines are connected when !0xf and disconnected with 0xf bit field,
+ * so we have to use specific dapm_put call for input mixer
+ */
+static int snd_soc_dapm_put_volsw_aic3x(struct snd_kcontrol *kcontrol,
+                                       struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
+       int reg = kcontrol->private_value & 0xff;
+       int shift = (kcontrol->private_value >> 8) & 0x0f;
+       int mask = (kcontrol->private_value >> 16) & 0xff;
+       int invert = (kcontrol->private_value >> 24) & 0x01;
+       unsigned short val, val_mask;
+       int ret;
+       struct snd_soc_dapm_path *path;
+       int found = 0;
+
+       val = (ucontrol->value.integer.value[0] & mask);
+
+       mask = 0xf;
+       if (val)
+               val = mask;
+
+       if (invert)
+               val = mask - val;
+       val_mask = mask << shift;
+       val = val << shift;
+
+       mutex_lock(&widget->codec->mutex);
+
+       if (snd_soc_test_bits(widget->codec, reg, val_mask, val)) {
+               /* find dapm widget path assoc with kcontrol */
+               list_for_each_entry(path, &widget->codec->dapm_paths, list) {
+                       if (path->kcontrol != kcontrol)
+                               continue;
+
+                       /* found, now check type */
+                       found = 1;
+                       if (val)
+                               /* new connection */
+                               path->connect = invert ? 0 : 1;
+                       else
+                               /* old connection must be powered down */
+                               path->connect = invert ? 1 : 0;
+                       break;
+               }
+
+               if (found)
+                       snd_soc_dapm_sync_endpoints(widget->codec);
+       }
+
+       ret = snd_soc_update_bits(widget->codec, reg, val_mask, val);
+
+       mutex_unlock(&widget->codec->mutex);
+       return ret;
+}
+
+static const char *aic3x_left_dac_mux[] = { "DAC_L1", "DAC_L3", "DAC_L2" };
+static const char *aic3x_right_dac_mux[] = { "DAC_R1", "DAC_R3", "DAC_R2" };
+static const char *aic3x_left_hpcom_mux[] =
+    { "differential of HPLOUT", "constant VCM", "single-ended" };
+static const char *aic3x_right_hpcom_mux[] =
+    { "differential of HPROUT", "constant VCM", "single-ended",
+      "differential of HPLCOM", "external feedback" };
+static const char *aic3x_linein_mode_mux[] = { "single-ended", "differential" };
+
+#define LDAC_ENUM      0
+#define RDAC_ENUM      1
+#define LHPCOM_ENUM    2
+#define RHPCOM_ENUM    3
+#define LINE1L_ENUM    4
+#define LINE1R_ENUM    5
+#define LINE2L_ENUM    6
+#define LINE2R_ENUM    7
+
+static const struct soc_enum aic3x_enum[] = {
+       SOC_ENUM_SINGLE(DAC_LINE_MUX, 6, 3, aic3x_left_dac_mux),
+       SOC_ENUM_SINGLE(DAC_LINE_MUX, 4, 3, aic3x_right_dac_mux),
+       SOC_ENUM_SINGLE(HPLCOM_CFG, 4, 3, aic3x_left_hpcom_mux),
+       SOC_ENUM_SINGLE(HPRCOM_CFG, 3, 5, aic3x_right_hpcom_mux),
+       SOC_ENUM_SINGLE(LINE1L_2_LADC_CTRL, 7, 2, aic3x_linein_mode_mux),
+       SOC_ENUM_SINGLE(LINE1R_2_RADC_CTRL, 7, 2, aic3x_linein_mode_mux),
+       SOC_ENUM_SINGLE(LINE2L_2_LADC_CTRL, 7, 2, aic3x_linein_mode_mux),
+       SOC_ENUM_SINGLE(LINE2R_2_RADC_CTRL, 7, 2, aic3x_linein_mode_mux),
+};
+
+static const struct snd_kcontrol_new aic3x_snd_controls[] = {
+       /* Output */
+       SOC_DOUBLE_R("PCM Playback Volume", LDAC_VOL, RDAC_VOL, 0, 0x7f, 1),
+
+       SOC_DOUBLE_R("Line DAC Playback Volume", DACL1_2_LLOPM_VOL,
+                    DACR1_2_RLOPM_VOL, 0, 0x7f, 1),
+       SOC_DOUBLE_R("Line DAC Playback Switch", LLOPM_CTRL, RLOPM_CTRL, 3,
+                    0x01, 0),
+       SOC_DOUBLE_R("Line PGA Bypass Playback Volume", PGAL_2_LLOPM_VOL,
+                    PGAR_2_RLOPM_VOL, 0, 0x7f, 1),
+       SOC_DOUBLE_R("Line Line2 Bypass Playback Volume", LINE2L_2_LLOPM_VOL,
+                    LINE2R_2_RLOPM_VOL, 0, 0x7f, 1),
+
+       SOC_DOUBLE_R("Mono DAC Playback Volume", DACL1_2_MONOLOPM_VOL,
+                    DACR1_2_MONOLOPM_VOL, 0, 0x7f, 1),
+       SOC_SINGLE("Mono DAC Playback Switch", MONOLOPM_CTRL, 3, 0x01, 0),
+       SOC_DOUBLE_R("Mono PGA Bypass Playback Volume", PGAL_2_MONOLOPM_VOL,
+                    PGAR_2_MONOLOPM_VOL, 0, 0x7f, 1),
+       SOC_DOUBLE_R("Mono Line2 Bypass Playback Volume", LINE2L_2_MONOLOPM_VOL,
+                    LINE2R_2_MONOLOPM_VOL, 0, 0x7f, 1),
+
+       SOC_DOUBLE_R("HP DAC Playback Volume", DACL1_2_HPLOUT_VOL,
+                    DACR1_2_HPROUT_VOL, 0, 0x7f, 1),
+       SOC_DOUBLE_R("HP DAC Playback Switch", HPLOUT_CTRL, HPROUT_CTRL, 3,
+                    0x01, 0),
+       SOC_DOUBLE_R("HP PGA Bypass Playback Volume", PGAL_2_HPLOUT_VOL,
+                    PGAR_2_HPROUT_VOL, 0, 0x7f, 1),
+       SOC_DOUBLE_R("HP Line2 Bypass Playback Volume", LINE2L_2_HPLOUT_VOL,
+                    LINE2R_2_HPROUT_VOL, 0, 0x7f, 1),
+
+       SOC_DOUBLE_R("HPCOM DAC Playback Volume", DACL1_2_HPLCOM_VOL,
+                    DACR1_2_HPRCOM_VOL, 0, 0x7f, 1),
+       SOC_DOUBLE_R("HPCOM DAC Playback Switch", HPLCOM_CTRL, HPRCOM_CTRL, 3,
+                    0x01, 0),
+       SOC_DOUBLE_R("HPCOM PGA Bypass Playback Volume", PGAL_2_HPLCOM_VOL,
+                    PGAR_2_HPRCOM_VOL, 0, 0x7f, 1),
+       SOC_DOUBLE_R("HPCOM Line2 Bypass Playback Volume", LINE2L_2_HPLCOM_VOL,
+                    LINE2R_2_HPRCOM_VOL, 0, 0x7f, 1),
+
+       /*
+        * Note: enable Automatic input Gain Controller with care. It can
+        * adjust PGA to max value when ADC is on and will never go back.
+       */
+       SOC_DOUBLE_R("AGC Switch", LAGC_CTRL_A, RAGC_CTRL_A, 7, 0x01, 0),
+
+       /* Input */
+       SOC_DOUBLE_R("PGA Capture Volume", LADC_VOL, RADC_VOL, 0, 0x7f, 0),
+       SOC_DOUBLE_R("PGA Capture Switch", LADC_VOL, RADC_VOL, 7, 0x01, 1),
+};
+
+/* add non dapm controls */
+static int aic3x_add_controls(struct snd_soc_codec *codec)
+{
+       int err, i;
+
+       for (i = 0; i < ARRAY_SIZE(aic3x_snd_controls); i++) {
+               err = snd_ctl_add(codec->card,
+                                 snd_soc_cnew(&aic3x_snd_controls[i],
+                                              codec, NULL));
+               if (err < 0)
+                       return err;
+       }
+
+       return 0;
+}
+
+/* Left DAC Mux */
+static const struct snd_kcontrol_new aic3x_left_dac_mux_controls =
+SOC_DAPM_ENUM("Route", aic3x_enum[LDAC_ENUM]);
+
+/* Right DAC Mux */
+static const struct snd_kcontrol_new aic3x_right_dac_mux_controls =
+SOC_DAPM_ENUM("Route", aic3x_enum[RDAC_ENUM]);
+
+/* Left HPCOM Mux */
+static const struct snd_kcontrol_new aic3x_left_hpcom_mux_controls =
+SOC_DAPM_ENUM("Route", aic3x_enum[LHPCOM_ENUM]);
+
+/* Right HPCOM Mux */
+static const struct snd_kcontrol_new aic3x_right_hpcom_mux_controls =
+SOC_DAPM_ENUM("Route", aic3x_enum[RHPCOM_ENUM]);
+
+/* Left DAC_L1 Mixer */
+static const struct snd_kcontrol_new aic3x_left_dac_mixer_controls[] = {
+       SOC_DAPM_SINGLE("Line Switch", DACL1_2_LLOPM_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("Mono Switch", DACL1_2_MONOLOPM_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("HP Switch", DACL1_2_HPLOUT_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("HPCOM Switch", DACL1_2_HPLCOM_VOL, 7, 1, 0),
+};
+
+/* Right DAC_R1 Mixer */
+static const struct snd_kcontrol_new aic3x_right_dac_mixer_controls[] = {
+       SOC_DAPM_SINGLE("Line Switch", DACR1_2_RLOPM_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("Mono Switch", DACR1_2_MONOLOPM_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("HP Switch", DACR1_2_HPROUT_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("HPCOM Switch", DACR1_2_HPRCOM_VOL, 7, 1, 0),
+};
+
+/* Left PGA Mixer */
+static const struct snd_kcontrol_new aic3x_left_pga_mixer_controls[] = {
+       SOC_DAPM_SINGLE_AIC3X("Line1L Switch", LINE1L_2_LADC_CTRL, 3, 1, 1),
+       SOC_DAPM_SINGLE_AIC3X("Line2L Switch", LINE2L_2_LADC_CTRL, 3, 1, 1),
+       SOC_DAPM_SINGLE_AIC3X("Mic3L Switch", MIC3LR_2_LADC_CTRL, 4, 1, 1),
+};
+
+/* Right PGA Mixer */
+static const struct snd_kcontrol_new aic3x_right_pga_mixer_controls[] = {
+       SOC_DAPM_SINGLE_AIC3X("Line1R Switch", LINE1R_2_RADC_CTRL, 3, 1, 1),
+       SOC_DAPM_SINGLE_AIC3X("Line2R Switch", LINE2R_2_RADC_CTRL, 3, 1, 1),
+       SOC_DAPM_SINGLE_AIC3X("Mic3R Switch", MIC3LR_2_RADC_CTRL, 0, 1, 1),
+};
+
+/* Left Line1 Mux */
+static const struct snd_kcontrol_new aic3x_left_line1_mux_controls =
+SOC_DAPM_ENUM("Route", aic3x_enum[LINE1L_ENUM]);
+
+/* Right Line1 Mux */
+static const struct snd_kcontrol_new aic3x_right_line1_mux_controls =
+SOC_DAPM_ENUM("Route", aic3x_enum[LINE1R_ENUM]);
+
+/* Left Line2 Mux */
+static const struct snd_kcontrol_new aic3x_left_line2_mux_controls =
+SOC_DAPM_ENUM("Route", aic3x_enum[LINE2L_ENUM]);
+
+/* Right Line2 Mux */
+static const struct snd_kcontrol_new aic3x_right_line2_mux_controls =
+SOC_DAPM_ENUM("Route", aic3x_enum[LINE2R_ENUM]);
+
+/* Left PGA Bypass Mixer */
+static const struct snd_kcontrol_new aic3x_left_pga_bp_mixer_controls[] = {
+       SOC_DAPM_SINGLE("Line Switch", PGAL_2_LLOPM_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("Mono Switch", PGAL_2_MONOLOPM_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("HP Switch", PGAL_2_HPLOUT_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("HPCOM Switch", PGAL_2_HPLCOM_VOL, 7, 1, 0),
+};
+
+/* Right PGA Bypass Mixer */
+static const struct snd_kcontrol_new aic3x_right_pga_bp_mixer_controls[] = {
+       SOC_DAPM_SINGLE("Line Switch", PGAR_2_RLOPM_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("Mono Switch", PGAR_2_MONOLOPM_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("HP Switch", PGAR_2_HPROUT_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("HPCOM Switch", PGAR_2_HPRCOM_VOL, 7, 1, 0),
+};
+
+/* Left Line2 Bypass Mixer */
+static const struct snd_kcontrol_new aic3x_left_line2_bp_mixer_controls[] = {
+       SOC_DAPM_SINGLE("Line Switch", LINE2L_2_LLOPM_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("Mono Switch", LINE2L_2_MONOLOPM_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("HP Switch", LINE2L_2_HPLOUT_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("HPCOM Switch", LINE2L_2_HPLCOM_VOL, 7, 1, 0),
+};
+
+/* Right Line2 Bypass Mixer */
+static const struct snd_kcontrol_new aic3x_right_line2_bp_mixer_controls[] = {
+       SOC_DAPM_SINGLE("Line Switch", LINE2R_2_RLOPM_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("Mono Switch", LINE2R_2_MONOLOPM_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("HP Switch", LINE2R_2_HPROUT_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("HPCOM Switch", LINE2R_2_HPRCOM_VOL, 7, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = {
+       /* Left DAC to Left Outputs */
+       SND_SOC_DAPM_DAC("Left DAC", "Left Playback", DAC_PWR, 7, 0),
+       SND_SOC_DAPM_MUX("Left DAC Mux", SND_SOC_NOPM, 0, 0,
+                        &aic3x_left_dac_mux_controls),
+       SND_SOC_DAPM_MIXER("Left DAC_L1 Mixer", SND_SOC_NOPM, 0, 0,
+                          &aic3x_left_dac_mixer_controls[0],
+                          ARRAY_SIZE(aic3x_left_dac_mixer_controls)),
+       SND_SOC_DAPM_MUX("Left HPCOM Mux", SND_SOC_NOPM, 0, 0,
+                        &aic3x_left_hpcom_mux_controls),
+       SND_SOC_DAPM_PGA("Left Line Out", LLOPM_CTRL, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("Left HP Out", HPLOUT_CTRL, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("Left HP Com", HPLCOM_CTRL, 0, 0, NULL, 0),
+
+       /* Right DAC to Right Outputs */
+       SND_SOC_DAPM_DAC("Right DAC", "Right Playback", DAC_PWR, 6, 0),
+       SND_SOC_DAPM_MUX("Right DAC Mux", SND_SOC_NOPM, 0, 0,
+                        &aic3x_right_dac_mux_controls),
+       SND_SOC_DAPM_MIXER("Right DAC_R1 Mixer", SND_SOC_NOPM, 0, 0,
+                          &aic3x_right_dac_mixer_controls[0],
+                          ARRAY_SIZE(aic3x_right_dac_mixer_controls)),
+       SND_SOC_DAPM_MUX("Right HPCOM Mux", SND_SOC_NOPM, 0, 0,
+                        &aic3x_right_hpcom_mux_controls),
+       SND_SOC_DAPM_PGA("Right Line Out", RLOPM_CTRL, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("Right HP Out", HPROUT_CTRL, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("Right HP Com", HPRCOM_CTRL, 0, 0, NULL, 0),
+
+       /* Mono Output */
+       SND_SOC_DAPM_PGA("Mono Out", MONOLOPM_CTRL, 0, 0, NULL, 0),
+
+       /* Left Inputs to Left ADC */
+       SND_SOC_DAPM_ADC("Left ADC", "Left Capture", LINE1L_2_LADC_CTRL, 2, 0),
+       SND_SOC_DAPM_MIXER("Left PGA Mixer", SND_SOC_NOPM, 0, 0,
+                          &aic3x_left_pga_mixer_controls[0],
+                          ARRAY_SIZE(aic3x_left_pga_mixer_controls)),
+       SND_SOC_DAPM_MUX("Left Line1L Mux", SND_SOC_NOPM, 0, 0,
+                        &aic3x_left_line1_mux_controls),
+       SND_SOC_DAPM_MUX("Left Line2L Mux", SND_SOC_NOPM, 0, 0,
+                        &aic3x_left_line2_mux_controls),
+
+       /* Right Inputs to Right ADC */
+       SND_SOC_DAPM_ADC("Right ADC", "Right Capture",
+                        LINE1R_2_RADC_CTRL, 2, 0),
+       SND_SOC_DAPM_MIXER("Right PGA Mixer", SND_SOC_NOPM, 0, 0,
+                          &aic3x_right_pga_mixer_controls[0],
+                          ARRAY_SIZE(aic3x_right_pga_mixer_controls)),
+       SND_SOC_DAPM_MUX("Right Line1R Mux", SND_SOC_NOPM, 0, 0,
+                        &aic3x_right_line1_mux_controls),
+       SND_SOC_DAPM_MUX("Right Line2R Mux", SND_SOC_NOPM, 0, 0,
+                        &aic3x_right_line2_mux_controls),
+
+       /* Mic Bias */
+       SND_SOC_DAPM_MICBIAS("Mic Bias 2V", MICBIAS_CTRL, 6, 0),
+       SND_SOC_DAPM_MICBIAS("Mic Bias 2.5V", MICBIAS_CTRL, 7, 0),
+       SND_SOC_DAPM_MICBIAS("Mic Bias AVDD", MICBIAS_CTRL, 6, 0),
+       SND_SOC_DAPM_MICBIAS("Mic Bias AVDD", MICBIAS_CTRL, 7, 0),
+
+       /* Left PGA to Left Output bypass */
+       SND_SOC_DAPM_MIXER("Left PGA Bypass Mixer", SND_SOC_NOPM, 0, 0,
+                          &aic3x_left_pga_bp_mixer_controls[0],
+                          ARRAY_SIZE(aic3x_left_pga_bp_mixer_controls)),
+
+       /* Right PGA to Right Output bypass */
+       SND_SOC_DAPM_MIXER("Right PGA Bypass Mixer", SND_SOC_NOPM, 0, 0,
+                          &aic3x_right_pga_bp_mixer_controls[0],
+                          ARRAY_SIZE(aic3x_right_pga_bp_mixer_controls)),
+
+       /* Left Line2 to Left Output bypass */
+       SND_SOC_DAPM_MIXER("Left Line2 Bypass Mixer", SND_SOC_NOPM, 0, 0,
+                          &aic3x_left_line2_bp_mixer_controls[0],
+                          ARRAY_SIZE(aic3x_left_line2_bp_mixer_controls)),
+
+       /* Right Line2 to Right Output bypass */
+       SND_SOC_DAPM_MIXER("Right Line2 Bypass Mixer", SND_SOC_NOPM, 0, 0,
+                          &aic3x_right_line2_bp_mixer_controls[0],
+                          ARRAY_SIZE(aic3x_right_line2_bp_mixer_controls)),
+
+       SND_SOC_DAPM_OUTPUT("LLOUT"),
+       SND_SOC_DAPM_OUTPUT("RLOUT"),
+       SND_SOC_DAPM_OUTPUT("MONO_LOUT"),
+       SND_SOC_DAPM_OUTPUT("HPLOUT"),
+       SND_SOC_DAPM_OUTPUT("HPROUT"),
+       SND_SOC_DAPM_OUTPUT("HPLCOM"),
+       SND_SOC_DAPM_OUTPUT("HPRCOM"),
+
+       SND_SOC_DAPM_INPUT("MIC3L"),
+       SND_SOC_DAPM_INPUT("MIC3R"),
+       SND_SOC_DAPM_INPUT("LINE1L"),
+       SND_SOC_DAPM_INPUT("LINE1R"),
+       SND_SOC_DAPM_INPUT("LINE2L"),
+       SND_SOC_DAPM_INPUT("LINE2R"),
+};
+
+static const char *intercon[][3] = {
+       /* Left Output */
+       {"Left DAC Mux", "DAC_L1", "Left DAC"},
+       {"Left DAC Mux", "DAC_L2", "Left DAC"},
+       {"Left DAC Mux", "DAC_L3", "Left DAC"},
+
+       {"Left DAC_L1 Mixer", "Line Switch", "Left DAC Mux"},
+       {"Left DAC_L1 Mixer", "Mono Switch", "Left DAC Mux"},
+       {"Left DAC_L1 Mixer", "HP Switch", "Left DAC Mux"},
+       {"Left DAC_L1 Mixer", "HPCOM Switch", "Left DAC Mux"},
+       {"Left Line Out", NULL, "Left DAC Mux"},
+       {"Left HP Out", NULL, "Left DAC Mux"},
+
+       {"Left HPCOM Mux", "differential of HPLOUT", "Left DAC_L1 Mixer"},
+       {"Left HPCOM Mux", "constant VCM", "Left DAC_L1 Mixer"},
+       {"Left HPCOM Mux", "single-ended", "Left DAC_L1 Mixer"},
+
+       {"Left Line Out", NULL, "Left DAC_L1 Mixer"},
+       {"Mono Out", NULL, "Left DAC_L1 Mixer"},
+       {"Left HP Out", NULL, "Left DAC_L1 Mixer"},
+       {"Left HP Com", NULL, "Left HPCOM Mux"},
+
+       {"LLOUT", NULL, "Left Line Out"},
+       {"LLOUT", NULL, "Left Line Out"},
+       {"HPLOUT", NULL, "Left HP Out"},
+       {"HPLCOM", NULL, "Left HP Com"},
+
+       /* Right Output */
+       {"Right DAC Mux", "DAC_R1", "Right DAC"},
+       {"Right DAC Mux", "DAC_R2", "Right DAC"},
+       {"Right DAC Mux", "DAC_R3", "Right DAC"},
+
+       {"Right DAC_R1 Mixer", "Line Switch", "Right DAC Mux"},
+       {"Right DAC_R1 Mixer", "Mono Switch", "Right DAC Mux"},
+       {"Right DAC_R1 Mixer", "HP Switch", "Right DAC Mux"},
+       {"Right DAC_R1 Mixer", "HPCOM Switch", "Right DAC Mux"},
+       {"Right Line Out", NULL, "Right DAC Mux"},
+       {"Right HP Out", NULL, "Right DAC Mux"},
+
+       {"Right HPCOM Mux", "differential of HPROUT", "Right DAC_R1 Mixer"},
+       {"Right HPCOM Mux", "constant VCM", "Right DAC_R1 Mixer"},
+       {"Right HPCOM Mux", "single-ended", "Right DAC_R1 Mixer"},
+       {"Right HPCOM Mux", "differential of HPLCOM", "Right DAC_R1 Mixer"},
+       {"Right HPCOM Mux", "external feedback", "Right DAC_R1 Mixer"},
+
+       {"Right Line Out", NULL, "Right DAC_R1 Mixer"},
+       {"Mono Out", NULL, "Right DAC_R1 Mixer"},
+       {"Right HP Out", NULL, "Right DAC_R1 Mixer"},
+       {"Right HP Com", NULL, "Right HPCOM Mux"},
+
+       {"RLOUT", NULL, "Right Line Out"},
+       {"RLOUT", NULL, "Right Line Out"},
+       {"HPROUT", NULL, "Right HP Out"},
+       {"HPRCOM", NULL, "Right HP Com"},
+
+       /* Mono Output */
+       {"MONOLOUT", NULL, "Mono Out"},
+       {"MONOLOUT", NULL, "Mono Out"},
+
+       /* Left Input */
+       {"Left Line1L Mux", "single-ended", "LINE1L"},
+       {"Left Line1L Mux", "differential", "LINE1L"},
+
+       {"Left Line2L Mux", "single-ended", "LINE2L"},
+       {"Left Line2L Mux", "differential", "LINE2L"},
+
+       {"Left PGA Mixer", "Line1L Switch", "Left Line1L Mux"},
+       {"Left PGA Mixer", "Line2L Switch", "Left Line2L Mux"},
+       {"Left PGA Mixer", "Mic3L Switch", "MIC3L"},
+
+       {"Left ADC", NULL, "Left PGA Mixer"},
+
+       /* Right Input */
+       {"Right Line1R Mux", "single-ended", "LINE1R"},
+       {"Right Line1R Mux", "differential", "LINE1R"},
+
+       {"Right Line2R Mux", "single-ended", "LINE2R"},
+       {"Right Line2R Mux", "differential", "LINE2R"},
+
+       {"Right PGA Mixer", "Line1R Switch", "Right Line1R Mux"},
+       {"Right PGA Mixer", "Line2R Switch", "Right Line2R Mux"},
+       {"Right PGA Mixer", "Mic3R Switch", "MIC3R"},
+
+       {"Right ADC", NULL, "Right PGA Mixer"},
+
+       /* Left PGA Bypass */
+       {"Left PGA Bypass Mixer", "Line Switch", "Left PGA Mixer"},
+       {"Left PGA Bypass Mixer", "Mono Switch", "Left PGA Mixer"},
+       {"Left PGA Bypass Mixer", "HP Switch", "Left PGA Mixer"},
+       {"Left PGA Bypass Mixer", "HPCOM Switch", "Left PGA Mixer"},
+
+       {"Left HPCOM Mux", "differential of HPLOUT", "Left PGA Bypass Mixer"},
+       {"Left HPCOM Mux", "constant VCM", "Left PGA Bypass Mixer"},
+       {"Left HPCOM Mux", "single-ended", "Left PGA Bypass Mixer"},
+
+       {"Left Line Out", NULL, "Left PGA Bypass Mixer"},
+       {"Mono Out", NULL, "Left PGA Bypass Mixer"},
+       {"Left HP Out", NULL, "Left PGA Bypass Mixer"},
+
+       /* Right PGA Bypass */
+       {"Right PGA Bypass Mixer", "Line Switch", "Right PGA Mixer"},
+       {"Right PGA Bypass Mixer", "Mono Switch", "Right PGA Mixer"},
+       {"Right PGA Bypass Mixer", "HP Switch", "Right PGA Mixer"},
+       {"Right PGA Bypass Mixer", "HPCOM Switch", "Right PGA Mixer"},
+
+       {"Right HPCOM Mux", "differential of HPROUT", "Right PGA Bypass Mixer"},
+       {"Right HPCOM Mux", "constant VCM", "Right PGA Bypass Mixer"},
+       {"Right HPCOM Mux", "single-ended", "Right PGA Bypass Mixer"},
+       {"Right HPCOM Mux", "differential of HPLCOM", "Right PGA Bypass Mixer"},
+       {"Right HPCOM Mux", "external feedback", "Right PGA Bypass Mixer"},
+
+       {"Right Line Out", NULL, "Right PGA Bypass Mixer"},
+       {"Mono Out", NULL, "Right PGA Bypass Mixer"},
+       {"Right HP Out", NULL, "Right PGA Bypass Mixer"},
+
+       /* Left Line2 Bypass */
+       {"Left Line2 Bypass Mixer", "Line Switch", "Left Line2L Mux"},
+       {"Left Line2 Bypass Mixer", "Mono Switch", "Left Line2L Mux"},
+       {"Left Line2 Bypass Mixer", "HP Switch", "Left Line2L Mux"},
+       {"Left Line2 Bypass Mixer", "HPCOM Switch", "Left Line2L Mux"},
+
+       {"Left HPCOM Mux", "differential of HPLOUT", "Left Line2 Bypass Mixer"},
+       {"Left HPCOM Mux", "constant VCM", "Left Line2 Bypass Mixer"},
+       {"Left HPCOM Mux", "single-ended", "Left Line2 Bypass Mixer"},
+
+       {"Left Line Out", NULL, "Left Line2 Bypass Mixer"},
+       {"Mono Out", NULL, "Left Line2 Bypass Mixer"},
+       {"Left HP Out", NULL, "Left Line2 Bypass Mixer"},
+
+       /* Right Line2 Bypass */
+       {"Right Line2 Bypass Mixer", "Line Switch", "Right Line2R Mux"},
+       {"Right Line2 Bypass Mixer", "Mono Switch", "Right Line2R Mux"},
+       {"Right Line2 Bypass Mixer", "HP Switch", "Right Line2R Mux"},
+       {"Right Line2 Bypass Mixer", "HPCOM Switch", "Right Line2R Mux"},
+
+       {"Right HPCOM Mux", "differential of HPROUT", "Right Line2 Bypass Mixer"},
+       {"Right HPCOM Mux", "constant VCM", "Right Line2 Bypass Mixer"},
+       {"Right HPCOM Mux", "single-ended", "Right Line2 Bypass Mixer"},
+       {"Right HPCOM Mux", "differential of HPLCOM", "Right Line2 Bypass Mixer"},
+       {"Right HPCOM Mux", "external feedback", "Right Line2 Bypass Mixer"},
+
+       {"Right Line Out", NULL, "Right Line2 Bypass Mixer"},
+       {"Mono Out", NULL, "Right Line2 Bypass Mixer"},
+       {"Right HP Out", NULL, "Right Line2 Bypass Mixer"},
+
+       /* terminator */
+       {NULL, NULL, NULL},
+};
+
+static int aic3x_add_widgets(struct snd_soc_codec *codec)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(aic3x_dapm_widgets); i++)
+               snd_soc_dapm_new_control(codec, &aic3x_dapm_widgets[i]);
+
+       /* set up audio path interconnects */
+       for (i = 0; intercon[i][0] != NULL; i++)
+               snd_soc_dapm_connect_input(codec, intercon[i][0],
+                                          intercon[i][1], intercon[i][2]);
+
+       snd_soc_dapm_new_widgets(codec);
+       return 0;
+}
+
+struct aic3x_rate_divs {
+       u32 mclk;
+       u32 rate;
+       u32 fsref_reg;
+       u8 sr_reg:4;
+       u8 pllj_reg;
+       u16 plld_reg;
+};
+
+/* AIC3X codec mclk clock divider coefficients */
+static const struct aic3x_rate_divs aic3x_divs[] = {
+       /* 8k */
+       {22579200, 8000, 48000, 0xa, 8, 7075},
+       {33868800, 8000, 48000, 0xa, 5, 8049},
+       /* 11.025k */
+       {22579200, 11025, 44100, 0x6, 8, 0},
+       {33868800, 11025, 44100, 0x6, 5, 3333},
+       /* 16k */
+       {22579200, 16000, 48000, 0x4, 8, 7075},
+       {33868800, 16000, 48000, 0x4, 5, 8049},
+       /* 22.05k */
+       {22579200, 22050, 44100, 0x2, 8, 0},
+       {33868800, 22050, 44100, 0x2, 5, 3333},
+       /* 32k */
+       {22579200, 32000, 48000, 0x1, 8, 7075},
+       {33868800, 32000, 48000, 0x1, 5, 8049},
+       /* 44.1k */
+       {22579200, 44100, 44100, 0x0, 8, 0},
+       {33868800, 44100, 44100, 0x0, 5, 3333},
+       /* 48k */
+       {22579200, 48000, 48000, 0x0, 8, 7075},
+       {33868800, 48000, 48000, 0x0, 5, 8049},
+       /* 64k */
+       {22579200, 96000, 96000, 0x1, 8, 7075},
+       {33868800, 96000, 96000, 0x1, 5, 8049},
+       /* 88.2k */
+       {22579200, 88200, 88200, 0x0, 8, 0},
+       {33868800, 88200, 88200, 0x0, 5, 3333},
+       /* 96k */
+       {22579200, 96000, 96000, 0x0, 8, 7075},
+       {33868800, 96000, 96000, 0x0, 5, 8049},
+};
+
+static inline int aic3x_get_divs(int mclk, int rate)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(aic3x_divs); i++) {
+               if (aic3x_divs[i].rate == rate && aic3x_divs[i].mclk == mclk)
+                       return i;
+       }
+
+       return 0;
+}
+
+static int aic3x_hw_params(struct snd_pcm_substream *substream,
+                          struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_device *socdev = rtd->socdev;
+       struct snd_soc_codec *codec = socdev->codec;
+       struct aic3x_priv *aic3x = codec->private_data;
+       int i;
+       u8 data, pll_p, pll_r, pll_j;
+       u16 pll_d;
+
+       i = aic3x_get_divs(aic3x->sysclk, params_rate(params));
+
+       /* Route Left DAC to left channel input and
+        * right DAC to right channel input */
+       data = (LDAC2LCH | RDAC2RCH);
+       switch (aic3x_divs[i].fsref_reg) {
+       case 44100:
+               data |= FSREF_44100;
+               break;
+       case 48000:
+               data |= FSREF_48000;
+               break;
+       case 88200:
+               data |= FSREF_44100 | DUAL_RATE_MODE;
+               break;
+       case 96000:
+               data |= FSREF_48000 | DUAL_RATE_MODE;
+               break;
+       }
+       aic3x_write(codec, AIC3X_CODEC_DATAPATH_REG, data);
+
+       /* codec sample rate select */
+       data = aic3x_divs[i].sr_reg;
+       data |= (data << 4);
+       aic3x_write(codec, AIC3X_SAMPLE_RATE_SEL_REG, data);
+
+       /* Use PLL for generation Fsref by equation:
+        * Fsref = (MCLK * K * R)/(2048 * P);
+        * Fix P = 2 and R = 1 and calculate K, if
+        * K = J.D, i.e. J - an interger portion of K and D is the fractional
+        * one with 4 digits of precision;
+        * Example:
+        * For MCLK = 22.5792 MHz and Fsref = 48kHz:
+        * Select P = 2, R= 1, K = 8.7074, which results in J = 8, D = 7074
+        */
+       pll_p = 2;
+       pll_r = 1;
+       pll_j = aic3x_divs[i].pllj_reg;
+       pll_d = aic3x_divs[i].plld_reg;
+
+       data = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG);
+       aic3x_write(codec, AIC3X_PLL_PROGA_REG, data | (pll_p << PLLP_SHIFT));
+       aic3x_write(codec, AIC3X_OVRF_STATUS_AND_PLLR_REG, pll_r << PLLR_SHIFT);
+       aic3x_write(codec, AIC3X_PLL_PROGB_REG, pll_j << PLLJ_SHIFT);
+       aic3x_write(codec, AIC3X_PLL_PROGC_REG, (pll_d >> 6) << PLLD_MSB_SHIFT);
+       aic3x_write(codec, AIC3X_PLL_PROGD_REG,
+                   (pll_d & 0x3F) << PLLD_LSB_SHIFT);
+
+       /* select data word length */
+       data =
+           aic3x_read_reg_cache(codec, AIC3X_ASD_INTF_CTRLB) & (~(0x3 << 4));
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               break;
+       case SNDRV_PCM_FORMAT_S20_3LE:
+               data |= (0x01 << 4);
+               break;
+       case SNDRV_PCM_FORMAT_S24_LE:
+               data |= (0x02 << 4);
+               break;
+       case SNDRV_PCM_FORMAT_S32_LE:
+               data |= (0x03 << 4);
+               break;
+       }
+       aic3x_write(codec, AIC3X_ASD_INTF_CTRLB, data);
+
+       return 0;
+}
+
+static int aic3x_mute(struct snd_soc_codec_dai *dai, int mute)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       u8 ldac_reg = aic3x_read_reg_cache(codec, LDAC_VOL) & ~MUTE_ON;
+       u8 rdac_reg = aic3x_read_reg_cache(codec, RDAC_VOL) & ~MUTE_ON;
+
+       if (mute) {
+               aic3x_write(codec, LDAC_VOL, ldac_reg | MUTE_ON);
+               aic3x_write(codec, RDAC_VOL, rdac_reg | MUTE_ON);
+       } else {
+               aic3x_write(codec, LDAC_VOL, ldac_reg);
+               aic3x_write(codec, RDAC_VOL, rdac_reg);
+       }
+
+       return 0;
+}
+
+static int aic3x_set_dai_sysclk(struct snd_soc_codec_dai *codec_dai,
+                               int clk_id, unsigned int freq, int dir)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       struct aic3x_priv *aic3x = codec->private_data;
+
+       switch (freq) {
+       case 22579200:
+       case 33868800:
+               aic3x->sysclk = freq;
+               return 0;
+       }
+
+       return -EINVAL;
+}
+
+static int aic3x_set_dai_fmt(struct snd_soc_codec_dai *codec_dai,
+                            unsigned int fmt)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       struct aic3x_priv *aic3x = codec->private_data;
+       u8 iface_areg = 0;
+       u8 iface_breg = 0;
+
+       /* set master/slave audio interface */
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBM_CFM:
+               aic3x->master = 1;
+               iface_areg |= BIT_CLK_MASTER | WORD_CLK_MASTER;
+               break;
+       case SND_SOC_DAIFMT_CBS_CFS:
+               aic3x->master = 0;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* interface format */
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               break;
+       case SND_SOC_DAIFMT_DSP_A:
+               iface_breg |= (0x01 << 6);
+               break;
+       case SND_SOC_DAIFMT_RIGHT_J:
+               iface_breg |= (0x02 << 6);
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               iface_breg |= (0x03 << 6);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* set iface */
+       aic3x_write(codec, AIC3X_ASD_INTF_CTRLA, iface_areg);
+       aic3x_write(codec, AIC3X_ASD_INTF_CTRLB, iface_breg);
+
+       return 0;
+}
+
+static int aic3x_dapm_event(struct snd_soc_codec *codec, int event)
+{
+       struct aic3x_priv *aic3x = codec->private_data;
+       u8 reg;
+
+       switch (event) {
+       case SNDRV_CTL_POWER_D0:
+               /* all power is driven by DAPM system */
+               if (aic3x->master) {
+                       /* enable pll */
+                       reg = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG);
+                       aic3x_write(codec, AIC3X_PLL_PROGA_REG,
+                                   reg | PLL_ENABLE);
+               }
+               break;
+       case SNDRV_CTL_POWER_D1:
+       case SNDRV_CTL_POWER_D2:
+               break;
+       case SNDRV_CTL_POWER_D3hot:
+               /*
+                * all power is driven by DAPM system,
+                * so output power is safe if bypass was set
+                */
+               if (aic3x->master) {
+                       /* disable pll */
+                       reg = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG);
+                       aic3x_write(codec, AIC3X_PLL_PROGA_REG,
+                                   reg & ~PLL_ENABLE);
+               }
+               break;
+       case SNDRV_CTL_POWER_D3cold:
+               /* force all power off */
+               reg = aic3x_read_reg_cache(codec, LINE1L_2_LADC_CTRL);
+               aic3x_write(codec, LINE1L_2_LADC_CTRL, reg & ~LADC_PWR_ON);
+               reg = aic3x_read_reg_cache(codec, LINE1R_2_RADC_CTRL);
+               aic3x_write(codec, LINE1R_2_RADC_CTRL, reg & ~RADC_PWR_ON);
+
+               reg = aic3x_read_reg_cache(codec, DAC_PWR);
+               aic3x_write(codec, DAC_PWR, reg & ~(LDAC_PWR_ON | RDAC_PWR_ON));
+
+               reg = aic3x_read_reg_cache(codec, HPLOUT_CTRL);
+               aic3x_write(codec, HPLOUT_CTRL, reg & ~HPLOUT_PWR_ON);
+               reg = aic3x_read_reg_cache(codec, HPROUT_CTRL);
+               aic3x_write(codec, HPROUT_CTRL, reg & ~HPROUT_PWR_ON);
+
+               reg = aic3x_read_reg_cache(codec, HPLCOM_CTRL);
+               aic3x_write(codec, HPLCOM_CTRL, reg & ~HPLCOM_PWR_ON);
+               reg = aic3x_read_reg_cache(codec, HPRCOM_CTRL);
+               aic3x_write(codec, HPRCOM_CTRL, reg & ~HPRCOM_PWR_ON);
+
+               reg = aic3x_read_reg_cache(codec, MONOLOPM_CTRL);
+               aic3x_write(codec, MONOLOPM_CTRL, reg & ~MONOLOPM_PWR_ON);
+
+               reg = aic3x_read_reg_cache(codec, LLOPM_CTRL);
+               aic3x_write(codec, LLOPM_CTRL, reg & ~LLOPM_PWR_ON);
+               reg = aic3x_read_reg_cache(codec, RLOPM_CTRL);
+               aic3x_write(codec, RLOPM_CTRL, reg & ~RLOPM_PWR_ON);
+
+               if (aic3x->master) {
+                       /* disable pll */
+                       reg = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG);
+                       aic3x_write(codec, AIC3X_PLL_PROGA_REG,
+                                   reg & ~PLL_ENABLE);
+               }
+               break;
+       }
+       codec->dapm_state = event;
+
+       return 0;
+}
+
+#define AIC3X_RATES    SNDRV_PCM_RATE_8000_96000
+#define AIC3X_FORMATS  (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+                        SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+struct snd_soc_codec_dai aic3x_dai = {
+       .name = "aic3x",
+       .playback = {
+               .stream_name = "Playback",
+               .channels_min = 1,
+               .channels_max = 2,
+               .rates = AIC3X_RATES,
+               .formats = AIC3X_FORMATS,},
+       .capture = {
+               .stream_name = "Capture",
+               .channels_min = 1,
+               .channels_max = 2,
+               .rates = AIC3X_RATES,
+               .formats = AIC3X_FORMATS,},
+       .ops = {
+               .hw_params = aic3x_hw_params,
+       },
+       .dai_ops = {
+               .digital_mute = aic3x_mute,
+               .set_sysclk = aic3x_set_dai_sysclk,
+               .set_fmt = aic3x_set_dai_fmt,
+       }
+};
+EXPORT_SYMBOL_GPL(aic3x_dai);
+
+static int aic3x_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec = socdev->codec;
+
+       aic3x_dapm_event(codec, SNDRV_CTL_POWER_D3cold);
+
+       return 0;
+}
+
+static int aic3x_resume(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec = socdev->codec;
+       int i;
+       u8 data[2];
+       u8 *cache = codec->reg_cache;
+
+       /* Sync reg_cache with the hardware */
+       for (i = 0; i < ARRAY_SIZE(aic3x_reg); i++) {
+               data[0] = i;
+               data[1] = cache[i];
+               codec->hw_write(codec->control_data, data, 2);
+       }
+
+       aic3x_dapm_event(codec, codec->suspend_dapm_state);
+
+       return 0;
+}
+
+/*
+ * initialise the AIC3X driver
+ * register the mixer and dsp interfaces with the kernel
+ */
+static int aic3x_init(struct snd_soc_device *socdev)
+{
+       struct snd_soc_codec *codec = socdev->codec;
+       int reg, ret = 0;
+
+       codec->name = "aic3x";
+       codec->owner = THIS_MODULE;
+       codec->read = aic3x_read_reg_cache;
+       codec->write = aic3x_write;
+       codec->dapm_event = aic3x_dapm_event;
+       codec->dai = &aic3x_dai;
+       codec->num_dai = 1;
+       codec->reg_cache_size = sizeof(aic3x_reg);
+       codec->reg_cache = kmemdup(aic3x_reg, sizeof(aic3x_reg), GFP_KERNEL);
+       if (codec->reg_cache == NULL)
+               return -ENOMEM;
+
+       aic3x_write(codec, AIC3X_PAGE_SELECT, PAGE0_SELECT);
+       aic3x_write(codec, AIC3X_RESET, SOFT_RESET);
+
+       /* register pcms */
+       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+       if (ret < 0) {
+               printk(KERN_ERR "aic3x: failed to create pcms\n");
+               goto pcm_err;
+       }
+
+       /* DAC default volume and mute */
+       aic3x_write(codec, LDAC_VOL, DEFAULT_VOL | MUTE_ON);
+       aic3x_write(codec, RDAC_VOL, DEFAULT_VOL | MUTE_ON);
+
+       /* DAC to HP default volume and route to Output mixer */
+       aic3x_write(codec, DACL1_2_HPLOUT_VOL, DEFAULT_VOL | ROUTE_ON);
+       aic3x_write(codec, DACR1_2_HPROUT_VOL, DEFAULT_VOL | ROUTE_ON);
+       aic3x_write(codec, DACL1_2_HPLCOM_VOL, DEFAULT_VOL | ROUTE_ON);
+       aic3x_write(codec, DACR1_2_HPRCOM_VOL, DEFAULT_VOL | ROUTE_ON);
+       /* DAC to Line Out default volume and route to Output mixer */
+       aic3x_write(codec, DACL1_2_LLOPM_VOL, DEFAULT_VOL | ROUTE_ON);
+       aic3x_write(codec, DACR1_2_RLOPM_VOL, DEFAULT_VOL | ROUTE_ON);
+       /* DAC to Mono Line Out default volume and route to Output mixer */
+       aic3x_write(codec, DACL1_2_MONOLOPM_VOL, DEFAULT_VOL | ROUTE_ON);
+       aic3x_write(codec, DACR1_2_MONOLOPM_VOL, DEFAULT_VOL | ROUTE_ON);
+
+       /* unmute all outputs */
+       reg = aic3x_read_reg_cache(codec, LLOPM_CTRL);
+       aic3x_write(codec, LLOPM_CTRL, reg | UNMUTE);
+       reg = aic3x_read_reg_cache(codec, RLOPM_CTRL);
+       aic3x_write(codec, RLOPM_CTRL, reg | UNMUTE);
+       reg = aic3x_read_reg_cache(codec, MONOLOPM_CTRL);
+       aic3x_write(codec, MONOLOPM_CTRL, reg | UNMUTE);
+       reg = aic3x_read_reg_cache(codec, HPLOUT_CTRL);
+       aic3x_write(codec, HPLOUT_CTRL, reg | UNMUTE);
+       reg = aic3x_read_reg_cache(codec, HPROUT_CTRL);
+       aic3x_write(codec, HPROUT_CTRL, reg | UNMUTE);
+       reg = aic3x_read_reg_cache(codec, HPLCOM_CTRL);
+       aic3x_write(codec, HPLCOM_CTRL, reg | UNMUTE);
+       reg = aic3x_read_reg_cache(codec, HPRCOM_CTRL);
+       aic3x_write(codec, HPRCOM_CTRL, reg | UNMUTE);
+
+       /* ADC default volume and unmute */
+       aic3x_write(codec, LADC_VOL, DEFAULT_GAIN);
+       aic3x_write(codec, RADC_VOL, DEFAULT_GAIN);
+       /* By default route Line1 to ADC PGA mixer */
+       aic3x_write(codec, LINE1L_2_LADC_CTRL, 0x0);
+       aic3x_write(codec, LINE1R_2_RADC_CTRL, 0x0);
+
+       /* PGA to HP Bypass default volume, disconnect from Output Mixer */
+       aic3x_write(codec, PGAL_2_HPLOUT_VOL, DEFAULT_VOL);
+       aic3x_write(codec, PGAR_2_HPROUT_VOL, DEFAULT_VOL);
+       aic3x_write(codec, PGAL_2_HPLCOM_VOL, DEFAULT_VOL);
+       aic3x_write(codec, PGAR_2_HPRCOM_VOL, DEFAULT_VOL);
+       /* PGA to Line Out default volume, disconnect from Output Mixer */
+       aic3x_write(codec, PGAL_2_LLOPM_VOL, DEFAULT_VOL);
+       aic3x_write(codec, PGAR_2_RLOPM_VOL, DEFAULT_VOL);
+       /* PGA to Mono Line Out default volume, disconnect from Output Mixer */
+       aic3x_write(codec, PGAL_2_MONOLOPM_VOL, DEFAULT_VOL);
+       aic3x_write(codec, PGAR_2_MONOLOPM_VOL, DEFAULT_VOL);
+
+       /* Line2 to HP Bypass default volume, disconnect from Output Mixer */
+       aic3x_write(codec, LINE2L_2_HPLOUT_VOL, DEFAULT_VOL);
+       aic3x_write(codec, LINE2R_2_HPROUT_VOL, DEFAULT_VOL);
+       aic3x_write(codec, LINE2L_2_HPLCOM_VOL, DEFAULT_VOL);
+       aic3x_write(codec, LINE2R_2_HPRCOM_VOL, DEFAULT_VOL);
+       /* Line2 Line Out default volume, disconnect from Output Mixer */
+       aic3x_write(codec, LINE2L_2_LLOPM_VOL, DEFAULT_VOL);
+       aic3x_write(codec, LINE2R_2_RLOPM_VOL, DEFAULT_VOL);
+       /* Line2 to Mono Out default volume, disconnect from Output Mixer */
+       aic3x_write(codec, LINE2L_2_MONOLOPM_VOL, DEFAULT_VOL);
+       aic3x_write(codec, LINE2R_2_MONOLOPM_VOL, DEFAULT_VOL);
+
+       /* off, with power on */
+       aic3x_dapm_event(codec, SNDRV_CTL_POWER_D3hot);
+
+       aic3x_add_controls(codec);
+       aic3x_add_widgets(codec);
+       ret = snd_soc_register_card(socdev);
+       if (ret < 0) {
+               printk(KERN_ERR "aic3x: failed to register card\n");
+               goto card_err;
+       }
+
+       return ret;
+
+card_err:
+       snd_soc_free_pcms(socdev);
+       snd_soc_dapm_free(socdev);
+pcm_err:
+       kfree(codec->reg_cache);
+       return ret;
+}
+
+static struct snd_soc_device *aic3x_socdev;
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+/*
+ * AIC3X 2 wire address can be up to 4 devices with device addresses
+ * 0x18, 0x19, 0x1A, 0x1B
+ */
+static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END };
+
+/* Magic definition of all other variables and things */
+I2C_CLIENT_INSMOD;
+
+static struct i2c_driver aic3x_i2c_driver;
+static struct i2c_client client_template;
+
+/*
+ * If the i2c layer weren't so broken, we could pass this kind of data
+ * around
+ */
+static int aic3x_codec_probe(struct i2c_adapter *adap, int addr, int kind)
+{
+       struct snd_soc_device *socdev = aic3x_socdev;
+       struct aic3x_setup_data *setup = socdev->codec_data;
+       struct snd_soc_codec *codec = socdev->codec;
+       struct i2c_client *i2c;
+       int ret;
+
+       if (addr != setup->i2c_address)
+               return -ENODEV;
+
+       client_template.adapter = adap;
+       client_template.addr = addr;
+
+       i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL);
+       if (i2c == NULL) {
+               kfree(codec);
+               return -ENOMEM;
+       }
+       i2c_set_clientdata(i2c, codec);
+       codec->control_data = i2c;
+
+       ret = i2c_attach_client(i2c);
+       if (ret < 0) {
+               printk(KERN_ERR "aic3x: failed to attach codec at addr %x\n",
+                      addr);
+               goto err;
+       }
+
+       ret = aic3x_init(socdev);
+       if (ret < 0) {
+               printk(KERN_ERR "aic3x: failed to initialise AIC3X\n");
+               goto err;
+       }
+       return ret;
+
+err:
+       kfree(codec);
+       kfree(i2c);
+       return ret;
+}
+
+static int aic3x_i2c_detach(struct i2c_client *client)
+{
+       struct snd_soc_codec *codec = i2c_get_clientdata(client);
+       i2c_detach_client(client);
+       kfree(codec->reg_cache);
+       kfree(client);
+       return 0;
+}
+
+static int aic3x_i2c_attach(struct i2c_adapter *adap)
+{
+       return i2c_probe(adap, &addr_data, aic3x_codec_probe);
+}
+
+/* machine i2c codec control layer */
+static struct i2c_driver aic3x_i2c_driver = {
+       .driver = {
+               .name = "aic3x I2C Codec",
+               .owner = THIS_MODULE,
+       },
+       .id = I2C_DRIVERID_I2CDEV,
+       .attach_adapter = aic3x_i2c_attach,
+       .detach_client = aic3x_i2c_detach,
+       .command = NULL,
+};
+
+static struct i2c_client client_template = {
+       .name = "AIC3X",
+       .driver = &aic3x_i2c_driver,
+};
+#endif
+
+static int aic3x_probe(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct aic3x_setup_data *setup;
+       struct snd_soc_codec *codec;
+       struct aic3x_priv *aic3x;
+       int ret = 0;
+
+       printk(KERN_INFO "AIC3X Audio Codec %s\n", AIC3X_VERSION);
+
+       setup = socdev->codec_data;
+       codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
+       if (codec == NULL)
+               return -ENOMEM;
+
+       aic3x = kzalloc(sizeof(struct aic3x_priv), GFP_KERNEL);
+       if (aic3x == NULL) {
+               kfree(codec);
+               return -ENOMEM;
+       }
+
+       codec->private_data = aic3x;
+       socdev->codec = codec;
+       mutex_init(&codec->mutex);
+       INIT_LIST_HEAD(&codec->dapm_widgets);
+       INIT_LIST_HEAD(&codec->dapm_paths);
+
+       aic3x_socdev = socdev;
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       if (setup->i2c_address) {
+               normal_i2c[0] = setup->i2c_address;
+               codec->hw_write = (hw_write_t) i2c_master_send;
+               ret = i2c_add_driver(&aic3x_i2c_driver);
+               if (ret != 0)
+                       printk(KERN_ERR "can't add i2c driver");
+       }
+#else
+       /* Add other interfaces here */
+#endif
+       return ret;
+}
+
+static int aic3x_remove(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec = socdev->codec;
+
+       /* power down chip */
+       if (codec->control_data)
+               aic3x_dapm_event(codec, SNDRV_CTL_POWER_D3);
+
+       snd_soc_free_pcms(socdev);
+       snd_soc_dapm_free(socdev);
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       i2c_del_driver(&aic3x_i2c_driver);
+#endif
+       kfree(codec->private_data);
+       kfree(codec);
+
+       return 0;
+}
+
+struct snd_soc_codec_device soc_codec_dev_aic3x = {
+       .probe = aic3x_probe,
+       .remove = aic3x_remove,
+       .suspend = aic3x_suspend,
+       .resume = aic3x_resume,
+};
+EXPORT_SYMBOL_GPL(soc_codec_dev_aic3x);
+
+MODULE_DESCRIPTION("ASoC TLV320AIC3X codec driver");
+MODULE_AUTHOR("Vladimir Barinov");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/tlv320aic3x.h b/sound/soc/codecs/tlv320aic3x.h
new file mode 100644 (file)
index 0000000..d0cdeeb
--- /dev/null
@@ -0,0 +1,181 @@
+/*
+ * ALSA SoC TLV320AIC3X codec driver
+ *
+ * Author:      Vladimir Barinov, <vbarinov@ru.mvista.com>
+ * Copyright:   (C) 2007 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 version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _AIC3X_H
+#define _AIC3X_H
+
+/* AIC3X register space */
+#define AIC3X_CACHEREGNUM              103
+
+/* Page select register */
+#define AIC3X_PAGE_SELECT              0
+/* Software reset register */
+#define AIC3X_RESET                    1
+/* Codec Sample rate select register */
+#define AIC3X_SAMPLE_RATE_SEL_REG      2
+/* PLL progrramming register A */
+#define AIC3X_PLL_PROGA_REG            3
+/* PLL progrramming register B */
+#define AIC3X_PLL_PROGB_REG            4
+/* PLL progrramming register C */
+#define AIC3X_PLL_PROGC_REG            5
+/* PLL progrramming register D */
+#define AIC3X_PLL_PROGD_REG            6
+/* Codec datapath setup register */
+#define AIC3X_CODEC_DATAPATH_REG       7
+/* Audio serial data interface control register A */
+#define AIC3X_ASD_INTF_CTRLA           8
+/* Audio serial data interface control register B */
+#define AIC3X_ASD_INTF_CTRLB           9
+/* Audio overflow status and PLL R value programming register */
+#define AIC3X_OVRF_STATUS_AND_PLLR_REG 11
+
+/* ADC PGA Gain control registers */
+#define LADC_VOL                       15
+#define RADC_VOL                       16
+/* MIC3 control registers */
+#define MIC3LR_2_LADC_CTRL             17
+#define MIC3LR_2_RADC_CTRL             18
+/* Line1 Input control registers */
+#define LINE1L_2_LADC_CTRL             19
+#define LINE1R_2_RADC_CTRL             22
+/* Line2 Input control registers */
+#define LINE2L_2_LADC_CTRL             20
+#define LINE2R_2_RADC_CTRL             23
+/* MICBIAS Control Register */
+#define MICBIAS_CTRL                   25
+
+/* AGC Control Registers A, B, C */
+#define LAGC_CTRL_A                    26
+#define LAGC_CTRL_B                    27
+#define LAGC_CTRL_C                    28
+#define RAGC_CTRL_A                    29
+#define RAGC_CTRL_B                    30
+#define RAGC_CTRL_C                    31
+
+/* DAC Power and Left High Power Output control registers */
+#define DAC_PWR                                37
+#define HPLCOM_CFG                     37
+/* Right High Power Output control registers */
+#define HPRCOM_CFG                     38
+/* DAC Output Switching control registers */
+#define DAC_LINE_MUX                   41
+/* High Power Output Driver Pop Reduction registers */
+#define HPOUT_POP_REDUCTION            42
+/* DAC Digital control registers */
+#define LDAC_VOL                       43
+#define RDAC_VOL                       44
+/* High Power Output control registers */
+#define LINE2L_2_HPLOUT_VOL            45
+#define LINE2R_2_HPROUT_VOL            62
+#define PGAL_2_HPLOUT_VOL              46
+#define PGAR_2_HPROUT_VOL              63
+#define DACL1_2_HPLOUT_VOL             47
+#define DACR1_2_HPROUT_VOL             64
+#define HPLOUT_CTRL                    51
+#define HPROUT_CTRL                    65
+/* High Power COM control registers */
+#define LINE2L_2_HPLCOM_VOL            52
+#define LINE2R_2_HPRCOM_VOL            69
+#define PGAL_2_HPLCOM_VOL              53
+#define PGAR_2_HPRCOM_VOL              70
+#define DACL1_2_HPLCOM_VOL             54
+#define DACR1_2_HPRCOM_VOL             71
+#define HPLCOM_CTRL                    58
+#define HPRCOM_CTRL                    72
+/* Mono Line Output Plus/Minus control registers */
+#define LINE2L_2_MONOLOPM_VOL          73
+#define LINE2R_2_MONOLOPM_VOL          76
+#define PGAL_2_MONOLOPM_VOL            74
+#define PGAR_2_MONOLOPM_VOL            77
+#define DACL1_2_MONOLOPM_VOL           75
+#define DACR1_2_MONOLOPM_VOL           78
+#define MONOLOPM_CTRL                  79
+/* Line Output Plus/Minus control registers */
+#define LINE2L_2_LLOPM_VOL             80
+#define LINE2R_2_RLOPM_VOL             90
+#define PGAL_2_LLOPM_VOL               81
+#define PGAR_2_RLOPM_VOL               91
+#define DACL1_2_LLOPM_VOL              82
+#define DACR1_2_RLOPM_VOL              92
+#define LLOPM_CTRL                     86
+#define RLOPM_CTRL                     93
+/* Clock generation control register */
+#define AIC3X_CLKGEN_CTRL_REG          102
+
+/* Page select register bits */
+#define PAGE0_SELECT           0
+#define PAGE1_SELECT           1
+
+/* Audio serial data interface control register A bits */
+#define BIT_CLK_MASTER          0x80
+#define WORD_CLK_MASTER         0x40
+
+/* Codec Datapath setup register 7 */
+#define FSREF_44100            (1 << 7)
+#define FSREF_48000            (0 << 7)
+#define DUAL_RATE_MODE         ((1 << 5) | (1 << 6))
+#define LDAC2LCH               (0x1 << 3)
+#define RDAC2RCH               (0x1 << 1)
+
+/* PLL registers bitfields */
+#define PLLP_SHIFT             0
+#define PLLR_SHIFT             0
+#define PLLJ_SHIFT             2
+#define PLLD_MSB_SHIFT         0
+#define PLLD_LSB_SHIFT         2
+
+/* Clock generation register bits */
+#define PLL_CLKIN_SHIFT                4
+#define MCLK_SOURCE            0x0
+#define PLL_CLKDIV_SHIFT       0
+
+/* Software reset register bits */
+#define SOFT_RESET             0x80
+
+/* PLL progrramming register A bits */
+#define PLL_ENABLE             0x80
+
+/* Route bits */
+#define ROUTE_ON               0x80
+
+/* Mute bits */
+#define UNMUTE                 0x08
+#define MUTE_ON                        0x80
+
+/* Power bits */
+#define LADC_PWR_ON            0x04
+#define RADC_PWR_ON            0x04
+#define LDAC_PWR_ON            0x80
+#define RDAC_PWR_ON            0x40
+#define HPLOUT_PWR_ON          0x01
+#define HPROUT_PWR_ON          0x01
+#define HPLCOM_PWR_ON          0x01
+#define HPRCOM_PWR_ON          0x01
+#define MONOLOPM_PWR_ON                0x01
+#define LLOPM_PWR_ON           0x01
+#define RLOPM_PWR_ON   0x01
+
+#define INVERT_VOL(val)   (0x7f - val)
+
+/* Default output volume (inverted) */
+#define DEFAULT_VOL     INVERT_VOL(0x50)
+/* Default input volume */
+#define DEFAULT_GAIN    0x20
+
+struct aic3x_setup_data {
+       unsigned short i2c_address;
+};
+
+extern struct snd_soc_codec_dai aic3x_dai;
+extern struct snd_soc_codec_device soc_codec_dev_aic3x;
+
+#endif /* _AIC3X_H */
index 7ca0b5268289e9e6260bf620f814dc24c2718368..9c33fe874928ec2ae746d112334a622e20d7dc14 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/pm.h>
 #include <linux/i2c.h>
 #include <linux/platform_device.h>
-#include <sound/driver.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
@@ -562,13 +561,13 @@ static int wm8731_init(struct snd_soc_device *socdev)
 
        /* set the update bits */
        reg = wm8731_read_reg_cache(codec, WM8731_LOUT1V);
-       wm8731_write(codec, WM8731_LOUT1V, reg 0x0100);
+       wm8731_write(codec, WM8731_LOUT1V, reg & ~0x0100);
        reg = wm8731_read_reg_cache(codec, WM8731_ROUT1V);
-       wm8731_write(codec, WM8731_ROUT1V, reg 0x0100);
+       wm8731_write(codec, WM8731_ROUT1V, reg & ~0x0100);
        reg = wm8731_read_reg_cache(codec, WM8731_LINVOL);
-       wm8731_write(codec, WM8731_LINVOL, reg 0x0100);
+       wm8731_write(codec, WM8731_LINVOL, reg & ~0x0100);
        reg = wm8731_read_reg_cache(codec, WM8731_RINVOL);
-       wm8731_write(codec, WM8731_RINVOL, reg 0x0100);
+       wm8731_write(codec, WM8731_RINVOL, reg & ~0x0100);
 
        wm8731_add_controls(codec);
        wm8731_add_widgets(codec);
index 28684eeda73845dd4a68745860f19c8631a465cf..77a857b997a2288e28ca2bc993a446057112dbff 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/pm.h>
 #include <linux/i2c.h>
 #include <linux/platform_device.h>
-#include <sound/driver.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
@@ -189,7 +188,7 @@ SOC_ENUM("Bass Boost", wm8750_enum[0]),
 SOC_ENUM("Bass Filter", wm8750_enum[1]),
 SOC_SINGLE("Bass Volume", WM8750_BASS, 0, 15, 1),
 
-SOC_SINGLE("Treble Volume", WM8750_TREBLE, 0, 15, 0),
+SOC_SINGLE("Treble Volume", WM8750_TREBLE, 0, 15, 1),
 SOC_ENUM("Treble Cut-off", wm8750_enum[2]),
 
 SOC_SINGLE("3D Switch", WM8750_3D, 0, 1, 0),
index efced934566d73bc950c915d318b1025e6ccac33..ddd9c71b3fdec189b61a1cc31f872ef6223bee77 100644 (file)
 #include <linux/pm.h>
 #include <linux/i2c.h>
 #include <linux/platform_device.h>
-#include <sound/driver.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
 #include <sound/soc-dapm.h>
 #include <sound/initval.h>
+#include <sound/tlv.h>
 #include <asm/div64.h>
 
 #include "wm8753.h"
@@ -258,6 +258,8 @@ static int wm8753_set_dai(struct snd_kcontrol *kcontrol,
        return 1;
 }
 
+static const DECLARE_TLV_DB_LINEAR(rec_mix_tlv, -1500, 600);
+
 static const struct snd_kcontrol_new wm8753_snd_controls[] = {
 SOC_DOUBLE_R("PCM Volume", WM8753_LDAC, WM8753_RDAC, 0, 255, 0),
 
@@ -287,8 +289,8 @@ SOC_SINGLE("Bass Volume", WM8753_BASS, 0, 15, 1),
 SOC_SINGLE("Treble Volume", WM8753_TREBLE, 0, 15, 1),
 SOC_ENUM("Treble Cut-off", wm8753_enum[2]),
 
-SOC_DOUBLE("Sidetone Capture Volume", WM8753_RECMIX1, 0, 4, 7, 1),
-SOC_SINGLE("Voice Sidetone Capture Volume", WM8753_RECMIX2, 0, 7, 1),
+SOC_DOUBLE_TLV("Sidetone Capture Volume", WM8753_RECMIX1, 0, 4, 7, 1, rec_mix_tlv),
+SOC_SINGLE_TLV("Voice Sidetone Capture Volume", WM8753_RECMIX2, 0, 7, 1, rec_mix_tlv),
 
 SOC_DOUBLE_R("Capture Volume", WM8753_LINVOL, WM8753_RINVOL, 0, 63, 0),
 SOC_DOUBLE_R("Capture ZC Switch", WM8753_LINVOL, WM8753_RINVOL, 6, 1, 0),
index 986b5d59cefaccd618a4f44d51266c832fb131c6..590baea3c4c3d9d3a2666025615b27f3c506545c 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/version.h>
 #include <linux/kernel.h>
 #include <linux/device.h>
-#include <sound/driver.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/ac97_codec.h>
@@ -102,7 +101,8 @@ SOC_SINGLE("Speaker Playback ZC Switch", AC97_MASTER, 7, 1, 0),
 SOC_SINGLE("Speaker Playback Invert Switch", AC97_MASTER, 6, 1, 0),
 SOC_SINGLE("Headphone Playback ZC Switch", AC97_HEADPHONE, 7, 1, 0),
 SOC_SINGLE("Mono Playback ZC Switch", AC97_MASTER_MONO, 7, 1, 0),
-SOC_SINGLE("Mono Playback Volume", AC97_MASTER_MONO, 0, 31, 0),
+SOC_SINGLE("Mono Playback Volume", AC97_MASTER_MONO, 0, 31, 1),
+SOC_SINGLE("Mono Playback Switch", AC97_MASTER_MONO, 15, 1, 1),
 
 SOC_SINGLE("ALC Target Volume", AC97_CODEC_CLASS_REV, 12, 15, 0),
 SOC_SINGLE("ALC Hold Time", AC97_CODEC_CLASS_REV, 8, 15, 0),
@@ -131,7 +131,7 @@ SOC_SINGLE("Aux Playback Headphone Volume", AC97_CD, 12, 7, 1),
 SOC_SINGLE("Aux Playback Speaker Volume", AC97_CD, 8, 7, 1),
 SOC_SINGLE("Aux Playback Phone Volume", AC97_CD, 4, 7, 1),
 
-SOC_SINGLE("Phone Volume", AC97_PHONE, 0, 15, 0),
+SOC_SINGLE("Phone Volume", AC97_PHONE, 0, 15, 1),
 SOC_DOUBLE("Line Capture Volume", AC97_LINE, 8, 0, 31, 1),
 
 SOC_SINGLE("Capture 20dB Boost Switch", AC97_REC_SEL, 14, 1, 0),
@@ -145,8 +145,8 @@ SOC_ENUM("Bass Control", wm9712_enum[5]),
 SOC_SINGLE("Bass Cut-off Switch", AC97_MASTER_TONE, 12, 1, 1),
 SOC_SINGLE("Tone Cut-off Switch", AC97_MASTER_TONE, 4, 1, 1),
 SOC_SINGLE("Playback Attenuate (-6dB) Switch", AC97_MASTER_TONE, 6, 1, 0),
-SOC_SINGLE("Bass Volume", AC97_MASTER_TONE, 8, 15, 0),
-SOC_SINGLE("Treble Volume", AC97_MASTER_TONE, 0, 15, 0),
+SOC_SINGLE("Bass Volume", AC97_MASTER_TONE, 8, 15, 1),
+SOC_SINGLE("Treble Volume", AC97_MASTER_TONE, 0, 15, 1),
 
 SOC_SINGLE("Capture ADC Switch", AC97_REC_GAIN, 15, 1, 1),
 SOC_ENUM("Capture Volume Steps", wm9712_enum[6]),
diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig
new file mode 100644 (file)
index 0000000..257101f
--- /dev/null
@@ -0,0 +1,20 @@
+menu "ALSA SoC audio for Freescale SOCs"
+
+config SND_SOC_MPC8610
+       bool "ALSA SoC support for the MPC8610 SOC"
+       depends on SND_SOC && MPC8610_HPCD
+       default y if MPC8610
+       help
+         Say Y if you want to add support for codecs attached to the SSI
+          device on an MPC8610.
+
+config SND_SOC_MPC8610_HPCD
+       bool "ALSA SoC support for the Freescale MPC8610 HPCD board"
+       depends on SND_SOC_MPC8610
+       select SND_SOC_CS4270
+       select SND_SOC_CS4270_VD33_ERRATA
+       default y if MPC8610_HPCD
+       help
+         Say Y if you want to enable audio on the Freescale MPC8610 HPCD.
+
+endmenu
diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile
new file mode 100644 (file)
index 0000000..62f680a
--- /dev/null
@@ -0,0 +1,6 @@
+# MPC8610 HPCD Machine Support
+obj-$(CONFIG_SND_SOC_MPC8610_HPCD) += mpc8610_hpcd.o
+
+# MPC8610 Platform Support
+obj-$(CONFIG_SND_SOC_MPC8610) += fsl_ssi.o fsl_dma.o
+
diff --git a/sound/soc/fsl/fsl_dma.c b/sound/soc/fsl/fsl_dma.c
new file mode 100644 (file)
index 0000000..652514f
--- /dev/null
@@ -0,0 +1,841 @@
+/*
+ * Freescale DMA ALSA SoC PCM driver
+ *
+ * Author: Timur Tabi <timur@freescale.com>
+ *
+ * Copyright 2007-2008 Freescale Semiconductor, Inc.  This file is licensed
+ * under the terms of the GNU General Public License version 2.  This
+ * program is licensed "as is" without any warranty of any kind, whether
+ * express or implied.
+ *
+ * This driver implements ASoC support for the Elo DMA controller, which is
+ * the DMA controller on Freescale 83xx, 85xx, and 86xx SOCs. In ALSA terms,
+ * the PCM driver is what handles the DMA buffer.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include <asm/io.h>
+
+#include "fsl_dma.h"
+
+/*
+ * The formats that the DMA controller supports, which is anything
+ * that is 8, 16, or 32 bits.
+ */
+#define FSLDMA_PCM_FORMATS (SNDRV_PCM_FMTBIT_S8        | \
+                           SNDRV_PCM_FMTBIT_U8         | \
+                           SNDRV_PCM_FMTBIT_S16_LE     | \
+                           SNDRV_PCM_FMTBIT_S16_BE     | \
+                           SNDRV_PCM_FMTBIT_U16_LE     | \
+                           SNDRV_PCM_FMTBIT_U16_BE     | \
+                           SNDRV_PCM_FMTBIT_S24_LE     | \
+                           SNDRV_PCM_FMTBIT_S24_BE     | \
+                           SNDRV_PCM_FMTBIT_U24_LE     | \
+                           SNDRV_PCM_FMTBIT_U24_BE     | \
+                           SNDRV_PCM_FMTBIT_S32_LE     | \
+                           SNDRV_PCM_FMTBIT_S32_BE     | \
+                           SNDRV_PCM_FMTBIT_U32_LE     | \
+                           SNDRV_PCM_FMTBIT_U32_BE)
+
+#define FSLDMA_PCM_RATES (SNDRV_PCM_RATE_5512 | SNDRV_PCM_RATE_8000_192000 | \
+                         SNDRV_PCM_RATE_CONTINUOUS)
+
+/* DMA global data.  This structure is used by fsl_dma_open() to determine
+ * which DMA channels to assign to a substream.  Unfortunately, ASoC V1 does
+ * not allow the machine driver to provide this information to the PCM
+ * driver in advance, and there's no way to differentiate between the two
+ * DMA controllers.  So for now, this driver only supports one SSI device
+ * using two DMA channels.  We cannot support multiple DMA devices.
+ *
+ * ssi_stx_phys: bus address of SSI STX register
+ * ssi_srx_phys: bus address of SSI SRX register
+ * dma_channel: pointer to the DMA channel's registers
+ * irq: IRQ for this DMA channel
+ * assigned: set to 1 if that DMA channel is assigned to a substream
+ */
+static struct {
+       dma_addr_t ssi_stx_phys;
+       dma_addr_t ssi_srx_phys;
+       struct ccsr_dma_channel __iomem *dma_channel[2];
+       unsigned int irq[2];
+       unsigned int assigned[2];
+} dma_global_data;
+
+/*
+ * The number of DMA links to use.  Two is the bare minimum, but if you
+ * have really small links you might need more.
+ */
+#define NUM_DMA_LINKS   2
+
+/** fsl_dma_private: p-substream DMA data
+ *
+ * Each substream has a 1-to-1 association with a DMA channel.
+ *
+ * The link[] array is first because it needs to be aligned on a 32-byte
+ * boundary, so putting it first will ensure alignment without padding the
+ * structure.
+ *
+ * @link[]: array of link descriptors
+ * @controller_id: which DMA controller (0, 1, ...)
+ * @channel_id: which DMA channel on the controller (0, 1, 2, ...)
+ * @dma_channel: pointer to the DMA channel's registers
+ * @irq: IRQ for this DMA channel
+ * @substream: pointer to the substream object, needed by the ISR
+ * @ssi_sxx_phys: bus address of the STX or SRX register to use
+ * @ld_buf_phys: physical address of the LD buffer
+ * @current_link: index into link[] of the link currently being processed
+ * @dma_buf_phys: physical address of the DMA buffer
+ * @dma_buf_next: physical address of the next period to process
+ * @dma_buf_end: physical address of the byte after the end of the DMA
+ * @buffer period_size: the size of a single period
+ * @num_periods: the number of periods in the DMA buffer
+ */
+struct fsl_dma_private {
+       struct fsl_dma_link_descriptor link[NUM_DMA_LINKS];
+       unsigned int controller_id;
+       unsigned int channel_id;
+       struct ccsr_dma_channel __iomem *dma_channel;
+       unsigned int irq;
+       struct snd_pcm_substream *substream;
+       dma_addr_t ssi_sxx_phys;
+       dma_addr_t ld_buf_phys;
+       unsigned int current_link;
+       dma_addr_t dma_buf_phys;
+       dma_addr_t dma_buf_next;
+       dma_addr_t dma_buf_end;
+       size_t period_size;
+       unsigned int num_periods;
+};
+
+/**
+ * fsl_dma_hardare: define characteristics of the PCM hardware.
+ *
+ * The PCM hardware is the Freescale DMA controller.  This structure defines
+ * the capabilities of that hardware.
+ *
+ * Since the sampling rate and data format are not controlled by the DMA
+ * controller, we specify no limits for those values.  The only exception is
+ * period_bytes_min, which is set to a reasonably low value to prevent the
+ * DMA controller from generating too many interrupts per second.
+ *
+ * Since each link descriptor has a 32-bit byte count field, we set
+ * period_bytes_max to the largest 32-bit number.  We also have no maximum
+ * number of periods.
+ */
+static const struct snd_pcm_hardware fsl_dma_hardware = {
+
+       .info                   = SNDRV_PCM_INFO_INTERLEAVED |
+                                 SNDRV_PCM_INFO_MMAP |
+                                 SNDRV_PCM_INFO_MMAP_VALID,
+       .formats                = FSLDMA_PCM_FORMATS,
+       .rates                  = FSLDMA_PCM_RATES,
+       .rate_min               = 5512,
+       .rate_max               = 192000,
+       .period_bytes_min       = 512,          /* A reasonable limit */
+       .period_bytes_max       = (u32) -1,
+       .periods_min            = NUM_DMA_LINKS,
+       .periods_max            = (unsigned int) -1,
+       .buffer_bytes_max       = 128 * 1024,   /* A reasonable limit */
+};
+
+/**
+ * fsl_dma_abort_stream: tell ALSA that the DMA transfer has aborted
+ *
+ * This function should be called by the ISR whenever the DMA controller
+ * halts data transfer.
+ */
+static void fsl_dma_abort_stream(struct snd_pcm_substream *substream)
+{
+       unsigned long flags;
+
+       snd_pcm_stream_lock_irqsave(substream, flags);
+
+       if (snd_pcm_running(substream))
+               snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
+
+       snd_pcm_stream_unlock_irqrestore(substream, flags);
+}
+
+/**
+ * fsl_dma_update_pointers - update LD pointers to point to the next period
+ *
+ * As each period is completed, this function changes the the link
+ * descriptor pointers for that period to point to the next period.
+ */
+static void fsl_dma_update_pointers(struct fsl_dma_private *dma_private)
+{
+       struct fsl_dma_link_descriptor *link =
+               &dma_private->link[dma_private->current_link];
+
+       /* Update our link descriptors to point to the next period */
+       if (dma_private->substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               link->source_addr =
+                       cpu_to_be32(dma_private->dma_buf_next);
+       else
+               link->dest_addr =
+                       cpu_to_be32(dma_private->dma_buf_next);
+
+       /* Update our variables for next time */
+       dma_private->dma_buf_next += dma_private->period_size;
+
+       if (dma_private->dma_buf_next >= dma_private->dma_buf_end)
+               dma_private->dma_buf_next = dma_private->dma_buf_phys;
+
+       if (++dma_private->current_link >= NUM_DMA_LINKS)
+               dma_private->current_link = 0;
+}
+
+/**
+ * fsl_dma_isr: interrupt handler for the DMA controller
+ *
+ * @irq: IRQ of the DMA channel
+ * @dev_id: pointer to the dma_private structure for this DMA channel
+ */
+static irqreturn_t fsl_dma_isr(int irq, void *dev_id)
+{
+       struct fsl_dma_private *dma_private = dev_id;
+       struct ccsr_dma_channel __iomem *dma_channel = dma_private->dma_channel;
+       irqreturn_t ret = IRQ_NONE;
+       u32 sr, sr2 = 0;
+
+       /* We got an interrupt, so read the status register to see what we
+          were interrupted for.
+        */
+       sr = in_be32(&dma_channel->sr);
+
+       if (sr & CCSR_DMA_SR_TE) {
+               dev_err(dma_private->substream->pcm->card->dev,
+                       "DMA transmit error (controller=%u channel=%u irq=%u\n",
+                       dma_private->controller_id,
+                       dma_private->channel_id, irq);
+               fsl_dma_abort_stream(dma_private->substream);
+               sr2 |= CCSR_DMA_SR_TE;
+               ret = IRQ_HANDLED;
+       }
+
+       if (sr & CCSR_DMA_SR_CH)
+               ret = IRQ_HANDLED;
+
+       if (sr & CCSR_DMA_SR_PE) {
+               dev_err(dma_private->substream->pcm->card->dev,
+                       "DMA%u programming error (channel=%u irq=%u)\n",
+                       dma_private->controller_id,
+                       dma_private->channel_id, irq);
+               fsl_dma_abort_stream(dma_private->substream);
+               sr2 |= CCSR_DMA_SR_PE;
+               ret = IRQ_HANDLED;
+       }
+
+       if (sr & CCSR_DMA_SR_EOLNI) {
+               sr2 |= CCSR_DMA_SR_EOLNI;
+               ret = IRQ_HANDLED;
+       }
+
+       if (sr & CCSR_DMA_SR_CB)
+               ret = IRQ_HANDLED;
+
+       if (sr & CCSR_DMA_SR_EOSI) {
+               struct snd_pcm_substream *substream = dma_private->substream;
+
+               /* Tell ALSA we completed a period. */
+               snd_pcm_period_elapsed(substream);
+
+               /*
+                * Update our link descriptors to point to the next period. We
+                * only need to do this if the number of periods is not equal to
+                * the number of links.
+                */
+               if (dma_private->num_periods != NUM_DMA_LINKS)
+                       fsl_dma_update_pointers(dma_private);
+
+               sr2 |= CCSR_DMA_SR_EOSI;
+               ret = IRQ_HANDLED;
+       }
+
+       if (sr & CCSR_DMA_SR_EOLSI) {
+               sr2 |= CCSR_DMA_SR_EOLSI;
+               ret = IRQ_HANDLED;
+       }
+
+       /* Clear the bits that we set */
+       if (sr2)
+               out_be32(&dma_channel->sr, sr2);
+
+       return ret;
+}
+
+/**
+ * fsl_dma_new: initialize this PCM driver.
+ *
+ * This function is called when the codec driver calls snd_soc_new_pcms(),
+ * once for each .dai_link in the machine driver's snd_soc_machine
+ * structure.
+ */
+static int fsl_dma_new(struct snd_card *card, struct snd_soc_codec_dai *dai,
+       struct snd_pcm *pcm)
+{
+       static u64 fsl_dma_dmamask = DMA_BIT_MASK(32);
+       int ret;
+
+       if (!card->dev->dma_mask)
+               card->dev->dma_mask = &fsl_dma_dmamask;
+
+       if (!card->dev->coherent_dma_mask)
+               card->dev->coherent_dma_mask = fsl_dma_dmamask;
+
+       ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, pcm->dev,
+               fsl_dma_hardware.buffer_bytes_max,
+               &pcm->streams[0].substream->dma_buffer);
+       if (ret) {
+               dev_err(card->dev,
+                       "Can't allocate playback DMA buffer (size=%u)\n",
+                       fsl_dma_hardware.buffer_bytes_max);
+               return -ENOMEM;
+       }
+
+       ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, pcm->dev,
+               fsl_dma_hardware.buffer_bytes_max,
+               &pcm->streams[1].substream->dma_buffer);
+       if (ret) {
+               snd_dma_free_pages(&pcm->streams[0].substream->dma_buffer);
+               dev_err(card->dev,
+                       "Can't allocate capture DMA buffer (size=%u)\n",
+                       fsl_dma_hardware.buffer_bytes_max);
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
+/**
+ * fsl_dma_open: open a new substream.
+ *
+ * Each substream has its own DMA buffer.
+ */
+static int fsl_dma_open(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct fsl_dma_private *dma_private;
+       dma_addr_t ld_buf_phys;
+       unsigned int channel;
+       int ret = 0;
+
+       /*
+        * Reject any DMA buffer whose size is not a multiple of the period
+        * size.  We need to make sure that the DMA buffer can be evenly divided
+        * into periods.
+        */
+       ret = snd_pcm_hw_constraint_integer(runtime,
+               SNDRV_PCM_HW_PARAM_PERIODS);
+       if (ret < 0) {
+               dev_err(substream->pcm->card->dev, "invalid buffer size\n");
+               return ret;
+       }
+
+       channel = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1;
+
+       if (dma_global_data.assigned[channel]) {
+               dev_err(substream->pcm->card->dev,
+                       "DMA channel already assigned\n");
+               return -EBUSY;
+       }
+
+       dma_private = dma_alloc_coherent(substream->pcm->dev,
+               sizeof(struct fsl_dma_private), &ld_buf_phys, GFP_KERNEL);
+       if (!dma_private) {
+               dev_err(substream->pcm->card->dev,
+                       "can't allocate DMA private data\n");
+               return -ENOMEM;
+       }
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               dma_private->ssi_sxx_phys = dma_global_data.ssi_stx_phys;
+       else
+               dma_private->ssi_sxx_phys = dma_global_data.ssi_srx_phys;
+
+       dma_private->dma_channel = dma_global_data.dma_channel[channel];
+       dma_private->irq = dma_global_data.irq[channel];
+       dma_private->substream = substream;
+       dma_private->ld_buf_phys = ld_buf_phys;
+       dma_private->dma_buf_phys = substream->dma_buffer.addr;
+
+       /* We only support one DMA controller for now */
+       dma_private->controller_id = 0;
+       dma_private->channel_id = channel;
+
+       ret = request_irq(dma_private->irq, fsl_dma_isr, 0, "DMA", dma_private);
+       if (ret) {
+               dev_err(substream->pcm->card->dev,
+                       "can't register ISR for IRQ %u (ret=%i)\n",
+                       dma_private->irq, ret);
+               dma_free_coherent(substream->pcm->dev,
+                       sizeof(struct fsl_dma_private),
+                       dma_private, dma_private->ld_buf_phys);
+               return ret;
+       }
+
+       dma_global_data.assigned[channel] = 1;
+
+       snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+       snd_soc_set_runtime_hwparams(substream, &fsl_dma_hardware);
+       runtime->private_data = dma_private;
+
+       return 0;
+}
+
+/**
+ * fsl_dma_hw_params: allocate the DMA buffer and the DMA link descriptors.
+ *
+ * ALSA divides the DMA buffer into N periods.  We create NUM_DMA_LINKS link
+ * descriptors that ping-pong from one period to the next.  For example, if
+ * there are six periods and two link descriptors, this is how they look
+ * before playback starts:
+ *
+ *                The last link descriptor
+ *   ____________  points back to the first
+ *  |           |
+ *  V           |
+ *  ___    ___   |
+ * |   |->|   |->|
+ * |___|  |___|
+ *   |      |
+ *   |      |
+ *   V      V
+ *  _________________________________________
+ * |      |      |      |      |      |      |  The DMA buffer is
+ * |      |      |      |      |      |      |    divided into 6 parts
+ * |______|______|______|______|______|______|
+ *
+ * and here's how they look after the first period is finished playing:
+ *
+ *   ____________
+ *  |           |
+ *  V           |
+ *  ___    ___   |
+ * |   |->|   |->|
+ * |___|  |___|
+ *   |      |
+ *   |______________
+ *          |       |
+ *          V       V
+ *  _________________________________________
+ * |      |      |      |      |      |      |
+ * |      |      |      |      |      |      |
+ * |______|______|______|______|______|______|
+ *
+ * The first link descriptor now points to the third period.  The DMA
+ * controller is currently playing the second period.  When it finishes, it
+ * will jump back to the first descriptor and play the third period.
+ *
+ * There are four reasons we do this:
+ *
+ * 1. The only way to get the DMA controller to automatically restart the
+ *    transfer when it gets to the end of the buffer is to use chaining
+ *    mode.  Basic direct mode doesn't offer that feature.
+ * 2. We need to receive an interrupt at the end of every period.  The DMA
+ *    controller can generate an interrupt at the end of every link transfer
+ *    (aka segment).  Making each period into a DMA segment will give us the
+ *    interrupts we need.
+ * 3. By creating only two link descriptors, regardless of the number of
+ *    periods, we do not need to reallocate the link descriptors if the
+ *    number of periods changes.
+ * 4. All of the audio data is still stored in a single, contiguous DMA
+ *    buffer, which is what ALSA expects.  We're just dividing it into
+ *    contiguous parts, and creating a link descriptor for each one.
+ *
+ * Note that due to a quirk of the SSI's STX register, the target address
+ * for the DMA operations depends on the sample size.  So we don't program
+ * the dest_addr (for playback -- source_addr for capture) fields in the
+ * link descriptors here.  We do that in fsl_dma_prepare()
+ */
+static int fsl_dma_hw_params(struct snd_pcm_substream *substream,
+       struct snd_pcm_hw_params *hw_params)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct fsl_dma_private *dma_private = runtime->private_data;
+       struct ccsr_dma_channel __iomem *dma_channel = dma_private->dma_channel;
+
+       dma_addr_t temp_addr;   /* Pointer to next period */
+       u64 temp_link;          /* Pointer to next link descriptor */
+       u32 mr;                 /* Temporary variable for MR register */
+
+       unsigned int i;
+
+       /* Get all the parameters we need */
+       size_t buffer_size = params_buffer_bytes(hw_params);
+       size_t period_size = params_period_bytes(hw_params);
+
+       /* Initialize our DMA tracking variables */
+       dma_private->period_size = period_size;
+       dma_private->num_periods = params_periods(hw_params);
+       dma_private->dma_buf_end = dma_private->dma_buf_phys + buffer_size;
+       dma_private->dma_buf_next = dma_private->dma_buf_phys +
+               (NUM_DMA_LINKS * period_size);
+       if (dma_private->dma_buf_next >= dma_private->dma_buf_end)
+               dma_private->dma_buf_next = dma_private->dma_buf_phys;
+
+       /*
+        * Initialize each link descriptor.
+        *
+        * The actual address in STX0 (destination for playback, source for
+        * capture) is based on the sample size, but we don't know the sample
+        * size in this function, so we'll have to adjust that later.  See
+        * comments in fsl_dma_prepare().
+        *
+        * The DMA controller does not have a cache, so the CPU does not
+        * need to tell it to flush its cache.  However, the DMA
+        * controller does need to tell the CPU to flush its cache.
+        * That's what the SNOOP bit does.
+        *
+        * Also, even though the DMA controller supports 36-bit addressing, for
+        * simplicity we currently support only 32-bit addresses for the audio
+        * buffer itself.
+        */
+       temp_addr = substream->dma_buffer.addr;
+       temp_link = dma_private->ld_buf_phys +
+               sizeof(struct fsl_dma_link_descriptor);
+
+       for (i = 0; i < NUM_DMA_LINKS; i++) {
+               struct fsl_dma_link_descriptor *link = &dma_private->link[i];
+
+               link->count = cpu_to_be32(period_size);
+               link->source_attr = cpu_to_be32(CCSR_DMA_ATR_SNOOP);
+               link->dest_attr = cpu_to_be32(CCSR_DMA_ATR_SNOOP);
+               link->next = cpu_to_be64(temp_link);
+
+               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+                       link->source_addr = cpu_to_be32(temp_addr);
+               else
+                       link->dest_addr = cpu_to_be32(temp_addr);
+
+               temp_addr += period_size;
+               temp_link += sizeof(struct fsl_dma_link_descriptor);
+       }
+       /* The last link descriptor points to the first */
+       dma_private->link[i - 1].next = cpu_to_be64(dma_private->ld_buf_phys);
+
+       /* Tell the DMA controller where the first link descriptor is */
+       out_be32(&dma_channel->clndar,
+               CCSR_DMA_CLNDAR_ADDR(dma_private->ld_buf_phys));
+       out_be32(&dma_channel->eclndar,
+               CCSR_DMA_ECLNDAR_ADDR(dma_private->ld_buf_phys));
+
+       /* The manual says the BCR must be clear before enabling EMP */
+       out_be32(&dma_channel->bcr, 0);
+
+       /*
+        * Program the mode register for interrupts, external master control,
+        * and source/destination hold.  Also clear the Channel Abort bit.
+        */
+       mr = in_be32(&dma_channel->mr) &
+               ~(CCSR_DMA_MR_CA | CCSR_DMA_MR_DAHE | CCSR_DMA_MR_SAHE);
+
+       /*
+        * We want External Master Start and External Master Pause enabled,
+        * because the SSI is controlling the DMA controller.  We want the DMA
+        * controller to be set up in advance, and then we signal only the SSI
+        * to start transfering.
+        *
+        * We want End-Of-Segment Interrupts enabled, because this will generate
+        * an interrupt at the end of each segment (each link descriptor
+        * represents one segment).  Each DMA segment is the same thing as an
+        * ALSA period, so this is how we get an interrupt at the end of every
+        * period.
+        *
+        * We want Error Interrupt enabled, so that we can get an error if
+        * the DMA controller is mis-programmed somehow.
+        */
+       mr |= CCSR_DMA_MR_EOSIE | CCSR_DMA_MR_EIE | CCSR_DMA_MR_EMP_EN |
+               CCSR_DMA_MR_EMS_EN;
+
+       /* For playback, we want the destination address to be held.  For
+          capture, set the source address to be held. */
+       mr |= (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
+               CCSR_DMA_MR_DAHE : CCSR_DMA_MR_SAHE;
+
+       out_be32(&dma_channel->mr, mr);
+
+       return 0;
+}
+
+/**
+ * fsl_dma_prepare - prepare the DMA registers for playback.
+ *
+ * This function is called after the specifics of the audio data are known,
+ * i.e. snd_pcm_runtime is initialized.
+ *
+ * In this function, we finish programming the registers of the DMA
+ * controller that are dependent on the sample size.
+ *
+ * One of the drawbacks with big-endian is that when copying integers of
+ * different sizes to a fixed-sized register, the address to which the
+ * integer must be copied is dependent on the size of the integer.
+ *
+ * For example, if P is the address of a 32-bit register, and X is a 32-bit
+ * integer, then X should be copied to address P.  However, if X is a 16-bit
+ * integer, then it should be copied to P+2.  If X is an 8-bit register,
+ * then it should be copied to P+3.
+ *
+ * So for playback of 8-bit samples, the DMA controller must transfer single
+ * bytes from the DMA buffer to the last byte of the STX0 register, i.e.
+ * offset by 3 bytes. For 16-bit samples, the offset is two bytes.
+ *
+ * For 24-bit samples, the offset is 1 byte.  However, the DMA controller
+ * does not support 3-byte copies (the DAHTS register supports only 1, 2, 4,
+ * and 8 bytes at a time).  So we do not support packed 24-bit samples.
+ * 24-bit data must be padded to 32 bits.
+ */
+static int fsl_dma_prepare(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct fsl_dma_private *dma_private = runtime->private_data;
+       struct ccsr_dma_channel __iomem *dma_channel = dma_private->dma_channel;
+       u32 mr;
+       unsigned int i;
+       dma_addr_t ssi_sxx_phys;        /* Bus address of SSI STX register */
+       unsigned int frame_size;        /* Number of bytes per frame */
+
+       ssi_sxx_phys = dma_private->ssi_sxx_phys;
+
+       mr = in_be32(&dma_channel->mr) & ~(CCSR_DMA_MR_BWC_MASK |
+                 CCSR_DMA_MR_SAHTS_MASK | CCSR_DMA_MR_DAHTS_MASK);
+
+       switch (runtime->sample_bits) {
+       case 8:
+               mr |= CCSR_DMA_MR_DAHTS_1 | CCSR_DMA_MR_SAHTS_1;
+               ssi_sxx_phys += 3;
+               break;
+       case 16:
+               mr |= CCSR_DMA_MR_DAHTS_2 | CCSR_DMA_MR_SAHTS_2;
+               ssi_sxx_phys += 2;
+               break;
+       case 32:
+               mr |= CCSR_DMA_MR_DAHTS_4 | CCSR_DMA_MR_SAHTS_4;
+               break;
+       default:
+               dev_err(substream->pcm->card->dev,
+                       "unsupported sample size %u\n", runtime->sample_bits);
+               return -EINVAL;
+       }
+
+       frame_size = runtime->frame_bits / 8;
+       /*
+        * BWC should always be a multiple of the frame size.  BWC determines
+        * how many bytes are sent/received before the DMA controller checks the
+        * SSI to see if it needs to stop.  For playback, the transmit FIFO can
+        * hold three frames, so we want to send two frames at a time. For
+        * capture, the receive FIFO is triggered when it contains one frame, so
+        * we want to receive one frame at a time.
+        */
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               mr |= CCSR_DMA_MR_BWC(2 * frame_size);
+       else
+               mr |= CCSR_DMA_MR_BWC(frame_size);
+
+       out_be32(&dma_channel->mr, mr);
+
+       /*
+        * Program the address of the DMA transfer to/from the SSI.
+        */
+       for (i = 0; i < NUM_DMA_LINKS; i++) {
+               struct fsl_dma_link_descriptor *link = &dma_private->link[i];
+
+               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+                       link->dest_addr = cpu_to_be32(ssi_sxx_phys);
+               else
+                       link->source_addr = cpu_to_be32(ssi_sxx_phys);
+       }
+
+       return 0;
+}
+
+/**
+ * fsl_dma_pointer: determine the current position of the DMA transfer
+ *
+ * This function is called by ALSA when ALSA wants to know where in the
+ * stream buffer the hardware currently is.
+ *
+ * For playback, the SAR register contains the physical address of the most
+ * recent DMA transfer.  For capture, the value is in the DAR register.
+ *
+ * The base address of the buffer is stored in the source_addr field of the
+ * first link descriptor.
+ */
+static snd_pcm_uframes_t fsl_dma_pointer(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct fsl_dma_private *dma_private = runtime->private_data;
+       struct ccsr_dma_channel __iomem *dma_channel = dma_private->dma_channel;
+       dma_addr_t position;
+       snd_pcm_uframes_t frames;
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               position = in_be32(&dma_channel->sar);
+       else
+               position = in_be32(&dma_channel->dar);
+
+       frames = bytes_to_frames(runtime, position - dma_private->dma_buf_phys);
+
+       /*
+        * If the current address is just past the end of the buffer, wrap it
+        * around.
+        */
+       if (frames == runtime->buffer_size)
+               frames = 0;
+
+       return frames;
+}
+
+/**
+ * fsl_dma_hw_free: release resources allocated in fsl_dma_hw_params()
+ *
+ * Release the resources allocated in fsl_dma_hw_params() and de-program the
+ * registers.
+ *
+ * This function can be called multiple times.
+ */
+static int fsl_dma_hw_free(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct fsl_dma_private *dma_private = runtime->private_data;
+
+       if (dma_private) {
+               struct ccsr_dma_channel __iomem *dma_channel;
+
+               dma_channel = dma_private->dma_channel;
+
+               /* Stop the DMA */
+               out_be32(&dma_channel->mr, CCSR_DMA_MR_CA);
+               out_be32(&dma_channel->mr, 0);
+
+               /* Reset all the other registers */
+               out_be32(&dma_channel->sr, -1);
+               out_be32(&dma_channel->clndar, 0);
+               out_be32(&dma_channel->eclndar, 0);
+               out_be32(&dma_channel->satr, 0);
+               out_be32(&dma_channel->sar, 0);
+               out_be32(&dma_channel->datr, 0);
+               out_be32(&dma_channel->dar, 0);
+               out_be32(&dma_channel->bcr, 0);
+               out_be32(&dma_channel->nlndar, 0);
+               out_be32(&dma_channel->enlndar, 0);
+       }
+
+       return 0;
+}
+
+/**
+ * fsl_dma_close: close the stream.
+ */
+static int fsl_dma_close(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct fsl_dma_private *dma_private = runtime->private_data;
+       int dir = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1;
+
+       if (dma_private) {
+               if (dma_private->irq)
+                       free_irq(dma_private->irq, dma_private);
+
+               if (dma_private->ld_buf_phys) {
+                       dma_unmap_single(substream->pcm->dev,
+                               dma_private->ld_buf_phys,
+                               sizeof(dma_private->link), DMA_TO_DEVICE);
+               }
+
+               /* Deallocate the fsl_dma_private structure */
+               dma_free_coherent(substream->pcm->dev,
+                       sizeof(struct fsl_dma_private),
+                       dma_private, dma_private->ld_buf_phys);
+               substream->runtime->private_data = NULL;
+       }
+
+       dma_global_data.assigned[dir] = 0;
+
+       return 0;
+}
+
+/*
+ * Remove this PCM driver.
+ */
+static void fsl_dma_free_dma_buffers(struct snd_pcm *pcm)
+{
+       struct snd_pcm_substream *substream;
+       unsigned int i;
+
+       for (i = 0; i < ARRAY_SIZE(pcm->streams); i++) {
+               substream = pcm->streams[i].substream;
+               if (substream) {
+                       snd_dma_free_pages(&substream->dma_buffer);
+                       substream->dma_buffer.area = NULL;
+                       substream->dma_buffer.addr = 0;
+               }
+       }
+}
+
+static struct snd_pcm_ops fsl_dma_ops = {
+       .open           = fsl_dma_open,
+       .close          = fsl_dma_close,
+       .ioctl          = snd_pcm_lib_ioctl,
+       .hw_params      = fsl_dma_hw_params,
+       .hw_free        = fsl_dma_hw_free,
+       .prepare        = fsl_dma_prepare,
+       .pointer        = fsl_dma_pointer,
+};
+
+struct snd_soc_platform fsl_soc_platform = {
+       .name           = "fsl-dma",
+       .pcm_ops        = &fsl_dma_ops,
+       .pcm_new        = fsl_dma_new,
+       .pcm_free       = fsl_dma_free_dma_buffers,
+};
+EXPORT_SYMBOL_GPL(fsl_soc_platform);
+
+/**
+ * fsl_dma_configure: store the DMA parameters from the fabric driver.
+ *
+ * This function is called by the ASoC fabric driver to give us the DMA and
+ * SSI channel information.
+ *
+ * Unfortunately, ASoC V1 does make it possible to determine the DMA/SSI
+ * data when a substream is created, so for now we need to store this data
+ * into a global variable.  This means that we can only support one DMA
+ * controller, and hence only one SSI.
+ */
+int fsl_dma_configure(struct fsl_dma_info *dma_info)
+{
+       static int initialized;
+
+       /* We only support one DMA controller for now */
+       if (initialized)
+               return 0;
+
+       dma_global_data.ssi_stx_phys = dma_info->ssi_stx_phys;
+       dma_global_data.ssi_srx_phys = dma_info->ssi_srx_phys;
+       dma_global_data.dma_channel[0] = dma_info->dma_channel[0];
+       dma_global_data.dma_channel[1] = dma_info->dma_channel[1];
+       dma_global_data.irq[0] = dma_info->dma_irq[0];
+       dma_global_data.irq[1] = dma_info->dma_irq[1];
+       dma_global_data.assigned[0] = 0;
+       dma_global_data.assigned[1] = 0;
+
+       initialized = 1;
+       return 1;
+}
+EXPORT_SYMBOL_GPL(fsl_dma_configure);
+
+MODULE_AUTHOR("Timur Tabi <timur@freescale.com>");
+MODULE_DESCRIPTION("Freescale Elo DMA ASoC PCM module");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/fsl/fsl_dma.h b/sound/soc/fsl/fsl_dma.h
new file mode 100644 (file)
index 0000000..430a6ce
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ * mpc8610-pcm.h - ALSA PCM interface for the Freescale MPC8610 SoC
+ *
+ * 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 _MPC8610_PCM_H
+#define _MPC8610_PCM_H
+
+struct ccsr_dma {
+       u8 res0[0x100];
+       struct ccsr_dma_channel {
+               __be32 mr;      /* Mode register */
+               __be32 sr;      /* Status register */
+               __be32 eclndar; /* Current link descriptor extended addr reg */
+               __be32 clndar;  /* Current link descriptor address register */
+               __be32 satr;    /* Source attributes register */
+               __be32 sar;     /* Source address register */
+               __be32 datr;    /* Destination attributes register */
+               __be32 dar;     /* Destination address register */
+               __be32 bcr;     /* Byte count register */
+               __be32 enlndar; /* Next link descriptor extended address reg */
+               __be32 nlndar;  /* Next link descriptor address register */
+               u8 res1[4];
+               __be32 eclsdar; /* Current list descriptor extended addr reg */
+               __be32 clsdar;  /* Current list descriptor address register */
+               __be32 enlsdar; /* Next list descriptor extended address reg */
+               __be32 nlsdar;  /* Next list descriptor address register */
+               __be32 ssr;     /* Source stride register */
+               __be32 dsr;     /* Destination stride register */
+               u8 res2[0x38];
+       } channel[4];
+       __be32 dgsr;
+};
+
+#define CCSR_DMA_MR_BWC_DISABLED       0x0F000000
+#define CCSR_DMA_MR_BWC_SHIFT          24
+#define CCSR_DMA_MR_BWC_MASK           0x0F000000
+#define CCSR_DMA_MR_BWC(x) \
+       ((ilog2(x) << CCSR_DMA_MR_BWC_SHIFT) & CCSR_DMA_MR_BWC_MASK)
+#define CCSR_DMA_MR_EMP_EN             0x00200000
+#define CCSR_DMA_MR_EMS_EN             0x00040000
+#define CCSR_DMA_MR_DAHTS_MASK         0x00030000
+#define CCSR_DMA_MR_DAHTS_1            0x00000000
+#define CCSR_DMA_MR_DAHTS_2            0x00010000
+#define CCSR_DMA_MR_DAHTS_4            0x00020000
+#define CCSR_DMA_MR_DAHTS_8            0x00030000
+#define CCSR_DMA_MR_SAHTS_MASK         0x0000C000
+#define CCSR_DMA_MR_SAHTS_1            0x00000000
+#define CCSR_DMA_MR_SAHTS_2            0x00004000
+#define CCSR_DMA_MR_SAHTS_4            0x00008000
+#define CCSR_DMA_MR_SAHTS_8            0x0000C000
+#define CCSR_DMA_MR_DAHE               0x00002000
+#define CCSR_DMA_MR_SAHE               0x00001000
+#define CCSR_DMA_MR_SRW                0x00000400
+#define CCSR_DMA_MR_EOSIE              0x00000200
+#define CCSR_DMA_MR_EOLNIE             0x00000100
+#define CCSR_DMA_MR_EOLSIE             0x00000080
+#define CCSR_DMA_MR_EIE                0x00000040
+#define CCSR_DMA_MR_XFE                0x00000020
+#define CCSR_DMA_MR_CDSM_SWSM          0x00000010
+#define CCSR_DMA_MR_CA                 0x00000008
+#define CCSR_DMA_MR_CTM                0x00000004
+#define CCSR_DMA_MR_CC                 0x00000002
+#define CCSR_DMA_MR_CS                 0x00000001
+
+#define CCSR_DMA_SR_TE                 0x00000080
+#define CCSR_DMA_SR_CH                 0x00000020
+#define CCSR_DMA_SR_PE                 0x00000010
+#define CCSR_DMA_SR_EOLNI              0x00000008
+#define CCSR_DMA_SR_CB                 0x00000004
+#define CCSR_DMA_SR_EOSI               0x00000002
+#define CCSR_DMA_SR_EOLSI              0x00000001
+
+/* ECLNDAR takes bits 32-36 of the CLNDAR register */
+static inline u32 CCSR_DMA_ECLNDAR_ADDR(u64 x)
+{
+       return (x >> 32) & 0xf;
+}
+
+#define CCSR_DMA_CLNDAR_ADDR(x) ((x) & 0xFFFFFFFE)
+#define CCSR_DMA_CLNDAR_EOSIE          0x00000008
+
+/* SATR and DATR, combined */
+#define CCSR_DMA_ATR_PBATMU            0x20000000
+#define CCSR_DMA_ATR_TFLOWLVL_0        0x00000000
+#define CCSR_DMA_ATR_TFLOWLVL_1        0x06000000
+#define CCSR_DMA_ATR_TFLOWLVL_2        0x08000000
+#define CCSR_DMA_ATR_TFLOWLVL_3        0x0C000000
+#define CCSR_DMA_ATR_PCIORDER          0x02000000
+#define CCSR_DMA_ATR_SME               0x01000000
+#define CCSR_DMA_ATR_NOSNOOP           0x00040000
+#define CCSR_DMA_ATR_SNOOP             0x00050000
+#define CCSR_DMA_ATR_ESAD_MASK         0x0000000F
+
+/**
+ *  List Descriptor for extended chaining mode DMA operations.
+ *
+ *  The CLSDAR register points to the first (in a linked-list) List
+ *  Descriptor.  Each object must be aligned on a 32-byte boundary. Each
+ *  list descriptor points to a linked-list of link Descriptors.
+ */
+struct fsl_dma_list_descriptor {
+       __be64 next;            /* Address of next list descriptor */
+       __be64 first_link;      /* Address of first link descriptor */
+       __be32 source;          /* Source stride */
+       __be32 dest;            /* Destination stride */
+       u8 res[8];              /* Reserved */
+} __attribute__ ((aligned(32), packed));
+
+/**
+ *  Link Descriptor for basic and extended chaining mode DMA operations.
+ *
+ *  A Link Descriptor points to a single DMA buffer.  Each link descriptor
+ *  must be aligned on a 32-byte boundary.
+ */
+struct fsl_dma_link_descriptor {
+       __be32 source_attr;     /* Programmed into SATR register */
+       __be32 source_addr;     /* Programmed into SAR register */
+       __be32 dest_attr;       /* Programmed into DATR register */
+       __be32 dest_addr;       /* Programmed into DAR register */
+       __be64 next;    /* Address of next link descriptor */
+       __be32 count;   /* Byte count */
+       u8 res[4];      /* Reserved */
+} __attribute__ ((aligned(32), packed));
+
+/* DMA information needed to create a snd_soc_cpu_dai object
+ *
+ * ssi_stx_phys: bus address of SSI STX register to use
+ * ssi_srx_phys: bus address of SSI SRX register to use
+ * dma[0]: points to the DMA channel to use for playback
+ * dma[1]: points to the DMA channel to use for capture
+ * dma_irq[0]: IRQ of the DMA channel to use for playback
+ * dma_irq[1]: IRQ of the DMA channel to use for capture
+ */
+struct fsl_dma_info {
+       dma_addr_t ssi_stx_phys;
+       dma_addr_t ssi_srx_phys;
+       struct ccsr_dma_channel __iomem *dma_channel[2];
+       unsigned int dma_irq[2];
+};
+
+extern struct snd_soc_platform fsl_soc_platform;
+
+int fsl_dma_configure(struct fsl_dma_info *dma_info);
+
+#endif
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c
new file mode 100644 (file)
index 0000000..145ad13
--- /dev/null
@@ -0,0 +1,644 @@
+/*
+ * Freescale SSI ALSA SoC Digital Audio Interface (DAI) driver
+ *
+ * Author: Timur Tabi <timur@freescale.com>
+ *
+ * Copyright 2007-2008 Freescale Semiconductor, Inc.  This file is licensed
+ * under the terms of the GNU General Public License version 2.  This
+ * program is licensed "as is" without any warranty of any kind, whether
+ * express or implied.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+
+#include <asm/immap_86xx.h>
+
+#include "fsl_ssi.h"
+
+/**
+ * FSLSSI_I2S_RATES: sample rates supported by the I2S
+ *
+ * This driver currently only supports the SSI running in I2S slave mode,
+ * which means the codec determines the sample rate.  Therefore, we tell
+ * ALSA that we support all rates and let the codec driver decide what rates
+ * are really supported.
+ */
+#define FSLSSI_I2S_RATES (SNDRV_PCM_RATE_5512 | SNDRV_PCM_RATE_8000_192000 | \
+                         SNDRV_PCM_RATE_CONTINUOUS)
+
+/**
+ * FSLSSI_I2S_FORMATS: audio formats supported by the SSI
+ *
+ * This driver currently only supports the SSI running in I2S slave mode.
+ *
+ * The SSI has a limitation in that the samples must be in the same byte
+ * order as the host CPU.  This is because when multiple bytes are written
+ * to the STX register, the bytes and bits must be written in the same
+ * order.  The STX is a shift register, so all the bits need to be aligned
+ * (bit-endianness must match byte-endianness).  Processors typically write
+ * the bits within a byte in the same order that the bytes of a word are
+ * written in.  So if the host CPU is big-endian, then only big-endian
+ * samples will be written to STX properly.
+ */
+#ifdef __BIG_ENDIAN
+#define FSLSSI_I2S_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_BE | \
+        SNDRV_PCM_FMTBIT_S18_3BE | SNDRV_PCM_FMTBIT_S20_3BE | \
+        SNDRV_PCM_FMTBIT_S24_3BE | SNDRV_PCM_FMTBIT_S24_BE)
+#else
+#define FSLSSI_I2S_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | \
+        SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+        SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_LE)
+#endif
+
+/**
+ * fsl_ssi_private: per-SSI private data
+ *
+ * @name: short name for this device ("SSI0", "SSI1", etc)
+ * @ssi: pointer to the SSI's registers
+ * @ssi_phys: physical address of the SSI registers
+ * @irq: IRQ of this SSI
+ * @dev: struct device pointer
+ * @playback: the number of playback streams opened
+ * @capture: the number of capture streams opened
+ * @cpu_dai: the CPU DAI for this device
+ * @dev_attr: the sysfs device attribute structure
+ * @stats: SSI statistics
+ */
+struct fsl_ssi_private {
+       char name[8];
+       struct ccsr_ssi __iomem *ssi;
+       dma_addr_t ssi_phys;
+       unsigned int irq;
+       struct device *dev;
+       unsigned int playback;
+       unsigned int capture;
+       struct snd_soc_cpu_dai cpu_dai;
+       struct device_attribute dev_attr;
+
+       struct {
+               unsigned int rfrc;
+               unsigned int tfrc;
+               unsigned int cmdau;
+               unsigned int cmddu;
+               unsigned int rxt;
+               unsigned int rdr1;
+               unsigned int rdr0;
+               unsigned int tde1;
+               unsigned int tde0;
+               unsigned int roe1;
+               unsigned int roe0;
+               unsigned int tue1;
+               unsigned int tue0;
+               unsigned int tfs;
+               unsigned int rfs;
+               unsigned int tls;
+               unsigned int rls;
+               unsigned int rff1;
+               unsigned int rff0;
+               unsigned int tfe1;
+               unsigned int tfe0;
+       } stats;
+};
+
+/**
+ * fsl_ssi_isr: SSI interrupt handler
+ *
+ * Although it's possible to use the interrupt handler to send and receive
+ * data to/from the SSI, we use the DMA instead.  Programming is more
+ * complicated, but the performance is much better.
+ *
+ * This interrupt handler is used only to gather statistics.
+ *
+ * @irq: IRQ of the SSI device
+ * @dev_id: pointer to the ssi_private structure for this SSI device
+ */
+static irqreturn_t fsl_ssi_isr(int irq, void *dev_id)
+{
+       struct fsl_ssi_private *ssi_private = dev_id;
+       struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
+       irqreturn_t ret = IRQ_NONE;
+       __be32 sisr;
+       __be32 sisr2 = 0;
+
+       /* We got an interrupt, so read the status register to see what we
+          were interrupted for.  We mask it with the Interrupt Enable register
+          so that we only check for events that we're interested in.
+        */
+       sisr = in_be32(&ssi->sisr) & in_be32(&ssi->sier);
+
+       if (sisr & CCSR_SSI_SISR_RFRC) {
+               ssi_private->stats.rfrc++;
+               sisr2 |= CCSR_SSI_SISR_RFRC;
+               ret = IRQ_HANDLED;
+       }
+
+       if (sisr & CCSR_SSI_SISR_TFRC) {
+               ssi_private->stats.tfrc++;
+               sisr2 |= CCSR_SSI_SISR_TFRC;
+               ret = IRQ_HANDLED;
+       }
+
+       if (sisr & CCSR_SSI_SISR_CMDAU) {
+               ssi_private->stats.cmdau++;
+               ret = IRQ_HANDLED;
+       }
+
+       if (sisr & CCSR_SSI_SISR_CMDDU) {
+               ssi_private->stats.cmddu++;
+               ret = IRQ_HANDLED;
+       }
+
+       if (sisr & CCSR_SSI_SISR_RXT) {
+               ssi_private->stats.rxt++;
+               ret = IRQ_HANDLED;
+       }
+
+       if (sisr & CCSR_SSI_SISR_RDR1) {
+               ssi_private->stats.rdr1++;
+               ret = IRQ_HANDLED;
+       }
+
+       if (sisr & CCSR_SSI_SISR_RDR0) {
+               ssi_private->stats.rdr0++;
+               ret = IRQ_HANDLED;
+       }
+
+       if (sisr & CCSR_SSI_SISR_TDE1) {
+               ssi_private->stats.tde1++;
+               ret = IRQ_HANDLED;
+       }
+
+       if (sisr & CCSR_SSI_SISR_TDE0) {
+               ssi_private->stats.tde0++;
+               ret = IRQ_HANDLED;
+       }
+
+       if (sisr & CCSR_SSI_SISR_ROE1) {
+               ssi_private->stats.roe1++;
+               sisr2 |= CCSR_SSI_SISR_ROE1;
+               ret = IRQ_HANDLED;
+       }
+
+       if (sisr & CCSR_SSI_SISR_ROE0) {
+               ssi_private->stats.roe0++;
+               sisr2 |= CCSR_SSI_SISR_ROE0;
+               ret = IRQ_HANDLED;
+       }
+
+       if (sisr & CCSR_SSI_SISR_TUE1) {
+               ssi_private->stats.tue1++;
+               sisr2 |= CCSR_SSI_SISR_TUE1;
+               ret = IRQ_HANDLED;
+       }
+
+       if (sisr & CCSR_SSI_SISR_TUE0) {
+               ssi_private->stats.tue0++;
+               sisr2 |= CCSR_SSI_SISR_TUE0;
+               ret = IRQ_HANDLED;
+       }
+
+       if (sisr & CCSR_SSI_SISR_TFS) {
+               ssi_private->stats.tfs++;
+               ret = IRQ_HANDLED;
+       }
+
+       if (sisr & CCSR_SSI_SISR_RFS) {
+               ssi_private->stats.rfs++;
+               ret = IRQ_HANDLED;
+       }
+
+       if (sisr & CCSR_SSI_SISR_TLS) {
+               ssi_private->stats.tls++;
+               ret = IRQ_HANDLED;
+       }
+
+       if (sisr & CCSR_SSI_SISR_RLS) {
+               ssi_private->stats.rls++;
+               ret = IRQ_HANDLED;
+       }
+
+       if (sisr & CCSR_SSI_SISR_RFF1) {
+               ssi_private->stats.rff1++;
+               ret = IRQ_HANDLED;
+       }
+
+       if (sisr & CCSR_SSI_SISR_RFF0) {
+               ssi_private->stats.rff0++;
+               ret = IRQ_HANDLED;
+       }
+
+       if (sisr & CCSR_SSI_SISR_TFE1) {
+               ssi_private->stats.tfe1++;
+               ret = IRQ_HANDLED;
+       }
+
+       if (sisr & CCSR_SSI_SISR_TFE0) {
+               ssi_private->stats.tfe0++;
+               ret = IRQ_HANDLED;
+       }
+
+       /* Clear the bits that we set */
+       if (sisr2)
+               out_be32(&ssi->sisr, sisr2);
+
+       return ret;
+}
+
+/**
+ * fsl_ssi_startup: create a new substream
+ *
+ * This is the first function called when a stream is opened.
+ *
+ * If this is the first stream open, then grab the IRQ and program most of
+ * the SSI registers.
+ */
+static int fsl_ssi_startup(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct fsl_ssi_private *ssi_private = rtd->dai->cpu_dai->private_data;
+
+       /*
+        * If this is the first stream opened, then request the IRQ
+        * and initialize the SSI registers.
+        */
+       if (!ssi_private->playback && !ssi_private->capture) {
+               struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
+               int ret;
+
+               ret = request_irq(ssi_private->irq, fsl_ssi_isr, 0,
+                                 ssi_private->name, ssi_private);
+               if (ret < 0) {
+                       dev_err(substream->pcm->card->dev,
+                               "could not claim irq %u\n", ssi_private->irq);
+                       return ret;
+               }
+
+               /*
+                * Section 16.5 of the MPC8610 reference manual says that the
+                * SSI needs to be disabled before updating the registers we set
+                * here.
+                */
+               clrbits32(&ssi->scr, CCSR_SSI_SCR_SSIEN);
+
+               /*
+                * Program the SSI into I2S Slave Non-Network Synchronous mode.
+                * Also enable the transmit and receive FIFO.
+                *
+                * FIXME: Little-endian samples require a different shift dir
+                */
+               clrsetbits_be32(&ssi->scr, CCSR_SSI_SCR_I2S_MODE_MASK,
+                       CCSR_SSI_SCR_TFR_CLK_DIS |
+                       CCSR_SSI_SCR_I2S_MODE_SLAVE | CCSR_SSI_SCR_SYN);
+
+               out_be32(&ssi->stcr,
+                        CCSR_SSI_STCR_TXBIT0 | CCSR_SSI_STCR_TFEN0 |
+                        CCSR_SSI_STCR_TFSI | CCSR_SSI_STCR_TEFS |
+                        CCSR_SSI_STCR_TSCKP);
+
+               out_be32(&ssi->srcr,
+                        CCSR_SSI_SRCR_RXBIT0 | CCSR_SSI_SRCR_RFEN0 |
+                        CCSR_SSI_SRCR_RFSI | CCSR_SSI_SRCR_REFS |
+                        CCSR_SSI_SRCR_RSCKP);
+
+               /*
+                * The DC and PM bits are only used if the SSI is the clock
+                * master.
+                */
+
+               /* 4. Enable the interrupts and DMA requests */
+               out_be32(&ssi->sier,
+                        CCSR_SSI_SIER_TFRC_EN | CCSR_SSI_SIER_TDMAE |
+                        CCSR_SSI_SIER_TIE | CCSR_SSI_SIER_TUE0_EN |
+                        CCSR_SSI_SIER_TUE1_EN | CCSR_SSI_SIER_RFRC_EN |
+                        CCSR_SSI_SIER_RDMAE | CCSR_SSI_SIER_RIE |
+                        CCSR_SSI_SIER_ROE0_EN | CCSR_SSI_SIER_ROE1_EN);
+
+               /*
+                * Set the watermark for transmit FIFI 0 and receive FIFO 0. We
+                * don't use FIFO 1.  Since the SSI only supports stereo, the
+                * watermark should never be an odd number.
+                */
+               out_be32(&ssi->sfcsr,
+                        CCSR_SSI_SFCSR_TFWM0(6) | CCSR_SSI_SFCSR_RFWM0(2));
+
+               /*
+                * We keep the SSI disabled because if we enable it, then the
+                * DMA controller will start.  It's not supposed to start until
+                * the SCR.TE (or SCR.RE) bit is set, but it does anyway.  The
+                * DMA controller will transfer one "BWC" of data (i.e. the
+                * amount of data that the MR.BWC bits are set to).  The reason
+                * this is bad is because at this point, the PCM driver has not
+                * finished initializing the DMA controller.
+                */
+       }
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               ssi_private->playback++;
+
+       if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+               ssi_private->capture++;
+
+       return 0;
+}
+
+/**
+ * fsl_ssi_prepare: prepare the SSI.
+ *
+ * Most of the SSI registers have been programmed in the startup function,
+ * but the word length must be programmed here.  Unfortunately, programming
+ * the SxCCR.WL bits requires the SSI to be temporarily disabled.  This can
+ * cause a problem with supporting simultaneous playback and capture.  If
+ * the SSI is already playing a stream, then that stream may be temporarily
+ * stopped when you start capture.
+ *
+ * Note: The SxCCR.DC and SxCCR.PM bits are only used if the SSI is the
+ * clock master.
+ */
+static int fsl_ssi_prepare(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct fsl_ssi_private *ssi_private = rtd->dai->cpu_dai->private_data;
+
+       struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
+       u32 wl;
+
+       wl = CCSR_SSI_SxCCR_WL(snd_pcm_format_width(runtime->format));
+
+       clrbits32(&ssi->scr, CCSR_SSI_SCR_SSIEN);
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               clrsetbits_be32(&ssi->stccr, CCSR_SSI_SxCCR_WL_MASK, wl);
+       else
+               clrsetbits_be32(&ssi->srccr, CCSR_SSI_SxCCR_WL_MASK, wl);
+
+       setbits32(&ssi->scr, CCSR_SSI_SCR_SSIEN);
+
+       return 0;
+}
+
+/**
+ * fsl_ssi_trigger: start and stop the DMA transfer.
+ *
+ * This function is called by ALSA to start, stop, pause, and resume the DMA
+ * transfer of data.
+ *
+ * The DMA channel is in external master start and pause mode, which
+ * means the SSI completely controls the flow of data.
+ */
+static int fsl_ssi_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct fsl_ssi_private *ssi_private = rtd->dai->cpu_dai->private_data;
+       struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+                       setbits32(&ssi->scr, CCSR_SSI_SCR_TE);
+               } else {
+                       setbits32(&ssi->scr, CCSR_SSI_SCR_RE);
+
+                       /*
+                        * I think we need this delay to allow time for the SSI
+                        * to put data into its FIFO.  Without it, ALSA starts
+                        * to complain about overruns.
+                        */
+                       msleep(1);
+               }
+               break;
+
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+                       clrbits32(&ssi->scr, CCSR_SSI_SCR_TE);
+               else
+                       clrbits32(&ssi->scr, CCSR_SSI_SCR_RE);
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/**
+ * fsl_ssi_shutdown: shutdown the SSI
+ *
+ * Shutdown the SSI if there are no other substreams open.
+ */
+static void fsl_ssi_shutdown(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct fsl_ssi_private *ssi_private = rtd->dai->cpu_dai->private_data;
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               ssi_private->playback--;
+
+       if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+               ssi_private->capture--;
+
+       /*
+        * If this is the last active substream, disable the SSI and release
+        * the IRQ.
+        */
+       if (!ssi_private->playback && !ssi_private->capture) {
+               struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
+
+               clrbits32(&ssi->scr, CCSR_SSI_SCR_SSIEN);
+
+               free_irq(ssi_private->irq, ssi_private);
+       }
+}
+
+/**
+ * fsl_ssi_set_sysclk: set the clock frequency and direction
+ *
+ * This function is called by the machine driver to tell us what the clock
+ * frequency and direction are.
+ *
+ * Currently, we only support operating as a clock slave (SND_SOC_CLOCK_IN),
+ * and we don't care about the frequency.  Return an error if the direction
+ * is not SND_SOC_CLOCK_IN.
+ *
+ * @clk_id: reserved, should be zero
+ * @freq: the frequency of the given clock ID, currently ignored
+ * @dir: SND_SOC_CLOCK_IN (clock slave) or SND_SOC_CLOCK_OUT (clock master)
+ */
+static int fsl_ssi_set_sysclk(struct snd_soc_cpu_dai *cpu_dai,
+                             int clk_id, unsigned int freq, int dir)
+{
+
+       return (dir == SND_SOC_CLOCK_IN) ? 0 : -EINVAL;
+}
+
+/**
+ * fsl_ssi_set_fmt: set the serial format.
+ *
+ * This function is called by the machine driver to tell us what serial
+ * format to use.
+ *
+ * Currently, we only support I2S mode.  Return an error if the format is
+ * not SND_SOC_DAIFMT_I2S.
+ *
+ * @format: one of SND_SOC_DAIFMT_xxx
+ */
+static int fsl_ssi_set_fmt(struct snd_soc_cpu_dai *cpu_dai, unsigned int format)
+{
+       return (format == SND_SOC_DAIFMT_I2S) ? 0 : -EINVAL;
+}
+
+/**
+ * fsl_ssi_dai_template: template CPU DAI for the SSI
+ */
+static struct snd_soc_cpu_dai fsl_ssi_dai_template = {
+       .playback = {
+               /* The SSI does not support monaural audio. */
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = FSLSSI_I2S_RATES,
+               .formats = FSLSSI_I2S_FORMATS,
+       },
+       .capture = {
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = FSLSSI_I2S_RATES,
+               .formats = FSLSSI_I2S_FORMATS,
+       },
+       .ops = {
+               .startup = fsl_ssi_startup,
+               .prepare = fsl_ssi_prepare,
+               .shutdown = fsl_ssi_shutdown,
+               .trigger = fsl_ssi_trigger,
+       },
+       .dai_ops = {
+               .set_sysclk = fsl_ssi_set_sysclk,
+               .set_fmt = fsl_ssi_set_fmt,
+       },
+};
+
+/**
+ * fsl_sysfs_ssi_show: display SSI statistics
+ *
+ * Display the statistics for the current SSI device.
+ */
+static ssize_t fsl_sysfs_ssi_show(struct device *dev,
+       struct device_attribute *attr, char *buf)
+{
+       struct fsl_ssi_private *ssi_private =
+       container_of(attr, struct fsl_ssi_private, dev_attr);
+       ssize_t length;
+
+       length = sprintf(buf, "rfrc=%u", ssi_private->stats.rfrc);
+       length += sprintf(buf + length, "\ttfrc=%u", ssi_private->stats.tfrc);
+       length += sprintf(buf + length, "\tcmdau=%u", ssi_private->stats.cmdau);
+       length += sprintf(buf + length, "\tcmddu=%u", ssi_private->stats.cmddu);
+       length += sprintf(buf + length, "\trxt=%u", ssi_private->stats.rxt);
+       length += sprintf(buf + length, "\trdr1=%u", ssi_private->stats.rdr1);
+       length += sprintf(buf + length, "\trdr0=%u", ssi_private->stats.rdr0);
+       length += sprintf(buf + length, "\ttde1=%u", ssi_private->stats.tde1);
+       length += sprintf(buf + length, "\ttde0=%u", ssi_private->stats.tde0);
+       length += sprintf(buf + length, "\troe1=%u", ssi_private->stats.roe1);
+       length += sprintf(buf + length, "\troe0=%u", ssi_private->stats.roe0);
+       length += sprintf(buf + length, "\ttue1=%u", ssi_private->stats.tue1);
+       length += sprintf(buf + length, "\ttue0=%u", ssi_private->stats.tue0);
+       length += sprintf(buf + length, "\ttfs=%u", ssi_private->stats.tfs);
+       length += sprintf(buf + length, "\trfs=%u", ssi_private->stats.rfs);
+       length += sprintf(buf + length, "\ttls=%u", ssi_private->stats.tls);
+       length += sprintf(buf + length, "\trls=%u", ssi_private->stats.rls);
+       length += sprintf(buf + length, "\trff1=%u", ssi_private->stats.rff1);
+       length += sprintf(buf + length, "\trff0=%u", ssi_private->stats.rff0);
+       length += sprintf(buf + length, "\ttfe1=%u", ssi_private->stats.tfe1);
+       length += sprintf(buf + length, "\ttfe0=%u\n", ssi_private->stats.tfe0);
+
+       return length;
+}
+
+/**
+ * fsl_ssi_create_dai: create a snd_soc_cpu_dai structure
+ *
+ * This function is called by the machine driver to create a snd_soc_cpu_dai
+ * structure.  The function creates an ssi_private object, which contains
+ * the snd_soc_cpu_dai.  It also creates the sysfs statistics device.
+ */
+struct snd_soc_cpu_dai *fsl_ssi_create_dai(struct fsl_ssi_info *ssi_info)
+{
+       struct snd_soc_cpu_dai *fsl_ssi_dai;
+       struct fsl_ssi_private *ssi_private;
+       int ret = 0;
+       struct device_attribute *dev_attr;
+
+       ssi_private = kzalloc(sizeof(struct fsl_ssi_private), GFP_KERNEL);
+       if (!ssi_private) {
+               dev_err(ssi_info->dev, "could not allocate DAI object\n");
+               return NULL;
+       }
+       memcpy(&ssi_private->cpu_dai, &fsl_ssi_dai_template,
+              sizeof(struct snd_soc_cpu_dai));
+
+       fsl_ssi_dai = &ssi_private->cpu_dai;
+       dev_attr = &ssi_private->dev_attr;
+
+       sprintf(ssi_private->name, "ssi%u", (u8) ssi_info->id);
+       ssi_private->ssi = ssi_info->ssi;
+       ssi_private->ssi_phys = ssi_info->ssi_phys;
+       ssi_private->irq = ssi_info->irq;
+       ssi_private->dev = ssi_info->dev;
+
+       ssi_private->dev->driver_data = fsl_ssi_dai;
+
+       /* Initialize the the device_attribute structure */
+       dev_attr->attr.name = "ssi-stats";
+       dev_attr->attr.mode = S_IRUGO;
+       dev_attr->show = fsl_sysfs_ssi_show;
+
+       ret = device_create_file(ssi_private->dev, dev_attr);
+       if (ret) {
+               dev_err(ssi_info->dev, "could not create sysfs %s file\n",
+                       ssi_private->dev_attr.attr.name);
+               kfree(fsl_ssi_dai);
+               return NULL;
+       }
+
+       fsl_ssi_dai->private_data = ssi_private;
+       fsl_ssi_dai->name = ssi_private->name;
+       fsl_ssi_dai->id = ssi_info->id;
+
+       return fsl_ssi_dai;
+}
+EXPORT_SYMBOL_GPL(fsl_ssi_create_dai);
+
+/**
+ * fsl_ssi_destroy_dai: destroy the snd_soc_cpu_dai object
+ *
+ * This function undoes the operations of fsl_ssi_create_dai()
+ */
+void fsl_ssi_destroy_dai(struct snd_soc_cpu_dai *fsl_ssi_dai)
+{
+       struct fsl_ssi_private *ssi_private =
+       container_of(fsl_ssi_dai, struct fsl_ssi_private, cpu_dai);
+
+       device_remove_file(ssi_private->dev, &ssi_private->dev_attr);
+
+       kfree(ssi_private);
+}
+EXPORT_SYMBOL_GPL(fsl_ssi_destroy_dai);
+
+MODULE_AUTHOR("Timur Tabi <timur@freescale.com>");
+MODULE_DESCRIPTION("Freescale Synchronous Serial Interface (SSI) ASoC Driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/fsl/fsl_ssi.h b/sound/soc/fsl/fsl_ssi.h
new file mode 100644 (file)
index 0000000..c5ce88e
--- /dev/null
@@ -0,0 +1,224 @@
+/*
+ * fsl_ssi.h - ALSA SSI interface for the Freescale MPC8610 SoC
+ *
+ * Author: Timur Tabi <timur@freescale.com>
+ *
+ * Copyright 2007-2008 Freescale Semiconductor, Inc.  This file is licensed
+ * under the terms of the GNU General Public License version 2.  This
+ * program is licensed "as is" without any warranty of any kind, whether
+ * express or implied.
+ */
+
+#ifndef _MPC8610_I2S_H
+#define _MPC8610_I2S_H
+
+/* SSI Register Map */
+struct ccsr_ssi {
+       __be32 stx0;    /* 0x.0000 - SSI Transmit Data Register 0 */
+       __be32 stx1;    /* 0x.0004 - SSI Transmit Data Register 1 */
+       __be32 srx0;    /* 0x.0008 - SSI Receive Data Register 0 */
+       __be32 srx1;    /* 0x.000C - SSI Receive Data Register 1 */
+       __be32 scr;     /* 0x.0010 - SSI Control Register */
+       __be32 sisr;    /* 0x.0014 - SSI Interrupt Status Register Mixed */
+       __be32 sier;    /* 0x.0018 - SSI Interrupt Enable Register */
+       __be32 stcr;    /* 0x.001C - SSI Transmit Configuration Register */
+       __be32 srcr;    /* 0x.0020 - SSI Receive Configuration Register */
+       __be32 stccr;   /* 0x.0024 - SSI Transmit Clock Control Register */
+       __be32 srccr;   /* 0x.0028 - SSI Receive Clock Control Register */
+       __be32 sfcsr;   /* 0x.002C - SSI FIFO Control/Status Register */
+       __be32 str;     /* 0x.0030 - SSI Test Register */
+       __be32 sor;     /* 0x.0034 - SSI Option Register */
+       __be32 sacnt;   /* 0x.0038 - SSI AC97 Control Register */
+       __be32 sacadd;  /* 0x.003C - SSI AC97 Command Address Register */
+       __be32 sacdat;  /* 0x.0040 - SSI AC97 Command Data Register */
+       __be32 satag;   /* 0x.0044 - SSI AC97 Tag Register */
+       __be32 stmsk;   /* 0x.0048 - SSI Transmit Time Slot Mask Register */
+       __be32 srmsk;   /* 0x.004C - SSI Receive Time Slot Mask Register */
+       __be32 saccst;  /* 0x.0050 - SSI AC97 Channel Status Register */
+       __be32 saccen;  /* 0x.0054 - SSI AC97 Channel Enable Register */
+       __be32 saccdis; /* 0x.0058 - SSI AC97 Channel Disable Register */
+};
+
+#define CCSR_SSI_SCR_RFR_CLK_DIS       0x00000800
+#define CCSR_SSI_SCR_TFR_CLK_DIS       0x00000400
+#define CCSR_SSI_SCR_TCH_EN            0x00000100
+#define CCSR_SSI_SCR_SYS_CLK_EN                0x00000080
+#define CCSR_SSI_SCR_I2S_MODE_MASK     0x00000060
+#define CCSR_SSI_SCR_I2S_MODE_NORMAL   0x00000000
+#define CCSR_SSI_SCR_I2S_MODE_MASTER   0x00000020
+#define CCSR_SSI_SCR_I2S_MODE_SLAVE    0x00000040
+#define CCSR_SSI_SCR_SYN               0x00000010
+#define CCSR_SSI_SCR_NET               0x00000008
+#define CCSR_SSI_SCR_RE                        0x00000004
+#define CCSR_SSI_SCR_TE                        0x00000002
+#define CCSR_SSI_SCR_SSIEN             0x00000001
+
+#define CCSR_SSI_SISR_RFRC             0x01000000
+#define CCSR_SSI_SISR_TFRC             0x00800000
+#define CCSR_SSI_SISR_CMDAU            0x00040000
+#define CCSR_SSI_SISR_CMDDU            0x00020000
+#define CCSR_SSI_SISR_RXT              0x00010000
+#define CCSR_SSI_SISR_RDR1             0x00008000
+#define CCSR_SSI_SISR_RDR0             0x00004000
+#define CCSR_SSI_SISR_TDE1             0x00002000
+#define CCSR_SSI_SISR_TDE0             0x00001000
+#define CCSR_SSI_SISR_ROE1             0x00000800
+#define CCSR_SSI_SISR_ROE0             0x00000400
+#define CCSR_SSI_SISR_TUE1             0x00000200
+#define CCSR_SSI_SISR_TUE0             0x00000100
+#define CCSR_SSI_SISR_TFS              0x00000080
+#define CCSR_SSI_SISR_RFS              0x00000040
+#define CCSR_SSI_SISR_TLS              0x00000020
+#define CCSR_SSI_SISR_RLS              0x00000010
+#define CCSR_SSI_SISR_RFF1             0x00000008
+#define CCSR_SSI_SISR_RFF0             0x00000004
+#define CCSR_SSI_SISR_TFE1             0x00000002
+#define CCSR_SSI_SISR_TFE0             0x00000001
+
+#define CCSR_SSI_SIER_RFRC_EN          0x01000000
+#define CCSR_SSI_SIER_TFRC_EN          0x00800000
+#define CCSR_SSI_SIER_RDMAE            0x00400000
+#define CCSR_SSI_SIER_RIE              0x00200000
+#define CCSR_SSI_SIER_TDMAE            0x00100000
+#define CCSR_SSI_SIER_TIE              0x00080000
+#define CCSR_SSI_SIER_CMDAU_EN         0x00040000
+#define CCSR_SSI_SIER_CMDDU_EN         0x00020000
+#define CCSR_SSI_SIER_RXT_EN           0x00010000
+#define CCSR_SSI_SIER_RDR1_EN          0x00008000
+#define CCSR_SSI_SIER_RDR0_EN          0x00004000
+#define CCSR_SSI_SIER_TDE1_EN          0x00002000
+#define CCSR_SSI_SIER_TDE0_EN          0x00001000
+#define CCSR_SSI_SIER_ROE1_EN          0x00000800
+#define CCSR_SSI_SIER_ROE0_EN          0x00000400
+#define CCSR_SSI_SIER_TUE1_EN          0x00000200
+#define CCSR_SSI_SIER_TUE0_EN          0x00000100
+#define CCSR_SSI_SIER_TFS_EN           0x00000080
+#define CCSR_SSI_SIER_RFS_EN           0x00000040
+#define CCSR_SSI_SIER_TLS_EN           0x00000020
+#define CCSR_SSI_SIER_RLS_EN           0x00000010
+#define CCSR_SSI_SIER_RFF1_EN          0x00000008
+#define CCSR_SSI_SIER_RFF0_EN          0x00000004
+#define CCSR_SSI_SIER_TFE1_EN          0x00000002
+#define CCSR_SSI_SIER_TFE0_EN          0x00000001
+
+#define CCSR_SSI_STCR_TXBIT0           0x00000200
+#define CCSR_SSI_STCR_TFEN1            0x00000100
+#define CCSR_SSI_STCR_TFEN0            0x00000080
+#define CCSR_SSI_STCR_TFDIR            0x00000040
+#define CCSR_SSI_STCR_TXDIR            0x00000020
+#define CCSR_SSI_STCR_TSHFD            0x00000010
+#define CCSR_SSI_STCR_TSCKP            0x00000008
+#define CCSR_SSI_STCR_TFSI             0x00000004
+#define CCSR_SSI_STCR_TFSL             0x00000002
+#define CCSR_SSI_STCR_TEFS             0x00000001
+
+#define CCSR_SSI_SRCR_RXEXT            0x00000400
+#define CCSR_SSI_SRCR_RXBIT0           0x00000200
+#define CCSR_SSI_SRCR_RFEN1            0x00000100
+#define CCSR_SSI_SRCR_RFEN0            0x00000080
+#define CCSR_SSI_SRCR_RFDIR            0x00000040
+#define CCSR_SSI_SRCR_RXDIR            0x00000020
+#define CCSR_SSI_SRCR_RSHFD            0x00000010
+#define CCSR_SSI_SRCR_RSCKP            0x00000008
+#define CCSR_SSI_SRCR_RFSI             0x00000004
+#define CCSR_SSI_SRCR_RFSL             0x00000002
+#define CCSR_SSI_SRCR_REFS             0x00000001
+
+/* STCCR and SRCCR */
+#define CCSR_SSI_SxCCR_DIV2            0x00040000
+#define CCSR_SSI_SxCCR_PSR             0x00020000
+#define CCSR_SSI_SxCCR_WL_SHIFT                13
+#define CCSR_SSI_SxCCR_WL_MASK         0x0001E000
+#define CCSR_SSI_SxCCR_WL(x) \
+       (((((x) / 2) - 1) << CCSR_SSI_SxCCR_WL_SHIFT) & CCSR_SSI_SxCCR_WL_MASK)
+#define CCSR_SSI_SxCCR_DC_SHIFT                8
+#define CCSR_SSI_SxCCR_DC_MASK         0x00001F00
+#define CCSR_SSI_SxCCR_DC(x) \
+       ((((x) - 1) << CCSR_SSI_SxCCR_DC_SHIFT) & CCSR_SSI_SxCCR_DC_MASK)
+#define CCSR_SSI_SxCCR_PM_SHIFT                0
+#define CCSR_SSI_SxCCR_PM_MASK         0x000000FF
+#define CCSR_SSI_SxCCR_PM(x) \
+       ((((x) - 1) << CCSR_SSI_SxCCR_PM_SHIFT) & CCSR_SSI_SxCCR_PM_MASK)
+
+/*
+ * The xFCNT bits are read-only, and the xFWM bits are read/write.  Use the
+ * CCSR_SSI_SFCSR_xFCNTy() macros to read the FIFO counters, and use the
+ * CCSR_SSI_SFCSR_xFWMy() macros to set the watermarks.
+ */
+#define CCSR_SSI_SFCSR_RFCNT1_SHIFT    28
+#define CCSR_SSI_SFCSR_RFCNT1_MASK     0xF0000000
+#define CCSR_SSI_SFCSR_RFCNT1(x) \
+       (((x) & CCSR_SSI_SFCSR_RFCNT1_MASK) >> CCSR_SSI_SFCSR_RFCNT1_SHIFT)
+#define CCSR_SSI_SFCSR_TFCNT1_SHIFT    24
+#define CCSR_SSI_SFCSR_TFCNT1_MASK     0x0F000000
+#define CCSR_SSI_SFCSR_TFCNT1(x) \
+       (((x) & CCSR_SSI_SFCSR_TFCNT1_MASK) >> CCSR_SSI_SFCSR_TFCNT1_SHIFT)
+#define CCSR_SSI_SFCSR_RFWM1_SHIFT     20
+#define CCSR_SSI_SFCSR_RFWM1_MASK      0x00F00000
+#define CCSR_SSI_SFCSR_RFWM1(x)        \
+       (((x) << CCSR_SSI_SFCSR_RFWM1_SHIFT) & CCSR_SSI_SFCSR_RFWM1_MASK)
+#define CCSR_SSI_SFCSR_TFWM1_SHIFT     16
+#define CCSR_SSI_SFCSR_TFWM1_MASK      0x000F0000
+#define CCSR_SSI_SFCSR_TFWM1(x)        \
+       (((x) << CCSR_SSI_SFCSR_TFWM1_SHIFT) & CCSR_SSI_SFCSR_TFWM1_MASK)
+#define CCSR_SSI_SFCSR_RFCNT0_SHIFT    12
+#define CCSR_SSI_SFCSR_RFCNT0_MASK     0x0000F000
+#define CCSR_SSI_SFCSR_RFCNT0(x) \
+       (((x) & CCSR_SSI_SFCSR_RFCNT0_MASK) >> CCSR_SSI_SFCSR_RFCNT0_SHIFT)
+#define CCSR_SSI_SFCSR_TFCNT0_SHIFT    8
+#define CCSR_SSI_SFCSR_TFCNT0_MASK     0x00000F00
+#define CCSR_SSI_SFCSR_TFCNT0(x) \
+       (((x) & CCSR_SSI_SFCSR_TFCNT0_MASK) >> CCSR_SSI_SFCSR_TFCNT0_SHIFT)
+#define CCSR_SSI_SFCSR_RFWM0_SHIFT     4
+#define CCSR_SSI_SFCSR_RFWM0_MASK      0x000000F0
+#define CCSR_SSI_SFCSR_RFWM0(x)        \
+       (((x) << CCSR_SSI_SFCSR_RFWM0_SHIFT) & CCSR_SSI_SFCSR_RFWM0_MASK)
+#define CCSR_SSI_SFCSR_TFWM0_SHIFT     0
+#define CCSR_SSI_SFCSR_TFWM0_MASK      0x0000000F
+#define CCSR_SSI_SFCSR_TFWM0(x)        \
+       (((x) << CCSR_SSI_SFCSR_TFWM0_SHIFT) & CCSR_SSI_SFCSR_TFWM0_MASK)
+
+#define CCSR_SSI_STR_TEST              0x00008000
+#define CCSR_SSI_STR_RCK2TCK           0x00004000
+#define CCSR_SSI_STR_RFS2TFS           0x00002000
+#define CCSR_SSI_STR_RXSTATE(x) (((x) >> 8) & 0x1F)
+#define CCSR_SSI_STR_TXD2RXD           0x00000080
+#define CCSR_SSI_STR_TCK2RCK           0x00000040
+#define CCSR_SSI_STR_TFS2RFS           0x00000020
+#define CCSR_SSI_STR_TXSTATE(x) ((x) & 0x1F)
+
+#define CCSR_SSI_SOR_CLKOFF            0x00000040
+#define CCSR_SSI_SOR_RX_CLR            0x00000020
+#define CCSR_SSI_SOR_TX_CLR            0x00000010
+#define CCSR_SSI_SOR_INIT              0x00000008
+#define CCSR_SSI_SOR_WAIT_SHIFT                1
+#define CCSR_SSI_SOR_WAIT_MASK         0x00000006
+#define CCSR_SSI_SOR_WAIT(x) (((x) & 3) << CCSR_SSI_SOR_WAIT_SHIFT)
+#define CCSR_SSI_SOR_SYNRST            0x00000001
+
+/* Instantiation data for an SSI interface
+ *
+ * This structure contains all the information that the the SSI driver needs
+ * to instantiate an SSI interface with ALSA.  The machine driver should
+ * create this structure, fill it in, call fsl_ssi_create_dai(), and then
+ * delete the structure.
+ *
+ * id: which SSI this is (0, 1, etc. )
+ * ssi: pointer to the SSI's registers
+ * ssi_phys: physical address of the SSI registers
+ * irq: IRQ of this SSI
+ * dev: struct device, used to create the sysfs statistics file
+*/
+struct fsl_ssi_info {
+       unsigned int id;
+       struct ccsr_ssi __iomem *ssi;
+       dma_addr_t ssi_phys;
+       unsigned int irq;
+       struct device *dev;
+};
+
+struct snd_soc_cpu_dai *fsl_ssi_create_dai(struct fsl_ssi_info *ssi_info);
+void fsl_ssi_destroy_dai(struct snd_soc_cpu_dai *fsl_ssi_dai);
+
+#endif
+
diff --git a/sound/soc/fsl/mpc8610_hpcd.c b/sound/soc/fsl/mpc8610_hpcd.c
new file mode 100644 (file)
index 0000000..f26c4b2
--- /dev/null
@@ -0,0 +1,631 @@
+/**
+ * Freescale MPC8610HPCD ALSA SoC Fabric driver
+ *
+ * Author: Timur Tabi <timur@freescale.com>
+ *
+ * Copyright 2007-2008 Freescale Semiconductor, Inc.  This file is licensed
+ * under the terms of the GNU General Public License version 2.  This
+ * program is licensed "as is" without any warranty of any kind, whether
+ * express or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+#include <sound/soc.h>
+#include <asm/immap_86xx.h>
+
+#include "../codecs/cs4270.h"
+#include "fsl_dma.h"
+#include "fsl_ssi.h"
+
+/**
+ * mpc8610_hpcd_data: fabric-specific ASoC device data
+ *
+ * This structure contains data for a single sound platform device on an
+ * MPC8610 HPCD.  Some of the data is taken from the device tree.
+ */
+struct mpc8610_hpcd_data {
+       struct snd_soc_device sound_devdata;
+       struct snd_soc_dai_link dai;
+       struct snd_soc_machine machine;
+       unsigned int dai_format;
+       unsigned int codec_clk_direction;
+       unsigned int cpu_clk_direction;
+       unsigned int clk_frequency;
+       struct ccsr_guts __iomem *guts;
+       struct ccsr_ssi __iomem *ssi;
+       unsigned int ssi_id;            /* 0 = SSI1, 1 = SSI2, etc */
+       unsigned int ssi_irq;
+       unsigned int dma_id;            /* 0 = DMA1, 1 = DMA2, etc */
+       unsigned int dma_irq[2];
+       struct ccsr_dma_channel __iomem *dma[2];
+       unsigned int dma_channel_id[2]; /* 0 = ch 0, 1 = ch 1, etc*/
+};
+
+/**
+ * mpc8610_hpcd_machine_probe: initalize the board
+ *
+ * This function is called when platform_device_add() is called.  It is used
+ * to initialize the board-specific hardware.
+ *
+ * Here we program the DMACR and PMUXCR registers.
+ */
+static int mpc8610_hpcd_machine_probe(struct platform_device *sound_device)
+{
+       struct mpc8610_hpcd_data *machine_data =
+               sound_device->dev.platform_data;
+
+       /* Program the signal routing between the SSI and the DMA */
+       guts_set_dmacr(machine_data->guts, machine_data->dma_id + 1,
+               machine_data->dma_channel_id[0], CCSR_GUTS_DMACR_DEV_SSI);
+       guts_set_dmacr(machine_data->guts, machine_data->dma_id + 1,
+               machine_data->dma_channel_id[1], CCSR_GUTS_DMACR_DEV_SSI);
+
+       guts_set_pmuxcr_dma(machine_data->guts, machine_data->dma_id,
+               machine_data->dma_channel_id[0], 0);
+       guts_set_pmuxcr_dma(machine_data->guts, machine_data->dma_id,
+               machine_data->dma_channel_id[1], 0);
+
+       guts_set_pmuxcr_dma(machine_data->guts, 1, 0, 0);
+       guts_set_pmuxcr_dma(machine_data->guts, 1, 3, 0);
+       guts_set_pmuxcr_dma(machine_data->guts, 0, 3, 0);
+
+       switch (machine_data->ssi_id) {
+       case 0:
+               clrsetbits_be32(&machine_data->guts->pmuxcr,
+                       CCSR_GUTS_PMUXCR_SSI1_MASK, CCSR_GUTS_PMUXCR_SSI1_SSI);
+               break;
+       case 1:
+               clrsetbits_be32(&machine_data->guts->pmuxcr,
+                       CCSR_GUTS_PMUXCR_SSI2_MASK, CCSR_GUTS_PMUXCR_SSI2_SSI);
+               break;
+       }
+
+       return 0;
+}
+
+/**
+ * mpc8610_hpcd_startup: program the board with various hardware parameters
+ *
+ * This function takes board-specific information, like clock frequencies
+ * and serial data formats, and passes that information to the codec and
+ * transport drivers.
+ */
+static int mpc8610_hpcd_startup(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai;
+       struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
+       struct mpc8610_hpcd_data *machine_data =
+               rtd->socdev->dev->platform_data;
+       int ret = 0;
+
+       /* Tell the CPU driver what the serial protocol is. */
+       if (cpu_dai->dai_ops.set_fmt) {
+               ret = cpu_dai->dai_ops.set_fmt(cpu_dai,
+                       machine_data->dai_format);
+               if (ret < 0) {
+                       dev_err(substream->pcm->card->dev,
+                               "could not set CPU driver audio format\n");
+                       return ret;
+               }
+       }
+
+       /* Tell the codec driver what the serial protocol is. */
+       if (codec_dai->dai_ops.set_fmt) {
+               ret = codec_dai->dai_ops.set_fmt(codec_dai,
+                       machine_data->dai_format);
+               if (ret < 0) {
+                       dev_err(substream->pcm->card->dev,
+                               "could not set codec driver audio format\n");
+                       return ret;
+               }
+       }
+
+       /*
+        * Tell the CPU driver what the clock frequency is, and whether it's a
+        * slave or master.
+        */
+       if (cpu_dai->dai_ops.set_sysclk) {
+               ret = cpu_dai->dai_ops.set_sysclk(cpu_dai, 0,
+                       machine_data->clk_frequency,
+                       machine_data->cpu_clk_direction);
+               if (ret < 0) {
+                       dev_err(substream->pcm->card->dev,
+                               "could not set CPU driver clock parameters\n");
+                       return ret;
+               }
+       }
+
+       /*
+        * Tell the codec driver what the MCLK frequency is, and whether it's
+        * a slave or master.
+        */
+       if (codec_dai->dai_ops.set_sysclk) {
+               ret = codec_dai->dai_ops.set_sysclk(codec_dai, 0,
+                       machine_data->clk_frequency,
+                       machine_data->codec_clk_direction);
+               if (ret < 0) {
+                       dev_err(substream->pcm->card->dev,
+                               "could not set codec driver clock params\n");
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+/**
+ * mpc8610_hpcd_machine_remove: Remove the sound device
+ *
+ * This function is called to remove the sound device for one SSI.  We
+ * de-program the DMACR and PMUXCR register.
+ */
+int mpc8610_hpcd_machine_remove(struct platform_device *sound_device)
+{
+       struct mpc8610_hpcd_data *machine_data =
+               sound_device->dev.platform_data;
+
+       /* Restore the signal routing */
+
+       guts_set_dmacr(machine_data->guts, machine_data->dma_id + 1,
+               machine_data->dma_channel_id[0], 0);
+       guts_set_dmacr(machine_data->guts, machine_data->dma_id + 1,
+               machine_data->dma_channel_id[1], 0);
+
+       switch (machine_data->ssi_id) {
+       case 0:
+               clrsetbits_be32(&machine_data->guts->pmuxcr,
+                       CCSR_GUTS_PMUXCR_SSI1_MASK, CCSR_GUTS_PMUXCR_SSI1_LA);
+               break;
+       case 1:
+               clrsetbits_be32(&machine_data->guts->pmuxcr,
+                       CCSR_GUTS_PMUXCR_SSI2_MASK, CCSR_GUTS_PMUXCR_SSI1_LA);
+               break;
+       }
+
+       return 0;
+}
+
+/**
+ * mpc8610_hpcd_ops: ASoC fabric driver operations
+ */
+static struct snd_soc_ops mpc8610_hpcd_ops = {
+       .startup = mpc8610_hpcd_startup,
+};
+
+/**
+ * mpc8610_hpcd_machine: ASoC machine data
+ */
+static struct snd_soc_machine mpc8610_hpcd_machine = {
+       .probe = mpc8610_hpcd_machine_probe,
+       .remove = mpc8610_hpcd_machine_remove,
+       .name = "MPC8610 HPCD",
+       .num_links = 1,
+};
+
+/**
+ * mpc8610_hpcd_probe: OF probe function for the fabric driver
+ *
+ * This function gets called when an SSI node is found in the device tree.
+ *
+ * Although this is a fabric driver, the SSI node is the "master" node with
+ * respect to audio hardware connections.  Therefore, we create a new ASoC
+ * device for each new SSI node that has a codec attached.
+ *
+ * FIXME: Currently, we only support one DMA controller, so if there are
+ * multiple SSI nodes with codecs, only the first will be supported.
+ *
+ * FIXME: Even if we did support multiple DMA controllers, we have no
+ * mechanism for assigning DMA controllers and channels to the individual
+ * SSI devices.  We also probably aren't compatible with the generic Elo DMA
+ * device driver.
+ */
+static int mpc8610_hpcd_probe(struct of_device *ofdev,
+       const struct of_device_id *match)
+{
+       struct device_node *np = ofdev->node;
+       struct device_node *codec_np = NULL;
+       struct device_node *guts_np = NULL;
+       struct device_node *dma_np = NULL;
+       struct device_node *dma_channel_np = NULL;
+       const phandle *codec_ph;
+       const char *sprop;
+       const u32 *iprop;
+       struct resource res;
+       struct platform_device *sound_device = NULL;
+       struct mpc8610_hpcd_data *machine_data;
+       struct fsl_ssi_info ssi_info;
+       struct fsl_dma_info dma_info;
+       int ret = -ENODEV;
+
+       machine_data = kzalloc(sizeof(struct mpc8610_hpcd_data), GFP_KERNEL);
+       if (!machine_data)
+               return -ENOMEM;
+
+       memset(&ssi_info, 0, sizeof(ssi_info));
+       memset(&dma_info, 0, sizeof(dma_info));
+
+       ssi_info.dev = &ofdev->dev;
+
+       /*
+        * We are only interested in SSIs with a codec phandle in them, so let's
+        * make sure this SSI has one.
+        */
+       codec_ph = of_get_property(np, "codec-handle", NULL);
+       if (!codec_ph)
+               goto error;
+
+       codec_np = of_find_node_by_phandle(*codec_ph);
+       if (!codec_np)
+               goto error;
+
+       /* The MPC8610 HPCD only knows about the CS4270 codec, so reject
+          anything else. */
+       if (!of_device_is_compatible(codec_np, "cirrus,cs4270"))
+               goto error;
+
+       /* Get the device ID */
+       iprop = of_get_property(np, "cell-index", NULL);
+       if (!iprop) {
+               dev_err(&ofdev->dev, "cell-index property not found\n");
+               ret = -EINVAL;
+               goto error;
+       }
+       machine_data->ssi_id = *iprop;
+       ssi_info.id = *iprop;
+
+       /* Get the serial format and clock direction. */
+       sprop = of_get_property(np, "fsl,mode", NULL);
+       if (!sprop) {
+               dev_err(&ofdev->dev, "fsl,mode property not found\n");
+               ret = -EINVAL;
+               goto error;
+       }
+
+       if (strcasecmp(sprop, "i2s-slave") == 0) {
+               machine_data->dai_format = SND_SOC_DAIFMT_I2S;
+               machine_data->codec_clk_direction = SND_SOC_CLOCK_OUT;
+               machine_data->cpu_clk_direction = SND_SOC_CLOCK_IN;
+
+               /*
+                * In i2s-slave mode, the codec has its own clock source, so we
+                * need to get the frequency from the device tree and pass it to
+                * the codec driver.
+                */
+               iprop = of_get_property(codec_np, "clock-frequency", NULL);
+               if (!iprop || !*iprop) {
+                       dev_err(&ofdev->dev, "codec bus-frequency property "
+                               "is missing or invalid\n");
+                       ret = -EINVAL;
+                       goto error;
+               }
+               machine_data->clk_frequency = *iprop;
+       } else if (strcasecmp(sprop, "i2s-master") == 0) {
+               machine_data->dai_format = SND_SOC_DAIFMT_I2S;
+               machine_data->codec_clk_direction = SND_SOC_CLOCK_IN;
+               machine_data->cpu_clk_direction = SND_SOC_CLOCK_OUT;
+       } else if (strcasecmp(sprop, "lj-slave") == 0) {
+               machine_data->dai_format = SND_SOC_DAIFMT_LEFT_J;
+               machine_data->codec_clk_direction = SND_SOC_CLOCK_OUT;
+               machine_data->cpu_clk_direction = SND_SOC_CLOCK_IN;
+       } else if (strcasecmp(sprop, "lj-master") == 0) {
+               machine_data->dai_format = SND_SOC_DAIFMT_LEFT_J;
+               machine_data->codec_clk_direction = SND_SOC_CLOCK_IN;
+               machine_data->cpu_clk_direction = SND_SOC_CLOCK_OUT;
+       } else if (strcasecmp(sprop, "rj-master") == 0) {
+               machine_data->dai_format = SND_SOC_DAIFMT_RIGHT_J;
+               machine_data->codec_clk_direction = SND_SOC_CLOCK_OUT;
+               machine_data->cpu_clk_direction = SND_SOC_CLOCK_IN;
+       } else if (strcasecmp(sprop, "rj-master") == 0) {
+               machine_data->dai_format = SND_SOC_DAIFMT_RIGHT_J;
+               machine_data->codec_clk_direction = SND_SOC_CLOCK_IN;
+               machine_data->cpu_clk_direction = SND_SOC_CLOCK_OUT;
+       } else if (strcasecmp(sprop, "ac97-slave") == 0) {
+               machine_data->dai_format = SND_SOC_DAIFMT_AC97;
+               machine_data->codec_clk_direction = SND_SOC_CLOCK_OUT;
+               machine_data->cpu_clk_direction = SND_SOC_CLOCK_IN;
+       } else if (strcasecmp(sprop, "ac97-master") == 0) {
+               machine_data->dai_format = SND_SOC_DAIFMT_AC97;
+               machine_data->codec_clk_direction = SND_SOC_CLOCK_IN;
+               machine_data->cpu_clk_direction = SND_SOC_CLOCK_OUT;
+       } else {
+               dev_err(&ofdev->dev,
+                       "unrecognized fsl,mode property \"%s\"\n", sprop);
+               ret = -EINVAL;
+               goto error;
+       }
+
+       if (!machine_data->clk_frequency) {
+               dev_err(&ofdev->dev, "unknown clock frequency\n");
+               ret = -EINVAL;
+               goto error;
+       }
+
+       /* Read the SSI information from the device tree */
+       ret = of_address_to_resource(np, 0, &res);
+       if (ret) {
+               dev_err(&ofdev->dev, "could not obtain SSI address\n");
+               goto error;
+       }
+       if (!res.start) {
+               dev_err(&ofdev->dev, "invalid SSI address\n");
+               goto error;
+       }
+       ssi_info.ssi_phys = res.start;
+
+       machine_data->ssi = ioremap(ssi_info.ssi_phys, sizeof(struct ccsr_ssi));
+       if (!machine_data->ssi) {
+               dev_err(&ofdev->dev, "could not map SSI address %x\n",
+                       ssi_info.ssi_phys);
+               ret = -EINVAL;
+               goto error;
+       }
+       ssi_info.ssi = machine_data->ssi;
+
+
+       /* Get the IRQ of the SSI */
+       machine_data->ssi_irq = irq_of_parse_and_map(np, 0);
+       if (!machine_data->ssi_irq) {
+               dev_err(&ofdev->dev, "could not get SSI IRQ\n");
+               ret = -EINVAL;
+               goto error;
+       }
+       ssi_info.irq = machine_data->ssi_irq;
+
+
+       /* Map the global utilities registers. */
+       guts_np = of_find_compatible_node(NULL, NULL, "fsl,mpc8610-guts");
+       if (!guts_np) {
+               dev_err(&ofdev->dev, "could not obtain address of GUTS\n");
+               ret = -EINVAL;
+               goto error;
+       }
+       machine_data->guts = of_iomap(guts_np, 0);
+       of_node_put(guts_np);
+       if (!machine_data->guts) {
+               dev_err(&ofdev->dev, "could not map GUTS\n");
+               ret = -EINVAL;
+               goto error;
+       }
+
+       /* Find the DMA channels to use.  For now, we always use the first DMA
+          controller. */
+       for_each_compatible_node(dma_np, NULL, "fsl,mpc8610-dma") {
+               iprop = of_get_property(dma_np, "cell-index", NULL);
+               if (iprop && (*iprop == 0)) {
+                       of_node_put(dma_np);
+                       break;
+               }
+       }
+       if (!dma_np) {
+               dev_err(&ofdev->dev, "could not find DMA node\n");
+               ret = -EINVAL;
+               goto error;
+       }
+       machine_data->dma_id = *iprop;
+
+       /*
+        * Find the DMA channels to use.  For now, we always use DMA channel 0
+        * for playback, and DMA channel 1 for capture.
+        */
+       while ((dma_channel_np = of_get_next_child(dma_np, dma_channel_np))) {
+               iprop = of_get_property(dma_channel_np, "cell-index", NULL);
+               /* Is it DMA channel 0? */
+               if (iprop && (*iprop == 0)) {
+                       /* dma_channel[0] and dma_irq[0] are for playback */
+                       dma_info.dma_channel[0] = of_iomap(dma_channel_np, 0);
+                       dma_info.dma_irq[0] =
+                               irq_of_parse_and_map(dma_channel_np, 0);
+                       machine_data->dma_channel_id[0] = *iprop;
+                       continue;
+               }
+               if (iprop && (*iprop == 1)) {
+                       /* dma_channel[1] and dma_irq[1] are for capture */
+                       dma_info.dma_channel[1] = of_iomap(dma_channel_np, 0);
+                       dma_info.dma_irq[1] =
+                               irq_of_parse_and_map(dma_channel_np, 0);
+                       machine_data->dma_channel_id[1] = *iprop;
+                       continue;
+               }
+       }
+       if (!dma_info.dma_channel[0] || !dma_info.dma_channel[1] ||
+           !dma_info.dma_irq[0] || !dma_info.dma_irq[1]) {
+               dev_err(&ofdev->dev, "could not find DMA channels\n");
+               ret = -EINVAL;
+               goto error;
+       }
+
+       dma_info.ssi_stx_phys = ssi_info.ssi_phys +
+               offsetof(struct ccsr_ssi, stx0);
+       dma_info.ssi_srx_phys = ssi_info.ssi_phys +
+               offsetof(struct ccsr_ssi, srx0);
+
+       /* We have the DMA information, so tell the DMA driver what it is */
+       if (!fsl_dma_configure(&dma_info)) {
+               dev_err(&ofdev->dev, "could not instantiate DMA device\n");
+               ret = -EBUSY;
+               goto error;
+       }
+
+       /*
+        * Initialize our DAI data structure.  We should probably get this
+        * information from the device tree.
+        */
+       machine_data->dai.name = "CS4270";
+       machine_data->dai.stream_name = "CS4270";
+
+       machine_data->dai.cpu_dai = fsl_ssi_create_dai(&ssi_info);
+       machine_data->dai.codec_dai = &cs4270_dai; /* The codec_dai we want */
+       machine_data->dai.ops = &mpc8610_hpcd_ops;
+
+       mpc8610_hpcd_machine.dai_link = &machine_data->dai;
+
+       /* Allocate a new audio platform device structure */
+       sound_device = platform_device_alloc("soc-audio", -1);
+       if (!sound_device) {
+               dev_err(&ofdev->dev, "platform device allocation failed\n");
+               ret = -ENOMEM;
+               goto error;
+       }
+
+       machine_data->sound_devdata.machine = &mpc8610_hpcd_machine;
+       machine_data->sound_devdata.codec_dev = &soc_codec_device_cs4270;
+       machine_data->sound_devdata.platform = &fsl_soc_platform;
+
+       sound_device->dev.platform_data = machine_data;
+
+
+       /* Set the platform device and ASoC device to point to each other */
+       platform_set_drvdata(sound_device, &machine_data->sound_devdata);
+
+       machine_data->sound_devdata.dev = &sound_device->dev;
+
+
+       /* Tell ASoC to probe us.  This will call mpc8610_hpcd_machine.probe(),
+          if it exists. */
+       ret = platform_device_add(sound_device);
+
+       if (ret) {
+               dev_err(&ofdev->dev, "platform device add failed\n");
+               goto error;
+       }
+
+       dev_set_drvdata(&ofdev->dev, sound_device);
+
+       return 0;
+
+error:
+       of_node_put(codec_np);
+       of_node_put(guts_np);
+       of_node_put(dma_np);
+       of_node_put(dma_channel_np);
+
+       if (sound_device)
+               platform_device_unregister(sound_device);
+
+       if (machine_data->dai.cpu_dai)
+               fsl_ssi_destroy_dai(machine_data->dai.cpu_dai);
+
+       if (ssi_info.ssi)
+               iounmap(ssi_info.ssi);
+
+       if (ssi_info.irq)
+               irq_dispose_mapping(ssi_info.irq);
+
+       if (dma_info.dma_channel[0])
+               iounmap(dma_info.dma_channel[0]);
+
+       if (dma_info.dma_channel[1])
+               iounmap(dma_info.dma_channel[1]);
+
+       if (dma_info.dma_irq[0])
+               irq_dispose_mapping(dma_info.dma_irq[0]);
+
+       if (dma_info.dma_irq[1])
+               irq_dispose_mapping(dma_info.dma_irq[1]);
+
+       if (machine_data->guts)
+               iounmap(machine_data->guts);
+
+       kfree(machine_data);
+
+       return ret;
+}
+
+/**
+ * mpc8610_hpcd_remove: remove the OF device
+ *
+ * This function is called when the OF device is removed.
+ */
+static int mpc8610_hpcd_remove(struct of_device *ofdev)
+{
+       struct platform_device *sound_device = dev_get_drvdata(&ofdev->dev);
+       struct mpc8610_hpcd_data *machine_data =
+               sound_device->dev.platform_data;
+
+       platform_device_unregister(sound_device);
+
+       if (machine_data->dai.cpu_dai)
+               fsl_ssi_destroy_dai(machine_data->dai.cpu_dai);
+
+       if (machine_data->ssi)
+               iounmap(machine_data->ssi);
+
+       if (machine_data->dma[0])
+               iounmap(machine_data->dma[0]);
+
+       if (machine_data->dma[1])
+               iounmap(machine_data->dma[1]);
+
+       if (machine_data->dma_irq[0])
+               irq_dispose_mapping(machine_data->dma_irq[0]);
+
+       if (machine_data->dma_irq[1])
+               irq_dispose_mapping(machine_data->dma_irq[1]);
+
+       if (machine_data->guts)
+               iounmap(machine_data->guts);
+
+       kfree(machine_data);
+       sound_device->dev.platform_data = NULL;
+
+       dev_set_drvdata(&ofdev->dev, NULL);
+
+       return 0;
+}
+
+static struct of_device_id mpc8610_hpcd_match[] = {
+       {
+               .compatible = "fsl,mpc8610-ssi",
+       },
+       {}
+};
+MODULE_DEVICE_TABLE(of, mpc8610_hpcd_match);
+
+static struct of_platform_driver mpc8610_hpcd_of_driver = {
+       .owner          = THIS_MODULE,
+       .name           = "mpc8610_hpcd",
+       .match_table    = mpc8610_hpcd_match,
+       .probe          = mpc8610_hpcd_probe,
+       .remove         = mpc8610_hpcd_remove,
+};
+
+/**
+ * mpc8610_hpcd_init: fabric driver initialization.
+ *
+ * This function is called when this module is loaded.
+ */
+static int __init mpc8610_hpcd_init(void)
+{
+       int ret;
+
+       printk(KERN_INFO "Freescale MPC8610 HPCD ALSA SoC fabric driver\n");
+
+       ret = of_register_platform_driver(&mpc8610_hpcd_of_driver);
+
+       if (ret)
+               printk(KERN_ERR
+                       "mpc8610-hpcd: failed to register platform driver\n");
+
+       return ret;
+}
+
+/**
+ * mpc8610_hpcd_exit: fabric driver exit
+ *
+ * This function is called when this driver is unloaded.
+ */
+static void __exit mpc8610_hpcd_exit(void)
+{
+       of_unregister_platform_driver(&mpc8610_hpcd_of_driver);
+}
+
+module_init(mpc8610_hpcd_init);
+module_exit(mpc8610_hpcd_exit);
+
+MODULE_AUTHOR("Timur Tabi <timur@freescale.com>");
+MODULE_DESCRIPTION("Freescale MPC8610 HPCD ALSA SoC fabric driver");
+MODULE_LICENSE("GPL");
index a83e22937c270ce0d92720203d73de99f8d1e434..484f883459e086a95af2ff2edd881b8c8b9a0500 100644 (file)
@@ -53,3 +53,12 @@ config SND_PXA2XX_SOC_TOSA
        help
          Say Y if you want to add support for SoC audio on Sharp
          Zaurus SL-C6000x models (Tosa).
+
+config SND_PXA2XX_SOC_E800
+       tristate "SoC AC97 Audio support for e800"
+       depends on SND_PXA2XX_SOC && MACH_E800
+       select SND_SOC_WM9712
+       select SND_PXA2XX_SOC_AC97
+       help
+         Say Y if you want to add support for SoC audio on the
+         Toshiba e800 PDA
index 78e0d6b07d1db9e4a8648166a55803bdabb385b1..04e5646f75ba3f8d77cc5a0caf4d162439c87b53 100644 (file)
@@ -11,10 +11,12 @@ obj-$(CONFIG_SND_PXA2XX_SOC_I2S) += snd-soc-pxa2xx-i2s.o
 snd-soc-corgi-objs := corgi.o
 snd-soc-poodle-objs := poodle.o
 snd-soc-tosa-objs := tosa.o
+snd-soc-e800-objs := e800_wm9712.o
 snd-soc-spitz-objs := spitz.o
 
 obj-$(CONFIG_SND_PXA2XX_SOC_CORGI) += snd-soc-corgi.o
 obj-$(CONFIG_SND_PXA2XX_SOC_POODLE) += snd-soc-poodle.o
 obj-$(CONFIG_SND_PXA2XX_SOC_TOSA) += snd-soc-tosa.o
+obj-$(CONFIG_SND_PXA2XX_SOC_E800) += snd-soc-e800.o
 obj-$(CONFIG_SND_PXA2XX_SOC_SPITZ) += snd-soc-spitz.o
 
index 5ee51a994ac3570752cc9ed081acdb6b6bb7841c..3f34e531bebf7921d210a05e583c937535095de1 100644 (file)
@@ -22,7 +22,6 @@
 #include <linux/timer.h>
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
-#include <sound/driver.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/soc.h>
diff --git a/sound/soc/pxa/e800_wm9712.c b/sound/soc/pxa/e800_wm9712.c
new file mode 100644 (file)
index 0000000..06e8afb
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * e800-wm9712.c  --  SoC audio for e800
+ *
+ * Based on tosa.c
+ *
+ * Copyright 2007 (c) Ian Molton <spyro@f2s.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 ONLY.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include <asm/mach-types.h>
+#include <asm/arch/pxa-regs.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/audio.h>
+
+#include "../codecs/wm9712.h"
+#include "pxa2xx-pcm.h"
+#include "pxa2xx-ac97.h"
+
+static struct snd_soc_machine e800;
+
+static struct snd_soc_dai_link e800_dai[] = {
+{
+       .name = "AC97 Aux",
+       .stream_name = "AC97 Aux",
+       .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX],
+       .codec_dai = &wm9712_dai[WM9712_DAI_AC97_AUX],
+},
+};
+
+static struct snd_soc_machine e800 = {
+       .name = "Toshiba e800",
+       .dai_link = e800_dai,
+       .num_links = ARRAY_SIZE(e800_dai),
+};
+
+static struct snd_soc_device e800_snd_devdata = {
+       .machine = &e800,
+       .platform = &pxa2xx_soc_platform,
+       .codec_dev = &soc_codec_dev_wm9712,
+};
+
+static struct platform_device *e800_snd_device;
+
+static int __init e800_init(void)
+{
+       int ret;
+
+       if (!machine_is_e800())
+               return -ENODEV;
+
+       e800_snd_device = platform_device_alloc("soc-audio", -1);
+       if (!e800_snd_device)
+               return -ENOMEM;
+
+       platform_set_drvdata(e800_snd_device, &e800_snd_devdata);
+       e800_snd_devdata.dev = &e800_snd_device->dev;
+       ret = platform_device_add(e800_snd_device);
+
+       if (ret)
+               platform_device_put(e800_snd_device);
+
+       return ret;
+}
+
+static void __exit e800_exit(void)
+{
+       platform_device_unregister(e800_snd_device);
+}
+
+module_init(e800_init);
+module_exit(e800_exit);
+
+/* Module information */
+MODULE_AUTHOR("Ian Molton <spyro@f2s.com>");
+MODULE_DESCRIPTION("ALSA SoC driver for e800");
+MODULE_LICENSE("GPL");
index 0915cf740421a809c69e35db07c577a28c78fdab..5ae59bd309a33863d05b3173c7e879df77a6372a 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/timer.h>
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
-#include <sound/driver.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/soc.h>
index 60e6f4677f932e4f3ed7037fe275884162ecb248..815c15336255d985d9f9e3a23f81c1b370043a47 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/wait.h>
 #include <linux/delay.h>
 
-#include <sound/driver.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/ac97_codec.h>
index 50c5c83f67db9ce636305e0259db13eced65b192..692b900024891646b96f5f8fb10f7b5339e7c5b2 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/module.h>
 #include <linux/device.h>
 #include <linux/delay.h>
-#include <sound/driver.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/initval.h>
index 35e8fa3a469c4745f4ff22bd188b19b79cf09067..daeaa4c8b876fc72b5441f0c662b220b1945081b 100644 (file)
@@ -16,7 +16,6 @@
 #include <linux/slab.h>
 #include <linux/dma-mapping.h>
 
-#include <sound/driver.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
index 4dd8f35312b300ea5a1c1e41ec4b431a0d74085e..d56709e15435e175cd533f7cd2badd558c3aded8 100644 (file)
@@ -22,7 +22,6 @@
 #include <linux/timer.h>
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
-#include <sound/driver.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/soc.h>
index 5504e30acf145508df4434af8239c3414cac8a61..e4d40b528ca47e6b85017ac52529b34fece23c55 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/moduleparam.h>
 #include <linux/device.h>
 
-#include <sound/driver.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/soc.h>
index 5632a2e1518d8dc48b242ad9579bccf2f136f6ec..1f6dbfc4caa85352412ba297e8094860e968fe00 100644 (file)
@@ -10,6 +10,9 @@ config SND_S3C24XX_SOC
 config SND_S3C24XX_SOC_I2S
        tristate
 
+config SND_S3C2412_SOC_I2S
+       tristate
+
 config SND_S3C2443_SOC_AC97
        tristate
        select AC97_BUS
@@ -34,4 +37,12 @@ config SND_S3C24XX_SOC_SMDK2443_WM9710
          Say Y if you want to add support for SoC audio on smdk2443
          with the WM9710.
 
+config SND_S3C24XX_SOC_LN2440SBC_ALC650
+       tristate "SoC AC97 Audio support for LN2440SBC - ALC650"
+       depends on SND_S3C24XX_SOC
+       select SND_S3C2443_SOC_AC97
+       select SND_SOC_AC97_CODEC
+       help
+         Say Y if you want to add support for SoC audio on ln2440sbc
+         with the ALC650.
 
index 13c92f0fa1e4a1905ea44b7a8019161eb0f78212..0aa5fb0b9700ae5d4db9ff3704da92aa18c7bfa9 100644 (file)
@@ -1,15 +1,19 @@
 # S3c24XX Platform Support
 snd-soc-s3c24xx-objs := s3c24xx-pcm.o
 snd-soc-s3c24xx-i2s-objs := s3c24xx-i2s.o
+snd-soc-s3c2412-i2s-objs := s3c2412-i2s.o
 snd-soc-s3c2443-ac97-objs := s3c2443-ac97.o
 
 obj-$(CONFIG_SND_S3C24XX_SOC) += snd-soc-s3c24xx.o
 obj-$(CONFIG_SND_S3C24XX_SOC_I2S) += snd-soc-s3c24xx-i2s.o
 obj-$(CONFIG_SND_S3C2443_SOC_AC97) += snd-soc-s3c2443-ac97.o
+obj-$(CONFIG_SND_S3C2412_SOC_I2S) += snd-soc-s3c2412-i2s.o
 
 # S3C24XX Machine Support
 snd-soc-neo1973-wm8753-objs := neo1973_wm8753.o
 snd-soc-smdk2443-wm9710-objs := smdk2443_wm9710.o
+snd-soc-ln2440sbc-alc650-objs := ln2440sbc_alc650.o
 
 obj-$(CONFIG_SND_S3C24XX_SOC_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o
 obj-$(CONFIG_SND_S3C24XX_SOC_SMDK2443_WM9710) += snd-soc-smdk2443-wm9710.o
+obj-$(CONFIG_SND_S3C24XX_SOC_LN2440SBC_ALC650) += snd-soc-ln2440sbc-alc650.o
diff --git a/sound/soc/s3c24xx/ln2440sbc_alc650.c b/sound/soc/s3c24xx/ln2440sbc_alc650.c
new file mode 100644 (file)
index 0000000..9ed8f2e
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * SoC audio for ln2440sbc
+ * 
+ * Copyright 2007 KonekTel, a.s.
+ * Author: Ivan Kuten
+ *         ivan.kuten@promwad.com
+ * 
+ * Heavily based on smdk2443_wm9710.c
+ * Copyright 2007 Wolfson Microelectronics PLC.
+ * Author: Graeme Gregory
+ *         graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include "../codecs/ac97.h"
+#include "s3c24xx-pcm.h"
+#include "s3c24xx-ac97.h"
+
+static struct snd_soc_machine ln2440sbc;
+
+static struct snd_soc_dai_link ln2440sbc_dai[] = {
+{
+       .name = "AC97",
+       .stream_name = "AC97 HiFi",
+       .cpu_dai = &s3c2443_ac97_dai[0],
+       .codec_dai = &ac97_dai,
+},
+};
+
+static struct snd_soc_machine ln2440sbc = {
+       .name = "LN2440SBC",
+       .dai_link = ln2440sbc_dai,
+       .num_links = ARRAY_SIZE(ln2440sbc_dai),
+};
+
+static struct snd_soc_device ln2440sbc_snd_ac97_devdata = {
+       .machine = &ln2440sbc,
+       .platform = &s3c24xx_soc_platform,
+       .codec_dev = &soc_codec_dev_ac97,
+};
+
+static struct platform_device *ln2440sbc_snd_ac97_device;
+
+static int __init ln2440sbc_init(void)
+{
+       int ret;
+
+       ln2440sbc_snd_ac97_device = platform_device_alloc("soc-audio", -1);
+       if (!ln2440sbc_snd_ac97_device)
+               return -ENOMEM;
+
+       platform_set_drvdata(ln2440sbc_snd_ac97_device,
+                               &ln2440sbc_snd_ac97_devdata);
+       ln2440sbc_snd_ac97_devdata.dev = &ln2440sbc_snd_ac97_device->dev;
+       ret = platform_device_add(ln2440sbc_snd_ac97_device);
+
+       if (ret)
+               platform_device_put(ln2440sbc_snd_ac97_device);
+
+       return ret;
+}
+
+static void __exit ln2440sbc_exit(void)
+{
+       platform_device_unregister(ln2440sbc_snd_ac97_device);
+}
+
+module_init(ln2440sbc_init);
+module_exit(ln2440sbc_exit);
+
+/* Module information */
+MODULE_AUTHOR("Ivan Kuten");
+MODULE_DESCRIPTION("ALSA SoC ALC650 LN2440SBC");
+MODULE_LICENSE("GPL");
index f1f6b9478af95d00480c2c814b9434bed98561e0..6ee115ceb011d22e207c5f33e43803d6a824f714 100644 (file)
@@ -22,7 +22,6 @@
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
 #include <linux/i2c.h>
-#include <sound/driver.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/soc.h>
 
 #include <asm/mach-types.h>
 #include <asm/hardware/scoop.h>
-#include <asm/arch/regs-iis.h>
 #include <asm/arch/regs-clock.h>
 #include <asm/arch/regs-gpio.h>
 #include <asm/hardware.h>
 #include <asm/arch/audio.h>
 #include <asm/io.h>
 #include <asm/arch/spi-gpio.h>
+
+#include <asm/plat-s3c24xx/regs-iis.h>
+
 #include "../codecs/wm8753.h"
 #include "lm4857.h"
 #include "s3c24xx-pcm.h"
diff --git a/sound/soc/s3c24xx/s3c2412-i2s.c b/sound/soc/s3c24xx/s3c2412-i2s.c
new file mode 100644 (file)
index 0000000..c4a46dd
--- /dev/null
@@ -0,0 +1,744 @@
+/* sound/soc/s3c24xx/s3c2412-i2s.c
+ *
+ * ALSA Soc Audio Layer - S3C2412 I2S driver
+ *
+ * Copyright (c) 2006 Wolfson Microelectronics PLC.
+ *     Graeme Gregory graeme.gregory@wolfsonmicro.com
+ *     linux@wolfsonmicro.com
+ *
+ * Copyright (c) 2007, 2004-2005 Simtec Electronics
+ *     http://armlinux.simtec.co.uk/
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * 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/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/kernel.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+#include <asm/hardware.h>
+
+#include <linux/io.h>
+#include <asm/dma.h>
+
+#include <asm/plat-s3c24xx/regs-s3c2412-iis.h>
+
+#include <asm/arch/regs-gpio.h>
+#include <asm/arch/audio.h>
+#include <asm/arch/dma.h>
+
+#include "s3c24xx-pcm.h"
+#include "s3c2412-i2s.h"
+
+#define S3C2412_I2S_DEBUG 0
+#define S3C2412_I2S_DEBUG_CON 0
+
+#if S3C2412_I2S_DEBUG
+#define DBG(x...) printk(KERN_INFO x)
+#else
+#define DBG(x...) do { } while (0)
+#endif
+
+static struct s3c2410_dma_client s3c2412_dma_client_out = {
+       .name           = "I2S PCM Stereo out"
+};
+
+static struct s3c2410_dma_client s3c2412_dma_client_in = {
+       .name           = "I2S PCM Stereo in"
+};
+
+static struct s3c24xx_pcm_dma_params s3c2412_i2s_pcm_stereo_out = {
+       .client         = &s3c2412_dma_client_out,
+       .channel        = DMACH_I2S_OUT,
+       .dma_addr       = S3C2410_PA_IIS + S3C2412_IISTXD,
+       .dma_size       = 4,
+};
+
+static struct s3c24xx_pcm_dma_params s3c2412_i2s_pcm_stereo_in = {
+       .client         = &s3c2412_dma_client_in,
+       .channel        = DMACH_I2S_IN,
+       .dma_addr       = S3C2410_PA_IIS + S3C2412_IISRXD,
+       .dma_size       = 4,
+};
+
+struct s3c2412_i2s_info {
+       struct device   *dev;
+       void __iomem    *regs;
+       struct clk      *iis_clk;
+       struct clk      *iis_pclk;
+       struct clk      *iis_cclk;
+
+       u32              suspend_iismod;
+       u32              suspend_iiscon;
+       u32              suspend_iispsr;
+};
+
+static struct s3c2412_i2s_info s3c2412_i2s;
+
+#define bit_set(v, b) (((v) & (b)) ? 1 : 0)
+
+#if S3C2412_I2S_DEBUG_CON
+static void dbg_showcon(const char *fn, u32 con)
+{
+       printk(KERN_DEBUG "%s: LRI=%d, TXFEMPT=%d, RXFEMPT=%d, TXFFULL=%d, RXFFULL=%d\n", fn,
+              bit_set(con, S3C2412_IISCON_LRINDEX),
+              bit_set(con, S3C2412_IISCON_TXFIFO_EMPTY),
+              bit_set(con, S3C2412_IISCON_RXFIFO_EMPTY),
+              bit_set(con, S3C2412_IISCON_TXFIFO_FULL),
+              bit_set(con, S3C2412_IISCON_RXFIFO_FULL));
+
+       printk(KERN_DEBUG "%s: PAUSE: TXDMA=%d, RXDMA=%d, TXCH=%d, RXCH=%d\n",
+              fn,
+              bit_set(con, S3C2412_IISCON_TXDMA_PAUSE),
+              bit_set(con, S3C2412_IISCON_RXDMA_PAUSE),
+              bit_set(con, S3C2412_IISCON_TXCH_PAUSE),
+              bit_set(con, S3C2412_IISCON_RXCH_PAUSE));
+       printk(KERN_DEBUG "%s: ACTIVE: TXDMA=%d, RXDMA=%d, IIS=%d\n", fn,
+              bit_set(con, S3C2412_IISCON_TXDMA_ACTIVE),
+              bit_set(con, S3C2412_IISCON_RXDMA_ACTIVE),
+              bit_set(con, S3C2412_IISCON_IIS_ACTIVE));
+}
+#else
+static inline void dbg_showcon(const char *fn, u32 con)
+{
+}
+#endif
+
+/* Turn on or off the transmission path. */
+static void s3c2412_snd_txctrl(int on)
+{
+       struct s3c2412_i2s_info *i2s = &s3c2412_i2s;
+       void __iomem *regs = i2s->regs;
+       u32 fic, con, mod;
+
+       DBG("%s(%d)\n", __func__, on);
+
+       fic = readl(regs + S3C2412_IISFIC);
+       con = readl(regs + S3C2412_IISCON);
+       mod = readl(regs + S3C2412_IISMOD);
+
+       DBG("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic);
+
+       if (on) {
+               con |= S3C2412_IISCON_TXDMA_ACTIVE | S3C2412_IISCON_IIS_ACTIVE;
+               con &= ~S3C2412_IISCON_TXDMA_PAUSE;
+               con &= ~S3C2412_IISCON_TXCH_PAUSE;
+
+               switch (mod & S3C2412_IISMOD_MODE_MASK) {
+               case S3C2412_IISMOD_MODE_TXONLY:
+               case S3C2412_IISMOD_MODE_TXRX:
+                       /* do nothing, we are in the right mode */
+                       break;
+
+               case S3C2412_IISMOD_MODE_RXONLY:
+                       mod &= ~S3C2412_IISMOD_MODE_MASK;
+                       mod |= S3C2412_IISMOD_MODE_TXRX;
+                       break;
+
+               default:
+                       dev_err(i2s->dev, "TXEN: Invalid MODE in IISMOD\n");
+               }
+
+               writel(con, regs + S3C2412_IISCON);
+               writel(mod, regs + S3C2412_IISMOD);
+       } else {
+               /* Note, we do not have any indication that the FIFO problems
+                * tha the S3C2410/2440 had apply here, so we should be able
+                * to disable the DMA and TX without resetting the FIFOS.
+                */
+
+               con |=  S3C2412_IISCON_TXDMA_PAUSE;
+               con |=  S3C2412_IISCON_TXCH_PAUSE;
+               con &= ~S3C2412_IISCON_TXDMA_ACTIVE;
+
+               switch (mod & S3C2412_IISMOD_MODE_MASK) {
+               case S3C2412_IISMOD_MODE_TXRX:
+                       mod &= ~S3C2412_IISMOD_MODE_MASK;
+                       mod |= S3C2412_IISMOD_MODE_RXONLY;
+                       break;
+
+               case S3C2412_IISMOD_MODE_TXONLY:
+                       mod &= ~S3C2412_IISMOD_MODE_MASK;
+                       con &= ~S3C2412_IISCON_IIS_ACTIVE;
+                       break;
+
+               default:
+                       dev_err(i2s->dev, "TXDIS: Invalid MODE in IISMOD\n");
+               }
+
+               writel(mod, regs + S3C2412_IISMOD);
+               writel(con, regs + S3C2412_IISCON);
+       }
+
+       fic = readl(regs + S3C2412_IISFIC);
+       dbg_showcon(__func__, con);
+       DBG("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic);
+}
+
+static void s3c2412_snd_rxctrl(int on)
+{
+       struct s3c2412_i2s_info *i2s = &s3c2412_i2s;
+       void __iomem *regs = i2s->regs;
+       u32 fic, con, mod;
+
+       DBG("%s(%d)\n", __func__, on);
+
+       fic = readl(regs + S3C2412_IISFIC);
+       con = readl(regs + S3C2412_IISCON);
+       mod = readl(regs + S3C2412_IISMOD);
+
+       DBG("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic);
+
+       if (on) {
+               con |= S3C2412_IISCON_RXDMA_ACTIVE | S3C2412_IISCON_IIS_ACTIVE;
+               con &= ~S3C2412_IISCON_RXDMA_PAUSE;
+               con &= ~S3C2412_IISCON_RXCH_PAUSE;
+
+               switch (mod & S3C2412_IISMOD_MODE_MASK) {
+               case S3C2412_IISMOD_MODE_TXRX:
+               case S3C2412_IISMOD_MODE_RXONLY:
+                       /* do nothing, we are in the right mode */
+                       break;
+
+               case S3C2412_IISMOD_MODE_TXONLY:
+                       mod &= ~S3C2412_IISMOD_MODE_MASK;
+                       mod |= S3C2412_IISMOD_MODE_TXRX;
+                       break;
+
+               default:
+                       dev_err(i2s->dev, "RXEN: Invalid MODE in IISMOD\n");
+               }
+
+               writel(mod, regs + S3C2412_IISMOD);
+               writel(con, regs + S3C2412_IISCON);
+       } else {
+               /* See txctrl notes on FIFOs. */
+
+               con &= ~S3C2412_IISCON_RXDMA_ACTIVE;
+               con |=  S3C2412_IISCON_RXDMA_PAUSE;
+               con |=  S3C2412_IISCON_RXCH_PAUSE;
+
+               switch (mod & S3C2412_IISMOD_MODE_MASK) {
+               case S3C2412_IISMOD_MODE_RXONLY:
+                       con &= ~S3C2412_IISCON_IIS_ACTIVE;
+                       mod &= ~S3C2412_IISMOD_MODE_MASK;
+                       break;
+
+               case S3C2412_IISMOD_MODE_TXRX:
+                       mod &= ~S3C2412_IISMOD_MODE_MASK;
+                       mod |= S3C2412_IISMOD_MODE_TXONLY;
+                       break;
+
+               default:
+                       dev_err(i2s->dev, "RXEN: Invalid MODE in IISMOD\n");
+               }
+
+               writel(con, regs + S3C2412_IISCON);
+               writel(mod, regs + S3C2412_IISMOD);
+       }
+
+       fic = readl(regs + S3C2412_IISFIC);
+       DBG("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic);
+}
+
+
+/*
+ * Wait for the LR signal to allow synchronisation to the L/R clock
+ * from the codec. May only be needed for slave mode.
+ */
+static int s3c2412_snd_lrsync(void)
+{
+       u32 iiscon;
+       unsigned long timeout = jiffies + msecs_to_jiffies(5);
+
+       DBG("Entered %s\n", __func__);
+
+       while (1) {
+               iiscon = readl(s3c2412_i2s.regs + S3C2412_IISCON);
+               if (iiscon & S3C2412_IISCON_LRINDEX)
+                       break;
+
+               if (timeout < jiffies) {
+                       printk(KERN_ERR "%s: timeout\n", __func__);
+                       return -ETIMEDOUT;
+               }
+       }
+
+       return 0;
+}
+
+/*
+ * Check whether CPU is the master or slave
+ */
+static inline int s3c2412_snd_is_clkmaster(void)
+{
+       u32 iismod = readl(s3c2412_i2s.regs + S3C2412_IISMOD);
+
+       DBG("Entered %s\n", __func__);
+
+       iismod &= S3C2412_IISMOD_MASTER_MASK;
+       return !(iismod == S3C2412_IISMOD_SLAVE);
+}
+
+/*
+ * Set S3C2412 I2S DAI format
+ */
+static int s3c2412_i2s_set_fmt(struct snd_soc_cpu_dai *cpu_dai,
+                              unsigned int fmt)
+{
+       u32 iismod;
+
+
+       DBG("Entered %s\n", __func__);
+
+       iismod = readl(s3c2412_i2s.regs + S3C2412_IISMOD);
+       DBG("hw_params r: IISMOD: %x \n", iismod);
+
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBM_CFM:
+               iismod &= ~S3C2412_IISMOD_MASTER_MASK;
+               iismod |= S3C2412_IISMOD_SLAVE;
+               break;
+       case SND_SOC_DAIFMT_CBS_CFS:
+               iismod &= ~S3C2412_IISMOD_MASTER_MASK;
+               iismod |= S3C2412_IISMOD_MASTER_INTERNAL;
+               break;
+       default:
+               DBG("unknwon master/slave format\n");
+               return -EINVAL;
+       }
+
+       iismod &= ~S3C2412_IISMOD_SDF_MASK;
+
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_RIGHT_J:
+               iismod |= S3C2412_IISMOD_SDF_MSB;
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               iismod |= S3C2412_IISMOD_SDF_LSB;
+               break;
+       case SND_SOC_DAIFMT_I2S:
+               iismod |= S3C2412_IISMOD_SDF_IIS;
+               break;
+       default:
+               DBG("Unknown data format\n");
+               return -EINVAL;
+       }
+
+       writel(iismod, s3c2412_i2s.regs + S3C2412_IISMOD);
+       DBG("hw_params w: IISMOD: %x \n", iismod);
+       return 0;
+}
+
+static int s3c2412_i2s_hw_params(struct snd_pcm_substream *substream,
+                                struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       u32 iismod;
+
+       DBG("Entered %s\n", __func__);
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               rtd->dai->cpu_dai->dma_data = &s3c2412_i2s_pcm_stereo_out;
+       else
+               rtd->dai->cpu_dai->dma_data = &s3c2412_i2s_pcm_stereo_in;
+
+       /* Working copies of register */
+       iismod = readl(s3c2412_i2s.regs + S3C2412_IISMOD);
+       DBG("%s: r: IISMOD: %x\n", __func__, iismod);
+
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S8:
+               iismod |= S3C2412_IISMOD_8BIT;
+               break;
+       case SNDRV_PCM_FORMAT_S16_LE:
+               iismod &= ~S3C2412_IISMOD_8BIT;
+               break;
+       }
+
+       writel(iismod, s3c2412_i2s.regs + S3C2412_IISMOD);
+       DBG("%s: w: IISMOD: %x\n", __func__, iismod);
+       return 0;
+}
+
+static int s3c2412_i2s_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+       int capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
+       unsigned long irqs;
+       int ret = 0;
+
+       DBG("Entered %s\n", __func__);
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+               /* On start, ensure that the FIFOs are cleared and reset. */
+
+               writel(capture ? S3C2412_IISFIC_RXFLUSH : S3C2412_IISFIC_TXFLUSH,
+                      s3c2412_i2s.regs + S3C2412_IISFIC);
+
+               /* clear again, just in case */
+               writel(0x0, s3c2412_i2s.regs + S3C2412_IISFIC);
+
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               if (!s3c2412_snd_is_clkmaster()) {
+                       ret = s3c2412_snd_lrsync();
+                       if (ret)
+                               goto exit_err;
+               }
+
+               local_irq_save(irqs);
+
+               if (capture)
+                       s3c2412_snd_rxctrl(1);
+               else
+                       s3c2412_snd_txctrl(1);
+
+               local_irq_restore(irqs);
+               break;
+
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               local_irq_save(irqs);
+
+               if (capture)
+                       s3c2412_snd_rxctrl(0);
+               else
+                       s3c2412_snd_txctrl(0);
+
+               local_irq_restore(irqs);
+               break;
+       default:
+               ret = -EINVAL;
+               break;
+       }
+
+exit_err:
+       return ret;
+}
+
+/* default table of all avaialable root fs divisors */
+static unsigned int s3c2412_iis_fs[] = { 256, 512, 384, 768, 0 };
+
+int s3c2412_iis_calc_rate(struct s3c2412_rate_calc *info,
+                         unsigned int *fstab,
+                         unsigned int rate, struct clk *clk)
+{
+       unsigned long clkrate = clk_get_rate(clk);
+       unsigned int div;
+       unsigned int fsclk;
+       unsigned int actual;
+       unsigned int fs;
+       unsigned int fsdiv;
+       signed int deviation = 0;
+       unsigned int best_fs = 0;
+       unsigned int best_div = 0;
+       unsigned int best_rate = 0;
+       unsigned int best_deviation = INT_MAX;
+
+
+       if (fstab == NULL)
+               fstab = s3c2412_iis_fs;
+
+       for (fs = 0;; fs++) {
+               fsdiv = s3c2412_iis_fs[fs];
+
+               if (fsdiv == 0)
+                       break;
+
+               fsclk = clkrate / fsdiv;
+               div = fsclk / rate;
+
+               if ((fsclk % rate) > (rate / 2))
+                       div++;
+
+               if (div <= 1)
+                       continue;
+
+               actual = clkrate / (fsdiv * div);
+               deviation = actual - rate;
+
+               printk(KERN_DEBUG "%dfs: div %d => result %d, deviation %d\n",
+                      fsdiv, div, actual, deviation);
+
+               deviation = abs(deviation);
+
+               if (deviation < best_deviation) {
+                       best_fs = fsdiv;
+                       best_div = div;
+                       best_rate = actual;
+                       best_deviation = deviation;
+               }
+
+               if (deviation == 0)
+                       break;
+       }
+
+       printk(KERN_DEBUG "best: fs=%d, div=%d, rate=%d\n",
+              best_fs, best_div, best_rate);
+
+       info->fs_div = best_fs;
+       info->clk_div = best_div;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(s3c2412_iis_calc_rate);
+
+/*
+ * Set S3C2412 Clock source
+ */
+static int s3c2412_i2s_set_sysclk(struct snd_soc_cpu_dai *cpu_dai,
+                                 int clk_id, unsigned int freq, int dir)
+{
+       u32 iismod = readl(s3c2412_i2s.regs + S3C2412_IISMOD);
+
+       DBG("%s(%p, %d, %u, %d)\n", __func__, cpu_dai, clk_id,
+           freq, dir);
+
+       switch (clk_id) {
+       case S3C2412_CLKSRC_PCLK:
+               iismod &= ~S3C2412_IISMOD_MASTER_MASK;
+               iismod |= S3C2412_IISMOD_MASTER_INTERNAL;
+               break;
+       case S3C2412_CLKSRC_I2SCLK:
+               iismod &= ~S3C2412_IISMOD_MASTER_MASK;
+               iismod |= S3C2412_IISMOD_MASTER_EXTERNAL;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       writel(iismod, s3c2412_i2s.regs + S3C2412_IISMOD);
+       return 0;
+}
+
+/*
+ * Set S3C2412 Clock dividers
+ */
+static int s3c2412_i2s_set_clkdiv(struct snd_soc_cpu_dai *cpu_dai,
+                                 int div_id, int div)
+{
+       struct s3c2412_i2s_info *i2s = &s3c2412_i2s;
+       u32 reg;
+
+       DBG("%s(%p, %d, %d)\n", __func__, cpu_dai, div_id, div);
+
+       switch (div_id) {
+       case S3C2412_DIV_BCLK:
+               reg = readl(i2s->regs + S3C2412_IISMOD);
+               reg &= ~S3C2412_IISMOD_BCLK_MASK;
+               writel(reg | div, i2s->regs + S3C2412_IISMOD);
+
+               DBG("%s: MOD=%08x\n", __func__, readl(i2s->regs + S3C2412_IISMOD));
+               break;
+
+       case S3C2412_DIV_RCLK:
+               if (div > 3) {
+                       /* convert value to bit field */
+
+                       switch (div) {
+                       case 256:
+                               div = S3C2412_IISMOD_RCLK_256FS;
+                               break;
+
+                       case 384:
+                               div = S3C2412_IISMOD_RCLK_384FS;
+                               break;
+
+                       case 512:
+                               div = S3C2412_IISMOD_RCLK_512FS;
+                               break;
+
+                       case 768:
+                               div = S3C2412_IISMOD_RCLK_768FS;
+                               break;
+
+                       default:
+                               return -EINVAL;
+                       }
+               }
+
+               reg = readl(s3c2412_i2s.regs + S3C2412_IISMOD);
+               reg &= ~S3C2412_IISMOD_RCLK_MASK;
+               writel(reg | div, i2s->regs + S3C2412_IISMOD);
+               DBG("%s: MOD=%08x\n", __func__, readl(i2s->regs + S3C2412_IISMOD));
+               break;
+
+       case S3C2412_DIV_PRESCALER:
+               if (div >= 0) {
+                       writel((div << 8) | S3C2412_IISPSR_PSREN,
+                              i2s->regs + S3C2412_IISPSR);
+               } else {
+                       writel(0x0, i2s->regs + S3C2412_IISPSR);
+               }
+               DBG("%s: PSR=%08x\n", __func__, readl(i2s->regs + S3C2412_IISPSR));
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+struct clk *s3c2412_get_iisclk(void)
+{
+       return s3c2412_i2s.iis_clk;
+}
+EXPORT_SYMBOL_GPL(s3c2412_get_iisclk);
+
+
+static int s3c2412_i2s_probe(struct platform_device *pdev)
+{
+       DBG("Entered %s\n", __func__);
+
+       s3c2412_i2s.dev = &pdev->dev;
+
+       s3c2412_i2s.regs = ioremap(S3C2410_PA_IIS, 0x100);
+       if (s3c2412_i2s.regs == NULL)
+               return -ENXIO;
+
+       s3c2412_i2s.iis_pclk = clk_get(&pdev->dev, "iis");
+       if (s3c2412_i2s.iis_pclk == NULL) {
+               DBG("failed to get iis_clock\n");
+               iounmap(s3c2412_i2s.regs);
+               return -ENODEV;
+       }
+
+       s3c2412_i2s.iis_cclk = clk_get(&pdev->dev, "i2sclk");
+       if (s3c2412_i2s.iis_cclk == NULL) {
+               DBG("failed to get i2sclk clock\n");
+               iounmap(s3c2412_i2s.regs);
+               return -ENODEV;
+       }
+
+       clk_set_parent(s3c2412_i2s.iis_cclk, clk_get(NULL, "mpll"));
+
+       clk_enable(s3c2412_i2s.iis_pclk);
+       clk_enable(s3c2412_i2s.iis_cclk);
+
+       s3c2412_i2s.iis_clk = s3c2412_i2s.iis_pclk;
+
+       /* Configure the I2S pins in correct mode */
+       s3c2410_gpio_cfgpin(S3C2410_GPE0, S3C2410_GPE0_I2SLRCK);
+       s3c2410_gpio_cfgpin(S3C2410_GPE1, S3C2410_GPE1_I2SSCLK);
+       s3c2410_gpio_cfgpin(S3C2410_GPE2, S3C2410_GPE2_CDCLK);
+       s3c2410_gpio_cfgpin(S3C2410_GPE3, S3C2410_GPE3_I2SSDI);
+       s3c2410_gpio_cfgpin(S3C2410_GPE4, S3C2410_GPE4_I2SSDO);
+
+       s3c2412_snd_txctrl(0);
+       s3c2412_snd_rxctrl(0);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int s3c2412_i2s_suspend(struct platform_device *dev,
+                             struct snd_soc_cpu_dai *dai)
+{
+       struct s3c2412_i2s_info *i2s = &s3c2412_i2s;
+       u32 iismod;
+
+       if (dai->active) {
+               i2s->suspend_iismod = readl(i2s->regs + S3C2412_IISMOD);
+               i2s->suspend_iiscon = readl(i2s->regs + S3C2412_IISCON);
+               i2s->suspend_iispsr = readl(i2s->regs + S3C2412_IISPSR);
+
+               /* some basic suspend checks */
+
+               iismod = readl(i2s->regs + S3C2412_IISMOD);
+
+               if (iismod & S3C2412_IISCON_RXDMA_ACTIVE)
+                       dev_warn(&dev->dev, "%s: RXDMA active?\n", __func__);
+
+               if (iismod & S3C2412_IISCON_TXDMA_ACTIVE)
+                       dev_warn(&dev->dev, "%s: TXDMA active?\n", __func__);
+
+               if (iismod & S3C2412_IISCON_IIS_ACTIVE)
+                       dev_warn(&dev->dev, "%s: IIS active\n", __func__);
+       }
+
+       return 0;
+}
+
+static int s3c2412_i2s_resume(struct platform_device *pdev,
+                             struct snd_soc_cpu_dai *dai)
+{
+       struct s3c2412_i2s_info *i2s = &s3c2412_i2s;
+
+       dev_info(&pdev->dev, "dai_active %d, IISMOD %08x, IISCON %08x\n",
+                dai->active, i2s->suspend_iismod, i2s->suspend_iiscon);
+
+       if (dai->active) {
+               writel(i2s->suspend_iiscon, i2s->regs + S3C2412_IISCON);
+               writel(i2s->suspend_iismod, i2s->regs + S3C2412_IISMOD);
+               writel(i2s->suspend_iispsr, i2s->regs + S3C2412_IISPSR);
+
+               writel(S3C2412_IISFIC_RXFLUSH | S3C2412_IISFIC_TXFLUSH,
+                      i2s->regs + S3C2412_IISFIC);
+
+               ndelay(250);
+               writel(0x0, i2s->regs + S3C2412_IISFIC);
+
+       }
+
+       return 0;
+}
+#else
+#define s3c2412_i2s_suspend NULL
+#define s3c2412_i2s_resume  NULL
+#endif /* CONFIG_PM */
+
+#define S3C2412_I2S_RATES \
+       (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \
+       SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
+       SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
+
+struct snd_soc_cpu_dai s3c2412_i2s_dai = {
+       .name   = "s3c2412-i2s",
+       .id     = 0,
+       .type   = SND_SOC_DAI_I2S,
+       .probe  = s3c2412_i2s_probe,
+       .suspend = s3c2412_i2s_suspend,
+       .resume = s3c2412_i2s_resume,
+       .playback = {
+               .channels_min   = 2,
+               .channels_max   = 2,
+               .rates          = S3C2412_I2S_RATES,
+               .formats        = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE,
+       },
+       .capture = {
+               .channels_min   = 2,
+               .channels_max   = 2,
+               .rates          = S3C2412_I2S_RATES,
+               .formats        = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE,
+       },
+       .ops = {
+               .trigger        = s3c2412_i2s_trigger,
+               .hw_params      = s3c2412_i2s_hw_params,
+       },
+       .dai_ops = {
+               .set_fmt        = s3c2412_i2s_set_fmt,
+               .set_clkdiv     = s3c2412_i2s_set_clkdiv,
+               .set_sysclk     = s3c2412_i2s_set_sysclk,
+       },
+};
+EXPORT_SYMBOL_GPL(s3c2412_i2s_dai);
+
+/* Module information */
+MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
+MODULE_DESCRIPTION("S3C2412 I2S SoC Interface");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/s3c24xx/s3c2412-i2s.h b/sound/soc/s3c24xx/s3c2412-i2s.h
new file mode 100644 (file)
index 0000000..27f48e1
--- /dev/null
@@ -0,0 +1,38 @@
+/* sound/soc/s3c24xx/s3c2412-i2s.c
+ *
+ * ALSA Soc Audio Layer - S3C2412 I2S driver
+ *
+ * Copyright (c) 2007 Simtec Electronics
+ *     http://armlinux.simtec.co.uk/
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ *  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 __SND_SOC_S3C24XX_S3C2412_I2S_H
+#define __SND_SOC_S3C24XX_S3C2412_I2S_H __FILE__
+
+#define S3C2412_DIV_BCLK       (1)
+#define S3C2412_DIV_RCLK       (2)
+#define S3C2412_DIV_PRESCALER  (3)
+
+#define S3C2412_CLKSRC_PCLK    (0)
+#define S3C2412_CLKSRC_I2SCLK  (1)
+
+extern struct clk *s3c2412_get_iisclk(void);
+
+extern struct snd_soc_cpu_dai s3c2412_i2s_dai;
+
+struct s3c2412_rate_calc {
+       unsigned int    clk_div;        /* for prescaler */
+       unsigned int    fs_div;         /* for root frame clock */
+};
+
+extern int s3c2412_iis_calc_rate(struct s3c2412_rate_calc *info,
+                                unsigned int *fstab,
+                                unsigned int rate, struct clk *clk);
+
+#endif /* __SND_SOC_S3C24XX_S3C2412_I2S_H */
index 758a2637e7ac408d7eb46ba4bf16f051e9ea9e00..1c1ddbf7f3c01e61605fc5f1ee29856f3a215349 100644 (file)
@@ -23,7 +23,6 @@
 #include <linux/delay.h>
 #include <linux/clk.h>
 
-#include <sound/driver.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/ac97_codec.h>
@@ -253,7 +252,7 @@ static int s3c2443_ac97_probe(struct platform_device *pdev)
        ac_glbctrl |= S3C_AC97_GLBCTRL_TRANSFERDATAENABLE;
        writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
 
-       ret = request_irq(IRQ_S3C2443_AC97, s3c2443_ac97_irq,
+       ret = request_irq(IRQ_S3C244x_AC97, s3c2443_ac97_irq,
                IRQF_DISABLED, "AC97", NULL);
        if (ret < 0) {
                printk(KERN_ERR "s3c24xx-ac97: interrupt request failed.\n");
@@ -266,7 +265,7 @@ static int s3c2443_ac97_probe(struct platform_device *pdev)
 
 static void s3c2443_ac97_remove(struct platform_device *pdev)
 {
-       free_irq(IRQ_S3C2443_AC97, NULL);
+       free_irq(IRQ_S3C244x_AC97, NULL);
        clk_disable(s3c24xx_ac97.ac97_clk);
        clk_put(s3c24xx_ac97.ac97_clk);
        iounmap(s3c24xx_ac97.regs);
index 2b835e8260fae11f6a9906dff28dad37dede9059..bf03e8ed16c30a8b22b4cf5d37e151b12ffc6a00 100644 (file)
 #define AC_CMD_ADDR(x) (x << 16)
 #define AC_CMD_DATA(x) (x & 0xffff)
 
+#ifdef CONFIG_CPU_S3C2440
+#define IRQ_S3C244x_AC97 IRQ_S3C2440_AC97
+#else
+#define IRQ_S3C244x_AC97 IRQ_S3C2443_AC97
+#endif
+
 extern struct snd_soc_cpu_dai s3c2443_ac97_dai[];
 
 #endif /*S3C24XXAC97_H_*/
index cd89c4105fcdc206615bf670db3445142d1fd3ff..0a3c630951bee11833fd349195f6a90e0cc8951b 100644 (file)
@@ -24,7 +24,7 @@
 #include <linux/device.h>
 #include <linux/delay.h>
 #include <linux/clk.h>
-#include <sound/driver.h>
+#include <linux/jiffies.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 
 #include <asm/hardware.h>
 #include <asm/io.h>
-#include <asm/arch/regs-iis.h>
 #include <asm/arch/regs-gpio.h>
 #include <asm/arch/regs-clock.h>
 #include <asm/arch/audio.h>
 #include <asm/dma.h>
 #include <asm/arch/dma.h>
 
+#include <asm/plat-s3c24xx/regs-iis.h>
+
 #include "s3c24xx-pcm.h"
 #include "s3c24xx-i2s.h"
 
@@ -75,6 +76,10 @@ static struct s3c24xx_pcm_dma_params s3c24xx_i2s_pcm_stereo_in = {
 struct s3c24xx_i2s_info {
        void __iomem    *regs;
        struct clk      *iis_clk;
+       u32             iiscon;
+       u32             iismod;
+       u32             iisfcon;
+       u32             iispsr;
 };
 static struct s3c24xx_i2s_info s3c24xx_i2s;
 
@@ -184,7 +189,7 @@ static int s3c24xx_snd_lrsync(void)
                if (iiscon & S3C2410_IISCON_LRINDEX)
                        break;
 
-               if (timeout < jiffies)
+               if (time_after(jiffies, timeout))
                        return -ETIMEDOUT;
        }
 
@@ -405,6 +410,38 @@ static int s3c24xx_i2s_probe(struct platform_device *pdev)
        return 0;
 }
 
+#ifdef CONFIG_PM
+int s3c24xx_i2s_suspend(struct platform_device *pdev,
+               struct snd_soc_cpu_dai *cpu_dai)
+{
+       s3c24xx_i2s.iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON);
+       s3c24xx_i2s.iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);
+       s3c24xx_i2s.iisfcon = readl(s3c24xx_i2s.regs + S3C2410_IISFCON);
+       s3c24xx_i2s.iispsr = readl(s3c24xx_i2s.regs + S3C2410_IISPSR);
+
+       clk_disable(s3c24xx_i2s.iis_clk);
+
+       return 0;
+}
+
+int s3c24xx_i2s_resume(struct platform_device *pdev,
+               struct snd_soc_cpu_dai *cpu_dai)
+{
+       clk_enable(s3c24xx_i2s.iis_clk);
+
+       writel(s3c24xx_i2s.iiscon, s3c24xx_i2s.regs + S3C2410_IISCON);
+       writel(s3c24xx_i2s.iismod, s3c24xx_i2s.regs + S3C2410_IISMOD);
+       writel(s3c24xx_i2s.iisfcon, s3c24xx_i2s.regs + S3C2410_IISFCON);
+       writel(s3c24xx_i2s.iispsr, s3c24xx_i2s.regs + S3C2410_IISPSR);
+
+       return 0;
+}
+#else
+#define s3c24xx_i2s_suspend NULL
+#define s3c24xx_i2s_resume NULL
+#endif
+
+
 #define S3C24XX_I2S_RATES \
        (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \
        SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
@@ -415,6 +452,8 @@ struct snd_soc_cpu_dai s3c24xx_i2s_dai = {
        .id = 0,
        .type = SND_SOC_DAI_I2S,
        .probe = s3c24xx_i2s_probe,
+       .suspend = s3c24xx_i2s_suspend,
+       .resume = s3c24xx_i2s_resume,
        .playback = {
                .channels_min = 2,
                .channels_max = 2,
index 4107a87d4de3cb39fdcf7f8d51432e5a37361c93..29a6c82f873ac7c5f50def0470ef4d44e6fb5222 100644 (file)
@@ -24,7 +24,6 @@
 #include <linux/slab.h>
 #include <linux/dma-mapping.h>
 
-#include <sound/driver.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
@@ -49,7 +48,9 @@ static const struct snd_pcm_hardware s3c24xx_pcm_hardware = {
        .info                   = SNDRV_PCM_INFO_INTERLEAVED |
                                    SNDRV_PCM_INFO_BLOCK_TRANSFER |
                                    SNDRV_PCM_INFO_MMAP |
-                                   SNDRV_PCM_INFO_MMAP_VALID,
+                                   SNDRV_PCM_INFO_MMAP_VALID |
+                                   SNDRV_PCM_INFO_PAUSE |
+                                   SNDRV_PCM_INFO_RESUME,
        .formats                = SNDRV_PCM_FMTBIT_S16_LE |
                                    SNDRV_PCM_FMTBIT_U16_LE |
                                    SNDRV_PCM_FMTBIT_U8 |
@@ -176,28 +177,6 @@ static int s3c24xx_pcm_hw_params(struct snd_pcm_substream *substream,
                }
        }
 
-       /* channel needs configuring for mem=>device, increment memory addr,
-        * sync to pclk, half-word transfers to the IIS-FIFO. */
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               s3c2410_dma_devconfig(prtd->params->channel,
-                               S3C2410_DMASRC_MEM, S3C2410_DISRCC_INC |
-                               S3C2410_DISRCC_APB, prtd->params->dma_addr);
-
-               s3c2410_dma_config(prtd->params->channel,
-                               prtd->params->dma_size,
-                               S3C2410_DCON_SYNC_PCLK | 
-                               S3C2410_DCON_HANDSHAKE);
-       } else {
-               s3c2410_dma_config(prtd->params->channel,
-                               prtd->params->dma_size,
-                               S3C2410_DCON_HANDSHAKE | 
-                               S3C2410_DCON_SYNC_PCLK);
-
-               s3c2410_dma_devconfig(prtd->params->channel,
-                                       S3C2410_DMASRC_HW, 0x3,
-                                       prtd->params->dma_addr);
-       }
-
        s3c2410_dma_set_buffdone_fn(prtd->params->channel,
                                    s3c24xx_audio_buffdone);
 
@@ -246,6 +225,28 @@ static int s3c24xx_pcm_prepare(struct snd_pcm_substream *substream)
        if (!prtd->params)
                return 0;
 
+       /* channel needs configuring for mem=>device, increment memory addr,
+        * sync to pclk, half-word transfers to the IIS-FIFO. */
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               s3c2410_dma_devconfig(prtd->params->channel,
+                               S3C2410_DMASRC_MEM, S3C2410_DISRCC_INC |
+                               S3C2410_DISRCC_APB, prtd->params->dma_addr);
+
+               s3c2410_dma_config(prtd->params->channel,
+                               prtd->params->dma_size,
+                               S3C2410_DCON_SYNC_PCLK |
+                               S3C2410_DCON_HANDSHAKE);
+       } else {
+               s3c2410_dma_config(prtd->params->channel,
+                               prtd->params->dma_size,
+                               S3C2410_DCON_HANDSHAKE |
+                               S3C2410_DCON_SYNC_PCLK);
+
+               s3c2410_dma_devconfig(prtd->params->channel,
+                                       S3C2410_DMASRC_HW, 0x3,
+                                       prtd->params->dma_addr);
+       }
+
        /* flush the DMA channel */
        s3c2410_dma_ctrl(prtd->params->channel, S3C2410_DMAOP_FLUSH);
        prtd->dma_loaded = 0;
index d46cd811ceb3e627f003a4050b2cd6333487d2c3..b4a56302b9ab091203427333c2174c35d4341ca2 100644 (file)
@@ -17,7 +17,6 @@
 
 #include <linux/module.h>
 #include <linux/device.h>
-#include <sound/driver.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/soc.h>
index cdee374b843efd9a4d7258f0c2e2b6c3408a7024..7a3ce80d6727dbe2daea6fa691ef0daff4974481 100644 (file)
@@ -16,7 +16,6 @@
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/dma-mapping.h>
-#include <sound/driver.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
index 8e3f03908cdbe6bc4b9d9fac4d58605ad1e3b9ae..b7b676b3d6715c38fd6196ce10162d245daca36d 100644 (file)
@@ -21,7 +21,6 @@
 #include <linux/interrupt.h>
 #include <linux/wait.h>
 #include <linux/delay.h>
-#include <sound/driver.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/ac97_codec.h>
@@ -105,7 +104,7 @@ static int hac_get_codec_data(struct hac_priv *hac, unsigned short r,
        unsigned int to1, to2, i;
        unsigned short adr;
 
-       for (i = 0; i < AC97_READ_RETRY; ++i) {
+       for (i = AC97_READ_RETRY; i; i--) {
                *v = 0;
                /* wait for HAC to receive something from the codec */
                for (to1 = TMO_E4;
@@ -132,7 +131,7 @@ static int hac_get_codec_data(struct hac_priv *hac, unsigned short r,
                udelay(21);
        }
        HACREG(HACRSR) &= ~(RSR_STDRY | RSR_STARY);
-       return (i < AC97_READ_RETRY);
+       return i;
 }
 
 static unsigned short hac_read_codec_aux(struct hac_priv *hac,
@@ -141,7 +140,7 @@ static unsigned short hac_read_codec_aux(struct hac_priv *hac,
        unsigned short val;
        unsigned int i, to;
 
-       for (i = 0; i < AC97_READ_RETRY; i++) {
+       for (i = AC97_READ_RETRY; i; i--) {
                /* send_read_request */
                local_irq_disable();
                HACREG(HACTSR) &= ~(TSR_CMDAMT);
@@ -159,10 +158,7 @@ static unsigned short hac_read_codec_aux(struct hac_priv *hac,
                        break;
        }
 
-       if (i == AC97_READ_RETRY)
-               return ~0;
-
-       return val;
+       return i ? val : ~0;
 }
 
 static void hac_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
@@ -172,7 +168,7 @@ static void hac_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
        struct hac_priv *hac = &hac_cpu_data[unit_id];
        unsigned int i, to;
        /* write_codec_aux */
-       for (i = 0; i < AC97_WRITE_RETRY; i++) {
+       for (i = AC97_WRITE_RETRY; i; i--) {
                /* send_write_request */
                local_irq_disable();
                HACREG(HACTSR) &= ~(TSR_CMDDMT | TSR_CMDAMT);
index 5563f14511fa4ed123c6a979d3c11fb344efcb33..2f91de84c5c762a2896c14230140c90b216d39a9 100644 (file)
@@ -9,7 +9,6 @@
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/platform_device.h>
-#include <sound/driver.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/soc.h>
index b72bc316cb8ec10e7b7cc8886ef44aa6602ccd75..3388bc3d62d10fbef92a56c148ea4259ae2a6654 100644 (file)
@@ -30,7 +30,6 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
-#include <sound/driver.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/initval.h>
index e6a67b58f296ec6269fc7c1ea833a5a1728bf7eb..9eb5479787c1d32203b17c1a037750a961c11f17 100644 (file)
@@ -32,7 +32,6 @@
 #include <linux/pm.h>
 #include <linux/bitops.h>
 #include <linux/platform_device.h>
-#include <sound/driver.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
@@ -288,16 +287,25 @@ static void close_delayed_work(struct work_struct *work)
                /* are we waiting on this codec DAI stream */
                if (codec_dai->pop_wait == 1) {
 
+                       /* power down the codec to D1 if no longer active */
+                       if (codec->active == 0) {
+                               dbg("pop wq D1 %s %s\n", codec->name,
+                                       codec_dai->playback.stream_name);
+                               snd_soc_dapm_device_event(socdev,
+                                       SNDRV_CTL_POWER_D1);
+                       }
+
                        codec_dai->pop_wait = 0;
-                       snd_soc_dapm_stream_event(codec, codec_dai->playback.stream_name,
+                       snd_soc_dapm_stream_event(codec,
+                               codec_dai->playback.stream_name,
                                SND_SOC_DAPM_STREAM_STOP);
 
                        /* power down the codec power domain if no longer active */
                        if (codec->active == 0) {
                                dbg("pop wq D3 %s %s\n", codec->name,
                                        codec_dai->playback.stream_name);
-                               if (codec->dapm_event)
-                                       codec->dapm_event(codec, SNDRV_CTL_POWER_D3hot);
+                               snd_soc_dapm_device_event(socdev,
+                                       SNDRV_CTL_POWER_D3hot);
                        }
                }
        }
@@ -353,12 +361,12 @@ static int soc_codec_close(struct snd_pcm_substream *substream)
        } else {
                /* capture streams can be powered down now */
                snd_soc_dapm_stream_event(codec,
-                       codec_dai->capture.stream_name, SND_SOC_DAPM_STREAM_STOP);
+                       codec_dai->capture.stream_name,
+                       SND_SOC_DAPM_STREAM_STOP);
 
-               if (codec->active == 0 && codec_dai->pop_wait == 0){
-                       if (codec->dapm_event)
-                               codec->dapm_event(codec, SNDRV_CTL_POWER_D3hot);
-               }
+               if (codec->active == 0 && codec_dai->pop_wait == 0)
+                       snd_soc_dapm_device_event(socdev,
+                                               SNDRV_CTL_POWER_D3hot);
        }
 
        mutex_unlock(&pcm_mutex);
@@ -433,8 +441,7 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream)
                /* no delayed work - do we need to power up codec */
                if (codec->dapm_state != SNDRV_CTL_POWER_D0) {
 
-                       if (codec->dapm_event)
-                               codec->dapm_event(codec, SNDRV_CTL_POWER_D1);
+                       snd_soc_dapm_device_event(socdev,  SNDRV_CTL_POWER_D1);
 
                        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
                                snd_soc_dapm_stream_event(codec,
@@ -445,8 +452,7 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream)
                                        codec_dai->capture.stream_name,
                                        SND_SOC_DAPM_STREAM_START);
 
-                       if (codec->dapm_event)
-                               codec->dapm_event(codec, SNDRV_CTL_POWER_D0);
+                       snd_soc_dapm_device_event(socdev, SNDRV_CTL_POWER_D0);
                        if (codec_dai->dai_ops.digital_mute)
                                codec_dai->dai_ops.digital_mute(codec_dai, 0);
 
@@ -639,6 +645,10 @@ static int soc_suspend(struct platform_device *pdev, pm_message_t state)
                        dai->dai_ops.digital_mute(dai, 1);
        }
 
+       /* suspend all pcms */
+       for (i = 0; i < machine->num_links; i++)
+               snd_pcm_suspend_all(machine->dai_link[i].pcm);
+
        if (machine->suspend_pre)
                machine->suspend_pre(pdev, state);
 
@@ -873,6 +883,7 @@ static int soc_new_pcm(struct snd_soc_device *socdev,
                return ret;
        }
 
+       dai_link->pcm = pcm;
        pcm->private_data = rtd;
        soc_pcm_ops.mmap = socdev->platform->pcm_ops->mmap;
        soc_pcm_ops.pointer = socdev->platform->pcm_ops->pointer;
@@ -1090,7 +1101,6 @@ int snd_soc_register_card(struct snd_soc_device *socdev)
        struct snd_soc_machine *machine = socdev->machine;
        int ret = 0, i, ac97 = 0, err = 0;
 
-       mutex_lock(&codec->mutex);
        for(i = 0; i < machine->num_links; i++) {
                if (socdev->machine->dai_link[i].init) {
                        err = socdev->machine->dai_link[i].init(codec);
@@ -1116,12 +1126,14 @@ int snd_soc_register_card(struct snd_soc_device *socdev)
                goto out;
        }
 
+       mutex_lock(&codec->mutex);
 #ifdef CONFIG_SND_SOC_AC97_BUS
        if (ac97) {
                ret = soc_ac97_dev_register(codec);
                if (ret < 0) {
                        printk(KERN_ERR "asoc: AC97 device register failed\n");
                        snd_card_free(codec->card);
+                       mutex_unlock(&codec->mutex);
                        goto out;
                }
        }
@@ -1134,8 +1146,10 @@ int snd_soc_register_card(struct snd_soc_device *socdev)
        err = device_create_file(socdev->dev, &dev_attr_codec_reg);
        if (err < 0)
                printk(KERN_WARNING "asoc: failed to add codec sysfs entries\n");
-out:
+
        mutex_unlock(&codec->mutex);
+
+out:
        return ret;
 }
 EXPORT_SYMBOL_GPL(snd_soc_register_card);
@@ -1215,7 +1229,6 @@ struct snd_kcontrol *snd_soc_cnew(const struct snd_kcontrol_new *_template,
        memcpy(&template, _template, sizeof(template));
        if (long_name)
                template.name = long_name;
-       template.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
        template.index = 0;
 
        return snd_ctl_new1(&template, data);
@@ -1350,13 +1363,16 @@ EXPORT_SYMBOL_GPL(snd_soc_info_enum_ext);
 int snd_soc_info_volsw_ext(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_info *uinfo)
 {
-       int mask = kcontrol->private_value;
+       int max = kcontrol->private_value;
+
+       if (max == 1)
+               uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       else
+               uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
 
-       uinfo->type =
-               mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
        uinfo->count = 1;
        uinfo->value.integer.min = 0;
-       uinfo->value.integer.max = mask;
+       uinfo->value.integer.max = max;
        return 0;
 }
 EXPORT_SYMBOL_GPL(snd_soc_info_volsw_ext);
@@ -1373,15 +1389,18 @@ EXPORT_SYMBOL_GPL(snd_soc_info_volsw_ext);
 int snd_soc_info_volsw(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_info *uinfo)
 {
-       int mask = (kcontrol->private_value >> 16) & 0xff;
+       int max = (kcontrol->private_value >> 16) & 0xff;
        int shift = (kcontrol->private_value >> 8) & 0x0f;
        int rshift = (kcontrol->private_value >> 12) & 0x0f;
 
-       uinfo->type =
-               mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
+       if (max == 1)
+               uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       else
+               uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+
        uinfo->count = shift == rshift ? 1 : 2;
        uinfo->value.integer.min = 0;
-       uinfo->value.integer.max = mask;
+       uinfo->value.integer.max = max;
        return 0;
 }
 EXPORT_SYMBOL_GPL(snd_soc_info_volsw);
@@ -1402,7 +1421,8 @@ int snd_soc_get_volsw(struct snd_kcontrol *kcontrol,
        int reg = kcontrol->private_value & 0xff;
        int shift = (kcontrol->private_value >> 8) & 0x0f;
        int rshift = (kcontrol->private_value >> 12) & 0x0f;
-       int mask = (kcontrol->private_value >> 16) & 0xff;
+       int max = (kcontrol->private_value >> 16) & 0xff;
+       int mask = (1 << fls(max)) - 1;
        int invert = (kcontrol->private_value >> 24) & 0x01;
 
        ucontrol->value.integer.value[0] =
@@ -1412,10 +1432,10 @@ int snd_soc_get_volsw(struct snd_kcontrol *kcontrol,
                        (snd_soc_read(codec, reg) >> rshift) & mask;
        if (invert) {
                ucontrol->value.integer.value[0] =
-                       mask - ucontrol->value.integer.value[0];
+                       max - ucontrol->value.integer.value[0];
                if (shift != rshift)
                        ucontrol->value.integer.value[1] =
-                               mask - ucontrol->value.integer.value[1];
+                               max - ucontrol->value.integer.value[1];
        }
 
        return 0;
@@ -1438,25 +1458,24 @@ int snd_soc_put_volsw(struct snd_kcontrol *kcontrol,
        int reg = kcontrol->private_value & 0xff;
        int shift = (kcontrol->private_value >> 8) & 0x0f;
        int rshift = (kcontrol->private_value >> 12) & 0x0f;
-       int mask = (kcontrol->private_value >> 16) & 0xff;
+       int max = (kcontrol->private_value >> 16) & 0xff;
+       int mask = (1 << fls(max)) - 1;
        int invert = (kcontrol->private_value >> 24) & 0x01;
-       int err;
        unsigned short val, val2, val_mask;
 
        val = (ucontrol->value.integer.value[0] & mask);
        if (invert)
-               val = mask - val;
+               val = max - val;
        val_mask = mask << shift;
        val = val << shift;
        if (shift != rshift) {
                val2 = (ucontrol->value.integer.value[1] & mask);
                if (invert)
-                       val2 = mask - val2;
+                       val2 = max - val2;
                val_mask |= mask << rshift;
                val |= val2 << rshift;
        }
-       err = snd_soc_update_bits(codec, reg, val_mask, val);
-       return err;
+       return snd_soc_update_bits(codec, reg, val_mask, val);
 }
 EXPORT_SYMBOL_GPL(snd_soc_put_volsw);
 
@@ -1473,13 +1492,16 @@ EXPORT_SYMBOL_GPL(snd_soc_put_volsw);
 int snd_soc_info_volsw_2r(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_info *uinfo)
 {
-       int mask = (kcontrol->private_value >> 12) & 0xff;
+       int max = (kcontrol->private_value >> 12) & 0xff;
+
+       if (max == 1)
+               uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       else
+               uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
 
-       uinfo->type =
-               mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
        uinfo->count = 2;
        uinfo->value.integer.min = 0;
-       uinfo->value.integer.max = mask;
+       uinfo->value.integer.max = max;
        return 0;
 }
 EXPORT_SYMBOL_GPL(snd_soc_info_volsw_2r);
@@ -1500,7 +1522,8 @@ int snd_soc_get_volsw_2r(struct snd_kcontrol *kcontrol,
        int reg = kcontrol->private_value & 0xff;
        int reg2 = (kcontrol->private_value >> 24) & 0xff;
        int shift = (kcontrol->private_value >> 8) & 0x0f;
-       int mask = (kcontrol->private_value >> 12) & 0xff;
+       int max = (kcontrol->private_value >> 12) & 0xff;
+       int mask = (1<<fls(max))-1;
        int invert = (kcontrol->private_value >> 20) & 0x01;
 
        ucontrol->value.integer.value[0] =
@@ -1509,9 +1532,9 @@ int snd_soc_get_volsw_2r(struct snd_kcontrol *kcontrol,
                (snd_soc_read(codec, reg2) >> shift) & mask;
        if (invert) {
                ucontrol->value.integer.value[0] =
-                       mask - ucontrol->value.integer.value[0];
+                       max - ucontrol->value.integer.value[0];
                ucontrol->value.integer.value[1] =
-                       mask - ucontrol->value.integer.value[1];
+                       max - ucontrol->value.integer.value[1];
        }
 
        return 0;
@@ -1534,7 +1557,8 @@ int snd_soc_put_volsw_2r(struct snd_kcontrol *kcontrol,
        int reg = kcontrol->private_value & 0xff;
        int reg2 = (kcontrol->private_value >> 24) & 0xff;
        int shift = (kcontrol->private_value >> 8) & 0x0f;
-       int mask = (kcontrol->private_value >> 12) & 0xff;
+       int max = (kcontrol->private_value >> 12) & 0xff;
+       int mask = (1 << fls(max)) - 1;
        int invert = (kcontrol->private_value >> 20) & 0x01;
        int err;
        unsigned short val, val2, val_mask;
@@ -1544,8 +1568,8 @@ int snd_soc_put_volsw_2r(struct snd_kcontrol *kcontrol,
        val2 = (ucontrol->value.integer.value[1] & mask);
 
        if (invert) {
-               val = mask - val;
-               val2 = mask - val2;
+               val = max - val;
+               val2 = max - val2;
        }
 
        val = val << shift;
index 29a546fecacf28fead8e36648dcf18e53a8e4852..620d7ea3c15ff56a10aba1e9402c98aa2c6940c8 100644 (file)
@@ -43,7 +43,6 @@
 #include <linux/bitops.h>
 #include <linux/platform_device.h>
 #include <linux/jiffies.h>
-#include <sound/driver.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
@@ -524,11 +523,13 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event)
                                        continue;
 
                                if (event == SND_SOC_DAPM_STREAM_START) {
-                                       ret = w->event(w, SND_SOC_DAPM_PRE_PMU);
+                                       ret = w->event(w,
+                                               NULL, SND_SOC_DAPM_PRE_PMU);
                                        if (ret < 0)
                                                return ret;
                                } else if (event == SND_SOC_DAPM_STREAM_STOP) {
-                                       ret = w->event(w, SND_SOC_DAPM_PRE_PMD);
+                                       ret = w->event(w,
+                                               NULL, SND_SOC_DAPM_PRE_PMD);
                                        if (ret < 0)
                                                return ret;
                                }
@@ -539,11 +540,13 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event)
                                        continue;
 
                                if (event == SND_SOC_DAPM_STREAM_START) {
-                                       ret = w->event(w, SND_SOC_DAPM_POST_PMU);
+                                       ret = w->event(w,
+                                               NULL, SND_SOC_DAPM_POST_PMU);
                                        if (ret < 0)
                                                return ret;
                                } else if (event == SND_SOC_DAPM_STREAM_STOP) {
-                                       ret = w->event(w, SND_SOC_DAPM_POST_PMD);
+                                       ret = w->event(w,
+                                               NULL, SND_SOC_DAPM_POST_PMD);
                                        if (ret < 0)
                                                return ret;
                                }
@@ -567,26 +570,30 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event)
                                        if (power) {
                                                /* power up event */
                                                if (w->event_flags & SND_SOC_DAPM_PRE_PMU) {
-                                                       ret = w->event(w, SND_SOC_DAPM_PRE_PMU);
+                                                       ret = w->event(w,
+                                                               NULL, SND_SOC_DAPM_PRE_PMU);
                                                        if (ret < 0)
                                                                return ret;
                                                }
                                                dapm_update_bits(w);
                                                if (w->event_flags & SND_SOC_DAPM_POST_PMU){
-                                                       ret = w->event(w, SND_SOC_DAPM_POST_PMU);
+                                                       ret = w->event(w,
+                                                               NULL, SND_SOC_DAPM_POST_PMU);
                                                        if (ret < 0)
                                                                return ret;
                                                }
                                        } else {
                                                /* power down event */
                                                if (w->event_flags & SND_SOC_DAPM_PRE_PMD) {
-                                                       ret = w->event(w, SND_SOC_DAPM_PRE_PMD);
+                                                       ret = w->event(w,
+                                                               NULL, SND_SOC_DAPM_PRE_PMD);
                                                        if (ret < 0)
                                                                return ret;
                                                }
                                                dapm_update_bits(w);
                                                if (w->event_flags & SND_SOC_DAPM_POST_PMD) {
-                                                       ret = w->event(w, SND_SOC_DAPM_POST_PMD);
+                                                       ret = w->event(w,
+                                                               NULL, SND_SOC_DAPM_POST_PMD);
                                                        if (ret < 0)
                                                                return ret;
                                                }
@@ -692,7 +699,7 @@ static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget,
        return 0;
 }
 
-/* test and update the power status of a mixer widget */
+/* test and update the power status of a mixer or switch widget */
 static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget,
                                   struct snd_kcontrol *kcontrol, int reg,
                                   int val_mask, int val, int invert)
@@ -700,7 +707,8 @@ static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget,
        struct snd_soc_dapm_path *path;
        int found = 0;
 
-       if (widget->id != snd_soc_dapm_mixer)
+       if (widget->id != snd_soc_dapm_mixer &&
+           widget->id != snd_soc_dapm_switch)
                return -ENODEV;
 
        if (!snd_soc_test_bits(widget->codec, reg, val_mask, val))
@@ -963,7 +971,6 @@ int snd_soc_dapm_new_widgets(struct snd_soc_codec *codec)
 {
        struct snd_soc_dapm_widget *w;
 
-       mutex_lock(&codec->mutex);
        list_for_each_entry(w, &codec->dapm_widgets, list)
        {
                if (w->new)
@@ -998,7 +1005,6 @@ int snd_soc_dapm_new_widgets(struct snd_soc_codec *codec)
        }
 
        dapm_power_widgets(codec, SND_SOC_DAPM_STREAM_NOP);
-       mutex_unlock(&codec->mutex);
        return 0;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_new_widgets);
@@ -1019,8 +1025,9 @@ int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol,
        int reg = kcontrol->private_value & 0xff;
        int shift = (kcontrol->private_value >> 8) & 0x0f;
        int rshift = (kcontrol->private_value >> 12) & 0x0f;
-       int mask = (kcontrol->private_value >> 16) & 0xff;
+       int max = (kcontrol->private_value >> 16) & 0xff;
        int invert = (kcontrol->private_value >> 24) & 0x01;
+       int mask = (1 << fls(max)) - 1;
 
        /* return the saved value if we are powered down */
        if (widget->id == snd_soc_dapm_pga && !widget->power) {
@@ -1035,10 +1042,10 @@ int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol,
                        (snd_soc_read(widget->codec, reg) >> rshift) & mask;
        if (invert) {
                ucontrol->value.integer.value[0] =
-                       mask - ucontrol->value.integer.value[0];
+                       max - ucontrol->value.integer.value[0];
                if (shift != rshift)
                        ucontrol->value.integer.value[1] =
-                               mask - ucontrol->value.integer.value[1];
+                               max - ucontrol->value.integer.value[1];
        }
 
        return 0;
@@ -1061,7 +1068,8 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
        int reg = kcontrol->private_value & 0xff;
        int shift = (kcontrol->private_value >> 8) & 0x0f;
        int rshift = (kcontrol->private_value >> 12) & 0x0f;
-       int mask = (kcontrol->private_value >> 16) & 0xff;
+       int max = (kcontrol->private_value >> 16) & 0xff;
+       int mask = (1 << fls(max)) - 1;
        int invert = (kcontrol->private_value >> 24) & 0x01;
        unsigned short val, val2, val_mask;
        int ret;
@@ -1069,13 +1077,13 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
        val = (ucontrol->value.integer.value[0] & mask);
 
        if (invert)
-               val = mask - val;
+               val = max - val;
        val_mask = mask << shift;
        val = val << shift;
        if (shift != rshift) {
                val2 = (ucontrol->value.integer.value[1] & mask);
                if (invert)
-                       val2 = mask - val2;
+                       val2 = max - val2;
                val_mask |= mask << rshift;
                val |= val2 << rshift;
        }
@@ -1093,13 +1101,17 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
        dapm_mixer_update_power(widget, kcontrol, reg, val_mask, val, invert);
        if (widget->event) {
                if (widget->event_flags & SND_SOC_DAPM_PRE_REG) {
-                       ret = widget->event(widget, SND_SOC_DAPM_PRE_REG);
-                       if (ret < 0)
+                       ret = widget->event(widget, kcontrol,
+                                               SND_SOC_DAPM_PRE_REG);
+                       if (ret < 0) {
+                               ret = 1;
                                goto out;
+                       }
                }
                ret = snd_soc_update_bits(widget->codec, reg, val_mask, val);
                if (widget->event_flags & SND_SOC_DAPM_POST_REG)
-                       ret = widget->event(widget, SND_SOC_DAPM_POST_REG);
+                       ret = widget->event(widget, kcontrol,
+                                               SND_SOC_DAPM_POST_REG);
        } else
                ret = snd_soc_update_bits(widget->codec, reg, val_mask, val);
 
@@ -1174,13 +1186,15 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
        dapm_mux_update_power(widget, kcontrol, mask, mux, e);
        if (widget->event) {
                if (widget->event_flags & SND_SOC_DAPM_PRE_REG) {
-                       ret = widget->event(widget, SND_SOC_DAPM_PRE_REG);
+                       ret = widget->event(widget,
+                               kcontrol, SND_SOC_DAPM_PRE_REG);
                        if (ret < 0)
                                goto out;
                }
                ret = snd_soc_update_bits(widget->codec, e->reg, mask, val);
                if (widget->event_flags & SND_SOC_DAPM_POST_REG)
-                       ret = widget->event(widget, SND_SOC_DAPM_POST_REG);
+                       ret = widget->event(widget,
+                               kcontrol, SND_SOC_DAPM_POST_REG);
        } else
                ret = snd_soc_update_bits(widget->codec, e->reg, mask, val);
 
@@ -1279,6 +1293,29 @@ int snd_soc_dapm_stream_event(struct snd_soc_codec *codec,
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_stream_event);
 
+/**
+ * snd_soc_dapm_device_event - send a device event to the dapm core
+ * @socdev: audio device
+ * @event: device event
+ *
+ * Sends a device event to the dapm core. The core then makes any
+ * necessary machine or codec power changes..
+ *
+ * Returns 0 for success else error.
+ */
+int snd_soc_dapm_device_event(struct snd_soc_device *socdev, int event)
+{
+       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_machine *machine = socdev->machine;
+
+       if (machine->dapm_event)
+               machine->dapm_event(machine, event);
+       if (codec->dapm_event)
+               codec->dapm_event(codec, event);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dapm_device_event);
+
 /**
  * snd_soc_dapm_set_endpoint - set audio endpoint status
  * @codec: audio codec
index 07962a35f2412f8461681835fcf6c12b7244bfc3..0c63e0585b15eed7d819dc55531db1d321865830 100644 (file)
@@ -36,7 +36,6 @@
 #include <linux/interrupt.h>
 #include <linux/moduleparam.h>
 
-#include <sound/driver.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/info.h>
@@ -859,7 +858,7 @@ static int snd_amd7930_put_volume(struct snd_kcontrol *kctl, struct snd_ctl_elem
        spin_lock_irqsave(&amd->lock, flags);
 
        if (*swval != ucontrol->value.integer.value[0]) {
-               *swval = ucontrol->value.integer.value[0];
+               *swval = ucontrol->value.integer.value[0] & 0xff;
                __amd7930_update_map(amd);
                change = 1;
        } else
index f8c7a120ccbb3ce2c98821523c55223fcbbb3458..1c4797be72ee774a54b6e3dd7ec8b0e476ee2381 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/io.h>
 
 
-#include <sound/driver.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/info.h>
index 376b98691c965bf228a585a0f619ed6a744fb50a..3d00e0797b11899042e5af98fa64a224ebc13597 100644 (file)
@@ -53,7 +53,6 @@
  * other       DBRI low-level stuff
  */
 
-#include <sound/driver.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 #include <linux/irq.h>
@@ -2279,14 +2278,25 @@ static int snd_cs4215_put_volume(struct snd_kcontrol *kcontrol,
        struct snd_dbri *dbri = snd_kcontrol_chip(kcontrol);
        struct dbri_streaminfo *info =
                                &dbri->stream_info[kcontrol->private_value];
+       unsigned int vol[2];
        int changed = 0;
 
-       if (info->left_gain != ucontrol->value.integer.value[0]) {
-               info->left_gain = ucontrol->value.integer.value[0];
+       vol[0] = ucontrol->value.integer.value[0];
+       vol[1] = ucontrol->value.integer.value[1];
+       if (kcontrol->private_value == DBRI_PLAY) {
+               if (vol[0] > DBRI_MAX_VOLUME || vol[1] > DBRI_MAX_VOLUME)
+                       return -EINVAL;
+       } else {
+               if (vol[0] > DBRI_MAX_GAIN || vol[1] > DBRI_MAX_GAIN)
+                       return -EINVAL;
+       }
+
+       if (info->left_gain != vol[0]) {
+               info->left_gain = vol[0];
                changed = 1;
        }
-       if (info->right_gain != ucontrol->value.integer.value[1]) {
-               info->right_gain = ucontrol->value.integer.value[1];
+       if (info->right_gain != vol[1]) {
+               info->right_gain = vol[1];
                changed = 1;
        }
        if (changed) {
index fee869bcc959a1c9e4da2c667fafebfcf406b6cb..89d6e9c351405c8d186176d7b80454d24153ad24 100644 (file)
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/module.h>
+#include <linux/mutex.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
 
-#include <sound/driver.h>
 #include <sound/initval.h>
 #include <sound/control.h>
 #include <sound/core.h>
@@ -76,8 +76,10 @@ struct snd_at73c213 {
        u8                              spi_rbuffer[2];
        /* Image of the SPI registers in AT73C213. */
        u8                              reg_image[18];
-       /* Protect registers against concurrent access. */
+       /* Protect SSC registers against concurrent access. */
        spinlock_t                      lock;
+       /* Protect mixer registers against concurrent access. */
+       struct mutex                    mixer_lock;
 };
 
 #define get_chip(card) ((struct snd_at73c213 *)card->private_data)
@@ -398,7 +400,7 @@ static int snd_at73c213_mono_get(struct snd_kcontrol *kcontrol,
        int mask = (kcontrol->private_value >> 16) & 0xff;
        int invert = (kcontrol->private_value >> 24) & 0xff;
 
-       spin_lock_irq(&chip->lock);
+       mutex_lock(&chip->mixer_lock);
 
        ucontrol->value.integer.value[0] =
                (chip->reg_image[reg] >> shift) & mask;
@@ -407,7 +409,7 @@ static int snd_at73c213_mono_get(struct snd_kcontrol *kcontrol,
                ucontrol->value.integer.value[0] =
                        mask - ucontrol->value.integer.value[0];
 
-       spin_unlock_irq(&chip->lock);
+       mutex_unlock(&chip->mixer_lock);
 
        return 0;
 }
@@ -428,13 +430,13 @@ static int snd_at73c213_mono_put(struct snd_kcontrol *kcontrol,
                val = mask - val;
        val <<= shift;
 
-       spin_lock_irq(&chip->lock);
+       mutex_lock(&chip->mixer_lock);
 
        val = (chip->reg_image[reg] & ~(mask << shift)) | val;
        change = val != chip->reg_image[reg];
        retval = snd_at73c213_write_reg(chip, reg, val);
 
-       spin_unlock_irq(&chip->lock);
+       mutex_unlock(&chip->mixer_lock);
 
        if (retval)
                return retval;
@@ -470,7 +472,7 @@ static int snd_at73c213_stereo_get(struct snd_kcontrol *kcontrol,
        int mask = (kcontrol->private_value >> 24) & 0xff;
        int invert = (kcontrol->private_value >> 22) & 1;
 
-       spin_lock_irq(&chip->lock);
+       mutex_lock(&chip->mixer_lock);
 
        ucontrol->value.integer.value[0] =
                (chip->reg_image[left_reg] >> shift_left) & mask;
@@ -484,7 +486,7 @@ static int snd_at73c213_stereo_get(struct snd_kcontrol *kcontrol,
                        mask - ucontrol->value.integer.value[1];
        }
 
-       spin_unlock_irq(&chip->lock);
+       mutex_unlock(&chip->mixer_lock);
 
        return 0;
 }
@@ -511,7 +513,7 @@ static int snd_at73c213_stereo_put(struct snd_kcontrol *kcontrol,
        val1 <<= shift_left;
        val2 <<= shift_right;
 
-       spin_lock_irq(&chip->lock);
+       mutex_lock(&chip->mixer_lock);
 
        val1 = (chip->reg_image[left_reg] & ~(mask << shift_left)) | val1;
        val2 = (chip->reg_image[right_reg] & ~(mask << shift_right)) | val2;
@@ -519,16 +521,16 @@ static int snd_at73c213_stereo_put(struct snd_kcontrol *kcontrol,
                || val2 != chip->reg_image[right_reg];
        retval = snd_at73c213_write_reg(chip, left_reg, val1);
        if (retval) {
-               spin_unlock_irq(&chip->lock);
+               mutex_unlock(&chip->mixer_lock);
                goto out;
        }
        retval = snd_at73c213_write_reg(chip, right_reg, val2);
        if (retval) {
-               spin_unlock_irq(&chip->lock);
+               mutex_unlock(&chip->mixer_lock);
                goto out;
        }
 
-       spin_unlock_irq(&chip->lock);
+       mutex_unlock(&chip->mixer_lock);
 
        return change;
 
@@ -536,16 +538,7 @@ out:
        return retval;
 }
 
-static int snd_at73c213_mono_switch_info(struct snd_kcontrol *kcontrol,
-                                 struct snd_ctl_elem_info *uinfo)
-{
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
-       uinfo->count = 1;
-       uinfo->value.integer.min = 0;
-       uinfo->value.integer.max = 1;
-
-       return 0;
-}
+#define snd_at73c213_mono_switch_info  snd_ctl_boolean_mono_info
 
 static int snd_at73c213_mono_switch_get(struct snd_kcontrol *kcontrol,
                                 struct snd_ctl_elem_value *ucontrol)
@@ -555,7 +548,7 @@ static int snd_at73c213_mono_switch_get(struct snd_kcontrol *kcontrol,
        int shift = (kcontrol->private_value >> 8) & 0xff;
        int invert = (kcontrol->private_value >> 24) & 0xff;
 
-       spin_lock_irq(&chip->lock);
+       mutex_lock(&chip->mixer_lock);
 
        ucontrol->value.integer.value[0] =
                (chip->reg_image[reg] >> shift) & 0x01;
@@ -564,7 +557,7 @@ static int snd_at73c213_mono_switch_get(struct snd_kcontrol *kcontrol,
                ucontrol->value.integer.value[0] =
                        0x01 - ucontrol->value.integer.value[0];
 
-       spin_unlock_irq(&chip->lock);
+       mutex_unlock(&chip->mixer_lock);
 
        return 0;
 }
@@ -589,14 +582,14 @@ static int snd_at73c213_mono_switch_put(struct snd_kcontrol *kcontrol,
                val = mask - val;
        val <<= shift;
 
-       spin_lock_irq(&chip->lock);
+       mutex_lock(&chip->mixer_lock);
 
        val |= (chip->reg_image[reg] & ~(mask << shift));
        change = val != chip->reg_image[reg];
 
        retval = snd_at73c213_write_reg(chip, reg, val);
 
-       spin_unlock_irq(&chip->lock);
+       mutex_unlock(&chip->mixer_lock);
 
        if (retval)
                return retval;
@@ -893,6 +886,7 @@ static int __devinit snd_at73c213_dev_init(struct snd_card *card,
                return irq;
 
        spin_lock_init(&chip->lock);
+       mutex_init(&chip->mixer_lock);
        chip->card = card;
        chip->irq = -1;
 
index ebcac13fd3970cd0c0fd989748b6a08c89a4b636..c89d2ea594b9f5dbd36d94c04e2e8fdacc5571bb 100644 (file)
@@ -18,7 +18,6 @@
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-#include <sound/driver.h>
 #include <linux/wait.h>
 #include <linux/slab.h>
 #include <linux/string.h>
index 9b63814c3f64412bb593b5d745a8e34b1d5f865d..0a5391436addfd3f0b67c5f91aa487f1af349bd7 100644 (file)
@@ -19,7 +19,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <sound/core.h>
 #include <sound/hwdep.h>
 #include <asm/uaccess.h>
index 3436816727c8190ff0f5e5960c38f62c7c01e886..f60a98ef7dec3d0d4e1dafc325471ae16e1de93c 100644 (file)
@@ -22,7 +22,6 @@
  *                             midi emulation.
  */
 
-#include <sound/driver.h>
 
 #ifdef CONFIG_SND_SEQUENCER_OSS
 
index 680f2b7fec207158abd4ef28cec6c72364ac9d83..687e6a13689e7cd912ac99ca79b9a14883931a56 100644 (file)
@@ -18,7 +18,6 @@
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-#include <sound/driver.h>
 #include <linux/wait.h>
 #include <linux/slab.h>
 #include <sound/core.h>
index 0a56ca18b16560da1de776b0f022d3216810b796..09711f84ed3049129681cb8b074e7f2b9c0ce2e2 100644 (file)
@@ -22,7 +22,6 @@
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-#include <sound/driver.h>
 #include <linux/wait.h>
 #include <linux/sched.h>
 #include <sound/core.h>
index 455e535933ecf0b3ac1a182588677a3ae31b95eb..36d53bd317ede3f2d3cc1974c7003a7746789d14 100644 (file)
@@ -25,7 +25,6 @@
  * of doing things so that the old sfxload utility can be used.
  * Everything may change when there is an alsa way of doing things.
  */
-#include <sound/driver.h>
 #include <asm/uaccess.h>
 #include <linux/slab.h>
 #include <sound/core.h>
index 6fc3d2b2519f935c76f1156962d4bae4cd0a6750..deabe5f899c494780eb29c188f9fe23edf8c92e8 100644 (file)
@@ -19,7 +19,6 @@
  */
 
 #include <linux/mutex.h>
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <sound/core.h>
index 706143826aff8102977b9c1cffa72d66ce0684ae..9351b8a765b9c6de7f5069e2c3c6d09b0f54a50d 100644 (file)
@@ -31,17 +31,18 @@ config SND_USB_USX2Y
 
 config SND_USB_CAIAQ
        tristate "Native Instruments USB audio devices"
-        depends on SND && USB
-        select SND_HWDEP
-        select SND_RAWMIDI
-        select SND_PCM
-        help
+       depends on SND && USB
+       select SND_HWDEP
+       select SND_RAWMIDI
+       select SND_PCM
+       help
           Say Y here to include support for caiaq USB audio interfaces,
           namely:
 
            * Native Instruments RigKontrol2
            * Native Instruments RigKontrol3
            * Native Instruments Kore Controller
+           * Native Instruments Kore Controller 2
            * Native Instruments Audio Kontrol 1
            * Native Instruments Audio 8 DJ
 
@@ -51,12 +52,15 @@ config SND_USB_CAIAQ
 config SND_USB_CAIAQ_INPUT
        bool "enable input device for controllers"
        depends on SND_USB_CAIAQ
+       depends on INPUT=y || INPUT=SND_USB_CAIAQ
        help
          Say Y here to support input controllers like buttons, knobs,
          alpha dials and analog pedals on the following products:
 
           * Native Instruments RigKontrol2
           * Native Instruments RigKontrol3
+          * Native Instruments Kore Controller
+          * Native Instruments Kore Controller 2
           * Native Instruments Audio Kontrol 1
 
 endmenu
index 455c8c58a1bdeb9e37edea913560453fb91ae3e1..23dadd5a11cd2d3e664ee96a12dbac4087ab2bfc 100644 (file)
@@ -1,3 +1,4 @@
-snd-usb-caiaq-objs := caiaq-device.o caiaq-audio.o caiaq-midi.o caiaq-input.o
+snd-usb-caiaq-y := caiaq-device.o caiaq-audio.o caiaq-midi.o caiaq-control.o
+snd-usb-caiaq-$(CONFIG_SND_USB_CAIAQ_INPUT) += caiaq-input.o
 
 obj-$(CONFIG_SND_USB_CAIAQ) += snd-usb-caiaq.o
index 0666908a2361a95023c5a897bdacbe25650f4bc6..9cc4cd8283f91561d744641b0afbead6e8b0495a 100644 (file)
@@ -16,7 +16,6 @@
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 */
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
@@ -27,9 +26,7 @@
 #include <sound/initval.h>
 #include <sound/pcm.h>
 #include <sound/rawmidi.h>
-#ifdef CONFIG_SND_USB_CAIAQ_INPUT
 #include <linux/input.h>
-#endif
 
 #include "caiaq-device.h"
 #include "caiaq-audio.h"
@@ -60,7 +57,7 @@ static struct snd_pcm_hardware snd_usb_caiaq_pcm_hardware = {
        .channels_min   = CHANNELS_PER_STREAM,
        .channels_max   = CHANNELS_PER_STREAM,
        .buffer_bytes_max = MAX_BUFFER_SIZE,
-       .period_bytes_min = 4096,
+       .period_bytes_min = 128,
        .period_bytes_max = MAX_BUFFER_SIZE,
        .periods_min    = 1,
        .periods_max    = 1024,
@@ -606,7 +603,7 @@ static void free_urbs(struct urb **urbs)
        kfree(urbs);
 }
 
-int __devinit snd_usb_caiaq_audio_init(struct snd_usb_caiaqdev *dev)
+int snd_usb_caiaq_audio_init(struct snd_usb_caiaqdev *dev)
 {
        int i, ret;
 
diff --git a/sound/usb/caiaq/caiaq-control.c b/sound/usb/caiaq/caiaq-control.c
new file mode 100644 (file)
index 0000000..798ca12
--- /dev/null
@@ -0,0 +1,315 @@
+/*
+ *   Copyright (c) 2007 Daniel Mack
+ *   friendly supported by NI.
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/usb.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include <sound/rawmidi.h>
+#include <sound/control.h>
+#include <linux/input.h>
+
+#include "caiaq-device.h"
+#include "caiaq-control.h"
+
+#define CNT_INTVAL 0x10000
+
+static int control_info(struct snd_kcontrol *kcontrol,
+                       struct snd_ctl_elem_info *uinfo)
+{
+       struct snd_usb_audio *chip = snd_kcontrol_chip(kcontrol);
+       struct snd_usb_caiaqdev *dev = caiaqdev(chip->card);
+       int pos = kcontrol->private_value;
+       int is_intval = pos & CNT_INTVAL;
+
+       uinfo->count = 1;
+       pos &= ~CNT_INTVAL;
+
+       if (dev->chip.usb_id ==
+               USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO8DJ)
+               && (pos == 0)) {
+               /* current input mode of A8DJ */
+               uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+               uinfo->value.integer.min = 0;
+               uinfo->value.integer.max = 2;
+               return 0;
+       }
+
+       if (is_intval) {
+               uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+               uinfo->value.integer.min = 0;
+               uinfo->value.integer.max = 64;
+       } else {
+               uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+               uinfo->value.integer.min = 0;
+               uinfo->value.integer.max = 1;
+       }
+
+       return 0;
+}
+
+static int control_get(struct snd_kcontrol *kcontrol,
+                      struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_usb_audio *chip = snd_kcontrol_chip(kcontrol);
+       struct snd_usb_caiaqdev *dev = caiaqdev(chip->card);
+       int pos = kcontrol->private_value;
+
+       if (pos & CNT_INTVAL)
+               ucontrol->value.integer.value[0]
+                       = dev->control_state[pos & ~CNT_INTVAL];
+       else
+               ucontrol->value.integer.value[0]
+                       = !!(dev->control_state[pos / 8] & (1 << pos % 8));
+
+       return 0;
+}
+
+static int control_put(struct snd_kcontrol *kcontrol,
+                      struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_usb_audio *chip = snd_kcontrol_chip(kcontrol);
+       struct snd_usb_caiaqdev *dev = caiaqdev(chip->card);
+       int pos = kcontrol->private_value;
+
+       if (pos & CNT_INTVAL) {
+               dev->control_state[pos & ~CNT_INTVAL]
+                       = ucontrol->value.integer.value[0];
+               snd_usb_caiaq_send_command(dev, EP1_CMD_DIMM_LEDS,
+                               dev->control_state, sizeof(dev->control_state));
+       } else {
+               if (ucontrol->value.integer.value[0])
+                       dev->control_state[pos / 8] |= 1 << (pos % 8);
+               else
+                       dev->control_state[pos / 8] &= ~(1 << (pos % 8));
+
+               snd_usb_caiaq_send_command(dev, EP1_CMD_WRITE_IO,
+                               dev->control_state, sizeof(dev->control_state));
+       }
+
+       return 1;
+}
+
+static struct snd_kcontrol_new kcontrol_template __devinitdata = {
+       .iface = SNDRV_CTL_ELEM_IFACE_HWDEP,
+       .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+       .index = 0,
+       .info = control_info,
+       .get  = control_get,
+       .put  = control_put,
+       /* name and private_value filled later */
+};
+
+struct caiaq_controller {
+       char *name;
+       int index;
+};
+
+static struct caiaq_controller ak1_controller[] = {
+       { "LED left",   2 },
+       { "LED middle", 1 },
+       { "LED right",  0 },
+       { "LED ring",   3 }
+};
+
+static struct caiaq_controller rk2_controller[] = {
+       { "LED 1",              5  },
+       { "LED 2",              4  },
+       { "LED 3",              3  },
+       { "LED 4",              2  },
+       { "LED 5",              1  },
+       { "LED 6",              0  },
+       { "LED pedal",          6  },
+       { "LED 7seg_1b",        8  },
+       { "LED 7seg_1c",        9  },
+       { "LED 7seg_2a",        10 },
+       { "LED 7seg_2b",        11 },
+       { "LED 7seg_2c",        12 },
+       { "LED 7seg_2d",        13 },
+       { "LED 7seg_2e",        14 },
+       { "LED 7seg_2f",        15 },
+       { "LED 7seg_2g",        16 },
+       { "LED 7seg_3a",        17 },
+       { "LED 7seg_3b",        18 },
+       { "LED 7seg_3c",        19 },
+       { "LED 7seg_3d",        20 },
+       { "LED 7seg_3e",        21 },
+       { "LED 7seg_3f",        22 },
+       { "LED 7seg_3g",        23 }
+};
+
+static struct caiaq_controller rk3_controller[] = {
+       { "LED 7seg_1a",        0 + 0 },
+       { "LED 7seg_1b",        0 + 1 },
+       { "LED 7seg_1c",        0 + 2 },
+       { "LED 7seg_1d",        0 + 3 },
+       { "LED 7seg_1e",        0 + 4 },
+       { "LED 7seg_1f",        0 + 5 },
+       { "LED 7seg_1g",        0 + 6 },
+       { "LED 7seg_1p",        0 + 7 },
+
+       { "LED 7seg_2a",        8 + 0 },
+       { "LED 7seg_2b",        8 + 1 },
+       { "LED 7seg_2c",        8 + 2 },
+       { "LED 7seg_2d",        8 + 3 },
+       { "LED 7seg_2e",        8 + 4 },
+       { "LED 7seg_2f",        8 + 5 },
+       { "LED 7seg_2g",        8 + 6 },
+       { "LED 7seg_2p",        8 + 7 },
+
+       { "LED 7seg_3a",        16 + 0 },
+       { "LED 7seg_3b",        16 + 1 },
+       { "LED 7seg_3c",        16 + 2 },
+       { "LED 7seg_3d",        16 + 3 },
+       { "LED 7seg_3e",        16 + 4 },
+       { "LED 7seg_3f",        16 + 5 },
+       { "LED 7seg_3g",        16 + 6 },
+       { "LED 7seg_3p",        16 + 7 },
+
+       { "LED 7seg_4a",        24 + 0 },
+       { "LED 7seg_4b",        24 + 1 },
+       { "LED 7seg_4c",        24 + 2 },
+       { "LED 7seg_4d",        24 + 3 },
+       { "LED 7seg_4e",        24 + 4 },
+       { "LED 7seg_4f",        24 + 5 },
+       { "LED 7seg_4g",        24 + 6 },
+       { "LED 7seg_4p",        24 + 7 },
+
+       { "LED 1",              32 + 0 },
+       { "LED 2",              32 + 1 },
+       { "LED 3",              32 + 2 },
+       { "LED 4",              32 + 3 },
+       { "LED 5",              32 + 4 },
+       { "LED 6",              32 + 5 },
+       { "LED 7",              32 + 6 },
+       { "LED 8",              32 + 7 },
+       { "LED pedal",          32 + 8 }
+};
+
+static struct caiaq_controller kore_controller[] = {
+       { "LED F1",             8   | CNT_INTVAL },
+       { "LED F2",             12  | CNT_INTVAL },
+       { "LED F3",             0   | CNT_INTVAL },
+       { "LED F4",             4   | CNT_INTVAL },
+       { "LED F5",             11  | CNT_INTVAL },
+       { "LED F6",             15  | CNT_INTVAL },
+       { "LED F7",             3   | CNT_INTVAL },
+       { "LED F8",             7   | CNT_INTVAL },
+       { "LED touch1",         10  | CNT_INTVAL },
+       { "LED touch2",         14  | CNT_INTVAL },
+       { "LED touch3",         2   | CNT_INTVAL },
+       { "LED touch4",         6   | CNT_INTVAL },
+       { "LED touch5",         9   | CNT_INTVAL },
+       { "LED touch6",         13  | CNT_INTVAL },
+       { "LED touch7",         1   | CNT_INTVAL },
+       { "LED touch8",         5   | CNT_INTVAL },
+       { "LED left",           18  | CNT_INTVAL },
+       { "LED right",          22  | CNT_INTVAL },
+       { "LED up",             16  | CNT_INTVAL },
+       { "LED down",           20  | CNT_INTVAL },
+       { "LED stop",           23  | CNT_INTVAL },
+       { "LED play",           21  | CNT_INTVAL },
+       { "LED record",         19  | CNT_INTVAL },
+       { "LED listen",         17  | CNT_INTVAL },
+       { "LED lcd",            30  | CNT_INTVAL },
+       { "LED menu",           28  | CNT_INTVAL },
+       { "LED sound",          31  | CNT_INTVAL },
+       { "LED esc",            29  | CNT_INTVAL },
+       { "LED view",           27  | CNT_INTVAL },
+       { "LED enter",          24  | CNT_INTVAL },
+       { "LED control",        26  | CNT_INTVAL }
+};
+
+static struct caiaq_controller a8dj_controller[] = {
+       { "Current input mode",                 0 | CNT_INTVAL  },
+       { "GND lift for TC Vinyl mode",         24 + 0          },
+       { "GND lift for TC CD/Line mode",       24 + 1          },
+       { "GND lift for phono mode",            24 + 2          },
+       { "GND lift for TC Vinyl mode",         24 + 3          },
+       { "Software lock",                      40              }
+};
+
+int __devinit snd_usb_caiaq_control_init(struct snd_usb_caiaqdev *dev)
+{
+       int i;
+       struct snd_kcontrol *kc;
+
+       switch (dev->chip.usb_id) {
+       case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AK1):
+               for (i = 0; i < ARRAY_SIZE(ak1_controller); i++) {
+                       struct caiaq_controller *c = ak1_controller + i;
+                       kcontrol_template.name = c->name;
+                       kcontrol_template.private_value = c->index;
+                       kc = snd_ctl_new1(&kcontrol_template, dev);
+                       snd_ctl_add(dev->chip.card, kc);
+               }
+
+               break;
+
+       case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL2):
+               for (i = 0; i < ARRAY_SIZE(rk2_controller); i++) {
+                       struct caiaq_controller *c = rk2_controller + i;
+                       kcontrol_template.name = c->name;
+                       kcontrol_template.private_value = c->index;
+                       kc = snd_ctl_new1(&kcontrol_template, dev);
+                       snd_ctl_add(dev->chip.card, kc);
+               }
+
+               break;
+
+       case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL3):
+               for (i = 0; i < ARRAY_SIZE(rk3_controller); i++) {
+                       struct caiaq_controller *c = rk3_controller + i;
+                       kcontrol_template.name = c->name;
+                       kcontrol_template.private_value = c->index;
+                       kc = snd_ctl_new1(&kcontrol_template, dev);
+                       snd_ctl_add(dev->chip.card, kc);
+               }
+
+               break;
+
+       case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER):
+       case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER2):
+               for (i = 0; i < ARRAY_SIZE(kore_controller); i++) {
+                       struct caiaq_controller *c = kore_controller + i;
+                       kcontrol_template.name = c->name;
+                       kcontrol_template.private_value = c->index;
+                       kc = snd_ctl_new1(&kcontrol_template, dev);
+                       snd_ctl_add(dev->chip.card, kc);
+               }
+
+               break;
+
+       case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO8DJ):
+               for (i = 0; i < ARRAY_SIZE(a8dj_controller); i++) {
+                       struct caiaq_controller *c = a8dj_controller + i;
+                       kcontrol_template.name = c->name;
+                       kcontrol_template.private_value = c->index;
+                       kc = snd_ctl_new1(&kcontrol_template, dev);
+                       snd_ctl_add(dev->chip.card, kc);
+               }
+
+               break;
+       }
+
+       return 0;
+}
+
diff --git a/sound/usb/caiaq/caiaq-control.h b/sound/usb/caiaq/caiaq-control.h
new file mode 100644 (file)
index 0000000..2e7ab1a
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef CAIAQ_CONTROL_H
+#define CAIAQ_CONTROL_H
+
+int snd_usb_caiaq_control_init(struct snd_usb_caiaqdev *dev);
+
+#endif /* CAIAQ_CONTROL_H */
index 58af8142c57100cf3b549dbbe73bd844d7e85d46..58d25e4e7d6cf34324ed67a8454c93d4225967e2 100644 (file)
 #include <linux/usb.h>
 #include <linux/input.h>
 #include <linux/spinlock.h>
-#include <sound/driver.h>
 #include <sound/core.h>
 #include <sound/initval.h>
 #include <sound/pcm.h>
 #include <sound/rawmidi.h>
+#include <sound/control.h>
 
 #include "caiaq-device.h"
 #include "caiaq-audio.h"
 #include "caiaq-midi.h"
+#include "caiaq-control.h"
 
 #ifdef CONFIG_SND_USB_CAIAQ_INPUT
 #include "caiaq-input.h"
 #endif
 
 MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>");
-MODULE_DESCRIPTION("caiaq USB audio, version 1.2.0");
+MODULE_DESCRIPTION("caiaq USB audio, version 1.3.2");
 MODULE_LICENSE("GPL");
 MODULE_SUPPORTED_DEVICE("{{Native Instruments, RigKontrol2},"
                         "{Native Instruments, RigKontrol3},"
                         "{Native Instruments, Kore Controller},"
+                        "{Native Instruments, Kore Controller 2},"
                         "{Native Instruments, Audio Kontrol 1}"
                         "{Native Instruments, Audio 8 DJ}}");
 
@@ -93,6 +95,11 @@ static struct usb_device_id snd_usb_id_table[] = {
                .idVendor =     USB_VID_NATIVEINSTRUMENTS,
                .idProduct =    USB_PID_KORECONTROLLER
        },
+       {
+               .match_flags =  USB_DEVICE_ID_MATCH_DEVICE,
+               .idVendor =     USB_VID_NATIVEINSTRUMENTS,
+               .idProduct =    USB_PID_KORECONTROLLER2
+       },
        {
                .match_flags =  USB_DEVICE_ID_MATCH_DEVICE,
                .idVendor =     USB_VID_NATIVEINSTRUMENTS,
@@ -140,14 +147,21 @@ static void usb_ep1_command_reply_dispatch (struct urb* urb)
        case EP1_CMD_MIDI_READ:
                snd_usb_caiaq_midi_handle_input(dev, buf[1], buf + 3, buf[2]);
                break;
-
+       case EP1_CMD_READ_IO:
+               if (dev->chip.usb_id ==
+                       USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO8DJ)) {
+                       if (urb->actual_length > sizeof(dev->control_state))
+                               urb->actual_length = sizeof(dev->control_state);
+                       memcpy(dev->control_state, buf + 1, urb->actual_length);
+                       wake_up(&dev->ep1_wait_queue);
+                       break;
+               }
 #ifdef CONFIG_SND_USB_CAIAQ_INPUT
        case EP1_CMD_READ_ERP:
        case EP1_CMD_READ_ANALOG:
-       case EP1_CMD_READ_IO:
                snd_usb_caiaq_input_dispatch(dev, buf, urb->actual_length);
-               break;
 #endif
+               break;
        }
 
        dev->ep1_in_urb.actual_length = 0;
@@ -156,10 +170,10 @@ static void usb_ep1_command_reply_dispatch (struct urb* urb)
                log("unable to submit urb. OOM!?\n");
 }
 
-static int send_command (struct snd_usb_caiaqdev *dev,
-                        unsigned char command, 
-                        const unsigned char *buffer,
-                        int len)
+int snd_usb_caiaq_send_command(struct snd_usb_caiaqdev *dev,
+                              unsigned char command,
+                              const unsigned char *buffer,
+                              int len)
 {
        int actual_len;
        struct usb_device *usb_dev = dev->chip.dev;
@@ -207,7 +221,8 @@ int snd_usb_caiaq_set_audio_params (struct snd_usb_caiaqdev *dev,
                rate, depth, bpp);
 
        dev->audio_parm_answer = -1;
-       ret = send_command(dev, EP1_CMD_AUDIO_PARAMS, tmp, sizeof(tmp));
+       ret = snd_usb_caiaq_send_command(dev, EP1_CMD_AUDIO_PARAMS,
+                                        tmp, sizeof(tmp));
 
        if (ret)
                return ret;
@@ -226,7 +241,8 @@ int snd_usb_caiaq_set_auto_msg (struct snd_usb_caiaqdev *dev,
                                int digital, int analog, int erp)
 {
        char tmp[3] = { digital, analog, erp };
-       return send_command(dev, EP1_CMD_AUTO_MSG, tmp, sizeof(tmp));
+       return snd_usb_caiaq_send_command(dev, EP1_CMD_AUTO_MSG,
+                                         tmp, sizeof(tmp));
 }
 
 static void setup_card(struct snd_usb_caiaqdev *dev)
@@ -241,7 +257,7 @@ static void setup_card(struct snd_usb_caiaqdev *dev)
                val[0] = 0x00;
                val[1] = 0x00;
                val[2] = 0x01;
-               send_command(dev, EP1_CMD_WRITE_IO, val, 3);
+               snd_usb_caiaq_send_command(dev, EP1_CMD_WRITE_IO, val, 3);
                break;
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL3):
                /* RigKontrol2 - display two centered dashes ('--') */
@@ -249,22 +265,52 @@ static void setup_card(struct snd_usb_caiaqdev *dev)
                val[1] = 0x40;
                val[2] = 0x40;
                val[3] = 0x00;
-               send_command(dev, EP1_CMD_WRITE_IO, val, 4);
+               snd_usb_caiaq_send_command(dev, EP1_CMD_WRITE_IO, val, 4);
                break;
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AK1):
                /* Audio Kontrol 1 - make USB-LED stop blinking */
                val[0] = 0x00;
-               send_command(dev, EP1_CMD_WRITE_IO, val, 1);
+               snd_usb_caiaq_send_command(dev, EP1_CMD_WRITE_IO, val, 1);
+               break;
+       case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO8DJ):
+               /* Audio 8 DJ - trigger read of current settings */
+               dev->control_state[0] = 0xff;
+               snd_usb_caiaq_set_auto_msg(dev, 1, 0, 0);
+               snd_usb_caiaq_send_command(dev, EP1_CMD_READ_IO, NULL, 0);
+
+               if (!wait_event_timeout(dev->ep1_wait_queue,
+                                       dev->control_state[0] != 0xff, HZ))
+                       return;
+
+               /* fix up some defaults */
+               if ((dev->control_state[1] != 2) ||
+                   (dev->control_state[2] != 3) ||
+                   (dev->control_state[4] != 2)) {
+                       dev->control_state[1] = 2;
+                       dev->control_state[2] = 3;
+                       dev->control_state[4] = 2;
+                       snd_usb_caiaq_send_command(dev,
+                               EP1_CMD_WRITE_IO, dev->control_state, 6);
+               }
+
                break;
        }
        
-       ret = snd_usb_caiaq_audio_init(dev);
-       if (ret < 0)
-               log("Unable to set up audio system (ret=%d)\n", ret);
+       if (dev->spec.num_analog_audio_out +
+           dev->spec.num_analog_audio_in +
+           dev->spec.num_digital_audio_out +
+           dev->spec.num_digital_audio_in > 0) {
+               ret = snd_usb_caiaq_audio_init(dev);
+               if (ret < 0)
+                       log("Unable to set up audio system (ret=%d)\n", ret);
+       }
        
-       ret = snd_usb_caiaq_midi_init(dev);
-       if (ret < 0)
-               log("Unable to set up MIDI system (ret=%d)\n", ret);
+       if (dev->spec.num_midi_in +
+           dev->spec.num_midi_out > 0) {
+               ret = snd_usb_caiaq_midi_init(dev);
+               if (ret < 0)
+                       log("Unable to set up MIDI system (ret=%d)\n", ret);
+       }
 
 #ifdef CONFIG_SND_USB_CAIAQ_INPUT
        ret = snd_usb_caiaq_input_init(dev);
@@ -278,6 +324,10 @@ static void setup_card(struct snd_usb_caiaqdev *dev)
                log("snd_card_register() returned %d\n", ret);
                snd_card_free(dev->chip.card);
        }
+
+       ret = snd_usb_caiaq_control_init(dev);
+       if (ret < 0)
+               log("Unable to set up control system (ret=%d)\n", ret);
 }
 
 static struct snd_card* create_card(struct usb_device* usb_dev)
@@ -340,7 +390,7 @@ static int init_card(struct snd_usb_caiaqdev *dev)
        if (usb_submit_urb(&dev->ep1_in_urb, GFP_KERNEL) != 0)
                return -EIO;
 
-       err = send_command(dev, EP1_CMD_GET_DEVICE_INFO, NULL, 0);
+       err = snd_usb_caiaq_send_command(dev, EP1_CMD_GET_DEVICE_INFO, NULL, 0);
        if (err)
                return err;
 
index 79bc5be2df7a2249a86b847b536475adfea68853..96a491379c6062b540ff2a063f64735f1e2f640e 100644 (file)
@@ -7,7 +7,8 @@
 
 #define USB_PID_RIGKONTROL2    0x1969
 #define USB_PID_RIGKONTROL3    0x1940
-#define USB_PID_KORECONTROLLER         0x4711
+#define USB_PID_KORECONTROLLER 0x4711
+#define USB_PID_KORECONTROLLER2        0x4712
 #define USB_PID_AK1            0x0815
 #define USB_PID_AUDIO8DJ       0x1978
 
@@ -35,6 +36,7 @@
 #define EP1_CMD_MIDI_WRITE     0x7
 #define EP1_CMD_AUDIO_PARAMS   0x9
 #define EP1_CMD_AUTO_MSG       0xb
+#define EP1_CMD_DIMM_LEDS       0xc
 
 struct caiaq_device_spec {
        unsigned short fw_version;
@@ -62,7 +64,7 @@ struct snd_usb_caiaqdev {
        struct urb **data_urbs_in;
        struct urb **data_urbs_out;
        struct snd_usb_caiaq_cb_info *data_cb_info;
-       
+
        unsigned char ep1_in_buf[EP1_BUFSIZE];
        unsigned char ep1_out_buf[EP1_BUFSIZE];
        unsigned char midi_out_buf[EP1_BUFSIZE];
@@ -72,7 +74,7 @@ struct snd_usb_caiaqdev {
        wait_queue_head_t ep1_wait_queue;
        wait_queue_head_t prepare_wait_queue;
        int spec_received, audio_parm_answer;
-       
+
        char vendor_name[CAIAQ_USB_STR_LEN];
        char product_name[CAIAQ_USB_STR_LEN];
        char serial[CAIAQ_USB_STR_LEN];
@@ -90,11 +92,16 @@ struct snd_usb_caiaqdev {
        struct snd_pcm_substream *sub_playback[MAX_STREAMS];
        struct snd_pcm_substream *sub_capture[MAX_STREAMS];
 
+       /* Controls */
+       unsigned char control_state[64];
+
        /* Linux input */
 #ifdef CONFIG_SND_USB_CAIAQ_INPUT
        struct input_dev *input_dev;
+       char phys[64];                  /* physical device path */
+       unsigned short keycode[64];
 #endif
-       
+
        /* ALSA */
        struct snd_pcm *pcm;
        struct snd_pcm_hardware pcm_info;
@@ -112,6 +119,9 @@ struct snd_usb_caiaq_cb_info {
 
 int snd_usb_caiaq_set_audio_params (struct snd_usb_caiaqdev *dev, int rate, int depth, int bbp);
 int snd_usb_caiaq_set_auto_msg (struct snd_usb_caiaqdev *dev, int digital, int analog, int erp);
-
+int snd_usb_caiaq_send_command(struct snd_usb_caiaqdev *dev,
+                              unsigned char command,
+                              const unsigned char *buffer,
+                              int len);
 
 #endif /* CAIAQ_DEVICE_H */
index cd536ca20e5632d479a70e2d498da16555cfe79d..f743847a5e5a0a9e8aa7d1e8a67ccb204586821a 100644 (file)
 #include <linux/moduleparam.h>
 #include <linux/input.h>
 #include <linux/usb.h>
+#include <linux/usb/input.h>
 #include <linux/spinlock.h>
-#include <sound/driver.h>
 #include <sound/core.h>
 #include <sound/rawmidi.h>
 #include <sound/pcm.h>
 #include "caiaq-device.h"
 #include "caiaq-input.h"
 
-#ifdef CONFIG_SND_USB_CAIAQ_INPUT
-
-static unsigned char keycode_ak1[] =  { KEY_C, KEY_B, KEY_A };
-static unsigned char keycode_rk2[] =  { KEY_1, KEY_2, KEY_3, KEY_4, 
-                                       KEY_5, KEY_6, KEY_7 };
-static unsigned char keycode_rk3[] =  { KEY_1, KEY_2, KEY_3, KEY_4,
-                                       KEY_5, KEY_6, KEY_7, KEY_5, KEY_6 };
-
-#define DEG90  (range/2)
-#define DEG180 (range)
-#define DEG270 (DEG90 + DEG180)
-#define DEG360 (DEG180 * 2)
-#define HIGH_PEAK (268)
-#define LOW_PEAK (-7)
+static unsigned short keycode_ak1[] =  { KEY_C, KEY_B, KEY_A };
+static unsigned short keycode_rk2[] =  { KEY_1, KEY_2, KEY_3, KEY_4,
+                                        KEY_5, KEY_6, KEY_7 };
+static unsigned short keycode_rk3[] =  { KEY_1, KEY_2, KEY_3, KEY_4,
+                                        KEY_5, KEY_6, KEY_7, KEY_5, KEY_6 };
+
+static unsigned short keycode_kore[] = {
+       KEY_FN_F1,      /* "menu"               */
+       KEY_FN_F7,      /* "lcd backlight       */
+       KEY_FN_F2,      /* "control"            */
+       KEY_FN_F3,      /* "enter"              */
+       KEY_FN_F4,      /* "view"               */
+       KEY_FN_F5,      /* "esc"                */
+       KEY_FN_F6,      /* "sound"              */
+       KEY_FN_F8,      /* array spacer, never triggered. */
+       KEY_RIGHT,
+       KEY_DOWN,
+       KEY_UP,
+       KEY_LEFT,
+       KEY_SOUND,      /* "listen"             */
+       KEY_RECORD,
+       KEY_PLAYPAUSE,
+       KEY_STOP,
+       BTN_4,          /* 8 softkeys */
+       BTN_3,
+       BTN_2,
+       BTN_1,
+       BTN_8,
+       BTN_7,
+       BTN_6,
+       BTN_5,
+       KEY_BRL_DOT4,   /* touch sensitive knobs */
+       KEY_BRL_DOT3,
+       KEY_BRL_DOT2,
+       KEY_BRL_DOT1,
+       KEY_BRL_DOT8,
+       KEY_BRL_DOT7,
+       KEY_BRL_DOT6,
+       KEY_BRL_DOT5
+};
+
+#define DEG90          (range / 2)
+#define DEG180         (range)
+#define DEG270         (DEG90 + DEG180)
+#define DEG360         (DEG180 * 2)
+#define HIGH_PEAK      (268)
+#define LOW_PEAK       (-7)
 
 /* some of these devices have endless rotation potentiometers
  * built in which use two tapers, 90 degrees phase shifted.
@@ -56,8 +89,8 @@ static unsigned int decode_erp(unsigned char a, unsigned char b)
        int range = HIGH_PEAK - LOW_PEAK;
        int mid_value = (HIGH_PEAK + LOW_PEAK) / 2;
 
-       weight_b = abs(mid_value-a) - (range/2 - 100)/2;
-       
+       weight_b = abs(mid_value - a) - (range / 2 - 100) / 2;
+
        if (weight_b < 0)
                weight_b = 0;
 
@@ -93,7 +126,7 @@ static unsigned int decode_erp(unsigned char a, unsigned char b)
 
        if (ret < 0)
                ret += 1000;
-       
+
        if (ret >= 1000)
                ret -= 1000;
 
@@ -108,76 +141,113 @@ static unsigned int decode_erp(unsigned char a, unsigned char b)
 #undef LOW_PEAK
 
 
-static void snd_caiaq_input_read_analog(struct snd_usb_caiaqdev *dev, 
+static void snd_caiaq_input_read_analog(struct snd_usb_caiaqdev *dev,
                                        const unsigned char *buf,
                                        unsigned int len)
 {
-       switch(dev->input_dev->id.product) {
-       case USB_PID_RIGKONTROL2:
-               input_report_abs(dev->input_dev, ABS_X, (buf[4] << 8) |buf[5]);
-               input_report_abs(dev->input_dev, ABS_Y, (buf[0] << 8) |buf[1]);
-               input_report_abs(dev->input_dev, ABS_Z, (buf[2] << 8) |buf[3]);
-               input_sync(dev->input_dev);
+       struct input_dev *input_dev = dev->input_dev;
+
+       switch (dev->chip.usb_id) {
+       case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL2):
+               input_report_abs(input_dev, ABS_X, (buf[4] << 8) | buf[5]);
+               input_report_abs(input_dev, ABS_Y, (buf[0] << 8) | buf[1]);
+               input_report_abs(input_dev, ABS_Z, (buf[2] << 8) | buf[3]);
+               input_sync(input_dev);
                break;
-       case USB_PID_RIGKONTROL3:
-               input_report_abs(dev->input_dev, ABS_X, (buf[0] << 8) |buf[1]);
-               input_report_abs(dev->input_dev, ABS_Y, (buf[2] << 8) |buf[3]);
-               input_report_abs(dev->input_dev, ABS_Z, (buf[4] << 8) |buf[5]);
-               input_sync(dev->input_dev);
+       case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL3):
+               input_report_abs(input_dev, ABS_X, (buf[0] << 8) | buf[1]);
+               input_report_abs(input_dev, ABS_Y, (buf[2] << 8) | buf[3]);
+               input_report_abs(input_dev, ABS_Z, (buf[4] << 8) | buf[5]);
+               input_sync(input_dev);
+               break;
+       case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER):
+       case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER2):
+               input_report_abs(input_dev, ABS_X, (buf[0] << 8) | buf[1]);
+               input_report_abs(input_dev, ABS_Y, (buf[2] << 8) | buf[3]);
+               input_report_abs(input_dev, ABS_Z, (buf[4] << 8) | buf[5]);
+               input_sync(input_dev);
                break;
        }
 }
 
-static void snd_caiaq_input_read_erp(struct snd_usb_caiaqdev *dev, 
+static void snd_caiaq_input_read_erp(struct snd_usb_caiaqdev *dev,
                                     const char *buf, unsigned int len)
 {
+       struct input_dev *input_dev = dev->input_dev;
        int i;
 
-       switch(dev->input_dev->id.product) {
-       case USB_PID_AK1:
+       switch (dev->chip.usb_id) {
+       case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AK1):
                i = decode_erp(buf[0], buf[1]);
-               input_report_abs(dev->input_dev, ABS_X, i);
-               input_sync(dev->input_dev);
+               input_report_abs(input_dev, ABS_X, i);
+               input_sync(input_dev);
+               break;
+       case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER):
+       case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER2):
+               i = decode_erp(buf[7], buf[5]);
+               input_report_abs(input_dev, ABS_HAT0X, i);
+               i = decode_erp(buf[12], buf[14]);
+               input_report_abs(input_dev, ABS_HAT0Y, i);
+               i = decode_erp(buf[15], buf[13]);
+               input_report_abs(input_dev, ABS_HAT1X, i);
+               i = decode_erp(buf[0], buf[2]);
+               input_report_abs(input_dev, ABS_HAT1Y, i);
+               i = decode_erp(buf[3], buf[1]);
+               input_report_abs(input_dev, ABS_HAT2X, i);
+               i = decode_erp(buf[8], buf[10]);
+               input_report_abs(input_dev, ABS_HAT2Y, i);
+               i = decode_erp(buf[11], buf[9]);
+               input_report_abs(input_dev, ABS_HAT3X, i);
+               i = decode_erp(buf[4], buf[6]);
+               input_report_abs(input_dev, ABS_HAT3Y, i);
+               input_sync(input_dev);
                break;
        }
 }
 
-static void snd_caiaq_input_read_io(struct snd_usb_caiaqdev *dev, 
+static void snd_caiaq_input_read_io(struct snd_usb_caiaqdev *dev,
                                    char *buf, unsigned int len)
 {
+       struct input_dev *input_dev = dev->input_dev;
+       unsigned short *keycode = input_dev->keycode;
        int i;
-       unsigned char *keycode = dev->input_dev->keycode;
 
        if (!keycode)
                return;
 
-       if (dev->input_dev->id.product == USB_PID_RIGKONTROL2)
-               for (i=0; i<len; i++)
+       if (input_dev->id.product == USB_PID_RIGKONTROL2)
+               for (i = 0; i < len; i++)
                        buf[i] = ~buf[i];
 
-       for (i=0; (i<dev->input_dev->keycodemax) && (i < len); i++)
-               input_report_key(dev->input_dev, keycode[i], 
-                                       buf[i/8] & (1 << (i%8)));
+       for (i = 0; i < input_dev->keycodemax && i < len * 8; i++)
+               input_report_key(input_dev, keycode[i],
+                                buf[i / 8] & (1 << (i % 8)));
 
-       input_sync(dev->input_dev);
+       if (dev->chip.usb_id ==
+               USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER) ||
+           dev->chip.usb_id ==
+               USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER2))
+               input_report_abs(dev->input_dev, ABS_MISC, 255 - buf[4]);
+
+       input_sync(input_dev);
 }
 
-void snd_usb_caiaq_input_dispatch(struct snd_usb_caiaqdev *dev, 
-                                 char *buf, 
+void snd_usb_caiaq_input_dispatch(struct snd_usb_caiaqdev *dev,
+                                 char *buf,
                                  unsigned int len)
 {
-       if (!dev->input_dev || (len < 1))
+       if (!dev->input_dev || len < 1)
                return;
 
        switch (buf[0]) {
        case EP1_CMD_READ_ANALOG:
-               snd_caiaq_input_read_analog(dev, buf+1, len-1);
+               snd_caiaq_input_read_analog(dev, buf + 1, len - 1);
                break;
        case EP1_CMD_READ_ERP:
-               snd_caiaq_input_read_erp(dev, buf+1, len-1);
+               snd_caiaq_input_read_erp(dev, buf + 1, len - 1);
                break;
        case EP1_CMD_READ_IO:
-               snd_caiaq_input_read_io(dev, buf+1, len-1);
+               snd_caiaq_input_read_io(dev, buf + 1, len - 1);
                break;
        }
 }
@@ -192,37 +262,34 @@ int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *dev)
        if (!input)
                return -ENOMEM;
 
+       usb_make_path(usb_dev, dev->phys, sizeof(dev->phys));
+       strlcat(dev->phys, "/input0", sizeof(dev->phys));
+
        input->name = dev->product_name;
-       input->id.bustype = BUS_USB;
-       input->id.vendor  = usb_dev->descriptor.idVendor;
-       input->id.product = usb_dev->descriptor.idProduct;
-       input->id.version = usb_dev->descriptor.bcdDevice;
+       input->phys = dev->phys;
+       usb_to_input_id(usb_dev, &input->id);
+       input->dev.parent = &usb_dev->dev;
 
         switch (dev->chip.usb_id) {
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL2):
                input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
                input->absbit[0] = BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) |
                        BIT_MASK(ABS_Z);
-               input->keycode = keycode_rk2;
-               input->keycodesize = sizeof(char);
+               BUILD_BUG_ON(sizeof(dev->keycode) < sizeof(keycode_rk2));
+               memcpy(dev->keycode, keycode_rk2, sizeof(keycode_rk2));
                input->keycodemax = ARRAY_SIZE(keycode_rk2);
-               for (i=0; i<ARRAY_SIZE(keycode_rk2); i++)
-                       set_bit(keycode_rk2[i], input->keybit);
-
                input_set_abs_params(input, ABS_X, 0, 4096, 0, 10);
                input_set_abs_params(input, ABS_Y, 0, 4096, 0, 10);
                input_set_abs_params(input, ABS_Z, 0, 4096, 0, 10);
                snd_usb_caiaq_set_auto_msg(dev, 1, 10, 0);
                break;
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL3):
-               input->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
-               input->absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_Z);
-               input->keycode = keycode_rk3;
-               input->keycodesize = sizeof(char);
+               input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+               input->absbit[0] = BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) |
+                       BIT_MASK(ABS_Z);
+               BUILD_BUG_ON(sizeof(dev->keycode) < sizeof(keycode_rk3));
+               memcpy(dev->keycode, keycode_rk3, sizeof(keycode_rk3));
                input->keycodemax = ARRAY_SIZE(keycode_rk3);
-               for (i=0; i<ARRAY_SIZE(keycode_rk3); i++)
-                       set_bit(keycode_rk3[i], input->keybit);
-
                input_set_abs_params(input, ABS_X, 0, 1024, 0, 10);
                input_set_abs_params(input, ABS_Y, 0, 1024, 0, 10);
                input_set_abs_params(input, ABS_Z, 0, 1024, 0, 10);
@@ -231,21 +298,50 @@ int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *dev)
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AK1):
                input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
                input->absbit[0] = BIT_MASK(ABS_X);
-               input->keycode = keycode_ak1;
-               input->keycodesize = sizeof(char);
+               BUILD_BUG_ON(sizeof(dev->keycode) < sizeof(keycode_ak1));
+               memcpy(dev->keycode, keycode_ak1, sizeof(keycode_ak1));
                input->keycodemax = ARRAY_SIZE(keycode_ak1);
-               for (i=0; i<ARRAY_SIZE(keycode_ak1); i++)
-                       set_bit(keycode_ak1[i], input->keybit);
-
                input_set_abs_params(input, ABS_X, 0, 999, 0, 10);
                snd_usb_caiaq_set_auto_msg(dev, 1, 0, 5);
                break;
+       case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER):
+       case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER2):
+               input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+               input->absbit[0] = BIT_MASK(ABS_HAT0X) | BIT_MASK(ABS_HAT0Y) |
+                                  BIT_MASK(ABS_HAT1X) | BIT_MASK(ABS_HAT1Y) |
+                                  BIT_MASK(ABS_HAT2X) | BIT_MASK(ABS_HAT2Y) |
+                                  BIT_MASK(ABS_HAT3X) | BIT_MASK(ABS_HAT3Y) |
+                                  BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) |
+                                  BIT_MASK(ABS_Z);
+               input->absbit[BIT_WORD(ABS_MISC)] |= BIT_MASK(ABS_MISC);
+               BUILD_BUG_ON(sizeof(dev->keycode) < sizeof(keycode_kore));
+               memcpy(dev->keycode, keycode_kore, sizeof(keycode_kore));
+               input->keycodemax = ARRAY_SIZE(keycode_kore);
+               input_set_abs_params(input, ABS_HAT0X, 0, 999, 0, 10);
+               input_set_abs_params(input, ABS_HAT0Y, 0, 999, 0, 10);
+               input_set_abs_params(input, ABS_HAT1X, 0, 999, 0, 10);
+               input_set_abs_params(input, ABS_HAT1Y, 0, 999, 0, 10);
+               input_set_abs_params(input, ABS_HAT2X, 0, 999, 0, 10);
+               input_set_abs_params(input, ABS_HAT2Y, 0, 999, 0, 10);
+               input_set_abs_params(input, ABS_HAT3X, 0, 999, 0, 10);
+               input_set_abs_params(input, ABS_HAT3Y, 0, 999, 0, 10);
+               input_set_abs_params(input, ABS_X, 0, 4096, 0, 10);
+               input_set_abs_params(input, ABS_Y, 0, 4096, 0, 10);
+               input_set_abs_params(input, ABS_Z, 0, 4096, 0, 10);
+               input_set_abs_params(input, ABS_MISC, 0, 255, 0, 1);
+               snd_usb_caiaq_set_auto_msg(dev, 1, 10, 5);
+               break;
        default:
                /* no input methods supported on this device */
                input_free_device(input);
                return 0;
        }
 
+       input->keycode = dev->keycode;
+       input->keycodesize = sizeof(unsigned short);
+       for (i = 0; i < input->keycodemax; i++)
+               __set_bit(dev->keycode[i], input->keybit);
+
        ret = input_register_device(input);
        if (ret < 0) {
                input_free_device(input);
@@ -265,5 +361,3 @@ void snd_usb_caiaq_input_free(struct snd_usb_caiaqdev *dev)
        dev->input_dev = NULL;
 }
 
-#endif /* CONFIG_SND_USB_CAIAQ_INPUT */
-
index 793ca20ce349c502732c7f160e0401dff9f13f47..30b57f97c6e411221517f9a8c3d0a5e1a42036b0 100644 (file)
@@ -23,7 +23,6 @@
 #include <linux/usb.h>
 #include <linux/input.h>
 #include <linux/spinlock.h>
-#include <sound/driver.h>
 #include <sound/core.h>
 #include <sound/rawmidi.h>
 #include <sound/pcm.h>
@@ -124,7 +123,7 @@ void snd_usb_caiaq_midi_handle_input(struct snd_usb_caiaqdev *dev,
        snd_rawmidi_receive(dev->midi_receive_substream, buf, len);
 }
 
-int __devinit snd_usb_caiaq_midi_init(struct snd_usb_caiaqdev *device)
+int snd_usb_caiaq_midi_init(struct snd_usb_caiaqdev *device)
 {
        int ret;
        struct snd_rawmidi *rmidi;
index 967b823eace083bbad39e4fae5378243b61dbbe7..8fa93566570272036365009776ec0fa952c1303d 100644 (file)
@@ -38,7 +38,6 @@
  */
 
 
-#include <sound/driver.h>
 #include <linux/bitops.h>
 #include <linux/init.h>
 #include <linux/list.h>
@@ -2078,6 +2077,14 @@ static int usb_audio_probe(struct usb_interface *intf,
                           const struct usb_device_id *id);
 static void usb_audio_disconnect(struct usb_interface *intf);
 
+#ifdef CONFIG_PM
+static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message);
+static int usb_audio_resume(struct usb_interface *intf);
+#else
+#define usb_audio_suspend NULL
+#define usb_audio_resume NULL
+#endif
+
 static struct usb_device_id usb_audio_ids [] = {
 #include "usbquirks.h"
     { .match_flags = (USB_DEVICE_ID_MATCH_INT_CLASS | USB_DEVICE_ID_MATCH_INT_SUBCLASS),
@@ -2092,6 +2099,8 @@ static struct usb_driver usb_audio_driver = {
        .name =         "snd-usb-audio",
        .probe =        usb_audio_probe,
        .disconnect =   usb_audio_disconnect,
+       .suspend =      usb_audio_suspend,
+       .resume =       usb_audio_resume,
        .id_table =     usb_audio_ids,
 };
 
@@ -3654,6 +3663,45 @@ static void usb_audio_disconnect(struct usb_interface *intf)
                                 dev_get_drvdata(&intf->dev));
 }
 
+#ifdef CONFIG_PM
+static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message)
+{
+       struct snd_usb_audio *chip = dev_get_drvdata(&intf->dev);
+       struct list_head *p;
+       struct snd_usb_stream *as;
+
+       if (chip == (void *)-1L)
+               return 0;
+
+       snd_power_change_state(chip->card, SNDRV_CTL_POWER_D3hot);
+       if (!chip->num_suspended_intf++) {
+               list_for_each(p, &chip->pcm_list) {
+                       as = list_entry(p, struct snd_usb_stream, list);
+                       snd_pcm_suspend_all(as->pcm);
+               }
+       }
+
+       return 0;
+}
+
+static int usb_audio_resume(struct usb_interface *intf)
+{
+       struct snd_usb_audio *chip = dev_get_drvdata(&intf->dev);
+
+       if (chip == (void *)-1L)
+               return 0;
+       if (--chip->num_suspended_intf)
+               return 0;
+       /*
+        * ALSA leaves material resumption to user space
+        * we just notify
+        */
+
+       snd_power_change_state(chip->card, SNDRV_CTL_POWER_D0);
+
+       return 0;
+}
+#endif         /* CONFIG_PM */
 
 static int __init snd_usb_audio_init(void)
 {
index 2272f45a18674320977d5314a6608b4449a27312..7cf18c38dc424c14a1decd29614105cfc4412e81 100644 (file)
@@ -126,6 +126,7 @@ struct snd_usb_audio {
        u32 usb_id;
        int shutdown;
        int num_interfaces;
+       int num_suspended_intf;
 
        struct list_head pcm_list;      /* list of pcm streams */
        int pcm_devs;
index 6330788c1c2b2d58ddf31c2802c682b5531f0004..750e929d5870504b39c1e0479a91af872c0cd539 100644 (file)
@@ -35,7 +35,6 @@
  * SUCH DAMAGE.
  */
 
-#include <sound/driver.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/bitops.h>
index 5e329690cfb1bbe6bb1fab91a36c7c5c1d6656ec..89c63d073cc6fac8f0c00ca1646377994157c64b 100644 (file)
@@ -26,7 +26,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/bitops.h>
 #include <linux/init.h>
 #include <linux/list.h>
@@ -1703,6 +1702,11 @@ static void snd_usb_mixer_memory_change(struct usb_mixer_interface *mixer,
        case 19: /* speaker out jacks */
        case 20: /* headphones out jack */
                break;
+       /* live24ext: 4 = line-in jack */
+       case 3: /* hp-out jack (may actuate Mute) */
+               if (mixer->chip->usb_id == USB_ID(0x041e, 0x3040))
+                       snd_usb_mixer_notify_id(mixer, mixer->rc_cfg->mute_mixer_id);
+               break;
        default:
                snd_printd(KERN_DEBUG "memory change in unknown unit %d\n", unitid);
                break;
@@ -1951,6 +1955,9 @@ static int snd_audigy2nx_controls_create(struct usb_mixer_interface *mixer)
        int i, err;
 
        for (i = 0; i < ARRAY_SIZE(snd_audigy2nx_controls); ++i) {
+               if (i > 1 &&  /* Live24ext has 2 LEDs only */
+                       mixer->chip->usb_id == USB_ID(0x041e, 0x3040))
+                       break; 
                err = snd_ctl_add(mixer->chip->card,
                                  snd_ctl_new1(&snd_audigy2nx_controls[i], mixer));
                if (err < 0)
@@ -1963,28 +1970,42 @@ static int snd_audigy2nx_controls_create(struct usb_mixer_interface *mixer)
 static void snd_audigy2nx_proc_read(struct snd_info_entry *entry,
                                    struct snd_info_buffer *buffer)
 {
-       static const struct {
+       static const struct sb_jack {
                int unitid;
                const char *name;
-       } jacks[] = {
+       }  jacks_audigy2nx[] = {
                {4,  "dig in "},
                {7,  "line in"},
                {19, "spk out"},
                {20, "hph out"},
+               {-1, NULL}
+       }, jacks_live24ext[] = {
+               {4,  "line in"}, /* &1=Line, &2=Mic*/
+               {3,  "hph out"}, /* headphones */
+               {0,  "RC     "}, /* last command, 6 bytes see rc_config above */
+               {-1, NULL}
        };
+       const struct sb_jack *jacks;
        struct usb_mixer_interface *mixer = entry->private_data;
        int i, err;
        u8 buf[3];
 
        snd_iprintf(buffer, "%s jacks\n\n", mixer->chip->card->shortname);
-       for (i = 0; i < ARRAY_SIZE(jacks); ++i) {
+       if (mixer->chip->usb_id == USB_ID(0x041e, 0x3020))
+               jacks = jacks_audigy2nx;
+       else if (mixer->chip->usb_id == USB_ID(0x041e, 0x3040))
+               jacks = jacks_live24ext;
+       else
+               return;
+
+       for (i = 0; jacks[i].name; ++i) {
                snd_iprintf(buffer, "%s: ", jacks[i].name);
                err = snd_usb_ctl_msg(mixer->chip->dev,
                                      usb_rcvctrlpipe(mixer->chip->dev, 0),
                                      GET_MEM, USB_DIR_IN | USB_TYPE_CLASS |
                                      USB_RECIP_INTERFACE, 0,
                                      jacks[i].unitid << 8, buf, 3, 100);
-               if (err == 3 && buf[0] == 3)
+               if (err == 3 && (buf[0] == 3 || buf[0] == 6))
                        snd_iprintf(buffer, "%02x %02x\n", buf[1], buf[2]);
                else
                        snd_iprintf(buffer, "?\n");
@@ -2022,7 +2043,8 @@ int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif)
        if ((err = snd_usb_soundblaster_remote_init(mixer)) < 0)
                goto _error;
 
-       if (mixer->chip->usb_id == USB_ID(0x041e, 0x3020)) {
+       if (mixer->chip->usb_id == USB_ID(0x041e, 0x3020) ||
+           mixer->chip->usb_id == USB_ID(0x041e, 0x3040)) {
                struct snd_info_entry *entry;
 
                if ((err = snd_audigy2nx_controls_create(mixer)) < 0)
index 7c4dcb3f436af09f3afa0e0ae88a6612d7edd503..d755be0ad8115da5c1296211678f81a7774277d5 100644 (file)
@@ -187,6 +187,13 @@ static struct usbmix_selector_map audigy2nx_selectors[] = {
        { 0 } /* terminator */
 };
 
+/* Creative SoundBlaster Live! 24-bit External */
+static struct usbmix_name_map live24ext_map[] = {
+       /* 2: PCM Playback Volume */
+       { 5, "Mic Capture" }, /* FU, default PCM Capture Volume */
+       { 0 } /* terminator */
+};
+
 /* LineX FM Transmitter entry - needed to bypass controls bug */
 static struct usbmix_name_map linex_map[] = {
        /* 1: IT pcm */
@@ -273,6 +280,10 @@ static struct usbmix_ctl_map usbmix_ctl_maps[] = {
                .map = audigy2nx_map,
                .selector_map = audigy2nx_selectors,
        },
+       {
+               .id = USB_ID(0x041e, 0x3040),
+               .map = live24ext_map,
+       },
        {
                /* Hercules DJ Console (Windows Edition) */
                .id = USB_ID(0x06f8, 0xb000),
index 59410f437705a745c5fb5736761ad725517d190b..938dff5f9cef5dcab423514921f0c5a76a862e05 100644 (file)
@@ -1003,12 +1003,36 @@ YAMAHA_DEVICE(0x7010, "UB99"),
                }
        }
 },
+{
+       /* has ID 0x0049 when not in "Advanced Driver" mode */
+       USB_DEVICE(0x0582, 0x0047),
+       .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+               /* .vendor_name = "EDIROL", */
+               /* .product_name = "UR-80", */
+               .ifnum = QUIRK_ANY_INTERFACE,
+               .type = QUIRK_COMPOSITE,
+               .data = (const struct snd_usb_audio_quirk[]) {
+                       /* in the 96 kHz modes, only interface 1 is there */
+                       {
+                               .ifnum = 1,
+                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
+                       },
+                       {
+                               .ifnum = 2,
+                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
+                       },
+                       {
+                               .ifnum = -1
+                       }
+               }
+       }
+},
 {
        /* has ID 0x004a when not in "Advanced Driver" mode */
        USB_DEVICE(0x0582, 0x0048),
        .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
-               .vendor_name = "EDIROL",
-               .product_name = "UR-80",
+               /* .vendor_name = "EDIROL", */
+               /* .product_name = "UR-80", */
                .ifnum = 0,
                .type = QUIRK_MIDI_FIXED_ENDPOINT,
                .data = & (const struct snd_usb_midi_endpoint_info) {
index b76b3dd9df25d48d878548238f040018c443b075..1558a5c4094faebb589c9822a37182c837867c39 100644 (file)
@@ -20,7 +20,6 @@
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-#include <sound/driver.h>
 #include <linux/interrupt.h>
 #include <linux/usb.h>
 #include <sound/core.h>
 int usX2Y_hwdep_pcm_new(struct snd_card *card);
 
 
-static struct page * snd_us428ctls_vm_nopage(struct vm_area_struct *area, unsigned long address, int *type)
+static int snd_us428ctls_vm_fault(struct vm_area_struct *area,
+                                 struct vm_fault *vmf)
 {
        unsigned long offset;
        struct page * page;
        void *vaddr;
 
-       snd_printdd("ENTER, start %lXh, ofs %lXh, pgoff %ld, addr %lXh\n",
+       snd_printdd("ENTER, start %lXh, pgoff %ld\n",
                   area->vm_start,
-                  address - area->vm_start,
-                  (address - area->vm_start) >> PAGE_SHIFT,
-                  address);
+                  vmf->pgoff);
        
-       offset = area->vm_pgoff << PAGE_SHIFT;
-       offset += address - area->vm_start;
-       snd_assert((offset % PAGE_SIZE) == 0, return NOPAGE_SIGBUS);
+       offset = vmf->pgoff << PAGE_SHIFT;
        vaddr = (char*)((struct usX2Ydev *)area->vm_private_data)->us428ctls_sharedmem + offset;
        page = virt_to_page(vaddr);
        get_page(page);
-       snd_printdd( "vaddr=%p made us428ctls_vm_nopage() return %p; offset=%lX\n", vaddr, page, offset);
+       vmf->page = page;
 
-       if (type)
-               *type = VM_FAULT_MINOR;
+       snd_printdd("vaddr=%p made us428ctls_vm_fault() page %p\n",
+                   vaddr, page);
 
-       return page;
+       return 0;
 }
 
 static struct vm_operations_struct us428ctls_vm_ops = {
-       .nopage = snd_us428ctls_vm_nopage,
+       .fault = snd_us428ctls_vm_fault,
 };
 
 static int snd_us428ctls_mmap(struct snd_hwdep * hw, struct file *filp, struct vm_area_struct *area)
@@ -88,7 +84,7 @@ static int snd_us428ctls_mmap(struct snd_hwdep * hw, struct file *filp, struct v
                us428->us428ctls_sharedmem->CtlSnapShotLast = -2;
        }
        area->vm_ops = &us428ctls_vm_ops;
-       area->vm_flags |= VM_RESERVED;
+       area->vm_flags |= VM_RESERVED | VM_DONTEXPAND;
        area->vm_private_data = hw->private_data;
        return 0;
 }
index e011fcacce92c298e82b0463583de1a0ea72edb9..e5981a630314a328253c4a92f3c7641f5b191938 100644 (file)
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 */
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
index 48e9aa3f18c94ac7dc3ecd57b53bfd749e9c3779..9a608fa85155c530019efcc56d8ca86cfb0195fa 100644 (file)
@@ -31,7 +31,6 @@
  */
 
 
-#include <sound/driver.h>
 #include <linux/interrupt.h>
 #include <linux/usb.h>
 #include <sound/core.h>
index a5e7bcd7ca2ec0c5b486ba0b56c5f8e8f9d41a75..117946f2debb3a04891d87de9327c16d8f27f7fe 100644 (file)
@@ -683,30 +683,24 @@ static void snd_usX2Y_hwdep_pcm_vm_close(struct vm_area_struct *area)
 }
 
 
-static struct page * snd_usX2Y_hwdep_pcm_vm_nopage(struct vm_area_struct *area, unsigned long address, int *type)
+static int snd_usX2Y_hwdep_pcm_vm_fault(struct vm_area_struct *area,
+                                       struct vm_fault *vmf)
 {
        unsigned long offset;
-       struct page *page;
        void *vaddr;
 
-       offset = area->vm_pgoff << PAGE_SHIFT;
-       offset += address - area->vm_start;
-       snd_assert((offset % PAGE_SIZE) == 0, return NOPAGE_OOM);
+       offset = vmf->pgoff << PAGE_SHIFT;
        vaddr = (char*)((struct usX2Ydev *)area->vm_private_data)->hwdep_pcm_shm + offset;
-       page = virt_to_page(vaddr);
-       get_page(page);
-
-       if (type)
-               *type = VM_FAULT_MINOR;
-
-       return page;
+       vmf->page = virt_to_page(vaddr);
+       get_page(vmf->page);
+       return 0;
 }
 
 
 static struct vm_operations_struct snd_usX2Y_hwdep_pcm_vm_ops = {
        .open = snd_usX2Y_hwdep_pcm_vm_open,
        .close = snd_usX2Y_hwdep_pcm_vm_close,
-       .nopage = snd_usX2Y_hwdep_pcm_vm_nopage,
+       .fault = snd_usX2Y_hwdep_pcm_vm_fault,
 };
 
 
@@ -728,7 +722,7 @@ static int snd_usX2Y_hwdep_pcm_mmap(struct snd_hwdep * hw, struct file *filp, st
                return -ENODEV;
        }
        area->vm_ops = &snd_usX2Y_hwdep_pcm_vm_ops;
-       area->vm_flags |= VM_RESERVED;
+       area->vm_flags |= VM_RESERVED | VM_DONTEXPAND;
        area->vm_private_data = hw->private_data;
        return 0;
 }